Remove broken extensions/sites (#8167)

* Remove HerenScan (403)

* Remove Its Your Right Manhua (403)

* Remove PrinceEdiciones (403)

* Remove Manhwas.es (403)

* Remove Yaoi Manga (403)

* Remove Kings Of Darkness (404)

* Remove ManhwaFreak.xyz (404)

* Remove HenChan (404)

* Remove Yaoi Flix (404)

* Remove Asura Scans.us (unoriginal) (disabled)

* Remove Bento Manga (404)

* Remove MR Yaoi Fansub (expired)

* Remove Aurora Scan (empty)

* Remove Varna Scan (unrelated)

* Remove Guilda Tier Draw (disabled / invite only)

* Remove Norte Rose Scan (under maintenance)

* Remove Nox Scans (disabled)

* Remove Novelle Leggere (unrelated)

* Remove IchiroManga (disabled)

* Remove LeerMangasXYZ (unrelated)

* Remove Wicked Scans (526, invalid SSL certificate)
This commit is contained in:
Vetle Ledaal 2025-03-23 16:05:03 +01:00 committed by Draff
parent af0d261251
commit 5b7ce2f85d
No known key found for this signature in database
GPG Key ID: E8A89F3211677653
158 changed files with 0 additions and 1959 deletions

View File

@ -1,10 +0,0 @@
ext {
extName = 'Asura Scans.us (unoriginal)'
extClass = '.AsuraScansUs'
themePkg = 'madara'
baseUrl = 'https://asurascans.us'
overrideVersionCode = 0
isNsfw = false
}
apply from: "$rootDir/common.gradle"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

View File

@ -1,7 +0,0 @@
package eu.kanade.tachiyomi.extension.en.asurascansus
import eu.kanade.tachiyomi.multisrc.madara.Madara
class AsuraScansUs : Madara("Asura Scans.us (unoriginal)", "https://asurascans.us", "en") {
override val useNewChapterEndpoint = true
}

View File

@ -1,10 +0,0 @@
ext {
extName = 'Its Your Right Manhua'
extClass = '.ItsYourRightManhua'
themePkg = 'madara'
baseUrl = 'https://itsyourightmanhua.com'
overrideVersionCode = 2
isNsfw = false
}
apply from: "$rootDir/common.gradle"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

View File

@ -1,7 +0,0 @@
package eu.kanade.tachiyomi.extension.en.itsyourrightmanhua
import eu.kanade.tachiyomi.multisrc.madara.Madara
class ItsYourRightManhua : Madara("Its Your Right Manhua", "https://itsyourightmanhua.com/", "en") {
override val useNewChapterEndpoint = true
}

View File

@ -1,10 +0,0 @@
ext {
extName = 'ManhwaFreak.xyz'
extClass = '.ManhwaFreakXyz'
themePkg = 'madara'
baseUrl = 'https://manhwafreak.xyz'
overrideVersionCode = 0
isNsfw = false
}
apply from: "$rootDir/common.gradle"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

View File

@ -1,152 +0,0 @@
package eu.kanade.tachiyomi.extension.en.manhwafreakxyz
import android.util.Base64
import eu.kanade.tachiyomi.multisrc.madara.Madara
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.network.POST
import eu.kanade.tachiyomi.source.model.FilterList
import eu.kanade.tachiyomi.source.model.MangasPage
import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.util.asJsoup
import kotlinx.serialization.json.decodeFromStream
import okhttp3.FormBody
import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.Request
import okhttp3.Response
import org.jsoup.Jsoup
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
class ManhwaFreakXyz : Madara(
"ManhwaFreak.xyz",
"https://manhwafreak.xyz",
"en",
) {
// ===================== Popular ============================
override fun popularMangaRequest(page: Int): Request {
val url = "$baseUrl/$mangaSubString/${searchPage(page)}".toHttpUrl().newBuilder()
.addQueryParameter("post_type", "wp-manga")
.addQueryParameter("s", "")
.addQueryParameter("sort", "most_viewed")
.build()
return GET(url, headers)
}
override fun popularMangaSelector() = "div[class*=unit item]"
override val popularMangaUrlSelector = ".info a"
override fun popularMangaFromElement(element: Element): SManga {
return super.popularMangaFromElement(element).apply {
element.selectFirst("img:not(.flag-icon)")?.let {
thumbnail_url = imageFromElement(it)
}
}
}
override fun popularMangaParse(response: Response): MangasPage {
if (nonce.isBlank()) {
nonce = response.peekBody().let(::findNonceValue)
}
return super.popularMangaParse(response)
}
private fun Response.peekBody(): Document =
Jsoup.parseBodyFragment(peekBody(Long.MAX_VALUE).string())
override fun popularMangaNextPageSelector() = ".navigation .page-item:last-child:not(.disabled)"
// ===================== Latest ============================
override fun latestUpdatesRequest(page: Int): Request {
val request = popularMangaRequest(page)
val url = request.url.newBuilder()
.setQueryParameter("sort", "recently_added")
.build()
return request.newBuilder()
.url(url)
.build()
}
// ===================== Search ============================
override fun searchRequest(page: Int, query: String, filters: FilterList): Request {
if (nonce.isBlank()) {
nonce = findNonceValue()
}
val form = FormBody.Builder()
.add("action", "live_search")
.add("search", query)
.add("nonce", nonce)
.build()
return POST("$baseUrl/wp-admin/admin-ajax.php", xhrHeaders, form)
}
override fun searchMangaParse(response: Response): MangasPage {
val searchDto = json.decodeFromStream<SearchDto>(response.body.byteStream())
val mangas = searchDto.mangas.map {
SManga.create().apply {
title = it.title
thumbnail_url = it.thumbnail
setUrlWithoutDomain(it.url)
}
}
return MangasPage(mangas, hasNextPage = false)
}
private var nonce: String = ""
private fun findNonceValue(document: Document? = null): String {
val dom = document ?: client.newCall(popularMangaRequest(1)).execute().asJsoup()
return dom.select("script")
.map(Element::data)
.firstOrNull { it.contains("'nonce','") }
?.substringAfter("'nonce','")
?.substringBefore("'") ?: ""
}
// ===================== Manga Details ============================
override val mangaDetailsSelectorTitle = ".serie-title"
override val mangaDetailsSelectorAuthor = ".stat-label:contains(Author) + .stat-value"
override val mangaDetailsSelectorArtist = ".stat-label:contains(Artist) + .stat-value"
override val mangaDetailsSelectorStatus = ".stat-label:contains(Status) + .manga"
override val mangaDetailsSelectorDescription = ".description-content"
override val mangaDetailsSelectorThumbnail = ".main-cover img.cover"
override val mangaDetailsSelectorGenre = ".genre-list .genre-link"
// ===================== Chapters ============================
override fun chapterListSelector() = ".list-body-hh li"
override fun chapterDateSelector() = "a > span:not(:has(i))"
override fun chapterFromElement(element: Element): SChapter {
return super.chapterFromElement(element).apply {
name = name.split(" ")
.take(2)
.joinToString(" ")
}
}
// ===================== Pages ============================
override fun pageListParse(document: Document): List<Page> {
launchIO { countViews(document) }
return document.select("canvas.manga-canvas").mapIndexed { index, canvas ->
val imageUrl = canvas.attr("data-src")
.let { Base64.decode(it, Base64.DEFAULT).toString(Charsets.UTF_8) }
Page(index, document.location(), imageUrl)
}
}
override fun getFilterList() = FilterList()
}

View File

@ -1,17 +0,0 @@
package eu.kanade.tachiyomi.extension.en.manhwafreakxyz
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@Serializable
class SearchDto(
@SerialName("data")
val mangas: List<MangaDto>,
)
@Serializable
class MangaDto(
val thumbnail: String,
val title: String,
val url: String,
)

View File

@ -1,10 +0,0 @@
ext {
extName = 'Varna Scan'
extClass = '.VarnaScan'
themePkg = 'mangathemesia'
baseUrl = 'https://varnascan.xyz'
overrideVersionCode = 2
isNsfw = false
}
apply from: "$rootDir/common.gradle"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

View File

@ -1,9 +0,0 @@
package eu.kanade.tachiyomi.extension.en.varnascan
import eu.kanade.tachiyomi.multisrc.mangathemesia.MangaThemesia
class VarnaScan : MangaThemesia(
"Varna Scan",
"https://varnascan.xyz",
"en",
)

View File

@ -1,9 +0,0 @@
ext {
extName = 'Wicked Scans'
extClass = '.WickedScans'
themePkg = 'keyoapp'
baseUrl = 'https://wickedscans.org'
overrideVersionCode = 1
}
apply from: "$rootDir/common.gradle"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

View File

@ -1,5 +0,0 @@
package eu.kanade.tachiyomi.extension.en.wickedscans
import eu.kanade.tachiyomi.multisrc.keyoapp.Keyoapp
class WickedScans : Keyoapp("Wicked Scans", "https://wickedscans.org", "en")

View File

@ -1,10 +0,0 @@
ext {
extName = 'HerenScan'
extClass = '.HerenScan'
themePkg = 'madara'
baseUrl = 'https://herenscan.com'
overrideVersionCode = 0
isNsfw = false
}
apply from: "$rootDir/common.gradle"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

View File

@ -1,17 +0,0 @@
package eu.kanade.tachiyomi.extension.es.herenscan
import eu.kanade.tachiyomi.multisrc.madara.Madara
import java.text.SimpleDateFormat
import java.util.Locale
class HerenScan : Madara(
"HerenScan",
"https://herenscan.com",
"es",
dateFormat = SimpleDateFormat("d 'de' MMM 'de' yyy", Locale("es")),
) {
override val useNewChapterEndpoint = true
// Disable type selector as it's junk data, must not be empty.
override val seriesTypeSelector = "#abcdefghijklmnopqrstuvwxyz"
}

View File

@ -1,7 +0,0 @@
ext {
extName = 'Kings Of Darkness'
extClass = '.KingsOfDarkness'
extVersionCode = 2
}
apply from: "$rootDir/common.gradle"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

View File

@ -1,99 +0,0 @@
package eu.kanade.tachiyomi.extension.es.kingsofdarkness
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 eu.kanade.tachiyomi.source.online.ParsedHttpSource
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
class KingsOfDarkness : ParsedHttpSource() {
override val name = "Kings Of Darkness"
override val baseUrl = "https://kings-of-darkness.wixsite.com/0000"
override val lang = "es"
override val supportsLatest = false
override fun popularMangaSelector() = "#SITE_PAGES div.wixui-image"
override fun popularMangaRequest(page: Int) =
GET("$baseUrl/proyectos", headers)
override fun popularMangaFromElement(element: Element) =
SManga.create().apply {
url = element.child(0).attr("href")
title = element.nextElementSibling()!!.text()
thumbnail_url = element.selectFirst("img")!!.image
}
override fun fetchSearchManga(page: Int, query: String, filters: FilterList) =
fetchPopularManga(page).map { mp ->
mp.copy(mp.mangas.filter { it.title.contains(query, true) })
}!!
override fun mangaDetailsRequest(manga: SManga) =
GET(manga.url, headers)
override fun mangaDetailsParse(document: Document) =
SManga.create().apply {
url = document.location()
title = document.selectFirst("#SITE_PAGES h2")!!.text()
thumbnail_url = document.selectFirst("#SITE_PAGES img")!!.image
document.select("#SITE_PAGES p:last-of-type").let { el ->
description = el[0].text().trim()
genre = el[1].select("a").joinToString { it.text() }
}
}
override fun chapterListSelector() = "#SITE_PAGES a[target=_self]"
override fun chapterListRequest(manga: SManga) =
GET(manga.url, headers)
override fun chapterFromElement(element: Element) =
SChapter.create().apply {
url = element.attr("href")
name = element.child(0).text()
chapter_number = name.substring(3).toFloat()
}
override fun pageListRequest(chapter: SChapter) =
GET(chapter.url, headers)
override fun pageListParse(document: Document) =
document.select("#SITE_PAGES img").mapIndexed { idx, el ->
Page(idx, "", el.image)
}
private inline val Element.image: String
get() = attr("src").substringBefore("/v1/fill")
override fun latestUpdatesSelector() = ""
override fun latestUpdatesNextPageSelector(): String? = null
override fun latestUpdatesRequest(page: Int) =
throw UnsupportedOperationException()
override fun latestUpdatesFromElement(element: Element) =
throw UnsupportedOperationException()
override fun popularMangaNextPageSelector(): String? = null
override fun searchMangaSelector() = ""
override fun searchMangaNextPageSelector(): String? = null
override fun searchMangaRequest(page: Int, query: String, filters: FilterList) =
throw UnsupportedOperationException()
override fun searchMangaFromElement(element: Element) =
throw UnsupportedOperationException()
override fun imageUrlParse(document: Document) =
throw UnsupportedOperationException()
}

View File

@ -1,7 +0,0 @@
ext {
extName = 'LeerMangasXYZ'
extClass = '.LeerMangasXYZ'
extVersionCode = 1
}
apply from: "$rootDir/common.gradle"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

View File

@ -1,116 +0,0 @@
package eu.kanade.tachiyomi.extension.es.leermangasxyz
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 eu.kanade.tachiyomi.source.online.ParsedHttpSource
import okhttp3.Request
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import rx.Observable
import java.net.URLEncoder
open class LeerMangasXYZ : ParsedHttpSource() {
override val baseUrl: String = "https://r1.leermanga.xyz"
override val lang: String = "es"
override val name: String = "LeerManga.xyz"
override fun latestUpdatesFromElement(element: Element): SManga = throw UnsupportedOperationException()
override fun latestUpdatesNextPageSelector(): String? = throw UnsupportedOperationException()
override fun latestUpdatesRequest(page: Int): Request = throw UnsupportedOperationException()
override fun latestUpdatesSelector(): String = throw UnsupportedOperationException()
override fun imageUrlParse(document: Document): String = throw UnsupportedOperationException()
override val supportsLatest: Boolean = false
override fun chapterFromElement(element: Element): SChapter = SChapter.create().apply {
val row = element.select("td")
with(row[0]) {
chapter_number = text().toFloat()
date_upload = 0
}
with(row[1]) {
name = text()
url = selectFirst("a")!!.attr("href")
}
}
override fun fetchChapterList(manga: SManga): Observable<List<SChapter>> = super.fetchChapterList(manga).map {
it.reversed()
}
override fun mangaDetailsParse(document: Document): SManga = SManga.create().apply {
setUrlWithoutDomain(document.baseUri())
val rawStatus = document.selectFirst("td:contains(Status)")!!.text()
status = getStatus(rawStatus.substringAfter("Status: "))
author = document.select("li[itemprop=author]").joinToString(separator = ", ") { it.text() }
thumbnail_url = document.selectFirst("img.img-thumbnail")!!.attr("abs:src")
description = document.selectFirst("p[itemprop=description]")!!.text()
genre = document.select("span[itemprop=genre]").joinToString(", ") { it.text() }
}
override fun pageListParse(document: Document): List<Page> {
val pages = document.select(pageListSelector()).map {
Page(
imageUrl = it.attr("href"),
index = it.attr("data-ngdesc").substringAfter("Page ").toInt(),
)
}
if (pages.isEmpty()) {
throw RuntimeException("Cannot fetch images from source")
}
return pages
}
override fun popularMangaFromElement(element: Element): SManga = SManga.create().apply {
thumbnail_url = element.selectFirst("img.card-img-top")!!.attr("abs:src")
element.selectFirst("div.card-body")!!.let {
val dc = it.selectFirst("h5.card-title a")!!
url = dc.attr("href")
title = dc.text()
}
}
override fun searchMangaFromElement(element: Element): SManga = SManga.create().apply {
with(element) {
thumbnail_url = selectFirst("img")!!.attr("abs:src")
title = selectFirst("span[itemprop=name]")!!.text()
url = selectFirst("div.col-4 a")!!.attr("href")
}
}
private fun encodeString(str: String): String = URLEncoder.encode(str, "utf-8")
private fun getStatus(str: String): Int = when (str) {
"Emitiéndose", "Ongoing", "En emisión" -> SManga.ONGOING
"Finalizado" -> SManga.COMPLETED
else -> SManga.UNKNOWN
}
// ========------- [[< Request >]]] =========--------
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request = GET("$baseUrl/search?query=${encodeString(query)}&page=$page")
override fun popularMangaRequest(page: Int): Request = GET(baseUrl, headers)
// ------ ======== [[[ SELECTORS ]]] ======== -------
private fun pageListSelector() = "div[data-nanogallery2] a"
override fun searchMangaSelector(): String = "div[itemtype*=ComicSeries]"
override fun searchMangaNextPageSelector(): String = "CHANGE THIS"
override fun popularMangaSelector(): String = "div.card-group div.card"
override fun popularMangaNextPageSelector(): String = "CHANGE THIS"
override fun chapterListSelector(): String = "table#chaptersTable tbody tr"
}

View File

@ -1,10 +0,0 @@
ext {
extName = 'Manhwas.es'
extClass = '.ManhwasEs'
themePkg = 'madara'
baseUrl = 'https://www.manhwas.es'
overrideVersionCode = 0
isNsfw = true
}
apply from: "$rootDir/common.gradle"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

View File

@ -1,14 +0,0 @@
package eu.kanade.tachiyomi.extension.es.manhwases
import eu.kanade.tachiyomi.multisrc.madara.Madara
import java.text.SimpleDateFormat
import java.util.Locale
class ManhwasEs : Madara(
"Manhwas.es",
"https://manhwas.es",
"es",
dateFormat = SimpleDateFormat("MMM dd, yy", Locale("es")),
) {
override val useNewChapterEndpoint = true
}

View File

@ -1,10 +0,0 @@
ext {
extName = 'PrinceEdiciones'
extClass = '.PrinceEdiciones'
themePkg = 'madara'
baseUrl = 'https://princediciones.com'
overrideVersionCode = 0
isNsfw = false
}
apply from: "$rootDir/common.gradle"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

View File

@ -1,15 +0,0 @@
package eu.kanade.tachiyomi.extension.es.princediciones
import eu.kanade.tachiyomi.multisrc.madara.Madara
import java.text.SimpleDateFormat
import java.util.Locale
class PrinceEdiciones : Madara(
"Prince Ediciones",
"https://princediciones.com",
"es",
SimpleDateFormat("MMMM dd, yyyy", Locale("es")),
) {
override val mangaSubString = "media"
override val useNewChapterEndpoint = true
}

View File

@ -1,10 +0,0 @@
ext {
extName = 'Yaoi Manga'
extClass = '.YaoiManga'
themePkg = 'madara'
baseUrl = 'https://yaoimanga.es'
overrideVersionCode = 0
isNsfw = true
}
apply from: "$rootDir/common.gradle"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 61 KiB

View File

@ -1,20 +0,0 @@
package eu.kanade.tachiyomi.extension.es.yaoimanga
import eu.kanade.tachiyomi.multisrc.madara.Madara
import eu.kanade.tachiyomi.network.interceptor.rateLimit
import okhttp3.OkHttpClient
class YaoiManga : Madara(
"Yaoi Manga",
"https://yaoimanga.es",
"es",
) {
override val client: OkHttpClient = super.client.newBuilder()
.rateLimit(3)
.build()
override val useNewChapterEndpoint = true
override val useLoadMoreRequest = LoadMoreStrategy.Never
}

View File

@ -1,8 +0,0 @@
ext {
extName = 'Bento Manga'
extClass = '.BentoManga'
extVersionCode = 16
isNsfw = true
}
apply from: "$rootDir/common.gradle"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 976 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 716 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 711 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 505 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 924 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.0 KiB

View File

@ -1,477 +0,0 @@
package eu.kanade.tachiyomi.extension.fr.japanread
import android.net.Uri
import android.widget.Toast
import androidx.preference.EditTextPreference
import androidx.preference.PreferenceScreen
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.network.asObservableSuccess
import eu.kanade.tachiyomi.network.interceptor.rateLimit
import eu.kanade.tachiyomi.source.ConfigurableSource
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.SChapter
import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import eu.kanade.tachiyomi.util.asJsoup
import keiyoushi.utils.getPreferences
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.jsonArray
import kotlinx.serialization.json.jsonObject
import kotlinx.serialization.json.jsonPrimitive
import okhttp3.Headers
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.Response
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import rx.Observable
import uy.kohesive.injekt.injectLazy
import java.util.Calendar
import java.util.concurrent.TimeUnit
class BentoManga : ParsedHttpSource(), ConfigurableSource {
override val name = "Bento Manga"
override val id: Long = 4697148576707003393
override val baseUrl = "https://www.bentomanga.com"
override val lang = "fr"
override val supportsLatest = true
private val json: Json by injectLazy()
override val client: OkHttpClient = network.cloudflareClient.newBuilder()
.connectTimeout(15, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.rateLimit(2, 1)
.build()
override fun headersBuilder(): Headers.Builder {
val builder = super.headersBuilder().apply {
set("Referer", "$baseUrl/")
// Headers for homepage + serie page
set("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8")
set("Accept-Language", "fr,fr-FR;q=0.8,en-US;q=0.5,en;q=0.3")
set("Connection", "keep-alive")
set("Sec-Fetch-Dest", "document")
set("Sec-Fetch-Mode", "navigate")
set("Sec-Fetch-Site", "same-origin")
set("Sec-Fetch-User", "?1")
}
val preferences = getPreferences()
val userAgent = preferences.getString(USER_AGENT_PREF, "")!!
return if (userAgent.isNotBlank()) {
builder.set("User-Agent", userAgent)
} else {
builder
}
}
// Generic (used by popular/latest/search)
private fun mangaListFromElement(element: Element): SManga {
return SManga.create().apply {
title = element.select("div").select("div.manga_header h1")
.text()
setUrlWithoutDomain(element.select("a").attr("href"))
thumbnail_url = element.select("div").select("img[alt=couverture manga]")
.attr("src")
}
}
private fun mangaListSelector() = "div#mangas_content div.manga"
private fun mangaListNextPageSelector() = ".paginator button:contains(>)"
// Popular
override fun popularMangaRequest(page: Int): Request {
return GET("$baseUrl/manga_list?withoutTypes=5&order_by=views&limit=" + (page - 1), headers)
}
override fun popularMangaSelector() = mangaListSelector()
override fun popularMangaFromElement(element: Element) = mangaListFromElement(element)
override fun popularMangaNextPageSelector() = mangaListNextPageSelector()
// Latest
override fun latestUpdatesRequest(page: Int): Request {
return GET("$baseUrl/manga_list?withoutTypes=5&limit=" + (page - 1), headers)
}
override fun latestUpdatesSelector() = mangaListSelector()
override fun latestUpdatesFromElement(element: Element) = mangaListFromElement(element)
override fun latestUpdatesNextPageSelector() = mangaListNextPageSelector()
// Search
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
// If there is any search text, use text search, otherwise use filter search
val uri = if (query.isNotBlank()) {
Uri.parse("$baseUrl/manga_list?withoutTypes=5")
.buildUpon()
.appendQueryParameter("search", query)
} else {
val uri = Uri.parse("$baseUrl/manga_list?withoutTypes=5").buildUpon()
// Append uri filters
filters.forEach {
if (it is UriFilter) {
it.addToUri(uri)
}
}
uri
}
// Append page number
uri.appendQueryParameter("limit", (page - 1).toString())
return GET(uri.toString())
}
override fun searchMangaSelector() = mangaListSelector()
override fun searchMangaFromElement(element: Element) = mangaListFromElement(element)
override fun searchMangaNextPageSelector() = mangaListNextPageSelector()
// Details
override fun mangaDetailsParse(document: Document): SManga {
return SManga.create().apply {
title = document.select("div.manga div.manga-infos div.component-manga-title div.component-manga-title_main h1 ")
.text()
artist = document.select("div.datas div.datas_more-artists div.datas_more-artists-people a").text()
author = document.select("div.datas div.datas_more-authors div.datas_more-authors-peoples div a").text()
description = document.select("div.datas div.datas_synopsis").text()
genre = document.select("div.manga div.manga-infos div.component-manga-categories a")
.joinToString(" , ") { it.text() }
status = document.select("div.datas div.datas_more div.datas_more-status div.datas_more-status-data")?.first()?.text()?.let {
when {
it.contains("En cours") -> SManga.ONGOING
it.contains("Terminé") -> SManga.COMPLETED
it.contains("En pause") -> SManga.ON_HIATUS
it.contains("Licencié") -> SManga.LICENSED
it.contains("Abandonné") -> SManga.CANCELLED
else -> SManga.UNKNOWN
}
} ?: SManga.UNKNOWN
thumbnail_url = document.select("img[alt=couverture manga]").attr("src")
}
}
private fun apiHeaders(refererURL: String) = headers.newBuilder().apply {
set("Referer", refererURL)
set("x-requested-with", "XMLHttpRequest")
// without this we get 404 but I don't know why, I cannot find any information about this 'a' header.
// In chrome the value is constantly changing on each request, but giving this fixed value seems to work
set("a", "1df19bce590b")
}.build()
// Chapters
// Subtract relative date
private fun parseRelativeDate(date: String): Long {
val trimmedDate = date.substringAfter("Il y a").trim().split(" ")
val calendar = Calendar.getInstance()
when (trimmedDate[1]) {
"ans" -> calendar.apply { add(Calendar.YEAR, -trimmedDate[0].toInt()) }
"an" -> calendar.apply { add(Calendar.YEAR, -trimmedDate[0].toInt()) }
"mois" -> calendar.apply { add(Calendar.MONTH, -trimmedDate[0].toInt()) }
"sem." -> calendar.apply { add(Calendar.WEEK_OF_MONTH, -trimmedDate[0].toInt()) }
"j" -> calendar.apply { add(Calendar.DAY_OF_MONTH, -trimmedDate[0].toInt()) }
"h" -> calendar.apply { add(Calendar.HOUR_OF_DAY, -trimmedDate[0].toInt()) }
"min" -> calendar.apply { add(Calendar.MINUTE, -trimmedDate[0].toInt()) }
"s" -> calendar.apply { add(Calendar.SECOND, 0) }
}
return calendar.timeInMillis
}
override fun chapterListSelector() = "div.page_content div.chapters_content div.div-item"
override fun chapterFromElement(element: Element): SChapter {
return SChapter.create().apply {
name = element.select("div.component-chapter-title a span.chapter_volume").text()
setUrlWithoutDomain(element.select("div.component-chapter-title a:not([style*='display:none'])").attr("href"))
date_upload = parseRelativeDate(element.select("div.component-chapter-date").text())
scanlator = element.select("div.component-chapter-teams a span").joinToString(" + ") { it.text() }
}
}
override fun fetchChapterList(manga: SManga): Observable<List<SChapter>> {
val requestUrl = if (manga.url.startsWith("http")) {
"${manga.url}"
} else {
"$baseUrl${manga.url}"
}
return client.newCall(GET(requestUrl, headers))
.asObservableSuccess()
.map { response ->
chapterListParse(response, requestUrl)
}
}
private fun chapterListParse(response: Response, requestUrl: String): List<SChapter> {
val chapters = mutableListOf<SChapter>()
var document = response.asJsoup()
var moreChapters = true
var nextPage = 1
val pagemax = if (!document.select(".paginator button:contains(>>)").isNullOrEmpty()) {
document.select(".paginator button:contains(>>)")?.first()?.attr("data-limit")?.toInt()?.plus(1)
?: 1
} else {
1
}
// chapters are paginated
while (moreChapters && nextPage <= pagemax) {
document.select(chapterListSelector()).map { chapters.add(chapterFromElement(it)) }
if (nextPage < pagemax) {
document = client.newCall(GET("$requestUrl?limit=$nextPage", headers)).execute().asJsoup()
nextPage++
} else {
moreChapters = false
}
}
return chapters
}
// Alternative way through API in case jSoup doesn't work anymore
// It gives precise timestamp, but we are not using it
// since the API wrongly returns null for the scanlation group
/*private fun getChapterName(jsonElement: JsonElement): String {
var name = ""
if (jsonElement["volume"].asString != "") {
name += "Tome " + jsonElement["volume"].asString + " "
}
if (jsonElement["chapter"].asString != "") {
name += "Ch " + jsonElement["chapter"].asString + " "
}
if (jsonElement["title"].asString != "") {
if (name != "") {
name += " - "
}
name += jsonElement["title"].asString
}
return name
}
override fun chapterListParse(response: Response): List<SChapter> {
val document = response.asJsoup()
val mangaId = document.select("div[data-avg]").attr("data-avg")
client.newCall(GET(baseUrl + document.select("#chapters div[data-row=chapter]").first()!!.select("div.col-lg-5 a").attr("href"), headers)).execute()
val apiResponse = client.newCall(GET("$baseUrl/api/?id=$mangaId&type=manga", apiHeaders())).execute()
val jsonData = apiResponse.body.string()
val json = JsonParser().parse(jsonData).asJsonObject
return json["chapter"].obj.entrySet()
.map {
SChapter.create().apply {
name = getChapterName(it.value.obj)
url = "$baseUrl/api/?id=${it.key}&type=chapter"
date_upload = it.value.obj["timestamp"].asLong * 1000
// scanlator = element.select(".chapter-list-group a").joinToString { it.text() }
}
}
.sortedByDescending { it.date_upload }
}
override fun chapterListSelector() = throw UnsupportedOperationException()
override fun chapterFromElement(element: Element): SChapter = throw UnsupportedOperationException()*/
// Pages
override fun pageListRequest(chapter: SChapter): Request = GET("$baseUrl${chapter.url}", headers)
override fun pageListParse(document: Document): List<Page> {
val chapterId = document.select("meta[data-chapter-id]").attr("data-chapter-id")
val apiRequest = GET("$baseUrl/api/?id=$chapterId&type=chapter", apiHeaders(document.location()))
val apiResponse = client.newCall(apiRequest).execute()
val jsonResult = json.parseToJsonElement(apiResponse.body.string()).jsonObject
val baseImagesUrl = jsonResult["baseImagesUrl"]!!.jsonPrimitive.content
return jsonResult["page_array"]!!.jsonArray.mapIndexed { i, jsonEl ->
Page(i, document.location(), "$baseUrl$baseImagesUrl/${jsonEl.jsonPrimitive.content}")
}
}
override fun imageUrlParse(document: Document) = ""
override fun imageRequest(page: Page): Request {
val newHeaders = headers.newBuilder().apply {
set("Referer", page.url)
set("Accept", "image/avif,image/webp,*/*")
set("Accept-Language", "fr,fr-FR;q=0.8,en-US;q=0.5,en;q=0.3")
set("Connection", "keep-alive")
set("Sec-Fetch-Dest", "document")
set("Sec-Fetch-Mode", "navigate")
set("Sec-Fetch-Site", "same-origin")
set("Sec-Fetch-User", "?1")
}.build()
return GET(page.imageUrl!!, newHeaders)
}
// Filters
override fun getFilterList() = FilterList(
SortFilter(),
TypeFilter(),
StatusFilter(),
GenreFilter(),
)
private class SortFilter : UriSelectFilter(
"Tri",
"order_by",
arrayOf(
Pair("views", "Les + vus"),
Pair("top", "Les mieux notés"),
Pair("name", "A - Z"),
Pair("comment", "Les + commentés"),
Pair("update", "Les + récents"),
Pair("create", "Par date de sortie"),
),
firstIsUnspecified = false,
)
private class TypeFilter : UriSelectFilter(
"Type",
"withTypes",
arrayOf(
Pair("0", "Tous"),
Pair("2", "Manga"),
Pair("3", "Manhwa"),
Pair("4", "Manhua"),
Pair("5", "Novel"),
Pair("6", "Doujinshi"),
),
)
private class StatusFilter : UriSelectFilter(
"Statut",
"status",
arrayOf(
Pair("0", "Tous"),
Pair("1", "En cours"),
Pair("2", "Terminé"),
Pair("3", "En pause"),
Pair("4", "Licencié"),
Pair("5", "Abandonné"),
),
)
private class GenreFilter : UriSelectFilter(
"Genre",
"withCategories",
arrayOf(
Pair("0", "Tous"),
Pair("1", "Action"),
Pair("27", "Adulte"),
Pair("20", "Amitié"),
Pair("21", "Amour"),
Pair("7", "Arts martiaux"),
Pair("3", "Aventure"),
Pair("6", "Combat"),
Pair("5", "Comédie"),
Pair("4", "Drame"),
Pair("12", "Ecchi"),
Pair("16", "Fantastique"),
Pair("29", "Gender Bender"),
Pair("8", "Guerre"),
Pair("22", "Harem"),
Pair("23", "Hentai"),
Pair("15", "Historique"),
Pair("19", "Horreur"),
Pair("13", "Josei"),
Pair("30", "Mature"),
Pair("18", "Mecha"),
Pair("32", "One-shot"),
Pair("42", "Parodie"),
Pair("17", "Policier"),
Pair("25", "Science-fiction"),
Pair("31", "Seinen"),
Pair("10", "Shojo"),
Pair("26", "Shojo Ai"),
Pair("2", "Shonen"),
Pair("35", "Shonen Ai"),
Pair("37", "Smut"),
Pair("14", "Sports"),
Pair("38", "Surnaturel"),
Pair("39", "Tragédie"),
Pair("36", "Tranches de vie"),
Pair("34", "Vie scolaire"),
Pair("24", "Yaoi"),
Pair("41", "Yuri"),
),
)
/**
* Class that creates a select filter. Each entry in the dropdown has a name and a display name.
* If an entry is selected it is appended as a query parameter onto the end of the URI.
* If `firstIsUnspecified` is set to true, if the first entry is selected, nothing will be appended on the the URI.
*/
// vals: <name, display>
private open class UriSelectFilter(
displayName: String,
val uriParam: String,
val vals: Array<Pair<String, String>>,
val firstIsUnspecified: Boolean = true,
defaultValue: Int = 0,
) :
Filter.Select<String>(displayName, vals.map { it.second }.toTypedArray(), defaultValue),
UriFilter {
override fun addToUri(uri: Uri.Builder) {
if (state != 0 || !firstIsUnspecified) {
uri.appendQueryParameter(uriParam, vals[state].first)
}
}
}
/**
* Represents a filter that is able to modify a URI.
*/
private interface UriFilter {
fun addToUri(uri: Uri.Builder)
}
// From Happymh for the custom User-Agent menu
override fun setupPreferenceScreen(screen: PreferenceScreen) {
// Maybe add the choice of a random UA ? (Like Mangathemesia)
EditTextPreference(screen.context).apply {
key = USER_AGENT_PREF
title = TITLE_RANDOM_UA
summary = USER_AGENT_PREF
dialogMessage =
"\n\nPermet d'indiquer un User-Agent custom\n" +
"Après l'ajout + restart de l'application, il faudra charger la page en webview et valider le captcha Cloudflare." +
"\n\nValeur par défaut:\n$DEFAULT_UA"
setDefaultValue(DEFAULT_UA)
setOnPreferenceChangeListener { _, newValue ->
try {
Headers.Builder().add("User-Agent", newValue as String)
Toast.makeText(screen.context, RESTART_APP_STRING, Toast.LENGTH_LONG).show()
summary = newValue
true
} catch (e: Throwable) {
Toast.makeText(screen.context, "$ERROR_USER_AGENT_SETUP ${e.message}", Toast.LENGTH_LONG).show()
false
}
}
}.let(screen::addPreference)
}
companion object {
private const val USER_AGENT_PREF = "Empty"
private const val RESTART_APP_STRING = "Restart Tachiyomi to apply new setting."
private const val ERROR_USER_AGENT_SETUP = "Invalid User-Agent :"
private const val TITLE_RANDOM_UA = "Set custom User-Agent"
private const val DEFAULT_UA = "Mozilla/5.0 (Linux; Android 9) AppleWebKit/537.36 (KHTML, like Gecko) Brave/107.0.0.0 Mobile Safari/537.36"
}
}

View File

@ -1,9 +0,0 @@
ext {
extName = 'IchiroManga'
extClass = '.IchiroManga'
themePkg = 'mangathemesia'
baseUrl = 'https://ichiromanga.my.id'
overrideVersionCode = 0
}
apply from: "$rootDir/common.gradle"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Some files were not shown because too many files have changed in this diff Show More