Skip to main content

yt_feed_xml/
channel.rs

1use color_eyre::eyre::Context;
2use serde::Deserialize;
3use serde::Serialize;
4
5use crate::video::Video;
6use crate::xml_feed::Feed;
7
8#[derive(Serialize, Deserialize, Debug, Clone, derive_builder::Builder)]
9pub struct Channel {
10    pub id: String,
11    pub title: String,
12    pub author: String,
13    pub url: String,
14    pub published: chrono::DateTime<chrono::Utc>,
15    pub videos: Option<Vec<Video>>,
16}
17
18impl Channel {
19    pub async fn new(id: &str) -> Self {
20        let uri = format!(
21            "https://www.youtube.com/feeds/videos.xml?channel_id={}",
22            &id
23        );
24
25        let feed: Feed = Feed::new(&uri)
26            .await
27            .wrap_err("Failed to create Channel.")
28            .unwrap();
29        feed.into()
30    }
31}
32
33impl From<Feed> for Channel {
34    fn from(f: Feed) -> Self {
35        Self {
36            id: f.channel_id,
37            title: f.title,
38            author: f.author,
39            url: f.url,
40            published: f.published,
41            videos: f.videos,
42        }
43    }
44}
45
46#[cfg(test)]
47mod tests {
48    use super::*;
49
50    #[tokio::test]
51    async fn test_linus() {
52        let linus = Channel::new("UCXuqSBlHAE6Xw-yeJA0Tunw").await;
53        assert_eq!(linus.id, "UCXuqSBlHAE6Xw-yeJA0Tunw");
54        assert_eq!(linus.title, "Linus Tech Tips");
55    }
56
57    #[tokio::test]
58    #[should_panic]
59    async fn test_linus_missing_playlist() {
60        let linus = Feed::new(
61            "https://www.youtube.com/feeds/videos.xml?channel_id=UCXuqSBlHAE6Xw-yeJA0Tunw",
62        )
63        .await
64        .unwrap();
65        let _panic = linus.playlist_id.unwrap();
66    }
67}