forked from recloudstream/cloudstream
		
	Merge remote-tracking branch 'origin/master'
This commit is contained in:
		
						commit
						a237ee5b7a
					
				
					 7 changed files with 208 additions and 1 deletions
				
			
		|  | @ -34,6 +34,7 @@ object APIHolder { | |||
|         PeliSmartProvider(), | ||||
|         GogoanimeProvider(), | ||||
|         AllAnimeProvider(), | ||||
|         AnimekisaProvider(), | ||||
|         //ShiroProvider(), // v2 fucked me | ||||
|         //AnimePaheProvider(), //ddos guard | ||||
|         AnimeFlickProvider(), | ||||
|  |  | |||
|  | @ -0,0 +1,127 @@ | |||
| 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.* | ||||
| import kotlin.collections.ArrayList | ||||
| 
 | ||||
| 
 | ||||
| class AnimekisaProvider : MainAPI() { | ||||
| 
 | ||||
|     override val mainUrl = "https://animekisa.in" | ||||
|     override val name = "Animekisa" | ||||
|     override val hasMainPage = true | ||||
|     override val hasChromecastSupport = true | ||||
|     override val hasDownloadSupport = true | ||||
|     override val supportedTypes = setOf( | ||||
|         TvType.AnimeMovie, | ||||
|         TvType.OVA, | ||||
|         TvType.Anime, | ||||
|     ) | ||||
| 
 | ||||
|     data class Response ( | ||||
|         @JsonProperty("html") val html: String | ||||
|     ) | ||||
| 
 | ||||
|     override suspend fun getMainPage(): HomePageResponse { | ||||
|         val urls = listOf( | ||||
|             Pair("$mainUrl/ajax/list/views?type=all", "All animes"), | ||||
|             Pair("$mainUrl/ajax/list/views?type=day", "Trending now"), | ||||
|             Pair("$mainUrl/ajax/list/views?type=week", "Trending by week"), | ||||
|             Pair("$mainUrl/ajax/list/views?type=month", "Trending by month"), | ||||
| 
 | ||||
|             ) | ||||
| 
 | ||||
|         val items = ArrayList<HomePageList>() | ||||
| 
 | ||||
|         for ((url, name) in urls) { | ||||
|             try { | ||||
|                 val home = Jsoup.parse( | ||||
|                     parseJson<Response>( | ||||
|                         app.get( | ||||
|                             url | ||||
|                         ).text | ||||
|                     ).html | ||||
|                 ).select("div.flw-item").map { | ||||
|                     val title = it.selectFirst("h3.title a").text() | ||||
|                     val link = it.selectFirst("a").attr("href") | ||||
|                     val poster = it.selectFirst("img.lazyload").attr("data-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), | ||||
|                     ) | ||||
|                 } | ||||
| 
 | ||||
|                 items.add(HomePageList(name, home)) | ||||
|             } catch (e: Exception) { | ||||
|                 e.printStackTrace() | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         if (items.size <= 0) throw ErrorLoadingException() | ||||
|         return HomePageResponse(items) | ||||
|     } | ||||
|     override suspend fun search(query: String): List<SearchResponse> { | ||||
|         return app.get("$mainUrl/search/?keyword=$query").document.select("div.flw-item").map { | ||||
|             val title = it.selectFirst("h3 a").text() | ||||
|             val url = it.selectFirst("a.film-poster-ahref").attr("href") | ||||
|                 .replace("watch/","anime/").replace(Regex("(-episode-(\\d+)\\/\$|-episode-(\\d+)\$|-episode-full|-episode-.*-.(\\/|))"),"") | ||||
|             val poster = it.selectFirst(".film-poster img").attr("data-src") | ||||
|             AnimeSearchResponse( | ||||
|                 title, | ||||
|                 url, | ||||
|                 this.name, | ||||
|                 TvType.Anime, | ||||
|                 poster, | ||||
|                 null, | ||||
|                 if (title.contains("(DUB)") || title.contains("(Dub)")) EnumSet.of( | ||||
|                     DubStatus.Dubbed | ||||
|                 ) else EnumSet.of(DubStatus.Subbed), | ||||
|             ) | ||||
|         }.toList() | ||||
|     } | ||||
|     override suspend fun load(url: String): LoadResponse { | ||||
|         val doc = app.get(url, timeout = 120).document | ||||
|         val poster = doc.selectFirst(".mb-2 img").attr("src") ?: doc.selectFirst("head meta[property=og:image]").attr("content") | ||||
|         val title = doc.selectFirst("h1.heading-name a").text() | ||||
|         val description = doc.selectFirst("div.description p").text().trim() | ||||
|         val genres = doc.select("div.row-line a").map { it.text() } | ||||
|         val test = if (doc.selectFirst("div.dp-i-c-right").toString().contains("Airing")) ShowStatus.Ongoing else ShowStatus.Completed | ||||
|         val episodes = doc.select("div.tab-content ul li.nav-item").map { | ||||
|             val link = it.selectFirst("a").attr("href") | ||||
|             AnimeEpisode(link) | ||||
|         } | ||||
|         val type = if (doc.selectFirst(".dp-i-stats").toString().contains("Movies")) TvType.AnimeMovie else TvType.Anime | ||||
|         return newAnimeLoadResponse(title, url, type) { | ||||
|             posterUrl = poster | ||||
|             addEpisodes(DubStatus.Subbed, episodes) | ||||
|             showStatus = test | ||||
|             plot = description | ||||
|             tags = genres | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     override suspend fun loadLinks( | ||||
|         data: String, | ||||
|         isCasting: Boolean, | ||||
|         subtitleCallback: (SubtitleFile) -> Unit, | ||||
|         callback: (ExtractorLink) -> Unit | ||||
|     ): Boolean { | ||||
|         app.get(data).document.select("#servers-list ul.nav li a").apmap { | ||||
|             val server = it.attr("data-embed") | ||||
|             loadExtractor(server, data, callback) | ||||
|         } | ||||
|         return true | ||||
|     } | ||||
| } | ||||
|  | @ -1,6 +1,7 @@ | |||
| package com.lagradost.cloudstream3.animeproviders | ||||
| 
 | ||||
| import com.lagradost.cloudstream3.* | ||||
| import com.lagradost.cloudstream3.extractors.Mcloud | ||||
| import com.lagradost.cloudstream3.extractors.WcoStream | ||||
| import com.lagradost.cloudstream3.utils.ExtractorLink | ||||
| import org.json.JSONObject | ||||
|  | @ -242,6 +243,7 @@ class WcoProvider : MainAPI() { | |||
| 
 | ||||
|         for (server in servers) { | ||||
|             WcoStream().getSafeUrl(server["link"].toString(), "")?.forEach(callback) | ||||
|             Mcloud().getSafeUrl(server["link"].toString(), "")?.forEach(callback) | ||||
|         } | ||||
|         return true | ||||
|     } | ||||
|  |  | |||
|  | @ -0,0 +1,75 @@ | |||
| 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.utils.AppUtils.parseJson | ||||
| 
 | ||||
| 
 | ||||
| open class Mcloud : ExtractorApi() { | ||||
|     override val name = "Mcloud" | ||||
|     override val mainUrl = "https://mcloud.to" | ||||
|     override val requiresReferer = true | ||||
|     val headers = mapOf( | ||||
|         "Host" to "mcloud.to", | ||||
|         "User-Agent" to USER_AGENT, | ||||
|         "Accept" to "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8", | ||||
|         "Accept-Language" to "en-US,en;q=0.5", | ||||
|         "DNT" to "1", | ||||
|         "Connection" to "keep-alive", | ||||
|         "Upgrade-Insecure-Requests" to "1", | ||||
|         "Sec-Fetch-Dest" to "iframe", | ||||
|         "Sec-Fetch-Mode" to "navigate", | ||||
|         "Sec-Fetch-Site" to "cross-site", | ||||
|         "Referer" to "https://animekisa.in/", //Referer works for wco and animekisa, probably with others too | ||||
|         "Pragma" to "no-cache", | ||||
|         "Cache-Control" to "no-cache",) | ||||
|     override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink>? { | ||||
|         val link = url.replace("$mainUrl/e/","$mainUrl/info/") | ||||
|         val response = app.get(link, headers = headers).text | ||||
| 
 | ||||
|         data class Sources ( | ||||
|             @JsonProperty("file") val file: String | ||||
|         ) | ||||
| 
 | ||||
|         data class Media ( | ||||
|             @JsonProperty("sources") val sources: List<Sources> | ||||
|         ) | ||||
| 
 | ||||
|         data class JsonMcloud ( | ||||
|             @JsonProperty("success") val success: Boolean, | ||||
|             @JsonProperty("media") val media: Media, | ||||
|         ) | ||||
| 
 | ||||
|         val mapped = response.let { parseJson<JsonMcloud>(it) } | ||||
|         val sources = mutableListOf<ExtractorLink>() | ||||
| 
 | ||||
|         if (mapped.success) | ||||
|             mapped.media.sources.apmap { | ||||
|                 if (it.file.contains("m3u8")) { | ||||
|                     M3u8Helper().m3u8Generation( | ||||
|                         M3u8Helper.M3u8Stream( | ||||
|                             it.file, | ||||
|                             headers = app.get(url).headers.toMap() | ||||
|                         ), true | ||||
|                     ) | ||||
|                         .map { stream -> | ||||
|                             val qualityString = if ((stream.quality ?: 0) == 0) "" else "${stream.quality}p" | ||||
|                             sources.add( | ||||
|                                 ExtractorLink( | ||||
|                                     name, | ||||
|                                     "$name $qualityString", | ||||
|                                     stream.streamUrl, | ||||
|                                     url, | ||||
|                                     getQualityFromName(stream.quality.toString()), | ||||
|                                     true | ||||
|                                 ) | ||||
|                             ) | ||||
|                         } | ||||
|                 } | ||||
|             } | ||||
|         return sources | ||||
|     } | ||||
| } | ||||
|  | @ -7,7 +7,7 @@ import com.lagradost.cloudstream3.mapper | |||
| import com.lagradost.cloudstream3.utils.* | ||||
| 
 | ||||
| class WcoStream : ExtractorApi() { | ||||
|     override val name = "WcoStream" | ||||
|     override val name = "VidStream" //Cause works for animekisa and wco | ||||
|     override val mainUrl = "https://vidstream.pro" | ||||
|     override val requiresReferer = false | ||||
|     private val hlsHelper = M3u8Helper() | ||||
|  |  | |||
|  | @ -97,6 +97,7 @@ val extractorApis: Array<ExtractorApi> = arrayOf( | |||
|     Mp4Upload(), | ||||
|     StreamTape(), | ||||
|     MixDrop(), | ||||
|     Mcloud(), | ||||
|     XStreamCdn(), | ||||
|     StreamSB(), | ||||
|     Streamhub(), | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue