xkcd: add more translations (#9793)
* Spanish * French * Russian * Korean
This commit is contained in:
parent
e210beeca4
commit
8c16b03bb9
|
@ -6,7 +6,7 @@ ext {
|
||||||
extName = 'xkcd'
|
extName = 'xkcd'
|
||||||
pkgNameSuffix = 'all.xkcd'
|
pkgNameSuffix = 'all.xkcd'
|
||||||
extClass = '.XkcdFactory'
|
extClass = '.XkcdFactory'
|
||||||
extVersionCode = 11
|
extVersionCode = 12
|
||||||
}
|
}
|
||||||
|
|
||||||
apply from: "$rootDir/common.gradle"
|
apply from: "$rootDir/common.gradle"
|
||||||
|
|
|
@ -27,7 +27,7 @@ open class Xkcd(
|
||||||
protected open val creator = "Randall Munroe"
|
protected open val creator = "Randall Munroe"
|
||||||
|
|
||||||
protected open val synopsis =
|
protected open val synopsis =
|
||||||
"A webcomic of romance, sarcasm, math and language"
|
"A webcomic of romance, sarcasm, math and language."
|
||||||
|
|
||||||
protected open val interactiveText =
|
protected open val interactiveText =
|
||||||
"To experience the interactive version of this comic," +
|
"To experience the interactive version of this comic," +
|
||||||
|
@ -47,6 +47,25 @@ open class Xkcd(
|
||||||
|
|
||||||
protected open fun String.numbered(number: Any) = "$number - $this"
|
protected open fun String.numbered(number: Any) = "$number - $this"
|
||||||
|
|
||||||
|
// TODO: maybe use BreakIterator
|
||||||
|
protected fun wordWrap(title: String, altText: String) = buildString {
|
||||||
|
title.split(' ').forEachIndexed { i, w ->
|
||||||
|
if (i != 0 && i % 7 == 0) append("\n")
|
||||||
|
append(w).append(' ')
|
||||||
|
}
|
||||||
|
append("\n\n")
|
||||||
|
|
||||||
|
var charCount = 0
|
||||||
|
altText.replace("\r\n", " ").split(' ').forEach { w ->
|
||||||
|
if (charCount > 25) {
|
||||||
|
append("\n")
|
||||||
|
charCount = 0
|
||||||
|
}
|
||||||
|
append(w).append(' ')
|
||||||
|
charCount += w.length + 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
final override fun fetchPopularManga(page: Int) =
|
final override fun fetchPopularManga(page: Int) =
|
||||||
SManga.create().apply {
|
SManga.create().apply {
|
||||||
title = name
|
title = name
|
||||||
|
@ -88,27 +107,7 @@ open class Xkcd(
|
||||||
}
|
}
|
||||||
|
|
||||||
// create a text image for the alt text
|
// create a text image for the alt text
|
||||||
val titleWords = img.attr("alt").split(' ')
|
val text = wordWrap(img.attr("alt"), img.attr("title"))
|
||||||
val altTextWords = img.attr("title").split(' ')
|
|
||||||
|
|
||||||
// TODO: maybe use BreakIterator
|
|
||||||
val text = buildString {
|
|
||||||
titleWords.forEachIndexed { i, w ->
|
|
||||||
if (i != 0 && i % 7 == 0) append("\n")
|
|
||||||
append(w).append(' ')
|
|
||||||
}
|
|
||||||
append("\n\n")
|
|
||||||
|
|
||||||
var charCount = 0
|
|
||||||
altTextWords.forEach { w ->
|
|
||||||
if (charCount > 25) {
|
|
||||||
append("\n")
|
|
||||||
charCount = 0
|
|
||||||
}
|
|
||||||
append(w).append(' ')
|
|
||||||
charCount += w.length + 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return listOf(Page(0, "", image), Page(1, "", text.image()))
|
return listOf(Page(0, "", image), Page(1, "", text.image()))
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,19 @@
|
||||||
package eu.kanade.tachiyomi.extension.all.xkcd
|
package eu.kanade.tachiyomi.extension.all.xkcd
|
||||||
|
|
||||||
|
import eu.kanade.tachiyomi.extension.all.xkcd.translations.XkcdES
|
||||||
|
import eu.kanade.tachiyomi.extension.all.xkcd.translations.XkcdFR
|
||||||
|
import eu.kanade.tachiyomi.extension.all.xkcd.translations.XkcdKO
|
||||||
|
import eu.kanade.tachiyomi.extension.all.xkcd.translations.XkcdRU
|
||||||
import eu.kanade.tachiyomi.extension.all.xkcd.translations.XkcdZH
|
import eu.kanade.tachiyomi.extension.all.xkcd.translations.XkcdZH
|
||||||
import eu.kanade.tachiyomi.source.SourceFactory
|
import eu.kanade.tachiyomi.source.SourceFactory
|
||||||
|
|
||||||
class XkcdFactory : SourceFactory {
|
class XkcdFactory : SourceFactory {
|
||||||
override fun createSources() = listOf(
|
override fun createSources() = listOf(
|
||||||
Xkcd("https://xkcd.com", "en"),
|
Xkcd("https://xkcd.com", "en"),
|
||||||
|
XkcdES(),
|
||||||
XkcdZH(),
|
XkcdZH(),
|
||||||
|
XkcdFR(),
|
||||||
|
XkcdRU(),
|
||||||
|
XkcdKO(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
package eu.kanade.tachiyomi.extension.all.xkcd.translations
|
||||||
|
|
||||||
|
import eu.kanade.tachiyomi.extension.all.xkcd.Xkcd
|
||||||
|
import eu.kanade.tachiyomi.source.model.SChapter
|
||||||
|
import eu.kanade.tachiyomi.util.asJsoup
|
||||||
|
import okhttp3.Response
|
||||||
|
|
||||||
|
class XkcdES : Xkcd("https://es.xkcd.com", "es") {
|
||||||
|
override val synopsis =
|
||||||
|
"Un webcómic sobre romance, sarcasmo, mates y lenguaje."
|
||||||
|
|
||||||
|
// Google translated, sorry
|
||||||
|
override val interactiveText =
|
||||||
|
"Para experimentar la versión interactiva de este cómic," +
|
||||||
|
"\nábralo en WebView/navegador."
|
||||||
|
|
||||||
|
override val chapterListSelector = "#archive-ul > ul > li > a"
|
||||||
|
|
||||||
|
override val imageSelector = "#middleContent .strip"
|
||||||
|
|
||||||
|
override fun chapterListParse(response: Response) =
|
||||||
|
response.asJsoup().select(chapterListSelector).mapIndexed { idx, el ->
|
||||||
|
SChapter.create().apply {
|
||||||
|
name = el.text()
|
||||||
|
// convert relative path to absolute
|
||||||
|
url = el.attr("href").substring(2)
|
||||||
|
// not accurate to the original ¯\_(ツ)_/¯
|
||||||
|
chapter_number = idx + 1f
|
||||||
|
// no dates available
|
||||||
|
date_upload = 0L
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun String.numbered(number: Any) =
|
||||||
|
throw UnsupportedOperationException("Not used")
|
||||||
|
}
|
|
@ -0,0 +1,46 @@
|
||||||
|
package eu.kanade.tachiyomi.extension.all.xkcd.translations
|
||||||
|
|
||||||
|
import eu.kanade.tachiyomi.extension.all.xkcd.Xkcd
|
||||||
|
import eu.kanade.tachiyomi.source.model.Page
|
||||||
|
import eu.kanade.tachiyomi.source.model.SChapter
|
||||||
|
import eu.kanade.tachiyomi.util.asJsoup
|
||||||
|
import okhttp3.Response
|
||||||
|
|
||||||
|
class XkcdFR : Xkcd("https://xkcd.lapin.org", "fr") {
|
||||||
|
override val archive = "/tous-episodes.php"
|
||||||
|
|
||||||
|
override val synopsis =
|
||||||
|
"Un webcomic sarcastique qui parle de romance, de maths et de langage."
|
||||||
|
|
||||||
|
override val chapterListSelector = "#content .s > a:not(:last-of-type)"
|
||||||
|
|
||||||
|
override val imageSelector = "#content .s"
|
||||||
|
|
||||||
|
override fun String.numbered(number: Any) = "$number. $this"
|
||||||
|
|
||||||
|
override fun chapterListParse(response: Response) =
|
||||||
|
response.asJsoup().select(chapterListSelector).map {
|
||||||
|
SChapter.create().apply {
|
||||||
|
url = "/" + it.attr("href")
|
||||||
|
val number = url.substringAfter('=')
|
||||||
|
name = it.text().numbered(number)
|
||||||
|
chapter_number = number.toFloat()
|
||||||
|
// no dates available
|
||||||
|
date_upload = 0L
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun pageListParse(response: Response) =
|
||||||
|
response.asJsoup().selectFirst(imageSelector).let {
|
||||||
|
// no interactive comics here
|
||||||
|
val img = it.child(2).child(0).child(0)
|
||||||
|
|
||||||
|
// create a text image for the alt text
|
||||||
|
val text = wordWrap(it.child(0).text(), img.attr("alt"))
|
||||||
|
|
||||||
|
listOf(Page(0, "", img.attr("abs:src")), Page(1, "", text.image()))
|
||||||
|
}
|
||||||
|
|
||||||
|
override val interactiveText: String
|
||||||
|
get() = throw UnsupportedOperationException("Not used")
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
package eu.kanade.tachiyomi.extension.all.xkcd.translations
|
||||||
|
|
||||||
|
import eu.kanade.tachiyomi.extension.all.xkcd.Xkcd
|
||||||
|
import eu.kanade.tachiyomi.source.model.Page
|
||||||
|
import eu.kanade.tachiyomi.source.model.SChapter
|
||||||
|
import eu.kanade.tachiyomi.util.asJsoup
|
||||||
|
import okhttp3.Response
|
||||||
|
|
||||||
|
class XkcdKO : Xkcd("https://xkcdko.com", "ko") {
|
||||||
|
override val creator = "랜들 먼로"
|
||||||
|
|
||||||
|
override val synopsis = "사랑, 풍자, 수학, 그리고 언어에 관한 웹 만화."
|
||||||
|
|
||||||
|
// Google translated, sorry
|
||||||
|
override val interactiveText =
|
||||||
|
"이 만화의 대화형 버전을 경험하려면\nWebView/브라우저에서 엽니다."
|
||||||
|
|
||||||
|
override val altTextUrl = CJK_ALT_TEXT_URL
|
||||||
|
|
||||||
|
override val chapterListSelector = "#comicList > ol > li > a"
|
||||||
|
|
||||||
|
override fun chapterListParse(response: Response) =
|
||||||
|
response.asJsoup().select(chapterListSelector).map {
|
||||||
|
SChapter.create().apply {
|
||||||
|
url = it.attr("href")
|
||||||
|
val number = it.attr("title")
|
||||||
|
name = it.text().numbered(number)
|
||||||
|
chapter_number = number.toFloat()
|
||||||
|
// no dates available
|
||||||
|
date_upload = 0L
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun pageListParse(response: Response): List<Page> {
|
||||||
|
// if the img tag is empty then it is an interactive comic
|
||||||
|
val img = response.asJsoup().selectFirst(imageSelector)
|
||||||
|
?: return listOf(Page(0, "", interactiveText.image()))
|
||||||
|
|
||||||
|
// if an HD image is available it'll be the srcset attribute
|
||||||
|
val image = when {
|
||||||
|
!img.hasAttr("srcset") -> img.attr("abs:src")
|
||||||
|
else -> img.attr("abs:srcset").substringBefore(' ')
|
||||||
|
}
|
||||||
|
|
||||||
|
// create a text image for the alt text
|
||||||
|
val text = img.attr("alt") + "\n\n" + img.attr("title")
|
||||||
|
|
||||||
|
return listOf(Page(0, "", image), Page(1, "", text.image()))
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,48 @@
|
||||||
|
package eu.kanade.tachiyomi.extension.all.xkcd.translations
|
||||||
|
|
||||||
|
import eu.kanade.tachiyomi.extension.all.xkcd.Xkcd
|
||||||
|
import eu.kanade.tachiyomi.source.model.Page
|
||||||
|
import eu.kanade.tachiyomi.source.model.SChapter
|
||||||
|
import eu.kanade.tachiyomi.util.asJsoup
|
||||||
|
import okhttp3.Response
|
||||||
|
|
||||||
|
class XkcdRU : Xkcd("https://xkcd.ru", "ru") {
|
||||||
|
override val archive = "/img"
|
||||||
|
|
||||||
|
override val creator = "Рэндел Манро"
|
||||||
|
|
||||||
|
override val synopsis = "о романтике, сарказме, математике и языке"
|
||||||
|
|
||||||
|
override val altTextUrl = super.altTextUrl.replace("museo", "noto")
|
||||||
|
|
||||||
|
override val chapterListSelector = ".main > a"
|
||||||
|
|
||||||
|
override val imageSelector = ".main"
|
||||||
|
|
||||||
|
override fun String.numbered(number: Any) = "$number: $this"
|
||||||
|
|
||||||
|
override fun chapterListParse(response: Response) =
|
||||||
|
response.asJsoup().select(chapterListSelector).map {
|
||||||
|
SChapter.create().apply {
|
||||||
|
url = it.attr("href")
|
||||||
|
name = it.child(0).attr("title")
|
||||||
|
chapter_number = url.removeSurrounding("/").toFloat()
|
||||||
|
// no dates available
|
||||||
|
date_upload = 0L
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun pageListParse(response: Response) =
|
||||||
|
response.asJsoup().selectFirst(imageSelector).let {
|
||||||
|
// no interactive comics here
|
||||||
|
val img = it.child(5).child(0)
|
||||||
|
|
||||||
|
// create a text image for the alt text
|
||||||
|
val text = wordWrap(img.attr("alt"), it.child(7).text())
|
||||||
|
|
||||||
|
listOf(Page(0, "", img.attr("abs:src")), Page(1, "", text.image()))
|
||||||
|
}
|
||||||
|
|
||||||
|
override val interactiveText: String
|
||||||
|
get() = throw UnsupportedOperationException("Not used")
|
||||||
|
}
|
Loading…
Reference in New Issue