Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(pt/pobreflix): Fix video extractor + Add more extractors #2445

Merged
merged 2 commits into from
Oct 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions multisrc/overrides/dooplay/pobreflix/additional.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
dependencies {
implementation(project(":lib-filemoon-extractor"))
implementation(project(":lib-playlist-utils"))
}
40 changes: 30 additions & 10 deletions multisrc/overrides/dooplay/pobreflix/src/Pobreflix.kt
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
package eu.kanade.tachiyomi.animeextension.pt.pobreflix

import android.util.Base64
import eu.kanade.tachiyomi.animeextension.pt.pobreflix.extractors.EplayerExtractor
import eu.kanade.tachiyomi.animeextension.pt.pobreflix.extractors.MyStreamExtractor
import eu.kanade.tachiyomi.animeextension.pt.pobreflix.extractors.PainelfxExtractor
import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.lib.filemoonextractor.FilemoonExtractor
import eu.kanade.tachiyomi.multisrc.dooplay.DooPlay
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.util.asJsoup
Expand All @@ -21,19 +24,36 @@ class Pobreflix : DooPlay(
override fun latestUpdatesRequest(page: Int) = GET("$baseUrl/series/page/$page/", headers)

// ============================ Video Links =============================
private val painelfxExtractor by lazy { PainelfxExtractor(client, headers, ::genericExtractor) }
private val eplayerExtractor by lazy { EplayerExtractor(client) }
private val filemoonExtractor by lazy { FilemoonExtractor(client) }
private val mystreamExtractor by lazy { MyStreamExtractor(client, headers) }

override fun videoListParse(response: Response): List<Video> {
val doc = response.use { it.asJsoup() }
return doc.select("div.source-box > a").flatMap {
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('"')
when {
url.contains("painelfx") ->
PainelfxExtractor(client).videosFromUrl(url, headers)
else -> emptyList()
}
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('"')
when {
url.contains("painelfx") ->
painelfxExtractor.videosFromUrl(url)
else -> genericExtractor(url)
}
}.getOrElse { emptyList() }
}
}

private fun genericExtractor(url: String, language: String = ""): List<Video> {
return when {
url.contains("filemoon") -> filemoonExtractor.videosFromUrl(url, headers = headers)
url.contains("watch.brplayer") || url.contains("/watch?v=") ->
mystreamExtractor.videosFromUrl(url, language)
url.contains("embedplayer") -> eplayerExtractor.videosFromUrl(url, language)
else -> emptyList()
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
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.POST
import okhttp3.FormBody
import okhttp3.Headers
import okhttp3.OkHttpClient

class EplayerExtractor(private val client: OkHttpClient) {
private val headers by lazy {
Headers.headersOf(
"X-Requested-With",
"XMLHttpRequest",
"Referer",
EPLAYER_HOST,
"Origin",
EPLAYER_HOST,
)
}

private val playlistUtils by lazy { PlaylistUtils(client, headers) }

fun videosFromUrl(url: String, lang: String): List<Video> {
val id = url.substringAfterLast("/")

val postUrl = "$EPLAYER_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().use {
it.body.string()
.substringAfter("videoSource\":\"")
.substringBefore('"')
.replace("\\", "")
}

return playlistUtils.extractFromHls(masterUrl, videoNameGen = { "[$lang] EmbedPlayer - $it" })
}

companion object {
private const val EPLAYER_HOST = "https://embedplayer.online"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
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?")

return runCatching {
val response = client.newCall(GET(url, headers)).execute()
val body = response.use { it.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()

playlistUtils.extractFromHls(
streamUrl,
masterHeaders = newHeaders,
videoHeaders = newHeaders,
videoNameGen = { "[$language] MyStream: $it" },
)
}.getOrElse { emptyList<Video>() }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,12 @@ import okhttp3.Headers
import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.OkHttpClient

class PainelfxExtractor(private val client: OkHttpClient) {
fun videosFromUrl(url: String, headers: Headers): List<Video> {
class PainelfxExtractor(
private val client: OkHttpClient,
private val headers: Headers,
private val genericExtractor: (String, String) -> List<Video>,
) {
fun videosFromUrl(url: String): List<Video> {
val docHeaders = headers.newBuilder().set("Referer", "https://gastronomiabrasileira.net/").build()
val doc = client.newCall(GET(url, docHeaders)).execute().use { it.asJsoup() }
val lang = when (url.substringAfterLast("/")) {
Expand Down Expand Up @@ -61,7 +65,8 @@ class PainelfxExtractor(private val client: OkHttpClient) {
Video(videoUrl, "$lang - $quality", videoUrl, videoHeaders)
}
} else {
emptyList()
val url = decoded.substringAfter("\"url\":\"").substringBefore('"')
genericExtractor(url, lang)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ class DooPlayGenerator : ThemeSourceGenerator {
SingleLang("Kinoking", "https://kinoking.cc", "de", isNsfw = false, overrideVersionCode = 17),
SingleLang("Multimovies", "https://multimovies.live", "en", isNsfw = false, overrideVersionCode = 12),
SingleLang("Pi Fansubs", "https://pifansubs.org", "pt-BR", isNsfw = true, overrideVersionCode = 17),
SingleLang("Pobreflix", "https://pobreflix.biz", "pt-BR", isNsfw = true, overrideVersionCode = 1),
SingleLang("Pobreflix", "https://pobreflix.biz", "pt-BR", isNsfw = true, overrideVersionCode = 2),
SingleLang("UniqueStream", "https://uniquestream.net", "en", isNsfw = false, overrideVersionCode = 2),
)

Expand Down