mirror of
https://github.com/owntone/owntone-server.git
synced 2025-10-30 00:05:05 -04:00
Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
49171dac1a | ||
|
|
09b9b0c7fc | ||
|
|
6f45f8b4a5 | ||
|
|
921d4446d6 | ||
|
|
bf598153f3 | ||
|
|
c1bdac931e | ||
|
|
a1e4982c0b | ||
|
|
352a73044e | ||
|
|
5f526c7a7e | ||
|
|
b7e385ffe0 | ||
|
|
2eba24b4ba | ||
|
|
336200727d | ||
|
|
b523ea4d35 |
@ -490,3 +490,7 @@ Note however, the equalizer appears to require a `plughw` device which means you
|
||||
This error will occur for output hardware that do not support concurrent device open and the server plays 2 files of different bitrate (44.1khz and 48khz) back to back.
|
||||
|
||||
If you observe the error, you will need to use the `dmix` configuration as mentioned above.
|
||||
|
||||
* Volume control on Raspberry Pi with hdmi output doesn't work
|
||||
|
||||
Prior to Debian 13, in the /boot/firmware.config file the entry "dtoverlay=vc4-kms-v3d" was commented out. Since 13 this line is active (not commented out). This changes, among other things, the way the HDMI and BCM devices are handled. Commenting out the entry again will fix the volume control for the hdmi output. If you use the RPi headless commenting this out shouldn't have undesirable effects. See https://forums.raspberrypi.com/viewtopic.php?t=49928&start=1825#p2344272.
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
192
src/artwork.c
192
src/artwork.c
@ -113,6 +113,8 @@ struct artwork_ctx {
|
||||
uint32_t media_kind;
|
||||
// Input data for group handlers
|
||||
int64_t persistentid;
|
||||
// Input data for queue item handlers
|
||||
struct db_queue_item *queue_item;
|
||||
|
||||
// Not to be used by handler - query for item or group
|
||||
struct query_params qp;
|
||||
@ -210,6 +212,8 @@ static int source_item_ownpl_get(struct artwork_ctx *ctx);
|
||||
static int source_item_spotifywebapi_search_get(struct artwork_ctx *ctx);
|
||||
static int source_item_discogs_get(struct artwork_ctx *ctx);
|
||||
static int source_item_coverartarchive_get(struct artwork_ctx *ctx);
|
||||
/* Forward - queue item handlers */
|
||||
static int source_queue_item_artwork_url_get(struct artwork_ctx *ctx);
|
||||
|
||||
/* List of sources that can provide artwork for a group (i.e. usually an album
|
||||
* identified by a persistentid). The source handlers will be called in the
|
||||
@ -353,6 +357,24 @@ static struct artwork_source artwork_item_source[] =
|
||||
}
|
||||
};
|
||||
|
||||
/* List of sources that can provide artwork for a queue item. The source
|
||||
* handlers will be called in the order of this list. Must be terminated by a
|
||||
* NULL struct.
|
||||
*/
|
||||
static struct artwork_source artwork_queue_item_source[] =
|
||||
{
|
||||
{
|
||||
.name = "artwork url",
|
||||
.handler = source_queue_item_artwork_url_get,
|
||||
.cache = NEVER,
|
||||
},
|
||||
{
|
||||
.name = NULL,
|
||||
.handler = NULL,
|
||||
.cache = 0,
|
||||
}
|
||||
};
|
||||
|
||||
/* Forward - parsers of online source responses */
|
||||
static enum parse_result response_jparse_spotify(char **artwork_url, json_object *response, int max_w, int max_h);
|
||||
static enum parse_result response_jparse_discogs(char **artwork_url, json_object *response, int max_w, int max_h);
|
||||
@ -1607,41 +1629,25 @@ source_item_own_get(struct artwork_ctx *ctx)
|
||||
return artwork_get(ctx->evbuf, path, NULL, false, ctx->data_kind, ctx->req_params);
|
||||
}
|
||||
|
||||
/*
|
||||
* Downloads the artwork from the location pointed to by queue_item->artwork_url
|
||||
*/
|
||||
static int
|
||||
source_item_artwork_url_get(struct artwork_ctx *ctx)
|
||||
{
|
||||
struct db_queue_item *queue_item;
|
||||
const char *proto_http = "http:";
|
||||
const char *proto_https = "https:";
|
||||
bool is_http;
|
||||
bool is_https;
|
||||
int ret;
|
||||
|
||||
DPRINTF(E_SPAM, L_ART, "Trying artwork url for %s\n", ctx->dbmfi->path);
|
||||
|
||||
queue_item = db_queue_fetch_byfileid(ctx->id);
|
||||
if (!queue_item || !queue_item->artwork_url)
|
||||
goto notfound;
|
||||
|
||||
is_http = (strncmp(queue_item->artwork_url, proto_http, strlen(proto_http)) == 0);
|
||||
is_https = (strncmp(queue_item->artwork_url, proto_https, strlen(proto_https)) == 0);
|
||||
if (!is_http && !is_https)
|
||||
goto notfound;
|
||||
|
||||
ret = artwork_get_byurl(ctx->evbuf, queue_item->artwork_url, ctx->req_params);
|
||||
|
||||
snprintf(ctx->path, sizeof(ctx->path), "%s", queue_item->artwork_url);
|
||||
|
||||
free_queue_item(queue_item, 0);
|
||||
if (ctx->queue_item)
|
||||
{
|
||||
ret = source_queue_item_artwork_url_get(ctx);
|
||||
}
|
||||
else
|
||||
{
|
||||
ctx->queue_item = db_queue_fetch_byfileid(ctx->id);
|
||||
ret = source_queue_item_artwork_url_get(ctx);
|
||||
free_queue_item(ctx->queue_item, 0);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
notfound:
|
||||
free_queue_item(queue_item, 0);
|
||||
return ART_E_NONE;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1852,11 +1858,46 @@ source_item_ownpl_get(struct artwork_ctx *ctx)
|
||||
return format;
|
||||
}
|
||||
|
||||
/*
|
||||
* Downloads artwork from ctx->queue_item->artwork_url
|
||||
*/
|
||||
static int
|
||||
source_queue_item_artwork_url_get(struct artwork_ctx *ctx)
|
||||
{
|
||||
const char *proto_http = "http:";
|
||||
const char *proto_https = "https:";
|
||||
const char *artwork_url;
|
||||
bool is_http;
|
||||
bool is_https;
|
||||
int ret;
|
||||
|
||||
if (!ctx->queue_item || !ctx->queue_item->artwork_url)
|
||||
goto notfound;
|
||||
|
||||
DPRINTF(E_SPAM, L_ART, "Trying artwork url for %s\n", ctx->queue_item->path);
|
||||
|
||||
artwork_url = ctx->queue_item->artwork_url;
|
||||
|
||||
is_http = (strncmp(artwork_url, proto_http, strlen(proto_http)) == 0);
|
||||
is_https = (strncmp(artwork_url, proto_https, strlen(proto_https)) == 0);
|
||||
if (!is_http && !is_https)
|
||||
goto notfound;
|
||||
|
||||
ret = artwork_get_byurl(ctx->evbuf, artwork_url, ctx->req_params);
|
||||
|
||||
snprintf(ctx->path, sizeof(ctx->path), "%s", artwork_url);
|
||||
|
||||
return ret;
|
||||
|
||||
notfound:
|
||||
return ART_E_NONE;
|
||||
}
|
||||
|
||||
|
||||
/* --------------------------- SOURCE PROCESSING --------------------------- */
|
||||
|
||||
static int
|
||||
process_items(struct artwork_ctx *ctx, int item_mode)
|
||||
process_file_items(struct artwork_ctx *ctx, int item_mode)
|
||||
{
|
||||
struct db_media_file_info dbmfi;
|
||||
int i;
|
||||
@ -2000,16 +2041,55 @@ process_group(struct artwork_ctx *ctx)
|
||||
}
|
||||
|
||||
invalid_group:
|
||||
return process_items(ctx, 0);
|
||||
return process_file_items(ctx, 0);
|
||||
}
|
||||
|
||||
static int
|
||||
process_queue_item(struct artwork_ctx *ctx)
|
||||
{
|
||||
const char *source_name;
|
||||
int i;
|
||||
int ret;
|
||||
|
||||
for (i = 0; artwork_queue_item_source[i].handler; i++)
|
||||
{
|
||||
// If just one handler says we should not cache a negative result then we obey that
|
||||
if ((artwork_queue_item_source[i].cache & ON_FAILURE) == 0)
|
||||
ctx->cache = NEVER;
|
||||
|
||||
source_name = artwork_queue_item_source[i].name;
|
||||
|
||||
DPRINTF(E_SPAM, L_ART, "Checking queue item source '%s'\n", source_name);
|
||||
|
||||
ret = artwork_queue_item_source[i].handler(ctx);
|
||||
if (ret > 0)
|
||||
{
|
||||
DPRINTF(E_DBG, L_ART, "Artwork for queue item '%s' found in source '%s'\n", ctx->queue_item->title, source_name);
|
||||
ctx->cache = artwork_queue_item_source[i].cache;
|
||||
return ret;
|
||||
}
|
||||
else if (ret == ART_E_ABORT)
|
||||
{
|
||||
DPRINTF(E_DBG, L_ART, "Source '%s' stopped search for artwork for queue item '%s'\n", source_name, ctx->queue_item->title);
|
||||
ctx->cache = NEVER;
|
||||
}
|
||||
else if (ret == ART_E_ERROR)
|
||||
{
|
||||
DPRINTF(E_LOG, L_ART, "Source '%s' returned an error for queue item '%s'\n", source_name, ctx->queue_item->title);
|
||||
ctx->cache = NEVER;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------ ARTWORK API ------------------------------ */
|
||||
|
||||
int
|
||||
artwork_get_item(struct evbuffer *evbuf, int id, int max_w, int max_h, int format)
|
||||
artwork_get_by_file_id(struct evbuffer *evbuf, int id, int max_w, int max_h, int format)
|
||||
{
|
||||
struct artwork_ctx ctx;
|
||||
struct artwork_ctx ctx = { 0 };
|
||||
char filter[32];
|
||||
int ret;
|
||||
|
||||
@ -2018,8 +2098,6 @@ artwork_get_item(struct evbuffer *evbuf, int id, int max_w, int max_h, int forma
|
||||
if (id == DB_MEDIA_FILE_NON_PERSISTENT_ID)
|
||||
return -1;
|
||||
|
||||
memset(&ctx, 0, sizeof(struct artwork_ctx));
|
||||
|
||||
ctx.qp.type = Q_ITEMS;
|
||||
ctx.qp.filter = filter;
|
||||
ctx.evbuf = evbuf;
|
||||
@ -2038,7 +2116,7 @@ artwork_get_item(struct evbuffer *evbuf, int id, int max_w, int max_h, int forma
|
||||
|
||||
// Note: process_items will set ctx.persistentid for the following process_group()
|
||||
// - and do nothing else if artwork_individual is not configured by user
|
||||
ret = process_items(&ctx, 1);
|
||||
ret = process_file_items(&ctx, 1);
|
||||
if (ret > 0)
|
||||
{
|
||||
if (ctx.cache & ON_SUCCESS)
|
||||
@ -2068,15 +2146,13 @@ artwork_get_item(struct evbuffer *evbuf, int id, int max_w, int max_h, int forma
|
||||
}
|
||||
|
||||
int
|
||||
artwork_get_group(struct evbuffer *evbuf, int id, int max_w, int max_h, int format)
|
||||
artwork_get_by_group_id(struct evbuffer *evbuf, int id, int max_w, int max_h, int format)
|
||||
{
|
||||
struct artwork_ctx ctx;
|
||||
struct artwork_ctx ctx = { 0 };
|
||||
int ret;
|
||||
|
||||
DPRINTF(E_DBG, L_ART, "Artwork request for group %d (max_w=%d, max_h=%d)\n", id, max_w, max_h);
|
||||
|
||||
memset(&ctx, 0, sizeof(struct artwork_ctx));
|
||||
|
||||
/* Get the persistent id for the given group id */
|
||||
ret = db_group_persistentid_byid(id, &ctx.persistentid);
|
||||
if (ret < 0)
|
||||
@ -2111,6 +2187,48 @@ artwork_get_group(struct evbuffer *evbuf, int id, int max_w, int max_h, int form
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
artwork_get_by_queue_item_id(struct evbuffer *evbuf, int item_id, int max_w, int max_h, int format)
|
||||
{
|
||||
struct artwork_ctx ctx = { 0 };
|
||||
struct db_queue_item *queue_item;
|
||||
int ret;
|
||||
|
||||
DPRINTF(E_DBG, L_ART, "Artwork request for queue item %d (max_w=%d, max_h=%d)\n", item_id, max_w, max_h);
|
||||
|
||||
queue_item = db_queue_fetch_byitemid(item_id);
|
||||
if (!queue_item)
|
||||
return -1;
|
||||
|
||||
if (queue_item->file_id != DB_MEDIA_FILE_NON_PERSISTENT_ID)
|
||||
{
|
||||
ret = artwork_get_by_file_id(evbuf, queue_item->file_id, max_w, max_h, format);
|
||||
free_queue_item(queue_item, 0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ctx.queue_item = queue_item;
|
||||
ctx.evbuf = evbuf;
|
||||
ctx.req_params.max_w = max_w;
|
||||
ctx.req_params.max_h = max_h;
|
||||
ctx.req_params.format = format;
|
||||
ctx.cache = ON_FAILURE;
|
||||
|
||||
ret = process_queue_item(&ctx);
|
||||
if (ret > 0)
|
||||
{
|
||||
// No caching of queue item artwork implemented as of yet
|
||||
free_queue_item(queue_item, 0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
DPRINTF(E_DBG, L_ART, "No artwork found for queue item %d\n", item_id);
|
||||
|
||||
free_queue_item(queue_item, 0);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Checks if the file is an artwork file */
|
||||
bool
|
||||
artwork_file_is_artwork(const char *filename)
|
||||
|
||||
@ -13,7 +13,7 @@
|
||||
#include <stdbool.h>
|
||||
|
||||
/*
|
||||
* Get the artwork image for an individual item (track)
|
||||
* Get the artwork image for an individual library item (track)
|
||||
*
|
||||
* @out evbuf Event buffer that will contain the (scaled) image
|
||||
* @in id The mfi item id
|
||||
@ -23,7 +23,7 @@
|
||||
* @return ART_FMT_* on success, -1 on error or no artwork found
|
||||
*/
|
||||
int
|
||||
artwork_get_item(struct evbuffer *evbuf, int id, int max_w, int max_h, int format);
|
||||
artwork_get_by_file_id(struct evbuffer *evbuf, int id, int max_w, int max_h, int format);
|
||||
|
||||
/*
|
||||
* Get the artwork image for a group (an album or an artist)
|
||||
@ -36,7 +36,21 @@ artwork_get_item(struct evbuffer *evbuf, int id, int max_w, int max_h, int forma
|
||||
* @return ART_FMT_* on success, -1 on error or no artwork found
|
||||
*/
|
||||
int
|
||||
artwork_get_group(struct evbuffer *evbuf, int id, int max_w, int max_h, int format);
|
||||
artwork_get_by_group_id(struct evbuffer *evbuf, int id, int max_w, int max_h, int format);
|
||||
|
||||
/*
|
||||
* Get the artwork image for a queue item. If the queue item is in the library,
|
||||
* this will return the same as artwork_get_by_file_id
|
||||
*
|
||||
* @out evbuf Event buffer that will contain the (scaled) image
|
||||
* @in item_id The queue item id
|
||||
* @in max_w Requested maximum image width (may not be obeyed)
|
||||
* @in max_h Requested maximum image height (may not be obeyed)
|
||||
* @in format Requested format (may not be obeyed), 0 for default
|
||||
* @return ART_FMT_* on success, -1 on error or no artwork found
|
||||
*/
|
||||
int
|
||||
artwork_get_by_queue_item_id(struct evbuffer *evbuf, int item_id, int max_w, int max_h, int format);
|
||||
|
||||
/*
|
||||
* Checks if the file is an artwork file (based on user config)
|
||||
|
||||
@ -920,7 +920,7 @@ stream_chunk_raw_cb(int fd, short event, void *arg)
|
||||
if (ret == 0)
|
||||
DPRINTF(E_INFO, L_HTTPD, "Done streaming file id %d\n", st->id);
|
||||
else
|
||||
DPRINTF(E_LOG, L_HTTPD, "Streaming error, file id %d\n", st->id);
|
||||
DPRINTF(E_LOG, L_HTTPD, "Read error, file id %d: %s\n", st->id, strerror(errno));
|
||||
|
||||
stream_end(st);
|
||||
return;
|
||||
|
||||
@ -74,20 +74,20 @@ response_process(struct httpd_request *hreq, int format)
|
||||
static int
|
||||
artworkapi_reply_nowplaying(struct httpd_request *hreq)
|
||||
{
|
||||
struct player_status status;
|
||||
uint32_t max_w;
|
||||
uint32_t max_h;
|
||||
uint32_t id;
|
||||
int ret;
|
||||
|
||||
ret = request_process(hreq, &max_w, &max_h);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
ret = player_playing_now(&id);
|
||||
if (ret != 0)
|
||||
player_get_status(&status);
|
||||
if (status.status == PLAY_STOPPED)
|
||||
return HTTP_NOTFOUND;
|
||||
|
||||
ret = artwork_get_item(hreq->out_body, id, max_w, max_h, 0);
|
||||
ret = artwork_get_by_queue_item_id(hreq->out_body, status.item_id, max_w, max_h, 0);
|
||||
|
||||
return response_process(hreq, ret);
|
||||
}
|
||||
@ -108,7 +108,7 @@ artworkapi_reply_item(struct httpd_request *hreq)
|
||||
if (ret != 0)
|
||||
return HTTP_BADREQUEST;
|
||||
|
||||
ret = artwork_get_item(hreq->out_body, id, max_w, max_h, 0);
|
||||
ret = artwork_get_by_file_id(hreq->out_body, id, max_w, max_h, 0);
|
||||
|
||||
return response_process(hreq, ret);
|
||||
}
|
||||
@ -129,7 +129,7 @@ artworkapi_reply_group(struct httpd_request *hreq)
|
||||
if (ret != 0)
|
||||
return HTTP_BADREQUEST;
|
||||
|
||||
ret = artwork_get_group(hreq->out_body, id, max_w, max_h, 0);
|
||||
ret = artwork_get_by_group_id(hreq->out_body, id, max_w, max_h, 0);
|
||||
|
||||
return response_process(hreq, ret);
|
||||
}
|
||||
|
||||
@ -1986,9 +1986,9 @@ daap_reply_extra_data(struct httpd_request *hreq)
|
||||
}
|
||||
|
||||
if (strcmp(hreq->path_parts[2], "groups") == 0)
|
||||
ret = artwork_get_group(hreq->out_body, id, max_w, max_h, 0);
|
||||
ret = artwork_get_by_group_id(hreq->out_body, id, max_w, max_h, 0);
|
||||
else if (strcmp(hreq->path_parts[2], "items") == 0)
|
||||
ret = artwork_get_item(hreq->out_body, id, max_w, max_h, 0);
|
||||
ret = artwork_get_by_file_id(hreq->out_body, id, max_w, max_h, 0);
|
||||
|
||||
len = evbuffer_get_length(hreq->out_body);
|
||||
|
||||
|
||||
@ -164,7 +164,7 @@ dacp_nowplaying(struct evbuffer *evbuf, struct player_status *status, struct db_
|
||||
* FIXME: Giving the client invalid ids on purpose is hardly ideal, but the
|
||||
* clients don't seem to use these ids for anything other than rating.
|
||||
*/
|
||||
if (queue_item->data_kind == DATA_KIND_HTTP || queue_item->data_kind == DATA_KIND_PIPE)
|
||||
if (queue_item->data_kind == DATA_KIND_HTTP || queue_item->data_kind == DATA_KIND_PIPE || queue_item->file_id == DB_MEDIA_FILE_NON_PERSISTENT_ID)
|
||||
{
|
||||
// Could also use queue_item->queue_version, but it changes a bit too much
|
||||
// leading to Remote reloading too much
|
||||
@ -1894,6 +1894,7 @@ dacp_reply_playqueueedit_add(struct httpd_request *hreq)
|
||||
const char *querymodifier;
|
||||
const char *sort;
|
||||
const char *param;
|
||||
const char *ptr;
|
||||
char modifiedquery[32];
|
||||
int mode;
|
||||
int plid;
|
||||
@ -1955,7 +1956,8 @@ dacp_reply_playqueueedit_add(struct httpd_request *hreq)
|
||||
else
|
||||
{
|
||||
// Modify the query: Take the id from the editquery and use it as a queuefilter playlist id
|
||||
ret = safe_atoi32(strchr(editquery, ':') + 1, &plid);
|
||||
ptr = strchr(editquery, ':');
|
||||
ret = ptr ? safe_atoi32(ptr + 1, &plid) : -1;
|
||||
if (ret < 0)
|
||||
{
|
||||
DPRINTF(E_LOG, L_DACP, "Invalid playlist id in request: %s\n", editquery);
|
||||
@ -2029,38 +2031,44 @@ dacp_reply_playqueueedit_move(struct httpd_request *hreq)
|
||||
struct player_status status;
|
||||
int ret;
|
||||
const char *param;
|
||||
const char *ptr;
|
||||
int src;
|
||||
int dst;
|
||||
|
||||
param = httpd_query_value_find(hreq->query, "edit-params");
|
||||
if (param)
|
||||
{
|
||||
ret = safe_atoi32(strchr(param, ':') + 1, &src);
|
||||
if (ret < 0)
|
||||
{
|
||||
DPRINTF(E_LOG, L_DACP, "Invalid edit-params move-from value in playqueue-edit request\n");
|
||||
if (!param)
|
||||
goto out;
|
||||
|
||||
dacp_send_error(hreq, "cacr", "Invalid request");
|
||||
return -1;
|
||||
}
|
||||
ptr = strchr(param, ':');
|
||||
if (!ptr)
|
||||
goto error;
|
||||
|
||||
ret = safe_atoi32(strchr(param, ',') + 1, &dst);
|
||||
if (ret < 0)
|
||||
{
|
||||
DPRINTF(E_LOG, L_DACP, "Invalid edit-params move-to value in playqueue-edit request\n");
|
||||
ret = safe_atoi32(ptr + 1, &src);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
|
||||
dacp_send_error(hreq, "cacr", "Invalid request");
|
||||
return -1;
|
||||
}
|
||||
ptr = strchr(param, ',');
|
||||
if (!ptr)
|
||||
goto error;
|
||||
|
||||
player_get_status(&status);
|
||||
db_queue_move_byposrelativetoitem(src, dst, status.item_id, status.shuffle);
|
||||
}
|
||||
ret = safe_atoi32(ptr + 1, &dst);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
|
||||
player_get_status(&status);
|
||||
db_queue_move_byposrelativetoitem(src, dst, status.item_id, status.shuffle);
|
||||
|
||||
out:
|
||||
/* 204 No Content is the canonical reply */
|
||||
httpd_send_reply(hreq, HTTP_NOCONTENT, "No Content", HTTPD_SEND_NO_GZIP);
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
DPRINTF(E_LOG, L_DACP, "Invalid edit-params in playqueue-edit request: '%s'\n", param);
|
||||
|
||||
dacp_send_error(hreq, "cacr", "Invalid request");
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
@ -2249,11 +2257,11 @@ dacp_reply_playstatusupdate(struct httpd_request *hreq)
|
||||
static int
|
||||
dacp_reply_nowplayingartwork(struct httpd_request *hreq)
|
||||
{
|
||||
struct player_status status;
|
||||
char clen[32];
|
||||
const char *param;
|
||||
char *ctype;
|
||||
size_t len;
|
||||
uint32_t id;
|
||||
int max_w;
|
||||
int max_h;
|
||||
int ret;
|
||||
@ -2290,11 +2298,11 @@ dacp_reply_nowplayingartwork(struct httpd_request *hreq)
|
||||
goto error;
|
||||
}
|
||||
|
||||
ret = player_playing_now(&id);
|
||||
if (ret < 0)
|
||||
player_get_status(&status);
|
||||
if (status.status == PLAY_STOPPED)
|
||||
goto no_artwork;
|
||||
|
||||
ret = artwork_get_item(hreq->out_body, id, max_w, max_h, 0);
|
||||
ret = artwork_get_by_queue_item_id(hreq->out_body, status.item_id, max_w, max_h, 0);
|
||||
len = evbuffer_get_length(hreq->out_body);
|
||||
|
||||
switch (ret)
|
||||
@ -2538,8 +2546,7 @@ dacp_reply_setspeakers(struct httpd_request *hreq)
|
||||
}
|
||||
|
||||
nspk = 1;
|
||||
ptr = param;
|
||||
while ((ptr = strchr(ptr + 1, ',')))
|
||||
for (ptr = param; ptr; ptr = strchr(ptr + 1, ','))
|
||||
nspk++;
|
||||
|
||||
CHECK_NULL(L_DACP, ids = calloc((nspk + 1), sizeof(uint64_t)));
|
||||
|
||||
20
src/mpd.c
20
src/mpd.c
@ -2391,7 +2391,7 @@ mpd_command_albumart(struct mpd_command_output *out, struct mpd_command_input *i
|
||||
|
||||
// Ref. docs: "If the song file was recognized, but there is no picture, the
|
||||
// response is successful, but is otherwise empty"
|
||||
format = artwork_get_item(artwork, id, ART_DEFAULT_WIDTH, ART_DEFAULT_HEIGHT, 0);
|
||||
format = artwork_get_by_file_id(artwork, id, ART_DEFAULT_WIDTH, ART_DEFAULT_HEIGHT, 0);
|
||||
if (format == ART_FMT_PNG)
|
||||
evbuffer_add_printf(out->evbuf, "type: image/png\n");
|
||||
else if (format == ART_FMT_JPEG)
|
||||
@ -4150,7 +4150,7 @@ artwork_cb(struct evhttp_request *req, void *arg)
|
||||
const char *path;
|
||||
char *decoded_path;
|
||||
char *last_slash;
|
||||
int itemid;
|
||||
int file_id;
|
||||
int format;
|
||||
|
||||
if (evhttp_request_get_command(req) != EVHTTP_REQ_GET)
|
||||
@ -4195,8 +4195,8 @@ artwork_cb(struct evhttp_request *req, void *arg)
|
||||
|
||||
DPRINTF(E_DBG, L_MPD, "Artwork request for path: %s\n", decoded_path);
|
||||
|
||||
itemid = db_file_id_byvirtualpath_match(decoded_path);
|
||||
if (!itemid)
|
||||
file_id = db_file_id_byvirtualpath_match(decoded_path);
|
||||
if (!file_id)
|
||||
{
|
||||
DPRINTF(E_WARN, L_MPD, "No item found for path '%s' from request uri '%s'\n", decoded_path, uri);
|
||||
evhttp_send_error(req, HTTP_NOTFOUND, "Document was not found");
|
||||
@ -4205,17 +4205,9 @@ artwork_cb(struct evhttp_request *req, void *arg)
|
||||
return;
|
||||
}
|
||||
|
||||
evbuffer = evbuffer_new();
|
||||
if (!evbuffer)
|
||||
{
|
||||
DPRINTF(E_LOG, L_MPD, "Could not allocate an evbuffer for artwork request\n");
|
||||
evhttp_send_error(req, HTTP_INTERNAL, "Document was not found");
|
||||
evhttp_uri_free(decoded);
|
||||
free(decoded_path);
|
||||
return;
|
||||
}
|
||||
CHECK_NULL(L_MPD, evbuffer = evbuffer_new());
|
||||
|
||||
format = artwork_get_item(evbuffer, itemid, ART_DEFAULT_WIDTH, ART_DEFAULT_HEIGHT, 0);
|
||||
format = artwork_get_by_file_id(evbuffer, file_id, ART_DEFAULT_WIDTH, ART_DEFAULT_HEIGHT, 0);
|
||||
if (format < 0)
|
||||
{
|
||||
evhttp_send_error(req, HTTP_NOTFOUND, "Document was not found");
|
||||
|
||||
@ -1632,7 +1632,7 @@ airplay_metadata_prepare(struct output_metadata *metadata)
|
||||
CHECK_NULL(L_AIRPLAY, rmd->metadata = evbuffer_new());
|
||||
CHECK_NULL(L_AIRPLAY, tmp = evbuffer_new());
|
||||
|
||||
ret = artwork_get_item(rmd->artwork, queue_item->file_id, ART_DEFAULT_WIDTH, ART_DEFAULT_HEIGHT, 0);
|
||||
ret = artwork_get_by_queue_item_id(rmd->artwork, queue_item->id, ART_DEFAULT_WIDTH, ART_DEFAULT_HEIGHT, 0);
|
||||
if (ret < 0)
|
||||
{
|
||||
DPRINTF(E_INFO, L_AIRPLAY, "Failed to retrieve artwork for file '%s'; no artwork will be sent\n", queue_item->path);
|
||||
|
||||
@ -2314,7 +2314,7 @@ raop_metadata_prepare(struct output_metadata *metadata)
|
||||
CHECK_NULL(L_RAOP, rmd->metadata = evbuffer_new());
|
||||
CHECK_NULL(L_RAOP, tmp = evbuffer_new());
|
||||
|
||||
ret = artwork_get_item(rmd->artwork, queue_item->file_id, ART_DEFAULT_WIDTH, ART_DEFAULT_HEIGHT, 0);
|
||||
ret = artwork_get_by_queue_item_id(rmd->artwork, queue_item->id, ART_DEFAULT_WIDTH, ART_DEFAULT_HEIGHT, 0);
|
||||
if (ret < 0)
|
||||
{
|
||||
DPRINTF(E_INFO, L_RAOP, "Failed to retrieve artwork for file '%s'; no artwork will be sent\n", queue_item->path);
|
||||
|
||||
771
web-src/package-lock.json
generated
771
web-src/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -16,27 +16,27 @@
|
||||
"@mdi/js": "^7.4.47",
|
||||
"@spotify/web-api-ts-sdk": "^1.2.0",
|
||||
"@ts-pro/vue-eternal-loading": "^1.3.1",
|
||||
"axios": "^1.11.0",
|
||||
"axios": "^1.12.2",
|
||||
"bulma": "^1.0.4",
|
||||
"luxon": "^3.7.2",
|
||||
"mdi-vue": "^3.0.13",
|
||||
"pinia": "^3.0.3",
|
||||
"reconnectingwebsocket": "^1.0.0",
|
||||
"vue": "^3.5.21",
|
||||
"vue": "^3.5.22",
|
||||
"vue-i18n": "^11.1.12",
|
||||
"vue-router": "^4.5.1",
|
||||
"vue-router": "^4.6.3",
|
||||
"vue3-click-away": "^1.2.4",
|
||||
"vue3-lazyload": "^0.3.8",
|
||||
"vuedraggable": "^4.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@intlify/unplugin-vue-i18n": "^11.0.0",
|
||||
"@intlify/unplugin-vue-i18n": "^11.0.1",
|
||||
"@vitejs/plugin-vue": "^6.0.1",
|
||||
"eslint": "^9.35.0",
|
||||
"eslint": "^9.38.0",
|
||||
"eslint-config-prettier": "^10.1.8",
|
||||
"eslint-plugin-vue": "^10.4.0",
|
||||
"eslint-plugin-vue": "^10.5.1",
|
||||
"prettier": "^3.6.2",
|
||||
"sass": "^1.92.1",
|
||||
"vite": "^7.1.5"
|
||||
"sass": "^1.93.2",
|
||||
"vite": "^7.1.11"
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user