diff --git a/app/src/main/kotlin/com/hippo/ehviewer/client/EhEngine.kt b/app/src/main/kotlin/com/hippo/ehviewer/client/EhEngine.kt
index 0603fde00..6ff77b752 100644
--- a/app/src/main/kotlin/com/hippo/ehviewer/client/EhEngine.kt
+++ b/app/src/main/kotlin/com/hippo/ehviewer/client/EhEngine.kt
@@ -41,6 +41,7 @@ import com.hippo.ehviewer.client.parser.FavoritesParser
import com.hippo.ehviewer.client.parser.GalleryApiParser
import com.hippo.ehviewer.client.parser.GalleryDetailParser
import com.hippo.ehviewer.client.parser.GalleryListParser
+import com.hippo.ehviewer.client.parser.GalleryMultiPageViewerPTokenParser
import com.hippo.ehviewer.client.parser.GalleryPageParser
import com.hippo.ehviewer.client.parser.GalleryTokenApiParser
import com.hippo.ehviewer.client.parser.HomeParser
@@ -62,6 +63,8 @@ import eu.kanade.tachiyomi.util.system.logcat
import io.ktor.client.statement.HttpResponse
import io.ktor.client.statement.HttpStatement
import io.ktor.client.statement.bodyAsChannel
+import io.ktor.client.statement.request
+import io.ktor.http.Url
import io.ktor.utils.io.pool.DirectByteBufferPool
import io.ktor.utils.io.pool.useInstance
import io.ktor.utils.io.readAvailable
@@ -86,7 +89,9 @@ private const val MAX_REQUEST_SIZE = 25
private const val MAX_SEQUENTIAL_REQUESTS = 5
private const val REQUEST_INTERVAL = 5000L
-fun Either.saveParseError(e: Throwable) {
+private val Url.isLogin get() = segments.firstOrNull() == "bounce_login.php"
+
+private fun Either.saveParseError(e: Throwable) {
val dir = AppConfig.externalParseErrorDir ?: return
val file = File(dir, ReadableTime.getFilenamableTime() + ".txt")
file.sink().buffer().use { sink ->
@@ -98,7 +103,7 @@ fun Either.saveParseError(e: Throwable) {
}
}
-fun rethrowExactly(response: HttpResponse, body: Either, e: Throwable): Nothing {
+private fun rethrowExactly(response: HttpResponse, body: Either, e: Throwable): Nothing {
// Don't translate coroutine cancellation
if (e is CancellationException) throw e
@@ -148,9 +153,10 @@ fun rethrowExactly(response: HttpResponse, body: Either, e:
throw e
}
-val httpContentPool = DirectByteBufferPool(8, 0x80000)
+private val httpContentPool = DirectByteBufferPool(8, 0x80000)
-suspend inline fun HttpStatement.fetchUsingAsText(crossinline block: suspend String.() -> T) = executeSafely { response ->
+private suspend inline fun HttpStatement.fetchUsingAsText(crossinline block: suspend String.() -> T) = executeSafely { response ->
+ if (response.request.url.isLogin) throw NotLoggedInException()
val body = response.bodyAsUtf8Text()
runSuspendCatching {
block(body)
@@ -159,7 +165,8 @@ suspend inline fun HttpStatement.fetchUsingAsText(crossinline block: suspend
}.getOrThrow()
}
-suspend inline fun HttpStatement.fetchUsingAsByteBuffer(crossinline block: suspend ByteBuffer.() -> T) = executeSafely { response ->
+private suspend inline fun HttpStatement.fetchUsingAsByteBuffer(crossinline block: suspend ByteBuffer.() -> T) = executeSafely { response ->
+ if (response.request.url.isLogin) throw NotLoggedInException()
httpContentPool.useInstance { buffer ->
with(response.bodyAsChannel()) { while (!isClosedForRead) readAvailable(buffer) }
buffer.flip()
@@ -175,9 +182,12 @@ suspend inline fun HttpStatement.fetchUsingAsByteBuffer(crossinline block: s
object EhEngine {
suspend fun getOriginalImageUrl(url: String, referer: String?) = noRedirectEhRequest(url, referer).executeSafely { response ->
val location = response.headers["Location"] ?: throw InsufficientFundsException()
- location.takeIf { "bounce_login" !in it } ?: throw NotLoggedInException()
+ location.takeUnless { Url(it).isLogin } ?: throw NotLoggedInException()
}
+ suspend fun getPTokenListFromMpv(gid: Long, token: String) = ehRequest(EhUrl.getGalleryMultiPageViewerUrl(gid, token), EhUrl.referer)
+ .fetchUsingAsText(GalleryMultiPageViewerPTokenParser::parse)
+
suspend fun getTorrentList(gid: Long, token: String): TorrentResult {
val url = EhUrl.getTorrentUrl(gid, token)
val referer = EhUrl.getGalleryDetailUrl(gid, token)
diff --git a/app/src/main/kotlin/com/hippo/ehviewer/spider/SpiderQueen.kt b/app/src/main/kotlin/com/hippo/ehviewer/spider/SpiderQueen.kt
index fd170f039..553601dd8 100644
--- a/app/src/main/kotlin/com/hippo/ehviewer/spider/SpiderQueen.kt
+++ b/app/src/main/kotlin/com/hippo/ehviewer/spider/SpiderQueen.kt
@@ -25,15 +25,11 @@ import com.hippo.ehviewer.Settings
import com.hippo.ehviewer.client.EhEngine
import com.hippo.ehviewer.client.EhUrl
import com.hippo.ehviewer.client.EhUrl.getGalleryDetailUrl
-import com.hippo.ehviewer.client.EhUrl.getGalleryMultiPageViewerUrl
import com.hippo.ehviewer.client.EhUrl.referer
import com.hippo.ehviewer.client.EhUtils
import com.hippo.ehviewer.client.data.GalleryInfo
import com.hippo.ehviewer.client.data.GalleryPreview
-import com.hippo.ehviewer.client.ehRequest
import com.hippo.ehviewer.client.exception.QuotaExceededException
-import com.hippo.ehviewer.client.fetchUsingAsText
-import com.hippo.ehviewer.client.parser.GalleryMultiPageViewerPTokenParser
import com.hippo.ehviewer.util.displayString
import com.hippo.files.find
import eu.kanade.tachiyomi.util.system.logcat
@@ -342,17 +338,11 @@ class SpiderQueen private constructor(val galleryInfo: GalleryInfo) : CoroutineS
suspend fun getPTokenFromMultiPageViewer(index: Int): String? {
if (!isMpvAvailable) return null
- val url = getGalleryMultiPageViewerUrl(
- galleryInfo.gid,
- galleryInfo.token,
- )
return runSuspendCatching {
- ehRequest(url, referer).fetchUsingAsText {
- GalleryMultiPageViewerPTokenParser.parse(this).forEachIndexed { index, s ->
- spiderInfo.pTokenMap[index] = s
- }
- spiderInfo.pTokenMap[index]
+ EhEngine.getPTokenListFromMpv(galleryInfo.gid, galleryInfo.token).forEachIndexed { index, s ->
+ spiderInfo.pTokenMap[index] = s
}
+ spiderInfo.pTokenMap[index]
}.getOrElse {
logcat(it)
null
diff --git a/app/src/main/rust/src/ffi/jvm.rs b/app/src/main/rust/src/ffi/jvm.rs
index d30acc08b..96de356a3 100644
--- a/app/src/main/rust/src/ffi/jvm.rs
+++ b/app/src/main/rust/src/ffi/jvm.rs
@@ -29,8 +29,8 @@ use tl::{ParserOptions, VDom};
#[jni_fn("com.hippo.ehviewer.client.parser.FavoritesParserKt")]
pub fn parseFav(mut env: JNIEnv, _class: JClass, input: JByteBuffer, limit: jint) -> jint {
- parse_marshal_inplace(&mut env, input, limit, |dom, html| {
- parse_fav(dom, dom.parser(), html)
+ parse_marshal_inplace(&mut env, input, limit, |dom, _| {
+ parse_fav(dom, dom.parser())
})
}
@@ -43,8 +43,8 @@ pub fn parseLimit(mut env: JNIEnv, _class: JClass, input: JByteBuffer, limit: ji
#[jni_fn("com.hippo.ehviewer.client.parser.GalleryListParserKt")]
pub fn parseGalleryInfoList(mut env: JNIEnv, _: JClass, buffer: JByteBuffer, limit: jint) -> jint {
- parse_marshal_inplace(&mut env, buffer, limit, |dom, str| {
- parse_info_list(dom, dom.parser(), str)
+ parse_marshal_inplace(&mut env, buffer, limit, |dom, _| {
+ parse_info_list(dom, dom.parser())
})
}
diff --git a/app/src/main/rust/src/parser/fav.rs b/app/src/main/rust/src/parser/fav.rs
index 0c8824cc3..b7159ddbd 100644
--- a/app/src/main/rust/src/parser/fav.rs
+++ b/app/src/main/rust/src/parser/fav.rs
@@ -1,4 +1,3 @@
-use crate::EhError;
use crate::parser::list::{GalleryListResult, parse_info_list};
use anyhow::{Result, bail};
use quick_xml::escape::unescape;
@@ -14,10 +13,7 @@ pub struct FavResult {
galleryListResult: GalleryListResult,
}
-pub fn parse_fav(dom: &VDom, parser: &Parser, html: &str) -> Result {
- if html.contains("This page requires you to log on.
") {
- bail!(EhError::NeedLogin)
- }
+pub fn parse_fav(dom: &VDom, parser: &Parser) -> Result {
let vec: Vec<(String, i32)> = dom
.get_elements_by_class_name("fp")
.enumerate()
@@ -38,7 +34,7 @@ pub fn parse_fav(dom: &VDom, parser: &Parser, html: &str) -> Result {
})
.collect();
if vec.len() == 10 {
- let list = parse_info_list(dom, parser, html)?;
+ let list = parse_info_list(dom, parser)?;
let cat = vec.iter().cloned().unzip();
Ok(FavResult {
catArray: cat.0,
diff --git a/app/src/main/rust/src/parser/list.rs b/app/src/main/rust/src/parser/list.rs
index 7d5030a8a..ae137c269 100644
--- a/app/src/main/rust/src/parser/list.rs
+++ b/app/src/main/rust/src/parser/list.rs
@@ -194,47 +194,46 @@ fn parse_gallery_info(node: &Node, parser: &Parser) -> Option {
})
}
-pub fn parse_info_list(dom: &VDom, parser: &Parser, str: &str) -> Result {
- if str.contains("You do not have any watched tags") {
- bail!(EhError::NoWatched)
- }
- if str.contains("No hits found
") || str.contains("No unfiltered results") {
- let e = get_vdom_first_element_by_class_name(dom, "searchwarn")
- .map_or(EhError::NoHits, |n| {
- EhError::Error(n.inner_text(parser).to_string())
- });
+pub fn parse_info_list(dom: &VDom, parser: &Parser) -> Result {
+ if let Some(n) = get_vdom_first_element_by_class_name(dom, "searchwarn") {
+ let text = n.inner_text(parser);
+ let e = if text.contains("You do not have any watched tags") {
+ EhError::NoWatched
+ } else {
+ EhError::Error(text.to_string())
+ };
bail!(e)
}
- let f = || {
- let itg = get_vdom_first_element_by_class_name(dom, "itg")?;
- let children = itg.children()?;
- let iter = children.top().iter();
- let info: Vec = iter
- .filter_map(|x| parse_gallery_info(x.get(parser)?, parser))
- .collect();
- let prev = dom.get_element_by_id("uprev").and_then(|e| {
- let str = get_node_handle_attr(&e, parser, "href")?;
- Some(
- regex!("prev=(\\d+(-\\d+)?)")
- .captures(str)?
- .index(1)
- .to_string(),
- )
- });
- let next = dom.get_element_by_id("unext").and_then(|e| {
- let str = get_node_handle_attr(&e, parser, "href")?;
- Some(
- regex!("next=(\\d+(-\\d+)?)")
- .captures(str)?
- .index(1)
- .to_string(),
- )
- });
- (!info.is_empty()).then_some(GalleryListResult {
- prev,
- next,
- galleryInfoList: info,
+ let info = get_vdom_first_element_by_class_name(dom, "itg")
+ .map(|itg| {
+ let children = itg.children().unwrap();
+ let iter = children.top().iter();
+ iter.filter_map(|x| parse_gallery_info(x.get(parser)?, parser))
+ .collect::>()
})
- };
- f().context("No content")
+ .filter(|v| !v.is_empty())
+ .context(EhError::NoHits)?;
+ let prev = dom.get_element_by_id("uprev").and_then(|e| {
+ let str = get_node_handle_attr(&e, parser, "href")?;
+ Some(
+ regex!("prev=(\\d+(-\\d+)?)")
+ .captures(str)?
+ .index(1)
+ .to_string(),
+ )
+ });
+ let next = dom.get_element_by_id("unext").and_then(|e| {
+ let str = get_node_handle_attr(&e, parser, "href")?;
+ Some(
+ regex!("next=(\\d+(-\\d+)?)")
+ .captures(str)?
+ .index(1)
+ .to_string(),
+ )
+ });
+ Ok(GalleryListResult {
+ prev,
+ next,
+ galleryInfoList: info,
+ })
}
diff --git a/app/src/main/rust/src/parser/test_parser.rs b/app/src/main/rust/src/parser/test_parser.rs
index 6b9503bf0..e97ef432e 100644
--- a/app/src/main/rust/src/parser/test_parser.rs
+++ b/app/src/main/rust/src/parser/test_parser.rs
@@ -14,7 +14,7 @@ mod tests {
let resp = get("https://e-hentai.org/").await.expect("Failed to get!");
let body = resp.text().await.expect("Failed to receive!");
let dom = tl::parse(&body, ParserOptions::default()).expect("Failed to parse html");
- let result = parse_info_list(&dom, dom.parser(), &body).expect("Failed to parse info list");
+ let result = parse_info_list(&dom, dom.parser()).expect("Failed to parse info list");
dbg!(result);
}