yt-feed-xml 0.2.2

A crate used to parse data from Youtube's XML feeds. WIP USE AT YOUR OWN RISK.
Documentation
use color_eyre::eyre::Context;
use serde::Deserialize;
use serde::Serialize;

use crate::{video::Video, xml_feed::Feed};

#[derive(Serialize, Deserialize, Debug, Clone, derive_builder::Builder)]
pub struct Playlist {
    pub id: String,
    pub title: String,
    pub author: String,
    pub channel_id: String,
    pub url: String,
    pub published: chrono::DateTime<chrono::Utc>,
    pub videos: Option<Vec<Video>>,
}

impl Playlist {
    pub async fn new(id: &str) -> Self {
        let uri = format!(
            "https://www.youtube.com/feeds/videos.xml?playlist_id={}",
            &id
        );

        let feed: Feed = Feed::new(&uri)
            .await
            .wrap_err("Failed to create Feed from given ID.")
            .unwrap();

        feed.try_into()
            .wrap_err("Failed to convert Feed to Playlist.")
            .unwrap()
    }
}

impl TryFrom<Feed> for Playlist {
    type Error = color_eyre::Report;

    fn try_from(f: Feed) -> Result<Self, Self::Error> {
        let id = f.playlist_id.ok_or_else(|| {
            color_eyre::eyre::eyre!("Could not find playlist id for given Playlist.")
        })?;
        Ok(Self {
            id: id.clone(),
            title: f.title,
            author: f.author,
            channel_id: f.channel_id,
            url: format!("https://www.youtube.com/playlist?list={id}"),
            published: f.published,
            videos: f.videos,
        })
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[tokio::test]
    async fn test_sinclair_lore_playlist() {
        let sinclair_lore_va_masq = Playlist::new("PLOIA4n5j7KcYj52DQ9orEBJDA9IqBTB3I").await;
        assert_eq!(
            sinclair_lore_va_masq.id,
            "PLOIA4n5j7KcYj52DQ9orEBJDA9IqBTB3I"
        );
        assert_eq!(
            sinclair_lore_va_masq.url,
            "https://www.youtube.com/playlist?list=PLOIA4n5j7KcYj52DQ9orEBJDA9IqBTB3I"
        );
        assert_eq!(sinclair_lore_va_masq.channel_id, "UCH6IMeS2HVdTJZU4BlN6ODg");
        assert_eq!(
            sinclair_lore_va_masq.title,
            "Vampire the Masquerade ► Down Under by Night | Actual Play"
        );
    }
}