feature: rewrite season subscription extractor

This commit is contained in:
2025-05-02 02:23:23 +08:00
parent 4301f1dbab
commit dbded94324
51 changed files with 8181 additions and 6035 deletions

View File

@@ -16,9 +16,7 @@ axum-extra = { workspace = true }
async-trait = { workspace = true }
moka = { workspace = true }
reqwest = { workspace = true }
leaky-bucket = "1.1"
cookie = "0.18"
http-cache-reqwest = { version = "0.15", features = [
"manager-cacache",
"manager-moka",
@@ -33,3 +31,4 @@ http-cache = { version = "0.20", features = [
"manager-cacache",
"manager-moka",
], default-features = false }
reqwest_cookie_store = { version = "0.8.0", features = ["serde"] }

View File

@@ -6,7 +6,8 @@ use http_cache_reqwest::{
Cache, CacheManager, CacheMode, HttpCache, HttpCacheOptions, MokaManager,
};
use leaky_bucket::RateLimiter;
use reqwest::{ClientBuilder, Request, Response};
use reqwest::{self, ClientBuilder, Request, Response};
use reqwest_cookie_store::{CookieStore, CookieStoreRwLock};
use reqwest_middleware::{
ClientBuilder as ClientWithMiddlewareBuilder, ClientWithMiddleware, Middleware, Next,
};
@@ -16,7 +17,6 @@ use serde::{Deserialize, Serialize};
use serde_with::serde_as;
use snafu::Snafu;
use super::HttpClientSecrecyDataTrait;
use crate::get_random_mobile_ua;
pub struct RateLimiterMiddleware {
@@ -109,6 +109,8 @@ pub enum HttpClientError {
ReqwestMiddlewareError { source: reqwest_middleware::Error },
#[snafu(transparent)]
HttpError { source: http::Error },
#[snafu(display("Failed to parse cookies: {}", source))]
ParseCookiesError { source: serde_json::Error },
}
pub trait HttpClientTrait: Deref<Target = ClientWithMiddleware> + Debug {}
@@ -117,17 +119,29 @@ pub struct HttpClientFork {
pub client_builder: ClientBuilder,
pub middleware_stack: Vec<Arc<dyn Middleware>>,
pub config: HttpClientConfig,
pub cookie_store: Option<Arc<CookieStoreRwLock>>,
}
impl HttpClientFork {
pub fn attach_secrecy<S: HttpClientSecrecyDataTrait>(self, secrecy: S) -> Self {
let mut fork = self;
fork.client_builder = secrecy.attach_secrecy_to_client(fork.client_builder);
fork
pub fn attach_cookies(mut self, cookies: &str) -> Result<Self, HttpClientError> {
let cookie_store: CookieStore = serde_json::from_str(cookies)
.map_err(|err| HttpClientError::ParseCookiesError { source: err })?;
let cookies_store = Arc::new(CookieStoreRwLock::new(cookie_store));
self.cookie_store = Some(cookies_store.clone());
self.client_builder = self.client_builder.cookie_provider(cookies_store);
Ok(self)
}
pub fn attach_user_agent(mut self, user_agent: &str) -> Self {
self.client_builder = self.client_builder.user_agent(user_agent);
self
}
}
pub struct HttpClient {
pub cookie_store: Option<Arc<CookieStoreRwLock>>,
client: ClientWithMiddleware,
middleware_stack: Vec<Arc<dyn Middleware>>,
pub config: HttpClientConfig,
@@ -268,6 +282,7 @@ impl HttpClient {
client: reqwest_with_middleware,
middleware_stack,
config,
cookie_store: None,
})
}
@@ -287,6 +302,7 @@ impl HttpClient {
client_builder: reqwest_client_builder,
middleware_stack: self.middleware_stack.clone(),
config: self.config.clone(),
cookie_store: self.cookie_store.clone(),
}
}
@@ -295,6 +311,7 @@ impl HttpClient {
client_builder,
middleware_stack,
config,
cookie_store,
} = fork;
let reqwest_client = client_builder.build()?;
let mut reqwest_with_middleware_builder = ClientWithMiddlewareBuilder::new(reqwest_client);
@@ -309,6 +326,7 @@ impl HttpClient {
client: reqwest_with_middleware,
middleware_stack,
config,
cookie_store,
})
}
}

View File

@@ -1,9 +1,6 @@
pub mod core;
pub mod secrecy;
pub use core::{
HttpClient, HttpClientCacheBackendConfig, HttpClientCachePresetConfig, HttpClientConfig,
HttpClientError, HttpClientTrait,
};
pub use secrecy::{HttpClientCookiesAuth, HttpClientSecrecyDataTrait};

View File

@@ -1,47 +0,0 @@
use std::sync::Arc;
use cookie::Cookie;
use reqwest::{ClientBuilder, cookie::Jar};
use url::Url;
use crate::FetchError;
pub trait HttpClientSecrecyDataTrait {
fn attach_secrecy_to_client(&self, client_builder: ClientBuilder) -> ClientBuilder {
client_builder
}
}
#[derive(Default)]
pub struct HttpClientCookiesAuth {
pub cookie_jar: Arc<Jar>,
pub user_agent: Option<String>,
}
impl HttpClientCookiesAuth {
pub fn from_cookies(
cookies: &str,
url: &Url,
user_agent: Option<String>,
) -> Result<Self, FetchError> {
let cookie_jar = Arc::new(Jar::default());
for cookie in Cookie::split_parse(cookies).collect::<Result<Vec<Cookie<'_>>, _>>()? {
cookie_jar.add_cookie_str(&cookie.to_string(), url);
}
Ok(Self {
cookie_jar,
user_agent,
})
}
}
impl HttpClientSecrecyDataTrait for HttpClientCookiesAuth {
fn attach_secrecy_to_client(&self, client_builder: ClientBuilder) -> ClientBuilder {
let mut client_builder = client_builder.cookie_provider(self.cookie_jar.clone());
if let Some(ref user_agent) = self.user_agent {
client_builder = client_builder.user_agent(user_agent);
}
client_builder
}
}

View File

@@ -3,8 +3,6 @@ use snafu::Snafu;
#[derive(Debug, Snafu)]
#[snafu(visibility(pub))]
pub enum FetchError {
#[snafu(transparent)]
CookieParseError { source: cookie::ParseError },
#[snafu(transparent)]
ReqwestError { source: reqwest::Error },
#[snafu(transparent)]

View File

@@ -9,10 +9,7 @@ pub mod test_util;
pub use core::get_random_mobile_ua;
pub use bytes::fetch_bytes;
pub use client::{
HttpClient, HttpClientConfig, HttpClientCookiesAuth, HttpClientError,
HttpClientSecrecyDataTrait, HttpClientTrait,
};
pub use client::{HttpClient, HttpClientConfig, HttpClientError, HttpClientTrait};
pub use errors::FetchError;
pub use html::fetch_html;
pub use image::fetch_image;