mirror of
https://github.com/recloudstream/cloudstream.git
synced 2024-08-15 01:53:11 +00:00
Major performance and bug fixes to downloads (#1164)
This commit is contained in:
parent
29ec554334
commit
03b8b6e637
10 changed files with 195 additions and 170 deletions
|
@ -2,6 +2,7 @@ package com.lagradost.cloudstream3
|
|||
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.RequestBody
|
||||
import okhttp3.RequestBody.Companion.toRequestBody
|
||||
import org.schabi.newpipe.extractor.downloader.Downloader
|
||||
import org.schabi.newpipe.extractor.downloader.Request
|
||||
import org.schabi.newpipe.extractor.downloader.Response
|
||||
|
@ -18,7 +19,7 @@ class DownloaderTestImpl private constructor(builder: OkHttpClient.Builder) : Do
|
|||
val dataToSend: ByteArray? = request.dataToSend()
|
||||
var requestBody: RequestBody? = null
|
||||
if (dataToSend != null) {
|
||||
requestBody = RequestBody.create(null, dataToSend)
|
||||
requestBody = dataToSend.toRequestBody(null, 0, dataToSend.size)
|
||||
}
|
||||
val requestBuilder: okhttp3.Request.Builder = okhttp3.Request.Builder()
|
||||
.method(httpMethod, requestBody).url(url)
|
||||
|
|
|
@ -13,9 +13,10 @@ import com.lagradost.cloudstream3.R
|
|||
import com.lagradost.cloudstream3.databinding.DownloadChildEpisodeBinding
|
||||
import com.lagradost.cloudstream3.databinding.DownloadHeaderEpisodeBinding
|
||||
import com.lagradost.cloudstream3.mvvm.logError
|
||||
import com.lagradost.cloudstream3.ui.download.button.DownloadStatusTell
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.getNameFull
|
||||
import com.lagradost.cloudstream3.utils.DataStoreHelper
|
||||
import com.lagradost.cloudstream3.utils.DataStoreHelper.fixVisual
|
||||
import com.lagradost.cloudstream3.utils.DataStoreHelper.getViewPos
|
||||
import com.lagradost.cloudstream3.utils.UIHelper.setImage
|
||||
import com.lagradost.cloudstream3.utils.VideoDownloadHelper
|
||||
|
||||
|
@ -26,6 +27,9 @@ const val DOWNLOAD_ACTION_PAUSE_DOWNLOAD = 3
|
|||
const val DOWNLOAD_ACTION_DOWNLOAD = 4
|
||||
const val DOWNLOAD_ACTION_LONG_CLICK = 5
|
||||
|
||||
const val DOWNLOAD_ACTION_GO_TO_CHILD = 0
|
||||
const val DOWNLOAD_ACTION_LOAD_RESULT = 1
|
||||
|
||||
abstract class VisualDownloadCached(
|
||||
open val currentBytes: Long,
|
||||
open val totalBytes: Long,
|
||||
|
@ -93,110 +97,128 @@ class DownloadAdapter(
|
|||
private val mediaClickCallback: (DownloadClickEvent) -> Unit,
|
||||
) : RecyclerView.ViewHolder(binding.root) {
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
fun bind(card: VisualDownloadCached?) {
|
||||
when (binding) {
|
||||
is DownloadHeaderEpisodeBinding -> binding.apply {
|
||||
if (card == null || card !is VisualDownloadHeaderCached) return@apply
|
||||
val d = card.data
|
||||
is DownloadHeaderEpisodeBinding -> bindHeader(card as? VisualDownloadHeaderCached)
|
||||
is DownloadChildEpisodeBinding -> bindChild(card as? VisualDownloadChildCached)
|
||||
}
|
||||
}
|
||||
|
||||
downloadHeaderPoster.apply {
|
||||
setImage(d.poster)
|
||||
setOnClickListener {
|
||||
clickCallback.invoke(DownloadHeaderClickEvent(1, d))
|
||||
}
|
||||
}
|
||||
@SuppressLint("SetTextI18n")
|
||||
private fun bindHeader(card: VisualDownloadHeaderCached?) {
|
||||
if (binding !is DownloadHeaderEpisodeBinding) return
|
||||
card ?: return
|
||||
val d = card.data
|
||||
|
||||
downloadHeaderTitle.text = d.name
|
||||
val mbString = formatShortFileSize(itemView.context, card.totalBytes)
|
||||
|
||||
if (card.child != null) {
|
||||
downloadHeaderGotoChild.isVisible = false
|
||||
|
||||
downloadButton.setDefaultClickListener(card.child, downloadHeaderInfo, mediaClickCallback)
|
||||
downloadButton.isVisible = true
|
||||
|
||||
episodeHolder.setOnClickListener {
|
||||
mediaClickCallback.invoke(
|
||||
DownloadClickEvent(
|
||||
DOWNLOAD_ACTION_PLAY_FILE,
|
||||
card.child
|
||||
)
|
||||
)
|
||||
}
|
||||
} else {
|
||||
downloadButton.isVisible = false
|
||||
downloadHeaderGotoChild.isVisible = true
|
||||
|
||||
try {
|
||||
downloadHeaderInfo.text =
|
||||
downloadHeaderInfo.context.getString(R.string.extra_info_format)
|
||||
.format(
|
||||
card.totalDownloads,
|
||||
if (card.totalDownloads == 1) downloadHeaderInfo.context.getString(
|
||||
R.string.episode
|
||||
) else downloadHeaderInfo.context.getString(
|
||||
R.string.episodes
|
||||
),
|
||||
mbString
|
||||
)
|
||||
} catch (t: Throwable) {
|
||||
// You probably formatted incorrectly
|
||||
downloadHeaderInfo.text = "Error"
|
||||
logError(t)
|
||||
}
|
||||
|
||||
episodeHolder.setOnClickListener {
|
||||
clickCallback.invoke(DownloadHeaderClickEvent(0, d))
|
||||
}
|
||||
binding.apply {
|
||||
downloadHeaderPoster.apply {
|
||||
setImage(d.poster)
|
||||
setOnClickListener {
|
||||
clickCallback.invoke(DownloadHeaderClickEvent(DOWNLOAD_ACTION_LOAD_RESULT, d))
|
||||
}
|
||||
}
|
||||
|
||||
is DownloadChildEpisodeBinding -> binding.apply {
|
||||
if (card == null || card !is VisualDownloadChildCached) return@apply
|
||||
val d = card.data
|
||||
downloadHeaderTitle.text = d.name
|
||||
val formattedSizeString = formatShortFileSize(itemView.context, card.totalBytes)
|
||||
|
||||
val posDur = DataStoreHelper.getViewPos(d.id)
|
||||
downloadChildEpisodeProgress.apply {
|
||||
if (posDur != null) {
|
||||
val visualPos = posDur.fixVisual()
|
||||
max = (visualPos.duration / 1000).toInt()
|
||||
progress = (visualPos.position / 1000).toInt()
|
||||
isVisible = true
|
||||
} else isVisible = false
|
||||
if (card.child != null) {
|
||||
downloadHeaderGotoChild.isVisible = false
|
||||
|
||||
val status = downloadButton.getStatus(card.child.id, card.currentBytes, card.totalBytes)
|
||||
if (status == DownloadStatusTell.IsDone) {
|
||||
// We do this here instead if we are finished downloading
|
||||
// so that we can use the value from the view model
|
||||
// rather than extra unneeded disk operations and to prevent a
|
||||
// delay in updating download icon state.
|
||||
downloadButton.setProgress(card.currentBytes, card.totalBytes)
|
||||
downloadButton.applyMetaData(card.child.id, card.currentBytes, card.totalBytes)
|
||||
// We will let the view model handle this
|
||||
downloadButton.doSetProgress = false
|
||||
downloadHeaderInfo.text = formattedSizeString
|
||||
} else downloadButton.doSetProgress = true
|
||||
|
||||
downloadButton.setDefaultClickListener(card.child, downloadHeaderInfo, mediaClickCallback)
|
||||
downloadButton.isVisible = true
|
||||
|
||||
episodeHolder.setOnClickListener {
|
||||
mediaClickCallback.invoke(DownloadClickEvent(DOWNLOAD_ACTION_PLAY_FILE, card.child))
|
||||
}
|
||||
} else {
|
||||
downloadButton.isVisible = false
|
||||
downloadHeaderGotoChild.isVisible = true
|
||||
|
||||
try {
|
||||
downloadHeaderInfo.text = downloadHeaderInfo.context.getString(R.string.extra_info_format)
|
||||
.format(
|
||||
card.totalDownloads,
|
||||
downloadHeaderInfo.context.resources.getQuantityString(
|
||||
R.plurals.episodes,
|
||||
card.totalDownloads
|
||||
),
|
||||
formattedSizeString
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
// You probably formatted incorrectly
|
||||
downloadHeaderInfo.text = "Error"
|
||||
logError(e)
|
||||
}
|
||||
|
||||
downloadButton.setDefaultClickListener(card.data, downloadChildEpisodeTextExtra, mediaClickCallback)
|
||||
|
||||
downloadChildEpisodeText.apply {
|
||||
text = context.getNameFull(d.name, d.episode, d.season)
|
||||
isSelected = true // Needed for text repeating
|
||||
episodeHolder.setOnClickListener {
|
||||
clickCallback.invoke(DownloadHeaderClickEvent(DOWNLOAD_ACTION_GO_TO_CHILD, d))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
downloadChildEpisodeHolder.setOnClickListener {
|
||||
mediaClickCallback.invoke(DownloadClickEvent(DOWNLOAD_ACTION_PLAY_FILE, d))
|
||||
private fun bindChild(card: VisualDownloadChildCached?) {
|
||||
if (binding !is DownloadChildEpisodeBinding) return
|
||||
card ?: return
|
||||
val d = card.data
|
||||
|
||||
binding.apply {
|
||||
val posDur = getViewPos(d.id)
|
||||
downloadChildEpisodeProgress.apply {
|
||||
isVisible = posDur != null
|
||||
posDur?.let {
|
||||
val visualPos = it.fixVisual()
|
||||
max = (visualPos.duration / 1000).toInt()
|
||||
progress = (visualPos.position / 1000).toInt()
|
||||
}
|
||||
}
|
||||
|
||||
val status = downloadButton.getStatus(d.id, card.currentBytes, card.totalBytes)
|
||||
if (status == DownloadStatusTell.IsDone) {
|
||||
// We do this here instead if we are finished downloading
|
||||
// so that we can use the value from the view model
|
||||
// rather than extra unneeded disk operations and to prevent a
|
||||
// delay in updating download icon state.
|
||||
downloadButton.setProgress(card.currentBytes, card.totalBytes)
|
||||
downloadButton.applyMetaData(d.id, card.currentBytes, card.totalBytes)
|
||||
// We will let the view model handle this
|
||||
downloadButton.doSetProgress = false
|
||||
downloadChildEpisodeTextExtra.text = formatShortFileSize(downloadChildEpisodeTextExtra.context, card.totalBytes)
|
||||
} else downloadButton.doSetProgress = true
|
||||
|
||||
downloadButton.setDefaultClickListener(d, downloadChildEpisodeTextExtra, mediaClickCallback)
|
||||
downloadButton.isVisible = true
|
||||
|
||||
downloadChildEpisodeText.apply {
|
||||
text = context.getNameFull(d.name, d.episode, d.season)
|
||||
isSelected = true // Needed for text repeating
|
||||
}
|
||||
|
||||
downloadChildEpisodeHolder.setOnClickListener {
|
||||
mediaClickCallback.invoke(DownloadClickEvent(DOWNLOAD_ACTION_PLAY_FILE, d))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DownloadViewHolder {
|
||||
val inflater = LayoutInflater.from(parent.context)
|
||||
val binding = when (viewType) {
|
||||
VIEW_TYPE_HEADER -> {
|
||||
DownloadHeaderEpisodeBinding.inflate(
|
||||
LayoutInflater.from(parent.context),
|
||||
parent,
|
||||
false
|
||||
)
|
||||
}
|
||||
VIEW_TYPE_CHILD -> {
|
||||
DownloadChildEpisodeBinding.inflate(
|
||||
LayoutInflater.from(parent.context),
|
||||
parent,
|
||||
false
|
||||
)
|
||||
}
|
||||
VIEW_TYPE_HEADER -> DownloadHeaderEpisodeBinding.inflate(inflater, parent, false)
|
||||
VIEW_TYPE_CHILD -> DownloadChildEpisodeBinding.inflate(inflater, parent, false)
|
||||
else -> throw IllegalArgumentException("Invalid view type")
|
||||
}
|
||||
return DownloadViewHolder(binding, clickCallback, mediaClickCallback)
|
||||
|
@ -207,8 +229,11 @@ class DownloadAdapter(
|
|||
}
|
||||
|
||||
override fun getItemViewType(position: Int): Int {
|
||||
val card = getItem(position)
|
||||
return if (card is VisualDownloadChildCached) VIEW_TYPE_CHILD else VIEW_TYPE_HEADER
|
||||
return when (getItem(position)) {
|
||||
is VisualDownloadChildCached -> VIEW_TYPE_CHILD
|
||||
is VisualDownloadHeaderCached -> VIEW_TYPE_HEADER
|
||||
else -> throw IllegalArgumentException("Invalid data type at position $position")
|
||||
}
|
||||
}
|
||||
|
||||
class DiffCallback : DiffUtil.ItemCallback<VisualDownloadCached>() {
|
||||
|
|
|
@ -35,6 +35,7 @@ class DownloadChildFragment : Fragment() {
|
|||
|
||||
override fun onDestroyView() {
|
||||
downloadDeleteEventListener?.let { VideoDownloadManager.downloadDeleteEvent -= it }
|
||||
downloadDeleteEventListener = null
|
||||
binding = null
|
||||
super.onDestroyView()
|
||||
}
|
||||
|
|
|
@ -40,7 +40,6 @@ import com.lagradost.cloudstream3.ui.result.setLinearListLayout
|
|||
import com.lagradost.cloudstream3.ui.settings.Globals.TV
|
||||
import com.lagradost.cloudstream3.ui.settings.Globals.isLayout
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.loadResult
|
||||
import com.lagradost.cloudstream3.utils.Coroutines.main
|
||||
import com.lagradost.cloudstream3.utils.DOWNLOAD_EPISODE_CACHE
|
||||
import com.lagradost.cloudstream3.utils.DataStore
|
||||
import com.lagradost.cloudstream3.utils.UIHelper.dismissSafe
|
||||
|
@ -65,16 +64,8 @@ class DownloadFragment : Fragment() {
|
|||
this.layoutParams = param
|
||||
}
|
||||
|
||||
private fun setList(list: List<VisualDownloadHeaderCached>) {
|
||||
main {
|
||||
(binding?.downloadList?.adapter as? DownloadAdapter)?.submitList(list)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
downloadDeleteEventListener?.let {
|
||||
VideoDownloadManager.downloadDeleteEvent -= it
|
||||
}
|
||||
downloadDeleteEventListener?.let { VideoDownloadManager.downloadDeleteEvent -= it }
|
||||
downloadDeleteEventListener = null
|
||||
binding = null
|
||||
super.onDestroyView()
|
||||
|
@ -100,12 +91,10 @@ class DownloadFragment : Fragment() {
|
|||
hideKeyboard()
|
||||
binding?.downloadStorageAppbar?.setAppBarNoScrollFlagsOnTV()
|
||||
|
||||
observe(downloadsViewModel.noDownloadsText) {
|
||||
binding?.textNoDownloads?.text = it
|
||||
}
|
||||
observe(downloadsViewModel.headerCards) {
|
||||
setList(it)
|
||||
(binding?.downloadList?.adapter as? DownloadAdapter)?.submitList(it)
|
||||
binding?.downloadLoading?.isVisible = false
|
||||
binding?.textNoDownloads?.isVisible = it.isEmpty()
|
||||
}
|
||||
observe(downloadsViewModel.availableBytes) {
|
||||
updateStorageInfo(view.context, it, R.string.free_storage, binding?.downloadFreeTxt, binding?.downloadFree)
|
||||
|
@ -164,7 +153,7 @@ class DownloadFragment : Fragment() {
|
|||
|
||||
private fun handleItemClick(click: DownloadHeaderClickEvent) {
|
||||
when (click.action) {
|
||||
0 -> {
|
||||
DOWNLOAD_ACTION_GO_TO_CHILD -> {
|
||||
if (!click.data.type.isMovieType()) {
|
||||
val folder = DataStore.getFolderName(DOWNLOAD_EPISODE_CACHE, click.data.id.toString())
|
||||
activity?.navigate(
|
||||
|
@ -173,7 +162,7 @@ class DownloadFragment : Fragment() {
|
|||
)
|
||||
}
|
||||
}
|
||||
1 -> {
|
||||
DOWNLOAD_ACTION_LOAD_RESULT -> {
|
||||
(activity as AppCompatActivity?)?.loadResult(click.data.url, click.data.apiName)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,17 +16,11 @@ import com.lagradost.cloudstream3.utils.DataStore.getFolderName
|
|||
import com.lagradost.cloudstream3.utils.DataStore.getKey
|
||||
import com.lagradost.cloudstream3.utils.DataStore.getKeys
|
||||
import com.lagradost.cloudstream3.utils.VideoDownloadHelper
|
||||
import com.lagradost.cloudstream3.utils.VideoDownloadManager
|
||||
import com.lagradost.cloudstream3.utils.VideoDownloadManager.getDownloadFileInfoAndUpdateSettings
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
class DownloadViewModel : ViewModel() {
|
||||
private val _noDownloadsText = MutableLiveData<String>().apply {
|
||||
value = ""
|
||||
}
|
||||
val noDownloadsText: LiveData<String> = _noDownloadsText
|
||||
|
||||
private val _headerCards =
|
||||
MutableLiveData<List<VisualDownloadHeaderCached>>().apply { listOf<VisualDownloadHeaderCached>() }
|
||||
val headerCards: LiveData<List<VisualDownloadHeaderCached>> = _headerCards
|
||||
|
@ -43,8 +37,8 @@ class DownloadViewModel : ViewModel() {
|
|||
|
||||
fun updateList(context: Context) = viewModelScope.launchSafe {
|
||||
val children = withContext(Dispatchers.IO) {
|
||||
val headers = context.getKeys(DOWNLOAD_EPISODE_CACHE)
|
||||
headers.mapNotNull { context.getKey<VideoDownloadHelper.DownloadEpisodeCached>(it) }
|
||||
context.getKeys(DOWNLOAD_EPISODE_CACHE)
|
||||
.mapNotNull { context.getKey<VideoDownloadHelper.DownloadEpisodeCached>(it) }
|
||||
.distinctBy { it.id } // Remove duplicates
|
||||
}
|
||||
|
||||
|
@ -57,10 +51,10 @@ class DownloadViewModel : ViewModel() {
|
|||
|
||||
// Gets all children downloads
|
||||
withContext(Dispatchers.IO) {
|
||||
for (c in children) {
|
||||
val childFile = VideoDownloadManager.getDownloadFileInfoAndUpdateSettings(context, c.id) ?: continue
|
||||
children.forEach { c ->
|
||||
val childFile = getDownloadFileInfoAndUpdateSettings(context, c.id) ?: return@forEach
|
||||
|
||||
if (childFile.fileLength <= 1) continue
|
||||
if (childFile.fileLength <= 1) return@forEach
|
||||
val len = childFile.totalBytes
|
||||
val flen = childFile.fileLength
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package com.lagradost.cloudstream3.ui.download.button
|
||||
|
||||
import android.content.Context
|
||||
import android.text.format.Formatter
|
||||
import android.text.format.Formatter.formatShortFileSize
|
||||
import android.util.AttributeSet
|
||||
import android.widget.FrameLayout
|
||||
import android.widget.TextView
|
||||
|
@ -9,6 +9,8 @@ import androidx.annotation.LayoutRes
|
|||
import androidx.core.view.isVisible
|
||||
import androidx.core.widget.ContentLoadingProgressBar
|
||||
import com.lagradost.cloudstream3.R
|
||||
import com.lagradost.cloudstream3.utils.Coroutines.ioSafe
|
||||
import com.lagradost.cloudstream3.utils.Coroutines.mainWork
|
||||
import com.lagradost.cloudstream3.utils.VideoDownloadManager
|
||||
|
||||
typealias DownloadStatusTell = VideoDownloadManager.DownloadType
|
||||
|
@ -34,7 +36,7 @@ abstract class BaseFetchButton(context: Context, attributeSet: AttributeSet) :
|
|||
lateinit var progressBar: ContentLoadingProgressBar
|
||||
var progressText: TextView? = null
|
||||
|
||||
/*val gid: String? get() = sessionIdToGid[persistentId]
|
||||
/* val gid: String? get() = sessionIdToGid[persistentId]
|
||||
|
||||
// used for resuming data
|
||||
var _lastRequestOverride: UriRequest? = null
|
||||
|
@ -44,7 +46,7 @@ abstract class BaseFetchButton(context: Context, attributeSet: AttributeSet) :
|
|||
_lastRequestOverride = value
|
||||
}
|
||||
|
||||
var files: List<AbstractClient.JsonFile> = emptyList()*/
|
||||
var files: List<AbstractClient.JsonFile> = emptyList() */
|
||||
protected var isZeroBytes: Boolean = true
|
||||
|
||||
fun inflate(@LayoutRes layout: Int) {
|
||||
|
@ -55,9 +57,12 @@ abstract class BaseFetchButton(context: Context, attributeSet: AttributeSet) :
|
|||
resetViewData()
|
||||
}
|
||||
|
||||
var doSetProgress = true
|
||||
|
||||
open fun resetViewData() {
|
||||
// lastRequest = null
|
||||
isZeroBytes = true
|
||||
doSetProgress = true
|
||||
persistentId = null
|
||||
}
|
||||
|
||||
|
@ -68,37 +73,45 @@ abstract class BaseFetchButton(context: Context, attributeSet: AttributeSet) :
|
|||
persistentId = id
|
||||
currentMetaData.id = id
|
||||
|
||||
VideoDownloadManager.getDownloadFileInfoAndUpdateSettings(context, id)?.let { savedData ->
|
||||
val downloadedBytes = savedData.fileLength
|
||||
val totalBytes = savedData.totalBytes
|
||||
if (!doSetProgress) return
|
||||
|
||||
/*lastRequest = savedData.uriRequest
|
||||
files = savedData.files
|
||||
ioSafe {
|
||||
val savedData = VideoDownloadManager.getDownloadFileInfoAndUpdateSettings(context, id)
|
||||
|
||||
var totalBytes: Long = 0
|
||||
var downloadedBytes: Long = 0
|
||||
for (file in savedData.files) {
|
||||
downloadedBytes += file.completedLength
|
||||
totalBytes += file.length
|
||||
}*/
|
||||
setProgress(downloadedBytes, totalBytes)
|
||||
// some extra padding for just in case
|
||||
val status = VideoDownloadManager.downloadStatus[id]
|
||||
?: if (downloadedBytes > 1024L && downloadedBytes + 1024L >= totalBytes) DownloadStatusTell.IsDone else DownloadStatusTell.IsPaused
|
||||
currentMetaData.apply {
|
||||
this.id = id
|
||||
this.downloadedLength = downloadedBytes
|
||||
this.totalLength = totalBytes
|
||||
this.status = status
|
||||
mainWork {
|
||||
if (savedData != null) {
|
||||
val downloadedBytes = savedData.fileLength
|
||||
val totalBytes = savedData.totalBytes
|
||||
|
||||
setProgress(downloadedBytes, totalBytes)
|
||||
applyMetaData(id, downloadedBytes, totalBytes)
|
||||
} else run { resetView() }
|
||||
}
|
||||
setStatus(status)
|
||||
} ?: run {
|
||||
resetView()
|
||||
}
|
||||
}
|
||||
|
||||
abstract fun setStatus(status: VideoDownloadManager.DownloadType?)
|
||||
|
||||
fun getStatus(id:Int, downloadedBytes: Long, totalBytes: Long): DownloadStatusTell {
|
||||
// some extra padding for just in case
|
||||
return VideoDownloadManager.downloadStatus[id]
|
||||
?: if (downloadedBytes > 1024L && downloadedBytes + 1024L >= totalBytes) {
|
||||
DownloadStatusTell.IsDone
|
||||
} else DownloadStatusTell.IsPaused
|
||||
}
|
||||
|
||||
fun applyMetaData(id:Int, downloadedBytes: Long, totalBytes: Long) {
|
||||
val status = getStatus(id, downloadedBytes, totalBytes)
|
||||
|
||||
currentMetaData.apply {
|
||||
this.id = id
|
||||
this.downloadedLength = downloadedBytes
|
||||
this.totalLength = totalBytes
|
||||
this.status = status
|
||||
}
|
||||
setStatus(status)
|
||||
}
|
||||
|
||||
open fun setProgress(downloadedBytes: Long, totalBytes: Long) {
|
||||
isZeroBytes = downloadedBytes == 0L
|
||||
progressBar.post {
|
||||
|
@ -124,13 +137,15 @@ abstract class BaseFetchButton(context: Context, attributeSet: AttributeSet) :
|
|||
if (isZeroBytes) {
|
||||
progressText?.isVisible = false
|
||||
} else {
|
||||
progressText?.apply {
|
||||
val currentMbString = Formatter.formatShortFileSize(context, downloadedBytes)
|
||||
val totalMbString = Formatter.formatShortFileSize(context, totalBytes)
|
||||
text =
|
||||
//if (isTextPercentage) "%d%%".format(setCurrentBytes * 100L / setTotalBytes) else
|
||||
context?.getString(R.string.download_size_format)
|
||||
?.format(currentMbString, totalMbString)
|
||||
if (doSetProgress) {
|
||||
progressText?.apply {
|
||||
val currentFormattedSizeString = formatShortFileSize(context, downloadedBytes)
|
||||
val totalFormattedSizeString = formatShortFileSize(context, totalBytes)
|
||||
text =
|
||||
// if (isTextPercentage) "%d%%".format(setCurrentBytes * 100L / setTotalBytes) else
|
||||
context?.getString(R.string.download_size_format)
|
||||
?.format(currentFormattedSizeString, totalFormattedSizeString)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -167,8 +182,8 @@ abstract class BaseFetchButton(context: Context, attributeSet: AttributeSet) :
|
|||
|
||||
override fun onAttachedToWindow() {
|
||||
VideoDownloadManager.downloadStatusEvent += ::downloadStatusEvent
|
||||
//VideoDownloadManager.downloadDeleteEvent += ::downloadDeleteEvent
|
||||
//VideoDownloadManager.downloadEvent += ::downloadEvent
|
||||
// VideoDownloadManager.downloadDeleteEvent += ::downloadDeleteEvent
|
||||
// VideoDownloadManager.downloadEvent += ::downloadEvent
|
||||
VideoDownloadManager.downloadProgressEvent += ::downloadProgressEvent
|
||||
|
||||
val pid = persistentId
|
||||
|
@ -182,8 +197,8 @@ abstract class BaseFetchButton(context: Context, attributeSet: AttributeSet) :
|
|||
|
||||
override fun onDetachedFromWindow() {
|
||||
VideoDownloadManager.downloadStatusEvent -= ::downloadStatusEvent
|
||||
//VideoDownloadManager.downloadDeleteEvent -= ::downloadDeleteEvent
|
||||
//VideoDownloadManager.downloadEvent -= ::downloadEvent
|
||||
// VideoDownloadManager.downloadDeleteEvent -= ::downloadDeleteEvent
|
||||
// VideoDownloadManager.downloadEvent -= ::downloadEvent
|
||||
VideoDownloadManager.downloadProgressEvent -= ::downloadProgressEvent
|
||||
|
||||
super.onDetachedFromWindow()
|
||||
|
@ -198,5 +213,4 @@ abstract class BaseFetchButton(context: Context, attributeSet: AttributeSet) :
|
|||
* Get a clean slate again, might be useful in recyclerview?
|
||||
* */
|
||||
abstract fun resetView()
|
||||
|
||||
}
|
|
@ -13,7 +13,6 @@ import androidx.annotation.MainThread
|
|||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.view.isGone
|
||||
import androidx.core.view.isVisible
|
||||
import com.lagradost.cloudstream3.AcraApplication.Companion.getKey
|
||||
import com.lagradost.cloudstream3.AcraApplication.Companion.removeKey
|
||||
import com.lagradost.cloudstream3.R
|
||||
import com.lagradost.cloudstream3.mvvm.logError
|
||||
|
@ -29,7 +28,6 @@ import com.lagradost.cloudstream3.utils.VideoDownloadHelper
|
|||
import com.lagradost.cloudstream3.utils.VideoDownloadManager
|
||||
import com.lagradost.cloudstream3.utils.VideoDownloadManager.KEY_RESUME_PACKAGES
|
||||
|
||||
|
||||
open class PieFetchButton(context: Context, attributeSet: AttributeSet) :
|
||||
BaseFetchButton(context, attributeSet) {
|
||||
|
||||
|
@ -303,6 +301,7 @@ open class PieFetchButton(context: Context, attributeSet: AttributeSet) :
|
|||
setStatus(null)
|
||||
currentMetaData = DownloadMetadata(0, 0, 0, null)
|
||||
isZeroBytes = true
|
||||
doSetProgress = true
|
||||
progressBar.progress = 0
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@ import androidx.work.Data
|
|||
import androidx.work.ExistingWorkPolicy
|
||||
import androidx.work.OneTimeWorkRequest
|
||||
import androidx.work.WorkManager
|
||||
import com.bumptech.glide.Glide
|
||||
import com.bumptech.glide.load.model.GlideUrl
|
||||
import com.fasterxml.jackson.annotation.JsonProperty
|
||||
import com.lagradost.cloudstream3.APIHolder.getApiFromNameNull
|
||||
|
@ -28,7 +29,6 @@ import com.lagradost.cloudstream3.R
|
|||
import com.lagradost.cloudstream3.TvType
|
||||
import com.lagradost.cloudstream3.app
|
||||
import com.lagradost.cloudstream3.mvvm.logError
|
||||
import com.lagradost.cloudstream3.mvvm.normalSafeApiCall
|
||||
import com.lagradost.cloudstream3.services.VideoDownloadService
|
||||
import com.lagradost.cloudstream3.utils.Coroutines.ioSafe
|
||||
import com.lagradost.cloudstream3.utils.Coroutines.main
|
||||
|
@ -234,10 +234,10 @@ object VideoDownloadManager {
|
|||
return cachedBitmaps[url]
|
||||
}
|
||||
|
||||
val bitmap = com.bumptech.glide.Glide.with(this)
|
||||
val bitmap = Glide.with(this)
|
||||
.asBitmap()
|
||||
.load(GlideUrl(url) { headers ?: emptyMap() })
|
||||
.into(720, 720)
|
||||
.submit(720, 720)
|
||||
.get()
|
||||
|
||||
if (bitmap != null) {
|
||||
|
|
|
@ -143,17 +143,14 @@
|
|||
|
||||
<TextView
|
||||
android:id="@+id/text_no_downloads"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:textAlignment="center"
|
||||
android:textSize="20sp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
android:layout_gravity="center"
|
||||
android:layout_margin="30dp"
|
||||
android:text="@string/downloads_empty"
|
||||
android:gravity="center"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<!--
|
||||
<ProgressBar
|
||||
|
|
|
@ -149,6 +149,7 @@
|
|||
<string name="download_canceled">Download Canceled</string>
|
||||
<string name="download_done">Download Done</string>
|
||||
<string name="download_format" translatable="false">%s - %s</string>
|
||||
<string name="downloads_empty">There are currently no downloads.</string>
|
||||
<string name="update_started">Update Started</string>
|
||||
<string name="stream">Network stream</string>
|
||||
<string name="open_local_video">Open local video</string>
|
||||
|
@ -340,6 +341,10 @@
|
|||
<string name="livestreams">Livestreams</string>
|
||||
<string name="nsfw">NSFW</string>
|
||||
<string name="others">Others</string>
|
||||
<plurals name="episodes" translatable="false">
|
||||
<item quantity="one">@string/episode</item>
|
||||
<item quantity="other">@string/episodes</item>
|
||||
</plurals>
|
||||
<!--singular-->
|
||||
<string name="movies_singular">Movie</string>
|
||||
<string name="tv_series_singular">Series</string>
|
||||
|
|
Loading…
Reference in a new issue