Refactor adding non library items to the queue

Instead of asking a client to first scan the path into a media_file_info
object and afterwards add it to the queue, we now offer a library
function to directly add a path.

The library-source that can handle the given path translates the path
into new queue item(s) and adds them to the queue.
This commit is contained in:
chme 2018-03-09 19:03:43 +01:00 committed by ejurgensen
parent acd5bd3272
commit 60ebac076b
6 changed files with 516 additions and 427 deletions

450
src/db.c
View File

@ -32,6 +32,9 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <unictype.h>
#include <uninorm.h>
#include <unistr.h>
#include <sys/mman.h>
#include <limits.h>
@ -641,6 +644,324 @@ unicode_fixup_mfi(struct media_file_info *mfi)
}
}
static void
sort_tag_create(char **sort_tag, char *src_tag)
{
const uint8_t *i_ptr;
const uint8_t *n_ptr;
const uint8_t *number;
uint8_t out[1024];
uint8_t *o_ptr;
int append_number;
ucs4_t puc;
int numlen;
size_t len;
int charlen;
/* Note: include terminating NUL in string length for u8_normalize */
if (*sort_tag)
{
DPRINTF(E_DBG, L_LIB, "Existing sort tag will be normalized: %s\n", *sort_tag);
o_ptr = u8_normalize(UNINORM_NFD, (uint8_t *)*sort_tag, strlen(*sort_tag) + 1, NULL, &len);
free(*sort_tag);
*sort_tag = (char *)o_ptr;
return;
}
if (!src_tag || ((len = strlen(src_tag)) == 0))
{
*sort_tag = NULL;
return;
}
// Set input pointer past article if present
if ((strncasecmp(src_tag, "a ", 2) == 0) && (len > 2))
i_ptr = (uint8_t *)(src_tag + 2);
else if ((strncasecmp(src_tag, "an ", 3) == 0) && (len > 3))
i_ptr = (uint8_t *)(src_tag + 3);
else if ((strncasecmp(src_tag, "the ", 4) == 0) && (len > 4))
i_ptr = (uint8_t *)(src_tag + 4);
else
i_ptr = (uint8_t *)src_tag;
// Poor man's natural sort. Makes sure we sort like this: a1, a2, a10, a11, a21, a111
// We do this by padding zeroes to (short) numbers. As an alternative we could have
// made a proper natural sort algorithm in sqlext.c, but we don't, since we don't
// want any risk of hurting response times
memset(&out, 0, sizeof(out));
o_ptr = (uint8_t *)&out;
number = NULL;
append_number = 0;
do
{
n_ptr = u8_next(&puc, i_ptr);
if (uc_is_digit(puc))
{
if (!number) // We have encountered the beginning of a number
number = i_ptr;
append_number = (n_ptr == NULL); // If last char in string append number now
}
else
{
if (number)
append_number = 1; // A number has ended so time to append it
else
{
charlen = u8_strmblen(i_ptr);
if (charlen >= 0)
o_ptr = u8_stpncpy(o_ptr, i_ptr, charlen); // No numbers in sight, just append char
}
}
// Break if less than 100 bytes remain (prevent buffer overflow)
if (sizeof(out) - u8_strlen(out) < 100)
break;
// Break if number is very large (prevent buffer overflow)
if (number && (i_ptr - number > 50))
break;
if (append_number)
{
numlen = i_ptr - number;
if (numlen < 5) // Max pad width
{
u8_strcpy(o_ptr, (uint8_t *)"00000");
o_ptr += (5 - numlen);
}
o_ptr = u8_stpncpy(o_ptr, number, numlen + u8_strmblen(i_ptr));
number = NULL;
append_number = 0;
}
i_ptr = n_ptr;
}
while (n_ptr);
*sort_tag = (char *)u8_normalize(UNINORM_NFD, (uint8_t *)&out, u8_strlen(out) + 1, NULL, &len);
}
void
fixup_tags_mfi(struct media_file_info *mfi)
{
cfg_t *lib;
size_t len;
char *tag;
char *sep = " - ";
char *ca;
if (mfi->genre && (strlen(mfi->genre) == 0))
{
free(mfi->genre);
mfi->genre = NULL;
}
if (mfi->artist && (strlen(mfi->artist) == 0))
{
free(mfi->artist);
mfi->artist = NULL;
}
if (mfi->title && (strlen(mfi->title) == 0))
{
free(mfi->title);
mfi->title = NULL;
}
/*
* Default to mpeg4 video/audio for unknown file types
* in an attempt to allow streaming of DRM-afflicted files
*/
if (mfi->codectype && strcmp(mfi->codectype, "unkn") == 0)
{
if (mfi->has_video)
{
strcpy(mfi->codectype, "mp4v");
strcpy(mfi->type, "m4v");
}
else
{
strcpy(mfi->codectype, "mp4a");
strcpy(mfi->type, "m4a");
}
}
if (!mfi->artist)
{
if (mfi->orchestra && mfi->conductor)
{
len = strlen(mfi->orchestra) + strlen(sep) + strlen(mfi->conductor);
tag = (char *)malloc(len + 1);
if (tag)
{
sprintf(tag,"%s%s%s", mfi->orchestra, sep, mfi->conductor);
mfi->artist = tag;
}
}
else if (mfi->orchestra)
{
mfi->artist = strdup(mfi->orchestra);
}
else if (mfi->conductor)
{
mfi->artist = strdup(mfi->conductor);
}
}
/* Handle TV shows, try to present prettier metadata */
if (mfi->tv_series_name && strlen(mfi->tv_series_name) != 0)
{
mfi->media_kind = MEDIA_KIND_TVSHOW; /* tv show */
/* Default to artist = series_name */
if (mfi->artist && strlen(mfi->artist) == 0)
{
free(mfi->artist);
mfi->artist = NULL;
}
if (!mfi->artist)
mfi->artist = strdup(mfi->tv_series_name);
/* Default to album = "<series_name>, Season <season_num>" */
if (mfi->album && strlen(mfi->album) == 0)
{
free(mfi->album);
mfi->album = NULL;
}
if (!mfi->album)
{
len = snprintf(NULL, 0, "%s, Season %u", mfi->tv_series_name, mfi->tv_season_num);
mfi->album = (char *)malloc(len + 1);
if (mfi->album)
sprintf(mfi->album, "%s, Season %u", mfi->tv_series_name, mfi->tv_season_num);
}
}
/* Check the 4 top-tags are filled */
if (!mfi->artist)
mfi->artist = strdup("Unknown artist");
if (!mfi->album)
mfi->album = strdup("Unknown album");
if (!mfi->genre)
mfi->genre = strdup("Unknown genre");
if (!mfi->title)
{
/* fname is left untouched by unicode_fixup_mfi() for
* obvious reasons, so ensure it is proper UTF-8
*/
mfi->title = unicode_fixup_string(mfi->fname, "ascii");
if (mfi->title == mfi->fname)
mfi->title = strdup(mfi->fname);
}
/* Ensure sort tags are filled, manipulated and normalized */
sort_tag_create(&mfi->artist_sort, mfi->artist);
sort_tag_create(&mfi->album_sort, mfi->album);
sort_tag_create(&mfi->title_sort, mfi->title);
/* We need to set album_artist according to media type and config */
if (mfi->compilation) /* Compilation */
{
lib = cfg_getsec(cfg, "library");
ca = cfg_getstr(lib, "compilation_artist");
if (ca && mfi->album_artist)
{
free(mfi->album_artist);
mfi->album_artist = strdup(ca);
}
else if (ca && !mfi->album_artist)
{
mfi->album_artist = strdup(ca);
}
else if (!ca && !mfi->album_artist)
{
mfi->album_artist = strdup("");
mfi->album_artist_sort = strdup("");
}
}
else if (mfi->media_kind == MEDIA_KIND_PODCAST) /* Podcast */
{
if (mfi->album_artist)
free(mfi->album_artist);
mfi->album_artist = strdup("");
mfi->album_artist_sort = strdup("");
}
else if (!mfi->album_artist) /* Regular media without album_artist */
{
mfi->album_artist = strdup(mfi->artist);
}
if (!mfi->album_artist_sort && (strcmp(mfi->album_artist, mfi->artist) == 0))
mfi->album_artist_sort = strdup(mfi->artist_sort);
else
sort_tag_create(&mfi->album_artist_sort, mfi->album_artist);
/* Composer is not one of our mandatory tags, so take extra care */
if (mfi->composer_sort || mfi->composer)
sort_tag_create(&mfi->composer_sort, mfi->composer);
}
static void
fixup_tags_queue_item(struct db_queue_item *queue_item)
{
if (queue_item->genre && (strlen(queue_item->genre) == 0))
{
free(queue_item->genre);
queue_item->genre = NULL;
}
if (queue_item->artist && (strlen(queue_item->artist) == 0))
{
free(queue_item->artist);
queue_item->artist = NULL;
}
if (queue_item->title && (strlen(queue_item->title) == 0))
{
free(queue_item->title);
queue_item->title = NULL;
}
/* Check the 4 top-tags are filled */
if (!queue_item->artist)
queue_item->artist = strdup("Unknown artist");
if (!queue_item->album)
queue_item->album = strdup("Unknown album");
if (!queue_item->genre)
queue_item->genre = strdup("Unknown genre");
if (!queue_item->title)
queue_item->title = strdup(queue_item->path);
/* Ensure sort tags are filled, manipulated and normalized */
sort_tag_create(&queue_item->artist_sort, queue_item->artist);
sort_tag_create(&queue_item->album_sort, queue_item->album);
/* We need to set album_artist according to media type and config */
if (queue_item->media_kind == MEDIA_KIND_PODCAST) /* Podcast */
{
if (queue_item->album_artist)
free(queue_item->album_artist);
queue_item->album_artist = strdup("");
queue_item->album_artist_sort = strdup("");
}
else if (!queue_item->album_artist) /* Regular media without album_artist */
{
queue_item->album_artist = strdup(queue_item->artist);
}
if (!queue_item->album_artist_sort && (strcmp(queue_item->album_artist, queue_item->artist) == 0))
queue_item->album_artist_sort = strdup(queue_item->artist_sort);
else
sort_tag_create(&queue_item->album_artist_sort, queue_item->album_artist);
}
/* Unlock notification support */
static void
@ -4219,6 +4540,38 @@ queue_add_file(struct db_media_file_info *dbmfi, int pos, int shuffle_pos, int q
#undef Q_TMPL
}
static int
queue_add_item(struct db_queue_item *item, int pos, int shuffle_pos, int queue_version)
{
#define Q_TMPL "INSERT INTO queue " \
"(id, file_id, song_length, data_kind, media_kind, " \
"pos, shuffle_pos, path, virtual_path, title, " \
"artist, album_artist, album, genre, songalbumid, " \
"time_modified, artist_sort, album_sort, album_artist_sort, year, " \
"track, disc, queue_version)" \
"VALUES" \
"(NULL, %d, %d, %d, %d, " \
"%d, %d, %Q, %Q, %Q, " \
"%Q, %Q, %Q, %Q, %" PRIi64 ", " \
"%d, %Q, %Q, %Q, %d, " \
"%d, %d, %d);"
char *query;
int ret;
query = sqlite3_mprintf(Q_TMPL,
item->file_id, item->song_length, item->data_kind, item->media_kind,
pos, pos, item->path, item->virtual_path, item->title,
item->artist, item->album_artist, item->album, item->genre, item->songalbumid,
item->time_modified, item->artist_sort, item->album_sort, item->album_artist_sort, item->year,
item->track, item->disc, queue_version);
ret = db_query_run(query, 1, 0);
return ret;
#undef Q_TMPL
}
int
db_queue_update_item(struct db_queue_item *qi)
{
@ -4337,6 +4690,46 @@ db_queue_add_by_queryafteritemid(struct query_params *qp, uint32_t item_id)
return ret;
}
int
db_queue_add_start(struct db_queue_add_info *queue_add_info)
{
int ret = 0;
memset(queue_add_info, 0, sizeof(struct db_queue_add_info));
queue_add_info->queue_version = queue_transaction_begin();
queue_add_info->pos = db_queue_get_count();
if (queue_add_info->pos < 0)
{
ret = -1;
queue_transaction_end(ret, queue_add_info->queue_version);
return ret;
}
return 0;
}
void
db_queue_add_end(struct db_queue_add_info *queue_add_info, int ret)
{
queue_transaction_end(ret, queue_add_info->queue_version);
}
int
db_queue_add_item(struct db_queue_add_info *queue_add_info, struct db_queue_item *item)
{
int ret;
fixup_tags_queue_item(item);
ret = queue_add_item(item, queue_add_info->pos, queue_add_info->pos, queue_add_info->queue_version);
if (ret == 0)
queue_add_info->pos++;
return ret;
#undef Q_TMPL
}
/*
* Adds the files matching the given query to the queue
*
@ -4465,63 +4858,6 @@ db_queue_add_by_fileid(int id, char reshuffle, uint32_t item_id)
return ret;
}
int
db_queue_add_item(struct db_queue_item *queue_item, char reshuffle, uint32_t item_id)
{
#define Q_TMPL "INSERT INTO queue " \
"(id, file_id, song_length, data_kind, media_kind, " \
"pos, shuffle_pos, path, virtual_path, title, " \
"artist, album_artist, album, genre, songalbumid, " \
"time_modified, artist_sort, album_sort, album_artist_sort, year, " \
"track, disc, queue_version)" \
"VALUES" \
"(NULL, %d, %d, %d, %d, " \
"%d, %d, %Q, %Q, %Q, " \
"%Q, %Q, %Q, %Q, %d, " \
"%d, %Q, %Q, %Q, %d, " \
"%d, %d, %d);"
int queue_version;
char *query;
int pos;
int new_item_id = 0; // Quell compiler warning about uninitialized use of new_item_id
int ret;
queue_version = queue_transaction_begin();
pos = db_queue_get_count();
if (pos < 0)
{
ret = -1;
goto end_transaction;
}
query = sqlite3_mprintf(Q_TMPL,
queue_item->file_id, queue_item->song_length, queue_item->data_kind, queue_item->media_kind,
pos, pos, queue_item->path, queue_item->virtual_path, queue_item->title,
queue_item->artist, queue_item->album_artist, queue_item->album, queue_item->genre, queue_item->songalbumid,
queue_item->time_modified, queue_item->artist_sort, queue_item->album_sort, queue_item->album_artist_sort, queue_item->year,
queue_item->track, queue_item->disc, queue_version);
ret = db_query_run(query, 1, 0);
if (ret < 0)
goto end_transaction;
new_item_id = (int) sqlite3_last_insert_rowid(hdl);
// Reshuffle after adding new items
if (reshuffle)
{
ret = queue_reshuffle(item_id, queue_version);
}
end_transaction:
queue_transaction_end(ret, queue_version);
return (ret == 0) ? new_item_id : ret;
#undef Q_TMPL
}
static int
queue_enum_start(struct query_params *qp)
{

View File

@ -454,6 +454,12 @@ struct db_queue_item
uint32_t queue_version;
};
struct db_queue_add_info
{
int queue_version;
int pos;
};
char *
db_escape_string(const char *str); // TODO Remove this, use db_mprintf instead
@ -484,6 +490,9 @@ free_queue_item(struct db_queue_item *queue_item, int content_only);
void
unicode_fixup_mfi(struct media_file_info *mfi);
void
fixup_tags_mfi(struct media_file_info *mfi);
/* Maintenance and DB hygiene */
void
db_hook_post_scan(void);
@ -764,7 +773,13 @@ int
db_queue_add_by_fileid(int id, char reshuffle, uint32_t item_id);
int
db_queue_add_item(struct db_queue_item *queue_item, char reshuffle, uint32_t item_id);
db_queue_add_start(struct db_queue_add_info *queue_add_info);
void
db_queue_add_end(struct db_queue_add_info *queue_add_info, int ret);
int
db_queue_add_item(struct db_queue_add_info *queue_add_info, struct db_queue_item *item);
int
db_queue_enum_start(struct query_params *qp);

View File

@ -111,270 +111,6 @@ handle_deferred_update_notifications(void)
return ret;
}
static void
sort_tag_create(char **sort_tag, char *src_tag)
{
const uint8_t *i_ptr;
const uint8_t *n_ptr;
const uint8_t *number;
uint8_t out[1024];
uint8_t *o_ptr;
int append_number;
ucs4_t puc;
int numlen;
size_t len;
int charlen;
/* Note: include terminating NUL in string length for u8_normalize */
if (*sort_tag)
{
DPRINTF(E_DBG, L_LIB, "Existing sort tag will be normalized: %s\n", *sort_tag);
o_ptr = u8_normalize(UNINORM_NFD, (uint8_t *)*sort_tag, strlen(*sort_tag) + 1, NULL, &len);
free(*sort_tag);
*sort_tag = (char *)o_ptr;
return;
}
if (!src_tag || ((len = strlen(src_tag)) == 0))
{
*sort_tag = NULL;
return;
}
// Set input pointer past article if present
if ((strncasecmp(src_tag, "a ", 2) == 0) && (len > 2))
i_ptr = (uint8_t *)(src_tag + 2);
else if ((strncasecmp(src_tag, "an ", 3) == 0) && (len > 3))
i_ptr = (uint8_t *)(src_tag + 3);
else if ((strncasecmp(src_tag, "the ", 4) == 0) && (len > 4))
i_ptr = (uint8_t *)(src_tag + 4);
else
i_ptr = (uint8_t *)src_tag;
// Poor man's natural sort. Makes sure we sort like this: a1, a2, a10, a11, a21, a111
// We do this by padding zeroes to (short) numbers. As an alternative we could have
// made a proper natural sort algorithm in sqlext.c, but we don't, since we don't
// want any risk of hurting response times
memset(&out, 0, sizeof(out));
o_ptr = (uint8_t *)&out;
number = NULL;
append_number = 0;
do
{
n_ptr = u8_next(&puc, i_ptr);
if (uc_is_digit(puc))
{
if (!number) // We have encountered the beginning of a number
number = i_ptr;
append_number = (n_ptr == NULL); // If last char in string append number now
}
else
{
if (number)
append_number = 1; // A number has ended so time to append it
else
{
charlen = u8_strmblen(i_ptr);
if (charlen >= 0)
o_ptr = u8_stpncpy(o_ptr, i_ptr, charlen); // No numbers in sight, just append char
}
}
// Break if less than 100 bytes remain (prevent buffer overflow)
if (sizeof(out) - u8_strlen(out) < 100)
break;
// Break if number is very large (prevent buffer overflow)
if (number && (i_ptr - number > 50))
break;
if (append_number)
{
numlen = i_ptr - number;
if (numlen < 5) // Max pad width
{
u8_strcpy(o_ptr, (uint8_t *)"00000");
o_ptr += (5 - numlen);
}
o_ptr = u8_stpncpy(o_ptr, number, numlen + u8_strmblen(i_ptr));
number = NULL;
append_number = 0;
}
i_ptr = n_ptr;
}
while (n_ptr);
*sort_tag = (char *)u8_normalize(UNINORM_NFD, (uint8_t *)&out, u8_strlen(out) + 1, NULL, &len);
}
static void
fixup_tags(struct media_file_info *mfi)
{
cfg_t *lib;
size_t len;
char *tag;
char *sep = " - ";
char *ca;
if (mfi->genre && (strlen(mfi->genre) == 0))
{
free(mfi->genre);
mfi->genre = NULL;
}
if (mfi->artist && (strlen(mfi->artist) == 0))
{
free(mfi->artist);
mfi->artist = NULL;
}
if (mfi->title && (strlen(mfi->title) == 0))
{
free(mfi->title);
mfi->title = NULL;
}
/*
* Default to mpeg4 video/audio for unknown file types
* in an attempt to allow streaming of DRM-afflicted files
*/
if (mfi->codectype && strcmp(mfi->codectype, "unkn") == 0)
{
if (mfi->has_video)
{
strcpy(mfi->codectype, "mp4v");
strcpy(mfi->type, "m4v");
}
else
{
strcpy(mfi->codectype, "mp4a");
strcpy(mfi->type, "m4a");
}
}
if (!mfi->artist)
{
if (mfi->orchestra && mfi->conductor)
{
len = strlen(mfi->orchestra) + strlen(sep) + strlen(mfi->conductor);
tag = (char *)malloc(len + 1);
if (tag)
{
sprintf(tag,"%s%s%s", mfi->orchestra, sep, mfi->conductor);
mfi->artist = tag;
}
}
else if (mfi->orchestra)
{
mfi->artist = strdup(mfi->orchestra);
}
else if (mfi->conductor)
{
mfi->artist = strdup(mfi->conductor);
}
}
/* Handle TV shows, try to present prettier metadata */
if (mfi->tv_series_name && strlen(mfi->tv_series_name) != 0)
{
mfi->media_kind = MEDIA_KIND_TVSHOW; /* tv show */
/* Default to artist = series_name */
if (mfi->artist && strlen(mfi->artist) == 0)
{
free(mfi->artist);
mfi->artist = NULL;
}
if (!mfi->artist)
mfi->artist = strdup(mfi->tv_series_name);
/* Default to album = "<series_name>, Season <season_num>" */
if (mfi->album && strlen(mfi->album) == 0)
{
free(mfi->album);
mfi->album = NULL;
}
if (!mfi->album)
{
len = snprintf(NULL, 0, "%s, Season %u", mfi->tv_series_name, mfi->tv_season_num);
mfi->album = (char *)malloc(len + 1);
if (mfi->album)
sprintf(mfi->album, "%s, Season %u", mfi->tv_series_name, mfi->tv_season_num);
}
}
/* Check the 4 top-tags are filled */
if (!mfi->artist)
mfi->artist = strdup("Unknown artist");
if (!mfi->album)
mfi->album = strdup("Unknown album");
if (!mfi->genre)
mfi->genre = strdup("Unknown genre");
if (!mfi->title)
{
/* fname is left untouched by unicode_fixup_mfi() for
* obvious reasons, so ensure it is proper UTF-8
*/
mfi->title = unicode_fixup_string(mfi->fname, "ascii");
if (mfi->title == mfi->fname)
mfi->title = strdup(mfi->fname);
}
/* Ensure sort tags are filled, manipulated and normalized */
sort_tag_create(&mfi->artist_sort, mfi->artist);
sort_tag_create(&mfi->album_sort, mfi->album);
sort_tag_create(&mfi->title_sort, mfi->title);
/* We need to set album_artist according to media type and config */
if (mfi->compilation) /* Compilation */
{
lib = cfg_getsec(cfg, "library");
ca = cfg_getstr(lib, "compilation_artist");
if (ca && mfi->album_artist)
{
free(mfi->album_artist);
mfi->album_artist = strdup(ca);
}
else if (ca && !mfi->album_artist)
{
mfi->album_artist = strdup(ca);
}
else if (!ca && !mfi->album_artist)
{
mfi->album_artist = strdup("");
mfi->album_artist_sort = strdup("");
}
}
else if (mfi->media_kind == MEDIA_KIND_PODCAST) /* Podcast */
{
if (mfi->album_artist)
free(mfi->album_artist);
mfi->album_artist = strdup("");
mfi->album_artist_sort = strdup("");
}
else if (!mfi->album_artist) /* Regular media without album_artist */
{
mfi->album_artist = strdup(mfi->artist);
}
if (!mfi->album_artist_sort && (strcmp(mfi->album_artist, mfi->artist) == 0))
mfi->album_artist_sort = strdup(mfi->artist_sort);
else
sort_tag_create(&mfi->album_artist_sort, mfi->album_artist);
/* Composer is not one of our mandatory tags, so take extra care */
if (mfi->composer_sort || mfi->composer)
sort_tag_create(&mfi->composer_sort, mfi->composer);
}
void
library_add_media(struct media_file_info *mfi)
{
@ -398,8 +134,7 @@ library_add_media(struct media_file_info *mfi)
mfi->media_kind = MEDIA_KIND_MUSIC; /* music */
unicode_fixup_mfi(mfi);
fixup_tags(mfi);
fixup_tags_mfi(mfi);
if (mfi->id == 0)
db_file_add(mfi);
@ -408,45 +143,33 @@ library_add_media(struct media_file_info *mfi)
}
int
library_scan_media(const char *path, struct media_file_info *mfi)
library_queue_add(const char *path)
{
int i;
int ret;
DPRINTF(E_DBG, L_LIB, "Scan metadata for path '%s'\n", path);
DPRINTF(E_DBG, L_LIB, "Add items for path '%s' to the queue\n", path);
ret = LIBRARY_PATH_INVALID;
for (i = 0; sources[i] && ret == LIBRARY_PATH_INVALID; i++)
{
if (sources[i]->disabled || !sources[i]->scan_metadata)
if (sources[i]->disabled || !sources[i]->queue_add)
{
DPRINTF(E_DBG, L_LIB, "Library source '%s' is disabled or does not support scan_metadata\n", sources[i]->name);
DPRINTF(E_DBG, L_LIB, "Library source '%s' is disabled or does not support queue_add\n", sources[i]->name);
continue;
}
ret = sources[i]->scan_metadata(path, mfi);
ret = sources[i]->queue_add(path);
if (ret == LIBRARY_OK)
DPRINTF(E_DBG, L_LIB, "Got metadata for path '%s' from library source '%s'\n", path, sources[i]->name);
{
DPRINTF(E_DBG, L_LIB, "Items for path '%s' from library source '%s' added to the queue\n", path, sources[i]->name);
break;
}
}
if (ret == LIBRARY_OK)
{
if (!mfi->virtual_path)
mfi->virtual_path = strdup(mfi->path);
if (!mfi->item_kind)
mfi->item_kind = 2; /* music */
if (!mfi->media_kind)
mfi->media_kind = MEDIA_KIND_MUSIC; /* music */
unicode_fixup_mfi(mfi);
fixup_tags(mfi);
}
else
{
DPRINTF(E_LOG, L_LIB, "Failed to read metadata for path '%s' (ret=%d)\n", path, ret);
}
if (ret != LIBRARY_OK)
DPRINTF(E_LOG, L_LIB, "Failed to add items for path '%s' to the queue (%d)\n", path, ret);
return ret;
}
@ -519,42 +242,6 @@ library_add_playlist_info(const char *path, const char *title, const char *virtu
return plid;
}
int
library_add_queue_item(struct media_file_info *mfi)
{
struct db_queue_item queue_item;
memset(&queue_item, 0, sizeof(struct db_queue_item));
if (mfi->id)
queue_item.file_id = mfi->id;
else
queue_item.file_id = 9999999;
queue_item.title = mfi->title;
queue_item.artist = mfi->artist;
queue_item.album_artist = mfi->album_artist;
queue_item.album = mfi->album;
queue_item.genre = mfi->genre;
queue_item.artist_sort = mfi->artist_sort;
queue_item.album_artist_sort = mfi->album_artist_sort;
queue_item.album_sort = mfi->album_sort;
queue_item.path = mfi->path;
queue_item.virtual_path = mfi->virtual_path;
queue_item.data_kind = mfi->data_kind;
queue_item.media_kind = mfi->media_kind;
queue_item.song_length = mfi->song_length;
queue_item.seek = mfi->seek;
queue_item.songalbumid = mfi->songalbumid;
queue_item.time_modified = mfi->time_modified;
queue_item.year = mfi->year;
queue_item.track = mfi->track;
queue_item.disc = mfi->disc;
//queue_item.artwork_url
return db_queue_add_item(&queue_item, 0, 0);
}
static void
purge_cruft(time_t start)
{

View File

@ -66,11 +66,6 @@ struct library_source
*/
int (*fullrescan)(void);
/*
* Scans metadata for the media file with the given path into the given mfi
*/
int (*scan_metadata)(const char *path, struct media_file_info *mfi);
/*
* Save queue as a new playlist under the given virtual path
*/
@ -85,8 +80,12 @@ struct library_source
* Save queue as a new playlist under the given virtual path
*/
int (*queue_save)(const char *virtual_path);
};
/*
* Add item for the given path to the current queue
*/
int (*queue_add)(const char *path);
};
void
library_add_media(struct media_file_info *mfi);
@ -95,10 +94,7 @@ 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);
int
library_scan_media(const char *path, struct media_file_info *mfi);
int
library_add_queue_item(struct media_file_info *mfi);
library_queue_add(const char *path);
void
library_rescan();

View File

@ -1643,39 +1643,102 @@ filescanner_fullrescan()
return 0;
}
static int
scan_metadata(const char *path, struct media_file_info *mfi)
static void
map_media_file_to_queue_item(struct db_queue_item *queue_item, struct media_file_info *mfi)
{
memset(queue_item, 0, sizeof(struct db_queue_item));
if (mfi->id)
queue_item->file_id = mfi->id;
else
queue_item->file_id = 9999999;
queue_item->title = safe_strdup(mfi->title);
queue_item->artist = safe_strdup(mfi->artist);
queue_item->album_artist = safe_strdup(mfi->album_artist);
queue_item->album = safe_strdup(mfi->album);
queue_item->genre = safe_strdup(mfi->genre);
queue_item->artist_sort = safe_strdup(mfi->artist_sort);
queue_item->album_artist_sort = safe_strdup(mfi->album_artist_sort);
queue_item->album_sort = safe_strdup(mfi->album_sort);
queue_item->path = safe_strdup(mfi->path);
queue_item->virtual_path = safe_strdup(mfi->virtual_path);
queue_item->data_kind = mfi->data_kind;
queue_item->media_kind = mfi->media_kind;
queue_item->song_length = mfi->song_length;
queue_item->seek = mfi->seek;
queue_item->songalbumid = mfi->songalbumid;
queue_item->time_modified = mfi->time_modified;
queue_item->year = mfi->year;
queue_item->track = mfi->track;
queue_item->disc = mfi->disc;
//queue_item->artwork_url
}
static int
queue_add_stream(const char *path)
{
struct media_file_info mfi;
char *pos;
struct db_queue_item item;
struct db_queue_add_info queue_add_info;
int ret;
if (strncasecmp(path, "http://", strlen("http://")) == 0)
memset(&mfi, 0, sizeof(struct media_file_info));
mfi.path = strdup(path);
mfi.virtual_path = safe_asprintf("/%s", mfi.path);
pos = strchr(path, '#');
if (pos)
mfi.fname = strdup(pos+1);
else
mfi.fname = strdup(filename_from_path(mfi.path));
mfi.data_kind = DATA_KIND_HTTP;
mfi.directory_id = DIR_HTTP;
ret = scan_metadata_ffmpeg(path, &mfi);
if (ret < 0)
{
memset(mfi, 0, sizeof(struct media_file_info));
mfi->path = strdup(path);
mfi->virtual_path = safe_asprintf("/%s", mfi->path);
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");
}
pos = strchr(path, '#');
if (pos)
mfi->fname = strdup(pos+1);
else
mfi->fname = strdup(filename_from_path(mfi->path));
if (!mfi.title)
mfi.title = strdup(mfi.fname);
mfi->data_kind = DATA_KIND_HTTP;
mfi->directory_id = DIR_HTTP;
if (!mfi.virtual_path)
mfi.virtual_path = strdup(mfi.path);
if (!mfi.item_kind)
mfi.item_kind = 2; /* music */
if (!mfi.media_kind)
mfi.media_kind = MEDIA_KIND_MUSIC; /* music */
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");
}
unicode_fixup_mfi(&mfi);
if (!mfi->title)
mfi->title = strdup(mfi->fname);
map_media_file_to_queue_item(&item, &mfi);
ret = db_queue_add_start(&queue_add_info);
if (ret == 0)
{
ret = db_queue_add_item(&queue_add_info, &item);
db_queue_add_end(&queue_add_info, ret);
}
free_queue_item(&item, 1);
free_mfi(&mfi, 1);
return 0;
}
static int
queue_add(const char *uri)
{
if (strncasecmp(uri, "http://", strlen("http://")) == 0)
{
queue_add_stream(uri);
return LIBRARY_OK;
}
@ -2052,8 +2115,8 @@ struct library_source filescanner =
.initscan = filescanner_initscan,
.rescan = filescanner_rescan,
.fullrescan = filescanner_fullrescan,
.scan_metadata = scan_metadata,
.playlist_add = playlist_add,
.playlist_remove = playlist_remove,
.queue_save = queue_save,
.queue_add = queue_add,
};

View File

@ -1685,7 +1685,6 @@ mpd_queue_add(char *path, bool exact_match)
static int
mpd_command_add(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, struct mpd_client_ctx *ctx)
{
struct media_file_info mfi;
int ret;
ret = mpd_queue_add(argv[1], false);
@ -1699,15 +1698,12 @@ mpd_command_add(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, st
if (ret == 0)
{
// Given path is not in the library, check if it is possible to add as a non-library queue item
ret = library_scan_media(argv[1], &mfi);
ret = library_queue_add(argv[1]);
if (ret != LIBRARY_OK)
{
*errmsg = safe_asprintf("Failed to add song '%s' to playlist (unkown path)", argv[1]);
return ACK_ERROR_UNKNOWN;
}
library_add_queue_item(&mfi);
free_mfi(&mfi, 1);
}
return 0;
@ -1722,7 +1718,6 @@ mpd_command_add(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, st
static int
mpd_command_addid(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, struct mpd_client_ctx *ctx)
{
struct media_file_info mfi;
int to_pos = -1;
int ret;
@ -1741,15 +1736,12 @@ mpd_command_addid(struct evbuffer *evbuf, int argc, char **argv, char **errmsg,
if (ret == 0)
{
// Given path is not in the library, directly add it as a new queue item
ret = library_scan_media(argv[1], &mfi);
ret = library_queue_add(argv[1]);
if (ret != LIBRARY_OK)
{
*errmsg = safe_asprintf("Failed to add song '%s' to playlist (unkown path)", argv[1]);
return ACK_ERROR_UNKNOWN;
}
ret = library_add_queue_item(&mfi);
free_mfi(&mfi, 1);
}
if (ret < 0)