feat: context menu to copy clean/short Ali links
This commit is contained in:
parent
a24b476d06
commit
84304be7da
|
@ -0,0 +1,105 @@
|
|||
/* 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);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
2
build.sh
2
build.sh
|
@ -19,7 +19,7 @@ cleanup() {
|
|||
trap cleanup EXIT
|
||||
|
||||
# Common files
|
||||
for f in manifest.json popup.html popup.js; do
|
||||
for f in manifest.json popup.html popup.js background.js; do
|
||||
cp "$ROOT_DIR/$f" "$WORK_CHROME/"
|
||||
cp "$ROOT_DIR/$f" "$WORK_FIREFOX/"
|
||||
done
|
||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -3,6 +3,9 @@
|
|||
"name": "Ali Sharelink",
|
||||
"version": "0.1.0",
|
||||
"description": "Get a clean, canonical share link for AliExpress/Alibaba products, with optional shortlink.",
|
||||
"background": {
|
||||
"service_worker": "background.js"
|
||||
},
|
||||
"action": {
|
||||
"default_title": "Ali Sharelink",
|
||||
"default_popup": "popup.html"
|
||||
|
@ -10,7 +13,9 @@
|
|||
"permissions": [
|
||||
"activeTab",
|
||||
"tabs",
|
||||
"clipboardWrite"
|
||||
"clipboardWrite",
|
||||
"contextMenus",
|
||||
"scripting"
|
||||
],
|
||||
"host_permissions": [
|
||||
"https://is.gd/*"
|
||||
|
|
Loading…
Reference in New Issue