Restart failed saves through a guarded server retry
This commit is contained in:
@@ -437,7 +437,7 @@ async function resumableOpfsSave(videoId, qs, hevc, onProgress, signal) {
|
||||
return { ok: false, error: 'the server copy kept changing — try again' };
|
||||
}
|
||||
|
||||
async function opfsDownload(videoId, { mux = false, onProgress = null, signal } = {}) {
|
||||
async function opfsDownload(videoId, { mux = false, retry = false, onProgress = null, signal } = {}) {
|
||||
if (!window.OPFS || !window.OPFS.isSupported()) {
|
||||
return { ok: false, error: 'OPFS not supported in this browser' };
|
||||
}
|
||||
@@ -452,6 +452,15 @@ async function opfsDownload(videoId, { mux = false, onProgress = null, signal }
|
||||
const qs = params.toString();
|
||||
const url = `/api/download/${encodeURIComponent(videoId)}${qs ? '?' + qs : ''}`;
|
||||
|
||||
if (retry) {
|
||||
try {
|
||||
const response = await fetch(`/api/download/${encodeURIComponent(videoId)}/retry`, { method: 'POST', cache: 'no-store', signal });
|
||||
const result = await response.json();
|
||||
if (!response.ok || !result.ok) return { ok: false, error: result.error || 'Could not restart this save.' };
|
||||
} catch (error) {
|
||||
return { ok: false, paused: true, error: error.name === 'AbortError' ? 'Save paused' : 'Connection lost' };
|
||||
}
|
||||
}
|
||||
const resumed = await resumableOpfsSave(videoId, qs, params.get('hevc') === '1', onProgress, signal);
|
||||
if (resumed) return resumed;
|
||||
|
||||
@@ -1791,7 +1800,7 @@ function recordDeviceFile(id, res) {
|
||||
}
|
||||
|
||||
// Download a video into the permanent offline cache. Safe to call repeatedly.
|
||||
async function preload(video, { quiet = false, mux = false } = {}) {
|
||||
async function preload(video, { quiet = false, mux = false, retry = false } = {}) {
|
||||
const id = video.id;
|
||||
// Custom (edited) videos have no YouTube source to (re)download — their
|
||||
// media is produced once by the editor. Never route them through the normal
|
||||
@@ -1816,7 +1825,7 @@ async function preload(video, { quiet = false, mux = false } = {}) {
|
||||
await SaveSlots.acquire(controller.signal);
|
||||
slot = true;
|
||||
SaveQueue.progress(id, null);
|
||||
const res = await API.cacheDownload(id, { mux, signal: controller.signal, onProgress: (p) => SaveQueue.progress(id, p) });
|
||||
const res = await API.cacheDownload(id, { mux, retry, signal: controller.signal, onProgress: (p) => SaveQueue.progress(id, p) });
|
||||
if (res && res.paused) {
|
||||
// The partial stays on the device; SaveQueue picks it up again.
|
||||
if (!quiet) toast(`Paused “${video.title}” — it will continue when the connection is back`);
|
||||
@@ -12560,7 +12569,7 @@ async function boot() {
|
||||
updateBottomChrome();
|
||||
if (window.Downloads) Downloads.configure({
|
||||
jobs: () => SaveQueue.pending().map(v => ({ ...v, status: downloading.has(v.id) ? (SaveQueue.get(v.id)?.phase === 'waiting' ? 'queued' : 'active') : v.status || 'paused', progress: SaveQueue.get(v.id) })),
|
||||
action: (id, action) => { if (action === 'pause') SaveQueue.pause(id); else if (action === 'cancel') SaveQueue.cancel(id); else { const v = SaveQueue.pending().find(v => v.id === id); if (v) preload(v, { quiet: true }); } },
|
||||
action: (id, action) => { if (action === 'pause') SaveQueue.pause(id); else if (action === 'cancel') SaveQueue.cancel(id); else { const v = SaveQueue.pending().find(v => v.id === id); if (v) preload(v, { quiet: true, retry: action === 'retry' }); } },
|
||||
playlists: () => data.playlists, slots: () => data.settings.parallelSaves || 4,
|
||||
files: async () => { const result = []; if (!WEB || !navigator.storage?.getDirectory) return result;
|
||||
const root = await navigator.storage.getDirectory();
|
||||
|
||||
Reference in New Issue
Block a user