diff --git a/src/en/webtoons/build.gradle b/src/all/webtoons/build.gradle similarity index 74% rename from src/en/webtoons/build.gradle rename to src/all/webtoons/build.gradle index 4396f6bdb..d9f330a28 100644 --- a/src/en/webtoons/build.gradle +++ b/src/all/webtoons/build.gradle @@ -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' } diff --git a/src/en/webtoons/res/mipmap-hdpi/ic_launcher.png b/src/all/webtoons/res/mipmap-hdpi/ic_launcher.png similarity index 100% rename from src/en/webtoons/res/mipmap-hdpi/ic_launcher.png rename to src/all/webtoons/res/mipmap-hdpi/ic_launcher.png diff --git a/src/en/webtoons/res/mipmap-mdpi/ic_launcher.png b/src/all/webtoons/res/mipmap-mdpi/ic_launcher.png similarity index 100% rename from src/en/webtoons/res/mipmap-mdpi/ic_launcher.png rename to src/all/webtoons/res/mipmap-mdpi/ic_launcher.png diff --git a/src/en/webtoons/res/mipmap-xhdpi/ic_launcher.png b/src/all/webtoons/res/mipmap-xhdpi/ic_launcher.png similarity index 100% rename from src/en/webtoons/res/mipmap-xhdpi/ic_launcher.png rename to src/all/webtoons/res/mipmap-xhdpi/ic_launcher.png diff --git a/src/en/webtoons/res/mipmap-xxhdpi/ic_launcher.png b/src/all/webtoons/res/mipmap-xxhdpi/ic_launcher.png similarity index 100% rename from src/en/webtoons/res/mipmap-xxhdpi/ic_launcher.png rename to src/all/webtoons/res/mipmap-xxhdpi/ic_launcher.png diff --git a/src/en/webtoons/res/mipmap-xxxhdpi/ic_launcher.png b/src/all/webtoons/res/mipmap-xxxhdpi/ic_launcher.png similarity index 100% rename from src/en/webtoons/res/mipmap-xxxhdpi/ic_launcher.png rename to src/all/webtoons/res/mipmap-xxxhdpi/ic_launcher.png diff --git a/src/en/webtoons/res/web_hi_res_512.png b/src/all/webtoons/res/web_hi_res_512.png similarity index 100% rename from src/en/webtoons/res/web_hi_res_512.png rename to src/all/webtoons/res/web_hi_res_512.png diff --git a/src/en/webtoons/src/eu/kanade/tachiyomi/extension/en/webtoons/Webtoons.kt b/src/all/webtoons/src/eu/kanade/tachiyomi/extension/all/webtoons/Webtoons.kt similarity index 79% rename from src/en/webtoons/src/eu/kanade/tachiyomi/extension/en/webtoons/Webtoons.kt rename to src/all/webtoons/src/eu/kanade/tachiyomi/extension/all/webtoons/Webtoons.kt index 104792480..baf63662f 100644 --- a/src/en/webtoons/src/eu/kanade/tachiyomi/extension/en/webtoons/Webtoons.kt +++ b/src/all/webtoons/src/eu/kanade/tachiyomi/extension/all/webtoons/Webtoons.kt @@ -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") + } diff --git a/src/all/webtoons/src/eu/kanade/tachiyomi/extension/all/webtoons/WebtoonsDefault.kt b/src/all/webtoons/src/eu/kanade/tachiyomi/extension/all/webtoons/WebtoonsDefault.kt new file mode 100644 index 000000000..4510263c5 --- /dev/null +++ b/src/all/webtoons/src/eu/kanade/tachiyomi/extension/all/webtoons/WebtoonsDefault.kt @@ -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")) } +} \ No newline at end of file diff --git a/src/all/webtoons/src/eu/kanade/tachiyomi/extension/all/webtoons/WebtoonsFactory.kt b/src/all/webtoons/src/eu/kanade/tachiyomi/extension/all/webtoons/WebtoonsFactory.kt new file mode 100644 index 000000000..c77c03533 --- /dev/null +++ b/src/all/webtoons/src/eu/kanade/tachiyomi/extension/all/webtoons/WebtoonsFactory.kt @@ -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 = getAllWebtoons() +} + +fun getAllWebtoons(): List { + return listOf( + WebtoonsEnglish(), + WebtoonsFrench() + ) +} \ No newline at end of file diff --git a/src/all/webtoons/src/eu/kanade/tachiyomi/extension/all/webtoons/WebtoonsTranslate.kt b/src/all/webtoons/src/eu/kanade/tachiyomi/extension/all/webtoons/WebtoonsTranslate.kt new file mode 100644 index 000000000..00ca26126 --- /dev/null +++ b/src/all/webtoons/src/eu/kanade/tachiyomi/extension/all/webtoons/WebtoonsTranslate.kt @@ -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 = 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 { + val chapterJson = JSONObject(response.body()!!.string()) + var results = chapterJson.getJSONObject("result").getJSONArray("episodes") + val ret = ArrayList() + 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 { + val pageJson = JSONObject(response.body()!!.string()) + var results = pageJson.getJSONObject("result").getJSONArray("imageInfo") + val ret = ArrayList() + for (i in 0 until results.length()) { + val result = results.getJSONObject(i) + ret.add(Page(i, "", result.getString("imageUrl"))) + } + return ret + } + +} diff --git a/src/all/webtoons/src/eu/kanade/tachiyomi/extension/en/webtoons/WebtoonsEnglish.kt b/src/all/webtoons/src/eu/kanade/tachiyomi/extension/en/webtoons/WebtoonsEnglish.kt new file mode 100644 index 000000000..f94b019c2 --- /dev/null +++ b/src/all/webtoons/src/eu/kanade/tachiyomi/extension/en/webtoons/WebtoonsEnglish.kt @@ -0,0 +1,5 @@ +package eu.kanade.tachiyomi.extension.en.webtoons + +import eu.kanade.tachiyomi.extension.all.webtoons.WebtoonsDefault + +class WebtoonsEnglish : WebtoonsDefault("en") \ No newline at end of file diff --git a/src/all/webtoons/src/eu/kanade/tachiyomi/extension/fr/webtoons/WebtoonsFrench.kt b/src/all/webtoons/src/eu/kanade/tachiyomi/extension/fr/webtoons/WebtoonsFrench.kt new file mode 100644 index 000000000..fc9d846f9 --- /dev/null +++ b/src/all/webtoons/src/eu/kanade/tachiyomi/extension/fr/webtoons/WebtoonsFrench.kt @@ -0,0 +1,5 @@ +package eu.kanade.tachiyomi.extension.fr.webtoons + +import eu.kanade.tachiyomi.extension.all.webtoons.WebtoonsTranslate + +class WebtoonsFrench : WebtoonsTranslate("fr", "FRA") \ No newline at end of file