mirror of
https://github.com/hexated/cloudstream-extensions-hexated.git
synced 2024-08-15 00:03:22 +00:00
Merge branch 'master' into adityajd-patch-1
This commit is contained in:
commit
81e43f707f
40 changed files with 704 additions and 816 deletions
20
.github/workflows/build.yml
vendored
20
.github/workflows/build.yml
vendored
|
@ -43,10 +43,6 @@ jobs:
|
|||
- name: Access Secrets
|
||||
env:
|
||||
TMDB_API: ${{ secrets.TMDB_API }}
|
||||
SORA_API: ${{ secrets.SORA_API }}
|
||||
SORAHE: ${{ secrets.SORAHE }}
|
||||
SORAXA: ${{ secrets.SORAXA }}
|
||||
SORATED: ${{ secrets.SORATED }}
|
||||
DUMP_API: ${{ secrets.DUMP_API }}
|
||||
DUMP_KEY: ${{ secrets.DUMP_KEY }}
|
||||
CRUNCHYROLL_BASIC_TOKEN: ${{ secrets.CRUNCHYROLL_BASIC_TOKEN }}
|
||||
|
@ -55,16 +51,13 @@ jobs:
|
|||
ANICHI_SERVER: ${{ secrets.ANICHI_SERVER }}
|
||||
ANICHI_ENDPOINT: ${{ secrets.ANICHI_ENDPOINT }}
|
||||
ANICHI_APP: ${{ secrets.ANICHI_APP }}
|
||||
PRIMEWIRE_KEY: ${{ secrets.PRIMEWIRE_KEY }}
|
||||
ZSHOW_API: ${{ secrets.ZSHOW_API }}
|
||||
SFMOVIES_API: ${{ secrets.SFMOVIES_API }}
|
||||
CINEMATV_API: ${{ secrets.CINEMATV_API }}
|
||||
OMOVIES_API: ${{ secrets.OMOVIES_API }}
|
||||
run: |
|
||||
cd $GITHUB_WORKSPACE/src
|
||||
echo SORA_API=$SORA_API >> local.properties
|
||||
echo TMDB_API=$TMDB_API >> local.properties
|
||||
echo SORAHE=$SORAHE >> local.properties
|
||||
echo SORAXA=$SORAXA >> local.properties
|
||||
echo SORATED=$SORATED >> local.properties
|
||||
echo DUMP_API=$DUMP_API >> local.properties
|
||||
echo DUMP_KEY=$DUMP_KEY >> local.properties
|
||||
echo CRUNCHYROLL_BASIC_TOKEN=$CRUNCHYROLL_BASIC_TOKEN >> local.properties
|
||||
|
@ -73,9 +66,10 @@ jobs:
|
|||
echo ANICHI_SERVER=$ANICHI_SERVER >> local.properties
|
||||
echo ANICHI_ENDPOINT=$ANICHI_ENDPOINT >> local.properties
|
||||
echo ANICHI_APP=$ANICHI_APP >> local.properties
|
||||
echo PRIMEWIRE_KEY=$PRIMEWIRE_KEY >> local.properties
|
||||
echo ZSHOW_API=$ZSHOW_API >> local.properties
|
||||
echo SFMOVIES_API=$SFMOVIES_API >> local.properties
|
||||
echo CINEMATV_API=$CINEMATV_API >> local.properties
|
||||
echo OMOVIES_API=$OMOVIES_API >> local.properties
|
||||
|
||||
- name: Build Plugins
|
||||
run: |
|
||||
|
@ -85,10 +79,10 @@ jobs:
|
|||
cp **/build/*.cs3 $GITHUB_WORKSPACE/builds
|
||||
cp build/plugins.json $GITHUB_WORKSPACE/builds
|
||||
|
||||
- name: Move Loklok
|
||||
- name: Move Kuramanime
|
||||
run: |
|
||||
rm $GITHUB_WORKSPACE/builds/Loklok.cs3 || true
|
||||
cp $GITHUB_WORKSPACE/builds/stored/Loklok.cs3 $GITHUB_WORKSPACE/builds
|
||||
rm $GITHUB_WORKSPACE/builds/KuramanimeProvider.cs3 || true
|
||||
cp $GITHUB_WORKSPACE/builds/stored/KuramanimeProvider.cs3 $GITHUB_WORKSPACE/builds
|
||||
|
||||
- name: Push builds
|
||||
run: |
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// use an integer for version numbers
|
||||
version = 6
|
||||
version = 8
|
||||
|
||||
|
||||
cloudstream {
|
||||
|
|
|
@ -138,7 +138,7 @@ class Animasu : MainAPI() {
|
|||
document.select(".mobius > .mirror > option").mapNotNull {
|
||||
fixUrl(Jsoup.parse(base64Decode(it.attr("value"))).select("iframe").attr("src")) to it.text()
|
||||
}.apmap { (iframe, quality) ->
|
||||
loadFixedExtractor(iframe, quality, "$mainUrl/", subtitleCallback, callback)
|
||||
loadFixedExtractor(iframe.fixIframe(), quality, "$mainUrl/", subtitleCallback, callback)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
@ -157,7 +157,7 @@ class Animasu : MainAPI() {
|
|||
link.name,
|
||||
link.url,
|
||||
link.referer,
|
||||
if(link.type != ExtractorLinkType.M3U8) getIndexQuality(quality) else link.quality,
|
||||
if(link.type == ExtractorLinkType.M3U8 || link.name == "Uservideo") link.quality else getIndexQuality(quality),
|
||||
link.type,
|
||||
link.headers,
|
||||
link.extractorData
|
||||
|
@ -166,6 +166,14 @@ class Animasu : MainAPI() {
|
|||
}
|
||||
}
|
||||
|
||||
private fun String.fixIframe() : String {
|
||||
return if(this.startsWith("https://dl.berkasdrive.com")) {
|
||||
base64Decode(this.substringAfter("id="))
|
||||
} else {
|
||||
this
|
||||
}
|
||||
}
|
||||
|
||||
private fun getIndexQuality(str: String?): Int {
|
||||
return Regex("(\\d{3,4})[pP]").find(str ?: "")?.groupValues?.getOrNull(1)?.toIntOrNull()
|
||||
?: Qualities.Unknown.value
|
||||
|
|
|
@ -4,12 +4,9 @@ import com.lagradost.cloudstream3.*
|
|||
import com.lagradost.cloudstream3.LoadResponse.Companion.addAniListId
|
||||
import com.lagradost.cloudstream3.LoadResponse.Companion.addMalId
|
||||
import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer
|
||||
import com.lagradost.cloudstream3.network.CloudflareKiller
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.httpsify
|
||||
import com.lagradost.cloudstream3.utils.loadExtractor
|
||||
import okhttp3.Interceptor
|
||||
import okhttp3.Response
|
||||
import org.jsoup.Jsoup
|
||||
import org.jsoup.nodes.Element
|
||||
|
||||
|
@ -18,26 +15,12 @@ class AnimeIndoProvider : MainAPI() {
|
|||
override var name = "AnimeIndo"
|
||||
override val hasMainPage = true
|
||||
override var lang = "id"
|
||||
private val cloudflareKiller by lazy { CloudflareKiller() }
|
||||
private val interceptor by lazy { CloudflareInterceptor(cloudflareKiller) }
|
||||
override val supportedTypes = setOf(
|
||||
TvType.Anime,
|
||||
TvType.AnimeMovie,
|
||||
TvType.OVA
|
||||
)
|
||||
|
||||
class CloudflareInterceptor(private val cloudflareKiller: CloudflareKiller): Interceptor {
|
||||
override fun intercept(chain: Interceptor.Chain): Response {
|
||||
val request = chain.request()
|
||||
val response = chain.proceed(request)
|
||||
val doc = Jsoup.parse(response.peekBody(1024 * 1024).string())
|
||||
if (doc.select("title").text() == "Just a moment...") {
|
||||
return cloudflareKiller.intercept(chain)
|
||||
}
|
||||
return response
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun getType(t: String): TvType {
|
||||
return if (t.contains("OVA", true) || t.contains("Special")) TvType.OVA
|
||||
|
@ -66,8 +49,7 @@ class AnimeIndoProvider : MainAPI() {
|
|||
page: Int,
|
||||
request: MainPageRequest
|
||||
): HomePageResponse {
|
||||
val url = "$mainUrl/${request.data}/page/$page"
|
||||
val document = app.get(url, interceptor = interceptor).document
|
||||
val document = app.get("$mainUrl/${request.data}/page/$page").document
|
||||
val home = document.select("main#main div.animposx").mapNotNull {
|
||||
it.toSearchResult()
|
||||
}
|
||||
|
@ -101,7 +83,6 @@ class AnimeIndoProvider : MainAPI() {
|
|||
return newAnimeSearchResponse(title, href, TvType.Anime) {
|
||||
this.posterUrl = posterUrl
|
||||
addSub(epNum)
|
||||
posterHeaders = cloudflareKiller.getCookieHeaders(mainUrl).toMap()
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -109,8 +90,7 @@ class AnimeIndoProvider : MainAPI() {
|
|||
override suspend fun search(query: String): List<SearchResponse> {
|
||||
val anime = mutableListOf<SearchResponse>()
|
||||
(1..2).forEach { page ->
|
||||
val link = "$mainUrl/page/$page/?s=$query"
|
||||
val document = app.get(link, interceptor = interceptor).document
|
||||
val document = app.get("$mainUrl/page/$page/?s=$query").document
|
||||
val media = document.select(".site-main.relat > article").mapNotNull {
|
||||
val title = it.selectFirst("div.title > h2")!!.ownText().trim()
|
||||
val href = it.selectFirst("a")!!.attr("href")
|
||||
|
@ -118,7 +98,6 @@ class AnimeIndoProvider : MainAPI() {
|
|||
val type = getType(it.select("div.type").text().trim())
|
||||
newAnimeSearchResponse(title, href, type) {
|
||||
this.posterUrl = posterUrl
|
||||
posterHeaders = cloudflareKiller.getCookieHeaders(mainUrl).toMap()
|
||||
}
|
||||
}
|
||||
if(media.isNotEmpty()) anime.addAll(media)
|
||||
|
@ -127,8 +106,7 @@ class AnimeIndoProvider : MainAPI() {
|
|||
}
|
||||
|
||||
override suspend fun load(url: String): LoadResponse? {
|
||||
val document = app.get(url, interceptor = interceptor).document
|
||||
|
||||
val document = app.get(url).document
|
||||
val title = document.selectFirst("h1.entry-title")?.text()?.replace("Subtitle Indonesia", "")
|
||||
?.trim() ?: return null
|
||||
val poster = document.selectFirst("div.thumb > img[itemprop=image]")?.attr("src")
|
||||
|
@ -168,7 +146,6 @@ class AnimeIndoProvider : MainAPI() {
|
|||
addTrailer(trailer)
|
||||
addMalId(tracker?.malId)
|
||||
addAniListId(tracker?.aniId?.toIntOrNull())
|
||||
posterHeaders = cloudflareKiller.getCookieHeaders(mainUrl).toMap()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -179,12 +156,12 @@ class AnimeIndoProvider : MainAPI() {
|
|||
callback: (ExtractorLink) -> Unit
|
||||
): Boolean {
|
||||
|
||||
val document = app.get(data, interceptor = interceptor).document
|
||||
val document = app.get(data).document
|
||||
document.select("div.itemleft > .mirror > option").mapNotNull {
|
||||
fixUrl(Jsoup.parse(base64Decode(it.attr("value"))).select("iframe").attr("src"))
|
||||
}.apmap {
|
||||
if (it.startsWith(mainUrl)) {
|
||||
app.get(it, referer = "$mainUrl/", interceptor = interceptor).document.select("iframe").attr("src")
|
||||
app.get(it, referer = "$mainUrl/").document.select("iframe").attr("src")
|
||||
} else {
|
||||
it
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import org.jetbrains.kotlin.konan.properties.Properties
|
||||
|
||||
// use an integer for version numbers
|
||||
version = 28
|
||||
version = 29
|
||||
|
||||
android {
|
||||
defaultConfig {
|
||||
|
|
|
@ -6,8 +6,12 @@ import com.lagradost.cloudstream3.utils.httpsify
|
|||
import com.lagradost.cloudstream3.utils.loadExtractor
|
||||
|
||||
class DutaMovie : Gomov() {
|
||||
|
||||
override var mainUrl = "https://cinema.dutamovie21.vip"
|
||||
override var name = "DutaMovie"
|
||||
|
||||
|
||||
|
||||
override var name = "DutaMovie"
|
||||
override val mainPage = mainPageOf(
|
||||
"category/box-office/page/%d/" to "Box Office",
|
||||
"category/serial-tv/page/%d/" to "Serial TV",
|
||||
|
|
|
@ -1,21 +1,14 @@
|
|||
package com.hexated
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty
|
||||
import com.lagradost.cloudstream3.ErrorLoadingException
|
||||
import com.lagradost.cloudstream3.SubtitleFile
|
||||
import com.lagradost.cloudstream3.apmap
|
||||
import com.lagradost.cloudstream3.app
|
||||
import com.lagradost.cloudstream3.base64Decode
|
||||
import com.lagradost.cloudstream3.extractors.*
|
||||
import com.lagradost.cloudstream3.extractors.helper.AesHelper
|
||||
import com.lagradost.cloudstream3.utils.AppUtils
|
||||
import com.lagradost.cloudstream3.utils.ExtractorApi
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.M3u8Helper
|
||||
import com.lagradost.cloudstream3.utils.loadExtractor
|
||||
import org.jsoup.nodes.Document
|
||||
import org.mozilla.javascript.Context
|
||||
import org.mozilla.javascript.Scriptable
|
||||
|
||||
open class Uplayer : ExtractorApi() {
|
||||
override val name = "Uplayer"
|
||||
|
@ -94,81 +87,4 @@ class Likessb : StreamSB() {
|
|||
|
||||
class DbGdriveplayer : Gdriveplayer() {
|
||||
override var mainUrl = "https://database.gdriveplayer.us"
|
||||
}
|
||||
|
||||
object NineTv {
|
||||
|
||||
suspend fun getUrl(
|
||||
url: String,
|
||||
referer: String?,
|
||||
subtitleCallback: (SubtitleFile) -> Unit,
|
||||
callback: (ExtractorLink) -> Unit
|
||||
) {
|
||||
val mainUrl = getBaseUrl(url)
|
||||
val res = app.get(url, headers = mapOf(
|
||||
"Accept" to "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
|
||||
"Accept-Language" to "en-US,en;q=0.5",
|
||||
"Referer" to (referer ?: ""),
|
||||
))
|
||||
val master = Regex("\\s*=\\s*'([^']+)").find(res.text)?.groupValues?.get(1)
|
||||
val key = "tSIsE8FgpRkv3QQQ"
|
||||
val decrypt = AesHelper.cryptoAESHandler(master ?: return, key.toByteArray(), false)
|
||||
?.replace("\\", "")
|
||||
?: throw ErrorLoadingException("failed to decrypt")
|
||||
|
||||
val source = Regex(""""?file"?:\s*"([^"]+)""").find(decrypt)?.groupValues?.get(1)
|
||||
val tracks = Regex("""tracks:\s*\[(.+)]""").find(decrypt)?.groupValues?.get(1)
|
||||
val name = url.getHost()
|
||||
|
||||
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
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun Document.getKeys(): String? {
|
||||
val script = (this.selectFirst("script:containsData(eval\\()")?.data()
|
||||
?.replace("eval(", "var result=")?.removeSuffix(");") + ";").trimIndent()
|
||||
val run = script.runJS("result")
|
||||
return """,\s*'([^']+)""".toRegex().find(run)?.groupValues?.getOrNull(1)
|
||||
}
|
||||
|
||||
private fun String.runJS(variable: String): String {
|
||||
val rhino = Context.enter()
|
||||
rhino.optimizationLevel = -1
|
||||
val scope: Scriptable = rhino.initSafeStandardObjects()
|
||||
val result: String
|
||||
try {
|
||||
rhino.evaluateString(scope, this, "JavaScript", 1, null)
|
||||
result = Context.toString(scope.get(variable, scope))
|
||||
} finally {
|
||||
Context.exit()
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
data class Tracks(
|
||||
@JsonProperty("file") val file: String? = null,
|
||||
@JsonProperty("label") val label: String? = null,
|
||||
@JsonProperty("kind") val kind: String? = null,
|
||||
)
|
||||
}
|
|
@ -20,7 +20,6 @@ open class Gomov : MainAPI() {
|
|||
TvType.TvSeries,
|
||||
TvType.AsianDrama
|
||||
)
|
||||
private val sources = arrayOf("https://chillx.top", "https://watchx.top", "https://bestx.stream")
|
||||
|
||||
override val mainPage = mainPageOf(
|
||||
"page/%d/?s&search=advanced&post_type=movie" to "Movies",
|
||||
|
@ -46,7 +45,7 @@ open class Gomov : MainAPI() {
|
|||
private fun Element.toSearchResult(): SearchResponse? {
|
||||
val title = this.selectFirst("h2.entry-title > a")?.text()?.trim() ?: return null
|
||||
val href = fixUrl(this.selectFirst("a")!!.attr("href"))
|
||||
val posterUrl = fixUrlNull(this.selectFirst("a > img").getImgAttr()).fixImageQuality()
|
||||
val posterUrl = fixUrlNull(this.selectFirst("a > img")?.getImageAttr()).fixImageQuality()
|
||||
val quality = this.select("div.gmr-qual, div.gmr-quality-item > a").text().trim().replace("-", "")
|
||||
return if (quality.isEmpty()) {
|
||||
val episode =
|
||||
|
@ -67,7 +66,7 @@ open class Gomov : MainAPI() {
|
|||
private fun Element.toRecommendResult(): SearchResponse? {
|
||||
val title = this.selectFirst("a > span.idmuvi-rp-title")?.text()?.trim() ?: return null
|
||||
val href = this.selectFirst("a")!!.attr("href")
|
||||
val posterUrl = fixUrlNull(this.selectFirst("a > img").getImgAttr().fixImageQuality())
|
||||
val posterUrl = fixUrlNull(this.selectFirst("a > img")?.getImageAttr().fixImageQuality())
|
||||
return newMovieSearchResponse(title, href, TvType.Movie) {
|
||||
this.posterUrl = posterUrl
|
||||
}
|
||||
|
@ -89,7 +88,7 @@ open class Gomov : MainAPI() {
|
|||
document.selectFirst("h1.entry-title")?.text()?.substringBefore("Season")?.substringBefore("Episode")?.trim()
|
||||
.toString()
|
||||
val poster =
|
||||
fixUrlNull(document.selectFirst("figure.pull-left > img").getImgAttr())?.fixImageQuality()
|
||||
fixUrlNull(document.selectFirst("figure.pull-left > img")?.getImageAttr())?.fixImageQuality()
|
||||
val tags = document.select("span.gmr-movie-genre:contains(Genre:) > a").map { it.text() }
|
||||
|
||||
val year =
|
||||
|
@ -159,12 +158,7 @@ open class Gomov : MainAPI() {
|
|||
val iframe = app.get(fixUrl(ele.attr("href"))).document.selectFirst("div.gmr-embed-responsive iframe")
|
||||
.getIframeAttr()?.let { httpsify(it) } ?: return@apmap
|
||||
|
||||
when {
|
||||
sources.any { iframe.startsWith(it) } -> NineTv.getUrl(iframe, "$directUrl/", subtitleCallback, callback)
|
||||
else -> {
|
||||
loadExtractor(iframe, "$directUrl/", subtitleCallback, callback)
|
||||
}
|
||||
}
|
||||
loadExtractor(iframe, "$directUrl/", subtitleCallback, callback)
|
||||
}
|
||||
} else {
|
||||
document.select("div.tab-content-ajax").apmap { ele ->
|
||||
|
@ -173,12 +167,7 @@ open class Gomov : MainAPI() {
|
|||
data = mapOf("action" to "muvipro_player_content", "tab" to ele.attr("id"), "post_id" to "$id")
|
||||
).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(server, "$directUrl/", subtitleCallback, callback)
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -187,28 +176,29 @@ open class Gomov : MainAPI() {
|
|||
|
||||
}
|
||||
|
||||
private fun Element?.getImgAttr() : String? {
|
||||
return this?.attr("data-src").takeIf { it?.isNotEmpty() == true } ?: this?.attr("src")
|
||||
private fun Element.getImageAttr(): String? {
|
||||
return when {
|
||||
this.hasAttr("data-src") -> this.attr("abs:data-src")
|
||||
this.hasAttr("data-lazy-src") -> this.attr("abs:data-lazy-src")
|
||||
this.hasAttr("srcset") -> this.attr("abs:srcset").substringBefore(" ")
|
||||
else -> this.attr("abs:src")
|
||||
}
|
||||
}
|
||||
|
||||
private fun Element?.getIframeAttr() : String? {
|
||||
return this?.attr("data-litespeed-src").takeIf { it?.isNotEmpty() == true } ?: this?.attr("src")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun String?.fixImageQuality(): String? {
|
||||
if (this == null) return null
|
||||
val regex = Regex("(-\\d*x\\d*)").find(this)?.groupValues?.get(0) ?: return this
|
||||
return this.replace(regex, "")
|
||||
}
|
||||
|
||||
fun getBaseUrl(url: String): String {
|
||||
return URI(url).let {
|
||||
"${it.scheme}://${it.host}"
|
||||
private fun String?.fixImageQuality(): String? {
|
||||
if (this == null) return null
|
||||
val regex = Regex("(-\\d*x\\d*)").find(this)?.groupValues?.get(0) ?: return this
|
||||
return this.replace(regex, "")
|
||||
}
|
||||
|
||||
private fun getBaseUrl(url: String): String {
|
||||
return URI(url).let {
|
||||
"${it.scheme}://${it.host}"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun String.getHost(): String {
|
||||
return fixTitle(URI(this).host.substringBeforeLast(".").substringAfterLast("."))
|
||||
}
|
|
@ -3,7 +3,10 @@ package com.hexated
|
|||
import com.lagradost.cloudstream3.mainPageOf
|
||||
|
||||
class Ngefilm : Gomov() {
|
||||
|
||||
override var mainUrl = "https://nge-film21.fun"
|
||||
|
||||
|
||||
override var name = "Ngefilm"
|
||||
|
||||
override val mainPage = mainPageOf(
|
||||
|
|
|
@ -9,7 +9,7 @@ import org.jsoup.nodes.Element
|
|||
import java.net.URI
|
||||
|
||||
class Nodrakorid : Gomov() {
|
||||
override var mainUrl = "https://no-drakor.xyz"
|
||||
override var mainUrl = "https://nodra-kor.xyz"
|
||||
override var name = "Nodrakorid"
|
||||
|
||||
override val mainPage = mainPageOf(
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// use an integer for version numbers
|
||||
version = 23
|
||||
version = 34
|
||||
|
||||
|
||||
cloudstream {
|
||||
|
|
|
@ -1,7 +1,14 @@
|
|||
package com.hexated
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty
|
||||
import com.lagradost.cloudstream3.SubtitleFile
|
||||
import com.lagradost.cloudstream3.app
|
||||
import com.lagradost.cloudstream3.extractors.Filesim
|
||||
import com.lagradost.cloudstream3.extractors.StreamSB
|
||||
import com.lagradost.cloudstream3.utils.ExtractorApi
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.Qualities
|
||||
import com.lagradost.cloudstream3.utils.getQualityFromName
|
||||
|
||||
class Nyomo : StreamSB() {
|
||||
override var name: String = "Nyomo"
|
||||
|
@ -11,4 +18,101 @@ class Nyomo : StreamSB() {
|
|||
class Streamhide : Filesim() {
|
||||
override var name: String = "Streamhide"
|
||||
override var mainUrl: String = "https://streamhide.to"
|
||||
}
|
||||
|
||||
open class Lbx : ExtractorApi() {
|
||||
override val name = "Linkbox"
|
||||
override val mainUrl = "https://lbx.to"
|
||||
private val realUrl = "https://www.linkbox.to"
|
||||
override val requiresReferer = true
|
||||
|
||||
override suspend fun getUrl(
|
||||
url: String,
|
||||
referer: String?,
|
||||
subtitleCallback: (SubtitleFile) -> Unit,
|
||||
callback: (ExtractorLink) -> Unit
|
||||
) {
|
||||
val token = Regex("""(?:/f/|/file/|\?id=)(\w+)""").find(url)?.groupValues?.get(1)
|
||||
val id = app.get("$realUrl/api/file/share_out_list/?sortField=utime&sortAsc=0&pageNo=1&pageSize=50&shareToken=$token").parsedSafe<Responses>()?.data?.itemId
|
||||
app.get("$realUrl/api/file/detail?itemId=$id", referer = url)
|
||||
.parsedSafe<Responses>()?.data?.itemInfo?.resolutionList?.map { link ->
|
||||
callback.invoke(
|
||||
ExtractorLink(
|
||||
name,
|
||||
name,
|
||||
link.url ?: return@map null,
|
||||
"$realUrl/",
|
||||
getQualityFromName(link.resolution)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
data class Resolutions(
|
||||
@JsonProperty("url") val url: String? = null,
|
||||
@JsonProperty("resolution") val resolution: String? = null,
|
||||
)
|
||||
|
||||
data class ItemInfo(
|
||||
@JsonProperty("resolutionList") val resolutionList: ArrayList<Resolutions>? = arrayListOf(),
|
||||
)
|
||||
|
||||
data class Data(
|
||||
@JsonProperty("itemInfo") val itemInfo: ItemInfo? = null,
|
||||
@JsonProperty("itemId") val itemId: String? = null,
|
||||
)
|
||||
|
||||
data class Responses(
|
||||
@JsonProperty("data") val data: Data? = null,
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
open class Kuramadrive : ExtractorApi() {
|
||||
override val name = "DriveKurama"
|
||||
override val mainUrl = "https://kuramadrive.com"
|
||||
override val requiresReferer = true
|
||||
|
||||
override suspend fun getUrl(
|
||||
url: String,
|
||||
referer: String?,
|
||||
subtitleCallback: (SubtitleFile) -> Unit,
|
||||
callback: (ExtractorLink) -> Unit
|
||||
) {
|
||||
val req = app.get(url, referer = referer)
|
||||
val doc = req.document
|
||||
|
||||
val title = doc.select("title").text()
|
||||
val token = doc.select("meta[name=csrf-token]").attr("content")
|
||||
val routeCheckAvl = doc.select("input#routeCheckAvl").attr("value")
|
||||
|
||||
val json = app.get(
|
||||
routeCheckAvl, headers = mapOf(
|
||||
"X-Requested-With" to "XMLHttpRequest",
|
||||
"X-CSRF-TOKEN" to token
|
||||
),
|
||||
referer = url,
|
||||
cookies = req.cookies
|
||||
).parsedSafe<Source>()
|
||||
|
||||
callback.invoke(
|
||||
ExtractorLink(
|
||||
name,
|
||||
name,
|
||||
json?.url ?: return,
|
||||
"$mainUrl/",
|
||||
getIndexQuality(title),
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private fun getIndexQuality(str: String?): Int {
|
||||
return Regex("(\\d{3,4})[pP]").find(str ?: "")?.groupValues?.getOrNull(1)?.toIntOrNull()
|
||||
?: Qualities.Unknown.value
|
||||
}
|
||||
|
||||
private data class Source(
|
||||
@JsonProperty("url") val url: String,
|
||||
)
|
||||
|
||||
}
|
|
@ -8,6 +8,8 @@ import com.lagradost.cloudstream3.utils.ExtractorLink
|
|||
import com.lagradost.cloudstream3.utils.Qualities
|
||||
import com.lagradost.cloudstream3.utils.loadExtractor
|
||||
import com.lagradost.nicehttp.requestCreator
|
||||
import okhttp3.Headers
|
||||
import okhttp3.HttpUrl
|
||||
import org.jsoup.Jsoup
|
||||
import org.jsoup.nodes.Element
|
||||
|
||||
|
@ -18,7 +20,7 @@ class KuramanimeProvider : MainAPI() {
|
|||
override val hasMainPage = true
|
||||
override var lang = "id"
|
||||
override val hasDownloadSupport = true
|
||||
private var auth: String? = null
|
||||
private var params: AuthParams? = null
|
||||
private var headers: Map<String,String> = mapOf()
|
||||
private var cookies: Map<String,String> = mapOf()
|
||||
override val supportedTypes = setOf(
|
||||
|
@ -199,67 +201,70 @@ class KuramanimeProvider : MainAPI() {
|
|||
|
||||
val req = app.get(data)
|
||||
val res = req.document
|
||||
val token = res.select("meta[name=csrf-token]").attr("content")
|
||||
headers = mapOf(
|
||||
"Accept" to "application/json, text/javascript, */*; q=0.01",
|
||||
"Authorization" to "${getAuth(data)}",
|
||||
"X-Requested-With" to "XMLHttpRequest",
|
||||
"X-CSRF-TOKEN" to token
|
||||
)
|
||||
cookies = req.cookies
|
||||
res.select("select#changeServer option").apmap { source ->
|
||||
val server = source.attr("value")
|
||||
val link = "$data?dfgRr1OagZvvxbzHNpyCy0FqJQ18mCnb=${getMisc()}&twEvZlbZbYRWBdKKwxkOnwYF0VWoGGVg=$server"
|
||||
if (server.contains(Regex("(?i)kuramadrive|archive"))) {
|
||||
invokeLocalSource(link, server, data, callback)
|
||||
} else {
|
||||
app.get(
|
||||
link,
|
||||
referer = data,
|
||||
headers = headers,
|
||||
cookies = cookies
|
||||
).document.select("div.iframe-container iframe").attr("src").let { videoUrl ->
|
||||
loadExtractor(fixUrl(videoUrl), "$mainUrl/", subtitleCallback, callback)
|
||||
|
||||
argamap(
|
||||
{
|
||||
val auth = getAuth(data)
|
||||
headers = auth.authHeader?.associate { it.first to it.second }?.filter { it.key != "Cookie" }!!
|
||||
cookies = req.cookies
|
||||
res.select("select#changeServer option").apmap { source ->
|
||||
val server = source.attr("value")
|
||||
val query = auth.serverUrl?.queryParameterNames?.map { it } ?: return@apmap
|
||||
val link = "$data?${query[0]}=${getMisc(auth.authUrl)}&${query[1]}=$server"
|
||||
if (server.contains(Regex("(?i)kuramadrive|archive"))) {
|
||||
invokeLocalSource(link, server, data, callback)
|
||||
} else {
|
||||
app.get(
|
||||
link,
|
||||
referer = data,
|
||||
headers = headers,
|
||||
cookies = cookies
|
||||
).document.select("div.iframe-container iframe").attr("src").let { videoUrl ->
|
||||
loadExtractor(fixUrl(videoUrl), "$mainUrl/", subtitleCallback, callback)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
res.select("div#animeDownloadLink a").apmap {
|
||||
loadExtractor(it.attr("href"), "$mainUrl/", subtitleCallback, callback)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
private fun getAuth() : String {
|
||||
val key = "kuramanime3:LEcXGYdOGcMCV8jM5fhRdM2mneSj6kaNts:${APIHolder.unixTimeMS};"
|
||||
return base64Encode(base64Encode(key.toByteArray()).toByteArray())
|
||||
}
|
||||
|
||||
private suspend fun fetchAuth(url: String) : String? {
|
||||
private suspend fun fetchAuth(url: String) : AuthParams {
|
||||
val regex = Regex("""$mainUrl/\S+""")
|
||||
val found = WebViewResolver(
|
||||
Regex("$mainUrl/misc/post/EVhcpMNbO77acNZcHr2XVjaG8WAdNC1u")
|
||||
Regex("""$url(?!\?page=)\?"""),
|
||||
additionalUrls = listOf(regex)
|
||||
).resolveUsingWebView(
|
||||
requestCreator(
|
||||
"GET", url
|
||||
)
|
||||
).first
|
||||
return found?.headers?.get("Authorization")
|
||||
)
|
||||
val addition = found.second.findLast { it.headers["X-Requested-With"] == "XMLHttpRequest" }
|
||||
return AuthParams(found.first?.url, addition?.url.toString(), addition?.headers)
|
||||
}
|
||||
|
||||
private suspend fun getAuth(url: String) = auth ?: fetchAuth(url)
|
||||
private suspend fun getAuth(url: String) = params ?: fetchAuth(url).also { params = it }
|
||||
|
||||
private suspend fun getMisc(): String {
|
||||
private suspend fun getMisc(url: String?): String {
|
||||
val misc = app.get(
|
||||
"$mainUrl/misc/post/EVhcpMNbO77acNZcHr2XVjaG8WAdNC1u",
|
||||
headers = headers + mapOf("X-Request-ID" to getRequestId()),
|
||||
"$url",
|
||||
headers = headers,
|
||||
cookies = cookies
|
||||
)
|
||||
cookies = misc.cookies
|
||||
return misc.parsed()
|
||||
}
|
||||
|
||||
private fun getRequestId(length: Int = 8): String {
|
||||
val allowedChars = ('a'..'z') + ('0'..'9')
|
||||
return (1..length)
|
||||
.map { allowedChars.random() }
|
||||
.joinToString("")
|
||||
}
|
||||
data class AuthParams (
|
||||
val serverUrl: HttpUrl?,
|
||||
val authUrl: String?,
|
||||
val authHeader: Headers?,
|
||||
)
|
||||
|
||||
}
|
|
@ -12,5 +12,7 @@ class KuramanimeProviderPlugin: Plugin() {
|
|||
registerMainAPI(KuramanimeProvider())
|
||||
registerExtractorAPI(Nyomo())
|
||||
registerExtractorAPI(Streamhide())
|
||||
registerExtractorAPI(Kuramadrive())
|
||||
registerExtractorAPI(Lbx())
|
||||
}
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
// use an integer for version numbers
|
||||
version = 8
|
||||
version = 9
|
||||
|
||||
|
||||
cloudstream {
|
||||
|
|
|
@ -44,10 +44,12 @@ open class Streampai : ExtractorApi() {
|
|||
this.name,
|
||||
this.name,
|
||||
fixUrl(it.file),
|
||||
"$mainUrl/",
|
||||
url,
|
||||
getQualityFromName(it.label),
|
||||
headers = mapOf(
|
||||
"Accept" to "video/webm,video/ogg,video/*;q=0.9,application/ogg;q=0.7,audio/*;q=0.6,*/*;q=0.5",
|
||||
"Accept-Language" to "en-US,en;q=0.5",
|
||||
"DNT" to "1",
|
||||
"Range" to "bytes=0-",
|
||||
"Sec-Fetch-Dest" to "video",
|
||||
"Sec-Fetch-Mode" to "no-cors",
|
||||
|
|
|
@ -2,10 +2,7 @@ package com.hexated
|
|||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty
|
||||
import com.lagradost.cloudstream3.*
|
||||
import com.lagradost.cloudstream3.network.CloudflareKiller
|
||||
import com.lagradost.cloudstream3.utils.*
|
||||
import okhttp3.Interceptor
|
||||
import okhttp3.Response
|
||||
import org.jsoup.Jsoup
|
||||
import org.jsoup.nodes.Element
|
||||
import java.net.URLDecoder
|
||||
|
@ -17,24 +14,10 @@ class Minioppai : MainAPI() {
|
|||
override var lang = "id"
|
||||
override val hasDownloadSupport = true
|
||||
override val hasQuickSearch = true
|
||||
private val cloudflareKiller by lazy { CloudflareKiller() }
|
||||
private val interceptor by lazy { CloudflareInterceptor(cloudflareKiller) }
|
||||
override val supportedTypes = setOf(
|
||||
TvType.NSFW,
|
||||
)
|
||||
|
||||
class CloudflareInterceptor(private val cloudflareKiller: CloudflareKiller): Interceptor {
|
||||
override fun intercept(chain: Interceptor.Chain): Response {
|
||||
val request = chain.request()
|
||||
val response = chain.proceed(request)
|
||||
val doc = Jsoup.parse(response.peekBody(1024 * 1024).string())
|
||||
if (doc.select("title").text() == "Just a moment...") {
|
||||
return cloudflareKiller.intercept(chain)
|
||||
}
|
||||
return response
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun getStatus(t: String?): ShowStatus {
|
||||
return when (t) {
|
||||
|
@ -54,7 +37,7 @@ class Minioppai : MainAPI() {
|
|||
page: Int,
|
||||
request: MainPageRequest
|
||||
): HomePageResponse {
|
||||
val document = app.get("${request.data}/page/$page", interceptor = interceptor).document
|
||||
val document = app.get("${request.data}/page/$page").document
|
||||
val home = document.select("div.latest a").mapNotNull {
|
||||
it.toSearchResult()
|
||||
}
|
||||
|
@ -84,7 +67,6 @@ class Minioppai : MainAPI() {
|
|||
return newAnimeSearchResponse(title, href, TvType.NSFW) {
|
||||
this.posterUrl = posterUrl
|
||||
addSub(epNum)
|
||||
posterHeaders = cloudflareKiller.getCookieHeaders(mainUrl).toMap()
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -97,7 +79,6 @@ class Minioppai : MainAPI() {
|
|||
"action" to "ts_ac_do_search",
|
||||
"ts_ac_query" to query,
|
||||
), headers = mapOf("X-Requested-With" to "XMLHttpRequest"),
|
||||
interceptor = interceptor
|
||||
).parsedSafe<SearchResponses>()?.post?.firstOrNull()?.all?.mapNotNull { item ->
|
||||
newAnimeSearchResponse(
|
||||
item.postTitle ?: "",
|
||||
|
@ -105,13 +86,12 @@ class Minioppai : MainAPI() {
|
|||
TvType.NSFW
|
||||
) {
|
||||
this.posterUrl = item.postImage
|
||||
posterHeaders = cloudflareKiller.getCookieHeaders(mainUrl).toMap()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun load(url: String): LoadResponse? {
|
||||
val document = app.get(url, interceptor = interceptor).document
|
||||
val document = app.get(url).document
|
||||
|
||||
val title = document.selectFirst("h1.entry-title")?.text()?.trim() ?: return null
|
||||
val poster = fixUrlNull(document.selectFirst("div.limage img")?.attr("src"))
|
||||
|
@ -127,7 +107,7 @@ class Minioppai : MainAPI() {
|
|||
val name = it.selectFirst("div.epl-num")?.text()
|
||||
val link = fixUrlNull(it.selectFirst("a")?.attr("href")) ?: return@mapNotNull null
|
||||
Episode(link, name = name)
|
||||
}.reversed()
|
||||
}
|
||||
|
||||
return newAnimeLoadResponse(title, url, TvType.NSFW) {
|
||||
engName = title
|
||||
|
@ -137,7 +117,6 @@ class Minioppai : MainAPI() {
|
|||
showStatus = status
|
||||
plot = description
|
||||
this.tags = tags
|
||||
posterHeaders = cloudflareKiller.getCookieHeaders(mainUrl).toMap()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -147,7 +126,7 @@ class Minioppai : MainAPI() {
|
|||
subtitleCallback: (SubtitleFile) -> Unit,
|
||||
callback: (ExtractorLink) -> Unit
|
||||
): Boolean {
|
||||
val document = app.get(data, interceptor = interceptor).document
|
||||
val document = app.get(data).document
|
||||
document.select("div.server ul.mirror li a").mapNotNull {
|
||||
Jsoup.parse(base64Decode(it.attr("data-em"))).select("iframe").attr("src")
|
||||
}.apmap { link ->
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// use an integer for version numbers
|
||||
version = 2
|
||||
version = 3
|
||||
|
||||
|
||||
cloudstream {
|
||||
|
@ -23,4 +23,4 @@ cloudstream {
|
|||
)
|
||||
|
||||
iconUrl = "https://www.google.com/s2/favicons?domain=moviehab.com&sz=%size%"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ import com.lagradost.cloudstream3.utils.loadExtractor
|
|||
import org.jsoup.nodes.Element
|
||||
|
||||
class Moviehab : MainAPI() {
|
||||
override var mainUrl = "https://vivamax.asia"
|
||||
override var mainUrl = "https://nowshowing.to"
|
||||
override var name = "Moviehab"
|
||||
override val hasMainPage = true
|
||||
override var lang = "tl"
|
||||
|
@ -23,16 +23,13 @@ class Moviehab : MainAPI() {
|
|||
)
|
||||
|
||||
companion object {
|
||||
private const val mainServer = "https://vivamax.asia"
|
||||
private const val mainServer = "https://nowshowing.to"
|
||||
}
|
||||
|
||||
override val mainPage = mainPageOf(
|
||||
"$mainUrl/library/movies?sort_by=imdb_rate&page=" to "Movies by IMDB Rating",
|
||||
"$mainUrl/library/shows?&sort_by=imdb_rate&page=" to "TV Shows by IMDB Rating",
|
||||
"$mainUrl/library/movies?&sort_by=year&page=" to "New Movies",
|
||||
"$mainUrl/library/shows?&sort_by=year&page=" to "New TV Shows",
|
||||
"$mainUrl/library/movies?country=Philippines&sort_by=year&page=" to "New Philippines Movies",
|
||||
"$mainUrl/library/shows?&country=Philippines&sort_by=year&page=" to "New Philippines TV Shows",
|
||||
"$mainUrl/category/movies/" to "New Movies",
|
||||
"$mainUrl/category/tv-series/" to "New TV Shows",
|
||||
"$mainUrl/category/coming-soon/" to "Coming Soon",
|
||||
)
|
||||
|
||||
override suspend fun getMainPage(
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
// use an integer for version numbers
|
||||
version = 53
|
||||
version = 55
|
||||
|
||||
|
||||
cloudstream {
|
||||
language = "hi"
|
||||
// All of these properties are optional, you can safely remove them
|
||||
|
||||
description = "Include: Hdmovie2"
|
||||
description = "Includes: Hdmovie2, Animesaga"
|
||||
authors = listOf("Hexated")
|
||||
|
||||
/**
|
||||
|
|
23
Movierulzhd/src/main/kotlin/com/hexated/Animesaga.kt
Normal file
23
Movierulzhd/src/main/kotlin/com/hexated/Animesaga.kt
Normal file
|
@ -0,0 +1,23 @@
|
|||
package com.hexated
|
||||
|
||||
import com.lagradost.cloudstream3.TvType
|
||||
import com.lagradost.cloudstream3.mainPageOf
|
||||
|
||||
class Animesaga : Movierulzhd() {
|
||||
|
||||
override var mainUrl = "https://www.animesaga.in"
|
||||
override var name = "Animesaga"
|
||||
override val supportedTypes = setOf(
|
||||
TvType.Anime,
|
||||
TvType.AnimeMovie,
|
||||
TvType.OVA
|
||||
)
|
||||
|
||||
override val mainPage = mainPageOf(
|
||||
"movies" to "Movies",
|
||||
"tvshows" to "TV-Shows",
|
||||
"genre/hindi-dub" to "Hindi Dub",
|
||||
)
|
||||
|
||||
|
||||
}
|
|
@ -2,10 +2,9 @@ package com.hexated
|
|||
|
||||
import com.lagradost.cloudstream3.SubtitleFile
|
||||
import com.lagradost.cloudstream3.app
|
||||
import com.lagradost.cloudstream3.extractors.Chillx
|
||||
import com.lagradost.cloudstream3.utils.*
|
||||
|
||||
const val twoEmbedAPI = "https://www.2embed.to"
|
||||
|
||||
class Sbnmp : ExtractorApi() {
|
||||
override val name = "Sbnmp"
|
||||
override var mainUrl = "https://sbnmp.bar"
|
||||
|
@ -66,3 +65,8 @@ open class Akamaicdn : ExtractorApi() {
|
|||
)
|
||||
}
|
||||
}
|
||||
|
||||
class AnimesagaStream : Chillx() {
|
||||
override val name = "AnimesagaStream"
|
||||
override val mainUrl = "https://stream.animesaga.in"
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ import org.jsoup.Jsoup
|
|||
|
||||
class Hdmovie2 : Movierulzhd() {
|
||||
|
||||
override var mainUrl = "https://hdmovie2.boo"
|
||||
override var mainUrl = "https://hdmovie2.li"
|
||||
override var name = "Hdmovie2"
|
||||
override val mainPage = mainPageOf(
|
||||
"trending" to "Trending",
|
||||
|
@ -44,7 +44,7 @@ class Hdmovie2 : Movierulzhd() {
|
|||
} else {
|
||||
var document = app.get(data).document
|
||||
if (document.select("title").text() == "Just a moment...") {
|
||||
document = app.get(data, interceptor = interceptor).document
|
||||
document = app.get(data).document
|
||||
}
|
||||
val id = document.select("meta#dooplay-ajax-counter").attr("data-postid")
|
||||
val type = if (data.contains("/movies/")) "movie" else "tv"
|
||||
|
|
|
@ -4,7 +4,6 @@ import com.fasterxml.jackson.annotation.JsonProperty
|
|||
import com.lagradost.cloudstream3.*
|
||||
import com.lagradost.cloudstream3.LoadResponse.Companion.addActors
|
||||
import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer
|
||||
import com.lagradost.cloudstream3.network.CloudflareKiller
|
||||
import com.lagradost.cloudstream3.utils.*
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.toJson
|
||||
import org.jsoup.nodes.Element
|
||||
|
@ -34,18 +33,13 @@ open class Movierulzhd : MainAPI() {
|
|||
"episodes" to "Episode",
|
||||
)
|
||||
|
||||
val interceptor = CloudflareKiller()
|
||||
|
||||
override suspend fun getMainPage(
|
||||
page: Int,
|
||||
request: MainPageRequest
|
||||
): HomePageResponse {
|
||||
var document = app.get("$mainUrl/${request.data}/page/$page").document
|
||||
if (document.select("title").text() == "Just a moment...") {
|
||||
document = app.get(request.data + page, interceptor = interceptor).document
|
||||
}
|
||||
val document = app.get("$mainUrl/${request.data}/page/$page").document
|
||||
val home =
|
||||
document.select("div.items.normal article, div#archive-content article").mapNotNull {
|
||||
document.select("div.items.normal article, div#archive-content article, div.items.full article").mapNotNull {
|
||||
it.toSearchResult()
|
||||
}
|
||||
return newHomePageResponse(request.name, home)
|
||||
|
@ -74,23 +68,17 @@ open class Movierulzhd : MainAPI() {
|
|||
private fun Element.toSearchResult(): SearchResponse? {
|
||||
val title = this.selectFirst("h3 > a")?.text() ?: return null
|
||||
val href = getProperLink(fixUrl(this.selectFirst("h3 > a")!!.attr("href")))
|
||||
val posterUrl = fixUrlNull(this.select("div.poster img").last()?.attr("src"))
|
||||
val posterUrl = fixUrlNull(this.select("div.poster img").last()?.getImageAttr())
|
||||
val quality = getQualityFromString(this.select("span.quality").text())
|
||||
return newMovieSearchResponse(title, href, TvType.Movie) {
|
||||
this.posterUrl = posterUrl
|
||||
this.quality = quality
|
||||
posterHeaders = interceptor.getCookieHeaders(mainUrl).toMap()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override suspend fun search(query: String): List<SearchResponse> {
|
||||
val link = "$mainUrl/search/$query"
|
||||
var document = app.get(link).document
|
||||
if (document.select("title").text() == "Just a moment...") {
|
||||
document = app.get(link, interceptor = interceptor).document
|
||||
}
|
||||
|
||||
val document = app.get("$mainUrl/search/$query").document
|
||||
return document.select("div.result-item").map {
|
||||
val title =
|
||||
it.selectFirst("div.title > a")!!.text().replace(Regex("\\(\\d{4}\\)"), "").trim()
|
||||
|
@ -98,21 +86,17 @@ open class Movierulzhd : MainAPI() {
|
|||
val posterUrl = it.selectFirst("img")!!.attr("src").toString()
|
||||
newMovieSearchResponse(title, href, TvType.TvSeries) {
|
||||
this.posterUrl = posterUrl
|
||||
posterHeaders = interceptor.getCookieHeaders(mainUrl).toMap()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun load(url: String): LoadResponse {
|
||||
val request = app.get(url)
|
||||
var document = request.document
|
||||
if (document.select("title").text() == "Just a moment...") {
|
||||
document = app.get(url, interceptor = interceptor).document
|
||||
}
|
||||
val document = request.document
|
||||
directUrl = getBaseUrl(request.url)
|
||||
val title =
|
||||
document.selectFirst("div.data > h1")?.text()?.trim().toString()
|
||||
val poster = fixUrlNull(document.select("div.poster img:last-child").attr("src"))
|
||||
val poster = fixUrlNull(document.selectFirst("div.poster img:last-child")?.getImageAttr())
|
||||
val tags = document.select("div.sgeneros > a").map { it.text() }
|
||||
|
||||
val year = Regex(",\\s?(\\d+)").find(
|
||||
|
@ -139,10 +123,9 @@ open class Movierulzhd : MainAPI() {
|
|||
val recName =
|
||||
it.selectFirst("a")!!.attr("href").toString().removeSuffix("/").split("/").last()
|
||||
val recHref = it.selectFirst("a")!!.attr("href")
|
||||
val recPosterUrl = it.selectFirst("img")?.attr("src").toString()
|
||||
val recPosterUrl = it.selectFirst("img")?.getImageAttr()
|
||||
newTvSeriesSearchResponse(recName, recHref, TvType.TvSeries) {
|
||||
this.posterUrl = recPosterUrl
|
||||
posterHeaders = interceptor.getCookieHeaders(url).toMap()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -151,7 +134,7 @@ open class Movierulzhd : MainAPI() {
|
|||
document.select("ul.episodios > li").map {
|
||||
val href = it.select("a").attr("href")
|
||||
val name = fixTitle(it.select("div.episodiotitle > a").text().trim())
|
||||
val image = it.select("div.imagen > img").attr("src")
|
||||
val image = it.selectFirst("div.imagen > img")?.getImageAttr()
|
||||
val episode =
|
||||
it.select("div.numerando").text().replace(" ", "").split("-").last()
|
||||
.toIntOrNull()
|
||||
|
@ -187,7 +170,6 @@ open class Movierulzhd : MainAPI() {
|
|||
addActors(actors)
|
||||
this.recommendations = recommendations
|
||||
addTrailer(trailer)
|
||||
posterHeaders = interceptor.getCookieHeaders(url).toMap()
|
||||
}
|
||||
} else {
|
||||
newMovieLoadResponse(title, url, TvType.Movie, url) {
|
||||
|
@ -199,7 +181,6 @@ open class Movierulzhd : MainAPI() {
|
|||
addActors(actors)
|
||||
this.recommendations = recommendations
|
||||
addTrailer(trailer)
|
||||
posterHeaders = interceptor.getCookieHeaders(url).toMap()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -230,18 +211,17 @@ open class Movierulzhd : MainAPI() {
|
|||
referer = data,
|
||||
headers = mapOf("X-Requested-With" to "XMLHttpRequest")
|
||||
).parsed<ResponseHash>().embed_url
|
||||
if (!source.contains("youtube")) loadCustomExtractor(loadData?.tag, source, "$directUrl/", subtitleCallback, callback)
|
||||
if (!source.contains("youtube")) loadCustomExtractor(source, "$directUrl/", subtitleCallback, callback)
|
||||
} else {
|
||||
var document = app.get(data).document
|
||||
if (document.select("title").text() == "Just a moment...") {
|
||||
document = app.get(data, interceptor = interceptor).document
|
||||
}
|
||||
val id = document.select("meta#dooplay-ajax-counter").attr("data-postid")
|
||||
val type = if (data.contains("/movies/")) "movie" else "tv"
|
||||
val document = app.get(data).document
|
||||
|
||||
document.select("ul#playeroptionsul > li").map {
|
||||
it.attr("data-nume") to it.select("span.title").text()
|
||||
}.apmap { (nume, tag) ->
|
||||
Triple(
|
||||
it.attr("data-post"),
|
||||
it.attr("data-nume"),
|
||||
it.attr("data-type")
|
||||
)
|
||||
}.apmap { (id, nume, type) ->
|
||||
val source = app.post(
|
||||
url = "$directUrl/wp-admin/admin-ajax.php",
|
||||
data = mapOf(
|
||||
|
@ -256,7 +236,6 @@ open class Movierulzhd : MainAPI() {
|
|||
|
||||
when {
|
||||
!source.contains("youtube") -> loadCustomExtractor(
|
||||
tag,
|
||||
source,
|
||||
"$directUrl/",
|
||||
subtitleCallback,
|
||||
|
@ -269,8 +248,16 @@ open class Movierulzhd : MainAPI() {
|
|||
return true
|
||||
}
|
||||
|
||||
private fun Element.getImageAttr(): String? {
|
||||
return when {
|
||||
this.hasAttr("data-src") -> this.attr("abs:data-src")
|
||||
this.hasAttr("data-lazy-src") -> this.attr("abs:data-lazy-src")
|
||||
this.hasAttr("srcset") -> this.attr("abs:srcset").substringBefore(" ")
|
||||
else -> this.attr("abs:src")
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun loadCustomExtractor(
|
||||
name: String? = null,
|
||||
url: String,
|
||||
referer: String? = null,
|
||||
subtitleCallback: (SubtitleFile) -> Unit,
|
||||
|
@ -278,21 +265,23 @@ open class Movierulzhd : MainAPI() {
|
|||
quality: Int? = null,
|
||||
) {
|
||||
loadExtractor(url, referer, subtitleCallback) { link ->
|
||||
callback.invoke(
|
||||
ExtractorLink(
|
||||
name ?: link.source,
|
||||
name ?: link.name,
|
||||
link.url,
|
||||
link.referer,
|
||||
when (link.type) {
|
||||
ExtractorLinkType.M3U8 -> link.quality
|
||||
else -> quality ?: link.quality
|
||||
},
|
||||
link.type,
|
||||
link.headers,
|
||||
link.extractorData
|
||||
if(link.quality == Qualities.Unknown.value) {
|
||||
callback.invoke(
|
||||
ExtractorLink(
|
||||
link.source,
|
||||
link.name,
|
||||
link.url,
|
||||
link.referer,
|
||||
when (link.type) {
|
||||
ExtractorLinkType.M3U8 -> link.quality
|
||||
else -> quality ?: link.quality
|
||||
},
|
||||
link.type,
|
||||
link.headers,
|
||||
link.extractorData
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -11,7 +11,9 @@ class MovierulzhdPlugin: Plugin() {
|
|||
// All providers should be added in this manner. Please don't edit the providers list directly.
|
||||
registerMainAPI(Movierulzhd())
|
||||
registerMainAPI(Hdmovie2())
|
||||
registerMainAPI(Animesaga())
|
||||
registerExtractorAPI(Sbnmp())
|
||||
registerExtractorAPI(Akamaicdn())
|
||||
registerExtractorAPI(AnimesagaStream())
|
||||
}
|
||||
}
|
|
@ -4,13 +4,9 @@ import com.lagradost.cloudstream3.*
|
|||
import com.lagradost.cloudstream3.LoadResponse.Companion.addAniListId
|
||||
import com.lagradost.cloudstream3.LoadResponse.Companion.addMalId
|
||||
import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer
|
||||
import com.lagradost.cloudstream3.network.CloudflareKiller
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.Qualities
|
||||
import com.lagradost.cloudstream3.utils.loadExtractor
|
||||
import okhttp3.Interceptor
|
||||
import okhttp3.Response
|
||||
import org.jsoup.Jsoup
|
||||
import org.jsoup.nodes.Element
|
||||
|
||||
class Samehadaku : MainAPI() {
|
||||
|
@ -19,26 +15,12 @@ class Samehadaku : MainAPI() {
|
|||
override val hasMainPage = true
|
||||
override var lang = "id"
|
||||
override val hasDownloadSupport = true
|
||||
private val cloudflareKiller by lazy { CloudflareKiller() }
|
||||
private val interceptor by lazy { CloudflareInterceptor(cloudflareKiller) }
|
||||
override val supportedTypes = setOf(
|
||||
TvType.Anime,
|
||||
TvType.AnimeMovie,
|
||||
TvType.OVA
|
||||
)
|
||||
|
||||
class CloudflareInterceptor(private val cloudflareKiller: CloudflareKiller): Interceptor {
|
||||
override fun intercept(chain: Interceptor.Chain): Response {
|
||||
val request = chain.request()
|
||||
val response = chain.proceed(request)
|
||||
val doc = Jsoup.parse(response.peekBody(1024 * 1024).string())
|
||||
if (doc.select("title").text() == "Just a moment...") {
|
||||
return cloudflareKiller.intercept(chain)
|
||||
}
|
||||
return response
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val acefile = "https://acefile.co"
|
||||
|
||||
|
@ -69,7 +51,7 @@ class Samehadaku : MainAPI() {
|
|||
val items = mutableListOf<HomePageList>()
|
||||
|
||||
if (request.name != "Episode Terbaru" && page <= 1) {
|
||||
val doc = app.get(request.data, interceptor = interceptor).document
|
||||
val doc = app.get(request.data).document
|
||||
doc.select("div.widget_senction:not(:contains(Baca Komik))").forEach { block ->
|
||||
val header = block.selectFirst("div.widget-title h3")?.ownText() ?: return@forEach
|
||||
val home = block.select("div.animepost").mapNotNull {
|
||||
|
@ -80,8 +62,7 @@ class Samehadaku : MainAPI() {
|
|||
}
|
||||
|
||||
if (request.name == "Episode Terbaru") {
|
||||
val home =
|
||||
app.get(request.data + page, interceptor = interceptor).document.selectFirst("div.post-show")?.select("ul li")
|
||||
val home = app.get(request.data + page).document.selectFirst("div.post-show")?.select("ul li")
|
||||
?.mapNotNull {
|
||||
it.toSearchResult()
|
||||
} ?: throw ErrorLoadingException("No Media Found")
|
||||
|
@ -101,13 +82,12 @@ class Samehadaku : MainAPI() {
|
|||
return newAnimeSearchResponse(title, href ?: return null, TvType.Anime) {
|
||||
this.posterUrl = posterUrl
|
||||
addSub(epNum)
|
||||
posterHeaders = cloudflareKiller.getCookieHeaders(mainUrl).toMap()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override suspend fun search(query: String): List<SearchResponse> {
|
||||
val document = app.get("$mainUrl/?s=$query", interceptor = interceptor).document
|
||||
val document = app.get("$mainUrl/?s=$query").document
|
||||
return document.select("main#main div.animepost").mapNotNull {
|
||||
it.toSearchResult()
|
||||
}
|
||||
|
@ -117,10 +97,10 @@ class Samehadaku : MainAPI() {
|
|||
val fixUrl = if (url.contains("/anime/")) {
|
||||
url
|
||||
} else {
|
||||
app.get(url, interceptor = interceptor).document.selectFirst("div.nvs.nvsc a")?.attr("href")
|
||||
app.get(url).document.selectFirst("div.nvs.nvsc a")?.attr("href")
|
||||
}
|
||||
|
||||
val document = app.get(fixUrl ?: return null, interceptor = interceptor).document
|
||||
val document = app.get(fixUrl ?: return null).document
|
||||
val title = document.selectFirst("h1.entry-title")?.text()?.removeBloat() ?: return null
|
||||
val poster = document.selectFirst("div.thumb > img")?.attr("src")
|
||||
val tags = document.select("div.genre-info > a").map { it.text() }
|
||||
|
@ -165,7 +145,6 @@ class Samehadaku : MainAPI() {
|
|||
this.recommendations = recommendations
|
||||
addMalId(tracker?.malId)
|
||||
addAniListId(tracker?.aniId?.toIntOrNull())
|
||||
posterHeaders = cloudflareKiller.getCookieHeaders(mainUrl).toMap()
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -177,7 +156,7 @@ class Samehadaku : MainAPI() {
|
|||
callback: (ExtractorLink) -> Unit
|
||||
): Boolean {
|
||||
|
||||
val document = app.get(data, interceptor = interceptor).document
|
||||
val document = app.get(data).document
|
||||
|
||||
argamap(
|
||||
{
|
||||
|
@ -196,7 +175,6 @@ class Samehadaku : MainAPI() {
|
|||
),
|
||||
referer = data,
|
||||
headers = mapOf("X-Requested-With" to "XMLHttpRequest"),
|
||||
interceptor = interceptor
|
||||
).document.select("iframe").attr("src")
|
||||
|
||||
loadFixedExtractor(fixedIframe(iframe), it.text(), "$mainUrl/", subtitleCallback, callback)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import org.jetbrains.kotlin.konan.properties.Properties
|
||||
|
||||
// use an integer for version numbers
|
||||
version = 197
|
||||
version = 204
|
||||
|
||||
android {
|
||||
defaultConfig {
|
||||
|
@ -9,15 +9,12 @@ android {
|
|||
properties.load(project.rootProject.file("local.properties").inputStream())
|
||||
|
||||
buildConfigField("String", "TMDB_API", "\"${properties.getProperty("TMDB_API")}\"")
|
||||
buildConfigField("String", "OMOVIES_API", "\"${properties.getProperty("OMOVIES_API")}\"")
|
||||
buildConfigField("String", "CINEMATV_API", "\"${properties.getProperty("CINEMATV_API")}\"")
|
||||
buildConfigField("String", "SFMOVIES_API", "\"${properties.getProperty("SFMOVIES_API")}\"")
|
||||
buildConfigField("String", "ZSHOW_API", "\"${properties.getProperty("ZSHOW_API")}\"")
|
||||
buildConfigField("String", "SORA_API", "\"${properties.getProperty("SORA_API")}\"")
|
||||
buildConfigField("String", "SORAHE", "\"${properties.getProperty("SORAHE")}\"")
|
||||
buildConfigField("String", "SORAXA", "\"${properties.getProperty("SORAXA")}\"")
|
||||
buildConfigField("String", "SORATED", "\"${properties.getProperty("SORATED")}\"")
|
||||
buildConfigField("String", "DUMP_API", "\"${properties.getProperty("DUMP_API")}\"")
|
||||
buildConfigField("String", "DUMP_KEY", "\"${properties.getProperty("DUMP_KEY")}\"")
|
||||
buildConfigField("String", "PRIMEWIRE_KEY", "\"${properties.getProperty("PRIMEWIRE_KEY")}\"")
|
||||
buildConfigField("String", "CRUNCHYROLL_BASIC_TOKEN", "\"${properties.getProperty("CRUNCHYROLL_BASIC_TOKEN")}\"")
|
||||
buildConfigField("String", "CRUNCHYROLL_REFRESH_TOKEN", "\"${properties.getProperty("CRUNCHYROLL_REFRESH_TOKEN")}\"")
|
||||
}
|
||||
|
|
|
@ -6,17 +6,13 @@ import com.lagradost.cloudstream3.extractors.StreamSB
|
|||
import com.lagradost.cloudstream3.extractors.Voe
|
||||
import com.fasterxml.jackson.annotation.JsonProperty
|
||||
import com.lagradost.cloudstream3.APIHolder.getCaptchaToken
|
||||
import com.lagradost.cloudstream3.ErrorLoadingException
|
||||
import com.lagradost.cloudstream3.SubtitleFile
|
||||
import com.lagradost.cloudstream3.apmap
|
||||
import com.lagradost.cloudstream3.app
|
||||
import com.lagradost.cloudstream3.base64Decode
|
||||
import com.lagradost.cloudstream3.extractors.Pixeldrain
|
||||
import com.lagradost.cloudstream3.extractors.helper.AesHelper
|
||||
import com.lagradost.cloudstream3.extractors.Vidplay
|
||||
import com.lagradost.cloudstream3.utils.*
|
||||
import org.jsoup.nodes.Document
|
||||
import org.mozilla.javascript.Context
|
||||
import org.mozilla.javascript.Scriptable
|
||||
import java.math.BigInteger
|
||||
import java.security.MessageDigest
|
||||
|
||||
|
@ -202,9 +198,10 @@ open class VCloud : ExtractorApi() {
|
|||
val res = app.get(url)
|
||||
val doc = res.document
|
||||
val changedLink = doc.selectFirst("script:containsData(url =)")?.data()?.let {
|
||||
"""url\s*=\s*['"](.*)['"];""".toRegex().find(it)?.groupValues?.get(1)
|
||||
?.substringAfter("r=")
|
||||
} ?: doc.selectFirst("div.div.vd.d-none a")?.attr("href")
|
||||
val regex = """url\s*=\s*['"](.*)['"];""".toRegex()
|
||||
val doc2 = app.get(regex.find(it)?.groupValues?.get(1) ?: return).text
|
||||
regex.find(doc2)?.groupValues?.get(1)?.substringAfter("r=")
|
||||
}
|
||||
val header = doc.selectFirst("div.card-header")?.text()
|
||||
app.get(
|
||||
base64Decode(changedLink ?: return), cookies = res.cookies, headers = mapOf(
|
||||
|
@ -212,7 +209,7 @@ open class VCloud : ExtractorApi() {
|
|||
)
|
||||
).document.select("p.text-success ~ a").apmap {
|
||||
val link = it.attr("href")
|
||||
if (link.contains("workers.dev")) {
|
||||
if (link.contains("workers.dev") || it.text().contains("[Server : 1]") || link.contains("/dl.php?")) {
|
||||
callback.invoke(
|
||||
ExtractorLink(
|
||||
this.name,
|
||||
|
@ -238,83 +235,6 @@ open class VCloud : ExtractorApi() {
|
|||
|
||||
}
|
||||
|
||||
object NineTv {
|
||||
|
||||
suspend fun getUrl(
|
||||
url: String,
|
||||
referer: String?,
|
||||
subtitleCallback: (SubtitleFile) -> Unit,
|
||||
callback: (ExtractorLink) -> Unit
|
||||
) {
|
||||
val mainUrl = getBaseUrl(url)
|
||||
val res = app.get(url, headers = mapOf(
|
||||
"Accept" to "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
|
||||
"Accept-Language" to "en-US,en;q=0.5",
|
||||
"Referer" to (referer ?: ""),
|
||||
))
|
||||
val master = Regex("\\s*=\\s*'([^']+)").find(res.text)?.groupValues?.get(1)
|
||||
val key = "tSIsE8FgpRkv3QQQ"
|
||||
val decrypt = AesHelper.cryptoAESHandler(master ?: return, key.toByteArray(), false)
|
||||
?.replace("\\", "")
|
||||
?: throw ErrorLoadingException("failed to decrypt")
|
||||
|
||||
val source = Regex(""""?file"?:\s*"([^"]+)""").find(decrypt)?.groupValues?.get(1)
|
||||
val tracks = Regex("""tracks:\s*\[(.+)]""").find(decrypt)?.groupValues?.get(1)
|
||||
val name = url.getHost()
|
||||
|
||||
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
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun Document.getKeys(): String? {
|
||||
val script = (this.selectFirst("script:containsData(eval\\()")?.data()
|
||||
?.replace("eval(", "var result=")?.removeSuffix(");") + ";").trimIndent()
|
||||
val run = script.runJS("result")
|
||||
return """,\s*'([^']+)""".toRegex().find(run)?.groupValues?.getOrNull(1)
|
||||
}
|
||||
|
||||
private fun String.runJS(variable: String): String {
|
||||
val rhino = Context.enter()
|
||||
rhino.optimizationLevel = -1
|
||||
val scope: Scriptable = rhino.initSafeStandardObjects()
|
||||
val result: String
|
||||
try {
|
||||
rhino.evaluateString(scope, this, "JavaScript", 1, null)
|
||||
result = Context.toString(scope.get(variable, scope))
|
||||
} finally {
|
||||
Context.exit()
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
data class Tracks(
|
||||
@JsonProperty("file") val file: String? = null,
|
||||
@JsonProperty("label") val label: String? = null,
|
||||
@JsonProperty("kind") val kind: String? = null,
|
||||
)
|
||||
}
|
||||
|
||||
open class Streamruby : ExtractorApi() {
|
||||
override val name = "Streamruby"
|
||||
override val mainUrl = "https://streamruby.com"
|
||||
|
@ -390,6 +310,40 @@ open class Uploadever : ExtractorApi() {
|
|||
|
||||
}
|
||||
|
||||
open class Netembed : ExtractorApi() {
|
||||
override var name: String = "Netembed"
|
||||
override var mainUrl: String = "https://play.netembed.xyz"
|
||||
override val requiresReferer = true
|
||||
|
||||
override suspend fun getUrl(
|
||||
url: String,
|
||||
referer: String?,
|
||||
subtitleCallback: (SubtitleFile) -> Unit,
|
||||
callback: (ExtractorLink) -> Unit
|
||||
) {
|
||||
val response = app.get(url, referer = referer)
|
||||
val script = getAndUnpack(response.text)
|
||||
val m3u8 = Regex("((https:|http:)//.*\\.m3u8)").find(script)?.groupValues?.getOrNull(1)
|
||||
|
||||
callback.invoke(
|
||||
ExtractorLink(
|
||||
this.name,
|
||||
this.name,
|
||||
m3u8 ?: return,
|
||||
"$mainUrl/",
|
||||
getQuality(m3u8),
|
||||
INFER_TYPE
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private suspend fun getQuality(url: String) : Int {
|
||||
val res = app.get(url, referer = "$mainUrl/").text
|
||||
val regex = "#quality:\\s*(\\S+)".toRegex().find(res)?.groupValues?.get(1)
|
||||
return getQualityFromName(regex)
|
||||
}
|
||||
}
|
||||
|
||||
class Streamwish : Filesim() {
|
||||
override val name = "Streamwish"
|
||||
override var mainUrl = "https://streamwish.to"
|
||||
|
@ -405,11 +359,6 @@ class FilelionsTo : Filesim() {
|
|||
override var mainUrl = "https://filelions.to"
|
||||
}
|
||||
|
||||
class Hubcloud : VCloud() {
|
||||
override val name = "Hubcloud"
|
||||
override val mainUrl = "https://hubcloud.in"
|
||||
}
|
||||
|
||||
class Pixeldra : Pixeldrain() {
|
||||
override val mainUrl = "https://pixeldra.in"
|
||||
}
|
||||
|
@ -447,4 +396,8 @@ class Yipsu : Voe() {
|
|||
class Embedwish : Filesim() {
|
||||
override val name = "Embedwish"
|
||||
override var mainUrl = "https://embedwish.com"
|
||||
}
|
||||
|
||||
class Vidplay2 : Vidplay() {
|
||||
override val mainUrl = "https://vidplay.online"
|
||||
}
|
|
@ -2,6 +2,7 @@ package com.hexated
|
|||
|
||||
import com.hexated.AESGCM.decrypt
|
||||
import com.lagradost.cloudstream3.*
|
||||
import com.lagradost.cloudstream3.APIHolder.unixTime
|
||||
import com.lagradost.cloudstream3.APIHolder.unixTimeMS
|
||||
import com.lagradost.cloudstream3.utils.*
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson
|
||||
|
@ -110,7 +111,8 @@ object SoraExtractor : SoraStream() {
|
|||
"$vidSrcAPI/embed/tv?tmdb=$id&season=$season&episode=$episode"
|
||||
}
|
||||
|
||||
val iframedoc = app.get(url).document.select("iframe#player_iframe").attr("src").let { httpsify(it) }
|
||||
val iframedoc =
|
||||
app.get(url).document.select("iframe#player_iframe").attr("src").let { httpsify(it) }
|
||||
val doc = app.get(iframedoc, referer = url).document
|
||||
|
||||
val index = doc.select("body").attr("data-i")
|
||||
|
@ -246,6 +248,7 @@ object SoraExtractor : SoraStream() {
|
|||
} else {
|
||||
"$multimoviesAPI/episodes/$fixTitle-${season}x${episode}"
|
||||
}
|
||||
invokeWpmovies(null, url, subtitleCallback, callback)
|
||||
}
|
||||
|
||||
suspend fun invokeNetmovies(
|
||||
|
@ -273,12 +276,11 @@ object SoraExtractor : SoraStream() {
|
|||
subtitleCallback: (SubtitleFile) -> Unit,
|
||||
callback: (ExtractorLink) -> Unit
|
||||
) {
|
||||
val api = BuildConfig.ZSHOW_API
|
||||
val fixTitle = title.createSlug()
|
||||
val url = if (season == null) {
|
||||
"$api/movie/$fixTitle-$year"
|
||||
"$zshowAPI/movie/$fixTitle-$year"
|
||||
} else {
|
||||
"$api/episode/$fixTitle-season-$season-episode-$episode"
|
||||
"$zshowAPI/episode/$fixTitle-season-$season-episode-$episode"
|
||||
}
|
||||
invokeWpmovies("ZShow", url, subtitleCallback, callback, encrypt = true)
|
||||
}
|
||||
|
@ -326,20 +328,7 @@ object SoraExtractor : SoraStream() {
|
|||
else -> it.embed_url
|
||||
}
|
||||
} ?: return@apmap
|
||||
val sources = arrayOf(
|
||||
"https://chillx.top",
|
||||
"https://watchx.top",
|
||||
"https://bestx.stream",
|
||||
"https://w1.moviesapi.club"
|
||||
)
|
||||
when {
|
||||
sources.any { source.startsWith(it) } -> NineTv.getUrl(
|
||||
source,
|
||||
"$referer/",
|
||||
subtitleCallback,
|
||||
callback
|
||||
)
|
||||
|
||||
!source.contains("youtube") -> {
|
||||
loadCustomExtractor(name, source, "$referer/", subtitleCallback, callback)
|
||||
}
|
||||
|
@ -451,7 +440,7 @@ object SoraExtractor : SoraStream() {
|
|||
sourcesData?.get("movie")?.get("movie")
|
||||
} else {
|
||||
sourcesData?.get("s$seasonSlug")?.get("e$episodeSlug")
|
||||
}
|
||||
} ?: return
|
||||
val subSources = if (season == null) {
|
||||
subSourcesData?.get("movie")?.get("movie")
|
||||
} else {
|
||||
|
@ -464,39 +453,45 @@ object SoraExtractor : SoraStream() {
|
|||
Regex("var\\suserNonce.*?[\"|'](\\S+?)[\"|'];").find(scriptUser)?.groupValues?.get(1)
|
||||
val userId =
|
||||
Regex("var\\suser_id.*?[\"|'](\\S+?)[\"|'];").find(scriptUser)?.groupValues?.get(1)
|
||||
val linkIDs = sources?.joinToString("") {
|
||||
"&linkIDs%5B%5D=$it"
|
||||
}?.replace("\"", "")
|
||||
|
||||
val json = app.post(
|
||||
"$filmxyAPI/wp-admin/admin-ajax.php",
|
||||
requestBody = "action=get_vid_links$linkIDs&user_id=$userId&nonce=$userNonce".toRequestBody(),
|
||||
referer = url,
|
||||
headers = mapOf(
|
||||
"Accept" to "*/*",
|
||||
"DNT" to "1",
|
||||
"Content-Type" to "application/x-www-form-urlencoded; charset=UTF-8",
|
||||
"Origin" to filmxyAPI,
|
||||
"X-Requested-With" to "XMLHttpRequest",
|
||||
),
|
||||
cookies = filmxyCookies
|
||||
).text.let { tryParseJson<HashMap<String, String>>(it) }
|
||||
val listSources = sources.withIndex()
|
||||
.groupBy { it.index / 2 }
|
||||
.map { entry -> entry.value.map { it.value } }
|
||||
|
||||
sources?.map { source ->
|
||||
val link = json?.get(source)
|
||||
val quality = sourcesDetail?.get(source)?.get("resolution")
|
||||
val server = sourcesDetail?.get(source)?.get("server")
|
||||
val size = sourcesDetail?.get(source)?.get("size")
|
||||
listSources.apmap { src ->
|
||||
val linkIDs = src.joinToString("") {
|
||||
"&linkIDs%5B%5D=$it"
|
||||
}.replace("\"", "")
|
||||
val json = app.post(
|
||||
"$filmxyAPI/wp-admin/admin-ajax.php",
|
||||
requestBody = "action=get_vid_links$linkIDs&user_id=$userId&nonce=$userNonce".toRequestBody(),
|
||||
referer = url,
|
||||
headers = mapOf(
|
||||
"Accept" to "*/*",
|
||||
"DNT" to "1",
|
||||
"Content-Type" to "application/x-www-form-urlencoded; charset=UTF-8",
|
||||
"Origin" to filmxyAPI,
|
||||
"X-Requested-With" to "XMLHttpRequest",
|
||||
),
|
||||
cookies = filmxyCookies
|
||||
).text.let { tryParseJson<HashMap<String, String>>(it) }
|
||||
|
||||
callback.invoke(
|
||||
ExtractorLink(
|
||||
"Filmxy",
|
||||
"Filmxy $server [$size]",
|
||||
link ?: return@map,
|
||||
"$filmxyAPI/",
|
||||
getQualityFromName(quality)
|
||||
src.map { source ->
|
||||
val link = json?.get(source)
|
||||
val quality = sourcesDetail?.get(source)?.get("resolution")
|
||||
val server = sourcesDetail?.get(source)?.get("server")
|
||||
val size = sourcesDetail?.get(source)?.get("size")
|
||||
|
||||
callback.invoke(
|
||||
ExtractorLink(
|
||||
"Filmxy",
|
||||
"Filmxy $server [$size]",
|
||||
link ?: return@map,
|
||||
"$filmxyAPI/",
|
||||
getQualityFromName(quality)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
subSources?.mapKeys { sub ->
|
||||
|
@ -686,12 +681,20 @@ object SoraExtractor : SoraStream() {
|
|||
"$vidsrctoAPI/embed/tv/$imdbId/$season/$episode"
|
||||
}
|
||||
|
||||
val mediaId = app.get(url).document.selectFirst("ul.episodes li a")?.attr("data-id") ?: return
|
||||
val mediaId =
|
||||
app.get(url).document.selectFirst("ul.episodes li a")?.attr("data-id") ?: return
|
||||
|
||||
app.get("$vidsrctoAPI/ajax/embed/episode/$mediaId/sources").parsedSafe<VidsrctoSources>()?.result?.apmap {
|
||||
val encUrl = app.get("$vidsrctoAPI/ajax/embed/source/${it.id}").parsedSafe<VidsrctoResponse>()?.result?.url
|
||||
loadExtractor(vidsrctoDecrypt(encUrl ?: return@apmap), "$vidsrctoAPI/", subtitleCallback, callback)
|
||||
}
|
||||
app.get("$vidsrctoAPI/ajax/embed/episode/$mediaId/sources")
|
||||
.parsedSafe<VidsrctoSources>()?.result?.apmap {
|
||||
val encUrl = app.get("$vidsrctoAPI/ajax/embed/source/${it.id}")
|
||||
.parsedSafe<VidsrctoResponse>()?.result?.url
|
||||
loadExtractor(
|
||||
vidsrctoDecrypt(encUrl ?: return@apmap),
|
||||
"$vidsrctoAPI/",
|
||||
subtitleCallback,
|
||||
callback
|
||||
)
|
||||
}
|
||||
|
||||
val subtitles = app.get("$vidsrctoAPI/ajax/embed/episode/$mediaId/subtitles").text
|
||||
tryParseJson<List<VidsrctoSubtitles>>(subtitles)?.map {
|
||||
|
@ -965,62 +968,50 @@ object SoraExtractor : SoraStream() {
|
|||
title: String? = null,
|
||||
year: Int? = null,
|
||||
season: Int? = null,
|
||||
lastSeason: Int? = null,
|
||||
episode: Int? = null,
|
||||
callback: (ExtractorLink) -> Unit
|
||||
) {
|
||||
val slug = title.createSlug()?.replace("-", " ")
|
||||
val url = "$uhdmoviesAPI/?s=$slug"
|
||||
var doc = app.get(url).document
|
||||
if (doc.select("title").text() == "Just a moment...") {
|
||||
doc = app.get(url, interceptor = CloudflareKiller()).document
|
||||
}
|
||||
val scriptData = doc.select("div.row.gridlove-posts article").map {
|
||||
it.selectFirst("a")?.attr("href") to it.selectFirst("h1")?.text()
|
||||
}
|
||||
val fixTitle = title.createSlug()
|
||||
val (seasonSlug, episodeSlug) = getEpisodeSlug(season, episode)
|
||||
|
||||
val detailUrl = (if (scriptData.size == 1) {
|
||||
scriptData.first()
|
||||
val url = if(season == null) {
|
||||
"$uhdmoviesAPI/download-$fixTitle-$year"
|
||||
} else {
|
||||
scriptData.find { it.second?.filterMedia(title, year, lastSeason) == true }
|
||||
})?.first
|
||||
"$uhdmoviesAPI/download-$fixTitle"
|
||||
}
|
||||
|
||||
val detailDoc = app.get(detailUrl ?: return).document
|
||||
val detailDoc = app.get(url).document
|
||||
|
||||
val iframeList = detailDoc.select("div.entry-content p").map { it }
|
||||
.filter { it.text().filterIframe(season, lastSeason, year, title) }.mapNotNull {
|
||||
if (season == null) {
|
||||
it.text() to it.nextElementSibling()?.select("a")?.attr("href")
|
||||
} else {
|
||||
it.text() to it.nextElementSibling()?.select("a")?.find { child ->
|
||||
child.select("span").text().equals("Episode $episode", true)
|
||||
}?.attr("href")
|
||||
}
|
||||
}.filter { it.second?.contains(Regex("(https:)|(http:)")) == true }
|
||||
val iSelector = if(season == null) {
|
||||
"div.entry-content p:has(:matches($year))"
|
||||
} else {
|
||||
"div.entry-content p:has(:matches((?i)(?:S\\s*$seasonSlug|Season\\s*$seasonSlug)))"
|
||||
}
|
||||
val iframeList = detailDoc.select(iSelector).mapNotNull {
|
||||
if (season == null) {
|
||||
it.text() to it.nextElementSibling()?.select("a")?.attr("href")
|
||||
} else {
|
||||
it.text() to it.nextElementSibling()?.select("a")?.find { child ->
|
||||
child.select("span").text().equals("Episode $episode", true)
|
||||
}?.attr("href")
|
||||
}
|
||||
}.filter { it.first.contains(Regex("(2160p)|(1080p)")) }
|
||||
|
||||
iframeList.apmap { (quality, link) ->
|
||||
val driveLink =
|
||||
when {
|
||||
link?.contains("oddfirm") == true -> bypassHrefli(link)
|
||||
link?.contains("driveleech") == true -> bypassDriveleech(link)
|
||||
else -> bypassTechmny(link ?: return@apmap)
|
||||
}
|
||||
val driveLink = bypassHrefli(link ?: return@apmap)
|
||||
val base = getBaseUrl(driveLink ?: return@apmap)
|
||||
val driveReq = app.get(driveLink)
|
||||
val driveRes = driveReq.document
|
||||
val bitLink = driveRes.select("a.btn.btn-outline-success").attr("href")
|
||||
val insLink =
|
||||
driveRes.select("a.btn.btn-danger:contains(Instant Download)").attr("href")
|
||||
val insLink = driveRes.select("a.btn.btn-danger:contains(Instant Download)").attr("href")
|
||||
val downloadLink = when {
|
||||
insLink.isNotEmpty() -> extractInstantUHD(insLink)
|
||||
driveRes.select("button.btn.btn-success").text()
|
||||
.contains("Direct Download", true) -> extractDirectUHD(driveLink, driveReq)
|
||||
|
||||
bitLink.isNullOrEmpty() -> {
|
||||
val backupIframe = driveRes.select("a.btn.btn-outline-warning").attr("href")
|
||||
extractBackupUHD(backupIframe ?: return@apmap)
|
||||
}
|
||||
|
||||
else -> {
|
||||
extractMirrorUHD(bitLink, base)
|
||||
}
|
||||
|
@ -1038,10 +1029,7 @@ object SoraExtractor : SoraStream() {
|
|||
qualities
|
||||
)
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
suspend fun invokeDotmovies(
|
||||
|
@ -1103,40 +1091,34 @@ object SoraExtractor : SoraStream() {
|
|||
1 -> "Season 1"
|
||||
else -> "Season 1 – $lastSeason"
|
||||
}
|
||||
val media =
|
||||
res.selectFirst("div.blog-items article:has(h3.entry-title:matches((?i)$title.*$match)) a")
|
||||
val media = res.selectFirst("div.blog-items article:has(h3.entry-title:matches((?i)$title.*$match)) a")
|
||||
?.attr("href")
|
||||
|
||||
res = app.get(media ?: return).document
|
||||
val hTag = if (season == null) "h5" else "h3"
|
||||
val aTag = if (season == null) "Download Now" else "V-Cloud"
|
||||
val sTag = if (season == null) "" else "(Season $season|S$seasonSlug)"
|
||||
res.select("div.entry-content > $hTag:matches((?i)$sTag.*(1080p|2160p))")
|
||||
.filter { element -> !element.text().contains("Download", true) }.apmap {
|
||||
val tags =
|
||||
"""(?:1080p|2160p)(.*)""".toRegex().find(it.text())?.groupValues?.get(1)?.trim()
|
||||
val href =
|
||||
it.nextElementSibling()?.select("a:contains($aTag)")?.attr("href")?.let { url ->
|
||||
app.post(
|
||||
"${getBaseUrl(url)}/red.php",
|
||||
data = mapOf("link" to url),
|
||||
referer = "$api/"
|
||||
).text.substringAfter("location.href = \"").substringBefore("\"")
|
||||
}
|
||||
val selector =
|
||||
if (season == null) "p a:contains(V-Cloud)" else "h4:matches(0?$episode) + p a:contains(V-Cloud)"
|
||||
val server =
|
||||
app.get(href ?: return@apmap).document.selectFirst("div.entry-content > $selector")
|
||||
?.attr("href")
|
||||
loadCustomTagExtractor(
|
||||
tags,
|
||||
server ?: return@apmap,
|
||||
"$api/",
|
||||
subtitleCallback,
|
||||
callback,
|
||||
getIndexQuality(it.text())
|
||||
)
|
||||
}
|
||||
val entry = res.select("div.entry-content > $hTag:matches((?i)$sTag.*(1080p|2160p))")
|
||||
.findLast { element -> !element.text().contains("Download", true) } ?: return
|
||||
val tags =
|
||||
"""(?:1080p|2160p)(.*)""".toRegex().find(entry.text())?.groupValues?.get(1)?.trim()
|
||||
val href =
|
||||
entry.nextElementSibling()?.select("a:contains($aTag)")?.attr("href")
|
||||
val selector =
|
||||
if (season == null) "p a:contains(V-Cloud)" else "h4:matches(0?$episode) + p a:contains(V-Cloud)"
|
||||
val server = app.get(
|
||||
href ?: return, interceptor = CloudflareKiller()
|
||||
).document.selectFirst("div.entry-content > $selector")
|
||||
?.attr("href") ?: return
|
||||
|
||||
loadCustomTagExtractor(
|
||||
tags,
|
||||
server,
|
||||
"$api/",
|
||||
subtitleCallback,
|
||||
callback,
|
||||
getIndexQuality(entry.text())
|
||||
)
|
||||
}
|
||||
|
||||
suspend fun invokeHdmovies4u(
|
||||
|
@ -1213,7 +1195,14 @@ object SoraExtractor : SoraStream() {
|
|||
|
||||
iframe.apmap { (iframeLink, title) ->
|
||||
val size = Regex("(?i)\\s(\\S+gb|mb)").find(title)?.groupValues?.getOrNull(1)
|
||||
loadCustomTagExtractor("[$size]",iframeLink, "$gMoviesAPI/", subtitleCallback, callback, getIndexQuality(title))
|
||||
loadCustomTagExtractor(
|
||||
"[$size]",
|
||||
iframeLink,
|
||||
"$gMoviesAPI/",
|
||||
subtitleCallback,
|
||||
callback,
|
||||
getIndexQuality(title)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1304,7 +1293,9 @@ object SoraExtractor : SoraStream() {
|
|||
scriptData.firstOrNull()
|
||||
} else {
|
||||
scriptData.find {
|
||||
it.first.contains(Regex("(?i)$title \\($year\\s?\\)")) && if(season!=null) it.third?.contains("-tvshow-") == true else it.third?.contains("-movie-") == true
|
||||
it.first.contains(Regex("(?i)$title \\($year\\s?\\)")) && if (season != null) it.third?.contains(
|
||||
"-tvshow-"
|
||||
) == true else it.third?.contains("-movie-") == true
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1527,10 +1518,16 @@ object SoraExtractor : SoraStream() {
|
|||
iframe?.apmap {
|
||||
val iframeDoc = app.get(it?.first ?: return@apmap).document
|
||||
val formUrl = iframeDoc.select("form").attr("action")
|
||||
val formData = iframeDoc.select("form button").associate { v -> v.attr("name") to v.attr("value") }
|
||||
val formData =
|
||||
iframeDoc.select("form button").associate { v -> v.attr("name") to v.attr("value") }
|
||||
|
||||
val videoUrl = app.post(formUrl, data = formData, referer = it.first).document.selectFirst("div.d-flex.justify-content-center.flex-wrap a")?.attr("href")
|
||||
val quality = Regex("(\\d{3,4})p").find(it.second)?.groupValues?.getOrNull(1)?.toIntOrNull()
|
||||
val videoUrl = app.post(
|
||||
formUrl,
|
||||
data = formData,
|
||||
referer = it.first
|
||||
).document.selectFirst("div.d-flex.justify-content-center.flex-wrap a")?.attr("href")
|
||||
val quality =
|
||||
Regex("(\\d{3,4})p").find(it.second)?.groupValues?.getOrNull(1)?.toIntOrNull()
|
||||
val qualityName = it.second.replace("${quality}p", "").trim()
|
||||
|
||||
callback.invoke(
|
||||
|
@ -1625,27 +1622,32 @@ object SoraExtractor : SoraStream() {
|
|||
}
|
||||
|
||||
suspend fun invokeSmashyStream(
|
||||
tmdbId: Int? = null,
|
||||
imdbId: String? = null,
|
||||
season: Int? = null,
|
||||
episode: Int? = null,
|
||||
subtitleCallback: (SubtitleFile) -> Unit,
|
||||
callback: (ExtractorLink) -> Unit,
|
||||
) {
|
||||
val url = if (season == null) {
|
||||
"$smashyStreamAPI/playere.php?tmdb=$tmdbId"
|
||||
"$smashyStreamAPI/playere.php?imdb=$imdbId"
|
||||
} else {
|
||||
"$smashyStreamAPI/playere.php?tmdb=$tmdbId&season=$season&episode=$episode"
|
||||
"$smashyStreamAPI/playere.php?imdb=$imdbId&season=$season&episode=$episode"
|
||||
}
|
||||
|
||||
app.get(
|
||||
url, referer = "https://smashystream.xyz/"
|
||||
url, referer = "https://smashystream.com/"
|
||||
).document.select("div#_default-servers a.server").map {
|
||||
it.attr("data-url") to it.text()
|
||||
}.apmap {
|
||||
when {
|
||||
it.second.contains(Regex("(Player F|Player FM)\$")) -> {
|
||||
when (it.second) {
|
||||
"Player F" -> {
|
||||
invokeSmashyFfix(it.second, it.first, url, callback)
|
||||
}
|
||||
|
||||
"Player D (Hindi)" -> {
|
||||
invokeSmashyD(it.first, url, callback)
|
||||
}
|
||||
|
||||
else -> return@apmap
|
||||
}
|
||||
}
|
||||
|
@ -1920,14 +1922,15 @@ object SoraExtractor : SoraStream() {
|
|||
"$twoEmbedAPI/embedtv/$imdbId&s=$season&e=$episode"
|
||||
}
|
||||
|
||||
val framesrc = app.get(url).document.selectFirst("iframe#iframesrc")?.attr("data-src") ?: return
|
||||
val framesrc =
|
||||
app.get(url).document.selectFirst("iframe#iframesrc")?.attr("data-src") ?: return
|
||||
val ref = getBaseUrl(framesrc)
|
||||
val id = framesrc.substringAfter("id=").substringBefore("&")
|
||||
loadExtractor("https://wishfast.top/e/$id", "$ref/", subtitleCallback, callback)
|
||||
|
||||
}
|
||||
|
||||
suspend fun invokeGomovies(
|
||||
suspend fun invokeOmovies(
|
||||
title: String? = null,
|
||||
year: Int? = null,
|
||||
season: Int? = null,
|
||||
|
@ -1940,10 +1943,10 @@ object SoraExtractor : SoraStream() {
|
|||
season,
|
||||
episode,
|
||||
callback,
|
||||
"https://gomovies-online.cam",
|
||||
"Gomovies",
|
||||
"_smQamBQsETb",
|
||||
"_sBWcqbTBMaT"
|
||||
BuildConfig.OMOVIES_API,
|
||||
"Omovies",
|
||||
base64Decode("X3NtUWFtQlFzRVRi"),
|
||||
base64Decode("X3NCV2NxYlRCTWFU")
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -1968,14 +1971,11 @@ object SoraExtractor : SoraStream() {
|
|||
} else {
|
||||
"$title Season $season"
|
||||
}
|
||||
val idCookies =
|
||||
mapOf(
|
||||
"advanced-frontendgomovies7" to "bjd4n0nnv4hlt4fj5cdjgbrne2",
|
||||
"_identitygomovies7" to "52fdc70b008c0b1d881dac0f01cca819edd512de01cc8bbc1224ed4aafb78b52a:2:{i:0;s:18:\"_identitygomovies7\";i:1;s:52:\"[2050366,\"HnVRRAObTASOJEr45YyCM8wiHol0V1ko\",2592000]\";}"
|
||||
val savedCookies = mapOf(
|
||||
"_identitygomovies7" to "52fdc70b008c0b1d881dac0f01cca819edd512de01cc8bbc1224ed4aafb78b52a%3A2%3A%7Bi%3A0%3Bs%3A18%3A%22_identitygomovies7%22%3Bi%3A1%3Bs%3A52%3A%22%5B2050366%2C%22HnVRRAObTASOJEr45YyCM8wiHol0V1ko%22%2C2592000%5D%22%3B%7D",
|
||||
)
|
||||
val req = app.get("$api/search/$query")
|
||||
val doc = req.document
|
||||
var cookies = req.cookies + idCookies
|
||||
val media = doc.select("div.$mediaSelector").map {
|
||||
Triple(
|
||||
it.attr("data-filmName"), it.attr("data-year"), it.select("a").attr("href")
|
||||
|
@ -2003,9 +2003,8 @@ object SoraExtractor : SoraStream() {
|
|||
fixUrl(
|
||||
media.third,
|
||||
api
|
||||
), cookies = cookies
|
||||
)
|
||||
)
|
||||
cookies = cookies + res.cookies
|
||||
res.document.selectFirst("div#$episodeSelector a:contains(Episode ${slug.second})")
|
||||
?.attr("href")
|
||||
} ?: return
|
||||
|
@ -2016,11 +2015,11 @@ object SoraExtractor : SoraStream() {
|
|||
media.third.substringAfterLast("/") to iframe.substringAfterLast("/")
|
||||
.substringBefore("-")
|
||||
}
|
||||
val res = app.get(fixUrl(iframe ?: return, api), cookies = cookies, verify = false)
|
||||
val res = app.get(fixUrl(iframe, api), verify = false)
|
||||
val serverUrl = res.document.selectFirst("script:containsData(pushState)")?.data()?.let {
|
||||
""",\s*'([^']+)""".toRegex().find(it)?.groupValues?.get(1)
|
||||
} ?: return
|
||||
cookies = cookies + res.cookies
|
||||
val cookies = savedCookies + res.cookies
|
||||
val url = res.document.select("meta[property=og:url]").attr("content")
|
||||
val headers = mapOf("X-Requested-With" to "XMLHttpRequest")
|
||||
val qualities = intArrayOf(2160, 1440, 1080, 720, 480, 360)
|
||||
|
@ -2064,7 +2063,6 @@ object SoraExtractor : SoraStream() {
|
|||
subtitleCallback: (SubtitleFile) -> Unit,
|
||||
callback: (ExtractorLink) -> Unit,
|
||||
) {
|
||||
val ref = "https://blackvid.space/"
|
||||
val key = "b6055c533c19131a638c3d2299d525d5ec08a814"
|
||||
val url = if (season == null) {
|
||||
"$blackvidAPI/v3/movie/sources/$tmdbId?key=$key"
|
||||
|
@ -2072,7 +2070,8 @@ object SoraExtractor : SoraStream() {
|
|||
"$blackvidAPI/v3/tv/sources/$tmdbId/$season/$episode?key=$key"
|
||||
}
|
||||
|
||||
val data = app.get(url, timeout = 120L, referer = ref).okhttpResponse.peekBody(1024 * 1024).bytes().decrypt("2378f8e4e844f2dc839ab48f66e00acc2305a401")
|
||||
val data = request(url,).peekBody(1024 * 512).source().buffer.readByteArray()
|
||||
.decrypt("2378f8e4e844f2dc839ab48f66e00acc2305a401")
|
||||
val json = tryParseJson<BlackvidResponses>(data)
|
||||
|
||||
json?.sources?.map { source ->
|
||||
|
@ -2082,7 +2081,7 @@ object SoraExtractor : SoraStream() {
|
|||
"Blackvid",
|
||||
"Blackvid${source.label}",
|
||||
s.url ?: return@s,
|
||||
ref,
|
||||
"https://blackvid.space/",
|
||||
if (s.quality.equals("4k")) Qualities.P2160.value else s.quality?.toIntOrNull()
|
||||
?: Qualities.P1080.value,
|
||||
INFER_TYPE
|
||||
|
@ -2163,7 +2162,7 @@ object SoraExtractor : SoraStream() {
|
|||
|
||||
}
|
||||
|
||||
suspend fun invokeWatchOnline(
|
||||
suspend fun invokeCinemaTv(
|
||||
imdbId: String? = null,
|
||||
title: String? = null,
|
||||
year: Int? = null,
|
||||
|
@ -2175,17 +2174,19 @@ object SoraExtractor : SoraStream() {
|
|||
val id = imdbId?.removePrefix("tt")
|
||||
val slug = title.createSlug()
|
||||
val url = if (season == null) {
|
||||
"$watchOnlineAPI/movies/play/$id-$slug-$year"
|
||||
"$cinemaTvAPI/movies/play/$id-$slug-$year"
|
||||
} else {
|
||||
"$watchOnlineAPI/shows/play/$id-$slug-$year"
|
||||
"$cinemaTvAPI/shows/play/$id-$slug-$year"
|
||||
}
|
||||
|
||||
val doc = app.get(
|
||||
url.replace(
|
||||
watchOnlineAPI,
|
||||
"https://ditairridgeleg.monster"
|
||||
) + "?mid=1&sid=9k9iupt5sebbnfajrc6ti3ht7l&sec=1974bc4a902c4d69fcbab261dcec69094a9b8164&t=1694986826984"
|
||||
).document
|
||||
val specialCookies = "PHPSESSID=e555h63ilisoj2l6j7b5d4jb6p; _csrf=9597150e45f485ad9c4f2e06a2572534d8415337eda9d48d0ecfa25b73b6a9e1a%3A2%3A%7Bi%3A0%3Bs%3A5%3A%22_csrf%22%3Bi%3A1%3Bs%3A32%3A%222HcnegjGB0nX205FAUPb86fqMx9HWIF1%22%3B%7D; _ga=GA1.1.1195498587.1701871187; _ga_VZD7HJ3WK6=GS1.1.$unixTime.4.0.1.$unixTime.0.0.0"
|
||||
val headers = mapOf(
|
||||
"Cookie" to specialCookies,
|
||||
"Connection" to "keep-alive",
|
||||
"x-requested-with" to "XMLHttpRequest",
|
||||
)
|
||||
|
||||
val doc = app.get(url, headers = headers).document
|
||||
val script = doc.selectFirst("script:containsData(hash:)")?.data()
|
||||
val hash = Regex("hash:\\s*['\"](\\S+)['\"]").find(script ?: return)?.groupValues?.get(1)
|
||||
val expires = Regex("expires:\\s*(\\d+)").find(script)?.groupValues?.get(1)
|
||||
|
@ -2196,24 +2197,24 @@ object SoraExtractor : SoraStream() {
|
|||
}).let { it.toRegex().find(script)?.groupValues?.get(1) }
|
||||
|
||||
val videoUrl = if (season == null) {
|
||||
"$watchOnlineAPI/api/v1/security/movie-access?id_movie=$episodeId&hash=$hash&expires=$expires"
|
||||
"$cinemaTvAPI/api/v1/security/movie-access?id_movie=$episodeId&hash=$hash&expires=$expires"
|
||||
} else {
|
||||
"$watchOnlineAPI/api/v1/security/episode-access?id_episode=$episodeId&hash=$hash&expires=$expires"
|
||||
"$cinemaTvAPI/api/v1/security/episode-access?id_episode=$episodeId&hash=$hash&expires=$expires"
|
||||
}
|
||||
|
||||
val sources = app.get(
|
||||
videoUrl,
|
||||
referer = url,
|
||||
headers = mapOf("X-Requested-With" to "XMLHttpRequest")
|
||||
).parsedSafe<WatchOnlineResponse>()
|
||||
).parsedSafe<CinemaTvResponse>()
|
||||
|
||||
sources?.streams?.mapKeys { source ->
|
||||
callback.invoke(
|
||||
ExtractorLink(
|
||||
"WatchOnline",
|
||||
"WatchOnline",
|
||||
"CinemaTv",
|
||||
"CinemaTv",
|
||||
source.value,
|
||||
"$watchOnlineAPI/",
|
||||
"$cinemaTvAPI/",
|
||||
getQualityFromName(source.key),
|
||||
true
|
||||
)
|
||||
|
@ -2225,7 +2226,7 @@ object SoraExtractor : SoraStream() {
|
|||
subtitleCallback.invoke(
|
||||
SubtitleFile(
|
||||
sub.language ?: return@map,
|
||||
if (file.startsWith("[")) return@map else fixUrl(file, watchOnlineAPI),
|
||||
if (file.startsWith("[")) return@map else fixUrl(file, cinemaTvAPI),
|
||||
)
|
||||
)
|
||||
}
|
||||
|
@ -2248,7 +2249,7 @@ object SoraExtractor : SoraStream() {
|
|||
val iframe = app.get(url, referer = "https://pressplay.top/").document.selectFirst("iframe")
|
||||
?.attr("src")
|
||||
|
||||
NineTv.getUrl(iframe ?: return, "$nineTvAPI/", subtitleCallback, callback)
|
||||
loadExtractor(iframe ?: return, "$nineTvAPI/", subtitleCallback, callback)
|
||||
|
||||
}
|
||||
|
||||
|
@ -2261,9 +2262,11 @@ object SoraExtractor : SoraStream() {
|
|||
) {
|
||||
val referer = "https://bflix.gs/"
|
||||
val slug = getEpisodeSlug(season, episode)
|
||||
var url = if (season == null) "$nowTvAPI/$tmdbId.mp4" else "$nowTvAPI/tv/$tmdbId/s${season}e${slug.second}.mp4"
|
||||
var url =
|
||||
if (season == null) "$nowTvAPI/$tmdbId.mp4" else "$nowTvAPI/tv/$tmdbId/s${season}e${slug.second}.mp4"
|
||||
if (!app.get(url, referer = referer).isSuccessful) {
|
||||
url = if (season == null) "$nowTvAPI/$imdbId.mp4" else "$nowTvAPI/tv/$imdbId/s${season}e${slug.second}.mp4"
|
||||
url =
|
||||
if (season == null) "$nowTvAPI/$imdbId.mp4" else "$nowTvAPI/tv/$imdbId/s${season}e${slug.second}.mp4"
|
||||
if (!app.get(url, referer = referer).isSuccessful) return
|
||||
}
|
||||
callback.invoke(
|
||||
|
@ -2463,7 +2466,7 @@ object SoraExtractor : SoraStream() {
|
|||
ExtractorLink(
|
||||
"SFMovies",
|
||||
"SFMovies",
|
||||
fixUrl(video, base64DecodeAPI("aQ==YXA=dGE=ZGE=c3Q=cmU=dC8=bmU=cy4=b3c=bmQ=d2k=ZS4=b3I=LmM=b2I=Ymw=aS4=YXA=dGE=ZGE=c3Q=cmU=Ly8=czo=dHA=aHQ=")),
|
||||
fixUrl(video, getSfServer()),
|
||||
"",
|
||||
Qualities.P1080.value,
|
||||
INFER_TYPE
|
||||
|
|
|
@ -152,14 +152,14 @@ data class JikanResponse(
|
|||
@JsonProperty("data") val data: JikanData? = null,
|
||||
)
|
||||
|
||||
data class WatchOnlineSubtitles(
|
||||
data class CinemaTvSubtitles(
|
||||
@JsonProperty("language") val language: String? = null,
|
||||
@JsonProperty("file") val file: Any? = null,
|
||||
)
|
||||
|
||||
data class WatchOnlineResponse(
|
||||
data class CinemaTvResponse(
|
||||
@JsonProperty("streams") val streams: HashMap<String, String>? = null,
|
||||
@JsonProperty("subtitles") val subtitles: ArrayList<WatchOnlineSubtitles>? = arrayListOf(),
|
||||
@JsonProperty("subtitles") val subtitles: ArrayList<CinemaTvSubtitles>? = arrayListOf(),
|
||||
)
|
||||
|
||||
data class VidsrctoResult(
|
||||
|
@ -424,4 +424,13 @@ data class RidoSearch(
|
|||
data class SmashySources(
|
||||
@JsonProperty("sourceUrls") var sourceUrls: ArrayList<String>? = arrayListOf(),
|
||||
@JsonProperty("subtitleUrls") var subtitleUrls: String? = null,
|
||||
)
|
||||
|
||||
data class SmashyDSources(
|
||||
@JsonProperty("sourceUrls") var sourceUrls: ArrayList<SmashyDSourcesUrls>? = arrayListOf(),
|
||||
)
|
||||
|
||||
data class SmashyDSourcesUrls(
|
||||
@JsonProperty("file") var file: String? = null,
|
||||
@JsonProperty("title") var title: String? = null,
|
||||
)
|
|
@ -43,7 +43,8 @@ import com.hexated.SoraExtractor.invokeTvMovies
|
|||
import com.hexated.SoraExtractor.invokeUhdmovies
|
||||
import com.hexated.SoraExtractor.invokeVegamovies
|
||||
import com.hexated.SoraExtractor.invokeVidsrcto
|
||||
import com.hexated.SoraExtractor.invokeWatchOnline
|
||||
import com.hexated.SoraExtractor.invokeCinemaTv
|
||||
import com.hexated.SoraExtractor.invokeOmovies
|
||||
import com.hexated.SoraExtractor.invokeWatchsomuch
|
||||
import com.hexated.SoraExtractor.invokeZshow
|
||||
import com.lagradost.cloudstream3.LoadResponse.Companion.addImdbId
|
||||
|
@ -93,10 +94,11 @@ open class SoraStream : TmdbProvider() {
|
|||
const val flixonAPI = "https://flixon.lol"
|
||||
const val smashyStreamAPI = "https://embed.smashystream.com"
|
||||
const val watchSomuchAPI = "https://watchsomuch.tv" // sub only
|
||||
const val watchOnlineAPI = "https://lookmovie.foundation"
|
||||
var cinemaTvAPI = BuildConfig.CINEMATV_API
|
||||
const val nineTvAPI = "https://moviesapi.club"
|
||||
const val nowTvAPI = "https://myfilestorage.xyz"
|
||||
const val gokuAPI = "https://goku.sx"
|
||||
const val zshowAPI = BuildConfig.ZSHOW_API
|
||||
const val ridomoviesAPI = "https://ridomovies.pw"
|
||||
const val navyAPI = "https://navy-issue-i-239.site"
|
||||
const val emoviesAPI = "https://emovies.si"
|
||||
|
@ -115,8 +117,8 @@ open class SoraStream : TmdbProvider() {
|
|||
const val uhdmoviesAPI = "https://uhdmovies.zip"
|
||||
const val gMoviesAPI = "https://gdrivemovies.xyz"
|
||||
const val hdmovies4uAPI = "https://hdmovies4u.band"
|
||||
const val vegaMoviesAPI = "https://vegamovies.boo"
|
||||
const val dotmoviesAPI = "https://dotmovies.im"
|
||||
const val vegaMoviesAPI = "https://vegamovies.dad"
|
||||
const val dotmoviesAPI = "https://dotmovies.bet"
|
||||
const val tvMoviesAPI = "https://www.tvseriesnmovies.com"
|
||||
const val moviezAddAPI = "https://ww3.moviezaddiction.click"
|
||||
const val bollyMazaAPI = "https://ww3.bollymaza.click"
|
||||
|
@ -300,6 +302,7 @@ open class SoraStream : TmdbProvider() {
|
|||
this.showStatus = getStatus(res.status)
|
||||
this.recommendations = recommendations
|
||||
this.actors = actors
|
||||
this.contentRating = fetchContentRating(data.id, "US")
|
||||
addTrailer(trailer)
|
||||
addTMDbId(data.id.toString())
|
||||
addImdbId(res.external_ids?.imdb_id)
|
||||
|
@ -334,6 +337,7 @@ open class SoraStream : TmdbProvider() {
|
|||
this.rating = rating
|
||||
this.recommendations = recommendations
|
||||
this.actors = actors
|
||||
this.contentRating = fetchContentRating(data.id, "US")
|
||||
addTrailer(trailer)
|
||||
addTMDbId(data.id.toString())
|
||||
addImdbId(res.external_ids?.imdb_id)
|
||||
|
@ -351,6 +355,15 @@ open class SoraStream : TmdbProvider() {
|
|||
val res = parseJson<LinkData>(data)
|
||||
|
||||
argamap(
|
||||
{
|
||||
if (!res.isAnime) invokeBlackvid(
|
||||
res.id,
|
||||
res.season,
|
||||
res.episode,
|
||||
subtitleCallback,
|
||||
callback
|
||||
)
|
||||
},
|
||||
{
|
||||
invokeDumpStream(
|
||||
res.title,
|
||||
|
@ -430,7 +443,7 @@ open class SoraStream : TmdbProvider() {
|
|||
)
|
||||
},
|
||||
{
|
||||
invokeKisskh(
|
||||
if (res.isAsian || res.isAnime) invokeKisskh(
|
||||
res.title,
|
||||
res.season,
|
||||
res.episode,
|
||||
|
@ -440,6 +453,15 @@ open class SoraStream : TmdbProvider() {
|
|||
callback
|
||||
)
|
||||
},
|
||||
{
|
||||
if (!res.isAnime) invokeOmovies (
|
||||
res.title,
|
||||
res.year,
|
||||
res.season,
|
||||
res.episode,
|
||||
callback
|
||||
)
|
||||
},
|
||||
{
|
||||
if (!res.isAnime) invokeLing(
|
||||
res.title,
|
||||
|
@ -455,7 +477,6 @@ open class SoraStream : TmdbProvider() {
|
|||
res.title,
|
||||
res.year,
|
||||
res.season,
|
||||
res.lastSeason,
|
||||
res.episode,
|
||||
callback
|
||||
)
|
||||
|
@ -527,7 +548,7 @@ open class SoraStream : TmdbProvider() {
|
|||
},
|
||||
{
|
||||
if (!res.isAnime) invokeSmashyStream(
|
||||
res.id,
|
||||
res.imdbId,
|
||||
res.season,
|
||||
res.episode,
|
||||
subtitleCallback,
|
||||
|
@ -561,7 +582,7 @@ open class SoraStream : TmdbProvider() {
|
|||
)
|
||||
},
|
||||
{
|
||||
invokeWatchOnline(
|
||||
invokeCinemaTv(
|
||||
res.imdbId,
|
||||
res.title,
|
||||
res.airedYear ?: res.year,
|
||||
|
@ -672,15 +693,6 @@ open class SoraStream : TmdbProvider() {
|
|||
callback
|
||||
)
|
||||
},
|
||||
{
|
||||
if (!res.isAnime) invokeBlackvid(
|
||||
res.id,
|
||||
res.season,
|
||||
res.episode,
|
||||
subtitleCallback,
|
||||
callback
|
||||
)
|
||||
},
|
||||
{
|
||||
if (!res.isAnime) invokeShowflix(
|
||||
res.title,
|
||||
|
|
|
@ -29,7 +29,8 @@ import com.hexated.SoraExtractor.invokeSFMovies
|
|||
import com.hexated.SoraExtractor.invokeShowflix
|
||||
import com.hexated.SoraExtractor.invokeVidSrc
|
||||
import com.hexated.SoraExtractor.invokeVidsrcto
|
||||
import com.hexated.SoraExtractor.invokeWatchOnline
|
||||
import com.hexated.SoraExtractor.invokeCinemaTv
|
||||
import com.hexated.SoraExtractor.invokeOmovies
|
||||
import com.hexated.SoraExtractor.invokeWatchsomuch
|
||||
import com.hexated.SoraExtractor.invokeZshow
|
||||
import com.lagradost.cloudstream3.SubtitleFile
|
||||
|
@ -133,6 +134,15 @@ class SoraStreamLite : SoraStream() {
|
|||
callback
|
||||
)
|
||||
},
|
||||
{
|
||||
if (!res.isAnime) invokeOmovies(
|
||||
res.title,
|
||||
res.year,
|
||||
res.season,
|
||||
res.episode,
|
||||
callback
|
||||
)
|
||||
},
|
||||
{
|
||||
if (!res.isAnime) invokeKimcartoon(
|
||||
res.title,
|
||||
|
@ -144,7 +154,7 @@ class SoraStreamLite : SoraStream() {
|
|||
},
|
||||
{
|
||||
if (!res.isAnime) invokeSmashyStream(
|
||||
res.id,
|
||||
res.imdbId,
|
||||
res.season,
|
||||
res.episode,
|
||||
subtitleCallback,
|
||||
|
@ -161,7 +171,7 @@ class SoraStreamLite : SoraStream() {
|
|||
)
|
||||
},
|
||||
{
|
||||
invokeKisskh(
|
||||
if (res.isAsian || res.isAnime) invokeKisskh(
|
||||
res.title,
|
||||
res.season,
|
||||
res.episode,
|
||||
|
@ -198,7 +208,7 @@ class SoraStreamLite : SoraStream() {
|
|||
if (!res.isAnime) invokeFlixon(res.id, res.imdbId, res.season, res.episode, callback)
|
||||
},
|
||||
{
|
||||
invokeWatchOnline(
|
||||
invokeCinemaTv(
|
||||
res.imdbId,
|
||||
res.title,
|
||||
res.airedYear ?: res.year,
|
||||
|
|
|
@ -20,7 +20,6 @@ class SoraStreamPlugin: Plugin() {
|
|||
registerExtractorAPI(Playm4u())
|
||||
registerExtractorAPI(VCloud())
|
||||
registerExtractorAPI(Pixeldra())
|
||||
registerExtractorAPI(Hubcloud())
|
||||
registerExtractorAPI(M4ufree())
|
||||
registerExtractorAPI(Streamruby())
|
||||
registerExtractorAPI(Streamwish())
|
||||
|
@ -28,5 +27,7 @@ class SoraStreamPlugin: Plugin() {
|
|||
registerExtractorAPI(Embedwish())
|
||||
registerExtractorAPI(Wishfast())
|
||||
registerExtractorAPI(Uploadever())
|
||||
registerExtractorAPI(Netembed())
|
||||
registerExtractorAPI(Vidplay2())
|
||||
}
|
||||
}
|
|
@ -8,7 +8,6 @@ import com.hexated.SoraStream.Companion.filmxyAPI
|
|||
import com.hexated.SoraStream.Companion.gdbot
|
||||
import com.hexated.SoraStream.Companion.hdmovies4uAPI
|
||||
import com.hexated.SoraStream.Companion.malsyncAPI
|
||||
import com.hexated.SoraStream.Companion.smashyStreamAPI
|
||||
import com.hexated.SoraStream.Companion.tvMoviesAPI
|
||||
import com.hexated.SoraStream.Companion.watchflxAPI
|
||||
import com.lagradost.cloudstream3.*
|
||||
|
@ -20,12 +19,16 @@ import com.lagradost.cloudstream3.utils.AppUtils.toJson
|
|||
import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson
|
||||
import com.lagradost.nicehttp.NiceResponse
|
||||
import com.lagradost.nicehttp.RequestBodyTypes
|
||||
import com.lagradost.nicehttp.Requests.Companion.await
|
||||
import com.lagradost.nicehttp.requestCreator
|
||||
import kotlinx.coroutines.delay
|
||||
import okhttp3.FormBody
|
||||
import okhttp3.HttpUrl.Companion.toHttpUrl
|
||||
import okhttp3.MediaType.Companion.toMediaTypeOrNull
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import okhttp3.RequestBody.Companion.toRequestBody
|
||||
import okhttp3.Response
|
||||
import org.jsoup.nodes.Document
|
||||
import java.math.BigInteger
|
||||
import java.net.*
|
||||
|
@ -34,9 +37,8 @@ import java.security.*
|
|||
import java.security.spec.PKCS8EncodedKeySpec
|
||||
import java.security.spec.X509EncodedKeySpec
|
||||
import java.text.SimpleDateFormat
|
||||
import java.time.LocalDate
|
||||
import java.time.format.DateTimeFormatter
|
||||
import java.util.*
|
||||
import java.util.concurrent.TimeUnit
|
||||
import javax.crypto.Cipher
|
||||
import javax.crypto.spec.GCMParameterSpec
|
||||
import javax.crypto.spec.IvParameterSpec
|
||||
|
@ -45,7 +47,9 @@ import kotlin.collections.ArrayList
|
|||
import kotlin.math.min
|
||||
|
||||
var watchflxCookies: Map<String, String>? = null
|
||||
var filmxyCookies: Map<String,String>? = null
|
||||
var filmxyCookies: Map<String, String>? = null
|
||||
var sfServer: String? = null
|
||||
|
||||
val encodedIndex = arrayOf(
|
||||
"GamMovies",
|
||||
"JSMovies",
|
||||
|
@ -93,51 +97,6 @@ val mimeType = arrayOf(
|
|||
"video/x-msvideo"
|
||||
)
|
||||
|
||||
fun String.filterIframe(
|
||||
seasonNum: Int? = null,
|
||||
lastSeason: Int? = null,
|
||||
year: Int?,
|
||||
title: String?
|
||||
): Boolean {
|
||||
val slug = title.createSlug()
|
||||
val dotSlug = slug?.replace("-", ".")
|
||||
val spaceSlug = slug?.replace("-", " ")
|
||||
return if (seasonNum != null) {
|
||||
if (lastSeason == 1) {
|
||||
this.contains(Regex("(?i)(S0?$seasonNum)|(Season\\s0?$seasonNum)|(\\d{3,4}p)")) && !this.contains(
|
||||
"Download",
|
||||
true
|
||||
)
|
||||
} else {
|
||||
this.contains(Regex("(?i)(S0?$seasonNum)|(Season\\s0?$seasonNum)")) && !this.contains(
|
||||
"Download",
|
||||
true
|
||||
)
|
||||
}
|
||||
} else {
|
||||
this.contains(Regex("(?i)($year)|($dotSlug)|($spaceSlug)")) && !this.contains(
|
||||
"Download",
|
||||
true
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun String.filterMedia(title: String?, yearNum: Int?, seasonNum: Int?): Boolean {
|
||||
val fixTitle = title.createSlug()?.replace("-", " ")
|
||||
return if (seasonNum != null) {
|
||||
when {
|
||||
seasonNum > 1 -> this.contains(Regex("(?i)(Season\\s0?1-0?$seasonNum)|(S0?1-S?0?$seasonNum)")) && this.contains(
|
||||
Regex("(?i)($fixTitle)|($title)")
|
||||
)
|
||||
else -> this.contains(Regex("(?i)(Season\\s0?1)|(S0?1)")) && this.contains(
|
||||
Regex("(?i)($fixTitle)|($title)")
|
||||
) && this.contains("$yearNum")
|
||||
}
|
||||
} else {
|
||||
this.contains(Regex("(?i)($fixTitle)|($title)")) && this.contains("$yearNum")
|
||||
}
|
||||
}
|
||||
|
||||
fun Document.getMirrorLink(): String? {
|
||||
return this.select("div.mb-4 a").randomOrNull()
|
||||
?.attr("href")
|
||||
|
@ -450,16 +409,28 @@ suspend fun invokeSmashyFfix(
|
|||
val json = app.get(url, referer = ref, headers = mapOf("X-Requested-With" to "XMLHttpRequest"))
|
||||
.parsedSafe<SmashySources>()
|
||||
json?.sourceUrls?.map {
|
||||
callback.invoke(
|
||||
ExtractorLink(
|
||||
"Smashy [$name]",
|
||||
"Smashy [$name]",
|
||||
it,
|
||||
if(name == "Player FM") "https://vidplay.site/" else "",
|
||||
Qualities.P1080.value,
|
||||
INFER_TYPE
|
||||
)
|
||||
)
|
||||
M3u8Helper.generateM3u8(
|
||||
"Smashy [$name]",
|
||||
it,
|
||||
""
|
||||
).forEach(callback)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
suspend fun invokeSmashyD(
|
||||
url: String,
|
||||
ref: String,
|
||||
callback: (ExtractorLink) -> Unit,
|
||||
) {
|
||||
val json = app.get(url, referer = ref, headers = mapOf("X-Requested-With" to "XMLHttpRequest"))
|
||||
.parsedSafe<SmashyDSources>()
|
||||
json?.sourceUrls?.apmap {
|
||||
M3u8Helper.generateM3u8(
|
||||
"Smashy [Player D ${it.title}]",
|
||||
it.file ?: return@apmap,
|
||||
""
|
||||
).forEach(callback)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -487,6 +458,7 @@ suspend fun getDumpIdAndType(title: String?, year: Int?, season: Int?): Pair<Str
|
|||
true
|
||||
) && it.releaseTime == "$year" && it.domainType == 0
|
||||
}
|
||||
|
||||
1 -> {
|
||||
it.name?.contains(
|
||||
"$title",
|
||||
|
@ -496,6 +468,7 @@ suspend fun getDumpIdAndType(title: String?, year: Int?, season: Int?): Pair<Str
|
|||
true
|
||||
)) && it.domainType == 1
|
||||
}
|
||||
|
||||
else -> {
|
||||
it.name?.contains(Regex("(?i)$title\\s?($season|${season.toRomanNumeral()}|Season\\s$season)")) == true && it.releaseTime == "$year" && it.domainType == 1
|
||||
}
|
||||
|
@ -531,25 +504,26 @@ suspend fun invokeDrivetot(
|
|||
) {
|
||||
val res = app.get(url)
|
||||
val data = res.document.select("form input").associate { it.attr("name") to it.attr("value") }
|
||||
app.post(res.url, data = data, cookies = res.cookies).document.select("div.card-body a").apmap { ele ->
|
||||
val href = base64Decode(ele.attr("href").substringAfterLast("/")).let {
|
||||
if(it.contains("hubcloud.lol")) it.replace("hubcloud.lol", "hubcloud.in") else it
|
||||
}
|
||||
loadExtractor(href, "$hdmovies4uAPI/", subtitleCallback) { link ->
|
||||
callback.invoke(
|
||||
ExtractorLink(
|
||||
link.source,
|
||||
"${link.name} $tags [$size]",
|
||||
link.url,
|
||||
link.referer,
|
||||
link.quality,
|
||||
link.type,
|
||||
link.headers,
|
||||
link.extractorData
|
||||
app.post(res.url, data = data, cookies = res.cookies).document.select("div.card-body a")
|
||||
.apmap { ele ->
|
||||
val href = base64Decode(ele.attr("href").substringAfterLast("/")).let {
|
||||
if (it.contains("hubcloud.lol")) it.replace("hubcloud.lol", "hubcloud.in") else it
|
||||
}
|
||||
loadExtractor(href, "$hdmovies4uAPI/", subtitleCallback) { link ->
|
||||
callback.invoke(
|
||||
ExtractorLink(
|
||||
link.source,
|
||||
"${link.name} $tags [$size]",
|
||||
link.url,
|
||||
link.referer,
|
||||
link.quality,
|
||||
link.type,
|
||||
link.headers,
|
||||
link.extractorData
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun bypassBqrecipes(url: String): String? {
|
||||
|
@ -614,28 +588,27 @@ suspend fun bypassFdAds(url: String?): String? {
|
|||
}
|
||||
|
||||
suspend fun bypassHrefli(url: String): String? {
|
||||
val postUrl = url.substringBefore("?id=").substringAfter("/?")
|
||||
val res = app.post(
|
||||
postUrl, data = mapOf(
|
||||
"_wp_http" to url.substringAfter("?id=")
|
||||
)
|
||||
).document
|
||||
fun Document.getFormUrl() : String {
|
||||
return this.select("form#landing").attr("action")
|
||||
}
|
||||
fun Document.getFormData() : Map<String,String> {
|
||||
return this.select("form#landing input").associate { it.attr("name") to it.attr("value") }
|
||||
}
|
||||
|
||||
val link = res.select("form#landing").attr("action")
|
||||
val wpHttp = res.select("input[name=_wp_http2]").attr("value")
|
||||
val token = res.select("input[name=token]").attr("value")
|
||||
val host = getBaseUrl(url)
|
||||
var res = app.get(url).document
|
||||
var formUrl = res.getFormUrl()
|
||||
var formData = res.getFormData()
|
||||
|
||||
val blogRes = app.post(
|
||||
link, data = mapOf(
|
||||
"_wp_http2" to wpHttp,
|
||||
"token" to token
|
||||
)
|
||||
).text
|
||||
res = app.post(formUrl, data = formData).document
|
||||
formUrl = res.getFormUrl()
|
||||
formData = res.getFormData()
|
||||
|
||||
val skToken = blogRes.substringAfter("?go=").substringBefore("\"")
|
||||
res = app.post(formUrl, data = formData).document
|
||||
val skToken = res.selectFirst("script:containsData(?go=)")?.data()?.substringAfter("?go=")?.substringBefore("\"") ?: return null
|
||||
val driveUrl = app.get(
|
||||
"$postUrl?go=$skToken", cookies = mapOf(
|
||||
skToken to wpHttp
|
||||
"$host?go=$skToken", cookies = mapOf(
|
||||
skToken to "${formData["_wp_http2"]}"
|
||||
)
|
||||
).document.selectFirst("meta[http-equiv=refresh]")?.attr("content")?.substringAfter("url=")
|
||||
val path = app.get(driveUrl ?: return null).text.substringAfter("replace(\"")
|
||||
|
@ -644,94 +617,6 @@ suspend fun bypassHrefli(url: String): String? {
|
|||
return fixUrl(path, getBaseUrl(driveUrl))
|
||||
}
|
||||
|
||||
suspend fun bypassTechmny(url: String): String? {
|
||||
val techRes = app.get(url).document
|
||||
val postUrl = url.substringBefore("?id=").substringAfter("/?")
|
||||
val (goUrl, goHeader) = if (techRes.selectFirst("form#landing input[name=_wp_http_c]") != null) {
|
||||
var res = app.post(
|
||||
postUrl, data = mapOf(
|
||||
"_wp_http_c" to url.substringAfter("?id=")
|
||||
)
|
||||
)
|
||||
val (longC, catC, _) = getTechmnyCookies(res.text)
|
||||
var headers = mapOf("Cookie" to "$longC; $catC")
|
||||
var formLink = res.document.selectFirst("center a")?.attr("href")
|
||||
res = app.get(formLink ?: return null, headers = headers)
|
||||
val (longC2, _, postC) = getTechmnyCookies(res.text)
|
||||
headers = mapOf("Cookie" to "$catC; $longC2; $postC")
|
||||
formLink = res.document.selectFirst("center a")?.attr("href")
|
||||
|
||||
res = app.get(formLink ?: return null, headers = headers)
|
||||
val goToken = res.text.substringAfter("?go=").substringBefore("\"")
|
||||
val tokenUrl = "$postUrl?go=$goToken"
|
||||
val newLongC = "$goToken=" + longC2.substringAfter("=")
|
||||
headers = mapOf("Cookie" to "$catC; rdst_post=; $newLongC")
|
||||
Pair(tokenUrl, headers)
|
||||
} else {
|
||||
val secondPage = techRes.getNextTechPage().document
|
||||
val thirdPage = secondPage.getNextTechPage().text
|
||||
val goToken = thirdPage.substringAfter("?go=").substringBefore("\"")
|
||||
val tokenUrl = "$postUrl?go=$goToken"
|
||||
val headers = mapOf(
|
||||
"Cookie" to "$goToken=${
|
||||
secondPage.select("form#landing input[name=_wp_http2]").attr("value")
|
||||
}"
|
||||
)
|
||||
Pair(tokenUrl, headers)
|
||||
}
|
||||
val driveUrl =
|
||||
app.get(goUrl, headers = goHeader).document.selectFirst("meta[http-equiv=refresh]")
|
||||
?.attr("content")?.substringAfter("url=")
|
||||
val path = app.get(driveUrl ?: return null).text.substringAfter("replace(\"")
|
||||
.substringBefore("\")")
|
||||
if (path == "/404") return null
|
||||
return fixUrl(path, getBaseUrl(driveUrl))
|
||||
}
|
||||
|
||||
private suspend fun Document.getNextTechPage(): NiceResponse {
|
||||
return app.post(
|
||||
this.select("form").attr("action"),
|
||||
data = this.select("form input").mapNotNull {
|
||||
it.attr("name") to it.attr("value")
|
||||
}.toMap().toMutableMap()
|
||||
)
|
||||
}
|
||||
|
||||
suspend fun bypassDriveleech(url: String): String? {
|
||||
val path = app.get(url).text.substringAfter("replace(\"")
|
||||
.substringBefore("\")")
|
||||
if (path == "/404") return null
|
||||
return fixUrl(path, getBaseUrl(url))
|
||||
}
|
||||
|
||||
private fun getTechmnyCookies(page: String): Triple<String, String, String> {
|
||||
val cat = "rdst_cat"
|
||||
val post = "rdst_post"
|
||||
val longC = page.substringAfter(".setTime")
|
||||
.substringAfter("document.cookie = \"")
|
||||
.substringBefore("\"")
|
||||
.substringBefore(";")
|
||||
val catC = if (page.contains("$cat=")) {
|
||||
page.substringAfterLast("$cat=")
|
||||
.substringBefore(";").let {
|
||||
"$cat=$it"
|
||||
}
|
||||
} else {
|
||||
""
|
||||
}
|
||||
|
||||
val postC = if (page.contains("$post=")) {
|
||||
page.substringAfterLast("$post=")
|
||||
.substringBefore(";").let {
|
||||
"$post=$it"
|
||||
}
|
||||
} else {
|
||||
""
|
||||
}
|
||||
|
||||
return Triple(longC, catC, postC)
|
||||
}
|
||||
|
||||
suspend fun getTvMoviesServer(url: String, season: Int?, episode: Int?): Pair<String, String?>? {
|
||||
|
||||
val req = app.get(url)
|
||||
|
@ -761,10 +646,20 @@ suspend fun getTvMoviesServer(url: String, season: Int?, episode: Int?): Pair<St
|
|||
}.lastOrNull()
|
||||
}
|
||||
}
|
||||
suspend fun getFilmxyCookies(url: String) = filmxyCookies ?: fetchFilmxyCookies(url).also { filmxyCookies = it }
|
||||
|
||||
suspend fun getSfServer() = sfServer ?: fetchSfServer().also { sfServer = it }
|
||||
|
||||
suspend fun fetchSfServer(): String {
|
||||
return app.get("https://raw.githubusercontent.com/hexated/cloudstream-resources/main/sfmovies_server").text
|
||||
}
|
||||
|
||||
suspend fun getFilmxyCookies(url: String) =
|
||||
filmxyCookies ?: fetchFilmxyCookies(url).also { filmxyCookies = it }
|
||||
|
||||
suspend fun fetchFilmxyCookies(url: String): Map<String, String> {
|
||||
|
||||
val defaultCookies = mutableMapOf("G_ENABLED_IDPS" to "google", "true_checker" to "1", "XID" to "1")
|
||||
val defaultCookies =
|
||||
mutableMapOf("G_ENABLED_IDPS" to "google", "true_checker" to "1", "XID" to "1")
|
||||
session.get(
|
||||
url,
|
||||
headers = mapOf(
|
||||
|
@ -777,7 +672,10 @@ suspend fun fetchFilmxyCookies(url: String): Map<String, String> {
|
|||
defaultCookies["PHPSESSID"] = phpsessid
|
||||
|
||||
val userNonce =
|
||||
app.get("$filmxyAPI/login/?redirect_to=$filmxyAPI/", cookies = defaultCookies).document.select("script")
|
||||
app.get(
|
||||
"$filmxyAPI/login/?redirect_to=$filmxyAPI/",
|
||||
cookies = defaultCookies
|
||||
).document.select("script")
|
||||
.find { it.data().contains("var userNonce") }?.data()?.let {
|
||||
Regex("var\\suserNonce.*?\"(\\S+?)\";").find(it)?.groupValues?.get(1)
|
||||
}
|
||||
|
@ -801,7 +699,8 @@ suspend fun fetchFilmxyCookies(url: String): Map<String, String> {
|
|||
return cookieJar.plus(defaultCookies)
|
||||
}
|
||||
|
||||
suspend fun getWatchflxCookies() = watchflxCookies ?: fetchWatchflxCookies().also { watchflxCookies = it }
|
||||
suspend fun getWatchflxCookies() =
|
||||
watchflxCookies ?: fetchWatchflxCookies().also { watchflxCookies = it }
|
||||
|
||||
suspend fun fetchWatchflxCookies(): Map<String, String> {
|
||||
session.get(watchflxAPI)
|
||||
|
@ -813,7 +712,8 @@ suspend fun fetchWatchflxCookies(): Map<String, String> {
|
|||
"continue_as_temp" to "true"
|
||||
), cookies = cookies, headers = mapOf("X-Requested-With" to "XMLHttpRequest")
|
||||
)
|
||||
return session.baseClient.cookieJar.loadForRequest(loginUrl.toHttpUrl()).associate { it.name to it.value }
|
||||
return session.baseClient.cookieJar.loadForRequest(loginUrl.toHttpUrl())
|
||||
.associate { it.name to it.value }
|
||||
}
|
||||
|
||||
fun Document.findTvMoviesIframe(): String? {
|
||||
|
@ -1148,7 +1048,11 @@ fun String.decodePrimewireXor(key: String): String {
|
|||
fun vidsrctoDecrypt(text: String): String {
|
||||
val parse = Base64.decode(text.toByteArray(), Base64.URL_SAFE)
|
||||
val cipher = Cipher.getInstance("RC4")
|
||||
cipher.init(Cipher.DECRYPT_MODE, SecretKeySpec("8z5Ag5wgagfsOuhz".toByteArray(), "RC4"), cipher.parameters)
|
||||
cipher.init(
|
||||
Cipher.DECRYPT_MODE,
|
||||
SecretKeySpec("8z5Ag5wgagfsOuhz".toByteArray(), "RC4"),
|
||||
cipher.parameters
|
||||
)
|
||||
return decode(cipher.doFinal(parse).toString(Charsets.UTF_8))
|
||||
}
|
||||
|
||||
|
@ -1288,7 +1192,7 @@ fun isUpcoming(dateString: String?): Boolean {
|
|||
}
|
||||
}
|
||||
|
||||
fun getDate() : TmdbDate {
|
||||
fun getDate(): TmdbDate {
|
||||
val formatter = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault())
|
||||
val calender = Calendar.getInstance()
|
||||
val today = formatter.format(calender.time)
|
||||
|
@ -1373,12 +1277,31 @@ private enum class Symbol(val decimalValue: Int) {
|
|||
|
||||
companion object {
|
||||
fun closestBelow(value: Int) =
|
||||
values()
|
||||
entries.toTypedArray()
|
||||
.sortedByDescending { it.decimalValue }
|
||||
.firstOrNull { value >= it.decimalValue }
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun request(
|
||||
url: String,
|
||||
allowRedirects: Boolean = true,
|
||||
timeout: Long = 60L
|
||||
): Response {
|
||||
val client = OkHttpClient().newBuilder()
|
||||
.connectTimeout(timeout, TimeUnit.SECONDS)
|
||||
.readTimeout(timeout, TimeUnit.SECONDS)
|
||||
.writeTimeout(timeout, TimeUnit.SECONDS)
|
||||
.followRedirects(allowRedirects)
|
||||
.followSslRedirects(allowRedirects)
|
||||
.build()
|
||||
|
||||
val request: Request = Request.Builder()
|
||||
.url(url)
|
||||
.build()
|
||||
return client.newCall(request).await()
|
||||
}
|
||||
|
||||
object DumpUtils {
|
||||
|
||||
private val deviceId = getDeviceId()
|
||||
|
@ -1644,4 +1567,4 @@ object AESGCM {
|
|||
dateFormat.timeZone = TimeZone.getTimeZone("GMT")
|
||||
return dateFormat.format(Date())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// use an integer for version numbers
|
||||
version = 11
|
||||
version = 12
|
||||
|
||||
|
||||
cloudstream {
|
||||
|
|
|
@ -13,8 +13,9 @@ import com.lagradost.cloudstream3.utils.AppUtils.toJson
|
|||
import java.net.URI
|
||||
import java.util.ArrayList
|
||||
import kotlin.math.roundToInt
|
||||
import com.lagradost.cloudstream3.metaproviders.TmdbProvider
|
||||
|
||||
open class StremioX : MainAPI() {
|
||||
open class StremioX : TmdbProvider() {
|
||||
override var mainUrl = "https://torrentio.strem.fun"
|
||||
override var name = "StremioX"
|
||||
override val hasMainPage = true
|
||||
|
@ -181,6 +182,7 @@ open class StremioX : MainAPI() {
|
|||
this.showStatus = getStatus(res.status)
|
||||
this.recommendations = recommendations
|
||||
this.actors = actors
|
||||
this.contentRating = fetchContentRating(data.id, "US")
|
||||
addTrailer(trailer)
|
||||
addTMDbId(data.id.toString())
|
||||
addImdbId(res.external_ids?.imdb_id)
|
||||
|
@ -202,6 +204,7 @@ open class StremioX : MainAPI() {
|
|||
this.rating = rating
|
||||
this.recommendations = recommendations
|
||||
this.actors = actors
|
||||
this.contentRating = fetchContentRating(data.id, "US")
|
||||
addTrailer(trailer)
|
||||
addTMDbId(data.id.toString())
|
||||
addImdbId(res.external_ids?.imdb_id)
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
// use an integer for version numbers
|
||||
version = 24
|
||||
version = 25
|
||||
|
||||
|
||||
cloudstream {
|
||||
language = "hi"
|
||||
// All of these properties are optional, you can safely remove them
|
||||
|
||||
description = "Include: Watchomovies"
|
||||
description = "Includes: Watchomovies(NS*W), Max resolution is 720p in both extensions."
|
||||
authors = listOf("Hexated")
|
||||
|
||||
/**
|
||||
|
|
|
@ -5,7 +5,7 @@ import com.lagradost.cloudstream3.TvType
|
|||
import com.lagradost.cloudstream3.mainPageOf
|
||||
|
||||
class Watchomovies : YomoviesProvider() {
|
||||
override var mainUrl = "https://watchomovies.beauty"
|
||||
override var mainUrl = "https://watchomovies.lat"
|
||||
override var name = "Watchomovies"
|
||||
override var lang = "en"
|
||||
override val supportedTypes = setOf(
|
||||
|
|
|
@ -10,7 +10,7 @@ import org.jsoup.nodes.Element
|
|||
import java.net.URI
|
||||
|
||||
open class YomoviesProvider : MainAPI() {
|
||||
override var mainUrl = "https://yomovies.show"
|
||||
override var mainUrl = "https://yomovies.media"
|
||||
private var directUrl = ""
|
||||
override var name = "Yomovies"
|
||||
override val hasMainPage = true
|
||||
|
|
|
@ -13,7 +13,7 @@ buildscript {
|
|||
classpath("com.android.tools.build:gradle:7.0.4")
|
||||
// Cloudstream gradle plugin which makes everything work and builds plugins
|
||||
classpath("com.github.recloudstream:gradle:-SNAPSHOT")
|
||||
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.20")
|
||||
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.21")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue