* Call GM_download with the callback-based API and turn it into a promise. * Resolves on onload (or save_cancelled — TM's behavior), rejects on onerror/ontimeout. * Captures all progress events. * * Returns: { promise, handle, progress[] } * - promise: { kind: "load"|"save_cancelled
(details)
| 441 | * - progress: array of onprogress callback args, in order received |
| 442 | */ |
| 443 | function gmDownloadCb(details) { |
| 444 | const progress = []; |
| 445 | let resolve, reject; |
| 446 | const promise = new Promise((res, rej) => { resolve = res; reject = rej; }); |
| 447 | let saveCancelled = false; |
| 448 | const opts = { |
| 449 | ...details, |
| 450 | onprogress(p) { |
| 451 | progress.push(p); |
| 452 | try { details.onprogress && details.onprogress(p); } catch {} |
| 453 | updateProgress(p.loaded ?? p.done ?? 0, p.total ?? p.totalSize ?? -1); |
| 454 | }, |
| 455 | onload(data) { |
| 456 | try { details.onload && details.onload(data); } catch {} |
| 457 | resolve({ kind: saveCancelled ? "save_cancelled" : "load", data }); |
| 458 | }, |
| 459 | onerror(err) { |
| 460 | try { details.onerror && details.onerror(err); } catch {} |
| 461 | reject({ kind: "error", err }); |
| 462 | }, |
| 463 | ontimeout(err) { |
| 464 | try { details.ontimeout && details.ontimeout(err); } catch {} |
| 465 | reject({ kind: "timeout", err }); |
| 466 | }, |
| 467 | }; |
| 468 | // GM_download returns { abort } in both TM and SC. |
| 469 | const handle = GM_download(opts); |
| 470 | return { promise, handle, progress, _markSaveCancelled() { saveCancelled = true; } }; |
| 471 | } |
| 472 | |
| 473 | /** |
| 474 | * Call GM.download (promise form). Returns the Promise itself plus the abort handle. |