API Subsonic: add ID3 browsing support

This commit is contained in:
emeric
2019-04-05 15:25:23 +02:00
parent 35b3d631ef
commit 316ef6eeb5
5 changed files with 189 additions and 75 deletions
+166 -74
View File
@@ -43,11 +43,13 @@
#define GET_RANDOM_SONGS_URL "/rest/getRandomSongs.view" #define GET_RANDOM_SONGS_URL "/rest/getRandomSongs.view"
#define GET_ALBUM_LIST_URL "/rest/getAlbumList.view" #define GET_ALBUM_LIST_URL "/rest/getAlbumList.view"
#define GET_ALBUM_LIST2_URL "/rest/getAlbumList2.view" #define GET_ALBUM_LIST2_URL "/rest/getAlbumList2.view"
#define GET_ALBUM_URL "/rest/getAlbum.view"
#define GET_ARTIST_URL "/rest/getArtist.view"
#define GET_ARTISTS_URL "/rest/getArtists.view"
#define GET_MUSIC_DIRECTORY_URL "/rest/getMusicDirectory.view" #define GET_MUSIC_DIRECTORY_URL "/rest/getMusicDirectory.view"
#define GET_MUSIC_FOLDERS_URL "/rest/getMusicFolders.view" #define GET_MUSIC_FOLDERS_URL "/rest/getMusicFolders.view"
#define GET_GENRES_URL "/rest/getGenres.view" #define GET_GENRES_URL "/rest/getGenres.view"
#define GET_INDEXES_URL "/rest/getIndexes.view" #define GET_INDEXES_URL "/rest/getIndexes.view"
#define GET_ARTISTS_URL "/rest/getArtists.view"
#define GET_STARRED_URL "/rest/getStarred.view" #define GET_STARRED_URL "/rest/getStarred.view"
#define GET_STARRED2_URL "/rest/getStarred2.view" #define GET_STARRED2_URL "/rest/getStarred2.view"
#define GET_PLAYLISTS_URL "/rest/getPlaylists.view" #define GET_PLAYLISTS_URL "/rest/getPlaylists.view"
@@ -67,11 +69,13 @@ static Response handleGetLicenseRequest(const Wt::Http::ParameterMap& request, D
static Response handleGetRandomSongsRequest(const Wt::Http::ParameterMap& request, Database::Handler& db); static Response handleGetRandomSongsRequest(const Wt::Http::ParameterMap& request, Database::Handler& db);
static Response handleGetAlbumListRequest(const Wt::Http::ParameterMap& request, Database::Handler& db); static Response handleGetAlbumListRequest(const Wt::Http::ParameterMap& request, Database::Handler& db);
static Response handleGetAlbumList2Request(const Wt::Http::ParameterMap& request, Database::Handler& db); static Response handleGetAlbumList2Request(const Wt::Http::ParameterMap& request, Database::Handler& db);
static Response handleGetAlbumRequest(const Wt::Http::ParameterMap& request, Database::Handler& db);
static Response handleGetArtistRequest(const Wt::Http::ParameterMap& request, Database::Handler& db);
static Response handleGetArtistsRequest(const Wt::Http::ParameterMap& request, Database::Handler& db);
static Response handleGetMusicDirectoryRequest(const Wt::Http::ParameterMap& request, Database::Handler& db); static Response handleGetMusicDirectoryRequest(const Wt::Http::ParameterMap& request, Database::Handler& db);
static Response handleGetMusicFoldersRequest(const Wt::Http::ParameterMap& request, Database::Handler& db); static Response handleGetMusicFoldersRequest(const Wt::Http::ParameterMap& request, Database::Handler& db);
static Response handleGetGenresRequest(const Wt::Http::ParameterMap& request, Database::Handler& db); static Response handleGetGenresRequest(const Wt::Http::ParameterMap& request, Database::Handler& db);
static Response handleGetIndexesRequest(const Wt::Http::ParameterMap& request, Database::Handler& db); static Response handleGetIndexesRequest(const Wt::Http::ParameterMap& request, Database::Handler& db);
static Response handleGetArtistsRequest(const Wt::Http::ParameterMap& request, Database::Handler& db);
static Response handleGetStarredRequest(const Wt::Http::ParameterMap& request, Database::Handler& db); static Response handleGetStarredRequest(const Wt::Http::ParameterMap& request, Database::Handler& db);
static Response handleGetStarred2Request(const Wt::Http::ParameterMap& request, Database::Handler& db); static Response handleGetStarred2Request(const Wt::Http::ParameterMap& request, Database::Handler& db);
static Response handleGetPlaylistsRequest(const Wt::Http::ParameterMap& request, Database::Handler& db); static Response handleGetPlaylistsRequest(const Wt::Http::ParameterMap& request, Database::Handler& db);
@@ -89,11 +93,13 @@ static std::map<std::string, RequestHandlerFunc> requestHandlers
{GET_RANDOM_SONGS_URL, handleGetRandomSongsRequest}, {GET_RANDOM_SONGS_URL, handleGetRandomSongsRequest},
{GET_ALBUM_LIST_URL, handleGetAlbumListRequest}, {GET_ALBUM_LIST_URL, handleGetAlbumListRequest},
{GET_ALBUM_LIST2_URL, handleGetAlbumList2Request}, {GET_ALBUM_LIST2_URL, handleGetAlbumList2Request},
{GET_ALBUM_URL, handleGetAlbumRequest},
{GET_ARTIST_URL, handleGetArtistRequest},
{GET_ARTISTS_URL, handleGetArtistsRequest},
{GET_MUSIC_DIRECTORY_URL, handleGetMusicDirectoryRequest}, {GET_MUSIC_DIRECTORY_URL, handleGetMusicDirectoryRequest},
{GET_MUSIC_FOLDERS_URL, handleGetMusicFoldersRequest}, {GET_MUSIC_FOLDERS_URL, handleGetMusicFoldersRequest},
{GET_GENRES_URL, handleGetGenresRequest}, {GET_GENRES_URL, handleGetGenresRequest},
{GET_INDEXES_URL, handleGetIndexesRequest}, {GET_INDEXES_URL, handleGetIndexesRequest},
{GET_ARTISTS_URL, handleGetArtistsRequest},
{GET_STARRED_URL, handleGetStarredRequest}, {GET_STARRED_URL, handleGetStarredRequest},
{GET_STARRED2_URL, handleGetStarred2Request}, {GET_STARRED2_URL, handleGetStarred2Request},
{GET_PLAYLISTS_URL, handleGetPlaylistsRequest}, {GET_PLAYLISTS_URL, handleGetPlaylistsRequest},
@@ -138,6 +144,21 @@ getParameterAs(const Wt::Http::ParameterMap& parameterMap, const std::string& pa
return it->second.front(); return it->second.front();
} }
Id
getParameterAsId(const Wt::Http::ParameterMap& parameterMap, const std::string& param)
{
auto idParam {getParameterAs<std::string>(parameterMap, "id")};
if (!idParam)
throw Error {Error::Code::RequiredParameterMissing};
auto id {IdFromString(*idParam)};
if (!id)
throw Error {"Bad id"};
return *id;
}
struct ClientInfo struct ClientInfo
{ {
std::string name; std::string name;
@@ -292,21 +313,29 @@ getArtistNames(const std::vector<Database::Artist::pointer> artists)
static static
Response::Node Response::Node
trackToResponseNode(const Database::Track::pointer& track) trackToResponseNode(const Database::Track::pointer& track, bool id3)
{ {
Response::Node trackResponse; Response::Node trackResponse;
trackResponse.setAttribute("title", track->getName()); trackResponse.setAttribute("title", track->getName());
if (!id3)
trackResponse.setAttribute("isDir", "false");
trackResponse.setAttribute("id", IdToString({Id::Type::Track, track.id()})); trackResponse.setAttribute("id", IdToString({Id::Type::Track, track.id()}));
trackResponse.setAttribute("coverArt", IdToString({Id::Type::Track, track.id()})); trackResponse.setAttribute("coverArt", IdToString({Id::Type::Track, track.id()}));
trackResponse.setAttribute("isDir", "false");
auto artists {track->getArtists()}; auto artists {track->getArtists()};
if (!artists.empty()) if (!artists.empty())
{
trackResponse.setAttribute("artist", getArtistNames(artists)); trackResponse.setAttribute("artist", getArtistNames(artists));
if (artists.size() == 1 && id3)
trackResponse.setAttribute("artistId", IdToString({Id::Type::Artist, artists.front().id()}));
}
trackResponse.setAttribute("path", track->getName() + ".mp3"); trackResponse.setAttribute("path", track->getName() + ".mp3");
trackResponse.setAttribute("bitrate", "128"); trackResponse.setAttribute("bitRate", "128");
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");
trackResponse.setAttribute("contentType", "audio/mpeg"); trackResponse.setAttribute("contentType", "audio/mpeg");
@@ -320,7 +349,11 @@ trackToResponseNode(const Database::Track::pointer& track)
if (track->getRelease()) if (track->getRelease())
{ {
trackResponse.setAttribute("parent", IdToString({Id::Type::Release, track->getRelease().id()})); if (id3)
trackResponse.setAttribute("albumId", IdToString({Id::Type::Release, track->getRelease().id()}));
else
trackResponse.setAttribute("parent", IdToString({Id::Type::Release, track->getRelease().id()}));
trackResponse.setAttribute("album", track->getRelease()->getName()); trackResponse.setAttribute("album", track->getRelease()->getName());
} }
@@ -329,14 +362,26 @@ trackToResponseNode(const Database::Track::pointer& track)
static static
Response::Node Response::Node
releaseToResponseNode(const Database::Release::pointer& release) releaseToResponseNode(const Database::Release::pointer& release, bool id3)
{ {
Response::Node albumNode; Response::Node albumNode;
albumNode.setAttribute("title", release->getName()); if (id3)
{
albumNode.setAttribute("name", release->getName());
albumNode.setAttribute("songCount", std::to_string(release->getTracks().size()));
albumNode.setAttribute("duration", std::to_string(std::chrono::duration_cast<std::chrono::seconds>(release->getDuration()).count()));
}
else
{
albumNode.setAttribute("title", release->getName());
albumNode.setAttribute("isDir", "true");
}
albumNode.setAttribute("id", IdToString({Id::Type::Release, release.id()})); albumNode.setAttribute("id", IdToString({Id::Type::Release, release.id()}));
albumNode.setAttribute("isDir", "true");
albumNode.setAttribute("coverArt", IdToString({Id::Type::Release, release.id()})); albumNode.setAttribute("coverArt", IdToString({Id::Type::Release, release.id()}));
if (release->getReleaseYear())
albumNode.setAttribute("year", std::to_string(*release->getReleaseYear()));
auto artists {release->getArtists()}; auto artists {release->getArtists()};
if (!artists.empty()) if (!artists.empty())
@@ -344,12 +389,18 @@ releaseToResponseNode(const Database::Release::pointer& release)
if (artists.size() > 1) if (artists.size() > 1)
{ {
albumNode.setAttribute("artist", "Various Artists"); albumNode.setAttribute("artist", "Various Artists");
albumNode.setAttribute("parent", IdToString({Id::Type::Root}));
if (!id3)
albumNode.setAttribute("parent", IdToString({Id::Type::Root}));
} }
else else
{ {
albumNode.setAttribute("artist", artists.front()->getName()); albumNode.setAttribute("artist", artists.front()->getName());
albumNode.setAttribute("parent", IdToString({Id::Type::Artist, artists.front().id()}));
if (id3)
albumNode.setAttribute("artistId", IdToString({Id::Type::Artist, artists.front().id()}));
else
albumNode.setAttribute("parent", IdToString({Id::Type::Artist, artists.front().id()}));
} }
} }
@@ -358,14 +409,16 @@ releaseToResponseNode(const Database::Release::pointer& release)
static static
Response::Node Response::Node
artistToResponseNode(const Database::Artist::pointer& artist) artistToResponseNode(const Database::Artist::pointer& artist, bool id3)
{ {
Response::Node artistNode; Response::Node artistNode;
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())); artistNode.setAttribute("albumCount", std::to_string(artist->getReleases().size()));
artistNode.setAttribute("parent", IdToString({Id::Type::Root}));
if (!id3)
artistNode.setAttribute("parent", IdToString({Id::Type::Root}));
return artistNode; return artistNode;
} }
@@ -426,7 +479,7 @@ handleGetRandomSongsRequest(const Wt::Http::ParameterMap& parameters, Database::
Response::Node& randomSongsNode {response.createNode("randomSongs")}; Response::Node& randomSongsNode {response.createNode("randomSongs")};
for (const Database::Track::pointer& track : tracks) for (const Database::Track::pointer& track : tracks)
randomSongsNode.addArrayChild("song", trackToResponseNode(track)); randomSongsNode.addArrayChild("song", trackToResponseNode(track, true));
return response; return response;
} }
@@ -464,10 +517,9 @@ std::vector<Database::Release::pointer> getRandomAlbums(Wt::Dbo::Session& sessio
return res; return res;
} }
static
Response Response
handleGetAlbumListRequest(const Wt::Http::ParameterMap& request, Database::Handler& db) handleGetAlbumListRequestCommon(const Wt::Http::ParameterMap& request, Database::Handler& db, bool id3)
{ {
// Mandatory params // Mandatory params
auto type {getParameterAs<std::string>(request, "type")}; auto type {getParameterAs<std::string>(request, "type")};
@@ -506,39 +558,109 @@ handleGetAlbumListRequest(const Wt::Http::ParameterMap& request, Database::Handl
LMS_LOG(API_SUBSONIC, DEBUG) << "Got " << releases.size() << " albums"; LMS_LOG(API_SUBSONIC, DEBUG) << "Got " << releases.size() << " albums";
Response response {Response::createOkResponse()}; Response response {Response::createOkResponse()};
Response::Node& albumListNode {response.createNode("albumList")}; Response::Node& albumListNode {response.createNode(id3 ? "albumList2" : "albumList")};
for (const Database::Release::pointer& release : releases) for (const Database::Release::pointer& release : releases)
albumListNode.addArrayChild("album", releaseToResponseNode(release)); albumListNode.addArrayChild("album", releaseToResponseNode(release, id3));
return response; return response;
} }
Response
handleGetAlbumListRequest(const Wt::Http::ParameterMap& request, Database::Handler& db)
{
return handleGetAlbumListRequestCommon(request, db, false /* no id3 */);
}
Response Response
handleGetAlbumList2Request(const Wt::Http::ParameterMap& request, Database::Handler& db) handleGetAlbumList2Request(const Wt::Http::ParameterMap& request, Database::Handler& db)
{ {
return handleGetAlbumListRequestCommon(request, db, true /* id3 */);
}
Response
handleGetAlbumRequest(const Wt::Http::ParameterMap& request, Database::Handler& db)
{
// Mandatory params
Id id {getParameterAsId(request, "id")};
if (id.type != Id::Type::Release)
throw Error {"Unexpected id type"};
Wt::Dbo::Transaction transaction {db.getSession()};
Database::Release::pointer release {Database::Release::getById(db.getSession(), id.id)};
if (!release)
throw Error {Error::Code::RequestedDataNotFound};
Response response {Response::createOkResponse()}; Response response {Response::createOkResponse()};
response.createNode("albumList2"); Response::Node releaseNode {releaseToResponseNode(release, true /* id3 */)};
auto tracks {release->getTracks()};
for (const Database::Track::pointer& track : tracks)
releaseNode.addArrayChild("song", trackToResponseNode(track, true /* id3 */));
response.addNode("album", std::move(releaseNode));
return response; return response;
} }
Response
handleGetArtistRequest(const Wt::Http::ParameterMap& request, Database::Handler& db)
{
// Mandatory params
Id id {getParameterAsId(request, "id")};
if (id.type != Id::Type::Artist)
throw Error {"Unexpected id type"};
Wt::Dbo::Transaction transaction {db.getSession()};
Database::Artist::pointer artist {Database::Artist::getById(db.getSession(), id.id)};
if (!artist)
throw Error {Error::Code::RequestedDataNotFound};
Response response {Response::createOkResponse()};
Response::Node artistNode {artistToResponseNode(artist, true /* id3 */)};
auto releases {artist->getReleases()};
for (const Database::Release::pointer& release : releases)
artistNode.addArrayChild("album", releaseToResponseNode(release, true /* id3 */));
response.addNode("artist", std::move(artistNode));
return response;
}
Response
handleGetArtistsRequest(const Wt::Http::ParameterMap& request, Database::Handler& db)
{
Response response {Response::createOkResponse()};
Response::Node& artistsNode {response.createNode("artists")};
Response::Node& indexNode {artistsNode.createArrayChild("index")};
indexNode.setAttribute("name", "?");
Wt::Dbo::Transaction transaction {db.getSession()};
auto artists {Database::Artist::getAll(db.getSession())};
for (const Database::Artist::pointer& artist : artists)
indexNode.addArrayChild("artist", artistToResponseNode(artist, true /* id3 */));
return response;
}
Response Response
handleGetMusicDirectoryRequest(const Wt::Http::ParameterMap& request, Database::Handler& db) handleGetMusicDirectoryRequest(const Wt::Http::ParameterMap& request, Database::Handler& db)
{ {
// Mandatory params // Mandatory params
auto idParam {getParameterAs<std::string>(request, "id")}; Id id {getParameterAsId(request, "id")};
if (!idParam)
throw Error {Error::Code::RequiredParameterMissing};
auto id {IdFromString(*idParam)};
if (!id)
throw Error {"Bad id"};
Response response {Response::createOkResponse()}; Response response {Response::createOkResponse()};
Response::Node& directoryNode {response.createNode("directory")}; Response::Node& directoryNode {response.createNode("directory")};
switch (id->type) switch (id.type)
{ {
case Id::Type::Root: case Id::Type::Root:
{ {
@@ -548,7 +670,7 @@ handleGetMusicDirectoryRequest(const Wt::Http::ParameterMap& request, Database::
auto artists {Database::Artist::getAll(db.getSession())}; auto artists {Database::Artist::getAll(db.getSession())};
for (const Database::Artist::pointer& artist : artists) for (const Database::Artist::pointer& artist : artists)
directoryNode.addArrayChild("child", artistToResponseNode(artist)); directoryNode.addArrayChild("child", artistToResponseNode(artist, false /* no id3 */));
break; break;
} }
@@ -557,7 +679,7 @@ handleGetMusicDirectoryRequest(const Wt::Http::ParameterMap& request, Database::
{ {
Wt::Dbo::Transaction transaction {db.getSession()}; Wt::Dbo::Transaction transaction {db.getSession()};
auto artist {Database::Artist::getById(db.getSession(), id->id)}; auto artist {Database::Artist::getById(db.getSession(), id.id)};
if (!artist) if (!artist)
throw Error {Error::Code::RequestedDataNotFound}; throw Error {Error::Code::RequestedDataNotFound};
@@ -565,7 +687,7 @@ handleGetMusicDirectoryRequest(const Wt::Http::ParameterMap& request, Database::
auto releases {artist->getReleases()}; auto releases {artist->getReleases()};
for (const Database::Release::pointer& release : releases) for (const Database::Release::pointer& release : releases)
directoryNode.addArrayChild("child", releaseToResponseNode(release)); directoryNode.addArrayChild("child", releaseToResponseNode(release, false /* no id3 */));
break; break;
} }
@@ -574,7 +696,7 @@ handleGetMusicDirectoryRequest(const Wt::Http::ParameterMap& request, Database::
{ {
Wt::Dbo::Transaction transaction {db.getSession()}; Wt::Dbo::Transaction transaction {db.getSession()};
auto release {Database::Release::getById(db.getSession(), id->id)}; auto release {Database::Release::getById(db.getSession(), id.id)};
if (!release) if (!release)
throw Error {Error::Code::RequestedDataNotFound}; throw Error {Error::Code::RequestedDataNotFound};
@@ -582,13 +704,13 @@ handleGetMusicDirectoryRequest(const Wt::Http::ParameterMap& request, Database::
auto tracks {release->getTracks()}; auto tracks {release->getTracks()};
for (const Database::Track::pointer& track : tracks) for (const Database::Track::pointer& track : tracks)
directoryNode.addArrayChild("child", trackToResponseNode(track)); directoryNode.addArrayChild("child", trackToResponseNode(track, false));
break; break;
} }
default: default:
throw Error {"Bad id"}; throw Error {"Unexpected id type"};
} }
return response; return response;
@@ -641,30 +763,12 @@ handleGetIndexesRequest(const Wt::Http::ParameterMap& request, Database::Handler
auto artists {Database::Artist::getAll(db.getSession())}; auto artists {Database::Artist::getAll(db.getSession())};
for (const Database::Artist::pointer& artist : artists) for (const Database::Artist::pointer& artist : artists)
indexNode.addArrayChild("artist", artistToResponseNode(artist)); indexNode.addArrayChild("artist", artistToResponseNode(artist, false /* no id3 */));
return response; return response;
} }
Response
handleGetArtistsRequest(const Wt::Http::ParameterMap& request, Database::Handler& db)
{
Response response {Response::createOkResponse()};
Response::Node& artistsNode {response.createNode("artists")};
Response::Node& indexNode {artistsNode.createArrayChild("index")};
indexNode.setAttribute("name", "?");
Wt::Dbo::Transaction transaction {db.getSession()};
auto artists {Database::Artist::getAll(db.getSession())};
for (const Database::Artist::pointer& artist : artists)
indexNode.addArrayChild("artist", artistToResponseNode(artist));
return response;
}
Response Response
handleGetStarredRequest(const Wt::Http::ParameterMap& request, Database::Handler& db) handleGetStarredRequest(const Wt::Http::ParameterMap& request, Database::Handler& db)
{ {
@@ -729,7 +833,7 @@ handleGetSongsByGenreRequest(const Wt::Http::ParameterMap& request, Database::Ha
bool more; bool more;
auto tracks {Database::Track::getByFilter(db.getSession(), {cluster.id()}, {}, offset, size, more)}; auto tracks {Database::Track::getByFilter(db.getSession(), {cluster.id()}, {}, offset, size, more)};
for (const Database::Track::pointer& track : tracks) for (const Database::Track::pointer& track : tracks)
songsByGenreNode.addArrayChild("song", trackToResponseNode(track)); songsByGenreNode.addArrayChild("song", trackToResponseNode(track, true));
return response; return response;
} }
@@ -739,13 +843,7 @@ std::shared_ptr<Av::Transcoder>
createTranscoder(const Wt::Http::ParameterMap& request, Database::Handler& db) createTranscoder(const Wt::Http::ParameterMap& request, Database::Handler& db)
{ {
// Mandatory params // Mandatory params
auto idParam {getParameterAs<std::string>(request, "id")}; Id id {getParameterAsId(request, "id")};
if (!idParam)
throw Error {Error::Code::RequiredParameterMissing};
auto id {IdFromString(*idParam)};
if (!id || id->type != Id::Type::Track)
throw Error {"bad id format"};
// Optional params // Optional params
auto maxBitRate {getParameterAs<std::size_t>(request, "maxBitRate")}; auto maxBitRate {getParameterAs<std::size_t>(request, "maxBitRate")};
@@ -758,7 +856,7 @@ createTranscoder(const Wt::Http::ParameterMap& request, Database::Handler& db)
{ {
Wt::Dbo::Transaction transaction {db.getSession()}; Wt::Dbo::Transaction transaction {db.getSession()};
auto track {Database::Track::getById(db.getSession(), id->id)}; auto track {Database::Track::getById(db.getSession(), id.id)};
if (!track) if (!track)
{ {
LMS_LOG(API_SUBSONIC, ERROR) << "Bad track id"; LMS_LOG(API_SUBSONIC, ERROR) << "Bad track id";
@@ -834,13 +932,7 @@ handleGetCoverArt(const Wt::Http::Request& request, Database::Handler& db, Wt::H
LMS_LOG(API_SUBSONIC, DEBUG) << "STREAM"; LMS_LOG(API_SUBSONIC, DEBUG) << "STREAM";
// Mandatory params // Mandatory params
auto idParam {getParameterAs<std::string>(request.getParameterMap(), "id")}; Id id {getParameterAsId(request.getParameterMap(), "id")};
if (!idParam)
throw Error {Error::Code::RequiredParameterMissing};
auto id {IdFromString(*idParam)};
if (!id)
throw Error {"bad id format"};
auto size {getParameterAs<std::size_t>(request.getParameterMap(), "size")}; auto size {getParameterAs<std::size_t>(request.getParameterMap(), "size")};
if (!size) if (!size)
@@ -849,16 +941,16 @@ handleGetCoverArt(const Wt::Http::Request& request, Database::Handler& db, Wt::H
*size = clamp(*size, std::size_t {32}, std::size_t {1024}); *size = clamp(*size, std::size_t {32}, std::size_t {1024});
std::vector<uint8_t> cover; std::vector<uint8_t> cover;
switch (id->type) switch (id.type)
{ {
case Id::Type::Track: case Id::Type::Track:
cover = getServices().coverArtGrabber->getFromTrack(db.getSession(), id->id, Image::Format::JPEG, *size); cover = getServices().coverArtGrabber->getFromTrack(db.getSession(), id.id, Image::Format::JPEG, *size);
break; break;
case Id::Type::Release: case Id::Type::Release:
cover = getServices().coverArtGrabber->getFromRelease(db.getSession(), id->id, Image::Format::JPEG, *size); cover = getServices().coverArtGrabber->getFromRelease(db.getSession(), id.id, Image::Format::JPEG, *size);
break; break;
default: default:
throw Error {"Bad id format"}; throw Error {"Unexpected id type"};
} }
response.setMimeType( Image::format_to_mimeType(Image::Format::JPEG) ); response.setMimeType( Image::format_to_mimeType(Image::Format::JPEG) );
+6
View File
@@ -154,6 +154,12 @@ Response::createFailedResponse(const Error& error)
return response; return response;
} }
void
Response::addNode(const std::string& key, Node node)
{
return _root._children["subsonic-response"].front().addChild(key, std::move(node));
}
Response::Node& Response::Node&
Response::createNode(const std::string& key) Response::createNode(const std::string& key)
{ {
+1
View File
@@ -90,6 +90,7 @@ class Response
Response(Response&&) = default; Response(Response&&) = default;
Response& operator=(Response&&) = default; Response& operator=(Response&&) = default;
void addNode(const std::string& key, Node node);
Node& createNode(const std::string& key); Node& createNode(const std::string& key);
Node& createArrayNode(const std::string& key); Node& createArrayNode(const std::string& key);
+15
View File
@@ -315,6 +315,21 @@ Release::getTracks(const std::set<IdType>& clusterIds) const
return std::vector< Wt::Dbo::ptr<Track> > (res.begin(), res.end()); return std::vector< Wt::Dbo::ptr<Track> > (res.begin(), res.end());
} }
std::chrono::milliseconds
Release::getDuration() const
{
assert(self());
assert(self()->id() != Wt::Dbo::dbo_traits<Artist>::invalidId() );
assert(session());
using milli = std::chrono::duration<int, std::milli>;
Wt::Dbo::Query<milli> query {session()->query<milli>("SELECT SUM(duration) FROM track t INNER JOIN release r ON t.release_id = r.id WHERE r.id = ?")
.bind(self()->id())};
return query.resultValue();
}
std::vector<std::vector<Wt::Dbo::ptr<Cluster>>> std::vector<std::vector<Wt::Dbo::ptr<Cluster>>>
Release::getClusterGroups(std::vector<ClusterType::pointer> clusterTypes, std::size_t size) const Release::getClusterGroups(std::vector<ClusterType::pointer> clusterTypes, std::size_t size) const
{ {
+1 -1
View File
@@ -79,7 +79,7 @@ class Release : public Wt::Dbo::Dbo<Release>
// Accessors // Accessors
std::string getName() const { return _name; } std::string getName() const { return _name; }
std::string getMBID() const { return _MBID; } std::string getMBID() const { return _MBID; }
std::chrono::seconds getDuration(void) const; std::chrono::milliseconds getDuration() const;
// Get the artists of this release // Get the artists of this release
std::vector<Wt::Dbo::ptr<Artist> > getArtists() const; std::vector<Wt::Dbo::ptr<Artist> > getArtists() const;