Remove defunct extensions (2/2) (#1824)
Remove defunct extensions (2/2)
|
@ -1,12 +0,0 @@
|
||||||
apply plugin: 'com.android.application'
|
|
||||||
apply plugin: 'kotlin-android'
|
|
||||||
|
|
||||||
ext {
|
|
||||||
appName = 'Tachiyomi: GetManhwa'
|
|
||||||
pkgNameSuffix = 'en.getmanhwa'
|
|
||||||
extClass = '.GetManhwa'
|
|
||||||
extVersionCode = 1
|
|
||||||
libVersion = '1.2'
|
|
||||||
}
|
|
||||||
|
|
||||||
apply from: "$rootDir/common.gradle"
|
|
Before Width: | Height: | Size: 5.2 KiB |
Before Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 7.8 KiB |
Before Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 24 KiB |
Before Width: | Height: | Size: 157 KiB |
|
@ -1,254 +0,0 @@
|
||||||
package eu.kanade.tachiyomi.extension.en.getmanhwa
|
|
||||||
|
|
||||||
import eu.kanade.tachiyomi.network.GET
|
|
||||||
import eu.kanade.tachiyomi.source.model.*
|
|
||||||
import eu.kanade.tachiyomi.source.online.ParsedHttpSource
|
|
||||||
import eu.kanade.tachiyomi.util.asJsoup
|
|
||||||
import okhttp3.OkHttpClient
|
|
||||||
import okhttp3.Request
|
|
||||||
import okhttp3.Response
|
|
||||||
import org.jsoup.nodes.Document
|
|
||||||
import org.jsoup.nodes.Element
|
|
||||||
import java.text.SimpleDateFormat
|
|
||||||
import java.util.*
|
|
||||||
|
|
||||||
class GetManhwa : ParsedHttpSource() {
|
|
||||||
|
|
||||||
override val name = "GetManhwa"
|
|
||||||
|
|
||||||
override val baseUrl = "https://getmanhwa.com"
|
|
||||||
|
|
||||||
override val lang = "en"
|
|
||||||
|
|
||||||
override val supportsLatest = true
|
|
||||||
|
|
||||||
override val client: OkHttpClient = network.cloudflareClient
|
|
||||||
|
|
||||||
// Popular
|
|
||||||
|
|
||||||
override fun popularMangaRequest(page: Int): Request {
|
|
||||||
return if (page == 1) {
|
|
||||||
GET(baseUrl, headers)
|
|
||||||
} else {
|
|
||||||
GET("$baseUrl/home/page-$page/", headers)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun popularMangaParse(response: Response): MangasPage {
|
|
||||||
return parseMangaDocument(response.asJsoup())
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun parseMangaDocument(document: Document): MangasPage {
|
|
||||||
val mangas = mutableListOf<SManga>()
|
|
||||||
|
|
||||||
document.select(popularMangaSelector()).map{ mangas.add(popularMangaFromElement(it)) }
|
|
||||||
|
|
||||||
return MangasPage(mangas, document.select(popularMangaNextPageSelector()).isNotEmpty())
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun popularMangaSelector() = "section:has(h1.elementor-heading-title) div.elementor-widget-wrap section:has(img)"
|
|
||||||
|
|
||||||
override fun popularMangaFromElement(element: Element): SManga {
|
|
||||||
val manga = SManga.create()
|
|
||||||
|
|
||||||
manga.setUrlWithoutDomain(element.select("a").attr("href"))
|
|
||||||
manga.title = element.select("div.elementor-flip-box__layer__description").text()
|
|
||||||
manga.thumbnail_url = element.select("img").attr("abs:src")
|
|
||||||
|
|
||||||
return manga
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun popularMangaNextPageSelector() = "i.fa-angle-right"
|
|
||||||
|
|
||||||
// Latest
|
|
||||||
|
|
||||||
override fun latestUpdatesRequest(page: Int): Request {
|
|
||||||
return GET(baseUrl, headers)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun latestUpdatesSelector() = "div.elementor-widget-wrap:contains(recent episodes) [data-column-clickable]"
|
|
||||||
|
|
||||||
override fun latestUpdatesFromElement(element: Element): SManga {
|
|
||||||
val manga = SManga.create()
|
|
||||||
|
|
||||||
manga.setUrlWithoutDomain(element.attr("data-column-clickable").substringBeforeLast("chapter"))
|
|
||||||
manga.title = element.select("div.elementor-flip-box__layer__description").first().text()
|
|
||||||
|
|
||||||
return manga
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun latestUpdatesNextPageSelector() = "a.next:has(i.fa-angle-right)"
|
|
||||||
|
|
||||||
// Search
|
|
||||||
|
|
||||||
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
|
|
||||||
return if (query.isNotEmpty()) {
|
|
||||||
GET("$baseUrl/?s=$query", headers)
|
|
||||||
} else {
|
|
||||||
lateinit var genre: String
|
|
||||||
filters.forEach { filter ->
|
|
||||||
when (filter) {
|
|
||||||
is GenreFilter -> {
|
|
||||||
genre = filter.toUriPart()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
GET("$baseUrl/genre-$genre/",headers)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun searchMangaParse(response: Response): MangasPage {
|
|
||||||
val document = response.asJsoup()
|
|
||||||
|
|
||||||
return if (document.location().contains("?s=")) {
|
|
||||||
// for search by query
|
|
||||||
val mangas = mutableListOf<SManga>()
|
|
||||||
document.select(searchMangaSelector()).map{ e -> mangas.add(searchMangaFromElement(e)) }
|
|
||||||
MangasPage(mangas, document.select(searchMangaNextPageSelector()).isNotEmpty())
|
|
||||||
} else {
|
|
||||||
// for search by genre
|
|
||||||
parseMangaDocument(document)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun searchMangaSelector() = "div.search-entry-inner"
|
|
||||||
|
|
||||||
override fun searchMangaFromElement(element: Element): SManga {
|
|
||||||
val manga = SManga.create()
|
|
||||||
|
|
||||||
element.select("h2 a").let{
|
|
||||||
manga.title = it.text()
|
|
||||||
manga.setUrlWithoutDomain(it.attr("href"))
|
|
||||||
}
|
|
||||||
manga.thumbnail_url = element.select("img").attr("abs:src")
|
|
||||||
|
|
||||||
return manga
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun searchMangaNextPageSelector() = "not using this"
|
|
||||||
|
|
||||||
// Manga summary page
|
|
||||||
|
|
||||||
override fun mangaDetailsParse(document: Document): SManga {
|
|
||||||
val infoElement = document.select("div.elementor-row:contains(creator)")
|
|
||||||
|
|
||||||
val manga = SManga.create()
|
|
||||||
manga.title = infoElement.select("h2:not(:has(a))").first().text()
|
|
||||||
manga.author = infoElement.select("div.elementor-text-editor:contains(creator) p").first().text().substringAfter("Creator: ")
|
|
||||||
val status = infoElement.select("span.elementor-button-text").text()
|
|
||||||
manga.status = parseStatus(status)
|
|
||||||
manga.genre = infoElement.select("div.elementor-clearfix a").text().replace(" ", ", ")
|
|
||||||
manga.description = infoElement.select("div.elementor-clearfix:not(:contains(creator))").text()
|
|
||||||
manga.thumbnail_url = infoElement.select("img").attr("abs:src")
|
|
||||||
return manga
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun parseStatus(status: String?) = when (status?.toLowerCase()) {
|
|
||||||
null -> SManga.UNKNOWN
|
|
||||||
"monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday" -> SManga.ONGOING
|
|
||||||
"end" -> SManga.COMPLETED
|
|
||||||
else -> SManga.UNKNOWN
|
|
||||||
}
|
|
||||||
|
|
||||||
// Chapters
|
|
||||||
|
|
||||||
/** Although getmanhwa isn't madara-based per se, there's a possibility of loading a page bassed
|
|
||||||
* off of madara, hence two selectors and an if-then for chapterFromElement
|
|
||||||
*/
|
|
||||||
override fun chapterListSelector() = "[data-column-clickable]:contains(chapter), li.wp-manga-chapter"
|
|
||||||
|
|
||||||
override fun chapterListParse(response: Response): List<SChapter> {
|
|
||||||
return super.chapterListParse(response).reversed()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun chapterFromElement(element: Element): SChapter {
|
|
||||||
val chapter = SChapter.create()
|
|
||||||
|
|
||||||
if (element.hasAttr("data-id")) {
|
|
||||||
chapter.setUrlWithoutDomain(element.attr("data-column-clickable"))
|
|
||||||
chapter.name = element.text().substringBeforeLast(" – ")
|
|
||||||
chapter.date_upload = parseChapterDate(element.select("div.elementor-clearfix").text().substringAfterLast(" – ", "0").trim()) ?: 0
|
|
||||||
} else {
|
|
||||||
element.select("a").let{
|
|
||||||
chapter.setUrlWithoutDomain(it.attr("href"))
|
|
||||||
chapter.name = it.text()
|
|
||||||
}
|
|
||||||
chapter.date_upload = parseChapterDate(element.select("span i").text()) ?: 0
|
|
||||||
}
|
|
||||||
return chapter
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
val dateFormat by lazy {
|
|
||||||
SimpleDateFormat("MMM dd, yyyy", Locale.US)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun parseChapterDate(string: String): Long? {
|
|
||||||
return when {
|
|
||||||
string == "0" -> 0
|
|
||||||
"ago" in string -> parseRelativeDate(string) ?: 0
|
|
||||||
else -> dateFormat.parse(string).time
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Subtract relative date (e.g. posted 3 days ago)
|
|
||||||
private fun parseRelativeDate(date: String): Long? {
|
|
||||||
val trimmedDate = date.substringBefore(" ago").removeSuffix("s").split(" ")
|
|
||||||
|
|
||||||
val calendar = Calendar.getInstance()
|
|
||||||
when (trimmedDate[1]) {
|
|
||||||
"month" -> calendar.apply { add(Calendar.MONTH, -trimmedDate[0].toInt()) }
|
|
||||||
"week" -> calendar.apply { add(Calendar.WEEK_OF_MONTH, -trimmedDate[0].toInt()) }
|
|
||||||
"day" -> calendar.apply { add(Calendar.DAY_OF_MONTH, -trimmedDate[0].toInt()) }
|
|
||||||
"hour" -> calendar.apply { add(Calendar.HOUR_OF_DAY, -trimmedDate[0].toInt()) }
|
|
||||||
"minute" -> calendar.apply { add(Calendar.MINUTE, -trimmedDate[0].toInt()) }
|
|
||||||
"second" -> calendar.apply { add(Calendar.SECOND, 0) }
|
|
||||||
}
|
|
||||||
|
|
||||||
return calendar.timeInMillis
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pages
|
|
||||||
|
|
||||||
override fun pageListRequest(chapter: SChapter): Request {
|
|
||||||
return GET("https://getmanhwa.co/${chapter.url}")
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun pageListParse(document: Document): List<Page> {
|
|
||||||
val pages = mutableListOf<Page>()
|
|
||||||
|
|
||||||
document.select("img.wp-manga-chapter-img").forEachIndexed { i, img ->
|
|
||||||
pages.add(Page(i, "", img.attr("abs:src")))
|
|
||||||
}
|
|
||||||
|
|
||||||
return pages
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun imageUrlParse(document: Document): String = throw UnsupportedOperationException("Not used")
|
|
||||||
|
|
||||||
// Filters
|
|
||||||
|
|
||||||
override fun getFilterList() = FilterList(
|
|
||||||
Filter.Header("NOTE: Ignored if using text search!"),
|
|
||||||
GenreFilter()
|
|
||||||
)
|
|
||||||
|
|
||||||
private class GenreFilter: UriPartFilter("Genre", arrayOf(
|
|
||||||
Pair("All","all"),
|
|
||||||
Pair("Romance","romance"),
|
|
||||||
Pair("Drama","drama"),
|
|
||||||
Pair("Comedy","comedy"),
|
|
||||||
Pair("Fantasy","fantasy"),
|
|
||||||
Pair("Action","action"),
|
|
||||||
Pair("BL","bl"),
|
|
||||||
Pair("GL","gl"),
|
|
||||||
Pair("Horror","horror"),
|
|
||||||
Pair("School Life","school-life")
|
|
||||||
))
|
|
||||||
|
|
||||||
private open class UriPartFilter(displayName: String, val vals: Array<Pair<String, String>>) :
|
|
||||||
Filter.Select<String>(displayName, vals.map { it.first }.toTypedArray()) {
|
|
||||||
fun toUriPart() = vals[state].second
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,12 +0,0 @@
|
||||||
apply plugin: 'com.android.application'
|
|
||||||
apply plugin: 'kotlin-android'
|
|
||||||
|
|
||||||
ext {
|
|
||||||
appName = 'Tachiyomi: DoujinHentai'
|
|
||||||
pkgNameSuffix = 'es.doujinhentai'
|
|
||||||
extClass = '.DoujinHentai'
|
|
||||||
extVersionCode = 2
|
|
||||||
libVersion = '1.2'
|
|
||||||
}
|
|
||||||
|
|
||||||
apply from: "$rootDir/common.gradle"
|
|
Before Width: | Height: | Size: 3.2 KiB |
Before Width: | Height: | Size: 2.1 KiB |
Before Width: | Height: | Size: 4.2 KiB |
Before Width: | Height: | Size: 6.8 KiB |
Before Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 13 KiB |
|
@ -1,117 +0,0 @@
|
||||||
package eu.kanade.tachiyomi.extension.es.doujinhentai
|
|
||||||
|
|
||||||
import eu.kanade.tachiyomi.network.GET
|
|
||||||
import eu.kanade.tachiyomi.source.model.*
|
|
||||||
import eu.kanade.tachiyomi.source.online.ParsedHttpSource
|
|
||||||
import okhttp3.Request
|
|
||||||
import org.jsoup.nodes.Document
|
|
||||||
import org.jsoup.nodes.Element
|
|
||||||
import java.text.ParseException
|
|
||||||
import java.text.SimpleDateFormat
|
|
||||||
import java.util.*
|
|
||||||
|
|
||||||
class DoujinHentai : ParsedHttpSource() {
|
|
||||||
|
|
||||||
override val baseUrl = "https://doujinhentai.net"
|
|
||||||
|
|
||||||
override val lang = "es"
|
|
||||||
|
|
||||||
override val name = "DoujinHentai"
|
|
||||||
|
|
||||||
override val supportsLatest = true
|
|
||||||
|
|
||||||
override fun popularMangaRequest(page: Int) = GET("$baseUrl/lista-manga-hentai?orderby=views&page=$page", headers)
|
|
||||||
|
|
||||||
override fun popularMangaSelector() = "div.page-content-listing > div.page-listing-item"
|
|
||||||
|
|
||||||
override fun popularMangaFromElement(element: Element) = SManga.create().apply {
|
|
||||||
element.select("div.page-item-detail").let {
|
|
||||||
it.select("div.item-summary > div.post-title > h5 > a").let {
|
|
||||||
setUrlWithoutDomain(it.attr("href"))
|
|
||||||
title = it.text()
|
|
||||||
}
|
|
||||||
thumbnail_url = it.select("div.item-thumb > a > img").attr("data-src")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun popularMangaNextPageSelector() = "a[rel=next]"
|
|
||||||
|
|
||||||
override fun latestUpdatesRequest(page: Int)= GET("$baseUrl/lista-manga-hentai?orderby=last&page=$page", headers)
|
|
||||||
|
|
||||||
override fun latestUpdatesSelector() = popularMangaSelector()
|
|
||||||
|
|
||||||
override fun latestUpdatesFromElement(element: Element) = popularMangaFromElement(element)
|
|
||||||
|
|
||||||
override fun latestUpdatesNextPageSelector() = popularMangaNextPageSelector()
|
|
||||||
|
|
||||||
override fun mangaDetailsParse(document: Document) = SManga.create().apply {
|
|
||||||
document.select("div.tab-summary").let {
|
|
||||||
thumbnail_url = it.select("div.summary_image > img").attr("data-src")
|
|
||||||
|
|
||||||
it.select("div.summary_content_wrap > div.summary_content").let {
|
|
||||||
author = document.select("div.author-content > a").text()
|
|
||||||
artist = document.select("div.artist-content > a").text()
|
|
||||||
genre = document.select("div.genres-content > a").joinToString(", ") {
|
|
||||||
it.text()
|
|
||||||
}
|
|
||||||
it.select("div.post-status").let {
|
|
||||||
status = parseStatus(it.select("span.label").text().orEmpty())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
description = document.select("div.description-summary").text().orEmpty()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun parseStatus(status: String) = when {
|
|
||||||
status.contains("Ongoing") -> SManga.ONGOING
|
|
||||||
status.contains("Complete") -> SManga.COMPLETED
|
|
||||||
else -> SManga.UNKNOWN
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun chapterListSelector() = "ul.main.version-chap > li.wp-manga-chapter:not(:last-child)" // removing empty li
|
|
||||||
|
|
||||||
override fun chapterFromElement(element: Element) = SChapter.create().apply {
|
|
||||||
name = element.select("a").text()
|
|
||||||
setUrlWithoutDomain(element.select("a").attr("href"))
|
|
||||||
scanlator = element.select("span.chapter-release-date > a").text()
|
|
||||||
date_upload = parseChapterDate(element.select("span.chapter-release-date > i").text())
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun parseChapterDate(date: String): Long {
|
|
||||||
val dateWords = date.split(" ")
|
|
||||||
|
|
||||||
if (dateWords.size == 3) {
|
|
||||||
return try {
|
|
||||||
SimpleDateFormat("d MMM. yyyy", Locale.ENGLISH).parse(date).time
|
|
||||||
} catch (e: ParseException) {
|
|
||||||
0L
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0L
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun pageListRequest(chapter: SChapter) = GET(baseUrl + chapter.url, headers)
|
|
||||||
|
|
||||||
override fun pageListParse(document: Document): List<Page> = mutableListOf<Page>().apply {
|
|
||||||
document.select("div#all > img.img-responsive")?.forEach {
|
|
||||||
add(Page(size, "", it.attr("data-src")))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun imageUrlParse(document: Document) = throw UnsupportedOperationException("Not used")
|
|
||||||
|
|
||||||
override fun searchMangaRequest(page: Int, query: String, filters: FilterList) = GET("$baseUrl/search?query=$query", headers)
|
|
||||||
|
|
||||||
override fun searchMangaSelector() = ".c-tabs-item__content .c-tabs-item__content"
|
|
||||||
|
|
||||||
override fun searchMangaFromElement(element: Element) = SManga.create().apply {
|
|
||||||
thumbnail_url = element.select("div.tab-thumb.c-image-hover > a > img").attr("data-src")
|
|
||||||
setUrlWithoutDomain(element.select("div.tab-thumb.c-image-hover > a").attr("href"))
|
|
||||||
title = element.select("div.tab-thumb.c-image-hover > a").attr("title")
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun searchMangaNextPageSelector() = "#not_actually_used"
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,12 +0,0 @@
|
||||||
apply plugin: 'com.android.application'
|
|
||||||
apply plugin: 'kotlin-android'
|
|
||||||
|
|
||||||
ext {
|
|
||||||
appName = 'Tachiyomi: Komikgo'
|
|
||||||
pkgNameSuffix = 'id.komikgo'
|
|
||||||
extClass = '.Komikgo'
|
|
||||||
extVersionCode = 2
|
|
||||||
libVersion = '1.2'
|
|
||||||
}
|
|
||||||
|
|
||||||
apply from: "$rootDir/common.gradle"
|
|
Before Width: | Height: | Size: 8.8 KiB |
Before Width: | Height: | Size: 4.4 KiB |
Before Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 52 KiB |
Before Width: | Height: | Size: 216 KiB |
|
@ -1,292 +0,0 @@
|
||||||
package eu.kanade.tachiyomi.extension.id.komikgo
|
|
||||||
|
|
||||||
import eu.kanade.tachiyomi.network.GET
|
|
||||||
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.Headers
|
|
||||||
import okhttp3.HttpUrl
|
|
||||||
import okhttp3.OkHttpClient
|
|
||||||
import okhttp3.Request
|
|
||||||
import org.jsoup.nodes.Document
|
|
||||||
import org.jsoup.nodes.Element
|
|
||||||
import java.text.ParseException
|
|
||||||
import java.text.SimpleDateFormat
|
|
||||||
import java.util.Locale
|
|
||||||
|
|
||||||
|
|
||||||
class Komikgo : ParsedHttpSource() {
|
|
||||||
|
|
||||||
override val name = "Komikgo"
|
|
||||||
override val baseUrl = "https://komikgo.com"
|
|
||||||
override val lang = "id"
|
|
||||||
override val supportsLatest = true
|
|
||||||
override val client: OkHttpClient = network.cloudflareClient
|
|
||||||
|
|
||||||
override fun popularMangaRequest(page: Int): Request {
|
|
||||||
return GET("$baseUrl/page/$page?s&post_type=wp-manga&m_orderby=views", headers)
|
|
||||||
}
|
|
||||||
override fun latestUpdatesRequest(page: Int): Request {
|
|
||||||
return GET("$baseUrl/page/$page?s&post_type=wp-manga&m_orderby=latest", headers)
|
|
||||||
}
|
|
||||||
// LIST SELECTOR
|
|
||||||
override fun popularMangaSelector() = "div.c-tabs-item__content"
|
|
||||||
override fun latestUpdatesSelector() = popularMangaSelector()
|
|
||||||
override fun searchMangaSelector() = popularMangaSelector()
|
|
||||||
|
|
||||||
// ELEMENT
|
|
||||||
override fun popularMangaFromElement(element: Element): SManga = searchMangaFromElement(element)
|
|
||||||
override fun latestUpdatesFromElement(element: Element): SManga = searchMangaFromElement(element)
|
|
||||||
|
|
||||||
// NEXT SELECTOR
|
|
||||||
override fun popularMangaNextPageSelector() = "#navigation-ajax"
|
|
||||||
override fun latestUpdatesNextPageSelector() = popularMangaNextPageSelector()
|
|
||||||
override fun searchMangaNextPageSelector() = popularMangaNextPageSelector()
|
|
||||||
|
|
||||||
override fun searchMangaFromElement(element: Element):SManga {
|
|
||||||
val manga = SManga.create()
|
|
||||||
manga.thumbnail_url = element.select("div.tab-thumb > a > img").attr("src")
|
|
||||||
element.select("div.tab-thumb > a").first().let {
|
|
||||||
manga.setUrlWithoutDomain(it.attr("href"))
|
|
||||||
manga.title = it.attr("title")
|
|
||||||
}
|
|
||||||
return manga
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
|
|
||||||
val url = HttpUrl.parse("$baseUrl/page/$page")!!.newBuilder()
|
|
||||||
url.addQueryParameter("post_type","wp-manga")
|
|
||||||
val pattern = "\\s+".toRegex()
|
|
||||||
val q = query.replace(pattern, "+")
|
|
||||||
if(query.length > 0){
|
|
||||||
url.addQueryParameter("s", q)
|
|
||||||
}else{
|
|
||||||
url.addQueryParameter("s", "")
|
|
||||||
}
|
|
||||||
|
|
||||||
var orderBy = ""
|
|
||||||
|
|
||||||
(if (filters.isEmpty()) getFilterList() else filters).forEach { filter ->
|
|
||||||
when (filter) {
|
|
||||||
// is Status -> url.addQueryParameter("manga_status", arrayOf("", "completed", "ongoing")[filter.state])
|
|
||||||
is GenreList -> {
|
|
||||||
val genreInclude = mutableListOf<String>()
|
|
||||||
filter.state.forEach {
|
|
||||||
if (it.state == 1) {
|
|
||||||
genreInclude.add(it.id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(genreInclude.isNotEmpty()){
|
|
||||||
genreInclude.forEach{ genre ->
|
|
||||||
url.addQueryParameter("genre[]", genre)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
is StatusList ->{
|
|
||||||
val statuses = mutableListOf<String>()
|
|
||||||
filter.state.forEach {
|
|
||||||
if (it.state == 1) {
|
|
||||||
statuses.add(it.id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(statuses.isNotEmpty()){
|
|
||||||
statuses.forEach{ status ->
|
|
||||||
url.addQueryParameter("status[]", status)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
is SortBy -> {
|
|
||||||
orderBy = filter.toUriPart();
|
|
||||||
url.addQueryParameter("m_orderby",orderBy)
|
|
||||||
}
|
|
||||||
is TextField -> url.addQueryParameter(filter.key, filter.state)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return GET(url.toString(), headers)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// max 200 results
|
|
||||||
|
|
||||||
override fun mangaDetailsParse(document: Document): SManga {
|
|
||||||
val infoElement = document.select("div.site-content").first()
|
|
||||||
|
|
||||||
val manga = SManga.create()
|
|
||||||
manga.author = infoElement.select("div.author-content")?.text()
|
|
||||||
manga.artist = infoElement.select("div.artist-content")?.text()
|
|
||||||
|
|
||||||
val genres = mutableListOf<String>()
|
|
||||||
infoElement.select("div.genres-content a").forEach { element ->
|
|
||||||
val genre = element.text()
|
|
||||||
genres.add(genre)
|
|
||||||
}
|
|
||||||
manga.genre =genres.joinToString(", ")
|
|
||||||
manga.status = parseStatus(infoElement.select("div.post-status > div:nth-child(2) div").text())
|
|
||||||
|
|
||||||
manga.description = document.select("div.description-summary")?.text()
|
|
||||||
manga.thumbnail_url = document.select("div.summary_image > a > img").attr("src")
|
|
||||||
|
|
||||||
return manga
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun parseStatus(element: String): Int = when {
|
|
||||||
|
|
||||||
element.toLowerCase().contains("ongoing") -> SManga.ONGOING
|
|
||||||
element.toLowerCase().contains("completed") -> SManga.COMPLETED
|
|
||||||
else -> SManga.UNKNOWN
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun chapterListSelector() = "li.wp-manga-chapter"
|
|
||||||
|
|
||||||
override fun chapterFromElement(element: Element): SChapter {
|
|
||||||
val urlElement = element.select("a").first()
|
|
||||||
val chapter = SChapter.create()
|
|
||||||
chapter.setUrlWithoutDomain(urlElement.attr("href"))
|
|
||||||
chapter.name = urlElement.text()
|
|
||||||
chapter.date_upload = element.select("span.chapter-release-date i").last()?.text()?.let {
|
|
||||||
try {
|
|
||||||
SimpleDateFormat("MMMM dd, yyyy", Locale.US).parse(it).time
|
|
||||||
} catch (e: ParseException) {
|
|
||||||
SimpleDateFormat("MMM dd, yyyy", Locale.US).parse(it).time
|
|
||||||
}
|
|
||||||
|
|
||||||
} ?: 0
|
|
||||||
return chapter
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun prepareNewChapter(chapter: SChapter, manga: SManga) {
|
|
||||||
val basic = Regex("""Chapter\s([0-9]+)""")
|
|
||||||
when {
|
|
||||||
basic.containsMatchIn(chapter.name) -> {
|
|
||||||
basic.find(chapter.name)?.let {
|
|
||||||
chapter.chapter_number = it.groups[1]?.value!!.toFloat()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun pageListParse(document: Document): List<Page> {
|
|
||||||
val pages = mutableListOf<Page>()
|
|
||||||
var i = 0
|
|
||||||
document.select("div.reading-content * img").forEach { element ->
|
|
||||||
val url = element.attr("src")
|
|
||||||
i++
|
|
||||||
if(url.length != 0){
|
|
||||||
pages.add(Page(i, "", url))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return pages
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun imageUrlParse(document: Document) = ""
|
|
||||||
|
|
||||||
override fun imageRequest(page: Page): Request {
|
|
||||||
val imgHeader = Headers.Builder().apply {
|
|
||||||
add("User-Agent", "Mozilla/5.0 (Linux; U; Android 4.1.1; en-gb; Build/KLP) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30")
|
|
||||||
add("Referer", baseUrl)
|
|
||||||
}.build()
|
|
||||||
return GET(page.imageUrl!!, imgHeader)
|
|
||||||
}
|
|
||||||
// private class Status : Filter.TriState("Completed")
|
|
||||||
private class TextField(name: String, val key: String) : Filter.Text(name)
|
|
||||||
private class SortBy : UriPartFilter("Sort by", arrayOf(
|
|
||||||
Pair("Relevance", ""),
|
|
||||||
Pair("Latest", "latest"),
|
|
||||||
Pair("A-Z", "alphabet"),
|
|
||||||
Pair("Rating", "rating"),
|
|
||||||
Pair("Trending", "trending"),
|
|
||||||
Pair("Most View", "views"),
|
|
||||||
Pair("New", "new-manga")
|
|
||||||
))
|
|
||||||
private class Genre(name: String, val id: String = name) : Filter.TriState(name)
|
|
||||||
private class GenreList(genres: List<Genre>) : Filter.Group<Genre>("Genres", genres)
|
|
||||||
private class Status(name: String, val id: String = name) : Filter.TriState(name)
|
|
||||||
private class StatusList(statuses: List<Status>) : Filter.Group<Status>("Status", statuses)
|
|
||||||
|
|
||||||
override fun getFilterList() = FilterList(
|
|
||||||
// TextField("Judul", "title"),
|
|
||||||
TextField("Author", "author"),
|
|
||||||
TextField("Year", "release"),
|
|
||||||
SortBy(),
|
|
||||||
StatusList(getStatusList()),
|
|
||||||
GenreList(getGenreList())
|
|
||||||
)
|
|
||||||
private fun getStatusList() = listOf(
|
|
||||||
Status("Completed","end"),
|
|
||||||
Status("Ongoing","on-going"),
|
|
||||||
Status("Canceled","canceled"),
|
|
||||||
Status("Onhold","on-hold")
|
|
||||||
)
|
|
||||||
private fun getGenreList() = listOf(
|
|
||||||
Genre("Adventure", "Adventure"),
|
|
||||||
Genre( "Action", "action"),
|
|
||||||
Genre( "Adventure", "adventure"),
|
|
||||||
Genre( "Cars", "cars"),
|
|
||||||
Genre( "4-Koma", "4-koma"),
|
|
||||||
Genre( "Comedy", "comedy"),
|
|
||||||
Genre( "Completed", "completed"),
|
|
||||||
Genre( "Cooking", "cooking"),
|
|
||||||
Genre( "Dementia", "dementia"),
|
|
||||||
Genre( "Demons", "demons"),
|
|
||||||
Genre( "Doujinshi", "doujinshi"),
|
|
||||||
Genre( "Drama", "drama"),
|
|
||||||
Genre( "Ecchi", "ecchi"),
|
|
||||||
Genre( "Fantasy", "fantasy"),
|
|
||||||
Genre( "Game", "game"),
|
|
||||||
Genre( "Gender Bender", "gender-bender"),
|
|
||||||
Genre( "Harem", "harem"),
|
|
||||||
Genre( "Historical", "historical"),
|
|
||||||
Genre( "Horror", "horror"),
|
|
||||||
Genre( "Isekai", "isekai"),
|
|
||||||
Genre( "Josei", "josei"),
|
|
||||||
Genre( "Kids", "kids"),
|
|
||||||
Genre( "Magic", "magic"),
|
|
||||||
Genre( "Manga", "manga"),
|
|
||||||
Genre( "Manhua", "manhua"),
|
|
||||||
Genre( "Manhwa", "manhwa"),
|
|
||||||
Genre( "Martial Arts", "martial-arts"),
|
|
||||||
Genre( "Mature", "mature"),
|
|
||||||
Genre( "Mecha", "mecha"),
|
|
||||||
Genre( "Military", "military"),
|
|
||||||
Genre( "Music", "music"),
|
|
||||||
Genre( "Mystery", "mystery"),
|
|
||||||
Genre( "Old Comic", "old-comic"),
|
|
||||||
Genre( "One Shot", "one-shot"),
|
|
||||||
Genre( "Oneshot", "oneshot"),
|
|
||||||
Genre( "Parodi", "parodi"),
|
|
||||||
Genre( "Parody", "parody"),
|
|
||||||
Genre( "Police", "police"),
|
|
||||||
Genre( "Psychological", "psychological"),
|
|
||||||
Genre( "Romance", "romance"),
|
|
||||||
Genre( "Samurai", "samurai"),
|
|
||||||
Genre( "School", "school"),
|
|
||||||
Genre( "School Life", "school-life"),
|
|
||||||
Genre( "Sci-Fi", "sci-fi"),
|
|
||||||
Genre( "Seinen", "seinen"),
|
|
||||||
Genre( "Shoujo", "shoujo"),
|
|
||||||
Genre( "Shoujo Ai", "shoujo-ai"),
|
|
||||||
Genre( "Shounen", "shounen"),
|
|
||||||
Genre( "Shounen ai", "shounen-ai"),
|
|
||||||
Genre( "Slice of Life", "slice-of-life"),
|
|
||||||
Genre( "Sports", "sports"),
|
|
||||||
Genre( "Super Power", "super-power"),
|
|
||||||
Genre( "Supernatural", "supernatural"),
|
|
||||||
Genre( "Thriller", "thriller"),
|
|
||||||
Genre( "Tragedy", "tragedy"),
|
|
||||||
Genre( "Vampire", "vampire"),
|
|
||||||
Genre( "Webtoons", "webtoons"),
|
|
||||||
Genre( "Yaoi", "yaoi"),
|
|
||||||
Genre( "Yuri", "yuri")
|
|
||||||
)
|
|
||||||
private open class UriPartFilter(displayName: String, val vals: Array<Pair<String, String>>) :
|
|
||||||
Filter.Select<String>(displayName, vals.map { it.first }.toTypedArray()) {
|
|
||||||
fun toUriPart() = vals[state].second
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|