184 lines
5.6 KiB
JavaScript
184 lines
5.6 KiB
JavaScript
"use strict";
|
|
|
|
const statusEl = document.getElementById("status");
|
|
const listEl = document.getElementById("urlList");
|
|
const openHistoryBtn = document.getElementById("openHistoryBtn");
|
|
const clearBtn = document.getElementById("clearBtn");
|
|
|
|
function setStatus(message) {
|
|
statusEl.textContent = message;
|
|
}
|
|
|
|
function isUserCancelledError(result) {
|
|
const error = result && typeof result.error === "string" ? result.error.toLowerCase() : "";
|
|
return error.includes("canceled by the user") || error.includes("cancelled by the user");
|
|
}
|
|
|
|
function entryLabel(entry) {
|
|
return entry && entry.fullUrl ? "full candidate" : "preview fallback";
|
|
}
|
|
|
|
function formatMeta(entry) {
|
|
const packName = entry && entry.packName ? entry.packName : "n/a";
|
|
const key = entry && entry.key ? entry.key : "n/a";
|
|
const bpm = entry && entry.bpm ? entry.bpm : "n/a";
|
|
return { packName, key, bpm };
|
|
}
|
|
|
|
function formatTags(entry) {
|
|
if (!entry || !Array.isArray(entry.tags) || !entry.tags.length) {
|
|
return "No tags";
|
|
}
|
|
const maxTags = 5;
|
|
const tags = entry.tags.slice(0, maxTags);
|
|
const suffix = entry.tags.length > maxTags ? ` +${entry.tags.length - maxTags}` : "";
|
|
return tags.join(" • ") + suffix;
|
|
}
|
|
|
|
function createDownloadIcon() {
|
|
const ns = "http://www.w3.org/2000/svg";
|
|
const svg = document.createElementNS(ns, "svg");
|
|
svg.setAttribute("viewBox", "0 0 24 24");
|
|
svg.setAttribute("width", "22");
|
|
svg.setAttribute("height", "22");
|
|
svg.setAttribute("aria-hidden", "true");
|
|
|
|
const arrow = document.createElementNS(ns, "path");
|
|
arrow.setAttribute("d", "M12 4v10m0 0l4-4m-4 4l-4-4");
|
|
arrow.setAttribute("fill", "none");
|
|
arrow.setAttribute("stroke", "currentColor");
|
|
arrow.setAttribute("stroke-width", "2");
|
|
arrow.setAttribute("stroke-linecap", "round");
|
|
arrow.setAttribute("stroke-linejoin", "round");
|
|
|
|
const tray = document.createElementNS(ns, "path");
|
|
tray.setAttribute("d", "M4 18v1a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-1");
|
|
tray.setAttribute("fill", "none");
|
|
tray.setAttribute("stroke", "currentColor");
|
|
tray.setAttribute("stroke-width", "2");
|
|
tray.setAttribute("stroke-linecap", "round");
|
|
tray.setAttribute("stroke-linejoin", "round");
|
|
|
|
svg.appendChild(arrow);
|
|
svg.appendChild(tray);
|
|
return svg;
|
|
}
|
|
|
|
function buildRow(entry) {
|
|
const li = document.createElement("li");
|
|
li.className = "url-item";
|
|
const meta = formatMeta(entry);
|
|
|
|
const head = document.createElement("div");
|
|
head.className = "item-head";
|
|
|
|
const cover = document.createElement("img");
|
|
cover.className = "cover-image";
|
|
cover.src = entry.coverImageUrl || "logo-single.png";
|
|
cover.alt = "Cover art";
|
|
cover.loading = "lazy";
|
|
|
|
const info = document.createElement("div");
|
|
info.className = "item-info";
|
|
|
|
const title = document.createElement("p");
|
|
title.className = "item-title";
|
|
title.textContent = entry.fileName || entry.sampleId || "(unknown filename)";
|
|
|
|
const sub = document.createElement("p");
|
|
sub.className = "item-sub";
|
|
sub.textContent = `${meta.packName} • ${entryLabel(entry)}`;
|
|
|
|
const tags = document.createElement("p");
|
|
tags.className = "item-tags";
|
|
tags.textContent = formatTags(entry);
|
|
|
|
const badges = document.createElement("div");
|
|
badges.className = "item-badges";
|
|
|
|
const keyBadge = document.createElement("span");
|
|
keyBadge.className = "badge";
|
|
keyBadge.textContent = `Key ${meta.key}`;
|
|
|
|
const bpmBadge = document.createElement("span");
|
|
bpmBadge.className = "badge";
|
|
bpmBadge.textContent = `BPM ${meta.bpm}`;
|
|
|
|
badges.appendChild(keyBadge);
|
|
badges.appendChild(bpmBadge);
|
|
info.appendChild(title);
|
|
info.appendChild(sub);
|
|
info.appendChild(tags);
|
|
info.appendChild(badges);
|
|
|
|
const download = document.createElement("button");
|
|
download.type = "button";
|
|
download.className = "download-icon-btn";
|
|
download.setAttribute("aria-label", "Download sample");
|
|
download.setAttribute("title", "Download sample");
|
|
download.appendChild(createDownloadIcon());
|
|
download.addEventListener("click", async () => {
|
|
const result = await browser.runtime.sendMessage({ type: "DOWNLOAD_ENTRY", entry });
|
|
if (!result || !result.ok) {
|
|
if (isUserCancelledError(result)) {
|
|
return;
|
|
}
|
|
window.alert((result && result.error) || "Download failed.");
|
|
return;
|
|
}
|
|
setStatus(result.mode === "full" ? "Downloaded full file URL." : "Downloaded decoded preview fallback.");
|
|
});
|
|
|
|
head.appendChild(cover);
|
|
head.appendChild(info);
|
|
head.appendChild(download);
|
|
li.appendChild(head);
|
|
return li;
|
|
}
|
|
|
|
async function loadCapturedUrls() {
|
|
const response = await browser.runtime.sendMessage({ type: "GET_HISTORY" });
|
|
|
|
if (!response || !response.ok) {
|
|
setStatus("Unable to load captured samples.");
|
|
return;
|
|
}
|
|
|
|
listEl.innerHTML = "";
|
|
const entries = Array.isArray(response.history) ? response.history : [];
|
|
if (!entries.length) {
|
|
setStatus("No captured samples yet.");
|
|
return;
|
|
}
|
|
|
|
setStatus(`Captured samples: ${entries.length}`);
|
|
for (const entry of entries) {
|
|
listEl.appendChild(buildRow(entry));
|
|
}
|
|
}
|
|
|
|
openHistoryBtn.addEventListener("click", async () => {
|
|
await browser.runtime.sendMessage({ type: "OPEN_HISTORY" });
|
|
window.close();
|
|
});
|
|
|
|
if (clearBtn) {
|
|
clearBtn.addEventListener("click", async () => {
|
|
const confirmed = window.confirm("Clear all captured samples and history?");
|
|
if (!confirmed) {
|
|
return;
|
|
}
|
|
const result = await browser.runtime.sendMessage({ type: "CLEAR_CAPTURED_STATE" });
|
|
if (!result || !result.ok) {
|
|
setStatus("Unable to clear captured samples.");
|
|
return;
|
|
}
|
|
await loadCapturedUrls();
|
|
setStatus("Captured samples cleared.");
|
|
});
|
|
}
|
|
|
|
loadCapturedUrls().catch(() => {
|
|
setStatus("Unexpected error while loading URLs.");
|
|
});
|