diff --git a/src/pt/yomumangas/build.gradle b/src/pt/yomumangas/build.gradle deleted file mode 100644 index b71b26aa2..000000000 --- a/src/pt/yomumangas/build.gradle +++ /dev/null @@ -1,8 +0,0 @@ -ext { - extName = 'Yomu Mangás' - extClass = '.YomuMangas' - extVersionCode = 3 - isNsfw = true -} - -apply from: "$rootDir/common.gradle" diff --git a/src/pt/yomumangas/res/mipmap-hdpi/ic_launcher.png b/src/pt/yomumangas/res/mipmap-hdpi/ic_launcher.png deleted file mode 100644 index 47013f348..000000000 Binary files a/src/pt/yomumangas/res/mipmap-hdpi/ic_launcher.png and /dev/null differ diff --git a/src/pt/yomumangas/res/mipmap-mdpi/ic_launcher.png b/src/pt/yomumangas/res/mipmap-mdpi/ic_launcher.png deleted file mode 100644 index dcd5ab52a..000000000 Binary files a/src/pt/yomumangas/res/mipmap-mdpi/ic_launcher.png and /dev/null differ diff --git a/src/pt/yomumangas/res/mipmap-xhdpi/ic_launcher.png b/src/pt/yomumangas/res/mipmap-xhdpi/ic_launcher.png deleted file mode 100644 index 1d3ce2077..000000000 Binary files a/src/pt/yomumangas/res/mipmap-xhdpi/ic_launcher.png and /dev/null differ diff --git a/src/pt/yomumangas/res/mipmap-xxhdpi/ic_launcher.png b/src/pt/yomumangas/res/mipmap-xxhdpi/ic_launcher.png deleted file mode 100644 index 321065398..000000000 Binary files a/src/pt/yomumangas/res/mipmap-xxhdpi/ic_launcher.png and /dev/null differ diff --git a/src/pt/yomumangas/res/mipmap-xxxhdpi/ic_launcher.png b/src/pt/yomumangas/res/mipmap-xxxhdpi/ic_launcher.png deleted file mode 100644 index 91ec7f3a6..000000000 Binary files a/src/pt/yomumangas/res/mipmap-xxxhdpi/ic_launcher.png and /dev/null differ diff --git a/src/pt/yomumangas/src/eu/kanade/tachiyomi/extension/pt/yomumangas/YomuMangas.kt b/src/pt/yomumangas/src/eu/kanade/tachiyomi/extension/pt/yomumangas/YomuMangas.kt deleted file mode 100644 index d112f0271..000000000 --- a/src/pt/yomumangas/src/eu/kanade/tachiyomi/extension/pt/yomumangas/YomuMangas.kt +++ /dev/null @@ -1,208 +0,0 @@ -package eu.kanade.tachiyomi.extension.pt.yomumangas - -import eu.kanade.tachiyomi.network.GET -import eu.kanade.tachiyomi.network.interceptor.rateLimitHost -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.Headers -import okhttp3.HttpUrl.Companion.toHttpUrl -import okhttp3.OkHttpClient -import okhttp3.Request -import okhttp3.Response -import rx.Observable -import uy.kohesive.injekt.injectLazy -import java.util.concurrent.TimeUnit - -class YomuMangas : HttpSource() { - - override val name = "Yomu Mangás" - - override val baseUrl = "https://yomumangas.com" - - override val lang = "pt-BR" - - override val supportsLatest = true - - override val client: OkHttpClient = network.cloudflareClient.newBuilder() - .rateLimitHost(baseUrl.toHttpUrl(), 1, 1, TimeUnit.SECONDS) - .rateLimitHost(API_URL.toHttpUrl(), 1, 1, TimeUnit.SECONDS) - .rateLimitHost(CDN_URL.toHttpUrl(), 1, 2, TimeUnit.SECONDS) - .build() - - private val json: Json by injectLazy() - - private val apiHeaders: Headers by lazy { apiHeadersBuilder().build() } - - override fun headersBuilder(): Headers.Builder = Headers.Builder() - .add("Origin", baseUrl) - .add("Referer", baseUrl) - - private fun apiHeadersBuilder(): Headers.Builder = headersBuilder() - .add("Accept", ACCEPT_JSON) - - override fun popularMangaRequest(page: Int): Request { - return GET("$API_URL/mangas/home", apiHeaders) - } - - override fun popularMangaParse(response: Response): MangasPage { - val result = response.parseAs() - val seriesList = result.votes.map(YomuMangasSeriesDto::toSManga) - - return MangasPage(seriesList, hasNextPage = false) - } - - override fun latestUpdatesRequest(page: Int) = popularMangaRequest(page) - - override fun latestUpdatesParse(response: Response): MangasPage { - val result = response.parseAs() - val seriesList = result.updates.map(YomuMangasSeriesDto::toSManga) - - return MangasPage(seriesList, hasNextPage = false) - } - - override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { - val apiUrl = "$API_URL/mangas/search".toHttpUrl().newBuilder() - .addQueryParameter("query", query) - .addQueryParameter("page", page.toString()) - - filters.filterIsInstance() - .forEach { it.addQueryParameter(apiUrl) } - - return GET(apiUrl.build(), apiHeaders) - } - - override fun searchMangaParse(response: Response): MangasPage { - val result = response.parseAs() - val seriesList = result.mangas.map(YomuMangasSeriesDto::toSManga) - - return MangasPage(seriesList, result.hasNextPage) - } - - override fun getMangaUrl(manga: SManga): String = baseUrl + manga.url - - override fun mangaDetailsRequest(manga: SManga): Request { - val id = manga.url - .substringAfter("/manga/") - .substringBefore("/") - - return GET("$API_URL/mangas/$id", apiHeaders) - } - - override fun mangaDetailsParse(response: Response): SManga { - return response.parseAs().manga.toSManga() - } - - override fun chapterListRequest(manga: SManga) = mangaDetailsRequest(manga) - - private fun chapterListApiRequest(mangaId: Int): Request { - return GET("$API_URL/mangas/$mangaId/chapters", apiHeaders) - } - - override fun chapterListParse(response: Response): List { - val series = response.parseAs().manga - - return client.newCall(chapterListApiRequest(series.id)).execute() - .parseAs().chapters - .sortedByDescending(YomuMangasChapterDto::chapter) - .map { it.toSChapter(series) } - } - - override fun getChapterUrl(chapter: SChapter): String = baseUrl + chapter.url - - override fun pageListRequest(chapter: SChapter): Request { - val urlParts = chapter.url.split("/", "#") - val seriesId = urlParts[2] - val chapterNumber = urlParts[6] - - return GET("$API_URL/mangas/$seriesId/chapters/$chapterNumber", apiHeaders) - } - - override fun pageListParse(response: Response): List { - return response.parseAs() - .chapter.images.orEmpty() - .mapIndexed { i, image -> Page(i, "", "$CDN_URL/${image.uri}") } - } - - override fun fetchImageUrl(page: Page): Observable = Observable.just(page.imageUrl!!) - - override fun imageUrlParse(response: Response): String = "" - - override fun imageRequest(page: Page): Request { - val newHeaders = headersBuilder() - .add("Accept", ACCEPT_IMAGE) - .build() - - return GET(page.imageUrl!!, newHeaders) - } - - override fun getFilterList(): FilterList = FilterList( - StatusFilter(getStatusList()), - TypeFilter(getTypesList()), - NsfwContentFilter(), - AdultContentFilter(), - GenreFilter(getGenresList()), - ) - - private fun getStatusList(): List = listOf( - Status("Todos", ""), - Status("Lançando", "RELEASING"), - Status("Finalizado", "FINISHED"), - Status("Cancelado", "CANCELLED"), - Status("Hiato", "HIATUS"), - Status("Não lançado", "NOT_YET_RELEASED"), - Status("Traduzindo", "TRANSLATING"), - Status("Desconhecido", "UNKNOWN"), - ) - - private fun getTypesList(): List = listOf( - Type("Todos", ""), - Type("Mangá", "MANGA"), - Type("Manhwa", "MANHWA"), - Type("Mangá em hiato", "MANGA_HIATUS"), - Type("Webcomic", "WEBCOMIC"), - Type("Webtoon", "WEBTOON"), - Type("Hentai", "HENTAI"), - Type("Doujinshi", "DOUJIN"), - Type("One-shot", "ONESHOT"), - ) - - private fun getGenresList(): List = listOf( - Genre("Ação", "1"), - Genre("Aventura", "8"), - Genre("Comédia", "2"), - Genre("Drama", "3"), - Genre("Ecchi", "15"), - Genre("Esportes", "14"), - Genre("Fantasia", "6"), - Genre("Hentai", "19"), - Genre("Horror", "4"), - Genre("Mahou shoujo", "18"), - Genre("Mecha", "17"), - Genre("Mistério", "7"), - Genre("Música", "16"), - Genre("Psicológico", "9"), - Genre("Romance", "13"), - Genre("Sci-fi", "11"), - Genre("Slice of life", "10"), - Genre("Sobrenatural", "5"), - Genre("Suspense", "12"), - ) - - private inline fun Response.parseAs(): T = use { - json.decodeFromString(it.body.string()) - } - - companion object { - private const val ACCEPT_IMAGE = "image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8" - private const val ACCEPT_JSON = "application/json" - - private const val API_URL = "https://api.yomumangas.com" - const val CDN_URL = "https://images.yomumangas.com" - } -} diff --git a/src/pt/yomumangas/src/eu/kanade/tachiyomi/extension/pt/yomumangas/YomuMangasDto.kt b/src/pt/yomumangas/src/eu/kanade/tachiyomi/extension/pt/yomumangas/YomuMangasDto.kt deleted file mode 100644 index e742993d8..000000000 --- a/src/pt/yomumangas/src/eu/kanade/tachiyomi/extension/pt/yomumangas/YomuMangasDto.kt +++ /dev/null @@ -1,96 +0,0 @@ -package eu.kanade.tachiyomi.extension.pt.yomumangas - -import eu.kanade.tachiyomi.source.model.SChapter -import eu.kanade.tachiyomi.source.model.SManga -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable -import java.text.SimpleDateFormat -import java.util.Locale - -@Serializable -data class YomuMangasHomeDto( - val updates: List = emptyList(), - val votes: List = emptyList(), -) - -@Serializable -data class YomuMangasSearchDto( - val mangas: List = emptyList(), - val page: Int, - val pages: Int, -) { - - val hasNextPage: Boolean - get() = page < pages -} - -@Serializable -data class YomuMangasDetailsDto(val manga: YomuMangasSeriesDto) - -@Serializable -data class YomuMangasSeriesDto( - val id: Int, - val slug: String, - val title: String, - val cover: String? = null, - val status: String, - val authors: List? = emptyList(), - val artists: List? = emptyList(), - val genres: List? = emptyList(), - val description: String? = null, -) { - - fun toSManga(): SManga = SManga.create().apply { - title = this@YomuMangasSeriesDto.title - author = authors.orEmpty().joinToString { it.trim() } - artist = artists.orEmpty().joinToString { it.trim() } - genre = genres.orEmpty() - .sortedBy { it.name } - .joinToString { it.name.trim() } - description = this@YomuMangasSeriesDto.description?.trim() - status = when (this@YomuMangasSeriesDto.status) { - "RELEASING" -> SManga.ONGOING - "FINISHED" -> SManga.COMPLETED - "HIATUS" -> SManga.ON_HIATUS - "CANCELLED" -> SManga.CANCELLED - "TRANSLATING" -> SManga.PUBLISHING_FINISHED - else -> SManga.UNKNOWN - } - thumbnail_url = cover?.let { "${YomuMangas.CDN_URL}/$it" } - url = "/manga/$id/$slug" - } -} - -@Serializable -data class YomuMangasGenreDto(val name: String) - -@Serializable -data class YomuMangasChaptersDto(val chapters: List = emptyList()) - -@Serializable -data class YomuMangasChapterDto( - val id: Int, - val chapter: Float, - @SerialName("uploaded_at") val uploadedAt: String, - val images: List? = emptyList(), -) { - - fun toSChapter(series: YomuMangasSeriesDto): SChapter = SChapter.create().apply { - name = "Capítulo ${chapter.toString().removeSuffix(".0")}" - date_upload = runCatching { DATE_FORMATTER.parse(uploadedAt)?.time } - .getOrNull() ?: 0L - url = "/manga/${series.id}/${series.slug}/chapter/$id#$chapter" - } - - companion object { - private val DATE_FORMATTER by lazy { - SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.US) - } - } -} - -@Serializable -data class YomuMangasChapterDetailsDto(val chapter: YomuMangasChapterDto) - -@Serializable -data class YomuMangasImageDto(val uri: String) diff --git a/src/pt/yomumangas/src/eu/kanade/tachiyomi/extension/pt/yomumangas/YomuMangasFilters.kt b/src/pt/yomumangas/src/eu/kanade/tachiyomi/extension/pt/yomumangas/YomuMangasFilters.kt deleted file mode 100644 index 2bd95683b..000000000 --- a/src/pt/yomumangas/src/eu/kanade/tachiyomi/extension/pt/yomumangas/YomuMangasFilters.kt +++ /dev/null @@ -1,73 +0,0 @@ -package eu.kanade.tachiyomi.extension.pt.yomumangas - -import eu.kanade.tachiyomi.source.model.Filter -import okhttp3.HttpUrl - -interface UrlQueryFilter { - fun addQueryParameter(url: HttpUrl.Builder) -} - -class NsfwContentFilter : Filter.CheckBox("Conteúdo NSFW"), UrlQueryFilter { - override fun addQueryParameter(url: HttpUrl.Builder) { - if (state) { - url.addQueryParameter("nsfw", "true") - } - } -} - -class AdultContentFilter : Filter.CheckBox("Conteúdo adulto"), UrlQueryFilter { - override fun addQueryParameter(url: HttpUrl.Builder) { - if (state) { - url.addQueryParameter("hentai", "true") - } - } -} - -open class EnhancedSelect(name: String, values: Array) : Filter.Select(name, values) { - val selected: T - get() = values[state] -} - -data class Status(val name: String, val value: String) { - override fun toString() = name -} - -class StatusFilter(statusList: List) : - EnhancedSelect("Status", statusList.toTypedArray()), - UrlQueryFilter { - - override fun addQueryParameter(url: HttpUrl.Builder) { - if (state > 0) { - url.addQueryParameter("status", selected.value) - } - } -} - -data class Type(val name: String, val value: String) { - override fun toString() = name -} - -class TypeFilter(typesList: List) : - EnhancedSelect("Tipo", typesList.toTypedArray()), - UrlQueryFilter { - - override fun addQueryParameter(url: HttpUrl.Builder) { - if (state > 0) { - url.addQueryParameter("type", selected.value) - } - } -} - -class Genre(name: String, val id: String) : Filter.CheckBox(name) { - override fun toString() = name -} - -class GenreFilter(genres: List) : - Filter.Group("Gêneros", genres), - UrlQueryFilter { - - override fun addQueryParameter(url: HttpUrl.Builder) { - state.filter(Genre::state) - .forEach { url.addQueryParameter("genres[]", it.id) } - } -}