sora: added ninetv

This commit is contained in:
hexated 2023-04-08 21:14:42 +07:00
parent 67f87cd7a5
commit 3ca01b9b81
6 changed files with 164 additions and 1 deletions

View file

@ -1,5 +1,5 @@
// use an integer for version numbers
version = 113
version = 114
cloudstream {

View file

@ -1,8 +1,19 @@
package com.hexated
import com.fasterxml.jackson.annotation.JsonProperty
import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.extractors.Filesim
import com.lagradost.cloudstream3.extractors.StreamSB
import com.lagradost.cloudstream3.extractors.XStreamCdn
import com.lagradost.cloudstream3.utils.AppUtils
import com.lagradost.cloudstream3.utils.ExtractorApi
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.Qualities
import javax.crypto.Cipher
import javax.crypto.SecretKeyFactory
import javax.crypto.spec.IvParameterSpec
import javax.crypto.spec.PBEKeySpec
import javax.crypto.spec.SecretKeySpec
class Sbnet : StreamSB() {
override var name = "Sbnet"
@ -28,3 +39,120 @@ class FileMoonIn : Filesim() {
override val mainUrl = "https://filemoon.in"
override val name = "FileMoon"
}
class Watchx : Chillx() {
override val name = "Watchx"
override val mainUrl = "https://watchx.top"
}
open class Chillx : ExtractorApi() {
override val name = "Chillx"
override val mainUrl = "https://chillx.top"
override val requiresReferer = true
companion object {
private const val KEY = "4VqE3#N7zt&HEP^a"
}
override suspend fun getUrl(
url: String,
referer: String?,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
) {
val master = Regex("MasterJS\\s*=\\s*'([^']+)").find(
app.get(
url,
referer = referer
).text
)?.groupValues?.get(1)
val encData = AppUtils.tryParseJson<AESData>(base64Decode(master ?: return))
val decrypt = cryptoAESHandler(encData ?: return, KEY, false)
val source = Regex("""sources:\s*\[\{"file":"([^"]+)""").find(decrypt)?.groupValues?.get(1)
val tracks = Regex("""tracks:\s*\[(.+)]""").find(decrypt)?.groupValues?.get(1)
val headers = mapOf(
"Accept" to "*/*",
"Connection" to "keep-alive",
"Sec-Fetch-Dest" to "empty",
"Sec-Fetch-Mode" to "cors",
"Sec-Fetch-Site" to "cross-site",
"Origin" to mainUrl,
)
callback.invoke(
ExtractorLink(
name,
name,
source ?: return,
"$mainUrl/",
Qualities.P1080.value,
headers = headers,
isM3u8 = true
)
)
AppUtils.tryParseJson<List<Tracks>>("[$tracks]")
?.filter { it.kind == "captions" }?.map { track ->
subtitleCallback.invoke(
SubtitleFile(
track.label ?: "",
track.file ?: return@map null
)
)
}
}
private fun cryptoAESHandler(
data: AESData,
pass: String,
encrypt: Boolean = true
): String {
val factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA512")
val spec = PBEKeySpec(
pass.toCharArray(),
data.salt?.hexToByteArray(),
data.iterations?.toIntOrNull() ?: 1,
256
)
val key = factory.generateSecret(spec)
val cipher = Cipher.getInstance("AES/CBC/PKCS5Padding")
return if (!encrypt) {
cipher.init(
Cipher.DECRYPT_MODE,
SecretKeySpec(key.encoded, "AES"),
IvParameterSpec(data.iv?.hexToByteArray())
)
String(cipher.doFinal(base64DecodeArray(data.ciphertext.toString())))
} else {
cipher.init(
Cipher.ENCRYPT_MODE,
SecretKeySpec(key.encoded, "AES"),
IvParameterSpec(data.iv?.hexToByteArray())
)
base64Encode(cipher.doFinal(data.ciphertext?.toByteArray()))
}
}
private fun String.hexToByteArray(): ByteArray {
check(length % 2 == 0) { "Must have an even length" }
return chunked(2)
.map { it.toInt(16).toByte() }
.toByteArray()
}
data class AESData(
@JsonProperty("ciphertext") val ciphertext: String? = null,
@JsonProperty("iv") val iv: String? = null,
@JsonProperty("salt") val salt: String? = null,
@JsonProperty("iterations") val iterations: String? = null,
)
data class Tracks(
@JsonProperty("file") val file: String? = null,
@JsonProperty("label") val label: String? = null,
@JsonProperty("kind") val kind: String? = null,
)
}

View file

@ -2767,6 +2767,24 @@ object SoraExtractor : SoraStream() {
}
}
suspend fun invokeNinetv(
tmdbId: Int? = null,
season: Int? = null,
episode: Int? = null,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
) {
val url = if (season == null) {
"$nineTvAPI/movie/$tmdbId"
} else {
"$nineTvAPI/tv/$tmdbId-$season-$episode"
}
val iframe = app.get(url).document.selectFirst("iframe")?.attr("src") ?: return
loadExtractor(iframe, "$nineTvAPI/", subtitleCallback, callback)
}
}

View file

@ -38,6 +38,7 @@ import com.hexated.SoraExtractor.invokeM4uhd
import com.hexated.SoraExtractor.invokeMovie123Net
import com.hexated.SoraExtractor.invokeMoviesbay
import com.hexated.SoraExtractor.invokeMoviezAdd
import com.hexated.SoraExtractor.invokeNinetv
import com.hexated.SoraExtractor.invokePapaonMovies1
import com.hexated.SoraExtractor.invokePapaonMovies2
import com.hexated.SoraExtractor.invokeRStream
@ -120,6 +121,7 @@ open class SoraStream : TmdbProvider() {
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"
// INDEX SITE
const val baymoviesAPI = "https://opengatewayindex.pages.dev" // dead
const val chillmovies0API = "https://chill.aicirou.workers.dev/0:" // dead
@ -630,6 +632,9 @@ open class SoraStream : TmdbProvider() {
subtitleCallback
)
},
{
if (!res.isAnime) invokeNinetv(res.id, res.season, res.episode, subtitleCallback, callback)
},
{
if (!res.isAnime) invokeBlackmovies(
blackMoviesAPI,

View file

@ -17,6 +17,7 @@ import com.hexated.SoraExtractor.invokeLing
import com.hexated.SoraExtractor.invokeM4uhd
import com.hexated.SoraExtractor.invokeMovie123Net
import com.hexated.SoraExtractor.invokeMovieHab
import com.hexated.SoraExtractor.invokeNinetv
import com.hexated.SoraExtractor.invokeRStream
import com.hexated.SoraExtractor.invokeSeries9
import com.hexated.SoraExtractor.invokeSmashyStream
@ -63,6 +64,15 @@ class SoraStreamLite : SoraStream() {
callback
)
},
{
if (!res.isAnime) invokeNinetv(
res.id,
res.season,
res.episode,
subtitleCallback,
callback
)
},
{
invokeTwoEmbed(res.id, res.season, res.episode, subtitleCallback, callback)
},

View file

@ -16,5 +16,7 @@ class SoraStreamPlugin: Plugin() {
registerExtractorAPI(Keephealth())
registerExtractorAPI(FileMoonIn())
registerExtractorAPI(Sbnet())
registerExtractorAPI(Chillx())
registerExtractorAPI(Watchx())
}
}