yt_sub_core/
video.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
use chrono::{DateTime, Utc};
use eyre::Result;
use xmltojson::to_json;

use crate::notifier::Notifier;

#[derive(Debug)]
pub struct Video {
    pub channel: String,
    pub title: String,
    pub link: String,
    pub published_at: DateTime<Utc>,
}

impl Video {
    pub fn parse_rss(rss_data: String) -> Result<Vec<Video>> {
        let mut videos = vec![];
        let json = to_json(&rss_data).expect("Failed to convert XML to JSON");
        let channel = json["feed"]["author"]["name"].as_str().unwrap();
        let videos_data = json["feed"]["entry"].as_array().unwrap();

        for video_data in videos_data {
            let title = video_data["title"].as_str().unwrap();
            let published_at = video_data["published"].as_str().unwrap();
            let published_at: DateTime<Utc> =
                published_at.parse().expect("Failed to parse DateTime");
            let link = video_data["link"]["@href"].as_str().unwrap();

            let video = Video {
                channel: channel.to_string(),
                title: title.to_string(),
                link: link.to_string(),
                published_at,
            };

            videos.push(video);
        }

        Ok(videos)
    }

    pub fn notification_text(&self, notifier: &Notifier) -> String {
        match notifier {
            Notifier::Log() => {
                format!("New video - {} {} {}", self.channel, self.title, self.link)
            }
            Notifier::Slack(_) => {
                format!(
                    "*New video - {}* <{}|{}>",
                    self.channel, self.link, self.title
                )
            }
            Notifier::Telegram => {
                todo!()
            }
        }
    }
}

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

    #[tokio::test]
    async fn parse_videos_test() {
        let rss_data = fs::read_to_string("src/fixtures/yt_videos_data.xml").unwrap();
        let videos = Video::parse_rss(rss_data).unwrap();
        assert_eq!(videos.len(), 15);
    }
}