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
|
@ -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", "/")
|
|
@ -1,30 +1,29 @@
|
|||
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.lib.ratelimit.RateLimitInterceptor
|
||||
import eu.kanade.tachiyomi.multisrc.foolslide.FoolSlide
|
||||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
import okhttp3.OkHttpClient
|
||||
import org.jsoup.nodes.Document
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
@Nsfw
|
||||
class BaixarHentai : FoolSlide(
|
||||
"Baixar Hentai",
|
||||
"https://leitura.baixarhentai.net",
|
||||
"pt-BR"
|
||||
) {
|
||||
class BaixarHentai : FoolSlide("Baixar Hentai", "https://leitura.baixarhentai.net", "pt-BR") {
|
||||
// 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))
|
||||
.build()
|
||||
|
||||
override fun mangaDetailsParse(document: Document): SManga {
|
||||
return SManga.create().apply {
|
||||
override fun mangaDetailsParse(document: Document) = SManga.create().apply {
|
||||
title = document.select("h1.title").text()
|
||||
thumbnail_url = getDetailsThumbnail(document, "div.title a")
|
||||
}
|
||||
}
|
||||
|
||||
// Always show adult content
|
||||
override val allowAdult = true
|
||||
|
||||
override fun setupPreferenceScreen(screen: PreferenceScreen) {}
|
||||
}
|
||||
|
|
|
@ -1,34 +1,28 @@
|
|||
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 androidx.preference.EditTextPreference
|
||||
import androidx.preference.PreferenceScreen
|
||||
import eu.kanade.tachiyomi.BuildConfig
|
||||
import eu.kanade.tachiyomi.source.ConfigurableSource
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import eu.kanade.tachiyomi.multisrc.foolslide.FoolSlide
|
||||
import eu.kanade.tachiyomi.source.SourceFactory
|
||||
|
||||
class FoolSlideCustomizableFactory : SourceFactory {
|
||||
override fun createSources(): List<Source> = listOf(
|
||||
FoolSlideCustomizable(),
|
||||
)
|
||||
override fun createSources() = listOf(FoolSlideCustomizable())
|
||||
}
|
||||
class FoolSlideCustomizable : ConfigurableSource, FoolSlide("FoolSlide Customizable", "", "other") {
|
||||
override val baseUrl: String by lazy { getPrefBaseUrl() }
|
||||
|
||||
private val preferences: SharedPreferences by lazy {
|
||||
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
|
||||
class FoolSlideCustomizable : FoolSlide("FoolSlide Customizable", "", "other") {
|
||||
override val baseUrl: String by lazy {
|
||||
preferences.getString(BASE_URL_PREF, DEFAULT_BASEURL)!!.substringBefore("/directory")
|
||||
}
|
||||
|
||||
override fun setupPreferenceScreen(screen: androidx.preference.PreferenceScreen) {
|
||||
val baseUrlPref = androidx.preference.EditTextPreference(screen.context).apply {
|
||||
override fun setupPreferenceScreen(screen: PreferenceScreen) {
|
||||
super.setupPreferenceScreen(screen)
|
||||
EditTextPreference(screen.context).apply {
|
||||
key = BASE_URL_PREF_TITLE
|
||||
title = BASE_URL_PREF_TITLE
|
||||
summary = BASE_URL_PREF_SUMMARY
|
||||
this.setDefaultValue(DEFAULT_BASEURL)
|
||||
setDefaultValue(DEFAULT_BASEURL)
|
||||
dialogTitle = BASE_URL_PREF_TITLE
|
||||
dialogMessage = "Default: $DEFAULT_BASEURL"
|
||||
|
||||
|
@ -42,17 +36,9 @@ class FoolSlideCustomizable : ConfigurableSource, FoolSlide("FoolSlide Customiza
|
|||
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 {
|
||||
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/"
|
||||
|
|
|
@ -1,50 +1,19 @@
|
|||
package eu.kanade.tachiyomi.extension.all.hniscantrad
|
||||
|
||||
import eu.kanade.tachiyomi.multisrc.foolslide.FoolSlide
|
||||
import eu.kanade.tachiyomi.source.Source
|
||||
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 org.jsoup.nodes.Element
|
||||
|
||||
class HNIScantradFactory : SourceFactory {
|
||||
override fun createSources(): List<Source> = listOf(
|
||||
HNIScantradFR(),
|
||||
HNIScantradEN(),
|
||||
)
|
||||
override fun createSources() = listOf(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") {
|
||||
override val supportsLatest = false
|
||||
override fun popularMangaRequest(page: Int) = GET(baseUrl + urlModifier, headers)
|
||||
override fun popularMangaSelector() = "div.listed"
|
||||
override fun popularMangaFromElement(element: Element): SManga {
|
||||
return SManga.create().apply {
|
||||
element.select("a:has(h3)").let {
|
||||
title = it.text()
|
||||
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]}")
|
||||
}
|
||||
}
|
||||
|
||||
class HNIScantradFR : FoolSlide("HNI-Scantrad", "https://hni-scantrad.com", "fr", "/lel") {
|
||||
override fun chapterListParse(response: Response) =
|
||||
super.chapterListParse(response).filter { "/fr/" in it.url }
|
||||
}
|
||||
|
||||
class HNIScantradEN : FoolSlide("HNI-Scantrad", "https://hni-scantrad.com", "en", "/lel") {
|
||||
override fun chapterListParse(response: Response) =
|
||||
super.chapterListParse(response).filter { "/en-us/" in it.url }
|
||||
}
|
||||
|
|
|
@ -4,12 +4,10 @@ import eu.kanade.tachiyomi.multisrc.foolslide.FoolSlide
|
|||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
import org.jsoup.nodes.Document
|
||||
|
||||
class Hyakuro : FoolSlide("Hyakuro", "https://hyakuro.com/reader/", "en") {
|
||||
override fun mangaDetailsParse(document: Document): SManga {
|
||||
return SManga.create().apply {
|
||||
class Hyakuro : FoolSlide("Hyakuro", "https://hyakuro.com", "en", "/reader") {
|
||||
override fun mangaDetailsParse(document: Document) = SManga.create().apply {
|
||||
description = document.select("$mangaDetailsInfoSelector li:has(b:contains(description))")
|
||||
.first()?.ownText()?.substringAfter(":")
|
||||
thumbnail_url = getDetailsThumbnail(document)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,11 +5,9 @@ import eu.kanade.tachiyomi.source.model.SManga
|
|||
import org.jsoup.nodes.Document
|
||||
|
||||
class KireiCake : FoolSlide("Kirei Cake", "https://reader.kireicake.com", "en") {
|
||||
override fun mangaDetailsParse(document: Document): SManga {
|
||||
return SManga.create().apply {
|
||||
override fun mangaDetailsParse(document: Document) = SManga.create().apply {
|
||||
description = document.select("$mangaDetailsInfoSelector li:has(b:contains(description))")
|
||||
.first()?.ownText()?.substringAfter(":")
|
||||
thumbnail_url = getDetailsThumbnail(document)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,18 +1,15 @@
|
|||
package eu.kanade.tachiyomi.extension.fr.lecercleduscan
|
||||
|
||||
import eu.kanade.tachiyomi.multisrc.foolslide.FoolSlide
|
||||
import java.util.Locale
|
||||
|
||||
class LeCercleDuScan : FoolSlide("Le Cercle du Scan", "https://lel.lecercleduscan.com", "fr") {
|
||||
|
||||
override fun parseChapterDate(date: String): Long? {
|
||||
val dateToEnglish = when (val lcDate = date.toLowerCase()) {
|
||||
override fun parseChapterDate(date: String) = super.parseChapterDate(
|
||||
when (val lcDate = date.toLowerCase(Locale.FRENCH)) {
|
||||
"hier" -> "yesterday"
|
||||
"aujourd'hui" -> "today"
|
||||
"demain" -> "tomorrow"
|
||||
|
||||
else -> lcDate
|
||||
}
|
||||
|
||||
return super.parseChapterDate(dateToEnglish)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
|
Before Width: | Height: | Size: 8.3 KiB After Width: | Height: | Size: 8.3 KiB |
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 27 KiB |
Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 47 KiB |
Before Width: | Height: | Size: 355 KiB After Width: | Height: | Size: 355 KiB |
|
@ -5,22 +5,17 @@ import eu.kanade.tachiyomi.source.model.SManga
|
|||
import org.jsoup.nodes.Document
|
||||
|
||||
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 manga = SManga.create()
|
||||
manga.author = infoElement.substringAfter("Autore: ").substringBefore("Artista: ")
|
||||
manga.artist = infoElement.substringAfter("Artista: ").substringBefore("Target: ")
|
||||
val stato = infoElement.substringAfter("Stato: ").substringBefore("Trama: ").substring(0, 8)
|
||||
manga.status = when (stato) {
|
||||
author = infoElement.substringAfter("Autore: ").substringBefore("Artista: ")
|
||||
artist = infoElement.substringAfter("Artista: ").substringBefore("Target: ")
|
||||
status = when (infoElement.substringAfter("Stato: ").substringBefore("Trama: ").take(8)) {
|
||||
"In corso" -> SManga.ONGOING
|
||||
"Completa" -> SManga.COMPLETED
|
||||
"Licenzia" -> SManga.LICENSED
|
||||
else -> SManga.UNKNOWN
|
||||
}
|
||||
manga.description = infoElement.substringAfter("Trama: ")
|
||||
manga.thumbnail_url = getDetailsThumbnail(document)
|
||||
|
||||
return manga
|
||||
description = infoElement.substringAfter("Trama: ")
|
||||
thumbnail_url = getDetailsThumbnail(document)
|
||||
}
|
||||
}
|
||||
|
|
After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 2.8 KiB |
After Width: | Height: | Size: 5.2 KiB |
After Width: | Height: | Size: 6.6 KiB |
After Width: | Height: | Size: 19 KiB |
|
@ -1,11 +1,5 @@
|
|||
package eu.kanade.tachiyomi.extension.en.mangatellers
|
||||
|
||||
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") {
|
||||
override fun popularMangaRequest(page: Int): Request {
|
||||
return GET("$baseUrl$urlModifier/list/$page/", headers)
|
||||
}
|
||||
}
|
||||
class Mangatellers : FoolSlide("Mangatellers", "https://reader.mangatellers.gr", "en")
|
||||
|
|
After Width: | Height: | Size: 3.4 KiB |
After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 3.8 KiB |
After Width: | Height: | Size: 7.2 KiB |
After Width: | Height: | Size: 8.8 KiB |
After Width: | Height: | Size: 57 KiB |
|
@ -12,7 +12,6 @@ class ComiCakeGenerator : ThemeSourceGenerator {
|
|||
override val baseVersionCode: Int = 1
|
||||
|
||||
override val sources = listOf(
|
||||
SingleLang("LetItGo Scans", "https://reader.letitgo.scans.today", "en"),
|
||||
SingleLang("WhimSubs", "https://whimsubs.xyz", "en")
|
||||
)
|
||||
|
||||
|
|
|
@ -1,7 +1,13 @@
|
|||
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.POST
|
||||
import eu.kanade.tachiyomi.source.ConfigurableSource
|
||||
import eu.kanade.tachiyomi.source.model.FilterList
|
||||
import eu.kanade.tachiyomi.source.model.MangasPage
|
||||
import eu.kanade.tachiyomi.source.model.Page
|
||||
|
@ -17,26 +23,24 @@ import okhttp3.Request
|
|||
import okhttp3.Response
|
||||
import org.jsoup.nodes.Document
|
||||
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.SimpleDateFormat
|
||||
import java.util.Calendar
|
||||
import java.util.Date
|
||||
import java.util.HashSet
|
||||
import java.util.Locale
|
||||
|
||||
abstract class FoolSlide(
|
||||
override val name: String,
|
||||
override val baseUrl: String,
|
||||
override val lang: String,
|
||||
val urlModifier: String = ""
|
||||
) : ParsedHttpSource() {
|
||||
|
||||
protected open val dedupeLatestUpdates = true
|
||||
open val urlModifier: String = ""
|
||||
) : ConfigurableSource, ParsedHttpSource() {
|
||||
|
||||
override val supportsLatest = true
|
||||
|
||||
private val json: Json by injectLazy()
|
||||
private val json by lazy { Injekt.get<Json>() }
|
||||
|
||||
override fun popularMangaSelector() = "div.group"
|
||||
|
||||
|
@ -44,48 +48,39 @@ abstract class FoolSlide(
|
|||
return GET("$baseUrl$urlModifier/directory/$page/", headers)
|
||||
}
|
||||
|
||||
val latestUpdatesUrls = HashSet<String>()
|
||||
private val latestUpdatesUrls = mutableSetOf<String>()
|
||||
|
||||
override fun latestUpdatesParse(response: Response): MangasPage {
|
||||
val mp = super.latestUpdatesParse(response)
|
||||
return if (dedupeLatestUpdates) {
|
||||
val mangas = mp.mangas.distinctBy { it.url }.filterNot { latestUpdatesUrls.contains(it.url) }
|
||||
latestUpdatesUrls.addAll(mangas.map { it.url })
|
||||
MangasPage(mangas, mp.hasNextPage)
|
||||
} else mp
|
||||
return mp.copy(
|
||||
mp.mangas.distinctBy { it.url }.filter {
|
||||
latestUpdatesUrls.add(it.url)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
override fun latestUpdatesSelector() = "div.group"
|
||||
|
||||
override fun latestUpdatesRequest(page: Int): Request {
|
||||
if (page == 1) {
|
||||
latestUpdatesUrls.clear()
|
||||
}
|
||||
if (page == 1) latestUpdatesUrls.clear()
|
||||
return GET("$baseUrl$urlModifier/latest/$page/")
|
||||
}
|
||||
|
||||
override fun popularMangaFromElement(element: Element): SManga {
|
||||
val manga = SManga.create()
|
||||
|
||||
override fun popularMangaFromElement(element: Element) = SManga.create().apply {
|
||||
element.select("a[title]").first().let {
|
||||
manga.setUrlWithoutDomain(it.attr("href"))
|
||||
manga.title = it.text()
|
||||
setUrlWithoutDomain(it.attr("href"))
|
||||
title = it.text()
|
||||
}
|
||||
|
||||
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 {
|
||||
val manga = SManga.create()
|
||||
override fun latestUpdatesFromElement(element: Element) = SManga.create().apply {
|
||||
element.select("a[title]").first().let {
|
||||
manga.setUrlWithoutDomain(it.attr("href"))
|
||||
manga.title = it.text()
|
||||
setUrlWithoutDomain(it.attr("href"))
|
||||
title = it.text()
|
||||
}
|
||||
return manga
|
||||
}
|
||||
|
||||
override fun popularMangaNextPageSelector() = "div.next"
|
||||
|
@ -94,11 +89,8 @@ abstract class FoolSlide(
|
|||
|
||||
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
|
||||
val searchHeaders = headersBuilder().add("Content-Type", "application/x-www-form-urlencoded").build()
|
||||
|
||||
val form = FormBody.Builder()
|
||||
.add("search", query)
|
||||
|
||||
return POST("$baseUrl$urlModifier/search/", searchHeaders, form.build())
|
||||
val form = FormBody.Builder().add("search", query).build()
|
||||
return POST("$baseUrl$urlModifier/search/", searchHeaders, form)
|
||||
}
|
||||
|
||||
override fun searchMangaSelector() = "div.group"
|
||||
|
@ -116,18 +108,17 @@ abstract class FoolSlide(
|
|||
|
||||
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
|
||||
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")
|
||||
?: 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 }
|
||||
}
|
||||
|
||||
override fun mangaDetailsParse(document: Document): SManga {
|
||||
return SManga.create().apply {
|
||||
override fun mangaDetailsParse(document: Document) = SManga.create().apply {
|
||||
document.select(mangaDetailsInfoSelector).firstOrNull()?.html()?.let { infoHtml ->
|
||||
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)
|
||||
|
@ -135,42 +126,34 @@ abstract class FoolSlide(
|
|||
}
|
||||
thumbnail_url = getDetailsThumbnail(document)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform a GET request into a POST request that automatically authorizes all adult content
|
||||
*/
|
||||
private fun allowAdult(request: Request) = allowAdult(request.url.toString())
|
||||
protected open val allowAdult: Boolean
|
||||
get() = preferences.getBoolean("adult", true)
|
||||
|
||||
private fun allowAdult(url: String): Request {
|
||||
return POST(
|
||||
url,
|
||||
body = FormBody.Builder()
|
||||
.add("adult", "true")
|
||||
.build()
|
||||
)
|
||||
private fun allowAdult(request: Request): Request {
|
||||
val form = FormBody.Builder().add("adult", allowAdult.toString()).build()
|
||||
return POST(request.url.toString(), headers, form)
|
||||
}
|
||||
|
||||
override fun chapterListRequest(manga: SManga) = allowAdult(super.chapterListRequest(manga))
|
||||
|
||||
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 dateElement = element.select(chapterDateSelector).first()
|
||||
val chapter = SChapter.create()
|
||||
chapter.setUrlWithoutDomain(urlElement.attr("href"))
|
||||
chapter.name = urlElement.text()
|
||||
chapter.date_upload = dateElement.text()?.let { parseChapterDate(it.substringAfter(", ")) }
|
||||
?: 0
|
||||
return chapter
|
||||
setUrlWithoutDomain(urlElement.attr("href"))
|
||||
name = urlElement.text()
|
||||
date_upload = dateElement.text()?.let {
|
||||
parseChapterDate(it.substringAfter(", "))
|
||||
} ?: 0
|
||||
}
|
||||
|
||||
open fun parseChapterDate(date: String): Long? {
|
||||
protected open fun parseChapterDate(date: String): Long? {
|
||||
val lcDate = date.toLowerCase(Locale.ROOT)
|
||||
if (lcDate.endsWith(" ago"))
|
||||
parseRelativeDate(lcDate)?.let { return it }
|
||||
|
@ -279,19 +262,33 @@ abstract class FoolSlide(
|
|||
val doc = document.toString()
|
||||
val jsonStr = doc.substringAfter("var pages = ").substringBefore(";")
|
||||
val pages = json.parseToJsonElement(jsonStr).jsonArray
|
||||
|
||||
return pages.mapIndexed { i, jsonEl ->
|
||||
// Create dummy element to resolve relative URL
|
||||
val absUrl = document.createElement("a")
|
||||
.attr("href", jsonEl.jsonObject["url"]!!.jsonPrimitive.content)
|
||||
.absUrl("href")
|
||||
|
||||
Page(i, "", absUrl)
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
private val ORDINAL_SUFFIXES = listOf("st", "nd", "rd", "th")
|
||||
private val DATE_FORMAT_1 = SimpleDateFormat("yyyy.MM.dd", Locale.US)
|
||||
|
|
|
@ -10,10 +10,10 @@ class FoolSlideGenerator : ThemeSourceGenerator {
|
|||
|
||||
override val themeClass = "FoolSlide"
|
||||
|
||||
override val baseVersionCode: Int = 2
|
||||
override val baseVersionCode: Int = 3
|
||||
|
||||
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("Death Toll Scans", "https://reader.deathtollscans.net", "en"),
|
||||
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("Sense-Scans", "https://sensescans.com", "en", className = "SenseScans", overrideVersionCode = 1),
|
||||
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("Anata no Motokare", "https://motokare.xyz", "en", className = "AnataNoMotokare"),
|
||||
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("Rama", "https://www.ramareader.it", "it"),
|
||||
SingleLang("Mabushimajo", "http://mabushimajo.com", "tr"),
|
||||
SingleLang("Hyakuro", "https://hyakuro.com/reader", "en"),
|
||||
SingleLang("Le Cercle du Scan", "https://lel.lecercleduscan.com", "fr", className = "LeCercleDuScan", overrideVersionCode = 1)
|
||||
//Sites that are down
|
||||
//SingleLang("One Time Scans", "https://reader.otscans.com", "en"),
|
||||
SingleLang("Hyakuro", "https://hyakuro.com", "en"),
|
||||
SingleLang("Le Cercle du Scan", "https://lel.lecercleduscan.com", "fr", className = "LeCercleDuScan", overrideVersionCode = 1),
|
||||
SingleLang("LetItGo Scans", "https://reader.letitgo.scans.today", "en", overrideVersionCode = 1)
|
||||
)
|
||||
|
||||
companion object {
|
||||
|
|