[skip ci] refactor: Make extensions use the dailymotion-extractor lib (#2160)
This commit is contained in:
parent
602e91e363
commit
4b0cf15499
@ -34,7 +34,7 @@ class DailymotionExtractor(private val client: OkHttpClient, private val headers
|
|||||||
|
|
||||||
private val playlistUtils by lazy { PlaylistUtils(client, 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 htmlString = client.newCall(GET(url)).execute().use { it.body.string() }
|
||||||
|
|
||||||
val internalData = htmlString.substringAfter("\"dmInternalData\":").substringBefore("</script>")
|
val internalData = htmlString.substringAfter("\"dmInternalData\":").substringBefore("</script>")
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
dependencies {
|
dependencies {
|
||||||
|
implementation(project(':lib-dailymotion-extractor'))
|
||||||
implementation(project(':lib-okru-extractor'))
|
implementation(project(':lib-okru-extractor'))
|
||||||
implementation(project(':lib-gdriveplayer-extractor'))
|
implementation(project(':lib-gdriveplayer-extractor'))
|
||||||
implementation "dev.datlag.jsunpacker:jsunpacker:1.0.1"
|
implementation "dev.datlag.jsunpacker:jsunpacker:1.0.1"
|
||||||
|
@ -2,11 +2,11 @@ package eu.kanade.tachiyomi.animeextension.all.animexin
|
|||||||
|
|
||||||
import androidx.preference.ListPreference
|
import androidx.preference.ListPreference
|
||||||
import androidx.preference.PreferenceScreen
|
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.DoodExtractor
|
||||||
import eu.kanade.tachiyomi.animeextension.all.animexin.extractors.VidstreamingExtractor
|
import eu.kanade.tachiyomi.animeextension.all.animexin.extractors.VidstreamingExtractor
|
||||||
import eu.kanade.tachiyomi.animeextension.all.animexin.extractors.YouTubeExtractor
|
import eu.kanade.tachiyomi.animeextension.all.animexin.extractors.YouTubeExtractor
|
||||||
import eu.kanade.tachiyomi.animesource.model.Video
|
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.gdriveplayerextractor.GdrivePlayerExtractor
|
||||||
import eu.kanade.tachiyomi.lib.okruextractor.OkruExtractor
|
import eu.kanade.tachiyomi.lib.okruextractor.OkruExtractor
|
||||||
import eu.kanade.tachiyomi.multisrc.animestream.AnimeStream
|
import eu.kanade.tachiyomi.multisrc.animestream.AnimeStream
|
||||||
@ -27,7 +27,7 @@ class AnimeXin : AnimeStream(
|
|||||||
}
|
}
|
||||||
|
|
||||||
url.contains("dailymotion") -> {
|
url.contains("dailymotion") -> {
|
||||||
DailymotionExtractor(client).videosFromUrl(url, prefix = prefix)
|
DailymotionExtractor(client, headers).videosFromUrl(url, prefix)
|
||||||
}
|
}
|
||||||
url.contains("https://dood") -> {
|
url.contains("https://dood") -> {
|
||||||
DoodExtractor(client).videosFromUrl(url, quality = name)
|
DoodExtractor(client).videosFromUrl(url, quality = name)
|
||||||
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,3 +1,4 @@
|
|||||||
dependencies {
|
dependencies {
|
||||||
|
implementation(project(':lib-dailymotion-extractor'))
|
||||||
implementation(project(':lib-playlist-utils'))
|
implementation(project(':lib-playlist-utils'))
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
package eu.kanade.tachiyomi.animeextension.en.donghuastream
|
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.animeextension.en.donghuastream.extractors.StreamPlayExtractor
|
||||||
import eu.kanade.tachiyomi.animesource.model.Video
|
import eu.kanade.tachiyomi.animesource.model.Video
|
||||||
|
import eu.kanade.tachiyomi.lib.dailymotionextractor.DailymotionExtractor
|
||||||
import eu.kanade.tachiyomi.multisrc.animestream.AnimeStream
|
import eu.kanade.tachiyomi.multisrc.animestream.AnimeStream
|
||||||
|
|
||||||
class DonghuaStream : AnimeStream(
|
class DonghuaStream : AnimeStream(
|
||||||
|
@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,3 +1,4 @@
|
|||||||
dependencies {
|
dependencies {
|
||||||
|
implementation(project(":lib-dailymotion-extractor"))
|
||||||
implementation(project(":lib-okru-extractor"))
|
implementation(project(":lib-okru-extractor"))
|
||||||
}
|
}
|
||||||
|
@ -3,8 +3,8 @@ package eu.kanade.tachiyomi.animeextension.all.lmanime
|
|||||||
import androidx.preference.ListPreference
|
import androidx.preference.ListPreference
|
||||||
import androidx.preference.MultiSelectListPreference
|
import androidx.preference.MultiSelectListPreference
|
||||||
import androidx.preference.PreferenceScreen
|
import androidx.preference.PreferenceScreen
|
||||||
import eu.kanade.tachiyomi.animeextension.all.lmanime.extractors.DailymotionExtractor
|
|
||||||
import eu.kanade.tachiyomi.animesource.model.Video
|
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.lib.okruextractor.OkruExtractor
|
||||||
import eu.kanade.tachiyomi.multisrc.animestream.AnimeStream
|
import eu.kanade.tachiyomi.multisrc.animestream.AnimeStream
|
||||||
import eu.kanade.tachiyomi.util.asJsoup
|
import eu.kanade.tachiyomi.util.asJsoup
|
||||||
@ -39,7 +39,7 @@ class LMAnime : AnimeStream(
|
|||||||
"ok.ru" in url ->
|
"ok.ru" in url ->
|
||||||
OkruExtractor(client).videosFromUrl(url, prefix)
|
OkruExtractor(client).videosFromUrl(url, prefix)
|
||||||
"dailymotion.com" in url ->
|
"dailymotion.com" in url ->
|
||||||
DailymotionExtractor(client).videosFromUrl(url, "Dailymotion ($name)")
|
DailymotionExtractor(client, headers).videosFromUrl(url, "Dailymotion ($name)")
|
||||||
else -> emptyList()
|
else -> emptyList()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,4 +1,4 @@
|
|||||||
dependencies {
|
dependencies {
|
||||||
|
implementation(project(':lib-dailymotion-extractor'))
|
||||||
implementation(project(':lib-okru-extractor'))
|
implementation(project(':lib-okru-extractor'))
|
||||||
implementation(project(':lib-playlist-utils'))
|
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
package eu.kanade.tachiyomi.animeextension.en.luciferdonghua
|
package eu.kanade.tachiyomi.animeextension.en.luciferdonghua
|
||||||
|
|
||||||
import android.util.Base64
|
import android.util.Base64
|
||||||
import eu.kanade.tachiyomi.animeextension.en.luciferdonghua.extractors.DailymotionExtractor
|
|
||||||
import eu.kanade.tachiyomi.animesource.model.Video
|
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.lib.okruextractor.OkruExtractor
|
||||||
import eu.kanade.tachiyomi.multisrc.animestream.AnimeStream
|
import eu.kanade.tachiyomi.multisrc.animestream.AnimeStream
|
||||||
import org.jsoup.Jsoup
|
import org.jsoup.Jsoup
|
||||||
@ -35,7 +35,7 @@ class LuciferDonghua : AnimeStream(
|
|||||||
OkruExtractor(client).videosFromUrl(url, prefix = prefix)
|
OkruExtractor(client).videosFromUrl(url, prefix = prefix)
|
||||||
}
|
}
|
||||||
url.contains("dailymotion") -> {
|
url.contains("dailymotion") -> {
|
||||||
DailymotionExtractor(client, headers).videosFromUrl(url, prefix = prefix)
|
DailymotionExtractor(client, headers).videosFromUrl(url, prefix)
|
||||||
}
|
}
|
||||||
else -> emptyList()
|
else -> emptyList()
|
||||||
}
|
}
|
||||||
|
@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
3
multisrc/overrides/dooplay/donghuax/additional.gradle
Normal file
3
multisrc/overrides/dooplay/donghuax/additional.gradle
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
dependencies {
|
||||||
|
implementation(project(':lib-dailymotion-extractor'))
|
||||||
|
}
|
@ -2,12 +2,12 @@ package eu.kanade.tachiyomi.animeextension.pt.donghuax
|
|||||||
|
|
||||||
import androidx.preference.ListPreference
|
import androidx.preference.ListPreference
|
||||||
import androidx.preference.PreferenceScreen
|
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.AnimeFilter
|
||||||
import eu.kanade.tachiyomi.animesource.model.AnimeFilterList
|
import eu.kanade.tachiyomi.animesource.model.AnimeFilterList
|
||||||
import eu.kanade.tachiyomi.animesource.model.AnimesPage
|
import eu.kanade.tachiyomi.animesource.model.AnimesPage
|
||||||
import eu.kanade.tachiyomi.animesource.model.SEpisode
|
import eu.kanade.tachiyomi.animesource.model.SEpisode
|
||||||
import eu.kanade.tachiyomi.animesource.model.Video
|
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.multisrc.dooplay.DooPlay
|
||||||
import eu.kanade.tachiyomi.network.GET
|
import eu.kanade.tachiyomi.network.GET
|
||||||
import eu.kanade.tachiyomi.network.POST
|
import eu.kanade.tachiyomi.network.POST
|
||||||
@ -240,7 +240,7 @@ class DonghuaX : DooPlay(
|
|||||||
GET(url),
|
GET(url),
|
||||||
).execute().asJsoup().selectFirst("vm-dailymotion[video-id]")?.attr("video-id")
|
).execute().asJsoup().selectFirst("vm-dailymotion[video-id]")?.attr("video-id")
|
||||||
id?.let {
|
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()
|
} ?: emptyList()
|
||||||
}
|
}
|
||||||
url.contains("csst.online") -> {
|
url.contains("csst.online") -> {
|
||||||
|
@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -12,6 +12,7 @@ ext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
implementation(project(':lib-dailymotion-extractor'))
|
||||||
implementation(project(':lib-dood-extractor'))
|
implementation(project(':lib-dood-extractor'))
|
||||||
implementation(project(':lib-okru-extractor'))
|
implementation(project(':lib-okru-extractor'))
|
||||||
implementation(project(':lib-mp4upload-extractor'))
|
implementation(project(':lib-mp4upload-extractor'))
|
||||||
|
@ -3,7 +3,6 @@ package eu.kanade.tachiyomi.animeextension.ar.witanime
|
|||||||
import android.app.Application
|
import android.app.Application
|
||||||
import androidx.preference.ListPreference
|
import androidx.preference.ListPreference
|
||||||
import androidx.preference.PreferenceScreen
|
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.SharedExtractor
|
||||||
import eu.kanade.tachiyomi.animeextension.ar.witanime.extractors.SoraPlayExtractor
|
import eu.kanade.tachiyomi.animeextension.ar.witanime.extractors.SoraPlayExtractor
|
||||||
import eu.kanade.tachiyomi.animesource.ConfigurableAnimeSource
|
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.SEpisode
|
||||||
import eu.kanade.tachiyomi.animesource.model.Video
|
import eu.kanade.tachiyomi.animesource.model.Video
|
||||||
import eu.kanade.tachiyomi.animesource.online.ParsedAnimeHttpSource
|
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.doodextractor.DoodExtractor
|
||||||
import eu.kanade.tachiyomi.lib.mp4uploadextractor.Mp4uploadExtractor
|
import eu.kanade.tachiyomi.lib.mp4uploadextractor.Mp4uploadExtractor
|
||||||
import eu.kanade.tachiyomi.lib.okruextractor.OkruExtractor
|
import eu.kanade.tachiyomi.lib.okruextractor.OkruExtractor
|
||||||
@ -135,7 +135,7 @@ class WitAnime : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
|||||||
private val soraPlayExtractor by lazy { SoraPlayExtractor(client) }
|
private val soraPlayExtractor by lazy { SoraPlayExtractor(client) }
|
||||||
private val doodExtractor by lazy { DoodExtractor(client) }
|
private val doodExtractor by lazy { DoodExtractor(client) }
|
||||||
private val sharedExtractor by lazy { SharedExtractor(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 okruExtractor by lazy { OkruExtractor(client) }
|
||||||
private val mp4uploadExtractor by lazy { Mp4uploadExtractor(client) }
|
private val mp4uploadExtractor by lazy { Mp4uploadExtractor(client) }
|
||||||
private val vidBomExtractor by lazy { VidBomExtractor(client) }
|
private val vidBomExtractor by lazy { VidBomExtractor(client) }
|
||||||
@ -159,7 +159,7 @@ class WitAnime : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
url.contains("dailymotion") -> {
|
url.contains("dailymotion") -> {
|
||||||
dailymotionExtractor.videosFromUrl(url, headers)
|
dailymotionExtractor.videosFromUrl(url)
|
||||||
}
|
}
|
||||||
url.contains("ok.ru") -> {
|
url.contains("ok.ru") -> {
|
||||||
okruExtractor.videosFromUrl(url)
|
okruExtractor.videosFromUrl(url)
|
||||||
|
@ -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()
|
|
||||||
}
|
|
||||||
}
|
|
@ -11,6 +11,7 @@ ext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
implementation(project(':lib-dailymotion-extractor'))
|
||||||
implementation(project(':lib-mp4upload-extractor'))
|
implementation(project(':lib-mp4upload-extractor'))
|
||||||
implementation(project(':lib-yourupload-extractor'))
|
implementation(project(':lib-yourupload-extractor'))
|
||||||
implementation "dev.datlag.jsunpacker:jsunpacker:1.0.1"
|
implementation "dev.datlag.jsunpacker:jsunpacker:1.0.1"
|
||||||
|
@ -4,7 +4,6 @@ import android.app.Application
|
|||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
import androidx.preference.ListPreference
|
import androidx.preference.ListPreference
|
||||||
import androidx.preference.PreferenceScreen
|
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.animeextension.en.kissanime.extractors.VodstreamExtractor
|
||||||
import eu.kanade.tachiyomi.animesource.ConfigurableAnimeSource
|
import eu.kanade.tachiyomi.animesource.ConfigurableAnimeSource
|
||||||
import eu.kanade.tachiyomi.animesource.model.AnimeFilterList
|
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.SEpisode
|
||||||
import eu.kanade.tachiyomi.animesource.model.Video
|
import eu.kanade.tachiyomi.animesource.model.Video
|
||||||
import eu.kanade.tachiyomi.animesource.online.ParsedAnimeHttpSource
|
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.mp4uploadextractor.Mp4uploadExtractor
|
||||||
import eu.kanade.tachiyomi.lib.youruploadextractor.YourUploadExtractor
|
import eu.kanade.tachiyomi.lib.youruploadextractor.YourUploadExtractor
|
||||||
import eu.kanade.tachiyomi.network.GET
|
import eu.kanade.tachiyomi.network.GET
|
||||||
@ -232,7 +232,7 @@ class KissAnime : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
|||||||
VodstreamExtractor(client).getVideosFromUrl(url, referer = referer, prefix = "${server.name} - ")
|
VodstreamExtractor(client).getVideosFromUrl(url, referer = referer, prefix = "${server.name} - ")
|
||||||
}
|
}
|
||||||
url.contains("dailymotion") -> {
|
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
|
else -> null
|
||||||
}
|
}
|
||||||
|
@ -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,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -11,6 +11,7 @@ ext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
implementation(project(':lib-dailymotion-extractor'))
|
||||||
implementation(project(':lib-gdriveplayer-extractor'))
|
implementation(project(':lib-gdriveplayer-extractor'))
|
||||||
implementation(project(':lib-okru-extractor'))
|
implementation(project(':lib-okru-extractor'))
|
||||||
implementation "dev.datlag.jsunpacker:jsunpacker:1.0.1"
|
implementation "dev.datlag.jsunpacker:jsunpacker:1.0.1"
|
||||||
|
@ -4,7 +4,6 @@ import android.app.Application
|
|||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
import androidx.preference.ListPreference
|
import androidx.preference.ListPreference
|
||||||
import androidx.preference.PreferenceScreen
|
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.animeextension.en.myanime.extractors.YouTubeExtractor
|
||||||
import eu.kanade.tachiyomi.animesource.ConfigurableAnimeSource
|
import eu.kanade.tachiyomi.animesource.ConfigurableAnimeSource
|
||||||
import eu.kanade.tachiyomi.animesource.model.AnimeFilter
|
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.SEpisode
|
||||||
import eu.kanade.tachiyomi.animesource.model.Video
|
import eu.kanade.tachiyomi.animesource.model.Video
|
||||||
import eu.kanade.tachiyomi.animesource.online.ParsedAnimeHttpSource
|
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.gdriveplayerextractor.GdrivePlayerExtractor
|
||||||
import eu.kanade.tachiyomi.lib.okruextractor.OkruExtractor
|
import eu.kanade.tachiyomi.lib.okruextractor.OkruExtractor
|
||||||
import eu.kanade.tachiyomi.network.GET
|
import eu.kanade.tachiyomi.network.GET
|
||||||
@ -207,7 +207,7 @@ class Myanime : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
|||||||
|
|
||||||
when {
|
when {
|
||||||
url.contains("dailymotion") -> {
|
url.contains("dailymotion") -> {
|
||||||
DailymotionExtractor(client).videosFromUrl(url)
|
DailymotionExtractor(client, headers).videosFromUrl(url)
|
||||||
}
|
}
|
||||||
url.contains("ok.ru") -> {
|
url.contains("ok.ru") -> {
|
||||||
OkruExtractor(client).videosFromUrl(url)
|
OkruExtractor(client).videosFromUrl(url)
|
||||||
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
@ -11,6 +11,7 @@ ext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
implementation(project(':lib-dailymotion-extractor'))
|
||||||
implementation(project(':lib-mp4upload-extractor'))
|
implementation(project(':lib-mp4upload-extractor'))
|
||||||
implementation(project(':lib-sibnet-extractor'))
|
implementation(project(':lib-sibnet-extractor'))
|
||||||
implementation "dev.datlag.jsunpacker:jsunpacker:1.0.1"
|
implementation "dev.datlag.jsunpacker:jsunpacker:1.0.1"
|
||||||
|
@ -6,7 +6,6 @@ import androidx.preference.ListPreference
|
|||||||
import androidx.preference.PreferenceScreen
|
import androidx.preference.PreferenceScreen
|
||||||
import androidx.preference.SwitchPreferenceCompat
|
import androidx.preference.SwitchPreferenceCompat
|
||||||
import eu.kanade.tachiyomi.animeextension.pl.wbijam.extractors.CdaPlExtractor
|
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.animeextension.pl.wbijam.extractors.VkExtractor
|
||||||
import eu.kanade.tachiyomi.animesource.ConfigurableAnimeSource
|
import eu.kanade.tachiyomi.animesource.ConfigurableAnimeSource
|
||||||
import eu.kanade.tachiyomi.animesource.model.AnimeFilterList
|
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.SEpisode
|
||||||
import eu.kanade.tachiyomi.animesource.model.Video
|
import eu.kanade.tachiyomi.animesource.model.Video
|
||||||
import eu.kanade.tachiyomi.animesource.online.ParsedAnimeHttpSource
|
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.mp4uploadextractor.Mp4uploadExtractor
|
||||||
import eu.kanade.tachiyomi.lib.sibnetextractor.SibnetExtractor
|
import eu.kanade.tachiyomi.lib.sibnetextractor.SibnetExtractor
|
||||||
import eu.kanade.tachiyomi.network.GET
|
import eu.kanade.tachiyomi.network.GET
|
||||||
@ -295,7 +295,7 @@ class Wbijam : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
|||||||
VkExtractor(client).getVideosFromUrl(serverUrl, headers)
|
VkExtractor(client).getVideosFromUrl(serverUrl, headers)
|
||||||
}
|
}
|
||||||
serverUrl.contains("dailymotion") -> {
|
serverUrl.contains("dailymotion") -> {
|
||||||
DailymotionExtractor(client).videosFromUrl(serverUrl, headers)
|
DailymotionExtractor(client, headers).videosFromUrl(serverUrl)
|
||||||
}
|
}
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
|
@ -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,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user