use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; use crate::gpodder; #[derive(Deserialize, Debug)] pub struct SubscriptionDelta { pub add: Vec, pub remove: Vec, } #[derive(Serialize, Default)] pub struct SubscriptionDeltaResponse { pub add: Vec, pub remove: Vec, pub timestamp: i64, } #[derive(Serialize)] pub struct UpdatedUrlsResponse { pub timestamp: i64, pub update_urls: Vec<(String, String)>, } #[derive(Serialize, Deserialize)] #[serde(rename_all = "lowercase")] pub enum DeviceType { Desktop, Laptop, Mobile, Server, Other, } #[derive(Serialize)] pub struct Device { pub id: String, pub caption: String, pub r#type: DeviceType, pub subscriptions: i64, } #[derive(Deserialize)] pub struct DevicePatch { pub caption: Option, pub r#type: Option, } #[derive(Serialize, Deserialize, Debug)] #[serde(rename_all = "lowercase")] #[serde(tag = "action")] pub enum EpisodeActionType { Download, Play { #[serde(default)] started: Option, position: i32, #[serde(default)] total: Option, }, Delete, New, } #[derive(Serialize, Deserialize, Debug)] pub struct EpisodeAction { pub podcast: String, pub episode: String, pub timestamp: Option, #[serde(default)] pub device: Option, #[serde(flatten)] pub action: EpisodeActionType, } impl From for DeviceType { fn from(value: gpodder::DeviceType) -> Self { match value { gpodder::DeviceType::Other => Self::Other, gpodder::DeviceType::Laptop => Self::Laptop, gpodder::DeviceType::Mobile => Self::Mobile, gpodder::DeviceType::Server => Self::Server, gpodder::DeviceType::Desktop => Self::Desktop, } } } impl From for gpodder::DeviceType { fn from(value: DeviceType) -> Self { match value { DeviceType::Other => gpodder::DeviceType::Other, DeviceType::Laptop => gpodder::DeviceType::Laptop, DeviceType::Mobile => gpodder::DeviceType::Mobile, DeviceType::Server => gpodder::DeviceType::Server, DeviceType::Desktop => gpodder::DeviceType::Desktop, } } } impl From for Device { fn from(value: gpodder::Device) -> Self { Self { id: value.id, caption: value.caption, r#type: value.r#type.into(), subscriptions: value.subscriptions, } } } impl From for gpodder::DevicePatch { fn from(value: DevicePatch) -> Self { Self { caption: value.caption, r#type: value.r#type.map(Into::into), } } } impl From for EpisodeActionType { fn from(value: gpodder::EpisodeActionType) -> Self { match value { gpodder::EpisodeActionType::New => Self::New, gpodder::EpisodeActionType::Delete => Self::Delete, gpodder::EpisodeActionType::Download => Self::Download, gpodder::EpisodeActionType::Play { started, position, total, } => Self::Play { started, position, total, }, } } } impl From for gpodder::EpisodeActionType { fn from(value: EpisodeActionType) -> Self { match value { EpisodeActionType::New => gpodder::EpisodeActionType::New, EpisodeActionType::Delete => gpodder::EpisodeActionType::Delete, EpisodeActionType::Download => gpodder::EpisodeActionType::Download, EpisodeActionType::Play { started, position, total, } => gpodder::EpisodeActionType::Play { started, position, total, }, } } } impl From for EpisodeAction { fn from(value: gpodder::EpisodeAction) -> Self { Self { podcast: value.podcast, episode: value.episode, timestamp: value.timestamp.map(|ts| ts.timestamp()), device: value.device, action: value.action.into(), } } } impl From for gpodder::EpisodeAction { fn from(value: EpisodeAction) -> Self { Self { podcast: value.podcast, episode: value.episode, // TODO remove this unwrap timestamp: value .timestamp .map(|ts| DateTime::from_timestamp(ts, 0).unwrap()), device: value.device, action: value.action.into(), time_changed: DateTime::::MIN_UTC, } } }