src/ar+de+es dead sources (#814)

* src/es pelisflix/seriesflix

* src/de streamcloud

* src/de movie2k

* src/de cineclix

* src/ar xsanime/xsmovie

* src/ar tuktuk

* src/ar akwam

---------

Co-authored-by: Your Name <you@example.com>
This commit is contained in:
krysanify 2025-03-25 02:30:35 +08:00 committed by GitHub
parent 0fb8c32aa6
commit 3a58bf47ff
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
61 changed files with 0 additions and 2551 deletions

View file

@ -1,7 +0,0 @@
ext {
extName = 'Akwam'
extClass = '.Akwam'
extVersionCode = 9
}
apply from: "$rootDir/common.gradle"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

View file

@ -1,355 +0,0 @@
package eu.kanade.tachiyomi.animeextension.ar.akwam
import android.app.Application
import android.content.SharedPreferences
import androidx.preference.ListPreference
import androidx.preference.PreferenceScreen
import eu.kanade.tachiyomi.animesource.ConfigurableAnimeSource
import eu.kanade.tachiyomi.animesource.model.AnimeFilter
import eu.kanade.tachiyomi.animesource.model.AnimeFilterList
import eu.kanade.tachiyomi.animesource.model.SAnime
import eu.kanade.tachiyomi.animesource.model.SEpisode
import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.animesource.online.ParsedAnimeHttpSource
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.util.asJsoup
import okhttp3.Headers
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
import okhttp3.Request
import okhttp3.Response
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
class Akwam : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
override val name = "أكوام"
override val baseUrl = "https://akw-cdn1.link"
override val lang = "ar"
override val supportsLatest = false
private val preferences: SharedPreferences by lazy {
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
}
// Popular
override fun popularAnimeSelector(): String = "div.entry-box-1 div.entry-image a.box"
override fun popularAnimeRequest(page: Int): Request = GET("$baseUrl/movies?page=$page")
override fun popularAnimeFromElement(element: Element): SAnime {
val anime = SAnime.create()
anime.thumbnail_url = element.select("picture img").attr("data-src")
anime.setUrlWithoutDomain(element.attr("href"))
anime.title = element.select("picture img").attr("alt")
return anime
}
override fun popularAnimeNextPageSelector(): String = "ul.pagination li.page-item a[rel=next]"
// episodes
override fun episodeListSelector() = "div.bg-primary2 h2 a"
override fun episodeListParse(response: Response): List<SEpisode> {
val episodes = mutableListOf<SEpisode>()
fun addEpisodes(document: Document) {
if (document.select(episodeListSelector()).isNullOrEmpty()) {
// add movie
document.select("input#reportInputUrl").map { episodes.add(episodeFromElement(it)) }
} else {
document.select(episodeListSelector()).map { episodes.add(episodesFromElement(it)) }
}
}
addEpisodes(response.asJsoup())
return episodes
}
override fun episodeFromElement(element: Element): SEpisode {
val episode = SEpisode.create()
episode.setUrlWithoutDomain(element.attr("value"))
episode.name = "مشاهدة"
return episode
}
private fun episodesFromElement(element: Element): SEpisode {
val episode = SEpisode.create()
val epNum = getNumberFromEpsString(element.text())
episode.setUrlWithoutDomain(element.attr("href"))
episode.name = element.text()
episode.episode_number = when {
epNum.isNotEmpty() -> epNum.toFloatOrNull() ?: 1F
else -> 1F
}
return episode
}
private fun getNumberFromEpsString(epsStr: String): String {
return epsStr.filter { it.isDigit() }
}
// Video links
override fun videoListParse(response: Response): List<Video> {
val document = response.asJsoup()
val iframe = "https://akw-cdn1.link/watch" + document.select("a.link-show").attr("href").substringAfter("watch") + "/" + document.ownerDocument()!!.select("input#page_id").attr("value")
val referer = response.request.url.toString()
val refererHeaders = Headers.headersOf("referer", referer)
val iframeResponse = client.newCall(GET(iframe, refererHeaders))
.execute().asJsoup()
return iframeResponse.select(videoListSelector()).map { videoFromElement(it) }
}
override fun videoListSelector() = "source"
override fun videoFromElement(element: Element): Video {
return Video(element.attr("src").replace("https", "http"), element.attr("size") + "p", element.attr("src").replace("https", "http"))
}
override fun List<Video>.sort(): List<Video> {
val quality = preferences.getString("preferred_quality", null)
if (quality != null) {
val newList = mutableListOf<Video>()
var preferred = 0
for (video in this) {
if (video.quality.contains(quality)) {
newList.add(preferred, video)
preferred++
} else {
newList.add(video)
}
}
return newList
}
return this
}
override fun videoUrlParse(document: Document) = throw UnsupportedOperationException()
// Search
override fun searchAnimeFromElement(element: Element): SAnime {
val anime = SAnime.create()
anime.thumbnail_url = element.select("picture img").attr("data-src")
anime.setUrlWithoutDomain(element.attr("href"))
anime.title = element.select("picture img").attr("alt")
return anime
}
override fun searchAnimeNextPageSelector(): String = "ul.pagination li.page-item a[rel=next]"
override fun searchAnimeSelector(): String = "div.widget div.widget-body div.col-lg-auto div.entry-box div.entry-image a.box"
override fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList): Request {
val url = if (query.isNotBlank()) {
val url = "$baseUrl/search?q=$query&page=$page".toHttpUrlOrNull()!!.newBuilder()
filters.forEach { filter ->
when (filter) {
is SectionFilter -> url.addQueryParameter("section", filter.toUriPart())
is RatingFilter -> url.addQueryParameter("rating", filter.toUriPart())
is FormatFilter -> url.addQueryParameter("formats", filter.toUriPart())
is QualityFilter -> url.addQueryParameter("quality", filter.toUriPart())
else -> {}
}
}
url.toString()
} else {
val url = "$baseUrl/search?page=$page".toHttpUrlOrNull()!!.newBuilder()
var type = "movies"
filters.forEach { filter ->
when (filter) {
is TypeFilter -> type = filter.toUriPart().toString()
is SectionSFilter -> url.addQueryParameter("section", filter.toUriPart())
is CategorySFilter -> url.addQueryParameter("category", filter.toUriPart())
is RatingSFilter -> url.addQueryParameter("rating", filter.toUriPart())
// is LanguageSFilter -> url.addQueryParameter("quality", filter.toUriPart())
else -> {}
}
}
url.toString().replace("search", type)
}
return GET(url, headers)
}
// Anime Details
override fun animeDetailsParse(document: Document): SAnime {
val anime = SAnime.create()
// anime.thumbnail_url = document.select("div.container div div a picture > img.img-fluid").attr("data-src")
anime.title = document.select("picture > img.img-fluid").attr("alt")
anime.genre = document.select("div.font-size-16.d-flex.align-items-center.mt-3 a.badge, span.badge-info, span:contains(جودة الفيلم), span:contains(انتاج)").joinToString(", ") { it.text().replace("جودة الفيلم : ", "") }
anime.author = document.select("span:contains(انتاج)").text().replace("انتاج : ", "")
anime.description = document.select("div.widget:contains(قصة )").text()
anime.status = SAnime.COMPLETED
return anime
}
// Latest
override fun latestUpdatesNextPageSelector(): String = throw UnsupportedOperationException()
override fun latestUpdatesFromElement(element: Element): SAnime = throw UnsupportedOperationException()
override fun latestUpdatesRequest(page: Int): Request = throw UnsupportedOperationException()
override fun latestUpdatesSelector(): String = throw UnsupportedOperationException()
// Filters
override fun getFilterList() = AnimeFilterList(
AnimeFilter.Header("فلترات البحث"),
AnimeFilter.Separator(),
SectionFilter(getSectionFilter()),
RatingFilter(getRatingFilter()),
FormatFilter(getFormatFilter()),
QualityFilter(getQualityFilter()),
AnimeFilter.Header("تصفح الموقع (تعمل فقط لو كان البحث فارغ)"),
AnimeFilter.Separator(),
TypeFilter(getTypeFilter()),
SectionSFilter(getSectionSFilter()),
CategorySFilter(getCategorySFilter()),
RatingSFilter(getRatingSFilter()),
)
private class SectionFilter(vals: Array<Pair<String?, String>>) : UriPartFilter("الأقسام", vals)
private class RatingFilter(vals: Array<Pair<String?, String>>) : UriPartFilter("التقيم", vals)
private class FormatFilter(vals: Array<Pair<String?, String>>) : UriPartFilter("الجودة", vals)
private class QualityFilter(vals: Array<Pair<String?, String>>) : UriPartFilter("الدقة", vals)
private class TypeFilter(vals: Array<Pair<String?, String>>) : UriPartFilter("النوع", vals)
private class SectionSFilter(vals: Array<Pair<String?, String>>) : UriPartFilter("القسم", vals)
private class CategorySFilter(vals: Array<Pair<String?, String>>) : UriPartFilter("التصنيف", vals)
private class RatingSFilter(vals: Array<Pair<String?, String>>) : UriPartFilter("التقييم", vals)
private fun getTypeFilter(): Array<Pair<String?, String>> = arrayOf(
Pair("movies", "افلام"),
Pair("series", "مسلسلات"),
)
private fun getSectionFilter(): Array<Pair<String?, String>> = arrayOf(
Pair("0", "الكل"),
Pair("movie", "افلام"),
Pair("series", "مسلسلات"),
Pair("show", "تلفزيون"),
)
private fun getRatingFilter(): Array<Pair<String?, String>> = arrayOf(
Pair("0", "التقييم"),
Pair("1", "1+"),
Pair("2", "2+"),
Pair("3", "3+"),
Pair("4", "4+"),
Pair("5", "5+"),
Pair("6", "6+"),
Pair("7", "7+"),
Pair("8", "8+"),
Pair("9", "9+"),
)
private fun getFormatFilter(): Array<Pair<String?, String>> = arrayOf(
Pair("0", "الكل"),
Pair("BluRay", "BluRay"),
Pair("WebRip", "WebRip"),
Pair("BRRIP", "BRRIP"),
Pair("DVDrip", "DVDrip"),
Pair("DVDSCR", "DVDSCR"),
Pair("HD", "HD"),
Pair("HDTS", "HDTS"),
Pair("HDTV", "HDTV"),
Pair("CAM", "CAM"),
Pair("WEB-DL", "WEB-DL"),
Pair("HDTC", "HDTC"),
Pair("BDRIP", "BDRIP"),
Pair("HDRIP", "HDRIP"),
Pair("HC+HDRIP", "HC HDRIP"),
)
private fun getQualityFilter(): Array<Pair<String?, String>> = arrayOf(
Pair("0", "الدقة"),
Pair("240p", "240p"),
Pair("360p", "360p"),
Pair("480p", "480p"),
Pair("720p", "720p"),
Pair("1080p", "1080p"),
Pair("3D", "3D"),
Pair("4K", "4K"),
)
private fun getSectionSFilter(): Array<Pair<String?, String>> = arrayOf(
Pair("0", "القسم"),
Pair("29", "عربي"),
Pair("30", "اجنبي"),
Pair("31", "هندي"),
Pair("32", "تركي"),
Pair("33", "اسيوي"),
)
private fun getCategorySFilter(): Array<Pair<String?, String>> = arrayOf(
Pair("0", "التصنيف"),
Pair("87", "رمضان"),
Pair("30", "انمي"),
Pair("18", "اكشن"),
Pair("71", "مدبلج"),
Pair("72", "NETFLIX"),
Pair("20", "كوميدي"),
Pair("35", "اثارة"),
Pair("34", "غموض"),
Pair("33", "عائلي"),
Pair("88", "اطفال"),
Pair("25", "حربي"),
Pair("32", "رياضي"),
Pair("89", "قصير"),
Pair("43", "فانتازيا"),
Pair("24", "خيال علمي"),
Pair("31", "موسيقى"),
Pair("29", "سيرة ذاتية"),
Pair("28", "وثائقي"),
Pair("27", "رومانسي"),
Pair("26", "تاريخي"),
Pair("23", "دراما"),
Pair("22", "رعب"),
Pair("21", "جريمة"),
Pair("19", "مغامرة"),
Pair("91", "غربي"),
)
private fun getRatingSFilter(): Array<Pair<String?, String>> = arrayOf(
Pair("0", "التقييم"),
Pair("1", "1+"),
Pair("2", "2+"),
Pair("3", "3+"),
Pair("4", "4+"),
Pair("5", "5+"),
Pair("6", "6+"),
Pair("7", "7+"),
Pair("8", "8+"),
Pair("9", "9+"),
)
open class UriPartFilter(displayName: String, private val vals: Array<Pair<String?, String>>) :
AnimeFilter.Select<String>(displayName, vals.map { it.second }.toTypedArray()) {
fun toUriPart() = vals[state].first
}
// preferred quality settings
override fun setupPreferenceScreen(screen: PreferenceScreen) {
val videoQualityPref = ListPreference(screen.context).apply {
key = "preferred_quality"
title = "Preferred quality"
entries = arrayOf("1080p", "720p", "480p", "360p", "240p")
entryValues = arrayOf("1080", "720", "480", "360", "240")
setDefaultValue("1080")
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

@ -1,17 +0,0 @@
ext {
extName = 'Tuktuk Cinema'
extClass = '.Tuktukcinema'
extVersionCode = 24
}
apply from: "$rootDir/common.gradle"
dependencies {
implementation(project(':lib:uqload-extractor'))
implementation(project(':lib:okru-extractor'))
implementation(project(':lib:dood-extractor'))
implementation(project(':lib:streamtape-extractor'))
implementation(project(':lib:vidbom-extractor'))
implementation(project(':lib:playlist-utils'))
implementation(libs.jsunpacker)
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

View file

@ -1,309 +0,0 @@
package eu.kanade.tachiyomi.animeextension.ar.tuktukcinema
import android.app.Application
import android.content.SharedPreferences
import androidx.preference.ListPreference
import androidx.preference.PreferenceScreen
import dev.datlag.jsunpacker.JsUnpacker
import eu.kanade.tachiyomi.animesource.ConfigurableAnimeSource
import eu.kanade.tachiyomi.animesource.model.AnimeFilter
import eu.kanade.tachiyomi.animesource.model.AnimeFilterList
import eu.kanade.tachiyomi.animesource.model.SAnime
import eu.kanade.tachiyomi.animesource.model.SEpisode
import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.animesource.online.ParsedAnimeHttpSource
import eu.kanade.tachiyomi.lib.doodextractor.DoodExtractor
import eu.kanade.tachiyomi.lib.okruextractor.OkruExtractor
import eu.kanade.tachiyomi.lib.playlistutils.PlaylistUtils
import eu.kanade.tachiyomi.lib.streamtapeextractor.StreamTapeExtractor
import eu.kanade.tachiyomi.lib.uqloadextractor.UqloadExtractor
import eu.kanade.tachiyomi.lib.vidbomextractor.VidBomExtractor
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.util.asJsoup
import eu.kanade.tachiyomi.util.parallelCatchingFlatMapBlocking
import okhttp3.Request
import okhttp3.Response
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
class Tuktukcinema : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
override val name = "توك توك سينما"
// TODO: Check frequency of url changes to potentially
// add back overridable baseurl preference
override val baseUrl = "https://w.tuktokcinema.com"
override val lang = "ar"
override val supportsLatest = true
private val preferences: SharedPreferences by lazy {
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
}
// ============================ popular ===============================
override fun popularAnimeSelector(): String = "div.Block--Item, div.Small--Box"
override fun popularAnimeRequest(page: Int): Request = GET(baseUrl)
override fun popularAnimeFromElement(element: Element): SAnime {
val anime = SAnime.create()
anime.title = titleEdit(element.select("a").attr("title"), true).trim()
anime.thumbnail_url = element.select("img").attr("data-src")
anime.setUrlWithoutDomain(element.select("a").attr("href") + "watch/")
return anime
}
private fun titleEdit(title: String, details: Boolean = false): String {
return if (Regex("(?:فيلم|عرض)\\s(.*\\s[0-9]+)\\s(.+?)\\s").containsMatchIn(title)) {
val titleGroup = Regex("(?:فيلم|عرض)\\s(.*\\s[0-9]+)\\s(.+?)\\s").find(title)
val movieName = titleGroup!!.groupValues[1]
val type = titleGroup.groupValues[2]
movieName + if (details) " ($type)" else ""
} else if (Regex("(?:مسلسل|برنامج|انمي)\\s(.+)\\sالحلقة\\s(\\d+)").containsMatchIn(title)) {
val titleGroup = Regex("(?:مسلسل|برنامج|انمي)\\s(.+)\\sالحلقة\\s(\\d+)").find(title)
val seriesName = titleGroup!!.groupValues[1]
val epNum = titleGroup.groupValues[2]
if (details) {
"$seriesName (ep:$epNum)"
} else if (seriesName.contains("الموسم")) {
seriesName.split("الموسم")[0].trim()
} else {
seriesName
}
} else {
title
}
}
override fun popularAnimeNextPageSelector(): String = "div.pagination ul.page-numbers li a.next"
// ============================ episodes ===============================
private fun seasonsNextPageSelector() = "section.allseasonss div.Block--Item"
override fun episodeListParse(response: Response): List<SEpisode> {
val episodes = mutableListOf<SEpisode>()
fun addEpisodeNew(url: String, title: String) {
val episode = SEpisode.create()
episode.setUrlWithoutDomain(url)
episode.name = title
episodes.add(episode)
}
fun addEpisodes(response: Response) {
val document = response.asJsoup()
val url = response.request.url.toString()
if (document.select(seasonsNextPageSelector()).isNullOrEmpty()) {
addEpisodeNew("$url/watch/", "مشاهدة")
} else {
document.select(seasonsNextPageSelector()).reversed().forEach { season ->
val seasonNum = season.select("h3").text()
(
if (seasonNum == document.selectFirst("div#mpbreadcrumbs a span:contains(الموسم)")!!.text()) {
document
} else {
client.newCall(GET(season.selectFirst("a")!!.attr("href"))).execute().asJsoup()
}
)
.select("section.allepcont a").forEach { episode ->
addEpisodeNew(
episode.attr("href") + "watch/",
seasonNum + " : الحلقة " + episode.select("div.epnum").text().filter { it.isDigit() },
)
}
}
}
}
addEpisodes(response)
return episodes
}
override fun episodeListSelector() = "link[rel=canonical]"
override fun episodeFromElement(element: Element): SEpisode = throw UnsupportedOperationException()
// ============================ video links ============================
override fun videoListRequest(episode: SEpisode): Request {
val refererHeaders = headers.newBuilder().apply {
add("Referer", "$baseUrl/")
}.build()
return GET("$baseUrl/${episode.url}", headers = refererHeaders)
}
override fun videoListSelector() = "div.watch--servers--list ul li.server--item"
override fun videoListParse(response: Response): List<Video> {
val document = response.asJsoup()
return document.select(videoListSelector())
.parallelCatchingFlatMapBlocking(::extractVideos)
}
private fun extractVideos(element: Element): List<Video> {
val url = element.attr("data-link")
val txt = element.text()
return when {
"Main" in txt -> {
videosFromMain(url)
}
url.contains("ok") -> {
OkruExtractor(client).videosFromUrl(url)
}
"Vidbom" in txt || "Vidshare" in txt || "Govid" in txt -> {
VidBomExtractor(client).videosFromUrl(url)
}
"Doodstream" in txt -> {
DoodExtractor(client).videoFromUrl(url, "Dood mirror")?.let(::listOf)
}
url.contains("uqload") -> {
UqloadExtractor(client).videosFromUrl(url, "mirror")
}
url.contains("tape") -> {
StreamTapeExtractor(client).videoFromUrl(url)?.let(::listOf)
}
"Upstream" in txt || "Streamruby" in txt || "Streamwish" in txt -> {
videosFromOthers(url, txt)
}
else -> null
} ?: emptyList()
}
override fun List<Video>.sort(): List<Video> {
val quality = preferences.getString("preferred_quality", null)!!
return sortedWith(
compareBy { it.quality.contains(quality) },
).reversed()
}
override fun videoUrlParse(document: Document) = throw UnsupportedOperationException()
override fun videoFromElement(element: Element) = throw UnsupportedOperationException()
private fun videosFromMain(url: String): List<Video> {
val jsE = client.newCall(GET(url)).execute().asJsoup().selectFirst("script:containsData(player)")!!.data()
val fileLinks = JsUnpacker.unpackAndCombine(jsE)!!.substringAfter("file").substringBefore("\",")
return Regex("\\[(.*?)\\](.*?mp4)").findAll(fileLinks).map {
Video(it.groupValues[2], "Main: " + it.groupValues[1], it.groupValues[2])
}.toList()
}
private fun videosFromOthers(url: String, prefix: String): List<Video> {
val jsE = client.newCall(GET(url)).execute().asJsoup().selectFirst("script:containsData(source)")!!.data()
val masterUrl = JsUnpacker.unpackAndCombine(jsE)!!.substringAfter("file").substringAfter("\"").substringBefore("\"")
return PlaylistUtils(client).extractFromHls(masterUrl, url, videoNameGen = { "$prefix - $it" })
}
// ============================ search ============================
override fun searchAnimeSelector(): String = "div.Block--Item"
override fun searchAnimeNextPageSelector(): String = "div.pagination ul.page-numbers li a.next"
override fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList): Request {
val url = if (query.isNotBlank()) {
"$baseUrl/?s=$query&page=$page"
} else {
val url = baseUrl
(if (filters.isEmpty()) getFilterList() else filters).forEach { filter ->
when (filter) {
is CategoryList -> {
if (filter.state > 0) {
val catQ = getCategoryList()[filter.state].query
val catUrl = "$baseUrl/$catQ/?page=$page/"
return GET(catUrl, headers)
}
}
else -> {}
}
}
return GET(url, headers)
}
return GET(url, headers)
}
override fun searchAnimeFromElement(element: Element): SAnime {
val anime = SAnime.create()
anime.title = titleEdit(element.select("h3").text(), true).trim()
anime.thumbnail_url = element.select("img").attr(if (element.ownerDocument()!!.location().contains("?s="))"src" else "data-src")
anime.setUrlWithoutDomain(element.select("a").attr("href") + "watch/")
return anime
}
// ============================ details ============================
override fun animeDetailsParse(document: Document): SAnime {
val anime = SAnime.create()
anime.genre = document.select("div.catssection li a").joinToString(", ") { it.text() }
anime.title = titleEdit(document.select("h1.post-title").text()).trim()
anime.author = document.select("ul.RightTaxContent li:contains(دولة) a").text()
anime.description = document.select("div.story").text().trim()
anime.status = SAnime.COMPLETED
anime.thumbnail_url = document.select("div.left div.image img").attr("src")
return anime
}
// ============================ latest ============================
override fun latestUpdatesSelector(): String = "div.Block--Item"
override fun latestUpdatesNextPageSelector(): String = "div.pagination ul.page-numbers li a.next"
override fun latestUpdatesRequest(page: Int): Request = GET("$baseUrl/recent/page/$page/")
override fun latestUpdatesFromElement(element: Element): SAnime {
val anime = SAnime.create()
anime.title = titleEdit(element.select("a").attr("title"), true).trim()
anime.thumbnail_url = element.select("img").attr("data-src")
anime.setUrlWithoutDomain(element.select("a").attr("href") + "watch/")
return anime
}
// ============================ filters ============================
override fun getFilterList() = AnimeFilterList(
CategoryList(categoriesName),
)
private class CategoryList(categories: Array<String>) : AnimeFilter.Select<String>("الأقسام", categories)
private data class CatUnit(val name: String, val query: String)
private val categoriesName = getCategoryList().map {
it.name
}.toTypedArray()
private fun getCategoryList() = listOf(
CatUnit("اختر", ""),
CatUnit("كل الافلام", "category/movies-33/"),
CatUnit("افلام اجنبى", "category/movies-33/افلام-اجنبي/"),
CatUnit("افلام انمى", "category/anime-6/افلام-انمي/"),
CatUnit("افلام تركيه", "category/movies-33/افلام-تركي/"),
CatUnit("افلام اسيويه", "category/movies-33/افلام-اسيوي/"),
CatUnit("افلام هنديه", "category/movies-33/افلام-هندى/"),
CatUnit("كل المسسلسلات", "category/series-9/"),
CatUnit("مسلسلات اجنبى", "category/series-9/مسلسلات-اجنبي/"),
CatUnit("مسلسلات انمى", "category/anime-6/انمي-مترجم/"),
CatUnit("مسلسلات تركى", "category/series-9/مسلسلات-تركي/"),
CatUnit("مسلسلات اسيوى", "category/series-9/مسلسلات-أسيوي/"),
CatUnit("مسلسلات هندى", "category/series-9/مسلسلات-هندي/"),
)
override fun setupPreferenceScreen(screen: PreferenceScreen) {
val videoQualityPref = ListPreference(screen.context).apply {
key = "preferred_quality"
title = "Preferred quality"
entries = arrayOf("720p", "480p", "Low", "Normal", "HD", "UHD", "DoodStream", "Uqload")
entryValues = arrayOf("720", "480", "Low", "Normal", "HD", "UHD", "Dood", "Uqload")
setDefaultValue("1080")
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

@ -1,7 +0,0 @@
ext {
extName = 'XS Anime'
extClass = '.XsAnime'
extVersionCode = 10
}
apply from: "$rootDir/common.gradle"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

View file

@ -1,225 +0,0 @@
package eu.kanade.tachiyomi.animeextension.ar.xsanime
import android.app.Application
import android.content.SharedPreferences
import androidx.preference.ListPreference
import androidx.preference.PreferenceScreen
import eu.kanade.tachiyomi.animesource.ConfigurableAnimeSource
import eu.kanade.tachiyomi.animesource.model.AnimeFilter
import eu.kanade.tachiyomi.animesource.model.AnimeFilterList
import eu.kanade.tachiyomi.animesource.model.SAnime
import eu.kanade.tachiyomi.animesource.model.SEpisode
import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.animesource.online.ParsedAnimeHttpSource
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.util.asJsoup
import okhttp3.Headers
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
import okhttp3.Request
import okhttp3.Response
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
class XsAnime : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
override val name = "XS Anime"
override val baseUrl = "https://ww.xsanime.com"
override val lang = "ar"
override val supportsLatest = false
private val preferences: SharedPreferences by lazy {
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
}
// Popular Anime
override fun popularAnimeSelector(): String = "ul.boxes--holder div.itemtype_anime a"
override fun popularAnimeRequest(page: Int): Request = GET("$baseUrl/anime_list/page/$page")
override fun popularAnimeFromElement(element: Element): SAnime {
val anime = SAnime.create()
anime.setUrlWithoutDomain(element.attr("href"))
anime.title = element.attr("title")
anime.thumbnail_url = element.selectFirst("div.itemtype_anime_poster img")!!.attr("data-src")
return anime
}
override fun popularAnimeNextPageSelector(): String = "ul.page-numbers li a.next"
// Episodes
override fun episodeListSelector() = "div.EpisodesList > a"
override fun episodeFromElement(element: Element): SEpisode {
val episode = SEpisode.create()
val epNum = getNumberFromEpsString(element.select("a > em").text())
episode.setUrlWithoutDomain(element.attr("abs:href"))
episode.name = element.select("a > em").text()
episode.episode_number = when {
epNum.isNotEmpty() -> epNum.toFloatOrNull() ?: 1F
else -> 1F
}
return episode
}
private fun getNumberFromEpsString(epsStr: String): String {
return epsStr.filter { it.isDigit() }
}
// Video Links
override fun videoListParse(response: Response): List<Video> {
val document = response.asJsoup()
val srcVid = preferences.getString("preferred_quality", "الجودة العالية")!!
val iframe = document.select("div.downloads ul div.listServ:contains($srcVid) div.serL a[href~=4shared]").attr("href").substringBeforeLast("/").replace("video", "web/embed/file")
val referer = response.request.url.toString()
val refererHeaders = Headers.headersOf("referer", referer)
val iframeResponse = client.newCall(GET(iframe, refererHeaders))
.execute().asJsoup()
return iframeResponse.select(videoListSelector()).map { videoFromElement(it) }
}
override fun videoListSelector() = "source"
override fun videoFromElement(element: Element): Video {
element.attr("src")
return Video(element.attr("src"), "Default: If you want to change the quality go to extension settings", element.attr("src"))
}
override fun videoUrlParse(document: Document) = throw UnsupportedOperationException()
// Search
override fun searchAnimeFromElement(element: Element): SAnime {
val anime = SAnime.create()
anime.setUrlWithoutDomain(element.attr("href"))
anime.title = element.attr("title")
anime.thumbnail_url = element.selectFirst("div.itemtype_anime_poster img")!!.attr("data-src")
return anime
}
override fun searchAnimeNextPageSelector(): String = "ul.page-numbers li a.next"
override fun searchAnimeSelector(): String = "ul.boxes--holder div.itemtype_anime a"
override fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList): Request {
return if (query.isNotBlank()) {
GET("$baseUrl/?s=$query&type=anime&page=$page", headers)
} else {
val url = "$baseUrl/anime_list/page/$page/?".toHttpUrlOrNull()!!.newBuilder()
filters.forEach { filter ->
when (filter) {
// is SeasonFilter -> url.addQueryParameter("season", filter.toUriPart())
is GenreFilter -> url.addQueryParameter("genre", filter.toUriPart())
is StatusFilter -> url.addQueryParameter("status", filter.toUriPart())
// is LetterFilter -> url.addQueryParameter("letter", filter.toUriPart())
else -> {}
}
}
GET(url.build().toString(), headers)
}
}
// Anime Details
override fun animeDetailsParse(document: Document): SAnime {
val anime = SAnime.create()
anime.thumbnail_url = document.selectFirst("div.inner--image img")!!.attr("src")
anime.title = document.select("h1.post--inner-title").text()
anime.genre = document.select("ul.terms--and--metas > li:contains(تصنيفات الأنمي) > a").joinToString(", ") { it.text() }
anime.description = document.select("div.post--content--inner").text()
document.select("ul.terms--and--metas li:contains(عدد الحلقات) a").text()?.also { statusText ->
when {
statusText.contains("غير معروف", true) -> anime.status = SAnime.ONGOING
else -> anime.status = SAnime.COMPLETED
}
}
return anime
}
// Filters
override fun getFilterList() = AnimeFilterList(
AnimeFilter.Header("NOTE: Ignored if using text search!"),
AnimeFilter.Separator(),
GenreFilter(getGenreFilters()),
StatusFilter(getStatusFilters()),
// SeasonFilter(getStatusFilters()),
// LetterFilter(getLetterFilter()),
)
private class StatusFilter(vals: Array<Pair<String?, String>>) : UriPartFilter("حالة الأنمي", vals)
private class GenreFilter(vals: Array<Pair<String?, String>>) : UriPartFilter("تصنيفات الانمى", vals)
// private class SeasonFilter(vals: Array<Pair<String?, String>>) : UriPartFilter("موسم الانمى", vals)
// private class LetterFilter(vals: Array<Pair<String?, String>>) : UriPartFilter("الحرف", vals)
private fun getStatusFilters(): Array<Pair<String?, String>> = arrayOf(
Pair("", "<اختر>"),
Pair("مستمر", "مستمر"),
Pair("منتهي", "منتهي"),
)
private fun getGenreFilters(): Array<Pair<String?, String>> = arrayOf(
Pair("", "<اختر>"),
Pair("أكشن", "أكشن"),
Pair("تاريخي", "تاريخي"),
Pair("حريم", "حريم"),
Pair("خارق للطبيعة", "خارق للطبيعة"),
Pair("خيال", "خيال"),
Pair("دراما", "دراما"),
Pair("رومانسي", "رومانسي"),
Pair("رياضي", "رياضي"),
Pair("سينين", "سينين"),
Pair("شونين", "شونين"),
Pair("شياطين", "شياطين"),
Pair("غموض", "غموض"),
Pair("قوى خارقة", "قوى خارقة"),
Pair("كوميدي", "كوميدي"),
Pair("لعبة", "لعبة"),
Pair("مدرسي", "مدرسي"),
Pair("مغامرات", "مغامرات"),
Pair("موسيقي", "موسيقي"),
Pair("نفسي", "نفسي"),
)
open class UriPartFilter(displayName: String, private val vals: Array<Pair<String?, String>>) :
AnimeFilter.Select<String>(displayName, vals.map { it.second }.toTypedArray()) {
fun toUriPart() = vals[state].first
}
// Latest
override fun latestUpdatesNextPageSelector(): String? = throw UnsupportedOperationException()
override fun latestUpdatesFromElement(element: Element): SAnime = throw UnsupportedOperationException()
override fun latestUpdatesRequest(page: Int): Request = throw UnsupportedOperationException()
override fun latestUpdatesSelector(): String = throw UnsupportedOperationException()
// Preferences
override fun setupPreferenceScreen(screen: PreferenceScreen) {
val qualityPref = ListPreference(screen.context).apply {
key = "preferred_quality"
title = "Preferred Quality"
entries = arrayOf("الجودة العالية", "الجودة الخارقة", "الجودة المتوسطة")
entryValues = arrayOf("الجودة العالية", "الجودة الخارقة", "الجودة المتوسطة")
setDefaultValue("الجودة العالية")
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(qualityPref)
}
}

View file

@ -1,7 +0,0 @@
ext {
extName = 'XS Movie'
extClass = '.XsMovie'
extVersionCode = 5
}
apply from: "$rootDir/common.gradle"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

View file

@ -1,149 +0,0 @@
package eu.kanade.tachiyomi.animeextension.ar.xsmovie
import android.app.Application
import android.content.SharedPreferences
import androidx.preference.ListPreference
import androidx.preference.PreferenceScreen
import eu.kanade.tachiyomi.animesource.ConfigurableAnimeSource
import eu.kanade.tachiyomi.animesource.model.AnimeFilterList
import eu.kanade.tachiyomi.animesource.model.SAnime
import eu.kanade.tachiyomi.animesource.model.SEpisode
import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.animesource.online.ParsedAnimeHttpSource
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.util.asJsoup
import okhttp3.Headers
import okhttp3.Request
import okhttp3.Response
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
class XsMovie : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
override val name = "XS Movie"
override val baseUrl = "https://ww.xsanime.com"
override val lang = "ar"
override val supportsLatest = false
private val preferences: SharedPreferences by lazy {
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
}
// Popular Anime
override fun popularAnimeSelector(): String = "ul.boxes--holder div.itemtype_anime a"
override fun popularAnimeRequest(page: Int): Request = GET("$baseUrl/movies_list/page/$page")
override fun popularAnimeFromElement(element: Element): SAnime {
val anime = SAnime.create()
anime.setUrlWithoutDomain(element.attr("href"))
anime.title = element.attr("title")
anime.thumbnail_url = element.selectFirst("div.itemtype_anime_poster img")!!.attr("data-src")
return anime
}
override fun popularAnimeNextPageSelector(): String = "ul.page-numbers li a.next"
// Episodes
override fun episodeListSelector() = "h1.post--inner-title > a"
override fun episodeFromElement(element: Element): SEpisode {
val episode = SEpisode.create()
episode.setUrlWithoutDomain(element.attr("href"))
episode.name = element.text().replace("فيلم ", "").replace("مترجم ", "").replace("اون لاين ", "").replace("بلوراي", "") // "movie"
return episode
}
// Video Links
override fun videoListParse(response: Response): List<Video> {
val document = response.asJsoup()
val srcVid = preferences.getString("preferred_quality", "الجودة العالية")!!
val iframe = document.select("div.downloads ul div.listServ:contains($srcVid) div.serL a[href~=4shared]").attr("href").substringBeforeLast("/").replace("video", "web/embed/file")
val referer = response.request.url.toString()
val refererHeaders = Headers.headersOf("referer", referer)
val iframeResponse = client.newCall(GET(iframe, refererHeaders))
.execute().asJsoup()
return iframeResponse.select(videoListSelector()).map { videoFromElement(it) }
}
override fun videoListSelector() = "source"
override fun videoFromElement(element: Element): Video {
return Video(element.attr("src"), "Default: If you want to change the quality go to extension settings", element.attr("src"))
}
override fun videoUrlParse(document: Document) = throw UnsupportedOperationException()
// Search
override fun searchAnimeFromElement(element: Element): SAnime {
val anime = SAnime.create()
anime.setUrlWithoutDomain(element.attr("href"))
anime.title = element.attr("title")
anime.thumbnail_url = element.selectFirst("div.itemtype_anime_poster img")!!.attr("data-src")
return anime
}
override fun searchAnimeNextPageSelector(): String = "ul.page-numbers li a.next"
override fun searchAnimeSelector(): String = "ul.boxes--holder div.itemtype_anime a"
override fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList): Request {
return GET("$baseUrl/?s=$query&type=movie&page=$page", headers)
}
// Anime Details
override fun animeDetailsParse(document: Document): SAnime {
val anime = SAnime.create()
anime.thumbnail_url = document.selectFirst("div.inner--image img")!!.attr("src")
anime.title = document.select("h1.post--inner-title").text()
anime.genre = document.select("ul.terms--and--metas > li:contains(تصنيفات الأنمي) > a").joinToString(", ") { it.text() }
anime.description = document.select("div.post--content--inner").text()
document.select("ul.terms--and--metas li:contains(عدد الحلقات) a").text()?.also { statusText ->
when {
statusText.contains("غير معروف", true) -> anime.status = SAnime.ONGOING
else -> anime.status = SAnime.COMPLETED
}
}
return anime
}
// Latest
override fun latestUpdatesNextPageSelector(): String? = throw UnsupportedOperationException()
override fun latestUpdatesFromElement(element: Element): SAnime = throw UnsupportedOperationException()
override fun latestUpdatesRequest(page: Int): Request = throw UnsupportedOperationException()
override fun latestUpdatesSelector(): String = throw UnsupportedOperationException()
// Preferences
override fun setupPreferenceScreen(screen: PreferenceScreen) {
val qualityPref = ListPreference(screen.context).apply {
key = "preferred_quality"
title = "Preferred Quality"
entries = arrayOf("الجودة العالية", "الجودة الخارقة", "الجودة المتوسطة")
entryValues = arrayOf("الجودة العالية", "الجودة الخارقة", "الجودة المتوسطة")
setDefaultValue("الجودة العالية")
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(qualityPref)
}
}

View file

@ -1,16 +0,0 @@
ext {
extName = 'CineClix'
extClass = '.CineClix'
extVersionCode = 18
}
apply from: "$rootDir/common.gradle"
dependencies {
implementation(project(':lib:streamtape-extractor'))
implementation(project(':lib:mixdrop-extractor'))
implementation(project(':lib:dood-extractor'))
implementation(project(':lib:voe-extractor'))
implementation(project(':lib:playlist-utils'))
implementation(libs.jsunpacker)
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.2 KiB

View file

@ -1,364 +0,0 @@
package eu.kanade.tachiyomi.animeextension.de.cineclix
import android.app.Application
import android.content.SharedPreferences
import androidx.preference.ListPreference
import androidx.preference.MultiSelectListPreference
import androidx.preference.PreferenceScreen
import eu.kanade.tachiyomi.animeextension.de.cineclix.extractors.StreamVidExtractor
import eu.kanade.tachiyomi.animeextension.de.cineclix.extractors.SuperVideoExtractor
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.doodextractor.DoodExtractor
import eu.kanade.tachiyomi.lib.mixdropextractor.MixDropExtractor
import eu.kanade.tachiyomi.lib.streamtapeextractor.StreamTapeExtractor
import eu.kanade.tachiyomi.lib.voeextractor.VoeExtractor
import eu.kanade.tachiyomi.network.GET
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.int
import kotlinx.serialization.json.jsonArray
import kotlinx.serialization.json.jsonObject
import kotlinx.serialization.json.jsonPrimitive
import okhttp3.Headers
import okhttp3.Request
import okhttp3.Response
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
class CineClix : ConfigurableAnimeSource, AnimeHttpSource() {
override val name = "CineClix"
override val baseUrl = "https://cineclix.de"
override val lang = "de"
override val supportsLatest = false
private val preferences: SharedPreferences by lazy {
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
}
private val json = Json {
isLenient = true
ignoreUnknownKeys = true
}
override fun popularAnimeRequest(page: Int): Request = GET(
"$baseUrl/api/v1/channel/64?returnContentOnly=true&restriction=&order=rating:desc&paginate=simple&perPage=50&query=&page=$page",
headers = Headers.headersOf("referer", "$baseUrl/movies?order=rating%3Adesc"),
)
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 jObject = json.decodeFromString<JsonObject>(jsonData)
val jO = jObject.jsonObject["pagination"]!!.jsonObject
val nextPage = jO.jsonObject["next_page"]!!.jsonPrimitive.int
// .substringAfter("page=").toInt()
val page = jO.jsonObject["current_page"]!!.jsonPrimitive.int
val hasNextPage = page < nextPage
val array = jO["data"]!!.jsonArray
val animeList = mutableListOf<SAnime>()
for (item in array) {
val anime = SAnime.create()
anime.title = item.jsonObject["name"]!!.jsonPrimitive.content
val animeId = item.jsonObject["id"]!!.jsonPrimitive.content
anime.setUrlWithoutDomain("$baseUrl/api/v1/titles/$animeId?load=images,genres,productionCountries,keywords,videos,primaryVideo,seasons,compactCredits")
anime.thumbnail_url = item.jsonObject["poster"]?.jsonPrimitive?.content ?: item.jsonObject["backdrop"]?.jsonPrimitive?.content
animeList.add(anime)
}
return AnimesPage(animeList, hasNextPage)
}
// episodes
override fun episodeListRequest(anime: SAnime): Request = GET(baseUrl + anime.url, headers = Headers.headersOf("referer", baseUrl))
override fun episodeListParse(response: Response): List<SEpisode> {
val responseString = response.body.string()
val url = response.request.url.toString()
return parseEpisodeAnimeJson(responseString, url)
}
private fun parseEpisodeAnimeJson(jsonLine: String?, url: String): List<SEpisode> {
val jsonData = jsonLine ?: return emptyList()
val jObject = json.decodeFromString<JsonObject>(jsonData)
val episodeList = mutableListOf<SEpisode>()
val mId = jObject.jsonObject["title"]!!.jsonObject["id"]!!.jsonPrimitive.content
val season = jObject.jsonObject["seasons"]?.jsonObject
if (season != null) {
val dataArray = season.jsonObject["data"]!!.jsonArray
val next = season.jsonObject["next_page"]?.jsonPrimitive?.content
if (next != null) {
val seNextJsonData = client.newCall(GET("$baseUrl/api/v1/titles/$mId/seasons?perPage=8&query=&page=$next", headers = Headers.headersOf("referer", baseUrl))).execute().body.string()
val seNextJObject = json.decodeFromString<JsonObject>(seNextJsonData)
val seasonNext = seNextJObject.jsonObject["pagination"]!!.jsonObject
val dataNextArray = seasonNext.jsonObject["data"]!!.jsonArray
val dataAllArray = dataArray.plus(dataNextArray)
for (item in dataAllArray) {
val id = item.jsonObject["title_id"]!!.jsonPrimitive.content
val num = item.jsonObject["number"]!!.jsonPrimitive.content
val seUrl = "$baseUrl/api/v1/titles/$id/seasons/$num?load=episodes,primaryVideo"
val seJsonData = client.newCall(GET(seUrl, headers = Headers.headersOf("referer", baseUrl))).execute().body.string()
val seJObject = json.decodeFromString<JsonObject>(seJsonData)
val epObject = seJObject.jsonObject["episodes"]!!.jsonObject
val epDataArray = epObject.jsonObject["data"]!!.jsonArray.reversed()
for (epItem in epDataArray) {
val episode = SEpisode.create()
val seNum = epItem.jsonObject["season_number"]!!.jsonPrimitive.content
val epNum = epItem.jsonObject["episode_number"]!!.jsonPrimitive.content
episode.name = "Staffel $seNum Folge $epNum : " + epItem.jsonObject["name"]!!.jsonPrimitive.content
episode.episode_number = epNum.toFloat()
val epId = epItem.jsonObject["title_id"]!!.jsonPrimitive.content
episode.setUrlWithoutDomain("$baseUrl/api/v1/titles/$epId/seasons/$seNum/episodes/$epNum?load=videos,compactCredits,primaryVideo")
episodeList.add(episode)
}
}
} else {
for (item in dataArray) {
val id = item.jsonObject["title_id"]!!.jsonPrimitive.content
val num = item.jsonObject["number"]!!.jsonPrimitive.content
val seUrl = "$baseUrl/api/v1/titles/$id/seasons/$num?load=episodes,primaryVideo"
val seJsonData = client.newCall(GET(seUrl, headers = Headers.headersOf("referer", baseUrl))).execute().body.string()
val seJObject = json.decodeFromString<JsonObject>(seJsonData)
val epObject = seJObject.jsonObject["episodes"]!!.jsonObject
val epDataArray = epObject.jsonObject["data"]!!.jsonArray.reversed()
for (epItem in epDataArray) {
val episode = SEpisode.create()
val seNum = epItem.jsonObject["season_number"]!!.jsonPrimitive.content
val epNum = epItem.jsonObject["episode_number"]!!.jsonPrimitive.content
episode.name = "Staffel $seNum Folge $epNum : " + epItem.jsonObject["name"]!!.jsonPrimitive.content
episode.episode_number = epNum.toFloat()
val epId = epItem.jsonObject["title_id"]!!.jsonPrimitive.content
episode.setUrlWithoutDomain("$baseUrl/api/v1/titles/$epId/seasons/$seNum/episodes/$epNum?load=videos,compactCredits,primaryVideo")
episodeList.add(episode)
}
}
}
} else {
val episode = SEpisode.create()
episode.episode_number = 1F
episode.name = "Film"
episode.setUrlWithoutDomain(url)
episodeList.add(episode)
}
return episodeList
}
// Video Extractor
override fun videoListRequest(episode: SEpisode): Request {
return GET(baseUrl + episode.url, headers = Headers.headersOf("referer", baseUrl))
}
override fun videoListParse(response: Response): List<Video> {
val responseString = response.body.string()
val url = response.request.url.toString()
return videosFromJson(responseString, url)
}
private fun videosFromJson(jsonLine: String?, url: String): List<Video> {
val videoList = mutableListOf<Video>()
val hosterSelection = preferences.getStringSet("hoster_selection", setOf("stape", "supv", "mix", "svid", "dood", "voe"))
val jsonData = jsonLine ?: return emptyList()
val jObject = json.decodeFromString<JsonObject>(jsonData)
if (url.contains("episodes")) {
val epObject = jObject.jsonObject["episode"]!!.jsonObject
val videoArray = epObject.jsonObject["videos"]!!.jsonArray
for (item in videoArray) {
val host = item.jsonObject["name"]!!.jsonPrimitive.content
val eUrl = item.jsonObject["src"]!!.jsonPrimitive.content
when {
host.contains("streamtape") && hosterSelection?.contains("stape") == true -> {
val quality = "Streamtape"
val video = StreamTapeExtractor(client).videoFromUrl(eUrl, quality)
if (video != null) {
videoList.add(video)
}
}
host.contains("supervideo") && hosterSelection?.contains("supv") == true -> {
val video = SuperVideoExtractor(client).videosFromUrl(eUrl)
videoList.addAll(video)
}
host.contains("mixdrop") && hosterSelection?.contains("mix") == true -> {
val video = MixDropExtractor(client).videoFromUrl(eUrl)
videoList.addAll(video)
}
host.contains("streamvid") && hosterSelection?.contains("svid") == true -> {
val video = StreamVidExtractor(client).videosFromUrl(eUrl)
videoList.addAll(video)
}
host.contains("DoodStream") && hosterSelection?.contains("dood") == true -> {
val video = DoodExtractor(client).videoFromUrl(eUrl)
if (video != null) {
videoList.add(video)
}
}
host.contains("VOE.SX") && hosterSelection?.contains("voe") == true -> {
videoList.addAll(VoeExtractor(client).videosFromUrl(eUrl))
}
}
}
} else {
val titleObject = jObject.jsonObject["title"]!!.jsonObject
val videoArray = titleObject.jsonObject["videos"]!!.jsonArray
for (item in videoArray) {
val host = item.jsonObject["name"]!!.jsonPrimitive.content
val fUrl = item.jsonObject["src"]!!.jsonPrimitive.content
when {
host.contains("streamtape") && hosterSelection?.contains("stape") == true -> {
val quality = "Streamtape"
val video = StreamTapeExtractor(client).videoFromUrl(fUrl, quality)
if (video != null) {
videoList.add(video)
}
}
host.contains("supervideo") && hosterSelection?.contains("supv") == true -> {
val video = SuperVideoExtractor(client).videosFromUrl(fUrl)
videoList.addAll(video)
}
host.contains("mixdrop") && hosterSelection?.contains("mix") == true -> {
val video = MixDropExtractor(client).videoFromUrl(fUrl)
videoList.addAll(video)
}
host.contains("streamvid") && hosterSelection?.contains("svid") == true -> {
val video = StreamVidExtractor(client).videosFromUrl(fUrl)
videoList.addAll(video)
}
host.contains("DoodStream") && hosterSelection?.contains("dood") == true -> {
val video = DoodExtractor(client).videoFromUrl(fUrl)
if (video != null) {
videoList.add(video)
}
}
host.contains("VOE.SX") && hosterSelection?.contains("voe") == true -> {
videoList.addAll(VoeExtractor(client).videosFromUrl(fUrl))
}
}
}
}
return videoList
}
override fun List<Video>.sort(): List<Video> {
val hoster = preferences.getString("preferred_hoster", null)
if (hoster != null) {
val newList = mutableListOf<Video>()
var preferred = 0
for (video in this) {
if (video.quality.contains(hoster)) {
newList.add(preferred, video)
preferred++
} else {
newList.add(video)
}
}
return newList
}
return this
}
// Search
override fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList): Request = GET(
"$baseUrl/api/v1/search/$query?query=$query",
headers = Headers.headersOf("referer", "$baseUrl/search/$query"),
)
override fun searchAnimeParse(response: Response): AnimesPage {
val responseString = response.body.string()
return parseSearchAnimeJson(responseString)
}
private fun parseSearchAnimeJson(jsonLine: String?): AnimesPage {
val jsonData = jsonLine ?: return AnimesPage(emptyList(), false)
val jObject = json.decodeFromString<JsonObject>(jsonData)
val array = jObject["results"]!!.jsonArray
val animeList = mutableListOf<SAnime>()
for (item in array) {
val anime = SAnime.create()
anime.title = item.jsonObject["name"]!!.jsonPrimitive.content
val animeId = item.jsonObject["id"]!!.jsonPrimitive.content
anime.setUrlWithoutDomain("$baseUrl/api/v1/titles/$animeId?load=images,genres,productionCountries,keywords,videos,primaryVideo,seasons,compactCredits")
anime.thumbnail_url = item.jsonObject["poster"]?.jsonPrimitive?.content ?: item.jsonObject["backdrop"]?.jsonPrimitive?.content
animeList.add(anime)
}
return AnimesPage(animeList, hasNextPage = false)
}
// Details
override fun animeDetailsRequest(anime: SAnime): Request = GET(baseUrl + anime.url, headers = Headers.headersOf("referer", baseUrl))
override fun animeDetailsParse(response: Response): SAnime {
val responseString = response.body.string()
return parseAnimeDetailsParseJson(responseString)
}
private fun parseAnimeDetailsParseJson(jsonLine: String?): SAnime {
val anime = SAnime.create()
val jsonData = jsonLine ?: return anime
val jObject = json.decodeFromString<JsonObject>(jsonData)
val jO = jObject.jsonObject["title"]!!.jsonObject
anime.title = jO.jsonObject["name"]!!.jsonPrimitive.content
anime.description = jO.jsonObject["description"]!!.jsonPrimitive.content
val genArray = jO.jsonObject["genres"]!!.jsonArray
val genres = mutableListOf<String>()
for (item in genArray) {
val genre = item.jsonObject["display_name"]!!.jsonPrimitive.content
genres.add(genre)
}
anime.genre = genres.joinToString { it }
anime.thumbnail_url = jO.jsonObject["poster"]?.jsonPrimitive?.content ?: jO.jsonObject["backdrop"]?.jsonPrimitive?.content
return anime
}
// Latest
override fun latestUpdatesParse(response: Response): AnimesPage = throw UnsupportedOperationException()
override fun latestUpdatesRequest(page: Int): Request = throw UnsupportedOperationException()
// Preferences
override fun setupPreferenceScreen(screen: PreferenceScreen) {
val hosterPref = ListPreference(screen.context).apply {
key = "preferred_hoster"
title = "Standard-Hoster"
entries = arrayOf("Streamtape", "SuperVideo", "MixDrop", "StreamVid", "DoodStream", "Voe")
entryValues = arrayOf("https://streamtape", "https://supervideo", "https://mixdrop", "https://streamvid", "https://dood", "https://voe")
setDefaultValue("https://streamtape")
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()
}
}
val subSelection = MultiSelectListPreference(screen.context).apply {
key = "hoster_selection"
title = "Hoster auswählen"
entries = arrayOf("Streamtape", "SuperVideo", "MixDrop", "StreamVid", "DoodStream", "Voe")
entryValues = arrayOf("stape", "supv", "mix", "svid", "dood", "voe")
setDefaultValue(setOf("stape", "supv", "mix", "svid", "dood", "voe"))
setOnPreferenceChangeListener { _, newValue ->
preferences.edit().putStringSet(key, newValue as Set<String>).commit()
}
}
screen.addPreference(hosterPref)
screen.addPreference(subSelection)
}
}

View file

@ -1,22 +0,0 @@
package eu.kanade.tachiyomi.animeextension.de.cineclix.extractors
import dev.datlag.jsunpacker.JsUnpacker
import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.lib.playlistutils.PlaylistUtils
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.util.asJsoup
import okhttp3.OkHttpClient
class StreamVidExtractor(private val client: OkHttpClient) {
fun videosFromUrl(url: String, prefix: String = ""): List<Video> {
return runCatching {
val doc = client.newCall(GET(url)).execute().asJsoup()
val script = doc.selectFirst("script:containsData(eval):containsData(p,a,c,k,e,d)")?.data()
?.let(JsUnpacker::unpackAndCombine)
?: return emptyList()
val masterUrl = script.substringAfter("sources:[{src:\"").substringBefore("\",")
PlaylistUtils(client).extractFromHls(masterUrl, videoNameGen = { "${prefix}StreamVid - $it" })
}.getOrElse { emptyList() }
}
}

View file

@ -1,22 +0,0 @@
package eu.kanade.tachiyomi.animeextension.de.cineclix.extractors
import dev.datlag.jsunpacker.JsUnpacker
import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.lib.playlistutils.PlaylistUtils
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.util.asJsoup
import okhttp3.OkHttpClient
class SuperVideoExtractor(private val client: OkHttpClient) {
fun videosFromUrl(url: String, prefix: String = ""): List<Video> {
return runCatching {
val doc = client.newCall(GET(url)).execute().asJsoup()
val script = doc.selectFirst("script:containsData(eval):containsData(p,a,c,k,e,d)")?.data()
?.let(JsUnpacker::unpackAndCombine)
?: return emptyList()
val masterUrl = script.substringAfter("sources:[{file:\"").substringBefore("\"}]")
PlaylistUtils(client).extractFromHls(masterUrl, videoNameGen = { "${prefix}SuperVideo - $it" })
}.getOrElse { emptyList() }
}
}

View file

@ -1,14 +0,0 @@
ext {
extName = 'Movie2k'
extClass = '.Movie2k'
extVersionCode = 8
}
apply from: "$rootDir/common.gradle"
dependencies {
implementation(project(':lib:dood-extractor'))
implementation(project(':lib:streamtape-extractor'))
implementation(project(':lib:mixdrop-extractor'))
implementation(libs.jsunpacker)
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.1 KiB

View file

@ -1,259 +0,0 @@
package eu.kanade.tachiyomi.animeextension.de.movie2k
import android.app.Application
import android.content.SharedPreferences
import androidx.preference.ListPreference
import androidx.preference.MultiSelectListPreference
import androidx.preference.PreferenceScreen
import eu.kanade.tachiyomi.animeextension.de.movie2k.extractors.DroploadExtractor
import eu.kanade.tachiyomi.animeextension.de.movie2k.extractors.UpstreamExtractor
import eu.kanade.tachiyomi.animesource.ConfigurableAnimeSource
import eu.kanade.tachiyomi.animesource.model.AnimeFilterList
import eu.kanade.tachiyomi.animesource.model.SAnime
import eu.kanade.tachiyomi.animesource.model.SEpisode
import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.animesource.online.ParsedAnimeHttpSource
import eu.kanade.tachiyomi.lib.doodextractor.DoodExtractor
import eu.kanade.tachiyomi.lib.mixdropextractor.MixDropExtractor
import eu.kanade.tachiyomi.lib.streamtapeextractor.StreamTapeExtractor
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.util.asJsoup
import okhttp3.Request
import okhttp3.Response
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
class Movie2k : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
override val name = "Movie2k"
override val baseUrl = "https://movie2k.skin"
override val lang = "de"
override val supportsLatest = false
private val preferences: SharedPreferences by lazy {
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
}
override fun popularAnimeSelector(): String = "div.item-container div.item"
override fun popularAnimeRequest(page: Int): Request = GET("$baseUrl/page/$page/")
override fun popularAnimeFromElement(element: Element): SAnime {
val anime = SAnime.create()
anime.setUrlWithoutDomain(element.select("a").attr("href"))
anime.thumbnail_url = element.select("a div.item-inner img").attr("data-src")
anime.title = element.select("a div.item-inner img").attr("alt")
return anime
}
override fun popularAnimeNextPageSelector(): String = "div.pagination a.next"
// episodes
override fun episodeListSelector() = throw UnsupportedOperationException()
override fun episodeListParse(response: Response): List<SEpisode> {
val document = response.asJsoup()
val episodeList = mutableListOf<SEpisode>()
val episode = SEpisode.create()
episode.episode_number = 1F
episode.name = "Film"
val hostdoc = client.newCall(GET(document.select("#multiplayer a").attr("href"))).execute().asJsoup()
episode.url = hostdoc.select("#video-container div.server1 iframe").attr("src")
episodeList.add(episode)
return episodeList.reversed()
}
override fun episodeFromElement(element: Element): SEpisode = throw UnsupportedOperationException()
// Video Extractor
override fun videoListRequest(episode: SEpisode): Request {
return GET(episode.url.replace(baseUrl, ""))
}
override fun videoListParse(response: Response): List<Video> {
val document = response.asJsoup()
return videosFromElement(document)
}
private fun videosFromElement(document: Document): List<Video> {
val videoList = mutableListOf<Video>()
val hosterSelection = preferences.getStringSet("hoster_selection", setOf("dood", "stape", "mix", "up", "drop"))
document.select("ul._player-mirrors li").forEach {
val purl = it.attr("data-link")
when {
purl.contains("//dood") && hosterSelection?.contains("dood") == true -> {
val quality = "Doodstream"
if (!purl.contains("https://")) {
val url = "https:$purl"
val video = DoodExtractor(client).videoFromUrl(url, quality)
if (video != null) {
videoList.add(video)
}
} else {
val video = DoodExtractor(client).videoFromUrl(purl, quality)
if (video != null) {
videoList.add(video)
}
}
}
purl.contains("//streamtape.com") && hosterSelection?.contains("stape") == true -> {
val quality = "Streamtape"
if (!purl.contains("https://")) {
val url = "https:$purl"
val video = StreamTapeExtractor(client).videoFromUrl(url, quality)
if (video != null) {
videoList.add(video)
}
} else {
val video = StreamTapeExtractor(client).videoFromUrl(purl, quality)
if (video != null) {
videoList.add(video)
}
}
}
purl.contains("//mixdrop") && hosterSelection?.contains("mix") == true -> {
if (!purl.contains("https://")) {
val url = "https:$purl"
val videos = MixDropExtractor(client).videoFromUrl(url)
videoList.addAll(videos)
} else {
val videos = MixDropExtractor(client).videoFromUrl(purl)
videoList.addAll(videos)
}
}
purl.contains("//upstream") && hosterSelection?.contains("up") == true -> {
if (!purl.contains("https://")) {
val url = "https:$purl"
val videos = UpstreamExtractor(client).videoFromUrl(url)
if (videos != null) {
videoList.addAll(videos)
}
} else {
val videos = UpstreamExtractor(client).videoFromUrl(purl)
if (videos != null) {
videoList.addAll(videos)
}
}
}
purl.contains("//dropload") && hosterSelection?.contains("drop") == true -> {
if (!purl.contains("https://")) {
val url = "https:$purl"
val videos = DroploadExtractor(client).videoFromUrl(url)
if (videos != null) {
videoList.addAll(videos)
}
} else {
val videos = DroploadExtractor(client).videoFromUrl(purl)
if (videos != null) {
videoList.addAll(videos)
}
}
}
}
}
return videoList
}
override fun List<Video>.sort(): List<Video> {
val hoster = preferences.getString("preferred_hoster", null)
if (hoster != null) {
val newList = mutableListOf<Video>()
var preferred = 0
for (video in this) {
if (video.quality.contains(hoster)) {
newList.add(preferred, video)
preferred++
} else {
newList.add(video)
}
}
return newList
}
return this
}
override fun videoListSelector() = throw UnsupportedOperationException()
override fun videoFromElement(element: Element) = throw UnsupportedOperationException()
override fun videoUrlParse(document: Document) = throw UnsupportedOperationException()
// Search
override fun searchAnimeFromElement(element: Element): SAnime {
val anime = SAnime.create()
anime.setUrlWithoutDomain(element.select("a").attr("href"))
anime.thumbnail_url = element.select("a div.item-inner img").attr("data-src")
anime.title = element.select("a div.item-inner img").attr("alt")
return anime
}
override fun searchAnimeNextPageSelector(): String = "div.pagination a.next"
override fun searchAnimeSelector(): String = "div.item-container div.item"
override fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList): Request = GET("$baseUrl/page/$page/?s=$query")
// Details
override fun animeDetailsParse(document: Document): SAnime {
val anime = SAnime.create()
anime.thumbnail_url = document.select("div.movie-image img").attr("src")
anime.title = document.select("div.movie-image img").attr("alt")
anime.description = document.select("p.movie-description span").text()
anime.author = document.select("span[itemprop=\"director\"] a").joinToString(", ") { it.text() }
anime.genre = document.select("span[itemprop=\"genre\"] a").joinToString(", ") { it.text() }
anime.status = SAnime.COMPLETED
return anime
}
// Latest
override fun latestUpdatesNextPageSelector(): String = throw UnsupportedOperationException()
override fun latestUpdatesFromElement(element: Element): SAnime = throw UnsupportedOperationException()
override fun latestUpdatesRequest(page: Int): Request = throw UnsupportedOperationException()
override fun latestUpdatesSelector(): String = throw UnsupportedOperationException()
// Preferences
override fun setupPreferenceScreen(screen: PreferenceScreen) {
val hosterPref = ListPreference(screen.context).apply {
key = "preferred_hoster"
title = "Standard-Hoster"
entries = arrayOf("Doodstream", "Streamtape", "Mixdrop", "Upstream", "Dropload")
entryValues = arrayOf("https://dood", "https://streamtape", "https://mixdrop", "https://upstream", "https://dropload")
setDefaultValue("https://dood")
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()
}
}
val subSelection = MultiSelectListPreference(screen.context).apply {
key = "hoster_selection"
title = "Hoster auswählen"
entries = arrayOf("Doodstream", "Streamtape", "MixDrop", "Upstream", "Dropload")
entryValues = arrayOf("dood", "stape", "mix", "up", "drop")
setDefaultValue(setOf("dood", "stape", "mix", "up", "drop"))
setOnPreferenceChangeListener { _, newValue ->
preferences.edit().putStringSet(key, newValue as Set<String>).commit()
}
}
screen.addPreference(hosterPref)
screen.addPreference(subSelection)
}
}

View file

@ -1,31 +0,0 @@
package eu.kanade.tachiyomi.animeextension.de.movie2k.extractors
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 DroploadExtractor(private val client: OkHttpClient) {
fun videoFromUrl(url: String): MutableList<Video>? {
try {
val jsE = client.newCall(GET(url)).execute().asJsoup().selectFirst("script:containsData(eval)")!!.data()
val masterUrl = JsUnpacker.unpackAndCombine(jsE).toString()
.substringAfter("{file:\"").substringBefore("\"}")
val masterBase = masterUrl.substringBefore("master")
val masterPlaylist = client.newCall(GET(masterUrl)).execute().body.string()
val videoList = mutableListOf<Video>()
masterPlaylist.substringAfter("#EXT-X-STREAM-INF:").split("#EXT-X-STREAM-INF:")
.forEach {
val quality = "Dropload:" + it.substringAfter("RESOLUTION=").substringAfter("x").substringBefore(",") + "p "
val videoUrl = masterBase + it.substringAfter("\n").substringBefore("\n")
videoList.add(Video(videoUrl, quality, videoUrl, headers = Headers.headersOf("origin", "https://dropload.io", "referer", "https://dropload.io/")))
}
return videoList
} catch (e: Exception) {
return null
}
}
}

View file

@ -1,31 +0,0 @@
package eu.kanade.tachiyomi.animeextension.de.movie2k.extractors
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 UpstreamExtractor(private val client: OkHttpClient) {
fun videoFromUrl(url: String): MutableList<Video>? {
try {
val jsE = client.newCall(GET(url)).execute().asJsoup().selectFirst("script:containsData(eval)")!!.data()
val masterUrl = JsUnpacker.unpackAndCombine(jsE).toString()
.substringAfter("{file:\"").substringBefore("\"}")
val masterBase = masterUrl.substringBefore("master")
val masterPlaylist = client.newCall(GET(masterUrl)).execute().body.string()
val videoList = mutableListOf<Video>()
masterPlaylist.substringAfter("#EXT-X-STREAM-INF:").split("#EXT-X-STREAM-INF:")
.forEach {
val quality = "Upstream:" + it.substringAfter("RESOLUTION=").substringAfter("x").substringBefore(",") + "p "
val videoUrl = masterBase + it.substringAfter("\n").substringBefore("\n")
videoList.add(Video(videoUrl, quality, videoUrl, headers = Headers.headersOf("origin", "https://upstream.to", "referer", "https://upstream.to/")))
}
return videoList
} catch (e: Exception) {
return null
}
}
}

View file

@ -1,13 +0,0 @@
ext {
extName = 'StreamCloud'
extClass = '.StreamCloud'
extVersionCode = 10
}
apply from: "$rootDir/common.gradle"
dependencies {
implementation(project(':lib:dood-extractor'))
implementation(project(':lib:streamtape-extractor'))
implementation(project(':lib:mixdrop-extractor'))
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

View file

@ -1,198 +0,0 @@
package eu.kanade.tachiyomi.animeextension.de.streamcloud
import android.app.Application
import androidx.preference.ListPreference
import androidx.preference.MultiSelectListPreference
import androidx.preference.PreferenceScreen
import eu.kanade.tachiyomi.animesource.ConfigurableAnimeSource
import eu.kanade.tachiyomi.animesource.model.AnimeFilterList
import eu.kanade.tachiyomi.animesource.model.SAnime
import eu.kanade.tachiyomi.animesource.model.SEpisode
import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.animesource.online.ParsedAnimeHttpSource
import eu.kanade.tachiyomi.lib.doodextractor.DoodExtractor
import eu.kanade.tachiyomi.lib.mixdropextractor.MixDropExtractor
import eu.kanade.tachiyomi.lib.streamtapeextractor.StreamTapeExtractor
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.util.asJsoup
import okhttp3.Response
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
class StreamCloud : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
override val name = "StreamCloud"
override val baseUrl = "https://streamcloud.movie"
override val lang = "de"
override val supportsLatest = false
private val preferences by lazy {
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
}
// ============================== Popular ===============================
override fun popularAnimeRequest(page: Int) = GET("$baseUrl/beliebte-filme/")
override fun popularAnimeSelector() = "div#dle-content > div.item > div.thumb > a"
override fun popularAnimeFromElement(element: Element) = SAnime.create().apply {
setUrlWithoutDomain(element.attr("href"))
element.selectFirst("img")!!.run {
thumbnail_url = absUrl("src")
title = attr("alt")
}
}
override fun popularAnimeNextPageSelector() = null
// =============================== Latest ===============================
override fun latestUpdatesNextPageSelector() = throw UnsupportedOperationException()
override fun latestUpdatesFromElement(element: Element) = throw UnsupportedOperationException()
override fun latestUpdatesRequest(page: Int) = throw UnsupportedOperationException()
override fun latestUpdatesSelector() = throw UnsupportedOperationException()
// =============================== Search ===============================
override fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList) =
GET("$baseUrl/index.php?do=search&subaction=search&search_start=$page&full_search=0&story=$query")
override fun searchAnimeSelector() = popularAnimeSelector()
override fun searchAnimeFromElement(element: Element) = popularAnimeFromElement(element)
override fun searchAnimeNextPageSelector() = "#nextlink"
// =========================== Anime Details ============================
override fun animeDetailsParse(document: Document) = SAnime.create().apply {
title = document.selectFirst("#title span.title")!!.text()
status = SAnime.COMPLETED
with(document.selectFirst("div#longInfo")!!) {
thumbnail_url = selectFirst("img")?.absUrl("src")
genre = selectFirst("span.masha_index10")?.let {
it.text().split("/").joinToString()
}
description = select("#storyline > span > p").eachText().joinToString("\n")
author = selectFirst("strong:contains(Regie:) + div > a")?.text()
}
}
// ============================== Episodes ==============================
override fun episodeListParse(response: Response): List<SEpisode> {
val document = response.asJsoup()
val episode = SEpisode.create().apply {
name = document.selectFirst("#title span.title")!!.text()
episode_number = 1F
setUrlWithoutDomain(document.location())
}
return listOf(episode)
}
override fun episodeListSelector() = throw UnsupportedOperationException()
override fun episodeFromElement(element: Element): SEpisode = throw UnsupportedOperationException()
// ============================ Video Links =============================
private val streamtapeExtractor by lazy { StreamTapeExtractor(client) }
private val doodExtractor by lazy { DoodExtractor(client) }
private val mixdropExtractor by lazy { MixDropExtractor(client) }
override fun videoListParse(response: Response): List<Video> {
val document = response.asJsoup()
val iframeurl = document.selectFirst("div.player-container-wrap > iframe")
?.attr("src")
?: error("No videos!")
val iframeDoc = client.newCall(GET(iframeurl)).execute().asJsoup()
val hosterSelection = preferences.getStringSet(PREF_HOSTER_SELECTION_KEY, PREF_HOSTER_SELECTION_DEFAULT)!!
val items = iframeDoc.select("div._player ul._player-mirrors li")
return items.flatMap { element ->
val url = element.attr("data-link").run {
takeIf { startsWith("https") }
?: "https:$this"
}
runCatching {
when {
url.contains("streamtape") && hosterSelection.contains("stape") -> {
streamtapeExtractor.videosFromUrl(url)
}
url.startsWith("https://dood") && hosterSelection.contains("dood") -> {
doodExtractor.videosFromUrl(url)
}
url.contains("mixdrop.") && hosterSelection.contains("mixdrop") -> {
mixdropExtractor.videosFromUrl(url)
}
else -> emptyList()
}
}.getOrElse { emptyList() }
}
}
override fun List<Video>.sort(): List<Video> {
val hoster = preferences.getString(PREF_HOSTER_KEY, PREF_HOSTER_DEFAULT)!!
return sortedWith(
compareBy { it.url.contains(hoster) },
).reversed()
}
override fun videoListSelector() = throw UnsupportedOperationException()
override fun videoFromElement(element: Element) = throw UnsupportedOperationException()
override fun videoUrlParse(document: Document) = throw UnsupportedOperationException()
// ============================== Settings ==============================
override fun setupPreferenceScreen(screen: PreferenceScreen) {
ListPreference(screen.context).apply {
key = PREF_HOSTER_KEY
title = PREF_HOSTER_TITLE
entries = PREF_HOSTER_ENTRIES
entryValues = PREF_HOSTER_VALUES
setDefaultValue(PREF_HOSTER_DEFAULT)
summary = "%s"
setOnPreferenceChangeListener { _, newValue ->
val selected = newValue as String
val index = findIndexOfValue(selected)
val entry = entryValues[index] as String
preferences.edit().putString(key, entry).commit()
}
}.also(screen::addPreference)
MultiSelectListPreference(screen.context).apply {
key = PREF_HOSTER_SELECTION_KEY
title = PREF_HOSTER_SELECTION_TITLE
entries = PREF_HOSTER_SELECTION_ENTRIES
entryValues = PREF_HOSTER_SELECTION_VALUES
setDefaultValue(PREF_HOSTER_SELECTION_DEFAULT)
setOnPreferenceChangeListener { _, newValue ->
@Suppress("UNCHECKED_CAST")
preferences.edit().putStringSet(key, newValue as Set<String>).commit()
}
}.also(screen::addPreference)
}
companion object {
private const val PREF_HOSTER_KEY = "preferred_hoster"
private const val PREF_HOSTER_TITLE = "Standard-Hoster"
private const val PREF_HOSTER_DEFAULT = "https://streamtape.com"
private val PREF_HOSTER_ENTRIES = arrayOf("Streamtape", "DoodStream")
private val PREF_HOSTER_VALUES = arrayOf("https://streamtape.com", "https://dood.")
private const val PREF_HOSTER_SELECTION_KEY = "hoster_selection"
private const val PREF_HOSTER_SELECTION_TITLE = "Hoster auswählen"
private val PREF_HOSTER_SELECTION_ENTRIES = arrayOf("Streamtape", "DoodStream", "MixDrop")
private val PREF_HOSTER_SELECTION_VALUES = arrayOf("stape", "dood", "mixdrop")
private val PREF_HOSTER_SELECTION_DEFAULT by lazy { PREF_HOSTER_SELECTION_VALUES.toSet() }
}
}

View file

@ -1,12 +0,0 @@
ext {
extName = 'Pelisflix'
extClass = '.PelisflixFactory'
extVersionCode = 18
}
apply from: "$rootDir/common.gradle"
dependencies {
implementation(project(':lib:streamtape-extractor'))
implementation(project(':lib:dood-extractor'))
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

View file

@ -1,267 +0,0 @@
package eu.kanade.tachiyomi.animeextension.es.pelisflix
import android.app.Application
import android.content.SharedPreferences
import android.util.Base64
import androidx.preference.ListPreference
import androidx.preference.PreferenceScreen
import eu.kanade.tachiyomi.animesource.ConfigurableAnimeSource
import eu.kanade.tachiyomi.animesource.model.AnimeFilter
import eu.kanade.tachiyomi.animesource.model.AnimeFilterList
import eu.kanade.tachiyomi.animesource.model.SAnime
import eu.kanade.tachiyomi.animesource.model.SEpisode
import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.animesource.online.ParsedAnimeHttpSource
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.util.asJsoup
import kotlinx.serialization.json.Json
import okhttp3.Request
import okhttp3.Response
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import org.jsoup.select.Elements
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
import uy.kohesive.injekt.injectLazy
import java.lang.Exception
open class Pelisflix(override val name: String, override val baseUrl: String) : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
override val lang = "es"
override val supportsLatest = false
private val json: Json by injectLazy()
private val preferences: SharedPreferences by lazy {
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
}
override fun popularAnimeRequest(page: Int): Request = GET("$baseUrl/peliculas-online/page/$page")
override fun popularAnimeSelector(): String = "#Tf-Wp div.TpRwCont ul.MovieList li.TPostMv article.TPost"
override fun popularAnimeFromElement(element: Element): SAnime {
val anime = SAnime.create()
anime.setUrlWithoutDomain(element.select("a").attr("href"))
anime.title = element.select("a h2.Title").text()
anime.thumbnail_url = externalOrInternalImg(element.selectFirst("a div.Image figure.Objf img.imglazy")!!.attr("data-src"))
anime.description = element.select("div.TPMvCn div.Description p:nth-child(1)").text().removeSurrounding("\"")
return anime
}
override fun popularAnimeNextPageSelector(): String = "nav.wp-pagenavi div.nav-links a ~ a"
override fun episodeListParse(response: Response): List<SEpisode> {
val document = response.asJsoup()
val episodeList = mutableListOf<SEpisode>()
val movie = document.select("ul.optnslst li div[data-url]")
val seasons = document.select("main .SeasonBx a")
if (movie.any()) {
val movieEp = SEpisode.create()
movieEp.name = "Pelicula"
movieEp.episode_number = 1f
movieEp.setUrlWithoutDomain(response.request.url.toString())
episodeList.add(movieEp)
} else if (seasons.any()) {
val seasonEp = extractEpisodesFromSeasons(seasons)
if (seasonEp.isNotEmpty()) episodeList.addAll(seasonEp)
}
return episodeList.reversed()
}
private fun extractEpisodesFromSeasons(seasons: Elements): List<SEpisode> {
val episodeList = mutableListOf<SEpisode>()
var noEp = 1f
var noTemp = 1
seasons!!.forEach {
var request = client.newCall(GET(it!!.attr("href"))).execute()
if (request.isSuccessful) {
val document = request.asJsoup()
document.select("div.TPTblCn table tbody tr.Viewed")!!.forEach { epContainer ->
val urlEp = epContainer.selectFirst("td.MvTbPly > a")!!.attr("href")
val ep = SEpisode.create()
ep.name = "T$noTemp - Episodio $noEp"
ep.episode_number = noEp
ep.setUrlWithoutDomain(urlEp)
episodeList.add(ep)
noEp++
}
}
noTemp++
}
return episodeList
}
override fun episodeListSelector() = "uwu"
override fun episodeFromElement(element: Element) = throw UnsupportedOperationException()
override fun videoListParse(response: Response): List<Video> {
val document = response.asJsoup()
val videoList = mutableListOf<Video>()
document.select("div.TPost.A.D div.Container div.optns-bx div.drpdn button.bstd").forEach { serverList ->
serverList.select("ul.optnslst li div[data-url]").forEach {
val langTag = it.selectFirst("span:nth-child(2)")!!
.text().substringBefore("HD")
.substringBefore("SD")
.trim()
val langVideo = if (langTag.contains("LATINO")) "LAT" else if (langTag.contains("CASTELLANO")) "CAST" else "SUB"
val encryptedUrl = it.attr("data-url")
val url = String(Base64.decode(encryptedUrl, Base64.DEFAULT))
val nuploadDomains = arrayOf("nuuuppp", "nupload")
if (nuploadDomains.any { x -> url.contains(x) } && !url.contains("/iframe/")) {
nuploadExtractor(langVideo, url).map { video -> videoList.add(video) }
}
}
}
return videoList
}
private fun nuploadExtractor(prefix: String, url: String): List<Video> {
val videoList = mutableListOf<Video>()
val request = client.newCall(GET(url)).execute()
if (request.isSuccessful) {
val document = request.asJsoup()
document.select("script").forEach { script ->
if (script!!.data().contains("var sesz=\"")) {
val key = script.data().substringAfter("var sesz=\"").substringBefore("\",")
var preUrl = script.data().substringAfter("file:\"").substringBefore("\"+")
var headersNupload = headers.newBuilder()
.set("authority", preUrl.substringAfter("https://").substringBefore("/"))
.set("accept-language", "es-MX,es-419;q=0.9,es;q=0.8,en;q=0.7")
.set("referer", "https://nupload.co/")
.set("dnt", "1")
.set("range", "bytes=0-")
.set("sec-ch-ua", "\"Chromium\";v=\"104\", \" Not A;Brand\";v=\"99\", \"Google Chrome\";v=\"104\"")
.set("sec-fetch-dest", "video")
.set("sec-fetch-mode", "no-cors")
.set("sec-fetch-site", "cross-site")
.set("sec-gpc", "1")
.set("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36")
.build()
videoList.add(Video(preUrl, "$prefix Nupload", preUrl + key, headers = headersNupload))
}
}
}
return videoList
}
override fun videoListSelector() = throw UnsupportedOperationException()
override fun videoUrlParse(document: Document) = throw UnsupportedOperationException()
override fun videoFromElement(element: Element) = throw UnsupportedOperationException()
override fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList): Request {
val filterList = if (filters.isEmpty()) getFilterList() else filters
val genreFilter = filterList.find { it is GenreFilter } as GenreFilter
return when {
query.isNotBlank() -> GET("$baseUrl/?s=$query&page=$page")
genreFilter.state != 0 -> GET("$baseUrl/${genreFilter.toUriPart()}/page/$page")
else -> popularAnimeRequest(page)
}
}
override fun getFilterList(): AnimeFilterList = AnimeFilterList(
AnimeFilter.Header("La busqueda por texto ignora el filtro"),
GenreFilter(),
)
private class GenreFilter : UriPartFilter(
"Géneros",
arrayOf(
Pair("<Selecionar>", ""),
Pair("Peliculas", "peliculas-online"),
Pair("Series", "series-online"),
Pair("Estrenos", "genero/estrenos"),
Pair("Aventura", "genero/aventura"),
Pair("Acción", "genero/accion"),
Pair("Ciencia ficción", "genero/ciencia-ficcion"),
Pair("Comedia", "genero/comedia"),
Pair("Crimen", "genero/crimen"),
Pair("Drama", "genero/drama"),
Pair("Romance", "genero/romance"),
Pair("Terror", "genero/terror"),
),
)
private open class UriPartFilter(displayName: String, val vals: Array<Pair<String, String>>) :
AnimeFilter.Select<String>(displayName, vals.map { it.first }.toTypedArray()) {
fun toUriPart() = vals[state].second
}
override fun searchAnimeFromElement(element: Element): SAnime {
return popularAnimeFromElement(element)
}
override fun searchAnimeNextPageSelector(): String = popularAnimeNextPageSelector()
override fun searchAnimeSelector(): String = popularAnimeSelector()
override fun animeDetailsParse(document: Document): SAnime {
val anime = SAnime.create()
var description = try {
document.selectFirst("article.TPost header.Container div.TPMvCn div.Description")!!
.text().removeSurrounding("\"")
.substringAfter("Online:")
.substringBefore("Recuerda ")
.substringBefore("Director:")
.trim()
} catch (e: Exception) {
document.selectFirst("article.TPost header div.TPMvCn div.Description p:nth-child(1)")!!.text().removeSurrounding("\"").trim()
}
var title = try {
document.selectFirst("article.TPost header.Container div.TPMvCn h1.Title")!!.text().removePrefix("Serie").trim()
} catch (e: Exception) {
document.selectFirst("article.TPost header.Container div.TPMvCn a h1.Title")!!.text().removePrefix("Serie").trim()
}
anime.title = title
anime.description = description
anime.genre = document.select("article.TPost header.Container div.TPMvCn div.Description p.Genre a").joinToString { it.text().replace(",", "") }
anime.status = SAnime.UNKNOWN
return anime
}
private fun externalOrInternalImg(url: String): String {
return if (url.contains("https")) url else if (url.startsWith("//")) "https:$url" else "$baseUrl/$url"
}
private fun parseStatus(statusString: String): Int {
return when {
statusString.contains("En emision") -> SAnime.ONGOING
statusString.contains("Finalizado") -> SAnime.COMPLETED
else -> SAnime.UNKNOWN
}
}
override fun latestUpdatesNextPageSelector() = popularAnimeNextPageSelector()
override fun latestUpdatesFromElement(element: Element) = popularAnimeFromElement(element)
override fun latestUpdatesRequest(page: Int) = GET("$baseUrl/browse?order=added&page=$page")
override fun latestUpdatesSelector() = popularAnimeSelector()
override fun setupPreferenceScreen(screen: PreferenceScreen) {
val videoQualityPref = ListPreference(screen.context).apply {
key = "preferred_quality"
title = "Preferred quality"
entries = arrayOf("LAT Nupload", "CAST Nupload", "SUB Nupload")
entryValues = arrayOf("LAT Nupload", "CAST Nupload", "SUB Nupload")
setDefaultValue("LAT Nupload")
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

@ -1,226 +0,0 @@
package eu.kanade.tachiyomi.animeextension.es.pelisflix
import android.app.Application
import android.content.SharedPreferences
import android.util.Log
import androidx.preference.ListPreference
import androidx.preference.PreferenceScreen
import eu.kanade.tachiyomi.animesource.AnimeSource
import eu.kanade.tachiyomi.animesource.AnimeSourceFactory
import eu.kanade.tachiyomi.animesource.model.AnimeFilter
import eu.kanade.tachiyomi.animesource.model.AnimeFilterList
import eu.kanade.tachiyomi.animesource.model.SAnime
import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.lib.doodextractor.DoodExtractor
import eu.kanade.tachiyomi.lib.streamtapeextractor.StreamTapeExtractor
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.util.asJsoup
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.RequestBody
import okhttp3.RequestBody.Companion.toRequestBody
import okhttp3.Response
import org.jsoup.nodes.Element
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
class PelisflixFactory : AnimeSourceFactory {
override fun createSources(): List<AnimeSource> = listOf(PelisflixClass(), SeriesflixClass())
}
class PelisflixClass : Pelisflix("Pelisflix", "https://pelisflix2.green")
class SeriesflixClass : Pelisflix("Seriesflix", "https://seriesflix.video") {
override fun popularAnimeRequest(page: Int): Request = GET("$baseUrl/ver-series-online/page/$page")
override fun popularAnimeSelector() = "li[id*=post-] > article"
private val preferences: SharedPreferences by lazy {
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
}
override fun popularAnimeFromElement(element: Element): SAnime {
val anime = SAnime.create()
anime.setUrlWithoutDomain(element.select("a").attr("href"))
anime.title = element.select("a h2.Title").text()
anime.thumbnail_url = element.selectFirst("a div.Image figure.Objf img")!!.attr("src")
anime.description = element.select("div.TPMvCn div.Description p:nth-child(1)").text().removeSurrounding("\"")
return anime
}
private fun loadVideoSources(urlResponse: String, lang: String): List<Video> {
val videoList = mutableListOf<Video>()
fetchUrls(urlResponse).map { serverUrl ->
Log.i("bruh url", serverUrl)
if (serverUrl.contains("doodstream")) {
val video = DoodExtractor(client).videoFromUrl(serverUrl.replace("https://doodstream.com", "https://dood.wf"), lang + "DoodStream")
if (video != null) videoList.add(video)
}
if (serverUrl.contains("streamtape")) {
val video = StreamTapeExtractor(client).videoFromUrl(serverUrl, lang + "StreamTape")
if (video != null) videoList.add(video)
}
}
return videoList
}
private fun fetchUrls(text: String?): List<String> {
if (text.isNullOrEmpty()) return listOf()
val linkRegex = "(http|ftp|https):\\/\\/([\\w_-]+(?:(?:\\.[\\w_-]+)+))([\\w.,@?^=%&:\\/~+#-]*[\\w@?^=%&\\/~+#-])".toRegex()
return linkRegex.findAll(text).map { it.value.trim().removeSurrounding("\"") }.toList()
}
override fun videoListParse(response: Response): List<Video> {
val document = response.asJsoup()
val videoList = mutableListOf<Video>()
document.select("ul.ListOptions li").forEach { serverList ->
val movieID = serverList.attr("data-id")
val serverID = serverList.attr("data-key")
val type = if (response.request.url.toString().contains("movies")) 1 else 2
val url = "$baseUrl/?trembed=$serverID&trid=$movieID&trtype=$type"
val langTag = serverList.selectFirst("p.AAIco-language")!!.text().substring(3).uppercase()
val lang = if (langTag.contains("LATINO")) "[LAT]" else if (langTag.contains("CASTELLANO")) "[CAST]" else "[SUB]"
var request = client.newCall(GET(url)).execute()
if (request.isSuccessful) {
val serverLinks = request.asJsoup()
serverLinks.select("div.Video iframe").map {
val iframe = it.attr("src")
if (iframe.contains("https://sc.seriesflix.video/index.php")) {
val postKey = iframe.replace("https://sc.seriesflix.video/index.php?h=", "")
val mediaType = "application/x-www-form-urlencoded".toMediaType()
val body: RequestBody = "h=$postKey".toRequestBody(mediaType)
val newClient = OkHttpClient().newBuilder().build()
val requestServer = Request.Builder()
.url("https://sc.seriesflix.video/r.php?h=$postKey")
.method("POST", body)
.addHeader("Host", "sc.seriesflix.video")
.addHeader(
"User-Agent",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36",
)
.addHeader(
"Accept",
"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
)
.addHeader("Accept-Language", "en-US,en;q=0.5")
.addHeader("Content-Type", "application/x-www-form-urlencoded")
.addHeader("Origin", "null")
.addHeader("DNT", "1")
.addHeader("Connection", "keep-alive")
.addHeader("Upgrade-Insecure-Requests", "1")
.addHeader("Sec-Fetch-Dest", "iframe")
.addHeader("Sec-Fetch-Mode", "no-cors")
.addHeader("sec-fetch-site", "same-origin")
.addHeader("Sec-Fetch-User", "?1")
.addHeader("Alt-Used", "sc.seriesflix.video")
.addHeader("Access-Control-Allow-Methods", "POST")
.build()
val document = newClient.newCall(requestServer).execute()
val urlResponse = document!!.networkResponse!!.toString()
loadVideoSources(urlResponse, lang)!!.forEach { source ->
videoList.add(source)
}
} else {
loadVideoSources(iframe, lang)
}
}
}
}
return videoList
}
override fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList): Request {
val filterList = if (filters.isEmpty()) getFilterList() else filters
val genreFilter = filterList.find { it is GenreFilter } as GenreFilter
return when {
query.isNotBlank() -> GET("$baseUrl/?s=$query&page=$page")
genreFilter.state != 0 -> GET("$baseUrl/${genreFilter.toUriPart()}/page/$page")
else -> popularAnimeRequest(page)
}
}
override fun getFilterList(): AnimeFilterList = AnimeFilterList(
AnimeFilter.Header("La busqueda por texto ignora el filtro"),
GenreFilter(),
)
private class GenreFilter : UriPartFilter(
"Géneros",
arrayOf(
Pair("<Selecionar>", ""),
Pair("Acción", "genero/accion"),
Pair("Animación", "genero/animacion"),
Pair("Anime", "genero/anime"),
Pair("Antiguas", "genero/series-antiguas"),
Pair("Aventura", "genero/aventura"),
Pair("Ciencia ficción", "genero/ciencia-ficcion"),
Pair("Comedia", "genero/comedia"),
Pair("Crimen", "genero/crimen"),
Pair("DC Comics", "genero/dc-comics"),
Pair("Drama", "genero/drama"),
Pair("Dorama", "genero/dorama"),
Pair("Estrenos", "genero/estrenos"),
Pair("Fantasía", "genero/fantasia"),
Pair("Misterio", "genero/misterio"),
Pair("Romance", "genero/romance"),
Pair("Terror", "genero/terror"),
),
)
private open class UriPartFilter(displayName: String, val vals: Array<Pair<String, String>>) :
AnimeFilter.Select<String>(displayName, vals.map { it.first }.toTypedArray()) {
fun toUriPart() = vals[state].second
}
override fun List<Video>.sort(): List<Video> {
return try {
val videoSorted = this.sortedWith(
compareBy<Video> { it.quality.replace("[0-9]".toRegex(), "") }.thenByDescending { getNumberFromString(it.quality) },
).toTypedArray()
val userPreferredQuality = preferences.getString("preferred_quality", "[LAT]DoodStream")
val preferredIdx = videoSorted.indexOfFirst { x -> x.quality == userPreferredQuality }
if (preferredIdx != -1) {
videoSorted.drop(preferredIdx + 1)
videoSorted[0] = videoSorted[preferredIdx]
}
videoSorted.toList()
} catch (e: Exception) {
this
}
}
private fun getNumberFromString(epsStr: String): String {
return epsStr.filter { it.isDigit() }.ifEmpty { "0" }
}
override fun setupPreferenceScreen(screen: PreferenceScreen) {
val qualities = arrayOf(
"[LAT]DoodStream",
"[CAST]DoodStream",
"[SUB]DoodStream",
"[LAT]StreamTape",
"[CAST]StreamTape",
"[SUB]StreamTape", // video servers without resolution
)
val videoQualityPref = ListPreference(screen.context).apply {
key = "preferred_quality"
title = "Preferred quality"
entries = qualities
entryValues = qualities
setDefaultValue("[LAT]DoodStream")
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)
}
}