long-term downloads resume

* recovery infrastructure
* bump serialVersionUID of DownloadMission
* misc cleanup in DownloadMission.java
* remove unused/redundant from strings.xml
This commit is contained in:
kapodamy 2019-09-28 18:11:05 -03:00
parent 0cdfa6e377
commit c891f2f1ed
42 changed files with 478 additions and 97 deletions

View File

@ -68,6 +68,7 @@ import java.util.Locale;
import icepick.Icepick;
import icepick.State;
import io.reactivex.disposables.CompositeDisposable;
import us.shandian.giga.get.MissionRecoveryInfo;
import us.shandian.giga.io.StoredDirectoryHelper;
import us.shandian.giga.io.StoredFileHelper;
import us.shandian.giga.postprocessing.Postprocessing;
@ -762,12 +763,13 @@ public class DownloadDialog extends DialogFragment implements RadioGroup.OnCheck
}
Stream selectedStream;
Stream secondaryStream = null;
char kind;
int threads = threadsSeekBar.getProgress() + 1;
String[] urls;
MissionRecoveryInfo[] recoveryInfo;
String psName = null;
String[] psArgs = null;
String secondaryStreamUrl = null;
long nearLength = 0;
// more download logic: select muxer, subtitle converter, etc.
@ -786,12 +788,12 @@ public class DownloadDialog extends DialogFragment implements RadioGroup.OnCheck
kind = 'v';
selectedStream = videoStreamsAdapter.getItem(selectedVideoIndex);
SecondaryStreamHelper<AudioStream> secondaryStream = videoStreamsAdapter
SecondaryStreamHelper<AudioStream> secondary = videoStreamsAdapter
.getAllSecondary()
.get(wrappedVideoStreams.getStreamsList().indexOf(selectedStream));
if (secondaryStream != null) {
secondaryStreamUrl = secondaryStream.getStream().getUrl();
if (secondary != null) {
secondaryStream = secondary.getStream();
if (selectedStream.getFormat() == MediaFormat.MPEG_4)
psName = Postprocessing.ALGORITHM_MP4_FROM_DASH_MUXER;
@ -803,8 +805,8 @@ public class DownloadDialog extends DialogFragment implements RadioGroup.OnCheck
// set nearLength, only, if both sizes are fetched or known. This probably
// does not work on slow networks but is later updated in the downloader
if (secondaryStream.getSizeInBytes() > 0 && videoSize > 0) {
nearLength = secondaryStream.getSizeInBytes() + videoSize;
if (secondary.getSizeInBytes() > 0 && videoSize > 0) {
nearLength = secondary.getSizeInBytes() + videoSize;
}
}
break;
@ -826,13 +828,25 @@ public class DownloadDialog extends DialogFragment implements RadioGroup.OnCheck
return;
}
if (secondaryStreamUrl == null) {
urls = new String[]{selectedStream.getUrl()};
if (secondaryStream == null) {
urls = new String[]{
selectedStream.getUrl()
};
recoveryInfo = new MissionRecoveryInfo[]{
new MissionRecoveryInfo(selectedStream)
};
} else {
urls = new String[]{selectedStream.getUrl(), secondaryStreamUrl};
urls = new String[]{
selectedStream.getUrl(), secondaryStream.getUrl()
};
recoveryInfo = new MissionRecoveryInfo[]{
new MissionRecoveryInfo(selectedStream), new MissionRecoveryInfo(secondaryStream)
};
}
DownloadManagerService.startMission(context, urls, storage, kind, threads, currentInfo.getUrl(), psName, psArgs, nearLength);
DownloadManagerService.startMission(
context, urls, storage, kind, threads, currentInfo.getUrl(), psName, psArgs, nearLength, recoveryInfo
);
dismiss();
}

View File

@ -1,6 +1,7 @@
package us.shandian.giga.get;
import androidx.annotation.NonNull;
import android.text.TextUtils;
import android.util.Log;
import org.schabi.newpipe.streams.io.SharpStream;
@ -151,6 +152,20 @@ public class DownloadInitializer extends Thread {
if (!mMission.running || Thread.interrupted()) return;
if (!mMission.unknownLength && mMission.recoveryInfo != null) {
String entityTag = mConn.getHeaderField("ETAG");
String lastModified = mConn.getHeaderField("Last-Modified");
MissionRecoveryInfo recovery = mMission.recoveryInfo[mMission.current];
if (!TextUtils.isEmpty(entityTag)) {
recovery.validateCondition = entityTag;
} else if (!TextUtils.isEmpty(lastModified)) {
recovery.validateCondition = lastModified;// Note: this is less precise
} else {
recovery.validateCondition = null;
}
}
mMission.running = false;
break;
} catch (InterruptedIOException | ClosedByInterruptException e) {

View File

@ -27,7 +27,7 @@ import us.shandian.giga.util.Utility;
import static org.schabi.newpipe.BuildConfig.DEBUG;
public class DownloadMission extends Mission {
private static final long serialVersionUID = 5L;// last bump: 30 june 2019
private static final long serialVersionUID = 6L;// last bump: 28 september 2019
static final int BUFFER_SIZE = 64 * 1024;
static final int BLOCK_SIZE = 512 * 1024;
@ -51,8 +51,9 @@ public class DownloadMission extends Mission {
public static final int ERROR_INSUFFICIENT_STORAGE = 1010;
public static final int ERROR_PROGRESS_LOST = 1011;
public static final int ERROR_TIMEOUT = 1012;
public static final int ERROR_RESOURCE_GONE = 1013;
public static final int ERROR_HTTP_NO_CONTENT = 204;
public static final int ERROR_HTTP_UNSUPPORTED_RANGE = 206;
static final int ERROR_HTTP_FORBIDDEN = 403;
/**
* The urls of the file to download
@ -125,6 +126,11 @@ public class DownloadMission extends Mission {
*/
public int threadCount = 3;
/**
* information required to recover a download
*/
public MissionRecoveryInfo[] recoveryInfo;
private transient int finishCount;
public transient boolean running;
public boolean enqueued;
@ -132,7 +138,6 @@ public class DownloadMission extends Mission {
public int errCode = ERROR_NOTHING;
public Exception errObject = null;
public transient boolean recovered;
public transient Handler mHandler;
private transient boolean mWritingToFile;
private transient boolean[] blockAcquired;
@ -197,9 +202,9 @@ public class DownloadMission extends Mission {
}
/**
* Open connection
* Opens a connection
*
* @param threadId id of the calling thread, used only for debug
* @param threadId id of the calling thread, used only for debugging
* @param rangeStart range start
* @param rangeEnd range end
* @return a {@link java.net.URLConnection URLConnection} linking to the URL.
@ -251,7 +256,7 @@ public class DownloadMission extends Mission {
case 204:
case 205:
case 207:
throw new HttpError(conn.getResponseCode());
throw new HttpError(statusCode);
case 416:
return;// let the download thread handle this error
default:
@ -270,10 +275,6 @@ public class DownloadMission extends Mission {
synchronized void notifyProgress(long deltaLen) {
if (!running) return;
if (recovered) {
recovered = false;
}
if (unknownLength) {
length += deltaLen;// Update length before proceeding
}
@ -344,7 +345,6 @@ public class DownloadMission extends Mission {
if (running) {
running = false;
recovered = true;
if (threads != null) selfPause();
}
}
@ -409,12 +409,13 @@ public class DownloadMission extends Mission {
* Start downloading with multiple threads.
*/
public void start() {
if (running || isFinished()) return;
if (running || isFinished() || urls.length < 1) return;
// ensure that the previous state is completely paused.
joinForThread(init);
int maxWait = 10000;// 10 seconds
joinForThread(init, maxWait);
if (threads != null) {
for (Thread thread : threads) joinForThread(thread);
for (Thread thread : threads) joinForThread(thread, maxWait);
threads = null;
}
@ -431,6 +432,11 @@ public class DownloadMission extends Mission {
return;
}
if (urls[current] == null) {
doRecover(null);
return;
}
if (blocks == null) {
initializer();
return;
@ -478,7 +484,6 @@ public class DownloadMission extends Mission {
}
running = false;
recovered = true;
if (init != null && init.isAlive()) {
// NOTE: if start() method is running ¡will no have effect!
@ -563,7 +568,7 @@ public class DownloadMission extends Mission {
* Write this {@link DownloadMission} to the meta file asynchronously
* if no thread is already running.
*/
private void writeThisToFile() {
void writeThisToFile() {
synchronized (LOCK) {
if (deleted) return;
Utility.writeToFile(metadata, DownloadMission.this);
@ -667,6 +672,7 @@ public class DownloadMission extends Mission {
* @return {@code true} is this mission its "healthy", otherwise, {@code false}
*/
public boolean isCorrupt() {
if (urls.length < 1) return false;
return (isPsFailed() || errCode == ERROR_POSTPROCESSING_HOLD) || isFinished();
}
@ -710,6 +716,48 @@ public class DownloadMission extends Mission {
return true;
}
/**
* Attempts to recover the download
*
* @param fromError exception which require update the url from the source
*/
void doRecover(Exception fromError) {
Log.i(TAG, "Attempting to recover the mission: " + storage.getName());
if (recoveryInfo == null) {
if (fromError == null)
notifyError(ERROR_RESOURCE_GONE, null);
else
notifyError(fromError);
urls = new String[0];// mark this mission as dead
return;
}
if (threads != null) {
for (Thread thread : threads) {
if (thread == Thread.currentThread()) continue;
thread.interrupt();
joinForThread(thread, 0);
}
}
// set the current download url to null in case if the recovery
// process is canceled. Next time start() method is called the
// recovery will be executed, saving time
urls[current] = null;
if (recoveryInfo[current].attempts >= maxRetry) {
recoveryInfo[current].attempts = 0;
notifyError(fromError);
return;
}
threads = new Thread[]{
runAsync(DownloadMissionRecover.mID, new DownloadMissionRecover(this, fromError))
};
}
private boolean deleteThisFromFile() {
synchronized (LOCK) {
return metadata.delete();
@ -749,7 +797,13 @@ public class DownloadMission extends Mission {
return who;
}
private void joinForThread(Thread thread) {
/**
* Waits at most {@code millis} milliseconds for the thread to die
*
* @param thread the desired thread
* @param millis the time to wait in milliseconds
*/
private void joinForThread(Thread thread, int millis) {
if (thread == null || !thread.isAlive()) return;
if (thread == Thread.currentThread()) return;
@ -764,7 +818,7 @@ public class DownloadMission extends Mission {
// start() method called quickly after pause()
try {
thread.join(10000);
thread.join(millis);
} catch (InterruptedException e) {
Log.d(TAG, "timeout on join : " + thread.getName());
throw new RuntimeException("A thread is still running:\n" + thread.getName());
@ -785,9 +839,9 @@ public class DownloadMission extends Mission {
}
}
static class Block {
int position;
int done;
public static class Block {
public int position;
public int done;
}
private static class Lock implements Serializable {

View File

@ -0,0 +1,222 @@
package us.shandian.giga.get;
import android.util.Log;
import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.extractor.StreamingService;
import org.schabi.newpipe.extractor.stream.AudioStream;
import org.schabi.newpipe.extractor.stream.StreamExtractor;
import org.schabi.newpipe.extractor.stream.SubtitlesStream;
import org.schabi.newpipe.extractor.stream.VideoStream;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.nio.channels.ClosedByInterruptException;
import java.util.List;
import static us.shandian.giga.get.DownloadMission.ERROR_RESOURCE_GONE;
public class DownloadMissionRecover extends Thread {
private static final String TAG = "DownloadMissionRecover";
static final int mID = -3;
private final DownloadMission mMission;
private final MissionRecoveryInfo mRecovery;
private final Exception mFromError;
private HttpURLConnection mConn;
DownloadMissionRecover(DownloadMission mission, Exception originError) {
mMission = mission;
mFromError = originError;
mRecovery = mission.recoveryInfo[mission.current];
}
@Override
public void run() {
if (mMission.source == null) {
mMission.notifyError(mFromError);
return;
}
try {
/*if (mMission.source.startsWith(MissionRecoveryInfo.DIRECT_SOURCE)) {
resolve(mMission.source.substring(MissionRecoveryInfo.DIRECT_SOURCE.length()));
return;
}*/
StreamingService svr = NewPipe.getServiceByUrl(mMission.source);
if (svr == null) {
throw new RuntimeException("Unknown source service");
}
StreamExtractor extractor = svr.getStreamExtractor(mMission.source);
extractor.fetchPage();
if (!mMission.running || super.isInterrupted()) return;
String url = null;
switch (mMission.kind) {
case 'a':
for (AudioStream audio : extractor.getAudioStreams()) {
if (audio.average_bitrate == mRecovery.desiredBitrate && audio.getFormat() == mRecovery.format) {
url = audio.getUrl();
break;
}
}
break;
case 'v':
List<VideoStream> videoStreams;
if (mRecovery.desired2)
videoStreams = extractor.getVideoOnlyStreams();
else
videoStreams = extractor.getVideoStreams();
for (VideoStream video : videoStreams) {
if (video.resolution.equals(mRecovery.desired) && video.getFormat() == mRecovery.format) {
url = video.getUrl();
break;
}
}
break;
case 's':
for (SubtitlesStream subtitles : extractor.getSubtitles(mRecovery.format)) {
String tag = subtitles.getLanguageTag();
if (tag.equals(mRecovery.desired) && subtitles.isAutoGenerated() == mRecovery.desired2) {
url = subtitles.getURL();
break;
}
}
break;
default:
throw new RuntimeException("Unknown stream type");
}
resolve(url);
} catch (Exception e) {
if (!mMission.running || e instanceof ClosedByInterruptException) return;
mRecovery.attempts++;
mMission.notifyError(e);
}
}
private void resolve(String url) throws IOException, DownloadMission.HttpError {
if (mRecovery.validateCondition == null) {
Log.w(TAG, "validation condition not defined, the resource can be stale");
}
if (mMission.unknownLength || mRecovery.validateCondition == null) {
recover(url, false);
return;
}
///////////////////////////////////////////////////////////////////////
////// Validate the http resource doing a range request
/////////////////////
try {
mConn = mMission.openConnection(url, mID, mMission.length - 10, mMission.length);
mConn.setRequestProperty("If-Range", mRecovery.validateCondition);
mMission.establishConnection(mID, mConn);
int code = mConn.getResponseCode();
switch (code) {
case 200:
case 413:
// stale
recover(url, true);
return;
case 206:
// in case of validation using the Last-Modified date, check the resource length
long[] contentRange = parseContentRange(mConn.getHeaderField("Content-Range"));
boolean lengthMismatch = contentRange[2] != -1 && contentRange[2] != mMission.length;
recover(url, lengthMismatch);
return;
}
throw new DownloadMission.HttpError(code);
} catch (Exception e) {
if (!mMission.running || e instanceof ClosedByInterruptException) return;
throw e;
} finally {
this.interrupt();
}
}
private void recover(String url, boolean stale) {
Log.i(TAG,
String.format("download recovered name=%s isStale=%s url=%s", mMission.storage.getName(), stale, url)
);
if (url == null) {
mMission.notifyError(ERROR_RESOURCE_GONE, null);
return;
}
mMission.urls[mMission.current] = url;
mRecovery.attempts = 0;
if (stale) {
mMission.resetState(false, false, DownloadMission.ERROR_NOTHING);
}
mMission.writeThisToFile();
if (!mMission.running || super.isInterrupted()) return;
mMission.running = false;
mMission.start();
}
private long[] parseContentRange(String value) {
long[] range = new long[3];
if (value == null) {
// this never should happen
return range;
}
try {
value = value.trim();
if (!value.startsWith("bytes")) {
return range;// unknown range type
}
int space = value.lastIndexOf(' ') + 1;
int dash = value.indexOf('-', space) + 1;
int bar = value.indexOf('/', dash);
// start
range[0] = Long.parseLong(value.substring(space, dash - 1));
// end
range[1] = Long.parseLong(value.substring(dash, bar));
// resource length
value = value.substring(bar + 1);
if (value.equals("*")) {
range[2] = -1;// unknown length received from the server but should be valid
} else {
range[2] = Long.parseLong(value);
}
} catch (Exception e) {
// nothing to do
}
return range;
}
@Override
public void interrupt() {
super.interrupt();
if (mConn != null) {
try {
mConn.disconnect();
} catch (Exception e) {
// nothing to do
}
}
}
}

View File

@ -10,8 +10,10 @@ import java.net.HttpURLConnection;
import java.nio.channels.ClosedByInterruptException;
import us.shandian.giga.get.DownloadMission.Block;
import us.shandian.giga.get.DownloadMission.HttpError;
import static org.schabi.newpipe.BuildConfig.DEBUG;
import static us.shandian.giga.get.DownloadMission.ERROR_HTTP_FORBIDDEN;
/**
@ -19,7 +21,7 @@ import static org.schabi.newpipe.BuildConfig.DEBUG;
* an error occurs or the process is stopped.
*/
public class DownloadRunnable extends Thread {
private static final String TAG = DownloadRunnable.class.getSimpleName();
private static final String TAG = "DownloadRunnable";
private final DownloadMission mMission;
private final int mId;
@ -41,13 +43,7 @@ public class DownloadRunnable extends Thread {
public void run() {
boolean retry = false;
Block block = null;
int retryCount = 0;
if (DEBUG) {
Log.d(TAG, mId + ":recovered: " + mMission.recovered);
}
SharpStream f;
try {
@ -133,6 +129,17 @@ public class DownloadRunnable extends Thread {
} catch (Exception e) {
if (!mMission.running || e instanceof ClosedByInterruptException) break;
if (e instanceof HttpError && ((HttpError) e).statusCode == ERROR_HTTP_FORBIDDEN) {
// for youtube streams. The url has expired, recover
f.close();
if (mId == 1) {
// only the first thread will execute the recovery procedure
mMission.doRecover(e);
}
return;
}
if (retryCount++ >= mMission.maxRetry) {
mMission.notifyError(e);
break;
@ -144,11 +151,7 @@ public class DownloadRunnable extends Thread {
}
}
try {
f.close();
} catch (Exception err) {
// ¿ejected media storage? ¿file deleted? ¿storage ran out of space?
}
f.close();
if (DEBUG) {
Log.d(TAG, "thread " + mId + " exited from main download loop");

View File

@ -10,9 +10,11 @@ import java.io.InputStream;
import java.net.HttpURLConnection;
import java.nio.channels.ClosedByInterruptException;
import us.shandian.giga.get.DownloadMission.HttpError;
import us.shandian.giga.util.Utility;
import static org.schabi.newpipe.BuildConfig.DEBUG;
import static us.shandian.giga.get.DownloadMission.ERROR_HTTP_FORBIDDEN;
/**
* Single-threaded fallback mode
@ -85,7 +87,7 @@ public class DownloadRunnableFallback extends Thread {
mIs = mConn.getInputStream();
byte[] buf = new byte[64 * 1024];
byte[] buf = new byte[DownloadMission.BUFFER_SIZE];
int len = 0;
while (mMission.running && (len = mIs.read(buf, 0, buf.length)) != -1) {
@ -103,6 +105,13 @@ public class DownloadRunnableFallback extends Thread {
if (!mMission.running || e instanceof ClosedByInterruptException) return;
if (e instanceof HttpError && ((HttpError) e).statusCode == ERROR_HTTP_FORBIDDEN) {
// for youtube streams. The url has expired, recover
mMission.doRecover(e);
dispose();
return;
}
if (mRetryCount++ >= mMission.maxRetry) {
mMission.notifyError(e);
return;

View File

@ -0,0 +1,79 @@
package us.shandian.giga.get;
import android.os.Parcel;
import android.os.Parcelable;
import android.support.annotation.NonNull;
import org.schabi.newpipe.extractor.MediaFormat;
import org.schabi.newpipe.extractor.stream.AudioStream;
import org.schabi.newpipe.extractor.stream.Stream;
import org.schabi.newpipe.extractor.stream.SubtitlesStream;
import org.schabi.newpipe.extractor.stream.VideoStream;
import java.io.Serializable;
public class MissionRecoveryInfo implements Serializable, Parcelable {
private static final long serialVersionUID = 0L;
//public static final String DIRECT_SOURCE = "direct-source://";
public MediaFormat format;
String desired;
boolean desired2;
int desiredBitrate;
transient int attempts = 0;
String validateCondition = null;
public MissionRecoveryInfo(@NonNull Stream stream) {
if (stream instanceof AudioStream) {
desiredBitrate = ((AudioStream) stream).average_bitrate;
desired2 = false;
} else if (stream instanceof VideoStream) {
desired = ((VideoStream) stream).getResolution();
desired2 = ((VideoStream) stream).isVideoOnly();
} else if (stream instanceof SubtitlesStream) {
desired = ((SubtitlesStream) stream).getLanguageTag();
desired2 = ((SubtitlesStream) stream).isAutoGenerated();
} else {
throw new RuntimeException("Unknown stream kind");
}
format = stream.getFormat();
if (format == null) throw new NullPointerException("Stream format cannot be null");
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel parcel, int flags) {
parcel.writeInt(this.format.ordinal());
parcel.writeString(this.desired);
parcel.writeInt(this.desired2 ? 0x01 : 0x00);
parcel.writeInt(this.desiredBitrate);
parcel.writeString(this.validateCondition);
}
private MissionRecoveryInfo(Parcel parcel) {
this.format = MediaFormat.values()[parcel.readInt()];
this.desired = parcel.readString();
this.desired2 = parcel.readInt() != 0x00;
this.desiredBitrate = parcel.readInt();
this.validateCondition = parcel.readString();
}
public static final Parcelable.Creator<MissionRecoveryInfo> CREATOR = new Parcelable.Creator<MissionRecoveryInfo>() {
@Override
public MissionRecoveryInfo createFromParcel(Parcel source) {
return new MissionRecoveryInfo(source);
}
@Override
public MissionRecoveryInfo[] newArray(int size) {
return new MissionRecoveryInfo[size];
}
};
}

View File

@ -177,7 +177,6 @@ public class DownloadManager {
mis.psAlgorithm.setTemporalDir(pickAvailableTemporalDir(ctx));
}
mis.recovered = exists;
mis.metadata = sub;
mis.maxRetry = mPrefMaxRetry;
mis.mHandler = mHandler;

View File

@ -23,6 +23,7 @@ import android.os.Handler;
import android.os.Handler.Callback;
import android.os.IBinder;
import android.os.Message;
import android.os.Parcelable;
import android.preference.PreferenceManager;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@ -40,8 +41,11 @@ import org.schabi.newpipe.player.helper.LockManager;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import us.shandian.giga.get.DownloadMission;
import us.shandian.giga.get.MissionRecoveryInfo;
import us.shandian.giga.io.StoredDirectoryHelper;
import us.shandian.giga.io.StoredFileHelper;
import us.shandian.giga.postprocessing.Postprocessing;
@ -73,6 +77,7 @@ public class DownloadManagerService extends Service {
private static final String EXTRA_PATH = "DownloadManagerService.extra.storagePath";
private static final String EXTRA_PARENT_PATH = "DownloadManagerService.extra.storageParentPath";
private static final String EXTRA_STORAGE_TAG = "DownloadManagerService.extra.storageTag";
private static final String EXTRA_RECOVERY_INFO = "DownloadManagerService.extra.recoveryInfo";
private static final String ACTION_RESET_DOWNLOAD_FINISHED = APPLICATION_ID + ".reset_download_finished";
private static final String ACTION_OPEN_DOWNLOADS_FINISHED = APPLICATION_ID + ".open_downloads_finished";
@ -364,18 +369,20 @@ public class DownloadManagerService extends Service {
/**
* Start a new download mission
*
* @param context the activity context
* @param urls the list of urls to download
* @param storage where the file is saved
* @param kind type of file (a: audio v: video s: subtitle ?: file-extension defined)
* @param threads the number of threads maximal used to download chunks of the file.
* @param psName the name of the required post-processing algorithm, or {@code null} to ignore.
* @param source source url of the resource
* @param psArgs the arguments for the post-processing algorithm.
* @param nearLength the approximated final length of the file
* @param context the activity context
* @param urls array of urls to download
* @param storage where the file is saved
* @param kind type of file (a: audio v: video s: subtitle ?: file-extension defined)
* @param threads the number of threads maximal used to download chunks of the file.
* @param psName the name of the required post-processing algorithm, or {@code null} to ignore.
* @param source source url of the resource
* @param psArgs the arguments for the post-processing algorithm.
* @param nearLength the approximated final length of the file
* @param recoveryInfo array of MissionRecoveryInfo, in case is required recover the download
*/
public static void startMission(Context context, String[] urls, StoredFileHelper storage, char kind,
int threads, String source, String psName, String[] psArgs, long nearLength) {
public static void startMission(Context context, String[] urls, StoredFileHelper storage,
char kind, int threads, String source, String psName,
String[] psArgs, long nearLength, MissionRecoveryInfo[] recoveryInfo) {
Intent intent = new Intent(context, DownloadManagerService.class);
intent.setAction(Intent.ACTION_RUN);
intent.putExtra(EXTRA_URLS, urls);
@ -385,6 +392,7 @@ public class DownloadManagerService extends Service {
intent.putExtra(EXTRA_POSTPROCESSING_NAME, psName);
intent.putExtra(EXTRA_POSTPROCESSING_ARGS, psArgs);
intent.putExtra(EXTRA_NEAR_LENGTH, nearLength);
intent.putExtra(EXTRA_RECOVERY_INFO, recoveryInfo);
intent.putExtra(EXTRA_PARENT_PATH, storage.getParentUri());
intent.putExtra(EXTRA_PATH, storage.getUri());
@ -404,6 +412,7 @@ public class DownloadManagerService extends Service {
String source = intent.getStringExtra(EXTRA_SOURCE);
long nearLength = intent.getLongExtra(EXTRA_NEAR_LENGTH, 0);
String tag = intent.getStringExtra(EXTRA_STORAGE_TAG);
Parcelable[] parcelRecovery = intent.getParcelableArrayExtra(EXTRA_RECOVERY_INFO);
StoredFileHelper storage;
try {
@ -418,10 +427,15 @@ public class DownloadManagerService extends Service {
else
ps = Postprocessing.getAlgorithm(psName, psArgs);
MissionRecoveryInfo[] recovery = new MissionRecoveryInfo[parcelRecovery.length];
for (int i = 0; i < parcelRecovery.length; i++)
recovery[i] = (MissionRecoveryInfo) parcelRecovery[i];
final DownloadMission mission = new DownloadMission(urls, storage, kind, ps);
mission.threadCount = threads;
mission.source = source;
mission.nearLength = nearLength;
mission.recoveryInfo = recovery;
if (ps != null)
ps.setTemporalDir(DownloadManager.pickAvailableTemporalDir(this));

View File

@ -62,7 +62,6 @@ import static android.content.Intent.FLAG_GRANT_READ_URI_PERMISSION;
import static us.shandian.giga.get.DownloadMission.ERROR_CONNECT_HOST;
import static us.shandian.giga.get.DownloadMission.ERROR_FILE_CREATION;
import static us.shandian.giga.get.DownloadMission.ERROR_HTTP_NO_CONTENT;
import static us.shandian.giga.get.DownloadMission.ERROR_HTTP_UNSUPPORTED_RANGE;
import static us.shandian.giga.get.DownloadMission.ERROR_INSUFFICIENT_STORAGE;
import static us.shandian.giga.get.DownloadMission.ERROR_NOTHING;
import static us.shandian.giga.get.DownloadMission.ERROR_PATH_CREATION;
@ -71,6 +70,7 @@ import static us.shandian.giga.get.DownloadMission.ERROR_POSTPROCESSING;
import static us.shandian.giga.get.DownloadMission.ERROR_POSTPROCESSING_HOLD;
import static us.shandian.giga.get.DownloadMission.ERROR_POSTPROCESSING_STOPPED;
import static us.shandian.giga.get.DownloadMission.ERROR_PROGRESS_LOST;
import static us.shandian.giga.get.DownloadMission.ERROR_RESOURCE_GONE;
import static us.shandian.giga.get.DownloadMission.ERROR_SSL_EXCEPTION;
import static us.shandian.giga.get.DownloadMission.ERROR_TIMEOUT;
import static us.shandian.giga.get.DownloadMission.ERROR_UNKNOWN_EXCEPTION;
@ -430,7 +430,7 @@ public class MissionAdapter extends Adapter<ViewHolder> implements Handler.Callb
switch (mission.errCode) {
case 416:
msg = R.string.error_http_requested_range_not_satisfiable;
msg = R.string.error_http_unsupported_range;
break;
case 404:
msg = R.string.error_http_not_found;
@ -443,9 +443,6 @@ public class MissionAdapter extends Adapter<ViewHolder> implements Handler.Callb
case ERROR_HTTP_NO_CONTENT:
msg = R.string.error_http_no_content;
break;
case ERROR_HTTP_UNSUPPORTED_RANGE:
msg = R.string.error_http_unsupported_range;
break;
case ERROR_PATH_CREATION:
msg = R.string.error_path_creation;
break;
@ -480,6 +477,9 @@ public class MissionAdapter extends Adapter<ViewHolder> implements Handler.Callb
case ERROR_TIMEOUT:
msg = R.string.error_timeout;
break;
case ERROR_RESOURCE_GONE:
msg = R.string.error_download_resource_gone;
break;
default:
if (mission.errCode >= 100 && mission.errCode < 600) {
msgEx = "HTTP " + mission.errCode;
@ -859,7 +859,7 @@ public class MissionAdapter extends Adapter<ViewHolder> implements Handler.Callb
delete.setVisible(true);
boolean flag = !mission.isPsFailed();
boolean flag = !mission.isPsFailed() && mission.urls.length > 0;
start.setVisible(flag);
queue.setVisible(flag);
}

View File

@ -468,7 +468,6 @@
<string name="error_connect_host">لا يمكن الاتصال بالخادم</string>
<string name="error_http_no_content">الخادم لايقوم بإرسال البيانات</string>
<string name="error_http_unsupported_range">الخادم لا يقبل التنزيل المتعدد، إعادة المحاولة مع @string/msg_threads = 1</string>
<string name="error_http_requested_range_not_satisfiable">عدم استيفاء النطاق المطلوب</string>
<string name="error_http_not_found">غير موجود</string>
<string name="error_postprocessing_failed">فشلت المعالجة الاولية</string>
<string name="clear_finished_download">حذف التنزيلات المنتهية</string>

View File

@ -455,7 +455,6 @@
<string name="error_connect_host">Немагчыма злучыцца з серверам</string>
<string name="error_http_no_content">Не атрымалася атрымаць дадзеныя з сервера</string>
<string name="error_http_unsupported_range">Сервер не падтрымлівае шматструменную загрузку, паспрабуйце з @string/msg_threads = 1</string>
<string name="error_http_requested_range_not_satisfiable">Запытаны дыяпазон недапушчальны</string>
<string name="error_http_not_found">Не знойдзена</string>
<string name="error_postprocessing_failed">Пасляапрацоўка не ўдалася</string>
<string name="clear_finished_download">Ачысціць завершаныя</string>

View File

@ -460,7 +460,6 @@
<string name="app_update_notification_content_title">NewPipe 更新可用!</string>
<string name="error_path_creation">无法创建目标文件夹</string>
<string name="error_http_unsupported_range">服务器不接受多线程下载, 请使用 @string/msg_threads = 1重试</string>
<string name="error_http_requested_range_not_satisfiable">请求范围无法满足</string>
<string name="msg_pending_downloads">继续进行%s个待下载转移</string>
<string name="pause_downloads_on_mobile_desc">切换至移动数据时有用,尽管一些下载无法被暂停</string>
<string name="show_comments_title">显示评论</string>

View File

@ -463,7 +463,6 @@ otevření ve vyskakovacím okně</string>
<string name="error_connect_host">Nelze se připojit k serveru</string>
<string name="error_http_no_content">Server neposílá data</string>
<string name="error_http_unsupported_range">Server neakceptuje vícevláknové stahování, opakujte akci s @string/msg_threads = 1</string>
<string name="error_http_requested_range_not_satisfiable">Požadovaný rozsah nelze splnit</string>
<string name="error_http_not_found">Nenalezeno</string>
<string name="error_postprocessing_failed">Post-processing selhal</string>
<string name="clear_finished_download">Vyčistit dokončená stahování</string>

View File

@ -380,7 +380,6 @@
<string name="error_connect_host">Kan ikke forbinde til serveren</string>
<string name="error_http_no_content">Serveren sender ikke data</string>
<string name="error_http_unsupported_range">Serveren accepterer ikke multitrådede downloads; prøv igen med @string/msg_threads = 1</string>
<string name="error_http_requested_range_not_satisfiable">Det anmodede interval er ikke gyldigt</string>
<string name="error_http_not_found">Ikke fundet</string>
<string name="error_postprocessing_failed">Efterbehandling fejlede</string>
<string name="stop">Stop</string>

View File

@ -454,7 +454,6 @@
<string name="error_connect_host">Kann nicht mit dem Server verbinden</string>
<string name="error_http_no_content">Der Server sendet keine Daten</string>
<string name="error_http_unsupported_range">Der Server erlaubt kein mehrfädiges Herunterladen wiederhole mit @string/msg_threads = 1</string>
<string name="error_http_requested_range_not_satisfiable">Gewünschter Bereich ist nicht verfügbar</string>
<string name="error_http_not_found">Nicht gefunden</string>
<string name="error_postprocessing_failed">Nachbearbeitung fehlgeschlagen</string>
<string name="clear_finished_download">Um fertige Downloads bereinigen</string>

View File

@ -456,7 +456,6 @@
<string name="error_connect_host">Αδυναμία σύνδεσης με τον εξυπηρετητή</string>
<string name="error_http_no_content">Ο εξυπηρετητής δεν μπορεί να στείλει τα δεδομένα</string>
<string name="error_http_unsupported_range">Ο εξυπηρετητής δέν υποστηρίζει πολυνηματικές λήψεις, ξαναπροσπαθήστε με @string/msg_threads = 1</string>
<string name="error_http_requested_range_not_satisfiable">Το ζητούμενο εύρος δεν μπορεί να εξυπηρετηθεί</string>
<string name="error_http_not_found">Δεν βρέθηκε</string>
<string name="error_postprocessing_failed">Μετεπεξεργασία απέτυχε</string>
<string name="clear_finished_download">Εκκαθάριση ολοκληρωμένων λήψεων</string>

View File

@ -351,8 +351,8 @@
\n3. Inicie sesión cuando se le pida
\n4. Copie la URL del perfil a la que fue redireccionado.</string>
<string name="import_soundcloud_instructions_hint">suID, soundcloud.com/suID</string>
<string name="import_network_expensive_warning">Observe que esta operación puede causar un uso intensivo de la red.
\n
<string name="import_network_expensive_warning">Observe que esta operación puede causar un uso intensivo de la red.
\n
\n¿Quiere continuar\?</string>
<string name="download_thumbnail_title">Cargar miniaturas</string>
<string name="download_thumbnail_summary">Desactívela para evitar la carga de miniaturas y ahorrar datos y memoria. Se vaciará la antememoria de imágenes en la memoria volátil y en el disco.</string>
@ -444,8 +444,8 @@
<string name="error_ssl_exception">Fallo la conexión segura</string>
<string name="error_unknown_host">No se pudo encontrar el servidor</string>
<string name="error_connect_host">No se puede conectar con el servidor</string>
<string name="error_http_no_content">El servidor no está enviando datos</string>
<string name="error_http_unsupported_range">El servidor no acepta descargas multiproceso; intente de nuevo con @string/msg_threads = 1</string>
<string name="error_http_no_content">El servidor no devolvio datos</string>
<string name="error_http_unsupported_range">El servidor no acepta descargas multi-hilos, intente de nuevo con @string/msg_threads = 1</string>
<string name="error_http_requested_range_not_satisfiable">No se puede satisfacer el intervalo seleccionado</string>
<string name="error_http_not_found">No encontrado</string>
<string name="error_postprocessing_failed">Falló el posprocesamiento</string>
@ -453,6 +453,7 @@
<string name="error_insufficient_storage">No hay suficiente espacio disponible en el dispositivo</string>
<string name="error_progress_lost">Se perdió el progreso porque el archivo fue eliminado</string>
<string name="error_timeout">Tiempo de espera excedido</string>
<string name="error_download_resource_gone">El recurso solicitado ya no esta disponible</string>
<string name="downloads_storage_ask_title">Preguntar dónde descargar</string>
<string name="downloads_storage_ask_summary">Se preguntará dónde guardar cada descarga</string>
<string name="downloads_storage_ask_summary_kitkat">Se le preguntará dónde guardar cada descarga.

View File

@ -457,7 +457,6 @@
<string name="error_connect_host">Serveriga ei saadud ühendust</string>
<string name="error_http_no_content">Server ei saada andmeid</string>
<string name="error_http_unsupported_range">Server ei toeta mitmelõimelisi allalaadimisi. Proovi uuesti kasutades @string/msg_threads = 1</string>
<string name="error_http_requested_range_not_satisfiable">Taotletud vahemik ei ole rahuldatav</string>
<string name="error_http_not_found">Ei leitud</string>
<string name="error_postprocessing_failed">Järeltöötlemine nurjus</string>
<string name="clear_finished_download">Eemalda lõpetatud allalaadimised</string>

View File

@ -456,7 +456,6 @@
<string name="error_connect_host">Ezin da zerbitzariarekin konektatu</string>
<string name="error_http_no_content">Zerbitzariak ez du daturik bidaltzen</string>
<string name="error_http_unsupported_range">Zerbitzariak ez ditu hainbat hariko deskargak onartzen, saiatu @string/msg_threads = 1 erabilita</string>
<string name="error_http_requested_range_not_satisfiable">Eskatutako barrutia ezin da bete</string>
<string name="error_http_not_found">Ez aurkitua</string>
<string name="error_postprocessing_failed">Post-prozesuak huts egin du</string>
<string name="clear_finished_download">Garbitu amaitutako deskargak</string>

View File

@ -467,7 +467,6 @@
<string name="saved_tabs_invalid_json">Utilisation des onglets par défaut, erreur lors de la lecture des onglets enregistrés</string>
<string name="error_http_unsupported_range">Le serveur naccepte pas les téléchargements multi-fils, veuillez réessayer avec @string/msg_threads = 1</string>
<string name="msg_pending_downloads">Continuer vos %s transferts en attente depuis Téléchargement</string>
<string name="error_http_requested_range_not_satisfiable">Le domaine désiré n\'est pas disponible</string>
<string name="show_comments_title">Afficher les commentaires</string>
<string name="show_comments_summary">Désactiver pour ne pas afficher les commentaires</string>
<string name="autoplay_title">Lecture automatique</string>

View File

@ -461,7 +461,6 @@
<string name="error_connect_host">לא ניתן להתחבר לשרת</string>
<string name="error_http_no_content">השרת לא שולח נתונים</string>
<string name="error_http_unsupported_range">"השרת לא מקבל הורדות רב ערוציות, מוטב לנסות שוב עם @string/msg_threads = 1 "</string>
<string name="error_http_requested_range_not_satisfiable">הטווח המבוקש לא מתאים</string>
<string name="error_http_not_found">לא נמצא</string>
<string name="error_postprocessing_failed">העיבוד המאוחר נכשל</string>
<string name="clear_finished_download">פינוי ההורדות שהסתיימו</string>

View File

@ -454,7 +454,6 @@
<string name="error_connect_host">Nije moguće povezati se s serverom</string>
<string name="error_http_no_content">Server ne šalje podatke</string>
<string name="error_http_unsupported_range">Poslužitelj ne prihvaća preuzimanja s više niti, pokušaj ponovo s @string/msg_threads = 1</string>
<string name="error_http_requested_range_not_satisfiable">Traženi raspon nije zadovoljavajući</string>
<string name="error_http_not_found">Nije pronađeno</string>
<string name="error_postprocessing_failed">Naknadna obrada nije uspjela</string>
<string name="clear_finished_download">Obriši završena preuzimanja</string>

View File

@ -450,7 +450,6 @@
<string name="error_connect_host">Tidak dapat terhubung ke server</string>
<string name="error_http_no_content">Server tidak mengirim data</string>
<string name="error_http_unsupported_range">Server tidak menerima unduhan multi-utas, coba lagi dengan @string/msg_threads = 1</string>
<string name="error_http_requested_range_not_satisfiable">Rentang yang diminta tidak memuaskan</string>
<string name="error_http_not_found">Tidak ditemukan</string>
<string name="error_postprocessing_failed">Pengolahan-pasca gagal</string>
<string name="clear_finished_download">Hapus unduhan yang sudah selesai</string>

View File

@ -454,7 +454,6 @@
<string name="error_connect_host">Impossibile connettersi al server</string>
<string name="error_http_no_content">Il server non invia dati</string>
<string name="error_http_unsupported_range">Il server non accetta download multipli, riprovare con @string/msg_threads = 1</string>
<string name="error_http_requested_range_not_satisfiable">Intervallo richiesto non soddisfatto</string>
<string name="error_http_not_found">Non trovato</string>
<string name="error_postprocessing_failed">Post-processing fallito</string>
<string name="clear_finished_download">Pulisci i download completati</string>

View File

@ -440,7 +440,6 @@
<string name="error_connect_host">サーバに接続できません</string>
<string name="error_http_no_content">サーバがデータを送信していません</string>
<string name="error_http_unsupported_range">サーバが同時接続ダウンロードを受け付けません。再試行してください @string/msg_threads = 1</string>
<string name="error_http_requested_range_not_satisfiable">必要な範囲が満たされていません</string>
<string name="error_http_not_found">見つかりません</string>
<string name="error_postprocessing_failed">保存処理に失敗しました</string>
<string name="clear_finished_download">完了済みを一覧から削除します</string>

View File

@ -451,7 +451,6 @@
<string name="error_connect_host">서버에 접속할 수 없습니다</string>
<string name="error_http_no_content">서버가 데이터를 전송하지 않고 있습니다</string>
<string name="error_http_unsupported_range">서버가 다중 스레드 다운로드를 받아들이지 않습니다, @string/msg_threads = 1 를 사용해 다시 시도해보세요</string>
<string name="error_http_requested_range_not_satisfiable">요청된 HTTP 범위가 충분하지 않습니다</string>
<string name="error_http_not_found">HTTP 찾을 수 없습니다</string>
<string name="error_postprocessing_failed">후처리 작업이 실패하였습니다</string>
<string name="clear_finished_download">완료된 다운로드 비우기</string>

View File

@ -450,7 +450,6 @@
<string name="error_connect_host">Tidak dapat menyambung ke server</string>
<string name="error_http_no_content">Server tidak menghantar data</string>
<string name="error_http_unsupported_range">Server tidak menerima muat turun berbilang thread, cuba lagi dengan @string/msg_threads = 1</string>
<string name="error_http_requested_range_not_satisfiable">Julat yang diminta tidak memuaskan</string>
<string name="error_http_not_found">Tidak ditemui</string>
<string name="error_postprocessing_failed">Pemprosesan-pasca gagal</string>
<string name="clear_finished_download">Hapuskan senarai muat turun yang selesai</string>

View File

@ -496,7 +496,7 @@
<string name="pause_downloads">Sett nedlastinger på pause</string>
<string name="downloads_storage_ask_title">Spør om hvor ting skal lastes ned til</string>
<string name="downloads_storage_ask_summary">Du vil bli spurt om hvor hver nedlasting skal plasseres</string>
<string name="downloads_storage_ask_summary_kitkat">Du vil bli spurt om hvor hver nedlasting skal plasseres.
<string name="downloads_storage_ask_summary_kitkat">Du vil bli spurt om hvor hver nedlasting skal plasseres.
\nSkru på SAF hvis du vil laste ned til eksternt SD-kort</string>
<string name="downloads_storage_use_saf_title">Bruk SAF</string>
<string name="downloads_storage_use_saf_summary">Lagringstilgangsrammeverk (SAF) tillater nedlastinger til eksternt SD-kort.

View File

@ -454,7 +454,6 @@
<string name="error_connect_host">Kan geen verbinding maken met de server</string>
<string name="error_http_no_content">De server verzendt geen gegevens</string>
<string name="error_http_unsupported_range">De server aanvaardt geen meerdradige downloads, probeert het opnieuw met @string/msg_threads = 1</string>
<string name="error_http_requested_range_not_satisfiable">Gevraagd bereik niet beschikbaar</string>
<string name="error_http_not_found">Niet gevonden</string>
<string name="error_postprocessing_failed">Nabewerking mislukt</string>
<string name="clear_finished_download">Voltooide downloads wissen</string>

View File

@ -454,7 +454,6 @@
<string name="error_connect_host">Kan niet met de server verbinden</string>
<string name="error_http_no_content">De server verzendt geen gegevens</string>
<string name="error_http_unsupported_range">De server accepteert geen multi-threaded downloads, probeer het opnieuw met @string/msg_threads = 1</string>
<string name="error_http_requested_range_not_satisfiable">Gevraagde bereik niet beschikbaar</string>
<string name="error_http_not_found">Niet gevonden</string>
<string name="error_postprocessing_failed">Nabewerking mislukt</string>
<string name="clear_finished_download">Voltooide downloads wissen</string>

View File

@ -450,7 +450,6 @@
<string name="error_connect_host">ਸਰਵਰ ਨਾਲ ਜੁੜ ਨਹੀਂ ਸਕਦਾ</string>
<string name="error_http_no_content">ਸਰਵਰ ਨੇ ਡਾਟਾ ਨਹੀਂ ਭੇਜਿਆ</string>
<string name="error_http_unsupported_range">ਸਰਵਰ ਮਲਟੀ-Threaded ਡਾਊਨਲੋਡਸ ਨੂੰ ਸਵੀਕਾਰ ਨਹੀਂ ਕਰਦਾ, ਇਸ ਨਾਲ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ @string/msg_threads = 1</string>
<string name="error_http_requested_range_not_satisfiable">ਬੇਨਤੀ ਕੀਤੀ ਸੀਮਾ ਤਸੱਲੀਬਖਸ਼ ਨਹੀਂ ਹੈ</string>
<string name="error_http_not_found">ਨਹੀਂ ਲਭਿਆ</string>
<string name="error_postprocessing_failed">Post-processing ਫੇਲ੍ਹ</string>
<string name="clear_finished_download">ਮੁਕੰਮਲ ਹੋਈਆਂ ਡਾਊਨਲੋਡ ਸਾਫ਼ ਕਰੋ</string>

View File

@ -456,7 +456,6 @@
<string name="error_connect_host">Nie można połączyć się z serwerem</string>
<string name="error_http_no_content">Serwer nie wysyła danych</string>
<string name="error_http_unsupported_range">Serwer nie akceptuje pobierania wielowątkowego, spróbuj ponownie za pomocą @string/msg_threads = 1</string>
<string name="error_http_requested_range_not_satisfiable">Niewłaściwy zakres</string>
<string name="error_http_not_found">Nie znaleziono</string>
<string name="error_postprocessing_failed">Przetwarzanie końcowe nie powiodło się</string>
<string name="clear_finished_download">Wyczyść ukończone pobieranie</string>

View File

@ -463,7 +463,6 @@ abrir em modo popup</string>
<string name="error_connect_host">Não foi possível conectar ao servidor</string>
<string name="error_http_no_content">O servidor não envia dados</string>
<string name="error_http_unsupported_range">O servidor não aceita downloads em multi-thread, tente com @string/msg_threads = 1</string>
<string name="error_http_requested_range_not_satisfiable">Intervalo solicitado não aceito</string>
<string name="error_http_not_found">Não encontrado</string>
<string name="error_postprocessing_failed">Falha no pós processamento</string>
<string name="clear_finished_download">Limpar downloads finalizados</string>

View File

@ -452,7 +452,6 @@
<string name="error_connect_host">Não é possível ligar ao servidor</string>
<string name="error_http_no_content">O servidor não envia dados</string>
<string name="error_http_unsupported_range">O servidor não aceita transferências de vários processos, tente novamente com @string/msg_threads = 1</string>
<string name="error_http_requested_range_not_satisfiable">Intervalo solicitado não satisfatório</string>
<string name="error_http_not_found">Não encontrado</string>
<string name="error_postprocessing_failed">Pós-processamento falhado</string>
<string name="clear_finished_download">Limpar transferências concluídas</string>

View File

@ -454,7 +454,6 @@
<string name="error_permission_denied">Доступ запрещён системой</string>
<string name="error_unknown_host">Сервер не найден</string>
<string name="error_http_unsupported_range">Сервер не принимает многопоточные загрузки, повторная попытка с @string/msg_threads = 1</string>
<string name="error_http_requested_range_not_satisfiable">Запрашиваемый диапазон недопустим</string>
<string name="error_http_not_found">Не найдено</string>
<string name="clear_finished_download">Очистить завершённые</string>
<string name="stop">Остановить</string>

View File

@ -462,7 +462,6 @@
<string name="error_connect_host">Nepodarilo sa pripojiť k serveru</string>
<string name="error_http_no_content">Server neposiela údaje</string>
<string name="error_http_unsupported_range">Server neakceptuje preberanie viacerých vlákien, zopakujte s @string/msg_threads = 1</string>
<string name="error_http_requested_range_not_satisfiable">Požadovaný rozsah nie je uspokojivý</string>
<string name="error_http_not_found">Nenájdené</string>
<string name="error_postprocessing_failed">Post-spracovanie zlyhalo</string>
<string name="clear_finished_download">Vyčistiť dokončené sťahovania</string>

View File

@ -449,7 +449,6 @@
<string name="error_connect_host">Sunucuya bağlanılamıyor</string>
<string name="error_http_no_content">Sunucu veri göndermiyor</string>
<string name="error_http_unsupported_range">Sunucu, çok iş parçacıklı indirmeleri kabul etmez, @string/msg_threads = 1 ile yeniden deneyin</string>
<string name="error_http_requested_range_not_satisfiable">İstenen aralık karşılanamıyor</string>
<string name="error_http_not_found">Bulunamadı</string>
<string name="error_postprocessing_failed">İşlem sonrası başarısız</string>
<string name="clear_finished_download">Tamamlanan indirmeleri temizle</string>

View File

@ -471,7 +471,6 @@
<string name="saved_tabs_invalid_json">Помилка зчитування збережених вкладок. Використовую типові вкладки.</string>
<string name="main_page_content_summary">Вкладки, що відображаються на головній сторінці</string>
<string name="updates_setting_description">Показувати сповіщення з пропозицією оновити застосунок за наявності нової версії</string>
<string name="error_http_requested_range_not_satisfiable">Запитуваний діапазон неприпустимий</string>
<string name="msg_pending_downloads">Продовжити ваші %s відкладених переміщень із Завантажень</string>
<string name="pause_downloads_on_mobile_desc">Корисно під час переходу на мобільні дані, хоча деякі завантаження не можуть бути призупинені</string>
<string name="show_comments_title">Показувати коментарі</string>

View File

@ -449,7 +449,6 @@
<string name="error_connect_host">Không thế kết nối với máy chủ</string>
<string name="error_http_no_content">Máy chủ không gửi dữ liệu về</string>
<string name="error_http_unsupported_range">Máy chủ không chấp nhận tải đa luồng, thử lại với số luồng = 1</string>
<string name="error_http_requested_range_not_satisfiable">(HTTP) Không thể đáp ứng khoảng dữ liệu đã yêu cầu</string>
<string name="error_http_not_found">Không tìm thấy</string>
<string name="error_postprocessing_failed">Xử lý thất bại</string>
<string name="clear_finished_download">Dọn các tải về đã hoàn thành</string>

View File

@ -447,7 +447,6 @@
<string name="error_connect_host">無法連線到伺服器</string>
<string name="error_http_no_content">伺服器沒有傳送資料</string>
<string name="error_http_unsupported_range">伺服器不接受多執行緒下載,請以 @string/msg_threads = 1 重試</string>
<string name="error_http_requested_range_not_satisfiable">請求範圍無法滿足</string>
<string name="error_http_not_found">找不到</string>
<string name="error_postprocessing_failed">後處理失敗</string>
<string name="clear_finished_download">清除已結束的下載</string>

View File

@ -551,13 +551,13 @@
<string name="error_connect_host">Can not connect to the server</string>
<string name="error_http_no_content">The server does not send data</string>
<string name="error_http_unsupported_range">The server does not accept multi-threaded downloads, retry with @string/msg_threads = 1</string>
<string name="error_http_requested_range_not_satisfiable">Requested range not satisfiable</string>
<string name="error_http_not_found">Not found</string>
<string name="error_postprocessing_failed">Post-processing failed</string>
<string name="error_postprocessing_stopped">NewPipe was closed while working on the file</string>
<string name="error_insufficient_storage">No space left on device</string>
<string name="error_progress_lost">Progress lost, because the file was deleted</string>
<string name="error_timeout">Connection timeout</string>
<string name="error_download_resource_gone">The solicited resource is not available anymore</string>
<string name="clear_finished_download">Clear finished downloads</string>
<string name="confirm_prompt">Are you sure?</string>
<string name="msg_pending_downloads">Continue your %s pending transfers from Downloads</string>