Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(multisrc): new theme #2347

Merged
merged 5 commits into from
Oct 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .run/ZoroThemeGenerator.run.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="ZoroThemeGenerator" type="JetRunConfigurationType" nameIsGenerated="true">
<module name="aniyomi-extensions.multisrc.main" />
<option name="MAIN_CLASS_NAME" value="eu.kanade.tachiyomi.multisrc.zorotheme.ZoroThemeGenerator" />
<method v="2">
<option name="Make" enabled="true" />
<option name="Gradle.BeforeRunTask" enabled="true" tasks="ktFormat" externalProjectPath="$PROJECT_DIR$/multisrc" vmOptions="" scriptParameters="-Ptheme=zorotheme" />
<option name="Gradle.BeforeRunTask" enabled="true" tasks="ktLint" externalProjectPath="$PROJECT_DIR$/multisrc" vmOptions="" scriptParameters="-Ptheme=zorotheme" />
</method>
</configuration>
</component>
21 changes: 21 additions & 0 deletions lib/megacloud-extractor/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
plugins {
id("com.android.library")
kotlin("android")
id("kotlinx-serialization")
}

android {
compileSdk = AndroidConfig.compileSdk
namespace = "eu.kanade.tachiyomi.lib.megacloudextractor"

defaultConfig {
minSdk = AndroidConfig.minSdk
}
}

dependencies {
compileOnly(libs.bundles.common)
implementation(project(":lib-cryptoaes"))
implementation(project(":lib-playlist-utils"))
}
// BUMPS: 0
Original file line number Diff line number Diff line change
@@ -1,19 +1,30 @@
package eu.kanade.tachiyomi.animeextension.en.zoro.extractors
package eu.kanade.tachiyomi.lib.megacloudextractor

import eu.kanade.tachiyomi.animeextension.en.zoro.dto.SourceResponseDto
import eu.kanade.tachiyomi.animeextension.en.zoro.dto.VideoDto
import eu.kanade.tachiyomi.animeextension.en.zoro.dto.VideoLink
import eu.kanade.tachiyomi.animesource.model.Track
import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.lib.cryptoaes.CryptoAES
import eu.kanade.tachiyomi.lib.playlistutils.PlaylistUtils
import okhttp3.Headers
import eu.kanade.tachiyomi.network.GET
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.jsonPrimitive
import okhttp3.OkHttpClient
import uy.kohesive.injekt.injectLazy
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.JsonElement
import okhttp3.CacheControl
import okhttp3.HttpUrl.Companion.toHttpUrl

class AniWatchExtractor(private val client: OkHttpClient) {
class MegaCloudExtractor(private val client: OkHttpClient, private val headers: Headers) {
private val json: Json by injectLazy()

private val playlistUtils by lazy { PlaylistUtils(client, headers) }

private val cacheControl = CacheControl.Builder().noStore().build()
private val noCacheClient = client.newBuilder()
.cache(null)
.build()

companion object {
private val SERVER_URL = arrayOf("https://megacloud.tv", "https://rapid-cloud.co")
private val SOURCES_URL = arrayOf("/embed-2/ajax/e-1/getSources?id=", "/ajax/embed-6-v2/getSources?id=")
Expand All @@ -24,7 +35,7 @@ class AniWatchExtractor(private val client: OkHttpClient) {
private fun cipherTextCleaner(data: String, type: String): Pair<String, String> {
// TODO: fetch the key only when needed, using a thread-safe map
// (Like ConcurrentMap?) or MUTEX hacks.
val indexPairs = client.newCall(GET("https://raw.githubusercontent.com/Claudemirovsky/keys/e$type/key"))
val indexPairs = noCacheClient.newCall(GET("https://raw.githubusercontent.com/Claudemirovsky/keys/e$type/key", cache = cacheControl))
.execute()
.use { it.body.string() }
.let { json.decodeFromString<List<List<Int>>>(it) }
Expand All @@ -49,7 +60,23 @@ class AniWatchExtractor(private val client: OkHttpClient) {
}
}

fun getVideoDto(url: String): VideoDto {
fun getVideosFromUrl(url: String, type: String, name: String): List<Video> {
val video = getVideoDto(url)

val masterUrl = video.sources.first().file
val subs2 = video.tracks
?.filter { it.kind == "captions" }
?.map { Track(it.file, it.label) }
?: emptyList()
return playlistUtils.extractFromHls(
masterUrl,
videoNameGen = { "$name - $it - $type" },
subtitleList = subs2,
referer = "https://${url.toHttpUrl().host}/"
)
}

private fun getVideoDto(url: String): VideoDto {
val type = if (url.startsWith("https://megacloud.tv")) 0 else 1
val keyType = SOURCES_KEY[type]

Expand All @@ -60,10 +87,32 @@ class AniWatchExtractor(private val client: OkHttpClient) {
.use { it.body.string() }

val data = json.decodeFromString<SourceResponseDto>(srcRes)

if (!data.encrypted) return json.decodeFromString<VideoDto>(srcRes)

val ciphered = data.sources.jsonPrimitive.content.toString()
val decrypted = json.decodeFromString<List<VideoLink>>(tryDecrypting(ciphered, keyType))

return VideoDto(decrypted, data.tracks)
}


@Serializable
data class VideoDto(
val sources: List<VideoLink>,
val tracks: List<TrackDto>? = null,
)

@Serializable
data class SourceResponseDto(
val sources: JsonElement,
val encrypted: Boolean = true,
val tracks: List<TrackDto>? = null,
)

@Serializable
data class VideoLink(val file: String = "")

@Serializable
data class TrackDto(val file: String, val kind: String, val label: String = "")
}
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,9 @@ class PlaylistUtils(private val client: OkHttpClient, private val headers: Heade

val playlistHttpUrl = playlistUrl.toHttpUrl()

val masterBase = "https://${playlistHttpUrl.host}${playlistHttpUrl.encodedPath}"
.substringBeforeLast("/") + "/"
val masterBase = playlistHttpUrl.newBuilder().apply {
removePathSegment(playlistHttpUrl.pathSize - 1)
}.build().toString() + "/"

// Get subtitles
val subtitleTracks = subtitleList + SUBTITLE_REGEX.findAll(masterPlaylist).mapNotNull {
Expand Down Expand Up @@ -126,6 +127,8 @@ class PlaylistUtils(private val client: OkHttpClient, private val headers: Heade
getAbsoluteUrl(url, playlistUrl, masterBase)
} ?: return@mapNotNull null



Video(
videoUrl, videoNameGen(resolution), videoUrl,
headers = videoHeadersGen(headers, referer, videoUrl),
Expand All @@ -139,7 +142,8 @@ class PlaylistUtils(private val client: OkHttpClient, private val headers: Heade
url.isEmpty() -> null
url.startsWith("http") -> url
url.startsWith("//") -> "https:$url"
url.startsWith("/") -> "https://" + playlistUrl.toHttpUrl().host + url
url.startsWith("/") -> playlistUrl.toHttpUrl().newBuilder().encodedPath("/").build().toString()
.substringBeforeLast("/") + url
else -> masterBase + url
}
}
Expand Down
4 changes: 4 additions & 0 deletions multisrc/overrides/zorotheme/kaido/additional.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
dependencies {
implementation(project(":lib-megacloud-extractor"))
implementation(project(':lib-streamtape-extractor'))
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
33 changes: 33 additions & 0 deletions multisrc/overrides/zorotheme/kaido/src/Kaido.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package eu.kanade.tachiyomi.animeextension.en.kaido

import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.lib.megacloudextractor.MegaCloudExtractor
import eu.kanade.tachiyomi.lib.streamtapeextractor.StreamTapeExtractor
import eu.kanade.tachiyomi.multisrc.zorotheme.ZoroTheme

class Kaido : ZoroTheme(
"en",
"Kaido",
"https://kaido.to",
) {
override val hosterNames: List<String> = listOf(
"Vidstreaming",
"Vidcloud",
"StreamTape",
)

private val streamtapeExtractor by lazy { StreamTapeExtractor(client) }
private val megaCloudExtractor by lazy { MegaCloudExtractor(client, headers) }

override fun extractVideo(server: VideoData): List<Video> {
return when (server.name) {
"StreamTape" -> {
streamtapeExtractor.videoFromUrl(server.link, "Streamtape - ${server.type}")
?.let(::listOf)
?: emptyList()
}
"Vidstreaming", "Vidcloud" -> megaCloudExtractor.getVideosFromUrl(server.link, server.type, server.name)
else -> emptyList()
}
}
}
4 changes: 4 additions & 0 deletions multisrc/overrides/zorotheme/zoro/additional.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
dependencies {
implementation(project(":lib-megacloud-extractor"))
implementation(project(':lib-streamtape-extractor'))
}
37 changes: 37 additions & 0 deletions multisrc/overrides/zorotheme/zoro/src/AniWatch.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package eu.kanade.tachiyomi.animeextension.en.zoro

import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.lib.megacloudextractor.MegaCloudExtractor
import eu.kanade.tachiyomi.lib.streamtapeextractor.StreamTapeExtractor
import eu.kanade.tachiyomi.multisrc.zorotheme.ZoroTheme

class AniWatch : ZoroTheme(
"en",
"AniWatch",
"https://aniwatch.to",
) {
override val id = 6706411382606718900L

override val ajaxRoute = "/v2"

override val hosterNames: List<String> = listOf(
"Vidstreaming",
"MegaCloud",
"StreamTape",
)

private val streamtapeExtractor by lazy { StreamTapeExtractor(client) }
private val megaCloudExtractor by lazy { MegaCloudExtractor(client, headers) }

override fun extractVideo(server: VideoData): List<Video> {
return when (server.name) {
"StreamTape" -> {
streamtapeExtractor.videoFromUrl(server.link, "Streamtape - ${server.type}")
?.let(::listOf)
?: emptyList()
}
"Vidstreaming", "MegaCloud" -> megaCloudExtractor.getVideosFromUrl(server.link, server.type, server.name)
else -> emptyList()
}
}
}
Loading