Update FoolSlide multisrc (#8301)

* FoolSlide code cleanup

* Add adult content preference

* Update The Cat Scans URL & add icons

* Update Hyakuro URL

* Update Mangatellers URL & add icons

* Update English HNI-Scantrad URL

* Move LetItGo Scans to FoolSlide
This commit is contained in:
ObserverOfTime 2021-07-29 19:20:43 +03:00 committed by GitHub
parent 959f64ff8c
commit 95c8d93798
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
30 changed files with 128 additions and 202 deletions

View File

@ -1,5 +0,0 @@
package eu.kanade.tachiyomi.extension.en.letitgoscans
import eu.kanade.tachiyomi.multisrc.comicake.ComiCake
class LetItGoScans : ComiCake("LetItGo Scans", "https://reader.letitgo.scans.today", "en", "/")

View File

@ -1,30 +1,29 @@
package eu.kanade.tachiyomi.extension.pt.baixarhentai package eu.kanade.tachiyomi.extension.pt.baixarhentai
import eu.kanade.tachiyomi.multisrc.foolslide.FoolSlide import androidx.preference.PreferenceScreen
import eu.kanade.tachiyomi.annotations.Nsfw import eu.kanade.tachiyomi.annotations.Nsfw
import eu.kanade.tachiyomi.lib.ratelimit.RateLimitInterceptor import eu.kanade.tachiyomi.lib.ratelimit.RateLimitInterceptor
import eu.kanade.tachiyomi.multisrc.foolslide.FoolSlide
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import okhttp3.OkHttpClient
import org.jsoup.nodes.Document import org.jsoup.nodes.Document
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
@Nsfw @Nsfw
class BaixarHentai : FoolSlide( class BaixarHentai : FoolSlide("Baixar Hentai", "https://leitura.baixarhentai.net", "pt-BR") {
"Baixar Hentai",
"https://leitura.baixarhentai.net",
"pt-BR"
) {
// Hardcode the id because the language wasn't specific. // Hardcode the id because the language wasn't specific.
override val id: Long = 8908032188831949972 override val id = 8908032188831949972
override val client: OkHttpClient = super.client.newBuilder() override val client = super.client.newBuilder()
.addInterceptor(RateLimitInterceptor(1, 2, TimeUnit.SECONDS)) .addInterceptor(RateLimitInterceptor(1, 2, TimeUnit.SECONDS))
.build() .build()
override fun mangaDetailsParse(document: Document): SManga { override fun mangaDetailsParse(document: Document) = SManga.create().apply {
return SManga.create().apply {
title = document.select("h1.title").text() title = document.select("h1.title").text()
thumbnail_url = getDetailsThumbnail(document, "div.title a") thumbnail_url = getDetailsThumbnail(document, "div.title a")
} }
}
// Always show adult content
override val allowAdult = true
override fun setupPreferenceScreen(screen: PreferenceScreen) {}
} }

View File

@ -1,34 +1,28 @@
package eu.kanade.tachiyomi.extension.all.foolslidecustomizable package eu.kanade.tachiyomi.extension.all.foolslidecustomizable
import eu.kanade.tachiyomi.multisrc.foolslide.FoolSlide
import eu.kanade.tachiyomi.source.Source
import eu.kanade.tachiyomi.source.SourceFactory
import android.app.Application
import android.content.SharedPreferences
import android.widget.Toast import android.widget.Toast
import androidx.preference.EditTextPreference
import androidx.preference.PreferenceScreen
import eu.kanade.tachiyomi.BuildConfig import eu.kanade.tachiyomi.BuildConfig
import eu.kanade.tachiyomi.source.ConfigurableSource import eu.kanade.tachiyomi.multisrc.foolslide.FoolSlide
import uy.kohesive.injekt.Injekt import eu.kanade.tachiyomi.source.SourceFactory
import uy.kohesive.injekt.api.get
class FoolSlideCustomizableFactory : SourceFactory { class FoolSlideCustomizableFactory : SourceFactory {
override fun createSources(): List<Source> = listOf( override fun createSources() = listOf(FoolSlideCustomizable())
FoolSlideCustomizable(),
)
} }
class FoolSlideCustomizable : ConfigurableSource, FoolSlide("FoolSlide Customizable", "", "other") {
override val baseUrl: String by lazy { getPrefBaseUrl() }
private val preferences: SharedPreferences by lazy { class FoolSlideCustomizable : FoolSlide("FoolSlide Customizable", "", "other") {
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000) override val baseUrl: String by lazy {
preferences.getString(BASE_URL_PREF, DEFAULT_BASEURL)!!.substringBefore("/directory")
} }
override fun setupPreferenceScreen(screen: androidx.preference.PreferenceScreen) { override fun setupPreferenceScreen(screen: PreferenceScreen) {
val baseUrlPref = androidx.preference.EditTextPreference(screen.context).apply { super.setupPreferenceScreen(screen)
EditTextPreference(screen.context).apply {
key = BASE_URL_PREF_TITLE key = BASE_URL_PREF_TITLE
title = BASE_URL_PREF_TITLE title = BASE_URL_PREF_TITLE
summary = BASE_URL_PREF_SUMMARY summary = BASE_URL_PREF_SUMMARY
this.setDefaultValue(DEFAULT_BASEURL) setDefaultValue(DEFAULT_BASEURL)
dialogTitle = BASE_URL_PREF_TITLE dialogTitle = BASE_URL_PREF_TITLE
dialogMessage = "Default: $DEFAULT_BASEURL" dialogMessage = "Default: $DEFAULT_BASEURL"
@ -42,17 +36,9 @@ class FoolSlideCustomizable : ConfigurableSource, FoolSlide("FoolSlide Customiza
false false
} }
} }
}.let(screen::addPreference)
} }
screen.addPreference(baseUrlPref)
}
/**
* Tell the user to include /directory/ in the URL even though we remove it
* To increase the chance they input a usable URL
*/
private fun getPrefBaseUrl() = preferences.getString(BASE_URL_PREF, DEFAULT_BASEURL)!!.substringBefore("/directory")
companion object { companion object {
private const val DEFAULT_BASEURL = "https://127.0.0.1" private const val DEFAULT_BASEURL = "https://127.0.0.1"
private const val BASE_URL_PREF_TITLE = "Example URL: https://domain.com/path_to/directory/" private const val BASE_URL_PREF_TITLE = "Example URL: https://domain.com/path_to/directory/"

View File

@ -1,50 +1,19 @@
package eu.kanade.tachiyomi.extension.all.hniscantrad package eu.kanade.tachiyomi.extension.all.hniscantrad
import eu.kanade.tachiyomi.multisrc.foolslide.FoolSlide import eu.kanade.tachiyomi.multisrc.foolslide.FoolSlide
import eu.kanade.tachiyomi.source.Source
import eu.kanade.tachiyomi.source.SourceFactory import eu.kanade.tachiyomi.source.SourceFactory
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.source.model.FilterList
import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga
import okhttp3.Request
import okhttp3.Response import okhttp3.Response
import org.jsoup.nodes.Element
class HNIScantradFactory : SourceFactory { class HNIScantradFactory : SourceFactory {
override fun createSources(): List<Source> = listOf( override fun createSources() = listOf(HNIScantradFR(), HNIScantradEN())
HNIScantradFR(),
HNIScantradEN(),
)
} }
class HNIScantradFR : FoolSlide("HNI-Scantrad", "https://hni-scantrad.com", "fr", "/lel")
class HNIScantradEN : FoolSlide("HNI-Scantrad", "https://hni-scantrad.com", "en", "/eng/lel") { class HNIScantradFR : FoolSlide("HNI-Scantrad", "https://hni-scantrad.com", "fr", "/lel") {
override val supportsLatest = false override fun chapterListParse(response: Response) =
override fun popularMangaRequest(page: Int) = GET(baseUrl + urlModifier, headers) super.chapterListParse(response).filter { "/fr/" in it.url }
override fun popularMangaSelector() = "div.listed" }
override fun popularMangaFromElement(element: Element): SManga {
return SManga.create().apply { class HNIScantradEN : FoolSlide("HNI-Scantrad", "https://hni-scantrad.com", "en", "/lel") {
element.select("a:has(h3)").let { override fun chapterListParse(response: Response) =
title = it.text() super.chapterListParse(response).filter { "/en-us/" in it.url }
setUrlWithoutDomain(it.attr("abs:href"))
}
thumbnail_url = element.select("img").attr("abs:src")
}
}
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request = GET("$baseUrl$urlModifier/?manga=${query.replace(" ", "+")}")
override fun searchMangaSelector(): String = popularMangaSelector()
override fun searchMangaFromElement(element: Element): SManga = popularMangaFromElement(element)
override fun chapterListSelector() = "div.theList > a"
override fun chapterFromElement(element: Element): SChapter {
return SChapter.create().apply {
name = element.select("div.chapter b").text()
setUrlWithoutDomain(element.attr("abs:href"))
}
}
override fun pageListParse(response: Response): List<Page> {
return Regex("""imageArray\[\d+]='(.*)'""").findAll(response.body!!.string()).toList().mapIndexed { i, mr ->
Page(i, "", "$baseUrl$urlModifier/${mr.groupValues[1]}")
}
}
} }

View File

@ -4,12 +4,10 @@ import eu.kanade.tachiyomi.multisrc.foolslide.FoolSlide
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import org.jsoup.nodes.Document import org.jsoup.nodes.Document
class Hyakuro : FoolSlide("Hyakuro", "https://hyakuro.com/reader/", "en") { class Hyakuro : FoolSlide("Hyakuro", "https://hyakuro.com", "en", "/reader") {
override fun mangaDetailsParse(document: Document): SManga { override fun mangaDetailsParse(document: Document) = SManga.create().apply {
return SManga.create().apply {
description = document.select("$mangaDetailsInfoSelector li:has(b:contains(description))") description = document.select("$mangaDetailsInfoSelector li:has(b:contains(description))")
.first()?.ownText()?.substringAfter(":") .first()?.ownText()?.substringAfter(":")
thumbnail_url = getDetailsThumbnail(document) thumbnail_url = getDetailsThumbnail(document)
} }
}
} }

View File

@ -5,11 +5,9 @@ import eu.kanade.tachiyomi.source.model.SManga
import org.jsoup.nodes.Document import org.jsoup.nodes.Document
class KireiCake : FoolSlide("Kirei Cake", "https://reader.kireicake.com", "en") { class KireiCake : FoolSlide("Kirei Cake", "https://reader.kireicake.com", "en") {
override fun mangaDetailsParse(document: Document): SManga { override fun mangaDetailsParse(document: Document) = SManga.create().apply {
return SManga.create().apply {
description = document.select("$mangaDetailsInfoSelector li:has(b:contains(description))") description = document.select("$mangaDetailsInfoSelector li:has(b:contains(description))")
.first()?.ownText()?.substringAfter(":") .first()?.ownText()?.substringAfter(":")
thumbnail_url = getDetailsThumbnail(document) thumbnail_url = getDetailsThumbnail(document)
} }
}
} }

View File

@ -1,18 +1,15 @@
package eu.kanade.tachiyomi.extension.fr.lecercleduscan package eu.kanade.tachiyomi.extension.fr.lecercleduscan
import eu.kanade.tachiyomi.multisrc.foolslide.FoolSlide import eu.kanade.tachiyomi.multisrc.foolslide.FoolSlide
import java.util.Locale
class LeCercleDuScan : FoolSlide("Le Cercle du Scan", "https://lel.lecercleduscan.com", "fr") { class LeCercleDuScan : FoolSlide("Le Cercle du Scan", "https://lel.lecercleduscan.com", "fr") {
override fun parseChapterDate(date: String) = super.parseChapterDate(
override fun parseChapterDate(date: String): Long? { when (val lcDate = date.toLowerCase(Locale.FRENCH)) {
val dateToEnglish = when (val lcDate = date.toLowerCase()) {
"hier" -> "yesterday" "hier" -> "yesterday"
"aujourd'hui" -> "today" "aujourd'hui" -> "today"
"demain" -> "tomorrow" "demain" -> "tomorrow"
else -> lcDate else -> lcDate
} }
)
return super.parseChapterDate(dateToEnglish)
}
} }

View File

Before

Width:  |  Height:  |  Size: 355 KiB

After

Width:  |  Height:  |  Size: 355 KiB

View File

@ -5,22 +5,17 @@ import eu.kanade.tachiyomi.source.model.SManga
import org.jsoup.nodes.Document import org.jsoup.nodes.Document
class LupiTeam : FoolSlide("LupiTeam", "https://lupiteam.net", "it", "/reader") { class LupiTeam : FoolSlide("LupiTeam", "https://lupiteam.net", "it", "/reader") {
override fun mangaDetailsParse(document: Document): SManga { override fun mangaDetailsParse(document: Document) = SManga.create().apply {
val infoElement = document.select(mangaDetailsInfoSelector).first().text() val infoElement = document.select(mangaDetailsInfoSelector).first().text()
author = infoElement.substringAfter("Autore: ").substringBefore("Artista: ")
val manga = SManga.create() artist = infoElement.substringAfter("Artista: ").substringBefore("Target: ")
manga.author = infoElement.substringAfter("Autore: ").substringBefore("Artista: ") status = when (infoElement.substringAfter("Stato: ").substringBefore("Trama: ").take(8)) {
manga.artist = infoElement.substringAfter("Artista: ").substringBefore("Target: ")
val stato = infoElement.substringAfter("Stato: ").substringBefore("Trama: ").substring(0, 8)
manga.status = when (stato) {
"In corso" -> SManga.ONGOING "In corso" -> SManga.ONGOING
"Completa" -> SManga.COMPLETED "Completa" -> SManga.COMPLETED
"Licenzia" -> SManga.LICENSED "Licenzia" -> SManga.LICENSED
else -> SManga.UNKNOWN else -> SManga.UNKNOWN
} }
manga.description = infoElement.substringAfter("Trama: ") description = infoElement.substringAfter("Trama: ")
manga.thumbnail_url = getDetailsThumbnail(document) thumbnail_url = getDetailsThumbnail(document)
return manga
} }
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

View File

@ -1,11 +1,5 @@
package eu.kanade.tachiyomi.extension.en.mangatellers package eu.kanade.tachiyomi.extension.en.mangatellers
import eu.kanade.tachiyomi.multisrc.foolslide.FoolSlide import eu.kanade.tachiyomi.multisrc.foolslide.FoolSlide
import eu.kanade.tachiyomi.network.GET
import okhttp3.Request
class Mangatellers : FoolSlide("Mangatellers", "http://www.mangatellers.gr", "en", "/reader/reader") { class Mangatellers : FoolSlide("Mangatellers", "https://reader.mangatellers.gr", "en")
override fun popularMangaRequest(page: Int): Request {
return GET("$baseUrl$urlModifier/list/$page/", headers)
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

View File

@ -12,7 +12,6 @@ class ComiCakeGenerator : ThemeSourceGenerator {
override val baseVersionCode: Int = 1 override val baseVersionCode: Int = 1
override val sources = listOf( override val sources = listOf(
SingleLang("LetItGo Scans", "https://reader.letitgo.scans.today", "en"),
SingleLang("WhimSubs", "https://whimsubs.xyz", "en") SingleLang("WhimSubs", "https://whimsubs.xyz", "en")
) )

View File

@ -1,7 +1,13 @@
package eu.kanade.tachiyomi.multisrc.foolslide package eu.kanade.tachiyomi.multisrc.foolslide
import android.app.Application
import android.os.Build
import androidx.preference.CheckBoxPreference
import androidx.preference.PreferenceScreen
import eu.kanade.tachiyomi.BuildConfig
import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.network.POST import eu.kanade.tachiyomi.network.POST
import eu.kanade.tachiyomi.source.ConfigurableSource
import eu.kanade.tachiyomi.source.model.FilterList import eu.kanade.tachiyomi.source.model.FilterList
import eu.kanade.tachiyomi.source.model.MangasPage import eu.kanade.tachiyomi.source.model.MangasPage
import eu.kanade.tachiyomi.source.model.Page import eu.kanade.tachiyomi.source.model.Page
@ -17,26 +23,24 @@ import okhttp3.Request
import okhttp3.Response import okhttp3.Response
import org.jsoup.nodes.Document import org.jsoup.nodes.Document
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
import java.text.ParseException import java.text.ParseException
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.Calendar import java.util.Calendar
import java.util.Date import java.util.Date
import java.util.HashSet
import java.util.Locale import java.util.Locale
abstract class FoolSlide( abstract class FoolSlide(
override val name: String, override val name: String,
override val baseUrl: String, override val baseUrl: String,
override val lang: String, override val lang: String,
val urlModifier: String = "" open val urlModifier: String = ""
) : ParsedHttpSource() { ) : ConfigurableSource, ParsedHttpSource() {
protected open val dedupeLatestUpdates = true
override val supportsLatest = true override val supportsLatest = true
private val json: Json by injectLazy() private val json by lazy { Injekt.get<Json>() }
override fun popularMangaSelector() = "div.group" override fun popularMangaSelector() = "div.group"
@ -44,48 +48,39 @@ abstract class FoolSlide(
return GET("$baseUrl$urlModifier/directory/$page/", headers) return GET("$baseUrl$urlModifier/directory/$page/", headers)
} }
val latestUpdatesUrls = HashSet<String>() private val latestUpdatesUrls = mutableSetOf<String>()
override fun latestUpdatesParse(response: Response): MangasPage { override fun latestUpdatesParse(response: Response): MangasPage {
val mp = super.latestUpdatesParse(response) val mp = super.latestUpdatesParse(response)
return if (dedupeLatestUpdates) { return mp.copy(
val mangas = mp.mangas.distinctBy { it.url }.filterNot { latestUpdatesUrls.contains(it.url) } mp.mangas.distinctBy { it.url }.filter {
latestUpdatesUrls.addAll(mangas.map { it.url }) latestUpdatesUrls.add(it.url)
MangasPage(mangas, mp.hasNextPage) }
} else mp )
} }
override fun latestUpdatesSelector() = "div.group" override fun latestUpdatesSelector() = "div.group"
override fun latestUpdatesRequest(page: Int): Request { override fun latestUpdatesRequest(page: Int): Request {
if (page == 1) { if (page == 1) latestUpdatesUrls.clear()
latestUpdatesUrls.clear()
}
return GET("$baseUrl$urlModifier/latest/$page/") return GET("$baseUrl$urlModifier/latest/$page/")
} }
override fun popularMangaFromElement(element: Element): SManga { override fun popularMangaFromElement(element: Element) = SManga.create().apply {
val manga = SManga.create()
element.select("a[title]").first().let { element.select("a[title]").first().let {
manga.setUrlWithoutDomain(it.attr("href")) setUrlWithoutDomain(it.attr("href"))
manga.title = it.text() title = it.text()
} }
element.select("img").first()?.let { element.select("img").first()?.let {
manga.thumbnail_url = it.absUrl("src").replace("/thumb_", "/") thumbnail_url = it.absUrl("src").replace("/thumb_", "/")
}
} }
return manga override fun latestUpdatesFromElement(element: Element) = SManga.create().apply {
}
override fun latestUpdatesFromElement(element: Element): SManga {
val manga = SManga.create()
element.select("a[title]").first().let { element.select("a[title]").first().let {
manga.setUrlWithoutDomain(it.attr("href")) setUrlWithoutDomain(it.attr("href"))
manga.title = it.text() title = it.text()
} }
return manga
} }
override fun popularMangaNextPageSelector() = "div.next" override fun popularMangaNextPageSelector() = "div.next"
@ -94,11 +89,8 @@ abstract class FoolSlide(
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
val searchHeaders = headersBuilder().add("Content-Type", "application/x-www-form-urlencoded").build() val searchHeaders = headersBuilder().add("Content-Type", "application/x-www-form-urlencoded").build()
val form = FormBody.Builder().add("search", query).build()
val form = FormBody.Builder() return POST("$baseUrl$urlModifier/search/", searchHeaders, form)
.add("search", query)
return POST("$baseUrl$urlModifier/search/", searchHeaders, form.build())
} }
override fun searchMangaSelector() = "div.group" override fun searchMangaSelector() = "div.group"
@ -116,18 +108,17 @@ abstract class FoolSlide(
override fun mangaDetailsRequest(manga: SManga) = allowAdult(super.mangaDetailsRequest(manga)) override fun mangaDetailsRequest(manga: SManga) = allowAdult(super.mangaDetailsRequest(manga))
open val mangaDetailsInfoSelector = "div.info" protected open val mangaDetailsInfoSelector = "div.info"
// if there's no image on the details page, get the first page of the first chapter // if there's no image on the details page, get the first page of the first chapter
fun getDetailsThumbnail(document: Document, urlSelector: String = chapterUrlSelector): String? { protected fun getDetailsThumbnail(document: Document, urlSelector: String = chapterUrlSelector): String? {
return document.select("div.thumbnail img, table.thumb img").firstOrNull()?.attr("abs:src") return document.select("div.thumbnail img, table.thumb img").firstOrNull()?.attr("abs:src")
?: document.select(chapterListSelector()).last().select(urlSelector).attr("abs:href") ?: document.select(chapterListSelector()).last().select(urlSelector).attr("abs:href")
.let { url -> client.newCall(allowAdult(GET(url, headers))).execute() } .let { url -> client.newCall(allowAdult(GET(url))).execute() }
.let { response -> pageListParse(response).first().imageUrl } .let { response -> pageListParse(response).first().imageUrl }
} }
override fun mangaDetailsParse(document: Document): SManga { override fun mangaDetailsParse(document: Document) = SManga.create().apply {
return SManga.create().apply {
document.select(mangaDetailsInfoSelector).firstOrNull()?.html()?.let { infoHtml -> document.select(mangaDetailsInfoSelector).firstOrNull()?.html()?.let { infoHtml ->
author = Regex("""(?i)(Author|Autore)</b>:\s?([^\n<]*)[\n<]""").find(infoHtml)?.groupValues?.get(2) author = Regex("""(?i)(Author|Autore)</b>:\s?([^\n<]*)[\n<]""").find(infoHtml)?.groupValues?.get(2)
artist = Regex("""Artist</b>:\s?([^\n<]*)[\n<]""").find(infoHtml)?.groupValues?.get(1) artist = Regex("""Artist</b>:\s?([^\n<]*)[\n<]""").find(infoHtml)?.groupValues?.get(1)
@ -135,42 +126,34 @@ abstract class FoolSlide(
} }
thumbnail_url = getDetailsThumbnail(document) thumbnail_url = getDetailsThumbnail(document)
} }
}
/** protected open val allowAdult: Boolean
* Transform a GET request into a POST request that automatically authorizes all adult content get() = preferences.getBoolean("adult", true)
*/
private fun allowAdult(request: Request) = allowAdult(request.url.toString())
private fun allowAdult(url: String): Request { private fun allowAdult(request: Request): Request {
return POST( val form = FormBody.Builder().add("adult", allowAdult.toString()).build()
url, return POST(request.url.toString(), headers, form)
body = FormBody.Builder()
.add("adult", "true")
.build()
)
} }
override fun chapterListRequest(manga: SManga) = allowAdult(super.chapterListRequest(manga)) override fun chapterListRequest(manga: SManga) = allowAdult(super.chapterListRequest(manga))
override fun chapterListSelector() = "div.group div.element, div.list div.element" override fun chapterListSelector() = "div.group div.element, div.list div.element"
open val chapterDateSelector = "div.meta_r" protected open val chapterDateSelector = "div.meta_r"
open val chapterUrlSelector = "a[title]" protected open val chapterUrlSelector = "a[title]"
override fun chapterFromElement(element: Element): SChapter { override fun chapterFromElement(element: Element) = SChapter.create().apply {
val urlElement = element.select(chapterUrlSelector).first() val urlElement = element.select(chapterUrlSelector).first()
val dateElement = element.select(chapterDateSelector).first() val dateElement = element.select(chapterDateSelector).first()
val chapter = SChapter.create() setUrlWithoutDomain(urlElement.attr("href"))
chapter.setUrlWithoutDomain(urlElement.attr("href")) name = urlElement.text()
chapter.name = urlElement.text() date_upload = dateElement.text()?.let {
chapter.date_upload = dateElement.text()?.let { parseChapterDate(it.substringAfter(", ")) } parseChapterDate(it.substringAfter(", "))
?: 0 } ?: 0
return chapter
} }
open fun parseChapterDate(date: String): Long? { protected open fun parseChapterDate(date: String): Long? {
val lcDate = date.toLowerCase(Locale.ROOT) val lcDate = date.toLowerCase(Locale.ROOT)
if (lcDate.endsWith(" ago")) if (lcDate.endsWith(" ago"))
parseRelativeDate(lcDate)?.let { return it } parseRelativeDate(lcDate)?.let { return it }
@ -279,19 +262,33 @@ abstract class FoolSlide(
val doc = document.toString() val doc = document.toString()
val jsonStr = doc.substringAfter("var pages = ").substringBefore(";") val jsonStr = doc.substringAfter("var pages = ").substringBefore(";")
val pages = json.parseToJsonElement(jsonStr).jsonArray val pages = json.parseToJsonElement(jsonStr).jsonArray
return pages.mapIndexed { i, jsonEl -> return pages.mapIndexed { i, jsonEl ->
// Create dummy element to resolve relative URL // Create dummy element to resolve relative URL
val absUrl = document.createElement("a") val absUrl = document.createElement("a")
.attr("href", jsonEl.jsonObject["url"]!!.jsonPrimitive.content) .attr("href", jsonEl.jsonObject["url"]!!.jsonPrimitive.content)
.absUrl("href") .absUrl("href")
Page(i, "", absUrl) Page(i, "", absUrl)
} }
} }
override fun imageUrlParse(document: Document) = throw UnsupportedOperationException("Not used") override fun imageUrlParse(document: Document) = throw UnsupportedOperationException("Not used")
protected val preferences by lazy {
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)!!
}
override fun setupPreferenceScreen(screen: PreferenceScreen) {
CheckBoxPreference(screen.context).apply {
key = "adult"
summary = "Show adult content"
setDefaultValue(true)
setOnPreferenceChangeListener { _, newValue ->
preferences.edit().putBoolean(key, newValue as Boolean).commit()
}
}.let(screen::addPreference)
}
companion object { companion object {
private val ORDINAL_SUFFIXES = listOf("st", "nd", "rd", "th") private val ORDINAL_SUFFIXES = listOf("st", "nd", "rd", "th")
private val DATE_FORMAT_1 = SimpleDateFormat("yyyy.MM.dd", Locale.US) private val DATE_FORMAT_1 = SimpleDateFormat("yyyy.MM.dd", Locale.US)

View File

@ -10,10 +10,10 @@ class FoolSlideGenerator : ThemeSourceGenerator {
override val themeClass = "FoolSlide" override val themeClass = "FoolSlide"
override val baseVersionCode: Int = 2 override val baseVersionCode: Int = 3
override val sources = listOf( override val sources = listOf(
SingleLang("The Cat Scans", "https://reader2.thecatscans.com/", "en"), SingleLang("The Cat Scans", "https://reader2.thecatscans.com", "en"),
SingleLang("Silent Sky", "https://reader.silentsky-scans.net", "en"), SingleLang("Silent Sky", "https://reader.silentsky-scans.net", "en"),
SingleLang("Death Toll Scans", "https://reader.deathtollscans.net", "en"), SingleLang("Death Toll Scans", "https://reader.deathtollscans.net", "en"),
SingleLang("MangaScouts", "http://onlinereader.mangascouts.org", "de"), SingleLang("MangaScouts", "http://onlinereader.mangascouts.org", "de"),
@ -25,7 +25,7 @@ class FoolSlideGenerator : ThemeSourceGenerator {
SingleLang("Menudo-Fansub", "https://www.menudo-fansub.com", "es", className = "MenudoFansub", overrideVersionCode = 1), SingleLang("Menudo-Fansub", "https://www.menudo-fansub.com", "es", className = "MenudoFansub", overrideVersionCode = 1),
SingleLang("Sense-Scans", "https://sensescans.com", "en", className = "SenseScans", overrideVersionCode = 1), SingleLang("Sense-Scans", "https://sensescans.com", "en", className = "SenseScans", overrideVersionCode = 1),
SingleLang("Kirei Cake", "https://reader.kireicake.com", "en"), SingleLang("Kirei Cake", "https://reader.kireicake.com", "en"),
SingleLang("Mangatellers", "http://www.mangatellers.gr", "en"), SingleLang("Mangatellers", "https://reader.mangatellers.gr", "en"),
SingleLang("Iskultrip Scans", "https://maryfaye.net", "en"), SingleLang("Iskultrip Scans", "https://maryfaye.net", "en"),
SingleLang("Anata no Motokare", "https://motokare.xyz", "en", className = "AnataNoMotokare"), SingleLang("Anata no Motokare", "https://motokare.xyz", "en", className = "AnataNoMotokare"),
SingleLang("Yuri-ism", "https://www.yuri-ism.net", "en", className = "YuriIsm"), SingleLang("Yuri-ism", "https://www.yuri-ism.net", "en", className = "YuriIsm"),
@ -42,10 +42,9 @@ class FoolSlideGenerator : ThemeSourceGenerator {
SingleLang("Tortuga Ceviri", "http://tortuga-ceviri.com", "tr"), SingleLang("Tortuga Ceviri", "http://tortuga-ceviri.com", "tr"),
SingleLang("Rama", "https://www.ramareader.it", "it"), SingleLang("Rama", "https://www.ramareader.it", "it"),
SingleLang("Mabushimajo", "http://mabushimajo.com", "tr"), SingleLang("Mabushimajo", "http://mabushimajo.com", "tr"),
SingleLang("Hyakuro", "https://hyakuro.com/reader", "en"), SingleLang("Hyakuro", "https://hyakuro.com", "en"),
SingleLang("Le Cercle du Scan", "https://lel.lecercleduscan.com", "fr", className = "LeCercleDuScan", overrideVersionCode = 1) SingleLang("Le Cercle du Scan", "https://lel.lecercleduscan.com", "fr", className = "LeCercleDuScan", overrideVersionCode = 1),
//Sites that are down SingleLang("LetItGo Scans", "https://reader.letitgo.scans.today", "en", overrideVersionCode = 1)
//SingleLang("One Time Scans", "https://reader.otscans.com", "en"),
) )
companion object { companion object {