mirror of
https://github.com/hexated/cloudstream-extensions-hexated.git
synced 2024-08-15 00:03:22 +00:00
Merge branch 'hexated:master' into master
This commit is contained in:
commit
f775a934bd
48 changed files with 1009 additions and 247 deletions
|
@ -1,7 +1,7 @@
|
||||||
import org.jetbrains.kotlin.konan.properties.Properties
|
import org.jetbrains.kotlin.konan.properties.Properties
|
||||||
|
|
||||||
// use an integer for version numbers
|
// use an integer for version numbers
|
||||||
version = 6
|
version = 7
|
||||||
|
|
||||||
android {
|
android {
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
|
|
|
@ -6,6 +6,8 @@ import com.lagradost.cloudstream3.app
|
||||||
import com.lagradost.cloudstream3.argamap
|
import com.lagradost.cloudstream3.argamap
|
||||||
import com.lagradost.cloudstream3.extractors.helper.GogoHelper
|
import com.lagradost.cloudstream3.extractors.helper.GogoHelper
|
||||||
import com.lagradost.cloudstream3.mvvm.safeApiCall
|
import com.lagradost.cloudstream3.mvvm.safeApiCall
|
||||||
|
import com.lagradost.cloudstream3.utils.AppUtils
|
||||||
|
import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson
|
||||||
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.SubtitleHelper
|
import com.lagradost.cloudstream3.utils.SubtitleHelper
|
||||||
|
@ -146,20 +148,19 @@ object AnichiExtractors : Anichi() {
|
||||||
),
|
),
|
||||||
referer = "$marinHost/anime",
|
referer = "$marinHost/anime",
|
||||||
).cookies.let {
|
).cookies.let {
|
||||||
it["XSRF-TOKEN"] to it["marin_session"]
|
decode(it["XSRF-TOKEN"].toString()) to decode(it["marin_session"].toString())
|
||||||
}
|
}
|
||||||
|
|
||||||
app.get(
|
val json = app.get(
|
||||||
url,
|
url,
|
||||||
headers = mapOf(
|
headers = mapOf(
|
||||||
"Referer" to "$marinHost/",
|
"Accept" to "text/html, application/xhtml+xml",
|
||||||
"Cookie" to "__ddg1=;__ddg2_=;XSRF-TOKEN=${cookies.first};marin_session=${cookies.second};",
|
"Cookie" to "__ddg1=;__ddg2_=;XSRF-TOKEN=${cookies.first};marin_session=${cookies.second};",
|
||||||
"x-inertia" to "true",
|
"X-XSRF-TOKEN" to cookies.first
|
||||||
"x-inertia-version" to "5ee7503af8c9844b1e8d34466b727694",
|
),
|
||||||
"X-Requested-With" to "XMLHttpRequest",
|
referer = "$marinHost/anime/$id"
|
||||||
"X-XSRF-TOKEN" to decode(cookies.first.toString())
|
).document.selectFirst("div#app")?.attr("data-page")
|
||||||
)
|
tryParseJson<MarinResponses>(json)?.props?.video?.data?.mirror?.map { video ->
|
||||||
).parsedSafe<MarinResponses>()?.props?.video?.data?.mirror?.map { video ->
|
|
||||||
callback.invoke(
|
callback.invoke(
|
||||||
ExtractorLink(
|
ExtractorLink(
|
||||||
"Marin",
|
"Marin",
|
||||||
|
|
|
@ -87,6 +87,7 @@ private val embedBlackList = listOf(
|
||||||
"https://videobin.co/",
|
"https://videobin.co/",
|
||||||
"https://ok.ru",
|
"https://ok.ru",
|
||||||
"https://streamlare.com",
|
"https://streamlare.com",
|
||||||
|
"https://filemoon",
|
||||||
"streaming.php",
|
"streaming.php",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// use an integer for version numbers
|
// use an integer for version numbers
|
||||||
version = 10
|
version = 11
|
||||||
|
|
||||||
|
|
||||||
cloudstream {
|
cloudstream {
|
||||||
|
|
|
@ -13,7 +13,6 @@ class AnimeIndoProvider : MainAPI() {
|
||||||
override var name = "AnimeIndo"
|
override var name = "AnimeIndo"
|
||||||
override val hasMainPage = true
|
override val hasMainPage = true
|
||||||
override var lang = "id"
|
override var lang = "id"
|
||||||
override val hasDownloadSupport = true
|
|
||||||
|
|
||||||
override val supportedTypes = setOf(
|
override val supportedTypes = setOf(
|
||||||
TvType.Anime,
|
TvType.Anime,
|
||||||
|
@ -39,18 +38,19 @@ class AnimeIndoProvider : MainAPI() {
|
||||||
}
|
}
|
||||||
|
|
||||||
override val mainPage = mainPageOf(
|
override val mainPage = mainPageOf(
|
||||||
"$mainUrl/anime-terbaru/page/" to "Anime Terbaru",
|
"episode-terbaru" to "Episode Terbaru",
|
||||||
"$mainUrl/ongoing/page/" to "Anime Ongoing",
|
"ongoing" to "Anime Ongoing",
|
||||||
"$mainUrl/populer/page/" to "Anime Populer",
|
"populer" to "Anime Populer",
|
||||||
"$mainUrl/donghua-terbaru/page/" to "Donghua Terbaru",
|
"donghua-terbaru" to "Donghua Terbaru",
|
||||||
)
|
)
|
||||||
|
|
||||||
override suspend fun getMainPage(
|
override suspend fun getMainPage(
|
||||||
page: Int,
|
page: Int,
|
||||||
request: MainPageRequest
|
request: MainPageRequest
|
||||||
): HomePageResponse {
|
): HomePageResponse {
|
||||||
val document = app.get(request.data + page).document
|
val url = "$mainUrl/pages/${request.data}/page/$page"
|
||||||
val home = document.select("div.post-show > article, div.relat > article").mapNotNull {
|
val document = app.get(url).document
|
||||||
|
val home = document.select("main#main div.animposx").mapNotNull {
|
||||||
it.toSearchResult()
|
it.toSearchResult()
|
||||||
}
|
}
|
||||||
return newHomePageResponse(request.name, home)
|
return newHomePageResponse(request.name, home)
|
||||||
|
@ -60,7 +60,7 @@ class AnimeIndoProvider : MainAPI() {
|
||||||
return if (uri.contains("/anime/")) {
|
return if (uri.contains("/anime/")) {
|
||||||
uri
|
uri
|
||||||
} else {
|
} else {
|
||||||
var title = uri.substringAfter("$mainUrl/")
|
var title = uri.substringAfter("nonton/")
|
||||||
title = when {
|
title = when {
|
||||||
(title.contains("-episode")) && !(title.contains("-movie")) -> Regex("(.+)-episode").find(
|
(title.contains("-episode")) && !(title.contains("-movie")) -> Regex("(.+)-episode").find(
|
||||||
title
|
title
|
||||||
|
@ -74,15 +74,13 @@ class AnimeIndoProvider : MainAPI() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun Element.toSearchResult(): AnimeSearchResponse? {
|
private fun Element.toSearchResult(): AnimeSearchResponse {
|
||||||
val title = this.selectFirst("div.title")?.text()?.trim() ?: return null
|
val title = this.selectFirst("div.titlex, h2.entry-title, h4")?.text()?.trim() ?: ""
|
||||||
val href = getProperAnimeLink(this.selectFirst("a")!!.attr("href"))
|
val href = getProperAnimeLink(this.selectFirst("a")!!.attr("href"))
|
||||||
val posterUrl = this.select("img[itemprop=image]").attr("src").toString()
|
val posterUrl = fixUrlNull(this.selectFirst("img")?.attr("src"))
|
||||||
val type = getType(this.select("div.type").text().trim())
|
val epNum = this.selectFirst("span.episode")?.ownText()?.replace(Regex("\\D"), "")?.trim()
|
||||||
val epNum =
|
|
||||||
this.selectFirst("span.episode")?.ownText()?.replace(Regex("\\D"), "")?.trim()
|
|
||||||
?.toIntOrNull()
|
?.toIntOrNull()
|
||||||
return newAnimeSearchResponse(title, href, type) {
|
return newAnimeSearchResponse(title, href, TvType.Anime) {
|
||||||
this.posterUrl = posterUrl
|
this.posterUrl = posterUrl
|
||||||
addSub(epNum)
|
addSub(epNum)
|
||||||
}
|
}
|
||||||
|
@ -131,6 +129,10 @@ class AnimeIndoProvider : MainAPI() {
|
||||||
Episode(link, header.text(), episode = episode)
|
Episode(link, header.text(), episode = episode)
|
||||||
}.reversed()
|
}.reversed()
|
||||||
|
|
||||||
|
val recommendations = document.select("div.relat div.animposx").mapNotNull {
|
||||||
|
it.toSearchResult()
|
||||||
|
}
|
||||||
|
|
||||||
return newAnimeLoadResponse(title, url, getType(type)) {
|
return newAnimeLoadResponse(title, url, getType(type)) {
|
||||||
engName = title
|
engName = title
|
||||||
posterUrl = poster
|
posterUrl = poster
|
||||||
|
@ -139,6 +141,7 @@ class AnimeIndoProvider : MainAPI() {
|
||||||
showStatus = status
|
showStatus = status
|
||||||
plot = description
|
plot = description
|
||||||
this.tags = tags
|
this.tags = tags
|
||||||
|
this.recommendations = recommendations
|
||||||
addTrailer(trailer)
|
addTrailer(trailer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
// use an integer for version numbers
|
// use an integer for version numbers
|
||||||
version = 6
|
version = 8
|
||||||
|
|
||||||
|
|
||||||
cloudstream {
|
cloudstream {
|
||||||
language = "id"
|
language = "id"
|
||||||
// All of these properties are optional, you can safely remove them
|
// All of these properties are optional, you can safely remove them
|
||||||
|
|
||||||
// description = "Lorem Ipsum"
|
description = "Include: Oppadrama"
|
||||||
authors = listOf("Hexated")
|
authors = listOf("Hexated")
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -3,6 +3,7 @@ package com.hexated
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty
|
import com.fasterxml.jackson.annotation.JsonProperty
|
||||||
import com.lagradost.cloudstream3.*
|
import com.lagradost.cloudstream3.*
|
||||||
import com.lagradost.cloudstream3.extractors.XStreamCdn
|
import com.lagradost.cloudstream3.extractors.XStreamCdn
|
||||||
|
import com.lagradost.cloudstream3.utils.AppUtils
|
||||||
import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson
|
import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson
|
||||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||||
import com.lagradost.cloudstream3.utils.getQualityFromName
|
import com.lagradost.cloudstream3.utils.getQualityFromName
|
||||||
|
@ -10,14 +11,11 @@ import com.lagradost.cloudstream3.utils.loadExtractor
|
||||||
import org.jsoup.Jsoup
|
import org.jsoup.Jsoup
|
||||||
import org.jsoup.nodes.Element
|
import org.jsoup.nodes.Element
|
||||||
|
|
||||||
class DramaidProvider : MainAPI() {
|
open class DramaidProvider : MainAPI() {
|
||||||
override var mainUrl = "https://dramaid.best"
|
override var mainUrl = "https://dramaid.best"
|
||||||
override var name = "DramaId"
|
override var name = "DramaId"
|
||||||
override val hasQuickSearch = false
|
|
||||||
override val hasMainPage = true
|
override val hasMainPage = true
|
||||||
override var lang = "id"
|
override var lang = "id"
|
||||||
override val hasDownloadSupport = true
|
|
||||||
override val hasChromecastSupport = false
|
|
||||||
override val supportedTypes = setOf(TvType.AsianDrama)
|
override val supportedTypes = setOf(TvType.AsianDrama)
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
@ -28,6 +26,14 @@ class DramaidProvider : MainAPI() {
|
||||||
else -> ShowStatus.Completed
|
else -> ShowStatus.Completed
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getType(t: String?): TvType {
|
||||||
|
return when {
|
||||||
|
t?.contains("Movie", true) == true -> TvType.Movie
|
||||||
|
t?.contains("Anime", true) == true -> TvType.Anime
|
||||||
|
else -> TvType.AsianDrama
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override val mainPage = mainPageOf(
|
override val mainPage = mainPageOf(
|
||||||
|
@ -45,18 +51,17 @@ class DramaidProvider : MainAPI() {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getProperDramaLink(uri: String): String {
|
private fun getProperDramaLink(uri: String): String {
|
||||||
return if (uri.contains("/series/")) {
|
return if (uri.contains("-episode-")) {
|
||||||
uri
|
|
||||||
} else {
|
|
||||||
"$mainUrl/series/" + Regex("$mainUrl/(.+)-ep.+").find(uri)?.groupValues?.get(1)
|
"$mainUrl/series/" + Regex("$mainUrl/(.+)-ep.+").find(uri)?.groupValues?.get(1)
|
||||||
.toString()
|
} else {
|
||||||
|
uri
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun Element.toSearchResult(): SearchResponse? {
|
private fun Element.toSearchResult(): SearchResponse? {
|
||||||
val href = getProperDramaLink(this.selectFirst("a.tip")!!.attr("href"))
|
val href = getProperDramaLink(this.selectFirst("a.tip")!!.attr("href"))
|
||||||
val title = this.selectFirst("h2[itemprop=headline]")?.text()?.trim() ?: return null
|
val title = this.selectFirst("h2[itemprop=headline]")?.text()?.trim() ?: return null
|
||||||
val posterUrl = fixUrlNull(this.selectFirst(".limit > noscript > img")?.attr("src"))
|
val posterUrl = fixUrlNull(this.select("img:last-child").attr("src"))
|
||||||
|
|
||||||
return newTvSeriesSearchResponse(title, href, TvType.AsianDrama) {
|
return newTvSeriesSearchResponse(title, href, TvType.AsianDrama) {
|
||||||
this.posterUrl = posterUrl
|
this.posterUrl = posterUrl
|
||||||
|
@ -64,27 +69,19 @@ class DramaidProvider : MainAPI() {
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun search(query: String): List<SearchResponse> {
|
override suspend fun search(query: String): List<SearchResponse> {
|
||||||
val link = "$mainUrl/?s=$query"
|
val document = app.get("$mainUrl/?s=$query").document
|
||||||
val document = app.get(link).document
|
return document.select("article[itemscope=itemscope]").mapNotNull {
|
||||||
|
it.toSearchResult()
|
||||||
return document.select("article[itemscope=itemscope]").map {
|
|
||||||
val title = it.selectFirst("h2[itemprop=headline]")!!.text().trim()
|
|
||||||
val poster = it.selectFirst(".limit > noscript > img")!!.attr("src")
|
|
||||||
val href = it.selectFirst("a.tip")!!.attr("href")
|
|
||||||
|
|
||||||
newTvSeriesSearchResponse(title, href, TvType.AsianDrama) {
|
|
||||||
this.posterUrl = poster
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun load(url: String): LoadResponse {
|
override suspend fun load(url: String): LoadResponse {
|
||||||
val document = app.get(url).document
|
val document = app.get(url).document
|
||||||
|
|
||||||
val title = document.selectFirst("h1.entry-title")!!.text().trim()
|
val title = document.selectFirst("h1.entry-title")?.text()?.trim() ?: ""
|
||||||
val poster = document.select(".thumb > noscript > img").attr("src")
|
val poster = fixUrlNull(document.select("div.thumb img:last-child").attr("src"))
|
||||||
val tags = document.select(".genxed > a").map { it.text() }
|
val tags = document.select(".genxed > a").map { it.text() }
|
||||||
|
val type = document.selectFirst(".info-content .spe span:contains(Tipe:)")?.ownText()
|
||||||
val year = Regex("\\d, ([0-9]*)").find(
|
val year = Regex("\\d, ([0-9]*)").find(
|
||||||
document.selectFirst(".info-content > .spe > span > time")!!.text().trim()
|
document.selectFirst(".info-content > .spe > span > time")!!.text().trim()
|
||||||
)?.groupValues?.get(1).toString().toIntOrNull()
|
)?.groupValues?.get(1).toString().toIntOrNull()
|
||||||
|
@ -94,37 +91,28 @@ class DramaidProvider : MainAPI() {
|
||||||
)
|
)
|
||||||
val description = document.select(".entry-content > p").text().trim()
|
val description = document.select(".entry-content > p").text().trim()
|
||||||
|
|
||||||
val episodes = document.select(".eplister > ul > li").map {
|
val episodes = document.select(".eplister > ul > li").mapNotNull {
|
||||||
val name = it.selectFirst("a > .epl-title")!!.text().trim()
|
val name = it.selectFirst("a > .epl-title")?.text()
|
||||||
val link = it.select("a").attr("href")
|
val link = fixUrl(it.selectFirst("a")?.attr("href") ?: return@mapNotNull null)
|
||||||
val epNum = it.selectFirst("a > .epl-num")!!.text().trim().toIntOrNull()
|
val epNum = it.selectFirst(".epl-num")?.text()?.toIntOrNull()
|
||||||
newEpisode(link) {
|
Episode(
|
||||||
this.name = name
|
link,
|
||||||
this.episode = epNum
|
name,
|
||||||
}
|
episode = epNum
|
||||||
|
)
|
||||||
}.reversed()
|
}.reversed()
|
||||||
|
|
||||||
val recommendations =
|
val recommendations =
|
||||||
document.select(".listupd > article[itemscope=itemscope]").map { rec ->
|
document.select(".listupd > article[itemscope=itemscope]").mapNotNull { rec ->
|
||||||
val epTitle = rec.selectFirst("h2[itemprop=headline]")!!.text().trim()
|
rec.toSearchResult()
|
||||||
val epPoster = rec.selectFirst(".limit > noscript > img")!!.attr("src")
|
|
||||||
val epHref = fixUrl(rec.selectFirst("a.tip")!!.attr("href"))
|
|
||||||
|
|
||||||
newTvSeriesSearchResponse(epTitle, epHref, TvType.AsianDrama) {
|
|
||||||
this.posterUrl = epPoster
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (episodes.size == 1) {
|
return newTvSeriesLoadResponse(
|
||||||
return newMovieLoadResponse(title, url, TvType.Movie, episodes[0].data) {
|
title,
|
||||||
posterUrl = poster
|
url,
|
||||||
this.year = year
|
getType(type),
|
||||||
plot = description
|
episodes = episodes
|
||||||
this.tags = tags
|
) {
|
||||||
this.recommendations = recommendations
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return newTvSeriesLoadResponse(title, url, TvType.AsianDrama, episodes = episodes) {
|
|
||||||
posterUrl = poster
|
posterUrl = poster
|
||||||
this.year = year
|
this.year = year
|
||||||
showStatus = status
|
showStatus = status
|
||||||
|
@ -132,7 +120,6 @@ class DramaidProvider : MainAPI() {
|
||||||
this.tags = tags
|
this.tags = tags
|
||||||
this.recommendations = recommendations
|
this.recommendations = recommendations
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -203,12 +190,13 @@ class DramaidProvider : MainAPI() {
|
||||||
it.replace("https://ndrama.xyz", "https://www.fembed.com")
|
it.replace("https://ndrama.xyz", "https://www.fembed.com")
|
||||||
}.apmap {
|
}.apmap {
|
||||||
when {
|
when {
|
||||||
it.contains("motonews.club") -> invokeDriveSource(
|
it.contains("motonews") -> invokeDriveSource(
|
||||||
it,
|
it,
|
||||||
this.name,
|
this.name,
|
||||||
subtitleCallback,
|
subtitleCallback,
|
||||||
callback
|
callback
|
||||||
)
|
)
|
||||||
|
|
||||||
else -> loadExtractor(it, data, subtitleCallback, callback)
|
else -> loadExtractor(it, data, subtitleCallback, callback)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ class DramaidProviderPlugin: Plugin() {
|
||||||
override fun load(context: Context) {
|
override fun load(context: Context) {
|
||||||
// All providers should be added in this manner. Please don't edit the providers list directly.
|
// All providers should be added in this manner. Please don't edit the providers list directly.
|
||||||
registerMainAPI(DramaidProvider())
|
registerMainAPI(DramaidProvider())
|
||||||
|
registerMainAPI(Oppadrama())
|
||||||
registerExtractorAPI(Vanfem())
|
registerExtractorAPI(Vanfem())
|
||||||
}
|
}
|
||||||
}
|
}
|
6
DramaidProvider/src/main/kotlin/com/hexated/Oppadrama.kt
Normal file
6
DramaidProvider/src/main/kotlin/com/hexated/Oppadrama.kt
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
package com.hexated
|
||||||
|
|
||||||
|
class Oppadrama : DramaidProvider() {
|
||||||
|
override var mainUrl = "http://185.217.95.34"
|
||||||
|
override var name = "Oppadrama"
|
||||||
|
}
|
|
@ -1,12 +1,12 @@
|
||||||
// use an integer for version numbers
|
// use an integer for version numbers
|
||||||
version = 4
|
version = 3
|
||||||
|
|
||||||
|
|
||||||
cloudstream {
|
cloudstream {
|
||||||
language = "id"
|
language = "id"
|
||||||
// All of these properties are optional, you can safely remove them
|
// All of these properties are optional, you can safely remove them
|
||||||
|
|
||||||
// description = "Lorem Ipsum"
|
description = "Include: DutaMovie, Ngefilm, Nodrakorid"
|
||||||
authors = listOf("Hexated")
|
authors = listOf("Hexated")
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -23,5 +23,5 @@ cloudstream {
|
||||||
"Movie",
|
"Movie",
|
||||||
)
|
)
|
||||||
|
|
||||||
iconUrl = "https://www.google.com/s2/favicons?domain=ngefilm21.club&sz=%size%"
|
iconUrl = "https://www.google.com/s2/favicons?domain=gomov.bio&sz=%size%"
|
||||||
}
|
}
|
37
Gomov/src/main/kotlin/com/hexated/DutaMovie.kt
Normal file
37
Gomov/src/main/kotlin/com/hexated/DutaMovie.kt
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
package com.hexated
|
||||||
|
|
||||||
|
import com.lagradost.cloudstream3.*
|
||||||
|
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||||
|
import com.lagradost.cloudstream3.utils.httpsify
|
||||||
|
import com.lagradost.cloudstream3.utils.loadExtractor
|
||||||
|
|
||||||
|
open class DutaMovie : Gomov() {
|
||||||
|
override var mainUrl = "https://dutamovie21.live"
|
||||||
|
override var name = "DutaMovie"
|
||||||
|
|
||||||
|
override val mainPage = mainPageOf(
|
||||||
|
"category/box-office/page/%d/" to "Box Office",
|
||||||
|
"category/serial-tv/page/%d/" to "Serial TV",
|
||||||
|
"category/animation/page/%d/" to "Animasi",
|
||||||
|
"country/korea/page/%d/" to "Serial TV Korea",
|
||||||
|
"country/indonesia/page/%d/" to "Serial TV Indonesia",
|
||||||
|
)
|
||||||
|
|
||||||
|
override suspend fun loadLinks(
|
||||||
|
data: String,
|
||||||
|
isCasting: Boolean,
|
||||||
|
subtitleCallback: (SubtitleFile) -> Unit,
|
||||||
|
callback: (ExtractorLink) -> Unit
|
||||||
|
): Boolean {
|
||||||
|
|
||||||
|
app.get(data).document.select("ul.muvipro-player-tabs li a").apmap {
|
||||||
|
val iframe = app.get(fixUrl(it.attr("href"))).document.selectFirst("div.gmr-embed-responsive iframe")
|
||||||
|
?.attr("src")
|
||||||
|
loadExtractor(httpsify(iframe ?: return@apmap ), "$mainUrl/", subtitleCallback, callback)
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
24
Gomov/src/main/kotlin/com/hexated/Extractors.kt
Normal file
24
Gomov/src/main/kotlin/com/hexated/Extractors.kt
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
package com.hexated
|
||||||
|
|
||||||
|
import com.lagradost.cloudstream3.extractors.Filesim
|
||||||
|
import com.lagradost.cloudstream3.extractors.Gdriveplayer
|
||||||
|
import com.lagradost.cloudstream3.extractors.StreamSB
|
||||||
|
|
||||||
|
class Dutamovie21 : StreamSB() {
|
||||||
|
override var name = "Dutamovie21"
|
||||||
|
override var mainUrl = "https://dutamovie21.xyz"
|
||||||
|
}
|
||||||
|
|
||||||
|
class Filelions : Filesim() {
|
||||||
|
override val name = "Filelions"
|
||||||
|
override var mainUrl = "https://filelions.to"
|
||||||
|
}
|
||||||
|
|
||||||
|
class Likessb : StreamSB() {
|
||||||
|
override var name = "Likessb"
|
||||||
|
override var mainUrl = "https://likessb.com"
|
||||||
|
}
|
||||||
|
|
||||||
|
class DbGdriveplayer : Gdriveplayer() {
|
||||||
|
override var mainUrl = "https://database.gdriveplayer.us"
|
||||||
|
}
|
|
@ -4,15 +4,15 @@ import com.lagradost.cloudstream3.*
|
||||||
import com.lagradost.cloudstream3.LoadResponse.Companion.addActors
|
import com.lagradost.cloudstream3.LoadResponse.Companion.addActors
|
||||||
import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer
|
import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer
|
||||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||||
|
import com.lagradost.cloudstream3.utils.httpsify
|
||||||
import com.lagradost.cloudstream3.utils.loadExtractor
|
import com.lagradost.cloudstream3.utils.loadExtractor
|
||||||
import org.jsoup.nodes.Element
|
import org.jsoup.nodes.Element
|
||||||
|
|
||||||
class Ngefilm : MainAPI() {
|
open class Gomov : MainAPI() {
|
||||||
override var mainUrl = "https://ngefilm21.cfd"
|
override var mainUrl = "https://gomov.bio"
|
||||||
override var name = "Ngefilm"
|
override var name = "Gomov"
|
||||||
override val hasMainPage = true
|
override val hasMainPage = true
|
||||||
override var lang = "id"
|
override var lang = "id"
|
||||||
override val hasDownloadSupport = true
|
|
||||||
override val supportedTypes = setOf(
|
override val supportedTypes = setOf(
|
||||||
TvType.Movie,
|
TvType.Movie,
|
||||||
TvType.TvSeries,
|
TvType.TvSeries,
|
||||||
|
@ -20,27 +20,57 @@ class Ngefilm : MainAPI() {
|
||||||
)
|
)
|
||||||
|
|
||||||
override val mainPage = mainPageOf(
|
override val mainPage = mainPageOf(
|
||||||
"?s&search=advanced&post_type=movie&index&orderby&genre&movieyear&country&quality=" to "Movies Terbaru",
|
"page/%d/?s&search=advanced&post_type=movie" to "Movies",
|
||||||
"?s=&search=advanced&post_type=tv&index=&orderby=&genre=&movieyear=&country=&quality=" to "Series Terbaru",
|
"category/western-series/page/%d/" to "Western Series",
|
||||||
"?s=&search=advanced&post_type=tv&index=&orderby=&genre=drakor&movieyear=&country=&quality=" to "Series Korea",
|
"tv/page/%d/" to "Tv Shows",
|
||||||
"?s=&search=advanced&post_type=tv&index=&orderby=&genre=&movieyear=&country=indonesia&quality=" to "Series Indonesia",
|
"category/korean-series/page/%d/" to "Korean Series",
|
||||||
|
"category/chinese-series/page/%d/" to "Chinese Series",
|
||||||
|
"category/india-series/page/%d/" to "India Series",
|
||||||
)
|
)
|
||||||
|
|
||||||
override suspend fun getMainPage(
|
override suspend fun getMainPage(
|
||||||
page: Int,
|
page: Int,
|
||||||
request: MainPageRequest
|
request: MainPageRequest
|
||||||
): HomePageResponse {
|
): HomePageResponse {
|
||||||
val document = app.get("$mainUrl/page/$page/${request.data}").document
|
val data = request.data.format(page)
|
||||||
val home = document.select("main#main article").mapNotNull {
|
val document = app.get("$mainUrl/$data").document
|
||||||
|
val home = document.select("article.item").mapNotNull {
|
||||||
it.toSearchResult()
|
it.toSearchResult()
|
||||||
}
|
}
|
||||||
return newHomePageResponse(request.name, home)
|
return newHomePageResponse(request.name, home)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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")?.attr("src"))?.fixImageQuality()
|
||||||
|
val quality = this.select("div.gmr-qual, div.gmr-quality-item > a").text().trim().replace("-", "")
|
||||||
|
return if (quality.isEmpty()) {
|
||||||
|
val episode = this.select("div.gmr-numbeps > span").text().toIntOrNull()
|
||||||
|
newAnimeSearchResponse(title, href, TvType.TvSeries) {
|
||||||
|
this.posterUrl = posterUrl
|
||||||
|
addSub(episode)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
newMovieSearchResponse(title, href, TvType.Movie) {
|
||||||
|
this.posterUrl = posterUrl
|
||||||
|
addQuality(quality)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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")?.attr("src").fixImageQuality())
|
||||||
|
return newMovieSearchResponse(title, href, TvType.Movie) {
|
||||||
|
this.posterUrl = posterUrl
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override suspend fun search(query: String): List<SearchResponse> {
|
override suspend fun search(query: String): List<SearchResponse> {
|
||||||
val link = "$mainUrl/?s=$query&post_type[]=post&post_type[]=tv"
|
return app.get("$mainUrl/?s=$query&post_type[]=post&post_type[]=tv").document.select("article.item")
|
||||||
val document = app.get(link).document
|
.mapNotNull {
|
||||||
return document.select("main#main article").mapNotNull {
|
|
||||||
it.toSearchResult()
|
it.toSearchResult()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -49,10 +79,10 @@ class Ngefilm : MainAPI() {
|
||||||
val document = app.get(url).document
|
val document = app.get(url).document
|
||||||
|
|
||||||
val title =
|
val title =
|
||||||
document.selectFirst("h1.entry-title")?.text()?.substringBefore("Season")?.trim() ?: ""
|
document.selectFirst("h1.entry-title")?.text()?.substringBefore("Season")?.trim()
|
||||||
val poster = fixUrlNull(
|
.toString()
|
||||||
document.selectFirst("figure.pull-left > img")?.attr("src")?.fixImageQuality()
|
val poster =
|
||||||
)
|
fixUrlNull(document.selectFirst("figure.pull-left > img")?.attr("src"))?.fixImageQuality()
|
||||||
val tags = document.select("span.gmr-movie-genre:contains(Genre:) > a").map { it.text() }
|
val tags = document.select("span.gmr-movie-genre:contains(Genre:) > a").map { it.text() }
|
||||||
|
|
||||||
val year =
|
val year =
|
||||||
|
@ -71,19 +101,18 @@ class Ngefilm : MainAPI() {
|
||||||
}
|
}
|
||||||
|
|
||||||
return if (tvType == TvType.TvSeries) {
|
return if (tvType == TvType.TvSeries) {
|
||||||
val episodes = document.select("div.gmr-listseries > a")
|
val episodes = document.select("div.vid-episodes a, div.gmr-listseries a").map { eps ->
|
||||||
.filter { element -> !element.text().contains("Pilih Episode", true) }
|
|
||||||
.map { eps ->
|
|
||||||
val href = fixUrl(eps.attr("href"))
|
val href = fixUrl(eps.attr("href"))
|
||||||
val episode = eps.text().substringAfter("Eps").toIntOrNull()
|
val name = eps.text()
|
||||||
val season =
|
val episode = name.split(" ").lastOrNull()?.filter { it.isDigit() }?.toIntOrNull()
|
||||||
eps.text().split(" ").first().substringAfter("S").toIntOrNull() ?: 1
|
val season = name.split(" ").firstOrNull()?.filter { it.isDigit() }?.toIntOrNull()
|
||||||
Episode(
|
Episode(
|
||||||
href,
|
href,
|
||||||
season = season,
|
name,
|
||||||
|
season = if(name.contains(" ")) season else null,
|
||||||
episode = episode,
|
episode = episode,
|
||||||
)
|
)
|
||||||
}
|
}.filter { it.episode != null }
|
||||||
newTvSeriesLoadResponse(title, url, TvType.TvSeries, episodes) {
|
newTvSeriesLoadResponse(title, url, TvType.TvSeries, episodes) {
|
||||||
this.posterUrl = poster
|
this.posterUrl = poster
|
||||||
this.year = year
|
this.year = year
|
||||||
|
@ -116,49 +145,26 @@ class Ngefilm : MainAPI() {
|
||||||
): Boolean {
|
): Boolean {
|
||||||
|
|
||||||
val document = app.get(data).document
|
val document = app.get(data).document
|
||||||
|
val id = document.selectFirst("div#muvipro_player_content_id")!!.attr("data-id")
|
||||||
|
|
||||||
document.select("ul.muvipro-player-tabs li a").apmap { server ->
|
document.select("div.tab-content-ajax").apmap {
|
||||||
val iframe = app.get(fixUrl(server.attr("href"))).document.selectFirst("div.gmr-embed-responsive iframe")
|
val server = app.post(
|
||||||
?.attr("src")?.let { fixUrl(it) } ?: return@apmap
|
"$mainUrl/wp-admin/admin-ajax.php",
|
||||||
loadExtractor(iframe, "$mainUrl/", subtitleCallback, callback)
|
data = mapOf("action" to "muvipro_player_content", "tab" to it.attr("id"), "post_id" to id)
|
||||||
|
).document.select("iframe").attr("src")
|
||||||
|
|
||||||
|
loadExtractor(httpsify(server), "$mainUrl/", subtitleCallback, callback)
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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") ?: return null)
|
|
||||||
val posterUrl = fixUrlNull(this.selectFirst("a > img")?.attr("src").fixImageQuality())
|
|
||||||
val quality = this.select("div.gmr-quality-item > a").text().trim()
|
|
||||||
return if (quality.isEmpty()) {
|
|
||||||
val episode =
|
|
||||||
this.select("div.gmr-numbeps > span").text().filter { it.isDigit() }.toIntOrNull()
|
|
||||||
newAnimeSearchResponse(title, href, TvType.TvSeries) {
|
|
||||||
this.posterUrl = posterUrl
|
|
||||||
addSub(episode)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
newMovieSearchResponse(title, href, TvType.Movie) {
|
|
||||||
this.posterUrl = posterUrl
|
|
||||||
addQuality(quality.replace("-", ""))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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")?.attr("src").fixImageQuality())
|
|
||||||
return newMovieSearchResponse(title, href, TvType.Movie) {
|
|
||||||
this.posterUrl = posterUrl
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun String?.fixImageQuality(): String? {
|
private fun String?.fixImageQuality(): String? {
|
||||||
val quality = Regex("(-\\d*x\\d*)").find(this ?: return null)?.groupValues?.get(0)
|
if(this == null) return null
|
||||||
return this.replace(quality ?: return null, "")
|
val regex = Regex("(-\\d*x\\d*)").find(this)?.groupValues
|
||||||
|
if(regex?.isEmpty() == true) return this
|
||||||
|
return this.replace(regex?.get(0) ?: return null, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
21
Gomov/src/main/kotlin/com/hexated/GomovPlugin.kt
Normal file
21
Gomov/src/main/kotlin/com/hexated/GomovPlugin.kt
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
|
||||||
|
package com.hexated
|
||||||
|
|
||||||
|
import com.lagradost.cloudstream3.plugins.CloudstreamPlugin
|
||||||
|
import com.lagradost.cloudstream3.plugins.Plugin
|
||||||
|
import android.content.Context
|
||||||
|
|
||||||
|
@CloudstreamPlugin
|
||||||
|
class GomovPlugin: Plugin() {
|
||||||
|
override fun load(context: Context) {
|
||||||
|
// All providers should be added in this manner. Please don't edit the providers list directly.
|
||||||
|
registerMainAPI(Gomov())
|
||||||
|
registerMainAPI(DutaMovie())
|
||||||
|
registerMainAPI(Ngefilm())
|
||||||
|
registerMainAPI(Nodrakorid())
|
||||||
|
registerExtractorAPI(Filelions())
|
||||||
|
registerExtractorAPI(Likessb())
|
||||||
|
registerExtractorAPI(DbGdriveplayer())
|
||||||
|
registerExtractorAPI(Dutamovie21())
|
||||||
|
}
|
||||||
|
}
|
22
Gomov/src/main/kotlin/com/hexated/Ngefilm.kt
Normal file
22
Gomov/src/main/kotlin/com/hexated/Ngefilm.kt
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
package com.hexated
|
||||||
|
|
||||||
|
import com.lagradost.cloudstream3.SubtitleFile
|
||||||
|
import com.lagradost.cloudstream3.apmap
|
||||||
|
import com.lagradost.cloudstream3.app
|
||||||
|
import com.lagradost.cloudstream3.fixUrl
|
||||||
|
import com.lagradost.cloudstream3.mainPageOf
|
||||||
|
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||||
|
import com.lagradost.cloudstream3.utils.loadExtractor
|
||||||
|
|
||||||
|
class Ngefilm : DutaMovie() {
|
||||||
|
override var mainUrl = "https://ngefilm21.lol"
|
||||||
|
override var name = "Ngefilm"
|
||||||
|
|
||||||
|
override val mainPage = mainPageOf(
|
||||||
|
"/page/%d/?s&search=advanced&post_type=movie&index&orderby&genre&movieyear&country&quality=" to "Movies Terbaru",
|
||||||
|
"/page/%d/?s=&search=advanced&post_type=tv&index=&orderby=&genre=&movieyear=&country=&quality=" to "Series Terbaru",
|
||||||
|
"/page/%d/?s=&search=advanced&post_type=tv&index=&orderby=&genre=drakor&movieyear=&country=&quality=" to "Series Korea",
|
||||||
|
"/page/%d/?s=&search=advanced&post_type=tv&index=&orderby=&genre=&movieyear=&country=indonesia&quality=" to "Series Indonesia",
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
16
Gomov/src/main/kotlin/com/hexated/Nodrakorid.kt
Normal file
16
Gomov/src/main/kotlin/com/hexated/Nodrakorid.kt
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
package com.hexated
|
||||||
|
|
||||||
|
import com.lagradost.cloudstream3.mainPageOf
|
||||||
|
|
||||||
|
class Nodrakorid : DutaMovie() {
|
||||||
|
override var mainUrl = "https://no-drak-or.xyz"
|
||||||
|
override var name = "Nodrakorid"
|
||||||
|
|
||||||
|
override val mainPage = mainPageOf(
|
||||||
|
"genre/movie/page/%d/" to "Film Terbaru",
|
||||||
|
"genre/korean-movie/page/%d/" to "Film Korea",
|
||||||
|
"genre/drama/page/%d/" to "Drama Korea",
|
||||||
|
"genre/c-drama/c-drama-c-drama/page/%d/" to "Drama China",
|
||||||
|
"genre/thai-drama/page/%d/" to "Drama Thailand",
|
||||||
|
)
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
// use an integer for version numbers
|
// use an integer for version numbers
|
||||||
version = 12
|
version = 13
|
||||||
|
|
||||||
|
|
||||||
cloudstream {
|
cloudstream {
|
||||||
|
|
|
@ -9,7 +9,7 @@ import org.jsoup.Jsoup
|
||||||
import org.jsoup.nodes.Element
|
import org.jsoup.nodes.Element
|
||||||
|
|
||||||
class KuramanimeProvider : MainAPI() {
|
class KuramanimeProvider : MainAPI() {
|
||||||
override var mainUrl = "https://kuramanime.net"
|
override var mainUrl = "https://kuramanime.xyz"
|
||||||
override var name = "Kuramanime"
|
override var name = "Kuramanime"
|
||||||
override val hasQuickSearch = false
|
override val hasQuickSearch = false
|
||||||
override val hasMainPage = true
|
override val hasMainPage = true
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// use an integer for version numbers
|
// use an integer for version numbers
|
||||||
version = 1
|
version = 2
|
||||||
|
|
||||||
|
|
||||||
cloudstream {
|
cloudstream {
|
||||||
|
|
|
@ -10,7 +10,7 @@ import com.lagradost.cloudstream3.utils.getQualityFromName
|
||||||
import org.jsoup.nodes.Element
|
import org.jsoup.nodes.Element
|
||||||
|
|
||||||
class MultiplexProvider : MainAPI() {
|
class MultiplexProvider : MainAPI() {
|
||||||
override var mainUrl = "https://146.19.24.137"
|
override var mainUrl = "http://5.104.81.46"
|
||||||
override var name = "Multiplex"
|
override var name = "Multiplex"
|
||||||
override val hasMainPage = true
|
override val hasMainPage = true
|
||||||
override var lang = "id"
|
override var lang = "id"
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// use an integer for version numbers
|
// use an integer for version numbers
|
||||||
version = 1
|
version = 3
|
||||||
|
|
||||||
|
|
||||||
cloudstream {
|
cloudstream {
|
||||||
|
|
|
@ -30,6 +30,7 @@ class Nekopoi : MainAPI() {
|
||||||
"SendCm",
|
"SendCm",
|
||||||
"GoogleDrive",
|
"GoogleDrive",
|
||||||
)
|
)
|
||||||
|
const val mirroredHost = "https://www.mirrored.to"
|
||||||
|
|
||||||
fun getStatus(t: String?): ShowStatus {
|
fun getStatus(t: String?): ShowStatus {
|
||||||
return when (t) {
|
return when (t) {
|
||||||
|
@ -155,7 +156,7 @@ class Nekopoi : MainAPI() {
|
||||||
) to ele.selectFirst("a:contains(ouo)")
|
) to ele.selectFirst("a:contains(ouo)")
|
||||||
?.attr("href")
|
?.attr("href")
|
||||||
}.filter { it.first != Qualities.P360.value }.map {
|
}.filter { it.first != Qualities.P360.value }.map {
|
||||||
val bypassedAds = bypassMirrored(bypassOuo(it.second ?: return@map) ?: return@map)
|
val bypassedAds = bypassMirrored(bypassOuo(it.second))
|
||||||
bypassedAds.apmap ads@{ adsLink ->
|
bypassedAds.apmap ads@{ adsLink ->
|
||||||
loadExtractor(
|
loadExtractor(
|
||||||
fixEmbed(adsLink) ?: return@ads,
|
fixEmbed(adsLink) ?: return@ads,
|
||||||
|
@ -225,21 +226,20 @@ class Nekopoi : MainAPI() {
|
||||||
return res.headers["location"]
|
return res.headers["location"]
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun bypassMirrored(url: String): List<String?> {
|
private suspend fun bypassMirrored(url: String?): List<String?> {
|
||||||
val request = app.get(url)
|
val request = app.get(url ?: return emptyList())
|
||||||
val hostUrl = getBaseUrl(request.url)
|
|
||||||
var nextUrl = request.document.selectFirst("div.row div.centered a")?.attr("href")
|
var nextUrl = request.document.selectFirst("div.row div.centered a")?.attr("href")
|
||||||
nextUrl = app.get(nextUrl ?: return emptyList()).text.substringAfter("\"GET\", \"")
|
nextUrl = app.get(nextUrl ?: return emptyList()).text.substringAfter("\"GET\", \"")
|
||||||
.substringBefore("\"")
|
.substringBefore("\"")
|
||||||
return app.get(fixUrl(nextUrl, hostUrl)).document.select("table.hoverable tbody tr")
|
return app.get(fixUrl(nextUrl, mirroredHost)).document.select("table.hoverable tbody tr")
|
||||||
.filter { mirror ->
|
.filter { mirror ->
|
||||||
!mirrorIsBlackList(mirror.selectFirst("img")?.attr("alt"))
|
!mirrorIsBlackList(mirror.selectFirst("img")?.attr("alt"))
|
||||||
}.apmap {
|
}.apmap {
|
||||||
val fileLink = it.selectFirst("a")?.attr("href")
|
val fileLink = it.selectFirst("a")?.attr("href")
|
||||||
app.get(
|
app.get(
|
||||||
fixUrl(
|
fixUrl(
|
||||||
fileLink.toString(),
|
fileLink ?: return@apmap null,
|
||||||
hostUrl
|
mirroredHost
|
||||||
)
|
)
|
||||||
).document.selectFirst("div.code_wrap code")?.text()
|
).document.selectFirst("div.code_wrap code")?.text()
|
||||||
}
|
}
|
||||||
|
|
27
Nimegami/build.gradle.kts
Normal file
27
Nimegami/build.gradle.kts
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
// use an integer for version numbers
|
||||||
|
version = 1
|
||||||
|
|
||||||
|
|
||||||
|
cloudstream {
|
||||||
|
language = "id"
|
||||||
|
// All of these properties are optional, you can safely remove them
|
||||||
|
|
||||||
|
// description = "Lorem Ipsum"
|
||||||
|
authors = listOf("Hexated")
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Status int as the following:
|
||||||
|
* 0: Down
|
||||||
|
* 1: Ok
|
||||||
|
* 2: Slow
|
||||||
|
* 3: Beta only
|
||||||
|
* */
|
||||||
|
status = 1 // will be 3 if unspecified
|
||||||
|
tvTypes = listOf(
|
||||||
|
"AnimeMovie",
|
||||||
|
"Anime",
|
||||||
|
"OVA",
|
||||||
|
)
|
||||||
|
|
||||||
|
iconUrl = "https://www.google.com/s2/favicons?domain=nimegami.id&sz=%size%"
|
||||||
|
}
|
2
Nimegami/src/main/AndroidManifest.xml
Normal file
2
Nimegami/src/main/AndroidManifest.xml
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<manifest package="com.hexated"/>
|
60
Nimegami/src/main/kotlin/com/hexated/Extractors.kt
Normal file
60
Nimegami/src/main/kotlin/com/hexated/Extractors.kt
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
package com.hexated
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty
|
||||||
|
import com.lagradost.cloudstream3.SubtitleFile
|
||||||
|
import com.lagradost.cloudstream3.app
|
||||||
|
import com.lagradost.cloudstream3.utils.ExtractorApi
|
||||||
|
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||||
|
import com.lagradost.cloudstream3.utils.Qualities
|
||||||
|
|
||||||
|
open class Mitedrive : ExtractorApi() {
|
||||||
|
override val name = "Mitedrive"
|
||||||
|
override val mainUrl = "https://mitedrive.com"
|
||||||
|
override val requiresReferer = false
|
||||||
|
|
||||||
|
override suspend fun getUrl(
|
||||||
|
url: String,
|
||||||
|
referer: String?,
|
||||||
|
subtitleCallback: (SubtitleFile) -> Unit,
|
||||||
|
callback: (ExtractorLink) -> Unit
|
||||||
|
) {
|
||||||
|
val id = url.substringAfterLast("/")
|
||||||
|
val video = app.post(
|
||||||
|
"$mainUrl/api/generate",
|
||||||
|
referer = "$mainUrl/",
|
||||||
|
data = mapOf(
|
||||||
|
"short_url" to id
|
||||||
|
)
|
||||||
|
).parsedSafe<Responses>()?.data?.url
|
||||||
|
|
||||||
|
val 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,
|
||||||
|
)
|
||||||
|
|
||||||
|
callback.invoke(
|
||||||
|
ExtractorLink(
|
||||||
|
this.name,
|
||||||
|
this.name,
|
||||||
|
video ?: return,
|
||||||
|
"$mainUrl/",
|
||||||
|
Qualities.Unknown.value,
|
||||||
|
headers = headers
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
data class Data(
|
||||||
|
@JsonProperty("url") val url: String? = null,
|
||||||
|
)
|
||||||
|
|
||||||
|
data class Responses(
|
||||||
|
@JsonProperty("data") val data: Data? = null,
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
197
Nimegami/src/main/kotlin/com/hexated/Nimegami.kt
Normal file
197
Nimegami/src/main/kotlin/com/hexated/Nimegami.kt
Normal file
|
@ -0,0 +1,197 @@
|
||||||
|
package com.hexated
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty
|
||||||
|
import com.lagradost.cloudstream3.*
|
||||||
|
import com.lagradost.cloudstream3.utils.*
|
||||||
|
import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson
|
||||||
|
import org.jsoup.nodes.Element
|
||||||
|
import org.jsoup.select.Elements
|
||||||
|
import java.net.URI
|
||||||
|
|
||||||
|
class Nimegami : MainAPI() {
|
||||||
|
override var mainUrl = "https://nimegami.id"
|
||||||
|
override var name = "Nimegami"
|
||||||
|
override val hasMainPage = true
|
||||||
|
override var lang = "id"
|
||||||
|
override val supportedTypes = setOf(
|
||||||
|
TvType.Anime,
|
||||||
|
TvType.AnimeMovie,
|
||||||
|
TvType.OVA
|
||||||
|
)
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun getType(t: String): TvType {
|
||||||
|
return if (t.contains("OVA", true) || t.contains("Special", true)) TvType.OVA
|
||||||
|
else if (t.contains("Movie", true)) TvType.AnimeMovie
|
||||||
|
else TvType.Anime
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getStatus(t: String?): ShowStatus {
|
||||||
|
return when {
|
||||||
|
t?.contains("On-Going", true) == true -> ShowStatus.Ongoing
|
||||||
|
else -> ShowStatus.Completed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override val mainPage = mainPageOf(
|
||||||
|
"" to "Updated Anime",
|
||||||
|
"/type/tv" to "Anime",
|
||||||
|
"/type/movie" to "Movie",
|
||||||
|
"/type/ona" to "ONA",
|
||||||
|
"/type/live-action" to "Live Action",
|
||||||
|
)
|
||||||
|
|
||||||
|
override suspend fun getMainPage(
|
||||||
|
page: Int,
|
||||||
|
request: MainPageRequest
|
||||||
|
): HomePageResponse {
|
||||||
|
val document = app.get("$mainUrl${request.data}/page/$page").document
|
||||||
|
val home = document.select("div.post-article article, div.archive article").mapNotNull {
|
||||||
|
it.toSearchResult()
|
||||||
|
}
|
||||||
|
return newHomePageResponse(
|
||||||
|
list = HomePageList(
|
||||||
|
name = request.name,
|
||||||
|
list = home,
|
||||||
|
isHorizontalImages = request.name != "Updated Anime"
|
||||||
|
),
|
||||||
|
hasNext = true
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun Element.toSearchResult(): AnimeSearchResponse? {
|
||||||
|
val href = fixUrl(this.selectFirst("a")!!.attr("href"))
|
||||||
|
val title = this.selectFirst("h2 a")?.text() ?: return null
|
||||||
|
val posterUrl = (this.selectFirst("noscript img") ?: this.selectFirst("img"))?.attr("src")
|
||||||
|
val episode = this.selectFirst("ul li:contains(Episode), div.eps-archive")?.ownText()
|
||||||
|
?.filter { it.isDigit() }?.toIntOrNull()
|
||||||
|
|
||||||
|
return newAnimeSearchResponse(title, href, TvType.Anime) {
|
||||||
|
this.posterUrl = posterUrl
|
||||||
|
addSub(episode)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun search(query: String): List<SearchResponse> {
|
||||||
|
return app.get("$mainUrl/?s=$query&post_type=post").document.select("div.archive article")
|
||||||
|
.mapNotNull {
|
||||||
|
it.toSearchResult()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun load(url: String): LoadResponse {
|
||||||
|
val document = app.get(url).document
|
||||||
|
|
||||||
|
val table = document.select("div#Info table tbody")
|
||||||
|
val title = table.getContent("Judul :").text()
|
||||||
|
val poster = document.selectFirst("div.coverthumbnail img")?.attr("src")
|
||||||
|
val bgPoster = document.selectFirst("div.thumbnail-a img")?.attr("src")
|
||||||
|
val tags = table.getContent("Kategori").select("a").map { it.text() }
|
||||||
|
|
||||||
|
val year = table.getContent("Musim / Rilis").text().filter { it.isDigit() }.toIntOrNull()
|
||||||
|
val status = getStatus(document.selectFirst("h1[itemprop=headline]")?.text())
|
||||||
|
val type = table.getContent("Type").text()
|
||||||
|
val description = document.select("div#Sinopsis p").text().trim()
|
||||||
|
|
||||||
|
|
||||||
|
val episodes = document.select("div.list_eps_stream li")
|
||||||
|
.mapNotNull {
|
||||||
|
val name = it.text()
|
||||||
|
val link = it.attr("data")
|
||||||
|
Episode(link, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
val recommendations = document.select("div#randomList > a").mapNotNull {
|
||||||
|
val epHref = it.attr("href")
|
||||||
|
val epTitle = it.select("h5.sidebar-title-h5.px-2.py-2").text()
|
||||||
|
val epPoster = it.select(".product__sidebar__view__item.set-bg").attr("data-setbg")
|
||||||
|
|
||||||
|
newAnimeSearchResponse(epTitle, epHref, TvType.Anime) {
|
||||||
|
this.posterUrl = epPoster
|
||||||
|
addDubStatus(dubExist = false, subExist = true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return newAnimeLoadResponse(title, url, getType(type)) {
|
||||||
|
engName = title
|
||||||
|
posterUrl = poster
|
||||||
|
backgroundPosterUrl = bgPoster
|
||||||
|
this.year = year
|
||||||
|
addEpisodes(DubStatus.Subbed, episodes)
|
||||||
|
showStatus = status
|
||||||
|
plot = description
|
||||||
|
this.tags = tags
|
||||||
|
this.recommendations = recommendations
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun loadLinks(
|
||||||
|
data: String,
|
||||||
|
isCasting: Boolean,
|
||||||
|
subtitleCallback: (SubtitleFile) -> Unit,
|
||||||
|
callback: (ExtractorLink) -> Unit
|
||||||
|
): Boolean {
|
||||||
|
|
||||||
|
tryParseJson<ArrayList<Sources>>(base64Decode(data))?.map { sources ->
|
||||||
|
sources.url?.apmap { url ->
|
||||||
|
loadFixedExtractor(url.fixIframe(), sources.format, "$mainUrl/", subtitleCallback, callback)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun loadFixedExtractor(
|
||||||
|
url: String,
|
||||||
|
quality: String?,
|
||||||
|
referer: String? = null,
|
||||||
|
subtitleCallback: (SubtitleFile) -> Unit,
|
||||||
|
callback: (ExtractorLink) -> Unit
|
||||||
|
) {
|
||||||
|
loadExtractor(url, referer, subtitleCallback) { link ->
|
||||||
|
callback.invoke(
|
||||||
|
ExtractorLink(
|
||||||
|
link.name,
|
||||||
|
link.name,
|
||||||
|
link.url,
|
||||||
|
link.referer,
|
||||||
|
getQualityFromName(quality),
|
||||||
|
link.isM3u8,
|
||||||
|
link.headers,
|
||||||
|
link.extractorData
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getBaseUrl(url: String): String {
|
||||||
|
return URI(url).let {
|
||||||
|
"${it.scheme}://${it.host}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun Elements.getContent(css: String) : Elements {
|
||||||
|
return this.select("tr:contains($css) td:last-child")
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun String.fixIframe() : String {
|
||||||
|
val url = base64Decode(this.substringAfter("url=").substringAfter("id="))
|
||||||
|
val host = getBaseUrl(url)
|
||||||
|
return when {
|
||||||
|
url.contains("hxfile") -> {
|
||||||
|
val id = url.substringAfterLast("/")
|
||||||
|
"$host/embed-$id.html"
|
||||||
|
}
|
||||||
|
else -> fixUrl(url)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data class Sources(
|
||||||
|
@JsonProperty("format") val format: String? = null,
|
||||||
|
@JsonProperty("url") val url: ArrayList<String>? = arrayListOf(),
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
15
Nimegami/src/main/kotlin/com/hexated/NimegamiPlugin.kt
Normal file
15
Nimegami/src/main/kotlin/com/hexated/NimegamiPlugin.kt
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
|
||||||
|
package com.hexated
|
||||||
|
|
||||||
|
import com.lagradost.cloudstream3.plugins.CloudstreamPlugin
|
||||||
|
import com.lagradost.cloudstream3.plugins.Plugin
|
||||||
|
import android.content.Context
|
||||||
|
|
||||||
|
@CloudstreamPlugin
|
||||||
|
class NimegamiPlugin: Plugin() {
|
||||||
|
override fun load(context: Context) {
|
||||||
|
// All providers should be added in this manner. Please don't edit the providers list directly.
|
||||||
|
registerMainAPI(Nimegami())
|
||||||
|
registerExtractorAPI(Mitedrive())
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
// use an integer for version numbers
|
// use an integer for version numbers
|
||||||
version = 15
|
version = 16
|
||||||
|
|
||||||
|
|
||||||
cloudstream {
|
cloudstream {
|
||||||
|
|
|
@ -11,7 +11,7 @@ import org.jsoup.nodes.Element
|
||||||
import java.net.URI
|
import java.net.URI
|
||||||
|
|
||||||
class NontonAnimeIDProvider : MainAPI() {
|
class NontonAnimeIDProvider : MainAPI() {
|
||||||
override var mainUrl = "https://nontonanimeid.bio"
|
override var mainUrl = "https://nontonanimeid.lol"
|
||||||
override var name = "NontonAnimeID"
|
override var name = "NontonAnimeID"
|
||||||
override val hasQuickSearch = false
|
override val hasQuickSearch = false
|
||||||
override val hasMainPage = true
|
override val hasMainPage = true
|
||||||
|
|
247
Phim1080/src/main/kotlin/com/hexated/Phim1080Provider.kt
Normal file
247
Phim1080/src/main/kotlin/com/hexated/Phim1080Provider.kt
Normal file
|
@ -0,0 +1,247 @@
|
||||||
|
package com.hexated
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty
|
||||||
|
import com.lagradost.cloudstream3.*
|
||||||
|
import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer
|
||||||
|
import com.lagradost.cloudstream3.utils.*
|
||||||
|
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||||
|
import org.jsoup.nodes.Element
|
||||||
|
|
||||||
|
class Phim1080Provider : MainAPI() {
|
||||||
|
override var mainUrl = "https://xem1080.com"
|
||||||
|
override var name = "Phim1080"
|
||||||
|
override val hasMainPage = true
|
||||||
|
override var lang = "vi"
|
||||||
|
override val hasDownloadSupport = true
|
||||||
|
override val supportedTypes = setOf(
|
||||||
|
TvType.Movie,
|
||||||
|
TvType.TvSeries,
|
||||||
|
TvType.Anime,
|
||||||
|
TvType.AsianDrama
|
||||||
|
)
|
||||||
|
|
||||||
|
private fun encodeString(e: String, t: Int): String {
|
||||||
|
var a = ""
|
||||||
|
for (element in e) {
|
||||||
|
val r = element.code
|
||||||
|
val o = r xor t
|
||||||
|
a += o.toChar()
|
||||||
|
}
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
|
||||||
|
override val mainPage = mainPageOf(
|
||||||
|
"$mainUrl/phim-de-cu?page=" to "Phim Đề Cử",
|
||||||
|
"$mainUrl/the-loai/hoat-hinh?page=" to "Phim Hoạt Hình",
|
||||||
|
"$mainUrl/phim-chieu-rap?page=" to "Phim Chiếu Rạp",
|
||||||
|
"$mainUrl/phim-bo?page=" to "Phim Bộ",
|
||||||
|
"$mainUrl/phim-le?page=" to "Phim Lẻ",
|
||||||
|
"$mainUrl/bang-xep-hang?page=" to "Bảng Xếp Hạng",
|
||||||
|
"$mainUrl/bo-suu-tap/disney-plus?page=" to "Disney+",
|
||||||
|
"$mainUrl/bo-suu-tap/netflix-original?page=" to "Netflix",
|
||||||
|
"$mainUrl/hom-nay-xem-gi?page=" to "Hôm Nay Xem Gì",
|
||||||
|
"$mainUrl/phim-sap-chieu?page=" to "Phim Sắp Chiếu",
|
||||||
|
)
|
||||||
|
|
||||||
|
override suspend fun getMainPage(
|
||||||
|
page: Int,
|
||||||
|
request: MainPageRequest
|
||||||
|
): HomePageResponse {
|
||||||
|
val document = app.get(request.data + page).document
|
||||||
|
val home = document.select("div.tray-item").mapNotNull {
|
||||||
|
it.toSearchResult()
|
||||||
|
}
|
||||||
|
return newHomePageResponse(
|
||||||
|
list = HomePageList(
|
||||||
|
name = request.name,
|
||||||
|
list = home,
|
||||||
|
),
|
||||||
|
hasNext = true
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun Element.toSearchResult(): SearchResponse {
|
||||||
|
val title = this.selectFirst("div.tray-item-title")?.text()?.trim().toString()
|
||||||
|
val href = fixUrl(this.selectFirst("a")!!.attr("href"))
|
||||||
|
val posterUrl = this.selectFirst("img")!!.attr("data-src")
|
||||||
|
val temp = this.select("div.tray-film-likes").text()
|
||||||
|
return if (temp.contains("/")) {
|
||||||
|
val episode = Regex("((\\d+)\\s)").find(temp)?.groupValues?.map { num ->
|
||||||
|
num.replace(Regex("\\s"), "")
|
||||||
|
}?.distinct()?.firstOrNull()?.toIntOrNull()
|
||||||
|
newAnimeSearchResponse(title, href, TvType.TvSeries) {
|
||||||
|
this.posterUrl = posterUrl
|
||||||
|
addSub(episode)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
val quality = this.select("span.tray-item-quality").text().replace("FHD", "HD").trim()
|
||||||
|
newMovieSearchResponse(title, href, TvType.Movie) {
|
||||||
|
this.posterUrl = posterUrl
|
||||||
|
addQuality(quality)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun search(query: String): List<SearchResponse> {
|
||||||
|
val link = "$mainUrl/tim-kiem/$query"
|
||||||
|
val document = app.get(link).document
|
||||||
|
|
||||||
|
return document.select("div.tray-item").map {
|
||||||
|
it.toSearchResult()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun load( url: String ): LoadResponse {
|
||||||
|
val document = app.get(
|
||||||
|
url = url,
|
||||||
|
referer = "$mainUrl/",
|
||||||
|
headers = mapOf(
|
||||||
|
"Sec-Ch-Ua-Mobile" to "?1",
|
||||||
|
"Sec-Ch-Ua-Platform" to "\"Android\"",
|
||||||
|
"User-Agent" to "Mozilla/5.0 (Linux; Android 10; SM-G981B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.162 Mobile Safari/537.36 Edg/114.0.0.0",
|
||||||
|
)
|
||||||
|
).document
|
||||||
|
val fId = document.select("div.container").attr("data-id")
|
||||||
|
val filmInfo = app.get(
|
||||||
|
"$mainUrl/api/v2/films/$fId",
|
||||||
|
referer = url,
|
||||||
|
headers = mapOf(
|
||||||
|
"Content-Type" to "application/json",
|
||||||
|
"X-Requested-With" to "XMLHttpRequest"
|
||||||
|
)
|
||||||
|
).parsedSafe<FilmInfo>()
|
||||||
|
val title = filmInfo?.name?.trim().toString()
|
||||||
|
val poster = filmInfo?.thumbnail
|
||||||
|
val background = filmInfo?.poster
|
||||||
|
val slug = filmInfo?.slug
|
||||||
|
val link = "$mainUrl/$slug"
|
||||||
|
val tags = document.select("div.film-content div.film-info-genre:nth-child(7) a").map { it.text() }
|
||||||
|
val year = filmInfo?.year
|
||||||
|
val tvType = if (document.select("div.episode-group-tab").isNotEmpty()) TvType.TvSeries else TvType.Movie
|
||||||
|
val description = document.select("div.film-info-description").text().trim()
|
||||||
|
val comingSoon = document.select("button.direction-trailer").isNotEmpty()
|
||||||
|
val trailerCode = filmInfo?.trailer?.original?.id
|
||||||
|
val trailer = "https://www.youtube.com/embed/$trailerCode"
|
||||||
|
val recommendations = document.select("section.tray.index.related div.tray-content.carousel div.tray-item").map {
|
||||||
|
it.toSearchResult()
|
||||||
|
}
|
||||||
|
|
||||||
|
return if (tvType == TvType.TvSeries) {
|
||||||
|
val epsInfo = app.get(
|
||||||
|
"$mainUrl/api/v2/films/$fId/episodes?sort=name",
|
||||||
|
referer = link,
|
||||||
|
headers = mapOf(
|
||||||
|
"Content-Type" to "application/json",
|
||||||
|
"X-Requested-With" to "XMLHttpRequest",
|
||||||
|
)
|
||||||
|
).parsedSafe<MediaDetailEpisodes>()?.eps?.map { ep ->
|
||||||
|
Episode(
|
||||||
|
data = fixUrl(ep.link.toString()),
|
||||||
|
name = ep.detailname,
|
||||||
|
episode = ep.episodeNumber,
|
||||||
|
)
|
||||||
|
} ?: listOf()
|
||||||
|
newTvSeriesLoadResponse(title, url, TvType.TvSeries, epsInfo) {
|
||||||
|
this.posterUrl = poster
|
||||||
|
this.backgroundPosterUrl = background
|
||||||
|
this.year = year
|
||||||
|
this.plot = description
|
||||||
|
this.tags = tags
|
||||||
|
this.comingSoon = comingSoon
|
||||||
|
addTrailer(trailer)
|
||||||
|
this.recommendations = recommendations
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
newMovieLoadResponse(title, url, TvType.Movie, link) {
|
||||||
|
this.posterUrl = poster
|
||||||
|
this.backgroundPosterUrl = background
|
||||||
|
this.year = year
|
||||||
|
this.plot = description
|
||||||
|
this.tags = tags
|
||||||
|
this.comingSoon = comingSoon
|
||||||
|
addTrailer(trailer)
|
||||||
|
this.recommendations = recommendations
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun loadLinks(
|
||||||
|
data: String,
|
||||||
|
isCasting: Boolean,
|
||||||
|
subtitleCallback: (SubtitleFile) -> Unit,
|
||||||
|
callback: (ExtractorLink) -> Unit
|
||||||
|
): Boolean {
|
||||||
|
|
||||||
|
val document = app.get(data).document
|
||||||
|
val fId = document.select("div.container").attr("data-id")
|
||||||
|
val epId = document.select("div.container").attr("data-episode-id")
|
||||||
|
val doc = app.get(
|
||||||
|
"$mainUrl/api/v2/films/$fId/episodes/$epId",
|
||||||
|
referer = data,
|
||||||
|
headers = mapOf(
|
||||||
|
"Content-Type" to "application/json",
|
||||||
|
"cookie" to "xem1080=%3D",
|
||||||
|
"X-Requested-With" to "XMLHttpRequest"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
val source = doc.text.substringAfter(":{\"hls\":\"").substringBefore("\"},")
|
||||||
|
val link = encodeString(source, 69)
|
||||||
|
callback.invoke(
|
||||||
|
ExtractorLink(
|
||||||
|
"HS",
|
||||||
|
"HS",
|
||||||
|
link,
|
||||||
|
referer = data,
|
||||||
|
quality = Qualities.Unknown.value,
|
||||||
|
isM3u8 = true,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
val subId = doc.parsedSafe<Media>()?.subtitle?.vi
|
||||||
|
val isSubIdEmpty = subId.isNullOrBlank()
|
||||||
|
if (!isSubIdEmpty) {
|
||||||
|
subtitleCallback.invoke(
|
||||||
|
SubtitleFile(
|
||||||
|
"Vietnamese",
|
||||||
|
"$mainUrl/subtitle/$subId.vtt"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
data class FilmInfo(
|
||||||
|
@JsonProperty("name") val name: String? = null,
|
||||||
|
@JsonProperty("poster") val poster: String? = null,
|
||||||
|
@JsonProperty("thumbnail") val thumbnail: String? = null,
|
||||||
|
@JsonProperty("slug") val slug: String? = null,
|
||||||
|
@JsonProperty("year") val year: Int? = null,
|
||||||
|
@JsonProperty("trailer") val trailer: TrailerInfo? = null,
|
||||||
|
)
|
||||||
|
|
||||||
|
data class TrailerInfo(
|
||||||
|
@JsonProperty("original") val original: TrailerKey? = null,
|
||||||
|
)
|
||||||
|
|
||||||
|
data class TrailerKey(
|
||||||
|
@JsonProperty("id") val id: String? = null,
|
||||||
|
)
|
||||||
|
|
||||||
|
data class MediaDetailEpisodes(
|
||||||
|
@JsonProperty("data") val eps: ArrayList<Episodes>? = arrayListOf(),
|
||||||
|
)
|
||||||
|
|
||||||
|
data class Episodes(
|
||||||
|
@JsonProperty("link") val link: String? = null,
|
||||||
|
@JsonProperty("detail_name") val detailname: String? = null,
|
||||||
|
@JsonProperty("name") val episodeNumber: Int? = null,
|
||||||
|
)
|
||||||
|
|
||||||
|
data class Media(
|
||||||
|
@JsonProperty("subtitle") val subtitle: SubInfo? = null,
|
||||||
|
)
|
||||||
|
|
||||||
|
data class SubInfo(
|
||||||
|
@JsonProperty("vi") val vi: String? = null,
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
|
@ -6,9 +6,9 @@ import com.lagradost.cloudstream3.plugins.Plugin
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
|
||||||
@CloudstreamPlugin
|
@CloudstreamPlugin
|
||||||
class NgefilmPlugin: Plugin() {
|
class Phim1080ProviderPlugin: Plugin() {
|
||||||
override fun load(context: Context) {
|
override fun load(context: Context) {
|
||||||
// All providers should be added in this manner. Please don't edit the providers list directly.
|
// All providers should be added in this manner. Please don't edit the providers list directly.
|
||||||
registerMainAPI(Ngefilm())
|
registerMainAPI(Phim1080Provider())
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,12 +1,12 @@
|
||||||
// use an integer for version numbers
|
// use an integer for version numbers
|
||||||
version = 6
|
version = 7
|
||||||
|
|
||||||
|
|
||||||
cloudstream {
|
cloudstream {
|
||||||
language = "id"
|
language = "id"
|
||||||
// All of these properties are optional, you can safely remove them
|
// All of these properties are optional, you can safely remove them
|
||||||
|
|
||||||
// description = "Lorem Ipsum"
|
description = "Include: Cgvindo, Kitanonton"
|
||||||
authors = listOf("Hexated")
|
authors = listOf("Hexated")
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
9
RebahinProvider/src/main/kotlin/com/hexated/Cgvindo.kt
Normal file
9
RebahinProvider/src/main/kotlin/com/hexated/Cgvindo.kt
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
package com.hexated
|
||||||
|
|
||||||
|
import com.lagradost.cloudstream3.TvType
|
||||||
|
|
||||||
|
class Cgvindo : RebahinProvider() {
|
||||||
|
override var mainUrl = "http://cgvindo.click"
|
||||||
|
override var name = "Cgvindo"
|
||||||
|
|
||||||
|
}
|
|
@ -13,11 +13,10 @@ import org.jsoup.nodes.Element
|
||||||
import java.net.URI
|
import java.net.URI
|
||||||
|
|
||||||
open class RebahinProvider : MainAPI() {
|
open class RebahinProvider : MainAPI() {
|
||||||
override var mainUrl = "http://104.237.198.198"
|
override var mainUrl = "http://179.43.163.50"
|
||||||
override var name = "Rebahin"
|
override var name = "Rebahin"
|
||||||
override val hasMainPage = true
|
override val hasMainPage = true
|
||||||
override var lang = "id"
|
override var lang = "id"
|
||||||
override val hasDownloadSupport = true
|
|
||||||
open var mainServer = "http://172.96.161.72"
|
open var mainServer = "http://172.96.161.72"
|
||||||
override val supportedTypes = setOf(
|
override val supportedTypes = setOf(
|
||||||
TvType.Movie,
|
TvType.Movie,
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
package com.hexated
|
package com.hexated
|
||||||
|
|
||||||
import com.lagradost.cloudstream3.plugins.CloudstreamPlugin
|
import com.lagradost.cloudstream3.plugins.CloudstreamPlugin
|
||||||
|
@ -11,5 +10,6 @@ class RebahinProviderPlugin: Plugin() {
|
||||||
// All providers should be added in this manner. Please don't edit the providers list directly.
|
// All providers should be added in this manner. Please don't edit the providers list directly.
|
||||||
registerMainAPI(RebahinProvider())
|
registerMainAPI(RebahinProvider())
|
||||||
registerMainAPI(Kitanonton())
|
registerMainAPI(Kitanonton())
|
||||||
|
registerMainAPI(Cgvindo())
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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 = 144
|
version = 147
|
||||||
|
|
||||||
android {
|
android {
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
|
|
|
@ -930,10 +930,7 @@ object SoraExtractor : SoraStream() {
|
||||||
|
|
||||||
argamap(
|
argamap(
|
||||||
{
|
{
|
||||||
invokeZoro(aniId, episode, subtitleCallback, callback)
|
invokeAniwatch(malId, episode, subtitleCallback, callback)
|
||||||
},
|
|
||||||
{
|
|
||||||
invokeAnimeKaizoku(malId, epsTitle, season, episode, callback)
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
invokeBiliBili(aniId, episode, subtitleCallback, callback)
|
invokeBiliBili(aniId, episode, subtitleCallback, callback)
|
||||||
|
@ -1004,28 +1001,26 @@ object SoraExtractor : SoraStream() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun invokeZoro(
|
private suspend fun invokeAniwatch(
|
||||||
aniId: Int? = null,
|
malId: Int? = null,
|
||||||
episode: Int? = null,
|
episode: Int? = null,
|
||||||
subtitleCallback: (SubtitleFile) -> Unit,
|
subtitleCallback: (SubtitleFile) -> Unit,
|
||||||
callback: (ExtractorLink) -> Unit
|
callback: (ExtractorLink) -> Unit
|
||||||
) {
|
) {
|
||||||
val animeId =
|
|
||||||
app.get("https://raw.githubusercontent.com/MALSync/MAL-Sync-Backup/master/data/anilist/anime/${aniId ?: return}.json")
|
|
||||||
.parsedSafe<MALSyncResponses>()?.pages?.zoro?.keys?.map { it }
|
|
||||||
val headers = mapOf(
|
val headers = mapOf(
|
||||||
"X-Requested-With" to "XMLHttpRequest",
|
"X-Requested-With" to "XMLHttpRequest",
|
||||||
)
|
)
|
||||||
|
val animeId = app.get("$malsyncAPI/mal/anime/${malId ?: return}").parsedSafe<MALSyncResponses>()?.sites?.zoro?.keys?.map { it }
|
||||||
animeId?.apmap { id ->
|
animeId?.apmap { id ->
|
||||||
val episodeId = app.get("$zoroAPI/ajax/episode/list/${id ?: return@apmap}", headers = headers)
|
val episodeId = app.get("$aniwatchAPI/ajax/v2/episode/list/${id ?: return@apmap}", headers = headers)
|
||||||
.parsedSafe<ZoroResponses>()?.html?.let {
|
.parsedSafe<AniwatchResponses>()?.html?.let {
|
||||||
Jsoup.parse(it)
|
Jsoup.parse(it)
|
||||||
}?.select("div.ss-list a")?.find { it.attr("data-number") == "${episode ?: 1}" }
|
}?.select("div.ss-list a")?.find { it.attr("data-number") == "${episode ?: 1}" }
|
||||||
?.attr("data-id")
|
?.attr("data-id")
|
||||||
|
|
||||||
val servers =
|
val servers =
|
||||||
app.get("$zoroAPI/ajax/episode/servers?episodeId=${episodeId ?: return@apmap}", headers = headers)
|
app.get("$aniwatchAPI/ajax/v2/episode/servers?episodeId=${episodeId ?: return@apmap}", headers = headers)
|
||||||
.parsedSafe<ZoroResponses>()?.html?.let { Jsoup.parse(it) }
|
.parsedSafe<AniwatchResponses>()?.html?.let { Jsoup.parse(it) }
|
||||||
?.select("div.item.server-item")?.map {
|
?.select("div.item.server-item")?.map {
|
||||||
Triple(
|
Triple(
|
||||||
it.text(),
|
it.text(),
|
||||||
|
@ -1035,22 +1030,21 @@ object SoraExtractor : SoraStream() {
|
||||||
}
|
}
|
||||||
|
|
||||||
servers?.apmap servers@{ server ->
|
servers?.apmap servers@{ server ->
|
||||||
val iframe =
|
val iframe = app.get("$aniwatchAPI/ajax/v2/episode/sources?id=${server.second ?: return@servers}", headers = headers)
|
||||||
app.get("$zoroAPI/ajax/episode/sources?id=${server.second ?: return@servers}", headers = headers)
|
.parsedSafe<AniwatchResponses>()?.link ?: return@servers
|
||||||
.parsedSafe<ZoroResponses>()?.link ?: return@servers
|
|
||||||
val audio = if (server.third == "sub") "Raw" else "English Dub"
|
val audio = if (server.third == "sub") "Raw" else "English Dub"
|
||||||
if (server.first.contains(Regex("Vidstreaming|MegaCloud|Vidcloud"))) {
|
if (server.first.contains(Regex("Vidstreaming|MegaCloud|Vidcloud"))) {
|
||||||
extractRabbitStream(
|
extractRabbitStream(
|
||||||
"${server.first} [$audio]",
|
"${server.first} [$audio]",
|
||||||
iframe,
|
iframe,
|
||||||
"$zoroAPI/",
|
"$aniwatchAPI/",
|
||||||
subtitleCallback,
|
subtitleCallback,
|
||||||
callback,
|
callback,
|
||||||
false,
|
false,
|
||||||
decryptKey = RabbitStream.getZoroKey()
|
decryptKey = RabbitStream.getZoroKey()
|
||||||
) { it }
|
) { it }
|
||||||
} else {
|
} else {
|
||||||
loadExtractor(iframe, "$zoroAPI/", subtitleCallback, callback)
|
loadExtractor(iframe, "$aniwatchAPI/", subtitleCallback, callback)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1491,7 +1485,13 @@ object SoraExtractor : SoraStream() {
|
||||||
extractGdflix(gdBotLink ?: return@apmap null)
|
extractGdflix(gdBotLink ?: return@apmap null)
|
||||||
}
|
}
|
||||||
type.contains("oiya") -> {
|
type.contains("oiya") -> {
|
||||||
extractOiya(fdLink ?: return@apmap null, qualities)
|
val oiyaLink = extractOiya(fdLink ?: return@apmap null, qualities)
|
||||||
|
if(oiyaLink?.contains("gdtot") == true) {
|
||||||
|
val gdBotLink = extractGdbot(oiyaLink)
|
||||||
|
extractGdflix(gdBotLink ?: return@apmap null)
|
||||||
|
} else {
|
||||||
|
oiyaLink
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
return@apmap null
|
return@apmap null
|
||||||
|
@ -2041,6 +2041,9 @@ object SoraExtractor : SoraStream() {
|
||||||
it.first.contains("/rip") -> {
|
it.first.contains("/rip") -> {
|
||||||
invokeSmashyRip(it.second, it.first, subtitleCallback, callback)
|
invokeSmashyRip(it.second, it.first, subtitleCallback, callback)
|
||||||
}
|
}
|
||||||
|
it.first.contains("/im.php") && !isAnime -> {
|
||||||
|
invokeSmashyIm(it.second, it.first, subtitleCallback, callback)
|
||||||
|
}
|
||||||
else -> return@apmap
|
else -> return@apmap
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2692,7 +2695,15 @@ object SoraExtractor : SoraStream() {
|
||||||
epsDoc.select("ul.group-links-list li:nth-child($episode) a").attr("data-embed-src")
|
epsDoc.select("ul.group-links-list li:nth-child($episode) a").attr("data-embed-src")
|
||||||
}
|
}
|
||||||
|
|
||||||
loadExtractor(iframe, ask4MoviesAPI, subtitleCallback, callback)
|
val iframeDoc = app.get(iframe, referer = "$ask4MoviesAPI/").text
|
||||||
|
val script = Regex("""eval\(function\(p,a,c,k,e,.*\)\)""").findAll(iframeDoc).lastOrNull()?.value
|
||||||
|
val unpacked = getAndUnpack(script ?: return)
|
||||||
|
val m3u8 = Regex("file:\\s*\"(.*?m3u8.*?)\"").find(unpacked)?.groupValues?.getOrNull(1)
|
||||||
|
M3u8Helper.generateM3u8(
|
||||||
|
"Ask4movie",
|
||||||
|
m3u8 ?: return,
|
||||||
|
mainUrl
|
||||||
|
).forEach(callback)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -336,16 +336,12 @@ data class VizcloudSources(
|
||||||
@JsonProperty("file") val file: String? = null,
|
@JsonProperty("file") val file: String? = null,
|
||||||
)
|
)
|
||||||
|
|
||||||
data class VizcloudMedia(
|
data class VizcloudResult(
|
||||||
@JsonProperty("sources") val sources: ArrayList<VizcloudSources>? = arrayListOf(),
|
@JsonProperty("sources") val sources: ArrayList<VizcloudSources>? = arrayListOf(),
|
||||||
)
|
)
|
||||||
|
|
||||||
data class VizcloudData(
|
|
||||||
@JsonProperty("media") val media: VizcloudMedia? = null,
|
|
||||||
)
|
|
||||||
|
|
||||||
data class VizcloudResponses(
|
data class VizcloudResponses(
|
||||||
@JsonProperty("data") val data: VizcloudData? = null,
|
@JsonProperty("result") val result: VizcloudResult? = null,
|
||||||
)
|
)
|
||||||
|
|
||||||
data class AnilistExternalLinks(
|
data class AnilistExternalLinks(
|
||||||
|
@ -405,15 +401,15 @@ data class CrunchyrollSourcesResponses(
|
||||||
@JsonProperty("meta") val meta: CrunchyrollMeta? = null,
|
@JsonProperty("meta") val meta: CrunchyrollMeta? = null,
|
||||||
)
|
)
|
||||||
|
|
||||||
data class MALSyncPages(
|
data class MALSyncSites(
|
||||||
@JsonProperty("Zoro") val zoro: HashMap<String?, HashMap<String, String?>>? = hashMapOf(),
|
@JsonProperty("Zoro") val zoro: HashMap<String?, HashMap<String, String?>>? = hashMapOf(),
|
||||||
)
|
)
|
||||||
|
|
||||||
data class MALSyncResponses(
|
data class MALSyncResponses(
|
||||||
@JsonProperty("Pages") val pages: MALSyncPages? = null,
|
@JsonProperty("Sites") val sites: MALSyncSites? = null,
|
||||||
)
|
)
|
||||||
|
|
||||||
data class ZoroResponses(
|
data class AniwatchResponses(
|
||||||
@JsonProperty("html") val html: String? = null,
|
@JsonProperty("html") val html: String? = null,
|
||||||
@JsonProperty("link") val link: String? = null,
|
@JsonProperty("link") val link: String? = null,
|
||||||
)
|
)
|
||||||
|
|
|
@ -16,7 +16,6 @@ import com.hexated.SoraExtractor.invokeMovieHab
|
||||||
import com.hexated.SoraExtractor.invokeNoverse
|
import com.hexated.SoraExtractor.invokeNoverse
|
||||||
import com.hexated.SoraExtractor.invokeSeries9
|
import com.hexated.SoraExtractor.invokeSeries9
|
||||||
import com.hexated.SoraExtractor.invokeVidSrc
|
import com.hexated.SoraExtractor.invokeVidSrc
|
||||||
import com.hexated.SoraExtractor.invokeXmovies
|
|
||||||
import com.lagradost.cloudstream3.*
|
import com.lagradost.cloudstream3.*
|
||||||
import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer
|
import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer
|
||||||
import com.lagradost.cloudstream3.metaproviders.TmdbProvider
|
import com.lagradost.cloudstream3.metaproviders.TmdbProvider
|
||||||
|
@ -100,7 +99,7 @@ open class SoraStream : TmdbProvider() {
|
||||||
const val filmxyAPI = "https://www.filmxy.vip"
|
const val filmxyAPI = "https://www.filmxy.vip"
|
||||||
const val kimcartoonAPI = "https://kimcartoon.li"
|
const val kimcartoonAPI = "https://kimcartoon.li"
|
||||||
const val xMovieAPI = "https://xemovies.to"
|
const val xMovieAPI = "https://xemovies.to"
|
||||||
const val zoroAPI = "https://kaido.to"
|
const val aniwatchAPI = "https://aniwatch.to"
|
||||||
const val crunchyrollAPI = "https://beta-api.crunchyroll.com"
|
const val crunchyrollAPI = "https://beta-api.crunchyroll.com"
|
||||||
const val kissKhAPI = "https://kisskh.co"
|
const val kissKhAPI = "https://kisskh.co"
|
||||||
const val lingAPI = "https://ling-online.net"
|
const val lingAPI = "https://ling-online.net"
|
||||||
|
@ -120,7 +119,7 @@ open class SoraStream : TmdbProvider() {
|
||||||
const val smashyStreamAPI = "https://embed.smashystream.com"
|
const val smashyStreamAPI = "https://embed.smashystream.com"
|
||||||
const val watchSomuchAPI = "https://watchsomuch.tv" // sub only
|
const val watchSomuchAPI = "https://watchsomuch.tv" // sub only
|
||||||
val gomoviesAPI = base64DecodeAPI("bQ==Y28=ZS4=aW4=bmw=LW8=ZXM=dmk=bW8=Z28=Ly8=czo=dHA=aHQ=")
|
val gomoviesAPI = base64DecodeAPI("bQ==Y28=ZS4=aW4=bmw=LW8=ZXM=dmk=bW8=Z28=Ly8=czo=dHA=aHQ=")
|
||||||
const val ask4MoviesAPI = "https://ask4movie.net"
|
const val ask4MoviesAPI = "https://ask4movie.nl"
|
||||||
const val biliBiliAPI = "https://api-vn.otakuz.live/server"
|
const val biliBiliAPI = "https://api-vn.otakuz.live/server"
|
||||||
const val watchOnlineAPI = "https://watchonline.ag"
|
const val watchOnlineAPI = "https://watchonline.ag"
|
||||||
const val nineTvAPI = "https://api.9animetv.live"
|
const val nineTvAPI = "https://api.9animetv.live"
|
||||||
|
|
|
@ -21,6 +21,7 @@ import com.lagradost.cloudstream3.APIHolder.getCaptchaToken
|
||||||
import com.lagradost.cloudstream3.APIHolder.unixTimeMS
|
import com.lagradost.cloudstream3.APIHolder.unixTimeMS
|
||||||
import com.lagradost.cloudstream3.mvvm.suspendSafeApiCall
|
import com.lagradost.cloudstream3.mvvm.suspendSafeApiCall
|
||||||
import com.lagradost.cloudstream3.utils.*
|
import com.lagradost.cloudstream3.utils.*
|
||||||
|
import com.lagradost.cloudstream3.utils.AppUtils.parseJson
|
||||||
import com.lagradost.cloudstream3.utils.AppUtils.toJson
|
import com.lagradost.cloudstream3.utils.AppUtils.toJson
|
||||||
import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson
|
import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson
|
||||||
import com.lagradost.cloudstream3.utils.Coroutines.ioSafe
|
import com.lagradost.cloudstream3.utils.Coroutines.ioSafe
|
||||||
|
@ -417,7 +418,7 @@ suspend fun invokeVizcloud(
|
||||||
) {
|
) {
|
||||||
val id = Regex("(?:/embed[-/]|/e/)([^?/]*)").find(url)?.groupValues?.getOrNull(1)
|
val id = Regex("(?:/embed[-/]|/e/)([^?/]*)").find(url)?.groupValues?.getOrNull(1)
|
||||||
app.get("$consumetHelper?query=${id ?: return}&action=vizcloud")
|
app.get("$consumetHelper?query=${id ?: return}&action=vizcloud")
|
||||||
.parsedSafe<VizcloudResponses>()?.data?.media?.sources?.map {
|
.parsedSafe<VizcloudResponses>()?.result?.sources?.map {
|
||||||
M3u8Helper.generateM3u8(
|
M3u8Helper.generateM3u8(
|
||||||
"Vizcloud",
|
"Vizcloud",
|
||||||
it.file ?: return@map,
|
it.file ?: return@map,
|
||||||
|
@ -563,6 +564,39 @@ suspend fun invokeSmashyRip(
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun invokeSmashyIm(
|
||||||
|
name: String,
|
||||||
|
url: String,
|
||||||
|
subtitleCallback: (SubtitleFile) -> Unit,
|
||||||
|
callback: (ExtractorLink) -> Unit,
|
||||||
|
) {
|
||||||
|
val script =
|
||||||
|
app.get(url).document.selectFirst("script:containsData(player =)")?.data() ?: return
|
||||||
|
|
||||||
|
val sources =
|
||||||
|
Regex("['\"]?file['\"]?:\\s*\"([^\"]+)").find(script)?.groupValues?.get(1) ?: return
|
||||||
|
val subtitles =
|
||||||
|
Regex("['\"]?subtitle['\"]?:\\s*\"([^\"]+)").find(script)?.groupValues?.get(1) ?: return
|
||||||
|
|
||||||
|
M3u8Helper.generateM3u8(
|
||||||
|
"Smashy [$name]",
|
||||||
|
sources,
|
||||||
|
""
|
||||||
|
).forEach(callback)
|
||||||
|
|
||||||
|
subtitles.split(",").map { sub ->
|
||||||
|
val lang = Regex("\\[(.*?)]").find(sub)?.groupValues?.getOrNull(1)?.trim()
|
||||||
|
val trimmedSubLink = sub.removePrefix("[$lang]").trim().substringAfter("?url=")
|
||||||
|
subtitleCallback.invoke(
|
||||||
|
SubtitleFile(
|
||||||
|
lang.takeIf { !it.isNullOrEmpty() } ?: return@map,
|
||||||
|
trimmedSubLink
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
suspend fun getDumpIdAndType(title: String?, year: Int?, season: Int?): Pair<String?, Int?> {
|
suspend fun getDumpIdAndType(title: String?, year: Int?, season: Int?): Pair<String?, Int?> {
|
||||||
val res = tryParseJson<DumpQuickSearchData>(
|
val res = tryParseJson<DumpQuickSearchData>(
|
||||||
queryApi(
|
queryApi(
|
||||||
|
@ -922,7 +956,7 @@ suspend fun searchWatchOnline(
|
||||||
}
|
}
|
||||||
|
|
||||||
//modified code from https://github.com/jmir1/aniyomi-extensions/blob/master/src/all/kamyroll/src/eu/kanade/tachiyomi/animeextension/all/kamyroll/AccessTokenInterceptor.kt
|
//modified code from https://github.com/jmir1/aniyomi-extensions/blob/master/src/all/kamyroll/src/eu/kanade/tachiyomi/animeextension/all/kamyroll/AccessTokenInterceptor.kt
|
||||||
fun getCrunchyrollToken(): Map<String, String> {
|
suspend fun getCrunchyrollToken(): Map<String, String> {
|
||||||
val client = app.baseClient.newBuilder()
|
val client = app.baseClient.newBuilder()
|
||||||
.proxy(Proxy(Proxy.Type.SOCKS, InetSocketAddress("cr-unblocker.us.to", 1080)))
|
.proxy(Proxy(Proxy.Type.SOCKS, InetSocketAddress("cr-unblocker.us.to", 1080)))
|
||||||
.build()
|
.build()
|
||||||
|
@ -942,7 +976,7 @@ fun getCrunchyrollToken(): Map<String, String> {
|
||||||
"Authorization" to "Basic ${BuildConfig.CRUNCHYROLL_BASIC_TOKEN}"
|
"Authorization" to "Basic ${BuildConfig.CRUNCHYROLL_BASIC_TOKEN}"
|
||||||
),
|
),
|
||||||
data = mapOf(
|
data = mapOf(
|
||||||
"refresh_token" to BuildConfig.CRUNCHYROLL_REFRESH_TOKEN,
|
"refresh_token" to app.get(BuildConfig.CRUNCHYROLL_REFRESH_TOKEN).text,
|
||||||
"grant_type" to "refresh_token",
|
"grant_type" to "refresh_token",
|
||||||
"scope" to "offline_access"
|
"scope" to "offline_access"
|
||||||
)
|
)
|
||||||
|
@ -1807,8 +1841,8 @@ object RabbitStream {
|
||||||
if (sources == null || encryptedMap.encrypted == false) {
|
if (sources == null || encryptedMap.encrypted == false) {
|
||||||
response.parsedSafe()
|
response.parsedSafe()
|
||||||
} else {
|
} else {
|
||||||
val decrypted =
|
val (realKey, encData) = extractRealKey(sources, decryptKey)
|
||||||
decryptMapped<List<Sources>>(sources, decryptKey)
|
val decrypted = decryptMapped<List<Sources>>(encData, realKey)
|
||||||
SourceObject(
|
SourceObject(
|
||||||
sources = decrypted,
|
sources = decrypted,
|
||||||
tracks = encryptedMap.tracks
|
tracks = encryptedMap.tracks
|
||||||
|
@ -1951,7 +1985,21 @@ object RabbitStream {
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun getZoroKey(): String {
|
suspend fun getZoroKey(): String {
|
||||||
return app.get("https://raw.githubusercontent.com/enimax-anime/key/e0/key.txt").text
|
return app.get("https://raw.githubusercontent.com/enimax-anime/key/e6/key.txt").text
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun extractRealKey(originalString: String?, stops: String) : Pair<String,String> {
|
||||||
|
val table = parseJson<List<List<Int>>>(stops)
|
||||||
|
val decryptedKey = StringBuilder()
|
||||||
|
var offset = 0
|
||||||
|
var encryptedString = originalString
|
||||||
|
|
||||||
|
table.forEach { (start, end) ->
|
||||||
|
decryptedKey.append(encryptedString?.substring(start - offset, end - offset))
|
||||||
|
encryptedString = encryptedString?.substring(0, start - offset) + encryptedString?.substring(end - offset)
|
||||||
|
offset += end - start
|
||||||
|
}
|
||||||
|
return decryptedKey.toString() to encryptedString.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
private inline fun <reified T> decryptMapped(input: String, key: String): T? {
|
private inline fun <reified T> decryptMapped(input: String, key: String): T? {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// use an integer for version numbers
|
// use an integer for version numbers
|
||||||
version = 14
|
version = 16
|
||||||
|
|
||||||
|
|
||||||
cloudstream {
|
cloudstream {
|
||||||
|
|
|
@ -19,8 +19,11 @@ open class TimefourTv : MainAPI() {
|
||||||
)
|
)
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val daddyUrl = "https://daddylive.watch"
|
const val daddyUrl = "https://daddylivehd.com"
|
||||||
val daddyHost: String = URI(daddyUrl).host.split(".").first()
|
val daddyHost: String = daddyUrl.getHost()
|
||||||
|
private fun String.getHost(): String {
|
||||||
|
return URI(this).host.substringBeforeLast(".").substringAfterLast(".")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override val mainPage = mainPageOf(
|
override val mainPage = mainPageOf(
|
||||||
|
|
|
@ -72,7 +72,7 @@ object TimefourTvExtractor : TimefourTv() {
|
||||||
return getSportLink(url)
|
return getSportLink(url)
|
||||||
}
|
}
|
||||||
|
|
||||||
if(url.contains(daddyHost)) {
|
if(url.contains(daddyHost, true)) {
|
||||||
mainServer = getBaseUrl(url)
|
mainServer = getBaseUrl(url)
|
||||||
return getFinalLink(app.get(url, referer = daddyUrl))
|
return getFinalLink(app.get(url, referer = daddyUrl))
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
// use an integer for version numbers
|
// use an integer for version numbers
|
||||||
version = 15
|
version = 17
|
||||||
|
|
||||||
|
|
||||||
cloudstream {
|
cloudstream {
|
||||||
language = "hi"
|
language = "hi"
|
||||||
// All of these properties are optional, you can safely remove them
|
// All of these properties are optional, you can safely remove them
|
||||||
|
|
||||||
// description = "Lorem Ipsum"
|
description = "Include: Watchomovies"
|
||||||
authors = listOf("Hexated")
|
authors = listOf("Hexated")
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
27
YomoviesProvider/src/main/kotlin/com/hexated/Watchomovies.kt
Normal file
27
YomoviesProvider/src/main/kotlin/com/hexated/Watchomovies.kt
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
package com.hexated
|
||||||
|
|
||||||
|
import com.lagradost.cloudstream3.LoadResponse
|
||||||
|
import com.lagradost.cloudstream3.TvType
|
||||||
|
import com.lagradost.cloudstream3.mainPageOf
|
||||||
|
|
||||||
|
class Watchomovies : YomoviesProvider() {
|
||||||
|
override var mainUrl = "https://watchomovies.mom"
|
||||||
|
override var name = "Watchomovies"
|
||||||
|
override var lang = "en"
|
||||||
|
override val supportedTypes = setOf(
|
||||||
|
TvType.NSFW,
|
||||||
|
)
|
||||||
|
|
||||||
|
override val mainPage = mainPageOf(
|
||||||
|
"most-favorites" to "Most Viewed",
|
||||||
|
"genre/xxx-scenes" to "XXX Scenes",
|
||||||
|
"genre/18" to "18+ Movies",
|
||||||
|
"genre/erotic-movies" to "Erotic Movies Movies",
|
||||||
|
"genre/parody" to "Parody Movies",
|
||||||
|
"genre/tv-shows" to "TV Shows Movies",
|
||||||
|
)
|
||||||
|
|
||||||
|
override suspend fun load(url: String): LoadResponse? {
|
||||||
|
return super.load(url).apply { this?.type = TvType.NSFW }
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,37 +9,32 @@ import com.lagradost.cloudstream3.utils.loadExtractor
|
||||||
import org.jsoup.nodes.Element
|
import org.jsoup.nodes.Element
|
||||||
import java.net.URI
|
import java.net.URI
|
||||||
|
|
||||||
class YomoviesProvider : MainAPI() {
|
open class YomoviesProvider : MainAPI() {
|
||||||
override var mainUrl = "https://yomovies.baby"
|
override var mainUrl = "https://yomovies.baby"
|
||||||
private var directUrl = mainUrl
|
private var directUrl = ""
|
||||||
override var name = "Yomovies"
|
override var name = "Yomovies"
|
||||||
override val hasMainPage = true
|
override val hasMainPage = true
|
||||||
override var lang = "hi"
|
override var lang = "hi"
|
||||||
override val hasDownloadSupport = true
|
|
||||||
override val supportedTypes = setOf(
|
override val supportedTypes = setOf(
|
||||||
TvType.Movie,
|
TvType.Movie,
|
||||||
TvType.TvSeries,
|
TvType.TvSeries,
|
||||||
)
|
)
|
||||||
|
|
||||||
override val mainPage = mainPageOf(
|
override val mainPage = mainPageOf(
|
||||||
"$mainUrl/most-favorites/page/" to "Most Viewed",
|
"most-favorites" to "Most Viewed",
|
||||||
"$mainUrl/genre/web-series/page/" to "Web Series Movies",
|
"genre/web-series" to "Web Series Movies",
|
||||||
"$mainUrl/genre/dual-audio/page/" to "Dual Audio Movies",
|
"genre/dual-audio" to "Dual Audio Movies",
|
||||||
"$mainUrl/genre/bollywood/page/" to "Bollywood Movies",
|
"genre/bollywood" to "Bollywood Movies",
|
||||||
"$mainUrl/genre/tv-shows/page/" to "TV Shows Movies",
|
"genre/tv-shows" to "TV Shows Movies",
|
||||||
"$mainUrl/genre/hollywood/page/" to "Hollywood Movies",
|
"genre/hollywood" to "Hollywood Movies",
|
||||||
"$mainUrl/series/page/" to "All TV Series",
|
"series" to "All TV Series",
|
||||||
)
|
)
|
||||||
|
|
||||||
override suspend fun getMainPage(
|
override suspend fun getMainPage(
|
||||||
page: Int,
|
page: Int,
|
||||||
request: MainPageRequest
|
request: MainPageRequest
|
||||||
): HomePageResponse {
|
): HomePageResponse {
|
||||||
val document = if (page == 1) {
|
val document = app.get("$mainUrl/${request.data}/page/$page").document
|
||||||
app.get(request.data.removeSuffix("page/")).document
|
|
||||||
} else {
|
|
||||||
app.get(request.data + page).document
|
|
||||||
}
|
|
||||||
val home = document.select("div.ml-item").mapNotNull {
|
val home = document.select("div.ml-item").mapNotNull {
|
||||||
it.toSearchResult()
|
it.toSearchResult()
|
||||||
}
|
}
|
||||||
|
@ -129,12 +124,6 @@ class YomoviesProvider : MainAPI() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getBaseUrl(url: String): String {
|
|
||||||
return URI(url).let {
|
|
||||||
"${it.scheme}://${it.host}"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun loadLinks(
|
override suspend fun loadLinks(
|
||||||
data: String,
|
data: String,
|
||||||
isCasting: Boolean,
|
isCasting: Boolean,
|
||||||
|
@ -175,4 +164,10 @@ class YomoviesProvider : MainAPI() {
|
||||||
return fixTitle(URI(this).host.substringBeforeLast(".").substringAfterLast("."))
|
return fixTitle(URI(this).host.substringBeforeLast(".").substringAfterLast("."))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun getBaseUrl(url: String): String {
|
||||||
|
return URI(url).let {
|
||||||
|
"${it.scheme}://${it.host}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,5 +10,6 @@ class YomoviesProviderPlugin: Plugin() {
|
||||||
override fun load(context: Context) {
|
override fun load(context: Context) {
|
||||||
// All providers should be added in this manner. Please don't edit the providers list directly.
|
// All providers should be added in this manner. Please don't edit the providers list directly.
|
||||||
registerMainAPI(YomoviesProvider())
|
registerMainAPI(YomoviesProvider())
|
||||||
|
registerMainAPI(Watchomovies())
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Add table
Add a link
Reference in a new issue