diff --git a/ythdd_struct_parser.py b/ythdd_struct_parser.py index f8f0a16..692fc75 100644 --- a/ythdd_struct_parser.py +++ b/ythdd_struct_parser.py @@ -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"]),