Skip to content

Commit a23c136

Browse files
authored
Fixed partial downloads + resume bugs
1 parent 89400be commit a23c136

2 files changed

Lines changed: 57 additions & 14 deletions

File tree

app/src/main/java/com/lagradost/cloudstream3/utils/downloader/DownloadManager.kt

Lines changed: 54 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import androidx.core.net.toUri
2121
import androidx.preference.PreferenceManager
2222
import com.lagradost.cloudstream3.APIHolder.getApiFromNameNull
2323
import com.lagradost.cloudstream3.BuildConfig
24+
import com.lagradost.cloudstream3.CloudStreamApp.Companion.getKey
2425
import com.lagradost.cloudstream3.CommonActivity.showToast
2526
import com.lagradost.cloudstream3.CloudStreamApp.Companion.removeKey
2627
import 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 ->

app/src/main/java/com/lagradost/cloudstream3/utils/downloader/DownloadObjects.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,9 @@ object DownloadObjects {
133133
@JsonProperty("relativePath") val relativePath: String,
134134
@JsonProperty("displayName") val displayName: String,
135135
@JsonProperty("extraInfo") val extraInfo: String? = null,
136-
@JsonProperty("basePath") val basePath: String? = null // null is for legacy downloads. See getBasePath()
136+
@JsonProperty("basePath") val basePath: String? = null, // null is for legacy downloads. See getBasePath()
137+
// Hash of the link associated with this DownloadFile, used so not override old data in the DownloadedFileInfo
138+
@JsonProperty("linkHash") val linkHash : Int? = null
137139
)
138140

139141
data class DownloadedFileInfoResult(

0 commit comments

Comments
 (0)