forked from Kohi-den/extensions-source
fix: Fixed Q1N source using UniversalExtractor as fallback
This commit is contained in:
parent
2ec968514f
commit
e39934a7e1
3 changed files with 138 additions and 2 deletions
|
@ -1,9 +1,10 @@
|
||||||
ext {
|
ext {
|
||||||
|
extKmkVersionCode = 1
|
||||||
extName = 'Q1N'
|
extName = 'Q1N'
|
||||||
extClass = '.Q1N'
|
extClass = '.Q1N'
|
||||||
themePkg = 'dooplay'
|
themePkg = 'dooplay'
|
||||||
baseUrl = 'https://q1n.net'
|
baseUrl = 'https://q1n.net'
|
||||||
overrideVersionCode = 20
|
overrideVersionCode = 21
|
||||||
}
|
}
|
||||||
|
|
||||||
apply from: "$rootDir/common.gradle"
|
apply from: "$rootDir/common.gradle"
|
||||||
|
@ -13,5 +14,6 @@ dependencies {
|
||||||
implementation(project(":lib:filemoon-extractor"))
|
implementation(project(":lib:filemoon-extractor"))
|
||||||
implementation(project(":lib:streamwish-extractor"))
|
implementation(project(":lib:streamwish-extractor"))
|
||||||
implementation(project(":lib:mixdrop-extractor"))
|
implementation(project(":lib:mixdrop-extractor"))
|
||||||
|
implementation(project(":lib:playlist-utils"))
|
||||||
implementation(project(":lib:streamtape-extractor"))
|
implementation(project(":lib:streamtape-extractor"))
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
package eu.kanade.tachiyomi.animeextension.pt.animesgratis
|
package eu.kanade.tachiyomi.animeextension.pt.animesgratis
|
||||||
|
|
||||||
|
import android.util.Log
|
||||||
import eu.kanade.tachiyomi.animeextension.pt.animesgratis.extractors.NoaExtractor
|
import eu.kanade.tachiyomi.animeextension.pt.animesgratis.extractors.NoaExtractor
|
||||||
import eu.kanade.tachiyomi.animeextension.pt.animesgratis.extractors.RuplayExtractor
|
import eu.kanade.tachiyomi.animeextension.pt.animesgratis.extractors.RuplayExtractor
|
||||||
|
import eu.kanade.tachiyomi.animeextension.pt.animesgratis.extractors.UniversalExtractor
|
||||||
import eu.kanade.tachiyomi.animesource.model.SAnime
|
import eu.kanade.tachiyomi.animesource.model.SAnime
|
||||||
import eu.kanade.tachiyomi.animesource.model.SEpisode
|
import eu.kanade.tachiyomi.animesource.model.SEpisode
|
||||||
import eu.kanade.tachiyomi.animesource.model.Video
|
import eu.kanade.tachiyomi.animesource.model.Video
|
||||||
|
@ -27,6 +29,8 @@ class Q1N : DooPlay(
|
||||||
"https://q1n.net",
|
"https://q1n.net",
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
private val tag by lazy { javaClass.simpleName }
|
||||||
|
|
||||||
override val id: Long = 2969482460524685571L
|
override val id: Long = 2969482460524685571L
|
||||||
|
|
||||||
override val dateFormatter by lazy {
|
override val dateFormatter by lazy {
|
||||||
|
@ -118,10 +122,12 @@ class Q1N : DooPlay(
|
||||||
private val streamTapeExtractor by lazy { StreamTapeExtractor(client) }
|
private val streamTapeExtractor by lazy { StreamTapeExtractor(client) }
|
||||||
private val streamWishExtractor by lazy { StreamWishExtractor(client, headers) }
|
private val streamWishExtractor by lazy { StreamWishExtractor(client, headers) }
|
||||||
private val mixDropExtractor by lazy { MixDropExtractor(client) }
|
private val mixDropExtractor by lazy { MixDropExtractor(client) }
|
||||||
|
private val universalExtractor by lazy { UniversalExtractor(client) }
|
||||||
|
|
||||||
private fun getPlayerVideos(player: Element): List<Video> {
|
private fun getPlayerVideos(player: Element): List<Video> {
|
||||||
val name = player.selectFirst("span.title")!!.text().lowercase()
|
val name = player.selectFirst("span.title")!!.text().lowercase()
|
||||||
val url = getPlayerUrl(player) ?: return emptyList()
|
val url = getPlayerUrl(player) ?: return emptyList()
|
||||||
|
Log.d(tag, "Fetching videos from: $url")
|
||||||
return when {
|
return when {
|
||||||
"ruplay" in name -> ruplayExtractor.videosFromUrl(url)
|
"ruplay" in name -> ruplayExtractor.videosFromUrl(url)
|
||||||
"streamwish" in name -> streamWishExtractor.videosFromUrl(url)
|
"streamwish" in name -> streamWishExtractor.videosFromUrl(url)
|
||||||
|
@ -131,7 +137,7 @@ class Q1N : DooPlay(
|
||||||
"noa" in name -> noaExtractor.videosFromUrl(url)
|
"noa" in name -> noaExtractor.videosFromUrl(url)
|
||||||
"mdplayer" in name -> noaExtractor.videosFromUrl(url, "MDPLAYER")
|
"mdplayer" in name -> noaExtractor.videosFromUrl(url, "MDPLAYER")
|
||||||
"/player/" in url -> bloggerExtractor.videosFromUrl(url, headers)
|
"/player/" in url -> bloggerExtractor.videosFromUrl(url, headers)
|
||||||
else -> emptyList()
|
else -> universalExtractor.videosFromUrl(url, headers)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,128 @@
|
||||||
|
package eu.kanade.tachiyomi.animeextension.pt.animesgratis.extractors
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.app.Application
|
||||||
|
import android.os.Handler
|
||||||
|
import android.os.Looper
|
||||||
|
import android.util.Log
|
||||||
|
import android.webkit.WebResourceRequest
|
||||||
|
import android.webkit.WebResourceResponse
|
||||||
|
import android.webkit.WebView
|
||||||
|
import android.webkit.WebViewClient
|
||||||
|
import eu.kanade.tachiyomi.animesource.model.Video
|
||||||
|
import eu.kanade.tachiyomi.lib.playlistutils.PlaylistUtils
|
||||||
|
import okhttp3.Headers
|
||||||
|
import okhttp3.HttpUrl.Companion.toHttpUrl
|
||||||
|
import okhttp3.OkHttpClient
|
||||||
|
import uy.kohesive.injekt.injectLazy
|
||||||
|
import java.util.Locale
|
||||||
|
import java.util.concurrent.CountDownLatch
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
|
class UniversalExtractor(private val client: OkHttpClient) {
|
||||||
|
private val tag by lazy { javaClass.simpleName }
|
||||||
|
private val context: Application by injectLazy()
|
||||||
|
private val handler by lazy { Handler(Looper.getMainLooper()) }
|
||||||
|
|
||||||
|
@SuppressLint("SetJavaScriptEnabled")
|
||||||
|
fun videosFromUrl(origRequestUrl: String, origRequestHeader: Headers): List<Video> {
|
||||||
|
Log.d(tag, "Fetching videos from: $origRequestUrl")
|
||||||
|
val host = origRequestUrl.toHttpUrl().host.substringBefore(".").proper()
|
||||||
|
val latch = CountDownLatch(1)
|
||||||
|
var webView: WebView? = null
|
||||||
|
var resultUrl = ""
|
||||||
|
val playlistUtils by lazy { PlaylistUtils(client, origRequestHeader) }
|
||||||
|
val headers = origRequestHeader.toMultimap().mapValues { it.value.getOrNull(0) ?: "" }.toMutableMap()
|
||||||
|
|
||||||
|
handler.post {
|
||||||
|
val newView = WebView(context)
|
||||||
|
webView = newView
|
||||||
|
with(newView.settings) {
|
||||||
|
javaScriptEnabled = true
|
||||||
|
domStorageEnabled = true
|
||||||
|
databaseEnabled = true
|
||||||
|
useWideViewPort = false
|
||||||
|
loadWithOverviewMode = false
|
||||||
|
userAgentString = origRequestHeader["User-Agent"]
|
||||||
|
}
|
||||||
|
newView.webViewClient = object : WebViewClient() {
|
||||||
|
override fun onPageFinished(view: WebView?, url: String?) {
|
||||||
|
Log.d(tag, "Page loaded, injecting script")
|
||||||
|
view?.evaluateJavascript(CHECK_SCRIPT) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun shouldInterceptRequest(
|
||||||
|
view: WebView,
|
||||||
|
request: WebResourceRequest,
|
||||||
|
): WebResourceResponse? {
|
||||||
|
val url = request.url.toString()
|
||||||
|
Log.d(tag, "Intercepted URL: $url")
|
||||||
|
if (VIDEO_REGEX.containsMatchIn(url)) {
|
||||||
|
resultUrl = url
|
||||||
|
latch.countDown()
|
||||||
|
}
|
||||||
|
return super.shouldInterceptRequest(view, request)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
webView?.loadUrl("$origRequestUrl&dl=1", headers)
|
||||||
|
}
|
||||||
|
|
||||||
|
latch.await(TIMEOUT_SEC, TimeUnit.SECONDS)
|
||||||
|
|
||||||
|
handler.post {
|
||||||
|
webView?.stopLoading()
|
||||||
|
webView?.destroy()
|
||||||
|
webView = null
|
||||||
|
}
|
||||||
|
|
||||||
|
return when {
|
||||||
|
"m3u8" in resultUrl -> {
|
||||||
|
Log.d(tag, "m3u8 URL: $resultUrl")
|
||||||
|
playlistUtils.extractFromHls(resultUrl, origRequestUrl, videoNameGen = { "$host: $it" })
|
||||||
|
}
|
||||||
|
"mpd" in resultUrl -> {
|
||||||
|
Log.d(tag, "mpd URL: $resultUrl")
|
||||||
|
playlistUtils.extractFromDash(resultUrl, { it -> "$host: $it" }, referer = origRequestUrl)
|
||||||
|
}
|
||||||
|
"mp4" in resultUrl -> {
|
||||||
|
Log.d(tag, "mp4 URL: $resultUrl")
|
||||||
|
Video(resultUrl, "$host: mp4", resultUrl, Headers.headersOf("referer", origRequestUrl)).let(::listOf)
|
||||||
|
}
|
||||||
|
else -> emptyList()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun String.proper(): String {
|
||||||
|
return this.replaceFirstChar {
|
||||||
|
if (it.isLowerCase()) {
|
||||||
|
it.titlecase(
|
||||||
|
Locale.getDefault(),
|
||||||
|
)
|
||||||
|
} else it.toString()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val TIMEOUT_SEC: Long = 10
|
||||||
|
private val VIDEO_REGEX by lazy { Regex(".*\\.(mp4|m3u8|mpd)(\\?.*)?$") }
|
||||||
|
private val CHECK_SCRIPT by lazy {
|
||||||
|
"""
|
||||||
|
setInterval(() => {
|
||||||
|
var playButton = document.getElementById('player-button-container')
|
||||||
|
if (playButton) {
|
||||||
|
playButton.click()
|
||||||
|
}
|
||||||
|
var downloadButton = document.querySelector(".downloader-button")
|
||||||
|
if (downloadButton) {
|
||||||
|
if (downloadButton.href) {
|
||||||
|
location.href = downloadButton.href
|
||||||
|
} else {
|
||||||
|
downloadButton.click()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 2500)
|
||||||
|
""".trimIndent()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue