Subsonic API: properly handle release artists

This commit is contained in:
emeric
2019-05-20 13:58:39 +02:00
parent 234d9f80ef
commit eec74c3f45
3 changed files with 36 additions and 28 deletions
+1 -1
View File
@@ -18,7 +18,7 @@
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label class="control-label col-sm-2" for="${id:transcoding}"> <label class="control-label col-sm-2" for="${id:transcoding-format}">
${tr:Lms.Settings.transcoding-format} ${tr:Lms.Settings.transcoding-format}
</label> </label>
<div class="col-sm-5"> <div class="col-sm-5">
+31 -18
View File
@@ -39,8 +39,13 @@
#include "SubsonicId.hpp" #include "SubsonicId.hpp"
#include "SubsonicResponse.hpp" #include "SubsonicResponse.hpp"
#define CLUSTER_TYPE_GENRE "GENRE" static const std::string genreClusterName {"GENRE"};
#define REPORTED_BITRATE 128 // Files are always reported to be in the same format
static const std::size_t reportedBitrate {128};
static const std::string reportedFileSuffix {"mp3"};
static const Av::Encoding reportedEncoding {Av::Encoding::MP3};
static const Av::Encoding transcodeEncoding {Av::Encoding::MP3};
// Requests // Requests
#define PING_URL "/rest/ping.view" #define PING_URL "/rest/ping.view"
@@ -413,9 +418,12 @@ getTrackPath(const Database::Track::pointer& track)
{ {
std::string path; std::string path;
if (track->getRelease()) auto release {track->getRelease()};
if (release)
{ {
auto artists {track->getRelease()->getArtists()}; auto artists {release->getReleaseArtists()};
if (artists.empty())
artists = release->getArtists();
if (artists.size() > 1) if (artists.size() > 1)
path = "Various Artists/"; path = "Various Artists/";
@@ -430,7 +438,7 @@ getTrackPath(const Database::Track::pointer& track)
if (track->getTrackNumber()) if (track->getTrackNumber())
path += std::to_string(*track->getTrackNumber()) + "-"; path += std::to_string(*track->getTrackNumber()) + "-";
return path + makeNameFilesystemCompatible(track->getName()) + ".mp3"; return path + makeNameFilesystemCompatible(track->getName()) + "." + reportedFileSuffix;
} }
static static
@@ -448,7 +456,7 @@ trackToResponseNode(const Database::Track::pointer& track)
trackResponse.setAttribute("discNumber", std::to_string(*track->getDiscNumber())); trackResponse.setAttribute("discNumber", std::to_string(*track->getDiscNumber()));
if (track->getYear()) if (track->getYear())
trackResponse.setAttribute("year", std::to_string(*track->getYear())); trackResponse.setAttribute("year", std::to_string(*track->getYear()));
trackResponse.setAttribute("size", std::to_string(REPORTED_BITRATE*1000/8 * std::chrono::duration_cast<std::chrono::seconds>(track->getDuration()).count())); trackResponse.setAttribute("size", std::to_string(reportedBitrate * 1000 / 8 * std::chrono::duration_cast<std::chrono::seconds>(track->getDuration()).count()));
trackResponse.setAttribute("coverArt", IdToString({Id::Type::Track, track.id()})); trackResponse.setAttribute("coverArt", IdToString({Id::Type::Track, track.id()}));
@@ -469,14 +477,14 @@ trackToResponseNode(const Database::Track::pointer& track)
} }
trackResponse.setAttribute("path", getTrackPath(track)); trackResponse.setAttribute("path", getTrackPath(track));
trackResponse.setAttribute("bitRate", std::to_string(REPORTED_BITRATE)); trackResponse.setAttribute("bitRate", std::to_string(reportedBitrate));
trackResponse.setAttribute("duration", std::to_string(std::chrono::duration_cast<std::chrono::seconds>(track->getDuration()).count())); trackResponse.setAttribute("duration", std::to_string(std::chrono::duration_cast<std::chrono::seconds>(track->getDuration()).count()));
trackResponse.setAttribute("suffix", "mp3"); trackResponse.setAttribute("suffix", reportedFileSuffix);
trackResponse.setAttribute("contentType", "audio/mpeg"); trackResponse.setAttribute("contentType", Av::encodingToMimetype(reportedEncoding));
trackResponse.setAttribute("type", "music"); trackResponse.setAttribute("type", "music");
// Report the first GENRE for this track // Report the first GENRE for this track
Database::ClusterType::pointer clusterType {Database::ClusterType::getByName(*track.session(), CLUSTER_TYPE_GENRE)}; Database::ClusterType::pointer clusterType {Database::ClusterType::getByName(*track.session(), genreClusterName)};
if (clusterType) if (clusterType)
{ {
auto clusters {track->getClusterGroups({clusterType}, 1)}; auto clusters {track->getClusterGroups({clusterType}, 1)};
@@ -510,7 +518,10 @@ releaseToResponseNode(const Database::Release::pointer& release, bool id3)
if (release->getReleaseYear()) if (release->getReleaseYear())
albumNode.setAttribute("year", std::to_string(*release->getReleaseYear())); albumNode.setAttribute("year", std::to_string(*release->getReleaseYear()));
auto artists {release->getArtists()}; auto artists {release->getReleaseArtists()};
if (artists.empty())
artists = release->getArtists();
if (artists.empty() && !id3) if (artists.empty() && !id3)
{ {
albumNode.setAttribute("parent", IdToString({Id::Type::Root})); albumNode.setAttribute("parent", IdToString({Id::Type::Root}));
@@ -538,7 +549,7 @@ releaseToResponseNode(const Database::Release::pointer& release, bool id3)
if (id3) if (id3)
{ {
// Report the first GENRE for this track // Report the first GENRE for this track
Database::ClusterType::pointer clusterType {Database::ClusterType::getByName(*release.session(), CLUSTER_TYPE_GENRE)}; Database::ClusterType::pointer clusterType {Database::ClusterType::getByName(*release.session(), genreClusterName)};
if (clusterType) if (clusterType)
{ {
auto clusters {release->getClusterGroups({clusterType}, 1)}; auto clusters {release->getClusterGroups({clusterType}, 1)};
@@ -767,7 +778,7 @@ handleGetAlbumListRequestCommon(const RequestContext& context, bool id3)
// Mandatory param // Mandatory param
std::string genre {getMandatoryParameterAs<std::string>(context.parameters, "genre")}; std::string genre {getMandatoryParameterAs<std::string>(context.parameters, "genre")};
Database::ClusterType::pointer clusterType {Database::ClusterType::getByName(context.db.getSession(), CLUSTER_TYPE_GENRE)}; Database::ClusterType::pointer clusterType {Database::ClusterType::getByName(context.db.getSession(), genreClusterName)};
if (clusterType) if (clusterType)
{ {
Database::Cluster::pointer cluster {clusterType->getCluster(genre)}; Database::Cluster::pointer cluster {clusterType->getCluster(genre)};
@@ -1009,7 +1020,7 @@ handleGetGenresRequest(RequestContext& context)
Wt::Dbo::Transaction transaction {context.db.getSession()}; Wt::Dbo::Transaction transaction {context.db.getSession()};
auto clusterType {Database::ClusterType::getByName(context.db.getSession(), CLUSTER_TYPE_GENRE)}; auto clusterType {Database::ClusterType::getByName(context.db.getSession(), genreClusterName)};
if (clusterType) if (clusterType)
{ {
auto clusters {clusterType->getClusters()}; auto clusters {clusterType->getClusters()};
@@ -1197,7 +1208,7 @@ handleGetSongsByGenreRequest(RequestContext& context)
Wt::Dbo::Transaction transaction {context.db.getSession()}; Wt::Dbo::Transaction transaction {context.db.getSession()};
auto clusterType {Database::ClusterType::getByName(context.db.getSession(), CLUSTER_TYPE_GENRE)}; auto clusterType {Database::ClusterType::getByName(context.db.getSession(), genreClusterName)};
if (!clusterType) if (!clusterType)
throw Error {Error::Code::RequestedDataNotFound}; throw Error {Error::Code::RequestedDataNotFound};
@@ -1369,7 +1380,7 @@ createTranscoder(RequestContext& context)
parameters.stripMetadata = false; // Since it can be cached and some players read the metadata from the downloaded file parameters.stripMetadata = false; // Since it can be cached and some players read the metadata from the downloaded file
parameters.bitrate = *maxBitRate * 1000; parameters.bitrate = *maxBitRate * 1000;
parameters.encoding = Av::Encoding::MP3; parameters.encoding = transcodeEncoding;
return std::make_shared<Av::Transcoder>(trackPath, parameters); return std::make_shared<Av::Transcoder>(trackPath, parameters);
} }
@@ -1383,8 +1394,10 @@ handleStream(RequestContext& context, Wt::Http::ResponseContinuation* continuati
if (!continuation) if (!continuation)
{ {
transcoder = createTranscoder(context); transcoder = createTranscoder(context);
response.setMimeType(Av::encodingToMimetype(Av::Encoding::MP3));
transcoder->start(); transcoder->start();
response.setMimeType(transcoder->getOutputMimeType());
LMS_LOG(API_SUBSONIC, DEBUG) << "Mime type set to '" << transcoder->getOutputMimeType() << "'";
} }
else else
{ {
@@ -1407,7 +1420,7 @@ handleStream(RequestContext& context, Wt::Http::ResponseContinuation* continuati
if (!response.out()) if (!response.out())
{ {
LMS_LOG(UI, ERROR) << "Write failed!"; LMS_LOG(API_SUBSONIC, ERROR) << "Write failed!";
return; return;
} }
} }
+4 -9
View File
@@ -27,10 +27,10 @@ std::string encodingToMimetype(Encoding encoding)
{ {
static const std::map<Encoding, std::string> encodings static const std::map<Encoding, std::string> encodings
{ {
{Encoding::MP3, "audio/mp3"}, {Encoding::MP3, "audio/mpeg"},
{Encoding::OGG_VORBIS, "audio/ogg"}, {Encoding::OGG_VORBIS, "audio/ogg"},
{Encoding::OGG_OPUS, "audio/opus"}, {Encoding::OGG_OPUS, "audio/opus"},
{Encoding::WEBM_VORBIS, "audio/webm"}, {Encoding::WEBM_VORBIS, "audio/webm"},
}; };
auto it {encodings.find(encoding)}; auto it {encodings.find(encoding)};
@@ -40,10 +40,5 @@ std::string encodingToMimetype(Encoding encoding)
return it->second; return it->second;
} }
Encoding guessEncoding(const boost::filesystem::path& file)
{
}
} }