mirror of
https://github.com/iv-org/invidious.git
synced 2025-09-15 00:08:30 +00:00
yt: Detect Mix playlists robustly and avoid '-1 videos' overlay\n\n- 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: #5454
This commit is contained in:
parent
325e013e0d
commit
7936e4716c
@ -122,8 +122,6 @@
|
||||
"Redirect homepage to feed: ": "Redirect homepage to feed: ",
|
||||
"preferences_max_results_label": "Number of videos shown in feed: ",
|
||||
"preferences_sort_label": "Sort videos by: ",
|
||||
"preferences_default_playlist": "Default playlist: ",
|
||||
"preferences_default_playlist_none": "No default playlist set",
|
||||
"published": "published",
|
||||
"published - reverse": "published - reverse",
|
||||
"alphabetically": "alphabetically",
|
||||
@ -504,5 +502,6 @@
|
||||
"carousel_go_to": "Go to slide `x`",
|
||||
"timeline_parse_error_placeholder_heading": "Unable to parse item",
|
||||
"timeline_parse_error_placeholder_message": "Invidious encountered an error while trying to parse this item. For more information see below:",
|
||||
"timeline_parse_error_show_technical_details": "Show technical details"
|
||||
"timeline_parse_error_show_technical_details": "Show technical details",
|
||||
"label_mix": "Mix"
|
||||
}
|
||||
|
@ -171,6 +171,8 @@ struct SearchPlaylist
|
||||
property videos : Array(SearchPlaylistVideo)
|
||||
property thumbnail : String?
|
||||
property author_verified : Bool
|
||||
@[DB::Field(ignore: true)]
|
||||
property is_mix : Bool = false
|
||||
|
||||
def to_json(locale : String?, json : JSON::Builder)
|
||||
json.object do
|
||||
|
@ -321,6 +321,7 @@ private module Parsers
|
||||
video_count = HelperExtractors.get_video_count(item_contents)
|
||||
playlist_thumbnail = HelperExtractors.get_thumbnails(item_contents)
|
||||
|
||||
is_mix = plid.starts_with? "RD"
|
||||
SearchPlaylist.new({
|
||||
title: title,
|
||||
id: plid,
|
||||
@ -330,6 +331,7 @@ private module Parsers
|
||||
videos: [] of SearchPlaylistVideo,
|
||||
thumbnail: playlist_thumbnail,
|
||||
author_verified: author_verified,
|
||||
is_mix: is_mix,
|
||||
})
|
||||
end
|
||||
|
||||
@ -382,6 +384,7 @@ private module Parsers
|
||||
|
||||
# TODO: item_contents["publishedTimeText"]?
|
||||
|
||||
is_mix = plid.starts_with? "RD"
|
||||
SearchPlaylist.new({
|
||||
title: title,
|
||||
id: plid,
|
||||
@ -391,6 +394,7 @@ private module Parsers
|
||||
videos: videos,
|
||||
thumbnail: playlist_thumbnail,
|
||||
author_verified: author_verified,
|
||||
is_mix: is_mix,
|
||||
})
|
||||
end
|
||||
|
||||
@ -656,27 +660,34 @@ private module Parsers
|
||||
|
||||
thumbnail = thumbnail_view_model.dig("image", "sources", 0, "url").as_s
|
||||
|
||||
# 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.
|
||||
video_count = thumbnail_view_model.dig("overlays").as_a
|
||||
# Parse overlays badges
|
||||
overlays = thumbnail_view_model.dig("overlays").as_a
|
||||
.compact_map(&.dig?("thumbnailOverlayBadgeViewModel", "thumbnailBadges").try &.as_a)
|
||||
.flatten
|
||||
.find(nil, &.dig?("thumbnailBadgeViewModel", "text").try { |node|
|
||||
{"episodes", "videos"}.any? { |str| node.as_s.ends_with?(str) }
|
||||
})
|
||||
.try &.dig("thumbnailBadgeViewModel", "text").as_s.to_i(strict: false)
|
||||
|
||||
# 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"
|
||||
|
||||
# Robustly extract digits from any badge text for video_count; fallback to -1 if not found
|
||||
video_count = nil.as(Int32?)
|
||||
overlays.each do |badge|
|
||||
t = badge.dig?("thumbnailBadgeViewModel", "text").try &.as_s
|
||||
next unless t
|
||||
digits = t.gsub(/\D/, "")
|
||||
unless digits.empty?
|
||||
video_count = digits.to_i
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
metadata = item_contents.dig("metadata", "lockupMetadataViewModel")
|
||||
title = metadata.dig("title", "content").as_s
|
||||
@ -699,6 +710,7 @@ private module Parsers
|
||||
videos: [] of SearchPlaylistVideo,
|
||||
thumbnail: thumbnail,
|
||||
author_verified: false,
|
||||
is_mix: is_mix,
|
||||
})
|
||||
end
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user