mirror of
https://github.com/euzu/tuliprox.git
synced 2026-10-09 09:22:18 +02:00
some xtream refactorings
This commit is contained in:
@@ -149,6 +149,10 @@ pub(crate) struct UserApiRequest {
|
||||
pub token: String,
|
||||
#[serde(default = "default_as_empty_str")]
|
||||
pub action: String,
|
||||
#[serde(default = "default_as_empty_str")]
|
||||
pub series_id: String,
|
||||
#[serde(default = "default_as_empty_str")]
|
||||
pub vod_id: String,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize, Debug, Clone)]
|
||||
|
||||
@@ -19,11 +19,9 @@ pub(crate) async fn serve_file(file_path: &Path, req: &HttpRequest) -> HttpRespo
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn get_user_target<'a>(api_req: &'a web::Query<UserApiRequest>, app_state: &'a web::Data<AppState>) -> Option<(UserCredentials, &'a ConfigTarget)> {
|
||||
let username = api_req.username.as_str().trim();
|
||||
let password = api_req.password.as_str().trim();
|
||||
pub(crate) fn get_user_target_by_credentials<'a>(username: &str, password: &str, api_req: &'a web::Query<UserApiRequest>, app_state: &'a web::Data<AppState>) -> Option<(UserCredentials, &'a ConfigTarget)> {
|
||||
if !username.is_empty() && !password.is_empty() {
|
||||
app_state.config.get_target_for_user(username, password)
|
||||
app_state.config.get_target_for_user(username, password)
|
||||
} else {
|
||||
let token = api_req.token.as_str().trim();
|
||||
if !token.is_empty() {
|
||||
@@ -32,4 +30,11 @@ pub(crate) fn get_user_target<'a>(api_req: &'a web::Query<UserApiRequest>, app_s
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub(crate) fn get_user_target<'a>(api_req: &'a web::Query<UserApiRequest>, app_state: &'a web::Data<AppState>) -> Option<(UserCredentials, &'a ConfigTarget)> {
|
||||
let username = api_req.username.as_str().trim();
|
||||
let password = api_req.password.as_str().trim();
|
||||
get_user_target_by_credentials(username, password, api_req, app_state)
|
||||
}
|
||||
+4
-3
@@ -32,8 +32,9 @@ pub(crate) async fn start_server(cfg: Arc<Config>, targets: Arc<ProcessTargets>)
|
||||
let port = cfg.api.port;
|
||||
let web_dir = cfg.api.web_root.to_string();
|
||||
let web_dir_path = PathBuf::from(&web_dir);
|
||||
if !web_dir_path.exists() || !web_dir_path.is_dir() {
|
||||
return Err(std::io::Error::new(ErrorKind::NotFound, format!("web_root does not exists or is not an directory: {:?}", &web_dir_path)));
|
||||
if !&web_dir_path.exists() || !&web_dir_path.is_dir() {
|
||||
return Err(std::io::Error::new(ErrorKind::NotFound,
|
||||
format!("web_root does not exists or is not an directory: {:?}", &web_dir_path)));
|
||||
}
|
||||
|
||||
let schedule = cfg.schedule.clone();
|
||||
@@ -72,7 +73,7 @@ pub(crate) async fn start_server(cfg: Arc<Config>, targets: Arc<ProcessTargets>)
|
||||
.service(m3u_api_register())
|
||||
.service(xmltv_api_register())
|
||||
.service(index)
|
||||
.service(actix_files::Files::new("/", web_dir.to_string()))
|
||||
.service(actix_files::Files::new("/", &web_dir_path))
|
||||
)
|
||||
.bind(format!("{}:{}", host, port))?
|
||||
.run().await
|
||||
|
||||
+116
-17
@@ -1,15 +1,18 @@
|
||||
// https://github.com/tellytv/go.xtream-codes/blob/master/structs.go
|
||||
|
||||
use std::io::Error;
|
||||
use std::str::FromStr;
|
||||
use actix_web::{HttpRequest, HttpResponse, web, Resource};
|
||||
use chrono::{Duration, Local};
|
||||
use log::debug;
|
||||
|
||||
use crate::api::api_utils::{get_user_target, serve_file};
|
||||
use crate::api::api_utils::{get_user_target, get_user_target_by_credentials, serve_file};
|
||||
use crate::api::api_model::{AppState, UserApiRequest, XtreamAuthorizationResponse, XtreamServerInfo, XtreamUserInfo};
|
||||
use crate::model::api_proxy::{UserCredentials};
|
||||
use crate::model::config::Config;
|
||||
use crate::model::config::{Config};
|
||||
use crate::model::model_config::{TargetType};
|
||||
use crate::repository::xtream_repository::{COL_CAT_LIVE, COL_CAT_SERIES, COL_CAT_VOD, COL_LIVE, COL_SERIES, COL_VOD, xtream_get_all};
|
||||
use crate::repository::xtream_repository::{COL_CAT_LIVE, COL_CAT_SERIES, COL_CAT_VOD, COL_LIVE, COL_SERIES, COL_VOD, xtream_get_all, xtream_get_series_info, xtream_get_vod_info};
|
||||
use crate::utils::get_client_request;
|
||||
|
||||
fn get_user_info(user: &UserCredentials, cfg: &Config) -> XtreamAuthorizationResponse {
|
||||
let server = cfg._api_proxy.read().unwrap().as_ref().unwrap().server.clone();
|
||||
@@ -41,6 +44,65 @@ fn get_user_info(user: &UserCredentials, cfg: &Config) -> XtreamAuthorizationRes
|
||||
}
|
||||
}
|
||||
|
||||
async fn xtream_player_api_stream(
|
||||
api_req: &web::Query<UserApiRequest>,
|
||||
_app_state: &web::Data<AppState>,
|
||||
context: &str,
|
||||
username: &str,
|
||||
password: &str,
|
||||
stream_id: &str,
|
||||
) -> HttpResponse {
|
||||
if let Some((_user, target)) = get_user_target_by_credentials(&username, &password, api_req, _app_state) {
|
||||
let target_name = &target.name;
|
||||
if target.has_output(&TargetType::Xtream) {
|
||||
match _app_state.config.get_xtream_input_for_target(target_name) {
|
||||
None => {}
|
||||
Some(input) => {
|
||||
let username = input.username.as_ref().unwrap().clone();
|
||||
let password = input.password.as_ref().unwrap().clone();
|
||||
let stream_url = format!("{}/{}/{}/{}/{}", input.url, context, username, password, stream_id);
|
||||
let url = reqwest::Url::parse(&stream_url).unwrap();
|
||||
let client = get_client_request(input, url);
|
||||
if let Ok(response) = client.send().await {
|
||||
if response.status().is_success() {
|
||||
return HttpResponse::Ok().streaming(response.bytes_stream());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
HttpResponse::BadRequest().finish()
|
||||
}
|
||||
|
||||
async fn xtream_player_api_live_stream(
|
||||
api_req: web::Query<UserApiRequest>,
|
||||
path: web::Path<(String, String, String)>,
|
||||
_app_state: web::Data<AppState>,
|
||||
) -> HttpResponse {
|
||||
let (username, password, stream_id) = path.into_inner();
|
||||
xtream_player_api_stream(&api_req, &_app_state, "live", &username, &password, &stream_id).await
|
||||
}
|
||||
|
||||
async fn xtream_player_api_series_stream(
|
||||
api_req: web::Query<UserApiRequest>,
|
||||
path: web::Path<(String, String, String)>,
|
||||
_app_state: web::Data<AppState>,
|
||||
) -> HttpResponse {
|
||||
let (username, password, stream_id) = path.into_inner();
|
||||
xtream_player_api_stream(&api_req, &_app_state, "series", &username, &password, &stream_id).await
|
||||
}
|
||||
|
||||
async fn xtream_player_api_movie_stream(
|
||||
api_req: web::Query<UserApiRequest>,
|
||||
path: web::Path<(String, String, String)>,
|
||||
_app_state: web::Data<AppState>,
|
||||
) -> HttpResponse {
|
||||
let (username, password, stream_id) = path.into_inner();
|
||||
xtream_player_api_stream(&api_req, &_app_state, "movie", &username, &password, &stream_id).await
|
||||
}
|
||||
|
||||
|
||||
async fn xtream_player_api(
|
||||
api_req: web::Query<UserApiRequest>,
|
||||
req: HttpRequest,
|
||||
@@ -54,21 +116,55 @@ async fn xtream_player_api(
|
||||
if action.is_empty() {
|
||||
return HttpResponse::Ok().json(get_user_info(&user, &_app_state.config));
|
||||
}
|
||||
match match action {
|
||||
"get_live_categories" => xtream_get_all(&_app_state.config, target_name, COL_CAT_LIVE),
|
||||
"get_vod_categories" => xtream_get_all(&_app_state.config, target_name, COL_CAT_VOD),
|
||||
"get_series_categories" => xtream_get_all(&_app_state.config, target_name, COL_CAT_SERIES),
|
||||
"get_live_streams" => xtream_get_all(&_app_state.config, target_name, COL_LIVE),
|
||||
"get_vod_streams" => xtream_get_all(&_app_state.config, target_name, COL_VOD),
|
||||
"get_series" => xtream_get_all(&_app_state.config, target_name, COL_SERIES),
|
||||
_ => Err(std::io::Error::new(std::io::ErrorKind::Unsupported, format!("Cant find action: {}/{}", target_name, action))),
|
||||
} {
|
||||
Ok(file_path) => {
|
||||
serve_file(&file_path, &req).await
|
||||
|
||||
match action {
|
||||
"get_series_info" => {
|
||||
match FromStr::from_str(api_req.series_id.trim()) {
|
||||
Ok(stream_id) => {
|
||||
match xtream_get_series_info(&_app_state.config, target_name, stream_id) {
|
||||
Ok(content) => HttpResponse::Ok().content_type(mime::APPLICATION_JSON).body(content),
|
||||
Err(_) => HttpResponse::NoContent().finish()
|
||||
}
|
||||
}
|
||||
Err(_) => HttpResponse::BadRequest().finish()
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
debug!("Could not open file for xtream target: {} {}", target_name, err);
|
||||
HttpResponse::NoContent().finish()
|
||||
"get_vod_info" => {
|
||||
match FromStr::from_str(api_req.vod_id.trim()) {
|
||||
Ok(stream_id) => {
|
||||
match xtream_get_vod_info(&_app_state.config, target_name, stream_id) {
|
||||
Ok(content) => HttpResponse::Ok().content_type(mime::APPLICATION_JSON).body(content),
|
||||
Err(_) => HttpResponse::NoContent().finish()
|
||||
}
|
||||
}
|
||||
Err(_) => HttpResponse::BadRequest().finish()
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
match match action {
|
||||
"get_live_categories" => xtream_get_all(&_app_state.config, target_name, COL_CAT_LIVE),
|
||||
"get_vod_categories" => xtream_get_all(&_app_state.config, target_name, COL_CAT_VOD),
|
||||
"get_series_categories" => xtream_get_all(&_app_state.config, target_name, COL_CAT_SERIES),
|
||||
"get_live_streams" => xtream_get_all(&_app_state.config, target_name, COL_LIVE),
|
||||
"get_vod_streams" => xtream_get_all(&_app_state.config, target_name, COL_VOD),
|
||||
"get_series" => xtream_get_all(&_app_state.config, target_name, COL_SERIES),
|
||||
_ => Err(Error::new(std::io::ErrorKind::Unsupported, format!("Cant find action: {}/{}", target_name, action))),
|
||||
} {
|
||||
Ok(maybe_file_path_or_content) => {
|
||||
let (path, content) = maybe_file_path_or_content;
|
||||
if let Some(file_path) = path {
|
||||
serve_file(&file_path, &req).await
|
||||
} else if let Some(payload) = content {
|
||||
HttpResponse::Ok().body(payload)
|
||||
} else {
|
||||
HttpResponse::NoContent().finish()
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
debug!("Could not open file for xtream target: {} {}", target_name, err);
|
||||
HttpResponse::NoContent().finish()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -92,5 +188,8 @@ pub(crate) fn xtream_api_register() -> Vec<Resource> {
|
||||
vec![
|
||||
web::resource("/player_api.php").route(web::get().to(xtream_player_api)),
|
||||
web::resource("/xtream").route(web::get().to(xtream_player_api)),
|
||||
web::resource("/live/{username}/{password}/{stream_id}").route(web::get().to(xtream_player_api_live_stream)),
|
||||
web::resource("/movie/{username}/{password}/{stream_id}").route(web::get().to(xtream_player_api_movie_stream)),
|
||||
web::resource("/series/{username}/{password}/{stream_id}").route(web::get().to(xtream_player_api_series_stream)),
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user