sora: fixed sources

This commit is contained in:
hexated 2023-04-29 00:25:17 +07:00
parent 43c6c3108b
commit db046fe123
4 changed files with 122 additions and 39 deletions

View file

@ -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 {

View file

@ -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,
) )

View file

@ -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

View file

@ -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 {