// ==UserScript==
// @name EasyTube V4.0 โ Ad Skip & SponsorBlock & HD Downloadโฌ๏ธ๐ (No Lag)
// @name:vi EasyTube V4.0 โ Bแป qua quแบฃng cรกo, SponsorBlock & Tแบฃi HD (Khรดng lag)
// @name:zh-CN EasyTube V4.0 โ ๅนฟๅ่ทณ่ฟใSponsorBlock ๅ HD ไธ่ฝฝๅจ๏ผๆ ๅก้กฟ๏ผ
// @name:zh-TW EasyTube V4.0 โ ๅปฃๅ่ทณ้ใSponsorBlock ๅ HD ไธ่ผๅจ๏ผ็กๅก้ ๏ผ
// @name:ru EasyTube V4.0 โ ะัะพะฟััะบ ัะตะบะปะฐะผั, SponsorBlock ะธ HD ะทะฐะณััะทัะธะบ (ะฑะตะท ะปะฐะณะพะฒ)
// @name:ja EasyTube V4.0 โ ๅบๅในใญใใใปSponsorBlockใปHDใใฆใณใญใผใใผ๏ผใฉใฐใชใ๏ผ
// @name:ko EasyTube V4.0 โ ๊ด๊ณ ๊ฑด๋๋ฐ๊ธฐ, SponsorBlock, HD ๋ค์ด๋ก๋ (๋ ์์)
// @name:es EasyTube V4.0 โ Saltar anuncios, SponsorBlock y descarga HD (sin lag)
// @name:pt-BR EasyTube V4.0 โ Pular anรบncios, SponsorBlock e download HD (sem lag)
// @name:fr EasyTube V4.0 โ Ignorer pubs, SponsorBlock et tรฉlรฉchargeur HD (sans lag)
// @name:de EasyTube V4.0 โ Werbung รผberspringen, SponsorBlock, HD-Download (kein Lag)
// @name:tr EasyTube V4.0 โ Reklam Atlama, SponsorBlock ve HD ฤฐndirici (Lag Yok)
// @name:pl EasyTube V4.0 โ Pomijanie reklam, SponsorBlock, pobieranie HD (bez opรณลบnieล)
// @name:id EasyTube V4.0 โ Lewati Iklan, SponsorBlock & Unduhan HD (Tanpa Lag)
// @name:th EasyTube V4.0 โ เธเนเธฒเธกเนเธเธฉเธเธฒ, SponsorBlock เนเธฅเธฐเธเธฒเธงเธเนเนเธซเธฅเธ HD (เนเธกเนเธเธฃเธฐเธเธธเธ)
// @name:ar EasyTube V4.0 โ ุชุฎุทู ุงูุฅุนูุงูุงุชุ SponsorBlock ูุชูุฒูู HD (ุจุฏูู ุชุฃุฎูุฑ)
// @description V4.0 โ Rewritten for performance. ๐ซ Multi-layer ad skip with minimal CPU usage. โญ SponsorBlock (9 cats). ๐ฅ Force 4K. โฌ Download via evdfrance.fr. ๐พ Remembers settings. Bypass adblock detection. No Cobalt. No lag.
// @description:vi V4.0 โ Viแบฟt lแบกi tแปi ฦฐu hiแปu nฤng. ๐ซ Skip quแบฃng cรกo ฤa lแปp, CPU thแบฅp. โญ SponsorBlock 9 danh mแปฅc. ๐ฅ รp 4K. โฌ Tแบฃi video qua evdfrance.fr. ๐พ Lฦฐu cร i ฤแบทt. Bypass popup adblock. Khรดng lag.
// @description:zh-CN V4.0 โ ๆง่ฝ้ๅ็ใ๐ซ ๅคๅฑๅนฟๅ่ทณ่ฟ๏ผไฝCPUๅ ็จใโญ SponsorBlock(9็ฑปๅซ)ใ๐ฅ 4K็ป่ดจใโฌ ้่ฟevdfrance.frไธ่ฝฝ่ง้ขใ๐พ ไฟๅญ่ฎพ็ฝฎใ็ป่ฟๅนฟๅๆฆๆชๆฃๆตใๆ ๅก้กฟใ
// @description:zh-TW V4.0 โ ๆ่ฝ้ๅฏซ็ใ๐ซ ๅคๅฑคๅปฃๅ่ทณ้๏ผไฝCPUๅ ็จใโญ SponsorBlock๏ผ9้กๅฅ๏ผใ๐ฅ 4K็ซ่ณชใโฌ ้้evdfrance.frไธ่ผๅฝฑ็ใ๐พ ๅฒๅญ่จญๅฎใ็น้ๅปฃๅๆๆชๅตๆธฌใ็กๅก้ ใ
// @description:ru V4.0 โ ะะตัะตะฟะธัะฐะฝะพ ะดะปั ะฟัะพะธะทะฒะพะดะธัะตะปัะฝะพััะธ. ๐ซ ะะณะฝะพะฒะตะฝะฝัะน ะฟัะพะฟััะบ ัะตะบะปะฐะผั. โญ SponsorBlock (9 ะบะฐัะตะณะพัะธะน). ๐ฅ 4K ะบะฐัะตััะฒะพ. โฌ ะะฐะณััะทะบะฐ ัะตัะตะท evdfrance.fr. ๐พ ะกะพั
ัะฐะฝะตะฝะธะต ะฝะฐัััะพะตะบ. ะะตะท ะปะฐะณะพะฒ.
// @description:ja V4.0 โ ใใใฉใผใใณในๆ้ฉๅ็ใ๐ซ ๅ
จๅบๅใๅณๆในใญใใใโญ SponsorBlock๏ผ9ใซใใดใช๏ผใ๐ฅ 4K็ป่ณชใโฌ evdfrance.frใงใใฆใณใญใผใใ๐พ ่จญๅฎไฟๅญใๅบๅใใญใใฏๆคๅบๅ้ฟใใฉใฐใชใใ
// @description:ko V4.0 โ ์ฑ๋ฅ ์ต์ ํ ์ฌ์์ฑ. ๐ซ ์ฆ์ ๊ด๊ณ ์คํต, CPU ์ ์ฝ. โญ SponsorBlock(9์นดํ
๊ณ ๋ฆฌ). ๐ฅ 4Kํ์ง. โฌ evdfrance.fr ๋ค์ด๋ก๋. ๐พ ์ค์ ์ ์ฅ. ๊ด๊ณ ์ฐจ๋จ ๊ฐ์ง ์ฐํ. ๋ ์์.
// @description:es V4.0 โ Reescrito para rendimiento. ๐ซ Salta anuncios al instante. โญ SponsorBlock. ๐ฅ 4K. โฌ Descarga por evdfrance.fr. ๐พ Ajustes guardados. Sin lag.
// @description:fr V4.0 โ Rรฉรฉcrit pour la performance. ๐ซ Ignore les pubs instantanรฉment. โญ SponsorBlock. ๐ฅ 4K. โฌ Tรฉlรฉchargement via evdfrance.fr. ๐พ Paramรจtres sauvegardรฉs. Sans lag.
// @description:de V4.0 โ Fรผr Performance neu geschrieben. ๐ซ Werbung sofort รผberspringen. โญ SponsorBlock. ๐ฅ 4K. โฌ Download via evdfrance.fr. ๐พ Einstellungen gespeichert. Kein Lag.
// @description:pt-BR V4.0 โ Reescrito para desempenho. ๐ซ Pula anรบncios instantaneamente. โญ SponsorBlock. ๐ฅ 4K. โฌ Download via evdfrance.fr. ๐พ Configuraรงรตes salvas. Sem lag.
// @description:tr V4.0 โ Performans iรงin yeniden yazฤฑldฤฑ. ๐ซ Reklamlarฤฑ anฤฑnda atlar. โญ SponsorBlock. ๐ฅ 4K. โฌ evdfrance.fr ile indirme. ๐พ Ayarlar kaydedilir. Lag yok.
// @description:pl V4.0 โ Przepisane dla wydajnoลci. ๐ซ Natychmiastowe pomijanie reklam. โญ SponsorBlock. ๐ฅ 4K. โฌ Pobieranie przez evdfrance.fr. ๐พ Zapamiฤtuje ustawienia. Bez opรณลบnieล.
// @description:id V4.0 โ Ditulis ulang untuk performa. ๐ซ Lewati iklan seketika. โญ SponsorBlock. ๐ฅ 4K. โฌ Unduh via evdfrance.fr. ๐พ Pengaturan tersimpan. Tanpa lag.
// @description:ar V4.0 โ ุฃูุนูุฏุช ุงููุชุงุจุฉ ูุชุญุณูู ุงูุฃุฏุงุก. ๐ซ ุชุฎุทู ุงูุฅุนูุงูุงุช ููุฑุงู. โญ SponsorBlock. ๐ฅ 4K. โฌ ุชูุฒูู ุนุจุฑ evdfrance.fr. ๐พ ุงูุฅุนุฏุงุฏุงุช ู
ุญููุธุฉ. ุจุฏูู ุชุฃุฎูุฑ.
// @description:th V4.0 โ เนเธเธตเธขเธเนเธซเธกเนเนเธเธทเนเธญเธเธฃเธฐเธชเธดเธเธเธดเธ เธฒเธ ๐ซ เธเนเธฒเธกเนเธเธฉเธเธฒเธเธฑเธเธเธต โญ SponsorBlock ๐ฅ 4K โฌ เธเธฒเธงเธเนเนเธซเธฅเธเธเนเธฒเธ evdfrance.fr ๐พ เธเธฑเธเธเธถเธเธเธฒเธฃเธเธฑเนเธเธเนเธฒ เนเธกเนเธเธฃเธฐเธเธธเธ
// @namespace https://greasyfork.org/users/1510019
// @version 4.0.0
// @author 2pixel (rewrite: performance-optimized)
// @license MIT
// @icon https://raw.githubusercontent.com/not2pixel/TampermonkeyProjects/refs/heads/main/EasyTube.png
// @icon64 https://raw.githubusercontent.com/not2pixel/TampermonkeyProjects/refs/heads/main/EasyTube.png
// @match https://*.youtube.com/*
// @exclude https://www.youtube.com/live_chat*
// @exclude https://studio.youtube.com/*
// @grant GM_addStyle
// @grant GM_xmlhttpRequest
// @grant GM_setValue
// @grant GM_getValue
// @connect sponsor.ajay.app
// @connect evdfrance.fr
// @run-at document-start
// @compatible chrome Tampermonkey 4+
// @compatible firefox Tampermonkey / Violentmonkey
// @compatible edge Tampermonkey 4+
// @compatible opera Supported via Tampermonkey / Violentmonkey
// @homepageURL https://greasyfork.org/en/scripts/561432
// @supportURL https://greasyfork.org/en/scripts/561432/feedback
// ==/UserScript==
'use strict';
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
// LAYER 0 โ InnerTube patch (document-start, zero cost)
// Wipes adPlacements before YouTube even schedules them.
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
(function patchYT() {
// Intercept adPlacements on any object
try {
Object.defineProperty(Object.prototype, 'adPlacements', {
get() { return undefined; },
set(v) {
Object.defineProperty(this, 'adPlacements', {
value: [], writable: true, configurable: true, enumerable: true,
});
},
configurable: true,
});
} catch (_) {}
// Intercept ytInitialPlayerResponse
try {
let _yipr;
Object.defineProperty(window, 'ytInitialPlayerResponse', {
get() { return _yipr; },
set(v) {
if (v) {
if (v.adPlacements) v.adPlacements = [];
if (v.auxiliaryUi?.messageRenderers) {
try { v.auxiliaryUi.messageRenderers.enforcementMessageViewModel = undefined; } catch {}
}
}
_yipr = v;
},
configurable: true,
});
} catch (_) {}
})();
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
// AD CSS โ hide ad elements instantly, no JS cost
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
(function injectAdCSS() {
const style = document.createElement('style');
style.textContent = `
ytd-action-companion-ad-renderer, ytd-display-ad-renderer,
ytd-video-masthead-ad-v3-renderer, ytd-overlay-ad-renderer,
ytd-promoted-sparkles-web-renderer, ytd-promoted-video-renderer,
ytd-search-pyv-renderer, ytd-ad-slot-renderer, yt-about-this-ad-renderer,
.ytd-banner-promo-renderer, #masthead-ad, ytd-mealbar-promo-renderer,
tp-yt-paper-dialog:has(ytd-mealbar-promo-renderer),
ytd-in-feed-ad-layout-renderer, ytd-statement-banner-renderer,
#player-ads, .ytd-ad-slot-renderer,
ytd-rich-item-renderer:has(ytd-ad-slot-renderer),
.ytp-ce-element, .ytp-cards-teaser
{ display: none !important; }
.ytp-ad-text-overlay, .ytp-ad-timed-pie-countdown-container,
.ytp-ad-image-overlay
{ visibility: hidden !important; opacity: 0 !important; }
`;
(document.head || document.documentElement).appendChild(style);
})();
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
// CONFIG
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
const CFG = {
version: '4.0.0',
sbApi: 'https://sponsor.ajay.app/api/skipSegments',
sbCats: ['sponsor','selfpromo','interaction','intro','outro',
'preview','music_offtopic','filler','exclusive_access'],
sbTypes: ['skip','mute'],
};
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
// STATE
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
const S = {
adEnabled: GM_getValue('et4_ad', false),
sbEnabled: GM_getValue('et4_sb', false),
qualityEnabled: GM_getValue('et4_quality', false),
adCount: 0,
sbCount: 0,
adSpeedActive: false,
prevVolume: 1,
sbSegments: [],
sbVideoId: null,
sbMutedSeg: null,
lastUrl: location.href,
videoId: null,
// Performance: cache DOM nodes
_player: null,
_video: null,
};
function save(key, val) { GM_setValue(key, val); }
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
// DOM HELPERS โ cached, low GC pressure
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
function getPlayer() {
if (S._player && S._player.isConnected) return S._player;
S._player = document.getElementById('movie_player');
return S._player;
}
function getVideo() {
if (S._video && S._video.isConnected) return S._video;
const p = getPlayer();
S._video = p ? p.querySelector('video') : document.querySelector('video');
return S._video;
}
// Single classList check โ much faster than querySelectorAll for hot path
function isAdPlaying() {
const p = getPlayer();
if (!p) return false;
// Check player class (fastest)
if (p.classList.contains('ad-showing') || p.classList.contains('ad-interrupting')) return true;
// Check countdown badge (reliable indicator)
return !!(
p.querySelector('.ytp-ad-countdown') ||
p.querySelector('.ytp-ad-simple-ad-badge') ||
p.querySelector('.ytp-ad-persistent-progress-bar-container')
);
}
const SKIP_SELECTORS = [
'.ytp-skip-ad-button',
'.ytp-ad-skip-button',
'.ytp-ad-skip-button-modern',
'.ytp-ad-skip-button-slot button',
'button[class*="skip-ad"]',
'[id*="skip-button"] button',
];
function getSkipBtn() {
const p = getPlayer();
if (!p) return null;
for (const sel of SKIP_SELECTORS) {
const btn = p.querySelector(sel);
if (btn && btn.offsetParent !== null) return btn;
}
return null;
}
function fireClick(el) {
el.dispatchEvent(new MouseEvent('click', { bubbles: true, cancelable: true, view: window }));
}
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
// AD ENGINE โ debounced, low CPU
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
let _skipRaf = false;
function trySkipAd() {
if (!S.adEnabled || _skipRaf) return;
_skipRaf = true;
// Defer to next frame โ batches rapid MutationObserver calls
requestAnimationFrame(() => {
_skipRaf = false;
_doSkip();
});
}
function _doSkip() {
const video = getVideo();
// 1. Skippable ad โ seek to end, then click
const btn = getSkipBtn();
if (btn) {
if (video && isFinite(video.duration) && video.duration > 0) {
video.currentTime = video.duration - 0.1;
}
fireClick(btn);
btn.click();
if (video) { video.playbackRate = 1; video.muted = false; }
S.adSpeedActive = false;
S.adCount++;
uiSync();
toast('๐ซ Ad skipped!', '#e53935');
return;
}
const adActive = isAdPlaying();
// 2. Unskippable โ 16x speed
if (video && adActive && !S.adSpeedActive) {
S.adSpeedActive = true;
S.prevVolume = video.volume;
video.playbackRate = 16;
video.muted = true;
toast('โก Ad 16รโฆ', '#ff6f00');
}
// 3. Restore after ad ends
if (video && !adActive && S.adSpeedActive) {
video.playbackRate = 1;
video.muted = false;
video.volume = S.prevVolume;
S.adSpeedActive = false;
}
// 4. Overlay close buttons
const p = getPlayer();
if (p) {
p.querySelectorAll(
'.ytp-ad-overlay-close-button, .ytp-ad-overlay-slot-close-button'
).forEach(b => { try { b.click(); } catch {} });
}
// 5. Enforcement popup
dismissEnforcement();
}
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
// ENFORCEMENT DISMISSAL โ runs on a slow timer, not hot path
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
const ENFORCEMENT_SELS = [
'ytd-enforcement-message-view-model',
'yt-playability-error-supported-renderers',
'[id="enforcement-message"]',
'yt-player-error-message-renderer',
];
function dismissEnforcement() {
for (const sel of ENFORCEMENT_SELS) {
const modal = document.querySelector(sel);
if (!modal) continue;
const btn = modal.querySelector('yt-button-shape button, button');
if (btn) { try { btn.click(); } catch {} }
else {
const wrap = modal.closest('tp-yt-paper-dialog, ytd-popup-container');
if (wrap) wrap.remove(); else modal.remove();
}
}
// Patch yt config flags
try {
const popup = window.yt?.config_?.openPopupConfig?.supportedPopups;
if (popup?.adBlockMessageViewModel !== undefined) popup.adBlockMessageViewModel = false;
} catch {}
try {
const d = window.ytcfg?.data_?.PLAYER_VARS;
if (d) d.ad3_module = '0';
} catch {}
}
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
// OBSERVER โ targeted, filtered, low CPU
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
let _adObserver = null;
let _bodyObserver = null;
function setupObservers() {
if (_adObserver) { _adObserver.disconnect(); _adObserver = null; }
if (_bodyObserver) { _bodyObserver.disconnect(); _bodyObserver = null; }
// Wait for player
let tries = 0;
const wait = setInterval(() => {
const player = getPlayer();
if (!player && ++tries < 40) return;
clearInterval(wait);
if (!player) return;
// Player observer โ only watch class changes (ad-showing is a class toggle)
_adObserver = new MutationObserver(mutations => {
if (!S.adEnabled) return;
for (const m of mutations) {
if (m.type === 'attributes' || m.addedNodes.length) {
trySkipAd();
return;
}
}
});
_adObserver.observe(player, {
childList: true,
subtree: true,
attributes: true,
attributeFilter: ['class', 'style'],
});
// Body observer โ only watch for enforcement modal injection
_bodyObserver = new MutationObserver(mutations => {
for (const m of mutations) {
for (const node of m.addedNodes) {
if (node.nodeType !== 1) continue;
if (
node.tagName?.includes('ENFORCEMENT') ||
node.id?.includes('enforcement') ||
node.querySelector?.('ytd-enforcement-message-view-model')
) {
setTimeout(dismissEnforcement, 80);
return;
}
}
}
});
_bodyObserver.observe(document.body, { childList: true, subtree: false });
}, 300);
}
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
// FALLBACK โ slow interval, only fires when needed
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
setInterval(() => {
if (S.adEnabled) _doSkip();
dismissEnforcement();
}, 800);
setInterval(dismissEnforcement, 2000);
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
// SPONSORBLOCK
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
async function sha256Prefix(str) {
try {
const buf = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(str));
return Array.from(new Uint8Array(buf)).map(b => b.toString(16).padStart(2,'0')).join('').slice(0, 4);
} catch { return null; }
}
function fetchSB(videoId) {
if (!S.sbEnabled || !videoId || videoId === S.sbVideoId) return;
S.sbVideoId = videoId;
S.sbSegments = [];
const cats = CFG.sbCats.map(c => `&category=${c}`).join('');
const types = CFG.sbTypes.map(t => `&actionType=${t}`).join('');
function parseSegments(text) {
try {
const data = JSON.parse(text);
let segs = [];
if (Array.isArray(data) && data[0]?.segments) {
const match = data.find(d => d.videoID === videoId);
segs = match?.segments || [];
} else if (Array.isArray(data) && data[0]?.segment) {
segs = data;
}
S.sbSegments = segs.map(s => ({
start: s.segment[0], end: s.segment[1],
cat: s.category, actionType: s.actionType || 'skip', uuid: s.UUID,
}));
} catch { S.sbSegments = []; }
}
sha256Prefix(videoId).then(prefix => {
const hashUrl = prefix ? `https://sponsor.ajay.app/api/skipSegments/${prefix}?${cats.slice(1)}${types}` : null;
const directUrl = `${CFG.sbApi}?videoID=${videoId}${cats}${types}`;
GM_xmlhttpRequest({
method: 'GET', url: hashUrl || directUrl,
onload(r) {
if (r.status === 200) { parseSegments(r.responseText); return; }
if (hashUrl) GM_xmlhttpRequest({
method: 'GET', url: directUrl,
onload(r2) { if (r2.status === 200) parseSegments(r2.responseText); },
onerror() {},
});
},
onerror() {
if (hashUrl) GM_xmlhttpRequest({
method: 'GET', url: directUrl,
onload(r2) { if (r2.status === 200) parseSegments(r2.responseText); },
onerror() {},
});
},
});
});
}
// SponsorBlock check โ runs on rAF, not interval
let _sbLast = 0;
function checkSB(ts) {
if (ts - _sbLast >= 400) {
_sbLast = ts;
_doCheckSB();
}
requestAnimationFrame(checkSB);
}
function _doCheckSB() {
if (!S.sbEnabled || !S.sbSegments.length) return;
const video = getVideo();
if (!video || video.paused) return;
const t = video.currentTime;
for (const seg of S.sbSegments) {
const inSeg = t >= seg.start && t < seg.end - 0.1;
if (seg.actionType === 'mute') {
if (inSeg) {
if (S.sbMutedSeg !== seg.uuid) {
S.sbMutedSeg = seg.uuid;
video.muted = true;
S.sbCount++; uiSync();
toast(`๐ SB: [${seg.cat}]`, '#7b1fa2');
}
} else if (S.sbMutedSeg === seg.uuid) {
video.muted = false;
S.sbMutedSeg = null;
}
} else if (inSeg) {
video.currentTime = seg.end;
S.sbCount++; uiSync();
toast(`โญ SB: [${seg.cat}]`, '#1a73e8');
break;
}
}
}
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
// AUTO QUALITY
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
const QUALITY_LABELS = {
highres:'8K', hd2160:'4K 2160p', hd1440:'1440p',
hd1080:'1080p HD', hd720:'720p HD', large:'480p', medium:'360p', small:'240p',
};
function setQuality() {
if (!S.qualityEnabled) return;
try {
const player = getPlayer();
if (!player?.getAvailableQualityLevels) return;
const levels = player.getAvailableQualityLevels();
if (!levels?.length) return;
const best = levels[0];
if (player.getPlaybackQuality() !== best) {
player.setPlaybackQualityRange(best, best);
player.setPlaybackQuality(best);
toast(`โจ Quality: ${QUALITY_LABELS[best] || best}`, '#e53935');
}
} catch {}
}
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
// DOWNLOAD โ evdfrance.fr (fast, no Cobalt timeout lag)
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
function downloadVideo(videoId) {
if (!videoId) return;
toast('โฌ Opening downloadโฆ', '#1565c0');
window.open(`https://evdfrance.fr/convert/?id=${videoId}`, '_blank');
}
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
// NAVIGATION
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
function getVideoId(url = location.href) {
return (
url.match(/[?&]v=([^&#]{11})/)?.[1] ||
url.match(/shorts\/([^?&#]{11})/)?.[1] ||
url.match(/youtu\.be\/([^?&#]{11})/)?.[1] ||
null
);
}
function getTitle() {
const sel = [
'ytd-watch-metadata h1 yt-formatted-string',
'#title h1 yt-formatted-string',
'h2 span.yt-core-attributed-string[role="text"]',
'.title.ytd-video-primary-info-renderer',
];
for (const s of sel) {
const t = document.querySelector(s)?.textContent?.trim();
if (t?.length > 1) return t;
}
return document.title?.replace(/\s*[-|]\s*YouTube\s*$/i, '').trim() || 'EasyTube';
}
let _navTimer = null;
function onNavigate() {
clearTimeout(_navTimer);
_navTimer = setTimeout(() => {
S._player = null;
S._video = null;
const vid = getVideoId();
S.videoId = vid;
if (vid) {
if (vid !== S.sbVideoId) fetchSB(vid);
if (S.qualityEnabled) {
[1500, 3000, 5000].forEach(d => setTimeout(setQuality, d));
}
}
setupObservers();
uiSync();
}, 600);
}
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
// UI
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
let _toastTimer = null;
function toast(msg, color = '#333') {
let el = document.getElementById('et4_toast');
if (!el) {
el = document.createElement('div');
el.id = 'et4_toast';
Object.assign(el.style, {
position:'fixed', bottom:'80px', left:'50%',
transform:'translateX(-50%)',
color:'#fff', padding:'7px 20px', borderRadius:'999px',
fontSize:'13px', fontWeight:'700',
zIndex:'2147483647', pointerEvents:'none',
fontFamily:'system-ui,sans-serif',
transition:'opacity .3s, transform .3s',
});
document.body.appendChild(el);
}
el.textContent = msg;
el.style.background = color;
el.style.opacity = '1';
el.style.transform = 'translateX(-50%) translateY(0)';
clearTimeout(_toastTimer);
_toastTimer = setTimeout(() => {
el.style.opacity = '0';
el.style.transform = 'translateX(-50%) translateY(-8px)';
}, 2500);
}
let _uiRaf = false;
function uiSync() {
if (_uiRaf) return;
_uiRaf = true;
requestAnimationFrame(() => {
_uiRaf = false;
document.getElementById('et4_ad_n')?.replaceChildren(document.createTextNode(S.adCount));
document.getElementById('et4_sb_n')?.replaceChildren(document.createTextNode(S.sbCount));
syncToggle('et4_sw_ad', S.adEnabled);
syncToggle('et4_sw_sb', S.sbEnabled);
syncToggle('et4_sw_q', S.qualityEnabled);
const vid = getVideoId();
const titleEl = document.getElementById('et4_title');
if (titleEl) titleEl.textContent = vid ? getTitle() : 'Open a video to start';
const idEl = document.getElementById('et4_vid_id');
if (idEl) idEl.textContent = vid || 'N/A';
// Update download button state
const dlBtn = document.getElementById('et4_dl_btn');
if (dlBtn) dlBtn.style.opacity = vid ? '1' : '0.5';
});
}
function syncToggle(id, state) {
const sw = document.getElementById(id);
if (!sw) return;
sw.classList.toggle('on', !!state);
const st = document.getElementById(id + '_st');
if (st) st.textContent = state ? 'ON' : 'OFF';
}
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
// PANEL BUILD โ Trusted Types compliant (no innerHTML)
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
// Create an element with optional class, text content, and attributes
function mk(tag, cls, text, attrs) {
const el = document.createElement(tag);
if (cls) el.className = cls;
if (text != null) el.appendChild(document.createTextNode(text));
if (attrs) {
for (const [k, v] of Object.entries(attrs)) {
if (k === 'id') el.id = v;
else el.setAttribute(k, v);
}
}
return el;
}
// Build one toggle card (icon + switch + label + state text)
function makeToggleCard(icon, swId, name, stId) {
const tc = mk('div', 'e4-tc');
const top = mk('div', 'e4-tc-top');
top.appendChild(mk('span', 'e4-tc-ico', icon));
const btn = mk('button', 'e4-sw', null, { id: swId, type: 'button' });
btn.appendChild(mk('span', 'e4-thumb'));
top.appendChild(btn);
const bot = mk('div', 'e4-tc-bot');
bot.appendChild(mk('span', 'e4-tc-name', name));
bot.appendChild(mk('span', 'e4-tc-st', 'OFF', { id: stId }));
tc.appendChild(top);
tc.appendChild(bot);
return tc;
}
function buildPanel() {
// โโ Toggle button โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
const tog = mk('div', null, null, { id: 'et4_tog' });
const svgNS = 'http://www.w3.org/2000/svg';
const svg = document.createElementNS(svgNS, 'svg');
svg.setAttribute('viewBox', '0 0 24 24');
svg.setAttribute('width', '22');
svg.setAttribute('height', '22');
const path1 = document.createElementNS(svgNS, 'path');
path1.setAttribute('d', 'M23.5 6.3a3.1 3.1 0 0 0-2.2-2.2C19.4 3.5 12 3.5 12 3.5s-7.4 0-9.3.6A3.1 3.1 0 0 0 .5 6.3 32.7 32.7 0 0 0 0 12a32.7 32.7 0 0 0 .5 5.7 3.1 3.1 0 0 0 2.2 2.2c1.9.6 9.3.6 9.3.6s7.4 0 9.3-.6a3.1 3.1 0 0 0 2.2-2.2A32.7 32.7 0 0 0 24 12a32.7 32.7 0 0 0-.5-5.7Z');
path1.setAttribute('fill', '#FF0000');
const path2 = document.createElementNS(svgNS, 'path');
path2.setAttribute('d', 'M9.75 15.5V8.5L16 12l-6.25 3.5Z');
path2.setAttribute('fill', '#FFF');
svg.appendChild(path1);
svg.appendChild(path2);
tog.appendChild(svg);
document.body.appendChild(tog);
// โโ Panel โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
const panel = mk('div', null, null, { id: 'et4_panel' });
// Header
const hdr = mk('div', 'e4-hdr', null, { id: 'et4_drag' });
const hdrL = mk('div', 'e4-hdr-l');
hdrL.appendChild(mk('div', 'e4-logo', 'โถ'));
const hdrTxt = mk('div');
hdrTxt.appendChild(mk('div', 'e4-hdr-title', 'EasyTube V4.0'));
hdrTxt.appendChild(mk('div', 'e4-hdr-sub', 'Ad Skip ยท SponsorBlock ยท 4K ยท HD Download'));
hdrL.appendChild(hdrTxt);
hdr.appendChild(hdrL);
hdr.appendChild(mk('div', 'e4-drag-dot', 'โฎ'));
panel.appendChild(hdr);
// Stats bar
const stats = mk('div', 'e4-stats');
const pillAd = mk('div', 'e4-pill', '๐ซ Ads: ');
pillAd.appendChild(mk('span', null, '0', { id: 'et4_ad_n' }));
const pillSb = mk('div', 'e4-pill', 'โญ Sponsors: ');
pillSb.appendChild(mk('span', null, '0', { id: 'et4_sb_n' }));
stats.appendChild(pillAd);
stats.appendChild(pillSb);
stats.appendChild(mk('div', 'e4-pill e4-ver', `v${CFG.version}`));
panel.appendChild(stats);
// Body
const body = mk('div', 'e4-body');
// Video card
const card = mk('div', 'e4-card');
const cardRow = mk('div', 'e4-card-row');
cardRow.appendChild(mk('div', 'e4-card-label', 'NOW PLAYING'));
const badge = mk('span', 'e4-badge', `โ v${CFG.version}`);
cardRow.appendChild(badge);
card.appendChild(cardRow);
card.appendChild(mk('div', 'e4-card-title', 'Open a video to start', { id: 'et4_title' }));
const cardId = mk('div', 'e4-card-id', 'ID: ');
cardId.appendChild(mk('code', null, 'N/A', { id: 'et4_vid_id' }));
card.appendChild(cardId);
body.appendChild(card);
// โโ Download button โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
const dlBtn = mk('button', 'e4-btn e4-btn-red', null, { id: 'et4_dl_btn', type: 'button' });
dlBtn.appendChild(mk('span', 'e4-btn-ico', 'โฌ'));
dlBtn.appendChild(mk('span', null, 'Download Video (HD/4K)'));
body.appendChild(dlBtn);
// Toggle grid
const grid = mk('div', 'e4-grid');
grid.appendChild(makeToggleCard('๐ซ', 'et4_sw_ad', 'Ad Skip', 'et4_sw_ad_st'));
grid.appendChild(makeToggleCard('โญ', 'et4_sw_sb', 'SponsorBlock', 'et4_sw_sb_st'));
grid.appendChild(makeToggleCard('โจ', 'et4_sw_q', 'Auto 4K', 'et4_sw_q_st'));
body.appendChild(grid);
// Info box
const info = mk('div', 'e4-info-box');
info.appendChild(mk('span', 'e4-info-icon', 'โก'));
info.appendChild(mk('span', null, 'V4.0: Rewritten for performance โ lower CPU, faster skip, no Cobalt timeout lag.'));
body.appendChild(info);
panel.appendChild(body);
panel.appendChild(mk('div', 'e4-foot', `EasyTube V4.0 ยท 2pixel ยท 2025`));
document.body.appendChild(panel);
return { panel, tog };
}
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
// DRAG โ pointer events, RAF-throttled
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
function initDrag(panel) {
const hdr = panel.querySelector('#et4_drag');
const vw = window.innerWidth, vh = window.innerHeight;
let ox = vw - 375, oy = vh - 580;
ox = Math.max(8, ox); oy = Math.max(8, oy);
panel.style.transform = `translate3d(${ox}px,${oy}px,0)`;
let dragging = false, pid = null, ix = 0, iy = 0, raf = false;
const pw = 360, ph = 560;
hdr.addEventListener('pointerdown', e => {
dragging = true; pid = e.pointerId;
ix = e.clientX - ox; iy = e.clientY - oy;
panel.classList.add('e4-drag');
try { hdr.setPointerCapture(pid); } catch {}
}, { passive: true });
hdr.addEventListener('pointermove', e => {
if (!dragging || e.pointerId !== pid || raf) return;
raf = true;
requestAnimationFrame(() => {
ox = Math.max(8, Math.min(window.innerWidth - pw - 8, e.clientX - ix));
oy = Math.max(8, Math.min(window.innerHeight - ph - 8, e.clientY - iy));
panel.style.transform = `translate3d(${ox}px,${oy}px,0)`;
raf = false;
});
}, { passive: true });
const endDrag = e => {
if (e.pointerId !== pid) return;
dragging = false;
panel.classList.remove('e4-drag');
};
hdr.addEventListener('pointerup', endDrag, { passive: true });
hdr.addEventListener('pointercancel', endDrag, { passive: true });
}
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
// EVENTS
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
function bindEvents(panel, tog) {
let visible = false;
tog.addEventListener('click', () => {
visible = !visible;
panel.classList.toggle('e4-show', visible);
tog.classList.toggle('e4-active', visible);
if (visible) uiSync();
});
// Download button
document.getElementById('et4_dl_btn').addEventListener('click', () => {
const vid = getVideoId();
if (vid) downloadVideo(vid);
else toast('โ Open a video first', '#f57c00');
});
document.getElementById('et4_sw_ad').addEventListener('click', () => {
S.adEnabled = !S.adEnabled;
save('et4_ad', S.adEnabled);
if (!S.adEnabled) {
const v = getVideo();
if (v) { v.playbackRate = 1; v.muted = false; }
S.adSpeedActive = false;
}
uiSync();
toast(S.adEnabled ? '๐ซ Ad Skip ON' : '๐ซ Ad Skip OFF', S.adEnabled ? '#2e7d32' : '#b71c1c');
});
document.getElementById('et4_sw_sb').addEventListener('click', () => {
S.sbEnabled = !S.sbEnabled;
save('et4_sb', S.sbEnabled);
if (S.sbEnabled) { S.sbVideoId = null; fetchSB(getVideoId()); }
uiSync();
toast(S.sbEnabled ? 'โญ SponsorBlock ON' : 'โญ SponsorBlock OFF', S.sbEnabled ? '#1565c0' : '#4a148c');
});
document.getElementById('et4_sw_q').addEventListener('click', () => {
S.qualityEnabled = !S.qualityEnabled;
save('et4_quality', S.qualityEnabled);
if (S.qualityEnabled) setQuality();
uiSync();
toast(S.qualityEnabled ? 'โจ Auto 4K ON' : 'โจ Auto 4K OFF', S.qualityEnabled ? '#e53935' : '#616161');
});
}
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
// STYLES
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
GM_addStyle(`
@import url('https://fonts.googleapis.com/css2?family=Nunito:wght@600;700;800;900&display=swap');
#et4_panel, #et4_panel * { box-sizing:border-box; font-family:'Nunito',system-ui,sans-serif; }
/* โโ Toggle button โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
#et4_tog {
position:fixed; bottom:90px; right:18px;
width:54px; height:36px; border-radius:999px;
background:rgba(255,255,255,0.15);
border:1px solid rgba(255,255,255,0.25);
box-shadow:0 6px 20px rgba(0,0,0,.22);
z-index:2147483646; cursor:pointer;
display:flex; align-items:center; justify-content:center;
backdrop-filter:blur(16px);
transition:transform .18s, box-shadow .18s;
}
#et4_tog:hover { transform:translateY(-2px); box-shadow:0 10px 28px rgba(0,0,0,.3); }
#et4_tog.e4-active svg { transform:rotate(180deg); }
#et4_tog svg { transition:transform .3s; }
/* โโ Panel โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
#et4_panel {
position:fixed; top:0; left:0;
width:355px; max-width:94vw;
display:flex; flex-direction:column;
background:rgba(255,255,255,0.12);
backdrop-filter:blur(32px) saturate(180%);
-webkit-backdrop-filter:blur(32px) saturate(180%);
border:1px solid rgba(255,255,255,0.18);
border-radius:24px;
box-shadow:0 18px 50px rgba(0,0,0,.30);
z-index:2147483647; overflow:hidden;
opacity:0; pointer-events:none;
transform:scale(.96) translateY(12px);
transition:opacity .28s, transform .3s cubic-bezier(.25,.46,.45,.94);
will-change:transform, opacity;
}
#et4_panel.e4-show { opacity:1; pointer-events:all; transform:scale(1) translateY(0); }
#et4_panel.e4-drag { transition:none !important; }
/* โโ Header โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
.e4-hdr {
background:linear-gradient(135deg,#ff1a1a,#b80000);
padding:12px 14px; cursor:move; user-select:none;
display:flex; align-items:center; justify-content:space-between;
border-radius:24px 24px 0 0;
}
.e4-hdr-l { display:flex; align-items:center; gap:10px; }
.e4-logo { width:46px; height:32px; background:rgba(255,255,255,.18); border-radius:9px; display:flex; align-items:center; justify-content:center; font-size:20px; color:#fff; font-weight:900; }
.e4-hdr-title { color:#fff; font-size:15px; font-weight:800; line-height:1.2; }
.e4-hdr-sub { color:rgba(255,255,255,.8); font-size:10px; font-weight:600; }
.e4-drag-dot { color:rgba(255,255,255,.85); font-size:22px; }
/* โโ Stats bar โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
.e4-stats {
display:flex; gap:5px; padding:7px 12px;
background:rgba(0,0,0,.06); border-bottom:1px solid rgba(255,255,255,.08);
}
.e4-pill {
flex:1; background:rgba(255,255,255,.22); border:1px solid rgba(255,255,255,.18);
border-radius:999px; padding:4px 8px;
font-size:11px; font-weight:800; color:#0f0f0f;
display:flex; align-items:center; justify-content:center; gap:3px;
}
.e4-pill span { font-weight:900; font-size:13px; }
.e4-ver { font-size:10px; color:#555; flex:0 0 auto; padding:4px 10px; }
/* โโ Body โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
.e4-body {
padding:11px 13px 13px; overflow-y:auto; flex:1 1 auto;
scrollbar-width:thin; scrollbar-color:rgba(255,255,255,.3) transparent;
display:flex; flex-direction:column; gap:9px;
}
.e4-body::-webkit-scrollbar { width:6px; }
.e4-body::-webkit-scrollbar-thumb { background:rgba(255,255,255,.25); border-radius:999px; }
/* โโ Video card โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
.e4-card {
background:rgba(255,255,255,.24); border:1px solid rgba(255,255,255,.2);
border-radius:18px; padding:11px;
}
.e4-card-row { display:flex; align-items:center; justify-content:space-between; margin-bottom:6px; }
.e4-card-label { font-size:10px; font-weight:800; color:#606060; text-transform:uppercase; letter-spacing:.6px; }
.e4-badge { font-size:10.5px; font-weight:700; color:#00a152; background:rgba(232,245,233,.9); padding:3px 9px; border-radius:999px; }
.e4-card-title { font-size:13.5px; font-weight:700; color:#0f0f0f; line-height:1.4; margin-bottom:6px; word-break:break-word; }
.e4-card-id { font-size:11px; font-weight:600; color:#555; }
.e4-card-id code { background:rgba(255,255,255,.65); padding:2px 8px; border-radius:999px; margin-left:4px; }
/* โโ Download button โโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
.e4-btn {
display:flex; align-items:center; justify-content:center; gap:9px;
width:100%; padding:12px 16px; border:none; border-radius:18px;
font-size:14px; font-weight:800; cursor:pointer; color:#fff;
text-decoration:none; position:relative; overflow:hidden; letter-spacing:.2px;
font-family:'Nunito',system-ui,sans-serif;
transition:transform .2s, box-shadow .2s, opacity .2s;
}
.e4-btn:hover { transform:translateY(-2px); }
.e4-btn:active { transform:scale(.98); }
.e4-btn-red { background:linear-gradient(135deg,#ff1a1a,#cc0000); box-shadow:0 4px 14px rgba(255,0,0,.28); }
.e4-btn-ico { font-size:18px; }
/* โโ Toggle grid โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
.e4-grid { display:grid; grid-template-columns:repeat(3,1fr); gap:7px; }
.e4-tc {
background:rgba(255,255,255,.22); border:1px solid rgba(255,255,255,.18);
border-radius:15px; padding:10px 9px;
display:flex; flex-direction:column; gap:7px;
transition:transform .15s;
}
.e4-tc:hover { transform:translateY(-1px); }
.e4-tc-top { display:flex; align-items:center; justify-content:space-between; }
.e4-tc-ico { font-size:19px; line-height:1; }
.e4-tc-bot { display:flex; align-items:center; justify-content:space-between; gap:3px; }
.e4-tc-name { font-size:11px; font-weight:800; color:#0f0f0f; }
.e4-tc-st { font-size:10px; font-weight:700; color:rgba(15,15,15,.4); }
/* โโ Switch โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
.e4-sw {
width:40px; height:24px; border-radius:999px; border:none;
background:rgba(120,120,128,.28); position:relative; cursor:pointer;
transition:background .18s; flex:0 0 auto;
}
.e4-sw.on { background:rgba(52,199,89,.95); }
.e4-thumb {
position:absolute; top:2px; left:2px; width:20px; height:20px;
border-radius:999px; background:#fff;
box-shadow:0 3px 8px rgba(0,0,0,.18);
transition:transform .18s;
}
.e4-sw.on .e4-thumb { transform:translateX(16px); }
/* โโ Info box โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
.e4-info-box {
background:rgba(6,95,212,.12); border:1px solid rgba(6,95,212,.2);
border-radius:14px; padding:9px 12px;
font-size:11.5px; font-weight:600; color:#0f0f0f;
display:flex; align-items:flex-start; gap:8px; line-height:1.5;
}
.e4-info-icon { font-size:16px; flex:0 0 auto; margin-top:1px; }
/* โโ Footer โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
.e4-foot {
padding:8px 13px; background:rgba(255,255,255,.1);
border-top:1px solid rgba(255,255,255,.1);
border-radius:0 0 24px 24px; text-align:center;
font-size:10.5px; color:#606060; font-weight:600;
}
`);
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
// BOOT
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
function boot() {
const { panel, tog } = buildPanel();
initDrag(panel);
bindEvents(panel, tog);
uiSync();
setupObservers();
// Start SponsorBlock RAF loop
requestAnimationFrame(checkSB);
// Periodic UI sync
setInterval(uiSync, 2500);
// Navigation detection
const navObs = new MutationObserver(() => {
if (location.href !== S.lastUrl) {
S.lastUrl = location.href;
S.sbVideoId = null;
S.sbSegments = [];
onNavigate();
}
});
navObs.observe(document.body, { childList: true, subtree: false });
window.addEventListener('yt-navigate-finish', () => onNavigate(), { passive: true });
window.addEventListener('yt-page-data-updated', () => onNavigate(), { passive: true });
window.addEventListener('yt-navigate-start', () => {
S.sbVideoId = null;
S.sbSegments = [];
S._player = null;
S._video = null;
}, { passive: true });
onNavigate();
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', boot);
} else {
boot();
}