Version 15
This commit is contained in:
@@ -191,40 +191,42 @@ class LibraryWatcher:
|
||||
def _full_scan_library(self, library_id: int, library_path: str):
|
||||
"""
|
||||
Sammenligner filer på disk med SQLite og synkroniserer forskelle.
|
||||
|
||||
Tre operationer:
|
||||
1. Nye filer → indsæt i SQLite
|
||||
2. Ændrede filer → opdater SQLite (baseret på fil-timestamp)
|
||||
3. Forsvundne → marker som missing i SQLite
|
||||
Håndterer utilgængelige mapper og symlinks sikkert.
|
||||
"""
|
||||
logger.info(f"Fuld scan starter: {library_path}")
|
||||
base = Path(library_path)
|
||||
|
||||
# Hvad SQLite kender til
|
||||
known = get_all_song_paths_for_library(library_id)
|
||||
# Tjek at mappen faktisk er tilgængelig — med timeout
|
||||
if not self._path_accessible(base):
|
||||
logger.warning(f"Bibliotek ikke tilgængeligt (timeout eller ingen adgang): {library_path}")
|
||||
return
|
||||
|
||||
# Hvad der faktisk er på disk
|
||||
known = get_all_song_paths_for_library(library_id)
|
||||
found_paths = set()
|
||||
processed = 0
|
||||
errors = 0
|
||||
|
||||
for file_path in base.rglob("*"):
|
||||
if not file_path.is_file() or not is_supported(file_path):
|
||||
continue
|
||||
|
||||
path_str = str(file_path)
|
||||
found_paths.add(path_str)
|
||||
disk_modified = get_file_modified_at(file_path)
|
||||
|
||||
# Ny fil eller ændret siden sidst
|
||||
if path_str not in known or known[path_str] != disk_modified:
|
||||
import os
|
||||
for dirpath, dirnames, filenames in os.walk(
|
||||
str(base), followlinks=False,
|
||||
onerror=lambda e: logger.warning(f"Adgang nægtet: {e}")
|
||||
):
|
||||
for filename in filenames:
|
||||
file_path = Path(dirpath) / filename
|
||||
try:
|
||||
tags = read_tags(file_path)
|
||||
tags["library_id"] = library_id
|
||||
upsert_song(tags)
|
||||
processed += 1
|
||||
if self.on_change:
|
||||
self.on_change("upserted", path_str, None)
|
||||
if not is_supported(file_path):
|
||||
continue
|
||||
path_str = str(file_path)
|
||||
found_paths.add(path_str)
|
||||
disk_modified = get_file_modified_at(file_path)
|
||||
|
||||
if path_str not in known or known[path_str] != disk_modified:
|
||||
tags = read_tags(file_path)
|
||||
tags["library_id"] = library_id
|
||||
upsert_song(tags)
|
||||
processed += 1
|
||||
if self.on_change:
|
||||
self.on_change("upserted", path_str, None)
|
||||
except Exception as e:
|
||||
logger.error(f"Scan-fejl for {file_path}: {e}")
|
||||
errors += 1
|
||||
@@ -244,6 +246,20 @@ class LibraryWatcher:
|
||||
f"{processed} opdateret, {missing_count} mangler, {errors} fejl"
|
||||
)
|
||||
|
||||
def _path_accessible(self, path: Path, timeout_sec: float = 5.0) -> bool:
|
||||
"""Tjek om en sti er tilgængelig inden for timeout."""
|
||||
import threading
|
||||
result = [False]
|
||||
def check():
|
||||
try:
|
||||
result[0] = path.exists() and path.is_dir()
|
||||
except Exception:
|
||||
result[0] = False
|
||||
t = threading.Thread(target=check, daemon=True)
|
||||
t.start()
|
||||
t.join(timeout=timeout_sec)
|
||||
return result[0]
|
||||
|
||||
|
||||
# ── Singleton til brug i appen ────────────────────────────────────────────────
|
||||
|
||||
|
||||
Reference in New Issue
Block a user