feat: new "Subsonic Minimal Clients" configuration option (#4850)

* Add `.editorconfig` file

Hints to users how to properly indent Go files (my setup was defaulting
to 2 spaces).

* Add Subsonic API minimal config option

This will allow users to specify clients which can operate with or need
the minimum required fields as per the [SubSonic API
spec](https://subsonic.org/pages/api.jsp).

* Return only required fields for Child Objects

For a minimal client, only return the required fields for Child Objects.

* Return only required fields for Playlist objects

* refactor: simplify client list checks and improve playlist response handling

Signed-off-by: Deluan <deluan@navidrome.org>

* test: add unit tests for client list checks and playlist building logic

Signed-off-by: Deluan <deluan@navidrome.org>

* fix: revert Child.IsVideo and Playlist.Public fields from pointer to boolean, and add omitempty to XML tag

Signed-off-by: Deluan <deluan@navidrome.org>

---------

Signed-off-by: Deluan <deluan@navidrome.org>
Co-authored-by: Deluan Quintão <deluan@navidrome.org>
This commit is contained in:
Matthew Simpson
2026-01-16 10:55:21 +00:00
committed by GitHub
parent 032cfa2a4d
commit 9ab0c2dc67
36 changed files with 360 additions and 60 deletions
@@ -9,7 +9,6 @@
{
"id": "1",
"isDir": false,
"isVideo": false,
"bpm": 0,
"comment": "",
"sortName": "sort name",
@@ -1,6 +1,6 @@
<subsonic-response xmlns="http://subsonic.org/restapi" status="ok" version="1.16.1" type="navidrome" serverVersion="v0.55.0" openSubsonic="true">
<albumList>
<album id="1" isDir="false" isVideo="false" sortName="sort name" mediaType="album" musicBrainzId="00000000-0000-0000-0000-000000000000" displayArtist="Display artist" displayAlbumArtist="Display album artist" explicitStatus="explicit">
<album id="1" isDir="false" sortName="sort name" mediaType="album" musicBrainzId="00000000-0000-0000-0000-000000000000" displayArtist="Display artist" displayAlbumArtist="Display album artist" explicitStatus="explicit">
<genres name="Genre 1"></genres>
<genres name="Genre 2"></genres>
<moods>mood1</moods>
@@ -9,8 +9,7 @@
{
"id": "1",
"isDir": false,
"title": "title",
"isVideo": false
"title": "title"
}
]
}
@@ -1,5 +1,5 @@
<subsonic-response xmlns="http://subsonic.org/restapi" status="ok" version="1.16.1" type="navidrome" serverVersion="v0.55.0" openSubsonic="true">
<albumList>
<album id="1" isDir="false" title="title" isVideo="false"></album>
<album id="1" isDir="false" title="title"></album>
</albumList>
</subsonic-response>
@@ -93,7 +93,6 @@
"transcodedSuffix": "mp3",
"duration": 146,
"bitRate": 320,
"isVideo": false,
"bpm": 127,
"comment": "a comment",
"sortName": "sorted song",
@@ -185,7 +184,6 @@
"transcodedSuffix": "mp3",
"duration": 146,
"bitRate": 320,
"isVideo": false,
"bpm": 0,
"comment": "",
"sortName": "",
@@ -15,7 +15,7 @@
<moods>sad</moods>
<artists id="1" name="artist1"></artists>
<artists id="2" name="artist2"></artists>
<song id="1" isDir="true" title="title" album="album" artist="artist" track="1" year="1985" genre="Rock" coverArt="1" size="8421341" contentType="audio/flac" suffix="flac" starred="2016-03-02T20:30:00Z" transcodedContentType="audio/mpeg" transcodedSuffix="mp3" duration="146" bitRate="320" isVideo="false" bpm="127" comment="a comment" sortName="sorted song" mediaType="song" musicBrainzId="4321" channelCount="2" samplingRate="44100" bitDepth="16" displayArtist="artist1 &amp; artist2" displayAlbumArtist="album artist1 &amp; album artist2" displayComposer="composer 1 &amp; composer 2" explicitStatus="clean">
<song id="1" isDir="true" title="title" album="album" artist="artist" track="1" year="1985" genre="Rock" coverArt="1" size="8421341" contentType="audio/flac" suffix="flac" starred="2016-03-02T20:30:00Z" transcodedContentType="audio/mpeg" transcodedSuffix="mp3" duration="146" bitRate="320" bpm="127" comment="a comment" sortName="sorted song" mediaType="song" musicBrainzId="4321" channelCount="2" samplingRate="44100" bitDepth="16" displayArtist="artist1 &amp; artist2" displayAlbumArtist="album artist1 &amp; album artist2" displayComposer="composer 1 &amp; composer 2" explicitStatus="clean">
<isrc>ISRC-1</isrc>
<genres name="rock"></genres>
<genres name="progressive"></genres>
@@ -33,7 +33,7 @@
<artist id="2" name="artist2"></artist>
</contributors>
</song>
<song id="2" isDir="true" title="title" album="album" artist="artist" track="1" year="1985" genre="Rock" coverArt="1" size="8421341" contentType="audio/flac" suffix="flac" starred="2016-03-02T20:30:00Z" transcodedContentType="audio/mpeg" transcodedSuffix="mp3" duration="146" bitRate="320" isVideo="false">
<song id="2" isDir="true" title="title" album="album" artist="artist" track="1" year="1985" genre="Rock" coverArt="1" size="8421341" contentType="audio/flac" suffix="flac" starred="2016-03-02T20:30:00Z" transcodedContentType="audio/mpeg" transcodedSuffix="mp3" duration="146" bitRate="320">
<replayGain trackGain="0" albumGain="0" trackPeak="0" albumPeak="0" baseGain="0" fallbackGain="0"></replayGain>
</song>
</album>
@@ -10,8 +10,7 @@
"entry": {
"id": "1",
"isDir": false,
"title": "title",
"isVideo": false
"title": "title"
},
"position": 123,
"username": "user2",
@@ -1,7 +1,7 @@
<subsonic-response xmlns="http://subsonic.org/restapi" status="ok" version="1.16.1" type="navidrome" serverVersion="v0.55.0" openSubsonic="true">
<bookmarks>
<bookmark position="123" username="user2" comment="a comment" created="0001-01-01T00:00:00Z" changed="0001-01-01T00:00:00Z">
<entry id="1" isDir="false" title="title" isVideo="false"></entry>
<entry id="1" isDir="false" title="title"></entry>
</bookmark>
</bookmarks>
</subsonic-response>
@@ -24,7 +24,6 @@
"transcodedSuffix": "mp3",
"duration": 146,
"bitRate": 320,
"isVideo": false,
"bpm": 127,
"comment": "a comment",
"sortName": "sorted title",
@@ -116,7 +115,6 @@
{
"id": "",
"isDir": false,
"isVideo": false,
"bpm": 0,
"comment": "",
"sortName": "",
@@ -1,6 +1,6 @@
<subsonic-response xmlns="http://subsonic.org/restapi" status="ok" version="1.16.1" type="navidrome" serverVersion="v0.55.0" openSubsonic="true">
<directory id="1" name="N">
<child id="1" isDir="true" title="title" album="album" artist="artist" track="1" year="1985" genre="Rock" coverArt="1" size="8421341" contentType="audio/flac" suffix="flac" starred="2016-03-02T20:30:00Z" transcodedContentType="audio/mpeg" transcodedSuffix="mp3" duration="146" bitRate="320" isVideo="false" bpm="127" comment="a comment" sortName="sorted title" mediaType="song" musicBrainzId="4321" channelCount="2" samplingRate="44100" bitDepth="16" displayArtist="artist 1 &amp; artist 2" displayAlbumArtist="album artist 1 &amp; album artist 2" displayComposer="composer 1 &amp; composer 2" explicitStatus="clean">
<child id="1" isDir="true" title="title" album="album" artist="artist" track="1" year="1985" genre="Rock" coverArt="1" size="8421341" contentType="audio/flac" suffix="flac" starred="2016-03-02T20:30:00Z" transcodedContentType="audio/mpeg" transcodedSuffix="mp3" duration="146" bitRate="320" bpm="127" comment="a comment" sortName="sorted title" mediaType="song" musicBrainzId="4321" channelCount="2" samplingRate="44100" bitDepth="16" displayArtist="artist 1 &amp; artist 2" displayAlbumArtist="album artist 1 &amp; album artist 2" displayComposer="composer 1 &amp; composer 2" explicitStatus="clean">
<isrc>ISRC-1</isrc>
<isrc>ISRC-2</isrc>
<genres name="rock"></genres>
@@ -25,7 +25,7 @@
<artist id="4" name="composer2"></artist>
</contributors>
</child>
<child id="" isDir="false" isVideo="false">
<child id="" isDir="false">
<replayGain trackGain="0" albumGain="0" trackPeak="0" albumPeak="0" baseGain="0" fallbackGain="0"></replayGain>
</child>
</directory>
@@ -8,8 +8,7 @@
"child": [
{
"id": "1",
"isDir": false,
"isVideo": false
"isDir": false
}
],
"id": "",
@@ -1,5 +1,5 @@
<subsonic-response xmlns="http://subsonic.org/restapi" status="ok" version="1.16.1" type="navidrome" serverVersion="v0.55.0" openSubsonic="true">
<directory id="" name="">
<child id="1" isDir="false" isVideo="false"></child>
<child id="1" isDir="false"></child>
</directory>
</subsonic-response>
@@ -9,7 +9,6 @@
{
"id": "1",
"isDir": false,
"isVideo": false,
"bpm": 0,
"comment": "",
"sortName": "",
@@ -1,5 +1,5 @@
<subsonic-response xmlns="http://subsonic.org/restapi" status="ok" version="1.16.1" type="navidrome" serverVersion="v0.55.0" openSubsonic="true">
<directory id="" name="">
<child id="1" isDir="false" isVideo="false"></child>
<child id="1" isDir="false"></child>
</directory>
</subsonic-response>
@@ -9,8 +9,7 @@
{
"id": "1",
"isDir": false,
"title": "title",
"isVideo": false
"title": "title"
}
],
"id": "1",
@@ -1,5 +1,5 @@
<subsonic-response xmlns="http://subsonic.org/restapi" status="ok" version="1.16.1" type="navidrome" serverVersion="v0.55.0" openSubsonic="true">
<directory id="1" name="N">
<child id="1" isDir="false" title="title" isVideo="false"></child>
<child id="1" isDir="false" title="title"></child>
</directory>
</subsonic-response>
@@ -9,8 +9,7 @@
{
"id": "1",
"isDir": false,
"title": "title",
"isVideo": false
"title": "title"
}
],
"current": "111",
@@ -1,5 +1,5 @@
<subsonic-response xmlns="http://subsonic.org/restapi" status="ok" version="1.16.1" type="navidrome" serverVersion="v0.55.0" openSubsonic="true">
<playQueue current="111" position="243" username="user1" changed="0001-01-01T00:00:00Z" changedBy="a_client">
<entry id="1" isDir="false" title="title" isVideo="false"></entry>
<entry id="1" isDir="false" title="title"></entry>
</playQueue>
</subsonic-response>
@@ -9,8 +9,7 @@
{
"id": "1",
"isDir": false,
"title": "title",
"isVideo": false
"title": "title"
}
],
"currentIndex": 0,
@@ -1,5 +1,5 @@
<subsonic-response xmlns="http://subsonic.org/restapi" status="ok" version="1.16.1" type="navidrome" serverVersion="v0.55.0" openSubsonic="true">
<playQueueByIndex currentIndex="0" position="243" username="user1" changed="0001-01-01T00:00:00Z" changedBy="a_client">
<entry id="1" isDir="false" title="title" isVideo="false"></entry>
<entry id="1" isDir="false" title="title"></entry>
</playQueueByIndex>
</subsonic-response>
@@ -23,7 +23,6 @@
"name": "bbb",
"songCount": 0,
"duration": 0,
"public": false,
"created": "0001-01-01T00:00:00Z",
"changed": "0001-01-01T00:00:00Z"
}
@@ -1,6 +1,6 @@
<subsonic-response xmlns="http://subsonic.org/restapi" status="ok" version="1.16.1" type="navidrome" serverVersion="v0.55.0" openSubsonic="true">
<playlists>
<playlist id="111" name="aaa" comment="comment" songCount="2" duration="120" public="true" owner="admin" created="0001-01-01T00:00:00Z" changed="0001-01-01T00:00:00Z" coverArt="pl-123123123123"></playlist>
<playlist id="222" name="bbb" songCount="0" duration="0" public="false" created="0001-01-01T00:00:00Z" changed="0001-01-01T00:00:00Z"></playlist>
<playlist id="222" name="bbb" songCount="0" duration="0" created="0001-01-01T00:00:00Z" changed="0001-01-01T00:00:00Z"></playlist>
</playlists>
</subsonic-response>
@@ -14,8 +14,7 @@
"title": "title",
"album": "album",
"artist": "artist",
"duration": 120,
"isVideo": false
"duration": 120
},
{
"id": "2",
@@ -23,8 +22,7 @@
"title": "title 2",
"album": "album",
"artist": "artist",
"duration": 300,
"isVideo": false
"duration": 300
}
],
"id": "ABC123",
@@ -1,8 +1,8 @@
<subsonic-response xmlns="http://subsonic.org/restapi" status="ok" version="1.16.1" type="navidrome" serverVersion="v0.55.0" openSubsonic="true">
<shares>
<share id="ABC123" url="http://localhost/p/ABC123" description="Check it out!" username="deluan" created="2016-03-02T20:30:00Z" expires="2016-03-02T20:30:00Z" lastVisited="2016-03-02T20:30:00Z" visitCount="2">
<entry id="1" isDir="false" title="title" album="album" artist="artist" duration="120" isVideo="false"></entry>
<entry id="2" isDir="false" title="title 2" album="album" artist="artist" duration="300" isVideo="false"></entry>
<entry id="1" isDir="false" title="title" album="album" artist="artist" duration="120"></entry>
<entry id="2" isDir="false" title="title 2" album="album" artist="artist" duration="300"></entry>
</share>
</shares>
</subsonic-response>
@@ -9,8 +9,7 @@
{
"id": "1",
"isDir": false,
"title": "title",
"isVideo": false
"title": "title"
}
]
}
@@ -1,5 +1,5 @@
<subsonic-response xmlns="http://subsonic.org/restapi" status="ok" version="1.16.1" type="navidrome" serverVersion="v0.55.0" openSubsonic="true">
<similarSongs>
<song id="1" isDir="false" title="title" isVideo="false"></song>
<song id="1" isDir="false" title="title"></song>
</similarSongs>
</subsonic-response>
@@ -9,8 +9,7 @@
{
"id": "1",
"isDir": false,
"title": "title",
"isVideo": false
"title": "title"
}
]
}
@@ -1,5 +1,5 @@
<subsonic-response xmlns="http://subsonic.org/restapi" status="ok" version="1.16.1" type="navidrome" serverVersion="v0.55.0" openSubsonic="true">
<similarSongs2>
<song id="1" isDir="false" title="title" isVideo="false"></song>
<song id="1" isDir="false" title="title"></song>
</similarSongs2>
</subsonic-response>
@@ -9,8 +9,7 @@
{
"id": "1",
"isDir": false,
"title": "title",
"isVideo": false
"title": "title"
}
]
}
@@ -1,5 +1,5 @@
<subsonic-response xmlns="http://subsonic.org/restapi" status="ok" version="1.16.1" type="navidrome" serverVersion="v0.55.0" openSubsonic="true">
<topSongs>
<song id="1" isDir="false" title="title" isVideo="false"></song>
<song id="1" isDir="false" title="title"></song>
</topSongs>
</subsonic-response>