106 lines
3.4 KiB
JavaScript
106 lines
3.4 KiB
JavaScript
/* 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);
|
|
}
|
|
}
|
|
});
|
|
|
|
|