parent
64904ba658
commit
948b756e7f
|
@ -5,7 +5,7 @@ ext {
|
|||
appName = 'Tachiyomi: Webtoons'
|
||||
pkgNameSuffix = 'all.webtoons'
|
||||
extClass = '.WebtoonsFactory'
|
||||
extVersionCode = 8
|
||||
extVersionCode = 9
|
||||
libVersion = '1.2'
|
||||
}
|
||||
|
||||
|
|
|
@ -4,9 +4,7 @@ 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.HttpUrl
|
||||
import okhttp3.Request
|
||||
import okhttp3.Response
|
||||
import okhttp3.*
|
||||
import org.jsoup.nodes.Document
|
||||
import org.jsoup.nodes.Element
|
||||
import java.util.*
|
||||
|
@ -71,7 +69,7 @@ abstract class Webtoons(override val lang: String, open val langCode: String = l
|
|||
return manga
|
||||
}
|
||||
|
||||
override fun popularMangaNextPageSelector() = null
|
||||
override fun popularMangaNextPageSelector() : String? = null
|
||||
|
||||
override fun latestUpdatesNextPageSelector() = null
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
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.extension.id.webtoons.WebtoonsIndonesian
|
||||
import eu.kanade.tachiyomi.extension.th.webtoons.WebtoonsThai
|
||||
import eu.kanade.tachiyomi.extension.zh.webtoons.WebtoonsChineseTraditional
|
||||
|
@ -14,10 +13,42 @@ class WebtoonsFactory : SourceFactory {
|
|||
|
||||
fun getAllWebtoons(): List<Source> {
|
||||
return listOf(
|
||||
WebtoonsEnglish(),
|
||||
WebtoonsChineseTraditional(),
|
||||
WebtoonsFrench(),
|
||||
WebtoonsIndonesian(),
|
||||
WebtoonsThai()
|
||||
WebtoonsEnglish(),
|
||||
WebtoonsChineseTraditional(),
|
||||
WebtoonsIndonesian(),
|
||||
WebtoonsThai(),
|
||||
|
||||
// fan translations
|
||||
WebtoonsTranslate("en", "ENG"),
|
||||
WebtoonsTranslate("zh", "CMN", " (Simplified)"),
|
||||
WebtoonsTranslate("zh", "CHT", " (Traditional)"),
|
||||
WebtoonsTranslate("th", "THA"),
|
||||
WebtoonsTranslate("in", "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")
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
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 eu.kanade.tachiyomi.source.model.MangasPage
|
||||
import eu.kanade.tachiyomi.source.model.Page
|
||||
import eu.kanade.tachiyomi.source.model.SChapter
|
||||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
import okhttp3.HttpUrl
|
||||
import okhttp3.Request
|
||||
import okhttp3.Response
|
||||
import org.json.JSONObject
|
||||
|
@ -10,14 +13,100 @@ import org.jsoup.nodes.Document
|
|||
import org.jsoup.nodes.Element
|
||||
import java.util.*
|
||||
|
||||
open class WebtoonsTranslate(override val lang: String, private val translationLangCode: String) : Webtoons(lang) {
|
||||
open class WebtoonsTranslate(override val lang: String, private val translateLangCode: String, private val languageNameExtra: 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 apiBaseUrl = HttpUrl.parse("https://global.apis.naver.com")!!
|
||||
private val mobileBaseUrl = HttpUrl.parse("https://m.webtoons.com")!!
|
||||
private val thumbnailBaseUrl = "https://mwebtoon-phinf.pstatic.net"
|
||||
|
||||
private val pageListUrlPattern = "/lineWebtoon/ctrans/translatedEpisodeDetail_jsonp.json?titleNo=%s&episodeNo=%d&languageCode=%s&teamVersion=%d"
|
||||
|
||||
private val pageSize = 24
|
||||
|
||||
override val name = "Webtoons.com Translations${languageNameExtra}"
|
||||
|
||||
override fun headersBuilder() = super.headersBuilder()
|
||||
.removeAll("Referer")
|
||||
.add("Referer", mobileBaseUrl.toString())
|
||||
|
||||
override fun popularMangaRequest(page: Int): Request {
|
||||
// Webtoons translations doesn't really have a "popular" sort; just "UPDATE", "TITLE_ASC",
|
||||
// and "TITLE_DESC". Pick UPDATE as the most useful sort.
|
||||
var url = apiBaseUrl
|
||||
.resolve("/lineWebtoon/ctrans/translatedWebtoons_jsonp.json")!!
|
||||
.newBuilder()
|
||||
.addQueryParameter("orderType", "UPDATE")
|
||||
.addQueryParameter("offset", "${page * pageSize}")
|
||||
.addQueryParameter("size", "${pageSize}")
|
||||
.addQueryParameter("languageCode", translateLangCode)
|
||||
.build()
|
||||
return GET(url.toString(), headers)
|
||||
}
|
||||
|
||||
override fun popularMangaParse(response: Response): MangasPage {
|
||||
val responseText = response.body()!!.string()
|
||||
val requestURL = response.request().url()
|
||||
val offset = requestURL.queryParameter("offset")!!.toInt()
|
||||
val responseJSON = JSONObject(responseText)
|
||||
val responseCode = responseJSON.getString("code")
|
||||
if (responseCode != "000") {
|
||||
throw Exception("Error getting popular manga: error code ${responseCode}")
|
||||
}
|
||||
var results = responseJSON.getJSONObject("result")
|
||||
val totalCount = results.getInt("totalCount")
|
||||
val titleList = results.getJSONArray("titleList")
|
||||
val mangas = (0 until titleList.length()).map { i ->
|
||||
val titleJSON = titleList.get(i) as JSONObject
|
||||
val titleNo = titleJSON.getInt("titleNo")
|
||||
val team = titleJSON.optInt("teamVersion", 0)
|
||||
val relativeThumnailURL = titleJSON.getString("thumbnailIPadUrl")
|
||||
?: titleJSON.getString("thumbnailMobileUrl")
|
||||
SManga.create()
|
||||
.apply {
|
||||
title = titleJSON.getString("representTitle")
|
||||
author = titleJSON.getString("writeAuthorName")
|
||||
artist = titleJSON.getString("pictureAuthorName") ?: author
|
||||
thumbnail_url = if (relativeThumnailURL != null) "${thumbnailBaseUrl}${relativeThumnailURL}" else null
|
||||
status = SManga.UNKNOWN
|
||||
url = mobileBaseUrl
|
||||
.resolve("/translate/episodeList")!!
|
||||
.newBuilder()
|
||||
.addQueryParameter("titleNo", titleNo.toString())
|
||||
.addQueryParameter("languageCode", translateLangCode)
|
||||
.addQueryParameter("teamVersion", team.toString())
|
||||
.build()
|
||||
.toString()
|
||||
initialized = true
|
||||
}
|
||||
}
|
||||
return MangasPage(mangas, totalCount < pageSize * offset)
|
||||
}
|
||||
|
||||
override fun mangaDetailsRequest(manga: SManga): Request {
|
||||
return GET(manga.url, headers)
|
||||
}
|
||||
|
||||
override fun mangaDetailsParse(document: Document): SManga {
|
||||
val getMetaProp = fun(property: String): String =
|
||||
document.head().select("meta[property=\"${property}\"]").attr("content")
|
||||
var parsedAuthor = getMetaProp("com-linewebtoon:webtoon:author")
|
||||
var parsedArtist = parsedAuthor
|
||||
val authorSplit = parsedAuthor.split(" / ", limit = 2)
|
||||
if (authorSplit.count() > 1) {
|
||||
parsedAuthor = authorSplit[0]
|
||||
parsedArtist = authorSplit[1]
|
||||
}
|
||||
|
||||
return SManga.create().apply {
|
||||
title = getMetaProp("og:title")
|
||||
artist = parsedArtist
|
||||
author = parsedAuthor
|
||||
description = getMetaProp("og:description")
|
||||
status = SManga.UNKNOWN
|
||||
thumbnail_url = getMetaProp("og:image")
|
||||
}
|
||||
}
|
||||
|
||||
override fun chapterListSelector(): String = throw Exception("Not used")
|
||||
|
||||
override fun chapterFromElement(element: Element): SChapter = throw Exception("Not used")
|
||||
|
@ -25,16 +114,27 @@ open class WebtoonsTranslate(override val lang: String, private val translationL
|
|||
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, translationLangCode)
|
||||
return GET(chapterUrl, headers)
|
||||
val titleNo = HttpUrl.parse(manga.url)!!
|
||||
.queryParameter("titleNo")
|
||||
val chapterUrl = apiBaseUrl
|
||||
.resolve("/lineWebtoon/ctrans/translatedEpisodes_jsonp.json")!!
|
||||
.newBuilder()
|
||||
.addQueryParameter("titleNo", titleNo)
|
||||
.addQueryParameter("languageCode", translateLangCode)
|
||||
.addQueryParameter("offset", "0")
|
||||
.addQueryParameter("limit", "10000")
|
||||
.toString()
|
||||
return GET(chapterUrl, mobileHeaders)
|
||||
}
|
||||
|
||||
override fun chapterListParse(response: Response): List<SChapter> {
|
||||
val chapterJson = JSONObject(response.body()!!.string())
|
||||
val chapterData = response.body()!!.string()
|
||||
val chapterJson = JSONObject(chapterData)
|
||||
val responseCode = chapterJson.getString("code")
|
||||
if (responseCode != "000") {
|
||||
val message = chapterJson.optString("message", "error code ${responseCode}")
|
||||
throw Exception("Error getting chapter list: ${message}")
|
||||
}
|
||||
var results = chapterJson.getJSONObject("result").getJSONArray("episodes")
|
||||
val ret = ArrayList<SChapter>()
|
||||
for (i in 0 until results.length()) {
|
||||
|
@ -52,11 +152,14 @@ open class WebtoonsTranslate(override val lang: String, private val translationL
|
|||
chapter_number = obj.getInt("episodeSeq").toFloat()
|
||||
date_upload = obj.getLong("updateYmdt")
|
||||
scanlator = obj.getString("teamVersion")
|
||||
if (scanlator == "0") {
|
||||
scanlator = "(wiki)"
|
||||
}
|
||||
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)
|
||||
return GET(apiBaseUrl.resolve(chapter.url).toString(), headers)
|
||||
}
|
||||
|
||||
override fun pageListParse(response: Response): List<Page> {
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
package eu.kanade.tachiyomi.extension.fr.webtoons
|
||||
|
||||
import eu.kanade.tachiyomi.extension.all.webtoons.WebtoonsTranslate
|
||||
|
||||
class WebtoonsFrench : WebtoonsTranslate("fr", "FRA")
|
Loading…
Reference in New Issue