Update video extraction (#1591)
This commit is contained in:
parent
8f19319f4c
commit
bb678e9562
@ -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'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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 ->
|
||||||
when {
|
runCatching {
|
||||||
url.toHttpUrl().host.contains("gdflix") -> {
|
val url = server.attr("href")
|
||||||
videoList.addAll(GDFlixExtractor(client, headers).videosFromUrl(url))
|
when {
|
||||||
}
|
url.toHttpUrl().host.contains("gdflix") -> {
|
||||||
// url.toHttpUrl().host.contains("gdtot") -> {
|
GDFlixExtractor(client, headers).videosFromUrl(url)
|
||||||
// videoList.addAll(GDTotExtractor(client, headers).videosFromUrl(url))
|
}
|
||||||
// }
|
url.toHttpUrl().host.contains("gdtot") -> {
|
||||||
}
|
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()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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") {
|
|
||||||
val (videos, mediaUrl) = extractVideo(EpUrl("Video", serverUrl, "Video"))
|
|
||||||
if (videos.isEmpty()) failedMediaUrl.add(Pair(mediaUrl, "Video"))
|
|
||||||
videoList.addAll(videos)
|
|
||||||
}
|
|
||||||
|
|
||||||
videoList.addAll(
|
videoList.addAll(
|
||||||
failedMediaUrl.mapNotNull { (url, quality) ->
|
listOf("direct", "drivebot").parallelMap { type ->
|
||||||
runCatching {
|
runCatching {
|
||||||
extractGDriveLink(url, quality)
|
when (type) {
|
||||||
|
"direct" -> {
|
||||||
|
extractGDriveLink(serverUrl)
|
||||||
|
}
|
||||||
|
"drivebot" -> {
|
||||||
|
extractDriveBotLink(serverUrl)
|
||||||
|
}
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
}.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,
|
||||||
|
@ -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")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user