@@ -21,6 +21,7 @@ import androidx.core.net.toUri
2121import androidx.preference.PreferenceManager
2222import com.lagradost.cloudstream3.APIHolder.getApiFromNameNull
2323import com.lagradost.cloudstream3.BuildConfig
24+ import com.lagradost.cloudstream3.CloudStreamApp.Companion.getKey
2425import com.lagradost.cloudstream3.CommonActivity.showToast
2526import com.lagradost.cloudstream3.CloudStreamApp.Companion.removeKey
2627import com.lagradost.cloudstream3.CloudStreamApp.Companion.setKey
@@ -182,6 +183,13 @@ object VideoDownloadManager {
182183 /* * the process failed due to some reason, so we retry and also try the next mirror */
183184 private val DOWNLOAD_FAILED = DownloadStatus (retrySame = true , tryNext = true , success = false )
184185
186+ /* * The download only downloaded partial */
187+ private val DOWNLOAD_PARTIAL_SUCCESS =
188+ DownloadStatus (retrySame = true , tryNext = false , success = true )
189+
190+ /* * 10MB minimum size */
191+ const val DOWNLOAD_PARTIAL_MIN_SIZE = 1_048_576L * 10L
192+
185193 /* * bad config, skip all mirrors as every call to download will have the same bad config */
186194 private val DOWNLOAD_BAD_CONFIG =
187195 DownloadStatus (retrySame = false , tryNext = false , success = false )
@@ -523,6 +531,7 @@ object VideoDownloadManager {
523531 /* * This class handles the notifications, as well as the relevant key */
524532 data class DownloadMetaData (
525533 private val id : Int? ,
534+ private val linkHash : Int ,
526535 var bytesDownloaded : Long = 0 ,
527536 var bytesWritten : Long = 0 ,
528537
@@ -534,7 +543,7 @@ object VideoDownloadManager {
534543 private val createNotificationCallback : (CreateNotificationMetadata ) -> Unit ,
535544
536545 private var internalType : DownloadType = DownloadType .IsPending ,
537-
546+ val isHLS : Boolean ,
538547 // how many segments that we have downloaded
539548 var hlsProgress : Int = 0 ,
540549 // how many segments that exist
@@ -552,13 +561,17 @@ object VideoDownloadManager {
552561 lastDownloadedBytes = length
553562 }
554563
564+ /* * Returns the appropriate failed status based on download progress */
565+ fun failedStatus () = if (this .bytesWritten > DOWNLOAD_PARTIAL_MIN_SIZE )
566+ DOWNLOAD_PARTIAL_SUCCESS
567+ else
568+ DOWNLOAD_FAILED
569+
555570 val approxTotalBytes: Long
556571 get() = totalBytes ? : hlsTotal?.let { total ->
557572 (bytesDownloaded * (total / hlsProgress.toFloat())).toLong()
558573 } ? : bytesDownloaded
559574
560- private val isHLS get() = hlsTotal != null
561-
562575 private var stopListener: (() -> Unit )? = null
563576
564577 /* * on cancel button pressed or failed invoke this once and only once */
@@ -593,11 +606,32 @@ object VideoDownloadManager {
593606 private fun updateFileInfo () {
594607 if (id == null ) return
595608 downloadFileInfoTemplate?.let { template ->
609+ /* * This looks strange, but fixes an issue where we do an instant retry, and it fails immediately,
610+ * eg. by turning off wifi */
611+ val totalBytesValue = if (approxTotalBytes <= bytesDownloaded) {
612+ val prevInfo = getKey<DownloadedFileInfo >(
613+ KEY_DOWNLOAD_INFO ,
614+ id.toString()
615+ )
616+
617+ /* * If this link is the same as the last cached video link metadata */
618+ if (prevInfo != null && prevInfo.linkHash == linkHash) {
619+ /* * Try to use totalBytes if it exists, otherwise the max of the prev data,
620+ * and download size to ensure total >= downloaded */
621+ totalBytes ? : maxOf(prevInfo.totalBytes, bytesDownloaded)
622+ } else {
623+ approxTotalBytes
624+ }
625+ } else {
626+ approxTotalBytes
627+ }
628+
596629 setKey(
597630 KEY_DOWNLOAD_INFO ,
598631 id.toString(),
599632 template.copy(
600- totalBytes = approxTotalBytes,
633+ linkHash = linkHash,
634+ totalBytes = totalBytesValue,
601635 extraInfo = if (isHLS) hlsWrittenProgress.toString() else null
602636 )
603637 )
@@ -982,6 +1016,8 @@ object VideoDownloadManager {
9821016 bytesDownloaded = 0 ,
9831017 createNotificationCallback = createNotificationCallback,
9841018 id = parentId,
1019+ linkHash = link.url.hashCode(),
1020+ isHLS = false
9851021 )
9861022 try {
9871023 // get the file path
@@ -1171,7 +1207,7 @@ object VideoDownloadManager {
11711207 if (! stream.exists) metadata.type = DownloadType .IsStopped
11721208
11731209 if (metadata.type == DownloadType .IsFailed ) {
1174- return @withContext DOWNLOAD_FAILED
1210+ return @withContext metadata.failedStatus()
11751211 }
11761212
11771213 if (metadata.type == DownloadType .IsStopped ) {
@@ -1201,11 +1237,11 @@ object VideoDownloadManager {
12011237 throw e
12021238 } catch (t: Throwable ) {
12031239 // some sort of network error, will error
1204-
1240+ logError(t)
12051241 // note that when failing we don't want to delete the file,
12061242 // only user interaction has that power
12071243 metadata.type = DownloadType .IsFailed
1208- return @withContext DOWNLOAD_FAILED
1244+ return @withContext metadata.failedStatus()
12091245 } finally {
12101246 fileStream?.closeQuietly()
12111247 // requestStream?.closeQuietly()
@@ -1227,7 +1263,9 @@ object VideoDownloadManager {
12271263
12281264 val metadata = DownloadMetaData (
12291265 createNotificationCallback = createNotificationCallback,
1230- id = parentId
1266+ id = parentId,
1267+ linkHash = link.url.hashCode(),
1268+ isHLS = true
12311269 )
12321270 var fileStream: OutputStream ? = null
12331271 try {
@@ -1385,7 +1423,7 @@ object VideoDownloadManager {
13851423 if (! stream.exists) metadata.type = DownloadType .IsStopped
13861424
13871425 if (metadata.type == DownloadType .IsFailed ) {
1388- return @withContext DOWNLOAD_FAILED
1426+ return @withContext metadata.failedStatus()
13891427 }
13901428
13911429 if (metadata.type == DownloadType .IsStopped ) {
@@ -1401,7 +1439,7 @@ object VideoDownloadManager {
14011439 } catch (t: Throwable ) {
14021440 logError(t)
14031441 metadata.type = DownloadType .IsFailed
1404- return @withContext DOWNLOAD_FAILED
1442+ return @withContext metadata.failedStatus()
14051443 } finally {
14061444 fileStream?.closeQuietly()
14071445 metadata.close()
@@ -1983,7 +2021,8 @@ object VideoDownloadManager {
19832021 linkLoadingJob?.join()
19842022
19852023 // Remove link loading notification
1986- NotificationManagerCompat .from(context).cancel(DOWNLOAD_NOTIFICATION_TAG , downloadItem.episode.id)
2024+ NotificationManagerCompat .from(context)
2025+ .cancel(DOWNLOAD_NOTIFICATION_TAG , downloadItem.episode.id)
19872026
19882027 if (linkLoadingJob?.isCancelled == true ) {
19892028 // Same as if no links, but no toast.
@@ -2009,8 +2048,10 @@ object VideoDownloadManager {
20092048 }
20102049
20112050 // Profiles should always contain a download type
2012- val profile = QualityDataHelper .getProfiles().first { it.types.contains(
2013- QualityDataHelper .QualityProfileType .Download )
2051+ val profile = QualityDataHelper .getProfiles().first {
2052+ it.types.contains(
2053+ QualityDataHelper .QualityProfileType .Download
2054+ )
20142055 }
20152056
20162057 val sortedLinks = currentLinks.sortedBy { link ->
0 commit comments