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'
|
||||
pkgNameSuffix = 'all.xkcd'
|
||||
extClass = '.XkcdFactory'
|
||||
extVersionCode = 11
|
||||
extVersionCode = 12
|
||||
}
|
||||
|
||||
apply from: "$rootDir/common.gradle"
|
||||
|
|
|
@ -27,7 +27,7 @@ open class Xkcd(
|
|||
protected open val creator = "Randall Munroe"
|
||||
|
||||
protected open val synopsis =
|
||||
"A webcomic of romance, sarcasm, math and language"
|
||||
"A webcomic of romance, sarcasm, math and language."
|
||||
|
||||
protected open val interactiveText =
|
||||
"To experience the interactive version of this comic," +
|
||||
|
@ -47,6 +47,25 @@ open class Xkcd(
|
|||
|
||||
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) =
|
||||
SManga.create().apply {
|
||||
title = name
|
||||
|
@ -88,27 +107,7 @@ open class Xkcd(
|
|||
}
|
||||
|
||||
// create a text image for the alt text
|
||||
val titleWords = img.attr("alt").split(' ')
|
||||
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
|
||||
}
|
||||
}
|
||||
val text = wordWrap(img.attr("alt"), img.attr("title"))
|
||||
|
||||
return listOf(Page(0, "", image), Page(1, "", text.image()))
|
||||
}
|
||||
|
|
|
@ -1,11 +1,19 @@
|
|||
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.source.SourceFactory
|
||||
|
||||
class XkcdFactory : SourceFactory {
|
||||
override fun createSources() = listOf(
|
||||
Xkcd("https://xkcd.com", "en"),
|
||||
XkcdES(),
|
||||
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