From c44797fbf98a51db6ea3fdf193d676f35ba7e66e Mon Sep 17 00:00:00 2001 From: Uyanide Date: Thu, 2 Apr 2026 19:28:20 +0200 Subject: [PATCH] feat: able to set confidence for certain source via cli --- README.md | 21 +++++++++------------ lrx_cli/cache.py | 28 +++++++++++++++++++++++++++- lrx_cli/cli.py | 24 ++++++++++++++++++++++++ pyproject.toml | 2 +- tests/test_cache.py | 29 +++++++++++++++++++++++++++++ uv.lock | 2 +- 6 files changed, 91 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 0263708..46b1b87 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ # LRX-CLI -A CLI tool for fetching LRC lyrics on Linux. Automatically detects the currently playing track via MPRIS/DBus and retrieves synced (or plain with all time tags set to `[00:00.00]` if failed to find any synced) lyrics from multiple sources. +A CLI tool for fetching LRC lyrics on Linux. Automatically detects the currently playing track via MPRIS/DBus and retrieves the best-matching lyrics from multiple sources, ranked by confidence scoring. ## Sources -Lyrics are fetched using a fallback pipeline (first synced result wins): +Sources are queried in order. High-confidence results (exact match or manual insert) terminate the pipeline early; otherwise all sources are tried and the highest-confidence result wins. 1. **Local** — sidecar `.lrc` files or embedded audio metadata (FLAC, MP3) 2. **Cache Search** — fuzzy cross-album lookup in local cache @@ -43,25 +43,22 @@ See `lrx --help` for full command reference. Common use cases: lrx search --path "/path/to/Westlife - My Love.flac" ``` -- Export to sidecar `.lrc` file: +- Export to sidecar `.lrc` file (or `.txt` with `--plain`): ```bash lrx export - ``` - - or to a custom path: - - ```bash + lrx export --plain lrx export --output /path/to/lyrics.lrc ``` - Cache management: ```bash - lrx cache stats # show cache statistics - lrx cache query # query cache for current track - lrx cache clear # clears cache of current track - lrx cache clear --all # clears entire cache + lrx cache stats # statistics with source×status table and confidence distribution + lrx cache query # inspect cache entries for current track + lrx cache clear # clear cache of current track + lrx cache clear --all # clear entire cache + lrx cache confidence spotify 100 # manually set confidence for a source ``` ## Configuration diff --git a/lrx_cli/cache.py b/lrx_cli/cache.py index c8f46a4..6c1d48e 100644 --- a/lrx_cli/cache.py +++ b/lrx_cli/cache.py @@ -133,7 +133,7 @@ class CacheEngine: elif status == CacheStatus.SUCCESS_UNSYNCED: confidence = LEGACY_CONFIDENCE_UNSYNCED else: - confidence = 100.0 # negative statuses: value irrelevant + confidence = 0.0 # negative statuses: no confidence return LyricResult( status=status, @@ -399,6 +399,32 @@ class CacheEngine: return matches + # Update + + def update_confidence( + self, + track: TrackMeta, + confidence: float, + source: str, + ) -> int: + """Update confidence for a specific source's cache entry matching *track*. + + Returns the number of rows updated. + """ + conditions, params = self._track_where(track) + if not conditions: + return 0 + conditions.append("source = ?") + params.append(source) + where = " AND ".join(conditions) + with sqlite3.connect(self.db_path) as conn: + cur = conn.execute( + f"UPDATE cache SET confidence = ? WHERE {where}", + [confidence] + params, + ) + conn.commit() + return cur.rowcount + # Query / inspect def query_track(self, track: TrackMeta) -> list[dict]: diff --git a/lrx_cli/cli.py b/lrx_cli/cli.py index c1beab1..63eebac 100644 --- a/lrx_cli/cli.py +++ b/lrx_cli/cli.py @@ -401,6 +401,30 @@ def stats(): print(f" {label:>{label_w}} : {count}") +@cache_app.command +def confidence( + source: Annotated[ + str, cyclopts.Parameter(help="Source to update (e.g. spotify, netease).") + ], + score: Annotated[float, cyclopts.Parameter(help="Confidence score (0-100).")], +): + """Set confidence score for the current track's cache entry from a specific source.""" + if not 0 <= score <= 100: + logger.error("Score must be between 0 and 100.") + sys.exit(1) + + track = get_current_track(_player) + if not track: + logger.error("No active playing track found.") + sys.exit(1) + + updated = manager.cache.update_confidence(track, score, source=source) + if updated: + print(f"Updated [{source}] confidence to {score:.0f}.") + else: + print(f"No cache entry found for [{source}].") + + @cache_app.command def insert( *, diff --git a/pyproject.toml b/pyproject.toml index b9772ec..5a8b665 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "hatchling.build" [project] name = "lrx-cli" -version = "0.3.1" +version = "0.3.2" description = "Fetch line-synced lyrics for your music player." readme = "README.md" requires-python = ">=3.13" diff --git a/tests/test_cache.py b/tests/test_cache.py index ce6bc89..205db32 100644 --- a/tests/test_cache.py +++ b/tests/test_cache.py @@ -305,6 +305,35 @@ def test_search_by_meta_fuzzy_rules_and_duration_sorting(cache_db: CacheEngine) assert sources[-1] == "unknown-len" +def test_update_confidence_targets_specific_source(cache_db: CacheEngine) -> None: + track = _track(artist="A", title="T", album="AL") + cache_db.set(track, "s1", _result(CacheStatus.SUCCESS_SYNCED, "x", "s1")) + cache_db.set(track, "s2", _result(CacheStatus.SUCCESS_UNSYNCED, "y", "s2")) + + updated = cache_db.update_confidence(track, 75.0, "s1") + + assert updated == 1 + rows = {r["source"]: r for r in cache_db.query_track(track)} + assert rows["s1"]["confidence"] == 75.0 + assert rows["s2"]["confidence"] == 100.0 # unchanged + + +def test_update_confidence_returns_zero_for_missing_source( + cache_db: CacheEngine, +) -> None: + track = _track(artist="A", title="T", album="AL") + cache_db.set(track, "s1", _result(CacheStatus.SUCCESS_SYNCED, "x", "s1")) + + assert cache_db.update_confidence(track, 50.0, "nonexistent") == 0 + + +def test_update_confidence_returns_zero_for_empty_track( + cache_db: CacheEngine, +) -> None: + empty = _track(artist=None, title=None, album=None, length=None) + assert cache_db.update_confidence(empty, 50.0, "s1") == 0 + + def test_query_track_and_stats_return_expected_aggregates( cache_db: CacheEngine, ) -> None: diff --git a/uv.lock b/uv.lock index 4ccaaef..a93895e 100644 --- a/uv.lock +++ b/uv.lock @@ -153,7 +153,7 @@ wheels = [ [[package]] name = "lrx-cli" -version = "0.3.1" +version = "0.3.2" source = { editable = "." } dependencies = [ { name = "cyclopts" },