alisharelink/popup.js

142 lines
4.3 KiB
JavaScript

/* global chrome, browser */
(function () {
const $ = (id) => document.getElementById(id);
const statusEl = $("status");
function setStatus(message, kind) {
statusEl.textContent = message || "";
statusEl.className = `row small ${kind === "error" ? "error" : kind === "ok" ? "ok" : "muted"}`;
}
function getApi() {
if (typeof chrome !== "undefined" && chrome.tabs) return chrome;
if (typeof browser !== "undefined" && browser.tabs) return browser;
throw new Error("Unsupported browser API");
}
function tabsQuery(api, queryInfo) {
// chrome: callback-based, firefox: promise-based
return new Promise((resolve, reject) => {
try {
const maybePromise = api.tabs.query(queryInfo, (tabs) => {
if (chrome && chrome.runtime && chrome.runtime.lastError) {
reject(chrome.runtime.lastError);
} else if (tabs) {
resolve(tabs);
}
});
if (maybePromise && typeof maybePromise.then === "function") {
maybePromise.then(resolve, reject);
}
} catch (e) {
reject(e);
}
});
}
function copyToClipboard(text) {
return navigator.clipboard.writeText(text);
}
function canonicalizeAliExpress(urlString) {
const url = new URL(urlString);
const host = url.hostname;
const path = url.pathname;
// Prefer global .com canonical
const canonicalHost = "www.aliexpress.com";
let productId = null;
const itemMatch = path.match(/\/(item|i)\/(\d+)\.html/i);
if (itemMatch) {
productId = itemMatch[2];
}
if (!productId) {
const xObjectId = url.searchParams.get("x_object_id") || url.searchParams.get("item_id");
if (xObjectId && /^\d+$/.test(xObjectId)) {
productId = xObjectId;
}
}
if (productId) {
return `https://${canonicalHost}/item/${productId}.html`;
}
// Fallback: strip params and hash
return `https://${canonicalHost}${path}`;
}
function canonicalizeAlibaba(urlString) {
const url = new URL(urlString);
// Keep origin + pathname only
return `${url.origin}${url.pathname}`;
}
function canonicalize(urlString) {
const url = new URL(urlString);
const hostname = url.hostname.toLowerCase();
if (hostname.includes("aliexpress.")) {
return { vendor: "AliExpress", url: canonicalizeAliExpress(urlString) };
}
if (hostname.includes("alibaba.")) {
return { vendor: "Alibaba", url: canonicalizeAlibaba(urlString) };
}
// Unknown: just strip params/hash
return { vendor: "Unknown", url: `${url.origin}${url.pathname}` };
}
async function shortenWithIsGd(longUrl) {
const endpoint = `https://is.gd/create.php?format=simple&url=${encodeURIComponent(longUrl)}`;
const res = await fetch(endpoint, { method: "GET" });
const text = await res.text();
if (!res.ok) throw new Error(text || `Shorten failed (${res.status})`);
if (!/^https?:\/\//i.test(text)) throw new Error(text || "Shorten failed");
return text.trim();
}
async function init() {
setStatus("Reading current tab…");
const api = getApi();
try {
const tabs = await tabsQuery(api, { active: true, currentWindow: true });
const active = tabs && tabs[0];
if (!active || !active.url) {
setStatus("No active tab URL found", "error");
return;
}
$("currentUrl").value = active.url;
const { vendor, url } = canonicalize(active.url);
$("cleanUrl").value = url;
setStatus(`Detected ${vendor}. Clean link ready.`, "ok");
$("copyClean").addEventListener("click", async () => {
try {
await copyToClipboard($("cleanUrl").value);
setStatus("Clean link copied.", "ok");
} catch (e) {
setStatus(`Copy failed: ${e.message}`, "error");
}
});
$("shortenCopy").addEventListener("click", async () => {
setStatus("Shortening with is.gd…");
try {
const shortUrl = await shortenWithIsGd($("cleanUrl").value);
await copyToClipboard(shortUrl);
setStatus("Short link copied.", "ok");
} catch (e) {
setStatus(`Shorten failed: ${e.message}`, "error");
}
});
} catch (e) {
setStatus(`Error: ${e.message}`, "error");
}
}
document.addEventListener("DOMContentLoaded", init);
})();