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