From d0d229818606d0bbaf9e3ba04ff2e34bf6504545 Mon Sep 17 00:00:00 2001 From: sherl Date: Sun, 14 Sep 2025 04:01:19 +0200 Subject: [PATCH] fix: rely on hardcoded default user avatar for failed requests --- ythdd_inv_tl.py | 10 ++++++---- ythdd_struct_parser.py | 4 +++- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/ythdd_inv_tl.py b/ythdd_inv_tl.py index 4efd965..f29a38f 100644 --- a/ythdd_inv_tl.py +++ b/ythdd_inv_tl.py @@ -31,6 +31,8 @@ import ythdd_struct_parser # [*] /api/v1/auth/playlists (stub? db?) # [*] /api/v1/videos/videoIdXXXX +DEFAULT_AVATAR = "https://yt3.ggpht.com/a/default-user=s176-c-k-c0x00ffffff-no-rj" + def incrementBadRequests(): ythdd_globals.apiFailedRequests += 1 @@ -399,7 +401,7 @@ def videos(data): related_entry['authorId'] = safeTraverse(lmvm, ['image', 'decoratedAvatarViewModel', 'rendererContext', 'commandContext', 'onTap', 'innertubeCommand', 'browseEndpoint', 'browseId'], default="UNKNOWNCHANNELID") related_entry['authorUrl'] = '/channel/' + related_entry['authorId'] related_entry['authorVerified'] = False if safeTraverse(lmvm, ['metadata', 'contentMetadataViewModel', 'metadataRows', 0, 'metadataParts', 0, 'text', 'attachmentRuns']) is None else True # seens to do the job - author_avatar_url = safeTraverse(lmvm, ['image', 'decoratedAvatarViewModel', 'avatar', 'avatarViewModel', 'image', 'sources', 0, 'url'], default="no-avatar") + author_avatar_url = safeTraverse(lmvm, ['image', 'decoratedAvatarViewModel', 'avatar', 'avatarViewModel', 'image', 'sources', 0, 'url'], default=DEFAULT_AVATAR) related_entry['authorThumbnails'] = ythdd_extractor.generateChannelAvatarsFromUrl(author_avatar_url) related_entry['lengthSeconds'] = ythdd_struct_parser.parseLengthFromTimeBadge(safeTraverse(y, ['contentImage', 'thumbnailViewModel', 'overlays', 0, 'thumbnailOverlayBadgeViewModel', 'thumbnailBadges', 0, 'thumbnailBadgeViewModel', 'text'], default="0:0")) related_entry['viewCountText'] = safeTraverse(lmvm, ['metadata', 'contentMetadataViewModel', 'metadataRows', 1, 'metadataParts', 0, 'text', 'content'], default="0").split(" ")[0] @@ -424,7 +426,7 @@ def videos(data): author = safeTraverse(video_details, ['author'], default="Unknown Author") ucid = safeTraverse(video_details, ['channelId'], default="UNKNOWNCHANNELID") subs = ydata['channel_follower_count'] - author_thumbnail = ythdd_extractor.generateChannelAvatarsFromUrl(safeTraverse(video_secondary_renderer, ['owner', 'videoOwnerRenderer', 'thumbnail', 'thumbnails', 0, 'url'], default="no-avatar")) + author_thumbnail = ythdd_extractor.generateChannelAvatarsFromUrl(safeTraverse(video_secondary_renderer, ['owner', 'videoOwnerRenderer', 'thumbnail', 'thumbnails', 0, 'url'], default=DEFAULT_AVATAR)) # so far it seems to be impossible to tell if a channel is verified or not, # that is - without making another request @@ -582,7 +584,7 @@ def get_channel_tab(requested_tab, ucid, req, only_json: bool = False): # load relevant data from global (general) cache param = safeTraverse(ythdd_globals.general_cache["continuations"]["channels"][ucid], ["tabs", requested_tab, "param"], default=None) name = safeTraverse(ythdd_globals.general_cache["continuations"]["channels"][ucid], ["name"], default="") - avatar = safeTraverse(ythdd_globals.general_cache["continuations"]["channels"][ucid], ["avatar"], default="no-avatar") + avatar = safeTraverse(ythdd_globals.general_cache["continuations"]["channels"][ucid], ["avatar"], default=DEFAULT_AVATAR) verified = safeTraverse(ythdd_globals.general_cache["continuations"]["channels"][ucid], ["verified"], default=False) # if provided, ctoken will be used for browsing as well @@ -694,7 +696,7 @@ def channels(data, req, only_json: bool = False): wdata = ythdd_extractor.browseChannel(data[3]) channel_meta = safeTraverse(wdata, ["metadata", "channelMetadataRenderer"]) banners = safeTraverse(wdata, ["header", "pageHeaderRenderer", "content", "pageHeaderViewModel", "banner", "imageBannerViewModel", "image", "sources"], default=[]) - avatar = safeTraverse(wdata, ["header", "pageHeaderRenderer", "content", "pageHeaderViewModel", "image", "decoratedAvatarViewModel", "avatar", "avatarViewModel", "image", "sources", 0, "url"], default="no-avatar") + avatar = safeTraverse(wdata, ["header", "pageHeaderRenderer", "content", "pageHeaderViewModel", "image", "decoratedAvatarViewModel", "avatar", "avatarViewModel", "image", "sources", 0, "url"], default=DEFAULT_AVATAR) subscribers = ythdd_struct_parser.parseViewsFromViewText(safeTraverse(wdata, ["header", "pageHeaderRenderer", "content", "pageHeaderViewModel", "metadata", "contentMetadataViewModel", "metadataRows", 1, "metadataParts", 0, "text", "content"], default="0")) verified = False # to be replaced later with ythdd_extractor.isVerified(...) diff --git a/ythdd_struct_parser.py b/ythdd_struct_parser.py index 0cd5441..5dcc826 100644 --- a/ythdd_struct_parser.py +++ b/ythdd_struct_parser.py @@ -5,6 +5,8 @@ import dateparser import ythdd_globals import ythdd_extractor +DEFAULT_AVATAR = "https://yt3.ggpht.com/a/default-user=s176-c-k-c0x00ffffff-no-rj" + def genThumbs(videoId: str): result = [] @@ -276,7 +278,7 @@ def parseRenderers(entry: dict, context: dict = {}) -> dict: case "channelRenderer": # channels in search results - avatars = ythdd_extractor.generateChannelAvatarsFromUrl(safeTraverse(entry, ["channelRenderer", "thumbnail", "thumbnails", 0, "url"], default="no-avatar")) + avatars = ythdd_extractor.generateChannelAvatarsFromUrl(safeTraverse(entry, ["channelRenderer", "thumbnail", "thumbnails", 0, "url"], default=DEFAULT_AVATAR)) description, description_html = parseDescriptionSnippet(safeTraverse(entry, ["channelRenderer", "descriptionSnippet", "runs"], default=[])) isVerified = ythdd_extractor.isVerified(safeTraverse(entry, ["channelRenderer", "ownerBadges", 0], default=[]))