From ebc59dd70c8ddb3b3e58612cebbcc9504999d4fb Mon Sep 17 00:00:00 2001 From: emeric Date: Sat, 11 Nov 2023 22:54:27 +0100 Subject: [PATCH] Subsonic API: added contentType and transcodedContentType fields, fixes #363 --- src/libs/av/impl/AudioFile.cpp | 56 ++++++++++--------- .../av/impl/RawResourceHandlerCreator.cpp | 10 +--- src/libs/av/include/av/IAudioFile.hpp | 3 +- src/libs/subsonic/impl/responses/Song.cpp | 8 ++- src/lms/ui/explore/ReleaseView.cpp | 4 +- 5 files changed, 43 insertions(+), 38 deletions(-) diff --git a/src/libs/av/impl/AudioFile.cpp b/src/libs/av/impl/AudioFile.cpp index 40f4d38b..e6172a98 100644 --- a/src/libs/av/impl/AudioFile.cpp +++ b/src/libs/av/impl/AudioFile.cpp @@ -258,35 +258,39 @@ namespace Av return res; } - std::optional guessAudioFileFormat(const std::filesystem::path& file) + std::string_view getMimeType(const std::filesystem::path& fileExtension) { - const AVOutputFormat* format{ ::av_guess_format(NULL, file.string().c_str(), NULL) }; - if (!format || !format->name) + static const std::unordered_map entries { - LMS_LOG(AV, INFO) << "File '" << file.string() << "': cannot guess file format!"; - return std::nullopt; - } + {".mp3", "audio/mpeg"}, + {".ogg", "audio/ogg"}, + {".oga", "audio/ogg"}, + {".opus", "audio/opus"}, + {".aac", "audio/aac"}, + {".alac", "audio/mp4"}, + {".m4a", "audio/mp4"}, + {".m4b", "audio/mp4"}, + {".flac", "audio/flac"}, + {".webm", "audio/webm"}, + {".wav", "audio/x-wav"}, + {".wma", "audio/x-ms-wma"}, + {".ape", "audio/x-monkeys-audio"}, + {".mpc", "audio/x-musepack"}, + {".shn", "audio/x-shn"}, + {".aif", "audio/x-aiff"}, + {".aiff", "audio/x-aiff"}, + {".m3u", "audio/x-mpegurl"}, + {".pls", "audio/x-scpls"}, + {".dsf", "audio/dsd"}, + {".wv", "audio/x-wavpack"}, + {".wvp", "audio/x-wavpack"}, + {".mka", "audio/x-matroska"}, + }; - LMS_LOG(AV, DEBUG) << "File '" << file.string() << "', formats = '" << format->name << "'"; + auto it{ entries.find(fileExtension) }; + if (it == std::cend(entries)) + return ""; - const auto formats{ StringUtils::splitString(format->name, ",") }; - if (formats.size() > 1) - LMS_LOG(AV, INFO) << "File '" << file.string() << "' reported several formats: '" << format->name << "'"; - - std::vector mimeTypes; - if (format->mime_type) - mimeTypes = StringUtils::splitString(format->mime_type, ","); - - if (mimeTypes.empty()) - LMS_LOG(AV, INFO) << "File '" << file.string() << "', no mime type found!"; - else if (mimeTypes.size() > 1) - LMS_LOG(AV, INFO) << "File '" << file.string() << "' reported several mime types: '" << format->mime_type << "'"; - - AudioFileFormat res; - res.format = formats.front(); - res.mimeType = mimeTypes.empty() ? "application/octet-stream" : mimeTypes.front(); - - return res; + return it->second; } - } // namespace Av diff --git a/src/libs/av/impl/RawResourceHandlerCreator.cpp b/src/libs/av/impl/RawResourceHandlerCreator.cpp index 5272b421..04ea6f88 100644 --- a/src/libs/av/impl/RawResourceHandlerCreator.cpp +++ b/src/libs/av/impl/RawResourceHandlerCreator.cpp @@ -26,13 +26,7 @@ namespace Av { std::unique_ptr createRawResourceHandler(const std::filesystem::path& path) { - std::string mimeType; - const auto guessedAudioFormat{ Av::guessAudioFileFormat(path) }; - if (guessedAudioFormat) - mimeType = guessedAudioFormat->mimeType; - else - mimeType = "application/octet-stream"; - - return createFileResourceHandler(path, mimeType); + std::string_view mimeType{ Av::getMimeType(path.extension()) }; + return createFileResourceHandler(path, mimeType.empty() ? "application/octet-stream" : mimeType); } } diff --git a/src/libs/av/include/av/IAudioFile.hpp b/src/libs/av/include/av/IAudioFile.hpp index 3083056a..0c788c66 100644 --- a/src/libs/av/include/av/IAudioFile.hpp +++ b/src/libs/av/include/av/IAudioFile.hpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include "Types.hpp" @@ -72,7 +73,7 @@ namespace Av std::string format; }; - std::optional guessAudioFileFormat(const std::filesystem::path& file); + std::string_view getMimeType(const std::filesystem::path& fileExtension); } // namespace Av diff --git a/src/libs/subsonic/impl/responses/Song.cpp b/src/libs/subsonic/impl/responses/Song.cpp index edc091be..4544ea70 100644 --- a/src/libs/subsonic/impl/responses/Song.cpp +++ b/src/libs/subsonic/impl/responses/Song.cpp @@ -21,6 +21,7 @@ #include +#include "av/IAudioFile.hpp" #include "services/database/Artist.hpp" #include "services/database/Cluster.hpp" #include "services/database/Listen.hpp" @@ -123,7 +124,11 @@ namespace API::Subsonic trackResponse.setAttribute("suffix", extension.string().substr(1)); } - trackResponse.setAttribute("transcodedSuffix", formatToSuffix(user->getSubsonicDefaultTranscodeFormat())); + { + const std::string fileSuffix{ formatToSuffix(user->getSubsonicDefaultTranscodeFormat()) }; + trackResponse.setAttribute("transcodedSuffix", fileSuffix); + trackResponse.setAttribute("transcodedContentType", Av::getMimeType(std::filesystem::path{ "." + fileSuffix })); + } trackResponse.setAttribute("coverArt", idToString(track->getId())); @@ -151,6 +156,7 @@ namespace API::Subsonic trackResponse.setAttribute("bitRate", (track->getBitrate() / 1000)); trackResponse.setAttribute("type", "music"); trackResponse.setAttribute("created", StringUtils::toISO8601String(track->getLastWritten())); + trackResponse.setAttribute("contentType", Av::getMimeType(track->getPath().extension())); if (const Wt::WDateTime dateTime{ Service::get()->getStarredDateTime(user->getId(), track->getId()) }; dateTime.isValid()) trackResponse.setAttribute("starred", StringUtils::toISO8601String(dateTime)); diff --git a/src/lms/ui/explore/ReleaseView.cpp b/src/lms/ui/explore/ReleaseView.cpp index 6ed8bc64..3e42f776 100644 --- a/src/lms/ui/explore/ReleaseView.cpp +++ b/src/lms/ui/explore/ReleaseView.cpp @@ -152,10 +152,10 @@ namespace UserInterface } } - if (std::size_t meanBitrate{ release->getMeanBitrate() }) + if (const std::size_t meanBitrate{ release->getMeanBitrate() }) { releaseInfo->setCondition("if-has-bitrate", true); - releaseInfo->bindString("bitrate", std::to_string(release->getMeanBitrate() / 1000) + " kbps"); + releaseInfo->bindString("bitrate", std::to_string(meanBitrate / 1000) + " kbps"); } Wt::WPushButton* okBtn{ releaseInfo->bindNew("ok-btn", Wt::WString::tr("Lms.ok")) };