Removes YouTube’s new “Delhi” player experiment flags to restore the old video player UI. In English, this userscript brings back the Youtube UI we all know and love. This was developed due to many users like myself wanting a free method to get rid of the new video player change Youtube has forced on us. This userscript also comes with Return Youtube Dislike, Skip Sponsored Segments via Sponsorblock & many tweaks, all of which are toggleable.
< Feedback on OldYTPlayer | YouTube Old Player UI Pre-2025 & Minimal Tweaks
I want that too. Here's what I got, but sometimes it works, sometimes it doesn't; apparently, it depends on the YouTube website itself:
// ==UserScript==
// @name OldYTPlayer
// @namespace YouTube Old Player UI Pre-2025 & Minimal Tweaks ✂
// @match https://www.youtube.com/*
// license
// @author DudeAint
// @grant none
// @run-at document-start
// @description Removes YouTube’s new “Delhi” player experiment flags to restore the old video player UI. In english, this userscript brings back the Youtube UI we all know and love. Credits go to Jonny Buchanan at the "Control Panel for Youtube" extension/project. This was developed due to many users like myself wanting a free method to get rid of the new video player change Youtube has forced on us.
// @version 0.1
// @icon https://files.catbox.moe/tac4lf.png
// supportURL greatest.deepsurf.us/scripts/553368/
// ==/UserScript==
(function () { 'use strict';
try {
const CONFIG_TOGGLES = [
{
id: 'revert_player',
name: 'Revert Old Youtube Player',
desc: 'Restores the pre-2025 player UI and hides the new fullscreen UI. May require a refresh.',
iconName: 'home',
promptRefresh: true,
onChange: (state) => {
if (state) {
robustRemoveDelhiFlagsWithRetries();
applyFullscreenHideCSS();
} else {
removeFullscreenHideCSS();
}
}
}
];
// Setting blocks open a nested popup with its own toggles
const CONFIG_BLOCKS = [
{
type: 'block',
id: 'annoyances',
name: 'Annoyances',
desc: 'Hide little nuisances in the player.',
iconName: 'block', // material icon name
/** Features inside this setting block */
children: [
]
}
];
// Defaults: only revert_player ON by default
const DEFAULT_CONFIG = { revert_player: true };
// Helper: flatten all toggles (booleans) including those inside blocks
function getAllToggles(){
const nested = [];
for (const b of CONFIG_BLOCKS) if (b && Array.isArray(b.children)) nested.push(...b.children.filter(c=>!c.type || c.type==='toggle'));
return [...CONFIG_TOGGLES, ...nested];
}
// Fullscreen “Delhi” UI hide defaults (auto-applied when revert_player is ON). You can turn this off if you'd like, I haven't included a toggle for this yet.
const HIDE_FULLSCREEN_CONFIG = {
playerHideFullScreenMoreVideos: true,
playerHideFullScreenControls: true
};
/* ============================ LIGHT STORAGE ========================= */
const STORAGE_PREFIX = 'OldYTPlayer:toggle:'; // booleans only
const APPLIED_PREFIX = 'OldYTPlayer:applied:'; // booleans only
const VALUE_PREFIX = 'OldYTPlayer:value:'; // string values (selects, etc.)
const LS = window.localStorage;
// boolean toggles
function storageGet(id){ try{ return LS.getItem(STORAGE_PREFIX+id)==='1'; }catch(){ return false; } }
function storageSet(id,v){ try{ LS.setItem(STORAGE_PREFIX+id, v?'1':'0'); }catch(){} }
function storageHas(id){ try{ return LS.getItem(STORAGE_PREFIX+id)!==null; }catch(){ return false; } }
function appliedGet(id){ try{ return LS.getItem(APPLIED_PREFIX+id)==='1'; }catch(){ return storageGet(id); } }
function appliedSet(id,v){ try{ LS.setItem(APPLIED_PREFIX+id, v?'1':'0'); }catch(_){} }
function appliedSeedFromCurrent(){ for (const cfg of getAllToggles()) appliedSet(cfg.id, storageGet(cfg.id)); }
// value selects
function storageGetVal(id, def){ try{ const v=LS.getItem(VALUE_PREFIX+id); return v!==null ? v : def; }catch(){ return def; } }
function storageSetVal(id, v){ try{ LS.setItem(VALUE_PREFIX+id, String(v)); }catch(){} }
function storageHasVal(id){ try{ return LS.getItem(VALUE_PREFIX+id)!==null; }catch(_){ return false; } }
// seed toggle defaults if missing
for (const cfg of getAllToggles()){
if (!storageHas(cfg.id)) {
const def = Object.prototype.hasOwnProperty.call(DEFAULT_CONFIG, cfg.id) ? !!DEFAULT_CONFIG[cfg.id] : false;
storageSet(cfg.id, def);
}
}
// seed select defaults
for (const b of CONFIG_BLOCKS){
if (!b.children) continue;
for (const c of b.children){
if (c && c.type==='select'){
if (!storageHasVal(c.id)) storageSetVal(c.id, c.default);
}
}
}
/** Reset refresh state on every run (fresh load). */
appliedSeedFromCurrent();
/* ==================== DELHI FLAG REMOVAL (optimized) =============== */
const DELHI_STYLE_RE = /ytp-fullscreen-(quick-actions|grid)/;
let didStripDelhiStyles = false;
function tryRemoveDelhiFlagsOnce() {
try {
const yt = window.yt;
let mod = 0;
if (yt && yt.config_ && yt.config_.WEB_PLAYER_CONTEXT_CONFIGS) {
const cfgs = yt.config_.WEB_PLAYER_CONTEXT_CONFIGS;
for (const k in cfgs) {
const c = cfgs[k];
if (c && typeof c.serializedExperimentFlags === 'string') {
const before = c.serializedExperimentFlags;
if (!before.includes('delhi_modern_web_player')) {
if (before.includes('delhi_modern_web_player_icons')) {
const after = before
.replace(/&?delhi_modern_web_player_icons=true/g, '')
.replace(/&&+/g, '&').replace(/^&+/, '').replace(/&+$/, '');
if (after !== before) { c.serializedExperimentFlags = after; mod++; }
}
} else {
const after = before
.replace(/&?delhi_modern_web_player=true/g, '')
.replace(/&?delhi_modern_web_player_icons=true/g, '')
.replace(/&&+/g, '&').replace(/^&+/, '').replace(/&+$/, '');
if (after !== before) { c.serializedExperimentFlags = after; mod++; }
}
}
}
}
const removed = removeFullscreenQuickActions();
return mod + (removed ? 1 : 0);
} catch (_) { return 0; }
}
function removeFullscreenQuickActions() {
let removed = false;
const hasTargets = document.querySelector('.ytp-fullscreen-quick-actions, .ytp-fullscreen-grid');
if (!didStripDelhiStyles || hasTargets) {
const styles = document.getElementsByTagName('style');
for (let i = styles.length - 1; i >= 0; i--) {
const s = styles[i];
try {
const txt = s.textContent;
if (txt && DELHI_STYLE_RE.test(txt)) {
s.remove();
removed = true;
didStripDelhiStyles = true;
}
} catch() {}
}
}
if (hasTargets) {
const q = document.querySelectorAll('.ytp-fullscreen-quick-actions, .ytp-fullscreen-grid');
for (let i=0;i<q.length;i++) { try{ q[i].remove(); removed = true; }catch(){} }
}
return removed;
}
function robustRemoveDelhiFlagsWithRetries() {
if (tryRemoveDelhiFlagsOnce() > 0) return true;
let tries = 0, max = 60;
const t = setInterval(() => { tries++; const n = tryRemoveDelhiFlagsOnce(); if (n > 0 || tries >= max) clearInterval(t); }, 200);
const obs = new MutationObserver((muts) => {
for (let i=0;i<muts.length;i++){
const m = muts[i];
for (let j=0;j<m.addedNodes.length;j++){
const n = m.addedNodes[j];
if (n && n.nodeType === 1) {
const el = n;
if (el.matches && (el.matches('.ytp-fullscreen-quick-actions, .ytp-fullscreen-grid') ||
(el.tagName === 'STYLE' && DELHI_STYLE_RE.test(el.textContent||'')) )) { removeFullscreenQuickActions(); return; }
if (el.querySelector && el.querySelector('.ytp-fullscreen-quick-actions, .ytp-fullscreen-grid')) { removeFullscreenQuickActions(); return; }
}
}
}
});
obs.observe(document.documentElement, { childList:true, subtree:true });
return false;
}
//function removeHideSponsoredCSS() { document.getElementById('hide-sponsored-style')?.remove(); }
/* ========== =============== */
if (storageGet('revert_player')) { robustRemoveDelhiFlagsWithRetries(); applyFullscreenHideCSS(); }
if (storageGet('remove_ai_summary')) applyRemoveAISummaryCSS();
if (storageGet('enable_dislikes')) RYD.start();
if (storageGet('remove_hide_button')) applyRemoveHideButtonCSS();
if (storageGet('remove_pink')) applyRemovePinkCSS();
if (storageGet('hide_sponsored')) applyHideSponsoredCSS();
if (storageGet('hide_shorts')) applyHideShortsCSS();
applySearchThumbSizeCSS(storageGetVal('search_thumb_size','medium'));
applyMinimumGridItemsCSS(storageGetVal('minimum_grid_items', 'auto'));
if (storageGet('hide_share_thanks_clip')) applyHideShareThanksClipCSS();
/* ============================ DOM/STYLE ============================= */
const STYLE_ID = 'oldytplayer-style-v077'; // keep same look
function safeAppend(p,n){ try{ if(p && n && n.nodeType===1) p.appendChild(n); }catch(){} }
function ensureMaterialIcons(){
if (!document.querySelector('link[href*="fonts.googleapis.com/icon"]')){
const link=document.createElement('link');
link.rel='stylesheet';
link.href='https://fonts.googleapis.com/icon?family=Material+Icons';
(document.head||document.documentElement).appendChild(link);
}
}
function injectStyles(){
if (document.getElementById(STYLE_ID)) return;
ensureMaterialIcons();
const css = [
'.oldyt-panel{width:101% !important;box-sizing:border-box;padding:6px 8px;min-height:120px;max-height:100%;display:flex;flex-direction:column;}',
'.oldyt-top-row{display:flex;align-items:center;gap:8px;margin-bottom:8px;min-height:32px;flex:0 0 auto;}',
'.oldyt-back{cursor:pointer;display:flex;align-items:center;gap:8px;font-weight:600;color:#fff;}',
'.oldyt-back .material-icons{font-size:18px;transform:translateY(1px)}',
'.oldyt-refresh-banner{margin-left:auto;background:#c62828;color:#fff;padding:6px 10px;border-radius:6px;display:flex;align-items:center;gap:8px;font-size:13px;}',
'.oldyt-refresh-banner.hidden{display:none !important;}',
'.oldyt-refresh-btn{background:transparent;border:1px solid rgba(255,255,255,0.2);color:#fff;padding:6px 8px;border-radius:4px;cursor:pointer;font-weight:600;}',
'.oldyt-list{display:flex;flex-direction:column;gap:6px;flex:1 1 auto;min-height:0;overflow-y:auto;overflow-x:hidden;padding-right:6px;-webkit-overflow-scrolling:touch;}',
'.oldyt-item{display:flex;align-items:center;gap:12px;padding:8px;border-radius:8px;min-height:52px;}',
'.oldyt-item:hover{background:rgba(255,255,255,0.03);transition:background .03s ease;}',
'.oldyt-icon{width:32px;height:32px;min-width:32px;display:flex;align-items:center;justify-content:center;border-radius:6px;background:rgba(255,255,255,0.03)}',
'.oldyt-icon img{width:18px;height:18px;}',
'.oldyt-icon .material-icons{font-size:18px;}',
'.oldyt-textcol{display:flex;flex-direction:column;gap:3px;flex:1 1 auto;min-width:0;}',
'.oldyt-name{color:#fff;font-size:13px;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}',
'.oldyt-desc{color:rgba(255,255,255,0.78);font-size:12px;line-height:1;display:-webkit-box;-webkit-line-clamp:4;-webkit-box-orient:vertical;overflow:hidden;text-overflow:ellipsis;}',
'.oldyt-rightcol{margin-left:12px;display:flex;align-items:center;justify-content:flex-end;min-width:26.5px;}',
'.oldyt-rightcol.has-select{min-width:50px;}',
'.oldyt-toggle{display:inline-block;width:40px;height:22px;border-radius:22px;background:#6b6b6b;position:relative;box-shadow:inset 0 -2px 0 rgba(0,0,0,0.12);transition:background .12s ease;min-width:40px;}',
'.oldyt-toggle .oldyt-knob{position:absolute;top:3px;left:3px;width:16px;height:16px;border-radius:50%;background:#fff;box-shadow:0 1px 2px rgba(0,0,0,0.35);transition:left .12s ease;}',
'.oldyt-toggle.on{background:#e53935;}',
'.oldyt-toggle.on .oldyt-knob{left:21px;}',
'.oldyt-change-badge{display:inline-flex;align-items:center;justify-content:center;width:18px;height:18px;border-radius:50%;background:#c62828;margin-left:8px;vertical-align:middle;flex:0 0 auto;}',
'.oldyt-change-badge .material-icons{font-size:12px;color:#fff;}',
'.oldyt-select{appearance:none;background:rgba(255,255,255,0.06);color:#fff;border:1px solid rgba(255,255,255,0.2);border-radius:6px;padding:4px 8px;font-size:12px;min-width:50px;cursor:pointer;}',
'.oldyt-select:focus{outline:none;}',
'.oldyt-list::-webkit-scrollbar{width:8px;height:8px;}',
'.oldyt-list::-webkit-scrollbar-thumb{background:rgba(255,255,255,0.06);border-radius:8px;}'
].join('\n');
const style=document.createElement('style'); style.id=STYLE_ID;
try{ style.appendChild(document.createTextNode(css)); }catch(){ style.textContent=css; }
(document.head||document.documentElement).appendChild(style);
}
function makeMaterialIcon(name){
const i=document.createElement('i');
i.className='material-icons'; i.setAttribute('aria-hidden','true'); i.textContent=name;
return i;
}
/* ==================== GLOBAL INJECTION OBSERVER ===================== */
const processedPopups = new WeakSet();
function scanAndInjectAll(){
injectStyles();
const list = document.querySelectorAll('.ytp-popup.ytp-settings-menu');
for (let i=0;i{
for (let i=0;i<muts.length;i++){
const m = muts[i];
for (let j=0;j<m.addedNodes.length;j++){
const n = m.addedNodes[j];
if(!(n && n.nodeType===1)) continue;
const el = n;
if (el.matches && el.matches('.ytp-popup.ytp-settings-menu')) {
if (!processedPopups.has(el)) { injectIntoPopup(el); processedPopups.add(el); }
} else if (el.querySelector) {
const found = el.querySelectorAll('.ytp-popup.ytp-settings-menu');
for (let k=0;k<found.length;k++){
const p = found[k];
if (!processedPopups.has(p)) { injectIntoPopup(p); processedPopups.add(p); }
}
}
}
}
});
mo.observe(document.documentElement, { childList:true, subtree:true });
setInterval(scanAndInjectAll, 3000);
}
startObserver();
/* =================================================================== */
} catch(err){ console.error('[OldYTPlayer] top-level error', err); }
})();
//////////////////////////////////////////////////////////////////////////////////////////////
/// Or there's also this style: https://userstyles.world/style/24688/youtube-player-2016-2025-abandoned
There is no option to post code in this section. The page breaks the code. Here is a similar style that returns the old panel: https://userstyles.world/style/24688/youtube-player-2016-2025-abandoned
Thanks. But I still need to know how to install it. This script in the link, is it installed through Tampermonkey?
Hi there,
as I don't need so many features in your combo, and I don't understand scripting and can't extract the necessary code myself.
I will be publishing a chrome extension translation of this userscript which allows for this exact scenario. The development of the OYTP extension is finished. You can view the image attached for a preview of the extension popup settings. Currently, I'm waiting on the extension to be reviewed by Chrome.
Could you please post the code (at least in the description) that changes only the player interface from new to old
I may also be planning to add a "Lite" userscript version which only has the old UI flags enabled. But since the source is open, you can edit it to your will (although I understand you don't understand scripting). You can check in on the main page (info/description page) of the OYTP Greasyfork page, I will be posting a link to the extension on the Chrome Web Store once it's done being reviewed by Chrome, and possibly a Lite version of the userscript that you were speaking about.
Thanks for bringing this to my attention and thank you for using my script!
Всем привет,
Спасибо, что обратили на это мое внимание, и спасибо, что воспользовались моим сценарием!
I'm using the Firefox browser. And one more nuance: your extension does not display after the end of the video in the player window the offered videos in the form of 3x3 tiles only a black screen. If you make a lightweight version for Firefox, I would like you to take this fact into consider.
Спасибо. Но мне все еще нужно знать, как его установить. Этот скрипт по ссылке, он через Tampermonkey устанавливается?
This is a style, styles are set through an extension, which you need to get here:
https://addons.mozilla.org/ru/firefox/addon/styl-us/
https://chromewebstore.google.com/detail/stylus/clngdbkpkpeebahjckkjfobafhncgmne?hl=en
More styles: https://userstyles.world/search?q=youtube&sort=recentlyupdated
Hello. Could you please post the code (at least in the description) that changes only the player interface from new to old, as I don't need so many features in your combo, and I don't understand scripting and can't extract the necessary code myself.