diff --git a/albumart.c b/albumart.c index 20ed14e..de026ec 100644 --- a/albumart.c +++ b/albumart.c @@ -104,6 +104,7 @@ update_if_album_art(const char *path) DIR *dh; struct dirent *dp; enum file_types type = TYPE_UNKNOWN; + media_types dir_type; int64_t art_id = 0; int ret; @@ -122,6 +123,9 @@ update_if_album_art(const char *path) album_art = is_album_art(match); strncpyt(dpath, path, sizeof(dpath)); + dir_type = valid_media_types(dpath); + if (!(dir_type & (TYPE_VIDEO|TYPE_AUDIO))) + return; dir = dirname(dpath); dh = opendir(dir); if( !dh ) @@ -129,29 +133,28 @@ update_if_album_art(const char *path) while ((dp = readdir(dh)) != NULL) { if (is_reg(dp) == 1) - { type = TYPE_FILE; - } else if (is_dir(dp) == 1) - { type = TYPE_DIR; - } else { snprintf(file, sizeof(file), "%s/%s", dir, dp->d_name); - type = resolve_unknown_type(file, ALL_MEDIA); + type = resolve_unknown_type(file, dir_type); } - if( type != TYPE_FILE ) + + if (type != TYPE_FILE || dp->d_name[0] == '.') continue; - if( (dp->d_name[0] != '.') && - (is_video(dp->d_name) || is_audio(dp->d_name)) && + + if(((is_video(dp->d_name) && (dir_type & TYPE_VIDEO)) || + (is_audio(dp->d_name) && (dir_type & TYPE_AUDIO))) && (album_art || strncmp(dp->d_name, match, ncmp) == 0) ) { - DPRINTF(E_DEBUG, L_METADATA, "New file %s looks like cover art for %s\n", path, dp->d_name); snprintf(file, sizeof(file), "%s/%s", dir, dp->d_name); art_id = find_album_art(file, NULL, 0); - ret = sql_exec(db, "UPDATE DETAILS set ALBUM_ART = %lld where PATH = '%q'", (long long)art_id, file); - if( ret != SQLITE_OK ) + ret = sql_exec(db, "UPDATE DETAILS set ALBUM_ART = %lld where PATH = '%q' and ALBUM_ART != %lld", (long long)art_id, file, (long long)art_id); + if( ret == SQLITE_OK ) + DPRINTF(E_DEBUG, L_METADATA, "Updated cover art for %s to %s\n", dp->d_name, path); + else DPRINTF(E_WARN, L_METADATA, "Error setting %s as cover art for %s\n", match, dp->d_name); } } diff --git a/minidlna.c b/minidlna.c index 322d04d..10b4806 100644 --- a/minidlna.c +++ b/minidlna.c @@ -255,6 +255,18 @@ getfriendlyname(char *buf, int len) #endif } +static time_t +_get_dbtime(void) +{ + char path[PATH_MAX]; + struct stat st; + + snprintf(path, sizeof(path), "%s/files.db", db_path); + if (stat(path, &st) != 0) + return 0; + return st.st_mtime; +} + static int open_db(sqlite3 **sq3) { @@ -295,7 +307,8 @@ check_db(sqlite3 *db, int new_db, pid_t *scanner_pid) media_path = media_dirs; while (media_path) { - ret = sql_get_int_field(db, "SELECT TIMESTAMP from DETAILS where PATH = %Q", media_path->path); + ret = sql_get_int_field(db, "SELECT TIMESTAMP as TYPE from DETAILS where PATH = %Q", + media_path->path); if (ret != media_path->types) { ret = 1; @@ -328,7 +341,7 @@ check_db(sqlite3 *db, int new_db, pid_t *scanner_pid) if (ret != 0) { rescan: - rescan_db = 0; + CLEARFLAG(RESCAN_MASK); if (ret < 0) DPRINTF(E_WARN, L_GENERAL, "Creating new database at %s/files.db\n", db_path); else if (ret == 1) @@ -348,10 +361,10 @@ rescan: if (CreateDatabase() != 0) DPRINTF(E_FATAL, L_GENERAL, "ERROR: Failed to create sqlite database! Exiting...\n"); } - if (ret || rescan_db) + if (ret || GETFLAG(RESCAN_MASK)) { #if USE_FORK - scanning = 1; + SETFLAG(SCANNING_MASK); sqlite3_close(db); *scanner_pid = fork(); open_db(&db); @@ -593,7 +606,7 @@ init(int argc, char **argv) else if (*path == 'V' || *path == 'v') types |= TYPE_VIDEO; else if (*path == 'P' || *path == 'p') - types |= TYPE_IMAGES; + types |= TYPE_IMAGE; else DPRINTF(E_FATAL, L_GENERAL, "Media directory entry not understood [%s]\n", ary_options[i].value); @@ -839,7 +852,7 @@ init(int argc, char **argv) runtime_vars.port = -1; // triggers help display break; case 'r': - rescan_db = 1; + SETFLAG(RESCAN_MASK); break; case 'R': snprintf(buf, sizeof(buf), "rm -rf %s/files.db %s/art_cache", db_path, db_path); @@ -1012,7 +1025,7 @@ main(int argc, char **argv) fd_set readset; /* for select() */ fd_set writeset; struct timeval timeout, timeofday, lastnotifytime = {0, 0}; - time_t lastupdatetime = 0; + time_t lastupdatetime = 0, lastdbtime = 0; int max_fd = -1; int last_changecnt = 0; pid_t scanner_pid = 0; @@ -1048,6 +1061,7 @@ main(int argc, char **argv) ret = -1; } check_db(db, ret, &scanner_pid); + lastdbtime = _get_dbtime(); #ifdef HAVE_INOTIFY if( GETFLAG(INOTIFY_MASK) ) { @@ -1165,12 +1179,13 @@ main(int argc, char **argv) #endif } - if (scanning) + if (GETFLAG(SCANNING_MASK)) { if (!scanner_pid || kill(scanner_pid, 0) != 0) { - scanning = 0; - updateID++; + CLEARFLAG(SCANNING_MASK); + if (_get_dbtime() != lastdbtime) + updateID++; } } @@ -1244,7 +1259,16 @@ main(int argc, char **argv) * and if there is an active HTTP connection, at most once every 2 seconds */ if (i && (timeofday.tv_sec >= (lastupdatetime + 2))) { - if (scanning || sqlite3_total_changes(db) != last_changecnt) + if (GETFLAG(SCANNING_MASK)) + { + time_t dbtime = _get_dbtime(); + if (dbtime != lastdbtime) + { + lastdbtime = dbtime; + last_changecnt = -1; + } + } + if (sqlite3_total_changes(db) != last_changecnt) { updateID++; last_changecnt = sqlite3_total_changes(db); @@ -1308,7 +1332,7 @@ main(int argc, char **argv) shutdown: /* kill the scanner */ - if (scanning && scanner_pid) + if (GETFLAG(SCANNING_MASK) && scanner_pid) kill(scanner_pid, SIGKILL); /* close out open sockets */ @@ -1336,7 +1360,10 @@ shutdown: } if (inotify_thread) + { + pthread_kill(inotify_thread, SIGCHLD); pthread_join(inotify_thread, NULL); + } /* kill other child processes */ process_reap_children(); diff --git a/minidlnatypes.h b/minidlnatypes.h index 6879b70..7cfad89 100644 --- a/minidlnatypes.h +++ b/minidlnatypes.h @@ -60,11 +60,14 @@ struct string_s { }; 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 +#define NO_MEDIA 0x00 +#define TYPE_AUDIO 0x01 +#define TYPE_VIDEO 0x02 +#define TYPE_IMAGE 0x04 +#define TYPE_PLAYLIST 0x09 +#define TYPE_CAPTION 0x10 +#define TYPE_NFO 0x20 +#define ALL_MEDIA TYPE_AUDIO|TYPE_VIDEO|TYPE_IMAGE enum file_types { TYPE_UNKNOWN, diff --git a/monitor.c b/monitor.c index cdb7d65..b3a17f5 100644 --- a/monitor.c +++ b/monitor.c @@ -350,18 +350,21 @@ monitor_insert_file(const char *name, const char *path) char *parent_buf = NULL; char *id = NULL; char video[PATH_MAX]; + const char *tbl = "DETAILS"; int depth = 1; int ts; - media_types types = ALL_MEDIA; - struct media_dir_s * media_path = media_dirs; + media_types dir_types; + media_types mtype = get_media_type(path); struct stat st; /* Is it cover art for another file? */ - if( is_image(path) ) + if (mtype == TYPE_IMAGE) update_if_album_art(path); - else if( is_caption(path) ) + else if (mtype == TYPE_CAPTION) check_for_captions(path, 0); - else if( is_nfo(path) ) + else if (mtype == TYPE_PLAYLIST) + tbl = "PLAYLISTS"; + else if (mtype == TYPE_NFO) { char *vpath = check_nfo(path); if (!vpath) @@ -370,95 +373,42 @@ monitor_insert_file(const char *name, const char *path) sqlite3_free(vpath); DPRINTF(E_DEBUG, L_INOTIFY, "Found modified nfo %s\n", video); monitor_remove_file(video); - path = video; name = strrchr(video, '/'); if (!name) return -1; name++; + path = video; + mtype = TYPE_VIDEO; } /* Check if we're supposed to be scanning for this file type in this directory */ - while( media_path ) - { - if( strncmp(path, media_path->path, strlen(media_path->path)) == 0 ) - { - types = media_path->types; - break; - } - media_path = media_path->next; - } - switch( types ) - { - case ALL_MEDIA: - if( !is_image(path) && - !is_audio(path) && - !is_video(path) && - !is_playlist(path) ) - return -1; - break; - case TYPE_AUDIO: - if( !is_audio(path) && - !is_playlist(path) ) - return -1; - break; - case TYPE_AUDIO|TYPE_VIDEO: - if( !is_audio(path) && - !is_video(path) && - !is_playlist(path) ) - return -1; - 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 TYPE_VIDEO|TYPE_IMAGES: - if( !is_image(path) && - !is_video(path) ) - return -1; - break; - case TYPE_IMAGES: - if( !is_image(path) ) - return -1; - break; - default: - return -1; - } + dir_types = valid_media_types(path); + if (!(mtype & dir_types)) + return -1; /* If it's already in the database and hasn't been modified, skip it. */ if( stat(path, &st) != 0 ) return -1; - ts = sql_get_int_field(db, "SELECT TIMESTAMP from DETAILS where PATH = '%q'", path); - if( !ts && is_playlist(path) && (sql_get_int_field(db, "SELECT ID from PLAYLISTS where PATH = '%q'", path) > 0) ) - { - DPRINTF(E_DEBUG, L_INOTIFY, "Re-reading modified playlist (%s).\n", path); - monitor_remove_file(path); - next_pl_fill = 1; - } - else if( !ts ) + ts = sql_get_int_field(db, "SELECT TIMESTAMP from %s where PATH = '%q'", tbl, path); + if( !ts ) { DPRINTF(E_DEBUG, L_INOTIFY, "Adding: %s\n", path); } else if( ts != st.st_mtime ) { DPRINTF(E_DEBUG, L_INOTIFY, "%s is %s than the last db entry.\n", - path, (ts < st.st_mtime) ? "older" : "newer"); + path, (ts > st.st_mtime) ? "older" : "newer"); monitor_remove_file(path); } else { - if( ts == st.st_mtime ) + if( ts == st.st_mtime && !GETFLAG(RESCAN_MASK) ) DPRINTF(E_DEBUG, L_INOTIFY, "%s already exists\n", path); return 0; } - /* Find the parentID. If it's not found, create all necessary parents. */ + /* Find the parentID. If it's not found, create all necessary parents. */ len = strlen(path)+1; if( !(path_buf = malloc(len)) || !(last_dir = malloc(len)) || @@ -509,13 +459,13 @@ monitor_insert_file(const char *name, const char *path) if( !depth ) { //DEBUG DPRINTF(E_DEBUG, L_INOTIFY, "Inserting %s\n", name); - insert_file(name, path, id+2, get_next_available_id("OBJECTS", id), types); - sqlite3_free(id); - if( (is_audio(path) || is_playlist(path)) && next_pl_fill != 1 ) + int ret = insert_file(name, path, id+2, get_next_available_id("OBJECTS", id), dir_types); + if (ret == 1 && (mtype & TYPE_PLAYLIST)) { next_pl_fill = time(NULL) + 120; // Schedule a playlist scan for 2 minutes from now. - //DEBUG DPRINTF(E_WARN, L_INOTIFY, "Playlist scan scheduled for %s", ctime(&next_pl_fill)); + //DEBUG DPRINTF(E_MAXDEBUG, L_INOTIFY, "Playlist scan scheduled for %s", ctime(&next_pl_fill)); } + sqlite3_free(id); } return depth; } @@ -528,8 +478,7 @@ monitor_insert_directory(int fd, char *name, const char * path) char *id, *parent_buf, *esc_name; char path_buf[PATH_MAX]; enum file_types type = TYPE_UNKNOWN; - media_types dir_types = ALL_MEDIA; - struct media_dir_s* media_path; + media_types dir_types; struct stat st; if( access(path, R_OK|X_OK) != 0 ) @@ -540,7 +489,8 @@ monitor_insert_directory(int fd, char *name, const char * path) if( sql_get_int_field(db, "SELECT ID from DETAILS where PATH = '%q'", path) > 0 ) { fd = 0; - DPRINTF(E_DEBUG, L_INOTIFY, "%s already exists\n", path); + if (!GETFLAG(RESCAN_MASK)) + DPRINTF(E_DEBUG, L_INOTIFY, "%s already exists\n", path); } else { @@ -569,16 +519,7 @@ monitor_insert_directory(int fd, char *name, const char * path) #endif } - media_path = media_dirs; - while( media_path ) - { - if( strncmp(path, media_path->path, strlen(media_path->path)) == 0 ) - { - dir_types = media_path->types; - break; - } - media_path = media_path->next; - } + dir_types = valid_media_types(path); ds = opendir(path); if( !ds ) @@ -664,7 +605,6 @@ void * start_inotify(void) { struct pollfd pollfds[1]; - int timeout = 1000; char buffer[BUF_LEN]; char path_buf[PATH_MAX]; int length, i = 0; @@ -673,6 +613,7 @@ start_inotify(void) sigset_t set; sigfillset(&set); + sigdelset(&set, SIGCHLD); pthread_sigmask(SIG_BLOCK, &set, NULL); pollfds[0].fd = inotify_init(); @@ -681,7 +622,7 @@ start_inotify(void) if ( pollfds[0].fd < 0 ) DPRINTF(E_ERROR, L_INOTIFY, "inotify_init() failed!\n"); - while( scanning ) + while( GETFLAG(SCANNING_MASK) ) { if( quitting ) goto quitting; @@ -695,6 +636,15 @@ start_inotify(void) while( !quitting ) { + int timeout = -1; + if (next_pl_fill) + { + time_t diff = next_pl_fill - time(NULL); + if (diff < 0) + timeout = 0; + else + timeout = diff * 1000; + } length = poll(pollfds, 1, timeout); if( !length ) { diff --git a/playlist.c b/playlist.c index 9bd8984..4ac3b2c 100644 --- a/playlist.c +++ b/playlist.c @@ -45,6 +45,9 @@ insert_playlist(const char *path, const char *name) char *objname; char type[4]; + if (stat(path, &file) != 0) + return -1; + strncpyt(type, strrchr(name, '.')+1, 4); if( start_plist(path, NULL, &file, NULL, type) != 0 ) @@ -62,28 +65,26 @@ insert_playlist(const char *path, const char *name) DPRINTF(E_WARN, L_SCANNER, "Bad playlist [%s]\n", path); return -1; } + objname = strdup(name); strip_ext(objname); + matches = sql_get_int_field(db, "SELECT count(*) from PLAYLISTS where NAME = '%q'", objname); + if (matches > 0) + { + char *newname; + xasprintf(&newname, "%s(%d)", objname, matches); + strip_ext(newname); + free(objname); + objname = newname; + } DPRINTF(E_DEBUG, L_SCANNER, "Playlist %s contains %d items\n", objname, items); - - matches = sql_get_int_field(db, "SELECT count(*) from PLAYLISTS where NAME = '%q'", objname); - if( matches > 0 ) - { - sql_exec(db, "INSERT into PLAYLISTS" - " (NAME, PATH, ITEMS) " - "VALUES" - " ('%q(%d)', '%q', %d)", - objname, matches, path, items); - } - else - { - sql_exec(db, "INSERT into PLAYLISTS" - " (NAME, PATH, ITEMS) " - "VALUES" - " ('%q', '%q', %d)", - objname, path, items); - } + + sql_exec(db, "INSERT into PLAYLISTS" + " (NAME, PATH, ITEMS, TIMESTAMP) " + "VALUES" + " ('%q', '%q', %d, %lld)", + objname, path, items, (long long)file.st_mtime); free(objname); return 0; } @@ -125,6 +126,12 @@ fill_playlists(void) int64_t plID, detailID; char sql_buf[] = "SELECT ID, NAME, PATH from PLAYLISTS where ITEMS > FOUND"; + if( GETFLAG(NO_PLAYLIST_MASK) ) + { + DPRINTF(E_WARN, L_SCANNER, "Playlist creation disabled\n"); + return 0; + } + DPRINTF(E_WARN, L_SCANNER, "Parsing playlists...\n"); if( sql_get_table(db, sql_buf, &result, &rows, NULL) != SQLITE_OK ) @@ -168,7 +175,7 @@ fill_playlists(void) { //DEBUG DPRINTF(E_DEBUG, L_SCANNER, "%d: already in database\n", plist.track); found++; - freetags(&plist); + freetags(&plist); continue; } if( last_dir ) @@ -248,7 +255,7 @@ found: goto retry; } } - freetags(&plist); + freetags(&plist); } if( last_dir ) { diff --git a/scanner.c b/scanner.c index ff7ec9e..a730567 100644 --- a/scanner.c +++ b/scanner.c @@ -449,42 +449,45 @@ insert_directory(const char *name, const char *path, const char *base, const cha int insert_file(const char *name, const char *path, const char *parentID, int object, media_types types) { - char class[32]; + const char *class; char objectID[64]; int64_t detailID = 0; char base[8]; char *typedir_parentID; char *baseid; char *objname; + media_types mtype = get_media_type(name); - if( (types & TYPE_IMAGES) && is_image(name) ) + if( mtype == TYPE_IMAGE && (types & TYPE_IMAGE) ) { if( is_album_art(name) ) return -1; strcpy(base, IMAGE_DIR_ID); - strcpy(class, "item.imageItem.photo"); + class = "item.imageItem.photo"; detailID = GetImageMetadata(path, name); } - else if( (types & TYPE_VIDEO) && is_video(name) ) + else if( mtype == TYPE_VIDEO && (types & TYPE_VIDEO) ) { strcpy(base, VIDEO_DIR_ID); - strcpy(class, "item.videoItem"); + class = "item.videoItem"; detailID = GetVideoMetadata(path, name); } - else if( is_playlist(name) ) + else if( mtype == TYPE_PLAYLIST && (types & TYPE_PLAYLIST) ) { if( insert_playlist(path, name) == 0 ) return 1; } - if( !detailID && (types & TYPE_AUDIO) && is_audio(name) ) + /* Some file extensions can be used for both audio and video. + ** Fall back to audio on these files if video parsing fails. */ + if (!detailID && (types & TYPE_AUDIO) && is_audio(name) ) { strcpy(base, MUSIC_DIR_ID); - strcpy(class, "item.audioItem.musicTrack"); + class = "item.audioItem.musicTrack"; detailID = GetAudioMetadata(path, name); } if( !detailID ) { - DPRINTF(E_WARN, L_SCANNER, "Unsuccessful getting details for %s!\n", path); + DPRINTF(E_WARN, L_SCANNER, "Unsuccessful getting details for %s\n", path); return -1; } @@ -628,9 +631,9 @@ filter_type(scan_filter *d) { #if HAVE_STRUCT_DIRENT_D_TYPE return ( (d->d_type == DT_DIR) || - (d->d_type == DT_LNK) || - (d->d_type == DT_UNKNOWN) - ); + (d->d_type == DT_LNK) || + (d->d_type == DT_UNKNOWN) + ); #else return 1; #endif @@ -640,79 +643,79 @@ static int filter_a(scan_filter *d) { return ( filter_hidden(d) && - (filter_type(d) || + (filter_type(d) || (is_reg(d) && (is_audio(d->d_name) || - is_playlist(d->d_name)))) - ); + is_playlist(d->d_name)))) + ); } static int filter_av(scan_filter *d) { return ( filter_hidden(d) && - (filter_type(d) || + (filter_type(d) || (is_reg(d) && (is_audio(d->d_name) || is_video(d->d_name) || - is_playlist(d->d_name)))) - ); + is_playlist(d->d_name)))) + ); } static int filter_ap(scan_filter *d) { return ( filter_hidden(d) && - (filter_type(d) || + (filter_type(d) || (is_reg(d) && (is_audio(d->d_name) || is_image(d->d_name) || - is_playlist(d->d_name)))) - ); + is_playlist(d->d_name)))) + ); } static int filter_v(scan_filter *d) { return ( filter_hidden(d) && - (filter_type(d) || + (filter_type(d) || (is_reg(d) && - is_video(d->d_name))) - ); + is_video(d->d_name))) + ); } static int filter_vp(scan_filter *d) { return ( filter_hidden(d) && - (filter_type(d) || + (filter_type(d) || (is_reg(d) && (is_video(d->d_name) || - is_image(d->d_name)))) - ); + is_image(d->d_name)))) + ); } static int filter_p(scan_filter *d) { return ( filter_hidden(d) && - (filter_type(d) || + (filter_type(d) || (is_reg(d) && is_image(d->d_name))) - ); + ); } static int filter_avp(scan_filter *d) { return ( filter_hidden(d) && - (filter_type(d) || + (filter_type(d) || (is_reg(d) && (is_audio(d->d_name) || is_image(d->d_name) || is_video(d->d_name) || - is_playlist(d->d_name)))) - ); + is_playlist(d->d_name)))) + ); } static void @@ -737,16 +740,16 @@ ScanDirectory(const char *dir, const char *parent, media_types dir_types) case TYPE_AUDIO|TYPE_VIDEO: n = scandir(dir, &namelist, filter_av, alphasort); break; - case TYPE_AUDIO|TYPE_IMAGES: + case TYPE_AUDIO|TYPE_IMAGE: n = scandir(dir, &namelist, filter_ap, alphasort); break; case TYPE_VIDEO: n = scandir(dir, &namelist, filter_v, alphasort); break; - case TYPE_VIDEO|TYPE_IMAGES: + case TYPE_VIDEO|TYPE_IMAGE: n = scandir(dir, &namelist, filter_vp, alphasort); break; - case TYPE_IMAGES: + case TYPE_IMAGE: n = scandir(dir, &namelist, filter_p, alphasort); break; default: @@ -818,26 +821,6 @@ ScanDirectory(const char *dir, const char *parent, media_types dir_types) } } -static void -_notify_start(void) -{ -#ifdef READYNAS - FILE *flag = fopen("/ramfs/.upnp-av_scan", "w"); - if( flag ) - fclose(flag); -#endif -} - -static void -_notify_stop(void) -{ -#ifdef READYNAS - if( access("/ramfs/.rescan_done", F_OK) == 0 ) - system("/bin/sh /ramfs/.rescan_done"); - unlink("/ramfs/.upnp-av_scan"); -#endif -} - /* rescan functions added by shrimpkin@sourceforge.net */ static int cb_orphans(void *args, int argc, char **argv, char **azColName) @@ -866,6 +849,8 @@ start_rescan(void) char *zErrMsg; const char *sql_files = "SELECT path, mime FROM details WHERE path NOT NULL AND mime IS NOT NULL;"; const char *sql_dir = "SELECT path, mime FROM details WHERE path NOT NULL AND mime IS NULL;"; + int changes = sqlite3_total_changes(db); + const char *summary; int ret; DPRINTF(E_INFO, L_SCANNER, "Starting rescan\n"); @@ -896,12 +881,18 @@ start_rescan(void) monitor_insert_directory(0, esc_name, path); free(esc_name); } - DPRINTF(E_INFO, L_SCANNER, "Rescan completed\n"); + fill_playlists(); + + if (sqlite3_total_changes(db) != changes) + summary = "changes found"; + else + summary = "no changes"; + DPRINTF(E_INFO, L_SCANNER, "Rescan completed. (%s)\n", summary); } /* end rescan functions */ void -start_scanner() +start_scanner(void) { struct media_dir_s *media_path; char path[MAXPATHLEN]; @@ -910,15 +901,12 @@ start_scanner() DPRINTF(E_WARN, L_INOTIFY, "Failed to reduce scanner thread priority\n"); setlocale(LC_COLLATE, ""); - av_register_all(); av_log_set_level(AV_LOG_PANIC); - if( rescan_db ) - { - start_rescan(); - return; - } - _notify_start(); + + if( GETFLAG(RESCAN_MASK) ) + return start_rescan(); + for( media_path = media_dirs; media_path != NULL; media_path = media_path->next ) { int64_t id; @@ -941,20 +929,12 @@ start_scanner() ScanDirectory(media_path->path, parent, media_path->types); sql_exec(db, "INSERT into SETTINGS values (%Q, %Q)", "media_dir", media_path->path); } - _notify_stop(); /* Create this index after scanning, so it doesn't slow down the scanning process. * This index is very useful for large libraries used with an XBox360 (or any * client that uses UPnPSearch on large containers). */ sql_exec(db, "create INDEX IDX_SEARCH_OPT ON OBJECTS(OBJECT_ID, CLASS, DETAIL_ID);"); - if( GETFLAG(NO_PLAYLIST_MASK) ) - { - DPRINTF(E_WARN, L_SCANNER, "Playlist creation disabled\n"); - } - else - { - fill_playlists(); - } + fill_playlists(); DPRINTF(E_DEBUG, L_SCANNER, "Initial file scan completed\n"); //JM: Set up a db version number, so we know if we need to rebuild due to a new structure. diff --git a/scanner_sqlite.h b/scanner_sqlite.h index cbc1e72..c998428 100644 --- a/scanner_sqlite.h +++ b/scanner_sqlite.h @@ -79,7 +79,8 @@ char create_playlistTable_sqlite[] = "CREATE TABLE PLAYLISTS (" "NAME TEXT NOT NULL, " "PATH TEXT NOT NULL, " "ITEMS INTEGER DEFAULT 0, " - "FOUND INTEGER DEFAULT 0" + "FOUND INTEGER DEFAULT 0, " + "TIMESTAMP INTEGER DEFAULT 0" ");"; char create_settingsTable_sqlite[] = "CREATE TABLE SETTINGS (" diff --git a/sql.c b/sql.c index 7889c31..8b3c029 100644 --- a/sql.c +++ b/sql.c @@ -282,6 +282,13 @@ db_upgrade(sqlite3 *db) if (ret != SQLITE_OK) return 9; } + if (db_vers < 11) + { + DPRINTF(E_WARN, L_DB_SQL, "Updating DB version to v%d\n", 11); + ret = sql_exec(db, "ALTER TABLE PLAYLISTS ADD TIMESTAMP INTEGER DEFAULT 1"); + if (ret != SQLITE_OK) + return 10; + } sql_exec(db, "PRAGMA user_version = %d", DB_VERSION); return 0; diff --git a/upnpglobalvars.c b/upnpglobalvars.c index f221619..2ca5676 100644 --- a/upnpglobalvars.c +++ b/upnpglobalvars.c @@ -85,8 +85,6 @@ char db_path[PATH_MAX] = {'\0'}; char log_path[PATH_MAX] = {'\0'}; struct media_dir_s * media_dirs = NULL; struct album_art_name_s * album_art_names = NULL; -short int scanning = 0; volatile short int quitting = 0; volatile uint32_t updateID = 0; const char *force_sort_criteria = NULL; -short int rescan_db = 0; diff --git a/upnpglobalvars.h b/upnpglobalvars.h index 079166c..aedc987 100644 --- a/upnpglobalvars.h +++ b/upnpglobalvars.h @@ -66,7 +66,7 @@ #endif #define USE_FORK 1 -#define DB_VERSION 10 +#define DB_VERSION 11 #ifdef ENABLE_NLS #define _(string) gettext(string) @@ -193,6 +193,8 @@ extern uint32_t runtime_flags; #else #define TIVO_BONJOUR_MASK 0x0000 #endif +#define SCANNING_MASK 0x0100 +#define RESCAN_MASK 0x0200 #define SETFLAG(mask) runtime_flags |= mask #define GETFLAG(mask) (runtime_flags & mask) @@ -229,10 +231,8 @@ extern char db_path[]; extern char log_path[]; extern struct media_dir_s *media_dirs; extern struct album_art_name_s *album_art_names; -extern short int scanning; extern volatile short int quitting; extern volatile uint32_t updateID; extern const char *force_sort_criteria; -extern short int rescan_db; #endif diff --git a/upnphttp.c b/upnphttp.c index 1902159..3b4b58a 100644 --- a/upnphttp.c +++ b/upnphttp.c @@ -630,7 +630,7 @@ SendResp_presentation(struct upnphttp * h) "Image files%d" "", a, v, p); - if (scanning) + if (GETFLAG(SCANNING_MASK)) strcatf(&str, "
* Media scan in progress
"); @@ -1360,7 +1360,7 @@ _open_file(const char *orig_path) if (strncmp(path, media_path->path, strlen(media_path->path)) == 0) break; } - if (!media_path && strncmp(path, db_path, strlen(db_path))) + if (!media_path && strncmp(path, db_path, strlen(db_path))) { DPRINTF(E_ERROR, L_HTTP, "Rejecting wide link %s -> %s\n", orig_path, path); diff --git a/utils.c b/utils.c index 46a2c2b..fc21b7f 100644 --- a/utils.c +++ b/utils.c @@ -435,6 +435,27 @@ is_caption(const char * file) return (ends_with(file, ".srt") || ends_with(file, ".smi")); } +media_types +get_media_type(const char *file) +{ + const char *ext = strrchr(file, '.'); + if (!ext) + return NO_MEDIA; + if (is_image(ext)) + return TYPE_IMAGE; + if (is_video(ext)) + return TYPE_VIDEO; + if (is_audio(ext)) + return TYPE_AUDIO; + if (is_playlist(ext)) + return TYPE_PLAYLIST; + if (is_caption(ext)) + return TYPE_CAPTION; + if (is_nfo(ext)) + return TYPE_NFO; + return NO_MEDIA; +} + int is_album_art(const char * name) { @@ -462,7 +483,7 @@ int resolve_unknown_type(const char * path, media_types dir_type) { struct stat entry; - unsigned char type = TYPE_UNKNOWN; + enum file_types type = TYPE_UNKNOWN; char str_buf[PATH_MAX]; ssize_t len; @@ -489,33 +510,24 @@ resolve_unknown_type(const char * path, media_types dir_type) } else if( S_ISREG(entry.st_mode) ) { - switch( dir_type ) - { - case ALL_MEDIA: - if( is_image(path) || - is_audio(path) || - is_video(path) || - is_playlist(path) ) - type = TYPE_FILE; - break; - case TYPE_AUDIO: - if( is_audio(path) || - is_playlist(path) ) - type = TYPE_FILE; - break; - case TYPE_VIDEO: - if( is_video(path) ) - type = TYPE_FILE; - break; - case TYPE_IMAGES: - if( is_image(path) ) - type = TYPE_FILE; - break; - default: - break; - } + media_types mtype = get_media_type(path); + if (dir_type & mtype) + type = TYPE_FILE; } } return type; } +media_types +valid_media_types(const char *path) +{ + struct media_dir_s *media_dir; + + for (media_dir = media_dirs; media_dir; media_dir = media_dir->next) + { + if (strncmp(path, media_dir->path, strlen(media_dir->path)) == 0) + return media_dir->types; + } + + return ALL_MEDIA; +} diff --git a/utils.h b/utils.h index 8fa70b2..a200756 100644 --- a/utils.h +++ b/utils.h @@ -90,6 +90,8 @@ int is_image(const char * file); int is_playlist(const char * file); int is_caption(const char * file); #define is_nfo(file) ends_with(file, ".nfo") +media_types get_media_type(const char *file); +media_types valid_media_types(const char *path); int is_album_art(const char * name); int resolve_unknown_type(const char * path, media_types dir_type);