Refactor library scan of media files

Remove the data_kind specific parts out of the general library functions
and into their (library) source specific functions.
This commit is contained in:
chme
2017-01-29 10:01:05 +01:00
committed by ejurgensen
parent bcb19908f4
commit dadba23efc
6 changed files with 257 additions and 255 deletions

View File

@@ -77,6 +77,12 @@
#define F_SCAN_FAST (1 << 2)
#define F_SCAN_MOVED (1 << 3)
#define F_SCAN_TYPE_FILE (1 << 0)
#define F_SCAN_TYPE_PODCAST (1 << 1)
#define F_SCAN_TYPE_AUDIOBOOK (1 << 2)
#define F_SCAN_TYPE_COMPILATION (1 << 3)
enum file_type {
FILE_UNKNOWN = 0,
FILE_IGNORE,
@@ -389,37 +395,83 @@ process_deferred_playlists(void)
}
}
static void
process_regular_file(char *file, struct stat *sb, int type, int flags, int dir_id)
{
time_t stamp;
int id;
bool is_bulkscan = (flags & F_SCAN_BULK);
struct media_file_info mfi;
char virtual_path[PATH_MAX];
int ret;
// Do not rescan metadata if file did not change since last scan
db_file_stamp_bypath(file, &stamp, &id);
if (stamp && (stamp >= sb->st_mtime))
{
db_file_ping(id);
return;
}
// File is new or modified - (re)scan metadata and update file in library
memset(&mfi, 0, sizeof(struct media_file_info));
mfi.id = id;
mfi.fname = strdup(basename(file));
mfi.path = strdup(file);
mfi.time_modified = sb->st_mtime;
mfi.file_size = sb->st_size;
snprintf(virtual_path, PATH_MAX, "/file:%s", file);
mfi.virtual_path = strdup(virtual_path);
mfi.directory_id = dir_id;
if (S_ISFIFO(sb->st_mode))
{
mfi.data_kind = DATA_KIND_PIPE;
mfi.type = strdup("wav");
mfi.codectype = strdup("wav");
mfi.description = strdup("PCM16 pipe");
mfi.media_kind = MEDIA_KIND_MUSIC;
}
else
{
mfi.data_kind = DATA_KIND_FILE;
if (type & F_SCAN_TYPE_AUDIOBOOK)
mfi.media_kind = MEDIA_KIND_AUDIOBOOK;
else if (type & F_SCAN_TYPE_PODCAST)
mfi.media_kind = MEDIA_KIND_PODCAST;
mfi.compilation = (type & F_SCAN_TYPE_COMPILATION);
mfi.file_size = sb->st_size;
ret = scan_metadata_ffmpeg(file, &mfi);
if (ret < 0)
{
free_mfi(&mfi, 1);
return;
}
}
library_process_media(&mfi);
cache_artwork_ping(file, sb->st_mtime, !is_bulkscan);
// TODO [artworkcache] If entry in artwork cache exists for no artwork available, delete the entry if media file has embedded artwork
free_mfi(&mfi, 1);
}
/* Thread: scan */
static void
process_file(char *file, time_t mtime, off_t size, int type, int flags, int dir_id)
process_file(char *file, struct stat *sb, int type, int flags, int dir_id)
{
bool is_bulkscan;
bool is_type_compilation;
enum media_kind media_kind;
enum data_kind data_kind;
is_bulkscan = (flags & F_SCAN_BULK);
switch (file_type_get(file))
{
case FILE_REGULAR:
is_type_compilation = type & F_SCAN_TYPE_COMPILATION;
if (type & F_SCAN_TYPE_AUDIOBOOK)
media_kind = MEDIA_KIND_AUDIOBOOK;
else if (type & F_SCAN_TYPE_PODCAST)
media_kind = MEDIA_KIND_PODCAST;
else
media_kind = 0;
if (F_SCAN_TYPE_PIPE & type)
data_kind = DATA_KIND_PIPE;
else
data_kind = DATA_KIND_FILE;
library_process_media(file, mtime, size, data_kind, media_kind, is_type_compilation, NULL, dir_id);
cache_artwork_ping(file, mtime, !is_bulkscan);
// TODO [artworkcache] If entry in artwork cache exists for no artwork available, delete the entry if media file has embedded artwork
process_regular_file(file, sb, type, flags, dir_id);
counter++;
@@ -435,19 +487,19 @@ process_file(char *file, time_t mtime, off_t size, int type, int flags, int dir_
case FILE_PLAYLIST:
case FILE_ITUNES:
if (flags & F_SCAN_BULK)
defer_playlist(file, mtime, dir_id);
defer_playlist(file, sb->st_mtime, dir_id);
else
process_playlist(file, mtime, dir_id);
process_playlist(file, sb->st_mtime, dir_id);
break;
case FILE_SMARTPL:
DPRINTF(E_DBG, L_SCAN, "Smart playlist file: %s\n", file);
scan_smartpl(file, mtime, dir_id);
scan_smartpl(file, sb->st_mtime, dir_id);
break;
case FILE_ARTWORK:
DPRINTF(E_DBG, L_SCAN, "Artwork file: %s\n", file);
cache_artwork_ping(file, mtime, !is_bulkscan);
cache_artwork_ping(file, sb->st_mtime, !(flags & F_SCAN_BULK));
// TODO [artworkcache] If entry in artwork cache exists for no artwork available for a album with files in the same directory, delete the entry
@@ -539,13 +591,58 @@ create_virtual_path(char *path, char *virtual_path, int virtual_path_len)
return 0;
}
/*
* Returns informations about the attributes of the file at the given 'path' in the structure
* pointed to by 'sb'.
*
* If path is a symbolic link, the attributes in sb describe the file that the link points to
* and resolved_path contains the resolved path (resolved_path must be of length PATH_MAX).
* If path is not a symbolic link, resolved_path holds the same value as path.
*
* The return value is 0 if the operation is successful, or -1 on failure. In addition
*/
static int
read_attributes(const char *path, struct stat *sb, char *resolved_path)
{
int ret;
ret = lstat(path, sb);
if (ret < 0)
{
DPRINTF(E_LOG, L_SCAN, "Skipping %s, lstat() failed: %s\n", path, strerror(errno));
return -1;
}
if (S_ISLNK(sb->st_mode))
{
if (!realpath(path, resolved_path))
{
DPRINTF(E_LOG, L_SCAN, "Skipping %s, could not dereference symlink: %s\n", path, strerror(errno));
return -1;
}
ret = stat(resolved_path, sb);
if (ret < 0)
{
DPRINTF(E_LOG, L_SCAN, "Skipping %s, stat() failed: %s\n", resolved_path, strerror(errno));
return -1;
}
}
else
{
strcpy(resolved_path, path);
}
return 0;
}
static void
process_directory(char *path, int parent_id, int flags)
{
DIR *dirp;
struct dirent *de;
char entry[PATH_MAX];
char *deref;
char resolved_path[PATH_MAX];
struct stat sb;
struct watch_info wi;
int type;
@@ -612,59 +709,25 @@ process_directory(char *path, int parent_id, int flags)
continue;
}
ret = lstat(entry, &sb);
ret = read_attributes(entry, &sb, resolved_path);
if (ret < 0)
{
DPRINTF(E_LOG, L_SCAN, "Skipping %s, lstat() failed: %s\n", entry, strerror(errno));
DPRINTF(E_LOG, L_SCAN, "Skipping %s, read_attributes() failed\n", entry);
continue;
}
if (S_ISLNK(sb.st_mode))
if (S_ISDIR(sb.st_mode))
{
deref = m_realpath(entry);
if (!deref)
{
DPRINTF(E_LOG, L_SCAN, "Skipping %s, could not dereference symlink: %s\n", entry, strerror(errno));
continue;
}
ret = stat(deref, &sb);
if (ret < 0)
{
DPRINTF(E_LOG, L_SCAN, "Skipping %s, stat() failed: %s\n", deref, strerror(errno));
free(deref);
continue;
}
ret = snprintf(entry, sizeof(entry), "%s", deref);
if ((ret < 0) || (ret >= sizeof(entry)))
{
DPRINTF(E_LOG, L_SCAN, "Skipping %s, PATH_MAX exceeded\n", entry);
free(deref);
continue;
}
free(deref);
push_dir(&dirstack, resolved_path, dir_id);
}
if (S_ISREG(sb.st_mode))
else if (!(flags & F_SCAN_FAST))
{
if (!(flags & F_SCAN_FAST))
process_file(entry, sb.st_mtime, sb.st_size, F_SCAN_TYPE_FILE | type, flags, dir_id);
if (S_ISREG(sb.st_mode) || S_ISFIFO(sb.st_mode))
process_file(resolved_path, &sb, type, flags, dir_id);
else
DPRINTF(E_LOG, L_SCAN, "Skipping %s, not a directory, symlink, pipe nor regular file\n", entry);
}
else if (S_ISFIFO(sb.st_mode))
{
if (!(flags & F_SCAN_FAST))
process_file(entry, sb.st_mtime, sb.st_size, F_SCAN_TYPE_PIPE | type, flags, dir_id);
}
else if (S_ISDIR(sb.st_mode))
push_dir(&dirstack, entry, dir_id);
else
DPRINTF(E_LOG, L_SCAN, "Skipping %s, not a directory, symlink, pipe nor regular file\n", entry);
}
closedir(dirp);
@@ -1040,8 +1103,8 @@ process_inotify_file(struct watch_info *wi, char *path, struct inotify_event *ie
{
struct stat sb;
uint32_t path_hash;
char *deref = NULL;
char *file = path;
char resolved_path[PATH_MAX];
char *dir;
char dir_vpath[PATH_MAX];
int type;
@@ -1177,44 +1240,14 @@ process_inotify_file(struct watch_info *wi, char *path, struct inotify_event *ie
incomingfiles_buffer[i] = 0;
}
ret = lstat(path, &sb);
ret = read_attributes(path, &sb, resolved_path);
if (ret < 0)
{
DPRINTF(E_LOG, L_SCAN, "Could not lstat() '%s': %s\n", path, strerror(errno));
{
DPRINTF(E_LOG, L_SCAN, "Skipping %s, read_attributes() failed\n", path);
return;
}
if (S_ISLNK(sb.st_mode))
{
deref = m_realpath(path);
if (!deref)
{
DPRINTF(E_LOG, L_SCAN, "Could not dereference symlink '%s': %s\n", path, strerror(errno));
return;
}
file = deref;
ret = stat(deref, &sb);
if (ret < 0)
{
DPRINTF(E_LOG, L_SCAN, "Could not stat() '%s': %s\n", file, strerror(errno));
free(deref);
return;
}
if (S_ISDIR(sb.st_mode))
{
process_inotify_dir(wi, deref, ie);
free(deref);
return;
}
}
type = 0;
if (check_speciallib(path, "compilations"))
type |= F_SCAN_TYPE_COMPILATION;
@@ -1225,15 +1258,18 @@ process_inotify_file(struct watch_info *wi, char *path, struct inotify_event *ie
dir_id = get_parent_dir_id(file);
if (S_ISREG(sb.st_mode))
{
process_file(file, sb.st_mtime, sb.st_size, F_SCAN_TYPE_FILE | type, 0, dir_id);
}
else if (S_ISFIFO(sb.st_mode))
process_file(file, sb.st_mtime, sb.st_size, F_SCAN_TYPE_PIPE | type, 0, dir_id);
if (S_ISDIR(sb.st_mode))
{
process_inotify_dir(wi, resolved_path, ie);
if (deref)
free(deref);
return;
}
else if (S_ISREG(sb.st_mode) || S_ISFIFO(sb.st_mode))
{
process_file(resolved_path, &sb, type, 0, dir_id);
}
else
DPRINTF(E_LOG, L_SCAN, "Skipping %s, not a directory, symlink, pipe nor regular file\n", resolved_path);
}
}

View File

@@ -4,14 +4,6 @@
#include "db.h"
#define F_SCAN_TYPE_FILE (1 << 0)
#define F_SCAN_TYPE_PODCAST (1 << 1)
#define F_SCAN_TYPE_AUDIOBOOK (1 << 2)
#define F_SCAN_TYPE_COMPILATION (1 << 3)
#define F_SCAN_TYPE_URL (1 << 4)
#define F_SCAN_TYPE_SPOTIFY (1 << 5)
#define F_SCAN_TYPE_PIPE (1 << 6)
/* Actual scanners */
int

View File

@@ -33,6 +33,7 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <libgen.h>
#include "logger.h"
#include "db.h"
@@ -94,6 +95,8 @@ scan_playlist(char *file, time_t mtime, int dir_id)
int ret;
char virtual_path[PATH_MAX];
int i;
time_t stamp;
int id;
DPRINTF(E_LOG, L_SCAN, "Processing static playlist: %s\n", file);
@@ -226,7 +229,14 @@ scan_playlist(char *file, time_t mtime, int dir_id)
/* Check if line is an URL, will be added to library */
if (strncasecmp(path, "http://", strlen("http://")) == 0)
{
DPRINTF(E_DBG, L_SCAN, "Playlist contains URL entry\n");
DPRINTF(E_DBG, L_SCAN, "Playlist contains URL entry: '%s'\n", path);
db_file_stamp_bypath(path, &stamp, &id);
if (stamp && (stamp >= sb.st_mtime))
{
db_file_ping(id);
continue;
}
filename = strdup(path);
if (!filename)
@@ -239,7 +249,25 @@ scan_playlist(char *file, time_t mtime, int dir_id)
if (extinf)
DPRINTF(E_INFO, L_SCAN, "Playlist has EXTINF metadata, artist is '%s', title is '%s'\n", mfi.artist, mfi.title);
library_process_media(filename, mtime, 0, DATA_KIND_HTTP, 0, false, &mfi, DIR_HTTP);
mfi.id = id;
mfi.fname = strdup(basename(filename));
mfi.path = strdup(filename);
mfi.data_kind = DATA_KIND_HTTP;
mfi.time_modified = mtime;
mfi.directory_id = DIR_HTTP;
ret = scan_metadata_ffmpeg(path, &mfi);
if (ret < 0)
{
DPRINTF(E_LOG, L_SCAN, "Playlist URL '%s' is unavailable for probe/metadata, assuming MP3 encoding\n", path);
mfi.type = strdup("mp3");
mfi.codectype = strdup("mpeg");
mfi.description = strdup("MPEG audio file");
}
snprintf(virtual_path, PATH_MAX, "/http:/%s", mfi.title); //TODO can title be null at this point?
mfi.virtual_path = strdup(virtual_path);
library_process_media(&mfi);
}
/* Regular file, should already be in library */
else