From 9df7df0cd71fc85217f1333de22b0a00e7848ee9 Mon Sep 17 00:00:00 2001 From: hexated Date: Wed, 19 Apr 2023 16:52:31 +0700 Subject: [PATCH] sora: fix several sources --- SoraStream/build.gradle.kts | 2 +- .../src/main/kotlin/com/hexated/Extractors.kt | 5 ++ .../main/kotlin/com/hexated/SoraExtractor.kt | 76 +++++++++++-------- .../kotlin/com/hexated/SoraStreamPlugin.kt | 1 + .../src/main/kotlin/com/hexated/SoraUtils.kt | 64 ++++++++++------ 5 files changed, 92 insertions(+), 56 deletions(-) diff --git a/SoraStream/build.gradle.kts b/SoraStream/build.gradle.kts index 79e94c36..6b150733 100644 --- a/SoraStream/build.gradle.kts +++ b/SoraStream/build.gradle.kts @@ -1,5 +1,5 @@ // use an integer for version numbers -version = 120 +version = 121 cloudstream { diff --git a/SoraStream/src/main/kotlin/com/hexated/Extractors.kt b/SoraStream/src/main/kotlin/com/hexated/Extractors.kt index 6ad3a2fa..746aed00 100644 --- a/SoraStream/src/main/kotlin/com/hexated/Extractors.kt +++ b/SoraStream/src/main/kotlin/com/hexated/Extractors.kt @@ -40,6 +40,11 @@ class FileMoonIn : Filesim() { override val name = "FileMoon" } +class StreamhideCom : Filesim() { + override var name: String = "Streamhide" + override var mainUrl: String = "https://streamhide.com" +} + class Watchx : Chillx() { override val name = "Watchx" override val mainUrl = "https://watchx.top" diff --git a/SoraStream/src/main/kotlin/com/hexated/SoraExtractor.kt b/SoraStream/src/main/kotlin/com/hexated/SoraExtractor.kt index 865585b4..f2139a81 100644 --- a/SoraStream/src/main/kotlin/com/hexated/SoraExtractor.kt +++ b/SoraStream/src/main/kotlin/com/hexated/SoraExtractor.kt @@ -827,8 +827,9 @@ object SoraExtractor : SoraStream() { subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit ) { + val query = title?.replace(Regex("[^\\w-\\s]"), "") 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()?.html val mediaId = Jsoup.parse(html ?: return).select("a.item").map { @@ -2935,40 +2936,49 @@ object SoraExtractor : SoraStream() { val res = app.get(url) - if (season == null) { - res.document.select("table.rwd-table tr").map { el -> - val name = el.select("td[data-th=File Name]").text() - val quality = getIndexQuality(name) - val tags = getIndexQualityTags(name) - val size = el.select("td[data-th=Size]").text() - 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, - ) + val media = if(season == null) { + res.document.select("table.rwd-table tr").map { + Triple( + it.select("td[data-th=File Name]").text(), + it.select("td[data-th=Size]").text(), + it.select("div.play_with_vlc_button > a").lastOrNull()?.attr("href") ) } - } else { - tryParseJson>(res.text)?.map { source -> - val quality = getIndexQuality(source.name) - val tags = getIndexQualityTags(source.name) - callback.invoke( - ExtractorLink( - "Shivamhw", - "Shivamhw $tags [${source.size}]", - source.stream_link?.encodeUrl() ?: return@map, - "", - quality, - ) + tryParseJson>(res.text)?.map { + Triple( + it.name, + it.size, + it.stream_link, ) } } + + 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( @@ -2978,8 +2988,8 @@ object SoraExtractor : SoraStream() { app.get("$cryMoviesAPI/stream/movie/$imdbId.json") .parsedSafe()?.streams?.map { stream -> val quality = getIndexQuality(stream.title) - val tags = getIndexQualityTags(stream.title) - val size = stream.title?.substringAfter("\uD83D\uDCBE")?.trim() + val tags = getIndexQualityTags(stream.title, true) + val size = getIndexSize(stream.title) val headers = stream.behaviorHints?.proxyHeaders?.request ?: mapOf() callback.invoke( @@ -3484,8 +3494,8 @@ data class AllanimeResponses( data class ShivamhwSources( @JsonProperty("id") val id: String? = null, @JsonProperty("stream_link") val stream_link: String? = null, - @JsonProperty("name") val name: String? = null, - @JsonProperty("size") val size: String? = null, + @JsonProperty("name") val name: String, + @JsonProperty("size") val size: String, ) data class CryMoviesProxyHeaders( diff --git a/SoraStream/src/main/kotlin/com/hexated/SoraStreamPlugin.kt b/SoraStream/src/main/kotlin/com/hexated/SoraStreamPlugin.kt index fd843743..0070c27f 100644 --- a/SoraStream/src/main/kotlin/com/hexated/SoraStreamPlugin.kt +++ b/SoraStream/src/main/kotlin/com/hexated/SoraStreamPlugin.kt @@ -18,5 +18,6 @@ class SoraStreamPlugin: Plugin() { registerExtractorAPI(Sbnet()) registerExtractorAPI(Chillx()) registerExtractorAPI(Watchx()) + registerExtractorAPI(StreamhideCom()) } } \ No newline at end of file diff --git a/SoraStream/src/main/kotlin/com/hexated/SoraUtils.kt b/SoraStream/src/main/kotlin/com/hexated/SoraUtils.kt index 650519f9..c68fb6e2 100644 --- a/SoraStream/src/main/kotlin/com/hexated/SoraUtils.kt +++ b/SoraStream/src/main/kotlin/com/hexated/SoraUtils.kt @@ -40,7 +40,8 @@ import javax.crypto.spec.SecretKeySpec import kotlin.collections.ArrayList 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 soraHeaders = mapOf( @@ -402,7 +403,8 @@ suspend fun invokeSmashyOne( url: String, 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 = Regex("file:\\s['\"](\\S+?)['|\"]").find(script)?.groupValues?.get( @@ -444,7 +446,7 @@ suspend fun invokeSmashyTwo( ).parsedSafe() ?: return val videoUrl = base64Decode(source.file ?: return) - if(videoUrl.contains("/bug")) return + if (videoUrl.contains("/bug")) return val quality = Regex("(\\d{3,4})[Pp]").find(videoUrl)?.groupValues?.getOrNull(1)?.toIntOrNull() ?: Qualities.P720.value @@ -473,15 +475,16 @@ suspend fun invokeSmashyThree( tryParseJson>(source)?.filter { it.title == "English" }?.map { M3u8Helper.generateM3u8( "Smashy [Player 2]", - it.file ?: return@map , + it.file ?: return@map, "" ).forEach(callback) } } -suspend fun getSoraIdAndType(title: String?, year: Int?, season: Int?) : Pair? { - val doc = app.get("${base64DecodeAPI("b20=LmM=b2s=a2w=bG8=Ly8=czo=dHA=aHQ=")}/search?keyword=$title").document +suspend fun getSoraIdAndType(title: String?, year: Int?, season: Int?): Pair? { + 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 { Triple( it.selectFirst("h2.title")?.text().toString(), @@ -523,7 +526,7 @@ suspend fun getSoraIdAndType(title: String?, year: Int?, season: Int?) : Pair { .substringBefore(";").let { "$cat=$it" } - } else { "" } + } else { + "" + } val postC = if (page.contains("$post=")) { page.substringAfterLast("$post=") .substringBefore(";").let { "$post=$it" } - } else { "" } + } else { + "" + } return Triple(longC, catC, postC) } @@ -805,7 +814,7 @@ suspend fun searchWatchOnline( } 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()?.results return (if (res?.size == 1) { res.firstOrNull() @@ -825,8 +834,10 @@ fun CrunchyrollDetails.findCrunchyrollId( episode: Int?, epsTitle: String? ): List?> { - val sub = this.episodes?.filterKeys { it.contains("subbed") }.matchingEpisode(epsTitle, season, episode) to "Raw" - val dub = this.episodes?.filterKeys { it.contains("English Dub") }.matchingEpisode(epsTitle, season, episode) to "English Dub" + val sub = this.episodes?.filterKeys { it.contains("subbed") } + .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) } @@ -894,7 +905,7 @@ suspend fun PutlockerResponses?.callback( fun getPutlockerQuality(quality: String): Int { return when { 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 } } @@ -1045,17 +1056,21 @@ fun getKisskhTitle(str: String?): String? { return str?.replace(Regex("[^a-zA-Z\\d]"), "-") } -fun String.getFileSize() : Float? { - val size = Regex("(\\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 +fun String.getFileSize(): Float? { + 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 return when { size.contains("GB") -> num * 1000000 else -> num * 1000 } } -fun getIndexQualityTags(str: String?): String { - return Regex("(?i)\\d{3,4}[pP]\\.?(.*?)\\.(mkv|mp4|avi)").find(str ?: "")?.groupValues?.getOrNull(1) +fun getIndexQualityTags(str: String?, fullTag: Boolean = false): String { + 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 ?: "" } @@ -1064,6 +1079,10 @@ fun getIndexQuality(str: String?): Int { ?: 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 { return when (str) { "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()