mirror of
https://github.com/hexated/cloudstream-extensions-hexated.git
synced 2024-08-15 00:03:22 +00:00
sora: added netflix
This commit is contained in:
parent
4077d1275d
commit
36e77332c5
12 changed files with 167 additions and 28 deletions
|
@ -1,5 +1,5 @@
|
||||||
// use an integer for version numbers
|
// use an integer for version numbers
|
||||||
version = 17
|
version = 18
|
||||||
|
|
||||||
|
|
||||||
cloudstream {
|
cloudstream {
|
||||||
|
|
|
@ -59,7 +59,7 @@ class NontonAnimeIDProvider : MainAPI() {
|
||||||
|
|
||||||
document.select("aside#sidebar_right > div.side").forEach { block ->
|
document.select("aside#sidebar_right > div.side").forEach { block ->
|
||||||
val header = block.selectFirst("h3")!!.ownText().trim()
|
val header = block.selectFirst("h3")!!.ownText().trim()
|
||||||
val animes = block.select("ul li.fullwdth").mapNotNull {
|
val animes = block.select("div.bor").mapNotNull {
|
||||||
it.toSearchResultPopular()
|
it.toSearchResultPopular()
|
||||||
}
|
}
|
||||||
if (animes.isNotEmpty()) homePageList.add(HomePageList(header, animes))
|
if (animes.isNotEmpty()) homePageList.add(HomePageList(header, animes))
|
||||||
|
@ -71,7 +71,7 @@ class NontonAnimeIDProvider : MainAPI() {
|
||||||
private fun Element.toSearchResult(): AnimeSearchResponse? {
|
private fun Element.toSearchResult(): AnimeSearchResponse? {
|
||||||
val href = fixUrl(this.selectFirst("a")!!.attr("href"))
|
val href = fixUrl(this.selectFirst("a")!!.attr("href"))
|
||||||
val title = this.selectFirst("h3.title")?.text() ?: return null
|
val title = this.selectFirst("h3.title")?.text() ?: return null
|
||||||
val posterUrl = fixUrl(this.select("img").attr("data-src"))
|
val posterUrl = fixUrl(this.select("img").attr("src"))
|
||||||
|
|
||||||
return newAnimeSearchResponse(title, href, TvType.Anime) {
|
return newAnimeSearchResponse(title, href, TvType.Anime) {
|
||||||
this.posterUrl = posterUrl
|
this.posterUrl = posterUrl
|
||||||
|
@ -83,7 +83,7 @@ class NontonAnimeIDProvider : MainAPI() {
|
||||||
private fun Element.toSearchResultPopular(): AnimeSearchResponse? {
|
private fun Element.toSearchResultPopular(): AnimeSearchResponse? {
|
||||||
val href = fixUrl(this.selectFirst("a")!!.attr("href"))
|
val href = fixUrl(this.selectFirst("a")!!.attr("href"))
|
||||||
val title = this.selectFirst("h4")?.text()?.trim() ?: return null
|
val title = this.selectFirst("h4")?.text()?.trim() ?: return null
|
||||||
val posterUrl = fixUrl(this.select("img").attr("data-src"))
|
val posterUrl = fixUrl(this.select("img").attr("src"))
|
||||||
|
|
||||||
return newAnimeSearchResponse(title, href, TvType.Anime) {
|
return newAnimeSearchResponse(title, href, TvType.Anime) {
|
||||||
this.posterUrl = posterUrl
|
this.posterUrl = posterUrl
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// use an integer for version numbers
|
// use an integer for version numbers
|
||||||
version = 15
|
version = 16
|
||||||
|
|
||||||
|
|
||||||
cloudstream {
|
cloudstream {
|
||||||
|
|
|
@ -4,9 +4,13 @@ import com.lagradost.cloudstream3.*
|
||||||
import com.lagradost.cloudstream3.LoadResponse.Companion.addAniListId
|
import com.lagradost.cloudstream3.LoadResponse.Companion.addAniListId
|
||||||
import com.lagradost.cloudstream3.LoadResponse.Companion.addMalId
|
import com.lagradost.cloudstream3.LoadResponse.Companion.addMalId
|
||||||
import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer
|
import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer
|
||||||
|
import com.lagradost.cloudstream3.network.CloudflareKiller
|
||||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||||
import com.lagradost.cloudstream3.utils.Qualities
|
import com.lagradost.cloudstream3.utils.Qualities
|
||||||
import com.lagradost.cloudstream3.utils.loadExtractor
|
import com.lagradost.cloudstream3.utils.loadExtractor
|
||||||
|
import okhttp3.Interceptor
|
||||||
|
import okhttp3.Response
|
||||||
|
import org.jsoup.Jsoup
|
||||||
import org.jsoup.nodes.Element
|
import org.jsoup.nodes.Element
|
||||||
|
|
||||||
class Samehadaku : MainAPI() {
|
class Samehadaku : MainAPI() {
|
||||||
|
@ -15,13 +19,26 @@ class Samehadaku : MainAPI() {
|
||||||
override val hasMainPage = true
|
override val hasMainPage = true
|
||||||
override var lang = "id"
|
override var lang = "id"
|
||||||
override val hasDownloadSupport = true
|
override val hasDownloadSupport = true
|
||||||
|
private val cloudflareKiller by lazy { CloudflareKiller() }
|
||||||
|
private val interceptor by lazy { CloudflareInterceptor(cloudflareKiller) }
|
||||||
override val supportedTypes = setOf(
|
override val supportedTypes = setOf(
|
||||||
TvType.Anime,
|
TvType.Anime,
|
||||||
TvType.AnimeMovie,
|
TvType.AnimeMovie,
|
||||||
TvType.OVA
|
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 {
|
companion object {
|
||||||
const val acefile = "https://acefile.co"
|
const val acefile = "https://acefile.co"
|
||||||
|
|
||||||
|
@ -52,7 +69,7 @@ class Samehadaku : MainAPI() {
|
||||||
val items = mutableListOf<HomePageList>()
|
val items = mutableListOf<HomePageList>()
|
||||||
|
|
||||||
if (request.name != "Episode Terbaru" && page <= 1) {
|
if (request.name != "Episode Terbaru" && page <= 1) {
|
||||||
val doc = app.get(request.data).document
|
val doc = app.get(request.data, interceptor = interceptor).document
|
||||||
doc.select("div.widget_senction:not(:contains(Baca Komik))").forEach { block ->
|
doc.select("div.widget_senction:not(:contains(Baca Komik))").forEach { block ->
|
||||||
val header = block.selectFirst("div.widget-title h3")?.ownText() ?: return@forEach
|
val header = block.selectFirst("div.widget-title h3")?.ownText() ?: return@forEach
|
||||||
val home = block.select("div.animepost").mapNotNull {
|
val home = block.select("div.animepost").mapNotNull {
|
||||||
|
@ -64,7 +81,7 @@ class Samehadaku : MainAPI() {
|
||||||
|
|
||||||
if (request.name == "Episode Terbaru") {
|
if (request.name == "Episode Terbaru") {
|
||||||
val home =
|
val home =
|
||||||
app.get(request.data + page).document.selectFirst("div.post-show")?.select("ul li")
|
app.get(request.data + page, interceptor = interceptor).document.selectFirst("div.post-show")?.select("ul li")
|
||||||
?.mapNotNull {
|
?.mapNotNull {
|
||||||
it.toSearchResult()
|
it.toSearchResult()
|
||||||
} ?: throw ErrorLoadingException("No Media Found")
|
} ?: throw ErrorLoadingException("No Media Found")
|
||||||
|
@ -84,12 +101,13 @@ class Samehadaku : MainAPI() {
|
||||||
return newAnimeSearchResponse(title, href ?: return null, TvType.Anime) {
|
return newAnimeSearchResponse(title, href ?: return null, TvType.Anime) {
|
||||||
this.posterUrl = posterUrl
|
this.posterUrl = posterUrl
|
||||||
addSub(epNum)
|
addSub(epNum)
|
||||||
|
posterHeaders = cloudflareKiller.getCookieHeaders(mainUrl).toMap()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun search(query: String): List<SearchResponse> {
|
override suspend fun search(query: String): List<SearchResponse> {
|
||||||
val document = app.get("$mainUrl/?s=$query").document
|
val document = app.get("$mainUrl/?s=$query", interceptor = interceptor).document
|
||||||
return document.select("main#main div.animepost").mapNotNull {
|
return document.select("main#main div.animepost").mapNotNull {
|
||||||
it.toSearchResult()
|
it.toSearchResult()
|
||||||
}
|
}
|
||||||
|
@ -99,10 +117,10 @@ class Samehadaku : MainAPI() {
|
||||||
val fixUrl = if (url.contains("/anime/")) {
|
val fixUrl = if (url.contains("/anime/")) {
|
||||||
url
|
url
|
||||||
} else {
|
} else {
|
||||||
app.get(url).document.selectFirst("div.nvs.nvsc a")?.attr("href")
|
app.get(url, interceptor = interceptor).document.selectFirst("div.nvs.nvsc a")?.attr("href")
|
||||||
}
|
}
|
||||||
|
|
||||||
val document = app.get(fixUrl ?: return null).document
|
val document = app.get(fixUrl ?: return null, interceptor = interceptor).document
|
||||||
val title = document.selectFirst("h1.entry-title")?.text()?.removeBloat() ?: return null
|
val title = document.selectFirst("h1.entry-title")?.text()?.removeBloat() ?: return null
|
||||||
val poster = document.selectFirst("div.thumb > img")?.attr("src")
|
val poster = document.selectFirst("div.thumb > img")?.attr("src")
|
||||||
val tags = document.select("div.genre-info > a").map { it.text() }
|
val tags = document.select("div.genre-info > a").map { it.text() }
|
||||||
|
@ -147,6 +165,7 @@ class Samehadaku : MainAPI() {
|
||||||
this.recommendations = recommendations
|
this.recommendations = recommendations
|
||||||
addMalId(tracker?.malId)
|
addMalId(tracker?.malId)
|
||||||
addAniListId(tracker?.aniId?.toIntOrNull())
|
addAniListId(tracker?.aniId?.toIntOrNull())
|
||||||
|
posterHeaders = cloudflareKiller.getCookieHeaders(mainUrl).toMap()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -158,7 +177,7 @@ class Samehadaku : MainAPI() {
|
||||||
callback: (ExtractorLink) -> Unit
|
callback: (ExtractorLink) -> Unit
|
||||||
): Boolean {
|
): Boolean {
|
||||||
|
|
||||||
val document = app.get(data).document
|
val document = app.get(data, interceptor = interceptor).document
|
||||||
|
|
||||||
argamap(
|
argamap(
|
||||||
{
|
{
|
||||||
|
@ -176,7 +195,8 @@ class Samehadaku : MainAPI() {
|
||||||
"type" to dataType
|
"type" to dataType
|
||||||
),
|
),
|
||||||
referer = data,
|
referer = data,
|
||||||
headers = mapOf("X-Requested-With" to "XMLHttpRequest")
|
headers = mapOf("X-Requested-With" to "XMLHttpRequest"),
|
||||||
|
interceptor = interceptor
|
||||||
).document.select("iframe").attr("src")
|
).document.select("iframe").attr("src")
|
||||||
|
|
||||||
loadFixedExtractor(fixedIframe(iframe), it.text(), "$mainUrl/", subtitleCallback, callback)
|
loadFixedExtractor(fixedIframe(iframe), it.text(), "$mainUrl/", subtitleCallback, callback)
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import org.jetbrains.kotlin.konan.properties.Properties
|
import org.jetbrains.kotlin.konan.properties.Properties
|
||||||
|
|
||||||
// use an integer for version numbers
|
// use an integer for version numbers
|
||||||
version = 168
|
version = 169
|
||||||
|
|
||||||
android {
|
android {
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
|
|
|
@ -13,6 +13,7 @@ import com.lagradost.cloudstream3.base64Decode
|
||||||
import com.lagradost.cloudstream3.extractors.Pixeldrain
|
import com.lagradost.cloudstream3.extractors.Pixeldrain
|
||||||
import com.lagradost.cloudstream3.utils.*
|
import com.lagradost.cloudstream3.utils.*
|
||||||
import java.math.BigInteger
|
import java.math.BigInteger
|
||||||
|
import java.net.URI
|
||||||
import java.security.MessageDigest
|
import java.security.MessageDigest
|
||||||
|
|
||||||
open class Playm4u : ExtractorApi() {
|
open class Playm4u : ExtractorApi() {
|
||||||
|
@ -150,7 +151,7 @@ open class VCloud : ExtractorApi() {
|
||||||
val changedLink = doc.selectFirst("script:containsData(url =)")?.data()?.let {
|
val changedLink = doc.selectFirst("script:containsData(url =)")?.data()?.let {
|
||||||
"""url\s*=\s*['"](.*)['"];""".toRegex().find(it)?.groupValues?.get(1)
|
"""url\s*=\s*['"](.*)['"];""".toRegex().find(it)?.groupValues?.get(1)
|
||||||
?.substringAfter("r=")
|
?.substringAfter("r=")
|
||||||
}
|
} ?: doc.selectFirst("div.div.vd.d-none a")?.attr("href")
|
||||||
val header = doc.selectFirst("div.card-header")?.text()
|
val header = doc.selectFirst("div.card-header")?.text()
|
||||||
app.get(
|
app.get(
|
||||||
base64Decode(changedLink ?: return), cookies = res.cookies, headers = mapOf(
|
base64Decode(changedLink ?: return), cookies = res.cookies, headers = mapOf(
|
||||||
|
@ -158,7 +159,8 @@ open class VCloud : ExtractorApi() {
|
||||||
)
|
)
|
||||||
).document.select("p.text-success ~ a").apmap {
|
).document.select("p.text-success ~ a").apmap {
|
||||||
val link = it.attr("href")
|
val link = it.attr("href")
|
||||||
if (it.text().contains(Regex("Server : 1|2"))) {
|
val uri = URI(link)
|
||||||
|
if (uri.path.contains("workers.dev")) {
|
||||||
callback.invoke(
|
callback.invoke(
|
||||||
ExtractorLink(
|
ExtractorLink(
|
||||||
this.name,
|
this.name,
|
||||||
|
@ -184,6 +186,16 @@ open class VCloud : ExtractorApi() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class HubcloudLol : VCloud() {
|
||||||
|
override val name = "Hubcloud"
|
||||||
|
override val mainUrl = "https://hubcloud.lol"
|
||||||
|
}
|
||||||
|
|
||||||
|
class Hubcloud : VCloud() {
|
||||||
|
override val name = "Hubcloud"
|
||||||
|
override val mainUrl = "https://hubcloud.in"
|
||||||
|
}
|
||||||
|
|
||||||
class Pixeldra : Pixeldrain() {
|
class Pixeldra : Pixeldrain() {
|
||||||
override val mainUrl = "https://pixeldra.in"
|
override val mainUrl = "https://pixeldra.in"
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,12 +5,7 @@ import com.lagradost.cloudstream3.utils.*
|
||||||
import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson
|
import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson
|
||||||
import com.lagradost.nicehttp.Requests
|
import com.lagradost.nicehttp.Requests
|
||||||
import com.lagradost.nicehttp.Session
|
import com.lagradost.nicehttp.Session
|
||||||
import com.lagradost.cloudstream3.extractors.Filesim
|
|
||||||
import com.lagradost.cloudstream3.extractors.GMPlayer
|
|
||||||
import com.lagradost.cloudstream3.extractors.StreamSB
|
|
||||||
import com.lagradost.cloudstream3.extractors.Voe
|
|
||||||
import com.lagradost.cloudstream3.extractors.helper.AesHelper.cryptoAESHandler
|
import com.lagradost.cloudstream3.extractors.helper.AesHelper.cryptoAESHandler
|
||||||
import com.lagradost.cloudstream3.extractors.helper.GogoHelper
|
|
||||||
import com.lagradost.cloudstream3.network.CloudflareKiller
|
import com.lagradost.cloudstream3.network.CloudflareKiller
|
||||||
import com.lagradost.nicehttp.RequestBodyTypes
|
import com.lagradost.nicehttp.RequestBodyTypes
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
|
@ -319,7 +314,6 @@ object SoraExtractor : SoraStream() {
|
||||||
callback: (ExtractorLink) -> Unit,
|
callback: (ExtractorLink) -> Unit,
|
||||||
fixIframe: Boolean = false,
|
fixIframe: Boolean = false,
|
||||||
encrypt: Boolean = false,
|
encrypt: Boolean = false,
|
||||||
key: String? = null,
|
|
||||||
) {
|
) {
|
||||||
fun String.fixBloat() : String {
|
fun String.fixBloat() : String {
|
||||||
return this.replace("\"", "").replace("\\", "")
|
return this.replace("\"", "").replace("\\", "")
|
||||||
|
@ -572,8 +566,8 @@ object SoraExtractor : SoraStream() {
|
||||||
"${link.name} ${it.second}",
|
"${link.name} ${it.second}",
|
||||||
link.url,
|
link.url,
|
||||||
link.referer,
|
link.referer,
|
||||||
when {
|
when (link.type) {
|
||||||
link.type == ExtractorLinkType.M3U8 -> link.quality
|
ExtractorLinkType.M3U8 -> link.quality
|
||||||
else -> getQualityFromName(it.first)
|
else -> getQualityFromName(it.first)
|
||||||
},
|
},
|
||||||
link.type,
|
link.type,
|
||||||
|
@ -900,8 +894,8 @@ object SoraExtractor : SoraStream() {
|
||||||
"${link.name} [${it.second}]",
|
"${link.name} [${it.second}]",
|
||||||
link.url,
|
link.url,
|
||||||
link.referer,
|
link.referer,
|
||||||
when {
|
when (link.type) {
|
||||||
link.type == ExtractorLinkType.M3U8 -> link.quality
|
ExtractorLinkType.M3U8 -> link.quality
|
||||||
else -> it.third
|
else -> it.third
|
||||||
},
|
},
|
||||||
link.type,
|
link.type,
|
||||||
|
@ -2756,6 +2750,52 @@ object SoraExtractor : SoraStream() {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun invokeNetflix(
|
||||||
|
imdbId: String? = null,
|
||||||
|
season: Int? = null,
|
||||||
|
episode: Int? = null,
|
||||||
|
callback: (ExtractorLink) -> Unit,
|
||||||
|
) {
|
||||||
|
val headers = mapOf("X-Requested-With" to "XMLHttpRequest", "Cookie" to "hd=on")
|
||||||
|
val netflixId = imdbToNetflixId(imdbId, season)
|
||||||
|
val (title, id) = app.get(
|
||||||
|
"$netflixAPI/post.php?id=${netflixId ?: return}&t=${APIHolder.unixTime}",
|
||||||
|
headers = headers
|
||||||
|
).parsedSafe<NetflixResponse>().let { media ->
|
||||||
|
if (season == null) {
|
||||||
|
media?.title to netflixId
|
||||||
|
} else {
|
||||||
|
val seasonId = media?.season?.find { it.s == "$season" }?.id
|
||||||
|
val episodeId =
|
||||||
|
app.get(
|
||||||
|
"$netflixAPI/episodes.php?s=${seasonId}&series=$netflixId&t=${APIHolder.unixTime}",
|
||||||
|
headers = headers
|
||||||
|
)
|
||||||
|
.parsedSafe<NetflixResponse>()?.episodes?.find { it.ep == "E$episode" }?.id
|
||||||
|
media?.title to episodeId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
app.get(
|
||||||
|
"$netflixAPI/playlist.php?id=${id ?: return}&t=${title ?: return}&tm=${APIHolder.unixTime}",
|
||||||
|
headers = headers
|
||||||
|
).text.let {
|
||||||
|
tryParseJson<ArrayList<NetflixResponse>>(it)
|
||||||
|
}?.firstOrNull()?.sources?.map {
|
||||||
|
callback.invoke(
|
||||||
|
ExtractorLink(
|
||||||
|
"Netflix",
|
||||||
|
"Netflix",
|
||||||
|
fixUrl(it.file ?: return@map, netflixAPI),
|
||||||
|
"$netflixAPI/",
|
||||||
|
getQualityFromName(it.file.substringAfter("q=")),
|
||||||
|
INFER_TYPE,
|
||||||
|
headers = mapOf("Cookie" to "hd=on")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -428,3 +428,36 @@ data class EMovieTraks(
|
||||||
data class FourCartoonSources(
|
data class FourCartoonSources(
|
||||||
@JsonProperty("videoSource") val videoSource: String? = null,
|
@JsonProperty("videoSource") val videoSource: String? = null,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
data class WatchhubStream(
|
||||||
|
@JsonProperty("name") val name: String? = null,
|
||||||
|
@JsonProperty("externalUrl") val externalUrl: String? = null,
|
||||||
|
)
|
||||||
|
|
||||||
|
data class WatchhubResponse(
|
||||||
|
@JsonProperty("streams") val streams: ArrayList<WatchhubStream>? = arrayListOf(),
|
||||||
|
)
|
||||||
|
|
||||||
|
data class NetflixSources(
|
||||||
|
@JsonProperty("file") val file: String? = null,
|
||||||
|
@JsonProperty("label") val label: String? = null,
|
||||||
|
)
|
||||||
|
|
||||||
|
data class NetflixEpisodes(
|
||||||
|
@JsonProperty("id") val id: String? = null,
|
||||||
|
@JsonProperty("t") val t: String? = null,
|
||||||
|
@JsonProperty("s") val s: String? = null,
|
||||||
|
@JsonProperty("ep") val ep: String? = null,
|
||||||
|
)
|
||||||
|
|
||||||
|
data class NetflixSeason(
|
||||||
|
@JsonProperty("s") val s: String? = null,
|
||||||
|
@JsonProperty("id") val id: String? = null,
|
||||||
|
)
|
||||||
|
|
||||||
|
data class NetflixResponse(
|
||||||
|
@JsonProperty("title") val title: String? = null,
|
||||||
|
@JsonProperty("season") val season: ArrayList<NetflixSeason>? = arrayListOf(),
|
||||||
|
@JsonProperty("episodes") val episodes: ArrayList<NetflixEpisodes>? = arrayListOf(),
|
||||||
|
@JsonProperty("sources") val sources: ArrayList<NetflixSources>? = arrayListOf(),
|
||||||
|
)
|
||||||
|
|
|
@ -41,6 +41,7 @@ import com.hexated.SoraExtractor.invokeFourCartoon
|
||||||
import com.hexated.SoraExtractor.invokeJump1
|
import com.hexated.SoraExtractor.invokeJump1
|
||||||
import com.hexated.SoraExtractor.invokeMoment
|
import com.hexated.SoraExtractor.invokeMoment
|
||||||
import com.hexated.SoraExtractor.invokeMultimovies
|
import com.hexated.SoraExtractor.invokeMultimovies
|
||||||
|
import com.hexated.SoraExtractor.invokeNetflix
|
||||||
import com.hexated.SoraExtractor.invokeNetmovies
|
import com.hexated.SoraExtractor.invokeNetmovies
|
||||||
import com.hexated.SoraExtractor.invokePobmovies
|
import com.hexated.SoraExtractor.invokePobmovies
|
||||||
import com.hexated.SoraExtractor.invokePrimewire
|
import com.hexated.SoraExtractor.invokePrimewire
|
||||||
|
@ -79,6 +80,7 @@ open class SoraStream : TmdbProvider() {
|
||||||
const val malsyncAPI = "https://api.malsync.moe"
|
const val malsyncAPI = "https://api.malsync.moe"
|
||||||
const val consumetHelper = "https://api.consumet.org/anime/9anime/helper"
|
const val consumetHelper = "https://api.consumet.org/anime/9anime/helper"
|
||||||
const val jikanAPI = "https://api.jikan.moe/v4"
|
const val jikanAPI = "https://api.jikan.moe/v4"
|
||||||
|
const val watchhubApi = "https://watchhub.strem.io"
|
||||||
|
|
||||||
private val apiKey =
|
private val apiKey =
|
||||||
base64DecodeAPI("ZTM=NTg=MjM=MjM=ODc=MzI=OGQ=MmE=Nzk=Nzk=ZjI=NTA=NDY=NDA=MzA=YjA=") // PLEASE DON'T STEAL
|
base64DecodeAPI("ZTM=NTg=MjM=MjM=ODc=MzI=OGQ=MmE=Nzk=Nzk=ZjI=NTA=NDY=NDA=MzA=YjA=") // PLEASE DON'T STEAL
|
||||||
|
@ -131,6 +133,7 @@ open class SoraStream : TmdbProvider() {
|
||||||
const val susflixAPI = "https://susflix.tv"
|
const val susflixAPI = "https://susflix.tv"
|
||||||
const val jump1API = "https://ca.jump1.net"
|
const val jump1API = "https://ca.jump1.net"
|
||||||
const val vegaMoviesAPI = "https://vegamovies.im"
|
const val vegaMoviesAPI = "https://vegamovies.im"
|
||||||
|
const val netflixAPI = "https://m.netflixmirror.com"
|
||||||
|
|
||||||
// INDEX SITE
|
// INDEX SITE
|
||||||
const val dahmerMoviesAPI = "https://edytjedhgmdhm.abfhaqrhbnf.workers.dev"
|
const val dahmerMoviesAPI = "https://edytjedhgmdhm.abfhaqrhbnf.workers.dev"
|
||||||
|
@ -738,6 +741,14 @@ open class SoraStream : TmdbProvider() {
|
||||||
callback
|
callback
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
if (!res.isAnime) invokeNetflix(
|
||||||
|
res.imdbId,
|
||||||
|
res.season,
|
||||||
|
res.episode,
|
||||||
|
callback
|
||||||
|
)
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
return true
|
return true
|
||||||
|
|
|
@ -28,6 +28,7 @@ import com.hexated.SoraExtractor.invokeFourCartoon
|
||||||
import com.hexated.SoraExtractor.invokeJump1
|
import com.hexated.SoraExtractor.invokeJump1
|
||||||
import com.hexated.SoraExtractor.invokeMoment
|
import com.hexated.SoraExtractor.invokeMoment
|
||||||
import com.hexated.SoraExtractor.invokeMultimovies
|
import com.hexated.SoraExtractor.invokeMultimovies
|
||||||
|
import com.hexated.SoraExtractor.invokeNetflix
|
||||||
import com.hexated.SoraExtractor.invokeNetmovies
|
import com.hexated.SoraExtractor.invokeNetmovies
|
||||||
import com.hexated.SoraExtractor.invokePrimewire
|
import com.hexated.SoraExtractor.invokePrimewire
|
||||||
import com.hexated.SoraExtractor.invokeVidSrc
|
import com.hexated.SoraExtractor.invokeVidSrc
|
||||||
|
@ -327,6 +328,14 @@ class SoraStreamLite : SoraStream() {
|
||||||
callback
|
callback
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
if (!res.isAnime) invokeNetflix(
|
||||||
|
res.imdbId,
|
||||||
|
res.season,
|
||||||
|
res.episode,
|
||||||
|
callback
|
||||||
|
)
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
return true
|
return true
|
||||||
|
|
|
@ -20,5 +20,7 @@ class SoraStreamPlugin: Plugin() {
|
||||||
registerExtractorAPI(Playm4u())
|
registerExtractorAPI(Playm4u())
|
||||||
registerExtractorAPI(VCloud())
|
registerExtractorAPI(VCloud())
|
||||||
registerExtractorAPI(Pixeldra())
|
registerExtractorAPI(Pixeldra())
|
||||||
|
registerExtractorAPI(Hubcloud())
|
||||||
|
registerExtractorAPI(HubcloudLol())
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -13,6 +13,7 @@ import com.hexated.SoraStream.Companion.malsyncAPI
|
||||||
import com.hexated.SoraStream.Companion.smashyStreamAPI
|
import com.hexated.SoraStream.Companion.smashyStreamAPI
|
||||||
import com.hexated.SoraStream.Companion.tvMoviesAPI
|
import com.hexated.SoraStream.Companion.tvMoviesAPI
|
||||||
import com.hexated.SoraStream.Companion.watchOnlineAPI
|
import com.hexated.SoraStream.Companion.watchOnlineAPI
|
||||||
|
import com.hexated.SoraStream.Companion.watchhubApi
|
||||||
import com.lagradost.cloudstream3.*
|
import com.lagradost.cloudstream3.*
|
||||||
import com.lagradost.cloudstream3.APIHolder.getCaptchaToken
|
import com.lagradost.cloudstream3.APIHolder.getCaptchaToken
|
||||||
import com.lagradost.cloudstream3.APIHolder.unixTimeMS
|
import com.lagradost.cloudstream3.APIHolder.unixTimeMS
|
||||||
|
@ -1139,6 +1140,17 @@ suspend fun tmdbToAnimeId(title: String?, year: Int?, season: String?, type: TvT
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun imdbToNetflixId(imdbId: String?, season: Int?): String? {
|
||||||
|
val url = if (season == null) {
|
||||||
|
"$watchhubApi/stream/movie/$imdbId.json"
|
||||||
|
} else {
|
||||||
|
"$watchhubApi/stream/series/$imdbId:1:1.json"
|
||||||
|
}
|
||||||
|
return app.get(url)
|
||||||
|
.parsedSafe<WatchhubResponse>()?.streams?.find { it.name == "Netflix" }?.externalUrl
|
||||||
|
?.substringAfterLast("/")
|
||||||
|
}
|
||||||
|
|
||||||
suspend fun loadCustomExtractor(
|
suspend fun loadCustomExtractor(
|
||||||
name: String? = null,
|
name: String? = null,
|
||||||
url: String,
|
url: String,
|
||||||
|
@ -1154,8 +1166,8 @@ suspend fun loadCustomExtractor(
|
||||||
name ?: link.name,
|
name ?: link.name,
|
||||||
link.url,
|
link.url,
|
||||||
link.referer,
|
link.referer,
|
||||||
when {
|
when (link.type) {
|
||||||
link.type == ExtractorLinkType.M3U8 -> link.quality
|
ExtractorLinkType.M3U8 -> link.quality
|
||||||
else -> quality ?: link.quality
|
else -> quality ?: link.quality
|
||||||
},
|
},
|
||||||
link.type,
|
link.type,
|
||||||
|
|
Loading…
Reference in a new issue