diff --git a/SUBSONIC.md b/SUBSONIC.md
index 36e2ba6f..7bb4b93c 100644
--- a/SUBSONIC.md
+++ b/SUBSONIC.md
@@ -18,9 +18,9 @@ The following extra fields are implemented:
* `moods`
* `originalReleaseDate`
* `isCompilation`
- * `discTitles`
+ * `discTitles`: discs with no subtitle are omitted
* `Child` response:
- * `musicBrainzId`: note this is actually the recording MBID
+ * `musicBrainzId`: note this is actually the recording MBID when this response refers to a song
* `genres`
* `artists`
* `albumArtists`
diff --git a/src/libs/subsonic/CMakeLists.txt b/src/libs/subsonic/CMakeLists.txt
index d4aa3f0e..8964a561 100644
--- a/src/libs/subsonic/CMakeLists.txt
+++ b/src/libs/subsonic/CMakeLists.txt
@@ -15,6 +15,7 @@ add_library(lmssubsonic SHARED
impl/responses/Bookmark.cpp
impl/responses/Contributor.cpp
impl/responses/DiscTitle.cpp
+ impl/responses/ItemGenre.cpp
impl/responses/Genre.cpp
impl/responses/Playlist.cpp
impl/responses/ReplayGain.cpp
diff --git a/src/libs/subsonic/impl/entrypoints/AlbumSongLists.cpp b/src/libs/subsonic/impl/entrypoints/AlbumSongLists.cpp
index 362bf311..e0b096db 100644
--- a/src/libs/subsonic/impl/entrypoints/AlbumSongLists.cpp
+++ b/src/libs/subsonic/impl/entrypoints/AlbumSongLists.cpp
@@ -176,7 +176,6 @@ namespace API::Subsonic
}
return response;
-
}
} // namespace
diff --git a/src/libs/subsonic/impl/entrypoints/System.cpp b/src/libs/subsonic/impl/entrypoints/System.cpp
index 6af37fd7..11d7b350 100644
--- a/src/libs/subsonic/impl/entrypoints/System.cpp
+++ b/src/libs/subsonic/impl/entrypoints/System.cpp
@@ -24,7 +24,7 @@ namespace API::Subsonic
Response response{ Response::createOkResponse(context.serverProtocolVersion) };
{
- Response::Node& transcodeOffsetNode{ response.createNode("openSubsonicExtensions") };
+ Response::Node& transcodeOffsetNode{ response.createArrayNode("openSubsonicExtensions") };
transcodeOffsetNode.setAttribute("name", "transcodeOffset");
transcodeOffsetNode.addArrayValue("versions", 1);
}
diff --git a/src/libs/subsonic/impl/responses/Album.cpp b/src/libs/subsonic/impl/responses/Album.cpp
index 6033a966..8694f06b 100644
--- a/src/libs/subsonic/impl/responses/Album.cpp
+++ b/src/libs/subsonic/impl/responses/Album.cpp
@@ -29,6 +29,7 @@
#include "responses/Artist.hpp"
#include "responses/DiscTitle.hpp"
+#include "responses/ItemGenre.hpp"
#include "SubsonicId.hpp"
namespace API::Subsonic
@@ -160,9 +161,28 @@ namespace API::Subsonic
}
} };
- addClusters("genres", "GENRE");
addClusters("moods", "MOOD");
+ // Genres
+ {
+ albumNode.createEmptyArrayChild("genres");
+
+ ClusterType::pointer clusterType{ ClusterType::find(dbSession, "GENRE") };
+ if (clusterType)
+ {
+ Cluster::FindParameters params;
+ params.setRelease(release->getId());
+ params.setClusterType(clusterType->getId());
+
+ for (const ClusterId clusterId : Cluster::find(dbSession, params).results)
+ {
+ Cluster::pointer cluster{ Cluster::find(dbSession, clusterId) };
+ if (cluster)
+ albumNode.addArrayChild("genres", createItemGenreNode(cluster));
+ }
+ }
+ }
+
albumNode.createEmptyArrayChild("artists");
for (const Artist::pointer& artist : release->getReleaseArtists())
albumNode.addArrayChild("artists", createArtistNode(artist));
diff --git a/src/libs/subsonic/impl/responses/Genre.hpp b/src/libs/subsonic/impl/responses/Genre.hpp
index 33577f71..6d217304 100644
--- a/src/libs/subsonic/impl/responses/Genre.hpp
+++ b/src/libs/subsonic/impl/responses/Genre.hpp
@@ -19,8 +19,6 @@
#pragma once
-#include "services/database/Cluster.hpp"
-
#include "services/database/Object.hpp"
#include "SubsonicResponse.hpp"
diff --git a/src/libs/subsonic/impl/responses/ItemGenre.cpp b/src/libs/subsonic/impl/responses/ItemGenre.cpp
new file mode 100644
index 00000000..a5b3387d
--- /dev/null
+++ b/src/libs/subsonic/impl/responses/ItemGenre.cpp
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2023 Emeric Poupon
+ *
+ * This file is part of LMS.
+ *
+ * LMS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * LMS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with LMS. If not, see .
+ */
+
+#include "responses/ItemGenre.hpp"
+
+#include "services/database/Cluster.hpp"
+
+namespace API::Subsonic
+{
+ Response::Node createItemGenreNode(const Database::Cluster::pointer& cluster)
+ {
+ Response::Node genreNode;
+
+ genreNode.setAttribute("name", cluster->getName());
+
+ return genreNode;
+ }
+}
\ No newline at end of file
diff --git a/src/libs/subsonic/impl/responses/ItemGenre.hpp b/src/libs/subsonic/impl/responses/ItemGenre.hpp
new file mode 100644
index 00000000..f4c1dda9
--- /dev/null
+++ b/src/libs/subsonic/impl/responses/ItemGenre.hpp
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2023 Emeric Poupon
+ *
+ * This file is part of LMS.
+ *
+ * LMS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * LMS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with LMS. If not, see .
+ */
+
+#pragma once
+
+#include "services/database/Object.hpp"
+#include "SubsonicResponse.hpp"
+
+namespace Database
+{
+ class Cluster;
+}
+
+namespace API::Subsonic
+{
+ Response::Node createItemGenreNode(const Database::ObjectPtr& cluster);
+}
diff --git a/src/libs/subsonic/impl/responses/Song.cpp b/src/libs/subsonic/impl/responses/Song.cpp
index 2eb7ed74..ac4d3246 100644
--- a/src/libs/subsonic/impl/responses/Song.cpp
+++ b/src/libs/subsonic/impl/responses/Song.cpp
@@ -32,6 +32,7 @@
#include "utils/String.hpp"
#include "responses/Artist.hpp"
#include "responses/Contributor.hpp"
+#include "responses/ItemGenre.hpp"
#include "responses/ReplayGain.hpp"
#include "SubsonicId.hpp"
#include "Utils.hpp"
@@ -212,14 +213,33 @@ namespace API::Subsonic
{
Cluster::pointer cluster {Cluster::find(dbSession, clusterId)};
if (cluster)
- trackResponse.addArrayValue(field, cluster->getName());
+ trackResponse.addArrayValue(field, cluster->getName());
}
}
} };
- addClusters("genres", "GENRE");
addClusters("moods", "MOOD");
+ // Genres
+ {
+ trackResponse.createEmptyArrayChild("genres");
+
+ ClusterType::pointer clusterType{ ClusterType::find(dbSession, "GENRE") };
+ if (clusterType)
+ {
+ Cluster::FindParameters params;
+ params.setTrack(track->getId());
+ params.setClusterType(clusterType->getId());
+
+ for (const ClusterId clusterId : Cluster::find(dbSession, params).results)
+ {
+ Cluster::pointer cluster{ Cluster::find(dbSession, clusterId) };
+ if (cluster)
+ trackResponse.addArrayChild("genres", createItemGenreNode(cluster));
+ }
+ }
+ }
+
trackResponse.addChild("replayGain", createReplayGainNode(track));
return trackResponse;