Greasy Fork is available in English.
Amazon.co.jp URL 清理脚本:移除路径中的 /ref= 片段与常见跟踪参数。商品页规范为 /dp/ASIN;非商品页仅删已知跟踪参数并保留其它参数以确保筛选等功能可用。拦截 History/Location、链接点击与 SPA 路由,让 URL 始终更易读、更注重隐私。
// ==UserScript==
// @name Amazon.co.jp URL Cleaner 🔗🧹
// @name:ja Amazon.co.jp URLクリーナー 🔗🧹
// @name:en Amazon.co.jp URL Cleaner 🔗🧹
// @name:zh-CN Amazon.co.jp 链接清理器 🔗🧹
// @name:zh-TW Amazon.co.jp 連結清理器 🔗🧹
// @name:ko Amazon.co.jp URL 클리너 🔗🧹
// @name:fr Nettoyeur d’URL Amazon.co.jp 🔗🧹
// @name:es Limpiador de URL de Amazon.co.jp 🔗🧹
// @name:de Amazon.co.jp-URL-Cleaner 🔗🧹
// @name:pt-BR Limpador de URL da Amazon.co.jp 🔗🧹
// @name:ru Очистка URL Amazon.co.jp 🔗🧹
// @namespace https://github.com/koyasi777/amazon-jp-url-cleaner
// @version 2.0.0
// @description Amazon.co.jp 用URLクリーナー。パス中の /ref= や一般的なトラッキング用パラメータを削除します。商品ページは /dp/ASIN に正規化し、それ以外は既知の追跡要素のみ除去して他のパラメータは保持(フィルタ等を維持)。History/Location・クリック・SPA遷移をフックし、URLを常に読みやすくプライバシー配慮に保ちます。
// @description:ja Amazon.co.jp 用URLクリーナー。パス中の /ref= や一般的なトラッキング用パラメータを削除します。商品ページは /dp/ASIN に正規化し、それ以外は既知の追跡要素のみ除去して他のパラメータは保持(フィルタ等を維持)。History/Location・クリック・SPA遷移をフックし、URLを常に読みやすくプライバシー配慮に保ちます。
// @description:en Amazon.co.jp URL cleaner userscript. Removes /ref= path segments and common tracking params. Product pages normalize to /dp/ASIN; other pages remove known tracking while keeping other params so filters work. Hooks History/Location, link clicks, and SPA navigation to keep URLs readable and privacy-friendly.
// @description:zh-CN Amazon.co.jp URL 清理脚本:移除路径中的 /ref= 片段与常见跟踪参数。商品页规范为 /dp/ASIN;非商品页仅删已知跟踪参数并保留其它参数以确保筛选等功能可用。拦截 History/Location、链接点击与 SPA 路由,让 URL 始终更易读、更注重隐私。
// @description:zh-TW Amazon.co.jp URL 清理腳本:移除路徑中的 /ref= 段落與常見追蹤參數。商品頁正規化為 /dp/ASIN;非商品頁僅刪已知追蹤參數並保留其它參數以維持篩選等功能。攔截 History/Location、連結點擊與 SPA 導覽,讓 URL 一直更易讀、更重視隱私。
// @description:ko Amazon.co.jp URL 클리너 유저스크립트. 경로의 /ref= 구간과 일반적인 추적 파라미터를 제거합니다. 상품 페이지는 /dp/ASIN으로 정리하고, 비상품 페이지는 알려진 추적만 제거하며 나머지는 유지해 필터 등이 동작하게 합니다. History/Location·클릭·SPA 내비게이션을 후킹해 URL을 항상 읽기 쉽고 프라이버시 친화적으로 유지합니다.
// @description:fr Userscript de nettoyage d’URL Amazon.co.jp. Supprime /ref= (chemin) et les paramètres de suivi courants. Pages produit → /dp/ASIN ; autres pages : retire le tracking connu en gardant les autres paramètres (filtres OK). Intercepte History/Location, clics et navigation SPA pour garder des URL lisibles et respectueuses de la vie privée.
// @description:es Userscript limpiador de URL para Amazon.co.jp. Elimina /ref= (ruta) y parámetros de seguimiento comunes. Páginas de producto → /dp/ASIN; otras páginas: quita tracking conocido y conserva el resto (filtros OK). Engancha History/Location, clics y navegación SPA para mantener URLs legibles y más privadas.
// @description:de Amazon.co.jp-URL-Cleaner-Userscript. Entfernt /ref= im Pfad und gängige Tracking-Parameter. Produktseiten → /dp/ASIN; andere Seiten: entfernt nur bekanntes Tracking und behält übrige Parameter (Filter ok). Hookt History/Location, Link-Klicks und SPA-Navigation, damit URLs lesbar und datenschutzfreundlich bleiben.
// @description:pt-BR Userscript limpador de URL para Amazon.co.jp. Remove /ref= no caminho e parâmetros comuns de rastreamento. Páginas de produto → /dp/ASIN; demais páginas: remove tracking conhecido e mantém o restante (filtros OK). Intercepta History/Location, cliques e navegação SPA para manter URLs legíveis e mais privadas.
// @description:ru Скрипт очистки URL для Amazon.co.jp. Удаляет /ref= в пути и типичные трекинговые параметры. Товарные страницы → /dp/ASIN; остальные: убирает известный трекинг, сохраняя прочие параметры (фильтры работают). Перехватывает History/Location, клики и SPA-навигацию, чтобы URL оставались читаемыми и более приватными.
// @author koyasi777
// @license MIT
// @homepageURL https://github.com/koyasi777/amazon-jp-url-cleaner
// @supportURL https://github.com/koyasi777/amazon-jp-url-cleaner/issues
// @icon https://www.amazon.co.jp/favicon.ico
// @match https://www.amazon.co.jp/*
// @grant none
// @run-at document-start
// @noframes
// ==/UserScript==
(function () {
'use strict';
// --- Configuration -----------------------------------------
// 【Mode A: 商品ページ用】許可するクエリキー(ホワイトリスト)
// 必要なパラメータ(アフィリエイトのtagや言語設定など)のみをここに定義。
// 空配列 [] なら、/dp/ASIN だけの最もクリーンなURLになります。
const PRODUCT_ALLOW_KEYS = [];
// 【Mode B: その他ページ用】削除対象パラメータ(ブラックリスト)
// 検索結果やトップページ等で「機能は壊さずにトラッキングだけ消す」ためのリスト。
const TRACKING_BLACKLIST = new Set([
'ref', 'ref_', 'pf_rd_r', 'pf_rd_p', 'pf_rd_m', 'pf_rd_s', 'pf_rd_t', 'pf_rd_i',
'pd_rd_r', 'pd_rd_w', 'pd_rd_wg', 'qid', 'sr', 'keywords', // keywordsは検索維持のため例外判定あり
'dchild', 'crid', 'sprefix', 'field-keywords', 'hvpos', 'hvexid', 'hvnetw',
'hvrand', 'hvqmt', 'hvbmt', 'hvdev', 'hvdvcmdl', 'hvlocint', 'hvlocphy',
'hvtargid', 'hydadcr', '_encoding','ie',
]);
// 上記ブラックリストに含まれていても、検索結果ページ等で機能維持のために残すべきキー
const FUNCTIONAL_KEYS_ON_SEARCH = new Set(['keywords', 'k', 'rh', 'page', 'sort', 'node']);
// --- Helpers ---------------------------------------------------------------
/**
* 安全なURLオブジェクト生成
* URL.canParse が使えない環境への配慮も含め、パース不可なら例外を投げるかnullを返す
*/
function toURL(input) {
const s = String(input);
// ベースURL解決を厳密に行う
try {
return new URL(s, location.href);
} catch {
throw new TypeError(`Unparsable URL: ${s}`);
}
}
/**
* パスからASINを抽出
* /dp/, /gp/product/, /gp/aw/d/ に対応
*/
function extractASIN(pathname) {
const m = pathname.match(/\/(?:dp|gp\/product|gp\/aw\/d)\/([A-Z0-9]{10})(?:[/?]|$)/i);
return m ? m[1].toUpperCase() : null;
}
// --- Core Logic: The Dual-Mode Canonicalizer -------------------------------
function canonicalize(input) {
let url;
try {
url = toURL(input);
} catch {
// パース不能な文字列は触らず返す(安全性優先)
return String(input);
}
// Safety check: amazon.co.jp 以外は絶対に触らない
if (!/\.amazon\.co\.jp$/i.test(url.hostname)) return url.href;
const asin = extractASIN(url.pathname);
// -------------------------------------------------------------------------
// Strategy A: 商品ページ (Strict Reconstruction)
// -------------------------------------------------------------------------
if (asin) {
// 言語プレフィックス(/-/en/ や /-/es/ 等)があれば保持
const langPrefixMatch = url.pathname.match(/^\/-\/[^/]+\//);
const prefix = langPrefixMatch ? langPrefixMatch[0].slice(0, -1) : '';
// 許可されたクエリだけをホワイトリスト方式で再構築
const keptParams = new URLSearchParams();
if (PRODUCT_ALLOW_KEYS.length) {
const allow = new Set(PRODUCT_ALLOW_KEYS.map(k => k.toLowerCase()));
for (const [k, v] of url.searchParams) {
if (allow.has(k.toLowerCase())) keptParams.append(k, v);
}
}
const qs = keptParams.toString();
// フラグメント(#)は維持しつつ、正規化URLを返す
return `${url.origin}${prefix}/dp/${asin}${qs ? `?${qs}` : ''}${url.hash}`;
}
// -------------------------------------------------------------------------
// Strategy B: その他ページ (General Cleaning)
// -------------------------------------------------------------------------
// 検索結果、トップページ、アカウントサービス等は、ブラックリストにあるゴミだけを除去する。
// 1. Path Cleaning: URLパス内の /ref=... をカット
if (url.pathname.includes('/ref=')) {
url.pathname = url.pathname.split('/ref=')[0];
if (url.pathname === '') url.pathname = '/';
}
// 2. Query Cleaning: トラッキングパラメータの除去
const isSearchPage = url.pathname.startsWith('/s');
const keys = Array.from(url.searchParams.keys());
for (const key of keys) {
const lowerKey = key.toLowerCase();
// ref=... は全ページで無条件削除
if (lowerKey === 'ref' || lowerKey.startsWith('ref_')) {
url.searchParams.delete(key);
continue;
}
// ブラックリスト判定
if (
lowerKey.startsWith('pf_rd_') ||
lowerKey.startsWith('pd_rd_') ||
TRACKING_BLACKLIST.has(lowerKey)
) {
// 例外: 検索ページで機能的に必要なキーなら維持 (例: keywords)
if (isSearchPage && FUNCTIONAL_KEYS_ON_SEARCH.has(lowerKey)) continue;
url.searchParams.delete(key);
}
}
return url.href;
}
// --- Execution & Hooks: Robustness ---------------------------------
function normalizeHere() {
const target = canonicalize(location.href);
if (target !== location.href) {
try {
// history.state を維持しつつ URL のみ置換
history.replaceState(history.state, document.title, target);
} catch {
// フォールバック
history.replaceState(null, '', target);
}
return true; // 変更あり
}
return false; // 変更なし
}
// 1) 初期実行(最速タイミング)
normalizeHere();
// 2) History API Hook
(function hookHistory() {
const _push = history.pushState;
const _replace = history.replaceState;
history.pushState = function (state, title, url) {
if (url !== undefined && url !== null) {
try { url = canonicalize(url); } catch {}
return _push.call(this, state, title, url);
}
return _push.call(this, state, title);
};
history.replaceState = function (state, title, url) {
if (url !== undefined && url !== null) {
try { url = canonicalize(url); } catch {}
return _replace.call(this, state, title, url);
} else {
// 引数なしreplaceでも現在地を浄化
const target = canonicalize(location.href);
if (target !== location.href) {
return _replace.call(this, state, title, target);
}
return _replace.call(this, state, title);
}
};
// SPAバック/フォワード時の再正規化
window.addEventListener('popstate', normalizeHere, { capture: true });
})();
// 3) Location API Hook
(function hookLocation() {
// ユーティリティ: 同一URLならリロードを防ぐ
function safeCallAssignReplace(fn, urlLike) {
try {
const c = canonicalize(urlLike);
if (c === location.href) return; // no-op
return fn.call(this, c);
} catch {
return fn.call(this, urlLike);
}
}
try {
const L = Location.prototype;
// assignフック
try {
const descA = Object.getOwnPropertyDescriptor(L, 'assign');
if (!descA || descA.writable) {
const _assign = L.assign;
L.assign = function (url) {
return safeCallAssignReplace.call(this, _assign, url);
};
}
} catch {}
// replaceフック
try {
const descR = Object.getOwnPropertyDescriptor(L, 'replace');
if (!descR || descR.writable) {
const _replace = L.replace;
L.replace = function (url) {
return safeCallAssignReplace.call(this, _replace, url);
};
}
} catch {}
} catch {
// prototype操作がブロックされた場合のインスタンス直接書き換え
try {
const loc = window.location;
const _assign2 = loc.assign.bind(loc);
const _replace2 = loc.replace.bind(loc);
Object.defineProperty(loc, 'assign', {
value: (url) => safeCallAssignReplace.call(loc, _assign2, url)
});
Object.defineProperty(loc, 'replace', {
value: (url) => safeCallAssignReplace.call(loc, _replace2, url)
});
} catch {}
}
})();
// 3.5) Click Event Hook
(function preNormalizeAnchorClicks() {
document.addEventListener('click', (e) => {
if (e.defaultPrevented) return;
if (e.button !== 0) return; // 左クリックのみ
if (e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) return;
const a = e.target && e.target.closest && e.target.closest('a[href]');
if (!a) return;
// 除外: ダウンロード、別タブ、外部リンク属性
if (a.hasAttribute('download')) return;
if (a.target === '_blank') return;
if (/\bexternal\b/i.test(a.rel || '')) return;
try {
const u = new URL(a.href, location.href);
// http/https 以外は無視
if (!/^https?:$/i.test(u.protocol)) return;
// Amazon以外は無視
if (!/\.amazon\.co\.jp$/i.test(u.hostname)) return;
const c = canonicalize(u);
// クリーンなURLに書き換えてから遷移させる
if (c !== a.href) a.href = c;
} catch {}
}, { capture: true });
})();
// 4) Watchdog
// Amazonの遅延ロードによるURL再汚染に対抗するため、変更が止まるまで監視する。
(function watchdog() {
let ticks = 0;
let stable = 0; // 連続して変更がなかった回数
const id = setInterval(() => {
const changed = normalizeHere();
// 変更があったらstableカウントをリセット、なければ加算
stable = changed ? 0 : (stable + 1);
// 終了条件:
// 1. 8回連続(約2秒)変更がない = 安定したとみなす
// 2. または合計40回(約10秒)経過しても終わらない = 強制終了
if (stable >= 8 || (++ticks > 40 && !changed)) {
clearInterval(id);
}
}, 250);
// 補助トリガー
document.addEventListener('DOMContentLoaded', normalizeHere, { once: true });
window.addEventListener('load', normalizeHere, { once: true });
document.addEventListener('visibilitychange', () => {
if (document.visibilityState === 'visible') normalizeHere();
});
})();
})();