您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
取代 YouTube 分享按鈕,複製不含追蹤參數的短網址到剪貼簿。
当前为
// ==UserScript== // @name YouTube 乾淨短網址分享器 // @name:en Clean YouTube Short URL Sharer // @name:zh-TW YouTube 乾淨短網址分享器 // @name:ja YouTubeクリーンショートURLシェア // @name:es Compartidor limpio de URL corta de YouTube // @name:de Sauberer YouTube-Kurzlink-Teiler // @description 取代 YouTube 分享按鈕,複製不含追蹤參數的短網址到剪貼簿。 // @description:en Replaces the YouTube Share button with a cleaner version that copies a tracking-free short URL using GM_setClipboard. // @description:zh-TW 取代 YouTube 分享按鈕,複製不含追蹤參數的短網址到剪貼簿。 // @description:ja YouTubeの共有ボタンを置き換え、トラッキングなしの短縮URLをクリップボードにコピーします。 // @description:es Reemplaza el botón de compartir de YouTube por uno que copia una URL corta sin rastreo al portapapeles. // @description:de Ersetzt die YouTube-Teilen-Schaltfläche durch eine saubere Version, die einen trackingfreien Kurzlink kopiert. // @author Max // @namespace https://github.com/Max46656 // @license MPL2.0 // @match https://www.youtube.com/* // @match https://www.youtube.com/watch* // @grant GM_setClipboard // @grant GM.info // @version 1.0.0 // ==/UserScript== class YouTubeShortUrlCopier { constructor() { this.shareButtonSelector = '#actions yt-button-view-model button-view-model button'; this.notificationDuration = 1000; this.pollInterval = 100; this.maxAttempts = 30; this.attempts = 0; this.init(); } init() { this.i18n = new LocalizationManager(); this.waitForShareButton(); } waitForShareButton() { const interval = setInterval(() => { const originalButton = document.querySelector(this.shareButtonSelector); this.attempts++; if (originalButton) { clearInterval(interval); this.replaceShareButton(originalButton); } else if (this.attempts >= this.maxAttempts) { clearInterval(interval); console.warn(this.i18n.get('max_retry', { name: GM_info.script.name })); } }, this.pollInterval); } replaceShareButton(originalButton) { const newButton = this.createCustomButton(originalButton); originalButton.parentNode.replaceChild(newButton, originalButton); } createCustomButton(originalButton) { const button = document.createElement('button'); button.innerHTML = originalButton.innerHTML; button.className = originalButton.className; button.style.cssText = originalButton.style.cssText; button.addEventListener('click', () => this.handleButtonClick()); return button; } handleButtonClick() { const shortUrl = this.getShortUrl(); if (shortUrl) { this.copyToClipboard(shortUrl); this.showNotification(this.i18n.get('copied', {name: GM_info.script.name,url: shortUrl})); } else { this.showNotification(this.i18n.get('format_error', { name: GM_info.script.name })); } } getShortUrl() { const currentUrl = window.location.href; const videoId = new URL(currentUrl).searchParams.get('v'); return videoId ? `https://youtu.be/${videoId}` : null; } copyToClipboard(text) { GM_setClipboard(text, 'text'); } showNotification(message) { const notification = document.createElement('div'); notification.textContent = message; Object.assign(notification.style, { position: 'fixed', top: '50%', left: '50%', transform: 'translate(-50%, -50%)', backgroundColor: 'rgba(0, 0, 0, 0.5)', color: 'white', padding: '10px', borderRadius: '5px', zIndex: '1000' }); document.body.appendChild(notification); setTimeout(() => { if (notification.parentNode) { document.body.removeChild(notification); } }, this.notificationDuration); } } class LocalizationManager { constructor() { const lang = navigator.language.toLowerCase(); console.log('lang',lang) if (lang.startsWith('zh')) this.lang = 'zh'; else if (lang.startsWith('ja')) this.lang = 'ja'; else if (lang.startsWith('es')) this.lang = 'es'; else if (lang.startsWith('de')) this.lang = 'de'; else this.lang = 'en'; } get(key, replacements = {}) { const template = this.messages[this.lang][key] || this.messages['en'][key] || key; return template.replace(/\{(\w+)\}/g, (_, name) => replacements[name] || ''); } messages = { en: { copied: "{name}:short URL copied: {url}", format_error: "{name}:short URL format changed, please wait for script update", no_title: "{name}:could not find <title> element", max_retry: "{name}:exceeded retry limit, share button not found" }, zh: { copied: "{name}:縮網址已被複製: {url}", format_error: "{name}:縮網址格式改變,請等待腳本更新", no_title: "{name}:找不到 <title> 元素", max_retry: "{name}:超過最大重試次數,無法找到分享按鈕" }, ja: { copied: "{name}:の短縮URLをコピーしました: {url}", format_error: "{name}:の短縮URL形式が変更されました。スクリプトの更新をお待ちください", no_title: "{name}:は <title> 要素を見つけられませんでした", max_retry: "{name}:は最大試行回數を超え、共有ボタンが見つかりません" }, es: { copied: "{name}:URL corta copiada por ${name}: ${url}", format_error: "{name}:El formato de URL corta de ${name} ha cambiado. Espera una actualización del script", no_title: "{name}:no pudo encontrar el elemento <title>", max_retry: "{name}:superó el número máximo de intentos. Botón de compartir no encontrado" }, de: { copied: "{name}:Kurzlink wurde kopiert: ${url}", format_error: "{name}:Kurzlink-Format wurde geändert. Bitte auf ein Skript-Update warten", no_title: "{name}:konnte das <title>-Element nicht finden", max_retry: "{name}:hat die maximale Anzahl an Versuchen überschritten. Teilen-Schaltfläche nicht gefunden" } }; } class TitleObserver { constructor(onNavigate) { this.currentTitle = document.title; this.onNavigate = onNavigate; this.observe(); } observe() { const titleElement = document.querySelector('title'); if (!titleElement) { console.warn('找不到 <title> 元素'); return; } const observer = new MutationObserver(() => { if (document.title !== this.currentTitle) { this.currentTitle = document.title; if (window.location.href.startsWith('https://www.youtube.com/watch?v=')) { this.onNavigate(); } } }); observer.observe(titleElement, { childList: true }); } } const johnTheTrackingStoper = new YouTubeShortUrlCopier(); new TitleObserver(() => johnTheTrackingStoper.waitForShareButton());
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址