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