fix: Fixed Q1N source using UniversalExtractor as fallback (#1019)
Checklist: - [ ] Updated `extVersionCode` value in `build.gradle` for individual extensions - [x] Updated `overrideVersionCode` or `baseVersionCode` as needed for all multisrc extensions - [ ] Referenced all related issues in the PR body (e.g. "Closes #xyz") - [ ] Added the `isNsfw = true` flag in `build.gradle` when appropriate - [ ] Have not changed source names - [ ] Have explicitly kept the `id` if a source's name or language were changed - [x] Have tested the modifications by compiling and running the extension through Android Studio - [ ] Have removed `web_hi_res_512.png` when adding a new extension - [ ] Have made sure all the icons are in png format Reviewed-on: #1019 Co-authored-by: WebDitto <webditto@proton.me> Co-committed-by: WebDitto <webditto@proton.me>
This commit is contained in:
parent
9a5e2a9083
commit
7147360823
3 changed files with 138 additions and 2 deletions
|
@ -1,9 +1,10 @@
|
|||
ext {
|
||||
extKmkVersionCode = 1
|
||||
extName = 'Q1N'
|
||||
extClass = '.Q1N'
|
||||
themePkg = 'dooplay'
|
||||
baseUrl = 'https://q1n.net'
|
||||
overrideVersionCode = 20
|
||||
overrideVersionCode = 21
|
||||
}
|
||||
|
||||
apply from: "$rootDir/common.gradle"
|
||||
|
@ -13,5 +14,6 @@ dependencies {
|
|||
implementation(project(":lib:filemoon-extractor"))
|
||||
implementation(project(":lib:streamwish-extractor"))
|
||||
implementation(project(":lib:mixdrop-extractor"))
|
||||
implementation(project(":lib:playlist-utils"))
|
||||
implementation(project(":lib:streamtape-extractor"))
|
||||
}
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
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.RuplayExtractor
|
||||
import eu.kanade.tachiyomi.animeextension.pt.animesgratis.extractors.UniversalExtractor
|
||||
import eu.kanade.tachiyomi.animesource.model.SAnime
|
||||
import eu.kanade.tachiyomi.animesource.model.SEpisode
|
||||
import eu.kanade.tachiyomi.animesource.model.Video
|
||||
|
@ -27,6 +29,8 @@ class Q1N : DooPlay(
|
|||
"https://q1n.net",
|
||||
) {
|
||||
|
||||
private val tag by lazy { javaClass.simpleName }
|
||||
|
||||
override val id: Long = 2969482460524685571L
|
||||
|
||||
override val dateFormatter by lazy {
|
||||
|
@ -118,10 +122,12 @@ class Q1N : DooPlay(
|
|||
private val streamTapeExtractor by lazy { StreamTapeExtractor(client) }
|
||||
private val streamWishExtractor by lazy { StreamWishExtractor(client, headers) }
|
||||
private val mixDropExtractor by lazy { MixDropExtractor(client) }
|
||||
private val universalExtractor by lazy { UniversalExtractor(client) }
|
||||
|
||||
private fun getPlayerVideos(player: Element): List<Video> {
|
||||
val name = player.selectFirst("span.title")!!.text().lowercase()
|
||||
val url = getPlayerUrl(player) ?: return emptyList()
|
||||
Log.d(tag, "Fetching videos from: $url")
|
||||
return when {
|
||||
"ruplay" in name -> ruplayExtractor.videosFromUrl(url)
|
||||
"streamwish" in name -> streamWishExtractor.videosFromUrl(url)
|
||||
|
@ -131,7 +137,7 @@ class Q1N : DooPlay(
|
|||
"noa" in name -> noaExtractor.videosFromUrl(url)
|
||||
"mdplayer" in name -> noaExtractor.videosFromUrl(url, "MDPLAYER")
|
||||
"/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