mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-16 14:16:16 -08:00
feat(downloads): pause and resume support for the download manager (#1147)
Adds a paused state to the Electron download manager with a full partial-file lifecycle: - Pause keeps the .part and byte progress; cancel discards them; every lifecycle stage (queued, active, mid-transfer) is pausable. - Resume continues via HTTP Range with If-Range entity validation (strong ETag / Last-Modified persisted in the new resume_validator column, idempotent migration incl. legacy-table rebuild). Non-206 answers restart from zero over the same .part; the 206 Content-Range offset is verified; responses that end before the advertised size are retained for a Range retry instead of being committed as completed. - Crash recovery converts interrupted transfers to paused, keeps queued-with-partial rows resumable, and commits finalizations that crashed before the DB update. - Destination collisions are non-destructive (retained partials finalize to the next numbered name); locked .part files never lose their DB owner across cancel/remove/restart; resume claims rows atomically and the queue dedupes ids. - Stored request headers are re-filtered through the User-Agent/Origin/Referer allowlist on read, URL-derived extensions are sanitized, resume appends never follow symlinks, and transfer errors are logged by message only. - UI: pause/resume/cancel/retry/remove surface failures in a snackbar; paused items show an active Resume button in VOD/episode detail views; translations for all 18 locales. - Runtime split into download-runtime/transfer/finalize/broadcast modules; +30 unit tests and an Electron E2E covering pause -> retained .part -> Range/If-Range resume -> byte-exact assembly. Co-authored-by: genrichh93-ui <genrichh93@users.noreply.github.com> 🤖 Generated with [Claude Code](https://claude.com/claude-code)
This commit is contained in:
1 parent
0273ded8e2
commit
188f5c4b56
63 files changed
+4986
-683
No files matched your search
@@ -1004,6 +1004,9 @@
|
||||
"SOURCE_PLAYLIST_MISSING": "لم يعد بالإمكان فتح هذا التنزيل في المكتبة لأنه تمت إزالة قائمة التشغيل المصدر.",
|
||||
"FILE_NOT_FOUND": "هذا الملف الذي تم تنزيله لم يعد متاحًا على القرص.",
|
||||
"FILE_ACTION_ERROR": "تعذر إكمال الإجراء على الملف.",
|
||||
"ACTION_FAILED": "فشل الإجراء",
|
||||
"PAUSE": "إيقاف مؤقت",
|
||||
"RESUME": "استئناف",
|
||||
"CANCEL": "إلغاء",
|
||||
"RETRY": "إعادة المحاولة",
|
||||
"REMOVE": "إزالة",
|
||||
@@ -1017,7 +1020,8 @@
|
||||
"DOWNLOADING": "جارٍ التنزيل",
|
||||
"COMPLETED": "مكتمل",
|
||||
"FAILED": "فشل",
|
||||
"CANCELED": "ملغى"
|
||||
"CANCELED": "ملغى",
|
||||
"PAUSED": "متوقف مؤقتًا"
|
||||
}
|
||||
},
|
||||
"REMOTE_CONTROL": {
|
||||
|
||||
@@ -1004,6 +1004,9 @@
|
||||
"SOURCE_PLAYLIST_MISSING": "هاد التحميل ما يقدرش يتحل في المكتبة حيت قائمة التشغيل المصدر تحيدات.",
|
||||
"FILE_NOT_FOUND": "هاد الملف المحمل ما بقاش متوفر على القرص.",
|
||||
"FILE_ACTION_ERROR": "العملية على الملف ما تكملاتش.",
|
||||
"ACTION_FAILED": "العملية ما نجحاتش",
|
||||
"PAUSE": "وقّف مؤقتاً",
|
||||
"RESUME": "كمّل",
|
||||
"CANCEL": "إلغاء",
|
||||
"RETRY": "حاول مرة أخرى",
|
||||
"REMOVE": "حيد",
|
||||
@@ -1017,7 +1020,8 @@
|
||||
"DOWNLOADING": "جاري التحميل",
|
||||
"COMPLETED": "كمل",
|
||||
"FAILED": "فشل",
|
||||
"CANCELED": "تلغى"
|
||||
"CANCELED": "تلغى",
|
||||
"PAUSED": "موقوف مؤقتاً"
|
||||
}
|
||||
},
|
||||
"REMOTE_CONTROL": {
|
||||
|
||||
@@ -1004,6 +1004,9 @@
|
||||
"SOURCE_PLAYLIST_MISSING": "Гэта спампаванне больш нельга адкрыць у бібліятэцы, бо яго зыходны плэйліст быў выдалены.",
|
||||
"FILE_NOT_FOUND": "Гэты спампаваны файл больш недаступны на дыску.",
|
||||
"FILE_ACTION_ERROR": "Не ўдалося выканаць дзеянне з файлам.",
|
||||
"ACTION_FAILED": "Дзеянне не выканана",
|
||||
"PAUSE": "Паўза",
|
||||
"RESUME": "Узнавіць",
|
||||
"CANCEL": "Скасаваць",
|
||||
"RETRY": "Паўтарыць",
|
||||
"REMOVE": "Выдаліць",
|
||||
@@ -1017,7 +1020,8 @@
|
||||
"DOWNLOADING": "Спампоўваецца",
|
||||
"COMPLETED": "Завершана",
|
||||
"FAILED": "Няўдала",
|
||||
"CANCELED": "Скасавана"
|
||||
"CANCELED": "Скасавана",
|
||||
"PAUSED": "На паўзе"
|
||||
}
|
||||
},
|
||||
"REMOTE_CONTROL": {
|
||||
|
||||
@@ -1004,6 +1004,9 @@
|
||||
"SOURCE_PLAYLIST_MISSING": "Dieser Download kann nicht mehr in der Bibliothek geöffnet werden, weil die zugehörige Playlist entfernt wurde.",
|
||||
"FILE_NOT_FOUND": "Diese heruntergeladene Datei ist auf der Festplatte nicht mehr verfügbar.",
|
||||
"FILE_ACTION_ERROR": "Die Dateiaktion konnte nicht ausgeführt werden.",
|
||||
"ACTION_FAILED": "Aktion fehlgeschlagen",
|
||||
"PAUSE": "Pausieren",
|
||||
"RESUME": "Fortsetzen",
|
||||
"CANCEL": "Abbrechen",
|
||||
"RETRY": "Wiederholen",
|
||||
"REMOVE": "Entfernen",
|
||||
@@ -1017,7 +1020,8 @@
|
||||
"DOWNLOADING": "Wird heruntergeladen",
|
||||
"COMPLETED": "Abgeschlossen",
|
||||
"FAILED": "Fehlgeschlagen",
|
||||
"CANCELED": "Abgebrochen"
|
||||
"CANCELED": "Abgebrochen",
|
||||
"PAUSED": "Pausiert"
|
||||
}
|
||||
},
|
||||
"REMOTE_CONTROL": {
|
||||
|
||||
@@ -1004,6 +1004,9 @@
|
||||
"SOURCE_PLAYLIST_MISSING": "Αυτή η λήψη δεν μπορεί πλέον να ανοίξει στη βιβλιοθήκη επειδή η πηγαία λίστα αναπαραγωγής αφαιρέθηκε.",
|
||||
"FILE_NOT_FOUND": "Αυτό το ληφθέν αρχείο δεν είναι πλέον διαθέσιμο στον δίσκο.",
|
||||
"FILE_ACTION_ERROR": "Δεν ήταν δυνατή η ολοκλήρωση της ενέργειας αρχείου.",
|
||||
"ACTION_FAILED": "Η ενέργεια απέτυχε",
|
||||
"PAUSE": "Παύση",
|
||||
"RESUME": "Συνέχιση",
|
||||
"CANCEL": "Ακύρωση",
|
||||
"RETRY": "Επανάληψη",
|
||||
"REMOVE": "Αφαίρεση",
|
||||
@@ -1017,7 +1020,8 @@
|
||||
"DOWNLOADING": "Λήψη",
|
||||
"COMPLETED": "Ολοκληρώθηκε",
|
||||
"FAILED": "Απέτυχε",
|
||||
"CANCELED": "Ακυρώθηκε"
|
||||
"CANCELED": "Ακυρώθηκε",
|
||||
"PAUSED": "Σε παύση"
|
||||
}
|
||||
},
|
||||
"REMOTE_CONTROL": {
|
||||
|
||||
@@ -1004,6 +1004,9 @@
|
||||
"SOURCE_PLAYLIST_MISSING": "This download can no longer open in the library because its source playlist was removed.",
|
||||
"FILE_NOT_FOUND": "This downloaded file is no longer available on disk.",
|
||||
"FILE_ACTION_ERROR": "The file action could not be completed.",
|
||||
"ACTION_FAILED": "Action failed",
|
||||
"PAUSE": "Pause",
|
||||
"RESUME": "Resume",
|
||||
"CANCEL": "Cancel",
|
||||
"RETRY": "Retry",
|
||||
"REMOVE": "Remove",
|
||||
@@ -1017,7 +1020,8 @@
|
||||
"DOWNLOADING": "Downloading",
|
||||
"COMPLETED": "Completed",
|
||||
"FAILED": "Failed",
|
||||
"CANCELED": "Canceled"
|
||||
"CANCELED": "Canceled",
|
||||
"PAUSED": "Paused"
|
||||
}
|
||||
},
|
||||
"REMOTE_CONTROL": {
|
||||
|
||||
@@ -1004,6 +1004,9 @@
|
||||
"SOURCE_PLAYLIST_MISSING": "Esta descarga ya no se puede abrir en la biblioteca porque su lista de reproducción de origen fue eliminada.",
|
||||
"FILE_NOT_FOUND": "Este archivo descargado ya no está disponible en el disco.",
|
||||
"FILE_ACTION_ERROR": "No se pudo completar la acción del archivo.",
|
||||
"ACTION_FAILED": "La acción ha fallado",
|
||||
"PAUSE": "Pausar",
|
||||
"RESUME": "Reanudar",
|
||||
"CANCEL": "Cancelar",
|
||||
"RETRY": "Reintentar",
|
||||
"REMOVE": "Eliminar",
|
||||
@@ -1017,7 +1020,8 @@
|
||||
"DOWNLOADING": "Descargando",
|
||||
"COMPLETED": "Completado",
|
||||
"FAILED": "Fallido",
|
||||
"CANCELED": "Cancelado"
|
||||
"CANCELED": "Cancelado",
|
||||
"PAUSED": "En pausa"
|
||||
}
|
||||
},
|
||||
"REMOTE_CONTROL": {
|
||||
|
||||
@@ -1004,6 +1004,9 @@
|
||||
"SOURCE_PLAYLIST_MISSING": "Ce téléchargement ne peut plus être ouvert dans la bibliothèque car sa liste de lecture source a été supprimée.",
|
||||
"FILE_NOT_FOUND": "Ce fichier téléchargé n'est plus disponible sur le disque.",
|
||||
"FILE_ACTION_ERROR": "L'action sur le fichier n'a pas pu être effectuée.",
|
||||
"ACTION_FAILED": "Échec de l'action",
|
||||
"PAUSE": "Mettre en pause",
|
||||
"RESUME": "Reprendre",
|
||||
"CANCEL": "Annuler",
|
||||
"RETRY": "Réessayer",
|
||||
"REMOVE": "Supprimer",
|
||||
@@ -1017,7 +1020,8 @@
|
||||
"DOWNLOADING": "En cours",
|
||||
"COMPLETED": "Terminé",
|
||||
"FAILED": "Échec",
|
||||
"CANCELED": "Annulé"
|
||||
"CANCELED": "Annulé",
|
||||
"PAUSED": "En pause"
|
||||
}
|
||||
},
|
||||
"REMOTE_CONTROL": {
|
||||
|
||||
@@ -1004,6 +1004,9 @@
|
||||
"SOURCE_PLAYLIST_MISSING": "Questo download non può più essere aperto nella libreria perché la playlist di origine è stata rimossa.",
|
||||
"FILE_NOT_FOUND": "Questo file scaricato non è più disponibile su disco.",
|
||||
"FILE_ACTION_ERROR": "Impossibile completare l'azione sul file.",
|
||||
"ACTION_FAILED": "Azione non riuscita",
|
||||
"PAUSE": "Pausa",
|
||||
"RESUME": "Riprendi",
|
||||
"CANCEL": "Annulla",
|
||||
"RETRY": "Riprova",
|
||||
"REMOVE": "Rimuovi",
|
||||
@@ -1017,7 +1020,8 @@
|
||||
"DOWNLOADING": "In download",
|
||||
"COMPLETED": "Completato",
|
||||
"FAILED": "Non riuscito",
|
||||
"CANCELED": "Annullato"
|
||||
"CANCELED": "Annullato",
|
||||
"PAUSED": "In pausa"
|
||||
}
|
||||
},
|
||||
"REMOTE_CONTROL": {
|
||||
|
||||
@@ -1004,6 +1004,9 @@
|
||||
"SOURCE_PLAYLIST_MISSING": "ソースのプレイリストが削除されたため、このダウンロードはライブラリで開けなくなりました。",
|
||||
"FILE_NOT_FOUND": "このダウンロードファイルはディスク上で見つかりませんでした。",
|
||||
"FILE_ACTION_ERROR": "ファイル操作を完了できませんでした。",
|
||||
"ACTION_FAILED": "操作に失敗しました",
|
||||
"PAUSE": "一時停止",
|
||||
"RESUME": "再開",
|
||||
"CANCEL": "キャンセル",
|
||||
"RETRY": "再試行",
|
||||
"REMOVE": "削除",
|
||||
@@ -1017,7 +1020,8 @@
|
||||
"DOWNLOADING": "ダウンロード中",
|
||||
"COMPLETED": "完了",
|
||||
"FAILED": "失敗",
|
||||
"CANCELED": "キャンセル済み"
|
||||
"CANCELED": "キャンセル済み",
|
||||
"PAUSED": "一時停止中"
|
||||
}
|
||||
},
|
||||
"REMOTE_CONTROL": {
|
||||
|
||||
@@ -1004,6 +1004,9 @@
|
||||
"SOURCE_PLAYLIST_MISSING": "원본 재생목록이 제거되어 이 다운로드 항목을 라이브러리에서 더 이상 열 수 없습니다.",
|
||||
"FILE_NOT_FOUND": "이 다운로드한 파일을 디스크에서 더 이상 사용할 수 없습니다.",
|
||||
"FILE_ACTION_ERROR": "파일 작업을 완료하지 못했습니다.",
|
||||
"ACTION_FAILED": "작업 실패",
|
||||
"PAUSE": "일시정지",
|
||||
"RESUME": "재개",
|
||||
"CANCEL": "취소",
|
||||
"RETRY": "다시 시도",
|
||||
"REMOVE": "제거",
|
||||
@@ -1017,7 +1020,8 @@
|
||||
"DOWNLOADING": "다운로드 중",
|
||||
"COMPLETED": "완료됨",
|
||||
"FAILED": "실패",
|
||||
"CANCELED": "취소됨"
|
||||
"CANCELED": "취소됨",
|
||||
"PAUSED": "일시정지됨"
|
||||
}
|
||||
},
|
||||
"REMOTE_CONTROL": {
|
||||
|
||||
@@ -1004,6 +1004,9 @@
|
||||
"SOURCE_PLAYLIST_MISSING": "Deze download kan niet meer worden geopend in de bibliotheek omdat de bronafspeellijst is verwijderd.",
|
||||
"FILE_NOT_FOUND": "Dit gedownloade bestand is niet meer beschikbaar op de schijf.",
|
||||
"FILE_ACTION_ERROR": "De bestandsactie kon niet worden voltooid.",
|
||||
"ACTION_FAILED": "Actie mislukt",
|
||||
"PAUSE": "Pauzeren",
|
||||
"RESUME": "Hervatten",
|
||||
"CANCEL": "Annuleren",
|
||||
"RETRY": "Opnieuw proberen",
|
||||
"REMOVE": "Verwijderen",
|
||||
@@ -1017,7 +1020,8 @@
|
||||
"DOWNLOADING": "Downloaden",
|
||||
"COMPLETED": "Voltooid",
|
||||
"FAILED": "Mislukt",
|
||||
"CANCELED": "Geannuleerd"
|
||||
"CANCELED": "Geannuleerd",
|
||||
"PAUSED": "Gepauzeerd"
|
||||
}
|
||||
},
|
||||
"REMOTE_CONTROL": {
|
||||
|
||||
@@ -1004,6 +1004,9 @@
|
||||
"SOURCE_PLAYLIST_MISSING": "Tego pobrania nie można już otworzyć w bibliotece, ponieważ jego źródłowa lista odtwarzania została usunięta.",
|
||||
"FILE_NOT_FOUND": "Ten pobrany plik nie jest już dostępny na dysku.",
|
||||
"FILE_ACTION_ERROR": "Nie udało się wykonać akcji na pliku.",
|
||||
"ACTION_FAILED": "Akcja nie powiodła się",
|
||||
"PAUSE": "Wstrzymaj",
|
||||
"RESUME": "Wznów",
|
||||
"CANCEL": "Anuluj",
|
||||
"RETRY": "Spróbuj ponownie",
|
||||
"REMOVE": "Usuń",
|
||||
@@ -1017,7 +1020,8 @@
|
||||
"DOWNLOADING": "Pobieranie",
|
||||
"COMPLETED": "Ukończone",
|
||||
"FAILED": "Niepowodzenie",
|
||||
"CANCELED": "Anulowane"
|
||||
"CANCELED": "Anulowane",
|
||||
"PAUSED": "Wstrzymane"
|
||||
}
|
||||
},
|
||||
"REMOTE_CONTROL": {
|
||||
|
||||
@@ -1004,6 +1004,9 @@
|
||||
"SOURCE_PLAYLIST_MISSING": "Este download não pode mais ser aberto na biblioteca porque sua playlist de origem foi removida.",
|
||||
"FILE_NOT_FOUND": "Este arquivo baixado não está mais disponível no disco.",
|
||||
"FILE_ACTION_ERROR": "A ação do arquivo não pôde ser concluída.",
|
||||
"ACTION_FAILED": "Falha na ação",
|
||||
"PAUSE": "Pausar",
|
||||
"RESUME": "Retomar",
|
||||
"CANCEL": "Cancelar",
|
||||
"RETRY": "Tentar novamente",
|
||||
"REMOVE": "Remover",
|
||||
@@ -1017,7 +1020,8 @@
|
||||
"DOWNLOADING": "Baixando",
|
||||
"COMPLETED": "Concluído",
|
||||
"FAILED": "Falhou",
|
||||
"CANCELED": "Cancelado"
|
||||
"CANCELED": "Cancelado",
|
||||
"PAUSED": "Pausado"
|
||||
}
|
||||
},
|
||||
"REMOTE_CONTROL": {
|
||||
|
||||
@@ -1004,6 +1004,9 @@
|
||||
"SOURCE_PLAYLIST_MISSING": "Эту загрузку больше нельзя открыть в библиотеке, потому что исходный плейлист был удален.",
|
||||
"FILE_NOT_FOUND": "Этот загруженный файл больше недоступен на диске.",
|
||||
"FILE_ACTION_ERROR": "Не удалось выполнить действие с файлом.",
|
||||
"ACTION_FAILED": "Действие не выполнено",
|
||||
"PAUSE": "Пауза",
|
||||
"RESUME": "Возобновить",
|
||||
"CANCEL": "Отмена",
|
||||
"RETRY": "Повторить",
|
||||
"REMOVE": "Удалить",
|
||||
@@ -1017,7 +1020,8 @@
|
||||
"DOWNLOADING": "Скачивается",
|
||||
"COMPLETED": "Завершено",
|
||||
"FAILED": "Ошибка",
|
||||
"CANCELED": "Отменено"
|
||||
"CANCELED": "Отменено",
|
||||
"PAUSED": "На паузе"
|
||||
}
|
||||
},
|
||||
"REMOTE_CONTROL": {
|
||||
|
||||
@@ -1004,6 +1004,9 @@
|
||||
"SOURCE_PLAYLIST_MISSING": "Bu indirme, kaynak oynatma listesi kaldırıldığı için kütüphanede artık açılamıyor.",
|
||||
"FILE_NOT_FOUND": "Bu indirilen dosya artık diskte mevcut değil.",
|
||||
"FILE_ACTION_ERROR": "Dosya işlemi tamamlanamadı.",
|
||||
"ACTION_FAILED": "İşlem başarısız oldu",
|
||||
"PAUSE": "Duraklat",
|
||||
"RESUME": "Devam et",
|
||||
"CANCEL": "İptal",
|
||||
"RETRY": "Tekrar Dene",
|
||||
"REMOVE": "Kaldır",
|
||||
@@ -1017,7 +1020,8 @@
|
||||
"DOWNLOADING": "İndiriliyor",
|
||||
"COMPLETED": "Tamamlandı",
|
||||
"FAILED": "Başarısız",
|
||||
"CANCELED": "İptal Edildi"
|
||||
"CANCELED": "İptal Edildi",
|
||||
"PAUSED": "Duraklatıldı"
|
||||
}
|
||||
},
|
||||
"REMOTE_CONTROL": {
|
||||
|
||||
@@ -1004,6 +1004,9 @@
|
||||
"SOURCE_PLAYLIST_MISSING": "由于源播放列表已被移除,此下载项无法在库中打开。",
|
||||
"FILE_NOT_FOUND": "此下载文件已不在磁盘上。",
|
||||
"FILE_ACTION_ERROR": "无法完成此文件操作。",
|
||||
"ACTION_FAILED": "操作失败",
|
||||
"PAUSE": "暂停",
|
||||
"RESUME": "继续",
|
||||
"CANCEL": "取消",
|
||||
"RETRY": "重试",
|
||||
"REMOVE": "移除",
|
||||
@@ -1017,7 +1020,8 @@
|
||||
"DOWNLOADING": "下载中",
|
||||
"COMPLETED": "已完成",
|
||||
"FAILED": "失败",
|
||||
"CANCELED": "已取消"
|
||||
"CANCELED": "已取消",
|
||||
"PAUSED": "已暂停"
|
||||
}
|
||||
},
|
||||
"REMOTE_CONTROL": {
|
||||
|
||||
@@ -1004,6 +1004,9 @@
|
||||
"SOURCE_PLAYLIST_MISSING": "此下載項目無法在媒體庫中開啟,因為其來源播放清單已被移除。",
|
||||
"FILE_NOT_FOUND": "此下載檔案在磁碟上已不存在。",
|
||||
"FILE_ACTION_ERROR": "無法完成檔案操作。",
|
||||
"ACTION_FAILED": "操作失敗",
|
||||
"PAUSE": "暫停",
|
||||
"RESUME": "繼續",
|
||||
"CANCEL": "取消",
|
||||
"RETRY": "重試",
|
||||
"REMOVE": "移除",
|
||||
@@ -1017,7 +1020,8 @@
|
||||
"DOWNLOADING": "下載中",
|
||||
"COMPLETED": "已完成",
|
||||
"FAILED": "失敗",
|
||||
"CANCELED": "已取消"
|
||||
"CANCELED": "已取消",
|
||||
"PAUSED": "已暫停"
|
||||
}
|
||||
},
|
||||
"REMOTE_CONTROL": {
|
||||
|
||||
Reference in new issue
Block a user