Navigate YouTube Shorts using your device's next/prev media keys (including headset).
// ==UserScript==
// @name Navigation for YouTube Shorts
// @namespace http://tampermonkey.net/
// @version 1.2
// @description Navigate YouTube Shorts using your device's next/prev media keys (including headset).
// @author CHJ85
// @match https://www.youtube.com/shorts/*
// @grant none
// ==/UserScript==
(function() {
'use strict';
// Inject code into the page context
function inject(fn) {
const s = document.createElement('script');
s.textContent = '(' + fn.toString() + ')()';
document.documentElement.appendChild(s);
s.remove();
}
// Code that runs directly in YouTube's JS context
function pageScript() {
// Simulate ArrowUp/ArrowDown
function simulateArrowKey(dir) {
const key = dir === 'next' ? 'ArrowDown' : 'ArrowUp';
document.dispatchEvent(new KeyboardEvent('keydown', { key, code: key, bubbles: true }));
//console.log(`[YS Nav] dispatched ${key}`);
}
// Clear & re-apply your handlers
function applyHandlers() {
if (!navigator.mediaSession || !location.pathname.includes('/shorts/')) return;
navigator.mediaSession.setActionHandler('nexttrack', null);
navigator.mediaSession.setActionHandler('previoustrack', null);
navigator.mediaSession.setActionHandler('nexttrack', () => simulateArrowKey('next'));
navigator.mediaSession.setActionHandler('previoustrack', () => simulateArrowKey('previous'));
//console.log('[YS Nav] handlers applied');
}
// Assign dummy metadata once so the session is live
try {
navigator.mediaSession.metadata = new MediaMetadata({
title: 'YouTube Short',
artist: 'Unknown',
album: 'YouTube Shorts'
});
} catch (e) {
// ignore
}
// Every 1 second, re-apply handlers (covers loops, SPA nav, metadata resets)
setInterval(applyHandlers, 1000);
console.log('[YS Nav] pageScript initialized (v1.9) – re-applying handlers every second');
}
inject(pageScript);
})();