Fixes and Updates (#1090)

This commit is contained in:
miguelantonioe 2022-12-20 01:07:23 -06:00 committed by GitHub
parent f0442520cb
commit a7c1fe3017
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 322 additions and 155 deletions

View File

@ -13,8 +13,7 @@ class FembedExtractor(private val client: OkHttpClient) {
client.newCall(POST(videoApi)).execute().body?.string().orEmpty() client.newCall(POST(videoApi)).execute().body?.string().orEmpty()
}.getOrNull() ?: return emptyList<Video>() }.getOrNull() ?: return emptyList<Video>()
val jsonResponse = Json { ignoreUnknownKeys = true } val jsonResponse = try{ Json { ignoreUnknownKeys = true }.decodeFromString<FembedResponse>(body) } catch (e: Exception) { FembedResponse(false, emptyList()) }
.decodeFromString<FembedResponse>(body)
return if (jsonResponse.success) { return if (jsonResponse.success) {
jsonResponse.data.map { jsonResponse.data.map {

View File

@ -1,5 +1,6 @@
package eu.kanade.tachiyomi.lib.streamsbextractor package eu.kanade.tachiyomi.lib.streamsbextractor
import eu.kanade.tachiyomi.animesource.model.Track
import eu.kanade.tachiyomi.animesource.model.Video import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.GET
import kotlinx.serialization.decodeFromString import kotlinx.serialization.decodeFromString
@ -73,4 +74,30 @@ class StreamSBExtractor(private val client: OkHttpClient) {
emptyList<Video>() emptyList<Video>()
} }
} }
fun videosFromDecryptedUrl(realUrl: String, headers: Headers, prefix: String = "", suffix: String = ""): List<Video> {
return try {
val json = Json.decodeFromString<JsonObject>(client.newCall(GET(realUrl, headers)).execute().body!!.string())
val masterUrl = json["stream_data"]!!.jsonObject["file"].toString().trim('"')
val masterPlaylist = client.newCall(GET(masterUrl, headers)).execute().body!!.string()
val separator = "#EXT-X-STREAM-INF"
masterPlaylist.substringAfter(separator).split(separator).map {
val resolution = it.substringAfter("RESOLUTION=")
.substringBefore("\n")
.substringAfter("x")
.substringBefore(",") + "p"
val quality = ("StreamSB:$resolution").let {
if(prefix.isNotBlank()) "$prefix $it"
else it
}.let {
if(suffix.isNotBlank()) "$it $suffix"
else it
}
val videoUrl = it.substringAfter("\n").substringBefore("\n")
Video(videoUrl, quality, videoUrl, headers = headers)
}
} catch (e: Exception) {
emptyList()
}
}
} }

View File

@ -6,15 +6,13 @@ import eu.kanade.tachiyomi.util.asJsoup
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
class VoeExtractor(private val client: OkHttpClient) { class VoeExtractor(private val client: OkHttpClient) {
fun videoFromUrl(url: String, quality: String? = null): Video? { fun videoFromUrl(url: String, quality: String? = null): Video? {
val document = client.newCall(GET(url)).execute().asJsoup() val document = client.newCall(GET(url)).execute().asJsoup()
val script = document.selectFirst("script:containsData(const sources)") val script = document.selectFirst("script:containsData(const sources)")
?.data() ?.data()
?: return null ?: return null
val videoUrl = script.substringAfter("hls': '").substringBefore("'") val videoUrl = script.substringAfter("hls': '").substringBefore("'")
val resolution = script.substringAfter("video_height': ") val resolution = script.substringAfter("video_height': ").substringBefore(",")
.substringBefore(",")
val qualityStr = quality ?: "VoeCDN(${resolution}p)" val qualityStr = quality ?: "VoeCDN(${resolution}p)"
return Video(url, qualityStr, videoUrl) return Video(url, qualityStr, videoUrl)
} }

View File

@ -5,7 +5,7 @@ ext {
extName = 'AnimeFLV' extName = 'AnimeFLV'
pkgNameSuffix = 'es.animeflv' pkgNameSuffix = 'es.animeflv'
extClass = '.AnimeFlv' extClass = '.AnimeFlv'
extVersionCode = 31 extVersionCode = 32
libVersion = '13' libVersion = '13'
} }

View File

@ -2,6 +2,7 @@ package eu.kanade.tachiyomi.animeextension.es.animeflv
import android.app.Application import android.app.Application
import android.content.SharedPreferences import android.content.SharedPreferences
import android.util.Log
import androidx.preference.ListPreference import androidx.preference.ListPreference
import androidx.preference.PreferenceScreen import androidx.preference.PreferenceScreen
import eu.kanade.tachiyomi.animeextension.es.animeflv.extractors.YourUploadExtractor import eu.kanade.tachiyomi.animeextension.es.animeflv.extractors.YourUploadExtractor
@ -33,7 +34,7 @@ import org.jsoup.nodes.Element
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
import java.lang.Exception import kotlin.Exception
class AnimeFlv : ConfigurableAnimeSource, ParsedAnimeHttpSource() { class AnimeFlv : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
@ -116,31 +117,43 @@ class AnimeFlv : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
val quality = json!!["title"]!!.jsonPrimitive!!.content val quality = json!!["title"]!!.jsonPrimitive!!.content
var url = json!!["code"]!!.jsonPrimitive!!.content var url = json!!["code"]!!.jsonPrimitive!!.content
if (quality == "SB") { if (quality == "SB") {
videoList.addAll( try {
StreamSBExtractor(client).videosFromUrl(url, headers) videoList.addAll(
) StreamSBExtractor(client).videosFromUrl(url, headers)
)
} catch (_: Exception) {}
} }
if (quality == "Fembed") { if (quality == "Fembed") {
videoList.addAll( try {
FembedExtractor(client).videosFromUrl(url) videoList.addAll(
) FembedExtractor(client).videosFromUrl(url)
)
} catch (_: Exception) {}
} }
if (quality == "Stape") { if (quality == "Stape") {
val url1 = json!!["url"]!!.jsonPrimitive!!.content try {
val video = StreamTapeExtractor(client).videoFromUrl(url1) val url1 = json!!["url"]!!.jsonPrimitive!!.content
if (video != null) videoList.add(video) val video = StreamTapeExtractor(client).videoFromUrl(url1)
if (video != null) videoList.add(video)
} catch (_: Exception) {}
} }
if (quality == "Doodstream") { if (quality == "Doodstream") {
val video = DoodExtractor(client).videoFromUrl(url, "DoodStream", false) try {
if (video != null) videoList.add(video) val video = DoodExtractor(client).videoFromUrl(url, "DoodStream", false)
if (video != null) videoList.add(video)
} catch (_: Exception) {}
} }
if (quality == "Okru") { if (quality == "Okru") {
val videos = OkruExtractor(client).videosFromUrl(url) try {
videoList.addAll(videos) val videos = OkruExtractor(client).videosFromUrl(url)
videoList.addAll(videos)
} catch (_: Exception) {}
} }
if (quality == "YourUpload") { if (quality == "YourUpload") {
val headers = headers.newBuilder().add("referer", "https://www.yourupload.com/").build() try {
YourUploadExtractor(client).videoFromUrl(url, headers = headers).map { videoList.add(it) } val headers = headers.newBuilder().add("referer", "https://www.yourupload.com/").build()
YourUploadExtractor(client).videoFromUrl(url, headers = headers).map { videoList.add(it) }
} catch (_: Exception) {}
} }
} }
} }
@ -178,23 +191,35 @@ class AnimeFlv : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
override fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList): Request { override fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList): Request {
val filterList = if (filters.isEmpty()) getFilterList() else filters val filterList = if (filters.isEmpty()) getFilterList() else filters
val genreFilter = filterList.find { it is GenreFilter } as GenreFilter val genreFilter = filterList.find { it is GenreFilter } as GenreFilter
val stateFilter = filterList.find { it is StateFilter } as StateFilter
val typeFilter = filterList.find { it is TypeFilter } as TypeFilter
val orderByFilter = filterList.find { it is OrderByFilter } as OrderByFilter
var uri = "$baseUrl/browse?"
uri += if (query.isNotBlank()) "&q=$query" else ""
uri += if (genreFilter.state != 0) "&genre[]=${genreFilter.toUriPart()}" else ""
uri += if (stateFilter.state != 0) "&status[]=${stateFilter.toUriPart()}" else ""
uri += if (typeFilter.state != 0) "&type[]=${typeFilter.toUriPart()}" else ""
uri += "&order=${orderByFilter.toUriPart()}"
uri += "&page=$page"
return when { return when {
query.isNotBlank() -> GET("$baseUrl/browse?q=$query&order=rating&page=$page") query.isNotBlank() || genreFilter.state != 0 || stateFilter.state != 0 || orderByFilter.state != 0 || typeFilter.state != 0 -> GET(uri)
genreFilter.state != 0 -> GET("$baseUrl/browse?genre[]=${genreFilter.toUriPart()}&order=rating&page=$page")
else -> GET("$baseUrl/browse?page=$page&order=rating") else -> GET("$baseUrl/browse?page=$page&order=rating")
} }
} }
override fun getFilterList(): AnimeFilterList = AnimeFilterList( override fun getFilterList(): AnimeFilterList = AnimeFilterList(
AnimeFilter.Header("La busqueda por texto ignora el filtro"), AnimeFilter.Header("La busqueda por texto ignora el filtro"),
GenreFilter() GenreFilter(),
StateFilter(),
TypeFilter(),
OrderByFilter()
) )
private class GenreFilter : UriPartFilter( private class GenreFilter : UriPartFilter(
"Géneros", "Géneros",
arrayOf( arrayOf(
Pair("<Selecionar>", "all"), Pair("<Selecionar>", "all"),
Pair("Todo", "all"),
Pair("Acción", "accion"), Pair("Acción", "accion"),
Pair("Artes Marciales", "artes_marciales"), Pair("Artes Marciales", "artes_marciales"),
Pair("Aventuras", "aventura"), Pair("Aventuras", "aventura"),
@ -238,6 +263,38 @@ class AnimeFlv : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
) )
) )
private class StateFilter : UriPartFilter(
"Estado",
arrayOf(
Pair("<Seleccionar>", ""),
Pair("En emisión", "1"),
Pair("Finalizado", "2"),
Pair("Próximamente", "3")
)
)
private class TypeFilter : UriPartFilter(
"Tipo",
arrayOf(
Pair("<Seleccionar>", ""),
Pair("TV", "tv"),
Pair("Película", "movie"),
Pair("Especial", "special"),
Pair("OVA", "ova")
)
)
private class OrderByFilter : UriPartFilter(
"Ordenar Por",
arrayOf(
Pair("Por defecto", "default"),
Pair("Recientemente Actualizados", "updated"),
Pair("Recientemente Agregados", "added"),
Pair("Nombre A-Z", "title"),
Pair("Calificación", "rating")
)
)
private open class UriPartFilter(displayName: String, val vals: Array<Pair<String, String>>) : private open class UriPartFilter(displayName: String, val vals: Array<Pair<String, String>>) :
AnimeFilter.Select<String>(displayName, vals.map { it.first }.toTypedArray()) { AnimeFilter.Select<String>(displayName, vals.map { it.first }.toTypedArray()) {
fun toUriPart() = vals[state].second fun toUriPart() = vals[state].second

View File

@ -5,7 +5,7 @@ ext {
extName = 'AnimeLatinoHD' extName = 'AnimeLatinoHD'
pkgNameSuffix = 'es.animelatinohd' pkgNameSuffix = 'es.animelatinohd'
extClass = '.AnimeLatinoHD' extClass = '.AnimeLatinoHD'
extVersionCode = 9 extVersionCode = 10
libVersion = '13' libVersion = '13'
} }

View File

@ -143,6 +143,12 @@ class AnimeLatinoHD : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
return list return list
} }
private fun fetchUrls(text: String?): List<String> {
if (text.isNullOrEmpty()) return listOf()
val linkRegex = "(https?://(www\\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\\.[a-zA-Z0-9()]{1,6}\\b([-a-zA-Z0-9()@:%_+.~#?&/=]*))".toRegex()
return linkRegex.findAll(text).map { it.value.trim().removeSurrounding("\"") }.toList()
}
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>()
@ -158,45 +164,82 @@ class AnimeLatinoHD : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
val servers = player!!.jsonArray val servers = player!!.jsonArray
servers.forEach { server -> servers.forEach { server ->
val item = server!!.jsonObject val item = server!!.jsonObject
val url = item["code"]!!.jsonPrimitive!!.content val request = client.newCall(
val language = if (item["languaje"]!!.jsonPrimitive!!.content == "1") "[Lat] " else "[Sub] " GET(
if (url.lowercase().contains("streamsb")) { url = "https://api.animelatinohd.com/stream/${item["id"]!!.jsonPrimitive.content}",
val videos = StreamSBExtractor(client).videosFromUrl(url, headers, language) headers = headers.newBuilder().add("Referer", "https://www.animelatinohd.com/").build()
videoList.addAll(videos) )
} ).execute()
if (url.lowercase().contains("www.fembed.com")) { val locationsDdh = request!!.networkResponse.toString()
val videos = FembedExtractor(client).videosFromUrl(url, language) fetchUrls(locationsDdh).map { url ->
videoList.addAll(videos) val language = if (item["languaje"]!!.jsonPrimitive!!.content == "1") "[Lat] " else "[Sub] "
} val embedUrl = url.lowercase()
if (url.lowercase().contains("streamtape")) { if (embedUrl.contains("sbembed.com") || embedUrl.contains("sbembed1.com") || embedUrl.contains("sbplay.org") ||
val video = StreamTapeExtractor(client).videoFromUrl(url, language + "Streamtape") embedUrl.contains("sbvideo.net") || embedUrl.contains("streamsb.net") || embedUrl.contains("sbplay.one") ||
if (video != null) { embedUrl.contains("cloudemb.com") || embedUrl.contains("playersb.com") || embedUrl.contains("tubesb.com") ||
videoList.add(video) embedUrl.contains("sbplay1.com") || embedUrl.contains("embedsb.com") || embedUrl.contains("watchsb.com") ||
embedUrl.contains("sbplay2.com") || embedUrl.contains("japopav.tv") || embedUrl.contains("viewsb.com") ||
embedUrl.contains("sbfast") || embedUrl.contains("sbfull.com") || embedUrl.contains("javplaya.com") ||
embedUrl.contains("ssbstream.net") || embedUrl.contains("p1ayerjavseen.com") || embedUrl.contains("sbthe.com") ||
embedUrl.contains("vidmovie.xyz") || embedUrl.contains("sbspeed.com") || embedUrl.contains("streamsss.net") ||
embedUrl.contains("sblanh.com")
) {
val videos = StreamSBExtractor(client).videosFromUrl(url, headers, language)
videoList.addAll(videos)
} }
} if (embedUrl.contains("fembed") || embedUrl.contains("anime789.com") || embedUrl.contains("24hd.club") ||
if (url.lowercase().contains("doodstream")) { embedUrl.contains("fembad.org") || embedUrl.contains("vcdn.io") || embedUrl.contains("sharinglink.club") ||
val video = try { embedUrl.contains("moviemaniac.org") || embedUrl.contains("votrefiles.club") || embedUrl.contains("femoload.xyz") ||
DoodExtractor(client).videoFromUrl(url, language + "DoodStream") embedUrl.contains("albavido.xyz") || embedUrl.contains("feurl.com") || embedUrl.contains("dailyplanet.pw") ||
} catch (e: Exception) { embedUrl.contains("ncdnstm.com") || embedUrl.contains("jplayer.net") || embedUrl.contains("xstreamcdn.com") ||
null embedUrl.contains("fembed-hd.com") || embedUrl.contains("gcloud.live") || embedUrl.contains("vcdnplay.com") ||
embedUrl.contains("superplayxyz.club") || embedUrl.contains("vidohd.com") || embedUrl.contains("vidsource.me") ||
embedUrl.contains("cinegrabber.com") || embedUrl.contains("votrefile.xyz") || embedUrl.contains("zidiplay.com") ||
embedUrl.contains("ndrama.xyz") || embedUrl.contains("fcdn.stream") || embedUrl.contains("mediashore.org") ||
embedUrl.contains("suzihaza.com") || embedUrl.contains("there.to") || embedUrl.contains("femax20.com") ||
embedUrl.contains("javstream.top") || embedUrl.contains("viplayer.cc") || embedUrl.contains("sexhd.co") ||
embedUrl.contains("fembed.net") || embedUrl.contains("mrdhan.com") || embedUrl.contains("votrefilms.xyz") ||
embedUrl.contains("embedsito.com") || embedUrl.contains("dutrag.com") || embedUrl.contains("youvideos.ru") ||
embedUrl.contains("streamm4u.club") || embedUrl.contains("moviepl.xyz") || embedUrl.contains("asianclub.tv") ||
embedUrl.contains("vidcloud.fun") || embedUrl.contains("fplayer.info") || embedUrl.contains("diasfem.com") ||
embedUrl.contains("javpoll.com") || embedUrl.contains("reeoov.tube") || embedUrl.contains("suzihaza.com") ||
embedUrl.contains("ezsubz.com") || embedUrl.contains("vidsrc.xyz") || embedUrl.contains("diampokusy.com") ||
embedUrl.contains("diampokusy.com") || embedUrl.contains("i18n.pw") || embedUrl.contains("vanfem.com") ||
embedUrl.contains("fembed9hd.com") || embedUrl.contains("votrefilms.xyz") || embedUrl.contains("watchjavnow.xyz")
) {
val videos = FembedExtractor(client).videosFromUrl(url, language)
videoList.addAll(videos)
} }
if (video != null) { if (url.lowercase().contains("streamtape")) {
videoList.add(video) val video = StreamTapeExtractor(client).videoFromUrl(url, language + "Streamtape")
if (video != null) {
videoList.add(video)
}
}
if (url.lowercase().contains("dood")) {
val video = try {
DoodExtractor(client).videoFromUrl(url, language + "DoodStream")
} catch (e: Exception) {
null
}
if (video != null) {
videoList.add(video)
}
}
if (url.lowercase().contains("okru")) {
val videos = OkruExtractor(client).videosFromUrl(url, language)
videoList.addAll(videos)
}
if (url.lowercase().contains("www.solidfiles.com")) {
val videos = SolidFilesExtractor(client).videosFromUrl(url, language)
videoList.addAll(videos)
}
if (url.lowercase().contains("od.lk")) {
videoList.add(Video(url, language + "Od.lk", url))
}
if (url.lowercase().contains("cldup.com")) {
videoList.add(Video(url, language + "CldUp", url))
} }
}
if (url.lowercase().contains("okru")) {
val videos = OkruExtractor(client).videosFromUrl(url, language)
videoList.addAll(videos)
}
if (url.lowercase().contains("www.solidfiles.com")) {
val videos = SolidFilesExtractor(client).videosFromUrl(url, language)
videoList.addAll(videos)
}
if (url.lowercase().contains("od.lk")) {
videoList.add(Video(url, language + "Od.lk", url))
}
if (url.lowercase().contains("cldup.com")) {
videoList.add(Video(url, language + "CldUp", url))
} }
} }
} }

View File

@ -5,7 +5,7 @@ ext {
extName = 'Pelisplushd' extName = 'Pelisplushd'
pkgNameSuffix = 'es.pelisplushd' pkgNameSuffix = 'es.pelisplushd'
extClass = '.Pelisplushd' extClass = '.Pelisplushd'
extVersionCode = 21 extVersionCode = 22
libVersion = '13' libVersion = '13'
} }
@ -14,6 +14,7 @@ dependencies {
implementation(project(':lib-streamtape-extractor')) implementation(project(':lib-streamtape-extractor'))
implementation(project(':lib-streamsb-extractor')) implementation(project(':lib-streamsb-extractor'))
implementation(project(':lib-dood-extractor')) implementation(project(':lib-dood-extractor'))
implementation(project(':lib-voe-extractor'))
} }
apply from: "$rootDir/common.gradle" apply from: "$rootDir/common.gradle"

View File

@ -5,6 +5,7 @@ import android.content.SharedPreferences
import android.util.Base64 import android.util.Base64
import androidx.preference.ListPreference import androidx.preference.ListPreference
import androidx.preference.PreferenceScreen import androidx.preference.PreferenceScreen
import eu.kanade.tachiyomi.animeextension.es.pelisplushd.extractors.StreamlareExtractor
import eu.kanade.tachiyomi.animeextension.es.pelisplushd.extractors.YourUploadExtractor import eu.kanade.tachiyomi.animeextension.es.pelisplushd.extractors.YourUploadExtractor
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
@ -17,13 +18,9 @@ import eu.kanade.tachiyomi.lib.doodextractor.DoodExtractor
import eu.kanade.tachiyomi.lib.fembedextractor.FembedExtractor import eu.kanade.tachiyomi.lib.fembedextractor.FembedExtractor
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.streamtapeextractor.StreamTapeExtractor
import eu.kanade.tachiyomi.lib.voeextractor.VoeExtractor
import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.network.POST
import eu.kanade.tachiyomi.util.asJsoup import eu.kanade.tachiyomi.util.asJsoup
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.jsonObject
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.Request import okhttp3.Request
import okhttp3.Response import okhttp3.Response
@ -31,8 +28,6 @@ import org.jsoup.nodes.Document
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
import uy.kohesive.injekt.injectLazy
import kotlin.Exception
class Pelisplushd : ConfigurableAnimeSource, ParsedAnimeHttpSource() { class Pelisplushd : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
@ -44,8 +39,6 @@ class Pelisplushd : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
override val supportsLatest = false override val supportsLatest = false
private val json: Json by injectLazy()
override val client: OkHttpClient = network.cloudflareClient override val client: OkHttpClient = network.cloudflareClient
private val preferences: SharedPreferences by lazy { private val preferences: SharedPreferences by lazy {
@ -75,7 +68,7 @@ class Pelisplushd : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
val episode = SEpisode.create().apply { val episode = SEpisode.create().apply {
val epnum = 1 val epnum = 1
episode_number = epnum.toFloat() episode_number = epnum.toFloat()
name = "PELICULA" name = "PELÍCULA"
} }
episode.setUrlWithoutDomain(response.request.url.toString()) episode.setUrlWithoutDomain(response.request.url.toString())
episodes.add(episode) episodes.add(episode)
@ -110,7 +103,7 @@ class Pelisplushd : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
encryptedList.forEach { encryptedList.forEach {
val url = String(Base64.decode(it.attr("data-r"), Base64.DEFAULT)) val url = String(Base64.decode(it.attr("data-r"), Base64.DEFAULT))
val server = it.select("span").text() val server = it.select("span").text()
serverVideoResolver(url, server.toString()).forEach { video -> videoList.add(video) } serverVideoResolver(url, server.toString())?.forEach { video -> videoList.add(video) }
} }
decryptedList.forEach { decryptedList.forEach {
val url = it.attr("onclick") val url = it.attr("onclick")
@ -120,9 +113,10 @@ class Pelisplushd : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
.substringBefore("?poster") .substringBefore("?poster")
.substringBefore("#poster=") .substringBefore("#poster=")
val server = it.select("span").text() val server = it.select("span").text()
serverVideoResolver(url, server.toString()).forEach { video -> videoList.add(video) } serverVideoResolver(url, server.toString())?.forEach { video -> videoList.add(video) }
} }
} }
// verifier for old series // verifier for old series
if (!apiUrl.contains("/video/") || alternativeServers.any()) { if (!apiUrl.contains("/video/") || alternativeServers.any()) {
document.select("ul.TbVideoNv.nav.nav-tabs li").forEach { id -> document.select("ul.TbVideoNv.nav.nav-tabs li").forEach { id ->
@ -138,88 +132,74 @@ class Pelisplushd : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
"upload" -> { serverUrl = "https://uqload.com/embed-$urlId.html" } "upload" -> { serverUrl = "https://uqload.com/embed-$urlId.html" }
} }
} }
serverVideoResolver(serverUrl, serverName.toString()).forEach { video -> videoList.add(video) } serverVideoResolver(serverUrl, serverName.toString())?.forEach { video -> videoList.add(video) }
} }
} }
return videoList return videoList
} }
private fun serverVideoResolver(url: String, server: String): List<Video> { private fun bytesToHex(bytes: ByteArray): String {
val videoList = mutableListOf<Video>() val hexArray = "0123456789ABCDEF".toCharArray()
val hexChars = CharArray(bytes.size * 2)
when (server.lowercase()) { for (j in bytes.indices) {
"sbfast" -> { val v = bytes[j].toInt() and 0xFF
runCatching { hexChars[j * 2] = hexArray[v ushr 4]
StreamSBExtractor(client).videosFromUrl(url, headers) hexChars[j * 2 + 1] = hexArray[v and 0x0F]
}.getOrNull()?.let { videoList.addAll(it) }
}
"plusto" -> {
val videos = FembedExtractor(client).videosFromUrl(url)
videoList.addAll(videos)
}
"stp" -> {
val videos = StreamTapeExtractor(client).videoFromUrl(url, "StreamTape")
if (videos != null) {
videoList.add(videos)
}
}
"uwu" -> {
try {
if (!url.contains("disable")) {
val body = client.newCall(GET(url)).execute().asJsoup()
if (body.select("script:containsData(var shareId)").toString()
.isNotBlank()
) {
val shareId =
body.selectFirst("script:containsData(var shareId)").data()
.substringAfter("shareId = \"").substringBefore("\"")
val amazonApiJson =
client.newCall(GET("https://www.amazon.com/drive/v1/shares/$shareId?resourceVersion=V2&ContentType=JSON&asset=ALL"))
.execute().asJsoup()
val epId = amazonApiJson.toString().substringAfter("\"id\":\"")
.substringBefore("\"")
val amazonApi =
client.newCall(GET("https://www.amazon.com/drive/v1/nodes/$epId/children?resourceVersion=V2&ContentType=JSON&limit=200&sort=%5B%22kind+DESC%22%2C+%22modifiedDate+DESC%22%5D&asset=ALL&tempLink=true&shareId=$shareId"))
.execute().asJsoup()
val videoUrl = amazonApi.toString().substringAfter("\"FOLDER\":")
.substringAfter("tempLink\":\"").substringBefore("\"")
videoList.add(Video(videoUrl, "Amazon", videoUrl))
}
}
} catch (e: Exception) {}
}
"voex" -> {
try {
val body = client.newCall(GET(url)).execute().asJsoup()
val data1 = body.selectFirst("script:containsData(const sources = {)").data()
val video = data1.substringAfter("hls\": \"").substringBefore("\"")
videoList.add(Video(video, "Voex", video))
} catch (e: Exception) {}
}
"streamlare" -> {
try {
val id = url.substringAfter("/e/").substringBefore("?poster")
val videoUrlResponse = client.newCall(POST("https://slwatch.co/api/video/stream/get?id=$id")).execute().asJsoup()
json.decodeFromString<JsonObject>(videoUrlResponse.select("body").text())["result"]?.jsonObject?.forEach { quality ->
val resolution = quality.toString().substringAfter("\"label\":\"").substringBefore("\"")
val videoUrl = quality.toString().substringAfter("\"file\":\"").substringBefore("\"")
videoList.add(Video(videoUrl, "Streamlare:$resolution", videoUrl))
}
} catch (e: Exception) {}
}
"doodstream" -> {
val url2 = url.replace("https://doodstream.com/e/", "https://dood.to/e/")
val video = DoodExtractor(client).videoFromUrl(url2, "DoodStream", false)
if (video != null) {
videoList.add(video)
}
}
"upload" -> {
val headers = headers.newBuilder().add("referer", "https://www.yourupload.com/").build()
val videos = YourUploadExtractor(client).videoFromUrl(url, headers = headers)
if (videos.isNotEmpty()) videoList.addAll(videos)
}
} }
return String(hexChars)
}
private fun fixUrl(url: String): String {
val sbUrl = url.substringBefore("/e/")
val id = url.substringAfter("/e/").substringBefore("?").substringBefore(".html")
val hexBytes = bytesToHex(id.toByteArray())
return "$sbUrl/sources49/316751675854774a53316b777c7c${hexBytes}7c7c744548764f5a666a315547577c7c73747265616d7362"
}
private fun serverVideoResolver(url: String, server: String): List<Video>? {
val videoList = mutableListOf<Video>()
try {
if (server.lowercase() == "sbfast") {
val newHeaders = headers.newBuilder().set("referer", url).set("watchsb", "sbstream").set("authority", url.substringBefore("/e/")).build()
return StreamSBExtractor(client).videosFromDecryptedUrl(fixUrl(url), headers = newHeaders)
} else if (server.lowercase() == "plusto") {
return FembedExtractor(client).videosFromUrl(url)
} else if (server.lowercase() == "stp") {
StreamTapeExtractor(client).videoFromUrl(url, "StreamTape")?.let { videoList.add(it) }
} else if (server.lowercase() == "uwu") {
if (!url.contains("disable")) {
val body = client.newCall(GET(url)).execute().asJsoup()
if (body.select("script:containsData(var shareId)").toString()
.isNotBlank()
) {
val shareId =
body.selectFirst("script:containsData(var shareId)").data()
.substringAfter("shareId = \"").substringBefore("\"")
val amazonApiJson =
client.newCall(GET("https://www.amazon.com/drive/v1/shares/$shareId?resourceVersion=V2&ContentType=JSON&asset=ALL"))
.execute().asJsoup()
val epId = amazonApiJson.toString().substringAfter("\"id\":\"")
.substringBefore("\"")
val amazonApi =
client.newCall(GET("https://www.amazon.com/drive/v1/nodes/$epId/children?resourceVersion=V2&ContentType=JSON&limit=200&sort=%5B%22kind+DESC%22%2C+%22modifiedDate+DESC%22%5D&asset=ALL&tempLink=true&shareId=$shareId"))
.execute().asJsoup()
val videoUrl = amazonApi.toString().substringAfter("\"FOLDER\":")
.substringAfter("tempLink\":\"").substringBefore("\"")
videoList.add(Video(videoUrl, "Amazon", videoUrl))
}
}
} else if (server.lowercase() == "voex") {
VoeExtractor(client).videoFromUrl(url, "Voex")?.let { videoList.add(it) }
} else if (server.lowercase() == "streamlare") {
StreamlareExtractor(client).videosFromUrl(url)?.let { videoList.add(it) }
} else if (server.lowercase() == "doodstream") {
val url2 = url.replace("https://doodstream.com/e/", "https://dood.to/e/")
DoodExtractor(client).videoFromUrl(url2, "DoodStream", false)?.let { videoList.add(it) }
} else if (server.lowercase() == "upload") {
val headers = headers.newBuilder().add("referer", "https://www.yourupload.com/").build()
return YourUploadExtractor(client).videoFromUrl(url, headers = headers)
}
} catch (_: Exception) {}
return videoList return videoList
} }
@ -253,11 +233,13 @@ class Pelisplushd : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
override fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList): Request { override fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList): Request {
val filterList = if (filters.isEmpty()) getFilterList() else filters val filterList = if (filters.isEmpty()) getFilterList() else filters
val genreFilter = filterList.find { it is GenreFilter } as GenreFilter val genreFilter = filterList.find { it is GenreFilter } as GenreFilter
val tagFilter = filters.find { it is Tags } as Tags
return when { return when {
query.isNotBlank() -> GET("$baseUrl/search?s=$query&page=$page", headers) query.isNotBlank() -> GET("$baseUrl/search?s=$query&page=$page", headers)
genreFilter.state != 0 -> GET("$baseUrl/${genreFilter.toUriPart()}?page=$page") genreFilter.state != 0 -> GET("$baseUrl/${genreFilter.toUriPart()}?page=$page")
else -> GET("$baseUrl/peliculas?page=$page ") tagFilter.state.isNotBlank() -> GET("$baseUrl/year/${tagFilter.state}?page=$page")
else -> GET("$baseUrl/peliculas?page=$page")
} }
} }
override fun searchAnimeFromElement(element: Element): SAnime { override fun searchAnimeFromElement(element: Element): SAnime {
@ -288,8 +270,10 @@ class Pelisplushd : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
override fun latestUpdatesSelector() = throw Exception("not used") override fun latestUpdatesSelector() = throw Exception("not used")
override fun getFilterList(): AnimeFilterList = AnimeFilterList( override fun getFilterList(): AnimeFilterList = AnimeFilterList(
AnimeFilter.Header("La busqueda por texto ignora el filtro"), AnimeFilter.Header("La busqueda por texto ignora el filtro de año"),
GenreFilter() GenreFilter(),
AnimeFilter.Header("Busqueda por año"),
Tags("Año")
) )
private class GenreFilter : UriPartFilter( private class GenreFilter : UriPartFilter(
@ -321,6 +305,8 @@ class Pelisplushd : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
) )
) )
private class Tags(name: String) : AnimeFilter.Text(name)
private open class UriPartFilter(displayName: String, val vals: Array<Pair<String, String>>) : private open class UriPartFilter(displayName: String, val vals: Array<Pair<String, String>>) :
AnimeFilter.Select<String>(displayName, vals.map { it.first }.toTypedArray()) { AnimeFilter.Select<String>(displayName, vals.map { it.first }.toTypedArray()) {
fun toUriPart() = vals[state].second fun toUriPart() = vals[state].second

View File

@ -0,0 +1,56 @@
package eu.kanade.tachiyomi.animeextension.es.pelisplushd.extractors
import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.network.POST
import eu.kanade.tachiyomi.util.asJsoup
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.jsonObject
import okhttp3.Headers
import okhttp3.OkHttpClient
import uy.kohesive.injekt.injectLazy
class StreamlareExtractor(private val client: OkHttpClient) {
private val json: Json by injectLazy()
fun videosFromUrl(url: String): Video? {
val id = url.substringAfter("/e/").substringBefore("?poster")
val videoUrlResponse =
client.newCall(POST("https://slwatch.co/api/video/stream/get?id=$id")).execute()
.asJsoup()
json.decodeFromString<JsonObject>(
videoUrlResponse.select("body").text()
)["result"]?.jsonObject?.forEach { quality ->
if (quality.toString().contains("file=\"")) {
val videoUrl = quality.toString().substringAfter("file=\"").substringBefore("\"").trim()
val type = if (videoUrl.contains(".m3u8")) "HSL" else "MP4"
val headers = Headers.Builder()
.add("authority", videoUrl.substringBefore("/hls").substringBefore("/mp4"))
.add("origin", "https://slwatch.co")
.add("referer", "https://slwatch.co/e/" + url.substringAfter("/e/"))
.add(
"sec-ch-ua",
"\"Not?A_Brand\";v=\"8\", \"Chromium\";v=\"108\", \"Google Chrome\";v=\"108\""
)
.add("sec-ch-ua-mobile", "?0")
.add("sec-ch-ua-platform", "\"Windows\"")
.add("sec-fetch-dest", "empty")
.add("sec-fetch-mode", "cors")
.add("sec-fetch-site", "cross-site")
.add(
"user-agent",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/),108.0.0.0 Safari/537.36"
)
.add("Accept-Encoding", "gzip, deflate, br")
.add("accept", "*/*")
.add(
"accept-language",
"es-MX,es-419;q=0.9,es;q=0.8,en;q=0.7,zh-TW;q=0.6,zh-CN;q=0.5,zh;q=0.4"
)
.build()
return Video(videoUrl, "Streamlare:$type", videoUrl, headers = headers)
}
}
return null
}
}