mirror of
https://github.com/hexated/cloudstream-extensions-hexated.git
synced 2024-08-15 00:03:22 +00:00
sora: fixed sources
This commit is contained in:
parent
43c6c3108b
commit
db046fe123
4 changed files with 122 additions and 39 deletions
|
@ -1,7 +1,7 @@
|
|||
import org.jetbrains.kotlin.konan.properties.Properties
|
||||
|
||||
// use an integer for version numbers
|
||||
version = 123
|
||||
version = 124
|
||||
|
||||
android {
|
||||
defaultConfig {
|
||||
|
|
|
@ -732,8 +732,8 @@ object SoraExtractor : SoraStream() {
|
|||
) {
|
||||
val query = title?.replace(Regex("[^\\w-\\s]"), "")
|
||||
val html =
|
||||
app.get("https://fmovies.to/ajax/film/search?vrf=${encodeVrf("$query")}&keyword=$query")
|
||||
.parsedSafe<FmoviesSearch>()?.html
|
||||
app.get("$fmoviesAPI/ajax/film/search?vrf=${encodeVrf("$query")}&keyword=$query")
|
||||
.parsedSafe<FmoviesResponses>()?.html
|
||||
|
||||
val mediaId = Jsoup.parse(html ?: return).select("a.item").map {
|
||||
Triple(
|
||||
|
@ -748,7 +748,7 @@ object SoraExtractor : SoraStream() {
|
|||
it.first.contains("/series/")
|
||||
} && (it.second.equals(title, true) || it.second.createSlug()
|
||||
.equals(title.createSlug())) && it.third.toInt() == year
|
||||
}?.first ?: return
|
||||
}?.first?.substringAfterLast("-") ?: return
|
||||
|
||||
val episodeId = if (season == null) {
|
||||
"1-full"
|
||||
|
@ -756,32 +756,32 @@ object SoraExtractor : SoraStream() {
|
|||
"$season-$episode"
|
||||
}
|
||||
|
||||
val sources = app.get(
|
||||
"$consumetFmoviesAPI/watch?mediaId=${mediaId.removePrefix("/")}&episodeId=$episodeId"
|
||||
).parsedSafe<ConsumetSourcesResponse>()
|
||||
val serversKname =
|
||||
app.get("$fmoviesAPI/ajax/film/servers?id=$mediaId&vrf=${encodeVrf(mediaId)}")
|
||||
.parsedSafe<FmoviesResponses>()?.html?.let { Jsoup.parse(it) }
|
||||
?.selectFirst("a[data-kname=$episodeId]")?.attr("data-ep")
|
||||
|
||||
sources?.sources?.map {
|
||||
callback.invoke(
|
||||
ExtractorLink(
|
||||
"Vizcloud",
|
||||
"Vizcloud",
|
||||
it.url ?: return@map null,
|
||||
sources.headers?.referer ?: "",
|
||||
getQualityFromName(it.quality),
|
||||
it.isM3U8 ?: true
|
||||
)
|
||||
)
|
||||
val servers = tryParseJson<HashMap<String, String>>(serversKname)
|
||||
|
||||
servers?.apmap { server ->
|
||||
val decryptServer = app.get("$fmoviesAPI/ajax/episode/info?id=${server.value}")
|
||||
.parsedSafe<FmoviesResponses>()?.url?.let { decodeVrf(it) } ?: return@apmap
|
||||
if (server.key == "41") {
|
||||
invokeVizcloud(decryptServer, callback)
|
||||
} else {
|
||||
loadExtractor(decryptServer, fmoviesAPI, subtitleCallback, callback)
|
||||
}
|
||||
}
|
||||
|
||||
sources?.subtitles?.map {
|
||||
val sub = app.get("$fmoviesAPI/ajax/episode/subtitles/${servers?.get("28") ?: return}").text
|
||||
tryParseJson<List<FmoviesSubtitles>>(sub)?.map {
|
||||
subtitleCallback.invoke(
|
||||
SubtitleFile(
|
||||
it.lang ?: "", it.url ?: return@map null
|
||||
it.label ?: "",
|
||||
it.file ?: return@map
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
suspend fun invokeKisskh(
|
||||
|
@ -3403,6 +3403,28 @@ data class DudetvSources(
|
|||
@JsonProperty("title") val title: String? = null,
|
||||
)
|
||||
|
||||
data class FmoviesSearch(
|
||||
data class FmoviesResponses(
|
||||
@JsonProperty("html") val html: String? = null,
|
||||
@JsonProperty("url") val url: String? = null,
|
||||
)
|
||||
|
||||
data class FmoviesSubtitles(
|
||||
@JsonProperty("label") val label: String? = null,
|
||||
@JsonProperty("file") val file: String? = null,
|
||||
)
|
||||
|
||||
data class VizcloudSources(
|
||||
@JsonProperty("file") val file: String? = null,
|
||||
)
|
||||
|
||||
data class VizcloudMedia(
|
||||
@JsonProperty("sources") val sources: ArrayList<VizcloudSources>? = arrayListOf(),
|
||||
)
|
||||
|
||||
data class VizcloudData(
|
||||
@JsonProperty("media") val media: VizcloudMedia? = null,
|
||||
)
|
||||
|
||||
data class VizcloudResponses(
|
||||
@JsonProperty("data") val data: VizcloudData? = null,
|
||||
)
|
|
@ -100,9 +100,7 @@ open class SoraStream : TmdbProvider() {
|
|||
const val filmxyAPI = "https://www.filmxy.vip"
|
||||
const val kimcartoonAPI = "https://kimcartoon.li"
|
||||
const val xMovieAPI = "https://xemovies.to"
|
||||
const val consumetFmoviesAPI = "https://api.consumet.org/movies/fmovies"
|
||||
const val consumetZoroAPI = "https://api.consumet.org/anime/zoro"
|
||||
const val consumetCrunchyrollAPI = "https://cronchy.consumet.stream" // dead
|
||||
const val allanimeAPI = "https://api.allanime.to"
|
||||
const val kissKhAPI = "https://kisskh.co"
|
||||
const val lingAPI = "https://ling-online.net"
|
||||
|
@ -121,21 +119,15 @@ open class SoraStream : TmdbProvider() {
|
|||
const val movie123NetAPI = "https://ww8.0123movie.net"
|
||||
const val smashyStreamAPI = "https://embed.smashystream.com"
|
||||
const val watchSomuchAPI = "https://watchsomuch.tv" // sub only
|
||||
val gomoviesAPI =
|
||||
base64DecodeAPI("bQ==Y28=ZS4=aW4=bmw=LW8=ZXM=dmk=bW8=Z28=Ly8=czo=dHA=aHQ=")
|
||||
val gomoviesAPI = base64DecodeAPI("bQ==Y28=ZS4=aW4=bmw=LW8=ZXM=dmk=bW8=Z28=Ly8=czo=dHA=aHQ=")
|
||||
const val ask4MoviesAPI = "https://ask4movie.mx"
|
||||
const val biliBiliAPI = "https://api-vn.kaguya.app/server"
|
||||
const val watchOnlineAPI = "https://watchonline.ag"
|
||||
const val nineTvAPI = "https://api.9animetv.live"
|
||||
const val putlockerAPI = "https://ww7.putlocker.vip"
|
||||
const val fmoviesAPI = "https://fmovies.to"
|
||||
|
||||
// INDEX SITE
|
||||
const val baymoviesAPI = "https://opengatewayindex.pages.dev" // dead
|
||||
const val chillmovies0API = "https://chill.aicirou.workers.dev/0:" // dead
|
||||
const val chillmovies1API = "https://chill.aicirou.workers.dev/1:" // dead
|
||||
const val gamMoviesAPI = "https://drive.gamick.workers.dev/0:" // dead
|
||||
const val jsMoviesAPI = "https://jsupload.jnsbot.workers.dev/0:" // dead
|
||||
const val xtremeMoviesAPI = "https://kartik19.xtrememirror0.workers.dev/0:" // dead
|
||||
const val blackMoviesAPI = "https://dl.blacklistedbois.workers.dev/0:"
|
||||
const val rinzryMoviesAPI = "https://rinzry.stream/0:"
|
||||
const val codexMoviesAPI = "https://packs.codexcloudx.tech/0:"
|
||||
|
@ -143,7 +135,6 @@ open class SoraStream : TmdbProvider() {
|
|||
const val papaonMovies1API = "https://m.papaonwork.workers.dev/0:"
|
||||
const val papaonMovies2API = "https://m.papaonwork.workers.dev/1:"
|
||||
const val dahmerMoviesAPI = "https://edytjedhgmdhm.abfhaqrhbnf.workers.dev"
|
||||
const val tgarMovieAPI = "https://tgarchive.eu.org" // dead
|
||||
const val jmdkhMovieAPI = "https://tg.jmdkh.eu.org/0:"
|
||||
const val rubyMovieAPI = "https://upload.rubyshare111.workers.dev/0:"
|
||||
const val shinobiMovieAPI = "https://home.shinobicloud.cf/0:"
|
||||
|
@ -151,6 +142,16 @@ open class SoraStream : TmdbProvider() {
|
|||
const val shivamhwAPI = "https://foogle.shivamhw.me"
|
||||
val cryMoviesAPI = base64DecodeAPI("ZXY=LmQ=cnM=a2U=b3I=Lnc=ZXI=ZGQ=bGE=cy0=b2I=YWM=Lmo=YWw=aW4=LWY=cm4=Ym8=cmU=Ly8=czo=dHA=aHQ=")
|
||||
|
||||
// DEAD SITE
|
||||
const val consumetCrunchyrollAPI = "https://cronchy.consumet.stream" // dead
|
||||
const val chillmovies0API = "https://chill.aicirou.workers.dev/0:" // dead
|
||||
const val chillmovies1API = "https://chill.aicirou.workers.dev/1:" // dead
|
||||
const val gamMoviesAPI = "https://drive.gamick.workers.dev/0:" // dead
|
||||
const val jsMoviesAPI = "https://jsupload.jnsbot.workers.dev/0:" // dead
|
||||
const val xtremeMoviesAPI = "https://kartik19.xtrememirror0.workers.dev/0:" // dead
|
||||
const val tgarMovieAPI = "https://tgarchive.eu.org" // dead
|
||||
const val baymoviesAPI = "https://opengatewayindex.pages.dev" // dead
|
||||
|
||||
fun getType(t: String?): TvType {
|
||||
return when (t) {
|
||||
"movie" -> TvType.Movie
|
||||
|
|
|
@ -29,6 +29,7 @@ import okhttp3.RequestBody.Companion.toRequestBody
|
|||
import org.jsoup.nodes.Document
|
||||
import java.net.URI
|
||||
import java.net.URL
|
||||
import java.net.URLDecoder
|
||||
import java.net.URLEncoder
|
||||
import java.nio.charset.StandardCharsets
|
||||
import java.security.MessageDigest
|
||||
|
@ -40,8 +41,9 @@ 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 bflixChipperKey = base64DecodeAPI("Yjc=ejM=TzA=YTk=WHE=WnU=bXU=RFo=")
|
||||
val bflixKey = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
|
||||
|
||||
val soraHeaders = mapOf(
|
||||
"lang" to "en",
|
||||
|
@ -397,6 +399,21 @@ suspend fun getDirectGdrive(url: String): String {
|
|||
|
||||
}
|
||||
|
||||
suspend fun invokeVizcloud(
|
||||
url: String,
|
||||
callback: (ExtractorLink) -> Unit,
|
||||
) {
|
||||
val id = Regex("(?:embed-|/e/)([^?]*)").find(url)?.groupValues?.getOrNull(1)
|
||||
app.get("https://api.consumet.org/anime/9anime/helper?query=${id ?: return}&action=vizcloud")
|
||||
.parsedSafe<VizcloudResponses>()?.data?.media?.sources?.map {
|
||||
M3u8Helper.generateM3u8(
|
||||
"Vizcloud",
|
||||
it.file ?: return@map,
|
||||
"${getBaseUrl(url)}/"
|
||||
).forEach(callback)
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun invokeSmashyOne(
|
||||
name: String,
|
||||
url: String,
|
||||
|
@ -1154,13 +1171,18 @@ fun getDeviceId(length: Int = 16): String {
|
|||
fun encodeVrf(query: String): String {
|
||||
return encode(
|
||||
encryptVrf(
|
||||
cipherVrf("DZmuZuXqa9O0z3b7", encode(query)),
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
|
||||
cipherVrf(bflixChipperKey, encode(query)),
|
||||
bflixKey
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
fun encryptVrf(input: String, key: String): String {
|
||||
fun decodeVrf(text: String): String {
|
||||
return decode(cipherVrf(bflixChipperKey, decryptVrf(text, bflixKey)))
|
||||
}
|
||||
|
||||
@Suppress("SameParameterValue")
|
||||
private fun encryptVrf(input: String, key: String): String {
|
||||
if (input.any { it.code > 255 }) throw Exception("illegal characters!")
|
||||
var output = ""
|
||||
for (i in input.indices step 3) {
|
||||
|
@ -1185,6 +1207,42 @@ fun encryptVrf(input: String, key: String): String {
|
|||
return output
|
||||
}
|
||||
|
||||
@Suppress("SameParameterValue")
|
||||
private fun decryptVrf(input: String, key: String): String {
|
||||
val t = if (input.replace("""[\t\n\f\r]""".toRegex(), "").length % 4 == 0) {
|
||||
input.replace("""==?$""".toRegex(), "")
|
||||
} else input
|
||||
if (t.length % 4 == 1 || t.contains("""[^+/0-9A-Za-z]""".toRegex())) throw Exception("bad input")
|
||||
var i: Int
|
||||
var r = ""
|
||||
var e = 0
|
||||
var u = 0
|
||||
for (o in t.indices) {
|
||||
e = e shl 6
|
||||
i = key.indexOf(t[o])
|
||||
e = e or i
|
||||
u += 6
|
||||
if (24 == u) {
|
||||
r += ((16711680 and e) shr 16).toChar()
|
||||
r += ((65280 and e) shr 8).toChar()
|
||||
r += (255 and e).toChar()
|
||||
e = 0
|
||||
u = 0
|
||||
}
|
||||
}
|
||||
return if (12 == u) {
|
||||
e = e shr 4
|
||||
r + e.toChar()
|
||||
} else {
|
||||
if (18 == u) {
|
||||
e = e shr 2
|
||||
r += ((65280 and e) shr 8).toChar()
|
||||
r += (255 and e).toChar()
|
||||
}
|
||||
r
|
||||
}
|
||||
}
|
||||
|
||||
fun cipherVrf(key: String, text: String): String {
|
||||
val arr = IntArray(256) { it }
|
||||
|
||||
|
@ -1225,6 +1283,8 @@ fun String.decodeBase64(): String {
|
|||
return Base64.decode(this, Base64.DEFAULT).toString(Charsets.UTF_8)
|
||||
}
|
||||
|
||||
fun decode(input: String): String = URLDecoder.decode(input, "utf-8")
|
||||
|
||||
fun encode(input: String): String = URLEncoder.encode(input, "utf-8").replace("+", "%20")
|
||||
|
||||
fun decryptStreamUrl(data: String): String {
|
||||
|
|
Loading…
Reference in a new issue