From dd102cb6ae7e6f4036378c4a807e47198648ade5 Mon Sep 17 00:00:00 2001 From: sherl Date: Sat, 28 Dec 2024 04:53:37 +0100 Subject: [PATCH] introduce related videos, small fixes to invidious translation layer --- ythdd_inv_tl.py | 48 +++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 39 insertions(+), 9 deletions(-) diff --git a/ythdd_inv_tl.py b/ythdd_inv_tl.py index 8059b9d..cc1a879 100644 --- a/ythdd_inv_tl.py +++ b/ythdd_inv_tl.py @@ -5,7 +5,7 @@ # to use internal extractors. from flask import Response, request, redirect from markupsafe import escape -from time import strftime, localtime, time +from time import strftime, gmtime, time import json, datetime import invidious_formats import ythdd_globals @@ -47,9 +47,9 @@ def stats(): return send(200, data_to_send) def videoIdSanityCheck(videoId: str): - if len(videId) != 11: + if len(videoId) != 11: incrementBadRequests() - return send(400, f'error: bad request. wrong videoId: {videoId} is {len(videoId)} characters long, but should be 11.', []) + return send(400, f'error: bad request. wrong videoId: {videoId} is {len(videoId)} characters long, but should be 11.') # elif...? def auth(data): @@ -67,8 +67,7 @@ def streams(): return send(200, '') def epochToDate(epoch): - # TODO: replace with UTC time - return strftime('%Y-%m-%d %H:%M:%S', localtime(epoch)) + return strftime('%Y-%m-%dT%H:%M:%SZ', gmtime(epoch)) def trending(): return send(200, [{}]) @@ -106,6 +105,7 @@ def genThumbs(videoId: str): height = x['height'] quality = x['quality'] url = ythdd_globals.config['general']['public_facing_url'] + 'vi/' + videoId + '/' + x['url'] + '.jpg' + #url = '/vi/' + videoId + '/' + x['url'] + '.jpg' result.append({'quality': quality, 'url': url, 'width': width, 'height': height}) return result @@ -157,8 +157,8 @@ def rebuildFormats(data): except: pass - if data[x]['itag'] <= 80: # temporary solution, I promise! - formatStreams.append(result[x]) + #if data[x]['itag'] <= 80: # won't be triggered for iOS player as it has no progressive streams + # formatStreams.append(result[x]) return result, formatStreams @@ -202,7 +202,36 @@ def videos(data): keywords = safeTraverse(video_details, ['keywords'], default=[]) # TODO: https://github.com/iv-org/invidious/blob/master/src/invidious/videos/parser.cr#L258 - related = safeTraverse(wdata, ['ec2', 'contents', 'twoColumnWatchNextResults', 'secondaryResults', 'secondaryResults', 'results'], default=[]) # can possibly change in the future + related_raw = safeTraverse(wdata, ['ec2', 'contents', 'twoColumnWatchNextResults', 'secondaryResults', 'secondaryResults', 'results'], default=[]) # can possibly change in the future + related = [] + for x in related_raw: + y = safeTraverse(x, ['compactVideoRenderer']) + if type(y) != dict: + continue + related_video = {} + related_video['videoId'] = safeTraverse(y, ['videoId']) + related_video['title'] = safeTraverse(y, ['title', 'simpleText']) + related_video['videoThumbnails'] = genThumbs(related_video['videoId']) #safeTraverse(y, ['thumbnail', 'thumbnails']) + related_video['author'] = safeTraverse(y, ['longBylineText', 'runs', 0, 'text']) + related_video['authorId'] = safeTraverse(y, ['longBylineText', 'runs', 0, 'navigationEndpoint', 'browseEndpoint', 'browseId'], default="UNKNOWNCHANNELID") + related_video['authorUrl'] = '/channel/' + related_video['authorId'] + related_video['authorVerified'] = False + related_video['authorThumbnails'] = safeTraverse(y, ['channelThumbnail', 'thumbnails'], default=[]) + for z in related_video['authorThumbnails']: + z['url'] = ythdd_globals.translateLinks(z['url']) + related_video['lengthSeconds'] = 0 + time_lookup_list = [1, 60, 3_600, 86_400] + time_list = safeTraverse(y, ['lengthText', 'simpleText'], default="0:0").split(":") + for z in range(len(time_list)): + related_video['lengthSeconds'] += time_lookup_list[z] * int(time_list[len(time_list) - 1 - z]) + related_views_text = safeTraverse(y, ['viewCountText', 'simpleText'], default="0").split(" ")[0] + related_video['viewCountText'] = related_views_text + related_views = 0 + if related_views_text: + related_views = int("".join([z for z in related_views_text if 48 <= ord(z) and ord(z) <= 57])) + related_views_text = related_views_text.split(" ")[0] + related_video['viewCount'] = related_views + related.append(related_video) magnitude = {'K': 1_000, 'M': 1_000_000, 'B': 1_000_000_000} toplevel_buttons = safeTraverse(video_primary_renderer, ['videoActions', 'menuRenderer', 'topLevelButtons'], default={}) # hacky solution @@ -318,7 +347,7 @@ def videos(data): # "license": String # } # ], - 'recommendedVideos': [] # not yet implemented + "recommendedVideos": related # "recommendedVideos": [ # { # "videoId": String, @@ -353,6 +382,7 @@ def videos(data): # for debugging: #return send(200, ythdd_extractor.WEBextractSinglePage(data[3])) #return send(200, ythdd_extractor.IOSextract(data[3])) + #return send(200, {'idata': idata, 'wdata': wdata}) # if youtube returns not the videoId we aksed # then it means that the instance is ratelimited