Doramasflix added (#1398)

This commit is contained in:
imper1aldev
2023-03-16 00:54:35 -06:00
committed by GitHub
parent 4da99feaa3
commit 7b17628d08
10 changed files with 499 additions and 0 deletions

View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest package="eu.kanade.tachiyomi.animeextension" />

View File

@ -0,0 +1,22 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
ext {
extName = 'Doramasflix'
pkgNameSuffix = 'es.doramasflix'
extClass = '.Doramasflix'
extVersionCode = 1
libVersion = '13'
}
dependencies {
implementation(project(':lib-fembed-extractor'))
implementation(project(':lib-streamtape-extractor'))
implementation(project(':lib-okru-extractor'))
implementation(project(':lib-streamsb-extractor'))
implementation(project(':lib-dood-extractor'))
implementation "dev.datlag.jsunpacker:jsunpacker:1.0.1"
implementation project(path: ':lib-voe-extractor')
}
apply from: "$rootDir/common.gradle"

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@ -0,0 +1,418 @@
package eu.kanade.tachiyomi.animeextension.es.doramasflix
import android.app.Application
import android.content.SharedPreferences
import androidx.preference.ListPreference
import androidx.preference.PreferenceScreen
import eu.kanade.tachiyomi.animeextension.es.doramasflix.extractor.MixDropExtractor
import eu.kanade.tachiyomi.animeextension.es.doramasflix.extractor.UqloadExtractor
import eu.kanade.tachiyomi.animesource.ConfigurableAnimeSource
import eu.kanade.tachiyomi.animesource.model.AnimeFilterList
import eu.kanade.tachiyomi.animesource.model.AnimesPage
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.AnimeHttpSource
import eu.kanade.tachiyomi.lib.fembedextractor.FembedExtractor
import eu.kanade.tachiyomi.lib.okruextractor.OkruExtractor
import eu.kanade.tachiyomi.lib.streamsbextractor.StreamSBExtractor
import eu.kanade.tachiyomi.lib.streamtapeextractor.StreamTapeExtractor
import eu.kanade.tachiyomi.lib.voeextractor.VoeExtractor
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.network.POST
import eu.kanade.tachiyomi.util.asJsoup
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.jsonArray
import kotlinx.serialization.json.jsonObject
import kotlinx.serialization.json.jsonPrimitive
import okhttp3.Headers
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.Request
import okhttp3.RequestBody.Companion.toRequestBody
import okhttp3.Response
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
import uy.kohesive.injekt.injectLazy
class Doramasflix : ConfigurableAnimeSource, AnimeHttpSource() {
override val name = "Doramasflix"
override val baseUrl = "https://doramasflix.in"
private val apiUrl = "https://sv1.fluxcedene.net/api/gql"
// The token is made through a type of milliseconds encryption in combination
// with other calculated strings, the milliseconds indicate the expiration date
// of the token, so it was calculated to expire in 100 years.
private val accessPlatform = "RxARncfg1S_MdpSrCvreoLu_SikCGMzE1NzQzODc3NjE2MQ=="
private val mediaType = "application/json; charset=utf-8".toMediaType()
override val lang = "es"
override val supportsLatest = true
private val json: Json by injectLazy()
private val preferences: SharedPreferences by lazy {
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
}
private val popularRequestHeaders = Headers.headersOf(
"authority", "sv1.fluxcedene.net",
"accept", "application/json, text/plain, */*",
"content-type", "application/json;charset=UTF-8",
"origin", "https://doramasflix.in",
"referer", "https://doramasflix.in/",
"platform", "doramasflix",
"authorization", "Bear",
"x-access-jwt-token", "",
"x-access-platform", accessPlatform,
)
private fun externalOrInternalImg(url: String, isThumb: Boolean = false): String {
return if (url.contains("https")) {
url
} else if (isThumb) {
"https://image.tmdb.org/t/p/w220_and_h330_face$url"
} else {
"https://image.tmdb.org/t/p/w500$url"
}
}
override fun animeDetailsParse(response: Response): SAnime {
val document = response.asJsoup()
val anime = SAnime.create()
document.select("script").map { el ->
if (el.data().contains("{\"props\":{\"pageProps\":{")) {
val apolloState = json.decodeFromString<JsonObject>(el.data())!!.jsonObject["props"]!!.jsonObject["pageProps"]!!.jsonObject["apolloState"]!!.jsonObject
val dorama = apolloState!!.entries!!.firstOrNull()!!.value!!.jsonObject
val genres = try { apolloState.entries.filter { x -> x.key.contains("genres") }.joinToString { it.value.jsonObject["name"]!!.jsonPrimitive.content } } catch (_: Exception) { null }
val network = try { apolloState.entries.firstOrNull { x -> x.key.contains("networks") }?.value?.jsonObject?.get("name")!!.jsonPrimitive.content } catch (_: Exception) { null }
val artist = try { dorama["cast"]?.jsonObject?.get("json")?.jsonArray?.firstOrNull()?.jsonObject?.get("name")?.jsonPrimitive?.content } catch (_: Exception) { null }
val type = dorama["__typename"]!!.jsonPrimitive.content.lowercase()
val poster = dorama["poster_path"]!!.jsonPrimitive.content
val urlImg = poster.ifEmpty { dorama["poster"]!!.jsonPrimitive.content }
val id = dorama["_id"]!!.jsonPrimitive!!.content
anime.title = "${dorama["name"]!!.jsonPrimitive!!.content} (${dorama["name_es"]!!.jsonPrimitive!!.content})"
anime.description = dorama["overview"]!!.jsonPrimitive!!.content.trim()
anime.genre = genres
anime.author = network
anime.artist = artist
anime.status = if (type == "movie") SAnime.COMPLETED else SAnime.UNKNOWN
anime.thumbnail_url = externalOrInternalImg(urlImg)
anime.setUrlWithoutDomain(urlSolverByType(dorama["__typename"]!!.jsonPrimitive!!.content, dorama["slug"]!!.jsonPrimitive!!.content, id))
}
}
return anime
}
override fun episodeListRequest(anime: SAnime): Request {
val id = anime.url.substringAfter("?id=")
return if (anime.url.contains("peliculas-online")) {
GET(baseUrl + anime.url)
} else {
val body = (
"{\"operationName\":\"listSeasons\",\"variables\":{\"serie_id\":\"$id\"},\"query\":\"query listSeasons(\$serie_id: MongoID!) " +
"{\\n listSeasons(sort: NUMBER_ASC, filter: {serie_id: \$serie_id}) {\\n slug\\n season_number\\n poster_path\\n air_date\\n " +
"serie_name\\n poster\\n backdrop\\n __typename\\n }\\n}\\n\"}"
).toRequestBody(mediaType)
POST("$apiUrl?id=$id", popularRequestHeaders, body)
}
}
override fun episodeListParse(response: Response): List<SEpisode> {
val episodes = mutableListOf<SEpisode>()
if (response.request.url.toString().contains("peliculas-online")) {
val episode = SEpisode.create()
episode.episode_number = 1F
episode.name = "Película"
episode.setUrlWithoutDomain(response.request.url.toString())
episodes.add(episode)
} else {
val jsonEpisodes = mutableListOf<String>()
val id = response.request.url.toString().substringAfter("?id=")
val responseString = response.body.string()
val data = json.decodeFromString<JsonObject>(responseString)!!.jsonObject["data"]!!.jsonObject
data["listSeasons"]!!.jsonArray.forEach {
val season = it.jsonObject["season_number"]!!.jsonPrimitive.content
val body = (
"{\"operationName\":\"listEpisodes\",\"variables\":{\"serie_id\":\"$id\",\"season_number\":$season},\"query\":\"query " +
"listEpisodes(\$season_number: Float!, \$serie_id: MongoID!) {\\n listEpisodes(sort: NUMBER_ASC, filter: {type_serie: \\\"dorama\\\", " +
"serie_id: \$serie_id, season_number: \$season_number}) {\\n _id\\n name\\n slug\\n serie_name\\n serie_name_es\\n " +
"serie_id\\n still_path\\n air_date\\n season_number\\n episode_number\\n languages\\n poster\\n backdrop\\n __typename\\n }\\n}\\n\"}"
).toRequestBody(mediaType)
client.newCall(POST(apiUrl, popularRequestHeaders, body)).execute().let { resp -> jsonEpisodes.add(resp.body.string()) }
}
jsonEpisodes.forEach { json -> episodes.addAll(parseEpisodeListJson(json)) }
}
return episodes.reversed()
}
private fun parseEpisodeListJson(jsonLine: String?): List<SEpisode> {
val jsonData = jsonLine ?: return emptyList()
val episodes = mutableListOf<SEpisode>()
val data = json.decodeFromString<JsonObject>(jsonData)!!.jsonObject["data"]!!.jsonObject
data["listEpisodes"]!!.jsonArray!!.map {
val noSeason = it.jsonObject["season_number"]!!.jsonPrimitive!!.content
val noEpisode = it.jsonObject["episode_number"]!!.jsonPrimitive!!.content
var nameEp = it.jsonObject["name"]!!.jsonPrimitive!!.content
nameEp = if (nameEp == "null") "- Capítulo $noEpisode" else "- $nameEp"
val slug = it.jsonObject["slug"]!!.jsonPrimitive!!.content
val episode = SEpisode.create()
episode.name = "T$noSeason - E$noEpisode $nameEp"
episode.episode_number = noEpisode.toFloat()
episode.setUrlWithoutDomain(urlSolverByType("episode", slug))
episodes.add(episode)
}
return episodes
}
override fun latestUpdatesParse(response: Response): AnimesPage {
val responseString = response.body.string()
return parsePopularAnimeJson(responseString)
}
override fun latestUpdatesRequest(page: Int): Request {
val mediaType = "application/json; charset=utf-8".toMediaType()
val body = (
"{\"operationName\":\"listDoramas\",\"variables\":{\"page\":$page,\"sort\":\"CREATEDAT_DESC\",\"perPage\":32,\"filter\":{\"isTVShow\":false}}," +
"\"query\":\"query listDoramas(\$page: Int, \$perPage: Int, \$sort: SortFindManyDoramaInput, \$filter: FilterFindManyDoramaInput) {\\n " +
"paginationDorama(page: \$page, perPage: \$perPage, sort: \$sort, filter: \$filter) {\\n count\\n pageInfo {\\n currentPage\\n " +
"hasNextPage\\n hasPreviousPage\\n __typename\\n }\\n items {\\n _id\\n name\\n name_es\\n slug\\n " +
"cast\\n names\\n overview\\n languages\\n created_by\\n popularity\\n poster_path\\n vote_average\\n " +
"backdrop_path\\n first_air_date\\n episode_run_time\\n isTVShow\\n poster\\n backdrop\\n genres {\\n " +
"name\\n slug\\n __typename\\n }\\n networks {\\n name\\n slug\\n __typename\\n }\\n " +
"__typename\\n }\\n __typename\\n }\\n}\\n\"}"
).toRequestBody(mediaType)
return POST(apiUrl, popularRequestHeaders, body)
}
override fun popularAnimeParse(response: Response): AnimesPage {
val responseString = response.body.string()
return parsePopularAnimeJson(responseString)
}
private fun parsePopularAnimeJson(jsonLine: String?): AnimesPage {
val jsonData = jsonLine ?: return AnimesPage(emptyList(), false)
val animeList = mutableListOf<SAnime>()
val paginationDorama = json.decodeFromString<JsonObject>(jsonData)!!.jsonObject["data"]!!.jsonObject!!["paginationDorama"]!!.jsonObject
val hasNextPage = paginationDorama["pageInfo"]!!.jsonObject["hasNextPage"]!!.jsonPrimitive!!.content!!.toBoolean()
paginationDorama["items"]!!.jsonArray.map {
val anime = SAnime.create()
val genres = it.jsonObject!!["genres"]!!.jsonArray!!.joinToString { it.jsonObject["name"]!!.jsonPrimitive!!.content }
val id = it.jsonObject!!["_id"]!!.jsonPrimitive!!.content
val poster = it.jsonObject["poster_path"]!!.jsonPrimitive.content
val urlImg = poster.ifEmpty { it.jsonObject!!["poster"]!!.jsonPrimitive.content }
anime.title = "${it.jsonObject!!["name"]!!.jsonPrimitive!!.content} (${it.jsonObject!!["name_es"]!!.jsonPrimitive!!.content})"
anime.description = it.jsonObject!!["overview"]!!.jsonPrimitive!!.content
anime.genre = genres
anime.thumbnail_url = externalOrInternalImg(urlImg, true)
// "https://image.tmdb.org/t/p/w220_and_h330_face${it.jsonObject!!["poster_path"]!!.jsonPrimitive!!.content}"
anime.setUrlWithoutDomain(urlSolverByType(it.jsonObject!!["__typename"]!!.jsonPrimitive!!.content, it.jsonObject!!["slug"]!!.jsonPrimitive!!.content, id))
animeList.add(anime)
}
return AnimesPage(animeList, hasNextPage)
}
private fun urlSolverByType(type: String, slug: String, id: String? = ""): String {
return when (type.lowercase()) {
"dorama" -> "$baseUrl/doramas-online/$slug?id=$id"
"episode" -> "$baseUrl/episodios/$slug"
"movie" -> "$baseUrl/peliculas-online/$slug?id=$id"
else -> ""
}
}
override fun popularAnimeRequest(page: Int): Request {
val mediaType = "application/json; charset=utf-8".toMediaType()
val body = (
"{\"operationName\":\"listDoramas\",\"variables\":{\"page\":$page,\"sort\":\"POPULARITY_DESC\",\"perPage\":32,\"filter\":{\"isTVShow\":false}}," +
"\"query\":\"query listDoramas(\$page: Int, \$perPage: Int, \$sort: SortFindManyDoramaInput, \$filter: FilterFindManyDoramaInput) {\\n " +
"paginationDorama(page: \$page, perPage: \$perPage, sort: \$sort, filter: \$filter) {\\n count\\n pageInfo {\\n currentPage\\n " +
"hasNextPage\\n hasPreviousPage\\n __typename\\n }\\n items {\\n _id\\n name\\n name_es\\n slug\\n " +
"cast\\n names\\n overview\\n languages\\n created_by\\n popularity\\n poster_path\\n vote_average\\n " +
"backdrop_path\\n first_air_date\\n episode_run_time\\n isTVShow\\n poster\\n backdrop\\n genres {\\n " +
"name\\n slug\\n __typename\\n }\\n networks {\\n name\\n slug\\n __typename\\n }\\n " +
"__typename\\n }\\n __typename\\n }\\n}\\n\"}"
).toRequestBody(mediaType)
return POST(apiUrl, popularRequestHeaders, body)
}
override fun searchAnimeParse(response: Response): AnimesPage {
val responseString = response.body.string()
return if (responseString.contains("searchDorama")) {
parseSearchAnimeJson(responseString)
} else {
parsePopularAnimeJson(responseString)
}
}
private fun parseSearchAnimeJson(jsonLine: String?): AnimesPage {
val jsonData = jsonLine ?: return AnimesPage(emptyList(), false)
val animeList = mutableListOf<SAnime>()
val paginationDorama = json.decodeFromString<JsonObject>(jsonData)!!.jsonObject["data"]!!.jsonObject
paginationDorama["searchDorama"]!!.jsonArray.map {
val anime = SAnime.create()
val id = it.jsonObject!!["_id"]!!.jsonPrimitive!!.content
val poster = it.jsonObject!!["poster_path"]!!.jsonPrimitive!!.content
val urlImg = poster.ifEmpty { it.jsonObject!!["poster"]!!.jsonPrimitive!!.content }
anime.title = "${it.jsonObject!!["name"]!!.jsonPrimitive!!.content} (${it.jsonObject!!["name_es"]!!.jsonPrimitive!!.content})"
anime.thumbnail_url = externalOrInternalImg(urlImg, true)
anime.setUrlWithoutDomain(urlSolverByType(it.jsonObject!!["__typename"]!!.jsonPrimitive!!.content, it.jsonObject!!["slug"]!!.jsonPrimitive!!.content, id))
animeList.add(anime)
}
paginationDorama["searchMovie"]!!.jsonArray.map {
val anime = SAnime.create()
val id = it.jsonObject!!["_id"]!!.jsonPrimitive!!.content
val poster = it.jsonObject!!["poster_path"]!!.jsonPrimitive!!.content
val urlImg = poster.ifEmpty { it.jsonObject!!["poster"]!!.jsonPrimitive!!.content }
anime.title = "${it.jsonObject!!["name"]!!.jsonPrimitive!!.content} (${it.jsonObject!!["name_es"]!!.jsonPrimitive!!.content})"
anime.thumbnail_url = externalOrInternalImg(urlImg, true)
anime.setUrlWithoutDomain(urlSolverByType(it.jsonObject!!["__typename"]!!.jsonPrimitive!!.content, it.jsonObject!!["slug"]!!.jsonPrimitive!!.content, id))
animeList.add(anime)
}
return AnimesPage(animeList, false)
}
override fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList): Request {
return when {
query.isNotBlank() -> searchQueryRequest(query)
else -> popularAnimeRequest(page)
}
}
private fun searchQueryRequest(query: String): Request {
val fxQuery = query.replace("+", " ")
val body = (
"{\"operationName\":\"searchAll\",\"variables\":{\"input\":\"$fxQuery\"},\"query\":\"query searchAll(\$input: String!) {\\n " +
"searchDorama(input: \$input, limit: 32) {\\n _id\\n slug\\n name\\n name_es\\n poster_path\\n poster\\n " +
"__typename\\n }\\n searchMovie(input: \$input, limit: 32) {\\n _id\\n name\\n name_es\\n slug\\n poster_path\\n " +
"poster\\n __typename\\n }\\n}\\n\"}"
).toRequestBody(mediaType)
return POST(apiUrl, popularRequestHeaders, body)
}
private fun fetchUrls(text: String?): List<String> {
if (text.isNullOrEmpty()) return listOf()
val linkRegex = "(https?://(www\\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\\.[a-zA-Z0-9()]{1,6}\\b([-a-zA-Z0-9()@:%_+.~#?&/=]*))".toRegex()
return linkRegex.findAll(text).map { it.value.trim().removeSurrounding("\"") }.toList()
}
override fun videoListParse(response: Response): List<Video> {
val document = response.asJsoup()
val videos = mutableListOf<Video>()
val script = document.selectFirst("script:containsData({\"props\":{\"pageProps\":{)")!!.data()
fetchUrls(script).map { link ->
resolveVideoServer(link).let { videos.addAll(it) }
}
return videos
}
private fun resolveVideoServer(link: String): List<Video> {
val videos = mutableListOf<Video>()
if (link.contains("streamtape")) {
try {
StreamTapeExtractor(client).videoFromUrl(link)?.let { videos.add(it) }
} catch (_: Exception) {}
}
if (link.contains("mixdrop")) {
try {
MixDropExtractor(client).videoFromUrl(link).let { videos.addAll(it) }
} catch (_: Exception) {}
}
if (link.contains("uqload")) {
try {
val headers = headers.newBuilder()
.add("authority", "uqload.co")
.add("referer", "https://uqload.co/")
.build()
UqloadExtractor(client).videoFromUrl(link, headers, "YourUpload").let { videos.addAll(it) }
} catch (_: Exception) {}
}
if (link.contains("ok.ru")) {
try {
OkruExtractor(client).videosFromUrl(link, "", true).let { videos.addAll(it) }
} catch (_: Exception) {}
}
if (link.contains("fembed") || link.contains("anime789.com") || link.contains("24hd.club") ||
link.contains("fembad.org") || link.contains("vcdn.io") || link.contains("sharinglink.club") ||
link.contains("moviemaniac.org") || link.contains("votrefiles.club") || link.contains("femoload.xyz") ||
link.contains("albavido.xyz") || link.contains("feurl.com") || link.contains("dailyplanet.pw") ||
link.contains("ncdnstm.com") || link.contains("jplayer.net") || link.contains("xstreamcdn.com") ||
link.contains("fembed-hd.com") || link.contains("gcloud.live") || link.contains("vcdnplay.com") ||
link.contains("superplayxyz.club") || link.contains("vidohd.com") || link.contains("vidsource.me") ||
link.contains("cinegrabber.com") || link.contains("votrefile.xyz") || link.contains("zidiplay.com") ||
link.contains("ndrama.xyz") || link.contains("fcdn.stream") || link.contains("mediashore.org") ||
link.contains("suzihaza.com") || link.contains("there.to") || link.contains("femax20.com") ||
link.contains("javstream.top") || link.contains("viplayer.cc") || link.contains("sexhd.co") ||
link.contains("fembed.net") || link.contains("mrdhan.com") || link.contains("votrefilms.xyz") ||
link.contains("embedsito.com") || link.contains("dutrag.com") || link.contains("youvideos.ru") ||
link.contains("streamm4u.club") || link.contains("moviepl.xyz") || link.contains("asianclub.tv") ||
link.contains("vidcloud.fun") || link.contains("fplayer.info") || link.contains("diasfem.com") ||
link.contains("javpoll.com") || link.contains("reeoov.tube") || link.contains("suzihaza.com") ||
link.contains("ezsubz.com") || link.contains("vidsrc.xyz") || link.contains("diampokusy.com") ||
link.contains("diampokusy.com") || link.contains("i18n.pw") || link.contains("vanfem.com") ||
link.contains("fembed9hd.com") || link.contains("votrefilms.xyz") || link.contains("watchjavnow.xyz")
) {
try {
FembedExtractor(client).videosFromUrl(link, redirect = !link.contains("fembed")).let { videos.addAll(it) }
} catch (_: Exception) {}
}
if (link.contains("voe")) {
try {
VoeExtractor(client).videoFromUrl(link, "Voex")?.let { videos.add(it) }
} catch (_: Exception) {}
}
if (link.contains("sbembed.com") || link.contains("sbembed1.com") || link.contains("sbplay.org") ||
link.contains("sbvideo.net") || link.contains("streamsb.net") || link.contains("sbplay.one") ||
link.contains("cloudemb.com") || link.contains("playersb.com") || link.contains("tubesb.com") ||
link.contains("sbplay1.com") || link.contains("embedsb.com") || link.contains("watchsb.com") ||
link.contains("sbplay2.com") || link.contains("japopav.tv") || link.contains("viewsb.com") ||
link.contains("sbfast") || link.contains("sbfull.com") || link.contains("javplaya.com") ||
link.contains("ssbstream.net") || link.contains("p1ayerjavseen.com") || link.contains("sbthe.com") ||
link.contains("vidmovie.xyz") || link.contains("sbspeed.com") || link.contains("streamsss.net") ||
link.contains("sblanh.com") || link.contains("tvmshow.com") || link.contains("sbanh.com") ||
link.contains("streamovies.xyz")
) {
try {
StreamSBExtractor(client).videosFromUrl(link, headers).let { videos.addAll(it) }
} catch (_: Exception) {}
}
return videos
}
override fun setupPreferenceScreen(screen: PreferenceScreen) {
val qualities = arrayOf(
"Okru:1080p", "Okru:720p", "Okru:480p", "Okru:360p", "Okru:240p", "Okru:144p", // Okru
"StreamSB:1080p", "StreamSB:720p", "StreamSB:480p", "StreamSB:360p", "StreamSB:240p", "StreamSB:144p", // StreamSB
"Fembed:1080p", "Fembed:720p", "Fembed:480p", "Fembed:360p", "Fembed:240p", "Fembed:144p", // Fembed
"Streamlare:1080p", "Streamlare:720p", "Streamlare:480p", "Streamlare:360p", "Streamlare:240p", // Streamlare
"StreamTape", "Voex", "DoodStream", "YourUpload", "MixDrop",
)
val videoQualityPref = ListPreference(screen.context).apply {
key = "preferred_quality"
title = "Preferred quality"
entries = qualities
entryValues = qualities
setDefaultValue("Voex")
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()
}
}
screen.addPreference(videoQualityPref)
}
}

View File

@ -0,0 +1,29 @@
package eu.kanade.tachiyomi.animeextension.es.doramasflix.extractor
import dev.datlag.jsunpacker.JsUnpacker
import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.util.asJsoup
import okhttp3.Headers
import okhttp3.OkHttpClient
class MixDropExtractor(private val client: OkHttpClient) {
fun videoFromUrl(url: String, lang: String = ""): List<Video> {
val doc = client.newCall(GET(url)).execute().asJsoup()
val unpacked = doc.selectFirst("script:containsData(eval):containsData(MDCore)")
?.data()
?.let { JsUnpacker.unpackAndCombine(it) }
?: return emptyList<Video>()
val videoUrl = "https:" + unpacked.substringAfter("Core.wurl=\"")
.substringBefore("\"")
val quality = ("MixDrop").let {
if (lang.isNotBlank()) {
"$it($lang)"
} else {
it
}
}
val referer = Headers.headersOf("Referer", "https://mixdrop.co/")
return listOf(Video(url, quality, videoUrl, headers = referer))
}
}

View File

@ -0,0 +1,28 @@
package eu.kanade.tachiyomi.animeextension.es.doramasflix.extractor
import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.util.asJsoup
import okhttp3.Headers
import okhttp3.OkHttpClient
class UqloadExtractor(private val client: OkHttpClient) {
fun videoFromUrl(url: String, headers: Headers, quality: String): List<Video> {
val videoList = mutableListOf<Video>()
return try {
val document = client.newCall(GET(url)).execute()
if (document.isSuccessful) {
val response = document.asJsoup()
response.select("script").map {
if (it.data().contains("var player =")) {
val basicUrl = it.data().substringAfter("sources: [\"").substringBefore("\"],")
videoList.add(Video(basicUrl, quality, basicUrl, headers = headers))
}
}
}
videoList
} catch (e: Exception) {
videoList
}
}
}