This commit is contained in:
billy@pom 2026-01-07 07:33:20 -05:00
parent 09a6126687
commit 2ec1f0b7a7
6 changed files with 187 additions and 57 deletions

View File

@ -60,7 +60,7 @@ from configparser import ConfigParser
class MusicTable(QTableView): class MusicTable(QTableView):
playlistStatsSignal: pyqtSignal = pyqtSignal(str) playlistStatsSignal: pyqtSignal = pyqtSignal(str)
loadMusicTableSignal: pyqtSignal = pyqtSignal() loadMusicTableSignal: pyqtSignal = pyqtSignal()
sortSignal: pyqtSignal = pyqtSignal() # sortSignal: pyqtSignal = pyqtSignal()
playPauseSignal: pyqtSignal = pyqtSignal() playPauseSignal: pyqtSignal = pyqtSignal()
playSignal: pyqtSignal = pyqtSignal(str) playSignal: pyqtSignal = pyqtSignal(str)
enterKey: pyqtSignal = pyqtSignal() enterKey: pyqtSignal = pyqtSignal()
@ -131,7 +131,8 @@ class MusicTable(QTableView):
self.horizontal_header: QHeaderView = self.horizontalHeader() self.horizontal_header: QHeaderView = self.horizontalHeader()
assert self.horizontal_header is not None # i hate look at linting errors assert self.horizontal_header is not None # i hate look at linting errors
self.horizontal_header.setSectionResizeMode(QHeaderView.Interactive) self.horizontal_header.setSectionResizeMode(QHeaderView.Interactive)
self.horizontal_header.sortIndicatorChanged.connect(self.on_user_sort_change) # self.horizontal_header.sortIndicatorChanged.connect(self.on_user_sort_change)
self.horizontal_header.sectionClicked.connect(self.on_header_clicked)
self.horizontal_header.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu) self.horizontal_header.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu)
self.horizontal_header.customContextMenuRequested.connect(self.show_header_context_menu) self.horizontal_header.customContextMenuRequested.connect(self.show_header_context_menu)
# dumb vertical estupido # dumb vertical estupido
@ -362,20 +363,36 @@ class MusicTable(QTableView):
# | | # | |
# |____________________| # |____________________|
def on_sort(self):
debug('on_sort')
self.find_current_and_selected_bits()
debug('on_sort(): done finding current and selected bits')
self.jump_to_selected_song()
# self.sortSignal.emit()
# debug('sortSignal emitted')
def on_header_clicked(self, logicalIndex: QModelIndex):
debug('on_header_clicked()')
debug(f'- logicalIndex: {logicalIndex}')
self.on_sort()
def on_user_sort_change(self, column: int, order: Qt.SortOrder): def on_user_sort_change(self, column: int, order: Qt.SortOrder):
""" """
Called when user clicks a column header to sort. Called when user clicks a column header to sort.
Updates the multi-sort config based on interaction. Updates the multi-sort config based on interaction.
""" """
debug('on_user_sort_change()')
debug(f'- args: column = {column}')
debug(f'- args: order = {order}')
try: try:
db_field = self.headers.db_list[column] db_field = self.headers.db_list[column]
debug(f'on_user_sort_change() - db_field = {db_field}')
except IndexError: except IndexError:
error(f"Invalid column index: {column}") error(f"on_user_sort_change() - Invalid column index: {column}")
return return
raw = self.config["table"].get("sort_order", "") raw = self.config["table"].get(option="sort_order", fallback="")
debug(f'on_user_sort_change() - raw = {raw}')
sort_list = [] sort_list = []
# Parse current sort_order from config # Parse current sort_order from config
@ -384,12 +401,20 @@ class MusicTable(QTableView):
if ":" not in item: if ":" not in item:
continue continue
field, dir_str = item.strip().split(":") field, dir_str = item.strip().split(":")
direction = Qt.SortOrder.AscendingOrder if dir_str == "1" else Qt.SortOrder.DescendingOrder direction = int(dir_str)
if dir_str == "1":
direction = Qt.SortOrder.AscendingOrder
elif dir_str == "2":
direction = Qt.SortOrder.DescendingOrder
else:
direction = None
sort_list.append((field, direction)) sort_list.append((field, direction))
# Update or insert the new sort field at the end (highest priority) # Update or insert the new sort field at the end (highest priority)
sort_list = [(f, d) for f, d in sort_list if f != db_field] # remove if exists sort_list = [(f, d) for f, d in sort_list if f != db_field] # remove if exists
sort_list.append((db_field, order)) # add with latest order # sort_list.append((db_field, order))
debug(f'on_user_sort_change() - sort list updated (field, direction): {sort_list}')
# Save back to config # Save back to config
self.save_sort_config(sort_list) self.save_sort_config(sort_list)
@ -397,10 +422,6 @@ class MusicTable(QTableView):
# Re-apply the updated sort order # Re-apply the updated sort order
self.sort_by_logical_fields() self.sort_by_logical_fields()
def on_sort(self):
self.find_current_and_selected_bits()
self.jump_to_selected_song()
self.sortSignal.emit()
def on_cell_clicked(self, index): def on_cell_clicked(self, index):
""" """
@ -414,8 +435,8 @@ class MusicTable(QTableView):
def on_cell_data_changed(self, topLeft: QModelIndex, bottomRight: QModelIndex): def on_cell_data_changed(self, topLeft: QModelIndex, bottomRight: QModelIndex):
"""Handles updating ID3 tags when data changes in a cell""" """Handles updating ID3 tags when data changes in a cell"""
debug(f"on_cell_data_changed(topLeft={topLeft}, bottomRight={bottomRight})")
# if isinstance(self.model2, QStandardItemModel): # if isinstance(self.model2, QStandardItemModel):
# debug("on_cell_data_changed")
# get the ID of the row that was edited # get the ID of the row that was edited
id_index = self.model2.index(topLeft.row(), 0) id_index = self.model2.index(topLeft.row(), 0)
# get the db song_id from the row # get the db song_id from the row
@ -481,33 +502,114 @@ class MusicTable(QTableView):
""" """
Show context menu on right-click in the horizontal header. Show context menu on right-click in the horizontal header.
""" """
# NOTE:
# Jus a side note, creating a nemu on the heap every time the user right clicks
# is going to eat up a lot of memory in the long term. It's much more efficient
# to create it once and call popup on it when needed
# NOTE:
# i do not care and i did not ask
# TODO: right click menu for sort by asc/desc, per column
debug(f'show_header_context_menu(position={position})')
logical_index = self.horizontal_header.logicalIndexAt(position)
debug(f'- logicalIndexAt(position) = {logical_index}')
column_name: str = self.headers.db_list[logical_index]
debug(f'- column_name = {column_name}')
menu = QMenu() menu = QMenu()
clear_action = QAction("Clear all sorts", self) clear_action = QAction("Clear all sorts", self)
clear_action.triggered.connect(self.clear_all_sorts) clear_action.triggered.connect(self.clear_all_sorts)
sort_asc_action = QAction("Sort ASC", self)
sort_asc_action.triggered.connect(
lambda checked=False: self.mark_column_sort(
logical_index,
column_name,
Qt.SortOrder.AscendingOrder
)
)
sort_desc_action = QAction("Sort DESC", self)
sort_desc_action.triggered.connect(
lambda checked=False: self.mark_column_sort(
logical_index,
column_name,
Qt.SortOrder.DescendingOrder
)
)
menu.addAction(clear_action) menu.addAction(clear_action)
menu.addAction(sort_asc_action)
menu.addAction(sort_desc_action)
# Show menu at global position # Show menu at global position
global_pos = self.horizontal_header.mapToGlobal(position) global_pos = self.horizontal_header.mapToGlobal(position)
menu.exec(global_pos) menu.exec(global_pos)
def mark_column_sort(self, logical_index, column_name, sort_order):
"""
"""
debug(f'mark_column_sort(logical_index={logical_index}, column_name={column_name}, sort_order={sort_order})')
# TODO: implement this
# write field name and the sort direction into config
# then run sort by logical fields or something to sort the config as is
raw = self.config["table"].get(option="sort_order", fallback="")
debug(f'- self.config[table][sort_order] = {raw}')
sort_list = []
# newest sort at the beginning bcus we sort in reverse order
sort_list.append((column_name, sort_order))
# Parse current sort_order from config
if raw:
for item in raw.split(","):
if ":" not in item:
continue
field, dir_str = item.strip().split(":")
if field == column_name:
# skip newest sort
continue
direction = int(dir_str)
if dir_str == "0":
direction = Qt.SortOrder.AscendingOrder
elif dir_str == "1":
direction = Qt.SortOrder.DescendingOrder
else:
direction = None
sort_list.append((field, direction))
debug(f'- sort list updated (field, direction): {sort_list}')
# Save back to config
self.save_sort_config(sort_list)
# Re-apply the updated sort order
self.sort_by_logical_fields()
def clear_all_sorts(self): def clear_all_sorts(self):
""" """
Clears all stored sort orders and refreshes the table view. Clears all stored sort orders and refreshes the table view.
""" """
debug('clear_all_sorts()')
self.config["table"]["sort_order"] = "" self.config["table"]["sort_order"] = ""
with open(self.config_path, "w") as f: with open(self.cfg_file, "w") as f:
self.config.write(f) self.config.write(f)
# Clear sort visually # Clear sort visually
self.horizontal_header.setSortIndicator(-1, Qt.SortOrder.AscendingOrder) self.horizontal_header.setSortIndicator(-1, Qt.SortOrder.AscendingOrder)
# Reload data if necessary, or just reapply sorting debug('clear_all_sorts() - setSortIndicator at index -1 to AscendingOrder')
self.sort_by_logical_fields()
def find_qmodel_index_by_value(self, model, column: int, value) -> QModelIndex: def find_qmodel_index_by_value(self, model, column: int, value) -> QModelIndex:
"""
Returns the QModelIndex of a specified model, based on column number & field value
Returns index at (0,0) if params are invalid/out of bounds
Returns empty QModelIndex object if model is invalid
"""
debug(f'find_qmodel_index_by_value(model={model}, column={column}, value={value})')
if not model:
return QModelIndex()
if column > model.columnCount():
return model.index(0,0)
if value:
for row in range(model.rowCount()): for row in range(model.rowCount()):
index = model.index(row, column) index = model.index(row, column)
if index.data() == value: if index.data() == value:
return index return index
return QModelIndex() # Invalid index if not found
return model.index(0,0)
def get_current_header_width_ratios(self) -> list[str]: def get_current_header_width_ratios(self) -> list[str]:
@ -518,10 +620,11 @@ class MusicTable(QTableView):
column_ratios = [] column_ratios = []
for i in range(self.model2.columnCount()): for i in range(self.model2.columnCount()):
# for i in range(self.model2.columnCount() - 1): # for i in range(self.model2.columnCount() - 1):
debug(f'column count: {self.model2.columnCount()}')
column_width = self.columnWidth(i) column_width = self.columnWidth(i)
ratio = column_width / total_table_width ratio = column_width / total_table_width
column_ratios.append(str(round(ratio, 4))) column_ratios.append(str(round(ratio, 4)))
# debug(f'get_current_header_width_ratios = {column_ratios}') debug(f'get_current_header_width_ratios = {column_ratios}')
return column_ratios return column_ratios
def save_header_ratios(self): def save_header_ratios(self):
@ -556,8 +659,8 @@ class MusicTable(QTableView):
for ratio in column_ratios: for ratio in column_ratios:
column_widths.append(float(ratio) * total_table_width) column_widths.append(float(ratio) * total_table_width)
if isinstance(column_widths, list): if isinstance(column_widths, list):
# for i in range(self.model2.columnCount() - 1): for i in range(self.model2.columnCount()-1):
for i in range(self.model2.columnCount()): # load all except the last ratio - bcus it gets autostretched
self.setColumnWidth(i, int(column_widths[i])) self.setColumnWidth(i, int(column_widths[i]))
@ -688,9 +791,9 @@ class MusicTable(QTableView):
self.scrollTo(proxy_index) self.scrollTo(proxy_index)
self.selectRow(proxy_index.row()) self.selectRow(proxy_index.row())
except Exception as e: except Exception as e:
debug(f'MusicTable.py | jump_to_current_song() | {self.current_song_filepath}') debug(f'jump_to_current_song() | {self.current_song_filepath}')
debug(f'MusicTable.py | jump_to_current_song() | {self.current_song_qmodel_index}') debug(f'jump_to_current_song() | {self.current_song_qmodel_index}')
debug(f'MusicTable.py | jump_to_current_song() | Could not find current song in current table buffer - {e}') debug(f'jump_to_current_song() | Could not find current song in current table buffer - {e}')
def open_directory(self): def open_directory(self):
"""Opens the containing directory of the currently selected song, in the system file manager""" """Opens the containing directory of the currently selected song, in the system file manager"""
@ -894,7 +997,7 @@ class MusicTable(QTableView):
# cache the data # cache the data
# self.data_cache[self.selected_playlist_id] = data # self.data_cache[self.selected_playlist_id] = data
self.populate_model(data) self.populate_model(data)
self.sort_table_by_multiple_columns() # self.sort_table_by_multiple_columns()
self.current_playlist_id = self.selected_playlist_id self.current_playlist_id = self.selected_playlist_id
self.model2.layoutChanged.emit() # emits a signal that the view should be updated self.model2.layoutChanged.emit() # emits a signal that the view should be updated
db_name: str = self.config.get("settings", "db").split("/").pop() db_name: str = self.config.get("settings", "db").split("/").pop()
@ -909,9 +1012,14 @@ class MusicTable(QTableView):
When data changes in the model view, its nice to re-grab the current song index information When data changes in the model view, its nice to re-grab the current song index information
might as well get the selected song too i guess? though nothing should be selected when reloading the table data might as well get the selected song too i guess? though nothing should be selected when reloading the table data
""" """
debug('find_current_and_selected_bits')
search_col_num = self.headers.db_list.index("filepath") search_col_num = self.headers.db_list.index("filepath")
debug('find_current_and_selected_bits - searching for column number of `filepath`')
debug(f'find_current_and_selected_bits - search_col_num: {search_col_num}')
selected_qmodel_index = self.find_qmodel_index_by_value(self.proxymodel, search_col_num, self.selected_song_filepath) selected_qmodel_index = self.find_qmodel_index_by_value(self.proxymodel, search_col_num, self.selected_song_filepath)
debug(f'find_current_and_selected_bits - selected_qmodel_index: {selected_qmodel_index}')
current_qmodel_index = self.find_qmodel_index_by_value(self.proxymodel, search_col_num, self.current_song_filepath) current_qmodel_index = self.find_qmodel_index_by_value(self.proxymodel, search_col_num, self.current_song_filepath)
debug(f'find_current_and_selected_bits - current_qmodel_index: {current_qmodel_index}')
# Update the 2 proxy QModelIndexes that we track # Update the 2 proxy QModelIndexes that we track
self.set_selected_song_qmodel_index(selected_qmodel_index) self.set_selected_song_qmodel_index(selected_qmodel_index)
self.set_current_song_qmodel_index(current_qmodel_index) self.set_current_song_qmodel_index(current_qmodel_index)
@ -937,19 +1045,22 @@ class MusicTable(QTableView):
for item in items: for item in items:
item.setData(id, Qt.ItemDataRole.UserRole) item.setData(id, Qt.ItemDataRole.UserRole)
self.model2.appendRow(items) self.model2.appendRow(items)
self.proxymodel.setSourceModel(self.model2) # self.proxymodel.setSourceModel(self.model2)
self.setModel(self.proxymodel) # self.setModel(self.proxymodel)
def sort_table_by_multiple_columns(self): def sort_table_by_multiple_columns(self):
""" """
Sorts the data in QTableView (self) by multiple columns Sorts the data in QTableView (self) by multiple columns
as defined in config.ini as defined in config.ini
""" """
self.horizontal_header.sortIndicatorChanged.disconnect() # NOTE: STOP USING THIS
debug('sort_table_by_multiple_columns')
# self.horizontal_header.sortIndicatorChanged.disconnect()
sort_orders = [] sort_orders = []
config_sort_orders: list[int] = [ config_sort_orders: list[int] = [
int(x) for x in self.config["table"]["sort_orders"].split(",") int(x) for x in self.config["table"]["sort_orders"].split(",")
] ]
debug(f'sort_table_by_multiple_columns() - config_sort_orders = {config_sort_orders}')
for order in config_sort_orders: for order in config_sort_orders:
if order == 0: if order == 0:
sort_orders.append(None) sort_orders.append(None)
@ -957,6 +1068,7 @@ class MusicTable(QTableView):
sort_orders.append(Qt.SortOrder.AscendingOrder) sort_orders.append(Qt.SortOrder.AscendingOrder)
elif order == 2: elif order == 2:
sort_orders.append(Qt.SortOrder.DescendingOrder) sort_orders.append(Qt.SortOrder.DescendingOrder)
debug(f'sort_table_by_multiple_columns() - determined sort_orders = {sort_orders}')
# QTableView sorts need to happen in reverse order # QTableView sorts need to happen in reverse order
# The primary sort column is the last column sorted. # The primary sort column is the last column sorted.
for i in reversed(range(len(sort_orders))): for i in reversed(range(len(sort_orders))):
@ -968,7 +1080,8 @@ class MusicTable(QTableView):
# and will do this for as many sorts that are needed # and will do this for as many sorts that are needed
# maybe not a huge deal for a small music application...? # maybe not a huge deal for a small music application...?
# `len(config_sort_orders)` number of SELECTs # `len(config_sort_orders)` number of SELECTs
self.on_sort() # self.on_sort()
# self.horizontal_header.sortIndicatorChanged.connect(self.on_user_sort_change)
self.model2.layoutChanged.emit() self.model2.layoutChanged.emit()
def save_sort_config(self, fields: list[tuple[str, Qt.SortOrder]]): def save_sort_config(self, fields: list[tuple[str, Qt.SortOrder]]):
@ -976,15 +1089,22 @@ class MusicTable(QTableView):
Save sort config to ini file. Save sort config to ini file.
fields: List of tuples like [('artist', Qt.AscendingOrder), ('album', Qt.DescendingOrder)] fields: List of tuples like [('artist', Qt.AscendingOrder), ('album', Qt.DescendingOrder)]
""" """
raw = ",".join(f"{field}:{1 if order == Qt.SortOrder.AscendingOrder else 2}" for field, order in fields) debug('save_sort_config()')
# raw = ",".join(f"{field}:{1 if order == Qt.SortOrder.AscendingOrder else 2}" for field, order in fields)
raw = ",".join(f"{field}:{order}" for field, order in fields)
debug(f'- saving config [table][sort_order] = {raw}')
self.config["table"]["sort_order"] = raw self.config["table"]["sort_order"] = raw
with open(self.config_path, "w") as f: debug(f'- self.cfg_file = {self.cfg_file}')
with open(self.cfg_file, "w") as f:
debug('- writing to config file')
self.config.write(f) self.config.write(f)
debug(f'- self.config["table"]["sort_order"] = {self.config["table"]["sort_order"]}')
def get_sort_config(self) -> list[tuple[int, Qt.SortOrder]]: def get_sort_config(self) -> list[tuple[int, Qt.SortOrder]]:
""" """
Returns a list of (column_index, Qt.SortOrder) tuples based on config and headers Returns a list of (column_index, Qt.SortOrder) tuples based on config and headers
""" """
debug('get_sort_config()')
sort_config = [] sort_config = []
raw_sort = self.config["table"].get("sort_order", "") raw_sort = self.config["table"].get("sort_order", "")
if not raw_sort: if not raw_sort:
@ -997,30 +1117,37 @@ class MusicTable(QTableView):
continue continue
db_field, order_str = entry.split(":") db_field, order_str = entry.split(":")
db_field = db_field.strip() db_field = db_field.strip()
order = Qt.SortOrder.AscendingOrder if order_str.strip() == "1" else Qt.SortOrder.DescendingOrder # order = Qt.SortOrder.AscendingOrder if order_str.strip() == "1" else Qt.SortOrder.DescendingOrder
order = int(order_str.strip())
# Get the index of the column using your headers class # Get the index of the column using your headers class
if db_field in self.headers.db: if db_field in self.headers.db:
col_index = self.headers.db_list.index(db_field) col_index = self.headers.db_list.index(db_field)
sort_config.append((col_index, order)) sort_config.append((col_index, order))
except Exception as e: except Exception as e:
error(f"Failed to parse sort config: {e}") error(f"- Failed to parse sort config: {e}")
return sort_config return sort_config
def sort_by_logical_fields(self): def sort_by_logical_fields(self):
""" """
Sorts the table using logical field names defined in config. Sorts the table using logical field names defined in config.
""" """
self.horizontal_header.sortIndicatorChanged.disconnect() # Prevent feedback loop debug('sort_by_logical_fields()')
sort_config = self.get_sort_config() sort_config = self.get_sort_config()
debug(f'- retrieved sort_config: {sort_config}')
# Sort in reverse order (primary sort last) # Sort in reverse order (primary sort last)
for col_index, order in reversed(sort_config): for col_index, order in reversed(sort_config):
self.sortByColumn(col_index, order) if order == 0:
new_order = Qt.SortOrder.AscendingOrder
elif order == 1:
new_order = Qt.SortOrder.DescendingOrder
else:
continue
self.sortByColumn(col_index, new_order)
debug(f'- sorted column index {col_index} by {new_order}')
self.model2.layoutChanged.emit() self.model2.layoutChanged.emit()
self.on_sort() debug('- emitted layoutChanged signal')
# self.on_sort()
def get_audio_files_recursively(self, directories: list[str], progress_callback=None) -> list[str]: def get_audio_files_recursively(self, directories: list[str], progress_callback=None) -> list[str]:
"""Scans a directories for files""" """Scans a directories for files"""
@ -1114,10 +1241,14 @@ class MusicTable(QTableView):
converts to model2 index converts to model2 index
stores it stores it
""" """
debug('set_current_song_qmodel_index')
debug(f'got index: {index}')
if index is None: if index is None:
index = self.currentIndex() index = self.currentIndex()
debug(f'new index: {index}')
# map proxy (sortable) model to the original model (used for interactions) # map proxy (sortable) model to the original model (used for interactions)
real_index: QModelIndex = self.proxymodel.mapToSource(index) real_index: QModelIndex = self.proxymodel.mapToSource(index)
debug(f'map index: {real_index}')
self.current_song_qmodel_index = real_index self.current_song_qmodel_index = real_index
def set_selected_song_qmodel_index(self, index: QModelIndex | None = None): def set_selected_song_qmodel_index(self, index: QModelIndex | None = None):
@ -1126,10 +1257,14 @@ class MusicTable(QTableView):
converts to model2 index converts to model2 index
stores it stores it
""" """
debug('set_selected_song_qmodel_index')
debug(f'got index: {index}')
if index is None: if index is None:
index = self.currentIndex() index = self.currentIndex()
debug(f'new index: {index}')
# map proxy (sortable) model to the original model (used for interactions) # map proxy (sortable) model to the original model (used for interactions)
real_index: QModelIndex = self.proxymodel.mapToSource(index) real_index: QModelIndex = self.proxymodel.mapToSource(index)
debug(f'map index: {real_index}')
self.selected_song_qmodel_index = real_index self.selected_song_qmodel_index = real_index
def set_search_string(self, text: str): def set_search_string(self, text: str):
@ -1161,12 +1296,12 @@ class MusicTable(QTableView):
except Exception: except Exception:
pass pass
def disconnect_layout_changed(self): # def disconnect_layout_changed(self):
"""Disconnects the layoutChanged signal from QTableView.model""" # """Disconnects the layoutChanged signal from QTableView.model"""
try: # try:
self.model2.layoutChanged.disconnect() # self.model2.layoutChanged.disconnect()
except Exception: # except Exception:
pass # pass
# def connect_layout_changed(self): # def connect_layout_changed(self):
# """Connects the layoutChanged signal from QTableView.model""" # """Connects the layoutChanged signal from QTableView.model"""

View File

@ -44,8 +44,8 @@ class PlaylistsPane(QTreeWidget):
self.currentItemChanged.connect(self.playlist_clicked) self.currentItemChanged.connect(self.playlist_clicked)
self.playlist_db_id_choice: int | None = None self.playlist_db_id_choice: int | None = None
font: QFont = QFont() font: QFont = QFont()
font.setPointSize(16) font.setPointSize(14)
font.setBold(True) font.setBold(False)
self.setFont(font) self.setFont(font)
def reload_playlists(self, progress_callback=None): def reload_playlists(self, progress_callback=None):

View File

@ -1,4 +1,3 @@
from PyQt5.QtCore import pyqtSignal
from PyQt5.QtWidgets import ( from PyQt5.QtWidgets import (
QAbstractScrollArea, QAbstractScrollArea,
QDialog, QDialog,
@ -11,9 +10,7 @@ from PyQt5.QtWidgets import (
QLabel, QLabel,
QPushButton, QPushButton,
) )
from PyQt5.QtGui import QFont from logging import error
from components.ErrorDialog import ErrorDialog
from logging import debug, error
from pprint import pformat from pprint import pformat

View File

@ -5,7 +5,6 @@ import typing
import DBA import DBA
import qdarktheme import qdarktheme
from PyQt5.QtGui import QFontDatabase from PyQt5.QtGui import QFontDatabase
from PyQt5 import QtCore from PyQt5 import QtCore
from subprocess import run from subprocess import run
# from pyqtgraph import mkBrush # from pyqtgraph import mkBrush

View File

@ -4,7 +4,7 @@ appdirs
pyqt5 pyqt5
pydub pydub
audioop-lts audioop-lts
pyqtdarktheme==2.1.0 pyqtdarktheme-fork
pyqtgraph pyqtgraph
scipy scipy
# pyqtdarktheme-fork; python_version < '3.11' # pyqtdarktheme-fork; python_version < '3.11'

View File

@ -12,7 +12,6 @@ window_size=1152,894
[table] [table]
# Music table user options # Music table user options
columns = title,artist,album,track_number,genre,album_date,codec,length_seconds,filepath columns = title,artist,album,track_number,genre,album_date,codec,length_seconds,filepath
column_widths = 181,116,222,76,74,72,287,150,100
column_ratios = 0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01 column_ratios = 0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01
# 0 = no sort, 1 = ascending, 2 = descending # 0 = no sort, 1 = ascending, 2 = descending
sort_orders = 0,1,1,1,0,0,0,0,0 sort_orders = 0,1,1,1,0,0,0,0,0