Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

322 строки
8.7 KiB

  1. /*
  2. * Copyright (C) 2019 Anthony Chomienne, anthony@mob-dev.fr
  3. *
  4. * This program is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU General Public License
  6. * as published by the Free Software Foundation; either version 3
  7. * of the License, or (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software
  16. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  17. */
  18. #include <stdio.h>
  19. #include <stdlib.h>
  20. #include <unistd.h>
  21. #include <getopt.h>
  22. #include <string.h>
  23. #include <sys/types.h>
  24. #include <sys/wait.h>
  25. #include <sys/stat.h>
  26. #include <fcntl.h>
  27. #define PROG_NAME "Split Audio File"
  28. #define VERSION "0.1"
  29. struct internal_data {
  30. char* input_file;
  31. char* output_dir;
  32. char* split_file_info;
  33. };
  34. struct track_info {
  35. int num;
  36. char* title;
  37. char* start;
  38. char* end;
  39. };
  40. struct album_info {
  41. int info_number;
  42. char* group;
  43. char* album;
  44. char* year;
  45. char* genre;
  46. int track_number;
  47. struct track_info* tracks;
  48. };
  49. char* prog_name;
  50. void help()
  51. {
  52. fprintf(stderr, "---------------- "PROG_NAME" --------------------------------\n");
  53. fprintf(stderr, "Usage: %s [options]\n" \
  54. " Available options:\n" \
  55. " \t -i | --input-file : Input File to split\n" \
  56. " \t -o | --output-dir : Output Directory for split files\n" \
  57. " \t -s | --split-file-info : Split File information\n" \
  58. " \t -h | --help : Print this help\n" \
  59. " \t -v | --version : Print programm version\n" \
  60. " All other arguments are data for the command, handled depending on the command.\n", prog_name);
  61. fprintf(stderr, "-----------------------------------------------------------------------\n");
  62. }
  63. void extract_trackinfo(FILE* split_file_info, struct track_info* info, int track_number)
  64. {
  65. int eof = 0;
  66. int parsed_tracks = 0;
  67. while(!eof && parsed_tracks < track_number)
  68. {
  69. char* line = NULL;
  70. size_t default_size = 0;
  71. int final_size = getline(&line,&default_size,split_file_info);
  72. if(final_size == -1) {
  73. eof = 1;
  74. continue;
  75. }
  76. char* split = strtok(line,";");
  77. size_t success = sscanf(split,"%d",&info[parsed_tracks].num);
  78. if(!success) {
  79. fprintf(stderr,"File Malformed: Track Number Error");
  80. }
  81. split = strtok(NULL,";");
  82. info[parsed_tracks].title = strdup(split);
  83. split = strtok(NULL,";");
  84. info[parsed_tracks].start = strdup(split);
  85. split = strtok(NULL,";");
  86. info[parsed_tracks].end = strdup(split);
  87. parsed_tracks++;
  88. free(line);
  89. }
  90. }
  91. void extract_albuminfo(struct internal_data* glob, struct album_info* info)
  92. {
  93. FILE* split_file = fopen(glob->split_file_info,"r");
  94. if(split_file == NULL)
  95. {
  96. fprintf(stderr,"%s doesn't exist\n", glob->split_file_info);
  97. exit(-1);
  98. }
  99. int found_tracks = 0;
  100. while(!found_tracks)
  101. {
  102. char* line = NULL;
  103. size_t default_size = 0;
  104. getline(&line,&default_size,split_file);
  105. char* category = strtok(line,";");
  106. if(strcmp(category,"group") == 0)
  107. {
  108. category = strtok(NULL,";");
  109. info->group = strdup(category);
  110. info->info_number++;
  111. }
  112. else if(strcmp(category,"album") == 0)
  113. {
  114. category = strtok(NULL,";");
  115. info->album = strdup(category);
  116. info->info_number++;
  117. }
  118. else if(strcmp(category,"year") == 0)
  119. {
  120. category = strtok(NULL,";");
  121. info->year = strdup(category);
  122. info->info_number++;
  123. }
  124. else if(strcmp(category,"genre") == 0)
  125. {
  126. category = strtok(NULL,";");
  127. info->genre = strdup(category);
  128. info->info_number++;
  129. }
  130. else if(strcmp(category,"tracks") == 0)
  131. {
  132. category = strtok(NULL,";");
  133. size_t success = sscanf(category,"%d",&info->track_number);
  134. if(!success)
  135. {
  136. fprintf(stderr,"File Malformed: Number of Tracks Error\n");
  137. exit(-1);
  138. }
  139. found_tracks = 1;
  140. info->info_number+=4*info->track_number;
  141. }
  142. free(line);
  143. }
  144. info->tracks = malloc(info->track_number * sizeof(struct track_info));
  145. extract_trackinfo(split_file,info->tracks, info->track_number);
  146. fclose(split_file);
  147. }
  148. void build_args(char* input_file, char* output_dir, struct album_info* info,int track_id, char*** args)
  149. {
  150. *args = malloc((15+2*info->info_number+1)*sizeof(char*));
  151. (*args)[0]="ffmpeg";
  152. (*args)[1]="-i";
  153. (*args)[2]=input_file;
  154. (*args)[3]="-acodec";
  155. (*args)[4]="copy";
  156. int optionnal = 5;
  157. if(info->group != NULL)
  158. {
  159. (*args)[optionnal++]="-metadata";
  160. (*args)[optionnal] = malloc(strlen("artist=")+strlen(info->group)+1);
  161. sprintf((*args)[optionnal++],"artist=%s",info->group);
  162. }
  163. if(info->album != NULL)
  164. {
  165. (*args)[optionnal++]="-metadata";
  166. (*args)[optionnal] = malloc(strlen("album=")+strlen(info->album)+1);
  167. sprintf((*args)[optionnal++],"album=%s",info->album);
  168. }
  169. if(info->genre != NULL)
  170. {
  171. (*args)[optionnal++]="-metadata";
  172. (*args)[optionnal] = malloc(strlen("genre=")+strlen(info->genre)+1);
  173. sprintf((*args)[optionnal++],"genre=%s",info->genre);
  174. }
  175. if(info->year != NULL)
  176. {
  177. (*args)[optionnal++]="-metadata";
  178. (*args)[optionnal] = malloc(strlen("date=")+strlen(info->year)+1);
  179. sprintf((*args)[optionnal++],"date=%s",info->year);
  180. }
  181. (*args)[optionnal++]="-metadata";
  182. (*args)[optionnal] = malloc(strlen("title=")+strlen(info->tracks[track_id].title)+1);
  183. sprintf((*args)[optionnal++],"title=%s",info->tracks[track_id].title);
  184. (*args)[optionnal++]="-metadata";
  185. (*args)[optionnal] = malloc(strlen("tracknumber=")+2+1);
  186. sprintf((*args)[optionnal++],"tracknumber=%02d",info->tracks[track_id].num);
  187. (*args)[optionnal++]="-ss";
  188. (*args)[optionnal] = malloc(8+1);
  189. sprintf((*args)[optionnal++],"00:%s",info->tracks[track_id].start);
  190. (*args)[optionnal++]="-to";
  191. (*args)[optionnal] = malloc(8+1);
  192. sprintf((*args)[optionnal++],"00:%s",info->tracks[track_id].end);
  193. (*args)[optionnal] = malloc(strlen(output_dir)+1+2+3+strlen(info->tracks[track_id].title)+4+1);
  194. sprintf((*args)[optionnal++],"%s/%02d - %s.ogg",output_dir,info->tracks[track_id].num,info->tracks[track_id].title);
  195. (*args)[optionnal]=NULL;
  196. printf("%d\n",optionnal);
  197. }
  198. void split_into_files(struct internal_data* data, struct album_info* info)
  199. {
  200. for(int i=0; i < info->track_number; i++)
  201. {
  202. if(fork() == 0)
  203. {
  204. char** args = NULL;
  205. build_args(data->input_file, data->output_dir, info, i, &args);
  206. execvp("ffmpeg",args);
  207. fprintf(stderr,"Error starting ffmpeg\n");
  208. exit(-1);
  209. }
  210. wait(NULL);
  211. }
  212. }
  213. void cleanup(struct album_info* info)
  214. {
  215. free(info->year);
  216. free(info->group);
  217. free(info->album);
  218. free(info->genre);
  219. for(int i=0; i < info->track_number; i++)
  220. {
  221. free(info->tracks[i].title);
  222. free(info->tracks[i].start);
  223. free(info->tracks[i].end);
  224. }
  225. free(info->tracks);
  226. }
  227. int main(int argc, char* argv[])
  228. {
  229. prog_name = argv[0];
  230. struct internal_data glob;
  231. memset(&glob,0,sizeof(struct internal_data));
  232. while(1)
  233. {
  234. int option_index = 0;
  235. int c = 0;
  236. struct option long_options[] = {
  237. {"input-file", required_argument, 0, 'i'},
  238. {"output-dir", required_argument, 0, 'o'},
  239. {"split-file-info", required_argument, 0, 's'},
  240. {"help", no_argument, 0, 'h'},
  241. {"version", no_argument, 0, 'v'},
  242. {0, 0, 0, 0}
  243. };
  244. c = getopt_long(argc, argv, "i:o:s:hv", long_options, &option_index);
  245. /* no more options to parse */
  246. if (c == -1) break;
  247. switch (c)
  248. {
  249. /* i Input Audio File */
  250. case 'i':
  251. glob.input_file = optarg;
  252. break;
  253. /* o, Output Directory*/
  254. case 'o':
  255. glob.output_dir = optarg;
  256. break;
  257. /* s, Split Information File */
  258. case 's':
  259. glob.split_file_info = optarg;
  260. break;
  261. /* v, version */
  262. case 'v':
  263. printf("%s Version %s\n", PROG_NAME, VERSION);
  264. return 0;
  265. break;
  266. /* h, help */
  267. case 'h':
  268. default:
  269. help();
  270. return 0;
  271. }
  272. }
  273. if(glob.input_file == NULL || glob.output_dir == NULL || glob.split_file_info == NULL)
  274. {
  275. fprintf(stderr,"Error, need input file, output directory and split file informations\n");
  276. help(argv[0]);
  277. }
  278. struct album_info album_info;
  279. memset(&album_info,0,sizeof(struct album_info));
  280. extract_albuminfo(&glob,&album_info);
  281. split_into_files(&glob,&album_info);
  282. cleanup(&album_info);
  283. return 0;
  284. }