refactor: add __all__ and more decouple

This commit is contained in:
2026-04-10 16:43:51 +02:00
parent 10bfb6090c
commit cfac95ca03
11 changed files with 78 additions and 47 deletions
+1 -1
View File
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
[project] [project]
name = "lrx-cli" name = "lrx-cli"
version = "0.7.8" version = "0.7.9"
description = "Fetch line-synced lyrics for your music player." description = "Fetch line-synced lyrics for your music player."
readme = "README.md" readme = "README.md"
requires-python = ">=3.13" requires-python = ">=3.13"
+21
View File
@@ -0,0 +1,21 @@
from .config import AppConfig, GeneralConfig, CredentialConfig, load_config
from .core import LrcManager
from .models import CacheStatus, TrackMeta, LyricResult
from .lrc import LRCData, LyricLine
from .fetchers import FetcherMethodType
from .utils import get_sidecar_path
__all__ = [
"AppConfig",
"GeneralConfig",
"CredentialConfig",
"load_config",
"LrcManager",
"CacheStatus",
"TrackMeta",
"LRCData",
"LyricLine",
"LyricResult",
"FetcherMethodType",
"get_sidecar_path",
]
+1 -1
View File
@@ -24,7 +24,7 @@ from .config import (
SLOT_UNSYNCED, SLOT_UNSYNCED,
) )
from .models import TrackMeta, LyricResult, CacheStatus from .models import TrackMeta, LyricResult, CacheStatus
from .ranking import is_positive_status, select_best_positive from .utils import is_positive_status, select_best_positive
_ALL_SLOTS = (SLOT_SYNCED, SLOT_UNSYNCED) _ALL_SLOTS = (SLOT_SYNCED, SLOT_UNSYNCED)
+1 -1
View File
@@ -23,11 +23,11 @@ from .config import (
load_config, load_config,
enable_debug, enable_debug,
) )
from .utils import get_sidecar_path
from .models import TrackMeta from .models import TrackMeta
from .mpris import get_current_track from .mpris import get_current_track
from .core import LrcManager from .core import LrcManager
from .fetchers import FetcherMethodType from .fetchers import FetcherMethodType
from .lrc import get_sidecar_path
from .watch import WatchCoordinator from .watch import WatchCoordinator
from .watch.control import ControlClient, parse_delta from .watch.control import ControlClient, parse_delta
from .watch.view.pipe import PipeOutput from .watch.view.pipe import PipeOutput
+1 -1
View File
@@ -28,7 +28,7 @@ from .config import (
) )
from .models import TrackMeta, LyricResult, CacheStatus from .models import TrackMeta, LyricResult, CacheStatus
from .enrichers import create_enrichers, enrich_track from .enrichers import create_enrichers, enrich_track
from .ranking import is_better_result, select_best_positive from .utils import is_better_result, select_best_positive
# Maps CacheStatus to the default TTL used when storing results # Maps CacheStatus to the default TTL used when storing results
+1 -1
View File
@@ -12,7 +12,7 @@ from mutagen._file import File, FileType
from .base import BaseEnricher from .base import BaseEnricher
from ..models import TrackMeta from ..models import TrackMeta
from ..lrc import get_audio_path from ..utils import get_audio_path
class AudioTagEnricher(BaseEnricher): class AudioTagEnricher(BaseEnricher):
+1 -1
View File
@@ -12,7 +12,7 @@ from loguru import logger
from .base import BaseEnricher from .base import BaseEnricher
from ..models import TrackMeta from ..models import TrackMeta
from ..lrc import get_audio_path from ..utils import get_audio_path
# Common track-number prefixes: "01 - ", "01. ", "1 - ", etc. # Common track-number prefixes: "01 - ", "01. ", "1 - ", etc.
+2 -1
View File
@@ -16,7 +16,8 @@ from mutagen.flac import FLAC
from .base import BaseFetcher, FetchResult from .base import BaseFetcher, FetchResult
from ..models import CacheStatus, TrackMeta, LyricResult from ..models import CacheStatus, TrackMeta, LyricResult
from ..lrc import get_audio_path, get_sidecar_path, LRCData from ..lrc import LRCData
from ..utils import get_audio_path, get_sidecar_path
class LocalFetcher(BaseFetcher): class LocalFetcher(BaseFetcher):
-33
View File
@@ -9,9 +9,7 @@ from __future__ import annotations
from abc import ABC, abstractmethod from abc import ABC, abstractmethod
from dataclasses import dataclass, field from dataclasses import dataclass, field
import re import re
from pathlib import Path
from typing import Optional from typing import Optional
from urllib.parse import unquote
from .models import CacheStatus from .models import CacheStatus
@@ -465,34 +463,3 @@ class LRCData:
""" """
normalized = self.normalize() normalized = self.normalize()
return self._serialize_lines(normalized._lines, include_word_sync=False) return self._serialize_lines(normalized._lines, include_word_sync=False)
def get_audio_path(audio_url: str, ensure_exists: bool = False) -> Optional[Path]:
"""Convert file:// URL to Path, return None if invalid or (if ensure_exists) file doesn't exist."""
if not audio_url.startswith("file://"):
return None
file_path = unquote(audio_url.replace("file://", "", 1))
path = Path(file_path)
if ensure_exists and not path.exists():
return None
return path
def get_sidecar_path(
audio_url: str,
ensure_audio_exists: bool = False,
ensure_exists: bool = False,
extension: str = ".lrc",
) -> Optional[Path]:
"""Given a file:// URL, return the corresponding .lrc sidecar path.
If ensure_audio_exists is True, return None if the audio file does not exist.
If ensure_exists is True, return None if the .lrc file does not exist.
"""
audio_path = get_audio_path(audio_url, ensure_exists=ensure_audio_exists)
if not audio_path:
return None
lrc_path = audio_path.with_suffix(extension)
if ensure_exists and not lrc_path.exists():
return None
return lrc_path
@@ -1,14 +1,56 @@
"""Shared ranking rules for LyricResult selection. """
Author: Uyanide pywang0608@foxmail.com
This module centralizes how positive lyric results are compared so cache/core Date: 2026-04-10 17:06:37
and other callers use the same precedence and edge-case handling. Description: Utility functions
""" """
from __future__ import annotations from __future__ import annotations
from typing import Optional from typing import TYPE_CHECKING, Optional
from urllib.parse import unquote
from pathlib import Path
from .models import CacheStatus, LyricResult from .models import CacheStatus
if TYPE_CHECKING:
from .models import LyricResult
# Paths
def get_audio_path(audio_url: str, ensure_exists: bool = False) -> Optional[Path]:
"""Convert file:// URL to Path, return None if invalid or (if ensure_exists) file doesn't exist."""
if not audio_url.startswith("file://"):
return None
file_path = unquote(audio_url.replace("file://", "", 1))
path = Path(file_path)
if ensure_exists and not path.exists():
return None
return path
def get_sidecar_path(
audio_url: str,
ensure_audio_exists: bool = False,
ensure_exists: bool = False,
extension: str = ".lrc",
) -> Optional[Path]:
"""Given a file:// URL, return the corresponding .lrc sidecar path.
If ensure_audio_exists is True, return None if the audio file does not exist.
If ensure_exists is True, return None if the .lrc file does not exist.
"""
audio_path = get_audio_path(audio_url, ensure_exists=ensure_audio_exists)
if not audio_path:
return None
lrc_path = audio_path.with_suffix(extension)
if ensure_exists and not lrc_path.exists():
return None
return lrc_path
# Ranking
def is_positive_status(status: CacheStatus) -> bool: def is_positive_status(status: CacheStatus) -> bool:
Generated
+1 -1
View File
@@ -153,7 +153,7 @@ wheels = [
[[package]] [[package]]
name = "lrx-cli" name = "lrx-cli"
version = "0.7.8" version = "0.7.9"
source = { editable = "." } source = { editable = "." }
dependencies = [ dependencies = [
{ name = "cyclopts" }, { name = "cyclopts" },