fix: fix playlists not showing any videos due to outdated playlist parsing (#5774)

* TODO, CHANGE COMMIT MESSAGE WHEN DONE

* save

* fix: fix playlists videos parsing

* revert text

* do not shadow outer item variable
This commit is contained in:
Fijxu
2026-06-24 23:54:34 -04:00
committed by GitHub
parent 73a1bacea8
commit 08f862292a

View File

@@ -454,6 +454,10 @@ def get_playlist_videos(playlist : InvidiousPlaylist | Playlist, offset : Int32,
end end
end end
# TODO (2026-06-24): Migrate this function to use parsers instead, as it uses,
# the same LockupViewModel used in Channel videos and Youtube playlists that
# appears on searches (Invidious /search endpoint).
# Related to https://github.com/iv-org/invidious/pull/5736
def extract_playlist_videos(playlist_id : String, initial_data : Hash(String, JSON::Any)) def extract_playlist_videos(playlist_id : String, initial_data : Hash(String, JSON::Any))
videos = [] of PlaylistVideo | ProblematicTimelineItem videos = [] of PlaylistVideo | ProblematicTimelineItem
@@ -467,8 +471,7 @@ def extract_playlist_videos(playlist_id : String, initial_data : Hash(String, JS
tabs_contents = tabs_renderer.["contents"]? || tabs_renderer.["content"] tabs_contents = tabs_renderer.["contents"]? || tabs_renderer.["content"]
list_renderer = tabs_contents.["sectionListRenderer"]["contents"][0] list_renderer = tabs_contents.["sectionListRenderer"]["contents"][0]
item_renderer = list_renderer.["itemSectionRenderer"]["contents"][0] contents = list_renderer.["itemSectionRenderer"]["contents"].as_a
contents = item_renderer.["playlistVideoListRenderer"]["contents"].as_a
else else
# Continuation data # Continuation data
contents = initial_data["onResponseReceivedActions"][0]? contents = initial_data["onResponseReceivedActions"][0]?
@@ -479,15 +482,39 @@ def extract_playlist_videos(playlist_id : String, initial_data : Hash(String, JS
end end
contents.try &.each do |item| contents.try &.each do |item|
if i = item["playlistVideoRenderer"]? if i = item["lockupViewModel"]?
video_id = i.dig?("navigationEndpoint", "watchEndpoint", "videoId").try &.as_s || i.dig("videoId").as_s thumbnail_view_model = i.dig?(
plid = i.dig?("navigationEndpoint", "watchEndpoint", "playlistId").try &.as_s || playlist_id "contentImage", "thumbnailViewModel"
index = i.dig?("navigationEndpoint", "watchEndpoint", "index").try &.as_i64 || i.dig("index", "simpleText").as_s.to_i64 )
watch_endpoint = i.dig?("rendererContext", "commandContext", "onTap", "innertubeCommand", "watchEndpoint")
video_id = watch_endpoint.try &.["videoId"]?.try &.as_s
plid = watch_endpoint.try &.["playlistId"]?.try &.as_s || playlist_id
index = watch_endpoint.try &.["index"]?.try &.as_i64
metadata = i["metadata"]?
lockup_metadata_view_model = metadata.try &.dig?("lockupMetadataViewModel")
title = lockup_metadata_view_model.try &.dig?("title", "content").try &.as_s
lockup_metadata = lockup_metadata_view_model.try &.dig?("metadata")
metadata_rows = lockup_metadata.try &.dig?("contentMetadataViewModel", "metadataRows").try &.as_a
# Find the metadataParts with commandRuns inside, which contains author
# information.
metadata_parts = metadata_rows.try &.find { |row|
parts = row["metadataParts"]?.try &.as_a
parts && parts.any? { |item2| item2.dig?("text", "commandRuns").try &.as_a }
}.try &.["metadataParts"].as_a
if author_info = metadata_parts.try &.find(&.dig?("text", "commandRuns"))
.try &.["text"]
author = author_info["content"].as_s
ucid = author_info.dig?("commandRuns", 0, "onTap", "innertubeCommand", "browseEndpoint", "browseId")
.try &.as_s
end
length = thumbnail_view_model.try &.dig?("overlays", 0, "thumbnailBottomOverlayViewModel", "badges", 0, "thumbnailBadgeViewModel", "text").try &.as_s
length_seconds = decode_length_seconds(length) if length
title = i["title"].try { |t| t["simpleText"]? || t["runs"]?.try &.[0]["text"]? }.try &.as_s || ""
author = i["shortBylineText"]?.try &.["runs"][0]["text"].as_s || ""
ucid = i["shortBylineText"]?.try &.["runs"][0]["navigationEndpoint"]["browseEndpoint"]["browseId"].as_s || ""
length_seconds = i["lengthSeconds"]?.try &.as_s.to_i
live = false live = false
if !length_seconds if !length_seconds
@@ -496,15 +523,15 @@ def extract_playlist_videos(playlist_id : String, initial_data : Hash(String, JS
end end
videos << PlaylistVideo.new({ videos << PlaylistVideo.new({
title: title, title: title || "",
id: video_id, id: video_id || "",
author: author, author: author || "",
ucid: ucid, ucid: ucid || "",
length_seconds: length_seconds, length_seconds: length_seconds,
published: Time.utc, published: Time.utc,
plid: plid, plid: plid,
live_now: live, live_now: live,
index: index, index: index || -1_i64,
}) })
end end
rescue ex rescue ex