/* global chrome, browser */ const API = typeof chrome !== "undefined" ? chrome : browser; function canonicalizeAliExpress(urlString) { const url = new URL(urlString); const path = url.pathname; 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`; return `https://${canonicalHost}${path}`; } function canonicalizeAlibaba(urlString) { const url = new URL(urlString); 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) }; 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(); } function createMenus() { try { API.contextMenus.removeAll(() => {}); } catch (e) {} API.contextMenus.create({ id: "ali-clean", title: "Copy clean Ali link", contexts: ["page", "selection", "link"], documentUrlPatterns: [ "*://*.aliexpress.*/*", "*://*.alibaba.*/*" ] }); API.contextMenus.create({ id: "ali-shorten", title: "Copy short Ali link", contexts: ["page", "selection", "link"], documentUrlPatterns: [ "*://*.aliexpress.*/*", "*://*.alibaba.*/*" ] }); } async function getRelevantUrl(info, tab) { if (info.linkUrl) return info.linkUrl; return tab && tab.url ? tab.url : null; } async function copyTextToClipboard(tabId, text) { // Using scripting to execute in page context for broad compatibility const code = `navigator.clipboard.writeText(${JSON.stringify(text)}).then(() => true).catch(() => false);`; try { const results = await API.scripting.executeScript({ target: { tabId }, func: (t) => navigator.clipboard.writeText(t).then(() => true).catch(() => false), args: [text] }); const ok = results && results[0] && results[0].result; return !!ok; } catch (e) { return false; } } API.runtime.onInstalled && API.runtime.onInstalled.addListener(() => { createMenus(); }); API.contextMenus.onClicked.addListener(async (info, tab) => { if (!tab || !tab.id) return; const rawUrl = await getRelevantUrl(info, tab); if (!rawUrl) return; const { url } = canonicalize(rawUrl); if (info.menuItemId === "ali-clean") { await copyTextToClipboard(tab.id, url); } else if (info.menuItemId === "ali-shorten") { try { const shortUrl = await shortenWithIsGd(url); await copyTextToClipboard(tab.id, shortUrl); } catch (e) { await copyTextToClipboard(tab.id, url); } } });