menu.c 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  1. #define _GNU_SOURCE
  2. #include "menu.h"
  3. #include "youtube.h"
  4. #include "parse.h"
  5. #include "common.h"
  6. #include <readline/readline.h>
  7. #include <readline/history.h>
  8. #include <string.h>
  9. #include <stdlib.h>
  10. #include <assert.h>
  11. #define NELEMS(arr) sizeof(arr) / sizeof(arr[0])
  12. /* %a will be replaced with link on audio file
  13. * %v will be replaced with link on video file */
  14. #define AUDIO_PLAYER "mplayer \"%a\""
  15. #define VIDEO_PLAYER "mplayer -really-quiet -vo fbdev2 \"%v\""
  16. #define WATCH_PLAYER "mplayer -really-quiet -vo fbdev2 \"%v\" -audiofile \"%a\""
  17. struct cmd_list
  18. {
  19. const char* const cmd;
  20. void (*func)(int argc, char** argv);
  21. };
  22. static void cmdexit(int argc, char** argv);
  23. static void cmdhelp(int argc, char** argv);
  24. static void cmdinfo(int argc, char** argv);
  25. static void cmdmedia(int argc, char** argv);
  26. static void cmdsearch(int argc, char** argv);
  27. static void cmdurl(int argc, char** argv);
  28. static void cmdaudio(int argc, char** argv);
  29. static void cmdvideo(int argc, char** argv);
  30. static void cmdwatch(int argc, char** argv);
  31. const struct cmd_list cmd_list[] =
  32. {
  33. {"exit", cmdexit},
  34. {"help", cmdhelp},
  35. {"info", cmdinfo},
  36. {"media", cmdmedia},
  37. {"search", cmdsearch},
  38. {"url", cmdurl},
  39. {"audio", cmdaudio},
  40. {"video", cmdvideo},
  41. {"watch", cmdwatch},
  42. };
  43. static _Bool loop_exit = 0;
  44. static char* line_read = NULL; /* Contains last line read from stdin */
  45. static video_list* last_vl = NULL;
  46. static video_info* last_vi = NULL;
  47. static void cmd(const char* _str)
  48. {
  49. char* str = strdup(_str);
  50. if(!str)
  51. return;
  52. char* ptr = str;
  53. int argc = 1;
  54. /* Split input string, replace spaces with \0 */
  55. while((ptr = strchr(ptr, ' ')))
  56. {
  57. *ptr++ = '\0';
  58. argc++;
  59. }
  60. /* Empty string */
  61. if(!*str)
  62. return;
  63. /* Find if command exists */
  64. int cmdnum = -1;
  65. int len = strlen(str);
  66. for(unsigned i = 0; i < NELEMS(cmd_list); i++)
  67. {
  68. if(!strncmp(str, cmd_list[i].cmd, len))
  69. {
  70. cmdnum = i;
  71. break;
  72. }
  73. }
  74. /* Command not found */
  75. if(cmdnum < 0)
  76. {
  77. printf("%s: command not found\n", str);
  78. return;
  79. }
  80. /* Fill argv array with arguments */
  81. char** argv = malloc(sizeof(char *) * (argc+1));
  82. argv[argc] = NULL;
  83. ptr = str;
  84. for(int i = 0; i < argc; i++)
  85. {
  86. argv[i] = ptr;
  87. ptr = strchr(ptr, '\0')+1;
  88. }
  89. /* Call command */
  90. assert(cmd_list[cmdnum].func);
  91. cmd_list[cmdnum].func(argc, argv);
  92. free(argv);
  93. }
  94. static char* rl_gets(void)
  95. {
  96. line_read = readline("> ");
  97. if(line_read && *line_read && *line_read != ' ')
  98. add_history(line_read);
  99. return line_read;
  100. }
  101. int menu_control(void)
  102. {
  103. while(!loop_exit)
  104. {
  105. rl_gets();
  106. if(!line_read) /* ^D -- exit */
  107. {
  108. puts("");
  109. break;
  110. }
  111. cmd(line_read);
  112. free(line_read);
  113. }
  114. return 0;
  115. }
  116. static video_info* menu_get_video_info(char* str)
  117. {
  118. video_info* vi = NULL;
  119. /* url? */
  120. char* id = video_id_from_url(str);
  121. if(id)
  122. {
  123. vi = get_video_info(id);
  124. free(id);
  125. return vi;
  126. }
  127. /* Menu item number? */
  128. char* notnum = NULL;
  129. long num = strtol(str, &notnum, 10);
  130. if(!*notnum && *str)
  131. {
  132. if(last_vl && num < last_vl->count)
  133. return get_video_info(last_vl->vi[num]->id);
  134. return NULL;
  135. }
  136. /* Just video ID? */
  137. vi = get_video_info(str);
  138. if(vi)
  139. return vi;
  140. return NULL;
  141. }
  142. static media_info* menu_get_media_info(char* vstr, char* mstr)
  143. {
  144. video_info* vi = menu_get_video_info(vstr);
  145. if(!vi)
  146. return NULL;
  147. char* notnum = NULL;
  148. unsigned long mnum = strtoul(mstr, &notnum, 10);
  149. if(!*notnum && *mstr && mnum < vi->ml->count)
  150. return vi->ml->mi[mnum];
  151. free_video_info(vi);
  152. return NULL;
  153. }
  154. static void play_media(const char* vurl, const char* aurl)
  155. {
  156. char* sys = NULL;
  157. if(vurl && aurl)
  158. {
  159. char* tmp = replace_sub_str(WATCH_PLAYER, "%v", vurl);
  160. sys = replace_sub_str(tmp, "%a", aurl);
  161. free(tmp);
  162. }
  163. else if(vurl)
  164. sys = replace_sub_str(VIDEO_PLAYER, "%v", vurl);
  165. else if(aurl)
  166. sys = replace_sub_str(AUDIO_PLAYER, "%a", aurl);
  167. else
  168. return;
  169. if(system(sys)){}
  170. free(sys);
  171. }
  172. static void cmdexit(UNUSED int argc, UNUSED char** argv)
  173. {
  174. loop_exit = 1;
  175. }
  176. static void cmdhelp(UNUSED int argc, UNUSED char** argv)
  177. {
  178. puts("Available commands:");
  179. for(unsigned i = 0; i < NELEMS(cmd_list); i++)
  180. puts(cmd_list[i].cmd);
  181. }
  182. static void cmdinfo(int argc, char** argv)
  183. {
  184. if(argc < 2)
  185. return;
  186. video_info* info = menu_get_video_info(argv[1]);
  187. if(info)
  188. {
  189. printf("Title: %s\n", info->title ? info->title : "");
  190. printf("Channel: %s\n", info->author ? info->author : "");
  191. printf("Id: %s\n", info->id ? info->id : "");
  192. printf("Description:\n%s\n", info->description ? info->description : "");
  193. free_video_info(info);
  194. }
  195. }
  196. static void cmdmedia(int argc, char** argv)
  197. {
  198. if(argc < 2)
  199. return;
  200. free_video_info(last_vi);
  201. last_vi = menu_get_video_info(argv[1]);
  202. if(last_vi && last_vi->ml)
  203. {
  204. media_list* ml = last_vi->ml;
  205. for(unsigned i = 0; i < ml->count; i++)
  206. {
  207. media_info* mi = ml->mi[i];
  208. printf("%2u ", i);
  209. if(mi->video)
  210. printf("V%hu %s%hu ", mi->itag, mi->quality, mi->fps);
  211. if(mi->audio)
  212. printf("A%hu", mi->itag);
  213. puts("");
  214. }
  215. }
  216. }
  217. static void cmdsearch(int argc, UNUSED char** argv)
  218. {
  219. if(argc < 2)
  220. return;
  221. char* str = strchr(line_read, ' ') + 1; /* Can't fail */
  222. str = percent_encode(str);
  223. if(!str)
  224. return;
  225. /* Do search */
  226. free_video_list(last_vl);
  227. last_vl = search_request(str, 1);
  228. free(str);
  229. if(!last_vl)
  230. return;
  231. for(unsigned i = 0; i < last_vl->count; i++)
  232. {
  233. video_info* vi = last_vl->vi[i];
  234. printf("%2u %s\n", i, vi->title);
  235. }
  236. }
  237. static void cmdurl(int argc, char** argv)
  238. {
  239. if(argc < 3)
  240. return;
  241. media_info* mi = menu_get_media_info(argv[1], argv[2]);
  242. printf("%s\n", mi->url);
  243. }
  244. static void cmdaudio(int argc, char** argv)
  245. {
  246. if(argc < 3)
  247. return;
  248. media_info* mi = menu_get_media_info(argv[1], argv[2]);
  249. if(mi && mi->audio && !mi->video)
  250. play_media(NULL, mi->url);
  251. }
  252. static void cmdvideo(int argc, char** argv)
  253. {
  254. if(argc < 3)
  255. return;
  256. media_info* mi = menu_get_media_info(argv[1], argv[2]);
  257. if(mi && mi->video && !mi->audio)
  258. play_media(mi->url, NULL);
  259. }
  260. static void cmdwatch(int argc, char** argv)
  261. {
  262. if(argc < 4)
  263. return;
  264. const char* aurl = NULL;
  265. const char* vurl = NULL;
  266. media_info* mi = menu_get_media_info(argv[1], argv[2]);
  267. if(mi && mi->video && !mi->audio)
  268. vurl = mi->url;
  269. mi = menu_get_media_info(argv[1], argv[3]);
  270. if(mi && !mi->video && mi->audio)
  271. aurl = mi->url;
  272. if(aurl && vurl)
  273. play_media(vurl, aurl);
  274. }
  275. /* Legacy function */
  276. void mprint(UNUSED PRINT_TYPE type, char* fmt, ...)
  277. {
  278. va_list arg;
  279. va_start(arg, fmt);
  280. vprintf(fmt, arg);
  281. va_end(arg);
  282. }