142 lines
4.3 KiB
JavaScript
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);
|
|
})();
|
|
|
|
|