From cbebdb542d97ab796f25a78667ea0328ea993b7a Mon Sep 17 00:00:00 2001 From: tarsin Date: Wed, 14 Jun 2023 16:20:18 +0800 Subject: [PATCH] Move torrent parser to rust --- .../ehviewer/client/parser/TorrentParser.kt | 38 +++---------------- app/src/main/rust/Cargo.toml | 2 + app/src/main/rust/src/lib.rs | 28 +++++++++++++- 3 files changed, 34 insertions(+), 34 deletions(-) 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 347063060..6c3305905 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 @@ -15,42 +15,16 @@ */ package com.hippo.ehviewer.client.parser -import org.jsoup.Jsoup -import java.util.regex.Pattern - object TorrentParser { - private val PATTERN_TORRENT = - Pattern.compile(" ([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='([^\"]+)'[^<]+>([^<]+)") - fun parse(body: String): List { - val torrentList = ArrayList() - val d = Jsoup.parse(body) - val es = d.select("form>div>table") - for (e in es) { - val m = PATTERN_TORRENT.matcher(e.html()) - if (m.find()) { - val posted = m.group(1)!! - val size = m.group(2)!! - val seeds = m.group(3)!!.toInt() - val peers = m.group(4)!!.toInt() - val downloads = m.group(5)!!.toInt() - val url = ParserUtils.trim(m.group(7)) - val name = ParserUtils.trim(m.group(8)) - torrentList.add(Result(posted, size, seeds, peers, downloads, url, name)) - } - } - return torrentList + 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( - private val posted: String, - private val size: String, - private val seeds: Int, - private val peers: Int, - private val downloads: Int, - val url: String, - val name: String, - ) { + 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]" } } + +private external fun parseTorrent(body: String, list: List>) diff --git a/app/src/main/rust/Cargo.toml b/app/src/main/rust/Cargo.toml index 5756b58a3..47ebe84fa 100644 --- a/app/src/main/rust/Cargo.toml +++ b/app/src/main/rust/Cargo.toml @@ -11,3 +11,5 @@ tl = "*" log = "*" android_logger = "*" apply = "*" +regex = "*" +once_cell = "*" diff --git a/app/src/main/rust/src/lib.rs b/app/src/main/rust/src/lib.rs index d78d7af1b..6ec6a3dd8 100644 --- a/app/src/main/rust/src/lib.rs +++ b/app/src/main/rust/src/lib.rs @@ -2,6 +2,8 @@ extern crate android_logger; extern crate apply; extern crate jni; extern crate log; +extern crate once_cell; +extern crate regex; extern crate tl; use std::ffi::c_void; @@ -9,12 +11,16 @@ use std::ffi::c_void; use android_logger::Config; use apply::Also; use jni::JNIEnv; -use jni::objects::{JClass, JObjectArray, JString}; +use jni::objects::{JClass, JList, JObject, JObjectArray, JString}; use jni::sys::{JavaVM, jint, jintArray, JNI_VERSION_1_6}; +use once_cell::sync::Lazy; +use regex::Regex; use tl::{Parser, VDom}; +static TORRENT_REGEX: Lazy = Lazy::new(|| { Regex::new(" ([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='([^\"]+)'[^<]+>([^<]+)").unwrap() }); + fn parse_jni_string(env: &mut JNIEnv, str: &JString, mut f: F) -> Option - where F: FnMut(&VDom, &Parser, &JNIEnv) -> Option { + where F: FnMut(&VDom, &Parser, &mut JNIEnv) -> Option { let html = env.get_string(str).ok()?; let dom = tl::parse(html.to_str().ok()?, tl::ParserOptions::default()).ok()?; let parser = dom.parser(); @@ -48,6 +54,24 @@ pub extern "system" fn Java_com_hippo_ehviewer_client_parser_FavoritesParserKt_p env.new_int_array(10).unwrap().also(|it| env.set_int_array_region(&it, 0, &vec).unwrap()).into_raw() } +#[no_mangle] +pub extern "system" fn Java_com_hippo_ehviewer_client_parser_TorrentParserKt_parseTorrent(mut env: JNIEnv, _class: JClass, 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.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 grp = TORRENT_REGEX.captures(&html)?; + let vec = vec![&grp[1], &grp[2], &grp[3], &grp[4], &grp[5], &grp[7], &grp[8]]; + 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 + }).collect(); + Some(0) + }); +} + #[no_mangle] pub extern "system" fn JNI_OnLoad(_: JavaVM, _: *mut c_void) -> jint { android_logger::init_once(Config::default());