Merge branch 'ownartwork' of @couteau and various modifications (see pr #75)

This commit is contained in:
ejurgensen 2015-01-03 00:31:48 +01:00
commit 0d7ec13ede
5 changed files with 154 additions and 22 deletions

View File

@ -91,6 +91,11 @@ library {
# forked-daapd will look for jpg and png files with these base names
# artwork_basenames = { "artwork", "cover", "Folder" }
# Enable searching for artwork corresponding to each individual media
# file instead of only looking for album artwork. This is disabled by
# default to reduce cache size.
# artwork_individual = false
# File types the scanner should ignore
# Non-audio files will never be added to the database, but here you
# can prevent the scanner from even probing them. This might improve

View File

@ -839,6 +839,59 @@ artwork_get_embedded_image(char *filename, int max_w, int max_h, struct evbuffer
}
#endif
static int
artwork_get_own_image(char *path, int max_w, int max_h, char *filename, struct evbuffer *evbuf)
{
char artwork[PATH_MAX];
char *ptr;
int len;
int nextensions;
int i;
int ret;
ret = snprintf(artwork, sizeof(artwork), "%s", path);
if ((ret < 0) || (ret >= sizeof(artwork)))
{
DPRINTF(E_INFO, L_ART, "Artwork path exceeds PATH_MAX\n");
return -1;
}
ptr = strrchr(artwork, '.');
if (ptr)
*ptr = '\0';
len = strlen(artwork);
nextensions = sizeof(cover_extension) / sizeof(cover_extension[0]);
for (i = 0; i < nextensions; i++)
{
ret = snprintf(artwork + len, sizeof(artwork) - len, ".%s", cover_extension[i]);
if ((ret < 0) || (ret >= sizeof(artwork) - len))
{
DPRINTF(E_INFO, L_ART, "Artwork path exceeds PATH_MAX (ext %s)\n", cover_extension[i]);
continue;
}
DPRINTF(E_SPAM, L_ART, "Trying own artwork file %s\n", artwork);
ret = access(artwork, F_OK);
if (ret == 0)
continue;
break;
}
if (i == nextensions)
return -1;
DPRINTF(E_DBG, L_ART, "Found own artwork file %s\n", artwork);
strcpy(filename, artwork);
return artwork_get(artwork, max_w, max_h, evbuf);
}
static int
artwork_get_dir_image(char *path, int max_w, int max_h, char *filename, struct evbuffer *evbuf)
{
@ -970,6 +1023,65 @@ artwork_get_item_path(char *path, int artwork, int max_w, int max_h, struct evbu
return -1;
}
/*
* Get the artwork for the given media file and the given maxiumum width/height
* @param mfi the media file structure for the file whose image should be returned
* @param max_w maximum image width
* @param max_h maximum image height
* @param evbuf the event buffer that will contain the (scaled) image
* @return 0 or the format code for the returned image on success, -1 on failure
*/
static int
artwork_get_item_mfi(struct media_file_info *mfi, int max_w, int max_h, struct evbuffer *evbuf)
{
int ret;
int cached;
int format;
char filename[PATH_MAX];
DPRINTF(E_DBG, L_ART, "Artwork request for item %d\n", mfi->id);
ret = 0;
format = 0;
ret = cache_artwork_get(CACHE_ARTWORK_INDIVIDUAL, mfi->id, max_w, max_h, &cached, &format, evbuf);
if (ret == 0 && cached)
{
if (format > 0)
{
DPRINTF(E_DBG, L_ART, "Artwork found in cache for item %d\n", mfi->id);
return format;
}
else if (format == 0)
{
DPRINTF(E_DBG, L_ART, "Artwork found in cache but no image available for item %d\n", mfi->id);
return -1;
}
}
if (mfi->data_kind == 0)
{
if (mfi->artwork == ARTWORK_OWN || mfi->artwork == ARTWORK_UNKNOWN)
{
/* Look for basename(filename).{png,jpg} */
format = artwork_get_own_image(mfi->path, max_w, max_h, filename, evbuf);
}
else
{
format = artwork_get_item_path(mfi->path, mfi->artwork, max_w, max_h, evbuf);
strcpy(filename, mfi->path);
}
if (format > 0)
cache_artwork_add(CACHE_ARTWORK_INDIVIDUAL, mfi->id, max_w, max_h, format, filename, evbuf);
return format;
}
return -1;
}
/*
* Get the artwork image for the given persistentid and the given maximum width/height
*
@ -1005,18 +1117,16 @@ artwork_get_group_persistentid(int64_t persistentid, int max_w, int max_h, struc
/*
* First check if the artwork cache has a cached entry for the given persistent id and requested width/height
*/
ret = cache_artwork_get(persistentid, max_w, max_h, &cached, &format, evbuf);
ret = cache_artwork_get(CACHE_ARTWORK_GROUP, persistentid, max_w, max_h, &cached, &format, evbuf);
if (ret == 0 && cached)
{
if (format > 0)
{
// Artwork found in cache "ret" contains the format of the image
DPRINTF(E_DBG, L_ART, "Artwork found in cache for group %" PRIi64 "\n", persistentid);
return format;
}
else if (format == 0)
{
// Entry found in cache but there is not artwork available
DPRINTF(E_DBG, L_ART, "Artwork found in cache but no image available for group %" PRIi64 "\n", persistentid);
return -1;
}
@ -1058,7 +1168,7 @@ artwork_get_group_persistentid(int64_t persistentid, int max_w, int max_h, struc
DPRINTF(E_LOG, L_ART, "Error fetching Q_GROUP_DIRS results\n");
else if (got_art > 0)
{
cache_artwork_add(persistentid, max_w, max_h, format, filename, evbuf);
cache_artwork_add(CACHE_ARTWORK_GROUP, persistentid, max_w, max_h, format, filename, evbuf);
return format;
}
@ -1108,13 +1218,13 @@ artwork_get_group_persistentid(int64_t persistentid, int max_w, int max_h, struc
}
else if (got_art > 0)
{
cache_artwork_add(persistentid, max_w, max_h, format, filename, evbuf);
cache_artwork_add(CACHE_ARTWORK_GROUP, persistentid, max_w, max_h, format, filename, evbuf);
return format;
}
/* Add cache entry for no artwork available */
if (!got_spotifyitem)
cache_artwork_add(persistentid, max_w, max_h, 0, "", evbuf);
cache_artwork_add(CACHE_ARTWORK_GROUP, persistentid, max_w, max_h, 0, "", evbuf);
DPRINTF(E_DBG, L_ART, "No artwork found for group %" PRIi64 "\n", persistentid);
@ -1133,12 +1243,18 @@ artwork_get_item(int id, int max_w, int max_h, struct evbuffer *evbuf)
if (!mfi)
return -1;
/*
* Load artwork image for the persistent id
*/
ret = artwork_get_group_persistentid(mfi->songalbumid, max_w, max_h, evbuf);
if (cfg_getbool(cfg_getsec(cfg, "library"), "artwork_individual"))
ret = artwork_get_item_mfi(mfi, max_w, max_h, evbuf);
else
ret = -1;
/* No individual artwork or individual artwork disabled, try group artwork */
if (ret < 0)
DPRINTF(E_DBG, L_ART, "No artwork found for item id %d (%s)\n", id, mfi->fname);
{
ret = artwork_get_group_persistentid(mfi->songalbumid, max_w, max_h, evbuf);
if (ret < 0)
DPRINTF(E_DBG, L_ART, "No artwork found for item id %d (%s)\n", id, mfi->fname);
}
free_mfi(mfi, 0);

View File

@ -38,7 +38,7 @@
#include "cache.h"
#define CACHE_VERSION 1
#define CACHE_VERSION 2
/* The DAAP cache will cache raw daap replies for queries added with
* cache_add(). Only some query types are supported.
@ -66,6 +66,7 @@ struct cache_command
int msec;
char *path; // artwork path
int type; // individual or group artwork
int64_t peristentid;
int max_w;
int max_h;
@ -236,6 +237,7 @@ cache_create_tables(void)
#define T_ARTWORK \
"CREATE TABLE IF NOT EXISTS artwork (" \
" id INTEGER PRIMARY KEY NOT NULL,"\
" type INTEGER NOT NULL DEFAULT 0," \
" persistentid INTEGER NOT NULL," \
" max_w INTEGER NOT NULL," \
" max_h INTEGER NOT NULL," \
@ -245,7 +247,7 @@ cache_create_tables(void)
" data BLOB" \
");"
#define I_ARTWORK_ID \
"CREATE INDEX IF NOT EXISTS idx_persistentidwh ON artwork(persistentid, max_w, max_h);"
"CREATE INDEX IF NOT EXISTS idx_persistentidwh ON artwork(type, persistentid, max_w, max_h);"
#define I_ARTWORK_PATH \
"CREATE INDEX IF NOT EXISTS idx_pathtime ON artwork(filepath, db_timestamp);"
#define T_ADMIN_CACHE \
@ -1055,7 +1057,7 @@ cache_artwork_add_impl(struct cache_command *cmd)
int datalen;
int ret;
query = "INSERT INTO artwork (id, persistentid, max_w, max_h, format, filepath, db_timestamp, data) VALUES (NULL, ?, ?, ?, ?, ?, ?, ?);";
query = "INSERT INTO artwork (id, persistentid, max_w, max_h, format, filepath, db_timestamp, data, type) VALUES (NULL, ?, ?, ?, ?, ?, ?, ?, ?);";
ret = sqlite3_prepare_v2(g_db_hdl, query, -1, &stmt, 0);
if (ret != SQLITE_OK)
@ -1079,6 +1081,7 @@ cache_artwork_add_impl(struct cache_command *cmd)
sqlite3_bind_text(stmt, 5, cmd->arg.path, -1, SQLITE_STATIC);
sqlite3_bind_int(stmt, 6, (uint64_t)time(NULL));
sqlite3_bind_blob(stmt, 7, data, datalen, SQLITE_STATIC);
sqlite3_bind_int(stmt, 8, cmd->arg.type);
ret = sqlite3_step(stmt);
if (ret != SQLITE_DONE)
@ -1104,7 +1107,8 @@ cache_artwork_add_impl(struct cache_command *cmd)
* If there is a cached entry for the given id and width/height, the parameter cached is set to 1.
* In this case format and data contain the cached values.
*
* @param cmd->arg.persistentid persistent songalbumid or songartistid
* @param cmd->arg.type individual or group artwork
* @param cmd->arg.persistentid persistent itemid, songalbumid or songartistid
* @param cmd->arg.max_w maximum image width
* @param cmd->arg.max_h maximum image height
* @param cmd->arg.cached set by this function to 0 if no cache entry exists, otherwise 1
@ -1115,13 +1119,13 @@ cache_artwork_add_impl(struct cache_command *cmd)
static int
cache_artwork_get_impl(struct cache_command *cmd)
{
#define Q_TMPL "SELECT a.format, a.data FROM artwork a WHERE a.persistentid = %" PRIi64 " AND a.max_w = %d AND a.max_h = %d;"
#define Q_TMPL "SELECT a.format, a.data FROM artwork a WHERE a.type = %d AND a.persistentid = %" PRIi64 " AND a.max_w = %d AND a.max_h = %d;"
sqlite3_stmt *stmt;
char *query;
int datalen;
int ret;
query = sqlite3_mprintf(Q_TMPL, cmd->arg.peristentid, cmd->arg.max_w, cmd->arg.max_h);
query = sqlite3_mprintf(Q_TMPL, cmd->arg.type, cmd->arg.peristentid, cmd->arg.max_w, cmd->arg.max_h);
if (!query)
{
DPRINTF(E_LOG, L_CACHE, "Out of memory for query string\n");
@ -1453,7 +1457,8 @@ cache_artwork_purge_cruft(time_t ref)
/*
* Adds the given (scaled) artwork image to the artwork cache
*
* @param persistentid persistent songalbumid or songartistid
* @param type individual or group artwork
* @param persistentid persistent itemid, songalbumid or songartistid
* @param max_w maximum image width
* @param max_h maximum image height
* @param format ART_FMT_PNG for png, ART_FMT_JPEG for jpeg or 0 if no artwork available
@ -1462,7 +1467,7 @@ cache_artwork_purge_cruft(time_t ref)
* @return 0 if successful, -1 if an error occurred
*/
int
cache_artwork_add(int64_t persistentid, int max_w, int max_h, int format, char *filename, struct evbuffer *evbuf)
cache_artwork_add(int type, int64_t persistentid, int max_w, int max_h, int format, char *filename, struct evbuffer *evbuf)
{
struct cache_command cmd;
int ret;
@ -1473,6 +1478,7 @@ cache_artwork_add(int64_t persistentid, int max_w, int max_h, int format, char *
command_init(&cmd);
cmd.func = cache_artwork_add_impl;
cmd.arg.type = type;
cmd.arg.peristentid = persistentid;
cmd.arg.max_w = max_w;
cmd.arg.max_h = max_h;
@ -1502,7 +1508,7 @@ cache_artwork_add(int64_t persistentid, int max_w, int max_h, int format, char *
* @return 0 if successful, -1 if an error occurred
*/
int
cache_artwork_get(int64_t persistentid, int max_w, int max_h, int *cached, int *format, struct evbuffer *evbuf)
cache_artwork_get(int type, int64_t persistentid, int max_w, int max_h, int *cached, int *format, struct evbuffer *evbuf)
{
struct cache_command cmd;
int ret;
@ -1513,6 +1519,7 @@ cache_artwork_get(int64_t persistentid, int max_w, int max_h, int *cached, int *
command_init(&cmd);
cmd.func = cache_artwork_get_impl;
cmd.arg.type = type;
cmd.arg.peristentid = persistentid;
cmd.arg.max_w = max_w;
cmd.arg.max_h = max_h;

View File

@ -27,6 +27,9 @@ cache_daap_threshold(void);
/* ---------------------------- Artwork cache API --------------------------- */
#define CACHE_ARTWORK_GROUP 0
#define CACHE_ARTWORK_INDIVIDUAL 1
int
cache_artwork_ping(char *path, time_t mtime);
@ -37,10 +40,10 @@ int
cache_artwork_purge_cruft(time_t ref);
int
cache_artwork_add(int64_t persistentid, int max_w, int max_h, int format, char *filename, struct evbuffer *evbuf);
cache_artwork_add(int type, int64_t persistentid, int max_w, int max_h, int format, char *filename, struct evbuffer *evbuf);
int
cache_artwork_get(int64_t persistentid, int max_w, int max_h, int *cached, int *format, struct evbuffer *evbuf);
cache_artwork_get(int type, int64_t persistentid, int max_w, int max_h, int *cached, int *format, struct evbuffer *evbuf);
/* ---------------------------- Cache API --------------------------- */

View File

@ -76,6 +76,7 @@ static cfg_opt_t sec_library[] =
CFG_STR("name_podcasts", "Podcasts", CFGF_NONE),
CFG_STR("name_audiobooks", "Audiobooks", CFGF_NONE),
CFG_STR_LIST("artwork_basenames", "{artwork,cover,Folder}", CFGF_NONE),
CFG_BOOL("artwork_individual", cfg_false, CFGF_NONE),
CFG_STR_LIST("filetypes_ignore", "{.db,.ini,.db-journal,.pdf}", CFGF_NONE),
CFG_BOOL("filescan_disable", cfg_false, CFGF_NONE),
CFG_BOOL("itunes_overrides", cfg_false, CFGF_NONE),