youtube/feed: add simple HTML and gopher output format - frontends - front-ends for some sites (experiment)
(DIR) Log
(DIR) Files
(DIR) Refs
(DIR) README
(DIR) LICENSE
---
(DIR) commit d22d896072715e337381959c0cca366b45810cb0
(DIR) parent 4715c8cfb1799ef4dfe14dea87efc8e4d7c3a60e
(HTM) Author: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Thu, 18 May 2023 15:28:32 +0200
youtube/feed: add simple HTML and gopher output format
Diffstat:
M youtube/feed.c | 136 ++++++++++++++++++++++++++++++-
M youtube/gopher.c | 2 +-
2 files changed, 136 insertions(+), 2 deletions(-)
---
(DIR) diff --git a/youtube/feed.c b/youtube/feed.c
@@ -86,6 +86,10 @@ static int parsetime(const char *, long long *);
static void atom_header(void);
static void atom_item(void);
static void atom_footer(void);
+static void gph_header(void);
+static void gph_footer(void);
+static void html_header(void);
+static void html_footer(void);
static void json_header(void);
static void json_item(void);
static void json_footer(void);
@@ -498,6 +502,122 @@ atom_item(void)
fputs("</entry>\n", stdout);
}
+
+static void
+html_header(void)
+{
+ fputs("<!DOCTYPE HTML>\n"
+ "<html>\n"
+ "<head>\n"
+ "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />\n"
+ "</head>\n"
+ "<body><pre>\n", stdout);
+}
+
+static void
+html_footer(void)
+{
+ fputs("</pre></body>\n</html>\n", stdout);
+}
+
+static void
+html_item(void)
+{
+ struct item *v, *found = NULL;
+ size_t i;
+
+ /* must have a video id */
+ if (!ctx.fields[FeedFieldYoutubeId].str.len)
+ return;
+
+ for (i = 0; i < search_res->nitems; i++) {
+ v = &(search_res->items[i]);
+ if (!strcmp(ctx.fields[FeedFieldYoutubeId].str.data, v->id))
+ found = v;
+ }
+ /* Only print the video if it was found in the feed aswell.
+ This way it filters away shorts too. */
+ if (!found)
+ return;
+
+ /* just print the original timestamp, it should conform */
+ xmlencode(ctx.fields[FeedFieldTime].str.data);
+ fputs(" ", stdout);
+
+ if (ctx.fields[FeedFieldLink].str.len) {
+ fputs("<a href=\"", stdout);
+ xmlencode(ctx.fields[FeedFieldLink].str.data);
+ fputs("\">", stdout);
+ }
+
+ xmlencode(ctx.fields[FeedFieldTitle].str.data);
+
+ if (found->duration[0]) {
+ fputs(" [", stdout);
+ xmlencode(found->duration);
+ fputs("]", stdout);
+ }
+ if (ctx.fields[FeedFieldLink].str.len) {
+ fputs("</a>", stdout);
+ }
+ fputs("\n", stdout);
+}
+
+static void
+gphencode(const char *s)
+{
+ gophertext(stdout, s, strlen(s));
+}
+
+static void
+gph_header(void)
+{
+}
+
+static void
+gph_footer(void)
+{
+ fputs(".\r\n", stdout);
+}
+
+static void
+gph_item(void)
+{
+ struct item *v, *found = NULL;
+ size_t i;
+
+ /* must have a video id */
+ if (!ctx.fields[FeedFieldYoutubeId].str.len)
+ return;
+
+ for (i = 0; i < search_res->nitems; i++) {
+ v = &(search_res->items[i]);
+ if (!strcmp(ctx.fields[FeedFieldYoutubeId].str.data, v->id))
+ found = v;
+ }
+ /* Only print the video if it was found in the feed aswell.
+ This way it filters away shorts too. */
+ if (!found)
+ return;
+
+ fputs("h", stdout);
+ /* just print the original timestamp, it should conform */
+ gphencode(ctx.fields[FeedFieldTime].str.data);
+ fputs(" ", stdout);
+ gphencode(ctx.fields[FeedFieldTitle].str.data);
+ if (found->duration[0]) {
+ fputs(" [", stdout);
+ gphencode(found->duration);
+ fputs("]", stdout);
+ }
+ fputs("\t", stdout);
+ if (ctx.fields[FeedFieldLink].str.len) {
+ fputs("URL:", stdout);
+ gphencode(ctx.fields[FeedFieldLink].str.data);
+ }
+ printf("\t%s\t%s\r\n", server_name, server_port);
+}
+
static void
json_header(void)
{
@@ -931,10 +1051,12 @@ usage(void)
fputs("Status: 400 Bad Request\r\n", stdout);
fputs("Content-Type: text/plain; charset=utf-8\r\n\r\n", stdout);
printf("400 %s\n", msg);
+ fputs("Supported extensions are: [atom|gph|html|json|tsv|txt]\n", stdout);
}
exit(0);
} else {
- fputs("usage: feed <channelid> [atom|json|tsv|txt]\n", stderr);
+ fputs("usage: feed <channelid> [atom|gph|html|json|tsv|txt]\n", stderr);
+ fputs("For example: feed UCrbvoMC0zUvPL8vjswhLOSw txt\n", stderr);
exit(1);
}
}
@@ -987,6 +1109,10 @@ main(int argc, char *argv[])
if (!strcmp(format, "atom") || !strcmp(format, "xml"))
printfields = atom_item;
+ else if (!strcmp(format, "gph"))
+ printfields = gph_item;
+ else if (!strcmp(format, "html"))
+ printfields = html_item;
else if (!strcmp(format, "json"))
printfields = json_item;
else if (!strcmp(format, "tsv") || !strcmp(format, "sfeed"))
@@ -1040,6 +1166,10 @@ main(int argc, char *argv[])
if (!strcmp(format, "atom") || !strcmp(format, "xml"))
atom_header();
+ else if (!strcmp(format, "gph"))
+ gph_header();
+ else if (!strcmp(format, "html"))
+ html_header();
else if (!strcmp(format, "json"))
json_header();
@@ -1048,6 +1178,10 @@ main(int argc, char *argv[])
if (!strcmp(format, "atom") || !strcmp(format, "xml"))
atom_footer();
+ else if (!strcmp(format, "gph"))
+ gph_footer();
+ else if (!strcmp(format, "html"))
+ html_footer();
else if (!strcmp(format, "json"))
json_footer();
(DIR) diff --git a/youtube/gopher.c b/youtube/gopher.c
@@ -50,7 +50,7 @@ header(void)
void
footer(void)
{
- printf(".\r\n");
+ fputs(".\r\n", stdout);
}
int