[artworkapi/jsonapi] Retrieve artwork for track/album/artist

This commit is contained in:
ejurgensen 2018-10-07 21:54:38 +02:00
parent c1619f7be0
commit 41126d7be4
5 changed files with 297 additions and 0 deletions

View File

@ -115,6 +115,7 @@ forked_daapd_SOURCES = main.c \
httpd_jsonapi.c httpd_jsonapi.h \
httpd_streaming.c httpd_streaming.h \
httpd_oauth.c httpd_oauth.h \
httpd_artworkapi.c httpd_artworkapi.h \
http.c http.h \
dmap_common.c dmap_common.h \
transcode.h artwork.h \

View File

@ -63,6 +63,7 @@
#include "httpd_jsonapi.h"
#include "httpd_streaming.h"
#include "httpd_oauth.h"
#include "httpd_artworkapi.h"
#include "transcode.h"
#ifdef LASTFM
# include "lastfm.h"
@ -842,6 +843,11 @@ httpd_gen_cb(struct evhttp_request *req, void *arg)
jsonapi_request(req, parsed);
goto out;
}
else if (artworkapi_is_request(parsed->path))
{
artworkapi_request(req, parsed);
goto out;
}
else if (streaming_is_request(parsed->path))
{
streaming_request(req, parsed);
@ -1679,6 +1685,14 @@ httpd_init(const char *webroot)
goto jsonapi_fail;
}
ret = artworkapi_init();
if (ret < 0)
{
DPRINTF(E_FATAL, L_HTTPD, "Artwork init failed\n");
goto artworkapi_fail;
}
ret = oauth_init();
if (ret < 0)
{
@ -1814,6 +1828,8 @@ httpd_init(const char *webroot)
#endif
oauth_deinit();
oauth_fail:
artworkapi_deinit();
artworkapi_fail:
jsonapi_deinit();
jsonapi_fail:
dacp_deinit();

240
src/httpd_artworkapi.c Normal file
View File

@ -0,0 +1,240 @@
/*
* Copyright (C) 2018 Espen Jürgensen <espenjurgensen@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <regex.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include "httpd_artworkapi.h"
#include "logger.h"
#include "misc.h"
#include "player.h"
#include "artwork.h"
static int
request_process(struct httpd_request *hreq, uint32_t *max_w, uint32_t *max_h)
{
const char *param;
int ret;
*max_w = 0;
*max_h = 0;
param = evhttp_find_header(hreq->query, "maxwidth");
if (param)
{
ret = safe_atou32(param, max_w);
if (ret < 0)
DPRINTF(E_LOG, L_WEB, "Invalid width in request: '%s'\n", hreq->uri_parsed->uri);
}
param = evhttp_find_header(hreq->query, "maxheight");
if (param)
{
ret = safe_atou32(param, max_h);
if (ret < 0)
DPRINTF(E_LOG, L_WEB, "Invalid height in request: '%s'\n", hreq->uri_parsed->uri);
}
return 0;
}
static int
response_process(struct httpd_request *hreq, int format)
{
struct evkeyvalq *headers;
headers = evhttp_request_get_output_headers(hreq->req);
if (format == ART_FMT_PNG)
evhttp_add_header(headers, "Content-Type", "image/png");
else if (format == ART_FMT_JPEG)
evhttp_add_header(headers, "Content-Type", "image/jpeg");
else
return HTTP_NOCONTENT;
return HTTP_OK;
}
static int
artworkapi_reply_nowplaying(struct httpd_request *hreq)
{
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_now_playing(&id);
if (ret != 0)
return HTTP_NOTFOUND;
ret = artwork_get_item(hreq->reply, id, max_w, max_h);
return response_process(hreq, ret);
}
static int
artworkapi_reply_item(struct httpd_request *hreq)
{
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 = safe_atou32(hreq->uri_parsed->path_parts[2], &id);
if (ret != 0)
return HTTP_BADREQUEST;
ret = artwork_get_item(hreq->reply, id, max_w, max_h);
return response_process(hreq, ret);
}
static int
artworkapi_reply_group(struct httpd_request *hreq)
{
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 = safe_atou32(hreq->uri_parsed->path_parts[2], &id);
if (ret != 0)
return HTTP_BADREQUEST;
ret = artwork_get_group(hreq->reply, id, max_w, max_h);
return response_process(hreq, ret);
}
static struct httpd_uri_map artworkapi_handlers[] =
{
{ EVHTTP_REQ_GET, "^/artwork/nowplaying$", artworkapi_reply_nowplaying },
{ EVHTTP_REQ_GET, "^/artwork/item/[[:digit:]]+$", artworkapi_reply_item },
{ EVHTTP_REQ_GET, "^/artwork/group/[[:digit:]]+$", artworkapi_reply_group },
{ 0, NULL, NULL }
};
/* ------------------------------- API --------------------------------- */
void
artworkapi_request(struct evhttp_request *req, struct httpd_uri_parsed *uri_parsed)
{
struct httpd_request *hreq;
int status_code;
DPRINTF(E_DBG, L_WEB, "Artwork api request: '%s'\n", uri_parsed->uri);
if (!httpd_admin_check_auth(req))
return;
hreq = httpd_request_parse(req, uri_parsed, NULL, artworkapi_handlers);
if (!hreq)
{
DPRINTF(E_LOG, L_WEB, "Unrecognized path '%s' in artwork api request: '%s'\n", uri_parsed->path, uri_parsed->uri);
httpd_send_error(req, HTTP_BADREQUEST, "Bad Request");
return;
}
CHECK_NULL(L_WEB, hreq->reply = evbuffer_new());
status_code = hreq->handler(hreq);
switch (status_code)
{
case HTTP_OK: /* 200 OK */
httpd_send_reply(req, status_code, "OK", hreq->reply, HTTPD_SEND_NO_GZIP);
break;
case HTTP_NOCONTENT: /* 204 No Content */
httpd_send_reply(req, status_code, "No Content", hreq->reply, HTTPD_SEND_NO_GZIP);
break;
case HTTP_NOTMODIFIED: /* 304 Not Modified */
httpd_send_reply(req, HTTP_NOTMODIFIED, NULL, NULL, HTTPD_SEND_NO_GZIP);
break;
case HTTP_BADREQUEST: /* 400 Bad Request */
httpd_send_error(req, status_code, "Bad Request");
break;
case HTTP_NOTFOUND: /* 404 Not Found */
httpd_send_error(req, status_code, "Not Found");
break;
case HTTP_INTERNAL: /* 500 Internal Server Error */
default:
httpd_send_error(req, HTTP_INTERNAL, "Internal Server Error");
}
evbuffer_free(hreq->reply);
free(hreq);
}
int
artworkapi_is_request(const char *path)
{
if (strncmp(path, "/artwork/", strlen("/artwork/")) == 0)
return 1;
return 0;
}
int
artworkapi_init(void)
{
char buf[64];
int i;
int ret;
for (i = 0; artworkapi_handlers[i].handler; i++)
{
ret = regcomp(&artworkapi_handlers[i].preg, artworkapi_handlers[i].regexp, REG_EXTENDED | REG_NOSUB);
if (ret != 0)
{
regerror(ret, &artworkapi_handlers[i].preg, buf, sizeof(buf));
DPRINTF(E_FATAL, L_WEB, "artwork api init failed; regexp error: %s\n", buf);
return -1;
}
}
return 0;
}
void
artworkapi_deinit(void)
{
int i;
for (i = 0; artworkapi_handlers[i].handler; i++)
regfree(&artworkapi_handlers[i].preg);
}

18
src/httpd_artworkapi.h Normal file
View File

@ -0,0 +1,18 @@
#ifndef __HTTPD_ARTWORK_H__
#define __HTTPD_ARTWORK_H__
#include "httpd.h"
int
artworkapi_init(void);
void
artworkapi_deinit(void);
void
artworkapi_request(struct evhttp_request *req, struct httpd_uri_parsed *uri_parsed);
int
artworkapi_is_request(const char *path);
#endif

View File

@ -117,6 +117,7 @@ artist_to_json(struct db_group_info *dbgri)
{
json_object *item;
char uri[100];
char artwork_url[100];
int ret;
item = json_object_new_object();
@ -132,6 +133,10 @@ artist_to_json(struct db_group_info *dbgri)
if (ret < sizeof(uri))
json_object_object_add(item, "uri", json_object_new_string(uri));
ret = snprintf(artwork_url, sizeof(artwork_url), "/artwork/group/%s", dbgri->id);
if (ret < sizeof(artwork_url))
json_object_object_add(item, "artwork_url", json_object_new_string(artwork_url));
return item;
}
@ -140,6 +145,7 @@ album_to_json(struct db_group_info *dbgri)
{
json_object *item;
char uri[100];
char artwork_url[100];
int ret;
item = json_object_new_object();
@ -156,6 +162,10 @@ album_to_json(struct db_group_info *dbgri)
if (ret < sizeof(uri))
json_object_object_add(item, "uri", json_object_new_string(uri));
ret = snprintf(artwork_url, sizeof(artwork_url), "/artwork/group/%s", dbgri->id);
if (ret < sizeof(artwork_url))
json_object_object_add(item, "artwork_url", json_object_new_string(artwork_url));
return item;
}
@ -164,6 +174,7 @@ track_to_json(struct db_media_file_info *dbmfi)
{
json_object *item;
char uri[100];
char artwork_url[100];
int intval;
int ret;
@ -207,6 +218,10 @@ track_to_json(struct db_media_file_info *dbmfi)
if (ret < sizeof(uri))
json_object_object_add(item, "uri", json_object_new_string(uri));
ret = snprintf(artwork_url, sizeof(artwork_url), "/artwork/item/%s", dbmfi->id);
if (ret < sizeof(artwork_url))
json_object_object_add(item, "artwork_url", json_object_new_string(artwork_url));
return item;
}
@ -1466,6 +1481,7 @@ jsonapi_reply_player(struct httpd_request *hreq)
json_object_object_add(reply, "item_id", json_object_new_int(status.item_id));
json_object_object_add(reply, "item_length_ms", json_object_new_int(status.len_ms));
json_object_object_add(reply, "item_progress_ms", json_object_new_int(status.pos_ms));
json_object_object_add(reply, "artwork_url", json_object_new_string("/artwork/nowplaying"));
}
else
{
@ -1498,6 +1514,7 @@ queue_item_to_json(struct db_queue_item *queue_item, char shuffle)
{
json_object *item;
char uri[100];
char artwork_url[100];
int ret;
item = json_object_new_object();
@ -1534,10 +1551,15 @@ queue_item_to_json(struct db_queue_item *queue_item, char shuffle)
ret = snprintf(uri, sizeof(uri), "%s:%s:%d", "library", "track", queue_item->file_id);
if (ret < sizeof(uri))
json_object_object_add(item, "uri", json_object_new_string(uri));
ret = snprintf(artwork_url, sizeof(artwork_url), "/artwork/item/%d", queue_item->file_id);
if (ret < sizeof(artwork_url))
json_object_object_add(item, "artwork_url", json_object_new_string(artwork_url));
}
else
{
safe_json_add_string(item, "uri", queue_item->path);
safe_json_add_string(item, "artwork_url", queue_item->artwork_url);
}
return item;