-
- return document.select("article > div div img")
- .filterNot { !it.hasAttr("data-original") || it.attr("data-original").contains("blank.gif") }
- .mapIndexed { i, img -> Page(i, "", img.attr("abs:data-original")) }
+ val script = document.select("script:containsData(html_data)").firstOrNull()?.data() ?: throw Exception("script not found")
+
+ return htmlDataRegex.findAll(script).map { it.groupValues[1] }
+ .asIterable()
+ .flatMap { it.split(".") }
+ .joinToString("") { it.toIntOrNull(16)?.toChar()?.toString() ?: "" }
+ .let { Jsoup.parse(it) }
+ .select("img[alt]")
+ .mapIndexed { i, img -> Page(i, "", if (img.hasAttr("abs:data-original")) img.attr("abs:data-original") else img.attr("abs:content")) }
}
override fun latestUpdatesSelector() = popularMangaSelector()
@@ -224,7 +256,27 @@ open class NewToki(override val name: String, private val defaultBaseUrl: String
}
}
+ val latestExperimentPref = androidx.preference.CheckBoxPreference(screen.context).apply {
+ key = EXPERIMENTAL_LATEST_PREF_TITLE
+ title = EXPERIMENTAL_LATEST_PREF_TITLE
+ summary = EXPERIMENTAL_LATEST_PREF_SUMMARY
+
+ setOnPreferenceChangeListener { _, newValue ->
+ try {
+ val res = preferences.edit().putBoolean(EXPERIMENTAL_LATEST_PREF, newValue as Boolean).commit()
+ Toast.makeText(screen.context, RESTART_TACHIYOMI, Toast.LENGTH_LONG).show()
+ res
+ } catch (e: Exception) {
+ e.printStackTrace()
+ false
+ }
+ }
+ }
+
screen.addPreference(baseUrlPref)
+ if (name == "ManaToki") {
+ screen.addPreference(latestExperimentPref)
+ }
}
override fun setupPreferenceScreen(screen: PreferenceScreen) {
@@ -248,10 +300,39 @@ open class NewToki(override val name: String, private val defaultBaseUrl: String
}
}
+ val latestExperimentPref = CheckBoxPreference(screen.context).apply {
+ key = EXPERIMENTAL_LATEST_PREF_TITLE
+ title = EXPERIMENTAL_LATEST_PREF_TITLE
+ summary = EXPERIMENTAL_LATEST_PREF_SUMMARY
+
+ setOnPreferenceChangeListener { _, newValue ->
+ try {
+ val res = preferences.edit().putBoolean(EXPERIMENTAL_LATEST_PREF, newValue as Boolean).commit()
+ Toast.makeText(screen.context, RESTART_TACHIYOMI, Toast.LENGTH_LONG).show()
+ res
+ } catch (e: Exception) {
+ e.printStackTrace()
+ false
+ }
+ }
+ }
+
screen.addPreference(baseUrlPref)
+ if (name == "ManaToki") {
+ screen.addPreference(latestExperimentPref)
+ }
+ }
+
+ protected fun getUrlPath(orig: String): String {
+ return try {
+ URI(orig).path
+ } catch (e: URISyntaxException) {
+ orig
+ }
}
private fun getPrefBaseUrl(): String = preferences.getString(BASE_URL_PREF, defaultBaseUrl)!!
+ protected fun getExperimentLatest(): Boolean = preferences.getBoolean(EXPERIMENTAL_LATEST_PREF, false)
companion object {
private const val BASE_URL_PREF_TITLE = "Override BaseUrl"
@@ -259,6 +340,11 @@ open class NewToki(override val name: String, private val defaultBaseUrl: String
private const val BASE_URL_PREF_SUMMARY = "For temporary uses. Update extension will erase this setting."
private const val RESTART_TACHIYOMI = "Restart Tachiyomi to apply new setting."
+ // Setting: Experimental Latest Fetcher
+ private const val EXPERIMENTAL_LATEST_PREF_TITLE = "Enable Latest (Experimental)"
+ private const val EXPERIMENTAL_LATEST_PREF = "fetchLatestExperiment"
+ private const val EXPERIMENTAL_LATEST_PREF_SUMMARY = "Fetch Latest Manga using Latest Chapters. May has duplicates, Also requires LOTS OF requests (70 per page)"
+
const val PREFIX_ID_SEARCH = "id:"
}
}
diff --git a/src/ko/newtoki/src/eu/kanade/tachiyomi/extension/ko/newtoki/NewTokiFactory.kt b/src/ko/newtoki/src/eu/kanade/tachiyomi/extension/ko/newtoki/NewTokiFactory.kt
index 9e1d03fcb..e09c7d36a 100644
--- a/src/ko/newtoki/src/eu/kanade/tachiyomi/extension/ko/newtoki/NewTokiFactory.kt
+++ b/src/ko/newtoki/src/eu/kanade/tachiyomi/extension/ko/newtoki/NewTokiFactory.kt
@@ -5,15 +5,17 @@ import eu.kanade.tachiyomi.source.Source
import eu.kanade.tachiyomi.source.SourceFactory
import eu.kanade.tachiyomi.source.model.Filter
import eu.kanade.tachiyomi.source.model.FilterList
-import eu.kanade.tachiyomi.source.model.Page
+import eu.kanade.tachiyomi.source.model.MangasPage
+import eu.kanade.tachiyomi.util.asJsoup
+import okhttp3.CacheControl
import okhttp3.HttpUrl
import okhttp3.Request
-import org.jsoup.Jsoup
-import org.jsoup.nodes.Document
+import okhttp3.Response
import java.security.MessageDigest
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
+import java.util.concurrent.TimeUnit.DAYS
/**
* Source changes domain names every few days (e.g. newtoki31.net to newtoki32.net)
@@ -35,6 +37,32 @@ class NewTokiFactory : SourceFactory {
class NewTokiManga : NewToki("ManaToki", "https://manatoki$domainNumber.net", "comic") {
// / ! DO NOT CHANGE THIS ! Only the site name changed from newtoki.
override val id by lazy { generateSourceId("NewToki", lang, versionId) }
+ override val supportsLatest by lazy { getExperimentLatest() }
+
+ // this does 70 request per page....
+ override fun latestUpdatesSelector() = ".media.post-list p > a"
+ override fun latestUpdatesRequest(page: Int) = GET("$baseUrl/page/update?hid=update&page=$page")
+ override fun latestUpdatesNextPageSelector() = "nav.pg_wrap > .pg > strong"
+ override fun latestUpdatesParse(response: Response): MangasPage {
+ val document = response.asJsoup()
+
+ // given cache time to prevent repeated lots of request in latest.
+ val cacheControl = CacheControl.Builder().maxAge(14, DAYS).maxStale(14, DAYS).build()
+ val mangas = document.select(latestUpdatesSelector()).map { element ->
+ val url = element.attr("abs:href")
+ val manga = mangaDetailsParse(client.newCall(GET(url, cache = cacheControl)).execute())
+ manga.url = getUrlPath(url)
+ manga
+ }
+
+ val hasNextPage = try {
+ !document.select(popularMangaNextPageSelector()).text().contains("10")
+ } catch (_: Exception) {
+ false
+ }
+
+ return MangasPage(mangas, hasNextPage)
+ }
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
val url = HttpUrl.parse("$baseUrl/comic" + (if (page > 1) "/p$page" else ""))!!.newBuilder()
@@ -151,6 +179,7 @@ class NewTokiManga : NewToki("ManaToki", "https://manatoki$domainNumber.net", "c
)
override fun getFilterList() = FilterList(
+ Filter.Header("Filter can't use with query"),
SearchPublishTypeList(),
SearchJaumTypeList(),
SearchGenreTypeList()
@@ -165,7 +194,7 @@ class NewTokiWebtoon : NewToki("NewToki", "https://newtoki$domainNumber.com", "w
val url = HttpUrl.parse("$baseUrl/webtoon" + (if (page > 1) "/p$page" else ""))!!.newBuilder()
filters.forEach { filter ->
when (filter) {
- is SearchTypeList -> {
+ is SearchTargetTypeList -> {
if (filter.state > 0) {
url.addQueryParameter("toon", filter.values[filter.state])
}
@@ -173,31 +202,103 @@ class NewTokiWebtoon : NewToki("NewToki", "https://newtoki$domainNumber.com", "w
}
}
+ // Imcompatible with Other Search Parametor
if (!query.isBlank()) {
url.addQueryParameter("stx", query)
+ } else {
+ filters.forEach { filter ->
+ when (filter) {
+ is SearchYoilTypeList -> {
+ if (filter.state > 0) {
+ url.addQueryParameter("yoil", filter.values[filter.state])
+ }
+ }
+
+ is SearchJaumTypeList -> {
+ if (filter.state > 0) {
+ url.addQueryParameter("jaum", filter.values[filter.state])
+ }
+ }
+
+ is SearchGenreTypeList -> {
+ if (filter.state > 0) {
+ url.addQueryParameter("tag", filter.values[filter.state])
+ }
+ }
+ }
+ }
}
return GET(url.toString())
}
- private val htmlDataRegex = Regex("""html_data\+='([^']+)'""")
+ private class SearchTargetTypeList : Filter.Select