Remove unused domains (#6820)
* Remove XKCD KO (domain for sale) * Remove MangaDino.top (unoriginal) (domain for sale) * Remove parked domains Remove Atlantis Scan Remove Boosei Remove CreepyScans Remove EarlyManga Remove Glory Manga Remove Heroxia Remove Lucky Manga Remove MangaDeemak Remove MangaKitsune Remove Manga Mitsu Remove Mangá Nanquim Remove ManhuaDex Remove Mirai Scans Remove Pony Manga Remove RawZ Remove TuManhwas * Remove more parked domains (other TLDs) Remove Komik Gue Remove MangaOnline.team (unoriginal) Remove Manga Rock.team (unoriginal) Remove MangaYami Remove Manhwua.fans Remove Nekomik
|
@ -2,7 +2,6 @@ package eu.kanade.tachiyomi.extension.all.xkcd
|
|||
|
||||
import eu.kanade.tachiyomi.extension.all.xkcd.translations.XkcdES
|
||||
import eu.kanade.tachiyomi.extension.all.xkcd.translations.XkcdFR
|
||||
import eu.kanade.tachiyomi.extension.all.xkcd.translations.XkcdKO
|
||||
import eu.kanade.tachiyomi.extension.all.xkcd.translations.XkcdRU
|
||||
import eu.kanade.tachiyomi.extension.all.xkcd.translations.XkcdZH
|
||||
import eu.kanade.tachiyomi.source.SourceFactory
|
||||
|
@ -14,6 +13,5 @@ class XkcdFactory : SourceFactory {
|
|||
XkcdZH(),
|
||||
XkcdFR(),
|
||||
XkcdRU(),
|
||||
XkcdKO(),
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,49 +0,0 @@
|
|||
package eu.kanade.tachiyomi.extension.all.xkcd.translations
|
||||
|
||||
import eu.kanade.tachiyomi.extension.all.xkcd.Xkcd
|
||||
import eu.kanade.tachiyomi.source.model.Page
|
||||
import eu.kanade.tachiyomi.source.model.SChapter
|
||||
import eu.kanade.tachiyomi.util.asJsoup
|
||||
import okhttp3.Response
|
||||
|
||||
class XkcdKO : Xkcd("https://xkcdko.com", "ko") {
|
||||
override val creator = "랜들 먼로"
|
||||
|
||||
override val synopsis = "사랑, 풍자, 수학, 그리고 언어에 관한 웹 만화."
|
||||
|
||||
// Google translated, sorry
|
||||
override val interactiveText =
|
||||
"이 만화의 대화형 버전을 경험하려면 WebView/브라우저에서 엽니다."
|
||||
|
||||
override val altTextUrl = CJK_ALT_TEXT_URL
|
||||
|
||||
override val chapterListSelector = "#comicList > ol > li > a"
|
||||
|
||||
override fun chapterListParse(response: Response) =
|
||||
response.asJsoup().select(chapterListSelector).map {
|
||||
SChapter.create().apply {
|
||||
url = it.attr("href")
|
||||
val number = it.attr("title")
|
||||
name = it.text().numbered(number)
|
||||
chapter_number = number.toFloat()
|
||||
// no dates available
|
||||
date_upload = 0L
|
||||
}
|
||||
}
|
||||
|
||||
override fun pageListParse(response: Response): List<Page> {
|
||||
// if the img tag is empty then it is an interactive comic
|
||||
val img = response.asJsoup().selectFirst(imageSelector) ?: error(interactiveText)
|
||||
|
||||
// if an HD image is available it'll be the srcset attribute
|
||||
val image = when {
|
||||
!img.hasAttr("srcset") -> img.attr("abs:src")
|
||||
else -> img.attr("abs:srcset").substringBefore(' ')
|
||||
}
|
||||
|
||||
// create a text image for the alt text
|
||||
val text = img.attr("alt") + "\n\n" + img.attr("title")
|
||||
|
||||
return listOf(Page(0, "", image), Page(1, "", text.image()))
|
||||
}
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
ext {
|
||||
extName = 'CreepyScans'
|
||||
extClass = '.CreepyScans'
|
||||
themePkg = 'madara'
|
||||
baseUrl = 'https://creepyscans.com'
|
||||
overrideVersionCode = 1
|
||||
}
|
||||
|
||||
apply from: "$rootDir/common.gradle"
|
Before Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 3.6 KiB |
Before Width: | Height: | Size: 6.2 KiB |
Before Width: | Height: | Size: 8.1 KiB |
|
@ -1,155 +0,0 @@
|
|||
package eu.kanade.tachiyomi.extension.en.creepyscans
|
||||
|
||||
import eu.kanade.tachiyomi.multisrc.madara.Madara
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.network.POST
|
||||
import eu.kanade.tachiyomi.network.asObservableSuccess
|
||||
import eu.kanade.tachiyomi.network.interceptor.rateLimit
|
||||
import eu.kanade.tachiyomi.source.model.Filter
|
||||
import eu.kanade.tachiyomi.source.model.FilterList
|
||||
import eu.kanade.tachiyomi.source.model.MangasPage
|
||||
import eu.kanade.tachiyomi.source.model.SChapter
|
||||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
import kotlinx.serialization.json.boolean
|
||||
import kotlinx.serialization.json.jsonArray
|
||||
import kotlinx.serialization.json.jsonObject
|
||||
import kotlinx.serialization.json.jsonPrimitive
|
||||
import okhttp3.FormBody
|
||||
import okhttp3.HttpUrl.Companion.toHttpUrl
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import org.jsoup.nodes.Document
|
||||
import rx.Observable
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class CreepyScans : Madara(
|
||||
"CreepyScans",
|
||||
"https://creepyscans.com",
|
||||
"en",
|
||||
) {
|
||||
|
||||
override val client: OkHttpClient = super.client.newBuilder()
|
||||
.rateLimit(1, 3, TimeUnit.SECONDS)
|
||||
.build()
|
||||
|
||||
override val useNewChapterEndpoint = true
|
||||
|
||||
// Search
|
||||
|
||||
override fun fetchSearchManga(
|
||||
page: Int,
|
||||
query: String,
|
||||
filters: FilterList,
|
||||
): Observable<MangasPage> {
|
||||
return if (query.isNotBlank()) {
|
||||
val form = FormBody.Builder()
|
||||
.add("action", "wp-manga-search-manga")
|
||||
.add("title", query)
|
||||
.build()
|
||||
client.newCall(POST("$baseUrl/wp-admin/admin-ajax.php", headers, form)).asObservableSuccess().map { res ->
|
||||
json.parseToJsonElement(res.body.string()).jsonObject.let { obj ->
|
||||
if (!obj["success"]!!.jsonPrimitive.boolean) {
|
||||
MangasPage(emptyList(), false)
|
||||
} else {
|
||||
val mangas = obj["data"]!!.jsonArray.map {
|
||||
SManga.create().apply {
|
||||
title = it.jsonObject["title"]!!.jsonPrimitive.content
|
||||
setUrlWithoutDomain(it.jsonObject["url"]!!.jsonPrimitive.content)
|
||||
}
|
||||
}
|
||||
MangasPage(mangas, false)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
super.fetchSearchManga(page, query, filters)
|
||||
}
|
||||
}
|
||||
|
||||
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
|
||||
val url = "$baseUrl/$mangaSubString/".toHttpUrl().newBuilder()
|
||||
filters.forEach { filter ->
|
||||
when (filter) {
|
||||
is OrderByFilter -> {
|
||||
if (filter.state != 0) {
|
||||
url.addQueryParameter("m_orderby", filter.toUriPart())
|
||||
}
|
||||
}
|
||||
is GenreFilter -> {
|
||||
val selected = filter.vals[filter.state].second
|
||||
if (selected.isNotBlank()) {
|
||||
url.removePathSegment(0)
|
||||
url.addPathSegment("manga-genre")
|
||||
url.addPathSegment(filter.vals[filter.state].second)
|
||||
}
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
return GET(url.build(), headers)
|
||||
}
|
||||
|
||||
override fun searchMangaSelector(): String =
|
||||
super.searchMangaSelector() + ",div.page-content-listing div.page-item-detail"
|
||||
|
||||
override fun searchMangaNextPageSelector(): String? = null
|
||||
|
||||
// Filter
|
||||
|
||||
override fun genresRequest(): Request {
|
||||
return GET("$baseUrl/$mangaSubString/?genres=", headers)
|
||||
}
|
||||
|
||||
override fun parseGenres(document: Document): List<Genre> {
|
||||
genresList = document.select(".list-unstyled li").mapNotNull { genre ->
|
||||
genre.selectFirst("a[href]")?.let {
|
||||
val slug = it.attr("href")
|
||||
.split("/")
|
||||
.last(String::isNotEmpty)
|
||||
|
||||
Pair(it.ownText().trim(), slug)
|
||||
}
|
||||
}
|
||||
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
// From manga18fx
|
||||
private var genresList: List<Pair<String, String>> = emptyList()
|
||||
|
||||
class GenreFilter(val vals: List<Pair<String, String>>) :
|
||||
Filter.Select<String>("Genre", vals.map { it.first }.toTypedArray())
|
||||
|
||||
override fun getFilterList(): FilterList {
|
||||
launchIO { fetchGenres() }
|
||||
|
||||
val filters = buildList(4) {
|
||||
add(
|
||||
OrderByFilter(
|
||||
title = intl["order_by_filter_title"],
|
||||
options = orderByFilterOptions.map { Pair(it.key, it.value) },
|
||||
state = 0,
|
||||
),
|
||||
)
|
||||
add(Filter.Separator())
|
||||
add(Filter.Header("Filters are ignored for text search!"))
|
||||
|
||||
if (genresList.isNotEmpty()) {
|
||||
add(GenreFilter(listOf(Pair("<select>", "")) + genresList))
|
||||
} else {
|
||||
add(Filter.Header("Wait for mangas to load then tap Reset"))
|
||||
}
|
||||
}
|
||||
|
||||
return FilterList(filters)
|
||||
}
|
||||
|
||||
// Page list
|
||||
|
||||
override fun pageListRequest(chapter: SChapter): Request {
|
||||
if (chapter.url.startsWith("http")) {
|
||||
return GET(chapter.url.substringBefore("?style=list"), headers)
|
||||
}
|
||||
return super.pageListRequest(chapter)
|
||||
}
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
ext {
|
||||
extName = 'EarlyManga'
|
||||
extClass = '.EarlyManga'
|
||||
extVersionCode = 27
|
||||
}
|
||||
|
||||
apply from: "$rootDir/common.gradle"
|
Before Width: | Height: | Size: 4.4 KiB |
Before Width: | Height: | Size: 2.3 KiB |
Before Width: | Height: | Size: 6.3 KiB |
Before Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 18 KiB |
|
@ -1,268 +0,0 @@
|
|||
package eu.kanade.tachiyomi.extension.en.earlymanga
|
||||
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.network.POST
|
||||
import eu.kanade.tachiyomi.network.interceptor.rateLimit
|
||||
import eu.kanade.tachiyomi.source.model.Filter
|
||||
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.source.online.HttpSource
|
||||
import kotlinx.serialization.decodeFromString
|
||||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.Json
|
||||
import okhttp3.MediaType.Companion.toMediaType
|
||||
import okhttp3.Request
|
||||
import okhttp3.RequestBody.Companion.toRequestBody
|
||||
import okhttp3.Response
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Locale
|
||||
|
||||
class EarlyManga : HttpSource() {
|
||||
|
||||
override val name = "EarlyManga"
|
||||
|
||||
override val baseUrl = "https://earlym.org"
|
||||
|
||||
private val apiUrl = "$baseUrl/api"
|
||||
|
||||
override val lang = "en"
|
||||
|
||||
override val supportsLatest = true
|
||||
|
||||
override val versionId = 2
|
||||
|
||||
private val json: Json by injectLazy()
|
||||
|
||||
override val client = network.cloudflareClient.newBuilder()
|
||||
.rateLimit(2)
|
||||
.build()
|
||||
|
||||
override fun headersBuilder() = super.headersBuilder()
|
||||
.add("Referer", baseUrl)
|
||||
|
||||
private val apiHeaders by lazy {
|
||||
headersBuilder()
|
||||
.set("Accept", ACCEPT_JSON)
|
||||
.build()
|
||||
}
|
||||
|
||||
/* Popular */
|
||||
override fun popularMangaRequest(page: Int) =
|
||||
searchMangaRequest(page, "", OrderByFilter.POPULAR)
|
||||
override fun popularMangaParse(response: Response) = searchMangaParse(response)
|
||||
|
||||
/* latest */
|
||||
override fun latestUpdatesRequest(page: Int): Request {
|
||||
return GET("$apiUrl/home/show-more?page=$page")
|
||||
}
|
||||
|
||||
override fun latestUpdatesParse(response: Response) = searchMangaParse(response)
|
||||
|
||||
/* search */
|
||||
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
|
||||
val triFilters = filters.filterIsInstance<TriStateFilterGroup>()
|
||||
|
||||
val payload = SearchPayload(
|
||||
excludedGenres_all = triFilters.flatMap { it.excluded },
|
||||
includedGenres_all = triFilters.flatMap { it.included },
|
||||
includedLanguages = filters.filterIsInstance<TypeFilter>().flatMap { it.checked },
|
||||
includedPubstatus = filters.filterIsInstance<StatusFilter>().flatMap { it.checked },
|
||||
list_order = filters.filterIsInstance<SortFilter>().firstOrNull()?.selected ?: "desc",
|
||||
list_type = filters.filterIsInstance<OrderByFilter>().firstOrNull()?.selected ?: "Views",
|
||||
term = query.trim(),
|
||||
)
|
||||
.let(json::encodeToString)
|
||||
.toRequestBody(JSON_MEDIA_TYPE)
|
||||
|
||||
return POST("$apiUrl/search/advanced/post?page=$page", apiHeaders, payload)
|
||||
}
|
||||
|
||||
override fun searchMangaParse(response: Response): MangasPage {
|
||||
runCatching(::fetchGenres)
|
||||
|
||||
val result = response.parseAs<SearchResponse>()
|
||||
|
||||
return MangasPage(
|
||||
result.data.map {
|
||||
SManga.create().apply {
|
||||
url = "/manga/${it.id}/${it.slug}"
|
||||
title = it.title
|
||||
thumbnail_url = it.cover?.let { cover ->
|
||||
"$baseUrl/storage/uploads/covers_optimized_mangalist/manga_${it.id}/$cover"
|
||||
}
|
||||
}
|
||||
},
|
||||
hasNextPage = result.meta.last_page > result.meta.current_page,
|
||||
)
|
||||
}
|
||||
|
||||
/* Filters */
|
||||
private var genresMap: Map<String, List<String>> = emptyMap()
|
||||
private var fetchGenresAttempts = 0
|
||||
private var fetchGenresFailed = false
|
||||
|
||||
private fun fetchGenres() {
|
||||
if (fetchGenresAttempts < 3 && (genresMap.isEmpty() || fetchGenresFailed)) {
|
||||
val genres = runCatching {
|
||||
client.newCall(GET("$apiUrl/search/filter", headers))
|
||||
.execute()
|
||||
.use { parseGenres(it) }
|
||||
}
|
||||
|
||||
fetchGenresFailed = genres.isFailure
|
||||
genresMap = genres.getOrNull().orEmpty()
|
||||
fetchGenresAttempts++
|
||||
}
|
||||
}
|
||||
|
||||
private fun parseGenres(response: Response): Map<String, List<String>> {
|
||||
val filterResponse = response.parseAs<FilterResponse>()
|
||||
|
||||
val result = mutableMapOf<String, List<String>>()
|
||||
|
||||
result["Genres"] = filterResponse.genres.map { it.name }
|
||||
result["Sub Genres"] = filterResponse.sub_genres.map { it.name }
|
||||
result["Content"] = filterResponse.contents.map { it.name }
|
||||
result["Demographic"] = filterResponse.demographics.map { it.name }
|
||||
result["Format"] = filterResponse.formats.map { it.name }
|
||||
result["Themes"] = filterResponse.themes.map { it.name }
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
override fun getFilterList(): FilterList {
|
||||
val filters = mutableListOf(
|
||||
OrderByFilter(),
|
||||
SortFilter(),
|
||||
Filter.Separator(),
|
||||
TypeFilter(),
|
||||
StatusFilter(),
|
||||
Filter.Separator(),
|
||||
)
|
||||
|
||||
filters += if (genresMap.isNotEmpty()) {
|
||||
genresMap.map { it ->
|
||||
TriStateFilterGroup(it.key, it.value.map { Pair(it, it) })
|
||||
}
|
||||
} else {
|
||||
listOf(Filter.Header("Press 'Reset' to attempt to show genres"))
|
||||
}
|
||||
|
||||
return FilterList(filters)
|
||||
}
|
||||
|
||||
override fun mangaDetailsRequest(manga: SManga): Request {
|
||||
return GET("$apiUrl${manga.url}", headers)
|
||||
}
|
||||
|
||||
override fun mangaDetailsParse(response: Response): SManga {
|
||||
val result = response.parseAs<MangaResponse>().main_manga
|
||||
return SManga.create().apply {
|
||||
url = "/manga/${result.id}/${result.slug}"
|
||||
title = result.title
|
||||
author = result.authors?.joinToString { it.trim() }
|
||||
artist = result.artists?.joinToString { it.trim() }
|
||||
description = buildString {
|
||||
result.desc?.trim()?.also { append(it, "\n\n") }
|
||||
result.alt_titles?.joinToString("\n") { "• ${it.name.trim()}" }
|
||||
?.takeUnless { it.isEmpty() }
|
||||
?.also { append("Alternative Names:\n", it) }
|
||||
}
|
||||
genre = result.all_genres?.joinToString { it.name.trim() }
|
||||
status = result.pubstatus[0].name.parseStatus()
|
||||
thumbnail_url = result.cover?.let { cover ->
|
||||
"$baseUrl/storage/uploads/covers/manga_${result.id}/$cover"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getMangaUrl(manga: SManga): String {
|
||||
return "$baseUrl${manga.url}"
|
||||
}
|
||||
|
||||
override fun chapterListRequest(manga: SManga): Request {
|
||||
return GET("$apiUrl${manga.url}/chapterlist", headers)
|
||||
}
|
||||
override fun chapterListParse(response: Response): List<SChapter> {
|
||||
val result = response.parseAs<List<ChapterList>>()
|
||||
|
||||
val mangaUrl = response.request.url.toString()
|
||||
.substringBefore("/chapterlist")
|
||||
.substringAfter(apiUrl)
|
||||
|
||||
return result.map { chapter ->
|
||||
SChapter.create().apply {
|
||||
url = "$mangaUrl/${chapter.id}/chapter-${chapter.slug}"
|
||||
name = "Chapter ${chapter.chapter_number}" + if (chapter.title.isNullOrEmpty()) "" else ": ${chapter.title}"
|
||||
date_upload = runCatching {
|
||||
dateFormat.parse(chapter.created_at!!)!!.time
|
||||
}.getOrDefault(0L)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getChapterUrl(chapter: SChapter): String {
|
||||
return "$baseUrl${chapter.url}"
|
||||
}
|
||||
|
||||
override fun pageListRequest(chapter: SChapter): Request {
|
||||
return GET("$apiUrl${chapter.url}", headers)
|
||||
}
|
||||
|
||||
override fun pageListParse(response: Response): List<Page> {
|
||||
val result = response.parseAs<PageListResponse>().chapter
|
||||
val chapterUrl = response.request.url.toString()
|
||||
.replace("/api", "")
|
||||
val preSlug = if (result.on_disk != 0 && result.on_disk != null) {
|
||||
"$baseUrl/storage/uploads/manga"
|
||||
} else {
|
||||
"https://images.${baseUrl.removePrefix("https://")}/manga"
|
||||
}
|
||||
return result.images
|
||||
.filterNot { it.endsWith(".ico") }
|
||||
.mapIndexed { index, img ->
|
||||
Page(index = index, url = chapterUrl, imageUrl = "$preSlug/manga_${result.manga_id}/chapter_${result.slug}/$img")
|
||||
}
|
||||
}
|
||||
|
||||
override fun imageRequest(page: Page): Request {
|
||||
val imageHeaders = headersBuilder()
|
||||
.set("Referer", page.url)
|
||||
.set("Accept", ACCEPT_IMAGE)
|
||||
.build()
|
||||
|
||||
return GET(page.imageUrl!!, imageHeaders)
|
||||
}
|
||||
|
||||
override fun imageUrlParse(response: Response): String {
|
||||
throw UnsupportedOperationException("not Used")
|
||||
}
|
||||
|
||||
private fun String.parseStatus(): Int {
|
||||
return when (this) {
|
||||
"Ongoing" -> SManga.ONGOING
|
||||
"Completed" -> SManga.COMPLETED
|
||||
"Cancelled" -> SManga.CANCELLED
|
||||
"Hiatus" -> SManga.ON_HIATUS
|
||||
else -> SManga.UNKNOWN
|
||||
}
|
||||
}
|
||||
|
||||
private inline fun <reified T> Response.parseAs(): T = use {
|
||||
json.decodeFromString(it.body.string())
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val ACCEPT_JSON = "application/json, text/plain, */*"
|
||||
private const val ACCEPT_IMAGE = "image/avif, image/webp, */*"
|
||||
private val JSON_MEDIA_TYPE = "application/json".toMediaType()
|
||||
|
||||
private val dateFormat by lazy {
|
||||
SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSSSS'Z'", Locale.ENGLISH)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,96 +0,0 @@
|
|||
package eu.kanade.tachiyomi.extension.en.earlymanga
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class SearchResponse(
|
||||
val data: List<SearchData>,
|
||||
val meta: SearchMeta,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class SearchData(
|
||||
val id: Int,
|
||||
val title: String,
|
||||
val slug: String,
|
||||
val cover: String? = null,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class MangaResponse(
|
||||
val main_manga: MangaData,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class MangaData(
|
||||
val id: Int,
|
||||
val title: String,
|
||||
val slug: String,
|
||||
val alt_titles: List<NameVal>?,
|
||||
val authors: List<String>?,
|
||||
val artists: List<String>?,
|
||||
val all_genres: List<NameVal>?,
|
||||
val pubstatus: List<NameVal>,
|
||||
val desc: String? = "Unknown",
|
||||
val cover: String? = null,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class NameVal(
|
||||
val name: String,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class ChapterList(
|
||||
val id: Int,
|
||||
val slug: String,
|
||||
val title: String?,
|
||||
val created_at: String?,
|
||||
val chapter_number: String,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class PageListResponse(
|
||||
val chapter: Chapter,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class Chapter(
|
||||
val id: Int,
|
||||
val manga_id: Int,
|
||||
val slug: String,
|
||||
val on_disk: Int?,
|
||||
val images: List<String>,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class SearchMeta(
|
||||
val current_page: Int,
|
||||
val last_page: Int,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class FilterResponse(
|
||||
val genres: List<Genre>,
|
||||
val sub_genres: List<Genre>,
|
||||
val contents: List<Genre>,
|
||||
val demographics: List<Genre>,
|
||||
val formats: List<Genre>,
|
||||
val themes: List<Genre>,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class SearchPayload(
|
||||
val excludedGenres_all: List<String>,
|
||||
val includedGenres_all: List<String>,
|
||||
val includedLanguages: List<String>,
|
||||
val includedPubstatus: List<String>,
|
||||
val list_order: String,
|
||||
val list_type: String,
|
||||
val term: String,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class Genre(
|
||||
val name: String,
|
||||
)
|
|
@ -1,93 +0,0 @@
|
|||
package eu.kanade.tachiyomi.extension.en.earlymanga
|
||||
|
||||
import eu.kanade.tachiyomi.source.model.Filter
|
||||
import eu.kanade.tachiyomi.source.model.FilterList
|
||||
|
||||
abstract class SelectFilter(
|
||||
name: String,
|
||||
private val options: List<Pair<String, String>>,
|
||||
defaultValue: String? = null,
|
||||
) : Filter.Select<String>(
|
||||
name,
|
||||
options.map { it.first }.toTypedArray(),
|
||||
options.indexOfFirst { it.second == defaultValue }.takeIf { it != -1 } ?: 0,
|
||||
) {
|
||||
val selected get() = options[state].second
|
||||
}
|
||||
|
||||
class CheckBoxFilter(
|
||||
name: String,
|
||||
val value: String,
|
||||
) : Filter.CheckBox(name)
|
||||
|
||||
abstract class CheckBoxFilterGroup(
|
||||
name: String,
|
||||
options: List<Pair<String, String>>,
|
||||
) : Filter.Group<CheckBoxFilter>(
|
||||
name,
|
||||
options.map { CheckBoxFilter(it.first, it.second) },
|
||||
) {
|
||||
val checked get() = state.filter { it.state }.map { it.value }
|
||||
}
|
||||
|
||||
class TriStateFilter(
|
||||
name: String,
|
||||
val value: String,
|
||||
) : Filter.TriState(name)
|
||||
|
||||
class TriStateFilterGroup(
|
||||
name: String,
|
||||
options: List<Pair<String, String>>,
|
||||
) : Filter.Group<TriStateFilter>(
|
||||
name,
|
||||
options.map { TriStateFilter(it.first, it.second) },
|
||||
) {
|
||||
val included get() = state.filter { it.isIncluded() }.map { it.value }
|
||||
val excluded get() = state.filter { it.isExcluded() }.map { it.value }
|
||||
}
|
||||
|
||||
class OrderByFilter(
|
||||
default: String? = null,
|
||||
) : SelectFilter("Order by", options.map { Pair(it, it) }, default) {
|
||||
companion object {
|
||||
private val options = listOf(
|
||||
"Views",
|
||||
"Bookmarks",
|
||||
"Number of chapters",
|
||||
"Rating",
|
||||
)
|
||||
|
||||
val POPULAR = FilterList(OrderByFilter("Views"))
|
||||
}
|
||||
}
|
||||
|
||||
class SortFilter : SelectFilter("Sort By", options) {
|
||||
companion object {
|
||||
private val options = listOf(
|
||||
Pair("Descending", "desc"),
|
||||
Pair("Ascending", "asc"),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class TypeFilter : CheckBoxFilterGroup("Type", options) {
|
||||
companion object {
|
||||
private val options = listOf(
|
||||
Pair("Manga", "Japanese"),
|
||||
Pair("Manhwa", "Korean"),
|
||||
Pair("Manhua", "Chinese"),
|
||||
Pair("Comic", "English"),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class StatusFilter : CheckBoxFilterGroup("Status", options.map { Pair(it, it) }) {
|
||||
companion object {
|
||||
private val options = listOf(
|
||||
"Ongoing",
|
||||
"Completed",
|
||||
"Cancelled",
|
||||
"Hiatus",
|
||||
)
|
||||
}
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
ext {
|
||||
extName = 'MangaDino.top (unoriginal)'
|
||||
extClass = '.MangaDinoTop'
|
||||
themePkg = 'madara'
|
||||
baseUrl = 'https://mangadino.top'
|
||||
overrideVersionCode = 0
|
||||
isNsfw = true
|
||||
}
|
||||
|
||||
apply from: "$rootDir/common.gradle"
|
Before Width: | Height: | Size: 3.1 KiB |
Before Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 4.5 KiB |
Before Width: | Height: | Size: 8.0 KiB |
Before Width: | Height: | Size: 12 KiB |
|
@ -1,7 +0,0 @@
|
|||
package eu.kanade.tachiyomi.extension.en.mangadinotop
|
||||
|
||||
import eu.kanade.tachiyomi.multisrc.madara.Madara
|
||||
|
||||
class MangaDinoTop : Madara("MangaDino.top (unoriginal)", "https://mangadino.top", "en") {
|
||||
override val useNewChapterEndpoint = false
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
ext {
|
||||
extName = 'MangaKitsune'
|
||||
extClass = '.MangaKitsune'
|
||||
themePkg = 'madara'
|
||||
baseUrl = 'https://mangakitsune.com'
|
||||
overrideVersionCode = 4
|
||||
isNsfw = true
|
||||
}
|
||||
|
||||
apply from: "$rootDir/common.gradle"
|
Before Width: | Height: | Size: 6.4 KiB |
Before Width: | Height: | Size: 3.3 KiB |
Before Width: | Height: | Size: 8.8 KiB |
Before Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 27 KiB |
|
@ -1,12 +0,0 @@
|
|||
package eu.kanade.tachiyomi.extension.en.mangakitsune
|
||||
|
||||
import eu.kanade.tachiyomi.multisrc.madara.Madara
|
||||
import eu.kanade.tachiyomi.source.model.SChapter
|
||||
import okhttp3.Response
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Locale
|
||||
|
||||
class MangaKitsune : Madara("MangaKitsune", "https://mangakitsune.com", "en", dateFormat = SimpleDateFormat("yyyy-MM-dd", Locale.US)) {
|
||||
|
||||
override fun chapterListParse(response: Response): List<SChapter> = super.chapterListParse(response).reversed()
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
ext {
|
||||
extName = 'Manga Mitsu'
|
||||
extClass = '.MangaMitsu'
|
||||
themePkg = 'madara'
|
||||
baseUrl = 'https://mangamitsu.com'
|
||||
overrideVersionCode = 2
|
||||
isNsfw = true
|
||||
}
|
||||
|
||||
apply from: "$rootDir/common.gradle"
|
Before Width: | Height: | Size: 3.9 KiB |
Before Width: | Height: | Size: 2.1 KiB |
Before Width: | Height: | Size: 5.0 KiB |
Before Width: | Height: | Size: 9.6 KiB |
Before Width: | Height: | Size: 14 KiB |
|
@ -1,5 +0,0 @@
|
|||
package eu.kanade.tachiyomi.extension.en.mangamitsu
|
||||
|
||||
import eu.kanade.tachiyomi.multisrc.madara.Madara
|
||||
|
||||
class MangaMitsu : Madara("Manga Mitsu", "https://mangamitsu.com", "en")
|
|
@ -1,9 +0,0 @@
|
|||
ext {
|
||||
extName = 'MangaOnline.team (unoriginal)'
|
||||
extClass = '.MangaOnlineTeamUnoriginal'
|
||||
themePkg = 'madara'
|
||||
baseUrl = 'https://mangaonline.team'
|
||||
overrideVersionCode = 0
|
||||
}
|
||||
|
||||
apply from: "$rootDir/common.gradle"
|
Before Width: | Height: | Size: 5.9 KiB |
Before Width: | Height: | Size: 3.1 KiB |
Before Width: | Height: | Size: 8.7 KiB |
Before Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 26 KiB |
|
@ -1,7 +0,0 @@
|
|||
package eu.kanade.tachiyomi.extension.en.mangaonlineteamunoriginal
|
||||
|
||||
import eu.kanade.tachiyomi.multisrc.madara.Madara
|
||||
|
||||
class MangaOnlineTeamUnoriginal : Madara("MangaOnline.team (unoriginal)", "https://mangaonline.team", "en") {
|
||||
override val useNewChapterEndpoint = false
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
ext {
|
||||
extName = 'Manga Rock.team (unoriginal)'
|
||||
extClass = '.MangaRockTeamUnoriginal'
|
||||
themePkg = 'madara'
|
||||
baseUrl = 'https://mangarock.team'
|
||||
overrideVersionCode = 0
|
||||
}
|
||||
|
||||
apply from: "$rootDir/common.gradle"
|
Before Width: | Height: | Size: 2.6 KiB |
Before Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 3.6 KiB |
Before Width: | Height: | Size: 6.4 KiB |
Before Width: | Height: | Size: 9.3 KiB |
|
@ -1,7 +0,0 @@
|
|||
package eu.kanade.tachiyomi.extension.en.mangarockteamunoriginal
|
||||
|
||||
import eu.kanade.tachiyomi.multisrc.madara.Madara
|
||||
|
||||
class MangaRockTeamUnoriginal : Madara("Manga Rock.team (unoriginal)", "https://mangarock.team", "en") {
|
||||
override val useNewChapterEndpoint = false
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
ext {
|
||||
extName = 'MangaYami'
|
||||
extClass = '.MangaYami'
|
||||
themePkg = 'madara'
|
||||
baseUrl = 'https://www.mangayami.club'
|
||||
overrideVersionCode = 2
|
||||
}
|
||||
|
||||
apply from: "$rootDir/common.gradle"
|
Before Width: | Height: | Size: 8.8 KiB |
Before Width: | Height: | Size: 4.1 KiB |
Before Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 26 KiB |
Before Width: | Height: | Size: 38 KiB |
|
@ -1,5 +0,0 @@
|
|||
package eu.kanade.tachiyomi.extension.en.mangayami
|
||||
|
||||
import eu.kanade.tachiyomi.multisrc.madara.Madara
|
||||
|
||||
class MangaYami : Madara("MangaYami", "https://www.mangayami.club", "en")
|
|
@ -1,9 +0,0 @@
|
|||
ext {
|
||||
extName = 'ManhuaDex'
|
||||
extClass = '.ManhuaDex'
|
||||
themePkg = 'madara'
|
||||
baseUrl = 'https://manhuadex.com'
|
||||
overrideVersionCode = 0
|
||||
}
|
||||
|
||||
apply from: "$rootDir/common.gradle"
|
Before Width: | Height: | Size: 4.2 KiB |
Before Width: | Height: | Size: 2.4 KiB |
Before Width: | Height: | Size: 5.4 KiB |
Before Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 14 KiB |
|
@ -1,7 +0,0 @@
|
|||
package eu.kanade.tachiyomi.extension.en.manhuadex
|
||||
|
||||
import eu.kanade.tachiyomi.multisrc.madara.Madara
|
||||
|
||||
class ManhuaDex : Madara("ManhuaDex", "https://manhuadex.com", "en") {
|
||||
override val useNewChapterEndpoint = true
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
ext {
|
||||
extName = 'Manhwua.fans'
|
||||
extClass = '.Manhwuafans'
|
||||
themePkg = 'madara'
|
||||
baseUrl = 'https://manhwua.fans'
|
||||
overrideVersionCode = 0
|
||||
isNsfw = true
|
||||
}
|
||||
|
||||
apply from: "$rootDir/common.gradle"
|
Before Width: | Height: | Size: 5.2 KiB |
Before Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 7.8 KiB |
Before Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 29 KiB |
|
@ -1,7 +0,0 @@
|
|||
package eu.kanade.tachiyomi.extension.en.manhwuafans
|
||||
|
||||
import eu.kanade.tachiyomi.multisrc.madara.Madara
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Locale
|
||||
|
||||
class Manhwuafans : Madara("Manhwua.fans", "https://manhwua.fans", "en", dateFormat = SimpleDateFormat("yyyy'年'M'月'd", Locale.US))
|
|
@ -1,10 +0,0 @@
|
|||
ext {
|
||||
extName = 'Pony Manga'
|
||||
extClass = '.PonyManga'
|
||||
themePkg = 'madara'
|
||||
baseUrl = 'https://ponymanga.com'
|
||||
overrideVersionCode = 0
|
||||
isNsfw = true
|
||||
}
|
||||
|
||||
apply from: "$rootDir/common.gradle"
|
Before Width: | Height: | Size: 4.5 KiB |
Before Width: | Height: | Size: 2.4 KiB |
Before Width: | Height: | Size: 6.8 KiB |
Before Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 20 KiB |
|
@ -1,7 +0,0 @@
|
|||
package eu.kanade.tachiyomi.extension.en.ponymanga
|
||||
|
||||
import eu.kanade.tachiyomi.multisrc.madara.Madara
|
||||
|
||||
class PonyManga : Madara("Pony Manga", "https://ponymanga.com", "en") {
|
||||
override val useNewChapterEndpoint = false
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
ext {
|
||||
extName = 'Atlantis Scan'
|
||||
extClass = '.AtlantisScan'
|
||||
themePkg = 'mangathemesia'
|
||||
baseUrl = 'https://scansatlanticos.com'
|
||||
overrideVersionCode = 6
|
||||
isNsfw = true
|
||||
}
|
||||
|
||||
apply from: "$rootDir/common.gradle"
|
Before Width: | Height: | Size: 5.4 KiB |
Before Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 7.9 KiB |
Before Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 22 KiB |
|
@ -1,22 +0,0 @@
|
|||
package eu.kanade.tachiyomi.extension.es.atlantisscan
|
||||
|
||||
import eu.kanade.tachiyomi.multisrc.mangathemesia.MangaThemesia
|
||||
import eu.kanade.tachiyomi.network.interceptor.rateLimit
|
||||
import okhttp3.OkHttpClient
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Locale
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class AtlantisScan : MangaThemesia(
|
||||
"Atlantis Scan",
|
||||
"https://scansatlanticos.com",
|
||||
"es",
|
||||
dateFormat = SimpleDateFormat("MMMM dd, yyyy", Locale.US),
|
||||
) {
|
||||
// Site moved from Madara to MangaThemesia
|
||||
override val versionId = 2
|
||||
|
||||
override val client: OkHttpClient = super.client.newBuilder()
|
||||
.rateLimit(2, 1, TimeUnit.SECONDS)
|
||||
.build()
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
ext {
|
||||
extName = 'Lucky Manga'
|
||||
extClass = '.LuckyManga'
|
||||
themePkg = 'madara'
|
||||
baseUrl = 'https://luckymanga.com'
|
||||
overrideVersionCode = 0
|
||||
isNsfw = true
|
||||
}
|
||||
|
||||
apply from: "$rootDir/common.gradle"
|
Before Width: | Height: | Size: 5.4 KiB |
Before Width: | Height: | Size: 3.0 KiB |
Before Width: | Height: | Size: 8.0 KiB |
Before Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 23 KiB |
|
@ -1,21 +0,0 @@
|
|||
package eu.kanade.tachiyomi.extension.es.luckymanga
|
||||
|
||||
import eu.kanade.tachiyomi.multisrc.madara.Madara
|
||||
import eu.kanade.tachiyomi.network.interceptor.rateLimit
|
||||
import okhttp3.OkHttpClient
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Locale
|
||||
|
||||
class LuckyManga : Madara(
|
||||
"Lucky Manga",
|
||||
"https://luckymanga.com",
|
||||
"es",
|
||||
SimpleDateFormat("d MMMM, yyyy", Locale("es")),
|
||||
) {
|
||||
override val useLoadMoreRequest = LoadMoreStrategy.Never
|
||||
override val useNewChapterEndpoint = true
|
||||
|
||||
override val client: OkHttpClient = super.client.newBuilder()
|
||||
.rateLimit(2)
|
||||
.build()
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<application>
|
||||
<activity
|
||||
android:name=".es.tumanhwas.TuManhwasUrlActivity"
|
||||
android:excludeFromRecents="true"
|
||||
android:exported="true"
|
||||
android:theme="@android:style/Theme.NoDisplay">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
|
||||
<data
|
||||
android:host="tumanhwas.com"
|
||||
android:pathPattern="/manga/..*"
|
||||
android:scheme="https" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
</manifest>
|
|
@ -1,8 +0,0 @@
|
|||
ext {
|
||||
extName = 'TuManhwas'
|
||||
extClass = '.TuManhwas'
|
||||
extVersionCode = 1
|
||||
isNsfw = true
|
||||
}
|
||||
|
||||
apply from: "$rootDir/common.gradle"
|
Before Width: | Height: | Size: 4.5 KiB |
Before Width: | Height: | Size: 2.4 KiB |
Before Width: | Height: | Size: 6.7 KiB |