Comicastle - move from FRReader to its own extension (#3923)

This commit is contained in:
Mike 2020-07-27 05:29:25 -04:00 committed by GitHub
parent 351832ff64
commit 5cf25b6c47
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 176 additions and 39 deletions

View File

@ -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'
} }

View File

@ -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)

View File

@ -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

View File

@ -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"))