mirror of
https://github.com/owntone/owntone-server.git
synced 2025-01-27 06:33:21 -05:00
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:
parent
bcb19908f4
commit
dadba23efc
128
src/library.c
128
src/library.c
@ -42,7 +42,6 @@
|
||||
#include "commands.h"
|
||||
#include "conffile.h"
|
||||
#include "db.h"
|
||||
#include "library/filescanner.h"
|
||||
#include "logger.h"
|
||||
#include "misc.h"
|
||||
#include "listener.h"
|
||||
@ -345,109 +344,20 @@ fixup_tags(struct media_file_info *mfi)
|
||||
}
|
||||
|
||||
void
|
||||
library_process_media(const char *path, time_t mtime, off_t size, enum data_kind data_kind, enum media_kind force_media_kind, bool force_compilation, struct media_file_info *external_mfi, int dir_id)
|
||||
library_process_media(struct media_file_info *mfi)
|
||||
{
|
||||
struct media_file_info *mfi;
|
||||
const char *filename;
|
||||
time_t stamp;
|
||||
int id;
|
||||
char virtual_path[PATH_MAX];
|
||||
int ret;
|
||||
|
||||
filename = strrchr(path, '/');
|
||||
if ((!filename) || (strlen(filename) == 1))
|
||||
filename = path;
|
||||
else
|
||||
filename++;
|
||||
|
||||
db_file_stamp_bypath(path, &stamp, &id);
|
||||
|
||||
if (stamp && (stamp >= mtime))
|
||||
if (!mfi->path || !mfi->fname || !mfi->data_kind)
|
||||
{
|
||||
db_file_ping(id);
|
||||
DPRINTF(E_LOG, L_LIB, "Ignoring media file with missing values (path='%s', fname='%s', data_kind='%d')\n",
|
||||
mfi->path, mfi->fname, mfi->data_kind);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!external_mfi)
|
||||
if (!mfi->directory_id || mfi->virtual_path)
|
||||
{
|
||||
mfi = (struct media_file_info*)malloc(sizeof(struct media_file_info));
|
||||
if (!mfi)
|
||||
{
|
||||
DPRINTF(E_LOG, L_LIB, "Out of memory for mfi\n");
|
||||
return;
|
||||
}
|
||||
|
||||
memset(mfi, 0, sizeof(struct media_file_info));
|
||||
}
|
||||
else
|
||||
mfi = external_mfi;
|
||||
|
||||
if (stamp)
|
||||
mfi->id = id;
|
||||
|
||||
mfi->fname = strdup(filename);
|
||||
if (!mfi->fname)
|
||||
{
|
||||
DPRINTF(E_LOG, L_LIB, "Out of memory for fname\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
mfi->path = strdup(path);
|
||||
if (!mfi->path)
|
||||
{
|
||||
DPRINTF(E_LOG, L_LIB, "Out of memory for path\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
mfi->time_modified = mtime;
|
||||
mfi->file_size = size;
|
||||
|
||||
if (force_compilation)
|
||||
mfi->compilation = 1;
|
||||
if (force_media_kind)
|
||||
mfi->media_kind = force_media_kind;
|
||||
|
||||
if (data_kind == DATA_KIND_FILE)
|
||||
{
|
||||
mfi->data_kind = DATA_KIND_FILE;
|
||||
ret = scan_metadata_ffmpeg(path, mfi);
|
||||
}
|
||||
else if (data_kind == DATA_KIND_HTTP)
|
||||
{
|
||||
mfi->data_kind = DATA_KIND_HTTP;
|
||||
ret = scan_metadata_ffmpeg(path, mfi);
|
||||
if (ret < 0)
|
||||
{
|
||||
DPRINTF(E_LOG, L_LIB, "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");
|
||||
ret = 1;
|
||||
}
|
||||
}
|
||||
else if (data_kind == DATA_KIND_SPOTIFY)
|
||||
{
|
||||
mfi->data_kind = DATA_KIND_SPOTIFY;
|
||||
ret = mfi->artist && mfi->album && mfi->title;
|
||||
}
|
||||
else if (data_kind == DATA_KIND_PIPE)
|
||||
{
|
||||
mfi->data_kind = DATA_KIND_PIPE;
|
||||
mfi->type = strdup("wav");
|
||||
mfi->codectype = strdup("wav");
|
||||
mfi->description = strdup("PCM16 pipe");
|
||||
ret = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
DPRINTF(E_LOG, L_LIB, "Unknown scan type for '%s', this error should not occur\n", path);
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
if (ret < 0)
|
||||
{
|
||||
DPRINTF(E_INFO, L_LIB, "Could not extract metadata for '%s'\n", path);
|
||||
goto out;
|
||||
// Missing informations for virtual_path and directory_id (may) lead to misplaced appearance in mpd clients
|
||||
DPRINTF(E_WARN, L_LIB, "Media file with missing values (path='%s', directory='%d', virtual_path='%s')\n",
|
||||
mfi->path, mfi->directory_id, mfi->virtual_path);
|
||||
}
|
||||
|
||||
if (!mfi->item_kind)
|
||||
@ -459,32 +369,10 @@ library_process_media(const char *path, time_t mtime, off_t size, enum data_kind
|
||||
|
||||
fixup_tags(mfi);
|
||||
|
||||
if (data_kind == DATA_KIND_HTTP)
|
||||
{
|
||||
snprintf(virtual_path, PATH_MAX, "/http:/%s", mfi->title);
|
||||
mfi->virtual_path = strdup(virtual_path);
|
||||
}
|
||||
else if (data_kind == DATA_KIND_SPOTIFY)
|
||||
{
|
||||
snprintf(virtual_path, PATH_MAX, "/spotify:/%s/%s/%s", mfi->album_artist, mfi->album, mfi->title);
|
||||
mfi->virtual_path = strdup(virtual_path);
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf(virtual_path, PATH_MAX, "/file:%s", mfi->path);
|
||||
mfi->virtual_path = strdup(virtual_path);
|
||||
}
|
||||
|
||||
mfi->directory_id = dir_id;
|
||||
|
||||
if (mfi->id == 0)
|
||||
db_file_add(mfi);
|
||||
else
|
||||
db_file_update(mfi);
|
||||
|
||||
out:
|
||||
if (!external_mfi)
|
||||
free_mfi(mfi, 0);
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -66,7 +66,7 @@ struct library_source
|
||||
|
||||
|
||||
void
|
||||
library_process_media(const char *path, time_t mtime, off_t size, enum data_kind data_kind, enum media_kind force_media_kind, bool force_compilation, struct media_file_info *external_mfi, int dir_id);
|
||||
library_process_media(struct media_file_info *mfi);
|
||||
|
||||
int
|
||||
library_add_playlist_info(const char *path, const char *title, const char *virtual_path, enum pl_type type, int parent_pl_id, int dir_id);
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -640,7 +640,10 @@ spotify_track_save(int plid, sp_track *track, const char *pltitle, int time_adde
|
||||
sp_link *link;
|
||||
char url[1024];
|
||||
int ret;
|
||||
char virtual_path[PATH_MAX];
|
||||
int dir_id;
|
||||
time_t stamp;
|
||||
int id;
|
||||
|
||||
memset(&mfi, 0, sizeof(struct media_file_info));
|
||||
|
||||
@ -697,7 +700,18 @@ spotify_track_save(int plid, sp_track *track, const char *pltitle, int time_adde
|
||||
|
||||
// DPRINTF(E_DBG, L_SPOTIFY, "Saving track '%s': '%s' by %s (%s)\n", url, mfi.title, mfi.artist, mfi.album);
|
||||
|
||||
library_process_media(url, time(NULL), 0, DATA_KIND_SPOTIFY, 0, false, &mfi, dir_id);
|
||||
db_file_stamp_bypath(url, &stamp, &id);
|
||||
|
||||
mfi.id = id;
|
||||
mfi.path = strdup(url);
|
||||
mfi.fname = strdup(url);
|
||||
mfi.time_modified = time(NULL);
|
||||
mfi.data_kind = DATA_KIND_SPOTIFY;
|
||||
snprintf(virtual_path, PATH_MAX, "/spotify:/%s/%s/%s", mfi.album_artist, mfi.album, mfi.title);
|
||||
mfi.virtual_path = strdup(virtual_path);
|
||||
mfi.directory_id = dir_id;
|
||||
|
||||
library_process_media(&mfi);
|
||||
|
||||
free_mfi(&mfi, 1);
|
||||
|
||||
@ -2008,6 +2022,9 @@ map_track_to_mfi(const struct spotify_track *track, struct media_file_info* mfi)
|
||||
mfi->type = strdup("spotify");
|
||||
mfi->codectype = strdup("wav");
|
||||
mfi->description = strdup("Spotify audio");
|
||||
|
||||
mfi->path = strdup(track->uri);
|
||||
mfi->fname = strdup(track->uri);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -2018,6 +2035,7 @@ map_album_to_mfi(const struct spotify_album *album, struct media_file_info* mfi)
|
||||
mfi->genre = safe_strdup(album->genre);
|
||||
mfi->compilation = album->is_compilation;
|
||||
mfi->year = album->release_year;
|
||||
mfi->time_modified = album->mtime;
|
||||
}
|
||||
|
||||
/* Thread: library */
|
||||
@ -2030,7 +2048,10 @@ scan_saved_albums()
|
||||
struct spotify_album album;
|
||||
struct spotify_track track;
|
||||
struct media_file_info mfi;
|
||||
char virtual_path[PATH_MAX];
|
||||
int dir_id;
|
||||
time_t stamp;
|
||||
int id;
|
||||
int i;
|
||||
int count;
|
||||
int ret;
|
||||
@ -2054,17 +2075,34 @@ scan_saved_albums()
|
||||
ret = spotifywebapi_album_track_fetch(jsontracks, i, &track);
|
||||
if (ret == 0 && track.uri)
|
||||
{
|
||||
memset(&mfi, 0, sizeof(struct media_file_info));
|
||||
map_track_to_mfi(&track, &mfi);
|
||||
map_album_to_mfi(&album, &mfi);
|
||||
db_file_stamp_bypath(track.uri, &stamp, &id);
|
||||
if (stamp && (stamp >= track.mtime))
|
||||
{
|
||||
db_file_ping(id);
|
||||
}
|
||||
else
|
||||
{
|
||||
memset(&mfi, 0, sizeof(struct media_file_info));
|
||||
|
||||
mfi.id = id;
|
||||
|
||||
map_track_to_mfi(&track, &mfi);
|
||||
map_album_to_mfi(&album, &mfi);
|
||||
|
||||
mfi.data_kind = DATA_KIND_SPOTIFY;
|
||||
snprintf(virtual_path, PATH_MAX, "/spotify:/%s/%s/%s", mfi.album_artist, mfi.album, mfi.title);
|
||||
mfi.virtual_path = strdup(virtual_path);
|
||||
mfi.directory_id = dir_id;
|
||||
|
||||
library_process_media(&mfi);
|
||||
|
||||
free_mfi(&mfi, 1);
|
||||
}
|
||||
|
||||
library_process_media(track.uri, album.mtime, 0, DATA_KIND_SPOTIFY, 0, album.is_compilation, &mfi, dir_id);
|
||||
spotify_uri_register(track.uri);
|
||||
|
||||
cache_artwork_ping(track.uri, album.mtime, 0);
|
||||
|
||||
free_mfi(&mfi, 1);
|
||||
|
||||
if (spotify_saved_plid)
|
||||
db_pl_add_item_bypath(spotify_saved_plid, track.uri);
|
||||
}
|
||||
@ -2093,7 +2131,10 @@ scan_playlisttracks(struct spotify_playlist *playlist, int plid)
|
||||
struct spotify_request request;
|
||||
struct spotify_track track;
|
||||
struct media_file_info mfi;
|
||||
char virtual_path[PATH_MAX];
|
||||
int dir_id;
|
||||
time_t stamp;
|
||||
int id;
|
||||
|
||||
memset(&request, 0, sizeof(struct spotify_request));
|
||||
|
||||
@ -2121,9 +2162,19 @@ scan_playlisttracks(struct spotify_playlist *playlist, int plid)
|
||||
if (track.linked_from_uri)
|
||||
DPRINTF(E_DBG, L_SPOTIFY, "Track '%s' (%s) linked from %s\n", track.name, track.uri, track.linked_from_uri);
|
||||
|
||||
dir_id = prepare_directories(track.album_artist, track.album);
|
||||
db_file_stamp_bypath(track.uri, &stamp, &id);
|
||||
if (stamp)
|
||||
{
|
||||
db_file_ping(id);
|
||||
continue;
|
||||
}
|
||||
|
||||
memset(&mfi, 0, sizeof(struct media_file_info));
|
||||
|
||||
mfi.id = id;
|
||||
|
||||
dir_id = prepare_directories(track.album_artist, track.album);
|
||||
|
||||
map_track_to_mfi(&track, &mfi);
|
||||
|
||||
mfi.compilation = (track.is_compilation || artist_override);
|
||||
@ -2133,7 +2184,14 @@ scan_playlisttracks(struct spotify_playlist *playlist, int plid)
|
||||
mfi.album = strdup(playlist->name);
|
||||
}
|
||||
|
||||
library_process_media(track.uri, 1 /* TODO passing one prevents overwriting existing entries */, 0, DATA_KIND_SPOTIFY, 0, track.is_compilation, &mfi, dir_id);
|
||||
mfi.time_modified = time(NULL);
|
||||
mfi.data_kind = DATA_KIND_SPOTIFY;
|
||||
snprintf(virtual_path, PATH_MAX, "/spotify:/%s/%s/%s", mfi.album_artist, mfi.album, mfi.title);
|
||||
mfi.virtual_path = strdup(virtual_path);
|
||||
mfi.directory_id = dir_id;
|
||||
|
||||
library_process_media(&mfi);
|
||||
|
||||
spotify_uri_register(track.uri);
|
||||
|
||||
cache_artwork_ping(track.uri, 1, 0);
|
||||
|
Loading…
x
Reference in New Issue
Block a user