diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index b6ac9d700..fc66e5173 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -13,6 +13,8 @@ -keep class androidx.viewpager.widget.ViewPager$LayoutParams { int position; } +-keep class com.hippo.ehviewer.client.parser.Torrent + -keepattributes LineNumberTable,SourceFile -renamesourcefileattribute SourceFile diff --git a/app/src/main/java/com/hippo/ehviewer/client/EhEngine.kt b/app/src/main/java/com/hippo/ehviewer/client/EhEngine.kt index 08a9a9edc..d1bf06db8 100644 --- a/app/src/main/java/com/hippo/ehviewer/client/EhEngine.kt +++ b/app/src/main/java/com/hippo/ehviewer/client/EhEngine.kt @@ -40,6 +40,7 @@ import com.hippo.ehviewer.client.parser.ProfileParser import com.hippo.ehviewer.client.parser.RateGalleryParser import com.hippo.ehviewer.client.parser.SignInParser import com.hippo.ehviewer.client.parser.TorrentParser +import com.hippo.ehviewer.client.parser.TorrentResult import com.hippo.ehviewer.client.parser.VoteCommentParser import com.hippo.ehviewer.client.parser.VoteTagParser import com.hippo.ehviewer.dailycheck.showEventNotification @@ -129,7 +130,7 @@ private suspend inline fun Request.executeAndParsingWith(block: String.() -> } object EhEngine { - suspend fun getTorrentList(url: String, gid: Long, token: String?): List { + suspend fun getTorrentList(url: String, gid: Long, token: String?): TorrentResult { val referer = EhUrl.getGalleryDetailUrl(gid, token) return ehRequest(url, referer).executeAndParsingWith(TorrentParser::parse) } diff --git a/app/src/main/java/com/hippo/ehviewer/client/parser/TorrentParser.kt b/app/src/main/java/com/hippo/ehviewer/client/parser/TorrentParser.kt index 6c3305905..51c9d1872 100644 --- a/app/src/main/java/com/hippo/ehviewer/client/parser/TorrentParser.kt +++ b/app/src/main/java/com/hippo/ehviewer/client/parser/TorrentParser.kt @@ -1,30 +1,25 @@ -/* - * Copyright 2016 Hippo Seven - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ package com.hippo.ehviewer.client.parser object TorrentParser { - fun parse(body: String): List { - val list = mutableListOf>() + fun parse(body: String) = run { + val list = mutableListOf() parseTorrent(body, list) - return list.map { Result(it[0], it[1], it[2].toInt(), it[3].toInt(), it[4].toInt(), it[5], it[6]) } - } - - class Result(val posted: String, val size: String, val seeds: Int, val peers: Int, val downloads: Int, val url: String, val name: String) { - fun format() = "[$posted] $name [$size] [↑$seeds ↓$peers ✓$downloads]" + list } } -private external fun parseTorrent(body: String, list: List>) +class Torrent( + val posted: String, + val size: String, + val seeds: Int, + val peers: Int, + val downloads: Int, + val url: String, + val name: String, +) { + fun format() = "[$posted] $name [$size] [↑$seeds ↓$peers ✓$downloads]" +} + +typealias TorrentResult = List + +private external fun parseTorrent(body: String, list: List) diff --git a/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryDetailScene.kt b/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryDetailScene.kt index cc8d3a27a..e99830fee 100755 --- a/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryDetailScene.kt +++ b/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryDetailScene.kt @@ -137,7 +137,7 @@ import com.hippo.ehviewer.client.exception.NoHAtHClientException import com.hippo.ehviewer.client.parser.ArchiveParser import com.hippo.ehviewer.client.parser.HomeParser import com.hippo.ehviewer.client.parser.ParserUtils -import com.hippo.ehviewer.client.parser.TorrentParser +import com.hippo.ehviewer.client.parser.TorrentResult import com.hippo.ehviewer.coil.imageRequest import com.hippo.ehviewer.coil.justDownload import com.hippo.ehviewer.coil.read @@ -204,7 +204,7 @@ class GalleryDetailScene : BaseScene(), DownloadInfoListener { private var favButtonText by mutableStateOf("") private var getDetailError by mutableStateOf("") - private var mTorrentList: List? = null + private var mTorrentList: TorrentResult? = null private var requestStoragePermissionLauncher = registerForActivityResult( ActivityResultContracts.RequestPermission(), ) { result: Boolean -> @@ -1696,7 +1696,7 @@ class GalleryDetailScene : BaseScene(), DownloadInfoListener { } } - private fun bind(data: List?) { + private fun bind(data: TorrentResult?) { if (null == mDialog || null == mProgressView || null == mErrorText || null == mListView) { return } diff --git a/app/src/main/rust/Cargo.toml b/app/src/main/rust/Cargo.toml index e4ee8d3c1..2ba4f3df5 100644 --- a/app/src/main/rust/Cargo.toml +++ b/app/src/main/rust/Cargo.toml @@ -6,7 +6,6 @@ version = "0.0.0" crate_type = ["cdylib"] [dependencies] -jni = "*" tl = "*" log = "*" android_logger = "*" @@ -14,6 +13,8 @@ apply = "*" regex = "*" once_cell = "*" quick-xml = "*" +jnix = "*" +jnix-macros = "*" [profile.release] strip = true diff --git a/app/src/main/rust/src/lib.rs b/app/src/main/rust/src/lib.rs index 14fdab9a8..b11e7ed56 100644 --- a/app/src/main/rust/src/lib.rs +++ b/app/src/main/rust/src/lib.rs @@ -1,6 +1,7 @@ extern crate android_logger; extern crate apply; -extern crate jni; +extern crate jnix; +extern crate jnix_macros; extern crate log; extern crate once_cell; extern crate quick_xml; @@ -9,9 +10,11 @@ extern crate tl; use android_logger::Config; use apply::Also; -use jni::objects::{JClass, JList, JObject, JObjectArray, JString}; -use jni::sys::{jint, jintArray, JavaVM, JNI_VERSION_1_6}; -use jni::JNIEnv; +use jnix::jni::objects::{JClass, JList, JObject, JString}; +use jnix::jni::sys::{jint, jintArray, jobjectArray, JavaVM, JNI_VERSION_1_6}; +use jnix::jni::JNIEnv; +use jnix::{IntoJava, JnixEnv}; +use jnix_macros::IntoJava; use quick_xml::escape::unescape; use std::ffi::c_void; use tl::{Parser, VDom}; @@ -23,11 +26,23 @@ macro_rules! regex { }}; } +#[derive(Default, IntoJava)] +#[jnix(package = "com.hippo.ehviewer.client.parser")] +pub struct Torrent { + posted: String, + size: String, + seeds: i32, + peers: i32, + downloads: i32, + url: String, + name: String, +} + fn parse_jni_string(env: &mut JNIEnv, str: &JString, mut f: F) -> Option where - F: FnMut(&VDom, &Parser, &mut JNIEnv) -> Option, + F: FnMut(&VDom, &Parser, &JNIEnv) -> Option, { - let html = env.get_string(str).ok()?; + let html = env.get_string(*str).ok()?; let dom = tl::parse(html.to_str().ok()?, tl::ParserOptions::default()).ok()?; let parser = dom.parser(); Some(f(&dom, parser, env)?) @@ -53,8 +68,7 @@ pub extern "system" fn Java_com_hippo_ehviewer_client_parser_HomeParserKt_parseL .unwrap_or(vec![]); env.new_int_array(3) .unwrap() - .also(|it| env.set_int_array_region(&it, 0, &vec).unwrap()) - .into_raw() + .also(|it| env.set_int_array_region(*it, 0, &vec).unwrap()) } #[no_mangle] @@ -62,7 +76,7 @@ pub extern "system" fn Java_com_hippo_ehviewer_client_parser_FavoritesParserKt_p mut env: JNIEnv, _class: JClass, input: JString, - str: JObjectArray, + str: jobjectArray, ) -> jintArray { let vec = parse_jni_string(&mut env, &input, |dom, parser, env| { let fp = dom.get_elements_by_class_name("fp"); @@ -76,7 +90,7 @@ pub extern "system" fn Java_com_hippo_ehviewer_client_parser_FavoritesParserKt_p let children = top.top(); let cat = children[5].get(parser)?.inner_text(parser); let name = unescape(&cat).ok()?; - env.set_object_array_element(&str, i as i32, env.new_string(name.trim()).ok()?) + env.set_object_array_element(str, i as i32, env.new_string(name.trim()).ok()?) .ok()?; Some( children[1] @@ -96,8 +110,7 @@ pub extern "system" fn Java_com_hippo_ehviewer_client_parser_FavoritesParserKt_p .unwrap_or(vec![]); env.new_int_array(10) .unwrap() - .also(|it| env.set_int_array_region(&it, 0, &vec).unwrap()) - .into_raw() + .also(|it| env.set_int_array_region(*it, 0, &vec).unwrap()) } #[no_mangle] @@ -107,28 +120,34 @@ pub extern "system" fn Java_com_hippo_ehviewer_client_parser_TorrentParserKt_par input: JString, list: JObject, ) { - let list = JList::from_env(&mut env, &list).unwrap(); - let string = env.find_class("java/lang/String").unwrap(); - parse_jni_string(&mut env, &input, |dom, parser, env| { - let _: Vec = dom + let env2 = JnixEnv::from(env); + let r = parse_jni_string(&mut env, &input, |dom, parser, _env| { + let vec: Vec = dom .query_selector("table")? .filter_map(|e| { - let array = env.new_object_array(7, &string, JObject::null()).ok()?; let html = e.get(parser)?.inner_html(parser); let reg = regex!(" ([0-9-]+) [0-9:]+[\\s\\S]+ ([0-9.]+ [KMGT]B)[\\s\\S]+ ([0-9]+)[\\s\\S]+ ([0-9]+)[\\s\\S]+ ([0-9]+)[\\s\\S]+([^<]+)[\\s\\S]+onclick=\"document.location='([^\"]+)'[^<]+>([^<]+)"); let grp = reg.captures(&html)?; let name = unescape(&grp[8]).ok()?; - let vec = vec![&grp[1], &grp[2], &grp[3], &grp[4], &grp[5], &grp[7], &name]; - vec.iter().enumerate().for_each(|(i, &n)| { - env.set_object_array_element(&array, i as i32, env.new_string(n).unwrap()) - .unwrap(); - }); - list.add(env, &array).ok()?; - None + Some( + Torrent { + posted: grp[1].to_string(), + size: grp[2].to_string(), + seeds: grp[3].parse().ok()?, + peers: grp[4].parse().ok()?, + downloads: grp[5].parse().ok()?, + url: grp[7].to_string(), + name: name.to_string(), + }.into_java(&env2).forget() + ) }) .collect(); - Some(0) - }); + Some(vec) + }).unwrap(); + let list = JList::from_env(&env, list).ok().unwrap(); + for i in r { + list.add(i).ok().unwrap() + } } #[no_mangle]