Introduction
Introduction Statistics Contact Development Disclaimer Help
youtube: output improvements - frontends - front-ends for some sites (experimen…
Log
Files
Refs
README
LICENSE
---
commit 4eef4fb9b890ae71f554e996a3a7a542302e68f4
parent 11f745425e13385e5a69cf3f8cdceaa3027dad64
Author: Hiltjo Posthuma <[email protected]>
Date: Fri, 24 Feb 2023 22:39:39 +0100
youtube: output improvements
- pre-parse numbers to long long.
- show duration as a string %H:%M:%S.
- show filesize in bytes and MB.
- etc...
Diffstat:
M util.c | 17 +++++++++++++++++
M util.h | 1 +
M youtube/cli.c | 110 +++++++++++++++++------------…
M youtube/youtube.c | 41 ++++++++++++++++++++---------…
M youtube/youtube.h | 31 ++++++++++++++++-------------…
5 files changed, 122 insertions(+), 78 deletions(-)
---
diff --git a/util.c b/util.c
@@ -204,3 +204,20 @@ gophertext(FILE *fp, const char *s, size_t len)
}
}
}
+
+/* seconds to duration string: "%H:%M:%S" or "%H:%M:%S" */
+int
+durationstr(long secs, char *buf, size_t bufsiz)
+{
+ int h, m, s, r;
+
+ h = secs / 3600;
+ m = secs / 60;
+ s = secs;
+ if (h <= 0)
+ r = snprintf(buf, bufsiz, "%02d:%02d", m % 60, s % 60);
+ else
+ r = snprintf(buf, bufsiz, "%d:%02d:%02d", h, m % 60, s % 60);
+
+ return r;
+}
diff --git a/util.h b/util.h
@@ -9,6 +9,7 @@ size_t strlcat(char *, const char *, size_t);
size_t strlcpy(char *, const char *, size_t);
int decodeparam(char *buf, size_t bufsiz, const char *s);
+int durationstr(long secs, char *buf, size_t bufsiz);
int friendlytime(time_t now, time_t t);
char *getparam(const char *query, const char *s);
void gophertext(FILE *fp, const char *s, size_t len);
diff --git a/youtube/cli.c b/youtube/cli.c
@@ -157,12 +157,11 @@ int
render_video(struct video_response *r)
{
struct video_format *f;
- long l;
+ char buf[256];
int i;
OUT("URL: ");
- OUTESCAPE(r->id);
- OUT(", https://www.youtube.com/embed/");
+ OUT("https://www.youtube.com/embed/");
OUTESCAPE(r->id);
OUT("\n");
@@ -170,21 +169,28 @@ render_video(struct video_response *r)
OUTESCAPE(r->title);
OUT("\n");
- OUT("Views: ");
- OUTESCAPE(r->viewcount);
- OUT("\n");
+ if (r->lengthseconds > 0) {
+ OUT("Length: ");
+ if (durationstr(r->lengthseconds, buf, sizeof(buf)) < sizeof(b…
+ OUTESCAPE(buf);
+ OUT("\n");
+ }
- OUT("Length: ");
- OUTESCAPE(r->lengthseconds);
+ OUT("Views: ");
+ printf("%ld", r->viewcount);
OUT("\n");
- OUT("Published: ");
- OUTESCAPE(r->publishdate);
- OUT("\n");
+ if (r->publishdate[0]) {
+ OUT("Published: ");
+ OUTESCAPE(r->publishdate);
+ OUT("\n");
+ }
- OUT("Uploaded: ");
- OUTESCAPE(r->uploaddate);
- OUT("\n");
+ if (r->uploaddate[0]) {
+ OUT("Uploaded: ");
+ OUTESCAPE(r->uploaddate);
+ OUT("\n");
+ }
if (r->author[0]) {
OUT("Channel: ");
@@ -208,9 +214,9 @@ render_video(struct video_response *r)
OUT("\n\nFormats:\n\n");
/* links expiration */
- if (r->expiresinseconds[0]) {
+ if (r->expiresinseconds > 0) {
OUT("Expires in ");
- OUTESCAPE(r->expiresinseconds);
+ printf("%ld", r->expiresinseconds);
OUT(" seconds\n");
}
@@ -218,68 +224,76 @@ render_video(struct video_response *r)
f = &(r->formats[i]);
#if 0
- l = strtol(f->width, NULL, 10);
- if (l < 1280)
- continue;
- l = strtol(f->height, NULL, 10);
- if (l < 720)
+ if (f->width < 1280 || f->height < 720)
continue;
#endif
#if 0
- OUT("\titag: ");
+ OUT("itag: ");
OUTESCAPE(f->itag);
OUT("\n");
- OUT("\tLast modified: ");
+ OUT("Last modified: ");
OUTESCAPE(f->lastmodified);
OUT("\n");
- OUT("\tContent-Length: ");
- OUTESCAPE(f->contentlength);
- OUT("\n");
+
#endif
- OUT("\tURL: ");
+ OUT("URL: ");
OUTESCAPE(f->url);
OUT("\n");
- OUT("\tMime-type: ");
- OUTESCAPE(f->mimetype);
- OUT("\n");
-
- OUT("\tBitrate: ");
- OUTESCAPE(f->bitrate);
- OUT("\n");
+ if (f->mimetype[0]) {
+ OUT("Mime-type: ");
+ OUTESCAPE(f->mimetype);
+ OUT("\n");
+ }
- OUT("\tQuality: ");
- if (f->qualitylabel[0])
+ if (f->qualitylabel[0]) {
+ OUT("Quality: ");
OUTESCAPE(f->qualitylabel);
- else if (f->quality[0])
+ } else if (f->quality[0]) {
+ OUT("Quality: ");
OUTESCAPE(f->quality);
+ }
- if (f->width[0]) {
+ if (f->width > 0) {
OUT(", ");
- OUTESCAPE(f->width);
+ printf("%ld", f->width);
OUT("x");
- OUTESCAPE(f->height);
+ printf("%ld", f->height);
OUT("");
}
- if (f->fps[0]) {
+ if (f->fps > 0) {
OUT(", ");
- OUTESCAPE(f->fps);
+ printf("%ld", f->fps);
OUT(" FPS");
}
OUT("\n");
- if (f->audiochannels[0]) {
- OUT("\tAudio channels: ");
- OUTESCAPE(f->audiochannels);
+ if (f->bitrate > 0) {
+ OUT("Bitrate: ");
+ printf("%ld", f->bitrate);
+ if (f->averagebitrate > 0)
+ printf(", average: %ld", f->averagebitrate);
OUT("\n");
}
- if (f->audiosamplerate[0]) {
- OUT("\tAudio sample rate: ");
- OUTESCAPE(f->audiosamplerate);
+
+ if (f->contentlength > 0) {
+ OUT("Size: ");
+ printf("%lld bytes (%.2f MB)\n", f->contentlength, f->…
+ }
+
+ if (f->audiochannels > 0 || f->audiosamplerate) {
+ OUT("Audio: ");
+ if (f->audiochannels > 0)
+ printf("%ld channels", f->audiochannels);
+ if (f->audiosamplerate > 0) {
+ if (f->audiochannels > 0)
+ OUT(", ");
+ printf("%ld sample rate", f->audiosamplerate);
+ }
OUT("\n");
}
diff --git a/youtube/youtube.c b/youtube/youtube.c
@@ -15,6 +15,17 @@
#include "util.h"
#include "youtube.h"
+static long long
+getnum(const char *s)
+{
+ long long l;
+
+ l = strtoll(s, 0, 10);
+ if (l < 0)
+ l = 0;
+ return l;
+}
+
static char *
youtube_request(const char *path)
{
@@ -286,7 +297,6 @@ processnode_video(struct json_node *nodes, size_t depth, co…
{
struct video_response *r = (struct video_response *)pp;
struct video_format *f;
- static struct item *item;
if (depth > 1) {
if (nodes[0].type == JSON_TYPE_OBJECT &&
@@ -296,7 +306,7 @@ processnode_video(struct json_node *nodes, size_t depth, co…
if (depth == 2 &&
nodes[2].type == JSON_TYPE_STRING &&
!strcmp(nodes[2].name, "expiresInSeconds")) {
- strlcpy(r->expiresinseconds, value, sizeof(r->…
+ r->expiresinseconds = getnum(value);
}
if (depth >= 3 &&
@@ -306,9 +316,8 @@ processnode_video(struct json_node *nodes, size_t depth, co…
if (r->nformats > MAX_FORMATS)
return; /* ignore: don't add too many …
- if (depth == 4 && nodes[3].type == JSON_TYPE_O…
+ if (depth == 4 && nodes[3].type == JSON_TYPE_O…
r->nformats++;
- }
if (r->nformats == 0)
return;
@@ -321,9 +330,9 @@ processnode_video(struct json_node *nodes, size_t depth, co…
nodes[4].type == JSON_TYPE_NUMBER ||
nodes[4].type == JSON_TYPE_BOOL)) {
if (!strcmp(nodes[4].name, "width")) {
- strlcpy(f->width, value, sizeo…
+ f->width = getnum(value);
} else if (!strcmp(nodes[4].name, "hei…
- strlcpy(f->height, value, size…
+ f->height = getnum(value);
} else if (!strcmp(nodes[4].name, "url…
strlcpy(f->url, value, sizeof(…
} else if (!strcmp(nodes[4].name, "qua…
@@ -331,21 +340,23 @@ processnode_video(struct json_node *nodes, size_t depth, …
} else if (!strcmp(nodes[4].name, "qua…
strlcpy(f->quality, value, siz…
} else if (!strcmp(nodes[4].name, "fps…
- strlcpy(f->fps, value, sizeof(…
+ f->fps = getnum(value);
} else if (!strcmp(nodes[4].name, "bit…
- strlcpy(f->bitrate, value, siz…
+ f->bitrate = getnum(value);
+ } else if (!strcmp(nodes[4].name, "ave…
+ f->averagebitrate = getnum(val…
} else if (!strcmp(nodes[4].name, "mim…
strlcpy(f->mimetype, value, si…
} else if (!strcmp(nodes[4].name, "ita…
- strlcpy(f->itag, value, sizeof…
+ f->itag = getnum(value);
} else if (!strcmp(nodes[4].name, "con…
- strlcpy(f->contentlength, valu…
+ f->contentlength = getnum(valu…
} else if (!strcmp(nodes[4].name, "las…
- strlcpy(f->lastmodified, value…
+ f->lastmodified = getnum(value…
} else if (!strcmp(nodes[4].name, "aud…
- strlcpy(f->audiochannels, valu…
+ f->audiochannels = getnum(valu…
} else if (!strcmp(nodes[4].name, "aud…
- strlcpy(f->audiosamplerate, va…
+ f->audiosamplerate = getnum(va…
}
}
}
@@ -375,11 +386,11 @@ processnode_video(struct json_node *nodes, size_t depth, …
} else if (!strcmp(nodes[2].name, "videoId")) {
strlcpy(r->id, value, sizeof(r->id));
} else if (!strcmp(nodes[2].name, "lengthSeconds")) {
- strlcpy(r->lengthseconds, value, sizeof(r->len…
+ r->lengthseconds = getnum(value);
} else if (!strcmp(nodes[2].name, "author")) {
strlcpy(r->author, value, sizeof(r->author));
} else if (!strcmp(nodes[2].name, "viewCount")) {
- strlcpy(r->viewcount, value, sizeof(r->viewcou…
+ r->viewcount = getnum(value);
} else if (!strcmp(nodes[2].name, "channelId")) {
strlcpy(r->channelid, value, sizeof(r->channel…
} else if (!strcmp(nodes[2].name, "shortDescription"))…
diff --git a/youtube/youtube.h b/youtube/youtube.h
@@ -5,9 +5,9 @@ struct item {
char channeltitle[1024];
char channelid[256];
char userid[256];
- char publishedat[32];
- char viewcount[32];
- char duration[32];
+ char publishedat[32]; /* "human-friendly" string */
+ char viewcount[32]; /* view count string, formatted */
+ char duration[32]; /* duration string */
#ifdef neinneinnein
char shortdescription[4096];
@@ -21,19 +21,20 @@ struct search_response {
};
struct video_format {
- char itag[32]; /* video id */
+ long itag;
char url[2048];
char mimetype[256]; /* mime-type and video codecs, etc */
- char bitrate[256];
- char width[32]; /* pixel width */
- char height[32]; /* pixel width */
- char fps[16]; /* frames-per-second */
+ long bitrate;
+ long averagebitrate;
+ long width; /* pixel width */
+ long height; /* pixel width */
+ long fps; /* frames-per-second */
char qualitylabel[64];
char quality[64];
- char contentlength[64]; /* content length in bytes */
- char lastmodified[64];
- char audiosamplerate[32];
- char audiochannels[16];
+ long long contentlength; /* content length in bytes */
+ long lastmodified; /* timestamp */
+ long audiosamplerate;
+ long audiochannels;
};
#define MAX_FORMATS 50
@@ -44,14 +45,14 @@ struct video_response {
char channelid[256];
char publishdate[32]; /* YYYY-mm-dd */
char uploaddate[32]; /* YYYY-mm-dd */
- char viewcount[32];
- char lengthseconds[32];
+ long viewcount;
+ long lengthseconds;
char shortdescription[4096 * 4];
int isfound;
/* expiration for URLs in video formats */
- char expiresinseconds[32];
+ long expiresinseconds;
struct video_format formats[MAX_FORMATS + 1];
int nformats;
};
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.