Initial commit
|
After Width: | Height: | Size: 4.8 KiB |
|
After Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 6.5 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 18 KiB |
BIN
multisrc/overrides/webtoons/default/res/web_hi_res_512.png
Normal file
|
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 |
BIN
multisrc/overrides/webtoons/dongmanmanhua/res/web_hi_res_512.png
Normal file
|
After Width: | Height: | Size: 41 KiB |
@@ -0,0 +1,62 @@
|
||||
package eu.kanade.tachiyomi.extension.zh.dongmanmanhua
|
||||
|
||||
import eu.kanade.tachiyomi.multisrc.webtoons.Webtoons
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.source.model.FilterList
|
||||
import eu.kanade.tachiyomi.source.model.SChapter
|
||||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
import eu.kanade.tachiyomi.util.asJsoup
|
||||
import okhttp3.Headers
|
||||
import okhttp3.Request
|
||||
import okhttp3.Response
|
||||
import org.jsoup.nodes.Document
|
||||
import org.jsoup.nodes.Element
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Locale
|
||||
|
||||
class DongmanManhua : Webtoons("Dongman Manhua", "https://www.dongmanmanhua.cn", "zh", "", dateFormat = SimpleDateFormat("yyyy-M-d", Locale.ENGLISH)) {
|
||||
|
||||
override fun headersBuilder(): Headers.Builder = super.headersBuilder()
|
||||
.removeAll("Referer")
|
||||
.add("Referer", baseUrl)
|
||||
|
||||
override fun popularMangaRequest(page: Int) = GET("$baseUrl/dailySchedule", headers)
|
||||
|
||||
override fun latestUpdatesRequest(page: Int) = GET("$baseUrl/dailySchedule?sortOrder=UPDATE&webtoonCompleteType=ONGOING", headers)
|
||||
|
||||
override fun parseDetailsThumbnail(document: Document): String? {
|
||||
return document.select("div.detail_body").attr("style").substringAfter("(").substringBefore(")")
|
||||
}
|
||||
|
||||
override fun chapterListRequest(manga: SManga): Request = GET(baseUrl + manga.url, headers)
|
||||
|
||||
override fun chapterListSelector() = "ul#_listUl li"
|
||||
|
||||
override fun chapterListParse(response: Response): List<SChapter> {
|
||||
var document = response.asJsoup()
|
||||
var continueParsing = true
|
||||
val chapters = mutableListOf<SChapter>()
|
||||
|
||||
while (continueParsing) {
|
||||
document.select(chapterListSelector()).map { chapters.add(chapterFromElement(it)) }
|
||||
document.select("div.paginate a[onclick] + a").let { element ->
|
||||
if (element.isNotEmpty()) {
|
||||
document = client.newCall(GET(element.attr("abs:href"), headers)).execute().asJsoup()
|
||||
} else {
|
||||
continueParsing = false
|
||||
}
|
||||
}
|
||||
}
|
||||
return chapters
|
||||
}
|
||||
|
||||
override fun chapterFromElement(element: Element): SChapter {
|
||||
return SChapter.create().apply {
|
||||
name = element.select("span.subj span").text()
|
||||
url = element.select("a").attr("href").substringAfter(".cn")
|
||||
date_upload = chapterParseDate(element.select("span.date").text())
|
||||
}
|
||||
}
|
||||
|
||||
override fun getFilterList(): FilterList = FilterList()
|
||||
}
|
||||
43
multisrc/overrides/webtoons/webtoons/AndroidManifest.xml
Normal file
@@ -0,0 +1,43 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<application>
|
||||
<activity
|
||||
android:name="eu.kanade.tachiyomi.multisrc.webtoons.WebtoonsUrlActivity"
|
||||
android:excludeFromRecents="true"
|
||||
android:exported="true"
|
||||
android:theme="@android:style/Theme.NoDisplay">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
|
||||
<data
|
||||
android:host="webtoons.com"
|
||||
android:pathPattern="/.*/.*/.*/..*"
|
||||
android:scheme="https" />
|
||||
<data
|
||||
android:host="www.webtoons.com"
|
||||
android:pathPattern="/.*/.*/.*/..*"
|
||||
android:scheme="https" />
|
||||
<data
|
||||
android:host="m.webtoons.com"
|
||||
android:pathPattern="/.*/.*/.*/..*"
|
||||
android:scheme="https" />
|
||||
<data
|
||||
android:host="webtoons.com"
|
||||
android:pathPattern="/.*/.*/.*/.*/..*"
|
||||
android:scheme="https" />
|
||||
<data
|
||||
android:host="www.webtoons.com"
|
||||
android:pathPattern="/.*/.*/.*/.*/..*"
|
||||
android:scheme="https" />
|
||||
<data
|
||||
android:host="m.webtoons.com"
|
||||
android:pathPattern="/.*/.*/.*/.*/..*"
|
||||
android:scheme="https" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
</manifest>
|
||||
3
multisrc/overrides/webtoons/webtoons/additional.gradle
Normal file
@@ -0,0 +1,3 @@
|
||||
dependencies {
|
||||
implementation(project(':lib-textinterceptor'))
|
||||
}
|
||||
66
multisrc/overrides/webtoons/webtoons/src/WebtoonsFactory.kt
Normal file
@@ -0,0 +1,66 @@
|
||||
package eu.kanade.tachiyomi.extension.all.webtoons
|
||||
|
||||
import eu.kanade.tachiyomi.source.Source
|
||||
import eu.kanade.tachiyomi.source.SourceFactory
|
||||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.GregorianCalendar
|
||||
import java.util.Locale
|
||||
|
||||
class WebtoonsFactory : SourceFactory {
|
||||
override fun createSources(): List<Source> = listOf(
|
||||
WebtoonsEN(),
|
||||
WebtoonsID(),
|
||||
WebtoonsTH(),
|
||||
WebtoonsES(),
|
||||
WebtoonsFR(),
|
||||
WebtoonsZH(),
|
||||
WebtoonsDE(),
|
||||
)
|
||||
}
|
||||
class WebtoonsEN : WebtoonsSrc("Webtoons.com", "https://www.webtoons.com", "en")
|
||||
class WebtoonsID : WebtoonsSrc("Webtoons.com", "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 : WebtoonsSrc("Webtoons.com", "https://www.webtoons.com", "th", dateFormat = SimpleDateFormat("d MMM yyyy", Locale("th")))
|
||||
class WebtoonsES : WebtoonsSrc("Webtoons.com", "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-Za-z]{3})-(\d{4})""").find(date) ?: return 0
|
||||
val (_, day, monthString, year) = expr.groupValues
|
||||
val monthIndex = dateMap.indexOf(monthString.lowercase(Locale("es")))
|
||||
return GregorianCalendar(year.toInt(), monthIndex, day.toInt()).time.time
|
||||
}
|
||||
}
|
||||
|
||||
class WebtoonsFR : WebtoonsSrc("Webtoons.com", "https://www.webtoons.com", "fr", dateFormat = SimpleDateFormat("d MMM yyyy", Locale.FRENCH)) {
|
||||
override fun String.toStatus(): Int = when {
|
||||
contains("NOUVEAU") -> SManga.ONGOING
|
||||
contains("TERMINÉ") -> SManga.COMPLETED
|
||||
else -> SManga.UNKNOWN
|
||||
}
|
||||
}
|
||||
|
||||
class WebtoonsZH : WebtoonsSrc("Webtoons.com", "https://www.webtoons.com", "zh-Hant", "zh-hant", "zh_TW", SimpleDateFormat("yyyy/MM/dd", Locale.TRADITIONAL_CHINESE)) {
|
||||
// Due to lang code getting more specific
|
||||
override val id: Long = 2959982438613576472
|
||||
}
|
||||
class WebtoonsDE : WebtoonsSrc("Webtoons.com", "https://www.webtoons.com", "de", dateFormat = SimpleDateFormat("dd.MM.yyyy", Locale.GERMAN))
|
||||
97
multisrc/overrides/webtoons/webtoons/src/WebtoonsSrc.kt
Normal file
@@ -0,0 +1,97 @@
|
||||
package eu.kanade.tachiyomi.extension.all.webtoons
|
||||
|
||||
import android.app.Application
|
||||
import android.content.SharedPreferences
|
||||
import androidx.preference.PreferenceScreen
|
||||
import androidx.preference.SwitchPreferenceCompat
|
||||
import eu.kanade.tachiyomi.lib.textinterceptor.TextInterceptor
|
||||
import eu.kanade.tachiyomi.lib.textinterceptor.TextInterceptorHelper
|
||||
import eu.kanade.tachiyomi.multisrc.webtoons.Webtoons
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.source.ConfigurableSource
|
||||
import eu.kanade.tachiyomi.source.model.Page
|
||||
import kotlinx.serialization.json.jsonObject
|
||||
import kotlinx.serialization.json.jsonPrimitive
|
||||
import okhttp3.OkHttpClient
|
||||
import org.jsoup.nodes.Document
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Locale
|
||||
|
||||
open class WebtoonsSrc(
|
||||
override val name: String,
|
||||
override val baseUrl: String,
|
||||
override val lang: String,
|
||||
langCode: String = lang,
|
||||
override val localeForCookie: String = lang,
|
||||
dateFormat: SimpleDateFormat = SimpleDateFormat("MMM d, yyyy", Locale.ENGLISH),
|
||||
) : ConfigurableSource, Webtoons(name, baseUrl, lang, langCode, localeForCookie, dateFormat) {
|
||||
|
||||
override val client: OkHttpClient = super.client.newBuilder()
|
||||
.addInterceptor(TextInterceptor())
|
||||
.build()
|
||||
|
||||
private val preferences: SharedPreferences by lazy {
|
||||
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
|
||||
}
|
||||
|
||||
override fun setupPreferenceScreen(screen: PreferenceScreen) {
|
||||
val authorsNotesPref = SwitchPreferenceCompat(screen.context).apply {
|
||||
key = SHOW_AUTHORS_NOTES_KEY
|
||||
title = "Show author's notes"
|
||||
summary = "Enable to see the author's notes at the end of chapters (if they're there)."
|
||||
setDefaultValue(false)
|
||||
|
||||
setOnPreferenceChangeListener { _, newValue ->
|
||||
val checkValue = newValue as Boolean
|
||||
preferences.edit().putBoolean(SHOW_AUTHORS_NOTES_KEY, checkValue).commit()
|
||||
}
|
||||
}
|
||||
screen.addPreference(authorsNotesPref)
|
||||
}
|
||||
|
||||
private fun showAuthorsNotesPref() = preferences.getBoolean(SHOW_AUTHORS_NOTES_KEY, false)
|
||||
|
||||
override fun pageListParse(document: Document): List<Page> {
|
||||
var pages = document.select("div#_imageList > img").mapIndexed { i, element -> Page(i, "", element.attr("data-url")) }
|
||||
|
||||
if (showAuthorsNotesPref()) {
|
||||
val note = document.select("div.creator_note p.author_text").text()
|
||||
|
||||
if (note.isNotEmpty()) {
|
||||
val creator = document.select("div.creator_note a.author_name span").text().trim()
|
||||
|
||||
pages = pages + Page(
|
||||
pages.size,
|
||||
"",
|
||||
TextInterceptorHelper.createUrl(creator, note),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
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 motiontoonResponse = client.newCall(GET(docUrl, headers)).execute()
|
||||
|
||||
val motiontoonJson = json.parseToJsonElement(motiontoonResponse.body.string()).jsonObject
|
||||
val motiontoonImages = motiontoonJson["assets"]!!.jsonObject["image"]!!.jsonObject
|
||||
|
||||
return motiontoonImages.entries
|
||||
.filter { it.key.contains("layer") }
|
||||
.mapIndexed { i, entry ->
|
||||
Page(i, "", motiontoonPath + entry.value.jsonPrimitive.content)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val SHOW_AUTHORS_NOTES_KEY = "showAuthorsNotes"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
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") {
|
||||
// Hardcode the id because the language code was wrong.
|
||||
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")
|
||||