sora: fix m4uhd

This commit is contained in:
lisa 2023-12-23 09:16:09 +07:00
parent 928db8c7ff
commit 211c58b0ef
9 changed files with 103 additions and 138 deletions

View file

@ -55,7 +55,6 @@ jobs:
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 }} OMOVIES_API: ${{ secrets.OMOVIES_API }}
FEBBOX_API: ${{ secrets.FEBBOX_API }}
run: | run: |
cd $GITHUB_WORKSPACE/src cd $GITHUB_WORKSPACE/src
echo TMDB_API=$TMDB_API >> local.properties echo TMDB_API=$TMDB_API >> local.properties
@ -71,7 +70,6 @@ jobs:
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 OMOVIES_API=$OMOVIES_API >> local.properties
echo FEBBOX_API=$FEBBOX_API >> local.properties
- name: Build Plugins - name: Build Plugins
run: | run: |

View file

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

View file

@ -9,7 +9,7 @@ import org.jsoup.nodes.Element
class LayarKacaProvider : MainAPI() { class LayarKacaProvider : MainAPI() {
override var mainUrl = "https://tv6.lk21official.wiki" override var mainUrl = "https://tv6.lk21official.wiki"
private var seriesUrl = "https://tv8.nontondrama.click/" private var seriesUrl = "https://tv8.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"
@ -40,6 +40,7 @@ class LayarKacaProvider : MainAPI() {
} }
private suspend fun getProperLink(url: String): String? { private suspend fun getProperLink(url: String): String? {
if(url.startsWith(seriesUrl)) return url
val res = app.get(url).document val res = app.get(url).document
return if (res.select("title").text().contains("- Nontondrama", true)) { return if (res.select("title").text().contains("- Nontondrama", true)) {
res.selectFirst("div#content a")?.attr("href") res.selectFirst("div#content a")?.attr("href")

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 = 207 version = 208
android { android {
defaultConfig { defaultConfig {
@ -9,7 +9,6 @@ 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", "FEBBOX_API", "\"${properties.getProperty("FEBBOX_API")}\"")
buildConfigField("String", "OMOVIES_API", "\"${properties.getProperty("OMOVIES_API")}\"") buildConfigField("String", "OMOVIES_API", "\"${properties.getProperty("OMOVIES_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")}\"")

View file

@ -209,7 +209,10 @@ open class VCloud : ExtractorApi() {
) )
).document.select("p.text-success ~ a").apmap { ).document.select("p.text-success ~ a").apmap {
val link = it.attr("href") val link = it.attr("href")
if (link.contains("workers.dev") || it.text().contains("[Server : 1]") || link.contains("/dl.php?")) { if (link.contains("workers.dev") || it.text().contains("[Server : 1]") || link.contains(
"/dl.php?"
)
) {
callback.invoke( callback.invoke(
ExtractorLink( ExtractorLink(
this.name, this.name,
@ -247,12 +250,14 @@ open class Streamruby : ExtractorApi() {
callback: (ExtractorLink) -> Unit callback: (ExtractorLink) -> Unit
) { ) {
val id = "/e/(\\w+)".toRegex().find(url)?.groupValues?.get(1) ?: return val id = "/e/(\\w+)".toRegex().find(url)?.groupValues?.get(1) ?: return
val response = app.post("$mainUrl/dl", data = mapOf( val response = app.post(
"$mainUrl/dl", data = mapOf(
"op" to "embed", "op" to "embed",
"file_code" to id, "file_code" to id,
"auto" to "1", "auto" to "1",
"referer" to "", "referer" to "",
), referer = referer) ), referer = referer
)
val script = if (!getPacked(response.text).isNullOrEmpty()) { val script = if (!getPacked(response.text).isNullOrEmpty()) {
getAndUnpack(response.text) getAndUnpack(response.text)
} else { } else {
@ -282,17 +287,25 @@ open class Uploadever : ExtractorApi() {
) { ) {
var res = app.get(url, referer = referer).document var res = app.get(url, referer = referer).document
val formUrl = res.select("form").attr("action") val formUrl = res.select("form").attr("action")
var formData = res.select("form input").associate { it.attr("name") to it.attr("value") }.filterKeys { it != "go" } var formData = res.select("form input").associate { it.attr("name") to it.attr("value") }
.filterKeys { it != "go" }
.toMutableMap() .toMutableMap()
val formReq = app.post(formUrl, data = formData) val formReq = app.post(formUrl, data = formData)
res = formReq.document res = formReq.document
val captchaKey = res.select("script[src*=https://www.google.com/recaptcha/api.js?render=]").attr("src").substringAfter("render=") val captchaKey =
res.select("script[src*=https://www.google.com/recaptcha/api.js?render=]").attr("src")
.substringAfter("render=")
val token = getCaptchaToken(url, captchaKey, referer = "$mainUrl/") val token = getCaptchaToken(url, captchaKey, referer = "$mainUrl/")
formData = res.select("form#down input").associate { it.attr("name") to it.attr("value") }.toMutableMap() formData = res.select("form#down input").associate { it.attr("name") to it.attr("value") }
.toMutableMap()
formData["adblock_detected"] = "0" formData["adblock_detected"] = "0"
formData["referer"] = url formData["referer"] = url
res = app.post(formReq.url, data = formData + mapOf("g-recaptcha-response" to "$token"), cookies = formReq.cookies).document res = app.post(
formReq.url,
data = formData + mapOf("g-recaptcha-response" to "$token"),
cookies = formReq.cookies
).document
val video = res.select("div.download-button a.btn.btn-dow.recaptchav2").attr("href") val video = res.select("div.download-button a.btn.btn-dow.recaptchav2").attr("href")
callback.invoke( callback.invoke(
@ -325,18 +338,7 @@ open class Netembed : ExtractorApi() {
val script = getAndUnpack(response.text) val script = getAndUnpack(response.text)
val m3u8 = Regex("((https:|http:)//.*\\.m3u8)").find(script)?.groupValues?.getOrNull(1) ?: return val m3u8 = Regex("((https:|http:)//.*\\.m3u8)").find(script)?.groupValues?.getOrNull(1) ?: return
if(m3u8.startsWith("https://www.febbox.com")) { if (!m3u8.startsWith("https://www.febbox.com")) {
callback.invoke(
ExtractorLink(
this.name,
this.name,
m3u8,
"$mainUrl/",
getQuality(m3u8),
INFER_TYPE
)
)
} else {
M3u8Helper.generateM3u8( M3u8Helper.generateM3u8(
this.name, this.name,
m3u8, m3u8,
@ -344,12 +346,6 @@ open class Netembed : ExtractorApi() {
).forEach(callback) ).forEach(callback)
} }
} }
private suspend fun getQuality(url: String) : Int {
val res = app.get(url, referer = "$mainUrl/").text
val regex = "#quality:\\s*(\\S+)".toRegex().find(res)?.groupValues?.get(1)
return getQualityFromName(regex)
}
} }
class Streamwish : Filesim() { class Streamwish : Filesim() {

View file

@ -1354,14 +1354,14 @@ object SoraExtractor : SoraStream() {
subtitleCallback: (SubtitleFile) -> Unit, subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit callback: (ExtractorLink) -> Unit
) { ) {
val slugTitle = title.createSlug()
val (seasonSlug, episodeSlug) = getEpisodeSlug(season, episode) val (seasonSlug, episodeSlug) = getEpisodeSlug(season, episode)
val req = app.get("$m4uhdAPI/search/${title.createSlug()}.html") val req = app.get("$m4uhdAPI/search/$slugTitle.html")
val referer = getBaseUrl(req.url) val referer = getBaseUrl(req.url)
val scriptData = req.document.select("div.row div.item").map { ele -> val scriptData = req.document.select("div.row div.item").map { ele ->
Triple( Triple(
ele.select("div.tiptitle p").text(), ele.select("div.tiptitle p").text().substringBefore("(").trim().createSlug(),
ele.select("div.jtip-top div:last-child").text().substringBefore("") ele.select("div.jtip-top div:last-child").text().filter { it.isDigit() },
.filter { it.isDigit() },
ele.selectFirst("a")?.attr("href") ele.selectFirst("a")?.attr("href")
) )
} }
@ -1370,7 +1370,7 @@ object SoraExtractor : SoraStream() {
scriptData.firstOrNull() scriptData.firstOrNull()
} else { } else {
scriptData.find { scriptData.find {
it.first.contains(Regex("(?i)$title \\($year\\s?\\)")) && if (season != null) it.third?.contains( it.first.equals(slugTitle) && it.second == "$year" && if (season != null) it.third?.contains(
"-tvshow-" "-tvshow-"
) == true else it.third?.contains("-movie-") == true ) == true else it.third?.contains("-movie-") == true
} }
@ -2133,52 +2133,6 @@ object SoraExtractor : SoraStream() {
} }
suspend fun invokeBlackvid(
tmdbId: Int? = null,
season: Int? = null,
episode: Int? = null,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit,
) {
val key = "b6055c533c19131a638c3d2299d525d5ec08a814"
val url = if (season == null) {
"$blackvidAPI/v3/movie/sources/$tmdbId?key=$key"
} else {
"$blackvidAPI/v3/tv/sources/$tmdbId/$season/$episode?key=$key"
}
val res = request(url).peekBody(1024 * 512)
val bytes = res.bytes().also { res.closeQuietly() }
val data = bytes.decrypt("2378f8e4e844f2dc839ab48f66e00acc2305a401")
val json = tryParseJson<BlackvidResponses>(data)
json?.sources?.map { source ->
source.sources.map s@{ s ->
callback.invoke(
ExtractorLink(
"Blackvid",
"Blackvid${source.label}",
s.url ?: return@s,
"https://blackvid.space/",
if (s.quality.equals("4k")) Qualities.P2160.value else s.quality?.toIntOrNull()
?: Qualities.P1080.value,
INFER_TYPE
)
)
}
}
json?.subtitles?.map { sub ->
subtitleCallback.invoke(
SubtitleFile(
sub.language.takeIf { it?.isNotEmpty() == true } ?: return@map,
sub.url ?: return@map,
)
)
}
}
suspend fun invokeShowflix( suspend fun invokeShowflix(
title: String? = null, title: String? = null,
year: Int? = null, year: Int? = null,
@ -2312,31 +2266,62 @@ object SoraExtractor : SoraStream() {
} }
suspend fun invokeFebbox( suspend fun invokeFebbox(
imdbId: String? = null, title: String? = null,
year: Int? = null,
season: Int? = null, season: Int? = null,
episode: Int? = null, episode: Int? = null,
callback: (ExtractorLink) -> Unit, callback: (ExtractorLink) -> Unit,
) { ) {
val url = if (season == null) { val showboxApi = "https://www.showbox.media"
"$febboxAPI/stream/movie/$imdbId.json" val (seasonSlug, episodeSlug) = getEpisodeSlug(season, episode)
val res = app.post(
"$showboxApi/search/autocomplate2", data = mapOf(
"keyword" to "$title"
), headers = mapOf("X-Requested-With" to "XMLHttpRequest")
).parsed<String>().let { Jsoup.parse(it) }
val mediaId = res.select("a.nav-item").find {
it.select("h3.film-name").text()
.equals(title, true) && it.select("div.film-infor > span:first-child").text()
.contains(if (season == null) "$year" else "SS") && it.select("div.film-infor > span:last-child")
.text()
.equals(if (season == null) "Movie" else "TV")
}?.attr("href")?.substringAfterLast("/")
val shareKey =
app.get("$showboxApi/index/share_link?id=${mediaId ?: return}&type=${if (season == null) "1" else "2"}")
.parsedSafe<FebboxResponse>()?.data?.link?.substringAfterLast("/")
val headers = mapOf("Accept-Language" to "en")
val shareRes = app.get("$febboxAPI/file/file_share_list?share_key=${shareKey ?: return}", headers = headers)
.parsedSafe<FebboxResponse>()?.data
val fids = if (season == null) {
shareRes?.file_list
} else { } else {
"$febboxAPI/stream/series/$imdbId:$season:$episode.json" val parentId = shareRes?.file_list?.find { it.file_name.equals("season $season", true) }?.fid
app.get("$febboxAPI/file/file_share_list?share_key=${shareKey}&parent_id=$parentId&page=1", headers = headers)
.parsedSafe<FebboxResponse>()?.data?.file_list?.filter {
it.file_name?.contains(
"s${seasonSlug}e${episodeSlug}",
true
) == true
}
} }
val res = request(url).body fids?.mapIndexed { index, fileList ->
val data = res.string().also { res.closeQuietly() }
val video = tryParseJson<FebboxResponse>(data)?.streams?.find { it.url?.startsWith("https://www.febbox.com") == true }?.url
callback.invoke( callback.invoke(
ExtractorLink( ExtractorLink(
"Febbox", "Febbox",
"Febbox", "Febbox [Server $index]",
video ?: return, "$febboxAPI/hls/main/${fileList.oss_fid}.m3u8",
"", "",
Qualities.P1080.value, getIndexQuality(fileList.file_name),
INFER_TYPE isM3u8 = true
) )
) )
}
} }

View file

@ -334,26 +334,6 @@ data class EMovieTraks(
@JsonProperty("label") val label: String? = null, @JsonProperty("label") val label: String? = null,
) )
data class BlackvidSubtitles(
@JsonProperty("language") val language: String? = null,
@JsonProperty("url") val url: String? = null,
)
data class BlackvidSource(
@JsonProperty("quality") var quality: String? = null,
@JsonProperty("url") var url: String? = null,
)
data class BlackvidSources(
@JsonProperty("label") var label: String? = null,
@JsonProperty("sources") var sources: ArrayList<BlackvidSource> = arrayListOf()
)
data class BlackvidResponses(
@JsonProperty("sources") var sources: ArrayList<BlackvidSources> = arrayListOf(),
@JsonProperty("subtitles") var subtitles: ArrayList<BlackvidSubtitles> = arrayListOf()
)
data class ShowflixResultsMovies( data class ShowflixResultsMovies(
@JsonProperty("movieName") val movieName: String? = null, @JsonProperty("movieName") val movieName: String? = null,
@JsonProperty("streamwish") val streamwish: String? = null, @JsonProperty("streamwish") val streamwish: String? = null,
@ -464,9 +444,16 @@ data class AoneroomResponse(
} }
data class FebboxResponse( data class FebboxResponse(
@JsonProperty("streams") val streams: ArrayList<Streams>? = arrayListOf(), @JsonProperty("data") val data: Data? = null,
) { ) {
data class Streams( data class Data(
@JsonProperty("url") val url: String? = null, @JsonProperty("link") val link: String? = null,
@JsonProperty("file_list") val file_list: ArrayList<FileList>? = arrayListOf(),
) {
data class FileList(
@JsonProperty("fid") val fid: Long? = null,
@JsonProperty("file_name") val file_name: String? = null,
@JsonProperty("oss_fid") val oss_fid: Long? = null,
) )
} }
}

View file

@ -4,7 +4,6 @@ import com.fasterxml.jackson.annotation.JsonProperty
import com.hexated.SoraExtractor.invoke2embed import com.hexated.SoraExtractor.invoke2embed
import com.hexated.SoraExtractor.invokeAnimes import com.hexated.SoraExtractor.invokeAnimes
import com.hexated.SoraExtractor.invokeAoneroom import com.hexated.SoraExtractor.invokeAoneroom
import com.hexated.SoraExtractor.invokeBlackvid
import com.hexated.SoraExtractor.invokeBollyMaza import com.hexated.SoraExtractor.invokeBollyMaza
import com.hexated.SoraExtractor.invokeDbgo import com.hexated.SoraExtractor.invokeDbgo
import com.hexated.SoraExtractor.invokeFilmxy import com.hexated.SoraExtractor.invokeFilmxy
@ -113,10 +112,9 @@ open class SoraStream : TmdbProvider() {
const val dramadayAPI = "https://dramaday.me" const val dramadayAPI = "https://dramaday.me"
const val animetoshoAPI = "https://animetosho.org" const val animetoshoAPI = "https://animetosho.org"
const val watchflxAPI = "https://watchflx.tv" const val watchflxAPI = "https://watchflx.tv"
const val blackvidAPI = "https://prod.api.blackvid.space"
const val showflixAPI = "https://showflix.space" const val showflixAPI = "https://showflix.space"
const val aoneroomAPI = "https://api3.aoneroom.com" const val aoneroomAPI = "https://api3.aoneroom.com"
const val febboxAPI = BuildConfig.FEBBOX_API const val febboxAPI = "https://www.febbox.com"
const val fdMoviesAPI = "https://freedrivemovie.lol" const val fdMoviesAPI = "https://freedrivemovie.lol"
const val uhdmoviesAPI = "https://uhdmovies.zip" const val uhdmoviesAPI = "https://uhdmovies.zip"
@ -364,8 +362,9 @@ open class SoraStream : TmdbProvider() {
argamap( argamap(
{ {
if (!res.isAnime) invokeFebbox( invokeFebbox(
res.imdbId, res.title,
res.year,
res.season, res.season,
res.episode, res.episode,
callback callback

View file

@ -3,7 +3,6 @@ package com.hexated
import com.hexated.SoraExtractor.invoke2embed import com.hexated.SoraExtractor.invoke2embed
import com.hexated.SoraExtractor.invokeAnimes import com.hexated.SoraExtractor.invokeAnimes
import com.hexated.SoraExtractor.invokeAoneroom import com.hexated.SoraExtractor.invokeAoneroom
import com.hexated.SoraExtractor.invokeBlackvid
import com.hexated.SoraExtractor.invokeDbgo 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
@ -54,8 +53,9 @@ class SoraStreamLite : SoraStream() {
argamap( argamap(
{ {
if (!res.isAnime) invokeFebbox( invokeFebbox(
res.imdbId, res.title,
res.year,
res.season, res.season,
res.episode, res.episode,
callback callback