mirror of
https://github.com/hexated/cloudstream-extensions-hexated.git
synced 2024-08-15 00:03:22 +00:00
sora: fix several sources
This commit is contained in:
parent
8d20beab6b
commit
9df7df0cd7
5 changed files with 92 additions and 56 deletions
|
@ -1,5 +1,5 @@
|
||||||
// use an integer for version numbers
|
// use an integer for version numbers
|
||||||
version = 120
|
version = 121
|
||||||
|
|
||||||
|
|
||||||
cloudstream {
|
cloudstream {
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -18,5 +18,6 @@ class SoraStreamPlugin: Plugin() {
|
||||||
registerExtractorAPI(Sbnet())
|
registerExtractorAPI(Sbnet())
|
||||||
registerExtractorAPI(Chillx())
|
registerExtractorAPI(Chillx())
|
||||||
registerExtractorAPI(Watchx())
|
registerExtractorAPI(Watchx())
|
||||||
|
registerExtractorAPI(StreamhideCom())
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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()
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue