Skip to content

feat(locallibrary): add a discogs plugin for covers and track details - #598

Open
botandbang wants to merge 3 commits into
mainfrom
bnb/loc-100-discogs-plugin
Open

botandbang wants to merge 3 commits into
mainfrom
bnb/loc-100-discogs-plugin

Conversation

@botandbang

@botandbang botandbang commented Nov 12, 2026 •

Copy link
Copy Markdown
Contributor

What and why

Fixes LOC-100. Replaces the plan in #227.

Adds two plugins on the providers hook, modelled on coverart:

  • plugins/discogs: discogs.covers (artwork) and discogs.tags (metadata), for locallibrary art fetch --from discogs.covers and locallibrary track fetch --from discogs.tags.
    • An album is searched by artist, album title and label when one of its tracks has a label, then by artist and album title if that finds nothing. A track without an album is searched by artist and track title.
    • Only releases titled as the album count, and a master's editions count once.
    • Each candidate is labelled like Bicep, Ninja Tune ZEN242, 2016, so the catalogue number shows (neither a track nor its tags have a field for it).
    • Tags offered: the album, its earliest year, the first label (Warp (2) read as Warp, "Not On Label" skipped) and the first style, else genre.
    • Scores: 0.95 found by label, 0.9 by name, 0.6 for the one release found by a track's title, 0.5 when there are several.
    • Covers are saved into the request's scratch folder and checked to be an image at least 16px wide, else a warning.
    • Discogs allows 60 authenticated requests a minute. On a 429 it waits as long as Retry-After says (a minute without one) and tries up to three times; a wait over two minutes leaves the album out with a warning. X-Discogs-Ratelimit-Remaining: 0 holds the next search for the rest of the minute.
    • Without an account, or with a token Discogs refuses, the lookup stops with one note saying how to sign in.
    • Capabilities: library:read (for a track's label), net:api.discogs.com (one request a second at most) and net:i.discogs.com. Requests carry locallibrary/<version> (+https://github.com/cutenode/localnetwork) as their contact.
  • plugins/accounts/discogs-account: a keys account type for a personal access token from discogs.com/settings/developers, sent as Discogs token={token}, whoami at /oauth/identity, with one scope covering only GET https://api.discogs.com/database/search*. Images are fetched without the account.

Also: both plugins are in apps/locallibrary/docs/plugins.md, how-it-works.md, editing.md and the plugin diagram, each crate has a README, and the CLI and player tests that list providers now list Discogs's too.

How it was tested

  • Plugin tests on FakeHost, with Discogs scripted from trimmed API shapes (no network): lookup order, scores, master grouping, no account, a refused token, 429 waits and retries, the per-minute hold, covers that can't be had, cancelling mid-wait, Discogs out of reach; Hegel properties for candidates only for what was asked, lookup order, and retries. 20 tests pass. Mutations checked: not holding after the last request of the minute, one try too many, splitting a title at the wrong dash, keeping a bad cover, scoring a title match as a name match.
  • cargo nextest run -p locallibrary-cli: 1278 passed, including the shipped-manifest checks that validate both new manifests.
  • cargo clippy --all-targets -- -D warnings on both crates and the CLI, cargo fmt --check.
  • Coverage of the new crate: 97.86% regions, 96.30% functions, 98.32% lines.

Not checked against the live API: Discogs' developer pages refused automated reads, so the response shapes follow the go-discogs client's types. Discogs' terms on downloading and keeping images (support.discogs.com/hc/en-us/articles/360009334593), which #227 asked about, need reading before merge.

New app or plugin

  • I went through Adding an app or plugin and did every step for this kind of project
  • The steps no check sees are done too: a changelog line, and READMEs that say what it does

Diagrams

diagrams-checked: apps/locallibrary/README.md: discogs links only crates the diagram already draws.
diagrams-checked: apps/locallibrary/docs/diagrams/accounts.md: a keys account behaves as the diagram's note says.

Checklist

  • Tests cover the change
  • For locallibrary: apps/locallibrary/changes/discogs-plugin.md has a changelog line
  • The READMEs, docs/ and --help still say what the code does

Budgets

budget-raise: deps/locallibrary-cli: the discogs plugin crate is the one package the CLI links that main does not (581 to 582)

Adds plugins/discogs, with covers and tags providers that search Discogs' database by an album's label, then its name, else a track's title, keep within Discogs' rate limit, and say how to sign in when there's no account. Adds plugins/accounts/discogs-account, a keys account type for a Discogs personal access token, scoped to database searches. Registers both with locallibrary, documents them, and updates the provider listings the CLI and player tests expect.
…lugin

# Conflicts:
#	apps/locallibrary/Cargo.toml
@botandbang
botandbang requested a review from bnb as a code owner November 12, 2026 19:15
@botandbang botandbang added enhancement New feature or request locallibrary locallibrary and the loclib-* crates locallibrary: plugins The plugin protocol, its host and the built-in plugins labels Nov 12, 2026
@linear-code

linear-code Bot commented Nov 12, 2026

Copy link
Copy Markdown

LOC-100

@github-actions github-actions Bot added documentation Improvements or additions to documentation dependencies Pull requests that update a dependency file locallibrary: cli The locallibrary command line locallibrary: player The terminal player and its waveforms tests Tests, fixtures and test harnesses labels Nov 12, 2026
@github-actions

github-actions Bot commented Nov 12, 2026 •

Copy link
Copy Markdown

Size

Compared with main. KiB are 1,024 bytes.

This pull request main Change
Client JavaScript 858.9 KiB 858.9 KiB 0 B (0%)
Client JavaScript, brotli 294.7 KiB 294.7 KiB 0 B (0%)
Client CSS 97.6 KiB 97.6 KiB 0 B (0%)
Client CSS, brotli 14.4 KiB 14.4 KiB 0 B (0%)

@github-actions

Copy link
Copy Markdown

Rust coverage

From run 840. Both are held to the thresholds in .cargo/config.toml.

Tests Lines Functions Regions
All 98.14% (92937/94702) 97.66% (15243/15608) 96.81% (206308/213104)
Hegel property tests alone 97.22% (92070/94702) 96.7% (15093/15608) 95.73% (204008/213104)

…'s floor and package count

No conflicts. The coverage check fails a crate with no floor, so plugins/discogs gets one just under what CI measured (98.32% lines, 96.30% functions, 98.01% regions). The CLI links 582 packages with the plugin, one more than main's 581: the plugin crate is the only package cargo tree lists that main doesn't. cargo-shear can't see the plugins used (build.rs links them), so discogs joins the others on its ignored list.
@github-actions github-actions Bot added the tooling Repo config, lint and build tooling, and GitHub settings label Nov 15, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Pull requests that update a dependency file documentation Improvements or additions to documentation enhancement New feature or request locallibrary: cli The locallibrary command line locallibrary: player The terminal player and its waveforms locallibrary: plugins The plugin protocol, its host and the built-in plugins locallibrary locallibrary and the loclib-* crates tests Tests, fixtures and test harnesses tooling Repo config, lint and build tooling, and GitHub settings

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants