commit 080409573048629bdb0c75589633a4c0c5571a1b Author: Ivory Date: Sun Feb 8 10:46:25 2026 -0500 init diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d77864a --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*.zip + diff --git a/README_PLEASE.md b/README_PLEASE.md new file mode 100644 index 0000000..28bee1e --- /dev/null +++ b/README_PLEASE.md @@ -0,0 +1,9 @@ + +THIS EXTENSION WILL NOT INSTALL UNLESS YOU SET + +xpinstall.signatures.required = false + +in the about:config page in LIBREWOLF. +ONLY TESTED IN LIBREWOLF. + + diff --git a/background.js b/background.js new file mode 100644 index 0000000..dfa111f --- /dev/null +++ b/background.js @@ -0,0 +1,15 @@ +browser.runtime.onMessage.addListener(async (msg) => { + if (msg.type !== "send") return; + + console.log("sending message to", msg.host); + + await fetch(msg.host, { + method: "POST", + headers: { + "Content-Type": "application/json" + }, + body: msg.data + }); + + return { ok: true }; +}); diff --git a/manifest.json b/manifest.json new file mode 100644 index 0000000..52a789a --- /dev/null +++ b/manifest.json @@ -0,0 +1,20 @@ +{ + "manifest_version": 2, + "name": "downloader-server", + "version": "0.1", + "description": "Extension for downloader-server", + "permissions": [ + "storage", "tabs" + ], + "optional_permissions": [ + "http://*/*", + "https://*/*" + ], + "background": { + "scripts": ["background.js"] + }, + "browser_action": { + "default_popup": "popup.html" + }, + "applications": { "gecko": { "id": "X@Y" } } +} diff --git a/package.sh b/package.sh new file mode 100755 index 0000000..2f29ea9 --- /dev/null +++ b/package.sh @@ -0,0 +1,5 @@ +zip -r -FS downloader.zip \ + background.js \ + manifest.json \ + popup.html \ + popup.js diff --git a/popup.html b/popup.html new file mode 100644 index 0000000..3ace65c --- /dev/null +++ b/popup.html @@ -0,0 +1,68 @@ + + + + + + +
+ + + +
+ +
+ +
+
+ +
+

+	
+
+ +
+
+ + +
+
+ + + + diff --git a/popup.js b/popup.js new file mode 100644 index 0000000..e7456d3 --- /dev/null +++ b/popup.js @@ -0,0 +1,206 @@ +const get_saved_domain = async () => (await browser.storage.local.get("domain")).domain; +const set_saved_domain = async (domain) => await browser.storage.local.set({ domain }); + +function load_domain_from_storage_and_enable_interactions() { + const save_button = document.getElementById("save_domain"); + const host_input = document.getElementById("host"); + + const disable_save_button = () => save_button.setAttribute('disabled', true); + const enable_save_button = () => save_button.removeAttribute('disabled'); + + async function populate_domain_textbox_from_storage() { + const domain = await get_saved_domain() + if (!domain) return; + host_input.value = domain; + disable_save_button(); + } + + async function domain_input_changed() { + const saved_domain = await get_saved_domain(); + const current_domain = host_input.value; + if(saved_domain !== current_domain) enable_save_button(); + else disable_save_button(); + } + + async function save_domain_input_to_storage() { + if (!host_input.value.endsWith("/")) + host_input.value = host_input.value + "/"; + const saved = set_saved_domain(host_input.value); + + const granted = await browser.permissions.request({ + origins: [host_input.value] + }); + if (!granted) throw new Error("Permission denied"); + + await saved; + disable_save_button(); + } + + populate_domain_textbox_from_storage() + host_input.addEventListener('change', domain_input_changed); + host_input.addEventListener('keypress', domain_input_changed); + host_input.addEventListener('keyup', domain_input_changed); + host_input.addEventListener('keydown', domain_input_changed); + save_button.addEventListener('click', save_domain_input_to_storage); +} + +const colors = ['red', 'green', 'blue', 'cyan', 'magenta']; +let current_color = -1; +function get_color() { return colors[current_color]; } +function next_color() { current_color ++; current_color = current_color % colors.length }; + +async function arm_action_buttons() { + next_color(); + const actions_container = document.getElementById('actions'); + actions_container.innerHTML = ""; + + async function send_data(route, payload) { + const domain = (await get_saved_domain()) + route; + await browser.runtime.sendMessage({ + type: 'send', + host: domain, + data: JSON.stringify(payload) + }); + } + + async function get_current_tab_url() { + return (await browser.tabs.query({ currentWindow: true, active: true }))[0].url + } + + const presets_req = await fetch(await get_saved_domain() + 'download/presets'); + const presets = await presets_req.json(); + + const groups = {}; + + function get_group(name) { + if (!name) name = "Ungrouped"; + if (name in groups) return groups[name]; + const fieldset = document.createElement('fieldset'); + // fieldset.style.background = get_color(); + const legend = document.createElement('legend'); + legend.innerText = name; + fieldset.className = "actionset"; + + fieldset.appendChild(legend); + actions_container.appendChild(fieldset); + + groups[name] = fieldset; + return groups[name]; + } + + for (const preset of presets) { + const button = document.createElement('button'); + const fieldset = get_group(preset.folder); + fieldset.appendChild(button); + + + + button.innerText = preset.name; + button.addEventListener('click', async function() { + send_data('download', { + url: await get_current_tab_url(), + preset_id: preset.id, + }); + }); + } + + const hr = document.createElement('hr'); + actions_container.appendChild(hr); + + const reload_button = document.createElement('button'); + reload_button.innerText = "Reload"; + reload_button.addEventListener('click', arm_action_buttons); + actions_container.appendChild(reload_button); + + +} + +async function dismiss_notif(status_id) { + url = await get_saved_domain() + 'notification/' + status_id + fetch(url, { + method: 'DELETE' + }) +} + +function create_notification_element_from_notification_object(notification) { + + const e_container = document.createElement('div'); + e_container.classList = `status status-${notification.type}`; + e_container.setAttribute('notification_id', "" + notification.id); + e_container.setAttribute('notification_hash', "" + notification.hash); + + const e_title = document.createElement('div'); + e_title.classList = 'status-title'; + e_title.innerText = notification.title; + + const e_text = document.createElement('div'); + e_text.classList = 'status-text'; + e_text.innerHTML = notification.text; + + const e_delete_button = document.createElement('button'); + e_delete_button.classList = 'dismiss'; + e_delete_button.innerText = "Dismis"; + e_delete_button.addEventListener('click', () => { + dismiss_notif(notification.id); + }) + + e_container.appendChild(e_title); + e_container.appendChild(e_text); + e_container.appendChild(e_delete_button); + + return e_container; +} + +function begin_status_update_loop() { + const statuses_container = document.getElementById('statuses'); + + function get_current_shown_status_ids() { + let arr = []; + for(const element of statuses_container.children) { + arr.push(element.getAttribute("notification_id")) + } + return arr; + } + + async function check_statuses() { + let domain = await get_saved_domain(); + let req = await fetch(domain + 'notifications'); + let json = await req.json(); + + const current_status_ids = get_current_shown_status_ids(); + const new_status_ids = json.map(v => v.id); + + const combined_ids = Array.from(new Set([ + ...current_status_ids, + ...new_status_ids + ])); + + for(const status_id of combined_ids) { + const in_current = current_status_ids.includes(status_id); + const in_new = new_status_ids.includes(status_id); + + if (in_current && !in_new) { + const status_element = statuses_container.querySelector(`[notification_id="${status_id}"]`); + status_element.outerHTML = ""; + } else if (!in_current && in_new) { + const status_object = json.find(status => status.id === status_id); + const new_element = create_notification_element_from_notification_object(status_object) + statuses_container.appendChild(new_element); + } else if (in_current && in_new) { + const status_object = json.find(status => status.id === status_id); + const current_element = statuses_container.querySelector(`[notification_id="${status_id}"]`); + const new_element = create_notification_element_from_notification_object(status_object); + current_element.replaceWith(new_element); + } + } + + setTimeout(check_statuses, 500); + } + check_statuses(); +} + +document.addEventListener("DOMContentLoaded", () => { + load_domain_from_storage_and_enable_interactions(); + arm_action_buttons(); + begin_status_update_loop(); +});