/* * cli-tube, just a simple youtube viewer * Copyright (C) 2021 vech * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #include #include #include #include #include #include #include #include #include "main.h" void error(char *c) { fprintf(stderr, "%s: %s\n", c, strerror(errno)); exit(1); } list *list_create(char title[], char id[]) { list *x = (list *)malloc(sizeof(list)); sscanf(title, "%199[^\n]", x->title); sscanf(id, "%11s", x->id); x->next = NULL; return x; } void list_free(list *start) { list *i; list *next = NULL; for (i = start; i != NULL; i = next) { next = i->next; free(i); } } void list_append(list *list_first, char title[], char id[]) { list *i; for(i = list_first; i->next != NULL; i = i->next); i->next = list_create(title, id); } void list_print_item(list *x, int i) { list *p; if (i == -1){ for (p = x; p->next != NULL; p = p->next); } else { for(p = x; i != 0; p = p->next, i--){ if (p == NULL) { fprintf(stderr, "List index out of range"); exit(1); } } } printf("title: %s\n", p->title); printf("id: %s\n\n", p->id); } list *list_get_node(list *x, int index) { list *p; for (p = x; index != 0; p = p->next, index--) { if (p == NULL) { fprintf(stderr, "List index out of range"); exit(1); } } return p; } list *parse_stream(FILE *file) { int i; list *videos = list_create("", ""); char buffer_id[ID_LENGTH], buffer_title[TITLE_LENGTH]; do { i = fscanf(file, "\"videoRenderer\":{\"videoId\":\"%11s\"", buffer_id); if (i == 1){ do{ i = fscanf(file, "\"title\":{\"runs\":[{\"text\":%199[^}]\"}", buffer_title); if (i == 1){ list_append(videos, buffer_title, buffer_id); break; } } while (fscanf(file, "%*c") != EOF); } } while (fscanf(file, "%*c") != EOF); return videos; } char *argv_concat(char *concat_char, char **argv, int argc) { int i; size_t concat_length = 0; concat_char[0] = '\0'; for (i = 1; i < argc; i++){ concat_length += strlen(argv[i]); } concat_length += argc - 2; if (concat_length > TITLE_LENGTH - 1){ fprintf(stderr, "Input characters exceded: you can enter %i " "chars at most not %i\n", TITLE_LENGTH - 1, (int)concat_length); exit(1); } strcat(concat_char, argv[1]); for (i = 2; i < argc; i++) { strcat(concat_char, "+"); strcat(concat_char, argv[i]); } return concat_char; } int main(int argc, char **argv) { char query[TITLE_LENGTH]; if (argc < 2) { fprintf(stderr, "You must provide at least 1 argument not %i\n", argc - 1); fprintf(stderr, "Usage: cli-tube ...\n"); exit(1); } argv_concat(query, argv, argc); char curl_query[TITLE_LENGTH + 43] = {"https://www.youtube.com/results?search_query="}; strcat(curl_query, query); int curl_main_pipe[2]; if (pipe(curl_main_pipe) == -1) { error("Can't create the pipe"); } pid_t curl_pid = fork(); if (curl_pid == -1) { error("Can't fork curl process"); } else if (!curl_pid) { close(curl_main_pipe[0]); dup2(curl_main_pipe[1], 1); if (execlp("curl", "curl", "--silent",curl_query, NULL) == -1) { error("Can't run curl command"); } } dup2(curl_main_pipe[0], 0); close(curl_main_pipe[1]); list *videos = parse_stream(stdin); int curl_exit_status; if (waitpid(curl_pid, &curl_exit_status, 0) == -1) { error("Can't wait curl process"); } if (WEXITSTATUS(curl_exit_status) < 0) { fprintf(stderr, "curl exit error, exit status: %i", WEXITSTATUS(curl_exit_status)); } close(curl_main_pipe[0]); if (!freopen("/dev/tty", "r", stdin)) { error("/dev/tty"); } list *q; int i = 0; char index_video[3]; do { printf( " ====================================================================\n" " | YOUTUBE RESULTS |\n" " ====================================================================\n" ); for (q = videos->next, i = 1; q != NULL; q = q->next, i++) { printf("%3d. %s\n", i, q->title); } printf("Select one video: "); fgets(index_video, 3, stdin); printf("\n\n"); } while (atoi(index_video) >= i || atoi(index_video) < 1); q = list_get_node(videos, atoi(index_video)); char url_watch[45]; sprintf(url_watch, "https://www.youtube.com/watch?v=%s", q->id); list_free(videos); pid_t mpv_pid = fork(); int mpv_exit_status; switch (mpv_pid) { case -1: error("Can't fork mpv process"); break; case 0: printf("Loading %s\n", url_watch); if (execlp("mpv", "mpv", url_watch, NULL) == -1) { error("Can't run mpv"); } break; default: if (waitpid(mpv_pid, &mpv_exit_status, 0) == -1) { error("Can't wait mpv process"); } if (WEXITSTATUS(mpv_exit_status) == -1) { fprintf(stderr, "mpv exit error, exit status: %i", WEXITSTATUS(mpv_exit_status)); } break; } return 0; }