monitor: Support NFO file changes
Detect when a .nfo file changes, and rescan metadata for the associated video file.
This commit is contained in:
parent
c8665bcf40
commit
9e534c56fd
22
metadata.c
22
metadata.c
@ -125,7 +125,7 @@ check_for_captions(const char *path, int64_t detailID)
|
|||||||
strncpyt(file, path, sizeof(file));
|
strncpyt(file, path, sizeof(file));
|
||||||
p = strip_ext(file);
|
p = strip_ext(file);
|
||||||
if (!p)
|
if (!p)
|
||||||
p = strrchr(file, '\0');
|
return;
|
||||||
|
|
||||||
/* If we weren't given a detail ID, look for one. */
|
/* If we weren't given a detail ID, look for one. */
|
||||||
if (!detailID)
|
if (!detailID)
|
||||||
@ -287,7 +287,7 @@ GetFolderMetadata(const char *name, const char *path, const char *artist, const
|
|||||||
}
|
}
|
||||||
|
|
||||||
int64_t
|
int64_t
|
||||||
GetAudioMetadata(const char *path, char *name)
|
GetAudioMetadata(const char *path, const char *name)
|
||||||
{
|
{
|
||||||
char type[4];
|
char type[4];
|
||||||
static char lang[6] = { '\0' };
|
static char lang[6] = { '\0' };
|
||||||
@ -303,7 +303,6 @@ GetAudioMetadata(const char *path, char *name)
|
|||||||
|
|
||||||
if ( stat(path, &file) != 0 )
|
if ( stat(path, &file) != 0 )
|
||||||
return 0;
|
return 0;
|
||||||
strip_ext(name);
|
|
||||||
|
|
||||||
if( ends_with(path, ".mp3") )
|
if( ends_with(path, ".mp3") )
|
||||||
{
|
{
|
||||||
@ -384,7 +383,9 @@ GetAudioMetadata(const char *path, char *name)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m.title = name;
|
free_flags |= FLAG_TITLE;
|
||||||
|
m.title = strdup(name);
|
||||||
|
strip_ext(m.title);
|
||||||
}
|
}
|
||||||
for( i = ROLE_START; i < N_ROLE; i++ )
|
for( i = ROLE_START; i < N_ROLE; i++ )
|
||||||
{
|
{
|
||||||
@ -493,7 +494,7 @@ libjpeg_error_handler(j_common_ptr cinfo)
|
|||||||
}
|
}
|
||||||
|
|
||||||
int64_t
|
int64_t
|
||||||
GetImageMetadata(const char *path, char *name)
|
GetImageMetadata(const char *path, const char *name)
|
||||||
{
|
{
|
||||||
ExifData *ed;
|
ExifData *ed;
|
||||||
ExifEntry *e = NULL;
|
ExifEntry *e = NULL;
|
||||||
@ -514,7 +515,6 @@ GetImageMetadata(const char *path, char *name)
|
|||||||
//DEBUG DPRINTF(E_DEBUG, L_METADATA, "Parsing %s...\n", path);
|
//DEBUG DPRINTF(E_DEBUG, L_METADATA, "Parsing %s...\n", path);
|
||||||
if ( stat(path, &file) != 0 )
|
if ( stat(path, &file) != 0 )
|
||||||
return 0;
|
return 0;
|
||||||
strip_ext(name);
|
|
||||||
//DEBUG DPRINTF(E_DEBUG, L_METADATA, " * size: %jd\n", file.st_size);
|
//DEBUG DPRINTF(E_DEBUG, L_METADATA, " * size: %jd\n", file.st_size);
|
||||||
|
|
||||||
/* MIME hard-coded to JPEG for now, until we add PNG support */
|
/* MIME hard-coded to JPEG for now, until we add PNG support */
|
||||||
@ -639,13 +639,15 @@ no_exifdata:
|
|||||||
else if( (width <= 4096 && height <= 4096) || !GETFLAG(DLNA_STRICT_MASK) )
|
else if( (width <= 4096 && height <= 4096) || !GETFLAG(DLNA_STRICT_MASK) )
|
||||||
m.dlna_pn = strdup("JPEG_LRG");
|
m.dlna_pn = strdup("JPEG_LRG");
|
||||||
xasprintf(&m.resolution, "%dx%d", width, height);
|
xasprintf(&m.resolution, "%dx%d", width, height);
|
||||||
|
m.title = strdup(name);
|
||||||
|
strip_ext(m.title);
|
||||||
|
|
||||||
ret = sql_exec(db, "INSERT into DETAILS"
|
ret = sql_exec(db, "INSERT into DETAILS"
|
||||||
" (PATH, TITLE, SIZE, TIMESTAMP, DATE, RESOLUTION,"
|
" (PATH, TITLE, SIZE, TIMESTAMP, DATE, RESOLUTION,"
|
||||||
" ROTATION, THUMBNAIL, CREATOR, DLNA_PN, MIME) "
|
" ROTATION, THUMBNAIL, CREATOR, DLNA_PN, MIME) "
|
||||||
"VALUES"
|
"VALUES"
|
||||||
" (%Q, '%q', %lld, %lld, %Q, %Q, %u, %d, %Q, %Q, %Q);",
|
" (%Q, '%q', %lld, %lld, %Q, %Q, %u, %d, %Q, %Q, %Q);",
|
||||||
path, name, (long long)file.st_size, (long long)file.st_mtime, m.date,
|
path, m.title, (long long)file.st_size, (long long)file.st_mtime, m.date,
|
||||||
m.resolution, m.rotation, thumb, m.creator, m.dlna_pn, m.mime);
|
m.resolution, m.rotation, thumb, m.creator, m.dlna_pn, m.mime);
|
||||||
if( ret != SQLITE_OK )
|
if( ret != SQLITE_OK )
|
||||||
{
|
{
|
||||||
@ -662,7 +664,7 @@ no_exifdata:
|
|||||||
}
|
}
|
||||||
|
|
||||||
int64_t
|
int64_t
|
||||||
GetVideoMetadata(const char *path, char *name)
|
GetVideoMetadata(const char *path, const char *name)
|
||||||
{
|
{
|
||||||
struct stat file;
|
struct stat file;
|
||||||
int ret, i;
|
int ret, i;
|
||||||
@ -685,7 +687,6 @@ GetVideoMetadata(const char *path, char *name)
|
|||||||
//DEBUG DPRINTF(E_DEBUG, L_METADATA, "Parsing video %s...\n", name);
|
//DEBUG DPRINTF(E_DEBUG, L_METADATA, "Parsing video %s...\n", name);
|
||||||
if ( stat(path, &file) != 0 )
|
if ( stat(path, &file) != 0 )
|
||||||
return 0;
|
return 0;
|
||||||
strip_ext(name);
|
|
||||||
//DEBUG DPRINTF(E_DEBUG, L_METADATA, " * size: %jd\n", file.st_size);
|
//DEBUG DPRINTF(E_DEBUG, L_METADATA, " * size: %jd\n", file.st_size);
|
||||||
|
|
||||||
ret = lav_open(&ctx, path);
|
ret = lav_open(&ctx, path);
|
||||||
@ -1533,7 +1534,10 @@ video_no_dlna:
|
|||||||
}
|
}
|
||||||
|
|
||||||
if( !m.title )
|
if( !m.title )
|
||||||
|
{
|
||||||
m.title = strdup(name);
|
m.title = strdup(name);
|
||||||
|
strip_ext(m.title);
|
||||||
|
}
|
||||||
|
|
||||||
album_art = find_album_art(path, m.thumb_data, m.thumb_size);
|
album_art = find_album_art(path, m.thumb_data, m.thumb_size);
|
||||||
freetags(&video);
|
freetags(&video);
|
||||||
|
@ -92,12 +92,12 @@ int64_t
|
|||||||
GetFolderMetadata(const char *name, const char *path, const char *artist, const char *genre, int64_t album_art);
|
GetFolderMetadata(const char *name, const char *path, const char *artist, const char *genre, int64_t album_art);
|
||||||
|
|
||||||
int64_t
|
int64_t
|
||||||
GetAudioMetadata(const char *path, char *name);
|
GetAudioMetadata(const char *path, const char *name);
|
||||||
|
|
||||||
int64_t
|
int64_t
|
||||||
GetImageMetadata(const char *path, char *name);
|
GetImageMetadata(const char *path, const char *name);
|
||||||
|
|
||||||
int64_t
|
int64_t
|
||||||
GetVideoMetadata(const char *path, char *name);
|
GetVideoMetadata(const char *path, const char *name);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
32
monitor.c
32
monitor.c
@ -327,8 +327,20 @@ monitor_remove_file(const char * path)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
static char *
|
||||||
monitor_insert_file(char * name, const char * path)
|
check_nfo(const char *path)
|
||||||
|
{
|
||||||
|
char file[PATH_MAX];
|
||||||
|
|
||||||
|
strncpyt(file, path, sizeof(file));
|
||||||
|
strip_ext(file);
|
||||||
|
|
||||||
|
return sql_get_text_field(db, "SELECT PATH from DETAILS where (PATH > '%q.' and PATH <= '%q.z')"
|
||||||
|
" and MIME glob 'video/*' limit 1", file, file);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
monitor_insert_file(const char *name, const char *path)
|
||||||
{
|
{
|
||||||
int len;
|
int len;
|
||||||
char *last_dir;
|
char *last_dir;
|
||||||
@ -337,6 +349,7 @@ monitor_insert_file(char * name, const char * path)
|
|||||||
char *base_copy;
|
char *base_copy;
|
||||||
char *parent_buf = NULL;
|
char *parent_buf = NULL;
|
||||||
char *id = NULL;
|
char *id = NULL;
|
||||||
|
char video[PATH_MAX];
|
||||||
int depth = 1;
|
int depth = 1;
|
||||||
int ts;
|
int ts;
|
||||||
media_types types = ALL_MEDIA;
|
media_types types = ALL_MEDIA;
|
||||||
@ -348,6 +361,21 @@ monitor_insert_file(char * name, const char * path)
|
|||||||
update_if_album_art(path);
|
update_if_album_art(path);
|
||||||
else if( is_caption(path) )
|
else if( is_caption(path) )
|
||||||
check_for_captions(path, 0);
|
check_for_captions(path, 0);
|
||||||
|
else if( is_nfo(path) )
|
||||||
|
{
|
||||||
|
char *vpath = check_nfo(path);
|
||||||
|
if (!vpath)
|
||||||
|
return -1;
|
||||||
|
strncpyt(video, vpath, sizeof(video));
|
||||||
|
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++;
|
||||||
|
}
|
||||||
|
|
||||||
/* Check if we're supposed to be scanning for this file type in this directory */
|
/* Check if we're supposed to be scanning for this file type in this directory */
|
||||||
while( media_path )
|
while( media_path )
|
||||||
|
14
monitor.h
14
monitor.h
@ -1,14 +1,6 @@
|
|||||||
int
|
int monitor_insert_directory(int fd, char *name, const char * path);
|
||||||
monitor_insert_file(char * name, const char * path);
|
int monitor_remove_file(const char * path);
|
||||||
|
int monitor_remove_directory(int fd, const char * path);
|
||||||
int
|
|
||||||
monitor_insert_directory(int fd, char *name, const char * path);
|
|
||||||
|
|
||||||
int
|
|
||||||
monitor_remove_file(const char * path);
|
|
||||||
|
|
||||||
int
|
|
||||||
monitor_remove_directory(int fd, const char * path);
|
|
||||||
|
|
||||||
#ifdef HAVE_INOTIFY
|
#ifdef HAVE_INOTIFY
|
||||||
void *
|
void *
|
||||||
|
15
playlist.c
15
playlist.c
@ -37,11 +37,12 @@
|
|||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
|
||||||
int
|
int
|
||||||
insert_playlist(const char * path, char * name)
|
insert_playlist(const char *path, const char *name)
|
||||||
{
|
{
|
||||||
struct song_metadata plist;
|
struct song_metadata plist;
|
||||||
struct stat file;
|
struct stat file;
|
||||||
int items = 0, matches, ret;
|
int items = 0, matches, ret;
|
||||||
|
char *objname;
|
||||||
char type[4];
|
char type[4];
|
||||||
|
|
||||||
strncpyt(type, strrchr(name, '.')+1, 4);
|
strncpyt(type, strrchr(name, '.')+1, 4);
|
||||||
@ -61,18 +62,19 @@ insert_playlist(const char * path, char * name)
|
|||||||
DPRINTF(E_WARN, L_SCANNER, "Bad playlist [%s]\n", path);
|
DPRINTF(E_WARN, L_SCANNER, "Bad playlist [%s]\n", path);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
strip_ext(name);
|
objname = strdup(name);
|
||||||
|
strip_ext(objname);
|
||||||
|
|
||||||
DPRINTF(E_DEBUG, L_SCANNER, "Playlist %s contains %d items\n", name, items);
|
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'", name);
|
matches = sql_get_int_field(db, "SELECT count(*) from PLAYLISTS where NAME = '%q'", objname);
|
||||||
if( matches > 0 )
|
if( matches > 0 )
|
||||||
{
|
{
|
||||||
sql_exec(db, "INSERT into PLAYLISTS"
|
sql_exec(db, "INSERT into PLAYLISTS"
|
||||||
" (NAME, PATH, ITEMS) "
|
" (NAME, PATH, ITEMS) "
|
||||||
"VALUES"
|
"VALUES"
|
||||||
" ('%q(%d)', '%q', %d)",
|
" ('%q(%d)', '%q', %d)",
|
||||||
name, matches, path, items);
|
objname, matches, path, items);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -80,8 +82,9 @@ insert_playlist(const char * path, char * name)
|
|||||||
" (NAME, PATH, ITEMS) "
|
" (NAME, PATH, ITEMS) "
|
||||||
"VALUES"
|
"VALUES"
|
||||||
" ('%q', '%q', %d)",
|
" ('%q', '%q', %d)",
|
||||||
name, path, items);
|
objname, path, items);
|
||||||
}
|
}
|
||||||
|
free(objname);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,10 +24,7 @@
|
|||||||
#ifndef __PLAYLIST_H__
|
#ifndef __PLAYLIST_H__
|
||||||
#define __PLAYLIST_H__
|
#define __PLAYLIST_H__
|
||||||
|
|
||||||
int
|
int insert_playlist(const char *path, const char *name);
|
||||||
insert_playlist(const char * path, char * name);
|
int fill_playlists(void);
|
||||||
|
|
||||||
int
|
|
||||||
fill_playlists(void);
|
|
||||||
|
|
||||||
#endif // __PLAYLIST_H__
|
#endif // __PLAYLIST_H__
|
||||||
|
20
scanner.c
20
scanner.c
@ -447,7 +447,7 @@ insert_directory(const char *name, const char *path, const char *base, const cha
|
|||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
insert_file(char *name, const char *path, const char *parentID, int object, media_types types)
|
insert_file(const char *name, const char *path, const char *parentID, int object, media_types types)
|
||||||
{
|
{
|
||||||
char class[32];
|
char class[32];
|
||||||
char objectID[64];
|
char objectID[64];
|
||||||
@ -455,7 +455,7 @@ insert_file(char *name, const char *path, const char *parentID, int object, medi
|
|||||||
char base[8];
|
char base[8];
|
||||||
char *typedir_parentID;
|
char *typedir_parentID;
|
||||||
char *baseid;
|
char *baseid;
|
||||||
char *orig_name = NULL;
|
char *objname;
|
||||||
|
|
||||||
if( (types & TYPE_IMAGES) && is_image(name) )
|
if( (types & TYPE_IMAGES) && is_image(name) )
|
||||||
{
|
{
|
||||||
@ -467,12 +467,9 @@ insert_file(char *name, const char *path, const char *parentID, int object, medi
|
|||||||
}
|
}
|
||||||
else if( (types & TYPE_VIDEO) && is_video(name) )
|
else if( (types & TYPE_VIDEO) && is_video(name) )
|
||||||
{
|
{
|
||||||
orig_name = strdup(name);
|
|
||||||
strcpy(base, VIDEO_DIR_ID);
|
strcpy(base, VIDEO_DIR_ID);
|
||||||
strcpy(class, "item.videoItem");
|
strcpy(class, "item.videoItem");
|
||||||
detailID = GetVideoMetadata(path, name);
|
detailID = GetVideoMetadata(path, name);
|
||||||
if( !detailID )
|
|
||||||
strcpy(name, orig_name);
|
|
||||||
}
|
}
|
||||||
else if( is_playlist(name) )
|
else if( is_playlist(name) )
|
||||||
{
|
{
|
||||||
@ -485,7 +482,6 @@ insert_file(char *name, const char *path, const char *parentID, int object, medi
|
|||||||
strcpy(class, "item.audioItem.musicTrack");
|
strcpy(class, "item.audioItem.musicTrack");
|
||||||
detailID = GetAudioMetadata(path, name);
|
detailID = GetAudioMetadata(path, name);
|
||||||
}
|
}
|
||||||
free(orig_name);
|
|
||||||
if( !detailID )
|
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);
|
||||||
@ -493,12 +489,14 @@ insert_file(char *name, const char *path, const char *parentID, int object, medi
|
|||||||
}
|
}
|
||||||
|
|
||||||
sprintf(objectID, "%s%s$%X", BROWSEDIR_ID, parentID, object);
|
sprintf(objectID, "%s%s$%X", BROWSEDIR_ID, parentID, object);
|
||||||
|
objname = strdup(name);
|
||||||
|
strip_ext(objname);
|
||||||
|
|
||||||
sql_exec(db, "INSERT into OBJECTS"
|
sql_exec(db, "INSERT into OBJECTS"
|
||||||
" (OBJECT_ID, PARENT_ID, CLASS, DETAIL_ID, NAME) "
|
" (OBJECT_ID, PARENT_ID, CLASS, DETAIL_ID, NAME) "
|
||||||
"VALUES"
|
"VALUES"
|
||||||
" ('%s', '%s%s', '%s', %lld, '%q')",
|
" ('%s', '%s%s', '%s', %lld, '%q')",
|
||||||
objectID, BROWSEDIR_ID, parentID, class, detailID, name);
|
objectID, BROWSEDIR_ID, parentID, class, detailID, objname);
|
||||||
|
|
||||||
if( *parentID )
|
if( *parentID )
|
||||||
{
|
{
|
||||||
@ -510,16 +508,18 @@ insert_file(char *name, const char *path, const char *parentID, int object, medi
|
|||||||
typedir_objectID = strtol(baseid+1, NULL, 16);
|
typedir_objectID = strtol(baseid+1, NULL, 16);
|
||||||
*baseid = '\0';
|
*baseid = '\0';
|
||||||
}
|
}
|
||||||
insert_directory(name, path, base, typedir_parentID, typedir_objectID);
|
insert_directory(objname, path, base, typedir_parentID, typedir_objectID);
|
||||||
free(typedir_parentID);
|
free(typedir_parentID);
|
||||||
}
|
}
|
||||||
sql_exec(db, "INSERT into OBJECTS"
|
sql_exec(db, "INSERT into OBJECTS"
|
||||||
" (OBJECT_ID, PARENT_ID, REF_ID, CLASS, DETAIL_ID, NAME) "
|
" (OBJECT_ID, PARENT_ID, REF_ID, CLASS, DETAIL_ID, NAME) "
|
||||||
"VALUES"
|
"VALUES"
|
||||||
" ('%s%s$%X', '%s%s', '%s', '%s', %lld, '%q')",
|
" ('%s%s$%X', '%s%s', '%s', '%s', %lld, '%q')",
|
||||||
base, parentID, object, base, parentID, objectID, class, detailID, name);
|
base, parentID, object, base, parentID, objectID, class, detailID, objname);
|
||||||
|
|
||||||
|
insert_containers(objname, path, objectID, class, detailID);
|
||||||
|
free(objname);
|
||||||
|
|
||||||
insert_containers(name, path, objectID, class, detailID);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,7 +75,7 @@ int64_t
|
|||||||
insert_directory(const char *name, const char *path, const char *base, const char *parentID, int objectID);
|
insert_directory(const char *name, const char *path, const char *base, const char *parentID, int objectID);
|
||||||
|
|
||||||
int
|
int
|
||||||
insert_file(char *name, const char *path, const char *parentID, int object, media_types dir_types);
|
insert_file(const char *name, const char *path, const char *parentID, int object, media_types dir_types);
|
||||||
|
|
||||||
int
|
int
|
||||||
CreateDatabase(void);
|
CreateDatabase(void);
|
||||||
|
2
utils.c
2
utils.c
@ -249,6 +249,8 @@ strip_ext(char *name)
|
|||||||
{
|
{
|
||||||
char *period;
|
char *period;
|
||||||
|
|
||||||
|
if (!name)
|
||||||
|
return NULL;
|
||||||
period = strrchr(name, '.');
|
period = strrchr(name, '.');
|
||||||
if (period)
|
if (period)
|
||||||
*period = '\0';
|
*period = '\0';
|
||||||
|
2
utils.h
2
utils.h
@ -89,6 +89,8 @@ int is_audio(const char * file);
|
|||||||
int is_image(const char * file);
|
int is_image(const char * file);
|
||||||
int is_playlist(const char * file);
|
int is_playlist(const char * file);
|
||||||
int is_caption(const char * file);
|
int is_caption(const char * file);
|
||||||
|
#define is_nfo(file) ends_with(file, ".nfo")
|
||||||
|
|
||||||
int is_album_art(const char * name);
|
int is_album_art(const char * name);
|
||||||
int resolve_unknown_type(const char * path, media_types dir_type);
|
int resolve_unknown_type(const char * path, media_types dir_type);
|
||||||
const char *mime_to_ext(const char * mime);
|
const char *mime_to_ext(const char * mime);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user