Migrate profile parser to rust
This commit is contained in:
1 parent
60cd7728e6
commit
000a932ff1
8 files changed
+106
-61
No files matched your search
@@ -38,7 +38,6 @@ import com.hippo.ehviewer.client.parser.ArchiveParser
|
||||
import com.hippo.ehviewer.client.parser.EventPaneParser
|
||||
import com.hippo.ehviewer.client.parser.FavParserResult
|
||||
import com.hippo.ehviewer.client.parser.FavoritesParser
|
||||
import com.hippo.ehviewer.client.parser.ForumsParser
|
||||
import com.hippo.ehviewer.client.parser.GalleryApiParser
|
||||
import com.hippo.ehviewer.client.parser.GalleryDetailParser
|
||||
import com.hippo.ehviewer.client.parser.GalleryListParser
|
||||
@@ -209,8 +208,8 @@ object EhEngine {
|
||||
.fetchUsingAsText { if (parse) EventPaneParser.parse(this) else null }
|
||||
|
||||
suspend fun getProfile(): ProfileParser.Result {
|
||||
val url = ehRequest(EhUrl.URL_FORUMS).fetchUsingAsText(ForumsParser::parse)
|
||||
return ehRequest(url, EhUrl.URL_FORUMS).fetchUsingAsText(ProfileParser::parse)
|
||||
val url = ehRequest(EhUrl.URL_FORUMS).fetchUsingAsByteBuffer(ProfileParser::parseProfileUrl)
|
||||
return ehRequest(url, EhUrl.URL_FORUMS).fetchUsingAsByteBuffer(ProfileParser::parse)
|
||||
}
|
||||
|
||||
suspend fun getUConfig(url: String = EhUrl.uConfigUrl) {
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
import arrow.core.Either
|
||||
import arrow.core.getOrElse
|
||||
import com.hippo.ehviewer.client.EhUrl
|
||||
import com.hippo.ehviewer.client.exception.NotLoggedInException
|
||||
import org.jsoup.Jsoup
|
||||
|
||||
object ForumsParser {
|
||||
fun parse(body: String): String = Either.catch {
|
||||
val d = Jsoup.parse(body, EhUrl.URL_FORUMS)
|
||||
val userlinks = d.getElementById("userlinks")
|
||||
val child = userlinks!!.child(0).child(0).child(0)
|
||||
child.attr("href")
|
||||
}.getOrElse {
|
||||
throw NotLoggedInException()
|
||||
}
|
||||
}
|
||||
@@ -15,36 +15,28 @@
|
||||
*/
|
||||
package com.hippo.ehviewer.client.parser
|
||||
|
||||
import arrow.core.Either
|
||||
import arrow.core.Either.Companion.catch
|
||||
import arrow.core.getOrElse
|
||||
import com.hippo.ehviewer.client.EhUrl
|
||||
import com.hippo.ehviewer.client.exception.ParseException
|
||||
import eu.kanade.tachiyomi.util.system.logcat
|
||||
import org.jsoup.Jsoup
|
||||
import java.nio.ByteBuffer
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
object ProfileParser {
|
||||
fun parse(body: String): Result = Either.catch {
|
||||
val d = Jsoup.parse(body)
|
||||
val profilename = d.getElementById("profilename")
|
||||
val displayName = profilename!!.child(0).text()
|
||||
val avatar = Either.catch {
|
||||
val avatar =
|
||||
profilename.nextElementSibling()!!.nextElementSibling()!!.child(0).attr("src")
|
||||
if (avatar.isEmpty()) {
|
||||
null
|
||||
} else if (!avatar.startsWith("http")) {
|
||||
EhUrl.URL_FORUMS + avatar
|
||||
} else {
|
||||
avatar
|
||||
}
|
||||
}.getOrElse {
|
||||
logcat { "No avatar" }
|
||||
null
|
||||
}
|
||||
Result(displayName, avatar)
|
||||
fun parse(body: ByteBuffer) = catch {
|
||||
unmarshalParsingAs<Result>(body, ::parseProfile)
|
||||
}.getOrElse {
|
||||
throw ParseException("Parse forums error")
|
||||
throw ParseException("Failed to parse profile", it)
|
||||
}
|
||||
|
||||
class Result(val displayName: String?, val avatar: String?)
|
||||
fun parseProfileUrl(body: ByteBuffer) = catch {
|
||||
unmarshalParsingAs<String>(body, ::parseProfileUrl)
|
||||
}.getOrElse {
|
||||
throw ParseException("Failed to parse profile url", it)
|
||||
}
|
||||
|
||||
@Serializable
|
||||
data class Result(val displayName: String, val avatar: String?)
|
||||
|
||||
private external fun parseProfile(body: ByteBuffer, size: Int = body.limit()): Int
|
||||
private external fun parseProfileUrl(body: ByteBuffer, size: Int = body.limit()): Int
|
||||
}
|
||||
@@ -5,6 +5,7 @@ use crate::parser::config::parse_fav_cat;
|
||||
use crate::parser::fav::parse_fav;
|
||||
use crate::parser::home::parse_limit;
|
||||
use crate::parser::list::parse_info_list;
|
||||
use crate::parser::profile::{parse_profile, parse_profile_url};
|
||||
use crate::parser::torrent::parse_torrent_list;
|
||||
use crate::EhError;
|
||||
use android_logger::Config;
|
||||
@@ -94,6 +95,24 @@ pub fn parseArchiveUrl(mut env: JNIEnv, _class: JClass, buffer: JByteBuffer, lim
|
||||
})
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[allow(non_snake_case)]
|
||||
#[jni_fn("com.hippo.ehviewer.client.parser.ProfileParser")]
|
||||
pub fn parseProfileUrl(mut env: JNIEnv, _class: JClass, buffer: JByteBuffer, limit: jint) -> jint {
|
||||
parse_marshal_inplace(&mut env, buffer, limit, |dom, _| {
|
||||
parse_profile_url(dom, dom.parser())
|
||||
})
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[allow(non_snake_case)]
|
||||
#[jni_fn("com.hippo.ehviewer.client.parser.ProfileParser")]
|
||||
pub fn parseProfile(mut env: JNIEnv, _class: JClass, buffer: JByteBuffer, limit: jint) -> jint {
|
||||
parse_marshal_inplace(&mut env, buffer, limit, |dom, _| {
|
||||
parse_profile(dom, dom.parser())
|
||||
})
|
||||
}
|
||||
|
||||
fn deref_mut_direct_bytebuffer<'local>(
|
||||
env: &JNIEnv,
|
||||
buffer: JByteBuffer<'local>,
|
||||
|
||||
@@ -3,6 +3,7 @@ pub mod config;
|
||||
pub mod fav;
|
||||
pub mod home;
|
||||
pub mod list;
|
||||
pub mod profile;
|
||||
mod test_parser;
|
||||
pub mod torrent;
|
||||
mod utils;
|
||||
@@ -0,0 +1,46 @@
|
||||
use crate::{get_node_handle_attr, get_tag_attr, select_first, EhError};
|
||||
use anyhow::{Context, Result};
|
||||
use serde::Serialize;
|
||||
use tl::{Parser, VDom};
|
||||
|
||||
const HOST_FORUMS: &str = "https://forums.e-hentai.org";
|
||||
|
||||
#[derive(Serialize, Debug)]
|
||||
#[allow(non_snake_case)]
|
||||
pub struct Profile {
|
||||
pub displayName: String,
|
||||
pub avatar: Option<String>,
|
||||
}
|
||||
|
||||
pub fn parse_profile_url(dom: &VDom, parser: &Parser) -> Result<String> {
|
||||
dom.get_element_by_id("userlinks")
|
||||
.and_then(|n| {
|
||||
let mut iter = n.get(parser)?.as_tag()?.query_selector(parser, "a")?;
|
||||
get_node_handle_attr(&iter.next()?, parser, "href").map(str::to_string)
|
||||
})
|
||||
.context(EhError::NeedLogin)
|
||||
}
|
||||
|
||||
pub fn parse_profile(dom: &VDom, parser: &Parser) -> Result<Profile> {
|
||||
dom.get_elements_by_class_name("row1")
|
||||
.next()
|
||||
.and_then(|n| {
|
||||
let mut iter = n.get(parser)?.as_tag()?.query_selector(parser, "div")?;
|
||||
let display_name = iter.next()?.get(parser)?.inner_text(parser).to_string();
|
||||
let avatar = iter.next().and_then(|n| {
|
||||
let img = select_first(n.get(parser)?.as_tag()?, parser, "img")?;
|
||||
get_tag_attr(img, "src").map(|src| {
|
||||
if src.starts_with("http") {
|
||||
src.to_string()
|
||||
} else {
|
||||
format!("{}{}", HOST_FORUMS, src)
|
||||
}
|
||||
})
|
||||
});
|
||||
Some(Profile {
|
||||
displayName: display_name,
|
||||
avatar,
|
||||
})
|
||||
})
|
||||
.context("Failed to parse profile")
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
mod tests {
|
||||
use crate::parser::archive::{parse_archive_url, parse_archives_with_funds};
|
||||
use crate::parser::list::parse_info_list;
|
||||
use crate::parser::profile::{parse_profile, parse_profile_url};
|
||||
use reqwest::get;
|
||||
use std::fs;
|
||||
use tl::ParserOptions;
|
||||
@@ -34,4 +35,21 @@ mod tests {
|
||||
parse_archive_url(&dom, dom.parser(), &body).expect("Failed to parse archives");
|
||||
assert_eq!(result, Some("https://0?start=1".to_string()));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_parse_profile() {
|
||||
let body =
|
||||
fs::read_to_string("test_data/profile_url.html").expect("Failed to read html file");
|
||||
let dom = tl::parse(&body, ParserOptions::default()).expect("Failed to parse html");
|
||||
let result = parse_profile_url(&dom, dom.parser()).expect("Failed to parse profile url");
|
||||
let resp = get(result).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_profile(&dom, dom.parser()).expect("Failed to parse profile");
|
||||
assert_eq!(result.displayName, "Tenboro".to_string());
|
||||
assert_eq!(
|
||||
result.avatar,
|
||||
Some("https://forums.e-hentai.org/ehgt/jdk_180.png".to_string())
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
<div id="userlinks">
|
||||
<p class="home"><b>Logged in as: <a href="https://forums.e-hentai.org/index.php?showuser=6">Tenboro</a></b> ( <a href="https://forums.e-hentai.org/index.php?act=Login&CODE=03">Log Out</a> )</p>
|
||||
</div>
|
||||
Reference in new issue
Block a user