Initial commit

This commit is contained in:
almightyhak 2024-06-20 11:54:12 +07:00
commit 98ed7e8839
2263 changed files with 108711 additions and 0 deletions

View file

@ -0,0 +1,15 @@
ext {
extName = 'desu-online'
extClass = '.DesuOnline'
themePkg = 'animestream'
baseUrl = 'https://desu-online.pl'
overrideVersionCode = 5
}
apply from: "$rootDir/common.gradle"
dependencies {
implementation(project(':lib:okru-extractor'))
implementation(project(':lib:googledrive-extractor'))
implementation(project(':lib:sibnet-extractor'))
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 KiB

View file

@ -0,0 +1,86 @@
package eu.kanade.tachiyomi.animeextension.pl.desuonline
import androidx.preference.ListPreference
import androidx.preference.PreferenceScreen
import eu.kanade.tachiyomi.animeextension.pl.desuonline.extractors.CDAExtractor
import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.lib.googledriveextractor.GoogleDriveExtractor
import eu.kanade.tachiyomi.lib.okruextractor.OkruExtractor
import eu.kanade.tachiyomi.lib.sibnetextractor.SibnetExtractor
import eu.kanade.tachiyomi.multisrc.animestream.AnimeStream
import okhttp3.Response
import java.text.SimpleDateFormat
import java.util.Locale
class DesuOnline : AnimeStream(
"pl",
"desu-online",
"https://desu-online.pl",
) {
override val dateFormatter by lazy {
SimpleDateFormat("d MMMM, yyyy", Locale("pl", "PL"))
}
private val prefServerKey = "preferred_server"
private val prefServerDefault = "CDA"
// ============================ Video Links =============================
override fun videoListParse(response: Response): List<Video> =
super.videoListParse(response).ifEmpty { throw Exception("Failed to fetch videos") }
private val okruExtractor by lazy { OkruExtractor(client) }
private val cdaExtractor by lazy { CDAExtractor(client, headers, "$baseUrl/") }
private val sibnetExtractor by lazy { SibnetExtractor(client) }
private val gdriveExtractor by lazy { GoogleDriveExtractor(client, headers) }
override fun getVideoList(url: String, name: String): List<Video> {
return when {
url.contains("ok.ru") -> okruExtractor.videosFromUrl(url, name)
url.contains("cda.pl") -> cdaExtractor.videosFromUrl(url, name)
url.contains("sibnet") -> sibnetExtractor.videosFromUrl(url, prefix = "$name - ")
url.contains("drive.google.com") -> {
val id = Regex("[\\w-]{28,}").find(url)?.groupValues?.get(0) ?: return emptyList()
gdriveExtractor.videosFromUrl("https://drive.google.com/uc?id=$id", videoName = name)
}
else -> emptyList()
}
}
// ============================= Utilities ==============================
override fun List<Video>.sort(): List<Video> {
val quality = preferences.getString(videoSortPrefKey, videoSortPrefDefault)!!
val server = preferences.getString(prefServerKey, prefServerDefault)!!
return sortedWith(
compareBy(
{ it.quality.contains(server, true) },
{ it.quality.contains(quality) },
{ Regex("""(\d+)p""").find(it.quality)?.groupValues?.get(1)?.toIntOrNull() ?: 0 },
),
).reversed()
}
// ============================== Settings ==============================
override fun setupPreferenceScreen(screen: PreferenceScreen) {
super.setupPreferenceScreen(screen) // Quality preferences
ListPreference(screen.context).apply {
key = prefServerKey
title = "Preferred server"
entries = arrayOf("CDA", "Sibnet", "Google Drive", "ok.ru")
entryValues = arrayOf("CDA", "sibnet", "gd", "okru")
setDefaultValue(prefServerDefault)
summary = "%s"
setOnPreferenceChangeListener { _, newValue ->
val selected = newValue as String
val index = findIndexOfValue(selected)
val entry = entryValues[index] as String
preferences.edit().putString(key, entry).commit()
}
}.also(screen::addPreference)
}
}

View file

@ -0,0 +1,105 @@
package eu.kanade.tachiyomi.animeextension.pl.desuonline.extractors
import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.network.POST
import eu.kanade.tachiyomi.util.asJsoup
import eu.kanade.tachiyomi.util.parseAs
import kotlinx.serialization.Serializable
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.add
import kotlinx.serialization.json.buildJsonObject
import kotlinx.serialization.json.put
import kotlinx.serialization.json.putJsonArray
import okhttp3.Headers
import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.OkHttpClient
import okhttp3.RequestBody.Companion.toRequestBody
import uy.kohesive.injekt.injectLazy
class CDAExtractor(private val client: OkHttpClient, private val headers: Headers, private val referer: String) {
private val json: Json by injectLazy()
fun videosFromUrl(url: String, name: String): List<Video> {
val urlHost = url.toHttpUrl().host
val docHeaders = headers.newBuilder().apply {
add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8")
add("Host", urlHost)
add("Referer", referer)
}.build()
val doc = client.newCall(
GET(url, headers = docHeaders),
).execute().asJsoup()
val playerData = doc.selectFirst("div[id~=mediaplayer][player_data]")
?.attr("player_data")
?.let { json.decodeFromString<PlayerData>(it) }
?: return emptyList()
val timestamp = playerData.api.ts.substringBefore("_")
val videoData = playerData.video
var idCounter = 1
return videoData.qualities.map { (quality, qualityId) ->
val postBody = json.encodeToString(
buildJsonObject {
put("id", idCounter)
put("jsonrpc", "2.0")
put("method", "videoGetLink")
putJsonArray("params") {
add(url.toHttpUrl().pathSegments.last())
add(qualityId)
add(timestamp.toInt())
add(videoData.hash2)
}
},
).toRequestBody("application/json; charset=utf-8".toMediaType())
val postHeaders = headers.newBuilder().apply {
add("Accept", "application/json, text/javascript, */*; q=0.01")
add("Host", "www.cda.pl")
add("Origin", "https://$urlHost")
add("Referer", url)
}.build()
val videoUrl = client.newCall(
POST("https://www.cda.pl/", headers = postHeaders, body = postBody),
).execute().parseAs<PostResponse>().result.resp
idCounter++
Video(videoUrl, "$name - $quality", videoUrl)
}
}
@Serializable
data class PlayerData(
val api: PlayerApi,
val video: PlayerVideoData,
) {
@Serializable
data class PlayerApi(
val ts: String,
)
@Serializable
data class PlayerVideoData(
val hash2: String,
val qualities: Map<String, String>,
)
}
@Serializable
data class PostResponse(
val result: PostResult,
) {
@Serializable
data class PostResult(
val resp: String,
)
}
}