forked from recloudstream/cloudstream
another provider and a bunch of bug fixes
This commit is contained in:
parent
9550154a49
commit
f1c563e3bc
12 changed files with 250 additions and 40 deletions
|
@ -12,9 +12,10 @@
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
android:icon="@mipmap/ic_launcher"
|
android:icon="@mipmap/ic_launcher"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
|
android:usesCleartextTraffic="true"
|
||||||
android:roundIcon="@mipmap/ic_launcher_round"
|
android:roundIcon="@mipmap/ic_launcher_round"
|
||||||
android:supportsRtl="true"
|
android:supportsRtl="true"
|
||||||
android:theme="@style/AppTheme" android:fullBackupContent="@xml/backup_descriptor">
|
android:theme="@style/AppTheme" android:fullBackupContent="@xml/backup_descriptor" tools:targetApi="m">
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="com.google.android.gms.cast.framework.OPTIONS_PROVIDER_CLASS_NAME"
|
android:name="com.google.android.gms.cast.framework.OPTIONS_PROVIDER_CLASS_NAME"
|
||||||
android:value="com.lagradost.cloudstream3.utils.CastOptionsProvider"/>
|
android:value="com.lagradost.cloudstream3.utils.CastOptionsProvider"/>
|
||||||
|
|
|
@ -6,6 +6,7 @@ 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.ShiroProvider
|
import com.lagradost.cloudstream3.animeproviders.ShiroProvider
|
||||||
|
import com.lagradost.cloudstream3.movieproviders.MeloMovieProvider
|
||||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import kotlin.collections.ArrayList
|
import kotlin.collections.ArrayList
|
||||||
|
@ -20,8 +21,9 @@ object APIHolder {
|
||||||
|
|
||||||
private const val defProvider = 0
|
private const val defProvider = 0
|
||||||
|
|
||||||
val apis = arrayListOf<MainAPI>(
|
val apis = arrayListOf(
|
||||||
ShiroProvider()
|
ShiroProvider(),
|
||||||
|
MeloMovieProvider(),
|
||||||
)
|
)
|
||||||
|
|
||||||
fun getApiFromName(apiName: String?): MainAPI {
|
fun getApiFromName(apiName: String?): MainAPI {
|
||||||
|
@ -44,6 +46,7 @@ object APIHolder {
|
||||||
abstract class MainAPI {
|
abstract class MainAPI {
|
||||||
open val name = "NONE"
|
open val name = "NONE"
|
||||||
open val mainUrl = "NONE"
|
open val mainUrl = "NONE"
|
||||||
|
open val instantLinkLoading = false // THIS IS IF THE LINK IS STORED IN THE "DATA"
|
||||||
open fun search(query: String): ArrayList<Any>? { // SearchResponse
|
open fun search(query: String): ArrayList<Any>? { // SearchResponse
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
@ -195,12 +198,14 @@ data class MovieLoadResponse(
|
||||||
val imdbId: Int?,
|
val imdbId: Int?,
|
||||||
) : LoadResponse
|
) : LoadResponse
|
||||||
|
|
||||||
|
data class TvSeriesEpisode(val name: String?, val season : Int?, val episode: Int?, val data : String)
|
||||||
|
|
||||||
data class TvSeriesLoadResponse(
|
data class TvSeriesLoadResponse(
|
||||||
override val name: String,
|
override val name: String,
|
||||||
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<String>,
|
val episodes: ArrayList<TvSeriesEpisode>,
|
||||||
|
|
||||||
override val posterUrl: String?,
|
override val posterUrl: String?,
|
||||||
override val year: Int?,
|
override val year: Int?,
|
||||||
|
|
|
@ -0,0 +1,155 @@
|
||||||
|
package com.lagradost.cloudstream3.movieproviders
|
||||||
|
|
||||||
|
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.getQualityFromName
|
||||||
|
import org.jsoup.Jsoup
|
||||||
|
import org.jsoup.nodes.Element
|
||||||
|
|
||||||
|
class MeloMovieProvider : MainAPI() {
|
||||||
|
override val name: String
|
||||||
|
get() = "MeloMovie"
|
||||||
|
override val mainUrl: String
|
||||||
|
get() = "https://melomovie.com"
|
||||||
|
override val instantLinkLoading: Boolean
|
||||||
|
get() = true
|
||||||
|
|
||||||
|
data class MeloMovieSearchResult(
|
||||||
|
@JsonProperty("id") val id: Int,
|
||||||
|
@JsonProperty("imdb_code") val imdbId: String,
|
||||||
|
@JsonProperty("title") val title: String,
|
||||||
|
@JsonProperty("type") val type: Int, // 1 = MOVIE, 2 = TV-SERIES
|
||||||
|
@JsonProperty("year") val year: Int?, // 1 = MOVIE, 2 = TV-SERIES
|
||||||
|
//"mppa" for tags
|
||||||
|
)
|
||||||
|
|
||||||
|
data class MeloMovieLink(val name: String, val link: String)
|
||||||
|
|
||||||
|
override fun search(query: String): ArrayList<Any>? {
|
||||||
|
val url = "$mainUrl/movie/search/?name=$query"
|
||||||
|
val returnValue: ArrayList<Any> = ArrayList()
|
||||||
|
val response = khttp.get(url)
|
||||||
|
val mapped = response.let { mapper.readValue<List<MeloMovieSearchResult>>(it.text) }
|
||||||
|
if (mapped.isEmpty()) return returnValue
|
||||||
|
|
||||||
|
for (i in mapped) {
|
||||||
|
val currentUrl = "$mainUrl/movie/${i.id}"
|
||||||
|
val currentPoster = "$mainUrl/assets/images/poster/${i.imdbId}.jpg"
|
||||||
|
if (i.type == 2) { // TV-SERIES
|
||||||
|
returnValue.add(TvSeriesSearchResponse(i.title,
|
||||||
|
currentUrl,
|
||||||
|
currentUrl,
|
||||||
|
this.name,
|
||||||
|
TvType.TvSeries,
|
||||||
|
currentPoster,
|
||||||
|
i.year,
|
||||||
|
null))
|
||||||
|
} else if (i.type == 1) { // MOVIE
|
||||||
|
returnValue.add(MovieSearchResponse(i.title,
|
||||||
|
currentUrl,
|
||||||
|
currentUrl,
|
||||||
|
this.name,
|
||||||
|
TvType.Movie,
|
||||||
|
currentUrl,
|
||||||
|
i.year))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return returnValue
|
||||||
|
}
|
||||||
|
|
||||||
|
// http not https, the links are not https!
|
||||||
|
private fun fixUrl(url: String): String {
|
||||||
|
if(url.isEmpty()) return ""
|
||||||
|
|
||||||
|
if (url.startsWith("//")) {
|
||||||
|
return "http:$url"
|
||||||
|
}
|
||||||
|
if (!url.startsWith("http")) {
|
||||||
|
return "http://$url"
|
||||||
|
}
|
||||||
|
return url
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun serializeData(element: Element): String {
|
||||||
|
val eps = element.select("> tbody > tr")
|
||||||
|
val parsed = eps.map {
|
||||||
|
try {
|
||||||
|
val tds = it.select("> td")
|
||||||
|
val name = tds[if (tds.size == 5) 1 else 0].text()
|
||||||
|
val url = fixUrl(tds.last().selectFirst("> a").attr("data-lnk").replace(" ", "%20"))
|
||||||
|
MeloMovieLink(name, url)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
MeloMovieLink("", "")
|
||||||
|
}
|
||||||
|
}.filter { it.link != "" && it.name != "" }
|
||||||
|
return mapper.writeValueAsString(parsed)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun loadLinks(data: String, isCasting: Boolean, callback: (ExtractorLink) -> Unit): Boolean {
|
||||||
|
val links = mapper.readValue<List<MeloMovieLink>>(data)
|
||||||
|
for (link in links) {
|
||||||
|
callback.invoke(ExtractorLink(this.name, link.name, link.link, "", getQualityFromName(link.name), false))
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun load(slug: String): Any? {
|
||||||
|
val response = khttp.get(slug).text
|
||||||
|
|
||||||
|
//backdrop = imgurl
|
||||||
|
fun findUsingRegex(src: String): String? {
|
||||||
|
return src.toRegex().find(response)?.groups?.get(1)?.value ?: return null
|
||||||
|
}
|
||||||
|
|
||||||
|
val imdbId = findUsingRegex("var imdb = \"(tt[0-9]*)\"")?.toIntOrNull()
|
||||||
|
val document = Jsoup.parse(response)
|
||||||
|
val poster = document.selectFirst("img.img-fluid").attr("src")
|
||||||
|
val type = findUsingRegex("var posttype = ([0-9]*)")?.toInt() ?: return null
|
||||||
|
val titleInfo = document.selectFirst("div.movie_detail_title > div > div > h1")
|
||||||
|
val title = titleInfo.ownText()
|
||||||
|
val year = titleInfo.selectFirst("> a").text().replace("(", "").replace(")", "").toIntOrNull()
|
||||||
|
val plot = document.selectFirst("div.col-lg-12 > p").text()
|
||||||
|
|
||||||
|
if (type == 1) { // MOVIE
|
||||||
|
val serialize = document.selectFirst("table.accordion__list")
|
||||||
|
return MovieLoadResponse(title,
|
||||||
|
slug,
|
||||||
|
this.name,
|
||||||
|
TvType.Movie,
|
||||||
|
serializeData(serialize),
|
||||||
|
poster,
|
||||||
|
year,
|
||||||
|
plot,
|
||||||
|
imdbId)
|
||||||
|
} else if (type == 2) {
|
||||||
|
val episodes = ArrayList<TvSeriesEpisode>()
|
||||||
|
val seasons = document.select("div.accordion__card")
|
||||||
|
for (s in seasons) {
|
||||||
|
val season =
|
||||||
|
s.selectFirst("> div.card-header > button > span").text().replace("Season: ", "").toIntOrNull()
|
||||||
|
val localEpisodes = s.select("> div.collapse > div > div > div.accordion__card")
|
||||||
|
for (e in localEpisodes) {
|
||||||
|
val episode =
|
||||||
|
e.selectFirst("> div.card-header > button > span").text().replace("Episode: ", "").toIntOrNull()
|
||||||
|
val links = e.selectFirst("> div.collapse > div > table.accordion__list")
|
||||||
|
val data = serializeData(links)
|
||||||
|
episodes.add(TvSeriesEpisode(null, season, episode, data))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
episodes.reverse()
|
||||||
|
return TvSeriesLoadResponse(title,
|
||||||
|
slug,
|
||||||
|
this.name,
|
||||||
|
TvType.TvSeries,
|
||||||
|
episodes,
|
||||||
|
poster,
|
||||||
|
year,
|
||||||
|
plot,
|
||||||
|
null,
|
||||||
|
imdbId)
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
|
@ -77,6 +77,7 @@ class SkipNextEpisodeController(val view: ImageView) : UIController() {
|
||||||
|
|
||||||
data class MetadataHolder(
|
data class MetadataHolder(
|
||||||
val apiName: String,
|
val apiName: String,
|
||||||
|
val isMovie: Boolean,
|
||||||
val title: String?,
|
val title: String?,
|
||||||
val poster: String?,
|
val poster: String?,
|
||||||
val currentEpisodeIndex: Int,
|
val currentEpisodeIndex: Int,
|
||||||
|
@ -91,13 +92,13 @@ class SelectSourceController(val view: ImageView, val activity: ControllerActivi
|
||||||
init {
|
init {
|
||||||
view.setImageResource(R.drawable.ic_baseline_playlist_play_24)
|
view.setImageResource(R.drawable.ic_baseline_playlist_play_24)
|
||||||
view.setOnClickListener {
|
view.setOnClickListener {
|
||||||
// lateinit var dialog: AlertDialog
|
// lateinit var dialog: AlertDialog
|
||||||
val holder = getCurrentMetaData()
|
val holder = getCurrentMetaData()
|
||||||
|
|
||||||
if (holder != null) {
|
if (holder != null) {
|
||||||
val items = holder.currentLinks
|
val items = holder.currentLinks
|
||||||
if (items.isNotEmpty() && remoteMediaClient?.currentItem != null) {
|
if (items.isNotEmpty() && remoteMediaClient?.currentItem != null) {
|
||||||
// val builder = AlertDialog.Builder(view.context, R.style.AlertDialogCustom)
|
// val builder = AlertDialog.Builder(view.context, R.style.AlertDialogCustom)
|
||||||
/*val builder = BottomSheetDialog(view.context, R.style.AlertDialogCustom)
|
/*val builder = BottomSheetDialog(view.context, R.style.AlertDialogCustom)
|
||||||
builder.setTitle("Pick source")*/
|
builder.setTitle("Pick source")*/
|
||||||
val bottomSheetDialog = BottomSheetDialog(view.context)
|
val bottomSheetDialog = BottomSheetDialog(view.context)
|
||||||
|
@ -212,7 +213,7 @@ class SelectSourceController(val view: ImageView, val activity: ControllerActivi
|
||||||
links.add(it)
|
links.add(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (res is Resource.Success) {
|
if (res is Resource.Success) {
|
||||||
val sorted = sortUrls(links)
|
val sorted = sortUrls(links)
|
||||||
if (sorted.isNotEmpty()) {
|
if (sorted.isNotEmpty()) {
|
||||||
|
@ -295,9 +296,9 @@ class ControllerActivity : ExpandedControllerActivity() {
|
||||||
uiMediaController.bindViewToUIController(skipBackButton, SkipTimeController(skipBackButton, false))
|
uiMediaController.bindViewToUIController(skipBackButton, SkipTimeController(skipBackButton, false))
|
||||||
uiMediaController.bindViewToUIController(skipForwardButton, SkipTimeController(skipForwardButton, true))
|
uiMediaController.bindViewToUIController(skipForwardButton, SkipTimeController(skipForwardButton, true))
|
||||||
uiMediaController.bindViewToUIController(skipOpButton, SkipNextEpisodeController(skipOpButton))
|
uiMediaController.bindViewToUIController(skipOpButton, SkipNextEpisodeController(skipOpButton))
|
||||||
/* val progressBar: CastSeekBar? = findViewById(R.id.cast_seek_bar)
|
/* val progressBar: CastSeekBar? = findViewById(R.id.cast_seek_bar)
|
||||||
|
|
||||||
progressBar?.backgroundTintList = (UIHelper.adjustAlpha(colorFromAttribute(R.attr.colorPrimary), 0.35f))
|
progressBar?.backgroundTintList = (UIHelper.adjustAlpha(colorFromAttribute(R.attr.colorPrimary), 0.35f))
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -386,11 +386,12 @@ class PlayerFragment : Fragment() {
|
||||||
if (useSystemBrightness) {
|
if (useSystemBrightness) {
|
||||||
// https://developer.android.com/reference/android/view/WindowManager.LayoutParams#screenBrightness
|
// https://developer.android.com/reference/android/view/WindowManager.LayoutParams#screenBrightness
|
||||||
val lp = activity?.window?.attributes
|
val lp = activity?.window?.attributes
|
||||||
val currentBrightness = if (lp?.screenBrightness ?: -1.0f <= 0f) (android.provider.Settings.System.getInt(
|
val currentBrightness =
|
||||||
context?.contentResolver,
|
if (lp?.screenBrightness ?: -1.0f <= 0f) (android.provider.Settings.System.getInt(
|
||||||
android.provider.Settings.System.SCREEN_BRIGHTNESS
|
context?.contentResolver,
|
||||||
) * (1 / 255).toFloat())
|
android.provider.Settings.System.SCREEN_BRIGHTNESS
|
||||||
else lp?.screenBrightness!!
|
) * (1 / 255).toFloat())
|
||||||
|
else lp?.screenBrightness!!
|
||||||
|
|
||||||
val alpha = minOf(
|
val alpha = minOf(
|
||||||
maxOf(
|
maxOf(
|
||||||
|
@ -403,8 +404,7 @@ class PlayerFragment : Fragment() {
|
||||||
|
|
||||||
progressBarRight?.max = 100 * 100
|
progressBarRight?.max = 100 * 100
|
||||||
progressBarRight?.progress = (alpha * 100 * 100).toInt()
|
progressBarRight?.progress = (alpha * 100 * 100).toInt()
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
val alpha = minOf(0.95f,
|
val alpha = minOf(0.95f,
|
||||||
brightness_overlay.alpha + diffY.toFloat() * 0.5f) // 0.05f *if (diffY > 0) 1 else -1
|
brightness_overlay.alpha + diffY.toFloat() * 0.5f) // 0.05f *if (diffY > 0) 1 else -1
|
||||||
brightness_overlay?.alpha = alpha
|
brightness_overlay?.alpha = alpha
|
||||||
|
@ -638,6 +638,7 @@ class PlayerFragment : Fragment() {
|
||||||
private var episodes: List<ResultEpisode> = ArrayList()
|
private var episodes: List<ResultEpisode> = ArrayList()
|
||||||
var currentPoster: String? = null
|
var currentPoster: String? = null
|
||||||
var currentHeaderName: String? = null
|
var currentHeaderName: String? = null
|
||||||
|
var currentIsMovie: Boolean? = null
|
||||||
|
|
||||||
//region PIP MODE
|
//region PIP MODE
|
||||||
private fun getPen(code: PlayerEventType): PendingIntent {
|
private fun getPen(code: PlayerEventType): PendingIntent {
|
||||||
|
@ -763,6 +764,7 @@ class PlayerFragment : Fragment() {
|
||||||
val index = links.indexOf(getCurrentUrl())
|
val index = links.indexOf(getCurrentUrl())
|
||||||
context?.startCast(
|
context?.startCast(
|
||||||
apiName,
|
apiName,
|
||||||
|
currentIsMovie ?: return@addCastStateListener,
|
||||||
currentHeaderName,
|
currentHeaderName,
|
||||||
currentPoster,
|
currentPoster,
|
||||||
epData.index,
|
epData.index,
|
||||||
|
@ -893,6 +895,7 @@ class PlayerFragment : Fragment() {
|
||||||
localData = d
|
localData = d
|
||||||
currentPoster = d.posterUrl
|
currentPoster = d.posterUrl
|
||||||
currentHeaderName = d.name
|
currentHeaderName = d.name
|
||||||
|
currentIsMovie = !d.isEpisodeBased()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is Resource.Failure -> {
|
is Resource.Failure -> {
|
||||||
|
@ -1209,8 +1212,8 @@ class PlayerFragment : Fragment() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handlePauseEvent(pause : Boolean) {
|
private fun handlePauseEvent(pause: Boolean) {
|
||||||
if(pause) {
|
if (pause) {
|
||||||
handlePlayerEvent(PlayerEventType.Pause)
|
handlePlayerEvent(PlayerEventType.Pause)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1474,6 +1477,7 @@ class PlayerFragment : Fragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onPlayerError(error: ExoPlaybackException) {
|
override fun onPlayerError(error: ExoPlaybackException) {
|
||||||
|
println("CURRENT URL: " + currentUrl.url)
|
||||||
// Lets pray this doesn't spam Toasts :)
|
// Lets pray this doesn't spam Toasts :)
|
||||||
when (error.type) {
|
when (error.type) {
|
||||||
ExoPlaybackException.TYPE_SOURCE -> {
|
ExoPlaybackException.TYPE_SOURCE -> {
|
||||||
|
|
|
@ -29,6 +29,7 @@ import com.google.android.gms.cast.framework.CastContext
|
||||||
import com.google.android.gms.cast.framework.CastState
|
import com.google.android.gms.cast.framework.CastState
|
||||||
import com.google.android.material.button.MaterialButton
|
import com.google.android.material.button.MaterialButton
|
||||||
import com.lagradost.cloudstream3.*
|
import com.lagradost.cloudstream3.*
|
||||||
|
import com.lagradost.cloudstream3.APIHolder.getApiFromName
|
||||||
import com.lagradost.cloudstream3.UIHelper.colorFromAttribute
|
import com.lagradost.cloudstream3.UIHelper.colorFromAttribute
|
||||||
import com.lagradost.cloudstream3.UIHelper.fixPaddingStatusbar
|
import com.lagradost.cloudstream3.UIHelper.fixPaddingStatusbar
|
||||||
import com.lagradost.cloudstream3.UIHelper.getStatusBarHeight
|
import com.lagradost.cloudstream3.UIHelper.getStatusBarHeight
|
||||||
|
@ -176,6 +177,7 @@ class ResultFragment : Fragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
private var currentPoster: String? = null
|
private var currentPoster: String? = null
|
||||||
|
private var currentIsMovie: Boolean? = null
|
||||||
|
|
||||||
var url: String? = null
|
var url: String? = null
|
||||||
|
|
||||||
|
@ -239,22 +241,33 @@ class ResultFragment : Fragment() {
|
||||||
currentLoadingCount++
|
currentLoadingCount++
|
||||||
when (episodeClick.action) {
|
when (episodeClick.action) {
|
||||||
ACTION_CHROME_CAST_EPISODE -> {
|
ACTION_CHROME_CAST_EPISODE -> {
|
||||||
|
|
||||||
|
val skipLoading = if (apiName != null) {
|
||||||
|
getApiFromName(apiName).instantLinkLoading
|
||||||
|
} else false
|
||||||
|
|
||||||
|
var dialog : AlertDialog? = null
|
||||||
val currentLoad = currentLoadingCount
|
val currentLoad = currentLoadingCount
|
||||||
val builder = AlertDialog.Builder(requireContext(), R.style.AlertDialogCustomTransparent)
|
|
||||||
val customLayout = layoutInflater.inflate(R.layout.dialog_loading, null)
|
|
||||||
builder.setView(customLayout)
|
|
||||||
|
|
||||||
val dialog = builder.create()
|
if(!skipLoading) {
|
||||||
|
val builder = AlertDialog.Builder(requireContext(), R.style.AlertDialogCustomTransparent)
|
||||||
|
val customLayout = layoutInflater.inflate(R.layout.dialog_loading, null)
|
||||||
|
builder.setView(customLayout)
|
||||||
|
|
||||||
dialog.show()
|
dialog = builder.create()
|
||||||
dialog.setOnDismissListener {
|
|
||||||
currentLoadingCount++
|
dialog.show()
|
||||||
|
dialog.setOnDismissListener {
|
||||||
|
currentLoadingCount++
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Toast.makeText(activity, "Loading links", Toast.LENGTH_SHORT).show()
|
// Toast.makeText(activity, "Loading links", Toast.LENGTH_SHORT).show()
|
||||||
|
|
||||||
viewModel.loadEpisode(episodeClick.data, true) { data ->
|
viewModel.loadEpisode(episodeClick.data, true) { data ->
|
||||||
if (currentLoadingCount != currentLoad) return@loadEpisode
|
if (currentLoadingCount != currentLoad) return@loadEpisode
|
||||||
dialog.dismiss()
|
dialog?.dismiss()
|
||||||
|
|
||||||
when (data) {
|
when (data) {
|
||||||
is Resource.Failure -> {
|
is Resource.Failure -> {
|
||||||
Toast.makeText(activity, "Failed to load links", Toast.LENGTH_SHORT).show()
|
Toast.makeText(activity, "Failed to load links", Toast.LENGTH_SHORT).show()
|
||||||
|
@ -263,6 +276,7 @@ class ResultFragment : Fragment() {
|
||||||
val eps = currentEpisodes ?: return@loadEpisode
|
val eps = currentEpisodes ?: return@loadEpisode
|
||||||
context?.startCast(
|
context?.startCast(
|
||||||
apiName ?: return@loadEpisode,
|
apiName ?: return@loadEpisode,
|
||||||
|
currentIsMovie ?: return@loadEpisode,
|
||||||
currentHeaderName,
|
currentHeaderName,
|
||||||
currentPoster,
|
currentPoster,
|
||||||
episodeClick.data.index,
|
episodeClick.data.index,
|
||||||
|
@ -354,6 +368,7 @@ class ResultFragment : Fragment() {
|
||||||
currentHeaderName = d.name
|
currentHeaderName = d.name
|
||||||
|
|
||||||
currentPoster = d.posterUrl
|
currentPoster = d.posterUrl
|
||||||
|
currentIsMovie = !d.isEpisodeBased()
|
||||||
|
|
||||||
result_openinbrower.setOnClickListener {
|
result_openinbrower.setOnClickListener {
|
||||||
val i = Intent(Intent.ACTION_VIEW)
|
val i = Intent(Intent.ACTION_VIEW)
|
||||||
|
|
|
@ -104,11 +104,12 @@ class ResultViewModel : ViewModel() {
|
||||||
val episodes = ArrayList<ResultEpisode>()
|
val episodes = ArrayList<ResultEpisode>()
|
||||||
for ((index, i) in d.episodes.withIndex()) {
|
for ((index, i) in d.episodes.withIndex()) {
|
||||||
episodes.add(context.buildResultEpisode(
|
episodes.add(context.buildResultEpisode(
|
||||||
null, // TODO ADD NAMES
|
(i.name
|
||||||
|
?: (if (i.season != null && i.episode != null) "S${i.season}:E${i.episode}" else null)), // TODO ADD NAMES
|
||||||
null,
|
null,
|
||||||
index + 1, //TODO MAKE ABLE TO NOT HAVE SOME EPISODE
|
i.episode ?: (index + 1),
|
||||||
null, // TODO FIX SEASON
|
i.season,
|
||||||
i,
|
i.data,
|
||||||
apiName,
|
apiName,
|
||||||
(mainId + index + 1).hashCode(),
|
(mainId + index + 1).hashCode(),
|
||||||
index,
|
index,
|
||||||
|
|
|
@ -144,7 +144,9 @@ class SearchFragment : Fragment() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
searchViewModel.search("overlord")
|
allApi.providersActive = requireActivity().getApiSettings()
|
||||||
|
|
||||||
|
searchViewModel.search("iron man")
|
||||||
// (activity as AppCompatActivity).loadResult("https://shiro.is/overlord-dubbed", "overlord-dubbed", "Shiro")
|
// (activity as AppCompatActivity).loadResult("https://shiro.is/overlord-dubbed", "overlord-dubbed", "Shiro")
|
||||||
/*
|
/*
|
||||||
(requireActivity() as AppCompatActivity).supportFragmentManager.beginTransaction()
|
(requireActivity() as AppCompatActivity).supportFragmentManager.beginTransaction()
|
||||||
|
|
|
@ -4,6 +4,7 @@ import androidx.lifecycle.LiveData
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
|
import com.lagradost.cloudstream3.APIHolder.allApi
|
||||||
import com.lagradost.cloudstream3.APIHolder.apis
|
import com.lagradost.cloudstream3.APIHolder.apis
|
||||||
import com.lagradost.cloudstream3.MainAPI
|
import com.lagradost.cloudstream3.MainAPI
|
||||||
import com.lagradost.cloudstream3.mvvm.Resource
|
import com.lagradost.cloudstream3.mvvm.Resource
|
||||||
|
@ -11,15 +12,13 @@ import com.lagradost.cloudstream3.mvvm.safeApiCall
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
class SearchViewModel : ViewModel() {
|
class SearchViewModel : ViewModel() {
|
||||||
val api: MainAPI = apis[0] //TODO MULTI API
|
|
||||||
|
|
||||||
private val _searchResponse: MutableLiveData<Resource<ArrayList<Any>>> = MutableLiveData()
|
private val _searchResponse: MutableLiveData<Resource<ArrayList<Any>>> = MutableLiveData()
|
||||||
val searchResponse: LiveData<Resource<ArrayList<Any>>> get() = _searchResponse
|
val searchResponse: LiveData<Resource<ArrayList<Any>>> get() = _searchResponse
|
||||||
|
|
||||||
fun search(query: String) = viewModelScope.launch {
|
fun search(query: String) = viewModelScope.launch {
|
||||||
_searchResponse.postValue(Resource.Loading())
|
_searchResponse.postValue(Resource.Loading())
|
||||||
val data = safeApiCall {
|
val data = safeApiCall {
|
||||||
api.search(query)
|
allApi.search(query)
|
||||||
}
|
}
|
||||||
|
|
||||||
_searchResponse.postValue(data as Resource<ArrayList<Any>>?)
|
_searchResponse.postValue(data as Resource<ArrayList<Any>>?)
|
||||||
|
|
|
@ -31,7 +31,10 @@ object CastHelper {
|
||||||
val link = holder.currentLinks[index]
|
val link = holder.currentLinks[index]
|
||||||
val movieMetadata = MediaMetadata(MediaMetadata.MEDIA_TYPE_MOVIE)
|
val movieMetadata = MediaMetadata(MediaMetadata.MEDIA_TYPE_MOVIE)
|
||||||
movieMetadata.putString(MediaMetadata.KEY_SUBTITLE,
|
movieMetadata.putString(MediaMetadata.KEY_SUBTITLE,
|
||||||
(epData.name ?: "Episode ${epData.episode}") + " - ${link.name}")
|
if (holder.isMovie)
|
||||||
|
link.name
|
||||||
|
else
|
||||||
|
(epData.name ?: "Episode ${epData.episode}") + " - ${link.name}")
|
||||||
|
|
||||||
movieMetadata.putString(MediaMetadata.KEY_TITLE, holder.title)
|
movieMetadata.putString(MediaMetadata.KEY_TITLE, holder.title)
|
||||||
|
|
||||||
|
@ -58,7 +61,7 @@ object CastHelper {
|
||||||
println("FAILED AND LOAD NEXT")
|
println("FAILED AND LOAD NEXT")
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
println("FAILED::: " + res.status)
|
//IDK DO SMTH HERE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -67,6 +70,7 @@ object CastHelper {
|
||||||
|
|
||||||
fun Context.startCast(
|
fun Context.startCast(
|
||||||
apiName: String,
|
apiName: String,
|
||||||
|
isMovie: Boolean,
|
||||||
title: String?,
|
title: String?,
|
||||||
poster: String?,
|
poster: String?,
|
||||||
currentEpisodeIndex: Int,
|
currentEpisodeIndex: Int,
|
||||||
|
@ -81,7 +85,7 @@ object CastHelper {
|
||||||
|
|
||||||
val epData = episodes[currentEpisodeIndex]
|
val epData = episodes[currentEpisodeIndex]
|
||||||
|
|
||||||
val holder = MetadataHolder(apiName, title, poster, currentEpisodeIndex, episodes, currentLinks)
|
val holder = MetadataHolder(apiName, isMovie, title, poster, currentEpisodeIndex, episodes, currentLinks)
|
||||||
|
|
||||||
val index = startIndex ?: 0
|
val index = startIndex ?: 0
|
||||||
val mediaItem =
|
val mediaItem =
|
||||||
|
@ -96,7 +100,15 @@ object CastHelper {
|
||||||
startTime ?: 0,
|
startTime ?: 0,
|
||||||
)) {
|
)) {
|
||||||
if (currentLinks.size > index + 1)
|
if (currentLinks.size > index + 1)
|
||||||
startCast(apiName, title, poster, currentEpisodeIndex, episodes, currentLinks, index + 1, startTime)
|
startCast(apiName,
|
||||||
|
isMovie,
|
||||||
|
title,
|
||||||
|
poster,
|
||||||
|
currentEpisodeIndex,
|
||||||
|
episodes,
|
||||||
|
currentLinks,
|
||||||
|
index + 1,
|
||||||
|
startTime)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -15,7 +15,7 @@ data class ExtractorLink(
|
||||||
val isM3u8: Boolean = false,
|
val isM3u8: Boolean = false,
|
||||||
)
|
)
|
||||||
|
|
||||||
fun ExtractorLink.getId() : Int {
|
fun ExtractorLink.getId(): Int {
|
||||||
return url.hashCode()
|
return url.hashCode()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,6 +27,20 @@ enum class Qualities(var value: Int) {
|
||||||
UHD(3) // 4k
|
UHD(3) // 4k
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getQualityFromName(qualityName: String): Int {
|
||||||
|
return when (qualityName.replace("p", "").replace("P", "")) {
|
||||||
|
"360" -> Qualities.SD
|
||||||
|
"480" -> Qualities.SD
|
||||||
|
"720" -> Qualities.HD
|
||||||
|
"1080" -> Qualities.FullHd
|
||||||
|
"1440" -> Qualities.UHD // I KNOW KINDA MISLEADING
|
||||||
|
"2160" -> Qualities.UHD
|
||||||
|
"4k" -> Qualities.UHD
|
||||||
|
"4K" -> Qualities.UHD
|
||||||
|
else -> Qualities.Unknown
|
||||||
|
}.value
|
||||||
|
}
|
||||||
|
|
||||||
private val packedRegex = Regex("""eval\(function\(p,a,c,k,e,.*\)\)""")
|
private val packedRegex = Regex("""eval\(function\(p,a,c,k,e,.*\)\)""")
|
||||||
fun getPacked(string: String): String? {
|
fun getPacked(string: String): String? {
|
||||||
return packedRegex.find(string)?.value
|
return packedRegex.find(string)?.value
|
||||||
|
|
|
@ -248,6 +248,7 @@
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/result_descript"
|
android:id="@+id/result_descript"
|
||||||
|
android:textSize="15sp"
|
||||||
tools:text="Ryan Quicksave Romano is an eccentric adventurer with a strange power: he can create a save-point in time and redo his life whenever he dies. Arriving in New Rome, the glitzy capital of sin of a rebuilding Europe, he finds the city torn between mega-corporations, sponsored heroes, superpowered criminals, and true monsters. It's a time of chaos, where potions can grant the power to rule the world and dangers lurk everywhere. "
|
tools:text="Ryan Quicksave Romano is an eccentric adventurer with a strange power: he can create a save-point in time and redo his life whenever he dies. Arriving in New Rome, the glitzy capital of sin of a rebuilding Europe, he finds the city torn between mega-corporations, sponsored heroes, superpowered criminals, and true monsters. It's a time of chaos, where potions can grant the power to rule the world and dangers lurk everywhere. "
|
||||||
android:layout_width="match_parent" android:layout_height="wrap_content">
|
android:layout_width="match_parent" android:layout_height="wrap_content">
|
||||||
</TextView>
|
</TextView>
|
||||||
|
|
Loading…
Reference in a new issue