X-Git-Url: http://royale.zerezo.com/git/?p=FAPG;a=blobdiff_plain;f=fapg.c;h=e627ea5294aa648c02264871c77043ce0ee1b07e;hp=e75235ed9bca7c2ba7cece1fab4dfe73b5208fe4;hb=421f874ec03fa08a659b5b4314411f24f1d6460b;hpb=eb987a9f4940f5143602e2ef7138550d0263ae40 diff --git a/fapg.c b/fapg.c index e75235e..e627ea5 100644 --- a/fapg.c +++ b/fapg.c @@ -1,6 +1,8 @@ /* - * FAPG version 0.30 - * + * 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,8 @@ #include #include #include +#include +#include #include "genres.h" #define MP3_BASE 1024 @@ -43,10 +47,15 @@ #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; 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; @@ -65,19 +74,38 @@ unsigned char unix2dos[256]={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,2 void usage() { - fprintf(stderr,"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 ...]\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> unable to open output file : %s\n",optarg); exit(2); } @@ -123,6 +155,12 @@ void parse_options(int argc,char **argv) case 'p': prefix=malloc(strlen(optarg)+1); strcpy(prefix,optarg); + base=malloc(strlen(prefix)+1); + strcpy(base,prefix); + dir=strchr(base,'/'); + if( (dir!=NULL) && (dir[1]=='/') ) dir=strchr(dir+2,'/'); + if (dir!=NULL) *dir++=0; else dir=""; + /* if prefix is a weblink, base is the baselink, dir is the path */ break; case 'r': recursive=1; @@ -154,6 +192,7 @@ void parse_options(int argc,char **argv) usage(); } } + /* hostname = getenv("HOSTNAME"); */ if (genrelist==NULL) { genrelist=calloc(257,sizeof(char)); @@ -473,13 +512,75 @@ void parse_mpc(unsigned char *file) fclose(fic); } -void parse_directory(unsigned char *path) +#define FSN 32 +#define MAXINO (1<<24) +#define INOTYP unsigned long +#define regbit_qry(x,y) ( x[( (y) / sizeof(INOTYP) )] & 1<<( (y) % sizeof(INOTYP) ) ) +#define regbit_set(x,y) ( x[( (y) / sizeof(INOTYP) )] |= 1<<( (y) % sizeof(INOTYP) ) ) + +int hlink_check(struct stat*info) +{ + /* + * for speed this subroutine should only be called + * - if the file has more than one hardlink + * - if the file is a resolved softlink + */ + /* the persistent variables */ + static INOTYP *list[FSN]; + static dev_t name[FSN]; + /* some temporary variables */ + int fsn, is_registered=0; + + /* assertions - in case parameters are lowered for less memory usage */ + assert(fsnst_ino)/sizeof(INOTYP)st_dev)) && (name[fsn]!=0) ; fsn++); + + /* if file system is not registered yet, do it and leave */ + if( name[fsn] == 0 ) + { + name[fsn] = (info->st_dev); + /* provide space for the bitmap that maps the inodes of this file system */ + list[fsn] = (INOTYP*)calloc(MAXINO,sizeof(INOTYP)); + /* no comparison is needed in empty lists ... return */ + if(debug) fprintf(stderr, "Debug >> Linked >> Init List %04x @mem %04lx\n", (int)name[fsn], (long)&list[fsn] ); + } else + { + /* this looks more complicated than it really is */ + /* the idea is very simple: + * provide a bitmap that maps all inodes of a file system + * to mark all files that have already been visited. + * If it is already visited, do not add it to the playlist + */ + /* + * The difficulty is as follows: + * struct inode_bitmap { char registered:1; } bitmap[1<st_ino) ) ) is_registered=1; + else regbit_set( list[fsn], (info->st_ino) ); + /* + * the debug expression is more complicated then the working stuff + */ + if(debug) + fprintf(stderr, "Debug >> Linked >> DEV %04x INO %06x => " + "list[%02x][%04x] = %04x & %04x --> %s registered\n", + (int)info->st_dev, (int)info->st_ino, fsn, (int)((info->st_ino)/sizeof(INOTYP)), + (int)list[fsn][(info->st_ino)/sizeof(INOTYP)], + 1<<((info->st_ino)%sizeof(INOTYP)), is_registered?"Already":"Not" ); + } + return is_registered; +} + + +void parse_file(unsigned char *newpath) { - int i,n; - struct dirent **namelist; - unsigned char newpath[PATH_MAX]; unsigned char *c; - struct stat infos; + unsigned char ext[5]; + int j; void print_faketitle() { @@ -494,31 +595,30 @@ void parse_directory(unsigned char *path) void print_path() { + char last=0; printf(prefix); - for (c=newpath+skip;*c!='\0';c++) if (*c=='/') putchar(separator); else if (windows) putchar(unix2dos[*c]); else putchar(*c); + c=newpath+skip; + /* remove leading "./" when parsing current directory */ + if (*c=='.' && *(c+1)=='/') { c+=2; last='/'; } + for (;*c!='\0';c++) + { + /* remove double "//" when parsing a directory ending with a "/" */ + if (last=='/' && *c=='/') continue; + last=*c; + if (*c=='/') putchar(separator); else if (windows) putchar(unix2dos[*c]); else putchar(*c); + } } - if (debug) fprintf(stderr,"Debug >> 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); - if (S_ISREG(infos.st_mode)) - { - unsigned 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[genre]) /* is it an audio file ? */ { @@ -551,8 +651,83 @@ void parse_directory(unsigned 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]); } @@ -572,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.30%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.30

%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);