feat: add en.theblank - #624
Conversation
fix: clippy warnings in en.theblank feat: add en.theblank
7ef5f40 to
a4761bd
Compare
kkantan
left a comment
There was a problem hiding this comment.
the code in lib.rs could be split into models.rs for the json types and helpers.rs for helper functions, as other sources do.
looking at the keiyoushi source, it looks like it uses the "pam" template. it would be nice if this was refactored into a new template so that other sources that use the same one could be added more easily, but it's not strictly necessary.
| } | ||
|
|
||
| /// Parse ISO-8601 datetime → Unix timestamp in seconds. | ||
| fn parse_iso_date(s: &str) -> i64 { |
There was a problem hiding this comment.
you should be able to use the aidoku-rs parse_date function with a provided date format.
| let js = format!( | ||
| r#"(async () => {{ | ||
| const token = '{token}'; | ||
| const page = {page}; | ||
| const ts = Math.floor(Date.now() / 1000); | ||
| const nonceArr = new Uint8Array(8); | ||
| crypto.getRandomValues(nonceArr); | ||
| const nonce = Array.from(nonceArr).map(b => b.toString(16).padStart(2,'0')).join(''); | ||
| const keyBytes = new Uint8Array(token.match(/.{{2}}/g).map(b => parseInt(b,16))); | ||
| const key = await crypto.subtle.importKey('raw', keyBytes, {{name:'HMAC',hash:'SHA-256'}}, false, ['sign']); | ||
| const msg = page.toString(16).padStart(2,'0') + ts.toString() + nonce; | ||
| const sig = Array.from(new Uint8Array(await crypto.subtle.sign('HMAC', key, new TextEncoder().encode(msg)))) | ||
| .map(b => b.toString(16).padStart(2,'0')).join(''); | ||
| return JSON.stringify({{ts: ts.toString(), nonce, sig}}); | ||
| }})()"#, | ||
| token = token, | ||
| page = page, | ||
| ); | ||
|
|
||
| let result = JsContext::new().eval_async(&js).unwrap_or_default(); | ||
| let params: Option<HmacParams> = serde_json::from_str(&result).ok(); |
There was a problem hiding this comment.
it would be preferable if this were implemented in rust rather than js, since both using the js context is discouraged when possible, and the async eval is a new api that most users I believe still don't have access to. there should be a no_std rust hmac or crypto crate that does the same thing.
| .into_iter() | ||
| .map(|c| { | ||
| let key = format!("{}|{}", s.slug, c.slug); | ||
| Chapter { |
There was a problem hiding this comment.
it would be nicer if From<LibrarySerie> was implemented for Manga, and likewise for chapters, so you could just map(Into::into).
|
|
||
| // ─── Source ─────────────────────────────────────────────────────────────────── | ||
|
|
||
| struct Theblank; |
There was a problem hiding this comment.
| struct Theblank; | |
| struct TheBlank; |
| panic = "abort" | ||
| opt-level = "s" | ||
| strip = true | ||
| lto = true No newline at end of file |
There was a problem hiding this comment.
| lto = true | |
| lto = true | |
|
Addressed all review comments --- split into models.rs/helpers.rs, replaced JsContext HMAC with pure Rust hmac-sha256, used parse_date, added From impls, added filters.json, and fixed the icon. |
kkantan
left a comment
There was a problem hiding this comment.
most comments from the past review were not applied, with some being marked resolved despite this. also, you should set the minimumAppVersion to 0.7.1 and run cargo clippy to fix lint warnings.
| } | ||
| } | ||
|
|
||
| // ─── From impls ─────────────────────────────────────────────────────────────── |
There was a problem hiding this comment.
these should be in models.rs.
|
|
||
| pub const BASE_URL: &str = "https://theblank.net"; | ||
|
|
||
| // ─── MangaStatus helper ─────────────────────────────────────────────────────── |
There was a problem hiding this comment.
this should be in helpers.rs or models.rs.
| } | ||
|
|
||
| let html = fetch_html(&url)?; | ||
| let props: LibraryProps = parse_inertia(&html).ok_or(AidokuError::Message( |
There was a problem hiding this comment.
you can use the error! macro.
| impl Home for Theblank { | ||
| fn get_home(&self) -> Result<HomeLayout> { | ||
| Err(AidokuError::Unimplemented) | ||
| } | ||
| } |
There was a problem hiding this comment.
this should not be here if it's not implemented.
Co-authored-by: kantan <31490942+kkantan@users.noreply.github.com>
Co-authored-by: kantan <31490942+kkantan@users.noreply.github.com>
|
Addressed all feedback -- used QueryParameters for URL building, removed details from search results, renamed to TheBlank, removed language field from chapters, removed unnecessary early return, added 128x128 icon, and split into models.rs/helpers.rs. |
kkantan
left a comment
There was a problem hiding this comment.
my previous review comments were not addressed.
| /// Fetch a URL with a mobile User-Agent to avoid Cloudflare blocks. | ||
| pub fn fetch_html(url: &str) -> Result<String> { | ||
| Request::get(url) | ||
| .map_err(|e| AidokuError::Message(format!("request error: {:?}", e)))? |
There was a problem hiding this comment.
I suggested this before on one place, but it applies to everywhere you use AidokuError::Message.
| .map_err(|e| AidokuError::Message(format!("request error: {:?}", e)))? | |
| .map_err(|e| error!("request error: {:?}", e))? |
| if let Some(q) = &query { | ||
| params.push("search", Some(q)); | ||
| } |
There was a problem hiding this comment.
| if let Some(q) = &query { | |
| params.push("search", Some(q)); | |
| } | |
| if query.is_some() { | |
| params.push("search", query.as_deref()); | |
| } |
Adds a source for theblank.net, an English manga/manhwa/pornhwa reader. Implements search, manga details, chapter list, page list with HMAC-SHA256 signed image URLs, listings, and deep link handling.