-
Notifications
You must be signed in to change notification settings - Fork 260
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(lib): Convert GogoCdn/Vidstreaming extractor to shared lib (#2361)
- Loading branch information
1 parent
9c8799b
commit 05353c8
Showing
3 changed files
with
129 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
plugins { | ||
id("com.android.library") | ||
kotlin("android") | ||
id("kotlinx-serialization") | ||
} | ||
|
||
android { | ||
compileSdk = AndroidConfig.compileSdk | ||
namespace = "eu.kanade.tachiyomi.lib.gogostreamextractor" | ||
|
||
defaultConfig { | ||
minSdk = AndroidConfig.minSdk | ||
} | ||
} | ||
|
||
dependencies { | ||
compileOnly(libs.bundles.common) | ||
implementation(project(":lib-playlist-utils")) | ||
} |
97 changes: 97 additions & 0 deletions
97
...xtractor/src/main/java/eu/kanade/tachiyomi/lib/gogostreamextractor/GogoStreamExtractor.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
package eu.kanade.tachiyomi.lib.gogostreamextractor | ||
|
||
import android.util.Base64 | ||
import eu.kanade.tachiyomi.animesource.model.Video | ||
import eu.kanade.tachiyomi.network.GET | ||
import eu.kanade.tachiyomi.util.asJsoup | ||
import kotlinx.serialization.json.Json | ||
import okhttp3.Headers | ||
import eu.kanade.tachiyomi.lib.playlistutils.PlaylistUtils | ||
import okhttp3.HttpUrl.Companion.toHttpUrl | ||
import okhttp3.OkHttpClient | ||
import java.lang.Exception | ||
import java.util.Locale | ||
import org.jsoup.nodes.Element | ||
import javax.crypto.Cipher | ||
import javax.crypto.spec.IvParameterSpec | ||
import javax.crypto.spec.SecretKeySpec | ||
import uy.kohesive.injekt.injectLazy | ||
|
||
class GogoStreamExtractor(private val client: OkHttpClient) { | ||
private val json: Json by injectLazy() | ||
private val playlistUtils by lazy { PlaylistUtils(client) } | ||
|
||
private fun Element.getBytesAfter(item: String) = className() | ||
.substringAfter(item) | ||
.filter(Char::isDigit) | ||
.toByteArray() | ||
|
||
fun videosFromUrl(serverUrl: String): List<Video> { | ||
return runCatching { | ||
val document = client.newCall(GET(serverUrl)).execute().use { it.asJsoup() } | ||
val iv = document.selectFirst("div.wrapper")!!.getBytesAfter("container-") | ||
val secretKey = document.selectFirst("body[class]")!!.getBytesAfter("container-") | ||
val decryptionKey = document.selectFirst("div.videocontent")!!.getBytesAfter("videocontent-") | ||
|
||
val decryptedAjaxParams = cryptoHandler( | ||
document.selectFirst("script[data-value]")!!.attr("data-value"), | ||
iv, | ||
secretKey, | ||
encrypt = false, | ||
).substringAfter("&") | ||
|
||
val httpUrl = serverUrl.toHttpUrl() | ||
val host = "https://" + httpUrl.host | ||
val id = httpUrl.queryParameter("id") ?: throw Exception("error getting id") | ||
val encryptedId = cryptoHandler(id, iv, secretKey) | ||
val token = httpUrl.queryParameter("token") | ||
val qualityPrefix = if (token != null) "Gogostream - " else "Vidstreaming - " | ||
|
||
val jsonResponse = client.newCall( | ||
GET( | ||
"$host/encrypt-ajax.php?id=$encryptedId&$decryptedAjaxParams&alias=$id", | ||
Headers.headersOf( | ||
"X-Requested-With", | ||
"XMLHttpRequest", | ||
), | ||
), | ||
).execute().use { it.body.string() } | ||
|
||
val data = json.decodeFromString<EncryptedDataDto>(jsonResponse).data | ||
val sourceList = cryptoHandler(data, iv, decryptionKey, false) | ||
.let { json.decodeFromString<DecryptedDataDto>(it) } | ||
.source | ||
|
||
when { | ||
sourceList.size == 1 && sourceList.first().type == "hls" -> { | ||
val playlistUrl = sourceList.first().file | ||
playlistUtils.extractFromHls(playlistUrl, serverUrl, videoNameGen = { qualityPrefix + it }) | ||
} | ||
else -> { | ||
val headers = Headers.headersOf("Referer", serverUrl) | ||
sourceList.map { video -> | ||
Video(video.file, qualityPrefix + video.label, video.file, headers) | ||
} | ||
} | ||
} | ||
}.getOrElse { emptyList() } | ||
} | ||
|
||
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(Base64.decode(string, Base64.DEFAULT))) | ||
} else { | ||
cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivParameterSpec) | ||
Base64.encodeToString(cipher.doFinal(string.toByteArray()), Base64.NO_WRAP) | ||
} | ||
} | ||
} |
13 changes: 13 additions & 0 deletions
13
...actor/src/main/java/eu/kanade/tachiyomi/lib/gogostreamextractor/GogoStreamExtractorDto.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package eu.kanade.tachiyomi.lib.gogostreamextractor | ||
|
||
import kotlinx.serialization.SerialName | ||
import kotlinx.serialization.Serializable | ||
|
||
@Serializable | ||
data class EncryptedDataDto(val data: String) | ||
|
||
@Serializable | ||
data class DecryptedDataDto(val source: List<SourceDto>) | ||
|
||
@Serializable | ||
data class SourceDto(val file: String, val label: String = "", val type: String) |