fix: verified badge extraction for search results

also introduces support for collaborative videos (mainly music videos)
This commit is contained in:
2025-09-27 21:41:51 +02:00
parent e6d32091e1
commit f2adc2e561

View File

@@ -77,6 +77,7 @@ def parseRenderers(entry: dict, context: dict = {}) -> dict:
published_date = safeTraverse(entry, ["videoRenderer", "publishedTimeText", "simpleText"], default="now")
published_date = published_date.removeprefix("Streamed ")
description, description_html = parseDescriptionSnippet(safeTraverse(entry, ["videoRenderer", "descriptionSnippet", "runs"], default=[]))
collaborative = False
if "author_name" in context:
author_name = context["author_name"]
@@ -87,16 +88,20 @@ def parseRenderers(entry: dict, context: dict = {}) -> dict:
author_ucid = context["author_ucid"]
else:
author_ucid = safeTraverse(entry, ["videoRenderer", "ownerText", "runs", 0, "navigationEndpoint", "browseEndpoint", "browseId"], default="UNKNOWNCHANNELID")
if author_ucid == "UNKNOWNCHANNELID":
# this is a first indicator that a video is a collaborative (has multiple authors)
# if that's the case, let's take the first author's ucid as the ucid
collaborative = safeTraverse(entry, ["videoRenderer", "ownerText", "runs", 0, "navigationEndpoint", "showDialogCommand", "panelLoadingStrategy", "inlineContent", "dialogViewModel", "header", "dialogHeaderViewModel", "headline", "content"]) == "Collaborators"
if "verified" in context:
verified = context["verified"]
else:
verified = ythdd_extractor.isVerified(safeTraverse(entry, ["ownerBadges", 0]))
verified = ythdd_extractor.isVerified(safeTraverse(entry, ["videoRenderer", "ownerBadges", 0]))
if "avatar" in context:
avatar_url = context["avatar"]
else:
avatar_url = safeTraverse(entry, ["videoRenderer", "avatar", "decoratedAvatarViewModel", "avatar", "avatarViewModel", "image", "sources", 0, "url"], default="unknown")
avatar_url = safeTraverse(entry, ["videoRenderer", "avatar", "decoratedAvatarViewModel", "avatar", "avatarViewModel", "image", "sources", 0, "url"], default=DEFAULT_AVATAR)
views_or_viewers_model = safeTraverse(entry, ["videoRenderer", "viewCountText"])
if "simpleText" in views_or_viewers_model:
@@ -112,6 +117,30 @@ def parseRenderers(entry: dict, context: dict = {}) -> dict:
view_count = 0
view_count_text = "Unknown amount of views"
if collaborative:
livm = safeTraverse(entry, ["videoRenderer", "ownerText", "runs", 0, "navigationEndpoint", "showDialogCommand", "panelLoadingStrategy", "inlineContent", "dialogViewModel", "customContent", "listViewModel", "listItems"], default=[])
if "author_name" not in context:
# override the default "name1 and others" or "name1 and name2" text
# with full author info
all_authors = []
for collaborative_author in livm:
collaborative_author_name = safeTraverse(collaborative_author, ["listItemViewModel", "title", "content"])
if collaborative_author_name is not None:
all_authors.append(collaborative_author_name)
if all_authors != []: # check if custom extraction succeeded
author_name = ", ".join(all_authors)
if author_ucid == "UNKNOWNCHANNELID":
# retrieve main author's ucid
author_ucid = safeTraverse(livm, [0, "listItemViewModel", "title", "commandRuns", 0, "onTap", "innertubeCommand", "browseEndpoint", "browseId"], default="UNKNOWNCHANNELID")
if safeTraverse(entry, ["videoRenderer", "ownerBadges", 0]) is None:
# check if the main author is verified
verified = False
if safeTraverse(livm, [0, "listItemViewModel", "title", "attachmentRuns", 0, "element", "type", "imageType", "image", "sources", 0, "clientResource", "imageName"]) in ("AUDIO_BADGE", "CHECK_CIRCLE_FILLED"):
verified = True
if avatar_url == DEFAULT_AVATAR:
# retrieve the main channel's avatar
avatar_url = safeTraverse(livm, [0, "listItemViewModel", "leadingAccessory", "avatarViewModel", "image", "sources", 0, "url"], default=DEFAULT_AVATAR)
return {
"type": "video",
"title": safeTraverse(entry, ["videoRenderer", "title", "runs", 0, "text"]),