forked from recloudstream/cloudstream
more links gogo, fixed #503
This commit is contained in:
parent
26ba1de2f2
commit
45567fb4f4
4 changed files with 160 additions and 34 deletions
|
@ -267,10 +267,24 @@ abstract class MainAPI {
|
|||
/** Might need a different implementation for desktop*/
|
||||
@SuppressLint("NewApi")
|
||||
fun base64Decode(string: String): String {
|
||||
return String(base64DecodeArray(string), Charsets.ISO_8859_1)
|
||||
}
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
fun base64DecodeArray(string: String): ByteArray {
|
||||
return try {
|
||||
String(android.util.Base64.decode(string, android.util.Base64.DEFAULT), Charsets.ISO_8859_1)
|
||||
android.util.Base64.decode(string, android.util.Base64.DEFAULT)
|
||||
} catch (e: Exception) {
|
||||
String(Base64.getDecoder().decode(string))
|
||||
Base64.getDecoder().decode(string)
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
fun base64Encode(array: ByteArray): String {
|
||||
return try {
|
||||
String(android.util.Base64.encode(array, android.util.Base64.NO_WRAP), Charsets.ISO_8859_1)
|
||||
} catch (e: Exception) {
|
||||
String(Base64.getEncoder().encode(array))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -29,6 +29,26 @@ fun <T, R> Iterable<T>.pmap(
|
|||
return ArrayList<R>(destination)
|
||||
}
|
||||
|
||||
fun <A, B>List<A>.apmap(f: suspend (A) -> B): List<B> = runBlocking {
|
||||
fun <A, B> List<A>.apmap(f: suspend (A) -> B): List<B> = runBlocking {
|
||||
map { async { f(it) } }.map { it.await() }
|
||||
}
|
||||
}
|
||||
|
||||
// run code in parallel
|
||||
fun <R> argpmap(
|
||||
vararg transforms: () -> R,
|
||||
numThreads: Int = maxOf(Runtime.getRuntime().availableProcessors() - 2, 1),
|
||||
exec: ExecutorService = Executors.newFixedThreadPool(numThreads)
|
||||
) {
|
||||
for (item in transforms) {
|
||||
exec.submit { item.invoke() }
|
||||
}
|
||||
|
||||
exec.shutdown()
|
||||
exec.awaitTermination(1, TimeUnit.DAYS)
|
||||
}
|
||||
|
||||
//fun <R> argamap(
|
||||
// vararg transforms: () -> R,
|
||||
//) = runBlocking {
|
||||
// transforms.map { async { it.invoke() } }.map { it.await() }
|
||||
//}
|
|
@ -1,11 +1,15 @@
|
|||
package com.lagradost.cloudstream3.animeproviders
|
||||
|
||||
import com.lagradost.cloudstream3.*
|
||||
import com.lagradost.cloudstream3.utils.AppUtils
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.getQualityFromName
|
||||
import com.lagradost.cloudstream3.utils.loadExtractor
|
||||
import org.jsoup.Jsoup
|
||||
import java.util.*
|
||||
import javax.crypto.Cipher
|
||||
import javax.crypto.spec.IvParameterSpec
|
||||
import javax.crypto.spec.SecretKeySpec
|
||||
|
||||
class GogoanimeProvider : MainAPI() {
|
||||
companion object {
|
||||
|
@ -24,6 +28,26 @@ class GogoanimeProvider : MainAPI() {
|
|||
}
|
||||
|
||||
val qualityRegex = Regex("(\\d+)P")
|
||||
|
||||
// https://github.com/saikou-app/saikou/blob/3e756bd8e876ad7a9318b17110526880525a5cd3/app/src/main/java/ani/saikou/anime/source/extractors/GogoCDN.kt#L60
|
||||
// No Licence on the function
|
||||
private fun cryptoHandler(
|
||||
string: String,
|
||||
iv: ByteArray,
|
||||
secretKeyString: ByteArray,
|
||||
encrypt: Boolean = true
|
||||
): String {
|
||||
val ivParameterSpec = IvParameterSpec(iv)
|
||||
val secretKey = SecretKeySpec(secretKeyString, "AES")
|
||||
val cipher = Cipher.getInstance("AES/CBC/PKCS5Padding")
|
||||
return if (!encrypt) {
|
||||
cipher.init(Cipher.DECRYPT_MODE, secretKey, ivParameterSpec)
|
||||
String(cipher.doFinal(base64DecodeArray(string)))
|
||||
} else {
|
||||
cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivParameterSpec)
|
||||
base64Encode(cipher.doFinal(string.toByteArray()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override val mainUrl = "https://gogoanime.wiki"
|
||||
|
@ -193,43 +217,111 @@ class GogoanimeProvider : MainAPI() {
|
|||
}
|
||||
}
|
||||
|
||||
data class GogoSources(
|
||||
val source: List<GogoSource>?,
|
||||
val sourceBk: List<GogoSource>?,
|
||||
//val track: List<Any?>,
|
||||
//val advertising: List<Any?>,
|
||||
//val linkiframe: String
|
||||
)
|
||||
|
||||
data class GogoSource(
|
||||
val file: String,
|
||||
val label: String?,
|
||||
val type: String?,
|
||||
val default: String? = null
|
||||
)
|
||||
|
||||
private fun extractVideos(uri: String, callback: (ExtractorLink) -> Unit) {
|
||||
val doc = app.get(uri).document
|
||||
|
||||
val iframe = fixUrlNull(doc.selectFirst("div.play-video > iframe").attr("src")) ?: return
|
||||
|
||||
val link = iframe.replace("streaming.php", "download")
|
||||
val page = app.get(link, headers = mapOf("Referer" to iframe))
|
||||
argpmap(
|
||||
{
|
||||
val link = iframe.replace("streaming.php", "download")
|
||||
val page = app.get(link, headers = mapOf("Referer" to iframe))
|
||||
|
||||
page.document.select(".dowload > a").pmap {
|
||||
if (it.hasAttr("download")) {
|
||||
val qual = if (it.text()
|
||||
.contains("HDP")
|
||||
) "1080" else qualityRegex.find(it.text())?.destructured?.component1().toString()
|
||||
callback(
|
||||
ExtractorLink(
|
||||
"Gogoanime",
|
||||
if (qual == "null") "Gogoanime" else "Gogoanime - " + qual + "p",
|
||||
it.attr("href"),
|
||||
page.url,
|
||||
getQualityFromName(qual),
|
||||
it.attr("href").contains(".m3u8")
|
||||
)
|
||||
)
|
||||
} else {
|
||||
val url = it.attr("href")
|
||||
loadExtractor(url, null, callback)
|
||||
}
|
||||
}
|
||||
page.document.select(".dowload > a").pmap {
|
||||
if (it.hasAttr("download")) {
|
||||
val qual = if (it.text()
|
||||
.contains("HDP")
|
||||
) "1080" else qualityRegex.find(it.text())?.destructured?.component1()
|
||||
.toString()
|
||||
callback(
|
||||
ExtractorLink(
|
||||
"Gogoanime",
|
||||
if (qual == "null") "Gogoanime" else "Gogoanime - " + qual + "p",
|
||||
it.attr("href"),
|
||||
page.url,
|
||||
getQualityFromName(qual),
|
||||
it.attr("href").contains(".m3u8")
|
||||
)
|
||||
)
|
||||
} else {
|
||||
val url = it.attr("href")
|
||||
loadExtractor(url, null, callback)
|
||||
}
|
||||
}
|
||||
}, {
|
||||
val streamingResponse = app.get(iframe, headers = mapOf("Referer" to iframe))
|
||||
val streamingDocument = streamingResponse.document
|
||||
argpmap({
|
||||
streamingDocument.select(".list-server-items > .linkserver")
|
||||
?.forEach { element ->
|
||||
val status = element.attr("data-status") ?: return@forEach
|
||||
if (status != "1") return@forEach
|
||||
val data = element.attr("data-video") ?: return@forEach
|
||||
loadExtractor(data, streamingResponse.url, callback)
|
||||
}
|
||||
}, {
|
||||
// https://github.com/saikou-app/saikou/blob/3e756bd8e876ad7a9318b17110526880525a5cd3/app/src/main/java/ani/saikou/anime/source/extractors/GogoCDN.kt
|
||||
// No Licence on the following code
|
||||
val encrypted =
|
||||
streamingDocument.select("script[data-name='crypto']").attr("data-value")
|
||||
val iv = streamingDocument.select("script[data-name='ts']").attr("data-value")
|
||||
.toByteArray()
|
||||
|
||||
val streamingResponse = app.get(iframe, headers = mapOf("Referer" to iframe))
|
||||
streamingResponse.document.select(".list-server-items > .linkserver")
|
||||
?.forEach { element ->
|
||||
val status = element.attr("data-status") ?: return@forEach
|
||||
if (status != "1") return@forEach
|
||||
val data = element.attr("data-video") ?: return@forEach
|
||||
loadExtractor(data, streamingResponse.url, callback)
|
||||
val id = Regex("id=([^&]+)").find(iframe)!!.value.removePrefix("id=")
|
||||
|
||||
val secretKey = cryptoHandler(encrypted, iv, iv + iv, false)
|
||||
val encryptedId =
|
||||
cryptoHandler(id, "0000000000000000".toByteArray(), secretKey.toByteArray())
|
||||
|
||||
val jsonResponse =
|
||||
app.get(
|
||||
"http://gogoplay.io/encrypt-ajax.php?id=$encryptedId&time=00000000000000000000",
|
||||
headers = mapOf("X-Requested-With" to "XMLHttpRequest")
|
||||
)
|
||||
val sources = AppUtils.parseJson<GogoSources>(jsonResponse.text)
|
||||
|
||||
fun invokeGogoSource(
|
||||
source: GogoSource,
|
||||
sourceCallback: (ExtractorLink) -> Unit
|
||||
) {
|
||||
sourceCallback.invoke(
|
||||
ExtractorLink(
|
||||
this.name,
|
||||
"${this.name} ${source.label?.replace("0 P","0p") ?: ""}",
|
||||
source.file,
|
||||
"",
|
||||
getQualityFromName(source.label ?: ""),
|
||||
isM3u8 = source.type == "hls"
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
sources.source?.forEach {
|
||||
println("${this.name} ${it.label ?: ""}")
|
||||
invokeGogoSource(it, callback)
|
||||
}
|
||||
sources.sourceBk?.forEach {
|
||||
println("${this.name} ${it.label ?: ""}")
|
||||
invokeGogoSource(it, callback)
|
||||
}
|
||||
})
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun loadLinks(
|
||||
|
|
|
@ -52,7 +52,7 @@ enum class Qualities(var value: Int) {
|
|||
}
|
||||
|
||||
fun getQualityFromName(qualityName: String): Int {
|
||||
return when (qualityName.replace("p", "").replace("P", "")) {
|
||||
return when (qualityName.replace("p", "").replace("P", "").trim()) {
|
||||
"360" -> Qualities.P360
|
||||
"480" -> Qualities.P480
|
||||
"720" -> Qualities.P720
|
||||
|
|
Loading…
Reference in a new issue