Manhua Plus - new extension (#2593)

* Manhua Plus - new extension

* Icons

* Time Zone

* Factory

* Icons, mangasum
This commit is contained in:
Mike 2020-04-09 06:15:21 -04:00 committed by GitHub
parent 9330b6662d
commit e04a2746a5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 223 additions and 0 deletions

View File

@ -0,0 +1,12 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
ext {
appName = 'Tachiyomi: WP-Comics'
pkgNameSuffix = 'all.wpcomics'
extClass = '.WPComicsFactory'
extVersionCode = 1
libVersion = '1.2'
}
apply from: "$rootDir/common.gradle"

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

View File

@ -0,0 +1,156 @@
package eu.kanade.tachiyomi.extension.all.wpcomics
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.source.model.*
import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import okhttp3.OkHttpClient
import okhttp3.Request
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import java.text.SimpleDateFormat
import java.util.Locale
import java.util.Calendar
abstract class WPComics(
override val name: String,
override val baseUrl: String,
override val lang: String,
private val dateFormat: SimpleDateFormat = SimpleDateFormat("HH:mm - dd/MM/yyyy Z", Locale.US),
private val gmtOffset: String? = "+0500"
) : ParsedHttpSource() {
override val supportsLatest = true
override val client: OkHttpClient = network.cloudflareClient
// Popular
open val popularPath = "hot"
override fun popularMangaRequest(page: Int): Request {
return GET("$baseUrl/$popularPath" + if (page > 1) "?page=$page" else "", headers)
}
override fun popularMangaSelector() = "div.items div.item"
override fun popularMangaFromElement(element: Element): SManga {
return SManga.create().apply {
element.select("h3 a").let {
title = it.text()
setUrlWithoutDomain(it.attr("abs:href"))
}
thumbnail_url = imageOrNull(element.select("div.image:first-of-type img").first())
}
}
override fun popularMangaNextPageSelector() = "a.next-page"
// Latest
override fun latestUpdatesRequest(page: Int): Request {
return GET(baseUrl + if (page > 1) "?page=$page" else "", 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 {
return GET("$baseUrl/?s=$query&post_type=comics&page=$page")
}
override fun searchMangaSelector() = "div.items div.item div.image a"
override fun searchMangaFromElement(element: Element): SManga {
return SManga.create().apply {
title = element.attr("title")
setUrlWithoutDomain(element.attr("href"))
thumbnail_url = imageOrNull(element.select("img").first())
}
}
override fun searchMangaNextPageSelector() = popularMangaNextPageSelector()
// Details
override fun mangaDetailsParse(document: Document): SManga {
return SManga.create().apply {
document.select("article#item-detail").let { info ->
author = info.select("li.author p.col-xs-8").text()
status = info.select("li.status p.col-xs-8").text().toStatus()
genre = info.select("li.kind p.col-xs-8 a").joinToString { it.text() }
description = info.select("div.detail-content p").text()
thumbnail_url = imageOrNull(info.select("div.col-image img").first())
}
}
}
private fun String?.toStatus() = when {
this == null -> SManga.UNKNOWN
this.contains("Updating", ignoreCase = true) -> SManga.ONGOING
this.contains("Complete", ignoreCase = true) -> SManga.COMPLETED
else -> SManga.UNKNOWN
}
// Chapters
override fun chapterListSelector() = "div.list-chapter li.row:not(.heading)"
override fun chapterFromElement(element: Element): SChapter {
return SChapter.create().apply {
element.select("a").let {
name = it.text()
setUrlWithoutDomain(it.attr("href"))
}
date_upload = element.select("div.col-xs-4").text().toDate()
}
}
private fun String?.toDate(): Long {
return try {
if (this?.contains("ago", ignoreCase = true) == true) {
val trimmedDate = this.substringBefore(" ago").removeSuffix("s").split(" ")
val calendar = Calendar.getInstance()
when (trimmedDate[1]) {
"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, -trimmedDate[0].toInt()) }
}
calendar.timeInMillis
} else {
dateFormat.parse(if (gmtOffset == null) this?.substringAfterLast(" ") else "$this $gmtOffset").time
}
} catch (_: Exception) {
0L
}
}
// Pages
// sources sometimes have an image element with an empty attr that isn't really an image
private fun imageOrNull(element: Element): String? {
return when {
element.attr("data-original").contains(Regex("""\.(jpg|png)""", RegexOption.IGNORE_CASE)) -> element.attr("abs:data-original")
element.attr("data-src").contains(Regex("""\.(jpg|png)""", RegexOption.IGNORE_CASE)) -> element.attr("abs:data-src")
element.attr("src").contains(Regex("""\.(jpg|png)""", RegexOption.IGNORE_CASE)) -> element.attr("abs:src")
else -> null
}
}
open val pageListSelector = "div.page-chapter > img, li.blocks-gallery-item img"
override fun pageListParse(document: Document): List<Page> {
return document.select(pageListSelector).mapNotNull { img -> imageOrNull(img) }
.mapIndexed { i, image -> Page(i, "", image)}
}
override fun imageUrlParse(document: Document): String = throw UnsupportedOperationException("Not used")
}

View File

@ -0,0 +1,55 @@
package eu.kanade.tachiyomi.extension.all.wpcomics
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.source.Source
import eu.kanade.tachiyomi.source.SourceFactory
import eu.kanade.tachiyomi.source.model.FilterList
import eu.kanade.tachiyomi.source.model.SManga
import okhttp3.Request
import org.jsoup.nodes.Element
import java.text.SimpleDateFormat
import java.util.Locale
class WPComicsFactory : SourceFactory {
override fun createSources(): List<Source> = listOf(
ManhuaPlus(),
ManhuaES(),
MangaSum()
)
}
private class ManhuaPlus : WPComics("Manhua Plus", "https://manhuaplus.com", "en")
private class ManhuaES : WPComics("Manhua ES", "https://manhuaes.com", "en", SimpleDateFormat("HH:mm - dd/MM/yyyy Z", Locale.US), "+0700") {
override val popularPath = "category-comics/manga"
override fun popularMangaFromElement(element: Element): SManga {
return SManga.create().apply {
element.select("div.image a").let {
title = it.attr("title")
setUrlWithoutDomain(it.attr("href"))
}
thumbnail_url = element.select("div.image img").attr("abs:src")
}
}
override fun latestUpdatesFromElement(element: Element): SManga {
return SManga.create().apply {
element.select("a.head").let {
title = it.text()
setUrlWithoutDomain(it.attr("href"))
}
thumbnail_url = element.select("img").attr("abs:src")
}
}
override val pageListSelector = "div.chapter-detail img"
}
private class MangaSum : WPComics("MangaSum", "https://mangasum.com", "en", SimpleDateFormat("MM/dd/yy", Locale.US), null) {
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request = GET("$baseUrl/genres?keyword=$query&page=$page", headers)
/**
* TODO - chapter dates come in 3 flavors: relative dates less than a month, time + month/day (current year is implied),
* and MM/dd/yy; see about getting all 3 working (currently at 2/3)
*/
}