Add new multi-src: zerotheme (#9544)
This commit is contained in:
parent
1980853506
commit
4050e42337
5
lib-multisrc/zerotheme/build.gradle.kts
Normal file
5
lib-multisrc/zerotheme/build.gradle.kts
Normal file
@ -0,0 +1,5 @@
|
||||
plugins {
|
||||
id("lib-multisrc")
|
||||
}
|
||||
|
||||
baseVersionCode = 1
|
@ -0,0 +1,83 @@
|
||||
package eu.kanade.tachiyomi.multisrc.zerotheme
|
||||
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.network.interceptor.rateLimit
|
||||
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.online.HttpSource
|
||||
import eu.kanade.tachiyomi.util.asJsoup
|
||||
import keiyoushi.utils.parseAs
|
||||
import okhttp3.HttpUrl.Companion.toHttpUrl
|
||||
import okhttp3.Request
|
||||
import okhttp3.Response
|
||||
|
||||
abstract class ZeroTheme(
|
||||
override val name: String,
|
||||
override val baseUrl: String,
|
||||
override val lang: String,
|
||||
) : HttpSource() {
|
||||
|
||||
override val supportsLatest: Boolean = true
|
||||
|
||||
override val client = network.cloudflareClient.newBuilder()
|
||||
.rateLimit(2)
|
||||
.build()
|
||||
|
||||
open val cdnUrl: String = "https://cdn.${baseUrl.substringAfterLast("/")}"
|
||||
|
||||
open val imageLocation: String = "images"
|
||||
|
||||
private val sourceLocation: String get() = "$cdnUrl/$imageLocation"
|
||||
|
||||
// =========================== Popular ================================
|
||||
|
||||
override fun popularMangaRequest(page: Int) = searchMangaRequest(page, "", FilterList())
|
||||
|
||||
override fun popularMangaParse(response: Response) = searchMangaParse(response)
|
||||
|
||||
// =========================== Latest ===================================
|
||||
|
||||
override fun latestUpdatesRequest(page: Int) = GET(baseUrl, headers)
|
||||
|
||||
override fun latestUpdatesParse(response: Response): MangasPage =
|
||||
MangasPage(response.toDto<LatestDto>().toSMangaList(sourceLocation), hasNextPage = false)
|
||||
|
||||
// =========================== Search =================================
|
||||
|
||||
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
|
||||
val url = "$baseUrl/api/search".toHttpUrl().newBuilder()
|
||||
.addQueryParameter("q", query)
|
||||
.addQueryParameter("page", page.toString())
|
||||
.build()
|
||||
return GET(url, headers)
|
||||
}
|
||||
|
||||
override fun searchMangaParse(response: Response): MangasPage {
|
||||
val dto = response.parseAs<SearchDto>()
|
||||
val mangas = dto.mangas.map { it.toSManga(sourceLocation) }
|
||||
return MangasPage(mangas, hasNextPage = dto.hasNextPage())
|
||||
}
|
||||
|
||||
// =========================== Details =================================
|
||||
|
||||
override fun mangaDetailsParse(response: Response) = response.toDto<MangaDetailsDto>().toSManga(sourceLocation)
|
||||
|
||||
// =========================== Chapter =================================
|
||||
|
||||
override fun chapterListParse(response: Response) = response.toDto<MangaDetailsDto>().toSChapterList()
|
||||
|
||||
// =========================== Pages ===================================
|
||||
|
||||
override fun pageListParse(response: Response): List<Page> =
|
||||
response.toDto<PageDto>().toPageList(sourceLocation)
|
||||
|
||||
override fun imageUrlParse(response: Response) = ""
|
||||
|
||||
// =========================== Utilities ===============================
|
||||
|
||||
inline fun <reified T> Response.toDto(): T {
|
||||
val jsonString = asJsoup().selectFirst("[data-page]")!!.attr("data-page")
|
||||
return jsonString.parseAs<T>()
|
||||
}
|
||||
}
|
@ -0,0 +1,139 @@
|
||||
package eu.kanade.tachiyomi.multisrc.zerotheme
|
||||
|
||||
import eu.kanade.tachiyomi.source.model.Page
|
||||
import eu.kanade.tachiyomi.source.model.SChapter
|
||||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
import keiyoushi.utils.tryParse
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.json.JsonNames
|
||||
import org.jsoup.Jsoup
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Locale
|
||||
|
||||
@Serializable
|
||||
class Props<T>(
|
||||
@JsonNames("comic_infos", "chapter", "new_chapters")
|
||||
val content: T,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
class LatestDto(
|
||||
private val props: Props<List<Comic>>,
|
||||
) {
|
||||
fun toSMangaList(srcPath: String) = props.content.map { it.comic.toSManga(srcPath) }
|
||||
|
||||
@Serializable
|
||||
class Comic(
|
||||
val comic: MangaDto,
|
||||
)
|
||||
}
|
||||
|
||||
@Serializable
|
||||
class MangaDetailsDto(
|
||||
private val props: Props<MangaDto>,
|
||||
) {
|
||||
fun toSManga(srcPath: String) = props.content.toSManga(srcPath)
|
||||
fun toSChapterList() = props.content.chapters!!.map { it.toSChapter() }
|
||||
}
|
||||
|
||||
@Serializable
|
||||
class PageDto(
|
||||
val props: Props<ChapterWrapper>,
|
||||
) {
|
||||
fun toPageList(srcPath: String): List<Page> {
|
||||
return props.content.chapter.pages
|
||||
.filter { it.pathSegment.contains("xml").not() }
|
||||
.mapIndexed { index, path ->
|
||||
Page(index, imageUrl = "$srcPath/${path.pathSegment}")
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable
|
||||
class ChapterWrapper(
|
||||
val chapter: Chapter,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
class Chapter(
|
||||
val pages: List<Image>,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
class Image(
|
||||
@SerialName("page_path")
|
||||
val pathSegment: String,
|
||||
)
|
||||
}
|
||||
|
||||
@Serializable
|
||||
class SearchDto(
|
||||
@SerialName("comics")
|
||||
private val page: PageDto,
|
||||
) {
|
||||
|
||||
val mangas: List<MangaDto> get() = page.data
|
||||
|
||||
fun hasNextPage() = page.currentPage < page.lastPage
|
||||
|
||||
@Serializable
|
||||
class PageDto(
|
||||
val `data`: List<MangaDto>,
|
||||
@SerialName("last_page")
|
||||
val lastPage: Int = 0,
|
||||
@SerialName("current_page")
|
||||
val currentPage: Int = 0,
|
||||
)
|
||||
}
|
||||
|
||||
@Serializable
|
||||
class MangaDto(
|
||||
val title: String,
|
||||
val description: String?,
|
||||
@SerialName("cover")
|
||||
val thumbnailUrl: String?,
|
||||
val slug: String,
|
||||
val status: List<ValueDto>? = emptyList(),
|
||||
val genres: List<ValueDto>? = emptyList(),
|
||||
val chapters: List<ChapterDto>? = emptyList(),
|
||||
) {
|
||||
|
||||
fun toSManga(srcPath: String) = SManga.create().apply {
|
||||
title = this@MangaDto.title
|
||||
description = this@MangaDto.description?.let { Jsoup.parseBodyFragment(it).text() }
|
||||
this.thumbnail_url = thumbnailUrl?.let { "$srcPath/$it" }
|
||||
|
||||
status = when (this@MangaDto.status?.firstOrNull()?.name?.lowercase()) {
|
||||
"em andamento" -> SManga.ONGOING
|
||||
else -> SManga.UNKNOWN
|
||||
}
|
||||
genre = genres?.joinToString { it.name }
|
||||
url = "/comic/$slug"
|
||||
}
|
||||
|
||||
@Serializable
|
||||
class ValueDto(
|
||||
val name: String,
|
||||
)
|
||||
}
|
||||
|
||||
@Serializable
|
||||
class ChapterDto(
|
||||
@SerialName("chapter_number")
|
||||
val number: Float,
|
||||
@SerialName("chapter_path")
|
||||
val path: String,
|
||||
@SerialName("created_at")
|
||||
val createdAt: String,
|
||||
) {
|
||||
fun toSChapter() = SChapter.create().apply {
|
||||
name = number.toString()
|
||||
chapter_number = number
|
||||
date_upload = dateFormat.tryParse(createdAt)
|
||||
url = "/chapter/$path"
|
||||
}
|
||||
|
||||
companion object {
|
||||
val dateFormat = SimpleDateFormat("yyyy-MM-dd", Locale.ROOT)
|
||||
}
|
||||
}
|
@ -1,9 +1,9 @@
|
||||
ext {
|
||||
extName = 'Ego Toons'
|
||||
extClass = '.EgoToons'
|
||||
themePkg = 'yuyu'
|
||||
themePkg = 'zerotheme'
|
||||
baseUrl = 'https://egotoons.com'
|
||||
overrideVersionCode = 1
|
||||
overrideVersionCode = 2
|
||||
isNsfw = true
|
||||
}
|
||||
|
||||
|
@ -1,18 +1,18 @@
|
||||
package eu.kanade.tachiyomi.extension.pt.egotoons
|
||||
|
||||
import eu.kanade.tachiyomi.multisrc.yuyu.YuYu
|
||||
import eu.kanade.tachiyomi.multisrc.zerotheme.ZeroTheme
|
||||
import eu.kanade.tachiyomi.network.interceptor.rateLimit
|
||||
|
||||
class EgoToons : YuYu(
|
||||
class EgoToons : ZeroTheme(
|
||||
"Ego Toons",
|
||||
"https://egotoons.com",
|
||||
"pt-BR",
|
||||
) {
|
||||
|
||||
override fun headersBuilder() = super.headersBuilder()
|
||||
.set("Accept-Encoding", "")
|
||||
override val versionId = 2
|
||||
|
||||
override val client = super.client.newBuilder()
|
||||
.rateLimit(2)
|
||||
.build()
|
||||
|
||||
override val imageLocation = "image-db"
|
||||
}
|
||||
|
10
src/pt/lertoons/build.gradle
Normal file
10
src/pt/lertoons/build.gradle
Normal file
@ -0,0 +1,10 @@
|
||||
ext {
|
||||
extName = 'Ler Toons'
|
||||
extClass = '.LerToons'
|
||||
themePkg = 'zerotheme'
|
||||
baseUrl = 'https://lertoons.com'
|
||||
overrideVersionCode = 0
|
||||
isNsfw = true
|
||||
}
|
||||
|
||||
apply from: "$rootDir/common.gradle"
|
BIN
src/pt/lertoons/res/mipmap-hdpi/ic_launcher.png
Normal file
BIN
src/pt/lertoons/res/mipmap-hdpi/ic_launcher.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.7 KiB |
BIN
src/pt/lertoons/res/mipmap-mdpi/ic_launcher.png
Normal file
BIN
src/pt/lertoons/res/mipmap-mdpi/ic_launcher.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.6 KiB |
BIN
src/pt/lertoons/res/mipmap-xhdpi/ic_launcher.png
Normal file
BIN
src/pt/lertoons/res/mipmap-xhdpi/ic_launcher.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.5 KiB |
BIN
src/pt/lertoons/res/mipmap-xxhdpi/ic_launcher.png
Normal file
BIN
src/pt/lertoons/res/mipmap-xxhdpi/ic_launcher.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.1 KiB |
BIN
src/pt/lertoons/res/mipmap-xxxhdpi/ic_launcher.png
Normal file
BIN
src/pt/lertoons/res/mipmap-xxxhdpi/ic_launcher.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 8.3 KiB |
@ -0,0 +1,16 @@
|
||||
package eu.kanade.tachiyomi.extension.pt.lertoons
|
||||
|
||||
import eu.kanade.tachiyomi.multisrc.zerotheme.ZeroTheme
|
||||
import eu.kanade.tachiyomi.network.interceptor.rateLimit
|
||||
|
||||
class LerToons : ZeroTheme(
|
||||
"Ler Toons",
|
||||
"https://lertoons.com",
|
||||
"pt-BR",
|
||||
) {
|
||||
override val versionId = 3
|
||||
|
||||
override val client = network.cloudflareClient.newBuilder()
|
||||
.rateLimit(2)
|
||||
.build()
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user