Comicastle - move from FRReader to its own extension (#3923)
This commit is contained in:
parent
351832ff64
commit
5cf25b6c47
|
@ -5,7 +5,7 @@ ext {
|
||||||
extName = 'FMReader (multiple aggregators)'
|
extName = 'FMReader (multiple aggregators)'
|
||||||
pkgNameSuffix = 'all.fmreader'
|
pkgNameSuffix = 'all.fmreader'
|
||||||
extClass = '.FMReaderFactory'
|
extClass = '.FMReaderFactory'
|
||||||
extVersionCode = 19
|
extVersionCode = 20
|
||||||
libVersion = '1.2'
|
libVersion = '1.2'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,6 @@ class FMReaderFactory : SourceFactory {
|
||||||
Manhwa18(),
|
Manhwa18(),
|
||||||
EighteenLHPlus(),
|
EighteenLHPlus(),
|
||||||
MangaTR(),
|
MangaTR(),
|
||||||
Comicastle(),
|
|
||||||
Manhwa18Net(),
|
Manhwa18Net(),
|
||||||
Manhwa18NetRaw(),
|
Manhwa18NetRaw(),
|
||||||
SayTruyen(),
|
SayTruyen(),
|
||||||
|
@ -207,43 +206,6 @@ class MangaTR : FMReader("Manga-TR", "https://manga-tr.com", "tr") {
|
||||||
override fun pageListRequest(chapter: SChapter): Request = GET("$baseUrl/${chapter.url.substringAfter("cek/")}", headers)
|
override fun pageListRequest(chapter: SChapter): Request = GET("$baseUrl/${chapter.url.substringAfter("cek/")}", headers)
|
||||||
}
|
}
|
||||||
|
|
||||||
class Comicastle : FMReader("Comicastle", "https://www.comicastle.org", "en") {
|
|
||||||
override fun popularMangaRequest(page: Int): Request =
|
|
||||||
GET("$baseUrl/comic-dir?sorting=views&c-page=$page&sorting-type=DESC", headers)
|
|
||||||
override fun popularMangaNextPageSelector() = "li:contains(»):not(.disabled)"
|
|
||||||
override fun latestUpdatesRequest(page: Int): Request =
|
|
||||||
GET("$baseUrl/comic-dir?sorting=lastUpdate&c-page=$page&sorting-type=ASC", headers)
|
|
||||||
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request =
|
|
||||||
GET("$baseUrl/comic-dir?q=$query" + if (page > 1) "&c-page=$page" else "", headers)
|
|
||||||
override fun getFilterList() = FilterList()
|
|
||||||
override fun mangaDetailsParse(document: Document): SManga {
|
|
||||||
val manga = SManga.create()
|
|
||||||
val infoElement = document.select("div.col-md-9").first()
|
|
||||||
|
|
||||||
manga.author = infoElement.select("tr + tr td a").first().text()
|
|
||||||
manga.artist = infoElement.select("tr + tr td + td a").text()
|
|
||||||
manga.genre = infoElement.select("tr + tr td + td + td").text()
|
|
||||||
manga.description = infoElement.select("p").text().trim()
|
|
||||||
manga.thumbnail_url = document.select("img.manga-cover").attr("abs:src")
|
|
||||||
|
|
||||||
return manga
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun chapterListSelector() = "div.col-md-9 table:last-of-type tr"
|
|
||||||
override fun chapterListParse(response: Response): List<SChapter> = super.chapterListParse(response).reversed()
|
|
||||||
override fun pageListParse(document: Document): List<Page> {
|
|
||||||
val pages = mutableListOf<Page>()
|
|
||||||
|
|
||||||
document.select("div.text-center select option").forEachIndexed { i, imgPage ->
|
|
||||||
pages.add(Page(i, imgPage.attr("value")))
|
|
||||||
}
|
|
||||||
return pages
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun imageUrlParse(document: Document): String = document.select("img.chapter-img").attr("abs:src").trim()
|
|
||||||
override fun getGenreList() = getComicsGenreList()
|
|
||||||
}
|
|
||||||
|
|
||||||
class Manhwa18Net : FMReader("Manhwa18.net", "https://manhwa18.net", "en") {
|
class Manhwa18Net : FMReader("Manhwa18.net", "https://manhwa18.net", "en") {
|
||||||
override fun popularMangaRequest(page: Int): Request =
|
override fun popularMangaRequest(page: Int): Request =
|
||||||
GET("$baseUrl/$requestPath?listType=pagination&page=$page&sort=views&sort_type=DESC&ungenre=raw", headers)
|
GET("$baseUrl/$requestPath?listType=pagination&page=$page&sort=views&sort_type=DESC&ungenre=raw", headers)
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
apply plugin: 'com.android.application'
|
||||||
|
apply plugin: 'kotlin-android'
|
||||||
|
|
||||||
|
ext {
|
||||||
|
extName = 'Comicastle'
|
||||||
|
pkgNameSuffix = 'en.comicastle'
|
||||||
|
extClass = '.Comicastle'
|
||||||
|
extVersionCode = 1
|
||||||
|
libVersion = '1.2'
|
||||||
|
}
|
||||||
|
|
||||||
|
apply from: "$rootDir/common.gradle"
|
Binary file not shown.
After Width: | Height: | Size: 3.7 KiB |
Binary file not shown.
After Width: | Height: | Size: 1.9 KiB |
Binary file not shown.
After Width: | Height: | Size: 5.6 KiB |
Binary file not shown.
After Width: | Height: | Size: 11 KiB |
Binary file not shown.
After Width: | Height: | Size: 16 KiB |
Binary file not shown.
After Width: | Height: | Size: 70 KiB |
|
@ -0,0 +1,163 @@
|
||||||
|
package eu.kanade.tachiyomi.extension.en.comicastle
|
||||||
|
|
||||||
|
import eu.kanade.tachiyomi.network.GET
|
||||||
|
import eu.kanade.tachiyomi.network.POST
|
||||||
|
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 okhttp3.HttpUrl
|
||||||
|
import okhttp3.MediaType
|
||||||
|
import okhttp3.OkHttpClient
|
||||||
|
import okhttp3.Request
|
||||||
|
import okhttp3.RequestBody
|
||||||
|
import okhttp3.Response
|
||||||
|
import org.jsoup.nodes.Document
|
||||||
|
import org.jsoup.nodes.Element
|
||||||
|
import java.net.URLEncoder
|
||||||
|
import java.util.Calendar
|
||||||
|
import java.util.Locale
|
||||||
|
|
||||||
|
class Comicastle : ParsedHttpSource() {
|
||||||
|
|
||||||
|
override val name = "Comicastle"
|
||||||
|
|
||||||
|
override val versionId = 2
|
||||||
|
|
||||||
|
override val baseUrl = "https://www.comicastle.org"
|
||||||
|
|
||||||
|
override val lang = "en"
|
||||||
|
|
||||||
|
override val supportsLatest = true
|
||||||
|
|
||||||
|
override val client: OkHttpClient = network.cloudflareClient
|
||||||
|
|
||||||
|
private fun pageSegments(page: Int): String = if (page > 1) "/index/${(page - 1) * 30}" else ""
|
||||||
|
|
||||||
|
// Popular
|
||||||
|
|
||||||
|
override fun popularMangaRequest(page: Int): Request {
|
||||||
|
return GET("$baseUrl/library/popular/desc" + pageSegments(page), headers)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun popularMangaSelector() = "div.col-lg-2"
|
||||||
|
|
||||||
|
override fun popularMangaFromElement(element: Element): SManga {
|
||||||
|
return SManga.create().apply {
|
||||||
|
title = element.select("p").text()
|
||||||
|
setUrlWithoutDomain(element.select("a").first().attr("href"))
|
||||||
|
thumbnail_url = element.select("img").attr("abs:src")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun popularMangaNextPageSelector() = "li.page-item.next a"
|
||||||
|
|
||||||
|
// Latest
|
||||||
|
|
||||||
|
override fun latestUpdatesRequest(page: Int): Request {
|
||||||
|
return GET("$baseUrl/library/postdate/desc" + pageSegments(page), headers)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun latestUpdatesSelector() = popularMangaSelector()
|
||||||
|
|
||||||
|
override fun latestUpdatesFromElement(element: Element): SManga = popularMangaFromElement(element)
|
||||||
|
|
||||||
|
override fun latestUpdatesNextPageSelector() = popularMangaNextPageSelector()
|
||||||
|
|
||||||
|
// Search
|
||||||
|
|
||||||
|
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
|
||||||
|
val url = HttpUrl.parse("$baseUrl/library/search")!!.newBuilder()
|
||||||
|
var rBody: RequestBody? = null
|
||||||
|
|
||||||
|
(filters.let { if (it.isEmpty()) getFilterList() else filters })
|
||||||
|
.filterIsInstance<PostFilter>()
|
||||||
|
.firstOrNull { it.hasSelection() }
|
||||||
|
?.let { filter ->
|
||||||
|
url.addPathSegment(filter.pathSegment)
|
||||||
|
rBody = filter.toRequestBody()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rBody == null) rBody = createRequestBody(query)
|
||||||
|
|
||||||
|
return POST(url.toString(), headers, rBody!!)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun searchMangaSelector() = popularMangaSelector()
|
||||||
|
|
||||||
|
override fun searchMangaFromElement(element: Element): SManga = popularMangaFromElement(element)
|
||||||
|
|
||||||
|
override fun searchMangaNextPageSelector() = popularMangaNextPageSelector()
|
||||||
|
|
||||||
|
// Details
|
||||||
|
|
||||||
|
override fun mangaDetailsParse(document: Document): SManga {
|
||||||
|
return SManga.create().apply {
|
||||||
|
with(document.select("div.card-body > div.mb-5")) {
|
||||||
|
thumbnail_url = select("img").attr("abs:src")
|
||||||
|
val publisher = select("p:contains(Publisher) button")
|
||||||
|
.firstOrNull()?.let { "Publisher: ${it.text()}\n" }
|
||||||
|
description = publisher + select("h5:contains(Description) + p").text()
|
||||||
|
author = select("p:contains(Writer) button").joinToString { it.text() }
|
||||||
|
artist = select("p:contains(Artist) button").joinToString { it.text() }
|
||||||
|
status = select("p span.mr-1 strong").text().toStatus()
|
||||||
|
genre = select("p:contains(Genre) button").joinToString { it.text() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun String.toStatus() = when {
|
||||||
|
this.contains("Ongoing", ignoreCase = true) -> SManga.ONGOING
|
||||||
|
this.contains("Completed", ignoreCase = true) -> SManga.COMPLETED
|
||||||
|
else -> SManga.UNKNOWN
|
||||||
|
}
|
||||||
|
|
||||||
|
// Chapters
|
||||||
|
|
||||||
|
override fun chapterListParse(response: Response): List<SChapter> {
|
||||||
|
return super.chapterListParse(response).reversed()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun chapterListSelector() = "table tr a"
|
||||||
|
|
||||||
|
override fun chapterFromElement(element: Element): SChapter {
|
||||||
|
return SChapter.create().apply {
|
||||||
|
name = element.text()
|
||||||
|
setUrlWithoutDomain(element.attr("href"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pages
|
||||||
|
|
||||||
|
override fun pageListParse(document: Document): List<Page> {
|
||||||
|
return document.select("div.img-list img").mapIndexed { i, img ->
|
||||||
|
Page(i, "", img.attr("abs:src"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun imageUrlParse(document: Document): String = throw UnsupportedOperationException("Not used")
|
||||||
|
|
||||||
|
// Filters
|
||||||
|
|
||||||
|
override fun getFilterList() = FilterList(
|
||||||
|
Filter.Header("Cannot combine search types!"),
|
||||||
|
Filter.Separator(),
|
||||||
|
PostFilter("Genre", getGenreList()),
|
||||||
|
PostFilter("Year", getYearList()),
|
||||||
|
PostFilter("Publisher", getPublisherList())
|
||||||
|
)
|
||||||
|
|
||||||
|
private open class PostFilter(name: String, val vals: Array<String>) : Filter.Select<String>(name, vals) {
|
||||||
|
val pathSegment = name.toLowerCase(Locale.US)
|
||||||
|
fun hasSelection(): Boolean = state != 0
|
||||||
|
fun toRequestBody(): RequestBody = createRequestBody(vals[state])
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getGenreList() = arrayOf("<Select>", "Action/Adventure", "Anthology", "Anthropomorphic", "Biography", "Children's", "Comedy", "Crime", "Drama", "Fantasy", "Gore", "Graphic Novels", "Historical", "Holiday", "Horror", "Leading Ladies", "LGBTQ", "Literature", "Manga", "Martial Arts", "Mature", "Military", "Movies & TV", "Music", "Mystery", "Mythology", "Non-Fiction", "Original Series", "Political", "Post-Apocalyptic", "Pulp", "Religious", "Risque", "Robots, Cyborgs & Mecha", "Romance", "School Life", "Science Fiction", "Slice of Life", "Spy", "Steampunk", "Superhero", "Supernatural/Occult", "Suspense", "Vampires", "Video Games", "Web Comics", "Werewolves", "Western", "Zombies")
|
||||||
|
private fun getYearList() = arrayOf("<Select>") + (Calendar.getInstance()[1] downTo 1963).map { it.toString() }.toTypedArray()
|
||||||
|
private fun getPublisherList() = arrayOf("<Select>", "Action Lab", "Aftershock", "AHOY", "American Mythology", "Aspen", "Avatar Press", "AWA Studios", "Black Mask", "BOOM! Studios", "Dark Horse", "DC", "Death Rattle", "Dynamite", "IDW", "Image", "Magnetic Press", "Marvel", "MAX", "Titan", "Ubiworkshop", "Valiant", "Vault", "Vertigo", "Wildstorm", "Zenescope")
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createRequestBody(value: String) = RequestBody.create(MediaType.parse("application/x-www-form-urlencoded"), "search=" + URLEncoder.encode(value, "UTF-8"))
|
Loading…
Reference in New Issue