Remove tsuki (#7366)
This commit is contained in:
parent
ed426f5e6b
commit
e6753d4ea5
|
@ -1,22 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<application>
|
|
||||||
<activity
|
|
||||||
android:name=".pt.tsukimangas.TsukiMangasUrlActivity"
|
|
||||||
android:excludeFromRecents="true"
|
|
||||||
android:exported="true"
|
|
||||||
android:theme="@android:style/Theme.NoDisplay">
|
|
||||||
<intent-filter>
|
|
||||||
<action android:name="android.intent.action.VIEW" />
|
|
||||||
|
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
|
||||||
<category android:name="android.intent.category.BROWSABLE" />
|
|
||||||
|
|
||||||
<data
|
|
||||||
android:host="tsuki-mangas.com"
|
|
||||||
android:pathPattern="/obra/..*"
|
|
||||||
android:scheme="https" />
|
|
||||||
</intent-filter>
|
|
||||||
</activity>
|
|
||||||
</application>
|
|
||||||
</manifest>
|
|
|
@ -1,8 +0,0 @@
|
||||||
ext {
|
|
||||||
extName = 'Tsuki Mangás'
|
|
||||||
extClass = '.TsukiMangas'
|
|
||||||
extVersionCode = 7
|
|
||||||
isNsfw = true
|
|
||||||
}
|
|
||||||
|
|
||||||
apply from: "$rootDir/common.gradle"
|
|
Binary file not shown.
Before Width: | Height: | Size: 3.3 KiB |
Binary file not shown.
Before Width: | Height: | Size: 1.7 KiB |
Binary file not shown.
Before Width: | Height: | Size: 3.8 KiB |
Binary file not shown.
Before Width: | Height: | Size: 6.3 KiB |
Binary file not shown.
Before Width: | Height: | Size: 8.9 KiB |
|
@ -1,360 +0,0 @@
|
||||||
package eu.kanade.tachiyomi.extension.pt.tsukimangas
|
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
|
||||||
import android.app.Application
|
|
||||||
import android.os.Handler
|
|
||||||
import android.os.Looper
|
|
||||||
import android.webkit.WebView
|
|
||||||
import android.webkit.WebViewClient
|
|
||||||
import eu.kanade.tachiyomi.extension.pt.tsukimangas.dto.ChapterListDto
|
|
||||||
import eu.kanade.tachiyomi.extension.pt.tsukimangas.dto.CompleteMangaDto
|
|
||||||
import eu.kanade.tachiyomi.extension.pt.tsukimangas.dto.MangaListDto
|
|
||||||
import eu.kanade.tachiyomi.extension.pt.tsukimangas.dto.PageListDto
|
|
||||||
import eu.kanade.tachiyomi.network.GET
|
|
||||||
import eu.kanade.tachiyomi.network.asObservableSuccess
|
|
||||||
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 eu.kanade.tachiyomi.util.asJsoup
|
|
||||||
import kotlinx.serialization.json.Json
|
|
||||||
import kotlinx.serialization.json.decodeFromStream
|
|
||||||
import okhttp3.HttpUrl
|
|
||||||
import okhttp3.HttpUrl.Companion.toHttpUrl
|
|
||||||
import okhttp3.Interceptor
|
|
||||||
import okhttp3.Request
|
|
||||||
import okhttp3.Response
|
|
||||||
import rx.Observable
|
|
||||||
import uy.kohesive.injekt.Injekt
|
|
||||||
import uy.kohesive.injekt.api.get
|
|
||||||
import uy.kohesive.injekt.injectLazy
|
|
||||||
import java.text.SimpleDateFormat
|
|
||||||
import java.util.Locale
|
|
||||||
import java.util.concurrent.CountDownLatch
|
|
||||||
import java.util.concurrent.TimeUnit
|
|
||||||
|
|
||||||
class TsukiMangas : HttpSource() {
|
|
||||||
|
|
||||||
override val name = "Tsuki Mangás"
|
|
||||||
|
|
||||||
override val baseUrl = "https://tsuki-mangas.com"
|
|
||||||
|
|
||||||
private val apiUrl = baseUrl + API_PATH
|
|
||||||
|
|
||||||
override val lang = "pt-BR"
|
|
||||||
|
|
||||||
override val supportsLatest = true
|
|
||||||
|
|
||||||
@delegate:SuppressLint("SetJavaScriptEnabled")
|
|
||||||
private val token: String by lazy {
|
|
||||||
val latch = CountDownLatch(1)
|
|
||||||
var token = ""
|
|
||||||
Handler(Looper.getMainLooper()).post {
|
|
||||||
val webView = WebView(Injekt.get<Application>())
|
|
||||||
with(webView.settings) {
|
|
||||||
javaScriptEnabled = true
|
|
||||||
domStorageEnabled = true
|
|
||||||
databaseEnabled = true
|
|
||||||
blockNetworkImage = true
|
|
||||||
}
|
|
||||||
webView.webViewClient = object : WebViewClient() {
|
|
||||||
override fun onPageFinished(view: WebView, url: String) {
|
|
||||||
val script = "javascript:localStorage['token']"
|
|
||||||
view.evaluateJavascript(script) {
|
|
||||||
view.apply {
|
|
||||||
stopLoading()
|
|
||||||
destroy()
|
|
||||||
}
|
|
||||||
if (it.isBlank() || it in listOf("null", "undefined")) {
|
|
||||||
return@evaluateJavascript
|
|
||||||
}
|
|
||||||
token = it.replace("[\"]+".toRegex(), "")
|
|
||||||
latch.countDown()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
webView.loadUrl(baseUrl)
|
|
||||||
}
|
|
||||||
latch.await(10, TimeUnit.SECONDS)
|
|
||||||
|
|
||||||
token
|
|
||||||
}
|
|
||||||
|
|
||||||
override val client by lazy {
|
|
||||||
network.client.newBuilder()
|
|
||||||
.addInterceptor(::apiHeadersInterceptor)
|
|
||||||
.addInterceptor(::imageCdnSwapper)
|
|
||||||
.rateLimitHost(baseUrl.toHttpUrl(), 2)
|
|
||||||
.rateLimitHost(MAIN_CDN.toHttpUrl(), 1)
|
|
||||||
.rateLimitHost(SECONDARY_CDN.toHttpUrl(), 1)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun headersBuilder() = super.headersBuilder()
|
|
||||||
.add("Referer", "$baseUrl/")
|
|
||||||
|
|
||||||
private val json: Json by injectLazy()
|
|
||||||
|
|
||||||
// ============================== Popular ===============================
|
|
||||||
override fun popularMangaRequest(page: Int) = GET("$apiUrl/mangas?page=$page&filter=0", headers)
|
|
||||||
|
|
||||||
override fun popularMangaParse(response: Response): MangasPage {
|
|
||||||
val item = response.parseAs<MangaListDto>()
|
|
||||||
val mangas = item.data.map {
|
|
||||||
SManga.create().apply {
|
|
||||||
url = "/obra" + it.entryPath
|
|
||||||
thumbnail_url = baseUrl + it.imagePath
|
|
||||||
title = it.title
|
|
||||||
}
|
|
||||||
}
|
|
||||||
val hasNextPage = item.page < item.lastPage
|
|
||||||
return MangasPage(mangas, hasNextPage)
|
|
||||||
}
|
|
||||||
|
|
||||||
// =============================== Latest ===============================
|
|
||||||
// Yes, "lastests". High IQ move.
|
|
||||||
// Also yeah, there's a "?format=0" glued to the page number. Without this,
|
|
||||||
// the request will blow up with a HTTP 500.
|
|
||||||
override fun latestUpdatesRequest(page: Int) = GET("$apiUrl/home/lastests?page=$page%3Fformat%3D0", headers)
|
|
||||||
|
|
||||||
override fun latestUpdatesParse(response: Response) = popularMangaParse(response)
|
|
||||||
|
|
||||||
// =============================== Search ===============================
|
|
||||||
override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable<MangasPage> {
|
|
||||||
return if (query.startsWith(PREFIX_SEARCH)) { // URL intent handler
|
|
||||||
val id = query.removePrefix(PREFIX_SEARCH)
|
|
||||||
client.newCall(GET("$apiUrl/mangas/$id", headers))
|
|
||||||
.asObservableSuccess()
|
|
||||||
.map(::searchMangaByIdParse)
|
|
||||||
} else {
|
|
||||||
super.fetchSearchManga(page, query, filters)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun searchMangaByIdParse(response: Response): MangasPage {
|
|
||||||
val details = mangaDetailsParse(response)
|
|
||||||
return MangasPage(listOf(details), false)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getFilterList() = TsukiMangasFilters.FILTER_LIST
|
|
||||||
|
|
||||||
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
|
|
||||||
val params = TsukiMangasFilters.getSearchParameters(filters)
|
|
||||||
val url = "$apiUrl/mangas".toHttpUrl().newBuilder()
|
|
||||||
.addQueryParameter("page", page.toString())
|
|
||||||
.addQueryParameter("title", query.trim())
|
|
||||||
.addIfNotBlank("filter", params.filter)
|
|
||||||
.addIfNotBlank("format", params.format)
|
|
||||||
.addIfNotBlank("status", params.status)
|
|
||||||
.addIfNotBlank("adult_content", params.adult)
|
|
||||||
.apply {
|
|
||||||
params.genres.forEach { addQueryParameter("genres[]", it) }
|
|
||||||
params.tags.forEach { addQueryParameter("tags[]", it) }
|
|
||||||
}.build()
|
|
||||||
|
|
||||||
return GET(url, headers)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun searchMangaParse(response: Response) = popularMangaParse(response)
|
|
||||||
|
|
||||||
// =========================== Manga Details ============================
|
|
||||||
override fun mangaDetailsRequest(manga: SManga): Request {
|
|
||||||
val id = manga.url.getMangaId()
|
|
||||||
return GET("$apiUrl/mangas/$id", headers)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getMangaUrl(manga: SManga) = baseUrl + manga.url
|
|
||||||
|
|
||||||
override fun mangaDetailsParse(response: Response) = SManga.create().apply {
|
|
||||||
val mangaDto = response.parseAs<CompleteMangaDto>()
|
|
||||||
url = "/obra" + mangaDto.entryPath
|
|
||||||
thumbnail_url = baseUrl + mangaDto.imagePath
|
|
||||||
title = mangaDto.title
|
|
||||||
artist = mangaDto.staff
|
|
||||||
genre = mangaDto.genres.joinToString { it.genre }
|
|
||||||
status = parseStatus(mangaDto.status.orEmpty())
|
|
||||||
description = buildString {
|
|
||||||
mangaDto.synopsis?.also { append("$it\n\n") }
|
|
||||||
if (mangaDto.titles.isNotEmpty()) {
|
|
||||||
append("Títulos alternativos: ${mangaDto.titles.joinToString { it.title }}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun parseStatus(status: String) = when (status) {
|
|
||||||
"Ativo" -> SManga.ONGOING
|
|
||||||
"Completo" -> SManga.COMPLETED
|
|
||||||
"Hiato" -> SManga.ON_HIATUS
|
|
||||||
else -> SManga.UNKNOWN
|
|
||||||
}
|
|
||||||
|
|
||||||
// ============================== Chapters ==============================
|
|
||||||
override fun chapterListRequest(manga: SManga): Request {
|
|
||||||
val split = manga.url.split("/").reversed()
|
|
||||||
val slug = split[0]
|
|
||||||
val id = split[1]
|
|
||||||
|
|
||||||
return GET("$apiUrl/chapters/$id/all#$slug", headers)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun chapterListParse(response: Response): List<SChapter> {
|
|
||||||
val parsed = response.parseAs<ChapterListDto>()
|
|
||||||
val mangaSlug = response.request.url.fragment!!
|
|
||||||
val mangaId = response.request.url.pathSegments.reversed()[1]
|
|
||||||
|
|
||||||
return parsed.chapters.reversed().map {
|
|
||||||
SChapter.create().apply {
|
|
||||||
name = "Capítulo ${it.number}"
|
|
||||||
// Sometimes the "number" attribute have letters or other characters,
|
|
||||||
// which could ruin the automatic chapter number recognition system.
|
|
||||||
chapter_number = it.number.trim { char -> !char.isDigit() }.toFloatOrNull() ?: 1F
|
|
||||||
|
|
||||||
url = "/leitor/$mangaId/${it.versionId}/$mangaSlug/${it.number}"
|
|
||||||
|
|
||||||
date_upload = it.created_at.orEmpty().toDate()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// =============================== Pages ================================
|
|
||||||
override fun getChapterUrl(chapter: SChapter) = baseUrl + chapter.url
|
|
||||||
|
|
||||||
override fun pageListRequest(chapter: SChapter): Request {
|
|
||||||
val versionId = chapter.url.split("/")[3]
|
|
||||||
|
|
||||||
return GET("$apiUrl/chapter/versions/$versionId", headers)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun pageListParse(response: Response): List<Page> {
|
|
||||||
val data = response.parseAs<PageListDto>()
|
|
||||||
val sortedPages = data.pages.sortedBy { it.url.extractPageNumber() }
|
|
||||||
val host = getImageHost(sortedPages.first().url)
|
|
||||||
|
|
||||||
return sortedPages.mapIndexed { index, item ->
|
|
||||||
Page(index, imageUrl = host + item.url)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The source normally uses only one CDN per chapter, so we'll try to get
|
|
||||||
* the correct CDN before loading all pages, leaving the [imageCdnSwapper]
|
|
||||||
* as the last choice.
|
|
||||||
*/
|
|
||||||
private fun getImageHost(path: String): String {
|
|
||||||
val pageCheck = super.client.newCall(GET(MAIN_CDN + path, headers)).execute()
|
|
||||||
pageCheck.close()
|
|
||||||
return when {
|
|
||||||
!pageCheck.isSuccessful -> SECONDARY_CDN
|
|
||||||
else -> MAIN_CDN
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun imageUrlParse(response: Response): String {
|
|
||||||
throw UnsupportedOperationException()
|
|
||||||
}
|
|
||||||
|
|
||||||
// ============================= Utilities ==============================
|
|
||||||
private inline fun <reified T> Response.parseAs(): T = use {
|
|
||||||
try {
|
|
||||||
json.decodeFromStream(it.body.byteStream())
|
|
||||||
} catch (_: Exception) {
|
|
||||||
throw Exception(
|
|
||||||
"""
|
|
||||||
Contéudo protegido ou foi removido.
|
|
||||||
Faça o login na WebView e tente novamente
|
|
||||||
""".trimIndent(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun HttpUrl.Builder.addIfNotBlank(query: String, value: String): HttpUrl.Builder {
|
|
||||||
if (value.isNotBlank()) addQueryParameter(query, value)
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun String.getMangaId() = substringAfter("/obra/").substringBefore("/")
|
|
||||||
|
|
||||||
private fun String.toDate(): Long {
|
|
||||||
return runCatching { DATE_FORMATTER.parse(trim())?.time }
|
|
||||||
.getOrNull() ?: 0L
|
|
||||||
}
|
|
||||||
|
|
||||||
private val pageNumberRegex = Regex("""(\d+)\.(png|jpg|jpeg|gif|webp)$""")
|
|
||||||
|
|
||||||
private fun String.extractPageNumber() = pageNumberRegex
|
|
||||||
.find(substringBefore("?"))
|
|
||||||
?.groupValues
|
|
||||||
?.get(1)
|
|
||||||
?.toInt() ?: 0
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This may sound stupid (because it is), but a similar approach exists
|
|
||||||
* in the source itself, because they somehow don't know to which server
|
|
||||||
* each page belongs to. I thought the `server` attribute returned by page
|
|
||||||
* objects would be enough, but it turns out that it isn't. Day ruined.
|
|
||||||
*/
|
|
||||||
private fun imageCdnSwapper(chain: Interceptor.Chain): Response {
|
|
||||||
val request = chain.request()
|
|
||||||
val response = chain.proceed(request)
|
|
||||||
|
|
||||||
return if (response.code != 404) {
|
|
||||||
response
|
|
||||||
} else {
|
|
||||||
response.close()
|
|
||||||
val url = request.url.toString()
|
|
||||||
val newUrl = when {
|
|
||||||
url.startsWith(MAIN_CDN) -> url.replace("$MAIN_CDN/tsuki", SECONDARY_CDN)
|
|
||||||
url.startsWith(SECONDARY_CDN) -> url.replace(SECONDARY_CDN, "$MAIN_CDN/tsuki")
|
|
||||||
else -> url
|
|
||||||
}
|
|
||||||
|
|
||||||
val newRequest = GET(newUrl, request.headers)
|
|
||||||
chain.proceed(newRequest)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private val apiHeadersRegex = Regex("""headers\.common(?:\.([0-9A-Za-z_]+)|\[['"]([0-9A-Za-z-_]+)['"]])\s*=\s*['"]([a-zA-Z0-9_ :;.,\\/?!(){}\[\]@<>=\-+*#$&`|~^%]+)['"]""")
|
|
||||||
|
|
||||||
private val apiHeaders by lazy {
|
|
||||||
val document = client.newCall(GET(baseUrl, headers)).execute().asJsoup()
|
|
||||||
val scriptUrl = document.selectFirst("script[src*=index-]")!!.absUrl("src")
|
|
||||||
val script = client.newCall(GET(scriptUrl, headers)).execute().body.string()
|
|
||||||
val matches = apiHeadersRegex.findAll(script)
|
|
||||||
|
|
||||||
matches.associate {
|
|
||||||
(it.groups[1] ?: it.groups[2]!!).value to it.groups[3]!!.value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun apiHeadersInterceptor(chain: Interceptor.Chain): Response {
|
|
||||||
val request = chain.request()
|
|
||||||
|
|
||||||
if (!request.url.encodedPath.startsWith(API_PATH)) {
|
|
||||||
return chain.proceed(request)
|
|
||||||
}
|
|
||||||
|
|
||||||
val newRequest = request.newBuilder().apply {
|
|
||||||
apiHeaders.entries.forEach { addHeader(it.key, it.value) }
|
|
||||||
if (token.isNotBlank()) {
|
|
||||||
addHeader("Authorization", "Bearer $token")
|
|
||||||
}
|
|
||||||
}.build()
|
|
||||||
|
|
||||||
return chain.proceed(newRequest)
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
const val PREFIX_SEARCH = "id:"
|
|
||||||
|
|
||||||
private val DATE_FORMATTER by lazy {
|
|
||||||
SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.ENGLISH)
|
|
||||||
}
|
|
||||||
|
|
||||||
private const val MAIN_CDN = "https://cdn.tsuki-mangas.com/tsuki"
|
|
||||||
private const val SECONDARY_CDN = "https://cdn2.tsuki-mangas.com"
|
|
||||||
private const val API_PATH = "/api/v3"
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,475 +0,0 @@
|
||||||
package eu.kanade.tachiyomi.extension.pt.tsukimangas
|
|
||||||
|
|
||||||
import eu.kanade.tachiyomi.source.model.Filter
|
|
||||||
import eu.kanade.tachiyomi.source.model.FilterList
|
|
||||||
|
|
||||||
object TsukiMangasFilters {
|
|
||||||
open class CheckBoxFilterList(name: String, val pairs: Array<Pair<String, String>>) :
|
|
||||||
Filter.Group<Filter.CheckBox>(name, pairs.map { CheckBoxVal(it.first) })
|
|
||||||
|
|
||||||
private class CheckBoxVal(name: String) : Filter.CheckBox(name, false)
|
|
||||||
|
|
||||||
private inline fun <reified R> FilterList.parseCheckbox(
|
|
||||||
options: Array<Pair<String, String>>,
|
|
||||||
): Sequence<String> {
|
|
||||||
return (first { it is R } as CheckBoxFilterList).state
|
|
||||||
.asSequence()
|
|
||||||
.filter { it.state }
|
|
||||||
.map { checkbox -> options.find { it.first == checkbox.name }!!.second }
|
|
||||||
}
|
|
||||||
|
|
||||||
open class SelectFilter(
|
|
||||||
displayName: String,
|
|
||||||
val vals: Array<Pair<String, String>>,
|
|
||||||
) : Filter.Select<String>(
|
|
||||||
displayName,
|
|
||||||
vals.map { it.first }.toTypedArray(),
|
|
||||||
) {
|
|
||||||
val selected get() = vals[state].second
|
|
||||||
}
|
|
||||||
|
|
||||||
private inline fun <reified R> FilterList.getSelected(): String {
|
|
||||||
return (first { it is R } as SelectFilter).selected
|
|
||||||
}
|
|
||||||
|
|
||||||
internal class GenresFilter : CheckBoxFilterList("Gêneros", GENRES)
|
|
||||||
internal class TagsFilter : CheckBoxFilterList("Tags", TAGS)
|
|
||||||
|
|
||||||
internal class FormatFilter : SelectFilter("Formato", FORMATS)
|
|
||||||
internal class AdultFilter : SelectFilter("Mostrar conteúdo adulto", ADULT_OPTIONS)
|
|
||||||
internal class ContentFilter : SelectFilter("Filtro", CONTENT_FILTER)
|
|
||||||
internal class StatusFilter : SelectFilter("Status", STATUS)
|
|
||||||
|
|
||||||
internal val FILTER_LIST get() = FilterList(
|
|
||||||
GenresFilter(),
|
|
||||||
TagsFilter(),
|
|
||||||
|
|
||||||
FormatFilter(),
|
|
||||||
AdultFilter(),
|
|
||||||
ContentFilter(),
|
|
||||||
StatusFilter(),
|
|
||||||
)
|
|
||||||
|
|
||||||
internal data class FilterSearchParams(
|
|
||||||
val genres: Sequence<String> = emptySequence(),
|
|
||||||
val tags: Sequence<String> = emptySequence(),
|
|
||||||
|
|
||||||
val format: String = "",
|
|
||||||
val adult: String = "",
|
|
||||||
val filter: String = "",
|
|
||||||
val status: String = "",
|
|
||||||
)
|
|
||||||
|
|
||||||
internal fun getSearchParameters(filters: FilterList): FilterSearchParams {
|
|
||||||
if (filters.isEmpty()) return FilterSearchParams()
|
|
||||||
|
|
||||||
return FilterSearchParams(
|
|
||||||
filters.parseCheckbox<GenresFilter>(GENRES),
|
|
||||||
filters.parseCheckbox<TagsFilter>(TAGS),
|
|
||||||
|
|
||||||
filters.getSelected<FormatFilter>(),
|
|
||||||
filters.getSelected<AdultFilter>(),
|
|
||||||
filters.getSelected<ContentFilter>(),
|
|
||||||
filters.getSelected<StatusFilter>(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private val GENRES = arrayOf(
|
|
||||||
"4-Koma",
|
|
||||||
"Adaptação",
|
|
||||||
"Aliens",
|
|
||||||
"Animais",
|
|
||||||
"Antologia",
|
|
||||||
"Artes Marciais",
|
|
||||||
"Aventura",
|
|
||||||
"Ação",
|
|
||||||
"Colorido por fã",
|
|
||||||
"Comédia",
|
|
||||||
"Criado pelo Usuário",
|
|
||||||
"Crime",
|
|
||||||
"Cross-dressing",
|
|
||||||
"Deliquentes",
|
|
||||||
"Demônios",
|
|
||||||
"Doujinshi",
|
|
||||||
"Drama",
|
|
||||||
"Ecchi",
|
|
||||||
"Esportes",
|
|
||||||
"Fantasia",
|
|
||||||
"Fantasmas",
|
|
||||||
"Filosófico",
|
|
||||||
"Gals",
|
|
||||||
"Ganhador de Prêmio",
|
|
||||||
"Garotas Monstro",
|
|
||||||
"Garotas Mágicas",
|
|
||||||
"Gastronomia",
|
|
||||||
"Gore",
|
|
||||||
"Harém",
|
|
||||||
"Harém Reverso",
|
|
||||||
"Hentai",
|
|
||||||
"Histórico",
|
|
||||||
"Horror",
|
|
||||||
"Incesto",
|
|
||||||
"Isekai",
|
|
||||||
"Jogos Tradicionais",
|
|
||||||
"Lolis",
|
|
||||||
"Long Strip",
|
|
||||||
"Mafia",
|
|
||||||
"Magia",
|
|
||||||
"Mecha",
|
|
||||||
"Medicina",
|
|
||||||
"Militar",
|
|
||||||
"Mistério",
|
|
||||||
"Monstros",
|
|
||||||
"Música",
|
|
||||||
"Ninjas",
|
|
||||||
"Obscenidade",
|
|
||||||
"Oficialmente Colorido",
|
|
||||||
"One-shot",
|
|
||||||
"Policial",
|
|
||||||
"Psicológico",
|
|
||||||
"Pós-apocalíptico",
|
|
||||||
"Realidade Virtual",
|
|
||||||
"Reencarnação",
|
|
||||||
"Romance",
|
|
||||||
"Samurais",
|
|
||||||
"Sci-Fi",
|
|
||||||
"Shotas",
|
|
||||||
"Shoujo Ai",
|
|
||||||
"Shounen Ai",
|
|
||||||
"Slice of Life",
|
|
||||||
"Sobrenatural",
|
|
||||||
"Sobrevivência",
|
|
||||||
"Super Herói",
|
|
||||||
"Thriller",
|
|
||||||
"Todo Colorido",
|
|
||||||
"Trabalho de Escritório",
|
|
||||||
"Tragédia",
|
|
||||||
"Troca de Gênero",
|
|
||||||
"Vampiros",
|
|
||||||
"Viagem no Tempo",
|
|
||||||
"Vida Escolar",
|
|
||||||
"Violência Sexual",
|
|
||||||
"Vídeo Games",
|
|
||||||
"Webcomic",
|
|
||||||
"Wuxia",
|
|
||||||
"Yaoi",
|
|
||||||
"Yuri",
|
|
||||||
"Zumbis",
|
|
||||||
).map { Pair(it, it) }.toTypedArray()
|
|
||||||
|
|
||||||
private val TAGS = arrayOf(
|
|
||||||
Pair("4-Koma", "4-Koma"),
|
|
||||||
Pair("Acromático", "Achromatic"),
|
|
||||||
Pair("Adoção", "Adoption"),
|
|
||||||
Pair("Agricultura", "Agriculture"),
|
|
||||||
Pair("Airsoft", "Airsoft"),
|
|
||||||
Pair("Alienígenas", "Aliens"),
|
|
||||||
Pair("Alquimia", "Alchemy"),
|
|
||||||
Pair("Amadurecimento", "Coming Of Age"),
|
|
||||||
Pair("Ambiental", "Environmental"),
|
|
||||||
Pair("Amnésia", "Amnesia"),
|
|
||||||
Pair("Amor entre Adolescentes", "Teens' Love"),
|
|
||||||
Pair("Amor entre Homens", "Boys' Love"),
|
|
||||||
Pair("Anacronismo", "Anachronism"),
|
|
||||||
Pair("Animais", "Animals"),
|
|
||||||
Pair("Anjos", "Angels"),
|
|
||||||
Pair("Anti-Herói", "Anti-Hero"),
|
|
||||||
Pair("Antologia", "Anthology"),
|
|
||||||
Pair("Antropomorfismo", "Anthropomorphism"),
|
|
||||||
Pair("Anúncio Publicitário", "Advertisement"),
|
|
||||||
Pair("Ao Ar Livre", "Outdoor"),
|
|
||||||
Pair("Arco e Flecha", "Archery"),
|
|
||||||
Pair("Armas", "Guns"),
|
|
||||||
Pair("Artes Marciais", "Martial Arts"),
|
|
||||||
Pair("Assassinos", "Assassins"),
|
|
||||||
Pair("Assexual", "Asexual"),
|
|
||||||
Pair("Astronomia", "Astronomy"),
|
|
||||||
Pair("Atletismo", "Athletics"),
|
|
||||||
Pair("Atuação", "Acting"),
|
|
||||||
Pair("Autobiográfico", "Autobiographical"),
|
|
||||||
Pair("Aviação", "Aviation"),
|
|
||||||
Pair("Badminton", "Badminton"),
|
|
||||||
Pair("Banda", "Band"),
|
|
||||||
Pair("Bar", "Bar"),
|
|
||||||
Pair("Barreira de Idioma Estrangeiro", "Foreign Language Barrier"),
|
|
||||||
Pair("Basquete", "Basketball"),
|
|
||||||
Pair("Batalha Real", "Battle Royale"),
|
|
||||||
Pair("Batalha de Cartas", "Card Battle"),
|
|
||||||
Pair("Beisebol", "Baseball"),
|
|
||||||
Pair("Biográfico", "Biographical"),
|
|
||||||
Pair("Bissexual", "Bisexual"),
|
|
||||||
Pair("Bombeiros", "Firefighters"),
|
|
||||||
Pair("Boxe", "Boxing"),
|
|
||||||
Pair("Bruxa", "Witch"),
|
|
||||||
Pair("Bullying", "Bullying"),
|
|
||||||
Pair("CGI Completo", "Full CGI"),
|
|
||||||
Pair("CGI", "CGI"),
|
|
||||||
Pair("Caligrafia", "Calligraphy"),
|
|
||||||
Pair("Canibalismo", "Cannibalism"),
|
|
||||||
Pair("Carros", "Cars"),
|
|
||||||
Pair("Casamento", "Marriage"),
|
|
||||||
Pair("Centauro", "Centaur"),
|
|
||||||
Pair("Chibi", "Chibi"),
|
|
||||||
Pair("Chuunibyou", "Chuunibyou"),
|
|
||||||
Pair("Ciborgue", "Cyborg"),
|
|
||||||
Pair("Ciclismo", "Cycling"),
|
|
||||||
Pair("Ciclomotores", "Mopeds"),
|
|
||||||
Pair("Circo", "Circus"),
|
|
||||||
Pair("Civilização Perdida", "Lost Civilization"),
|
|
||||||
Pair("Clone", "Clone"),
|
|
||||||
Pair("Clube Escolar", "School Club"),
|
|
||||||
Pair("Comida", "Food"),
|
|
||||||
Pair("Comédia Surrealista", "Surreal Comedy"),
|
|
||||||
Pair("Conspiração", "Conspiracy"),
|
|
||||||
Pair("Conto de Fadas", "Fairy Tale"),
|
|
||||||
Pair("Cor Completa", "Full Color"),
|
|
||||||
Pair("Cosplay", "Cosplay"),
|
|
||||||
Pair("Crime", "Crime"),
|
|
||||||
Pair("Crossover", "Crossover"),
|
|
||||||
Pair("Cultivo", "Cultivation"),
|
|
||||||
Pair("Culto", "Cult"),
|
|
||||||
Pair("Cultura Otaku", "Otaku Culture"),
|
|
||||||
Pair("Cyberpunk", "Cyberpunk"),
|
|
||||||
Pair("Dança", "Dancing"),
|
|
||||||
Pair("Deficiência", "Disability"),
|
|
||||||
Pair("Delinquentes", "Delinquents"),
|
|
||||||
Pair("Demônios", "Demons"),
|
|
||||||
Pair("Denpa", "Denpa"),
|
|
||||||
Pair("Desenho", "Drawing"),
|
|
||||||
Pair("Desenvolvimento de Software", "Software Development"),
|
|
||||||
Pair("Deserto", "Desert"),
|
|
||||||
Pair("Detetive", "Detective"),
|
|
||||||
Pair("Deuses", "Gods"),
|
|
||||||
Pair("Diferença de Idade", "Age Gap"),
|
|
||||||
Pair("Dinossauros", "Dinosaurs"),
|
|
||||||
Pair("Distópico", "Dystopian"),
|
|
||||||
Pair("Donzela do Santuário", "Shrine Maiden"),
|
|
||||||
Pair("Dragões", "Dragons"),
|
|
||||||
Pair("Drogas", "Drugs"),
|
|
||||||
Pair("Dullahan", "Dullahan"),
|
|
||||||
Pair("E-Sports", "E-Sports"),
|
|
||||||
Pair("Economia", "Economics"),
|
|
||||||
Pair("Educacional", "Educational"),
|
|
||||||
Pair("Elenco Conjunto", "Ensemble Cast"),
|
|
||||||
Pair("Elenco Principalmente Adolescente", "Primarily Teen Cast"),
|
|
||||||
Pair("Elenco Principalmente Adulto", "Primarily Adult Cast"),
|
|
||||||
Pair("Elenco Principalmente Feminino", "Primarily Female Cast"),
|
|
||||||
Pair("Elenco Principalmente Infantil", "Primarily Child Cast"),
|
|
||||||
Pair("Elenco Principalmente Masculino", "Primarily Male Cast"),
|
|
||||||
Pair("Elfo", "Elf"),
|
|
||||||
Pair("Empregadas", "Maids"),
|
|
||||||
Pair("Episódico", "Episodic"),
|
|
||||||
Pair("Ero Guro", "Ero Guro"),
|
|
||||||
Pair("Escola", "School"),
|
|
||||||
Pair("Escravidão", "Slavery"),
|
|
||||||
Pair("Escrita", "Writing"),
|
|
||||||
Pair("Esgrima", "Fencing"),
|
|
||||||
Pair("Espaço", "Space"),
|
|
||||||
Pair("Espionagem", "Espionage"),
|
|
||||||
Pair("Esqueleto", "Skeleton"),
|
|
||||||
Pair("Faculdade", "College"),
|
|
||||||
Pair("Fada", "Fairy"),
|
|
||||||
Pair("Família Encontrada", "Found Family"),
|
|
||||||
Pair("Fantasia Urbana", "Urban Fantasy"),
|
|
||||||
Pair("Fantasma", "Ghost"),
|
|
||||||
Pair("Filosofia", "Philosophy"),
|
|
||||||
Pair("Fitness", "Fitness"),
|
|
||||||
Pair("Flash", "Flash"),
|
|
||||||
Pair("Fotografia", "Photography"),
|
|
||||||
Pair("Freira", "Nun"),
|
|
||||||
Pair("Fugitivo", "Fugitive"),
|
|
||||||
Pair("Futebol Americano", "American Football"),
|
|
||||||
Pair("Futebol", "Football"),
|
|
||||||
Pair("Gangues", "Gangs"),
|
|
||||||
Pair("Garota Monstro", "Monster Girl"),
|
|
||||||
Pair("Garotas Bonitinhas Fazendo Coisas Bonitinhas", "Cute Girls Doing Cute Things"),
|
|
||||||
Pair("Garoto Feminino", "Femboy"),
|
|
||||||
Pair("Garoto Monstro", "Monster Boy"),
|
|
||||||
Pair("Garotos Bonitinhos Fazendo Coisas Bonitinhas", "Cute Boys Doing Cute Things"),
|
|
||||||
Pair("Go", "Go"),
|
|
||||||
Pair("Goblin", "Goblin"),
|
|
||||||
Pair("Golfe", "Golf"),
|
|
||||||
Pair("Gore", "Gore"),
|
|
||||||
Pair("Guerra", "War"),
|
|
||||||
Pair("Gyaru", "Gyaru"),
|
|
||||||
Pair("Gêmeos", "Twins"),
|
|
||||||
Pair("Handebol", "Handball"),
|
|
||||||
Pair("Harém Feminino", "Female Harem"),
|
|
||||||
Pair("Harém Masculino", "Male Harem"),
|
|
||||||
Pair("Harém com Gêneros Mistos", "Mixed Gender Harem"),
|
|
||||||
Pair("Henshin", "Henshin"),
|
|
||||||
Pair("Heterossexual", "Heterosexual"),
|
|
||||||
Pair("Hikikomori", "Hikikomori"),
|
|
||||||
Pair("Histórico", "Historical"),
|
|
||||||
Pair("Horror Corporal", "Body Horror"),
|
|
||||||
Pair("Horror Cósmico", "Cosmic Horror"),
|
|
||||||
Pair("Identidades Dissociativas", "Dissociative Identities"),
|
|
||||||
Pair("Inteligência Artificial", "Artificial Intelligence"),
|
|
||||||
Pair("Isekai", "Isekai"),
|
|
||||||
Pair("Iyashikei", "Iyashikei"),
|
|
||||||
Pair("Jogo da Morte", "Death Game"),
|
|
||||||
Pair("Jogos Eletrônicos", "Video Games"),
|
|
||||||
Pair("Jogos de Azar", "Gambling"),
|
|
||||||
Pair("Judô", "Judo"),
|
|
||||||
Pair("Kaiju", "Kaiju"),
|
|
||||||
Pair("Karuta", "Karuta"),
|
|
||||||
Pair("Kemonomimi", "Kemonomimi"),
|
|
||||||
Pair("Kuudere", "Kuudere"),
|
|
||||||
Pair("Lacrosse", "Lacrosse"),
|
|
||||||
Pair("Literatura Clássica", "Classic Literature"),
|
|
||||||
Pair("Lobisomem", "Werewolf"),
|
|
||||||
Pair("Luta Livre", "Wrestling"),
|
|
||||||
Pair("Luta com Espada", "Swordplay"),
|
|
||||||
Pair("Luta com Lança", "Spearplay"),
|
|
||||||
Pair("Líder de Torcida", "Cheerleading"),
|
|
||||||
Pair("Magia", "Magic"),
|
|
||||||
Pair("Mahjong", "Mahjong"),
|
|
||||||
Pair("Manipulação de Memória", "Memory Manipulation"),
|
|
||||||
Pair("Manipulação do Tempo", "Time Manipulation"),
|
|
||||||
Pair("Maquiagem", "Makeup"),
|
|
||||||
Pair("Maria-rapaz", "Tomboy"),
|
|
||||||
Pair("Masmorra", "Dungeon"),
|
|
||||||
Pair("Medicina", "Medicine"),
|
|
||||||
Pair("Mergulho", "Scuba Diving"),
|
|
||||||
Pair("Meta", "Meta"),
|
|
||||||
Pair("Militar", "Military"),
|
|
||||||
Pair("Mitologia", "Mythology"),
|
|
||||||
Pair("Moda", "Fashion"),
|
|
||||||
Pair("Mordomo", "Butler"),
|
|
||||||
Pair("Motocicletas", "Motorcycles"),
|
|
||||||
Pair("Mudança de Forma", "Shapeshifting"),
|
|
||||||
Pair("Mulher de Escritório", "Office Lady"),
|
|
||||||
Pair("Mundo Virtual", "Virtual World"),
|
|
||||||
Pair("Musical", "Musical"),
|
|
||||||
Pair("Máfia", "Mafia"),
|
|
||||||
Pair("Natação", "Swimming"),
|
|
||||||
Pair("Navios", "Ships"),
|
|
||||||
Pair("Necromancia", "Necromancy"),
|
|
||||||
Pair("Nekomimi", "Nekomimi"),
|
|
||||||
Pair("Ninja", "Ninja"),
|
|
||||||
Pair("Noir", "Noir"),
|
|
||||||
Pair("Nudez", "Nudity"),
|
|
||||||
Pair("Não Ficção", "Non-Fiction"),
|
|
||||||
Pair("Oiran", "Oiran"),
|
|
||||||
Pair("Ojou-Sama", "Ojou-Sama"),
|
|
||||||
Pair("Ordem Acrônica", "Achronological Order"),
|
|
||||||
Pair("Pandemia", "Pandemic"),
|
|
||||||
Pair("Parkour", "Parkour"),
|
|
||||||
Pair("Paródia", "Parody"),
|
|
||||||
Pair("Patinagem no Gelo", "Ice Skating"),
|
|
||||||
Pair("Pele Bronzeada", "Tanned Skin"),
|
|
||||||
Pair("Pesca", "Fishing"),
|
|
||||||
Pair("Piratas", "Pirates"),
|
|
||||||
Pair("Polícia", "Police"),
|
|
||||||
Pair("Política", "Politics"),
|
|
||||||
Pair("Ponto de Vista", "POV"),
|
|
||||||
Pair("Prisão", "Prison"),
|
|
||||||
Pair("Professor(a)", "Teacher"),
|
|
||||||
Pair("Protagonista Feminina", "Female Protagonist"),
|
|
||||||
Pair("Protagonista Masculino", "Male Protagonist"),
|
|
||||||
Pair("Pular no Tempo", "Time Skip"),
|
|
||||||
Pair("Puppetry", "Puppetry"),
|
|
||||||
Pair("Pós-Apocalíptico", "Post-Apocalyptic"),
|
|
||||||
Pair("Pós-Vida", "Afterlife"),
|
|
||||||
Pair("Pôquer", "Poker"),
|
|
||||||
Pair("Quimera", "Chimera"),
|
|
||||||
Pair("Rakugo", "Rakugo"),
|
|
||||||
Pair("Reabilitação", "Rehabilitation"),
|
|
||||||
Pair("Realidade Aumentada", "Augmented Reality"),
|
|
||||||
Pair("Reencarnação", "Reincarnation"),
|
|
||||||
Pair("Regressão de Idade", "Age Regression"),
|
|
||||||
Pair("Religião", "Religion"),
|
|
||||||
Pair("Robô Real", "Real Robot"),
|
|
||||||
Pair("Robôs", "Robots"),
|
|
||||||
Pair("Rotoscopia", "Rotoscoping"),
|
|
||||||
Pair("Rugby", "Rugby"),
|
|
||||||
Pair("Rural", "Rural"),
|
|
||||||
Pair("Samurai", "Samurai"),
|
|
||||||
Pair("Sem Diálogo", "No Dialogue"),
|
|
||||||
Pair("Sem Gênero", "Agender"),
|
|
||||||
Pair("Sem-teto", "Homeless"),
|
|
||||||
Pair("Sereia", "Mermaid"),
|
|
||||||
Pair("Shogi", "Shogi"),
|
|
||||||
Pair("Skateboarding", "Skateboarding"),
|
|
||||||
Pair("Slapstick", "Slapstick"),
|
|
||||||
Pair("Sobrevivência", "Survival"),
|
|
||||||
Pair("Steampunk", "Steampunk"),
|
|
||||||
Pair("Stop Motion", "Stop Motion"),
|
|
||||||
Pair("Suicídio", "Suicide"),
|
|
||||||
Pair("Sumô", "Sumo"),
|
|
||||||
Pair("Super Robô", "Super Robot"),
|
|
||||||
Pair("Super-herói", "Superhero"),
|
|
||||||
Pair("Superpoder", "Super Power"),
|
|
||||||
Pair("Surf", "Surfing"),
|
|
||||||
Pair("Sátira", "Satire"),
|
|
||||||
Pair("Súcubo", "Succubus"),
|
|
||||||
Pair("Tanques", "Tanks"),
|
|
||||||
Pair("Temas LGBTQ+", "LGBTQ+ Themes"),
|
|
||||||
Pair("Terrorismo", "Terrorism"),
|
|
||||||
Pair("Tokusatsu", "Tokusatsu"),
|
|
||||||
Pair("Tortura", "Torture"),
|
|
||||||
Pair("Trabalho", "Work"),
|
|
||||||
Pair("Tragédia", "Tragedy"),
|
|
||||||
Pair("Transgênero", "Transgender"),
|
|
||||||
Pair("Travestismo", "Crossdressing"),
|
|
||||||
Pair("Trens", "Trains"),
|
|
||||||
Pair("Triângulo Amoroso", "Love Triangle"),
|
|
||||||
Pair("Troca de Corpos", "Body Swapping"),
|
|
||||||
Pair("Troca de Gênero", "Gender Bending"),
|
|
||||||
Pair("Tríades", "Triads"),
|
|
||||||
Pair("Tsundere", "Tsundere"),
|
|
||||||
Pair("Tênis de Mesa", "Table Tennis"),
|
|
||||||
Pair("Tênis", "Tennis"),
|
|
||||||
Pair("Universo Alternativo", "Alternate Universe"),
|
|
||||||
Pair("Urbano", "Urban"),
|
|
||||||
Pair("VTuber", "VTuber"),
|
|
||||||
Pair("Vampiro", "Vampire"),
|
|
||||||
Pair("Viagem", "Travel"),
|
|
||||||
Pair("Vida Familiar", "Family Life"),
|
|
||||||
Pair("Vikings", "Vikings"),
|
|
||||||
Pair("Vilã", "Villainess"),
|
|
||||||
Pair("Vingança", "Revenge"),
|
|
||||||
Pair("Vôlei", "Volleyball"),
|
|
||||||
Pair("Wuxia", "Wuxia"),
|
|
||||||
Pair("Yakuza", "Yakuza"),
|
|
||||||
Pair("Yandere", "Yandere"),
|
|
||||||
Pair("Youkai", "Youkai"),
|
|
||||||
Pair("Yuri", "Yuri"),
|
|
||||||
Pair("Zumbi", "Zombie"),
|
|
||||||
Pair("Ídolo", "Idol"),
|
|
||||||
Pair("Ópera Espacial", "Space Opera"),
|
|
||||||
Pair("Órfão/Órfã", "Orphan"),
|
|
||||||
)
|
|
||||||
|
|
||||||
private val ANY = Pair("Qualquer um", "")
|
|
||||||
|
|
||||||
private val FORMATS = arrayOf(
|
|
||||||
ANY,
|
|
||||||
Pair("Mangá", "1"),
|
|
||||||
Pair("Manhwa", "2"),
|
|
||||||
Pair("Manhua", "3"),
|
|
||||||
Pair("Novel", "4"),
|
|
||||||
)
|
|
||||||
|
|
||||||
private val ADULT_OPTIONS = arrayOf(
|
|
||||||
ANY,
|
|
||||||
Pair("Sim", "1"),
|
|
||||||
Pair("Não", "0"),
|
|
||||||
)
|
|
||||||
|
|
||||||
private val CONTENT_FILTER = arrayOf(
|
|
||||||
ANY,
|
|
||||||
Pair("Mais popular", "0"),
|
|
||||||
Pair("Menos popular", "1"),
|
|
||||||
Pair("Melhores notas", "2"),
|
|
||||||
Pair("Piores notas", "3"),
|
|
||||||
)
|
|
||||||
|
|
||||||
private val STATUS = arrayOf(
|
|
||||||
ANY,
|
|
||||||
Pair("Ativo", "0"),
|
|
||||||
Pair("Completo", "1"),
|
|
||||||
Pair("Cancelado", "2"),
|
|
||||||
Pair("Hiato", "3"),
|
|
||||||
)
|
|
||||||
}
|
|
|
@ -1,41 +0,0 @@
|
||||||
package eu.kanade.tachiyomi.extension.pt.tsukimangas
|
|
||||||
|
|
||||||
import android.app.Activity
|
|
||||||
import android.content.ActivityNotFoundException
|
|
||||||
import android.content.Intent
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.util.Log
|
|
||||||
import kotlin.system.exitProcess
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Springboard that accepts https://tsuki-mangas.com/obra/<id>/<item> intents
|
|
||||||
* and redirects them to the main Tachiyomi process.
|
|
||||||
*/
|
|
||||||
class TsukiMangasUrlActivity : Activity() {
|
|
||||||
|
|
||||||
private val tag = javaClass.simpleName
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
|
||||||
super.onCreate(savedInstanceState)
|
|
||||||
val pathSegments = intent?.data?.pathSegments
|
|
||||||
if (pathSegments != null && pathSegments.size > 1) {
|
|
||||||
val id = pathSegments[1]
|
|
||||||
val mainIntent = Intent().apply {
|
|
||||||
action = "eu.kanade.tachiyomi.SEARCH"
|
|
||||||
putExtra("query", "${TsukiMangas.PREFIX_SEARCH}$id")
|
|
||||||
putExtra("filter", packageName)
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
startActivity(mainIntent)
|
|
||||||
} catch (e: ActivityNotFoundException) {
|
|
||||||
Log.e(tag, e.toString())
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Log.e(tag, "could not parse uri from intent $intent")
|
|
||||||
}
|
|
||||||
|
|
||||||
finish()
|
|
||||||
exitProcess(0)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,70 +0,0 @@
|
||||||
package eu.kanade.tachiyomi.extension.pt.tsukimangas.dto
|
|
||||||
|
|
||||||
import kotlinx.serialization.SerialName
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class MangaListDto(
|
|
||||||
val data: List<SimpleMangaDto>,
|
|
||||||
val page: Int,
|
|
||||||
val lastPage: Int,
|
|
||||||
)
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class SimpleMangaDto(
|
|
||||||
val id: Int,
|
|
||||||
@SerialName("url") val slug: String,
|
|
||||||
val title: String,
|
|
||||||
val poster: String? = null,
|
|
||||||
val cover: String? = null,
|
|
||||||
) {
|
|
||||||
val imagePath = "/img/imgs/${poster ?: cover ?: "nobackground.jpg"}"
|
|
||||||
val entryPath = "/$id/$slug"
|
|
||||||
}
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class CompleteMangaDto(
|
|
||||||
val id: Int,
|
|
||||||
@SerialName("url") val slug: String,
|
|
||||||
|
|
||||||
val title: String,
|
|
||||||
val poster: String? = null,
|
|
||||||
val cover: String? = null,
|
|
||||||
val status: String? = null,
|
|
||||||
val synopsis: String? = null,
|
|
||||||
val staff: String? = null,
|
|
||||||
val genres: List<Genre> = emptyList(),
|
|
||||||
val titles: List<Title> = emptyList(),
|
|
||||||
) {
|
|
||||||
val entryPath = "/$id/$slug"
|
|
||||||
|
|
||||||
val imagePath = "/img/imgs/${poster ?: cover ?: "nobackground.jpg"}"
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class Genre(val genre: String)
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class Title(val title: String)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class ChapterListDto(val chapters: List<ChapterDto>)
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class ChapterDto(
|
|
||||||
val number: String,
|
|
||||||
val title: String? = null,
|
|
||||||
val created_at: String? = null,
|
|
||||||
private val versions: List<Version>,
|
|
||||||
) {
|
|
||||||
@Serializable
|
|
||||||
data class Version(val id: Int)
|
|
||||||
|
|
||||||
val versionId = versions.first().id
|
|
||||||
}
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class PageListDto(val pages: List<PageDto>)
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class PageDto(val url: String)
|
|
Loading…
Reference in New Issue