1use std::convert::TryFrom;
2
3use anyhow::anyhow;
4use anyhow::Result;
5use chrono::offset::FixedOffset;
6use chrono::DateTime;
7use regex::Regex;
8use rss::Enclosure;
9use rss::{Channel, Item};
10use serde::{Deserialize, Serialize};
11
12impl TryFrom<String> for AllEpisodes {
13 fn try_from(value: String) -> Result<Self, Self::Error> {
14 let channel = Channel::read_from(value.as_bytes())?;
15 println!("deserialized items: {}", channel.items.len());
16
17 let episodes: Vec<Episode> = channel
18 .items
19 .into_iter()
20 .map(|i| i.try_into())
21 .collect::<Result<_>>()?;
22 Ok(AllEpisodes { episodes })
23 }
24
25 type Error = anyhow::Error;
26}
27
28pub struct AllEpisodes {
29 pub episodes: Vec<Episode>,
30}
31
32#[derive(Serialize, Deserialize, Debug, Clone)]
33pub struct Episode {
34 pub id: String,
36 pub title: String,
37 pub description: Option<String>,
38 pub content: Option<String>,
39 pub link: String,
40 pub enclosure: Enclosure,
41 pub pub_date: DateTime<FixedOffset>,
42}
43
44impl TryFrom<Item> for Episode {
45 type Error = anyhow::Error;
46 fn try_from(episode: Item) -> Result<Self, Self::Error> {
47 let re = Regex::new(r"[a-zA-Z0-9]").unwrap();
49 let title = episode.title.ok_or_else(|| anyhow!("missing title"))?;
50 let episode = Episode {
51 id: re
52 .find_iter(&title)
53 .map(|a| a.as_str())
54 .collect::<Vec<_>>()
55 .join(""),
56 title,
57 description: episode.description,
58 content: episode.content,
59 link: episode.link.ok_or_else(|| anyhow!("missing link!"))?,
60 enclosure: episode
61 .enclosure
62 .ok_or_else(|| anyhow!("missing enclosure url"))?,
63 pub_date: DateTime::parse_from_rfc2822(
64 &episode
65 .pub_date
66 .ok_or_else(|| anyhow!("missing pubValue"))?,
67 )?,
68 };
69
70 Ok(episode)
71 }
72}