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:
parent
ea5f9d038b
commit
a2d92b75e0
64
src/main.py
64
src/main.py
@ -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):
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user