fix: fix json serialization
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful

This commit is contained in:
Lys 2023-11-28 05:39:38 +02:00
parent 513997cd79
commit 79e2f730cc
Signed by: lyssieth
GPG key ID: C9CF3D614FAA3940
5 changed files with 140 additions and 143 deletions

View file

@ -1,4 +1,5 @@
use poem::{http::StatusCode, IntoResponse, Response};
use serde::ser::SerializeStruct;
use serde::{Serialize, Serializer};
use crate::authentication::VersionTriple;
@ -12,130 +13,126 @@ 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>
where
S: Serializer,
{
match value {
SubResponseType::MusicFolders { music_folders } => {
#[derive(Serialize)]
struct MF {
id: String,
name: String,
}
impl Serialize for SubsonicResponse {
fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
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();
}
impl From<MusicFolder> for MF {
fn from(value: MusicFolder) -> Self {
Self {
id: value.id,
name: value.name,
}
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 License {
#[serde(rename = "valid")]
valid: bool,
}
}
#[derive(Serialize)]
struct MusicFolders {
#[serde(rename = "musicFolders")]
music_folders: Vec<MF>,
s.serialize_field("license", &License { valid: *valid })?;
}
SubResponseType::AlbumList { albums } => {
#[derive(Serialize)]
struct AlbumList<'a> {
#[serde(rename = "album")]
albums: &'a Vec<Album>,
}
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 {
#[serde(rename = "album")]
albums: Vec<Album>,
s.serialize_field("albumList", &AlbumList { albums })?;
}
SubResponseType::AlbumList2 { albums } => {
#[derive(Serialize)]
struct AlbumList2<'a> {
#[serde(rename = "album")]
albums: &'a Vec<Album>,
}
AlbumList {
albums: albums.clone(),
}
.serialize(s)
}
SubResponseType::AlbumList2 { albums } => {
#[derive(Serialize)]
struct AlbumList2 {
#[serde(rename = "album")]
albums: Vec<Album>,
s.serialize_field("albumList2", &AlbumList2 { albums })?;
}
SubResponseType::Album { album, songs } => {
#[derive(Serialize)]
struct AlbumWithSongs<'a> {
#[serde(flatten)]
album: &'a Album,
#[serde(rename = "song")]
songs: &'a Vec<Child>,
}
AlbumList2 {
albums: albums.clone(),
}
.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<Child>,
s.serialize_field("album", &AlbumWithSongs { album, songs })?;
}
SubResponseType::ScanStatus { scanning, count } => {
#[derive(Serialize)]
struct ScanStatus {
scanning: bool,
count: u64,
}
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,
s.serialize_field(
"scanStatus",
&ScanStatus {
scanning: *scanning,
count: *count,
},
)?;
}
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<Artist>,
#[serde(rename = "album")]
albums: &'a Vec<Album>,
#[serde(rename = "song")]
songs: &'a Vec<Child>,
}
SearchResult3 {
SubResponseType::SearchResult3 {
artists,
albums,
songs,
} => {
#[derive(Serialize)]
struct SearchResult3<'a> {
#[serde(rename = "artist")]
artists: &'a Vec<Artist>,
#[serde(rename = "album")]
albums: &'a Vec<Album>,
#[serde(rename = "song")]
songs: &'a Vec<Child>,
}
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>,
}
s.serialize_field("artists", &Artists { artists })?;
}
SubResponseType::Artist { artist } => s.serialize_field("artist", artist)?,
SubResponseType::Empty => unreachable!("Empty response should be handled above"),
}
SubResponseType::Artists { artists } => artists.serialize(s),
SubResponseType::Artist { artist } => artist.serialize(s),
SubResponseType::Empty => s.serialize_none(),
s.end()
}
}

View file

@ -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>,
}

View file

@ -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>,
}

View file

@ -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,
}

View file

@ -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,
}