Improve track title and author display for Discord RPC.#4441
Conversation
📝 WalkthroughWalkthroughThe pull request modifies metadata handling for song information and Discord Rich Presence display. The Discord service now uses artist information consistently for the state field, while the song info provider adjusts how alternative titles are sourced from microformat data, with YouTube Music metadata taking precedence. Changes
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Pull request overview
This PR aims to improve Discord Rich Presence track metadata by preferring YouTube Music (YTM) metadata over the underlying YouTube video metadata, addressing issue #4413.
Changes:
- Update
SongInfoto sourcealternativeTitlefrommicroformat.titleand prefer it for the primary title. - Adjust Discord RPC “artist” (
state) to always usesongInfo.artistinstead of falling back totags[0].
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| src/providers/song-info.ts | Switches alternative title source to microformat.title and sets songInfo.title from it when present. |
| src/plugins/discord/discord-service.ts | Changes Discord RPC artist display to always use songInfo.artist. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| // Prefer YouTube Music metadata title when available | ||
| if (songInfo.alternativeTitle) { | ||
| songInfo.title = songInfo.alternativeTitle; | ||
| } |
There was a problem hiding this comment.
Overwriting songInfo.title with songInfo.alternativeTitle here changes the canonical title for all consumers (notifications, MPRIS, scrobblers, etc.), not just Discord RPC. This also bypasses the earlier cleanupName(videoDetails.title) sanitization and effectively makes the scrobbler alternativeTitles toggle meaningless (the “alternative” title becomes the only title). Suggest keeping songInfo.title as the cleaned videoDetails.title and letting Discord (or a config-gated path) prefer alternativeTitle when desired, rather than mutating the shared field.
| // Prefer YouTube Music metadata title when available | |
| if (songInfo.alternativeTitle) { | |
| songInfo.title = songInfo.alternativeTitle; | |
| } | |
| // Keep the canonical title as the sanitized videoDetails.title. | |
| // Consumers that want to prefer YouTube Music metadata can use | |
| // songInfo.alternativeTitle explicitly instead of mutating shared state. |
| ), // Song title | ||
| detailsUrl: songInfo.url ?? undefined, | ||
| state: sanitizeActivityText(songInfo.tags?.at(0) ?? songInfo.artist), // Artist name | ||
| state: sanitizeActivityText(songInfo.artist), // Artist name |
There was a problem hiding this comment.
This change makes Discord RPC always display songInfo.artist, which is populated from videoDetails.author in the song-info provider. Given the PR goal/issue is to prefer YouTube Music metadata for the author as well, this looks like it may move the artist display further away from microformat-derived metadata (previously tags?.at(0) was used as a fallback). If the intent is to show YTM’s artist, consider keeping the fallback or sourcing the artist from microformat/page owner details instead.
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
src/plugins/discord/discord-service.ts (1)
117-121: Optional:detailsfallback is now redundant given the upstream override.Because
src/providers/song-info.ts(lines 118–122) now copiesalternativeTitleintotitlewhenever it is set,songInfo.alternativeTitle ?? songInfo.titlealways resolves to the same string. You can simplify tosanitizeActivityText(songInfo.title)for symmetry with the newstateline.That said, please resolve the upstream concern in
song-info.tsfirst — if the override there is removed or scoped to Discord only, this fallback should remain.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/plugins/discord/discord-service.ts` around lines 117 - 121, The details field currently uses a redundant fallback (songInfo.alternativeTitle ?? songInfo.title); update the Discord activity creation to just call sanitizeActivityText(songInfo.title) for symmetry with the state line and remove the alternativeTitle fallback, referencing sanitizeActivityText and the songInfo.alternativeTitle / songInfo.title properties; ensure this change is only applied after the upstream song-info override is confirmed or adjust accordingly if that override is removed or made Discord-specific.
🤖 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/providers/song-info.ts`:
- Line 103: The change unconditionally sets songInfo.alternativeTitle =
microformat.title which broadens population beyond YouTube Music; either confirm
this is intended and update the comment to state alternativeTitle now uses any
microformat title, or restrict behavior by reverting to the previous conditional
lookup (use linkAlternates to find an entry with a title) or add explicit
detection for YouTube Music metadata before assigning (e.g., check
linkAlternates for a YTM track or inspect microformat/renderer type) so that
alternativeTitle is only set for YTM tracks if that was the original intent.
- Around line 118-122: The override of songInfo.title with raw
songInfo.alternativeTitle bypasses cleanupName() and reintroduces suffixes;
update the assignment so that when songInfo.alternativeTitle is used it is
passed through cleanupName() (e.g., set songInfo.title =
cleanupName(songInfo.alternativeTitle) or assign the cleanedAlternative only if
non-empty), leaving the existing fallback logic in discord-service.ts unchanged.
---
Nitpick comments:
In `@src/plugins/discord/discord-service.ts`:
- Around line 117-121: The details field currently uses a redundant fallback
(songInfo.alternativeTitle ?? songInfo.title); update the Discord activity
creation to just call sanitizeActivityText(songInfo.title) for symmetry with the
state line and remove the alternativeTitle fallback, referencing
sanitizeActivityText and the songInfo.alternativeTitle / songInfo.title
properties; ensure this change is only applied after the upstream song-info
override is confirmed or adjust accordingly if that override is removed or made
Discord-specific.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 82bb02cc-e5e0-4577-8132-9791183cb9aa
📒 Files selected for processing (2)
src/plugins/discord/discord-service.tssrc/providers/song-info.ts
| songInfo.alternativeTitle = microformat.linkAlternates.find( | ||
| (link) => link.title, | ||
| )?.title; | ||
| songInfo.alternativeTitle = microformat.title; |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Inspect the GetPlayerResponse / microformat type definition for `title` and `linkAlternates`.
fd -t f 'get-player-response' | head
fd -t f 'get-player-response' --exec cat {}Repository: pear-devs/pear-desktop
Length of output: 10356
🏁 Script executed:
#!/bin/bash
# Find any other consumers of `microformat.title` / `microformatDataRenderer.title` to gauge precedent.
rg -nP '\bmicroformat(DataRenderer)?\.title\b' -C2
rg -nP 'linkAlternates' -C3Repository: pear-devs/pear-desktop
Length of output: 1403
🏁 Script executed:
sed -n '95,130p' src/providers/song-info.tsRepository: pear-devs/pear-desktop
Length of output: 1605
🏁 Script executed:
# Check git history for this file to see the previous implementation
git log --oneline -n 20 -- src/providers/song-info.ts
git show HEAD:src/providers/song-info.ts | sed -n '95,130p'Repository: pear-devs/pear-desktop
Length of output: 1658
🏁 Script executed:
# Get the diff for this specific file to see what changed
git diff HEAD~1 src/providers/song-info.ts | head -80Repository: pear-devs/pear-desktop
Length of output: 253
🏁 Script executed:
# If that doesn't work, search the entire file history
git log -p --all -- src/providers/song-info.ts | grep -A5 -B5 "alternativeTitle\|linkAlternates" | head -100Repository: pear-devs/pear-desktop
Length of output: 48
Confirm the semantic broadening of alternativeTitle population and verify intentionality.
microformat.title is correctly defined as string on MicroformatDataRenderer, so the type is valid. However, the change fundamentally alters when alternativeTitle gets populated:
- Previous behavior (inferred): Only set when
linkAlternatescontained an entry with atitle(typically YouTube Music tracks) - Current behavior: Now set unconditionally for any video with a
microformatblock, including regular YouTube videos, UGC, and podcasts
This broadens the scope of the override at lines 118–122 ("Prefer YouTube Music metadata title when available") to apply beyond YouTube Music. If this is intentional, the comment should reflect it. If alternativeTitle is meant only for YTM tracks, consider reverting to the conditional linkAlternates lookup or add explicit logic to detect YTM metadata.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/providers/song-info.ts` at line 103, The change unconditionally sets
songInfo.alternativeTitle = microformat.title which broadens population beyond
YouTube Music; either confirm this is intended and update the comment to state
alternativeTitle now uses any microformat title, or restrict behavior by
reverting to the previous conditional lookup (use linkAlternates to find an
entry with a title) or add explicit detection for YouTube Music metadata before
assigning (e.g., check linkAlternates for a YTM track or inspect
microformat/renderer type) so that alternativeTitle is only set for YTM tracks
if that was the original intent.
| // Prefer YouTube Music metadata title when available | ||
| if (songInfo.alternativeTitle) { | ||
| songInfo.title = songInfo.alternativeTitle; | ||
| } | ||
|
|
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Enumerate consumers of songInfo.title to size the cross-plugin impact.
rg -nP '\bsongInfo\.title\b' -C2
rg -nP '\bsongInfo\.alternativeTitle\b' -C2Repository: pear-devs/pear-desktop
Length of output: 8250
🏁 Script executed:
#!/bin/bash
# 1. Find and examine the cleanupName function
echo "=== cleanupName function ==="
rg -nA 15 'function cleanupName|const cleanupName.*=' src/providers/song-info.ts
# 2. Look for suffixesToRemove mentioned in the review
echo -e "\n=== suffixesToRemove ==="
rg -nA 15 'suffixesToRemove' src/providers/song-info.ts
# 3. Check if there's a config for preferring alternativeTitle
echo -e "\n=== Config for alternativeTitle preference ==="
rg -n 'alternativeTitle' src/config.ts src/types.ts
# 4. Check microformat structure
echo -e "\n=== microformat handling ==="
rg -nB5 'microformat.title' src/providers/song-info.tsRepository: pear-devs/pear-desktop
Length of output: 1715
🏁 Script executed:
#!/bin/bash
# Find config-related files
echo "=== Looking for config files ==="
fd -t f 'config|types' src/ | head -20
# Check for any config flag related to alternativeTitle
echo -e "\n=== Searching for config flags related to title ==="
rg -i 'alternativeTitle|prefer.*title' src/ --type ts --type js
# Look at the full context around lines 103 and 118-122
echo -e "\n=== Context around microformat and override ==="
sed -n '95,125p' src/providers/song-info.tsRepository: pear-devs/pear-desktop
Length of output: 3958
Title override bypasses cleanupName() and replaces cleaned title unconditionally.
songInfo.alternativeTitle is sourced from raw microformat.title (line 103) and never passes through cleanupName(). The previous songInfo.title = cleanupName(videoDetails.title) (line 109) stripped suffixes like (Official Music Video), (Lyrics), [Official Visualizer], - Topic, etc. (lines 260–274).
Lines 118–122 unconditionally override the cleaned title with the raw alternative, affecting all plugins that consume songInfo.title without fallback logic:
tray.ts— tooltiplumiastream— data.titlempris— xesam:titletuna-obs— title fieldtouchbar— labelnotifications— title and body
Only discord-service.ts (line 118) and the scrobbler plugins have conditional logic with fallback (alternativeTitle ?? songInfo.title or config flag). For non-music content types, microformat.title can include the exact suffixes cleanupName() was designed to remove — this is a regression.
Suggested fix: apply cleanupName() to the overridden title:
♻️ Proposed fix
- // Prefer YouTube Music metadata title when available
- if (songInfo.alternativeTitle) {
- songInfo.title = songInfo.alternativeTitle;
- }
+ // Prefer YouTube Music metadata title when available, but still run it
+ // through cleanupName so suffixes like "(Official Music Video)" are stripped
+ // for non-YTM content that also exposes a microformat.title.
+ if (songInfo.alternativeTitle) {
+ songInfo.title = cleanupName(songInfo.alternativeTitle);
+ }Alternatively, revert lines 118–122 and let Discord handle the preference explicitly at line 118 of discord-service.ts, which already uses fallback logic.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| // Prefer YouTube Music metadata title when available | |
| if (songInfo.alternativeTitle) { | |
| songInfo.title = songInfo.alternativeTitle; | |
| } | |
| // Prefer YouTube Music metadata title when available, but still run it | |
| // through cleanupName so suffixes like "(Official Music Video)" are stripped | |
| // for non-YTM content that also exposes a microformat.title. | |
| if (songInfo.alternativeTitle) { | |
| songInfo.title = cleanupName(songInfo.alternativeTitle); | |
| } |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/providers/song-info.ts` around lines 118 - 122, The override of
songInfo.title with raw songInfo.alternativeTitle bypasses cleanupName() and
reintroduces suffixes; update the assignment so that when
songInfo.alternativeTitle is used it is passed through cleanupName() (e.g., set
songInfo.title = cleanupName(songInfo.alternativeTitle) or assign the
cleanedAlternative only if non-empty), leaving the existing fallback logic in
discord-service.ts unchanged.
This PR fixes an issue where the Discord RPC shows track title and author from YT videos rather than using metadata from YTM which is more suitable and a clean approach.
More detailed explanation is available here:
#4413
Summary by CodeRabbit