Skip to content

Fix yt-dlp using wrong music-service track metadata - #33

Merged
MrDix merged 3 commits into
mainfrom
fix/yt-dlp-track-metadata
Mar 14, 2026
Merged

Fix yt-dlp using wrong music-service track metadata#33
MrDix merged 3 commits into
mainfrom
fix/yt-dlp-track-metadata

Conversation

@MrDix

@MrDix MrDix commented Mar 14, 2026

Copy link
Copy Markdown
Owner

Summary

  • YouTube Music embeds its own artist/track metadata into videos, which can differ from the actual video title. get_youtube_title() prefers these YT Music fields, so incorrect suffixes like (live) propagate into the UltraStar output and all generated filenames.
  • Adds strip_unmatched_suffixes() which cross-checks trailing parenthetical groups in the YT Music track name against the actual video title and strips any that are absent (e.g. (live), (acoustic), (remastered)) while keeping legitimate ones (e.g. (feat. …)).
  • 16 unit tests covering the new function and the integration with get_youtube_title().

Problem

Real-world example: https://youtu.be/OnzkhQsmSag

Field Value
Video title Electric Callboy - PUMP IT (OFFICIAL VIDEO)
YT Music track Pump It (live)incorrect
After fix Pump It(live) stripped

The (live) tag comes from YouTube Music's internal metadata system, not from the video itself. This is a known yt-dlp behavior where YouTube enriches videos with metadata from YouTube Music that can be inaccurate.

How it works

strip_unmatched_suffixes(track, video_title) iteratively checks trailing (...) groups in the track name:

  1. Extract the trailing parenthetical suffix content (e.g. live from (live))
  2. Check if that content appears anywhere in the video title (case-insensitive)
  3. If not found → strip the suffix and log a warning
  4. If found → keep it (it's a legitimate qualifier)
  5. Repeat for the next trailing suffix

This preserves inner parenthetical parts (e.g. Song (Part 2)) and keeps suffixes that are confirmed by the video title.

Test plan

  • strip_unmatched_suffixes() strips (live) when not in video title
  • Keeps suffix when present in video title
  • Strips (acoustic) when not in video title
  • Keeps (feat. …) when in video title
  • Strips multiple trailing suffixes
  • Keeps inner parenthetical groups
  • No-op when no parenthetical present
  • Handles empty track name
  • Case-insensitive matching
  • Strips only unmatched, keeps matched (mixed case)
  • Integration: get_youtube_title() applies stripping
  • Integration: get_youtube_title() keeps matching suffix
  • Full test suite: 156 passed, 3 skipped

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Improved YouTube audio metadata: smarter track-name cleanup removes irrelevant trailing qualifiers when they don't match the video title, yielding cleaner artist/track results.
  • Tests

    • Expanded test coverage for YouTube title parsing and track cleanup, including many suffix, case, whitelist, and edge-case scenarios; added thumbnail-related path tests.

YouTube Music embeds its own metadata (artist/track) into videos,
which can differ from the actual video title.  For example, a video
titled "Artist - SONG (OFFICIAL VIDEO)" may carry YT Music metadata
with track="Song (live)" even though it is not a live recording.

Since get_youtube_title() prefers the YT Music `artist`/`track` fields
over the video `title`, these incorrect suffixes propagate into the
UltraStar output and all generated filenames.

Add strip_unmatched_suffixes() which cross-checks trailing parenthetical
groups in the track name against the video title and removes any that
are absent (e.g. "(live)", "(acoustic)", "(remastered)") while keeping
legitimate ones (e.g. "(feat. …)").

Example: https://youtu.be/OnzkhQsmSag
- Video title: "Electric Callboy - PUMP IT (OFFICIAL VIDEO)"
- YT Music track: "Pump It (live)"  ← incorrect
- After fix: "Pump It"  ← "(live)" stripped

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Mar 14, 2026

Copy link
Copy Markdown

Warning

Rate limit exceeded

@MrDix has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 18 minutes and 21 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 4866c63c-89fd-42c2-aed5-ee7fd659a173

📥 Commits

Reviewing files that changed from the base of the PR and between fb3c6ea and 38dee6c.

📒 Files selected for processing (2)
  • pytest/modules/Audio/test_youtube.py
  • src/modules/Audio/youtube.py
📝 Walkthrough

Walkthrough

Added a public utility strip_unmatched_suffixes(track, video_title) to the YouTube audio module and integrated it into get_youtube_title to remove unmatched parenthetical suffixes from track names. Comprehensive unit tests were added/expanded to validate stripping behavior and related title parsing.

Changes

Cohort / File(s) Summary
YouTube audio source
src/modules/Audio/youtube.py
Added strip_unmatched_suffixes(track, video_title) which iteratively removes trailing parenthetical suffixes from track names when the suffix content doesn't appear in the video title. get_youtube_title() now invokes this post-processing when artist/track are present. Added re usage and logging via red_highlighted.
Tests
pytest/modules/Audio/test_youtube.py
Expanded test suite: added TestStripUnmatchedSuffixes with many cases (case-insensitive matching, whitelist/preservation rules, edge cases), augmented TestGetYoutubeTitle with suffix-related scenarios, updated imports to expose strip_unmatched_suffixes, and added thumbnail download path tests using mocks.
Misc (scaffolding/formatting)
...
Minor whitespace/newline and test scaffolding adjustments to support new tests and consistent formatting.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Poem

🐰 I nibble at brackets, tidy each tune,
Stripping odd suffixes beneath the moon.
Tests hop beside me, all tidy and spry,
Metadata neat as a carrot pie.
Hooray — the track names gleam, oh my! 🥕🎶

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 58.62% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the core issue being fixed: stripping erroneous suffixes from track metadata sourced from YouTube Music, which resolves incorrect metadata appearing in UltraStar output.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/yt-dlp-track-metadata
📝 Coding Plan
  • Generate coding plan for human review comments

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/modules/Audio/youtube.py`:
- Line 39: The warning string built in src/modules/Audio/youtube.py using
ULTRASINGER_HEAD and red_highlighted includes an EN DASH character; update the
f-string that references suffix_content to use a plain hyphen '-' instead of the
en dash so Ruff RUF001 is resolved (look for the formatted message constructed
with ULTRASINGER_HEAD and red_highlighted around the text "Stripped YT Music
suffix ... – not in video title" and replace the "–" with "-").
- Around line 35-41: The code is too aggressive: it strips any trailing
parenthetical (suffix_content from m.group(1)) when that text isn't in
video_title, which removes valid metadata like "(feat. Guest)"; change the logic
to only remove the suffix when it matches a restricted cleanup whitelist (e.g.,
case-insensitive patterns like "live", "acoustic", "official( video| audio)?",
"lyrics", "remastered", etc.) rather than any unmatched parenthetical.
Concretely, update the code around suffix_content, m, video_title and track so
you check suffix_content.lower() against a predefined set/regex of cleanup
tokens and only do track = track[: m.start()].strip() (and print the strip
message) when it matches that whitelist; otherwise leave track unchanged.
- Around line 56-60: The branch currently checks only for "artist" but directly
accesses result["track"] and result.get("title") without ensuring a usable track
or non-None title; update the condition to require a present, non-empty track
(e.g., check "track" in result and bool(result.get("track"))), use
result.get("title", "") or coerce None to "" when assigning video_title, call
strip_unmatched_suffixes(track, video_title) with the validated track and title,
and return result["artist"].strip(), track so the later title/channel fallback
runs when track is absent; refer to the variables/function names result, track,
video_title, and strip_unmatched_suffixes to locate and change the logic.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 75421b12-e7e1-4190-911b-eecfa98e95a8

📥 Commits

Reviewing files that changed from the base of the PR and between 7ac91a1 and 3b4f358.

📒 Files selected for processing (2)
  • pytest/modules/Audio/test_youtube.py
  • src/modules/Audio/youtube.py

Comment thread src/modules/Audio/youtube.py
Comment thread src/modules/Audio/youtube.py Outdated
Comment thread src/modules/Audio/youtube.py Outdated
- Replace open-ended suffix stripping with a whitelist of known YouTube
  Music qualifiers (live, acoustic, remastered, radio edit, explicit,
  clean, lyrics, official video/audio, single version).  Arbitrary
  metadata like "(feat. …)" or "(Part 2)" is now never stripped.
- Harden get_youtube_title() against missing/None track or artist fields
  using result.get() with fallback, so partial YT Music metadata falls
  through to the title-split or channel fallback paths.
- Replace EN DASH (–) with plain hyphen (-) in warning message (RUF001).
- Expand test suite from 16 to 27 tests covering whitelist edge cases,
  non-whitelisted suffixes (feat, Part), and missing track/artist fields.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/modules/Audio/youtube.py`:
- Around line 58-59: The current substring check using "if
suffix_content.lower() in video_title.lower()" can produce false positives;
replace it with a boundary-aware regex match using re.search(r'\b' +
re.escape(suffix_content.lower()) + r'\b', video_title.lower()) (import re if
needed) so the suffix_content matches as a whole word/token (or use split/token
comparison) before breaking; reference the suffix_content and video_title
variables in youtube.py.
- Around line 80-85: The fallback parsing uses result["title"] and
result["channel"] unsafely and splits the title twice which loses content after
additional dashes; change to read title = (result.get("title") or "").strip()
and channel = (result.get("channel") or "").strip(), test title truthiness, and
when splitting use title.split("-", 1) to only split on the first dash (then
strip parts) before returning; keep existing artist/track branch and continue to
call strip_unmatched_suffixes(track, video_title) with the safely normalized
video_title variable.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: cff50476-6c16-4308-9c70-7d26d5c27507

📥 Commits

Reviewing files that changed from the base of the PR and between 3b4f358 and fb3c6ea.

📒 Files selected for processing (2)
  • pytest/modules/Audio/test_youtube.py
  • src/modules/Audio/youtube.py

Comment thread src/modules/Audio/youtube.py Outdated
Comment thread src/modules/Audio/youtube.py Outdated
- Replace substring `in` check with word-boundary regex to avoid false
  positives (e.g. "live" matching inside "delivered").
- Harden fallback title/channel parsing: use result.get() with or ""
  for None safety, and split("-", 1) to preserve multi-dash titles
  like "Artist - Song - Part 2".
- Add 3 new tests: substring false positive, word boundary real match,
  multi-dash title preservation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@MrDix
MrDix merged commit ed8916a into main Mar 14, 2026
1 check passed
@MrDix
MrDix deleted the fix/yt-dlp-track-metadata branch March 14, 2026 05:13
MrDix pushed a commit that referenced this pull request Mar 14, 2026
Resolve conflicts: keep onset_correction setting and CLI option
alongside vocal_center_correction from PR #29.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@MrDix MrDix changed the title Fix yt-dlp using wrong YT Music track metadata Fix yt-dlp using wrong music-service track metadata Jul 4, 2026
MrDix added a commit that referenced this pull request Jul 4, 2026
* Fix yt-dlp using wrong track title from the music service metadata

the music service embeds its own metadata (artist/track) into videos,
which can differ from the actual video title.  For example, a video
titled "Artist - SONG (OFFICIAL VIDEO)" may carry the music service metadata
with track="Song (live)" even though it is not a live recording.

Since get_youtube_title() prefers the the music service `artist`/`track` fields
over the video `title`, these incorrect suffixes propagate into the
UltraStar output and all generated filenames.

Add strip_unmatched_suffixes() which cross-checks trailing parenthetical
groups in the track name against the video title and removes any that
are absent (e.g. "(live)", "(acoustic)", "(remastered)") while keeping
legitimate ones (e.g. "(feat. …)").

Example: https://youtu.be/OnzkhQsmSag
- Video title: "Electric Callboy - PUMP IT (OFFICIAL VIDEO)"
- the music service track: "Pump It (live)"  ← incorrect
- After fix: "Pump It"  ← "(live)" stripped

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Address CodeRabbit review: whitelist approach + defensive checks

- Replace open-ended suffix stripping with a whitelist of known the video platform
  Music qualifiers (live, acoustic, remastered, radio edit, explicit,
  clean, lyrics, official video/audio, single version).  Arbitrary
  metadata like "(feat. …)" or "(Part 2)" is now never stripped.
- Harden get_youtube_title() against missing/None track or artist fields
  using result.get() with fallback, so partial the music service metadata falls
  through to the title-split or channel fallback paths.
- Replace EN DASH (–) with plain hyphen (-) in warning message (RUF001).
- Expand test suite from 16 to 27 tests covering whitelist edge cases,
  non-whitelisted suffixes (feat, Part), and missing track/artist fields.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Address CodeRabbit re-review: word-boundary matching + safe fallback

- Replace substring `in` check with word-boundary regex to avoid false
  positives (e.g. "live" matching inside "delivered").
- Harden fallback title/channel parsing: use result.get() with or ""
  for None safety, and split("-", 1) to preserve multi-dash titles
  like "Artist - Song - Part 2".
- Add 3 new tests: substring false positive, word boundary real match,
  multi-dash title preservation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Anthony <anthony@baseattack.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant