[test] Adding UHDMovies into SoraExtractor

This commit is contained in:
hexated 2022-11-21 17:27:07 +07:00
parent de52441ad0
commit 6c10e59ee5
9 changed files with 135 additions and 17 deletions

View file

@ -7,7 +7,7 @@ cloudstream {
// All of these properties are optional, you can safely remove them // All of these properties are optional, you can safely remove them
description = "Premium porn with 4K support (use VPN if links not working)" description = "Premium porn with 4K support (use VPN if links not working)"
authors = listOf("Hexated") authors = listOf("Sora")
/** /**
* Status int as the following: * Status int as the following:

View file

@ -7,7 +7,7 @@ cloudstream {
// 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 = "Lorem Ipsum"
authors = listOf("Hexated") authors = listOf("Sora")
/** /**
* Status int as the following: * Status int as the following:

View file

@ -6,7 +6,7 @@ cloudstream {
language = "en" language = "en"
// All of these properties are optional, you can safely remove them // All of these properties are optional, you can safely remove them
description = "#1 best extension based on Loklok API" description = "#2 best extension based on Loklok API"
authors = listOf("Hexated") authors = listOf("Hexated")
/** /**

View file

@ -7,7 +7,7 @@ cloudstream {
// All of these properties are optional, you can safely remove them // All of these properties are optional, you can safely remove them
description = "Series porn (use VPN if links not working)" description = "Series porn (use VPN if links not working)"
authors = listOf("Hexated") authors = listOf("Sora")
/** /**
* Status int as the following: * Status int as the following:

View file

@ -1,12 +1,12 @@
// use an integer for version numbers // use an integer for version numbers
version = 32 version = 33
cloudstream { cloudstream {
language = "en" language = "en"
// All of these properties are optional, you can safely remove them // All of these properties are optional, you can safely remove them
description = "#2 best extention based on MultiAPI" description = "#1 best extention based on MultiAPI"
authors = listOf("Hexated", "Sora") authors = listOf("Hexated", "Sora")
/** /**

View file

@ -1163,18 +1163,13 @@ object SoraExtractor : SoraStream() {
val source = app.get(iframe ?: return) val source = app.get(iframe ?: return)
val link = Regex("((https:|http:)//.*\\.mp4)").find(source.text)?.value ?: return val link = Regex("((https:|http:)//.*\\.mp4)").find(source.text)?.value ?: return
val quality = when {
link.contains("1080p") -> Qualities.P1080.value
link.contains("720p") -> Qualities.P720.value
else -> Qualities.Unknown.value
}
callback.invoke( callback.invoke(
ExtractorLink( ExtractorLink(
"Ling", "Ling",
"Ling", "Ling",
link, link,
"$lingAPI/", "$lingAPI/",
quality, Qualities.Unknown.value,
headers = mapOf( headers = mapOf(
"Range" to "bytes=0-" "Range" to "bytes=0-"
) )
@ -1192,6 +1187,81 @@ object SoraExtractor : SoraStream() {
} }
suspend fun invokeUhdmovies(
title: String? = null,
year: Int? = null,
season: Int? = null,
lastSeason: Int? = null,
episode: Int? = null,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
) {
val doc = app.get("$uhdmoviesAPI/?s=$title").document
val scriptData = doc.select("div.row.gridlove-posts article").map {
it.selectFirst("a")?.attr("href") to it.selectFirst("h1")?.text()
}
val script = if (scriptData.size == 1) {
scriptData.first()
} else {
scriptData.find { it.second?.filterMedia(title, year, lastSeason) == true }
}
val detailDoc = app.get(script?.first ?: return).document
val iframe =
detailDoc.select("div.entry-content p").map { it }
.filter { it.text().filterIframe(season, year) }
.mapNotNull {
if (season == null) {
Triple(
it.ownText(),
it.selectFirst("span")?.text(),
it.nextElementSibling()?.select("a")?.attr("href")
)
} else {
Triple(
it.ownText(),
it.selectFirst("span")?.text(),
it.nextElementSibling()?.select("a:contains(Episode $episode)")
?.attr("href")
)
}
}
iframe.apmap { (quality, size, link) ->
val res = app.get(link ?: return@apmap null).document
val base = getBaseUrl(link)
val bitLink =
res.selectFirst("a.btn.btn-outline-success")?.attr("href") ?: return@apmap null
val downLink =
app.get(fixUrl(bitLink, base)).document.selectFirst("div.mb-4 a")?.attr("href")
val mirrorLink = app.get(
downLink ?: return@apmap null
).document.selectFirst("form[method=post] a.btn.btn-primary")
?.attr("onclick")?.substringAfter("Openblank('")?.substringBefore("')")?.let {
app.get(it).document.selectFirst("script:containsData(input.value =)")
?.data()?.substringAfter("input.value = '")?.substringBefore("';")
}
val videoQuality = Regex("(\\d{3,4})p").find(quality)?.groupValues?.getOrNull(1)?.toIntOrNull()
?: Qualities.Unknown.value
val videoSize = size?.substringBeforeLast("/")
callback.invoke(
ExtractorLink(
"UHDMovies [$videoSize]",
"UHDMovies [$videoSize]",
mirrorLink ?: return@apmap null,
"",
videoQuality
)
)
}
}
} }
data class FilmxyCookies( data class FilmxyCookies(
@ -1200,6 +1270,31 @@ data class FilmxyCookies(
val wSec: String? = null, val wSec: String? = null,
) )
fun String.filterIframe(seasonNum: Int?, year: Int?): Boolean {
return if (seasonNum != null) {
this.contains(Regex("(?i)(S0?$seasonNum)")) && !this.contains("Download", true)
} else {
this.contains("$year", true) && !this.contains("Download", true)
}
}
fun String.filterMedia(title: String?, yearNum: Int?, seasonNum: Int?): Boolean {
return if (seasonNum != null) {
when {
seasonNum > 1 -> this.contains(Regex("(?i)(Season\\s0?1-0?$seasonNum)|(S0?1-S?0?$seasonNum)")) && this.contains(
"$title",
true
) && this.contains("$yearNum")
else -> this.contains(Regex("(?i)(Season\\s0?1)|(S0?1)")) && this.contains(
"$title",
true
) && this.contains("$yearNum")
}
} else {
this.contains("$title", true) && this.contains("$yearNum")
}
}
suspend fun getFilmxyCookies(imdbId: String? = null, season: Int? = null): FilmxyCookies? { suspend fun getFilmxyCookies(imdbId: String? = null, season: Int? = null): FilmxyCookies? {
val url = if (season == null) { val url = if (season == null) {

View file

@ -23,6 +23,7 @@ import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer
import com.lagradost.cloudstream3.metaproviders.TmdbProvider import com.lagradost.cloudstream3.metaproviders.TmdbProvider
import com.hexated.SoraExtractor.invoZoro import com.hexated.SoraExtractor.invoZoro
import com.hexated.SoraExtractor.invokeLing import com.hexated.SoraExtractor.invokeLing
import com.hexated.SoraExtractor.invokeUhdmovies
import com.lagradost.cloudstream3.utils.AppUtils.parseJson 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.ExtractorLink import com.lagradost.cloudstream3.utils.ExtractorLink
@ -69,6 +70,7 @@ open class SoraStream : TmdbProvider() {
const val consumetZoroAPI = "https://api.consumet.org/anime/zoro" const val consumetZoroAPI = "https://api.consumet.org/anime/zoro"
const val kissKhAPI = "https://kisskh.me" const val kissKhAPI = "https://kisskh.me"
const val lingAPI = "https://ling-online.net" const val lingAPI = "https://ling-online.net"
const val uhdmoviesAPI = "https://uhdmovies.site"
fun getType(t: String?): TvType { fun getType(t: String?): TvType {
return when (t) { return when (t) {
@ -209,6 +211,7 @@ open class SoraStream : TmdbProvider() {
return if (type == TvType.TvSeries) { return if (type == TvType.TvSeries) {
val episodes = mutableListOf<Episode>() val episodes = mutableListOf<Episode>()
val lastSeason = res.seasons?.lastOrNull()?.seasonNumber
res.seasons?.apmap { season -> res.seasons?.apmap { season ->
app.get("$tmdbAPI/${data.type}/${data.id}/season/${season.seasonNumber}?api_key=$apiKey") app.get("$tmdbAPI/${data.type}/${data.id}/season/${season.seasonNumber}?api_key=$apiKey")
.parsedSafe<MediaDetailEpisodes>()?.episodes?.map { eps -> .parsedSafe<MediaDetailEpisodes>()?.episodes?.map { eps ->
@ -223,7 +226,8 @@ open class SoraStream : TmdbProvider() {
year = season.airDate?.split("-")?.first()?.toIntOrNull(), year = season.airDate?.split("-")?.first()?.toIntOrNull(),
orgTitle = orgTitle, orgTitle = orgTitle,
show = show, show = show,
airedYear = year airedYear = year,
lastSeason = lastSeason
).toJson(), ).toJson(),
name = eps.name, name = eps.name,
season = eps.seasonNumber, season = eps.seasonNumber,
@ -342,9 +346,9 @@ open class SoraStream : TmdbProvider() {
{ {
invokeVidSrc(res.id, res.season, res.episode, subtitleCallback, callback) invokeVidSrc(res.id, res.season, res.episode, subtitleCallback, callback)
}, },
{ // {
invokeOlgply(res.id, res.season, res.episode, callback) // invokeOlgply(res.id, res.season, res.episode, callback)
}, // },
{ {
invokeDbgo(res.imdbId, res.season, res.episode, subtitleCallback, callback) invokeDbgo(res.imdbId, res.season, res.episode, subtitleCallback, callback)
}, },
@ -447,6 +451,17 @@ open class SoraStream : TmdbProvider() {
callback callback
) )
}, },
{
invokeUhdmovies(
res.title,
res.year,
res.season,
res.lastSeason,
res.episode,
subtitleCallback,
callback
)
},
) )
return true return true
@ -465,6 +480,7 @@ open class SoraStream : TmdbProvider() {
val orgTitle: String? = null, val orgTitle: String? = null,
val show: String? = null, val show: String? = null,
val airedYear: Int? = null, val airedYear: Int? = null,
val lastSeason: Int? = null,
) )
data class Data( data class Data(

View file

@ -149,7 +149,7 @@ class WcofunProvider : MainAPI() {
"${this.name} ${source.second}", "${this.name} ${source.second}",
"${this.name} ${source.second}", "${this.name} ${source.second}",
"${it.server}/getvid?evid=${source.first}", "${it.server}/getvid?evid=${source.first}",
mainUrl, referer = mainUrl,
if (source.second == "HD") Qualities.P720.value else Qualities.P480.value if (source.second == "HD") Qualities.P720.value else Qualities.P480.value
) )
) )

View file

@ -1,5 +1,6 @@
import com.lagradost.cloudstream3.gradle.CloudstreamExtension import com.lagradost.cloudstream3.gradle.CloudstreamExtension
import com.android.build.gradle.BaseExtension import com.android.build.gradle.BaseExtension
import java.util.Properties
buildscript { buildscript {
repositories { repositories {
@ -47,6 +48,12 @@ subprojects {
defaultConfig { defaultConfig {
minSdk = 21 minSdk = 21
targetSdk = 32 targetSdk = 32
// val properties = Properties()
// properties.load(project.rootProject.file("local.properties").inputStream())
//
// buildConfigField("String", "API_KEY", "\"${properties.getProperty("API_KEY")}\"")
} }
compileOptions { compileOptions {