From df2652e6ccdc393032f588c6cbabc5a39f3a835c Mon Sep 17 00:00:00 2001 From: Keith Edmunds Date: Tue, 7 Feb 2023 21:25:16 +0000 Subject: [PATCH] Import tracks in QThread Allows progress messages to be sent Fixes #164 --- app/musicmuster.py | 77 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 61 insertions(+), 16 deletions(-) diff --git a/app/musicmuster.py b/app/musicmuster.py index 94c114c..6992ef5 100755 --- a/app/musicmuster.py +++ b/app/musicmuster.py @@ -1,6 +1,7 @@ #!/usr/bin/env python from log import log +from os.path import basename import argparse import stackprinter # type: ignore import subprocess @@ -20,8 +21,10 @@ from PyQt5.QtCore import ( pyqtSignal, QDate, QEvent, + QObject, Qt, QSize, + QThread, QTime, QTimer, ) @@ -209,6 +212,42 @@ class PlaylistTrack: self.start_time + timedelta(milliseconds=self.duration)) +class ImportTrack(QObject): + import_error = pyqtSignal(str) + importing = pyqtSignal(str) + finished = pyqtSignal(PlaylistTab) + + def __init__(self, playlist: PlaylistTab, filenames: list) -> None: + super().__init__() + self.filenames = filenames + self.playlist = playlist + + def run(self): + """ + Create track objects from passed files and add to visible playlist + """ + + with Session() as session: + for fname in self.filenames: + self.importing.emit(f"Importing {basename(fname)}") + try: + track = Tracks(session, fname) + except ValueError: + self.import_error.emit(basename(fname)) + continue + helpers.set_track_metadata(session, track) + helpers.normalise_track(track.path) + self.playlist.insert_track(session, track) + # We're importing potentially multiple tracks in a loop. + # If there's an error adding the track to the Tracks + # table, the session will rollback, thus losing any + # previous additions in this loop. So, commit now to + # lock in what we've just done. + session.commit() + self.playlist.save_playlist(session) + self.finished.emit(self.playlist) + + class Window(QMainWindow, Ui_MainWindow): def __init__(self, parent=None, *args, **kwargs) -> None: super().__init__(*args, **kwargs) @@ -806,7 +845,7 @@ class Window(QMainWindow, Ui_MainWindow): for fname in dlg.selectedFiles(): txt = "" tags = helpers.get_tags(fname) - new_tracks.append((fname, tags)) + new_tracks.append(fname) title = tags['title'] artist = tags['artist'] count = 0 @@ -834,26 +873,32 @@ class Window(QMainWindow, Ui_MainWindow): return # Import in separate thread - thread = threading.Thread(target=self._import_tracks, - args=(new_tracks,)) - thread.start() + self.import_thread = QThread() + self.worker = ImportTrack(self.visible_playlist_tab(), new_tracks) + self.worker.moveToThread(self.import_thread) + self.import_thread.started.connect(self.worker.run) + self.worker.finished.connect(self.import_thread.quit) + self.worker.finished.connect(self.worker.deleteLater) + self.import_thread.finished.connect(self.import_thread.deleteLater) + self.worker.import_error.connect( + lambda msg: helpers.show_warning( + "Import error", "Error importing " + msg + ) + ) + self.worker.importing.connect( + lambda msg: self.statusbar.showMessage("Importing " + msg, 5000) + ) + self.worker.finished.connect(self.import_complete) + self.import_thread.start() - def _import_tracks(self, tracks: list): + def import_complete(self, playlist_tab: PlaylistTab): """ - Create track objects from passed files and add to visible playlist + Called by thread when track import complete """ + self.statusbar.showMessage("Imports complete") with Session() as session: - for (fname, tags) in tracks: - try: - track = Tracks(session, fname) - except ValueError: - # Error adding track to database - continue - helpers.set_track_metadata(session, track) - helpers.normalise_track(track.path) - self.visible_playlist_tab().insert_track(session, track) - self.visible_playlist_tab().save_playlist(session) + playlist_tab.update_display(session) def insert_header(self) -> None: """Show dialog box to enter header text and add to playlist"""