fix(src/es): Some fixes for Spanish extensions (#2980)

This commit is contained in:
imper1aldev
2024-03-04 04:31:04 -06:00
committed by GitHub
parent bdeb3f1b16
commit f8daecd5b4
9 changed files with 742 additions and 565 deletions

View File

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

View File

@ -0,0 +1,300 @@
package eu.kanade.tachiyomi.animeextension.es.doramasflix
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.JsonObject
// -----------------------Season models------------------------//
@Serializable
data class SeasonModel(
val data: DataSeason = DataSeason(),
)
@Serializable
data class DataSeason(
val listSeasons: List<ListSeason> = emptyList(),
)
@Serializable
data class ListSeason(
val slug: String,
@SerialName("season_number")
val seasonNumber: Long,
@SerialName("poster_path")
val posterPath: String?,
@SerialName("air_date")
val airDate: String?,
@SerialName("serie_name")
val serieName: String?,
val poster: String?,
val backdrop: String?,
@SerialName("__typename")
val typename: String,
)
// -----------------------Episode Model------------------------//
@Serializable
data class EpisodeModel(
val data: DataEpisode = DataEpisode(),
)
@Serializable
data class DataEpisode(
val listEpisodes: List<ListEpisode> = emptyList(),
)
@Serializable
data class ListEpisode(
@SerialName("_id")
val id: String,
val name: String?,
val slug: String,
@SerialName("serie_name")
val serieName: String?,
@SerialName("serie_name_es")
val serieNameEs: String?,
@SerialName("serie_id")
val serieId: String?,
@SerialName("still_path")
val stillPath: String?,
@SerialName("air_date")
val airDate: String?,
@SerialName("season_number")
val seasonNumber: Long?,
@SerialName("episode_number")
val episodeNumber: Long?,
// val languages: List<Any?>,
val poster: String?,
val backdrop: String?,
@SerialName("__typename")
val typename: String,
)
// -----------------------Details Model------------------------//
data class DetailsModel(
val props: Props,
val page: String,
val query: Query,
val buildId: String,
val isFallback: Boolean,
val gip: Boolean,
)
data class Props(
val pageProps: PageProps,
)
data class PageProps(
val deviceType: String,
val slug: String,
// val apolloClient: Any?,
val apolloState: HashMap<String, HashMap<String, JsonObject>>,
val ssrComplete: Boolean,
)
data class Query(
val slug: String,
)
// -----------------------Pagination Model------------------------//
@Serializable
data class PaginationModel(
val data: DataPagination = DataPagination(),
)
@Serializable
data class DataPagination(
val paginationDorama: PaginationDorama? = null,
val paginationMovie: PaginationDorama? = null,
)
@Serializable
data class PaginationDorama(
val count: Long,
val pageInfo: PageInfo,
val items: List<Item> = emptyList(),
@SerialName("__typename")
val typename: String,
)
@Serializable
data class PageInfo(
val currentPage: Long,
val hasNextPage: Boolean,
val hasPreviousPage: Boolean,
@SerialName("__typename")
val typename: String,
)
@Serializable
data class Item(
@SerialName("_id")
val id: String,
val name: String,
@SerialName("name_es")
val nameEs: String?,
val slug: String,
val cast: List<Cast> = emptyList(),
val names: String?,
val overview: String?,
val languages: List<String> = emptyList(),
@SerialName("created_by")
val createdBy: List<CreatedBy> = emptyList(),
val popularity: Double?,
@SerialName("poster_path")
val posterPath: String?,
@SerialName("backdrop_path")
val backdropPath: String?,
@SerialName("first_air_date")
val firstAirDate: String?,
@SerialName("isTVShow")
val isTvshow: Boolean?,
val poster: String?,
val backdrop: String?,
val genres: List<Genre> = emptyList(),
val networks: List<Network> = emptyList(),
@SerialName("__typename")
val typename: String,
)
@Serializable
data class Cast(
val adult: Boolean?,
val gender: Long?,
val id: Long?,
@SerialName("known_for_department")
val knownForDepartment: String?,
val name: String?,
@SerialName("original_name")
val originalName: String?,
val popularity: Double?,
@SerialName("profile_path")
val profilePath: String?,
val character: String?,
@SerialName("credit_id")
val creditId: String?,
val order: Long?,
)
@Serializable
data class CreatedBy(
val adult: Boolean?,
val gender: Long?,
val id: Long?,
@SerialName("known_for_department")
val knownForDepartment: String?,
val name: String?,
@SerialName("original_name")
val originalName: String?,
val popularity: Double?,
@SerialName("profile_path")
val profilePath: String?,
@SerialName("credit_id")
val creditId: String?,
val department: String?,
val job: String?,
)
@Serializable
data class Genre(
val name: String?,
val slug: String?,
@SerialName("__typename")
val typename: String?,
)
@Serializable
data class Network(
val name: String?,
val slug: String?,
@SerialName("__typename")
val typename: String?,
)
// -----------------------Search Model------------------------//
@Serializable
data class SearchModel(
val data: Data = Data(),
)
@Serializable
data class Data(
val searchDorama: List<SearchDorama> = emptyList(),
val searchMovie: List<SearchDorama> = emptyList(),
)
@Serializable
data class SearchDorama(
@SerialName("_id")
val id: String,
val slug: String,
val name: String,
@SerialName("name_es")
val nameEs: String?,
@SerialName("poster_path")
val posterPath: String?,
val poster: String?,
@SerialName("__typename")
val typename: String,
)
// -------------------------------------------------------
@Serializable
data class VideoModel(
val json: JsonVideo = JsonVideo(),
)
@Serializable
data class JsonVideo(
val lang: String? = "",
val page: String? = "",
val link: String? = "",
val server: String? = "",
)
@Serializable
data class VideoToken(
val link: String?,
val server: String?,
val app: String?,
val iat: Long?,
val exp: Long?,
)
// ------------------------------------------------
@Serializable
data class TokenModel(
val props: PropsToken = PropsToken(),
val page: String? = null,
val query: QueryToken = QueryToken(),
val buildId: String? = null,
val isFallback: Boolean? = false,
val isExperimentalCompile: Boolean? = false,
val gssp: Boolean? = false,
// val scriptLoader: List<Any?>,
)
@Serializable
data class PropsToken(
val pageProps: PagePropsToken = PagePropsToken(),
@SerialName("__N_SSP")
val nSsp: Boolean? = false,
)
@Serializable
data class PagePropsToken(
val token: String? = null,
val name: String? = null,
val app: String? = null,
val server: String? = null,
val iosapp: String? = null,
val externalLink: String? = null,
)
@Serializable
data class QueryToken(
val token: String? = null,
)

View File

@ -2,9 +2,11 @@ package eu.kanade.tachiyomi.animeextension.es.doramasflix
import android.app.Application import android.app.Application
import android.content.SharedPreferences import android.content.SharedPreferences
import android.util.Base64
import androidx.preference.ListPreference import androidx.preference.ListPreference
import androidx.preference.PreferenceScreen import androidx.preference.PreferenceScreen
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.AnimeFilterList import eu.kanade.tachiyomi.animesource.model.AnimeFilterList
import eu.kanade.tachiyomi.animesource.model.AnimesPage import eu.kanade.tachiyomi.animesource.model.AnimesPage
import eu.kanade.tachiyomi.animesource.model.SAnime import eu.kanade.tachiyomi.animesource.model.SAnime
@ -24,11 +26,12 @@ import eu.kanade.tachiyomi.lib.streamwishextractor.StreamWishExtractor
import eu.kanade.tachiyomi.lib.upstreamextractor.UpstreamExtractor import eu.kanade.tachiyomi.lib.upstreamextractor.UpstreamExtractor
import eu.kanade.tachiyomi.lib.uqloadextractor.UqloadExtractor import eu.kanade.tachiyomi.lib.uqloadextractor.UqloadExtractor
import eu.kanade.tachiyomi.lib.voeextractor.VoeExtractor import eu.kanade.tachiyomi.lib.voeextractor.VoeExtractor
import eu.kanade.tachiyomi.lib.vudeoextractor.VudeoExtractor
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.network.POST import eu.kanade.tachiyomi.network.POST
import eu.kanade.tachiyomi.util.asJsoup import eu.kanade.tachiyomi.util.asJsoup
import kotlinx.serialization.decodeFromString import eu.kanade.tachiyomi.util.parallelCatchingFlatMapBlocking
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonObject import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.jsonArray import kotlinx.serialization.json.jsonArray
@ -43,6 +46,8 @@ import okhttp3.Response
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.text.SimpleDateFormat
import java.util.Date
class Doramasflix : ConfigurableAnimeSource, AnimeHttpSource() { class Doramasflix : ConfigurableAnimeSource, AnimeHttpSource() {
@ -86,6 +91,10 @@ class Doramasflix : ConfigurableAnimeSource, AnimeHttpSource() {
"Fastream", "Filemoon", "StreamWish", "Okru", "Streamlare", "Fastream", "Filemoon", "StreamWish", "Okru", "Streamlare",
"Uqload", "Uqload",
) )
private val DATE_FORMATTER by lazy {
SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")
}
} }
private val preferences: SharedPreferences by lazy { private val preferences: SharedPreferences by lazy {
@ -121,7 +130,8 @@ class Doramasflix : ConfigurableAnimeSource, AnimeHttpSource() {
document.select("script").map { el -> document.select("script").map { el ->
if (el.data().contains("{\"props\":{\"pageProps\":{")) { if (el.data().contains("{\"props\":{\"pageProps\":{")) {
val apolloState = json.decodeFromString<JsonObject>(el.data())!!.jsonObject["props"]!!.jsonObject["pageProps"]!!.jsonObject["apolloState"]!!.jsonObject val apolloState = json.decodeFromString<JsonObject>(el.data())!!.jsonObject["props"]!!.jsonObject["pageProps"]!!.jsonObject["apolloState"]!!.jsonObject
val dorama = apolloState!!.entries!!.firstOrNull()!!.value!!.jsonObject val dorama = apolloState!!.entries!!.firstOrNull { (key, _) -> Regex("\\b(?:Movie|Dorama):[a-zA-Z0-9]+").matches(key) }!!.value!!.jsonObject
val genres = try { apolloState.entries.filter { x -> x.key.contains("genres") }.joinToString { it.value.jsonObject["name"]!!.jsonPrimitive.content } } catch (_: Exception) { "" } val genres = try { apolloState.entries.filter { x -> x.key.contains("genres") }.joinToString { it.value.jsonObject["name"]!!.jsonPrimitive.content } } catch (_: Exception) { "" }
val network = try { apolloState.entries.firstOrNull { x -> x.key.contains("networks") }?.value?.jsonObject?.get("name")!!.jsonPrimitive.content } catch (_: Exception) { "" } val network = try { apolloState.entries.firstOrNull { x -> x.key.contains("networks") }?.value?.jsonObject?.get("name")!!.jsonPrimitive.content } catch (_: Exception) { "" }
val artist = try { dorama["cast"]?.jsonObject?.get("json")?.jsonArray?.firstOrNull()?.jsonObject?.get("name")?.jsonPrimitive?.content } catch (_: Exception) { "" } val artist = try { dorama["cast"]?.jsonObject?.get("json")?.jsonArray?.firstOrNull()?.jsonObject?.get("name")?.jsonPrimitive?.content } catch (_: Exception) { "" }
@ -158,55 +168,60 @@ class Doramasflix : ConfigurableAnimeSource, AnimeHttpSource() {
} }
override fun episodeListParse(response: Response): List<SEpisode> { override fun episodeListParse(response: Response): List<SEpisode> {
val episodes = mutableListOf<SEpisode>() return if (response.request.url.toString().contains("peliculas-online")) {
if (response.request.url.toString().contains("peliculas-online")) { listOf(
val episode = SEpisode.create() SEpisode.create().apply {
episode.episode_number = 1F episode_number = 1F
episode.name = "Película" name = "Película"
episode.setUrlWithoutDomain(response.request.url.toString()) setUrlWithoutDomain(response.request.url.toString())
episodes.add(episode) },
)
} else { } else {
val jsonEpisodes = mutableListOf<String>()
val id = response.request.url.toString().substringAfter("?id=") val id = response.request.url.toString().substringAfter("?id=")
val responseString = response.body.string() val responseString = response.body.string()
val data = json.decodeFromString<JsonObject>(responseString)!!.jsonObject["data"]!!.jsonObject val data = json.decodeFromString<SeasonModel>(responseString).data
data["listSeasons"]!!.jsonArray.forEach {
val season = it.jsonObject["season_number"]!!.jsonPrimitive.content data.listSeasons.parallelCatchingFlatMapBlocking {
val season = it.seasonNumber
val body = ( val body = (
"{\"operationName\":\"listEpisodes\",\"variables\":{\"serie_id\":\"$id\",\"season_number\":$season},\"query\":\"query " + "{\"operationName\":\"listEpisodes\",\"variables\":{\"serie_id\":\"$id\",\"season_number\":$season},\"query\":\"query " +
"listEpisodes(\$season_number: Float!, \$serie_id: MongoID!) {\\n listEpisodes(sort: NUMBER_ASC, filter: {type_serie: \\\"dorama\\\", " + "listEpisodes(\$season_number: Float!, \$serie_id: MongoID!) {\\n listEpisodes(sort: NUMBER_ASC, filter: {type_serie: \\\"dorama\\\", " +
"serie_id: \$serie_id, season_number: \$season_number}) {\\n _id\\n name\\n slug\\n serie_name\\n serie_name_es\\n " + "serie_id: \$serie_id, season_number: \$season_number}) {\\n _id\\n name\\n slug\\n serie_name\\n serie_name_es\\n " +
"serie_id\\n still_path\\n air_date\\n season_number\\n episode_number\\n languages\\n poster\\n backdrop\\n __typename\\n }\\n}\\n\"}" "serie_id\\n still_path\\n air_date\\n season_number\\n episode_number\\n languages\\n poster\\n backdrop\\n __typename\\n }\\n}\\n\"}"
).toRequestBody(mediaType) ).toRequestBody(mediaType)
client.newCall(POST(apiUrl, popularRequestHeaders, body)).execute().let { resp -> jsonEpisodes.add(resp.body.string()) }
val episodes = client.newCall(POST(apiUrl, popularRequestHeaders, body)).execute().let { resp ->
json.decodeFromString<EpisodeModel>(resp.body.string())
}
parseEpisodeListJson(episodes)
} }
jsonEpisodes.forEach { json -> episodes.addAll(parseEpisodeListJson(json)) } }.reversed()
}
return episodes.reversed()
} }
private fun parseEpisodeListJson(jsonLine: String?): List<SEpisode> { private fun parseEpisodeListJson(episodes: EpisodeModel): List<SEpisode> {
val jsonData = jsonLine ?: return emptyList() var isUpcoming = false
val episodes = mutableListOf<SEpisode>() val currentDate = Date().time
val data = json.decodeFromString<JsonObject>(jsonData)!!.jsonObject["data"]!!.jsonObject return episodes.data.listEpisodes.mapIndexed { idx, episodeObject ->
data["listEpisodes"]!!.jsonArray!!.map { val dateEp = episodeObject.airDate
val noSeason = it.jsonObject["season_number"]!!.jsonPrimitive!!.content val nameEp = if (episodeObject.name.isNullOrEmpty()) "- Capítulo ${episodeObject.episodeNumber}" else "- ${episodeObject.name}"
val noEpisode = it.jsonObject["episode_number"]!!.jsonPrimitive!!.content if (dateEp != null && dateEp.toDate() > currentDate && !isUpcoming) isUpcoming = true
var nameEp = it.jsonObject["name"]!!.jsonPrimitive!!.content
nameEp = if (nameEp == "null") "- Capítulo $noEpisode" else "- $nameEp" SEpisode.create().apply {
val slug = it.jsonObject["slug"]!!.jsonPrimitive!!.content name = "T${episodeObject.seasonNumber} - E${episodeObject.episodeNumber} $nameEp"
val episode = SEpisode.create() episode_number = episodeObject.episodeNumber?.toFloat() ?: idx.toFloat()
episode.name = "T$noSeason - E$noEpisode $nameEp" date_upload = dateEp?.toDate() ?: 0L
episode.episode_number = noEpisode.toFloat() scanlator = if (isUpcoming) "Próximamente..." else null
episode.setUrlWithoutDomain(urlSolverByType("episode", slug)) setUrlWithoutDomain(urlSolverByType("episode", episodeObject.slug))
episodes.add(episode) }
} }
return episodes
} }
override fun latestUpdatesParse(response: Response): AnimesPage { override fun latestUpdatesParse(response: Response): AnimesPage {
val responseString = response.body.string() val responseString = response.body.string()
return parsePopularAnimeJson(responseString) return when {
responseString.contains("paginationMovie") -> parsePopularJson(responseString, "movie")
else -> parsePopularJson(responseString, "dorama")
}
} }
override fun latestUpdatesRequest(page: Int): Request { override fun latestUpdatesRequest(page: Int): Request {
@ -226,7 +241,10 @@ class Doramasflix : ConfigurableAnimeSource, AnimeHttpSource() {
override fun popularAnimeParse(response: Response): AnimesPage { override fun popularAnimeParse(response: Response): AnimesPage {
val responseString = response.body.string() val responseString = response.body.string()
return parsePopularAnimeJson(responseString) return when {
responseString.contains("paginationMovie") -> parsePopularJson(responseString, "movie")
else -> parsePopularJson(responseString, "dorama")
}
} }
private val languages = arrayOf( private val languages = arrayOf(
@ -248,26 +266,33 @@ class Doramasflix : ConfigurableAnimeSource, AnimeHttpSource() {
return languages.firstOrNull { it.first == this }?.second ?: "" return languages.firstOrNull { it.first == this }?.second ?: ""
} }
private fun parsePopularAnimeJson(jsonLine: String?): AnimesPage { private fun parsePopularJson(jsonLine: String?, type: String): AnimesPage {
val jsonData = jsonLine ?: return AnimesPage(emptyList(), false) val jsonData = jsonLine ?: return AnimesPage(emptyList(), false)
val animeList = mutableListOf<SAnime>() val data = json.decodeFromString<PaginationModel>(jsonData).data
val paginationDorama = json.decodeFromString<JsonObject>(jsonData)!!.jsonObject["data"]!!.jsonObject!!["paginationDorama"]!!.jsonObject
val hasNextPage = paginationDorama["pageInfo"]!!.jsonObject["hasNextPage"]!!.jsonPrimitive!!.content!!.toBoolean()
paginationDorama["items"]!!.jsonArray.map {
val anime = SAnime.create()
val genres = it.jsonObject!!["genres"]!!.jsonArray!!.joinToString { it.jsonObject["name"]!!.jsonPrimitive!!.content }
val id = it.jsonObject!!["_id"]!!.jsonPrimitive!!.content
val poster = it.jsonObject["poster_path"]!!.jsonPrimitive.content
val urlImg = poster.ifEmpty { it.jsonObject!!["poster"]!!.jsonPrimitive.content }
anime.title = "${it.jsonObject!!["name"]!!.jsonPrimitive!!.content} (${it.jsonObject!!["name_es"]!!.jsonPrimitive!!.content})" val pagination = when (type) {
anime.description = it.jsonObject!!["overview"]!!.jsonPrimitive!!.content "dorama" -> data.paginationDorama
anime.genre = genres "movie" -> data.paginationMovie
anime.thumbnail_url = externalOrInternalImg(urlImg, true) else -> throw IllegalArgumentException("Tipo de dato no válido: $type")
anime.setUrlWithoutDomain(urlSolverByType(it.jsonObject!!["__typename"]!!.jsonPrimitive!!.content, it.jsonObject!!["slug"]!!.jsonPrimitive!!.content, id))
animeList.add(anime)
} }
return AnimesPage(animeList, hasNextPage)
val hasNextPage = pagination?.pageInfo?.hasNextPage ?: false
val animeList = pagination?.items?.map { animeObject ->
val urlImg = when {
!animeObject.posterPath.isNullOrEmpty() -> animeObject.posterPath.toString()
!animeObject.poster.isNullOrEmpty() -> animeObject.poster.toString()
else -> ""
}
SAnime.create().apply {
title = "${animeObject.name} (${animeObject.nameEs})"
description = animeObject.overview
genre = animeObject.genres.joinToString { it.name ?: "" }
thumbnail_url = externalOrInternalImg(urlImg, true)
setUrlWithoutDomain(urlSolverByType(animeObject.typename, animeObject.slug, animeObject.id))
}
}
return AnimesPage(animeList ?: emptyList(), hasNextPage)
} }
private fun urlSolverByType(type: String, slug: String, id: String? = ""): String { private fun urlSolverByType(type: String, slug: String, id: String? = ""): String {
@ -296,45 +321,45 @@ class Doramasflix : ConfigurableAnimeSource, AnimeHttpSource() {
override fun searchAnimeParse(response: Response): AnimesPage { override fun searchAnimeParse(response: Response): AnimesPage {
val responseString = response.body.string() val responseString = response.body.string()
return if (responseString.contains("searchDorama")) { return when {
parseSearchAnimeJson(responseString) responseString.contains("searchDorama") -> parseSearchAnimeJson(responseString)
} else { responseString.contains("paginationMovie") -> parsePopularJson(responseString, "movie")
parsePopularAnimeJson(responseString) else -> parsePopularJson(responseString, "dorama")
} }
} }
private fun parseSearchAnimeJson(jsonLine: String?): AnimesPage { private fun parseSearchAnimeJson(jsonLine: String?): AnimesPage {
val jsonData = jsonLine ?: return AnimesPage(emptyList(), false) val jsonData = jsonLine ?: return AnimesPage(emptyList(), false)
val jsonObject = json.decodeFromString<SearchModel>(jsonData).data
val animeList = mutableListOf<SAnime>() val animeList = mutableListOf<SAnime>()
val paginationDorama = json.decodeFromString<JsonObject>(jsonData)!!.jsonObject["data"]!!.jsonObject jsonObject.searchDorama.map { castToSAnime(it) }.also(animeList::addAll)
paginationDorama["searchDorama"]!!.jsonArray.map { jsonObject.searchMovie.map { castToSAnime(it) }.also(animeList::addAll)
val anime = SAnime.create()
val id = it.jsonObject!!["_id"]!!.jsonPrimitive!!.content
val poster = it.jsonObject!!["poster_path"]!!.jsonPrimitive!!.content
val urlImg = poster.ifEmpty { it.jsonObject!!["poster"]!!.jsonPrimitive!!.content }
anime.title = "${it.jsonObject!!["name"]!!.jsonPrimitive!!.content} (${it.jsonObject!!["name_es"]!!.jsonPrimitive!!.content})"
anime.thumbnail_url = externalOrInternalImg(urlImg, true)
anime.setUrlWithoutDomain(urlSolverByType(it.jsonObject!!["__typename"]!!.jsonPrimitive!!.content, it.jsonObject!!["slug"]!!.jsonPrimitive!!.content, id))
animeList.add(anime)
}
paginationDorama["searchMovie"]!!.jsonArray.map {
val anime = SAnime.create()
val id = it.jsonObject!!["_id"]!!.jsonPrimitive!!.content
val poster = it.jsonObject!!["poster_path"]!!.jsonPrimitive!!.content
val urlImg = poster.ifEmpty { it.jsonObject!!["poster"]!!.jsonPrimitive!!.content }
anime.title = "${it.jsonObject!!["name"]!!.jsonPrimitive!!.content} (${it.jsonObject!!["name_es"]!!.jsonPrimitive!!.content})"
anime.thumbnail_url = externalOrInternalImg(urlImg, true)
anime.setUrlWithoutDomain(urlSolverByType(it.jsonObject!!["__typename"]!!.jsonPrimitive!!.content, it.jsonObject!!["slug"]!!.jsonPrimitive!!.content, id))
animeList.add(anime)
}
return AnimesPage(animeList, false) return AnimesPage(animeList, false)
} }
private fun castToSAnime(animeObject: SearchDorama): SAnime {
val urlImg = when {
!animeObject.posterPath.isNullOrEmpty() -> animeObject.posterPath.toString()
!animeObject.poster.isNullOrEmpty() -> animeObject.poster.toString()
else -> ""
}
return SAnime.create().apply {
title = "${animeObject.name} (${animeObject.nameEs})"
thumbnail_url = externalOrInternalImg(urlImg, true)
setUrlWithoutDomain(urlSolverByType(animeObject.typename, animeObject.slug, animeObject.id))
}
}
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 genreFilter = filterList.find { it is GenreFilter } as GenreFilter
return when { return when {
query.isNotBlank() -> searchQueryRequest(query) query.isNotBlank() -> searchQueryRequest(query)
"peliculas" in genreFilter.toUriPart() -> popularMovieRequest(page)
"variedades" in genreFilter.toUriPart() -> popularVarietiesRequest(page)
else -> popularAnimeRequest(page) else -> popularAnimeRequest(page)
} }
} }
@ -350,123 +375,148 @@ class Doramasflix : ConfigurableAnimeSource, AnimeHttpSource() {
return POST(apiUrl, popularRequestHeaders, body) return POST(apiUrl, popularRequestHeaders, body)
} }
private fun popularMovieRequest(page: Int): Request {
val mediaType = "application/json; charset=utf-8".toMediaType()
val body = (
"{\"operationName\":\"listMovies\",\"variables\":{\"perPage\":32,\"sort\":\"CREATEDAT_DESC\",\"filter\":{},\"page\":$page},\"query\":\"query " +
"listMovies(\$page: Int, \$perPage: Int, \$sort: SortFindManyMovieInput, \$filter: FilterFindManyMovieInput) {\\n paginationMovie(page: \$page" +
", perPage: \$perPage, sort: \$sort, filter: \$filter) {\\n count\\n pageInfo {\\n currentPage\\n hasNextPage\\n hasPreviousPage\\n" +
" __typename\\n }\\n items {\\n _id\\n name\\n name_es\\n slug\\n cast\\n names\\n overview\\n " +
"languages\\n popularity\\n poster_path\\n vote_average\\n backdrop_path\\n release_date\\n runtime\\n poster\\n " +
"backdrop\\n genres {\\n name\\n __typename\\n }\\n networks {\\n name\\n __typename\\n }\\n " +
"__typename\\n }\\n __typename\\n }\\n}\\n\"}"
).toRequestBody(mediaType)
return POST(apiUrl, popularRequestHeaders, body)
}
private fun popularVarietiesRequest(page: Int): Request {
val mediaType = "application/json; charset=utf-8".toMediaType()
val body = (
"{\"operationName\":\"listDoramas\",\"variables\":{\"page\":$page,\"sort\":\"CREATEDAT_DESC\",\"perPage\":32,\"filter\":{\"isTVShow\":true}},\"query\":\"query " +
"listDoramas(\$page: Int, \$perPage: Int, \$sort: SortFindManyDoramaInput, \$filter: FilterFindManyDoramaInput) {\\n paginationDorama(page: \$page, perPage: \$perPage, " +
"sort: \$sort, filter: \$filter) {\\n count\\n pageInfo {\\n currentPage\\n hasNextPage\\n hasPreviousPage\\n __typename\\n }\\n " +
"items {\\n _id\\n name\\n name_es\\n slug\\n cast\\n names\\n overview\\n languages\\n created_by\\n " +
"popularity\\n poster_path\\n vote_average\\n backdrop_path\\n first_air_date\\n episode_run_time\\n isTVShow\\n poster\\n " +
"backdrop\\n genres {\\n name\\n slug\\n __typename\\n }\\n networks {\\n name\\n slug\\n " +
"__typename\\n }\\n __typename\\n }\\n __typename\\n }\\n}\\n\"}"
).toRequestBody(mediaType)
return POST(apiUrl, popularRequestHeaders, body)
}
override fun getFilterList(): AnimeFilterList = AnimeFilterList(
AnimeFilter.Header("La busqueda por texto ignora el filtro"),
GenreFilter(),
)
private class GenreFilter : UriPartFilter(
"Géneros",
arrayOf(
Pair("Doramas", "doramas"),
Pair("Películas", "peliculas"),
Pair("Variedades", "variedades"),
),
)
private open class UriPartFilter(displayName: String, val vals: Array<Pair<String, String>>) :
AnimeFilter.Select<String>(displayName, vals.map { it.first }.toTypedArray()) {
fun toUriPart() = vals[state].second
}
private fun String.toDate(): Long {
return runCatching { DATE_FORMATTER.parse(trim())?.time }.getOrNull() ?: 0L
}
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 jsonData = document.selectFirst("script:containsData({\"props\":{\"pageProps\":{)")!!.data() val jsonData = document.selectFirst("script:containsData({\"props\":{\"pageProps\":{)")!!.data()
val apolloState = json.decodeFromString<JsonObject>(jsonData).jsonObject["props"]!!.jsonObject["pageProps"]!!.jsonObject["apolloState"]!!.jsonObject val apolloState = json.decodeFromString<JsonObject>(jsonData).jsonObject["props"]!!.jsonObject["pageProps"]!!.jsonObject["apolloState"]!!.jsonObject
val episode = apolloState.entries.firstOrNull { x -> x.key.contains("Episode:") }!!.value.jsonObject val episodeItem = apolloState.entries.firstOrNull { x -> x.key.contains("Episode:") }
val linksOnline = episode["links_online"]!!.jsonObject["json"]!!.jsonArray val episode = episodeItem?.value?.jsonObject
?: apolloState.entries.firstOrNull { (key, _) -> Regex("\\b(?:Movie|Dorama):[a-zA-Z0-9]+").matches(key) }?.value?.jsonObject
linksOnline.map { var linksOnline = episode?.get("links_online")?.jsonObject?.get("json")?.jsonArray
val bMovies = apolloState.entries.any { x -> x.key.contains("ROOT_QUERY.getMovieLinks(") }
if (bMovies && linksOnline == null) {
linksOnline = apolloState.entries.firstOrNull { x -> x.key.contains("ROOT_QUERY.getMovieLinks(") }
?.value?.jsonObject?.get("links_online")?.jsonObject?.get("json")?.jsonArray
}
return linksOnline?.parallelCatchingFlatMapBlocking {
val link = it.jsonObject["link"]!!.jsonPrimitive.content val link = it.jsonObject["link"]!!.jsonPrimitive.content
val lang = it.jsonObject["lang"]?.jsonPrimitive?.content?.getLang() ?: "" val lang = it.jsonObject["lang"]?.jsonPrimitive?.content?.getLang() ?: ""
serverVideoResolver(link, lang).also(videoList::addAll) serverVideoResolver(link, lang)
} } ?: apolloState.entries.filter { x -> x.key.contains("ROOT_QUERY.listProblems(") }
return videoList .mapNotNull { entry ->
val server = entry.value.jsonObject["server"]?.jsonObject?.get("json")?.jsonObject
val link = server?.get("link")?.jsonPrimitive?.content
val lang = server?.get("lang")?.jsonPrimitive?.content?.getLang() ?: ""
link?.let { it to lang }
}.distinctBy { it.first }
.parallelCatchingFlatMapBlocking { (link, lang) ->
val finalLink = getRealLink(link)
serverVideoResolver(finalLink, lang)
}
}
private fun getRealLink(link: String): String {
if (!link.contains("fkplayer.xyz")) return link
val token = client.newCall(GET(link)).execute()
.asJsoup().selectFirst("script:containsData({\"props\":{\"pageProps\":{)")?.data()
?.parseTo<TokenModel>()
val mediaType = "application/json".toMediaType()
val requestBody = "{\"token\":\"${token?.props?.pageProps?.token ?: token?.query?.token}\"}".toRequestBody(mediaType)
val headersVideo = headers.newBuilder()
.add("origin", "https://${link.toHttpUrl().host}")
.add("Content-Type", "application/json")
.build()
val json = client.newCall(POST("https://fkplayer.xyz/api/decoding", headersVideo, requestBody))
.execute().body.string().parseTo<VideoToken>()
return String(Base64.decode(json.link, Base64.DEFAULT))
} }
private fun serverVideoResolver(url: String, prefix: String = ""): List<Video> { private fun serverVideoResolver(url: String, prefix: String = ""): List<Video> {
val videoList = mutableListOf<Video>()
val embedUrl = url.lowercase() val embedUrl = url.lowercase()
try { return when {
if (embedUrl.contains("voe")) { "voe" in embedUrl -> VoeExtractor(client).videosFromUrl(url, " $prefix")
VoeExtractor(client).videosFromUrl(url, prefix).also(videoList::addAll) "ok.ru" in embedUrl || "okru" in embedUrl -> OkruExtractor(client).videosFromUrl(url, prefix = "$prefix ")
} "filemoon" in embedUrl || "moonplayer" in embedUrl -> {
if ((embedUrl.contains("amazon") || embedUrl.contains("amz")) && !embedUrl.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, "$prefix Amazon", videoUrl))
}
}
if (embedUrl.contains("ok.ru") || embedUrl.contains("okru")) {
OkruExtractor(client).videosFromUrl(url, prefix = "$prefix ").also(videoList::addAll)
}
if (embedUrl.contains("filemoon") || embedUrl.contains("moonplayer")) {
val vidHeaders = headers.newBuilder() val vidHeaders = headers.newBuilder()
.add("Origin", "https://${url.toHttpUrl().host}") .add("Origin", "https://${url.toHttpUrl().host}")
.add("Referer", "https://${url.toHttpUrl().host}/") .add("Referer", "https://${url.toHttpUrl().host}/")
.build() .build()
FilemoonExtractor(client).videosFromUrl(url, prefix = "$prefix Filemoon:", headers = vidHeaders).also(videoList::addAll) FilemoonExtractor(client).videosFromUrl(url, prefix = "$prefix Filemoon:", headers = vidHeaders)
} }
if (embedUrl.contains("uqload")) { "uqload" in embedUrl -> UqloadExtractor(client).videosFromUrl(url, prefix = prefix)
UqloadExtractor(client).videosFromUrl(url, prefix = prefix).also(videoList::addAll) "mp4upload" in embedUrl -> Mp4uploadExtractor(client).videosFromUrl(url, prefix = "$prefix ", headers = headers)
} "doodstream" in embedUrl || "dood." in embedUrl ->
if (embedUrl.contains("mp4upload")) { listOf(DoodExtractor(client).videoFromUrl(url.replace("https://doodstream.com/e/", "https://dood.to/e/"), "$prefix DoodStream", false)!!)
Mp4uploadExtractor(client).videosFromUrl(url, prefix = "$prefix ", headers = headers).let { videoList.addAll(it) } "streamlare" in embedUrl -> StreamlareExtractor(client).videosFromUrl(url, prefix = prefix)
} "yourupload" in embedUrl || "upload" in embedUrl -> YourUploadExtractor(client).videoFromUrl(url, headers = headers, prefix = "$prefix ")
if (embedUrl.contains("wishembed") || embedUrl.contains("streamwish") || embedUrl.contains("strwish") || embedUrl.contains("wish")) { "wishembed" in embedUrl || "streamwish" in embedUrl || "strwish" in embedUrl || "wish" in embedUrl -> {
val docHeaders = headers.newBuilder() val docHeaders = headers.newBuilder()
.add("Origin", "https://streamwish.to") .add("Origin", "https://streamwish.to")
.add("Referer", "https://streamwish.to/") .add("Referer", "https://streamwish.to/")
.build() .build()
StreamWishExtractor(client, docHeaders).videosFromUrl(url, videoNameGen = { "$prefix StreamWish:$it" }).also(videoList::addAll) StreamWishExtractor(client, docHeaders).videosFromUrl(url, videoNameGen = { "$prefix StreamWish:$it" })
} }
if (embedUrl.contains("doodstream") || embedUrl.contains("dood.")) { "burstcloud" in embedUrl || "burst" in embedUrl -> BurstCloudExtractor(client).videoFromUrl(url, headers = headers, prefix = "$prefix ")
val url2 = url.replace("https://doodstream.com/e/", "https://dood.to/e/") "fastream" in embedUrl -> FastreamExtractor(client, headers).videosFromUrl(url, prefix = "$prefix Fastream:")
DoodExtractor(client).videoFromUrl(url2, "$prefix DoodStream", false)?.let { videoList.add(it) } "upstream" in embedUrl -> UpstreamExtractor(client).videosFromUrl(url, prefix = "$prefix ")
} "streamtape" in embedUrl || "stp" in embedUrl || "stape" in embedUrl -> listOf(StreamTapeExtractor(client).videoFromUrl(url, quality = "$prefix StreamTape")!!)
if (embedUrl.contains("streamlare")) { "ahvsh" in embedUrl || "streamhide" in embedUrl -> StreamHideVidExtractor(client).videosFromUrl(url, "$prefix ")
StreamlareExtractor(client).videosFromUrl(url, prefix = prefix).let { videoList.addAll(it) } "filelions" in embedUrl || "lion" in embedUrl -> StreamWishExtractor(client, headers).videosFromUrl(url, videoNameGen = { "$prefix FileLions:$it" })
} "vudeo" in embedUrl || "vudea" in embedUrl -> VudeoExtractor(client).videosFromUrl(url, "$prefix ")
if (embedUrl.contains("yourupload") || embedUrl.contains("upload")) { else -> emptyList()
YourUploadExtractor(client).videoFromUrl(url, headers = headers, prefix = "$prefix ").let { videoList.addAll(it) } }
}
if (embedUrl.contains("burstcloud") || embedUrl.contains("burst")) {
BurstCloudExtractor(client).videoFromUrl(url, headers = headers, prefix = "$prefix ").let { videoList.addAll(it) }
}
if (embedUrl.contains("fastream")) {
FastreamExtractor(client, headers).videosFromUrl(url, prefix = "$prefix Fastream:").also(videoList::addAll)
}
if (embedUrl.contains("upstream")) {
UpstreamExtractor(client).videosFromUrl(url, prefix = "$prefix ").let { videoList.addAll(it) }
}
if (embedUrl.contains("streamtape") || embedUrl.contains("stp") || embedUrl.contains("stape")) {
StreamTapeExtractor(client).videoFromUrl(url, quality = "$prefix StreamTape")?.let { videoList.add(it) }
}
if (embedUrl.contains("ahvsh") || embedUrl.contains("streamhide")) {
StreamHideVidExtractor(client).videosFromUrl(url, "$prefix ").let { videoList.addAll(it) }
}
if (embedUrl.contains("filelions") || embedUrl.contains("lion")) {
StreamWishExtractor(client, headers).videosFromUrl(url, videoNameGen = { "$prefix FileLions:$it" }).also(videoList::addAll)
}
if (embedUrl.contains("tomatomatela")) {
runCatching {
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) { }
return videoList
} }
override fun List<Video>.sort(): List<Video> { override fun List<Video>.sort(): List<Video> {
@ -532,4 +582,11 @@ class Doramasflix : ConfigurableAnimeSource, AnimeHttpSource() {
} }
}.also(screen::addPreference) }.also(screen::addPreference)
} }
private inline fun <reified T> String.parseTo(): T {
return json.decodeFromString<T>(this)
}
private inline fun <reified T> Response.parseTo(): T {
return json.decodeFromString<T>(this.body.string())
}
} }

View File

@ -1,7 +1,7 @@
ext { ext {
extName = 'LocoPelis' extName = 'LocoPelis'
extClass = '.LocoPelis' extClass = '.LocoPelis'
extVersionCode = 20 extVersionCode = 21
} }
apply from: "$rootDir/common.gradle" apply from: "$rootDir/common.gradle"
@ -10,4 +10,5 @@ dependencies {
implementation(project(':lib:streamtape-extractor')) implementation(project(':lib:streamtape-extractor'))
implementation(project(':lib:okru-extractor')) implementation(project(':lib:okru-extractor'))
implementation(project(':lib:dood-extractor')) implementation(project(':lib:dood-extractor'))
implementation(project(':lib:streamhidevid-extractor'))
} }

View File

@ -13,9 +13,11 @@ import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.animesource.online.ParsedAnimeHttpSource 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.streamhidevidextractor.StreamHideVidExtractor
import eu.kanade.tachiyomi.lib.streamtapeextractor.StreamTapeExtractor import eu.kanade.tachiyomi.lib.streamtapeextractor.StreamTapeExtractor
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.Request import okhttp3.Request
import okhttp3.Response import okhttp3.Response
import org.jsoup.nodes.Document import org.jsoup.nodes.Document
@ -90,35 +92,23 @@ class LocoPelis : 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>() return document.select(".tab_container .tab_content iframe").parallelCatchingFlatMapBlocking { iframe ->
document.select(".tab_container .tab_content iframe").forEach { iframe -> runCatching {
val url = iframe.attr("src") val url = iframe.attr("src")
val embedUrl = url.lowercase() with(url.lowercase()) {
if (embedUrl.contains("streamtape")) { when {
val video = StreamTapeExtractor(client).videoFromUrl(url, "StreamTape") contains("streamtape") || contains("stp") || contains("stape")
if (video != null) { -> listOf(StreamTapeExtractor(client).videoFromUrl(this, quality = "StreamTape")!!)
videoList.add(video) contains("doodstream") || contains("dood.") || contains("ds2play") || contains("doods.")
-> listOf(DoodExtractor(client).videoFromUrl(this, "DoodStream", true)!!)
contains("ok.ru") || contains("okru") -> OkruExtractor(client).videosFromUrl(this)
contains("vidhide") || contains("streamhide") || contains("guccihide") || contains("streamvid")
-> StreamHideVidExtractor(client).videosFromUrl(this)
else -> emptyList()
}
} }
} }.getOrDefault(emptyList())
if (embedUrl.contains("doodstream") ||
embedUrl.contains("dood") ||
embedUrl.contains("ds2play")
) {
val video = try {
DoodExtractor(client).videoFromUrl(url, "DoodStream", true)
} catch (e: Exception) {
null
}
if (video != null) {
videoList.add(video)
}
}
if (embedUrl.contains("okru") || embedUrl.contains("ok.ru")) {
val videos = OkruExtractor(client).videosFromUrl(url)
videoList.addAll(videos)
}
} }
return videoList
} }
override fun videoListSelector() = throw UnsupportedOperationException() override fun videoListSelector() = throw UnsupportedOperationException()

View File

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

View File

@ -28,9 +28,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 kotlinx.serialization.json.Json import eu.kanade.tachiyomi.util.parallelCatchingFlatMapBlocking
import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.jsonPrimitive
import okhttp3.HttpUrl.Companion.toHttpUrl import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.Request import okhttp3.Request
import okhttp3.Response import okhttp3.Response
@ -38,7 +36,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
open class Pelisplushd(override val name: String, override val baseUrl: String) : ConfigurableAnimeSource, ParsedAnimeHttpSource() { open class Pelisplushd(override val name: String, override val baseUrl: String) : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
@ -46,8 +43,6 @@ open class Pelisplushd(override val name: String, override val baseUrl: String)
override val supportsLatest = false override val supportsLatest = false
private val json: Json by injectLazy()
val preferences: SharedPreferences by lazy { val preferences: SharedPreferences by lazy {
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000) Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
} }
@ -111,161 +106,114 @@ open class Pelisplushd(override val name: String, override val baseUrl: String)
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() val data = document.selectFirst("script:containsData(video[1] = )")?.data()
val apiUrl = data.substringAfter("video[1] = '", "").substringBefore("';", "") val apiUrl = data?.substringAfter("video[1] = '", "")?.substringBefore("';", "")
val alternativeServers = document.select("ul.TbVideoNv.nav.nav-tabs li:not(:first-child)") val alternativeServers = document.select("ul.TbVideoNv.nav.nav-tabs li:not(:first-child)")
if (apiUrl.isNotEmpty()) { if (!apiUrl.isNullOrEmpty()) {
val apiResponse = client.newCall(GET(apiUrl)).execute().asJsoup() val apiResponse = client.newCall(GET(apiUrl)).execute().asJsoup()
val encryptedList = apiResponse!!.select("#PlayerDisplay div[class*=\"OptionsLangDisp\"] div[class*=\"ODDIV\"] div[class*=\"OD\"] li")
val regIsUrl = "https?:\\/\\/(www\\.)?[-a-zA-Z0-9@:%._\\+~#=]{1,256}\\.[a-zA-Z0-9()]{1,6}\\b([-a-zA-Z0-9()@:%_\\+.~#?&//=]*)".toRegex() val regIsUrl = "https?:\\/\\/(www\\.)?[-a-zA-Z0-9@:%._\\+~#=]{1,256}\\.[a-zA-Z0-9()]{1,6}\\b([-a-zA-Z0-9()@:%_\\+.~#?&//=]*)".toRegex()
val encryptedList = apiResponse.select("#PlayerDisplay div[class*=\"OptionsLangDisp\"] div[class*=\"ODDIV\"] div[class*=\"OD\"] li")
encryptedList.forEach { encryptedList.parallelCatchingFlatMapBlocking {
val server = it.select("span").text() val url = it.attr("onclick")
var url = it.attr("onclick")
.substringAfter("go_to_player('") .substringAfter("go_to_player('")
.substringAfter("go_to_playerVast('")
.substringBefore("?cover_url=") .substringBefore("?cover_url=")
.substringBefore("')") .substringBefore("')")
.substringBefore("',") .substringBefore("',")
.substringBefore("?poster") .substringBefore("?poster")
.substringBefore("?c_poster=")
.substringBefore("?thumb=")
.substringBefore("#poster=") .substringBefore("#poster=")
if (!regIsUrl.containsMatchIn(url)) { val realUrl = if (!regIsUrl.containsMatchIn(url)) {
url = String(Base64.decode(url, Base64.DEFAULT)) String(Base64.decode(url, Base64.DEFAULT))
} else if (url.contains("?data=")) {
val apiPageSoup = client.newCall(GET(url)).execute().asJsoup()
apiPageSoup.selectFirst("iframe")?.attr("src") ?: ""
} else {
url
} }
if (!url.contains("?data=")) { serverVideoResolver(realUrl)
serverVideoResolver(url)?.forEach { video -> videoList.add(video) } }.also(videoList::addAll)
} else {
val apiPageSoup = client.newCall(GET(url)).execute().asJsoup()
val realUrl = apiPageSoup.selectFirst("iframe")?.attr("src")
if (realUrl != null) {
serverVideoResolver(realUrl)?.forEach { video -> videoList.add(video) }
}
}
}
} }
// verifier for old series // verifier for old series
if (!apiUrl.contains("/video/") || alternativeServers.any()) { if (!apiUrl.isNullOrEmpty() && !apiUrl.contains("/video/") || alternativeServers.any()) {
document.select("ul.TbVideoNv.nav.nav-tabs li").forEach { id -> document.select("ul.TbVideoNv.nav.nav-tabs li").parallelCatchingFlatMapBlocking { id ->
val serverName = id.select("a").text() val serverName = id.select("a").text().lowercase()
val serverId = id.attr("data-id") val serverId = id.attr("data-id")
var serverUrl = data.substringAfter("video[$serverId] = '", "").substringBefore("';", "") var serverUrl = data?.substringAfter("video[$serverId] = '", "")?.substringBefore("';", "")
if (serverUrl.contains("api.mycdn.moe")) { if (serverUrl != null && serverUrl.contains("api.mycdn.moe")) {
val urlId = serverUrl.substringAfter("id=") val urlId = serverUrl.substringAfter("id=")
when (serverName.lowercase()) { serverUrl = when (serverName) {
"sbfast" -> { serverUrl = "https://sbfull.com/e/$urlId" } "sbfast" -> { "https://sbfull.com/e/$urlId" }
"plusto" -> { serverUrl = "https://owodeuwu.xyz/v/$urlId" } "plusto" -> { "https://owodeuwu.xyz/v/$urlId" }
"doodstream" -> { serverUrl = "https://dood.to/e/$urlId" } "doodstream" -> { "https://dood.to/e/$urlId" }
"upload", "uqload" -> { serverUrl = "https://uqload.com/embed-$urlId.html" } "upload", "uqload" -> { "https://uqload.com/embed-$urlId.html" }
else -> ""
} }
} }
serverVideoResolver(serverUrl)?.forEach { video -> videoList.add(video) }
} serverVideoResolver(serverUrl ?: "")
}.also(videoList::addAll)
} }
return videoList return videoList
} }
private fun serverVideoResolver(url: String): List<Video> { private fun serverVideoResolver(url: String): List<Video> {
val videoList = mutableListOf<Video>()
val embedUrl = url.lowercase() val embedUrl = url.lowercase()
try { return runCatching {
if (embedUrl.contains("voe")) { when {
VoeExtractor(client).videosFromUrl(url).also(videoList::addAll) embedUrl.contains("voe") -> VoeExtractor(client).videosFromUrl(url)
} embedUrl.contains("ok.ru") || embedUrl.contains("okru") -> OkruExtractor(client).videosFromUrl(url)
if ((embedUrl.contains("amazon") || embedUrl.contains("amz")) && !embedUrl.contains("disable")) { embedUrl.contains("filemoon") || embedUrl.contains("moonplayer") -> {
val body = client.newCall(GET(url)).execute().asJsoup() val vidHeaders = headers.newBuilder()
if (body.select("script:containsData(var shareId)").toString().isNotBlank()) { .add("Origin", "https://${url.toHttpUrl().host}")
val shareId = body.selectFirst("script:containsData(var shareId)")!!.data() .add("Referer", "https://${url.toHttpUrl().host}/")
.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))
}
}
if (embedUrl.contains("ok.ru") || embedUrl.contains("okru")) {
OkruExtractor(client).videosFromUrl(url).also(videoList::addAll)
}
if (embedUrl.contains("filemoon") || embedUrl.contains("moonplayer")) {
val vidHeaders = headers.newBuilder()
.add("Origin", "https://${url.toHttpUrl().host}")
.add("Referer", "https://${url.toHttpUrl().host}/")
.build()
FilemoonExtractor(client).videosFromUrl(url, prefix = "Filemoon:", headers = vidHeaders).also(videoList::addAll)
}
if (embedUrl.contains("uqload")) {
UqloadExtractor(client).videosFromUrl(url).also(videoList::addAll)
}
if (embedUrl.contains("mp4upload")) {
Mp4uploadExtractor(client).videosFromUrl(url, headers).let { videoList.addAll(it) }
}
if (embedUrl.contains("wishembed") || embedUrl.contains("streamwish") || embedUrl.contains("strwish") || embedUrl.contains("wish")) {
val docHeaders = headers.newBuilder()
.add("Origin", "https://streamwish.to")
.add("Referer", "https://streamwish.to/")
.build()
StreamWishExtractor(client, docHeaders).videosFromUrl(url, videoNameGen = { "StreamWish:$it" }).also(videoList::addAll)
}
if (embedUrl.contains("doodstream") || embedUrl.contains("dood.")) {
val url2 = url.replace("https://doodstream.com/e/", "https://dood.to/e/")
DoodExtractor(client).videoFromUrl(url2, "DoodStream", false)?.let { videoList.add(it) }
}
if (embedUrl.contains("streamlare")) {
StreamlareExtractor(client).videosFromUrl(url).let { videoList.addAll(it) }
}
if (embedUrl.contains("yourupload") || embedUrl.contains("upload")) {
YourUploadExtractor(client).videoFromUrl(url, headers = headers).let { videoList.addAll(it) }
}
if (embedUrl.contains("burstcloud") || embedUrl.contains("burst")) {
BurstCloudExtractor(client).videoFromUrl(url, headers = headers).let { videoList.addAll(it) }
}
if (embedUrl.contains("fastream")) {
FastreamExtractor(client, headers).videosFromUrl(url).also(videoList::addAll)
}
if (embedUrl.contains("upstream")) {
UpstreamExtractor(client).videosFromUrl(url).let { videoList.addAll(it) }
}
if (embedUrl.contains("streamtape") || embedUrl.contains("stp") || embedUrl.contains("stape")) {
StreamTapeExtractor(client).videoFromUrl(url)?.let { videoList.add(it) }
}
if (embedUrl.contains("ahvsh") || embedUrl.contains("streamhide")) {
StreamHideExtractor(client).videosFromUrl(url, "StreamHide").let { videoList.addAll(it) }
}
if (embedUrl.contains("filelions") || embedUrl.contains("lion")) {
StreamWishExtractor(client, headers).videosFromUrl(url, videoNameGen = { "FileLions:$it" }).also(videoList::addAll)
}
if (embedUrl.contains("tomatomatela")) {
runCatching {
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() .build()
val token = url.substringAfter("/embed.html#") FilemoonExtractor(client).videosFromUrl(url, prefix = "Filemoon:", headers = vidHeaders)
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, "Tomatomatela", file, headers = null)) }
} }
!embedUrl.contains("disable") && (embedUrl.contains("amazon") || embedUrl.contains("amz")) -> {
val body = client.newCall(GET(url)).execute().asJsoup()
return 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("\"")
listOf(Video(videoUrl, "Amazon", videoUrl))
} else {
emptyList()
}
}
embedUrl.contains("uqload") -> UqloadExtractor(client).videosFromUrl(url)
embedUrl.contains("mp4upload") -> Mp4uploadExtractor(client).videosFromUrl(url, headers)
embedUrl.contains("wishembed") || embedUrl.contains("streamwish") || embedUrl.contains("strwish") || embedUrl.contains("wish") -> {
val docHeaders = headers.newBuilder()
.add("Origin", "https://streamwish.to")
.add("Referer", "https://streamwish.to/")
.build()
StreamWishExtractor(client, docHeaders).videosFromUrl(url, videoNameGen = { "StreamWish:$it" })
}
embedUrl.contains("doodstream") || embedUrl.contains("dood.") || embedUrl.contains("ds2play") || embedUrl.contains("doods.") -> {
val url2 = url.replace("https://doodstream.com/e/", "https://dood.to/e/")
listOf(DoodExtractor(client).videoFromUrl(url2, "DoodStream", false)!!)
}
embedUrl.contains("streamlare") -> StreamlareExtractor(client).videosFromUrl(url)
embedUrl.contains("yourupload") || embedUrl.contains("upload") -> YourUploadExtractor(client).videoFromUrl(url, headers = headers)
embedUrl.contains("burstcloud") || embedUrl.contains("burst") -> BurstCloudExtractor(client).videoFromUrl(url, headers = headers)
embedUrl.contains("fastream") -> FastreamExtractor(client, headers).videosFromUrl(url, prefix = "Fastream:")
embedUrl.contains("upstream") -> UpstreamExtractor(client).videosFromUrl(url)
embedUrl.contains("streamtape") || embedUrl.contains("stp") || embedUrl.contains("stape") -> listOf(StreamTapeExtractor(client).videoFromUrl(url, quality = "StreamTape")!!)
embedUrl.contains("ahvsh") || embedUrl.contains("streamhide") || embedUrl.contains("guccihide") || embedUrl.contains("streamvid") -> StreamHideExtractor(client).videosFromUrl(url, "StreamHide")
else -> emptyList()
} }
} catch (_: Exception) { } }.getOrNull() ?: emptyList()
return videoList
} }
override fun videoListSelector() = throw UnsupportedOperationException() override fun videoListSelector() = throw UnsupportedOperationException()

View File

@ -23,20 +23,15 @@ 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 kotlinx.serialization.json.Json import eu.kanade.tachiyomi.util.parallelCatchingFlatMapBlocking
import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.jsonPrimitive
import okhttp3.HttpUrl.Companion.toHttpUrl import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.Request import okhttp3.Request
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
import uy.kohesive.injekt.injectLazy
class Pelisplusph(override val name: String, override val baseUrl: String) : Pelisplushd(name, baseUrl) { class Pelisplusph(override val name: String, override val baseUrl: String) : Pelisplushd(name, baseUrl) {
private val json: Json by injectLazy()
override val supportsLatest = false override val supportsLatest = false
companion object { companion object {
@ -82,7 +77,8 @@ class Pelisplusph(override val name: String, override val baseUrl: String) : Pel
anime.artist = p.select(".content-type ~ span").text().substringBefore(",") anime.artist = p.select(".content-type ~ span").text().substringBefore(",")
} }
} }
anime.status = if (document.location().contains("/serie/")) SAnime.UNKNOWN else SAnime.COMPLETED anime.status =
if (document.location().contains("/serie/")) SAnime.UNKNOWN else SAnime.COMPLETED
return anime return anime
} }
@ -107,7 +103,9 @@ class Pelisplusph(override val name: String, override val baseUrl: String) : Pel
index += 1 index += 1
val noEp = try { val noEp = try {
getNumberFromString(ep.ownText()) getNumberFromString(ep.ownText())
} catch (_: Exception) { idx + 1 } } catch (_: Exception) {
idx + 1
}
val episode = SEpisode.create().apply { val episode = SEpisode.create().apply {
episode_number = index.toFloat() episode_number = index.toFloat()
name = "T$seasonNumber - E$noEp - ${ep.ownText()}" name = "T$seasonNumber - E$noEp - ${ep.ownText()}"
@ -132,118 +130,54 @@ class Pelisplusph(override val name: String, override val baseUrl: String) : Pel
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>() return document.select("[class*=server-item-]").parallelCatchingFlatMapBlocking { serverItem ->
document.select("[class*=server-item-]").map { val langIdx = getNumberFromString(serverItem.attr("class").substringAfter("server-item-"))
val langIdx = getNumberFromString(it.attr("class").substringAfter("server-item-"))
val langItem = document.select("li[data-id=\"$langIdx\"] a").text() val langItem = document.select("li[data-id=\"$langIdx\"] a").text()
val lang = if (langItem.contains("Subtitulado")) "[SUB]" else if (langItem.contains("Latino")) "[LAT]" else "[CAST]" val lang = if (langItem.contains("Subtitulado")) "[SUB]" else if (langItem.contains("Latino")) "[LAT]" else "[CAST]"
it.select("li.tab-video").map { servers ->
val url = servers.attr("data-video") serverItem.select("li.tab-video").map { videoItem ->
serverVideoResolver(url, lang).let { videos -> val url = videoItem.attr("data-video")
videoList.addAll(videos) serverVideoResolver(url, lang)
} }.flatten()
}
} }
return videoList
} }
private fun serverVideoResolver(url: String, prefix: String = ""): List<Video> { private fun serverVideoResolver(url: String, prefix: String = ""): List<Video> {
val videoList = mutableListOf<Video>()
val embedUrl = url.lowercase() val embedUrl = url.lowercase()
try { return runCatching {
if (embedUrl.contains("voe")) { when {
VoeExtractor(client).videosFromUrl(url, prefix).also(videoList::addAll) embedUrl.contains("voe") -> VoeExtractor(client).videosFromUrl(url, prefix)
} embedUrl.contains("ok.ru") || embedUrl.contains("okru") -> OkruExtractor(client).videosFromUrl(url, prefix)
if ((embedUrl.contains("amazon") || embedUrl.contains("amz")) && !embedUrl.contains("disable")) { embedUrl.contains("filemoon") || embedUrl.contains("moonplayer") -> {
val body = client.newCall(GET(url)).execute().asJsoup() val vidHeaders = headers.newBuilder()
if (body.select("script:containsData(var shareId)").toString().isNotBlank()) { .add("Origin", "https://${url.toHttpUrl().host}")
val shareId = body.selectFirst("script:containsData(var shareId)")!!.data() .add("Referer", "https://${url.toHttpUrl().host}/")
.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, "$prefix Amazon", videoUrl))
}
}
if (embedUrl.contains("ok.ru") || embedUrl.contains("okru")) {
OkruExtractor(client).videosFromUrl(url, prefix).also(videoList::addAll)
}
if (embedUrl.contains("filemoon") || embedUrl.contains("moonplayer")) {
val vidHeaders = headers.newBuilder()
.add("Origin", "https://${url.toHttpUrl().host}")
.add("Referer", "https://${url.toHttpUrl().host}/")
.build()
FilemoonExtractor(client).videosFromUrl(url, prefix = "$prefix Filemoon:", headers = vidHeaders).also(videoList::addAll)
}
if (embedUrl.contains("uqload")) {
UqloadExtractor(client).videosFromUrl(url, prefix = prefix).also(videoList::addAll)
}
if (embedUrl.contains("mp4upload")) {
Mp4uploadExtractor(client).videosFromUrl(url, headers, prefix = prefix).let { videoList.addAll(it) }
}
if (embedUrl.contains("wishembed") || embedUrl.contains("streamwish") || embedUrl.contains("strwish") || embedUrl.contains("wish")) {
val docHeaders = headers.newBuilder()
.add("Origin", "https://streamwish.to")
.add("Referer", "https://streamwish.to/")
.build()
StreamWishExtractor(client, docHeaders).videosFromUrl(url, videoNameGen = { "$prefix StreamWish:$it" }).also(videoList::addAll)
}
if (embedUrl.contains("doodstream") || embedUrl.contains("dood.")) {
val url2 = url.replace("https://doodstream.com/e/", "https://dood.to/e/")
DoodExtractor(client).videoFromUrl(url2, "$prefix DoodStream", false)?.let { videoList.add(it) }
}
if (embedUrl.contains("streamlare")) {
StreamlareExtractor(client).videosFromUrl(url, prefix = prefix).let { videoList.addAll(it) }
}
if (embedUrl.contains("yourupload") || embedUrl.contains("upload")) {
YourUploadExtractor(client).videoFromUrl(url, headers = headers, prefix = prefix).let { videoList.addAll(it) }
}
if (embedUrl.contains("burstcloud") || embedUrl.contains("burst")) {
BurstCloudExtractor(client).videoFromUrl(url, headers = headers, prefix = prefix).let { videoList.addAll(it) }
}
if (embedUrl.contains("fastream")) {
FastreamExtractor(client, headers).videosFromUrl(url, prefix = "$prefix Fastream:").also(videoList::addAll)
}
if (embedUrl.contains("upstream")) {
UpstreamExtractor(client).videosFromUrl(url, prefix = prefix).let { videoList.addAll(it) }
}
if (embedUrl.contains("streamtape") || embedUrl.contains("stp") || embedUrl.contains("stape")) {
StreamTapeExtractor(client).videoFromUrl(url, quality = "$prefix StreamTape")?.let { videoList.add(it) }
}
if (embedUrl.contains("ahvsh") || embedUrl.contains("streamhide")) {
StreamHideExtractor(client).videosFromUrl(url, "$prefix StreamHide").let { videoList.addAll(it) }
}
if (embedUrl.contains("tomatomatela")) {
runCatching {
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() .build()
val token = url.substringAfter("/embed.html#") FilemoonExtractor(client).videosFromUrl(url, prefix = "$prefix Filemoon:", headers = vidHeaders)
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)) }
} }
embedUrl.contains("uqload") -> UqloadExtractor(client).videosFromUrl(url, prefix = prefix)
embedUrl.contains("mp4upload") -> Mp4uploadExtractor(client).videosFromUrl(url, headers, prefix = prefix)
embedUrl.contains("wishembed") || embedUrl.contains("streamwish") || embedUrl.contains("strwish") || embedUrl.contains("wish") -> {
val docHeaders = headers.newBuilder()
.add("Origin", "https://streamwish.to")
.add("Referer", "https://streamwish.to/")
.build()
StreamWishExtractor(client, docHeaders).videosFromUrl(url, videoNameGen = { "$prefix StreamWish:$it" })
}
embedUrl.contains("doodstream") || embedUrl.contains("dood.") || embedUrl.contains("ds2play") || embedUrl.contains("doods.") -> {
val url2 = url.replace("https://doodstream.com/e/", "https://dood.to/e/")
listOf(DoodExtractor(client).videoFromUrl(url2, "$prefix DoodStream", false)!!)
}
embedUrl.contains("streamlare") -> StreamlareExtractor(client).videosFromUrl(url, prefix = prefix)
embedUrl.contains("yourupload") || embedUrl.contains("upload") -> YourUploadExtractor(client).videoFromUrl(url, headers = headers, prefix = prefix)
embedUrl.contains("burstcloud") || embedUrl.contains("burst") -> BurstCloudExtractor(client).videoFromUrl(url, headers = headers, prefix = prefix)
embedUrl.contains("fastream") -> FastreamExtractor(client, headers).videosFromUrl(url, prefix = "$prefix Fastream:")
embedUrl.contains("upstream") -> UpstreamExtractor(client).videosFromUrl(url, prefix = prefix)
embedUrl.contains("streamtape") || embedUrl.contains("stp") || embedUrl.contains("stape") -> listOf(StreamTapeExtractor(client).videoFromUrl(url, quality = "$prefix StreamTape")!!)
embedUrl.contains("ahvsh") || embedUrl.contains("streamhide") || embedUrl.contains("guccihide") || embedUrl.contains("streamvid") -> StreamHideExtractor(client).videosFromUrl(url, "$prefix StreamHide")
else -> emptyList()
} }
} catch (_: Exception) { } }.getOrNull() ?: emptyList()
return videoList
} }
override fun List<Video>.sort(): List<Video> { override fun List<Video>.sort(): List<Video> {

View File

@ -21,10 +21,10 @@ import eu.kanade.tachiyomi.lib.streamwishextractor.StreamWishExtractor
import eu.kanade.tachiyomi.lib.upstreamextractor.UpstreamExtractor import eu.kanade.tachiyomi.lib.upstreamextractor.UpstreamExtractor
import eu.kanade.tachiyomi.lib.uqloadextractor.UqloadExtractor import eu.kanade.tachiyomi.lib.uqloadextractor.UqloadExtractor
import eu.kanade.tachiyomi.lib.voeextractor.VoeExtractor import eu.kanade.tachiyomi.lib.voeextractor.VoeExtractor
import eu.kanade.tachiyomi.lib.vudeoextractor.VudeoExtractor
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 kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonObject import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.jsonArray import kotlinx.serialization.json.jsonArray
@ -120,7 +120,7 @@ class Pelisplusto(override val name: String, override val baseUrl: String) : Pel
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
return when { return when {
query.isNotBlank() -> GET("$baseUrl/api/search?search=$query", headers) query.isNotBlank() -> GET("$baseUrl/api/search/$query", headers)
genreFilter.state != 0 -> GET("$baseUrl/${genreFilter.toUriPart()}?page=$page") genreFilter.state != 0 -> GET("$baseUrl/${genreFilter.toUriPart()}?page=$page")
else -> popularAnimeRequest(page) else -> popularAnimeRequest(page)
} }
@ -134,30 +134,24 @@ class Pelisplusto(override val name: String, override val baseUrl: String) : Pel
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 regIsUrl = "https?:\\/\\/(www\\.)?[-a-zA-Z0-9@:%._\\+~#=]{1,256}\\.[a-zA-Z0-9()]{1,6}\\b([-a-zA-Z0-9()@:%_\\+.~#?&//=]*)".toRegex()
document.select(".bg-tabs ul li").map { it -> return document.select(".bg-tabs ul li").parallelCatchingFlatMapBlocking {
val url = String(Base64.decode(it.attr("data-server"), Base64.DEFAULT)) val decode = String(Base64.decode(it.attr("data-server"), Base64.DEFAULT))
if (url.contains("/player/")) {
try {
val script = client.newCall(GET(url)).execute().asJsoup().selectFirst("script:containsData(window.onload)")!!.data()
fetchUrls(script).map {
val link = it.replace("https://sblanh.com", "https://lvturbo.com")
.replace(Regex("([a-zA-Z0-9]{0,8}[a-zA-Z0-9_-]+)=https:\\/\\/ww3.pelisplus.to.*"), "")
serverVideoResolver(link).let { videos ->
videoList.addAll(videos)
}
}
} catch (_: Exception) {}
} else {
val link = url.replace("https://sblanh.com", "https://lvturbo.com")
.replace(Regex("([a-zA-Z0-9]{0,8}[a-zA-Z0-9_-]+)=https:\\/\\/ww3.pelisplus.to.*"), "")
serverVideoResolver(link).let { videos -> val url = if (!regIsUrl.containsMatchIn(decode)) {
videoList.addAll(videos) "$baseUrl/player/${String(Base64.encode(it.attr("data-server").toByteArray(), Base64.DEFAULT))}"
} } else { decode }
}
val videoUrl = if (url.contains("/player/")) {
val script = client.newCall(GET(url)).execute().asJsoup().selectFirst("script:containsData(window.onload)")?.data() ?: ""
fetchUrls(script).firstOrNull() ?: ""
} else {
url
}.replace("https://sblanh.com", "https://lvturbo.com")
.replace(Regex("([a-zA-Z0-9]{0,8}[a-zA-Z0-9_-]+)=https:\\/\\/ww3.pelisplus.to.*"), "")
serverVideoResolver(videoUrl)
} }
return videoList
} }
override fun List<Video>.sort(): List<Video> { override fun List<Video>.sort(): List<Video> {
@ -173,105 +167,58 @@ class Pelisplusto(override val name: String, override val baseUrl: String) : Pel
} }
private fun serverVideoResolver(url: String): List<Video> { private fun serverVideoResolver(url: String): List<Video> {
val videoList = mutableListOf<Video>()
val embedUrl = url.lowercase() val embedUrl = url.lowercase()
try { return runCatching {
if (embedUrl.contains("voe")) { when {
VoeExtractor(client).videosFromUrl(url).also(videoList::addAll) embedUrl.contains("voe") -> VoeExtractor(client).videosFromUrl(url)
} embedUrl.contains("ok.ru") || embedUrl.contains("okru") -> OkruExtractor(client).videosFromUrl(url)
if ((embedUrl.contains("amazon") || embedUrl.contains("amz")) && !embedUrl.contains("disable")) { embedUrl.contains("filemoon") || embedUrl.contains("moonplayer") -> {
val body = client.newCall(GET(url)).execute().asJsoup() val vidHeaders = headers.newBuilder()
if (body.select("script:containsData(var shareId)").toString().isNotBlank()) { .add("Origin", "https://${url.toHttpUrl().host}")
val shareId = body.selectFirst("script:containsData(var shareId)")!!.data() .add("Referer", "https://${url.toHttpUrl().host}/")
.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))
}
}
if (embedUrl.contains("ok.ru") || embedUrl.contains("okru")) {
OkruExtractor(client).videosFromUrl(url).also(videoList::addAll)
}
if (embedUrl.contains("filemoon") || embedUrl.contains("moonplayer")) {
val vidHeaders = headers.newBuilder()
.add("Origin", "https://${url.toHttpUrl().host}")
.add("Referer", "https://${url.toHttpUrl().host}/")
.build()
FilemoonExtractor(client).videosFromUrl(url, prefix = "Filemoon:", headers = vidHeaders).also(videoList::addAll)
}
if (embedUrl.contains("uqload")) {
UqloadExtractor(client).videosFromUrl(url).also(videoList::addAll)
}
if (embedUrl.contains("mp4upload")) {
Mp4uploadExtractor(client).videosFromUrl(url, headers).let { videoList.addAll(it) }
}
if (embedUrl.contains("wishembed") || embedUrl.contains("streamwish") || embedUrl.contains("strwish") || embedUrl.contains("wish")) {
val docHeaders = headers.newBuilder()
.add("Origin", "https://streamwish.to")
.add("Referer", "https://streamwish.to/")
.build()
StreamWishExtractor(client, docHeaders).videosFromUrl(url, videoNameGen = { "StreamWish:$it" }).also(videoList::addAll)
}
if (embedUrl.contains("doodstream") || embedUrl.contains("dood.")) {
val url2 = url.replace("https://doodstream.com/e/", "https://dood.to/e/")
DoodExtractor(client).videoFromUrl(url2, "DoodStream", false)?.let { videoList.add(it) }
}
if (embedUrl.contains("streamlare")) {
StreamlareExtractor(client).videosFromUrl(url).let { videoList.addAll(it) }
}
if (embedUrl.contains("yourupload") || embedUrl.contains("upload")) {
YourUploadExtractor(client).videoFromUrl(url, headers = headers).let { videoList.addAll(it) }
}
if (embedUrl.contains("burstcloud") || embedUrl.contains("burst")) {
BurstCloudExtractor(client).videoFromUrl(url, headers = headers).let { videoList.addAll(it) }
}
if (embedUrl.contains("fastream")) {
FastreamExtractor(client, headers).videosFromUrl(url).also(videoList::addAll)
}
if (embedUrl.contains("upstream")) {
UpstreamExtractor(client).videosFromUrl(url).let { videoList.addAll(it) }
}
if (embedUrl.contains("streamtape") || embedUrl.contains("stp") || embedUrl.contains("stape")) {
StreamTapeExtractor(client).videoFromUrl(url)?.let { videoList.add(it) }
}
if (embedUrl.contains("ahvsh") || embedUrl.contains("streamhide")) {
StreamHideExtractor(client).videosFromUrl(url, "StreamHide").let { videoList.addAll(it) }
}
if (embedUrl.contains("vudeo") || embedUrl.contains("vudea")) {
VudeoExtractor(client).videosFromUrl(url).let { videoList.addAll(it) }
}
if (embedUrl.contains("tomatomatela")) {
runCatching {
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() .build()
val token = url.substringAfter("/embed.html#") FilemoonExtractor(client).videosFromUrl(url, prefix = "Filemoon:", headers = vidHeaders)
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, "Tomatomatela", file, headers = null)) }
} }
!embedUrl.contains("disable") && (embedUrl.contains("amazon") || embedUrl.contains("amz")) -> {
val body = client.newCall(GET(url)).execute().asJsoup()
return 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("\"")
listOf(Video(videoUrl, "Amazon", videoUrl))
} else {
emptyList()
}
}
embedUrl.contains("uqload") -> UqloadExtractor(client).videosFromUrl(url)
embedUrl.contains("mp4upload") -> Mp4uploadExtractor(client).videosFromUrl(url, headers)
embedUrl.contains("wishembed") || embedUrl.contains("streamwish") || embedUrl.contains("strwish") || embedUrl.contains("wish") -> {
val docHeaders = headers.newBuilder()
.add("Origin", "https://streamwish.to")
.add("Referer", "https://streamwish.to/")
.build()
StreamWishExtractor(client, docHeaders).videosFromUrl(url, videoNameGen = { "StreamWish:$it" })
}
embedUrl.contains("doodstream") || embedUrl.contains("dood.") || embedUrl.contains("ds2play") || embedUrl.contains("doods.") -> {
val url2 = url.replace("https://doodstream.com/e/", "https://dood.to/e/")
listOf(DoodExtractor(client).videoFromUrl(url2, "DoodStream", false)!!)
}
embedUrl.contains("streamlare") -> StreamlareExtractor(client).videosFromUrl(url)
embedUrl.contains("yourupload") || embedUrl.contains("upload") -> YourUploadExtractor(client).videoFromUrl(url, headers = headers)
embedUrl.contains("burstcloud") || embedUrl.contains("burst") -> BurstCloudExtractor(client).videoFromUrl(url, headers = headers)
embedUrl.contains("fastream") -> FastreamExtractor(client, headers).videosFromUrl(url, prefix = "Fastream:")
embedUrl.contains("upstream") -> UpstreamExtractor(client).videosFromUrl(url)
embedUrl.contains("streamtape") || embedUrl.contains("stp") || embedUrl.contains("stape") -> listOf(StreamTapeExtractor(client).videoFromUrl(url, quality = "StreamTape")!!)
embedUrl.contains("ahvsh") || embedUrl.contains("streamhide") || embedUrl.contains("guccihide") || embedUrl.contains("streamvid") -> StreamHideExtractor(client).videosFromUrl(url, "StreamHide")
else -> emptyList()
} }
} catch (_: Exception) { } }.getOrNull() ?: emptyList()
return videoList
} }
override fun getFilterList(): AnimeFilterList = AnimeFilterList( override fun getFilterList(): AnimeFilterList = AnimeFilterList(