1use std::path::PathBuf;
2use std::io;
3use std::collections::HashSet;
4use std::fs::File;
5use std::io::prelude::*;
6use std::string::String;
7use std::vec::Vec;
8
9use crate::scrapper;
10
11
12pub struct Playlist {
13 pub urls: Vec<String>
14}
15
16impl Playlist {
17
18 pub fn try_from(path: &PathBuf) -> Result<Self, io::Error> {
19
20 let f = File::open(path)?;
22 let reader = io::BufReader::new(f);
23
24 let urls = reader.lines()
26 .filter_map(|line| {
27 let line = line.ok().unwrap();
28
29 if !line.starts_with('#') && line.starts_with("http") {
30 return Some(line.trim().to_string());
31 }
32
33 None
34 })
35 .collect::<Vec<String>>();
36
37 Ok(Playlist {
39 urls,
40 })
41 }
42
43 pub fn save(&self, target: PathBuf, videos: &[scrapper::Video]) -> Result<(), io::Error> {
44
45 fn format_title(video: &scrapper::Video) -> String {
46 format!(
47 "({} | {}) - {}",
48 video.published, video.channel, video.title.content,
49 )
50 }
51
52 let mut f = File::create(target)?;
53
54 f.write_all(b"# Created by YTitler\n")?;
56 f.write_all(b"# See: https://gitlab.com/n1_/ytitler\n\n")?;
57 f.write_all(b"#EXTM3U\n")?;
58
59 for v in videos {
61
62 f.write_fmt(format_args!(
63 "#EXTINF:{},{}\n",
64 v.duration.as_secs(),
65 format_title(v)
66 ))?;
67 f.write_fmt(format_args!("{}\n", v.url))?;
68 }
69
70 f.sync_all()?;
71
72 Ok(())
73 }
74
75 pub fn remove_duplicities(&mut self) {
76 let mut set = HashSet::new();
82 self.urls.retain(|i| set.insert(i.clone()));
83 }
84
85 pub fn to_chunks(&self) -> Vec<Vec<String>> {
86
87 self.urls.chunks(10).map(|s| s.to_vec()).collect()
88 }
89}