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(),
 | 
			
		||||
        AkwamProvider(),
 | 
			
		||||
        AnimePaheProvider(),
 | 
			
		||||
        NineAnimeProvider(),
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    val restrictedApis = arrayListOf(
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -87,13 +87,13 @@ class AllAnimeProvider : MainAPI() {
 | 
			
		|||
        @JsonProperty("data") val data: Data
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    override suspend fun search(query: String): ArrayList<SearchResponse> {
 | 
			
		||||
    override suspend fun search(query: String): List<SearchResponse> {
 | 
			
		||||
        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"""
 | 
			
		||||
        var res = app.get(link).text
 | 
			
		||||
        if (res.contains("PERSISTED_QUERY_NOT_FOUND")) {
 | 
			
		||||
            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)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -102,7 +102,7 @@ class AllAnimeProvider : MainAPI() {
 | 
			
		|||
            !(it.availableEpisodes?.raw == 0 && it.availableEpisodes.sub == 0 && it.availableEpisodes.dub == 0)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return ArrayList(results.map {
 | 
			
		||||
        return results.map {
 | 
			
		||||
            AnimeSearchResponse(
 | 
			
		||||
                it.name,
 | 
			
		||||
                "$mainUrl/anime/${it.Id}",
 | 
			
		||||
| 
						 | 
				
			
			@ -115,7 +115,7 @@ class AllAnimeProvider : MainAPI() {
 | 
			
		|||
                it.availableEpisodes?.dub,
 | 
			
		||||
                it.availableEpisodes?.sub
 | 
			
		||||
            )
 | 
			
		||||
        })
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private data class AvailableEpisodesDetail(
 | 
			
		||||
| 
						 | 
				
			
			@ -154,11 +154,11 @@ class AllAnimeProvider : MainAPI() {
 | 
			
		|||
 | 
			
		||||
        val episodes = showData.availableEpisodes.let {
 | 
			
		||||
            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(
 | 
			
		||||
                    "$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(
 | 
			
		||||
                    "$mainUrl/anime/${showData.Id}/episodes/dub/$epNum", episode = epNum
 | 
			
		||||
                )
 | 
			
		||||
| 
						 | 
				
			
			@ -251,21 +251,20 @@ class AllAnimeProvider : MainAPI() {
 | 
			
		|||
    private fun getM3u8Qualities(
 | 
			
		||||
        m3u8Link: String,
 | 
			
		||||
        referer: String,
 | 
			
		||||
        qualityName: String
 | 
			
		||||
    ): ArrayList<ExtractorLink> {
 | 
			
		||||
        return ArrayList(
 | 
			
		||||
            hlsHelper.m3u8Generation(M3u8Helper.M3u8Stream(m3u8Link, null), true).map { stream ->
 | 
			
		||||
                val qualityString = if ((stream.quality ?: 0) == 0) "" else "${stream.quality}p"
 | 
			
		||||
                ExtractorLink(
 | 
			
		||||
                    this.name,
 | 
			
		||||
                    "${this.name} - $qualityName $qualityString",
 | 
			
		||||
                    stream.streamUrl,
 | 
			
		||||
                    referer,
 | 
			
		||||
                    getQualityFromName(stream.quality.toString()),
 | 
			
		||||
                    true,
 | 
			
		||||
                    stream.headers
 | 
			
		||||
                )
 | 
			
		||||
            })
 | 
			
		||||
        qualityName: String,
 | 
			
		||||
    ): List<ExtractorLink> {
 | 
			
		||||
        return hlsHelper.m3u8Generation(M3u8Helper.M3u8Stream(m3u8Link, null), true).map { stream ->
 | 
			
		||||
            val qualityString = if ((stream.quality ?: 0) == 0) "" else "${stream.quality}p"
 | 
			
		||||
            ExtractorLink(
 | 
			
		||||
                this.name,
 | 
			
		||||
                "${this.name} - $qualityName $qualityString",
 | 
			
		||||
                stream.streamUrl,
 | 
			
		||||
                referer,
 | 
			
		||||
                getQualityFromName(stream.quality.toString()),
 | 
			
		||||
                true,
 | 
			
		||||
                stream.headers
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override suspend fun loadLinks(
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -27,12 +27,12 @@ class AnimeFlickProvider : MainAPI() {
 | 
			
		|||
        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 html = app.get(link).text
 | 
			
		||||
        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 title = it.selectFirst("h5 > a").text()
 | 
			
		||||
            val poster = mainUrl + it.selectFirst("img").attr("src").replace("70x110", "225x320")
 | 
			
		||||
| 
						 | 
				
			
			@ -45,7 +45,7 @@ class AnimeFlickProvider : MainAPI() {
 | 
			
		|||
                null,
 | 
			
		||||
                EnumSet.of(DubStatus.Subbed),
 | 
			
		||||
            )
 | 
			
		||||
        })
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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
 | 
			
		||||
 | 
			
		||||
import com.lagradost.cloudstream3.utils.*
 | 
			
		||||
import com.lagradost.cloudstream3.app
 | 
			
		||||
import com.fasterxml.jackson.annotation.JsonProperty
 | 
			
		||||
import com.lagradost.cloudstream3.USER_AGENT
 | 
			
		||||
import com.lagradost.cloudstream3.apmap
 | 
			
		||||
import com.lagradost.cloudstream3.app
 | 
			
		||||
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() {
 | 
			
		||||
    override val name = "Mcloud"
 | 
			
		||||
| 
						 | 
				
			
			@ -30,6 +32,11 @@ open class Mcloud : ExtractorApi() {
 | 
			
		|||
        val link = url.replace("$mainUrl/e/","$mainUrl/info/")
 | 
			
		||||
        val response = app.get(link, headers = headers).text
 | 
			
		||||
 | 
			
		||||
        if(response.startsWith("<!DOCTYPE html>")) {
 | 
			
		||||
            // TODO decrypt html for link
 | 
			
		||||
            return emptyList()
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        data class Sources (
 | 
			
		||||
            @JsonProperty("file") val file: String
 | 
			
		||||
        )
 | 
			
		||||
| 
						 | 
				
			
			@ -43,7 +50,7 @@ open class Mcloud : ExtractorApi() {
 | 
			
		|||
            @JsonProperty("media") val media: Media,
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        val mapped = response.let { parseJson<JsonMcloud>(it) }
 | 
			
		||||
        val mapped = parseJson<JsonMcloud>(response)
 | 
			
		||||
        val sources = mutableListOf<ExtractorLink>()
 | 
			
		||||
 | 
			
		||||
        if (mapped.success)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,7 +6,11 @@ import com.lagradost.cloudstream3.app
 | 
			
		|||
import com.lagradost.cloudstream3.mapper
 | 
			
		||||
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 mainUrl = "https://vidstream.pro"
 | 
			
		||||
    override val requiresReferer = false
 | 
			
		||||
| 
						 | 
				
			
			@ -16,8 +20,8 @@ class WcoStream : ExtractorApi() {
 | 
			
		|||
        val baseUrl = url.split("/e/")[0]
 | 
			
		||||
 | 
			
		||||
        val html = app.get(url, headers = mapOf("Referer" to "https://wcostream.cc/")).text
 | 
			
		||||
        val (Id) = "/e/(.*?)?domain".toRegex().find(url)!!.destructured
 | 
			
		||||
        val (skey) = """skey\s=\s['"](.*?)['"];""".toRegex().find(html)!!.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 ?: return emptyList()
 | 
			
		||||
 | 
			
		||||
        val apiLink = "$baseUrl/info/$Id?domain=wcostream.cc&skey=$skey"
 | 
			
		||||
        val referrer = "$baseUrl/e/$Id?domain=wcostream.cc"
 | 
			
		||||
| 
						 | 
				
			
			@ -44,19 +48,21 @@ class WcoStream : ExtractorApi() {
 | 
			
		|||
        if (mapped.success) {
 | 
			
		||||
            mapped.media.sources.forEach {
 | 
			
		||||
                if (it.file.contains("m3u8")) {
 | 
			
		||||
                    hlsHelper.m3u8Generation(M3u8Helper.M3u8Stream(it.file, null), true).forEach { stream ->
 | 
			
		||||
                        val qualityString = if ((stream.quality ?: 0) == 0) "" else "${stream.quality}p"
 | 
			
		||||
                        sources.add(
 | 
			
		||||
                            ExtractorLink(
 | 
			
		||||
                                name,
 | 
			
		||||
                                "$name $qualityString",
 | 
			
		||||
                                stream.streamUrl,
 | 
			
		||||
                                "",
 | 
			
		||||
                                getQualityFromName(stream.quality.toString()),
 | 
			
		||||
                                true
 | 
			
		||||
                    hlsHelper.m3u8Generation(M3u8Helper.M3u8Stream(it.file, null), true)
 | 
			
		||||
                        .forEach { stream ->
 | 
			
		||||
                            val qualityString =
 | 
			
		||||
                                if ((stream.quality ?: 0) == 0) "" else "${stream.quality}p"
 | 
			
		||||
                            sources.add(
 | 
			
		||||
                                ExtractorLink(
 | 
			
		||||
                                    name,
 | 
			
		||||
                                    "$name $qualityString",
 | 
			
		||||
                                    stream.streamUrl,
 | 
			
		||||
                                    "",
 | 
			
		||||
                                    getQualityFromName(stream.quality.toString()),
 | 
			
		||||
                                    true
 | 
			
		||||
                                )
 | 
			
		||||
                            )
 | 
			
		||||
                        )
 | 
			
		||||
                    }
 | 
			
		||||
                        }
 | 
			
		||||
                } else {
 | 
			
		||||
                    sources.add(
 | 
			
		||||
                        ExtractorLink(
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -94,6 +94,7 @@ suspend fun loadExtractor(url: String, referer: String? = null, callback: (Extra
 | 
			
		|||
val extractorApis: Array<ExtractorApi> = arrayOf(
 | 
			
		||||
    //AllProvider(),
 | 
			
		||||
    WcoStream(),
 | 
			
		||||
    Vidstreamz(),
 | 
			
		||||
    Mp4Upload(),
 | 
			
		||||
    StreamTape(),
 | 
			
		||||
    MixDrop(),
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue