Skip to content

Conversation

naoNao89
Copy link

This PR fixes issue #5454: Mix playlists rendering as "-1 videos" instead of showing a "Mix" label.

Summary of changes:

  • LockupViewModelParser (src/invidious/yt_backend/extractors.cr):
    • Detect MIX icon at any index in icon.sources.
    • Detect "Mix" case-insensitively in badge text.
    • Fallback Mix detection if playlist_id starts with RD.
    • Robust video_count extraction by reading digits from badge text (locale/case agnostic) and fallback to -1 if not present.
    • Populate is_mix flag on SearchPlaylist.
  • GridPlaylistRendererParser & PlaylistRendererParser:
    • Set is_mix when playlistId starts with RD (fallback for non-lockup structures).
  • SearchPlaylist (src/invidious/helpers/serialized_yt_data.cr):
    • Add is_mix : Bool = false (@[DB::Field(ignore: true)] to avoid DB impact).
  • locales/en-US.json:
    • Add missing label_mix key used by the UI overlay.

Why:

  • Current detection is brittle (only checks icon at index 0, exact text "Mix") and video_count parsing is English-only, causing UI to show "-1 videos" instead of "Mix" in many locales/variants.

Validation:

  • Added and executed a standalone script (not included in PR) to simulate lockup JSON cases. Results show improved detection/count parsing:
casecur_is_mixcur_countimp_is_miximp_count
icon_MIX_index0true430true430
text_Mix_onlytrue-1true-1
localized_videos_ptfalse-1false123
icon_MIX_index1false430true430
no_overlaysfalse-1false-1
text_mix_lowercasefalse-1true-1
episodes_countfalse430false430
count_Videos_capitalizedfalse-1false430
rd_prefix_no_overlaysfalse-1true-1

UI behavior:

  • With is_mix reliably set, the view overlay displays label_mix instead of numeric count for Mix playlists.

Notes:

  • Only en-US locale string added; other locales can be updated subsequently.

Fixes: #5454

…LockupViewModelParser: detect MIX icon at any index, case-insensitive 'Mix' text, RD- prefixed fallback; robust digit extraction for video_count.\n- GridPlaylistRendererParser/PlaylistRendererParser: set is_mix based on RD prefix.\n- SearchPlaylist: add is_mix field (ignored by DB).\n- locales(en-US): add label_mix.\n\nFixes: iv-org#5454
@SamantazFox
Copy link
Member

I'm wondering: Did you use an AI tool to write this ?

@naoNao89
Copy link
Author

naoNao89 commented Sep 15, 2025

@SamantazFox I use Copilot to create PR.

@ashley0143
Copy link

@naoNao89 whats a "Compitol" ?

@unixfox
Copy link
Member

unixfox commented Sep 16, 2025

It's copilot with a typo

Copy link
Member

@SamantazFox SamantazFox left a comment

Choose a reason for hiding this comment

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

I don't see where the frontend (HTML) code is using the new is_mix property. Did you forget to push a commit?

Comment on lines -125 to -126
"preferences_default_playlist": "Default playlist: ",
"preferences_default_playlist_none": "No default playlist set",
Copy link
Member

Choose a reason for hiding this comment

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

Please don't make unrelated changes.

Comment on lines -659 to -672
# This complicated sequences tries to extract the following data structure:
# "overlays": [{
# "thumbnailOverlayBadgeViewModel": {
# "thumbnailBadges": [{
# "thumbnailBadgeViewModel": {
# "text": "430 episodes",
# "badgeStyle": "THUMBNAIL_OVERLAY_BADGE_STYLE_DEFAULT"
# }
# }]
# }
# }]
#
# NOTE: this simplistic `.to_i` conversion might not work on larger
# playlists and hasn't been tested.
Copy link
Member

Choose a reason for hiding this comment

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

Please consider adapting the comment instead of entirely removing it

Comment on lines +668 to +678
# Detect Mix playlists via icon imageName at any index or text case-insensitively
is_mix = overlays.any? { |badge|
sources = badge.dig?("thumbnailBadgeViewModel", "icon", "sources").try &.as_a || [] of JSON::Any
has_mix_icon = sources.any? { |s| s.dig?("clientResource", "imageName").try &.as_s == "MIX" }
text = badge.dig?("thumbnailBadgeViewModel", "text").try &.as_s || ""
has_mix_text = text.downcase == "mix"
has_mix_icon || has_mix_text
}

# Fallback: RD-prefixed playlist IDs are Mixes
is_mix ||= playlist_id.starts_with? "RD"
Copy link
Member

Choose a reason for hiding this comment

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

I'm not sure to fully understand why you need all that extra logic to determine if the playlist is a mix, when that last check seems robust enough? (as far as I know, mixes have always began with RD).

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.

[Bug] Mix playlists render as -1 videos
4 participants