From f03308bd7e3f8cb55f93b06da7fdf25c8e9bf44d Mon Sep 17 00:00:00 2001 From: hexated Date: Tue, 3 Oct 2023 23:47:31 +0700 Subject: [PATCH] sora: added Blackvid --- SoraStream/build.gradle.kts | 2 +- .../main/kotlin/com/hexated/SoraExtractor.kt | 44 +++++++++++++++++++ .../src/main/kotlin/com/hexated/SoraParser.kt | 20 +++++++++ .../src/main/kotlin/com/hexated/SoraStream.kt | 11 +++++ .../main/kotlin/com/hexated/SoraStreamLite.kt | 10 +++++ .../src/main/kotlin/com/hexated/SoraUtils.kt | 28 ++++++++++++ 6 files changed, 114 insertions(+), 1 deletion(-) diff --git a/SoraStream/build.gradle.kts b/SoraStream/build.gradle.kts index bb4a8615..115265e8 100644 --- a/SoraStream/build.gradle.kts +++ b/SoraStream/build.gradle.kts @@ -1,7 +1,7 @@ import org.jetbrains.kotlin.konan.properties.Properties // use an integer for version numbers -version = 177 +version = 178 android { defaultConfig { diff --git a/SoraStream/src/main/kotlin/com/hexated/SoraExtractor.kt b/SoraStream/src/main/kotlin/com/hexated/SoraExtractor.kt index 640ec1a3..794bdb2b 100644 --- a/SoraStream/src/main/kotlin/com/hexated/SoraExtractor.kt +++ b/SoraStream/src/main/kotlin/com/hexated/SoraExtractor.kt @@ -1,5 +1,6 @@ package com.hexated +import com.hexated.AESGCM.decrypt import com.lagradost.cloudstream3.* import com.lagradost.cloudstream3.APIHolder.unixTimeMS import com.lagradost.cloudstream3.utils.* @@ -2175,6 +2176,49 @@ object SoraExtractor : SoraStream() { } + suspend fun invokeBlackvid( + tmdbId: Int? = null, + season: Int? = null, + episode: Int? = null, + subtitleCallback: (SubtitleFile) -> Unit, + callback: (ExtractorLink) -> Unit, + ) { + val key = "c3124ecca65f4e72ef5cb39033cdfed69697e94e" + val url = if (season == null) { + "$blackvidAPI/v3/movie/sources/$tmdbId?key=$key" + } else { + "$blackvidAPI/v3/tv/sources/$tmdbId/$season/$episode?key=$key" + } + + val data = app.get(url).body.bytes().decrypt(key) + val json = tryParseJson(data) + + json?.sources?.map { source -> + source.sources.map s@{ s -> + callback.invoke( + ExtractorLink( + "Blackvid", + "Blackvid${source.label}", + s.url ?: return@s, + "$blackvidAPI/", + s.quality?.toIntOrNull() ?: Qualities.Unknown.value, + INFER_TYPE + ) + ) + } + } + + json?.subtitles?.map { sub -> + subtitleCallback.invoke( + SubtitleFile( + sub.language.takeIf { it?.isNotEmpty() == true } ?: return@map, + sub.url ?: return@map, + ) + ) + } + + } + suspend fun invokeWatchOnline( imdbId: String? = null, title: String? = null, diff --git a/SoraStream/src/main/kotlin/com/hexated/SoraParser.kt b/SoraStream/src/main/kotlin/com/hexated/SoraParser.kt index f1ccf851..02d5a6cd 100644 --- a/SoraStream/src/main/kotlin/com/hexated/SoraParser.kt +++ b/SoraStream/src/main/kotlin/com/hexated/SoraParser.kt @@ -391,4 +391,24 @@ data class EMovieSources( data class EMovieTraks( @JsonProperty("file") val file: String? = null, @JsonProperty("label") val label: String? = null, +) + +data class BlackvidSubtitles( + @JsonProperty("language") val language: String? = null, + @JsonProperty("url") val url: String? = null, +) + +data class BlackvidSource( + @JsonProperty("quality") var quality: String? = null, + @JsonProperty("url") var url: String? = null, +) + +data class BlackvidSources( + @JsonProperty("label") var label: String? = null, + @JsonProperty("sources") var sources: ArrayList = arrayListOf() +) + +data class BlackvidResponses( + @JsonProperty("sources") var sources: ArrayList = arrayListOf(), + @JsonProperty("subtitles") var subtitles: ArrayList = arrayListOf() ) \ No newline at end of file diff --git a/SoraStream/src/main/kotlin/com/hexated/SoraStream.kt b/SoraStream/src/main/kotlin/com/hexated/SoraStream.kt index dac1e69f..8d7537ca 100644 --- a/SoraStream/src/main/kotlin/com/hexated/SoraStream.kt +++ b/SoraStream/src/main/kotlin/com/hexated/SoraStream.kt @@ -3,6 +3,7 @@ package com.hexated import com.fasterxml.jackson.annotation.JsonProperty import com.hexated.SoraExtractor.invoke2embed import com.hexated.SoraExtractor.invokeAnimes +import com.hexated.SoraExtractor.invokeBlackvid import com.hexated.SoraExtractor.invokeBollyMaza import com.hexated.SoraExtractor.invokeCryMovies import com.hexated.SoraExtractor.invokeDbgo @@ -130,6 +131,7 @@ open class SoraStream : TmdbProvider() { const val watchflxAPI = "https://watchflx.tv" const val gomoviesAPI = "https://gomovies-online.cam" const val dotmoviesAPI = "https://dotmovies.today" + const val blackvidAPI = "https://prod.api.blackvid.space" // INDEX SITE const val dahmerMoviesAPI = "https://edytjedhgmdhm.abfhaqrhbnf.workers.dev" @@ -736,6 +738,15 @@ open class SoraStream : TmdbProvider() { subtitleCallback, callback ) + }, + { + if (!res.isAnime) invokeBlackvid( + res.id, + res.season, + res.episode, + subtitleCallback, + callback + ) } ) diff --git a/SoraStream/src/main/kotlin/com/hexated/SoraStreamLite.kt b/SoraStream/src/main/kotlin/com/hexated/SoraStreamLite.kt index 08809b45..1f93d261 100644 --- a/SoraStream/src/main/kotlin/com/hexated/SoraStreamLite.kt +++ b/SoraStream/src/main/kotlin/com/hexated/SoraStreamLite.kt @@ -2,6 +2,7 @@ package com.hexated import com.hexated.SoraExtractor.invoke2embed import com.hexated.SoraExtractor.invokeAnimes +import com.hexated.SoraExtractor.invokeBlackvid import com.hexated.SoraExtractor.invokeDbgo import com.hexated.SoraExtractor.invokeDoomovies import com.hexated.SoraExtractor.invokeDramaday @@ -64,6 +65,15 @@ class SoraStreamLite : SoraStream() { // callback // ) // }, + { + if (!res.isAnime) invokeBlackvid( + res.id, + res.season, + res.episode, + subtitleCallback, + callback + ) + }, { if (!res.isAnime) invokeWatchsomuch( res.imdbId, diff --git a/SoraStream/src/main/kotlin/com/hexated/SoraUtils.kt b/SoraStream/src/main/kotlin/com/hexated/SoraUtils.kt index 4339e60e..31c4028c 100644 --- a/SoraStream/src/main/kotlin/com/hexated/SoraUtils.kt +++ b/SoraStream/src/main/kotlin/com/hexated/SoraUtils.kt @@ -30,12 +30,14 @@ import okhttp3.RequestBody.Companion.toRequestBody import org.jsoup.nodes.Document import java.math.BigInteger import java.net.* +import java.nio.charset.StandardCharsets import java.security.* import java.security.spec.PKCS8EncodedKeySpec import java.security.spec.X509EncodedKeySpec import java.text.SimpleDateFormat import java.util.* import javax.crypto.Cipher +import javax.crypto.spec.GCMParameterSpec import javax.crypto.spec.IvParameterSpec import javax.crypto.spec.SecretKeySpec import kotlin.collections.ArrayList @@ -1641,4 +1643,30 @@ object CryptoJS { SecureRandom().nextBytes(this) } } +} + +object AESGCM { + fun ByteArray.decrypt(pass: String): String { + val (key, iv) = generateKeyAndIv(pass) + val cipher = Cipher.getInstance("AES/GCM/NoPadding") + cipher.init(Cipher.DECRYPT_MODE, SecretKeySpec(key, "AES"), GCMParameterSpec(128, iv)) + return String(cipher.doFinal(this), StandardCharsets.UTF_8) + } + + private fun generateKeyAndIv(pass: String): Pair { + val datePart = getCurrentUTCDateString().take(16) + val hexString = datePart + pass + val byteArray = hexString.toByteArray(StandardCharsets.UTF_8) + val digest = MessageDigest.getInstance("SHA-256").digest(byteArray) + return digest.copyOfRange(0, digest.size / 2) to digest.copyOfRange( + digest.size / 2, + digest.size + ) + } + + private fun getCurrentUTCDateString(): String { + val dateFormat = SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.getDefault()) + dateFormat.timeZone = TimeZone.getTimeZone("GMT") + return dateFormat.format(Date()) + } } \ No newline at end of file