Skip to content

Commit

Permalink
fix(pt/pobreflix): Fix video extractor + add more extractors + parall…
Browse files Browse the repository at this point in the history
…elize (#2610)
  • Loading branch information
Claudemirovsky authored Dec 5, 2023
1 parent dadd535 commit 34b01b1
Show file tree
Hide file tree
Showing 5 changed files with 161 additions and 87 deletions.
2 changes: 2 additions & 0 deletions multisrc/overrides/dooplay/pobreflix/additional.gradle
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
dependencies {
implementation(project(":lib-filemoon-extractor"))
implementation(project(":lib-streamwish-extractor"))
implementation(project(":lib-streamtape-extractor"))
implementation(project(":lib-playlist-utils"))
}
25 changes: 19 additions & 6 deletions multisrc/overrides/dooplay/pobreflix/src/Pobreflix.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,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.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
Expand All @@ -24,10 +26,12 @@ 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) }
private val streamtapeExtractor by lazy { StreamTapeExtractor(client) }
private val streamwishExtractor by lazy { StreamWishExtractor(client, headers) }
private val superflixExtractor by lazy { SuperFlixExtractor(client, headers, ::genericExtractor) }

override fun videoListParse(response: Response): List<Video> {
val doc = response.use { it.asJsoup() }
Expand All @@ -39,20 +43,29 @@ class Pobreflix : DooPlay(
?: return@flatMap emptyList()
val url = data.replace("\\", "").substringAfter("url\":\"").substringBefore('"')
when {
url.contains("painelfx") ->
painelfxExtractor.videosFromUrl(url)
url.contains("superflix") ->
superflixExtractor.videosFromUrl(url)
else -> genericExtractor(url)
}
}.getOrElse { emptyList() }
}
}

private fun genericExtractor(url: String, language: String = ""): List<Video> {
val langSubstr = "[$language]"
return when {
url.contains("filemoon") -> filemoonExtractor.videosFromUrl(url, headers = headers)
url.contains("filemoon") ->
filemoonExtractor.videosFromUrl(url, "$langSubstr Filemoon - ", headers = headers)
url.contains("watch.brplayer") || url.contains("/watch?v=") ->
mystreamExtractor.videosFromUrl(url, language)
url.contains("embedplayer") -> eplayerExtractor.videosFromUrl(url, language)
url.contains("embedplayer") ->
eplayerExtractor.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()
}
}
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
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.util.asJsoup
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.runBlocking
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 json: Json by injectLazy()

fun videosFromUrl(url: String): List<Video> {
val links = linksFromUrl(url)

val fixedLinks = links.parallelCatchingFlatMap {
val (language, linkUrl) = it
when {
linkUrl.contains("?vid=") -> linksFromPlayer(linkUrl, language)
else -> listOf(it)
}
}

return fixedLinks.parallelCatchingFlatMap { genericExtractor(it.second, it.first) }
}

private 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", "$API_DOMAIN/")
.set("origin", API_DOMAIN)
.build()

val doc = client.newCall(GET(url, headers)).execute().use { it.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)).execute()
.use { it.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().use { it.asJsoup() }

val items = doc.select("div.select_language").mapNotNull {
val target = it.attr("data-target")
val id = doc.selectFirst("div.players_select div[data-target=$target] div[data-id]")
?.attr("data-id")
?: return@mapNotNull null

it.text() to id // (Language, videoId)
}

val headers = defaultHeaders.newBuilder()
.set("Origin", API_DOMAIN)
.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("$API_DOMAIN/api", headers, body)).execute()
.use { it.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)

private inline fun <A, B> Iterable<A>.parallelCatchingFlatMap(crossinline f: suspend (A) -> Iterable<B>): List<B> =
runBlocking {
map {
async(Dispatchers.Default) {
runCatching { f(it) }.getOrElse { emptyList() }
}
}.awaitAll().flatten()
}
}

private const val API_DOMAIN = "https://superflixapi.top"
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ class DooPlayGenerator : ThemeSourceGenerator {
SingleLang("Kinoking", "https://kinoking.cc", "de", isNsfw = false, overrideVersionCode = 19),
SingleLang("Multimovies", "https://multimovies.live", "en", isNsfw = false, overrideVersionCode = 13),
SingleLang("Pi Fansubs", "https://pifansubs.org", "pt-BR", isNsfw = true, overrideVersionCode = 17),
SingleLang("Pobreflix", "https://pobreflix.biz", "pt-BR", isNsfw = true, overrideVersionCode = 2),
SingleLang("Pobreflix", "https://pobreflix.biz", "pt-BR", isNsfw = true, overrideVersionCode = 3),
SingleLang("UniqueStream", "https://uniquestream.net", "en", isNsfw = false, overrideVersionCode = 2),
)

Expand Down

0 comments on commit 34b01b1

Please sign in to comment.