mirror of
				https://github.com/recloudstream/cloudstream.git
				synced 2024-08-15 01:53:11 +00:00 
			
		
		
		
	9anime by Stormunblessed + minor code changes
This commit is contained in:
		
							parent
							
								
									73bcb4145e
								
							
						
					
					
						commit
						428e97ab1c
					
				
					 7 changed files with 331 additions and 43 deletions
				
			
		|  | @ -84,6 +84,7 @@ object APIHolder { | ||||||
|         KdramaHoodProvider(), |         KdramaHoodProvider(), | ||||||
|         AkwamProvider(), |         AkwamProvider(), | ||||||
|         AnimePaheProvider(), |         AnimePaheProvider(), | ||||||
|  |         NineAnimeProvider(), | ||||||
|     ) |     ) | ||||||
| 
 | 
 | ||||||
|     val restrictedApis = arrayListOf( |     val restrictedApis = arrayListOf( | ||||||
|  |  | ||||||
|  | @ -87,13 +87,13 @@ class AllAnimeProvider : MainAPI() { | ||||||
|         @JsonProperty("data") val data: Data |         @JsonProperty("data") val data: Data | ||||||
|     ) |     ) | ||||||
| 
 | 
 | ||||||
|     override suspend fun search(query: String): ArrayList<SearchResponse> { |     override suspend fun search(query: String): List<SearchResponse> { | ||||||
|         val link = |         val link = | ||||||
|             """$mainUrl/graphql?variables=%7B%22search%22%3A%7B%22allowAdult%22%3Afalse%2C%22query%22%3A%22$query%22%7D%2C%22limit%22%3A26%2C%22page%22%3A1%2C%22translationType%22%3A%22sub%22%7D&extensions=%7B%22persistedQuery%22%3A%7B%22version%22%3A1%2C%22sha256Hash%22%3A%229343797cc3d9e3f444e2d3b7db9a84d759b816a4d84512ea72d079f85bb96e98%22%7D%7D""" |             """$mainUrl/graphql?variables=%7B%22search%22%3A%7B%22allowAdult%22%3Afalse%2C%22query%22%3A%22$query%22%7D%2C%22limit%22%3A26%2C%22page%22%3A1%2C%22translationType%22%3A%22sub%22%7D&extensions=%7B%22persistedQuery%22%3A%7B%22version%22%3A1%2C%22sha256Hash%22%3A%229343797cc3d9e3f444e2d3b7db9a84d759b816a4d84512ea72d079f85bb96e98%22%7D%7D""" | ||||||
|         var res = app.get(link).text |         var res = app.get(link).text | ||||||
|         if (res.contains("PERSISTED_QUERY_NOT_FOUND")) { |         if (res.contains("PERSISTED_QUERY_NOT_FOUND")) { | ||||||
|             res = app.get(link).text |             res = app.get(link).text | ||||||
|             if (res.contains("PERSISTED_QUERY_NOT_FOUND")) return ArrayList() |             if (res.contains("PERSISTED_QUERY_NOT_FOUND")) return emptyList() | ||||||
|         } |         } | ||||||
|         val response = mapper.readValue<AllAnimeQuery>(res) |         val response = mapper.readValue<AllAnimeQuery>(res) | ||||||
| 
 | 
 | ||||||
|  | @ -102,7 +102,7 @@ class AllAnimeProvider : MainAPI() { | ||||||
|             !(it.availableEpisodes?.raw == 0 && it.availableEpisodes.sub == 0 && it.availableEpisodes.dub == 0) |             !(it.availableEpisodes?.raw == 0 && it.availableEpisodes.sub == 0 && it.availableEpisodes.dub == 0) | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         return ArrayList(results.map { |         return results.map { | ||||||
|             AnimeSearchResponse( |             AnimeSearchResponse( | ||||||
|                 it.name, |                 it.name, | ||||||
|                 "$mainUrl/anime/${it.Id}", |                 "$mainUrl/anime/${it.Id}", | ||||||
|  | @ -115,7 +115,7 @@ class AllAnimeProvider : MainAPI() { | ||||||
|                 it.availableEpisodes?.dub, |                 it.availableEpisodes?.dub, | ||||||
|                 it.availableEpisodes?.sub |                 it.availableEpisodes?.sub | ||||||
|             ) |             ) | ||||||
|         }) |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private data class AvailableEpisodesDetail( |     private data class AvailableEpisodesDetail( | ||||||
|  | @ -154,11 +154,11 @@ class AllAnimeProvider : MainAPI() { | ||||||
| 
 | 
 | ||||||
|         val episodes = showData.availableEpisodes.let { |         val episodes = showData.availableEpisodes.let { | ||||||
|             if (it == null) return@let Pair(null, null) |             if (it == null) return@let Pair(null, null) | ||||||
|             Pair(if (it.sub != 0) ArrayList((1..it.sub).map { epNum -> |             Pair(if (it.sub != 0) ((1..it.sub).map { epNum -> | ||||||
|                 AnimeEpisode( |                 AnimeEpisode( | ||||||
|                     "$mainUrl/anime/${showData.Id}/episodes/sub/$epNum", episode = epNum |                     "$mainUrl/anime/${showData.Id}/episodes/sub/$epNum", episode = epNum | ||||||
|                 ) |                 ) | ||||||
|             }) else null, if (it.dub != 0) ArrayList((1..it.dub).map { epNum -> |             }) else null, if (it.dub != 0) ((1..it.dub).map { epNum -> | ||||||
|                 AnimeEpisode( |                 AnimeEpisode( | ||||||
|                     "$mainUrl/anime/${showData.Id}/episodes/dub/$epNum", episode = epNum |                     "$mainUrl/anime/${showData.Id}/episodes/dub/$epNum", episode = epNum | ||||||
|                 ) |                 ) | ||||||
|  | @ -251,21 +251,20 @@ class AllAnimeProvider : MainAPI() { | ||||||
|     private fun getM3u8Qualities( |     private fun getM3u8Qualities( | ||||||
|         m3u8Link: String, |         m3u8Link: String, | ||||||
|         referer: String, |         referer: String, | ||||||
|         qualityName: String |         qualityName: String, | ||||||
|     ): ArrayList<ExtractorLink> { |     ): List<ExtractorLink> { | ||||||
|         return ArrayList( |         return hlsHelper.m3u8Generation(M3u8Helper.M3u8Stream(m3u8Link, null), true).map { stream -> | ||||||
|             hlsHelper.m3u8Generation(M3u8Helper.M3u8Stream(m3u8Link, null), true).map { stream -> |             val qualityString = if ((stream.quality ?: 0) == 0) "" else "${stream.quality}p" | ||||||
|                 val qualityString = if ((stream.quality ?: 0) == 0) "" else "${stream.quality}p" |             ExtractorLink( | ||||||
|                 ExtractorLink( |                 this.name, | ||||||
|                     this.name, |                 "${this.name} - $qualityName $qualityString", | ||||||
|                     "${this.name} - $qualityName $qualityString", |                 stream.streamUrl, | ||||||
|                     stream.streamUrl, |                 referer, | ||||||
|                     referer, |                 getQualityFromName(stream.quality.toString()), | ||||||
|                     getQualityFromName(stream.quality.toString()), |                 true, | ||||||
|                     true, |                 stream.headers | ||||||
|                     stream.headers |             ) | ||||||
|                 ) |         } | ||||||
|             }) |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     override suspend fun loadLinks( |     override suspend fun loadLinks( | ||||||
|  |  | ||||||
|  | @ -27,12 +27,12 @@ class AnimeFlickProvider : MainAPI() { | ||||||
|         TvType.OVA |         TvType.OVA | ||||||
|     ) |     ) | ||||||
| 
 | 
 | ||||||
|     override suspend fun search(query: String): ArrayList<SearchResponse> { |     override suspend fun search(query: String): List<SearchResponse> { | ||||||
|         val link = "https://animeflick.net/search.php?search=$query" |         val link = "https://animeflick.net/search.php?search=$query" | ||||||
|         val html = app.get(link).text |         val html = app.get(link).text | ||||||
|         val doc = Jsoup.parse(html) |         val doc = Jsoup.parse(html) | ||||||
| 
 | 
 | ||||||
|         return ArrayList(doc.select(".row.mt-2").map { |         return doc.select(".row.mt-2").map { | ||||||
|             val href = mainUrl + it.selectFirst("a").attr("href") |             val href = mainUrl + it.selectFirst("a").attr("href") | ||||||
|             val title = it.selectFirst("h5 > a").text() |             val title = it.selectFirst("h5 > a").text() | ||||||
|             val poster = mainUrl + it.selectFirst("img").attr("src").replace("70x110", "225x320") |             val poster = mainUrl + it.selectFirst("img").attr("src").replace("70x110", "225x320") | ||||||
|  | @ -45,7 +45,7 @@ class AnimeFlickProvider : MainAPI() { | ||||||
|                 null, |                 null, | ||||||
|                 EnumSet.of(DubStatus.Subbed), |                 EnumSet.of(DubStatus.Subbed), | ||||||
|             ) |             ) | ||||||
|         }) |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     override suspend fun load(url: String): LoadResponse { |     override suspend fun load(url: String): LoadResponse { | ||||||
|  |  | ||||||
|  | @ -0,0 +1,274 @@ | ||||||
|  | package com.lagradost.cloudstream3.animeproviders | ||||||
|  | 
 | ||||||
|  | import com.fasterxml.jackson.annotation.JsonProperty | ||||||
|  | import com.lagradost.cloudstream3.* | ||||||
|  | import com.lagradost.cloudstream3.utils.AppUtils.parseJson | ||||||
|  | import com.lagradost.cloudstream3.utils.ExtractorLink | ||||||
|  | import com.lagradost.cloudstream3.utils.loadExtractor | ||||||
|  | import org.jsoup.Jsoup | ||||||
|  | import java.util.* | ||||||
|  | 
 | ||||||
|  | class NineAnimeProvider : MainAPI() { | ||||||
|  |     override val mainUrl = "https://9anime.center" | ||||||
|  |     override val name = "9Anime" | ||||||
|  |     override val hasMainPage = true | ||||||
|  |     override val hasChromecastSupport = true | ||||||
|  |     override val hasDownloadSupport = true | ||||||
|  |     override val supportedTypes = setOf(TvType.Anime) | ||||||
|  | 
 | ||||||
|  |     override suspend fun getMainPage(): HomePageResponse { | ||||||
|  |         val items = listOf( | ||||||
|  |             Pair("$mainUrl/ajax/home/widget?name=trending", "Trending"), | ||||||
|  |             Pair("$mainUrl/ajax/home/widget?name=updated_all", "All"), | ||||||
|  |             Pair("$mainUrl/ajax/home/widget?name=updated_sub&page=1", "Recently Updated (SUB)"), | ||||||
|  |             Pair("$mainUrl/ajax/home/widget?name=updated_dub&page=1", "Recently Updated (DUB)"), | ||||||
|  |             Pair( | ||||||
|  |                 "$mainUrl/ajax/home/widget?name=updated_chinese&page=1", | ||||||
|  |                 "Recently Updated (Chinese)" | ||||||
|  |             ), | ||||||
|  |             Pair("$mainUrl/ajax/home/widget?name=random", "Random"), | ||||||
|  |         ).map { (url, name) -> | ||||||
|  |             val home = Jsoup.parse( | ||||||
|  |                 app.get( | ||||||
|  |                     url | ||||||
|  |                 ).mapped<Response>().html | ||||||
|  |             ).select("ul.anime-list li").map { | ||||||
|  |                 val title = it.selectFirst("a.name").text() | ||||||
|  |                 val link = it.selectFirst("a").attr("href") | ||||||
|  |                 val poster = it.selectFirst("a.poster img").attr("src") | ||||||
|  |                 AnimeSearchResponse( | ||||||
|  |                     title, | ||||||
|  |                     link, | ||||||
|  |                     this.name, | ||||||
|  |                     TvType.Anime, | ||||||
|  |                     poster, | ||||||
|  |                     null, | ||||||
|  |                     if (title.contains("(DUB)") || title.contains("(Dub)")) EnumSet.of( | ||||||
|  |                         DubStatus.Dubbed | ||||||
|  |                     ) else EnumSet.of(DubStatus.Subbed), | ||||||
|  |                 ) | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             HomePageList(name, home) | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         return HomePageResponse(items) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     //Credits to https://github.com/jmir1 | ||||||
|  |     private val key = "0wMrYU+ixjJ4QdzgfN2HlyIVAt3sBOZnCT9Lm7uFDovkb/EaKpRWhqXS5168ePcG" | ||||||
|  | 
 | ||||||
|  |     private fun getVrf(id: String): String? { | ||||||
|  |         val reversed = ue(encode(id) + "0000000").slice(0..5).reversed() | ||||||
|  | 
 | ||||||
|  |         return reversed + ue(je(reversed, encode(id) ?: return null)).replace( | ||||||
|  |             """=+$""".toRegex(), | ||||||
|  |             "" | ||||||
|  |         ) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private fun getLink(url: String): String? { | ||||||
|  |         val i = url.slice(0..5) | ||||||
|  |         val n = url.slice(6..url.lastIndex) | ||||||
|  |         return decode(je(i, ze(n))) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private fun ue(input: String): String { | ||||||
|  |         if (input.any { it.code >= 256 }) throw Exception("illegal characters!") | ||||||
|  |         var output = "" | ||||||
|  |         for (i in input.indices step 3) { | ||||||
|  |             val a = intArrayOf(-1, -1, -1, -1) | ||||||
|  |             a[0] = input[i].code shr 2 | ||||||
|  |             a[1] = (3 and input[i].code) shl 4 | ||||||
|  |             if (input.length > i + 1) { | ||||||
|  |                 a[1] = a[1] or (input[i + 1].code shr 4) | ||||||
|  |                 a[2] = (15 and input[i + 1].code) shl 2 | ||||||
|  |             } | ||||||
|  |             if (input.length > i + 2) { | ||||||
|  |                 a[2] = a[2] or (input[i + 2].code shr 6) | ||||||
|  |                 a[3] = 63 and input[i + 2].code | ||||||
|  |             } | ||||||
|  |             for (n in a) { | ||||||
|  |                 if (n == -1) output += "=" | ||||||
|  |                 else { | ||||||
|  |                     if (n in 0..63) output += key[n] | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         return output; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private fun je(inputOne: String, inputTwo: String): String { | ||||||
|  |         val arr = IntArray(256) { it } | ||||||
|  |         var output = "" | ||||||
|  |         var u = 0 | ||||||
|  |         var r: Int | ||||||
|  |         for (a in arr.indices) { | ||||||
|  |             u = (u + arr[a] + inputOne[a % inputOne.length].code) % 256 | ||||||
|  |             r = arr[a] | ||||||
|  |             arr[a] = arr[u] | ||||||
|  |             arr[u] = r | ||||||
|  |         } | ||||||
|  |         u = 0 | ||||||
|  |         var c = 0 | ||||||
|  |         for (f in inputTwo.indices) { | ||||||
|  |             c = (c + f) % 256 | ||||||
|  |             u = (u + arr[c]) % 256 | ||||||
|  |             r = arr[c] | ||||||
|  |             arr[c] = arr[u] | ||||||
|  |             arr[u] = r | ||||||
|  |             output += (inputTwo[f].code xor arr[(arr[c] + arr[u]) % 256]).toChar() | ||||||
|  |         } | ||||||
|  |         return output | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private fun ze(input: 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 | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private fun encode(input: String): String? = java.net.URLEncoder.encode(input, "utf-8") | ||||||
|  | 
 | ||||||
|  |     private fun decode(input: String): String? = java.net.URLDecoder.decode(input, "utf-8") | ||||||
|  | 
 | ||||||
|  |     override suspend fun search(query: String): List<SearchResponse> { | ||||||
|  |         val url = "$mainUrl/filter?sort=title%3Aasc&keyword=$query" | ||||||
|  | 
 | ||||||
|  |         return app.get(url).document.select("ul.anime-list li").mapNotNull { | ||||||
|  |             val title = it.selectFirst("a.name").text() | ||||||
|  |             val href = | ||||||
|  |                 fixUrlNull(it.selectFirst("a").attr("href"))?.replace(Regex("(\\?ep=(\\d+)\$)"), "") | ||||||
|  |                     ?: return@mapNotNull null | ||||||
|  |             val image = it.selectFirst("a.poster img").attr("src") | ||||||
|  |             AnimeSearchResponse( | ||||||
|  |                 title, | ||||||
|  |                 href, | ||||||
|  |                 this.name, | ||||||
|  |                 TvType.Anime, | ||||||
|  |                 image, | ||||||
|  |                 null, | ||||||
|  |                 if (title.contains("(DUB)") || title.contains("(Dub)")) EnumSet.of( | ||||||
|  |                     DubStatus.Dubbed | ||||||
|  |                 ) else EnumSet.of(DubStatus.Subbed), | ||||||
|  |             ) | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     data class Response( | ||||||
|  |         @JsonProperty("html") val html: String | ||||||
|  |     ) | ||||||
|  | 
 | ||||||
|  |     override suspend fun load(url: String): LoadResponse? { | ||||||
|  |         val urlclean = url.substringAfter("watch/") | ||||||
|  |         val regexID = Regex("(\\.[a-zA-Z0-9]{0,8}[a-zA-Z0-9_-]+)") | ||||||
|  |         val animeid = regexID.find(urlclean)?.value?.replace(".", "") ?: return null | ||||||
|  |         val animeidencoded = encode(getVrf(animeid) ?: return null) | ||||||
|  | 
 | ||||||
|  |         val doc = app.get(url).document | ||||||
|  |         val poster = doc.selectFirst("aside.main div.thumb div img").attr("src") | ||||||
|  |         val title = doc.selectFirst(".info .title").text() | ||||||
|  |         val description = doc.selectFirst("div.info p").text().replace("Ver menos", "").trim() | ||||||
|  |         val episodes = Jsoup.parse( | ||||||
|  |             app.get( | ||||||
|  |                 "$mainUrl/ajax/anime/servers?ep=1&id=${animeid}&vrf=$animeidencoded&ep=8&episode=&token=" | ||||||
|  |             ).mapped<Response>().html | ||||||
|  |         )?.select("ul.episodes li a")?.mapNotNull { | ||||||
|  |             val link = it?.attr("href") ?: return@mapNotNull null | ||||||
|  |             val epnum = it.attr("data-base")?.toIntOrNull() | ||||||
|  |             AnimeEpisode(link, episode = epnum) | ||||||
|  |         } ?: return null | ||||||
|  | 
 | ||||||
|  |         return newAnimeLoadResponse(title, url, TvType.Anime) { | ||||||
|  |             posterUrl = poster | ||||||
|  |             addEpisodes(DubStatus.Subbed, episodes) | ||||||
|  |             plot = description | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     data class Links( | ||||||
|  |         @JsonProperty("url") val url: String | ||||||
|  |     ) | ||||||
|  | 
 | ||||||
|  |     data class Servers( | ||||||
|  |         @JsonProperty("28") val mcloud: String?, | ||||||
|  |         @JsonProperty("35") val mp4upload: String?, | ||||||
|  |         @JsonProperty("40") val streamtape: String?, | ||||||
|  |         @JsonProperty("41") val vidstream: String?, | ||||||
|  |         @JsonProperty("43") val videovard: String? | ||||||
|  |     ) | ||||||
|  | 
 | ||||||
|  |     override suspend fun loadLinks( | ||||||
|  |         data: String, | ||||||
|  |         isCasting: Boolean, | ||||||
|  |         subtitleCallback: (SubtitleFile) -> Unit, | ||||||
|  |         callback: (ExtractorLink) -> Unit | ||||||
|  |     ): Boolean { | ||||||
|  |         val urlclean = data.substringAfter("watch/") | ||||||
|  |         val regexID = Regex("(\\.[a-zA-Z0-9]{0,8}[a-zA-Z0-9_-]+)") | ||||||
|  |         val animeid = regexID.find(urlclean)?.value?.replace(".", "") ?: return false | ||||||
|  | 
 | ||||||
|  |         val animeidencoded = encode(getVrf(animeid) ?: return false) | ||||||
|  | 
 | ||||||
|  |         Jsoup.parse( | ||||||
|  |             app.get( | ||||||
|  |                 "$mainUrl/ajax/anime/servers?&id=${animeid}&vrf=$animeidencoded&episode=&token=" | ||||||
|  |             ).mapped<Response>().html | ||||||
|  |         ).select("div.body").map { element -> | ||||||
|  |             val jsonregex = Regex("(\\{.+\\}.*$data)") | ||||||
|  |             val servers = jsonregex.find(element.toString())?.value?.replace( | ||||||
|  |                 Regex("(\".*data-base=.*href=\"$data)"), | ||||||
|  |                 "" | ||||||
|  |             )?.replace(""", "\"") ?: return@map | ||||||
|  | 
 | ||||||
|  |             val jsonservers = parseJson<Servers?>(servers) ?: return@map | ||||||
|  |             listOfNotNull( | ||||||
|  |                 jsonservers.vidstream, | ||||||
|  |                 jsonservers.mcloud, | ||||||
|  |                 jsonservers.mp4upload, | ||||||
|  |                 jsonservers.streamtape | ||||||
|  |             ).mapNotNull { | ||||||
|  |                 val epserver = app.get("$mainUrl/ajax/anime/episode?id=$it").text | ||||||
|  |                 (if (epserver.contains("url")) { | ||||||
|  |                     parseJson<Links>(epserver) | ||||||
|  |                 } else null)?.url?.let { it1 -> getLink(it1.replace("=", "")) } | ||||||
|  |                     ?.replace("/embed/", "/e/") | ||||||
|  |             }.apmap { url -> | ||||||
|  |                 loadExtractor( | ||||||
|  |                     url, data, callback | ||||||
|  |                 ) | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         return true | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -1,12 +1,14 @@ | ||||||
| package com.lagradost.cloudstream3.extractors | package com.lagradost.cloudstream3.extractors | ||||||
| 
 | 
 | ||||||
| import com.lagradost.cloudstream3.utils.* |  | ||||||
| import com.lagradost.cloudstream3.app |  | ||||||
| import com.fasterxml.jackson.annotation.JsonProperty | import com.fasterxml.jackson.annotation.JsonProperty | ||||||
| import com.lagradost.cloudstream3.USER_AGENT | import com.lagradost.cloudstream3.USER_AGENT | ||||||
| import com.lagradost.cloudstream3.apmap | import com.lagradost.cloudstream3.apmap | ||||||
|  | import com.lagradost.cloudstream3.app | ||||||
| import com.lagradost.cloudstream3.utils.AppUtils.parseJson | import com.lagradost.cloudstream3.utils.AppUtils.parseJson | ||||||
| 
 | import com.lagradost.cloudstream3.utils.ExtractorApi | ||||||
|  | import com.lagradost.cloudstream3.utils.ExtractorLink | ||||||
|  | import com.lagradost.cloudstream3.utils.M3u8Helper | ||||||
|  | import com.lagradost.cloudstream3.utils.getQualityFromName | ||||||
| 
 | 
 | ||||||
| open class Mcloud : ExtractorApi() { | open class Mcloud : ExtractorApi() { | ||||||
|     override val name = "Mcloud" |     override val name = "Mcloud" | ||||||
|  | @ -30,6 +32,11 @@ open class Mcloud : ExtractorApi() { | ||||||
|         val link = url.replace("$mainUrl/e/","$mainUrl/info/") |         val link = url.replace("$mainUrl/e/","$mainUrl/info/") | ||||||
|         val response = app.get(link, headers = headers).text |         val response = app.get(link, headers = headers).text | ||||||
| 
 | 
 | ||||||
|  |         if(response.startsWith("<!DOCTYPE html>")) { | ||||||
|  |             // TODO decrypt html for link | ||||||
|  |             return emptyList() | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         data class Sources ( |         data class Sources ( | ||||||
|             @JsonProperty("file") val file: String |             @JsonProperty("file") val file: String | ||||||
|         ) |         ) | ||||||
|  | @ -43,7 +50,7 @@ open class Mcloud : ExtractorApi() { | ||||||
|             @JsonProperty("media") val media: Media, |             @JsonProperty("media") val media: Media, | ||||||
|         ) |         ) | ||||||
| 
 | 
 | ||||||
|         val mapped = response.let { parseJson<JsonMcloud>(it) } |         val mapped = parseJson<JsonMcloud>(response) | ||||||
|         val sources = mutableListOf<ExtractorLink>() |         val sources = mutableListOf<ExtractorLink>() | ||||||
| 
 | 
 | ||||||
|         if (mapped.success) |         if (mapped.success) | ||||||
|  |  | ||||||
|  | @ -6,7 +6,11 @@ import com.lagradost.cloudstream3.app | ||||||
| import com.lagradost.cloudstream3.mapper | import com.lagradost.cloudstream3.mapper | ||||||
| import com.lagradost.cloudstream3.utils.* | import com.lagradost.cloudstream3.utils.* | ||||||
| 
 | 
 | ||||||
| class WcoStream : ExtractorApi() { | class Vidstreamz : WcoStream() { | ||||||
|  |     override val mainUrl: String = "https://vidstreamz.online" | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | open class WcoStream : ExtractorApi() { | ||||||
|     override val name = "VidStream" //Cause works for animekisa and wco |     override val name = "VidStream" //Cause works for animekisa and wco | ||||||
|     override val mainUrl = "https://vidstream.pro" |     override val mainUrl = "https://vidstream.pro" | ||||||
|     override val requiresReferer = false |     override val requiresReferer = false | ||||||
|  | @ -16,8 +20,8 @@ class WcoStream : ExtractorApi() { | ||||||
|         val baseUrl = url.split("/e/")[0] |         val baseUrl = url.split("/e/")[0] | ||||||
| 
 | 
 | ||||||
|         val html = app.get(url, headers = mapOf("Referer" to "https://wcostream.cc/")).text |         val html = app.get(url, headers = mapOf("Referer" to "https://wcostream.cc/")).text | ||||||
|         val (Id) = "/e/(.*?)?domain".toRegex().find(url)!!.destructured |         val (Id) = ("/e/(.*?)?domain".toRegex().find(url)?.destructured ?: Regex("""/e/(.*)""").find(url)?.destructured) ?: return emptyList() | ||||||
|         val (skey) = """skey\s=\s['"](.*?)['"];""".toRegex().find(html)!!.destructured |         val (skey) = """skey\s=\s['"](.*?)['"];""".toRegex().find(html)?.destructured ?: return emptyList() | ||||||
| 
 | 
 | ||||||
|         val apiLink = "$baseUrl/info/$Id?domain=wcostream.cc&skey=$skey" |         val apiLink = "$baseUrl/info/$Id?domain=wcostream.cc&skey=$skey" | ||||||
|         val referrer = "$baseUrl/e/$Id?domain=wcostream.cc" |         val referrer = "$baseUrl/e/$Id?domain=wcostream.cc" | ||||||
|  | @ -44,19 +48,21 @@ class WcoStream : ExtractorApi() { | ||||||
|         if (mapped.success) { |         if (mapped.success) { | ||||||
|             mapped.media.sources.forEach { |             mapped.media.sources.forEach { | ||||||
|                 if (it.file.contains("m3u8")) { |                 if (it.file.contains("m3u8")) { | ||||||
|                     hlsHelper.m3u8Generation(M3u8Helper.M3u8Stream(it.file, null), true).forEach { stream -> |                     hlsHelper.m3u8Generation(M3u8Helper.M3u8Stream(it.file, null), true) | ||||||
|                         val qualityString = if ((stream.quality ?: 0) == 0) "" else "${stream.quality}p" |                         .forEach { stream -> | ||||||
|                         sources.add( |                             val qualityString = | ||||||
|                             ExtractorLink( |                                 if ((stream.quality ?: 0) == 0) "" else "${stream.quality}p" | ||||||
|                                 name, |                             sources.add( | ||||||
|                                 "$name $qualityString", |                                 ExtractorLink( | ||||||
|                                 stream.streamUrl, |                                     name, | ||||||
|                                 "", |                                     "$name $qualityString", | ||||||
|                                 getQualityFromName(stream.quality.toString()), |                                     stream.streamUrl, | ||||||
|                                 true |                                     "", | ||||||
|  |                                     getQualityFromName(stream.quality.toString()), | ||||||
|  |                                     true | ||||||
|  |                                 ) | ||||||
|                             ) |                             ) | ||||||
|                         ) |                         } | ||||||
|                     } |  | ||||||
|                 } else { |                 } else { | ||||||
|                     sources.add( |                     sources.add( | ||||||
|                         ExtractorLink( |                         ExtractorLink( | ||||||
|  |  | ||||||
|  | @ -94,6 +94,7 @@ suspend fun loadExtractor(url: String, referer: String? = null, callback: (Extra | ||||||
| val extractorApis: Array<ExtractorApi> = arrayOf( | val extractorApis: Array<ExtractorApi> = arrayOf( | ||||||
|     //AllProvider(), |     //AllProvider(), | ||||||
|     WcoStream(), |     WcoStream(), | ||||||
|  |     Vidstreamz(), | ||||||
|     Mp4Upload(), |     Mp4Upload(), | ||||||
|     StreamTape(), |     StreamTape(), | ||||||
|     MixDrop(), |     MixDrop(), | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue