Subsonic API: added contentType and transcodedContentType fields, fixes #363

This commit is contained in:
emeric
2023-11-11 22:54:27 +01:00
parent 1d21ba41b7
commit ebc59dd70c
5 changed files with 43 additions and 38 deletions
+30 -26
View File
@@ -258,35 +258,39 @@ namespace Av
return res; return res;
} }
std::optional<AudioFileFormat> 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) }; static const std::unordered_map<std::filesystem::path, std::string_view> entries
if (!format || !format->name)
{ {
LMS_LOG(AV, INFO) << "File '" << file.string() << "': cannot guess file format!"; {".mp3", "audio/mpeg"},
return std::nullopt; {".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, ",") }; return it->second;
if (formats.size() > 1)
LMS_LOG(AV, INFO) << "File '" << file.string() << "' reported several formats: '" << format->name << "'";
std::vector<std::string_view> 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;
} }
} // namespace Av } // namespace Av
@@ -26,13 +26,7 @@ namespace Av
{ {
std::unique_ptr<IResourceHandler> createRawResourceHandler(const std::filesystem::path& path) std::unique_ptr<IResourceHandler> createRawResourceHandler(const std::filesystem::path& path)
{ {
std::string mimeType; std::string_view mimeType{ Av::getMimeType(path.extension()) };
const auto guessedAudioFormat{ Av::guessAudioFileFormat(path) }; return createFileResourceHandler(path, mimeType.empty() ? "application/octet-stream" : mimeType);
if (guessedAudioFormat)
mimeType = guessedAudioFormat->mimeType;
else
mimeType = "application/octet-stream";
return createFileResourceHandler(path, mimeType);
} }
} }
+2 -1
View File
@@ -27,6 +27,7 @@
#include <unordered_map> #include <unordered_map>
#include <optional> #include <optional>
#include <string> #include <string>
#include <string_view>
#include <vector> #include <vector>
#include "Types.hpp" #include "Types.hpp"
@@ -72,7 +73,7 @@ namespace Av
std::string format; std::string format;
}; };
std::optional<AudioFileFormat> guessAudioFileFormat(const std::filesystem::path& file); std::string_view getMimeType(const std::filesystem::path& fileExtension);
} // namespace Av } // namespace Av
+7 -1
View File
@@ -21,6 +21,7 @@
#include <string_view> #include <string_view>
#include "av/IAudioFile.hpp"
#include "services/database/Artist.hpp" #include "services/database/Artist.hpp"
#include "services/database/Cluster.hpp" #include "services/database/Cluster.hpp"
#include "services/database/Listen.hpp" #include "services/database/Listen.hpp"
@@ -123,7 +124,11 @@ namespace API::Subsonic
trackResponse.setAttribute("suffix", extension.string().substr(1)); 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())); trackResponse.setAttribute("coverArt", idToString(track->getId()));
@@ -151,6 +156,7 @@ namespace API::Subsonic
trackResponse.setAttribute("bitRate", (track->getBitrate() / 1000)); trackResponse.setAttribute("bitRate", (track->getBitrate() / 1000));
trackResponse.setAttribute("type", "music"); trackResponse.setAttribute("type", "music");
trackResponse.setAttribute("created", StringUtils::toISO8601String(track->getLastWritten())); trackResponse.setAttribute("created", StringUtils::toISO8601String(track->getLastWritten()));
trackResponse.setAttribute("contentType", Av::getMimeType(track->getPath().extension()));
if (const Wt::WDateTime dateTime{ Service<Feedback::IFeedbackService>::get()->getStarredDateTime(user->getId(), track->getId()) }; dateTime.isValid()) if (const Wt::WDateTime dateTime{ Service<Feedback::IFeedbackService>::get()->getStarredDateTime(user->getId(), track->getId()) }; dateTime.isValid())
trackResponse.setAttribute("starred", StringUtils::toISO8601String(dateTime)); trackResponse.setAttribute("starred", StringUtils::toISO8601String(dateTime));
+2 -2
View File
@@ -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->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<Wt::WPushButton>("ok-btn", Wt::WString::tr("Lms.ok")) }; Wt::WPushButton* okBtn{ releaseInfo->bindNew<Wt::WPushButton>("ok-btn", Wt::WString::tr("Lms.ok")) };