From ec7ed1213397a8fd00d23a0d984f821ee5612103 Mon Sep 17 00:00:00 2001 From: Zastian Pretorius Date: Sat, 9 Jul 2022 23:40:18 +0100 Subject: [PATCH] Added anime support --- Cargo.lock | 7 ++ Cargo.toml | 3 +- src/main.rs | 185 ++++++++++++++++++++++++++++++++++++++++++++++------ 3 files changed, 173 insertions(+), 22 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 104e9c5..433b680 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -39,6 +39,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "base64" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" + [[package]] name = "bytes" version = "1.1.0" @@ -317,6 +323,7 @@ dependencies = [ name = "log_e" version = "0.2.0" dependencies = [ + "base64", "colored", "isahc", "regex", diff --git a/Cargo.toml b/Cargo.toml index 30fed42..0bb0975 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "log_e" -author = "mrfluffy-dev" +#author = "mrfluffy-dev" license = "GPL-3.0" version = "0.2.0" edition = "2021" @@ -11,3 +11,4 @@ edition = "2021" regex = "1.5.6" colored = "2.0.0" isahc = "1.7.2" +base64 = "0.13" diff --git a/src/main.rs b/src/main.rs index d6de429..5063dc6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,28 +3,83 @@ use std::vec::Vec; use std::fs::File; use std::io::prelude::*; use colored::Colorize; -use isahc::prelude::*; +use isahc::{prelude::*,Request}; use std::process::{Command, ExitStatus}; use std::io::Result; +use base64::{encode, decode}; fn main() { - let ln_url = search_ln(); - let mut selected_page = 1; - loop { - //make empty tuple called chapter_url with (String, u32, u32) - let chapter_url = chapter_selector(&ln_url, selected_page); - selected_page = chapter_url.1; - let full_text = get_full_text(&chapter_url.0); - //write full_text to file called temp.txt - let mut file = File::create("/tmp/log_e").expect("Unable to create file"); - file.write_all(full_text.as_bytes()).expect("Unable to write to file"); - //close file - file.sync_all().expect("Unable to sync file"); - //open temp.txt in cat for user to read - let _com = open_bat(); + let mut _arg = String::new(); + if std::env::args().len() > 1 { + _arg = std::env::args().nth(1).unwrap(); + } else { + println!("argument a\t:anime"); + println!("argument l\t:light novel"); + //kill the program + std::process::exit(0); + } + if _arg == "l"{ + let ln_url = search_ln(); + let mut selected_page = 1; + loop { + //make empty tuple called chapter_url with (String, u32, u32) + let chapter_url = chapter_selector(&ln_url, selected_page); + selected_page = chapter_url.1; + let full_text = get_full_text(&chapter_url.0); + //write full_text to file called temp.txt + let mut file = File::create("/tmp/log_e").expect("Unable to create file"); + file.write_all(full_text.as_bytes()).expect("Unable to write to file"); + //close file + file.sync_all().expect("Unable to sync file"); + //open temp.txt in cat for user to read + let _com = open_bat(); + print!("\x1B[2J\x1B[1;1H"); + } + } + else if _arg == "a" { + let mut query = String::new(); + if std::env::args().len() > 2 { + query = std::env::args().nth(1).unwrap(); + } else { + print!("\x1B[2J\x1B[1;1H"); + println!("Enter query: "); + std::io::stdin().read_line(&mut query).unwrap(); + query = query.trim().to_string(); + } + let anime_list = anime_names(&query); + let mut count = 0; print!("\x1B[2J\x1B[1;1H"); + for anime in &anime_list{ + if count % 2 == 0 { + println!("({})\t{}",format!("{}",count.to_string().blue()), format!("{}", anime.blue())); + } else { + println!("({})\t{}",format!("{}",count.to_string().yellow()), format!("{}", anime.yellow())); + } + count += 1; + } + println!("Enter anime number: "); + let mut anime_num = String::new(); + std::io::stdin().read_line(&mut anime_num).expect("Failed to read line"); + + // convert anime_num to u16 + let anime_num = anime_num.trim().to_string(); + let anime_num = anime_num.parse::().unwrap(); + + //let num: u16 = anime_num.parse().unwrap(); + let title = &anime_list[anime_num]; + let ep_range = anime_ep_range(&title); + println!("select episode 0-{}: ",ep_range); + let mut ep_num = String::new(); + std::io::stdin().read_line(&mut ep_num).expect("Failed to read line"); + let ep_num = ep_num.trim().to_string(); + let ep_num = ep_num.trim().parse::().unwrap(); + let command = anime_link(&title,ep_num); + open_mp3(command); + } + else { + println!("Invalid argument"); } } - +// light novel stuff fn search_ln()->String{ let mut _is_n = false; print!("\x1B[2J\x1B[1;1H"); @@ -109,7 +164,8 @@ fn chapter_selector(ln_url: &String, mut selected_page: u32)->(String, u32){ let chaprer_number = chaprer_number.parse::().unwrap(); let chaprer_url = &ln_chapters_urls[chaprer_number]; let chaprer_url = chaprer_url.trim().to_string(); - return (chaprer_url, selected_page); } + return (chaprer_url, selected_page); + } } return ("".to_string(),1); } @@ -130,9 +186,14 @@ pub fn open_bat() -> Result { //gets the full html of the page fn get_html(url: &str) -> String { - let mut resp = isahc::get(url).unwrap(); - let html = resp.text().unwrap(); + let req = Request::builder() + .uri(url) + .header("user-agent","Mozilla/5.0 (X11; Linux x86_64; rv:99.0) Gecko/20100101 Firefox/100.0") + .body(()) + .unwrap(); + let html = req.send().unwrap().text().unwrap(); html + } //gets the list of ln's from the html and returns it as a vector of the ln's name and href fn get_ln_list(html: &str) -> Vec { @@ -282,8 +343,14 @@ fn get_ln_id(html: &str) -> String { fn get_ln_next_page(ln_id: &str, page: &str) -> String { let url = "https://readlightnovels.net/wp-admin/admin-ajax.php".to_string(); let form = format!("action=tw_ajax&type=pagination&id={}.html&page={}", ln_id, page); - let mut resp = isahc::post(url,form).unwrap(); - let html = resp.text().unwrap(); + //let mut resp = isahc::post(&url,form).unwrap(); + let req = Request::builder() + .method("POST") + .uri(url) + .header("user-agent", "Mozilla/5.0 (X11; Linux x86_64; rv:99.0) Gecko/20100101 Firefox/100.0") + .body(form) + .unwrap(); + let html = req.send().unwrap().text().unwrap(); html } @@ -305,3 +372,79 @@ fn get_ln_text(chapter_url: &str) -> Vec { let ln_text = fix_html_encoding(&ln_text); ln_text } + + + + +//anime stuff + + +fn anime_names(query: &str) -> Vec { + let url = format!("https://gogoanime.lu//search.html?keyword={}",query); + //relpace all spaces with %20 + let url = url.replace(" ","%20"); + let html = get_anime_html(&url); + let re = Regex::new(r#"(?m)/category/([^"]*)"#).unwrap(); + let mut anime_list:Vec = Vec::new(); + for cap in re.captures_iter(&html) { + anime_list.push(cap.get(1).unwrap().as_str().trim().to_string()); + } + anime_list.dedup(); + + anime_list +} + +fn anime_ep_range(anime_name: &str) -> u16{ + let url = format!("https://gogoanime.lu/category/{}",anime_name); + let re = Regex::new(r#"(?m)\s"#).unwrap(); + let episodes = re.captures_iter(&get_anime_html(&url)).next().unwrap().get(1).unwrap().as_str().trim().to_string(); + episodes.split("-").nth(1).unwrap_or("0").parse::().unwrap_or(0) +} + +fn anime_link(title: &str, ep: u16) -> (String,String) { + let url = format!("https://animixplay.to/v1/{}",title); + let html = get_anime_html(&url); + let re = Regex::new(r#"(?m)\?id=([^&]+)"#).unwrap(); + let id1 = re.captures_iter(&html).nth(ep as usize - 1).unwrap().get(1).unwrap().as_str().trim().to_string(); + let title = format!("{} episode {}",title.replace("-"," "),ep); + let encoded_id1 = encode(&id1); + let anime_id = encode(format!("{}LTXs3GrU8we9O{}",id1,encoded_id1)); + let html = format!("https://animixplay.to/api/live{}",anime_id); + let url = get_ep_location(&html); + let url = url.split("#").nth(1).unwrap(); + let url = format!("{}",std::str::from_utf8(&decode(url).unwrap()).unwrap()); + (url,title) +} + + + +fn get_anime_html(url: &str) -> String { + let req = Request::builder() + .uri(url) + .header("user-agent","Mozilla/5.0 (X11; Linux x86_64; rv:99.0) Gecko/20100101 Firefox/100.0") + .body(()) + .unwrap(); + let html = req.send().unwrap().text().unwrap(); + html +} +fn get_ep_location(url: &str) -> String { + let request = Request::builder() + .method("HEAD") + .uri(url) + .header("user-agent", "Mozilla/5.0 (X11; Linux x86_64; rv:99.0) Gecko/20100101 Firefox/100.0") + .body(()) + .unwrap(); + let response = request.send().unwrap(); + let headers = response.headers(); + let location = headers.get("location").unwrap(); + location.to_str().unwrap().to_string() +} + + +#[allow(unused)] +pub fn open_mp3(command: (String,String)) { + Command::new("mpv") + .arg(command.0) + .arg(command.1) + .spawn(); +}