Screenshot for YouTube™ | 4K Frame & Thumbnail Cap
@@ -73,3 +73,15 @@ { | ||
| "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" | ||
| } | ||
| } | ||
| } |
@@ -73,3 +73,15 @@ { | ||
| "description": "Reset settings button" | ||
| }, | ||
| "copyBtn": { | ||
| "message": "📋 Copy to Clipboard", | ||
| "description": "Button to copy frame to clipboard" | ||
| }, | ||
| "copySuccess": { | ||
| "message": "Frame copied to clipboard!", | ||
| "description": "Success message after copying a frame" | ||
| }, | ||
| "showPreviewLabel": { | ||
| "message": "Show Thumbnail Preview", | ||
| "description": "Setting to toggle thumbnail preview" | ||
| } | ||
| } | ||
| } |
+157
-126
@@ -6,3 +6,3 @@ :root { | ||
| --gold-gradient: linear-gradient(135deg, #f6d365 0%, #fda085 100%); | ||
| --bg-color: #ffffff; | ||
@@ -13,7 +13,7 @@ --surface-color: #f8f9fa; | ||
| --border-color: #e2e8f0; | ||
| --shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05); | ||
| --shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); | ||
| --shadow-colored: 0 4px 14px 0 rgba(0, 118, 255, 0.39); | ||
| --radius-md: 8px; | ||
@@ -32,3 +32,3 @@ --radius-lg: 12px; | ||
| body { | ||
| width: 350px; | ||
| width: 380px; | ||
| background-color: var(--bg-color); | ||
@@ -40,6 +40,6 @@ color: var(--text-primary); | ||
| .popup-container { | ||
| padding: 16px; | ||
| padding: 14px; | ||
| display: flex; | ||
| flex-direction: column; | ||
| gap: 16px; | ||
| gap: 12px; | ||
| } | ||
@@ -58,3 +58,3 @@ | ||
| font-weight: 700; | ||
| font-size: 16px; | ||
| font-size: 15px; | ||
| display: flex; | ||
@@ -65,2 +65,3 @@ align-items: center; | ||
| -webkit-background-clip: text; | ||
| background-clip: text; | ||
| -webkit-text-fill-color: transparent; | ||
@@ -71,3 +72,4 @@ } | ||
| font-size: 18px; | ||
| -webkit-text-fill-color: initial; /* Don't apply gradient to emoji */ | ||
| -webkit-text-fill-color: initial; | ||
| /* Don't apply gradient to emoji */ | ||
| } | ||
@@ -107,11 +109,21 @@ | ||
| .action-buttons-grid { | ||
| display: grid; | ||
| grid-template-columns: 1fr 1fr; | ||
| gap: 10px; | ||
| } | ||
| .primary-action-btn.copy-btn { | ||
| background: var(--secondary-gradient); | ||
| } | ||
| .primary-action-btn { | ||
| width: 100%; | ||
| padding: 14px; | ||
| padding: 10px 14px; | ||
| background: var(--primary-gradient); | ||
| border: none; | ||
| border-radius: var(--radius-lg); | ||
| border-radius: var(--radius-md); | ||
| color: white; | ||
| font-weight: 700; | ||
| font-size: 16px; | ||
| font-weight: 600; | ||
| font-size: 14px; | ||
| cursor: pointer; | ||
@@ -122,3 +134,3 @@ transition: transform 0.2s, box-shadow 0.2s; | ||
| justify-content: center; | ||
| gap: 8px; | ||
| gap: 6px; | ||
| box-shadow: var(--shadow-colored); | ||
@@ -139,3 +151,3 @@ } | ||
| display: flex; | ||
| gap: 10px; | ||
| gap: 8px; | ||
| } | ||
@@ -145,3 +157,3 @@ | ||
| flex: 1; | ||
| padding: 10px; | ||
| padding: 8px; | ||
| border: 1px solid var(--border-color); | ||
@@ -154,5 +166,5 @@ background: white; | ||
| justify-content: center; | ||
| gap: 6px; | ||
| gap: 5px; | ||
| font-weight: 600; | ||
| font-size: 13px; | ||
| font-size: 12px; | ||
| transition: all 0.2s; | ||
@@ -180,2 +192,3 @@ color: var(--text-primary); | ||
| -webkit-background-clip: text; | ||
| background-clip: text; | ||
| -webkit-text-fill-color: transparent; | ||
@@ -185,3 +198,4 @@ } | ||
| .rate-btn .btn-icon { | ||
| color: orange; /* Fallback */ | ||
| color: orange; | ||
| /* Fallback */ | ||
| } | ||
@@ -192,3 +206,3 @@ | ||
| background: var(--surface-color); | ||
| padding: 10px 12px; | ||
| padding: 8px 10px; | ||
| border-radius: var(--radius-md); | ||
@@ -198,3 +212,3 @@ display: flex; | ||
| align-items: center; | ||
| font-size: 13px; | ||
| font-size: 12px; | ||
| } | ||
@@ -234,145 +248,156 @@ | ||
| .tools-section { | ||
| border-top: 1px solid var(--border-color); | ||
| padding-top: 12px; | ||
| border-top: 1px solid var(--border-color); | ||
| padding-top: 10px; | ||
| } | ||
| .tools-header { | ||
| margin-bottom: 8px; | ||
| font-size: 12px; | ||
| font-weight: 700; | ||
| text-transform: uppercase; | ||
| color: var(--text-secondary); | ||
| letter-spacing: 0.5px; | ||
| margin-bottom: 8px; | ||
| font-size: 12px; | ||
| font-weight: 700; | ||
| text-transform: uppercase; | ||
| color: var(--text-secondary); | ||
| letter-spacing: 0.5px; | ||
| } | ||
| .thumbnail-tool-container { | ||
| background: var(--surface-color); | ||
| border-radius: var(--radius-md); | ||
| padding: 10px; | ||
| margin-bottom: 10px; | ||
| background: var(--surface-color); | ||
| border-radius: var(--radius-md); | ||
| padding: 8px; | ||
| margin-bottom: 8px; | ||
| } | ||
| .secondary-btn { | ||
| width: 100%; | ||
| padding: 8px; | ||
| background: white; | ||
| border: 1px solid var(--border-color); | ||
| border-radius: 6px; | ||
| color: var(--text-primary); | ||
| font-weight: 600; | ||
| cursor: pointer; | ||
| font-size: 13px; | ||
| transition: all 0.2s; | ||
| width: 100%; | ||
| padding: 7px 10px; | ||
| background: white; | ||
| border: 1px solid var(--border-color); | ||
| border-radius: 6px; | ||
| color: var(--text-primary); | ||
| font-weight: 600; | ||
| cursor: pointer; | ||
| font-size: 12px; | ||
| transition: all 0.2s; | ||
| } | ||
| .secondary-btn:hover { | ||
| border-color: #4facfe; | ||
| color: #4facfe; | ||
| border-color: #4facfe; | ||
| color: #4facfe; | ||
| } | ||
| .secondary-btn:disabled { | ||
| opacity: 0.6; | ||
| cursor: not-allowed; | ||
| border-color: var(--border-color); | ||
| color: var(--text-secondary); | ||
| opacity: 0.6; | ||
| cursor: not-allowed; | ||
| border-color: var(--border-color); | ||
| color: var(--text-secondary); | ||
| } | ||
| .video-status { | ||
| margin-top: 6px; | ||
| font-size: 11px; | ||
| color: var(--text-secondary); | ||
| white-space: nowrap; | ||
| overflow: hidden; | ||
| text-overflow: ellipsis; | ||
| margin-top: 6px; | ||
| font-size: 11px; | ||
| color: var(--text-secondary); | ||
| white-space: nowrap; | ||
| overflow: hidden; | ||
| text-overflow: ellipsis; | ||
| } | ||
| .settings-toggle-container { | ||
| display: flex; | ||
| justify-content: flex-end; | ||
| display: flex; | ||
| justify-content: flex-end; | ||
| } | ||
| .icon-btn { | ||
| background: none; | ||
| border: none; | ||
| cursor: pointer; | ||
| font-size: 18px; | ||
| opacity: 0.7; | ||
| transition: opacity 0.2s; | ||
| padding: 4px; | ||
| background: none; | ||
| border: none; | ||
| cursor: pointer; | ||
| font-size: 18px; | ||
| opacity: 0.7; | ||
| transition: opacity 0.2s; | ||
| padding: 4px; | ||
| } | ||
| .icon-btn:hover { | ||
| opacity: 1; | ||
| opacity: 1; | ||
| } | ||
| .settings-content { | ||
| display: none; | ||
| background: var(--surface-color); | ||
| margin-top: 10px; | ||
| padding: 12px; | ||
| border-radius: var(--radius-md); | ||
| border: 1px solid var(--border-color); | ||
| animation: slideDown 0.2s ease-out; | ||
| display: none; | ||
| background: var(--surface-color); | ||
| margin-top: 8px; | ||
| padding: 10px; | ||
| border-radius: var(--radius-md); | ||
| border: 1px solid var(--border-color); | ||
| animation: slideDown 0.2s ease-out; | ||
| } | ||
| @keyframes slideDown { | ||
| from { opacity: 0; transform: translateY(-5px); } | ||
| to { opacity: 1; transform: translateY(0); } | ||
| from { | ||
| opacity: 0; | ||
| transform: translateY(-5px); | ||
| } | ||
| to { | ||
| opacity: 1; | ||
| transform: translateY(0); | ||
| } | ||
| } | ||
| .form-group { | ||
| margin-bottom: 10px; | ||
| margin-bottom: 8px; | ||
| } | ||
| .form-group label { | ||
| display: block; | ||
| font-size: 12px; | ||
| font-weight: 600; | ||
| margin-bottom: 4px; | ||
| color: var(--text-secondary); | ||
| display: block; | ||
| font-size: 12px; | ||
| font-weight: 600; | ||
| margin-bottom: 4px; | ||
| color: var(--text-secondary); | ||
| } | ||
| .form-group select, .form-group input { | ||
| width: 100%; | ||
| padding: 8px; | ||
| border: 1px solid var(--border-color); | ||
| border-radius: 6px; | ||
| font-size: 13px; | ||
| outline: none; | ||
| transition: border-color 0.2s; | ||
| .form-group select, | ||
| .form-group input { | ||
| width: 100%; | ||
| padding: 7px; | ||
| border: 1px solid var(--border-color); | ||
| border-radius: 6px; | ||
| font-size: 12px; | ||
| outline: none; | ||
| transition: border-color 0.2s; | ||
| } | ||
| .form-group select:focus, .form-group input:focus { | ||
| border-color: #4facfe; | ||
| .form-group select:focus, | ||
| .form-group input:focus { | ||
| border-color: #4facfe; | ||
| } | ||
| .action-buttons { | ||
| display: flex; | ||
| gap: 8px; | ||
| margin-top: 12px; | ||
| display: flex; | ||
| gap: 8px; | ||
| margin-top: 10px; | ||
| } | ||
| .save-btn, .reset-btn { | ||
| flex: 1; | ||
| padding: 8px; | ||
| border: none; | ||
| border-radius: 6px; | ||
| font-size: 12px; | ||
| font-weight: 600; | ||
| cursor: pointer; | ||
| transition: opacity 0.2s; | ||
| .save-btn, | ||
| .reset-btn { | ||
| flex: 1; | ||
| padding: 7px; | ||
| border: none; | ||
| border-radius: 6px; | ||
| font-size: 11px; | ||
| font-weight: 600; | ||
| cursor: pointer; | ||
| transition: opacity 0.2s; | ||
| } | ||
| .save-btn { | ||
| background: var(--text-primary); | ||
| color: white; | ||
| background: var(--text-primary); | ||
| color: white; | ||
| } | ||
| .reset-btn { | ||
| background: #e2e8f0; | ||
| color: var(--text-primary); | ||
| background: #e2e8f0; | ||
| color: var(--text-primary); | ||
| } | ||
| .save-btn:hover, .reset-btn:hover { | ||
| opacity: 0.9; | ||
| .save-btn:hover, | ||
| .reset-btn:hover { | ||
| opacity: 0.9; | ||
| } | ||
@@ -382,29 +407,35 @@ | ||
| .status-message { | ||
| padding: 10px; | ||
| border-radius: var(--radius-md); | ||
| font-size: 13px; | ||
| text-align: center; | ||
| font-weight: 500; | ||
| animation: fadeIn 0.3s; | ||
| display: none; /* Controlled by JS */ | ||
| padding: 8px; | ||
| border-radius: var(--radius-md); | ||
| font-size: 12px; | ||
| text-align: center; | ||
| font-weight: 500; | ||
| animation: fadeIn 0.3s; | ||
| display: none; | ||
| /* Controlled by JS */ | ||
| } | ||
| .status-message.success { | ||
| background-color: #d1fae5; | ||
| color: #065f46; | ||
| background-color: #d1fae5; | ||
| color: #065f46; | ||
| } | ||
| .status-message.error { | ||
| background-color: #fee2e2; | ||
| color: #991b1b; | ||
| background-color: #fee2e2; | ||
| color: #991b1b; | ||
| } | ||
| .status-message.info { | ||
| background-color: #eff6ff; | ||
| color: #1e40af; | ||
| background-color: #eff6ff; | ||
| color: #1e40af; | ||
| } | ||
| @keyframes fadeIn { | ||
| from { opacity: 0; } | ||
| to { opacity: 1; } | ||
| from { | ||
| opacity: 0; | ||
| } | ||
| to { | ||
| opacity: 1; | ||
| } | ||
| } | ||
@@ -414,13 +445,13 @@ | ||
| .rtl { | ||
| direction: rtl; | ||
| direction: rtl; | ||
| } | ||
| .rtl .popup-title { | ||
| flex-direction: row-reverse; | ||
| flex-direction: row-reverse; | ||
| } | ||
| .rtl .primary-action-btn, | ||
| .rtl .primary-action-btn, | ||
| .rtl .growth-btn, | ||
| .rtl .shortcut-info { | ||
| flex-direction: row-reverse; | ||
| flex-direction: row-reverse; | ||
| } |
+2
-1
| { | ||
| "manifest_version": 2, | ||
| "name": "YouTube Screenshot Tool", | ||
| "version": "1.2.2", | ||
| "version": "1.2.3", | ||
| "description": "Extract high-quality frames from YouTube videos without UI elements", | ||
@@ -10,2 +10,3 @@ "default_locale": "en", | ||
| "storage", | ||
| "clipboardWrite", | ||
| "*://*.youtube.com/*" | ||
@@ -12,0 +13,0 @@ ], |
+31
-17
@@ -25,3 +25,3 @@ <!DOCTYPE html> | ||
| <!-- Main Action Section --> | ||
| <div class="hero-section"> | ||
| <div class="hero-section action-buttons-grid"> | ||
| <button id="capture" class="primary-action-btn"> | ||
@@ -31,2 +31,6 @@ <span class="btn-icon">📸</span> | ||
| </button> | ||
| <button id="copyFrame" class="primary-action-btn copy-btn"> | ||
| <span class="btn-icon">📋</span> | ||
| <span class="btn-text">Copy to Clipboard</span> | ||
| </button> | ||
| </div> | ||
@@ -57,22 +61,27 @@ | ||
| <div class="tools-section"> | ||
| <div class="tools-header"> | ||
| <span id="toolsLabel">Tools & Settings</span> | ||
| <div class="tools-header"> | ||
| <span id="toolsLabel">Tools & Settings</span> | ||
| </div> | ||
| <div class="thumbnail-tool-container"> | ||
| <div class="form-group" style="margin-bottom: 8px;"> | ||
| <input type="text" id="videoUrlInput" placeholder="Enter YouTube URL or ID..."> | ||
| </div> | ||
| <div class="thumbnail-tool-container"> | ||
| <button id="openThumbnailTool" class="secondary-btn"> | ||
| <span class="btn-text">Open Thumbnail Tool</span> | ||
| </button> | ||
| <div class="video-status"> | ||
| <span id="videoUrlDisplay">No video detected</span> | ||
| </div> | ||
| <button id="downloadThumbnail" class="secondary-btn"> | ||
| <span class="btn-text">Download HD Thumbnail</span> | ||
| </button> | ||
| <div id="thumbPreview" style="margin-top: 10px; display: none; text-align: center;"> | ||
| <img id="thumbImg" src="" | ||
| style="width: 100%; border-radius: 4px; box-shadow: var(--shadow-sm); cursor: pointer;" | ||
| title="Click to view full size"> | ||
| </div> | ||
| </div> | ||
| <div class="settings-toggle-container"> | ||
| <button id="settingsToggle" class="icon-btn" aria-label="Settings"> | ||
| ⚙️ | ||
| </button> | ||
| </div> | ||
| <div class="settings-toggle-container"> | ||
| <button id="settingsToggle" class="icon-btn" aria-label="Settings"> | ||
| ⚙️ | ||
| </button> | ||
| </div> | ||
| </div> | ||
| <!-- Collapsible Settings Panel --> | ||
@@ -103,2 +112,7 @@ <div class="settings-content" id="settingsContent"> | ||
| <div class="form-group" style="display: flex; align-items: center; gap: 8px;"> | ||
| <input type="checkbox" id="showThumbnailPreview" style="width: auto;"> | ||
| <label for="showThumbnailPreview" id="showPreviewLabel" style="margin-bottom: 0;">Show Thumbnail Preview</label> | ||
| </div> | ||
| <div class="action-buttons"> | ||
@@ -105,0 +119,0 @@ <button id="saveSettings" class="save-btn">Save</button> |
@@ -12,3 +12,4 @@ // YouTube Screenshot Tool - Background Script | ||
| filename: 'youtube_frame', | ||
| language: 'en' | ||
| language: 'en', | ||
| showThumbnailPreview: false | ||
| }; | ||
@@ -15,0 +16,0 @@ |
+56
-10
@@ -8,5 +8,4 @@ /** | ||
| // استخدام الواجهة الموحدة لتحقيق التوافق مع Chrome و Firefox | ||
| // Unified approach for Firefox and Chrome | ||
| const isBrowser = typeof browser !== 'undefined'; | ||
| const isChrome = typeof chrome !== 'undefined'; | ||
| const browserAPI = isBrowser ? browser : chrome; | ||
@@ -20,2 +19,9 @@ | ||
| return true; // Keep the message channel open for async response | ||
| } else if (message.action === 'copyFrame') { | ||
| copyFrame(message.settings).then(result => { | ||
| sendResponse(result); | ||
| }).catch(err => { | ||
| sendResponse(err.toString()); | ||
| }); | ||
| return true; | ||
| } else if (message.action === 'ping' || message.action === 'injected_check') { | ||
@@ -48,3 +54,3 @@ // Respond to ping or injected_check message to confirm content script is loaded | ||
| const lang = settings.language || 'en'; | ||
| const video = document.querySelector('video'); | ||
@@ -57,3 +63,3 @@ if (!video) { | ||
| const canvas = document.createElement('canvas'); | ||
| // Set dimensions based on quality | ||
@@ -66,3 +72,3 @@ let scaleFactor = 1; | ||
| } | ||
| canvas.width = video.videoWidth * scaleFactor; | ||
@@ -78,3 +84,3 @@ canvas.height = video.videoHeight * scaleFactor; | ||
| let quality = 1; | ||
| if (settings.format === 'jpeg') { | ||
@@ -87,3 +93,3 @@ mimeType = 'image/jpeg'; | ||
| } | ||
| // Get video title for filename | ||
@@ -95,3 +101,3 @@ const videoTitle = document.querySelector('h1.title')?.textContent?.trim() || 'youtube_video'; | ||
| const timeString = `${minutes}_${seconds.toString().padStart(2, '0')}`; | ||
| // Create a safe filename | ||
@@ -105,3 +111,3 @@ let filename = settings.filename; | ||
| .substring(0, 50); // Limit length | ||
| filename = `${filename}_${timeString}.${settings.format}`; | ||
@@ -117,3 +123,3 @@ } else { | ||
| link.click(); | ||
| return true; | ||
@@ -123,2 +129,42 @@ } catch (error) { | ||
| } | ||
| } | ||
| /** | ||
| * Captures a frame and copies it to the clipboard | ||
| * @param {Object} settings - The capture settings | ||
| * @returns {Promise<boolean|string>} - True on success, error message on failure | ||
| */ | ||
| async function copyFrame(settings) { | ||
| try { | ||
| const lang = settings.language || 'en'; | ||
| const video = document.querySelector('video'); | ||
| if (!video) { | ||
| return messages[lang].videoNotFound; | ||
| } | ||
| const canvas = document.createElement('canvas'); | ||
| let scaleFactor = 1; | ||
| if (settings.quality === 'medium') scaleFactor = 0.75; | ||
| else if (settings.quality === 'low') scaleFactor = 0.5; | ||
| canvas.width = video.videoWidth * scaleFactor; | ||
| canvas.height = video.videoHeight * scaleFactor; | ||
| const ctx = canvas.getContext('2d'); | ||
| ctx.drawImage(video, 0, 0, canvas.width, canvas.height); | ||
| const blob = await new Promise(resolve => canvas.toBlob(resolve, 'image/png')); | ||
| if (!blob) { | ||
| throw new Error('Failed to create image blob'); | ||
| } | ||
| const data = [new ClipboardItem({ 'image/png': blob })]; | ||
| await navigator.clipboard.write(data); | ||
| return true; | ||
| } catch (error) { | ||
| console.error('Copy frame error:', error); | ||
| return error.toString(); | ||
| } | ||
| } |
+121
-25
@@ -5,3 +5,2 @@ // YouTube Screenshot Tool - Popup Script | ||
| const isBrowser = typeof browser !== 'undefined'; | ||
| const isChrome = typeof chrome !== 'undefined'; | ||
| const browserAPI = isBrowser ? browser : chrome; | ||
@@ -17,3 +16,4 @@ | ||
| filename: 'youtube_frame', | ||
| language: 'en' | ||
| language: 'en', | ||
| showThumbnailPreview: false | ||
| }; | ||
@@ -37,2 +37,4 @@ | ||
| const lowQualityOption = document.getElementById('lowQualityOption'); | ||
| const copyFrameBtn = document.getElementById('copyFrame'); | ||
| const showPreviewToggle = document.getElementById('showThumbnailPreview'); | ||
@@ -64,3 +66,6 @@ // Messages cache | ||
| toolsLabel: "Tools & Settings", | ||
| openThumbnailTool: "Open Thumbnail", | ||
| 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, | ||
@@ -86,3 +91,6 @@ copied: "Copied! ✅" | ||
| toolsLabel: "الأدوات والإعدادات", | ||
| openThumbnailTool: "فتح الصورة المصغرة", | ||
| downloadThumbnail: "تحميل الصورة المصغرة", | ||
| showPreviewLabel: "تفعيل معاينة الصورة", | ||
| copyBtn: "📋 نسخ للحافظة", | ||
| copySuccess: "تم نسخ الإطار للحافظة!", | ||
| shareMessage: "أداة رائعة لالتقاط الصور من يوتيوب بجودة عالية! جربها: " + STORE_URL, | ||
@@ -104,2 +112,3 @@ copied: "تم النسخ! ✅" | ||
| if (filenameInput) filenameInput.value = settings.filename; | ||
| if (showPreviewToggle) showPreviewToggle.checked = settings.showThumbnailPreview || false; | ||
@@ -129,6 +138,8 @@ // Set language | ||
| async function initThumbnailTool() { | ||
| const videoUrlDisplay = document.getElementById('videoUrlDisplay'); | ||
| const openThumbnailToolBtn = document.getElementById('openThumbnailTool'); | ||
| const videoUrlInput = document.getElementById('videoUrlInput'); | ||
| const downloadThumbnailBtn = document.getElementById('downloadThumbnail'); | ||
| const thumbPreview = document.getElementById('thumbPreview'); | ||
| const thumbImg = document.getElementById('thumbImg'); | ||
| if (!videoUrlDisplay || !openThumbnailToolBtn) return; | ||
| if (!videoUrlInput || !downloadThumbnailBtn) return; | ||
@@ -138,21 +149,15 @@ try { | ||
| if (tabs.length > 0 && tabs[0].url && (tabs[0].url.includes('youtube.com/watch') || tabs[0].url.includes('youtu.be/'))) { | ||
| videoUrlDisplay.textContent = tabs[0].url; | ||
| openThumbnailToolBtn.disabled = false; | ||
| openThumbnailToolBtn.classList.remove('disabled'); | ||
| } else { | ||
| videoUrlDisplay.textContent = "No YouTube video detected"; | ||
| openThumbnailToolBtn.disabled = true; | ||
| openThumbnailToolBtn.classList.add('disabled'); | ||
| videoUrlInput.value = tabs[0].url; | ||
| updateThumbPreview(tabs[0].url); | ||
| } | ||
| // Remove old listeners to avoid duplicates | ||
| const newBtn = openThumbnailToolBtn.cloneNode(true); | ||
| openThumbnailToolBtn.parentNode.replaceChild(newBtn, openThumbnailToolBtn); | ||
| videoUrlInput.addEventListener('input', () => { | ||
| updateThumbPreview(videoUrlInput.value); | ||
| }); | ||
| newBtn.addEventListener('click', () => { | ||
| const url = videoUrlDisplay.textContent; | ||
| downloadThumbnailBtn.addEventListener('click', () => { | ||
| const url = videoUrlInput.value; | ||
| const videoId = extractVideoId(url); | ||
| if (videoId) { | ||
| // Open the maximum resolution thumbnail directly | ||
| const thumbUrl = `https://img.youtube.com/vi/${videoId}/maxresdefault.jpg`; | ||
@@ -165,2 +170,31 @@ browserAPI.tabs.create({ url: thumbUrl }); | ||
| thumbImg.addEventListener('click', () => { | ||
| const videoId = extractVideoId(videoUrlInput.value); | ||
| if (videoId) { | ||
| const thumbUrl = `https://img.youtube.com/vi/${videoId}/maxresdefault.jpg`; | ||
| browserAPI.tabs.create({ url: thumbUrl }); | ||
| } | ||
| }); | ||
| function updateThumbPreview(url) { | ||
| const videoId = extractVideoId(url); | ||
| const isEnabled = showPreviewToggle ? showPreviewToggle.checked : false; | ||
| if (videoId) { | ||
| if (isEnabled) { | ||
| const thumbUrl = `https://img.youtube.com/vi/${videoId}/mqdefault.jpg`; | ||
| thumbImg.src = thumbUrl; | ||
| thumbPreview.style.display = 'block'; | ||
| } else { | ||
| thumbPreview.style.display = 'none'; | ||
| } | ||
| downloadThumbnailBtn.disabled = false; | ||
| downloadThumbnailBtn.classList.remove('disabled'); | ||
| } else { | ||
| thumbPreview.style.display = 'none'; | ||
| downloadThumbnailBtn.disabled = true; | ||
| downloadThumbnailBtn.classList.add('disabled'); | ||
| } | ||
| } | ||
| } catch (error) { | ||
@@ -296,2 +330,57 @@ console.error('Error initializing thumbnail tool:', error); | ||
| // Copy button click | ||
| if (copyFrameBtn) { | ||
| copyFrameBtn.addEventListener('click', async () => { | ||
| const settings = await loadSettings(); | ||
| showStatus('Copying...', 'info'); | ||
| try { | ||
| const tabs = await browserAPI.tabs.query({ active: true, currentWindow: true }); | ||
| if (tabs[0].url.includes('youtube.com/watch')) { | ||
| try { | ||
| await sendMessageToTab(tabs[0].id, { action: 'ping' }); | ||
| await handleCopyMessage(tabs[0].id, settings); | ||
| } catch (err) { | ||
| console.log('Content script not loaded, injecting:', err); | ||
| try { | ||
| await injectContentScript(tabs[0].id); | ||
| await handleCopyMessage(tabs[0].id, settings); | ||
| } catch (injectError) { | ||
| showStatus('Error injecting script: ' + injectError.message, 'error'); | ||
| } | ||
| } | ||
| } 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'); | ||
| } | ||
| } catch (error) { | ||
| showStatus('Error: ' + (error.message || 'Unknown error'), 'error'); | ||
| } | ||
| }); | ||
| } | ||
| // Handle copy message | ||
| async function handleCopyMessage(tabId, settings) { | ||
| try { | ||
| const response = await sendMessageToTab(tabId, { | ||
| action: 'copyFrame', | ||
| settings: settings | ||
| }); | ||
| if (response === true) { | ||
| const successMsg = getMessage('copySuccess'); | ||
| showStatus(successMsg, 'success'); | ||
| } else { | ||
| showStatus('Error: ' + (response || 'Unknown error'), 'error'); | ||
| } | ||
| } catch (error) { | ||
| showStatus('Error: ' + (error.message || 'Unknown error'), 'error'); | ||
| } | ||
| } | ||
| // Inject content script | ||
@@ -362,3 +451,4 @@ async function injectContentScript(tabId) { | ||
| filename: filenameInput.value, | ||
| language: document.querySelector('.language-btn.active').dataset.lang | ||
| language: document.querySelector('.language-btn.active').dataset.lang, | ||
| showThumbnailPreview: showPreviewToggle.checked | ||
| }; | ||
@@ -380,2 +470,3 @@ | ||
| filenameInput.value = DEFAULT_SETTINGS.filename; | ||
| showPreviewToggle.checked = DEFAULT_SETTINGS.showThumbnailPreview; | ||
@@ -478,3 +569,4 @@ // Update language | ||
| 'changeShortcut': fallbackMessages[lang].changeShortcut, | ||
| 'toolsLabel': fallbackMessages[lang].toolsLabel | ||
| 'toolsLabel': fallbackMessages[lang].toolsLabel, | ||
| 'showPreviewLabel': fallbackMessages[lang].showPreviewLabel | ||
| }; | ||
@@ -494,7 +586,10 @@ | ||
| } | ||
| if (copyFrameBtn) { | ||
| copyFrameBtn.querySelector('.btn-text').textContent = fallbackMessages[lang].copyBtn.replace("📋 ", ""); | ||
| } | ||
| if (rateBtn) { | ||
| rateBtn.querySelector('.btn-text').textContent = fallbackMessages[lang].rateText; | ||
| } | ||
| if (document.getElementById('openThumbnailTool')) { | ||
| document.getElementById('openThumbnailTool').querySelector('.btn-text').textContent = fallbackMessages[lang].openThumbnailTool; | ||
| if (document.getElementById('downloadThumbnail')) { | ||
| document.getElementById('downloadThumbnail').querySelector('.btn-text').textContent = fallbackMessages[lang].downloadThumbnail; | ||
| } | ||
@@ -517,3 +612,4 @@ } | ||
| 'Settings reset to default': 'تم إعادة الإعدادات للوضع الافتراضي', | ||
| 'Failed to copy to clipboard': 'فشل نسخ النص' | ||
| 'Failed to copy to clipboard': 'فشل نسخ النص', | ||
| 'Copying...': 'جاري النسخ...' | ||
| } | ||
@@ -520,0 +616,0 @@ }; |
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