mirror of
https://github.com/GetOpenScript/YouTube.openscript.git
synced 2026-10-08 22:05:19 +00:00
Add Better Share Button script
Clicking Share copies a clean video link without the si tracking token. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,24 @@
|
||||
# YouTube.openscript
|
||||
|
||||
User scripts for YouTube powered by [OpenScript](https://github.com/GetOpenScript/OpenScript).
|
||||
|
||||
## Scripts
|
||||
|
||||
### 1. Better Share Button (`better-share-button.os.js`)
|
||||
|
||||
Clicking **Share** instantly copies a clean video link to your clipboard: no share dialog, no `?si=` tracking token.
|
||||
|
||||
#### Features
|
||||
- **One Click Copy:** Share skips the dialog and copies the link straight away, with a small confirmation toast.
|
||||
- **Tracking Stripped:** Copies `https://youtu.be/<id>` instead of `https://youtu.be/<id>?si=...`.
|
||||
- **Shorts Support:** The Shorts share button copies `https://youtube.com/shorts/<id>`.
|
||||
- **Player Buttons Too:** Covers the watch page, the fullscreen player actions, and the player share button.
|
||||
- **Dialog Fallback:** If the native share dialog still opens, its **Copy** button copies the link without tracking parameters (keeps `t` and `list`).
|
||||
- **Language Independent:** Targets the share icon rather than the localized `Share` label.
|
||||
|
||||
#### Installation
|
||||
1. Install [OpenScript](https://chromewebstore.google.com/detail/openscript/dkelmgdchndagjemmodhkphdikhpnfol).
|
||||
2. Open the OpenScript popup and click **New Script**.
|
||||
3. Copy and paste the contents of [`better-share-button.os.js`](better-share-button.os.js) into the editor.
|
||||
4. Save the script and ensure it is enabled.
|
||||
5. Open any YouTube video or Short and click **Share**.
|
||||
@@ -0,0 +1,78 @@
|
||||
// ==UserScript==
|
||||
// @name Better Share Button
|
||||
// @version 1.0.0
|
||||
// @description Clicking Share on YouTube instantly copies a clean video link with the si tracking parameter stripped.
|
||||
// @match https://www.youtube.com/*
|
||||
// @run-at document_idle
|
||||
// ==/UserScript==
|
||||
|
||||
const TOAST_ID = 'os-better-share-toast';
|
||||
const SHARE_ICON = 'M10 3.158V7.51';
|
||||
const SCOPE = 'ytd-watch-metadata, ytd-video-primary-info-renderer, reel-action-bar-view-model, #movie_player, #shorts-player';
|
||||
const KEEP = ['t', 'list'];
|
||||
let toastTimer;
|
||||
|
||||
const videoUrl = () => {
|
||||
const short = location.pathname.match(/^\/shorts\/([\w-]{11})/)?.[1];
|
||||
if (short) return `https://youtube.com/shorts/${short}`;
|
||||
const id = new URLSearchParams(location.search).get('v')
|
||||
|| location.pathname.match(/^\/live\/([\w-]{11})/)?.[1]
|
||||
|| document.querySelector('ytd-watch-flexy')?.getAttribute('video-id');
|
||||
return id && `https://youtu.be/${id}`;
|
||||
};
|
||||
|
||||
const clean = raw => {
|
||||
try {
|
||||
const url = new URL(raw);
|
||||
[...url.searchParams.keys()].forEach(k => KEEP.includes(k) || url.searchParams.delete(k));
|
||||
return url.href;
|
||||
} catch { return raw; }
|
||||
};
|
||||
|
||||
const copy = async text => {
|
||||
try { await navigator.clipboard.writeText(text); }
|
||||
catch {
|
||||
const area = Object.assign(document.createElement('textarea'), { value: text });
|
||||
area.style.cssText = 'position:fixed;opacity:0';
|
||||
document.body.append(area);
|
||||
area.select();
|
||||
document.execCommand('copy');
|
||||
area.remove();
|
||||
}
|
||||
toast('Clean link copied to clipboard');
|
||||
};
|
||||
|
||||
const toast = msg => {
|
||||
let el = document.getElementById(TOAST_ID);
|
||||
if (!el) {
|
||||
el = Object.assign(document.createElement('div'), { id: TOAST_ID });
|
||||
el.style.cssText = `position:fixed;left:24px;bottom:24px;z-index:9999;padding:14px 16px;border-radius:8px;
|
||||
font:500 14px Roboto,Arial,sans-serif;pointer-events:none;transition:opacity .2s,transform .2s;
|
||||
background:var(--yt-spec-inverted-background,#0f0f0f);color:var(--yt-spec-text-primary-inverse,#fff)`;
|
||||
document.body.append(el);
|
||||
}
|
||||
el.textContent = msg;
|
||||
el.style.opacity = '1';
|
||||
el.style.transform = 'none';
|
||||
clearTimeout(toastTimer);
|
||||
toastTimer = setTimeout(() => {
|
||||
el.style.opacity = '0';
|
||||
el.style.transform = 'translateY(8px)';
|
||||
}, 2500);
|
||||
};
|
||||
|
||||
const isShare = btn => btn.closest(SCOPE)
|
||||
&& !btn.closest('ytd-macro-markers-list-item-renderer')
|
||||
&& (btn.matches('.ytp-share-button') || btn.querySelector(`path[d^="${SHARE_ICON}"]`));
|
||||
|
||||
window.addEventListener('click', e => {
|
||||
const btn = e.target.closest?.('button');
|
||||
if (!btn) return;
|
||||
// Native share dialog (e.g. opened from a menu): copy its link without tracking
|
||||
const input = btn.closest('yt-copy-link-renderer')?.querySelector('#share-url');
|
||||
const url = input ? clean(input.value) : isShare(btn) && videoUrl();
|
||||
if (!url) return;
|
||||
e.preventDefault();
|
||||
e.stopImmediatePropagation();
|
||||
copy(url);
|
||||
}, true);
|
||||
Reference in New Issue
Block a user