mirror of
				https://github.com/recloudstream/cloudstream.git
				synced 2024-08-15 01:53:11 +00:00 
			
		
		
		
	Merge branch 'my-temporary-work'
fuck git
This commit is contained in:
		
						commit
						42fe04a0b0
					
				
					 18 changed files with 440 additions and 272 deletions
				
			
		|  | @ -8,6 +8,7 @@ import com.fasterxml.jackson.module.kotlin.KotlinModule | |||
| import com.lagradost.cloudstream3.animeproviders.DubbedAnimeProvider | ||||
| import com.lagradost.cloudstream3.animeproviders.ShiroProvider | ||||
| import com.lagradost.cloudstream3.animeproviders.TenshiProvider | ||||
| import com.lagradost.cloudstream3.animeproviders.WcoProvider | ||||
| import com.lagradost.cloudstream3.movieproviders.HDMProvider | ||||
| import com.lagradost.cloudstream3.movieproviders.LookMovieProvider | ||||
| import com.lagradost.cloudstream3.movieproviders.MeloMovieProvider | ||||
|  | @ -33,6 +34,7 @@ object APIHolder { | |||
|     val apis = arrayListOf( | ||||
|         ShiroProvider(), | ||||
|         TenshiProvider(), | ||||
|         WcoProvider(), | ||||
|         MeloMovieProvider(), | ||||
|         DubbedAnimeProvider(), | ||||
|         HDMProvider(), | ||||
|  |  | |||
|  | @ -1,31 +1,24 @@ | |||
| package com.lagradost.cloudstream3.animeproviders | ||||
| 
 | ||||
| import android.annotation.SuppressLint | ||||
| import com.fasterxml.jackson.annotation.JsonProperty | ||||
| import com.fasterxml.jackson.module.kotlin.readValue | ||||
| import com.lagradost.cloudstream3.* | ||||
| import com.lagradost.cloudstream3.utils.ExtractorLink | ||||
| import com.lagradost.cloudstream3.utils.extractors.Vidstream | ||||
| import com.lagradost.cloudstream3.utils.getQualityFromName | ||||
| import khttp.structures.cookie.CookieJar | ||||
| import org.jsoup.Jsoup | ||||
| import org.jsoup.nodes.Document | ||||
| import java.util.* | ||||
| import kotlin.collections.ArrayList | ||||
| import khttp.structures.cookie.CookieJar | ||||
| import java.text.SimpleDateFormat | ||||
| 
 | ||||
| 
 | ||||
| import java.util.* | ||||
| 
 | ||||
| class TenshiProvider : MainAPI() { | ||||
| 
 | ||||
|     companion object { | ||||
|         var token: String? = null | ||||
|         var cookie: CookieJar? = null | ||||
| 
 | ||||
|         fun getType(t: String): TvType { | ||||
|             if (t.contains("OVA") || t.contains("Special"))  return TvType.ONA | ||||
|             else if (t.contains("Movie")) return TvType.Movie | ||||
|             else return TvType.Anime | ||||
|             return if (t.contains("OVA") || t.contains("Special")) TvType.ONA | ||||
|             else if (t.contains("Movie")) TvType.Movie | ||||
|             else TvType.Anime | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|  | @ -43,9 +36,7 @@ class TenshiProvider : MainAPI() { | |||
| 
 | ||||
|     private fun loadToken(): Boolean { | ||||
|         return try { | ||||
|             val response = khttp.get( | ||||
|                 "https://tenshi.moe/", | ||||
|             ) | ||||
|             val response = khttp.get(mainUrl) | ||||
|             cookie = response.cookies | ||||
|             val document = Jsoup.parse(response.text) | ||||
|             token = document.selectFirst("""meta[name="csrf-token"]""").attr("content") | ||||
|  | @ -179,7 +170,7 @@ class TenshiProvider : MainAPI() { | |||
|         return returnValue | ||||
|     } | ||||
| 
 | ||||
|     override fun load(slug: String): LoadResponse? { | ||||
|     override fun load(slug: String): LoadResponse { | ||||
|         val url = "$mainUrl/anime/${slug}" | ||||
| 
 | ||||
|         val response = khttp.get(url, timeout = 120.0, cookies=mapOf("loop-view" to "thumb")) | ||||
|  | @ -189,7 +180,6 @@ class TenshiProvider : MainAPI() { | |||
|         val japaneseTitle = document.selectFirst("span.value > span[title=\"Japanese\"]")?.parent()?.text()?.trim() | ||||
|         val canonicalTitle = document.selectFirst("header.entry-header > h1.mb-3").text().trim() | ||||
| 
 | ||||
|         val isDubbed = false | ||||
|         val episodeNodes = document.select("li[class*=\"episode\"] > a") | ||||
| 
 | ||||
|         val episodes = ArrayList<AnimeEpisode>(episodeNodes?.map { | ||||
|  | @ -212,7 +202,7 @@ class TenshiProvider : MainAPI() { | |||
|         val (year) = pattern.find(yearText)!!.destructured | ||||
| 
 | ||||
|         val poster = document.selectFirst("img.cover-image")?.attr("src") | ||||
|         val type = document.selectFirst("a[href*=\"https://tenshi.moe/type/\"]")?.text()?.trim() | ||||
|         val type = document.selectFirst("a[href*=\"$mainUrl/type/\"]")?.text()?.trim() | ||||
| 
 | ||||
|         val synopsis = document.selectFirst(".entry-description > .card-body")?.text()?.trim() | ||||
|         val genre = document.select("li.genre.meta-data > span.value").map { it?.text()?.trim().toString() } | ||||
|  | @ -232,7 +222,7 @@ class TenshiProvider : MainAPI() { | |||
|             episodes, | ||||
|             status, | ||||
|             synopsis, | ||||
|             ArrayList(genre) ?: ArrayList(), | ||||
|             ArrayList(genre), | ||||
|             ArrayList(synonyms), | ||||
|             null, | ||||
|             null, | ||||
|  |  | |||
|  | @ -0,0 +1,212 @@ | |||
| package com.lagradost.cloudstream3.animeproviders | ||||
| 
 | ||||
| import com.lagradost.cloudstream3.* | ||||
| import com.lagradost.cloudstream3.utils.ExtractorLink | ||||
| import com.lagradost.cloudstream3.utils.extractors.WcoStream | ||||
| import org.jsoup.Jsoup | ||||
| import org.jsoup.nodes.Document | ||||
| import java.util.* | ||||
| import kotlin.collections.ArrayList | ||||
| 
 | ||||
| 
 | ||||
| class WcoProvider : MainAPI() { | ||||
|     companion object { | ||||
|         fun getType(t: String): TvType { | ||||
|             return if (t.contains("OVA") || t.contains("Special")) TvType.ONA | ||||
|             else if (t.contains("Movie")) TvType.Movie | ||||
|             else TvType.Anime | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     override val mainUrl: String | ||||
|         get() = "https://wcostream.cc" | ||||
|     override val name: String | ||||
|         get() = "WCO Stream" | ||||
|     override val hasQuickSearch: Boolean | ||||
|         get() = true | ||||
| 
 | ||||
| 
 | ||||
|     private fun getSlug(href: String): String { | ||||
|         return href.replace("$mainUrl/anime/", "").replace("/", "") | ||||
|     } | ||||
| 
 | ||||
|     private fun fixAnimeLink(url: String): String { | ||||
|         val regex = "watch/([a-zA-Z\\-0-9]*)-episode".toRegex() | ||||
|         val (aniId) = regex.find(url)!!.destructured | ||||
|         return "$mainUrl/anime/$aniId" | ||||
|     } | ||||
| 
 | ||||
|     private fun parseSearchPage(soup: Document): ArrayList<SearchResponse> { | ||||
|         val items = soup.select(".film_list-wrap > .flw-item") | ||||
|         if (items.isEmpty()) return ArrayList() | ||||
|         val returnValue = ArrayList<SearchResponse>() | ||||
|         for (i in items) { | ||||
|             val href = fixAnimeLink(i.selectFirst("a").attr("href")) | ||||
|             val img = fixUrl(i.selectFirst("img").attr("data-src")) | ||||
|             val title = i.selectFirst("img").attr("title") | ||||
|             val isDub = !i.select(".pick.film-poster-quality").isEmpty() | ||||
|             val year = i.selectFirst(".film-detail.film-detail-fix > div > span:nth-child(1)").text().toIntOrNull() | ||||
|             val type = i.selectFirst(".film-detail.film-detail-fix > div > span:nth-child(3)").text() | ||||
| 
 | ||||
|             returnValue.add( | ||||
|                 if (getType(type) == TvType.Movie) { | ||||
|                     MovieSearchResponse( | ||||
|                         title, href, getSlug(href), this.name, TvType.Movie, img, year | ||||
|                     ) | ||||
|                 } else { | ||||
|                     AnimeSearchResponse( | ||||
|                         title, | ||||
|                         href, | ||||
|                         getSlug(href), | ||||
|                         this.name, | ||||
|                         TvType.Anime, | ||||
|                         img, | ||||
|                         year, | ||||
|                         null, | ||||
|                         EnumSet.of(if (isDub) DubStatus.Dubbed else DubStatus.Subbed), | ||||
|                         null, | ||||
|                         null | ||||
|                     ) | ||||
|                 } | ||||
|             ) | ||||
|         } | ||||
|         return returnValue | ||||
|     } | ||||
| 
 | ||||
|     override fun search(query: String): ArrayList<SearchResponse> { | ||||
|         val url = "$mainUrl/search" | ||||
|         val response = khttp.get(url, params=mapOf("keyword" to query)) | ||||
|         var document = Jsoup.parse(response.text) | ||||
|         val returnValue = parseSearchPage(document) | ||||
| 
 | ||||
|         while (!document.select(".pagination").isEmpty()) { | ||||
|             val link = document.select("a.page-link[rel=\"next\"]") | ||||
|             if (!link.isEmpty()) { | ||||
|                 val extraResponse = khttp.get(fixUrl(link[0].attr("href"))) | ||||
|                 document = Jsoup.parse(extraResponse.text) | ||||
|                 returnValue.addAll(parseSearchPage(document)) | ||||
|             } else { | ||||
|                 break | ||||
|             } | ||||
|         } | ||||
|         return returnValue | ||||
|     } | ||||
| 
 | ||||
|     override fun quickSearch(query: String): ArrayList<SearchResponse> { | ||||
|         val returnValue: ArrayList<SearchResponse> = ArrayList() | ||||
| 
 | ||||
|         val response = khttp.post( | ||||
|             "https://wcostream.cc/ajax/search", | ||||
|             data=mapOf("keyword" to query) | ||||
|         ).jsonObject.getString("html") // I won't make a dataclass for this shit | ||||
|         val document = Jsoup.parse(response) | ||||
| 
 | ||||
|         document.select("a.nav-item").forEach { | ||||
|             val title = it.selectFirst("img")?.attr("title").toString() | ||||
|             val img = it?.selectFirst("img")?.attr("src") | ||||
|             val href = it?.attr("href").toString() | ||||
|             val isDub = title.contains("(Dub)") | ||||
|             val filmInfo = it?.selectFirst(".film-infor") | ||||
|             val year = filmInfo?.select("span")?.get(0)?.text()?.toIntOrNull() | ||||
|             val type = filmInfo?.select("span")?.get(1)?.text().toString() | ||||
|             if (title != "null") { | ||||
|                 returnValue.add( | ||||
|                     if (getType(type) == TvType.Movie) { | ||||
|                         MovieSearchResponse( | ||||
|                             title, href, getSlug(href), this.name, TvType.Movie, img, year | ||||
|                         ) | ||||
|                     } else { | ||||
|                         AnimeSearchResponse( | ||||
|                             title, | ||||
|                             href, | ||||
|                             getSlug(href), | ||||
|                             this.name, | ||||
|                             TvType.Anime, | ||||
|                             img, | ||||
|                             year, | ||||
|                             null, | ||||
|                             EnumSet.of(if (isDub) DubStatus.Dubbed else DubStatus.Subbed), | ||||
|                             null, | ||||
|                             null | ||||
|                         ) | ||||
|                     } | ||||
|                 ) | ||||
|             } | ||||
|         } | ||||
|         return returnValue | ||||
|     } | ||||
| 
 | ||||
|     override fun load(slug: String): LoadResponse { | ||||
|         val url = "$mainUrl/anime/${slug}" | ||||
| 
 | ||||
|         val response = khttp.get(url, timeout = 120.0) | ||||
|         val document = Jsoup.parse(response.text) | ||||
| 
 | ||||
|         val japaneseTitle = document.selectFirst("div.elements div.row > div:nth-child(1) > div.row-line:nth-child(1)") | ||||
|             ?.text()?.trim()?.replace("Other names:", "")?.trim() | ||||
| 
 | ||||
|         val canonicalTitle = document.selectFirst("meta[name=\"title\"]") | ||||
|             ?.attr("content")?.split("| W")?.get(0).toString() | ||||
| 
 | ||||
|         val isDubbed = canonicalTitle.contains("Dub") | ||||
|         val episodeNodes = document.select(".tab-content .nav-item > a") | ||||
| 
 | ||||
|         val episodes = ArrayList<AnimeEpisode>(episodeNodes?.map { | ||||
|             AnimeEpisode(it.attr("href")) | ||||
|         } | ||||
|             ?: ArrayList<AnimeEpisode>()) | ||||
|         val statusElem = document.selectFirst("div.elements div.row > div:nth-child(1) > div.row-line:nth-child(2)") | ||||
|         val status = when (statusElem?.text()?.replace("Status:", "")?.trim()) { | ||||
|             "Ongoing" -> ShowStatus.Ongoing | ||||
|             "Completed" -> ShowStatus.Completed | ||||
|             else -> null | ||||
|         } | ||||
|         val yearText = document.selectFirst("div.elements div.row > div:nth-child(2) > div.row-line:nth-child(4)")?.text() | ||||
|         val year = yearText?.replace("Date release:", "")?.trim()?.split("-")?.get(0)?.toIntOrNull() | ||||
| 
 | ||||
|         val poster = document.selectFirst(".film-poster-img")?.attr("src") | ||||
|         val type = document.selectFirst("span.item.mr-1 > a")?.text()?.trim() | ||||
| 
 | ||||
|         val synopsis = document.selectFirst(".description > p")?.text()?.trim() | ||||
|         val genre = document.select("div.elements div.row > div:nth-child(1) > div.row-line:nth-child(5) > a").map { it?.text()?.trim().toString() } | ||||
| 
 | ||||
|         return AnimeLoadResponse( | ||||
|             canonicalTitle, | ||||
|             japaneseTitle, | ||||
|             canonicalTitle, | ||||
|             "$mainUrl/anime/${slug}", | ||||
|             this.name, | ||||
|             getType(type ?: ""), | ||||
|             poster, | ||||
|             year, | ||||
|             if(isDubbed) episodes else null, | ||||
|             if(!isDubbed) episodes else null, | ||||
|             status, | ||||
|             synopsis, | ||||
|             ArrayList(genre), | ||||
|             ArrayList(), | ||||
|         ) | ||||
|     } | ||||
| 
 | ||||
|     override fun loadLinks( | ||||
|         data: String, | ||||
|         isCasting: Boolean, | ||||
|         subtitleCallback: (SubtitleFile) -> Unit, | ||||
|         callback: (ExtractorLink) -> Unit | ||||
|     ): Boolean { | ||||
|         val response = khttp.get(data) | ||||
|         val servers = Jsoup.parse(response.text).select("#servers-list > ul > li").map { | ||||
|             mapOf( | ||||
|                 "link" to it?.selectFirst("a")?.attr("data-embed"), | ||||
|                 "title" to it?.selectFirst("span")?.text()?.trim() | ||||
|             ) | ||||
|         } | ||||
| 
 | ||||
|         for (server in servers) { | ||||
|             WcoStream().getSafeUrl(server["link"].toString(), "")?.forEach { | ||||
|                 callback.invoke(it) | ||||
|             } | ||||
|         } | ||||
|         return true | ||||
|     } | ||||
| } | ||||
|  | @ -1,10 +1,7 @@ | |||
| package com.lagradost.cloudstream3.utils | ||||
| 
 | ||||
| import com.lagradost.cloudstream3.utils.extractors.MixDrop | ||||
| import com.lagradost.cloudstream3.utils.extractors.Mp4Upload | ||||
| import com.lagradost.cloudstream3.utils.extractors.Shiro | ||||
| import com.lagradost.cloudstream3.utils.extractors.StreamTape | ||||
| import com.lagradost.cloudstream3.utils.extractors.XStreamCdn | ||||
| import com.lagradost.cloudstream3.mvvm.normalSafeApiCall | ||||
| import com.lagradost.cloudstream3.utils.extractors.* | ||||
| 
 | ||||
| data class ExtractorLink( | ||||
|     val source: String, | ||||
|  | @ -54,10 +51,12 @@ fun getAndUnpack(string: String): String? { | |||
| val extractorApis: Array<ExtractorApi> = arrayOf( | ||||
|     //AllProvider(), | ||||
|     Shiro(), | ||||
|     WcoStream(), | ||||
|     Mp4Upload(), | ||||
|     StreamTape(), | ||||
|     MixDrop(), | ||||
|     XStreamCdn() | ||||
|     XStreamCdn(), | ||||
|     StreamSB(), | ||||
| ) | ||||
| 
 | ||||
| fun getExtractorApiFromName(name: String): ExtractorApi { | ||||
|  | @ -80,9 +79,16 @@ abstract class ExtractorApi { | |||
|     abstract val mainUrl: String | ||||
|     abstract val requiresReferer: Boolean | ||||
| 
 | ||||
|     fun getSafeUrl(url: String, referer: String? = null): List<ExtractorLink>? { | ||||
|         return normalSafeApiCall { getUrl(url, referer) } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Will throw errors, use getSafeUrl if you don't want to handle the exception yourself | ||||
|      */ | ||||
|     abstract fun getUrl(url: String, referer: String? = null): List<ExtractorLink>? | ||||
| 
 | ||||
|     open fun getExtractorUrl(id: String): String { | ||||
|         return id | ||||
|     } | ||||
| } | ||||
| } | ||||
|  |  | |||
|  | @ -13,25 +13,21 @@ class MixDrop : ExtractorApi() { | |||
|     } | ||||
| 
 | ||||
|     override fun getUrl(url: String, referer: String?): List<ExtractorLink>? { | ||||
|         try { | ||||
|             with(khttp.get(url)) { | ||||
|                 getAndUnpack(this.text)?.let { unpackedText -> | ||||
|                     srcRegex.find(unpackedText)?.groupValues?.get(1)?.let { link -> | ||||
|                         return listOf( | ||||
|                             ExtractorLink( | ||||
|                                 name, | ||||
|                                 name, | ||||
|                                 httpsify(link), | ||||
|                                 url, | ||||
|                                 Qualities.Unknown.value, | ||||
|                             ) | ||||
|         with(khttp.get(url)) { | ||||
|             getAndUnpack(this.text)?.let { unpackedText -> | ||||
|                 srcRegex.find(unpackedText)?.groupValues?.get(1)?.let { link -> | ||||
|                     return listOf( | ||||
|                         ExtractorLink( | ||||
|                             name, | ||||
|                             name, | ||||
|                             httpsify(link), | ||||
|                             url, | ||||
|                             Qualities.Unknown.value, | ||||
|                         ) | ||||
|                     } | ||||
|                     ) | ||||
|                 } | ||||
|             } | ||||
|             return null | ||||
|         } catch (e: Exception) { | ||||
|             return null | ||||
|         } | ||||
|         return null | ||||
|     } | ||||
| } | ||||
|  | @ -9,25 +9,21 @@ class Mp4Upload : ExtractorApi() { | |||
|     override val requiresReferer = true | ||||
| 
 | ||||
|     override fun getUrl(url: String, referer: String?): List<ExtractorLink>? { | ||||
|         try { | ||||
|             with(khttp.get(url)) { | ||||
|                 getAndUnpack(this.text)?.let { unpackedText -> | ||||
|                     srcRegex.find(unpackedText)?.groupValues?.get(1)?.let { link -> | ||||
|                         return listOf( | ||||
|                             ExtractorLink( | ||||
|                                 name, | ||||
|                                 name, | ||||
|                                 link, | ||||
|                                 url, | ||||
|                                 Qualities.Unknown.value, | ||||
|                             ) | ||||
|         with(khttp.get(url)) { | ||||
|             getAndUnpack(this.text)?.let { unpackedText -> | ||||
|                 srcRegex.find(unpackedText)?.groupValues?.get(1)?.let { link -> | ||||
|                     return listOf( | ||||
|                         ExtractorLink( | ||||
|                             name, | ||||
|                             name, | ||||
|                             link, | ||||
|                             url, | ||||
|                             Qualities.Unknown.value, | ||||
|                         ) | ||||
|                     } | ||||
|                     ) | ||||
|                 } | ||||
|             } | ||||
|             return null | ||||
|         } catch (e: Exception) { | ||||
|             return null | ||||
|         } | ||||
|         return null | ||||
|     } | ||||
| } | ||||
|  | @ -27,44 +27,40 @@ class MultiQuality : ExtractorApi() { | |||
|     } | ||||
| 
 | ||||
|     override fun getUrl(url: String, referer: String?): List<ExtractorLink>? { | ||||
|         try { | ||||
|             val extractedLinksList: MutableList<ExtractorLink> = mutableListOf() | ||||
|             with(khttp.get(url)) { | ||||
|                 sourceRegex.findAll(this.text).forEach { sourceMatch -> | ||||
|                     val extractedUrl = sourceMatch.groupValues[1] | ||||
|                     // Trusting this isn't mp4, may fuck up stuff | ||||
|                     if (extractedUrl.endsWith(".m3u8")) { | ||||
|                         with(khttp.get(extractedUrl)) { | ||||
|                             m3u8Regex.findAll(this.text).forEach { match -> | ||||
|                                 extractedLinksList.add( | ||||
|                                     ExtractorLink( | ||||
|                                         name, | ||||
|                                         "$name ${match.groupValues[1]}p", | ||||
|                                         urlRegex.find(this.url)!!.groupValues[1] + match.groupValues[0], | ||||
|                                         url, | ||||
|                                         getQuality(match.groupValues[1]), | ||||
|                                         isM3u8 = true | ||||
|                                     ) | ||||
|         val extractedLinksList: MutableList<ExtractorLink> = mutableListOf() | ||||
|         with(khttp.get(url)) { | ||||
|             sourceRegex.findAll(this.text).forEach { sourceMatch -> | ||||
|                 val extractedUrl = sourceMatch.groupValues[1] | ||||
|                 // Trusting this isn't mp4, may fuck up stuff | ||||
|                 if (extractedUrl.endsWith(".m3u8")) { | ||||
|                     with(khttp.get(extractedUrl)) { | ||||
|                         m3u8Regex.findAll(this.text).forEach { match -> | ||||
|                             extractedLinksList.add( | ||||
|                                 ExtractorLink( | ||||
|                                     name, | ||||
|                                     "$name ${match.groupValues[1]}p", | ||||
|                                     urlRegex.find(this.url)!!.groupValues[1] + match.groupValues[0], | ||||
|                                     url, | ||||
|                                     getQuality(match.groupValues[1]), | ||||
|                                     isM3u8 = true | ||||
|                                 ) | ||||
|                             } | ||||
| 
 | ||||
|                         } | ||||
|                     } else if (extractedUrl.endsWith(".mp4")) { | ||||
|                         extractedLinksList.add( | ||||
|                             ExtractorLink( | ||||
|                                 name, | ||||
|                                 "$name ${sourceMatch.groupValues[2]}", | ||||
|                                 extractedUrl, | ||||
|                                 url.replace(" ", "%20"), | ||||
|                                 Qualities.Unknown.value, | ||||
|                             ) | ||||
|                         ) | ||||
|                     } | ||||
|                 } | ||||
|                 return extractedLinksList | ||||
|             } | ||||
|         } catch (e: Exception) { | ||||
|                         } | ||||
| 
 | ||||
|                     } | ||||
|                 } else if (extractedUrl.endsWith(".mp4")) { | ||||
|                     extractedLinksList.add( | ||||
|                         ExtractorLink( | ||||
|                             name, | ||||
|                             "$name ${sourceMatch.groupValues[2]}", | ||||
|                             extractedUrl, | ||||
|                             url.replace(" ", "%20"), | ||||
|                             Qualities.Unknown.value, | ||||
|                         ) | ||||
|                     ) | ||||
|                 } | ||||
|             } | ||||
|             return extractedLinksList | ||||
|         } | ||||
|         return null | ||||
|     } | ||||
|  |  | |||
|  | @ -0,0 +1,51 @@ | |||
| package com.lagradost.cloudstream3.utils.extractors | ||||
| 
 | ||||
| import com.lagradost.cloudstream3.utils.ExtractorApi | ||||
| import com.lagradost.cloudstream3.utils.ExtractorLink | ||||
| import com.lagradost.cloudstream3.utils.getAndUnpack | ||||
| import com.lagradost.cloudstream3.utils.getQualityFromName | ||||
| 
 | ||||
| class StreamSB : ExtractorApi() { | ||||
|     override val name: String = "StreamSB" | ||||
|     override val mainUrl: String = "https://sbplay.org" | ||||
|     private val sourceRegex = Regex("""sources:[\W\w]*?file:\s*"(.*?)"""") | ||||
| 
 | ||||
|     //private val m3u8Regex = Regex(""".*?(\d*).m3u8""") | ||||
|     //private val urlRegex = Regex("""(.*?)([^/]+$)""") | ||||
| 
 | ||||
|     // 1: Resolution 2: url | ||||
|     private val m3u8UrlRegex = Regex("""RESOLUTION=\d*x(\d*).*\n(http.*.m3u8)""") | ||||
|     override val requiresReferer = false | ||||
| 
 | ||||
|     // 	https://sbembed.com/embed-ns50b0cukf9j.html   ->   https://sbvideo.net/play/ns50b0cukf9j | ||||
|     override fun getUrl(url: String, referer: String?): List<ExtractorLink> { | ||||
|         val extractedLinksList: MutableList<ExtractorLink> = mutableListOf() | ||||
|         val newUrl = url.replace("sbplay.org/embed-", "sbplay.org/play/").removeSuffix(".html") | ||||
|         with(khttp.get(newUrl, timeout = 10.0)) { | ||||
|             getAndUnpack(this.text)?.let { | ||||
|                 sourceRegex.findAll(it).forEach { sourceMatch -> | ||||
|                     val extractedUrl = sourceMatch.groupValues[1] | ||||
|                     if (extractedUrl.contains(".m3u8")) { | ||||
|                         with(khttp.get(extractedUrl)) { | ||||
|                             m3u8UrlRegex.findAll(this.text).forEach { match -> | ||||
|                                 val extractedUrlM3u8 = match.groupValues[2] | ||||
|                                 val extractedRes = match.groupValues[1] | ||||
|                                 extractedLinksList.add( | ||||
|                                     ExtractorLink( | ||||
|                                         name, | ||||
|                                         "$name ${extractedRes}p", | ||||
|                                         extractedUrlM3u8, | ||||
|                                         extractedUrl, | ||||
|                                         getQualityFromName(extractedRes), | ||||
|                                         true | ||||
|                                     ) | ||||
|                                 ) | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         return extractedLinksList | ||||
|     } | ||||
| } | ||||
|  | @ -14,22 +14,19 @@ class StreamTape : ExtractorApi() { | |||
|         Regex("""(i(|" \+ ')d(|" \+ ')=.*?&(|" \+ ')e(|" \+ ')x(|" \+ ')p(|" \+ ')i(|" \+ ')r(|" \+ ')e(|" \+ ')s(|" \+ ')=.*?&(|" \+ ')i(|" \+ ')p(|" \+ ')=.*?&(|" \+ ')t(|" \+ ')o(|" \+ ')k(|" \+ ')e(|" \+ ')n(|" \+ ')=.*)'""") | ||||
| 
 | ||||
|     override fun getUrl(url: String, referer: String?): List<ExtractorLink>? { | ||||
|         try { | ||||
|             with(khttp.get(url)) { | ||||
|                 linkRegex.find(this.text)?.let { | ||||
|                     val extractedUrl = "https://streamtape.com/get_video?${it.groupValues[1]}".replace("""" + '""", "") | ||||
|                     return listOf( | ||||
|                         ExtractorLink( | ||||
|                             name, | ||||
|                             name, | ||||
|                             extractedUrl, | ||||
|                             url, | ||||
|                             Qualities.Unknown.value, | ||||
|                         ) | ||||
|         with(khttp.get(url)) { | ||||
|             linkRegex.find(this.text)?.let { | ||||
|                 val extractedUrl = "https://streamtape.com/get_video?${it.groupValues[1]}".replace("""" + '""", "") | ||||
|                 return listOf( | ||||
|                     ExtractorLink( | ||||
|                         name, | ||||
|                         name, | ||||
|                         extractedUrl, | ||||
|                         url, | ||||
|                         Qualities.Unknown.value, | ||||
|                     ) | ||||
|                 } | ||||
|                 ) | ||||
|             } | ||||
|         } catch (e: Exception) { | ||||
|         } | ||||
|         return null | ||||
|     } | ||||
|  |  | |||
|  | @ -20,7 +20,7 @@ class Vidstream { | |||
|         try { | ||||
|             normalApis.pmap { api -> | ||||
|                 val url = api.getExtractorUrl(id) | ||||
|                 val source = api.getUrl(url) | ||||
|                 val source = api.getSafeUrl(url) | ||||
|                 source?.forEach { callback.invoke(it) } | ||||
|             } | ||||
| 
 | ||||
|  | @ -38,7 +38,7 @@ class Vidstream { | |||
|                     // Matches vidstream links with extractors | ||||
|                     extractorApis.filter { !it.requiresReferer || !isCasting }.pmap { api -> | ||||
|                         if (link.startsWith(api.mainUrl)) { | ||||
|                             val extractedLinks = api.getUrl(link, url) | ||||
|                             val extractedLinks = api.getSafeUrl(link, url) | ||||
|                             if (extractedLinks?.isNotEmpty() == true) { | ||||
|                                 extractedLinks.forEach { | ||||
|                                     callback.invoke(it) | ||||
|  |  | |||
|  | @ -0,0 +1,58 @@ | |||
| package com.lagradost.cloudstream3.utils.extractors | ||||
| 
 | ||||
| import com.fasterxml.jackson.annotation.JsonProperty | ||||
| import com.fasterxml.jackson.module.kotlin.readValue | ||||
| import com.lagradost.cloudstream3.utils.* | ||||
| import com.lagradost.cloudstream3.mapper | ||||
| 
 | ||||
| class WcoStream : ExtractorApi() { | ||||
|     override val name: String = "WcoStream" | ||||
|     override val mainUrl: String = "https://vidstream.pro" | ||||
|     override val requiresReferer = false | ||||
| 
 | ||||
|     override fun getUrl(url: String, referer: String?): List<ExtractorLink> { | ||||
|         val baseUrl = url.split("/e/")[0] | ||||
| 
 | ||||
|         val html = khttp.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 apiLink = "$baseUrl/info/$Id?domain=wcostream.cc&skey=$skey" | ||||
|         val referrer = "$baseUrl/e/$Id?domain=wcostream.cc" | ||||
| 
 | ||||
|         val response = khttp.get(apiLink, headers = mapOf("Referer" to referrer)).text | ||||
| 
 | ||||
|         data class Sources( | ||||
|             @JsonProperty("file") val file: String, | ||||
|             @JsonProperty("label") val label: String? | ||||
|         ) | ||||
| 
 | ||||
|         data class Media( | ||||
|             @JsonProperty("sources") val sources: List<Sources> | ||||
|         ) | ||||
| 
 | ||||
|         data class WcoResponse( | ||||
|             @JsonProperty("success") val success: Boolean, | ||||
|             @JsonProperty("media") val media: Media | ||||
|         ) | ||||
| 
 | ||||
|         val mapped = response.let { mapper.readValue<WcoResponse>(it) } | ||||
|         val sources = mutableListOf<ExtractorLink>() | ||||
| 
 | ||||
|         if (mapped.success) { | ||||
|             mapped.media.sources.forEach { | ||||
|                 sources.add( | ||||
|                     ExtractorLink( | ||||
|                         name, | ||||
|                         name + if (it.label != null) "- ${it.label}" else "", | ||||
|                         it.file, | ||||
|                         "", | ||||
|                         Qualities.HD.value, | ||||
|                         it.file.contains(".m3u8") | ||||
|                     ) | ||||
|                 ) | ||||
|             } | ||||
|         } | ||||
|         return sources | ||||
|     } | ||||
| } | ||||
|  | @ -38,34 +38,29 @@ class XStreamCdn : ExtractorApi() { | |||
|     } | ||||
| 
 | ||||
|     override fun getUrl(url: String, referer: String?): List<ExtractorLink>? { | ||||
|         try { | ||||
|             val headers = mapOf( | ||||
|                 "Referer" to url, | ||||
|                 "User-Agent" to "Mozilla/5.0 (Windows NT 10.0; rv:78.0) Gecko/20100101 Firefox/78.0", | ||||
|             ) | ||||
|             val newUrl = url.replace("$mainUrl/v/", "$mainUrl/api/source/") | ||||
|             val extractedLinksList: MutableList<ExtractorLink> = mutableListOf() | ||||
|             with(khttp.post(newUrl, headers = headers)) { | ||||
|                 mapper.readValue<ResponseJson?>(this.text)?.let { | ||||
|                     if (it.success && it.data != null) { | ||||
|                         it.data.forEach { data -> | ||||
|                             extractedLinksList.add( | ||||
|                                 ExtractorLink( | ||||
|                                     name, | ||||
|                                     "$name ${data.label}", | ||||
|                                     data.file, | ||||
|                                     url, | ||||
|                                     getQuality(data.label), | ||||
|                                 ) | ||||
|         val headers = mapOf( | ||||
|             "Referer" to url, | ||||
|             "User-Agent" to "Mozilla/5.0 (Windows NT 10.0; rv:78.0) Gecko/20100101 Firefox/78.0", | ||||
|         ) | ||||
|         val newUrl = url.replace("$mainUrl/v/", "$mainUrl/api/source/") | ||||
|         val extractedLinksList: MutableList<ExtractorLink> = mutableListOf() | ||||
|         with(khttp.post(newUrl, headers = headers)) { | ||||
|             mapper.readValue<ResponseJson?>(this.text)?.let { | ||||
|                 if (it.success && it.data != null) { | ||||
|                     it.data.forEach { data -> | ||||
|                         extractedLinksList.add( | ||||
|                             ExtractorLink( | ||||
|                                 name, | ||||
|                                 "$name ${data.label}", | ||||
|                                 data.file, | ||||
|                                 url, | ||||
|                                 getQuality(data.label), | ||||
|                             ) | ||||
|                         } | ||||
|                         ) | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|             return extractedLinksList | ||||
|         } catch (e: Exception) { | ||||
|         } | ||||
|         return null | ||||
|         return extractedLinksList | ||||
|     } | ||||
| 
 | ||||
| } | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue