Merge remote-tracking branch 'OriginHexa/master' into update2

# Conflicts:
#	Movierulzhd/build.gradle.kts
#	Movierulzhd/src/main/kotlin/com/hexated/Movierulzhd.kt
This commit is contained in:
IndusAryan 2024-01-28 15:08:04 +05:30
commit 8215b17940
39 changed files with 350 additions and 548 deletions

View File

@ -54,7 +54,7 @@ jobs:
ZSHOW_API: ${{ secrets.ZSHOW_API }} ZSHOW_API: ${{ secrets.ZSHOW_API }}
SFMOVIES_API: ${{ secrets.SFMOVIES_API }} SFMOVIES_API: ${{ secrets.SFMOVIES_API }}
CINEMATV_API: ${{ secrets.CINEMATV_API }} CINEMATV_API: ${{ secrets.CINEMATV_API }}
OMOVIES_API: ${{ secrets.OMOVIES_API }} GHOSTX_API: ${{ secrets.GHOSTX_API }}
SUPERSTREAM_FIRST_API: ${{ secrets.SUPERSTREAM_FIRST_API }} SUPERSTREAM_FIRST_API: ${{ secrets.SUPERSTREAM_FIRST_API }}
SUPERSTREAM_SECOND_API: ${{ secrets.SUPERSTREAM_SECOND_API }} SUPERSTREAM_SECOND_API: ${{ secrets.SUPERSTREAM_SECOND_API }}
SUPERSTREAM_THIRD_API: ${{ secrets.SUPERSTREAM_THIRD_API }} SUPERSTREAM_THIRD_API: ${{ secrets.SUPERSTREAM_THIRD_API }}
@ -73,7 +73,7 @@ jobs:
echo ZSHOW_API=$ZSHOW_API >> local.properties echo ZSHOW_API=$ZSHOW_API >> local.properties
echo SFMOVIES_API=$SFMOVIES_API >> local.properties echo SFMOVIES_API=$SFMOVIES_API >> local.properties
echo CINEMATV_API=$CINEMATV_API >> local.properties echo CINEMATV_API=$CINEMATV_API >> local.properties
echo OMOVIES_API=$OMOVIES_API >> local.properties echo GHOSTX_API=$GHOSTX_API >> local.properties
echo SUPERSTREAM_FIRST_API=$SUPERSTREAM_FIRST_API >> local.properties echo SUPERSTREAM_FIRST_API=$SUPERSTREAM_FIRST_API >> local.properties
echo SUPERSTREAM_SECOND_API=$SUPERSTREAM_SECOND_API >> local.properties echo SUPERSTREAM_SECOND_API=$SUPERSTREAM_SECOND_API >> local.properties
echo SUPERSTREAM_THIRD_API=$SUPERSTREAM_THIRD_API >> local.properties echo SUPERSTREAM_THIRD_API=$SUPERSTREAM_THIRD_API >> local.properties

View File

@ -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 = 9 version = 10
android { android {
defaultConfig { defaultConfig {
@ -38,5 +38,5 @@ cloudstream {
"OVA", "OVA",
) )
iconUrl = "https://media.discordapp.net/attachments/1059306855865782282/1123970193274712096/Anichi.png" iconUrl = "https://cdn.discordapp.com/attachments/1109266606292488297/1200425504432472176/Anichi.png"
} }

View File

@ -1,6 +1,5 @@
package com.hexated package com.hexated
import com.hexated.AnichiExtractors.invokeExternalSources
import com.hexated.AnichiExtractors.invokeInternalSources import com.hexated.AnichiExtractors.invokeInternalSources
import com.lagradost.cloudstream3.* import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.LoadResponse.Companion.addActors import com.lagradost.cloudstream3.LoadResponse.Companion.addActors
@ -214,25 +213,12 @@ open class Anichi : MainAPI() {
val loadData = parseJson<AnichiLoadData>(data) val loadData = parseJson<AnichiLoadData>(data)
argamap( invokeInternalSources(
{ loadData.hash,
invokeInternalSources( loadData.dubStatus,
loadData.hash, loadData.episode,
loadData.dubStatus, subtitleCallback,
loadData.episode, callback
subtitleCallback,
callback
)
},
{
invokeExternalSources(
loadData.idMal,
loadData.dubStatus,
loadData.episode,
subtitleCallback,
callback
)
}
) )
return true return true
@ -245,7 +231,6 @@ open class Anichi : MainAPI() {
const val anilistApi = "https://graphql.anilist.co" const val anilistApi = "https://graphql.anilist.co"
const val jikanApi = "https://api.jikan.moe/v4" const val jikanApi = "https://api.jikan.moe/v4"
const val marinHost = "https://marin.moe"
private const val mainHash = "e42a4466d984b2c0a2cecae5dd13aa68867f634b16ee0f17b380047d14482406" private const val mainHash = "e42a4466d984b2c0a2cecae5dd13aa68867f634b16ee0f17b380047d14482406"
private const val popularHash = "31a117653812a2547fd981632e8c99fa8bf8a75c4ef1a77a1567ef1741a7ab9c" private const val popularHash = "31a117653812a2547fd981632e8c99fa8bf8a75c4ef1a77a1567ef1741a7ab9c"

View File

@ -121,67 +121,6 @@ object AnichiExtractors : Anichi() {
} }
} }
suspend fun invokeExternalSources(
idMal: Int? = null,
dubStatus: String,
episode: String,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit,
) {
val ids = app.get("https://api.malsync.moe/mal/anime/${idMal ?: return}")
.parsedSafe<MALSyncResponses>()?.sites
if (dubStatus == "sub") invokeMarin(ids?.marin?.keys?.firstOrNull(), episode, callback)
}
private suspend fun invokeMarin(
id: String? = null,
episode: String,
callback: (ExtractorLink) -> Unit
) {
val url = "$marinHost/anime/${id ?: return}/$episode"
val cookies = app.get(
"$marinHost/anime",
headers = mapOf(
"Cookie" to "__ddg1_=;__ddg2_=;"
),
referer = "$marinHost/anime",
).cookies.let {
decode(it["XSRF-TOKEN"].toString()) to decode(it["marin_session"].toString())
}
val json = app.get(
url,
headers = mapOf(
"Accept" to "text/html, application/xhtml+xml",
"Cookie" to "__ddg1=;__ddg2_=;XSRF-TOKEN=${cookies.first};marin_session=${cookies.second};",
"X-XSRF-TOKEN" to cookies.first
),
referer = "$marinHost/anime/$id"
).document.selectFirst("div#app")?.attr("data-page")
tryParseJson<MarinResponses>(json)?.props?.video?.data?.mirror?.map { video ->
callback.invoke(
ExtractorLink(
"Marin",
"Marin",
video.code?.file ?: return@map,
url,
video.code.height ?: Qualities.Unknown.value,
headers = mapOf(
"Accept" to "video/webm,video/ogg,video/*;q=0.9,application/ogg;q=0.7,audio/*;q=0.6,*/*;q=0.5",
"Accept-Language" to "en-US,en;q=0.5",
"Cookie" to "__ddg1=;__ddg2_=; XSRF-TOKEN=${cookies.first}; marin_session=${cookies.second};",
"Connection" to "keep-alive",
"Sec-Fetch-Dest" to "video",
"Sec-Fetch-Mode" to "cors",
"Sec-Fetch-Site" to "cross-site",
)
)
)
}
}
private suspend fun invokeGogo( private suspend fun invokeGogo(
link: String, link: String,
subtitleCallback: (SubtitleFile) -> Unit, subtitleCallback: (SubtitleFile) -> Unit,

View File

@ -240,7 +240,6 @@ data class PageStatus(
@JsonProperty("__typename") val _typename: String? = null @JsonProperty("__typename") val _typename: String? = null
) )
data class Recommendations( data class Recommendations(
@JsonProperty("anyCard") val anyCard: AnyCard? = null, @JsonProperty("anyCard") val anyCard: AnyCard? = null,
@JsonProperty("pageStatus") val pageStatus: PageStatus? = PageStatus(), @JsonProperty("pageStatus") val pageStatus: PageStatus? = PageStatus(),
@ -255,38 +254,4 @@ data class QueryPopular(
data class DataPopular( data class DataPopular(
@JsonProperty("queryPopular") val queryPopular: QueryPopular? = QueryPopular() @JsonProperty("queryPopular") val queryPopular: QueryPopular? = QueryPopular()
)
data class MALSyncSites(
@JsonProperty("Zoro") val zoro: HashMap<String?, HashMap<String, String?>>? = hashMapOf(),
@JsonProperty("Marin") val marin: HashMap<String?, HashMap<String, String?>>? = hashMapOf(),
)
data class MALSyncResponses(
@JsonProperty("Sites") val sites: MALSyncSites? = null,
)
data class MarinCode(
@JsonProperty("file") val file: String? = null,
@JsonProperty("height") val height: Int? = null,
)
data class MarinMirror(
@JsonProperty("code") val code: MarinCode? = null,
)
data class MarinData(
@JsonProperty("mirror") val mirror: ArrayList<MarinMirror>? = arrayListOf(),
)
data class MarinVideos(
@JsonProperty("data") val data: MarinData? = null,
)
data class MarinProps(
@JsonProperty("video") val video: MarinVideos? = null,
)
data class MarinResponses(
@JsonProperty("props") val props: MarinProps? = null,
) )

View File

@ -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 = 30 version = 31
android { android {
defaultConfig { defaultConfig {

View File

@ -10,7 +10,7 @@ import org.jsoup.nodes.Element
import java.net.URI import java.net.URI
open class Gomov : MainAPI() { open class Gomov : MainAPI() {
override var mainUrl = "https://gomov.bio" override var mainUrl = "https://gomov.co"
private var directUrl: String? = null private var directUrl: String? = null
override var name = "Gomov" override var name = "Gomov"
override val hasMainPage = true override val hasMainPage = true

View File

@ -3,7 +3,7 @@ package com.hexated
import com.lagradost.cloudstream3.mainPageOf import com.lagradost.cloudstream3.mainPageOf
class Ngefilm : Gomov() { class Ngefilm : Gomov() {
override var mainUrl = "https://tv3.ngefilm21.homes" override var mainUrl = "https://tv4.ngefilm21.homes"
override var name = "Ngefilm" override var name = "Ngefilm"
override val mainPage = mainPageOf( 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=movie&index&orderby&genre&movieyear&country&quality=" to "Movies Terbaru",

View File

@ -6,7 +6,7 @@ import com.lagradost.cloudstream3.TvSeriesLoadResponse
import com.lagradost.cloudstream3.* import com.lagradost.cloudstream3.*
class Pusatfilm : Gomov() { class Pusatfilm : Gomov() {
override var mainUrl = "https://pusatfilm21.vip" override var mainUrl = "https://pf21.vip"
override var name = "Pusatfilm" override var name = "Pusatfilm"
override val mainPage = mainPageOf( override val mainPage = mainPageOf(
"film-terbaru/page/%d/" to "Film Terbaru", "film-terbaru/page/%d/" to "Film Terbaru",

View File

@ -1,5 +1,5 @@
// use an integer for version numbers // use an integer for version numbers
version = 36 version = 39
cloudstream { cloudstream {

View File

@ -1,5 +1,5 @@
// use an integer for version numbers // use an integer for version numbers
version = 19 version = 20
cloudstream { cloudstream {

View File

@ -8,8 +8,8 @@ import com.lagradost.cloudstream3.utils.*
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
class LayarKacaProvider : MainAPI() { class LayarKacaProvider : MainAPI() {
override var mainUrl = "https://tv7.lk21official.wiki" override var mainUrl = "https://tv10.lk21official.wiki"
private var seriesUrl = "https://tv9.nontondrama.click" private var seriesUrl = "https://tv11.nontondrama.click"
override var name = "LayarKaca" override var name = "LayarKaca"
override val hasMainPage = true override val hasMainPage = true
override var lang = "id" override var lang = "id"

View File

@ -36,12 +36,16 @@ open class Streampai : ExtractorApi() {
val res = app.get(url, referer = referer).document val res = app.get(url, referer = referer).document
val data = res.selectFirst("script:containsData(player =)")?.data() ?: return val data = res.selectFirst("script:containsData(player =)")?.data() ?: return
val sources = data.substringAfter("sources: [").substringBefore("]").replace("\'", "\"") val sources = data.substringAfter("sources: [").substringBefore("]")
.addMarks("src") .addMarks("src")
.addMarks("type") .addMarks("type")
.addMarks("size") .addMarks("size")
.replace("\'", "\"") .replace("\'", "\"")
val tracks = data.substringAfter("tracks: [").substringBefore("]")
.replace("\'", "\"")
tryParseJson<List<Responses>>("[$sources]")?.forEach { tryParseJson<List<Responses>>("[$sources]")?.forEach {
callback.invoke( callback.invoke(
ExtractorLink( ExtractorLink(
@ -56,6 +60,15 @@ open class Streampai : ExtractorApi() {
) )
) )
} }
tryParseJson<List<Responses>>("[$tracks]")?.forEach {
subtitleCallback.invoke(
SubtitleFile(
fixTitle(it.label ?: return@forEach),
fixUrl(it.src)
)
)
}
} }
private fun String.addMarks(str: String): String { private fun String.addMarks(str: String): String {
@ -65,6 +78,7 @@ open class Streampai : ExtractorApi() {
data class Responses( data class Responses(
@JsonProperty("src") val src: String, @JsonProperty("src") val src: String,
@JsonProperty("type") val type: String?, @JsonProperty("type") val type: String?,
@JsonProperty("label") val label: String?,
@JsonProperty("size") val size: Int? @JsonProperty("size") val size: Int?
) )

View File

@ -1,5 +1,5 @@
// use an integer for version numbers // use an integer for version numbers
version = 60 version = 61
cloudstream { cloudstream {

View File

@ -11,7 +11,7 @@ import java.net.URI
open class Movierulzhd : MainAPI() { open class Movierulzhd : MainAPI() {
override var mainUrl = "https://movierulzhd.dog" override var mainUrl = "https://movierulzhd.party"
var directUrl = "" var directUrl = ""
override var name = "Movierulzhd" override var name = "Movierulzhd"
override val hasMainPage = true override val hasMainPage = true

View File

@ -1,5 +1,5 @@
// use an integer for version numbers // use an integer for version numbers
version = 9 version = 11
cloudstream { cloudstream {

View File

@ -1,12 +1,8 @@
package com.hexated package com.hexated
import com.fasterxml.jackson.annotation.JsonProperty import com.fasterxml.jackson.annotation.JsonProperty
import com.lagradost.cloudstream3.SubtitleFile import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.app import com.lagradost.cloudstream3.utils.*
import com.lagradost.cloudstream3.utils.ExtractorApi
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.INFER_TYPE
import com.lagradost.cloudstream3.utils.Qualities
open class Mitedrive : ExtractorApi() { open class Mitedrive : ExtractorApi() {
override val name = "Mitedrive" override val name = "Mitedrive"
@ -79,4 +75,21 @@ open class Berkasdrive : ExtractorApi() {
} }
}
open class Videogami : ExtractorApi() {
override val name = "Videogami"
override val mainUrl = "https://video.nimegami.id"
override val requiresReferer = false
override suspend fun getUrl(
url: String,
referer: String?,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
) {
val id = base64Decode(url.substringAfter("url=")).substringAfterLast("/")
loadExtractor("https://hxfile.co/embed-$id.html", "$mainUrl/", subtitleCallback, callback)
}
} }

View File

@ -81,7 +81,7 @@ class Nimegami : MainAPI() {
override suspend fun search(query: String): List<SearchResponse> { override suspend fun search(query: String): List<SearchResponse> {
val searchResponse = mutableListOf<SearchResponse>() val searchResponse = mutableListOf<SearchResponse>()
for (i in 1..2) { for (i in 1..2) {
val res = app.get("$mainUrl/page/$i/?s=gintama&post_type=post").document.select("div.archive article") val res = app.get("$mainUrl/page/$i/?s=$query&post_type=post").document.select("div.archive article")
.mapNotNull { .mapNotNull {
it.toSearchResult() it.toSearchResult()
} }

View File

@ -12,5 +12,6 @@ class NimegamiPlugin: Plugin() {
registerMainAPI(Nimegami()) registerMainAPI(Nimegami())
registerExtractorAPI(Mitedrive()) registerExtractorAPI(Mitedrive())
registerExtractorAPI(Berkasdrive()) registerExtractorAPI(Berkasdrive())
registerExtractorAPI(Videogami())
} }
} }

View File

@ -1,5 +1,5 @@
// use an integer for version numbers // use an integer for version numbers
version = 27 version = 28
cloudstream { cloudstream {

View File

@ -27,10 +27,7 @@ open class Qiwi : ExtractorApi() {
"$mainUrl/", "$mainUrl/",
getIndexQuality(title), getIndexQuality(title),
headers = mapOf( headers = mapOf(
"Accept" to "video/webm,video/ogg,video/*;q=0.9,application/ogg;q=0.7,audio/*;q=0.6,*/*;q=0.5",
"Range" to "bytes=0-", "Range" to "bytes=0-",
"Sec-Fetch-Dest" to "video",
"Sec-Fetch-Mode" to "no-cors",
) )
) )
) )
@ -42,39 +39,4 @@ open class Qiwi : ExtractorApi() {
?: Qualities.Unknown.value ?: Qualities.Unknown.value
} }
}
open class Mediafire : ExtractorApi() {
override val name = "Mediafire"
override val mainUrl = "https://www.mediafire.com"
override val requiresReferer = true
override suspend fun getUrl(
url: String,
referer: String?,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
) {
val res = app.get(url, referer = referer).document
val title = res.select("div.dl-btn-label").text()
val video = res.selectFirst("a#downloadButton")?.attr("href")
callback.invoke(
ExtractorLink(
this.name,
this.name,
video ?: return,
"",
getQuality(title),
INFER_TYPE
)
)
}
private fun getQuality(str: String?): Int {
return Regex("(\\d{3,4})[pP]").find(str ?: "")?.groupValues?.getOrNull(1)?.toIntOrNull()
?: Qualities.Unknown.value
}
} }

View File

@ -7,7 +7,7 @@ import com.lagradost.cloudstream3.utils.*
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
class OploverzProvider : MainAPI() { class OploverzProvider : MainAPI() {
override var mainUrl = "https://oploverz.cool" override var mainUrl = "https://oploverz.bio"
override var name = "Oploverz" override var name = "Oploverz"
override val hasMainPage = true override val hasMainPage = true
override var lang = "id" override var lang = "id"

View File

@ -11,6 +11,5 @@ class OploverzProviderPlugin: 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(OploverzProvider()) registerMainAPI(OploverzProvider())
registerExtractorAPI(Qiwi()) registerExtractorAPI(Qiwi())
registerExtractorAPI(Mediafire())
} }
} }

View File

@ -1,5 +1,5 @@
// use an integer for version numbers // use an integer for version numbers
version = 8 version = 9
cloudstream { cloudstream {

View File

@ -3,7 +3,7 @@ package com.hexated
import com.lagradost.cloudstream3.TvType import com.lagradost.cloudstream3.TvType
class Cgvindo : RebahinProvider() { class Cgvindo : RebahinProvider() {
override var mainUrl = "http://198.54.124.245" override var mainUrl = "http://cgvindo.lol"
override var name = "Cgvindo" override var name = "Cgvindo"
} }

View File

@ -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 = 218 version = 220
android { android {
defaultConfig { defaultConfig {
@ -9,7 +9,7 @@ android {
properties.load(project.rootProject.file("local.properties").inputStream()) properties.load(project.rootProject.file("local.properties").inputStream())
buildConfigField("String", "TMDB_API", "\"${properties.getProperty("TMDB_API")}\"") buildConfigField("String", "TMDB_API", "\"${properties.getProperty("TMDB_API")}\"")
buildConfigField("String", "OMOVIES_API", "\"${properties.getProperty("OMOVIES_API")}\"") buildConfigField("String", "GHOSTX_API", "\"${properties.getProperty("GHOSTX_API")}\"")
buildConfigField("String", "CINEMATV_API", "\"${properties.getProperty("CINEMATV_API")}\"") buildConfigField("String", "CINEMATV_API", "\"${properties.getProperty("CINEMATV_API")}\"")
buildConfigField("String", "SFMOVIES_API", "\"${properties.getProperty("SFMOVIES_API")}\"") buildConfigField("String", "SFMOVIES_API", "\"${properties.getProperty("SFMOVIES_API")}\"")
buildConfigField("String", "ZSHOW_API", "\"${properties.getProperty("ZSHOW_API")}\"") buildConfigField("String", "ZSHOW_API", "\"${properties.getProperty("ZSHOW_API")}\"")

View File

@ -436,9 +436,9 @@ class Streamwish : Filesim() {
override var mainUrl = "https://streamwish.to" override var mainUrl = "https://streamwish.to"
} }
class Wishfast : Filesim() { class UqloadsXyz : Filesim() {
override val name = "Wishfast" override val name = "Uqloads"
override var mainUrl = "https://wishfast.top" override var mainUrl = "https://uqloads.xyz"
} }
class FilelionsTo : Filesim() { class FilelionsTo : Filesim() {

View File

@ -1,7 +1,6 @@
package com.hexated package com.hexated
import com.lagradost.cloudstream3.* import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.APIHolder.unixTime
import com.lagradost.cloudstream3.APIHolder.unixTimeMS import com.lagradost.cloudstream3.APIHolder.unixTimeMS
import com.lagradost.cloudstream3.utils.* import com.lagradost.cloudstream3.utils.*
import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson
@ -125,8 +124,8 @@ object SoraExtractor : SoraStream() {
httpsify(srcrcp), httpsify(srcrcp),
referer = iframedoc referer = iframedoc
).document.selectFirst("script:containsData(Playerjs)")?.data() ).document.selectFirst("script:containsData(Playerjs)")?.data()
val video = script?.substringAfter("file:\"#2")?.substringBefore("\"") val video = script?.substringAfter("file:\"#9")?.substringBefore("\"")
?.replace(Regex("/.*?=?="), "")?.let { base64Decode(it) } ?.replace(Regex("/@#@\\S+?=?="), "")?.let { base64Decode(it) }
callback.invoke( callback.invoke(
ExtractorLink( ExtractorLink(
@ -136,66 +135,6 @@ object SoraExtractor : SoraStream() {
) )
} }
suspend fun invokeDbgo(
id: String? = null,
season: Int? = null,
episode: Int? = null,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
) {
val iframeDbgo: String?
val script = if (season == null) {
val doc = app.get("$dbgoAPI/imdb.php?id=$id").document
iframeDbgo = doc.select("div.myvideo iframe").attr("src")
app.get(iframeDbgo, referer = "$dbgoAPI/").document.select("script")
.find { it.data().contains("CDNplayerConfig =") }?.data()
} else {
val doc = app.get("$dbgoAPI/tv-imdb.php?id=$id&s=$season").document
iframeDbgo = doc.select("div.myvideo iframe").attr("src")
val token = app.get(
iframeDbgo,
referer = "$dbgoAPI/"
).document.selectFirst("select#translator-name option")?.attr("data-token")
app.get("https://voidboost.net/serial/$token/iframe?s=$season&e=$episode&h=dbgo.fun").document.select(
"script"
).find { it.data().contains("CDNplayerConfig =") }?.data()
} ?: return
val source =
Regex("['|\"]file['|\"]:\\s['|\"](#\\S+?)['|\"]").find(script)?.groupValues?.get(1)
?: return
val subtitle =
Regex("['|\"]subtitle['|\"]:\\s['|\"](\\S+?)['|\"]").find(script)?.groupValues?.get(1)
val ref = getBaseUrl(iframeDbgo)
decryptStreamUrl(source).split(",").map { links ->
val quality = Regex("\\[(\\d*p.*?)]").find(links)?.groupValues?.getOrNull(1)?.trim()
?: return@map null
links.replace("[$quality]", "").split(" or ").map { it.trim() }.map { link ->
val name = if (link.contains(".m3u8")) "Dbgo (Main)" else "Dbgo (Backup)"
callback.invoke(
ExtractorLink(
name,
name,
link,
"$ref/",
getQuality(quality),
isM3u8 = link.contains(".m3u8"),
headers = mapOf("Origin" to ref)
)
)
}
}
subtitle?.split(",")?.map { sub ->
val language = Regex("\\[(.*)]").find(sub)?.groupValues?.getOrNull(1) ?: return@map null
val link = sub.replace("[$language]", "").trim()
subtitleCallback.invoke(SubtitleFile(getDbgoLanguage(language), link))
}
}
suspend fun invokeDreamfilm( suspend fun invokeDreamfilm(
title: String? = null, title: String? = null,
season: Int? = null, season: Int? = null,
@ -1788,21 +1727,21 @@ object SoraExtractor : SoraStream() {
} }
suspend fun invokeSmashyStream( suspend fun invokeSmashyStream(
imdbId: String? = null, tmdbId: Int? = null,
season: Int? = null, season: Int? = null,
episode: Int? = null, episode: Int? = null,
subtitleCallback: (SubtitleFile) -> Unit, subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit, callback: (ExtractorLink) -> Unit,
) { ) {
val url = if (season == null) { val url = if (season == null) {
"$smashyStreamAPI/playere.php?imdb=$imdbId" "$smashyStreamAPI/playere.php?tmdb=$tmdbId"
} else { } else {
"$smashyStreamAPI/playere.php?imdb=$imdbId&season=$season&episode=$episode" "$smashyStreamAPI/playere.php?tmdb=$tmdbId&season=$season&episode=$episode"
} }
app.get( app.get(
url, url,
referer = "https://smashystream.com/" referer = "https://smashystream.xyz/"
).document.select("div#_default-servers a.server").map { ).document.select("div#_default-servers a.server").map {
it.attr("data-url") to it.text() it.attr("data-url") to it.text()
}.apmap { }.apmap {
@ -1810,9 +1749,8 @@ object SoraExtractor : SoraStream() {
"Player F" -> { "Player F" -> {
invokeSmashyFfix(it.second, it.first, url, subtitleCallback, callback) invokeSmashyFfix(it.second, it.first, url, subtitleCallback, callback)
} }
"Player SU" -> {
"Player D (Hindi)" -> { invokeSmashySu(it.second, it.first, url, callback)
invokeSmashyD(it.first, url, callback)
} }
else -> return@apmap else -> return@apmap
@ -1821,6 +1759,52 @@ object SoraExtractor : SoraStream() {
} }
suspend fun invokeMoflix(
tmdbId: Int? = null,
season: Int? = null,
episode: Int? = null,
callback: (ExtractorLink) -> Unit
) {
val id = (if(season == null) {
"tmdb|movie|$tmdbId"
} else {
"tmdb|series|$tmdbId"
}).let { base64Encode(it.toByteArray()) }
val loaderUrl = "$moflixAPI/api/v1/titles/$id?loader=titlePage"
val url = if(season == null) {
loaderUrl
} else {
val mediaId = app.get(loaderUrl, referer = "$moflixAPI/").parsedSafe<MoflixResponse>()?.title?.id
"$moflixAPI/api/v1/titles/$mediaId/seasons/$season/episodes/$episode?loader=episodePage"
}
val res = app.get(url, referer = "$moflixAPI/").parsedSafe<MoflixResponse>()
(res?.episode ?: res?.title)?.videos?.filter { it.category.equals("full", true) }?.apmap { iframe ->
val response = app.get(iframe.src ?: return@apmap, referer = "$moflixAPI/")
val host = getBaseUrl(iframe.src)
val doc = response.document.selectFirst("script:containsData(sources:)")?.data()
val script = if (doc.isNullOrEmpty()) {
getAndUnpack(response.text)
} else {
doc
}
val m3u8 = Regex("file:\\s*\"(.*?m3u8.*?)\"").find(script ?: return@apmap)?.groupValues?.getOrNull(1)
if(m3u8?.haveDub("$host/") == false) return@apmap
callback.invoke(
ExtractorLink(
"Moflix",
"Moflix [${iframe.name}]",
m3u8 ?: return@apmap,
"$host/",
iframe.quality?.filter { it.isDigit() }?.toIntOrNull() ?: Qualities.Unknown.value,
INFER_TYPE
)
)
}
}
//TODO only subs //TODO only subs
suspend fun invokeWatchsomuch( suspend fun invokeWatchsomuch(
imdbId: String? = null, imdbId: String? = null,
@ -2100,11 +2084,11 @@ object SoraExtractor : SoraStream() {
?: return ?: return
val ref = getBaseUrl(framesrc) val ref = getBaseUrl(framesrc)
val id = framesrc.substringAfter("id=").substringBefore("&") val id = framesrc.substringAfter("id=").substringBefore("&")
loadExtractor("https://wishfast.top/e/$id", "$ref/", subtitleCallback, callback) loadExtractor("https://uqloads.xyz/e/$id", "$ref/", subtitleCallback, callback)
} }
suspend fun invokeOmovies( suspend fun invokeGhostx(
title: String? = null, title: String? = null,
year: Int? = null, year: Int? = null,
season: Int? = null, season: Int? = null,
@ -2117,8 +2101,8 @@ object SoraExtractor : SoraStream() {
season, season,
episode, episode,
callback, callback,
BuildConfig.OMOVIES_API, BuildConfig.GHOSTX_API,
"Omovies", "Ghostx",
base64Decode("X3NtUWFtQlFzRVRi"), base64Decode("X3NtUWFtQlFzRVRi"),
base64Decode("X3NCV2NxYlRCTWFU") base64Decode("X3NCV2NxYlRCTWFU")
) )
@ -2136,7 +2120,7 @@ object SoraExtractor : SoraStream() {
episodeSelector: String, episodeSelector: String,
) { ) {
fun String.decrypt(key: String): List<GpressSources>? { fun String.decrypt(key: String): List<GpressSources>? {
return tryParseJson<List<GpressSources>>(base64Decode(this).decodePrimewireXor(key)) return tryParseJson<List<GpressSources>>(base64Decode(this).xorDecrypt(key))
} }
val slug = getEpisodeSlug(season, episode) val slug = getEpisodeSlug(season, episode)
@ -2148,8 +2132,10 @@ object SoraExtractor : SoraStream() {
val savedCookies = mapOf( val savedCookies = mapOf(
base64Decode("X2lkZW50aXR5Z29tb3ZpZXM3") to base64Decode("NTJmZGM3MGIwMDhjMGIxZDg4MWRhYzBmMDFjY2E4MTllZGQ1MTJkZTAxY2M4YmJjMTIyNGVkNGFhZmI3OGI1MmElM0EyJTNBJTdCaSUzQTAlM0JzJTNBMTglM0ElMjJfaWRlbnRpdHlnb21vdmllczclMjIlM0JpJTNBMSUzQnMlM0E1MiUzQSUyMiU1QjIwNTAzNjYlMkMlMjJIblZSUkFPYlRBU09KRXI0NVl5Q004d2lIb2wwVjFrbyUyMiUyQzI1OTIwMDAlNUQlMjIlM0IlN0Q="), base64Decode("X2lkZW50aXR5Z29tb3ZpZXM3") to base64Decode("NTJmZGM3MGIwMDhjMGIxZDg4MWRhYzBmMDFjY2E4MTllZGQ1MTJkZTAxY2M4YmJjMTIyNGVkNGFhZmI3OGI1MmElM0EyJTNBJTdCaSUzQTAlM0JzJTNBMTglM0ElMjJfaWRlbnRpdHlnb21vdmllczclMjIlM0JpJTNBMSUzQnMlM0E1MiUzQSUyMiU1QjIwNTAzNjYlMkMlMjJIblZSUkFPYlRBU09KRXI0NVl5Q004d2lIb2wwVjFrbyUyMiUyQzI1OTIwMDAlNUQlMjIlM0IlN0Q="),
) )
val req = app.get("$api/search/$query")
val doc = req.document var res = app.get("$api/search/$query")
val cookies = savedCookies + res.cookies
val doc = res.document
val media = doc.select("div.$mediaSelector").map { val media = doc.select("div.$mediaSelector").map {
Triple(it.attr("data-filmName"), it.attr("data-year"), it.select("a").attr("href")) Triple(it.attr("data-filmName"), it.attr("data-year"), it.select("a").attr("href"))
}.let { el -> }.let { el ->
@ -2172,45 +2158,38 @@ object SoraExtractor : SoraStream() {
val iframe = if (season == null) { val iframe = if (season == null) {
media.third media.third
} else { } else {
val res = app.get(fixUrl(media.third, api)) app.get(fixUrl(media.third, api), cookies = cookies)
res.document.selectFirst("div#$episodeSelector a:contains(Episode ${slug.second})") .document.selectFirst("div#$episodeSelector a:contains(Episode ${slug.second})")
?.attr("href") ?.attr("href")
} ?: return
val users = if (season == null) {
media.third.substringAfterLast("/") to "0"
} else {
media.third.substringAfterLast("/") to iframe.substringAfterLast("/")
.substringBefore("-")
} }
val res = app.get(fixUrl(iframe, api), verify = false)
delay(2000) res = app.get(fixUrl(iframe ?: return, api), cookies = cookies)
val serverUrl = res.document.selectFirst("script:containsData(pushState)")?.data()?.let {
""",\s*'([^']+)""".toRegex().find(it)?.groupValues?.get(1)
} ?: return
val cookies = savedCookies + res.cookies
val url = res.document.select("meta[property=og:url]").attr("content") val url = res.document.select("meta[property=og:url]").attr("content")
val headers = mapOf("X-Requested-With" to "XMLHttpRequest") val headers = mapOf("X-Requested-With" to "XMLHttpRequest")
val qualities = intArrayOf(2160, 1440, 1080, 720, 480, 360) val qualities = intArrayOf(2160, 1440, 1080, 720, 480, 360)
val (serverId, episodeId) = if (season == null) {
url.substringAfterLast("/") to "0"
} else {
url.substringBeforeLast("/").substringAfterLast("/") to url.substringAfterLast("/")
.substringBefore("-")
}
val serverRes = app.get( val serverRes = app.get(
"$api/user/servers/${users.first}?ep=${users.second}", "$api/user/servers/$serverId?ep=$episodeId",
cookies = cookies, cookies = cookies,
referer = url, referer = url,
headers = headers headers = headers
) ).document
val unpack = getAndUnpack(serverRes.text) serverRes.select("ul li").apmap { el ->
val key = unpack.substringAfter("(key=").substringBefore(")")
val key2 = unpack.substringAfter("<\"").substringBefore("\".")
serverRes.document.select("ul li").amap { el ->
val server = el.attr("data-value") val server = el.attr("data-value")
val encryptedData = app.get( val encryptedData = app.get(
"${fixUrl(serverUrl, api)}?server=$server&_=$unixTimeMS", "$url?server=$server&_=$unixTimeMS",
cookies = cookies, cookies = cookies,
referer = url, referer = url,
headers = headers headers = headers
).text ).text
val links = encryptedData.decrypt(key) ?: encryptedData.decrypt(key2) ?: return@amap val links = encryptedData.decrypt(base64Decode("MTEx"))
links.forEach { video -> links?.forEach { video ->
qualities.filter { it <= video.max.toInt() }.forEach { qualities.filter { it <= video.max.toInt() }.forEach {
callback( callback(
ExtractorLink( ExtractorLink(
@ -2291,43 +2270,23 @@ object SoraExtractor : SoraStream() {
subtitleCallback: (SubtitleFile) -> Unit, subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit, callback: (ExtractorLink) -> Unit,
) { ) {
val id = imdbId?.removePrefix("tt") val media = app.get("$cinemaTvAPI/v1/${if (season == null) "movies" else "shows"}?filters[q]=$title")
val slug = title.createSlug() .parsedSafe<CinemaTvResponse>()?.items?.find {
val url = if (season == null) { it.imdb_id?.removePrefix("tt")
"$cinemaTvAPI/movies/play/$id-$slug-$year" .equals(imdbId?.removePrefix("tt")) || (it.title.equals(
title,
true
) && it.year == year)
} ?: return
val mediaId = if (season == null) {
media.id_movie
} else { } else {
"$cinemaTvAPI/shows/play/$id-$slug-$year" app.get("$cinemaTvAPI/v1/shows?expand=episodes&id=${media.id_show}")
} .parsedSafe<CinemaTvResponse>()?.episodes?.find { it.episode == episode && it.season == season }?.id
} ?: return
val session = val sources = app.get("$cinemaTvAPI/v1/${if (season == null) "movies" else "episodes"}/view?expand=streams,subtitles&id=$mediaId").parsedSafe<CinemaTvResponse>()
"PHPSESSID=ngr4cudjrimdnhkth30ssohs0n; _csrf=a6ffd7bb7654083fce6df528225a238d0e85aa1fb885dc7638c1259ec1ba0d5ca%3A2%3A%7Bi%3A0%3Bs%3A5%3A%22_csrf%22%3Bi%3A1%3Bs%3A32%3A%22mTTLiDLjxohs-CpKk0bjRH3HdYMB9uBV%22%3B%7D; _ga=GA1.1.1195498587.1701871187; _ga_VZD7HJ3WK6=GS1.1.$unixTime.4.0.1.$unixTime.0.0.0"
val headers = mapOf(
"Cookie" to session,
"x-requested-with" to "com.wwcinematv",
)
val doc = app.get(url, headers = headers).document
val script = doc.selectFirst("script:containsData(hash:)")?.data()
val hash = Regex("hash:\\s*['\"](\\S+)['\"]").find(script ?: return)?.groupValues?.get(1)
val expires = Regex("expires:\\s*(\\d+)").find(script)?.groupValues?.get(1)
val episodeId = (if (season == null) {
"""id_movie:\s*(\d+)"""
} else {
"""episode:\s*['"]$episode['"],[\n\s]+id_episode:\s*(\d+),[\n\s]+season:\s*['"]$season['"]"""
}).let { it.toRegex().find(script)?.groupValues?.get(1) }
val videoUrl = if (season == null) {
"$cinemaTvAPI/api/v1/security/movie-access?id_movie=$episodeId&hash=$hash&expires=$expires"
} else {
"$cinemaTvAPI/api/v1/security/episode-access?id_episode=$episodeId&hash=$hash&expires=$expires"
}
val sources = app.get(
videoUrl,
referer = url,
headers = mapOf("X-Requested-With" to "XMLHttpRequest")
).parsedSafe<CinemaTvResponse>()
sources?.streams?.mapKeys { source -> sources?.streams?.mapKeys { source ->
callback.invoke( callback.invoke(
@ -2335,19 +2294,18 @@ object SoraExtractor : SoraStream() {
"CinemaTv", "CinemaTv",
"CinemaTv", "CinemaTv",
source.value, source.value,
"$cinemaTvAPI/", "",
getQualityFromName(source.key), getQualityFromName(source.key),
true true
) )
) )
} }
sources?.subtitles?.map { sub -> sources?.subtitles?.map {
val file = sub.file.toString()
subtitleCallback.invoke( subtitleCallback.invoke(
SubtitleFile( SubtitleFile(
sub.language ?: return@map, it.language ?: return@map,
if (file.startsWith("[")) return@map else fixUrl(file, cinemaTvAPI), fixUrl(it.url ?: return@map, cinemaTvAPI)
) )
) )
} }
@ -2410,37 +2368,25 @@ object SoraExtractor : SoraStream() {
suspend fun invokeRidomovies( suspend fun invokeRidomovies(
tmdbId: Int? = null, tmdbId: Int? = null,
imdbId: String? = null, imdbId: String? = null,
title: String? = null,
season: Int? = null, season: Int? = null,
episode: Int? = null, episode: Int? = null,
subtitleCallback: (SubtitleFile) -> Unit, subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit, callback: (ExtractorLink) -> Unit,
) { ) {
val slug = if (season == null) { val mediaSlug = app.get("$ridomoviesAPI/core/api/search?q=$imdbId").parsedSafe<RidoSearch>()?.data?.items?.find {
app.get("$ridomoviesAPI/core/api/search?q=$imdbId") it.contentable?.tmdbId == tmdbId || it.contentable?.imdbId == imdbId
.parsedSafe<RidoSearch>()?.data?.items?.find { }?.slug ?: return
it.contentable?.tmdbId == tmdbId || it.contentable?.imdbId == imdbId
}?.slug val id = season?.let {
} else { val episodeUrl = "$ridomoviesAPI/tv/$mediaSlug/season-$it/episode-$episode"
app.get("$ridomoviesAPI/tv/${title.createSlug()}/season-$season/episode-$episode").text.substringAfterLast( app.get(episodeUrl).text.substringAfterLast("""postid\":\"""").substringBefore("""\""")
"""postid\":\"""" } ?: mediaSlug
).substringBefore("""\"""")
} ?: return val url = "$ridomoviesAPI/core/api/${if (season == null) "movies" else "episodes"}/$id/videos"
val url = if (season == null) {
"$ridomoviesAPI/core/api/movies/$slug/videos"
} else {
"$ridomoviesAPI/core/api/episodes/$slug/videos"
}
app.get(url).parsedSafe<RidoResponses>()?.data?.apmap { link -> app.get(url).parsedSafe<RidoResponses>()?.data?.apmap { link ->
val iframe = Jsoup.parse(link.url ?: return@apmap).select("iframe").attr("data-src") val iframe = Jsoup.parse(link.url ?: return@apmap).select("iframe").attr("data-src")
if (iframe.startsWith("https://closeload.top")) { if (iframe.startsWith("https://closeload.top")) {
val unpacked = val unpacked = getAndUnpack(app.get(iframe, referer = "$ridomoviesAPI/").text)
getAndUnpack(
app.get(
iframe,
referer = "$ridomoviesAPI/"
).text
)
val video = Regex("=\"(aHR.*?)\";").find(unpacked)?.groupValues?.get(1) val video = Regex("=\"(aHR.*?)\";").find(unpacked)?.groupValues?.get(1)
callback.invoke( callback.invoke(
ExtractorLink( ExtractorLink(

View File

@ -47,6 +47,23 @@ data class AniwaveServer(
} }
} }
data class MoflixResponse(
@JsonProperty("title") val title: Episode? = null,
@JsonProperty("episode") val episode: Episode? = null,
) {
data class Episode(
@JsonProperty("id") val id: Int? = null,
@JsonProperty("videos") val videos: ArrayList<Videos>? = arrayListOf(),
) {
data class Videos(
@JsonProperty("name") val name: String? = null,
@JsonProperty("category") val category: String? = null,
@JsonProperty("src") val src: String? = null,
@JsonProperty("quality") val quality: String? = null,
)
}
}
data class AniMedia( data class AniMedia(
@JsonProperty("id") var id: Int? = null, @JsonProperty("id") var id: Int? = null,
@JsonProperty("idMal") var idMal: Int? = null @JsonProperty("idMal") var idMal: Int? = null
@ -174,15 +191,31 @@ data class JikanResponse(
@JsonProperty("data") val data: JikanData? = null, @JsonProperty("data") val data: JikanData? = null,
) )
data class CinemaTvSubtitles(
@JsonProperty("language") val language: String? = null,
@JsonProperty("file") val file: Any? = null,
)
data class CinemaTvResponse( data class CinemaTvResponse(
@JsonProperty("items") val items: ArrayList<Items>? = arrayListOf(),
@JsonProperty("episodes") val episodes: ArrayList<Episodes>? = arrayListOf(),
@JsonProperty("streams") val streams: HashMap<String, String>? = null, @JsonProperty("streams") val streams: HashMap<String, String>? = null,
@JsonProperty("subtitles") val subtitles: ArrayList<CinemaTvSubtitles>? = arrayListOf(), @JsonProperty("subtitles") val subtitles: ArrayList<Subtitles>? = arrayListOf(),
) ) {
data class Items(
@JsonProperty("id_movie") val id_movie: Int? = null,
@JsonProperty("id_show") val id_show: Int? = null,
@JsonProperty("title") val title: String? = null,
@JsonProperty("year") val year: Int? = null,
@JsonProperty("imdb_id") val imdb_id: String? = null,
)
data class Episodes(
@JsonProperty("id") val id: Int? = null,
@JsonProperty("season") val season: Int? = null,
@JsonProperty("episode") val episode: Int? = null,
)
data class Subtitles(
@JsonProperty("language") val language: String? = null,
@JsonProperty("url") val url: String? = null,
)
}
data class VidsrctoResult( data class VidsrctoResult(
@JsonProperty("id") val id: String? = null, @JsonProperty("id") val id: String? = null,
@ -427,15 +460,6 @@ data class SmashySources(
@JsonProperty("subtitleUrls") var subtitleUrls: String? = null, @JsonProperty("subtitleUrls") var subtitleUrls: String? = null,
) )
data class SmashyDSources(
@JsonProperty("sourceUrls") var sourceUrls: ArrayList<SmashyDSourcesUrls>? = arrayListOf(),
)
data class SmashyDSourcesUrls(
@JsonProperty("file") var file: String? = null,
@JsonProperty("title") var title: String? = null,
)
data class AoneroomResponse( data class AoneroomResponse(
@JsonProperty("data") val data: Data? = null, @JsonProperty("data") val data: Data? = null,
) { ) {

View File

@ -6,7 +6,6 @@ import com.hexated.SoraExtractor.invokeAllMovieland
import com.hexated.SoraExtractor.invokeAnimes import com.hexated.SoraExtractor.invokeAnimes
import com.hexated.SoraExtractor.invokeAoneroom import com.hexated.SoraExtractor.invokeAoneroom
import com.hexated.SoraExtractor.invokeBollyMaza import com.hexated.SoraExtractor.invokeBollyMaza
import com.hexated.SoraExtractor.invokeDbgo
import com.hexated.SoraExtractor.invokeFilmxy import com.hexated.SoraExtractor.invokeFilmxy
import com.hexated.SoraExtractor.invokeKimcartoon import com.hexated.SoraExtractor.invokeKimcartoon
import com.hexated.SoraExtractor.invokeVidSrc import com.hexated.SoraExtractor.invokeVidSrc
@ -36,15 +35,14 @@ import com.hexated.SoraExtractor.invokeEmovies
import com.hexated.SoraExtractor.invokeHdmovies4u import com.hexated.SoraExtractor.invokeHdmovies4u
import com.hexated.SoraExtractor.invokeMultimovies import com.hexated.SoraExtractor.invokeMultimovies
import com.hexated.SoraExtractor.invokeNetmovies import com.hexated.SoraExtractor.invokeNetmovies
import com.hexated.SoraExtractor.invokeSFMovies
import com.hexated.SoraExtractor.invokeShowflix import com.hexated.SoraExtractor.invokeShowflix
import com.hexated.SoraExtractor.invokeTvMovies import com.hexated.SoraExtractor.invokeTvMovies
import com.hexated.SoraExtractor.invokeUhdmovies import com.hexated.SoraExtractor.invokeUhdmovies
import com.hexated.SoraExtractor.invokeVegamovies import com.hexated.SoraExtractor.invokeVegamovies
import com.hexated.SoraExtractor.invokeVidsrcto import com.hexated.SoraExtractor.invokeVidsrcto
import com.hexated.SoraExtractor.invokeCinemaTv import com.hexated.SoraExtractor.invokeCinemaTv
import com.hexated.SoraExtractor.invokeMMovies import com.hexated.SoraExtractor.invokeMoflix
import com.hexated.SoraExtractor.invokeOmovies import com.hexated.SoraExtractor.invokeGhostx
import com.hexated.SoraExtractor.invokeWatchCartoon import com.hexated.SoraExtractor.invokeWatchCartoon
import com.hexated.SoraExtractor.invokeWatchsomuch import com.hexated.SoraExtractor.invokeWatchsomuch
import com.hexated.SoraExtractor.invokeZshow import com.hexated.SoraExtractor.invokeZshow
@ -119,6 +117,7 @@ open class SoraStream : TmdbProvider() {
const val aoneroomAPI = "https://api3.aoneroom.com" const val aoneroomAPI = "https://api3.aoneroom.com"
const val mMoviesAPI = "https://multimovies.uno" const val mMoviesAPI = "https://multimovies.uno"
const val watchCartoonAPI = "https://www1.watchcartoononline.bz" const val watchCartoonAPI = "https://www1.watchcartoononline.bz"
const val moflixAPI = "https://moflix-stream.xyz"
const val fdMoviesAPI = "https://freedrivemovie.com" const val fdMoviesAPI = "https://freedrivemovie.com"
const val uhdmoviesAPI = "https://uhdmovies.zip" const val uhdmoviesAPI = "https://uhdmovies.zip"
@ -384,9 +383,6 @@ open class SoraStream : TmdbProvider() {
{ {
invokeVidSrc(res.id, res.season, res.episode, callback) invokeVidSrc(res.id, res.season, res.episode, callback)
}, },
{
invokeDbgo(res.imdbId, res.season, res.episode, subtitleCallback, callback)
},
{ {
if (!res.isAnime) invokeAoneroom( if (!res.isAnime) invokeAoneroom(
res.title, res.airedYear res.title, res.airedYear
@ -466,7 +462,7 @@ open class SoraStream : TmdbProvider() {
) )
}, },
{ {
if (!res.isAnime) invokeOmovies( if (!res.isAnime) invokeGhostx(
res.title, res.title,
res.year, res.year,
res.season, res.season,
@ -547,7 +543,7 @@ open class SoraStream : TmdbProvider() {
}, },
{ {
if (!res.isAnime) invokeSmashyStream( if (!res.isAnime) invokeSmashyStream(
res.imdbId, res.id,
res.season, res.season,
res.episode, res.episode,
subtitleCallback, subtitleCallback,
@ -587,7 +583,6 @@ open class SoraStream : TmdbProvider() {
if (!res.isAnime) invokeRidomovies( if (!res.isAnime) invokeRidomovies(
res.id, res.id,
res.imdbId, res.imdbId,
res.title,
res.season, res.season,
res.episode, res.episode,
subtitleCallback, subtitleCallback,
@ -716,13 +711,7 @@ open class SoraStream : TmdbProvider() {
) )
}, },
{ {
if (!res.isAnime) invokeSFMovies( if (!res.isAnime) invokeMoflix(res.id, res.season, res.episode, callback)
res.id, res.title, res.airedYear
?: res.year, res.season, res.episode, callback
)
},
{
invokeMMovies(res.title, res.season, res.episode, subtitleCallback, callback)
}, },
) )

View File

@ -4,7 +4,6 @@ import com.hexated.SoraExtractor.invoke2embed
import com.hexated.SoraExtractor.invokeAllMovieland import com.hexated.SoraExtractor.invokeAllMovieland
import com.hexated.SoraExtractor.invokeAnimes import com.hexated.SoraExtractor.invokeAnimes
import com.hexated.SoraExtractor.invokeAoneroom import com.hexated.SoraExtractor.invokeAoneroom
import com.hexated.SoraExtractor.invokeDbgo
import com.hexated.SoraExtractor.invokeDoomovies import com.hexated.SoraExtractor.invokeDoomovies
import com.hexated.SoraExtractor.invokeDramaday import com.hexated.SoraExtractor.invokeDramaday
import com.hexated.SoraExtractor.invokeDreamfilm import com.hexated.SoraExtractor.invokeDreamfilm
@ -24,13 +23,12 @@ import com.hexated.SoraExtractor.invokeDumpStream
import com.hexated.SoraExtractor.invokeEmovies import com.hexated.SoraExtractor.invokeEmovies
import com.hexated.SoraExtractor.invokeMultimovies import com.hexated.SoraExtractor.invokeMultimovies
import com.hexated.SoraExtractor.invokeNetmovies import com.hexated.SoraExtractor.invokeNetmovies
import com.hexated.SoraExtractor.invokeSFMovies
import com.hexated.SoraExtractor.invokeShowflix import com.hexated.SoraExtractor.invokeShowflix
import com.hexated.SoraExtractor.invokeVidSrc import com.hexated.SoraExtractor.invokeVidSrc
import com.hexated.SoraExtractor.invokeVidsrcto import com.hexated.SoraExtractor.invokeVidsrcto
import com.hexated.SoraExtractor.invokeCinemaTv import com.hexated.SoraExtractor.invokeCinemaTv
import com.hexated.SoraExtractor.invokeMMovies import com.hexated.SoraExtractor.invokeMoflix
import com.hexated.SoraExtractor.invokeOmovies import com.hexated.SoraExtractor.invokeGhostx
import com.hexated.SoraExtractor.invokeWatchCartoon import com.hexated.SoraExtractor.invokeWatchCartoon
import com.hexated.SoraExtractor.invokeWatchsomuch import com.hexated.SoraExtractor.invokeWatchsomuch
import com.hexated.SoraExtractor.invokeZshow import com.hexated.SoraExtractor.invokeZshow
@ -52,6 +50,9 @@ class SoraStreamLite : SoraStream() {
val res = AppUtils.parseJson<LinkData>(data) val res = AppUtils.parseJson<LinkData>(data)
argamap( argamap(
{
if (!res.isAnime) invokeMoflix(res.id, res.season, res.episode, callback)
},
{ {
if (!res.isAnime) invokeWatchsomuch( if (!res.isAnime) invokeWatchsomuch(
res.imdbId, res.imdbId,
@ -93,9 +94,6 @@ class SoraStreamLite : SoraStream() {
{ {
invokeVidSrc(res.id, res.season, res.episode, callback) invokeVidSrc(res.id, res.season, res.episode, callback)
}, },
{
invokeDbgo(res.imdbId, res.season, res.episode, subtitleCallback, callback)
},
{ {
if (!res.isAnime && res.isCartoon) invokeWatchCartoon( if (!res.isAnime && res.isCartoon) invokeWatchCartoon(
res.title, res.title,
@ -137,7 +135,7 @@ class SoraStreamLite : SoraStream() {
) )
}, },
{ {
if (!res.isAnime) invokeOmovies( if (!res.isAnime) invokeGhostx(
res.title, res.title,
res.year, res.year,
res.season, res.season,
@ -156,7 +154,7 @@ class SoraStreamLite : SoraStream() {
}, },
{ {
if (!res.isAnime) invokeSmashyStream( if (!res.isAnime) invokeSmashyStream(
res.imdbId, res.id,
res.season, res.season,
res.episode, res.episode,
subtitleCallback, subtitleCallback,
@ -226,7 +224,6 @@ class SoraStreamLite : SoraStream() {
if (!res.isAnime) invokeRidomovies( if (!res.isAnime) invokeRidomovies(
res.id, res.id,
res.imdbId, res.imdbId,
res.title,
res.season, res.season,
res.episode, res.episode,
subtitleCallback, subtitleCallback,
@ -322,15 +319,6 @@ class SoraStreamLite : SoraStream() {
callback callback
) )
}, },
{
if (!res.isAnime) invokeSFMovies(
res.id, res.title, res.airedYear
?: res.year, res.season, res.episode, callback
)
},
{
invokeMMovies(res.title, res.season, res.episode, subtitleCallback, callback)
},
) )
return true return true

View File

@ -25,7 +25,7 @@ class SoraStreamPlugin: Plugin() {
registerExtractorAPI(Streamwish()) registerExtractorAPI(Streamwish())
registerExtractorAPI(FilelionsTo()) registerExtractorAPI(FilelionsTo())
registerExtractorAPI(Embedwish()) registerExtractorAPI(Embedwish())
registerExtractorAPI(Wishfast()) registerExtractorAPI(UqloadsXyz())
registerExtractorAPI(Uploadever()) registerExtractorAPI(Uploadever())
registerExtractorAPI(Netembed()) registerExtractorAPI(Netembed())
registerExtractorAPI(Flaswish()) registerExtractorAPI(Flaswish())

View File

@ -18,17 +18,12 @@ import com.lagradost.cloudstream3.utils.AppUtils.toJson
import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson
import com.lagradost.nicehttp.NiceResponse import com.lagradost.nicehttp.NiceResponse
import com.lagradost.nicehttp.RequestBodyTypes import com.lagradost.nicehttp.RequestBodyTypes
import com.lagradost.nicehttp.Requests.Companion.await
import com.lagradost.nicehttp.requestCreator import com.lagradost.nicehttp.requestCreator
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import okhttp3.FormBody import okhttp3.FormBody
import okhttp3.HttpUrl.Companion.toHttpUrl import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.Interceptor
import okhttp3.MediaType.Companion.toMediaTypeOrNull import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.RequestBody.Companion.toRequestBody import okhttp3.RequestBody.Companion.toRequestBody
import okhttp3.Response
import org.jsoup.nodes.Document import org.jsoup.nodes.Document
import java.math.BigInteger import java.math.BigInteger
import java.net.* import java.net.*
@ -38,7 +33,6 @@ import java.security.spec.PKCS8EncodedKeySpec
import java.security.spec.X509EncodedKeySpec import java.security.spec.X509EncodedKeySpec
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.* import java.util.*
import java.util.concurrent.TimeUnit
import javax.crypto.Cipher import javax.crypto.Cipher
import javax.crypto.spec.GCMParameterSpec import javax.crypto.spec.GCMParameterSpec
import javax.crypto.spec.IvParameterSpec import javax.crypto.spec.IvParameterSpec
@ -427,21 +421,28 @@ suspend fun invokeSmashyFfix(
} }
suspend fun invokeSmashyD( suspend fun invokeSmashySu(
name: String,
url: String, url: String,
ref: String, ref: String,
callback: (ExtractorLink) -> Unit, callback: (ExtractorLink) -> Unit,
) { ) {
val json = app.get(url, referer = ref, headers = mapOf("X-Requested-With" to "XMLHttpRequest")) val json = app.get(url, referer = ref, headers = mapOf("X-Requested-With" to "XMLHttpRequest"))
.parsedSafe<SmashyDSources>() .parsedSafe<SmashySources>()
json?.sourceUrls?.apmap { json?.sourceUrls?.firstOrNull()?.removeSuffix(",")?.split(",")?.forEach { links ->
M3u8Helper.generateM3u8( val quality = Regex("\\[(\\S+)]").find(links)?.groupValues?.getOrNull(1) ?: return@forEach
"Smashy [Player D ${it.title}]", val trimmedLink = links.removePrefix("[$quality]").trim()
it.file ?: return@apmap, callback.invoke(
"" ExtractorLink(
).forEach(callback) "Smashy [$name]",
"Smashy [$name]",
trimmedLink,
"",
getQualityFromName(quality),
INFER_TYPE
)
)
} }
} }
suspend fun getDumpIdAndType(title: String?, year: Int?, season: Int?): Pair<String?, Int?> { suspend fun getDumpIdAndType(title: String?, year: Int?, season: Int?): Pair<String?, Int?> {
@ -800,6 +801,10 @@ suspend fun getCrunchyrollIdFromMalSync(aniId: String?): String? {
?: regex.find("$crunchyroll")?.groupValues?.getOrNull(1) ?: regex.find("$crunchyroll")?.groupValues?.getOrNull(1)
} }
suspend fun String.haveDub(referer: String) : Boolean {
return app.get(this,referer=referer).text.contains("TYPE=AUDIO")
}
suspend fun convertTmdbToAnimeId( suspend fun convertTmdbToAnimeId(
title: String?, title: String?,
date: String?, date: String?,
@ -1034,7 +1039,7 @@ fun decodeIndexJson(json: String): String {
return base64Decode(slug.substring(0, slug.length - 20)) return base64Decode(slug.substring(0, slug.length - 20))
} }
fun String.decodePrimewireXor(key: String): String { fun String.xorDecrypt(key: String): String {
val sb = StringBuilder() val sb = StringBuilder()
var i = 0 var i = 0
while (i < this.length) { while (i < this.length) {
@ -1060,9 +1065,9 @@ fun vidsrctoDecrypt(text: String): String {
} }
fun String?.createSlug(): String? { fun String?.createSlug(): String? {
return this?.replace(Regex("[^\\w\\s-]"), "") return this?.filter { it.isWhitespace() || it.isLetterOrDigit() }
?.replace(" ", "-") ?.trim()
?.replace(Regex("( )|( -)|(- )|(--)"), "-") ?.replace("\\s+".toRegex(), "-")
?.lowercase() ?.lowercase()
} }
@ -1148,14 +1153,6 @@ fun getVipLanguage(str: String): String {
} }
} }
fun getDbgoLanguage(str: String): String {
return when (str) {
"Русский" -> "Russian"
"Українська" -> "Ukrainian"
else -> str
}
}
fun fixCrunchyrollLang(language: String?): String? { fun fixCrunchyrollLang(language: String?): String? {
return SubtitleHelper.fromTwoLettersToLanguage(language ?: return null) return SubtitleHelper.fromTwoLettersToLanguage(language ?: return null)
?: SubtitleHelper.fromTwoLettersToLanguage(language.substringBefore("-")) ?: SubtitleHelper.fromTwoLettersToLanguage(language.substringBefore("-"))
@ -1212,37 +1209,6 @@ fun base64DecodeAPI(api: String): String {
return api.chunked(4).map { base64Decode(it) }.reversed().joinToString("") return api.chunked(4).map { base64Decode(it) }.reversed().joinToString("")
} }
fun decryptStreamUrl(data: String): String {
fun getTrash(arr: List<String>, item: Int): List<String> {
val trash = ArrayList<List<String>>()
for (i in 1..item) {
trash.add(arr)
}
return trash.reduce { acc, list ->
val temp = ArrayList<String>()
acc.forEach { ac ->
list.forEach { li ->
temp.add(ac.plus(li))
}
}
return@reduce temp
}
}
val trashList = listOf("@", "#", "!", "^", "$")
val trashSet = getTrash(trashList, 2) + getTrash(trashList, 3)
var trashString = data.replace("#2", "").split("//_//").joinToString("")
trashSet.forEach {
val temp = base64Encode(it.toByteArray())
trashString = trashString.replace(temp, "")
}
return base64Decode(trashString)
}
fun fixUrl(url: String, domain: String): String { fun fixUrl(url: String, domain: String): String {
if (url.startsWith("http")) { if (url.startsWith("http")) {
return url return url

View File

@ -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 = 1 version = 3
android { android {
defaultConfig { defaultConfig {

View File

@ -1,7 +1,9 @@
package com.hexated package com.hexated
import com.lagradost.cloudstream3.* import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.mvvm.normalSafeApiCall
import com.lagradost.cloudstream3.utils.* import com.lagradost.cloudstream3.utils.*
import java.net.URL
object Extractors : Superstream() { object Extractors : Superstream() {
@ -66,45 +68,44 @@ object Extractors : Superstream() {
callback: (ExtractorLink) -> Unit, callback: (ExtractorLink) -> Unit,
) { ) {
val (seasonSlug, episodeSlug) = getEpisodeSlug(season, episode) val (seasonSlug, episodeSlug) = getEpisodeSlug(season, episode)
val shareKey = app.get( val shareKey = app.get("$fourthAPI/index/share_link?id=${mediaId}&type=$type")
"$fourthAPI/index/share_link?id=${mediaId}&type=$type" .parsedSafe<ExternalResponse>()?.data?.link?.substringAfterLast("/") ?: return
).parsedSafe<ExternalResponse>()?.data?.link?.substringAfterLast("/")
val headers = mapOf("Accept-Language" to "en") val headers = mapOf("Accept-Language" to "en")
val shareRes = app.get( val shareRes = app.get("$thirdAPI/file/file_share_list?share_key=$shareKey", headers = headers)
"$thirdAPI/file/file_share_list?share_key=${shareKey ?: return}", .parsedSafe<ExternalResponse>()?.data ?: return
headers = headers
).parsedSafe<ExternalResponse>()?.data
val fids = if (season == null) { val fids = if (season == null) {
shareRes?.file_list shareRes.file_list
} else { } else {
val parentId = val parentId = shareRes.file_list?.find { it.file_name.equals("season $season", true) }?.fid
shareRes?.file_list?.find { it.file_name.equals("season $season", true) }?.fid app.get("$thirdAPI/file/file_share_list?share_key=$shareKey&parent_id=$parentId&page=1", headers = headers)
app.get( .parsedSafe<ExternalResponse>()?.data?.file_list?.filter {
"$thirdAPI/file/file_share_list?share_key=$shareKey&parent_id=$parentId&page=1", it.file_name?.contains("s${seasonSlug}e${episodeSlug}", true) == true
headers = headers }
).parsedSafe<ExternalResponse>()?.data?.file_list?.filter { } ?: return
it.file_name?.contains(
"s${seasonSlug}e${episodeSlug}",
true
) == true
}
}
fids?.apmapIndexed { index, fileList -> fids.apmapIndexed { index, fileList ->
val player = app.get("$thirdAPI/file/player?fid=${fileList.fid}&share_key=$shareKey").text val player = app.get("$thirdAPI/file/player?fid=${fileList.fid}&share_key=$shareKey").text
val video = """"(https.*?m3u8.*?)"""".toRegex().find(player)?.groupValues?.get(1) val sources = "sources\\s*=\\s*(.*);".toRegex().find(player)?.groupValues?.get(1)
callback.invoke( val qualities = "quality_list\\s*=\\s*(.*);".toRegex().find(player)?.groupValues?.get(1)
ExtractorLink( listOf(sources, qualities).forEach {
"External", AppUtils.tryParseJson<ArrayList<ExternalSources>>(it)?.forEach org@{ source ->
"External [Server ${index + 1}]", val format = if (source.type == "video/mp4") ExtractorLinkType.VIDEO else ExtractorLinkType.M3U8
video?.replace("\\/", "/") ?: return@apmapIndexed, val label = if (format == ExtractorLinkType.M3U8) "Hls" else "Mp4"
"$thirdAPI/", if(!(source.label == "AUTO" || format == ExtractorLinkType.VIDEO)) return@org
getIndexQuality(fileList.file_name), callback.invoke(
isM3u8 = true ExtractorLink(
) "External",
) "External $label [Server ${index + 1}]",
(source.m3u8_url ?: source.file)?.replace("\\/", "/") ?: return@org,
"",
getIndexQuality(if (format == ExtractorLinkType.M3U8) fileList.file_name else source.label),
type = format,
)
)
}
}
} }
} }

View File

@ -623,7 +623,6 @@ open class Superstream : MainAPI() {
} }
} }
private data class LinkData( private data class LinkData(
val id: Int, val id: Int,
val type: Int, val type: Int,
@ -633,7 +632,6 @@ open class Superstream : MainAPI() {
val imdbId: String?, val imdbId: String?,
) )
data class LinkDataProp( data class LinkDataProp(
@JsonProperty("code") val code: Int? = null, @JsonProperty("code") val code: Int? = null,
@JsonProperty("msg") val msg: String? = null, @JsonProperty("msg") val msg: String? = null,
@ -776,6 +774,13 @@ open class Superstream : MainAPI() {
} }
} }
data class ExternalSources(
@JsonProperty("m3u8_url") val m3u8_url: String? = null,
@JsonProperty("file") val file: String? = null,
@JsonProperty("label") val label: String? = null,
@JsonProperty("type") val type: String? = null,
)
data class WatchsomuchTorrents( data class WatchsomuchTorrents(
@JsonProperty("id") val id: Int? = null, @JsonProperty("id") val id: Int? = null,
@JsonProperty("movieId") val movieId: Int? = null, @JsonProperty("movieId") val movieId: Int? = null,

View File

@ -1,5 +1,5 @@
// use an integer for version numbers // use an integer for version numbers
version = 22 version = 23
cloudstream { cloudstream {

View File

@ -4,7 +4,7 @@ import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.utils.AppUtils import com.lagradost.cloudstream3.utils.AppUtils
import com.lagradost.cloudstream3.utils.AppUtils.toJson import com.lagradost.cloudstream3.utils.AppUtils.toJson
import com.lagradost.cloudstream3.utils.ExtractorLink import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.M3u8Helper import com.lagradost.cloudstream3.utils.Qualities
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import java.net.URI import java.net.URI
@ -14,22 +14,22 @@ class TimefourTv : MainAPI() {
override val hasDownloadSupport = false override val hasDownloadSupport = false
override val hasMainPage = true override val hasMainPage = true
override val supportedTypes = setOf( override val supportedTypes = setOf(
TvType.Live TvType.Live
) )
private val homePoster = private val homePoster =
"https://cdn.discordapp.com/attachments/1109266606292488297/1193060449193840681/Screenshot_2024-01-06_at_12-14-16_Logo_Maker_Used_By_2.3_Million_Startups.png" "https://cdn.discordapp.com/attachments/1109266606292488297/1193060449193840681/Screenshot_2024-01-06_at_12-14-16_Logo_Maker_Used_By_2.3_Million_Startups.png"
private val detailPoster = private val detailPoster =
"https://cdn.discordapp.com/attachments/1109266606292488297/1193060448929595454/Screenshot_2024-01-06_at_12-13-02_Logo_Maker_Used_By_2.3_Million_Startups.png" "https://cdn.discordapp.com/attachments/1109266606292488297/1193060448929595454/Screenshot_2024-01-06_at_12-13-02_Logo_Maker_Used_By_2.3_Million_Startups.png"
override val mainPage = mainPageOf( override val mainPage = mainPageOf(
"$mainUrl/24-7-channels.php" to "24/7 Channels", "$mainUrl/24-7-channels.php" to "24/7 Channels",
"$mainUrl/schedule/schedule-generated.json" to "Schedule Channels" "$mainUrl/schedule/schedule-generated.json" to "Schedule Channels"
) )
override suspend fun getMainPage( override suspend fun getMainPage(
page: Int, page: Int,
request: MainPageRequest request: MainPageRequest
): HomePageResponse { ): HomePageResponse {
val items = mutableListOf<HomePageList>() val items = mutableListOf<HomePageList>()
if (request.name == "24/7 Channels") { if (request.name == "24/7 Channels") {
@ -46,11 +46,11 @@ class TimefourTv : MainAPI() {
val header = tag.key val header = tag.key
val channels = tag.value.mapNotNull { val channels = tag.value.mapNotNull {
LiveSearchResponse( LiveSearchResponse(
it.key, it.key,
Item(it.key, items = it.value.toJson()).toJson(), Item(it.key, items = it.value.toJson()).toJson(),
this@TimefourTv.name, this@TimefourTv.name,
TvType.Live, TvType.Live,
posterUrl = homePoster, posterUrl = homePoster,
) )
} }
if (channels.isNotEmpty()) items.add(HomePageList(header, channels, true)) if (channels.isNotEmpty()) items.add(HomePageList(header, channels, true))
@ -64,11 +64,11 @@ class TimefourTv : MainAPI() {
val title = this.select("strong").text() val title = this.select("strong").text()
val href = fixUrl(this.select("a").attr("href")) val href = fixUrl(this.select("a").attr("href"))
return LiveSearchResponse( return LiveSearchResponse(
title, title,
Item(title, href).toJson(), Item(title, href).toJson(),
this@TimefourTv.name, this@TimefourTv.name,
TvType.Live, TvType.Live,
posterUrl = homePoster, posterUrl = homePoster,
) )
} }
@ -88,18 +88,18 @@ class TimefourTv : MainAPI() {
val items = AppUtils.parseJson<ArrayList<Items>>(data.items) val items = AppUtils.parseJson<ArrayList<Items>>(data.items)
items.mapNotNull { eps -> items.mapNotNull { eps ->
Episode( Episode(
data = eps.channels?.toJson() ?: return@mapNotNull null, data = eps.channels?.toJson() ?: return@mapNotNull null,
name = "${eps.event}${eps.time}", name = "${eps.event}${eps.time}",
description = eps.channels.map { it.channel_name }.joinToString(""), description = eps.channels.map { it.channel_name }.joinToString(""),
posterUrl = detailPoster, posterUrl = detailPoster,
) )
} }
} }
return newTvSeriesLoadResponse( return newTvSeriesLoadResponse(
data.title ?: "", data.title ?: "",
url, url,
TvType.TvSeries, TvType.TvSeries,
episodes = episodes episodes = episodes
) { ) {
posterUrl = homePoster posterUrl = homePoster
} }
@ -107,29 +107,34 @@ class TimefourTv : MainAPI() {
} }
override suspend fun loadLinks( override suspend fun loadLinks(
data: String, data: String,
isCasting: Boolean, isCasting: Boolean,
subtitleCallback: (SubtitleFile) -> Unit, subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit callback: (ExtractorLink) -> Unit
): Boolean { ): Boolean {
val json = AppUtils.parseJson<ArrayList<Channels>>(data) val json = AppUtils.parseJson<ArrayList<Channels>>(data)
json.apmap { json.apmap {
val iframe = app.get( val iframe = app.get(
fixChannelUrl( fixChannelUrl(
it.channel_id ?: return@apmap it.channel_id ?: return@apmap
) )
).document.selectFirst("iframe#thatframe")?.attr("src") ).document.selectFirst("iframe#thatframe")?.attr("src")
?: throw ErrorLoadingException("No Iframe Found") ?: throw ErrorLoadingException("No Iframe Found")
val host = getBaseUrl(iframe) val host = getBaseUrl(iframe)
val video = extractVideo(iframe) val video = extractVideo(iframe)
M3u8Helper.generateM3u8( callback.invoke(
ExtractorLink(
this.name,
it.channel_name ?: return@apmap, it.channel_name ?: return@apmap,
video ?: return@apmap, video ?: return@apmap,
"$host/", "$host/",
).forEach(callback) Qualities.Unknown.value,
isM3u8 = true,
)
)
} }
return true return true
@ -138,13 +143,13 @@ class TimefourTv : MainAPI() {
private suspend fun extractVideo(url: String): String? { private suspend fun extractVideo(url: String): String? {
val res = app.get(url, referer = mainUrl) val res = app.get(url, referer = mainUrl)
return Regex("""source:['"](\S+.m3u8)['"],""").find(res.text)?.groupValues?.getOrNull( return Regex("""source:['"](\S+.m3u8)['"],""").find(res.text)?.groupValues?.getOrNull(
1 1
) ?: run { ) ?: run {
val scriptData = val scriptData =
res.document.selectFirst("div#player")?.nextElementSibling()?.data() res.document.selectFirst("div#player")?.nextElementSibling()?.data()
?.substringAfterLast("return(")?.substringBefore(".join") ?.substringAfterLast("return(")?.substringBefore(".join")
scriptData?.removeSurrounding("[", "]")?.replace("\"", "")?.split(",") scriptData?.removeSurrounding("[", "]")?.replace("\"", "")?.split(",")
?.joinToString("") ?.joinToString("")
} }
} }
@ -163,20 +168,20 @@ class TimefourTv : MainAPI() {
} }
data class Item( data class Item(
val title: String? = null, val title: String? = null,
val url: String? = null, val url: String? = null,
val items: String? = null, val items: String? = null,
) )
data class Items( data class Items(
val time: String? = null, val time: String? = null,
val event: String? = null, val event: String? = null,
val channels: ArrayList<Channels>? = arrayListOf(), val channels: ArrayList<Channels>? = arrayListOf(),
) )
data class Channels( data class Channels(
val channel_name: String? = null, val channel_name: String? = null,
val channel_id: String? = null, val channel_id: String? = null,
) )
} }

View File

@ -77,7 +77,7 @@ subprojects {
// https://github.com/recloudstream/cloudstream/blob/master/app/build.gradle // https://github.com/recloudstream/cloudstream/blob/master/app/build.gradle
implementation(kotlin("stdlib")) // adds standard kotlin features, like listOf, mapOf etc implementation(kotlin("stdlib")) // adds standard kotlin features, like listOf, mapOf etc
implementation("com.github.Blatzar:NiceHttp:0.4.4") // http library implementation("com.github.Blatzar:NiceHttp:0.4.5") // http library
implementation("org.jsoup:jsoup:1.17.2") // html parser implementation("org.jsoup:jsoup:1.17.2") // html parser
implementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.16.1") implementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.16.1")
implementation("io.karn:khttp-android:0.1.2") implementation("io.karn:khttp-android:0.1.2")