feat: livestream browsing
adds the ability to browse channel's livestreams, just like with shorts, videos and playlists
This commit is contained in:
@@ -619,6 +619,9 @@ def get_channel_tab(requested_tab, ucid, req, only_json: bool = False):
|
|||||||
tabs = safeTraverse(wdata, ["contents", "twoColumnBrowseResultsRenderer", "tabs"], default=[])
|
tabs = safeTraverse(wdata, ["contents", "twoColumnBrowseResultsRenderer", "tabs"], default=[])
|
||||||
for tab in tabs:
|
for tab in tabs:
|
||||||
tab_name = safeTraverse(tab, ["tabRenderer", "title"], default="").lower()
|
tab_name = safeTraverse(tab, ["tabRenderer", "title"], default="").lower()
|
||||||
|
# rewrite livestream tab for backwards compatibility with invidious (and clients like freetube)
|
||||||
|
if tab_name == "live":
|
||||||
|
tab_name = "streams"
|
||||||
if tab_name and tab_name == requested_tab:
|
if tab_name and tab_name == requested_tab:
|
||||||
result = safeTraverse(tab, ["tabRenderer", "content"], default=[])
|
result = safeTraverse(tab, ["tabRenderer", "content"], default=[])
|
||||||
break
|
break
|
||||||
@@ -628,8 +631,8 @@ def get_channel_tab(requested_tab, ucid, req, only_json: bool = False):
|
|||||||
new_continuation = ""
|
new_continuation = ""
|
||||||
response = {}
|
response = {}
|
||||||
match requested_tab:
|
match requested_tab:
|
||||||
case "videos" | "shorts":
|
case "videos" | "shorts" | "streams":
|
||||||
# videos/shorts have actually the same response schema,
|
# videos/shorts/livestreams have actually the same response schema,
|
||||||
# only the renderers differ - but they are taken care of in ythdd_struct_parser.parseRenderers()
|
# only the renderers differ - but they are taken care of in ythdd_struct_parser.parseRenderers()
|
||||||
|
|
||||||
if ctoken is None:
|
if ctoken is None:
|
||||||
@@ -646,10 +649,12 @@ def get_channel_tab(requested_tab, ucid, req, only_json: bool = False):
|
|||||||
new_continuation = safeTraverse(inner_contents[-1], ["continuationItemRenderer", "continuationEndpoint", "continuationCommand", "token"], default="")
|
new_continuation = safeTraverse(inner_contents[-1], ["continuationItemRenderer", "continuationEndpoint", "continuationCommand", "token"], default="")
|
||||||
|
|
||||||
response = {
|
response = {
|
||||||
"videos": items,
|
"videos": items
|
||||||
"continuation": new_continuation
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if new_continuation:
|
||||||
|
response["continuation"] = new_continuation
|
||||||
|
|
||||||
# cache response
|
# cache response
|
||||||
if ythdd_globals.config['general']['cache']:
|
if ythdd_globals.config['general']['cache']:
|
||||||
ythdd_globals.general_cache["channels"][unique_request_fingerprint] = response
|
ythdd_globals.general_cache["channels"][unique_request_fingerprint] = response
|
||||||
@@ -672,10 +677,12 @@ def get_channel_tab(requested_tab, ucid, req, only_json: bool = False):
|
|||||||
new_continuation = safeTraverse(inner_contents[-1], ["continuationItemRenderer", "continuationEndpoint", "continuationCommand", "token"], default="")
|
new_continuation = safeTraverse(inner_contents[-1], ["continuationItemRenderer", "continuationEndpoint", "continuationCommand", "token"], default="")
|
||||||
|
|
||||||
response = {
|
response = {
|
||||||
"playlists": items,
|
"playlists": items
|
||||||
"continuation": new_continuation
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if new_continuation:
|
||||||
|
response["continuation"] = new_continuation
|
||||||
|
|
||||||
# cache response
|
# cache response
|
||||||
if ythdd_globals.config['general']['cache']:
|
if ythdd_globals.config['general']['cache']:
|
||||||
ythdd_globals.general_cache["channels"][unique_request_fingerprint] = response
|
ythdd_globals.general_cache["channels"][unique_request_fingerprint] = response
|
||||||
@@ -764,8 +771,10 @@ def channels(data, req, only_json: bool = False):
|
|||||||
|
|
||||||
if len(data) > 4:
|
if len(data) > 4:
|
||||||
match data[4]:
|
match data[4]:
|
||||||
case "videos" | "shorts" | "playlists" | "podcasts":
|
case "videos" | "shorts" | "playlists" | "podcasts" | "streams":
|
||||||
return get_channel_tab(data[4], data[3], req)
|
return get_channel_tab( data[4], data[3], req)
|
||||||
|
case "live":
|
||||||
|
return get_channel_tab("streams", data[3], req)
|
||||||
case _:
|
case _:
|
||||||
return send(400, {"error": f"Bad request, unrecognized/unsupported tab \"{data[4]}\"."})
|
return send(400, {"error": f"Bad request, unrecognized/unsupported tab \"{data[4]}\"."})
|
||||||
|
|
||||||
@@ -791,6 +800,9 @@ def channels(data, req, only_json: bool = False):
|
|||||||
# collect tab names
|
# collect tab names
|
||||||
tab_name = safeTraverse(tab, ["tabRenderer", "title"], default="").lower()
|
tab_name = safeTraverse(tab, ["tabRenderer", "title"], default="").lower()
|
||||||
if tab_name:
|
if tab_name:
|
||||||
|
# same as in get_channel_tab
|
||||||
|
if tab_name == "live":
|
||||||
|
tab_name = "streams"
|
||||||
tab_names.append(tab_name)
|
tab_names.append(tab_name)
|
||||||
# and their params (used to retrieve data about them)
|
# and their params (used to retrieve data about them)
|
||||||
ythdd_globals.general_cache["continuations"]["channels"][author_ucid]["tabs"][tab_name] = dict()
|
ythdd_globals.general_cache["continuations"]["channels"][author_ucid]["tabs"][tab_name] = dict()
|
||||||
|
|||||||
Reference in New Issue
Block a user