feat: better LRC format handling

This commit is contained in:
2026-03-31 15:35:22 +02:00
parent 29273ad9fe
commit 03acda4478
10 changed files with 133 additions and 105 deletions
+4 -2
View File
@@ -17,7 +17,7 @@ from mutagen.flac import FLAC
from .base import BaseFetcher
from ..models import TrackMeta, LyricResult
from ..lrc import detect_sync_status, get_audio_path, get_sidecar_path
from ..lrc import detect_sync_status, normalize_tags, get_audio_path, get_sidecar_path
class LocalFetcher(BaseFetcher):
@@ -45,6 +45,7 @@ class LocalFetcher(BaseFetcher):
with open(lrc_path, "r", encoding="utf-8") as f:
content = f.read().strip()
if content:
content = normalize_tags(content)
status = detect_sync_status(content)
logger.info(f"Local: found .lrc sidecar ({status.value})")
return LyricResult(
@@ -77,11 +78,12 @@ class LocalFetcher(BaseFetcher):
break
if lyrics:
lyrics = normalize_tags(lyrics.strip())
status = detect_sync_status(lyrics)
logger.info(f"Local: found embedded lyrics ({status.value})")
return LyricResult(
status=status,
lyrics=lyrics.strip(),
lyrics=lyrics,
source=f"{self.source_name} (embedded)",
)
else:
+7 -4
View File
@@ -15,6 +15,7 @@ from urllib.parse import urlencode
from .base import BaseFetcher
from ..models import TrackMeta, LyricResult, CacheStatus
from ..lrc import normalize_tags
from ..config import (
HTTP_TIMEOUT,
TTL_UNSYNCED,
@@ -75,21 +76,23 @@ class LrclibFetcher(BaseFetcher):
unsynced = data.get("plainLyrics")
if isinstance(synced, str) and synced.strip():
lyrics = normalize_tags(synced.strip())
logger.info(
f"LRCLIB: got synced lyrics ({len(synced.splitlines())} lines)"
f"LRCLIB: got synced lyrics ({len(lyrics.splitlines())} lines)"
)
return LyricResult(
status=CacheStatus.SUCCESS_SYNCED,
lyrics=synced.strip(),
lyrics=lyrics,
source=self.source_name,
)
elif isinstance(unsynced, str) and unsynced.strip():
lyrics = normalize_tags(unsynced.strip())
logger.info(
f"LRCLIB: got unsynced lyrics ({len(unsynced.splitlines())} lines)"
f"LRCLIB: got unsynced lyrics ({len(lyrics.splitlines())} lines)"
)
return LyricResult(
status=CacheStatus.SUCCESS_UNSYNCED,
lyrics=unsynced.strip(),
lyrics=lyrics,
source=self.source_name,
ttl=TTL_UNSYNCED,
)
+7 -4
View File
@@ -16,6 +16,7 @@ from urllib.parse import urlencode
from .base import BaseFetcher
from ..models import TrackMeta, LyricResult, CacheStatus
from ..lrc import normalize_tags
from ..config import (
HTTP_TIMEOUT,
TTL_UNSYNCED,
@@ -78,21 +79,23 @@ class LrclibSearchFetcher(BaseFetcher):
unsynced = best.get("plainLyrics")
if isinstance(synced, str) and synced.strip():
lyrics = normalize_tags(synced.strip())
logger.info(
f"LRCLIB-search: got synced lyrics ({len(synced.splitlines())} lines)"
f"LRCLIB-search: got synced lyrics ({len(lyrics.splitlines())} lines)"
)
return LyricResult(
status=CacheStatus.SUCCESS_SYNCED,
lyrics=synced.strip(),
lyrics=lyrics,
source=self.source_name,
)
elif isinstance(unsynced, str) and unsynced.strip():
lyrics = normalize_tags(unsynced.strip())
logger.info(
f"LRCLIB-search: got unsynced lyrics ({len(unsynced.splitlines())} lines)"
f"LRCLIB-search: got unsynced lyrics ({len(lyrics.splitlines())} lines)"
)
return LyricResult(
status=CacheStatus.SUCCESS_UNSYNCED,
lyrics=unsynced.strip(),
lyrics=lyrics,
source=self.source_name,
ttl=TTL_UNSYNCED,
)
+3 -5
View File
@@ -18,7 +18,7 @@ from loguru import logger
from .base import BaseFetcher
from ..models import TrackMeta, LyricResult, CacheStatus
from ..lrc import is_synced
from ..lrc import detect_sync_status, normalize_tags
from ..config import (
HTTP_TIMEOUT,
TTL_NOT_FOUND,
@@ -178,10 +178,8 @@ class NeteaseFetcher(BaseFetcher):
return LyricResult(status=CacheStatus.NOT_FOUND, ttl=TTL_NOT_FOUND)
# Determine sync status
synced = is_synced(lrc)
status = (
CacheStatus.SUCCESS_SYNCED if synced else CacheStatus.SUCCESS_UNSYNCED
)
lrc = normalize_tags(lrc)
status = detect_sync_status(lrc)
logger.info(
f"Netease: got {status.value} lyrics for song_id={song_id} "
f"({len(lrc.splitlines())} lines)"
+3 -5
View File
@@ -17,7 +17,7 @@ from loguru import logger
from .base import BaseFetcher
from ..models import TrackMeta, LyricResult, CacheStatus
from ..lrc import is_synced
from ..lrc import detect_sync_status, normalize_tags
from ..config import (
HTTP_TIMEOUT,
TTL_NOT_FOUND,
@@ -139,10 +139,8 @@ class QQMusicFetcher(BaseFetcher):
logger.debug(f"QQMusic: empty lyrics for mid={mid}")
return LyricResult(status=CacheStatus.NOT_FOUND, ttl=TTL_NOT_FOUND)
synced = is_synced(lrc)
status = (
CacheStatus.SUCCESS_SYNCED if synced else CacheStatus.SUCCESS_UNSYNCED
)
lrc = normalize_tags(lrc)
status = detect_sync_status(lrc)
logger.info(
f"QQMusic: got {status.value} lyrics for mid={mid} "
f"({len(lrc.splitlines())} lines)"
+2 -1
View File
@@ -28,6 +28,7 @@ from loguru import logger
from .base import BaseFetcher
from ..models import TrackMeta, LyricResult, CacheStatus
from ..lrc import normalize_tags
from ..config import (
HTTP_TIMEOUT,
SPOTIFY_APP_VERSION,
@@ -354,7 +355,7 @@ class SpotifyFetcher(BaseFetcher):
# Unsynced: emit with zero timestamps
lrc_lines.append(f"[00:00.00]{words}")
content = "\n".join(lrc_lines)
content = normalize_tags("\n".join(lrc_lines))
status = (
CacheStatus.SUCCESS_SYNCED
if is_synced