League of Legends: new extension (#9463)

This commit is contained in:
ObserverOfTime 2021-10-13 15:19:01 +03:00 committed by GitHub
parent abf7fe4284
commit 64ba1e6ba4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 254 additions and 0 deletions

View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest package="eu.kanade.tachiyomi.extension"/>

View File

@ -0,0 +1,12 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlinx-serialization'
ext {
extName = 'League of Legends'
pkgNameSuffix = 'all.leagueoflegends'
extClass = '.LOLFactory'
extVersionCode = 1
}
apply from: "$rootDir/common.gradle"

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 220 KiB

View File

@ -0,0 +1,30 @@
package eu.kanade.tachiyomi.extension.all.leagueoflegends
import eu.kanade.tachiyomi.source.SourceFactory
import kotlinx.serialization.ExperimentalSerializationApi
@ExperimentalSerializationApi
class LOLFactory : SourceFactory {
override fun createSources() = listOf(
LOLUniverse("en_us"),
// LOLUniverse("en_gb"),
LOLUniverse("de_de"),
LOLUniverse("es_es"),
LOLUniverse("fr_fr"),
LOLUniverse("it_it"),
// LOLUniverse("en_pl"),
LOLUniverse("pl_pl"),
LOLUniverse("el_gr"),
LOLUniverse("ro_ro"),
LOLUniverse("hu_hu"),
LOLUniverse("cs_cz"),
LOLUniverse("es_mx", "es-419"),
// LOLUniverse("es_ar", "es-419"),
LOLUniverse("pt_br", "pt-BR"),
LOLUniverse("ja_jp"),
LOLUniverse("ru_ru"),
LOLUniverse("tr_tr"),
// LOLUniverse("en_au"),
LOLUniverse("ko_kr"),
)
}

View File

@ -0,0 +1,62 @@
package eu.kanade.tachiyomi.extension.all.leagueoflegends
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@Serializable
data class LOLHub(
private val sections: LOLSections
) : Iterable<LOLComic> by sections
@Serializable
data class LOLSections(
val series: LOLData,
@SerialName("one-shots")
private val oneShots: LOLData
) : Iterable<LOLComic> {
override fun iterator() = (series + oneShots).iterator()
}
@Serializable
data class LOLData(
private val data: List<LOLComic>
) : Iterable<LOLComic> by data
@Serializable
data class LOLComic(
val title: String,
val subtitle: String? = null,
val index: Float? = null,
private val url: String,
val description: String,
val background: LOLImage,
@SerialName("featured-champions")
val champions: List<LOLChampion>? = null
) {
override fun toString() = url.substringAfter("/comic/")
}
@Serializable
data class LOLIssues(
private val issues: List<LOLComic>
) : Iterable<LOLComic> by issues
@Serializable
data class LOLPages(
@SerialName("staging-date")
val date: String,
@SerialName("desktop-pages")
private val pages: List<List<LOLImage>>
) : Iterable<LOLImage> {
override fun iterator() = pages.flatten().iterator()
}
@Serializable
data class LOLImage(private val uri: String) {
override fun toString() = uri
}
@Serializable
data class LOLChampion(private val name: String) {
override fun toString() = name
}

View File

@ -0,0 +1,148 @@
package eu.kanade.tachiyomi.extension.all.leagueoflegends
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.network.asObservableSuccess
import eu.kanade.tachiyomi.source.model.FilterList
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 eu.kanade.tachiyomi.source.online.HttpSource
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json
import okhttp3.Response
import rx.Observable
import uy.kohesive.injekt.injectLazy
import java.text.SimpleDateFormat
import java.util.Locale
@ExperimentalSerializationApi
class LOLUniverse(
private val siteLang: String,
override val lang: String = siteLang.substring(0, 2)
) : HttpSource() {
override val baseUrl = "$UNIVERSE_URL/$siteLang/comic/"
override val name = "League of Legends"
override val supportsLatest = false
private val json by injectLazy<Json>()
private val pageCache = mutableMapOf<String, List<Page>>()
override fun headersBuilder() = super.headersBuilder()
.set("Origin", UNIVERSE_URL).set("Referer", "$UNIVERSE_URL/")
override fun popularMangaRequest(page: Int) =
GET("$MEEPS_URL/$siteLang/comics/index.json", headers)
// Request the actual manga URL for the webview
override fun mangaDetailsRequest(manga: SManga) =
GET("$UNIVERSE_URL/$siteLang/comic/${manga.url}")
override fun chapterListRequest(manga: SManga) =
GET("$MEEPS_URL/$siteLang/comics/${manga.url}/index.json", headers)
override fun pageListRequest(chapter: SChapter) =
GET("$COMICS_URL/$siteLang/${chapter.url}/index.json", headers)
override fun popularMangaParse(response: Response) =
response.decode<LOLHub>().map {
SManga.create().apply {
title = it.title
url = it.toString()
description = it.description.clean()
thumbnail_url = it.background.toString()
genre = it.subtitle ?: it.champions?.joinToString()
}
}.run { MangasPage(this, false) }
override fun chapterListParse(response: Response) =
response.decode<LOLIssues>().map {
SChapter.create().apply {
name = it.title
url = it.toString()
chapter_number = it.index ?: -1f
fetchPageList()
}
}
override fun fetchSearchManga(page: Int, query: String, filters: FilterList) =
client.newCall(popularMangaRequest(page)).asObservableSuccess()
.map { popularMangaParse(it).filter(query) }!!
override fun fetchMangaDetails(manga: SManga) =
Observable.just(manga.apply { initialized = true })!!
override fun fetchChapterList(manga: SManga): Observable<List<SChapter>> {
if ('/' !in manga.url) return super.fetchChapterList(manga)
val chapter = SChapter.create().apply {
url = manga.url
name = "One Shot"
chapter_number = 0f
fetchPageList()
}
return Observable.just(listOf(chapter))
}
override fun fetchPageList(chapter: SChapter) =
Observable.just(pageCache[chapter.url].orEmpty())!!
override fun latestUpdatesRequest(page: Int) =
throw UnsupportedOperationException("Not used")
override fun searchMangaRequest(page: Int, query: String, filters: FilterList) =
throw UnsupportedOperationException("Not used")
override fun latestUpdatesParse(response: Response) =
throw UnsupportedOperationException("Not used")
override fun searchMangaParse(response: Response) =
throw UnsupportedOperationException("Not used")
override fun mangaDetailsParse(response: Response) =
throw UnsupportedOperationException("Not used")
override fun pageListParse(response: Response) =
throw UnsupportedOperationException("Not used")
override fun imageUrlParse(response: Response) =
throw UnsupportedOperationException("Not used")
private inline fun <reified T> Response.decode() =
json.decodeFromString<T>(body!!.string())
private fun String.clean() =
replace("</p> ", "</p>").replace("</p>", "\n").replace("<p>", "")
private fun SChapter.fetchPageList() {
client.newCall(pageListRequest(this)).execute().decode<LOLPages>().let {
// The chapter date is only available in the page list
date_upload = isoDate.parse(it.date)?.time ?: 0L
pageCache[url] = it.mapIndexed { idx, img ->
Page(idx, "", img.toString())
}
}
}
private fun MangasPage.filter(query: String) = copy(
mangas.filter {
it.title.contains(query, true) ||
it.genre?.contains(query, true) ?: false
}
)
companion object {
private const val UNIVERSE_URL = "https://universe.leagueoflegends.com"
private const val MEEPS_URL = "https://universe-meeps.leagueoflegends.com/v1"
private const val COMICS_URL = "https://universe-comics.leagueoflegends.com/comics"
private val isoDate by lazy {
SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.ROOT)
}
}
}