import { AsyncLocalStorage, DeviceManager, RemoteCDMManager, SettingsManager, Util } from "../lib/util.js"; const key_container = document.getElementById('key-container'); // ================ Main ================ const enabled = document.getElementById('enabled'); enabled.addEventListener('change', async function (){ await SettingsManager.setEnabled(enabled.checked); }); const toggle = document.getElementById('darkModeToggle'); toggle.addEventListener('change', async () => { SettingsManager.setDarkMode(toggle.checked); await SettingsManager.saveDarkMode(toggle.checked); }); const wvd_select = document.getElementById('wvd_select'); wvd_select.addEventListener('change', async function (){ if (wvd_select.checked) { await SettingsManager.saveSelectedDeviceType("WVD"); } }); const remote_select = document.getElementById('remote_select'); remote_select.addEventListener('change', async function (){ if (remote_select.checked) { await SettingsManager.saveSelectedDeviceType("REMOTE"); } }); const export_button = document.getElementById('exportLogs'); export_button.addEventListener('click', async function() { const logs = await AsyncLocalStorage.getStorage(null); SettingsManager.downloadFile(new Blob([JSON.stringify(logs)], { type: "application/json;charset=utf-8" }), "logs.json"); }); const clear_logs = document.getElementById('clearLogs'); clear_logs.addEventListener('click', function() { AsyncLocalStorage.clearStorage(); }); // ====================================== // ================ Widevine Device ================ const fileInput = document.getElementById('fileInput'); fileInput.addEventListener('click', () => { if ("ontouchstart" in window || navigator.maxTouchPoints > 0) { chrome.runtime.sendMessage({ type: "OPEN_PICKER_WVD_MOBILE" }); } else { chrome.runtime.sendMessage({ type: "OPEN_PICKER_WVD" }); } window.close(); }); const remove = document.getElementById('remove'); remove.addEventListener('click', async function() { await DeviceManager.removeSelectedWidevineDevice(); wvd_combobox.innerHTML = ''; await DeviceManager.loadSetAllWidevineDevices(); const selected_option = wvd_combobox.options[wvd_combobox.selectedIndex]; if (selected_option) { await DeviceManager.saveSelectedWidevineDevice(selected_option.text); } else { await DeviceManager.removeSelectedWidevineDeviceKey(); } }); const download = document.getElementById('download'); download.addEventListener('click', async function() { const widevine_device = await DeviceManager.getSelectedWidevineDevice(); SettingsManager.downloadFile( Util.b64.decode(await DeviceManager.loadWidevineDevice(widevine_device)), widevine_device + ".wvd" ) }); const wvd_combobox = document.getElementById('wvd-combobox'); wvd_combobox.addEventListener('change', async function() { await DeviceManager.saveSelectedWidevineDevice(wvd_combobox.options[wvd_combobox.selectedIndex].text); }); // ================================================= // ================ Remote CDM ================ document.getElementById('remoteInput').addEventListener('click', () => { if ("ontouchstart" in window || navigator.maxTouchPoints > 0) { chrome.runtime.sendMessage({ type: "OPEN_PICKER_REMOTE_MOBILE" }); } else { chrome.runtime.sendMessage({ type: "OPEN_PICKER_REMOTE" }); } window.close(); }); const remote_remove = document.getElementById('remoteRemove'); remote_remove.addEventListener('click', async function() { await RemoteCDMManager.removeSelectedRemoteCDM(); remote_combobox.innerHTML = ''; await RemoteCDMManager.loadSetAllRemoteCDMs(); const selected_option = remote_combobox.options[remote_combobox.selectedIndex]; if (selected_option) { await RemoteCDMManager.saveSelectedRemoteCDM(selected_option.text); } else { await RemoteCDMManager.removeSelectedRemoteCDMKey(); } }); const remote_download = document.getElementById('remoteDownload'); remote_download.addEventListener('click', async function() { const remote_cdm = await RemoteCDMManager.getSelectedRemoteCDM(); SettingsManager.downloadFile( await RemoteCDMManager.loadRemoteCDM(remote_cdm), remote_cdm + ".json" ) }); const remote_combobox = document.getElementById('remote-combobox'); remote_combobox.addEventListener('change', async function() { await RemoteCDMManager.saveSelectedRemoteCDM(remote_combobox.options[remote_combobox.selectedIndex].text); }); // ============================================ // ================ Command Options ================ const use_shaka = document.getElementById('use-shaka'); use_shaka.addEventListener('change', async function (){ await SettingsManager.saveUseShakaPackager(use_shaka.checked); }); const use_single_quotes = document.getElementById('use-single-quotes'); use_single_quotes.addEventListener('change', async function (){ await SettingsManager.saveUseSingleQuotes(use_single_quotes.checked); }); const downloader_name = document.getElementById('downloader-name'); downloader_name.addEventListener('input', async function (){ await SettingsManager.saveExecutableName(downloader_name.value); }); const downloader_args = document.getElementById('downloader-args'); downloader_args.addEventListener('input', async function (){ await SettingsManager.saveAdditionalArguments(downloader_args.value); }); // ================================================= // ================ Keys ================ const clear = document.getElementById('clear'); clear.addEventListener('click', async function() { chrome.runtime.sendMessage({ type: "CLEAR" }); key_container.innerHTML = ""; }); async function createCommand(json, key_string) { const metadata = JSON.parse(json); // Based on user choice in the panel, we have the quote character that should be used in the command, // and a safe quote character that can be used to format the header values. const useSingleQuotes = await SettingsManager.getUseSingleQuotes(); const quoteChar = useSingleQuotes ? "'" : '"'; const safeQuoteChar = useSingleQuotes ? '"' : "'"; const headerString = Object.entries(metadata.headers).map( ([key, value]) => `-H ${quoteChar}${key}: ${value.replaceAll(quoteChar, safeQuoteChar)}${quoteChar}` ).join(' '); const executableName = await SettingsManager.getExecutableName(); const useShaka = await SettingsManager.getUseShakaPackager(); const additionalArgs = await SettingsManager.getAdditionalArguments(); return `${executableName} ${quoteChar}${metadata.url}${quoteChar} ${headerString} ${key_string} ${useShaka ? "--use-shaka-packager " : ""}${additionalArgs}`; } async function appendLog(result) { const key_string = result.keys.map(key => `--key ${key.kid}:${key.k}`).join(' '); const date = new Date(result.timestamp * 1000); const date_string = date.toLocaleString(); const logContainer = document.createElement('div'); logContainer.classList.add('log-container'); logContainer.innerHTML = `
`; const keysInput = logContainer.querySelector('.key-copy'); keysInput.addEventListener('click', () => { navigator.clipboard.writeText(key_string); }); if (result.manifests.length > 0) { const command = logContainer.querySelector('#command'); const select = logContainer.querySelector("#manifest"); select.addEventListener('change', async () => { command.value = await createCommand(select.value, key_string); }); result.manifests.forEach((manifest) => { const option = new Option(`[${manifest.type}] ${manifest.url}`, JSON.stringify(manifest)); select.add(option); }); command.value = await createCommand(select.value, key_string); const manifest_copy = logContainer.querySelector('.manifest-copy'); manifest_copy.addEventListener('click', () => { navigator.clipboard.writeText(JSON.parse(select.value).url); }); const command_copy = logContainer.querySelector('.command-copy'); command_copy.addEventListener('click', () => { navigator.clipboard.writeText(command.value); }); } const toggleButtons = logContainer.querySelector('.toggleButton'); toggleButtons.addEventListener('click', function () { const expandableDiv = this.nextElementSibling; if (expandableDiv.classList.contains('collapsed')) { toggleButtons.innerHTML = "-"; expandableDiv.classList.remove('collapsed'); expandableDiv.classList.add('expanded'); } else { toggleButtons.innerHTML = "+"; expandableDiv.classList.remove('expanded'); expandableDiv.classList.add('collapsed'); } }); key_container.appendChild(logContainer); } chrome.storage.onChanged.addListener(async (changes, areaName) => { if (areaName === 'local') { for (const [key, values] of Object.entries(changes)) { await appendLog(values.newValue); } } }); function checkLogs() { chrome.runtime.sendMessage({ type: "GET_LOGS" }, (response) => { if (response) { response.forEach(async (result) => { await appendLog(result); }); } }); } document.addEventListener('DOMContentLoaded', async function () { enabled.checked = await SettingsManager.getEnabled(); SettingsManager.setDarkMode(await SettingsManager.getDarkMode()); use_shaka.checked = await SettingsManager.getUseShakaPackager(); use_single_quotes.checked = await SettingsManager.getUseSingleQuotes(); downloader_name.value = await SettingsManager.getExecutableName(); downloader_args.value = await SettingsManager.getAdditionalArguments(); SettingsManager.setSelectedDeviceType(await SettingsManager.getSelectedDeviceType()); await DeviceManager.loadSetAllWidevineDevices(); await DeviceManager.selectWidevineDevice(await DeviceManager.getSelectedWidevineDevice()); await RemoteCDMManager.loadSetAllRemoteCDMs(); await RemoteCDMManager.selectRemoteCDM(await RemoteCDMManager.getSelectedRemoteCDM()); checkLogs(); }); // ======================================