Doramasflix added (#1398)
This commit is contained in:
2
src/es/doramasflix/AndroidManifest.xml
Normal file
2
src/es/doramasflix/AndroidManifest.xml
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<manifest package="eu.kanade.tachiyomi.animeextension" />
|
22
src/es/doramasflix/build.gradle
Normal file
22
src/es/doramasflix/build.gradle
Normal 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"
|
BIN
src/es/doramasflix/res/mipmap-hdpi/ic_launcher.png
Normal file
BIN
src/es/doramasflix/res/mipmap-hdpi/ic_launcher.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.1 KiB |
BIN
src/es/doramasflix/res/mipmap-mdpi/ic_launcher.png
Normal file
BIN
src/es/doramasflix/res/mipmap-mdpi/ic_launcher.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.7 KiB |
BIN
src/es/doramasflix/res/mipmap-xhdpi/ic_launcher.png
Normal file
BIN
src/es/doramasflix/res/mipmap-xhdpi/ic_launcher.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.6 KiB |
BIN
src/es/doramasflix/res/mipmap-xxhdpi/ic_launcher.png
Normal file
BIN
src/es/doramasflix/res/mipmap-xxhdpi/ic_launcher.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 8.2 KiB |
BIN
src/es/doramasflix/res/mipmap-xxxhdpi/ic_launcher.png
Normal file
BIN
src/es/doramasflix/res/mipmap-xxxhdpi/ic_launcher.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
@ -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)
|
||||||
|
}
|
||||||
|
}
|
@ -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))
|
||||||
|
}
|
||||||
|
}
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user