all/webtoons: Add additonal languages (#1510)

* all/webtoons: Add additonal languages

This adds more languages where webtoons has official comics:

- Chinese (Traditional)
- Indonesian
- Thai

Closes #1492

Note that Webtoons also has Chinese (Simplified) pages, but those go off
into a separate host name, so we're not touching that for now.

* all/webtoons: Fix build error

One file was not checked in by accident.

* all/webtoons: Bump extVersionCode
This commit is contained in:
Mook 2019-09-20 06:07:30 -07:00 committed by arkon
parent 0f3be64801
commit a685757575
8 changed files with 67 additions and 14 deletions

View File

@ -5,7 +5,7 @@ ext {
appName = 'Tachiyomi: Webtoons' appName = 'Tachiyomi: Webtoons'
pkgNameSuffix = 'all.webtoons' pkgNameSuffix = 'all.webtoons'
extClass = '.WebtoonsFactory' extClass = '.WebtoonsFactory'
extVersionCode = 7 extVersionCode = 8
libVersion = '1.2' libVersion = '1.2'
} }

View File

@ -11,7 +11,7 @@ import org.jsoup.nodes.Document
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import java.util.* import java.util.*
abstract class Webtoons(override val lang: String) : ParsedHttpSource() { abstract class Webtoons(override val lang: String, open val langCode: String = lang) : ParsedHttpSource() {
override val name = "Webtoons.com" override val name = "Webtoons.com"
@ -40,21 +40,22 @@ abstract class Webtoons(override val lang: String) : ParsedHttpSource() {
override fun latestUpdatesSelector() = "div#dailyList > $day li > a:has(span:contains(UP))" override fun latestUpdatesSelector() = "div#dailyList > $day li > a:has(span:contains(UP))"
override fun headersBuilder() = super.headersBuilder() override fun headersBuilder() = super.headersBuilder()
.add("Referer", "http://www.webtoons.com/en/") .add("Referer", "http://www.webtoons.com/$langCode/")
protected val mobileHeaders = super.headersBuilder() protected val mobileHeaders = super.headersBuilder()
.add("Referer", "http://m.webtoons.com") .add("Referer", "http://m.webtoons.com")
.build() .build()
override fun popularMangaRequest(page: Int) = GET("$baseUrl/en/top", headers) override fun popularMangaRequest(page: Int) = GET("$baseUrl/$langCode/top", headers)
override fun latestUpdatesRequest(page: Int) = GET("$baseUrl/en/dailySchedule?sortOrder=UPDATE&webtoonCompleteType=ONGOING", headers) override fun latestUpdatesRequest(page: Int) = GET("$baseUrl/$langCode/dailySchedule?sortOrder=UPDATE&webtoonCompleteType=ONGOING", headers)
private fun mangaFromElement(query: String, element: Element): SManga { private fun mangaFromElement(query: String, element: Element): SManga {
val manga = SManga.create() val manga = SManga.create()
element.select(query).first().let { element.select(query).first().let {
manga.setUrlWithoutDomain(it.attr("href")) manga.setUrlWithoutDomain(it.attr("href"))
manga.title = it.select("p.subj").text() manga.title = it.select("p.subj").text()
manga.thumbnail_url = it.select(".pic_area > img")?.attr("src")
} }
return manga return manga
} }
@ -117,8 +118,8 @@ abstract class Webtoons(override val lang: String) : ParsedHttpSource() {
val discoverPic = document.select("#content > div.cont_box > div.detail_header > span.thmb") val discoverPic = document.select("#content > div.cont_box > div.detail_header > span.thmb")
val manga = SManga.create() val manga = SManga.create()
manga.author = detailElement.select(".author:nth-of-type(1)").text().substringBefore("author info") manga.author = detailElement.select(".author:nth-of-type(1)").first()?.ownText()
manga.artist = detailElement.select(".author:nth-of-type(2)").first()?.text()?.substringBefore("author info") ?: manga.author manga.artist = detailElement.select(".author:nth-of-type(2)").first()?.ownText() ?: manga.author
manga.genre = detailElement.select(".genre").map { it.text() }.joinToString(", ") manga.genre = detailElement.select(".genre").map { it.text() }.joinToString(", ")
manga.description = infoElement.select("p.summary").text() manga.description = infoElement.select("p.summary").text()
manga.status = infoElement.select("p.day_info").text().orEmpty().let { parseStatus(it) } manga.status = infoElement.select("p.day_info").text().orEmpty().let { parseStatus(it) }

View File

@ -9,7 +9,7 @@ import org.jsoup.nodes.Element
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.* import java.util.*
open class WebtoonsDefault(override val lang: String) : Webtoons(lang) { open class WebtoonsDefault(override val lang: String, override val langCode: String = lang) : Webtoons(lang, langCode) {
override fun chapterListSelector() = "ul#_episodeList > li[id*=episode]" override fun chapterListSelector() = "ul#_episodeList > li[id*=episode]"
@ -26,10 +26,14 @@ open class WebtoonsDefault(override val lang: String) : Webtoons(lang) {
if (element.select(".ico_bgm").isNotEmpty()) { if (element.select(".ico_bgm").isNotEmpty()) {
chapter.name += "" chapter.name += ""
} }
chapter.date_upload = element.select("a > div.row > div.info > p.date").text()?.let { SimpleDateFormat("MMM d, yyyy", Locale.ENGLISH).parse(it).time } ?: 0 chapter.date_upload = element.select("a > div.row > div.info > p.date").text()?.let { chapterParseDate(it) } ?: 0
return chapter return chapter
} }
open fun chapterParseDate(date: String): Long {
return SimpleDateFormat("MMM d, yyyy", Locale.ENGLISH).parse(date).time
}
override fun chapterListRequest(manga: SManga) = GET("http://m.webtoons.com" + manga.url, mobileHeaders) override fun chapterListRequest(manga: SManga) = GET("http://m.webtoons.com" + manga.url, mobileHeaders)
override fun pageListParse(document: Document) = document.select("div#_imageList > img").mapIndexed { i, element -> Page(i, "", element.attr("data-url")) } override fun pageListParse(document: Document) = document.select("div#_imageList > img").mapIndexed { i, element -> Page(i, "", element.attr("data-url")) }

View File

@ -2,6 +2,9 @@ package eu.kanade.tachiyomi.extension.all.webtoons
import eu.kanade.tachiyomi.extension.en.webtoons.WebtoonsEnglish import eu.kanade.tachiyomi.extension.en.webtoons.WebtoonsEnglish
import eu.kanade.tachiyomi.extension.fr.webtoons.WebtoonsFrench import eu.kanade.tachiyomi.extension.fr.webtoons.WebtoonsFrench
import eu.kanade.tachiyomi.extension.id.webtoons.WebtoonsIndonesian
import eu.kanade.tachiyomi.extension.th.webtoons.WebtoonsThai
import eu.kanade.tachiyomi.extension.zh.webtoons.WebtoonsChineseTraditional
import eu.kanade.tachiyomi.source.Source import eu.kanade.tachiyomi.source.Source
import eu.kanade.tachiyomi.source.SourceFactory import eu.kanade.tachiyomi.source.SourceFactory
@ -12,6 +15,9 @@ class WebtoonsFactory : SourceFactory {
fun getAllWebtoons(): List<Source> { fun getAllWebtoons(): List<Source> {
return listOf( return listOf(
WebtoonsEnglish(), WebtoonsEnglish(),
WebtoonsFrench() WebtoonsChineseTraditional(),
WebtoonsFrench(),
WebtoonsIndonesian(),
WebtoonsThai()
) )
} }

View File

@ -10,7 +10,7 @@ import org.jsoup.nodes.Document
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import java.util.* import java.util.*
open class WebtoonsTranslate(override val lang: String, private val langCode: String) : Webtoons(lang) { open class WebtoonsTranslate(override val lang: String, private val translationLangCode: String) : Webtoons(lang) {
private val apiBaseUrl = "https://global.apis.naver.com" private val apiBaseUrl = "https://global.apis.naver.com"
@ -29,7 +29,7 @@ open class WebtoonsTranslate(override val lang: String, private val langCode: St
val titleRegex = Regex("title_?[nN]o=([0-9]*)") val titleRegex = Regex("title_?[nN]o=([0-9]*)")
val titleNo = titleRegex.find(original)!!.groupValues[1].toInt() val titleNo = titleRegex.find(original)!!.groupValues[1].toInt()
val chapterUrl = String.format("$apiBaseUrl$chapterListUrlPattern", titleNo, langCode) val chapterUrl = String.format("$apiBaseUrl$chapterListUrlPattern", titleNo, translationLangCode)
return GET(chapterUrl, headers) return GET(chapterUrl, headers)
} }

View File

@ -0,0 +1,20 @@
package eu.kanade.tachiyomi.extension.id.webtoons
import eu.kanade.tachiyomi.extension.all.webtoons.WebtoonsDefault
import java.util.*
class WebtoonsIndonesian: WebtoonsDefault("en", "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 DATE_MAP: 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{1,})""").find(date) ?: return 0
val (_, year, monthString, day) = expr.groupValues
val monthIndex = DATE_MAP.indexOf(monthString)
return GregorianCalendar(year.toInt(), monthIndex, day.toInt()).time.time
}
}

View File

@ -0,0 +1,11 @@
package eu.kanade.tachiyomi.extension.th.webtoons
import eu.kanade.tachiyomi.extension.all.webtoons.WebtoonsDefault
import java.text.SimpleDateFormat
import java.util.*
class WebtoonsThai: WebtoonsDefault("th") {
override fun chapterParseDate(date: String): Long {
return SimpleDateFormat("d MMM yyyy", Locale("th")).parse(date).time
}
}

View File

@ -0,0 +1,11 @@
package eu.kanade.tachiyomi.extension.zh.webtoons
import eu.kanade.tachiyomi.extension.all.webtoons.WebtoonsDefault
import java.text.SimpleDateFormat
import java.util.*
class WebtoonsChineseTraditional: WebtoonsDefault("zh", "zh-hant") {
override fun chapterParseDate(date: String): Long {
return SimpleDateFormat("yyyy/MM/dd", Locale.TRADITIONAL_CHINESE).parse(date).time
}
}