Remove VapoScans (#7218)
This commit is contained in:
parent
04fce0106a
commit
4193a3e304
|
@ -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.vaposcans.VapoScansUrlActivity"
|
|
||||||
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="vaposcans.site"
|
|
||||||
android:pathPattern="/series/..*"
|
|
||||||
android:scheme="https" />
|
|
||||||
</intent-filter>
|
|
||||||
</activity>
|
|
||||||
</application>
|
|
||||||
</manifest>
|
|
|
@ -1,7 +0,0 @@
|
||||||
ext {
|
|
||||||
extName = 'Vapo Scans'
|
|
||||||
extClass = '.VapoScans'
|
|
||||||
extVersionCode = 1
|
|
||||||
}
|
|
||||||
|
|
||||||
apply from: "$rootDir/common.gradle"
|
|
Binary file not shown.
Before Width: | Height: | Size: 4.3 KiB |
Binary file not shown.
Before Width: | Height: | Size: 2.3 KiB |
Binary file not shown.
Before Width: | Height: | Size: 6.2 KiB |
Binary file not shown.
Before Width: | Height: | Size: 11 KiB |
Binary file not shown.
Before Width: | Height: | Size: 16 KiB |
|
@ -1,198 +0,0 @@
|
||||||
package eu.kanade.tachiyomi.extension.pt.vaposcans
|
|
||||||
|
|
||||||
import eu.kanade.tachiyomi.network.POST
|
|
||||||
import eu.kanade.tachiyomi.network.interceptor.rateLimit
|
|
||||||
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.encodeToString
|
|
||||||
import kotlinx.serialization.json.Json
|
|
||||||
import okhttp3.MediaType.Companion.toMediaTypeOrNull
|
|
||||||
import okhttp3.Request
|
|
||||||
import okhttp3.RequestBody
|
|
||||||
import okhttp3.RequestBody.Companion.toRequestBody
|
|
||||||
import okhttp3.Response
|
|
||||||
import rx.Observable
|
|
||||||
import uy.kohesive.injekt.injectLazy
|
|
||||||
import java.text.SimpleDateFormat
|
|
||||||
import java.util.Calendar
|
|
||||||
import java.util.Locale
|
|
||||||
|
|
||||||
class VapoScans : HttpSource() {
|
|
||||||
override val name = "Vapo Scans"
|
|
||||||
|
|
||||||
override val baseUrl = "https://vaposcans.site"
|
|
||||||
|
|
||||||
override val lang = "pt-BR"
|
|
||||||
|
|
||||||
override val supportsLatest = true
|
|
||||||
|
|
||||||
override val client = network.cloudflareClient.newBuilder()
|
|
||||||
.rateLimit(2)
|
|
||||||
.build()
|
|
||||||
|
|
||||||
private val json: Json by injectLazy()
|
|
||||||
|
|
||||||
// Keeps the behavior of the web page
|
|
||||||
private val emptyPayload = "{}".toRequestBody()
|
|
||||||
|
|
||||||
private var popularMangaCache: List<SManga> = mutableListOf()
|
|
||||||
|
|
||||||
override fun headersBuilder() = super.headersBuilder()
|
|
||||||
.set("Origin", baseUrl)
|
|
||||||
.set("Referer", "$baseUrl/")
|
|
||||||
|
|
||||||
override fun popularMangaRequest(page: Int) =
|
|
||||||
POST("$apiUrl/api/series/", headers, emptyPayload)
|
|
||||||
|
|
||||||
override fun popularMangaParse(response: Response) =
|
|
||||||
MangasPage(
|
|
||||||
response.parseAs<List<MangaDto>>()
|
|
||||||
.map(::sMangaParse)
|
|
||||||
.also {
|
|
||||||
popularMangaCache = it
|
|
||||||
},
|
|
||||||
false,
|
|
||||||
)
|
|
||||||
|
|
||||||
override fun latestUpdatesRequest(page: Int) =
|
|
||||||
POST("$apiUrl/api/recent-chapters/", headers, emptyPayload)
|
|
||||||
|
|
||||||
override fun latestUpdatesParse(response: Response) =
|
|
||||||
MangasPage(
|
|
||||||
response.parseAs<List<LatestMangaDto>>()
|
|
||||||
.map { sMangaParse(it.mangaDto) },
|
|
||||||
false,
|
|
||||||
)
|
|
||||||
|
|
||||||
override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable<MangasPage> {
|
|
||||||
if (query.startsWith(URL_SEARCH_PREFIX)) {
|
|
||||||
val manga = SManga.create().apply {
|
|
||||||
url = query.substringAfter(URL_SEARCH_PREFIX)
|
|
||||||
}
|
|
||||||
|
|
||||||
return fetchMangaDetails(manga).map {
|
|
||||||
MangasPage(listOf(it), false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (popularMangaCache.isNotEmpty()) {
|
|
||||||
return Observable.just(findMangaByTitle(query))
|
|
||||||
}
|
|
||||||
|
|
||||||
return super.fetchSearchManga(page, query, filters)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun searchMangaRequest(page: Int, query: String, filters: FilterList) =
|
|
||||||
POST("$apiUrl/api/series/#$query", headers, emptyPayload)
|
|
||||||
|
|
||||||
override fun searchMangaParse(response: Response): MangasPage {
|
|
||||||
val mangas = popularMangaParse(response).mangas
|
|
||||||
val query = response.request.url.toString().substringAfter("#")
|
|
||||||
return findMangaByTitle(query, mangas)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getMangaUrl(manga: SManga): String = "$baseUrl/series/${manga.url}"
|
|
||||||
|
|
||||||
override fun mangaDetailsRequest(manga: SManga): Request {
|
|
||||||
val payload = MangaCode(manga.url).toRequestBody()
|
|
||||||
return POST("$apiUrl/api/serie/", headers, payload)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun mangaDetailsParse(response: Response) = SManga.create().apply {
|
|
||||||
response.parseAs<MangaDetailsDto>().let {
|
|
||||||
title = it.title
|
|
||||||
description = it.synopsis
|
|
||||||
url = it.code
|
|
||||||
genre = it.genres.joinToString()
|
|
||||||
artist = it.artist
|
|
||||||
author = it.author
|
|
||||||
thumbnail_url = it.cover
|
|
||||||
status = when (it.status) {
|
|
||||||
"completed" -> SManga.COMPLETED
|
|
||||||
"ongoing" -> SManga.ONGOING
|
|
||||||
else -> SManga.UNKNOWN
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getChapterUrl(chapter: SChapter) = "$baseUrl/reader/${chapter.url}"
|
|
||||||
|
|
||||||
override fun chapterListRequest(manga: SManga): Request {
|
|
||||||
val payload = MangaCode(manga.url).toRequestBody()
|
|
||||||
return POST("$apiUrl/api/serie/chapters/", headers, payload)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun chapterListParse(response: Response): List<SChapter> {
|
|
||||||
return response.parseAs<List<ChapterDto>>().map {
|
|
||||||
SChapter.create().apply {
|
|
||||||
name = it.number
|
|
||||||
url = it.code
|
|
||||||
date_upload = parseDate(it.upload_date)
|
|
||||||
chapter_number = it.number.toFloat()
|
|
||||||
}
|
|
||||||
}.sortedBy { it.chapter_number }.reversed()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun pageListRequest(chapter: SChapter): Request {
|
|
||||||
val payload = MangaCode(chapter.url).toRequestBody()
|
|
||||||
return POST("$apiUrl/api/chapter_details/", headers, payload)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun pageListParse(response: Response): List<Page> {
|
|
||||||
val dto = response.parseAs<PagesDto>()
|
|
||||||
val chapterUrl = "$baseUrl/reader/${dto.chapter_code}"
|
|
||||||
return dto.images.mapIndexed { index, image ->
|
|
||||||
Page(index, chapterUrl, "$apiUrl/$image")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun imageUrlParse(response: Response) = ""
|
|
||||||
|
|
||||||
private fun findMangaByTitle(query: String, collection: List<SManga> = popularMangaCache): MangasPage {
|
|
||||||
val mangas = collection
|
|
||||||
.filter { it.title.contains(query, ignoreCase = true) }
|
|
||||||
|
|
||||||
return MangasPage(mangas, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
private inline fun <reified T> Response.parseAs(): T =
|
|
||||||
json.decodeFromString(body.string())
|
|
||||||
|
|
||||||
private inline fun <reified T : Any> T.toRequestBody(): RequestBody =
|
|
||||||
json.encodeToString(this)
|
|
||||||
.toRequestBody(JSON_MEDIA_TYPE)
|
|
||||||
|
|
||||||
private fun sMangaParse(dto: MangaDto) = SManga.create().apply {
|
|
||||||
title = dto.title
|
|
||||||
thumbnail_url = "$apiUrl/${dto.cover}"
|
|
||||||
url = dto.code
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun parseDate(date: String): Long =
|
|
||||||
try { dateFormat.parse(date)!!.time } catch (_: Exception) { parseRelativeDate(date) }
|
|
||||||
|
|
||||||
private fun parseRelativeDate(date: String): Long {
|
|
||||||
val number = RELATIVE_DATE_REGEX.find(date)?.value?.toIntOrNull() ?: return 0
|
|
||||||
val cal = Calendar.getInstance()
|
|
||||||
return when {
|
|
||||||
date.contains("dia", ignoreCase = true) -> cal.apply { add(Calendar.DATE, -number) }.timeInMillis
|
|
||||||
date.contains("mes", ignoreCase = true) -> cal.apply { add(Calendar.MONTH, -number) }.timeInMillis
|
|
||||||
date.contains("ano", ignoreCase = true) -> cal.apply { add(Calendar.YEAR, -number) }.timeInMillis
|
|
||||||
else -> 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
const val apiUrl = "https://api.vaposcans.site"
|
|
||||||
const val URL_SEARCH_PREFIX = "slug:"
|
|
||||||
val JSON_MEDIA_TYPE = "application/json".toMediaTypeOrNull()
|
|
||||||
val RELATIVE_DATE_REGEX = """(\d+)""".toRegex()
|
|
||||||
|
|
||||||
val dateFormat = SimpleDateFormat("dd/MM/yyyy", Locale("pt", "BR"))
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,47 +0,0 @@
|
||||||
package eu.kanade.tachiyomi.extension.pt.vaposcans
|
|
||||||
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
class MangaDto(
|
|
||||||
val code: String,
|
|
||||||
val cover: String,
|
|
||||||
val title: String,
|
|
||||||
)
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
class LatestMangaDto(
|
|
||||||
val serie_code: String,
|
|
||||||
val serie_cover: String,
|
|
||||||
val serie_title: String,
|
|
||||||
) {
|
|
||||||
val mangaDto get() = MangaDto(serie_code, serie_cover, serie_title)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
class MangaCode(val code: String)
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
class MangaDetailsDto(
|
|
||||||
val artist: String,
|
|
||||||
val author: String,
|
|
||||||
val code: String,
|
|
||||||
val cover: String,
|
|
||||||
val genres: List<String>,
|
|
||||||
val status: String,
|
|
||||||
val synopsis: String,
|
|
||||||
val title: String,
|
|
||||||
)
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
class ChapterDto(
|
|
||||||
val number: String,
|
|
||||||
val code: String,
|
|
||||||
val upload_date: String,
|
|
||||||
)
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
class PagesDto(
|
|
||||||
val chapter_code: String,
|
|
||||||
val images: List<String>,
|
|
||||||
)
|
|
|
@ -1,37 +0,0 @@
|
||||||
package eu.kanade.tachiyomi.extension.pt.vaposcans
|
|
||||||
|
|
||||||
import android.app.Activity
|
|
||||||
import android.content.ActivityNotFoundException
|
|
||||||
import android.content.Intent
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.util.Log
|
|
||||||
import kotlin.system.exitProcess
|
|
||||||
|
|
||||||
class VapoScansUrlActivity : 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 item = pathSegments[1]
|
|
||||||
val mainIntent = Intent().apply {
|
|
||||||
action = "eu.kanade.tachiyomi.SEARCH"
|
|
||||||
putExtra("query", "${VapoScans.URL_SEARCH_PREFIX}$item")
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue