forked from recloudstream/cloudstream
WatchCartoonOnlineProvider
This commit is contained in:
parent
2839d59a28
commit
a0ad101605
18 changed files with 354 additions and 41 deletions
|
@ -94,4 +94,7 @@ dependencies {
|
||||||
|
|
||||||
// subtitle color picker
|
// subtitle color picker
|
||||||
implementation 'com.jaredrummler:colorpicker:1.1.0'
|
implementation 'com.jaredrummler:colorpicker:1.1.0'
|
||||||
|
|
||||||
|
//run JS
|
||||||
|
implementation 'org.mozilla:rhino:1.7R4'
|
||||||
}
|
}
|
|
@ -6,17 +6,18 @@ import com.fasterxml.jackson.databind.DeserializationFeature
|
||||||
import com.fasterxml.jackson.databind.json.JsonMapper
|
import com.fasterxml.jackson.databind.json.JsonMapper
|
||||||
import com.fasterxml.jackson.module.kotlin.KotlinModule
|
import com.fasterxml.jackson.module.kotlin.KotlinModule
|
||||||
import com.lagradost.cloudstream3.animeproviders.DubbedAnimeProvider
|
import com.lagradost.cloudstream3.animeproviders.DubbedAnimeProvider
|
||||||
import com.lagradost.cloudstream3.animeproviders.ShiroProvider
|
|
||||||
import com.lagradost.cloudstream3.animeproviders.TenshiProvider
|
import com.lagradost.cloudstream3.animeproviders.TenshiProvider
|
||||||
|
import com.lagradost.cloudstream3.animeproviders.WatchCartoonOnlineProvider
|
||||||
import com.lagradost.cloudstream3.animeproviders.WcoProvider
|
import com.lagradost.cloudstream3.animeproviders.WcoProvider
|
||||||
import com.lagradost.cloudstream3.movieproviders.HDMProvider
|
import com.lagradost.cloudstream3.movieproviders.HDMProvider
|
||||||
import com.lagradost.cloudstream3.movieproviders.MeloMovieProvider
|
|
||||||
import com.lagradost.cloudstream3.movieproviders.TrailersToProvider
|
import com.lagradost.cloudstream3.movieproviders.TrailersToProvider
|
||||||
import com.lagradost.cloudstream3.movieproviders.VMoveeProvider
|
import com.lagradost.cloudstream3.movieproviders.VMoveeProvider
|
||||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
const val USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; rv:68.0) Gecko/20100101 Firefox/68.0"
|
|
||||||
|
const val 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"
|
||||||
val baseHeader = mapOf("User-Agent" to USER_AGENT)
|
val baseHeader = mapOf("User-Agent" to USER_AGENT)
|
||||||
val mapper = JsonMapper.builder().addModule(KotlinModule())
|
val mapper = JsonMapper.builder().addModule(KotlinModule())
|
||||||
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false).build()!!
|
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false).build()!!
|
||||||
|
@ -37,6 +38,7 @@ object APIHolder {
|
||||||
HDMProvider(),
|
HDMProvider(),
|
||||||
//LookMovieProvider(), // RECAPTCHA (Please allow up to 5 seconds...)
|
//LookMovieProvider(), // RECAPTCHA (Please allow up to 5 seconds...)
|
||||||
VMoveeProvider(),
|
VMoveeProvider(),
|
||||||
|
WatchCartoonOnlineProvider(),
|
||||||
)
|
)
|
||||||
|
|
||||||
fun getApiFromName(apiName: String?): MainAPI {
|
fun getApiFromName(apiName: String?): MainAPI {
|
||||||
|
@ -86,6 +88,14 @@ abstract class MainAPI {
|
||||||
open val hasMainPage = false
|
open val hasMainPage = false
|
||||||
open val hasQuickSearch = false
|
open val hasQuickSearch = false
|
||||||
|
|
||||||
|
open val supportedTypes = setOf(
|
||||||
|
TvType.Movie,
|
||||||
|
TvType.TvSeries,
|
||||||
|
TvType.Cartoon,
|
||||||
|
TvType.Anime,
|
||||||
|
TvType.ONA
|
||||||
|
)
|
||||||
|
|
||||||
open fun getMainPage(): HomePageResponse? {
|
open fun getMainPage(): HomePageResponse? {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
@ -177,6 +187,7 @@ enum class DubStatus {
|
||||||
enum class TvType {
|
enum class TvType {
|
||||||
Movie,
|
Movie,
|
||||||
TvSeries,
|
TvSeries,
|
||||||
|
Cartoon,
|
||||||
Anime,
|
Anime,
|
||||||
ONA,
|
ONA,
|
||||||
}
|
}
|
||||||
|
@ -255,7 +266,7 @@ interface LoadResponse {
|
||||||
val year: Int?
|
val year: Int?
|
||||||
val plot: String?
|
val plot: String?
|
||||||
val rating: Int? // 0-100
|
val rating: Int? // 0-100
|
||||||
val tags: ArrayList<String>?
|
val tags: List<String>?
|
||||||
val duration: String?
|
val duration: String?
|
||||||
val trailerUrl: String?
|
val trailerUrl: String?
|
||||||
}
|
}
|
||||||
|
@ -290,13 +301,13 @@ data class AnimeLoadResponse(
|
||||||
override val posterUrl: String?,
|
override val posterUrl: String?,
|
||||||
override val year: Int?,
|
override val year: Int?,
|
||||||
|
|
||||||
val dubEpisodes: ArrayList<AnimeEpisode>?,
|
val dubEpisodes: List<AnimeEpisode>?,
|
||||||
val subEpisodes: ArrayList<AnimeEpisode>?,
|
val subEpisodes: List<AnimeEpisode>?,
|
||||||
val showStatus: ShowStatus?,
|
val showStatus: ShowStatus?,
|
||||||
|
|
||||||
override val plot: String?,
|
override val plot: String?,
|
||||||
override val tags: ArrayList<String>? = null,
|
override val tags: List<String>? = null,
|
||||||
val synonyms: ArrayList<String>? = null,
|
val synonyms: List<String>? = null,
|
||||||
|
|
||||||
val malId: Int? = null,
|
val malId: Int? = null,
|
||||||
val anilistId: Int? = null,
|
val anilistId: Int? = null,
|
||||||
|
@ -318,7 +329,7 @@ data class MovieLoadResponse(
|
||||||
|
|
||||||
val imdbId: String?,
|
val imdbId: String?,
|
||||||
override val rating: Int? = null,
|
override val rating: Int? = null,
|
||||||
override val tags: ArrayList<String>? = null,
|
override val tags: List<String>? = null,
|
||||||
override val duration: String? = null,
|
override val duration: String? = null,
|
||||||
override val trailerUrl: String? = null,
|
override val trailerUrl: String? = null,
|
||||||
) : LoadResponse
|
) : LoadResponse
|
||||||
|
@ -339,7 +350,7 @@ data class TvSeriesLoadResponse(
|
||||||
override val url: String,
|
override val url: String,
|
||||||
override val apiName: String,
|
override val apiName: String,
|
||||||
override val type: TvType,
|
override val type: TvType,
|
||||||
val episodes: ArrayList<TvSeriesEpisode>,
|
val episodes: List<TvSeriesEpisode>,
|
||||||
|
|
||||||
override val posterUrl: String?,
|
override val posterUrl: String?,
|
||||||
override val year: Int?,
|
override val year: Int?,
|
||||||
|
@ -348,7 +359,7 @@ data class TvSeriesLoadResponse(
|
||||||
val showStatus: ShowStatus?,
|
val showStatus: ShowStatus?,
|
||||||
val imdbId: String?,
|
val imdbId: String?,
|
||||||
override val rating: Int? = null,
|
override val rating: Int? = null,
|
||||||
override val tags: ArrayList<String>? = null,
|
override val tags: List<String>? = null,
|
||||||
override val duration: String? = null,
|
override val duration: String? = null,
|
||||||
override val trailerUrl: String? = null,
|
override val trailerUrl: String? = null,
|
||||||
) : LoadResponse
|
) : LoadResponse
|
||||||
|
|
|
@ -18,6 +18,12 @@ class DubbedAnimeProvider : MainAPI() {
|
||||||
override val hasQuickSearch: Boolean
|
override val hasQuickSearch: Boolean
|
||||||
get() = true
|
get() = true
|
||||||
|
|
||||||
|
override val supportedTypes: Set<TvType>
|
||||||
|
get() = setOf(
|
||||||
|
TvType.Movie,
|
||||||
|
TvType.Anime,
|
||||||
|
)
|
||||||
|
|
||||||
data class QueryEpisodeResultRoot(
|
data class QueryEpisodeResultRoot(
|
||||||
@JsonProperty("result")
|
@JsonProperty("result")
|
||||||
val result: QueryEpisodeResult,
|
val result: QueryEpisodeResult,
|
||||||
|
|
|
@ -160,7 +160,7 @@ class ShiroProvider : MainAPI() {
|
||||||
val set: EnumSet<DubStatus> =
|
val set: EnumSet<DubStatus> =
|
||||||
EnumSet.of(if (isDubbed) DubStatus.Dubbed else DubStatus.Subbed)
|
EnumSet.of(if (isDubbed) DubStatus.Dubbed else DubStatus.Subbed)
|
||||||
|
|
||||||
val episodeCount = data.episodeCount?.toIntOrNull()
|
val episodeCount = data.episodeCount.toIntOrNull()
|
||||||
|
|
||||||
return@map AnimeSearchResponse(
|
return@map AnimeSearchResponse(
|
||||||
data.name.replace("Dubbed", ""), // i.english ?: i.canonicalTitle,
|
data.name.replace("Dubbed", ""), // i.english ?: i.canonicalTitle,
|
||||||
|
|
|
@ -29,6 +29,9 @@ class TenshiProvider : MainAPI() {
|
||||||
override val hasQuickSearch: Boolean
|
override val hasQuickSearch: Boolean
|
||||||
get() = false
|
get() = false
|
||||||
|
|
||||||
|
override val supportedTypes: Set<TvType>
|
||||||
|
get() = setOf(TvType.Anime, TvType.Movie, TvType.ONA)
|
||||||
|
|
||||||
private fun autoLoadToken(): Boolean {
|
private fun autoLoadToken(): Boolean {
|
||||||
if (token != null) return true
|
if (token != null) return true
|
||||||
return loadToken()
|
return loadToken()
|
||||||
|
@ -91,7 +94,11 @@ class TenshiProvider : MainAPI() {
|
||||||
private fun dateParser(dateString: String): String? {
|
private fun dateParser(dateString: String): String? {
|
||||||
val format = SimpleDateFormat("dd 'of' MMM',' yyyy")
|
val format = SimpleDateFormat("dd 'of' MMM',' yyyy")
|
||||||
val newFormat = SimpleDateFormat("dd-MM-yyyy")
|
val newFormat = SimpleDateFormat("dd-MM-yyyy")
|
||||||
return newFormat.format(format.parse(dateString.replace("th ", " ").replace("st ", " ").replace("nd ", " ").replace("rd ", " ")))
|
return newFormat.format(
|
||||||
|
format.parse(
|
||||||
|
dateString.replace("th ", " ").replace("st ", " ").replace("nd ", " ").replace("rd ", " ")
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// data class TenshiSearchResponse(
|
// data class TenshiSearchResponse(
|
||||||
|
@ -147,14 +154,14 @@ class TenshiProvider : MainAPI() {
|
||||||
|
|
||||||
override fun search(query: String): ArrayList<SearchResponse> {
|
override fun search(query: String): ArrayList<SearchResponse> {
|
||||||
val url = "$mainUrl/anime"
|
val url = "$mainUrl/anime"
|
||||||
var response = khttp.get(url, params=mapOf("q" to query), cookies=mapOf("loop-view" to "thumb"))
|
var response = khttp.get(url, params = mapOf("q" to query), cookies = mapOf("loop-view" to "thumb"))
|
||||||
var document = Jsoup.parse(response.text)
|
var document = Jsoup.parse(response.text)
|
||||||
val returnValue = parseSearchPage(document)
|
val returnValue = parseSearchPage(document)
|
||||||
|
|
||||||
while (!document.select("""a.page-link[rel="next"]""").isEmpty()) {
|
while (!document.select("""a.page-link[rel="next"]""").isEmpty()) {
|
||||||
val link = document.select("""a.page-link[rel="next"]""")
|
val link = document.select("""a.page-link[rel="next"]""")
|
||||||
if (link != null && !link.isEmpty()) {
|
if (link != null && !link.isEmpty()) {
|
||||||
response = khttp.get(link[0].attr("href"), cookies=mapOf("loop-view" to "thumb"))
|
response = khttp.get(link[0].attr("href"), cookies = mapOf("loop-view" to "thumb"))
|
||||||
document = Jsoup.parse(response.text)
|
document = Jsoup.parse(response.text)
|
||||||
returnValue.addAll(parseSearchPage(document))
|
returnValue.addAll(parseSearchPage(document))
|
||||||
} else {
|
} else {
|
||||||
|
@ -166,7 +173,7 @@ class TenshiProvider : MainAPI() {
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun load(url: String): LoadResponse {
|
override fun load(url: String): LoadResponse {
|
||||||
val response = khttp.get(url, timeout = 120.0, cookies=mapOf("loop-view" to "thumb"))
|
val response = khttp.get(url, timeout = 120.0, cookies = mapOf("loop-view" to "thumb"))
|
||||||
val document = Jsoup.parse(response.text)
|
val document = Jsoup.parse(response.text)
|
||||||
|
|
||||||
val englishTitle = document.selectFirst("span.value > span[title=\"English\"]")?.parent()?.text()?.trim()
|
val englishTitle = document.selectFirst("span.value > span[title=\"English\"]")?.parent()?.text()?.trim()
|
||||||
|
@ -177,13 +184,14 @@ class TenshiProvider : MainAPI() {
|
||||||
|
|
||||||
val episodes = ArrayList<AnimeEpisode>(episodeNodes?.map {
|
val episodes = ArrayList<AnimeEpisode>(episodeNodes?.map {
|
||||||
AnimeEpisode(
|
AnimeEpisode(
|
||||||
it.attr("href"),
|
it.attr("href"),
|
||||||
it.selectFirst(".episode-title")?.text()?.trim(),
|
it.selectFirst(".episode-title")?.text()?.trim(),
|
||||||
it.selectFirst("img")?.attr("src"),
|
it.selectFirst("img")?.attr("src"),
|
||||||
dateParser(it.selectFirst(".episode-date").text().trim()).toString(),
|
dateParser(it.selectFirst(".episode-date").text().trim()).toString(),
|
||||||
null,
|
null,
|
||||||
it.attr("data-content").trim(),
|
it.attr("data-content").trim(),
|
||||||
) }
|
)
|
||||||
|
}
|
||||||
?: ArrayList<AnimeEpisode>())
|
?: ArrayList<AnimeEpisode>())
|
||||||
val status = when (document.selectFirst("li.status > .value")?.text()?.trim()) {
|
val status = when (document.selectFirst("li.status > .value")?.text()?.trim()) {
|
||||||
"Ongoing" -> ShowStatus.Ongoing
|
"Ongoing" -> ShowStatus.Ongoing
|
||||||
|
@ -200,7 +208,8 @@ class TenshiProvider : MainAPI() {
|
||||||
val synopsis = document.selectFirst(".entry-description > .card-body")?.text()?.trim()
|
val synopsis = document.selectFirst(".entry-description > .card-body")?.text()?.trim()
|
||||||
val genre = document.select("li.genre.meta-data > span.value").map { it?.text()?.trim().toString() }
|
val genre = document.select("li.genre.meta-data > span.value").map { it?.text()?.trim().toString() }
|
||||||
|
|
||||||
val synonyms = document.select("li.synonym.meta-data > div.info-box > span.value").map { it?.text()?.trim().toString() }
|
val synonyms =
|
||||||
|
document.select("li.synonym.meta-data > div.info-box > span.value").map { it?.text()?.trim().toString() }
|
||||||
|
|
||||||
return AnimeLoadResponse(
|
return AnimeLoadResponse(
|
||||||
englishTitle,
|
englishTitle,
|
||||||
|
@ -231,7 +240,7 @@ class TenshiProvider : MainAPI() {
|
||||||
): Boolean {
|
): Boolean {
|
||||||
val response = khttp.get(data)
|
val response = khttp.get(data)
|
||||||
val src = Jsoup.parse(response.text).selectFirst(".embed-responsive > iframe").attr("src")
|
val src = Jsoup.parse(response.text).selectFirst(".embed-responsive > iframe").attr("src")
|
||||||
val mp4moe = Jsoup.parse(khttp.get(src, headers=mapOf("Referer" to data)).text).selectFirst("video#player")
|
val mp4moe = Jsoup.parse(khttp.get(src, headers = mapOf("Referer" to data)).text).selectFirst("video#player")
|
||||||
|
|
||||||
val sources = mp4moe.select("source").map {
|
val sources = mp4moe.select("source").map {
|
||||||
ExtractorLink(
|
ExtractorLink(
|
||||||
|
|
|
@ -0,0 +1,224 @@
|
||||||
|
package com.lagradost.cloudstream3.animeproviders
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty
|
||||||
|
import com.fasterxml.jackson.module.kotlin.readValue
|
||||||
|
import com.lagradost.cloudstream3.*
|
||||||
|
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||||
|
import com.lagradost.cloudstream3.utils.Qualities
|
||||||
|
import org.jsoup.Jsoup
|
||||||
|
import org.mozilla.javascript.Context
|
||||||
|
import org.mozilla.javascript.Scriptable
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
|
||||||
|
class WatchCartoonOnlineProvider : MainAPI() {
|
||||||
|
override val name: String
|
||||||
|
get() = "WatchCartoonOnline"
|
||||||
|
override val mainUrl: String
|
||||||
|
get() = "https://www.wcostream.com"
|
||||||
|
|
||||||
|
override val supportedTypes: Set<TvType>
|
||||||
|
get() = setOf(
|
||||||
|
TvType.Cartoon,
|
||||||
|
TvType.Anime,
|
||||||
|
)
|
||||||
|
|
||||||
|
override fun search(query: String): ArrayList<SearchResponse>? {
|
||||||
|
val url = "https://www.wcostream.com/search"
|
||||||
|
|
||||||
|
val response =
|
||||||
|
khttp.post(
|
||||||
|
url,
|
||||||
|
headers = mapOf("Referer" to url),
|
||||||
|
data = mapOf("catara" to query, "konuara" to "series")
|
||||||
|
)
|
||||||
|
val document = Jsoup.parse(response.text)
|
||||||
|
val items = document.select("div#blog > div.cerceve")
|
||||||
|
if (items.isNullOrEmpty()) return ArrayList()
|
||||||
|
val returnValue = ArrayList<SearchResponse>()
|
||||||
|
|
||||||
|
for (item in items) {
|
||||||
|
val header = item.selectFirst("> div.iccerceve")
|
||||||
|
val titleHeader = header.selectFirst("> div.aramadabaslik > a")
|
||||||
|
val title = titleHeader.text()
|
||||||
|
val href = fixUrl(titleHeader.attr("href"))
|
||||||
|
val poster = fixUrl(header.selectFirst("> a > img").attr("src"))
|
||||||
|
val genreText = item.selectFirst("div.cerceve-tur-ve-genre").ownText()
|
||||||
|
if (genreText.contains("cartoon")) {
|
||||||
|
returnValue.add(TvSeriesSearchResponse(title, href, this.name, TvType.Cartoon, poster, null, null))
|
||||||
|
} else {
|
||||||
|
val isDubbed = genreText.contains("dubbed")
|
||||||
|
val set: EnumSet<DubStatus> =
|
||||||
|
EnumSet.of(if (isDubbed) DubStatus.Dubbed else DubStatus.Subbed)
|
||||||
|
returnValue.add(
|
||||||
|
AnimeSearchResponse(
|
||||||
|
title,
|
||||||
|
href,
|
||||||
|
this.name,
|
||||||
|
TvType.Anime,
|
||||||
|
poster,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
set,
|
||||||
|
null,
|
||||||
|
null
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return returnValue
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun load(url: String): LoadResponse? {
|
||||||
|
val response = khttp.get(url)
|
||||||
|
val document = Jsoup.parse(response.text)
|
||||||
|
|
||||||
|
val title = document.selectFirst("td.vsbaslik > h2").text()
|
||||||
|
val poster = fixUrl(document.selectFirst("div#cat-img-desc > div > img").attr("src"))
|
||||||
|
val plot = document.selectFirst("div.iltext").text()
|
||||||
|
val genres = document.select("div#cat-genre > div.wcobtn > a").map { it.text() }
|
||||||
|
val episodes = document.select("div#catlist-listview > ul > li > a").reversed().map {
|
||||||
|
val text = it.text()
|
||||||
|
val match = Regex("Season ([0-9]*) Episode ([0-9]*).*? (.*)").find(text)
|
||||||
|
val href = it.attr("href")
|
||||||
|
if (match != null) {
|
||||||
|
val last = match.groupValues[3]
|
||||||
|
return@map TvSeriesEpisode(
|
||||||
|
if (last.startsWith("English")) null else last,
|
||||||
|
match.groupValues[1].toIntOrNull(),
|
||||||
|
match.groupValues[2].toIntOrNull(),
|
||||||
|
href
|
||||||
|
)
|
||||||
|
}
|
||||||
|
val match2 = Regex("Episode ([0-9]*).*? (.*)").find(text)
|
||||||
|
if (match2 != null) {
|
||||||
|
val last = match2.groupValues[2]
|
||||||
|
return@map TvSeriesEpisode(
|
||||||
|
if (last.startsWith("English")) null else last,
|
||||||
|
null,
|
||||||
|
match2.groupValues[1].toIntOrNull(),
|
||||||
|
href
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return@map TvSeriesEpisode(
|
||||||
|
text,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
href
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return TvSeriesLoadResponse(
|
||||||
|
title,
|
||||||
|
url,
|
||||||
|
this.name,
|
||||||
|
TvType.TvSeries,
|
||||||
|
episodes,
|
||||||
|
poster,
|
||||||
|
null,
|
||||||
|
plot,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
tags = genres
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
data class LinkResponse(
|
||||||
|
// @JsonProperty("cdn")
|
||||||
|
// val cdn: String,
|
||||||
|
@JsonProperty("enc")
|
||||||
|
val enc: String,
|
||||||
|
@JsonProperty("hd")
|
||||||
|
val hd: String,
|
||||||
|
@JsonProperty("server")
|
||||||
|
val server: String,
|
||||||
|
)
|
||||||
|
|
||||||
|
override fun loadLinks(
|
||||||
|
data: String,
|
||||||
|
isCasting: Boolean,
|
||||||
|
subtitleCallback: (SubtitleFile) -> Unit,
|
||||||
|
callback: (ExtractorLink) -> Unit
|
||||||
|
): Boolean {
|
||||||
|
val response = khttp.get(data)
|
||||||
|
/*val embedUrl = fixUrl(
|
||||||
|
Regex("itemprop=\"embedURL\" content=\"(.*?)\"").find(response.text)?.groupValues?.get(1) ?: return false
|
||||||
|
)*/
|
||||||
|
val text = response.text
|
||||||
|
val start = text.indexOf("itemprop=\"embedURL")
|
||||||
|
val foundJS = Regex("<script>(.*?)</script>").find(text, start)?.groupValues?.get(1)
|
||||||
|
?.replace("document.write", "var returnValue = ")
|
||||||
|
println("JS: $foundJS")
|
||||||
|
val rhino = Context.enter()
|
||||||
|
rhino.initStandardObjects()
|
||||||
|
rhino.optimizationLevel = -1
|
||||||
|
val scope: Scriptable = rhino.initStandardObjects()
|
||||||
|
|
||||||
|
val decodeBase64 = "atob = function(s) {\n" +
|
||||||
|
" var e={},i,b=0,c,x,l=0,a,r='',w=String.fromCharCode,L=s.length;\n" +
|
||||||
|
" var A=\"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\";\n" +
|
||||||
|
" for(i=0;i<64;i++){e[A.charAt(i)]=i;}\n" +
|
||||||
|
" for(x=0;x<L;x++){\n" +
|
||||||
|
" c=e[s.charAt(x)];b=(b<<6)+c;l+=6;\n" +
|
||||||
|
" while(l>=8){((a=(b>>>(l-=8))&0xff)||(x<(L-2)))&&(r+=w(a));}\n" +
|
||||||
|
" }\n" +
|
||||||
|
" return r;\n" +
|
||||||
|
"};"
|
||||||
|
|
||||||
|
rhino.evaluateString(scope, decodeBase64 + foundJS, "JavaScript", 1, null)
|
||||||
|
val jsEval = scope.get("returnValue", scope) ?: return false
|
||||||
|
val src = fixUrl(Regex("src=\"(.*?)\"").find(jsEval as String)?.groupValues?.get(1) ?: return false)
|
||||||
|
|
||||||
|
val embedResponse = khttp.get(
|
||||||
|
(src),
|
||||||
|
headers = mapOf("Referer" to data)
|
||||||
|
)
|
||||||
|
|
||||||
|
val getVidLink = fixUrl(
|
||||||
|
Regex("get\\(\"(.*?)\"").find(embedResponse.text)?.groupValues?.get(1) ?: return false
|
||||||
|
)
|
||||||
|
val linkResponse = khttp.get(
|
||||||
|
getVidLink, headers = mapOf(
|
||||||
|
"sec-ch-ua" to "\"Chromium\";v=\"91\", \" Not;A Brand\";v=\"99\"",
|
||||||
|
"sec-ch-ua-mobile" to "?0",
|
||||||
|
"sec-fetch-dest" to "empty",
|
||||||
|
"sec-fetch-mode" to "cors",
|
||||||
|
"sec-fetch-site" to "same-origin",
|
||||||
|
"accept" to "*/*",
|
||||||
|
"x-requested-with" to "XMLHttpRequest",
|
||||||
|
"referer" to src.replace(" ", "%20"),
|
||||||
|
"user-agent" to "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36",
|
||||||
|
"cookie" to "countrytabs=0"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
println("LINK:" + linkResponse.text)
|
||||||
|
val link = mapper.readValue<LinkResponse>(linkResponse.text)
|
||||||
|
|
||||||
|
val hdLink = "${link.server}/getvid?evid=${link.hd}"
|
||||||
|
val sdLink = "${link.server}/getvid?evid=${link.enc}"
|
||||||
|
|
||||||
|
if (link.hd.isNotBlank())
|
||||||
|
callback.invoke(
|
||||||
|
ExtractorLink(
|
||||||
|
this.name,
|
||||||
|
this.name + " HD",
|
||||||
|
hdLink,
|
||||||
|
"",
|
||||||
|
Qualities.HD.value
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
if (link.enc.isNotBlank())
|
||||||
|
callback.invoke(
|
||||||
|
ExtractorLink(
|
||||||
|
this.name,
|
||||||
|
this.name + " SD",
|
||||||
|
sdLink,
|
||||||
|
"",
|
||||||
|
Qualities.SD.value
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
|
@ -27,6 +27,13 @@ class WcoProvider : MainAPI() {
|
||||||
override val hasMainPage: Boolean
|
override val hasMainPage: Boolean
|
||||||
get() = true
|
get() = true
|
||||||
|
|
||||||
|
override val supportedTypes: Set<TvType>
|
||||||
|
get() = setOf(
|
||||||
|
TvType.Movie,
|
||||||
|
TvType.Anime,
|
||||||
|
TvType.ONA
|
||||||
|
)
|
||||||
|
|
||||||
override fun getMainPage(): HomePageResponse? {
|
override fun getMainPage(): HomePageResponse? {
|
||||||
val urls = listOf(
|
val urls = listOf(
|
||||||
Pair("$mainUrl/ajax/list/recently_updated?type=tv", "Recently Updated Anime"),
|
Pair("$mainUrl/ajax/list/recently_updated?type=tv", "Recently Updated Anime"),
|
||||||
|
|
|
@ -13,6 +13,11 @@ class HDMProvider : MainAPI() {
|
||||||
override val hasDownloadSupport: Boolean
|
override val hasDownloadSupport: Boolean
|
||||||
get() = false
|
get() = false
|
||||||
|
|
||||||
|
override val supportedTypes: Set<TvType>
|
||||||
|
get() = setOf(
|
||||||
|
TvType.Movie,
|
||||||
|
)
|
||||||
|
|
||||||
override fun search(query: String): ArrayList<SearchResponse> {
|
override fun search(query: String): ArrayList<SearchResponse> {
|
||||||
val url = "$mainUrl/search/$query"
|
val url = "$mainUrl/search/$query"
|
||||||
val response = khttp.get(url)
|
val response = khttp.get(url)
|
||||||
|
|
|
@ -20,6 +20,12 @@ class LookMovieProvider : MainAPI() {
|
||||||
override val mainUrl: String
|
override val mainUrl: String
|
||||||
get() = "https://lookmovie.io"
|
get() = "https://lookmovie.io"
|
||||||
|
|
||||||
|
override val supportedTypes: Set<TvType>
|
||||||
|
get() = setOf(
|
||||||
|
TvType.Movie,
|
||||||
|
TvType.TvSeries,
|
||||||
|
)
|
||||||
|
|
||||||
data class LookMovieSearchResult(
|
data class LookMovieSearchResult(
|
||||||
@JsonProperty("backdrop") val backdrop: String?,
|
@JsonProperty("backdrop") val backdrop: String?,
|
||||||
@JsonProperty("imdb_rating") val imdb_rating: String,
|
@JsonProperty("imdb_rating") val imdb_rating: String,
|
||||||
|
|
|
@ -23,6 +23,12 @@ class TrailersToProvider : MainAPI() {
|
||||||
override val hasChromecastSupport: Boolean
|
override val hasChromecastSupport: Boolean
|
||||||
get() = false
|
get() = false
|
||||||
|
|
||||||
|
override val supportedTypes: Set<TvType>
|
||||||
|
get() = setOf(
|
||||||
|
TvType.Movie,
|
||||||
|
TvType.TvSeries,
|
||||||
|
)
|
||||||
|
|
||||||
override fun getMainPage(): HomePageResponse? {
|
override fun getMainPage(): HomePageResponse? {
|
||||||
val response = khttp.get(mainUrl)
|
val response = khttp.get(mainUrl)
|
||||||
val document = Jsoup.parse(response.text)
|
val document = Jsoup.parse(response.text)
|
||||||
|
|
|
@ -14,6 +14,11 @@ class VMoveeProvider : MainAPI() {
|
||||||
override val mainUrl: String
|
override val mainUrl: String
|
||||||
get() = "https://www.vmovee.watch"
|
get() = "https://www.vmovee.watch"
|
||||||
|
|
||||||
|
override val supportedTypes: Set<TvType>
|
||||||
|
get() = setOf(
|
||||||
|
TvType.Movie,
|
||||||
|
)
|
||||||
|
|
||||||
override fun search(query: String): ArrayList<SearchResponse>? {
|
override fun search(query: String): ArrayList<SearchResponse>? {
|
||||||
val url = "$mainUrl/?s=$query"
|
val url = "$mainUrl/?s=$query"
|
||||||
val response = khttp.get(url)
|
val response = khttp.get(url)
|
||||||
|
|
|
@ -61,6 +61,7 @@ class HomeChildItemAdapter(
|
||||||
TvType.Movie -> "Movie"
|
TvType.Movie -> "Movie"
|
||||||
TvType.ONA -> "ONA"
|
TvType.ONA -> "ONA"
|
||||||
TvType.TvSeries -> "TV"
|
TvType.TvSeries -> "TV"
|
||||||
|
TvType.Cartoon -> "Cartoon"
|
||||||
}
|
}
|
||||||
// search_result_lang?.visibility = View.GONE
|
// search_result_lang?.visibility = View.GONE
|
||||||
|
|
||||||
|
|
|
@ -796,7 +796,7 @@ class PlayerFragment : Fragment() {
|
||||||
}
|
}
|
||||||
//endregion
|
//endregion
|
||||||
|
|
||||||
private fun onSubStyleChanged(style : SaveCaptionStyle) {
|
private fun onSubStyleChanged(style: SaveCaptionStyle) {
|
||||||
context?.let { ctx ->
|
context?.let { ctx ->
|
||||||
subStyle = style
|
subStyle = style
|
||||||
subView?.setStyle(ctx.fromSaveToStyle(style))
|
subView?.setStyle(ctx.fromSaveToStyle(style))
|
||||||
|
@ -1131,7 +1131,7 @@ class PlayerFragment : Fragment() {
|
||||||
val speedsNumbers = listOf(0.5f, 0.75f, 1f, 1.25f, 1.5f, 1.75f, 2f)
|
val speedsNumbers = listOf(0.5f, 0.75f, 1f, 1.25f, 1.5f, 1.75f, 2f)
|
||||||
val speedIndex = speedsNumbers.indexOf(playbackSpeed)
|
val speedIndex = speedsNumbers.indexOf(playbackSpeed)
|
||||||
|
|
||||||
context?.showDialog(speedsText,speedIndex,"Player Speed", false, {
|
context?.showDialog(speedsText, speedIndex, "Player Speed", false, {
|
||||||
activity?.hideSystemUI()
|
activity?.hideSystemUI()
|
||||||
}) { index ->
|
}) { index ->
|
||||||
playbackSpeed = speedsNumbers[index]
|
playbackSpeed = speedsNumbers[index]
|
||||||
|
@ -1541,8 +1541,19 @@ class PlayerFragment : Fragment() {
|
||||||
/*FastAniApi.currentHeaders?.forEach {
|
/*FastAniApi.currentHeaders?.forEach {
|
||||||
dataSource.setRequestProperty(it.key, it.value)
|
dataSource.setRequestProperty(it.key, it.value)
|
||||||
}*/
|
}*/
|
||||||
if (currentUrl != null)
|
if (currentUrl != null) {
|
||||||
dataSource.setRequestProperty("Referer", currentUrl.referer)
|
dataSource.setRequestProperty("Referer", currentUrl.referer)
|
||||||
|
// extra stuff
|
||||||
|
dataSource.setRequestProperty(
|
||||||
|
"sec-ch-ua",
|
||||||
|
"\"Chromium\";v=\"91\", \" Not;A Brand\";v=\"99\""
|
||||||
|
)
|
||||||
|
dataSource.setRequestProperty("sec-ch-ua-mobile", "?0")
|
||||||
|
// dataSource.setRequestProperty("Sec-Fetch-Site", "none") //same-site
|
||||||
|
dataSource.setRequestProperty("Sec-Fetch-User", "?1")
|
||||||
|
dataSource.setRequestProperty("Sec-Fetch-Mode", "navigate")
|
||||||
|
dataSource.setRequestProperty("Sec-Fetch-Dest", "document")
|
||||||
|
}
|
||||||
dataSource
|
dataSource
|
||||||
} else {
|
} else {
|
||||||
DefaultDataSourceFactory(requireContext(), USER_AGENT).createDataSource()
|
DefaultDataSourceFactory(requireContext(), USER_AGENT).createDataSource()
|
||||||
|
|
|
@ -238,14 +238,14 @@ class ResultFragment : Fragment() {
|
||||||
var startAction: Int? = null
|
var startAction: Int? = null
|
||||||
|
|
||||||
private fun lateFixDownloadButton(show: Boolean) {
|
private fun lateFixDownloadButton(show: Boolean) {
|
||||||
if (show) {
|
if(!show || currentType?.isMovieType() == true) {
|
||||||
result_movie_parent.visibility = VISIBLE
|
|
||||||
result_episodes_text.visibility = GONE
|
|
||||||
result_episodes.visibility = GONE
|
|
||||||
} else {
|
|
||||||
result_movie_parent.visibility = GONE
|
result_movie_parent.visibility = GONE
|
||||||
result_episodes_text.visibility = VISIBLE
|
result_episodes_text.visibility = VISIBLE
|
||||||
result_episodes.visibility = VISIBLE
|
result_episodes.visibility = VISIBLE
|
||||||
|
} else {
|
||||||
|
result_movie_parent.visibility = VISIBLE
|
||||||
|
result_episodes_text.visibility = GONE
|
||||||
|
result_episodes.visibility = GONE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -430,6 +430,7 @@ class ResultFragment : Fragment() {
|
||||||
TvType.Movie -> "Movies"
|
TvType.Movie -> "Movies"
|
||||||
TvType.TvSeries -> "TVSeries/$titleName"
|
TvType.TvSeries -> "TVSeries/$titleName"
|
||||||
TvType.ONA -> "ONA"
|
TvType.ONA -> "ONA"
|
||||||
|
TvType.Cartoon -> "Cartoons/$titleName"
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -119,7 +119,6 @@ class ResultViewModel : ViewModel() {
|
||||||
rangeList.add("${i + 1}-${currentList.size}")
|
rangeList.add("${i + 1}-${currentList.size}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_rangeOptions.postValue(rangeList)
|
|
||||||
|
|
||||||
val cRange = range ?: if (selection != null) {
|
val cRange = range ?: if (selection != null) {
|
||||||
0
|
0
|
||||||
|
@ -133,14 +132,19 @@ class ResultViewModel : ViewModel() {
|
||||||
cRange
|
cRange
|
||||||
}
|
}
|
||||||
|
|
||||||
selectedRangeInt.postValue(realRange)
|
|
||||||
selectedRange.postValue(rangeList[realRange])
|
|
||||||
|
|
||||||
if (currentList.size > EPISODE_RANGE_OVERLOAD) {
|
if (currentList.size > EPISODE_RANGE_OVERLOAD) {
|
||||||
currentList = currentList.subList(
|
currentList = currentList.subList(
|
||||||
realRange * EPISODE_RANGE_SIZE,
|
realRange * EPISODE_RANGE_SIZE,
|
||||||
minOf(currentList.size, (realRange + 1) * EPISODE_RANGE_SIZE)
|
minOf(currentList.size, (realRange + 1) * EPISODE_RANGE_SIZE)
|
||||||
)
|
)
|
||||||
|
_rangeOptions.postValue(rangeList)
|
||||||
|
selectedRangeInt.postValue(realRange)
|
||||||
|
selectedRange.postValue(rangeList[realRange])
|
||||||
|
} else {
|
||||||
|
val allRange ="1-${currentList.size}"
|
||||||
|
_rangeOptions.postValue(listOf(allRange))
|
||||||
|
selectedRangeInt.postValue(0)
|
||||||
|
selectedRange.postValue(allRange)
|
||||||
}
|
}
|
||||||
|
|
||||||
_publicEpisodes.postValue(currentList)
|
_publicEpisodes.postValue(currentList)
|
||||||
|
|
|
@ -50,7 +50,6 @@ class SearchAdapter(
|
||||||
is CardViewHolder -> {
|
is CardViewHolder -> {
|
||||||
holder.bind(cardList[position])
|
holder.bind(cardList[position])
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,6 +93,7 @@ class SearchAdapter(
|
||||||
TvType.Movie -> "Movie"
|
TvType.Movie -> "Movie"
|
||||||
TvType.ONA -> "ONA"
|
TvType.ONA -> "ONA"
|
||||||
TvType.TvSeries -> "TV"
|
TvType.TvSeries -> "TV"
|
||||||
|
TvType.Cartoon -> "Cartoon"
|
||||||
}
|
}
|
||||||
// search_result_lang?.visibility = View.GONE
|
// search_result_lang?.visibility = View.GONE
|
||||||
|
|
||||||
|
|
|
@ -47,7 +47,7 @@ object VideoDownloadManager {
|
||||||
private var currentDownloads = mutableListOf<Int>()
|
private var currentDownloads = mutableListOf<Int>()
|
||||||
|
|
||||||
private const val USER_AGENT =
|
private const val USER_AGENT =
|
||||||
"Mozilla/5.0 (Windows NT 10.0; rv:68.0) Gecko/20100101 Firefox/68.0"
|
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"
|
||||||
|
|
||||||
@DrawableRes
|
@DrawableRes
|
||||||
const val imgDone = R.drawable.rddone
|
const val imgDone = R.drawable.rddone
|
||||||
|
@ -511,6 +511,18 @@ object VideoDownloadManager {
|
||||||
connection.setRequestProperty("Accept-Encoding", "identity")
|
connection.setRequestProperty("Accept-Encoding", "identity")
|
||||||
connection.setRequestProperty("User-Agent", USER_AGENT)
|
connection.setRequestProperty("User-Agent", USER_AGENT)
|
||||||
if (link.referer.isNotEmpty()) connection.setRequestProperty("Referer", link.referer)
|
if (link.referer.isNotEmpty()) connection.setRequestProperty("Referer", link.referer)
|
||||||
|
|
||||||
|
// extra stuff
|
||||||
|
connection.setRequestProperty(
|
||||||
|
"sec-ch-ua",
|
||||||
|
"\"Chromium\";v=\"91\", \" Not;A Brand\";v=\"99\""
|
||||||
|
)
|
||||||
|
connection.setRequestProperty("sec-ch-ua-mobile", "?0")
|
||||||
|
// dataSource.setRequestProperty("Sec-Fetch-Site", "none") //same-site
|
||||||
|
connection.setRequestProperty("Sec-Fetch-User", "?1")
|
||||||
|
connection.setRequestProperty("Sec-Fetch-Mode", "navigate")
|
||||||
|
connection.setRequestProperty("Sec-Fetch-Dest", "document")
|
||||||
|
|
||||||
if (resume)
|
if (resume)
|
||||||
connection.setRequestProperty("Range", "bytes=${fileLength}-")
|
connection.setRequestProperty("Range", "bytes=${fileLength}-")
|
||||||
val resumeLength = (if (resume) fileLength else 0)
|
val resumeLength = (if (resume) fileLength else 0)
|
||||||
|
|
|
@ -11,6 +11,9 @@
|
||||||
android:screenOrientation="userLandscape"
|
android:screenOrientation="userLandscape"
|
||||||
app:surface_type="texture_view"
|
app:surface_type="texture_view"
|
||||||
>
|
>
|
||||||
|
<!--
|
||||||
|
app:fastforward_increment="10000"
|
||||||
|
app:rewind_increment="10000"-->
|
||||||
<com.google.android.exoplayer2.ui.PlayerView
|
<com.google.android.exoplayer2.ui.PlayerView
|
||||||
android:id="@+id/player_view"
|
android:id="@+id/player_view"
|
||||||
app:show_timeout="0"
|
app:show_timeout="0"
|
||||||
|
@ -18,8 +21,7 @@
|
||||||
app:auto_show="true"
|
app:auto_show="true"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
app:fastforward_increment="10000"
|
|
||||||
app:rewind_increment="10000"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
|
Loading…
Reference in a new issue