diff --git a/SoraStream/build.gradle.kts b/SoraStream/build.gradle.kts index 7a3a9c0d..92a81802 100644 --- a/SoraStream/build.gradle.kts +++ b/SoraStream/build.gradle.kts @@ -1,7 +1,7 @@ import org.jetbrains.kotlin.konan.properties.Properties // use an integer for version numbers -version = 173 +version = 174 android { defaultConfig { diff --git a/SoraStream/src/main/kotlin/com/hexated/SoraExtractor.kt b/SoraStream/src/main/kotlin/com/hexated/SoraExtractor.kt index 26f7dc28..170fa271 100644 --- a/SoraStream/src/main/kotlin/com/hexated/SoraExtractor.kt +++ b/SoraStream/src/main/kotlin/com/hexated/SoraExtractor.kt @@ -1719,7 +1719,6 @@ object SoraExtractor : SoraStream() { imdbId: String? = null, season: Int? = null, episode: Int? = null, - isAnime: Boolean = false, subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit, ) { @@ -1735,13 +1734,13 @@ object SoraExtractor : SoraStream() { it.attr("data-id") to it.text() }.apmap { when { - (it.second.equals("Player F", true) || it.second.equals( + it.second.equals("Player F", true) || it.second.equals( "Player N", true - )) && !isAnime -> { + ) -> { invokeSmashyFfix(it.second, it.first, url, callback) } - it.second.equals("Player FM", true) && !isAnime -> invokeSmashyFm( + it.second.equals("Player FM", true) -> invokeSmashyFm( it.second, it.first, url, callback ) @@ -2034,6 +2033,26 @@ object SoraExtractor : SoraStream() { } + suspend fun invokePutactor( + title: String? = null, + year: Int? = null, + season: Int? = null, + episode: Int? = null, + callback: (ExtractorLink) -> Unit, + ) { + invokeGpress( + title, + year, + season, + episode, + callback, + putactorAPI, + "Putactor", + "_VPzQdLFXWQppjNou", + "_hfDAQaOJyNSkXHjy" + ) + } + suspend fun invokePrimewire( title: String? = null, year: Int? = null, @@ -2041,8 +2060,32 @@ object SoraExtractor : SoraStream() { episode: Int? = null, callback: (ExtractorLink) -> Unit, ) { - fun String.decrypt(key: String): List? { - return tryParseJson>(base64Decode(this).decodePrimewireXor(key)) + invokeGpress( + title, + year, + season, + episode, + callback, + primewireAPI, + "Primewire", + "RvnMfoxhgm", + "vvqUtffkId" + ) + } + + private suspend fun invokeGpress( + title: String? = null, + year: Int? = null, + season: Int? = null, + episode: Int? = null, + callback: (ExtractorLink) -> Unit, + api: String, + name: String, + mediaSelector: String, + episodeSelector: String, + ) { + fun String.decrypt(key: String): List? { + return tryParseJson>(base64Decode(this).decodePrimewireXor(key)) } val slug = getEpisodeSlug(season, episode) @@ -2052,9 +2095,9 @@ object SoraExtractor : SoraStream() { "$title Season $season" } - val doc = app.get("$primewireAPI/search/$query").document + val doc = app.get("$api/search/$query").document - val media = doc.select("div.RvnMfoxhgm").map { + val media = doc.select("div.$mediaSelector").map { Triple( it.attr("data-filmName"), it.attr("data-year"), it.select("a").attr("href") ) @@ -2079,21 +2122,23 @@ object SoraExtractor : SoraStream() { } else { app.get( fixUrl( - media.third, primewireAPI + media.third, + api ) - ).document.selectFirst("div#vvqUtffkId a:contains(Episode ${slug.second})") + ).document.selectFirst("div#$episodeSelector a:contains(Episode ${slug.second})") ?.attr("href") } ?: return - val res = app.get(fixUrl(iframe, primewireAPI), verify = false) + val res = app.get(fixUrl(iframe, api), verify = false) val serverUrl = "var url = '(/user/servers/.*?\\?ep=.*?)';".toRegex() .find(res.text)?.groupValues?.get(1) ?: return - val cookies = res.okhttpResponse.headers.getPrimewireCookies() + val cookies = res.cookies val url = res.document.select("meta[property=og:url]").attr("content") val headers = mapOf("X-Requested-With" to "XMLHttpRequest") val qualities = intArrayOf(2160, 1440, 1080, 720, 480, 360) val serverRes = app.get( - "$primewireAPI$serverUrl", cookies = cookies, referer = url, headers = headers + "$api$serverUrl", + cookies = cookies, referer = url, headers = headers ) val unpack = getAndUnpack(serverRes.text) val key = unpack.substringAfter("(key=").substringBefore(")") @@ -2101,7 +2146,7 @@ object SoraExtractor : SoraStream() { serverRes.document.select("ul li").amap { el -> val server = el.attr("data-value") val encryptedData = app.get( - "$url?server=$server&_=${unixTimeMS}", + "$url?server=$server&_=$unixTimeMS", cookies = cookies, referer = url, headers = headers @@ -2111,10 +2156,10 @@ object SoraExtractor : SoraStream() { qualities.filter { it <= video.max.toInt() }.forEach { callback( ExtractorLink( - "Primewire", - "Primewire", + name, + name, video.src.split("360", limit = 3).joinToString(it.toString()), - "$primewireAPI/", + "$api/", it, ) ) diff --git a/SoraStream/src/main/kotlin/com/hexated/SoraParser.kt b/SoraStream/src/main/kotlin/com/hexated/SoraParser.kt index 538176da..88eaabe4 100644 --- a/SoraStream/src/main/kotlin/com/hexated/SoraParser.kt +++ b/SoraStream/src/main/kotlin/com/hexated/SoraParser.kt @@ -31,7 +31,7 @@ data class AniSearch( @JsonProperty("data") var data: AniData? = AniData() ) -data class PrimewireSources( +data class GpressSources( @JsonProperty("src") val src: String, @JsonProperty("file") val file: String? = null, @JsonProperty("label") val label: Int? = null, diff --git a/SoraStream/src/main/kotlin/com/hexated/SoraStream.kt b/SoraStream/src/main/kotlin/com/hexated/SoraStream.kt index 21095851..721563fe 100644 --- a/SoraStream/src/main/kotlin/com/hexated/SoraStream.kt +++ b/SoraStream/src/main/kotlin/com/hexated/SoraStream.kt @@ -43,6 +43,7 @@ import com.hexated.SoraExtractor.invokeNetflix import com.hexated.SoraExtractor.invokeNetmovies import com.hexated.SoraExtractor.invokePobmovies import com.hexated.SoraExtractor.invokePrimewire +import com.hexated.SoraExtractor.invokePutactor import com.hexated.SoraExtractor.invokeTvMovies import com.hexated.SoraExtractor.invokeUhdmovies import com.hexated.SoraExtractor.invokeVegamovies @@ -124,6 +125,7 @@ open class SoraStream : TmdbProvider() { const val vidsrctoAPI = "https://vidsrc.to" const val dramadayAPI = "https://dramaday.me" const val animetoshoAPI = "https://animetosho.org" + const val putactorAPI = "https://putlocker.actor" const val susflixAPI = "https://susflix.tv" const val jump1API = "https://ca.jump1.net" const val vegaMoviesAPI = "https://vegamovies.im" @@ -152,7 +154,7 @@ open class SoraStream : TmdbProvider() { } } - fun base64DecodeAPI(api: String): String { + private fun base64DecodeAPI(api: String): String { return api.chunked(4).map { base64Decode(it) }.reversed().joinToString("") } @@ -466,7 +468,7 @@ open class SoraStream : TmdbProvider() { ) }, { - invokeLing( + if (!res.isAnime) invokeLing( res.title, res.airedYear ?: res.year, res.season, @@ -486,7 +488,7 @@ open class SoraStream : TmdbProvider() { ) }, { - invokeFwatayako(res.imdbId, res.season, res.episode, callback) + if (!res.isAnime) invokeFwatayako(res.imdbId, res.season, res.episode, callback) }, { if (!res.isAnime) invokeGMovies( @@ -516,7 +518,7 @@ open class SoraStream : TmdbProvider() { ) }, { - invokeTvMovies(res.title, res.season, res.episode, callback) + if (!res.isAnime) invokeTvMovies(res.title, res.season, res.episode, callback) }, { if (!res.isAnime) invokeMoviezAdd( @@ -541,23 +543,22 @@ open class SoraStream : TmdbProvider() { ) }, { - invokeRStream(res.id, res.season, res.episode, callback) + if (!res.isAnime) invokeRStream(res.id, res.season, res.episode, callback) }, { - invokeFlixon(res.id, res.imdbId, res.season, res.episode, callback) + if (!res.isAnime) invokeFlixon(res.id, res.imdbId, res.season, res.episode, callback) }, { - invokeSmashyStream( + if (!res.isAnime) invokeSmashyStream( res.imdbId, res.season, res.episode, - res.isAnime, subtitleCallback, callback ) }, { - invokeWatchsomuch( + if (!res.isAnime) invokeWatchsomuch( res.imdbId, res.season, res.episode, @@ -583,17 +584,11 @@ open class SoraStream : TmdbProvider() { ) }, { - invokePrimewire(res.title, res.year, res.season, res.episode, callback) + if (!res.isAnime) invokePrimewire(res.title, res.year, res.season, res.episode, callback) + }, + { + if (!res.isAnime) invokePutactor(res.title, res.year, res.season, res.episode, callback) }, -// { -// if (!res.isAnime) invokeGdbotMovies( -// res.title, -// res.year, -// res.season, -// res.episode, -// callback -// ) -// }, { if (!res.isAnime) invokeShinobiMovies( shinobiMovieAPI, diff --git a/SoraStream/src/main/kotlin/com/hexated/SoraStreamLite.kt b/SoraStream/src/main/kotlin/com/hexated/SoraStreamLite.kt index a262379c..8a9745dc 100644 --- a/SoraStream/src/main/kotlin/com/hexated/SoraStreamLite.kt +++ b/SoraStream/src/main/kotlin/com/hexated/SoraStreamLite.kt @@ -28,6 +28,7 @@ import com.hexated.SoraExtractor.invokeMultimovies import com.hexated.SoraExtractor.invokeNetflix import com.hexated.SoraExtractor.invokeNetmovies import com.hexated.SoraExtractor.invokePrimewire +import com.hexated.SoraExtractor.invokePutactor import com.hexated.SoraExtractor.invokeVidSrc import com.hexated.SoraExtractor.invokeVidsrcto import com.hexated.SoraExtractor.invokeWatchOnline @@ -65,7 +66,7 @@ class SoraStreamLite : SoraStream() { // ) // }, { - invokeWatchsomuch( + if (!res.isAnime) invokeWatchsomuch( res.imdbId, res.season, res.episode, @@ -129,16 +130,6 @@ class SoraStreamLite : SoraStream() { callback ) }, -// { -// invokeUniqueStream( -// res.title, -// res.year, -// res.season, -// res.episode, -// subtitleCallback, -// callback -// ) -// }, { if (!res.isAnime) invokeFilmxy( res.imdbId, @@ -158,25 +149,14 @@ class SoraStreamLite : SoraStream() { ) }, { - invokeSmashyStream( + if (!res.isAnime) invokeSmashyStream( res.imdbId, res.season, res.episode, - res.isAnime, subtitleCallback, callback ) }, -// { -// invokeXmovies( -// res.title, -// res.year, -// res.season, -// res.episode, -// subtitleCallback, -// callback -// ) -// }, { if (!res.isAnime) invokeVidsrcto( res.imdbId, @@ -198,7 +178,7 @@ class SoraStreamLite : SoraStream() { ) }, { - invokeLing( + if (!res.isAnime) invokeLing( res.title, res.airedYear ?: res.year, res.season, @@ -221,13 +201,16 @@ class SoraStreamLite : SoraStream() { ) }, { - invokeRStream(res.id, res.season, res.episode, callback) + if (!res.isAnime) invokeRStream(res.id, res.season, res.episode, callback) }, { - invokeFlixon(res.id, res.imdbId, res.season, res.episode, callback) + if (!res.isAnime) invokeFlixon(res.id, res.imdbId, res.season, res.episode, callback) }, { - invokePrimewire(res.title, res.year, res.season, res.episode, callback) + if (!res.isAnime) invokePrimewire(res.title, res.year, res.season, res.episode, callback) + }, + { + if (!res.isAnime) invokePutactor(res.title, res.year, res.season, res.episode, callback) }, { invokeWatchOnline( diff --git a/SoraStream/src/main/kotlin/com/hexated/SoraUtils.kt b/SoraStream/src/main/kotlin/com/hexated/SoraUtils.kt index 29780467..42694143 100644 --- a/SoraStream/src/main/kotlin/com/hexated/SoraUtils.kt +++ b/SoraStream/src/main/kotlin/com/hexated/SoraUtils.kt @@ -3,7 +3,6 @@ package com.hexated import android.util.Base64 import com.hexated.DumpUtils.queryApi import com.hexated.SoraStream.Companion.anilistAPI -import com.hexated.SoraStream.Companion.base64DecodeAPI import com.hexated.SoraStream.Companion.crunchyrollAPI import com.hexated.SoraStream.Companion.filmxyAPI import com.hexated.SoraStream.Companion.gdbot @@ -26,7 +25,6 @@ import com.lagradost.nicehttp.RequestBodyTypes import com.lagradost.nicehttp.requestCreator import kotlinx.coroutines.delay import okhttp3.FormBody -import okhttp3.Headers import okhttp3.HttpUrl.Companion.toHttpUrl import okhttp3.MediaType.Companion.toMediaTypeOrNull import okhttp3.RequestBody.Companion.toRequestBody @@ -1202,17 +1200,6 @@ fun String.decodePrimewireXor(key: String): String { return sb.toString() } -fun Headers.getPrimewireCookies(cookieKey: String = "set-cookie"): Map { - val cookieList = - this.filter { it.first.equals(cookieKey, ignoreCase = true) }.mapNotNull { - it.second.split(";").firstOrNull() - } - return cookieList.associate { - val split = it.split("=", limit = 2) - (split.getOrNull(0)?.trim() ?: "") to (split.getOrNull(1)?.trim() ?: "") - }.filter { it.key.isNotBlank() && it.value.isNotBlank() } -} - fun String?.createSlug(): String? { return this?.replace(Regex("[^\\w\\s-]"), "") ?.replace(" ", "-")