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
|
import org.jetbrains.kotlin.konan.properties.Properties
|
||||||
|
|
||||||
// use an integer for version numbers
|
// use an integer for version numbers
|
||||||
version = 123
|
version = 124
|
||||||
|
|
||||||
android {
|
android {
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
|
|
|
@ -732,8 +732,8 @@ object SoraExtractor : SoraStream() {
|
||||||
) {
|
) {
|
||||||
val query = title?.replace(Regex("[^\\w-\\s]"), "")
|
val query = title?.replace(Regex("[^\\w-\\s]"), "")
|
||||||
val html =
|
val html =
|
||||||
app.get("https://fmovies.to/ajax/film/search?vrf=${encodeVrf("$query")}&keyword=$query")
|
app.get("$fmoviesAPI/ajax/film/search?vrf=${encodeVrf("$query")}&keyword=$query")
|
||||||
.parsedSafe<FmoviesSearch>()?.html
|
.parsedSafe<FmoviesResponses>()?.html
|
||||||
|
|
||||||
val mediaId = Jsoup.parse(html ?: return).select("a.item").map {
|
val mediaId = Jsoup.parse(html ?: return).select("a.item").map {
|
||||||
Triple(
|
Triple(
|
||||||
|
@ -748,7 +748,7 @@ object SoraExtractor : SoraStream() {
|
||||||
it.first.contains("/series/")
|
it.first.contains("/series/")
|
||||||
} && (it.second.equals(title, true) || it.second.createSlug()
|
} && (it.second.equals(title, true) || it.second.createSlug()
|
||||||
.equals(title.createSlug())) && it.third.toInt() == year
|
.equals(title.createSlug())) && it.third.toInt() == year
|
||||||
}?.first ?: return
|
}?.first?.substringAfterLast("-") ?: return
|
||||||
|
|
||||||
val episodeId = if (season == null) {
|
val episodeId = if (season == null) {
|
||||||
"1-full"
|
"1-full"
|
||||||
|
@ -756,32 +756,32 @@ object SoraExtractor : SoraStream() {
|
||||||
"$season-$episode"
|
"$season-$episode"
|
||||||
}
|
}
|
||||||
|
|
||||||
val sources = app.get(
|
val serversKname =
|
||||||
"$consumetFmoviesAPI/watch?mediaId=${mediaId.removePrefix("/")}&episodeId=$episodeId"
|
app.get("$fmoviesAPI/ajax/film/servers?id=$mediaId&vrf=${encodeVrf(mediaId)}")
|
||||||
).parsedSafe<ConsumetSourcesResponse>()
|
.parsedSafe<FmoviesResponses>()?.html?.let { Jsoup.parse(it) }
|
||||||
|
?.selectFirst("a[data-kname=$episodeId]")?.attr("data-ep")
|
||||||
|
|
||||||
sources?.sources?.map {
|
val servers = tryParseJson<HashMap<String, String>>(serversKname)
|
||||||
callback.invoke(
|
|
||||||
ExtractorLink(
|
servers?.apmap { server ->
|
||||||
"Vizcloud",
|
val decryptServer = app.get("$fmoviesAPI/ajax/episode/info?id=${server.value}")
|
||||||
"Vizcloud",
|
.parsedSafe<FmoviesResponses>()?.url?.let { decodeVrf(it) } ?: return@apmap
|
||||||
it.url ?: return@map null,
|
if (server.key == "41") {
|
||||||
sources.headers?.referer ?: "",
|
invokeVizcloud(decryptServer, callback)
|
||||||
getQualityFromName(it.quality),
|
} else {
|
||||||
it.isM3U8 ?: true
|
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(
|
subtitleCallback.invoke(
|
||||||
SubtitleFile(
|
SubtitleFile(
|
||||||
it.lang ?: "", it.url ?: return@map null
|
it.label ?: "",
|
||||||
|
it.file ?: return@map
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun invokeKisskh(
|
suspend fun invokeKisskh(
|
||||||
|
@ -3403,6 +3403,28 @@ data class DudetvSources(
|
||||||
@JsonProperty("title") val title: String? = null,
|
@JsonProperty("title") val title: String? = null,
|
||||||
)
|
)
|
||||||
|
|
||||||
data class FmoviesSearch(
|
data class FmoviesResponses(
|
||||||
@JsonProperty("html") val html: String? = null,
|
@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 filmxyAPI = "https://www.filmxy.vip"
|
||||||
const val kimcartoonAPI = "https://kimcartoon.li"
|
const val kimcartoonAPI = "https://kimcartoon.li"
|
||||||
const val xMovieAPI = "https://xemovies.to"
|
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 consumetZoroAPI = "https://api.consumet.org/anime/zoro"
|
||||||
const val consumetCrunchyrollAPI = "https://cronchy.consumet.stream" // dead
|
|
||||||
const val allanimeAPI = "https://api.allanime.to"
|
const val allanimeAPI = "https://api.allanime.to"
|
||||||
const val kissKhAPI = "https://kisskh.co"
|
const val kissKhAPI = "https://kisskh.co"
|
||||||
const val lingAPI = "https://ling-online.net"
|
const val lingAPI = "https://ling-online.net"
|
||||||
|
@ -121,21 +119,15 @@ open class SoraStream : TmdbProvider() {
|
||||||
const val movie123NetAPI = "https://ww8.0123movie.net"
|
const val movie123NetAPI = "https://ww8.0123movie.net"
|
||||||
const val smashyStreamAPI = "https://embed.smashystream.com"
|
const val smashyStreamAPI = "https://embed.smashystream.com"
|
||||||
const val watchSomuchAPI = "https://watchsomuch.tv" // sub only
|
const val watchSomuchAPI = "https://watchsomuch.tv" // sub only
|
||||||
val gomoviesAPI =
|
val gomoviesAPI = base64DecodeAPI("bQ==Y28=ZS4=aW4=bmw=LW8=ZXM=dmk=bW8=Z28=Ly8=czo=dHA=aHQ=")
|
||||||
base64DecodeAPI("bQ==Y28=ZS4=aW4=bmw=LW8=ZXM=dmk=bW8=Z28=Ly8=czo=dHA=aHQ=")
|
|
||||||
const val ask4MoviesAPI = "https://ask4movie.mx"
|
const val ask4MoviesAPI = "https://ask4movie.mx"
|
||||||
const val biliBiliAPI = "https://api-vn.kaguya.app/server"
|
const val biliBiliAPI = "https://api-vn.kaguya.app/server"
|
||||||
const val watchOnlineAPI = "https://watchonline.ag"
|
const val watchOnlineAPI = "https://watchonline.ag"
|
||||||
const val nineTvAPI = "https://api.9animetv.live"
|
const val nineTvAPI = "https://api.9animetv.live"
|
||||||
const val putlockerAPI = "https://ww7.putlocker.vip"
|
const val putlockerAPI = "https://ww7.putlocker.vip"
|
||||||
|
const val fmoviesAPI = "https://fmovies.to"
|
||||||
|
|
||||||
// INDEX SITE
|
// 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 blackMoviesAPI = "https://dl.blacklistedbois.workers.dev/0:"
|
||||||
const val rinzryMoviesAPI = "https://rinzry.stream/0:"
|
const val rinzryMoviesAPI = "https://rinzry.stream/0:"
|
||||||
const val codexMoviesAPI = "https://packs.codexcloudx.tech/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 papaonMovies1API = "https://m.papaonwork.workers.dev/0:"
|
||||||
const val papaonMovies2API = "https://m.papaonwork.workers.dev/1:"
|
const val papaonMovies2API = "https://m.papaonwork.workers.dev/1:"
|
||||||
const val dahmerMoviesAPI = "https://edytjedhgmdhm.abfhaqrhbnf.workers.dev"
|
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 jmdkhMovieAPI = "https://tg.jmdkh.eu.org/0:"
|
||||||
const val rubyMovieAPI = "https://upload.rubyshare111.workers.dev/0:"
|
const val rubyMovieAPI = "https://upload.rubyshare111.workers.dev/0:"
|
||||||
const val shinobiMovieAPI = "https://home.shinobicloud.cf/0:"
|
const val shinobiMovieAPI = "https://home.shinobicloud.cf/0:"
|
||||||
|
@ -151,6 +142,16 @@ open class SoraStream : TmdbProvider() {
|
||||||
const val shivamhwAPI = "https://foogle.shivamhw.me"
|
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=")
|
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 {
|
fun getType(t: String?): TvType {
|
||||||
return when (t) {
|
return when (t) {
|
||||||
"movie" -> TvType.Movie
|
"movie" -> TvType.Movie
|
||||||
|
|
|
@ -29,6 +29,7 @@ import okhttp3.RequestBody.Companion.toRequestBody
|
||||||
import org.jsoup.nodes.Document
|
import org.jsoup.nodes.Document
|
||||||
import java.net.URI
|
import java.net.URI
|
||||||
import java.net.URL
|
import java.net.URL
|
||||||
|
import java.net.URLDecoder
|
||||||
import java.net.URLEncoder
|
import java.net.URLEncoder
|
||||||
import java.nio.charset.StandardCharsets
|
import java.nio.charset.StandardCharsets
|
||||||
import java.security.MessageDigest
|
import java.security.MessageDigest
|
||||||
|
@ -40,8 +41,9 @@ import javax.crypto.spec.SecretKeySpec
|
||||||
import kotlin.collections.ArrayList
|
import kotlin.collections.ArrayList
|
||||||
import kotlin.math.min
|
import kotlin.math.min
|
||||||
|
|
||||||
val soraAPI =
|
val soraAPI = 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=")
|
val bflixChipperKey = base64DecodeAPI("Yjc=ejM=TzA=YTk=WHE=WnU=bXU=RFo=")
|
||||||
|
val bflixKey = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
|
||||||
|
|
||||||
val soraHeaders = mapOf(
|
val soraHeaders = mapOf(
|
||||||
"lang" to "en",
|
"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(
|
suspend fun invokeSmashyOne(
|
||||||
name: String,
|
name: String,
|
||||||
url: String,
|
url: String,
|
||||||
|
@ -1154,13 +1171,18 @@ fun getDeviceId(length: Int = 16): String {
|
||||||
fun encodeVrf(query: String): String {
|
fun encodeVrf(query: String): String {
|
||||||
return encode(
|
return encode(
|
||||||
encryptVrf(
|
encryptVrf(
|
||||||
cipherVrf("DZmuZuXqa9O0z3b7", encode(query)),
|
cipherVrf(bflixChipperKey, encode(query)),
|
||||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
|
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!")
|
if (input.any { it.code > 255 }) throw Exception("illegal characters!")
|
||||||
var output = ""
|
var output = ""
|
||||||
for (i in input.indices step 3) {
|
for (i in input.indices step 3) {
|
||||||
|
@ -1185,6 +1207,42 @@ fun encryptVrf(input: String, key: String): String {
|
||||||
return output
|
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 {
|
fun cipherVrf(key: String, text: String): String {
|
||||||
val arr = IntArray(256) { it }
|
val arr = IntArray(256) { it }
|
||||||
|
|
||||||
|
@ -1225,6 +1283,8 @@ fun String.decodeBase64(): String {
|
||||||
return Base64.decode(this, Base64.DEFAULT).toString(Charsets.UTF_8)
|
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 encode(input: String): String = URLEncoder.encode(input, "utf-8").replace("+", "%20")
|
||||||
|
|
||||||
fun decryptStreamUrl(data: String): String {
|
fun decryptStreamUrl(data: String): String {
|
||||||
|
|
Loading…
Reference in a new issue