Move Olympus Scanlation to an individual extension (#15540)
* created OlympusScan * adjustments * removed old olympus scanlation ext * adjustments
|
@ -1,35 +0,0 @@
|
||||||
package eu.kanade.tachiyomi.extension.all.olympusscanlation
|
|
||||||
|
|
||||||
import eu.kanade.tachiyomi.multisrc.madara.Madara
|
|
||||||
import eu.kanade.tachiyomi.network.interceptor.rateLimit
|
|
||||||
import eu.kanade.tachiyomi.source.SourceFactory
|
|
||||||
import okhttp3.OkHttpClient
|
|
||||||
import java.text.SimpleDateFormat
|
|
||||||
import java.util.Locale
|
|
||||||
import java.util.concurrent.TimeUnit
|
|
||||||
|
|
||||||
class OlympusScanlationFactory : SourceFactory {
|
|
||||||
override fun createSources() = listOf(
|
|
||||||
OlympusScanlationBr(),
|
|
||||||
OlympusScanlationEs(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract class OlympusScanlation(
|
|
||||||
override val baseUrl: String,
|
|
||||||
lang: String,
|
|
||||||
dateFormat: SimpleDateFormat = SimpleDateFormat("MMMMM dd, yyyy", Locale.US),
|
|
||||||
) : Madara("Olympus Scanlation", baseUrl, lang, dateFormat)
|
|
||||||
|
|
||||||
class OlympusScanlationEs : OlympusScanlation("https://olympusscanlation.com", "es")
|
|
||||||
|
|
||||||
class OlympusScanlationBr : OlympusScanlation(
|
|
||||||
"https://br.olympusscanlation.com",
|
|
||||||
"pt-BR",
|
|
||||||
SimpleDateFormat("MMMMM dd, yyyy", Locale("pt", "BR")),
|
|
||||||
) {
|
|
||||||
|
|
||||||
override val client: OkHttpClient = super.client.newBuilder()
|
|
||||||
.rateLimit(1, 2, TimeUnit.SECONDS)
|
|
||||||
.build()
|
|
||||||
}
|
|
|
@ -16,7 +16,6 @@ class MadaraGenerator : ThemeSourceGenerator {
|
||||||
MultiLang("Leviatan Scans", "https://leviatanscans.com", listOf("en", "es"), className = "LeviatanScansFactory", overrideVersionCode = 13),
|
MultiLang("Leviatan Scans", "https://leviatanscans.com", listOf("en", "es"), className = "LeviatanScansFactory", overrideVersionCode = 13),
|
||||||
MultiLang("MangaForFree.net", "https://mangaforfree.net", listOf("en", "ko", "all"), isNsfw = true, className = "MangaForFreeFactory", pkgName = "mangaforfree", overrideVersionCode = 1),
|
MultiLang("MangaForFree.net", "https://mangaforfree.net", listOf("en", "ko", "all"), isNsfw = true, className = "MangaForFreeFactory", pkgName = "mangaforfree", overrideVersionCode = 1),
|
||||||
MultiLang("Manhwa18.cc", "https://manhwa18.cc", listOf("en", "ko", "all"), isNsfw = true, className = "Manhwa18CcFactory", pkgName = "manhwa18cc", overrideVersionCode = 4),
|
MultiLang("Manhwa18.cc", "https://manhwa18.cc", listOf("en", "ko", "all"), isNsfw = true, className = "Manhwa18CcFactory", pkgName = "manhwa18cc", overrideVersionCode = 4),
|
||||||
MultiLang("Olympus Scanlation", "https://olympusscanlation.com", listOf("es", "pt-BR")),
|
|
||||||
MultiLang("Reaper Scans", "https://reaperscans.com", listOf("fr", "tr"), className = "ReaperScansFactory", pkgName = "reaperscans", overrideVersionCode = 12),
|
MultiLang("Reaper Scans", "https://reaperscans.com", listOf("fr", "tr"), className = "ReaperScansFactory", pkgName = "reaperscans", overrideVersionCode = 12),
|
||||||
SingleLang("1st Kiss Manga.love", "https://1stkissmanga.love", "en", className = "FirstKissMangaLove", overrideVersionCode = 2),
|
SingleLang("1st Kiss Manga.love", "https://1stkissmanga.love", "en", className = "FirstKissMangaLove", overrideVersionCode = 2),
|
||||||
SingleLang("1st Kiss Manhua", "https://1stkissmanhua.com", "en", className = "FirstKissManhua", overrideVersionCode = 4),
|
SingleLang("1st Kiss Manhua", "https://1stkissmanhua.com", "en", className = "FirstKissManhua", overrideVersionCode = 4),
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<manifest package="eu.kanade.tachiyomi.extension" />
|
|
@ -0,0 +1,13 @@
|
||||||
|
apply plugin: 'com.android.application'
|
||||||
|
apply plugin: 'kotlin-android'
|
||||||
|
apply plugin: 'kotlinx-serialization'
|
||||||
|
|
||||||
|
|
||||||
|
ext {
|
||||||
|
extName = 'Olympus Scanlation'
|
||||||
|
pkgNameSuffix = 'es.olympusscanlation'
|
||||||
|
extClass = '.OlympusScanlation'
|
||||||
|
extVersionCode = 2
|
||||||
|
}
|
||||||
|
|
||||||
|
apply from: "$rootDir/common.gradle"
|
Before Width: | Height: | Size: 5.0 KiB After Width: | Height: | Size: 5.0 KiB |
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 2.5 KiB |
Before Width: | Height: | Size: 7.8 KiB After Width: | Height: | Size: 7.8 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |
Before Width: | Height: | Size: 118 KiB After Width: | Height: | Size: 118 KiB |
|
@ -0,0 +1,165 @@
|
||||||
|
package eu.kanade.tachiyomi.extension.es.olympusscanlation
|
||||||
|
|
||||||
|
import eu.kanade.tachiyomi.extension.es.olympusscanlation.dto.OlympusScanlationDto.ChapterDto
|
||||||
|
import eu.kanade.tachiyomi.extension.es.olympusscanlation.dto.OlympusScanlationDto.MangaDetailDto
|
||||||
|
import eu.kanade.tachiyomi.extension.es.olympusscanlation.dto.OlympusScanlationDto.MangaDto
|
||||||
|
import eu.kanade.tachiyomi.extension.es.olympusscanlation.dto.OlympusScanlationDto.PayloadChapterDto
|
||||||
|
import eu.kanade.tachiyomi.extension.es.olympusscanlation.dto.OlympusScanlationDto.PayloadHomeDto
|
||||||
|
import eu.kanade.tachiyomi.extension.es.olympusscanlation.dto.OlympusScanlationDto.PayloadMangaDto
|
||||||
|
import eu.kanade.tachiyomi.extension.es.olympusscanlation.dto.OlympusScanlationDto.PayloadPagesDto
|
||||||
|
import eu.kanade.tachiyomi.network.GET
|
||||||
|
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.decodeFromString
|
||||||
|
import kotlinx.serialization.json.Json
|
||||||
|
import okhttp3.HttpUrl.Companion.toHttpUrl
|
||||||
|
import okhttp3.Request
|
||||||
|
import okhttp3.Response
|
||||||
|
import uy.kohesive.injekt.injectLazy
|
||||||
|
class OlympusScanlation : HttpSource() {
|
||||||
|
|
||||||
|
override val baseUrl: String = "https://olympusscans.com"
|
||||||
|
private val apiBaseUrl: String = "https://dashboard.olympusscans.com"
|
||||||
|
override val lang: String = "es"
|
||||||
|
override val name: String = "Olympus Scanlation"
|
||||||
|
override val versionId = 2
|
||||||
|
override val supportsLatest: Boolean = true
|
||||||
|
private val json: Json by injectLazy()
|
||||||
|
|
||||||
|
// Search
|
||||||
|
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
|
||||||
|
val apiUrl = "$apiBaseUrl/api/search".toHttpUrl().newBuilder()
|
||||||
|
.addQueryParameter("name", query)
|
||||||
|
.build()
|
||||||
|
return GET(apiUrl, headers)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun searchMangaParse(response: Response): MangasPage {
|
||||||
|
val result = json.decodeFromString<PayloadMangaDto>(response.body.string())
|
||||||
|
val mangaList = result.data.map {
|
||||||
|
SManga.create().apply {
|
||||||
|
url = "/series/comic-${it.slug}"
|
||||||
|
title = it.name
|
||||||
|
thumbnail_url = it.cover
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return MangasPage(mangaList, hasNextPage = false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Latest
|
||||||
|
override fun latestUpdatesRequest(page: Int): Request = popularMangaRequest(1)
|
||||||
|
override fun latestUpdatesParse(response: Response): MangasPage {
|
||||||
|
val result = json.decodeFromString<PayloadHomeDto>(response.body.string())
|
||||||
|
val mangaList = result.data.new_chapters.map {
|
||||||
|
SManga.create().apply {
|
||||||
|
url = "/series/comic-${it.slug}"
|
||||||
|
title = it.name
|
||||||
|
thumbnail_url = it.cover
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return MangasPage(mangaList, hasNextPage = false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Details
|
||||||
|
override fun mangaDetailsParse(response: Response): SManga {
|
||||||
|
val slug = response.request.url
|
||||||
|
.toString()
|
||||||
|
.substringAfter("/series/comic-")
|
||||||
|
.substringBefore("/chapters")
|
||||||
|
val urla = "$apiBaseUrl/api/series/$slug?type=comic"
|
||||||
|
val newRequest = GET(url = urla, headers = headers)
|
||||||
|
val newResponse = client.newCall(newRequest).execute()
|
||||||
|
val result = json.decodeFromString<MangaDetailDto>(newResponse.body.string())
|
||||||
|
return SManga.create().apply {
|
||||||
|
url = "/series/comic-$slug"
|
||||||
|
title = result.data.name
|
||||||
|
thumbnail_url = result.data.cover
|
||||||
|
description = result.data.summary
|
||||||
|
}
|
||||||
|
}
|
||||||
|
override fun imageUrlParse(response: Response): String = throw Exception("Not used")
|
||||||
|
|
||||||
|
// Chapters
|
||||||
|
|
||||||
|
override fun chapterListRequest(manga: SManga): Request {
|
||||||
|
return paginatedChapterListRequest(
|
||||||
|
manga.url
|
||||||
|
.substringAfter("/series/comic-")
|
||||||
|
.substringBefore("/chapters"),
|
||||||
|
1,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun paginatedChapterListRequest(mangaUrl: String, page: Int): Request {
|
||||||
|
return GET(
|
||||||
|
url = "$apiBaseUrl/api/series/$mangaUrl/chapters?page=$page&direction=desc&type=comic",
|
||||||
|
headers = headers,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun chapterListParse(response: Response): List<SChapter> {
|
||||||
|
val slug = response.request.url
|
||||||
|
.toString()
|
||||||
|
.substringAfter("/series/")
|
||||||
|
.substringBefore("/chapters")
|
||||||
|
var data = json.decodeFromString<PayloadChapterDto>(response.body.string())
|
||||||
|
var resultSize = data.data.size
|
||||||
|
var page = 2
|
||||||
|
while (data.meta.total > resultSize) {
|
||||||
|
val newRequest = paginatedChapterListRequest("$slug", page)
|
||||||
|
val newResponse = client.newCall(newRequest).execute()
|
||||||
|
var newData = json.decodeFromString<PayloadChapterDto>(newResponse.body.string())
|
||||||
|
data.data += newData.data
|
||||||
|
resultSize += newData.data.size
|
||||||
|
page += 1
|
||||||
|
}
|
||||||
|
return data.data.map { chap -> chapterFromObject(chap, slug) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun chapterFromObject(chapter: ChapterDto, slug: String) = SChapter.create().apply {
|
||||||
|
url = "/capitulo/${chapter.id}/comic-$slug"
|
||||||
|
name = "Capitulo ${chapter.name}"
|
||||||
|
chapter_number = chapter.name.toFloatOrNull() ?: -1f
|
||||||
|
}
|
||||||
|
// Pages
|
||||||
|
|
||||||
|
override fun pageListRequest(chapter: SChapter): Request {
|
||||||
|
var id = chapter.url
|
||||||
|
.substringAfter("/capitulo/")
|
||||||
|
.substringBefore("/chapters")
|
||||||
|
.substringBefore("/comic")
|
||||||
|
val slug = chapter.url
|
||||||
|
.substringAfter("comic-")
|
||||||
|
.substringBefore("/chapters")
|
||||||
|
.substringBefore("/comic")
|
||||||
|
return GET("$apiBaseUrl/api/series/$slug/chapters/$id?type=comic")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun pageListParse(response: Response): List<Page> =
|
||||||
|
json.decodeFromString<PayloadPagesDto>(response.body.string()).chapter.pages.mapIndexed { i, img ->
|
||||||
|
Page(i, "", img)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Popular
|
||||||
|
override fun popularMangaParse(response: Response): MangasPage {
|
||||||
|
val result = json.decodeFromString<PayloadHomeDto>(response.body.string())
|
||||||
|
val resultMangaList = json.decodeFromString<List<MangaDto>>(result.data.popular_comics)
|
||||||
|
val mangaList = resultMangaList.map {
|
||||||
|
SManga.create().apply {
|
||||||
|
url = "/series/comic-${it.slug}"
|
||||||
|
title = it.name
|
||||||
|
thumbnail_url = it.cover
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return MangasPage(mangaList, hasNextPage = false)
|
||||||
|
}
|
||||||
|
override fun popularMangaRequest(page: Int): Request {
|
||||||
|
val apiUrl = "$apiBaseUrl/api/home".toHttpUrl().newBuilder()
|
||||||
|
.build()
|
||||||
|
return GET(apiUrl, headers)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,48 @@
|
||||||
|
package eu.kanade.tachiyomi.extension.es.olympusscanlation.dto
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
@Serializable
|
||||||
|
object OlympusScanlationDto {
|
||||||
|
@Serializable
|
||||||
|
data class ChapterDto(val id: Int, val name: String)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class MangaDto(
|
||||||
|
val id: Int,
|
||||||
|
val name: String,
|
||||||
|
val slug: String?,
|
||||||
|
val cover: String?,
|
||||||
|
val type: String?,
|
||||||
|
val summary: String?,
|
||||||
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class MangaDetailDto(
|
||||||
|
var data: MangaDto,
|
||||||
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class MetaDto(val total: Int)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class PageDto(val pages: List<String>)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class PayloadChapterDto(var data: List<ChapterDto>, val meta: MetaDto)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class PayloadMangaDto(val data: List<MangaDto>)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class PayloadPagesDto(val chapter: PageDto)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class HomeDto(
|
||||||
|
val popular_comics: String,
|
||||||
|
val new_chapters: List<MangaDto>,
|
||||||
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class PayloadHomeDto(
|
||||||
|
val data: HomeDto,
|
||||||
|
)
|
||||||
|
}
|