diff --git a/README.md b/README.md index 54c2542..0b501e8 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,20 @@ Modifies the challenge before it reaches the web player and retrieves the decryp + Supports Widevine Device files + Manifest V3 compliant +--- +
+

OLD UI

+ Old +
+ + +
+

NEW UI

+ New +
+ +--- + ## Widevine Devices This addon requires a Widevine Device file to work, which is not provided by this project. + Use an existing Remote CDM like [this one](https://github.com/user-attachments/files/19639399/remote.json) diff --git a/images/icon-128.png b/images/icon-128.png index 4938138..103fe83 100644 Binary files a/images/icon-128.png and b/images/icon-128.png differ diff --git a/imgs/new.png b/imgs/new.png new file mode 100644 index 0000000..f5c86f5 Binary files /dev/null and b/imgs/new.png differ diff --git a/imgs/old.png b/imgs/old.png new file mode 100644 index 0000000..0b41b38 Binary files /dev/null and b/imgs/old.png differ diff --git a/panel/panel.css b/panel/panel.css index ef1f017..a0fed09 100644 --- a/panel/panel.css +++ b/panel/panel.css @@ -1,65 +1,162 @@ +:root { + --font-family-sans-serif: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; + --font-weight-normal: 400; + --font-weight-bold: 600; + --border-radius: 0.375rem; + --shadow-sm: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075); + + --color-bg: #f8f9fa; + --color-bg-inset: #ffffff; + --color-text: #212529; + --color-text-muted: #6c757d; + --color-border: #dee2e6; + --color-accent: #0d6efd; + --color-input-bg: #ffffff; + --color-input-focus-border: #86b7fe; + --color-danger-bg: #dc3545; + --color-danger-border: #dc3545; + --color-danger-hover-bg: #bb2d3b; + --color-danger-hover-border: #b02a37; +} + +.dark-mode { + --color-bg: #212529; + --color-bg-inset: #2c3136; + --color-text: #e9ecef; + --color-text-muted: #adb5bd; + --color-border: #495057; + --color-accent: #3b82f6; + --color-input-bg: #343a40; + --color-input-focus-border: #528BFF; + --color-danger-bg: #842029; + --color-danger-border: #842029; + --color-danger-hover-bg: #972e3a; + --color-danger-hover-border: #8f2c38; +} + body { - font-family: Arial, sans-serif; - background-color: #ffffff; - color: black; + font-family: var(--font-family-sans-serif); + background-color: var(--color-bg); + color: var(--color-text); width: 400px; + padding: 0.75rem; + box-sizing: border-box; } -.toggleButton { - width: 24px; + + +.header { + display: flex; + justify-content: center; + align-items: center; + gap: 0.5rem; + margin-bottom: 0.75rem; +} + +fieldset { + background-color: var(--color-bg-inset); + border: 1px solid var(--color-border); + border-radius: var(--border-radius); + padding: 0.75rem 1rem; + margin-bottom: 0.75rem; + box-shadow: var(--shadow-sm); +} + +fieldset legend { + font-weight: var(--font-weight-bold); + padding: 0 0.5em; + color: var(--color-text-muted); + font-size: 0.875rem; +} + +#wvd, #remote { + display: none; } -select { - max-width: 330px; + +button, +select, +input[type="text"] { + display: inline-block; + font-family: inherit; + font-size: 0.875rem; + color: var(--color-text); + background-color: var(--color-input-bg); + border: 1px solid var(--color-border); + border-radius: var(--border-radius); + padding: 0.375rem 0.75rem; + transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; + box-sizing: border-box; } -.text-box { - outline: none; - width: 80%; + +button { + cursor: pointer; + background-color: var(--color-bg); } -#downloader-name { - width: 160px; + +button:hover { + border-color: var(--color-accent); } -#export { - margin-top: 5px; + +select, +input[type="text"] { + width: 100%; } +select:focus, +input[type="text"]:focus { + outline: 0; + border-color: var(--color-input-focus-border); + box-shadow: 0 0 0 0.25rem rgba(var(--color-accent), 0.25); +} -/* Dark mode */ -.dark-mode { - background-color: #1b1b1b; - color: #D5D5D5; +.button-group { + display: flex; + gap: 0.5rem; + margin-bottom: 0.5rem; } -.dark-mode fieldset { - border-color: #535353; + +#clear { + width: 100%; + margin-bottom: 0.5rem; + background-color: var(--color-danger-bg); + border-color: var(--color-danger-border); + color: white; +} +#clear:hover{ + background-color: var(--color-danger-hover-bg); + border-color: var(--color-danger-hover-border); +} + +#settings-grid { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 0.5rem 1rem; + align-items: center; } -.dark-mode button, .dark-mode select { - background-color: #222; - color: #D5D5D5; +#settings-grid > label, #settings-grid > div { + display: flex; + align-items: center; + gap: 0.5rem; } -.dark-mode button:hover, .dark-mode select:hover { - background-color: #323232; +#settings-grid > div { + flex-direction: column; + align-items: flex-start; } -.dark-mode .expandableDiv { - background-color: #1b2027; +label { + user-select: none; + font-size: 0.875rem; } -.dark-mode .text-box { - background-color: #323232; - color: #D5D5D5; +input[type="checkbox"], input[type="radio"] { + margin: 0; } -/* Switch */ .switch { position: relative; display: inline-block; - width: 40px; + width: 34px; height: 20px; - margin-left: 10px; -} -.switch input { - opacity: 0; - width: 0; - height: 0; + flex-shrink: 0; } - -/* Slider */ +.switch input { opacity: 0; width: 0; height: 0; } .slider { position: absolute; cursor: pointer; @@ -67,7 +164,7 @@ select { left: 0; right: 0; bottom: 0; - background-color: #ccc; + background-color: var(--color-border); transition: 0.4s; border-radius: 20px; } @@ -80,65 +177,45 @@ select { bottom: 3px; background-color: white; border-radius: 50%; + transition: 0.4s; } -input:checked + .slider { - background-color: #2196F3; -} -input:checked + .slider:before { - transform: translateX(20px); -} - -#clear { - width: 100%; - margin-bottom: 3px; -} - -#type-select { - margin-left: auto; -} - -#settings { - display: flex; -} - -.header { - display: flex; - justify-content: center; - align-items: center; -} -.header > * { - margin: 5px; -} +input:checked + .slider { background-color: var(--color-accent); } +input:checked + .slider:before { transform: translateX(14px); } -#wvd > *, #remote > * { - margin: 5px; -} +#key-container { display: flex; flex-direction: column; gap: 0.5rem; } .log-container { display: flex; - justify-content: center; -} -.right-bound { - text-align: right; + align-items: flex-start; + gap: 0.5rem; + background-color: var(--color-bg); + border: 1px solid var(--color-border); + border-radius: var(--border-radius); + padding: 0.5rem; } -.expandableDiv { - width: 100%; - overflow: hidden; - background-color: lightblue; - padding: 0; -} -.expandableDiv.expanded { - padding: 5px; -} -.expandableDiv.collapsed { +.toggleButton { + flex-shrink: 0; + width: 24px; + height: 24px; padding: 0; + font-family: monospace; + font-size: 1rem; } -.always-visible { - display: block; +.expandableDiv { width: 100%; overflow: hidden; display: flex; flex-direction: column; gap: 0.5rem; } +.expandableDiv label { + display: grid; + grid-template-columns: 60px 1fr; + align-items: center; + gap: 0.5rem; + width: 100%; } -.expanded-only { - display: none; +.expandableDiv label > a { + color: var(--color-accent); + text-decoration: none; + cursor: pointer; + font-weight: var(--font-weight-bold); + text-align: right; + justify-self: end; } -.expandableDiv.expanded .expanded-only { - display: block; -} \ No newline at end of file +.expandableDiv label a:hover { text-decoration: underline; } +.expandableDiv.collapsed .expanded-only { display: none; } \ No newline at end of file diff --git a/panel/panel.html b/panel/panel.html index a20599a..3c930e5 100644 --- a/panel/panel.html +++ b/panel/panel.html @@ -1,71 +1,86 @@ + - + WidevineProxy + - + + +
- WidevineProxy Icon - ProxyText + WidevineProxy Icon + ProxyText
+
Settings -
- -
- - -
- -
-
+ +
+ Remote CDM +
-
- -
-
- Command options - -
- - -
- + + + +
- Keys - + Logs +
+
+ - + + \ No newline at end of file diff --git a/panel/panel.js b/panel/panel.js index 659b312..296ecc2 100644 --- a/panel/panel.js +++ b/panel/panel.js @@ -1,241 +1,298 @@ import "../protobuf.min.js"; import "../license_protocol.js"; -import {AsyncLocalStorage, base64toUint8Array, stringToUint8Array, DeviceManager, RemoteCDMManager, SettingsManager} from "../util.js"; +import { + AsyncLocalStorage, + base64toUint8Array, + stringToUint8Array, + DeviceManager, + RemoteCDMManager, + SettingsManager, +} from "../util.js"; -const key_container = document.getElementById('key-container'); +const key_container = document.getElementById("key-container"); -// ================ Main ================ -const enabled = document.getElementById('enabled'); -enabled.addEventListener('change', async function (){ - await SettingsManager.setEnabled(enabled.checked); +function updateThemeVisuals(isDarkMode) { + document.body.classList.toggle("dark-mode", isDarkMode); + const textImage = document.getElementById("textImage"); + if (textImage) { + textImage.src = isDarkMode + ? "../images/proxy_text_dark.png" + : "../images/proxy_text.png"; + } +} + +function updateDeviceFieldsetVisibility() { + const wvd_select = document.getElementById("wvd_select"); + document.getElementById("wvd").style.display = wvd_select.checked + ? "block" + : "none"; + document.getElementById("remote").style.display = wvd_select.checked + ? "none" + : "block"; +} + +const enabled = document.getElementById("enabled"); +enabled.addEventListener("change", async function () { + await SettingsManager.setEnabled(enabled.checked); }); -const toggle = document.getElementById('darkModeToggle'); -toggle.addEventListener('change', async () => { - await SettingsManager.setDarkMode(toggle.checked); - await SettingsManager.saveDarkMode(toggle.checked); +const toggle = document.getElementById("darkModeToggle"); +toggle.addEventListener("change", async () => { + await SettingsManager.saveDarkMode(toggle.checked); + updateThemeVisuals(toggle.checked); }); -const wvd_select = document.getElementById('wvd_select'); -wvd_select.addEventListener('change', async function (){ - if (wvd_select.checked) { - await SettingsManager.saveSelectedDeviceType("WVD"); - } +const wvd_select = document.getElementById("wvd_select"); +wvd_select.addEventListener("change", async function () { + if (wvd_select.checked) { + await SettingsManager.saveSelectedDeviceType("WVD"); + updateDeviceFieldsetVisibility(); + } }); -const remote_select = document.getElementById('remote_select'); -remote_select.addEventListener('change', async function (){ - if (remote_select.checked) { - await SettingsManager.saveSelectedDeviceType("REMOTE"); - } +const remote_select = document.getElementById("remote_select"); +remote_select.addEventListener("change", async function () { + if (remote_select.checked) { + await SettingsManager.saveSelectedDeviceType("REMOTE"); + updateDeviceFieldsetVisibility(); + } }); -const export_button = document.getElementById('export'); -export_button.addEventListener('click', async function() { - const logs = await AsyncLocalStorage.getStorage(null); - SettingsManager.downloadFile(stringToUint8Array(JSON.stringify(logs)), "logs.json"); +const export_button = document.getElementById("export"); +export_button.addEventListener("click", async function () { + const logs = await AsyncLocalStorage.getStorage(null); + SettingsManager.downloadFile( + stringToUint8Array(JSON.stringify(logs)), + "logs.json" + ); }); -// ====================================== -// ================ Widevine Device ================ -document.getElementById('fileInput').addEventListener('click', () => { - chrome.runtime.sendMessage({ type: "OPEN_PICKER_WVD" }); - window.close(); +document.getElementById("fileInput").addEventListener("click", () => { + 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 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( - base64toUint8Array(await DeviceManager.loadWidevineDevice(widevine_device)), - widevine_device + ".wvd" - ) +const download = document.getElementById("download"); +download.addEventListener("click", async function () { + const widevine_device = await DeviceManager.getSelectedWidevineDevice(); + SettingsManager.downloadFile( + base64toUint8Array(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); +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', () => { - chrome.runtime.sendMessage({ type: "OPEN_PICKER_REMOTE" }); - window.close(); +document.getElementById("remoteInput").addEventListener("click", () => { + 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_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_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); +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_shaka = document.getElementById("use-shaka"); +use_shaka.addEventListener("change", async function () { + await SettingsManager.saveUseShakaPackager(use_shaka.checked); }); -const downloader_name = document.getElementById('downloader-name'); -downloader_name.addEventListener('input', async function (event){ - console.log("input change", event); - await SettingsManager.saveExecutableName(downloader_name.value); +const downloader_name = document.getElementById("downloader-name"); +downloader_name.addEventListener("input", async function (event) { + await SettingsManager.saveExecutableName(downloader_name.value); }); -// ================================================= -// ================ Keys ================ -const clear = document.getElementById('clear'); -clear.addEventListener('click', async function() { - chrome.runtime.sendMessage({ type: "CLEAR" }); - key_container.innerHTML = ""; +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); - const header_string = Object.entries(metadata.headers).map(([key, value]) => `-H "${key}: ${value.replace(/"/g, "'")}"`).join(' '); - return `${await SettingsManager.getExecutableName()} "${metadata.url}" ${header_string} ${key_string} ${await SettingsManager.getUseShakaPackager() ? "--use-shaka-packager " : ""}-M format=mkv`; + const metadata = JSON.parse(json); + const header_string = Object.entries(metadata.headers) + .map(([key, value]) => `-H "${key}: ${value.replace(/"/g, "'")}"`) + .join(" "); + return `${await SettingsManager.getExecutableName()} "${ + metadata.url + }" ${header_string} ${key_string} ${ + (await SettingsManager.getUseShakaPackager()) ? "--use-shaka-packager " : "" + }-M format=mkv`; } 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 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 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); - }); - } + logContainer.querySelector(".key-copy > a").addEventListener("click", (e) => { + e.preventDefault(); + navigator.clipboard.writeText(key_string); + }); - 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'); - } + if (result.manifests.length > 0) { + const commandInput = logContainer.querySelector(".command-copy input"); + const select = logContainer.querySelector(".manifest-copy select"); + const updateCommand = async () => { + commandInput.value = await createCommand(select.value, key_string); + }; + select.addEventListener("change", updateCommand); + result.manifests.forEach((manifest) => { + const option = new Option( + `[${manifest.type}] ${manifest.url}`, + JSON.stringify(manifest) + ); + select.add(option); }); + updateCommand(); + logContainer + .querySelector(".manifest-copy > a") + .addEventListener("click", (e) => { + e.preventDefault(); + navigator.clipboard.writeText(JSON.parse(select.value).url); + }); + logContainer + .querySelector(".command-copy > a") + .addEventListener("click", (e) => { + e.preventDefault(); + navigator.clipboard.writeText(commandInput.value); + }); + } - key_container.appendChild(logContainer); + const toggleButtons = logContainer.querySelector(".toggleButton"); + toggleButtons.addEventListener("click", function () { + const expandableDiv = this.nextElementSibling; + if (expandableDiv.classList.contains("collapsed")) { + this.innerHTML = "-"; + expandableDiv.classList.remove("collapsed"); + } else { + this.innerHTML = "+"; + 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); - } + 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); - }); - } - }); + 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(); - downloader_name.value = await SettingsManager.getExecutableName(); - await SettingsManager.setSelectedDeviceType(await SettingsManager.getSelectedDeviceType()); - await DeviceManager.loadSetAllWidevineDevices(); - await DeviceManager.selectWidevineDevice(await DeviceManager.getSelectedWidevineDevice()); - await RemoteCDMManager.loadSetAllRemoteCDMs(); - await RemoteCDMManager.selectRemoteCDM(await RemoteCDMManager.getSelectedRemoteCDM()); - checkLogs(); -}); -// ====================================== +document.addEventListener("DOMContentLoaded", async function () { + enabled.checked = await SettingsManager.getEnabled(); + const isDarkMode = await SettingsManager.getDarkMode(); + toggle.checked = isDarkMode; + use_shaka.checked = await SettingsManager.getUseShakaPackager(); + downloader_name.value = await SettingsManager.getExecutableName(); + + updateThemeVisuals(isDarkMode); + await SettingsManager.setSelectedDeviceType( + await SettingsManager.getSelectedDeviceType() + ); + updateDeviceFieldsetVisibility(); + + await DeviceManager.loadSetAllWidevineDevices(); + await DeviceManager.selectWidevineDevice( + await DeviceManager.getSelectedWidevineDevice() + ); + await RemoteCDMManager.loadSetAllRemoteCDMs(); + await RemoteCDMManager.selectRemoteCDM( + await RemoteCDMManager.getSelectedRemoteCDM() + ); + + checkLogs(); +}); diff --git a/picker/remote/filePicker.css b/picker/remote/filePicker.css new file mode 100644 index 0000000..89f16a2 --- /dev/null +++ b/picker/remote/filePicker.css @@ -0,0 +1,60 @@ +* { + box-sizing: border-box; + margin: 0; + padding: 0; +} + +html, +body { + height: 100%; +} + +body { + display: flex; + align-items: center; + justify-content: center; + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, + Arial, sans-serif; + background-color: #121212; + color: #e0e0e0; +} + +.file-drop-zone { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + width: 320px; + max-width: 90%; + padding: 40px; + border: 2px dashed #444; + border-radius: 12px; + cursor: pointer; + transition: background-color 0.2s ease-in-out, border-color 0.2s ease-in-out; + text-align: center; +} + +.file-drop-zone:hover { + background-color: #1e1e1e; + border-color: #666; +} + +.file-drop-zone__icon { + margin-bottom: 16px; + color: #888; +} + +.file-drop-zone__text { + font-size: 1.1rem; + font-weight: 500; +} + +.file-drop-zone__format { + font-size: 0.8rem; + color: #888; + margin-top: 8px; +} + +#fileInput[hidden] { + display: none; +} diff --git a/picker/remote/filePicker.html b/picker/remote/filePicker.html index 646076d..4bee189 100644 --- a/picker/remote/filePicker.html +++ b/picker/remote/filePicker.html @@ -1,7 +1,33 @@ + + + + + Select Device File + + + - + + + + + + \ No newline at end of file diff --git a/picker/remote/filePicker.js b/picker/remote/filePicker.js index 832609b..308859b 100644 --- a/picker/remote/filePicker.js +++ b/picker/remote/filePicker.js @@ -2,9 +2,28 @@ import "../../protobuf.min.js"; import "../../license_protocol.js"; import { SettingsManager } from "../../util.js"; -document.getElementById('fileInput').addEventListener('change', async (event) => { - const file = event.target.files[0]; - await SettingsManager.loadRemoteCDM(file).then(() => { - window.close(); - }); -}); \ No newline at end of file +document + .getElementById("fileInput") + .addEventListener("change", async (event) => { + const files = event.target.files; + + if (!files || files.length === 0) { + console.log("No file selected."); + return; + } + + const file = files[0]; + + try { + console.log(`Importing: ${file.name}`); + await SettingsManager.importDevice(file); + + console.log("File imported successfully. Closing window."); + window.close(); + } catch (error) { + console.error("An error occurred during file import:", error); + alert( + `Failed to import "${file.name}". Please check the console for details.` + ); + } + }); diff --git a/picker/wvd/filePicker.css b/picker/wvd/filePicker.css new file mode 100644 index 0000000..89f16a2 --- /dev/null +++ b/picker/wvd/filePicker.css @@ -0,0 +1,60 @@ +* { + box-sizing: border-box; + margin: 0; + padding: 0; +} + +html, +body { + height: 100%; +} + +body { + display: flex; + align-items: center; + justify-content: center; + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, + Arial, sans-serif; + background-color: #121212; + color: #e0e0e0; +} + +.file-drop-zone { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + width: 320px; + max-width: 90%; + padding: 40px; + border: 2px dashed #444; + border-radius: 12px; + cursor: pointer; + transition: background-color 0.2s ease-in-out, border-color 0.2s ease-in-out; + text-align: center; +} + +.file-drop-zone:hover { + background-color: #1e1e1e; + border-color: #666; +} + +.file-drop-zone__icon { + margin-bottom: 16px; + color: #888; +} + +.file-drop-zone__text { + font-size: 1.1rem; + font-weight: 500; +} + +.file-drop-zone__format { + font-size: 0.8rem; + color: #888; + margin-top: 8px; +} + +#fileInput[hidden] { + display: none; +} diff --git a/picker/wvd/filePicker.html b/picker/wvd/filePicker.html index 2b8de4a..2227ca9 100644 --- a/picker/wvd/filePicker.html +++ b/picker/wvd/filePicker.html @@ -1,7 +1,33 @@ + + + + + Select Device File + + + - + + + + + + \ No newline at end of file diff --git a/picker/wvd/filePicker.js b/picker/wvd/filePicker.js index 41e7af2..308859b 100644 --- a/picker/wvd/filePicker.js +++ b/picker/wvd/filePicker.js @@ -2,9 +2,28 @@ import "../../protobuf.min.js"; import "../../license_protocol.js"; import { SettingsManager } from "../../util.js"; -document.getElementById('fileInput').addEventListener('change', async (event) => { - const file = event.target.files[0]; - await SettingsManager.importDevice(file).then(() => { - window.close(); - }); -}); \ No newline at end of file +document + .getElementById("fileInput") + .addEventListener("change", async (event) => { + const files = event.target.files; + + if (!files || files.length === 0) { + console.log("No file selected."); + return; + } + + const file = files[0]; + + try { + console.log(`Importing: ${file.name}`); + await SettingsManager.importDevice(file); + + console.log("File imported successfully. Closing window."); + window.close(); + } catch (error) { + console.error("An error occurred during file import:", error); + alert( + `Failed to import "${file.name}". Please check the console for details.` + ); + } + });