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;
}