Introduction
Introduction Statistics Contact Development Disclaimer Help
youtube: workaround, don't list topic/playlist items as channels - frontends - …
Log
Files
Refs
README
LICENSE
---
commit b608dae128234bedd5ed09fe89c22c0dd5ef0b28
parent 6242ec658d5610990c6b19944473fa7277493ac1
Author: Hiltjo Posthuma <[email protected]>
Date: Sun, 1 Jun 2025 13:37:34 +0200
youtube: workaround, don't list topic/playlist items as channels
Listing channel videos based on this topic or playlist would serve different
JSON which we don't handle, so it would serve an empty page.
For now just reset the channelid if the channeltitle ends with " - Topic".
Separate the function for checking the renderer name. This might make it easier
to adapt to support playlists in the future. The JSON output for
playlists/topics has a "shelfRenderer".
Diffstat:
M youtube/youtube.c | 40 +++++++++++++++++++++++++----…
1 file changed, 32 insertions(+), 8 deletions(-)
---
diff --git a/youtube/youtube.c b/youtube/youtube.c
@@ -145,6 +145,12 @@ extractjson_video(const char *s, const char **start, const…
return 0;
}
+static int
+isrenderername(const char *name)
+{
+ return !strcmp(name, "videoRenderer");
+}
+
static void
processnode_search(struct json_node *nodes, size_t depth, const char *value, s…
void *pp)
@@ -159,7 +165,7 @@ processnode_search(struct json_node *nodes, size_t depth, c…
(items|contents)[].videoRenderer objects */
if (depth >= 3 &&
nodes[depth - 1].type == JSON_TYPE_OBJECT &&
- !strcmp(nodes[depth - 1].name, "videoRenderer")) {
+ isrenderername(nodes[depth - 1].name)) {
r->nitems++;
return;
}
@@ -170,7 +176,7 @@ processnode_search(struct json_node *nodes, size_t depth, c…
if (depth >= 4 &&
nodes[depth - 1].type == JSON_TYPE_STRING &&
- !strcmp(nodes[depth - 2].name, "videoRenderer") &&
+ isrenderername(nodes[depth - 2].name) &&
!strcmp(nodes[depth - 1].name, "videoId")) {
strlcpy(item->id, value, sizeof(item->id));
}
@@ -181,7 +187,7 @@ processnode_search(struct json_node *nodes, size_t depth, c…
nodes[depth - 3].type == JSON_TYPE_ARRAY &&
nodes[depth - 2].type == JSON_TYPE_OBJECT &&
nodes[depth - 1].type == JSON_TYPE_STRING &&
- !strcmp(nodes[depth - 5].name, "videoRenderer") &&
+ isrenderername(nodes[depth - 5].name) &&
!strcmp(nodes[depth - 4].name, "title") &&
!strcmp(nodes[depth - 3].name, "runs") &&
!strcmp(nodes[depth - 1].name, "text") &&
@@ -198,7 +204,7 @@ processnode_search(struct json_node *nodes, size_t depth, c…
nodes[depth - 3].type == JSON_TYPE_ARRAY &&
nodes[depth - 2].type == JSON_TYPE_OBJECT &&
nodes[depth - 1].type == JSON_TYPE_STRING &&
- !strcmp(nodes[depth - 7].name, "videoRenderer") &&
+ isrenderername(nodes[depth - 7].name) &&
!strcmp(nodes[depth - 6].name, "detailedMetadataSnippets") &&
!strcmp(nodes[depth - 4].name, "snippetText") &&
!strcmp(nodes[depth - 3].name, "runs") &&
@@ -213,7 +219,7 @@ processnode_search(struct json_node *nodes, size_t depth, c…
nodes[depth - 3].type == JSON_TYPE_ARRAY &&
nodes[depth - 2].type == JSON_TYPE_OBJECT &&
nodes[depth - 1].type == JSON_TYPE_STRING &&
- !strcmp(nodes[depth - 5].name, "videoRenderer") &&
+ isrenderername(nodes[depth - 5].name) &&
!strcmp(nodes[depth - 4].name, "descriptionSnippet") &&
!strcmp(nodes[depth - 3].name, "runs") &&
!strcmp(nodes[depth - 1].name, "text")) {
@@ -225,7 +231,7 @@ processnode_search(struct json_node *nodes, size_t depth, c…
nodes[depth - 3].type == JSON_TYPE_OBJECT &&
nodes[depth - 2].type == JSON_TYPE_OBJECT &&
nodes[depth - 1].type == JSON_TYPE_STRING &&
- !strcmp(nodes[depth - 3].name, "videoRenderer") &&
+ isrenderername(nodes[depth - 3].name) &&
!strcmp(nodes[depth - 1].name, "simpleText")) {
if (!strcmp(nodes[depth - 2].name, "viewCountText") &&
!item->viewcount[0]) {
@@ -248,7 +254,7 @@ processnode_search(struct json_node *nodes, size_t depth, c…
nodes[depth - 3].type == JSON_TYPE_OBJECT &&
nodes[depth - 2].type == JSON_TYPE_OBJECT &&
nodes[depth - 1].type == JSON_TYPE_STRING &&
- !strcmp(nodes[depth - 7].name, "videoRenderer") &&
+ isrenderername(nodes[depth - 7].name) &&
!strcmp(nodes[depth - 6].name, "longBylineText") &&
!strcmp(nodes[depth - 5].name, "runs") &&
!strcmp(nodes[depth - 3].name, "navigationEndpoint") &&
@@ -265,7 +271,7 @@ processnode_search(struct json_node *nodes, size_t depth, c…
nodes[depth - 3].type == JSON_TYPE_ARRAY &&
nodes[depth - 2].type == JSON_TYPE_OBJECT &&
nodes[depth - 1].type == JSON_TYPE_STRING &&
- !strcmp(nodes[depth - 5].name, "videoRenderer") &&
+ isrenderername(nodes[depth - 5].name) &&
!strcmp(nodes[depth - 4].name, "longBylineText") &&
!strcmp(nodes[depth - 3].name, "runs")) {
if (!strcmp(nodes[depth - 1].name, "text") &&
@@ -279,7 +285,9 @@ static struct search_response *
parse_search_response(const char *data)
{
struct search_response *r;
+ struct item *item;
const char *s, *start, *end;
+ size_t i, len;
int ret;
if (!(s = strstr(data, "\r\n\r\n")))
@@ -300,6 +308,22 @@ parse_search_response(const char *data)
free(r);
return NULL;
}
+
+ /* workaround: sometimes playlists or topics are listed as channels, f…
+ these topic/playlist links away because they won't work for channel…
+ JSON response would have to be parsed in a different way than chann…
+ for (i = 0; i < r->nitems; i++) {
+ item = &(r->items[i]);
+ len = strlen(item->channeltitle);
+
+ if (len > sizeof(" - Topic") &&
+ !strcmp(item->channeltitle + len - sizeof(" - Topic") + 1,…
+ /* reset information that doesn't work for topics */
+ item->channelid[0] = '\0';
+ item->viewcount[0] = '\0';
+ }
+ }
+
return r;
}
You are viewing proxied material from codemadness.org. The copyright of proxied material belongs to its original authors. Any comments or complaints in relation to proxied material should be directed to the original authors of the content concerned. Please see the disclaimer for more details.