unsafe which in context is safe implementation of update m3u8

This commit is contained in:
Love 2023-01-18 00:06:55 +01:00
parent e34243d7d8
commit e12e26221f
2 changed files with 61 additions and 37 deletions

View File

@ -39,7 +39,7 @@ fn main() {
for (idx, m3u8_item) in search_result.as_ref().unwrap().iter().enumerate().rev() { for (idx, m3u8_item) in search_result.as_ref().unwrap().iter().enumerate().rev() {
println!(" {}: {}", idx + 1, m3u8_item); 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(); stdout.flush().unwrap();
buf = String::new(); buf = String::new();
stdin.read_line(&mut buf).unwrap(); stdin.read_line(&mut buf).unwrap();
@ -51,6 +51,18 @@ fn main() {
} else if user_wish == "s" { } else if user_wish == "s" {
search_result = None; search_result = None;
continue; 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::<usize>(); let choosen = user_wish.parse::<usize>();

View File

@ -1,4 +1,3 @@
use std::ops::Deref;
use std::path::PathBuf; use std::path::PathBuf;
use std::rc::Rc; use std::rc::Rc;
use std::{fs, process}; use std::{fs, process};
@ -12,9 +11,36 @@ const MAX_TRIES: usize = 4;
pub struct Parser { pub struct Parser {
watched_name: Rc<PathBuf>, watched_name: Rc<PathBuf>,
m3u8_items: Vec<M3u8>, m3u8_items: Vec<M3u8>,
ilovetv_url: Rc<String>,
file_name: Rc<PathBuf>,
} }
impl Parser { 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 { fn should_update(file_name: &PathBuf) -> bool {
fs::metadata(&file_name) fs::metadata(&file_name)
.and_then(|metadata| { .and_then(|metadata| {
@ -36,34 +62,24 @@ impl Parser {
) )
} }
pub fn new(file_name: String, iptv_url: String, watched_name: String) -> Self { pub fn forcefully_update(&mut self) {
let project_dirs = ProjectDirs::from("com", "billenius", "iptvnator_rs").unwrap(); let mut counter = 0;
let cache = project_dirs.cache_dir(); let content = loop {
let _ = fs::create_dir_all(&cache); 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 _ = fs::write(&*self.file_name, &content);
let iptv_url = Rc::new(iptv_url); self.m3u8_items = Self::parse_m3u8(content, &self.watched_name.clone());
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()
} }
pub fn save_watched(&self) { 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 let watched_items = self
.m3u8_items .m3u8_items
.iter() .iter()
@ -71,9 +87,9 @@ impl Parser {
.map(|item| item.link.clone()) .map(|item| item.link.clone())
.collect::<Vec<String>>(); .collect::<Vec<String>>();
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(_) => { Ok(_) => {
println!("Saved watched") println!("Saved watched")
} }
@ -84,6 +100,10 @@ impl Parser {
} }
fn get_parsed_content(link: &String, file_name: &PathBuf, watched_name: &PathBuf) -> Vec<M3u8> { fn get_parsed_content(link: &String, file_name: &PathBuf, watched_name: &PathBuf) -> Vec<M3u8> {
Self::parse_m3u8(Self::get_stringcontent(link, file_name, 0), watched_name)
}
fn parse_m3u8(content: String, watched_name: &PathBuf) -> Vec<M3u8> {
let saved_watches = fs::read_to_string(&watched_name); let saved_watches = fs::read_to_string(&watched_name);
let saved_watches = if saved_watches.is_ok() { let saved_watches = if saved_watches.is_ok() {
saved_watches.unwrap() saved_watches.unwrap()
@ -94,7 +114,7 @@ impl Parser {
let watched: Vec<String> = saved_watches.lines().map(String::from).collect(); let watched: Vec<String> = saved_watches.lines().map(String::from).collect();
let mut m3u8_items: Vec<M3u8> = Vec::new(); let mut m3u8_items: Vec<M3u8> = Vec::new();
let interesting_lines: Vec<String> = Self::get_stringcontent(link, file_name, 0) let interesting_lines: Vec<String> = content
.replacen("#EXTM3U\n", "", 1) .replacen("#EXTM3U\n", "", 1)
.lines() .lines()
.map(str::trim) .map(str::trim)
@ -160,11 +180,3 @@ impl Parser {
.and_then(|resp| Ok(resp.text().expect("Could not get m3u8 from server"))) .and_then(|resp| Ok(resp.text().expect("Could not get m3u8 from server")))
} }
} }
impl Deref for Parser {
type Target = Vec<M3u8>;
fn deref(&self) -> &Self::Target {
&self.m3u8_items
}
}