Initial let parser use bytebuffer
This commit is contained in:
1 parent
cf8097babc
commit
02855b68e6
5 files changed
+66
-16
No files matched your search
@@ -45,10 +45,14 @@ import com.hippo.ehviewer.client.parser.TorrentParser
|
||||
import com.hippo.ehviewer.client.parser.TorrentResult
|
||||
import com.hippo.ehviewer.client.parser.VoteCommentResult
|
||||
import com.hippo.ehviewer.client.parser.VoteTagParser
|
||||
import com.hippo.ehviewer.cronet.awaitBodyFully
|
||||
import com.hippo.ehviewer.cronet.cronetRequest
|
||||
import com.hippo.ehviewer.cronet.execute
|
||||
import com.hippo.ehviewer.dailycheck.showEventNotification
|
||||
import com.hippo.ehviewer.dailycheck.today
|
||||
import com.hippo.ehviewer.util.AppConfig
|
||||
import com.hippo.ehviewer.util.StatusCodeException
|
||||
import io.ktor.utils.io.pool.DirectByteBufferPool
|
||||
import kotlinx.coroutines.CancellationException
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.serialization.json.add
|
||||
@@ -65,6 +69,7 @@ import okhttp3.RequestBody.Companion.asRequestBody
|
||||
import org.jsoup.Jsoup
|
||||
import splitties.init.appCtx
|
||||
import java.io.File
|
||||
import java.nio.ByteBuffer
|
||||
import kotlin.math.ceil
|
||||
|
||||
private const val TAG = "EhEngine"
|
||||
@@ -124,6 +129,25 @@ private fun rethrowExactly(code: Int, headers: Headers, body: String, e: Throwab
|
||||
throw e
|
||||
}
|
||||
|
||||
val httpContentPool = DirectByteBufferPool(16, 16384)
|
||||
|
||||
suspend inline fun <T> fetchCompat(url: String, referer: String? = null, crossinline parser: (ByteBuffer) -> T): T {
|
||||
val ret: T
|
||||
cronetRequest(url, referer).execute {
|
||||
val buffer = httpContentPool.borrow()
|
||||
try {
|
||||
awaitBodyFully {
|
||||
buffer.put(it)
|
||||
}
|
||||
buffer.flip()
|
||||
ret = parser(buffer)
|
||||
} finally {
|
||||
httpContentPool.recycle(buffer)
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
@Suppress("REDUNDANT_INLINE_SUSPEND_FUNCTION_TYPE")
|
||||
private suspend inline fun <T> Request.executeAndParsingWith(block: suspend String.() -> T): T {
|
||||
Log.d(TAG, url.toString())
|
||||
@@ -151,7 +175,7 @@ object EhEngine {
|
||||
|
||||
suspend fun getTorrentList(url: String, gid: Long, token: String?): TorrentResult {
|
||||
val referer = EhUrl.getGalleryDetailUrl(gid, token)
|
||||
return ehRequest(url, referer).executeAndParsingWith(TorrentParser::parse)
|
||||
return fetchCompat(url, referer, TorrentParser::parse)
|
||||
}
|
||||
|
||||
suspend fun getArchiveList(url: String, gid: Long, token: String?) = ehRequest(url, EhUrl.getGalleryDetailUrl(gid, token))
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package com.hippo.ehviewer.client.parser
|
||||
|
||||
import java.nio.ByteBuffer
|
||||
|
||||
object TorrentParser {
|
||||
fun parse(body: String) = parseTorrent(body)
|
||||
fun parse(body: ByteBuffer) = parseTorrent(body)
|
||||
}
|
||||
|
||||
class Torrent(
|
||||
@@ -18,4 +20,4 @@ fun Torrent.format() = "[$posted] $name [$size] [↑$seeds ↓$peers ✓$downloa
|
||||
|
||||
typealias TorrentResult = ArrayList<Torrent>
|
||||
|
||||
private external fun parseTorrent(body: String): ArrayList<Torrent>
|
||||
private external fun parseTorrent(body: ByteBuffer, size: Int = body.limit()): ArrayList<Torrent>
|
||||
@@ -19,6 +19,8 @@ import org.chromium.net.UrlResponseInfo
|
||||
import splitties.init.appCtx
|
||||
import java.nio.ByteBuffer
|
||||
import java.nio.channels.FileChannel
|
||||
import kotlin.contracts.InvocationKind
|
||||
import kotlin.contracts.contract
|
||||
import kotlin.coroutines.Continuation
|
||||
import kotlin.coroutines.resume
|
||||
import kotlin.coroutines.resumeWithException
|
||||
@@ -72,7 +74,7 @@ class CronetRequest {
|
||||
}
|
||||
}
|
||||
|
||||
inline fun cronetRequest(url: String, referer: String? = null, conf: UrlRequest.Builder.() -> Unit) = CronetRequest().apply {
|
||||
inline fun cronetRequest(url: String, referer: String? = null, conf: UrlRequest.Builder.() -> Unit = {}) = CronetRequest().apply {
|
||||
request = cronetHttpClient.newUrlRequestBuilder(url, callback, cronetHttpClientExecutor).apply {
|
||||
addHeader("Cookie", EhCookieStore.getCookieHeader(url.toHttpUrl()))
|
||||
addHeader("User-Agent", CHROME_USER_AGENT)
|
||||
@@ -104,11 +106,16 @@ suspend inline fun CronetRequest.copyToChannel(chan: FileChannel, crossinline li
|
||||
listener(bytes)
|
||||
}
|
||||
|
||||
suspend inline fun CronetRequest.execute(crossinline callback: suspend CronetRequest.(UrlResponseInfo) -> Unit) = coroutineScope {
|
||||
onResponse = { launch { callback(it) } }
|
||||
suspendCancellableCoroutine { cont ->
|
||||
cont.invokeOnCancellation { request.cancel() }
|
||||
daemonCont = cont
|
||||
request.start()
|
||||
suspend inline fun CronetRequest.execute(crossinline callback: suspend CronetRequest.(UrlResponseInfo) -> Unit): Boolean {
|
||||
contract {
|
||||
callsInPlace(callback, InvocationKind.EXACTLY_ONCE)
|
||||
}
|
||||
return coroutineScope {
|
||||
onResponse = { launch { callback(it) } }
|
||||
suspendCancellableCoroutine { cont ->
|
||||
cont.invokeOnCancellation { request.cancel() }
|
||||
daemonCont = cont
|
||||
request.start()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13,11 +13,13 @@ extern crate regex_lite;
|
||||
extern crate tl;
|
||||
|
||||
use android_logger::Config;
|
||||
use jnix::jni::objects::JString;
|
||||
use jnix::jni::objects::{JByteBuffer, JString};
|
||||
use jnix::jni::sys::{jint, JavaVM, JNI_VERSION_1_6};
|
||||
use jnix::JnixEnv;
|
||||
use log::LevelFilter;
|
||||
use std::ffi::c_void;
|
||||
use std::ptr::slice_from_raw_parts;
|
||||
use std::str::from_utf8;
|
||||
use tl::{Bytes, Node, NodeHandle, Parser, VDom};
|
||||
|
||||
#[macro_export]
|
||||
@@ -70,6 +72,20 @@ where
|
||||
f(&dom, parser, env)
|
||||
}
|
||||
|
||||
fn parse_bytebuffer<F, R>(env: &mut JnixEnv, str: JByteBuffer, limit: jint, mut f: F) -> Option<R>
|
||||
where
|
||||
F: FnMut(&VDom, &Parser, &JnixEnv) -> Option<R>,
|
||||
{
|
||||
let ptr = env.get_direct_buffer_address(str).ok()?;
|
||||
let html = unsafe {
|
||||
let buff = slice_from_raw_parts(ptr, limit as usize);
|
||||
from_utf8(&*buff).ok()?
|
||||
};
|
||||
let dom = tl::parse(html, tl::ParserOptions::default()).ok()?;
|
||||
let parser = dom.parser();
|
||||
f(&dom, parser, env)
|
||||
}
|
||||
|
||||
fn get_node_handle_attr<'a>(
|
||||
node: &NodeHandle,
|
||||
parser: &'a Parser,
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
use catch_panic::catch_panic;
|
||||
use jni_fn::jni_fn;
|
||||
use jnix::jni::objects::{JClass, JString};
|
||||
use jnix::jni::sys::jobject;
|
||||
use jnix::jni::objects::{JByteBuffer, JClass};
|
||||
use jnix::jni::sys::{jint, jobject};
|
||||
use jnix::jni::JNIEnv;
|
||||
use jnix::{IntoJava, JnixEnv};
|
||||
use jnix_macros::IntoJava;
|
||||
use parse_bytebuffer;
|
||||
use quick_xml::escape::unescape;
|
||||
use {parse_jni_string, regex};
|
||||
use regex;
|
||||
|
||||
#[derive(Default, IntoJava)]
|
||||
#[jnix(package = "com.hippo.ehviewer.client.parser")]
|
||||
@@ -24,9 +25,9 @@ pub struct Torrent {
|
||||
#[catch_panic(default = "std::ptr::null_mut()")]
|
||||
#[allow(non_snake_case)]
|
||||
#[jni_fn("com.hippo.ehviewer.client.parser.TorrentParserKt")]
|
||||
pub fn parseTorrent(env: JNIEnv, _class: JClass, input: JString) -> jobject {
|
||||
pub fn parseTorrent(env: JNIEnv, _class: JClass, buffer: JByteBuffer, limit: jint) -> jobject {
|
||||
let mut env = JnixEnv { env };
|
||||
parse_jni_string(&mut env, &input, |dom, parser, _env| {
|
||||
parse_bytebuffer(&mut env, buffer, limit, |dom, parser, _env| {
|
||||
Some(dom.query_selector("table")?.filter_map(|e| {
|
||||
let html = e.get(parser)?.inner_html(parser);
|
||||
let grp = regex!("</span> ([0-9-]+) [0-9:]+</td>[\\s\\S]+</span> ([0-9.]+ [KMGT]B)</td>[\\s\\S]+</span> ([0-9]+)</td>[\\s\\S]+</span> ([0-9]+)</td>[\\s\\S]+</span> ([0-9]+)</td>[\\s\\S]+</span>([^<]+)</td>[\\s\\S]+onclick=\"document.location='([^\"]+)'[^<]+>([^<]+)</a>").captures(&html)?;
|
||||
|
||||
Reference in new issue
Block a user