[Sora] fixed missing anime in zoro and crunchy

This commit is contained in:
hexated 2022-12-22 04:49:12 +07:00
parent 95b2dbfe9a
commit b6ffffa34b
4 changed files with 119 additions and 185 deletions

View file

@ -1,5 +1,5 @@
// use an integer for version numbers // use an integer for version numbers
version = 60 version = 61
cloudstream { cloudstream {

View file

@ -80,8 +80,7 @@ object SoraExtractor : SoraStream() {
document.select(".dropdown-menu a[data-id]").map { it.attr("data-id") }.apmap { serverID -> document.select(".dropdown-menu a[data-id]").map { it.attr("data-id") }.apmap { serverID ->
val token = APIHolder.getCaptchaToken(url, captchaKey) val token = APIHolder.getCaptchaToken(url, captchaKey)
app.get( app.get(
"$twoEmbedAPI/ajax/embed/play?id=$serverID&_token=$token", "$twoEmbedAPI/ajax/embed/play?id=$serverID&_token=$token", referer = url
referer = url
).parsedSafe<EmbedJson>()?.let { source -> ).parsedSafe<EmbedJson>()?.let { source ->
val link = source.link ?: return@let val link = source.link ?: return@let
if (link.contains("rabbitstream")) { if (link.contains("rabbitstream")) {
@ -92,17 +91,13 @@ object SoraExtractor : SoraStream() {
).parsedSafe<RabbitSources>()?.tracks?.map { sub -> ).parsedSafe<RabbitSources>()?.tracks?.map { sub ->
subtitleCallback.invoke( subtitleCallback.invoke(
SubtitleFile( SubtitleFile(
sub.label.toString(), sub.label.toString(), sub.file ?: return@map null
sub.file ?: return@map null
) )
) )
} }
} else { } else {
loadExtractor( loadExtractor(
link, link, twoEmbedAPI, subtitleCallback, callback
twoEmbedAPI,
subtitleCallback,
callback
) )
} }
} }
@ -144,8 +139,7 @@ object SoraExtractor : SoraStream() {
episode: Int? = null, episode: Int? = null,
callback: (ExtractorLink) -> Unit callback: (ExtractorLink) -> Unit
) { ) {
val url = val url = "$olgplyAPI/${id}${season?.let { "/$it" } ?: ""}${episode?.let { "/$it" } ?: ""}"
"$olgplyAPI/${id}${season?.let { "/$it" } ?: ""}${episode?.let { "/$it" } ?: ""}"
loadLinksWithWebView(url, callback) loadLinksWithWebView(url, callback)
} }
@ -167,13 +161,11 @@ object SoraExtractor : SoraStream() {
val doc = app.get("$dbgoAPI/tv-imdb.php?id=$id&s=$season").document val doc = app.get("$dbgoAPI/tv-imdb.php?id=$id&s=$season").document
iframeDbgo = doc.select("div.myvideo iframe").attr("src") iframeDbgo = doc.select("div.myvideo iframe").attr("src")
val token = app.get( val token = app.get(
iframeDbgo, iframeDbgo, referer = "$dbgoAPI/"
referer = "$dbgoAPI/"
).document.selectFirst("select#translator-name option")?.attr("data-token") ).document.selectFirst("select#translator-name option")?.attr("data-token")
app.get("https://voidboost.net/serial/$token/iframe?s=$season&e=$episode&h=dbgo.fun").document.select( app.get("https://voidboost.net/serial/$token/iframe?s=$season&e=$episode&h=dbgo.fun").document.select(
"script" "script"
) ).find { it.data().contains("CDNplayerConfig =") }?.data()
.find { it.data().contains("CDNplayerConfig =") }?.data()
} }
val source = val source =
@ -189,34 +181,30 @@ object SoraExtractor : SoraStream() {
decryptStreamUrl(source).split(",").map { links -> decryptStreamUrl(source).split(",").map { links ->
val quality = val quality =
Regex("\\[([0-9]*p.*?)]").find(links)?.groupValues?.getOrNull(1).toString().trim() Regex("\\[([0-9]*p.*?)]").find(links)?.groupValues?.getOrNull(1).toString().trim()
links.replace("[$quality]", "").split(" or ").map { it.trim() } links.replace("[$quality]", "").split(" or ").map { it.trim() }.map { link ->
.map { link -> val name = if (link.contains(".m3u8")) "Dbgo (Main)" else "Dbgo (Backup)"
val name = if (link.contains(".m3u8")) "Dbgo (Main)" else "Dbgo (Backup)" callback.invoke(
callback.invoke( ExtractorLink(
ExtractorLink( name,
name, name,
name, link,
link, "$ref/",
"$ref/", getQuality(quality),
getQuality(quality), isM3u8 = link.contains(".m3u8"),
isM3u8 = link.contains(".m3u8"), headers = mapOf(
headers = mapOf( "Origin" to ref
"Origin" to ref
)
) )
) )
} )
}
} }
subtitle?.split(",")?.map { sub -> subtitle?.split(",")?.map { sub ->
val language = val language = Regex("\\[(.*)]").find(sub)?.groupValues?.getOrNull(1).toString()
Regex("\\[(.*)]").find(sub)?.groupValues?.getOrNull(1)
.toString()
val link = sub.replace("[$language]", "").trim() val link = sub.replace("[$language]", "").trim()
subtitleCallback.invoke( subtitleCallback.invoke(
SubtitleFile( SubtitleFile(
language, language, link
link
) )
) )
} }
@ -250,10 +238,7 @@ object SoraExtractor : SoraStream() {
} }
}.apmap { link -> }.apmap { link ->
loadExtractor( loadExtractor(
link, link, "https://123moviesjr.cc/", subtitleCallback, callback
"https://123moviesjr.cc/",
subtitleCallback,
callback
) )
} }
} }
@ -282,10 +267,7 @@ object SoraExtractor : SoraStream() {
headers = mapOf("X-Requested-With" to "XMLHttpRequest") headers = mapOf("X-Requested-With" to "XMLHttpRequest")
).parsedSafe<MovieHabRes>()?.data?.let { res -> ).parsedSafe<MovieHabRes>()?.data?.let { res ->
loadExtractor( loadExtractor(
res.link ?: return@let null, res.link ?: return@let null, movieHabAPI, subtitleCallback, callback
movieHabAPI,
subtitleCallback,
callback
) )
} }
} }
@ -387,8 +369,7 @@ object SoraExtractor : SoraStream() {
?.attr("src") ?.attr("src")
val script = app.get( val script = app.get(
iframe ?: return, iframe ?: return, referer = "$hdMovieBoxAPI/"
referer = "$hdMovieBoxAPI/"
).document.selectFirst("script:containsData(var vhash =)")?.data() ).document.selectFirst("script:containsData(var vhash =)")?.data()
?.substringAfter("vhash, {")?.substringBefore("}, false") ?.substringAfter("vhash, {")?.substringBefore("}, false")
@ -399,8 +380,7 @@ object SoraExtractor : SoraStream() {
base64Encode(source.videoDisk.toString().toByteArray()) base64Encode(source.videoDisk.toString().toByteArray())
} }
val link = getBaseUrl(iframe) + source?.videoUrl?.replace( val link = getBaseUrl(iframe) + source?.videoUrl?.replace(
"\\", "\\", ""
""
) + "?s=${source?.videoServer}&d=$disk" ) + "?s=${source?.videoServer}&d=$disk"
callback.invoke( callback.invoke(
ExtractorLink( ExtractorLink(
@ -485,15 +465,9 @@ object SoraExtractor : SoraStream() {
it.attr("data-nume") it.attr("data-nume")
}.apmap { nume -> }.apmap { nume ->
val source = app.post( val source = app.post(
url = "$referer/wp-admin/admin-ajax.php", url = "$referer/wp-admin/admin-ajax.php", data = mapOf(
data = mapOf( "action" to "doo_player_ajax", "post" to id, "nume" to nume, "type" to type
"action" to "doo_player_ajax", ), headers = mapOf("X-Requested-With" to "XMLHttpRequest"), referer = url
"post" to id,
"nume" to nume,
"type" to type
),
headers = mapOf("X-Requested-With" to "XMLHttpRequest"),
referer = url
).parsed<ResponseHash>().embed_url ).parsed<ResponseHash>().embed_url
if (!source.contains("youtube")) { if (!source.contains("youtube")) {
@ -525,15 +499,9 @@ object SoraExtractor : SoraStream() {
val id = el.attr("data-post") val id = el.attr("data-post")
val nume = el.attr("data-nume") val nume = el.attr("data-nume")
val source = app.post( val source = app.post(
url = "$uniqueStreamAPI/wp-admin/admin-ajax.php", url = "$uniqueStreamAPI/wp-admin/admin-ajax.php", data = mapOf(
data = mapOf( "action" to "doo_player_ajax", "post" to id, "nume" to nume, "type" to type
"action" to "doo_player_ajax", ), headers = mapOf("X-Requested-With" to "XMLHttpRequest"), referer = url
"post" to id,
"nume" to nume,
"type" to type
),
headers = mapOf("X-Requested-With" to "XMLHttpRequest"),
referer = url
).parsed<ResponseHash>().embed_url.let { fixUrl(it) } ).parsed<ResponseHash>().embed_url.let { fixUrl(it) }
when { when {
@ -569,10 +537,7 @@ object SoraExtractor : SoraStream() {
) )
} }
!source.contains("youtube") -> loadExtractor( !source.contains("youtube") -> loadExtractor(
source, source, "$uniqueStreamAPI/", subtitleCallback, callback
"$uniqueStreamAPI/",
subtitleCallback,
callback
) )
else -> { else -> {
// pass // pass
@ -602,8 +567,7 @@ object SoraExtractor : SoraStream() {
} }
} else { } else {
doc.select("table.table-striped tbody tr") doc.select("table.table-striped tbody tr")
.find { it.text().contains("Episode $episode") } .find { it.text().contains("Episode $episode") }?.select("td")?.map {
?.select("td")?.map {
it.select("a").attr("href") to it.select("a").text() it.select("a").attr("href") to it.select("a").text()
} }
} ?: return } ?: return
@ -771,9 +735,7 @@ object SoraExtractor : SoraStream() {
callback: (ExtractorLink) -> Unit callback: (ExtractorLink) -> Unit
) { ) {
val headers = mapOf( val headers = mapOf(
"lang" to "en", "lang" to "en", "versioncode" to "11", "clienttype" to "ios_jike_default"
"versioncode" to "11",
"clienttype" to "ios_jike_default"
) )
val vipAPI = val vipAPI =
base64DecodeAPI("cA==YXA=cy8=Y20=di8=LnQ=b2s=a2w=bG8=aS4=YXA=ZS0=aWw=b2I=LW0=Z2E=Ly8=czo=dHA=aHQ=") base64DecodeAPI("cA==YXA=cy8=Y20=di8=LnQ=b2s=a2w=bG8=aS4=YXA=ZS0=aWw=b2I=LW0=Z2E=Ly8=czo=dHA=aHQ=")
@ -786,8 +748,7 @@ object SoraExtractor : SoraStream() {
val scriptData = doc.select("div.search-list div.search-video-card").map { val scriptData = doc.select("div.search-list div.search-video-card").map {
Triple( Triple(
it.selectFirst("h2.title")?.text().toString(), it.selectFirst("h2.title")?.text().toString(),
it.selectFirst("div.desc")?.text() it.selectFirst("div.desc")?.text()?.substringBefore(".")?.toIntOrNull(),
?.substringBefore(".")?.toIntOrNull(),
it.selectFirst("a")?.attr("href")?.split("/") it.selectFirst("a")?.attr("href")?.split("/")
) )
} }
@ -799,20 +760,17 @@ object SoraExtractor : SoraStream() {
when (season) { when (season) {
null -> { null -> {
it.first.equals( it.first.equals(
title, title, true
true
) && it.second == year ) && it.second == year
} }
1 -> { 1 -> {
it.first.contains( it.first.contains(
"$title", "$title", true
true
) && (it.second == year || it.first.contains("Season $season", true)) ) && (it.second == year || it.first.contains("Season $season", true))
} }
else -> { else -> {
it.first.contains( it.first.contains(
"$title", "$title", true
true
) && it.second == year && it.first.contains("Season $season", true) ) && it.second == year && it.first.contains("Season $season", true)
} }
} }
@ -823,8 +781,7 @@ object SoraExtractor : SoraStream() {
val type = script.third?.get(2) ?: return val type = script.third?.get(2) ?: return
val jsonResponse = app.get( val jsonResponse = app.get(
"$vipAPI/movieDrama/get?id=${id}&category=${type}", "$vipAPI/movieDrama/get?id=${id}&category=${type}", headers = headers
headers = headers
) )
if (!jsonResponse.isSuccessful) return if (!jsonResponse.isSuccessful) return
@ -836,8 +793,7 @@ object SoraExtractor : SoraStream() {
json?.subtitlingList?.map { sub -> json?.subtitlingList?.map { sub ->
subtitleCallback.invoke( subtitleCallback.invoke(
SubtitleFile( SubtitleFile(
sub.language ?: "", sub.language ?: "", sub.subtitlingUrl ?: return@map
sub.subtitlingUrl ?: return@map
) )
) )
} }
@ -908,18 +864,16 @@ object SoraExtractor : SoraStream() {
callback: (ExtractorLink) -> Unit callback: (ExtractorLink) -> Unit
) { ) {
val fixTitle = title?.replace("", "-") val fixTitle = title?.replace("", "-")
val id = val id = app.get("$consumetFlixhqAPI/$title")
app.get("$consumetFlixhqAPI/$title") .parsedSafe<ConsumetSearchResponse>()?.results?.find {
.parsedSafe<ConsumetSearchResponse>()?.results?.find { if (season == null) {
if (season == null) { it.title?.equals(
it.title?.equals( "$fixTitle", true
"$fixTitle", ) == true && it.releaseDate?.equals("$year") == true && it.type == "Movie"
true } else {
) == true && it.releaseDate?.equals("$year") == true && it.type == "Movie" it.title?.equals("$fixTitle", true) == true && it.type == "TV Series"
} else { }
it.title?.equals("$fixTitle", true) == true && it.type == "TV Series" }?.id ?: return
}
}?.id ?: return
val episodeId = val episodeId =
app.get("$consumetFlixhqAPI/info?id=$id").parsedSafe<ConsumetDetails>()?.let { app.get("$consumetFlixhqAPI/info?id=$id").parsedSafe<ConsumetDetails>()?.let {
@ -931,16 +885,12 @@ object SoraExtractor : SoraStream() {
} ?: return } ?: return
listOf( listOf(
"vidcloud", "vidcloud", "upcloud"
"upcloud"
).apmap { server -> ).apmap { server ->
delay(1000) val sources = app.get(
val sources = "$consumetFlixhqAPI/watch?episodeId=$episodeId&mediaId=$id&server=$server",
app.get( timeout = 120L
"$consumetFlixhqAPI/watch?episodeId=$episodeId&mediaId=$id&server=$server", ).parsedSafe<ConsumetSourcesResponse>()
timeout = 120L
)
.parsedSafe<ConsumetSourcesResponse>()
val name = fixTitle(server) val name = fixTitle(server)
sources?.sources?.map { sources?.sources?.map {
callback.invoke( callback.invoke(
@ -958,8 +908,7 @@ object SoraExtractor : SoraStream() {
sources?.subtitles?.map { sources?.subtitles?.map {
subtitleCallback.invoke( subtitleCallback.invoke(
SubtitleFile( SubtitleFile(
it.lang ?: "", it.lang ?: "", it.url ?: return@map null
it.url ?: return@map null
) )
) )
} }
@ -978,8 +927,7 @@ object SoraExtractor : SoraStream() {
) { ) {
val fixTitle = title?.replace("", "-") val fixTitle = title?.replace("", "-")
val res = app.get( val res = app.get(
"$kissKhAPI/api/DramaList/Search?q=$title&type=0", "$kissKhAPI/api/DramaList/Search?q=$title&type=0", referer = "$kissKhAPI/"
referer = "$kissKhAPI/"
).text.let { ).text.let {
tryParseJson<ArrayList<KisskhResults>>(it) tryParseJson<ArrayList<KisskhResults>>(it)
} ?: return } ?: return
@ -993,8 +941,7 @@ object SoraExtractor : SoraStream() {
} else { } else {
val data = res.find { val data = res.find {
it.title?.contains( it.title?.contains(
"$fixTitle", "$fixTitle", true
true
) == true && it.title.contains("Season $season", true) ) == true && it.title.contains("Season $season", true)
} }
data?.id to data?.title data?.id to data?.title
@ -1002,8 +949,7 @@ object SoraExtractor : SoraStream() {
} }
val resDetail = app.get( val resDetail = app.get(
"$kissKhAPI/api/DramaList/Drama/$id?isq=false", "$kissKhAPI/api/DramaList/Drama/$id?isq=false", referer = "$kissKhAPI/Drama/${
referer = "$kissKhAPI/Drama/${
getKisskhTitle(contentTitle) getKisskhTitle(contentTitle)
}?id=$id" }?id=$id"
).parsedSafe<KisskhDetail>() ?: return ).parsedSafe<KisskhDetail>() ?: return
@ -1042,8 +988,7 @@ object SoraExtractor : SoraStream() {
tryParseJson<List<KisskhSubtitle>>(resSub)?.map { sub -> tryParseJson<List<KisskhSubtitle>>(resSub)?.map { sub ->
subtitleCallback.invoke( subtitleCallback.invoke(
SubtitleFile( SubtitleFile(
getLanguage(sub.label ?: return@map), getLanguage(sub.label ?: return@map), sub.src ?: return@map
sub.src ?: return@map
) )
) )
} }
@ -1060,27 +1005,17 @@ object SoraExtractor : SoraStream() {
callback: (ExtractorLink) -> Unit callback: (ExtractorLink) -> Unit
) { ) {
val malId = app.get("$tmdb2mal/?id=$id&s=$season").text.trim() val malId = app.get("$tmdb2mal/?id=$id&s=$season").text.trim()
val (engTitle, japTitle) = app.get("https://animixplay.to/assets/mal/$malId.json") val anilistId = app.post(
.parsedSafe<AnimixData>()?.let { "https://graphql.anilist.co/", data = mapOf(
it.title_english to it.title "query" to "{Media(idMal:$malId,type:ANIME){id}}",
} ?: return )
).parsedSafe<DataAni>()?.data?.media?.id
val animeId = val episodeId = app.get("$consumetAnilistAPI/info/$anilistId?provider=zoro")
app.get("$consumetZoroAPI/$japTitle")
.parsedSafe<ConsumetSearchResponse>()?.results?.find {
val title = it.title ?: return
(title.equals(engTitle, true) || title.equals(
japTitle,
true
)) && it.type == "TV"
}?.id ?: return
val episodeId = app.get("$consumetZoroAPI/info?id=$animeId")
.parsedSafe<ConsumetDetails>()?.episodes?.find { .parsedSafe<ConsumetDetails>()?.episodes?.find {
it.number == episode it.number == episode
}?.id ?: return }?.id ?: return
delay(1000)
val sources = app.get("$consumetZoroAPI/watch?episodeId=$episodeId", timeout = 120L) val sources = app.get("$consumetZoroAPI/watch?episodeId=$episodeId", timeout = 120L)
.parsedSafe<ConsumetSourcesResponse>() ?: return .parsedSafe<ConsumetSourcesResponse>() ?: return
@ -1137,8 +1072,7 @@ object SoraExtractor : SoraStream() {
} else { } else {
scriptData.find { scriptData.find {
it.first?.contains( it.first?.contains(
"$fixTitle", "$fixTitle", true
true
) == true && it.second?.contains("$year") == true ) == true && it.second?.contains("$year") == true
} }
} }
@ -1155,12 +1089,7 @@ object SoraExtractor : SoraStream() {
val link = Regex("((https:|http:)//.*\\.mp4)").find(source.text)?.value ?: return val link = Regex("((https:|http:)//.*\\.mp4)").find(source.text)?.value ?: return
callback.invoke( callback.invoke(
ExtractorLink( ExtractorLink(
"Ling", "Ling", "Ling", link, "$lingAPI/", Qualities.Unknown.value, headers = mapOf(
"Ling",
link,
"$lingAPI/",
Qualities.Unknown.value,
headers = mapOf(
"Range" to "bytes=0-" "Range" to "bytes=0-"
) )
) )
@ -1203,8 +1132,7 @@ object SoraExtractor : SoraStream() {
val detailDoc = app.get(script?.first ?: return).document val detailDoc = app.get(script?.first ?: return).document
val iframeList = detailDoc.select("div.entry-content p").map { it } val iframeList = detailDoc.select("div.entry-content p").map { it }
.filter { it.text().filterIframe(season, lastSeason, year) } .filter { it.text().filterIframe(season, lastSeason, year) }.mapNotNull {
.mapNotNull {
if (season == null) { if (season == null) {
it.text() to it.nextElementSibling()?.select("a")?.attr("href") it.text() to it.nextElementSibling()?.select("a")?.attr("href")
} else { } else {
@ -1215,8 +1143,7 @@ object SoraExtractor : SoraStream() {
val iframe = if (iframeList.any { it.first.contains("2160p", true) }) iframeList.filter { val iframe = if (iframeList.any { it.first.contains("2160p", true) }) iframeList.filter {
it.first.contains( it.first.contains(
"2160p", "2160p", true
true
) )
} else iframeList.filter { it.first.contains("1080p", true) } } else iframeList.filter { it.first.contains("1080p", true) }
@ -1270,14 +1197,13 @@ object SoraExtractor : SoraStream() {
) { ) {
val request = app.get("$fwatayakoAPI/IAF0wWTdNYZm?imdb_id=$imdbId") val request = app.get("$fwatayakoAPI/IAF0wWTdNYZm?imdb_id=$imdbId")
if (!request.isSuccessful) return if (!request.isSuccessful) return
val files = request.document.selectFirst("input#files")?.attr("value") val files = request.document.selectFirst("input#files")?.attr("value").let {
.let { if (season == null) {
if (season == null) { it?.replace("\"381\"", "\"movie\"")
it?.replace("\"381\"", "\"movie\"") } else {
} else { it?.replace("\"381\"", "\"tv\"")
it?.replace("\"381\"", "\"tv\"") }
} }.let { tryParseJson<SourcesFwatayako>(it) } ?: return
}.let { tryParseJson<SourcesFwatayako>(it) } ?: return
val sourcesLink = if (season == null) { val sourcesLink = if (season == null) {
files.sourcesMovie files.sourcesMovie
@ -1332,8 +1258,7 @@ object SoraExtractor : SoraStream() {
} }
})?.filter { })?.filter {
it.first.contains("gdtot") && (it.second.contains( it.first.contains("gdtot") && (it.second.contains(
"1080p", "1080p", true
true
) || it.second.contains("4k", true)) ) || it.second.contains("4k", true))
} ?: return } ?: return
@ -1380,8 +1305,7 @@ object SoraExtractor : SoraStream() {
) )
}.filter { }.filter {
(it.quality.contains("1080p", true) || it.quality.contains( (it.quality.contains("1080p", true) || it.quality.contains(
"4k", "4k", true
true
)) && (it.type.contains("gdtot") || it.type.contains("oiya")) )) && (it.type.contains("gdtot") || it.type.contains("oiya"))
} }
Log.i("hexated", "$iframe") Log.i("hexated", "$iframe")
@ -1436,8 +1360,7 @@ object SoraExtractor : SoraStream() {
} else { } else {
scriptData.find { scriptData.find {
it.first?.contains( it.first?.contains(
"Watch Free ${title?.replace(":", "")}", "Watch Free ${title?.replace(":", "")}", true
true
) == true && (it.first?.contains("$year") == true || it.second?.contains( ) == true && (it.first?.contains("$year") == true || it.second?.contains(
"$year" "$year"
) == true) ) == true)
@ -1464,16 +1387,11 @@ object SoraExtractor : SoraStream() {
?: return ?: return
val idepisode = episodeData.select("button").attr("idepisode") ?: return val idepisode = episodeData.select("button").attr("idepisode") ?: return
val requestEmbed = app.post( val requestEmbed = app.post(
"$m4uhdAPI/ajaxtv", "$m4uhdAPI/ajaxtv", data = mapOf(
data = mapOf( "idepisode" to idepisode, "_token" to "$token"
"idepisode" to idepisode, ), referer = link, headers = mapOf(
"_token" to "$token"
),
referer = link,
headers = mapOf(
"X-Requested-With" to "XMLHttpRequest", "X-Requested-With" to "XMLHttpRequest",
), ), cookies = mapOf(
cookies = mapOf(
"laravel_session" to "$session", "laravel_session" to "$session",
"XSRF-TOKEN" to "$xsrf", "XSRF-TOKEN" to "$xsrf",
) )
@ -1491,8 +1409,7 @@ object SoraExtractor : SoraStream() {
val iframe = app.post( val iframe = app.post(
"$m4uhdAPI/ajax", "$m4uhdAPI/ajax",
data = mapOf( data = mapOf(
"m4u" to m4uData, "m4u" to m4uData, "_token" to "$token"
"_token" to "$token"
), ),
referer = link, referer = link,
headers = mapOf( headers = mapOf(
@ -1525,7 +1442,8 @@ object SoraExtractor : SoraStream() {
val server = getTvMoviesServer(url, season, episode) ?: return val server = getTvMoviesServer(url, season, episode) ?: return
val videoData = extractCovyn(server.second ?: return) val videoData = extractCovyn(server.second ?: return)
val quality = Regex("([0-9]{3,4})p").find(server.first)?.groupValues?.getOrNull(1)?.toIntOrNull() val quality =
Regex("([0-9]{3,4})p").find(server.first)?.groupValues?.getOrNull(1)?.toIntOrNull()
callback.invoke( callback.invoke(
ExtractorLink( ExtractorLink(
@ -1543,24 +1461,30 @@ object SoraExtractor : SoraStream() {
suspend fun invokeCrunchyroll( suspend fun invokeCrunchyroll(
title: String? = null, title: String? = null,
epsTitle: String? = null, epsTitle: String? = null,
season: Int? = null,
episode: Int? = null,
subtitleCallback: (SubtitleFile) -> Unit, subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit callback: (ExtractorLink) -> Unit
) { ) {
val id = app.get("$consumetCrunchyrollAPI/$title") val id = app.get("$consumetCrunchyrollAPI/$title")
.parsedSafe<ConsumetSearchResponse>()?.results?.find { .parsedSafe<ConsumetSearchResponse>()?.results?.find {
it.title.equals( it.title.equals(
title, title, true
true
) && it.type.equals("series") ) && it.type.equals("series")
} ?: return } ?: return
val detail = app.get("$consumetCrunchyrollAPI/info?id=${id.id}&mediaType=series").text val detail = app.get("$consumetCrunchyrollAPI/info?id=${id.id}&mediaType=series").text
val episodeId = tryParseJson<ConsumetDetails>(detail)?.episodes?.filter { val episodeId = tryParseJson<ConsumetDetails>(detail)?.episodes?.filter {
it.title.equals(epsTitle, true) && (it.type == "Subbed" || it.type == "English Dub") (if (season == 1) {
it.title.equals(
epsTitle, true
) || it.number == episode
} else {
it.title.equals(epsTitle, true)
}) && (it.type == "Subbed" || it.type == "English Dub")
}?.map { it.id to it.type } ?: return }?.map { it.id to it.type } ?: return
episodeId.apmap { (id, type) -> episodeId.apmap { (id, type) ->
delay(1000)
val json = app.get("$consumetCrunchyrollAPI/watch?episodeId=$id&format=srt") val json = app.get("$consumetCrunchyrollAPI/watch?episodeId=$id&format=srt")
.parsedSafe<ConsumetSourcesResponse>() .parsedSafe<ConsumetSourcesResponse>()
@ -1758,4 +1682,16 @@ data class PreviewResponse(
data class PreviewVideos( data class PreviewVideos(
@JsonProperty("mediaUrl") val mediaUrl: String? = null, @JsonProperty("mediaUrl") val mediaUrl: String? = null,
@JsonProperty("currentDefinition") val currentDefinition: String? = null, @JsonProperty("currentDefinition") val currentDefinition: String? = null,
)
data class IdAni(
@JsonProperty("id") val id: String? = null,
)
data class MediaAni(
@JsonProperty("Media") val media: IdAni? = null,
)
data class DataAni(
@JsonProperty("data") val data: MediaAni? = null,
) )

View file

@ -54,6 +54,7 @@ open class SoraStream : TmdbProvider() {
base64DecodeAPI("ZTM=NTg=MjM=MjM=ODc=MzI=OGQ=MmE=Nzk=Nzk=ZjI=NTA=NDY=NDA=MzA=YjA=") // PLEASE DON'T STEAL base64DecodeAPI("ZTM=NTg=MjM=MjM=ODc=MzI=OGQ=MmE=Nzk=Nzk=ZjI=NTA=NDY=NDA=MzA=YjA=") // PLEASE DON'T STEAL
const val tmdb2mal = "https://tmdb2mal.slidemovies.org" const val tmdb2mal = "https://tmdb2mal.slidemovies.org"
const val gdbot = "https://gdbot.xyz" const val gdbot = "https://gdbot.xyz"
const val consumetAnilistAPI = "https://api.consumet.org/meta/anilist"
private val mainAPI = private val mainAPI =
base64DecodeAPI("cHA=LmE=ZWw=cmM=dmU=aC4=dGM=d2E=eHA=Ly8=czo=dHA=aHQ=") base64DecodeAPI("cHA=LmE=ZWw=cmM=dmU=aC4=dGM=d2E=eHA=Ly8=czo=dHA=aHQ=")
@ -79,7 +80,7 @@ open class SoraStream : TmdbProvider() {
const val consumetCrunchyrollAPI = "https://api.consumet.org/anime/crunchyroll" const val consumetCrunchyrollAPI = "https://api.consumet.org/anime/crunchyroll"
const val kissKhAPI = "https://kisskh.me" const val kissKhAPI = "https://kisskh.me"
const val lingAPI = "https://ling-online.net" const val lingAPI = "https://ling-online.net"
const val uhdmoviesAPI = "https://uhdmovies.site" const val uhdmoviesAPI = "https://uhdmovies.org.in"
const val fwatayakoAPI = "https://5100.svetacdn.in" const val fwatayakoAPI = "https://5100.svetacdn.in"
const val gMoviesAPI = "https://gdrivemovies.xyz" const val gMoviesAPI = "https://gdrivemovies.xyz"
const val fdMoviesAPI = "https://freedrivemovie.com" const val fdMoviesAPI = "https://freedrivemovie.com"
@ -162,18 +163,13 @@ open class SoraStream : TmdbProvider() {
} }
} }
override suspend fun search(query: String): List<SearchResponse> { override suspend fun search(query: String): List<SearchResponse>? {
val searchResponse = mutableListOf<SearchResponse>() return app.get(
val mainResponse = app.get(
"$tmdbAPI/search/multi?api_key=$apiKey&language=en-US&query=$query&page=1&include_adult=${settingsForProvider.enableAdult}", "$tmdbAPI/search/multi?api_key=$apiKey&language=en-US&query=$query&page=1&include_adult=${settingsForProvider.enableAdult}",
referer = "$mainAPI/" referer = "$mainAPI/"
).parsedSafe<Results>()?.results?.mapNotNull { media -> ).parsedSafe<Results>()?.results?.mapNotNull { media ->
media.toSearchResponse() media.toSearchResponse()
} }
if (mainResponse?.isNotEmpty() == true) searchResponse.addAll(mainResponse)
return searchResponse
} }
override suspend fun load(url: String): LoadResponse? { override suspend fun load(url: String): LoadResponse? {
@ -246,7 +242,7 @@ open class SoraStream : TmdbProvider() {
newTvSeriesLoadResponse( newTvSeriesLoadResponse(
title, title,
url, url,
TvType.TvSeries, if(isAnime) TvType.Anime else TvType.TvSeries,
episodes episodes
) { ) {
this.posterUrl = poster this.posterUrl = poster
@ -355,6 +351,8 @@ open class SoraStream : TmdbProvider() {
if (res.season != null && res.isAnime) invokeCrunchyroll( if (res.season != null && res.isAnime) invokeCrunchyroll(
res.title, res.title,
res.epsTitle, res.epsTitle,
res.season,
res.episode,
subtitleCallback, subtitleCallback,
callback callback
) )

View file

@ -174,7 +174,7 @@ suspend fun extractGdflix(url: String): String? {
?.attr("href") ?: return null ?.attr("href") ?: return null
val base = getBaseUrl(iframeGdflix) val base = getBaseUrl(iframeGdflix)
val gdfDoc = app.get(iframeGdflix).document.selectFirst("script")?.data()?.substringAfter("replace(\"") val gdfDoc = app.get(iframeGdflix).document.selectFirst("script:containsData(replace)")?.data()?.substringAfter("replace(\"")
?.substringBefore("\")")?.let { ?.substringBefore("\")")?.let {
app.get(fixUrl(it, base)).document app.get(fixUrl(it, base)).document
} }