diff --git a/popup/main.html b/popup/main.html index cb6afd1..87ead62 100644 --- a/popup/main.html +++ b/popup/main.html @@ -142,7 +142,7 @@ CrawlFlix Server + placeholder="http://localhost:4200" value="http://localhost:4200">
@@ -237,7 +237,7 @@
+ placeholder="http://localhost:4200" value="http://localhost:4200">
diff --git a/popup/main.js b/popup/main.js index a667e8e..d3ad82e 100644 --- a/popup/main.js +++ b/popup/main.js @@ -4,109 +4,113 @@ let requests = chrome.extension.getBackgroundPage().requests; let pageURL = chrome.extension.getBackgroundPage().pageURL; let targetIds = chrome.extension.getBackgroundPage().targetIds; let clearkey = chrome.extension.getBackgroundPage().clearkey; -let userInputs = {}; +let userInputs = {}; // IMPORTANT: Cette variable était manquante! // === WIDEVINE KEY EXTRACTION === class WidevineExtractor { - static async extractKeys() { - const guessButton = document.getElementById("guess"); - const resultTextarea = document.getElementById('result'); - - try { - // UI feedback - UIHelpers.setLoadingState(guessButton, true); - document.body.style.cursor = "wait"; - - // Initialize Pyodide - const pyodide = await loadPyodide(); - await pyodide.loadPackage([ - "certifi-2024.2.2-py3-none-any.whl", - "charset_normalizer-3.3.2-py3-none-any.whl", - "construct-2.8.8-py2.py3-none-any.whl", - "idna-3.6-py3-none-any.whl", - "packaging-23.2-py3-none-any.whl", - "protobuf-4.24.4-cp312-cp312-emscripten_3_1_52_wasm32.whl", - "pycryptodome-3.20.0-cp35-abi3-emscripten_3_1_52_wasm32.whl", - "pymp4-1.4.0-py3-none-any.whl", - "pyodide_http-0.2.1-py3-none-any.whl", - "pywidevine-1.8.0-py3-none-any.whl", - "requests-2.31.0-py3-none-any.whl", - "urllib3-2.2.1-py3-none-any.whl" - ].map(e => "/libs/wheels/" + e)); + static async extractKeys() { + const guessButton = document.getElementById("guess"); + const resultTextarea = document.getElementById('result'); + + try { + // Vérifier que userInputs.license est défini + if (userInputs.license === undefined || !requests[userInputs.license]) { + throw new Error('License not selected. Please wait for auto-selection or select manually.'); + } + + // UI feedback + UIHelpers.setLoadingState(guessButton, true); + document.body.style.cursor = "wait"; + + // Initialize Pyodide + const pyodide = await loadPyodide(); + await pyodide.loadPackage([ + "certifi-2024.2.2-py3-none-any.whl", + "charset_normalizer-3.3.2-py3-none-any.whl", + "construct-2.8.8-py2.py3-none-any.whl", + "idna-3.6-py3-none-any.whl", + "packaging-23.2-py3-none-any.whl", + "protobuf-4.24.4-cp312-cp312-emscripten_3_1_52_wasm32.whl", + "pycryptodome-3.20.0-cp35-abi3-emscripten_3_1_52_wasm32.whl", + "pymp4-1.4.0-py3-none-any.whl", + "pyodide_http-0.2.1-py3-none-any.whl", + "pywidevine-1.8.0-py3-none-any.whl", + "requests-2.31.0-py3-none-any.whl", + "urllib3-2.2.1-py3-none-any.whl" + ].map(e => "/libs/wheels/" + e)); - // Configure Guesser - pyodide.globals.set("pssh", document.getElementById('pssh').value); - pyodide.globals.set("licUrl", requests[userInputs['license']]['url']); - pyodide.globals.set("licHeaders", requests[userInputs['license']]['headers']); - pyodide.globals.set("licBody", requests[userInputs['license']]['body']); + // Configure Guesser + pyodide.globals.set("pssh", document.getElementById('pssh').value); + pyodide.globals.set("licUrl", requests[userInputs['license']]['url']); + pyodide.globals.set("licHeaders", requests[userInputs['license']]['headers']); + pyodide.globals.set("licBody", requests[userInputs['license']]['body']); - // Load Python scripts - const [pre, after, scheme] = await Promise.all([ - fetch('/python/pre.py').then(res => res.text()), - fetch('/python/after.py').then(res => res.text()), - Promise.resolve(document.getElementById("schemeCode").value) - ]); + // Load Python scripts + const [pre, after, scheme] = await Promise.all([ + fetch('/python/pre.py').then(res => res.text()), + fetch('/python/after.py').then(res => res.text()), + Promise.resolve(document.getElementById("schemeCode").value) + ]); - // Execute Python script - const result = await pyodide.runPythonAsync([pre, scheme, after].join("\n")); - resultTextarea.value = result; + // Execute Python script + const result = await pyodide.runPythonAsync([pre, scheme, after].join("\n")); + resultTextarea.value = result; - // Save to history - this.saveToHistory(result); - - // Auto-update CrawlFlix integration - CrawlFlixIntegration.updateAfterKeyExtraction(); - - StatusManager.show('Keys extracted successfully!', 'success'); - - } catch (error) { - console.error('Key extraction failed:', error); - StatusManager.show(`Key extraction failed: ${error.message}`, 'error'); - } finally { - // Reset UI - UIHelpers.setLoadingState(guessButton, false); - document.body.style.cursor = "auto"; - } - } + // Save to history + this.saveToHistory(result); + + // Auto-update CrawlFlix integration + CrawlFlixIntegration.updateAfterKeyExtraction(); + + StatusManager.show('Keys extracted successfully!', 'success'); + + } catch (error) { + console.error('Key extraction failed:', error); + StatusManager.show(`Key extraction failed: ${error.message}`, 'error'); + } finally { + // Reset UI + UIHelpers.setLoadingState(guessButton, false); + document.body.style.cursor = "auto"; + } + } - static saveToHistory(result) { - const historyData = { - PSSH: document.getElementById('pssh').value, - KEYS: result.split("\n").slice(0, -1) - }; - chrome.storage.local.set({[pageURL]: historyData}, null); - } + static saveToHistory(result) { + const historyData = { + PSSH: document.getElementById('pssh').value, + KEYS: result.split("\n").slice(0, -1) + }; + chrome.storage.local.set({[pageURL]: historyData}, null); + } - static async autoSelect() { - userInputs["license"] = 0; - document.getElementById("license").value = requests[0]['url']; - document.getElementById('pssh').value = psshs[0]; - - try { - const selectRules = await fetch("/selectRules.conf").then(r => r.text()); - const rules = selectRules - .replace(/\n^\s*$|\s*\/\/.*|\s*$/gm, "") - .split("\n") - .map(row => row.split("$$")); + static async autoSelect() { + userInputs["license"] = 0; + document.getElementById("license").value = requests[0]['url']; + document.getElementById('pssh').value = psshs[0]; + + try { + const selectRules = await fetch("/selectRules.conf").then(r => r.text()); + const rules = selectRules + .replace(/\n^\s*$|\s*\/\/.*|\s*$/gm, "") + .split("\n") + .map(row => row.split("$$")); - for (const item of rules) { - const search = requests.map(r => r['url']).findIndex(e => e.includes(item[0])); - if (search >= 0) { - if (item[1]) document.getElementById("schemeSelect").value = item[1]; - userInputs["license"] = search; - document.getElementById("license").value = requests[search]['url']; - break; - } - } + for (const item of rules) { + const search = requests.map(r => r['url']).findIndex(e => e.includes(item[0])); + if (search >= 0) { + if (item[1]) document.getElementById("schemeSelect").value = item[1]; + userInputs["license"] = search; + document.getElementById("license").value = requests[search]['url']; + break; + } + } - document.getElementById("schemeSelect").dispatchEvent(new Event("input")); - } catch (error) { - console.error('Auto-select failed:', error); - } - } + document.getElementById("schemeSelect").dispatchEvent(new Event("input")); + } catch (error) { + console.error('Auto-select failed:', error); + } + } } -// === SMART MPD SELECTOR === class SmartMPDSelector { static scoreAndRankMPDs(mpdUrls) { const scoredMPDs = mpdUrls.map(url => ({ @@ -359,343 +363,345 @@ class MPDDetector { // === CRAWLFLIX INTEGRATION === class CrawlFlixIntegration { - static async sendToCrawlFlix(isClearchey = false) { - const suffix = isClearchey ? 'CK' : ''; - const crawlFlixUrl = document.getElementById(`crawlFlixUrl${suffix}`).value || 'http://localhost:3000'; - const mpdUrl = document.getElementById(`mpdUrl${suffix}`).value; - const resultTextarea = document.getElementById(isClearchey ? 'ckResult' : 'result'); - - // Validation - if (!mpdUrl.trim()) { - StatusManager.show('Please enter or select an MPD URL', 'error', suffix); - return; - } - - if (!resultTextarea.value.trim()) { - StatusManager.show('No keys available to send', 'error', suffix); - return; - } - - try { - StatusManager.show('Processing MPD and sending to CrawlFlix...', 'info', suffix); - - // Parse and validate keys - const keys = this.parseKeys(resultTextarea.value); - if (keys.length === 0) { - StatusManager.show('No valid keys found in the format key:value', 'error', suffix); - return; - } + static async sendToCrawlFlix(isClearchey = false) { + const suffix = isClearchey ? 'CK' : ''; + const crawlFlixUrl = document.getElementById(`crawlFlixUrl${suffix}`).value || 'http://localhost:4200'; + const mpdUrl = document.getElementById(`mpdUrl${suffix}`).value; + const resultTextarea = document.getElementById(isClearchey ? 'ckResult' : 'result'); + + // Validation + if (!mpdUrl.trim()) { + StatusManager.show('Please enter or select an MPD URL', 'error', suffix); + return; + } + + if (!resultTextarea.value.trim()) { + StatusManager.show('No keys available to send', 'error', suffix); + return; + } + + try { + StatusManager.show('Opening CrawlFlix with preloaded data...', 'info', suffix); + + // Parse et valide les clés pour information + const keys = this.parseKeys(resultTextarea.value); + if (keys.length === 0) { + StatusManager.show('No valid keys found in the format key:value', 'error', suffix); + return; + } - // Test CrawlFlix connection and process MPD - const mpdData = await this.processMPD(crawlFlixUrl, mpdUrl); - - // Create success message - const message = `✓ Successfully sent to CrawlFlix! -${keys.length} key(s) • ${mpdData.videoTracks.length} video track(s) • ${mpdData.audioTracks.length} audio track(s) • ${mpdData.subtitles.length} subtitle(s)`; - - StatusManager.show(message, 'success', suffix); - - // Open CrawlFlix with pre-filled data - this.openCrawlFlixTab(crawlFlixUrl, mpdUrl, resultTextarea.value); - - } catch (error) { - console.error('CrawlFlix send error:', error); - StatusManager.show(`Failed to send: ${error.message}`, 'error', suffix); - } - } + // Ouvrir CrawlFlix directement avec les paramètres + this.openCrawlFlixTab(crawlFlixUrl, mpdUrl, resultTextarea.value); + + // Message de succès + const contentType = isClearchey ? 'ClearKey' : 'Widevine'; + StatusManager.show(`${contentType} data sent to CrawlFlix! (${keys.length} keys, MPD URL)`, 'success', suffix); + + } catch (error) { + console.error('CrawlFlix send error:', error); + StatusManager.show(`Failed to send: ${error.message}`, 'error', suffix); + } + } - static parseKeys(keysText) { - return keysText - .split('\n') - .map(line => line.trim()) - .filter(line => line && line.includes(':')) - .map(line => { - const [key, value] = line.split(':'); - return { - key: key?.trim(), - value: value?.trim() - }; - }) - .filter(k => k.key && k.value && k.key.length > 0 && k.value.length > 0); - } + static parseKeys(keysText) { + return keysText + .split('\n') + .map(line => line.trim()) + .filter(line => line && line.includes(':')) + .map(line => { + const [key, value] = line.split(':'); + return { + key: key?.trim(), + value: value?.trim() + }; + }) + .filter(k => k.key && k.value && k.key.length > 0 && k.value.length > 0); + } - static async processMPD(crawlFlixUrl, mpdUrl) { - const response = await fetch(`${crawlFlixUrl}/processMPD`, { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ mpdUrl }) - }); - - if (!response.ok) { - const errorText = await response.text().catch(() => 'Unknown error'); - throw new Error(`MPD processing failed (${response.status}): ${errorText}`); - } - - return await response.json(); - } + static async processMPD(crawlFlixUrl, mpdUrl) { + const response = await fetch(`${crawlFlixUrl}/processMPD`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ mpdUrl }) + }); + + if (!response.ok) { + const errorText = await response.text().catch(() => 'Unknown error'); + throw new Error(`MPD processing failed (${response.status}): ${errorText}`); + } + + return await response.json(); + } - static openCrawlFlixTab(crawlFlixUrl, mpdUrl, keysText) { - const params = new URLSearchParams({ - mpdUrl: mpdUrl, - keys: keysText, - source: 'widevine-plugin' - }); - - const crawlFlixTab = `${crawlFlixUrl}?${params.toString()}`; - chrome.tabs.create({ url: crawlFlixTab }); - } + static openCrawlFlixTab(crawlFlixUrl, mpdUrl, keysText) { + // Encoder les données pour l'URL + const params = new URLSearchParams({ + mpdUrl: mpdUrl, + keys: keysText, + autoLoad: 'true' + }); + + // Ouvrir CrawlFlix avec les paramètres pré-remplis + const crawlFlixTab = `${crawlFlixUrl}?${params.toString()}`; + chrome.tabs.create({ url: crawlFlixTab }); + + console.log('Opening CrawlFlix with preloaded data:', crawlFlixTab); + } - static copyKeys(resultTextareaId) { - const textarea = document.getElementById(resultTextareaId); - if (!textarea || !textarea.value.trim()) { - StatusManager.show('No keys to copy', 'error'); - return; - } + static copyKeys(resultTextareaId) { + const textarea = document.getElementById(resultTextareaId); + if (!textarea || !textarea.value.trim()) { + StatusManager.show('No keys to copy', 'error'); + return; + } - navigator.clipboard.writeText(textarea.value).then(() => { - StatusManager.show('Keys copied to clipboard!', 'success'); - }).catch(err => { - console.error('Copy failed:', err); - StatusManager.show('Failed to copy keys', 'error'); - }); - } + navigator.clipboard.writeText(textarea.value).then(() => { + StatusManager.show('Keys copied to clipboard!', 'success'); + }).catch(err => { + console.error('Copy failed:', err); + StatusManager.show('Failed to copy keys', 'error'); + }); + } - static updateAfterKeyExtraction() { - // Auto-refresh MPD detection after key extraction - setTimeout(() => { - MPDDetector.updateDropdowns(); - }, 1000); - } + static updateAfterKeyExtraction() { + // Auto-refresh MPD detection after key extraction + setTimeout(() => { + MPDDetector.updateDropdowns(); + }, 1000); + } - static loadSavedSettings() { - chrome.storage.local.get(['crawlFlixUrl'], (result) => { - if (result.crawlFlixUrl) { - const inputs = ['crawlFlixUrl', 'crawlFlixUrlCK']; - inputs.forEach(id => { - const input = document.getElementById(id); - if (input && !input.value) { - input.value = result.crawlFlixUrl; - } - }); - } - }); - } + static loadSavedSettings() { + chrome.storage.local.get(['crawlFlixUrl'], (result) => { + if (result.crawlFlixUrl) { + const inputs = ['crawlFlixUrl', 'crawlFlixUrlCK']; + inputs.forEach(id => { + const input = document.getElementById(id); + if (input && !input.value) { + input.value = result.crawlFlixUrl; + } + }); + } + }); + } - static saveSettings() { - const inputs = ['crawlFlixUrl', 'crawlFlixUrlCK']; - inputs.forEach(id => { - const input = document.getElementById(id); - if (input) { - input.addEventListener('change', (e) => { - chrome.storage.local.set({ crawlFlixUrl: e.target.value }); - }); - } - }); - } + static saveSettings() { + const inputs = ['crawlFlixUrl', 'crawlFlixUrlCK']; + inputs.forEach(id => { + const input = document.getElementById(id); + if (input) { + input.addEventListener('change', (e) => { + chrome.storage.local.set({ crawlFlixUrl: e.target.value }); + }); + } + }); + } } // === STATUS MANAGER === class StatusManager { - static show(message, type, suffix = '') { - const statusDiv = document.getElementById(`crawlFlixStatus${suffix}`); - if (!statusDiv) return; + static show(message, type, suffix = '') { + const statusDiv = document.getElementById(`crawlFlixStatus${suffix}`); + if (!statusDiv) return; - // Clear any existing content - statusDiv.innerHTML = ''; + // Clear any existing content + statusDiv.innerHTML = ''; - // Create alert element - const alert = document.createElement('div'); - alert.className = `alert alert-${this.getBootstrapClass(type)} alert-dismissible fade show`; - alert.innerHTML = ` - - ${message.replace(/\n/g, '
')} - - `; - - statusDiv.appendChild(alert); + // Create alert element + const alert = document.createElement('div'); + alert.className = `alert alert-${this.getBootstrapClass(type)} alert-dismissible fade show`; + alert.innerHTML = ` + + ${message.replace(/\n/g, '
')} + + `; + + statusDiv.appendChild(alert); - // Auto-dismiss after delay - if (type === 'success' || type === 'info') { - setTimeout(() => { - if (alert.parentNode) { - alert.classList.remove('show'); - setTimeout(() => alert.remove(), 300); - } - }, 5000); - } - } + // Auto-dismiss after delay + if (type === 'success' || type === 'info') { + setTimeout(() => { + if (alert.parentNode) { + alert.classList.remove('show'); + setTimeout(() => alert.remove(), 300); + } + }, 5000); + } + } - static getBootstrapClass(type) { - const mapping = { - success: 'success', - error: 'danger', - info: 'info', - warning: 'warning' - }; - return mapping[type] || 'secondary'; - } + static getBootstrapClass(type) { + const mapping = { + success: 'success', + error: 'danger', + info: 'info', + warning: 'warning' + }; + return mapping[type] || 'secondary'; + } - static getIcon(type) { - const mapping = { - success: 'fa-check-circle', - error: 'fa-exclamation-triangle', - info: 'fa-info-circle', - warning: 'fa-exclamation-triangle' - }; - return mapping[type] || 'fa-info'; - } + static getIcon(type) { + const mapping = { + success: 'fa-check-circle', + error: 'fa-exclamation-triangle', + info: 'fa-info-circle', + warning: 'fa-exclamation-triangle' + }; + return mapping[type] || 'fa-info'; + } } // === UI HELPERS === class UIHelpers { - static setLoadingState(button, isLoading) { - if (!button) return; - - if (isLoading) { - button.disabled = true; - const originalText = button.innerHTML; - button.dataset.originalText = originalText; - button.innerHTML = 'Extracting Keys...'; - } else { - button.disabled = false; - button.innerHTML = button.dataset.originalText || button.innerHTML; - } - } + static setLoadingState(button, isLoading) { + if (!button) return; + + if (isLoading) { + button.disabled = true; + const originalText = button.innerHTML; + button.dataset.originalText = originalText; + button.innerHTML = 'Extracting Keys...'; + } else { + button.disabled = false; + button.innerHTML = ' Extract Widevine Keys'; + } + } - static copyToClipboard(text) { - const textarea = document.createElement('textarea'); - textarea.value = text; - document.body.appendChild(textarea); - textarea.select(); - document.execCommand('copy'); - document.body.removeChild(textarea); - } + static copyToClipboard(text) { + const textarea = document.createElement('textarea'); + textarea.value = text; + document.body.appendChild(textarea); + textarea.select(); + document.execCommand('copy'); + document.body.removeChild(textarea); + } } // === EVENT LISTENERS === class EventManager { - static init() { - this.setupWidevineListeners(); - this.setupCrawlFlixListeners(); - this.setupUIListeners(); - } + static init() { + this.setupWidevineListeners(); + this.setupCrawlFlixListeners(); + this.setupUIListeners(); + } - static setupWidevineListeners() { - const guessButton = document.getElementById('guess'); - const resultTextarea = document.getElementById('result'); - - if (guessButton) { - guessButton.addEventListener('click', () => WidevineExtractor.extractKeys()); - } - - if (resultTextarea) { - resultTextarea.addEventListener('click', function() { - this.select(); - navigator.clipboard.writeText(this.value); - }); - } - } + static setupWidevineListeners() { + const guessButton = document.getElementById('guess'); + const resultTextarea = document.getElementById('result'); + + if (guessButton) { + guessButton.addEventListener('click', () => WidevineExtractor.extractKeys()); + } + + if (resultTextarea) { + resultTextarea.addEventListener('click', function() { + this.select(); + navigator.clipboard.writeText(this.value); + }); + } + } - static setupCrawlFlixListeners() { - // Dropdown selections - ['mpdSelect', 'mpdSelectCK'].forEach(selectId => { - const select = document.getElementById(selectId); - const urlInput = document.getElementById(selectId.replace('Select', 'Url')); - if (select && urlInput) { - select.addEventListener('change', (e) => { - if (e.target.value) { - urlInput.value = e.target.value; - } - }); - } - }); + static setupCrawlFlixListeners() { + // Dropdown selections + ['mpdSelect', 'mpdSelectCK'].forEach(selectId => { + const select = document.getElementById(selectId); + const urlInput = document.getElementById(selectId.replace('Select', 'Url')); + if (select && urlInput) { + select.addEventListener('change', (e) => { + if (e.target.value) { + urlInput.value = e.target.value; + } + }); + } + }); - // Refresh buttons - ['refreshMPDs', 'refreshMPDsCK'].forEach(buttonId => { - const button = document.getElementById(buttonId); - if (button) { - button.addEventListener('click', () => MPDDetector.updateDropdowns()); - } - }); + // Refresh buttons + ['refreshMPDs', 'refreshMPDsCK'].forEach(buttonId => { + const button = document.getElementById(buttonId); + if (button) { + button.addEventListener('click', () => MPDDetector.updateDropdowns()); + } + }); - // Send buttons - const sendButton = document.getElementById('sendToCrawlFlix'); - if (sendButton) { - sendButton.addEventListener('click', () => CrawlFlixIntegration.sendToCrawlFlix(false)); - } + // Send buttons + const sendButton = document.getElementById('sendToCrawlFlix'); + if (sendButton) { + sendButton.addEventListener('click', () => CrawlFlixIntegration.sendToCrawlFlix(false)); + } - const sendButtonCK = document.getElementById('sendToCrawlFlixCK'); - if (sendButtonCK) { - sendButtonCK.addEventListener('click', () => CrawlFlixIntegration.sendToCrawlFlix(true)); - } + const sendButtonCK = document.getElementById('sendToCrawlFlixCK'); + if (sendButtonCK) { + sendButtonCK.addEventListener('click', () => CrawlFlixIntegration.sendToCrawlFlix(true)); + } - // Copy buttons - const copyButton = document.getElementById('copyKeys'); - if (copyButton) { - copyButton.addEventListener('click', () => CrawlFlixIntegration.copyKeys('result')); - } + // Copy buttons + const copyButton = document.getElementById('copyKeys'); + if (copyButton) { + copyButton.addEventListener('click', () => CrawlFlixIntegration.copyKeys('result')); + } - const copyButtonCK = document.getElementById('copyKeysCK'); - if (copyButtonCK) { - copyButtonCK.addEventListener('click', () => CrawlFlixIntegration.copyKeys('ckResult')); - } - } + const copyButtonCK = document.getElementById('copyKeysCK'); + if (copyButtonCK) { + copyButtonCK.addEventListener('click', () => CrawlFlixIntegration.copyKeys('ckResult')); + } + } - static setupUIListeners() { - // ClearKey result click handler - const ckResult = document.getElementById('ckResult'); - if (ckResult) { - ckResult.addEventListener('click', function() { - this.select(); - navigator.clipboard.writeText(this.value); - }); - } - } + static setupUIListeners() { + // ClearKey result click handler + const ckResult = document.getElementById('ckResult'); + if (ckResult) { + ckResult.addEventListener('click', function() { + this.select(); + navigator.clipboard.writeText(this.value); + }); + } + } } // === CORS FETCH HELPER === window.corsFetch = (u, m, h, b) => { - return new Promise((resolve, reject) => { - chrome.tabs.sendMessage(targetIds[0], { - type: "FETCH", - u: u, - m: m, - h: h, - b: b - }, {frameId: targetIds[1]}, res => { - resolve(res); - }); - }); + return new Promise((resolve, reject) => { + chrome.tabs.sendMessage(targetIds[0], { + type: "FETCH", + u: u, + m: m, + h: h, + b: b + }, {frameId: targetIds[1]}, res => { + resolve(res); + }); + }); }; // === INITIALIZATION === document.addEventListener('DOMContentLoaded', () => { - EventManager.init(); - CrawlFlixIntegration.loadSavedSettings(); - CrawlFlixIntegration.saveSettings(); + EventManager.init(); + CrawlFlixIntegration.loadSavedSettings(); + CrawlFlixIntegration.saveSettings(); }); // Main initialization logic if (clearkey) { - // ClearKey detected - document.getElementById('noEME').style.display = 'none'; - document.getElementById('ckHome').style.display = 'block'; - document.getElementById('ckResult').value = clearkey; - - MPDDetector.updateDropdowns(); - StatusManager.show('ClearKey content detected', 'success'); - MPDDetector.updateBadgeFromPopup(); + // ClearKey detected + document.getElementById('noEME').style.display = 'none'; + document.getElementById('ckHome').style.display = 'block'; + document.getElementById('ckResult').value = clearkey; + + MPDDetector.updateDropdowns(); + StatusManager.show('ClearKey content detected', 'success'); + } else if (psshs.length) { - // Widevine detected - document.getElementById('noEME').style.display = 'none'; - document.getElementById('home').style.display = 'block'; - - WidevineExtractor.autoSelect(); - MPDDetector.updateDropdowns(); - StatusManager.show('Widevine content detected', 'success'); - MPDDetector.updateBadgeFromPopup(); - // Auto-refresh MPD detection periodically - setInterval(() => { - MPDDetector.updateDropdowns(); - }, 3000); + // Widevine detected + document.getElementById('noEME').style.display = 'none'; + document.getElementById('home').style.display = 'block'; + + // IMPORTANT: Faire autoSelect avant d'initialiser les event listeners + WidevineExtractor.autoSelect().then(() => { + EventManager.init(); + MPDDetector.updateDropdowns(); + StatusManager.show('Widevine content detected and configured', 'success'); + }); + + // Auto-refresh MPD detection periodically + setInterval(() => { + MPDDetector.updateDropdowns(); + }, 3000); } \ No newline at end of file