Music Catalog QA - DSP & ISRC Audit avatar

Music Catalog QA - DSP & ISRC Audit

Pricing

Pay per usage

Go to Apify Store
Music Catalog QA - DSP & ISRC Audit

Music Catalog QA - DSP & ISRC Audit

Audit music catalog ISRC delivery and metadata across Spotify, Apple Music, and Deezer. Produces evidence-rich correction reports.

Pricing

Pay per usage

Rating

0.0

(0)

Developer

Vlad Vitvitsky

Vlad Vitvitsky

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

5 days ago

Last modified

Share

Music Catalog QA prototype

A metadata-only prototype for auditing a music catalog across Spotify, Apple Music, and Deezer. It detects missing platform deliveries, wrong artist mapping, duplicate ISRCs, and conflicting title, artist, duration, date, explicit, and label metadata.

The observation API also returns useful source metadata instead of discarding it: album IDs and titles, source genres, normalized genres, artwork, track/disc numbers, contributors, storefront availability, and streamability when the source exposes those fields.

The prototype never downloads audio and never submits correction requests. It produces evidence-rich findings and a correction packet for a label, distributor, or artist manager to review.

Run the deterministic demo

./run-demo.ps1

Or run it directly:

uv run python -m catalog_qa audit examples/catalog.csv `
--fixtures examples/observations.json `
--output demo-output

Open demo-output/correction-report.md and inspect:

  • summary.json — counts by severity and issue type;
  • findings.csv / findings.json — one row per issue;
  • observations.json — normalized source observations;
  • correction-report.md — human-readable correction packets.

Try public live sources

uv run python -m catalog_qa audit examples/live-catalog.csv --live --output live-output

Live mode uses public surfaces and can optionally use the official Spotify API:

  • Deezer exact ISRC lookup;
  • Odesli/Songlink cross-platform link resolution when a platform URL is supplied;
  • Apple iTunes lookup/search for mapped track IDs or a title/artist fallback;
  • Spotify oEmbed for a known Spotify URL;
  • exact Spotify ISRC lookup when SPOTIFY_CLIENT_ID and SPOTIFY_CLIENT_SECRET are configured.

It is intentionally best-effort. Public endpoints can rate-limit, change, or return incomplete fields. Every observation includes its source, retrieval time, match method, confidence, and any error. A platform that cannot be checked reliably is reported as source_unavailable, never as a missing release. A missing_platform finding is emitted only after an exact lookup.

Apple title/artist search results are returned as unverified candidates. They are never promoted to a verified release without a supplied/mapped URL or an exact identifier lookup.

Genre normalization

Source genres are always preserved in observations[].genres. By default, known aliases are mapped deterministically into genre_matches, for example Dance to electronic/dance and dnb to electronic/drum_and_bass. Unknown values remain unmapped rather than being guessed.

An optional Sentence Transformer mode handles descriptive or unfamiliar English labels. Install it in the uv environment and run:

uv sync --extra genres
uv run python -m catalog_qa audit examples/live-catalog.csv --live `
--genre-normalization embeddings `
--genre-model BAAI/bge-small-en-v1.5 `
--output live-output

Every semantic result includes its score, acceptance state, and the top three alternatives. The model is therefore a guarded fallback, not the source of truth. Rules-only mode is the deployment default and does not load a model. The default embedding model is pinned to BGE small English v1.5 revision 5c38ec7c405ec4b44b94cc5a9bb96e735b38267a; calibrated automatic acceptance requires a score of at least 0.78 and a 0.02 lead over the second result.

The repeatable English evaluation set can be run with:

uv run python -m catalog_qa.genre_eval examples/genre-eval.json `
--model BAAI/bge-small-en-v1.5 `
--holdout `
--output genre-eval-bge.json

Current pinned-model results on 56 difficult positive descriptions and 16 non-music traps:

  • deterministic rules: 281/281 canonical names and aliases mapped correctly;
  • BGE and E5 both ranked the expected genre first for 53/56 difficult music descriptions (94.6%);
  • calibrated BGE automatically accepted 23/56 positives, with no wrong accepted positive and 0/16 false accepts;
  • E5 accepted 38/56 positives but also accepted 3/16 non-music traps;
  • therefore BGE is the default and low-confidence results remain review-only with top-three alternatives.

Thresholds were selected on a stratified half of the set and separately reported against the untouched half. This is a small contract-focused test, not a claim of universal genre classification accuracy.

Catalog columns

Required:

  • artist
  • title
  • isrc

Optional:

  • row_id (generated as row-N when omitted)
  • upc, release_date, duration_ms, explicit, label
  • spotify_url, apple_music_url, deezer_url
  • expected_spotify_artist_id
  • expected_apple_music_artist_id
  • expected_deezer_artist_id

Apify-shaped runner

The Docker image runs python -m catalog_qa actor. The Actor input accepts a catalog array and a mode of live or fixtures. Optional Spotify client credentials use an encrypted Apify secret input. On Apify, normalized audit rows are pushed to the default dataset and REPORT.md, SUMMARY.json, FINDINGS.json, and OBSERVATIONS.json are written to the default key-value store. Outside Apify the same runner writes an actor-output directory. Its dataset-items.json file mirrors the rows that the cloud Actor pushes to the default dataset, so the complete API response can be inspected locally.

The default dataset always starts with an audit_summary row, followed by any findings and then one normalized observation per checked platform. A clean audit therefore remains a valid, evidence-rich Actor result.

The Actor output schema exposes API links for the dataset, summary, findings, and Markdown report. Invalid catalog/fixture input fails with a non-zero exit code; the local CLI also writes a JSON error object to stderr.

Verify the contract

uv run python -m unittest discover -s tests -v

Scope and non-goals

This is an experiment, not a rights audit or legal opinion. It does not verify ownership, royalties, publishing registrations, DDEX compliance, audio identity, or every territory. High-severity findings should be confirmed by a human before contacting a DSP or distributor.