diff --git a/NEWS b/NEWS index 6391f04..e0d5a3e 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,8 @@ +1.0.21 - Released 00-MONTH-2011 +-------------------------------- +- Add the ability to change the root media container. +- Add WAV/RIFF INFO tag parsing support for the most common tags. + 1.0.20 - Released 09-June-2011 -------------------------------- - Fix a crash bug when scanning MPEG-TS files with odd packet sizes. diff --git a/minidlna.c b/minidlna.c index de01adb..1180074 100644 --- a/minidlna.c +++ b/minidlna.c @@ -376,6 +376,7 @@ init(int argc, char * * argv) runtime_vars.port = -1; runtime_vars.notify_interval = 895; /* seconds between SSDP announces */ + runtime_vars.root_container = NULL; /* read options file first since * command line arguments have final say */ @@ -559,6 +560,34 @@ init(int argc, char * * argv) if( (strcmp(ary_options[i].value, "yes") == 0) || atoi(ary_options[i].value) ) SETFLAG(DLNA_STRICT_MASK); break; + case ROOT_CONTAINER: + switch( ary_options[i].value[0] ) + { + case '.': + runtime_vars.root_container = NULL; + break; + case 'B': + case 'b': + runtime_vars.root_container = BROWSEDIR_ID; + break; + case 'M': + case 'm': + runtime_vars.root_container = MUSIC_ID; + break; + case 'V': + case 'v': + runtime_vars.root_container = VIDEO_ID; + break; + case 'P': + case 'p': + runtime_vars.root_container = IMAGE_ID; + break; + default: + fprintf(stderr, "Invalid root container! [%s]\n", + ary_options[i].value); + break; + } + break; default: fprintf(stderr, "Unknown option in file %s\n", optionsfile); diff --git a/minidlna.conf b/minidlna.conf index f44c350..9849f59 100644 --- a/minidlna.conf +++ b/minidlna.conf @@ -48,3 +48,13 @@ notify_interval=900 # in its XML description serial=12345678 model_number=1 + +# use different container as root of the tree +# possible values: +# + "." - use standard container (this is the default) +# + "B" - "Browse Directory" +# + "M" - "Music" +# + "V" - "Video" +# + "P" - "Pictures" +# if you specify "B" and client device is audio-only then "Music/Folders" will be used as root +#root_container=. diff --git a/minidlnatypes.h b/minidlnatypes.h index 539202d..2ca3f2b 100644 --- a/minidlnatypes.h +++ b/minidlnatypes.h @@ -42,6 +42,7 @@ struct lan_addr_s { struct runtime_vars_s { int port; /* HTTP Port */ int notify_interval; /* seconds between SSDP announces */ + char *root_container; /* root ObjectID (instead of "0") */ }; struct string_s { diff --git a/options.c b/options.c index cfca9ee..a283040 100644 --- a/options.c +++ b/options.c @@ -59,7 +59,8 @@ static const struct { { UPNPDBDIR, "db_dir" }, { UPNPLOGDIR, "log_dir" }, { ENABLE_TIVO, "enable_tivo" }, - { ENABLE_DLNA_STRICT, "strict_dlna" } + { ENABLE_DLNA_STRICT, "strict_dlna" }, + { ROOT_CONTAINER, "root_container" } }; int diff --git a/options.h b/options.h index 88a517a..b208542 100644 --- a/options.h +++ b/options.h @@ -52,7 +52,8 @@ enum upnpconfigoptions { UPNPDBDIR, /* base directory to store the database and album art cache */ UPNPLOGDIR, /* base directory to store the log file */ ENABLE_TIVO, /* enable support for streaming images and music to TiVo */ - ENABLE_DLNA_STRICT /* strictly adhere to DLNA specs */ + ENABLE_DLNA_STRICT, /* strictly adhere to DLNA specs */ + ROOT_CONTAINER /* root ObjectID (instead of "0") */ }; /* readoptionsfile() diff --git a/upnphttp.h b/upnphttp.h index 4808c12..95711cb 100644 --- a/upnphttp.h +++ b/upnphttp.h @@ -115,6 +115,7 @@ struct upnphttp { #define FLAG_AUDIO_ONLY 0x08000000 #define FLAG_FREE_OBJECT_ID 0x00000001 +#define FLAG_ROOT_CONTAINER 0x00000002 /* New_upnphttp() */ struct upnphttp * diff --git a/upnpsoap.c b/upnpsoap.c index f3272be..d6b1d89 100644 --- a/upnpsoap.c +++ b/upnpsoap.c @@ -609,10 +609,11 @@ add_res(char *size, char *duration, char *bitrate, char *sampleFrequency, runtime_vars.port, detailID, ext); } -#define SELECT_COLUMNS "SELECT o.OBJECT_ID, o.PARENT_ID, o.REF_ID, o.DETAIL_ID, o.CLASS," \ - " d.SIZE, d.TITLE, d.DURATION, d.BITRATE, d.SAMPLERATE, d.ARTIST," \ - " d.ALBUM, d.GENRE, d.COMMENT, d.CHANNELS, d.TRACK, d.DATE, d.RESOLUTION," \ - " d.THUMBNAIL, d.CREATOR, d.DLNA_PN, d.MIME, d.ALBUM_ART, d.DISC " +#define COLUMNS "o.REF_ID, o.DETAIL_ID, o.CLASS," \ + " d.SIZE, d.TITLE, d.DURATION, d.BITRATE, d.SAMPLERATE, d.ARTIST," \ + " d.ALBUM, d.GENRE, d.COMMENT, d.CHANNELS, d.TRACK, d.DATE, d.RESOLUTION," \ + " d.THUMBNAIL, d.CREATOR, d.DLNA_PN, d.MIME, d.ALBUM_ART, d.DISC " +#define SELECT_COLUMNS "SELECT o.OBJECT_ID, o.PARENT_ID, " COLUMNS static int callback(void *args, int argc, char **argv, char **azColName) @@ -664,6 +665,9 @@ callback(void *args, int argc, char **argv, char **azColName) else strcpy(dlna_buf, "*"); + if( runtime_vars.root_container && strcmp(parent, runtime_vars.root_container) == 0 ) + parent = "0"; + if( strncmp(class, "item", 4) == 0 ) { /* We may need special handling for certain MIME types */ @@ -1029,19 +1033,31 @@ BrowseContentDirectory(struct upnphttp * h, const char * action) ObjectID, RequestedCount, StartingIndex, BrowseFlag, Filter, SortCriteria); - if( (args.flags & FLAG_AUDIO_ONLY) && (strcmp(ObjectID, "0") == 0) ) + if( strcmp(ObjectID, "0") == 0 ) { - ObjectID = sqlite3_mprintf("%s", MUSIC_ID); - args.flags |= FLAG_FREE_OBJECT_ID; + args.flags |= FLAG_ROOT_CONTAINER; + if( runtime_vars.root_container ) + { + if( (args.flags & FLAG_AUDIO_ONLY) && (strcmp(runtime_vars.root_container, BROWSEDIR_ID) == 0) ) + ObjectID = MUSIC_DIR_ID; + else + ObjectID = runtime_vars.root_container; + } + else + { + if( args.flags & FLAG_AUDIO_ONLY ) + ObjectID = MUSIC_ID; + } } if( strcmp(BrowseFlag+6, "Metadata") == 0 ) { args.requested = 1; - sql = sqlite3_mprintf( SELECT_COLUMNS + sql = sqlite3_mprintf("SELECT %s, " COLUMNS "from OBJECTS o left join DETAILS d on (d.ID = o.DETAIL_ID)" - " where OBJECT_ID = '%s';" - , ObjectID); + " where OBJECT_ID = '%s';", + (args.flags & FLAG_ROOT_CONTAINER) ? "0, -1" : "o.OBJECT_ID, o.PARENT_ID", + ObjectID); ret = sqlite3_exec(db, sql, callback, (void *) &args, &zErrMsg); totalMatches = args.returned; }