Introduction
Introduction Statistics Contact Development Disclaimer Help
cli.c - frontends - front-ends for some sites (experiment)
Log
Files
Refs
README
LICENSE
---
cli.c (8420B)
---
1 #include <sys/socket.h>
2 #include <sys/types.h>
3
4 #include <errno.h>
5 #include <netdb.h>
6 #include <stdarg.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <unistd.h>
11
12 #include "https.h"
13 #include "util.h"
14 #include "youtube.h"
15
16 #define OUT(s) fputs((s), stdout)
17 #define OUTESCAPE(s) printescape((s))
18 #define OUTENCODED(s) printencoded((s))
19
20 /* print: ignore control-characters */
21 void
22 printescape(const char *s)
23 {
24 for (; *s; ++s)
25 if (!ISCNTRL((unsigned char)*s))
26 fputc(*s, stdout);
27 }
28
29 /* print: encode TAB, newline and '\', remove other whitespace. */
30 void
31 printencoded(const char *s)
32 {
33 for (; *s; ++s) {
34 switch (*s) {
35 case '\n': putchar('\\'); putchar('n'); break;
36 case '\\': putchar('\\'); putchar('\\'); break;
37 case '\t': putchar('\\'); putchar('t'); break;
38 default:
39 /* ignore control chars */
40 if (!ISCNTRL((unsigned char)*s))
41 putchar(*s);
42 break;
43 }
44 }
45 }
46
47 void
48 printescape_multiline(const char *s, const char *indent)
49 {
50 int i = 0;
51
52 for (; *s; ++s) {
53 if (!i)
54 fputs(indent, stdout);
55
56 if (*s == '\n') {
57 i = 0;
58 fputc(*s, stdout);
59 } else if (!ISCNTRL((unsigned char)*s)) {
60 fputc(*s, stdout);
61 i = 1;
62 }
63 }
64 }
65
66 int
67 render_search_tsv(struct search_response *r)
68 {
69 struct item *v;
70 size_t i;
71
72 for (i = 0; i < r->nitems; i++) {
73 v = &(r->items[i]);
74
75 OUTESCAPE(v->id);
76 OUT("\t");
77 if (v->id[0]) {
78 OUT("https://www.youtube.com/embed/");
79 OUTESCAPE(v->id);
80 }
81 OUT("\t");
82 OUTESCAPE(v->title);
83 OUT("\t");
84 OUTESCAPE(v->publishedat);
85 OUT("\t");
86 OUTESCAPE(v->viewcount); /* from Youtube, the text can b…
87 OUT("\t");
88 OUTESCAPE(v->duration);
89 OUT("\t");
90 switch (v->linktype) {
91 case Channel: OUT("channel"); break;
92 case Movie: OUT("movie"); break;
93 case Playlist: OUT("playlist"); break;
94 default: break;
95 }
96 OUT("\t");
97 OUTESCAPE(v->channelid);
98 OUT("\t");
99 OUTESCAPE(v->channeltitle);
100 OUT("\t");
101 OUTESCAPE(v->userid);
102 OUT("\t");
103 OUTENCODED(v->shortdescription);
104 OUT("\n");
105 }
106
107 return 0;
108 }
109
110 int
111 render_search(struct search_response *r)
112 {
113 struct item *v;
114 size_t i;
115
116 for (i = 0; i < r->nitems; i++) {
117 v = &(r->items[i]);
118
119 switch (v->linktype) {
120 case Channel:
121 OUT("Channel: ");
122 OUTESCAPE(v->channeltitle);
123 break;
124 case Movie:
125 OUT("Movie: ");
126 OUTESCAPE(v->title);
127 break;
128 case Playlist:
129 OUT("Playlist: ");
130 OUTESCAPE(v->title);
131 break;
132 default:
133 OUT(" ");
134 OUTESCAPE(v->title);
135 break;
136 }
137 if (v->duration[0]) {
138 OUT(" [");
139 OUTESCAPE(v->duration);
140 OUT("]");
141 }
142 OUT("\n");
143
144 if (v->id[0]) {
145 OUT("URL: https://www.youtube.com/embed/");
146 OUTESCAPE(v->id);
147 OUT("\n");
148 }
149
150 if (v->channelid[0] || v->userid[0]) {
151 OUT("Channel: ");
152 OUTESCAPE(v->channeltitle);
153 OUT(": https://www.youtube.com/feeds/videos.xml?…
154 if (v->channelid[0]) {
155 OUT("channel_id=");
156 OUTESCAPE(v->channelid);
157 } else if (v->userid[0]) {
158 OUT("user=");
159 OUTESCAPE(v->userid);
160 }
161 OUT("\n");
162 }
163 if (v->publishedat[0]) {
164 OUT("Published: ");
165 OUTESCAPE(v->publishedat);
166 OUT("\n");
167 }
168 if (v->viewcount[0]) {
169 OUT("Views: ");
170 if (!printnumsep(v->viewcount))
171 OUT("0");
172 OUT("\n");
173 }
174 OUT("\n");
175 }
176
177 return 0;
178 }
179
180 int
181 render_video(struct video_response *r)
182 {
183 struct video_format *f;
184 char buf[256];
185 int i;
186
187 OUT("URL: ");
188 OUT("https://www.youtube.com/embed/");
189 OUTESCAPE(r->id);
190 OUT("\n");
191
192 OUT("Title: ");
193 OUTESCAPE(r->title);
194 OUT("\n");
195
196 if (r->lengthseconds > 0) {
197 OUT("Length: ");
198 if (durationstr(r->lengthseconds, buf, sizeof(buf)) < si…
199 OUTESCAPE(buf);
200 OUT("\n");
201 }
202
203 OUT("Views: ");
204 snprintf(buf, sizeof(buf), "%ld", r->viewcount);
205 if (!printnumsep(buf))
206 OUT("0");
207 OUT("\n");
208
209 if (r->publishdate[0]) {
210 OUT("Published: ");
211 OUTESCAPE(r->publishdate);
212 OUT("\n");
213 }
214
215 if (r->uploaddate[0]) {
216 OUT("Uploaded: ");
217 OUTESCAPE(r->uploaddate);
218 OUT("\n");
219 }
220
221 if (r->author[0]) {
222 OUT("Channel: ");
223 OUTESCAPE(r->author);
224 if (r->channelid[0]) {
225 OUT(": https://www.youtube.com/feeds/videos.xml?…
226 OUTESCAPE(r->channelid);
227 }
228 OUT("\n");
229 }
230
231 if (r->shortdescription[0]) {
232 OUT("Description:\n\n");
233 printescape_multiline(r->shortdescription, "");
234 OUT("\n");
235 }
236
237 if (r->nformats == 0)
238 return 0;
239
240 OUT("\n\nFormats:\n\n");
241
242 /* links expiration */
243 if (r->expiresinseconds > 0) {
244 OUT("Expires in ");
245 printf("%ld", r->expiresinseconds);
246 OUT(" seconds\n");
247 }
248
249 for (i = 0; i < r->nformats; i++) {
250 f = &(r->formats[i]);
251
252 #if 0
253 if (f->width < 1280 || f->height < 720)
254 continue;
255 #endif
256
257 #if 0
258 OUT("Last modified: ");
259 OUTESCAPE(f->lastmodified);
260 OUT("\n");
261 #endif
262
263 if (f->url[0]) {
264 OUT("URL: ");
265 OUTESCAPE(f->url);
266 OUT("\n");
267 }
268
269 /* encrypted stream */
270 if (f->signaturecipher[0]) {
271 OUT("Signature: ");
272 OUTESCAPE(f->signaturecipher);
273 OUT("\n");
274 }
275
276 if (f->mimetype[0]) {
277 OUT("Mime: ");
278 OUTESCAPE(f->mimetype);
279 OUT("\n");
280 }
281
282 if (f->itag > 0) {
283 OUT("itag: ");
284 printf("%ld\n", f->itag);
285 }
286
287 if (f->qualitylabel[0]) {
288 OUT("Quality: ");
289 OUTESCAPE(f->qualitylabel);
290 } else if (f->quality[0]) {
291 OUT("Quality: ");
292 OUTESCAPE(f->quality);
293 }
294
295 if (f->width > 0) {
296 OUT(", ");
297 printf("%ld", f->width);
298 OUT("x");
299 printf("%ld", f->height);
300 OUT("");
301 }
302 if (f->fps > 0) {
303 OUT(", ");
304 printf("%ld", f->fps);
305 OUT(" FPS");
306 }
307 OUT("\n");
308
309 if (f->bitrate > 0) {
310 OUT("Bitrate: ");
311 printf("%ld", f->bitrate);
312 if (f->averagebitrate > 0)
313 printf(", average: %ld", f->averagebitra…
314 OUT("\n");
315 }
316
317 if (f->contentlength > 0) {
318 OUT("Size: ");
319 printf("%lld bytes (%.2f MB)\n", f->contentlengt…
320 }
321
322 if (f->audiochannels > 0 || f->audiosamplerate) {
323 OUT("Audio: ");
324 if (f->audiochannels > 0)
325 printf("%ld channels", f->audiochannels);
326 if (f->audiosamplerate > 0) {
327 if (f->audiochannels > 0)
328 OUT(", ");
329 printf("%ld sample rate", f->audiosample…
330 }
331 OUT("\n");
332 }
333
334 OUT("\n");
335 }
336
337 return 0;
338 }
339
340 static void
341 usage(const char *argv0)
342 {
343 fprintf(stderr, "usage: %s [-t] <keyword> | <-c channelid> | <-u…
344 exit(1);
345 }
346
347 int
348 main(int argc, char *argv[])
349 {
350 struct search_response *r = NULL;
351 struct video_response *vr = NULL;
352 char search[1024];
353 const char *keywords = NULL, *channelid = NULL, *user = NULL, *v…
354 const char *order = "relevance";
355 int i, usetsv = 0;
356
357 if (pledge("stdio dns inet rpath unveil", NULL) == -1) {
358 fprintf(stderr, "pledge: %s\n", strerror(errno));
359 exit(1);
360 }
361
362 for (i = 1; i < argc; i++) {
363 if (argv[i][0] == '-') {
364 switch (argv[i][1]) {
365 case 'c':
366 if (i + 1 >= argc)
367 usage(argv[0]);
368 channelid = argv[i + 1];
369 i++;
370 break;
371 case 'i':
372 if (i + 1 >= argc)
373 usage(argv[0]);
374 videoid = argv[i + 1];
375 i++;
376 break;
377 case 'o':
378 if (i + 1 >= argc)
379 usage(argv[0]);
380 order = argv[i + 1];
381 i++;
382 break;
383 case 'u':
384 if (i + 1 >= argc)
385 usage(argv[0]);
386 user = argv[i + 1];
387 i++;
388 break;
389 case 't':
390 usetsv = 1;
391 break;
392 default:
393 usage(argv[0]);
394 }
395 continue;
396 }
397 keywords = argv[i];
398 }
399
400 if (unveil(TLS_CA_CERT_FILE, "r") == -1) {
401 fprintf(stderr, "unveil: %s\n", strerror(errno));
402 exit(1);
403 }
404 if (unveil(NULL, NULL) == -1) {
405 fprintf(stderr, "unveil: %s\n", strerror(errno));
406 exit(1);
407 }
408
409 if (argc < 2 || !argv[1][0])
410 usage(argv[0]);
411
412 /* check order options */
413 if (strcmp(order, "relevance") &&
414 strcmp(order, "views") &&
415 strcmp(order, "rating"))
416 usage(argv[0]);
417
418 if (channelid) {
419 r = youtube_channel_videos(channelid);
420 } else if (user) {
421 r = youtube_user_videos(user);
422 } else if (videoid) {
423 vr = youtube_video(videoid);
424 if (!vr || vr->isfound == 0) {
425 OUT("No video found\n");
426 exit(1);
427 }
428 render_video(vr);
429 return 0;
430 } else if (keywords) {
431 if (!uriencode(keywords, search, sizeof(search)))
432 usage(argv[0]);
433 r = youtube_search(search, "", order);
434 }
435 if (!r || r->nitems == 0) {
436 OUT("No videos found\n");
437 exit(1);
438 }
439
440 if (pledge("stdio", NULL) == -1) {
441 fprintf(stderr, "pledge: %s\n", strerror(errno));
442 exit(1);
443 }
444
445 if (usetsv)
446 render_search_tsv(r);
447 else
448 render_search(r);
449
450 return 0;
451 }
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.