Webtoons split (#6444)
* Create Webtoons.kt * Added Webtoons Generator and translate * Updated Vesion numbers * Update WebtoonsTranslateGenerator.kt * Added Icons and ovverides * Removed non split files * Update WebtoonsGenerator.kt * Added id overrides for a few languages * Added ID Override for Indonesian * Fixed backwards compability * Fix backward compability
Before Width: | Height: | Size: 4.8 KiB After Width: | Height: | Size: 4.8 KiB |
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.6 KiB |
Before Width: | Height: | Size: 6.5 KiB After Width: | Height: | Size: 6.5 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 60 KiB After Width: | Height: | Size: 60 KiB |
After Width: | Height: | Size: 2.6 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 3.3 KiB |
After Width: | Height: | Size: 5.5 KiB |
After Width: | Height: | Size: 8.3 KiB |
After Width: | Height: | Size: 41 KiB |
|
@ -1,6 +1,7 @@
|
||||||
package eu.kanade.tachiyomi.extension.all.webtoons
|
package eu.kanade.tachiyomi.extension.zh.dongmanmanhua
|
||||||
|
|
||||||
import eu.kanade.tachiyomi.network.GET
|
import eu.kanade.tachiyomi.network.GET
|
||||||
|
import eu.kanade.tachiyomi.multisrc.webtoons.Webtoons
|
||||||
import eu.kanade.tachiyomi.source.model.FilterList
|
import eu.kanade.tachiyomi.source.model.FilterList
|
||||||
import eu.kanade.tachiyomi.source.model.SChapter
|
import eu.kanade.tachiyomi.source.model.SChapter
|
||||||
import eu.kanade.tachiyomi.source.model.SManga
|
import eu.kanade.tachiyomi.source.model.SManga
|
||||||
|
@ -13,10 +14,7 @@ import org.jsoup.nodes.Element
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
|
|
||||||
class DongmanManhua : WebtoonsDefault("zh", "", dateFormat = SimpleDateFormat("yyyy-M-d", Locale.ENGLISH)) {
|
class DongmanManhua : Webtoons("Dongman Manhua", "https://www.dongmanmanhua.cn", "zh", "", dateFormat = SimpleDateFormat("yyyy-M-d", Locale.ENGLISH)) {
|
||||||
override val baseUrl = "https://www.dongmanmanhua.cn"
|
|
||||||
|
|
||||||
override val name = "Dongman Manhua"
|
|
||||||
|
|
||||||
override fun headersBuilder(): Headers.Builder = super.headersBuilder()
|
override fun headersBuilder(): Headers.Builder = super.headersBuilder()
|
||||||
.removeAll("Referer")
|
.removeAll("Referer")
|
|
@ -0,0 +1,56 @@
|
||||||
|
package eu.kanade.tachiyomi.extension.all.webtoons
|
||||||
|
|
||||||
|
import eu.kanade.tachiyomi.multisrc.webtoons.Webtoons
|
||||||
|
import eu.kanade.tachiyomi.source.Source
|
||||||
|
import eu.kanade.tachiyomi.source.SourceFactory
|
||||||
|
import java.text.SimpleDateFormat
|
||||||
|
import java.util.GregorianCalendar
|
||||||
|
import java.util.Locale
|
||||||
|
import java.util.Calendar
|
||||||
|
|
||||||
|
class WebtoonsFactory : SourceFactory {
|
||||||
|
override fun createSources(): List<Source> = listOf(
|
||||||
|
WebtoonsEN(),
|
||||||
|
WebtoonsID(),
|
||||||
|
WebtoonsTH(),
|
||||||
|
WebtoonsES(),
|
||||||
|
WebtoonsFR(),
|
||||||
|
WebtoonsZH(),
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
||||||
|
class WebtoonsEN : Webtoons("Webtoons", "https://www.webtoons.com", "en")
|
||||||
|
class WebtoonsID : Webtoons("Webtoons", "https://www.webtoons.com", "id") {
|
||||||
|
// Override ID as part of the name was removed to be more consiten with other enteries
|
||||||
|
override val id: Long = 8749627068478740298
|
||||||
|
|
||||||
|
// Android seems to be unable to parse Indonesian dates; we'll use a short hard-coded table
|
||||||
|
// instead.
|
||||||
|
private val dateMap: Array<String> = arrayOf(
|
||||||
|
"Jan", "Feb", "Mar", "Apr", "Mei", "Jun", "Jul", "Agu", "Sep", "Okt", "Nov", "Des"
|
||||||
|
)
|
||||||
|
|
||||||
|
override fun chapterParseDate(date: String): Long {
|
||||||
|
val expr = Regex("""(\d{4}) ([A-Z][a-z]{2}) (\d+)""").find(date) ?: return 0
|
||||||
|
val (_, year, monthString, day) = expr.groupValues
|
||||||
|
val monthIndex = dateMap.indexOf(monthString)
|
||||||
|
return GregorianCalendar(year.toInt(), monthIndex, day.toInt()).time.time
|
||||||
|
}
|
||||||
|
}
|
||||||
|
class WebtoonsTH : Webtoons("Webtoons", "https://www.webtoons.com", "th", dateFormat = SimpleDateFormat("d MMM yyyy", Locale("th")))
|
||||||
|
class WebtoonsES : Webtoons("Webtoons", "https://www.webtoons.com", "es") {
|
||||||
|
// Android seems to be unable to parse es dates like Indonesian; we'll use a short hard-coded table
|
||||||
|
// instead.
|
||||||
|
private val dateMap: Array<String> = arrayOf(
|
||||||
|
"Ene", "Feb", "Mar", "Abr", "May", "Jun", "Jul", "Ago", "Sep", "Oct", "Nov", "Dic"
|
||||||
|
)
|
||||||
|
|
||||||
|
override fun chapterParseDate(date: String): Long {
|
||||||
|
val expr = Regex("""(\d+)-([a-z]{3})-(\d{4})""").find(date) ?: return 0
|
||||||
|
val (_, day, monthString, year) = expr.groupValues
|
||||||
|
val monthIndex = dateMap.indexOf(monthString)
|
||||||
|
return GregorianCalendar(year.toInt(), monthIndex, day.toInt()).time.time
|
||||||
|
}
|
||||||
|
}
|
||||||
|
class WebtoonsFR : Webtoons("Webtoons", "https://www.webtoons.com", "fr", dateFormat = SimpleDateFormat("d MMM yyyy", Locale.FRENCH))
|
||||||
|
class WebtoonsZH : Webtoons("Webtoons", "https://www.webtoons.com", "zh", "zh-hant", "zh_TW", SimpleDateFormat("yyyy/MM/dd", Locale.TRADITIONAL_CHINESE))
|
|
@ -0,0 +1,85 @@
|
||||||
|
package eu.kanade.tachiyomi.extension.all.webtoonstranslate
|
||||||
|
|
||||||
|
import eu.kanade.tachiyomi.multisrc.webtoons.WebtoonsTranslate
|
||||||
|
import eu.kanade.tachiyomi.source.Source
|
||||||
|
import eu.kanade.tachiyomi.source.SourceFactory
|
||||||
|
|
||||||
|
class WebtoonsTranslateFactory : SourceFactory {
|
||||||
|
override fun createSources(): List<Source> = listOf(
|
||||||
|
WebtoonsTranslateEN(),
|
||||||
|
WebtoonsTranslateZH_CMN(),
|
||||||
|
WebtoonsTranslateZH_CMY(),
|
||||||
|
WebtoonsTranslateTH(),
|
||||||
|
WebtoonsTranslateID(),
|
||||||
|
WebtoonsTranslateFR(),
|
||||||
|
WebtoonsTranslateVI(),
|
||||||
|
WebtoonsTranslateRU(),
|
||||||
|
WebtoonsTranslateAR(),
|
||||||
|
WebtoonsTranslateFIL(),
|
||||||
|
WebtoonsTranslateDE(),
|
||||||
|
WebtoonsTranslateHI(),
|
||||||
|
WebtoonsTranslateIT(),
|
||||||
|
WebtoonsTranslateJA(),
|
||||||
|
WebtoonsTranslatePT_POR(),
|
||||||
|
WebtoonsTranslateTR(),
|
||||||
|
WebtoonsTranslateMS(),
|
||||||
|
WebtoonsTranslatePL(),
|
||||||
|
WebtoonsTranslatePT_POT(),
|
||||||
|
WebtoonsTranslateBG(),
|
||||||
|
WebtoonsTranslateDA(),
|
||||||
|
WebtoonsTranslateNL(),
|
||||||
|
WebtoonsTranslateRO(),
|
||||||
|
WebtoonsTranslateMN(),
|
||||||
|
WebtoonsTranslateEL(),
|
||||||
|
WebtoonsTranslateLT(),
|
||||||
|
WebtoonsTranslateCS(),
|
||||||
|
WebtoonsTranslateSV(),
|
||||||
|
WebtoonsTranslateBN(),
|
||||||
|
WebtoonsTranslateFA(),
|
||||||
|
WebtoonsTranslateUK(),
|
||||||
|
WebtoonsTranslateES(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
class WebtoonsTranslateEN : WebtoonsTranslate("Webtoons.com Translations", "https://translate.webtoons.com", "en", "ENG")
|
||||||
|
class WebtoonsTranslateZH_CMN : WebtoonsTranslate("Webtoons.com Translations", "https://translate.webtoons.com", "zh-hans", "CMN"){
|
||||||
|
override val id: Long = 5196522547754842244
|
||||||
|
}
|
||||||
|
class WebtoonsTranslateZH_CMY : WebtoonsTranslate("Webtoons.com Translations", "https://translate.webtoons.com", "zh-hant", "CMT"){
|
||||||
|
override val id: Long = 1016181401146312893
|
||||||
|
}
|
||||||
|
class WebtoonsTranslateTH : WebtoonsTranslate("Webtoons.com Translations", "https://translate.webtoons.com", "th", "THA")
|
||||||
|
class WebtoonsTranslateID : WebtoonsTranslate("Webtoons.com Translations", "https://translate.webtoons.com", "id", "IND")
|
||||||
|
class WebtoonsTranslateFR : WebtoonsTranslate("Webtoons.com Translations", "https://translate.webtoons.com", "fr", "FRA")
|
||||||
|
class WebtoonsTranslateVI : WebtoonsTranslate("Webtoons.com Translations", "https://translate.webtoons.com", "vi", "VIE")
|
||||||
|
class WebtoonsTranslateRU : WebtoonsTranslate("Webtoons.com Translations", "https://translate.webtoons.com", "ru", "RUS")
|
||||||
|
class WebtoonsTranslateAR : WebtoonsTranslate("Webtoons.com Translations", "https://translate.webtoons.com", "ar", "ARA")
|
||||||
|
class WebtoonsTranslateFIL : WebtoonsTranslate("Webtoons.com Translations", "https://translate.webtoons.com", "fil", "FIL")
|
||||||
|
class WebtoonsTranslateDE : WebtoonsTranslate("Webtoons.com Translations", "https://translate.webtoons.com", "de", "DEU")
|
||||||
|
class WebtoonsTranslateHI : WebtoonsTranslate("Webtoons.com Translations", "https://translate.webtoons.com", "hi", "HIN")
|
||||||
|
class WebtoonsTranslateIT : WebtoonsTranslate("Webtoons.com Translations", "https://translate.webtoons.com", "it", "ITA")
|
||||||
|
class WebtoonsTranslateJA : WebtoonsTranslate("Webtoons.com Translations", "https://translate.webtoons.com", "ja", "JPN")
|
||||||
|
class WebtoonsTranslatePT_POR : WebtoonsTranslate("Webtoons.com Translations", "https://translate.webtoons.com", "pt-br", "POR"){
|
||||||
|
//Changed languge code from pt to pt-br
|
||||||
|
override val id: Long = 275670196689829558
|
||||||
|
}
|
||||||
|
class WebtoonsTranslateTR : WebtoonsTranslate("Webtoons.com Translations", "https://translate.webtoons.com", "tr", "TUR")
|
||||||
|
class WebtoonsTranslateMS : WebtoonsTranslate("Webtoons.com Translations", "https://translate.webtoons.com", "ms", "MAY")
|
||||||
|
class WebtoonsTranslatePL : WebtoonsTranslate("Webtoons.com Translations", "https://translate.webtoons.com", "pl", "POL")
|
||||||
|
class WebtoonsTranslatePT_POT : WebtoonsTranslate("Webtoons.com Translations", "https://translate.webtoons.com", "pt", "POT") {
|
||||||
|
override val id: Long = 9219933036054791613
|
||||||
|
}
|
||||||
|
class WebtoonsTranslateBG : WebtoonsTranslate("Webtoons.com Translations", "https://translate.webtoons.com", "bg", "BUL")
|
||||||
|
class WebtoonsTranslateDA : WebtoonsTranslate("Webtoons.com Translations", "https://translate.webtoons.com", "da", "DAN")
|
||||||
|
class WebtoonsTranslateNL : WebtoonsTranslate("Webtoons.com Translations", "https://translate.webtoons.com", "nl", "NLD")
|
||||||
|
class WebtoonsTranslateRO : WebtoonsTranslate("Webtoons.com Translations", "https://translate.webtoons.com", "ro", "RON")
|
||||||
|
class WebtoonsTranslateMN : WebtoonsTranslate("Webtoons.com Translations", "https://translate.webtoons.com", "mn", "MON")
|
||||||
|
class WebtoonsTranslateEL : WebtoonsTranslate("Webtoons.com Translations", "https://translate.webtoons.com", "el", "GRE")
|
||||||
|
class WebtoonsTranslateLT : WebtoonsTranslate("Webtoons.com Translations", "https://translate.webtoons.com", "lt", "LIT")
|
||||||
|
class WebtoonsTranslateCS : WebtoonsTranslate("Webtoons.com Translations", "https://translate.webtoons.com", "cs", "CES")
|
||||||
|
class WebtoonsTranslateSV : WebtoonsTranslate("Webtoons.com Translations", "https://translate.webtoons.com", "sv", "SWE")
|
||||||
|
class WebtoonsTranslateBN : WebtoonsTranslate("Webtoons.com Translations", "https://translate.webtoons.com", "bn", "BEN")
|
||||||
|
class WebtoonsTranslateFA : WebtoonsTranslate("Webtoons.com Translations", "https://translate.webtoons.com", "fa", "PER")
|
||||||
|
class WebtoonsTranslateUK : WebtoonsTranslate("Webtoons.com Translations", "https://translate.webtoons.com", "uk", "UKR")
|
||||||
|
class WebtoonsTranslateES : WebtoonsTranslate("Webtoons.com Translations", "https://translate.webtoons.com", "es", "SPA")
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,10 @@
|
||||||
package eu.kanade.tachiyomi.extension.all.webtoons
|
package eu.kanade.tachiyomi.multisrc.webtoons
|
||||||
|
|
||||||
import eu.kanade.tachiyomi.network.GET
|
import eu.kanade.tachiyomi.network.GET
|
||||||
import eu.kanade.tachiyomi.source.model.Filter.Header
|
import eu.kanade.tachiyomi.source.model.Filter.Header
|
||||||
import eu.kanade.tachiyomi.source.model.Filter.Select
|
import eu.kanade.tachiyomi.source.model.Filter.Select
|
||||||
import eu.kanade.tachiyomi.source.model.Filter.Separator
|
import eu.kanade.tachiyomi.source.model.Filter.Separator
|
||||||
import eu.kanade.tachiyomi.source.model.FilterList
|
import eu.kanade.tachiyomi.source.model.FilterList
|
||||||
import eu.kanade.tachiyomi.source.model.MangasPage
|
|
||||||
import eu.kanade.tachiyomi.source.model.SManga
|
|
||||||
import eu.kanade.tachiyomi.source.online.ParsedHttpSource
|
import eu.kanade.tachiyomi.source.online.ParsedHttpSource
|
||||||
import eu.kanade.tachiyomi.util.asJsoup
|
import eu.kanade.tachiyomi.util.asJsoup
|
||||||
import okhttp3.Cookie
|
import okhttp3.Cookie
|
||||||
|
@ -16,20 +14,26 @@ import okhttp3.HttpUrl
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
import okhttp3.Request
|
import okhttp3.Request
|
||||||
import okhttp3.Response
|
import okhttp3.Response
|
||||||
|
import org.json.JSONObject
|
||||||
import org.jsoup.nodes.Document
|
import org.jsoup.nodes.Document
|
||||||
import org.jsoup.nodes.Element
|
import org.jsoup.nodes.Element
|
||||||
|
import java.text.SimpleDateFormat
|
||||||
|
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.model.MangasPage
|
||||||
|
import java.util.Locale
|
||||||
import java.util.Calendar
|
import java.util.Calendar
|
||||||
|
|
||||||
abstract class Webtoons(
|
open class Webtoons(
|
||||||
|
override val name: String,
|
||||||
|
override val baseUrl: String,
|
||||||
override val lang: String,
|
override val lang: String,
|
||||||
open val langCode: String = lang,
|
open val langCode: String = lang,
|
||||||
open val localeForCookie: String = lang
|
open val localeForCookie: String = lang,
|
||||||
|
private val dateFormat: SimpleDateFormat = SimpleDateFormat("MMM d, yyyy", Locale.ENGLISH)
|
||||||
) : ParsedHttpSource() {
|
) : ParsedHttpSource() {
|
||||||
|
|
||||||
override val name = "Webtoons.com"
|
|
||||||
|
|
||||||
override val baseUrl = "https://www.webtoons.com"
|
|
||||||
|
|
||||||
override val supportsLatest = true
|
override val supportsLatest = true
|
||||||
|
|
||||||
override val client: OkHttpClient = super.client.newBuilder()
|
override val client: OkHttpClient = super.client.newBuilder()
|
||||||
|
@ -178,6 +182,8 @@ abstract class Webtoons(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun chapterListSelector() = "ul#_episodeList li[id*=episode]"
|
||||||
|
|
||||||
private class SearchType(vals: Array<Pair<String, String>>) : UriPartFilter("Official or Challenge", vals)
|
private class SearchType(vals: Array<Pair<String, String>>) : UriPartFilter("Official or Challenge", vals)
|
||||||
|
|
||||||
private fun getOfficialList() = arrayOf(
|
private fun getOfficialList() = arrayOf(
|
||||||
|
@ -190,4 +196,48 @@ abstract class Webtoons(
|
||||||
Select<String>(displayName, vals.map { it.first }.toTypedArray()) {
|
Select<String>(displayName, vals.map { it.first }.toTypedArray()) {
|
||||||
fun toUriPart() = vals[state].second
|
fun toUriPart() = vals[state].second
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun chapterFromElement(element: Element): SChapter {
|
||||||
|
val urlElement = element.select("a")
|
||||||
|
|
||||||
|
val chapter = SChapter.create()
|
||||||
|
chapter.setUrlWithoutDomain(urlElement.attr("href"))
|
||||||
|
chapter.name = element.select("a > div.row > div.info > p.sub_title > span.ellipsis").text()
|
||||||
|
val select = element.select("a > div.row > div.num")
|
||||||
|
if (select.isNotEmpty()) {
|
||||||
|
chapter.name += " Ch. " + select.text().substringAfter("#")
|
||||||
|
}
|
||||||
|
if (element.select(".ico_bgm").isNotEmpty()) {
|
||||||
|
chapter.name += " ♫"
|
||||||
|
}
|
||||||
|
chapter.date_upload = element.select("a > div.row > div.info > p.date").text()?.let { chapterParseDate(it) } ?: 0
|
||||||
|
return chapter
|
||||||
|
}
|
||||||
|
|
||||||
|
open fun chapterParseDate(date: String): Long {
|
||||||
|
return dateFormat.parse(date)?.time ?: 0
|
||||||
|
}
|
||||||
|
override fun chapterListRequest(manga: SManga) = GET("https://m.webtoons.com" + manga.url, mobileHeaders)
|
||||||
|
|
||||||
|
override fun pageListParse(document: Document): List<Page> {
|
||||||
|
val pages = document.select("div#_imageList > img").mapIndexed { i, element -> Page(i, "", element.attr("data-url")) }
|
||||||
|
|
||||||
|
if (pages.isNotEmpty()) { return pages }
|
||||||
|
|
||||||
|
val docString = document.toString()
|
||||||
|
|
||||||
|
val docUrlRegex = Regex("documentURL:.*?'(.*?)'")
|
||||||
|
val motiontoonPathRegex = Regex("jpg:.*?'(.*?)\\{")
|
||||||
|
|
||||||
|
val docUrl = docUrlRegex.find(docString)!!.destructured.toList()[0]
|
||||||
|
val motiontoonPath = motiontoonPathRegex.find(docString)!!.destructured.toList()[0]
|
||||||
|
|
||||||
|
val motiontoonJson = JSONObject(client.newCall(GET(docUrl, headers)).execute().body()!!.string()).getJSONObject("assets").getJSONObject("image")
|
||||||
|
|
||||||
|
val keys = motiontoonJson.keys().asSequence().toList().filter { it.contains("layer") }
|
||||||
|
|
||||||
|
return keys.mapIndexed { i, key ->
|
||||||
|
Page(i, "", motiontoonPath + motiontoonJson.getString(key))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
package eu.kanade.tachiyomi.multisrc.webtoons
|
||||||
|
|
||||||
|
import generator.ThemeSourceData.SingleLang
|
||||||
|
import generator.ThemeSourceData.MultiLang
|
||||||
|
import generator.ThemeSourceGenerator
|
||||||
|
|
||||||
|
class WebtoonsGenerator : ThemeSourceGenerator {
|
||||||
|
|
||||||
|
override val themePkg = "webtoons"
|
||||||
|
|
||||||
|
override val themeClass = "Webtoons"
|
||||||
|
|
||||||
|
override val baseVersionCode: Int = 1
|
||||||
|
|
||||||
|
override val sources = listOf(
|
||||||
|
MultiLang("Webtoons.com", "https://www.webtoons.com", listOf("en", "fr", "es", "id", "th", "zh"), className = "WebtoonsFactory", pkgName = "webtoons", overrideVersionCode = 26),
|
||||||
|
SingleLang("Dongman Manhua", "https://www.dongmanmanhua.cn", "zh")
|
||||||
|
)
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
@JvmStatic
|
||||||
|
fun main(args: Array<String>) {
|
||||||
|
WebtoonsGenerator().createAll()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package eu.kanade.tachiyomi.extension.all.webtoons
|
package eu.kanade.tachiyomi.multisrc.webtoons
|
||||||
|
|
||||||
import eu.kanade.tachiyomi.network.GET
|
import eu.kanade.tachiyomi.network.GET
|
||||||
import eu.kanade.tachiyomi.network.asObservableSuccess
|
import eu.kanade.tachiyomi.network.asObservableSuccess
|
||||||
|
@ -17,7 +17,12 @@ import org.jsoup.nodes.Element
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
import java.util.ArrayList
|
import java.util.ArrayList
|
||||||
|
|
||||||
open class WebtoonsTranslate(override val lang: String, private val translateLangCode: String, languageNameExtra: String = "") : Webtoons(lang) {
|
open class WebtoonsTranslate (
|
||||||
|
override val name: String,
|
||||||
|
override val baseUrl: String,
|
||||||
|
override val lang: String,
|
||||||
|
private val translateLangCode: String
|
||||||
|
) : Webtoons(name, baseUrl, lang) {
|
||||||
// popularMangaRequest already returns manga sorted by latest update
|
// popularMangaRequest already returns manga sorted by latest update
|
||||||
override val supportsLatest = false
|
override val supportsLatest = false
|
||||||
|
|
||||||
|
@ -29,7 +34,6 @@ open class WebtoonsTranslate(override val lang: String, private val translateLan
|
||||||
|
|
||||||
private val pageSize = 24
|
private val pageSize = 24
|
||||||
|
|
||||||
override val name = "Webtoons.com Translations$languageNameExtra"
|
|
||||||
|
|
||||||
override fun headersBuilder(): Headers.Builder = super.headersBuilder()
|
override fun headersBuilder(): Headers.Builder = super.headersBuilder()
|
||||||
.removeAll("Referer")
|
.removeAll("Referer")
|
|
@ -0,0 +1,24 @@
|
||||||
|
package eu.kanade.tachiyomi.multisrc.webtoons
|
||||||
|
|
||||||
|
import generator.ThemeSourceData.SingleLang
|
||||||
|
import generator.ThemeSourceData.MultiLang
|
||||||
|
import generator.ThemeSourceGenerator
|
||||||
|
|
||||||
|
class WebtoonsTranslateGenerator : ThemeSourceGenerator {
|
||||||
|
override val themePkg = "webtoons"
|
||||||
|
|
||||||
|
override val themeClass = "WebtoonsTranslation"
|
||||||
|
|
||||||
|
override val baseVersionCode: Int = 1
|
||||||
|
|
||||||
|
override val sources = listOf(
|
||||||
|
MultiLang("Webtoons.com Translations", "https://translate.webtoons.com", listOf("en", "zh-hans", "zh-hant", "th", "id", "fr", "vi", "ru", "ar", "fil", "de", "hi", "it", "ja", "pt-br", "tr", "ms", "pl", "pt", "bg", "da", "nl", "ro", "mn", "el", "lt", "cs", "sv", "bn", "fa", "uk", "es"), className = "WebtoonsTranslateFactory", pkgName = "webtoonstranslate"),
|
||||||
|
)
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
@JvmStatic
|
||||||
|
fun main(args: Array<String>) {
|
||||||
|
WebtoonsTranslateGenerator().createAll()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,2 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<manifest package="eu.kanade.tachiyomi.extension" />
|
|
|
@ -1,12 +0,0 @@
|
||||||
apply plugin: 'com.android.application'
|
|
||||||
apply plugin: 'kotlin-android'
|
|
||||||
|
|
||||||
ext {
|
|
||||||
extName = 'Webtoons'
|
|
||||||
pkgNameSuffix = 'all.webtoons'
|
|
||||||
extClass = '.WebtoonsFactory'
|
|
||||||
extVersionCode = 26
|
|
||||||
libVersion = '1.2'
|
|
||||||
}
|
|
||||||
|
|
||||||
apply from: "$rootDir/common.gradle"
|
|
|
@ -1,66 +0,0 @@
|
||||||
package eu.kanade.tachiyomi.extension.all.webtoons
|
|
||||||
|
|
||||||
import eu.kanade.tachiyomi.network.GET
|
|
||||||
import eu.kanade.tachiyomi.source.model.Page
|
|
||||||
import eu.kanade.tachiyomi.source.model.SChapter
|
|
||||||
import eu.kanade.tachiyomi.source.model.SManga
|
|
||||||
import org.json.JSONObject
|
|
||||||
import org.jsoup.nodes.Document
|
|
||||||
import org.jsoup.nodes.Element
|
|
||||||
import java.text.SimpleDateFormat
|
|
||||||
import java.util.Locale
|
|
||||||
|
|
||||||
open class WebtoonsDefault(
|
|
||||||
override val lang: String,
|
|
||||||
override val langCode: String = lang,
|
|
||||||
override val localeForCookie: String = lang,
|
|
||||||
private val dateFormat: SimpleDateFormat = SimpleDateFormat("MMM d, yyyy", Locale.ENGLISH)
|
|
||||||
) : Webtoons(lang, langCode, lang) {
|
|
||||||
|
|
||||||
override fun chapterListSelector() = "ul#_episodeList li[id*=episode]"
|
|
||||||
|
|
||||||
override fun chapterFromElement(element: Element): SChapter {
|
|
||||||
val urlElement = element.select("a")
|
|
||||||
|
|
||||||
val chapter = SChapter.create()
|
|
||||||
chapter.setUrlWithoutDomain(urlElement.attr("href"))
|
|
||||||
chapter.name = element.select("a > div.row > div.info > p.sub_title > span.ellipsis").text()
|
|
||||||
val select = element.select("a > div.row > div.num")
|
|
||||||
if (select.isNotEmpty()) {
|
|
||||||
chapter.name += " Ch. " + select.text().substringAfter("#")
|
|
||||||
}
|
|
||||||
if (element.select(".ico_bgm").isNotEmpty()) {
|
|
||||||
chapter.name += " ♫"
|
|
||||||
}
|
|
||||||
chapter.date_upload = element.select("a > div.row > div.info > p.date").text()?.let { chapterParseDate(it) } ?: 0
|
|
||||||
return chapter
|
|
||||||
}
|
|
||||||
|
|
||||||
open fun chapterParseDate(date: String): Long {
|
|
||||||
return dateFormat.parse(date)?.time ?: 0
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun chapterListRequest(manga: SManga) = GET("https://m.webtoons.com" + manga.url, mobileHeaders)
|
|
||||||
|
|
||||||
override fun pageListParse(document: Document): List<Page> {
|
|
||||||
val pages = document.select("div#_imageList > img").mapIndexed { i, element -> Page(i, "", element.attr("data-url")) }
|
|
||||||
|
|
||||||
if (pages.isNotEmpty()) { return pages }
|
|
||||||
|
|
||||||
val docString = document.toString()
|
|
||||||
|
|
||||||
val docUrlRegex = Regex("documentURL:.*?'(.*?)'")
|
|
||||||
val motiontoonPathRegex = Regex("jpg:.*?'(.*?)\\{")
|
|
||||||
|
|
||||||
val docUrl = docUrlRegex.find(docString)!!.destructured.toList()[0]
|
|
||||||
val motiontoonPath = motiontoonPathRegex.find(docString)!!.destructured.toList()[0]
|
|
||||||
|
|
||||||
val motiontoonJson = JSONObject(client.newCall(GET(docUrl, headers)).execute().body()!!.string()).getJSONObject("assets").getJSONObject("image")
|
|
||||||
|
|
||||||
val keys = motiontoonJson.keys().asSequence().toList().filter { it.contains("layer") }
|
|
||||||
|
|
||||||
return keys.mapIndexed { i, key ->
|
|
||||||
Page(i, "", motiontoonPath + motiontoonJson.getString(key))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,93 +0,0 @@
|
||||||
package eu.kanade.tachiyomi.extension.all.webtoons
|
|
||||||
|
|
||||||
import eu.kanade.tachiyomi.source.Source
|
|
||||||
import eu.kanade.tachiyomi.source.SourceFactory
|
|
||||||
import java.text.SimpleDateFormat
|
|
||||||
import java.util.GregorianCalendar
|
|
||||||
import java.util.Locale
|
|
||||||
|
|
||||||
class WebtoonsFactory : SourceFactory {
|
|
||||||
override fun createSources(): List<Source> = listOf(
|
|
||||||
WebtoonsEnglish(),
|
|
||||||
WebtoonsChineseTraditional(),
|
|
||||||
WebtoonsIndonesian(),
|
|
||||||
WebtoonsThai(),
|
|
||||||
WebtoonsFr(),
|
|
||||||
WebtoonsEs(),
|
|
||||||
DongmanManhua(),
|
|
||||||
|
|
||||||
// Fan translations
|
|
||||||
WebtoonsTranslate("en", "ENG"),
|
|
||||||
WebtoonsTranslate("zh", "CMN", " (Simplified)"),
|
|
||||||
WebtoonsTranslate("zh", "CMT", " (Traditional)"),
|
|
||||||
WebtoonsTranslate("th", "THA"),
|
|
||||||
WebtoonsTranslate("id", "IND"),
|
|
||||||
WebtoonsTranslate("fr", "FRA"),
|
|
||||||
WebtoonsTranslate("vi", "VIE"),
|
|
||||||
WebtoonsTranslate("ru", "RUS"),
|
|
||||||
WebtoonsTranslate("ar", "ARA"),
|
|
||||||
WebtoonsTranslate("fil", "FIL"),
|
|
||||||
WebtoonsTranslate("de", "DEU"),
|
|
||||||
WebtoonsTranslate("hi", "HIN"),
|
|
||||||
WebtoonsTranslate("it", "ITA"),
|
|
||||||
WebtoonsTranslate("ja", "JPN"),
|
|
||||||
WebtoonsTranslate("pt", "POR", " (Brazilian)"),
|
|
||||||
WebtoonsTranslate("tr", "TUR"),
|
|
||||||
WebtoonsTranslate("ms", "MAY"),
|
|
||||||
WebtoonsTranslate("pl", "POL"),
|
|
||||||
WebtoonsTranslate("pt", "POT", " (European)"),
|
|
||||||
WebtoonsTranslate("bg", "BUL"),
|
|
||||||
WebtoonsTranslate("da", "DAN"),
|
|
||||||
WebtoonsTranslate("nl", "NLD"),
|
|
||||||
WebtoonsTranslate("ro", "RON"),
|
|
||||||
WebtoonsTranslate("mn", "MON"),
|
|
||||||
WebtoonsTranslate("el", "GRE"),
|
|
||||||
WebtoonsTranslate("lt", "LIT"),
|
|
||||||
WebtoonsTranslate("cs", "CES"),
|
|
||||||
WebtoonsTranslate("sv", "SWE"),
|
|
||||||
WebtoonsTranslate("bn", "BEN"),
|
|
||||||
WebtoonsTranslate("fa", "PER"),
|
|
||||||
WebtoonsTranslate("uk", "UKR"),
|
|
||||||
WebtoonsTranslate("es", "SPA")
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
class WebtoonsEnglish : WebtoonsDefault("en")
|
|
||||||
|
|
||||||
class WebtoonsIndonesian : WebtoonsDefault("id") {
|
|
||||||
override val name: String = "Webtoons.com (Indonesian)"
|
|
||||||
|
|
||||||
// Android seems to be unable to parse Indonesian dates; we'll use a short hard-coded table
|
|
||||||
// instead.
|
|
||||||
private val dateMap: Array<String> = arrayOf(
|
|
||||||
"Jan", "Feb", "Mar", "Apr", "Mei", "Jun", "Jul", "Agu", "Sep", "Okt", "Nov", "Des"
|
|
||||||
)
|
|
||||||
|
|
||||||
override fun chapterParseDate(date: String): Long {
|
|
||||||
val expr = Regex("""(\d{4}) ([A-Z][a-z]{2}) (\d+)""").find(date) ?: return 0
|
|
||||||
val (_, year, monthString, day) = expr.groupValues
|
|
||||||
val monthIndex = dateMap.indexOf(monthString)
|
|
||||||
return GregorianCalendar(year.toInt(), monthIndex, day.toInt()).time.time
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class WebtoonsThai : WebtoonsDefault("th", dateFormat = SimpleDateFormat("d MMM yyyy", Locale("th")))
|
|
||||||
|
|
||||||
class WebtoonsChineseTraditional : WebtoonsDefault("zh", "zh-hant", "zh_TW", SimpleDateFormat("yyyy/MM/dd", Locale.TRADITIONAL_CHINESE))
|
|
||||||
|
|
||||||
class WebtoonsFr : WebtoonsDefault("fr", dateFormat = SimpleDateFormat("d MMM yyyy", Locale.FRENCH))
|
|
||||||
|
|
||||||
class WebtoonsEs : WebtoonsDefault("es") {
|
|
||||||
// Android seems to be unable to parse es dates like Indonesian; we'll use a short hard-coded table
|
|
||||||
// instead.
|
|
||||||
private val dateMap: Array<String> = arrayOf(
|
|
||||||
"Ene", "Feb", "Mar", "Abr", "May", "Jun", "Jul", "Ago", "Sep", "Oct", "Nov", "Dic"
|
|
||||||
)
|
|
||||||
|
|
||||||
override fun chapterParseDate(date: String): Long {
|
|
||||||
val expr = Regex("""(\d+)-([a-z]{3})-(\d{4})""").find(date) ?: return 0
|
|
||||||
val (_, day, monthString, year) = expr.groupValues
|
|
||||||
val monthIndex = dateMap.indexOf(monthString)
|
|
||||||
return GregorianCalendar(year.toInt(), monthIndex, day.toInt()).time.time
|
|
||||||
}
|
|
||||||
}
|
|