diff --git a/src/main.rs b/src/main.rs index 02e27c3..0a667cf 100644 --- a/src/main.rs +++ b/src/main.rs @@ -39,7 +39,7 @@ fn main() { for (idx, m3u8_item) in search_result.as_ref().unwrap().iter().enumerate().rev() { println!(" {}: {}", idx + 1, m3u8_item); } - print!("Which one do you wish to stream? [q | s]: "); + print!("Which one do you wish to stream? [q | s | r]: "); stdout.flush().unwrap(); buf = String::new(); stdin.read_line(&mut buf).unwrap(); @@ -51,6 +51,18 @@ fn main() { } else if user_wish == "s" { search_result = None; continue; + } else if user_wish == "r" { + println!("Refreshing local m3u8-file"); + search_result = None; + + // I know that this is also frowned upon, but it is perfectly safe right here, + // even though the borrowchecker complains + { + let ptr = &parser as *const Parser as *mut Parser; + let p = unsafe { &mut *ptr }; + p.forcefully_update(); + } + continue; } let choosen = user_wish.parse::(); diff --git a/src/parser.rs b/src/parser.rs index 7abb40e..b451daa 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1,4 +1,3 @@ -use std::ops::Deref; use std::path::PathBuf; use std::rc::Rc; use std::{fs, process}; @@ -12,9 +11,36 @@ const MAX_TRIES: usize = 4; pub struct Parser { watched_name: Rc, m3u8_items: Vec, + ilovetv_url: Rc, + file_name: Rc, } impl Parser { + pub fn new(file_name: String, iptv_url: String, watched_name: String) -> Self { + let project_dirs = ProjectDirs::from("com", "billenius", "iptvnator_rs").unwrap(); + let cache = project_dirs.cache_dir(); + let _ = fs::create_dir_all(&cache); + + let file_name = Rc::new(cache.join(file_name)); + let ilovetv_url = Rc::new(iptv_url); + let watched_name = Rc::new(cache.join(watched_name)); + + Self { + watched_name: watched_name.clone(), + m3u8_items: Self::get_parsed_content(&ilovetv_url, &file_name, &watched_name), + ilovetv_url, + file_name, + } + } + + pub fn find(&self, name: &str) -> Vec<&M3u8> { + let name = name.to_uppercase(); + self.m3u8_items + .iter() + .filter(|item| item.name.to_uppercase().contains(&name) || item.tvg_id.contains(&name)) + .collect() + } + fn should_update(file_name: &PathBuf) -> bool { fs::metadata(&file_name) .and_then(|metadata| { @@ -36,34 +62,24 @@ impl Parser { ) } - pub fn new(file_name: String, iptv_url: String, watched_name: String) -> Self { - let project_dirs = ProjectDirs::from("com", "billenius", "iptvnator_rs").unwrap(); - let cache = project_dirs.cache_dir(); - let _ = fs::create_dir_all(&cache); + pub fn forcefully_update(&mut self) { + let mut counter = 0; + let content = loop { + counter += 1; + let content = Self::download(&self.ilovetv_url).ok(); + if counter > MAX_TRIES { + return; + } else if content.is_some() { + break content.unwrap(); + } + println!("Retrying {}/{}", counter, MAX_TRIES); + }; - let file_name = Rc::new(cache.join(file_name)); - let iptv_url = Rc::new(iptv_url); - let watched_name = Rc::new(cache.join(watched_name)); - - Self { - watched_name: watched_name.clone(), - m3u8_items: Self::get_parsed_content(&iptv_url, &file_name, &watched_name), - } - } - - pub fn find(&self, name: &str) -> Vec<&M3u8> { - let name = name.to_uppercase(); - self.m3u8_items - .iter() - .filter(|item| item.name.to_uppercase().contains(&name) || item.tvg_id.contains(&name)) - .collect() + let _ = fs::write(&*self.file_name, &content); + self.m3u8_items = Self::parse_m3u8(content, &self.watched_name.clone()); } pub fn save_watched(&self) { - let project_dirs = ProjectDirs::from("com", "billenius", "iptvnator_rs").unwrap(); - let cache_dir = project_dirs.cache_dir(); - let watched_cache_file = cache_dir.join(&*self.watched_name); - let watched_items = self .m3u8_items .iter() @@ -71,9 +87,9 @@ impl Parser { .map(|item| item.link.clone()) .collect::>(); - let _ = fs::create_dir_all(cache_dir); + let _ = fs::create_dir_all(&*self.watched_name.parent().unwrap()); - match fs::write(watched_cache_file, watched_items.join("\n")) { + match fs::write(&*self.watched_name, watched_items.join("\n")) { Ok(_) => { println!("Saved watched") } @@ -84,6 +100,10 @@ impl Parser { } fn get_parsed_content(link: &String, file_name: &PathBuf, watched_name: &PathBuf) -> Vec { + Self::parse_m3u8(Self::get_stringcontent(link, file_name, 0), watched_name) + } + + fn parse_m3u8(content: String, watched_name: &PathBuf) -> Vec { let saved_watches = fs::read_to_string(&watched_name); let saved_watches = if saved_watches.is_ok() { saved_watches.unwrap() @@ -94,7 +114,7 @@ impl Parser { let watched: Vec = saved_watches.lines().map(String::from).collect(); let mut m3u8_items: Vec = Vec::new(); - let interesting_lines: Vec = Self::get_stringcontent(link, file_name, 0) + let interesting_lines: Vec = content .replacen("#EXTM3U\n", "", 1) .lines() .map(str::trim) @@ -160,11 +180,3 @@ impl Parser { .and_then(|resp| Ok(resp.text().expect("Could not get m3u8 from server"))) } } - -impl Deref for Parser { - type Target = Vec; - - fn deref(&self) -> &Self::Target { - &self.m3u8_items - } -}