From 6c10e59ee5f3ef23930752f77fb840215ec01ab2 Mon Sep 17 00:00:00 2001 From: hexated Date: Mon, 21 Nov 2022 17:27:07 +0700 Subject: [PATCH] [test] Adding UHDMovies into SoraExtractor --- GoodPorn/build.gradle.kts | 2 +- Hentaiheaven/build.gradle.kts | 2 +- Loklok/build.gradle.kts | 2 +- Paradisehill/build.gradle.kts | 2 +- SoraStream/build.gradle.kts | 4 +- .../main/kotlin/com/hexated/SoraExtractor.kt | 107 +++++++++++++++++- .../src/main/kotlin/com/hexated/SoraStream.kt | 24 +++- .../main/kotlin/com/hexated/WcofunProvider.kt | 2 +- build.gradle.kts | 7 ++ 9 files changed, 135 insertions(+), 17 deletions(-) diff --git a/GoodPorn/build.gradle.kts b/GoodPorn/build.gradle.kts index ab96da41..a40d91b2 100644 --- a/GoodPorn/build.gradle.kts +++ b/GoodPorn/build.gradle.kts @@ -7,7 +7,7 @@ cloudstream { // All of these properties are optional, you can safely remove them description = "Premium porn with 4K support (use VPN if links not working)" - authors = listOf("Hexated") + authors = listOf("Sora") /** * Status int as the following: diff --git a/Hentaiheaven/build.gradle.kts b/Hentaiheaven/build.gradle.kts index 4e9adbad..b50b6865 100644 --- a/Hentaiheaven/build.gradle.kts +++ b/Hentaiheaven/build.gradle.kts @@ -7,7 +7,7 @@ cloudstream { // All of these properties are optional, you can safely remove them // description = "Lorem Ipsum" - authors = listOf("Hexated") + authors = listOf("Sora") /** * Status int as the following: diff --git a/Loklok/build.gradle.kts b/Loklok/build.gradle.kts index 223d458d..6cf3c0a9 100644 --- a/Loklok/build.gradle.kts +++ b/Loklok/build.gradle.kts @@ -6,7 +6,7 @@ cloudstream { language = "en" // 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") /** diff --git a/Paradisehill/build.gradle.kts b/Paradisehill/build.gradle.kts index a8f17b26..167fdc84 100644 --- a/Paradisehill/build.gradle.kts +++ b/Paradisehill/build.gradle.kts @@ -7,7 +7,7 @@ cloudstream { // All of these properties are optional, you can safely remove them description = "Series porn (use VPN if links not working)" - authors = listOf("Hexated") + authors = listOf("Sora") /** * Status int as the following: diff --git a/SoraStream/build.gradle.kts b/SoraStream/build.gradle.kts index b35f66bd..a03dcbed 100644 --- a/SoraStream/build.gradle.kts +++ b/SoraStream/build.gradle.kts @@ -1,12 +1,12 @@ // use an integer for version numbers -version = 32 +version = 33 cloudstream { language = "en" // 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") /** diff --git a/SoraStream/src/main/kotlin/com/hexated/SoraExtractor.kt b/SoraStream/src/main/kotlin/com/hexated/SoraExtractor.kt index ba5c1dfd..2d1d8332 100644 --- a/SoraStream/src/main/kotlin/com/hexated/SoraExtractor.kt +++ b/SoraStream/src/main/kotlin/com/hexated/SoraExtractor.kt @@ -1163,18 +1163,13 @@ object SoraExtractor : SoraStream() { val source = app.get(iframe ?: 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( ExtractorLink( "Ling", "Ling", link, "$lingAPI/", - quality, + Qualities.Unknown.value, headers = mapOf( "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( @@ -1200,6 +1270,31 @@ data class FilmxyCookies( 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? { val url = if (season == null) { diff --git a/SoraStream/src/main/kotlin/com/hexated/SoraStream.kt b/SoraStream/src/main/kotlin/com/hexated/SoraStream.kt index ff5cb9c7..446059ab 100644 --- a/SoraStream/src/main/kotlin/com/hexated/SoraStream.kt +++ b/SoraStream/src/main/kotlin/com/hexated/SoraStream.kt @@ -23,6 +23,7 @@ import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer import com.lagradost.cloudstream3.metaproviders.TmdbProvider import com.hexated.SoraExtractor.invoZoro import com.hexated.SoraExtractor.invokeLing +import com.hexated.SoraExtractor.invokeUhdmovies import com.lagradost.cloudstream3.utils.AppUtils.parseJson import com.lagradost.cloudstream3.utils.AppUtils.toJson 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 kissKhAPI = "https://kisskh.me" const val lingAPI = "https://ling-online.net" + const val uhdmoviesAPI = "https://uhdmovies.site" fun getType(t: String?): TvType { return when (t) { @@ -209,6 +211,7 @@ open class SoraStream : TmdbProvider() { return if (type == TvType.TvSeries) { val episodes = mutableListOf() + val lastSeason = res.seasons?.lastOrNull()?.seasonNumber res.seasons?.apmap { season -> app.get("$tmdbAPI/${data.type}/${data.id}/season/${season.seasonNumber}?api_key=$apiKey") .parsedSafe()?.episodes?.map { eps -> @@ -223,7 +226,8 @@ open class SoraStream : TmdbProvider() { year = season.airDate?.split("-")?.first()?.toIntOrNull(), orgTitle = orgTitle, show = show, - airedYear = year + airedYear = year, + lastSeason = lastSeason ).toJson(), name = eps.name, season = eps.seasonNumber, @@ -342,9 +346,9 @@ open class SoraStream : TmdbProvider() { { 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) }, @@ -447,6 +451,17 @@ open class SoraStream : TmdbProvider() { callback ) }, + { + invokeUhdmovies( + res.title, + res.year, + res.season, + res.lastSeason, + res.episode, + subtitleCallback, + callback + ) + }, ) return true @@ -465,6 +480,7 @@ open class SoraStream : TmdbProvider() { val orgTitle: String? = null, val show: String? = null, val airedYear: Int? = null, + val lastSeason: Int? = null, ) data class Data( diff --git a/WcofunProvider/src/main/kotlin/com/hexated/WcofunProvider.kt b/WcofunProvider/src/main/kotlin/com/hexated/WcofunProvider.kt index bbeeef13..0fd06390 100644 --- a/WcofunProvider/src/main/kotlin/com/hexated/WcofunProvider.kt +++ b/WcofunProvider/src/main/kotlin/com/hexated/WcofunProvider.kt @@ -149,7 +149,7 @@ class WcofunProvider : MainAPI() { "${this.name} ${source.second}", "${this.name} ${source.second}", "${it.server}/getvid?evid=${source.first}", - mainUrl, + referer = mainUrl, if (source.second == "HD") Qualities.P720.value else Qualities.P480.value ) ) diff --git a/build.gradle.kts b/build.gradle.kts index e3b76bfd..1330ebd8 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,5 +1,6 @@ import com.lagradost.cloudstream3.gradle.CloudstreamExtension import com.android.build.gradle.BaseExtension +import java.util.Properties buildscript { repositories { @@ -47,6 +48,12 @@ subprojects { defaultConfig { minSdk = 21 targetSdk = 32 + +// val properties = Properties() +// properties.load(project.rootProject.file("local.properties").inputStream()) +// +// buildConfigField("String", "API_KEY", "\"${properties.getProperty("API_KEY")}\"") + } compileOptions {