gogo: fix video links

This commit is contained in:
jmir1
2022-01-07 15:22:03 +01:00
parent e58267f22d
commit cd640b5e2c
4 changed files with 189 additions and 90 deletions

View File

@ -5,7 +5,7 @@ ext {
extName = 'Gogoanime'
pkgNameSuffix = 'en.gogoanime'
extClass = '.GogoAnime'
extVersionCode = 24
extVersionCode = 25
libVersion = '12'
}

View File

@ -0,0 +1,100 @@
package eu.kanade.tachiyomi.animeextension.en.gogoanime
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.WebSettings
import android.webkit.WebView
import android.webkit.WebViewClient
import eu.kanade.tachiyomi.network.GET
import okhttp3.Headers.Companion.toHeaders
import okhttp3.Interceptor
import okhttp3.Request
import okhttp3.Response
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
import java.io.IOException
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit
class GetSourcesInterceptor() : Interceptor {
private val context = Injekt.get<Application>()
private val handler by lazy { Handler(Looper.getMainLooper()) }
private val initWebView by lazy {
WebSettings.getDefaultUserAgent(context)
}
@Synchronized
override fun intercept(chain: Interceptor.Chain): Response {
initWebView
val request = chain.request()
try {
val newRequest = resolveWithWebView(request)
return chain.proceed(newRequest ?: request)
} catch (e: Exception) {
throw IOException(e)
}
}
@SuppressLint("SetJavaScriptEnabled")
private fun resolveWithWebView(request: Request): Request? {
val latch = CountDownLatch(1)
var webView: WebView? = null
val origRequestUrl = request.url.toString()
val headers = request.headers.toMultimap().mapValues { it.value.getOrNull(0) ?: "" }.toMutableMap()
var newRequest: Request? = null
handler.post {
val webview = WebView(context)
webView = webview
with(webview.settings) {
javaScriptEnabled = true
domStorageEnabled = true
databaseEnabled = true
useWideViewPort = false
loadWithOverviewMode = false
userAgentString = "Mozilla/5.0 (Linux; Android) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.109 Safari/537.36 CrKey/1.54.248666"
}
webview.webViewClient = object : WebViewClient() {
override fun shouldInterceptRequest(
view: WebView,
request: WebResourceRequest
): WebResourceResponse? {
val url = request.url.toString()
if (url.contains("https://gogoplay.io/encrypt-ajax.php")) {
Log.i("bruh", "hi")
val newHeaders = request.requestHeaders.toHeaders()
newRequest = GET(url, newHeaders)
latch.countDown()
}
return super.shouldInterceptRequest(view, request)
}
}
webView?.loadUrl(origRequestUrl, headers)
}
latch.await(TIMEOUT_SEC, TimeUnit.SECONDS)
handler.post {
webView?.stopLoading()
webView?.destroy()
webView = null
}
return newRequest
}
companion object {
const val TIMEOUT_SEC: Long = 10
}
}

View File

@ -4,6 +4,7 @@ import android.app.Application
import android.content.SharedPreferences
import androidx.preference.ListPreference
import androidx.preference.PreferenceScreen
import eu.kanade.tachiyomi.animeextension.en.gogoanime.extractors.DoodExtractor
import eu.kanade.tachiyomi.animesource.ConfigurableAnimeSource
import eu.kanade.tachiyomi.animesource.model.AnimeFilter
import eu.kanade.tachiyomi.animesource.model.AnimeFilterList
@ -13,22 +14,29 @@ import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.animesource.online.ParsedAnimeHttpSource
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.util.asJsoup
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.jsonArray
import kotlinx.serialization.json.jsonObject
import kotlinx.serialization.json.jsonPrimitive
import okhttp3.Headers
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.Response
import org.jsoup.Jsoup
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import org.jsoup.select.Elements
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
import uy.kohesive.injekt.injectLazy
import java.lang.Exception
class GogoAnime : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
override val name = "Gogoanime"
override val baseUrl = "https://gogoanime.cm"
override val baseUrl = "https://www3.gogoanime.cm"
override val lang = "en"
@ -36,6 +44,8 @@ class GogoAnime : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
override val client: OkHttpClient = network.cloudflareClient
private val json: Json by injectLazy()
private val preferences: SharedPreferences by lazy {
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
}
@ -80,103 +90,52 @@ class GogoAnime : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
return episode
}
override fun videoListRequest(episode: SEpisode): Request {
val document = client.newCall(GET(baseUrl + episode.url)).execute().asJsoup()
val link = document.selectFirst("li.dowloads a").attr("href")
return GET(link)
}
override fun videoListParse(response: Response): List<Video> {
val document = response.asJsoup()
return document.select(videoListSelector()).ordered().map { videoFromElement(it) }
.filter { it.videoUrl != null }
val responseString = response.body!!.string()
val doc = Jsoup.parse(
responseString
.substringAfter("<!------------------ vidstream.io server type = 1 display --------------->")
.substringBefore("<!--")
)
val iframe = "https:" + doc.select("iframe").attr("src")
val baseReferer = Headers.headersOf("Referer", baseUrl)
val iframeResponse = client.newCall(GET(iframe, baseReferer)).execute().asJsoup()
val videoList = mutableListOf<Video>()
// get mirror videos
val mirrors = iframeResponse.select("div#list-server-more ul li.linkserver:not(li.active)")
val doodMirror = mirrors.first { it.attr("data-video").startsWith("https://dood.") }.attr("data-video")
val doodVideo = DoodExtractor(client).videoFromUrl(doodMirror)
// get vidstreaming videos
try {
val interceptorClient = client.newBuilder().addInterceptor(GetSourcesInterceptor()).build()
val sources = interceptorClient.newCall(GET(iframe, baseReferer)).execute().body!!.string()
val jObject = json.decodeFromString<JsonObject>(sources)
val sourcesArray = jObject["source"]!!.jsonArray
val videoHeaders = Headers.headersOf("Referer", iframe)
for (element in sourcesArray.reversed()) {
val videoUrl = element.jsonObject["file"]!!.jsonPrimitive.content
val quality = element.jsonObject["label"]!!.jsonPrimitive.content
videoList.add(Video(videoUrl, quality, videoUrl, null, videoHeaders))
}
} catch (e: Exception) {}
if (doodVideo != null) {
videoList.add(doodVideo)
}
if (videoList.isEmpty()) throw Exception("no links found")
return videoList
}
private fun Elements.ordered(): Elements {
val newElements = Elements()
var googleElements = 0
for (element in this) {
if (element.attr("href").contains("https://dood")) {
newElements.add(element)
continue
}
newElements.add(googleElements, element)
if (element.attr("href").contains("google")) {
googleElements++
}
}
return newElements
}
override fun videoListSelector() = throw Exception("not used")
override fun videoListSelector() = "div.mirror_link a[download], div.mirror_link a[href*=https://dood]"
override fun videoFromElement(element: Element): Video {
val quality = element.text().substringAfter("Download (").replace("P - mp4)", "p")
val url = element.attr("href")
val location = element.ownerDocument().location()
val videoHeaders = Headers.headersOf("Referer", location)
return when {
url.contains("https://dood") -> {
val newQuality = "Doodstream mirror"
Video(url, newQuality, doodUrlParse(url), null, videoHeaders)
}
url.contains("google") -> {
val parsedQuality = "Google server: " + when (quality) {
"FullHDp" -> "1080p"
"HDp" -> "720p"
"SDp" -> "360p"
else -> quality
}
Video(url, parsedQuality, url, null)
}
else -> {
val parsedQuality = when (quality) {
"FullHDp" -> "1080p"
"HDp" -> "720p"
"SDp" -> "360p"
else -> quality
}
Video(url, parsedQuality, videoUrlParse(url, location), null, videoHeaders)
}
}
}
override fun videoFromElement(element: Element) = throw Exception("not used")
override fun videoUrlParse(document: Document) = throw Exception("not used")
private fun videoUrlParse(url: String, referer: String): String {
val refererHeader = Headers.headersOf("Referer", referer)
val noRedirectClient = client.newBuilder().followRedirects(false).build()
val response = noRedirectClient.newCall(GET(url, refererHeader)).execute()
val videoUrl = response.header("location")
response.close()
return videoUrl ?: url
}
private fun doodUrlParse(url: String): String? {
val response = client.newCall(GET(url.replace("/d/", "/e/"))).execute()
val content = response.body!!.string()
if (!content.contains("'/pass_md5/")) return null
val md5 = content.substringAfter("'/pass_md5/").substringBefore("',")
val token = md5.substringAfterLast("/")
val doodTld = url.substringAfter("https://dood.").substringBefore("/")
val randomString = getRandomString()
val expiry = System.currentTimeMillis()
val videoUrlStart = client.newCall(
GET(
"https://dood.$doodTld/pass_md5/$md5",
Headers.headersOf("referer", url)
)
).execute().body!!.string()
return "$videoUrlStart$randomString?token=$token&expiry=$expiry"
}
private fun getRandomString(length: Int = 10): String {
val allowedChars = ('A'..'Z') + ('a'..'z') + ('0'..'9')
return (1..length)
.map { allowedChars.random() }
.joinToString("")
}
override fun List<Video>.sort(): List<Video> {
val quality = preferences.getString("preferred_quality", null)
if (quality != null) {

View File

@ -0,0 +1,40 @@
package eu.kanade.tachiyomi.animeextension.en.gogoanime.extractors
import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.network.GET
import okhttp3.Headers
import okhttp3.OkHttpClient
class DoodExtractor(private val client: OkHttpClient) {
fun videoFromUrl(url: String): Video? {
val response = client.newCall(GET(url)).execute()
val doodTld = url.substringAfter("https://dood.").substringBefore("/")
val content = response.body!!.string()
if (!content.contains("'/pass_md5/")) return null
val md5 = content.substringAfter("'/pass_md5/").substringBefore("',")
val token = md5.substringAfterLast("/")
val randomString = getRandomString()
val expiry = System.currentTimeMillis()
val videoUrlStart = client.newCall(
GET(
"https://dood.$doodTld/pass_md5/$md5",
Headers.headersOf("referer", url)
)
).execute().body!!.string()
val videoUrl = "$videoUrlStart$randomString?token=$token&expiry=$expiry"
return Video(url, "Doodstream mirror", videoUrl, null, doodHeaders(doodTld))
}
private fun getRandomString(length: Int = 10): String {
val allowedChars = ('A'..'Z') + ('a'..'z') + ('0'..'9')
return (1..length)
.map { allowedChars.random() }
.joinToString("")
}
private fun doodHeaders(tld: String) = Headers.Builder().apply {
add("User-Agent", "Aniyomi")
add("Referer", "https://dood.$tld/")
}.build()
}