fix(ko/aniweek): Fix video extraction (#2455)

This commit is contained in:
Secozzi
2023-11-01 13:45:38 +00:00
committed by GitHub
parent 4bd4436e3e
commit f248c8b1a8
2 changed files with 74 additions and 63 deletions

View File

@ -1,13 +1,19 @@
apply plugin: 'com.android.application' plugins {
apply plugin: 'kotlin-android' alias(libs.plugins.android.application)
apply plugin: 'kotlinx-serialization' alias(libs.plugins.kotlin.android)
alias(libs.plugins.kotlin.serialization)
}
ext { ext {
extName = 'Aniweek' extName = 'Aniweek'
pkgNameSuffix = 'ko.aniweek' pkgNameSuffix = 'ko.aniweek'
extClass = '.Aniweek' extClass = '.Aniweek'
extVersionCode = 2 extVersionCode = 3
libVersion = '13' libVersion = '13'
} }
dependencies {
implementation(project(':lib-playlist-utils'))
}
apply from: "$rootDir/common.gradle" apply from: "$rootDir/common.gradle"

View File

@ -12,12 +12,14 @@ import eu.kanade.tachiyomi.animesource.model.SEpisode
import eu.kanade.tachiyomi.animesource.model.Track import eu.kanade.tachiyomi.animesource.model.Track
import eu.kanade.tachiyomi.animesource.model.Video import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.animesource.online.ParsedAnimeHttpSource import eu.kanade.tachiyomi.animesource.online.ParsedAnimeHttpSource
import eu.kanade.tachiyomi.lib.playlistutils.PlaylistUtils
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.serialization.Serializable import kotlinx.serialization.Serializable
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import okhttp3.FormBody
import okhttp3.Headers
import okhttp3.HttpUrl.Companion.toHttpUrl import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.MediaType.Companion.toMediaType import okhttp3.MediaType.Companion.toMediaType
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
@ -205,20 +207,33 @@ class Aniweek : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
// ============================ Video Links ============================= // ============================ Video Links =============================
private val playlistUtils by lazy { PlaylistUtils(client, headers) }
override fun videoListParse(response: Response): List<Video> { override fun videoListParse(response: Response): List<Video> {
val document = response.asJsoup() val document = response.asJsoup()
val videoList = mutableListOf<Video>()
val iframeElement = document.selectFirst("iframe") val form = document.selectFirst("form.tt") ?: error("Failed to generate form")
val iframeUrl = if (iframeElement == null) { val postUrl = form.attr("action")
val script = document.selectFirst("script:containsData(movie_player)")?.data() ?: error("Failed to extract iframe")
val newDoc = client.newCall( val postBody = FormBody.Builder().apply {
GET(baseUrl + script.substringAfter("url : \"..").substringBefore("\"")), form.select("input[type=hidden][name][value]").forEach {
).execute().asJsoup() add(it.attr("name"), it.attr("value"))
newDoc.selectFirst("iframe")?.attr("src") ?: error("Failed to extract iframe") }
} else { }.build()
iframeElement.attr("src")
} val postHeaders = headers.newBuilder().apply {
add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8")
add("Content-Type", "application/x-www-form-urlencoded")
add("Host", postUrl.toHttpUrl().host)
add("Origin", baseUrl)
add("Referer", "$baseUrl/")
}.build()
val newDocument = client.newCall(
POST(postUrl, body = postBody, headers = postHeaders),
).execute().use { it.asJsoup() }
val iframeUrl = newDocument.selectFirst("iframe")?.attr("src") ?: error("Failed to extract iframe")
val iframeHeaders = headers.newBuilder() val iframeHeaders = 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")
@ -263,62 +278,52 @@ class Aniweek : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
iframeUrl.substringAfter("data=") iframeUrl.substringAfter("data=")
} }
val postHeaders = headers.newBuilder() val videoPostHeaders = headers.newBuilder().apply {
.add("Accept", "*/*") add("Accept", "*/*")
.add("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8") add("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8")
.add("Origin", "https://${iframeUrl.toHttpUrl().host}") add("Origin", "https://${iframeUrl.toHttpUrl().host}")
.add("Referer", iframeUrl) add("Referer", iframeUrl)
.add("X-Requested-With", "XMLHttpRequest") add("X-Requested-With", "XMLHttpRequest")
.add("Cookie", cookieValue.substringBefore(";")) add("Cookie", cookieValue.substringBefore(";"))
.build() }.build()
val postBody = "hash=$hash&r=${java.net.URLEncoder.encode("$baseUrl/", "utf-8")}" val videoPostBody = "hash=$hash&r=${java.net.URLEncoder.encode("$baseUrl/", "utf-8")}"
.toRequestBody("application/x-www-form-urlencoded".toMediaType()) .toRequestBody("application/x-www-form-urlencoded".toMediaType())
val postResponse = client.newCall( val postResponse = client.newCall(
POST("https://${iframeUrl.toHttpUrl().host}/player/index.php?data=$hash&do=getVideo", body = postBody, headers = postHeaders), POST("https://${iframeUrl.toHttpUrl().host}/player/index.php?data=$hash&do=getVideo", body = videoPostBody, headers = videoPostHeaders),
).execute() ).execute().use { it.body.string() }
val parsed = json.decodeFromString<IframeResponse>(postResponse.body.string()) val parsed = json.decodeFromString<IframeResponse>(postResponse)
if (parsed.hls) { return if (parsed.hls) {
val playlistHeaders = headers.newBuilder() val masterHeaders = headers.newBuilder().apply {
.add("Accept", "*/*") add("Accept", "*/*")
.add("Cookie", cookieValue.substringBefore(";")) add("Cookie", cookieValue.substringBefore(";"))
.add("Host", iframeUrl.toHttpUrl().host) add("Host", iframeUrl.toHttpUrl().host)
.add("Referer", iframeUrl) add("Referer", iframeUrl)
.add("Sec-Fetch-Dest", "empty") add("Sec-Fetch-Dest", "empty")
.add("Sec-Fetch-Mode", "cors") add("Sec-Fetch-Mode", "cors")
.add("Sec-Fetch-Site", "same-origin") add("Sec-Fetch-Site", "same-origin")
.add("TE", "trailers") add("TE", "trailers")
.build() }.build()
val masterPlaylist = client.newCall( fun genVideoHeaders(baseHeaders: Headers, referer: String, videoUrl: String): Headers {
GET(parsed.videoSource, headers = playlistHeaders), return baseHeaders.newBuilder().apply {
).execute().body.string() add("Accept", "*/*")
add("Origin", "https://${iframeUrl.toHttpUrl().host}")
add("Referer", "https://${iframeUrl.toHttpUrl().host}/")
}.build()
}
val videoHeaders = headers.newBuilder() playlistUtils.extractFromHls(
.add("Accept", "*/*") parsed.videoSource,
.add("Origin", baseUrl) masterHeadersGen = { _, _ -> masterHeaders },
.add("Referer", "$baseUrl/") videoHeadersGen = ::genVideoHeaders,
.add("Sec-Fetch-Dest", "empty") )
.add("Sec-Fetch-Mode", "cors") } else {
.add("Sec-Fetch-Site", "same-origin") emptyList()
.build()
masterPlaylist.substringAfter("#EXT-X-STREAM-INF:").split("#EXT-X-STREAM-INF:")
.forEach {
val quality = it.substringAfter("RESOLUTION=").substringAfter("x")
.substringBefore(",").substringBefore("\n") + "p"
val videoUrl = it.substringAfter("\n").substringBefore("\n")
videoList.add(Video(videoUrl, quality, videoUrl, headers = videoHeaders, subtitleTracks = subtitleList))
}
} }
require(videoList.isNotEmpty()) { "Failed to fetch videos" }
return videoList.sort()
} }
override fun videoFromElement(element: Element): Video = throw Exception("Not Used") override fun videoFromElement(element: Element): Video = throw Exception("Not Used")