sora: fix several sources

This commit is contained in:
hexated 2023-04-19 16:52:31 +07:00
parent 8d20beab6b
commit 9df7df0cd7
5 changed files with 92 additions and 56 deletions

View File

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

View File

@ -40,6 +40,11 @@ class FileMoonIn : Filesim() {
override val name = "FileMoon" override val name = "FileMoon"
} }
class StreamhideCom : Filesim() {
override var name: String = "Streamhide"
override var mainUrl: String = "https://streamhide.com"
}
class Watchx : Chillx() { class Watchx : Chillx() {
override val name = "Watchx" override val name = "Watchx"
override val mainUrl = "https://watchx.top" override val mainUrl = "https://watchx.top"

View File

@ -827,8 +827,9 @@ object SoraExtractor : SoraStream() {
subtitleCallback: (SubtitleFile) -> Unit, subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit callback: (ExtractorLink) -> Unit
) { ) {
val query = title?.replace(Regex("[^\\w-\\s]"), "")
val html = val html =
app.get("https://fmovies.to/ajax/film/search?vrf=${encodeVrf("$title")}&keyword=$title") app.get("https://fmovies.to/ajax/film/search?vrf=${encodeVrf("$query")}&keyword=$query")
.parsedSafe<FmoviesSearch>()?.html .parsedSafe<FmoviesSearch>()?.html
val mediaId = Jsoup.parse(html ?: return).select("a.item").map { val mediaId = Jsoup.parse(html ?: return).select("a.item").map {
@ -2935,40 +2936,49 @@ object SoraExtractor : SoraStream() {
val res = app.get(url) val res = app.get(url)
if (season == null) { val media = if(season == null) {
res.document.select("table.rwd-table tr").map { el -> res.document.select("table.rwd-table tr").map {
val name = el.select("td[data-th=File Name]").text() Triple(
val quality = getIndexQuality(name) it.select("td[data-th=File Name]").text(),
val tags = getIndexQualityTags(name) it.select("td[data-th=Size]").text(),
val size = el.select("td[data-th=Size]").text() it.select("div.play_with_vlc_button > a").lastOrNull()?.attr("href")
val videoUrl = el.select("div.play_with_vlc_button > a").lastOrNull()?.attr("href")
callback.invoke(
ExtractorLink(
"Shivamhw",
"Shivamhw $tags [${size}]",
videoUrl?.removePrefix("vlc://")?.encodeUrl() ?: return@map,
"",
quality,
)
) )
} }
} else { } else {
tryParseJson<ArrayList<ShivamhwSources>>(res.text)?.map { source -> tryParseJson<ArrayList<ShivamhwSources>>(res.text)?.map {
val quality = getIndexQuality(source.name) Triple(
val tags = getIndexQualityTags(source.name) it.name,
callback.invoke( it.size,
ExtractorLink( it.stream_link,
"Shivamhw",
"Shivamhw $tags [${source.size}]",
source.stream_link?.encodeUrl() ?: return@map,
"",
quality,
)
) )
} }
} }
media?.filter {
matchingIndex(
it.first,
null,
title,
year,
season,
episode,
true
)
}?.sortedByDescending {
it.second.getFileSize()
}?.map { source ->
val quality = getIndexQuality(source.first)
val tags = getIndexQualityTags(source.first)
callback.invoke(
ExtractorLink(
"Shivamhw",
"Shivamhw $tags [${source.second}]",
source.third?.removePrefix("vlc://") ?: return@map,
"",
quality,
)
)
}
} }
suspend fun invokeCryMovies( suspend fun invokeCryMovies(
@ -2978,8 +2988,8 @@ object SoraExtractor : SoraStream() {
app.get("$cryMoviesAPI/stream/movie/$imdbId.json") app.get("$cryMoviesAPI/stream/movie/$imdbId.json")
.parsedSafe<CryMoviesResponse>()?.streams?.map { stream -> .parsedSafe<CryMoviesResponse>()?.streams?.map { stream ->
val quality = getIndexQuality(stream.title) val quality = getIndexQuality(stream.title)
val tags = getIndexQualityTags(stream.title) val tags = getIndexQualityTags(stream.title, true)
val size = stream.title?.substringAfter("\uD83D\uDCBE")?.trim() val size = getIndexSize(stream.title)
val headers = stream.behaviorHints?.proxyHeaders?.request ?: mapOf() val headers = stream.behaviorHints?.proxyHeaders?.request ?: mapOf()
callback.invoke( callback.invoke(
@ -3484,8 +3494,8 @@ data class AllanimeResponses(
data class ShivamhwSources( data class ShivamhwSources(
@JsonProperty("id") val id: String? = null, @JsonProperty("id") val id: String? = null,
@JsonProperty("stream_link") val stream_link: String? = null, @JsonProperty("stream_link") val stream_link: String? = null,
@JsonProperty("name") val name: String? = null, @JsonProperty("name") val name: String,
@JsonProperty("size") val size: String? = null, @JsonProperty("size") val size: String,
) )
data class CryMoviesProxyHeaders( data class CryMoviesProxyHeaders(

View File

@ -18,5 +18,6 @@ class SoraStreamPlugin: Plugin() {
registerExtractorAPI(Sbnet()) registerExtractorAPI(Sbnet())
registerExtractorAPI(Chillx()) registerExtractorAPI(Chillx())
registerExtractorAPI(Watchx()) registerExtractorAPI(Watchx())
registerExtractorAPI(StreamhideCom())
} }
} }

View File

@ -40,7 +40,8 @@ import javax.crypto.spec.SecretKeySpec
import kotlin.collections.ArrayList import kotlin.collections.ArrayList
import kotlin.math.min import kotlin.math.min
val soraAPI = base64DecodeAPI("cA==YXA=cy8=Y20=di8=LnQ=b2s=a2w=bG8=aS4=YXA=ZS0=aWw=b2I=LW0=Z2E=Ly8=czo=dHA=aHQ=") val soraAPI =
base64DecodeAPI("cA==YXA=cy8=Y20=di8=LnQ=b2s=a2w=bG8=aS4=YXA=ZS0=aWw=b2I=LW0=Z2E=Ly8=czo=dHA=aHQ=")
val soraBackupAPI = base64DecodeAPI("dHY=bC4=aWw=Y2g=c3Q=anU=MS4=b2s=a2w=bG8=Ly8=czo=dHA=aHQ=") val soraBackupAPI = base64DecodeAPI("dHY=bC4=aWw=Y2g=c3Q=anU=MS4=b2s=a2w=bG8=Ly8=czo=dHA=aHQ=")
val soraHeaders = mapOf( val soraHeaders = mapOf(
@ -402,7 +403,8 @@ suspend fun invokeSmashyOne(
url: String, url: String,
callback: (ExtractorLink) -> Unit, callback: (ExtractorLink) -> Unit,
) { ) {
val script = app.get(url).document.selectFirst("script:containsData(player =)")?.data() ?: return val script =
app.get(url).document.selectFirst("script:containsData(player =)")?.data() ?: return
val source = val source =
Regex("file:\\s['\"](\\S+?)['|\"]").find(script)?.groupValues?.get( Regex("file:\\s['\"](\\S+?)['|\"]").find(script)?.groupValues?.get(
@ -444,7 +446,7 @@ suspend fun invokeSmashyTwo(
).parsedSafe<Smashy1Source>() ?: return ).parsedSafe<Smashy1Source>() ?: return
val videoUrl = base64Decode(source.file ?: return) val videoUrl = base64Decode(source.file ?: return)
if(videoUrl.contains("/bug")) return if (videoUrl.contains("/bug")) return
val quality = val quality =
Regex("(\\d{3,4})[Pp]").find(videoUrl)?.groupValues?.getOrNull(1)?.toIntOrNull() Regex("(\\d{3,4})[Pp]").find(videoUrl)?.groupValues?.getOrNull(1)?.toIntOrNull()
?: Qualities.P720.value ?: Qualities.P720.value
@ -473,15 +475,16 @@ suspend fun invokeSmashyThree(
tryParseJson<ArrayList<DudetvSources>>(source)?.filter { it.title == "English" }?.map { tryParseJson<ArrayList<DudetvSources>>(source)?.filter { it.title == "English" }?.map {
M3u8Helper.generateM3u8( M3u8Helper.generateM3u8(
"Smashy [Player 2]", "Smashy [Player 2]",
it.file ?: return@map , it.file ?: return@map,
"" ""
).forEach(callback) ).forEach(callback)
} }
} }
suspend fun getSoraIdAndType(title: String?, year: Int?, season: Int?) : Pair<String, String>? { suspend fun getSoraIdAndType(title: String?, year: Int?, season: Int?): Pair<String, String>? {
val doc = app.get("${base64DecodeAPI("b20=LmM=b2s=a2w=bG8=Ly8=czo=dHA=aHQ=")}/search?keyword=$title").document val doc =
app.get("${base64DecodeAPI("b20=LmM=b2s=a2w=bG8=Ly8=czo=dHA=aHQ=")}/search?keyword=$title").document
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(),
@ -523,7 +526,7 @@ suspend fun getSoraIdAndType(title: String?, year: Int?, season: Int?) : Pair<St
return id to type return id to type
} }
suspend fun fetchSoraEpisodes(id: String, type: String, episode: Int?) : EpisodeVo? { suspend fun fetchSoraEpisodes(id: String, type: String, episode: Int?): EpisodeVo? {
return app.get( return app.get(
"$soraAPI/movieDrama/get?id=${id}&category=${type}", "$soraAPI/movieDrama/get?id=${id}&category=${type}",
headers = soraHeaders headers = soraHeaders
@ -634,7 +637,7 @@ suspend fun bypassHrefli(url: String): String? {
return fixUrl(path, getBaseUrl(driveUrl)) return fixUrl(path, getBaseUrl(driveUrl))
} }
suspend fun bypassTechmny(url: String) : String? { suspend fun bypassTechmny(url: String): String? {
val postUrl = url.substringBefore("?id=").substringAfter("/?") val postUrl = url.substringBefore("?id=").substringAfter("/?")
var res = app.post( var res = app.post(
postUrl, data = mapOf( postUrl, data = mapOf(
@ -656,14 +659,16 @@ suspend fun bypassTechmny(url: String) : String? {
val newLongC = "$goToken=" + longC2.substringAfter("=") val newLongC = "$goToken=" + longC2.substringAfter("=")
headers = mapOf("Cookie" to "$catC; rdst_post=; $newLongC") headers = mapOf("Cookie" to "$catC; rdst_post=; $newLongC")
val driveUrl = app.get(tokenUrl, headers = headers).document.selectFirst("meta[http-equiv=refresh]")?.attr("content")?.substringAfter("url=") val driveUrl =
app.get(tokenUrl, headers = headers).document.selectFirst("meta[http-equiv=refresh]")
?.attr("content")?.substringAfter("url=")
val path = app.get(driveUrl ?: return null).text.substringAfter("replace(\"") val path = app.get(driveUrl ?: return null).text.substringAfter("replace(\"")
.substringBefore("\")") .substringBefore("\")")
if (path == "/404") return null if (path == "/404") return null
return fixUrl(path, getBaseUrl(driveUrl)) return fixUrl(path, getBaseUrl(driveUrl))
} }
suspend fun bypassDriveleech(url: String) : String? { suspend fun bypassDriveleech(url: String): String? {
val path = app.get(url).text.substringAfter("replace(\"") val path = app.get(url).text.substringAfter("replace(\"")
.substringBefore("\")") .substringBefore("\")")
if (path == "/404") return null if (path == "/404") return null
@ -682,14 +687,18 @@ private fun getTechmnyCookies(page: String): Triple<String, String, String> {
.substringBefore(";").let { .substringBefore(";").let {
"$cat=$it" "$cat=$it"
} }
} else { "" } } else {
""
}
val postC = if (page.contains("$post=")) { val postC = if (page.contains("$post=")) {
page.substringAfterLast("$post=") page.substringAfterLast("$post=")
.substringBefore(";").let { .substringBefore(";").let {
"$post=$it" "$post=$it"
} }
} else { "" } } else {
""
}
return Triple(longC, catC, postC) return Triple(longC, catC, postC)
} }
@ -805,7 +814,7 @@ suspend fun searchWatchOnline(
} }
suspend fun searchCrunchyrollAnimeId(title: String): String? { suspend fun searchCrunchyrollAnimeId(title: String): String? {
val res = app.get("${consumetCrunchyrollAPI}/search/$title",timeout = 600L) val res = app.get("${consumetCrunchyrollAPI}/search/$title", timeout = 600L)
.parsedSafe<ConsumetSearchResponse>()?.results .parsedSafe<ConsumetSearchResponse>()?.results
return (if (res?.size == 1) { return (if (res?.size == 1) {
res.firstOrNull() res.firstOrNull()
@ -825,8 +834,10 @@ fun CrunchyrollDetails.findCrunchyrollId(
episode: Int?, episode: Int?,
epsTitle: String? epsTitle: String?
): List<Pair<CrunchyrollEpisodes?, String?>?> { ): List<Pair<CrunchyrollEpisodes?, String?>?> {
val sub = this.episodes?.filterKeys { it.contains("subbed") }.matchingEpisode(epsTitle, season, episode) to "Raw" val sub = this.episodes?.filterKeys { it.contains("subbed") }
val dub = this.episodes?.filterKeys { it.contains("English Dub") }.matchingEpisode(epsTitle, season, episode) to "English Dub" .matchingEpisode(epsTitle, season, episode) to "Raw"
val dub = this.episodes?.filterKeys { it.contains("English Dub") }
.matchingEpisode(epsTitle, season, episode) to "English Dub"
return listOf(sub, dub) return listOf(sub, dub)
} }
@ -894,7 +905,7 @@ suspend fun PutlockerResponses?.callback(
fun getPutlockerQuality(quality: String): Int { fun getPutlockerQuality(quality: String): Int {
return when { return when {
quality.contains("NAME=\"1080p\"") || quality.contains("RESOLUTION=1920x1080") -> Qualities.P1080.value quality.contains("NAME=\"1080p\"") || quality.contains("RESOLUTION=1920x1080") -> Qualities.P1080.value
quality.contains("NAME=\"720p\"") || quality.contains("RESOLUTION=1280x720")-> Qualities.P720.value quality.contains("NAME=\"720p\"") || quality.contains("RESOLUTION=1280x720") -> Qualities.P720.value
else -> Qualities.P480.value else -> Qualities.P480.value
} }
} }
@ -1045,17 +1056,21 @@ fun getKisskhTitle(str: String?): String? {
return str?.replace(Regex("[^a-zA-Z\\d]"), "-") return str?.replace(Regex("[^a-zA-Z\\d]"), "-")
} }
fun String.getFileSize() : Float? { fun String.getFileSize(): Float? {
val size = Regex("(\\d+\\.?\\d+\\sGB|MB)").find(this)?.groupValues?.get(0)?.trim() val size = Regex("(?i)(\\d+\\.?\\d+\\sGB|MB)").find(this)?.groupValues?.get(0)?.trim()
val num = Regex("(\\d+\\.?\\d+)").find(size ?: return null)?.groupValues?.get(0)?.toFloat() ?: return null val num = Regex("(\\d+\\.?\\d+)").find(size ?: return null)?.groupValues?.get(0)?.toFloat()
?: return null
return when { return when {
size.contains("GB") -> num * 1000000 size.contains("GB") -> num * 1000000
else -> num * 1000 else -> num * 1000
} }
} }
fun getIndexQualityTags(str: String?): String { fun getIndexQualityTags(str: String?, fullTag: Boolean = false): String {
return Regex("(?i)\\d{3,4}[pP]\\.?(.*?)\\.(mkv|mp4|avi)").find(str ?: "")?.groupValues?.getOrNull(1) return if (fullTag) Regex("(?i)(.*)\\.(?:mkv|mp4|avi)").find(str ?: "")?.groupValues?.get(1)
?.trim() ?: str ?: "" else Regex("(?i)\\d{3,4}[pP]\\.?(.*?)\\.(mkv|mp4|avi)").find(
str ?: ""
)?.groupValues?.getOrNull(1)
?.replace(".", " ")?.trim() ?: str ?: "" ?.replace(".", " ")?.trim() ?: str ?: ""
} }
@ -1064,6 +1079,10 @@ fun getIndexQuality(str: String?): Int {
?: Qualities.Unknown.value ?: Qualities.Unknown.value
} }
fun getIndexSize(str: String?): String? {
return Regex("(?i)([\\d.]+\\s*(?:gb|mb))").find(str ?: "")?.groupValues?.getOrNull(1)?.trim()
}
fun getQuality(str: String): Int { fun getQuality(str: String): Int {
return when (str) { return when (str) {
"360p" -> Qualities.P240.value "360p" -> Qualities.P240.value
@ -1424,7 +1443,8 @@ object CryptoAES {
} }
} }
private fun ByteArray.toHex(): String = joinToString(separator = "") { eachByte -> "%02x".format(eachByte) } private fun ByteArray.toHex(): String =
joinToString(separator = "") { eachByte -> "%02x".format(eachByte) }
private fun String.toHex(): String = toByteArray().toHex() private fun String.toHex(): String = toByteArray().toHex()