youtube: some cleanups, add option to list user videos - frontends - front-ends for some sites (experiment)
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit b407559e2ea372a5d16bd0b08c9088762fa9ce75
 (DIR) parent 1752940aca51413222b22939b7c6ce5947960967
 (HTM) Author: Hiltjo Posthuma <hiltjo@codemadness.org>
       Date:   Tue, 21 Feb 2023 20:31:42 +0100
       
       youtube: some cleanups, add option to list user videos
       
       Diffstat:
         M json.c                              |       2 +-
         M xml.c                               |       2 +-
         M youtube/cli.c                       |       6 +++++-
         M youtube/youtube.c                   |      69 ++++++++++++++++++-------------
         M youtube/youtube.h                   |       3 +++
       
       5 files changed, 50 insertions(+), 32 deletions(-)
       ---
 (DIR) diff --git a/json.c b/json.c
       @@ -28,7 +28,7 @@ setjsondata(const char *s, size_t len)
        {
                json_data_off = 0;
                json_data_size = len;
       -        json_data = s;
       +        json_data = (unsigned char *)s;
        }
        
        static int
 (DIR) diff --git a/xml.c b/xml.c
       @@ -18,7 +18,7 @@ setxmldata(const char *s, size_t len)
        {
                xml_data_off = 0;
                xml_data_size = len;
       -        xml_data_buf = s;
       +        xml_data_buf = (unsigned char *)s;
        }
        
        static int
 (DIR) diff --git a/youtube/cli.c b/youtube/cli.c
       @@ -114,7 +114,7 @@ render(struct search_response *r)
        static void
        usage(const char *argv0)
        {
       -        fprintf(stderr, "usage: %s <keyword> | <-c channelid>\n", argv0);
       +        fprintf(stderr, "usage: %s <keyword> | <-c channelid> | <-u user>\n", argv0);
                exit(1);
        }
        
       @@ -143,6 +143,10 @@ main(int argc, char *argv[])
                        if (argc < 3)
                                usage(argv[0]);
                        r = youtube_channel_videos(argv[2]);
       +        } else if (!strcmp(argv[1], "-u")) {
       +                if (argc < 3)
       +                        usage(argv[0]);
       +                r = youtube_user_videos(argv[2]);
                } else {
                        if (!uriencode(argv[1], search, sizeof(search)))
                                usage(argv[0]);
 (DIR) diff --git a/youtube/youtube.c b/youtube/youtube.c
       @@ -36,6 +36,20 @@ request_channel_videos(const char *channelid)
        }
        
        static char *
       +request_user_videos(const char *user)
       +{
       +        char path[4096];
       +        int r;
       +
       +        r = snprintf(path, sizeof(path), "/user/%s/videos", user);
       +        /* check if request is too long (truncation) */
       +        if (r < 0 || (size_t)r >= sizeof(path))
       +                return NULL;
       +
       +        return youtube_request(path);
       +}
       +
       +static char *
        request_search(const char *s, const char *page, const char *order)
        {
                char path[4096];
       @@ -66,8 +80,8 @@ request_search(const char *s, const char *page, const char *order)
                return youtube_request(path);
        }
        
       -int
       -extractjson(const char *s, char **start, char **end)
       +static int
       +extractjson(const char *s, const char **start, const char **end)
        {
                *start = strstr(s, "window[\"ytInitialData\"] = ");
                if (*start) {
       @@ -91,7 +105,7 @@ extractjson(const char *s, char **start, char **end)
                return 0;
        }
        
       -void
       +static void
        processnode(struct json_node *nodes, size_t depth, const char *value,
                void *pp)
        {
       @@ -191,16 +205,13 @@ processnode(struct json_node *nodes, size_t depth, const char *value,
                }
        }
        
       -struct search_response *
       -youtube_search(const char *rawsearch, const char *page, const char *order)
       +static struct search_response *
       +parse_search_response(const char *data)
        {
                struct search_response *r;
       -        char *data, *s, *start, *end;
       +        const char *s, *start, *end;
                int ret;
        
       -        if (!(data = request_search(rawsearch, page, order)))
       -                return NULL;
       -
                if (!(s = strstr(data, "\r\n\r\n")))
                        return NULL; /* invalid response */
                /* skip header */
       @@ -219,38 +230,38 @@ youtube_search(const char *rawsearch, const char *page, const char *order)
                        free(r);
                        return NULL;
                }
       -
                return r;
        }
        
        struct search_response *
       -youtube_channel_videos(const char *channelid)
       +youtube_search(const char *rawsearch, const char *page, const char *order)
        {
       -        struct search_response *r;
       -        char *data, *s, *start, *end;
       -        int ret;
       +        const char *data;
        
       -        if (!(data = request_channel_videos(channelid)))
       +        if (!(data = request_search(rawsearch, page, order)))
                        return NULL;
        
       -        if (!(s = strstr(data, "\r\n\r\n")))
       -                return NULL; /* invalid response */
       -        /* skip header */
       -        s += strlen("\r\n\r\n");
       +        return parse_search_response(data);
       +}
        
       -        if (!(r = calloc(1, sizeof(*r))))
       -                return NULL;
       +struct search_response *
       +youtube_channel_videos(const char *channelid)
       +{
       +        const char *data;
        
       -        if (extractjson(s, &start, &end) == -1) {
       -                free(r);
       +        if (!(data = request_channel_videos(channelid)))
                        return NULL;
       -        }
        
       -        ret = parsejson(start, end - start, processnode, r);
       -        if (ret < 0) {
       -                free(r);
       +        return parse_search_response(data);
       +}
       +
       +struct search_response *
       +youtube_user_videos(const char *user)
       +{
       +        const char *data;
       +
       +        if (!(data = request_user_videos(user)))
                        return NULL;
       -        }
        
       -        return r;
       +        return parse_search_response(data);
        }
 (DIR) diff --git a/youtube/youtube.h b/youtube/youtube.h
       @@ -22,3 +22,6 @@ youtube_search(const char *rawsearch, const char *page, const char *order);
        
        struct search_response *
        youtube_channel_videos(const char *channelid);
       +
       +struct search_response *
       +youtube_user_videos(const char *user);