episode options sff

This commit is contained in:
LagradOst 2021-07-17 16:14:25 +02:00
parent bcc17171e5
commit b5f913cc72
7 changed files with 285 additions and 134 deletions

View file

@ -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)

View file

@ -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)
if (castContext.castState == CastState.CONNECTED) {
clickCallback.invoke(EpisodeClickEvent(ACTION_CHROME_CAST_EPISODE, card)) clickCallback.invoke(EpisodeClickEvent(ACTION_CHROME_CAST_EPISODE, 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))
} }
} else {
// 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 {

View file

@ -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,18 +260,29 @@ 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++
when (episodeClick.action) { var currentLinks: ArrayList<ExtractorLink>? = null
ACTION_CHROME_CAST_EPISODE -> { 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) { val skipLoading = if (apiName != null) {
getApiFromName(apiName).instantLinkLoading getApiFromName(apiName).instantLinkLoading
} else false } else false
var dialog: AlertDialog? = null var loadingDialog: AlertDialog? = null
val currentLoad = currentLoadingCount val currentLoad = currentLoadingCount
if (!skipLoading) { if (!skipLoading) {
@ -274,41 +290,97 @@ class ResultFragment : Fragment() {
val customLayout = layoutInflater.inflate(R.layout.dialog_loading, null) val customLayout = layoutInflater.inflate(R.layout.dialog_loading, null)
builder.setView(customLayout) builder.setView(customLayout)
dialog = builder.create() loadingDialog = builder.create()
dialog.show() loadingDialog.show()
dialog.setOnDismissListener { loadingDialog.setOnDismissListener {
currentLoadingCount++ currentLoadingCount++
} }
} }
// Toast.makeText(activity, "Loading links", Toast.LENGTH_SHORT).show() val data = viewModel.loadEpisode(episodeClick.data, isCasting)
if (currentLoadingCount != currentLoad) return false
viewModel.loadEpisode(episodeClick.data, true) { data -> loadingDialog?.dismiss()
if (currentLoadingCount != currentLoad) return@loadEpisode
dialog?.dismiss()
when (data) { when (data) {
is Resource.Failure -> {
Toast.makeText(activity, "Failed to load links", Toast.LENGTH_SHORT).show()
}
is Resource.Success -> { is Resource.Success -> {
val eps = currentEpisodes ?: return@loadEpisode 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) {
ACTION_SHOW_OPTIONS -> {
val builder = AlertDialog.Builder(requireContext(), R.style.AlertDialogCustom)
var dialog: AlertDialog? = null
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)
val verifiedOptions = ArrayList<String>()
val verifiedOptionsValues = ArrayList<Int>()
for (i in options.indices) {
val opv = optionsValues[i]
val op = options[i]
val isConnected = requireContext().isConnectedToChromecast()
val add = when (opv) {
ACTION_CHROME_CAST_EPISODE -> isConnected
ACTION_CHROME_CAST_MIRROR -> isConnected
else -> true
}
if (add) {
verifiedOptions.add(op)
verifiedOptionsValues.add(opv)
}
}
builder.setItems(
verifiedOptions.toTypedArray()
) { _, which ->
handleAction(EpisodeClickEvent(verifiedOptionsValues[which], episodeClick.data))
dialog?.dismiss()
}
dialog = builder.create()
dialog.show()
}
ACTION_CHROME_CAST_EPISODE -> {
val eps = currentEpisodes ?: return@main
context?.startCast( context?.startCast(
apiName ?: return@loadEpisode, apiName ?: return@main,
currentIsMovie ?: return@loadEpisode, currentIsMovie ?: return@main,
currentHeaderName, currentHeaderName,
currentPoster, currentPoster,
episodeClick.data.index, episodeClick.data.index,
eps, eps,
sortUrls(data.value.links), sortUrls(currentLinks ?: return@main),
data.value.subs, currentSubs ?: return@main,
startTime = episodeClick.data.getRealPosition(), startTime = episodeClick.data.getRealPosition(),
) )
} }
}
}
}
ACTION_PLAY_EPISODE_IN_PLAYER -> { ACTION_PLAY_EPISODE_IN_PLAYER -> {
if (buildInPlayer) { if (buildInPlayer) {
@ -330,23 +402,16 @@ 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( val meta = VideoDownloadManager.DownloadEpisodeMetadata(
episodeClick.data.id, episodeClick.data.id,
titleName, titleName,
apiName ?: return@loadEpisode, apiName ?: return@main,
episodeClick.data.poster ?: currentPoster, episodeClick.data.poster ?: currentPoster,
episodeClick.data.name, episodeClick.data.name,
if (isMovie) null else episodeClick.data.season, if (isMovie) null else episodeClick.data.season,
@ -361,29 +426,56 @@ class ResultFragment : Fragment() {
else -> null 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( VideoDownloadManager.downloadEpisode(
requireContext(), ctx,
tempUrl, url ?: return@main,
folder, folder,
meta, meta,
data.value.links 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 -> {

View file

@ -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,19 +208,24 @@ class ResultViewModel : ViewModel() {
loadEpisode(episode.id, episode.data, isCasting, callback) loadEpisode(episode.id, episode.data, isCasting, callback)
} }
private fun loadEpisode( suspend fun loadEpisode(
episode: ResultEpisode,
isCasting: Boolean,
) : Resource<ResultViewModel.EpisodeData> {
return loadEpisode(episode.id, episode.data, isCasting)
}
private suspend fun loadEpisode(
id: Int, id: Int,
data: String, data: String,
isCasting: Boolean, isCasting: Boolean,
callback: (Resource<EpisodeData>) -> Unit, ): Resource<ResultViewModel.EpisodeData> {
) =
viewModelScope.launch {
if (_allEpisodes.value?.contains(id) == true) { if (_allEpisodes.value?.contains(id) == true) {
_allEpisodes.value?.remove(id) _allEpisodes.value?.remove(id)
} }
val links = ArrayList<ExtractorLink>() val links = ArrayList<ExtractorLink>()
val subs = ArrayList<SubtitleFile>() val subs = ArrayList<SubtitleFile>()
val localData = safeApiCall { return safeApiCall {
getApiFromName(_apiName.value).loadLinks(data, isCasting, { subtitleFile -> getApiFromName(_apiName.value).loadLinks(data, isCasting, { subtitleFile ->
if (!subs.any { it.url == subtitleFile.url }) { if (!subs.any { it.url == subtitleFile.url }) {
subs.add(subtitleFile) subs.add(subtitleFile)
@ -236,6 +241,16 @@ class ResultViewModel : ViewModel() {
} }
EpisodeData(links, subs) EpisodeData(links, subs)
} }
}
private fun loadEpisode(
id: Int,
data: String,
isCasting: Boolean,
callback: (Resource<EpisodeData>) -> Unit,
) =
viewModelScope.launch {
val localData = loadEpisode(id, data, isCasting)
callback.invoke(localData) callback.invoke(localData)
} }

View file

@ -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 {

View file

@ -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>

View file

@ -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>