diff --git a/multisrc/overrides/madara/olympusscanlation/src/OlympusScanlationFactory.kt b/multisrc/overrides/madara/olympusscanlation/src/OlympusScanlationFactory.kt deleted file mode 100644 index 9c00dfaf7..000000000 --- a/multisrc/overrides/madara/olympusscanlation/src/OlympusScanlationFactory.kt +++ /dev/null @@ -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() -} diff --git a/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/madara/MadaraGenerator.kt b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/madara/MadaraGenerator.kt index 178f32c3c..73ff11a6c 100644 --- a/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/madara/MadaraGenerator.kt +++ b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/madara/MadaraGenerator.kt @@ -16,7 +16,6 @@ class MadaraGenerator : ThemeSourceGenerator { 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("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), 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), diff --git a/src/es/olympusscanlation/AndroidManifest.xml b/src/es/olympusscanlation/AndroidManifest.xml new file mode 100644 index 000000000..b4571bfa8 --- /dev/null +++ b/src/es/olympusscanlation/AndroidManifest.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/src/es/olympusscanlation/build.gradle b/src/es/olympusscanlation/build.gradle new file mode 100644 index 000000000..0d79d83f8 --- /dev/null +++ b/src/es/olympusscanlation/build.gradle @@ -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" \ No newline at end of file diff --git a/multisrc/overrides/madara/olympusscanlation/res/mipmap-hdpi/ic_launcher.png b/src/es/olympusscanlation/res/mipmap-hdpi/ic_launcher.png similarity index 100% rename from multisrc/overrides/madara/olympusscanlation/res/mipmap-hdpi/ic_launcher.png rename to src/es/olympusscanlation/res/mipmap-hdpi/ic_launcher.png diff --git a/multisrc/overrides/madara/olympusscanlation/res/mipmap-mdpi/ic_launcher.png b/src/es/olympusscanlation/res/mipmap-mdpi/ic_launcher.png similarity index 100% rename from multisrc/overrides/madara/olympusscanlation/res/mipmap-mdpi/ic_launcher.png rename to src/es/olympusscanlation/res/mipmap-mdpi/ic_launcher.png diff --git a/multisrc/overrides/madara/olympusscanlation/res/mipmap-xhdpi/ic_launcher.png b/src/es/olympusscanlation/res/mipmap-xhdpi/ic_launcher.png similarity index 100% rename from multisrc/overrides/madara/olympusscanlation/res/mipmap-xhdpi/ic_launcher.png rename to src/es/olympusscanlation/res/mipmap-xhdpi/ic_launcher.png diff --git a/multisrc/overrides/madara/olympusscanlation/res/mipmap-xxhdpi/ic_launcher.png b/src/es/olympusscanlation/res/mipmap-xxhdpi/ic_launcher.png similarity index 100% rename from multisrc/overrides/madara/olympusscanlation/res/mipmap-xxhdpi/ic_launcher.png rename to src/es/olympusscanlation/res/mipmap-xxhdpi/ic_launcher.png diff --git a/multisrc/overrides/madara/olympusscanlation/res/mipmap-xxxhdpi/ic_launcher.png b/src/es/olympusscanlation/res/mipmap-xxxhdpi/ic_launcher.png similarity index 100% rename from multisrc/overrides/madara/olympusscanlation/res/mipmap-xxxhdpi/ic_launcher.png rename to src/es/olympusscanlation/res/mipmap-xxxhdpi/ic_launcher.png diff --git a/multisrc/overrides/madara/olympusscanlation/res/web_hi_res_512.png b/src/es/olympusscanlation/res/web_hi_res_512.png similarity index 100% rename from multisrc/overrides/madara/olympusscanlation/res/web_hi_res_512.png rename to src/es/olympusscanlation/res/web_hi_res_512.png diff --git a/src/es/olympusscanlation/src/eu/kanade/tachiyomi/extension/es/olympusscanlation/OlympusScanlation.kt b/src/es/olympusscanlation/src/eu/kanade/tachiyomi/extension/es/olympusscanlation/OlympusScanlation.kt new file mode 100644 index 000000000..fa2bde9ea --- /dev/null +++ b/src/es/olympusscanlation/src/eu/kanade/tachiyomi/extension/es/olympusscanlation/OlympusScanlation.kt @@ -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(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(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(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 { + val slug = response.request.url + .toString() + .substringAfter("/series/") + .substringBefore("/chapters") + var data = json.decodeFromString(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(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 = + json.decodeFromString(response.body.string()).chapter.pages.mapIndexed { i, img -> + Page(i, "", img) + } + + // Popular + override fun popularMangaParse(response: Response): MangasPage { + val result = json.decodeFromString(response.body.string()) + val resultMangaList = json.decodeFromString>(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) + } +} diff --git a/src/es/olympusscanlation/src/eu/kanade/tachiyomi/extension/es/olympusscanlation/dto/OlympusScanlationDto.kt b/src/es/olympusscanlation/src/eu/kanade/tachiyomi/extension/es/olympusscanlation/dto/OlympusScanlationDto.kt new file mode 100644 index 000000000..6e73d9811 --- /dev/null +++ b/src/es/olympusscanlation/src/eu/kanade/tachiyomi/extension/es/olympusscanlation/dto/OlympusScanlationDto.kt @@ -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) + + @Serializable + data class PayloadChapterDto(var data: List, val meta: MetaDto) + + @Serializable + data class PayloadMangaDto(val data: List) + + @Serializable + data class PayloadPagesDto(val chapter: PageDto) + + @Serializable + data class HomeDto( + val popular_comics: String, + val new_chapters: List, + ) + + @Serializable + data class PayloadHomeDto( + val data: HomeDto, + ) +}