// Background service worker chrome.runtime.onInstalled.addListener(() => { console.log('SDB Audio Extractor extension installed'); // Create context menu chrome.contextMenus.create({ id: 'extractAudio', title: 'Extract Audio with SDB', contexts: ['page'], documentUrlPatterns: ['https://www.youtube.com/watch*'] }); }); // Function to clean YouTube URL function getCleanVideoUrl(url) { const match = url.match(/[?&]v=([^&]+)/); if (match) { return `https://www.youtube.com/watch?v=${match[1]}`; } return url; // Return original if we can't extract video ID } // Handle context menu clicks chrome.contextMenus.onClicked.addListener(async (info, tab) => { if (info.menuItemId === 'extractAudio') { // Get API configuration const result = await chrome.storage.sync.get(['apiToken', 'apiBaseUrl']); const apiToken = result.apiToken; const apiBaseUrl = result.apiBaseUrl || 'http://goyave'; if (!apiToken) { // Open options page if no token configured chrome.runtime.openOptionsPage(); return; } // Get video information from content script for notification let videoTitle = null; try { const videoInfo = await chrome.tabs.sendMessage(tab.id, { action: 'getVideoInfo' }); if (videoInfo && videoInfo.title) { videoTitle = videoInfo.title; } } catch (error) { console.log('Could not get video info from content script:', error); } // Send extraction request try { // Use clean URL for the API request const cleanUrl = getCleanVideoUrl(tab.url); const response = await fetch(`${apiBaseUrl}/api/v1/extractions/?url=${encodeURIComponent(cleanUrl)}`, { method: 'POST', headers: { 'API-TOKEN': apiToken } }); if (response.ok) { // Show success notification const notificationMessage = videoTitle ? `Audio extraction started for "${videoTitle}"!` : 'Audio extraction started successfully!'; chrome.notifications.create({ type: 'basic', iconUrl: 'icon48.png', title: 'SDB Audio Extractor', message: notificationMessage }); } else { throw new Error(`HTTP ${response.status}`); } } catch (error) { console.error('Extraction error:', error); let errorMessage = 'Unknown error occurred'; if (error.message) { errorMessage = error.message; } else if (error.name === 'TypeError' && error.message.includes('fetch')) { errorMessage = 'Cannot connect to API server'; } else if (typeof error === 'string') { errorMessage = error; } chrome.notifications.create({ type: 'basic', iconUrl: 'icon48.png', title: 'SDB Audio Extractor', message: `Failed to extract audio: ${errorMessage}` }); } } }); // Handle messages from content scripts or popup chrome.runtime.onMessage.addListener((request, _sender, sendResponse) => { console.log('Background received message:', request); if (request.action === 'extractAudio') { // Handle extraction request from content script if needed handleExtraction(request.url).then(sendResponse); return true; // Keep message channel open for async response } }); async function handleExtraction(url) { try { const result = await chrome.storage.sync.get(['apiToken', 'apiBaseUrl']); const apiToken = result.apiToken; const apiBaseUrl = result.apiBaseUrl || 'http://goyave'; if (!apiToken) { throw new Error('API token not configured'); } // Use clean URL for the API request const cleanUrl = getCleanVideoUrl(url); const response = await fetch(`${apiBaseUrl}/api/v1/extractions/?url=${encodeURIComponent(cleanUrl)}`, { method: 'POST', headers: { 'API-TOKEN': apiToken } }); if (!response.ok) { let errorMessage = `HTTP ${response.status}`; try { const errorData = await response.json(); if (errorData.detail) { errorMessage = errorData.detail; } else if (errorData.message) { errorMessage = errorData.message; } else if (typeof errorData === 'string') { errorMessage = errorData; } } catch (e) { errorMessage = response.statusText || errorMessage; } throw new Error(errorMessage); } return await response.json(); } catch (error) { console.error('Extraction error:', error); throw error; } }