This commit is contained in:
2026-01-11 01:04:39 -08:00
parent 7c1959483f
commit 61ab690604
2 changed files with 32 additions and 14 deletions

View File

@@ -208,7 +208,7 @@ class API_folder_store:
Args: Args:
library_root: Path to the local library root directory library_root: Path to the local library root directory
""" """
self.library_root = expand_path(library_root) self.library_root = expand_path(library_root).resolve()
self.db_path = self.library_root / self.DB_NAME self.db_path = self.library_root / self.DB_NAME
self.connection: Optional[sqlite3.Connection] = None self.connection: Optional[sqlite3.Connection] = None
# sqlite3 connections are not safe for concurrent use across threads. # sqlite3 connections are not safe for concurrent use across threads.
@@ -218,14 +218,24 @@ class API_folder_store:
self._init_db() self._init_db()
def _normalize_input_path(self, file_path: Path) -> Path: def _normalize_input_path(self, file_path: Path) -> Path:
p = expand_path(file_path) p = expand_path(file_path).resolve()
if not p.is_absolute(): # If the path is relative to the current working directory, we check if it's meant to be in the library_root.
# Check if it already seems to start with library_root but just wasn't absolute # However, because we call .resolve() above, it's already absolute relative to CWD if it was relative.
# (e.g. library_root is "C:\foo" and p is "foo\bar" which might happen in some cases) # But we want it to be absolute relative to library_root if it's not absolute or if it exists in library_root.
# though usually it's better to just join.
# But the recursive case happened because library_root was "$home/files" (not absolute) # If it's already under library_root, we are done.
# and p was "$home/files/..." (not absolute). try:
p = self.library_root / p p.relative_to(self.library_root)
return p
except ValueError:
pass
# If it was a relative path (unresolved), we should have joined it before resolving.
# Let's re-expand without resolve to check if it's absolute.
raw_p = expand_path(file_path)
if not raw_p.is_absolute():
return (self.library_root / raw_p).resolve()
return p return p
def _to_db_file_path(self, file_path: Path) -> str: def _to_db_file_path(self, file_path: Path) -> str:
@@ -2349,8 +2359,8 @@ class DatabaseAPI:
"""Query API wrapper for LocalLibraryDB providing specialized search methods.""" """Query API wrapper for LocalLibraryDB providing specialized search methods."""
def __init__(self, search_dir: Path): def __init__(self, search_dir: Path):
self.search_dir = search_dir self.search_dir = expand_path(search_dir).resolve()
self.db = API_folder_store(search_dir) self.db = API_folder_store(self.search_dir)
def __enter__(self): def __enter__(self):
self.db.__enter__() self.db.__enter__()
@@ -2749,8 +2759,8 @@ class LocalLibraryInitializer:
def __init__(self, library_root: Path): def __init__(self, library_root: Path):
"""Initialize the database scanner.""" """Initialize the database scanner."""
self.library_root = Path(library_root) self.library_root = expand_path(library_root).resolve()
self.db = API_folder_store(library_root) self.db = API_folder_store(self.library_root)
self.stats = { self.stats = {
"files_scanned": 0, "files_scanned": 0,
"files_new": 0, "files_new": 0,

View File

@@ -37,7 +37,15 @@ def expand_path(p: str | Path | None) -> Path:
"""Expand ~ and environment variables in path.""" """Expand ~ and environment variables in path."""
if p is None: if p is None:
return None # type: ignore return None # type: ignore
expanded = os.path.expandvars(str(p)) s = str(p)
# Courtesy check for $home -> $HOME if we're on a POSIX-like system
# (where env vars are case-sensitive)
if os.name != 'nt' and '$home' in s and '$HOME' not in os.environ:
# If $home is literally used in config but only HOME is defined
if 'HOME' in os.environ:
s = s.replace('$home', '$HOME')
expanded = os.path.expandvars(s)
return Path(expanded).expanduser() return Path(expanded).expanduser()