diff --git a/LICENSE b/LICENSE index e97cd05..608e505 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright 2026 Uyanide me@uyani.de +Copyright 2026 Uyanide pywang0608@foxmail.com Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: diff --git a/lrx_cli/__main__.py b/lrx_cli/__main__.py index 7f34de1..739cee1 100644 --- a/lrx_cli/__main__.py +++ b/lrx_cli/__main__.py @@ -1,4 +1,10 @@ -from lrx_cli.cli import run +""" +Author: Uyanide pywang0608@foxmail.com +Date: 2026-04-06 08:19:54 +Description: The entry point. +""" + +from .cli import run if __name__ == "__main__": run() diff --git a/lrx_cli/authenticators/__init__.py b/lrx_cli/authenticators/__init__.py index 0e78f92..07db8e3 100644 --- a/lrx_cli/authenticators/__init__.py +++ b/lrx_cli/authenticators/__init__.py @@ -1,5 +1,6 @@ """ Author: Uyanide pywang0608@foxmail.com +Date: 2026-04-06 08:21:01 Description: Credential authenticators for third-party provider APIs """ diff --git a/lrx_cli/authenticators/base.py b/lrx_cli/authenticators/base.py index 09e3fd2..1196b09 100644 --- a/lrx_cli/authenticators/base.py +++ b/lrx_cli/authenticators/base.py @@ -1,7 +1,7 @@ """ Author: Uyanide pywang0608@foxmail.com Date: 2026-04-05 03:18:14 -Description: Base class for credential authenticators +Description: Base class for credential authenticators. """ from abc import ABC, abstractmethod diff --git a/lrx_cli/authenticators/dummy.py b/lrx_cli/authenticators/dummy.py index 085df00..f436fab 100644 --- a/lrx_cli/authenticators/dummy.py +++ b/lrx_cli/authenticators/dummy.py @@ -1,7 +1,7 @@ """ Author: Uyanide pywang0608@foxmail.com Date: 2026-04-05 03:36:44 -Description: +Description: A dummy authenticator that does nothing and always reports as configured. """ from .base import BaseAuthenticator diff --git a/lrx_cli/authenticators/musixmatch.py b/lrx_cli/authenticators/musixmatch.py index 331d37a..f6f4252 100644 --- a/lrx_cli/authenticators/musixmatch.py +++ b/lrx_cli/authenticators/musixmatch.py @@ -1,7 +1,7 @@ """ Author: Uyanide pywang0608@foxmail.com Date: 2026-04-05 03:27:56 -Description: Musixmatch authenticator — token management, 401 retry, and cooldown +Description: Musixmatch authenticator — token management, 401 retry, and cooldown. """ import time diff --git a/lrx_cli/authenticators/qqmusic.py b/lrx_cli/authenticators/qqmusic.py index e4f4a8d..0a78fe7 100644 --- a/lrx_cli/authenticators/qqmusic.py +++ b/lrx_cli/authenticators/qqmusic.py @@ -1,7 +1,7 @@ """ Author: Uyanide pywang0608@foxmail.com Date: 2026-04-05 03:47:30 -Description: QQ Music API authenticator - currently only a proxy +Description: QQ Music API authenticator - currently only a proxy. """ from typing import Optional diff --git a/lrx_cli/authenticators/spotify.py b/lrx_cli/authenticators/spotify.py index 2d8796c..99d0450 100644 --- a/lrx_cli/authenticators/spotify.py +++ b/lrx_cli/authenticators/spotify.py @@ -1,7 +1,7 @@ """ Author: Uyanide pywang0608@foxmail.com Date: 2026-04-05 03:18:14 -Description: Spotify authenticator — TOTP-based access token via SP_DC cookie +Description: Spotify authenticator — TOTP-based access token via SP_DC cookie. """ import hashlib @@ -134,9 +134,7 @@ class SpotifyAuthenticator(BaseAuthenticator): return db_token if not credentials.SPOTIFY_SP_DC: - logger.error( - "Spotify: settings.SPOTIFY_SP_DC env var not set — cannot authenticate" - ) + logger.error("Spotify: SPOTIFY_SP_DC env var not set — cannot authenticate") return None headers = { diff --git a/lrx_cli/cache.py b/lrx_cli/cache.py index 659e55b..ecac3c5 100644 --- a/lrx_cli/cache.py +++ b/lrx_cli/cache.py @@ -1,7 +1,7 @@ """ Author: Uyanide pywang0608@foxmail.com Date: 2026-03-25 10:18:03 -Description: SQLite-based lyric cache with per-source storage and TTL expiration +Description: SQLite-based lyric cache with per-source storage and TTL expiration. """ import json @@ -79,7 +79,7 @@ class CacheEngine: self._init_db() def _init_db(self) -> None: - """Create or migrate the cache table.""" + """Create or migrate the cache and credentials tables.""" with sqlite3.connect(self.db_path) as conn: conn.execute(""" CREATE TABLE IF NOT EXISTS cache ( diff --git a/lrx_cli/cli.py b/lrx_cli/cli.py index 4cf80f0..f9e3c46 100644 --- a/lrx_cli/cli.py +++ b/lrx_cli/cli.py @@ -1,7 +1,7 @@ """ Author: Uyanide pywang0608@foxmail.com Date: 2026-03-26 02:04:39 -Description: CLI interface +Description: CLI interface. """ import sys diff --git a/lrx_cli/config.py b/lrx_cli/config.py index 355024e..6b19865 100644 --- a/lrx_cli/config.py +++ b/lrx_cli/config.py @@ -1,7 +1,7 @@ """ Author: Uyanide pywang0608@foxmail.com Date: 2026-03-25 10:17:56 -Description: Global configuration constants and logger setup +Description: Global configuration constants and logger setup. """ import os diff --git a/lrx_cli/core.py b/lrx_cli/core.py index 5652275..fcc5172 100644 --- a/lrx_cli/core.py +++ b/lrx_cli/core.py @@ -1,7 +1,7 @@ """ Author: Uyanide pywang0608@foxmail.com Date: 2026-03-25 11:09:53 -Description: Core orchestrator — coordinates fetchers with cache-aware fallback +Description: Core orchestrator — coordinates fetchers with cache-aware fallback. """ import asyncio diff --git a/lrx_cli/enrichers/audio_tag.py b/lrx_cli/enrichers/audio_tag.py index 90aebe1..879685c 100644 --- a/lrx_cli/enrichers/audio_tag.py +++ b/lrx_cli/enrichers/audio_tag.py @@ -1,7 +1,7 @@ """ Author: Uyanide pywang0608@foxmail.com Date: 2026-03-31 06:11:27 -Description: Enricher that reads metadata from audio file tags (mutagen) +Description: Enricher that reads metadata from audio file tags. """ from typing import Optional diff --git a/lrx_cli/enrichers/base.py b/lrx_cli/enrichers/base.py index ebdc100..428bcbe 100644 --- a/lrx_cli/enrichers/base.py +++ b/lrx_cli/enrichers/base.py @@ -1,7 +1,7 @@ """ Author: Uyanide pywang0608@foxmail.com Date: 2026-03-31 06:08:16 -Description: Base class for metadata enrichers +Description: Base class for metadata enrichers. """ from abc import ABC, abstractmethod diff --git a/lrx_cli/enrichers/file_name.py b/lrx_cli/enrichers/file_name.py index c8aacf1..741ff18 100644 --- a/lrx_cli/enrichers/file_name.py +++ b/lrx_cli/enrichers/file_name.py @@ -1,7 +1,7 @@ """ Author: Uyanide pywang0608@foxmail.com Date: 2026-03-31 06:08:44 -Description: Enricher that parses metadata from the audio file path +Description: Enricher that parses metadata from the audio file path. """ import re diff --git a/lrx_cli/enrichers/musixmatch.py b/lrx_cli/enrichers/musixmatch.py index 6425eaf..481e40d 100644 --- a/lrx_cli/enrichers/musixmatch.py +++ b/lrx_cli/enrichers/musixmatch.py @@ -1,7 +1,7 @@ """ Author: Uyanide pywang0608@foxmail.com Date: 2026-04-05 02:13:49 -Description: Musixmatch metadata enricher (matcher.track.get by Spotify track ID) +Description: Musixmatch metadata enricher (matcher.track.get by Spotify track ID). """ from typing import Optional diff --git a/lrx_cli/fetchers/__init__.py b/lrx_cli/fetchers/__init__.py index db79998..ea6c4ea 100644 --- a/lrx_cli/fetchers/__init__.py +++ b/lrx_cli/fetchers/__init__.py @@ -1,7 +1,7 @@ """ Author: Uyanide pywang0608@foxmail.com Date: 2026-03-25 02:33:26 -Description: Fetcher pipeline — registry and types +Description: Fetcher pipeline — registry and types. """ from typing import Literal, Optional diff --git a/lrx_cli/fetchers/base.py b/lrx_cli/fetchers/base.py index 4bd7501..6bb3b78 100644 --- a/lrx_cli/fetchers/base.py +++ b/lrx_cli/fetchers/base.py @@ -1,7 +1,7 @@ """ Author: Uyanide pywang0608@foxmail.com Date: 2026-03-25 02:33:26 -Description: Base fetcher class and common interfaces +Description: Base fetcher class and common interfaces. """ from abc import ABC, abstractmethod diff --git a/lrx_cli/fetchers/cache_search.py b/lrx_cli/fetchers/cache_search.py index b66f7a7..beca459 100644 --- a/lrx_cli/fetchers/cache_search.py +++ b/lrx_cli/fetchers/cache_search.py @@ -1,13 +1,11 @@ """ Author: Uyanide pywang0608@foxmail.com Date: 2026-03-28 05:57:46 -Description: Cache-search fetcher — cross-album fuzzy lookup in the local cache -""" +Description: Cache-search fetcher — cross-album fuzzy lookup in the local cache. -""" -Searches existing cache entries by artist + title with fuzzy normalization, -ignoring album and source. Useful when the same track appears on different -albums or is played from different players. + Searches existing cache entries by artist + title with fuzzy normalization, + ignoring album and source. Useful when the same track appears on different + albums or is played from different players. """ from typing import Optional diff --git a/lrx_cli/fetchers/local.py b/lrx_cli/fetchers/local.py index 837aea8..7684c03 100644 --- a/lrx_cli/fetchers/local.py +++ b/lrx_cli/fetchers/local.py @@ -1,13 +1,10 @@ """ Author: Uyanide pywang0608@foxmail.com Date: 2026-03-26 02:08:41 -Description: Local fetcher — reads lyrics from .lrc sidecar files or embedded audio metadata -""" - -""" -Priority: - 1. Same-directory .lrc file (e.g. /path/to/track.lrc) - 2. Embedded lyrics in audio metadata (FLAC, MP3 USLT/SYLT tags) +Description: Local fetcher — reads lyrics from .lrc sidecar files or embedded audio metadata. + Priority: + 1. Same-directory .lrc file (e.g. /path/to/track.lrc) + 2. Embedded lyrics in audio metadata (FLAC, MP3 USLT/SYLT tags) """ from typing import Optional diff --git a/lrx_cli/fetchers/lrclib.py b/lrx_cli/fetchers/lrclib.py index 1292e86..f55cc75 100644 --- a/lrx_cli/fetchers/lrclib.py +++ b/lrx_cli/fetchers/lrclib.py @@ -1,11 +1,8 @@ """ Author: Uyanide pywang0608@foxmail.com Date: 2026-03-25 05:23:38 -Description: LRCLIB fetcher — queries lrclib.net for synced/plain lyrics -""" - -""" -Requires complete track metadata (artist, title, album, duration). +Description: LRCLIB fetcher — queries lrclib.net for synced/plain lyrics. + Requires complete track metadata (artist, title, album, duration). """ from typing import Optional diff --git a/lrx_cli/fetchers/lrclib_search.py b/lrx_cli/fetchers/lrclib_search.py index d25a9ed..3e53346 100644 --- a/lrx_cli/fetchers/lrclib_search.py +++ b/lrx_cli/fetchers/lrclib_search.py @@ -1,12 +1,8 @@ """ Author: Uyanide pywang0608@foxmail.com Date: 2026-03-25 05:30:50 -Description: LRCLIB search fetcher — fuzzy search via lrclib.net /api/search -""" - -""" -Used when metadata is incomplete (no album or duration) but title is available. -Selects the best match by duration when track length is known. +Description: LRCLIB search fetcher — fuzzy search via lrclib.net /api/search. + Used when metadata is incomplete (no album or duration) but title is available. """ import asyncio diff --git a/lrx_cli/fetchers/musixmatch.py b/lrx_cli/fetchers/musixmatch.py index 33476f1..56113e3 100644 --- a/lrx_cli/fetchers/musixmatch.py +++ b/lrx_cli/fetchers/musixmatch.py @@ -1,16 +1,14 @@ """ Author: Uyanide pywang0608@foxmail.com Date: 2026-04-04 15:28:34 -Description: Musixmatch fetchers (desktop API, usertoken auth) -""" +Description: Musixmatch fetchers (desktop API, anonymous or usertoken auth). -""" -Uses the Musixmatch desktop API (apic-desktop.musixmatch.com). -Token and all HTTP calls are managed by MusixmatchAuthenticator. + Uses the Musixmatch desktop API (apic-desktop.musixmatch.com). + Token and all HTTP calls are managed by MusixmatchAuthenticator. -Two fetchers: - musixmatch-spotify — direct lookup by Spotify track ID (exact, no search) - musixmatch — metadata search + best-candidate fallback + Two fetchers: + musixmatch-spotify — direct lookup by Spotify track ID (exact, no search) + musixmatch — metadata search + best-candidate fallback """ import json @@ -24,9 +22,7 @@ from ..lrc import LRCData from ..models import CacheStatus, LyricResult, TrackMeta from ..config import TTL_NETWORK_ERROR, TTL_NOT_FOUND -_MUSIXMATCH_MACRO_URL = ( - "https://apic-desktop.musixmatch.com/ws/1.1/macro.subtitles.get" -) +_MUSIXMATCH_MACRO_URL = "https://apic-desktop.musixmatch.com/ws/1.1/macro.subtitles.get" _MUSIXMATCH_SEARCH_URL = "https://apic-desktop.musixmatch.com/ws/1.1/track.search" # Macro-specific params (format/app_id injected by authenticator) diff --git a/lrx_cli/fetchers/netease.py b/lrx_cli/fetchers/netease.py index e0601f8..6160025 100644 --- a/lrx_cli/fetchers/netease.py +++ b/lrx_cli/fetchers/netease.py @@ -1,15 +1,10 @@ """ Author: Uyanide pywang0608@foxmail.com Date: 2026-03-25 11:04:51 -Description: Netease Cloud Music fetcher -""" +Description: Netease Cloud Music fetcher. -""" -Uses the public cloudsearch API for searching and the song/lyric API for -retrieving lyrics. No authentication required. - -Search results are filtered by duration when the track has a known length -to avoid returning lyrics for the wrong version of a song. + Uses the public cloudsearch API for searching and the song/lyric API for + retrieving lyrics. No authentication required. """ import asyncio diff --git a/lrx_cli/fetchers/qqmusic.py b/lrx_cli/fetchers/qqmusic.py index ad10922..d85ce92 100644 --- a/lrx_cli/fetchers/qqmusic.py +++ b/lrx_cli/fetchers/qqmusic.py @@ -1,14 +1,12 @@ """ Author: Uyanide pywang0608@foxmail.com Date: 2026-03-31 01:54:02 -Description: QQ Music fetcher via self-hosted API proxy -""" +Description: QQ Music fetcher via self-hosted API proxy. -""" -Requires a running qq-music-api instance. -The base URL is read from the QQ_MUSIC_API_URL environment variable. + Requires a running qq-music-api instance. + The base URL is read from the QQ_MUSIC_API_URL environment variable. -Search → pick best match by duration → fetch LRC lyrics. + Search → pick best match → fetch LRC lyrics. """ import asyncio diff --git a/lrx_cli/fetchers/selection.py b/lrx_cli/fetchers/selection.py index 92c416c..7932266 100644 --- a/lrx_cli/fetchers/selection.py +++ b/lrx_cli/fetchers/selection.py @@ -1,9 +1,11 @@ """ -Shared candidate-selection logic for search-based fetchers. +Author: Uyanide pywang0608@foxmail.com +Date: 2026-04-04 11:32:23 +Description: Shared candidate-selection logic for search-based fetchers. -Each fetcher maps its API-specific results to SearchCandidate, then calls -select_best() which scores candidates by metadata similarity, duration -proximity, and sync status. + Each fetcher maps its API-specific results to SearchCandidate, then calls + select_best() which scores candidates by metadata similarity, duration + proximity, and sync status. """ from dataclasses import dataclass diff --git a/lrx_cli/lrc.py b/lrx_cli/lrc.py index f7aa99e..f9a0caa 100644 --- a/lrx_cli/lrc.py +++ b/lrx_cli/lrc.py @@ -1,7 +1,7 @@ """ Author: Uyanide pywang0608@foxmail.com Date: 2026-03-25 21:54:01 -Description: Shared LRC time-tag utilities (definitely overengineered) +Description: Shared LRC time-tag utilities (definitely overengineered). """ import re diff --git a/lrx_cli/models.py b/lrx_cli/models.py index 0626d7e..c91d75f 100644 --- a/lrx_cli/models.py +++ b/lrx_cli/models.py @@ -1,7 +1,7 @@ """ Author: Uyanide pywang0608@foxmail.com Date: 2026-03-25 04:09:36 -Description: Data models +Description: Data models. """ from __future__ import annotations diff --git a/lrx_cli/mpris.py b/lrx_cli/mpris.py index 6f54977..1d9e12e 100644 --- a/lrx_cli/mpris.py +++ b/lrx_cli/mpris.py @@ -1,7 +1,7 @@ """ Author: Uyanide pywang0608@foxmail.com Date: 2026-03-25 04:44:15 -Description: MPRIS integration for fetching track metadata +Description: MPRIS integration for fetching track metadata. """ import asyncio diff --git a/lrx_cli/normalize.py b/lrx_cli/normalize.py index 941e3d9..4a20184 100644 --- a/lrx_cli/normalize.py +++ b/lrx_cli/normalize.py @@ -1,7 +1,8 @@ """ -Shared text normalization utilities for fuzzy matching. - -Used by cache key generation, cache search, and candidate selection scoring. +Author: Uyanide pywang0608@foxmail.com +Date: 2026-04-02 05:24:27 +Description: Shared text normalization utilities for fuzzy matching. + Used by cache key generation, cache search, and candidate selection scoring. """ import re