From 4f74324be33589312d609c125ee77c1c6457472f Mon Sep 17 00:00:00 2001 From: Blatzar <46196380+Blatzar@users.noreply.github.com> Date: Mon, 31 Oct 2022 19:20:29 +0100 Subject: [PATCH 01/12] Fix AllAnimeProvider --- AllAnimeProvider/build.gradle.kts | 2 +- .../kotlin/com/lagradost/AllAnimeProvider.kt | 89 +++++++++++-------- .../main/kotlin/com/lagradost/PopularQuery.kt | 68 ++++++++++++++ 3 files changed, 121 insertions(+), 38 deletions(-) create mode 100644 AllAnimeProvider/src/main/kotlin/com/lagradost/PopularQuery.kt diff --git a/AllAnimeProvider/build.gradle.kts b/AllAnimeProvider/build.gradle.kts index dcfc449..0963531 100644 --- a/AllAnimeProvider/build.gradle.kts +++ b/AllAnimeProvider/build.gradle.kts @@ -1,5 +1,5 @@ // use an integer for version numbers -version = 3 +version = 4 cloudstream { diff --git a/AllAnimeProvider/src/main/kotlin/com/lagradost/AllAnimeProvider.kt b/AllAnimeProvider/src/main/kotlin/com/lagradost/AllAnimeProvider.kt index 31bded0..ba53b31 100644 --- a/AllAnimeProvider/src/main/kotlin/com/lagradost/AllAnimeProvider.kt +++ b/AllAnimeProvider/src/main/kotlin/com/lagradost/AllAnimeProvider.kt @@ -4,6 +4,7 @@ import com.fasterxml.jackson.annotation.JsonProperty import com.lagradost.cloudstream3.* import com.lagradost.cloudstream3.LoadResponse.Companion.addActors import com.lagradost.cloudstream3.mvvm.safeApiCall +import com.lagradost.cloudstream3.ui.settings.SettingsProviders import com.lagradost.cloudstream3.utils.AppUtils.parseJson import com.lagradost.cloudstream3.utils.ExtractorLink import com.lagradost.cloudstream3.utils.M3u8Helper @@ -104,56 +105,70 @@ class AllAnimeProvider : MainAPI() { @JsonProperty("__typename") val _typename: String? = null ) - override suspend fun getMainPage(page: Int, request : MainPageRequest): HomePageResponse { - val items = ArrayList() - val urls = listOf( -// Pair( -// "Top Anime", -// """$mainUrl/graphql?variables={"type":"anime","size":30,"dateRange":30}&extensions={"persistedQuery":{"version":1,"sha256Hash":"276d52ba09ca48ce2b8beb3affb26d9d673b22f9d1fd4892aaa39524128bc745"}}""" -// ), - // "countryOrigin":"JP" for Japanese only - Pair( - "Recently updated", - """$mainUrl/graphql?variables={"search":{"allowAdult":false,"allowUnknown":false},"limit":30,"page":1,"translationType":"dub","countryOrigin":"ALL"}&extensions={"persistedQuery":{"version":1,"sha256Hash":"d2670e3e27ee109630991152c8484fce5ff5e280c523378001f9a23dc1839068"}}""" - ), + private val popularTitle = "Popular" + private val recentTitle = "Recently updated" + override val mainPage = listOf( + MainPageData( + recentTitle, + """$mainUrl/allanimeapi?variables={"search":{"sortBy":"Recent","allowAdult":${settingsForProvider.enableAdult},"allowUnknown":false},"limit":26,"page":%d,"translationType":"sub","countryOrigin":"ALL"}&extensions={"persistedQuery":{"version":1,"sha256Hash":"9c7a8bc1e095a34f2972699e8105f7aaf9082c6e1ccd56eab99c2f1a971152c6"}}""" + ), + MainPageData( + popularTitle, + """$mainUrl/allanimeapi?variables={"type":"anime","size":30,"dateRange":1,"page":%d,"allowAdult":${settingsForProvider.enableAdult},"allowUnknown":false}&extensions={"persistedQuery":{"version":1,"sha256Hash":"6f6fe5663e3e9ea60bdfa693f878499badab83e7f18b56acdba5f8e8662002aa"}}""" ) + ) - val random = - """$mainUrl/graphql?variables={"format":"anime"}&extensions={"persistedQuery":{"version":1,"sha256Hash":"21ac672633498a3698e8f6a93ce6c2b3722b29a216dcca93363bf012c360cd54"}}""" - val ranlink = app.get(random).text - val jsonran = parseJson(ranlink) - val ranhome = jsonran.data?.queryRandomRecommendation?.map { - newAnimeSearchResponse(it.name!!, "$mainUrl/anime/${it.Id}", fix = false) { - this.posterUrl = it.thumbnail - this.otherName = it.nativeName - } - } + override suspend fun getMainPage(page: Int, request: MainPageRequest): HomePageResponse { + val url = request.data.format(page) + val test = app.get(url).text - items.add(HomePageList("Random", ranhome!!)) + val home = when (request.name) { + recentTitle -> { + val json = parseJson(test) + val results = json.data.shows.edges.filter { + // filtering in case there is an anime with 0 episodes available on the site. + !(it.availableEpisodes?.raw == 0 && it.availableEpisodes.sub == 0 && it.availableEpisodes.dub == 0) + } - urls.apmap { (HomeName, url) -> - val test = app.get(url).text - val json = parseJson(test) - val home = ArrayList() - val results = json.data.shows.edges.filter { - // filtering in case there is an anime with 0 episodes available on the site. - !(it.availableEpisodes?.raw == 0 && it.availableEpisodes.sub == 0 && it.availableEpisodes.dub == 0) - } - results.map { - home.add( + results.map { newAnimeSearchResponse(it.name, "$mainUrl/anime/${it.Id}", fix = false) { this.posterUrl = it.thumbnail this.year = it.airedStart?.year this.otherName = it.englishName addDub(it.availableEpisodes?.dub) addSub(it.availableEpisodes?.sub) - }) + } + } } - items.add(HomePageList(HomeName, home)) + popularTitle -> { + val json = parseJson(test) + val results = json.data?.queryPopular?.recommendations?.filter { + // filtering in case there is an anime with 0 episodes available on the site. + !(it.anyCard?.availableEpisodes?.raw == 0 && it.anyCard.availableEpisodes.sub == 0 && it.anyCard.availableEpisodes.dub == 0) + } + results?.mapNotNull { + newAnimeSearchResponse( + it.anyCard?.name ?: return@mapNotNull null, + "$mainUrl/anime/${it.anyCard.Id ?: it.pageStatus?.Id}", + fix = false + ) { + this.posterUrl = it.anyCard.thumbnail + this.otherName = it.anyCard.englishName + addDub(it.anyCard.availableEpisodes?.dub) + addSub(it.anyCard.availableEpisodes?.sub) + } + } ?: emptyList() + } + else -> emptyList() } - if (items.size <= 0) throw ErrorLoadingException() - return HomePageResponse(items) + + + return HomePageResponse( + listOf( + HomePageList(request.name, home) + ), hasNext = home.isNotEmpty() + ) } override suspend fun search(query: String): List { diff --git a/AllAnimeProvider/src/main/kotlin/com/lagradost/PopularQuery.kt b/AllAnimeProvider/src/main/kotlin/com/lagradost/PopularQuery.kt new file mode 100644 index 0000000..ed09992 --- /dev/null +++ b/AllAnimeProvider/src/main/kotlin/com/lagradost/PopularQuery.kt @@ -0,0 +1,68 @@ +package com.lagradost + +import com.fasterxml.jackson.annotation.JsonProperty + +data class PopularQuery( + @JsonProperty("data") val data: Data? = Data() +) + + +data class AvailableEpisodes( + @JsonProperty("sub") val sub: Int? = null, + @JsonProperty("dub") val dub: Int? = null, + @JsonProperty("raw") val raw: Int? = null +) + +data class Sub( + @JsonProperty("hour") val hour: Int? = null, + @JsonProperty("minute") val minute: Int? = null, + @JsonProperty("year") val year: Int? = null, + @JsonProperty("month") val month: Int? = null, + @JsonProperty("date") val date: Int? = null +) + +data class LastEpisodeDate( + @JsonProperty("dub") val dub: Sub? = Sub(), + @JsonProperty("sub") val sub: Sub? = Sub(), + @JsonProperty("raw") val raw: Sub? = Sub() +) + +data class AnyCard( + @JsonProperty("_id") val Id: String? = null, + @JsonProperty("name") val name: String? = null, + @JsonProperty("englishName") val englishName: String? = null, + @JsonProperty("nativeName") val nativeName: String? = null, + @JsonProperty("availableEpisodes") val availableEpisodes: AvailableEpisodes? = AvailableEpisodes(), + @JsonProperty("score") val score: Double? = null, + @JsonProperty("lastEpisodeDate") val lastEpisodeDate: LastEpisodeDate? = LastEpisodeDate(), + @JsonProperty("thumbnail") val thumbnail: String? = null, + @JsonProperty("lastChapterDate") val lastChapterDate: String? = null, + @JsonProperty("availableChapters") val availableChapters: String? = null, + @JsonProperty("__typename") val _typename: String? = null +) + +data class PageStatus( + @JsonProperty("_id") val Id: String? = null, + @JsonProperty("views") val views: String? = null, + @JsonProperty("showId") val showId: String? = null, + @JsonProperty("rangeViews") val rangeViews: String? = null, + @JsonProperty("isManga") val isManga: Boolean? = null, + @JsonProperty("__typename") val _typename: String? = null +) + + +data class Recommendations( + @JsonProperty("anyCard") val anyCard: AnyCard? = AnyCard(), + @JsonProperty("pageStatus") val pageStatus: PageStatus? = PageStatus(), + @JsonProperty("__typename") val _typename: String? = null +) + +data class QueryPopular( + @JsonProperty("total") val total: Int? = null, + @JsonProperty("recommendations") val recommendations: ArrayList = arrayListOf(), + @JsonProperty("__typename") val _typename: String? = null +) + +data class Data( + @JsonProperty("queryPopular") val queryPopular: QueryPopular? = QueryPopular() +) \ No newline at end of file From a3a4df376886158b57471b79c6fb3f45354c0de0 Mon Sep 17 00:00:00 2001 From: Cloudburst <18114966+C10udburst@users.noreply.github.com> Date: Tue, 1 Nov 2022 12:50:58 +0100 Subject: [PATCH 02/12] add infoHash to stremio (i've yet to find a working link) --- .../kotlin/com/lagradost/StremioProvider.kt | 34 +++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/StremioProvider/src/main/kotlin/com/lagradost/StremioProvider.kt b/StremioProvider/src/main/kotlin/com/lagradost/StremioProvider.kt index 7df1815..9e7cc31 100644 --- a/StremioProvider/src/main/kotlin/com/lagradost/StremioProvider.kt +++ b/StremioProvider/src/main/kotlin/com/lagradost/StremioProvider.kt @@ -13,6 +13,8 @@ import com.lagradost.cloudstream3.utils.loadExtractor import org.json.JSONObject import java.net.URLEncoder +private const val TRACKER_LIST_URL = "https://raw.githubusercontent.com/ngosang/trackerslist/master/trackers_best.txt" + class StremioProvider : MainAPI() { override var mainUrl = "https://stremio.github.io/stremio-static-addon-example" override var name = "Stremio example" @@ -53,7 +55,6 @@ class StremioProvider : MainAPI() { subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit ): Boolean { - Log.i("Stremio", data) val res = tryParseJson(app.get(data).text) ?: return false res.streams.forEach { stream -> stream.runCallback(subtitleCallback, callback) @@ -164,7 +165,9 @@ class StremioProvider : MainAPI() { val url: String?, val ytId: String?, val externalUrl: String?, - val behaviorHints: JSONObject? + val behaviorHints: JSONObject?, + val infoHash: String?, + val sources: List = emptyList() ) { suspend fun runCallback(subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit) { if (url != null) { @@ -205,6 +208,33 @@ class StremioProvider : MainAPI() { if (externalUrl != null) { loadExtractor(externalUrl, subtitleCallback, callback) } + if (infoHash != null) { + val resp = app.get(TRACKER_LIST_URL).text + val otherTrackers = resp + .split("\n") + .filterIndexed{i, s -> i%2==0} + .filter{s -> !s.isNullOrEmpty()} + .map{it -> "&tr=$it"} + .joinToString("") + + val sourceTrackers = sources + .filter{it->it.startsWith("tracker:")} + .map{it->it.removePrefix("tracker:")} + .filter{s -> !s.isNullOrEmpty()} + .map{it -> "&tr=$it"} + .joinToString("") + + val magnet = "magnet:?xt=urn:btih:${infoHash}${sourceTrackers}" + callback.invoke( + ExtractorLink( + name ?: "", + title ?: name ?: "", + magnet, + "", + Qualities.Unknown.value + ) + ) + } } } From 5b5d6d9481af61cc33bc814ec83bb815b997e834 Mon Sep 17 00:00:00 2001 From: Cloudburst <18114966+C10udburst@users.noreply.github.com> Date: Tue, 1 Nov 2022 12:51:51 +0100 Subject: [PATCH 03/12] oops --- .../src/main/kotlin/com/lagradost/StremioProvider.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/StremioProvider/src/main/kotlin/com/lagradost/StremioProvider.kt b/StremioProvider/src/main/kotlin/com/lagradost/StremioProvider.kt index 9e7cc31..c47d8b3 100644 --- a/StremioProvider/src/main/kotlin/com/lagradost/StremioProvider.kt +++ b/StremioProvider/src/main/kotlin/com/lagradost/StremioProvider.kt @@ -224,7 +224,7 @@ class StremioProvider : MainAPI() { .map{it -> "&tr=$it"} .joinToString("") - val magnet = "magnet:?xt=urn:btih:${infoHash}${sourceTrackers}" + val magnet = "magnet:?xt=urn:btih:${infoHash}${sourceTrackers}${otherTrackers}" callback.invoke( ExtractorLink( name ?: "", From cdb34effb3ceab0081bbb71cbed8018033607df2 Mon Sep 17 00:00:00 2001 From: Blatzar <46196380+Blatzar@users.noreply.github.com> Date: Fri, 18 Nov 2022 00:16:20 +0100 Subject: [PATCH 04/12] Fix SuperStream timeout and Zoro --- SflixProvider/build.gradle.kts | 2 +- .../main/kotlin/com/lagradost/ZoroProvider.kt | 29 ++++++++++--------- SuperStream/build.gradle.kts | 2 +- .../main/kotlin/com/lagradost/SuperStream.kt | 3 +- 4 files changed, 19 insertions(+), 17 deletions(-) diff --git a/SflixProvider/build.gradle.kts b/SflixProvider/build.gradle.kts index 9e9f6d0..942db7d 100644 --- a/SflixProvider/build.gradle.kts +++ b/SflixProvider/build.gradle.kts @@ -1,5 +1,5 @@ // use an integer for version numbers -version = 9 +version = 10 cloudstream { diff --git a/SflixProvider/src/main/kotlin/com/lagradost/ZoroProvider.kt b/SflixProvider/src/main/kotlin/com/lagradost/ZoroProvider.kt index 83d35e1..963acf5 100644 --- a/SflixProvider/src/main/kotlin/com/lagradost/ZoroProvider.kt +++ b/SflixProvider/src/main/kotlin/com/lagradost/ZoroProvider.kt @@ -1,6 +1,7 @@ package com.lagradost import com.fasterxml.jackson.annotation.JsonProperty +import com.lagradost.SflixProvider.Companion.extractRabbitStream import com.lagradost.cloudstream3.* import com.lagradost.cloudstream3.LoadResponse.Companion.addAniListId import com.lagradost.cloudstream3.LoadResponse.Companion.addMalId @@ -345,21 +346,21 @@ class ZoroProvider : MainAPI() { val extractorLink = app.get( link, ).parsed().link -// val hasLoadedExtractorLink = + val hasLoadedExtractorLink = loadExtractor(extractorLink, "https://rapid-cloud.ru/", subtitleCallback, callback) -// if (!hasLoadedExtractorLink) { -// extractRabbitStream( -// extractorLink, -// subtitleCallback, -// // Blacklist VidCloud for now -// { videoLink -> if (!videoLink.url.contains("betterstream")) callback(videoLink) }, -//// false, -//// extractorData, -//// decryptKey = getKey() -// ) { sourceName -> -// sourceName + " - ${it.first}" -// } -// } + if (!hasLoadedExtractorLink) { + extractRabbitStream( + extractorLink, + subtitleCallback, + // Blacklist VidCloud for now + { videoLink -> if (!videoLink.url.contains("betterstream")) callback(videoLink) }, + false, + null, + decryptKey = getKey() + ) { sourceName -> + sourceName + " - ${it.first}" + } + } } return true diff --git a/SuperStream/build.gradle.kts b/SuperStream/build.gradle.kts index d388487..0e09b16 100644 --- a/SuperStream/build.gradle.kts +++ b/SuperStream/build.gradle.kts @@ -1,5 +1,5 @@ // use an integer for version numbers -version = 4 +version = 5 cloudstream { diff --git a/SuperStream/src/main/kotlin/com/lagradost/SuperStream.kt b/SuperStream/src/main/kotlin/com/lagradost/SuperStream.kt index 3885358..f18bb26 100644 --- a/SuperStream/src/main/kotlin/com/lagradost/SuperStream.kt +++ b/SuperStream/src/main/kotlin/com/lagradost/SuperStream.kt @@ -22,6 +22,7 @@ import javax.crypto.spec.SecretKeySpec import kotlin.math.roundToInt class SuperStream : MainAPI() { + private val timeout = 120L override var name = "SuperStream" override val hasMainPage = true override val hasChromecastSupport = true @@ -177,7 +178,7 @@ class SuperStream : MainAPI() { "medium" to "Website&token$token" ) - return app.post(apiUrl, headers = headers, data = data) + return app.post(apiUrl, headers = headers, data = data, timeout = timeout) } private suspend inline fun queryApiParsed(query: String): T { From 4d149a20f7100399bb6d8db1cd45e5b8fda55695 Mon Sep 17 00:00:00 2001 From: LagradOst <46196380+Blatzar@users.noreply.github.com> Date: Wed, 30 Nov 2022 19:05:30 +0000 Subject: [PATCH 05/12] Update build.gradle.kts --- Crunchyroll/build.gradle.kts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Crunchyroll/build.gradle.kts b/Crunchyroll/build.gradle.kts index 3be4f4e..83f90d7 100644 --- a/Crunchyroll/build.gradle.kts +++ b/Crunchyroll/build.gradle.kts @@ -16,7 +16,7 @@ cloudstream { * 2: Slow * 3: Beta only * */ - status = 1 // will be 3 if unspecified + status = 0 // will be 3 if unspecified tvTypes = listOf("AnimeMovie", "Anime", "OVA") iconUrl = "https://www.google.com/s2/favicons?domain=crunchyroll.com&sz=%size%" -} \ No newline at end of file +} From f1c06a7ffa3ceea4fe0286345f69bb4568b243d4 Mon Sep 17 00:00:00 2001 From: Blatzar <46196380+Blatzar@users.noreply.github.com> Date: Fri, 2 Dec 2022 01:07:16 +0100 Subject: [PATCH 06/12] Perhaps fix SuperStream searching --- SuperStream/build.gradle.kts | 2 +- .../main/kotlin/com/lagradost/SuperStream.kt | 18 +++++++++++++----- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/SuperStream/build.gradle.kts b/SuperStream/build.gradle.kts index 0e09b16..dbd9613 100644 --- a/SuperStream/build.gradle.kts +++ b/SuperStream/build.gradle.kts @@ -1,5 +1,5 @@ // use an integer for version numbers -version = 5 +version = 6 cloudstream { diff --git a/SuperStream/src/main/kotlin/com/lagradost/SuperStream.kt b/SuperStream/src/main/kotlin/com/lagradost/SuperStream.kt index f18bb26..0318bab 100644 --- a/SuperStream/src/main/kotlin/com/lagradost/SuperStream.kt +++ b/SuperStream/src/main/kotlin/com/lagradost/SuperStream.kt @@ -156,7 +156,7 @@ class SuperStream : MainAPI() { } } - private suspend fun queryApi(query: String): NiceResponse { + private suspend fun queryApi(query: String, useAlternativeApi: Boolean = false): NiceResponse { val encryptedQuery = CipherUtils.encrypt(query, key, iv)!! val appKeyHash = CipherUtils.md5(appKey)!! val newBody = @@ -178,11 +178,12 @@ class SuperStream : MainAPI() { "medium" to "Website&token$token" ) - return app.post(apiUrl, headers = headers, data = data, timeout = timeout) + val url = if (useAlternativeApi) secondApiUrl else apiUrl + return app.post(url, headers = headers, data = data, timeout = timeout) } - private suspend inline fun queryApiParsed(query: String): T { - return queryApi(query).parsed() + private suspend inline fun queryApiParsed(query: String, useAlternativeApi: Boolean = false): T { + return queryApi(query, useAlternativeApi).parsed() } private fun getExpiryDate(): Long { @@ -220,9 +221,16 @@ class SuperStream : MainAPI() { // Free Tibet, The Tienanmen Square protests of 1989 private val iv = base64Decode("d0VpcGhUbiE=") private val key = base64Decode("MTIzZDZjZWRmNjI2ZHk1NDIzM2FhMXc2") + private val ip = base64Decode("aHR0cHM6Ly8xNTIuMzIuMTQ5LjE2MA==") private val apiUrl = "$ip${base64Decode("L2FwaS9hcGlfY2xpZW50L2luZGV4Lw==")}" + + // Another url because the first one sucks at searching + // This one was revealed to me in a dream + private val secondApiUrl = + base64Decode("aHR0cHM6Ly9tYnBhcGkuc2hlZ3UubmV0L2FwaS9hcGlfY2xpZW50L2luZGV4Lw==") + private val appKey = base64Decode("bW92aWVib3g=") private val appId = base64Decode("Y29tLnRkby5zaG93Ym94") @@ -291,7 +299,7 @@ class SuperStream : MainAPI() { val apiQuery = // Originally 8 pagelimit """{"childmode":"$hideNsfw","app_version":"11.5","appid":"$appId","module":"Search3","channel":"Website","page":"1","lang":"en","type":"all","keyword":"$query","pagelimit":"20","expired_date":"${getExpiryDate()}","platform":"android"}""" - val searchResponse = parseJson(queryApi(apiQuery).text).data.mapNotNull { + val searchResponse = queryApiParsed(apiQuery, true).data.mapNotNull { it.toSearchResponse(this) } return searchResponse From caa4526f183d7927d4def7e2b613261fd9400b0c Mon Sep 17 00:00:00 2001 From: Osten <11805592+LagradOst@users.noreply.github.com> Date: Fri, 9 Dec 2022 19:07:35 +0000 Subject: [PATCH 07/12] Update AllAnimeProvider.kt --- .../kotlin/com/lagradost/AllAnimeProvider.kt | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/AllAnimeProvider/src/main/kotlin/com/lagradost/AllAnimeProvider.kt b/AllAnimeProvider/src/main/kotlin/com/lagradost/AllAnimeProvider.kt index ba53b31..cf23e73 100644 --- a/AllAnimeProvider/src/main/kotlin/com/lagradost/AllAnimeProvider.kt +++ b/AllAnimeProvider/src/main/kotlin/com/lagradost/AllAnimeProvider.kt @@ -3,6 +3,7 @@ package com.lagradost import com.fasterxml.jackson.annotation.JsonProperty import com.lagradost.cloudstream3.* import com.lagradost.cloudstream3.LoadResponse.Companion.addActors +import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer import com.lagradost.cloudstream3.mvvm.safeApiCall import com.lagradost.cloudstream3.ui.settings.SettingsProviders import com.lagradost.cloudstream3.utils.AppUtils.parseJson @@ -55,9 +56,14 @@ class AllAnimeProvider : MainAPI() { @JsonProperty("availableEpisodes") val availableEpisodes: AvailableEpisodes?, @JsonProperty("availableEpisodesDetail") val availableEpisodesDetail: AvailableEpisodesDetail?, @JsonProperty("studios") val studios: List?, + @JsonProperty("genres") val genres: List?, + @JsonProperty("averageScore") val averageScore: Int?, @JsonProperty("description") val description: String?, @JsonProperty("status") val status: String?, - ) + @JsonProperty("banner") val banner : String?, + @JsonProperty("episodeDuration") val episodeDuration : Int?, + @JsonProperty("prevideos") val prevideos : List = emptyList(), + ) private data class AvailableEpisodes( @JsonProperty("sub") val sub: Int, @@ -225,6 +231,7 @@ class AllAnimeProvider : MainAPI() { rhino.evaluateString(scope, js, "JavaScript", 1, null) val jsEval = scope.get("returnValue", scope) ?: return null + val showData = parseJson(jsEval as String) val title = showData.name @@ -256,7 +263,7 @@ class AllAnimeProvider : MainAPI() { Pair(Actor(name, img), role) } - // bruh, they use graphql + // bruh, they use graphql and bruh it is fucked //val recommendations = soup.select("#suggesction > div > div.p > .swipercard")?.mapNotNull { // val recTitle = it?.selectFirst(".showname > a") ?: return@mapNotNull null // val recName = recTitle.text() ?: return@mapNotNull null @@ -267,7 +274,12 @@ class AllAnimeProvider : MainAPI() { return newAnimeLoadResponse(title, url, TvType.Anime) { posterUrl = poster + backgroundPosterUrl = showData.banner + rating = showData.averageScore?.times(100) + tags = showData.genres year = showData.airedStart?.year + duration = showData.episodeDuration?.div(60_000) + addTrailer(showData.prevideos.filter { it.isNotBlank() }.map { "https://www.youtube.com/watch?v=$it" }) addEpisodes(DubStatus.Subbed, episodes.first) addEpisodes(DubStatus.Dubbed, episodes.second) From 8cb21079c5e303ceb9ccf490c823cbf373ada9f6 Mon Sep 17 00:00:00 2001 From: Osten <11805592+LagradOst@users.noreply.github.com> Date: Fri, 9 Dec 2022 19:07:59 +0000 Subject: [PATCH 08/12] Update PopularQuery.kt --- .../src/main/kotlin/com/lagradost/PopularQuery.kt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/AllAnimeProvider/src/main/kotlin/com/lagradost/PopularQuery.kt b/AllAnimeProvider/src/main/kotlin/com/lagradost/PopularQuery.kt index ed09992..4d1bb9f 100644 --- a/AllAnimeProvider/src/main/kotlin/com/lagradost/PopularQuery.kt +++ b/AllAnimeProvider/src/main/kotlin/com/lagradost/PopularQuery.kt @@ -65,4 +65,8 @@ data class QueryPopular( data class Data( @JsonProperty("queryPopular") val queryPopular: QueryPopular? = QueryPopular() -) \ No newline at end of file +) + +data class Data( + @JsonProperty("queryPopular") val queryPopular: QueryPopular? = QueryPopular() +) From 09d98d89964258c79ebc8e7711afdeed4287a806 Mon Sep 17 00:00:00 2001 From: Osten <11805592+LagradOst@users.noreply.github.com> Date: Fri, 9 Dec 2022 19:09:15 +0000 Subject: [PATCH 09/12] Update PopularQuery.kt --- .../src/main/kotlin/com/lagradost/PopularQuery.kt | 4 ---- 1 file changed, 4 deletions(-) diff --git a/AllAnimeProvider/src/main/kotlin/com/lagradost/PopularQuery.kt b/AllAnimeProvider/src/main/kotlin/com/lagradost/PopularQuery.kt index 4d1bb9f..add1ac9 100644 --- a/AllAnimeProvider/src/main/kotlin/com/lagradost/PopularQuery.kt +++ b/AllAnimeProvider/src/main/kotlin/com/lagradost/PopularQuery.kt @@ -66,7 +66,3 @@ data class QueryPopular( data class Data( @JsonProperty("queryPopular") val queryPopular: QueryPopular? = QueryPopular() ) - -data class Data( - @JsonProperty("queryPopular") val queryPopular: QueryPopular? = QueryPopular() -) From f491cd5d275f9e5f532750cc1324912945e56205 Mon Sep 17 00:00:00 2001 From: Blatzar <46196380+Blatzar@users.noreply.github.com> Date: Tue, 13 Dec 2022 23:39:30 +0100 Subject: [PATCH 10/12] Switched more api calls to lessen the strain on the link generating server --- SuperStream/build.gradle.kts | 2 +- .../main/kotlin/com/lagradost/SuperStream.kt | 65 +++++++++++++++---- build.gradle.kts | 2 +- 3 files changed, 53 insertions(+), 16 deletions(-) diff --git a/SuperStream/build.gradle.kts b/SuperStream/build.gradle.kts index dbd9613..2880eb4 100644 --- a/SuperStream/build.gradle.kts +++ b/SuperStream/build.gradle.kts @@ -1,5 +1,5 @@ // use an integer for version numbers -version = 6 +version = 7 cloudstream { diff --git a/SuperStream/src/main/kotlin/com/lagradost/SuperStream.kt b/SuperStream/src/main/kotlin/com/lagradost/SuperStream.kt index 0318bab..2a5b80f 100644 --- a/SuperStream/src/main/kotlin/com/lagradost/SuperStream.kt +++ b/SuperStream/src/main/kotlin/com/lagradost/SuperStream.kt @@ -17,6 +17,8 @@ import java.nio.charset.StandardCharsets import java.security.MessageDigest import java.security.NoSuchAlgorithmException import javax.crypto.Cipher +import javax.crypto.Cipher.DECRYPT_MODE +import javax.crypto.Cipher.ENCRYPT_MODE import javax.crypto.spec.IvParameterSpec import javax.crypto.spec.SecretKeySpec import kotlin.math.roundToInt @@ -79,7 +81,7 @@ class SuperStream : MainAPI() { length++ } cipher.init( - 1, + ENCRYPT_MODE, SecretKeySpec(bArr, ALGORITHM), IvParameterSpec(iv.toByteArray()) ) @@ -91,6 +93,31 @@ class SuperStream : MainAPI() { } } + // Useful for deobfuscation + fun decrypt(str: String, key: String, iv: String): String? { + return try { + val cipher: Cipher = Cipher.getInstance(TRANSFORMATION) + val bArr = ByteArray(24) + val bytes: ByteArray = key.toByteArray() + var length = if (bytes.size <= 24) bytes.size else 24 + System.arraycopy(bytes, 0, bArr, 0, length) + while (length < 24) { + bArr[length] = 0 + length++ + } + cipher.init( + DECRYPT_MODE, + SecretKeySpec(bArr, ALGORITHM), + IvParameterSpec(iv.toByteArray()) + ) + val inputStr = Base64.decode(str.toByteArray(), Base64.DEFAULT) + cipher.doFinal(inputStr).decodeToString() + } catch (e: Exception) { + e.printStackTrace() + null + } + } + fun md5(str: String): String? { return MD5Util.md5(str)?.let { HexDump.toHexString(it).lowercase() } } @@ -156,7 +183,7 @@ class SuperStream : MainAPI() { } } - private suspend fun queryApi(query: String, useAlternativeApi: Boolean = false): NiceResponse { + private suspend fun queryApi(query: String, useAlternativeApi: Boolean): NiceResponse { val encryptedQuery = CipherUtils.encrypt(query, key, iv)!! val appKeyHash = CipherUtils.md5(appKey)!! val newBody = @@ -173,7 +200,7 @@ class SuperStream : MainAPI() { "data" to base64Body, "appid" to "27", "platform" to "android", - "version" to "129", + "version" to appVersionCode, // Probably best to randomize this "medium" to "Website&token$token" ) @@ -182,7 +209,10 @@ class SuperStream : MainAPI() { return app.post(url, headers = headers, data = data, timeout = timeout) } - private suspend inline fun queryApiParsed(query: String, useAlternativeApi: Boolean = false): T { + private suspend inline fun queryApiParsed( + query: String, + useAlternativeApi: Boolean = true + ): T { return queryApi(query, useAlternativeApi).parsed() } @@ -233,16 +263,19 @@ class SuperStream : MainAPI() { private val appKey = base64Decode("bW92aWVib3g=") private val appId = base64Decode("Y29tLnRkby5zaG93Ym94") + private val appIdSecond = base64Decode("Y29tLm1vdmllYm94cHJvLmFuZHJvaWQ=") + private val appVersion = "14.7" + private val appVersionCode = "160" override suspend fun getMainPage(page: Int, request: MainPageRequest): HomePageResponse { val hideNsfw = if (settingsForProvider.enableAdult) 0 else 1 - val json = queryApi( - """{"childmode":"$hideNsfw","app_version":"11.5","appid":"$appId","module":"Home_list_type_v2","channel":"Website","page":"$page","lang":"en","type":"all","pagelimit":"10","expired_date":"${getExpiryDate()}","platform":"android"} + val data = queryApiParsed( + """{"childmode":"$hideNsfw","app_version":"$appVersion","appid":"$appIdSecond","module":"Home_list_type_v5","channel":"Website","page":"$page","lang":"en","type":"all","pagelimit":"10","expired_date":"${getExpiryDate()}","platform":"android"} """.trimIndent() - ).text + ) // Cut off the first row (featured) - val pages = parseJson(json).data.let { it.subList(minOf(it.size, 1), it.size) } + val pages = data.data.let { it.subList(minOf(it.size, 1), it.size) } .mapNotNull { var name = it.name if (name.isNullOrEmpty()) name = "Featured" @@ -279,7 +312,10 @@ class SuperStream : MainAPI() { fun toSearchResponse(api: MainAPI): MovieSearchResponse? { return api.newMovieSearchResponse( this.title ?: "", - LoadData(this.id ?: this.mid ?: return null, this.boxType ?: ResponseTypes.Movies.value).toJson(), + LoadData( + this.id ?: this.mid ?: return null, + this.boxType ?: ResponseTypes.Movies.value + ).toJson(), ResponseTypes.getResponseType(this.boxType).toTvType(), false ) { @@ -298,7 +334,7 @@ class SuperStream : MainAPI() { val hideNsfw = if (settingsForProvider.enableAdult) 0 else 1 val apiQuery = // Originally 8 pagelimit - """{"childmode":"$hideNsfw","app_version":"11.5","appid":"$appId","module":"Search3","channel":"Website","page":"1","lang":"en","type":"all","keyword":"$query","pagelimit":"20","expired_date":"${getExpiryDate()}","platform":"android"}""" + """{"childmode":"$hideNsfw","app_version":"$appVersion","appid":"$appIdSecond","module":"Search3","channel":"Website","page":"1","lang":"en","type":"all","keyword":"$query","pagelimit":"20","expired_date":"${getExpiryDate()}","platform":"android"}""" val searchResponse = queryApiParsed(apiQuery, true).data.mapNotNull { it.toSearchResponse(this) } @@ -480,7 +516,7 @@ class SuperStream : MainAPI() { val hideNsfw = if (settingsForProvider.enableAdult) 0 else 1 if (isMovie) { // 1 = Movie val apiQuery = - """{"childmode":"$hideNsfw","uid":"","app_version":"11.5","appid":"$appId","module":"Movie_detail","channel":"Website","mid":"${loadData.id}","lang":"en","expired_date":"${getExpiryDate()}","platform":"android","oss":"","group":""}""" + """{"childmode":"$hideNsfw","uid":"","app_version":"$appVersion","appid":"$appIdSecond","module":"Movie_detail","channel":"Website","mid":"${loadData.id}","lang":"en","expired_date":"${getExpiryDate()}","platform":"android","oss":"","group":""}""" val data = (queryApiParsed(apiQuery)).data ?: throw RuntimeException("API error") @@ -507,13 +543,13 @@ class SuperStream : MainAPI() { } } else { // 2 Series val apiQuery = - """{"childmode":"$hideNsfw","uid":"","app_version":"11.5","appid":"$appId","module":"TV_detail_1","display_all":"1","channel":"Website","lang":"en","expired_date":"${getExpiryDate()}","platform":"android","tid":"${loadData.id}"}""" + """{"childmode":"$hideNsfw","uid":"","app_version":"$appVersion","appid":"$appIdSecond","module":"TV_detail_1","display_all":"1","channel":"Website","lang":"en","expired_date":"${getExpiryDate()}","platform":"android","tid":"${loadData.id}"}""" val data = (queryApiParsed(apiQuery)).data ?: throw RuntimeException("API error") val episodes = data.season.mapNotNull { val seasonQuery = - """{"childmode":"$hideNsfw","app_version":"11.5","year":"0","appid":"$appId","module":"TV_episode","display_all":"1","channel":"Website","season":"$it","lang":"en","expired_date":"${getExpiryDate()}","platform":"android","tid":"${loadData.id}"}""" + """{"childmode":"$hideNsfw","app_version":"$appVersion","year":"0","appid":"$appIdSecond","module":"TV_episode","display_all":"1","channel":"Website","season":"$it","lang":"en","expired_date":"${getExpiryDate()}","platform":"android","tid":"${loadData.id}"}""" (queryApiParsed(seasonQuery)).data }.flatten() @@ -655,6 +691,7 @@ class SuperStream : MainAPI() { val parsed = parseJson(data) // No childmode when getting links + // New api does not return video links :( val query = if (parsed.type == ResponseTypes.Movies.value) { """{"childmode":"0","uid":"","app_version":"11.5","appid":"$appId","module":"Movie_downloadurl_v3","channel":"Website","mid":"${parsed.id}","lang":"","expired_date":"${getExpiryDate()}","platform":"android","oss":"1","group":""}""" } else { @@ -663,7 +700,7 @@ class SuperStream : MainAPI() { """{"childmode":"0","app_version":"11.5","module":"TV_downloadurl_v3","channel":"Website","episode":"$episode","expired_date":"${getExpiryDate()}","platform":"android","tid":"${parsed.id}","oss":"1","uid":"","appid":"$appId","season":"$season","lang":"en","group":""}""" } - val linkData = queryApiParsed(query) + val linkData = queryApiParsed(query, false) linkData.data?.list?.forEach { callback.invoke(it.toExtractorLink() ?: return@forEach) } diff --git a/build.gradle.kts b/build.gradle.kts index 7d6e19e..31f6e88 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -80,7 +80,7 @@ subprojects { implementation("com.github.Blatzar:NiceHttp:0.3.2") // http library implementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.13.1") implementation("org.jsoup:jsoup:1.13.1") // html parser - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4") // html parser + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4") // delay() //run JS implementation("org.mozilla:rhino:1.7.14") From ad526142b9e488cfa4575b4848e19e6411fbc835 Mon Sep 17 00:00:00 2001 From: Cloudburst <18114966+C10udburst@users.noreply.github.com> Date: Sun, 18 Dec 2022 11:20:05 +0100 Subject: [PATCH 11/12] update superembed --- .../kotlin/com/lagradost/CaptchaSolver.kt | 36 ++++++++++++ .../com/lagradost/SuperembedProvider.kt | 58 ++++++++----------- 2 files changed, 60 insertions(+), 34 deletions(-) create mode 100644 SuperembedProvider/src/main/kotlin/com/lagradost/CaptchaSolver.kt diff --git a/SuperembedProvider/src/main/kotlin/com/lagradost/CaptchaSolver.kt b/SuperembedProvider/src/main/kotlin/com/lagradost/CaptchaSolver.kt new file mode 100644 index 0000000..6f81b17 --- /dev/null +++ b/SuperembedProvider/src/main/kotlin/com/lagradost/CaptchaSolver.kt @@ -0,0 +1,36 @@ +package com.lagradost + +import com.lagradost.cloudstream3.* +import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson +import com.lagradost.cloudstream3.utils.AppUtils.toJson +import kotlinx.coroutines.delay +import org.json.JSONArray +import org.json.JSONObject +import android.util.Log + +public object CaptchaSolver { + suspend fun predictFace(url: String): String? { + val img = "data:image/jpeg;base64," + base64Encode(app.get(url).body.bytes()) + val reqData = HFRequest(listOf(img)).toJson() + val res = app.post("https://yuqi-gender-classifier.hf.space/api/queue/push/", json = reqData).text + val request = tryParseJson(res) + for (i in 1..5) { + delay(500L) + val document = app.post("https://yuqi-gender-classifier.hf.space/api/queue/status/", json=request?.toJson()).text + val status = tryParseJson(document) + if (status?.get("status") != "COMPLETE") continue + return (((status.get("data") as? JSONObject?) + ?.get("data") as? JSONArray?) + ?.get(0) as? JSONObject?) + ?.get("label") as String? + } + return null + } + + private data class HFRequest( + val data: List, + val action: String = "predict", + val fn_index: Int = 0, + val session_hash: String = "aaaaaaaaaaa" + ) +} \ No newline at end of file diff --git a/SuperembedProvider/src/main/kotlin/com/lagradost/SuperembedProvider.kt b/SuperembedProvider/src/main/kotlin/com/lagradost/SuperembedProvider.kt index 8b3936f..ae084a4 100644 --- a/SuperembedProvider/src/main/kotlin/com/lagradost/SuperembedProvider.kt +++ b/SuperembedProvider/src/main/kotlin/com/lagradost/SuperembedProvider.kt @@ -6,9 +6,8 @@ import com.lagradost.cloudstream3.metaproviders.TmdbProvider import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson import com.lagradost.cloudstream3.utils.ExtractorLink import com.lagradost.cloudstream3.utils.loadExtractor -import kotlinx.coroutines.delay -import org.json.JSONArray -import org.json.JSONObject +import okhttp3.FormBody +import android.util.Log class SuperembedProvider : TmdbProvider() { override var mainUrl = "https://seapi.link" @@ -54,40 +53,31 @@ class SuperembedProvider : TmdbProvider() { val url: String ) { suspend fun getIframeContents(): String? { - val document = app.get(url) + var document = app.get(url) + for (i in 1..5) { + if ("captcha-message" in document.text) { + val soup = document.document + val prompt = soup.selectFirst(".captcha-message")?.text() ?: continue + val captchaId = soup.selectFirst("input[name=\"captcha_id\"]")?.attr("value") ?: continue + val promptGender = if ("female" in prompt) "female" else "male" + val checkboxes = soup.select(".captcha-checkbox").mapNotNull { it -> + val img = it.selectFirst("img")?.attr("src") ?: return@mapNotNull null + val gender = CaptchaSolver.predictFace("https://streamembed.net${img}") ?: return@mapNotNull null + if (gender != promptGender) return@mapNotNull null + return@mapNotNull it.selectFirst("input")?.attr("value") + } + val formData = FormBody.Builder().apply { + add("captcha_id", captchaId) + checkboxes.forEach { check -> + add("captcha_answer[]", check) + } + }.build() + document = app.post(url, requestBody=formData) + } else { break } + } val regex = "(res) - for (i in 1..5) { - delay(500L) - val document = app.post("https://hf.space/embed/njgroene/age-gender-profilepic/api/queue/status/", json=request).text - val status = tryParseJson(document) - if (status?.get("status") != "COMPLETE") continue - val pred = (((status.get("data") as? JSONObject?) - ?.get("data") as? JSONArray?) - ?.get(0) as? String?) ?: return null - return if ("Male" in pred) Gender.Male - else if ("Female" in pred) Gender.Female - else null - } - } - - private data class HFRequest( - val data: List, - val action: String = "predict", - val fn_index: Int = 0, - val session_hash: String = "aaaaaaaaaaa" - ) - }*/ } From b15b792576bf98f551489ccd5e8ace53b707cc19 Mon Sep 17 00:00:00 2001 From: Marouane <57333995+riimuru@users.noreply.github.com> Date: Sun, 18 Dec 2022 05:26:40 -0500 Subject: [PATCH 12/12] fix sflix (#30) Co-authored-by: Cloudburst <18114966+C10udburst@users.noreply.github.com> --- SflixProvider/build.gradle.kts | 4 ++-- .../src/main/kotlin/com/lagradost/SflixProvider.kt | 7 ++----- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/SflixProvider/build.gradle.kts b/SflixProvider/build.gradle.kts index 942db7d..37cb297 100644 --- a/SflixProvider/build.gradle.kts +++ b/SflixProvider/build.gradle.kts @@ -1,5 +1,5 @@ // use an integer for version numbers -version = 10 +version = 11 cloudstream { @@ -25,4 +25,4 @@ cloudstream { ) iconUrl = "https://www.google.com/s2/favicons?domain=www.2embed.to&sz=%size%" -} \ No newline at end of file +} diff --git a/SflixProvider/src/main/kotlin/com/lagradost/SflixProvider.kt b/SflixProvider/src/main/kotlin/com/lagradost/SflixProvider.kt index 0c14c67..e998ab6 100644 --- a/SflixProvider/src/main/kotlin/com/lagradost/SflixProvider.kt +++ b/SflixProvider/src/main/kotlin/com/lagradost/SflixProvider.kt @@ -458,11 +458,8 @@ open class SflixProvider : MainAPI() { } suspend fun getKey(): String? { - data class KeyObject( - @JsonProperty("key") val key: String? = null - ) - return app.get("https://raw.githubusercontent.com/BlipBlob/blabflow/main/keys.json") - .parsed().key + return app.get("https://raw.githubusercontent.com/consumet/rapidclown/rabbitstream/key.txt") + .text } /**