|
@ -3,8 +3,8 @@ apply plugin: 'kotlin-android'
|
|||
|
||||
ext {
|
||||
appName = 'Tachiyomi: Webtoons'
|
||||
pkgNameSuffix = 'en.webtoons'
|
||||
extClass = '.Webtoons'
|
||||
pkgNameSuffix = 'all.webtoons'
|
||||
extClass = '.WebtoonsFactory'
|
||||
extVersionCode = 6
|
||||
libVersion = '1.2'
|
||||
}
|
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 |
|
@ -1,4 +1,4 @@
|
|||
package eu.kanade.tachiyomi.extension.en.webtoons
|
||||
package eu.kanade.tachiyomi.extension.all.webtoons
|
||||
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.source.model.*
|
||||
|
@ -9,17 +9,14 @@ import okhttp3.Request
|
|||
import okhttp3.Response
|
||||
import org.jsoup.nodes.Document
|
||||
import org.jsoup.nodes.Element
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
|
||||
class Webtoons : ParsedHttpSource() {
|
||||
abstract class Webtoons(override val lang: String) : ParsedHttpSource() {
|
||||
|
||||
override val name = "Webtoons.com"
|
||||
|
||||
override val baseUrl = "http://www.webtoons.com"
|
||||
|
||||
override val lang = "en"
|
||||
|
||||
override val supportsLatest = true
|
||||
|
||||
val day: String
|
||||
|
@ -45,7 +42,7 @@ class Webtoons : ParsedHttpSource() {
|
|||
override fun headersBuilder() = super.headersBuilder()
|
||||
.add("Referer", "http://www.webtoons.com/en/")
|
||||
|
||||
private val mobileHeaders = super.headersBuilder()
|
||||
protected val mobileHeaders = super.headersBuilder()
|
||||
.add("Referer", "http://m.webtoons.com")
|
||||
.build()
|
||||
|
||||
|
@ -135,28 +132,6 @@ class Webtoons : ParsedHttpSource() {
|
|||
else -> SManga.UNKNOWN
|
||||
}
|
||||
|
||||
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 { SimpleDateFormat("MMM d, yyyy", Locale.ENGLISH).parse(it).time } ?: 0
|
||||
return chapter
|
||||
}
|
||||
|
||||
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 imageUrlParse(document: Document) = document.select("img").first().attr("src")
|
||||
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
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.jsoup.nodes.Document
|
||||
import org.jsoup.nodes.Element
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
|
||||
open class WebtoonsDefault(override val lang: String) : Webtoons(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 { SimpleDateFormat("MMM d, yyyy", Locale.ENGLISH).parse(it).time } ?: 0
|
||||
return chapter
|
||||
}
|
||||
|
||||
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")) }
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package eu.kanade.tachiyomi.extension.all.webtoons
|
||||
|
||||
import eu.kanade.tachiyomi.extension.en.webtoons.WebtoonsEnglish
|
||||
import eu.kanade.tachiyomi.extension.fr.webtoons.WebtoonsFrench
|
||||
import eu.kanade.tachiyomi.source.Source
|
||||
import eu.kanade.tachiyomi.source.SourceFactory
|
||||
|
||||
class WebtoonsFactory : SourceFactory {
|
||||
override fun createSources(): List<Source> = getAllWebtoons()
|
||||
}
|
||||
|
||||
fun getAllWebtoons(): List<Source> {
|
||||
return listOf(
|
||||
WebtoonsEnglish(),
|
||||
WebtoonsFrench()
|
||||
)
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
package eu.kanade.tachiyomi.extension.all.webtoons
|
||||
|
||||
import android.util.Log.e
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.source.model.*
|
||||
import okhttp3.Request
|
||||
import okhttp3.Response
|
||||
import org.json.JSONObject
|
||||
import org.jsoup.nodes.Document
|
||||
import org.jsoup.nodes.Element
|
||||
import java.util.*
|
||||
|
||||
open class WebtoonsTranslate(override val lang: String, private val langCode: String) : Webtoons(lang) {
|
||||
|
||||
private val apiBaseUrl = "https://global.apis.naver.com"
|
||||
|
||||
private val chapterListUrlPattern = "/lineWebtoon/ctrans/translatedEpisodes_jsonp.json?titleNo=%d&languageCode=%s&offset=0&limit=10000"
|
||||
|
||||
private val pageListUrlPattern = "/lineWebtoon/ctrans/translatedEpisodeDetail_jsonp.json?titleNo=%s&episodeNo=%d&languageCode=%s&teamVersion=%d"
|
||||
|
||||
override fun chapterListSelector(): String = throw Exception("Not used")
|
||||
|
||||
override fun chapterFromElement(element: Element): SChapter = throw Exception("Not used")
|
||||
|
||||
override fun pageListParse(document: Document): List<Page> = throw Exception("Not used")
|
||||
|
||||
override fun chapterListRequest(manga: SManga): Request {
|
||||
val original = manga.url;
|
||||
val titleRegex = Regex("title_?[nN]o=([0-9]*)")
|
||||
val titleNo = titleRegex.find(original)!!.groupValues[1].toInt()
|
||||
|
||||
val chapterUrl = String.format("$apiBaseUrl$chapterListUrlPattern", titleNo, langCode)
|
||||
return GET(chapterUrl, headers)
|
||||
}
|
||||
|
||||
override fun chapterListParse(response: Response): List<SChapter> {
|
||||
val chapterJson = JSONObject(response.body()!!.string())
|
||||
var results = chapterJson.getJSONObject("result").getJSONArray("episodes")
|
||||
val ret = ArrayList<SChapter>()
|
||||
for (i in 0 until results.length()) {
|
||||
val result = results.getJSONObject(i)
|
||||
if (result.getBoolean("translateCompleted")) {
|
||||
ret.add(parseChapterJson(result))
|
||||
}
|
||||
}
|
||||
ret.reverse()
|
||||
return ret
|
||||
}
|
||||
|
||||
private fun parseChapterJson(obj: JSONObject) = SChapter.create().apply {
|
||||
name = obj.getString("title") + " #" + obj.getString("episodeSeq")
|
||||
chapter_number = obj.getInt("episodeSeq").toFloat()
|
||||
date_upload = obj.getLong("updateYmdt")
|
||||
scanlator = obj.getString("teamVersion")
|
||||
url = String.format(pageListUrlPattern, obj.getInt("titleNo"), obj.getInt("episodeNo"), obj.getString("languageCode"), obj.getInt("teamVersion"))
|
||||
}
|
||||
|
||||
override fun pageListRequest(chapter: SChapter): Request {
|
||||
return GET(apiBaseUrl + chapter.url, mobileHeaders)
|
||||
}
|
||||
|
||||
override fun pageListParse(response: Response): List<Page> {
|
||||
val pageJson = JSONObject(response.body()!!.string())
|
||||
var results = pageJson.getJSONObject("result").getJSONArray("imageInfo")
|
||||
val ret = ArrayList<Page>()
|
||||
for (i in 0 until results.length()) {
|
||||
val result = results.getJSONObject(i)
|
||||
ret.add(Page(i, "", result.getString("imageUrl")))
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
package eu.kanade.tachiyomi.extension.en.webtoons
|
||||
|
||||
import eu.kanade.tachiyomi.extension.all.webtoons.WebtoonsDefault
|
||||
|
||||
class WebtoonsEnglish : WebtoonsDefault("en")
|
|
@ -0,0 +1,5 @@
|
|||
package eu.kanade.tachiyomi.extension.fr.webtoons
|
||||
|
||||
import eu.kanade.tachiyomi.extension.all.webtoons.WebtoonsTranslate
|
||||
|
||||
class WebtoonsFrench : WebtoonsTranslate("fr", "FRA")
|