Treat search warnings as errors
This commit is contained in:
1 parent
4db96c7bdb
commit
348d45f2f5
6 files changed
+65
-70
No files matched your search
@@ -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<String, ByteBuffer>.saveParseError(e: Throwable) {
|
||||
private val Url.isLogin get() = segments.firstOrNull() == "bounce_login.php"
|
||||
|
||||
private fun Either<String, ByteBuffer>.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<String, ByteBuffer>.saveParseError(e: Throwable) {
|
||||
}
|
||||
}
|
||||
|
||||
fun rethrowExactly(response: HttpResponse, body: Either<String, ByteBuffer>, e: Throwable): Nothing {
|
||||
private fun rethrowExactly(response: HttpResponse, body: Either<String, ByteBuffer>, e: Throwable): Nothing {
|
||||
// Don't translate coroutine cancellation
|
||||
if (e is CancellationException) throw e
|
||||
|
||||
@@ -148,9 +153,10 @@ fun rethrowExactly(response: HttpResponse, body: Either<String, ByteBuffer>, e:
|
||||
throw e
|
||||
}
|
||||
|
||||
val httpContentPool = DirectByteBufferPool(8, 0x80000)
|
||||
private val httpContentPool = DirectByteBufferPool(8, 0x80000)
|
||||
|
||||
suspend inline fun <T> HttpStatement.fetchUsingAsText(crossinline block: suspend String.() -> T) = executeSafely { response ->
|
||||
private suspend inline fun <T> 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 <T> HttpStatement.fetchUsingAsText(crossinline block: suspend
|
||||
}.getOrThrow()
|
||||
}
|
||||
|
||||
suspend inline fun <T> HttpStatement.fetchUsingAsByteBuffer(crossinline block: suspend ByteBuffer.() -> T) = executeSafely { response ->
|
||||
private suspend inline fun <T> 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 <T> 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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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())
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -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<FavResult> {
|
||||
if html.contains("This page requires you to log on.</p>") {
|
||||
bail!(EhError::NeedLogin)
|
||||
}
|
||||
pub fn parse_fav(dom: &VDom, parser: &Parser) -> Result<FavResult> {
|
||||
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<FavResult> {
|
||||
})
|
||||
.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,
|
||||
|
||||
@@ -194,47 +194,46 @@ fn parse_gallery_info(node: &Node, parser: &Parser) -> Option<BaseGalleryInfo> {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn parse_info_list(dom: &VDom, parser: &Parser, str: &str) -> Result<GalleryListResult> {
|
||||
if str.contains("<p>You do not have any watched tags") {
|
||||
bail!(EhError::NoWatched)
|
||||
}
|
||||
if str.contains("No hits found</p>") || 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<GalleryListResult> {
|
||||
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<BaseGalleryInfo> = 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::<Vec<_>>()
|
||||
})
|
||||
};
|
||||
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,
|
||||
})
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user