diff --git a/app/classes.py b/app/classes.py index 25d8102..fda81b0 100644 --- a/app/classes.py +++ b/app/classes.py @@ -209,9 +209,10 @@ class TrackFileData: Simple class to track details changes to a track file """ - source_file_path: str + new_file_path: str track_id: int = 0 track_path: Optional[str] = None + obsolete_path: Optional[str] = None tags: dict[str, Any] = field(default_factory=dict) audio_metadata: dict[str, str | int | float] = field(default_factory=dict) diff --git a/app/dialogs.py b/app/dialogs.py index 75ff953..36ec626 100644 --- a/app/dialogs.py +++ b/app/dialogs.py @@ -78,18 +78,18 @@ class ReplaceFilesDialog(QDialog): # Work through new files source_dir = self.ui.lblSourceDirectory.text() with db.Session() as session: - for new_basename in os.listdir(source_dir): - new_path = os.path.join(source_dir, new_basename) - if not os.path.isfile(new_path): + for new_file_basename in os.listdir(source_dir): + new_file_path = os.path.join(source_dir, new_file_basename) + if not os.path.isfile(new_file_path): continue - rf = TrackFileData(source_file_path=new_path) - rf.tags = get_tags(new_path) + rf = TrackFileData(new_file_path=new_file_path) + rf.tags = get_tags(new_file_path) if not rf.tags['title'] or not rf.tags['artist']: show_warning( parent=self.main_window, title="Error", msg=( - f"File {new_path} missing tags\n\n:" + f"File {new_file_path} missing tags\n\n:" f"Title={rf.tags['title']}\n" f"Artist={rf.tags['artist']}\n" ), @@ -98,41 +98,52 @@ class ReplaceFilesDialog(QDialog): # Check for same filename match_track = self.check_by_basename( - session, new_path, rf.tags['artist'], rf.tags['title'] + session, new_file_path, rf.tags['artist'], rf.tags['title'] ) if not match_track: match_track = self.check_by_title( - session, new_path, rf.tags['artist'], rf.tags['title'] + session, new_file_path, rf.tags['artist'], rf.tags['title'] ) + if not match_track: - match_track = self.get_fuzzy_match(session, new_basename) + match_track = self.get_fuzzy_match(session, new_file_basename) # Build summary - rf.track_path = os.path.join(Config.REPLACE_FILES_DEFAULT_DESTINATION, - new_basename) if match_track: + # We will store new file in the same directory as the + # existing file but with the new file name + rf.track_path = os.path.join( + os.path.dirname(match_track.path), + new_file_basename + ) + + # We will remove existing track file + rf.obsolete_path = match_track.path + rf.track_id = match_track.id match_basename = os.path.basename(match_track.path) - if match_basename == new_basename: - path_text = " " + new_basename + " (no change)" + if match_basename == new_file_basename: + path_text = " " + new_file_basename + " (no change)" else: - path_text = f" {match_basename} →\n {new_basename}" + path_text = f" {match_basename} →\n {new_file_basename} (replace)" filename_item = QTableWidgetItem(path_text) if match_track.title == rf.tags['title']: title_text = " " + rf.tags['title'] + " (no change)" else: - title_text = f" {match_track.title} →\n {rf.tags['title']}" + title_text = f" {match_track.title} →\n {rf.tags['title']} (update)" title_item = QTableWidgetItem(title_text) if match_track.artist == rf.tags['artist']: artist_text = " " + rf.tags['artist'] + " (no change)" else: - artist_text = f" {match_track.artist} →\n {rf.tags['artist']}" + artist_text = f" {match_track.artist} →\n {rf.tags['artist']} (update)" artist_item = QTableWidgetItem(artist_text) else: - filename_item = QTableWidgetItem(" " + new_basename + " (new)") + rf.track_path = os.path.join(Config.REPLACE_FILES_DEFAULT_DESTINATION, + new_file_basename) + filename_item = QTableWidgetItem(" " + new_file_basename + " (new)") title_item = QTableWidgetItem(" " + rf.tags['title']) artist_item = QTableWidgetItem(" " + rf.tags['artist']) diff --git a/app/musicmuster.py b/app/musicmuster.py index 32d068a..04d5db6 100755 --- a/app/musicmuster.py +++ b/app/musicmuster.py @@ -165,13 +165,13 @@ class ImportTrack(QObject): # Sanity check for tf in track_files: if not tf.tags: - raise Exception(f"ImportTrack: no tags for {tf.source_file_path}") + raise Exception(f"ImportTrack: no tags for {tf.new_file_path}") if not tf.audio_metadata: raise Exception( - f"ImportTrack: no audio_metadata for {tf.source_file_path}" + f"ImportTrack: no audio_metadata for {tf.new_file_path}" ) if tf.track_path is None: - raise Exception(f"ImportTrack: no track_path for {tf.source_file_path}") + raise Exception(f"ImportTrack: no track_path for {tf.new_file_path}") def run(self): """ @@ -181,19 +181,19 @@ class ImportTrack(QObject): with db.Session() as session: for tf in self.track_files: self.signals.status_message_signal.emit( - f"Importing {basename(tf.source_file_path)}", 5000 + f"Importing {basename(tf.new_file_path)}", 5000 ) # Sanity check - if not os.path.exists(tf.source_file_path): - log.error(f"ImportTrack: file not found: {tf.source_file_path=}") + if not os.path.exists(tf.new_file_path): + log.error(f"ImportTrack: file not found: {tf.new_file_path=}") continue # Move the track file. Check that we're not importing a # file that's already in its final destination. - if os.path.exists(tf.track_path) and tf.track_path != tf.source_file_path: + if os.path.exists(tf.track_path) and tf.track_path != tf.new_file_path: os.unlink(tf.track_path) - shutil.move(tf.source_file_path, tf.track_path) + shutil.move(tf.new_file_path, tf.track_path) # Import track try: @@ -1305,10 +1305,18 @@ class Window(QMainWindow, Ui_MainWindow): for rf in dlg.replacement_files: if rf.track_id: # We're updating an existing track + # If the filename has changed, remove the + # existing file + if rf.obsolete_path is not None: + if os.path.exists(rf.obsolete_path): + os.unlink(rf.obsolete_path) + else: + log.error(f"replace_files: could not unlink {rf.obsolete_path=}") + continue if rf.track_path: if os.path.exists(rf.track_path): os.unlink(rf.track_path) - shutil.move(rf.source_file_path, rf.track_path) + shutil.move(rf.new_file_path, rf.track_path) track = session.get(Tracks, rf.track_id) if not track: raise Exception( @@ -1327,16 +1335,17 @@ class Window(QMainWindow, Ui_MainWindow): track.path = "DUMMY" session.commit() track.path = rf.track_path - session.commit() + else: + session.commit() else: # We're importing a new track do_import = self.ok_to_import( session, - os.path.basename(rf.source_file_path), + os.path.basename(rf.new_file_path), rf.tags ) if do_import: - rf.audio_metadata = helpers.get_audio_metadata(rf.source_file_path) + rf.audio_metadata = helpers.get_audio_metadata(rf.new_file_path) import_files.append(rf) # self.import_filenames(dlg.replacement_files)