scanner: Clean up non-destructive rescan

Fix several issues with the non-destructive rescan functionality.
Most of these issues also affected inotify scanning as well.  These
include annoying debug messages, adding album art for files that we
aren't supposed to be scanning anyway, incrementing the UpdateID when no
changes were made to the database, and other smaller issues.
This commit is contained in:
Justin Maggard 2017-08-23 23:43:42 -07:00
parent 9e534c56fd
commit 50b1a2e289
13 changed files with 232 additions and 242 deletions

View File

@ -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);
}
}

View File

@ -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,11 +1179,12 @@ main(int argc, char **argv)
#endif
}
if (scanning)
if (GETFLAG(SCANNING_MASK))
{
if (!scanner_pid || kill(scanner_pid, 0) != 0)
{
scanning = 0;
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();

View File

@ -63,8 +63,11 @@ 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 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,

118
monitor.c
View File

@ -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,90 +373,37 @@ 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) )
dir_types = valid_media_types(path);
if (!(mtype & dir_types))
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;
}
/* 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;
}
@ -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,6 +489,7 @@ 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;
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 )
{

View File

@ -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);
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);
char *newname;
xasprintf(&newname, "%s(%d)", objname, matches);
strip_ext(newname);
free(objname);
objname = newname;
}
else
{
DPRINTF(E_DEBUG, L_SCANNER, "Playlist %s contains %d items\n", objname, items);
sql_exec(db, "INSERT into PLAYLISTS"
" (NAME, PATH, ITEMS) "
" (NAME, PATH, ITEMS, TIMESTAMP) "
"VALUES"
" ('%q', '%q', %d)",
objname, path, items);
}
" ('%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 )

View File

@ -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;
}
/* 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;
}
@ -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();
}
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.

View File

@ -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 ("

7
sql.c
View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -630,7 +630,7 @@ SendResp_presentation(struct upnphttp * h)
"<tr><td>Image files</td><td>%d</td></tr>"
"</table>", a, v, p);
if (scanning)
if (GETFLAG(SCANNING_MASK))
strcatf(&str,
"<br><i>* Media scan in progress</i><br>");

62
utils.c
View File

@ -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) )
media_types mtype = get_media_type(path);
if (dir_type & mtype)
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;
}
}
}
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;
}

View File

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