mirror of
https://github.com/GopeedLab/gopeed.git
synced 2026-11-05 16:15:43 +00:00
feat: add automatic cleanup options for completed torrents and missing files (#1243)
This commit is contained in:
1 parent
bad7f1d06c
commit
8d33e1a5b3
23 files changed
+152
-6
No files matched your search
@@ -185,6 +185,10 @@ type DownloaderStoreConfig struct {
|
||||
Proxy *DownloaderProxyConfig `json:"proxy"`
|
||||
Webhook *WebhookConfig `json:"webhook"` // Webhook is the webhook configuration
|
||||
Archive *ArchiveConfig `json:"archive"` // Archive is the archive extraction configuration
|
||||
|
||||
// New fields added for auto-management
|
||||
AutoDeleteTorrents bool `json:"autoDeleteTorrents"` // AutoDeleteTorrents enables automatic deletion of .torrent files after download
|
||||
AutoCleanMissingFiles bool `json:"autoCleanMissingFiles"` // AutoCleanMissingFiles enables automatic cleanup of tasks with missing files
|
||||
}
|
||||
|
||||
func (cfg *DownloaderStoreConfig) Init() *DownloaderStoreConfig {
|
||||
|
||||
@@ -205,6 +205,9 @@ func (d *Downloader) Setup() error {
|
||||
}
|
||||
d.extensions = extensions
|
||||
|
||||
// Auto-cleanup non-existing tasks on startup
|
||||
d.cleanupNonExistingTasks()
|
||||
|
||||
// handle upload
|
||||
go func() {
|
||||
for _, task := range d.tasks {
|
||||
@@ -271,6 +274,51 @@ func (d *Downloader) Setup() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// cleanupNonExistingTasks checks for tasks whose files are missing on disk
|
||||
// and removes them if the AutoCleanMissingFiles config is enabled.
|
||||
func (d *Downloader) cleanupNonExistingTasks() {
|
||||
cfg, err := d.GetConfig()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// If the feature is disabled, do nothing
|
||||
if !cfg.AutoCleanMissingFiles {
|
||||
return
|
||||
}
|
||||
|
||||
var tasksToDelete []string
|
||||
|
||||
for _, task := range d.tasks {
|
||||
if task.Meta == nil || task.Meta.Res == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
var targetPath string
|
||||
// Determine if it is a single file or a directory (multi-file torrent)
|
||||
if task.Meta.Res.Name != "" {
|
||||
targetPath = task.Meta.FolderPath()
|
||||
} else {
|
||||
targetPath = task.Meta.SingleFilepath()
|
||||
}
|
||||
|
||||
// Skip if path is empty
|
||||
if targetPath == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
// Check if file/folder exists
|
||||
if _, err := os.Stat(targetPath); os.IsNotExist(err) {
|
||||
d.Logger.Info().Msgf("Auto-cleanup: task %s file not found at %s, removing from list", task.ID, targetPath)
|
||||
tasksToDelete = append(tasksToDelete, task.ID)
|
||||
}
|
||||
}
|
||||
|
||||
if len(tasksToDelete) > 0 {
|
||||
d.Delete(&TaskFilter{IDs: tasksToDelete}, false)
|
||||
}
|
||||
}
|
||||
|
||||
func (d *Downloader) parseFm(url string) (fetcher.FetcherManager, error) {
|
||||
for _, fm := range d.cfg.FetchManagers {
|
||||
for _, filter := range fm.Filters() {
|
||||
@@ -910,6 +958,10 @@ func (d *Downloader) watch(task *Task) {
|
||||
if e, ok := task.Meta.Opts.Extra.(*http.OptsExtra); ok {
|
||||
downloadFilePath := task.Meta.SingleFilepath()
|
||||
if e.AutoTorrent && strings.HasSuffix(downloadFilePath, ".torrent") {
|
||||
|
||||
cfg, err := d.GetConfig()
|
||||
shouldDelete := err == nil && cfg.AutoDeleteTorrents
|
||||
|
||||
go func() {
|
||||
_, err2 := d.CreateDirect(
|
||||
&base.Request{
|
||||
@@ -921,8 +973,12 @@ func (d *Downloader) watch(task *Task) {
|
||||
})
|
||||
if err2 != nil {
|
||||
d.Logger.Error().Err(err2).Msgf("auto create torrent task failed, task id: %s", task.ID)
|
||||
}
|
||||
} else {
|
||||
|
||||
if shouldDelete {
|
||||
d.Delete(&TaskFilter{IDs: []string{task.ID}}, true)
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,10 @@ class DownloaderConfig {
|
||||
WebhookConfig webhook = WebhookConfig();
|
||||
ArchiveConfig archive = ArchiveConfig();
|
||||
|
||||
// New fields for auto-management
|
||||
bool autoDeleteTorrents = false;
|
||||
bool autoCleanMissingFiles = false;
|
||||
|
||||
DownloaderConfig({
|
||||
this.downloadDir = '',
|
||||
this.maxRunning = 0,
|
||||
@@ -244,4 +248,4 @@ class ArchiveConfig {
|
||||
json == null ? ArchiveConfig() : _$ArchiveConfigFromJson(json);
|
||||
|
||||
Map<String, dynamic> toJson() => _$ArchiveConfigToJson(this);
|
||||
}
|
||||
}
|
||||
@@ -18,7 +18,9 @@ DownloaderConfig _$DownloaderConfigFromJson(Map<String, dynamic> json) =>
|
||||
..webhook =
|
||||
WebhookConfig.fromJson(json['webhook'] as Map<String, dynamic>?)
|
||||
..archive =
|
||||
ArchiveConfig.fromJson(json['archive'] as Map<String, dynamic>?);
|
||||
ArchiveConfig.fromJson(json['archive'] as Map<String, dynamic>?)
|
||||
..autoDeleteTorrents = json['autoDeleteTorrents'] as bool
|
||||
..autoCleanMissingFiles = json['autoCleanMissingFiles'] as bool;
|
||||
|
||||
Map<String, dynamic> _$DownloaderConfigToJson(DownloaderConfig instance) =>
|
||||
<String, dynamic>{
|
||||
@@ -29,6 +31,8 @@ Map<String, dynamic> _$DownloaderConfigToJson(DownloaderConfig instance) =>
|
||||
'proxy': instance.proxy.toJson(),
|
||||
'webhook': instance.webhook.toJson(),
|
||||
'archive': instance.archive.toJson(),
|
||||
'autoDeleteTorrents': instance.autoDeleteTorrents,
|
||||
'autoCleanMissingFiles': instance.autoCleanMissingFiles,
|
||||
};
|
||||
|
||||
ProtocolConfig _$ProtocolConfigFromJson(Map<String, dynamic> json) =>
|
||||
|
||||
@@ -169,6 +169,46 @@ class SettingView extends GetView<SettingController> {
|
||||
);
|
||||
});
|
||||
|
||||
// New: Auto Delete Torrents
|
||||
final buildAutoDeleteTorrents = _buildConfigItem('autoDeleteTorrents', () {
|
||||
return appController.downloaderConfig.value.autoDeleteTorrents
|
||||
? 'on'.tr
|
||||
: 'off'.tr;
|
||||
}, (Key key) {
|
||||
return Container(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Switch(
|
||||
value: appController.downloaderConfig.value.autoDeleteTorrents,
|
||||
onChanged: (bool value) async {
|
||||
appController.downloaderConfig.update((val) {
|
||||
val!.autoDeleteTorrents = value;
|
||||
});
|
||||
await debounceSave();
|
||||
},
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
// New: Auto Clean Missing Files
|
||||
final buildAutoCleanMissingFiles = _buildConfigItem('autoCleanMissingFiles', () {
|
||||
return appController.downloaderConfig.value.autoCleanMissingFiles
|
||||
? 'on'.tr
|
||||
: 'off'.tr;
|
||||
}, (Key key) {
|
||||
return Container(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Switch(
|
||||
value: appController.downloaderConfig.value.autoCleanMissingFiles,
|
||||
onChanged: (bool value) async {
|
||||
appController.downloaderConfig.update((val) {
|
||||
val!.autoCleanMissingFiles = value;
|
||||
});
|
||||
await debounceSave();
|
||||
},
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
// Archive auto extract configuration
|
||||
final buildAutoExtract = _buildConfigItem('autoExtract', () {
|
||||
return appController.downloaderConfig.value.archive.autoExtract
|
||||
@@ -1414,6 +1454,8 @@ class SettingView extends GetView<SettingController> {
|
||||
buildMaxRunning(),
|
||||
buildDefaultDirectDownload(),
|
||||
buildAutoStartTasks(),
|
||||
buildAutoDeleteTorrents(),
|
||||
buildAutoCleanMissingFiles(),
|
||||
buildBrowserExtension(),
|
||||
buildAutoStartup(),
|
||||
buildMenubarMode(),
|
||||
@@ -1948,4 +1990,4 @@ extension ProxyMode on ProxyConfig {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -42,6 +42,8 @@ const deDE = {
|
||||
'maxRunning': 'Maximale Anzahl ausgeführter Aufgaben',
|
||||
'defaultDirectDownload': 'Direkten Download standardmäßig aktivieren',
|
||||
'autoStartTasks': 'Unvollständige Aufgaben beim Start automatisch starten',
|
||||
'autoDeleteTorrents': 'Automatisches Löschen von .torrent-Dateien',
|
||||
'autoCleanMissingFiles': 'Automatisches Bereinigen fehlender Dateien',
|
||||
'items': '@count Artikel',
|
||||
'subscribeTracker': 'Abonnement-Tracker',
|
||||
'subscribeFail':
|
||||
|
||||
@@ -39,6 +39,8 @@ const enUS = {
|
||||
'maxRunning': 'Max Running Tasks',
|
||||
'defaultDirectDownload': 'Check direct download by default',
|
||||
'autoStartTasks': 'Auto-start incomplete tasks on startup',
|
||||
'autoDeleteTorrents': 'Auto delete .torrent files',
|
||||
'autoCleanMissingFiles': 'Auto clean missing files',
|
||||
'items': '@count items',
|
||||
'subscribeTracker': 'Subscribe Tracker',
|
||||
'subscribeFail':
|
||||
@@ -172,4 +174,4 @@ const enUS = {
|
||||
'githubMirrorUrl': 'Mirror URL',
|
||||
'githubMirrorUrlHint': 'Enter mirror URL',
|
||||
},
|
||||
};
|
||||
};
|
||||
@@ -39,6 +39,8 @@ const esES = {
|
||||
'useServerCtime': 'Usar tiempo del servidor para la creación de archivos',
|
||||
'maxRunning': 'Máximo de Tareas en Ejecución',
|
||||
'autoStartTasks': 'Iniciar automáticamente tareas incompletas al arrancar',
|
||||
'autoDeleteTorrents': 'Eliminar automáticamente archivos .torrent',
|
||||
'autoCleanMissingFiles': 'Limpiar automáticamente archivos faltantes',
|
||||
'items': '@count elementos',
|
||||
'subscribeTracker': 'Suscribirse al Tracker',
|
||||
'subscribeFail':
|
||||
|
||||
@@ -26,6 +26,8 @@ const faIR = {
|
||||
'downloadDir': 'دایرکتوری دانلود',
|
||||
'downloadDirValid': 'لطفا دایرکتوری دانلود را انتخاب کنید',
|
||||
'connections': 'اتصالات',
|
||||
'autoDeleteTorrents': 'حذف خودکار فایلهای .torrent',
|
||||
'autoCleanMissingFiles': 'پاکسازی خودکار فایلهای گم شده',
|
||||
'items': '@count آیتم ها',
|
||||
'subscribeTracker': 'Subscribe Tracker',
|
||||
'subscribeFail':
|
||||
|
||||
@@ -40,6 +40,8 @@ const frFR = {
|
||||
'maxRunning': 'Tâches en cours maximum',
|
||||
'autoStartTasks':
|
||||
'Démarrer automatiquement les tâches incomplètes au lancement',
|
||||
'autoDeleteTorrents': 'Supprimer automatiquement les fichiers .torrent',
|
||||
'autoCleanMissingFiles': 'Nettoyer automatiquement les fichiers manquants',
|
||||
'items': '@count éléments',
|
||||
'subscribeTracker': 'S\'abonner au tracker',
|
||||
'subscribeFail':
|
||||
|
||||
@@ -40,6 +40,8 @@ const huHU = {
|
||||
'maxRunning': 'Maximális futó feladatok',
|
||||
'defaultDirectDownload':
|
||||
'Alapértelmezettként ellenőrizze a közvetlen letöltést',
|
||||
'autoDeleteTorrents': 'Automatikus .torrent fájlok törlése',
|
||||
'autoCleanMissingFiles': 'Hiányzó fájlok automatikus tisztítása',
|
||||
'items': '@count elem',
|
||||
'subscribeTracker': 'Nyomkövető előfizetése',
|
||||
'subscribeFail':
|
||||
|
||||
@@ -39,6 +39,8 @@ const idID = {
|
||||
'useServerCtime': 'Gunakan waktu server untuk pembuatan file',
|
||||
'maxRunning': 'Tugas Maksimum yang Berjalan',
|
||||
'defaultDirectDownload': 'Pilih unduhan langsung sebagai opsi standar',
|
||||
'autoDeleteTorrents': 'Otomatis hapus file .torrent',
|
||||
'autoCleanMissingFiles': 'Otomatis bersihkan file yang hilang',
|
||||
'items': '@count items',
|
||||
'subscribeTracker': 'Berlangganan Tracker',
|
||||
'subscribeFail':
|
||||
|
||||
@@ -37,6 +37,8 @@ const itIT = {
|
||||
'connections': 'Connessioni',
|
||||
'useServerCtime': "Utilizza l'ora del server per la creazione dei file",
|
||||
'maxRunning': 'Numero massimo di attività in esecuzione',
|
||||
'autoDeleteTorrents': 'Elimina automaticamente i file .torrent',
|
||||
'autoCleanMissingFiles': 'Pulisci automaticamente i file mancanti',
|
||||
'items': '@count elementi',
|
||||
'subscribeTracker': 'Iscriviti al tracker',
|
||||
'subscribeFail':
|
||||
|
||||
@@ -30,6 +30,8 @@ const jaJP = {
|
||||
'connections': '接続',
|
||||
'maxRunning': '最大実行タスク',
|
||||
'autoStartTasks': '起動時に未完了のタスクを自動的に開始',
|
||||
'autoDeleteTorrents': '.torrentファイルを自動削除',
|
||||
'autoCleanMissingFiles': '欠落ファイルを自動クリーン',
|
||||
'items': '@count アイテム',
|
||||
'subscribeTracker': 'トラッカーを購読',
|
||||
'subscribeFail': '登録に失敗しました。ネットワークを確認するか、後でもう一度お試しください',
|
||||
|
||||
@@ -36,6 +36,8 @@ const plPL = {
|
||||
'connections': 'Połączenia',
|
||||
'useServerCtime': 'Użyj czasu serwera do utworzenia pliku',
|
||||
'maxRunning': 'Maksymalna liczba zadań',
|
||||
'autoDeleteTorrents': 'Automatycznie usuń pliki .torrent',
|
||||
'autoCleanMissingFiles': 'Automatycznie wyczyść brakujące pliki',
|
||||
'items': '@count items',
|
||||
'subscribeTracker': 'Subskrybuj tracker',
|
||||
'subscribeFail': 'Błąd subskrypcji, sprawdź łączność z internetem',
|
||||
|
||||
@@ -39,6 +39,8 @@ const ptBR = {
|
||||
'useServerCtime': 'Use server time for file creation',
|
||||
'maxRunning': 'Máximo de Tarefas Simultâneas',
|
||||
'defaultDirectDownload': 'Marcar download direto por padrão',
|
||||
'autoDeleteTorrents': 'Excluir automaticamente arquivos .torrent',
|
||||
'autoCleanMissingFiles': 'Limpar automaticamente arquivos ausentes',
|
||||
'items': '@count itens',
|
||||
'subscribeTracker': 'Assinar Rastreador',
|
||||
'subscribeFail':
|
||||
|
||||
@@ -40,6 +40,8 @@ const ruRU = {
|
||||
'maxRunning': 'Максимальное количество активных задач',
|
||||
'defaultDirectDownload': 'Прямая загрузка по умолчанию',
|
||||
'autoStartTasks': 'Автоматически запускать незавершённые задачи при старте',
|
||||
'autoDeleteTorrents': 'Автоудаление торрент-файлов',
|
||||
'autoCleanMissingFiles': 'Автоочистка отсутствующих файлов',
|
||||
'items': '@подсчет элементов',
|
||||
'subscribeTracker': 'Подпись трекера',
|
||||
'subscribeFail':
|
||||
@@ -149,4 +151,4 @@ const ruRU = {
|
||||
'builtInCategory': 'Встроенную категорию нельзя удалить',
|
||||
'selectCategory': 'Выбрать категорию',
|
||||
}
|
||||
};
|
||||
};
|
||||
@@ -37,6 +37,8 @@ const taTA = {
|
||||
'connections': 'தொடர்புகள்',
|
||||
'useServerCtime': 'Use server time for file creation',
|
||||
'maxRunning': 'அதிகபட்ச இயங்கும் பணிகள்',
|
||||
'autoDeleteTorrents': 'தானாக .torrent கோப்புகளை நீக்கு',
|
||||
'autoCleanMissingFiles': 'காணாமல் போன கோப்புகளை தானாக சுத்தம் செய்',
|
||||
'items': '@count items',
|
||||
'subscribeTracker': 'Subscribe Tracker',
|
||||
'subscribeFail':
|
||||
|
||||
@@ -39,6 +39,8 @@ const trTR = {
|
||||
'useServerCtime': 'Dosya oluşturma için sunucu zamanını kullan',
|
||||
'maxRunning': 'Maksimum Çalışan Görev',
|
||||
'defaultDirectDownload': 'Varsayılan olarak doğrudan indirmeyi seç',
|
||||
'autoDeleteTorrents': '.torrent dosyalarını otomatik sil',
|
||||
'autoCleanMissingFiles': 'Eksik dosyaları otomatik temizle',
|
||||
'items': '@count öğe',
|
||||
'subscribeTracker': 'Tracker Aboneliği',
|
||||
'subscribeFail':
|
||||
|
||||
@@ -39,6 +39,8 @@ const ukUA = {
|
||||
'useServerCtime': 'Використовувати час сервера для створення файлу',
|
||||
'maxRunning': 'Макс. завдань у черзі',
|
||||
'defaultDirectDownload': 'Пряме завантаження за замовчуванням',
|
||||
'autoDeleteTorrents': 'Автоматично видаляти файли .torrent',
|
||||
'autoCleanMissingFiles': 'Автоматично очищати відсутні файли',
|
||||
'items': '@count елементів',
|
||||
'subscribeTracker': 'Підписатися на трекер',
|
||||
'subscribeFail':
|
||||
|
||||
@@ -36,6 +36,8 @@ const viVN = {
|
||||
'connections': 'Kết nối',
|
||||
'useServerCtime': 'Sử dụng thời gian máy chủ cho việc tạo tệp',
|
||||
'maxRunning': 'Số nhiệm vụ tối đa',
|
||||
'autoDeleteTorrents': 'Tự động xóa tệp .torrent',
|
||||
'autoCleanMissingFiles': 'Tự động dọn dẹp tệp bị thiếu',
|
||||
'items': '@count mục',
|
||||
'subscribeTracker': 'Theo dõi Tracker',
|
||||
'subscribeFail':
|
||||
|
||||
@@ -39,6 +39,8 @@ const zhCN = {
|
||||
'maxRunning': '最大下载数',
|
||||
'defaultDirectDownload': '默认勾选直接下载',
|
||||
'autoStartTasks': '启动时自动开始未完成的任务',
|
||||
'autoDeleteTorrents': '自动删除 .torrent 文件',
|
||||
'autoCleanMissingFiles': '自动清理缺失文件',
|
||||
'items': '@count 项',
|
||||
'subscribeTracker': '订阅 Tracker',
|
||||
'subscribeFail': '订阅失败,请检查网络或稍后重试',
|
||||
|
||||
@@ -39,6 +39,8 @@ const zhTW = {
|
||||
'maxRunning': '最大執行任務數',
|
||||
'defaultDirectDownload': '預設勾選直接下載',
|
||||
'autoStartTasks': '啟動時自動開始未完成的任務',
|
||||
'autoDeleteTorrents': '自動刪除 .torrent 檔案',
|
||||
'autoCleanMissingFiles': '自動清理缺失檔案',
|
||||
'items': '@count 個項目',
|
||||
'subscribeTracker': '訂閱 Tracker',
|
||||
'subscribeFail': '訂閱失敗,請檢查網路或稍後再試',
|
||||
|
||||
Reference in new issue
Block a user