forked from recloudstream/cloudstream
		
	cracked encryption and added more servers on AsianLoad, DramaSee and WatchAsian
This commit is contained in:
		
							parent
							
								
									fbfcde0295
								
							
						
					
					
						commit
						5a00637768
					
				
					 6 changed files with 209 additions and 129 deletions
				
			
		|  | @ -2,9 +2,10 @@ package com.lagradost.cloudstream3.animeproviders | |||
| 
 | ||||
| import com.fasterxml.jackson.annotation.JsonProperty | ||||
| import com.lagradost.cloudstream3.* | ||||
| import com.lagradost.cloudstream3.mvvm.safeApiCall | ||||
| import com.lagradost.cloudstream3.utils.* | ||||
| import okio.ByteString.Companion.decodeHex | ||||
| import org.jsoup.Jsoup | ||||
| import java.net.URI | ||||
| import java.util.* | ||||
| import javax.crypto.Cipher | ||||
| import javax.crypto.spec.IvParameterSpec | ||||
|  | @ -47,7 +48,6 @@ class GogoanimeProvider : MainAPI() { | |||
|                 base64Encode(cipher.doFinal(string.toByteArray())) | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|         private fun String.decodeHex(): ByteArray { | ||||
|             check(length % 2 == 0) { "Must have an even length" } | ||||
|  | @ -56,6 +56,106 @@ class GogoanimeProvider : MainAPI() { | |||
|                 .toByteArray() | ||||
|         } | ||||
| 
 | ||||
|         /** | ||||
|          * @param iframeUrl something like https://gogoplay4.com/streaming.php?id=XXXXXX | ||||
|          * @param mainApiName used for ExtractorLink names and source | ||||
|          * @param iv secret iv from site, required non-null | ||||
|          * @param secretKey secret key for decryption from site, required non-null | ||||
|          * */ | ||||
|         suspend fun extractVidstream( | ||||
|             iframeUrl: String, | ||||
|             mainApiName: String, | ||||
|             callback: (ExtractorLink) -> Unit, | ||||
|             iv: ByteArray?, | ||||
|             secretKey: ByteArray? | ||||
|         ) = safeApiCall { | ||||
|             // https://github.com/saikou-app/saikou/blob/3e756bd8e876ad7a9318b17110526880525a5cd3/app/src/main/java/ani/saikou/anime/source/extractors/GogoCDN.kt | ||||
|             // No Licence on the following code | ||||
|             // Also modified of https://github.com/jmir1/aniyomi-extensions/blob/master/src/en/gogoanime/src/eu/kanade/tachiyomi/animeextension/en/gogoanime/extractors/GogoCdnExtractor.kt | ||||
|             // License on the code above  https://github.com/jmir1/aniyomi-extensions/blob/master/LICENSE | ||||
| 
 | ||||
|             if (iv == null || secretKey == null) | ||||
|                 return@safeApiCall | ||||
| 
 | ||||
|             val uri = URI(iframeUrl) | ||||
|             val mainUrl = "https://" + uri.host | ||||
| 
 | ||||
|             val id = Regex("id=([^&]+)").find(iframeUrl)!!.value.removePrefix("id=") | ||||
|             val encryptedId = cryptoHandler(id, iv, secretKey) | ||||
|             val jsonResponse = | ||||
|                 app.get( | ||||
|                     "$mainUrl/encrypt-ajax.php?id=$encryptedId", | ||||
|                     headers = mapOf("X-Requested-With" to "XMLHttpRequest") | ||||
|                 ) | ||||
|             val dataencrypted = | ||||
|                 jsonResponse.text.substringAfter("{\"data\":\"").substringBefore("\"}") | ||||
|             val datadecrypted = cryptoHandler(dataencrypted, iv, secretKey, false) | ||||
|             val sources = AppUtils.parseJson<GogoSources>(datadecrypted) | ||||
|             println("GET SOURCES $sources $iframeUrl") | ||||
| 
 | ||||
|             fun invokeGogoSource( | ||||
|                 source: GogoSource, | ||||
|                 sourceCallback: (ExtractorLink) -> Unit | ||||
|             ) { | ||||
|                 when { | ||||
|                     source.file.contains("m3u8") -> { | ||||
|                         M3u8Helper().m3u8Generation( | ||||
|                             M3u8Helper.M3u8Stream( | ||||
|                                 source.file, | ||||
|                                 headers = mapOf("Referer" to "https://gogoplay4.com") | ||||
|                             ), true | ||||
|                         ) | ||||
|                             .map { stream -> | ||||
|                                 val qualityString = | ||||
|                                     if ((stream.quality ?: 0) == 0) "" else "${stream.quality}p" | ||||
|                                 sourceCallback( | ||||
|                                     ExtractorLink( | ||||
|                                         mainApiName, | ||||
|                                         "$mainApiName $qualityString", | ||||
|                                         stream.streamUrl, | ||||
|                                         mainUrl, | ||||
|                                         getQualityFromName(stream.quality.toString()), | ||||
|                                         true | ||||
|                                     ) | ||||
|                                 ) | ||||
|                             } | ||||
|                     } | ||||
|                     source.file.contains("vidstreaming") -> { | ||||
|                         sourceCallback.invoke( | ||||
|                             ExtractorLink( | ||||
|                                 mainApiName, | ||||
|                                 "$mainApiName ${source.label?.replace("0 P", "0p") ?: ""}", | ||||
|                                 source.file, | ||||
|                                 mainUrl, | ||||
|                                 getQualityFromName(source.label ?: ""), | ||||
|                                 isM3u8 = source.type == "hls" | ||||
|                             ) | ||||
|                         ) | ||||
|                     } | ||||
|                     else -> { | ||||
|                         sourceCallback.invoke( | ||||
|                             ExtractorLink( | ||||
|                                 mainApiName, | ||||
|                                 "$mainApiName ${source.label?.replace("0 P", "0p") ?: ""}", | ||||
|                                 source.file, | ||||
|                                 mainUrl, | ||||
|                                 getQualityFromName(source.label ?: ""), | ||||
|                                 isM3u8 = source.type == "hls" | ||||
|                             ) | ||||
|                         ) | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             sources.source?.forEach { | ||||
|                 invokeGogoSource(it, callback) | ||||
|             } | ||||
|             sources.sourceBk?.forEach { | ||||
|                 invokeGogoSource(it, callback) | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     override val mainUrl = "https://gogoanime.film" | ||||
|     override val name = "GogoAnime" | ||||
|     override val hasQuickSearch = false | ||||
|  | @ -281,67 +381,10 @@ class GogoanimeProvider : MainAPI() { | |||
|                             loadExtractor(data, streamingResponse.url, callback) | ||||
|                         } | ||||
|                 }, { | ||||
|                     // https://github.com/saikou-app/saikou/blob/3e756bd8e876ad7a9318b17110526880525a5cd3/app/src/main/java/ani/saikou/anime/source/extractors/GogoCDN.kt | ||||
|                     // No Licence on the following code | ||||
|                     // Also modified of https://github.com/jmir1/aniyomi-extensions/blob/master/src/en/gogoanime/src/eu/kanade/tachiyomi/animeextension/en/gogoanime/extractors/GogoCdnExtractor.kt | ||||
|                     // License on the code above  https://github.com/jmir1/aniyomi-extensions/blob/master/LICENSE | ||||
| 
 | ||||
|                     val iv = "31323835363732333833393339383532".decodeHex() | ||||
|                     val secretKey = "3235373136353338353232393338333936313634363632323738383333323838".decodeHex() | ||||
| 
 | ||||
|                     val id = Regex("id=([^&]+)").find(iframe)!!.value.removePrefix("id=") | ||||
|                     val encryptedId = cryptoHandler(id, iv, secretKey) | ||||
|                     val jsonResponse = | ||||
|                         app.get( | ||||
|                             "http://gogoplay4.com/encrypt-ajax.php?id=$encryptedId&time=00000000000000000000", | ||||
|                             headers = mapOf("X-Requested-With" to "XMLHttpRequest") | ||||
|                         ) | ||||
|                     val dataencrypted = jsonResponse.text.substringAfter("{\"data\":\"").substringBefore("\"}") | ||||
|                     val datadecrypted = cryptoHandler(dataencrypted, iv, secretKey, false) | ||||
|                     val sources = AppUtils.parseJson<GogoSources>(datadecrypted) | ||||
| 
 | ||||
|                     fun invokeGogoSource( | ||||
|                         source: GogoSource, | ||||
|                         sourceCallback: (ExtractorLink) -> Unit | ||||
|                     ) { | ||||
|                         if (source.file.contains("m3u8")) { | ||||
|                             M3u8Helper().m3u8Generation( | ||||
|                                 M3u8Helper.M3u8Stream( | ||||
|                                     source.file, | ||||
|                                     headers = mapOf("Referer" to "https://gogoplay4.com") | ||||
|                                 ), true | ||||
|                             ) | ||||
|                                 .map { stream -> | ||||
|                                     val qualityString = if ((stream.quality ?: 0) == 0) "" else "${stream.quality}p" | ||||
|                                     sourceCallback(  ExtractorLink( | ||||
|                                         name, | ||||
|                                         "$name $qualityString", | ||||
|                                         stream.streamUrl, | ||||
|                                         "https://gogoplay4.com", | ||||
|                                         getQualityFromName(stream.quality.toString()), | ||||
|                                         true | ||||
|                                     )) | ||||
|                                 } | ||||
|                         } else if (source.file.contains("vidstreaming")) { | ||||
|                             sourceCallback.invoke( | ||||
|                                 ExtractorLink( | ||||
|                                     this.name, | ||||
|                                     "${this.name} ${source.label?.replace("0 P", "0p") ?: ""}", | ||||
|                                     source.file, | ||||
|                                     "https://gogoplay4.com", | ||||
|                                     getQualityFromName(source.label ?: ""), | ||||
|                                     isM3u8 = source.type == "hls" | ||||
|                                 ) | ||||
|                             ) | ||||
|                         } | ||||
|                     } | ||||
| 
 | ||||
|                     sources.source?.forEach { | ||||
|                         invokeGogoSource(it, callback) | ||||
|                     } | ||||
|                     sources.sourceBk?.forEach { | ||||
|                         invokeGogoSource(it, callback) | ||||
|                     } | ||||
|                     val secretKey = | ||||
|                         "3235373136353338353232393338333936313634363632323738383333323838".decodeHex() | ||||
|                     extractVidstream(iframe, this.name, callback, iv, secretKey) | ||||
|                 }) | ||||
|             } | ||||
|         ) | ||||
|  |  | |||
|  | @ -32,7 +32,6 @@ class Vidstream(val mainUrl: String) { | |||
|         isCasting: Boolean = false, | ||||
|         callback: (ExtractorLink) -> Unit | ||||
|     ): Boolean { | ||||
|         println("VIDSTREAM:: $id") | ||||
|         val extractorUrl = getExtractorUrl(id) | ||||
|         argamap( | ||||
|             { | ||||
|  |  | |||
|  | @ -17,5 +17,8 @@ class AsianLoadProvider : VidstreamProviderTemplate() { | |||
|         "$mainUrl/ongoing-series" | ||||
|     ) | ||||
| 
 | ||||
|     override val iv = "9262859232435825".toByteArray() | ||||
|     override val secretKey = "93422192433952489752342908585752".toByteArray() | ||||
| 
 | ||||
|     override val supportedTypes = setOf(TvType.TvSeries, TvType.Movie) | ||||
| } | ||||
|  |  | |||
|  | @ -2,6 +2,7 @@ package com.lagradost.cloudstream3.movieproviders | |||
| 
 | ||||
| import com.fasterxml.jackson.module.kotlin.readValue | ||||
| import com.lagradost.cloudstream3.* | ||||
| import com.lagradost.cloudstream3.animeproviders.GogoanimeProvider.Companion.extractVidstream | ||||
| import com.lagradost.cloudstream3.extractors.* | ||||
| import com.lagradost.cloudstream3.extractors.helper.AsianEmbedHelper | ||||
| import com.lagradost.cloudstream3.utils.AppUtils.toJson | ||||
|  | @ -22,7 +23,8 @@ class DramaSeeProvider : MainAPI() { | |||
|         val document = app.get(mainUrl, headers = headers).document | ||||
|         val mainbody = document.getElementsByTag("body") | ||||
| 
 | ||||
|         return HomePageResponse(mainbody?.select("section")?.map { row -> | ||||
|         return HomePageResponse( | ||||
|             mainbody?.select("section")?.map { row -> | ||||
|                 val main = row?.select("main") ?: return@map null | ||||
|                 val title = main.select("div.title > div > h2")?.text() ?: "Main" | ||||
|                 val inner = main.select("li.series-item") ?: return@map null | ||||
|  | @ -88,12 +90,17 @@ class DramaSeeProvider : MainAPI() { | |||
|         val poster = fixUrlNull(inner?.select("div.img > img")?.attr("src")) ?: "" | ||||
|         //Log.i(this.name, "Result => (imgLinkCode) ${imgLinkCode}") | ||||
|         val title = inner?.select("h1.series-name")?.text() ?: "" | ||||
|         val year = if (title.length > 5) { title.substring(title.length - 5) | ||||
|             .trim().trimEnd(')').toIntOrNull() } else { null } | ||||
|         val year = if (title.length > 5) { | ||||
|             title.substring(title.length - 5) | ||||
|                 .trim().trimEnd(')').toIntOrNull() | ||||
|         } else { | ||||
|             null | ||||
|         } | ||||
|         //Log.i(this.name, "Result => (year) ${title.substring(title.length - 5)}") | ||||
|         val seriesBody = body?.select("div.series-body") | ||||
|         val descript = seriesBody?.firstOrNull()?.select("div.js-content")?.text() | ||||
|         val tags = seriesBody?.select("div.series-tags > a")?.mapNotNull { it?.text()?.trim() ?: return@mapNotNull null } | ||||
|         val tags = seriesBody?.select("div.series-tags > a") | ||||
|             ?.mapNotNull { it?.text()?.trim() ?: return@mapNotNull null } | ||||
|         val recs = body?.select("ul.series > li")?.mapNotNull { | ||||
|             val a = it.select("a.series-img") ?: return@mapNotNull null | ||||
|             val aUrl = fixUrlNull(a.attr("href")) ?: return@mapNotNull null | ||||
|  | @ -190,6 +197,9 @@ class DramaSeeProvider : MainAPI() { | |||
|                 //Log.i(this.name, "Result => (url) ${url}") | ||||
|                 when { | ||||
|                     url.startsWith("https://asianembed.io") || url.startsWith("https://asianload.io") -> { | ||||
|                         val iv = "9262859232435825".toByteArray() | ||||
|                         val secretKey = "93422192433952489752342908585752".toByteArray() | ||||
|                         extractVidstream(url, this.name, callback, iv, secretKey) | ||||
|                         AsianEmbedHelper.getUrls(url, callback) | ||||
|                     } | ||||
|                     url.startsWith("https://embedsito.com") -> { | ||||
|  |  | |||
|  | @ -1,6 +1,7 @@ | |||
| package com.lagradost.cloudstream3.movieproviders | ||||
| 
 | ||||
| import com.lagradost.cloudstream3.* | ||||
| import com.lagradost.cloudstream3.animeproviders.GogoanimeProvider.Companion.extractVidstream | ||||
| import com.lagradost.cloudstream3.extractors.Vidstream | ||||
| import com.lagradost.cloudstream3.utils.ExtractorLink | ||||
| import com.lagradost.cloudstream3.utils.getQualityFromName | ||||
|  | @ -14,6 +15,14 @@ open class VidstreamProviderTemplate : MainAPI() { | |||
|     open val homePageUrlList = listOf<String>() | ||||
|     open val vidstreamExtractorUrl: String? = null | ||||
| 
 | ||||
|     /** | ||||
|      *  Used to generate encrypted video links. | ||||
|      *  Try keys from other providers before cracking | ||||
|      *  one yourself. | ||||
|      * */ | ||||
|     open val iv: ByteArray? = null | ||||
|     open val secretKey: ByteArray? = null | ||||
| 
 | ||||
| //    // mainUrl is good to have as a holder for the url to make future changes easier. | ||||
| //    override val mainUrl: String | ||||
| //        get() = "https://vidembed.cc" | ||||
|  | @ -212,6 +221,7 @@ open class VidstreamProviderTemplate : MainAPI() { | |||
|         val iframeLink = | ||||
|             Jsoup.parse(app.get(data).text).selectFirst("iframe")?.attr("src") ?: return false | ||||
| 
 | ||||
|         extractVidstream(iframeLink, this.name, callback, iv, secretKey) | ||||
|         // In this case the video player is a vidstream clone and can be handled by the vidstream extractor. | ||||
|         // This case is a both unorthodox and you normally do not call extractors as they detect the url returned and does the rest. | ||||
|         val vidstreamObject = Vidstream(vidstreamExtractorUrl ?: mainUrl) | ||||
|  |  | |||
|  | @ -2,6 +2,7 @@ package com.lagradost.cloudstream3.movieproviders | |||
| 
 | ||||
| import com.fasterxml.jackson.module.kotlin.readValue | ||||
| import com.lagradost.cloudstream3.* | ||||
| import com.lagradost.cloudstream3.animeproviders.GogoanimeProvider.Companion.extractVidstream | ||||
| import com.lagradost.cloudstream3.extractors.XStreamCdn | ||||
| import com.lagradost.cloudstream3.extractors.helper.AsianEmbedHelper | ||||
| import com.lagradost.cloudstream3.utils.AppUtils.toJson | ||||
|  | @ -36,7 +37,8 @@ class WatchAsianProvider : MainAPI() { | |||
|         return HomePageResponse( | ||||
|             rowPair.mapNotNull { row -> | ||||
|                 val main = (doc.select("div.tab-content.${row.second}") | ||||
|                 ?: doc.select("div.tab-content.${row.second}.selected")) ?: return@mapNotNull null | ||||
|                     ?: doc.select("div.tab-content.${row.second}.selected")) | ||||
|                     ?: return@mapNotNull null | ||||
| 
 | ||||
|                 val title = row.first | ||||
|                 val inner = main.select("li") ?: return@mapNotNull null | ||||
|  | @ -48,8 +50,10 @@ class WatchAsianProvider : MainAPI() { | |||
|                         val innerBody = it?.selectFirst("a") | ||||
|                         // Fetch details | ||||
|                         val link = fixUrlNull(innerBody?.attr("href")) ?: return@map null | ||||
|                 val image = fixUrlNull(innerBody?.select("img")?.attr("data-original")) ?: "" | ||||
|                 val name = (innerBody?.selectFirst("h3.title")?.text() ?: innerBody?.text())?: "<Untitled>" | ||||
|                         val image = | ||||
|                             fixUrlNull(innerBody?.select("img")?.attr("data-original")) ?: "" | ||||
|                         val name = (innerBody?.selectFirst("h3.title")?.text() ?: innerBody?.text()) | ||||
|                             ?: "<Untitled>" | ||||
|                         //Log.i(this.name, "Result => (innerBody, image) ${innerBody} / ${image}") | ||||
|                         MovieSearchResponse( | ||||
|                             name, | ||||
|  | @ -74,7 +78,9 @@ class WatchAsianProvider : MainAPI() { | |||
|             val innerA = it?.selectFirst("a") ?: return@mapNotNull null | ||||
|             val link = fixUrlNull(innerA.attr("href")) ?: return@mapNotNull null | ||||
|             val title = it.select("h3.title")?.text() ?: return@mapNotNull null | ||||
|             if (title.isEmpty()) { return@mapNotNull null } | ||||
|             if (title.isEmpty()) { | ||||
|                 return@mapNotNull null | ||||
|             } | ||||
|             val year = null | ||||
|             val imgsrc = innerA.select("img")?.attr("data-original") ?: return@mapNotNull null | ||||
|             val image = fixUrlNull(imgsrc) | ||||
|  | @ -110,7 +116,9 @@ class WatchAsianProvider : MainAPI() { | |||
|             descript = inner?.text() | ||||
| 
 | ||||
|             inner?.select("p")?.forEach { p -> | ||||
|                 val caption = p?.selectFirst("span")?.text()?.trim()?.lowercase()?.removeSuffix(":")?.trim() ?: return@forEach | ||||
|                 val caption = | ||||
|                     p?.selectFirst("span")?.text()?.trim()?.lowercase()?.removeSuffix(":")?.trim() | ||||
|                         ?: return@forEach | ||||
|                 when (caption) { | ||||
|                     "genre" -> { | ||||
|                         tags = p.select("a")?.mapNotNull { it?.text()?.trim() } | ||||
|  | @ -132,7 +140,9 @@ class WatchAsianProvider : MainAPI() { | |||
|             year = if (title.length > 5) { | ||||
|                 title.replace(")", "").replace("(", "").substring(title.length - 5) | ||||
|                     .trim().trimEnd(')').toIntOrNull() | ||||
|             } else { null } | ||||
|             } else { | ||||
|                 null | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         // Episodes Links | ||||
|  | @ -194,7 +204,9 @@ class WatchAsianProvider : MainAPI() { | |||
|     ): Boolean { | ||||
|         val links = if (data.startsWith(mainUrl)) { | ||||
|             getServerLinks(data) | ||||
|         } else { data } | ||||
|         } else { | ||||
|             data | ||||
|         } | ||||
|         var count = 0 | ||||
|         mapper.readValue<List<String>>(links).apmap { item -> | ||||
|             count++ | ||||
|  | @ -202,6 +214,9 @@ class WatchAsianProvider : MainAPI() { | |||
|             //Log.i(this.name, "Result => (url) $url") | ||||
|             when { | ||||
|                 url.startsWith("https://asianembed.io") || url.startsWith("https://asianload.io") -> { | ||||
|                     val iv = "9262859232435825".toByteArray() | ||||
|                     val secretKey = "93422192433952489752342908585752".toByteArray() | ||||
|                     extractVidstream(url, this.name, callback, iv, secretKey) | ||||
|                     AsianEmbedHelper.getUrls(url, callback) | ||||
|                 } | ||||
|                 url.startsWith("https://embedsito.com") -> { | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue