diff --git a/NEWS b/NEWS index 59de635..cbad7cb 100644 --- a/NEWS +++ b/NEWS @@ -4,6 +4,7 @@ - Switch to autoconf from our handcrafted genconfig.sh. - Add configuration option for UUID. - Add configuration option to specify the user to run as. +- Add support for limiting a media dir to multiple media types. 1.0.25 - Released 13-July-2012 -------------------------------- diff --git a/inotify.c b/inotify.c index 9a36df0..74a8fbd 100644 --- a/inotify.c +++ b/inotify.c @@ -290,7 +290,7 @@ inotify_insert_file(char * name, const char * path) char * id = NULL; int depth = 1; int ts; - enum media_types type = ALL_MEDIA; + media_types types = ALL_MEDIA; struct media_dir_s * media_path = media_dirs; struct stat st; @@ -305,12 +305,12 @@ inotify_insert_file(char * name, const char * path) { if( strncmp(path, media_path->path, strlen(media_path->path)) == 0 ) { - type = media_path->type; + types = media_path->types; break; } media_path = media_path->next; } - switch( type ) + switch( types ) { case ALL_MEDIA: if( !is_image(path) && @@ -319,16 +319,32 @@ inotify_insert_file(char * name, const char * path) !is_playlist(path) ) return -1; break; - case AUDIO_ONLY: + case TYPE_AUDIO: if( !is_audio(path) && !is_playlist(path) ) return -1; break; - case VIDEO_ONLY: + case TYPE_AUDIO|TYPE_VIDEO: + if( !is_audio(path) && + !is_video(path) && + !is_playlist(path) ) + break; + case TYPE_AUDIO|TYPE_IMAGES: + if( !is_image(path) && + !is_audio(path) && + !is_playlist(path) ) + return -1; + break; + case TYPE_VIDEO: if( !is_video(path) ) return -1; break; - case IMAGES_ONLY: + case TYPE_VIDEO|TYPE_IMAGES: + if( !is_image(path) && + !is_video(path) ) + return -1; + break; + case TYPE_IMAGES: if( !is_image(path) ) return -1; break; @@ -426,8 +442,8 @@ inotify_insert_directory(int fd, char *name, const char * path) char path_buf[PATH_MAX]; int wd; enum file_types type = TYPE_UNKNOWN; - enum media_types dir_type = ALL_MEDIA; - struct media_dir_s * media_path; + media_types dir_types = ALL_MEDIA; + struct media_dir_s* media_path; struct stat st; if( access(path, R_OK|X_OK) != 0 ) @@ -465,7 +481,7 @@ inotify_insert_directory(int fd, char *name, const char * path) { if( strncmp(path, media_path->path, strlen(media_path->path)) == 0 ) { - dir_type = media_path->type; + dir_types = media_path->types; break; } media_path = media_path->next; @@ -489,7 +505,7 @@ inotify_insert_directory(int fd, char *name, const char * path) case DT_REG: case DT_LNK: case DT_UNKNOWN: - type = resolve_unknown_type(path_buf, dir_type); + type = resolve_unknown_type(path_buf, dir_types); default: break; } diff --git a/minidlna.c b/minidlna.c index 01c8231..fc640ff 100644 --- a/minidlna.c +++ b/minidlna.c @@ -496,12 +496,13 @@ init(int argc, char * * argv) const char * optionsfile = "/etc/minidlna.conf"; char mac_str[13]; char *string, *word; - enum media_types type; char *path; char buf[PATH_MAX]; char ip_addr[INET_ADDRSTRLEN + 3] = {'\0'}; char log_str[75] = "general,artwork,database,inotify,scanner,metadata,http,ssdp,tivo=warn"; char *log_level = NULL; + struct media_dir_s *media_dir; + media_types types; uid_t uid = -1; /* first check if "-f" option is used */ @@ -598,30 +599,39 @@ init(int argc, char * * argv) strncpyt(friendly_name, ary_options[i].value, FRIENDLYNAME_MAX_LEN); break; case UPNPMEDIADIR: - type = ALL_MEDIA; + types = ALL_MEDIA; path = ary_options[i].value; - if( *path && (path[1] == ',') && (access(path, F_OK) != 0) ) + word = strchr(path, ','); + if( word && (access(path, F_OK) != 0) ) { - switch( *path ) + types = 0; + while( *path ) { - case 'A': - case 'a': - type = AUDIO_ONLY; - break; - case 'V': - case 'v': - type = VIDEO_ONLY; - break; - case 'P': - case 'p': - type = IMAGES_ONLY; - break; - default: - DPRINTF(E_FATAL, L_GENERAL, "Media directory entry not understood [%s]\n", - ary_options[i].value); - break; + if( *path == 'A' || *path == 'a' ) + { + types |= TYPE_AUDIO; + } + else if( *path == 'V' || *path == 'v' ) + { + types |= TYPE_VIDEO; + } + else if( *path == 'P' || *path == 'p' ) + { + types |= TYPE_IMAGES; + } + else if( *path == ',' ) + { + path++; + break; + } + else + { + DPRINTF(E_FATAL, L_GENERAL, "Media directory entry not understood [%s]\n", + ary_options[i].value); + break; + } + path++; } - path += 2; } path = realpath(path, buf); if( !path || access(path, F_OK) != 0 ) @@ -630,19 +640,19 @@ init(int argc, char * * argv) ary_options[i].value, strerror(errno)); break; } - struct media_dir_s * this_dir = calloc(1, sizeof(struct media_dir_s)); - this_dir->path = strdup(path); - this_dir->type = type; + media_dir = calloc(1, sizeof(struct media_dir_s)); + media_dir->path = strdup(path); + media_dir->types = types; if( !media_dirs ) { - media_dirs = this_dir; + media_dirs = media_dir; } else { struct media_dir_s * all_dirs = media_dirs; while( all_dirs->next ) all_dirs = all_dirs->next; - all_dirs->next = this_dir; + all_dirs->next = media_dir; } break; case UPNPALBUMART_NAMES: diff --git a/minidlna.conf b/minidlna.conf index 089f421..bfb71d5 100644 --- a/minidlna.conf +++ b/minidlna.conf @@ -8,12 +8,13 @@ port=8200 #user=jmaggard # set this to the directory you want scanned. -# * if have multiple directories, you can have multiple media_dir= lines -# * if you want to restrict a media_dir to a specific content type, you -# can prepend the type, followed by a comma, to the directory: +# * if you want multiple directories, you can have multiple media_dir= lines +# * if you want to restrict a media_dir to specific content types, you +# can prepend the types, followed by a comma, to the directory: # + "A" for audio (eg. media_dir=A,/home/jmaggard/Music) # + "V" for video (eg. media_dir=V,/home/jmaggard/Videos) # + "P" for images (eg. media_dir=P,/home/jmaggard/Pictures) +# + "PV" for pictures and video (eg. media_dir=AV,/home/jmaggard/digital_camera) media_dir=/opt # set this if you want to customize the name that shows up on your clients diff --git a/minidlnatypes.h b/minidlnatypes.h index 2ed17c2..4bc6833 100644 --- a/minidlnatypes.h +++ b/minidlnatypes.h @@ -53,13 +53,12 @@ struct string_s { int size; }; -enum media_types { - ALL_MEDIA, - AUDIO_ONLY, - VIDEO_ONLY, - IMAGES_ONLY, - NO_MEDIA -}; +typedef uint8_t media_types; +#define NO_MEDIA 0x00 +#define TYPE_AUDIO 0x01 +#define TYPE_VIDEO 0x02 +#define TYPE_IMAGES 0x04 +#define ALL_MEDIA TYPE_AUDIO|TYPE_VIDEO|TYPE_IMAGES enum file_types { TYPE_UNKNOWN, @@ -90,15 +89,15 @@ enum client_types { }; struct media_dir_s { - char * path; /* Base path */ - enum media_types type; /* type of files to scan */ - struct media_dir_s * next; + char *path; /* base path */ + media_types types; /* types of files to scan */ + struct media_dir_s *next; }; struct album_art_name_s { - char * name; /* Base path */ + char *name; /* base path */ uint8_t wildcard; - struct album_art_name_s * next; + struct album_art_name_s *next; }; struct client_cache_s { diff --git a/scanner.c b/scanner.c index 0234a88..07c1479 100644 --- a/scanner.c +++ b/scanner.c @@ -594,62 +594,90 @@ sql_failed: return (ret != SQLITE_OK); } -int -filter_audio(scan_filter *d) +static int +filter_type(scan_filter *d) { return ( (*d->d_name != '.') && ((d->d_type == DT_DIR) || (d->d_type == DT_LNK) || - (d->d_type == DT_UNKNOWN) || - ((d->d_type == DT_REG) && - (is_audio(d->d_name) || - is_playlist(d->d_name) - ) - ) )); + (d->d_type == DT_UNKNOWN)) + ); } -int -filter_video(scan_filter *d) +static int +filter_a(scan_filter *d) { - return ( (*d->d_name != '.') && - ((d->d_type == DT_DIR) || - (d->d_type == DT_LNK) || - (d->d_type == DT_UNKNOWN) || - ((d->d_type == DT_REG) && - is_video(d->d_name) ) + return ( filter_type(d) || + ((d->d_type == DT_REG) && + (is_audio(d->d_name) || + is_playlist(d->d_name)) ) ); } -int -filter_images(scan_filter *d) +static int +filter_av(scan_filter *d) { - return ( (*d->d_name != '.') && - ((d->d_type == DT_DIR) || - (d->d_type == DT_LNK) || - (d->d_type == DT_UNKNOWN) || - ((d->d_type == DT_REG) && - is_image(d->d_name) ) - ) ); + return ( filter_type(d) || + ((d->d_type == DT_REG) && + (is_audio(d->d_name) || + is_video(d->d_name) || + is_playlist(d->d_name))) + ); } -int -filter_media(scan_filter *d) +static int +filter_ap(scan_filter *d) { - return ( (*d->d_name != '.') && - ((d->d_type == DT_DIR) || - (d->d_type == DT_LNK) || - (d->d_type == DT_UNKNOWN) || - ((d->d_type == DT_REG) && - (is_image(d->d_name) || - is_audio(d->d_name) || - is_video(d->d_name) || - is_playlist(d->d_name) - ) - ) )); + return ( filter_type(d) || + ((d->d_type == DT_REG) && + (is_audio(d->d_name) || + is_image(d->d_name) || + is_playlist(d->d_name))) + ); +} + +static int +filter_v(scan_filter *d) +{ + return ( filter_type(d) || + (d->d_type == DT_REG && + is_video(d->d_name)) + ); +} + +static int +filter_vp(scan_filter *d) +{ + return ( filter_type(d) || + ((d->d_type == DT_REG) && + (is_video(d->d_name) || + is_image(d->d_name))) + ); +} + +static int +filter_p(scan_filter *d) +{ + return ( filter_type(d) || + (d->d_type == DT_REG && + is_image(d->d_name)) + ); +} + +static int +filter_avp(scan_filter *d) +{ + return ( filter_type(d) || + ((d->d_type == DT_REG) && + (is_audio(d->d_name) || + is_image(d->d_name) || + is_video(d->d_name) || + is_playlist(d->d_name))) + ); } void -ScanDirectory(const char *dir, const char *parent, enum media_types dir_type) +ScanDirectory(const char *dir, const char *parent, media_types dir_types) { struct dirent **namelist; int i, n, startID=0; @@ -659,22 +687,29 @@ ScanDirectory(const char *dir, const char *parent, enum media_types dir_type) static long long unsigned int fileno = 0; enum file_types type; - setlocale(LC_COLLATE, ""); - DPRINTF(parent?E_INFO:E_WARN, L_SCANNER, _("Scanning %s\n"), dir); - switch( dir_type ) + switch( dir_types ) { case ALL_MEDIA: - n = scandir(dir, &namelist, filter_media, alphasort); + n = scandir(dir, &namelist, filter_avp, alphasort); break; - case AUDIO_ONLY: - n = scandir(dir, &namelist, filter_audio, alphasort); + case TYPE_AUDIO: + n = scandir(dir, &namelist, filter_a, alphasort); break; - case VIDEO_ONLY: - n = scandir(dir, &namelist, filter_video, alphasort); + case TYPE_AUDIO|TYPE_VIDEO: + n = scandir(dir, &namelist, filter_av, alphasort); break; - case IMAGES_ONLY: - n = scandir(dir, &namelist, filter_images, alphasort); + case TYPE_AUDIO|TYPE_IMAGES: + n = scandir(dir, &namelist, filter_ap, alphasort); + break; + case TYPE_VIDEO: + n = scandir(dir, &namelist, filter_v, alphasort); + break; + case TYPE_VIDEO|TYPE_IMAGES: + n = scandir(dir, &namelist, filter_vp, alphasort); + break; + case TYPE_IMAGES: + n = scandir(dir, &namelist, filter_p, alphasort); break; default: n = -1; @@ -709,13 +744,13 @@ ScanDirectory(const char *dir, const char *parent, enum media_types dir_type) } else { - type = resolve_unknown_type(full_path, dir_type); + type = resolve_unknown_type(full_path, dir_types); } if( (type == TYPE_DIR) && (access(full_path, R_OK|X_OK) == 0) ) { insert_directory(name, full_path, BROWSEDIR_ID, (parent ? parent:""), i+startID); sprintf(parent_id, "%s$%X", (parent ? parent:""), i+startID); - ScanDirectory(full_path, parent_id, dir_type); + ScanDirectory(full_path, parent_id, dir_types); } else if( type == TYPE_FILE && (access(full_path, R_OK) == 0) ) { @@ -746,13 +781,15 @@ start_scanner() if( flag ) fclose(flag); #endif + setlocale(LC_COLLATE, ""); + av_register_all(); av_log_set_level(AV_LOG_PANIC); while( media_path ) { strncpyt(name, media_path->path, sizeof(name)); GetFolderMetadata(basename(name), media_path->path, NULL, NULL, 0); - ScanDirectory(media_path->path, NULL, media_path->type); + ScanDirectory(media_path->path, NULL, media_path->types); media_path = media_path->next; } #ifdef READYNAS diff --git a/utils.c b/utils.c index 38daad6..b9079c2 100644 --- a/utils.c +++ b/utils.c @@ -358,7 +358,7 @@ is_album_art(const char * name) } int -resolve_unknown_type(const char * path, enum media_types dir_type) +resolve_unknown_type(const char * path, media_types dir_type) { struct stat entry; unsigned char type = TYPE_UNKNOWN; @@ -397,16 +397,16 @@ resolve_unknown_type(const char * path, enum media_types dir_type) is_playlist(path) ) type = TYPE_FILE; break; - case AUDIO_ONLY: + case TYPE_AUDIO: if( is_audio(path) || is_playlist(path) ) type = TYPE_FILE; break; - case VIDEO_ONLY: + case TYPE_VIDEO: if( is_video(path) ) type = TYPE_FILE; break; - case IMAGES_ONLY: + case TYPE_IMAGES: if( is_image(path) ) type = TYPE_FILE; break; diff --git a/utils.h b/utils.h index 7bf22a8..191e133 100644 --- a/utils.h +++ b/utils.h @@ -78,6 +78,6 @@ int is_album_art(const char * name); int -resolve_unknown_type(const char * path, enum media_types dir_type); +resolve_unknown_type(const char * path, media_types dir_type); #endif