OlympusScanlation: Update domain and minor refactor (#1300)

* Update domain and other things

* Change popular endpoint

* fetchFilters in getFilterList

* Make SManga and SChapter in DTO

* I just want to update the domain

* Move attempts to finally block

* idk

* update

---------

Co-authored-by: stevenyomi <95685115+stevenyomi@users.noreply.github.com>
This commit is contained in:
bapeey 2024-02-16 23:12:23 -05:00 committed by GitHub
parent edecdb4e8d
commit 5901557544
3 changed files with 129 additions and 119 deletions

View File

@ -1,7 +1,7 @@
ext { ext {
extName = 'Olympus Scanlation' extName = 'Olympus Scanlation'
extClass = '.OlympusScanlation' extClass = '.OlympusScanlation'
extVersionCode = 6 extVersionCode = 7
} }
apply from: "$rootDir/common.gradle" apply from: "$rootDir/common.gradle"

View File

@ -18,13 +18,14 @@ import uy.kohesive.injekt.injectLazy
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.Locale import java.util.Locale
import java.util.TimeZone import java.util.TimeZone
import kotlin.concurrent.thread
class OlympusScanlation : HttpSource() { class OlympusScanlation : HttpSource() {
override val versionId = 2 override val versionId = 2
override val baseUrl: String = "https://olympusvisor.com" override val baseUrl: String = "https://visorolym.com"
private val apiBaseUrl: String = "https://dashboard.olympusvisor.com" private val apiBaseUrl: String = "https://dashboard.visorolym.com"
override val lang: String = "es" override val lang: String = "es"
override val name: String = "Olympus Scanlation" override val name: String = "Olympus Scanlation"
@ -37,27 +38,21 @@ class OlympusScanlation : HttpSource() {
.build() .build()
private val json: Json by injectLazy() private val json: Json by injectLazy()
private val dateFormat = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSSSS'Z'", Locale.US).apply { private val dateFormat = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSSSS'Z'", Locale.US).apply {
timeZone = TimeZone.getTimeZone("UTC") timeZone = TimeZone.getTimeZone("UTC")
} }
override fun popularMangaRequest(page: Int): Request { override fun popularMangaRequest(page: Int): Request {
val apiUrl = "$apiBaseUrl/api/series?page=1&direction=asc&type=comic".toHttpUrl().newBuilder() val apiUrl = "$apiBaseUrl/api/sf/home".toHttpUrl().newBuilder()
.build() .build()
return GET(apiUrl, headers) return GET(apiUrl, headers)
} }
override fun popularMangaParse(response: Response): MangasPage { override fun popularMangaParse(response: Response): MangasPage {
runCatching { fetchFilters() } val result = json.decodeFromString<PayloadHomeDto>(response.body.string())
val result = json.decodeFromString<PayloadSeriesDto>(response.body.string()) val popularJson = json.decodeFromString<List<MangaDto>>(result.data.popularComics)
val resultMangaList = json.decodeFromString<List<MangaDto>>(result.data.recommended_series) val mangaList = popularJson.filter { it.type == "comic" }.map { it.toSManga() }
val mangaList = resultMangaList.filter { it.type == "comic" }.map {
SManga.create().apply {
url = "/series/comic-${it.slug}"
title = it.name
thumbnail_url = it.cover
}
}
return MangasPage(mangaList, hasNextPage = false) return MangasPage(mangaList, hasNextPage = false)
} }
@ -68,15 +63,8 @@ class OlympusScanlation : HttpSource() {
} }
override fun latestUpdatesParse(response: Response): MangasPage { override fun latestUpdatesParse(response: Response): MangasPage {
runCatching { fetchFilters() }
val result = json.decodeFromString<NewChaptersDto>(response.body.string()) val result = json.decodeFromString<NewChaptersDto>(response.body.string())
val mangaList = result.data.filter { it.type == "comic" }.map { val mangaList = result.data.filter { it.type == "comic" }.map { it.toSManga() }
SManga.create().apply {
url = "/series/comic-${it.slug}"
title = it.name
thumbnail_url = it.cover
}
}
val hasNextPage = result.current_page < result.last_page val hasNextPage = result.current_page < result.last_page
return MangasPage(mangaList, hasNextPage) return MangasPage(mangaList, hasNextPage)
} }
@ -118,27 +106,14 @@ class OlympusScanlation : HttpSource() {
} }
override fun searchMangaParse(response: Response): MangasPage { override fun searchMangaParse(response: Response): MangasPage {
runCatching { fetchFilters() }
if (response.request.url.toString().startsWith("$apiBaseUrl/api/search")) { if (response.request.url.toString().startsWith("$apiBaseUrl/api/search")) {
val result = json.decodeFromString<PayloadMangaDto>(response.body.string()) val result = json.decodeFromString<PayloadMangaDto>(response.body.string())
val mangaList = result.data.filter { it.type == "comic" }.map { val mangaList = result.data.filter { it.type == "comic" }.map { it.toSManga() }
SManga.create().apply {
url = "/series/comic-${it.slug}"
title = it.name
thumbnail_url = it.cover
}
}
return MangasPage(mangaList, hasNextPage = false) return MangasPage(mangaList, hasNextPage = false)
} }
val result = json.decodeFromString<PayloadSeriesDto>(response.body.string()) val result = json.decodeFromString<PayloadSeriesDto>(response.body.string())
val mangaList = result.data.series.data.map { val mangaList = result.data.series.data.map { it.toSManga() }
SManga.create().apply {
url = "/series/comic-${it.slug}"
title = it.name
thumbnail_url = it.cover
}
}
val hasNextPage = result.data.series.current_page < result.data.series.last_page val hasNextPage = result.data.series.current_page < result.data.series.last_page
return MangasPage(mangaList, hasNextPage) return MangasPage(mangaList, hasNextPage)
} }
@ -152,14 +127,7 @@ class OlympusScanlation : HttpSource() {
val newRequest = GET(url = apiUrl, headers = headers) val newRequest = GET(url = apiUrl, headers = headers)
val newResponse = client.newCall(newRequest).execute() val newResponse = client.newCall(newRequest).execute()
val result = json.decodeFromString<MangaDetailDto>(newResponse.body.string()) val result = json.decodeFromString<MangaDetailDto>(newResponse.body.string())
return SManga.create().apply { return result.data.toSMangaDetails()
url = "/series/comic-$slug"
title = result.data.name
thumbnail_url = result.data.cover
description = result.data.summary
status = parseStatus(result.data.status?.id)
genre = result.data.genres?.joinToString { it.name.trim() }
}
} }
override fun getChapterUrl(chapter: SChapter): String = baseUrl + chapter.url override fun getChapterUrl(chapter: SChapter): String = baseUrl + chapter.url
@ -196,14 +164,7 @@ class OlympusScanlation : HttpSource() {
resultSize += newData.data.size resultSize += newData.data.size
page += 1 page += 1
} }
return data.data.map { chap -> chapterFromObject(chap, slug) } return data.data.map { it.toSChapter(slug, dateFormat) }
}
private fun chapterFromObject(chapter: ChapterDto, slug: String) = SChapter.create().apply {
url = "/capitulo/${chapter.id}/comic-$slug"
name = "Capitulo ${chapter.name}"
date_upload = runCatching { dateFormat.parse(chapter.date)?.time }
.getOrNull() ?: 0L
} }
override fun pageListRequest(chapter: SChapter): Request { override fun pageListRequest(chapter: SChapter): Request {
@ -220,20 +181,12 @@ class OlympusScanlation : HttpSource() {
override fun pageListParse(response: Response): List<Page> { override fun pageListParse(response: Response): List<Page> {
return json.decodeFromString<PayloadPagesDto>(response.body.string()).chapter.pages.mapIndexed { i, img -> return json.decodeFromString<PayloadPagesDto>(response.body.string()).chapter.pages.mapIndexed { i, img ->
Page(i, "", img) Page(i, imageUrl = img)
} }
} }
override fun imageUrlParse(response: Response): String = throw UnsupportedOperationException() override fun imageUrlParse(response: Response): String = throw UnsupportedOperationException()
private fun parseStatus(statusId: Int?) = when (statusId) {
1 -> SManga.ONGOING
3 -> SManga.ON_HIATUS
4 -> SManga.COMPLETED
5 -> SManga.CANCELLED
else -> SManga.UNKNOWN
}
private class SortFilter : Filter.Sort( private class SortFilter : Filter.Sort(
"Ordenar", "Ordenar",
arrayOf("Alfabético"), arrayOf("Alfabético"),
@ -257,13 +210,14 @@ class OlympusScanlation : HttpSource() {
) )
override fun getFilterList(): FilterList { override fun getFilterList(): FilterList {
fetchFilters()
val filters = mutableListOf<Filter<*>>( val filters = mutableListOf<Filter<*>>(
Filter.Header("Los filtros no funcionan en la búsqueda por texto"), Filter.Header("Los filtros no funcionan en la búsqueda por texto"),
Filter.Separator(), Filter.Separator(),
SortFilter(), SortFilter(),
) )
if (genresList.isNotEmpty() || statusesList.isNotEmpty()) { if (filtersState == FiltersState.FETCHED) {
filters += listOf( filters += listOf(
Filter.Separator(), Filter.Separator(),
Filter.Header("Filtrar por género"), Filter.Header("Filtrar por género"),
@ -287,20 +241,25 @@ class OlympusScanlation : HttpSource() {
private var genresList: List<Pair<String, Int>> = emptyList() private var genresList: List<Pair<String, Int>> = emptyList()
private var statusesList: List<Pair<String, Int>> = emptyList() private var statusesList: List<Pair<String, Int>> = emptyList()
private var fetchFiltersAttemps = 0 private var fetchFiltersAttempts = 0
private var fetchFiltersFailed = false private var filtersState = FiltersState.NOT_FETCHED
private fun fetchFilters() { private fun fetchFilters() {
if (fetchFiltersAttemps <= 3 && ((genresList.isEmpty() && statusesList.isEmpty()) || fetchFiltersFailed)) { if (filtersState != FiltersState.NOT_FETCHED || fetchFiltersAttempts >= 3) return
val filters = runCatching { filtersState = FiltersState.FETCHING
fetchFiltersAttempts++
thread {
try {
val response = client.newCall(GET("$apiBaseUrl/api/genres-statuses", headers)).execute() val response = client.newCall(GET("$apiBaseUrl/api/genres-statuses", headers)).execute()
json.decodeFromString<GenresStatusesDto>(response.body.string()) val filters = json.decodeFromString<GenresStatusesDto>(response.body.string())
}
fetchFiltersFailed = filters.isFailure genresList = filters.genres.map { it.name.trim() to it.id }
genresList = filters.getOrNull()?.genres?.map { it.name.trim() to it.id } ?: emptyList() statusesList = filters.statuses.map { it.name.trim() to it.id }
statusesList = filters.getOrNull()?.statuses?.map { it.name.trim() to it.id } ?: emptyList()
fetchFiltersAttemps++ filtersState = FiltersState.FETCHED
} catch (e: Throwable) {
filtersState = FiltersState.NOT_FETCHED
}
} }
} }
@ -308,4 +267,6 @@ class OlympusScanlation : HttpSource() {
Filter.Select<String>(displayName, vals.map { it.first }.toTypedArray()) { Filter.Select<String>(displayName, vals.map { it.first }.toTypedArray()) {
fun toUriPart() = vals[state].second fun toUriPart() = vals[state].second
} }
private enum class FiltersState { NOT_FETCHED, FETCHING, FETCHED }
} }

View File

@ -1,93 +1,142 @@
package eu.kanade.tachiyomi.extension.es.olympusscanlation package eu.kanade.tachiyomi.extension.es.olympusscanlation
import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import java.text.ParseException
import java.text.SimpleDateFormat
@Serializable @Serializable
data class PayloadSeriesDto(val data: PayloadSeriesDataDto) class PayloadHomeDto(
val data: HomeDto,
@Serializable
data class PayloadSeriesDataDto(
val series: SeriesDto,
val recommended_series: String,
) )
@Serializable @Serializable
data class SeriesDto( class HomeDto(
@SerialName("popular_comics") val popularComics: String,
)
@Serializable
class PayloadSeriesDto(val data: PayloadSeriesDataDto)
@Serializable
class PayloadSeriesDataDto(
val series: SeriesDto,
)
@Serializable
class SeriesDto(
val current_page: Int, val current_page: Int,
val data: List<MangaDto>, val data: List<MangaDto>,
val last_page: Int, val last_page: Int,
) )
@Serializable @Serializable
data class PayloadMangaDto(val data: List<MangaDto>) class PayloadMangaDto(val data: List<MangaDto>)
@Serializable @Serializable
data class MangaDto( class MangaDto(
val id: Int, private val name: String,
val name: String, private val slug: String,
val slug: String, private val cover: String? = null,
val cover: String? = null,
val type: String? = null, val type: String? = null,
val summary: String? = null, private val summary: String? = null,
val status: MangaStatusDto? = null, private val status: MangaStatusDto? = null,
val genres: List<FilterDto>? = null, private val genres: List<FilterDto>? = null,
) ) {
fun toSManga() = SManga.create().apply {
title = name
url = "/series/comic-$slug"
thumbnail_url = cover
}
fun toSMangaDetails() = toSManga().apply {
description = summary
status = parseStatus()
genre = genres?.joinToString { it.name.trim() }
}
private fun parseStatus(): Int {
val status = this.status ?: return SManga.UNKNOWN
return when (status.id) {
1 -> SManga.ONGOING
3 -> SManga.ON_HIATUS
4 -> SManga.COMPLETED
5 -> SManga.CANCELLED
else -> SManga.UNKNOWN
}
}
}
@Serializable @Serializable
data class NewChaptersDto( class NewChaptersDto(
val data: List<LatestMangaDto>, val data: List<LatestMangaDto>,
val current_page: Int, val current_page: Int,
val last_page: Int, val last_page: Int,
) )
@Serializable @Serializable
data class LatestMangaDto( class LatestMangaDto(
val id: Int, private val name: String,
val name: String, private val slug: String,
val slug: String, private val cover: String? = null,
val cover: String? = null,
val type: String? = null, val type: String? = null,
) ) {
fun toSManga() = SManga.create().apply {
title = name
url = "/series/comic-$slug"
thumbnail_url = cover
}
}
@Serializable @Serializable
data class MangaDetailDto( class MangaDetailDto(
var data: MangaDto, var data: MangaDto,
) )
@Serializable @Serializable
data class PayloadChapterDto(var data: List<ChapterDto>, val meta: MetaDto) class PayloadChapterDto(var data: List<ChapterDto>, val meta: MetaDto)
@Serializable @Serializable
data class ChapterDto( class ChapterDto(
private val id: Int,
private val name: String,
@SerialName("published_at") private val date: String,
) {
fun toSChapter(mangaSlug: String, dateFormat: SimpleDateFormat) = SChapter.create().apply {
name = "Capitulo ${this@ChapterDto.name}"
url = "/capitulo/$id/comic-$mangaSlug"
date_upload = try {
dateFormat.parse(date)!!.time
} catch (e: ParseException) {
0L
}
}
}
@Serializable
class MetaDto(val total: Int)
@Serializable
class PayloadPagesDto(val chapter: PageDto)
@Serializable
class PageDto(val pages: List<String>)
@Serializable
class MangaStatusDto(
val id: Int, val id: Int,
val name: String,
@SerialName("published_at") val date: String,
) )
@Serializable @Serializable
data class MetaDto(val total: Int) class GenresStatusesDto(
@Serializable
data class PayloadPagesDto(val chapter: PageDto)
@Serializable
data class PageDto(val pages: List<String>)
@Serializable
data class MangaStatusDto(
val id: Int,
val name: String,
)
@Serializable
data class GenresStatusesDto(
val genres: List<FilterDto>, val genres: List<FilterDto>,
val statuses: List<FilterDto>, val statuses: List<FilterDto>,
) )
@Serializable @Serializable
data class FilterDto( class FilterDto(
val id: Int, val id: Int,
val name: String, val name: String,
) )