chore: Sync with latest commits

This commit is contained in:
WebDitto 2024-06-23 11:00:51 -03:00
parent 9b96273df0
commit 56c945d716
115 changed files with 2230 additions and 445 deletions

View file

@ -0,0 +1,18 @@
ext {
extName = 'Pobreflix'
extClass = '.Pobreflix'
themePkg = 'dooplay'
baseUrl = 'https://pobreflix1.art'
overrideVersionCode = 9
isNsfw = true
}
apply from: "$rootDir/common.gradle"
dependencies {
implementation(project(":lib:filemoon-extractor"))
implementation(project(":lib:streamwish-extractor"))
implementation(project(":lib:streamtape-extractor"))
implementation(project(":lib:playlist-utils"))
implementation "dev.datlag.jsunpacker:jsunpacker:1.0.1"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

View file

@ -0,0 +1,79 @@
package eu.kanade.tachiyomi.animeextension.pt.pobreflix
import android.util.Base64
import eu.kanade.tachiyomi.animeextension.pt.pobreflix.extractors.FireplayerExtractor
import eu.kanade.tachiyomi.animeextension.pt.pobreflix.extractors.MyStreamExtractor
import eu.kanade.tachiyomi.animeextension.pt.pobreflix.extractors.SuperFlixExtractor
import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.lib.filemoonextractor.FilemoonExtractor
import eu.kanade.tachiyomi.lib.streamtapeextractor.StreamTapeExtractor
import eu.kanade.tachiyomi.lib.streamwishextractor.StreamWishExtractor
import eu.kanade.tachiyomi.multisrc.dooplay.DooPlay
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.util.asJsoup
import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.Response
class Pobreflix : DooPlay(
"pt-BR",
"Pobreflix",
"https://pobreflix1.art",
) {
// ============================== Popular ===============================
override fun popularAnimeSelector() = "div.featured div.poster"
// =============================== Latest ===============================
override fun latestUpdatesRequest(page: Int) = GET("$baseUrl/series/page/$page/", headers)
// ============================ Video Links =============================
private val embedplayerExtractor by lazy { FireplayerExtractor(client) }
private val brbeastExtractor by lazy { FireplayerExtractor(client, "https://brbeast.com") }
private val superembedsExtractor by lazy { FireplayerExtractor(client, "https://superembeds.com/") }
private val filemoonExtractor by lazy { FilemoonExtractor(client) }
private val mystreamExtractor by lazy { MyStreamExtractor(client, headers) }
private val streamtapeExtractor by lazy { StreamTapeExtractor(client) }
private val streamwishExtractor by lazy { StreamWishExtractor(client, headers) }
private val superflixExtractor by lazy { SuperFlixExtractor(client, headers, ::genericExtractor) }
private val supercdnExtractor by lazy { SuperFlixExtractor(client, headers, ::genericExtractor, "https://supercdn.org") }
override fun videoListParse(response: Response): List<Video> {
val doc = response.asJsoup()
return doc.select("div.source-box > a").flatMap {
runCatching {
val data = it.attr("href").toHttpUrl().queryParameter("auth")
?.let { Base64.decode(it, Base64.DEFAULT) }
?.let(::String)
?: return@flatMap emptyList()
val url = data.replace("\\", "").substringAfter("url\":\"").substringBefore('"')
genericExtractor(url)
}.getOrElse { emptyList() }
}
}
private fun genericExtractor(url: String, language: String = ""): List<Video> {
val langSubstr = "[$language]"
return when {
url.contains("superflix") ->
superflixExtractor.videosFromUrl(url)
url.contains("supercdn") ->
supercdnExtractor.videosFromUrl(url)
url.contains("filemoon") ->
filemoonExtractor.videosFromUrl(url, "$langSubstr Filemoon - ", headers = headers)
url.contains("watch.brplayer") || url.contains("/watch?v=") ->
mystreamExtractor.videosFromUrl(url, language)
url.contains("brbeast") ->
brbeastExtractor.videosFromUrl(url, language)
url.contains("embedplayer") ->
embedplayerExtractor.videosFromUrl(url, language)
url.contains("superembeds") ->
superembedsExtractor.videosFromUrl(url, language)
url.contains("streamtape") ->
streamtapeExtractor.videosFromUrl(url, "$langSubstr Streamtape")
url.contains("filelions") ->
streamwishExtractor.videosFromUrl(url, videoNameGen = { "$langSubstr FileLions - $it" })
url.contains("streamwish") ->
streamwishExtractor.videosFromUrl(url, videoNameGen = { "$langSubstr Streamwish - $it" })
else -> emptyList()
}
}
}

View file

@ -0,0 +1,56 @@
package eu.kanade.tachiyomi.animeextension.pt.pobreflix.extractors
import dev.datlag.jsunpacker.JsUnpacker
import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.lib.playlistutils.PlaylistUtils
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.network.POST
import eu.kanade.tachiyomi.util.asJsoup
import okhttp3.FormBody
import okhttp3.Headers
import okhttp3.OkHttpClient
class FireplayerExtractor(private val client: OkHttpClient, private val host: String = "https://embedplayer.online") {
private val headers by lazy {
Headers.headersOf(
"X-Requested-With",
"XMLHttpRequest",
"Referer",
host,
"Origin",
host,
)
}
private val playlistUtils by lazy { PlaylistUtils(client, headers) }
fun videosFromUrl(url: String, lang: String): List<Video> {
var id = url.substringAfterLast("/")
if (id.length < 32) {
val doc = client.newCall(GET(url, headers)).execute().asJsoup()
val script = doc.selectFirst("script:containsData(eval):containsData(p,a,c,k,e,d)")?.data()
?.let(JsUnpacker::unpackAndCombine)
?: doc.selectFirst("script:containsData(FirePlayer)")?.data()
if (script?.contains("FirePlayer(") == true) {
id = script.substringAfter("FirePlayer(\"").substringBefore('"')
}
}
val postUrl = "$host/player/index.php?data=$id&do=getVideo"
val body = FormBody.Builder()
.add("hash", id)
.add("r", "")
.build()
val masterUrl = client.newCall(POST(postUrl, headers, body = body)).execute()
.body.string()
.substringAfter("securedLink\":\"")
.substringBefore('"')
.replace("\\", "")
return playlistUtils.extractFromHls(masterUrl, videoNameGen = { "[$lang] EmbedPlayer - $it" })
}
}

View file

@ -0,0 +1,48 @@
package eu.kanade.tachiyomi.animeextension.pt.pobreflix.extractors
import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.lib.playlistutils.PlaylistUtils
import eu.kanade.tachiyomi.network.GET
import okhttp3.Headers
import okhttp3.OkHttpClient
// From animeworldindia
class MyStreamExtractor(private val client: OkHttpClient, private val headers: Headers) {
private val playlistUtils by lazy { PlaylistUtils(client, headers) }
fun videosFromUrl(url: String, language: String): List<Video> {
val host = url.substringBefore("/watch?")
val response = client.newCall(GET(url, headers)).execute()
val body = response.body.string()
val codePart = body
.substringAfter("sniff(") // Video function
.substringBefore(",[")
val streamCode = codePart
.substringAfterLast(",\"") // our beloved hash
.substringBefore('"')
val id = codePart.substringAfter(",\"").substringBefore('"') // required ID
val streamUrl = "$host/m3u8/$id/$streamCode/master.txt?s=1&cache=1"
val cookie = response.headers.firstOrNull {
it.first.startsWith("set-cookie", true) && it.second.startsWith("PHPSESSID", true)
}?.second?.substringBefore(";") ?: ""
val newHeaders = headers.newBuilder()
.set("cookie", cookie)
.set("accept", "*/*")
.build()
return playlistUtils.extractFromHls(
streamUrl,
masterHeaders = newHeaders,
videoHeaders = newHeaders,
videoNameGen = { "[$language] MyStream: $it" },
)
}
}

View file

@ -0,0 +1,134 @@
package eu.kanade.tachiyomi.animeextension.pt.pobreflix.extractors
import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.network.POST
import eu.kanade.tachiyomi.network.await
import eu.kanade.tachiyomi.util.asJsoup
import eu.kanade.tachiyomi.util.parallelCatchingFlatMapBlocking
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json
import okhttp3.FormBody
import okhttp3.Headers
import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.OkHttpClient
import uy.kohesive.injekt.injectLazy
class SuperFlixExtractor(
private val client: OkHttpClient,
private val defaultHeaders: Headers,
private val genericExtractor: (String, String) -> List<Video>,
private val host: String = "https://superflixapi.top",
) {
private val json: Json by injectLazy()
fun videosFromUrl(url: String): List<Video> {
val links = linksFromUrl(url)
val fixedLinks = links.parallelCatchingFlatMapBlocking {
val (language, linkUrl) = it
when {
linkUrl.contains("?vid=") -> linksFromPlayer(linkUrl, language)
else -> listOf(it)
}
}
return fixedLinks.parallelCatchingFlatMapBlocking { genericExtractor(it.second, it.first) }
}
private suspend fun linksFromPlayer(url: String, language: String): List<Pair<String, String>> {
val httpUrl = url.toHttpUrl()
val id = httpUrl.queryParameter("vid")!!
val headers = defaultHeaders.newBuilder()
.set("referer", "$host/")
.set("origin", host)
.build()
val doc = client.newCall(GET(url, headers)).await().asJsoup()
val baseUrl = "https://" + httpUrl.host
val apiUrl = "$baseUrl/ajax_sources.php"
val apiHeaders = headers.newBuilder()
.set("referer", url)
.set("origin", baseUrl)
.set("X-Requested-With", "XMLHttpRequest")
.build()
return doc.select("ul > li[data-order-value]").mapNotNull {
val name = it.attr("data-dropdown-value")
val order = it.attr("data-order-value")
val formBody = FormBody.Builder()
.add("vid", id)
.add("alternative", name)
.add("ord", order)
.build()
val req = client.newCall(POST(apiUrl, apiHeaders, formBody)).await()
.body.string()
runCatching {
val iframeUrl = json.decodeFromString<PlayerLinkDto>(req).iframe!!
val iframeServer = iframeUrl.toHttpUrl().queryParameter("sv")!!
language to when (name) {
"1xbet" -> "https://watch.brplayer.site/watch?v=${iframeServer.trim('/')}"
else -> iframeServer
}
}.getOrNull()
}
}
@Serializable
data class PlayerLinkDto(val iframe: String? = null)
private fun linksFromUrl(url: String): List<Pair<String, String>> {
val doc = client.newCall(GET(url, defaultHeaders)).execute().asJsoup()
val items = doc.select("div.select_languages").mapNotNull {
val id = it.nextElementSibling()
?.selectFirst("div[data-id]")
?.attr("data-id")
?: return@mapNotNull null
val language = it.text()
.replace("Disponível", "")
.replace("disponível", "")
.replace("Apenas", "")
.replace("em", "")
.trim()
language to id // (Language, videoId)
}
val headers = defaultHeaders.newBuilder()
.set("Origin", host)
.set("Referer", url)
.set("X-Requested-With", "XMLHttpRequest")
.build()
return items.mapNotNull {
runCatching {
it.first to getLink(it.second, headers)!!
}.getOrNull()
}
}
private fun getLink(id: String, headers: Headers): String? {
val body = FormBody.Builder()
.add("action", "getPlayer")
.add("video_id", id)
.build()
val res = client.newCall(POST("$host/api", headers, body)).execute()
.body.string()
return json.decodeFromString<ApiResponseDto>(res).data?.video_url
}
@Serializable
data class ApiResponseDto(val data: DataDto? = null)
@Serializable
data class DataDto(val video_url: String? = null)
}