fix: fix json serialization
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
This commit is contained in:
parent
513997cd79
commit
79e2f730cc
5 changed files with 140 additions and 143 deletions
|
|
@ -1,4 +1,5 @@
|
|||
use poem::{http::StatusCode, IntoResponse, Response};
|
||||
use serde::ser::SerializeStruct;
|
||||
use serde::{Serialize, Serializer};
|
||||
|
||||
use crate::authentication::VersionTriple;
|
||||
|
|
@ -12,79 +13,64 @@ pub use types::artist::Artist;
|
|||
pub use types::child::Child;
|
||||
pub use types::music_folder::MusicFolder;
|
||||
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct SubsonicResponse {
|
||||
pub status: ResponseStatus,
|
||||
pub version: VersionTriple,
|
||||
#[serde(
|
||||
skip_serializing_if = "SubResponseType::is_empty",
|
||||
serialize_with = "serialize_without_root",
|
||||
flatten
|
||||
)]
|
||||
pub value: Box<SubResponseType>,
|
||||
}
|
||||
|
||||
fn serialize_without_root<S>(value: &SubResponseType, s: S) -> Result<S::Ok, S::Error>
|
||||
impl Serialize for SubsonicResponse {
|
||||
fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
match value {
|
||||
if self.value.is_empty() {
|
||||
let mut empty = s.serialize_struct("subsonic-response", 2)?;
|
||||
empty.serialize_field("status", &self.status)?;
|
||||
empty.serialize_field("version", &self.version)?;
|
||||
return empty.end();
|
||||
}
|
||||
|
||||
let mut s = s.serialize_struct("subsonic-response", 3)?;
|
||||
s.serialize_field("status", &self.status)?;
|
||||
s.serialize_field("version", &self.version)?;
|
||||
match self.value.as_ref() {
|
||||
SubResponseType::MusicFolders { music_folders } => {
|
||||
s.serialize_field("musicFolders", music_folders)?;
|
||||
}
|
||||
SubResponseType::Error(error) => {
|
||||
s.serialize_field("error", error)?;
|
||||
}
|
||||
SubResponseType::License { valid } => {
|
||||
#[derive(Serialize)]
|
||||
struct MF {
|
||||
id: String,
|
||||
name: String,
|
||||
struct License {
|
||||
#[serde(rename = "valid")]
|
||||
valid: bool,
|
||||
}
|
||||
|
||||
impl From<MusicFolder> for MF {
|
||||
fn from(value: MusicFolder) -> Self {
|
||||
Self {
|
||||
id: value.id,
|
||||
name: value.name,
|
||||
s.serialize_field("license", &License { valid: *valid })?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct MusicFolders {
|
||||
#[serde(rename = "musicFolders")]
|
||||
music_folders: Vec<MF>,
|
||||
}
|
||||
|
||||
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 } => {
|
||||
#[derive(Serialize)]
|
||||
struct AlbumList {
|
||||
struct AlbumList<'a> {
|
||||
#[serde(rename = "album")]
|
||||
albums: Vec<Album>,
|
||||
albums: &'a Vec<Album>,
|
||||
}
|
||||
|
||||
AlbumList {
|
||||
albums: albums.clone(),
|
||||
}
|
||||
.serialize(s)
|
||||
s.serialize_field("albumList", &AlbumList { albums })?;
|
||||
}
|
||||
SubResponseType::AlbumList2 { albums } => {
|
||||
#[derive(Serialize)]
|
||||
struct AlbumList2 {
|
||||
struct AlbumList2<'a> {
|
||||
#[serde(rename = "album")]
|
||||
albums: Vec<Album>,
|
||||
albums: &'a Vec<Album>,
|
||||
}
|
||||
|
||||
AlbumList2 {
|
||||
albums: albums.clone(),
|
||||
}
|
||||
.serialize(s)
|
||||
s.serialize_field("albumList2", &AlbumList2 { albums })?;
|
||||
}
|
||||
SubResponseType::Album { album, songs } => {
|
||||
#[derive(Serialize)]
|
||||
#[serde(rename = "album")]
|
||||
struct AlbumWithSongs<'a> {
|
||||
#[serde(flatten)]
|
||||
album: &'a Album,
|
||||
|
|
@ -92,23 +78,22 @@ where
|
|||
songs: &'a Vec<Child>,
|
||||
}
|
||||
|
||||
AlbumWithSongs { album, songs }.serialize(s)
|
||||
s.serialize_field("album", &AlbumWithSongs { album, songs })?;
|
||||
}
|
||||
SubResponseType::ScanStatus { scanning, count } => {
|
||||
#[derive(Serialize)]
|
||||
#[serde(rename = "scanStatus")]
|
||||
struct ScanStatus {
|
||||
#[serde(rename = "scanning")]
|
||||
scanning: bool,
|
||||
#[serde(rename = "count")]
|
||||
count: u64,
|
||||
}
|
||||
|
||||
ScanStatus {
|
||||
s.serialize_field(
|
||||
"scanStatus",
|
||||
&ScanStatus {
|
||||
scanning: *scanning,
|
||||
count: *count,
|
||||
}
|
||||
.serialize(s)
|
||||
},
|
||||
)?;
|
||||
}
|
||||
SubResponseType::SearchResult3 {
|
||||
artists,
|
||||
|
|
@ -116,7 +101,6 @@ where
|
|||
songs,
|
||||
} => {
|
||||
#[derive(Serialize)]
|
||||
#[serde(rename = "searchResult3")]
|
||||
struct SearchResult3<'a> {
|
||||
#[serde(rename = "artist")]
|
||||
artists: &'a Vec<Artist>,
|
||||
|
|
@ -126,16 +110,29 @@ where
|
|||
songs: &'a Vec<Child>,
|
||||
}
|
||||
|
||||
SearchResult3 {
|
||||
s.serialize_field(
|
||||
"searchResult3",
|
||||
&SearchResult3 {
|
||||
artists,
|
||||
albums,
|
||||
songs,
|
||||
},
|
||||
)?;
|
||||
}
|
||||
.serialize(s)
|
||||
SubResponseType::Artists { artists } => {
|
||||
#[derive(Serialize)]
|
||||
struct Artists<'a> {
|
||||
#[serde(rename = "artist")]
|
||||
artists: &'a Vec<Artist>,
|
||||
}
|
||||
SubResponseType::Artists { artists } => artists.serialize(s),
|
||||
SubResponseType::Artist { artist } => artist.serialize(s),
|
||||
SubResponseType::Empty => s.serialize_none(),
|
||||
|
||||
s.serialize_field("artists", &Artists { artists })?;
|
||||
}
|
||||
SubResponseType::Artist { artist } => s.serialize_field("artist", artist)?,
|
||||
SubResponseType::Empty => unreachable!("Empty response should be handled above"),
|
||||
}
|
||||
|
||||
s.end()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,29 +4,29 @@ use time::format_description::well_known::Iso8601;
|
|||
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
pub struct Album {
|
||||
#[serde(rename = "@id")]
|
||||
#[serde(rename = "id")]
|
||||
pub id: String,
|
||||
#[serde(rename = "@name")]
|
||||
#[serde(rename = "name")]
|
||||
pub name: String,
|
||||
#[serde(rename = "@artist", skip_serializing_if = "Option::is_none")]
|
||||
#[serde(rename = "artist", skip_serializing_if = "Option::is_none")]
|
||||
pub artist: Option<String>,
|
||||
#[serde(rename = "@artistId", skip_serializing_if = "Option::is_none")]
|
||||
#[serde(rename = "artistId", skip_serializing_if = "Option::is_none")]
|
||||
pub artist_id: Option<String>,
|
||||
#[serde(rename = "@coverArt", skip_serializing_if = "Option::is_none")]
|
||||
#[serde(rename = "coverArt", skip_serializing_if = "Option::is_none")]
|
||||
pub cover_art_id: Option<String>,
|
||||
#[serde(rename = "@songCount")]
|
||||
#[serde(rename = "songCount")]
|
||||
pub song_count: u64,
|
||||
#[serde(rename = "@duration")]
|
||||
#[serde(rename = "duration")]
|
||||
pub duration: u64,
|
||||
#[serde(rename = "@playCount")]
|
||||
#[serde(rename = "playCount")]
|
||||
pub play_count: u64,
|
||||
#[serde(rename = "@created")]
|
||||
#[serde(rename = "created")]
|
||||
pub created: String,
|
||||
#[serde(rename = "@starred", skip_serializing_if = "Option::is_none")]
|
||||
#[serde(rename = "starred", skip_serializing_if = "Option::is_none")]
|
||||
pub starred: Option<String>,
|
||||
#[serde(rename = "@year", skip_serializing_if = "Option::is_none")]
|
||||
#[serde(rename = "year", skip_serializing_if = "Option::is_none")]
|
||||
pub year: Option<u32>,
|
||||
#[serde(rename = "@genre", skip_serializing_if = "Option::is_none")]
|
||||
#[serde(rename = "genre", skip_serializing_if = "Option::is_none")]
|
||||
pub genre: Option<String>,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,17 +4,17 @@ use time::format_description::well_known::Iso8601;
|
|||
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
pub struct Artist {
|
||||
#[serde(rename = "@id")]
|
||||
#[serde(rename = "id")]
|
||||
pub id: String,
|
||||
#[serde(rename = "@name")]
|
||||
#[serde(rename = "name")]
|
||||
pub name: String,
|
||||
#[serde(rename = "@coverArtId")]
|
||||
#[serde(rename = "coverArtId")]
|
||||
pub cover_art: Option<String>,
|
||||
#[serde(rename = "@artistImageUrl")]
|
||||
#[serde(rename = "artistImageUrl")]
|
||||
pub artist_image_url: Option<String>,
|
||||
#[serde(rename = "@albumCount")]
|
||||
#[serde(rename = "albumCount")]
|
||||
pub album_count: u64,
|
||||
#[serde(rename = "@starred")]
|
||||
#[serde(rename = "starred")]
|
||||
pub starred: Option<String>,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,49 +6,49 @@ use crate::subsonic::{Album, Artist};
|
|||
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
pub struct Child {
|
||||
#[serde(rename = "@id")]
|
||||
#[serde(rename = "id")]
|
||||
pub id: String,
|
||||
#[serde(rename = "@isDir")]
|
||||
#[serde(rename = "isDir")]
|
||||
pub is_dir: bool,
|
||||
#[serde(rename = "@title")]
|
||||
#[serde(rename = "title")]
|
||||
pub title: String,
|
||||
#[serde(rename = "@album", skip_serializing_if = "Option::is_none")]
|
||||
#[serde(rename = "album", skip_serializing_if = "Option::is_none")]
|
||||
pub album: Option<String>,
|
||||
#[serde(rename = "@track", skip_serializing_if = "Option::is_none")]
|
||||
#[serde(rename = "track", skip_serializing_if = "Option::is_none")]
|
||||
pub track: Option<u32>,
|
||||
#[serde(rename = "@year", skip_serializing_if = "Option::is_none")]
|
||||
#[serde(rename = "year", skip_serializing_if = "Option::is_none")]
|
||||
pub year: Option<u32>,
|
||||
#[serde(rename = "@coverArtId", skip_serializing_if = "Option::is_none")]
|
||||
#[serde(rename = "coverArtId", skip_serializing_if = "Option::is_none")]
|
||||
pub cover_art_id: Option<String>,
|
||||
#[serde(rename = "@size")]
|
||||
#[serde(rename = "size")]
|
||||
pub size: u64,
|
||||
#[serde(rename = "@contentType")]
|
||||
#[serde(rename = "contentType")]
|
||||
pub content_type: String,
|
||||
#[serde(rename = "@suffix")]
|
||||
#[serde(rename = "suffix")]
|
||||
pub suffix: String,
|
||||
#[serde(rename = "@starred", skip_serializing_if = "Option::is_none")]
|
||||
#[serde(rename = "starred", skip_serializing_if = "Option::is_none")]
|
||||
pub starred: Option<String>,
|
||||
#[serde(rename = "@duration")]
|
||||
#[serde(rename = "duration")]
|
||||
pub duration: u64,
|
||||
#[serde(rename = "@bitRate", skip_serializing_if = "Option::is_none")]
|
||||
#[serde(rename = "bitRate", skip_serializing_if = "Option::is_none")]
|
||||
pub bit_rate: Option<u64>,
|
||||
#[serde(rename = "@path")]
|
||||
#[serde(rename = "path")]
|
||||
pub path: String,
|
||||
#[serde(rename = "@playCount")]
|
||||
#[serde(rename = "playCount")]
|
||||
pub play_count: u64,
|
||||
#[serde(rename = "@discNumber")]
|
||||
#[serde(rename = "discNumber")]
|
||||
pub disc_number: u32,
|
||||
#[serde(rename = "@created")]
|
||||
#[serde(rename = "created")]
|
||||
pub created: String,
|
||||
#[serde(rename = "@albumId", skip_serializing_if = "Option::is_none")]
|
||||
#[serde(rename = "albumId", skip_serializing_if = "Option::is_none")]
|
||||
pub album_id: Option<String>,
|
||||
#[serde(rename = "@artistId", skip_serializing_if = "Option::is_none")]
|
||||
#[serde(rename = "artistId", skip_serializing_if = "Option::is_none")]
|
||||
pub artist_id: Option<String>,
|
||||
#[serde(rename = "@artist")]
|
||||
#[serde(rename = "artist")]
|
||||
pub artist: String,
|
||||
#[serde(rename = "@type")]
|
||||
#[serde(rename = "type")]
|
||||
pub child_type: String,
|
||||
#[serde(rename = "@isVideo")]
|
||||
#[serde(rename = "isVideo")]
|
||||
pub is_video: bool,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,9 +3,9 @@ use serde::Serialize;
|
|||
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
pub struct MusicFolder {
|
||||
#[serde(rename = "@id")]
|
||||
#[serde(rename = "id")]
|
||||
pub id: String,
|
||||
#[serde(rename = "@name")]
|
||||
#[serde(rename = "name")]
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue