sora: added Putactor

This commit is contained in:
hexated 2023-09-23 10:28:11 +07:00
parent d960e02d3a
commit a4913d7ab7
6 changed files with 88 additions and 78 deletions

View file

@ -1,7 +1,7 @@
import org.jetbrains.kotlin.konan.properties.Properties
// use an integer for version numbers
version = 173
version = 174
android {
defaultConfig {

View file

@ -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<PrimewireSources>? {
return tryParseJson<List<PrimewireSources>>(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<GpressSources>? {
return tryParseJson<List<GpressSources>>(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,
)
)

View file

@ -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,

View file

@ -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,

View file

@ -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(

View file

@ -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<String, String> {
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(" ", "-")