Subsonic API: make API more compliant
This commit is contained in:
@@ -121,6 +121,13 @@ static std::map<std::string, MediaRetrivalHandlerFunc> mediaRetrievalHandlers
|
|||||||
{GET_COVER_ART_URL, handleGetCoverArt},
|
{GET_COVER_ART_URL, handleGetCoverArt},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static
|
||||||
|
std::string
|
||||||
|
makeNameFilesystemCompatible(const std::string& name)
|
||||||
|
{
|
||||||
|
return replaceInString(name, "/", "_");
|
||||||
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
boost::optional<T>
|
boost::optional<T>
|
||||||
getParameterAs(const Wt::Http::ParameterMap& parameterMap, const std::string& param)
|
getParameterAs(const Wt::Http::ParameterMap& parameterMap, const std::string& param)
|
||||||
@@ -314,6 +321,34 @@ getArtistNames(const std::vector<Database::Artist::pointer>& artists)
|
|||||||
return joinStrings(names, ", ");
|
return joinStrings(names, ", ");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
std::string
|
||||||
|
getTrackPath(const Database::Track::pointer& track)
|
||||||
|
{
|
||||||
|
std::string path;
|
||||||
|
|
||||||
|
// TODO encode '/'?
|
||||||
|
|
||||||
|
if (track->getRelease())
|
||||||
|
{
|
||||||
|
auto artists {track->getRelease()->getArtists()};
|
||||||
|
|
||||||
|
if (artists.size() > 1)
|
||||||
|
path = "Various Artists/";
|
||||||
|
else if (artists.size() == 1)
|
||||||
|
path = makeNameFilesystemCompatible(artists.front()->getName()) + "/";
|
||||||
|
|
||||||
|
path += makeNameFilesystemCompatible(track->getRelease()->getName()) + "/";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (track->getDiscNumber())
|
||||||
|
path += *track->getDiscNumber() + "-";
|
||||||
|
if (track->getTrackNumber())
|
||||||
|
path += *track->getTrackNumber() + "-";
|
||||||
|
|
||||||
|
return path + makeNameFilesystemCompatible(track->getName()) + ".mp3";
|
||||||
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
Response::Node
|
Response::Node
|
||||||
trackToResponseNode(const Database::Track::pointer& track)
|
trackToResponseNode(const Database::Track::pointer& track)
|
||||||
@@ -349,7 +384,7 @@ trackToResponseNode(const Database::Track::pointer& track)
|
|||||||
trackResponse.setAttribute("parent", IdToString({Id::Type::Release, track->getRelease().id()}));
|
trackResponse.setAttribute("parent", IdToString({Id::Type::Release, track->getRelease().id()}));
|
||||||
}
|
}
|
||||||
|
|
||||||
trackResponse.setAttribute("path", track->getName() + ".mp3");
|
trackResponse.setAttribute("path", getTrackPath(track));
|
||||||
trackResponse.setAttribute("bitRate", std::to_string(REPORTED_BITRATE));
|
trackResponse.setAttribute("bitRate", std::to_string(REPORTED_BITRATE));
|
||||||
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", "mp3");
|
||||||
@@ -392,7 +427,11 @@ releaseToResponseNode(const Database::Release::pointer& release, bool id3)
|
|||||||
albumNode.setAttribute("year", std::to_string(*release->getReleaseYear()));
|
albumNode.setAttribute("year", std::to_string(*release->getReleaseYear()));
|
||||||
|
|
||||||
auto artists {release->getArtists()};
|
auto artists {release->getArtists()};
|
||||||
if (!artists.empty())
|
if (artists.empty() && !id3)
|
||||||
|
{
|
||||||
|
albumNode.setAttribute("parent", IdToString({Id::Type::Root}));
|
||||||
|
}
|
||||||
|
else if (!artists.empty())
|
||||||
{
|
{
|
||||||
if (artists.size() > 1)
|
if (artists.size() > 1)
|
||||||
{
|
{
|
||||||
@@ -412,6 +451,18 @@ releaseToResponseNode(const Database::Release::pointer& release, bool id3)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (id3)
|
||||||
|
{
|
||||||
|
// Report the first GENRE for this track
|
||||||
|
Database::ClusterType::pointer clusterType {Database::ClusterType::getByName(*release.session(), CLUSTER_TYPE_GENRE)};
|
||||||
|
if (clusterType)
|
||||||
|
{
|
||||||
|
auto clusters {release->getClusterGroups({clusterType}, 1)};
|
||||||
|
if (!clusters.empty() && !clusters.front().empty())
|
||||||
|
albumNode.setAttribute("genre", clusters.front().front()->getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return albumNode;
|
return albumNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -423,10 +474,9 @@ artistToResponseNode(const Database::Artist::pointer& artist, bool id3)
|
|||||||
|
|
||||||
artistNode.setAttribute("id", IdToString({Id::Type::Artist, artist.id()}));
|
artistNode.setAttribute("id", IdToString({Id::Type::Artist, artist.id()}));
|
||||||
artistNode.setAttribute("name", artist->getName());
|
artistNode.setAttribute("name", artist->getName());
|
||||||
artistNode.setAttribute("albumCount", std::to_string(artist->getReleases().size()));
|
|
||||||
|
|
||||||
if (!id3)
|
if (id3)
|
||||||
artistNode.setAttribute("parent", IdToString({Id::Type::Root}));
|
artistNode.setAttribute("albumCount", std::to_string(artist->getReleases().size()));
|
||||||
|
|
||||||
return artistNode;
|
return artistNode;
|
||||||
}
|
}
|
||||||
@@ -656,6 +706,8 @@ handleGetMusicDirectoryRequest(const Wt::Http::ParameterMap& request, Database::
|
|||||||
Response response {Response::createOkResponse()};
|
Response response {Response::createOkResponse()};
|
||||||
Response::Node& directoryNode {response.createNode("directory")};
|
Response::Node& directoryNode {response.createNode("directory")};
|
||||||
|
|
||||||
|
directoryNode.setAttribute("id", IdToString(id));
|
||||||
|
|
||||||
switch (id.type)
|
switch (id.type)
|
||||||
{
|
{
|
||||||
case Id::Type::Root:
|
case Id::Type::Root:
|
||||||
@@ -679,7 +731,7 @@ handleGetMusicDirectoryRequest(const Wt::Http::ParameterMap& request, Database::
|
|||||||
if (!artist)
|
if (!artist)
|
||||||
throw Error {Error::Code::RequestedDataNotFound};
|
throw Error {Error::Code::RequestedDataNotFound};
|
||||||
|
|
||||||
directoryNode.setAttribute("name", artist->getName());
|
directoryNode.setAttribute("name", makeNameFilesystemCompatible(artist->getName()));
|
||||||
|
|
||||||
auto releases {artist->getReleases()};
|
auto releases {artist->getReleases()};
|
||||||
for (const Database::Release::pointer& release : releases)
|
for (const Database::Release::pointer& release : releases)
|
||||||
@@ -696,7 +748,7 @@ handleGetMusicDirectoryRequest(const Wt::Http::ParameterMap& request, Database::
|
|||||||
if (!release)
|
if (!release)
|
||||||
throw Error {Error::Code::RequestedDataNotFound};
|
throw Error {Error::Code::RequestedDataNotFound};
|
||||||
|
|
||||||
directoryNode.setAttribute("name", release->getName());
|
directoryNode.setAttribute("name", makeNameFilesystemCompatible(release->getName()));
|
||||||
|
|
||||||
auto tracks {release->getTracks()};
|
auto tracks {release->getTracks()};
|
||||||
for (const Database::Track::pointer& track : tracks)
|
for (const Database::Track::pointer& track : tracks)
|
||||||
|
|||||||
Reference in New Issue
Block a user