New:Socket for Asana Is Now Available.Learn more
Get Started

Screenshot for YouTube™ | 4K Frame & Thumbnail Cap

Package Overview
Versions
1
Alerts
File Explorer
Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

youtube-frame-extractor@example.com - firefox Package Compare versions

Comparing version
1.2.6
to
1.2.9
+138
_locales/de/messages.json
{
"appName": {
"message": "YouTube Frame-Extractor",
"description": "The name of the extension"
},
"appDesc": {
"message": "Extrahiere hochwertige Frames aus YouTube-Videos ohne UI-Elemente (4K Screenshot)",
"description": "The description of the extension"
},
"captureBtn": {
"message": "Aufnehmen",
"description": "Button to capture a frame"
},
"thumbnailBtn": {
"message": "Thumbnail laden",
"description": "Button to download video thumbnail"
},
"settings": {
"message": "Einstellungen",
"description": "Settings label"
},
"captureQuality": {
"message": "Qualität",
"description": "Capture quality option"
},
"fileFormat": {
"message": "Format",
"description": "File format option"
},
"fileName": {
"message": "Dateiname",
"description": "File name option"
},
"language": {
"message": "Sprache",
"description": "Language selection"
},
"videoNotFound": {
"message": "Kein Video gefunden!",
"description": "Error when video is not found"
},
"captureSuccess": {
"message": "Frame aufgenommen!",
"description": "Success message after capturing a frame"
},
"thumbnailSuccess": {
"message": "Thumbnail heruntergeladen!",
"description": "Success message after downloading thumbnail"
},
"thumbnailError": {
"message": "Fehler beim Download",
"description": "Error message for thumbnail download"
},
"highQuality": {
"message": "Hoch",
"description": "High quality option"
},
"mediumQuality": {
"message": "Mittel",
"description": "Medium quality option"
},
"lowQuality": {
"message": "Niedrig",
"description": "Low quality option"
},
"saveSettings": {
"message": "Speichern",
"description": "Save settings button"
},
"resetSettings": {
"message": "Zurücksetzen",
"description": "Reset settings button"
},
"copyBtn": {
"message": "Kopieren",
"description": "Button to copy frame to clipboard"
},
"copySuccess": {
"message": "In Zwischenablage kopiert!",
"description": "Success message after copying a frame"
},
"showPreviewLabel": {
"message": "Vorschau",
"description": "Setting to toggle thumbnail preview"
},
"shortcutLabel": {
"message": "Tastenkürzel:",
"description": "Label for keyboard shortcut"
},
"changeShortcut": {
"message": "Ändern",
"description": "Button to change keyboard shortcut"
},
"shareText": {
"message": "Teilen",
"description": "Share button text"
},
"rateText": {
"message": "Bewerten",
"description": "Rate button text"
},
"toolsLabel": {
"message": "Werkzeuge",
"description": "Tools section header"
},
"downloadThumbnail": {
"message": "HD Thumbnail laden",
"description": "Button to download HD thumbnail"
},
"copied": {
"message": "Kopiert! ✅",
"description": "Confirmation when text is copied"
},
"capturing": {
"message": "Aufnahme...",
"description": "Status while capturing"
},
"copying": {
"message": "Kopiere...",
"description": "Status while copying"
},
"settingsSaved": {
"message": "Einstellungen gespeichert",
"description": "Confirmation when settings are saved"
},
"settingsReset": {
"message": "Einstellungen zurückgesetzt",
"description": "Confirmation when settings are reset"
},
"navigateToYouTube": {
"message": "Bitte öffne zuerst ein YouTube-Video",
"description": "Error when not on YouTube"
},
"firefoxShortcutHelp": {
"message": "Tastenkürzel in Firefox ändern: Add-ons (Strg+Umschalt+A) > Zahnrad > Tastenkürzel verwalten",
"description": "Help text for Firefox shortcut change"
}
}
{
"appName": {
"message": "Extractor de Fotogramas de YouTube",
"description": "The name of the extension"
},
"appDesc": {
"message": "Extrae fotogramas de alta calidad de vídeos de YouTube sin elementos de interfaz (Screenshot 4K)",
"description": "The description of the extension"
},
"captureBtn": {
"message": "Capturar",
"description": "Button to capture a frame"
},
"thumbnailBtn": {
"message": "Descargar Miniatura",
"description": "Button to download video thumbnail"
},
"settings": {
"message": "Ajustes",
"description": "Settings label"
},
"captureQuality": {
"message": "Calidad",
"description": "Capture quality option"
},
"fileFormat": {
"message": "Formato",
"description": "File format option"
},
"fileName": {
"message": "Nombre",
"description": "File name option"
},
"language": {
"message": "Idioma",
"description": "Language selection"
},
"videoNotFound": {
"message": "¡No se encontró ningún vídeo!",
"description": "Error when video is not found"
},
"captureSuccess": {
"message": "¡Fotograma capturado!",
"description": "Success message after capturing a frame"
},
"thumbnailSuccess": {
"message": "¡Miniatura descargada!",
"description": "Success message after downloading thumbnail"
},
"thumbnailError": {
"message": "Error al descargar",
"description": "Error message for thumbnail download"
},
"highQuality": {
"message": "Alta",
"description": "High quality option"
},
"mediumQuality": {
"message": "Media",
"description": "Medium quality option"
},
"lowQuality": {
"message": "Baja",
"description": "Low quality option"
},
"saveSettings": {
"message": "Guardar",
"description": "Save settings button"
},
"resetSettings": {
"message": "Restablecer",
"description": "Reset settings button"
},
"copyBtn": {
"message": "Copiar",
"description": "Button to copy frame to clipboard"
},
"copySuccess": {
"message": "¡Copiado al portapapeles!",
"description": "Success message after copying a frame"
},
"showPreviewLabel": {
"message": "Vista Previa",
"description": "Setting to toggle thumbnail preview"
},
"shortcutLabel": {
"message": "Atajo:",
"description": "Label for keyboard shortcut"
},
"changeShortcut": {
"message": "Cambiar",
"description": "Button to change keyboard shortcut"
},
"shareText": {
"message": "Compartir",
"description": "Share button text"
},
"rateText": {
"message": "Valorar",
"description": "Rate button text"
},
"toolsLabel": {
"message": "Herramientas",
"description": "Tools section header"
},
"downloadThumbnail": {
"message": "Descargar Miniatura HD",
"description": "Button to download HD thumbnail"
},
"copied": {
"message": "¡Copiado! ✅",
"description": "Confirmation when text is copied"
},
"capturing": {
"message": "Capturando...",
"description": "Status while capturing"
},
"copying": {
"message": "Copiando...",
"description": "Status while copying"
},
"settingsSaved": {
"message": "Ajustes guardados",
"description": "Confirmation when settings are saved"
},
"settingsReset": {
"message": "Ajustes restablecidos",
"description": "Confirmation when settings are reset"
},
"navigateToYouTube": {
"message": "Navega a un vídeo de YouTube primero",
"description": "Error when not on YouTube"
},
"firefoxShortcutHelp": {
"message": "Para cambiar atajos en Firefox: Complementos (Ctrl+Shift+A) > Engranaje > Administrar Atajos",
"description": "Help text for Firefox shortcut change"
}
}
{
"appName": {
"message": "Extracteur de Frames YouTube",
"description": "The name of the extension"
},
"appDesc": {
"message": "Extrayez des images haute qualité de vidéos YouTube sans éléments d'interface (Screenshot 4K)",
"description": "The description of the extension"
},
"captureBtn": {
"message": "Capturer",
"description": "Button to capture a frame"
},
"thumbnailBtn": {
"message": "Télécharger miniature",
"description": "Button to download video thumbnail"
},
"settings": {
"message": "Paramètres",
"description": "Settings label"
},
"captureQuality": {
"message": "Qualité",
"description": "Capture quality option"
},
"fileFormat": {
"message": "Format",
"description": "File format option"
},
"fileName": {
"message": "Nom",
"description": "File name option"
},
"language": {
"message": "Langue",
"description": "Language selection"
},
"videoNotFound": {
"message": "Aucune vidéo trouvée !",
"description": "Error when video is not found"
},
"captureSuccess": {
"message": "Image capturée !",
"description": "Success message after capturing a frame"
},
"thumbnailSuccess": {
"message": "Miniature téléchargée !",
"description": "Success message after downloading thumbnail"
},
"thumbnailError": {
"message": "Erreur de téléchargement",
"description": "Error message for thumbnail download"
},
"highQuality": {
"message": "Haute",
"description": "High quality option"
},
"mediumQuality": {
"message": "Moyenne",
"description": "Medium quality option"
},
"lowQuality": {
"message": "Basse",
"description": "Low quality option"
},
"saveSettings": {
"message": "Enregistrer",
"description": "Save settings button"
},
"resetSettings": {
"message": "Réinitialiser",
"description": "Reset settings button"
},
"copyBtn": {
"message": "Copier",
"description": "Button to copy frame to clipboard"
},
"copySuccess": {
"message": "Copié dans le presse-papiers !",
"description": "Success message after copying a frame"
},
"showPreviewLabel": {
"message": "Aperçu",
"description": "Setting to toggle thumbnail preview"
},
"shortcutLabel": {
"message": "Raccourci :",
"description": "Label for keyboard shortcut"
},
"changeShortcut": {
"message": "Modifier",
"description": "Button to change keyboard shortcut"
},
"shareText": {
"message": "Partager",
"description": "Share button text"
},
"rateText": {
"message": "Noter",
"description": "Rate button text"
},
"toolsLabel": {
"message": "Outils",
"description": "Tools section header"
},
"downloadThumbnail": {
"message": "Télécharger miniature HD",
"description": "Button to download HD thumbnail"
},
"copied": {
"message": "Copié ! ✅",
"description": "Confirmation when text is copied"
},
"capturing": {
"message": "Capture...",
"description": "Status while capturing"
},
"copying": {
"message": "Copie...",
"description": "Status while copying"
},
"settingsSaved": {
"message": "Paramètres enregistrés",
"description": "Confirmation when settings are saved"
},
"settingsReset": {
"message": "Paramètres réinitialisés",
"description": "Confirmation when settings are reset"
},
"navigateToYouTube": {
"message": "Ouvrez d'abord une vidéo YouTube",
"description": "Error when not on YouTube"
},
"firefoxShortcutHelp": {
"message": "Modifier les raccourcis Firefox : Extensions (Ctrl+Maj+A) > Roue dentée > Gérer les raccourcis",
"description": "Help text for Firefox shortcut change"
}
}
{
"appName": {
"message": "YouTube フレーム抽出ツール",
"description": "The name of the extension"
},
"appDesc": {
"message": "YouTube動画から高画質フレームをUI要素なしで抽出 (4K Screenshot対応)",
"description": "The description of the extension"
},
"captureBtn": {
"message": "フレームをキャプチャ",
"description": "Button to capture a frame"
},
"thumbnailBtn": {
"message": "サムネイルをダウンロード",
"description": "Button to download video thumbnail"
},
"settings": {
"message": "設定",
"description": "Settings label"
},
"captureQuality": {
"message": "画質",
"description": "Capture quality option"
},
"fileFormat": {
"message": "形式",
"description": "File format option"
},
"fileName": {
"message": "ファイル名",
"description": "File name option"
},
"language": {
"message": "言語",
"description": "Language selection"
},
"videoNotFound": {
"message": "動画が見つかりません!",
"description": "Error when video is not found"
},
"captureSuccess": {
"message": "フレームのキャプチャに成功しました!",
"description": "Success message after capturing a frame"
},
"thumbnailSuccess": {
"message": "サムネイルのダウンロードに成功しました!",
"description": "Success message after downloading thumbnail"
},
"thumbnailError": {
"message": "サムネイルのダウンロードに失敗しました",
"description": "Error message for thumbnail download"
},
"highQuality": {
"message": "高画質",
"description": "High quality option"
},
"mediumQuality": {
"message": "標準",
"description": "Medium quality option"
},
"lowQuality": {
"message": "低画質",
"description": "Low quality option"
},
"saveSettings": {
"message": "保存",
"description": "Save settings button"
},
"resetSettings": {
"message": "リセット",
"description": "Reset settings button"
},
"copyBtn": {
"message": "クリップボードにコピー",
"description": "Button to copy frame to clipboard"
},
"copySuccess": {
"message": "フレームをクリップボードにコピーしました!",
"description": "Success message after copying a frame"
},
"showPreviewLabel": {
"message": "サムネイルプレビュー",
"description": "Setting to toggle thumbnail preview"
},
"shortcutLabel": {
"message": "ショートカット:",
"description": "Label for keyboard shortcut"
},
"changeShortcut": {
"message": "変更",
"description": "Button to change keyboard shortcut"
},
"shareText": {
"message": "共有する",
"description": "Share button text"
},
"rateText": {
"message": "評価する",
"description": "Rate button text"
},
"toolsLabel": {
"message": "ツールと設定",
"description": "Tools section header"
},
"downloadThumbnail": {
"message": "HDサムネイルをダウンロード",
"description": "Button to download HD thumbnail"
},
"copied": {
"message": "コピー完了! ✅",
"description": "Confirmation when text is copied"
},
"capturing": {
"message": "キャプチャ中...",
"description": "Status while capturing"
},
"copying": {
"message": "コピー中...",
"description": "Status while copying"
},
"settingsSaved": {
"message": "設定を保存しました",
"description": "Confirmation when settings are saved"
},
"settingsReset": {
"message": "設定を初期化しました",
"description": "Confirmation when settings are reset"
},
"navigateToYouTube": {
"message": "YouTubeの動画ページを開いてください",
"description": "Error when not on YouTube"
},
"firefoxShortcutHelp": {
"message": "Firefoxでショートカットを変更: アドオン (Ctrl+Shift+A) > 歯車アイコン > 拡張機能のショートカットを管理",
"description": "Help text for Firefox shortcut change"
}
}
{
"appName": {
"message": "Extrator de Frames do YouTube",
"description": "The name of the extension"
},
"appDesc": {
"message": "Extraia frames de alta qualidade de vídeos do YouTube sem elementos de interface (4K Screenshot)",
"description": "The description of the extension"
},
"captureBtn": {
"message": "Capturar Frame",
"description": "Button to capture a frame"
},
"thumbnailBtn": {
"message": "Baixar Miniatura",
"description": "Button to download video thumbnail"
},
"settings": {
"message": "Configurações",
"description": "Settings label"
},
"captureQuality": {
"message": "Qualidade",
"description": "Capture quality option"
},
"fileFormat": {
"message": "Formato",
"description": "File format option"
},
"fileName": {
"message": "Nome",
"description": "File name option"
},
"language": {
"message": "Idioma",
"description": "Language selection"
},
"videoNotFound": {
"message": "Nenhum vídeo encontrado!",
"description": "Error when video is not found"
},
"captureSuccess": {
"message": "Frame capturado com sucesso!",
"description": "Success message after capturing a frame"
},
"thumbnailSuccess": {
"message": "Miniatura baixada com sucesso!",
"description": "Success message after downloading thumbnail"
},
"thumbnailError": {
"message": "Erro ao baixar miniatura",
"description": "Error message for thumbnail download"
},
"highQuality": {
"message": "Alta",
"description": "High quality option"
},
"mediumQuality": {
"message": "Média",
"description": "Medium quality option"
},
"lowQuality": {
"message": "Baixa",
"description": "Low quality option"
},
"saveSettings": {
"message": "Salvar",
"description": "Save settings button"
},
"resetSettings": {
"message": "Restaurar",
"description": "Reset settings button"
},
"copyBtn": {
"message": "Copiar",
"description": "Button to copy frame to clipboard"
},
"copySuccess": {
"message": "Frame copiado!",
"description": "Success message after copying a frame"
},
"showPreviewLabel": {
"message": "Mostrar Prévia",
"description": "Setting to toggle thumbnail preview"
},
"shortcutLabel": {
"message": "Atalho:",
"description": "Label for keyboard shortcut"
},
"changeShortcut": {
"message": "Alterar",
"description": "Button to change keyboard shortcut"
},
"shareText": {
"message": "Compartilhar",
"description": "Share button text"
},
"rateText": {
"message": "Avaliar",
"description": "Rate button text"
},
"toolsLabel": {
"message": "Ferramentas",
"description": "Tools section header"
},
"downloadThumbnail": {
"message": "Baixar Miniatura HD",
"description": "Button to download HD thumbnail"
},
"copied": {
"message": "Copiado! ✅",
"description": "Confirmation when text is copied"
},
"capturing": {
"message": "Capturando...",
"description": "Status while capturing"
},
"copying": {
"message": "Copiando...",
"description": "Status while copying"
},
"settingsSaved": {
"message": "Configurações salvas",
"description": "Confirmation when settings are saved"
},
"settingsReset": {
"message": "Configurações restauradas",
"description": "Confirmation when settings are reset"
},
"navigateToYouTube": {
"message": "Acesse uma página de vídeo do YouTube primeiro",
"description": "Error when not on YouTube"
},
"firefoxShortcutHelp": {
"message": "Para alterar atalhos no Firefox: Extensões (Ctrl+Shift+A) > Engrenagem > Gerenciar Atalhos",
"description": "Help text for Firefox shortcut change"
}
}
{
"appName": {
"message": "YouTube Frame Extractor",
"description": "The name of the extension"
},
"appDesc": {
"message": "Извлекайте качественные кадры из видео YouTube без элементов интерфейса (4K Screenshot)",
"description": "The description of the extension"
},
"captureBtn": {
"message": "Захватить",
"description": "Button to capture a frame"
},
"thumbnailBtn": {
"message": "Скачать превью",
"description": "Button to download video thumbnail"
},
"settings": {
"message": "Настройки",
"description": "Settings label"
},
"captureQuality": {
"message": "Качество",
"description": "Capture quality option"
},
"fileFormat": {
"message": "Формат",
"description": "File format option"
},
"fileName": {
"message": "Имя файла",
"description": "File name option"
},
"language": {
"message": "Язык",
"description": "Language selection"
},
"videoNotFound": {
"message": "Видео не найдено!",
"description": "Error when video is not found"
},
"captureSuccess": {
"message": "Кадр сохранён!",
"description": "Success message after capturing a frame"
},
"thumbnailSuccess": {
"message": "Превью скачано!",
"description": "Success message after downloading thumbnail"
},
"thumbnailError": {
"message": "Ошибка загрузки",
"description": "Error message for thumbnail download"
},
"highQuality": {
"message": "Высокое",
"description": "High quality option"
},
"mediumQuality": {
"message": "Среднее",
"description": "Medium quality option"
},
"lowQuality": {
"message": "Низкое",
"description": "Low quality option"
},
"saveSettings": {
"message": "Сохранить",
"description": "Save settings button"
},
"resetSettings": {
"message": "Сброс",
"description": "Reset settings button"
},
"copyBtn": {
"message": "Копировать",
"description": "Button to copy frame to clipboard"
},
"copySuccess": {
"message": "Скопировано!",
"description": "Success message after copying a frame"
},
"showPreviewLabel": {
"message": "Превью",
"description": "Setting to toggle thumbnail preview"
},
"shortcutLabel": {
"message": "Горячая клавиша:",
"description": "Label for keyboard shortcut"
},
"changeShortcut": {
"message": "Изменить",
"description": "Button to change keyboard shortcut"
},
"shareText": {
"message": "Поделиться",
"description": "Share button text"
},
"rateText": {
"message": "Оценить",
"description": "Rate button text"
},
"toolsLabel": {
"message": "Инструменты",
"description": "Tools section header"
},
"downloadThumbnail": {
"message": "Скачать HD превью",
"description": "Button to download HD thumbnail"
},
"copied": {
"message": "Скопировано! ✅",
"description": "Confirmation when text is copied"
},
"capturing": {
"message": "Захват...",
"description": "Status while capturing"
},
"copying": {
"message": "Копирование...",
"description": "Status while copying"
},
"settingsSaved": {
"message": "Настройки сохранены",
"description": "Confirmation when settings are saved"
},
"settingsReset": {
"message": "Настройки сброшены",
"description": "Confirmation when settings are reset"
},
"navigateToYouTube": {
"message": "Сначала откройте видео на YouTube",
"description": "Error when not on YouTube"
},
"firefoxShortcutHelp": {
"message": "Изменить горячие клавиши в Firefox: Дополнения (Ctrl+Shift+A) > Шестерёнка > Управление горячими клавишами",
"description": "Help text for Firefox shortcut change"
}
}
{
"appName": {
"message": "YouTube 帧提取器",
"description": "The name of the extension"
},
"appDesc": {
"message": "从YouTube视频中提取高清帧画面,无UI干扰 (4K Screenshot截图)",
"description": "The description of the extension"
},
"captureBtn": {
"message": "截取",
"description": "Button to capture a frame"
},
"thumbnailBtn": {
"message": "下载缩略图",
"description": "Button to download video thumbnail"
},
"settings": {
"message": "设置",
"description": "Settings label"
},
"captureQuality": {
"message": "画质",
"description": "Capture quality option"
},
"fileFormat": {
"message": "格式",
"description": "File format option"
},
"fileName": {
"message": "文件名",
"description": "File name option"
},
"language": {
"message": "语言",
"description": "Language selection"
},
"videoNotFound": {
"message": "未找到视频!",
"description": "Error when video is not found"
},
"captureSuccess": {
"message": "截取成功!",
"description": "Success message after capturing a frame"
},
"thumbnailSuccess": {
"message": "缩略图下载成功!",
"description": "Success message after downloading thumbnail"
},
"thumbnailError": {
"message": "下载失败",
"description": "Error message for thumbnail download"
},
"highQuality": {
"message": "高清",
"description": "High quality option"
},
"mediumQuality": {
"message": "标清",
"description": "Medium quality option"
},
"lowQuality": {
"message": "低清",
"description": "Low quality option"
},
"saveSettings": {
"message": "保存",
"description": "Save settings button"
},
"resetSettings": {
"message": "重置",
"description": "Reset settings button"
},
"copyBtn": {
"message": "复制",
"description": "Button to copy frame to clipboard"
},
"copySuccess": {
"message": "已复制到剪贴板!",
"description": "Success message after copying a frame"
},
"showPreviewLabel": {
"message": "显示预览",
"description": "Setting to toggle thumbnail preview"
},
"shortcutLabel": {
"message": "快捷键:",
"description": "Label for keyboard shortcut"
},
"changeShortcut": {
"message": "更改",
"description": "Button to change keyboard shortcut"
},
"shareText": {
"message": "分享",
"description": "Share button text"
},
"rateText": {
"message": "评价",
"description": "Rate button text"
},
"toolsLabel": {
"message": "工具",
"description": "Tools section header"
},
"downloadThumbnail": {
"message": "下载高清缩略图",
"description": "Button to download HD thumbnail"
},
"copied": {
"message": "已复制! ✅",
"description": "Confirmation when text is copied"
},
"capturing": {
"message": "截取中...",
"description": "Status while capturing"
},
"copying": {
"message": "复制中...",
"description": "Status while copying"
},
"settingsSaved": {
"message": "设置已保存",
"description": "Confirmation when settings are saved"
},
"settingsReset": {
"message": "设置已重置",
"description": "Confirmation when settings are reset"
},
"navigateToYouTube": {
"message": "请先打开YouTube视频页面",
"description": "Error when not on YouTube"
},
"firefoxShortcutHelp": {
"message": "Firefox快捷键设置: 附加组件 (Ctrl+Shift+A) > 齿轮图标 > 管理扩展快捷键",
"description": "Help text for Firefox shortcut change"
}
}
+62
-10

@@ -11,7 +11,7 @@ {

"captureBtn": {
"message": "📸 التقط الإطار",
"message": "التقط الإطار",
"description": "Button to capture a frame"
},
"thumbnailBtn": {
"message": "🖼️ تحميل الصورة المصغرة",
"message": "تحميل الصورة المصغرة",
"description": "Button to download video thumbnail"

@@ -24,7 +24,7 @@ },

"captureQuality": {
"message": "جودة الالتقاط",
"message": "الجودة",
"description": "Capture quality option"
},
"fileFormat": {
"message": "صيغة الملف",
"message": "الصيغة",
"description": "File format option"

@@ -57,23 +57,23 @@ },

"highQuality": {
"message": "جودة عالية",
"message": "عالية",
"description": "High quality option"
},
"mediumQuality": {
"message": "جودة متوسطة",
"message": "متوسطة",
"description": "Medium quality option"
},
"lowQuality": {
"message": "جودة منخفضة",
"message": "منخفضة",
"description": "Low quality option"
},
"saveSettings": {
"message": "حفظ الإعدادات",
"message": "حفظ",
"description": "Save settings button"
},
"resetSettings": {
"message": "إعادة للإعدادات الافتراضية",
"message": "إعادة تعيين",
"description": "Reset settings button"
},
"copyBtn": {
"message": "📋 نسخ للحافظة",
"message": "نسخ للحافظة",
"description": "Button to copy frame to clipboard"

@@ -88,3 +88,55 @@ },

"description": "Setting to toggle thumbnail preview"
},
"shortcutLabel": {
"message": "الاختصار:",
"description": "Label for keyboard shortcut"
},
"changeShortcut": {
"message": "تغيير",
"description": "Button to change keyboard shortcut"
},
"shareText": {
"message": "انشر التطبيق",
"description": "Share button text"
},
"rateText": {
"message": "قيمنا",
"description": "Rate button text"
},
"toolsLabel": {
"message": "الأدوات والإعدادات",
"description": "Tools section header"
},
"downloadThumbnail": {
"message": "تحميل الصورة المصغرة",
"description": "Button to download HD thumbnail"
},
"copied": {
"message": "تم النسخ! ✅",
"description": "Confirmation when text is copied"
},
"capturing": {
"message": "جاري الالتقاط...",
"description": "Status while capturing"
},
"copying": {
"message": "جاري النسخ...",
"description": "Status while copying"
},
"settingsSaved": {
"message": "تم حفظ الإعدادات",
"description": "Confirmation when settings are saved"
},
"settingsReset": {
"message": "تم إعادة الإعدادات للوضع الافتراضي",
"description": "Confirmation when settings are reset"
},
"navigateToYouTube": {
"message": "يرجى الانتقال إلى صفحة فيديو YouTube أولاً",
"description": "Error when not on YouTube"
},
"firefoxShortcutHelp": {
"message": "لتغيير الاختصارات في فايرفوكس: اذهب إلى الإضافات (Ctrl+Shift+A) > أيقونة الترس > إدارة اختصارات الإضافات",
"description": "Help text for Firefox shortcut change"
}
}

@@ -11,7 +11,7 @@ {

"captureBtn": {
"message": "📸 Capture Frame",
"message": "Capture Frame",
"description": "Button to capture a frame"
},
"thumbnailBtn": {
"message": "🖼️ Download Thumbnail",
"message": "Download Thumbnail",
"description": "Button to download video thumbnail"

@@ -24,11 +24,11 @@ },

"captureQuality": {
"message": "Capture Quality",
"message": "Quality",
"description": "Capture quality option"
},
"fileFormat": {
"message": "File Format",
"message": "Format",
"description": "File format option"
},
"fileName": {
"message": "File Name",
"message": "Filename",
"description": "File name option"

@@ -57,23 +57,23 @@ },

"highQuality": {
"message": "High Quality",
"message": "High",
"description": "High quality option"
},
"mediumQuality": {
"message": "Medium Quality",
"message": "Medium",
"description": "Medium quality option"
},
"lowQuality": {
"message": "Low Quality",
"message": "Low",
"description": "Low quality option"
},
"saveSettings": {
"message": "Save Settings",
"message": "Save",
"description": "Save settings button"
},
"resetSettings": {
"message": "Reset to Default",
"message": "Reset",
"description": "Reset settings button"
},
"copyBtn": {
"message": "📋 Copy to Clipboard",
"message": "Copy to Clipboard",
"description": "Button to copy frame to clipboard"

@@ -88,3 +88,55 @@ },

"description": "Setting to toggle thumbnail preview"
},
"shortcutLabel": {
"message": "Shortcut:",
"description": "Label for keyboard shortcut"
},
"changeShortcut": {
"message": "Change",
"description": "Button to change keyboard shortcut"
},
"shareText": {
"message": "Spread the Word",
"description": "Share button text"
},
"rateText": {
"message": "Rate Us",
"description": "Rate button text"
},
"toolsLabel": {
"message": "Tools & Settings",
"description": "Tools section header"
},
"downloadThumbnail": {
"message": "Download HD Thumbnail",
"description": "Button to download HD thumbnail"
},
"copied": {
"message": "Copied! ✅",
"description": "Confirmation when text is copied"
},
"capturing": {
"message": "Capturing...",
"description": "Status while capturing"
},
"copying": {
"message": "Copying...",
"description": "Status while copying"
},
"settingsSaved": {
"message": "Settings saved",
"description": "Confirmation when settings are saved"
},
"settingsReset": {
"message": "Settings reset to default",
"description": "Confirmation when settings are reset"
},
"navigateToYouTube": {
"message": "Please navigate to a YouTube video page first",
"description": "Error when not on YouTube"
},
"firefoxShortcutHelp": {
"message": "To change shortcuts in Firefox: Go to Add-ons (Ctrl+Shift+A) > Gear Icon > Manage Extension Shortcuts",
"description": "Help text for Firefox shortcut change"
}
}
+22
-23

@@ -25,3 +25,3 @@ /* @@package_name - v@@version - @@timestamp */

// JSON file.
const apiMetadata = {/* include("api-metadata.json") */};
const apiMetadata = {/* include("api-metadata.json") */ };

@@ -104,3 +104,3 @@ if (Object.keys(apiMetadata).length === 0) {

} else if (metadata.singleCallbackArg ||
(callbackArgs.length <= 1 && metadata.singleCallbackArg !== false)) {
(callbackArgs.length <= 1 && metadata.singleCallbackArg !== false)) {
promise.resolve(callbackArgs[0]);

@@ -157,6 +157,6 @@ } else {

try {
target[name](...args, makeCallback({resolve, reject}, metadata));
target[name](...args, makeCallback({ resolve, reject }, metadata));
} catch (cbError) {
console.warn(`${name} API method doesn't seem to support the callback parameter, ` +
"falling back to call it without a callback: ", cbError);
"falling back to call it without a callback: ", cbError);

@@ -176,3 +176,3 @@ target[name](...args);

} else {
target[name](...args, makeCallback({resolve, reject}, metadata));
target[name](...args, makeCallback({ resolve, reject }, metadata));
}

@@ -271,4 +271,4 @@ });

} else if (typeof value === "object" && value !== null &&
(hasOwnProperty(wrappers, prop) ||
hasOwnProperty(metadata, prop))) {
(hasOwnProperty(wrappers, prop) ||
hasOwnProperty(metadata, prop))) {
// This is an object that we need to do some wrapping for the children

@@ -415,3 +415,3 @@ // of. Create a sub-object wrapper for it with the appropriate child

let sendResponsePromise = new Promise(resolve => {
wrappedSendResponse = function(response) {
wrappedSendResponse = function (response) {
didCallSendResponse = true;

@@ -451,3 +451,3 @@ resolve(response);

if (error && (error instanceof Error ||
typeof error.message === "string")) {
typeof error.message === "string")) {
message = error.message;

@@ -482,3 +482,3 @@ } else {

const wrappedSendMessageCallback = ({reject, resolve}, reply) => {
const wrappedSendMessageCallback = ({ reject, resolve }, reply) => {
if (extensionAPIs.runtime.lastError) {

@@ -512,3 +512,3 @@ // Detect when none of the listeners replied to the sendMessage call and resolve

return new Promise((resolve, reject) => {
const wrappedCb = wrappedSendMessageCallback.bind(null, {resolve, reject});
const wrappedCb = wrappedSendMessageCallback.bind(null, { resolve, reject });
args.push(wrappedCb);

@@ -528,17 +528,17 @@ apiNamespaceObj.sendMessage(...args);

onMessageExternal: wrapEvent(onMessageWrappers),
sendMessage: wrappedSendMessage.bind(null, "sendMessage", {minArgs: 1, maxArgs: 3}),
sendMessage: wrappedSendMessage.bind(null, "sendMessage", { minArgs: 1, maxArgs: 3 }),
},
tabs: {
sendMessage: wrappedSendMessage.bind(null, "sendMessage", {minArgs: 2, maxArgs: 3}),
sendMessage: wrappedSendMessage.bind(null, "sendMessage", { minArgs: 2, maxArgs: 3 }),
},
};
const settingMetadata = {
clear: {minArgs: 1, maxArgs: 1},
get: {minArgs: 1, maxArgs: 1},
set: {minArgs: 1, maxArgs: 1},
clear: { minArgs: 1, maxArgs: 1 },
get: { minArgs: 1, maxArgs: 1 },
set: { minArgs: 1, maxArgs: 1 },
};
apiMetadata.privacy = {
network: {"*": settingMetadata},
services: {"*": settingMetadata},
websites: {"*": settingMetadata},
network: { "*": settingMetadata },
services: { "*": settingMetadata },
websites: { "*": settingMetadata },
};

@@ -549,7 +549,6 @@

// The build process adds a UMD wrapper around this file, which makes the
// `module` variable available.
module.exports = wrapAPIs(chrome);
// Assign the wrapped API to globalThis.browser for use in the extension
globalThis.browser = wrapAPIs(chrome);
} else {
module.exports = globalThis.browser;
// Firefox already has globalThis.browser, no action needed
}
{
"manifest_version": 2,
"name": "YouTube Screenshot Tool",
"version": "1.2.6",
"version": "1.2.9",
"description": "Extract high-quality frames from YouTube videos without UI elements",

@@ -6,0 +6,0 @@ "default_locale": "en",

@@ -9,3 +9,5 @@ <!DOCTYPE html>

<link rel="stylesheet" href="../css/popup.css">
<script src="../lib/browser-polyfill.js"></script>
</head>

@@ -19,8 +21,5 @@

</div>
<div class="language-selector">
<button id="en-btn" class="language-btn active" data-lang="en">EN</button>
<button id="ar-btn" class="language-btn" data-lang="ar">عربي</button>
</div>
</div>
<!-- Main Action Section -->

@@ -65,2 +64,3 @@ <div class="hero-section action-buttons-grid">

<div class="thumbnail-tool-container">

@@ -79,2 +79,3 @@ <div class="form-group" style="margin-bottom: 8px;">

</div>

@@ -113,2 +114,3 @@ <div class="settings-toggle-container">

<div class="form-group" style="display: flex; align-items: center; gap: 8px;">

@@ -118,2 +120,3 @@ <input type="checkbox" id="showThumbnailPreview" style="width: auto;">

</div>

@@ -120,0 +123,0 @@ <div class="action-buttons">

@@ -59,5 +59,6 @@ // YouTube Screenshot Tool - Background Script

cta: 'Rate Now ⭐',
// @firefox-only-start
ctaUrl: 'https://addons.mozilla.org/en-US/firefox/addon/youtube-frame-extractor/'
// @firefox-only-end
// Runtime detection for browser-specific URL
ctaUrl: isBrowser
? 'https://addons.mozilla.org/en-US/firefox/addon/youtube-frame-extractor/'
: 'https://chromewebstore.google.com/detail/youtube-screenshot-tool/jgglipjcahbknbghcandjkoahlegcdkd'
},

@@ -68,3 +69,3 @@ 50: {

cta: 'Share on X',
ctaUrl: 'https://twitter.com/intent/tweet?text=I%20just%20captured%2050%20screenshots%20with%20YouTube%20Screenshot%20Tool!%20%F0%9F%9A%80'
ctaUrl: 'https://x.com/intent/tweet?text=I%20just%20captured%2050%20screenshots%20with%20YouTube%20Screenshot%20Tool!%20%F0%9F%9A%80'
},

@@ -173,8 +174,12 @@ 100: {

// Inject script
// Inject script - only include polyfill for Firefox
const browserScripting = isBrowser ? browser.scripting : chrome.scripting;
if (browserScripting) {
const filesToInject = isBrowser
? ['lib/browser-polyfill.js', 'scripts/content.js']
: ['scripts/content.js'];
await browserScripting.executeScript({
target: { tabId: tab.id },
files: ['lib/browser-polyfill.js', 'scripts/content.js']
files: filesToInject
});

@@ -181,0 +186,0 @@

@@ -520,5 +520,13 @@ /**

}).catch(err => {
sendResponse(err.toString());
sendResponse({ success: false, error: err.toString() });
});
return true;
} else if (message.action === 'trackCapture') {
// Track screenshot capture for gamification (called by popup after clipboard copy)
trackScreenshotCapture().then(() => {
sendResponse(true);
}).catch(() => {
sendResponse(false);
});
return true;
} else if (message.action === 'ping' || message.action === 'injected_check') {

@@ -626,5 +634,8 @@ // Respond to ping or injected_check message to confirm content script is loaded

/**
* Captures a frame and copies it to the clipboard
* Captures a frame and returns the dataURL for clipboard copy
* For Chrome: Returns dataURL so popup can handle clipboard (has user gesture)
* For Firefox: Tries clipboard API directly
*
* @param {Object} settings - The capture settings
* @returns {Promise<boolean|string>} - True on success, error message on failure
* @returns {Promise<{success: boolean, dataUrl?: string, error?: string}>}
*/

@@ -638,3 +649,3 @@ async function copyFrame(settings) {

if (!video) {
return messages[lang].videoNotFound;
return { success: false, error: messages[lang].videoNotFound };
}

@@ -653,19 +664,33 @@

const blob = await new Promise(resolve => canvas.toBlob(resolve, 'image/png'));
// Convert to dataURL for transfer to popup
const dataUrl = canvas.toDataURL('image/png');
if (!blob) {
throw new Error('Failed to create image blob');
if (!dataUrl || dataUrl === 'data:,') {
throw new Error('Failed to capture frame - canvas is empty');
}
const data = [new ClipboardItem({ 'image/png': blob })];
await navigator.clipboard.write(data);
// For Firefox, try clipboard API directly (it may work in content script)
if (typeof browser !== 'undefined') {
try {
const blob = await new Promise(resolve => canvas.toBlob(resolve, 'image/png'));
if (blob) {
const data = [new ClipboardItem({ 'image/png': blob })];
await navigator.clipboard.write(data);
// Track successful capture for gamification
trackScreenshotCapture();
return { success: true, copiedInContentScript: true };
}
} catch (firefoxClipboardError) {
console.log('Firefox clipboard API failed, falling back to popup:', firefoxClipboardError);
}
}
// Track successful capture for gamification
trackScreenshotCapture();
// For Chrome (and Firefox fallback): Return dataURL for popup to handle
// The popup has user gesture context and can use Clipboard API
return { success: true, dataUrl: dataUrl, needsPopupCopy: true };
return true;
} catch (error) {
console.error('Copy frame error:', error);
return error.toString();
return { success: false, error: error.toString() };
}
}

@@ -7,4 +7,6 @@ // YouTube Screenshot Tool - Popup Script

// Store URL (Placeholder - Update with actual store link)
const STORE_URL = "https://addons.mozilla.org/en-US/firefox/addon/youtube-frame-extractor/"; // Update this!
// Store URL - Runtime detection for Chrome vs Firefox
const STORE_URL = isBrowser
? "https://addons.mozilla.org/en-US/firefox/addon/youtube-frame-extractor/"
: "https://chromewebstore.google.com/detail/youtube-screenshot-tool/jgglipjcahbknbghcandjkoahlegcdkd";

@@ -16,6 +18,11 @@ // Default settings

filename: 'youtube_frame',
language: 'en',
showThumbnailPreview: false
};
// Helper: Get i18n message with fallback
function getMessage(key, fallback = '') {
const msg = browserAPI.i18n.getMessage(key);
return msg || fallback || key;
}
// Elements

@@ -33,3 +40,2 @@ const captureBtn = document.getElementById('capture');

const statusMessage = document.getElementById('statusMessage');
const languageBtns = document.querySelectorAll('.language-btn');
const highQualityOption = document.getElementById('highQualityOption');

@@ -41,60 +47,2 @@ const mediumQualityOption = document.getElementById('mediumQualityOption');

// Messages cache
const messagesCache = {
en: {},
ar: {}
};
// Fallback messages
const fallbackMessages = {
en: {
captureBtn: "📸 Capture Frame",
settings: "Settings",
captureQuality: "Quality",
fileFormat: "Format",
fileName: "Filename",
highQuality: "High",
mediumQuality: "Medium",
lowQuality: "Low",
saveSettings: "Save",
resetSettings: "Reset",
captureSuccess: "Frame captured successfully!",
shortcutLabel: "Shortcut:",
changeShortcut: "Change",
shareText: "Spread the Word",
rateText: "Rate Us",
toolsLabel: "Tools & Settings",
downloadThumbnail: "Download HD Thumbnail",
showPreviewLabel: "Show Thumbnail Preview",
copyBtn: "📋 Copy to Clipboard",
copySuccess: "Frame copied to clipboard!",
shareMessage: "I'm loving this YouTube Screenshot Tool! It helps me extract high-quality frames. Try it: " + STORE_URL,
copied: "Copied! ✅"
},
ar: {
captureBtn: "📸 التقط الإطار",
settings: "الإعدادات",
captureQuality: "الجودة",
fileFormat: "الصيغة",
fileName: "اسم الملف",
highQuality: "عالية",
mediumQuality: "متوسطة",
lowQuality: "منخفضة",
saveSettings: "حفظ",
resetSettings: "إعادة تعيين",
captureSuccess: "تم التقاط الإطار بنجاح!",
shortcutLabel: "الاختصار:",
changeShortcut: "تغيير",
shareText: "انشر التطبيق",
rateText: "قيمنا",
toolsLabel: "الأدوات والإعدادات",
downloadThumbnail: "تحميل الصورة المصغرة",
showPreviewLabel: "تفعيل معاينة الصورة",
copyBtn: "📋 نسخ للحافظة",
copySuccess: "تم نسخ الإطار للحافظة!",
shareMessage: "أداة رائعة لالتقاط الصور من يوتيوب بجودة عالية! جربها: " + STORE_URL,
copied: "تم النسخ! ✅"
}
};
// Initialize Popup

@@ -113,12 +61,4 @@ document.addEventListener('DOMContentLoaded', async () => {

// Set language
const currentLang = settings.language || 'en';
languageBtns.forEach(btn => {
if (btn.dataset.lang === currentLang) {
btn.classList.add('active');
} else {
btn.classList.remove('active');
}
});
await setLanguage(currentLang);
// Apply i18n to UI
applyLocalization();

@@ -135,2 +75,52 @@ // Hide settings initially

// Apply localization to all UI elements
function applyLocalization() {
// Detect RTL languages (Arabic, Hebrew, etc.)
const uiLang = browserAPI.i18n.getUILanguage();
if (uiLang.startsWith('ar') || uiLang.startsWith('he') || uiLang.startsWith('fa')) {
document.body.classList.add('rtl');
document.documentElement.setAttribute('lang', uiLang.substring(0, 2));
document.documentElement.setAttribute('dir', 'rtl');
}
// Update text elements
const elements = {
'qualityLabel': getMessage('captureQuality', 'Quality'),
'formatLabel': getMessage('fileFormat', 'Format'),
'filenameLabel': getMessage('fileName', 'Filename'),
'saveSettings': getMessage('saveSettings', 'Save'),
'resetSettings': getMessage('resetSettings', 'Reset'),
'highQualityOption': getMessage('highQuality', 'High'),
'mediumQualityOption': getMessage('mediumQuality', 'Medium'),
'lowQualityOption': getMessage('lowQuality', 'Low'),
'shortcutLabel': getMessage('shortcutLabel', 'Shortcut:'),
'changeShortcut': getMessage('changeShortcut', 'Change'),
'toolsLabel': getMessage('toolsLabel', 'Tools & Settings'),
'showPreviewLabel': getMessage('showPreviewLabel', 'Show Thumbnail Preview')
};
for (const [id, text] of Object.entries(elements)) {
const element = document.getElementById(id);
if (element) element.textContent = text;
}
// Update buttons with icons
if (captureBtn) {
captureBtn.querySelector('.btn-text').textContent = getMessage('captureBtn', 'Capture Frame');
}
if (shareBtn) {
shareBtn.querySelector('.btn-text').textContent = getMessage('shareText', 'Spread the Word');
}
if (copyFrameBtn) {
copyFrameBtn.querySelector('.btn-text').textContent = getMessage('copyBtn', 'Copy to Clipboard');
}
if (rateBtn) {
rateBtn.querySelector('.btn-text').textContent = getMessage('rateText', 'Rate Us');
}
const downloadThumbnailBtn = document.getElementById('downloadThumbnail');
if (downloadThumbnailBtn) {
downloadThumbnailBtn.querySelector('.btn-text').textContent = getMessage('downloadThumbnail', 'Download HD Thumbnail');
}
}
// Initialize Thumbnail Tool

@@ -164,3 +154,3 @@ async function initThumbnailTool() {

} else {
showStatus('Could not extract video ID', 'error');
showStatus(getMessage('thumbnailError', 'Could not extract video ID'), 'error');
}

@@ -233,18 +223,4 @@ });

if (navigator.userAgent.toLowerCase().includes('firefox')) {
const currentLang = document.querySelector('.language-btn.active').dataset.lang || 'en';
const messages = {
en: "To change shortcuts in Firefox: Go to Add-ons (Ctrl+Shift+A) > Gear Icon > Manage Extension Shortcuts",
ar: "لتغيير الاختصارات في فايرفوكس: اذهب إلى الإضافات (Ctrl+Shift+A) > أيقونة الترس > إدارة اختصارات الإضافات"
};
// Show message with longer duration for readability
const statusElement = document.getElementById('statusMessage');
if (statusElement) {
statusElement.textContent = messages[currentLang];
statusElement.className = 'status-message info';
statusElement.style.display = 'block';
setTimeout(() => {
statusElement.style.display = 'none';
}, 8000); // 8 seconds to read
}
const helpText = getMessage('firefoxShortcutHelp', 'To change shortcuts in Firefox: Go to Add-ons (Ctrl+Shift+A) > Gear Icon > Manage Extension Shortcuts');
showStatus(helpText, 'info', 8000);
} else {

@@ -259,7 +235,6 @@ browserAPI.tabs.create({ url: 'chrome://extensions/shortcuts' });

shareBtn.addEventListener('click', async () => {
const lang = document.querySelector('.language-btn.active').dataset.lang || 'en';
const message = fallbackMessages[lang].shareMessage;
const shareMessage = `I'm loving this YouTube Screenshot Tool! It helps me extract high-quality frames. Try it: ${STORE_URL}`;
try {
await navigator.clipboard.writeText(message);
await navigator.clipboard.writeText(shareMessage);

@@ -270,3 +245,3 @@ // Visual feedback

shareBtn.querySelector('.btn-text').textContent = fallbackMessages[lang].copied;
shareBtn.querySelector('.btn-text').textContent = getMessage('copied', 'Copied! ✅');
shareBtn.querySelector('.btn-icon').textContent = "✅";

@@ -299,3 +274,3 @@ shareBtn.classList.add('success');

const settings = await loadSettings();
showStatus('Capturing...', 'info');
showStatus(getMessage('capturing', 'Capturing...'), 'info');

@@ -319,8 +294,3 @@ try {

} else {
const currentLang = document.querySelector('.language-btn.active').dataset.lang || 'en';
const messages = {
en: 'Please navigate to a YouTube video page first',
ar: 'يرجى الانتقال إلى صفحة فيديو YouTube أولاً'
};
showStatus(messages[currentLang], 'error');
showStatus(getMessage('navigateToYouTube', 'Please navigate to a YouTube video page first'), 'error');
}

@@ -337,3 +307,3 @@ } catch (error) {

const settings = await loadSettings();
showStatus('Copying...', 'info');
showStatus(getMessage('copying', 'Copying...'), 'info');

@@ -357,8 +327,3 @@ try {

} else {
const currentLang = document.querySelector('.language-btn.active').dataset.lang || 'en';
const messages = {
en: 'Please navigate to a YouTube video page first',
ar: 'يرجى الانتقال إلى صفحة فيديو YouTube أولاً'
};
showStatus(messages[currentLang], 'error');
showStatus(getMessage('navigateToYouTube', 'Please navigate to a YouTube video page first'), 'error');
}

@@ -379,5 +344,39 @@ } catch (error) {

if (response === true) {
const successMsg = getMessage('copySuccess');
showStatus(successMsg, 'success');
// Handle new response format: { success, dataUrl, error, copiedInContentScript, needsPopupCopy }
if (response && response.success) {
// If content script already copied (Firefox), just show success
if (response.copiedInContentScript) {
showStatus(getMessage('copySuccess', 'Frame copied to clipboard!'), 'success');
return;
}
// For Chrome: content script returns dataURL, popup handles clipboard
if (response.needsPopupCopy && response.dataUrl) {
try {
// Convert dataURL to blob
const fetchResponse = await fetch(response.dataUrl);
const blob = await fetchResponse.blob();
// Write to clipboard (popup has user gesture context!)
const clipboardItem = new ClipboardItem({ 'image/png': blob });
await navigator.clipboard.write([clipboardItem]);
showStatus(getMessage('copySuccess', 'Frame copied to clipboard!'), 'success');
// Notify content script to track gamification
sendMessageToTab(tabId, { action: 'trackCapture' }).catch(() => { });
} catch (clipboardError) {
console.error('Popup clipboard write failed:', clipboardError);
showStatus('Error: Failed to copy to clipboard - ' + clipboardError.message, 'error');
}
return;
}
// Legacy format (response === true)
showStatus(getMessage('copySuccess', 'Frame copied to clipboard!'), 'success');
} else if (response && response.error) {
showStatus('Error: ' + response.error, 'error');
} else if (response === true) {
// Legacy format support
showStatus(getMessage('copySuccess', 'Frame copied to clipboard!'), 'success');
} else {

@@ -396,5 +395,10 @@ showStatus('Error: ' + (response || 'Unknown error'), 'error');

if (browserScripting) {
// Only inject browser-polyfill.js for Firefox
const filesToInject = isBrowser
? ['lib/browser-polyfill.js', 'scripts/content.js']
: ['scripts/content.js'];
await browserScripting.executeScript({
target: { tabId: tabId },
files: ['lib/browser-polyfill.js', 'scripts/content.js']
files: filesToInject
});

@@ -420,4 +424,3 @@ } else {

if (response === true) {
const successMsg = getMessage('captureSuccess');
showStatus(successMsg, 'success');
showStatus(getMessage('captureSuccess', 'Frame captured successfully!'), 'success');
} else {

@@ -458,8 +461,7 @@ showStatus('Error: ' + (response || 'Unknown error'), 'error');

filename: filenameInput.value,
language: document.querySelector('.language-btn.active').dataset.lang,
showThumbnailPreview: showPreviewToggle.checked
showThumbnailPreview: showPreviewToggle ? showPreviewToggle.checked : false
};
await saveSettings(settings);
showStatus('Settings saved', 'success');
showStatus(getMessage('settingsSaved', 'Settings saved'), 'success');
});

@@ -477,33 +479,8 @@ }

filenameInput.value = DEFAULT_SETTINGS.filename;
showPreviewToggle.checked = DEFAULT_SETTINGS.showThumbnailPreview;
if (showPreviewToggle) showPreviewToggle.checked = DEFAULT_SETTINGS.showThumbnailPreview;
// Update language
const lang = DEFAULT_SETTINGS.language;
languageBtns.forEach(btn => {
if (btn.dataset.lang === lang) {
btn.classList.add('active');
} else {
btn.classList.remove('active');
}
});
await setLanguage(lang);
showStatus('Settings reset to default', 'success');
showStatus(getMessage('settingsReset', 'Settings reset to default'), 'success');
});
}
// Language buttons
languageBtns.forEach(btn => {
btn.addEventListener('click', async () => {
const lang = btn.dataset.lang;
languageBtns.forEach(b => b.classList.remove('active'));
btn.classList.add('active');
const settings = await loadSettings();
settings.language = lang;
await saveSettings(settings);
await setLanguage(lang);
});
});
// Helper: Load Settings

@@ -529,99 +506,4 @@ async function loadSettings() {

// Helper: Get Message
function getMessage(messageName) {
const lang = document.querySelector('.language-btn.active').dataset.lang || 'en';
if (messagesCache[lang] && messagesCache[lang][messageName]) {
return messagesCache[lang][messageName];
}
let message = browserAPI.i18n.getMessage(messageName);
if (!message && fallbackMessages[lang] && fallbackMessages[lang][messageName]) {
message = fallbackMessages[lang][messageName];
}
if (!messagesCache[lang]) messagesCache[lang] = {};
messagesCache[lang][messageName] = message || messageName;
return message || messageName;
}
// Helper: Set Language
function setLanguage(lang) {
document.querySelectorAll('.language-btn').forEach(btn => {
if (btn.dataset.lang === lang) btn.classList.add('active');
else btn.classList.remove('active');
});
if (lang === 'ar') {
document.body.classList.add('rtl');
document.documentElement.setAttribute('lang', 'ar');
} else {
document.body.classList.remove('rtl');
document.documentElement.setAttribute('lang', 'en');
}
// Update text content for static elements
const elements = {
'settingsLabel': fallbackMessages[lang].settings,
'qualityLabel': fallbackMessages[lang].captureQuality,
'formatLabel': fallbackMessages[lang].fileFormat,
'filenameLabel': fallbackMessages[lang].fileName,
'saveSettings': fallbackMessages[lang].saveSettings,
'resetSettings': fallbackMessages[lang].resetSettings,
'highQualityOption': fallbackMessages[lang].highQuality,
'mediumQualityOption': fallbackMessages[lang].mediumQuality,
'lowQualityOption': fallbackMessages[lang].lowQuality,
'shortcutLabel': fallbackMessages[lang].shortcutLabel,
'changeShortcut': fallbackMessages[lang].changeShortcut,
'toolsLabel': fallbackMessages[lang].toolsLabel,
'showPreviewLabel': fallbackMessages[lang].showPreviewLabel
};
for (const [id, text] of Object.entries(elements)) {
const element = document.getElementById(id);
if (element) element.textContent = text;
}
// Update buttons with icons specially
if (captureBtn) {
captureBtn.querySelector('.btn-text').textContent = fallbackMessages[lang].captureBtn.replace("📸 ", "");
}
if (shareBtn) {
shareBtn.querySelector('.btn-text').textContent = fallbackMessages[lang].shareText;
}
if (copyFrameBtn) {
copyFrameBtn.querySelector('.btn-text').textContent = fallbackMessages[lang].copyBtn.replace("📋 ", "");
}
if (rateBtn) {
rateBtn.querySelector('.btn-text').textContent = fallbackMessages[lang].rateText;
}
if (document.getElementById('downloadThumbnail')) {
document.getElementById('downloadThumbnail').querySelector('.btn-text').textContent = fallbackMessages[lang].downloadThumbnail;
}
}
// Helper: Show Status
function showStatus(message, type) {
const currentLang = document.querySelector('.language-btn.active').dataset.lang || 'en';
const commonMessages = {
en: {
'Capturing...': 'Capturing...',
'Settings saved': 'Settings saved',
'Settings reset to default': 'Settings reset to default',
'Failed to copy to clipboard': 'Failed to copy to clipboard'
},
ar: {
'Capturing...': 'جاري الالتقاط...',
'Settings saved': 'تم حفظ الإعدادات',
'Settings reset to default': 'تم إعادة الإعدادات للوضع الافتراضي',
'Failed to copy to clipboard': 'فشل نسخ النص',
'Copying...': 'جاري النسخ...'
}
};
if (commonMessages[currentLang][message]) {
message = commonMessages[currentLang][message];
}
function showStatus(message, type, duration = 3000) {
statusMessage.textContent = message;

@@ -633,3 +515,3 @@ statusMessage.className = 'status-message ' + type;

statusMessage.style.display = 'none';
}, 3000);
}, duration);
}
# YouTube Frame Extractor
<div align="center">
<img src="assets/icons/icon128.png" alt="YouTube Frame Extractor Logo" width="120">
<br>
<p>
<b>Extract high-quality frames from YouTube videos without UI elements</b>
</p>
<p>
<b>استخراج إطارات عالية الجودة من فيديوهات يوتيوب بدون عناصر واجهة المستخدم</b>
</p>
</div>
## 📝 Description | الوصف
YouTube Frame Extractor is a browser extension for Chromium-based browsers (Chrome, Brave, Edge) that allows users to capture clean, high-quality frames directly from YouTube videos without any UI elements such as:
- Video progress bar
- Video title
- Control buttons
- Comments or suggestions
The goal is to get a perfectly clean image from the video as if it was taken from the original production files.
*مستخرج إطارات يوتيوب هو إضافة لمتصفحات كروميوم (كروم، بريف، إيدج) تتيح للمستخدمين التقاط إطارات نظيفة وعالية الجودة مباشرة من فيديوهات يوتيوب بدون أي عناصر واجهة مثل:*
- *شريط تقدم الفيديو*
- *عنوان الفيديو*
- *أزرار التحكم*
- *التعليقات أو الاقتراحات*
*الهدف هو الحصول على صورة نظيفة تمامًا من الفيديو كما لو كانت مأخوذة من ملفات الإنتاج الأصلية.*
## 🌟 Features | المميزات
- 🖼️ Extract frames in their original video quality
- 📷 Download video thumbnails in highest available quality
- 🔄 Multiple export formats (PNG, JPEG, WebP)
- 📊 Quality control options
- 🔤 Multilingual support (English and Arabic)
- 🌓 Dark/Light mode support
- 📋 Custom filename options
- 📱 Responsive design
- 💾 Settings are saved between sessions
*- استخراج إطارات بجودتها الأصلية*
*- تحميل الصور المصغرة للفيديوهات بأعلى جودة متاحة*
*- صيغ تصدير متعددة (PNG, JPEG, WebP)*
*- خيارات التحكم في الجودة*
*- دعم متعدد اللغات (الإنجليزية والعربية)*
*- دعم الوضع المظلم/الفاتح*
*- خيارات تخصيص اسم الملف*
*- تصميم متجاوب*
*- حفظ الإعدادات بين الجلسات*
## ⚙️ How It Works | كيف تعمل الإضافة
### Frame Capture | التقاط الإطار
1. Navigate to a YouTube video
2. Click the extension icon
3. Click "Capture Frame" button
4. The frame is saved automatically with video title and timestamp
*1. انتقل إلى فيديو يوتيوب*
*2. انقر على أيقونة الإضافة*
*3. انقر على زر "التقط الإطار"*
*4. يتم حفظ الإطار تلقائيًا باسم الفيديو والتوقيت*
### Thumbnail Download | تحميل الصورة المصغرة
1. Navigate to a YouTube video
2. Click the extension icon
3. Click "Download Thumbnail" button
4. The highest quality thumbnail is saved with the video title
*1. انتقل إلى فيديو يوتيوب*
*2. انقر على أيقونة الإضافة*
*3. انقر على زر "تحميل الصورة المصغرة"*
*4. يتم حفظ الصورة المصغرة بأعلى جودة متاحة باسم الفيديو*
## 🛠️ Technical Details | التفاصيل التقنية
This extension is built using:
- Modern JavaScript
- Chrome Extension APIs
- HTML5 Canvas API
- Manifest V3 specification
*تم بناء هذه الإضافة باستخدام:*
*- جافاسكريبت الحديثة*
*- واجهات برمجة تطبيقات كروم*
*- واجهة برمجة تطبيقات HTML5 Canvas*
*- مواصفات Manifest V3*
### Security & Privacy | الأمان والخصوصية
This extension:
- Does not collect any user data
- Does not send any information to remote servers
- Only accesses the active YouTube tab when the user explicitly activates it
- Does not use any third-party libraries or services
- Does not circumvent any content protection mechanisms
*هذه الإضافة:*
*- لا تجمع أي بيانات المستخدم*
*- لا ترسل أي معلومات إلى خوادم خارجية*
*- تصل فقط إلى علامة تبويب يوتيوب النشطة عند تفعيلها من قبل المستخدم*
*- لا تستخدم أي مكتبات أو خدمات خارجية*
*- لا تتجاوز أي آليات حماية المحتوى*
## 🔧 Installation | التثبيت
### From Chrome Web Store | من متجر كروم
1. Visit the Chrome Web Store
2. Search for "YouTube Frame Extractor"
3. Click "Add to Chrome"
*1. قم بزيارة متجر كروم*
*2. ابحث عن "YouTube Frame Extractor"*
*3. انقر على "إضافة إلى كروم"*
### Manual Installation | التثبيت اليدوي
1. Download or clone this repository
2. Open Chrome/Brave/Edge and navigate to `chrome://extensions/`
3. Enable "Developer Mode"
4. Click "Load unpacked"
5. Select the extension folder
*1. قم بتنزيل أو استنساخ هذا المستودع*
*2. افتح كروم/بريف/إيدج وانتقل إلى `chrome://extensions/`*
*3. فعّل "وضع المطوّر"*
*4. انقر على "تحميل غير مضغوط"*
*5. اختر مجلد الإضافة*
## 🚀 Future Enhancements | التحسينات المستقبلية
- 🎬 Frame-by-frame navigation
- 📹 Support for more video platforms (Vimeo, Twitch, etc.)
- 📸 Burst mode for capturing multiple frames
- 📊 Auto-capture at specified intervals
- 🖌️ Basic image editing tools
- 🌐 More language options
*- التنقل إطارًا بإطار*
*- دعم المزيد من منصات الفيديو (Vimeo, Twitch, إلخ)*
*- وضع التصوير المتتابع لالتقاط إطارات متعددة*
*- الالتقاط التلقائي على فترات محددة*
*- أدوات تحرير الصور الأساسية*
*- المزيد من خيارات اللغة*
## 📝 License | الترخيص
This project is open source and available under the MIT license.
*هذا المشروع مفتوح المصدر ومتاح تحت رخصة MIT.*
## 👨‍💻 Developer | المطوّر
Developed with ❤️. For support or feature requests, please open an issue on GitHub.
*طُوّر بكل ❤️. للدعم أو طلبات الميزات، يرجى فتح مشكلة على GitHub.*
---
*Note: YouTube is a trademark of Google LLC. This extension is not affiliated with or endorsed by YouTube or Google.*
*ملاحظة: يوتيوب هي علامة تجارية لشركة Google LLC. هذه الإضافة ليست مرتبطة أو معتمدة من قبل يوتيوب أو جوجل.*

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet