forked from AlmightyHak/extensions-source
fix(pt/animeszone): Removed dead source Animes Zone (#606)
This commit is contained in:
parent
41e37c016f
commit
a0ec79cd9d
13 changed files with 0 additions and 840 deletions
|
@ -1,23 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
|
|
||||||
<application>
|
|
||||||
<activity
|
|
||||||
android:name=".pt.animeszone.AZUrlActivity"
|
|
||||||
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="animeszone.net"
|
|
||||||
android:pathPattern="/..*/..*"
|
|
||||||
android:scheme="https" />
|
|
||||||
</intent-filter>
|
|
||||||
</activity>
|
|
||||||
</application>
|
|
||||||
</manifest>
|
|
|
@ -1,12 +0,0 @@
|
||||||
ext {
|
|
||||||
extName = 'AnimesZone'
|
|
||||||
extClass = '.AnimesZone'
|
|
||||||
extVersionCode = 8
|
|
||||||
isNsfw = true
|
|
||||||
}
|
|
||||||
|
|
||||||
apply from: "$rootDir/common.gradle"
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
implementation(project(':lib:dood-extractor'))
|
|
||||||
}
|
|
Binary file not shown.
Before Width: | Height: | Size: 4.2 KiB |
Binary file not shown.
Before Width: | Height: | Size: 2.2 KiB |
Binary file not shown.
Before Width: | Height: | Size: 6.1 KiB |
Binary file not shown.
Before Width: | Height: | Size: 11 KiB |
Binary file not shown.
Before Width: | Height: | Size: 17 KiB |
Binary file not shown.
Before Width: | Height: | Size: 100 KiB |
|
@ -1,42 +0,0 @@
|
||||||
package eu.kanade.tachiyomi.animeextension.pt.animeszone
|
|
||||||
|
|
||||||
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://animeszone.net/<type>/<slug> intents
|
|
||||||
* and redirects them to the main Aniyomi process.
|
|
||||||
*/
|
|
||||||
class AZUrlActivity : 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 searchQuery = "${pathSegments[0]}/${pathSegments[1]}"
|
|
||||||
|
|
||||||
val mainIntent = Intent().apply {
|
|
||||||
action = "eu.kanade.tachiyomi.ANIMESEARCH"
|
|
||||||
putExtra("query", "${AnimesZone.PREFIX_SEARCH}$searchQuery")
|
|
||||||
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,439 +0,0 @@
|
||||||
package eu.kanade.tachiyomi.animeextension.pt.animeszone
|
|
||||||
|
|
||||||
import android.app.Application
|
|
||||||
import androidx.preference.ListPreference
|
|
||||||
import androidx.preference.PreferenceScreen
|
|
||||||
import app.cash.quickjs.QuickJs
|
|
||||||
import eu.kanade.tachiyomi.animeextension.pt.animeszone.extractors.BloggerJWPlayerExtractor
|
|
||||||
import eu.kanade.tachiyomi.animeextension.pt.animeszone.extractors.PlaylistExtractor
|
|
||||||
import eu.kanade.tachiyomi.animesource.ConfigurableAnimeSource
|
|
||||||
import eu.kanade.tachiyomi.animesource.model.AnimeFilterList
|
|
||||||
import eu.kanade.tachiyomi.animesource.model.AnimesPage
|
|
||||||
import eu.kanade.tachiyomi.animesource.model.SAnime
|
|
||||||
import eu.kanade.tachiyomi.animesource.model.SEpisode
|
|
||||||
import eu.kanade.tachiyomi.animesource.model.Video
|
|
||||||
import eu.kanade.tachiyomi.animesource.online.ParsedAnimeHttpSource
|
|
||||||
import eu.kanade.tachiyomi.lib.doodextractor.DoodExtractor
|
|
||||||
import eu.kanade.tachiyomi.network.GET
|
|
||||||
import eu.kanade.tachiyomi.network.POST
|
|
||||||
import eu.kanade.tachiyomi.network.awaitSuccess
|
|
||||||
import eu.kanade.tachiyomi.util.asJsoup
|
|
||||||
import eu.kanade.tachiyomi.util.parseAs
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
import kotlinx.serialization.json.Json
|
|
||||||
import okhttp3.MediaType.Companion.toMediaType
|
|
||||||
import okhttp3.Request
|
|
||||||
import okhttp3.RequestBody.Companion.toRequestBody
|
|
||||||
import okhttp3.Response
|
|
||||||
import org.jsoup.Jsoup
|
|
||||||
import org.jsoup.nodes.Document
|
|
||||||
import org.jsoup.nodes.Element
|
|
||||||
import uy.kohesive.injekt.Injekt
|
|
||||||
import uy.kohesive.injekt.api.get
|
|
||||||
import uy.kohesive.injekt.injectLazy
|
|
||||||
|
|
||||||
class AnimesZone : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
|
||||||
|
|
||||||
override val name = "AnimesZone"
|
|
||||||
|
|
||||||
override val baseUrl = "https://animeszone.net"
|
|
||||||
|
|
||||||
override val lang = "pt-BR"
|
|
||||||
|
|
||||||
override val supportsLatest = true
|
|
||||||
|
|
||||||
override fun headersBuilder() = super.headersBuilder()
|
|
||||||
.add("Referer", "$baseUrl/")
|
|
||||||
.add("Origin", baseUrl)
|
|
||||||
|
|
||||||
private val json: Json by injectLazy()
|
|
||||||
|
|
||||||
private val preferences by lazy {
|
|
||||||
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ============================== Popular ===============================
|
|
||||||
override fun popularAnimeRequest(page: Int): Request = GET("$baseUrl/tendencia/")
|
|
||||||
|
|
||||||
override fun popularAnimeSelector(): String = "div.items > div.seriesList"
|
|
||||||
|
|
||||||
override fun popularAnimeNextPageSelector(): String? = null
|
|
||||||
|
|
||||||
override fun popularAnimeFromElement(element: Element) = SAnime.create().apply {
|
|
||||||
setUrlWithoutDomain(element.selectFirst("a[href]")!!.attr("abs:href"))
|
|
||||||
thumbnail_url = element.selectFirst("div.cover-image")?.run {
|
|
||||||
attr("style").substringAfter("url('").substringBefore("'")
|
|
||||||
}
|
|
||||||
title = element.selectFirst("span.series-title")!!.text()
|
|
||||||
}
|
|
||||||
|
|
||||||
// =============================== Latest ===============================
|
|
||||||
override fun latestUpdatesRequest(page: Int): Request {
|
|
||||||
return if (page == 1) {
|
|
||||||
GET("$baseUrl/animes-legendados/")
|
|
||||||
} else {
|
|
||||||
GET("$baseUrl/animes-legendados/page/$page/")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun latestUpdatesSelector(): String = "main#list-animes ul.post-lst > li"
|
|
||||||
|
|
||||||
override fun latestUpdatesNextPageSelector(): String = "div.paginadorplay > a.active + a"
|
|
||||||
|
|
||||||
override fun latestUpdatesFromElement(element: Element) = SAnime.create().apply {
|
|
||||||
setUrlWithoutDomain(element.selectFirst("div.aniItem > a[href]")!!.attr("abs:href"))
|
|
||||||
thumbnail_url = element.selectFirst("div.aniItemImg img[src]")?.attr("abs:src")
|
|
||||||
title = element.selectFirst("h2.aniTitulo")!!.text()
|
|
||||||
}
|
|
||||||
|
|
||||||
// =============================== Search ===============================
|
|
||||||
override suspend fun getSearchAnime(page: Int, query: String, filters: AnimeFilterList): AnimesPage {
|
|
||||||
return if (query.startsWith(PREFIX_SEARCH)) {
|
|
||||||
val path = query.removePrefix(PREFIX_SEARCH)
|
|
||||||
client.newCall(GET("$baseUrl/$path"))
|
|
||||||
.awaitSuccess()
|
|
||||||
.use(::searchAnimeByIdParse)
|
|
||||||
} else {
|
|
||||||
super.getSearchAnime(page, query, filters)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun searchAnimeByIdParse(response: Response): AnimesPage {
|
|
||||||
val details = animeDetailsParse(response).apply {
|
|
||||||
setUrlWithoutDomain(response.request.url.toString())
|
|
||||||
initialized = true
|
|
||||||
}
|
|
||||||
|
|
||||||
return AnimesPage(listOf(details), false)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList): Request {
|
|
||||||
val params = AnimesZoneFilters.getSearchParameters(filters)
|
|
||||||
|
|
||||||
val cleanQuery = query.replace(" ", "%20")
|
|
||||||
val queryQuery = if (query.isBlank()) {
|
|
||||||
""
|
|
||||||
} else {
|
|
||||||
"&_pesquisa=$cleanQuery"
|
|
||||||
}
|
|
||||||
val url = "$baseUrl/?s=${params.genre}${params.year}${params.version}${params.studio}${params.type}${params.adult}$queryQuery"
|
|
||||||
|
|
||||||
val httpParams = url.substringAfter("$baseUrl/?").split("&").joinToString(",") {
|
|
||||||
val (key, value) = it.split("=", limit = 2)
|
|
||||||
"\"$key\":\"$value\""
|
|
||||||
}
|
|
||||||
val softRefresh = if (page == 1) 0 else 1
|
|
||||||
val jsonBody = """
|
|
||||||
{
|
|
||||||
"action":"facetwp_refresh",
|
|
||||||
"data":{
|
|
||||||
"facets":{
|
|
||||||
"generos":[
|
|
||||||
${queryToJsonList(params.genre)}
|
|
||||||
],
|
|
||||||
"versao":[
|
|
||||||
${queryToJsonList(params.year)}
|
|
||||||
],
|
|
||||||
"tipo":[
|
|
||||||
${queryToJsonList(params.version)}
|
|
||||||
],
|
|
||||||
"estudio":[
|
|
||||||
${queryToJsonList(params.studio)}
|
|
||||||
],
|
|
||||||
"tipototal":[
|
|
||||||
${queryToJsonList(params.type)}
|
|
||||||
],
|
|
||||||
"adulto":[
|
|
||||||
${queryToJsonList(params.adult)}
|
|
||||||
],
|
|
||||||
"pesquisa":"$query",
|
|
||||||
"paginar":[
|
|
||||||
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"frozen_facets":{
|
|
||||||
|
|
||||||
},
|
|
||||||
"http_params":{
|
|
||||||
"get":{
|
|
||||||
$httpParams
|
|
||||||
},
|
|
||||||
"uri":"",
|
|
||||||
"url_vars":[
|
|
||||||
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"template":"wp",
|
|
||||||
"extras":{
|
|
||||||
"sort":"default"
|
|
||||||
},
|
|
||||||
"soft_refresh":$softRefresh,
|
|
||||||
"is_bfcache":1,
|
|
||||||
"first_load":0,
|
|
||||||
"paged":$page
|
|
||||||
}
|
|
||||||
}
|
|
||||||
""".trimIndent().toRequestBody("application/json".toMediaType())
|
|
||||||
|
|
||||||
return POST(url, headers, jsonBody)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun searchAnimeParse(response: Response): AnimesPage {
|
|
||||||
val parsed = response.parseAs<PostResponse>()
|
|
||||||
|
|
||||||
val document = Jsoup.parse(parsed.template)
|
|
||||||
|
|
||||||
val animes = document.select(searchAnimeSelector()).map(::searchAnimeFromElement)
|
|
||||||
|
|
||||||
val hasNextPage = parsed.settings.pager.run { page < total_pages }
|
|
||||||
|
|
||||||
return AnimesPage(animes, hasNextPage)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun searchAnimeSelector(): String = "div.aniItem"
|
|
||||||
|
|
||||||
override fun searchAnimeNextPageSelector(): String? = null
|
|
||||||
|
|
||||||
override fun searchAnimeFromElement(element: Element) = SAnime.create().apply {
|
|
||||||
setUrlWithoutDomain(element.selectFirst("a[href]")!!.attr("href"))
|
|
||||||
thumbnail_url = element.selectFirst("img[src]")?.attr("abs:src")
|
|
||||||
title = element.selectFirst("div.aniInfos")?.text() ?: "Anime"
|
|
||||||
}
|
|
||||||
|
|
||||||
// ============================== FILTERS ===============================
|
|
||||||
override fun getFilterList(): AnimeFilterList = AnimesZoneFilters.FILTER_LIST
|
|
||||||
|
|
||||||
// =========================== Anime Details ============================
|
|
||||||
override fun animeDetailsParse(document: Document) = SAnime.create().apply {
|
|
||||||
title = document.selectFirst("div.container > div div.bottom-div > h4")?.ownText()
|
|
||||||
?: document.selectFirst("div#info > h1")?.text()
|
|
||||||
?: "Anime"
|
|
||||||
thumbnail_url = document.selectFirst("div.container > div > img[src]")?.attr("abs:src")
|
|
||||||
description = document.selectFirst("section#sinopse p:matches(.)")?.text()
|
|
||||||
?: document.selectFirst("div.content.right > dialog > p:matches(.)")?.text()
|
|
||||||
genre = document.select("div.card-body table > tbody > tr:has(>td:contains(Genres)) td > a").joinToString { it.text() }
|
|
||||||
}
|
|
||||||
|
|
||||||
// ============================== Episodes ==============================
|
|
||||||
override fun episodeListParse(response: Response): List<SEpisode> {
|
|
||||||
val document = response.asJsoup()
|
|
||||||
|
|
||||||
val singleVideo = document.selectFirst("div.anime__video__player")
|
|
||||||
|
|
||||||
// First check if single episode
|
|
||||||
return if (singleVideo != null) {
|
|
||||||
SEpisode.create().apply {
|
|
||||||
name = document.selectFirst("div#info h1")?.text() ?: "Episódio"
|
|
||||||
episode_number = 1F
|
|
||||||
setUrlWithoutDomain(document.location())
|
|
||||||
}.let(::listOf)
|
|
||||||
} else {
|
|
||||||
buildList {
|
|
||||||
document.select(episodeListSelector()).forEach { ep ->
|
|
||||||
val name = ep.selectFirst("h2.aniTitulo")?.text()?.trim()
|
|
||||||
// Check if it's multi-season
|
|
||||||
var nextPageUrl = when {
|
|
||||||
name != null && name.startsWith("temporada ", true) -> ep.selectFirst("a[href]")!!.attr("href")
|
|
||||||
else -> {
|
|
||||||
add(episodeFromElement(ep, size + 1))
|
|
||||||
document.nextPageUrl()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
while (nextPageUrl != null) {
|
|
||||||
val seasonDocument = client.newCall(GET(nextPageUrl)).execute()
|
|
||||||
.asJsoup()
|
|
||||||
|
|
||||||
seasonDocument.select(episodeListSelector()).forEach { seasonEp ->
|
|
||||||
add(episodeFromElement(seasonEp, size + 1, name))
|
|
||||||
}
|
|
||||||
|
|
||||||
nextPageUrl = seasonDocument.nextPageUrl()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
reverse()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun Document.nextPageUrl() = selectFirst("div.paginadorplay > a:contains(Próxima Pagina)")?.absUrl("href")
|
|
||||||
|
|
||||||
override fun episodeListSelector(): String = "main.site-main ul.post-lst > li"
|
|
||||||
|
|
||||||
private fun episodeFromElement(element: Element, counter: Int, info: String? = null): SEpisode {
|
|
||||||
val epTitle = element.selectFirst("div.title")?.text() ?: element.text()
|
|
||||||
val epNumber = element.selectFirst("span.epiTipo")
|
|
||||||
|
|
||||||
return SEpisode.create().apply {
|
|
||||||
name = "Ep. ${epNumber?.text()?.trim() ?: counter} - ${epTitle.replace(EPISODE_REGEX, "")}"
|
|
||||||
.replace(" - - ", " - ")
|
|
||||||
episode_number = epNumber?.run {
|
|
||||||
text().trim().toFloatOrNull()
|
|
||||||
} ?: counter.toFloat()
|
|
||||||
scanlator = info
|
|
||||||
setUrlWithoutDomain(element.selectFirst("article > a")!!.attr("href"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun episodeFromElement(element: Element): SEpisode = throw UnsupportedOperationException()
|
|
||||||
|
|
||||||
// ============================ Video Links =============================
|
|
||||||
override fun videoListParse(response: Response): List<Video> {
|
|
||||||
val document = response.asJsoup()
|
|
||||||
|
|
||||||
val videoList = document.select("div#playeroptions li[data-post]").flatMap { vid ->
|
|
||||||
val jsonHeaders = headersBuilder()
|
|
||||||
.add("Accept", "application/json, text/javascript, */*; q=0.01")
|
|
||||||
.add("X-Requested-With", "XMLHttpRequest")
|
|
||||||
.build()
|
|
||||||
|
|
||||||
val post = vid.attr("data-post")
|
|
||||||
val type = vid.attr("data-type")
|
|
||||||
val nume = vid.attr("data-nume")
|
|
||||||
|
|
||||||
val apires = client.newCall(
|
|
||||||
GET("$baseUrl/wp-json/dooplayer/v2/$post/$type/$nume", jsonHeaders),
|
|
||||||
).execute()
|
|
||||||
|
|
||||||
val url = apires.parseAs<VideoResponse>().embed_url
|
|
||||||
|
|
||||||
when {
|
|
||||||
url.startsWith("https://dood") -> DoodExtractor(client).videosFromUrl(url, vid.text().trim())
|
|
||||||
"https://gojopoolt" in url -> {
|
|
||||||
client.newCall(GET(url, headers)).execute()
|
|
||||||
.asJsoup()
|
|
||||||
.selectFirst("script:containsData(sources:)")
|
|
||||||
?.data()
|
|
||||||
?.let(BloggerJWPlayerExtractor::videosFromScript)
|
|
||||||
.orEmpty()
|
|
||||||
}
|
|
||||||
url.startsWith(baseUrl) -> videosFromInternalUrl(url)
|
|
||||||
"blogger.com" in url -> extractBloggerVideos(url, vid.text().trim())
|
|
||||||
else -> emptyList()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return videoList
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun videosFromInternalUrl(url: String): List<Video> {
|
|
||||||
val videoDocument = client.newCall(GET(url, headers)).execute()
|
|
||||||
.asJsoup()
|
|
||||||
|
|
||||||
val script = videoDocument.selectFirst("script:containsData(decodeURIComponent)")?.data()
|
|
||||||
?.let(::getDecrypted)
|
|
||||||
?: videoDocument.selectFirst("script:containsData(sources:)")?.data()
|
|
||||||
?: return emptyList()
|
|
||||||
|
|
||||||
return when {
|
|
||||||
"/bloggerjwplayer" in url || "jwplayer-2" in url || "/ctaplayer" in url -> {
|
|
||||||
BloggerJWPlayerExtractor.videosFromScript(script)
|
|
||||||
}
|
|
||||||
"/m3u8" in url -> PlaylistExtractor.videosFromScript(script)
|
|
||||||
else -> emptyList()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun extractBloggerVideos(url: String, name: String): List<Video> {
|
|
||||||
return client.newCall(GET(url, headers)).execute()
|
|
||||||
.body.string()
|
|
||||||
.takeIf { !it.contains("errorContainer") }
|
|
||||||
.let { it ?: return emptyList() }
|
|
||||||
.substringAfter("\"streams\":[")
|
|
||||||
.substringBefore("]")
|
|
||||||
.split("},")
|
|
||||||
.map {
|
|
||||||
val videoUrl = it.substringAfter("{\"play_url\":\"").substringBefore('"')
|
|
||||||
val format = it.substringAfter("\"format_id\":").substringBefore("}")
|
|
||||||
val quality = when (format) {
|
|
||||||
"18" -> "360p"
|
|
||||||
"22" -> "720p"
|
|
||||||
else -> "Unknown"
|
|
||||||
}
|
|
||||||
Video(videoUrl, "$quality - $name", videoUrl, headers = headers)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun videoFromElement(element: Element): Video = throw UnsupportedOperationException()
|
|
||||||
|
|
||||||
override fun videoListSelector(): String = throw UnsupportedOperationException()
|
|
||||||
|
|
||||||
override fun videoUrlParse(document: Document): String = throw UnsupportedOperationException()
|
|
||||||
|
|
||||||
// ============================== Settings ==============================
|
|
||||||
override fun setupPreferenceScreen(screen: PreferenceScreen) {
|
|
||||||
ListPreference(screen.context).apply {
|
|
||||||
key = PREF_QUALITY_KEY
|
|
||||||
title = PREF_QUALITY_TITLE
|
|
||||||
entries = PREF_QUALITY_ENTRIES
|
|
||||||
entryValues = PREF_QUALITY_VALUES
|
|
||||||
setDefaultValue(PREF_QUALITY_DEFAULT)
|
|
||||||
summary = "%s"
|
|
||||||
|
|
||||||
setOnPreferenceChangeListener { _, newValue ->
|
|
||||||
val selected = newValue as String
|
|
||||||
val index = findIndexOfValue(selected)
|
|
||||||
val entry = entryValues[index] as String
|
|
||||||
preferences.edit().putString(key, entry).commit()
|
|
||||||
}
|
|
||||||
}.also(screen::addPreference)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ============================= Utilities ==============================
|
|
||||||
private fun getDecrypted(script: String): String? {
|
|
||||||
val patchedScript = script.trim().split("\n").first()
|
|
||||||
.replace("eval(function", "function a")
|
|
||||||
.replace("decodeURIComponent(escape(r))}(", "r};a(")
|
|
||||||
.substringBeforeLast(")")
|
|
||||||
|
|
||||||
return QuickJs.create().use {
|
|
||||||
it.evaluate(patchedScript)?.toString()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun queryToJsonList(input: String): String {
|
|
||||||
if (input.isEmpty()) return ""
|
|
||||||
return input.substringAfter("=").split("%2C").joinToString(",") {
|
|
||||||
"\"$it\""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class VideoResponse(val embed_url: String)
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class PostResponse(
|
|
||||||
val template: String,
|
|
||||||
val settings: Settings,
|
|
||||||
) {
|
|
||||||
@Serializable
|
|
||||||
data class Settings(val pager: Pager) {
|
|
||||||
@Serializable
|
|
||||||
data class Pager(
|
|
||||||
val page: Int,
|
|
||||||
val total_pages: Int,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun List<Video>.sort(): List<Video> {
|
|
||||||
val quality = preferences.getString(PREF_QUALITY_KEY, PREF_QUALITY_DEFAULT)!!
|
|
||||||
|
|
||||||
return sortedWith(
|
|
||||||
compareBy { it.quality.contains(quality) },
|
|
||||||
).reversed()
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
const val PREFIX_SEARCH = "id:"
|
|
||||||
|
|
||||||
private val EPISODE_REGEX by lazy { Regex("""Episódio ?\d+\.?\d* ?""") }
|
|
||||||
|
|
||||||
private const val PREF_QUALITY_KEY = "preferred_quality"
|
|
||||||
private const val PREF_QUALITY_TITLE = "Qualidade preferida"
|
|
||||||
private const val PREF_QUALITY_DEFAULT = "720"
|
|
||||||
private val PREF_QUALITY_ENTRIES = arrayOf("1080p", "720p", "480p", "360p")
|
|
||||||
private val PREF_QUALITY_VALUES = arrayOf("1080", "720", "480", "360")
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,279 +0,0 @@
|
||||||
package eu.kanade.tachiyomi.animeextension.pt.animeszone
|
|
||||||
|
|
||||||
import eu.kanade.tachiyomi.animesource.model.AnimeFilter
|
|
||||||
import eu.kanade.tachiyomi.animesource.model.AnimeFilterList
|
|
||||||
|
|
||||||
object AnimesZoneFilters {
|
|
||||||
open class QueryPartFilter(
|
|
||||||
displayName: String,
|
|
||||||
val vals: Array<Pair<String, String>>,
|
|
||||||
) : AnimeFilter.Select<String>(
|
|
||||||
displayName,
|
|
||||||
vals.map { it.first }.toTypedArray(),
|
|
||||||
) {
|
|
||||||
fun toQueryPart() = vals[state].second
|
|
||||||
}
|
|
||||||
|
|
||||||
open class CheckBoxFilterList(name: String, values: List<CheckBox>) : AnimeFilter.Group<AnimeFilter.CheckBox>(name, values)
|
|
||||||
private class CheckBoxVal(name: String, state: Boolean = false) : AnimeFilter.CheckBox(name, state)
|
|
||||||
|
|
||||||
private inline fun <reified R> AnimeFilterList.asQueryPart(name: String): String {
|
|
||||||
return (first { it is R } as QueryPartFilter).toQueryPart()
|
|
||||||
.takeUnless(String::isEmpty)
|
|
||||||
?.let { "&$name=$it" }
|
|
||||||
.orEmpty()
|
|
||||||
}
|
|
||||||
|
|
||||||
private inline fun <reified R> AnimeFilterList.parseCheckbox(
|
|
||||||
options: Array<Pair<String, String>>,
|
|
||||||
name: String,
|
|
||||||
): String {
|
|
||||||
return (first { it is R } as CheckBoxFilterList).state
|
|
||||||
.asSequence()
|
|
||||||
.filter { it.state }
|
|
||||||
.map { checkbox -> options.find { it.first == checkbox.name }!!.second }
|
|
||||||
.filter(String::isNotBlank)
|
|
||||||
.joinToString("%2C") { "&$name=$it" }
|
|
||||||
}
|
|
||||||
|
|
||||||
class GenreFilter : CheckBoxFilterList(
|
|
||||||
"Selecionar Gêneros",
|
|
||||||
AnimesZoneFiltersData.GENRE.map { CheckBoxVal(it.first, false) },
|
|
||||||
)
|
|
||||||
|
|
||||||
class YearFilter : QueryPartFilter("Ano", AnimesZoneFiltersData.YEAR)
|
|
||||||
|
|
||||||
class VersionFilter : QueryPartFilter("Versão", AnimesZoneFiltersData.VERSION)
|
|
||||||
|
|
||||||
class StudioFilter : CheckBoxFilterList(
|
|
||||||
"Estudio",
|
|
||||||
AnimesZoneFiltersData.STUDIO.map { CheckBoxVal(it.first, false) },
|
|
||||||
)
|
|
||||||
|
|
||||||
class TypeFilter : QueryPartFilter("Tipo", AnimesZoneFiltersData.TYPE)
|
|
||||||
|
|
||||||
class AdultFilter : QueryPartFilter("Adulto", AnimesZoneFiltersData.ADULT)
|
|
||||||
|
|
||||||
val FILTER_LIST get() = AnimeFilterList(
|
|
||||||
GenreFilter(),
|
|
||||||
StudioFilter(),
|
|
||||||
YearFilter(),
|
|
||||||
VersionFilter(),
|
|
||||||
TypeFilter(),
|
|
||||||
AdultFilter(),
|
|
||||||
)
|
|
||||||
|
|
||||||
data class FilterSearchParams(
|
|
||||||
val genre: String = "",
|
|
||||||
val year: String = "",
|
|
||||||
val version: String = "",
|
|
||||||
val studio: String = "",
|
|
||||||
val type: String = "",
|
|
||||||
val adult: String = "",
|
|
||||||
)
|
|
||||||
|
|
||||||
internal fun getSearchParameters(filters: AnimeFilterList): FilterSearchParams {
|
|
||||||
if (filters.isEmpty()) return FilterSearchParams()
|
|
||||||
|
|
||||||
return FilterSearchParams(
|
|
||||||
filters.parseCheckbox<GenreFilter>(AnimesZoneFiltersData.GENRE, "_generos"),
|
|
||||||
filters.asQueryPart<YearFilter>("_versao"),
|
|
||||||
filters.asQueryPart<VersionFilter>("_tipo"),
|
|
||||||
filters.parseCheckbox<StudioFilter>(AnimesZoneFiltersData.STUDIO, "_estudio"),
|
|
||||||
filters.asQueryPart<TypeFilter>("_tipototal"),
|
|
||||||
filters.asQueryPart<AdultFilter>("_adulto"),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private object AnimesZoneFiltersData {
|
|
||||||
val ANY = Pair("Selecione", "")
|
|
||||||
|
|
||||||
val GENRE = arrayOf(
|
|
||||||
Pair("Comédia", "comedia"),
|
|
||||||
Pair("Ação", "acao"),
|
|
||||||
Pair("Fantasia", "fantasia"),
|
|
||||||
Pair("Romance", "romance"),
|
|
||||||
Pair("Drama", "drama"),
|
|
||||||
Pair("Escolar", "escolar"),
|
|
||||||
Pair("Aventura", "aventura"),
|
|
||||||
Pair("Shounen", "shounen"),
|
|
||||||
Pair("Sobrenatural", "sobrenatural"),
|
|
||||||
Pair("Slice-of-life", "slice-of-life"),
|
|
||||||
Pair("Sci-Fi", "sci-fi"),
|
|
||||||
Pair("Ecchi", "ecchi"),
|
|
||||||
Pair("Mistério", "misterio"),
|
|
||||||
Pair("Seinen", "seinen"),
|
|
||||||
Pair("Magia", "magia"),
|
|
||||||
Pair("Animação", "animacao"),
|
|
||||||
Pair("Harem", "harem"),
|
|
||||||
Pair("Psicológico", "psicologico"),
|
|
||||||
Pair("Super Poder", "super-poder"),
|
|
||||||
Pair("Violência", "violencia"),
|
|
||||||
Pair("Sci-Fi & Fantasy", "sci-fi-fantasy"),
|
|
||||||
Pair("Histórico", "historico"),
|
|
||||||
Pair("Isekai", "isekai"),
|
|
||||||
Pair("Mecha", "mecha"),
|
|
||||||
Pair("Demónio", "demonio"),
|
|
||||||
Pair("Terror", "terror"),
|
|
||||||
Pair("Esportes", "esportes"),
|
|
||||||
Pair("Militar", "militar"),
|
|
||||||
Pair("Artes Marciais", "artes-marciais"),
|
|
||||||
Pair("Jogo", "jogo"),
|
|
||||||
Pair("Vampiro", "vampiro"),
|
|
||||||
Pair("Musical", "musical"),
|
|
||||||
Pair("Suspense", "suspense"),
|
|
||||||
Pair("Paródia", "parodia"),
|
|
||||||
Pair("Shoujo", "shoujo"),
|
|
||||||
Pair("Nudez", "nudez"),
|
|
||||||
Pair("Supernatural", "supernatural"),
|
|
||||||
Pair("Espacial", "espacial"),
|
|
||||||
Pair("Shoujo-ai", "shoujo-ai"),
|
|
||||||
Pair("Crime", "crime"),
|
|
||||||
Pair("Policial", "policial"),
|
|
||||||
Pair("Ficção Científica", "ficcao-cientifica"),
|
|
||||||
Pair("Samurai", "samurai"),
|
|
||||||
Pair("Josei", "josei"),
|
|
||||||
Pair("Action & Adventure", "action-adventure"),
|
|
||||||
Pair("Amizade", "amizade"),
|
|
||||||
Pair("Horror", "horror"),
|
|
||||||
Pair("Família", "familia"),
|
|
||||||
Pair("Música", "musica"),
|
|
||||||
Pair("Insanidade", "insanidade"),
|
|
||||||
Pair("Obsceno", "obsceno"),
|
|
||||||
Pair("Shounen-ai", "shounen-ai"),
|
|
||||||
Pair("Carros", "carros"),
|
|
||||||
Pair("Gore", "gore"),
|
|
||||||
Pair("War & Politics", "war-politics"),
|
|
||||||
Pair("Yaoi", "yaoi"),
|
|
||||||
Pair("Cinema TV", "cinema-tv"),
|
|
||||||
Pair("Gourmet", "gourmet"),
|
|
||||||
Pair("Infantil", "infantil"),
|
|
||||||
Pair("Vida Escolar", "vida-escolar"),
|
|
||||||
)
|
|
||||||
|
|
||||||
val YEAR = arrayOf(ANY) + (1986..2024).map {
|
|
||||||
Pair(it.toString(), it.toString())
|
|
||||||
}.reversed().toTypedArray()
|
|
||||||
|
|
||||||
val VERSION = arrayOf(
|
|
||||||
ANY,
|
|
||||||
Pair("Legendados", "legendada"),
|
|
||||||
Pair("Dublado", "series02"),
|
|
||||||
Pair("Seção de Hentais", "series03"),
|
|
||||||
)
|
|
||||||
|
|
||||||
val STUDIO = arrayOf(
|
|
||||||
Pair("J.C.Staff", "j-c-staff"),
|
|
||||||
Pair("Shueisha", "shueisha"),
|
|
||||||
Pair("Aniplex", "aniplex"),
|
|
||||||
Pair("BONES", "bones"),
|
|
||||||
Pair("Kadokawa", "kadokawa"),
|
|
||||||
Pair("TOHO Animation", "toho-animation"),
|
|
||||||
Pair("Pony Canyon", "pony-canyon"),
|
|
||||||
Pair("A-1 Pictures", "a-1-pictures"),
|
|
||||||
Pair("DENTSU", "dentsu"),
|
|
||||||
Pair("Kodansha", "kodansha"),
|
|
||||||
Pair("Production I.G", "production-i-g"),
|
|
||||||
Pair("CloverWorks", "cloverworks"),
|
|
||||||
Pair("Madhouse", "madhouse"),
|
|
||||||
Pair("Bit grooove promotion", "bit-grooove-promotion"),
|
|
||||||
Pair("MAPPA", "mappa"),
|
|
||||||
Pair("SILVER LINK.", "silver-link"),
|
|
||||||
Pair("Wit Studio", "wit-studio"),
|
|
||||||
Pair("Magic Capsule", "magic-capsule"),
|
|
||||||
Pair("OLM", "olm"),
|
|
||||||
Pair("Lantis", "lantis"),
|
|
||||||
Pair("Movic", "movic"),
|
|
||||||
Pair("SATELIGHT", "satelight"),
|
|
||||||
Pair("Shogakukan-Shueisha Productions", "shogakukan-shueisha-productions"),
|
|
||||||
Pair("Square Enix", "square-enix"),
|
|
||||||
Pair("STUDIO MAUSU", "studio-mausu"),
|
|
||||||
Pair("Yomiuri Telecasting Corporation", "yomiuri-telecasting-corporation"),
|
|
||||||
Pair("Bandai Namco Arts", "bandai-namco-arts"),
|
|
||||||
Pair("David Production", "david-production"),
|
|
||||||
Pair("EGG FIRM", "egg-firm"),
|
|
||||||
Pair("Lerche", "lerche"),
|
|
||||||
Pair("Liden Films", "liden-films"),
|
|
||||||
Pair("Sony Music Entertainment", "sony-music-entertainment-japan"),
|
|
||||||
Pair("Studio Deen", "studio-deen"),
|
|
||||||
Pair("TMS Entertainment", "tms-entertainment"),
|
|
||||||
Pair("Toho", "toho"),
|
|
||||||
Pair("Crunchyroll", "crunchyroll"),
|
|
||||||
Pair("dugout", "dugout"),
|
|
||||||
Pair("ENGI", "engi"),
|
|
||||||
Pair("MBS", "mbs"),
|
|
||||||
Pair("P.A.Works", "p-a-works"),
|
|
||||||
Pair("Tezuka Productions", "tezuka-productions"),
|
|
||||||
Pair("TV Tokyo", "tv-tokyo"),
|
|
||||||
Pair("Warner Bros. Japan", "warner-bros-japan"),
|
|
||||||
Pair("White Fox", "white-fox"),
|
|
||||||
Pair("avex pictures", "avex-pictures"),
|
|
||||||
Pair("Bibury Animation Studios", "bibury-animation-studios"),
|
|
||||||
Pair("Brain's Base", "brains-base"),
|
|
||||||
Pair("DMM music", "dmm-music"),
|
|
||||||
Pair("DMM pictures", "dmm-pictures"),
|
|
||||||
Pair("feel.", "feel"),
|
|
||||||
Pair("Hakuhodo DY Music & Pictures", "hakuhodo-dy-music-pictures"),
|
|
||||||
Pair("Lidenfilms", "lidenfilms"),
|
|
||||||
Pair("MAHO FILM", "maho-film"),
|
|
||||||
Pair("NHK Enterprises", "nhk-enterprises"),
|
|
||||||
Pair("Passione", "passione"),
|
|
||||||
Pair("Pierrot", "pierrot"),
|
|
||||||
Pair("Pine Jam", "pine-jam"),
|
|
||||||
Pair("Pink Pineapple", "pink-pineapple"),
|
|
||||||
Pair("project No.9", "project-no-9"),
|
|
||||||
Pair("Seven", "seven"),
|
|
||||||
Pair("SHAFT", "shaft"),
|
|
||||||
Pair("TNK", "tnk"),
|
|
||||||
Pair("Zero-G", "zero-g"),
|
|
||||||
Pair("Asahi Production", "asahi-production"),
|
|
||||||
Pair("asread", "asread"),
|
|
||||||
Pair("AT-X", "at-x"),
|
|
||||||
Pair("Bandai Namco Pictures", "bandai-namco-pictures"),
|
|
||||||
Pair("BS Fuji", "bs-fuji"),
|
|
||||||
Pair("C2C", "c2c"),
|
|
||||||
Pair("Children's Playground Entertainment", "childrens-playground-entertainment"),
|
|
||||||
Pair("diomedéa", "diomedea"),
|
|
||||||
Pair("Doga Kobo", "doga-kobo"),
|
|
||||||
Pair("Geno Studio", "geno-studio"),
|
|
||||||
Pair("Good Smile Company", "good-smile-company"),
|
|
||||||
Pair("Graphinica", "graphinica"),
|
|
||||||
Pair("Hakusensha", "hakusensha"),
|
|
||||||
Pair("HALF H·P STUDIO", "f279ee47217fbae84c07eb11181f4997"),
|
|
||||||
Pair("King Records", "king-records"),
|
|
||||||
Pair("Kyoto Animation", "kyoto-animation"),
|
|
||||||
Pair("Nippon BS Broadcasting", "nippon-bs-broadcasting"),
|
|
||||||
Pair("Nippon Columbia", "nippon-columbia"),
|
|
||||||
Pair("Nitroplus", "nitroplus"),
|
|
||||||
Pair("Shogakukan", "shogakukan"),
|
|
||||||
Pair("Sotsu", "sotsu"),
|
|
||||||
Pair("Sound Team・Don Juan", "45e6f4604baaebfbebf4f43139db8d68"),
|
|
||||||
Pair("Studio Gokumi", "studio-gokumi"),
|
|
||||||
Pair("Suiseisha", "suiseisha"),
|
|
||||||
Pair("SUNRISE", "sunrise"),
|
|
||||||
Pair("SynergySP", "synergysp"),
|
|
||||||
Pair("Techno Sound", "techno-sound"),
|
|
||||||
Pair("THE KLOCKWORX", "the-klockworx"),
|
|
||||||
Pair("Toei Animation", "toei-animation"),
|
|
||||||
Pair("TOY'S FACTORY", "toys-factory"),
|
|
||||||
Pair("Twin Engine", "twin-engine"),
|
|
||||||
Pair("ufotable", "ufotable"),
|
|
||||||
Pair("ABC Animation", "abc-animation"),
|
|
||||||
Pair("Ajiado", "ajiado"),
|
|
||||||
Pair("APDREAM", "apdream"),
|
|
||||||
Pair("Ashi Productions", "ashi-productions"),
|
|
||||||
)
|
|
||||||
|
|
||||||
val TYPE = arrayOf(
|
|
||||||
ANY,
|
|
||||||
Pair("TV Shows", "tvshows"),
|
|
||||||
Pair("Filmes", "movies"),
|
|
||||||
)
|
|
||||||
|
|
||||||
val ADULT = arrayOf(
|
|
||||||
ANY,
|
|
||||||
Pair("Hentais", "dublada"),
|
|
||||||
Pair("Seção de Hentais", "series03"),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,27 +0,0 @@
|
||||||
package eu.kanade.tachiyomi.animeextension.pt.animeszone.extractors
|
|
||||||
|
|
||||||
import eu.kanade.tachiyomi.animesource.model.Video
|
|
||||||
|
|
||||||
object BloggerJWPlayerExtractor {
|
|
||||||
fun videosFromScript(script: String): List<Video> {
|
|
||||||
val sources = script.substringAfter("sources: [").substringBefore("],")
|
|
||||||
|
|
||||||
return sources.split("{").drop(1).mapNotNull {
|
|
||||||
val label = it.substringAfter("label")
|
|
||||||
.substringAfter(':')
|
|
||||||
.substringAfter('"')
|
|
||||||
.substringBefore('"')
|
|
||||||
|
|
||||||
val videoUrl = it.substringAfter("file")
|
|
||||||
.substringAfter(':')
|
|
||||||
.substringAfter('"')
|
|
||||||
.substringBefore('"')
|
|
||||||
.replace("\\", "")
|
|
||||||
if (videoUrl.isEmpty()) {
|
|
||||||
null
|
|
||||||
} else {
|
|
||||||
Video(videoUrl, "BloggerJWPlayer - $label", videoUrl)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,18 +0,0 @@
|
||||||
package eu.kanade.tachiyomi.animeextension.pt.animeszone.extractors
|
|
||||||
|
|
||||||
import eu.kanade.tachiyomi.animesource.model.Video
|
|
||||||
|
|
||||||
object PlaylistExtractor {
|
|
||||||
fun videosFromScript(script: String): List<Video> {
|
|
||||||
val sources = script.substringAfter("sources: [").substringBefore("],")
|
|
||||||
|
|
||||||
return sources.split("file:\"").drop(1).mapNotNull { source ->
|
|
||||||
val url = source.substringBefore("\"").ifEmpty { return@mapNotNull null }
|
|
||||||
val label = source.substringAfter("label:\"").substringBefore("\"")
|
|
||||||
.replace("FHD", "1080p")
|
|
||||||
.replace("HD", "720p")
|
|
||||||
.replace("SD", "480p")
|
|
||||||
Video(url, "Playlist - $label", url)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Add table
Add a link
Reference in a new issue