feat: able to set confidence for certain source via cli
This commit is contained in:
@@ -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
@@ -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]:
|
||||
|
||||
@@ -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
@@ -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"
|
||||
|
||||
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user