mirror of
https://github.com/recloudstream/cloudstream.git
synced 2024-08-15 01:53:11 +00:00
fixed some warnings
This commit is contained in:
parent
509a0a6b90
commit
bf18e657f6
29 changed files with 235 additions and 283 deletions
|
@ -9,7 +9,6 @@ import com.lagradost.cloudstream3.utils.extractorApis
|
||||||
import org.jsoup.Jsoup
|
import org.jsoup.Jsoup
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
|
|
||||||
class AnimeFlickProvider : MainAPI() {
|
class AnimeFlickProvider : MainAPI() {
|
||||||
companion object {
|
companion object {
|
||||||
fun getType(t: String): TvType {
|
fun getType(t: String): TvType {
|
||||||
|
|
|
@ -10,7 +10,6 @@ import com.lagradost.cloudstream3.utils.getQualityFromName
|
||||||
import org.jsoup.Jsoup
|
import org.jsoup.Jsoup
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
|
|
||||||
class GogoanimeProvider : MainAPI() {
|
class GogoanimeProvider : MainAPI() {
|
||||||
companion object {
|
companion object {
|
||||||
fun getType(t: String): TvType {
|
fun getType(t: String): TvType {
|
||||||
|
|
|
@ -4,7 +4,6 @@ import android.annotation.SuppressLint
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty
|
import com.fasterxml.jackson.annotation.JsonProperty
|
||||||
import com.fasterxml.jackson.module.kotlin.readValue
|
import com.fasterxml.jackson.module.kotlin.readValue
|
||||||
import com.lagradost.cloudstream3.*
|
import com.lagradost.cloudstream3.*
|
||||||
import com.lagradost.cloudstream3.network.cookies
|
|
||||||
import com.lagradost.cloudstream3.network.get
|
import com.lagradost.cloudstream3.network.get
|
||||||
import com.lagradost.cloudstream3.network.text
|
import com.lagradost.cloudstream3.network.text
|
||||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||||
|
@ -16,8 +15,8 @@ import java.util.*
|
||||||
|
|
||||||
class TenshiProvider : MainAPI() {
|
class TenshiProvider : MainAPI() {
|
||||||
companion object {
|
companion object {
|
||||||
var token: String? = null
|
//var token: String? = null
|
||||||
var cookie: Map<String, String> = mapOf()
|
//var cookie: Map<String, String> = mapOf()
|
||||||
|
|
||||||
fun getType(t: String): TvType {
|
fun getType(t: String): TvType {
|
||||||
return if (t.contains("OVA") || t.contains("Special")) TvType.ONA
|
return if (t.contains("OVA") || t.contains("Special")) TvType.ONA
|
||||||
|
@ -39,7 +38,7 @@ class TenshiProvider : MainAPI() {
|
||||||
override val supportedTypes: Set<TvType>
|
override val supportedTypes: Set<TvType>
|
||||||
get() = setOf(TvType.Anime, TvType.AnimeMovie, TvType.ONA)
|
get() = setOf(TvType.Anime, TvType.AnimeMovie, TvType.ONA)
|
||||||
|
|
||||||
private fun loadToken(): Boolean {
|
/*private fun loadToken(): Boolean {
|
||||||
return try {
|
return try {
|
||||||
val response = get(mainUrl)
|
val response = get(mainUrl)
|
||||||
cookie = response.cookies
|
cookie = response.cookies
|
||||||
|
@ -49,7 +48,7 @@ class TenshiProvider : MainAPI() {
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
|
|
||||||
override fun getMainPage(): HomePageResponse {
|
override fun getMainPage(): HomePageResponse {
|
||||||
val items = ArrayList<HomePageList>()
|
val items = ArrayList<HomePageList>()
|
||||||
|
@ -259,8 +258,7 @@ class TenshiProvider : MainAPI() {
|
||||||
null,
|
null,
|
||||||
it.attr("data-content").trim(),
|
it.attr("data-content").trim(),
|
||||||
)
|
)
|
||||||
}
|
})
|
||||||
?: 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
|
||||||
"Completed" -> ShowStatus.Completed
|
"Completed" -> ShowStatus.Completed
|
||||||
|
@ -322,7 +320,7 @@ class TenshiProvider : MainAPI() {
|
||||||
headers = mapOf("Referer" to data)
|
headers = mapOf("Referer" to data)
|
||||||
).text
|
).text
|
||||||
|
|
||||||
val match = Regex("""sources: (\[(?:.|\s)+?type: ['\"]video\/.*?['\"](?:.|\s)+?\])""").find(sourceHTML)
|
val match = Regex("""sources: (\[(?:.|\s)+?type: ['"]video/.*?['"](?:.|\s)+?])""").find(sourceHTML)
|
||||||
if (match != null) {
|
if (match != null) {
|
||||||
val qualities = mapper.readValue<List<Quality>>(
|
val qualities = mapper.readValue<List<Quality>>(
|
||||||
match.destructured.component1()
|
match.destructured.component1()
|
||||||
|
|
|
@ -80,16 +80,16 @@ class WatchCartoonOnlineProvider : MainAPI() {
|
||||||
data = mapOf("catara" to query, "konuara" to "episodes")
|
data = mapOf("catara" to query, "konuara" to "episodes")
|
||||||
).text
|
).text
|
||||||
document = Jsoup.parse(response)
|
document = Jsoup.parse(response)
|
||||||
items = document.select("#catlist-listview2 > ul > li").filter { it?.text() != null && !it?.text().toString().contains("Episode") }
|
items = document.select("#catlist-listview2 > ul > li").filter { it?.text() != null && !it.text().toString().contains("Episode") }
|
||||||
|
|
||||||
|
|
||||||
for (item in items) {
|
for (item in items) {
|
||||||
val titleHeader = item.selectFirst("a")
|
val titleHeader = item.selectFirst("a")
|
||||||
val title = titleHeader.text()
|
val title = titleHeader.text()
|
||||||
val href = fixUrl(titleHeader.attr("href"))
|
val href = fixUrl(titleHeader.attr("href"))
|
||||||
val isDubbed = title.contains("dubbed")
|
//val isDubbed = title.contains("dubbed")
|
||||||
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)
|
||||||
returnValue.add(
|
returnValue.add(
|
||||||
TvSeriesSearchResponse(
|
TvSeriesSearchResponse(
|
||||||
title,
|
title,
|
||||||
|
|
|
@ -16,7 +16,7 @@ class MixDrop : ExtractorApi() {
|
||||||
|
|
||||||
override fun getUrl(url: String, referer: String?): List<ExtractorLink>? {
|
override fun getUrl(url: String, referer: String?): List<ExtractorLink>? {
|
||||||
with(get(url)) {
|
with(get(url)) {
|
||||||
getAndUnpack(this.text)?.let { unpackedText ->
|
getAndUnpack(this.text).let { unpackedText ->
|
||||||
srcRegex.find(unpackedText)?.groupValues?.get(1)?.let { link ->
|
srcRegex.find(unpackedText)?.groupValues?.get(1)?.let { link ->
|
||||||
return listOf(
|
return listOf(
|
||||||
ExtractorLink(
|
ExtractorLink(
|
||||||
|
|
|
@ -12,7 +12,7 @@ class Mp4Upload : ExtractorApi() {
|
||||||
|
|
||||||
override fun getUrl(url: String, referer: String?): List<ExtractorLink>? {
|
override fun getUrl(url: String, referer: String?): List<ExtractorLink>? {
|
||||||
with(get(url)) {
|
with(get(url)) {
|
||||||
getAndUnpack(this.text)?.let { unpackedText ->
|
getAndUnpack(this.text).let { unpackedText ->
|
||||||
srcRegex.find(unpackedText)?.groupValues?.get(1)?.let { link ->
|
srcRegex.find(unpackedText)?.groupValues?.get(1)?.let { link ->
|
||||||
return listOf(
|
return listOf(
|
||||||
ExtractorLink(
|
ExtractorLink(
|
||||||
|
|
|
@ -29,7 +29,7 @@ class MultiQuality : ExtractorApi() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getUrl(url: String, referer: String?): List<ExtractorLink>? {
|
override fun getUrl(url: String, referer: String?): List<ExtractorLink> {
|
||||||
val extractedLinksList: MutableList<ExtractorLink> = mutableListOf()
|
val extractedLinksList: MutableList<ExtractorLink> = mutableListOf()
|
||||||
with(get(url)) {
|
with(get(url)) {
|
||||||
sourceRegex.findAll(this.text).forEach { sourceMatch ->
|
sourceRegex.findAll(this.text).forEach { sourceMatch ->
|
||||||
|
@ -65,6 +65,5 @@ class MultiQuality : ExtractorApi() {
|
||||||
}
|
}
|
||||||
return extractedLinksList
|
return extractedLinksList
|
||||||
}
|
}
|
||||||
return null
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -23,7 +23,7 @@ class SBPlay : ExtractorApi() {
|
||||||
val response = get(url, referer = referer).text
|
val response = get(url, referer = referer).text
|
||||||
val document = Jsoup.parse(response)
|
val document = Jsoup.parse(response)
|
||||||
|
|
||||||
val links = ArrayList<ExtractorLink>();
|
val links = ArrayList<ExtractorLink>()
|
||||||
|
|
||||||
val tree = document.select("table > tbody > tr > td > a")
|
val tree = document.select("table > tbody > tr > td > a")
|
||||||
for (item in tree) {
|
for (item in tree) {
|
||||||
|
|
|
@ -24,7 +24,7 @@ class StreamSB : ExtractorApi() {
|
||||||
val extractedLinksList: MutableList<ExtractorLink> = mutableListOf()
|
val extractedLinksList: MutableList<ExtractorLink> = mutableListOf()
|
||||||
val newUrl = url.replace("sbplay.org/embed-", "sbplay.org/play/").removeSuffix(".html")
|
val newUrl = url.replace("sbplay.org/embed-", "sbplay.org/play/").removeSuffix(".html")
|
||||||
with(get(newUrl, timeout = 10)) {
|
with(get(newUrl, timeout = 10)) {
|
||||||
getAndUnpack(this.text)?.let {
|
getAndUnpack(this.text).let {
|
||||||
sourceRegex.findAll(it).forEach { sourceMatch ->
|
sourceRegex.findAll(it).forEach { sourceMatch ->
|
||||||
val extractedUrl = sourceMatch.groupValues[1]
|
val extractedUrl = sourceMatch.groupValues[1]
|
||||||
if (extractedUrl.contains(".m3u8")) {
|
if (extractedUrl.contains(".m3u8")) {
|
||||||
|
|
|
@ -293,7 +293,7 @@ class TrailersToProvider : MainAPI() {
|
||||||
Pair(
|
Pair(
|
||||||
subUrl,
|
subUrl,
|
||||||
fixUrl(
|
fixUrl(
|
||||||
document?.selectFirst("content")?.attr("data-url")
|
document.selectFirst("content")?.attr("data-url")
|
||||||
?: throw ErrorLoadingException("Link not found")
|
?: throw ErrorLoadingException("Link not found")
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
|
@ -77,10 +77,10 @@ class VfFilmProvider : MainAPI() {
|
||||||
|
|
||||||
private fun getDirect(original: String): String { // original data, https://vf-film.org/?trembed=1&trid=55313&trtype=1 for example
|
private fun getDirect(original: String): String { // original data, https://vf-film.org/?trembed=1&trid=55313&trtype=1 for example
|
||||||
val response = get(original).text
|
val response = get(original).text
|
||||||
val url = "iframe .*src=\\\"(.*?)\\\"".toRegex().find(response)?.groupValues?.get(1).toString() // https://vudeo.net/embed-uweno86lzx8f.html for example
|
val url = "iframe .*src=\"(.*?)\"".toRegex().find(response)?.groupValues?.get(1).toString() // https://vudeo.net/embed-uweno86lzx8f.html for example
|
||||||
val vudoResponse = get(url).text
|
val vudoResponse = get(url).text
|
||||||
val document = Jsoup.parse(vudoResponse)
|
val document = Jsoup.parse(vudoResponse)
|
||||||
val vudoUrl = Regex("sources: \\[\\\"(.*?)\\\"\\]").find(document.html())?.groupValues?.get(1).toString() // direct mp4 link, https://m11.vudeo.net/2vp3ukyw2avjdohilpebtzuct42q5jwvpmpsez3xjs6d7fbs65dpuey2rbra/v.mp4 for exemple
|
val vudoUrl = Regex("sources: \\[\"(.*?)\"]").find(document.html())?.groupValues?.get(1).toString() // direct mp4 link, https://m11.vudeo.net/2vp3ukyw2avjdohilpebtzuct42q5jwvpmpsez3xjs6d7fbs65dpuey2rbra/v.mp4 for exemple
|
||||||
return vudoUrl
|
return vudoUrl
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -95,7 +95,7 @@ class VidEmbedProvider : MainAPI() {
|
||||||
val description = soup.selectFirst(".post-entry")?.text()?.trim()
|
val description = soup.selectFirst(".post-entry")?.text()?.trim()
|
||||||
var poster: String? = null
|
var poster: String? = null
|
||||||
|
|
||||||
val episodes = soup.select(".listing.items.lists > .video-block").withIndex().map { (index, li) ->
|
val episodes = soup.select(".listing.items.lists > .video-block").withIndex().map { (_, li) ->
|
||||||
val epTitle = if (li.selectFirst(".name") != null)
|
val epTitle = if (li.selectFirst(".name") != null)
|
||||||
if (li.selectFirst(".name").text().contains("Episode"))
|
if (li.selectFirst(".name").text().contains("Episode"))
|
||||||
"Episode " + li.selectFirst(".name").text().split("Episode")[1].trim()
|
"Episode " + li.selectFirst(".name").text().split("Episode")[1].trim()
|
||||||
|
@ -162,7 +162,7 @@ class VidEmbedProvider : MainAPI() {
|
||||||
|
|
||||||
// This loads the homepage, which is basically a collection of search results with labels.
|
// This loads the homepage, which is basically a collection of search results with labels.
|
||||||
// Optional function, but make sure to enable hasMainPage if you program this.
|
// Optional function, but make sure to enable hasMainPage if you program this.
|
||||||
override fun getMainPage(): HomePageResponse? {
|
override fun getMainPage(): HomePageResponse {
|
||||||
val urls = listOf(
|
val urls = listOf(
|
||||||
mainUrl,
|
mainUrl,
|
||||||
"$mainUrl/movies",
|
"$mainUrl/movies",
|
||||||
|
@ -262,8 +262,8 @@ class VidEmbedProvider : MainAPI() {
|
||||||
|
|
||||||
// Having a referer is often required. It's a basic security check most providers have.
|
// Having a referer is often required. It's a basic security check most providers have.
|
||||||
// Try to replicate what your browser does.
|
// Try to replicate what your browser does.
|
||||||
val html = get(it.second, headers = mapOf("referer" to iframeLink)).text
|
val serverHtml = get(it.second, headers = mapOf("referer" to iframeLink)).text
|
||||||
sourceRegex.findAll(html).forEach { match ->
|
sourceRegex.findAll(serverHtml).forEach { match ->
|
||||||
callback.invoke(
|
callback.invoke(
|
||||||
ExtractorLink(
|
ExtractorLink(
|
||||||
this.name,
|
this.name,
|
||||||
|
@ -279,7 +279,7 @@ class VidEmbedProvider : MainAPI() {
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
trackRegex.findAll(html).forEach { match ->
|
trackRegex.findAll(serverHtml).forEach { match ->
|
||||||
subtitleCallback.invoke(
|
subtitleCallback.invoke(
|
||||||
SubtitleFile(
|
SubtitleFile(
|
||||||
match.groupValues.getOrNull(2) ?: "Unknown",
|
match.groupValues.getOrNull(2) ?: "Unknown",
|
||||||
|
|
|
@ -5,7 +5,6 @@ import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
|
|
||||||
|
|
||||||
class VideoDownloadRestartReceiver : BroadcastReceiver() {
|
class VideoDownloadRestartReceiver : BroadcastReceiver() {
|
||||||
override fun onReceive(context: Context?, intent: Intent?) {
|
override fun onReceive(context: Context?, intent: Intent?) {
|
||||||
Log.i("Broadcast Listened", "Service tried to stop")
|
Log.i("Broadcast Listened", "Service tried to stop")
|
||||||
|
|
|
@ -28,15 +28,12 @@ import com.lagradost.cloudstream3.sortUrls
|
||||||
import com.lagradost.cloudstream3.ui.result.ResultEpisode
|
import com.lagradost.cloudstream3.ui.result.ResultEpisode
|
||||||
import com.lagradost.cloudstream3.utils.CastHelper.awaitLinks
|
import com.lagradost.cloudstream3.utils.CastHelper.awaitLinks
|
||||||
import com.lagradost.cloudstream3.utils.CastHelper.getMediaInfo
|
import com.lagradost.cloudstream3.utils.CastHelper.getMediaInfo
|
||||||
import com.lagradost.cloudstream3.utils.Coroutines.main
|
|
||||||
import com.lagradost.cloudstream3.utils.DataStore.toKotlinObject
|
import com.lagradost.cloudstream3.utils.DataStore.toKotlinObject
|
||||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.withContext
|
|
||||||
import org.json.JSONObject
|
import org.json.JSONObject
|
||||||
import kotlin.concurrent.thread
|
import kotlin.concurrent.thread
|
||||||
|
|
||||||
class SkipOpController(val view: ImageView) : UIController() {
|
/*class SkipOpController(val view: ImageView) : UIController() {
|
||||||
init {
|
init {
|
||||||
view.setImageResource(R.drawable.exo_controls_fastforward)
|
view.setImageResource(R.drawable.exo_controls_fastforward)
|
||||||
view.setOnClickListener {
|
view.setOnClickListener {
|
||||||
|
@ -47,12 +44,12 @@ class SkipOpController(val view: ImageView) : UIController() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
|
|
||||||
private fun RemoteMediaClient.getItemIndex(): Int? {
|
private fun RemoteMediaClient.getItemIndex(): Int? {
|
||||||
return try {
|
return try {
|
||||||
val index = this.mediaQueue?.itemIds?.indexOf(this.currentItem?.itemId ?: 0)
|
val index = this.mediaQueue.itemIds.indexOf(this.currentItem?.itemId ?: 0)
|
||||||
if (index == null || index < 0) null else index
|
if (index < 0) null else index
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
@ -136,7 +133,7 @@ class SelectSourceController(val view: ImageView, val activity: ControllerActivi
|
||||||
|
|
||||||
subtitleList.setOnItemClickListener { _, _, which, _ ->
|
subtitleList.setOnItemClickListener { _, _, which, _ ->
|
||||||
if (which == 0) {
|
if (which == 0) {
|
||||||
remoteMediaClient.setActiveMediaTracks(longArrayOf()) // NO SUBS
|
remoteMediaClient?.setActiveMediaTracks(longArrayOf()) // NO SUBS
|
||||||
} else {
|
} else {
|
||||||
val font = TextTrackStyle()
|
val font = TextTrackStyle()
|
||||||
font.fontFamily = "Google Sans" //TODO FONT SETTINGS
|
font.fontFamily = "Google Sans" //TODO FONT SETTINGS
|
||||||
|
@ -147,10 +144,10 @@ class SelectSourceController(val view: ImageView, val activity: ControllerActivi
|
||||||
font.foregroundColor = Color.WHITE
|
font.foregroundColor = Color.WHITE
|
||||||
font.fontScale = 1.05f
|
font.fontScale = 1.05f
|
||||||
|
|
||||||
remoteMediaClient.setTextTrackStyle(font)
|
remoteMediaClient?.setTextTrackStyle(font)
|
||||||
|
|
||||||
remoteMediaClient.setActiveMediaTracks(longArrayOf(subTracks[which - 1].id))
|
remoteMediaClient?.setActiveMediaTracks(longArrayOf(subTracks[which - 1].id))
|
||||||
.setResultCallback {
|
?.setResultCallback {
|
||||||
if (!it.status.isSuccess) {
|
if (!it.status.isSuccess) {
|
||||||
Log.e(
|
Log.e(
|
||||||
"CHROMECAST", "Failed with status code:" +
|
"CHROMECAST", "Failed with status code:" +
|
||||||
|
@ -332,7 +329,9 @@ class SelectSourceController(val view: ImageView, val activity: ControllerActivi
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onSessionConnected(castSession: CastSession?) {
|
override fun onSessionConnected(castSession: CastSession?) {
|
||||||
super.onSessionConnected(castSession)
|
castSession?.let {
|
||||||
|
super.onSessionConnected(it)
|
||||||
|
}
|
||||||
remoteMediaClient?.queueSetRepeatMode(REPEAT_MODE_REPEAT_OFF, JSONObject())
|
remoteMediaClient?.queueSetRepeatMode(REPEAT_MODE_REPEAT_OFF, JSONObject())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,7 +54,7 @@ class DownloadChildFragment : Fragment() {
|
||||||
?: return@mapNotNull null
|
?: return@mapNotNull null
|
||||||
VisualDownloadChildCached(info.fileLength, info.totalBytes, it)
|
VisualDownloadChildCached(info.fileLength, info.totalBytes, it)
|
||||||
}
|
}
|
||||||
}
|
}.sortedBy { it.data.episode + (it.data.season?: 0)*100000 }
|
||||||
if (eps.isEmpty()) {
|
if (eps.isEmpty()) {
|
||||||
activity?.onBackPressed()
|
activity?.onBackPressed()
|
||||||
return@main
|
return@main
|
||||||
|
|
|
@ -102,10 +102,7 @@ class DownloadFragment : Fragment() {
|
||||||
} else {
|
} else {
|
||||||
val folder = getFolderName(DOWNLOAD_EPISODE_CACHE, click.data.id.toString())
|
val folder = getFolderName(DOWNLOAD_EPISODE_CACHE, click.data.id.toString())
|
||||||
val navController = activity?.findNavController(R.id.nav_host_fragment)
|
val navController = activity?.findNavController(R.id.nav_host_fragment)
|
||||||
navController?.navigate(R.id.navigation_download_child, Bundle().apply {
|
navController?.navigate(R.id.navigation_download_child, DownloadChildFragment.newInstance(click.data.name,folder))
|
||||||
putString("folder", folder)
|
|
||||||
putString("name", click.data.name)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{ downloadClickEvent ->
|
{ downloadClickEvent ->
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
package com.lagradost.cloudstream3.ui.download
|
package com.lagradost.cloudstream3.ui.download
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
|
|
@ -13,7 +13,6 @@ import com.lagradost.cloudstream3.SearchResponse
|
||||||
import com.lagradost.cloudstream3.mvvm.Resource
|
import com.lagradost.cloudstream3.mvvm.Resource
|
||||||
import com.lagradost.cloudstream3.ui.APIRepository
|
import com.lagradost.cloudstream3.ui.APIRepository
|
||||||
import com.lagradost.cloudstream3.ui.APIRepository.Companion.noneApi
|
import com.lagradost.cloudstream3.ui.APIRepository.Companion.noneApi
|
||||||
import com.lagradost.cloudstream3.ui.APIRepository.Companion.noneRepo
|
|
||||||
import com.lagradost.cloudstream3.ui.APIRepository.Companion.randomApi
|
import com.lagradost.cloudstream3.ui.APIRepository.Companion.randomApi
|
||||||
import com.lagradost.cloudstream3.ui.WatchType
|
import com.lagradost.cloudstream3.ui.WatchType
|
||||||
import com.lagradost.cloudstream3.utils.DOWNLOAD_HEADER_CACHE
|
import com.lagradost.cloudstream3.utils.DOWNLOAD_HEADER_CACHE
|
||||||
|
|
|
@ -33,7 +33,6 @@ import android.widget.*
|
||||||
import android.widget.Toast.LENGTH_SHORT
|
import android.widget.Toast.LENGTH_SHORT
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.core.net.toUri
|
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
|
@ -47,7 +46,6 @@ import com.fasterxml.jackson.module.kotlin.KotlinModule
|
||||||
import com.fasterxml.jackson.module.kotlin.readValue
|
import com.fasterxml.jackson.module.kotlin.readValue
|
||||||
import com.google.android.exoplayer2.*
|
import com.google.android.exoplayer2.*
|
||||||
import com.google.android.exoplayer2.C.TIME_UNSET
|
import com.google.android.exoplayer2.C.TIME_UNSET
|
||||||
import com.google.android.exoplayer2.PlaybackException.ERROR_CODE_AUDIO_TRACK_INIT_FAILED
|
|
||||||
import com.google.android.exoplayer2.database.ExoDatabaseProvider
|
import com.google.android.exoplayer2.database.ExoDatabaseProvider
|
||||||
import com.google.android.exoplayer2.source.DefaultMediaSourceFactory
|
import com.google.android.exoplayer2.source.DefaultMediaSourceFactory
|
||||||
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector
|
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector
|
||||||
|
@ -247,8 +245,6 @@ class PlayerFragment : Fragment() {
|
||||||
private lateinit var playerData: PlayerData
|
private lateinit var playerData: PlayerData
|
||||||
private lateinit var uriData: UriData
|
private lateinit var uriData: UriData
|
||||||
private var isDownloadedFile = false
|
private var isDownloadedFile = false
|
||||||
private var downloadId = 0
|
|
||||||
private var isLoading = true
|
|
||||||
private var isShowing = true
|
private var isShowing = true
|
||||||
private lateinit var exoPlayer: SimpleExoPlayer
|
private lateinit var exoPlayer: SimpleExoPlayer
|
||||||
|
|
||||||
|
@ -748,8 +744,6 @@ class PlayerFragment : Fragment() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private var volumeObserver: SettingsContentObserver? = null
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun String.toSubtitleMimeType(): String {
|
fun String.toSubtitleMimeType(): String {
|
||||||
return when {
|
return when {
|
||||||
|
@ -764,7 +758,6 @@ class PlayerFragment : Fragment() {
|
||||||
return Bundle().apply {
|
return Bundle().apply {
|
||||||
//println(data)
|
//println(data)
|
||||||
putString("data", mapper.writeValueAsString(data))
|
putString("data", mapper.writeValueAsString(data))
|
||||||
println("PUT START: " + startPos)
|
|
||||||
if (startPos != null) {
|
if (startPos != null) {
|
||||||
putLong(STATE_RESUME_POSITION, startPos)
|
putLong(STATE_RESUME_POSITION, startPos)
|
||||||
}
|
}
|
||||||
|
@ -1042,88 +1035,89 @@ class PlayerFragment : Fragment() {
|
||||||
exoPlayer.play()
|
exoPlayer.play()
|
||||||
}
|
}
|
||||||
}*/
|
}*/
|
||||||
|
activity?.let { act ->
|
||||||
|
if (act.isCastApiAvailable() && !isDownloadedFile) {
|
||||||
|
try {
|
||||||
|
CastButtonFactory.setUpMediaRouteButton(act, player_media_route_button)
|
||||||
|
val castContext = CastContext.getSharedInstance(requireContext())
|
||||||
|
|
||||||
if (activity?.isCastApiAvailable() == true && !isDownloadedFile) {
|
if (castContext.castState != CastState.NO_DEVICES_AVAILABLE) player_media_route_button.visibility =
|
||||||
try {
|
VISIBLE
|
||||||
CastButtonFactory.setUpMediaRouteButton(activity, player_media_route_button)
|
castContext.addCastStateListener { state ->
|
||||||
val castContext = CastContext.getSharedInstance(requireContext())
|
if (player_media_route_button != null) {
|
||||||
|
player_media_route_button.isVisible = state != CastState.NO_DEVICES_AVAILABLE
|
||||||
|
|
||||||
if (castContext.castState != CastState.NO_DEVICES_AVAILABLE) player_media_route_button.visibility = VISIBLE
|
if (state == CastState.CONNECTED) {
|
||||||
castContext.addCastStateListener { state ->
|
if (!this::exoPlayer.isInitialized) return@addCastStateListener
|
||||||
if (player_media_route_button != null) {
|
val links = sortUrls(getUrls() ?: return@addCastStateListener)
|
||||||
player_media_route_button.isVisible = state != CastState.NO_DEVICES_AVAILABLE
|
val epData = getEpisode() ?: return@addCastStateListener
|
||||||
|
|
||||||
if (state == CastState.CONNECTED) {
|
val index = links.indexOf(getCurrentUrl())
|
||||||
if (!this::exoPlayer.isInitialized) return@addCastStateListener
|
activity?.getCastSession()?.startCast(
|
||||||
val links = sortUrls(getUrls() ?: return@addCastStateListener)
|
apiName,
|
||||||
val epData = getEpisode() ?: return@addCastStateListener
|
currentIsMovie ?: return@addCastStateListener,
|
||||||
|
currentHeaderName,
|
||||||
|
currentPoster,
|
||||||
|
epData.index,
|
||||||
|
episodes,
|
||||||
|
links,
|
||||||
|
context?.getSubs(supportsDownloadedFiles = false) ?: emptyList(),
|
||||||
|
index,
|
||||||
|
exoPlayer.currentPosition
|
||||||
|
)
|
||||||
|
|
||||||
val index = links.indexOf(getCurrentUrl())
|
/*
|
||||||
activity?.getCastSession()?.startCast(
|
val customData =
|
||||||
apiName,
|
links.map { JSONObject().put("name", it.name) }
|
||||||
currentIsMovie ?: return@addCastStateListener,
|
val jsonArray = JSONArray()
|
||||||
currentHeaderName,
|
for (item in customData) {
|
||||||
currentPoster,
|
jsonArray.put(item)
|
||||||
epData.index,
|
|
||||||
episodes,
|
|
||||||
links,
|
|
||||||
context?.getSubs(supportsDownloadedFiles = false) ?: emptyList(),
|
|
||||||
index,
|
|
||||||
exoPlayer.currentPosition
|
|
||||||
)
|
|
||||||
|
|
||||||
/*
|
|
||||||
val customData =
|
|
||||||
links.map { JSONObject().put("name", it.name) }
|
|
||||||
val jsonArray = JSONArray()
|
|
||||||
for (item in customData) {
|
|
||||||
jsonArray.put(item)
|
|
||||||
}
|
|
||||||
|
|
||||||
val mediaItems = links.map {
|
|
||||||
val movieMetadata = MediaMetadata(MediaMetadata.MEDIA_TYPE_MOVIE)
|
|
||||||
|
|
||||||
movieMetadata.putString(MediaMetadata.KEY_SUBTITLE,
|
|
||||||
epData.name ?: "Episode ${epData.episode}")
|
|
||||||
|
|
||||||
if (currentHeaderName != null)
|
|
||||||
movieMetadata.putString(MediaMetadata.KEY_TITLE, currentHeaderName)
|
|
||||||
|
|
||||||
val srcPoster = epData.poster ?: currentPoster
|
|
||||||
if (srcPoster != null) {
|
|
||||||
movieMetadata.addImage(WebImage(Uri.parse(srcPoster)))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MediaQueueItem.Builder(
|
val mediaItems = links.map {
|
||||||
MediaInfo.Builder(it.url)
|
val movieMetadata = MediaMetadata(MediaMetadata.MEDIA_TYPE_MOVIE)
|
||||||
.setStreamType(MediaInfo.STREAM_TYPE_BUFFERED)
|
|
||||||
.setContentType(MimeTypes.VIDEO_UNKNOWN)
|
|
||||||
|
|
||||||
.setCustomData(JSONObject().put("data", jsonArray))
|
movieMetadata.putString(MediaMetadata.KEY_SUBTITLE,
|
||||||
.setMetadata(movieMetadata)
|
epData.name ?: "Episode ${epData.episode}")
|
||||||
|
|
||||||
|
if (currentHeaderName != null)
|
||||||
|
movieMetadata.putString(MediaMetadata.KEY_TITLE, currentHeaderName)
|
||||||
|
|
||||||
|
val srcPoster = epData.poster ?: currentPoster
|
||||||
|
if (srcPoster != null) {
|
||||||
|
movieMetadata.addImage(WebImage(Uri.parse(srcPoster)))
|
||||||
|
}
|
||||||
|
|
||||||
|
MediaQueueItem.Builder(
|
||||||
|
MediaInfo.Builder(it.url)
|
||||||
|
.setStreamType(MediaInfo.STREAM_TYPE_BUFFERED)
|
||||||
|
.setContentType(MimeTypes.VIDEO_UNKNOWN)
|
||||||
|
|
||||||
|
.setCustomData(JSONObject().put("data", jsonArray))
|
||||||
|
.setMetadata(movieMetadata)
|
||||||
|
.build()
|
||||||
|
)
|
||||||
.build()
|
.build()
|
||||||
)
|
}.toTypedArray()
|
||||||
.build()
|
|
||||||
}.toTypedArray()
|
|
||||||
|
|
||||||
val castPlayer = CastPlayer(castContext)
|
val castPlayer = CastPlayer(castContext)
|
||||||
castPlayer.loadItems(
|
castPlayer.loadItems(
|
||||||
mediaItems,
|
mediaItems,
|
||||||
if (index > 0) index else 0,
|
if (index > 0) index else 0,
|
||||||
exoPlayer.currentPosition,
|
exoPlayer.currentPosition,
|
||||||
MediaStatus.REPEAT_MODE_REPEAT_SINGLE
|
MediaStatus.REPEAT_MODE_REPEAT_SINGLE
|
||||||
)*/
|
)*/
|
||||||
// activity?.popCurrentPage(isInPlayer = true, isInExpandedView = false, isInResults = false)
|
// activity?.popCurrentPage(isInPlayer = true, isInExpandedView = false, isInResults = false)
|
||||||
safeReleasePlayer()
|
safeReleasePlayer()
|
||||||
activity?.popCurrentPage()
|
activity?.popCurrentPage()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
logError(e)
|
||||||
}
|
}
|
||||||
} catch (e : Exception) {
|
|
||||||
logError(e)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
isDownloadedFile = false
|
isDownloadedFile = false
|
||||||
arguments?.getString("uriData")?.let {
|
arguments?.getString("uriData")?.let {
|
||||||
uriData = mapper.readValue(it)
|
uriData = mapper.readValue(it)
|
||||||
|
@ -1159,7 +1153,7 @@ class PlayerFragment : Fragment() {
|
||||||
|
|
||||||
activity?.let {
|
activity?.let {
|
||||||
it.contentResolver?.registerContentObserver(
|
it.contentResolver?.registerContentObserver(
|
||||||
android.provider.Settings.System.CONTENT_URI, true, SettingsContentObserver(
|
Settings.System.CONTENT_URI, true, SettingsContentObserver(
|
||||||
Handler(
|
Handler(
|
||||||
Looper.getMainLooper()
|
Looper.getMainLooper()
|
||||||
), it
|
), it
|
||||||
|
@ -1172,13 +1166,13 @@ class PlayerFragment : Fragment() {
|
||||||
|
|
||||||
observeDirectly(viewModel.episodes) { _episodes ->
|
observeDirectly(viewModel.episodes) { _episodes ->
|
||||||
episodes = _episodes
|
episodes = _episodes
|
||||||
if (isLoading) {
|
/*if (isLoading) {
|
||||||
/*if (playerData.episodeIndex > 0 && playerData.episodeIndex < episodes.size) {
|
if (playerData.episodeIndex > 0 && playerData.episodeIndex < episodes.size) {
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// WHAT THE FUCK DID YOU DO
|
// WHAT THE FUCK DID YOU DO
|
||||||
}*/
|
}
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
observe(viewModel.apiName) {
|
observe(viewModel.apiName) {
|
||||||
|
@ -1485,7 +1479,7 @@ class PlayerFragment : Fragment() {
|
||||||
requireContext().setKey(RESIZE_MODE_KEY, resizeMode)
|
requireContext().setKey(RESIZE_MODE_KEY, resizeMode)
|
||||||
player_view.resizeMode = resizeModes[resizeMode].first
|
player_view.resizeMode = resizeModes[resizeMode].first
|
||||||
activity?.let { act ->
|
activity?.let { act ->
|
||||||
showToast(act, resizeModes[resizeMode].second, Toast.LENGTH_SHORT);
|
showToast(act, resizeModes[resizeMode].second, LENGTH_SHORT)
|
||||||
}
|
}
|
||||||
//exoPlayer.videoScalingMode = C.VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING
|
//exoPlayer.videoScalingMode = C.VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING
|
||||||
}
|
}
|
||||||
|
@ -1508,18 +1502,6 @@ class PlayerFragment : Fragment() {
|
||||||
// initPlayer()
|
// initPlayer()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getRendererIndex(trackIndex: Int): Int? {
|
|
||||||
if (!this::exoPlayer.isInitialized) return null
|
|
||||||
|
|
||||||
for (renderIndex in 0 until exoPlayer.rendererCount) {
|
|
||||||
if (exoPlayer.getRendererType(renderIndex) == renderIndex) {
|
|
||||||
return renderIndex
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getCurrentUrl(): ExtractorLink? {
|
private fun getCurrentUrl(): ExtractorLink? {
|
||||||
val urls = getUrls() ?: return null
|
val urls = getUrls() ?: return null
|
||||||
for (i in urls) {
|
for (i in urls) {
|
||||||
|
@ -2067,7 +2049,11 @@ class PlayerFragment : Fragment() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PlaybackException.ERROR_CODE_REMOTE_ERROR, PlaybackException.ERROR_CODE_IO_BAD_HTTP_STATUS, PlaybackException.ERROR_CODE_TIMEOUT, PlaybackException.ERROR_CODE_IO_NETWORK_CONNECTION_FAILED, PlaybackException.ERROR_CODE_IO_INVALID_HTTP_CONTENT_TYPE -> {
|
PlaybackException.ERROR_CODE_REMOTE_ERROR, PlaybackException.ERROR_CODE_IO_BAD_HTTP_STATUS, PlaybackException.ERROR_CODE_TIMEOUT, PlaybackException.ERROR_CODE_IO_NETWORK_CONNECTION_FAILED, PlaybackException.ERROR_CODE_IO_INVALID_HTTP_CONTENT_TYPE -> {
|
||||||
showToast(activity, "${getString(R.string.remote_error)}\n$errorName ($code)\n$msg", LENGTH_SHORT)
|
showToast(
|
||||||
|
activity,
|
||||||
|
"${getString(R.string.remote_error)}\n$errorName ($code)\n$msg",
|
||||||
|
LENGTH_SHORT
|
||||||
|
)
|
||||||
}
|
}
|
||||||
PlaybackException.ERROR_CODE_DECODING_FAILED, PlaybackErrorEvent.ERROR_AUDIO_TRACK_INIT_FAILED, PlaybackErrorEvent.ERROR_AUDIO_TRACK_OTHER, PlaybackException.ERROR_CODE_AUDIO_TRACK_WRITE_FAILED, PlaybackException.ERROR_CODE_DECODER_INIT_FAILED, PlaybackException.ERROR_CODE_DECODER_QUERY_FAILED -> {
|
PlaybackException.ERROR_CODE_DECODING_FAILED, PlaybackErrorEvent.ERROR_AUDIO_TRACK_INIT_FAILED, PlaybackErrorEvent.ERROR_AUDIO_TRACK_OTHER, PlaybackException.ERROR_CODE_AUDIO_TRACK_WRITE_FAILED, PlaybackException.ERROR_CODE_DECODER_INIT_FAILED, PlaybackException.ERROR_CODE_DECODER_QUERY_FAILED -> {
|
||||||
showToast(
|
showToast(
|
||||||
|
|
|
@ -280,7 +280,7 @@ class ResultViewModel : ViewModel() {
|
||||||
if (dataList != null) { // TODO dub and sub at the same time
|
if (dataList != null) { // TODO dub and sub at the same time
|
||||||
val episodes = ArrayList<ResultEpisode>()
|
val episodes = ArrayList<ResultEpisode>()
|
||||||
for ((index, i) in dataList.withIndex()) {
|
for ((index, i) in dataList.withIndex()) {
|
||||||
val episode = i.episode ?: (index + 1);
|
val episode = i.episode ?: (index + 1)
|
||||||
episodes.add(
|
episodes.add(
|
||||||
context.buildResultEpisode(
|
context.buildResultEpisode(
|
||||||
filterName(i.name),
|
filterName(i.name),
|
||||||
|
|
|
@ -72,7 +72,7 @@ object CastHelper {
|
||||||
if (pending == null) return
|
if (pending == null) return
|
||||||
main {
|
main {
|
||||||
val res = withContext(Dispatchers.IO) { pending.await() }
|
val res = withContext(Dispatchers.IO) { pending.await() }
|
||||||
when (res.status?.statusCode) {
|
when (res.status.statusCode) {
|
||||||
CastStatusCodes.FAILED -> {
|
CastStatusCodes.FAILED -> {
|
||||||
callback.invoke(true)
|
callback.invoke(true)
|
||||||
println("FAILED AND LOAD NEXT")
|
println("FAILED AND LOAD NEXT")
|
||||||
|
|
|
@ -10,7 +10,6 @@ import com.lagradost.cloudstream3.utils.DataStore.getKey
|
||||||
import com.lagradost.cloudstream3.utils.DataStore.removeKey
|
import com.lagradost.cloudstream3.utils.DataStore.removeKey
|
||||||
import com.lagradost.cloudstream3.utils.VideoDownloadManager.WORK_KEY_INFO
|
import com.lagradost.cloudstream3.utils.VideoDownloadManager.WORK_KEY_INFO
|
||||||
import com.lagradost.cloudstream3.utils.VideoDownloadManager.WORK_KEY_PACKAGE
|
import com.lagradost.cloudstream3.utils.VideoDownloadManager.WORK_KEY_PACKAGE
|
||||||
import com.lagradost.cloudstream3.utils.VideoDownloadManager.createNotification
|
|
||||||
import com.lagradost.cloudstream3.utils.VideoDownloadManager.downloadCheck
|
import com.lagradost.cloudstream3.utils.VideoDownloadManager.downloadCheck
|
||||||
import com.lagradost.cloudstream3.utils.VideoDownloadManager.downloadEpisode
|
import com.lagradost.cloudstream3.utils.VideoDownloadManager.downloadEpisode
|
||||||
import com.lagradost.cloudstream3.utils.VideoDownloadManager.downloadFromResume
|
import com.lagradost.cloudstream3.utils.VideoDownloadManager.downloadFromResume
|
||||||
|
|
|
@ -1,9 +1,5 @@
|
||||||
package com.lagradost.cloudstream3.utils
|
package com.lagradost.cloudstream3.utils
|
||||||
|
|
||||||
import com.lagradost.cloudstream3.mvvm.logError
|
|
||||||
import java.lang.Exception
|
|
||||||
import java.lang.StringBuilder
|
|
||||||
import java.util.HashMap
|
|
||||||
import java.util.regex.Pattern
|
import java.util.regex.Pattern
|
||||||
import kotlin.math.pow
|
import kotlin.math.pow
|
||||||
|
|
||||||
|
|
|
@ -85,7 +85,7 @@ class M3u8Helper {
|
||||||
|
|
||||||
for (match in QUALITY_REGEX.findAll(response)) {
|
for (match in QUALITY_REGEX.findAll(response)) {
|
||||||
var (quality, m3u8Link, m3u8Link2) = match.destructured
|
var (quality, m3u8Link, m3u8Link2) = match.destructured
|
||||||
if (m3u8Link.isNullOrEmpty()) m3u8Link = m3u8Link2
|
if (m3u8Link.isEmpty()) m3u8Link = m3u8Link2
|
||||||
if (absoluteExtensionDetermination(m3u8Link) == "m3u8") {
|
if (absoluteExtensionDetermination(m3u8Link) == "m3u8") {
|
||||||
if (isNotCompleteUrl(m3u8Link)) {
|
if (isNotCompleteUrl(m3u8Link)) {
|
||||||
m3u8Link = "$m3u8Parent/$m3u8Link"
|
m3u8Link = "$m3u8Parent/$m3u8Link"
|
||||||
|
@ -138,7 +138,7 @@ class M3u8Helper {
|
||||||
if (secondSelection != null) {
|
if (secondSelection != null) {
|
||||||
val m3u8Response = get(secondSelection.streamUrl, headers = headers).text
|
val m3u8Response = get(secondSelection.streamUrl, headers = headers).text
|
||||||
|
|
||||||
var encryptionUri: String? = null
|
var encryptionUri: String?
|
||||||
var encryptionIv = byteArrayOf()
|
var encryptionIv = byteArrayOf()
|
||||||
var encryptionData = byteArrayOf()
|
var encryptionData = byteArrayOf()
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,6 @@ package com.lagradost.cloudstream3.utils
|
||||||
|
|
||||||
import android.app.Dialog
|
import android.app.Dialog
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.view.View
|
|
||||||
import android.widget.*
|
import android.widget.*
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
|
@ -10,9 +9,7 @@ import androidx.core.view.marginLeft
|
||||||
import androidx.core.view.marginRight
|
import androidx.core.view.marginRight
|
||||||
import androidx.core.view.marginTop
|
import androidx.core.view.marginTop
|
||||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||||
import com.lagradost.cloudstream3.MainActivity.Companion.updateLocale
|
|
||||||
import com.lagradost.cloudstream3.R
|
import com.lagradost.cloudstream3.R
|
||||||
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showDialog
|
|
||||||
|
|
||||||
object SingleSelectionHelper {
|
object SingleSelectionHelper {
|
||||||
fun Context.showDialog(
|
fun Context.showDialog(
|
||||||
|
|
|
@ -16,7 +16,7 @@ object SubtitleHelper {
|
||||||
val ISO_639_6: String,
|
val ISO_639_6: String,
|
||||||
)
|
)
|
||||||
|
|
||||||
fun createISO() {
|
/*fun createISO() {
|
||||||
val url = "https://infogalactic.com/info/List_of_ISO_639-1_codes"
|
val url = "https://infogalactic.com/info/List_of_ISO_639-1_codes"
|
||||||
val response = get(url).text
|
val response = get(url).text
|
||||||
val document = Jsoup.parse(response)
|
val document = Jsoup.parse(response)
|
||||||
|
@ -40,7 +40,7 @@ object SubtitleHelper {
|
||||||
}
|
}
|
||||||
text += ")"
|
text += ")"
|
||||||
println("ISO CREATED:\n$text")
|
println("ISO CREATED:\n$text")
|
||||||
}
|
}*/
|
||||||
|
|
||||||
/** lang -> ISO_639_1*/
|
/** lang -> ISO_639_1*/
|
||||||
fun fromLanguageToTwoLetters(input: String): String? {
|
fun fromLanguageToTwoLetters(input: String): String? {
|
||||||
|
|
|
@ -661,10 +661,9 @@ object VideoDownloadManager {
|
||||||
|
|
||||||
val contentLength = try {
|
val contentLength = try {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { // fuck android
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { // fuck android
|
||||||
connection.contentLengthLong ?: 0L
|
connection.contentLengthLong
|
||||||
} else {
|
} else {
|
||||||
connection.getHeaderField("content-length").toLongOrNull() ?: connection.contentLength?.toLong()
|
connection.getHeaderField("content-length").toLongOrNull() ?: connection.contentLength.toLong()
|
||||||
?: 0L
|
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
logError(e)
|
logError(e)
|
||||||
|
|
|
@ -1,17 +0,0 @@
|
||||||
package com.lagradost.cloudstream3
|
|
||||||
|
|
||||||
import org.junit.Test
|
|
||||||
|
|
||||||
import org.junit.Assert.*
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Example local unit test, which will execute on the development machine (host).
|
|
||||||
*
|
|
||||||
* See [testing documentation](http://d.android.com/tools/testing).
|
|
||||||
*/
|
|
||||||
class ExampleUnitTest {
|
|
||||||
@Test
|
|
||||||
fun addition_isCorrect() {
|
|
||||||
assertEquals(4, 2 + 2)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -13,6 +13,115 @@ class ProviderTests {
|
||||||
return allApis
|
return allApis
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun loadLinks(api: MainAPI, url: String?): Boolean {
|
||||||
|
Assert.assertNotNull("Api ${api.name} has invalid url on episode", url)
|
||||||
|
if (url == null) return true
|
||||||
|
var linksLoaded = 0
|
||||||
|
try {
|
||||||
|
val success = api.loadLinks(url, false, {}) { link ->
|
||||||
|
Assert.assertTrue(
|
||||||
|
"Api ${api.name} returns link with invalid Quality",
|
||||||
|
Qualities.values().map { it.value }.contains(link.quality)
|
||||||
|
)
|
||||||
|
Assert.assertTrue("Api ${api.name} returns link with invalid url", link.url.length > 4)
|
||||||
|
linksLoaded++
|
||||||
|
}
|
||||||
|
if (success) {
|
||||||
|
return linksLoaded > 0
|
||||||
|
}
|
||||||
|
Assert.assertTrue("Api ${api.name} has returns false on .loadLinks", success)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
if (e.cause is NotImplementedError) {
|
||||||
|
Assert.fail("Provider has not implemented .loadLinks")
|
||||||
|
}
|
||||||
|
logError(e)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun test_single_provider(api: MainAPI) {
|
||||||
|
val searchQueries = listOf("over", "iron", "guy")
|
||||||
|
var correctResponses = 0
|
||||||
|
var searchResult: List<SearchResponse>? = null
|
||||||
|
for (query in searchQueries) {
|
||||||
|
val response = try {
|
||||||
|
api.search(query)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
if (e.cause is NotImplementedError) {
|
||||||
|
Assert.fail("Provider has not implemented .search")
|
||||||
|
}
|
||||||
|
logError(e)
|
||||||
|
null
|
||||||
|
}
|
||||||
|
if (!response.isNullOrEmpty()) {
|
||||||
|
correctResponses++
|
||||||
|
if (searchResult == null) {
|
||||||
|
searchResult = response
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (correctResponses == 0 || searchResult == null) {
|
||||||
|
println("Api ${api.name} did not return any valid search responses")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
var validResults = false
|
||||||
|
for (result in searchResult) {
|
||||||
|
Assert.assertEquals("Invalid apiName on response on ${api.name}", result.apiName, api.name)
|
||||||
|
val load = api.load(result.url) ?: continue
|
||||||
|
Assert.assertEquals("Invalid apiName on load on ${api.name}", load.apiName, result.apiName)
|
||||||
|
Assert.assertTrue(
|
||||||
|
"Api ${api.name} on load does not contain any of the supportedTypes",
|
||||||
|
api.supportedTypes.contains(load.type)
|
||||||
|
)
|
||||||
|
when (load) {
|
||||||
|
is AnimeLoadResponse -> {
|
||||||
|
val gotNoEpisodes =
|
||||||
|
load.dubEpisodes.isNullOrEmpty() && load.subEpisodes.isNullOrEmpty()
|
||||||
|
if (gotNoEpisodes) {
|
||||||
|
println("Api ${api.name} got no episodes on ${load.url}")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
val url = (load.dubEpisodes ?: load.subEpisodes)?.first()?.url
|
||||||
|
validResults = loadLinks(api, url)
|
||||||
|
if (!validResults) continue
|
||||||
|
}
|
||||||
|
is MovieLoadResponse -> {
|
||||||
|
val gotNoEpisodes = load.dataUrl.isBlank()
|
||||||
|
if (gotNoEpisodes) {
|
||||||
|
println("Api ${api.name} got no movie on ${load.url}")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
validResults = loadLinks(api, load.dataUrl)
|
||||||
|
if (!validResults) continue
|
||||||
|
}
|
||||||
|
is TvSeriesLoadResponse -> {
|
||||||
|
val gotNoEpisodes = load.episodes.isEmpty()
|
||||||
|
if (gotNoEpisodes) {
|
||||||
|
println("Api ${api.name} got no episodes on ${load.url}")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
validResults = loadLinks(api, load.episodes.first().data)
|
||||||
|
if (!validResults) continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.assertTrue("Api ${api.name} did not load on any}", validResults)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
if (e.cause is NotImplementedError) {
|
||||||
|
Assert.fail("Provider has not implemented .load")
|
||||||
|
}
|
||||||
|
logError(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun providers_exist() {
|
fun providers_exist() {
|
||||||
Assert.assertTrue(getAllProviders().isNotEmpty())
|
Assert.assertTrue(getAllProviders().isNotEmpty())
|
||||||
|
@ -23,7 +132,7 @@ class ProviderTests {
|
||||||
val isoNames = SubtitleHelper.languages.map { it.ISO_639_1 }
|
val isoNames = SubtitleHelper.languages.map { it.ISO_639_1 }
|
||||||
Assert.assertFalse("ISO does not contain any languages", isoNames.isNullOrEmpty())
|
Assert.assertFalse("ISO does not contain any languages", isoNames.isNullOrEmpty())
|
||||||
for (api in getAllProviders()) {
|
for (api in getAllProviders()) {
|
||||||
Assert.assertTrue("Api does not contain a mainurl", api.mainUrl != "NONE")
|
Assert.assertTrue("Api does not contain a mainUrl", api.mainUrl != "NONE")
|
||||||
Assert.assertTrue("Api does not contain a name", api.name != "NONE")
|
Assert.assertTrue("Api does not contain a name", api.name != "NONE")
|
||||||
Assert.assertTrue("Api ${api.name} does not contain a valid language code", isoNames.contains(api.lang))
|
Assert.assertTrue("Api ${api.name} does not contain a valid language code", isoNames.contains(api.lang))
|
||||||
Assert.assertTrue("Api ${api.name} does not contain any supported types", api.supportedTypes.isNotEmpty())
|
Assert.assertTrue("Api ${api.name} does not contain any supported types", api.supportedTypes.isNotEmpty())
|
||||||
|
@ -57,118 +166,13 @@ class ProviderTests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun loadLinks(api: MainAPI, url: String?): Boolean {
|
|
||||||
Assert.assertNotNull("Api ${api.name} has invalid url on episode", url)
|
|
||||||
if (url == null) return true
|
|
||||||
var linksLoaded = 0
|
|
||||||
try {
|
|
||||||
val success = api.loadLinks(url, false, {}) { link ->
|
|
||||||
Assert.assertTrue(
|
|
||||||
"Api ${api.name} returns link with invalid Quality",
|
|
||||||
Qualities.values().map { it.value }.contains(link.quality)
|
|
||||||
)
|
|
||||||
Assert.assertTrue("Api ${api.name} returns link with invalid url", link.url.length > 4)
|
|
||||||
linksLoaded++
|
|
||||||
}
|
|
||||||
if (success) {
|
|
||||||
return linksLoaded > 0
|
|
||||||
}
|
|
||||||
Assert.assertTrue("Api ${api.name} has returns false on .loadLinks", success)
|
|
||||||
} catch (e: Exception) {
|
|
||||||
if (e.cause is NotImplementedError) {
|
|
||||||
Assert.fail("Provider has not implemented .loadLinks")
|
|
||||||
}
|
|
||||||
logError(e)
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun provider_correct() {
|
fun provider_correct() {
|
||||||
val searchQueries = listOf("over", "iron", "guy")
|
|
||||||
val providers = getAllProviders()
|
val providers = getAllProviders()
|
||||||
for ((index, api) in providers.withIndex()) {
|
for ((index, api) in providers.withIndex()) {
|
||||||
try {
|
try {
|
||||||
println("Trying $api (${index + 1}/${providers.size})")
|
println("Trying $api (${index + 1}/${providers.size})")
|
||||||
var correctResponses = 0
|
test_single_provider(api)
|
||||||
var searchResult: List<SearchResponse>? = null
|
|
||||||
for (query in searchQueries) {
|
|
||||||
val response = try {
|
|
||||||
api.search(query)
|
|
||||||
} catch (e: Exception) {
|
|
||||||
if (e.cause is NotImplementedError) {
|
|
||||||
Assert.fail("Provider has not implemented .search")
|
|
||||||
}
|
|
||||||
logError(e)
|
|
||||||
null
|
|
||||||
}
|
|
||||||
if (!response.isNullOrEmpty()) {
|
|
||||||
correctResponses++
|
|
||||||
if (searchResult == null) {
|
|
||||||
searchResult = response
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (correctResponses == 0 || searchResult == null) {
|
|
||||||
println("Api ${api.name} did not return any valid search responses")
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
var validResults = false
|
|
||||||
for (result in searchResult) {
|
|
||||||
Assert.assertEquals("Invalid apiName on response on ${api.name}", result.apiName, api.name)
|
|
||||||
val load = api.load(result.url) ?: continue
|
|
||||||
Assert.assertEquals("Invalid apiName on load on ${api.name}", load.apiName, result.apiName)
|
|
||||||
Assert.assertTrue(
|
|
||||||
"Api ${api.name} on load does not contain any of the supportedTypes",
|
|
||||||
api.supportedTypes.contains(load.type)
|
|
||||||
)
|
|
||||||
when (load) {
|
|
||||||
is AnimeLoadResponse -> {
|
|
||||||
val gotNoEpisodes =
|
|
||||||
load.dubEpisodes.isNullOrEmpty() && load.subEpisodes.isNullOrEmpty()
|
|
||||||
if (gotNoEpisodes) {
|
|
||||||
println("Api ${api.name} got no episodes on ${load.url}")
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
val url = (load.dubEpisodes ?: load.subEpisodes)?.first()?.url
|
|
||||||
validResults = loadLinks(api, url)
|
|
||||||
if (!validResults) continue
|
|
||||||
}
|
|
||||||
is MovieLoadResponse -> {
|
|
||||||
val gotNoEpisodes = load.dataUrl.isBlank()
|
|
||||||
if (gotNoEpisodes) {
|
|
||||||
println("Api ${api.name} got no movie on ${load.url}")
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
validResults = loadLinks(api, load.dataUrl)
|
|
||||||
if (!validResults) continue
|
|
||||||
}
|
|
||||||
is TvSeriesLoadResponse -> {
|
|
||||||
val gotNoEpisodes = load.episodes.isEmpty()
|
|
||||||
if (gotNoEpisodes) {
|
|
||||||
println("Api ${api.name} got no episodes on ${load.url}")
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
validResults = loadLinks(api, load.episodes.first().data)
|
|
||||||
if (!validResults) continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
Assert.assertTrue("Api ${api.name} did not load on any}", validResults)
|
|
||||||
} catch (e: Exception) {
|
|
||||||
if (e.cause is NotImplementedError) {
|
|
||||||
Assert.fail("Provider has not implemented .load")
|
|
||||||
}
|
|
||||||
logError(e)
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
logError(e)
|
logError(e)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue