refactor: DLO-16/17/18/20 — CLI simplification, config Pydantic, planner split, type system unification
DLO-16: Reduce cli.py from 1073 to 83 lines by registering Click commands from commands/*.py modules DLO-17: Migrate Config to Pydantic BaseModel for validation DLO-18: Split planner.py (826 lines) into orchestration, path rendering, and duplicate handling modules DLO-20: Unify type system — convert 14 dataclasses to Pydantic BaseModel, keep TypedDicts as JSON schema hints Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.5
parent
8a60aaf9a9
commit
fe03a31dd4
+2
-74
@@ -1,7 +1,7 @@
|
||||
"""Inventory scanner for discovering and cataloging video files.
|
||||
|
||||
This module implements the core scanning functionality for the Video Library Manager,
|
||||
including file discovery via `find`, metadata extraction, and categorization based on
|
||||
including file discovery, metadata extraction, and categorization based on
|
||||
directory structure.
|
||||
"""
|
||||
|
||||
@@ -143,79 +143,7 @@ def scan_library(
|
||||
|
||||
|
||||
def _discover_video_paths(root: Path, video_extensions: list[str]) -> list[Path]:
|
||||
"""Discover matching video files under root.
|
||||
|
||||
Uses the system `find` command for traversal speed and falls back to Python
|
||||
recursion if `find` is unavailable.
|
||||
"""
|
||||
try:
|
||||
return _discover_video_paths_with_find(root, video_extensions)
|
||||
except FileNotFoundError:
|
||||
logger.warning("`find` command not available - falling back to Python recursion")
|
||||
return _discover_video_paths_recursive(root, video_extensions)
|
||||
|
||||
|
||||
def _log_find_nonzero_exit(returncode: int, stderr_text: str, discovered_count: int) -> None:
|
||||
"""Log the explicit contract for non-zero `find` exits.
|
||||
|
||||
Contract: if `find` emits partial stdout before failing, keep those paths and
|
||||
continue with a warning. If no paths were emitted, return an empty result and
|
||||
log that scan discovery was incomplete.
|
||||
"""
|
||||
stderr_suffix = f": {stderr_text}" if stderr_text else ""
|
||||
if discovered_count > 0:
|
||||
logger.warning(
|
||||
"find exited with code %s; using %s partial scan result(s)%s",
|
||||
returncode,
|
||||
discovered_count,
|
||||
stderr_suffix,
|
||||
)
|
||||
else:
|
||||
logger.warning(
|
||||
"find exited with code %s and produced no scan results%s",
|
||||
returncode,
|
||||
stderr_suffix,
|
||||
)
|
||||
|
||||
|
||||
def _discover_video_paths_with_find(root: Path, video_extensions: list[str]) -> list[Path]:
|
||||
"""Discover matching video files using the system `find` command."""
|
||||
normalized_extensions = [ext.lower() for ext in video_extensions if ext]
|
||||
if not normalized_extensions:
|
||||
return []
|
||||
|
||||
command: list[str] = ["find", str(root), "-type", "f", "("]
|
||||
for index, extension in enumerate(normalized_extensions):
|
||||
if index > 0:
|
||||
command.append("-o")
|
||||
command.extend(["-iname", f"*{extension}"])
|
||||
command.extend([")", "-print0"])
|
||||
|
||||
process = subprocess.Popen(
|
||||
command,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE
|
||||
)
|
||||
stdout, stderr = process.communicate()
|
||||
|
||||
discovered_paths: list[Path] = []
|
||||
for path_bytes in stdout.split(b"\0"):
|
||||
if not path_bytes:
|
||||
continue
|
||||
file_path = Path(os.fsdecode(path_bytes))
|
||||
if _is_hidden_path(file_path, root):
|
||||
continue
|
||||
discovered_paths.append(file_path)
|
||||
|
||||
if process.returncode != 0:
|
||||
stderr_text = stderr.decode(errors="replace").strip()
|
||||
_log_find_nonzero_exit(process.returncode, stderr_text, len(discovered_paths))
|
||||
|
||||
return discovered_paths
|
||||
|
||||
|
||||
def _discover_video_paths_recursive(root: Path, video_extensions: list[str]) -> list[Path]:
|
||||
"""Fallback discovery using Python directory traversal."""
|
||||
"""Discover matching video files under root using os.scandir recursion."""
|
||||
discovered_paths: list[Path] = []
|
||||
for file_path in _scan_directory_recursive(root, video_extensions):
|
||||
if _is_hidden_path(file_path, root):
|
||||
|
||||
Reference in New Issue
Block a user