mirror of
https://github.com/owntone/owntone-server.git
synced 2024-12-27 23:55:57 -05:00
[pipe/artwork] Support for artwork via Shairport metadata pipes, take 3
This implementation uses a tmpfile for storage of the artwork, plus it uses artwork_get() which means that it scales the image as requested by the client. It also does not create a tmpfile unless we actually receive artwork.
This commit is contained in:
parent
ddb91e61ef
commit
7316c060b8
@ -852,10 +852,8 @@ static int
|
||||
source_item_pipe_get(struct artwork_ctx *ctx)
|
||||
{
|
||||
struct db_queue_item *queue_item;
|
||||
uint8_t header[2] = { 0 };
|
||||
const char *proto = "file:";
|
||||
char *path;
|
||||
int ret;
|
||||
|
||||
DPRINTF(E_SPAM, L_ART, "Trying pipe metadata from %s.metadata\n", ctx->dbmfi->path);
|
||||
|
||||
@ -868,23 +866,9 @@ source_item_pipe_get(struct artwork_ctx *ctx)
|
||||
|
||||
path = queue_item->artwork_url + strlen(proto);
|
||||
|
||||
ret = artwork_read(ctx->evbuf, path);
|
||||
if (ret < 0)
|
||||
{
|
||||
free_queue_item(queue_item, 0);
|
||||
return ART_E_ERROR;
|
||||
}
|
||||
snprintf(ctx->path, sizeof(ctx->path), "%s", path);
|
||||
|
||||
free_queue_item(queue_item, 0);
|
||||
|
||||
evbuffer_copyout(ctx->evbuf, header, sizeof(header));
|
||||
|
||||
if (header[0] == 0xff && header[1] == 0xd8)
|
||||
return ART_FMT_JPEG;
|
||||
else if (header[0] == 0x89 && header[1] == 0x50)
|
||||
return ART_FMT_PNG;
|
||||
else
|
||||
return ART_E_ERROR;
|
||||
return artwork_get(ctx->evbuf, path, NULL, ctx->max_w, ctx->max_h, false);
|
||||
}
|
||||
|
||||
#ifdef HAVE_SPOTIFY_H
|
||||
|
@ -75,7 +75,8 @@
|
||||
// Ignore pictures with larger size than this
|
||||
#define PIPE_PICTURE_SIZE_MAX 262144
|
||||
// Where we store pictures for the artwork module to read
|
||||
#define PIPE_TMPFILE_TEMPLATE "/tmp/forked-daapd.XXXXXX"
|
||||
#define PIPE_TMPFILE_TEMPLATE "/tmp/forked-daapd.XXXXXX.ext"
|
||||
#define PIPE_TMPFILE_TEMPLATE_EXTLEN 4
|
||||
|
||||
enum pipetype
|
||||
{
|
||||
@ -298,6 +299,36 @@ dmapval(const char s[4])
|
||||
return ((s[0] << 24) | (s[1] << 16) | (s[2] << 8) | (s[3] << 0));
|
||||
}
|
||||
|
||||
static void
|
||||
pict_tmpfile_close(struct pipe_metadata *pm)
|
||||
{
|
||||
if (pm->pict_tmpfile_fd < 0)
|
||||
return;
|
||||
|
||||
close(pm->pict_tmpfile_fd);
|
||||
unlink(pm->pict_tmpfile_path);
|
||||
|
||||
pm->pict_tmpfile_fd = -1;
|
||||
}
|
||||
|
||||
// Opens a tmpfile to store metadata artwork in. *ext is the extension to use
|
||||
// for the tmpfile, eg .jpg or .png. Extension cannot be longer than
|
||||
// PIPE_TMPFILE_TEMPLATE_EXTLEN.
|
||||
static int
|
||||
pict_tmpfile_recreate(struct pipe_metadata *pm, const char *ext)
|
||||
{
|
||||
int offset = strlen(PIPE_TMPFILE_TEMPLATE) - PIPE_TMPFILE_TEMPLATE_EXTLEN;
|
||||
|
||||
pict_tmpfile_close(pm);
|
||||
|
||||
strcpy(pm->pict_tmpfile_path, PIPE_TMPFILE_TEMPLATE);
|
||||
strncpy(pm->pict_tmpfile_path + offset, ext, PIPE_TMPFILE_TEMPLATE_EXTLEN);
|
||||
|
||||
pm->pict_tmpfile_fd = mkstemps(pm->pict_tmpfile_path, PIPE_TMPFILE_TEMPLATE_EXTLEN);
|
||||
|
||||
return pm->pict_tmpfile_fd;
|
||||
}
|
||||
|
||||
static void
|
||||
handle_progress(struct input_metadata *m, char *progress)
|
||||
{
|
||||
@ -370,32 +401,39 @@ handle_volume(const char *volume)
|
||||
static void
|
||||
handle_picture(struct input_metadata *m, uint8_t *data, int data_len)
|
||||
{
|
||||
const char *ext;
|
||||
ssize_t ret;
|
||||
|
||||
free(m->artwork_url);
|
||||
m->artwork_url = NULL;
|
||||
|
||||
if (pipe_metadata.pict_tmpfile_fd < 0)
|
||||
return;
|
||||
|
||||
if (data_len < 2 || data_len > PIPE_PICTURE_SIZE_MAX)
|
||||
{
|
||||
DPRINTF(E_WARN, L_PLAYER, "Unsupported picture size (%d) from Shairport metadata pipe\n", data_len);
|
||||
return;
|
||||
}
|
||||
|
||||
// Reset in case we previously wrote to the tmp file
|
||||
lseek(pipe_metadata.pict_tmpfile_fd, 0L, SEEK_SET);
|
||||
if (data[0] == 0xff && data[1] == 0xd8)
|
||||
ext = ".jpg";
|
||||
else if (data[0] == 0x89 && data[1] == 0x50)
|
||||
ext = ".png";
|
||||
|
||||
pict_tmpfile_recreate(&pipe_metadata, ext);
|
||||
if (pipe_metadata.pict_tmpfile_fd < 0)
|
||||
{
|
||||
DPRINTF(E_LOG, L_PLAYER, "Could not open tmpfile for pipe artwork '%s': %s\n", pipe_metadata.pict_tmpfile_path, strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
ret = write(pipe_metadata.pict_tmpfile_fd, data, data_len);
|
||||
if (ret < 0)
|
||||
{
|
||||
DPRINTF(E_WARN, L_PLAYER, "Error writing artwork from metadata pipe to '%s': %s\n", pipe_metadata.pict_tmpfile_path, strerror(errno));
|
||||
DPRINTF(E_LOG, L_PLAYER, "Error writing artwork from metadata pipe to '%s': %s\n", pipe_metadata.pict_tmpfile_path, strerror(errno));
|
||||
return;
|
||||
}
|
||||
else if (ret != data_len)
|
||||
{
|
||||
DPRINTF(E_WARN, L_PLAYER, "Incomplete write of artwork to '%s' (%zd/%d)\n", pipe_metadata.pict_tmpfile_path, ret, data_len);
|
||||
DPRINTF(E_LOG, L_PLAYER, "Incomplete write of artwork to '%s' (%zd/%d)\n", pipe_metadata.pict_tmpfile_path, ret, data_len);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -695,11 +733,7 @@ pipe_metadata_watch_del(void *arg)
|
||||
pipe_free(pipe_metadata.pipe);
|
||||
pipe_metadata.pipe = NULL;
|
||||
|
||||
if (pipe_metadata.pict_tmpfile_fd >= 0)
|
||||
{
|
||||
close(pipe_metadata.pict_tmpfile_fd);
|
||||
unlink(pipe_metadata.pict_tmpfile_path);
|
||||
}
|
||||
pict_tmpfile_close(&pipe_metadata);
|
||||
}
|
||||
|
||||
// Some metadata arrived on a pipe we watch
|
||||
@ -775,13 +809,6 @@ pipe_metadata_watch_add(void *arg)
|
||||
pipe_metadata.pipe = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
// Try to open a tmpfile to store metadata artwork in (the PICT tag). If we
|
||||
// can't open a tmpfile we will just ignore artwork.
|
||||
strcpy(pipe_metadata.pict_tmpfile_path, PIPE_TMPFILE_TEMPLATE);
|
||||
pipe_metadata.pict_tmpfile_fd = mkstemp(pipe_metadata.pict_tmpfile_path);
|
||||
if (pipe_metadata.pict_tmpfile_fd < 0)
|
||||
DPRINTF(E_WARN, L_PLAYER, "Error opening tmpfile for metadata pipe artwork: %s\n", strerror(errno));
|
||||
}
|
||||
|
||||
|
||||
@ -999,6 +1026,8 @@ init(void)
|
||||
{
|
||||
CHECK_ERR(L_PLAYER, mutex_init(&pipe_metadata.lock));
|
||||
|
||||
pipe_metadata.pict_tmpfile_fd = -1;
|
||||
|
||||
pipe_autostart = cfg_getbool(cfg_getsec(cfg, "library"), "pipe_autostart");
|
||||
if (pipe_autostart)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user