A lot of refactoring
Made the program a lot more configurable and also cleaned up the parser struct
This commit is contained in:
parent
86f85011ec
commit
36b79fd01f
20
Cargo.lock
generated
20
Cargo.lock
generated
@ -464,6 +464,8 @@ dependencies = [
|
|||||||
"futures-util",
|
"futures-util",
|
||||||
"indicatif",
|
"indicatif",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
"tokio",
|
"tokio",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -871,12 +873,26 @@ name = "serde"
|
|||||||
version = "1.0.152"
|
version = "1.0.152"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb"
|
checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb"
|
||||||
|
dependencies = [
|
||||||
|
"serde_derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_derive"
|
||||||
|
version = "1.0.152"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_json"
|
name = "serde_json"
|
||||||
version = "1.0.91"
|
version = "1.0.93"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "877c235533714907a8c2464236f5c4b2a17262ef1bd71f38f35ea592c8da6883"
|
checksum = "cad406b69c91885b5107daf2c29572f6c8cdb3c66826821e286c533490c0bc76"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"itoa",
|
"itoa",
|
||||||
"ryu",
|
"ryu",
|
||||||
|
@ -10,4 +10,6 @@ directories = "4.0.1"
|
|||||||
futures-util = "0.3.25"
|
futures-util = "0.3.25"
|
||||||
indicatif = { version = "0.17.3", features = ["tokio"] }
|
indicatif = { version = "0.17.3", features = ["tokio"] }
|
||||||
reqwest = { version = "0.11.13", features = ["blocking", "deflate", "gzip", "rustls", "rustls-tls", "stream"] }
|
reqwest = { version = "0.11.13", features = ["blocking", "deflate", "gzip", "rustls", "rustls-tls", "stream"] }
|
||||||
tokio = { version = "1.24.2", features = ["full"] }
|
serde = { version = "1.0.152", features = ["serde_derive"] }
|
||||||
|
serde_json = "1.0.93"
|
||||||
|
tokio = { version = "1.24.2", features = ["full"] }
|
||||||
|
188
src/config.rs
188
src/config.rs
@ -0,0 +1,188 @@
|
|||||||
|
use std::{
|
||||||
|
fs::{self, File},
|
||||||
|
io::{self, BufReader},
|
||||||
|
ops::Deref,
|
||||||
|
path::{Path, PathBuf},
|
||||||
|
};
|
||||||
|
|
||||||
|
use directories::ProjectDirs;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use serde_json;
|
||||||
|
|
||||||
|
use crate::{download_with_progress, Readline};
|
||||||
|
|
||||||
|
const JSON_CONFIG_FILENAME: &'static str = "iptvnator_config.json";
|
||||||
|
const APP_IDENTIFIER: [&'static str; 3] = ["com", "billenius", "iptvnator"];
|
||||||
|
const STANDARD_PLAYLIST_FILENAME: &'static str = "ilovetv.m3u8";
|
||||||
|
const STANDARD_SEEN_LINKS_FILENAME: &'static str = "watched_links.json";
|
||||||
|
const MAX_TRIES: u8 = 4;
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
pub struct Conf {
|
||||||
|
pub playlist_filename: String,
|
||||||
|
pub playlist_url: String,
|
||||||
|
pub last_search: Option<String>,
|
||||||
|
pub seen_links_filename: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Conf {
|
||||||
|
/**
|
||||||
|
* Read configurationfile or ask user for link input if it isn't created.
|
||||||
|
* Will error if it fails to write config file
|
||||||
|
*/
|
||||||
|
pub fn new(ilovetv_config_file: &Path) -> Result<Conf, io::Error> {
|
||||||
|
// Read the configuraionfile if it exists
|
||||||
|
if ilovetv_config_file.exists() {
|
||||||
|
let config_file = Self::read_configfile(&ilovetv_config_file);
|
||||||
|
if let Ok(cfg) = config_file {
|
||||||
|
return Ok(cfg);
|
||||||
|
} else {
|
||||||
|
println!("There are some problem with the configurationfile");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get fresh config with url from user
|
||||||
|
let playlist_url = Self::user_setup();
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
playlist_filename: STANDARD_PLAYLIST_FILENAME.to_owned(),
|
||||||
|
playlist_url,
|
||||||
|
last_search: None,
|
||||||
|
seen_links_filename: STANDARD_SEEN_LINKS_FILENAME.to_owned(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_configfile(config_file: &Path) -> Result<Conf, io::Error> {
|
||||||
|
let reader = BufReader::new(File::open(config_file)?);
|
||||||
|
let conf: Conf = serde_json::from_reader(reader)?;
|
||||||
|
Ok(conf)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn user_setup() -> String {
|
||||||
|
let mut readline = Readline::new();
|
||||||
|
|
||||||
|
println!("Hello, I would need an url to your iptv/m3u/m3u8 stream");
|
||||||
|
loop {
|
||||||
|
let url = readline.input("enter url: ");
|
||||||
|
let yn = readline.input("Are you sure? (Y/n) ");
|
||||||
|
|
||||||
|
if yn.trim().to_lowercase() != "n" {
|
||||||
|
break url.trim().to_owned();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Configuration {
|
||||||
|
pub conf: Conf,
|
||||||
|
pub playlist_path: PathBuf,
|
||||||
|
pub seen_links_path: PathBuf,
|
||||||
|
pub seen_links: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Configuration {
|
||||||
|
pub fn new() -> Result<Self, io::Error> {
|
||||||
|
let project_dirs =
|
||||||
|
ProjectDirs::from(APP_IDENTIFIER[0], APP_IDENTIFIER[1], APP_IDENTIFIER[2]).unwrap();
|
||||||
|
let config_dir = project_dirs.config_dir();
|
||||||
|
let _ = fs::create_dir_all(config_dir);
|
||||||
|
let config_file = config_dir.join(JSON_CONFIG_FILENAME);
|
||||||
|
|
||||||
|
let configuration = Conf::new(&config_file)?;
|
||||||
|
|
||||||
|
fs::write(config_file, serde_json::to_string(&configuration).unwrap())?;
|
||||||
|
|
||||||
|
// Setup dirs for playlist
|
||||||
|
let cache_dir = project_dirs.cache_dir().to_path_buf();
|
||||||
|
let playlist_path = cache_dir.join(&configuration.playlist_filename);
|
||||||
|
let seen_links_path = cache_dir.join(&configuration.seen_links_filename);
|
||||||
|
let _ = fs::create_dir_all(&cache_dir);
|
||||||
|
|
||||||
|
let seen_links = Self::get_watched(&seen_links_path).unwrap_or_default();
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
conf: configuration,
|
||||||
|
playlist_path,
|
||||||
|
seen_links,
|
||||||
|
seen_links_path,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_watched(path: &Path) -> Option<Vec<String>> {
|
||||||
|
let reader = BufReader::new(File::open(&path).ok()?);
|
||||||
|
serde_json::from_reader(reader).ok()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn should_update_playlist(&self) -> bool {
|
||||||
|
fs::metadata(&self.playlist_path)
|
||||||
|
.and_then(|metadata| {
|
||||||
|
Ok({
|
||||||
|
let seconds = metadata.modified()?;
|
||||||
|
seconds
|
||||||
|
.elapsed()
|
||||||
|
.expect("Failed to get systemtime")
|
||||||
|
.as_secs()
|
||||||
|
> 60 * 60 * 24 * 3
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.map_or_else(
|
||||||
|
|_| {
|
||||||
|
println!("Could not find playlist-file, Downloading a new one");
|
||||||
|
false
|
||||||
|
},
|
||||||
|
|x| x,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
pub async fn get_playlist(&self) -> Result<String, String> {
|
||||||
|
let content = if let Some(content) = self.get_saved_playlist() {
|
||||||
|
content
|
||||||
|
} else {
|
||||||
|
let downloaded = self.download_playlist().await?;
|
||||||
|
if let Err(e) = fs::write(&self.playlist_path, &downloaded) {
|
||||||
|
println!(
|
||||||
|
"Failed to save downloaded playlist to file, {:?}, path: '{}'",
|
||||||
|
e,
|
||||||
|
&self.playlist_path.as_os_str().to_str().unwrap()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
downloaded
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(content)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_saved_playlist(&self) -> Option<String> {
|
||||||
|
if !self.should_update_playlist() {
|
||||||
|
return fs::read_to_string(&self.playlist_path).ok();
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn download_playlist(&self) -> Result<String, String> {
|
||||||
|
let mut counter: u8 = 0;
|
||||||
|
loop {
|
||||||
|
counter += 1;
|
||||||
|
|
||||||
|
if let Ok(content) = self.just_download().await {
|
||||||
|
break Ok(content);
|
||||||
|
} else if counter > MAX_TRIES {
|
||||||
|
break Err("Failed to download playlist".to_owned());
|
||||||
|
}
|
||||||
|
println!("Retrying {}/{}", counter + 1, MAX_TRIES);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn just_download(&self) -> Result<String, String> {
|
||||||
|
download_with_progress(&self.playlist_url, None)
|
||||||
|
.await?
|
||||||
|
.get_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deref for Configuration {
|
||||||
|
type Target = Conf;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.conf
|
||||||
|
}
|
||||||
|
}
|
39
src/lib.rs
39
src/lib.rs
@ -1,47 +1,14 @@
|
|||||||
mod m3u8;
|
mod m3u8;
|
||||||
mod parser;
|
mod parser;
|
||||||
use std::{
|
use std::io::{stdin, stdout, Stdin, StdoutLock, Write};
|
||||||
fs,
|
|
||||||
io::{stdin, stdout, Stdin, StdoutLock, Write},
|
|
||||||
process,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub use m3u8::M3u8;
|
pub use m3u8::M3u8;
|
||||||
pub use parser::Parser;
|
pub use parser::Parser;
|
||||||
mod config;
|
mod config;
|
||||||
|
pub use config::Configuration;
|
||||||
mod downloader;
|
mod downloader;
|
||||||
use directories::ProjectDirs;
|
|
||||||
pub use downloader::download_with_progress;
|
pub use downloader::download_with_progress;
|
||||||
|
|
||||||
pub fn setup() -> String {
|
|
||||||
let project_dirs = ProjectDirs::from("com", "billenius", "iptvnator_rs").unwrap();
|
|
||||||
let config_dir = project_dirs.config_dir();
|
|
||||||
let ilovetv_config_file = config_dir.join("iptv_url.txt");
|
|
||||||
if ilovetv_config_file.exists() {
|
|
||||||
return fs::read_to_string(&ilovetv_config_file).expect("Failed to read iptv_url");
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut readline = Readline::new();
|
|
||||||
|
|
||||||
println!("Hello, I would need an url to your iptv/m3u/m3u8 stream");
|
|
||||||
let url = loop {
|
|
||||||
let url = readline.input("enter url: ");
|
|
||||||
let yn = readline.input("Are you sure? (Y/n) ");
|
|
||||||
|
|
||||||
if yn.trim().to_lowercase() != "n" {
|
|
||||||
break url.trim().to_string();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let _ = fs::create_dir_all(config_dir);
|
|
||||||
if let Err(e) = fs::write(ilovetv_config_file, &url) {
|
|
||||||
eprintln!("{:?}", e);
|
|
||||||
process::exit(-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
url
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Readline<'a> {
|
pub struct Readline<'a> {
|
||||||
stdout: StdoutLock<'a>,
|
stdout: StdoutLock<'a>,
|
||||||
stdin: Stdin,
|
stdin: Stdin,
|
||||||
@ -66,7 +33,7 @@ impl<'a> Readline<'a> {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* I know that this isn't considered true rusty code, but the places it's used in is
|
* I know that this isn't considered true rusty code, but the places it's used in is
|
||||||
* safe. For this I'll leave the funciton as unsafe, so to better see it's uses.
|
* safe. For this I'll leave the funciton as unsafe, so to better see it's uses.
|
||||||
* This solution makes the uses BLAZINGLY FAST which moreover is the most rusty you can get.
|
* This solution makes the uses BLAZINGLY FAST which moreover is the most rusty you can get.
|
||||||
*/
|
*/
|
||||||
pub unsafe fn get_mut_ref<T>(reference: &T) -> &mut T {
|
pub unsafe fn get_mut_ref<T>(reference: &T) -> &mut T {
|
||||||
|
@ -3,7 +3,7 @@ use std::process::Command;
|
|||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use colored::Colorize;
|
use colored::Colorize;
|
||||||
use iptvnator::{download_with_progress, get_mut_ref, setup, M3u8, Parser, Readline};
|
use iptvnator::{download_with_progress, get_mut_ref, Configuration, M3u8, Parser, Readline};
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() {
|
async fn main() {
|
||||||
@ -17,7 +17,9 @@ async fn main() {
|
|||||||
"r".bold(),"q".bold(),"d".bold(),"s".bold(),"a".bold(), "f".bold()
|
"r".bold(),"q".bold(),"d".bold(),"s".bold(),"a".bold(), "f".bold()
|
||||||
);
|
);
|
||||||
|
|
||||||
let parser = Parser::new("iptv.m3u8".to_owned(), setup(), "watched.txt".to_owned()).await;
|
let config = Rc::new(Configuration::new().expect("Failed to write to configfile"));
|
||||||
|
|
||||||
|
let parser = Parser::new(config.clone()).await;
|
||||||
|
|
||||||
let mut mpv_fs = false;
|
let mut mpv_fs = false;
|
||||||
let mut search_result: Option<Rc<Vec<&M3u8>>> = None;
|
let mut search_result: Option<Rc<Vec<&M3u8>>> = None;
|
||||||
|
141
src/parser.rs
141
src/parser.rs
@ -1,36 +1,24 @@
|
|||||||
use std::path::PathBuf;
|
use std::fs;
|
||||||
|
use std::ops::Deref;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::{fs, process};
|
|
||||||
|
|
||||||
use directories::ProjectDirs;
|
|
||||||
|
|
||||||
use crate::downloader::download_with_progress;
|
|
||||||
use crate::m3u8::M3u8;
|
use crate::m3u8::M3u8;
|
||||||
|
use crate::Configuration;
|
||||||
|
|
||||||
const MAX_TRIES: usize = 4;
|
const MAX_TRIES: usize = 4;
|
||||||
|
|
||||||
pub struct Parser {
|
pub struct Parser {
|
||||||
watched_name: Rc<PathBuf>,
|
configuration: Rc<Configuration>,
|
||||||
m3u8_items: Vec<M3u8>,
|
m3u8_items: Vec<M3u8>,
|
||||||
ilovetv_url: Rc<String>,
|
|
||||||
file_name: Rc<PathBuf>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parser {
|
impl Parser {
|
||||||
pub async fn new(file_name: String, iptv_url: String, watched_name: String) -> Self {
|
pub async fn new(configuration: Rc<Configuration>) -> Self {
|
||||||
let project_dirs = ProjectDirs::from("com", "billenius", "iptvnator_rs").unwrap();
|
let m3u8_items = Self::get_parsed_m3u8(&configuration).await.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 {
|
Self {
|
||||||
watched_name: watched_name.clone(),
|
configuration,
|
||||||
m3u8_items: Self::get_parsed_content(&ilovetv_url, &file_name, &watched_name).await,
|
m3u8_items,
|
||||||
ilovetv_url,
|
|
||||||
file_name,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,42 +30,20 @@ impl Parser {
|
|||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn should_update(file_name: &PathBuf) -> bool {
|
|
||||||
fs::metadata(&file_name)
|
|
||||||
.and_then(|metadata| {
|
|
||||||
Ok({
|
|
||||||
let seconds = metadata.modified()?;
|
|
||||||
seconds
|
|
||||||
.elapsed()
|
|
||||||
.expect("Failed to get systemtime")
|
|
||||||
.as_secs()
|
|
||||||
> 60 * 60 * 24 * 3
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.map_or_else(
|
|
||||||
|_| {
|
|
||||||
println!("Could not find playlist-file, Downloading a new one");
|
|
||||||
false
|
|
||||||
},
|
|
||||||
|x| x,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn forcefully_update(&mut self) {
|
pub async fn forcefully_update(&mut self) {
|
||||||
let mut counter = 0;
|
let mut counter = 0;
|
||||||
let content = loop {
|
let content = loop {
|
||||||
counter += 1;
|
counter += 1;
|
||||||
let content = Self::download(&self.ilovetv_url).await.ok();
|
let content = self.download_playlist().await;
|
||||||
if counter > MAX_TRIES {
|
if counter > MAX_TRIES {
|
||||||
return;
|
return;
|
||||||
} else if content.is_some() {
|
} else if content.is_ok() {
|
||||||
break content.unwrap();
|
break content.unwrap();
|
||||||
}
|
}
|
||||||
println!("Retrying {}/{}", counter, MAX_TRIES);
|
println!("Retrying {}/{}", counter, MAX_TRIES);
|
||||||
};
|
};
|
||||||
|
|
||||||
let _ = fs::write(&*self.file_name, &content);
|
self.m3u8_items = Self::parse_m3u8(content, &self.seen_links);
|
||||||
self.m3u8_items = Self::parse_m3u8(content, &self.watched_name.clone());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn save_watched(&self) {
|
pub fn save_watched(&self) {
|
||||||
@ -88,36 +54,17 @@ impl Parser {
|
|||||||
.map(|item| item.link.clone())
|
.map(|item| item.link.clone())
|
||||||
.collect::<Vec<String>>();
|
.collect::<Vec<String>>();
|
||||||
|
|
||||||
let _ = fs::create_dir_all(&*self.watched_name.parent().unwrap());
|
let resp = fs::write(
|
||||||
|
&self.seen_links_path,
|
||||||
if let Err(e) = fs::write(&*self.watched_name, watched_items.join("\n")) {
|
serde_json::to_string(&watched_items).unwrap(),
|
||||||
|
);
|
||||||
|
|
||||||
|
if let Err(e) = resp {
|
||||||
eprintln!("Failed to write watched links {:?}", e);
|
eprintln!("Failed to write watched links {:?}", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_parsed_content(
|
fn parse_m3u8(content: String, watched_links: &Vec<String>) -> Vec<M3u8> {
|
||||||
link: &String,
|
|
||||||
file_name: &PathBuf,
|
|
||||||
watched_name: &PathBuf,
|
|
||||||
) -> Vec<M3u8> {
|
|
||||||
Self::parse_m3u8(
|
|
||||||
Self::get_stringcontent(link, file_name)
|
|
||||||
.await
|
|
||||||
.expect("Failed to retrieve playlist"),
|
|
||||||
watched_name,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_m3u8(content: String, watched_name: &PathBuf) -> Vec<M3u8> {
|
|
||||||
let saved_watches = fs::read_to_string(&watched_name);
|
|
||||||
let saved_watches = if saved_watches.is_ok() {
|
|
||||||
saved_watches.unwrap()
|
|
||||||
} else {
|
|
||||||
String::from("")
|
|
||||||
};
|
|
||||||
|
|
||||||
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> = content
|
let interesting_lines: Vec<String> = content
|
||||||
.replacen("#EXTM3U\n", "", 1)
|
.replacen("#EXTM3U\n", "", 1)
|
||||||
@ -139,7 +86,7 @@ impl Parser {
|
|||||||
let name_start = interesting_lines[i].rfind(",").unwrap() + 1;
|
let name_start = interesting_lines[i].rfind(",").unwrap() + 1;
|
||||||
let name = &interesting_lines[i][name_start..];
|
let name = &interesting_lines[i][name_start..];
|
||||||
let link = &interesting_lines[i + 1];
|
let link = &interesting_lines[i + 1];
|
||||||
let is_watched = watched.contains(link);
|
let is_watched = watched_links.contains(link);
|
||||||
let m3u8_item = M3u8 {
|
let m3u8_item = M3u8 {
|
||||||
tvg_id: items[0].to_owned(),
|
tvg_id: items[0].to_owned(),
|
||||||
tvg_name: items[1].to_owned(),
|
tvg_name: items[1].to_owned(),
|
||||||
@ -154,42 +101,18 @@ impl Parser {
|
|||||||
m3u8_items
|
m3u8_items
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_stringcontent(link: &String, file_name: &PathBuf) -> Result<String, String> {
|
async fn get_parsed_m3u8(config: &Configuration) -> Result<Vec<M3u8>, String> {
|
||||||
if !Self::should_update(file_name) {
|
Ok(Self::parse_m3u8(
|
||||||
let content = fs::read_to_string(&file_name);
|
config.get_playlist().await?,
|
||||||
if content.is_ok() {
|
&config.seen_links,
|
||||||
return Ok(content.unwrap());
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut counter: usize = 0;
|
impl Deref for Parser {
|
||||||
let content = loop {
|
type Target = Configuration;
|
||||||
counter += 1;
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
if let Ok(content) = Self::download(link).await {
|
&self.configuration
|
||||||
break Ok(content);
|
|
||||||
} else if counter > MAX_TRIES {
|
|
||||||
break Err("".to_owned());
|
|
||||||
}
|
|
||||||
println!("Retrying {}/{}", counter + 1, MAX_TRIES);
|
|
||||||
};
|
|
||||||
|
|
||||||
match content {
|
|
||||||
Ok(s) => {
|
|
||||||
let _ = fs::write(&file_name, s.as_bytes());
|
|
||||||
Ok(s)
|
|
||||||
}
|
|
||||||
Err(_) => {
|
|
||||||
println!("Couldn't get m3u8 file!");
|
|
||||||
process::exit(-1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn download(link: &String) -> Result<String, String> {
|
|
||||||
Ok(download_with_progress(link, None)
|
|
||||||
.await?
|
|
||||||
.get_string()
|
|
||||||
.unwrap())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user