Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion app/src/main/java/us/shandian/giga/get/DownloadMission.java
Original file line number Diff line number Diff line change
Expand Up @@ -661,7 +661,8 @@ public void psContinue(boolean recover) {
* @return {@code true}, if storage is invalid and cannot be used
*/
public boolean hasInvalidStorage() {
return errCode == ERROR_PROGRESS_LOST || storage == null || !storage.existsAsFile();
// Don't consider ERROR_PROGRESS_LOST as invalid storage - it can be recovered
return storage == null || !storage.existsAsFile();
}

/**
Expand Down
57 changes: 45 additions & 12 deletions app/src/main/java/us/shandian/giga/service/DownloadManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
import us.shandian.giga.util.Utility;

import static org.schabi.newpipe.BuildConfig.DEBUG;
import static us.shandian.giga.get.DownloadMission.ERROR_NOTHING;
import static us.shandian.giga.get.DownloadMission.ERROR_PROGRESS_LOST;

public class DownloadManager {
private static final String TAG = DownloadManager.class.getSimpleName();
Expand Down Expand Up @@ -149,12 +151,31 @@ private void loadPendingMissions(Context ctx) {
if (sub.getName().equals(".tmp")) continue;

DownloadMission mis = Utility.readFromFile(sub);
if (mis == null || mis.isFinished() || mis.hasInvalidStorage()) {
if (mis == null) {
//noinspection ResultOfMethodCallIgnored
sub.delete();
continue;
}

// DON'T delete missions that are truly finished - let them be moved to finished list
if (mis.isFinished()) {
// Move to finished missions instead of deleting
setFinished(mis);
//noinspection ResultOfMethodCallIgnored
sub.delete();
continue;
}

// DON'T delete missions with storage issues - try to recover them
if (mis.hasInvalidStorage() && mis.errCode != ERROR_PROGRESS_LOST) {
// Only delete if it's truly unrecoverable (not just progress lost)
if (mis.storage == null) {
//noinspection ResultOfMethodCallIgnored
sub.delete();
continue;
}
}

mis.threads = new Thread[0];

boolean exists;
Expand All @@ -163,16 +184,13 @@ private void loadPendingMissions(Context ctx) {
exists = !mis.storage.isInvalid() && mis.storage.existsAsFile();
} catch (Exception ex) {
Log.e(TAG, "Failed to load the file source of " + mis.storage.toString(), ex);
mis.storage.invalidate();
// Don't invalidate storage immediately - try to recover first
exists = false;
}

if (mis.isPsRunning()) {
if (mis.psAlgorithm.worksOnSameFile) {
// Incomplete post-processing results in a corrupted download file
// because the selected algorithm works on the same file to save space.
// the file will be deleted if the storage API
// is Java IO (avoid showing the "Save as..." dialog)
if (exists && mis.storage.isDirect() && !mis.storage.delete())
Log.w(TAG, "Unable to delete incomplete download file: " + sub.getPath());
}
Expand All @@ -181,10 +199,11 @@ private void loadPendingMissions(Context ctx) {
mis.errCode = DownloadMission.ERROR_POSTPROCESSING_STOPPED;
} else if (!exists) {
tryRecover(mis);

// the progress is lost, reset mission state
if (mis.isInitialized())
mis.resetState(true, true, DownloadMission.ERROR_PROGRESS_LOST);
// Keep the mission even if recovery fails - don't reset to ERROR_PROGRESS_LOST
// This allows user to see the failed download and potentially retry
if (mis.isInitialized() && mis.errCode == ERROR_NOTHING) {
mis.resetState(true, true, ERROR_PROGRESS_LOST);
}
}

if (mis.psAlgorithm != null) {
Expand Down Expand Up @@ -446,7 +465,7 @@ boolean runMissions() {
continue;

resumeMission(mission);
if (mission.errCode != DownloadMission.ERROR_NOTHING) continue;
if (mission.errCode != ERROR_NOTHING) continue;

if (mPrefQueueLimit) return true;
flag = true;
Expand Down Expand Up @@ -510,6 +529,15 @@ void updateMaximumAttempts() {
}
}

public boolean canRecoverMission(DownloadMission mission) {
if (mission == null) return false;

// Can recover missions with progress lost or storage issues
return mission.errCode == ERROR_PROGRESS_LOST ||
mission.storage == null ||
!mission.storage.existsAsFile();
}

public MissionState checkForExistingMission(StoredFileHelper storage) {
synchronized (this) {
DownloadMission pending = getPendingMission(storage);
Expand Down Expand Up @@ -582,8 +610,13 @@ private ArrayList<Object> getSpecialItems() {
ArrayList<Mission> finished = new ArrayList<>(mMissionsFinished);
List<Mission> remove = new ArrayList<>(hidden);

// hide missions (if required)
remove.removeIf(mission -> pending.remove(mission) || finished.remove(mission));
// Don't hide recoverable missions
remove.removeIf(mission -> {
if (mission instanceof DownloadMission dm && canRecoverMission(dm)) {
return false; // Don't remove recoverable missions
}
return pending.remove(mission) || finished.remove(mission);
});

int fakeTotal = pending.size();
if (fakeTotal > 0) fakeTotal++;
Expand Down