mirror of
https://github.com/hexated/cloudstream-extensions-hexated.git
synced 2024-08-15 00:03:22 +00:00
fixed #295
This commit is contained in:
parent
207f8359c2
commit
f4f5ee5f5b
9 changed files with 184 additions and 33 deletions
|
@ -1,7 +1,7 @@
|
||||||
import org.jetbrains.kotlin.konan.properties.Properties
|
import org.jetbrains.kotlin.konan.properties.Properties
|
||||||
|
|
||||||
// use an integer for version numbers
|
// use an integer for version numbers
|
||||||
version = 15
|
version = 16
|
||||||
|
|
||||||
android {
|
android {
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
|
|
|
@ -1,6 +1,14 @@
|
||||||
package com.hexated
|
package com.hexated
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty
|
||||||
|
import com.lagradost.cloudstream3.ErrorLoadingException
|
||||||
|
import com.lagradost.cloudstream3.SubtitleFile
|
||||||
|
import com.lagradost.cloudstream3.app
|
||||||
import com.lagradost.cloudstream3.extractors.*
|
import com.lagradost.cloudstream3.extractors.*
|
||||||
|
import com.lagradost.cloudstream3.extractors.helper.AesHelper
|
||||||
|
import com.lagradost.cloudstream3.utils.AppUtils
|
||||||
|
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||||
|
import com.lagradost.cloudstream3.utils.M3u8Helper
|
||||||
|
|
||||||
class Doods : DoodLaExtractor() {
|
class Doods : DoodLaExtractor() {
|
||||||
override var name = "Doods"
|
override var name = "Doods"
|
||||||
|
@ -35,3 +43,60 @@ class Likessb : StreamSB() {
|
||||||
class DbGdriveplayer : Gdriveplayer() {
|
class DbGdriveplayer : Gdriveplayer() {
|
||||||
override var mainUrl = "https://database.gdriveplayer.us"
|
override var mainUrl = "https://database.gdriveplayer.us"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class NineTv {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val key = "B#8G4o2\$WWFz"
|
||||||
|
suspend fun getUrl(
|
||||||
|
url: String,
|
||||||
|
referer: String?,
|
||||||
|
subtitleCallback: (SubtitleFile) -> Unit,
|
||||||
|
callback: (ExtractorLink) -> Unit
|
||||||
|
) {
|
||||||
|
val mainUrl = getBaseUrl(url)
|
||||||
|
val master = Regex("MasterJS\\s*=\\s*'([^']+)").find(
|
||||||
|
app.get(
|
||||||
|
url,
|
||||||
|
referer = referer
|
||||||
|
).text
|
||||||
|
)?.groupValues?.get(1)
|
||||||
|
val decrypt = AesHelper.cryptoAESHandler(master ?: return, key.toByteArray(), false)
|
||||||
|
?.replace("\\", "") ?: throw ErrorLoadingException("failed to decrypt")
|
||||||
|
|
||||||
|
val name = url.getHost()
|
||||||
|
val source = Regex(""""?file"?:\s*"([^"]+)""").find(decrypt)?.groupValues?.get(1)
|
||||||
|
val tracks = Regex("""tracks:\s*\[(.+)]""").find(decrypt)?.groupValues?.get(1)
|
||||||
|
|
||||||
|
M3u8Helper.generateM3u8(
|
||||||
|
name,
|
||||||
|
source ?: return,
|
||||||
|
"$mainUrl/",
|
||||||
|
headers = mapOf(
|
||||||
|
"Accept" to "*/*",
|
||||||
|
"Connection" to "keep-alive",
|
||||||
|
"Sec-Fetch-Dest" to "empty",
|
||||||
|
"Sec-Fetch-Mode" to "cors",
|
||||||
|
"Sec-Fetch-Site" to "cross-site",
|
||||||
|
"Origin" to mainUrl,
|
||||||
|
)
|
||||||
|
).forEach(callback)
|
||||||
|
|
||||||
|
AppUtils.tryParseJson<List<Tracks>>("[$tracks]")
|
||||||
|
?.filter { it.kind == "captions" }?.map { track ->
|
||||||
|
subtitleCallback.invoke(
|
||||||
|
SubtitleFile(
|
||||||
|
track.label ?: "",
|
||||||
|
track.file ?: return@map null
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data class Tracks(
|
||||||
|
@JsonProperty("file") val file: String? = null,
|
||||||
|
@JsonProperty("label") val label: String? = null,
|
||||||
|
@JsonProperty("kind") val kind: String? = null,
|
||||||
|
)
|
||||||
|
}
|
|
@ -21,6 +21,8 @@ open class Gomov : MainAPI() {
|
||||||
TvType.AsianDrama
|
TvType.AsianDrama
|
||||||
)
|
)
|
||||||
|
|
||||||
|
val sources = arrayOf("https://chillx.top", "https://watchx.top", "https://bestx.stream")
|
||||||
|
|
||||||
override val mainPage = mainPageOf(
|
override val mainPage = mainPageOf(
|
||||||
"page/%d/?s&search=advanced&post_type=movie" to "Movies",
|
"page/%d/?s&search=advanced&post_type=movie" to "Movies",
|
||||||
"category/western-series/page/%d/" to "Western Series",
|
"category/western-series/page/%d/" to "Western Series",
|
||||||
|
@ -154,19 +156,31 @@ open class Gomov : MainAPI() {
|
||||||
val id = document.selectFirst("div#muvipro_player_content_id")?.attr("data-id")
|
val id = document.selectFirst("div#muvipro_player_content_id")?.attr("data-id")
|
||||||
|
|
||||||
if(id.isNullOrEmpty()) {
|
if(id.isNullOrEmpty()) {
|
||||||
document.select("ul.muvipro-player-tabs li a").apmap {
|
document.select("ul.muvipro-player-tabs li a").apmap { ele ->
|
||||||
val iframe = app.get(fixUrl(it.attr("href"))).document.selectFirst("div.gmr-embed-responsive iframe")
|
val iframe = app.get(fixUrl(ele.attr("href"))).document.selectFirst("div.gmr-embed-responsive iframe")
|
||||||
?.attr("src")
|
?.attr("src")?.let { httpsify(it) } ?: return@apmap
|
||||||
loadExtractor(httpsify(iframe ?: return@apmap ), "$directUrl/", subtitleCallback, callback)
|
|
||||||
|
when {
|
||||||
|
sources.any { iframe.startsWith(it) } -> NineTv.getUrl(iframe, "$directUrl/", subtitleCallback, callback)
|
||||||
|
else -> {
|
||||||
|
loadExtractor(iframe, "$directUrl/", subtitleCallback, callback)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
document.select("div.tab-content-ajax").apmap {
|
document.select("div.tab-content-ajax").apmap { ele ->
|
||||||
val server = app.post(
|
val server = app.post(
|
||||||
"$directUrl/wp-admin/admin-ajax.php",
|
"$directUrl/wp-admin/admin-ajax.php",
|
||||||
data = mapOf("action" to "muvipro_player_content", "tab" to it.attr("id"), "post_id" to "$id")
|
data = mapOf("action" to "muvipro_player_content", "tab" to ele.attr("id"), "post_id" to "$id")
|
||||||
).document.select("iframe").attr("src")
|
).document.select("iframe").attr("src").let { httpsify(it) }
|
||||||
|
|
||||||
|
when {
|
||||||
|
sources.any { server.startsWith(it) } -> NineTv.getUrl(server, "$directUrl/", subtitleCallback, callback)
|
||||||
|
else -> {
|
||||||
|
loadExtractor(server, "$directUrl/", subtitleCallback, callback)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
loadExtractor(httpsify(server), "$directUrl/", subtitleCallback, callback)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -174,17 +188,21 @@ open class Gomov : MainAPI() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun String?.fixImageQuality(): String? {
|
}
|
||||||
|
|
||||||
|
fun String?.fixImageQuality(): String? {
|
||||||
if(this == null) return null
|
if(this == null) return null
|
||||||
val regex = Regex("(-\\d*x\\d*)").find(this)?.groupValues
|
val regex = Regex("(-\\d*x\\d*)").find(this)?.groupValues
|
||||||
if(regex?.isEmpty() == true) return this
|
if(regex?.isEmpty() == true) return this
|
||||||
return this.replace(regex?.get(0) ?: return null, "")
|
return this.replace(regex?.get(0) ?: return null, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getBaseUrl(url: String): String {
|
fun getBaseUrl(url: String): String {
|
||||||
return URI(url).let {
|
return URI(url).let {
|
||||||
"${it.scheme}://${it.host}"
|
"${it.scheme}://${it.host}"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun String.getHost(): String {
|
||||||
|
return fixTitle(URI(this).host.substringBeforeLast(".").substringAfterLast("."))
|
||||||
}
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
import org.jetbrains.kotlin.konan.properties.Properties
|
import org.jetbrains.kotlin.konan.properties.Properties
|
||||||
|
|
||||||
// use an integer for version numbers
|
// use an integer for version numbers
|
||||||
version = 174
|
version = 175
|
||||||
|
|
||||||
android {
|
android {
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
|
|
|
@ -6,14 +6,15 @@ import com.lagradost.cloudstream3.extractors.StreamSB
|
||||||
import com.lagradost.cloudstream3.extractors.Voe
|
import com.lagradost.cloudstream3.extractors.Voe
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty
|
import com.fasterxml.jackson.annotation.JsonProperty
|
||||||
import com.lagradost.cloudstream3.APIHolder.getCaptchaToken
|
import com.lagradost.cloudstream3.APIHolder.getCaptchaToken
|
||||||
|
import com.lagradost.cloudstream3.ErrorLoadingException
|
||||||
import com.lagradost.cloudstream3.SubtitleFile
|
import com.lagradost.cloudstream3.SubtitleFile
|
||||||
import com.lagradost.cloudstream3.apmap
|
import com.lagradost.cloudstream3.apmap
|
||||||
import com.lagradost.cloudstream3.app
|
import com.lagradost.cloudstream3.app
|
||||||
import com.lagradost.cloudstream3.base64Decode
|
import com.lagradost.cloudstream3.base64Decode
|
||||||
import com.lagradost.cloudstream3.extractors.Pixeldrain
|
import com.lagradost.cloudstream3.extractors.Pixeldrain
|
||||||
|
import com.lagradost.cloudstream3.extractors.helper.AesHelper
|
||||||
import com.lagradost.cloudstream3.utils.*
|
import com.lagradost.cloudstream3.utils.*
|
||||||
import java.math.BigInteger
|
import java.math.BigInteger
|
||||||
import java.net.URI
|
|
||||||
import java.security.MessageDigest
|
import java.security.MessageDigest
|
||||||
|
|
||||||
open class Playm4u : ExtractorApi() {
|
open class Playm4u : ExtractorApi() {
|
||||||
|
@ -234,6 +235,63 @@ open class VCloud : ExtractorApi() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class NineTv {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val key = "B#8G4o2\$WWFz"
|
||||||
|
suspend fun getUrl(
|
||||||
|
url: String,
|
||||||
|
referer: String?,
|
||||||
|
subtitleCallback: (SubtitleFile) -> Unit,
|
||||||
|
callback: (ExtractorLink) -> Unit
|
||||||
|
) {
|
||||||
|
val mainUrl = getBaseUrl(url)
|
||||||
|
val master = Regex("MasterJS\\s*=\\s*'([^']+)").find(
|
||||||
|
app.get(
|
||||||
|
url,
|
||||||
|
referer = referer
|
||||||
|
).text
|
||||||
|
)?.groupValues?.get(1)
|
||||||
|
val decrypt = AesHelper.cryptoAESHandler(master ?: return, key.toByteArray(), false)
|
||||||
|
?.replace("\\", "") ?: throw ErrorLoadingException("failed to decrypt")
|
||||||
|
|
||||||
|
val name = url.getHost()
|
||||||
|
val source = Regex(""""?file"?:\s*"([^"]+)""").find(decrypt)?.groupValues?.get(1)
|
||||||
|
val tracks = Regex("""tracks:\s*\[(.+)]""").find(decrypt)?.groupValues?.get(1)
|
||||||
|
|
||||||
|
M3u8Helper.generateM3u8(
|
||||||
|
name,
|
||||||
|
source ?: return,
|
||||||
|
"$mainUrl/",
|
||||||
|
headers = mapOf(
|
||||||
|
"Accept" to "*/*",
|
||||||
|
"Connection" to "keep-alive",
|
||||||
|
"Sec-Fetch-Dest" to "empty",
|
||||||
|
"Sec-Fetch-Mode" to "cors",
|
||||||
|
"Sec-Fetch-Site" to "cross-site",
|
||||||
|
"Origin" to mainUrl,
|
||||||
|
)
|
||||||
|
).forEach(callback)
|
||||||
|
|
||||||
|
AppUtils.tryParseJson<List<Tracks>>("[$tracks]")
|
||||||
|
?.filter { it.kind == "captions" }?.map { track ->
|
||||||
|
subtitleCallback.invoke(
|
||||||
|
SubtitleFile(
|
||||||
|
track.label ?: "",
|
||||||
|
track.file ?: return@map null
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data class Tracks(
|
||||||
|
@JsonProperty("file") val file: String? = null,
|
||||||
|
@JsonProperty("label") val label: String? = null,
|
||||||
|
@JsonProperty("kind") val kind: String? = null,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
class Hubcloud : VCloud() {
|
class Hubcloud : VCloud() {
|
||||||
override val name = "Hubcloud"
|
override val name = "Hubcloud"
|
||||||
override val mainUrl = "https://hubcloud.in"
|
override val mainUrl = "https://hubcloud.in"
|
||||||
|
@ -272,3 +330,4 @@ class Yipsu : Voe() {
|
||||||
override val name = "Yipsu"
|
override val name = "Yipsu"
|
||||||
override var mainUrl = "https://yip.su"
|
override var mainUrl = "https://yip.su"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -304,11 +304,15 @@ object SoraExtractor : SoraStream() {
|
||||||
else -> it.embed_url
|
else -> it.embed_url
|
||||||
}
|
}
|
||||||
} ?: return@apmap
|
} ?: return@apmap
|
||||||
if (!source.contains("youtube")) {
|
val sources = arrayOf("https://chillx.top", "https://watchx.top", "https://bestx.stream")
|
||||||
|
when {
|
||||||
|
sources.any { source.startsWith(it) } -> NineTv.getUrl(source, "$referer/", subtitleCallback, callback)
|
||||||
|
!source.contains("youtube") -> {
|
||||||
loadCustomExtractor(name, source, "$referer/", subtitleCallback, callback)
|
loadCustomExtractor(name, source, "$referer/", subtitleCallback, callback)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
suspend fun invokeDoomovies(
|
suspend fun invokeDoomovies(
|
||||||
title: String? = null,
|
title: String? = null,
|
||||||
|
@ -2289,9 +2293,9 @@ object SoraExtractor : SoraStream() {
|
||||||
"$nineTvAPI/tv/$tmdbId-$season-$episode"
|
"$nineTvAPI/tv/$tmdbId-$season-$episode"
|
||||||
}
|
}
|
||||||
|
|
||||||
val iframe = app.get(url, referer = "https://pressplay.top/").document.selectFirst("iframe")
|
val iframe = app.get(url, referer = "https://pressplay.top/").document.selectFirst("iframe")?.attr("src")
|
||||||
?.attr("src") ?: return
|
|
||||||
loadExtractor(iframe, "$nineTvAPI/", subtitleCallback, callback)
|
NineTv.getUrl(iframe ?: return, "$nineTvAPI/", subtitleCallback, callback)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -118,7 +118,7 @@ open class SoraStream : TmdbProvider() {
|
||||||
const val emoviesAPI = "https://emovies.si"
|
const val emoviesAPI = "https://emovies.si"
|
||||||
const val pobmoviesAPI = "https://pobmovies.cam"
|
const val pobmoviesAPI = "https://pobmovies.cam"
|
||||||
const val multimoviesAPI = "https://multi-movies.xyz"
|
const val multimoviesAPI = "https://multi-movies.xyz"
|
||||||
const val netmoviesAPI = "https://web.netmovies.to"
|
const val netmoviesAPI = "https://netmovies.to"
|
||||||
const val momentAPI = "https://moment-explanation-i-244.site"
|
const val momentAPI = "https://moment-explanation-i-244.site"
|
||||||
const val doomoviesAPI = "https://doomovies.net"
|
const val doomoviesAPI = "https://doomovies.net"
|
||||||
const val primewireAPI = "https://real-primewire.club"
|
const val primewireAPI = "https://real-primewire.club"
|
||||||
|
@ -626,7 +626,7 @@ open class SoraStream : TmdbProvider() {
|
||||||
if (!res.isAnime) invokeNowTv(res.id, res.season, res.episode, callback)
|
if (!res.isAnime) invokeNowTv(res.id, res.season, res.episode, callback)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
if (res.season == null) invokeRidomovies(res.title, res.year, callback)
|
if (!res.isAnime && res.season == null) invokeRidomovies(res.title, res.year, callback)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
invokeNavy(res.imdbId, res.season, res.episode, callback)
|
invokeNavy(res.imdbId, res.season, res.episode, callback)
|
||||||
|
|
|
@ -231,7 +231,7 @@ class SoraStreamLite : SoraStream() {
|
||||||
invokeNavy(res.imdbId, res.season, res.episode, callback)
|
invokeNavy(res.imdbId, res.season, res.episode, callback)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
if (res.season == null) invokeRidomovies(
|
if (!res.isAnime && res.season == null) invokeRidomovies(
|
||||||
res.title,
|
res.title,
|
||||||
res.year,
|
res.year,
|
||||||
callback
|
callback
|
||||||
|
|
|
@ -1079,8 +1079,9 @@ suspend fun loadCustomExtractor(
|
||||||
name ?: link.name,
|
name ?: link.name,
|
||||||
link.url,
|
link.url,
|
||||||
link.referer,
|
link.referer,
|
||||||
when (link.type) {
|
when {
|
||||||
ExtractorLinkType.M3U8 -> link.quality
|
link.type == ExtractorLinkType.M3U8 -> link.quality
|
||||||
|
link.name == "VidSrc" -> Qualities.P1080.value
|
||||||
else -> quality ?: link.quality
|
else -> quality ?: link.quality
|
||||||
},
|
},
|
||||||
link.type,
|
link.type,
|
||||||
|
@ -1321,6 +1322,10 @@ fun getBaseUrl(url: String): String {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun String.getHost(): String {
|
||||||
|
return fixTitle(URI(this).host.substringBeforeLast(".").substringAfterLast("."))
|
||||||
|
}
|
||||||
|
|
||||||
fun isUpcoming(dateString: String?): Boolean {
|
fun isUpcoming(dateString: String?): Boolean {
|
||||||
return try {
|
return try {
|
||||||
val format = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault())
|
val format = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault())
|
||||||
|
|
Loading…
Reference in a new issue