Spanish extension fixes (#138)

* Spanish extension fixes

Closes #134

* Fix bugs
This commit is contained in:
imper1aldev 2024-08-14 10:10:17 -06:00 committed by GitHub
parent c6456c8ff4
commit 2419e31671
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 74 additions and 92 deletions

View file

@ -34,7 +34,7 @@ class DoodExtractor(private val client: OkHttpClient) {
), ),
).execute().body.string() ).execute().body.string()
val videoUrl = "$videoUrlStart$randomString?token=$token&expiry=$expiry" val videoUrl = "$videoUrlStart$randomString?token=$token&expiry=$expiry"
Video(newUrl, newQuality, videoUrl, headers = doodHeaders(doodHost), subtitleTracks = externalSubs) Video(videoUrl, newQuality, videoUrl, headers = doodHeaders(doodHost), subtitleTracks = externalSubs)
}.getOrNull() }.getOrNull()
} }

View file

@ -1,7 +1,7 @@
ext { ext {
extName = 'Cuevana' extName = 'Cuevana'
extClass = '.CuevanaFactory' extClass = '.CuevanaFactory'
extVersionCode = 31 extVersionCode = 32
} }
apply from: "$rootDir/common.gradle" apply from: "$rootDir/common.gradle"

View file

@ -24,10 +24,7 @@ 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
import eu.kanade.tachiyomi.util.asJsoup import eu.kanade.tachiyomi.util.asJsoup
import eu.kanade.tachiyomi.util.parallelMapBlocking
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.jsonPrimitive
import okhttp3.Request import okhttp3.Request
import okhttp3.Response import okhttp3.Response
import org.jsoup.nodes.Document import org.jsoup.nodes.Document
@ -151,28 +148,28 @@ class CuevanaEu(override val name: String, override val baseUrl: String) : Confi
private fun serverIterator(videos: Videos?): MutableList<Video> { private fun serverIterator(videos: Videos?): MutableList<Video> {
val videoList = mutableListOf<Video>() val videoList = mutableListOf<Video>()
videos?.latino?.parallelMapBlocking { videos?.latino?.forEach {
try { try {
val body = client.newCall(GET(it.result!!)).execute().asJsoup() val body = client.newCall(GET(it.result!!)).execute().asJsoup()
val url = body.selectFirst("script:containsData(var message)")?.data()?.substringAfter("var url = '")?.substringBefore("'") ?: "" val url = body.selectFirst("script:containsData(var message)")?.data()?.substringAfter("var url = '")?.substringBefore("'") ?: ""
loadExtractor(url, "[LAT]").let { videoList.addAll(it) } loadExtractor(url, "[LAT]").let { videoList.addAll(it) }
} catch (_: Exception) { } } catch (_: Exception) { }
} }
videos?.spanish?.map { videos?.spanish?.forEach {
try { try {
val body = client.newCall(GET(it.result!!)).execute().asJsoup() val body = client.newCall(GET(it.result!!)).execute().asJsoup()
val url = body.selectFirst("script:containsData(var message)")?.data()?.substringAfter("var url = '")?.substringBefore("'") ?: "" val url = body.selectFirst("script:containsData(var message)")?.data()?.substringAfter("var url = '")?.substringBefore("'") ?: ""
loadExtractor(url, "[CAST]").let { videoList.addAll(it) } loadExtractor(url, "[CAST]").let { videoList.addAll(it) }
} catch (_: Exception) { } } catch (_: Exception) { }
} }
videos?.english?.map { videos?.english?.forEach {
try { try {
val body = client.newCall(GET(it.result!!)).execute().asJsoup() val body = client.newCall(GET(it.result!!)).execute().asJsoup()
val url = body.selectFirst("script:containsData(var message)")?.data()?.substringAfter("var url = '")?.substringBefore("'") ?: "" val url = body.selectFirst("script:containsData(var message)")?.data()?.substringAfter("var url = '")?.substringBefore("'") ?: ""
loadExtractor(url, "[ENG]").let { videoList.addAll(it) } loadExtractor(url, "[ENG]").let { videoList.addAll(it) }
} catch (_: Exception) { } } catch (_: Exception) { }
} }
videos?.japanese?.map { videos?.japanese?.forEach {
val body = client.newCall(GET(it.result!!)).execute().asJsoup() val body = client.newCall(GET(it.result!!)).execute().asJsoup()
val url = body.selectFirst("script:containsData(var message)")?.data()?.substringAfter("var url = '")?.substringBefore("'") ?: "" val url = body.selectFirst("script:containsData(var message)")?.data()?.substringAfter("var url = '")?.substringBefore("'") ?: ""
loadExtractor(url, "[JAP]").let { videoList.addAll(it) } loadExtractor(url, "[JAP]").let { videoList.addAll(it) }
@ -183,31 +180,6 @@ class CuevanaEu(override val name: String, override val baseUrl: String) : Confi
private fun loadExtractor(url: String, prefix: String = ""): List<Video> { private fun loadExtractor(url: String, prefix: String = ""): List<Video> {
val videoList = mutableListOf<Video>() val videoList = mutableListOf<Video>()
val embedUrl = url.lowercase() val embedUrl = url.lowercase()
if (embedUrl.contains("tomatomatela")) {
try {
val mainUrl = url.substringBefore("/embed.html#").substringAfter("https://")
val headers = headers.newBuilder()
.set("authority", mainUrl)
.set("accept", "application/json, text/javascript, */*; q=0.01")
.set("accept-language", "es-MX,es-419;q=0.9,es;q=0.8,en;q=0.7")
.set("sec-ch-ua", "\"Chromium\";v=\"106\", \"Google Chrome\";v=\"106\", \"Not;A=Brand\";v=\"99\"")
.set("sec-ch-ua-mobile", "?0")
.set("sec-ch-ua-platform", "Windows")
.set("sec-fetch-dest", "empty")
.set("sec-fetch-mode", "cors")
.set("sec-fetch-site", "same-origin")
.set("x-requested-with", "XMLHttpRequest")
.build()
val token = url.substringAfter("/embed.html#")
val urlRequest = "https://$mainUrl/details.php?v=$token"
val response = client.newCall(GET(urlRequest, headers = headers)).execute().asJsoup()
val bodyText = response.select("body").text()
val json = json.decodeFromString<JsonObject>(bodyText)
val status = json["status"]!!.jsonPrimitive!!.content
val file = json["file"]!!.jsonPrimitive!!.content
if (status == "200") { videoList.add(Video(file, "$prefix Tomatomatela", file, headers = null)) }
} 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)
videoList.addAll(videos) videoList.addAll(videos)

View file

@ -1,7 +1,7 @@
ext { ext {
extName = 'MetroSeries' extName = 'MetroSeries'
extClass = '.MetroSeries' extClass = '.MetroSeries'
extVersionCode = 9 extVersionCode = 10
} }
apply from: "$rootDir/common.gradle" apply from: "$rootDir/common.gradle"

View file

@ -49,6 +49,10 @@ class MetroSeries : ConfigurableAnimeSource, AnimeHttpSource() {
} }
companion object { companion object {
private const val PREF_LANGUAGE_KEY = "preferred_language"
private const val PREF_LANGUAGE_DEFAULT = "[LAT]"
private val LANGUAGE_LIST = arrayOf("[LAT]", "[SUB]", "[CAST]")
private const val PREF_QUALITY_KEY = "preferred_quality" private const val PREF_QUALITY_KEY = "preferred_quality"
private const val PREF_QUALITY_DEFAULT = "1080" private const val PREF_QUALITY_DEFAULT = "1080"
private val QUALITY_LIST = arrayOf("1080", "720", "480", "360") private val QUALITY_LIST = arrayOf("1080", "720", "480", "360")
@ -129,7 +133,7 @@ class MetroSeries : ConfigurableAnimeSource, AnimeHttpSource() {
return episodes return episodes
} }
private fun getDetailSeason(element: org.jsoup.nodes.Element, objectNumber: String, referer: String): IntRange { private fun getDetailSeason(element: Element, objectNumber: String, referer: String): IntRange {
try { try {
val post = element.attr("data-post") val post = element.attr("data-post")
val season = element.attr("data-season") val season = element.attr("data-season")
@ -189,6 +193,16 @@ class MetroSeries : ConfigurableAnimeSource, AnimeHttpSource() {
val videoList = mutableListOf<Video>() val videoList = mutableListOf<Video>()
val termId = document.select("#option-players").attr("data-term") val termId = document.select("#option-players").attr("data-term")
document.select(".player-options-list li a").forEach { document.select(".player-options-list li a").forEach {
val prefix = runCatching {
val lang = it.select(".option").text().lowercase()
when {
lang.contains("latino") -> "[LAT]"
lang.contains("castellano") -> "[CAST]"
lang.contains("sub") -> "[SUB]"
else -> ""
}
}.getOrDefault("")
val ide = it.attr("data-opt") val ide = it.attr("data-opt")
val formBody = FormBody.Builder() val formBody = FormBody.Builder()
.add("action", "action_player_series") .add("action", "action_player_series")
@ -217,29 +231,29 @@ class MetroSeries : ConfigurableAnimeSource, AnimeHttpSource() {
val key = src.split("/").last() val key = src.split("/").last()
src = "https://fastream.to/embed-$key.html" src = "https://fastream.to/embed-$key.html"
} }
FastreamExtractor(client, headers).videosFromUrl(src, needsSleep = false).also(videoList::addAll) FastreamExtractor(client, headers).videosFromUrl(src, needsSleep = false, prefix = "$prefix Fastream:").also(videoList::addAll)
} }
if (src.contains("upstream")) { if (src.contains("upstream")) {
UpstreamExtractor(client).videosFromUrl(src).let { videoList.addAll(it) } UpstreamExtractor(client).videosFromUrl(src, prefix = "$prefix ").let { videoList.addAll(it) }
} }
if (src.contains("yourupload")) { if (src.contains("yourupload")) {
YourUploadExtractor(client).videoFromUrl(src, headers).let { videoList.addAll(it) } YourUploadExtractor(client).videoFromUrl(src, headers, prefix = "$prefix ").let { videoList.addAll(it) }
} }
if (src.contains("voe")) { if (src.contains("voe")) {
VoeExtractor(client).videosFromUrl(src).also(videoList::addAll) VoeExtractor(client).videosFromUrl(src, prefix = "$prefix ").also(videoList::addAll)
} }
if (src.contains("wishembed") || src.contains("streamwish") || src.contains("wish")) { if (src.contains("wishembed") || src.contains("streamwish") || src.contains("wish")) {
StreamWishExtractor(client, headers).videosFromUrl(src) { "StreamWish:$it" }.also(videoList::addAll) StreamWishExtractor(client, headers).videosFromUrl(src) { "$prefix StreamWish:$it" }.also(videoList::addAll)
} }
if (src.contains("mp4upload")) { if (src.contains("mp4upload")) {
Mp4uploadExtractor(client).videosFromUrl(src, headers).let { videoList.addAll(it) } Mp4uploadExtractor(client).videosFromUrl(src, headers, prefix = "$prefix ").let { videoList.addAll(it) }
} }
if (src.contains("burst")) { if (src.contains("burst")) {
BurstCloudExtractor(client).videoFromUrl(src, headers = headers).let { videoList.addAll(it) } BurstCloudExtractor(client).videoFromUrl(src, headers = headers, prefix = "$prefix ").let { videoList.addAll(it) }
} }
if (src.contains("filemoon") || src.contains("moonplayer")) { if (src.contains("filemoon") || src.contains("moonplayer")) {
FilemoonExtractor(client).videosFromUrl(src, headers = headers, prefix = "Filemoon:").let { videoList.addAll(it) } FilemoonExtractor(client).videosFromUrl(src, headers = headers, prefix = "$prefix Filemoon:").let { videoList.addAll(it) }
} }
} catch (_: Exception) {} } catch (_: Exception) {}
} }
@ -250,8 +264,10 @@ class MetroSeries : ConfigurableAnimeSource, AnimeHttpSource() {
override fun List<Video>.sort(): List<Video> { override fun List<Video>.sort(): List<Video> {
val quality = preferences.getString(PREF_QUALITY_KEY, PREF_QUALITY_DEFAULT)!! val quality = preferences.getString(PREF_QUALITY_KEY, PREF_QUALITY_DEFAULT)!!
val server = preferences.getString(PREF_SERVER_KEY, PREF_SERVER_DEFAULT)!! val server = preferences.getString(PREF_SERVER_KEY, PREF_SERVER_DEFAULT)!!
val lang = preferences.getString(PREF_LANGUAGE_KEY, PREF_LANGUAGE_DEFAULT)!!
return this.sortedWith( return this.sortedWith(
compareBy( compareBy(
{ it.quality.contains(lang) },
{ it.quality.contains(server, true) }, { it.quality.contains(server, true) },
{ it.quality.contains(quality) }, { it.quality.contains(quality) },
{ Regex("""(\d+)p""").find(it.quality)?.groupValues?.get(1)?.toIntOrNull() ?: 0 }, { Regex("""(\d+)p""").find(it.quality)?.groupValues?.get(1)?.toIntOrNull() ?: 0 },
@ -260,6 +276,22 @@ class MetroSeries : ConfigurableAnimeSource, AnimeHttpSource() {
} }
override fun setupPreferenceScreen(screen: PreferenceScreen) { override fun setupPreferenceScreen(screen: PreferenceScreen) {
ListPreference(screen.context).apply {
key = PREF_LANGUAGE_KEY
title = "Preferred language"
entries = LANGUAGE_LIST
entryValues = LANGUAGE_LIST
setDefaultValue(PREF_LANGUAGE_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)
ListPreference(screen.context).apply { ListPreference(screen.context).apply {
key = PREF_QUALITY_KEY key = PREF_QUALITY_KEY
title = "Preferred quality" title = "Preferred quality"

View file

@ -1,7 +1,7 @@
ext { ext {
extName = 'Pelisplushd' extName = 'Pelisplushd'
extClass = '.PelisplushdFactory' extClass = '.PelisplushdFactory'
extVersionCode = 55 extVersionCode = 56
} }
apply from: "$rootDir/common.gradle" apply from: "$rootDir/common.gradle"

View file

@ -28,7 +28,6 @@ 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
import eu.kanade.tachiyomi.util.asJsoup import eu.kanade.tachiyomi.util.asJsoup
import eu.kanade.tachiyomi.util.parallelCatchingFlatMapBlocking
import okhttp3.HttpUrl.Companion.toHttpUrl import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.Request import okhttp3.Request
import okhttp3.Response import okhttp3.Response
@ -59,6 +58,9 @@ open class Pelisplushd(override val name: String, override val baseUrl: String)
"Upload", "BurstCloud", "Upstream", "StreamTape", "Amazon", "Upload", "BurstCloud", "Upstream", "StreamTape", "Amazon",
"Fastream", "Filemoon", "StreamWish", "Okru", "Streamlare", "Fastream", "Filemoon", "StreamWish", "Okru", "Streamlare",
) )
private val REGEX_LINK = "https?:\\/\\/(www\\.)?[-a-zA-Z0-9@:%._\\+~#=]{1,256}\\.[a-zA-Z0-9()]{1,6}\\b([-a-zA-Z0-9()@:%_\\+.~#?&//=]*)".toRegex()
private val REGEX_VIDEO_OPTS = "'(https?://[^']*)'".toRegex()
} }
override fun popularAnimeSelector(): String = "div.Posters a.Posters-link" override fun popularAnimeSelector(): String = "div.Posters a.Posters-link"
@ -105,20 +107,23 @@ open class Pelisplushd(override val name: String, override val baseUrl: String)
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>()
val data = document.selectFirst("script:containsData(video[1] = )")?.data() ?: return emptyList()
val data = document.selectFirst("script:containsData(video[1] = )")?.data() REGEX_VIDEO_OPTS.findAll(data).map { it.groupValues[1] }.forEach { opt ->
val apiUrl = data?.substringAfter("video[1] = '", "")?.substringBefore("';", "") val apiResponse = client.newCall(GET(opt)).execute()
val alternativeServers = document.select("ul.TbVideoNv.nav.nav-tabs li:not(:first-child)")
if (!apiUrl.isNullOrEmpty()) {
val apiResponse = client.newCall(GET(apiUrl)).execute()
val docResponse = apiResponse.asJsoup() val docResponse = apiResponse.asJsoup()
if (apiResponse.isSuccessful) { if (apiResponse.isSuccessful) {
val regIsUrl = "https?:\\/\\/(www\\.)?[-a-zA-Z0-9@:%._\\+~#=]{1,256}\\.[a-zA-Z0-9()]{1,6}\\b([-a-zA-Z0-9()@:%_\\+.~#?&//=]*)".toRegex() val encryptedList = if (docResponse.select("iframe").any()) {
val encryptedList = docResponse.select("#PlayerDisplay div[class*=\"OptionsLangDisp\"] div[class*=\"ODDIV\"] div[class*=\"OD\"] li") listOf(docResponse.select("iframe").attr("src"))
} else {
docResponse.select("#PlayerDisplay div[class*=\"OptionsLangDisp\"] div[class*=\"ODDIV\"] div[class*=\"OD\"] li")
.map { it.attr("onclick") }
}
encryptedList.flatMap { encryptedList.flatMap {
runCatching { runCatching {
val url = it.attr("onclick") val url = it.substringAfter("go_to_player('")
.substringAfter("go_to_player('")
.substringAfter("go_to_playerVast('") .substringAfter("go_to_playerVast('")
.substringBefore("?cover_url=") .substringBefore("?cover_url=")
.substringBefore("')") .substringBefore("')")
@ -128,7 +133,7 @@ open class Pelisplushd(override val name: String, override val baseUrl: String)
.substringBefore("?thumb=") .substringBefore("?thumb=")
.substringBefore("#poster=") .substringBefore("#poster=")
val realUrl = if (!regIsUrl.containsMatchIn(url)) { val realUrl = if (!REGEX_LINK.containsMatchIn(url)) {
String(Base64.decode(url, Base64.DEFAULT)) String(Base64.decode(url, Base64.DEFAULT))
} else if (url.contains("?data=")) { } else if (url.contains("?data=")) {
val apiPageSoup = client.newCall(GET(url)).execute().asJsoup() val apiPageSoup = client.newCall(GET(url)).execute().asJsoup()
@ -142,27 +147,6 @@ open class Pelisplushd(override val name: String, override val baseUrl: String)
}.also(videoList::addAll) }.also(videoList::addAll)
} }
} }
// verifier for old series
if (!apiUrl.isNullOrEmpty() && !apiUrl.contains("/video/") || alternativeServers.any()) {
document.select("ul.TbVideoNv.nav.nav-tabs li").parallelCatchingFlatMapBlocking { id ->
val serverName = id.select("a").text().lowercase()
val serverId = id.attr("data-id")
var serverUrl = data?.substringAfter("video[$serverId] = '", "")?.substringBefore("';", "")
if (serverUrl != null && serverUrl.contains("api.mycdn.moe")) {
val urlId = serverUrl.substringAfter("id=")
serverUrl = when (serverName) {
"sbfast" -> { "https://sbfull.com/e/$urlId" }
"plusto" -> { "https://owodeuwu.xyz/v/$urlId" }
"doodstream" -> { "https://dood.to/e/$urlId" }
"upload", "uqload" -> { "https://uqload.com/embed-$urlId.html" }
else -> ""
}
}
serverVideoResolver(serverUrl ?: "")
}.also(videoList::addAll)
}
return videoList return videoList
} }
@ -206,8 +190,8 @@ open class Pelisplushd(override val name: String, override val baseUrl: String)
StreamWishExtractor(client, docHeaders).videosFromUrl(url, videoNameGen = { "StreamWish:$it" }) StreamWishExtractor(client, docHeaders).videosFromUrl(url, videoNameGen = { "StreamWish:$it" })
} }
embedUrl.contains("doodstream") || embedUrl.contains("dood.") || embedUrl.contains("ds2play") || embedUrl.contains("doods.") -> { embedUrl.contains("doodstream") || embedUrl.contains("dood.") || embedUrl.contains("ds2play") || embedUrl.contains("doods.") -> {
val url2 = url.replace("https://doodstream.com/e/", "https://dood.to/e/") val url2 = url.replace("https://doodstream.com/e/", "https://d0000d.com/e/")
listOf(DoodExtractor(client).videoFromUrl(url2, "DoodStream", false)!!) listOf(DoodExtractor(client).videoFromUrl(url2, "DoodStream")!!)
} }
embedUrl.contains("streamlare") -> StreamlareExtractor(client).videosFromUrl(url) embedUrl.contains("streamlare") -> StreamlareExtractor(client).videosFromUrl(url)
embedUrl.contains("yourupload") || embedUrl.contains("upload") -> YourUploadExtractor(client).videoFromUrl(url, headers = headers) embedUrl.contains("yourupload") || embedUrl.contains("upload") -> YourUploadExtractor(client).videoFromUrl(url, headers = headers)

View file

@ -83,26 +83,20 @@ class Pelisplusto(override val name: String, override val baseUrl: String) : Pel
val episode = SEpisode.create().apply { val episode = SEpisode.create().apply {
episode_number = 1F episode_number = 1F
name = "PELÍCULA" name = "PELÍCULA"
setUrlWithoutDomain(response.request.url.toString()) setUrlWithoutDomain(jsoup.location())
} }
episodes.add(episode) episodes.add(episode)
} else { } else {
var jsonscript = "" val jsonStrData = jsoup.selectFirst("script:containsData(const seasonUrl =)")?.data() ?: return emptyList()
jsoup.select("script[type=text/javascript]").mapNotNull { script -> val jsonParse = json.decodeFromString<JsonObject>(jsonStrData.substringAfter("seasonsJson = ").substringBefore(";"))
val ssRegex = Regex("(?i)seasons")
val ss = if (script.data().contains(ssRegex)) script.data() else ""
val swaa = ss.substringAfter("seasonsJson = ").substringBefore(";")
jsonscript = swaa
}
val jsonParse = json.decodeFromString<JsonObject>(jsonscript)
var index = 0 var index = 0
jsonParse.entries.map { jsonParse.entries.map {
it.value.jsonArray.reversed().map { element -> it.value.jsonArray.reversed().map { element ->
index += 1 index += 1
val jsonElement = element!!.jsonObject val jsonElement = element.jsonObject
val season = jsonElement["season"]!!.jsonPrimitive!!.content val season = jsonElement["season"]!!.jsonPrimitive.content
val title = jsonElement["title"]!!.jsonPrimitive!!.content val title = jsonElement["title"]!!.jsonPrimitive.content
val ep = jsonElement["episode"]!!.jsonPrimitive!!.content val ep = jsonElement["episode"]!!.jsonPrimitive.content
val episode = SEpisode.create().apply { val episode = SEpisode.create().apply {
episode_number = index.toFloat() episode_number = index.toFloat()
name = "T$season - E$ep - $title" name = "T$season - E$ep - $title"