Cleanup EhFilter
This commit is contained in:
1 parent
969c9a66af
commit
004d8a4bff
4 files changed
+65
-178
No files matched your search
@@ -20,6 +20,7 @@ import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.os.Environment;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.hippo.ehviewer.client.exception.ParseException;
|
||||
@@ -134,7 +135,7 @@ public class AppConfig {
|
||||
return FileUtils.createTempFile(getTempDir(), null);
|
||||
}
|
||||
|
||||
public static void saveParseErrorBody(ParseException e) {
|
||||
public static void saveParseErrorBody(@NonNull ParseException e) {
|
||||
File dir = getExternalParseErrorDir();
|
||||
if (null == dir) {
|
||||
return;
|
||||
@@ -150,9 +151,7 @@ public class AppConfig {
|
||||
os.write(message.getBytes(StandardCharsets.UTF_8));
|
||||
os.write('\n');
|
||||
}
|
||||
if (null != body) {
|
||||
os.write(body.getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
os.write(body.getBytes(StandardCharsets.UTF_8));
|
||||
os.flush();
|
||||
} catch (IOException e1) {
|
||||
// Ignore
|
||||
|
||||
@@ -25,7 +25,6 @@ import com.hippo.ehviewer.Settings
|
||||
import com.hippo.ehviewer.client.data.GalleryCommentList
|
||||
import com.hippo.ehviewer.client.data.GalleryDetail
|
||||
import com.hippo.ehviewer.client.data.GalleryInfo
|
||||
import com.hippo.ehviewer.client.data.GalleryPreview
|
||||
import com.hippo.ehviewer.client.exception.EhException
|
||||
import com.hippo.ehviewer.client.exception.ParseException
|
||||
import com.hippo.ehviewer.client.parser.ArchiveParser
|
||||
@@ -49,6 +48,7 @@ import com.hippo.ehviewer.client.parser.VoteTagParser
|
||||
import com.hippo.ehviewer.dailycheck.showEventNotification
|
||||
import com.hippo.ehviewer.dailycheck.today
|
||||
import com.hippo.network.StatusCodeException
|
||||
import kotlinx.coroutines.CancellationException
|
||||
import kotlinx.coroutines.delay
|
||||
import moe.tarsin.coroutines.runSuspendCatching
|
||||
import okhttp3.Headers
|
||||
@@ -72,9 +72,11 @@ private const val SAD_PANDA_LENGTH = "9615"
|
||||
private const val KOKOMADE_URL = "https://exhentai.org/img/kokomade.jpg"
|
||||
private const val U_CONFIG_TEXT = "Selected Profile"
|
||||
private val MEDIA_TYPE_JPEG: MediaType = "image/jpeg".toMediaType()
|
||||
private var sEhFilter = EhFilter
|
||||
|
||||
private fun rethrowExactly(code: Int, headers: Headers, body: String, e: Throwable) {
|
||||
private fun rethrowExactly(code: Int, headers: Headers, body: String, e: Throwable): Nothing {
|
||||
// Don't translate coroutine cancellation
|
||||
if (e is CancellationException) throw e
|
||||
|
||||
// Check sad panda
|
||||
if (SAD_PANDA_DISPOSITION == headers["Content-Disposition"] && SAD_PANDA_TYPE == headers["Content-Type"] && SAD_PANDA_LENGTH == headers["Content-Length"]) {
|
||||
throw EhException("Sad Panda")
|
||||
@@ -106,12 +108,10 @@ private fun rethrowExactly(code: Int, headers: Headers, body: String, e: Throwab
|
||||
if (e is ParseException) {
|
||||
if (body.isEmpty()) {
|
||||
throw EhException(GetText.getString(R.string.error_empty_html))
|
||||
} else if (!body.contains("<")) {
|
||||
} else if ("<" !in body) {
|
||||
throw EhException(body)
|
||||
} else {
|
||||
if (Settings.saveParseErrorBody) {
|
||||
AppConfig.saveParseErrorBody(e as ParseException?)
|
||||
}
|
||||
if (Settings.saveParseErrorBody) AppConfig.saveParseErrorBody(e)
|
||||
throw EhException(GetText.getString(R.string.error_parse_error))
|
||||
}
|
||||
}
|
||||
@@ -124,11 +124,11 @@ private suspend inline fun <T> Request.executeAndParsingWith(block: String.() ->
|
||||
Log.d(TAG, url.toString())
|
||||
return okHttpClient.newCall(this).executeAsync().use { response ->
|
||||
val body = response.body.string()
|
||||
runCatching {
|
||||
try {
|
||||
block(body)
|
||||
}.onFailure {
|
||||
rethrowExactly(response.code, response.headers, body, it)
|
||||
}.getOrThrow()
|
||||
} catch (e: Exception) {
|
||||
rethrowExactly(response.code, response.headers, body, e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -149,15 +149,10 @@ object EhEngine {
|
||||
}.executeAndParsingWith(SignInParser::parse)
|
||||
}
|
||||
|
||||
private suspend fun fillGalleryList(
|
||||
list: MutableList<GalleryInfo>,
|
||||
url: String,
|
||||
filter: Boolean,
|
||||
) {
|
||||
private suspend fun fillGalleryList(list: MutableList<GalleryInfo>, url: String, filter: Boolean) {
|
||||
// Filter title and uploader
|
||||
if (filter) {
|
||||
list.removeAll { !sEhFilter.filterTitle(it) || !sEhFilter.filterUploader(it) }
|
||||
}
|
||||
if (filter) list.removeAll { EhFilter.filterTitle(it) || EhFilter.filterUploader(it) }
|
||||
|
||||
var hasTags = false
|
||||
var hasPages = false
|
||||
var hasRated = false
|
||||
@@ -172,57 +167,26 @@ object EhEngine {
|
||||
hasRated = true
|
||||
}
|
||||
}
|
||||
val needApi = filter && sEhFilter.needTags() && !hasTags ||
|
||||
Settings.showGalleryPages && !hasPages || hasRated
|
||||
if (needApi) {
|
||||
fillGalleryListByApi(list, url)
|
||||
val needApi = filter && EhFilter.needTags() && !hasTags || Settings.showGalleryPages && !hasPages || hasRated
|
||||
if (needApi) fillGalleryListByApi(list, url)
|
||||
|
||||
// Filter tag, thumbnail mode need filter uploader again
|
||||
if (filter) list.removeAll { EhFilter.filterUploader(it) || EhFilter.filterTag(it) || EhFilter.filterTagNamespace(it) }
|
||||
}
|
||||
|
||||
suspend fun getGalleryList(url: String) = ehRequest(url, EhUrl.referer)
|
||||
.executeAndParsingWith(GalleryListParser::parse)
|
||||
.apply { fillGalleryList(galleryInfoList, url, true) }
|
||||
|
||||
suspend fun fillGalleryListByApi(galleryInfoList: List<GalleryInfo>, referer: String) = galleryInfoList.chunked(MAX_REQUEST_SIZE).forEach { doFillGalleryListByApi(it, referer) }
|
||||
|
||||
private suspend fun doFillGalleryListByApi(galleryInfoList: List<GalleryInfo>, referer: String) = ehRequest(EhUrl.apiUrl, referer, EhUrl.origin) {
|
||||
jsonBody {
|
||||
put("method", "gdata")
|
||||
array("gidlist") { galleryInfoList.forEach { put(jsonArrayOf(it.gid, it.token)) } }
|
||||
put("namespace", 1)
|
||||
}
|
||||
|
||||
// Filter tag
|
||||
if (filter) {
|
||||
// Thumbnail mode need filter uploader again
|
||||
list.removeAll {
|
||||
!sEhFilter.filterUploader(it) || !sEhFilter.filterTag(it) ||
|
||||
!sEhFilter.filterTagNamespace(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun getGalleryList(url: String): GalleryListParser.Result {
|
||||
return ehRequest(url, EhUrl.referer).executeAndParsingWith(GalleryListParser::parse)
|
||||
.apply { fillGalleryList(galleryInfoList, url, true) }
|
||||
}
|
||||
|
||||
suspend fun fillGalleryListByApi(
|
||||
galleryInfoList: List<GalleryInfo>,
|
||||
referer: String,
|
||||
): List<GalleryInfo> {
|
||||
val requestItems: MutableList<GalleryInfo> = ArrayList(MAX_REQUEST_SIZE)
|
||||
var i = 0
|
||||
val size = galleryInfoList.size
|
||||
while (i < size) {
|
||||
requestItems.add(galleryInfoList[i])
|
||||
if (requestItems.size == MAX_REQUEST_SIZE || i == size - 1) {
|
||||
doFillGalleryListByApi(requestItems, referer)
|
||||
requestItems.clear()
|
||||
}
|
||||
i++
|
||||
}
|
||||
return galleryInfoList
|
||||
}
|
||||
|
||||
private suspend fun doFillGalleryListByApi(
|
||||
galleryInfoList: List<GalleryInfo>,
|
||||
referer: String,
|
||||
) {
|
||||
return ehRequest(EhUrl.apiUrl, referer, EhUrl.origin) {
|
||||
jsonBody {
|
||||
put("method", "gdata")
|
||||
array("gidlist") { galleryInfoList.forEach { put(jsonArrayOf(it.gid, it.token)) } }
|
||||
put("namespace", 1)
|
||||
}
|
||||
}.executeAndParsingWith { GalleryApiParser.parse(this, galleryInfoList) }
|
||||
}
|
||||
}.executeAndParsingWith { GalleryApiParser.parse(this, galleryInfoList) }
|
||||
|
||||
suspend fun getGalleryDetail(url: String): GalleryDetail {
|
||||
return ehRequest(url, EhUrl.referer).executeAndParsingWith {
|
||||
@@ -234,10 +198,8 @@ object EhEngine {
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun getPreviewList(url: String): Pair<List<GalleryPreview>, Int> {
|
||||
return ehRequest(url, EhUrl.referer).executeAndParsingWith {
|
||||
GalleryDetailParser.parsePreviewList(this) to GalleryDetailParser.parsePreviewPages(this)
|
||||
}
|
||||
suspend fun getPreviewList(url: String) = ehRequest(url, EhUrl.referer).executeAndParsingWith {
|
||||
GalleryDetailParser.parsePreviewList(this) to GalleryDetailParser.parsePreviewPages(this)
|
||||
}
|
||||
|
||||
@Throws(Throwable::class)
|
||||
@@ -360,24 +322,14 @@ object EhEngine {
|
||||
dstCat: Int,
|
||||
): FavoritesParser.Result {
|
||||
val catStr: String = when (dstCat) {
|
||||
-1 -> {
|
||||
"delete"
|
||||
}
|
||||
|
||||
in 0..9 -> {
|
||||
"fav$dstCat"
|
||||
}
|
||||
|
||||
else -> {
|
||||
throw EhException("Invalid dstCat: $dstCat")
|
||||
}
|
||||
-1 -> { "delete" }
|
||||
in 0..9 -> { "fav$dstCat" }
|
||||
else -> { throw EhException("Invalid dstCat: $dstCat") }
|
||||
}
|
||||
return ehRequest(url, url, EhUrl.origin) {
|
||||
form {
|
||||
add("ddact", catStr)
|
||||
for (gid in gidArray) {
|
||||
add("modifygids[]", gid.toString())
|
||||
}
|
||||
for (gid in gidArray) add("modifygids[]", gid.toString())
|
||||
add("apply", "Apply")
|
||||
}
|
||||
}.executeAndParsingWith(FavoritesParser::parse).apply { fillGalleryList(galleryInfoList, url, false) }
|
||||
|
||||
@@ -130,56 +130,25 @@ object EhFilter {
|
||||
}
|
||||
}
|
||||
|
||||
private inline fun <T> Iterable<T>.contains(predicate: (T) -> Boolean) = firstOrNull(predicate) != null
|
||||
|
||||
private inline fun <T> Array<T>.contains(predicate: (T) -> Boolean) = firstOrNull(predicate) != null
|
||||
|
||||
@Synchronized
|
||||
fun needTags(): Boolean {
|
||||
return 0 != mTagFilterList.size || 0 != mTagNamespaceFilterList.size
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
fun filterTitle(info: GalleryInfo?): Boolean {
|
||||
if (null == info) {
|
||||
return false
|
||||
}
|
||||
|
||||
// Title
|
||||
val title = info.title
|
||||
val filters: List<Filter> = mTitleFilterList
|
||||
if (null != title && filters.isNotEmpty()) {
|
||||
var i = 0
|
||||
val n = filters.size
|
||||
while (i < n) {
|
||||
if (filters[i].enable!! && title.lowercase(Locale.getDefault()).contains(
|
||||
filters[i].text!!,
|
||||
)
|
||||
) {
|
||||
return false
|
||||
}
|
||||
i++
|
||||
}
|
||||
}
|
||||
return true
|
||||
fun filterTitle(info: GalleryInfo): Boolean {
|
||||
val title = info.title ?: return false
|
||||
return mTitleFilterList.contains { it.enable!! && it.text!! in title.lowercase() }
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
fun filterUploader(info: GalleryInfo?): Boolean {
|
||||
if (null == info) {
|
||||
return false
|
||||
}
|
||||
|
||||
// Uploader
|
||||
val uploader = info.uploader
|
||||
val filters: List<Filter> = mUploaderFilterList
|
||||
if (null != uploader && filters.isNotEmpty()) {
|
||||
var i = 0
|
||||
val n = filters.size
|
||||
while (i < n) {
|
||||
if (filters[i].enable!! && uploader == filters[i].text) {
|
||||
return false
|
||||
}
|
||||
i++
|
||||
}
|
||||
}
|
||||
return true
|
||||
fun filterUploader(info: GalleryInfo): Boolean {
|
||||
val uploader = info.uploader ?: return false
|
||||
return mUploaderFilterList.contains { it.enable!! && it.text == uploader }
|
||||
}
|
||||
|
||||
private fun matchTag(tag: String?, filter: String?): Boolean {
|
||||
@@ -216,27 +185,9 @@ object EhFilter {
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
fun filterTag(info: GalleryInfo?): Boolean {
|
||||
if (null == info) {
|
||||
return false
|
||||
}
|
||||
|
||||
// Tag
|
||||
val tags = info.simpleTags
|
||||
val filters: List<Filter> = mTagFilterList
|
||||
if (null != tags && filters.isNotEmpty()) {
|
||||
for (tag in tags) {
|
||||
var i = 0
|
||||
val n = filters.size
|
||||
while (i < n) {
|
||||
if (filters[i].enable!! && matchTag(tag, filters[i].text)) {
|
||||
return false
|
||||
}
|
||||
i++
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
fun filterTag(info: GalleryInfo): Boolean {
|
||||
val tags = info.simpleTags ?: return false
|
||||
return tags.contains { tag -> mTagFilterList.contains { it.enable!! && matchTag(tag, it.text) } }
|
||||
}
|
||||
|
||||
private fun matchTagNamespace(tag: String?, filter: String?): Boolean {
|
||||
@@ -254,25 +205,9 @@ object EhFilter {
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
fun filterTagNamespace(info: GalleryInfo?): Boolean {
|
||||
if (null == info) {
|
||||
return false
|
||||
}
|
||||
val tags = info.simpleTags
|
||||
val filters: List<Filter> = mTagNamespaceFilterList
|
||||
if (null != tags && filters.isNotEmpty()) {
|
||||
for (tag in tags) {
|
||||
var i = 0
|
||||
val n = filters.size
|
||||
while (i < n) {
|
||||
if (filters[i].enable!! && matchTagNamespace(tag, filters[i].text)) {
|
||||
return false
|
||||
}
|
||||
i++
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
fun filterTagNamespace(info: GalleryInfo): Boolean {
|
||||
val tags = info.simpleTags ?: return false
|
||||
return tags.contains { tag -> mTagNamespaceFilterList.contains { it.enable!! && matchTagNamespace(tag, it.text) } }
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
|
||||
@@ -76,12 +76,13 @@ class RestoreDownloadPreference @JvmOverloads constructor(
|
||||
private suspend fun doRealWork(): List<GalleryInfo>? {
|
||||
val dir = Settings.downloadLocation ?: return null
|
||||
val files = dir.listFiles() ?: return null
|
||||
val restoreItemList = files.mapNotNull { getRestoreItem(it) }
|
||||
return runSuspendCatching {
|
||||
fillGalleryListByApi(restoreItemList, EhUrl.referer)
|
||||
}.onFailure {
|
||||
it.printStackTrace()
|
||||
}.getOrNull()
|
||||
return files.mapNotNull { getRestoreItem(it) }.apply {
|
||||
runSuspendCatching {
|
||||
fillGalleryListByApi(this, EhUrl.referer)
|
||||
}.onFailure {
|
||||
it.printStackTrace()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class RestoreItem : BaseGalleryInfo() {
|
||||
|
||||
Reference in new issue
Block a user