From e8d9299939f8db1f56f608b89507762e8206f673 Mon Sep 17 00:00:00 2001 From: Uyanide Date: Tue, 31 Mar 2026 16:56:49 +0200 Subject: [PATCH] refactor: add is_available method to fetchers --- lrcfetch/core.py | 15 +++------------ lrcfetch/fetchers/base.py | 5 +++++ lrcfetch/fetchers/cache_search.py | 3 +++ lrcfetch/fetchers/local.py | 3 +++ lrcfetch/fetchers/lrclib.py | 3 +++ lrcfetch/fetchers/lrclib_search.py | 3 +++ lrcfetch/fetchers/netease.py | 3 +++ lrcfetch/fetchers/qqmusic.py | 3 +++ lrcfetch/fetchers/spotify.py | 3 +++ 9 files changed, 29 insertions(+), 12 deletions(-) diff --git a/lrcfetch/core.py b/lrcfetch/core.py index e51bd87..0acabca 100644 --- a/lrcfetch/core.py +++ b/lrcfetch/core.py @@ -51,18 +51,9 @@ class LrcManager: return [self.fetchers[force_method]] sequence: list[BaseFetcher] = [] - if track.is_local: - sequence.append(self.fetchers["local"]) - if track.title: - sequence.append(self.fetchers["cache-search"]) - if track.trackid: - sequence.append(self.fetchers["spotify"]) - if track.is_complete: - sequence.append(self.fetchers["lrclib"]) - if track.title: - sequence.append(self.fetchers["lrclib-search"]) - sequence.append(self.fetchers["netease"]) - sequence.append(self.fetchers["qqmusic"]) + for method in self.fetchers.keys(): + if self.fetchers[method].is_available(track): + sequence.append(self.fetchers[method]) logger.debug(f"Fallback sequence: {[f.source_name for f in sequence]}") return sequence diff --git a/lrcfetch/fetchers/base.py b/lrcfetch/fetchers/base.py index 28b8f98..2bf70af 100644 --- a/lrcfetch/fetchers/base.py +++ b/lrcfetch/fetchers/base.py @@ -22,6 +22,11 @@ class BaseFetcher(ABC): """True if this fetcher manages its own cache (skip per-source cache check).""" return False + @abstractmethod + def is_available(self, track: TrackMeta) -> bool: + """Check if the fetcher is available for the given track (e.g. has required metadata).""" + pass + @abstractmethod def fetch( self, track: TrackMeta, bypass_cache: bool = False diff --git a/lrcfetch/fetchers/cache_search.py b/lrcfetch/fetchers/cache_search.py index 7246bbc..af973c5 100644 --- a/lrcfetch/fetchers/cache_search.py +++ b/lrcfetch/fetchers/cache_search.py @@ -30,6 +30,9 @@ class CacheSearchFetcher(BaseFetcher): def self_cached(self) -> bool: return True + def is_available(self, track: TrackMeta) -> bool: + return bool(track.title) + def fetch( self, track: TrackMeta, bypass_cache: bool = False ) -> Optional[LyricResult]: diff --git a/lrcfetch/fetchers/local.py b/lrcfetch/fetchers/local.py index 8e2267e..82e3ecd 100644 --- a/lrcfetch/fetchers/local.py +++ b/lrcfetch/fetchers/local.py @@ -25,6 +25,9 @@ class LocalFetcher(BaseFetcher): def source_name(self) -> str: return "local" + def is_available(self, track: TrackMeta) -> bool: + return track.is_local + def fetch( self, track: TrackMeta, bypass_cache: bool = False ) -> Optional[LyricResult]: diff --git a/lrcfetch/fetchers/lrclib.py b/lrcfetch/fetchers/lrclib.py index 71d08d1..94928d1 100644 --- a/lrcfetch/fetchers/lrclib.py +++ b/lrcfetch/fetchers/lrclib.py @@ -31,6 +31,9 @@ class LrclibFetcher(BaseFetcher): def source_name(self) -> str: return "lrclib" + def is_available(self, track: TrackMeta) -> bool: + return track.is_complete + def fetch( self, track: TrackMeta, bypass_cache: bool = False ) -> Optional[LyricResult]: diff --git a/lrcfetch/fetchers/lrclib_search.py b/lrcfetch/fetchers/lrclib_search.py index 3fa9357..95f87c2 100644 --- a/lrcfetch/fetchers/lrclib_search.py +++ b/lrcfetch/fetchers/lrclib_search.py @@ -33,6 +33,9 @@ class LrclibSearchFetcher(BaseFetcher): def source_name(self) -> str: return "lrclib-search" + def is_available(self, track: TrackMeta) -> bool: + return bool(track.title) + def fetch( self, track: TrackMeta, bypass_cache: bool = False ) -> Optional[LyricResult]: diff --git a/lrcfetch/fetchers/netease.py b/lrcfetch/fetchers/netease.py index cee4ab9..eecc8d7 100644 --- a/lrcfetch/fetchers/netease.py +++ b/lrcfetch/fetchers/netease.py @@ -40,6 +40,9 @@ class NeteaseFetcher(BaseFetcher): def source_name(self) -> str: return "netease" + def is_available(self, track: TrackMeta) -> bool: + return bool(track.title) + def _search(self, track: TrackMeta, limit: int = 10) -> Optional[int]: """Search Netease and return the best-matching song ID. diff --git a/lrcfetch/fetchers/qqmusic.py b/lrcfetch/fetchers/qqmusic.py index 061fc7b..a5d0b63 100644 --- a/lrcfetch/fetchers/qqmusic.py +++ b/lrcfetch/fetchers/qqmusic.py @@ -32,6 +32,9 @@ class QQMusicFetcher(BaseFetcher): def source_name(self) -> str: return "qqmusic" + def is_available(self, track: TrackMeta) -> bool: + return bool(track.title) and bool(QQ_MUSIC_API_URL) + def _search(self, track: TrackMeta, limit: int = 10) -> Optional[str]: """Search QQ Music and return the best-matching song MID.""" query = f"{track.artist or ''} {track.title or ''}".strip() diff --git a/lrcfetch/fetchers/spotify.py b/lrcfetch/fetchers/spotify.py index 110f86a..fcd568c 100644 --- a/lrcfetch/fetchers/spotify.py +++ b/lrcfetch/fetchers/spotify.py @@ -55,6 +55,9 @@ class SpotifyFetcher(BaseFetcher): def source_name(self) -> str: return "spotify" + def is_available(self, track: TrackMeta) -> bool: + return bool(track.trackid) and bool(SPOTIFY_SP_DC) + # ─── Auth helpers ──────────────────────────────────────────────── def _get_server_time(self, client: httpx.Client) -> Optional[int]: