Replacing VidGuardExtractor files in extensions
This commit is contained in:
parent
7b99310812
commit
8a4093ab8d
18 changed files with 46 additions and 524 deletions
|
@ -29,7 +29,7 @@ class StreamSilkExtractor(private val client: OkHttpClient, private val headers:
|
||||||
|
|
||||||
private val playlistUtils by lazy { PlaylistUtils(client, videoHeaders) }
|
private val playlistUtils by lazy { PlaylistUtils(client, videoHeaders) }
|
||||||
|
|
||||||
fun videosFromUrl(url: String, prefix: String) = videosFromUrl(url) { "$prefix $it" }
|
fun videosFromUrl(url: String, prefix: String) = videosFromUrl(url) { "${prefix}StreamSilk:$it" }
|
||||||
|
|
||||||
fun videosFromUrl(url: String, videoNameGen: (String) -> String = { quality -> "StreamSilk:$quality" }): List<Video> {
|
fun videosFromUrl(url: String, videoNameGen: (String) -> String = { quality -> "StreamSilk:$quality" }): List<Video> {
|
||||||
val document = client.newCall(GET(url)).execute().asJsoup()
|
val document = client.newCall(GET(url)).execute().asJsoup()
|
||||||
|
|
|
@ -21,7 +21,7 @@ class VidGuardExtractor(private val client: OkHttpClient) {
|
||||||
|
|
||||||
private val json: Json by injectLazy()
|
private val json: Json by injectLazy()
|
||||||
|
|
||||||
fun videosFromUrl(url: String, prefix: String) = videosFromUrl(url) { "$prefix $it" }
|
fun videosFromUrl(url: String, prefix: String) = videosFromUrl(url) { "${prefix}VidGuard:$it" }
|
||||||
|
|
||||||
fun videosFromUrl(url: String, videoNameGen: (String) -> String = { quality -> "VidGuard:$quality" }): List<Video> {
|
fun videosFromUrl(url: String, videoNameGen: (String) -> String = { quality -> "VidGuard:$quality" }): List<Video> {
|
||||||
val res = client.newCall(GET(url)).execute().asJsoup()
|
val res = client.newCall(GET(url)).execute().asJsoup()
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
ext {
|
ext {
|
||||||
extName = 'Anime-Base'
|
extName = 'Anime-Base'
|
||||||
extClass = '.AnimeBase'
|
extClass = '.AnimeBase'
|
||||||
extVersionCode = 25
|
extVersionCode = 26
|
||||||
isNsfw = true
|
isNsfw = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,6 +10,7 @@ apply from: "$rootDir/common.gradle"
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation(project(":lib:voe-extractor"))
|
implementation(project(":lib:voe-extractor"))
|
||||||
implementation(project(":lib:streamwish-extractor"))
|
implementation(project(":lib:streamwish-extractor"))
|
||||||
|
implementation(project(":lib:vidguard-extractor"))
|
||||||
implementation(project(":lib:playlist-utils"))
|
implementation(project(":lib:playlist-utils"))
|
||||||
implementation("dev.datlag.jsunpacker:jsunpacker:1.0.1")
|
implementation("dev.datlag.jsunpacker:jsunpacker:1.0.1")
|
||||||
}
|
}
|
|
@ -4,7 +4,6 @@ import android.app.Application
|
||||||
import androidx.preference.ListPreference
|
import androidx.preference.ListPreference
|
||||||
import androidx.preference.PreferenceScreen
|
import androidx.preference.PreferenceScreen
|
||||||
import eu.kanade.tachiyomi.animeextension.de.animebase.extractors.UnpackerExtractor
|
import eu.kanade.tachiyomi.animeextension.de.animebase.extractors.UnpackerExtractor
|
||||||
import eu.kanade.tachiyomi.animeextension.de.animebase.extractors.VidGuardExtractor
|
|
||||||
import eu.kanade.tachiyomi.animesource.ConfigurableAnimeSource
|
import eu.kanade.tachiyomi.animesource.ConfigurableAnimeSource
|
||||||
import eu.kanade.tachiyomi.animesource.model.AnimeFilterList
|
import eu.kanade.tachiyomi.animesource.model.AnimeFilterList
|
||||||
import eu.kanade.tachiyomi.animesource.model.AnimesPage
|
import eu.kanade.tachiyomi.animesource.model.AnimesPage
|
||||||
|
@ -13,6 +12,7 @@ import eu.kanade.tachiyomi.animesource.model.SEpisode
|
||||||
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.streamwishextractor.StreamWishExtractor
|
import eu.kanade.tachiyomi.lib.streamwishextractor.StreamWishExtractor
|
||||||
|
import eu.kanade.tachiyomi.lib.vidguardextractor.VidGuardExtractor
|
||||||
import eu.kanade.tachiyomi.lib.voeextractor.VoeExtractor
|
import eu.kanade.tachiyomi.lib.voeextractor.VoeExtractor
|
||||||
import eu.kanade.tachiyomi.network.GET
|
import eu.kanade.tachiyomi.network.GET
|
||||||
import eu.kanade.tachiyomi.network.POST
|
import eu.kanade.tachiyomi.network.POST
|
||||||
|
|
|
@ -1,124 +0,0 @@
|
||||||
package eu.kanade.tachiyomi.animeextension.de.animebase.extractors
|
|
||||||
|
|
||||||
import android.app.Application
|
|
||||||
import android.os.Handler
|
|
||||||
import android.os.Looper
|
|
||||||
import android.util.Base64
|
|
||||||
import android.webkit.JavascriptInterface
|
|
||||||
import android.webkit.WebSettings
|
|
||||||
import android.webkit.WebView
|
|
||||||
import android.webkit.WebViewClient
|
|
||||||
import eu.kanade.tachiyomi.animesource.model.Video
|
|
||||||
import eu.kanade.tachiyomi.network.GET
|
|
||||||
import eu.kanade.tachiyomi.util.asJsoup
|
|
||||||
import okhttp3.Headers
|
|
||||||
import okhttp3.HttpUrl.Companion.toHttpUrl
|
|
||||||
import okhttp3.OkHttpClient
|
|
||||||
import uy.kohesive.injekt.injectLazy
|
|
||||||
import java.util.concurrent.CountDownLatch
|
|
||||||
import java.util.concurrent.TimeUnit
|
|
||||||
|
|
||||||
class VidGuardExtractor(private val client: OkHttpClient) {
|
|
||||||
private val context: Application by injectLazy()
|
|
||||||
private val handler by lazy { Handler(Looper.getMainLooper()) }
|
|
||||||
|
|
||||||
class JsObject(private val latch: CountDownLatch) {
|
|
||||||
var payload: String = ""
|
|
||||||
|
|
||||||
@JavascriptInterface
|
|
||||||
fun passPayload(passedPayload: String) {
|
|
||||||
payload = passedPayload
|
|
||||||
latch.countDown()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun videosFromUrl(url: String): List<Video> {
|
|
||||||
val doc = client.newCall(GET(url)).execute().asJsoup()
|
|
||||||
val scriptUrl = doc.selectFirst("script[src*=ad/plugin]")
|
|
||||||
?.absUrl("src")
|
|
||||||
?: return emptyList()
|
|
||||||
|
|
||||||
val headers = Headers.headersOf("Referer", url)
|
|
||||||
val script = client.newCall(GET(scriptUrl, headers)).execute()
|
|
||||||
.body.string()
|
|
||||||
|
|
||||||
val sources = getSourcesFromScript(script, url)
|
|
||||||
.takeIf { it.isNotBlank() && it != "undefined" }
|
|
||||||
?: return emptyList()
|
|
||||||
|
|
||||||
return sources.substringAfter("stream:[").substringBefore("}]")
|
|
||||||
.split('{')
|
|
||||||
.drop(1)
|
|
||||||
.mapNotNull { line ->
|
|
||||||
val resolution = line.substringAfter("Label\":\"").substringBefore('"')
|
|
||||||
val videoUrl = line.substringAfter("URL\":\"").substringBefore('"')
|
|
||||||
.takeIf(String::isNotBlank)
|
|
||||||
?.let(::fixUrl)
|
|
||||||
?: return@mapNotNull null
|
|
||||||
Video(videoUrl, "VidGuard - $resolution", videoUrl, headers)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getSourcesFromScript(script: String, url: String): String {
|
|
||||||
val latch = CountDownLatch(1)
|
|
||||||
|
|
||||||
var webView: WebView? = null
|
|
||||||
|
|
||||||
val jsinterface = JsObject(latch)
|
|
||||||
|
|
||||||
handler.post {
|
|
||||||
val webview = WebView(context)
|
|
||||||
webView = webview
|
|
||||||
with(webview.settings) {
|
|
||||||
javaScriptEnabled = true
|
|
||||||
domStorageEnabled = true
|
|
||||||
databaseEnabled = true
|
|
||||||
useWideViewPort = false
|
|
||||||
loadWithOverviewMode = false
|
|
||||||
cacheMode = WebSettings.LOAD_NO_CACHE
|
|
||||||
}
|
|
||||||
|
|
||||||
webview.addJavascriptInterface(jsinterface, "android")
|
|
||||||
webview.webViewClient = object : WebViewClient() {
|
|
||||||
override fun onPageFinished(view: WebView?, url: String?) {
|
|
||||||
view?.clearCache(true)
|
|
||||||
view?.clearFormData()
|
|
||||||
view?.evaluateJavascript(script) {}
|
|
||||||
view?.evaluateJavascript("window.android.passPayload(JSON.stringify(window.svg))") {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
webview.loadDataWithBaseURL(url, "<html></html>", "text/html", "UTF-8", null)
|
|
||||||
}
|
|
||||||
|
|
||||||
latch.await(5, TimeUnit.SECONDS)
|
|
||||||
|
|
||||||
handler.post {
|
|
||||||
webView?.stopLoading()
|
|
||||||
webView?.destroy()
|
|
||||||
webView = null
|
|
||||||
}
|
|
||||||
|
|
||||||
return jsinterface.payload
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun fixUrl(url: String): String {
|
|
||||||
val httpUrl = url.toHttpUrl()
|
|
||||||
val originalSign = httpUrl.queryParameter("sig")!!
|
|
||||||
val newSign = originalSign.chunked(2).joinToString("") {
|
|
||||||
Char(it.toInt(16) xor 2).toString()
|
|
||||||
}
|
|
||||||
.let { String(Base64.decode(it, Base64.DEFAULT)) }
|
|
||||||
.substring(5)
|
|
||||||
.chunked(2)
|
|
||||||
.reversed()
|
|
||||||
.joinToString("")
|
|
||||||
.substring(5)
|
|
||||||
|
|
||||||
return httpUrl.newBuilder()
|
|
||||||
.removeAllQueryParameters("sig")
|
|
||||||
.addQueryParameter("sig", newSign)
|
|
||||||
.build()
|
|
||||||
.toString()
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,7 +1,7 @@
|
||||||
ext {
|
ext {
|
||||||
extName = 'Moflix-Stream'
|
extName = 'Moflix-Stream'
|
||||||
extClass = '.MoflixStream'
|
extClass = '.MoflixStream'
|
||||||
extVersionCode = 9
|
extVersionCode = 10
|
||||||
}
|
}
|
||||||
|
|
||||||
apply from: "$rootDir/common.gradle"
|
apply from: "$rootDir/common.gradle"
|
||||||
|
@ -10,6 +10,7 @@ dependencies {
|
||||||
implementation(project(':lib:streamvid-extractor'))
|
implementation(project(':lib:streamvid-extractor'))
|
||||||
implementation(project(':lib:streamwish-extractor'))
|
implementation(project(':lib:streamwish-extractor'))
|
||||||
implementation(project(':lib:streamtape-extractor'))
|
implementation(project(':lib:streamtape-extractor'))
|
||||||
|
implementation(project(':lib:vidguard-extractor'))
|
||||||
implementation(project(':lib:playlist-utils'))
|
implementation(project(':lib:playlist-utils'))
|
||||||
implementation "dev.datlag.jsunpacker:jsunpacker:1.0.1"
|
implementation "dev.datlag.jsunpacker:jsunpacker:1.0.1"
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,6 @@ import eu.kanade.tachiyomi.animeextension.de.moflixstream.dto.SearchDto
|
||||||
import eu.kanade.tachiyomi.animeextension.de.moflixstream.dto.SeasonPaginationDto
|
import eu.kanade.tachiyomi.animeextension.de.moflixstream.dto.SeasonPaginationDto
|
||||||
import eu.kanade.tachiyomi.animeextension.de.moflixstream.dto.VideoResponseDto
|
import eu.kanade.tachiyomi.animeextension.de.moflixstream.dto.VideoResponseDto
|
||||||
import eu.kanade.tachiyomi.animeextension.de.moflixstream.extractors.UnpackerExtractor
|
import eu.kanade.tachiyomi.animeextension.de.moflixstream.extractors.UnpackerExtractor
|
||||||
import eu.kanade.tachiyomi.animeextension.de.moflixstream.extractors.VidGuardExtractor
|
|
||||||
import eu.kanade.tachiyomi.animesource.ConfigurableAnimeSource
|
import eu.kanade.tachiyomi.animesource.ConfigurableAnimeSource
|
||||||
import eu.kanade.tachiyomi.animesource.model.AnimeFilterList
|
import eu.kanade.tachiyomi.animesource.model.AnimeFilterList
|
||||||
import eu.kanade.tachiyomi.animesource.model.AnimesPage
|
import eu.kanade.tachiyomi.animesource.model.AnimesPage
|
||||||
|
@ -24,6 +23,7 @@ import eu.kanade.tachiyomi.animesource.online.AnimeHttpSource
|
||||||
import eu.kanade.tachiyomi.lib.streamtapeextractor.StreamTapeExtractor
|
import eu.kanade.tachiyomi.lib.streamtapeextractor.StreamTapeExtractor
|
||||||
import eu.kanade.tachiyomi.lib.streamvidextractor.StreamVidExtractor
|
import eu.kanade.tachiyomi.lib.streamvidextractor.StreamVidExtractor
|
||||||
import eu.kanade.tachiyomi.lib.streamwishextractor.StreamWishExtractor
|
import eu.kanade.tachiyomi.lib.streamwishextractor.StreamWishExtractor
|
||||||
|
import eu.kanade.tachiyomi.lib.vidguardextractor.VidGuardExtractor
|
||||||
import eu.kanade.tachiyomi.network.GET
|
import eu.kanade.tachiyomi.network.GET
|
||||||
import eu.kanade.tachiyomi.util.parseAs
|
import eu.kanade.tachiyomi.util.parseAs
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
|
|
|
@ -1,124 +0,0 @@
|
||||||
package eu.kanade.tachiyomi.animeextension.de.moflixstream.extractors
|
|
||||||
|
|
||||||
import android.app.Application
|
|
||||||
import android.os.Handler
|
|
||||||
import android.os.Looper
|
|
||||||
import android.util.Base64
|
|
||||||
import android.webkit.JavascriptInterface
|
|
||||||
import android.webkit.WebSettings
|
|
||||||
import android.webkit.WebView
|
|
||||||
import android.webkit.WebViewClient
|
|
||||||
import eu.kanade.tachiyomi.animesource.model.Video
|
|
||||||
import eu.kanade.tachiyomi.network.GET
|
|
||||||
import eu.kanade.tachiyomi.util.asJsoup
|
|
||||||
import okhttp3.Headers
|
|
||||||
import okhttp3.HttpUrl.Companion.toHttpUrl
|
|
||||||
import okhttp3.OkHttpClient
|
|
||||||
import uy.kohesive.injekt.injectLazy
|
|
||||||
import java.util.concurrent.CountDownLatch
|
|
||||||
import java.util.concurrent.TimeUnit
|
|
||||||
|
|
||||||
class VidGuardExtractor(private val client: OkHttpClient) {
|
|
||||||
private val context: Application by injectLazy()
|
|
||||||
private val handler by lazy { Handler(Looper.getMainLooper()) }
|
|
||||||
|
|
||||||
class JsObject(private val latch: CountDownLatch) {
|
|
||||||
var payload: String = ""
|
|
||||||
|
|
||||||
@JavascriptInterface
|
|
||||||
fun passPayload(passedPayload: String) {
|
|
||||||
payload = passedPayload
|
|
||||||
latch.countDown()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun videosFromUrl(url: String): List<Video> {
|
|
||||||
val doc = client.newCall(GET(url)).execute().asJsoup()
|
|
||||||
val scriptUrl = doc.selectFirst("script[src*=ad/plugin]")
|
|
||||||
?.absUrl("src")
|
|
||||||
?: return emptyList()
|
|
||||||
|
|
||||||
val headers = Headers.headersOf("Referer", url)
|
|
||||||
val script = client.newCall(GET(scriptUrl, headers)).execute()
|
|
||||||
.body.string()
|
|
||||||
|
|
||||||
val sources = getSourcesFromScript(script, url)
|
|
||||||
.takeIf { it.isNotBlank() && it != "undefined" }
|
|
||||||
?: return emptyList()
|
|
||||||
|
|
||||||
return sources.substringAfter("stream:[").substringBefore("}]")
|
|
||||||
.split('{')
|
|
||||||
.drop(1)
|
|
||||||
.mapNotNull { line ->
|
|
||||||
val resolution = line.substringAfter("Label\":\"").substringBefore('"')
|
|
||||||
val videoUrl = line.substringAfter("URL\":\"").substringBefore('"')
|
|
||||||
.takeIf(String::isNotBlank)
|
|
||||||
?.let(::fixUrl)
|
|
||||||
?: return@mapNotNull null
|
|
||||||
Video(videoUrl, "VidGuard - $resolution", videoUrl, headers)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getSourcesFromScript(script: String, url: String): String {
|
|
||||||
val latch = CountDownLatch(1)
|
|
||||||
|
|
||||||
var webView: WebView? = null
|
|
||||||
|
|
||||||
val jsinterface = JsObject(latch)
|
|
||||||
|
|
||||||
handler.post {
|
|
||||||
val webview = WebView(context)
|
|
||||||
webView = webview
|
|
||||||
with(webview.settings) {
|
|
||||||
javaScriptEnabled = true
|
|
||||||
domStorageEnabled = true
|
|
||||||
databaseEnabled = true
|
|
||||||
useWideViewPort = false
|
|
||||||
loadWithOverviewMode = false
|
|
||||||
cacheMode = WebSettings.LOAD_NO_CACHE
|
|
||||||
}
|
|
||||||
|
|
||||||
webview.addJavascriptInterface(jsinterface, "android")
|
|
||||||
webview.webViewClient = object : WebViewClient() {
|
|
||||||
override fun onPageFinished(view: WebView?, url: String?) {
|
|
||||||
view?.clearCache(true)
|
|
||||||
view?.clearFormData()
|
|
||||||
view?.evaluateJavascript(script) {}
|
|
||||||
view?.evaluateJavascript("window.android.passPayload(JSON.stringify(window.svg))") {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
webview.loadDataWithBaseURL(url, "<html></html>", "text/html", "UTF-8", null)
|
|
||||||
}
|
|
||||||
|
|
||||||
latch.await(5, TimeUnit.SECONDS)
|
|
||||||
|
|
||||||
handler.post {
|
|
||||||
webView?.stopLoading()
|
|
||||||
webView?.destroy()
|
|
||||||
webView = null
|
|
||||||
}
|
|
||||||
|
|
||||||
return jsinterface.payload
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun fixUrl(url: String): String {
|
|
||||||
val httpUrl = url.toHttpUrl()
|
|
||||||
val originalSign = httpUrl.queryParameter("sig")!!
|
|
||||||
val newSign = originalSign.chunked(2).joinToString("") {
|
|
||||||
Char(it.toInt(16) xor 2).toString()
|
|
||||||
}
|
|
||||||
.let { String(Base64.decode(it, Base64.DEFAULT)) }
|
|
||||||
.substring(5)
|
|
||||||
.chunked(2)
|
|
||||||
.reversed()
|
|
||||||
.joinToString("")
|
|
||||||
.substring(5)
|
|
||||||
|
|
||||||
return httpUrl.newBuilder()
|
|
||||||
.removeAllQueryParameters("sig")
|
|
||||||
.addQueryParameter("sig", newSign)
|
|
||||||
.build()
|
|
||||||
.toString()
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -11,4 +11,5 @@ dependencies {
|
||||||
implementation(project(':lib:okru-extractor'))
|
implementation(project(':lib:okru-extractor'))
|
||||||
implementation(project(':lib:streamwish-extractor'))
|
implementation(project(':lib:streamwish-extractor'))
|
||||||
implementation(project(':lib:vk-extractor'))
|
implementation(project(':lib:vk-extractor'))
|
||||||
|
implementation(project(':lib:vidguard-extractor'))
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,6 @@ import android.app.Application
|
||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
import androidx.preference.ListPreference
|
import androidx.preference.ListPreference
|
||||||
import androidx.preference.PreferenceScreen
|
import androidx.preference.PreferenceScreen
|
||||||
import eu.kanade.tachiyomi.animeextension.es.asialiveaction.extractors.VidGuardExtractor
|
|
||||||
import eu.kanade.tachiyomi.animesource.ConfigurableAnimeSource
|
import eu.kanade.tachiyomi.animesource.ConfigurableAnimeSource
|
||||||
import eu.kanade.tachiyomi.animesource.model.AnimeFilter
|
import eu.kanade.tachiyomi.animesource.model.AnimeFilter
|
||||||
import eu.kanade.tachiyomi.animesource.model.AnimeFilterList
|
import eu.kanade.tachiyomi.animesource.model.AnimeFilterList
|
||||||
|
@ -15,6 +14,7 @@ import eu.kanade.tachiyomi.animesource.online.ParsedAnimeHttpSource
|
||||||
import eu.kanade.tachiyomi.lib.filemoonextractor.FilemoonExtractor
|
import eu.kanade.tachiyomi.lib.filemoonextractor.FilemoonExtractor
|
||||||
import eu.kanade.tachiyomi.lib.okruextractor.OkruExtractor
|
import eu.kanade.tachiyomi.lib.okruextractor.OkruExtractor
|
||||||
import eu.kanade.tachiyomi.lib.streamwishextractor.StreamWishExtractor
|
import eu.kanade.tachiyomi.lib.streamwishextractor.StreamWishExtractor
|
||||||
|
import eu.kanade.tachiyomi.lib.vidguardextractor.VidGuardExtractor
|
||||||
import eu.kanade.tachiyomi.lib.vkextractor.VkExtractor
|
import eu.kanade.tachiyomi.lib.vkextractor.VkExtractor
|
||||||
import eu.kanade.tachiyomi.network.GET
|
import eu.kanade.tachiyomi.network.GET
|
||||||
import eu.kanade.tachiyomi.util.asJsoup
|
import eu.kanade.tachiyomi.util.asJsoup
|
||||||
|
@ -148,7 +148,7 @@ class AsiaLiveAction : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
||||||
arrayOf("ok.ru", "okru").any(url) -> okruExtractor.videosFromUrl(url)
|
arrayOf("ok.ru", "okru").any(url) -> okruExtractor.videosFromUrl(url)
|
||||||
arrayOf("wishembed", "streamwish", "strwish", "wish").any(url) -> streamWishExtractor.videosFromUrl(url, videoNameGen = { "StreamWish:$it" })
|
arrayOf("wishembed", "streamwish", "strwish", "wish").any(url) -> streamWishExtractor.videosFromUrl(url, videoNameGen = { "StreamWish:$it" })
|
||||||
arrayOf("filemoon", "moonplayer").any(url) -> filemoonExtractor.videosFromUrl(url, prefix = "Filemoon:")
|
arrayOf("filemoon", "moonplayer").any(url) -> filemoonExtractor.videosFromUrl(url, prefix = "Filemoon:")
|
||||||
arrayOf("vembed", "guard").any(url) -> vidGuardExtractor.videosFromUrl(url)
|
arrayOf("vembed", "guard", "listeamed", "bembed", "vgfplay").any(url) -> vidGuardExtractor.videosFromUrl(url)
|
||||||
arrayOf("filelions", "lion", "fviplions").any(url) -> streamWishExtractor.videosFromUrl(url, videoNameGen = { "FileLions:$it" })
|
arrayOf("filelions", "lion", "fviplions").any(url) -> streamWishExtractor.videosFromUrl(url, videoNameGen = { "FileLions:$it" })
|
||||||
!url.contains("disable") && (arrayOf("amazon", "amz").any(url)) -> {
|
!url.contains("disable") && (arrayOf("amazon", "amz").any(url)) -> {
|
||||||
val body = client.newCall(GET(url)).execute().asJsoup()
|
val body = client.newCall(GET(url)).execute().asJsoup()
|
||||||
|
|
|
@ -1,124 +0,0 @@
|
||||||
package eu.kanade.tachiyomi.animeextension.es.asialiveaction.extractors
|
|
||||||
|
|
||||||
import android.app.Application
|
|
||||||
import android.os.Handler
|
|
||||||
import android.os.Looper
|
|
||||||
import android.util.Base64
|
|
||||||
import android.webkit.JavascriptInterface
|
|
||||||
import android.webkit.WebSettings
|
|
||||||
import android.webkit.WebView
|
|
||||||
import android.webkit.WebViewClient
|
|
||||||
import eu.kanade.tachiyomi.animesource.model.Video
|
|
||||||
import eu.kanade.tachiyomi.network.GET
|
|
||||||
import eu.kanade.tachiyomi.util.asJsoup
|
|
||||||
import okhttp3.Headers
|
|
||||||
import okhttp3.HttpUrl.Companion.toHttpUrl
|
|
||||||
import okhttp3.OkHttpClient
|
|
||||||
import uy.kohesive.injekt.injectLazy
|
|
||||||
import java.util.concurrent.CountDownLatch
|
|
||||||
import java.util.concurrent.TimeUnit
|
|
||||||
|
|
||||||
class VidGuardExtractor(private val client: OkHttpClient) {
|
|
||||||
private val context: Application by injectLazy()
|
|
||||||
private val handler by lazy { Handler(Looper.getMainLooper()) }
|
|
||||||
|
|
||||||
class JsObject(private val latch: CountDownLatch) {
|
|
||||||
var payload: String = ""
|
|
||||||
|
|
||||||
@JavascriptInterface
|
|
||||||
fun passPayload(passedPayload: String) {
|
|
||||||
payload = passedPayload
|
|
||||||
latch.countDown()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun videosFromUrl(url: String): List<Video> {
|
|
||||||
val doc = client.newCall(GET(url)).execute().asJsoup()
|
|
||||||
val scriptUrl = doc.selectFirst("script[src*=ad/plugin]")
|
|
||||||
?.absUrl("src")
|
|
||||||
?: return emptyList()
|
|
||||||
|
|
||||||
val headers = Headers.headersOf("Referer", url)
|
|
||||||
val script = client.newCall(GET(scriptUrl, headers)).execute()
|
|
||||||
.body.string()
|
|
||||||
|
|
||||||
val sources = getSourcesFromScript(script, url)
|
|
||||||
.takeIf { it.isNotBlank() && it != "undefined" }
|
|
||||||
?: return emptyList()
|
|
||||||
|
|
||||||
return sources.substringAfter("stream:[").substringBefore("}]")
|
|
||||||
.split('{')
|
|
||||||
.drop(1)
|
|
||||||
.mapNotNull { line ->
|
|
||||||
val resolution = line.substringAfter("Label\":\"").substringBefore('"')
|
|
||||||
val videoUrl = line.substringAfter("URL\":\"").substringBefore('"')
|
|
||||||
.takeIf(String::isNotBlank)
|
|
||||||
?.let(::fixUrl)
|
|
||||||
?: return@mapNotNull null
|
|
||||||
Video(videoUrl, "VidGuard:$resolution", videoUrl, headers)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getSourcesFromScript(script: String, url: String): String {
|
|
||||||
val latch = CountDownLatch(1)
|
|
||||||
|
|
||||||
var webView: WebView? = null
|
|
||||||
|
|
||||||
val jsinterface = JsObject(latch)
|
|
||||||
|
|
||||||
handler.post {
|
|
||||||
val webview = WebView(context)
|
|
||||||
webView = webview
|
|
||||||
with(webview.settings) {
|
|
||||||
javaScriptEnabled = true
|
|
||||||
domStorageEnabled = true
|
|
||||||
databaseEnabled = true
|
|
||||||
useWideViewPort = false
|
|
||||||
loadWithOverviewMode = false
|
|
||||||
cacheMode = WebSettings.LOAD_NO_CACHE
|
|
||||||
}
|
|
||||||
|
|
||||||
webview.addJavascriptInterface(jsinterface, "android")
|
|
||||||
webview.webViewClient = object : WebViewClient() {
|
|
||||||
override fun onPageFinished(view: WebView?, url: String?) {
|
|
||||||
view?.clearCache(true)
|
|
||||||
view?.clearFormData()
|
|
||||||
view?.evaluateJavascript(script) {}
|
|
||||||
view?.evaluateJavascript("window.android.passPayload(JSON.stringify(window.svg))") {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
webview.loadDataWithBaseURL(url, "<html></html>", "text/html", "UTF-8", null)
|
|
||||||
}
|
|
||||||
|
|
||||||
latch.await(5, TimeUnit.SECONDS)
|
|
||||||
|
|
||||||
handler.post {
|
|
||||||
webView?.stopLoading()
|
|
||||||
webView?.destroy()
|
|
||||||
webView = null
|
|
||||||
}
|
|
||||||
|
|
||||||
return jsinterface.payload
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun fixUrl(url: String): String {
|
|
||||||
val httpUrl = url.toHttpUrl()
|
|
||||||
val originalSign = httpUrl.queryParameter("sig")!!
|
|
||||||
val newSign = originalSign.chunked(2).joinToString("") {
|
|
||||||
Char(it.toInt(16) xor 2).toString()
|
|
||||||
}
|
|
||||||
.let { String(Base64.decode(it, Base64.DEFAULT)) }
|
|
||||||
.substring(5)
|
|
||||||
.chunked(2)
|
|
||||||
.reversed()
|
|
||||||
.joinToString("")
|
|
||||||
.substring(5)
|
|
||||||
|
|
||||||
return httpUrl.newBuilder()
|
|
||||||
.removeAllQueryParameters("sig")
|
|
||||||
.addQueryParameter("sig", newSign)
|
|
||||||
.build()
|
|
||||||
.toString()
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,7 +1,7 @@
|
||||||
ext {
|
ext {
|
||||||
extName = 'Cine24h'
|
extName = 'Cine24h'
|
||||||
extClass = '.Cine24h'
|
extClass = '.Cine24h'
|
||||||
extVersionCode = 1
|
extVersionCode = 2
|
||||||
}
|
}
|
||||||
|
|
||||||
apply from: "$rootDir/common.gradle"
|
apply from: "$rootDir/common.gradle"
|
||||||
|
@ -11,4 +11,5 @@ dependencies {
|
||||||
implementation(project(':lib:dood-extractor'))
|
implementation(project(':lib:dood-extractor'))
|
||||||
implementation(project(':lib:filemoon-extractor'))
|
implementation(project(':lib:filemoon-extractor'))
|
||||||
implementation(project(':lib:voe-extractor'))
|
implementation(project(':lib:voe-extractor'))
|
||||||
|
implementation(project(':lib:vidguard-extractor'))
|
||||||
}
|
}
|
|
@ -15,6 +15,7 @@ import eu.kanade.tachiyomi.animesource.online.AnimeHttpSource
|
||||||
import eu.kanade.tachiyomi.lib.doodextractor.DoodExtractor
|
import eu.kanade.tachiyomi.lib.doodextractor.DoodExtractor
|
||||||
import eu.kanade.tachiyomi.lib.fastreamextractor.FastreamExtractor
|
import eu.kanade.tachiyomi.lib.fastreamextractor.FastreamExtractor
|
||||||
import eu.kanade.tachiyomi.lib.filemoonextractor.FilemoonExtractor
|
import eu.kanade.tachiyomi.lib.filemoonextractor.FilemoonExtractor
|
||||||
|
import eu.kanade.tachiyomi.lib.vidguardextractor.VidGuardExtractor
|
||||||
import eu.kanade.tachiyomi.lib.voeextractor.VoeExtractor
|
import eu.kanade.tachiyomi.lib.voeextractor.VoeExtractor
|
||||||
import eu.kanade.tachiyomi.network.GET
|
import eu.kanade.tachiyomi.network.GET
|
||||||
import eu.kanade.tachiyomi.util.asJsoup
|
import eu.kanade.tachiyomi.util.asJsoup
|
||||||
|
@ -153,6 +154,7 @@ open class Cine24h : ConfigurableAnimeSource, AnimeHttpSource() {
|
||||||
private val filemoonExtractor by lazy { FilemoonExtractor(client) }
|
private val filemoonExtractor by lazy { FilemoonExtractor(client) }
|
||||||
private val doodExtractor by lazy { DoodExtractor(client) }
|
private val doodExtractor by lazy { DoodExtractor(client) }
|
||||||
private val voeExtractor by lazy { VoeExtractor(client) }
|
private val voeExtractor by lazy { VoeExtractor(client) }
|
||||||
|
private val vidGuardExtractor by lazy { VidGuardExtractor(client) }
|
||||||
|
|
||||||
private fun serverVideoResolver(url: String): List<Video> {
|
private fun serverVideoResolver(url: String): List<Video> {
|
||||||
val embedUrl = url.lowercase()
|
val embedUrl = url.lowercase()
|
||||||
|
@ -161,9 +163,10 @@ open class Cine24h : ConfigurableAnimeSource, AnimeHttpSource() {
|
||||||
val link = if (url.contains("emb.html")) "https://fastream.to/embed-${url.split("/").last()}.html" else url
|
val link = if (url.contains("emb.html")) "https://fastream.to/embed-${url.split("/").last()}.html" else url
|
||||||
FastreamExtractor(client, headers).videosFromUrl(link)
|
FastreamExtractor(client, headers).videosFromUrl(link)
|
||||||
}
|
}
|
||||||
embedUrl.contains("filemoon") || embedUrl.contains("moonplayer") -> filemoonExtractor.videosFromUrl(url, prefix = "Filemoon:")
|
arrayOf("filemoon", "moonplayer").any(url) -> filemoonExtractor.videosFromUrl(url, prefix = "Filemoon:")
|
||||||
embedUrl.contains("voe") -> voeExtractor.videosFromUrl(url)
|
arrayOf("voe").any(url) -> voeExtractor.videosFromUrl(url)
|
||||||
embedUrl.contains("dood") -> doodExtractor.videosFromUrl(url)
|
arrayOf("doodstream", "dood.", "ds2play", "doods.").any(url) -> doodExtractor.videosFromUrl(url)
|
||||||
|
arrayOf("vembed", "guard", "listeamed", "bembed", "vgfplay").any(url) -> vidGuardExtractor.videosFromUrl(url)
|
||||||
else -> emptyList()
|
else -> emptyList()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -236,6 +239,8 @@ open class Cine24h : ConfigurableAnimeSource, AnimeHttpSource() {
|
||||||
return !attr(attrName).contains("data:image/")
|
return !attr(attrName).contains("data:image/")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun Array<String>.any(url: String): Boolean = this.any { url.contains(it, ignoreCase = true) }
|
||||||
|
|
||||||
override fun setupPreferenceScreen(screen: PreferenceScreen) {
|
override fun setupPreferenceScreen(screen: PreferenceScreen) {
|
||||||
ListPreference(screen.context).apply {
|
ListPreference(screen.context).apply {
|
||||||
key = PREF_SERVER_KEY
|
key = PREF_SERVER_KEY
|
||||||
|
|
|
@ -24,5 +24,6 @@ dependencies {
|
||||||
implementation(project(':lib:upstream-extractor'))
|
implementation(project(':lib:upstream-extractor'))
|
||||||
implementation(project(':lib:streamhidevid-extractor'))
|
implementation(project(':lib:streamhidevid-extractor'))
|
||||||
implementation(project(':lib:streamsilk-extractor'))
|
implementation(project(':lib:streamsilk-extractor'))
|
||||||
|
implementation(project(':lib:vidguard-extractor'))
|
||||||
implementation "dev.datlag.jsunpacker:jsunpacker:1.0.1"
|
implementation "dev.datlag.jsunpacker:jsunpacker:1.0.1"
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,7 @@ import eu.kanade.tachiyomi.lib.streamtapeextractor.StreamTapeExtractor
|
||||||
import eu.kanade.tachiyomi.lib.streamwishextractor.StreamWishExtractor
|
import eu.kanade.tachiyomi.lib.streamwishextractor.StreamWishExtractor
|
||||||
import eu.kanade.tachiyomi.lib.upstreamextractor.UpstreamExtractor
|
import eu.kanade.tachiyomi.lib.upstreamextractor.UpstreamExtractor
|
||||||
import eu.kanade.tachiyomi.lib.uqloadextractor.UqloadExtractor
|
import eu.kanade.tachiyomi.lib.uqloadextractor.UqloadExtractor
|
||||||
|
import eu.kanade.tachiyomi.lib.vidguardextractor.VidGuardExtractor
|
||||||
import eu.kanade.tachiyomi.lib.voeextractor.VoeExtractor
|
import eu.kanade.tachiyomi.lib.voeextractor.VoeExtractor
|
||||||
import eu.kanade.tachiyomi.lib.youruploadextractor.YourUploadExtractor
|
import eu.kanade.tachiyomi.lib.youruploadextractor.YourUploadExtractor
|
||||||
import eu.kanade.tachiyomi.network.GET
|
import eu.kanade.tachiyomi.network.GET
|
||||||
|
@ -57,6 +58,7 @@ open class Pelisplushd(override val name: String, override val baseUrl: String)
|
||||||
"YourUpload", "BurstCloud", "Voe", "Mp4Upload", "Doodstream",
|
"YourUpload", "BurstCloud", "Voe", "Mp4Upload", "Doodstream",
|
||||||
"Upload", "BurstCloud", "Upstream", "StreamTape", "Amazon",
|
"Upload", "BurstCloud", "Upstream", "StreamTape", "Amazon",
|
||||||
"Fastream", "Filemoon", "StreamWish", "Okru", "Streamlare",
|
"Fastream", "Filemoon", "StreamWish", "Okru", "Streamlare",
|
||||||
|
"VidGuard",
|
||||||
)
|
)
|
||||||
|
|
||||||
private val REGEX_LINK = "https?:\\/\\/(www\\.)?[-a-zA-Z0-9@:%._\\+~#=]{1,256}\\.[a-zA-Z0-9()]{1,6}\\b([-a-zA-Z0-9()@:%_\\+.~#?&//=]*)".toRegex()
|
private val REGEX_LINK = "https?:\\/\\/(www\\.)?[-a-zA-Z0-9@:%._\\+~#=]{1,256}\\.[a-zA-Z0-9()]{1,6}\\b([-a-zA-Z0-9()@:%_\\+.~#?&//=]*)".toRegex()
|
||||||
|
@ -166,6 +168,7 @@ open class Pelisplushd(override val name: String, override val baseUrl: String)
|
||||||
private val streamTapeExtractor by lazy { StreamTapeExtractor(client) }
|
private val streamTapeExtractor by lazy { StreamTapeExtractor(client) }
|
||||||
private val streamHideVidExtractor by lazy { StreamHideVidExtractor(client) }
|
private val streamHideVidExtractor by lazy { StreamHideVidExtractor(client) }
|
||||||
private val streamSilkExtractor by lazy { StreamSilkExtractor(client) }
|
private val streamSilkExtractor by lazy { StreamSilkExtractor(client) }
|
||||||
|
private val vidGuardExtractor by lazy { VidGuardExtractor(client) }
|
||||||
|
|
||||||
fun serverVideoResolver(url: String, prefix: String = ""): List<Video> {
|
fun serverVideoResolver(url: String, prefix: String = ""): List<Video> {
|
||||||
return runCatching {
|
return runCatching {
|
||||||
|
@ -207,6 +210,7 @@ open class Pelisplushd(override val name: String, override val baseUrl: String)
|
||||||
arrayOf("streamsilk").any(url) -> streamSilkExtractor.videosFromUrl(url, videoNameGen = { "$prefix StreamSilk:$it" })
|
arrayOf("streamsilk").any(url) -> streamSilkExtractor.videosFromUrl(url, videoNameGen = { "$prefix StreamSilk:$it" })
|
||||||
arrayOf("streamtape", "stp", "stape").any(url) -> streamTapeExtractor.videosFromUrl(url, quality = "$prefix StreamTape")
|
arrayOf("streamtape", "stp", "stape").any(url) -> streamTapeExtractor.videosFromUrl(url, quality = "$prefix StreamTape")
|
||||||
arrayOf("ahvsh", "streamhide", "guccihide", "streamvid", "vidhide").any(url) -> streamHideVidExtractor.videosFromUrl(url, prefix = "$prefix ")
|
arrayOf("ahvsh", "streamhide", "guccihide", "streamvid", "vidhide").any(url) -> streamHideVidExtractor.videosFromUrl(url, prefix = "$prefix ")
|
||||||
|
arrayOf("vembed", "guard", "listeamed", "bembed", "vgfplay").any(url) -> vidGuardExtractor.videosFromUrl(url, prefix = "$prefix ")
|
||||||
else -> emptyList()
|
else -> emptyList()
|
||||||
}
|
}
|
||||||
}.getOrNull() ?: emptyList()
|
}.getOrNull() ?: emptyList()
|
||||||
|
|
|
@ -12,4 +12,5 @@ dependencies {
|
||||||
implementation(project(':lib:streamhidevid-extractor'))
|
implementation(project(':lib:streamhidevid-extractor'))
|
||||||
implementation(project(':lib:voe-extractor'))
|
implementation(project(':lib:voe-extractor'))
|
||||||
implementation(project(':lib:yourupload-extractor'))
|
implementation(project(':lib:yourupload-extractor'))
|
||||||
|
implementation(project(':lib:vidguard-extractor'))
|
||||||
}
|
}
|
|
@ -4,7 +4,6 @@ import android.app.Application
|
||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
import androidx.preference.ListPreference
|
import androidx.preference.ListPreference
|
||||||
import androidx.preference.PreferenceScreen
|
import androidx.preference.PreferenceScreen
|
||||||
import eu.kanade.tachiyomi.animeextension.es.veranimes.extractors.VidGuardExtractor
|
|
||||||
import eu.kanade.tachiyomi.animesource.ConfigurableAnimeSource
|
import eu.kanade.tachiyomi.animesource.ConfigurableAnimeSource
|
||||||
import eu.kanade.tachiyomi.animesource.model.AnimeFilterList
|
import eu.kanade.tachiyomi.animesource.model.AnimeFilterList
|
||||||
import eu.kanade.tachiyomi.animesource.model.AnimesPage
|
import eu.kanade.tachiyomi.animesource.model.AnimesPage
|
||||||
|
@ -15,6 +14,7 @@ import eu.kanade.tachiyomi.animesource.online.AnimeHttpSource
|
||||||
import eu.kanade.tachiyomi.lib.okruextractor.OkruExtractor
|
import eu.kanade.tachiyomi.lib.okruextractor.OkruExtractor
|
||||||
import eu.kanade.tachiyomi.lib.streamhidevidextractor.StreamHideVidExtractor
|
import eu.kanade.tachiyomi.lib.streamhidevidextractor.StreamHideVidExtractor
|
||||||
import eu.kanade.tachiyomi.lib.streamwishextractor.StreamWishExtractor
|
import eu.kanade.tachiyomi.lib.streamwishextractor.StreamWishExtractor
|
||||||
|
import eu.kanade.tachiyomi.lib.vidguardextractor.VidGuardExtractor
|
||||||
import eu.kanade.tachiyomi.lib.voeextractor.VoeExtractor
|
import eu.kanade.tachiyomi.lib.voeextractor.VoeExtractor
|
||||||
import eu.kanade.tachiyomi.lib.youruploadextractor.YourUploadExtractor
|
import eu.kanade.tachiyomi.lib.youruploadextractor.YourUploadExtractor
|
||||||
import eu.kanade.tachiyomi.network.GET
|
import eu.kanade.tachiyomi.network.GET
|
||||||
|
@ -56,6 +56,7 @@ class VerAnimes : ConfigurableAnimeSource, AnimeHttpSource() {
|
||||||
"YourUpload",
|
"YourUpload",
|
||||||
"FileLions",
|
"FileLions",
|
||||||
"StreamHideVid",
|
"StreamHideVid",
|
||||||
|
"VidGuard",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -157,23 +158,23 @@ class VerAnimes : ConfigurableAnimeSource, AnimeHttpSource() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*--------------------------------Video extractors------------------------------------*/
|
||||||
|
private val okruExtractor by lazy { OkruExtractor(client) }
|
||||||
|
private val streamWishExtractor by lazy { StreamWishExtractor(client, headers) }
|
||||||
|
private val streamHideVidExtractor by lazy { StreamHideVidExtractor(client) }
|
||||||
|
private val voeExtractor by lazy { VoeExtractor(client) }
|
||||||
|
private val yourUploadExtractor by lazy { YourUploadExtractor(client) }
|
||||||
|
private val vidGuardExtractor by lazy { VidGuardExtractor(client) }
|
||||||
|
|
||||||
private fun serverVideoResolver(url: String): List<Video> {
|
private fun serverVideoResolver(url: String): List<Video> {
|
||||||
val embedUrl = url.lowercase()
|
|
||||||
return when {
|
return when {
|
||||||
embedUrl.contains("ok.ru") || embedUrl.contains("okru") -> OkruExtractor(client).videosFromUrl(url)
|
arrayOf("ok.ru", "okru").any(url) -> okruExtractor.videosFromUrl(url)
|
||||||
embedUrl.contains("filelions") || embedUrl.contains("lion") -> StreamWishExtractor(client, headers).videosFromUrl(url, videoNameGen = { "FileLions:$it" })
|
arrayOf("filelions", "lion", "fviplions").any(url) -> streamWishExtractor.videosFromUrl(url, videoNameGen = { "FileLions:$it" })
|
||||||
embedUrl.contains("wishembed") || embedUrl.contains("streamwish") || embedUrl.contains("strwish") || embedUrl.contains("wish") -> {
|
arrayOf("wishembed", "streamwish", "strwish", "wish").any(url) -> streamWishExtractor.videosFromUrl(url, videoNameGen = { "StreamWish:$it" })
|
||||||
val docHeaders = headers.newBuilder()
|
arrayOf("vidhide", "streamhide", "guccihide", "streamvid").any(url) -> streamHideVidExtractor.videosFromUrl(url)
|
||||||
.add("Origin", "https://streamwish.to")
|
arrayOf("voe").any(url) -> voeExtractor.videosFromUrl(url)
|
||||||
.add("Referer", "https://streamwish.to/")
|
arrayOf("yourupload", "upload").any(url) -> yourUploadExtractor.videoFromUrl(url, headers = headers)
|
||||||
.build()
|
arrayOf("vembed", "guard", "listeamed", "bembed", "vgfplay").any(url) -> vidGuardExtractor.videosFromUrl(url)
|
||||||
StreamWishExtractor(client, docHeaders).videosFromUrl(url, videoNameGen = { "StreamWish:$it" })
|
|
||||||
}
|
|
||||||
embedUrl.contains("vidhide") || embedUrl.contains("streamhide") ||
|
|
||||||
embedUrl.contains("guccihide") || embedUrl.contains("streamvid") -> StreamHideVidExtractor(client).videosFromUrl(url)
|
|
||||||
embedUrl.contains("voe") -> VoeExtractor(client).videosFromUrl(url)
|
|
||||||
embedUrl.contains("yourupload") || embedUrl.contains("upload") -> YourUploadExtractor(client).videoFromUrl(url, headers = headers)
|
|
||||||
embedUrl.contains("vidguard") || embedUrl.contains("vgfplay") || embedUrl.contains("listeamed") -> VidGuardExtractor(client).videosFromUrl(url)
|
|
||||||
else -> emptyList()
|
else -> emptyList()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -192,6 +193,8 @@ class VerAnimes : ConfigurableAnimeSource, AnimeHttpSource() {
|
||||||
|
|
||||||
override fun getFilterList(): AnimeFilterList = VerAnimesFilters.FILTER_LIST
|
override fun getFilterList(): AnimeFilterList = VerAnimesFilters.FILTER_LIST
|
||||||
|
|
||||||
|
private fun Array<String>.any(url: String): Boolean = this.any { url.contains(it, ignoreCase = true) }
|
||||||
|
|
||||||
override fun setupPreferenceScreen(screen: PreferenceScreen) {
|
override fun setupPreferenceScreen(screen: PreferenceScreen) {
|
||||||
ListPreference(screen.context).apply {
|
ListPreference(screen.context).apply {
|
||||||
key = PREF_SERVER_KEY
|
key = PREF_SERVER_KEY
|
||||||
|
|
|
@ -1,124 +0,0 @@
|
||||||
package eu.kanade.tachiyomi.animeextension.es.veranimes.extractors
|
|
||||||
|
|
||||||
import android.app.Application
|
|
||||||
import android.os.Handler
|
|
||||||
import android.os.Looper
|
|
||||||
import android.util.Base64
|
|
||||||
import android.webkit.JavascriptInterface
|
|
||||||
import android.webkit.WebSettings
|
|
||||||
import android.webkit.WebView
|
|
||||||
import android.webkit.WebViewClient
|
|
||||||
import eu.kanade.tachiyomi.animesource.model.Video
|
|
||||||
import eu.kanade.tachiyomi.network.GET
|
|
||||||
import eu.kanade.tachiyomi.util.asJsoup
|
|
||||||
import okhttp3.Headers
|
|
||||||
import okhttp3.HttpUrl.Companion.toHttpUrl
|
|
||||||
import okhttp3.OkHttpClient
|
|
||||||
import uy.kohesive.injekt.injectLazy
|
|
||||||
import java.util.concurrent.CountDownLatch
|
|
||||||
import java.util.concurrent.TimeUnit
|
|
||||||
|
|
||||||
class VidGuardExtractor(private val client: OkHttpClient) {
|
|
||||||
private val context: Application by injectLazy()
|
|
||||||
private val handler by lazy { Handler(Looper.getMainLooper()) }
|
|
||||||
|
|
||||||
class JsObject(private val latch: CountDownLatch) {
|
|
||||||
var payload: String = ""
|
|
||||||
|
|
||||||
@JavascriptInterface
|
|
||||||
fun passPayload(passedPayload: String) {
|
|
||||||
payload = passedPayload
|
|
||||||
latch.countDown()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun videosFromUrl(url: String): List<Video> {
|
|
||||||
val doc = client.newCall(GET(url)).execute().asJsoup()
|
|
||||||
val scriptUrl = doc.selectFirst("script[src*=ad/plugin]")
|
|
||||||
?.absUrl("src")
|
|
||||||
?: return emptyList()
|
|
||||||
|
|
||||||
val headers = Headers.headersOf("Referer", url)
|
|
||||||
val script = client.newCall(GET(scriptUrl, headers)).execute()
|
|
||||||
.body.string()
|
|
||||||
|
|
||||||
val sources = getSourcesFromScript(script, url)
|
|
||||||
.takeIf { it.isNotBlank() && it != "undefined" }
|
|
||||||
?: return emptyList()
|
|
||||||
|
|
||||||
return sources.substringAfter("stream:[").substringBefore("}]")
|
|
||||||
.split('{')
|
|
||||||
.drop(1)
|
|
||||||
.mapNotNull { line ->
|
|
||||||
val resolution = line.substringAfter("Label\":\"").substringBefore('"')
|
|
||||||
val videoUrl = line.substringAfter("URL\":\"").substringBefore('"')
|
|
||||||
.takeIf(String::isNotBlank)
|
|
||||||
?.let(::fixUrl)
|
|
||||||
?: return@mapNotNull null
|
|
||||||
Video(videoUrl, "VidGuard:$resolution", videoUrl, headers)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getSourcesFromScript(script: String, url: String): String {
|
|
||||||
val latch = CountDownLatch(1)
|
|
||||||
|
|
||||||
var webView: WebView? = null
|
|
||||||
|
|
||||||
val jsinterface = JsObject(latch)
|
|
||||||
|
|
||||||
handler.post {
|
|
||||||
val webview = WebView(context)
|
|
||||||
webView = webview
|
|
||||||
with(webview.settings) {
|
|
||||||
javaScriptEnabled = true
|
|
||||||
domStorageEnabled = true
|
|
||||||
databaseEnabled = true
|
|
||||||
useWideViewPort = false
|
|
||||||
loadWithOverviewMode = false
|
|
||||||
cacheMode = WebSettings.LOAD_NO_CACHE
|
|
||||||
}
|
|
||||||
|
|
||||||
webview.addJavascriptInterface(jsinterface, "android")
|
|
||||||
webview.webViewClient = object : WebViewClient() {
|
|
||||||
override fun onPageFinished(view: WebView?, url: String?) {
|
|
||||||
view?.clearCache(true)
|
|
||||||
view?.clearFormData()
|
|
||||||
view?.evaluateJavascript(script) {}
|
|
||||||
view?.evaluateJavascript("window.android.passPayload(JSON.stringify(window.svg))") {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
webview.loadDataWithBaseURL(url, "<html></html>", "text/html", "UTF-8", null)
|
|
||||||
}
|
|
||||||
|
|
||||||
latch.await(5, TimeUnit.SECONDS)
|
|
||||||
|
|
||||||
handler.post {
|
|
||||||
webView?.stopLoading()
|
|
||||||
webView?.destroy()
|
|
||||||
webView = null
|
|
||||||
}
|
|
||||||
|
|
||||||
return jsinterface.payload
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun fixUrl(url: String): String {
|
|
||||||
val httpUrl = url.toHttpUrl()
|
|
||||||
val originalSign = httpUrl.queryParameter("sig")!!
|
|
||||||
val newSign = originalSign.chunked(2).joinToString("") {
|
|
||||||
Char(it.toInt(16) xor 2).toString()
|
|
||||||
}
|
|
||||||
.let { String(Base64.decode(it, Base64.DEFAULT)) }
|
|
||||||
.substring(5)
|
|
||||||
.chunked(2)
|
|
||||||
.reversed()
|
|
||||||
.joinToString("")
|
|
||||||
.substring(5)
|
|
||||||
|
|
||||||
return httpUrl.newBuilder()
|
|
||||||
.removeAllQueryParameters("sig")
|
|
||||||
.addQueryParameter("sig", newSign)
|
|
||||||
.build()
|
|
||||||
.toString()
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Add table
Add a link
Reference in a new issue