[skip ci] refactor: Make extensions use the dailymotion-extractor lib (#2160)

This commit is contained in:
Claudemirovsky 2023-09-09 08:22:33 -03:00 committed by GitHub
parent 602e91e363
commit 4b0cf15499
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 30 additions and 729 deletions

View File

@ -34,7 +34,7 @@ class DailymotionExtractor(private val client: OkHttpClient, private val headers
private val playlistUtils by lazy { PlaylistUtils(client, headers) }
fun videosFromUrl(url: String, prefix: String, baseUrl: String = "", password: String? = null): List<Video> {
fun videosFromUrl(url: String, prefix: String = "Dailymotion - ", baseUrl: String = "", password: String? = null): List<Video> {
val htmlString = client.newCall(GET(url)).execute().use { it.body.string() }
val internalData = htmlString.substringAfter("\"dmInternalData\":").substringBefore("</script>")

View File

@ -1,4 +1,5 @@
dependencies {
implementation(project(':lib-dailymotion-extractor'))
implementation(project(':lib-okru-extractor'))
implementation(project(':lib-gdriveplayer-extractor'))
implementation "dev.datlag.jsunpacker:jsunpacker:1.0.1"

View File

@ -2,11 +2,11 @@ package eu.kanade.tachiyomi.animeextension.all.animexin
import androidx.preference.ListPreference
import androidx.preference.PreferenceScreen
import eu.kanade.tachiyomi.animeextension.all.animexin.extractors.DailymotionExtractor
import eu.kanade.tachiyomi.animeextension.all.animexin.extractors.DoodExtractor
import eu.kanade.tachiyomi.animeextension.all.animexin.extractors.VidstreamingExtractor
import eu.kanade.tachiyomi.animeextension.all.animexin.extractors.YouTubeExtractor
import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.lib.dailymotionextractor.DailymotionExtractor
import eu.kanade.tachiyomi.lib.gdriveplayerextractor.GdrivePlayerExtractor
import eu.kanade.tachiyomi.lib.okruextractor.OkruExtractor
import eu.kanade.tachiyomi.multisrc.animestream.AnimeStream
@ -27,7 +27,7 @@ class AnimeXin : AnimeStream(
}
url.contains("dailymotion") -> {
DailymotionExtractor(client).videosFromUrl(url, prefix = prefix)
DailymotionExtractor(client, headers).videosFromUrl(url, prefix)
}
url.contains("https://dood") -> {
DoodExtractor(client).videosFromUrl(url, quality = name)

View File

@ -1,91 +0,0 @@
package eu.kanade.tachiyomi.animeextension.all.animexin.extractors
import eu.kanade.tachiyomi.animesource.model.Track
import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.network.GET
import kotlinx.serialization.Serializable
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json
import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.OkHttpClient
import uy.kohesive.injekt.injectLazy
@Serializable
data class DailyQuality(
val qualities: Auto,
val subtitles: Subtitle? = null,
) {
@Serializable
data class Auto(
val auto: List<Item>,
) {
@Serializable
data class Item(
val type: String,
val url: String,
)
}
@Serializable
data class Subtitle(
val data: Map<String, SubtitleObject>,
) {
@Serializable
data class SubtitleObject(
val label: String,
val urls: List<String>,
)
}
}
class DailymotionExtractor(private val client: OkHttpClient) {
private val json: Json by injectLazy()
fun videosFromUrl(url: String, prefix: String): List<Video> {
val videoList = mutableListOf<Video>()
val htmlString = client.newCall(GET(url)).execute().body.string()
val internalData = htmlString.substringAfter("\"dmInternalData\":").substringBefore("</script>")
val ts = internalData.substringAfter("\"ts\":").substringBefore(",")
val v1st = internalData.substringAfter("\"v1st\":\"").substringBefore("\",")
val jsonUrl = "https://www.dailymotion.com/player/metadata/video/${url.toHttpUrl().encodedPath}?locale=en-US&dmV1st=$v1st&dmTs=$ts&is_native_app=0"
val parsed = json.decodeFromString<DailyQuality>(
client.newCall(GET(jsonUrl))
.execute().body.string(),
)
val subtitleList = mutableListOf<Track>()
if (parsed.subtitles != null) {
try {
subtitleList.addAll(
parsed.subtitles.data.map { k ->
Track(
k.value.urls.first(),
k.value.label,
)
},
)
} catch (a: Exception) { }
}
val masterUrl = parsed.qualities.auto.first().url
val masterPlaylist = client.newCall(GET(masterUrl)).execute().body.string()
val separator = "#EXT-X-STREAM-INF"
masterPlaylist.substringAfter(separator).split(separator).map {
val quality = it.substringAfter("RESOLUTION=").substringAfter("x").substringBefore(",NAME") + "p"
var videoUrl = it.substringAfter("\n").substringBefore("\n")
try {
videoList.add(Video(videoUrl, prefix + quality, videoUrl, subtitleTracks = subtitleList))
} catch (a: Exception) {
videoList.add(Video(videoUrl, prefix + quality, videoUrl))
}
}
return videoList
}
}

View File

@ -1,3 +1,4 @@
dependencies {
implementation(project(':lib-dailymotion-extractor'))
implementation(project(':lib-playlist-utils'))
}

View File

@ -1,8 +1,8 @@
package eu.kanade.tachiyomi.animeextension.en.donghuastream
import eu.kanade.tachiyomi.animeextension.en.donghuastream.extractors.DailymotionExtractor
import eu.kanade.tachiyomi.animeextension.en.donghuastream.extractors.StreamPlayExtractor
import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.lib.dailymotionextractor.DailymotionExtractor
import eu.kanade.tachiyomi.multisrc.animestream.AnimeStream
class DonghuaStream : AnimeStream(

View File

@ -1,77 +0,0 @@
package eu.kanade.tachiyomi.animeextension.en.donghuastream.extractors
import eu.kanade.tachiyomi.animesource.model.Track
import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.lib.playlistutils.PlaylistUtils
import eu.kanade.tachiyomi.network.GET
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json
import okhttp3.Headers
import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.OkHttpClient
import okhttp3.Response
import uy.kohesive.injekt.injectLazy
class DailymotionExtractor(private val client: OkHttpClient, private val headers: Headers) {
private val json: Json by injectLazy()
private val playlistUtils by lazy { PlaylistUtils(client, headers) }
fun videosFromUrl(url: String, prefix: String): List<Video> {
val htmlString = client.newCall(GET(url)).execute().use { it.body.string() }
val internalData = htmlString.substringAfter("\"dmInternalData\":").substringBefore("</script>")
val ts = internalData.substringAfter("\"ts\":").substringBefore(",")
val v1st = internalData.substringAfter("\"v1st\":\"").substringBefore("\",")
val videoQuery = url.toHttpUrl().queryParameter("video") ?: url.toHttpUrl().encodedPath
val jsonUrl = "https://www.dailymotion.com/player/metadata/video/$videoQuery?locale=en-US&dmV1st=$v1st&dmTs=$ts&is_native_app=0"
val parsed = client.newCall(GET(jsonUrl)).execute().parseAs<DailyQuality>()
val subtitleList = parsed.subtitles?.data?.map { k ->
Track(
k.value.urls.first(),
k.value.label,
)
} ?: emptyList()
val masterUrl = parsed.qualities.auto.first().url
return playlistUtils.extractFromHls(masterUrl, subtitleList = subtitleList, videoNameGen = { q -> "$prefix$q" })
}
@Serializable
data class DailyQuality(
val qualities: Auto,
val subtitles: Subtitle? = null,
) {
@Serializable
data class Auto(
val auto: List<Item>,
) {
@Serializable
data class Item(
val type: String,
val url: String,
)
}
@Serializable
data class Subtitle(
val data: Map<String, SubtitleObject>,
) {
@Serializable
data class SubtitleObject(
val label: String,
val urls: List<String>,
)
}
}
private inline fun <reified T> Response.parseAs(transform: (String) -> String = { it }): T {
val responseBody = use { transform(it.body.string()) }
return json.decodeFromString(responseBody)
}
}

View File

@ -1,3 +1,4 @@
dependencies {
implementation(project(":lib-dailymotion-extractor"))
implementation(project(":lib-okru-extractor"))
}

View File

@ -3,8 +3,8 @@ package eu.kanade.tachiyomi.animeextension.all.lmanime
import androidx.preference.ListPreference
import androidx.preference.MultiSelectListPreference
import androidx.preference.PreferenceScreen
import eu.kanade.tachiyomi.animeextension.all.lmanime.extractors.DailymotionExtractor
import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.lib.dailymotionextractor.DailymotionExtractor
import eu.kanade.tachiyomi.lib.okruextractor.OkruExtractor
import eu.kanade.tachiyomi.multisrc.animestream.AnimeStream
import eu.kanade.tachiyomi.util.asJsoup
@ -39,7 +39,7 @@ class LMAnime : AnimeStream(
"ok.ru" in url ->
OkruExtractor(client).videosFromUrl(url, prefix)
"dailymotion.com" in url ->
DailymotionExtractor(client).videosFromUrl(url, "Dailymotion ($name)")
DailymotionExtractor(client, headers).videosFromUrl(url, "Dailymotion ($name)")
else -> emptyList()
}
}

View File

@ -1,50 +0,0 @@
package eu.kanade.tachiyomi.animeextension.all.lmanime.extractors
import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.network.GET
import kotlinx.serialization.Serializable
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json
import okhttp3.OkHttpClient
import uy.kohesive.injekt.injectLazy
@Serializable
data class DailyQuality(
val qualities: Auto,
) {
@Serializable
data class Auto(
val auto: List<Video>,
) {
@Serializable
data class Video(
val type: String,
val url: String,
)
}
}
class DailymotionExtractor(private val client: OkHttpClient) {
private val json: Json by injectLazy()
fun videosFromUrl(url: String, prefix: String): List<Video> {
val id = url.substringBefore("?").substringAfterLast("/")
val jsonUrl = "https://www.dailymotion.com/player/metadata/video/$id"
val jsonRequest = client.newCall(GET(jsonUrl)).execute().body.string()
val parsed = json.decodeFromString<DailyQuality>(jsonRequest)
val masterUrl = parsed.qualities.auto.first().url
val masterPlaylist = client.newCall(GET(masterUrl)).execute().body.string()
val separator = "#EXT-X-STREAM-INF"
return masterPlaylist.substringAfter(separator).split(separator).map {
val resolution = it.substringAfter("RESOLUTION=")
.substringAfter("x")
.substringBefore(",NAME") + "p"
val quality = "$prefix $resolution"
val videoUrl = it.substringAfter("\n").substringBefore("\n")
Video(videoUrl, quality, videoUrl)
}
}
}

View File

@ -1,4 +1,4 @@
dependencies {
implementation(project(':lib-dailymotion-extractor'))
implementation(project(':lib-okru-extractor'))
implementation(project(':lib-playlist-utils'))
}

View File

@ -1,8 +1,8 @@
package eu.kanade.tachiyomi.animeextension.en.luciferdonghua
import android.util.Base64
import eu.kanade.tachiyomi.animeextension.en.luciferdonghua.extractors.DailymotionExtractor
import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.lib.dailymotionextractor.DailymotionExtractor
import eu.kanade.tachiyomi.lib.okruextractor.OkruExtractor
import eu.kanade.tachiyomi.multisrc.animestream.AnimeStream
import org.jsoup.Jsoup
@ -35,7 +35,7 @@ class LuciferDonghua : AnimeStream(
OkruExtractor(client).videosFromUrl(url, prefix = prefix)
}
url.contains("dailymotion") -> {
DailymotionExtractor(client, headers).videosFromUrl(url, prefix = prefix)
DailymotionExtractor(client, headers).videosFromUrl(url, prefix)
}
else -> emptyList()
}

View File

@ -1,84 +0,0 @@
package eu.kanade.tachiyomi.animeextension.en.luciferdonghua.extractors
import eu.kanade.tachiyomi.animesource.model.Track
import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.lib.playlistutils.PlaylistUtils
import eu.kanade.tachiyomi.network.GET
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonElement
import okhttp3.Headers
import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.OkHttpClient
import okhttp3.Response
import uy.kohesive.injekt.injectLazy
class DailymotionExtractor(private val client: OkHttpClient, private val headers: Headers) {
private val json: Json by injectLazy()
private val playlistUtils by lazy { PlaylistUtils(client, headers) }
fun videosFromUrl(url: String, prefix: String): List<Video> {
val htmlString = client.newCall(GET(url)).execute().use { it.body.string() }
val internalData = htmlString.substringAfter("\"dmInternalData\":").substringBefore("</script>")
val ts = internalData.substringAfter("\"ts\":").substringBefore(",")
val v1st = internalData.substringAfter("\"v1st\":\"").substringBefore("\",")
val videoQuery = url.toHttpUrl().queryParameter("video") ?: url.toHttpUrl().pathSegments.last()
val jsonUrl = "https://www.dailymotion.com/player/metadata/video/$videoQuery?locale=en-US&dmV1st=$v1st&dmTs=$ts&is_native_app=0"
val parsed = client.newCall(GET(jsonUrl)).execute().parseAs<DailyQuality>()
// Blame dailymotion for this monstrosity
val subtitlesString = parsed.subtitles.data.toString()
val subtitleList = if (subtitlesString == "[]") {
emptyList()
} else {
json.decodeFromString<Map<String, DailyQuality.SubtitleObject>>(subtitlesString).map { k ->
Track(
k.value.urls.first(),
k.value.label,
)
}
}
val masterUrl = parsed.qualities.auto.first().url
return playlistUtils.extractFromHls(masterUrl, subtitleList = subtitleList, videoNameGen = { q -> "$prefix$q" })
}
@Serializable
data class DailyQuality(
val qualities: Auto,
val subtitles: Subtitle,
) {
@Serializable
data class Auto(
val auto: List<Item>,
) {
@Serializable
data class Item(
val type: String,
val url: String,
)
}
@Serializable
data class Subtitle(
val data: JsonElement,
)
@Serializable
data class SubtitleObject(
val label: String,
val urls: List<String>,
)
}
private inline fun <reified T> Response.parseAs(transform: (String) -> String = { it }): T {
val responseBody = use { transform(it.body.string()) }
return json.decodeFromString(responseBody)
}
}

View File

@ -0,0 +1,3 @@
dependencies {
implementation(project(':lib-dailymotion-extractor'))
}

View File

@ -2,12 +2,12 @@ package eu.kanade.tachiyomi.animeextension.pt.donghuax
import androidx.preference.ListPreference
import androidx.preference.PreferenceScreen
import eu.kanade.tachiyomi.animeextension.pt.donghuax.extractors.DailymotionExtractor
import eu.kanade.tachiyomi.animesource.model.AnimeFilter
import eu.kanade.tachiyomi.animesource.model.AnimeFilterList
import eu.kanade.tachiyomi.animesource.model.AnimesPage
import eu.kanade.tachiyomi.animesource.model.SEpisode
import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.lib.dailymotionextractor.DailymotionExtractor
import eu.kanade.tachiyomi.multisrc.dooplay.DooPlay
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.network.POST
@ -240,7 +240,7 @@ class DonghuaX : DooPlay(
GET(url),
).execute().asJsoup().selectFirst("vm-dailymotion[video-id]")?.attr("video-id")
id?.let {
DailymotionExtractor(client).videosFromUrl("https://www.dailymotion.com/embed/video/$it", "Dailymotion - ")
DailymotionExtractor(client, headers).videosFromUrl("https://www.dailymotion.com/embed/video/$it")
} ?: emptyList()
}
url.contains("csst.online") -> {

View File

@ -1,56 +0,0 @@
package eu.kanade.tachiyomi.animeextension.pt.donghuax.extractors
import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.network.GET
import kotlinx.serialization.Serializable
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json
import okhttp3.Headers
import okhttp3.OkHttpClient
import uy.kohesive.injekt.injectLazy
@Serializable
data class DailyQuality(
val qualities: Auto,
) {
@Serializable
data class Auto(
val auto: List<Video>,
) {
@Serializable
data class Video(
val type: String,
val url: String,
)
}
}
class DailymotionExtractor(private val client: OkHttpClient) {
private val json: Json by injectLazy()
fun videosFromUrl(url: String, prefix: String): List<Video> {
val id = url.substringBefore("?").substringAfterLast("/")
val jsonUrl = "https://www.dailymotion.com/player/metadata/video/$id"
val jsonRequest = client.newCall(GET(jsonUrl)).execute().body.string()
val parsed = json.decodeFromString<DailyQuality>(jsonRequest)
val masterUrl = parsed.qualities.auto.first().url
val masterPlaylist = client.newCall(GET(masterUrl)).execute().body.string()
val separator = "#EXT-X-STREAM-INF"
return masterPlaylist.substringAfter(separator).split(separator).map {
val resolution = it.substringAfter("RESOLUTION=")
.substringAfter("x")
.substringBefore(",NAME") + "p"
val quality = "$prefix $resolution"
val videoUrl = it.substringAfter("\n").substringBefore("\n")
val videoHeaders = Headers.headersOf(
"Referer",
"https://www.dailymotion.com/",
)
Video(videoUrl, quality, videoUrl, headers = videoHeaders)
}
}
}

View File

@ -12,6 +12,7 @@ ext {
}
dependencies {
implementation(project(':lib-dailymotion-extractor'))
implementation(project(':lib-dood-extractor'))
implementation(project(':lib-okru-extractor'))
implementation(project(':lib-mp4upload-extractor'))

View File

@ -3,7 +3,6 @@ package eu.kanade.tachiyomi.animeextension.ar.witanime
import android.app.Application
import androidx.preference.ListPreference
import androidx.preference.PreferenceScreen
import eu.kanade.tachiyomi.animeextension.ar.witanime.extractors.DailymotionExtractor
import eu.kanade.tachiyomi.animeextension.ar.witanime.extractors.SharedExtractor
import eu.kanade.tachiyomi.animeextension.ar.witanime.extractors.SoraPlayExtractor
import eu.kanade.tachiyomi.animesource.ConfigurableAnimeSource
@ -12,6 +11,7 @@ import eu.kanade.tachiyomi.animesource.model.SAnime
import eu.kanade.tachiyomi.animesource.model.SEpisode
import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.animesource.online.ParsedAnimeHttpSource
import eu.kanade.tachiyomi.lib.dailymotionextractor.DailymotionExtractor
import eu.kanade.tachiyomi.lib.doodextractor.DoodExtractor
import eu.kanade.tachiyomi.lib.mp4uploadextractor.Mp4uploadExtractor
import eu.kanade.tachiyomi.lib.okruextractor.OkruExtractor
@ -135,7 +135,7 @@ class WitAnime : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
private val soraPlayExtractor by lazy { SoraPlayExtractor(client) }
private val doodExtractor by lazy { DoodExtractor(client) }
private val sharedExtractor by lazy { SharedExtractor(client) }
private val dailymotionExtractor by lazy { DailymotionExtractor(client) }
private val dailymotionExtractor by lazy { DailymotionExtractor(client, headers) }
private val okruExtractor by lazy { OkruExtractor(client) }
private val mp4uploadExtractor by lazy { Mp4uploadExtractor(client) }
private val vidBomExtractor by lazy { VidBomExtractor(client) }
@ -159,7 +159,7 @@ class WitAnime : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
}
url.contains("dailymotion") -> {
dailymotionExtractor.videosFromUrl(url, headers)
dailymotionExtractor.videosFromUrl(url)
}
url.contains("ok.ru") -> {
okruExtractor.videosFromUrl(url)

View File

@ -1,22 +0,0 @@
package eu.kanade.tachiyomi.animeextension.ar.witanime.extractors
import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.network.GET
import okhttp3.Headers
import okhttp3.OkHttpClient
class DailymotionExtractor(private val client: OkHttpClient) {
fun videosFromUrl(url: String, headers: Headers): List<Video> {
val id = url.split("/").last()
val request = GET("https://www.dailymotion.com/player/metadata/video/$id", headers)
val body = client.newCall(request).execute().body.string()
val streamURL = body.substringAfter("{\"type\":\"application\\/x-mpegURL\",\"url\":\"")
.substringBefore("\"")
.replace("\\", "")
val sources = client.newCall(GET(streamURL)).execute().body.string()
return Regex("#EXT(?:.*?)NAME=\"(.*?)\",PROGRESSIVE-URI=\"(.*?)\"").findAll(sources).map {
Video(it.groupValues[2], "Dailymotion: ${it.groupValues[1]}p", it.groupValues[2])
}.toList()
}
}

View File

@ -11,6 +11,7 @@ ext {
}
dependencies {
implementation(project(':lib-dailymotion-extractor'))
implementation(project(':lib-mp4upload-extractor'))
implementation(project(':lib-yourupload-extractor'))
implementation "dev.datlag.jsunpacker:jsunpacker:1.0.1"

View File

@ -4,7 +4,6 @@ import android.app.Application
import android.content.SharedPreferences
import androidx.preference.ListPreference
import androidx.preference.PreferenceScreen
import eu.kanade.tachiyomi.animeextension.en.kissanime.extractors.DailymotionExtractor
import eu.kanade.tachiyomi.animeextension.en.kissanime.extractors.VodstreamExtractor
import eu.kanade.tachiyomi.animesource.ConfigurableAnimeSource
import eu.kanade.tachiyomi.animesource.model.AnimeFilterList
@ -13,6 +12,7 @@ import eu.kanade.tachiyomi.animesource.model.SAnime
import eu.kanade.tachiyomi.animesource.model.SEpisode
import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.animesource.online.ParsedAnimeHttpSource
import eu.kanade.tachiyomi.lib.dailymotionextractor.DailymotionExtractor
import eu.kanade.tachiyomi.lib.mp4uploadextractor.Mp4uploadExtractor
import eu.kanade.tachiyomi.lib.youruploadextractor.YourUploadExtractor
import eu.kanade.tachiyomi.network.GET
@ -232,7 +232,7 @@ class KissAnime : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
VodstreamExtractor(client).getVideosFromUrl(url, referer = referer, prefix = "${server.name} - ")
}
url.contains("dailymotion") -> {
DailymotionExtractor(client).videosFromUrl(url, prefix = "${server.name} - ", password = server.password, baseUrl = baseUrl)
DailymotionExtractor(client, headers).videosFromUrl(url, "${server.name} - ", baseUrl, server.password)
}
else -> null
}

View File

@ -1,174 +0,0 @@
package eu.kanade.tachiyomi.animeextension.en.kissanime.extractors
import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.network.POST
import kotlinx.serialization.Serializable
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json
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 DailymotionExtractor(private val client: OkHttpClient) {
private val json: Json by injectLazy()
fun videosFromUrl(url: String, prefix: String, baseUrl: String, password: String?): List<Video> {
val videoList = mutableListOf<Video>()
val htmlString = client.newCall(GET(url)).execute().body.string()
val internalData = htmlString.substringAfter("\"dmInternalData\":").substringBefore("</script>")
val ts = internalData.substringAfter("\"ts\":").substringBefore(",")
val v1st = internalData.substringAfter("\"v1st\":\"").substringBefore("\",")
val jsonUrl = "https://www.dailymotion.com/player/metadata/video${url.toHttpUrl().encodedPath}?locale=en-US&dmV1st=$v1st&dmTs=$ts&is_native_app=0"
var parsed = json.decodeFromString<DailyQuality>(
client.newCall(GET(jsonUrl))
.execute().body.string(),
)
var playlistHeaders = Headers.headersOf()
val videoHeaders = Headers.headersOf(
"Accept",
"*/*",
"Origin",
"https://www.dailymotion.com",
"Referer",
"https://www.dailymotion.com/",
)
if (parsed.error != null) {
if (parsed.error!!.type == "password_protected") {
val postUrl = "https://graphql.api.dailymotion.com/oauth/token"
val clientId = htmlString.substringAfter("client_id\":\"").substringBefore("\"")
val clientSecret = htmlString.substringAfter("client_secret\":\"").substringBefore("\"")
val scope = htmlString.substringAfter("client_scope\":\"").substringBefore("\"")
val tokenHeaders = Headers.headersOf(
"Accept",
"application/json, text/plain, */*",
"Content-Type",
"application/x-www-form-urlencoded",
"Origin",
"https://www.dailymotion.com",
"Referer",
"https://www.dailymotion.com/",
)
val tokenBody = "client_id=$clientId&client_secret=$clientSecret&traffic_segment=$ts&visitor_id=$v1st&grant_type=client_credentials&scope=$scope".toRequestBody("application/x-www-form-urlencoded".toMediaType())
val tokenResponse = client.newCall(
POST(postUrl, body = tokenBody, headers = tokenHeaders),
).execute()
val tokenParsed = json.decodeFromString<TokenResponse>(tokenResponse.body.string())
val idUrl = "https://graphql.api.dailymotion.com/"
val idHeaders = Headers.headersOf(
"Accept", "application/json, text/plain, */*",
"Authorization", "${tokenParsed.token_type} ${tokenParsed.access_token}",
"Content-Type", "application/json",
"Origin", "https://www.dailymotion.com",
"Referer", "https://www.dailymotion.com/",
)
val idData = """
{
"query":"query playerPasswordQuery(${'$'}videoId:String!,${'$'}password:String!){video(xid:${'$'}videoId,password:${'$'}password){id xid}}",
"variables":{
"videoId":"${parsed.id!!}",
"password":"$password"
}
}
""".trimIndent().toRequestBody("application/json".toMediaType())
val idResponse = client.newCall(
POST(idUrl, body = idData, headers = idHeaders),
).execute()
val idParsed = json.decodeFromString<ProtectedResponse>(idResponse.body.string()).data.video
val dmvk = htmlString.substringAfter("\"dmvk\":\"").substringBefore("\"")
val getVideoIdUrl = "https://www.dailymotion.com/player/metadata/video/${idParsed.xid}?embedder=${"$baseUrl/"}&locale=en-US&dmV1st=$v1st&dmTs=$ts&is_native_app=0"
val getVideoIdHeaders = Headers.headersOf(
"Accept",
"*/*",
"Cookie",
"dmvk=$dmvk; ts=$ts; v1st=$v1st; usprivacy=1---; client_token=${tokenParsed.access_token}",
"Referer",
url,
)
playlistHeaders = Headers.headersOf(
"Accept",
"*/*",
"Cookie",
"dmvk=$dmvk; ts=$ts; v1st=$v1st; usprivacy=1---; client_token=${tokenParsed.access_token}",
"Referer",
url,
)
val getVideoIdResponse = client.newCall(GET(getVideoIdUrl, headers = getVideoIdHeaders)).execute()
val videoQualityBody = getVideoIdResponse.body.string()
parsed = json.decodeFromString<DailyQuality>(videoQualityBody)
}
}
val masterUrl = parsed.qualities!!.auto.first().url
val masterPlaylist = client.newCall(GET(masterUrl, headers = playlistHeaders)).execute().body.string()
val separator = "#EXT-X-STREAM-INF"
masterPlaylist.substringAfter(separator).split(separator).map {
val quality = it.substringAfter("RESOLUTION=").substringAfter("x").substringBefore(",NAME") + "p"
var videoUrl = it.substringAfter("\n").substringBefore("\n")
videoList.add(Video(videoUrl, prefix + quality, videoUrl, headers = videoHeaders))
}
return videoList
}
@Serializable
data class TokenResponse(
val access_token: String,
val token_type: String,
)
@Serializable
data class ProtectedResponse(
val data: DataObject,
) {
@Serializable
data class DataObject(
val video: VideoObject,
) {
@Serializable
data class VideoObject(
val id: String,
val xid: String,
)
}
}
@Serializable
data class DailyQuality(
val error: Error? = null,
val id: String? = null,
val qualities: Auto? = null,
) {
@Serializable
data class Error(
val type: String,
)
@Serializable
data class Auto(
val auto: List<Item>,
) {
@Serializable
data class Item(
val type: String,
val url: String,
)
}
}
}

View File

@ -11,6 +11,7 @@ ext {
}
dependencies {
implementation(project(':lib-dailymotion-extractor'))
implementation(project(':lib-gdriveplayer-extractor'))
implementation(project(':lib-okru-extractor'))
implementation "dev.datlag.jsunpacker:jsunpacker:1.0.1"

View File

@ -4,7 +4,6 @@ import android.app.Application
import android.content.SharedPreferences
import androidx.preference.ListPreference
import androidx.preference.PreferenceScreen
import eu.kanade.tachiyomi.animeextension.en.myanime.extractors.DailymotionExtractor
import eu.kanade.tachiyomi.animeextension.en.myanime.extractors.YouTubeExtractor
import eu.kanade.tachiyomi.animesource.ConfigurableAnimeSource
import eu.kanade.tachiyomi.animesource.model.AnimeFilter
@ -13,6 +12,7 @@ import eu.kanade.tachiyomi.animesource.model.SAnime
import eu.kanade.tachiyomi.animesource.model.SEpisode
import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.animesource.online.ParsedAnimeHttpSource
import eu.kanade.tachiyomi.lib.dailymotionextractor.DailymotionExtractor
import eu.kanade.tachiyomi.lib.gdriveplayerextractor.GdrivePlayerExtractor
import eu.kanade.tachiyomi.lib.okruextractor.OkruExtractor
import eu.kanade.tachiyomi.network.GET
@ -207,7 +207,7 @@ class Myanime : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
when {
url.contains("dailymotion") -> {
DailymotionExtractor(client).videosFromUrl(url)
DailymotionExtractor(client, headers).videosFromUrl(url)
}
url.contains("ok.ru") -> {
OkruExtractor(client).videosFromUrl(url)

View File

@ -1,85 +0,0 @@
package eu.kanade.tachiyomi.animeextension.en.myanime.extractors
import eu.kanade.tachiyomi.animesource.model.Track
import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.network.GET
import kotlinx.serialization.Serializable
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonElement
import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.OkHttpClient
import uy.kohesive.injekt.injectLazy
@Serializable
data class DailyQuality(
val qualities: Auto,
val subtitles: Subtitle? = null,
) {
@Serializable
data class Auto(
val auto: List<Item>,
) {
@Serializable
data class Item(
val type: String,
val url: String,
)
}
// @Serializable
// data class SubtitleObject(
// val label: String,
// val urls: List<String>,
// )
@Serializable
data class Subtitle(
// data can be either an empty list, or `Map<String, SubtitleObject>`
val data: JsonElement? = null,
)
}
class DailymotionExtractor(private val client: OkHttpClient) {
private val json: Json by injectLazy()
fun videosFromUrl(url: String, prefix: String = "Dailymotion - "): List<Video> {
val videoList = mutableListOf<Video>()
val htmlString = client.newCall(GET(url)).execute().body.string()
val internalData = htmlString.substringAfter("\"dmInternalData\":").substringBefore("</script>")
val ts = internalData.substringAfter("\"ts\":").substringBefore(",")
val v1st = internalData.substringAfter("\"v1st\":\"").substringBefore("\",")
val jsonUrl = "https://www.dailymotion.com/player/metadata/video${url.toHttpUrl().encodedPath}?locale=en-US&dmV1st=$v1st&dmTs=$ts&is_native_app=0"
val parsed = json.decodeFromString<DailyQuality>(
client.newCall(GET(jsonUrl))
.execute().body.string(),
)
val subtitleList = mutableListOf<Track>()
// if (parsed.subtitles != null) {
// if (parsed.subtitles.data.toString() != "[]") {
//
// }
// }
val masterUrl = parsed.qualities.auto.first().url
val masterPlaylist = client.newCall(GET(masterUrl)).execute().body.string()
val separator = "#EXT-X-STREAM-INF"
masterPlaylist.substringAfter(separator).split(separator).map {
val quality = it.substringAfter("RESOLUTION=").substringAfter("x").substringBefore(",NAME") + "p"
var videoUrl = it.substringAfter("\n").substringBefore("\n")
try {
videoList.add(Video(videoUrl, prefix + quality, videoUrl, subtitleTracks = subtitleList))
} catch (a: Exception) {
videoList.add(Video(videoUrl, prefix + quality, videoUrl))
}
}
return videoList
}
}

View File

@ -11,6 +11,7 @@ ext {
}
dependencies {
implementation(project(':lib-dailymotion-extractor'))
implementation(project(':lib-mp4upload-extractor'))
implementation(project(':lib-sibnet-extractor'))
implementation "dev.datlag.jsunpacker:jsunpacker:1.0.1"

View File

@ -6,7 +6,6 @@ import androidx.preference.ListPreference
import androidx.preference.PreferenceScreen
import androidx.preference.SwitchPreferenceCompat
import eu.kanade.tachiyomi.animeextension.pl.wbijam.extractors.CdaPlExtractor
import eu.kanade.tachiyomi.animeextension.pl.wbijam.extractors.DailymotionExtractor
import eu.kanade.tachiyomi.animeextension.pl.wbijam.extractors.VkExtractor
import eu.kanade.tachiyomi.animesource.ConfigurableAnimeSource
import eu.kanade.tachiyomi.animesource.model.AnimeFilterList
@ -15,6 +14,7 @@ import eu.kanade.tachiyomi.animesource.model.SAnime
import eu.kanade.tachiyomi.animesource.model.SEpisode
import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.animesource.online.ParsedAnimeHttpSource
import eu.kanade.tachiyomi.lib.dailymotionextractor.DailymotionExtractor
import eu.kanade.tachiyomi.lib.mp4uploadextractor.Mp4uploadExtractor
import eu.kanade.tachiyomi.lib.sibnetextractor.SibnetExtractor
import eu.kanade.tachiyomi.network.GET
@ -295,7 +295,7 @@ class Wbijam : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
VkExtractor(client).getVideosFromUrl(serverUrl, headers)
}
serverUrl.contains("dailymotion") -> {
DailymotionExtractor(client).videosFromUrl(serverUrl, headers)
DailymotionExtractor(client, headers).videosFromUrl(serverUrl)
}
else -> null
}

View File

@ -1,70 +0,0 @@
package eu.kanade.tachiyomi.animeextension.pl.wbijam.extractors
import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.network.GET
import kotlinx.serialization.Serializable
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json
import okhttp3.Headers
import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.OkHttpClient
import uy.kohesive.injekt.injectLazy
class DailymotionExtractor(private val client: OkHttpClient) {
private val json: Json by injectLazy()
fun videosFromUrl(url: String, headers: Headers): List<Video> {
val videoList = mutableListOf<Video>()
val htmlString = client.newCall(GET(url)).execute().body.string()
val internalData = htmlString.substringAfter("\"dmInternalData\":").substringBefore("</script>")
val ts = internalData.substringAfter("\"ts\":").substringBefore(",")
val v1st = internalData.substringAfter("\"v1st\":\"").substringBefore("\",")
val jsonUrl = "https://www.dailymotion.com/player/metadata/video/${url.toHttpUrl().encodedPath}?locale=en-US&dmV1st=$v1st&dmTs=$ts&is_native_app=0"
val parsed = json.decodeFromString<DailyQuality>(
client.newCall(GET(jsonUrl))
.execute().body.string(),
)
val masterUrl = parsed.qualities.auto.first().url
val masterPlaylist = client.newCall(GET(masterUrl)).execute().body.string()
val separator = "#EXT-X-STREAM-INF"
masterPlaylist.substringAfter(separator).split(separator).map {
val quality = it.substringAfter("RESOLUTION=").substringAfter("x").substringBefore(",NAME") + "p"
val videoUrl = it.substringAfter("\n").substringBefore("\n")
val videoHeaders = headers.newBuilder()
.add("Accept", "*/*")
.add("Host", videoUrl.toHttpUrl().host)
.add("Origin", "https://www.dailymotion.com")
.add("Referer", "https://www.dailymotion.com")
.build()
videoList.add(
Video(videoUrl, "Dailymotion - $quality", videoUrl, headers = videoHeaders),
)
}
return videoList
}
@Serializable
data class DailyQuality(
val qualities: Auto,
) {
@Serializable
data class Auto(
val auto: List<Item>,
) {
@Serializable
data class Item(
val type: String,
val url: String,
)
}
}
}