youtube/cgi: add page with basic video information - frontends - front-ends for some sites (experiment) (DIR) Log (DIR) Files (DIR) Refs (DIR) README (DIR) LICENSE --- (DIR) commit 2237f8c69f34d8f48a37e34d1462d327b9ddc40d (DIR) parent d8464a0a1169fc7b1ff0cea3a907b879a7230b47 (HTM) Author: Hiltjo Posthuma <hiltjo@codemadness.org> Date: Sat, 25 Feb 2023 20:14:18 +0100 youtube/cgi: add page with basic video information Diffstat: M youtube/cgi.c | 161 +++++++++++++++++++++++++++---- 1 file changed, 140 insertions(+), 21 deletions(-) --- (DIR) diff --git a/youtube/cgi.c b/youtube/cgi.c @@ -21,7 +21,9 @@ extern char **environ; static int curpage = 1; /* CGI parameters */ -static char rawsearch[4096], search[4096], order[16], page[64], channelid[256], userid[256]; +static char rawsearch[4096], search[4096], order[16], page[64]; +static char videoid[256]; +static char channelid[256], userid[256]; void parsecgi(void) @@ -81,28 +83,32 @@ parsecgi(void) if (decodeparam(userid, sizeof(userid), p) == -1) userid[0] = '\0'; } -} -int -render(struct search_response *r) -{ - struct item *v; - char tmp[64]; - size_t i; - - if (pledge("stdio", NULL) == -1) { - OUT("Status: 500 Internal Server Error\r\n\r\n"); - exit(1); + /* video ID */ + if ((p = getparam(query, "v"))) { + if (decodeparam(videoid, sizeof(videoid), p) == -1) + videoid[0] = '\0'; } +} +void +header(void) +{ OUT( "Content-Type: text/html; charset=utf-8\r\n\r\n" "<!DOCTYPE html>\n<html>\n<head>\n" "<meta name=\"referrer\" content=\"no-referrer\" />\n" - "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />\n" - "<title>Search: \""); + "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />\n"); + + if (videoid[0]) { + OUT("<title>Video: "); + xmlencode(videoid); + OUT("</title>"); + } else { + OUT("<title>Search: \""); xmlencode(search); printf("\" sorted by %s</title>\n", order); + } OUT( "<link rel=\"stylesheet\" href=\"css/style.css\" type=\"text/css\" media=\"screen\" />\n" "<link rel=\"icon\" type=\"image/png\" href=\"/favicon.png\" />\n" @@ -133,6 +139,27 @@ render(struct search_response *r) "</tr>\n" "</table>\n" "</form>\n"); +} + +void +footer(void) +{ + OUT("</body>\n</html>\n"); +} + +int +render_search(struct search_response *r) +{ + struct item *v; + char tmp[64]; + size_t i; + + if (pledge("stdio", NULL) == -1) { + OUT("Status: 500 Internal Server Error\r\n\r\n"); + exit(1); + } + + header(); if (r && r->nitems) { OUT( @@ -163,7 +190,13 @@ render(struct search_response *r) if (v->id[0]) { OUT("<a href=\"https://www.youtube.com/embed/"); xmlencode(v->id); - printf("\" accesskey=\"%zu\">", i); + printf("\" accesskey=\"%zu\"", i); +/* if (v->shortdescription[0]) { + OUT(" title=\""); + xmlencode(v->shortdescription); + OUT("\""); + }*/ + OUT(">"); } switch (v->linktype) { @@ -187,6 +220,13 @@ render(struct search_response *r) if (v->id[0]) OUT("</a>"); + /* link to video information */ + if (v->id[0]) { + OUT(" <a href=\"?v="); + xmlencode(v->id); + OUT("\">[I]</a>"); + } + OUT( "</span><br/>\n" "\t\t<span class=\"channel\">"); @@ -277,7 +317,76 @@ render(struct search_response *r) "</table>\n"); } - OUT("</body>\n</html>\n"); + footer(); + + return 0; +} + +int +render_video(struct video_response *r) +{ + char buf[256]; + + if (pledge("stdio", NULL) == -1) { + OUT("Status: 500 Internal Server Error\r\n\r\n"); + exit(1); + } + + header(); + + OUT("<pre>"); + + OUT("URL: "); + OUT("https://www.youtube.com/embed/"); + xmlencode(r->id); + OUT("\n"); + + OUT("Title: "); + xmlencode(r->title); + OUT("\n"); + + if (r->lengthseconds > 0) { + OUT("Length: "); + if (durationstr(r->lengthseconds, buf, sizeof(buf)) < sizeof(buf)) + xmlencode(buf); + OUT("\n"); + } + + OUT("Views: "); + printf("%ld", r->viewcount); + OUT("\n"); + + if (r->publishdate[0]) { + OUT("Published: "); + xmlencode(r->publishdate); + OUT("\n"); + } + + if (r->uploaddate[0]) { + OUT("Uploaded: "); + xmlencode(r->uploaddate); + OUT("\n"); + } + + if (r->author[0]) { + OUT("Channel: "); + xmlencode(r->author); + if (r->channelid[0]) { + OUT(": https://www.youtube.com/feeds/videos.xml?channel_id="); + xmlencode(r->channelid); + } + OUT("\n"); + } + + if (r->shortdescription[0]) { + OUT("Description:\n\n"); + xmlencode(r->shortdescription); + OUT("\n"); + } + + OUT("</pre>"); + + footer(); return 0; } @@ -286,6 +395,7 @@ int main(void) { struct search_response *r = NULL; + struct video_response *vr = NULL; if (pledge("stdio dns inet rpath unveil", NULL) == -1 || unveil(TLS_CA_CERT_FILE, "r") == -1 || @@ -296,21 +406,30 @@ main(void) parsecgi(); - if (rawsearch[0]) + if (rawsearch[0]) { r = youtube_search(rawsearch, page, order); - else if (channelid[0]) + } else if (channelid[0]) { r = youtube_channel_videos(channelid); - else if (userid[0]) + } else if (userid[0]) { r = youtube_user_videos(userid); - else + } else if (videoid[0]) { + vr = youtube_video(videoid); + if (!vr || vr->isfound == 0) { + OUT("Status: 500 Internal Server Error\r\n\r\n"); + exit(1); + } + render_video(vr); + return 0; + } else { goto show; + } if (!r || r->nitems == 0) { OUT("Status: 500 Internal Server Error\r\n\r\n"); exit(1); } show: - render(r); + render_search(r); return 0; }