You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
322 lines
8.7 KiB
322 lines
8.7 KiB
/*
|
|
* Copyright (C) 2019 Anthony Chomienne, anthony@mob-dev.fr
|
|
*
|
|
* 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, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <getopt.h>
|
|
#include <string.h>
|
|
#include <sys/types.h>
|
|
#include <sys/wait.h>
|
|
#include <sys/stat.h>
|
|
#include <fcntl.h>
|
|
|
|
|
|
#define PROG_NAME "Split Audio File"
|
|
#define VERSION "0.1"
|
|
|
|
struct internal_data {
|
|
char* input_file;
|
|
char* output_dir;
|
|
char* split_file_info;
|
|
};
|
|
|
|
struct track_info {
|
|
int num;
|
|
char* title;
|
|
char* start;
|
|
char* end;
|
|
};
|
|
|
|
struct album_info {
|
|
int info_number;
|
|
char* group;
|
|
char* album;
|
|
char* year;
|
|
char* genre;
|
|
int track_number;
|
|
struct track_info* tracks;
|
|
};
|
|
|
|
char* prog_name;
|
|
|
|
void help()
|
|
{
|
|
fprintf(stderr, "---------------- "PROG_NAME" --------------------------------\n");
|
|
fprintf(stderr, "Usage: %s [options]\n" \
|
|
" Available options:\n" \
|
|
" \t -i | --input-file : Input File to split\n" \
|
|
" \t -o | --output-dir : Output Directory for split files\n" \
|
|
" \t -s | --split-file-info : Split File information\n" \
|
|
" \t -h | --help : Print this help\n" \
|
|
" \t -v | --version : Print programm version\n" \
|
|
" All other arguments are data for the command, handled depending on the command.\n", prog_name);
|
|
fprintf(stderr, "-----------------------------------------------------------------------\n");
|
|
}
|
|
|
|
void extract_trackinfo(FILE* split_file_info, struct track_info* info, int track_number)
|
|
{
|
|
int eof = 0;
|
|
int parsed_tracks = 0;
|
|
while(!eof && parsed_tracks < track_number)
|
|
{
|
|
char* line = NULL;
|
|
size_t default_size = 0;
|
|
int final_size = getline(&line,&default_size,split_file_info);
|
|
if(final_size == -1) {
|
|
eof = 1;
|
|
continue;
|
|
}
|
|
char* split = strtok(line,";");
|
|
size_t success = sscanf(split,"%d",&info[parsed_tracks].num);
|
|
if(!success) {
|
|
fprintf(stderr,"File Malformed: Track Number Error");
|
|
}
|
|
split = strtok(NULL,";");
|
|
info[parsed_tracks].title = strdup(split);
|
|
split = strtok(NULL,";");
|
|
info[parsed_tracks].start = strdup(split);
|
|
split = strtok(NULL,";");
|
|
info[parsed_tracks].end = strdup(split);
|
|
parsed_tracks++;
|
|
free(line);
|
|
}
|
|
}
|
|
|
|
void extract_albuminfo(struct internal_data* glob, struct album_info* info)
|
|
{
|
|
FILE* split_file = fopen(glob->split_file_info,"r");
|
|
if(split_file == NULL)
|
|
{
|
|
fprintf(stderr,"%s doesn't exist\n", glob->split_file_info);
|
|
exit(-1);
|
|
}
|
|
|
|
int found_tracks = 0;
|
|
|
|
while(!found_tracks)
|
|
{
|
|
char* line = NULL;
|
|
size_t default_size = 0;
|
|
getline(&line,&default_size,split_file);
|
|
|
|
char* category = strtok(line,";");
|
|
if(strcmp(category,"group") == 0)
|
|
{
|
|
category = strtok(NULL,";");
|
|
info->group = strdup(category);
|
|
info->info_number++;
|
|
}
|
|
else if(strcmp(category,"album") == 0)
|
|
{
|
|
category = strtok(NULL,";");
|
|
info->album = strdup(category);
|
|
info->info_number++;
|
|
}
|
|
else if(strcmp(category,"year") == 0)
|
|
{
|
|
category = strtok(NULL,";");
|
|
info->year = strdup(category);
|
|
info->info_number++;
|
|
}
|
|
else if(strcmp(category,"genre") == 0)
|
|
{
|
|
category = strtok(NULL,";");
|
|
info->genre = strdup(category);
|
|
info->info_number++;
|
|
}
|
|
else if(strcmp(category,"tracks") == 0)
|
|
{
|
|
category = strtok(NULL,";");
|
|
size_t success = sscanf(category,"%d",&info->track_number);
|
|
if(!success)
|
|
{
|
|
fprintf(stderr,"File Malformed: Number of Tracks Error\n");
|
|
exit(-1);
|
|
}
|
|
found_tracks = 1;
|
|
info->info_number+=4*info->track_number;
|
|
|
|
}
|
|
free(line);
|
|
}
|
|
info->tracks = malloc(info->track_number * sizeof(struct track_info));
|
|
extract_trackinfo(split_file,info->tracks, info->track_number);
|
|
|
|
fclose(split_file);
|
|
}
|
|
|
|
void build_args(char* input_file, char* output_dir, struct album_info* info,int track_id, char*** args)
|
|
{
|
|
*args = malloc((15+2*info->info_number+1)*sizeof(char*));
|
|
(*args)[0]="ffmpeg";
|
|
(*args)[1]="-i";
|
|
(*args)[2]=input_file;
|
|
(*args)[3]="-acodec";
|
|
(*args)[4]="copy";
|
|
int optionnal = 5;
|
|
if(info->group != NULL)
|
|
{
|
|
(*args)[optionnal++]="-metadata";
|
|
(*args)[optionnal] = malloc(strlen("artist=")+strlen(info->group)+1);
|
|
sprintf((*args)[optionnal++],"artist=%s",info->group);
|
|
}
|
|
if(info->album != NULL)
|
|
{
|
|
(*args)[optionnal++]="-metadata";
|
|
(*args)[optionnal] = malloc(strlen("album=")+strlen(info->album)+1);
|
|
sprintf((*args)[optionnal++],"album=%s",info->album);
|
|
}
|
|
if(info->genre != NULL)
|
|
{
|
|
(*args)[optionnal++]="-metadata";
|
|
(*args)[optionnal] = malloc(strlen("genre=")+strlen(info->genre)+1);
|
|
sprintf((*args)[optionnal++],"genre=%s",info->genre);
|
|
}
|
|
if(info->year != NULL)
|
|
{
|
|
(*args)[optionnal++]="-metadata";
|
|
(*args)[optionnal] = malloc(strlen("date=")+strlen(info->year)+1);
|
|
sprintf((*args)[optionnal++],"date=%s",info->year);
|
|
}
|
|
|
|
(*args)[optionnal++]="-metadata";
|
|
(*args)[optionnal] = malloc(strlen("title=")+strlen(info->tracks[track_id].title)+1);
|
|
sprintf((*args)[optionnal++],"title=%s",info->tracks[track_id].title);
|
|
|
|
(*args)[optionnal++]="-metadata";
|
|
(*args)[optionnal] = malloc(strlen("tracknumber=")+2+1);
|
|
sprintf((*args)[optionnal++],"tracknumber=%02d",info->tracks[track_id].num);
|
|
(*args)[optionnal++]="-ss";
|
|
(*args)[optionnal] = malloc(8+1);
|
|
sprintf((*args)[optionnal++],"00:%s",info->tracks[track_id].start);
|
|
(*args)[optionnal++]="-to";
|
|
(*args)[optionnal] = malloc(8+1);
|
|
sprintf((*args)[optionnal++],"00:%s",info->tracks[track_id].end);
|
|
|
|
(*args)[optionnal] = malloc(strlen(output_dir)+1+2+3+strlen(info->tracks[track_id].title)+4+1);
|
|
sprintf((*args)[optionnal++],"%s/%02d - %s.ogg",output_dir,info->tracks[track_id].num,info->tracks[track_id].title);
|
|
(*args)[optionnal]=NULL;
|
|
printf("%d\n",optionnal);
|
|
}
|
|
|
|
void split_into_files(struct internal_data* data, struct album_info* info)
|
|
{
|
|
for(int i=0; i < info->track_number; i++)
|
|
{
|
|
if(fork() == 0)
|
|
{
|
|
char** args = NULL;
|
|
build_args(data->input_file, data->output_dir, info, i, &args);
|
|
execvp("ffmpeg",args);
|
|
fprintf(stderr,"Error starting ffmpeg\n");
|
|
exit(-1);
|
|
}
|
|
wait(NULL);
|
|
}
|
|
}
|
|
|
|
void cleanup(struct album_info* info)
|
|
{
|
|
free(info->year);
|
|
free(info->group);
|
|
free(info->album);
|
|
free(info->genre);
|
|
for(int i=0; i < info->track_number; i++)
|
|
{
|
|
free(info->tracks[i].title);
|
|
free(info->tracks[i].start);
|
|
free(info->tracks[i].end);
|
|
}
|
|
free(info->tracks);
|
|
}
|
|
|
|
int main(int argc, char* argv[])
|
|
{
|
|
|
|
prog_name = argv[0];
|
|
|
|
struct internal_data glob;
|
|
memset(&glob,0,sizeof(struct internal_data));
|
|
while(1)
|
|
{
|
|
int option_index = 0;
|
|
int c = 0;
|
|
|
|
struct option long_options[] = {
|
|
{"input-file", required_argument, 0, 'i'},
|
|
{"output-dir", required_argument, 0, 'o'},
|
|
{"split-file-info", required_argument, 0, 's'},
|
|
{"help", no_argument, 0, 'h'},
|
|
{"version", no_argument, 0, 'v'},
|
|
{0, 0, 0, 0}
|
|
};
|
|
|
|
c = getopt_long(argc, argv, "i:o:s:hv", long_options, &option_index);
|
|
|
|
/* no more options to parse */
|
|
if (c == -1) break;
|
|
switch (c)
|
|
{
|
|
/* i Input Audio File */
|
|
case 'i':
|
|
glob.input_file = optarg;
|
|
break;
|
|
|
|
/* o, Output Directory*/
|
|
case 'o':
|
|
glob.output_dir = optarg;
|
|
break;
|
|
|
|
/* s, Split Information File */
|
|
case 's':
|
|
glob.split_file_info = optarg;
|
|
break;
|
|
|
|
/* v, version */
|
|
case 'v':
|
|
printf("%s Version %s\n", PROG_NAME, VERSION);
|
|
return 0;
|
|
break;
|
|
|
|
/* h, help */
|
|
case 'h':
|
|
default:
|
|
help();
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
if(glob.input_file == NULL || glob.output_dir == NULL || glob.split_file_info == NULL)
|
|
{
|
|
fprintf(stderr,"Error, need input file, output directory and split file informations\n");
|
|
help(argv[0]);
|
|
}
|
|
|
|
struct album_info album_info;
|
|
memset(&album_info,0,sizeof(struct album_info));
|
|
|
|
extract_albuminfo(&glob,&album_info);
|
|
split_into_files(&glob,&album_info);
|
|
cleanup(&album_info);
|
|
|
|
return 0;
|
|
}
|