fixes and idk

This commit is contained in:
billy 2025-08-17 08:20:04 -04:00
parent 69ce4bc763
commit d01a743c45
3 changed files with 92 additions and 71 deletions

View File

@ -75,58 +75,38 @@ class MusicTable(QTableView):
focusEnterSignal = pyqtSignal()
focusLeaveSignal = pyqtSignal()
def focusInEvent(self, e):
"""
Event filter: when self is focused
"""
self.focusEnterSignal.emit()
# arrow keys act normal
super().focusInEvent(e)
def focusOutEvent(self, e):
"""
Event filter: when self becomes unfocused
"""
self.focusLeaveSignal.emit()
def __init__(self, parent=None, application_window=None):
super().__init__(parent)
# why do i need this?
self.application_window = application_window
# NOTE: wtf is actually going on here with the models?
# Create QStandardItemModel
# Create QSortFilterProxyModel
# Set QSortFilterProxyModel source to QStandardItemModel
# Set QTableView model to the Proxy model
# so it looks like this, i guess:
# QTableView model2 = QSortFilterProxyModel(QStandardItemModel)
# need a standard item model to do actions on cells
self.model2: QStandardItemModel = QStandardItemModel()
# proxy model for sorting i guess?
self.proxymodel = QSortFilterProxyModel()
self.proxymodel.setSourceModel(self.model2)
self.setModel(self.proxymodel)
self.setSortingEnabled(True)
self.search_string = None
self.config = ConfigParser()
# Config
cfg_file = (
Path(user_config_dir(appname="musicpom", appauthor="billypom"))
/ "config.ini"
)
self.config = ConfigParser()
self.config.read(cfg_file)
debug(f"music table config: {self.config}")
# Threads
self.threadpool = QThreadPool
# headers class thing
self.headers = HeaderTags()
# NOTE:
# QTableView model2 = QSortFilterProxyModel(QStandardItemModel)
#
# wtf is actually going on here with the models?
# Create QStandardItemModel
# Create QSortFilterProxyModel
# Set QSortFilterProxyModel source to QStandardItemModel
# Set QTableView model to the Proxy model
# so it looks like that, i guess
# need a QStandardItemModel to do actions on cells
self.model2: QStandardItemModel = QStandardItemModel()
self.proxymodel = QSortFilterProxyModel()
self.search_string = None
self.threadpool = QThreadPool
self.headers = HeaderTags()
# db names of headers
self.database_columns = str(self.config["table"]["columns"]).split(",")
self.database_columns: list[str] = str(
self.config["table"]["columns"]).split(",")
self.vertical_scroll_position = 0
self.selected_song_filepath = ""
self.selected_song_qmodel_index: QModelIndex
@ -135,6 +115,11 @@ class MusicTable(QTableView):
self.current_song_qmodel_index: QModelIndex
self.selected_playlist_id: int | None = None
# proxy model for sorting i guess?
self.proxymodel.setSourceModel(self.model2)
self.setModel(self.proxymodel)
self.setSortingEnabled(True)
# Properties
self.setAcceptDrops(True)
self.setHorizontalScrollBarPolicy(
@ -175,6 +160,20 @@ class MusicTable(QTableView):
# | |
# |_________________|
def focusInEvent(self, e):
"""
Event filter: when self is focused
"""
self.focusEnterSignal.emit()
# arrow keys act normal
super().focusInEvent(e)
def focusOutEvent(self, e):
"""
Event filter: when self becomes unfocused
"""
self.focusLeaveSignal.emit()
def resizeEvent(self, e: typing.Optional[QResizeEvent]) -> None:
"""Do something when the QTableView is resized"""
if e is None:
@ -490,7 +489,8 @@ class MusicTable(QTableView):
"""
worker = Worker(add_files_to_database, files)
_ = worker.signals.signal_progress.connect(self.qapp.handle_progress)
_ = worker.signals.signal_result.connect(self.on_add_files_to_database_finished)
_ = worker.signals.signal_result.connect(
self.on_add_files_to_database_finished)
worker.signals.signal_finished.connect(self.load_music_table)
if self.qapp:
threadpool = self.qapp.threadpool
@ -660,7 +660,7 @@ class MusicTable(QTableView):
def reorganize_files(self, filepaths, progress_callback=None):
"""
Reorganizes files into Artist/Album/Song,
based on self.config['directories'][reorganize_destination']
based on self.config['settings'][reorganize_destination']
"""
debug("reorganizing files")
# FIXME: batch update, instead of doing 1 file at a time
@ -671,7 +671,7 @@ class MusicTable(QTableView):
# FIXME: change reorganize location in config, try to reorganize, failed - old reference
# Get target directory
target_dir = str(self.config["directories"]["reorganize_destination"])
target_dir = str(self.config["settings"]["reorganize_destination"])
for filepath in filepaths:
# Read file metadata
artist, album = get_reorganize_vars(filepath)
@ -737,7 +737,8 @@ class MusicTable(QTableView):
self.selected_playlist_id = playlist_id[0]
try:
with DBA.DBAccess() as db:
query = f"SELECT id, {fields} FROM song JOIN song_playlist sp ON id = sp.song_id WHERE sp.playlist_id = ?"
query = f"SELECT id, {
fields} FROM song JOIN song_playlist sp ON id = sp.song_id WHERE sp.playlist_id = ?"
# fulltext search
if self.search_string:
# params = 3 * [self.search_string]
@ -821,7 +822,8 @@ class MusicTable(QTableView):
db_name: str = self.config.get("settings", "db").split("/").pop()
db_filename = self.config.get("settings", "db")
self.playlistStatsSignal.emit(
f"Songs: {row_count} | Total time: {total_time} | {db_name} | {db_filename}"
f"Songs: {row_count} | Total time: {
total_time} | {db_name} | {db_filename}"
)
self.loadMusicTableSignal.emit()
self.connect_data_changed()

70
main.py
View File

@ -57,6 +57,8 @@ from utils import (
add_files_to_database,
set_album_art,
id3_remap,
get_album_art,
Worker
)
from components import (
HeaderTags,
@ -68,9 +70,6 @@ from components import (
ExportPlaylistWindow,
SearchLineEdit,
)
from utils.get_album_art import get_album_art
# from utils.Worker import Worker
from utils import Worker
# good help with signals slots in threads
# https://stackoverflow.com/questions/52993677/how-do-i-setup-signals-and-slots-in-pyqt-with-qthreads-in-both-directions
@ -162,18 +161,23 @@ class ApplicationWindow(QMainWindow, Ui_MainWindow):
self.playbackSlider.sliderReleased.connect(
lambda: self.player.setPosition(self.playbackSlider.value())
) # sliderReleased works better than sliderMoved
self.volumeSlider.sliderMoved[int].connect(lambda: self.on_volume_changed())
self.volumeSlider.sliderMoved[int].connect(
lambda: self.on_volume_changed())
self.speedSlider.sliderMoved.connect(
lambda: self.on_speed_changed(self.speedSlider.value())
)
# self.speedSlider.doubleClicked.connect(lambda: self.on_speed_changed(1))
self.playButton.clicked.connect(self.on_play_clicked) # Click to play/pause
self.playButton.clicked.connect(
self.on_play_clicked) # Click to play/pause
self.previousButton.clicked.connect(self.on_prev_clicked)
self.nextButton.clicked.connect(self.on_next_clicked) # Click to next song
self.nextButton.clicked.connect(
self.on_next_clicked) # Click to next song
# FILE MENU
self.actionOpenFiles.triggered.connect(self.open_files) # Open files window
self.actionNewPlaylist.triggered.connect(self.playlistTreeView.create_playlist)
self.actionOpenFiles.triggered.connect(
self.open_files) # Open files window
self.actionNewPlaylist.triggered.connect(
self.playlistTreeView.create_playlist)
self.actionExportPlaylist.triggered.connect(self.export_playlist)
# EDIT MENU
@ -195,14 +199,16 @@ class ApplicationWindow(QMainWindow, Ui_MainWindow):
self.lineEditSearch: QLineEdit
# CONNECTIONS
self.lineEditSearch.textTypedSignal.connect(self.handle_search_box_text)
self.lineEditSearch.textTypedSignal.connect(
self.handle_search_box_text)
# tableView
self.tableView.playSignal.connect(self.play_audio_file)
self.tableView.playPauseSignal.connect(
self.on_play_clicked
) # Spacebar toggle play/pause signal
self.tableView.handleProgressSignal.connect(self.handle_progress)
self.tableView.searchBoxSignal.connect(self.handle_search_box_visibility)
self.tableView.searchBoxSignal.connect(
self.handle_search_box_visibility)
self.tableView.playlistStatsSignal.connect(
self.set_permanent_status_bar_message
)
@ -213,7 +219,8 @@ class ApplicationWindow(QMainWindow, Ui_MainWindow):
self.playlistTreeView.playlistChoiceSignal.connect(
self.tableView.load_music_table
)
self.playlistTreeView.allSongsSignal.connect(self.tableView.load_music_table)
self.playlistTreeView.allSongsSignal.connect(
self.tableView.load_music_table)
# albumGraphicsView
self.albumGraphicsView.albumArtDropped.connect(
@ -315,7 +322,7 @@ class ApplicationWindow(QMainWindow, Ui_MainWindow):
current_real_index = self.tableView.current_song_qmodel_index
try:
index = self.tableView.proxymodel.mapFromSource(current_real_index)
except:
except Exception:
return
row: int = index.row()
prev_row: int = row - 1
@ -392,7 +399,8 @@ class ApplicationWindow(QMainWindow, Ui_MainWindow):
def load_config(self) -> None:
"""does what it says"""
cfg_file = (
Path(user_config_dir(appname="musicpom", appauthor="billypom")) / "config.ini"
Path(user_config_dir(appname="musicpom",
appauthor="billypom")) / "config.ini"
)
self.config.read(cfg_file)
debug("load_config()")
@ -470,7 +478,8 @@ class ApplicationWindow(QMainWindow, Ui_MainWindow):
selected_songs = self.tableView.get_selected_songs_filepaths()
for song in selected_songs:
debug(
f"main.py set_album_art_for_selected_songs() | updating album art for {song}"
f"main.py set_album_art_for_selected_songs() | updating album art for {
song}"
)
set_album_art(song, album_art_path)
@ -497,7 +506,8 @@ class ApplicationWindow(QMainWindow, Ui_MainWindow):
self.playbackSlider.setMaximum(self.player.duration())
slider_position = self.player.position()
self.playbackSlider.setValue(slider_position)
current_minutes, current_seconds = divmod(slider_position / 1000, 60)
current_minutes, current_seconds = divmod(
slider_position / 1000, 60)
duration_minutes, duration_seconds = divmod(
self.player.duration() / 1000, 60
)
@ -548,7 +558,8 @@ class ApplicationWindow(QMainWindow, Ui_MainWindow):
def create_playlist(self) -> None:
"""Creates a database record for a playlist, given a name"""
window = CreatePlaylistWindow(self.playlistCreatedSignal)
window.playlistCreatedSignal.connect(self.add_latest_playlist_to_tree) # type: ignore
window.playlistCreatedSignal.connect(
self.add_latest_playlist_to_tree) # type: ignore
window.exec_()
def import_playlist(self) -> None:
@ -574,8 +585,10 @@ class ApplicationWindow(QMainWindow, Ui_MainWindow):
preferences_window = PreferencesWindow(
self.reloadConfigSignal, self.reloadDatabaseSignal
)
preferences_window.reloadConfigSignal.connect(self.load_config) # type: ignore
preferences_window.reloadDatabaseSignal.connect(self.tableView.load_music_table) # type: ignore
preferences_window.reloadConfigSignal.connect(
self.load_config) # type: ignore
preferences_window.reloadDatabaseSignal.connect(
self.tableView.load_music_table) # type: ignore
preferences_window.exec_() # Display the preferences window modally
# Quick Actions
@ -609,9 +622,11 @@ def update_database_file() -> bool:
Reads the database file (specified by config file)
"""
cfg_file = (
Path(user_config_dir(appname="musicpom", appauthor="billypom")) / "config.ini"
Path(user_config_dir(appname="musicpom",
appauthor="billypom")) / "config.ini"
)
cfg_path = str(Path(user_config_dir(appname="musicpom", appauthor="billypom")))
cfg_path = str(Path(user_config_dir(
appname="musicpom", appauthor="billypom")))
config = ConfigParser()
config.read(cfg_file)
db_filepath: str = config.get("settings", "db")
@ -620,9 +635,10 @@ def update_database_file() -> bool:
if not db_filepath.startswith(cfg_path):
new_path = f"{cfg_path}/{db_filepath}"
debug(
f"Set new config [db] database path: \n> Current: {db_filepath}\n> New:{new_path}"
f"Set new config [db] database path: \n> Current: {
db_filepath}\n> New:{new_path}"
)
config["db"]["database"] = new_path
config["settings"]["db"] = new_path
# Save the config
with open(cfg_file, "w") as configfile:
config.write(configfile)
@ -654,9 +670,11 @@ def update_config_file() -> ConfigParser:
If the user config file is not up to date, update it with examples from sample config
"""
cfg_file = (
Path(user_config_dir(appname="musicpom", appauthor="billypom")) / "config.ini"
Path(user_config_dir(appname="musicpom",
appauthor="billypom")) / "config.ini"
)
cfg_path = str(Path(user_config_dir(appname="musicpom", appauthor="billypom")))
cfg_path = str(Path(user_config_dir(
appname="musicpom", appauthor="billypom")))
# If config path doesn't exist, create it
if not os.path.exists(cfg_path):
@ -720,8 +738,8 @@ if __name__ == "__main__":
app = QApplication(sys.argv)
clipboard = app.clipboard()
# Dark theme >:3
qdarktheme.setup_theme()
# qdarktheme.setup_theme("auto") # this is supposed to work but doesnt
# qdarktheme.setup_theme()
qdarktheme.setup_theme("auto") # this is supposed to work but doesnt
# Show the UI
ui = ApplicationWindow(clipboard)
# window size

View File

@ -3,7 +3,8 @@ matplotlib
appdirs
pyqt5
pydub
pyqtdarktheme-fork; python_version > '3.11'
pyqtdarktheme; python_version < '3.12'
audioop-lts
pyqtdarktheme-fork; python_version < '3.11'
pyqtdarktheme; python_version > '3.12'
pyqtgraph
scipy