From 3729d2941e7bea8f57528ab9dcaf7bd14403b6cf Mon Sep 17 00:00:00 2001 From: oop7 <110548351+oop7@users.noreply.github.com> Date: Mon, 3 Nov 2025 20:53:53 +0200 Subject: [PATCH] Add output format selection to settings Introduces new settings for forcing output format when merging videos, allowing users to select a preferred format (mp4, webm, mkv). Updates all language files with relevant translations, adds UI controls in the settings dialog, persists settings via ConfigManager, and passes options through the download workflow to yt-dlp. --- languages/ar.json | 9 ++- languages/de.json | 9 ++- languages/en.json | 9 ++- languages/es.json | 9 ++- languages/fr.json | 9 ++- languages/hi.json | 9 ++- languages/id.json | 9 ++- languages/it.json | 9 ++- languages/ja.json | 9 ++- languages/pl.json | 9 ++- languages/pt.json | 9 ++- languages/ru.json | 9 ++- languages/tr.json | 9 ++- languages/zh.json | 9 ++- src/core/ytsage_downloader.py | 15 +++++ .../ytsage_dialogs_settings.py | 59 ++++++++++++++++++- src/gui/ytsage_gui_main.py | 17 +++++- src/utils/ytsage_config_manager.py | 2 + 18 files changed, 203 insertions(+), 16 deletions(-) diff --git a/languages/ar.json b/languages/ar.json index 91b10d2..a3ba2ff 100644 --- a/languages/ar.json +++ b/languages/ar.json @@ -277,7 +277,14 @@ "update_frequency_group": "تكرار التحديثات", "save_settings": "حفظ الإعدادات", "settings_saved_successfully": "✅ تم حفظ الإعدادات بنجاح!", - "error_saving": "❌ خطأ في حفظ الإعدادات: {error}" + "error_saving": "❌ خطأ في حفظ الإعدادات: {error}", + "output_format_settings": "إعدادات تنسيق الإخراج", + "force_output_format": "فرض تنسيق الإخراج عند الدمج", + "preferred_format": "التنسيق المفضل:", + "force_format_help": "عند التمكين، سيتم تحويل الفيديوهات المدموجة إلى تنسيقك المفضل. قم بالتعطيل للسماح لـ yt-dlp بالقرار تلقائياً.", + "format_mp4": "MP4 (الأكثر توافقاً)", + "format_webm": "WebM (حديث، مفتوح)", + "format_mkv": "MKV (غني بالميزات)" }, "main_ui": { "url_placeholder": "أدخل رابط فيديو يوتيوب أو قائمة تشغيل", diff --git a/languages/de.json b/languages/de.json index fce7d10..579af68 100644 --- a/languages/de.json +++ b/languages/de.json @@ -277,7 +277,14 @@ "update_frequency_group": "Update-Häufigkeit", "save_settings": "Einstellungen speichern", "settings_saved_successfully": "✅ Einstellungen erfolgreich gespeichert!", - "error_saving": "❌ Fehler beim Speichern der Einstellungen: {error}" + "error_saving": "❌ Fehler beim Speichern der Einstellungen: {error}", + "output_format_settings": "Ausgabeformat-Einstellungen", + "force_output_format": "Ausgabeformat beim Zusammenführen erzwingen", + "preferred_format": "Bevorzugtes Format:", + "force_format_help": "Wenn aktiviert, werden zusammengeführte Videos in Ihr bevorzugtes Format konvertiert. Deaktivieren Sie diese Option, damit yt-dlp automatisch entscheidet.", + "format_mp4": "MP4 (Am kompatibelsten)", + "format_webm": "WebM (Modern, offen)", + "format_mkv": "MKV (Funktionsreich)" }, "main_ui": { "url_placeholder": "YouTube-Video- oder Playlist-URL eingeben", diff --git a/languages/en.json b/languages/en.json index 8b07099..f4b4bf3 100644 --- a/languages/en.json +++ b/languages/en.json @@ -277,7 +277,14 @@ "update_frequency_group": "Update Frequency", "save_settings": "Save Settings", "settings_saved_successfully": "✅ Settings saved successfully!", - "error_saving": "❌ Error saving settings: {error}" + "error_saving": "❌ Error saving settings: {error}", + "output_format_settings": "Output Format Settings", + "force_output_format": "Force output format when merging", + "preferred_format": "Preferred format:", + "force_format_help": "When enabled, merged videos will be converted to your preferred format. Disable to let yt-dlp decide automatically.", + "format_mp4": "MP4 (Most compatible)", + "format_webm": "WebM (Modern, open)", + "format_mkv": "MKV (Feature-rich)" }, "main_ui": { "url_placeholder": "Enter YouTube video or playlist URL", diff --git a/languages/es.json b/languages/es.json index 10a1792..89cbb32 100644 --- a/languages/es.json +++ b/languages/es.json @@ -260,7 +260,14 @@ "update_frequency_group": "Frecuencia de Actualización", "save_settings": "Guardar Configuración", "settings_saved_successfully": "✅ ¡Configuración guardada exitosamente!", - "error_saving": "❌ Error al guardar configuración: {error}" + "error_saving": "❌ Error al guardar configuración: {error}", + "output_format_settings": "Configuración de Formato de Salida", + "force_output_format": "Forzar formato de salida al combinar", + "preferred_format": "Formato preferido:", + "force_format_help": "Cuando está habilitado, los videos combinados se convertirán a su formato preferido. Deshabilitar para dejar que yt-dlp decida automáticamente.", + "format_mp4": "MP4 (Más compatible)", + "format_webm": "WebM (Moderno, abierto)", + "format_mkv": "MKV (Rico en funciones)" }, "main_ui": { "url_placeholder": "Ingresa URL de video o lista de YouTube", diff --git a/languages/fr.json b/languages/fr.json index e752ed5..391f4ed 100644 --- a/languages/fr.json +++ b/languages/fr.json @@ -277,7 +277,14 @@ "update_frequency_group": "Fréquence de mise à jour", "save_settings": "Sauvegarder les paramètres", "settings_saved_successfully": "✅ Paramètres sauvegardés avec succès !", - "error_saving": "❌ Erreur lors de la sauvegarde des paramètres : {error}" + "error_saving": "❌ Erreur lors de la sauvegarde des paramètres : {error}", + "output_format_settings": "Paramètres du format de sortie", + "force_output_format": "Forcer le format de sortie lors de la fusion", + "preferred_format": "Format préféré :", + "force_format_help": "Lorsqu'activé, les vidéos fusionnées seront converties vers votre format préféré. Désactivez pour laisser yt-dlp décider automatiquement.", + "format_mp4": "MP4 (Plus compatible)", + "format_webm": "WebM (Moderne, ouvert)", + "format_mkv": "MKV (Riche en fonctionnalités)" }, "main_ui": { "url_placeholder": "Entrer l'URL de la vidéo ou de la playlist YouTube", diff --git a/languages/hi.json b/languages/hi.json index c3ad3dd..b33846e 100644 --- a/languages/hi.json +++ b/languages/hi.json @@ -277,7 +277,14 @@ "update_frequency_group": "अपडेट आवृत्ति", "save_settings": "सेटिंग्स सेव करें", "settings_saved_successfully": "✅ सेटिंग्स सफलतापूर्वक सेव हुईं!", - "error_saving": "❌ सेटिंग्स सेव करने में त्रुटि: {error}" + "error_saving": "❌ सेटिंग्स सेव करने में त्रुटि: {error}", + "output_format_settings": "आउटपुट प्रारूप सेटिंग्स", + "force_output_format": "मर्ज करते समय आउटपुट प्रारूप बाध्य करें", + "preferred_format": "पसंदीदा प्रारूप:", + "force_format_help": "सक्षम होने पर, मर्ज किए गए वीडियो आपके पसंदीदा प्रारूप में परिवर्तित हो जाएंगे। yt-dlp को स्वचालित रूप से निर्णय लेने देने के लिए अक्षम करें।", + "format_mp4": "MP4 (सबसे संगत)", + "format_webm": "WebM (आधुनिक, खुला)", + "format_mkv": "MKV (सुविधा समृद्ध)" }, "main_ui": { "url_placeholder": "YouTube वीडियो या प्लेलिस्ट URL दर्ज करें", diff --git a/languages/id.json b/languages/id.json index 69986de..8114465 100644 --- a/languages/id.json +++ b/languages/id.json @@ -277,7 +277,14 @@ "update_frequency_group": "Frekuensi pembaruan", "save_settings": "Simpan pengaturan", "settings_saved_successfully": "✅ Pengaturan berhasil disimpan!", - "error_saving": "❌ Kesalahan menyimpan pengaturan: {error}" + "error_saving": "❌ Kesalahan menyimpan pengaturan: {error}", + "output_format_settings": "Pengaturan Format Output", + "force_output_format": "Paksa format output saat menggabungkan", + "preferred_format": "Format yang disukai:", + "force_format_help": "Jika diaktifkan, video yang digabungkan akan dikonversi ke format pilihan Anda. Nonaktifkan untuk membiarkan yt-dlp memutuskan secara otomatis.", + "format_mp4": "MP4 (Paling kompatibel)", + "format_webm": "WebM (Modern, terbuka)", + "format_mkv": "MKV (Kaya fitur)" }, "main_ui": { "url_placeholder": "Masukkan URL video atau playlist YouTube", diff --git a/languages/it.json b/languages/it.json index f08aad8..c0a3afc 100644 --- a/languages/it.json +++ b/languages/it.json @@ -277,7 +277,14 @@ "update_frequency_group": "Frequenza aggiornamenti", "save_settings": "Salva impostazioni", "settings_saved_successfully": "✅ Impostazioni salvate con successo!", - "error_saving": "❌ Errore nel salvataggio impostazioni: {error}" + "error_saving": "❌ Errore nel salvataggio impostazioni: {error}", + "output_format_settings": "Impostazioni formato output", + "force_output_format": "Forza formato output durante la fusione", + "preferred_format": "Formato preferito:", + "force_format_help": "Quando attivato, i video uniti verranno convertiti nel formato preferito. Disattiva per lasciare che yt-dlp decida automaticamente.", + "format_mp4": "MP4 (Più compatibile)", + "format_webm": "WebM (Moderno, aperto)", + "format_mkv": "MKV (Ricco di funzionalità)" }, "main_ui": { "url_placeholder": "Inserisci URL video YouTube o playlist", diff --git a/languages/ja.json b/languages/ja.json index 1018749..827fe96 100644 --- a/languages/ja.json +++ b/languages/ja.json @@ -277,7 +277,14 @@ "update_frequency_group": "更新頻度", "save_settings": "設定を保存", "settings_saved_successfully": "✅ 設定が正常に保存されました!", - "error_saving": "❌ 設定の保存エラー: {error}" + "error_saving": "❌ 設定の保存エラー: {error}", + "output_format_settings": "出力形式設定", + "force_output_format": "マージ時に出力形式を強制", + "preferred_format": "優先形式:", + "force_format_help": "有効にすると、マージされた動画は優先形式に変換されます。無効にすると、yt-dlpが自動的に決定します。", + "format_mp4": "MP4(最も互換性が高い)", + "format_webm": "WebM(モダン、オープン)", + "format_mkv": "MKV(機能豊富)" }, "main_ui": { "url_placeholder": "YouTubeの動画URLまたはプレイリストURLを入力", diff --git a/languages/pl.json b/languages/pl.json index 5caa024..c64e153 100644 --- a/languages/pl.json +++ b/languages/pl.json @@ -277,7 +277,14 @@ "update_frequency_group": "Częstotliwość aktualizacji", "save_settings": "Zapisz ustawienia", "settings_saved_successfully": "✅ Ustawienia zapisane pomyślnie!", - "error_saving": "❌ Błąd zapisywania ustawień: {error}" + "error_saving": "❌ Błąd zapisywania ustawień: {error}", + "output_format_settings": "Ustawienia formatu wyjściowego", + "force_output_format": "Wymuś format wyjściowy podczas łączenia", + "preferred_format": "Preferowany format:", + "force_format_help": "Po włączeniu połączone filmy zostaną przekonwertowane na wybrany format. Wyłącz, aby pozwolić yt-dlp zdecydować automatycznie.", + "format_mp4": "MP4 (Najbardziej kompatybilny)", + "format_webm": "WebM (Nowoczesny, otwarty)", + "format_mkv": "MKV (Bogaty w funkcje)" }, "main_ui": { "url_placeholder": "Wprowadź URL wideo YouTube lub playlisty", diff --git a/languages/pt.json b/languages/pt.json index 1c4ec0e..4d5503a 100644 --- a/languages/pt.json +++ b/languages/pt.json @@ -277,7 +277,14 @@ "update_frequency_group": "Frequência de Atualização", "save_settings": "Salvar Configurações", "settings_saved_successfully": "✅ Configurações salvas com sucesso!", - "error_saving": "❌ Erro ao salvar configurações: {error}" + "error_saving": "❌ Erro ao salvar configurações: {error}", + "output_format_settings": "Configurações de Formato de Saída", + "force_output_format": "Forçar formato de saída ao mesclar", + "preferred_format": "Formato preferido:", + "force_format_help": "Quando ativado, os vídeos mesclados serão convertidos para o seu formato preferido. Desative para deixar o yt-dlp decidir automaticamente.", + "format_mp4": "MP4 (Mais compatível)", + "format_webm": "WebM (Moderno, aberto)", + "format_mkv": "MKV (Rico em recursos)" }, "main_ui": { "url_placeholder": "Digite a URL do vídeo ou playlist do YouTube", diff --git a/languages/ru.json b/languages/ru.json index 4b1fdc5..8878d74 100644 --- a/languages/ru.json +++ b/languages/ru.json @@ -277,7 +277,14 @@ "update_frequency_group": "Частота обновления", "save_settings": "Сохранить настройки", "settings_saved_successfully": "✅ Настройки успешно сохранены!", - "error_saving": "❌ Ошибка сохранения настроек: {error}" + "error_saving": "❌ Ошибка сохранения настроек: {error}", + "output_format_settings": "Настройки выходного формата", + "force_output_format": "Принудительно задать выходной формат при объединении", + "preferred_format": "Предпочтительный формат:", + "force_format_help": "Когда включено, объединённые видео будут конвертированы в ваш предпочтительный формат. Отключите, чтобы yt-dlp решал автоматически.", + "format_mp4": "MP4 (Наиболее совместимый)", + "format_webm": "WebM (Современный, открытый)", + "format_mkv": "MKV (Многофункциональный)" }, "main_ui": { "url_placeholder": "Введите URL видео или плейлиста YouTube", diff --git a/languages/tr.json b/languages/tr.json index 0847fd3..14ae8a2 100644 --- a/languages/tr.json +++ b/languages/tr.json @@ -277,7 +277,14 @@ "update_frequency_group": "Güncelleme sıklığı", "save_settings": "Ayarları kaydet", "settings_saved_successfully": "✅ Ayarlar başarıyla kaydedildi!", - "error_saving": "❌ Ayarları kaydetme hatası: {error}" + "error_saving": "❌ Ayarları kaydetme hatası: {error}", + "output_format_settings": "Çıktı Formatı Ayarları", + "force_output_format": "Birleştirirken çıktı formatını zorla", + "preferred_format": "Tercih edilen format:", + "force_format_help": "Etkinleştirildiğinde, birleştirilen videolar tercih ettiğiniz formata dönüştürülür. yt-dlp'nin otomatik karar vermesini sağlamak için devre dışı bırakın.", + "format_mp4": "MP4 (En uyumlu)", + "format_webm": "WebM (Modern, açık)", + "format_mkv": "MKV (Özellik açısından zengin)" }, "main_ui": { "url_placeholder": "YouTube video veya oynatma listesi URL'sini girin", diff --git a/languages/zh.json b/languages/zh.json index 80dbc0d..c232493 100644 --- a/languages/zh.json +++ b/languages/zh.json @@ -277,7 +277,14 @@ "update_frequency_group": "更新频率", "save_settings": "保存设置", "settings_saved_successfully": "✅ 设置保存成功!", - "error_saving": "❌ 保存设置时出错:{error}" + "error_saving": "❌ 保存设置时出错:{error}", + "output_format_settings": "输出格式设置", + "force_output_format": "合并时强制输出格式", + "preferred_format": "首选格式:", + "force_format_help": "启用后,合并的视频将转换为您的首选格式。禁用以让 yt-dlp 自动决定。", + "format_mp4": "MP4(最兼容)", + "format_webm": "WebM(现代、开放)", + "format_mkv": "MKV(功能丰富)" }, "main_ui": { "url_placeholder": "输入 YouTube 视频或播放列表网址", diff --git a/src/core/ytsage_downloader.py b/src/core/ytsage_downloader.py index 18dae05..cf7b029 100644 --- a/src/core/ytsage_downloader.py +++ b/src/core/ytsage_downloader.py @@ -58,6 +58,8 @@ class DownloadThread(QThread): force_keyframes=False, proxy_url=None, geo_proxy_url=None, + force_output_format=False, + preferred_output_format="mp4", ) -> None: super().__init__() self.url = url @@ -81,6 +83,8 @@ class DownloadThread(QThread): self.force_keyframes = force_keyframes self.proxy_url = proxy_url self.geo_proxy_url = geo_proxy_url + self.force_output_format = force_output_format + self.preferred_output_format = preferred_output_format self.paused = False self.cancelled = False self.process = None @@ -189,6 +193,17 @@ class DownloadThread(QThread): res_value = self.resolution if self.resolution else "720" # Default to 720p if no resolution specified cmd.extend(["-S", f"res:{res_value}"]) + # Force output format if enabled and merging is needed + if self.force_output_format and not self.is_audio_only: + if self.format_has_audio: + # Progressive format (video with audio) - use remux to convert container + cmd.extend(["--remux-video", self.preferred_output_format]) + logger.debug(f"Using --remux-video to force progressive format to: {self.preferred_output_format}") + else: + # Merging video+audio - force merge output format + cmd.extend(["--merge-output-format", self.preferred_output_format]) + logger.debug(f"Using --merge-output-format to force merged format to: {self.preferred_output_format}") + # Output template with resolution in filename # Use string concatenation instead of Path.joinpath to avoid Path object issues base_path = self.path.as_posix() diff --git a/src/gui/ytsage_gui_dialogs/ytsage_dialogs_settings.py b/src/gui/ytsage_gui_dialogs/ytsage_dialogs_settings.py index 8dfa93b..585f07a 100644 --- a/src/gui/ytsage_gui_dialogs/ytsage_dialogs_settings.py +++ b/src/gui/ytsage_gui_dialogs/ytsage_dialogs_settings.py @@ -36,6 +36,7 @@ from src.core.ytsage_utils import ( from src.gui.ytsage_gui_dialogs.ytsage_dialogs_update import YTDLPUpdateDialog from src.utils.ytsage_logger import logger from src.utils.ytsage_localization import _ +from src.utils.ytsage_config_manager import ConfigManager class DownloadSettingsDialog(QDialog): @@ -199,6 +200,47 @@ class DownloadSettingsDialog(QDialog): speed_group_box.setLayout(speed_layout) layout.addWidget(speed_group_box) + # --- Output Format Settings Section --- + output_format_group_box = QGroupBox(_("settings.output_format_settings")) + output_format_layout = QVBoxLayout() + + # Load current format settings from ConfigManager + self.force_format_enabled = ConfigManager.get("force_output_format") or False + self.preferred_format_value = ConfigManager.get("preferred_output_format") or "mp4" + + # Enable/Disable force output format checkbox + self.force_format_checkbox = QCheckBox(_("settings.force_output_format")) + self.force_format_checkbox.setChecked(self.force_format_enabled) + output_format_layout.addWidget(self.force_format_checkbox) + + # Format selection layout + format_select_layout = QHBoxLayout() + format_label = QLabel(_("settings.preferred_format")) + format_label.setStyleSheet("color: #ffffff; margin-top: 5px;") + format_select_layout.addWidget(format_label) + + self.format_combo = QComboBox() + self.format_combo.addItems([ + _("settings.format_mp4"), + _("settings.format_webm"), + _("settings.format_mkv") + ]) + # Set current selection based on saved format + format_index_map = {"mp4": 0, "webm": 1, "mkv": 2} + self.format_combo.setCurrentIndex(format_index_map.get(self.preferred_format_value, 0)) + format_select_layout.addWidget(self.format_combo) + format_select_layout.addStretch() + output_format_layout.addLayout(format_select_layout) + + # Help text + help_label = QLabel(_("settings.force_format_help")) + help_label.setWordWrap(True) + help_label.setStyleSheet("color: #cccccc; margin: 5px; font-size: 10px;") + output_format_layout.addWidget(help_label) + + output_format_group_box.setLayout(output_format_layout) + layout.addWidget(output_format_group_box) + # --- Auto-Update yt-dlp Section --- auto_update_group_box = QGroupBox(_("settings.auto_update_ytdlp")) auto_update_layout = QVBoxLayout() @@ -278,6 +320,15 @@ class DownloadSettingsDialog(QDialog): """Returns the index of the selected speed limit unit.""" return self.speed_limit_unit.currentIndex() + def get_force_format_enabled(self) -> bool: + """Returns whether force output format is enabled.""" + return self.force_format_checkbox.isChecked() + + def get_preferred_format(self) -> str: + """Returns the selected preferred format (lowercase).""" + format_map = {0: "mp4", 1: "webm", 2: "mkv"} + return format_map.get(self.format_combo.currentIndex(), "mp4") + def _create_styled_message_box(self, icon, title, text) -> QMessageBox: """Create a styled QMessageBox that matches the app theme.""" msg_box = QMessageBox(self) @@ -334,11 +385,17 @@ class DownloadSettingsDialog(QDialog): return enabled, frequency def accept(self) -> None: - """Override accept to save auto-update settings.""" + """Override accept to save auto-update and format settings.""" try: # Save auto-update settings enabled, frequency = self.get_auto_update_settings() + # Save output format settings + force_format = self.get_force_format_enabled() + preferred_format = self.get_preferred_format() + ConfigManager.set("force_output_format", force_format) + ConfigManager.set("preferred_output_format", preferred_format) + if update_auto_update_settings(enabled, frequency): QMessageBox.information( self, diff --git a/src/gui/ytsage_gui_main.py b/src/gui/ytsage_gui_main.py index ee4688b..28f3906 100644 --- a/src/gui/ytsage_gui_main.py +++ b/src/gui/ytsage_gui_main.py @@ -124,6 +124,9 @@ class YTSageApp(QMainWindow, FormatTableMixin, VideoInfoMixin): # Inherit from self.speed_limit_unit_index = 0 # Store speed limit unit index (0: KB/s, 1: MB/s) self.download_section = None self.force_keyframes = False + # Initialize output format settings + self.force_output_format = ConfigManager.get("force_output_format") or False + self.preferred_output_format = ConfigManager.get("preferred_output_format") or "mp4" self.init_ui() self.setStyleSheet( @@ -768,8 +771,18 @@ class YTSageApp(QMainWindow, FormatTableMixin, VideoInfoMixin): # Inherit from f"Speed limit updated to: {self.speed_limit_value} {['KB/s', 'MB/s'][self.speed_limit_unit_index] if self.speed_limit_value else 'None'}" ) + # Update Output Format Settings + new_force_format = dialog.get_force_format_enabled() + new_preferred_format = dialog.get_preferred_format() + format_changed = False + if new_force_format != self.force_output_format or new_preferred_format != self.preferred_output_format: + self.force_output_format = new_force_format + self.preferred_output_format = new_preferred_format + format_changed = True + logger.info(f"Output format settings updated - Force: {self.force_output_format}, Preferred: {self.preferred_output_format}") + # Update Tooltip if anything changed - if path_changed or limit_changed: + if path_changed or limit_changed or format_changed: limit_text = "None" if self.speed_limit_value: limit_text = f"{self.speed_limit_value} {['KB/s', 'MB/s'][self.speed_limit_unit_index]}" @@ -876,6 +889,8 @@ class YTSageApp(QMainWindow, FormatTableMixin, VideoInfoMixin): # Inherit from force_keyframes=self.force_keyframes, # Pass the force keyframes setting proxy_url=self.proxy_url, # Pass the proxy URL geo_proxy_url=self.geo_proxy_url, # Pass the geo-verification proxy URL + force_output_format=self.force_output_format, # Pass force output format setting + preferred_output_format=self.preferred_output_format, # Pass preferred format ) # Connect signals diff --git a/src/utils/ytsage_config_manager.py b/src/utils/ytsage_config_manager.py index ff3a04b..f7b9f9e 100644 --- a/src/utils/ytsage_config_manager.py +++ b/src/utils/ytsage_config_manager.py @@ -80,6 +80,8 @@ class ConfigManager: "auto_update_frequency": "daily", "last_update_check": 0, "language": "en", + "force_output_format": False, + "preferred_output_format": "mp4", "cached_versions": { "ytdlp": {"version": None, "path": None, "last_check": 0, "path_mtime": 0}, "ffmpeg": {"version": None, "path": None, "last_check": 0, "path_mtime": 0},