diff --git a/.idea/.gitignore b/.idea/.gitignore deleted file mode 100644 index 26d33521..00000000 --- a/.idea/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -# Default ignored files -/shelf/ -/workspace.xml diff --git a/.idea/gradle.xml b/.idea/gradle.xml index 33b144a8..1b86bb06 100644 --- a/.idea/gradle.xml +++ b/.idea/gradle.xml @@ -1,11 +1,11 @@ - \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml index 6199cc2a..4bc4fc6e 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,9 +1,5 @@ - - - - - + + \ No newline at end of file diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml deleted file mode 100644 index e96534fb..00000000 --- a/.idea/uiDesigner.xml +++ /dev/null @@ -1,124 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml index 94a25f7f..35eb1ddf 100644 --- a/.idea/vcs.xml +++ b/.idea/vcs.xml @@ -1,6 +1,6 @@ - + \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/MainAPI.kt b/app/src/main/java/com/lagradost/cloudstream3/MainAPI.kt index 3adcdc02..5493c217 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/MainAPI.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/MainAPI.kt @@ -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(), diff --git a/app/src/main/java/com/lagradost/cloudstream3/animeproviders/TenshiProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/animeproviders/TenshiProvider.kt index 83c28eb3..23bb646e 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/animeproviders/TenshiProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/animeproviders/TenshiProvider.kt @@ -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(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, diff --git a/app/src/main/java/com/lagradost/cloudstream3/animeproviders/WcoProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/animeproviders/WcoProvider.kt new file mode 100644 index 00000000..5fd1022c --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/animeproviders/WcoProvider.kt @@ -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 { + val items = soup.select(".film_list-wrap > .flw-item") + if (items.isEmpty()) return ArrayList() + val returnValue = ArrayList() + 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 { + 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 { + val returnValue: ArrayList = 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(episodeNodes?.map { + AnimeEpisode(it.attr("href")) + } + ?: ArrayList()) + 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 + } +} diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/ExtractorApi.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/ExtractorApi.kt index e388c97e..f6a7955b 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/ExtractorApi.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/ExtractorApi.kt @@ -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 = 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? { + 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? open fun getExtractorUrl(id: String): String { return id } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/extractors/MixDrop.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/extractors/MixDrop.kt index b3e2aa7d..f506645d 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/extractors/MixDrop.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/extractors/MixDrop.kt @@ -13,25 +13,21 @@ class MixDrop : ExtractorApi() { } override fun getUrl(url: String, referer: String?): List? { - 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 } } \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/extractors/Mp4Upload.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/extractors/Mp4Upload.kt index 188e9735..e8166583 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/extractors/Mp4Upload.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/extractors/Mp4Upload.kt @@ -9,25 +9,21 @@ class Mp4Upload : ExtractorApi() { override val requiresReferer = true override fun getUrl(url: String, referer: String?): List? { - 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 } } \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/extractors/MultiQuality.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/extractors/MultiQuality.kt index df668356..2450c1e2 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/extractors/MultiQuality.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/extractors/MultiQuality.kt @@ -27,44 +27,40 @@ class MultiQuality : ExtractorApi() { } override fun getUrl(url: String, referer: String?): List? { - try { - val extractedLinksList: MutableList = 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 = 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 } diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/extractors/StreamSB.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/extractors/StreamSB.kt new file mode 100644 index 00000000..388c04c4 --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/extractors/StreamSB.kt @@ -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 { + val extractedLinksList: MutableList = 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 + } +} \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/extractors/StreamTape.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/extractors/StreamTape.kt index b8661f03..aefc067d 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/extractors/StreamTape.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/extractors/StreamTape.kt @@ -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? { - 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 } diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/extractors/Vidstream.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/extractors/Vidstream.kt index 72ae464b..e89a62fa 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/extractors/Vidstream.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/extractors/Vidstream.kt @@ -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) diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/extractors/WcoStream.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/extractors/WcoStream.kt new file mode 100644 index 00000000..a124aede --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/extractors/WcoStream.kt @@ -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 { + 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 + ) + + data class WcoResponse( + @JsonProperty("success") val success: Boolean, + @JsonProperty("media") val media: Media + ) + + val mapped = response.let { mapper.readValue(it) } + val sources = mutableListOf() + + 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 + } +} diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/extractors/XStreamCdn.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/extractors/XStreamCdn.kt index 6edf65dd..b30d9179 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/extractors/XStreamCdn.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/extractors/XStreamCdn.kt @@ -38,34 +38,29 @@ class XStreamCdn : ExtractorApi() { } override fun getUrl(url: String, referer: String?): List? { - 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 = mutableListOf() - with(khttp.post(newUrl, headers = headers)) { - mapper.readValue(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 = mutableListOf() + with(khttp.post(newUrl, headers = headers)) { + mapper.readValue(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 } - } \ No newline at end of file