From 421f874ec03fa08a659b5b4314411f24f1d6460b Mon Sep 17 00:00:00 2001 From: Antoine Jacquet Date: Sat, 21 Jan 2006 00:00:00 +0100 Subject: [PATCH] version 0.34 (by Andreas Neuper) * BUG fix: "unsigned char" (like in 0.31) to get complete output and avoid core dumps * BUG fix: disabled "skip" variable to use multiple args * added first attempt to generate RSS feeds (i.e. XML output) * allow plain file arguments (before: only directories) * raised defaults for inodes and file systems * adapt man page, etc --- CHANGELOG | 8 ++ README | 4 +- fapg.1 | 9 ++- fapg.c | 219 ++++++++++++++++++++++++++++++++++++++++-------------- 4 files changed, 182 insertions(+), 58 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 4acccea..cfc88f1 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,13 @@ Change log file for FAPG +version 0.34 (2006-01-21) (by Andreas Neuper) + * BUG fix: "unsigned char" (like in 0.31) to get complete output and avoid core dumps + * BUG fix: disabled "skip" variable to use multiple args + * added first attempt to generate RSS feeds (i.e. XML output) + * allow plain file arguments (before: only directories) + * raised defaults for inodes and file systems + * adapt man page, etc + version 0.33 (2006-01-15) * code cleanup to avoid compilation warnings with gcc 4 (patch by Laurent Coustet) * remove leading "./" when parsing current directory diff --git a/README b/README index 529b653..332dae5 100644 --- a/README +++ b/README @@ -1,4 +1,4 @@ -FAPG 0.33 (Fast Audio Playlist Generator) +FAPG 0.34 (Fast Audio Playlist Generator) site: http://royale.zerezo.com/fapg/ mail: royale@zerezo.com @@ -7,7 +7,7 @@ make make install usage: -fapg [-b|--backslash] [-d|--debug] [-f|--format=m3u|pls|html] [-g|--genre=#:#:...] [-o|--output=/path/to/file.m3u] [-p|--prefix=/the/prefix] [-r|--recursive] [-w|--windows] [-x|--exclude=#:#:...] /path/to/mp3/dir1 [/path/to/mp3/dir2 ...] +fapg [-b|--backslash] [-d|--debug] [-f|--format=m3u|pls|html|rss] [-g|--genre=#:#:...] [-o|--output=/path/to/file.m3u] [-p|--prefix=/the/prefix] [-r|--recursive] [-w|--windows] [-x|--exclude=#:#:...] /path/to/mp3/dir1 [/path/to/mp3/dir2 ...] - backslash : replace the '/' with '\' in Unix path. - debug : display useful messages if the program fails ;) - format : choose which format of playlist you want to generate (default is m3u). diff --git a/fapg.1 b/fapg.1 index a9af76f..8b3588f 100644 --- a/fapg.1 +++ b/fapg.1 @@ -18,7 +18,7 @@ fapg \- Fast Audio Playlist Generator .SH DESCRIPTION .B fapg is a tool to generate list of audio files (Wav, MP2, MP3, Ogg, etc) in various -formats (M3U, PLS, HTML, etc). It is very useful if you have a large amount +formats (M3U, PLS, HTML, RSS, etc). It is very useful if you have a large amount of audio files and you want to quickly and frequently build a playlist. .P It is coded in C to be as fast as possible, and does not use any specific @@ -32,7 +32,7 @@ formats. Replace the '/' with '\' in Unix path. .IP -d|--debug Display useful messages if the program fails ;) -.IP -f|--format=m3u|pls|html +.IP -f|--format=m3u|pls|html|rss Choose which format of playlist you want to generate (default is m3u). .IP -g|--genre=#:#:... Choose which genres (numerical values only) will be included in the generated playlist (default is all). @@ -70,6 +70,11 @@ An HTML playlist for an album: A playlist that contains all your classical tracks may receive the genres to include (or exclude) in one or multiple portions .B fapg --genre=32:105 --genre=106:104:103 /path/to/all/music +Generate a podcasting XML file: +.B fapg --output=dir.xml -f rss -r --prefix=http://thisserver/basedir path/to/mp3 +Please note that in all given directories ( and in /rss ) files called podcast.jpg are referenced. +Many header fields are set to defaults using environment variables like LOGNAME or LANG. + .SH AUTHOR Antoine Jacquet , http://royale.zerezo.com/fapg/. diff --git a/fapg.c b/fapg.c index b800d76..e627ea5 100644 --- a/fapg.c +++ b/fapg.c @@ -1,6 +1,8 @@ /* - * FAPG version 0.33 - * + * FAPG + */ +#define VERSION "0.34" +/* * FAPG means Fast Audio Playlist Generator. * It is a tool to generate list of audio files (Wav, MP3, Ogg, etc) * in various formats (M3U, PLS, HTML, etc). @@ -36,6 +38,7 @@ #include #include #include +#include #include #include "genres.h" @@ -44,33 +47,55 @@ #define MAX 1024*200 /* 200ko for ID3 with JPEG images in it */ int debug=0; -int format=0; /* 0 = m3u ; 1 = pls ; 2 = html */ +int format=0; /* 0 = m3u ; 1 = pls ; 2 = html ; 3 = rss */ char *genrelist=NULL; -char *prefix=""; +unsigned char *prefix=""; +unsigned char *base=""; +unsigned char *dir=""; +unsigned char *hostname="fritzserver.de"; +unsigned char *referal="http://www.explaining.text.org/select.php?title="; int recursive=0; int avoidhlinked=0; int separator='/'; int skip=0; int windows=0; -char *eol="\n"; -char buffer[MAX]; +unsigned char *eol="\n"; +unsigned char buffer[MAX]; int counter=0; -char artist[1024]; -char title[1024]; -char genrebuf[1024]; -char genre=0; +unsigned char artist[1024]; +unsigned char title[1024]; +unsigned char genrebuf[1024]; +unsigned char genre=0; int duration; -char unix2dos[256]={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,70,35,36,37,38,39,40,41,82,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,84,59,36,61,65,71,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,36,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,36,125,126,127,199,252,233,226,228,224,229,231,234,235,232,239,238,236,196,197,201,230,198,244,246,242,251,249,255,214,220,248,163,216,215,131,225,237,243,250,241,209,170,186,191,174,172,189,188,161,171,187,166,166,166,166,166,193,194,192,169,166,166,43,43,162,165,43,43,45,45,43,45,43,227,195,43,43,45,45,166,45,43,164,240,208,202,203,200,105,205,206,207,43,43,166,220,166,204,175,211,223,212,210,245,213,181,254,222,218,219,217,253,221,175,180,173,177,61,190,182,167,247,184,176,168,183,185,179,178,166,160}; +unsigned char unix2dos[256]={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,70,35,36,37,38,39,40,41,82,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,84,59,36,61,65,71,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,36,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,36,125,126,127,199,252,233,226,228,224,229,231,234,235,232,239,238,236,196,197,201,230,198,244,246,242,251,249,255,214,220,248,163,216,215,131,225,237,243,250,241,209,170,186,191,174,172,189,188,161,171,187,166,166,166,166,166,193,194,192,169,166,166,43,43,162,165,43,43,45,45,43,45,43,227,195,43,43,45,45,166,45,43,164,240,208,202,203,200,105,205,206,207,43,43,166,220,166,204,175,211,223,212,210,245,213,181,254,222,218,219,217,253,221,175,180,173,177,61,190,182,167,247,184,176,168,183,185,179,178,166,160}; void usage() { - fprintf(stderr,"Usage >> fapg [-b|--backslash] [-d|--debug] [-f|--format=m3u|pls|html] [-g|--genre=#:#:...] [-n|--nohardlink] [-o|--output=/path/to/file.m3u] [-p|--prefix=/the/prefix] [-r|--recursive] [-w|--windows] [-x|--exclude=#:#:...] /path/to/mp3/dir1 [/path/to/mp3/dir2 ...]\n"); + fprintf(stderr,"Usage >> fapg [-b|--backslash] [-d|--debug] [-f|--format=m3u|pls|html|rss] [-g|--genre=#:#:...] [-n|--nohardlink] [-o|--output=/path/to/file.m3u] [-p|--prefix=/the/prefix] [-r|--recursive] [-w|--windows] [-x|--exclude=#:#:...] /path/to/mp3/dir1 [/path/to/mp3/dir2 ...]\n"); exit(1); } +const char*reflink(const char*title) +{ + int i=0; + static char *buffer; + buffer=malloc(strlen(title)+strlen(referal)+2); + strcpy(buffer,referal); + strcat(buffer,title); + for(i=strlen(referal);i> parsing directory : %s\n",path); - if ((n=scandir(path,&namelist,0,alphasort))<0) { fprintf(stderr,"Warning >> can't open directory : %s\n",path); return; } - for (i=0;id_name); - if (stat(newpath,&infos)!=0) { fprintf(stderr,"Warning >> can't stat file : %s\n",newpath); continue; } - if (recursive && S_ISDIR(infos.st_mode) && strcmp(namelist[i]->d_name,".")!=0 && strcmp(namelist[i]->d_name,"..")!=0) parse_directory(newpath); - /* hlink_check() might be applied more selective ... avoidhlink is only a simple prereq */ - if (S_ISREG(infos.st_mode) && ! ( avoidhlinked && hlink_check(&infos) ) ) - { - char ext[5]; - int j; - for (j=0;j<5;j++) ext[j]=tolower(namelist[i]->d_name[strlen(namelist[i]->d_name)-4+j]); - artist[0]='\0'; - title[0]='\0'; - duration=-2; - if (strcmp(".mp2",ext)==0) { duration=-1; parse_mp3(newpath); } - if (strcmp(".mp3",ext)==0) { duration=-1; parse_mp3(newpath); } - if (strcmp(".mpc",ext)==0) { duration=-1; parse_mpc(newpath); } - if (strcmp(".mp+",ext)==0) { duration=-1; parse_mpc(newpath); } - if (strcmp(".ogg",ext)==0) { duration=-1; parse_ogg(newpath); } - if (strcmp(".wav",ext)==0) { duration=-1; /* parse_wav(newpath); */ } + for (j=0;j<5;j++) ext[j]=tolower(newpath[strlen(newpath)-4+j]); + artist[0]='\0'; + title[0]='\0'; + duration=-2; + if (strcmp(".mp2",ext)==0) { duration=-1; parse_mp3(newpath); } + if (strcmp(".mp3",ext)==0) { duration=-1; parse_mp3(newpath); } + if (strcmp(".mpc",ext)==0) { duration=-1; parse_mpc(newpath); } + if (strcmp(".mp+",ext)==0) { duration=-1; parse_mpc(newpath); } + if (strcmp(".ogg",ext)==0) { duration=-1; parse_ogg(newpath); } + if (strcmp(".wav",ext)==0) { duration=-1; /* parse_wav(newpath); */ } - if (duration!=-2 && genrelist[(int)genre]) /* is it an audio file ? */ + if (duration!=-2 && genrelist[genre]) /* is it an audio file ? */ { counter++; switch (format) @@ -631,8 +651,83 @@ void parse_directory(char *path) if (duration==-1) printf("?"); else printf("%d:%s%d",duration/60,duration%60<10?"0":"",duration%60); printf("%s",eol); break; + case 3: + if (duration!=-1) + { time_t zeit; + time(&zeit); + char timebuffer[256]; + strftime(timebuffer,255, "%a %d %b %Y %T %Z", localtime(&zeit) ); /* ctime() had a trailing CR */ + printf("\t%s",eol); + if (strlen(artist)==0 && strlen(title)==0) + { + /* find a better solution for this */ + printf("\t\t%s%s\t\t%s%s",newpath,eol, newpath,eol ); + } + else printf("\t\t%s%s\t\t%s%s",artist,eol, title,eol ); + /* you might want to add more into description --> look for a smart, not a fast program */ + printf("\t\t%s
%s
Direct Link to Audiofile
]]>
%s",eol); +#if 1 + printf("\t\t%s%s",reflink(title),eol); +#endif + printf("\t\t%s%s",timebuffer,eol); + printf("\t\t%s\t\t",duration, eol); + print_path(); + printf("%s",eol ); + printf("\t\t%d:%d:%d%s",duration/3600,(duration/60)%60,duration%60,eol); + printf("\t\t%s%s", artist, eol); + printf("\t
%s",eol ); + } + break; } } +} + +void parse_directory(unsigned char *path) +{ + int i,n; + struct dirent **namelist; + unsigned char newpath[PATH_MAX]; + struct stat infos; + + if (debug) + fprintf(stderr,"Debug >> parsing directory : %s\n",path); + if (stat(path,&infos)!=0) + { + fprintf(stderr,"Warning >> can't stat entry : %s\n",path); + return; + } + /* check if it is a filename */ + if (S_ISREG(infos.st_mode) || S_ISLNK(infos.st_mode)) + { + parse_file(path); + return; + } + /* must be a directory - or something unusable like pipe, socket, etc */ + if ((n=scandir(path,&namelist,0,alphasort))<0) + { + fprintf(stderr,"Warning >> can't open directory : %s\n",path); + return; + } + for (i=0;id_name); + + if (stat(newpath,&infos)!=0) + { + fprintf(stderr,"Warning >> can't stat entry : %s\n",newpath); + continue; + } + if (recursive && S_ISDIR(infos.st_mode) + && strcmp(namelist[i]->d_name,".")!=0 + && strcmp(namelist[i]->d_name,"..")!=0) parse_directory(newpath); + /* hlink_check() might be applied more selective ... avoidhlink is only a simple prereq */ + if (S_ISREG(infos.st_mode) && ! ( avoidhlinked && hlink_check(&infos) ) ) + { + parse_file(newpath); } free(namelist[i]); } @@ -652,12 +747,25 @@ int main(int argc,char **argv) printf("[playlist]%s",eol); break; case 2: - printf("%s%s%s%s%sPlaylist generated by FAPG 0.33%s%s%s%s%s%s%s

Playlist

%s%s%s%s",eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol); + printf("%s%s%s%s%sPlaylist generated by FAPG " VERSION "%s%s%s%s%s%s%s

Playlist

%s%s
EntryArtistTitleLength
%s%s",eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol,eol); + break; + case 3: + { time_t zeit; + time(&zeit); + char timebuffer[256]; + strftime(timebuffer,255, "%a %d %b %Y %T %Z", localtime(&zeit) ); + printf("%s%s%s %s\t%s - %s%s\tDirectory Tree %s%s\t%s%s\t%s\t%s%s\tFAPG " VERSION "%s\t%s\t\t%s/podcast.jpg%s\t\tServer Logo%s\t\t%s%s\t\tFeed provided by FAPG. Click to visit.%s\t%s\t%s\t\tAdmin %s%s\t\tpodcast@%s%s\t%s\tVarious%s\tDirectory Tree %s%s\t%s%s\tunknown%s\t%s%s\tNo%s\t1800%s",eol,eol,eol,eol,hostname,dir,eol,prefix,eol,base,eol,prefix,eol,timebuffer,eol,eol,eol,base,eol,eol,base,eol,eol,eol,eol,base,eol,hostname,eol,eol,eol,dir,eol,getenv("LOGNAME"),eol,eol,getenv("LANG"),eol,eol,eol); + } break; } for (;optind%s%s

Playlist generated by FAPG 0.33

%s%s%s%s",eol,eol,eol,eol,eol,eol); + printf("
EntryArtistTitleLength
%s%s

Playlist generated by FAPG " VERSION "

%s%s%s%s",eol,eol,eol,eol,eol,eol); + break; + case 3: + printf(" %s%s",eol,eol); break; } if (genrelist) free(genrelist); -- 2.20.1