-/*
- * FAPG
- */
-#define VERSION "0.35"
/*
* FAPG means Fast Audio Playlist Generator.
* It is a tool to generate list of audio files (Wav, MP3, Ogg, etc)
#include <time.h>
#include <assert.h>
#include "genres.h"
+#ifdef HAVE_LIBURIPARSER
+# include <uriparser/Uri.h>
+#endif
#define MP3_BASE 1024
#define OGG_BASE 1024*10
-#define MAX 1024*200 /* 200ko for ID3 with JPEG images in it */
+#define MAX 1024*250 /* 250ko for ID3 with JPEG images in it */
+#define MAX_ITEM 1024
+
+#define FORMAT_M3U 0 /* "0" is not a good choice for debugging, but OK for a default */
+#define FORMAT_PLS 1
+#define FORMAT_HTML 2
+#define FORMAT_RSS 3
+#define FORMAT_PLP 4
+#define FORMAT_UMS 5
+#ifdef HAVE_LIBURIPARSER
+# define FORMAT_XSPF 6
+#endif
int debug = 0;
-int format = 0; /* 0 = m3u ; 1 = pls ; 2 = html ; 3 = rss */
+int format = FORMAT_M3U;
char *genrelist = NULL;
unsigned char *prefix = "";
unsigned char *base = "";
// unsigned char *referal="/usr/local/bin/fapg-rss.sh";
unsigned char *referal = NULL;
//int windows=0;
+int fromstdin = 0;
int recursive = 0;
int avoidhlinked = 0;
int separator = '/';
int counter = 0;
-unsigned char artist[1024];
-unsigned char title[1024];
-unsigned char genrebuf[1024];
+unsigned char artist[MAX_ITEM];
+unsigned char title[MAX_ITEM];
+unsigned char genrebuf[MAX_ITEM];
unsigned char genre = 0;
int duration;
#define MP2ENC 1
#define MPPENC 4
#define OGGENC 5
#define WAVENC 6
+#define WMAENC 7
char *magic[] = { NULL,
"audio/mpeg", "audio/mpeg",
"audio/mpeg", "audio/mpeg",
"audio/ogg-vorbis", "audio/x-wav",
+ "audio/x-ms-wma",
NULL
};
void usage()
{
+#ifdef HAVE_LIBURIPARSER
+# define FAPG_FORMATS "m3u|pls|xspf|html|rss|pla|txx"
+#else
+# define FAPG_FORMATS "m3u|pls|html|rss|pla|txx"
+#endif
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] [-c|--command=<intern|....>] [-x|--exclude=#:#:...] /path/to/mp3/dir1 [/path/to/mp3/dir2 ...]\n");
+ "Usage >> fapg [-b|--backslash] [-d|--debug] [-f|--format=" FAPG_FORMATS "] [-g|--genre=#:#:...] [-n|--nohardlink] [-o|--output=/path/to/file.m3u] [-p|--prefix=/the/prefix] [-r|--recursive] [-w|--windows] [-c|--command=<intern|...>] [-x|--exclude=#:#:...] [-s|--stdin] /path/to/mp3/dir1 [/path/to/mp3/dir2 ...]\n");
+#undef FAPG_FORMATS
exit(1);
}
#define mywebputchar(x) { fputs(iso2web[(unsigned char)winorunix[(unsigned char)x]], stdout); }
#define myputchar(x) { putchar(basemap[(unsigned char)winorunix[(unsigned char)x]]); }
+/* #define myplaputchar(x) { putchar(basemap[(unsigned char)winorunix[(unsigned char)x]]);putchar('\0');} */
+void myplaputchar(const char x)
+{
+ putchar(basemap[(unsigned char)winorunix[(unsigned char)x]]);
+ putchar('\0');
+}
void mywebputstr(const char *c)
{
}
}
+void utf16toutf8(char *c,int n)
+{
+ /* check whether the we need to convert UTF-16 to UTF-8 strings */
+ if ( ( c[0] != '\377' ) || ( c[1] != '\376' ) ) { return; }
+ /* only continue here, if the first 2 letters are 0xfffe *
+ * c references an UTF-16 input, where latin letters are *
+ * separated by zero bytes, which we need to eliminate */
+ int i=0; --n;
+ for(int j=2; (j<n) && (j<MAX_ITEM); j++ ) {
+ if( isprint(c[j]) ) { /* this is not perfect ! */
+ c[i++]=c[j];
+ } } c[i+1]=c[i]='\0';
+ /* the index i follows the zero-terminated "string" *
+ * now the read buffer is modified, not the file */
+ return;
+}
+
+void myplaputstr(const char *c)
+{
+ while(*c != 0) {
+ if(*c == '/')
+ myplaputchar('\\'); /* translate slash to backslash */
+ else
+ myplaputchar(*c);
+ c++;
+ /* remove multiple slashes "//" when parsing a directory ending with a "/" */
+ while(*c == '/' && c[1] == '/')
+ c++;
+ }
+}
+
void myputstr(const char *c)
{
while(*c != 0) {
- myputchar(*c);
+ if(*c == '/')
+ putchar(separator);
+ else
+ myputchar(*c);
c++;
/* remove multiple slashes "//" when parsing a directory ending with a "/" */
while(*c == '/' && c[1] == '/')
}
}
+void txxputheader(const char *c)
+{
+ int cnt = 0;
+
+ while(*c != 0) {
+ myputchar(*c);
+ cnt++;
+ c++;
+ }
+
+ while(cnt < 512) {
+ putchar('\0');
+ cnt++;
+ }
+}
+
+void txxputnameoffset(const char *c)
+{
+ int pos = 0;
+ int cnt = 0;
+ char b;
+ unsigned char *prefx;
+
+ prefx = prefix;
+
+ if(*prefx != 0) {
+ while(*prefx != 0) {
+ if(*prefx == '/') {
+ pos = cnt;
+ }
+ cnt++;
+ prefx++;
+ }
+
+ cnt--; // skip the leading dot of the filepath
+ }
+
+ while(*c != 0) {
+ if(*c == '/') {
+ pos = cnt;
+ }
+ cnt++;
+ c++;
+ }
+
+ pos += 2;
+
+ b = (pos & 0xFF00) >> 8;
+ putchar(b);
+ b = (pos & 0x00FF);
+ putchar(b);
+}
+
+void txxputstr(const char *c)
+{
+ int cnt = 0;
+ int pos;
+ unsigned char *prefx;
+
+ txxputnameoffset(c);
+
+ prefx = prefix;
+ fprintf(stderr, "prefix: '%s'\n", prefx);
+
+ if(*prefx != 0) {
+ while(*prefx != 0) {
+ myputchar('\0');
+ cnt++;
+
+ if(*prefx == '/')
+ putchar(separator);
+ else
+ myputchar(*prefx);
+ cnt++;
+
+ prefx++;
+ }
+
+ c++; // skip the leading dot
+ }
+
+ while(*c != 0) {
+ myputchar('\0');
+ cnt++;
+
+ if(*c == '/')
+ putchar(separator);
+ else
+ myputchar(*c);
+ cnt++;
+
+ c++;
+ }
+
+ while(cnt < 510) {
+ myputchar('\0');
+ cnt++;
+ }
+}
+
+void txxputcounter(int c)
+{
+ int b;
+
+ rewind(stdout);
+
+ b = (c & 0xFF000000) >> 24;
+ putchar(b);
+ b = (c & 0x00FF0000) >> 16;
+ putchar(b);
+ b = (c & 0x0000FF00) >> 8;
+ putchar(b);
+ b = (c & 0x000000FF);
+ putchar(b);
+}
+
+/* remove spaces at beginning and end of string */
+void trim(char *c)
+{
+ char *p;
+ /* remove spaces at beginning ... */
+ while(*c == ' ') {
+ p = c;
+ while(*p != '\0') {
+ *p = *(p + 1);
+ p++;
+ }
+ }
+ /* ... and end of string */
+ p = c + strlen(c);
+ while(--p > c && *p == ' ')
+ *p = '\0';
+}
+
void print_webpath(const char *path)
{
const char *c = path;
- printf(prefix); /* we must not modify this part */
+ printf("%s", prefix); /* we must not modify this part */
if(*c == '.' && c[1] == '/') { /* remove leading "./" when parsing current directory */
c += 2;
/* maybe there follow many slashes */
void print_path(const char *path)
{
const char *c = path;
- printf(prefix);
+ printf("%s", prefix);
/* skip leading "./" when parsing current directory */
if(*c == '.' && *(c + 1) == '/') {
c += 2;
pipe = popen(command, "r");
if(pipe == NULL) {
fprintf(stderr, "Warning >> can't open pipe >%s< !\n", command);
- free(command);
return;
}
fgets(buffer, 1020, pipe);
void parse_options(int argc, char **argv)
{
- static char const short_options[] = "c:bdf:g:lo:np:ruwx:";
+ static char const short_options[] = "bc:df:g:lo:np:rsuwx:";
static struct option long_options[] = {
{"backslash", no_argument, NULL, 'b'},
- {"command", required_argument, NULL, 'b'},
+ {"command", required_argument, NULL, 'c'},
{"debug", no_argument, NULL, 'd'},
{"format", required_argument, NULL, 'f'},
{"genre", required_argument, NULL, 'g'},
{"output", required_argument, NULL, 'o'},
{"prefix", required_argument, NULL, 'p'},
{"recursive", no_argument, NULL, 'r'},
+ {"stdin", no_argument, NULL, 's'},
{"windows", no_argument, NULL, 'w'},
- {"exclude", required_argument, NULL, 'x'}
+ {"exclude", required_argument, NULL, 'x'},
+ {NULL, 0, NULL, 0}
};
int c;
int option_index = 0;
break;
case 'f':
if(strcmp(optarg, "m3u") == 0)
- format = 0;
+ format = FORMAT_M3U;
else if(strcmp(optarg, "pls") == 0)
- format = 1;
+ format = FORMAT_PLS;
else if(strcmp(optarg, "html") == 0)
- format = 2;
+ format = FORMAT_HTML;
else if(strcmp(optarg, "rss") == 0)
- format = 3;
+ format = FORMAT_RSS;
+ else if(strcmp(optarg, "pla") == 0)
+ format = FORMAT_PLP;
+ else if(strcmp(optarg, "txx") == 0)
+ format = FORMAT_UMS;
+#ifdef HAVE_LIBURIPARSER
+ else if(strcmp(optarg, "xspf") == 0)
+ format = FORMAT_XSPF;
+#endif
else
usage();
break;
}
}
break;
+ case 's':
+ fromstdin = 1;
+ break;
default:
usage();
}
fprintf(stderr, "Debug >> parsing mp3 : %s\n", file);
/* read header */
- if((fic = fopen(file, "r")) == NULL) {
+ if((fic = fopen(file, "rb")) == NULL) {
fprintf(stderr, "Warning >> can't open file : %s\n", file);
return;
}
if(*c == 0)
break;
if(strncmp(c, "TT2", 3) == 0) {
+ utf16toutf8(c+7,size);
strncpy(title, c + 7, size - 1);
title[size - 1] = '\0';
}
if(strncmp(c, "TP1", 3) == 0) {
+ utf16toutf8(c+7,size);
strncpy(artist, c + 7, size - 1);
artist[size - 1] = '\0';
}
if(*c == 0)
break;
if(strncmp(c, "TIT2", 4) == 0) {
+ utf16toutf8(c+11,size);
strncpy(title, c + 11, size - 1);
title[size - 1] = '\0';
}
if(strncmp(c, "TPE1", 4) == 0) {
+ utf16toutf8(c+11,size);
strncpy(artist, c + 11, size - 1);
artist[size - 1] = '\0';
}
/* genre=atoi(&genrebuf[1]); */
genre = atoi(c + 12);
}
+ if(strncmp(c, "TLEN", 4) == 0) {
+ duration = atoi(c + 11) / 1000;
+ }
c += size + 10;
}
}
lus = fread(buffer, 1, OGG_BASE, fic);
/* try Ogg */
- if(buffer[0] != 'O' && buffer[1] != 'g' && buffer[2] != 'g') {
+ if(strncmp(buffer, "Ogg", 3) != 0) {
fprintf(stderr, "Warning >> not a Ogg header : %s\n", file);
return;
}
title[size - 6] = '\0';
c += size;
}
+ if(strncasecmp(c, "ALBUM ARTIST=", 13) == 0) {
+ // ignore tag
+ size =
+ *(c - 4) + (*(c - 3) << 8) + (*(c - 2) << 16) +
+ (*(c - 1) << 24);
+ c += size;
+ }
if(strncasecmp(c, "ARTIST=", 7) == 0) {
size =
*(c - 4) + (*(c - 3) << 8) + (*(c - 2) << 16) +
fclose(fic);
}
-
void parse_mpc(unsigned char *file)
{
FILE *fic;
lus = fread(buffer, 1, 12, fic);
/* try Musepack */
- if(buffer[0] != 'M' && buffer[1] != 'P' && buffer[2] != '+') {
+ if (strncmp(buffer, "MP+", 3) != 0) {
fprintf(stderr, "Warning >> not a Musepack header : %s\n", file);
return;
}
return is_registered;
}
+#ifdef HAVE_LIBURIPARSER
+char * relative_uri_malloc(const char * unixFilename, const char * baseDir)
+{
+ char * absSourceFile;
+ size_t absSourceLen;
+ char * sourceUriString;
+ char * baseUriString;
+ UriParserStateA state;
+ UriUriA sourceUri;
+ UriUriA baseUri;
+ UriUriA relativeUri;
+ int charsRequired;
+ char * output;
+
+ /* checks */
+ if ((unixFilename == NULL) || (baseDir == NULL)) {
+ return NULL;
+ }
+
+ /* base URI */
+ baseUriString = malloc((7 + 3 * strlen(baseDir) + 1) * sizeof(char));
+ if (baseUriString == NULL) {
+ return NULL;
+ }
+ if (uriUnixFilenameToUriStringA(baseDir, baseUriString) != 0) {
+ free(baseUriString);
+ return NULL;
+ }
+ state.uri = &baseUri;
+ if (uriParseUriA(&state, baseUriString) != 0) {
+ free(baseUriString);
+ uriFreeUriMembersA(&baseUri);
+ return NULL;
+ }
+
+ /* source URI */
+ if (unixFilename[0] != '/') {
+ const int baseDirLen = strlen(baseDir);
+ const int sourceFileLen = strlen(unixFilename);
+ absSourceLen = baseDirLen + sourceFileLen;
+ absSourceFile = malloc((absSourceLen + 1) * sizeof(char));
+ sprintf(absSourceFile, "%s%s", baseDir, unixFilename);
+ } else {
+ absSourceLen = strlen(unixFilename);
+ absSourceFile = (char *)unixFilename;
+ }
+ sourceUriString = malloc((7 + 3 * absSourceLen + 1) * sizeof(char));
+ if (sourceUriString == NULL) {
+ free(baseUriString);
+ if (unixFilename[0] != '/') {
+ free(absSourceFile);
+ }
+ uriFreeUriMembersA(&baseUri);
+ return NULL;
+ }
+ if (uriUnixFilenameToUriStringA(absSourceFile, sourceUriString) != 0) {
+ free(baseUriString);
+ free(sourceUriString);
+ if (unixFilename[0] != '/') {
+ free(absSourceFile);
+ }
+ uriFreeUriMembersA(&baseUri);
+ return NULL;
+ }
+ state.uri = &sourceUri;
+ if (uriParseUriA(&state, sourceUriString) != 0) {
+ free(baseUriString);
+ free(sourceUriString);
+ uriFreeUriMembersA(&baseUri);
+ uriFreeUriMembersA(&sourceUri);
+ return NULL;
+ }
+ if (uriNormalizeSyntaxA(&sourceUri) != 0) {
+ free(baseUriString);
+ free(sourceUriString);
+ if (unixFilename[0] != '/') {
+ free(absSourceFile);
+ }
+ uriFreeUriMembersA(&baseUri);
+ uriFreeUriMembersA(&sourceUri);
+ return NULL;
+ }
+
+ /* make relative (or keep absolute if necessary) */
+ if (uriRemoveBaseUriA(&relativeUri, &sourceUri, &baseUri, URI_FALSE) != 0) {
+ free(baseUriString);
+ free(sourceUriString);
+ if (unixFilename[0] != '/') {
+ free(absSourceFile);
+ }
+ uriFreeUriMembersA(&baseUri);
+ uriFreeUriMembersA(&sourceUri);
+ uriFreeUriMembersA(&relativeUri);
+ return NULL;
+ }
+
+ /* back to string */
+ if (uriToStringCharsRequiredA(&relativeUri, &charsRequired) != 0) {
+ free(baseUriString);
+ free(sourceUriString);
+ if (unixFilename[0] != '/') {
+ free(absSourceFile);
+ }
+ uriFreeUriMembersA(&baseUri);
+ uriFreeUriMembersA(&sourceUri);
+ uriFreeUriMembersA(&relativeUri);
+ return NULL;
+ }
+ output = malloc((charsRequired + 1) * sizeof(char));
+ if (uriToStringA(output, &relativeUri, charsRequired + 1, NULL) != 0) {
+ free(baseUriString);
+ free(sourceUriString);
+ if (unixFilename[0] != '/') {
+ free(absSourceFile);
+ }
+ free(output);
+ uriFreeUriMembersA(&baseUri);
+ uriFreeUriMembersA(&sourceUri);
+ uriFreeUriMembersA(&relativeUri);
+ return NULL;
+ }
+
+ free(baseUriString);
+ free(sourceUriString);
+ if (unixFilename[0] != '/') {
+ free(absSourceFile);
+ }
+ uriFreeUriMembersA(&baseUri);
+ uriFreeUriMembersA(&sourceUri);
+ uriFreeUriMembersA(&relativeUri);
+
+ return output;
+}
+
+char * xml_escape_malloc(const char * input)
+{
+ const char * read = input;
+ char * output;
+ char * write;
+
+ if (input == NULL) {
+ return NULL;
+ }
+
+ output = malloc((6 * strlen(input) + 1) * sizeof(char));
+ if (output == NULL) {
+ return NULL;
+ }
+ write = output;
+
+ for (;;) {
+ if (*read == '\0') {
+ *write = '\0';
+ return output;
+ }
+
+ switch ((unsigned char)*read) {
+ case '&':
+ strcpy(write, "&");
+ write += 5;
+ break;
+ case '<':
+ strcpy(write, "<");
+ write += 4;
+ break;
+ case '>':
+ strcpy(write, ">");
+ write += 4;
+ break;
+ case '\'':
+ strcpy(write, "'");
+ write += 6;
+ break;
+ case '"':
+ strcpy(write, """);
+ write += 6;
+ break;
+ default:
+ *(write++) = *read;
+ }
+ read++;
+ }
+}
+#endif
-void parse_file(unsigned char *newpath)
+void parse_file(unsigned char *newpath, unsigned char * original_path)
{
unsigned char ext[5];
int j, encoding = 0;
encoding = OGGENC;
}
if(strcmp(".wav", ext) == 0) {
- duration = -1; /* parse_wav(newpath); */
+ duration = -1;
+ /* parse_wav(newpath); */
encoding = WAVENC;
}
- /* faketitle() */
+ if(strcmp(".wma", ext) == 0) {
+ duration = -1;
+ /* parse_wma(newpath); */
+ encoding = WMAENC;
+ }
+ /* guesstitle() */
if((strlen(artist) == 0) && (strlen(title) == 0)) {
// there are no tag infos read
// use file name to state substitute it
char *c = strrchr(newpath, separator);
+ if(c == NULL)
+ c = newpath;
strcpy(artist, ++c);
// arbitrarily use the first '-'
// to separate artist and title
*c = ' ';
for(c = title; (c = strchr(c, '_')) != NULL; c++)
*c = ' ';
+ // trim spaces
+ trim(artist);
+ trim(title);
}
- /* faketitle() end */
+ /* guesstitle() end */
if(duration != -2 && genrelist[genre]) { /* is it an audio file ? */
counter++;
switch (format) {
- case 0:
- if(duration != -1) {
- printf("#EXTINF:%d,%s - %s%s", duration, artist, title,
- eol);
- }
+ case FORMAT_M3U:
+ printf("#EXTINF:%d,", duration);
+ if(strlen(artist) != 0)
+ printf("%s - ", artist);
+ printf("%s%s", title, eol);
print_path(newpath);
printf("%s", eol);
break;
- case 1:
+ case FORMAT_PLS:
printf("File%d=", counter);
print_path(newpath);
- printf("%sTitle%d=%s - %s%s", eol, counter, artist, title,
- eol);
+ printf("%sTitle%d=", eol, counter);
+ if(strlen(artist) != 0)
+ printf("%s - ", artist);
+ printf("%s%s", title, eol);
if(duration != -1)
printf("Length%d=%d%s", counter, duration, eol);
break;
- case 2:
+ case FORMAT_HTML:
printf("<tr><td>%d</td><td>%s</td><td>%s</td><td>", counter,
artist, title);
if(duration == -1)
printf("%d:%s%d</td></tr>%s", duration / 60,
duration % 60 < 10 ? "0" : "", duration % 60, eol);
break;
- case 3:
+ case FORMAT_RSS:
if(duration != -1) {
struct stat infos;
char timebuffer[256];
printf("\t</item>%s", eol);
}
break;
+ case FORMAT_PLP:
+ myplaputstr("HARP, ");
+ myplaputstr(newpath);
+ myplaputstr(eol);
+ break;
+ case FORMAT_UMS:
+ txxputstr(newpath);
+ break;
+#ifdef HAVE_LIBURIPARSER
+ case FORMAT_XSPF:
+ printf("<track>\n");
+ if (strlen(title) > 0) {
+ char * escaped_title = xml_escape_malloc(title);
+ if (escaped_title != NULL) {
+ printf(" <title>%s</title>\n", escaped_title);
+ free(escaped_title);
+ }
+ }
+ if (strlen(artist) > 0) {
+ char * escaped_artist = xml_escape_malloc(artist);
+ if (escaped_artist != NULL) {
+ printf(" <creator>%s</creator>\n", escaped_artist);
+ free(escaped_artist);
+ }
+ }
+ if (duration > 0) {
+ printf(" <duration>%d</duration>\n", duration);
+ }
+ {
+ char * relative_location;
+ char * escaped_location;
+ relative_location = relative_uri_malloc(newpath, original_path);
+ if (relative_location != NULL) {
+ escaped_location = xml_escape_malloc(relative_location);
+ if (escaped_location != NULL) {
+ printf(" <location>%s</location>\n", escaped_location);
+ free(escaped_location);
+ }
+ free(relative_location);
+ }
+ }
+ printf("</track>\n");
+ break;
+#endif
}
}
}
-void parse_directory(unsigned char *path)
+void parse_directory(unsigned char *path, unsigned char * original_path)
{
int i, n;
struct dirent **namelist;
}
/* check if it is a filename */
if(S_ISREG(infos.st_mode) || S_ISLNK(infos.st_mode)) {
- parse_file(path);
+ parse_file(path, original_path);
return;
}
/* must be a directory - or something unusable like pipe, socket, etc */
return;
}
for(i = 0; i < n; i++) {
- sprintf(newpath, "%s/%s", path, namelist[i]->d_name);
+ snprintf(newpath, PATH_MAX, "%s/%s", path, namelist[i]->d_name);
if(stat(newpath, &infos) != 0) {
fprintf(stderr, "Warning >> can't stat entry : %s\n", newpath);
if(recursive && S_ISDIR(infos.st_mode)
&& strcmp(namelist[i]->d_name, ".") != 0
&& strcmp(namelist[i]->d_name, "..") != 0)
- parse_directory(newpath);
+ parse_directory(newpath, original_path);
/* 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);
+ parse_file(newpath, original_path);
}
free(namelist[i]);
}
winorunix = one2one;
basemap = one2one;
parse_options(argc, argv);
- if(optind == argc)
+
+ if(optind == argc && !fromstdin)
usage();
+
+ /* print header */
switch (format) {
- case 0:
+ case FORMAT_M3U:
printf("#EXTM3U%s", eol);
break;
- case 1:
+ case FORMAT_PLS:
printf("[playlist]%s", eol);
break;
- case 2:
+ case FORMAT_HTML:
printf
("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">%s%s<html>%s%s<head>%s<title>Playlist generated by FAPG "
VERSION
eol, eol, eol, eol, eol, eol, eol, eol, eol, eol, eol, eol,
eol, eol, eol);
break;
- case 3:
+ case FORMAT_RSS:
{
time_t zeit;
char timebuffer[256];
basemap = noand;
}
break;
+ case FORMAT_PLP:
+ {
+ eol = "\r\n";
+ myplaputstr("PLP PLAYLIST\r\nVERSION 1.20\r\n\r\n");
+ }
+ break;
+ case FORMAT_UMS:
+ {
+ txxputheader(" iriver UMS PLA");
+ }
+ break;
+#ifdef HAVE_LIBURIPARSER
+ case FORMAT_XSPF:
+ printf("<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n"
+ "<!-- generator=\"FAPG " VERSION " -->\n"
+ "<playlist version=\"1\" xmlns=\"http://xspf.org/ns/0/\">\n"
+ "<trackList>\n");
+ break;
+#endif
}
- for(; optind < argc; optind++) {
- parse_directory(argv[optind]);
+
+ /* iterate through files */
+ {
+ const char * const pwd_source = getenv("PWD");
+ const int pwdlen = strlen(pwd_source);
+ char * const pwd = malloc((pwdlen + 1 + 1) * sizeof(char));
+ sprintf(pwd, "%s/", pwd_source);
+
+ if(fromstdin) {
+ unsigned char path[PATH_MAX];
+ int i;
+ while(fgets(path, PATH_MAX, stdin)) {
+ for(i = 0; i < PATH_MAX; i++)
+ if(path[i] == '\r' || path[i] == '\n')
+ path[i] = '\0';
+ if (i <= 0) {
+ continue;
+ }
+
+ /* strip trailing slash */
+ if (path[i - 1] == '/') {
+ path[i - 1] = '\0';
+ }
+
+ parse_directory(path, pwd);
+ }
+ } else
+ for(; optind < argc; optind++) {
+ /* strip trailing slash */
+ char * dup = strdup(argv[optind]);
+ const int len = strlen(dup);
+ if ((len > 0) && (dup[len - 1] == '/')) {
+ dup[len - 1] = '\0';
+ }
+
+ parse_directory(dup, pwd);
+ }
+
+ free(pwd);
}
+
+ /* print footer */
switch (format) {
- case 1:
+ case FORMAT_PLS:
printf("NumberOfEntries=%d%sVersion=2%s", counter, eol, eol);
break;
- case 2:
+ case FORMAT_HTML:
printf
("</table>%s%s<p>Playlist generated by <a href=\"http://royale.zerezo.com/fapg/\">FAPG "
VERSION "</a></p>%s%s</body>%s%s</html>", eol, eol, eol, eol,
eol, eol);
break;
- case 3:
+ case FORMAT_RSS:
printf(" </channel>%s</rss>%s", eol, eol);
break;
+ case FORMAT_UMS:
+ txxputcounter(counter);
+ break;
+#ifdef HAVE_LIBURIPARSER
+ case FORMAT_XSPF:
+ printf("</trackList>\n"
+ "</playlist>\n");
+ break;
+#endif
}
+
if(genrelist)
free(genrelist);
+
exit(0);
}
+