// ==UserScript== // @name YouTube enhancer for Via // @namespace https://viayoo.com/ // @version 1.1 // @license MIT // @description NewPipe button, force H.264 ≤30FPS, persistent quality lock, HW acceleration. // @author jc // @match *://*.youtube.com/* // @match *://*.youtube-nocookie.com/* // @match *://*.youtubekids.com/* // @match https://m.youtube.com/* // @exclude *://www.youtube.com/*/music* // @exclude *://music.youtube.com/* // @run-at document-start // @grant none // @downloadURL none // ==/UserScript== (function () { 'use strict'; // 1. Force H.264 and ≤30fps (function () { const BAD = /webm|vp8|vp9|av01/i; const FR = /framerate=(\d+)/; const ms = window.MediaSource; if (!ms) return; const orig = ms.isTypeSupported.bind(ms); ms.isTypeSupported = type => { if (typeof type !== 'string' || BAD.test(type)) return false; const m = FR.exec(type); if (m && +m[1] > 30) return false; return orig(type); }; })(); // 2. Hide overlays (function () { const rules = [ '.ytp-ad-overlay.ytp-overlay-loading', '.ytp-featured-product', 'ytd-ad-preview-slot-renderer', 'ytm-compact-ad' ]; const s = document.createElement('style'); s.textContent = rules.join(',') + '{display:none!important;}'; document.head.appendChild(s); })(); // 3. Floating NewPipe-style download button (function () { function makeBtn() { const btn = document.createElement('div'); btn.textContent = '↓'; Object.assign(btn.style, { position: 'fixed', bottom: '80px', right: '16px', width: '44px', height: '44px', display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: '24px', background: '#222', color: '#fff', borderRadius: '50%', boxShadow: '0 2px 10px rgba(0,0,0,0.3)', cursor: 'pointer', zIndex: 999999, transition: 'opacity .2s, transform .2s', opacity: '0.6' }); btn.addEventListener('mouseenter', () => btn.style.opacity = '1'); btn.addEventListener('mouseleave', () => btn.style.opacity = '0.6'); btn.addEventListener('click', () => { let id = new URL(location.href).searchParams.get('v'); if (!id) { const m = location.pathname.match(/\/shorts\/([^\/?&]+)/); id = m && m[1]; } if (id) { location.href = `intent://www.youtube.com/watch?v=${id}#Intent;scheme=https;package=org.schabi.newpipe;end`; } }); document.body.appendChild(btn); } if (document.body) makeBtn(); else new MutationObserver((_, obs) => { if (document.body) { obs.disconnect(); makeBtn(); } }).observe(document.documentElement, { childList: true }); })(); // 4. Persistent quality setter with fallback (function () { const QUALITY_KEY = 'yt_quality_preference'; // Save quality on selection const observeMenu = new MutationObserver(() => { document.querySelectorAll('.ytp-menuitem-label').forEach(el => { if (/^\d+p$/.test(el.textContent)) { el.addEventListener('click', () => { localStorage.setItem(QUALITY_KEY, el.textContent); }, { once: true }); } }); }); observeMenu.observe(document.documentElement, { childList: true, subtree: true }); // Apply saved quality function applyQuality() { const q = localStorage.getItem(QUALITY_KEY); if (!q) return; const trySet = () => { const player = document.querySelector('video')?.player_ || window.ytplayer?.config?.args; if (!player) return; try { if (typeof player.setPlaybackQuality === 'function') { player.setPlaybackQuality(q); player.setPlaybackQualityRange && player.setPlaybackQualityRange(q); } else if (window.yt && yt.player && yt.player.getPlayerByElement) { const p = yt.player.getPlayerByElement(document.querySelector('#movie_player')); if (p && p.setPlaybackQuality) p.setPlaybackQuality(q); } } catch (e) {} }; const t = setInterval(() => { trySet(); }, 1000); setTimeout(() => clearInterval(t), 8000); } document.addEventListener('yt-navigate-finish', applyQuality); window.addEventListener('load', applyQuality); })(); // 5. Mobile-only hardware acceleration and bottom bar pin if (location.hostname === 'm.youtube.com') { const css = ` ytm-app>.page-manager, ytm-browse-response-renderer, ytm-search-response-renderer, ytm-section-list-renderer, ytm-player-fragment, ytm-watch-player-renderer, ytm-player-layout, .html5-video-player, ytm-reel-player-overlay-renderer, ytm-shorts-player-renderer, ytm-reel-video-renderer, ytm-reel-watch-sequence-renderer { transform: translateZ(0); } ytm-pivot-bar-renderer { position: fixed!important; bottom: 0!important; left: 0!important; right: 0!important; width: 100%!important; z-index: 2000!important; background-color: var(--yt-spec-brand-background-solid,#fff)!important; border-top: 1px solid var(--yt-spec-10-percent-layer,rgba(0,0,0,0.1))!important; } body, ytm-app, ytm-app>.page-manager { padding-bottom: 56px!important; } `; const style = document.createElement('style'); style.textContent = css; (document.head || document.documentElement).appendChild(style); document.body.addEventListener('click', e => { const a = e.target.closest('a[href]'); if (a) { const u = a.href; if ((u.includes('/watch?v=') || u.includes('/shorts/')) && !a.closest('ytm-pivot-bar-renderer') && !a.closest('ytm-player-controls-overlay-renderer') && !a.closest('.player-controls-middle')) { e.preventDefault(); e.stopPropagation(); window.open(u, '_blank'); } } }, true); } })();