Update video extraction (#1591)

This commit is contained in:
Secozzi 2023-05-09 12:38:12 +02:00 committed by GitHub
parent 8f19319f4c
commit bb678e9562
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 51 additions and 83 deletions

View File

@ -6,7 +6,7 @@ ext {
extName = 'HolaMovies' extName = 'HolaMovies'
pkgNameSuffix = 'en.holamovies' pkgNameSuffix = 'en.holamovies'
extClass = '.HolaMovies' extClass = '.HolaMovies'
extVersionCode = 1 extVersionCode = 2
libVersion = '13' libVersion = '13'
} }

View File

@ -3,6 +3,10 @@ package eu.kanade.tachiyomi.animeextension.en.holamovies.extractors
import eu.kanade.tachiyomi.animesource.model.Video import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.util.asJsoup import eu.kanade.tachiyomi.util.asJsoup
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.runBlocking
import okhttp3.Headers import okhttp3.Headers
import okhttp3.HttpUrl.Companion.toHttpUrl import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
@ -24,18 +28,29 @@ class GDBotExtractor(private val client: OkHttpClient, private val headers: Head
GET("$botUrl/file/$fileId", headers = docHeaders), GET("$botUrl/file/$fileId", headers = docHeaders),
).execute().asJsoup() ).execute().asJsoup()
document.select("li.py-6 > a[href]").forEach { videoList.addAll(
val url = it.attr("href") document.select("li.py-6 > a[href]").parallelMap { server ->
runCatching {
val url = server.attr("href")
when { when {
url.toHttpUrl().host.contains("gdflix") -> { url.toHttpUrl().host.contains("gdflix") -> {
videoList.addAll(GDFlixExtractor(client, headers).videosFromUrl(url)) GDFlixExtractor(client, headers).videosFromUrl(url)
} }
// url.toHttpUrl().host.contains("gdtot") -> { url.toHttpUrl().host.contains("gdtot") -> {
// videoList.addAll(GDTotExtractor(client, headers).videosFromUrl(url)) GDTotExtractor(client, headers).videosFromUrl(url)
// }
} }
else -> null
} }
}.getOrNull()
}.filterNotNull().flatten(),
)
return videoList return videoList
} }
// From Dopebox
private fun <A, B> Iterable<A>.parallelMap(f: suspend (A) -> B): List<B> =
runBlocking {
map { async(Dispatchers.Default) { f(it) } }.awaitAll()
}
} }

View File

@ -1,10 +1,13 @@
package eu.kanade.tachiyomi.animeextension.en.holamovies.extractors package eu.kanade.tachiyomi.animeextension.en.holamovies.extractors
import android.util.Base64
import eu.kanade.tachiyomi.animesource.model.Video import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.network.POST import eu.kanade.tachiyomi.network.POST
import eu.kanade.tachiyomi.util.asJsoup 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.Serializable
import kotlinx.serialization.decodeFromString import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
@ -20,78 +23,37 @@ class GDFlixExtractor(private val client: OkHttpClient, private val headers: Hea
fun videosFromUrl(serverUrl: String): List<Video> { fun videosFromUrl(serverUrl: String): List<Video> {
val videoList = mutableListOf<Video>() val videoList = mutableListOf<Video>()
val failedMediaUrl = mutableListOf<Pair<String, String>>()
if (serverUrl.toHttpUrl().encodedPath != "/404") { videoList.addAll(
val (videos, mediaUrl) = extractVideo(EpUrl("Video", serverUrl, "Video")) listOf("direct", "drivebot").parallelMap { type ->
if (videos.isEmpty()) failedMediaUrl.add(Pair(mediaUrl, "Video")) runCatching {
videoList.addAll(videos) when (type) {
"direct" -> {
extractGDriveLink(serverUrl)
}
"drivebot" -> {
extractDriveBotLink(serverUrl)
}
else -> null
} }
videoList.addAll(
failedMediaUrl.mapNotNull { (url, quality) ->
runCatching {
extractGDriveLink(url, quality)
}.getOrNull() }.getOrNull()
}.flatten(), }.filterNotNull().flatten(),
)
videoList.addAll(
failedMediaUrl.mapNotNull { (url, quality) ->
runCatching {
extractDriveBotLink(url)
}.getOrNull()
}.flatten(),
) )
return videoList return videoList
} }
private fun extractVideo(epUrl: EpUrl): Pair<List<Video>, String> { // From Dopebox
val videoList = mutableListOf<Video>() private fun <A, B> Iterable<A>.parallelMap(f: suspend (A) -> B): List<B> =
runBlocking {
val qualityRegex = """(\d+)p""".toRegex() map { async(Dispatchers.Default) { f(it) } }.awaitAll()
val matchResult = qualityRegex.find(epUrl.name)
val quality = if (matchResult == null) {
epUrl.quality
} else {
matchResult.groupValues[1]
} }
for (type in 1..3) { private fun extractGDriveLink(mediaUrl: String): List<Video> {
videoList.addAll(
extractWorkerLinks(epUrl.url, quality, type),
)
}
return Pair(videoList, epUrl.url)
}
private val sizeRegex = "\\[((?:.(?!\\[))+)][ ]*\$".toRegex(RegexOption.IGNORE_CASE)
private fun extractWorkerLinks(mediaUrl: String, quality: String, type: Int): List<Video> {
val reqLink = mediaUrl.replace("/file/", "/wfile/") + "?type=$type"
val resp = client.newCall(GET(reqLink)).execute().asJsoup()
val sizeMatch = sizeRegex.find(resp.select("div.card-header").text().trim())
val size = sizeMatch?.groups?.get(1)?.value?.let { " - $it" } ?: ""
return resp.select("div.card-body div.mb-4 > a").mapIndexed { index, linkElement ->
val link = linkElement.attr("href")
val decodedLink = if (link.contains("workers.dev")) {
link
} else {
String(Base64.decode(link.substringAfter("download?url="), Base64.DEFAULT))
}
Video(
url = decodedLink,
quality = "$quality - CF $type Worker ${index + 1}$size",
videoUrl = decodedLink,
)
}
}
private fun extractGDriveLink(mediaUrl: String, quality: String): List<Video> {
val tokenClient = client.newBuilder().addInterceptor(TokenInterceptor()).build() val tokenClient = client.newBuilder().addInterceptor(TokenInterceptor()).build()
val response = tokenClient.newCall(GET(mediaUrl)).execute().asJsoup() val response = tokenClient.newCall(GET(mediaUrl)).execute().asJsoup()
val gdBtn = response.selectFirst("div.card-body a.btn")!! val gdBtn = response.selectFirst("div.card-body a.btn")!!
val gdLink = gdBtn.attr("href") val gdLink = gdBtn.attr("href")
@ -160,13 +122,6 @@ class GDFlixExtractor(private val client: OkHttpClient, private val headers: Hea
) )
} }
@Serializable
data class EpUrl(
val quality: String,
val url: String,
val name: String,
)
@Serializable @Serializable
data class DriveBotResp( data class DriveBotResp(
val url: String, val url: String,

View File

@ -9,8 +9,6 @@ import okhttp3.OkHttpClient
class GDTotExtractor(private val client: OkHttpClient, private val headers: Headers) { class GDTotExtractor(private val client: OkHttpClient, private val headers: Headers) {
fun videosFromUrl(serverUrl: String): List<Video> { fun videosFromUrl(serverUrl: String): List<Video> {
val videoList = mutableListOf<Video>()
val docHeaders = headers.newBuilder() val docHeaders = headers.newBuilder()
.add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8") .add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8")
.add("Host", serverUrl.toHttpUrl().host) .add("Host", serverUrl.toHttpUrl().host)
@ -34,8 +32,8 @@ class GDTotExtractor(private val client: OkHttpClient, private val headers: Head
GET(ddlUrl, headers = ddlHeaders), GET(ddlUrl, headers = ddlHeaders),
).execute().asJsoup() ).execute().asJsoup()
// TODO - Finish it val btn = document.selectFirst("button[onclick~=drive.google.com]")?.attr("onclick") ?: return emptyList()
return videoList return GoogleDriveExtractor(client, headers).videosFromUrl(btn.substringAfter("myDl('").substringBefore("'"), "GDToT")
} }
} }