Locale-agnostic synced-lyrics fetching library: NetEase and LRCLib providers, LRC parsing, credit-line filtering, on-disk fetch cache, and media-tag query building. Stdlib only, no runtime dependencies.
- NetEase search + lyric fetch, returns the full candidate list, not best-match-only
- LRCLib search with plain-text fallback when no synced lyrics exist
Candidatedataclass with lazy-parsed LRC lines- NetEase
tlyrickept on the candidate: the translated LRC rides the samesong/lyricfetch, no extra request - LRC parser fanning multi-timestamp lines out into one entry per timestamp, timed lines sorted, untimed ones kept last in source order, source typography preserved
- Credit-line detection (
is_credit_line,classify_lines,filter_credit_lines) strips non-sung metadata: CJK, katakana and English role labels, uppercase-onlyOP/ED/BPM, colonlessLyrics & Music by Xand作詞 n-bunaforms, watermarks whose domain is host-shaped and lowercase, LRC headers bracketed ([ti:晴る]) or bare (ar:周杰倫) - Raw fetch cache as readable json under
LYRICS_DIR, one subdir per provider - Query building from container tags via ffprobe,
title artistpermutations, reusabletagsto skip a second probe
from lyrickit import fetch_from_providers, build_queries
queries, title, artists = build_queries("concert.mkv")
candidates = fetch_from_providers(queries[0], ["netease", "lrclib"])
lines = candidates[0].lines # [(seconds_or_None, text)]Single provider, bypassing cache:
from lyrickit import netease_candidates
candidates = netease_candidates("晴る ヨルシカ", fresh=True)Strip credits before display:
from lyrickit import classify_lines, filter_credit_lines
lines = candidates[0].lines
sung = filter_credit_lines(lines, classify_lines(lines))| Setting | Default | Description |
|---|---|---|
LYRICS_DIR env var |
~/.cache/lyrickit |
Root for the fetch cache |
Cache layout: LYRICS_DIR/netease/<slug>.json stores query + candidates + lrcs + tlyrics; identical query reuses it, fresh=True refetches. Distinct queries can collide on slug, the stored query disambiguates (mismatch refetches, last one wins), so two queries sharing a slug refetch on every alternation. LRCLib is not cached, fresh applies to NetEase only.
NetEase endpoints (search/pc, song/lyric) are adapted from the syncedlyrics netease provider, returning the full candidate list with per-candidate LRCs. A non-200 body (e.g. 405 rate limit) raises instead of caching an empty result. media_tags shells out to ffprobe once per file for title/artist/album/duration/embedded lyrics, degrading to {} when ffprobe is absent or exits non-zero.
NFKC normalization applies to the matching copy only, so a wide : and a plain colon read alike while the returned text keeps its wave dash, ellipsis and units.
Credit detection reads line shape only, never the right-hand side, so an English role word followed by a colon and prose is struck: Music: the food of love, Words: they fail me, Title: unknown. Known limitation, telling those from a real credit needs semantics.
pip install -e .- syncedlyrics: NetEase endpoint + cookie approach