Skip to content

fix(artist): split conjunctions correctly and resolve missing artist IDs#3813

Draft
kairosci wants to merge 3 commits into
MetrolistGroup:mainfrom
kairosci:fix/artist-conjunction-handling
Draft

fix(artist): split conjunctions correctly and resolve missing artist IDs#3813
kairosci wants to merge 3 commits into
MetrolistGroup:mainfrom
kairosci:fix/artist-conjunction-handling

Conversation

@kairosci
Copy link
Copy Markdown
Contributor

@kairosci kairosci commented May 26, 2026

Problem

Artist names joined by conjunctions (e.g., "Tiziano Ferro e Ariete") were not split correctly. Conjunction words like "e" (Italian for "and") appeared as separate clickable artists, and when splitting a single run, the second artist inherited the first artist's navigation endpoint, leading to wrong artist pages.

Cause

  • splitArtistsByConjunction() only checked for standalone conjunction runs but did not split runs containing conjunction words
  • When splitting a single run, all split parts received the same navigationEndpoint, making the second artist navigate to the first artist's page
  • mapNotNull in fromMusicTwoRowItemRenderer filtered out artists with null IDs before resolveArtistIds() could resolve them

Solution

  • Split single runs like "Artist1 e Artist2" into separate runs
  • Only the first split part retains the original navigationEndpoint; subsequent parts get null
  • Replaced mapNotNull with .map in fromMusicTwoRowItemRenderer so null-ID artists are preserved for resolveArtistIds()
  • Added Italian translation "e" for the conjunction string
  • Replaced hardcoded " - " separator with ARTIST_SEPARATOR constant (" e ")

Testing

  • Built with ./gradlew :app:assembleFossDebug

Summary by CodeRabbit

Release Notes

  • Refactor
    • Standardized artist name formatting across the app with a consistent, localized separator for improved display consistency.
    • Updated artist display logic to ensure only valid artist entries appear in menus, playlists, and UI components.
    • Refined artist parsing to be more strict about data validation across various screens and features.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 26, 2026

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 1a231bc6-a21c-4766-9d6e-a9f4d8cf62ce

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR replaces hardcoded artist separator strings throughout the app with a shared, localization-aware ARTIST_SEPARATOR constant (" e "), adds Italian localization for the conjunction, and refactors parser logic to improve artist extraction and filtering in playback components.

Changes

Artist Separator Standardization

Layer / File(s) Summary
Constant definition and localization
app/src/main/kotlin/com/metrolist/music/utils/Utils.kt, app/src/main/res/values-it/metrolist_strings.xml
Defines ARTIST_SEPARATOR = " e " and adds Italian string resource and = "e".
UI list and grid item rendering
app/src/main/kotlin/com/metrolist/music/ui/component/Items.kt
Updates SongListItem, SongGridItem, AlbumListItem, AlbumGridItem, MediaMetadataListItem, and YouTube item variants to join artists using ARTIST_SEPARATOR.
Dropdown, menu items, and speed dials
app/src/main/kotlin/com/metrolist/music/ui/component/SongDropdownSelect.kt, app/src/main/kotlin/com/metrolist/music/ui/menu/AlbumMenu.kt, app/src/main/kotlin/com/metrolist/music/ui/menu/SongMenu.kt, app/src/main/kotlin/com/metrolist/music/ui/menu/YouTubeSongMenu.kt
Updates dropdown and menu components to use ARTIST_SEPARATOR for artist display in selections and speed dial items.
Screen and card components
app/src/main/kotlin/com/metrolist/music/ui/screens/HomeScreen.kt, app/src/main/kotlin/com/metrolist/music/ui/screens/wrapped/pages/WrappedTop5SongsScreen.kt
Updates CommunityPlaylistCard, DailyDiscoverCard, and wrapped screens to display artists using ARTIST_SEPARATOR.
Entity mapping
app/src/main/kotlin/com/metrolist/music/db/entities/SpeedDialItem.kt
Updates SpeedDialItem.fromYTItem() to use ARTIST_SEPARATOR when converting YouTube items to speed dial subtitles.
Playback services and callbacks
app/src/main/kotlin/com/metrolist/music/listentogether/ListenTogetherManager.kt, app/src/main/kotlin/com/metrolist/music/playback/MediaLibrarySessionCallback.kt, app/src/main/kotlin/com/metrolist/music/playback/MusicService.kt
Updates track info, media items, and widget UI to use ARTIST_SEPARATOR for artist formatting.
Player UI with artist filtering
app/src/main/kotlin/com/metrolist/music/ui/player/MiniPlayer.kt, app/src/main/kotlin/com/metrolist/music/ui/player/Player.kt
MiniPlayer now filters artists (non-null id, non-blank name) and uses ARTIST_SEPARATOR; Player changes separator to " - " for bottom sheet display.
Export and import logging
app/src/main/kotlin/com/metrolist/music/utils/PlaylistExporter.kt, app/src/main/kotlin/com/metrolist/music/viewmodels/BackupRestoreViewModel.kt
Updates M3U export and CSV import logging to use ARTIST_SEPARATOR.
Parser improvements
innertube/src/main/kotlin/com/metrolist/innertube/models/Runs.kt, innertube/src/main/kotlin/com/metrolist/innertube/pages/ArtistItemsPage.kt, innertube/src/main/kotlin/com/metrolist/innertube/pages/ArtistPage.kt
Runs.kt preserves navigation endpoints only on first split part; ArtistItemsPage.kt and ArtistPage.kt simplify artist extraction and return null when no valid artists exist instead of providing fallback entries with null ids.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • MetrolistGroup/Metrolist#3255: Changes song artist rendering in Items.kt by switching to orderedArtists; this PR standardizes the separator used for that display.
  • MetrolistGroup/Metrolist#2378: Modifies SongDropdownSelect.kt dropdown UI component; this PR refactors how artist strings are formatted in that same component.

Suggested reviewers

  • nyxiereal
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 7.41% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main fix: splitting conjunctions correctly in artist names and resolving missing artist IDs, which aligns with the primary changes across multiple files.
Description check ✅ Passed The description follows the template structure with all required sections (Problem, Cause, Solution, Testing, Related Issues) completed with sufficient detail about the artist conjunction handling fixes.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@kairosci
Copy link
Copy Markdown
Contributor Author

This applies to Italian artists, but the same principle applies to artists of other nationalities as well

Copy link
Copy Markdown
Contributor

@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: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
innertube/src/main/kotlin/com/metrolist/innertube/models/Runs.kt (1)

34-37: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Make conjunction splitting case-insensitive

conjunctionPattern is built without RegexOption.IGNORE_CASE, so in-text splitting remains case-sensitive while the standalone conjunction check is case-insensitive—mixed/upper-case conjunctions can bypass splitting.

Proposed fix
-    val conjunctionPattern = Regex(
-        if (words.isNotEmpty()) " (${words.joinToString("|") { Regex.escape(it) }}) | & "
-        else " & "
-    )
+    val conjunctionPattern = Regex(
+        if (words.isNotEmpty()) " (${words.joinToString("|") { Regex.escape(it) }}) | & "
+        else " & ",
+        options = setOf(RegexOption.IGNORE_CASE)
+    )
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@innertube/src/main/kotlin/com/metrolist/innertube/models/Runs.kt` around
lines 34 - 37, conjunctionPattern in Runs.kt is constructed without
case-insensitive matching so mixed/upper-case conjunctions aren't split; update
the Regex creation for conjunctionPattern to use case-insensitive matching
(e.g., pass RegexOption.IGNORE_CASE or embed (?i)) so the pattern built from
words and the standalone " & " are matched regardless of case, keeping the same
joinToString logic that escapes words.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@app/src/main/kotlin/com/metrolist/music/db/entities/SpeedDialItem.kt`:
- Line 80: Deserialization is still splitting artist strings using the
hard-coded ", " while serialization uses ARTIST_SEPARATOR (causing round-trip
failure); update the deserialization calls that currently use split(", ") to
split(ARTIST_SEPARATOR) (and preserve trimming if needed), i.e., change the code
that converts the subtitle back into artist names to use ARTIST_SEPARATOR
instead of the literal ", " in the SpeedDialItem deserialization logic so both
occurrences are fixed.

In `@app/src/main/kotlin/com/metrolist/music/ui/player/MiniPlayer.kt`:
- Around line 674-677: In MiniPlayer.kt update the logic that computes
displayArtists: stop filtering artists by it.id != null and instead only filter
by non-blank names (e.g., metadata.artists.filter { it.name.isNotBlank() }) so
the Text that joins names with ARTIST_SEPARATOR always shows valid names;
preserve any existing id checks where artist IDs are required for actions
(subscribe/navigation) rather than for rendering.

In `@app/src/main/kotlin/com/metrolist/music/utils/PlaylistExporter.kt`:
- Line 133: PlaylistExporter started using the ARTIST_SEPARATOR constant when
serializing artists but loadM3UOnline in BackupRestoreViewModel still splits
artist fields with a hardcoded ';', breaking round-trip imports; update
loadM3UOnline to use the same ARTIST_SEPARATOR constant (or split on
Regex.escape(ARTIST_SEPARATOR) if treating it as a regex) instead of split(';')
so both export (PlaylistExporter) and import (loadM3UOnline) use the identical
delimiter.

In `@app/src/main/kotlin/com/metrolist/music/utils/Utils.kt`:
- Line 12: Replace the hardcoded ARTIST_SEPARATOR constant with a locale-aware
retrieval and update callsites to use it: remove or stop using const val
ARTIST_SEPARATOR in Utils.kt and provide a way to get the separator from
resources (e.g., use context.getString(R.string.and) or
stringResource(R.string.and) in composables) so UI code that composes artists
(where ARTIST_SEPARATOR was used) builds the separator as "
${context.getString(R.string.and)} " rather than the literal " e "; update all
usages to call the new localized accessor or inline resource lookup (referencing
R.string.and and the former ARTIST_SEPARATOR symbol to find replacements).

---

Outside diff comments:
In `@innertube/src/main/kotlin/com/metrolist/innertube/models/Runs.kt`:
- Around line 34-37: conjunctionPattern in Runs.kt is constructed without
case-insensitive matching so mixed/upper-case conjunctions aren't split; update
the Regex creation for conjunctionPattern to use case-insensitive matching
(e.g., pass RegexOption.IGNORE_CASE or embed (?i)) so the pattern built from
words and the standalone " & " are matched regardless of case, keeping the same
joinToString logic that escapes words.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 39b94326-94e9-4d2d-a7cf-c9f6c8859fff

📥 Commits

Reviewing files that changed from the base of the PR and between d952e61 and cfaab15.

📒 Files selected for processing (20)
  • app/src/main/kotlin/com/metrolist/music/db/entities/SpeedDialItem.kt
  • app/src/main/kotlin/com/metrolist/music/listentogether/ListenTogetherManager.kt
  • app/src/main/kotlin/com/metrolist/music/playback/MediaLibrarySessionCallback.kt
  • app/src/main/kotlin/com/metrolist/music/playback/MusicService.kt
  • app/src/main/kotlin/com/metrolist/music/ui/component/Items.kt
  • app/src/main/kotlin/com/metrolist/music/ui/component/SongDropdownSelect.kt
  • app/src/main/kotlin/com/metrolist/music/ui/menu/AlbumMenu.kt
  • app/src/main/kotlin/com/metrolist/music/ui/menu/SongMenu.kt
  • app/src/main/kotlin/com/metrolist/music/ui/menu/YouTubeSongMenu.kt
  • app/src/main/kotlin/com/metrolist/music/ui/player/MiniPlayer.kt
  • app/src/main/kotlin/com/metrolist/music/ui/player/Player.kt
  • app/src/main/kotlin/com/metrolist/music/ui/screens/HomeScreen.kt
  • app/src/main/kotlin/com/metrolist/music/ui/screens/wrapped/pages/WrappedTop5SongsScreen.kt
  • app/src/main/kotlin/com/metrolist/music/utils/PlaylistExporter.kt
  • app/src/main/kotlin/com/metrolist/music/utils/Utils.kt
  • app/src/main/kotlin/com/metrolist/music/viewmodels/BackupRestoreViewModel.kt
  • app/src/main/res/values-it/metrolist_strings.xml
  • innertube/src/main/kotlin/com/metrolist/innertube/models/Runs.kt
  • innertube/src/main/kotlin/com/metrolist/innertube/pages/ArtistItemsPage.kt
  • innertube/src/main/kotlin/com/metrolist/innertube/pages/ArtistPage.kt

Comment thread app/src/main/kotlin/com/metrolist/music/db/entities/SpeedDialItem.kt Outdated
Comment on lines +674 to +677
val displayArtists = metadata.artists.filter { it.id != null && it.name.isNotBlank() }
if (displayArtists.isNotEmpty()) {
Text(
text = metadata.artists.joinToString { it.name },
text = displayArtists.joinToString(ARTIST_SEPARATOR) { it.name },
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Do not gate displayed artist names on id.

At Line 674, filtering by it.id != null can hide valid artist names in the mini-player subtitle when IDs are unavailable. For text rendering, filter by non-blank name only; keep ID checks for actions (e.g., subscribe).

Proposed fix
-                val displayArtists = metadata.artists.filter { it.id != null && it.name.isNotBlank() }
+                val displayArtists = metadata.artists.filter { it.name.isNotBlank() }
                 if (displayArtists.isNotEmpty()) {
                     Text(
                         text = displayArtists.joinToString(ARTIST_SEPARATOR) { it.name },
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/src/main/kotlin/com/metrolist/music/ui/player/MiniPlayer.kt` around lines
674 - 677, In MiniPlayer.kt update the logic that computes displayArtists: stop
filtering artists by it.id != null and instead only filter by non-blank names
(e.g., metadata.artists.filter { it.name.isNotBlank() }) so the Text that joins
names with ARTIST_SEPARATOR always shows valid names; preserve any existing id
checks where artist IDs are required for actions (subscribe/navigation) rather
than for rendering.

Comment thread app/src/main/kotlin/com/metrolist/music/utils/PlaylistExporter.kt Outdated
Comment thread app/src/main/kotlin/com/metrolist/music/utils/Utils.kt Outdated
@kairosci kairosci marked this pull request as draft May 26, 2026 21:05
@kairosci kairosci force-pushed the fix/artist-conjunction-handling branch from 57b35a7 to b83719f Compare May 26, 2026 21:32
@kairosci kairosci force-pushed the fix/artist-conjunction-handling branch from b83719f to 08a5f17 Compare May 26, 2026 21:35
When artists are separated by conjunctions in YouTube Music API responses,
all artists now maintain their navigationEndpoint, not just the first one.
This allows each artist to be individually clickable without showing commas.

Fixes: PR MetrolistGroup#3813
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