forked from recloudstream/cloudstream
Added VidEmbed with the help of Arjix :)
This commit is contained in:
parent
711397c257
commit
afeb0785a4
7 changed files with 299 additions and 56 deletions
|
@ -1,6 +1,5 @@
|
||||||
package com.lagradost.cloudstream3
|
package com.lagradost.cloudstream3
|
||||||
|
|
||||||
import android.app.Activity
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import androidx.preference.PreferenceManager
|
import androidx.preference.PreferenceManager
|
||||||
import com.fasterxml.jackson.databind.DeserializationFeature
|
import com.fasterxml.jackson.databind.DeserializationFeature
|
||||||
|
@ -10,11 +9,10 @@ import com.lagradost.cloudstream3.animeproviders.*
|
||||||
import com.lagradost.cloudstream3.movieproviders.*
|
import com.lagradost.cloudstream3.movieproviders.*
|
||||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import kotlin.collections.ArrayList
|
|
||||||
import kotlin.collections.HashSet
|
|
||||||
|
|
||||||
const val USER_AGENT =
|
const val USER_AGENT =
|
||||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"
|
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"
|
||||||
|
|
||||||
//val baseHeader = mapOf("User-Agent" to USER_AGENT)
|
//val baseHeader = mapOf("User-Agent" to USER_AGENT)
|
||||||
val mapper = JsonMapper.builder().addModule(KotlinModule())
|
val mapper = JsonMapper.builder().addModule(KotlinModule())
|
||||||
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false).build()!!
|
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false).build()!!
|
||||||
|
@ -44,7 +42,8 @@ object APIHolder {
|
||||||
WatchCartoonOnlineProvider(),
|
WatchCartoonOnlineProvider(),
|
||||||
AllMoviesForYouProvider(),
|
AllMoviesForYouProvider(),
|
||||||
AsiaFlixProvider(),
|
AsiaFlixProvider(),
|
||||||
ThenosProvider()
|
ThenosProvider(),
|
||||||
|
VidEmbedProvider()
|
||||||
)
|
)
|
||||||
|
|
||||||
val restrictedApis = arrayListOf(
|
val restrictedApis = arrayListOf(
|
||||||
|
@ -87,11 +86,11 @@ object APIHolder {
|
||||||
val list = HashSet<String>()
|
val list = HashSet<String>()
|
||||||
for (name in set) {
|
for (name in set) {
|
||||||
val api = getApiFromNameNull(name) ?: continue
|
val api = getApiFromNameNull(name) ?: continue
|
||||||
if(activeLangs.contains(api.lang) ) {
|
if (activeLangs.contains(api.lang)) {
|
||||||
list.add(name)
|
list.add(name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(list.isEmpty()) return hashSet
|
if (list.isEmpty()) return hashSet
|
||||||
return list
|
return list
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,7 +118,7 @@ object APIHolder {
|
||||||
hashSet.toMutableSet()
|
hashSet.toMutableSet()
|
||||||
)
|
)
|
||||||
|
|
||||||
if(list.isNullOrEmpty()) return hashSet
|
if (list.isNullOrEmpty()) return hashSet
|
||||||
return list.toHashSet()
|
return list.toHashSet()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -132,11 +131,11 @@ object APIHolder {
|
||||||
hashSet.map { it.name }.toMutableSet()
|
hashSet.map { it.name }.toMutableSet()
|
||||||
)
|
)
|
||||||
|
|
||||||
if(list.isNullOrEmpty()) return hashSet
|
if (list.isNullOrEmpty()) return hashSet
|
||||||
|
|
||||||
val names = TvType.values().map { it.name }.toHashSet()
|
val names = TvType.values().map { it.name }.toHashSet()
|
||||||
val realSet = list.filter { names.contains(it) }.map { TvType.valueOf(it) }.toHashSet()
|
val realSet = list.filter { names.contains(it) }.map { TvType.valueOf(it) }.toHashSet()
|
||||||
if(realSet.isEmpty()) return hashSet
|
if (realSet.isEmpty()) return hashSet
|
||||||
|
|
||||||
return realSet
|
return realSet
|
||||||
}
|
}
|
||||||
|
@ -380,7 +379,7 @@ data class AnimeEpisode(
|
||||||
val date: String? = null,
|
val date: String? = null,
|
||||||
val rating: Int? = null,
|
val rating: Int? = null,
|
||||||
val descript: String? = null,
|
val descript: String? = null,
|
||||||
val episode : Int? = null,
|
val episode: Int? = null,
|
||||||
)
|
)
|
||||||
|
|
||||||
data class TorrentLoadResponse(
|
data class TorrentLoadResponse(
|
||||||
|
|
|
@ -1,34 +0,0 @@
|
||||||
package com.lagradost.cloudstream3.extractors
|
|
||||||
|
|
||||||
import com.lagradost.cloudstream3.utils.ExtractorApi
|
|
||||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
|
||||||
import com.lagradost.cloudstream3.utils.Qualities
|
|
||||||
import org.jsoup.Jsoup
|
|
||||||
|
|
||||||
class Shiro : ExtractorApi() {
|
|
||||||
override val name: String = "Shiro"
|
|
||||||
override val mainUrl: String = "https://cherry.subsplea.se"
|
|
||||||
override val requiresReferer = false
|
|
||||||
|
|
||||||
override fun getExtractorUrl(id: String): String {
|
|
||||||
return "$mainUrl/$id"
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getUrl(url: String, referer: String?): List<ExtractorLink>? {
|
|
||||||
val headers = mapOf("Referer" to "https://shiro.is/")
|
|
||||||
val res = khttp.get(url, headers = headers).text
|
|
||||||
Jsoup.parse(res).select("source").firstOrNull()?.attr("src")?.replace("&", "?")?.let {
|
|
||||||
return listOf(
|
|
||||||
ExtractorLink(
|
|
||||||
name,
|
|
||||||
name,
|
|
||||||
it.replace(" ", "%20"),
|
|
||||||
"https://cherry.subsplea.se/",
|
|
||||||
// UHD to give top priority
|
|
||||||
Qualities.P2160.value
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,19 +1,29 @@
|
||||||
package com.lagradost.cloudstream3.extractors
|
package com.lagradost.cloudstream3.extractors
|
||||||
|
|
||||||
|
import com.lagradost.cloudstream3.mvvm.normalSafeApiCall
|
||||||
import com.lagradost.cloudstream3.pmap
|
import com.lagradost.cloudstream3.pmap
|
||||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||||
import com.lagradost.cloudstream3.utils.extractorApis
|
import com.lagradost.cloudstream3.utils.extractorApis
|
||||||
|
import com.lagradost.cloudstream3.utils.getQualityFromName
|
||||||
import org.jsoup.Jsoup
|
import org.jsoup.Jsoup
|
||||||
|
|
||||||
class Vidstream {
|
/**
|
||||||
|
* overrideMainUrl is necessary for for other vidstream clones like vidembed.cc
|
||||||
|
* If they diverge it'd be better to make them separate.
|
||||||
|
* */
|
||||||
|
class Vidstream(overrideMainUrl: String? = null) {
|
||||||
val name: String = "Vidstream"
|
val name: String = "Vidstream"
|
||||||
private val mainUrl: String = "https://gogo-stream.com"
|
private val mainUrl: String = overrideMainUrl ?: "https://gogo-stream.com"
|
||||||
|
|
||||||
private fun getExtractorUrl(id: String): String {
|
private fun getExtractorUrl(id: String): String {
|
||||||
return "$mainUrl/streaming.php?id=$id"
|
return "$mainUrl/streaming.php?id=$id"
|
||||||
}
|
}
|
||||||
|
|
||||||
private val normalApis = arrayListOf(Shiro(), MultiQuality())
|
private fun getDownloadUrl(id: String): String {
|
||||||
|
return "$mainUrl/download?id=$id"
|
||||||
|
}
|
||||||
|
|
||||||
|
private val normalApis = arrayListOf(MultiQuality())
|
||||||
|
|
||||||
// https://gogo-stream.com/streaming.php?id=MTE3NDg5
|
// https://gogo-stream.com/streaming.php?id=MTE3NDg5
|
||||||
fun getUrl(id: String, isCasting: Boolean = false, callback: (ExtractorLink) -> Unit): Boolean {
|
fun getUrl(id: String, isCasting: Boolean = false, callback: (ExtractorLink) -> Unit): Boolean {
|
||||||
|
@ -23,22 +33,47 @@ class Vidstream {
|
||||||
val source = api.getSafeUrl(url)
|
val source = api.getSafeUrl(url)
|
||||||
source?.forEach { callback.invoke(it) }
|
source?.forEach { callback.invoke(it) }
|
||||||
}
|
}
|
||||||
|
val extractorUrl = getExtractorUrl(id)
|
||||||
|
|
||||||
val url = getExtractorUrl(id)
|
/** Stolen from GogoanimeProvider.kt extractor */
|
||||||
with(khttp.get(url)) {
|
normalSafeApiCall {
|
||||||
|
val link = getDownloadUrl(id)
|
||||||
|
val page = khttp.get(link, headers = mapOf("Referer" to extractorUrl))
|
||||||
|
val pageDoc = Jsoup.parse(page.text)
|
||||||
|
val qualityRegex = Regex("(\\d+)P")
|
||||||
|
|
||||||
|
pageDoc.select(".dowload > a[download]").forEach {
|
||||||
|
val qual = if (it.text()
|
||||||
|
.contains("HDP")
|
||||||
|
) "1080" else qualityRegex.find(it.text())?.destructured?.component1().toString()
|
||||||
|
|
||||||
|
callback.invoke(
|
||||||
|
ExtractorLink(
|
||||||
|
this.name,
|
||||||
|
if (qual == "null") this.name else "${this.name} - " + qual + "p",
|
||||||
|
it.attr("href"),
|
||||||
|
page.url,
|
||||||
|
getQualityFromName(qual),
|
||||||
|
it.attr("href").contains(".m3u8")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
with(khttp.get(extractorUrl)) {
|
||||||
val document = Jsoup.parse(this.text)
|
val document = Jsoup.parse(this.text)
|
||||||
val primaryLinks = document.select("ul.list-server-items > li.linkserver")
|
val primaryLinks = document.select("ul.list-server-items > li.linkserver")
|
||||||
//val extractedLinksList: MutableList<ExtractorLink> = mutableListOf()
|
//val extractedLinksList: MutableList<ExtractorLink> = mutableListOf()
|
||||||
|
|
||||||
// All vidstream links passed to extractors
|
// All vidstream links passed to extractors
|
||||||
primaryLinks.forEach { element ->
|
primaryLinks.distinctBy { it.attr("data-video") }.forEach { element ->
|
||||||
val link = element.attr("data-video")
|
val link = element.attr("data-video")
|
||||||
//val name = element.text()
|
//val name = element.text()
|
||||||
|
|
||||||
// Matches vidstream links with extractors
|
// Matches vidstream links with extractors
|
||||||
extractorApis.filter { !it.requiresReferer || !isCasting }.pmap { api ->
|
extractorApis.filter { !it.requiresReferer || !isCasting }.pmap { api ->
|
||||||
if (link.startsWith(api.mainUrl)) {
|
if (link.startsWith(api.mainUrl)) {
|
||||||
val extractedLinks = api.getSafeUrl(link, url)
|
val extractedLinks = api.getSafeUrl(link, extractorUrl)
|
||||||
if (extractedLinks?.isNotEmpty() == true) {
|
if (extractedLinks?.isNotEmpty() == true) {
|
||||||
extractedLinks.forEach {
|
extractedLinks.forEach {
|
||||||
callback.invoke(it)
|
callback.invoke(it)
|
||||||
|
|
|
@ -45,6 +45,7 @@ class XStreamCdn : ExtractorApi() {
|
||||||
val newUrl = url.replace("$mainUrl/v/", "$mainUrl/api/source/")
|
val newUrl = url.replace("$mainUrl/v/", "$mainUrl/api/source/")
|
||||||
val extractedLinksList: MutableList<ExtractorLink> = mutableListOf()
|
val extractedLinksList: MutableList<ExtractorLink> = mutableListOf()
|
||||||
with(khttp.post(newUrl, headers = headers)) {
|
with(khttp.post(newUrl, headers = headers)) {
|
||||||
|
if (this.text == """{"success":false,"data":"Video not found or has been removed"}""") return listOf()
|
||||||
mapper.readValue<ResponseJson?>(this.text)?.let {
|
mapper.readValue<ResponseJson?>(this.text)?.let {
|
||||||
if (it.success && it.data != null) {
|
if (it.success && it.data != null) {
|
||||||
it.data.forEach { data ->
|
it.data.forEach { data ->
|
||||||
|
|
|
@ -0,0 +1,243 @@
|
||||||
|
package com.lagradost.cloudstream3.movieproviders
|
||||||
|
|
||||||
|
import org.jsoup.Jsoup
|
||||||
|
import com.lagradost.cloudstream3.*
|
||||||
|
import com.lagradost.cloudstream3.extractors.Vidstream
|
||||||
|
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||||
|
import com.lagradost.cloudstream3.utils.getQualityFromName
|
||||||
|
import java.util.*
|
||||||
|
import kotlin.collections.ArrayList
|
||||||
|
|
||||||
|
|
||||||
|
class VidEmbedProvider : MainAPI() {
|
||||||
|
override val mainUrl: String
|
||||||
|
get() = "https://vidembed.cc"
|
||||||
|
override val name: String
|
||||||
|
get() = "VidEmbed"
|
||||||
|
override val hasQuickSearch: Boolean
|
||||||
|
get() = false
|
||||||
|
override val hasMainPage: Boolean
|
||||||
|
get() = true
|
||||||
|
|
||||||
|
private fun fixUrl(url: String): String {
|
||||||
|
return if (url.startsWith("//")) {
|
||||||
|
"https:$url"
|
||||||
|
} else if (url.startsWith("/")) {
|
||||||
|
"$mainUrl$url"
|
||||||
|
} else {
|
||||||
|
url
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override val supportedTypes: Set<TvType>
|
||||||
|
get() = setOf(TvType.Anime, TvType.AnimeMovie, TvType.TvSeries, TvType.Movie)
|
||||||
|
|
||||||
|
override fun search(query: String): ArrayList<SearchResponse> {
|
||||||
|
val link = "$mainUrl/search.html?keyword=$query"
|
||||||
|
val html = khttp.get(link).text
|
||||||
|
val soup = Jsoup.parse(html)
|
||||||
|
|
||||||
|
return ArrayList(soup.select(".listing.items > .video-block").map { li ->
|
||||||
|
val href = fixUrl(li.selectFirst("a").attr("href"))
|
||||||
|
val poster = li.selectFirst("img")?.attr("src")
|
||||||
|
val title = li.selectFirst(".name").text()
|
||||||
|
val year = li.selectFirst(".date")?.text()?.split("-")?.get(0)?.toIntOrNull()
|
||||||
|
|
||||||
|
TvSeriesSearchResponse(
|
||||||
|
if (!title.contains("Episode")) title else title.split("Episode")[0].trim(),
|
||||||
|
href,
|
||||||
|
this.name,
|
||||||
|
TvType.TvSeries,
|
||||||
|
poster, year,
|
||||||
|
null
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun load(url: String): LoadResponse? {
|
||||||
|
val html = khttp.get(url).text
|
||||||
|
val soup = Jsoup.parse(html)
|
||||||
|
|
||||||
|
var title = soup.selectFirst("h1,h2,h3").text()
|
||||||
|
title = if (!title.contains("Episode")) title else title.split("Episode")[0].trim()
|
||||||
|
|
||||||
|
val description = soup.selectFirst(".post-entry")?.text()?.trim()
|
||||||
|
var poster: String? = null
|
||||||
|
|
||||||
|
val episodes = soup.select(".listing.items.lists > .video-block").withIndex().map { (index, li) ->
|
||||||
|
val epTitle = if (li.selectFirst(".name") != null)
|
||||||
|
if (li.selectFirst(".name").text().contains("Episode"))
|
||||||
|
"Episode " + li.selectFirst(".name").text().split("Episode")[1].trim()
|
||||||
|
else
|
||||||
|
li.selectFirst(".name").text()
|
||||||
|
else ""
|
||||||
|
val epThumb = li.selectFirst("img")?.attr("src")
|
||||||
|
val epDate = li.selectFirst(".meta > .date").text()
|
||||||
|
|
||||||
|
if (poster == null) {
|
||||||
|
poster = li.selectFirst("img")?.attr("onerror")?.split("=")?.get(1)?.replace(Regex("[';]"), "")
|
||||||
|
}
|
||||||
|
|
||||||
|
val epNum = Regex("""Episode (\d+)""").find(epTitle)?.destructured?.component1()?.toIntOrNull()
|
||||||
|
|
||||||
|
TvSeriesEpisode(
|
||||||
|
epTitle,
|
||||||
|
null,
|
||||||
|
epNum,
|
||||||
|
fixUrl(li.selectFirst("a").attr("href")),
|
||||||
|
epThumb,
|
||||||
|
epDate
|
||||||
|
)
|
||||||
|
}.reversed()
|
||||||
|
val year = if (episodes.isNotEmpty()) episodes.first().date?.split("-")?.get(0)?.toIntOrNull() else null
|
||||||
|
|
||||||
|
val tvType = if (episodes.size == 1 && episodes[0].name == title) TvType.Movie else TvType.TvSeries
|
||||||
|
|
||||||
|
return when (tvType) {
|
||||||
|
TvType.TvSeries -> {
|
||||||
|
TvSeriesLoadResponse(
|
||||||
|
title,
|
||||||
|
url,
|
||||||
|
this.name,
|
||||||
|
tvType,
|
||||||
|
episodes,
|
||||||
|
poster,
|
||||||
|
year,
|
||||||
|
description,
|
||||||
|
ShowStatus.Ongoing,
|
||||||
|
null,
|
||||||
|
null
|
||||||
|
)
|
||||||
|
}
|
||||||
|
TvType.Movie -> {
|
||||||
|
MovieLoadResponse(
|
||||||
|
title,
|
||||||
|
url,
|
||||||
|
this.name,
|
||||||
|
tvType,
|
||||||
|
episodes[0].data,
|
||||||
|
poster,
|
||||||
|
year,
|
||||||
|
description,
|
||||||
|
null,
|
||||||
|
null
|
||||||
|
)
|
||||||
|
}
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getMainPage(): HomePageResponse? {
|
||||||
|
val urls = listOf(
|
||||||
|
mainUrl,
|
||||||
|
"$mainUrl/movies",
|
||||||
|
"$mainUrl/series",
|
||||||
|
"$mainUrl/recommended-series",
|
||||||
|
"$mainUrl/cinema-movies"
|
||||||
|
)
|
||||||
|
val homePageList = ArrayList<HomePageList>()
|
||||||
|
urls.pmap { url ->
|
||||||
|
val response = khttp.get(url, timeout = 20.0)
|
||||||
|
val document = Jsoup.parse(response.text)
|
||||||
|
document.select("div.main-inner")?.forEach {
|
||||||
|
val title = it.select(".widget-title").text().trim()
|
||||||
|
val elements = it.select(".video-block").map {
|
||||||
|
val link = fixUrl(it.select("a").attr("href"))
|
||||||
|
val image = it.select(".picture > img").attr("src")
|
||||||
|
val name = it.select("div.name").text().trim()
|
||||||
|
val isSeries = (name.contains("Season") || name.contains("Episode"))
|
||||||
|
|
||||||
|
if (isSeries) {
|
||||||
|
TvSeriesSearchResponse(
|
||||||
|
name,
|
||||||
|
link,
|
||||||
|
this.name,
|
||||||
|
TvType.TvSeries,
|
||||||
|
image,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
MovieSearchResponse(
|
||||||
|
name,
|
||||||
|
link,
|
||||||
|
this.name,
|
||||||
|
TvType.Movie,
|
||||||
|
image,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
homePageList.add(
|
||||||
|
HomePageList(
|
||||||
|
title, elements
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return HomePageResponse(homePageList)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun loadLinks(
|
||||||
|
data: String,
|
||||||
|
isCasting: Boolean,
|
||||||
|
subtitleCallback: (SubtitleFile) -> Unit,
|
||||||
|
callback: (ExtractorLink) -> Unit
|
||||||
|
): Boolean {
|
||||||
|
val iframeLink = Jsoup.parse(khttp.get(data).text).selectFirst("iframe")?.attr("src") ?: return false
|
||||||
|
val vidstreamObject = Vidstream("https://vidembed.cc")
|
||||||
|
// https://vidembed.cc/streaming.php?id=MzUwNTY2&... -> MzUwNTY2
|
||||||
|
val id = Regex("""id=([^&]*)""").find(iframeLink)?.groupValues?.get(1)
|
||||||
|
|
||||||
|
if (id != null) {
|
||||||
|
vidstreamObject.getUrl(id, isCasting, callback)
|
||||||
|
}
|
||||||
|
|
||||||
|
val html = khttp.get(fixUrl(iframeLink)).text
|
||||||
|
val soup = Jsoup.parse(html)
|
||||||
|
|
||||||
|
val servers = soup.select(".list-server-items > .linkserver").mapNotNull { li ->
|
||||||
|
if (!li?.attr("data-video").isNullOrEmpty()) {
|
||||||
|
Pair(li.text(), fixUrl(li.attr("data-video")))
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
servers.forEach {
|
||||||
|
if (it.first.toLowerCase(Locale.ROOT).trim() == "beta server") {
|
||||||
|
// Group 1: link, Group 2: Label
|
||||||
|
val sourceRegex = Regex("""sources:[\W\w]*?file:\s*["'](.*?)["'][\W\w]*?label:\s*["'](.*?)["']""")
|
||||||
|
val trackRegex = Regex("""tracks:[\W\w]*?file:\s*["'](.*?)["'][\W\w]*?label:\s*["'](.*?)["']""")
|
||||||
|
|
||||||
|
val html = khttp.get(it.second, headers = mapOf("referer" to iframeLink)).text
|
||||||
|
sourceRegex.findAll(html).forEach { match ->
|
||||||
|
callback.invoke(
|
||||||
|
ExtractorLink(
|
||||||
|
this.name,
|
||||||
|
match.groupValues.getOrNull(2)?.let { "${this.name} $it" } ?: this.name,
|
||||||
|
match.groupValues[1],
|
||||||
|
it.second,
|
||||||
|
getQualityFromName(match.groupValues.getOrNull(2) ?: ""),
|
||||||
|
// Kinda risky
|
||||||
|
match.groupValues[1].endsWith(".m3u8"),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
trackRegex.findAll(html).forEach { match ->
|
||||||
|
subtitleCallback.invoke(
|
||||||
|
SubtitleFile(
|
||||||
|
match.groupValues.getOrNull(2) ?: "Unknown",
|
||||||
|
match.groupValues[1]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
|
@ -49,9 +49,9 @@ fun getPacked(string: String): String? {
|
||||||
return packedRegex.find(string)?.value
|
return packedRegex.find(string)?.value
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getAndUnpack(string: String): String? {
|
fun getAndUnpack(string: String): String {
|
||||||
val packedText = getPacked(string)
|
val packedText = getPacked(string)
|
||||||
return JsUnpacker(packedText).unpack()
|
return JsUnpacker(packedText).unpack() ?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
fun loadExtractor(url: String, referer: String?, callback: (ExtractorLink) -> Unit) {
|
fun loadExtractor(url: String, referer: String?, callback: (ExtractorLink) -> Unit) {
|
||||||
|
@ -65,7 +65,6 @@ fun loadExtractor(url: String, referer: String?, callback: (ExtractorLink) -> Un
|
||||||
|
|
||||||
val extractorApis: Array<ExtractorApi> = arrayOf(
|
val extractorApis: Array<ExtractorApi> = arrayOf(
|
||||||
//AllProvider(),
|
//AllProvider(),
|
||||||
Shiro(),
|
|
||||||
WcoStream(),
|
WcoStream(),
|
||||||
Mp4Upload(),
|
Mp4Upload(),
|
||||||
StreamTape(),
|
StreamTape(),
|
||||||
|
|
|
@ -32,7 +32,7 @@ class JsUnpacker(packedJS: String?) {
|
||||||
val js = packedJS
|
val js = packedJS
|
||||||
try {
|
try {
|
||||||
var p =
|
var p =
|
||||||
Pattern.compile("""}\s*\('(.*)',\s*(.*?),\s*(\d+),\s*'(.*?)'\.split\('\|'\)""", Pattern.DOTALL)
|
Pattern.compile("""\}\s*\('(.*)',\s*(.*?),\s*(\d+),\s*'(.*?)'\.split\('\|'\)""", Pattern.DOTALL)
|
||||||
var m = p.matcher(js)
|
var m = p.matcher(js)
|
||||||
if (m.find() && m.groupCount() == 4) {
|
if (m.find() && m.groupCount() == 4) {
|
||||||
val payload = m.group(1).replace("\\'", "'")
|
val payload = m.group(1).replace("\\'", "'")
|
||||||
|
@ -72,7 +72,7 @@ class JsUnpacker(packedJS: String?) {
|
||||||
return decoded.toString()
|
return decoded.toString()
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
logError(e)
|
// logError(e)
|
||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue