Fix Add Files flow: manual source files now persist across scans

- Add self.library_source_files list to store manually added file paths
- _on_library_add_files now adds to library_source_files instead of
  calling _scan_library() (which would clear the list)
- _refresh_source_ui merges scanned sources + library_source_files
  with dedup by path. All items get proper UserRole data.
- _on_library_remove_selected now removes from library_source_files too
- Previously added files would be lost on every scan because
  _scan_library() called .clear() on the source list
This commit is contained in:
Maksim Totmin 2026-05-31 15:15:07 +07:00
parent ea5f9d038b
commit a2d92b75e0

View File

@ -216,6 +216,7 @@ class MainWindow(QMainWindow):
self.worker_thread = None self.worker_thread = None
self.downloaded_tracks: List[TrackInfo] = [] self.downloaded_tracks: List[TrackInfo] = []
self.library_ready: List[Dict] = [] self.library_ready: List[Dict] = []
self.library_source_files: List[str] = []
self.ipod_devices: List[Dict] = [] self.ipod_devices: List[Dict] = []
self.current_mount_point: Optional[str] = None self.current_mount_point: Optional[str] = None
@ -560,15 +561,54 @@ class MainWindow(QMainWindow):
self.library_status.setText("No tracks ready — convert source files or download") self.library_status.setText("No tracks ready — convert source files or download")
self.library_transfer_btn.setEnabled(False) self.library_transfer_btn.setEnabled(False)
def _refresh_source_ui(self, sources): def _refresh_source_ui(self, scanned_sources):
"""Build the Source Files list by combining scanned files + manual additions.
Deduplicates by path. All items get UserRole data for _get_selected_source_files().
"""
self.library_source_list.clear() self.library_source_list.clear()
for src in sorted(sources, key=lambda s: (s["artist"], s["title"])):
seen_paths = set()
all_sources = []
for src in scanned_sources:
path = src.get("path", "")
if path and path not in seen_paths and os.path.exists(path):
seen_paths.add(path)
all_sources.append(src)
for fpath in self.library_source_files:
if fpath in seen_paths:
continue
if not os.path.exists(fpath):
continue
fname = os.path.basename(fpath)
size = os.path.getsize(fpath)
try:
handler = MetadataHandler()
info = handler.extract_tags(fpath)
title = info.title if info else fname
artist = info.artist if info else "Unknown"
except Exception:
title = fname
artist = "Unknown"
src = {
"path": fpath,
"title": title,
"artist": artist,
"size": size,
}
all_sources.append(src)
seen_paths.add(fpath)
for src in sorted(all_sources, key=lambda s: (s["artist"], s["title"])):
display = f"{src['artist']}{src['title']} {self._format_size(src['size'])}" display = f"{src['artist']}{src['title']} {self._format_size(src['size'])}"
item = QListWidgetItem(display) item = QListWidgetItem(display)
item.setData(Qt.ItemDataRole.UserRole, src) item.setData(Qt.ItemDataRole.UserRole, src)
self.library_source_list.addItem(item) self.library_source_list.addItem(item)
count = len(sources) count = len(all_sources)
if count: if count:
self.library_convert_btn.setEnabled(True) self.library_convert_btn.setEnabled(True)
else: else:
@ -620,15 +660,19 @@ class MainWindow(QMainWindow):
self._scan_library() self._scan_library()
def _on_library_add_files(self): def _on_library_add_files(self):
audio_filter = "Audio Files (*.flac *.wav *.ogg *.opus *.wma *.ape *.aiff *.alac)" source_filter = "Audio Files (*.flac *.wav *.ogg *.opus *.wma *.ape *.aiff *.alac)"
files, _ = QFileDialog.getOpenFileNames( files, _ = QFileDialog.getOpenFileNames(
self, "Select Audio Files", "", audio_filter self, "Select Audio Files", "", source_filter
) )
new_files = []
for f in files: for f in files:
existing = self.library_source_list.findItems(f, Qt.MatchFlag.MatchExactly) ext = os.path.splitext(f)[1].lower()
if not existing: if ext in SOURCE_EXTS and os.path.exists(f) and f not in self.library_source_files:
self.library_source_list.addItem(f) self.library_source_files.append(f)
self._scan_library() new_files.append(f)
if new_files:
self._refresh_source_ui([])
def _on_library_remove_selected(self): def _on_library_remove_selected(self):
"""Delete selected files from disk and clean up empty directories.""" """Delete selected files from disk and clean up empty directories."""
@ -666,6 +710,8 @@ class MainWindow(QMainWindow):
try: try:
os.remove(path) os.remove(path)
deleted += 1 deleted += 1
if path in self.library_source_files:
self.library_source_files.remove(path)
parent = os.path.dirname(path) parent = os.path.dirname(path)
while parent != os.path.dirname(parent): while parent != os.path.dirname(parent):
if os.listdir(parent): if os.listdir(parent):