diff --git a/rave/src/subsonic/mod.rs b/rave/src/subsonic/mod.rs index d1728e1..ee2eb12 100644 --- a/rave/src/subsonic/mod.rs +++ b/rave/src/subsonic/mod.rs @@ -1,5 +1,5 @@ use poem::{http::StatusCode, IntoResponse, Response}; -use serde::Serialize; +use serde::{Serialize, Serializer}; use crate::authentication::VersionTriple; @@ -16,10 +16,108 @@ pub use types::music_folder::MusicFolder; pub struct SubsonicResponse { pub status: ResponseStatus, pub version: VersionTriple, - #[serde(skip_serializing_if = "SubResponseType::is_empty")] + #[serde( + skip_serializing_if = "SubResponseType::is_empty", + serialize_with = "serialize_without_root", + flatten + )] pub value: Box, } +fn serialize_without_root(value: &SubResponseType, s: S) -> Result +where + S: Serializer, +{ + match value { + SubResponseType::MusicFolders { music_folders } => { + #[derive(Serialize)] + struct MF { + id: String, + name: String, + } + + impl From for MF { + fn from(value: MusicFolder) -> Self { + Self { + id: value.id, + name: value.name, + } + } + } + + #[derive(Serialize)] + struct MusicFolders { + #[serde(rename = "musicFolders")] + music_folders: Vec, + } + + MusicFolders { + music_folders: music_folders.iter().map(|v| v.clone().into()).collect(), + } + .serialize(s) + } + SubResponseType::Error(error) => error.serialize(s), + SubResponseType::License { valid } => valid.serialize(s), + SubResponseType::AlbumList { albums } | SubResponseType::AlbumList2 { albums } => { + albums.serialize(s) + } + SubResponseType::Album { album, songs } => { + #[derive(Serialize)] + #[serde(rename = "album")] + struct AlbumWithSongs<'a> { + #[serde(flatten)] + album: &'a Album, + #[serde(rename = "song")] + songs: &'a Vec, + } + + AlbumWithSongs { album, songs }.serialize(s) + } + SubResponseType::ScanStatus { scanning, count } => { + #[derive(Serialize)] + #[serde(rename = "scanStatus")] + struct ScanStatus { + #[serde(rename = "scanning")] + scanning: bool, + #[serde(rename = "count")] + count: u64, + } + + ScanStatus { + scanning: *scanning, + count: *count, + } + .serialize(s) + } + SubResponseType::SearchResult3 { + artists, + albums, + songs, + } => { + #[derive(Serialize)] + #[serde(rename = "searchResult3")] + struct SearchResult3<'a> { + #[serde(rename = "artist")] + artists: &'a Vec, + #[serde(rename = "album")] + albums: &'a Vec, + #[serde(rename = "song")] + songs: &'a Vec, + } + + SearchResult3 { + artists, + albums, + songs, + } + .serialize(s) + } + SubResponseType::Artists { artists } => artists.serialize(s), + SubResponseType::Artist { artist } => artist.serialize(s), + SubResponseType::Empty => s.serialize_none(), + } +} + impl From for SubsonicResponseJson { fn from(value: SubsonicResponse) -> Self { Self { @@ -142,7 +240,6 @@ impl SubsonicResponse { } #[derive(Debug, Clone, Serialize)] -#[serde(untagged)] pub enum SubResponseType { #[serde(rename = "musicFolders")] MusicFolders {