Files
podcast-hoarder/src/rss.rs

92 lines
2.9 KiB
Rust
Raw Normal View History

2024-01-11 17:30:55 +11:00
#![allow(dead_code)]
// See https://support.google.com/podcast-publishers/answer/9889544
// for some reasonably guidelines for how a podcast RSS feed should look.
use std::fmt;
use std::borrow::Cow;
#[derive(Debug, serde::Deserialize)]
pub struct Feed<'a> {
pub(crate) rss: Rss<'a>,
2024-01-11 17:30:55 +11:00
}
#[derive(Debug, serde::Deserialize)]
pub struct Rss<'a> {
pub(crate) channel: Channel<'a>,
2024-01-11 17:30:55 +11:00
}
#[derive(Debug, serde::Deserialize)]
pub struct Channel<'a> {
#[serde(rename = "item", default)]
pub(crate) items: Vec<Item<'a>>,
pub(crate) link: Option<Cow<'a, str>>,
pub(crate) title: Cow<'a, str>,
pub(crate) description: Option<Cow<'a, str>>,
2024-01-11 17:30:55 +11:00
#[serde(rename = "{http://www.itunes.com/dtds/podcast-1.0.dtd}itunes:author")]
pub(crate) author: Option<Cow<'a, str>>,
2024-01-11 17:30:55 +11:00
#[serde(rename = "{http://www.itunes.com/dtds/podcast-1.0.dtd}itunes:summary")]
pub(crate) summary: Option<Cow<'a, str>>,
2024-01-11 17:30:55 +11:00
#[serde(rename = "{http://www.itunes.com/dtds/podcast-1.0.dtd}itunes:image")]
pub(crate) itunes_image: Option<ItunesImage<'a>>,
pub(crate) image: Option<Image<'a>>,
2024-01-11 17:30:55 +11:00
}
#[derive(Debug, serde::Deserialize)]
pub struct Image<'a> {
pub(crate) link: Option<Cow<'a, str>>,
pub(crate) title: Cow<'a, str>,
pub(crate) url: Cow<'a, str>,
2024-01-11 17:30:55 +11:00
}
#[derive(Debug, serde::Deserialize)]
pub struct ItunesImage<'a> {
#[serde(rename = "$attr:href")]
pub(crate) href: Cow<'a, str>,
2024-01-11 17:30:55 +11:00
}
fn deserialize_publish_date<'de, D: serde::de::Deserializer<'de>> (
deserializer: D
2024-01-11 17:30:55 +11:00
) -> Result<chrono::NaiveDateTime, D::Error> {
struct Visitor;
impl<'de> serde::de::Visitor<'de> for Visitor {
type Value = chrono::NaiveDateTime;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
2024-01-11 17:30:55 +11:00
formatter.write_str("a string containing json data")
}
fn visit_str<E: serde::de::Error>(self, input: &str) -> Result<Self::Value, E> {
2024-01-11 17:30:55 +11:00
chrono::NaiveDateTime::parse_from_str(
input,
"%a, %d %b %Y %H:%M:%S %Z"
).map_err(E::custom)
}
}
deserializer.deserialize_any(Visitor)
}
#[derive(Debug, serde::Deserialize)]
pub struct Item<'a> {
pub(crate) title: Cow<'a, str>,
pub(crate) enclosure: Option<Enclosure<'a>>,
pub(crate) description: Option<Cow<'a, str>>,
2024-01-11 17:30:55 +11:00
#[serde(rename = "{http://www.itunes.com/dtds/podcast-1.0.dtd}itunes:summary")]
pub(crate) summary: Option<Cow<'a, str>>,
2024-01-11 17:30:55 +11:00
#[serde(rename = "pubDate", deserialize_with = "deserialize_publish_date")]
pub(crate) published: chrono::NaiveDateTime,
pub(crate) guid: Option<Cow<'a, str>>,
2024-01-11 17:30:55 +11:00
}
#[derive(Debug, serde::Deserialize)]
pub struct Enclosure<'a> {
#[serde(rename = "$attr:url")]
pub(crate) url: Cow<'a, str>,
2024-01-11 17:30:55 +11:00
#[serde(rename = "$attr:type")]
pub(crate) mime_type: Option<Cow<'a, str>>,
//#[serde(rename = "$attr:length")]
//pub(crate) length: Option<u64>,
2024-01-11 17:30:55 +11:00
}