// ==UserScript==
// @name YouTube Vertical Toggle Videos/Comments
// @namespace http://tampermonkey.net/
// @version 1.0
// @description Toggle between "Videos" and "comments" sections on YouTube when screen width less than 1000px, is useful when on a Vertical Screen
// @author Nate2898
// @match *://*.youtube.com/*
// @icon https://www.google.com/s2/favicons?sz=64&domain=youtube.com
// @license MIT
// @grant none
// @namespace https://gf.qytechs.cn/en/users/1083698
// @downloadURL
// @updateURL
// ==/UserScript==
(function() {
'use strict';
// Add CSS to only show the toggle button when screen is < 1000px
const style = document.createElement('style');
style.textContent = `
#toggle-videos-comments-container { display: none !important; }
@media (max-width: 1000px) {
#toggle-videos-comments-container { display: flex !important; }
}
`;
document.head.appendChild(style);
const STATE_KEY = 'ytToggleState';
const SAVE_ENABLED_KEY = 'ytToggleSaveEnabled';
// Default save setting: disabled
if (!localStorage.getItem(SAVE_ENABLED_KEY)) {
localStorage.setItem(SAVE_ENABLED_KEY, 'false');
}
// Save the toggle state (videos or comments) if saving is enabled
function saveState(isComments) {
if (!isSaveEnabled()) return;
try {
localStorage.setItem(STATE_KEY, isComments ? 'comments' : 'videos');
} catch {}
}
// Load the previously saved toggle state
function loadState() {
try {
return isSaveEnabled() ? localStorage.getItem(STATE_KEY) : null;
} catch {
return null;
}
}
// Check if the save setting is enabled
function isSaveEnabled() {
try {
return localStorage.getItem(SAVE_ENABLED_KEY) === 'true';
} catch {
return false;
}
}
// Set whether saving is enabled
function setSaveEnabled(enabled) {
try {
localStorage.setItem(SAVE_ENABLED_KEY, enabled ? 'true' : 'false');
} catch {}
}
// Show both videos and comments sections
function showBoth() {
['#related', '#comments'].forEach(sel => {
const el = document.querySelector(sel);
if (el) el.style.display = '';
});
}
// Apply the saved toggle state to show either comments or videos
function applyState() {
const state = loadState();
const videos = document.querySelector('#related');
const comments = document.querySelector('#comments');
const toggle = document.querySelector('#toggle-videos-comments-container input[type=checkbox].main-toggle');
if (!videos || !comments || !toggle) return;
const showComments = (state === 'comments');
videos.style.display = showComments ? 'none' : '';
comments.style.display = showComments ? '' : 'none';
toggle.checked = showComments;
toggle.dispatchEvent(new Event('change'));
}
// Create the toggle button UI and checkbox
function createToggleButton() {
if (document.querySelector('#toggle-videos-comments-container')) return;
const container = document.createElement('div');
container.id = 'toggle-videos-comments-container';
Object.assign(container.style, {
display: 'flex',
flexDirection: 'row',
alignItems: 'center',
margin: '5px 0',
justifyContent: 'center',
gap: '10px'
});
// Add "Remember toggle" checkbox
const saveCheckbox = document.createElement('input');
saveCheckbox.type = 'checkbox';
saveCheckbox.checked = isSaveEnabled();
saveCheckbox.title = 'Remember toggle between sessions';
saveCheckbox.addEventListener('change', () => {
setSaveEnabled(saveCheckbox.checked);
});
// Add label text next to the toggle
const label = document.createElement('div');
label.textContent = 'Videos/Comments';
Object.assign(label.style, {
fontSize: '16px',
fontWeight: 'bold',
color: '#FFF'
});
// Create the toggle switch
const sliderLabel = document.createElement('label');
Object.assign(sliderLabel.style, {
position: 'relative',
display: 'inline-block',
width: '60px',
height: '20px'
});
const input = document.createElement('input');
input.classList.add('main-toggle');
input.type = 'checkbox';
input.style.opacity = '0';
input.style.width = '0';
input.style.height = '0';
input.addEventListener('change', () => {
const videos = document.querySelector('#related');
const comments = document.querySelector('#comments');
if (!videos || !comments) return;
if (input.checked) {
videos.style.display = 'none';
comments.style.display = '';
saveState(true);
} else {
videos.style.display = '';
comments.style.display = 'none';
saveState(false);
}
});
// Style the toggle track and thumb
const track = document.createElement('span');
Object.assign(track.style, {
position: 'absolute',
cursor: 'pointer',
top: '0',
left: '0',
right: '0',
bottom: '0',
backgroundColor: '#fc0703', //Video slider color
transition: '0.4s',
borderRadius: '20px'
});
const thumb = document.createElement('span');
Object.assign(thumb.style, {
position: 'absolute',
height: '15px',
width: '15px',
left: '4px',
bottom: '3px',
backgroundColor: '#FFF', // Slider dot color
transition: '0.4s',
borderRadius: '50%'
});
// Update appearance when toggle changes
input.addEventListener('change', () => {
if (input.checked) {
track.style.backgroundColor = '#2196F3'; //Comments slider color
thumb.style.transform = 'translateX(36px)';
} else {
track.style.backgroundColor = '#fc0703'; //Video slider color
thumb.style.transform = 'translateX(0)';
}
});
track.appendChild(thumb);
sliderLabel.appendChild(input);
sliderLabel.appendChild(track);
// Append all elements to the container
container.appendChild(saveCheckbox);
container.appendChild(label);
container.appendChild(sliderLabel);
// Insert the toggle below the main video content
const above = document.querySelector('#above-the-fold');
if (above) above.insertAdjacentElement('afterend', container);
// Apply toggle state if small screen
if (window.matchMedia('(max-width: 1000px)').matches) applyState();
}
// Observe for page changes and create toggle accordingly
let currentUrl = location.href;
const observer = new MutationObserver(() => {
if (location.href !== currentUrl) {
currentUrl = location.href;
handleUrlChange();
}
createToggleButton();
});
// Clean up and reset when navigating
function handleUrlChange() {
const old = document.querySelector('#toggle-videos-comments-container');
if (old) old.remove();
showBoth();
createToggleButton();
}
observer.observe(document.body, { childList: true, subtree: true });
// Re-apply state when resizing below 1000px
window.matchMedia('(max-width: 1000px)').addEventListener('change', e => {
if (e.matches) applyState();
else showBoth();
});
})();