parent
748b8c4b11
commit
801106dee5
8
src/pt/geasscomics/build.gradle
Normal file
8
src/pt/geasscomics/build.gradle
Normal file
@ -0,0 +1,8 @@
|
||||
ext {
|
||||
extName = 'Geass Comics'
|
||||
extClass = '.GeassComics'
|
||||
extVersionCode = 1
|
||||
isNsfw = true
|
||||
}
|
||||
|
||||
apply from: "$rootDir/common.gradle"
|
BIN
src/pt/geasscomics/res/mipmap-hdpi/ic_launcher.png
Normal file
BIN
src/pt/geasscomics/res/mipmap-hdpi/ic_launcher.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.8 KiB |
BIN
src/pt/geasscomics/res/mipmap-mdpi/ic_launcher.png
Normal file
BIN
src/pt/geasscomics/res/mipmap-mdpi/ic_launcher.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.6 KiB |
BIN
src/pt/geasscomics/res/mipmap-xhdpi/ic_launcher.png
Normal file
BIN
src/pt/geasscomics/res/mipmap-xhdpi/ic_launcher.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.4 KiB |
BIN
src/pt/geasscomics/res/mipmap-xxhdpi/ic_launcher.png
Normal file
BIN
src/pt/geasscomics/res/mipmap-xxhdpi/ic_launcher.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.1 KiB |
BIN
src/pt/geasscomics/res/mipmap-xxxhdpi/ic_launcher.png
Normal file
BIN
src/pt/geasscomics/res/mipmap-xxxhdpi/ic_launcher.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 8.5 KiB |
@ -0,0 +1,118 @@
|
||||
package eu.kanade.tachiyomi.extension.pt.geasscomics
|
||||
|
||||
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 keiyoushi.utils.parseAs
|
||||
import okhttp3.HttpUrl.Companion.toHttpUrl
|
||||
import okhttp3.Request
|
||||
import okhttp3.Response
|
||||
|
||||
class GeassComics : HttpSource() {
|
||||
|
||||
override val name: String = "Geass Comics"
|
||||
|
||||
override val baseUrl: String = "https://geasscomics.xyz"
|
||||
|
||||
private val apiUrl = "https://api.${baseUrl.substringAfterLast("/")}"
|
||||
|
||||
override val lang: String = "pt-BR"
|
||||
|
||||
override val supportsLatest: Boolean = true
|
||||
|
||||
override val client = network.cloudflareClient.newBuilder()
|
||||
.rateLimitHost(apiUrl.toHttpUrl(), 2, 1)
|
||||
.build()
|
||||
|
||||
// ========================= Popular ====================================
|
||||
|
||||
override fun popularMangaRequest(page: Int) = GET("$apiUrl/obras?page=$page&limit=12", headers)
|
||||
|
||||
override fun popularMangaParse(response: Response): MangasPage {
|
||||
val dto = response.parseAs<PopularDto>()
|
||||
return MangasPage(dto.mangas.map(MangaDto::toSManga), dto.hasNextPage())
|
||||
}
|
||||
|
||||
// ========================= Latest =====================================
|
||||
|
||||
override fun latestUpdatesRequest(page: Int) = GET("$apiUrl/capitulos/recentes?page=$page&limit=150", headers)
|
||||
|
||||
override fun latestUpdatesParse(response: Response): MangasPage {
|
||||
val dto = response.parseAs<LatestDto>()
|
||||
return MangasPage(dto.mangas.map(SimpleMangaDto::toSManga).distinctBy(SManga::url), false)
|
||||
}
|
||||
|
||||
// ========================= Search =====================================
|
||||
|
||||
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
|
||||
val url = "$apiUrl/obras".toHttpUrl().newBuilder()
|
||||
.addQueryParameter("page", page.toString())
|
||||
.addQueryParameter("limit", "12")
|
||||
|
||||
if (query.isNotBlank()) {
|
||||
url.addPathSegment("search")
|
||||
url.addQueryParameter("q", query)
|
||||
}
|
||||
|
||||
filters.forEach { filter ->
|
||||
when (filter) {
|
||||
is GenreList -> {
|
||||
val genres = filter.state.filter(GenreCheckBox::state)
|
||||
if (genres.isEmpty()) return@forEach
|
||||
url.addQueryParameter("generos", genres.joinToString { it.id })
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
return GET(url.build(), headers)
|
||||
}
|
||||
|
||||
override fun searchMangaParse(response: Response): MangasPage = popularMangaParse(response)
|
||||
|
||||
// ========================= Details ====================================
|
||||
|
||||
override fun getMangaUrl(manga: SManga) = "$baseUrl/manga/${manga.url}"
|
||||
|
||||
override fun mangaDetailsRequest(manga: SManga) =
|
||||
GET("$apiUrl/obras/${manga.url}/info", headers)
|
||||
|
||||
override fun mangaDetailsParse(response: Response): SManga =
|
||||
response.parseAs<DetailsDto>().manga.toSManga()
|
||||
|
||||
// ========================= Chapters ===================================
|
||||
|
||||
override fun getChapterUrl(chapter: SChapter): String = "$baseUrl/${chapter.url}"
|
||||
|
||||
override fun chapterListRequest(manga: SManga): Request = mangaDetailsRequest(manga)
|
||||
|
||||
override fun chapterListParse(response: Response): List<SChapter> =
|
||||
response.parseAs<DetailsDto>().toChapters()
|
||||
|
||||
// ========================= Pages ======================================
|
||||
|
||||
override fun pageListRequest(chapter: SChapter) =
|
||||
GET("$apiUrl${chapter.url.replace("manga", "obras").replace("chapter", "capitulos")}", headers)
|
||||
|
||||
override fun pageListParse(response: Response): List<Page> =
|
||||
response.parseAs<PageDto>().toPages()
|
||||
|
||||
override fun imageUrlParse(response: Response): String = ""
|
||||
|
||||
// ========================= Filters ====================================
|
||||
|
||||
override fun getFilterList(): FilterList {
|
||||
return FilterList(
|
||||
listOf(
|
||||
GenreList(
|
||||
title = "Gêneros",
|
||||
genres = genresList.sortedBy(Genre::name),
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
@ -0,0 +1,131 @@
|
||||
package eu.kanade.tachiyomi.extension.pt.geasscomics
|
||||
|
||||
import eu.kanade.tachiyomi.source.model.Page
|
||||
import eu.kanade.tachiyomi.source.model.SChapter
|
||||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
class Pagination(
|
||||
@SerialName("has_next")
|
||||
val hasNext: Boolean = false,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
class PopularDto(
|
||||
@SerialName("obras")
|
||||
val mangas: List<MangaDto> = emptyList(),
|
||||
val pagination: Pagination = Pagination(),
|
||||
) {
|
||||
fun hasNextPage() = pagination.hasNext
|
||||
}
|
||||
|
||||
@Serializable
|
||||
class LatestDto(
|
||||
@SerialName("recentes")
|
||||
val mangas: List<SimpleMangaDto> = emptyList(),
|
||||
)
|
||||
|
||||
@Serializable
|
||||
class DetailsDto(
|
||||
@SerialName("obra")
|
||||
val manga: MangaDto,
|
||||
) {
|
||||
fun toChapters(): List<SChapter> {
|
||||
return manga.chapters.map {
|
||||
SChapter.create().apply {
|
||||
name = it.name
|
||||
chapter_number = it.number.toFloat()
|
||||
url = "/manga/${manga.id}/chapter/${it.number}"
|
||||
}
|
||||
}.sortedBy(SChapter::chapter_number).reversed()
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable
|
||||
class SimpleMangaDto(
|
||||
@SerialName("obra_id")
|
||||
val id: Int,
|
||||
@SerialName("titulo_obra")
|
||||
val title: String,
|
||||
@SerialName("capa")
|
||||
val thumbnail_url: String,
|
||||
) {
|
||||
fun toSManga() = SManga.create().apply {
|
||||
title = this@SimpleMangaDto.title
|
||||
thumbnail_url = this@SimpleMangaDto.thumbnail_url
|
||||
url = this@SimpleMangaDto.id.toString()
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable
|
||||
class MangaDto(
|
||||
val id: Int,
|
||||
@SerialName("titulo")
|
||||
val title: String,
|
||||
@SerialName("artista")
|
||||
val artist: String,
|
||||
@SerialName("autor")
|
||||
val author: String,
|
||||
@SerialName("capa")
|
||||
val thumbnail_url: String,
|
||||
@SerialName("generos")
|
||||
val genres: List<Genre>,
|
||||
val sinopse: String,
|
||||
val status: String,
|
||||
@SerialName("capitulos")
|
||||
val chapters: List<ChapterDto> = emptyList(),
|
||||
) {
|
||||
|
||||
fun toSManga() = SManga.create().apply {
|
||||
title = this@MangaDto.title
|
||||
description = this@MangaDto.sinopse
|
||||
thumbnail_url = this@MangaDto.thumbnail_url
|
||||
artist = this@MangaDto.artist
|
||||
author = this@MangaDto.author
|
||||
genre = genres.joinToString { it.name }
|
||||
url = this@MangaDto.id.toString()
|
||||
status = when (this@MangaDto.status) {
|
||||
"EM ANDAMENTO" -> SManga.ONGOING
|
||||
"COMPLETO" -> SManga.COMPLETED
|
||||
else -> SManga.UNKNOWN
|
||||
}
|
||||
initialized = true
|
||||
}
|
||||
|
||||
@Serializable
|
||||
class Genre(
|
||||
@SerialName("nome")
|
||||
val name: String,
|
||||
)
|
||||
}
|
||||
|
||||
@Serializable
|
||||
class ChapterDto(
|
||||
val id: Long,
|
||||
@SerialName("numero")
|
||||
val number: String,
|
||||
@SerialName("titulo")
|
||||
val name: String,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
class PageDto(
|
||||
@SerialName("capitulo")
|
||||
val chapter: Image,
|
||||
) {
|
||||
fun toPages(): List<Page> =
|
||||
chapter.images.mapIndexed { index, source -> Page(index, imageUrl = source.url) }
|
||||
|
||||
@Serializable
|
||||
class Source(
|
||||
val url: String,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
class Image(
|
||||
@SerialName("imagens")
|
||||
val images: List<Source> = emptyList(),
|
||||
)
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
package eu.kanade.tachiyomi.extension.pt.geasscomics
|
||||
|
||||
import eu.kanade.tachiyomi.source.model.Filter
|
||||
|
||||
class GenreList(title: String, genres: List<Genre>) : Filter.Group<GenreCheckBox>(title, genres.map { GenreCheckBox(it.name, it.id.toString()) })
|
||||
class GenreCheckBox(name: String, val id: String = name) : Filter.CheckBox(name)
|
||||
class Genre(val id: Int, val name: String)
|
||||
|
||||
val genresList = listOf(
|
||||
Genre(10, "Isekai"),
|
||||
Genre(11, "Sistema"),
|
||||
Genre(12, "Shonen"),
|
||||
Genre(13, "Shojo"),
|
||||
Genre(14, "Seinen"),
|
||||
Genre(15, "Josei"),
|
||||
Genre(16, "Slice of Life"),
|
||||
Genre(17, "Horror"),
|
||||
Genre(18, "Fantasy"),
|
||||
Genre(19, "Romance"),
|
||||
Genre(20, "Comedia"),
|
||||
Genre(21, "Sports"),
|
||||
Genre(22, "Supernatural"),
|
||||
Genre(23, "Mystery"),
|
||||
Genre(24, "Psychological"),
|
||||
Genre(25, "Aventura"),
|
||||
Genre(26, "Adulto"),
|
||||
Genre(27, "Hentai"),
|
||||
Genre(29, "Harém"),
|
||||
Genre(30, "Ação"),
|
||||
Genre(31, "Drama"),
|
||||
Genre(32, "Escolar"),
|
||||
Genre(35, "Monstros"),
|
||||
Genre(36, "Ecchi"),
|
||||
Genre(37, "Magia"),
|
||||
Genre(38, "Demônios"),
|
||||
Genre(40, "Dungeons"),
|
||||
Genre(41, "Manga"),
|
||||
Genre(42, "Apocalipse"),
|
||||
Genre(43, "Manhwa"),
|
||||
Genre(44, "Ficção Científica"),
|
||||
Genre(45, "Sugestivo"),
|
||||
Genre(46, "Loli"),
|
||||
)
|
Loading…
x
Reference in New Issue
Block a user