mirror of
https://github.com/recloudstream/cloudstream.git
synced 2024-08-15 01:53:11 +00:00
episode options sff
This commit is contained in:
parent
bcc17171e5
commit
b5f913cc72
7 changed files with 285 additions and 134 deletions
|
@ -27,6 +27,7 @@ import androidx.core.content.ContextCompat
|
||||||
import androidx.fragment.app.FragmentActivity
|
import androidx.fragment.app.FragmentActivity
|
||||||
import androidx.preference.PreferenceManager
|
import androidx.preference.PreferenceManager
|
||||||
import com.google.android.gms.cast.framework.CastContext
|
import com.google.android.gms.cast.framework.CastContext
|
||||||
|
import com.google.android.gms.cast.framework.CastState
|
||||||
import com.google.android.gms.common.ConnectionResult
|
import com.google.android.gms.common.ConnectionResult
|
||||||
import com.google.android.gms.common.GoogleApiAvailability
|
import com.google.android.gms.common.GoogleApiAvailability
|
||||||
import com.lagradost.cloudstream3.ui.result.ResultFragment
|
import com.lagradost.cloudstream3.ui.result.ResultFragment
|
||||||
|
@ -151,6 +152,17 @@ object UIHelper {
|
||||||
return isCastApiAvailable
|
return isCastApiAvailable
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun Context.isConnectedToChromecast(): Boolean {
|
||||||
|
if (isCastApiAvailable()) {
|
||||||
|
val castContext = CastContext.getSharedInstance(this)
|
||||||
|
if (castContext.castState == CastState.CONNECTED) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
fun adjustAlpha(@ColorInt color: Int, factor: Float): Int {
|
fun adjustAlpha(@ColorInt color: Int, factor: Float): Int {
|
||||||
val alpha = (Color.alpha(color) * factor).roundToInt()
|
val alpha = (Color.alpha(color) * factor).roundToInt()
|
||||||
val red = Color.red(color)
|
val red = Color.red(color)
|
||||||
|
|
|
@ -2,6 +2,8 @@ package com.lagradost.cloudstream3.ui.result
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.DialogInterface
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
@ -9,6 +11,7 @@ import android.widget.ImageView
|
||||||
import android.widget.LinearLayout
|
import android.widget.LinearLayout
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import androidx.annotation.LayoutRes
|
import androidx.annotation.LayoutRes
|
||||||
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.core.widget.ContentLoadingProgressBar
|
import androidx.core.widget.ContentLoadingProgressBar
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.bumptech.glide.Glide
|
import com.bumptech.glide.Glide
|
||||||
|
@ -16,15 +19,27 @@ import com.bumptech.glide.load.model.GlideUrl
|
||||||
import com.google.android.gms.cast.framework.CastContext
|
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.lagradost.cloudstream3.*
|
import com.lagradost.cloudstream3.*
|
||||||
|
import com.lagradost.cloudstream3.UIHelper.hideSystemUI
|
||||||
import com.lagradost.cloudstream3.UIHelper.isCastApiAvailable
|
import com.lagradost.cloudstream3.UIHelper.isCastApiAvailable
|
||||||
|
import com.lagradost.cloudstream3.utils.getId
|
||||||
import kotlinx.android.synthetic.main.result_episode.view.episode_holder
|
import kotlinx.android.synthetic.main.result_episode.view.episode_holder
|
||||||
import kotlinx.android.synthetic.main.result_episode.view.episode_text
|
import kotlinx.android.synthetic.main.result_episode.view.episode_text
|
||||||
import kotlinx.android.synthetic.main.result_episode_large.view.*
|
import kotlinx.android.synthetic.main.result_episode_large.view.*
|
||||||
|
|
||||||
const val ACTION_RELOAD_EPISODE = 4
|
|
||||||
const val ACTION_CHROME_CAST_EPISODE = 2
|
|
||||||
const val ACTION_DOWNLOAD_EPISODE = 3
|
|
||||||
const val ACTION_PLAY_EPISODE_IN_PLAYER = 1
|
const val ACTION_PLAY_EPISODE_IN_PLAYER = 1
|
||||||
|
const val ACTION_PLAY_EPISODE_IN_EXTERNAL_PLAYER = 2
|
||||||
|
const val ACTION_PLAY_EPISODE_IN_BROWSER = 3
|
||||||
|
|
||||||
|
const val ACTION_CHROME_CAST_EPISODE = 4
|
||||||
|
const val ACTION_CHROME_CAST_MIRROR = 5
|
||||||
|
|
||||||
|
const val ACTION_DOWNLOAD_EPISODE = 6
|
||||||
|
const val ACTION_DOWNLOAD_MIRROR = 7
|
||||||
|
|
||||||
|
const val ACTION_RELOAD_EPISODE = 8
|
||||||
|
const val ACTION_COPY_LINK = 9
|
||||||
|
|
||||||
|
const val ACTION_SHOW_OPTIONS = 10
|
||||||
|
|
||||||
data class EpisodeClickEvent(val action: Int, val data: ResultEpisode)
|
data class EpisodeClickEvent(val action: Int, val data: ResultEpisode)
|
||||||
|
|
||||||
|
@ -69,8 +84,6 @@ class EpisodeAdapter(
|
||||||
itemView: View,
|
itemView: View,
|
||||||
private val clickCallback: (EpisodeClickEvent) -> Unit,
|
private val clickCallback: (EpisodeClickEvent) -> Unit,
|
||||||
) : RecyclerView.ViewHolder(itemView) {
|
) : RecyclerView.ViewHolder(itemView) {
|
||||||
//private val episodeViewPrecentage: View? = itemView.episode_view_procentage
|
|
||||||
// private val episodeViewPercentageOff: View? = itemView.episode_view_procentage_off
|
|
||||||
private val episodeText: TextView = itemView.episode_text
|
private val episodeText: TextView = itemView.episode_text
|
||||||
private val episodeRating: TextView? = itemView.episode_rating
|
private val episodeRating: TextView? = itemView.episode_rating
|
||||||
private val episodeDescript: TextView? = itemView.episode_descript
|
private val episodeDescript: TextView? = itemView.episode_descript
|
||||||
|
@ -78,8 +91,6 @@ class EpisodeAdapter(
|
||||||
private val episodePoster: ImageView? = itemView.episode_poster
|
private val episodePoster: ImageView? = itemView.episode_poster
|
||||||
private val episodeDownload: ImageView? = itemView.episode_download
|
private val episodeDownload: ImageView? = itemView.episode_download
|
||||||
|
|
||||||
// val episodeExtra: ImageView = itemView.episode_extra
|
|
||||||
// private val episodePlay: ImageView = itemView.episode_play
|
|
||||||
private val episodeHolder = itemView.episode_holder
|
private val episodeHolder = itemView.episode_holder
|
||||||
|
|
||||||
@SuppressLint("SetTextI18n")
|
@SuppressLint("SetTextI18n")
|
||||||
|
@ -87,20 +98,7 @@ class EpisodeAdapter(
|
||||||
val name = if (card.name == null) "Episode ${card.episode}" else "${card.episode}. ${card.name}"
|
val name = if (card.name == null) "Episode ${card.episode}" else "${card.episode}. ${card.name}"
|
||||||
episodeText.text = name
|
episodeText.text = name
|
||||||
|
|
||||||
fun setWidth(v: View, procentage: Float) {
|
|
||||||
val param = LinearLayout.LayoutParams(
|
|
||||||
v.layoutParams.width,
|
|
||||||
v.layoutParams.height,
|
|
||||||
procentage
|
|
||||||
)
|
|
||||||
v.layoutParams = param
|
|
||||||
}
|
|
||||||
|
|
||||||
val watchProgress = card.getWatchProgress()
|
val watchProgress = card.getWatchProgress()
|
||||||
/*if (episodeViewPrecentage != null && episodeViewPercentageOff != null) {
|
|
||||||
setWidth(episodeViewPrecentage, watchProgress)
|
|
||||||
setWidth(episodeViewPercentageOff, 1 - watchProgress)
|
|
||||||
}*/
|
|
||||||
|
|
||||||
episodeProgress?.progress = (watchProgress * 50).toInt()
|
episodeProgress?.progress = (watchProgress * 50).toInt()
|
||||||
episodeProgress?.visibility = if (watchProgress > 0.0f) View.VISIBLE else View.GONE
|
episodeProgress?.visibility = if (watchProgress > 0.0f) View.VISIBLE else View.GONE
|
||||||
|
@ -133,21 +131,18 @@ class EpisodeAdapter(
|
||||||
|
|
||||||
episodeHolder.setOnClickListener {
|
episodeHolder.setOnClickListener {
|
||||||
episodeHolder.context?.let { ctx ->
|
episodeHolder.context?.let { ctx ->
|
||||||
if (ctx.isCastApiAvailable()) {
|
if (ctx.isConnectedToChromecast()) {
|
||||||
val castContext = CastContext.getSharedInstance(ctx)
|
clickCallback.invoke(EpisodeClickEvent(ACTION_CHROME_CAST_EPISODE, card))
|
||||||
|
|
||||||
if (castContext.castState == CastState.CONNECTED) {
|
|
||||||
clickCallback.invoke(EpisodeClickEvent(ACTION_CHROME_CAST_EPISODE, card))
|
|
||||||
} else {
|
|
||||||
// clickCallback.invoke(EpisodeClickEvent(ACTION_PLAY_EPISODE_IN_PLAYER, card))
|
|
||||||
clickCallback.invoke(EpisodeClickEvent(ACTION_PLAY_EPISODE_IN_PLAYER, card))
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// clickCallback.invoke(EpisodeClickEvent(ACTION_PLAY_EPISODE_IN_PLAYER, card))
|
clickCallback.invoke(EpisodeClickEvent(ACTION_PLAY_EPISODE_IN_PLAYER, card))
|
||||||
clickCallback.invoke(EpisodeClickEvent(ACTION_PLAY_EPISODE_IN_PLAYER, card)) //TODO REDO TO MAIN
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
episodeHolder.setOnLongClickListener {
|
||||||
|
clickCallback.invoke(EpisodeClickEvent(ACTION_SHOW_OPTIONS, card))
|
||||||
|
|
||||||
|
return@setOnLongClickListener true
|
||||||
}
|
}
|
||||||
|
|
||||||
episodeDownload?.setOnClickListener {
|
episodeDownload?.setOnClickListener {
|
||||||
|
|
|
@ -35,6 +35,7 @@ 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
|
||||||
import com.lagradost.cloudstream3.UIHelper.isCastApiAvailable
|
import com.lagradost.cloudstream3.UIHelper.isCastApiAvailable
|
||||||
|
import com.lagradost.cloudstream3.UIHelper.isConnectedToChromecast
|
||||||
import com.lagradost.cloudstream3.UIHelper.popCurrentPage
|
import com.lagradost.cloudstream3.UIHelper.popCurrentPage
|
||||||
import com.lagradost.cloudstream3.UIHelper.popupMenuNoIcons
|
import com.lagradost.cloudstream3.UIHelper.popupMenuNoIcons
|
||||||
import com.lagradost.cloudstream3.UIHelper.popupMenuNoIconsAndNoStringres
|
import com.lagradost.cloudstream3.UIHelper.popupMenuNoIconsAndNoStringres
|
||||||
|
@ -43,14 +44,16 @@ import com.lagradost.cloudstream3.mvvm.observe
|
||||||
import com.lagradost.cloudstream3.ui.WatchType
|
import com.lagradost.cloudstream3.ui.WatchType
|
||||||
import com.lagradost.cloudstream3.ui.player.PlayerData
|
import com.lagradost.cloudstream3.ui.player.PlayerData
|
||||||
import com.lagradost.cloudstream3.ui.player.PlayerFragment
|
import com.lagradost.cloudstream3.ui.player.PlayerFragment
|
||||||
|
import com.lagradost.cloudstream3.utils.*
|
||||||
import com.lagradost.cloudstream3.utils.CastHelper.startCast
|
import com.lagradost.cloudstream3.utils.CastHelper.startCast
|
||||||
|
import com.lagradost.cloudstream3.utils.Coroutines.main
|
||||||
|
import com.lagradost.cloudstream3.utils.DataStore.setKey
|
||||||
import com.lagradost.cloudstream3.utils.DataStoreHelper.getViewPos
|
import com.lagradost.cloudstream3.utils.DataStoreHelper.getViewPos
|
||||||
|
|
||||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
|
||||||
import com.lagradost.cloudstream3.utils.VideoDownloadManager
|
|
||||||
import com.lagradost.cloudstream3.utils.VideoDownloadManager.sanitizeFilename
|
import com.lagradost.cloudstream3.utils.VideoDownloadManager.sanitizeFilename
|
||||||
import jp.wasabeef.glide.transformations.BlurTransformation
|
import jp.wasabeef.glide.transformations.BlurTransformation
|
||||||
import kotlinx.android.synthetic.main.fragment_result.*
|
import kotlinx.android.synthetic.main.fragment_result.*
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
|
|
||||||
|
|
||||||
const val MAX_SYNO_LENGH = 300
|
const val MAX_SYNO_LENGH = 300
|
||||||
|
@ -134,6 +137,7 @@ class ResultFragment : Fragment() {
|
||||||
private var currentLoadingCount = 0 // THIS IS USED TO PREVENT LATE EVENTS, AFTER DISMISS WAS CLICKED
|
private var currentLoadingCount = 0 // THIS IS USED TO PREVENT LATE EVENTS, AFTER DISMISS WAS CLICKED
|
||||||
private lateinit var viewModel: ResultViewModel
|
private lateinit var viewModel: ResultViewModel
|
||||||
private var allEpisodes: HashMap<Int, ArrayList<ExtractorLink>> = HashMap()
|
private var allEpisodes: HashMap<Int, ArrayList<ExtractorLink>> = HashMap()
|
||||||
|
private var allEpisodesSubs: HashMap<Int, ArrayList<SubtitleFile>> = HashMap()
|
||||||
private var currentHeaderName: String? = null
|
private var currentHeaderName: String? = null
|
||||||
private var currentType: TvType? = null
|
private var currentType: TvType? = null
|
||||||
private var currentEpisodes: List<ResultEpisode>? = null
|
private var currentEpisodes: List<ResultEpisode>? = null
|
||||||
|
@ -188,6 +192,7 @@ class ResultFragment : Fragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
private var currentPoster: String? = null
|
private var currentPoster: String? = null
|
||||||
|
private var currentId: Int? = null
|
||||||
private var currentIsMovie: Boolean? = null
|
private var currentIsMovie: Boolean? = null
|
||||||
|
|
||||||
var url: String? = null
|
var url: String? = null
|
||||||
|
@ -255,59 +260,126 @@ class ResultFragment : Fragment() {
|
||||||
requireActivity().popCurrentPage()
|
requireActivity().popCurrentPage()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun handleAction(episodeClick: EpisodeClickEvent) {
|
fun handleAction(episodeClick: EpisodeClickEvent): Job = main {
|
||||||
//val id = episodeClick.data.id
|
//val id = episodeClick.data.id
|
||||||
val index = episodeClick.data.index
|
val index = episodeClick.data.index
|
||||||
val buildInPlayer = true
|
val buildInPlayer = true
|
||||||
currentLoadingCount++
|
currentLoadingCount++
|
||||||
|
var currentLinks: ArrayList<ExtractorLink>? = null
|
||||||
|
var currentSubs: ArrayList<SubtitleFile>? = null
|
||||||
|
|
||||||
|
suspend fun requireLinks(isCasting: Boolean = false): Boolean {
|
||||||
|
val currentLinksTemp =
|
||||||
|
if (allEpisodes.containsKey(episodeClick.data.id)) allEpisodes[episodeClick.data.id] else null
|
||||||
|
val currentSubsTemp =
|
||||||
|
if (allEpisodes.containsKey(episodeClick.data.id)) allEpisodes[episodeClick.data.id] else null
|
||||||
|
if (currentLinksTemp != null && currentLinksTemp.size > 0) {
|
||||||
|
currentLinks = currentLinksTemp
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
val skipLoading = if (apiName != null) {
|
||||||
|
getApiFromName(apiName).instantLinkLoading
|
||||||
|
} else false
|
||||||
|
|
||||||
|
var loadingDialog: AlertDialog? = null
|
||||||
|
val currentLoad = currentLoadingCount
|
||||||
|
|
||||||
|
if (!skipLoading) {
|
||||||
|
val builder = AlertDialog.Builder(requireContext(), R.style.AlertDialogCustomTransparent)
|
||||||
|
val customLayout = layoutInflater.inflate(R.layout.dialog_loading, null)
|
||||||
|
builder.setView(customLayout)
|
||||||
|
|
||||||
|
loadingDialog = builder.create()
|
||||||
|
|
||||||
|
loadingDialog.show()
|
||||||
|
loadingDialog.setOnDismissListener {
|
||||||
|
currentLoadingCount++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val data = viewModel.loadEpisode(episodeClick.data, isCasting)
|
||||||
|
if (currentLoadingCount != currentLoad) return false
|
||||||
|
loadingDialog?.dismiss()
|
||||||
|
|
||||||
|
when (data) {
|
||||||
|
is Resource.Success -> {
|
||||||
|
currentLinks = data.value.links
|
||||||
|
currentSubs = data.value.subs
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
is Resource.Failure -> {
|
||||||
|
Toast.makeText(requireContext(), R.string.error_loading_links, Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
val isLoaded = when (episodeClick.action) {
|
||||||
|
ACTION_PLAY_EPISODE_IN_PLAYER -> true
|
||||||
|
ACTION_CHROME_CAST_EPISODE -> requireLinks(true)
|
||||||
|
ACTION_CHROME_CAST_MIRROR -> requireLinks(true)
|
||||||
|
else -> requireLinks()
|
||||||
|
}
|
||||||
|
if (!isLoaded) return@main // CANT LOAD
|
||||||
|
|
||||||
when (episodeClick.action) {
|
when (episodeClick.action) {
|
||||||
ACTION_CHROME_CAST_EPISODE -> {
|
ACTION_SHOW_OPTIONS -> {
|
||||||
val skipLoading = if (apiName != null) {
|
val builder = AlertDialog.Builder(requireContext(), R.style.AlertDialogCustom)
|
||||||
getApiFromName(apiName).instantLinkLoading
|
|
||||||
} else false
|
|
||||||
|
|
||||||
var dialog: AlertDialog? = null
|
var dialog: AlertDialog? = null
|
||||||
val currentLoad = currentLoadingCount
|
builder.setTitle(episodeClick.data.name)
|
||||||
|
val options = requireContext().resources.getStringArray(R.array.episode_long_click_options)
|
||||||
|
val optionsValues =
|
||||||
|
requireContext().resources.getIntArray(R.array.episode_long_click_options_values)
|
||||||
|
|
||||||
if (!skipLoading) {
|
val verifiedOptions = ArrayList<String>()
|
||||||
val builder = AlertDialog.Builder(requireContext(), R.style.AlertDialogCustomTransparent)
|
val verifiedOptionsValues = ArrayList<Int>()
|
||||||
val customLayout = layoutInflater.inflate(R.layout.dialog_loading, null)
|
|
||||||
builder.setView(customLayout)
|
|
||||||
|
|
||||||
dialog = builder.create()
|
for (i in options.indices) {
|
||||||
|
val opv = optionsValues[i]
|
||||||
|
val op = options[i]
|
||||||
|
|
||||||
dialog.show()
|
val isConnected = requireContext().isConnectedToChromecast()
|
||||||
dialog.setOnDismissListener {
|
val add = when (opv) {
|
||||||
currentLoadingCount++
|
ACTION_CHROME_CAST_EPISODE -> isConnected
|
||||||
|
ACTION_CHROME_CAST_MIRROR -> isConnected
|
||||||
|
else -> true
|
||||||
|
}
|
||||||
|
if (add) {
|
||||||
|
verifiedOptions.add(op)
|
||||||
|
verifiedOptionsValues.add(opv)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Toast.makeText(activity, "Loading links", Toast.LENGTH_SHORT).show()
|
builder.setItems(
|
||||||
|
verifiedOptions.toTypedArray()
|
||||||
viewModel.loadEpisode(episodeClick.data, true) { data ->
|
) { _, which ->
|
||||||
if (currentLoadingCount != currentLoad) return@loadEpisode
|
handleAction(EpisodeClickEvent(verifiedOptionsValues[which], episodeClick.data))
|
||||||
dialog?.dismiss()
|
dialog?.dismiss()
|
||||||
|
|
||||||
when (data) {
|
|
||||||
is Resource.Failure -> {
|
|
||||||
Toast.makeText(activity, "Failed to load links", Toast.LENGTH_SHORT).show()
|
|
||||||
}
|
|
||||||
is Resource.Success -> {
|
|
||||||
val eps = currentEpisodes ?: return@loadEpisode
|
|
||||||
context?.startCast(
|
|
||||||
apiName ?: return@loadEpisode,
|
|
||||||
currentIsMovie ?: return@loadEpisode,
|
|
||||||
currentHeaderName,
|
|
||||||
currentPoster,
|
|
||||||
episodeClick.data.index,
|
|
||||||
eps,
|
|
||||||
sortUrls(data.value.links),
|
|
||||||
data.value.subs,
|
|
||||||
startTime = episodeClick.data.getRealPosition(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dialog = builder.create()
|
||||||
|
dialog.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ACTION_CHROME_CAST_EPISODE -> {
|
||||||
|
|
||||||
|
val eps = currentEpisodes ?: return@main
|
||||||
|
context?.startCast(
|
||||||
|
apiName ?: return@main,
|
||||||
|
currentIsMovie ?: return@main,
|
||||||
|
currentHeaderName,
|
||||||
|
currentPoster,
|
||||||
|
episodeClick.data.index,
|
||||||
|
eps,
|
||||||
|
sortUrls(currentLinks ?: return@main),
|
||||||
|
currentSubs ?: return@main,
|
||||||
|
startTime = episodeClick.data.getRealPosition(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
ACTION_PLAY_EPISODE_IN_PLAYER -> {
|
ACTION_PLAY_EPISODE_IN_PLAYER -> {
|
||||||
|
@ -330,60 +402,80 @@ class ResultFragment : Fragment() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ACTION_RELOAD_EPISODE -> {
|
ACTION_RELOAD_EPISODE -> {
|
||||||
/*viewModel.load(episodeClick.data) { res ->
|
viewModel.loadEpisode(episodeClick.data, false)
|
||||||
if (res is Resource.Success) {
|
|
||||||
playEpisode(allEpisodes[id], index)
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
}
|
}
|
||||||
ACTION_DOWNLOAD_EPISODE -> {
|
ACTION_DOWNLOAD_EPISODE -> {
|
||||||
val tempUrl = url
|
val isMovie = currentIsMovie ?: return@main
|
||||||
if (tempUrl != null) {
|
val titleName = sanitizeFilename(currentHeaderName ?: return@main)
|
||||||
viewModel.loadEpisode(episodeClick.data, true) { data ->
|
|
||||||
if (data is Resource.Success) {
|
|
||||||
val isMovie = currentIsMovie ?: return@loadEpisode
|
|
||||||
val titleName = sanitizeFilename(currentHeaderName ?: return@loadEpisode)
|
|
||||||
val meta = VideoDownloadManager.DownloadEpisodeMetadata(
|
|
||||||
episodeClick.data.id,
|
|
||||||
titleName,
|
|
||||||
apiName ?: return@loadEpisode,
|
|
||||||
episodeClick.data.poster ?: currentPoster,
|
|
||||||
episodeClick.data.name,
|
|
||||||
if (isMovie) null else episodeClick.data.season,
|
|
||||||
if (isMovie) null else episodeClick.data.episode
|
|
||||||
)
|
|
||||||
|
|
||||||
val folder = when (currentType) {
|
val meta = VideoDownloadManager.DownloadEpisodeMetadata(
|
||||||
TvType.Anime -> "Anime/$titleName"
|
episodeClick.data.id,
|
||||||
TvType.Movie -> "Movies"
|
titleName,
|
||||||
TvType.TvSeries -> "TVSeries/$titleName"
|
apiName ?: return@main,
|
||||||
TvType.ONA -> "ONA"
|
episodeClick.data.poster ?: currentPoster,
|
||||||
else -> null
|
episodeClick.data.name,
|
||||||
}
|
if (isMovie) null else episodeClick.data.season,
|
||||||
|
if (isMovie) null else episodeClick.data.episode
|
||||||
|
)
|
||||||
|
|
||||||
VideoDownloadManager.downloadEpisode(
|
val folder = when (currentType) {
|
||||||
requireContext(),
|
TvType.Anime -> "Anime/$titleName"
|
||||||
tempUrl,
|
TvType.Movie -> "Movies"
|
||||||
folder,
|
TvType.TvSeries -> "TVSeries/$titleName"
|
||||||
meta,
|
TvType.ONA -> "ONA"
|
||||||
data.value.links
|
else -> null
|
||||||
)
|
}
|
||||||
}
|
|
||||||
}
|
context?.let { ctx ->
|
||||||
|
// SET VISUAL KEYS
|
||||||
|
ctx.setKey(
|
||||||
|
DOWNLOAD_HEADER_CACHE, (currentId ?: return@let).toString(),
|
||||||
|
VideoDownloadHelper.DownloadHeaderCached(
|
||||||
|
apiName,
|
||||||
|
url ?: return@let,
|
||||||
|
currentType ?: return@let,
|
||||||
|
currentHeaderName ?: return@let,
|
||||||
|
currentPoster ?: return@let,
|
||||||
|
currentId ?: return@let
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
val epData = episodeClick.data
|
||||||
|
ctx.setKey(
|
||||||
|
DOWNLOAD_EPISODE_CACHE,
|
||||||
|
epData.id.toString(),
|
||||||
|
VideoDownloadHelper.DownloadEpisodeCached(
|
||||||
|
epData.name,
|
||||||
|
epData.poster,
|
||||||
|
epData.episode,
|
||||||
|
epData.season,
|
||||||
|
epData.id,
|
||||||
|
currentId ?: return@let,
|
||||||
|
epData.rating,
|
||||||
|
epData.descript
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
// DOWNLOAD VIDEO
|
||||||
|
VideoDownloadManager.downloadEpisode(
|
||||||
|
ctx,
|
||||||
|
url ?: return@main,
|
||||||
|
folder,
|
||||||
|
meta,
|
||||||
|
currentLinks ?: return@main
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val adapter: RecyclerView.Adapter<RecyclerView.ViewHolder>? = activity?.let { it ->
|
val adapter: RecyclerView.Adapter<RecyclerView.ViewHolder> =
|
||||||
EpisodeAdapter(
|
EpisodeAdapter(
|
||||||
it,
|
|
||||||
ArrayList(),
|
ArrayList(),
|
||||||
result_episodes,
|
|
||||||
) { episodeClick ->
|
) { episodeClick ->
|
||||||
handleAction(episodeClick)
|
handleAction(episodeClick)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
result_episodes.adapter = adapter
|
result_episodes.adapter = adapter
|
||||||
result_episodes.layoutManager = GridLayoutManager(context, 1)
|
result_episodes.layoutManager = GridLayoutManager(context, 1)
|
||||||
|
@ -409,6 +501,12 @@ class ResultFragment : Fragment() {
|
||||||
allEpisodes = it
|
allEpisodes = it
|
||||||
}
|
}
|
||||||
|
|
||||||
|
observe(viewModel.allEpisodesSubs) {
|
||||||
|
allEpisodesSubs = it
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
observe(viewModel.selectedSeason) { season ->
|
observe(viewModel.selectedSeason) { season ->
|
||||||
result_season_button?.text = fromIndexToSeasonText(season)
|
result_season_button?.text = fromIndexToSeasonText(season)
|
||||||
}
|
}
|
||||||
|
@ -437,6 +535,10 @@ class ResultFragment : Fragment() {
|
||||||
(result_episodes.adapter as EpisodeAdapter).notifyDataSetChanged()
|
(result_episodes.adapter as EpisodeAdapter).notifyDataSetChanged()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
observe(viewModel.id) {
|
||||||
|
currentId = it
|
||||||
|
}
|
||||||
|
|
||||||
observe(viewModel.resultResponse) { data ->
|
observe(viewModel.resultResponse) { data ->
|
||||||
when (data) {
|
when (data) {
|
||||||
is Resource.Success -> {
|
is Resource.Success -> {
|
||||||
|
|
|
@ -26,7 +26,7 @@ class ResultViewModel : ViewModel() {
|
||||||
private val dubStatus: MutableLiveData<DubStatus> = MutableLiveData()
|
private val dubStatus: MutableLiveData<DubStatus> = MutableLiveData()
|
||||||
|
|
||||||
private val page: MutableLiveData<LoadResponse> = MutableLiveData()
|
private val page: MutableLiveData<LoadResponse> = MutableLiveData()
|
||||||
private val id: MutableLiveData<Int> = MutableLiveData()
|
val id: MutableLiveData<Int> = MutableLiveData()
|
||||||
val selectedSeason: MutableLiveData<Int> = MutableLiveData(-2)
|
val selectedSeason: MutableLiveData<Int> = MutableLiveData(-2)
|
||||||
val seasonSelections: MutableLiveData<List<Int?>> = MutableLiveData()
|
val seasonSelections: MutableLiveData<List<Int?>> = MutableLiveData()
|
||||||
|
|
||||||
|
@ -208,6 +208,41 @@ class ResultViewModel : ViewModel() {
|
||||||
loadEpisode(episode.id, episode.data, isCasting, callback)
|
loadEpisode(episode.id, episode.data, isCasting, callback)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun loadEpisode(
|
||||||
|
episode: ResultEpisode,
|
||||||
|
isCasting: Boolean,
|
||||||
|
) : Resource<ResultViewModel.EpisodeData> {
|
||||||
|
return loadEpisode(episode.id, episode.data, isCasting)
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun loadEpisode(
|
||||||
|
id: Int,
|
||||||
|
data: String,
|
||||||
|
isCasting: Boolean,
|
||||||
|
): Resource<ResultViewModel.EpisodeData> {
|
||||||
|
if (_allEpisodes.value?.contains(id) == true) {
|
||||||
|
_allEpisodes.value?.remove(id)
|
||||||
|
}
|
||||||
|
val links = ArrayList<ExtractorLink>()
|
||||||
|
val subs = ArrayList<SubtitleFile>()
|
||||||
|
return safeApiCall {
|
||||||
|
getApiFromName(_apiName.value).loadLinks(data, isCasting, { subtitleFile ->
|
||||||
|
if (!subs.any { it.url == subtitleFile.url }) {
|
||||||
|
subs.add(subtitleFile)
|
||||||
|
_allEpisodesSubs.value?.set(id, subs)
|
||||||
|
_allEpisodesSubs.postValue(_allEpisodesSubs.value)
|
||||||
|
}
|
||||||
|
}) { link ->
|
||||||
|
if (!links.any { it.url == link.url }) {
|
||||||
|
links.add(link)
|
||||||
|
_allEpisodes.value?.set(id, links)
|
||||||
|
_allEpisodes.postValue(_allEpisodes.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EpisodeData(links, subs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun loadEpisode(
|
private fun loadEpisode(
|
||||||
id: Int,
|
id: Int,
|
||||||
data: String,
|
data: String,
|
||||||
|
@ -215,27 +250,7 @@ class ResultViewModel : ViewModel() {
|
||||||
callback: (Resource<EpisodeData>) -> Unit,
|
callback: (Resource<EpisodeData>) -> Unit,
|
||||||
) =
|
) =
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
if (_allEpisodes.value?.contains(id) == true) {
|
val localData = loadEpisode(id, data, isCasting)
|
||||||
_allEpisodes.value?.remove(id)
|
|
||||||
}
|
|
||||||
val links = ArrayList<ExtractorLink>()
|
|
||||||
val subs = ArrayList<SubtitleFile>()
|
|
||||||
val localData = safeApiCall {
|
|
||||||
getApiFromName(_apiName.value).loadLinks(data, isCasting, { subtitleFile ->
|
|
||||||
if (!subs.any { it.url == subtitleFile.url }) {
|
|
||||||
subs.add(subtitleFile)
|
|
||||||
_allEpisodesSubs.value?.set(id, subs)
|
|
||||||
_allEpisodesSubs.postValue(_allEpisodesSubs.value)
|
|
||||||
}
|
|
||||||
}) { link ->
|
|
||||||
if (!links.any { it.url == link.url }) {
|
|
||||||
links.add(link)
|
|
||||||
_allEpisodes.value?.set(id, links)
|
|
||||||
_allEpisodes.postValue(_allEpisodes.value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
EpisodeData(links, subs)
|
|
||||||
}
|
|
||||||
callback.invoke(localData)
|
callback.invoke(localData)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,9 @@ 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
|
||||||
|
|
||||||
|
const val DOWNLOAD_HEADER_CACHE = "download_header_cache"
|
||||||
|
const val DOWNLOAD_EPISODE_CACHE = "download_episode_cache"
|
||||||
|
|
||||||
const val PREFERENCES_NAME: String = "rebuild_preference"
|
const val PREFERENCES_NAME: String = "rebuild_preference"
|
||||||
|
|
||||||
object DataStore {
|
object DataStore {
|
||||||
|
|
|
@ -13,4 +13,27 @@
|
||||||
<!-- Actually fake to make the skip op button the same style -->
|
<!-- Actually fake to make the skip op button the same style -->
|
||||||
<item>@id/cast_button_type_forward_30_seconds</item>
|
<item>@id/cast_button_type_forward_30_seconds</item>
|
||||||
</array>
|
</array>
|
||||||
|
|
||||||
|
<array name="episode_long_click_options">
|
||||||
|
<item>Chromecast Episode</item>
|
||||||
|
<item>Chromecast Mirror</item>
|
||||||
|
<item>Play In App</item>
|
||||||
|
<item>Play In External App</item>
|
||||||
|
<item>Play In Browser</item>
|
||||||
|
<item>Copy Link</item>
|
||||||
|
<item>Auto Download</item>
|
||||||
|
<item>Download Mirror</item>
|
||||||
|
<item>Reload Links</item>
|
||||||
|
</array>
|
||||||
|
<array name="episode_long_click_options_values">
|
||||||
|
<item>4</item>
|
||||||
|
<item>5</item>
|
||||||
|
<item>1</item>
|
||||||
|
<item>2</item>
|
||||||
|
<item>3</item>
|
||||||
|
<item>9</item>
|
||||||
|
<item>6</item>
|
||||||
|
<item>7</item>
|
||||||
|
<item>8</item>
|
||||||
|
</array>
|
||||||
</resources>
|
</resources>
|
|
@ -39,4 +39,5 @@
|
||||||
<string name="play_episode">Play Episode</string>
|
<string name="play_episode">Play Episode</string>
|
||||||
<string name="need_storage">Allow to download episodes</string>
|
<string name="need_storage">Allow to download episodes</string>
|
||||||
<string name="download_descript">Download</string>
|
<string name="download_descript">Download</string>
|
||||||
|
<string name="error_loading_links">Error Loading Links</string>
|
||||||
</resources>
|
</resources>
|
Loading…
Reference in a new issue