diff --git a/alfred/application/filesystem/manage_subtitles.py b/alfred/application/filesystem/manage_subtitles.py index 0872548..e2e307b 100644 --- a/alfred/application/filesystem/manage_subtitles.py +++ b/alfred/application/filesystem/manage_subtitles.py @@ -10,7 +10,11 @@ from alfred.domain.subtitles.knowledge.loader import KnowledgeLoader from alfred.domain.subtitles.services.identifier import SubtitleIdentifier from alfred.domain.subtitles.services.matcher import SubtitleMatcher from alfred.domain.subtitles.services.pattern_detector import PatternDetector -from alfred.domain.subtitles.services.placer import PlacedTrack, SubtitlePlacer +from alfred.domain.subtitles.services.placer import ( + PlacedTrack, + SubtitlePlacer, + _build_dest_name, +) from alfred.domain.subtitles.services.utils import available_subtitles from alfred.domain.subtitles.value_objects import ScanStrategy from alfred.infrastructure.persistence.context import get_memory @@ -174,8 +178,6 @@ class ManageSubtitlesUseCase: # --- Dry run: skip placement --- if dry_run: - from alfred.domain.subtitles.services.placer import _build_dest_name - placed_dtos = [] for t in matched: if not t.file_path: diff --git a/alfred/domain/release/knowledge.py b/alfred/domain/release/knowledge.py index f97de06..63d62e8 100644 --- a/alfred/domain/release/knowledge.py +++ b/alfred/domain/release/knowledge.py @@ -111,7 +111,7 @@ def load_editions() -> dict: def load_sources_extra() -> set[str]: """Additional source tokens from site files.""" - return {t for t in _load_sites().get("sources", [])} + return set(_load_sites().get("sources", [])) def load_hdr_extra() -> set[str]: diff --git a/alfred/domain/release/value_objects.py b/alfred/domain/release/value_objects.py index 83af56c..4b18853 100644 --- a/alfred/domain/release/value_objects.py +++ b/alfred/domain/release/value_objects.py @@ -65,11 +65,6 @@ def _strip_episode_from_normalized(normalized: str) -> str: return ".".join(result) -# Keep old names as aliases for backward compatibility during the US English migration -_sanitise_for_fs = _sanitize_for_fs -_strip_episode_from_normalised = _strip_episode_from_normalized - - @dataclass class ParsedRelease: """Structured representation of a parsed release name.""" diff --git a/alfred/domain/shared/knowledge/language_registry.py b/alfred/domain/shared/knowledge/language_registry.py index e7fb264..9911b1d 100644 --- a/alfred/domain/shared/knowledge/language_registry.py +++ b/alfred/domain/shared/knowledge/language_registry.py @@ -11,12 +11,12 @@ from pathlib import Path import yaml +import alfred as _alfred_pkg + from ..value_objects import Language logger = logging.getLogger(__name__) -import alfred as _alfred_pkg - _BUILTIN_ROOT = Path(_alfred_pkg.__file__).parent / "knowledge" _LEARNED_ROOT = Path(_alfred_pkg.__file__).parent.parent / "data" / "knowledge" diff --git a/alfred/domain/subtitles/knowledge/loader.py b/alfred/domain/subtitles/knowledge/loader.py index 6528154..23f1e65 100644 --- a/alfred/domain/subtitles/knowledge/loader.py +++ b/alfred/domain/subtitles/knowledge/loader.py @@ -5,10 +5,10 @@ from pathlib import Path import yaml -logger = logging.getLogger(__name__) - import alfred as _alfred_pkg +logger = logging.getLogger(__name__) + # Builtin knowledge — anchored on the alfred package itself, not on this file's depth _BUILTIN_ROOT = Path(_alfred_pkg.__file__).parent / "knowledge" diff --git a/alfred/domain/subtitles/services/identifier.py b/alfred/domain/subtitles/services/identifier.py index 276eb83..6118001 100644 --- a/alfred/domain/subtitles/services/identifier.py +++ b/alfred/domain/subtitles/services/identifier.py @@ -110,6 +110,7 @@ class SubtitleIdentifier: capture_output=True, text=True, timeout=30, + check=False, ) data = json.loads(result.stdout) except ( @@ -127,7 +128,6 @@ class SubtitleIdentifier: tags = stream.get("tags", {}) disposition = stream.get("disposition", {}) lang_code = tags.get("language", "") - title = tags.get("title", "") lang = self.kb.language_for_token(lang_code) if lang_code else None @@ -320,7 +320,7 @@ class SubtitleIdentifier: lang_groups.setdefault(key, []).append(track) result = [] - for lang_code, group in lang_groups.items(): + for group in lang_groups.values(): if len(group) == 1: result.extend(group) continue diff --git a/alfred/domain/subtitles/services/pattern_detector.py b/alfred/domain/subtitles/services/pattern_detector.py index 6b94ebd..e8f2bd1 100644 --- a/alfred/domain/subtitles/services/pattern_detector.py +++ b/alfred/domain/subtitles/services/pattern_detector.py @@ -62,6 +62,7 @@ class PatternDetector: capture_output=True, text=True, timeout=30, + check=False, ) data = json.loads(result.stdout) return len(data.get("streams", [])) > 0 diff --git a/alfred/domain/subtitles/services/placer.py b/alfred/domain/subtitles/services/placer.py index 1e9ee00..81b6a56 100644 --- a/alfred/domain/subtitles/services/placer.py +++ b/alfred/domain/subtitles/services/placer.py @@ -6,6 +6,7 @@ from dataclasses import dataclass from pathlib import Path from ..entities import SubtitleCandidate +from ..value_objects import SubtitleType logger = logging.getLogger(__name__) @@ -18,8 +19,6 @@ def _build_dest_name(track: SubtitleCandidate, video_stem: str) -> str: {video_stem}.{lang}.sdh.{ext} {video_stem}.{lang}.forced.{ext} """ - from ..value_objects import SubtitleType - if not track.language or not track.format: raise ValueError("Cannot compute destination name: language or format missing") diff --git a/alfred/infrastructure/api/qbittorrent/client.py b/alfred/infrastructure/api/qbittorrent/client.py index fafc16b..bae9e14 100644 --- a/alfred/infrastructure/api/qbittorrent/client.py +++ b/alfred/infrastructure/api/qbittorrent/client.py @@ -1,6 +1,7 @@ """qBittorrent Web API client.""" import logging +from pathlib import Path from typing import Any import requests @@ -365,8 +366,6 @@ class QBittorrentClient: return t # 3. save_path ends with the folder name - from pathlib import Path - for t in torrents: if t.save_path and Path(t.save_path).name.lower() == name_lower: return t diff --git a/alfred/infrastructure/filesystem/ffprobe.py b/alfred/infrastructure/filesystem/ffprobe.py index 4c2bc99..792039d 100644 --- a/alfred/infrastructure/filesystem/ffprobe.py +++ b/alfred/infrastructure/filesystem/ffprobe.py @@ -34,6 +34,7 @@ def probe(path: Path) -> MediaInfo | None: capture_output=True, text=True, timeout=30, + check=False, ) except subprocess.TimeoutExpired: logger.warning("ffprobe timed out on %s", path) diff --git a/alfred/infrastructure/filesystem/file_manager.py b/alfred/infrastructure/filesystem/file_manager.py index a30acd1..7f266b9 100644 --- a/alfred/infrastructure/filesystem/file_manager.py +++ b/alfred/infrastructure/filesystem/file_manager.py @@ -2,6 +2,7 @@ import logging import os +import shutil from collections import namedtuple from pathlib import Path from typing import Any @@ -285,8 +286,6 @@ class FileManager: if dest_item.exists(): skipped.append(str(rel)) continue - import shutil - shutil.copy2(item, dest_item) copied.append(str(rel)) logger.debug(f"Copied for seeding: {rel}") diff --git a/alfred/infrastructure/filesystem/filesystem_operations.py b/alfred/infrastructure/filesystem/filesystem_operations.py index 77e1e32..2670eec 100644 --- a/alfred/infrastructure/filesystem/filesystem_operations.py +++ b/alfred/infrastructure/filesystem/filesystem_operations.py @@ -59,6 +59,7 @@ def move(source: str, destination: str) -> dict[str, Any]: ["mv", str(src), str(dst)], capture_output=True, text=True, + check=False, ) if result.returncode != 0: logger.error(f"mv failed: {result.stderr}") diff --git a/pyproject.toml b/pyproject.toml index b1c200e..99b4936 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -136,7 +136,15 @@ lint.select = [ "PL", "UP", ] -lint.ignore = ["PLR0913", "PLR2004", "TID252", "E501"] +lint.ignore = [ + "PLR0911", # too-many-returns: noisy on mappers / orchestrator use-cases with early-return validation + "PLR0912", # too-many-branches: same as above + "PLR0913", # too-many-arguments + "PLR2004", # magic-value-comparison + "PLW0603", # global statement: intentional for the memory singleton (see project_memory_singleton.md) + "TID252", + "E501", +] [tool.ruff.lint.per-file-ignores] "tests/**/*.py" = ["PLC0415"]