mirror of
https://github.com/crunchy-labs/crunchy-cli.git
synced 2026-01-21 04:02:00 -06:00
Add option so specify different proxies for api and download requests (#282)
This commit is contained in:
parent
f1d266c940
commit
e3a7fd9246
2 changed files with 85 additions and 38 deletions
|
|
@ -61,9 +61,10 @@ pub struct Cli {
|
|||
|
||||
#[arg(help = "Use a proxy to route all traffic through")]
|
||||
#[arg(long_help = "Use a proxy to route all traffic through. \
|
||||
Make sure that the proxy can either forward TLS requests, which is needed to bypass the (cloudflare) bot protection, or that it is configured so that the proxy can bypass the protection itself")]
|
||||
#[arg(global = true, long, value_parser = crate::utils::clap::clap_parse_proxy)]
|
||||
proxy: Option<Proxy>,
|
||||
Make sure that the proxy can either forward TLS requests, which is needed to bypass the (cloudflare) bot protection, or that it is configured so that the proxy can bypass the protection itself. \
|
||||
Besides specifying a simple url, you also can partially control where a proxy should be used: '<url>:' only proxies api requests, ':<url>' only proxies download traffic, '<url>:<url>' proxies api requests through the first url and download traffic through the second url")]
|
||||
#[arg(global = true, long, value_parser = crate::utils::clap::clap_parse_proxies)]
|
||||
proxy: Option<(Option<Proxy>, Option<Proxy>)>,
|
||||
|
||||
#[arg(help = "Use custom user agent")]
|
||||
#[arg(global = true, long)]
|
||||
|
|
@ -238,43 +239,29 @@ async fn execute_executor(executor: impl Execute, ctx: Context) {
|
|||
}
|
||||
|
||||
async fn create_ctx(cli: &mut Cli) -> Result<Context> {
|
||||
let client = {
|
||||
let mut builder = CrunchyrollBuilder::predefined_client_builder();
|
||||
if let Some(p) = &cli.proxy {
|
||||
builder = builder.proxy(p.clone())
|
||||
}
|
||||
if let Some(ua) = &cli.user_agent {
|
||||
builder = builder.user_agent(ua)
|
||||
}
|
||||
let crunchy_client = reqwest_client(
|
||||
cli.proxy.as_ref().and_then(|p| p.0.clone()),
|
||||
cli.user_agent.clone(),
|
||||
);
|
||||
let internal_client = reqwest_client(
|
||||
cli.proxy.as_ref().and_then(|p| p.1.clone()),
|
||||
cli.user_agent.clone(),
|
||||
);
|
||||
|
||||
#[cfg(any(feature = "openssl-tls", feature = "openssl-tls-static"))]
|
||||
let client = {
|
||||
let mut builder = builder.use_native_tls().tls_built_in_root_certs(false);
|
||||
|
||||
for certificate in rustls_native_certs::load_native_certs().unwrap() {
|
||||
builder = builder.add_root_certificate(
|
||||
reqwest::Certificate::from_der(certificate.0.as_slice()).unwrap(),
|
||||
)
|
||||
}
|
||||
|
||||
builder.build().unwrap()
|
||||
};
|
||||
#[cfg(not(any(feature = "openssl-tls", feature = "openssl-tls-static")))]
|
||||
let client = builder.build().unwrap();
|
||||
|
||||
client
|
||||
};
|
||||
|
||||
let rate_limiter = cli
|
||||
.speed_limit
|
||||
.map(|l| RateLimiterService::new(l, client.clone()));
|
||||
|
||||
let crunchy = crunchyroll_session(cli, client.clone(), rate_limiter.clone()).await?;
|
||||
let crunchy = crunchyroll_session(
|
||||
cli,
|
||||
crunchy_client.clone(),
|
||||
cli.speed_limit
|
||||
.map(|l| RateLimiterService::new(l, crunchy_client)),
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok(Context {
|
||||
crunchy,
|
||||
client,
|
||||
rate_limiter,
|
||||
client: internal_client.clone(),
|
||||
rate_limiter: cli
|
||||
.speed_limit
|
||||
.map(|l| RateLimiterService::new(l, internal_client)),
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -372,3 +359,30 @@ async fn crunchyroll_session(
|
|||
|
||||
Ok(crunchy)
|
||||
}
|
||||
|
||||
fn reqwest_client(proxy: Option<Proxy>, user_agent: Option<String>) -> Client {
|
||||
let mut builder = CrunchyrollBuilder::predefined_client_builder();
|
||||
if let Some(p) = proxy {
|
||||
builder = builder.proxy(p)
|
||||
}
|
||||
if let Some(ua) = user_agent {
|
||||
builder = builder.user_agent(ua)
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "openssl-tls", feature = "openssl-tls-static"))]
|
||||
let client = {
|
||||
let mut builder = builder.use_native_tls().tls_built_in_root_certs(false);
|
||||
|
||||
for certificate in rustls_native_certs::load_native_certs().unwrap() {
|
||||
builder = builder.add_root_certificate(
|
||||
reqwest::Certificate::from_der(certificate.0.as_slice()).unwrap(),
|
||||
)
|
||||
}
|
||||
|
||||
builder.build().unwrap()
|
||||
};
|
||||
#[cfg(not(any(feature = "openssl-tls", feature = "openssl-tls-static")))]
|
||||
let client = builder.build().unwrap();
|
||||
|
||||
client
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,13 +1,46 @@
|
|||
use crate::utils::parse::parse_resolution;
|
||||
use crunchyroll_rs::media::Resolution;
|
||||
use regex::Regex;
|
||||
use reqwest::Proxy;
|
||||
|
||||
pub fn clap_parse_resolution(s: &str) -> Result<Resolution, String> {
|
||||
parse_resolution(s.to_string()).map_err(|e| e.to_string())
|
||||
}
|
||||
|
||||
pub fn clap_parse_proxy(s: &str) -> Result<Proxy, String> {
|
||||
Proxy::all(s).map_err(|e| e.to_string())
|
||||
pub fn clap_parse_proxies(s: &str) -> Result<(Option<Proxy>, Option<Proxy>), String> {
|
||||
let double_proxy_regex =
|
||||
Regex::new(r"^(?P<first>(https?|socks5h?)://.+):(?P<second>(https?|socks5h?)://.+)$")
|
||||
.unwrap();
|
||||
|
||||
if let Some(capture) = double_proxy_regex.captures(s) {
|
||||
// checks if the input is formatted like 'https://example.com:socks5://examples.com' and
|
||||
// splits the string into 2 separate proxies at the middle colon
|
||||
|
||||
let first = capture.name("first").unwrap().as_str();
|
||||
let second = capture.name("second").unwrap().as_str();
|
||||
Ok((
|
||||
Some(Proxy::all(first).map_err(|e| format!("first proxy: {e}"))?),
|
||||
Some(Proxy::all(second).map_err(|e| format!("second proxy: {e}"))?),
|
||||
))
|
||||
} else if s.starts_with(':') {
|
||||
// checks if the input is formatted like ':https://example.com' and returns a proxy on the
|
||||
// second tuple position
|
||||
Ok((
|
||||
None,
|
||||
Some(Proxy::all(s.trim_start_matches(':')).map_err(|e| e.to_string())?),
|
||||
))
|
||||
} else if s.ends_with(':') {
|
||||
// checks if the input is formatted like 'https://example.com:' and returns a proxy on the
|
||||
// first tuple position
|
||||
Ok((
|
||||
Some(Proxy::all(s.trim_end_matches(':')).map_err(|e| e.to_string())?),
|
||||
None,
|
||||
))
|
||||
} else {
|
||||
// returns the same proxy for both tuple positions
|
||||
let proxy = Proxy::all(s).map_err(|e| e.to_string())?;
|
||||
Ok((Some(proxy.clone()), Some(proxy)))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn clap_parse_speed_limit(s: &str) -> Result<u32, String> {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue