fix(es/cuevana): Change domain (#2016)

This commit is contained in:
imper1aldev
2023-08-05 18:29:58 -06:00
committed by GitHub
parent c7c6f4403f
commit c7902b38ae
3 changed files with 79 additions and 69 deletions

View File

@ -5,7 +5,7 @@ ext {
extName = 'Cuevana' extName = 'Cuevana'
pkgNameSuffix = 'es.cuevana' pkgNameSuffix = 'es.cuevana'
extClass = '.Cuevana' extClass = '.Cuevana'
extVersionCode = 17 extVersionCode = 18
libVersion = '13' libVersion = '13'
} }
@ -15,6 +15,8 @@ dependencies {
implementation project(path: ':lib-streamsb-extractor') implementation project(path: ':lib-streamsb-extractor')
implementation project(path: ':lib-okru-extractor') implementation project(path: ':lib-okru-extractor')
implementation project(path: ':lib-voe-extractor') implementation project(path: ':lib-voe-extractor')
implementation project(path: ':lib-streamtape-extractor')
implementation "dev.datlag.jsunpacker:jsunpacker:1.0.1"
} }
apply from: "$rootDir/common.gradle" apply from: "$rootDir/common.gradle"

View File

@ -4,6 +4,7 @@ import android.app.Application
import android.content.SharedPreferences import android.content.SharedPreferences
import androidx.preference.ListPreference import androidx.preference.ListPreference
import androidx.preference.PreferenceScreen import androidx.preference.PreferenceScreen
import eu.kanade.tachiyomi.animeextension.es.cuevana.extractors.StreamWishExtractor
import eu.kanade.tachiyomi.animesource.ConfigurableAnimeSource import eu.kanade.tachiyomi.animesource.ConfigurableAnimeSource
import eu.kanade.tachiyomi.animesource.model.AnimeFilter import eu.kanade.tachiyomi.animesource.model.AnimeFilter
import eu.kanade.tachiyomi.animesource.model.AnimeFilterList import eu.kanade.tachiyomi.animesource.model.AnimeFilterList
@ -14,6 +15,7 @@ import eu.kanade.tachiyomi.animesource.online.ParsedAnimeHttpSource
import eu.kanade.tachiyomi.lib.doodextractor.DoodExtractor import eu.kanade.tachiyomi.lib.doodextractor.DoodExtractor
import eu.kanade.tachiyomi.lib.okruextractor.OkruExtractor import eu.kanade.tachiyomi.lib.okruextractor.OkruExtractor
import eu.kanade.tachiyomi.lib.streamsbextractor.StreamSBExtractor import eu.kanade.tachiyomi.lib.streamsbextractor.StreamSBExtractor
import eu.kanade.tachiyomi.lib.streamtapeextractor.StreamTapeExtractor
import eu.kanade.tachiyomi.lib.voeextractor.VoeExtractor import eu.kanade.tachiyomi.lib.voeextractor.VoeExtractor
import eu.kanade.tachiyomi.lib.youruploadextractor.YourUploadExtractor import eu.kanade.tachiyomi.lib.youruploadextractor.YourUploadExtractor
import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.GET
@ -22,10 +24,8 @@ import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonObject import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.jsonPrimitive import kotlinx.serialization.json.jsonPrimitive
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.Request import okhttp3.Request
import okhttp3.RequestBody.Companion.toRequestBody
import okhttp3.Response import okhttp3.Response
import org.jsoup.nodes.Document import org.jsoup.nodes.Document
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
@ -38,7 +38,7 @@ class Cuevana : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
override val name = "Cuevana" override val name = "Cuevana"
override val baseUrl = "https://n2.cuevana3.me" override val baseUrl = "https://www12.cuevana3.ch"
override val lang = "es" override val lang = "es"
@ -52,15 +52,15 @@ class Cuevana : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000) Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
} }
override fun popularAnimeSelector(): String = "section li.xxx.TPostMv div.TPost" override fun popularAnimeSelector(): String = ".MovieList .TPostMv .TPost"
override fun popularAnimeRequest(page: Int): Request = GET("$baseUrl/peliculas/page/$page") override fun popularAnimeRequest(page: Int): Request = GET("$baseUrl/peliculas?page=$page")
override fun popularAnimeFromElement(element: Element): SAnime { override fun popularAnimeFromElement(element: Element): SAnime {
val anime = SAnime.create() val anime = SAnime.create()
anime.setUrlWithoutDomain(element.selectFirst("a")!!.attr("href")) anime.setUrlWithoutDomain(element.selectFirst("a")!!.attr("href"))
anime.title = element.select("a .Title").text() anime.title = element.select("a .Title").text()
anime.thumbnail_url = element.select("a .Image figure.Objf img").attr("data-src") anime.thumbnail_url = element.select("a .Image figure.Objf img").attr("abs:data-src")
return anime return anime
} }
@ -70,13 +70,13 @@ class Cuevana : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
val episodes = mutableListOf<SEpisode>() val episodes = mutableListOf<SEpisode>()
val document = response.asJsoup() val document = response.asJsoup()
if (response.request.url.toString().contains("/serie/")) { if (response.request.url.toString().contains("/serie/")) {
document.select("[id*=season-]").mapIndexed { idxSeason, season -> document.select("[id*=season-]").reversed().mapIndexed { idxSeason, season ->
val noSeason = try { val noSeason = try {
season.attr("id").substringAfter("season-").toInt() season.attr("id").substringAfter("season-").toInt()
} catch (e: Exception) { } catch (e: Exception) {
idxSeason idxSeason
} }
season.select(".TPostMv article.TPost").mapIndexed { idxCap, cap -> season.select(".TPostMv article.TPost").reversed().mapIndexed { idxCap, cap ->
val epNum = try { cap.select("a div.Image span.Year").text().substringAfter("x").toFloat() } catch (e: Exception) { idxCap.toFloat() } val epNum = try { cap.select("a div.Image span.Year").text().substringAfter("x").toFloat() } catch (e: Exception) { idxCap.toFloat() }
val episode = SEpisode.create() val episode = SEpisode.create()
val date = cap.select("a > p").text() val date = cap.select("a > p").text()
@ -90,8 +90,7 @@ class Cuevana : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
} }
} else { } else {
val episode = SEpisode.create().apply { val episode = SEpisode.create().apply {
val epnum = 1 episode_number = 1f
episode_number = epnum.toFloat()
name = "PELÍCULA" name = "PELÍCULA"
} }
episode.setUrlWithoutDomain(response.request.url.toString()) episode.setUrlWithoutDomain(response.request.url.toString())
@ -107,13 +106,12 @@ class Cuevana : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
override fun videoListParse(response: Response): List<Video> { override fun videoListParse(response: Response): List<Video> {
val document = response.asJsoup() val document = response.asJsoup()
val videoList = mutableListOf<Video>() val videoList = mutableListOf<Video>()
document.select("div.TPlayer.embed_div iframe").map { document.select("ul.anime_muti_link li").map {
val langPrefix = try { val langPrefix = try {
val optLanguage = it.parent()!!.attr("id") val languageTag = it.selectFirst(".cdtr span")!!.text()
val languageTag = document.selectFirst("li[data-tplayernv=$optLanguage]")!!.closest(".open_submenu")!!.selectFirst("div:first-child")!!.text()
if (languageTag.lowercase().contains("latino")) { if (languageTag.lowercase().contains("latino")) {
"[LAT]" "[LAT]"
} else if (languageTag.lowercase().contains("españa")) { } else if (languageTag.lowercase().contains("castellano")) {
"[CAST]" "[CAST]"
} else if (languageTag.lowercase().contains("subtitulado")) { } else if (languageTag.lowercase().contains("subtitulado")) {
"[SUB]" "[SUB]"
@ -121,53 +119,12 @@ class Cuevana : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
"" ""
} }
} catch (e: Exception) { "" } } catch (e: Exception) { "" }
val regIsUrl = "https?:\\/\\/(www\\.)?[-a-zA-Z0-9@:%._\\+~#=]{1,256}\\.[a-zA-Z0-9()]{1,6}\\b([-a-zA-Z0-9()@:%_\\+.~#?&//=]*)".toRegex() val url = it.attr("abs:data-video")
val iframe = urlServerSolver(it.attr("data-src")) try {
if (iframe.contains("apialfa.tomatomatela.club")) { loadExtractor(url, langPrefix).map { video -> videoList.add(video) }
try { } catch (_: Exception) { }
val tomkey = iframe.substringAfter("?h=")
val clientGoTo = OkHttpClient().newBuilder().build()
val mediaType = "application/x-www-form-urlencoded".toMediaType()
val bodyGoTo = "url=$tomkey".toRequestBody(mediaType)
val requestGoTo = Request.Builder()
.url("https://apialfa.tomatomatela.club/ir/rd.php")
.method("POST", bodyGoTo)
.addHeader("Host", "apialfa.tomatomatela.club")
.addHeader(
"User-Agent",
"Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:96.0) Gecko/20100101 Firefox/96.0",
)
.addHeader(
"Accept",
"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
)
.addHeader("Accept-Language", "en-US,en;q=0.5")
.addHeader("Content-Type", "application/x-www-form-urlencoded")
.addHeader("Origin", "null")
.addHeader("DNT", "1")
.addHeader("Connection", "keep-alive")
.addHeader("Upgrade-Insecure-Requests", "1")
.addHeader("Sec-Fetch-Dest", "iframe")
.addHeader("Sec-Fetch-Mode", "navigate")
.addHeader("Sec-Fetch-Site", "same-origin")
.build()
val responseGoto = clientGoTo.newCall(requestGoTo).execute()
val locations = responseGoto!!.networkResponse.toString()
fetchUrls(locations).map {
if (!it.contains("ir/rd.php")) {
loadExtractor(it, langPrefix).map { video -> videoList.add(video) }
}
}
} catch (e: Exception) { }
}
if (regIsUrl.containsMatchIn(iframe) &&
!iframe.contains("apialfa.tomatomatela.club")
) {
try {
loadExtractor(iframe, langPrefix).map { video -> videoList.add(video) }
} catch (e: Exception) { }
}
} }
return videoList return videoList
} }
@ -197,7 +154,7 @@ class Cuevana : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
val status = json["status"]!!.jsonPrimitive!!.content val status = json["status"]!!.jsonPrimitive!!.content
val file = json["file"]!!.jsonPrimitive!!.content val file = json["file"]!!.jsonPrimitive!!.content
if (status == "200") { videoList.add(Video(file, "$prefix Tomatomatela", file, headers = null)) } if (status == "200") { videoList.add(Video(file, "$prefix Tomatomatela", file, headers = null)) }
} catch (e: Exception) { } } catch (_: Exception) { }
} }
if (embedUrl.contains("yourupload")) { if (embedUrl.contains("yourupload")) {
val videos = YourUploadExtractor(client).videoFromUrl(url, headers = headers) val videos = YourUploadExtractor(client).videoFromUrl(url, headers = headers)
@ -227,7 +184,13 @@ class Cuevana : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
) )
} }
if (embedUrl.contains("voe")) { if (embedUrl.contains("voe")) {
VoeExtractor(client).videoFromUrl(url)?.let { videoList.add(it) } VoeExtractor(client).videoFromUrl(url, "$prefix Voe")?.let { videoList.add(it) }
}
if (embedUrl.contains("streamtape")) {
StreamTapeExtractor(client).videoFromUrl(url, "$prefix StreamTape")?.let { videoList.add(it) }
}
if (embedUrl.contains("wishembed") || embedUrl.contains("streamwish") || embedUrl.contains("wish")) {
StreamWishExtractor(client, headers).videosFromUrl(url, "$prefix StreamWish:")?.let { videoList.addAll(it) }
} }
return videoList return videoList
} }
@ -272,8 +235,8 @@ class Cuevana : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
val genreFilter = filterList.find { it is GenreFilter } as GenreFilter val genreFilter = filterList.find { it is GenreFilter } as GenreFilter
return when { return when {
query.isNotBlank() -> GET("$baseUrl/page/$page?s=$query", headers) query.isNotBlank() -> GET("$baseUrl/search.html?keyword=$query&page=$page", headers)
genreFilter.state != 0 -> GET("$baseUrl/category/${genreFilter.toUriPart()}/page/$page") genreFilter.state != 0 -> GET("$baseUrl/category/${genreFilter.toUriPart()}?page=$page")
else -> popularAnimeRequest(page) else -> popularAnimeRequest(page)
} }
} }
@ -288,10 +251,10 @@ class Cuevana : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
override fun animeDetailsParse(document: Document): SAnime { override fun animeDetailsParse(document: Document): SAnime {
val anime = SAnime.create() val anime = SAnime.create()
anime.title = document.selectFirst("#top-single div.backdrop article.TPost header .Title")!!.text() anime.title = document.selectFirst(".TPost header .Title")!!.text()
anime.thumbnail_url = document.selectFirst("#top-single div.backdrop article div.Image figure img")!!.attr("data-src") anime.thumbnail_url = document.selectFirst(".backdrop article div.Image figure img")!!.attr("abs:data-src")
anime.description = document.selectFirst("#top-single div.backdrop article.TPost div.Description")!!.text().trim() anime.description = document.selectFirst(".backdrop article.TPost div.Description")!!.text().trim()
anime.genre = document.select("#MvTb-Info ul.InfoList li:nth-child(2) > a").joinToString { it.text() } anime.genre = document.select("ul.InfoList li:nth-child(1) > a").joinToString { it.text() }
anime.status = SAnime.UNKNOWN anime.status = SAnime.UNKNOWN
return anime return anime
} }

View File

@ -0,0 +1,45 @@
package eu.kanade.tachiyomi.animeextension.es.cuevana.extractors
import dev.datlag.jsunpacker.JsUnpacker
import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.util.asJsoup
import okhttp3.Headers
import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.OkHttpClient
class StreamWishExtractor(private val client: OkHttpClient, private val headers: Headers) {
fun videosFromUrl(url: String, prefix: String): List<Video> {
val videoList = mutableListOf<Video>()
val doc = client.newCall(GET(url, headers = headers)).execute().asJsoup()
val jsEval = doc.selectFirst("script:containsData(m3u8)")?.data() ?: "UwU"
val masterUrl = JsUnpacker.unpackAndCombine(jsEval)
?.substringAfter("source")
?.substringAfter("file:\"")
?.substringBefore("\"")
?: return emptyList()
val playlistHeaders = headers.newBuilder()
.add("Accept", "*/*")
.add("Host", masterUrl.toHttpUrl().host)
.add("Origin", "https://${url.toHttpUrl().host}")
.set("Referer", "https://${url.toHttpUrl().host}/")
.build()
val masterBase = "https://${masterUrl.toHttpUrl().host}${masterUrl.toHttpUrl().encodedPath}"
.substringBeforeLast("/") + "/"
val masterPlaylist = client.newCall(
GET(masterUrl, headers = playlistHeaders),
).execute().body.string()
val separator = "#EXT-X-STREAM-INF:"
masterPlaylist.substringAfter(separator).split(separator).forEach {
val quality = prefix + it.substringAfter("RESOLUTION=").substringAfter("x").substringBefore(",") + "p "
val videoUrl = masterBase + it.substringAfter("\n").substringBefore("\n")
videoList.add(Video(videoUrl, quality, videoUrl, headers = playlistHeaders))
}
return videoList
}
}