Jinmantiantang genre filtering in preferences and general code fixes (#5281)

* Add blocklist preference panel

* change thumbnail jpg size to 3:4

* misc code fix

* rename preference key

* update version number

* more comment

Co-authored-by: calion-m <>
This commit is contained in:
calion-m 2020-12-30 20:44:14 +08:00 committed by GitHub
parent a552a5267b
commit a71060c742
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 72 additions and 15 deletions

View File

@ -5,7 +5,7 @@ ext {
extName = 'Jinmantiantang' extName = 'Jinmantiantang'
pkgNameSuffix = 'zh.jinmantiantang' pkgNameSuffix = 'zh.jinmantiantang'
extClass = '.Jinmantiantang' extClass = '.Jinmantiantang'
extVersionCode = 9 extVersionCode = 10
libVersion = '1.2' libVersion = '1.2'
containsNsfw = true containsNsfw = true
} }

View File

@ -1,11 +1,16 @@
package eu.kanade.tachiyomi.extension.zh.jinmantiantang package eu.kanade.tachiyomi.extension.zh.jinmantiantang
import android.app.Application
import android.content.SharedPreferences
import android.graphics.Bitmap import android.graphics.Bitmap
import android.graphics.BitmapFactory import android.graphics.BitmapFactory
import android.graphics.Canvas import android.graphics.Canvas
import android.graphics.Rect import android.graphics.Rect
import androidx.preference.EditTextPreference
import androidx.preference.PreferenceScreen
import eu.kanade.tachiyomi.annotations.Nsfw import eu.kanade.tachiyomi.annotations.Nsfw
import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.source.ConfigurableSource
import eu.kanade.tachiyomi.source.model.Filter import eu.kanade.tachiyomi.source.model.Filter
import eu.kanade.tachiyomi.source.model.FilterList import eu.kanade.tachiyomi.source.model.FilterList
import eu.kanade.tachiyomi.source.model.Page import eu.kanade.tachiyomi.source.model.Page
@ -22,13 +27,18 @@ import okhttp3.ResponseBody
import org.jsoup.nodes.Document import org.jsoup.nodes.Document
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import org.jsoup.select.Elements import org.jsoup.select.Elements
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
import java.io.ByteArrayOutputStream import java.io.ByteArrayOutputStream
import java.io.InputStream import java.io.InputStream
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.Locale import java.util.Locale
import kotlin.math.floor
import android.support.v7.preference.EditTextPreference as LegacyEditTextPreference
import android.support.v7.preference.PreferenceScreen as LegacyPreferenceScreen
@Nsfw @Nsfw
class Jinmantiantang : ParsedHttpSource() { class Jinmantiantang : ConfigurableSource, ParsedHttpSource() {
override val baseUrl: String = "https://18comic5.biz" override val baseUrl: String = "https://18comic5.biz"
override val lang: String = "zh" override val lang: String = "zh"
@ -38,7 +48,7 @@ class Jinmantiantang : ParsedHttpSource() {
// 220980 // 220980
// 算法 html页面 1800 行左右 // 算法 html页面 1800 行左右
// 图片开始分割的ID编号 // 图片开始分割的ID编号
val scramble_id = 220980 private val scrambleId = 220980
// 对只有一章的漫画进行判断条件 // 对只有一章的漫画进行判断条件
private var chapterArea = "a[class=col btn btn-primary dropdown-toggle reading]" private var chapterArea = "a[class=col btn btn-primary dropdown-toggle reading]"
@ -49,7 +59,7 @@ class Jinmantiantang : ParsedHttpSource() {
val url = chain.request().url().toString() val url = chain.request().url().toString()
val response = chain.proceed(chain.request()) val response = chain.proceed(chain.request())
if (!url.contains("media/photos", ignoreCase = true)) return response // 对非漫画图片连接直接放行 if (!url.contains("media/photos", ignoreCase = true)) return response // 对非漫画图片连接直接放行
if (url.substring(url.indexOf("photos/") + 7, url.lastIndexOf("/")).toInt() < scramble_id) return response // 对在漫画章节ID为220980之前的图片未进行图片分割,直接放行 if (url.substring(url.indexOf("photos/") + 7, url.lastIndexOf("/")).toInt() < scrambleId) return response // 对在漫画章节ID为220980之前的图片未进行图片分割,直接放行
// 章节ID:220980(包含)之后的漫画(2020.10.27之后)图片进行了分割倒序处理 // 章节ID:220980(包含)之后的漫画(2020.10.27之后)图片进行了分割倒序处理
val res = response.body()!!.byteStream().use { val res = response.body()!!.byteStream().use {
decodeImage(it) decodeImage(it)
@ -70,20 +80,20 @@ class Jinmantiantang : ParsedHttpSource() {
// 水平分割10个小图 // 水平分割10个小图
val rows = 10 val rows = 10
// 未除尽像素 // 未除尽像素
var remainder = (height % rows) val remainder = (height % rows)
// 创建新的图片对象 // 创建新的图片对象
val resultBitmap = Bitmap.createBitmap(input.width, input.height, Bitmap.Config.ARGB_8888) val resultBitmap = Bitmap.createBitmap(input.width, input.height, Bitmap.Config.ARGB_8888)
val canvas = Canvas(resultBitmap) val canvas = Canvas(resultBitmap)
// 分割图片 // 分割图片
for (x in 0 until rows) { for (x in 0 until rows) {
// 分割算法(详情见html源码页的方法"function scramble_image(img)") // 分割算法(详情见html源码页的方法"function scramble_image(img)")
var copyH = Math.floor(height / rows.toDouble()).toInt() var copyH = floor(height / rows.toDouble()).toInt()
var py = copyH * (x) var py = copyH * (x)
var y = height - (copyH * (x + 1)) - remainder val y = height - (copyH * (x + 1)) - remainder
if (x == 0) { if (x == 0) {
copyH = copyH + remainder copyH += remainder
} else { } else {
py = py + remainder py += remainder
} }
// 要裁剪的区域 // 要裁剪的区域
val crop = Rect(0, y, width, y + copyH) val crop = Rect(0, y, width, y + copyH)
@ -103,12 +113,21 @@ class Jinmantiantang : ParsedHttpSource() {
return GET("$baseUrl/albums?o=mv&page=$page", headers) return GET("$baseUrl/albums?o=mv&page=$page", headers)
} }
override fun popularMangaNextPageSelector(): String? = "a.prevnext" override fun popularMangaNextPageSelector(): String = "a.prevnext"
override fun popularMangaSelector(): String = "div.col-xs-6.col-sm-6.col-md-4.col-lg-3.list-col div.well.well-sm" override fun popularMangaSelector(): String {
val baseSelector = "div.col-xs-6.col-sm-6.col-md-4.col-lg-3.list-col div.well.well-sm"
val removedGenres = preferences.getString("BLOCK_GENRES_LIST", "")!!.substringBefore("//").trim()
// Extra selector is jquery-like selector, it uses regex to match element.text().
// If string after 標籤 contains any word of removedGenres, the element would be ignored.
return if (removedGenres != "")
baseSelector + ":not(:matches((?i).*標籤: .*(${removedGenres.split(' ').joinToString("|")}).*))"
else
baseSelector
}
override fun popularMangaFromElement(element: Element): SManga = SManga.create().apply { override fun popularMangaFromElement(element: Element): SManga = SManga.create().apply {
title = element.select("span.video-title").text() title = element.select("span.video-title").text()
setUrlWithoutDomain(element.select("a").first().attr("href")) setUrlWithoutDomain(element.select("a").first().attr("href"))
thumbnail_url = element.select("img").attr("data-original").split("?")[0].replace("_3x4", "") thumbnail_url = element.select("img").attr("data-original").split("?")[0]
author = element.select("div.title-truncate").select("a").first().text() author = element.select("div.title-truncate").select("a").first().text()
} }
@ -117,7 +136,7 @@ class Jinmantiantang : ParsedHttpSource() {
return GET("$baseUrl/albums?o=mr&page=$page", headers) return GET("$baseUrl/albums?o=mr&page=$page", headers)
} }
override fun latestUpdatesNextPageSelector(): String? = popularMangaNextPageSelector() override fun latestUpdatesNextPageSelector(): String = popularMangaNextPageSelector()
override fun latestUpdatesSelector(): String = popularMangaSelector() override fun latestUpdatesSelector(): String = popularMangaSelector()
override fun latestUpdatesFromElement(element: Element): SManga = popularMangaFromElement(element) override fun latestUpdatesFromElement(element: Element): SManga = popularMangaFromElement(element)
@ -153,7 +172,7 @@ class Jinmantiantang : ParsedHttpSource() {
return GET(url.toString(), headers) return GET(url.toString(), headers)
} }
override fun searchMangaNextPageSelector(): String? = popularMangaNextPageSelector() override fun searchMangaNextPageSelector(): String = popularMangaNextPageSelector()
override fun searchMangaSelector(): String = popularMangaSelector() override fun searchMangaSelector(): String = popularMangaSelector()
override fun searchMangaFromElement(element: Element): SManga = popularMangaFromElement(element) override fun searchMangaFromElement(element: Element): SManga = popularMangaFromElement(element)
@ -164,7 +183,8 @@ class Jinmantiantang : ParsedHttpSource() {
override fun mangaDetailsParse(document: Document): SManga = SManga.create().apply { override fun mangaDetailsParse(document: Document): SManga = SManga.create().apply {
determineChapterInfo(document) determineChapterInfo(document)
title = document.select("div.panel-heading").select("div.pull-left").first().text() title = document.select("div.panel-heading").select("div.pull-left").first().text()
thumbnail_url = document.select("img.lazy_img.img-responsive").attr("src").split("?")[0].replace("_3x4", "") // keep thumbnail_url same as the one in popularMangaFromElement()
thumbnail_url = document.select("img.lazy_img.img-responsive").attr("src").split("?")[0].replace(".jpg", "_3x4.jpg")
author = selectAuthor(document) author = selectAuthor(document)
artist = author artist = author
genre = selectDetailsStatusAndGenre(document, 0).trim().split(" ").joinToString(", ") genre = selectDetailsStatusAndGenre(document, 0).trim().split(" ").joinToString(", ")
@ -389,4 +409,41 @@ class Jinmantiantang : ParsedHttpSource() {
Filter.Select<String>(displayName, vals.map { it.first }.toTypedArray(), defaultValue) { Filter.Select<String>(displayName, vals.map { it.first }.toTypedArray(), defaultValue) {
open fun toUriPart() = vals[state].second open fun toUriPart() = vals[state].second
} }
private val preferences: SharedPreferences by lazy {
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
}
private val BLOCK_PREF_TITLE = "屏蔽词列表"
private val BLOCK_PREF_DEFAULT = "// 例如 \"YAOI cos 扶他 毛絨絨 獵奇 韩漫 韓漫\", " +
"关键词之间用空格分离, 大小写不敏感, \"//\"后的字符会被忽略"
private val BLOCK_PREF_DIALOGTITLE = "关键词列表"
override fun setupPreferenceScreen(screen: PreferenceScreen) {
EditTextPreference(screen.context).apply {
key = "BLOCK_GENRES_LIST"
title = BLOCK_PREF_TITLE
setDefaultValue(BLOCK_PREF_DEFAULT)
dialogTitle = BLOCK_PREF_DIALOGTITLE
setOnPreferenceChangeListener { _, newValue ->
preferences.edit().putString("BLOCK_GENRES_LIST", newValue as String).commit()
}
}.let {
screen.addPreference(it)
}
}
override fun setupPreferenceScreen(screen: LegacyPreferenceScreen) {
LegacyEditTextPreference(screen.context).apply {
key = "BLOCK_GENRES_LIST"
title = BLOCK_PREF_TITLE
setDefaultValue(BLOCK_PREF_DEFAULT)
dialogTitle = BLOCK_PREF_DIALOGTITLE
setOnPreferenceChangeListener { _, newValue ->
preferences.edit().putString("BLOCK_GENRES_LIST", newValue as String).commit()
}
}.let {
screen.addPreference(it)
}
}
} }