diff --git a/htdocs/sw.js.in b/htdocs/sw.js.in index 6ae86ec80..5672123ec 100644 --- a/htdocs/sw.js.in +++ b/htdocs/sw.js.in @@ -10,13 +10,13 @@ const urlsToCache = [ subdir + '/js/combined.js', subdir + '/assets/appicon-192.png', subdir + '/assets/appicon-512.png', - subdir + '/assets/coverimage-booklet.svg', - subdir + '/assets/coverimage-folder.svg', - subdir + '/assets/coverimage-stream.svg', - subdir + '/assets/coverimage-notavailable.svg', - subdir + '/assets/coverimage-mympd.svg', - subdir + '/assets/coverimage-playlist.svg', - subdir + '/assets/coverimage-smartpls.svg', + subdir + '/assets/coverimage-booklet', + subdir + '/assets/coverimage-folder', + subdir + '/assets/coverimage-stream', + subdir + '/assets/coverimage-notavailable', + subdir + '/assets/coverimage-mympd', + subdir + '/assets/coverimage-playlist', + subdir + '/assets/coverimage-smartpls', __I18NASSETS__ subdir + '/assets/ligatures.json', subdir + '/assets/MaterialIcons-Regular.woff2', diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b8da46ae0..ac323b298 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -143,6 +143,7 @@ target_sources(mympd web_server/albumart.c web_server/folderart.c web_server/request_handler.c + web_server/placeholder.c web_server/proxy.c web_server/sessions.c web_server/playlistart.c diff --git a/src/web_server/albumart.c b/src/web_server/albumart.c index 6eaac4fcf..5ed887757 100644 --- a/src/web_server/albumart.c +++ b/src/web_server/albumart.c @@ -22,6 +22,7 @@ #include "src/lib/sds_extras.h" #include "src/lib/utility.h" #include "src/lib/validate.h" +#include "src/web_server/placeholder.h" #include "src/web_server/webradio.h" #include @@ -64,7 +65,7 @@ void webserver_send_albumart_redirect(struct mg_connection *nc, sds data) { FREE_SDS(redirect_uri); } else { - webserver_serve_placeholder_image(nc, PLACEHOLDER_NA); + webserver_redirect_placeholder_image(nc, PLACEHOLDER_NA); } FREE_SDS(uri); } @@ -89,7 +90,7 @@ void webserver_send_albumart(struct mg_connection *nc, sds data, sds binary) { FREE_SDS(headers); } else { - webserver_serve_placeholder_image(nc, PLACEHOLDER_NA); + webserver_redirect_placeholder_image(nc, PLACEHOLDER_NA); } FREE_SDS(mime_type); } @@ -139,7 +140,7 @@ bool request_handler_albumart_by_uri(struct mg_connection *nc, struct mg_http_me sdslen(uri) == 0) { MYMPD_LOG_ERROR(NULL, "Failed to decode query"); - webserver_serve_placeholder_image(nc, PLACEHOLDER_NA); + webserver_redirect_placeholder_image(nc, PLACEHOLDER_NA); FREE_SDS(offset_s); FREE_SDS(uri); return true; @@ -158,7 +159,7 @@ bool request_handler_albumart_by_uri(struct mg_connection *nc, struct mg_http_me if (sdslen(uri) > FILEPATH_LEN_MAX) { FREE_SDS(uri); MYMPD_LOG_WARN(NULL, "Uri is too long, max len is %d", FILEPATH_LEN_MAX); - webserver_serve_placeholder_image(nc, PLACEHOLDER_NA); + webserver_redirect_placeholder_image(nc, PLACEHOLDER_NA); return true; } @@ -167,7 +168,7 @@ bool request_handler_albumart_by_uri(struct mg_connection *nc, struct mg_http_me if (sdslen(uri) > FILENAME_LEN_MAX) { FREE_SDS(uri); MYMPD_LOG_DEBUG(NULL, "Uri is too long, max len is %d", FILENAME_LEN_MAX); - webserver_serve_placeholder_image(nc, PLACEHOLDER_STREAM); + webserver_redirect_placeholder_image(nc, PLACEHOLDER_STREAM); return true; } @@ -257,7 +258,7 @@ bool request_handler_albumart_by_uri(struct mg_connection *nc, struct mg_http_me MYMPD_LOG_INFO(NULL, "No coverimage found for \"%s\"", uri); FREE_SDS(uri); - webserver_serve_placeholder_image(nc, PLACEHOLDER_NA); + webserver_redirect_placeholder_image(nc, PLACEHOLDER_NA); return true; } diff --git a/src/web_server/folderart.c b/src/web_server/folderart.c index 3dff98a73..588b9d008 100644 --- a/src/web_server/folderart.c +++ b/src/web_server/folderart.c @@ -14,6 +14,7 @@ #include "src/lib/log.h" #include "src/lib/sds_extras.h" #include "src/lib/validate.h" +#include "src/web_server/placeholder.h" /** * Serves the first image in a folder @@ -26,7 +27,7 @@ bool request_handler_folderart(struct mg_connection *nc, struct mg_http_message struct t_mg_user_data *mg_user_data) { if (sdslen(mg_user_data->music_directory) == 0) { - webserver_serve_placeholder_image(nc, PLACEHOLDER_NA); + webserver_redirect_placeholder_image(nc, PLACEHOLDER_NA); return false; } @@ -37,7 +38,7 @@ bool request_handler_folderart(struct mg_connection *nc, struct mg_http_message vcb_isfilepath(path) == false) { MYMPD_LOG_ERROR(NULL, "Failed to decode query"); - webserver_serve_placeholder_image(nc, PLACEHOLDER_FOLDER); + webserver_redirect_placeholder_image(nc, PLACEHOLDER_FOLDER); FREE_SDS(path); return false; } @@ -55,6 +56,6 @@ bool request_handler_folderart(struct mg_connection *nc, struct mg_http_message MYMPD_LOG_INFO(NULL, "No folderimage found for \"%s\"", path); FREE_SDS(path); FREE_SDS(coverfile); - webserver_serve_placeholder_image(nc, PLACEHOLDER_FOLDER); + webserver_redirect_placeholder_image(nc, PLACEHOLDER_FOLDER); return false; } diff --git a/src/web_server/placeholder.c b/src/web_server/placeholder.c new file mode 100644 index 000000000..a3f5154dd --- /dev/null +++ b/src/web_server/placeholder.c @@ -0,0 +1,96 @@ +/* + SPDX-License-Identifier: GPL-3.0-or-later + myMPD (c) 2018-2024 Juergen Mang + https://github.com/jcorporation/mympd +*/ + +/*! \file + * \brief Placeholder image functions + */ + +#include "compile_time.h" +#include "src/web_server/placeholder.h" + +#include "src/lib/log.h" +#include "src/lib/sds_extras.h" +#include "src/web_server/utility.h" + +/** + * Placeholder image names + */ +const char *placeholder_image_names[] = { + [PLACEHOLDER_BOOKLET] = "coverimage-booklet", + [PLACEHOLDER_MYMPD] = "coverimage-mympd", + [PLACEHOLDER_NA] = "coverimage-notavailable", + [PLACEHOLDER_STREAM] = "coverimage-stream", + [PLACEHOLDER_PLAYLIST] = "coverimage-playlist", + [PLACEHOLDER_SMARTPLS] = "coverimage-smartpls" +}; + +/** + * Lookups the placeholder string + * @param placeholder Placeholder + * @return placeholder name + */ +const char* placeholder_lookup_name(enum placeholder_types placeholder) { + if (placeholder > 0 && placeholder < PLACEHOLDER_COUNT) { + return placeholder_image_names[placeholder]; + } + return placeholder_image_names[PLACEHOLDER_NA]; +} + +/** + * Redirects to the placeholder image + * @param nc mongoose connection + * @param placeholder_type Type of placeholder image + */ +void webserver_redirect_placeholder_image(struct mg_connection *nc, enum placeholder_types placeholder_type) { + sds placeholder_uri = sdscatfmt(sdsempty(), "/assets/%s", placeholder_lookup_name(placeholder_type)); + webserver_send_header_redirect(nc, placeholder_uri, ""); + FREE_SDS(placeholder_uri); +} + +/** + * Serves the placeholder image + * @param nc mongoose connection + * @param hm http message + * @param uri placeholder uri + */ +void webserver_serve_placeholder_image(struct mg_connection *nc, struct mg_http_message *hm, sds uri) { + struct t_mg_user_data *mg_user_data = (struct t_mg_user_data *) nc->mgr->userdata; + if (uri[1] == 'a') { + // Default placeholders + #ifdef MYMPD_EMBEDDED_ASSETS + webserver_serve_embedded_files(nc, uri); + #else + sds abs_uri = sdscatfmt(sdsempty(), "%s%S", MYMPD_DOC_ROOT, uri); + webserver_serve_file(nc, hm, MYMPD_DOC_ROOT, abs_uri); + FREE_SDS(abs_uri); + #endif + } + else { + // Custom placeholders + webserver_serve_file(nc, hm, mg_user_data->config->workdir, uri); + } +} + +/** + * Finds and sets the placeholder images + * @param workdir myMPD working directory + * @param name basename to search for + * @param result pointer to sds result + */ +void get_placeholder_image(sds workdir, const char *name, sds *result) { + sds file = sdscatfmt(sdsempty(), "%S/%s/%s", workdir, DIR_WORK_PICS_THUMBS, name); + MYMPD_LOG_DEBUG(NULL, "Check for custom placeholder image \"%s\"", file); + file = webserver_find_image_file(file); + sdsclear(*result); + if (sdslen(file) > 0) { + MYMPD_LOG_INFO(NULL, "Setting custom placeholder image for %s to \"%s\"", name, file); + *result = sdscatsds(*result, file); + } + else { + *result = sdscatfmt(*result, "/assets/%s.svg", name); + } + FREE_SDS(file); +} diff --git a/src/web_server/placeholder.h b/src/web_server/placeholder.h new file mode 100644 index 000000000..ab874d634 --- /dev/null +++ b/src/web_server/placeholder.h @@ -0,0 +1,37 @@ +/* + SPDX-License-Identifier: GPL-3.0-or-later + myMPD (c) 2018-2024 Juergen Mang + https://github.com/jcorporation/mympd +*/ + +/*! \file + * \brief Webserver utility functions + */ + +#ifndef MYMPD_WEB_SERVER_PLACEHOLDER_H +#define MYMPD_WEB_SERVER_PLACEHOLDER_H + +#include "dist/mongoose/mongoose.h" +#include "dist/sds/sds.h" + +/** + * Placeholder types + */ +enum placeholder_types { + PLACEHOLDER_UNKNOWN = -1, + PLACEHOLDER_BOOKLET, + PLACEHOLDER_FOLDER, + PLACEHOLDER_MYMPD, + PLACEHOLDER_NA, + PLACEHOLDER_PLAYLIST, + PLACEHOLDER_SMARTPLS, + PLACEHOLDER_STREAM, + PLACEHOLDER_COUNT +}; + +const char* placeholder_lookup_name(enum placeholder_types placeholder); +void webserver_redirect_placeholder_image(struct mg_connection *nc, enum placeholder_types placeholder_type); +void webserver_serve_placeholder_image(struct mg_connection *nc, struct mg_http_message *hm, sds uri); +void get_placeholder_image(sds workdir, const char *name, sds *result); + +#endif diff --git a/src/web_server/playlistart.c b/src/web_server/playlistart.c index 8f7a1bbff..89ec56c86 100644 --- a/src/web_server/playlistart.c +++ b/src/web_server/playlistart.c @@ -16,6 +16,7 @@ #include "src/lib/sds_extras.h" #include "src/lib/utility.h" #include "src/lib/validate.h" +#include "src/web_server/placeholder.h" /** * Request handler for /playlistart @@ -35,7 +36,7 @@ bool request_handler_playlistart(struct mg_connection *nc, struct mg_http_messag vcb_isfilepath(name) == false) { MYMPD_LOG_ERROR(NULL, "Failed to decode query"); - webserver_serve_placeholder_image(nc, PLACEHOLDER_PLAYLIST); + webserver_redirect_placeholder_image(nc, PLACEHOLDER_PLAYLIST); FREE_SDS(name); return false; } @@ -52,7 +53,7 @@ bool request_handler_playlistart(struct mg_connection *nc, struct mg_http_messag } else { MYMPD_LOG_DEBUG(NULL, "No image for tag found"); - webserver_serve_placeholder_image(nc, PLACEHOLDER_PLAYLIST); + webserver_redirect_placeholder_image(nc, PLACEHOLDER_PLAYLIST); } FREE_SDS(mediafile); FREE_SDS(name); diff --git a/src/web_server/proxy.c b/src/web_server/proxy.c index 8d19c2f09..23b209b67 100644 --- a/src/web_server/proxy.c +++ b/src/web_server/proxy.c @@ -19,6 +19,7 @@ #include "src/lib/mg_str_utils.h" #include "src/lib/mimetype.h" #include "src/lib/sds_extras.h" +#include "src/web_server/placeholder.h" #include "src/web_server/utility.h" /** @@ -204,7 +205,7 @@ void forward_backend_to_frontend_covercache(struct mg_connection *nc, int ev, vo } case MG_EV_ERROR: { MYMPD_LOG_ERROR(NULL, "HTTP connection to \"%s\", connection %lu failed", backend_nc_data->uri, nc->id); - webserver_serve_placeholder_image(backend_nc_data->frontend_nc, PLACEHOLDER_NA); + webserver_redirect_placeholder_image(backend_nc_data->frontend_nc, PLACEHOLDER_NA); break; } case MG_EV_HTTP_MSG: { @@ -237,7 +238,7 @@ void forward_backend_to_frontend_covercache(struct mg_connection *nc, int ev, vo } else { MYMPD_LOG_ERROR(NULL, "Invalid response from connection \"%lu\", response code %d", nc->id, response_code); - webserver_serve_placeholder_image(backend_nc_data->frontend_nc, PLACEHOLDER_NA); + webserver_redirect_placeholder_image(backend_nc_data->frontend_nc, PLACEHOLDER_NA); } break; } diff --git a/src/web_server/tagart.c b/src/web_server/tagart.c index ba9a14274..26091f4e0 100644 --- a/src/web_server/tagart.c +++ b/src/web_server/tagart.c @@ -19,6 +19,7 @@ #include "src/lib/sds_extras.h" #include "src/lib/utility.h" #include "src/lib/validate.h" +#include "src/web_server/placeholder.h" /** * Request handler for /tagart @@ -40,7 +41,7 @@ bool request_handler_tagart(struct mg_connection *nc, struct mg_http_message *hm vcb_ismpdtag(tag) == false) { MYMPD_LOG_ERROR(NULL, "Failed to decode query"); - webserver_serve_placeholder_image(nc, PLACEHOLDER_NA); + webserver_redirect_placeholder_image(nc, PLACEHOLDER_NA); FREE_SDS(tag); FREE_SDS(value); return true; @@ -82,7 +83,7 @@ bool request_handler_tagart(struct mg_connection *nc, struct mg_http_message *hm return false; #else MYMPD_LOG_DEBUG(NULL, "No image for tag found"); - webserver_serve_placeholder_image(nc, PLACEHOLDER_NA); + webserver_redirect_placeholder_image(nc, PLACEHOLDER_NA); FREE_SDS(tag); FREE_SDS(value); return true; diff --git a/src/web_server/utility.c b/src/web_server/utility.c index d0502f319..f7a15edea 100644 --- a/src/web_server/utility.c +++ b/src/web_server/utility.c @@ -275,8 +275,7 @@ void webserver_send_raw(struct mg_connection *nc, const char *data, size_t len) * @param file file to serve */ void webserver_serve_file(struct mg_connection *nc, struct mg_http_message *hm, const char *path, const char *file) { - const char *mime_type = get_mime_type_by_ext(file); - MYMPD_LOG_DEBUG(NULL, "Serving file %s (%s)", file, mime_type); + MYMPD_LOG_DEBUG(NULL, "Serving file %s", file); static struct mg_http_serve_opts s_http_server_opts; s_http_server_opts.root_dir = path; s_http_server_opts.extra_headers = EXTRA_HEADERS_IMAGE; @@ -352,38 +351,6 @@ void webserver_handle_connection_close(struct mg_connection *nc) { nc->is_resp = 0; } -/** - * Redirects to the placeholder image - * @param nc mongoose connection - * @param placeholder_type Type of placeholder image - */ -void webserver_serve_placeholder_image(struct mg_connection *nc, enum placeholder_types placeholder_type) { - struct t_mg_user_data *mg_user_data = nc->mgr->userdata; - switch (placeholder_type) { - case PLACEHOLDER_NA: - webserver_send_header_redirect(nc, mg_user_data->placeholder_na, ""); - break; - case PLACEHOLDER_STREAM: - webserver_send_header_redirect(nc, mg_user_data->placeholder_stream, ""); - break; - case PLACEHOLDER_MYMPD: - webserver_send_header_redirect(nc, mg_user_data->placeholder_mympd, ""); - break; - case PLACEHOLDER_BOOKLET: - webserver_send_header_redirect(nc, mg_user_data->placeholder_booklet, ""); - break; - case PLACEHOLDER_PLAYLIST: - webserver_send_header_redirect(nc, mg_user_data->placeholder_playlist, ""); - break; - case PLACEHOLDER_SMARTPLS: - webserver_send_header_redirect(nc, mg_user_data->placeholder_smartpls, ""); - break; - case PLACEHOLDER_FOLDER: - webserver_send_header_redirect(nc, mg_user_data->placeholder_folder, ""); - break; - } -} - #ifdef MYMPD_EMBEDDED_ASSETS /** * Struct holding embedded file information diff --git a/src/web_server/utility.h b/src/web_server/utility.h index 5d559ca48..52f6c99e5 100644 --- a/src/web_server/utility.h +++ b/src/web_server/utility.h @@ -62,19 +62,6 @@ struct t_frontend_nc_data { time_t last_ws_ping; //!< last websocket ping from client }; -/** - * Placeholder types - */ -enum placeholder_types { - PLACEHOLDER_NA, - PLACEHOLDER_STREAM, - PLACEHOLDER_MYMPD, - PLACEHOLDER_BOOKLET, - PLACEHOLDER_PLAYLIST, - PLACEHOLDER_SMARTPLS, - PLACEHOLDER_FOLDER -}; - #ifdef MYMPD_EMBEDDED_ASSETS bool webserver_serve_embedded_files(struct mg_connection *nc, sds uri); #endif @@ -87,7 +74,6 @@ sds webserver_find_image_file(sds basefilename); bool find_image_in_folder(sds *coverfile, sds music_directory, sds path, sds *names, int names_len); void webserver_send_error(struct mg_connection *nc, int code, const char *msg); void webserver_serve_file(struct mg_connection *nc, struct mg_http_message *hm, const char *path, const char *file); -void webserver_serve_placeholder_image(struct mg_connection *nc, enum placeholder_types placeholder_type); void webserver_send_header_ok(struct mg_connection *nc, size_t len, const char *extra_headers); void webserver_send_header_redirect(struct mg_connection *nc, const char *location, const char *headers); void webserver_send_header_found(struct mg_connection *nc, const char *location, const char *headers); diff --git a/src/web_server/web_server.c b/src/web_server/web_server.c index a4bb2a5e9..9554ec9e8 100644 --- a/src/web_server/web_server.c +++ b/src/web_server/web_server.c @@ -24,6 +24,7 @@ #include "src/lib/thread.h" #include "src/web_server/albumart.h" #include "src/web_server/folderart.h" +#include "src/web_server/placeholder.h" #include "src/web_server/playlistart.h" #include "src/web_server/proxy.h" #include "src/web_server/request_handler.h" @@ -40,7 +41,6 @@ * Private definitions */ -static void get_placeholder_image(sds workdir, const char *name, sds *result); static void read_queue(struct mg_mgr *mgr); static bool parse_internal_message(struct t_work_response *response, struct t_mg_user_data *mg_user_data); static void ev_handler(struct mg_connection *nc, int ev, void *ev_data); @@ -367,28 +367,6 @@ static bool parse_internal_message(struct t_work_response *response, struct t_mg return rc; } -/** - * Finds and sets the placeholder images - * @param workdir myMPD working directory - * @param name basename to search for - * @param result pointer to sds result - */ -static void get_placeholder_image(sds workdir, const char *name, sds *result) { - sds file = sdscatfmt(sdsempty(), "%S/%s/%s", workdir, DIR_WORK_PICS_THUMBS, name); - MYMPD_LOG_DEBUG(NULL, "Check for custom placeholder image \"%s\"", file); - file = webserver_find_image_file(file); - sdsclear(*result); - if (sdslen(file) > 0) { - file = sds_basename(file); - MYMPD_LOG_INFO(NULL, "Setting custom placeholder image for %s to \"%s\"", name, file); - *result = sdscatfmt(*result, "/browse/%s/%S", DIR_WORK_PICS_THUMBS, file); - } - else { - *result = sdscatfmt(*result, "/assets/%s.svg", name); - } - FREE_SDS(file); -} - /** * Broadcasts a message through all websocket connections for a specific or all partitions * @param mgr mongoose mgr @@ -522,7 +500,7 @@ static void send_api_response(struct mg_mgr *mgr, struct t_work_response *respon webserver_send_albumart_redirect(nc, response->data); break; case INTERNAL_API_TAGART: - webserver_serve_placeholder_image(nc, PLACEHOLDER_NA); + webserver_redirect_placeholder_image(nc, PLACEHOLDER_NA); break; default: MYMPD_LOG_DEBUG(response->partition, "Sending response to conn_id \"%lu\" (length: %lu): %s", nc->id, (unsigned long)sdslen(response->data), response->data); @@ -855,22 +833,22 @@ static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) { } #endif else if (mg_match(hm->uri, mg_str("/assets/coverimage-booklet"), NULL)) { - webserver_serve_placeholder_image(nc, PLACEHOLDER_BOOKLET); + webserver_serve_placeholder_image(nc, hm, mg_user_data->placeholder_booklet); } else if (mg_match(hm->uri, mg_str("/assets/coverimage-mympd"), NULL)) { - webserver_serve_placeholder_image(nc, PLACEHOLDER_MYMPD); + webserver_serve_placeholder_image(nc, hm, mg_user_data->placeholder_mympd); } else if (mg_match(hm->uri, mg_str("/assets/coverimage-notavailable"), NULL)) { - webserver_serve_placeholder_image(nc, PLACEHOLDER_NA); + webserver_serve_placeholder_image(nc, hm, mg_user_data->placeholder_na); } else if (mg_match(hm->uri, mg_str("/assets/coverimage-stream"), NULL)) { - webserver_serve_placeholder_image(nc, PLACEHOLDER_STREAM); + webserver_serve_placeholder_image(nc, hm, mg_user_data->placeholder_stream); } else if (mg_match(hm->uri, mg_str("/assets/coverimage-playlist"), NULL)) { - webserver_serve_placeholder_image(nc, PLACEHOLDER_PLAYLIST); + webserver_serve_placeholder_image(nc, hm, mg_user_data->placeholder_playlist); } else if (mg_match(hm->uri, mg_str("/assets/coverimage-smartpls"), NULL)) { - webserver_serve_placeholder_image(nc, PLACEHOLDER_SMARTPLS); + webserver_serve_placeholder_image(nc, hm, mg_user_data->placeholder_smartpls); } else if (mg_match(hm->uri, mg_str("/index.html"), NULL)) { webserver_send_header_redirect(nc, "/", "");