Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hianime streamtape server #10

Merged
merged 12 commits into from
Sep 16, 2024
36 changes: 27 additions & 9 deletions src/hianime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use crate::{
env::{self, EnvVar, SecretConfig},
error::AniRustError,
proxy::{load_proxies, Proxy},
servers::{AnimeServer, EpisodeType, MegaCloudServer},
servers::{AnimeServer, EpisodeType, MegaCloudServer, ServerExtractedInfo, StreamTapeServer},
utils::{anirust_error_vec_to_string, get_ajax_curl, get_curl},
};

Expand Down Expand Up @@ -576,19 +576,24 @@ impl HiAnimeRust {
id: &str,
episode_type: EpisodeType,
anime_server: Option<AnimeServer>,
) -> Result<(), AniRustError> {
) -> Result<ServerExtractedInfo, AniRustError> {
let server_list = self.scrape_servers(id).await?;
let mut error_vec = vec![];
let mut link = String::new();

let mut server_id: u32 = 0;
let mut data_id: u32 = 0;

match episode_type {
EpisodeType::Dub => update_server_id(&mut server_id, server_list.dub, anime_server),
_ => update_server_id(&mut server_id, server_list.sub, anime_server),
EpisodeType::Dub => {
update_server_id(&mut server_id, &mut data_id, server_list.dub, anime_server)
}
_ => update_server_id(&mut server_id, &mut data_id, server_list.sub, anime_server),
}

for domain in &self.domains {
let url = format!("{}/ajax/v2/episode/sources?id={}", domain, server_id);
let url = format!("{}/ajax/v2/episode/sources?id={}", domain, data_id);
println!("{:?}", url);

match get_ajax_curl(&url, "link").await {
Ok(curl_string) => {
Expand All @@ -605,9 +610,16 @@ impl HiAnimeRust {
let error_string: String = anirust_error_vec_to_string(error_vec);
return Err(AniRustError::UnknownError(error_string));
}
println!("{:?}", MegaCloudServer::extract(&link, &self.proxies).await);

Ok(())
let server_info = match server_id {
3 => StreamTapeServer::extract(&link, &self.proxies).await?,
4 => MegaCloudServer::extract(&link, &self.proxies).await?,
5 => MegaCloudServer::extract(&link, &self.proxies).await?,
1 => MegaCloudServer::extract(&link, &self.proxies).await?,
_ => MegaCloudServer::extract(&link, &self.proxies).await?,
};

Ok(server_info)
}
}

Expand Down Expand Up @@ -1393,14 +1405,20 @@ fn initialize_secret(secret: Option<SecretConfig>) -> Option<SecretConfig> {
secret_clone
}

fn update_server_id(server_id: &mut u32, servers: Vec<Server>, anime_server: Option<AnimeServer>) {
fn update_server_id(
server_id: &mut u32,
data_id: &mut u32,
servers: Vec<Server>,
anime_server: Option<AnimeServer>,
) {
let anime_server = anime_server.unwrap_or(AnimeServer::Vidstreaming);

for server in servers {
println!("{} - {}", server.server_name, anime_server.as_str());
if server.server_name == anime_server.as_str() {
*server_id = server.server_id;
*data_id = server.data_id;
return;
}
}
}
}
93 changes: 73 additions & 20 deletions src/servers.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
use regex::Regex;
use scraper::Html;
use serde::{Deserialize, Serialize};
use serde_json::Value;

use crate::{
error::AniRustError,
proxy::Proxy,
utils::{decrypt_aes_256_cbc, get_curl},
utils::{anirust_error_vec_to_string, decrypt_aes_256_cbc, get_curl},
};
use std::time::{SystemTime, UNIX_EPOCH};

Expand All @@ -30,27 +31,23 @@ impl Default for IntroOutro {
}

#[derive(Debug, Serialize, Deserialize)]
pub struct UnencryptedSrc {
pub struct MegaCloudUnencryptedSrc {
pub file: String,
pub src_type: String,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct ExtractedSrc {
pub sources: Vec<UnencryptedSrc>,
pub tracks: Vec<Track>,
pub encrypted: bool,
pub struct MegaCloudExtractedData {
pub intro: IntroOutro,
pub outro: IntroOutro,
pub server: u32,
pub tracks: Vec<Track>,
pub sources: Vec<Source>,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct ExtractedData {
pub intro: IntroOutro,
pub outro: IntroOutro,
pub tracks: Vec<Track>,
pub sources: Vec<Source>,
pub struct StreamTapeExtractedData {
pub url: String,
pub is_m3u8: bool,
}

#[derive(Debug, Serialize, Deserialize)]
Expand Down Expand Up @@ -127,15 +124,22 @@ impl EpisodeType {
}
}

#[derive(Debug, Serialize, Deserialize)]
pub enum ServerExtractedInfo {
MegaCloud(MegaCloudExtractedData),
StreamTape(StreamTapeExtractedData),
}

pub struct MegaCloudServer;

impl MegaCloudServer {
pub async fn extract(
video_url: &str,
proxies: &[Proxy],
) -> Result<ExtractedData, AniRustError> {
) -> Result<ServerExtractedInfo, AniRustError> {
let video_id = extract_video_id(video_url);
let json_data = fetch_initial_data(&video_id, proxies).await?;
let url = format!("{}{}", MEGACLOUD.sources, video_id);
let json_data = fetch_initial_data(&url, proxies).await?;

let is_encrypted = json_data["encrypted"].as_bool().unwrap_or(false);
let intro: IntroOutro = parse_json_field(&json_data, "intro").unwrap_or_default();
Expand All @@ -150,12 +154,62 @@ impl MegaCloudServer {
parse_json_field(&json_data, "sources")?
};

Ok(ExtractedData {
Ok(ServerExtractedInfo::MegaCloud(MegaCloudExtractedData {
intro,
outro,
tracks,
sources,
})
}))
}
}

pub struct StreamTapeServer;

impl StreamTapeServer {
pub async fn extract(
video_url: &str,
proxies: &[Proxy],
) -> Result<ServerExtractedInfo, AniRustError> {
let mut error_vec = vec![];
let mut curl = String::new();

match get_curl(video_url, proxies).await {
Ok(curl_string) => {
curl = curl_string;
}
Err(e) => {
error_vec.push(Some(e));
}
}

if curl.is_empty() {
let error_string = anirust_error_vec_to_string(error_vec);
return Err(AniRustError::UnknownError(error_string));
}

let document = Html::parse_document(&curl);

let re = Regex::new(r"robotlink'\).innerHTML = (.*)'").unwrap();
let html = document.root_element().html();

if let Some(captures) = re.captures(&html) {
if let Some(matched) = captures.get(1) {
let parts: Vec<&str> = matched.as_str().split("+ ('").collect();
if parts.len() == 2 {
let fh = parts[0].replace('\'', "");
let mut sh = parts[1].to_string();
sh = sh[3..].to_string();

let url = format!("https:{}{}", fh, sh);
return Ok(ServerExtractedInfo::StreamTape(StreamTapeExtractedData {
url: url.clone(),
is_m3u8: url.contains(".m3u8"),
}));
}
}
}

Err(AniRustError::FailedToFetchAfterRetries)
}
}

Expand Down Expand Up @@ -270,9 +324,8 @@ fn extract_video_id(video_url: &str) -> String {
.to_string()
}

async fn fetch_initial_data(video_id: &str, proxies: &[Proxy]) -> Result<Value, AniRustError> {
let url = format!("{}{}", MEGACLOUD.sources, video_id);
let response = get_curl(&url, proxies).await?;
async fn fetch_initial_data(url: &str, proxies: &[Proxy]) -> Result<Value, AniRustError> {
let response = get_curl(url, proxies).await?;
serde_json::from_str(&response).map_err(|e| AniRustError::UnknownError(e.to_string()))
}

Expand Down Expand Up @@ -322,4 +375,4 @@ async fn decrypt_sources(
fn parse_sources(decrypted: &str) -> Result<Vec<Source>, AniRustError> {
serde_json::from_str(decrypted)
.map_err(|e| AniRustError::UnknownError(format!("Failed to parse sources: {}", e)))
}
}