feat: able to set confidence for certain source via cli

This commit is contained in:
2026-04-02 19:28:20 +02:00
parent 6baa487565
commit c44797fbf9
6 changed files with 91 additions and 15 deletions
+9 -12
View File
@@ -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
+27 -1
View File
@@ -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]:
+24
View File
@@ -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(
*,
+1 -1
View File
@@ -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"
+29
View File
@@ -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:
Generated
+1 -1
View File
@@ -153,7 +153,7 @@ wheels = [
[[package]]
name = "lrx-cli"
version = "0.3.1"
version = "0.3.2"
source = { editable = "." }
dependencies = [
{ name = "cyclopts" },