Skip to content

feat(lyrics-plus): adding a performer tag for the Musixmatch provider#3689

Open
ianz56 wants to merge 3 commits intospicetify:mainfrom
ianz56:feat/performer-tag
Open

feat(lyrics-plus): adding a performer tag for the Musixmatch provider#3689
ianz56 wants to merge 3 commits intospicetify:mainfrom
ianz56:feat/performer-tag

Conversation

@ianz56
Copy link
Contributor

@ianz56 ianz56 commented Feb 3, 2026

Display performer tags for each line showing who the singer is. This can be enabled/disabled via the Option Menu.

output1.mp4

Summary by CodeRabbit

  • New Features

    • "Show performers" slider added to Adjustments (enabled by default); appears only when performer data exists and in Synced/Karaoke/Unsynced modes.
    • Lyrics now include performer/artist labels sourced from the provider and shown alongside lines with smart deduplication for consecutive same-performer lines.
  • Style

    • Subtle performer label styling (smaller, subdued text).
    • Improved hover cue for karaoke words to enhance interactivity.

@coderabbitai
Copy link

coderabbitai bot commented Feb 3, 2026

📝 Walkthrough

Walkthrough

Adds performer extraction and matching from Musixmatch metadata, annotates lyric lines with performer(s), renders optional performer labels in multiple lyric views, and exposes a "Show performers" toggle in the adjustments menu when performer data is present.

Changes

Cohort / File(s) Summary
Provider — performer extraction & matching
CustomApps/lyrics-plus/ProviderMusixmatch.js
Extend API request to include performer tagging; add parsePerformerData() and matchSequential() to build/align performer snippet queues; annotate lines returned by getKaraoke(), getSynced(), and getUnsynced() with a performer field.
Rendering — performer-aware lyric pages
CustomApps/lyrics-plus/Pages.js
Pass endTime to KaraokeLine and update its signature; include performer in active/padded lines; render a .lyrics-lyricsContainer-Performer span conditionally (honoring show-performers and synced-compact suppression) and add unique keys for word spans.
UI & config
CustomApps/lyrics-plus/OptionsMenu.js, CustomApps/lyrics-plus/index.js
AdjustmentsMenu signature now accepts hasPerformer; add "Show performers" slider visible when hasPerformer && mode ∈ {SYNCED, KARAOKE, UNSYNCED}; add CONFIG.visual["show-performers"] default true and compute hasPerformer at runtime.
Styling
CustomApps/lyrics-plus/style.css
Add .lyrics-lyricsContainer-Performer rules for small, subdued performer label; add hover rule adjusting karaoke word background-position.
Submodule / small changes
CustomApps/lyrics-plus-enhcance
Submodule commit reference updated (no code/API changes).

Sequence Diagram(s)

sequenceDiagram
    participant UI as Rendered UI
    participant Pages as Pages Component
    participant Provider as ProviderMusixmatch
    participant API as Musixmatch API
    participant Matcher as matchSequential

    UI->>Pages: request lyrics
    Pages->>Provider: fetch lyrics & metadata
    Provider->>API: request track (with performer tagging)
    API-->>Provider: return lyrics + performer_tagging metadata
    Provider->>Provider: parsePerformerData(meta) -> snippetQueue
    Provider->>Matcher: provide raw lines + snippetQueue
    Matcher->>Matcher: matchSequential() -> annotate lines with performer
    Matcher-->>Provider: enriched lines
    Provider-->>Pages: return lines (with performer)
    Pages->>Pages: compute hasPerformer, check CONFIG.visual["show-performers"]
    alt show-performers && hasPerformer
        Pages->>UI: render performer span + lyric text (suppress redundant labels when applicable)
    else
        Pages->>UI: render lyric text only
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Suggested reviewers

  • rxri

Poem

🐰 I hopped through tags and chased each name,

I stitched performers to each whispered frame,
Small labels bloom where voices once hid,
Toggle them on — see who softly did,
A tiny rabbit clap for every singing claim.

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% 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 summarizes the primary change: adding performer tag functionality to the Musixmatch provider in lyrics-plus, which is the core focus across all modified files.

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

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@CustomApps/lyrics-plus/ProviderMusixmatch.js`:
- Around line 94-157: parsePerformerData currently assumes
meta.track.performer_tagging exists and will throw if meta or meta.track or
performer_tagging is missing; add defensive checks at the top of
parsePerformerData to return an empty snippetQueue when meta, meta.track, or
meta.track.performer_tagging is falsy, ensure miscTags defaults to an empty
object and resourcesList is derived safely from tagging.resources?.artists
(falling back to []), and keep the rest of the logic (performerMap building,
normalizeForMatch, snippetQueue population) unchanged so the function never
operates on undefined fields.
🧹 Nitpick comments (1)
CustomApps/lyrics-plus/ProviderMusixmatch.js (1)

108-121: Consider safer parsing of fqid values.

The parseInt(fqid.split(":")[2]) pattern assumes a specific format. If the format is unexpected, this could return NaN or cause issues. The same pattern is repeated at line 119.

♻️ Suggested improvement
 const resolvedPerformers = c.performers.map((p) => {
 	let name = "Unknown";
 	if (p.type === "artist") {
 		const fqid = p.fqid;
-		const idFromFqid = fqid ? parseInt(fqid.split(":")[2]) : null;
+		const idFromFqid = fqid ? parseInt(fqid.split(":")[2], 10) : null;

 		const artist = resourcesList.find((r) => r.artist_id === idFromFqid);
 		if (artist) name = artist.artist_name;
 	} else if (miscTags[p.type]) {
 		name = miscTags[p.type];
 	}
 	return {
 		fqid: p.fqid,
-		artist_id: p.fqid ? parseInt(p.fqid.split(":")[2]) : null,
+		artist_id: p.fqid ? parseInt(p.fqid.split(":")[2], 10) : null,
 		name: name,
 	};
 });

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@CustomApps/lyrics-plus/ProviderMusixmatch.js`:
- Around line 110-135: resolvedPerformers currently includes entries with name
"Unknown" which end up in the UI; update the logic so only resolved performers
are kept by filtering out entries with name === "Unknown" (either filter the
resolvedPerformers array after the map or build it with a filter/flatMap) before
computing names and before returning the object so the returned performers array
and names.join(", ") contain only resolved performers; ensure the early return
(names.length === 0) stays intact and references
resolvedPerformers/names/snippet when constructing the returned object.

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