Greasy Fork is available in English.
Home: collapse guide, fixed hero layout for the first 5 videos, then 4/5 col grid below, hide Shorts. Flat chip bar. Watch: hide recommendations sidebar and center the player/content, while preserving live chat on streams/replays and engagement panels. Adds topbar theme and home grid switchers.
// ==UserScript==
// @name YouTube Layout Plus
// @namespace https://qazwsx123.uk/
// @version 0.7.0
// @description Home: collapse guide, fixed hero layout for the first 5 videos, then 4/5 col grid below, hide Shorts. Flat chip bar. Watch: hide recommendations sidebar and center the player/content, while preserving live chat on streams/replays and engagement panels. Adds topbar theme and home grid switchers.
// @author Codex
// @match https://www.youtube.com/*
// @run-at document-idle
// @grant none
// ==/UserScript==
(function () {
'use strict';
// ============================================================================
// 模块1: 常量定义
// ============================================================================
const Constants = {
// ID 常量
STYLE_ID: 'tm-youtube-layout-plus-style',
STYLE_VERSION: '0.7.0',
THEME_SWITCHER_ID: 'tm-youtube-layout-plus-theme-switcher',
HOME_GRID_SWITCHER_ID: 'tm-youtube-layout-plus-home-grid-switcher',
THEME_STATUS_ID: 'tm-youtube-layout-plus-theme-status',
// CSS 类名
Classes: {
REPLAY_HIDE: 'tm-youtube-layout-plus-hide-replay-prompt',
WATCH_PANEL_OPEN: 'tm-youtube-layout-plus-watch-panel-open',
WATCH_THEATER: 'tm-youtube-layout-plus-watch-theater',
WATCH_VERTICAL: 'tm-youtube-layout-plus-watch-vertical',
ROUTE_TRANSITION: 'tm-youtube-layout-plus-route-transition',
HERO_MIX: 'tm-youtube-layout-plus-hero-mix',
WATCH_CHAT_OPEN: 'tm-youtube-layout-plus-watch-chat-open',
WATCH_CHAT_COLLAPSED: 'tm-youtube-layout-plus-watch-chat-collapsed',
LAYOUT_MODES: [
'tm-youtube-layout-plus-home',
'tm-youtube-layout-plus-watch',
'tm-youtube-layout-plus-watch-chat',
'tm-youtube-layout-plus-watch-plain',
],
},
// 属性名
WATCH_READY_ATTR: 'data-tm-watch-ready',
// 存储键
Storage: {
THEME_MODE: 'tm-youtube-layout-plus-theme-mode',
HOME_GRID_COLUMNS: 'tm-youtube-layout-plus-home-grid-columns',
},
// 主题配置
THEME_MODES: [
{ mode: 'auto', label: 'Auto', actionName: 'yt-signal-action-toggle-dark-theme-device' },
{ mode: 'light', label: 'Light', actionName: 'yt-signal-action-toggle-dark-theme-off' },
{ mode: 'dark', label: 'Dark', actionName: 'yt-signal-action-toggle-dark-theme-on' },
],
// 布局配置
Layout: {
HOME_GRID_COLUMN_OPTIONS: [4, 5],
HOME_GRID_TRACK_COUNT: 20,
HOME_MAX_LAYOUT_WIDTH: 3000,
MAX_LAYOUT_WIDTH: 1300,
HOME_SIDE_CARDS_STACK_MEDIA: '(max-width: 1340px)',
HOME_SIDE_CARD_THUMB_DEFAULT: 'clamp(96px, 10vw, 180px)',
HOME_SIDE_CARD_TEXT_WIDTH_RATIO: 0.52,
HOME_SIDE_CARD_WIDE_THUMB_CAP: 460,
HOME_SIDE_CARD_ULTRAWIDE_THUMB_CAP: 520,
},
// 定时器配置
Timing: {
OBSERVER_APPLY_DEBOUNCE_MS: 150,
ROUTE_POLL_INTERVAL_MS: 3000,
WATCH_BOOTSTRAP_DELAYS: [0, 80, 200, 500, 1200],
},
// Cookie 位掩码
PREF_F6_PREF_BIT: 0x80,
PREF_F6_DARK_BIT: 0x400,
PREF_F6_LIGHT_BIT: 0x80000,
};
// ============================================================================
// 模块2: 状态管理
// ============================================================================
const State = {
// URL 状态
currentUrl: location.href,
// 动画帧
applyFrame: 0,
resizeFrame: 0,
// 定时器
timers: {
applyDelay: null,
route: null,
resize: null,
routeTransition: null,
watchBootstrap: null,
watchChatState: null,
themeStatusHide: null,
},
// 观察者
observers: {
body: null,
watchFlexyAttr: null,
watchFlexyObservedElement: null,
},
// 布局状态
layout: {
lastWatchChatExpanded: null,
lastEngagementPanelOpen: null,
lastTheaterMode: null,
lastPlayerSyncKey: '',
lastAutoCollapsedHomeUrl: '',
lastAutoCollapsedWatchChatKey: '',
watchBootstrapStep: 0,
},
// 主题状态
theme: {
currentMode: null,
switchInFlight: false,
pendingMode: null,
lastRenderedMode: null,
lastRenderedDisabled: null,
lastPersistedMode: null,
},
// 网格状态
grid: {
currentColumns: 5,
lastRenderedColumns: null,
},
// 缓存
elementDataCache: new WeakMap(),
};
// ============================================================================
// 模块3: 工具函数
// ============================================================================
const Utils = {
/**
* 延迟执行
*/
delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
},
/**
* 防抖函数
*/
debounce(fn, ms) {
let timer = null;
return function (...args) {
clearTimeout(timer);
timer = setTimeout(() => fn.apply(this, args), ms);
};
},
/**
* 检查元素是否可见
*/
isVisible(element) {
if (!element || element.hidden) return false;
const style = window.getComputedStyle(element);
if (style.display === 'none' || style.visibility === 'hidden') return false;
const rect = element.getBoundingClientRect();
return rect.width > 0 && rect.height > 0;
},
/**
* 安全获取数值样式
*/
getNumericStyle(style, property) {
const value = parseFloat(style.getPropertyValue(property));
return Number.isFinite(value) ? value : 0;
},
/**
* 从 URL 提取视频 ID
*/
extractVideoId(value) {
const text = String(value || '');
const directMatch = text.match(/(?:\/vi(?:_webp)?\/|[?&]v=)([a-zA-Z0-9_-]{11})/);
if (directMatch) return directMatch[1];
try {
const url = new URL(text, location.origin);
return url.searchParams.get('v');
} catch {
return null;
}
},
/**
* 从 Cookie 获取主题模式
*/
getThemeModeFromCookie() {
const prefEntries = document.cookie
.split('; ')
.filter(entry => entry.startsWith('PREF='));
const lastEntry = prefEntries[prefEntries.length - 1];
if (!lastEntry) return null;
try {
const pref = decodeURIComponent(lastEntry.slice(5));
const f6Match = pref.match(/(?:^|&)f6=([0-9a-fA-F]+)/);
if (!f6Match) return null;
const f6 = parseInt(f6Match[1], 16);
if (!Number.isFinite(f6)) return null;
if ((f6 & Constants.PREF_F6_LIGHT_BIT) !== 0) return 'light';
if ((f6 & Constants.PREF_F6_DARK_BIT) !== 0) return 'dark';
if ((f6 & Constants.PREF_F6_PREF_BIT) !== 0) return 'auto';
return null;
} catch {
return null;
}
},
/**
* 从文档推断主题模式
*/
inferThemeMode() {
return document.documentElement.hasAttribute('dark') ? 'dark' : 'light';
},
/**
* 获取观察到的主题模式
*/
getObservedThemeMode() {
return this.getThemeModeFromCookie() || this.inferThemeMode();
},
};
// ============================================================================
// 模块4: 存储管理
// ============================================================================
const Storage = {
/**
* 加载主题模式
*/
loadThemeMode() {
try {
const mode = localStorage.getItem(Constants.Storage.THEME_MODE);
return Constants.THEME_MODES.some(item => item.mode === mode) ? mode : null;
} catch {
return null;
}
},
/**
* 保存主题模式
*/
saveThemeMode(mode) {
if (State.theme.lastPersistedMode === mode) return;
try {
if (Constants.THEME_MODES.some(item => item.mode === mode)) {
localStorage.setItem(Constants.Storage.THEME_MODE, mode);
} else {
localStorage.removeItem(Constants.Storage.THEME_MODE);
}
State.theme.lastPersistedMode = mode;
} catch {
// 忽略存储失败
}
},
/**
* 加载首页网格列数
*/
loadHomeGridColumns() {
try {
const value = localStorage.getItem(Constants.Storage.HOME_GRID_COLUMNS);
return this.normalizeGridColumns(value);
} catch {
return 5;
}
},
/**
* 保存首页网格列数
*/
saveHomeGridColumns(columns) {
try {
localStorage.setItem(Constants.Storage.HOME_GRID_COLUMNS, String(this.normalizeGridColumns(columns)));
} catch {
// 忽略存储失败
}
},
/**
* 标准化网格列数
*/
normalizeGridColumns(value) {
const columns = Number(value);
return Constants.Layout.HOME_GRID_COLUMN_OPTIONS.includes(columns) ? columns : 5;
},
};
// ============================================================================
// 模块5: DOM 查询助手
// ============================================================================
const DOM = {
/**
* 页面类型判断
*/
isHomePage() {
return location.pathname === '/';
},
isWatchPage() {
return location.pathname === '/watch';
},
/**
* 获取观看页面键
*/
getWatchPageKey() {
if (!this.isWatchPage()) return location.pathname;
const params = new URLSearchParams(location.search);
const videoId = params.get('v');
return videoId ? `/watch?v=${videoId}` : location.pathname;
},
/**
* 获取页面元素
*/
getApp() {
return document.querySelector('ytd-app');
},
getWatchFlexy() {
return document.querySelector('ytd-watch-flexy');
},
getRichGrid() {
return document.querySelector('ytd-rich-grid-renderer');
},
getRichGridItems() {
return Array.from(document.querySelectorAll('#contents.ytd-rich-grid-renderer > ytd-rich-item-renderer'));
},
getLogoRenderer() {
return document.querySelector('ytd-topbar-logo-renderer');
},
/**
* 获取观看预告文本
*/
getWatchTeaserText() {
const teaser = document.querySelector('ytd-watch-metadata #teaser-carousel');
return (teaser?.innerText || teaser?.textContent || '').trim();
},
/**
* 检查直播/回放提示
*/
hasLiveWatchPrompt(teaserText) {
return /join the conversation to interact with the creator and others watching this live stream/i.test(teaserText)
|| (/watching now/i.test(document.body.innerText) && /started streaming/i.test(document.body.innerText));
},
hasReplayWatchPrompt(teaserText) {
return /live chat replay/i.test(teaserText)
|| /see what others said about this video while it was live/i.test(teaserText);
},
/**
* 检查侧边聊天
*/
hasWatchSidebarChat(watchFlexy) {
if (!watchFlexy) return false;
if (
watchFlexy.hasAttribute('is-live') ||
watchFlexy.hasAttribute('is-live-content') ||
watchFlexy.hasAttribute('live-chat-collapsed')
) {
return true;
}
const liveBadge = watchFlexy.querySelector(
'ytd-badge-supported-renderer[system-icons][icon="LIVE"], ' +
'ytd-thumbnail-overlay-time-status-renderer[overlay-style="LIVE"], ' +
'yt-icon[icon="yt-icons:live"]'
);
if (liveBadge && Utils.isVisible(liveBadge)) return true;
const teaserText = this.getWatchTeaserText();
if (this.hasLiveWatchPrompt(teaserText)) return true;
const chatFrame = watchFlexy.querySelector(
'ytd-live-chat-frame#chat, #chat ytd-live-chat-frame, #chat-container ytd-live-chat-frame'
);
const chatHost = chatFrame?.closest('#chat') || watchFlexy.querySelector('#chat, #chat-container');
const hasStampedChat = watchFlexy.hasAttribute('should-stamp-chat') || !!chatFrame || !!chatHost;
if (this.hasReplayWatchPrompt(teaserText) && hasStampedChat) return true;
if (!chatFrame || chatFrame.hasAttribute('hidden')) return false;
if (chatFrame.hasAttribute('collapsed')) return hasStampedChat;
return Utils.isVisible(chatFrame) || Utils.isVisible(chatHost);
},
/**
* 检查互动面板
*/
hasOpenEngagementPanel(watchFlexy) {
const host = watchFlexy || this.getWatchFlexy();
if (!host) return false;
return !!host.querySelector(
'ytd-engagement-panel-section-list-renderer[visibility="ENGAGEMENT_PANEL_VISIBILITY_EXPANDED"]'
);
},
/**
* 检查剧院模式
*/
isTheaterModeActive(watchFlexy) {
if (!this.isWatchPage()) return false;
const flexy = watchFlexy || this.getWatchFlexy();
return !!(flexy && flexy.hasAttribute('theater'));
},
/**
* 检查全屏
*/
isFullscreenActive() {
if (document.fullscreenElement) return true;
const flexy = this.getWatchFlexy();
return !!(flexy && flexy.hasAttribute('fullscreen'));
},
/**
* 检查是否为 Mix 卡片
*/
isHomeHeroMixCard(item) {
if (!item) return false;
if (item.querySelector('yt-collection-thumbnail-view-model, .ytCollectionThumbnailViewModelHost')) {
return true;
}
const titleElement = item.querySelector('#video-title, yt-formatted-string#video-title, a[title], h3');
const title = (titleElement?.getAttribute('title') || titleElement?.innerText || titleElement?.textContent || '').trim();
return /^mix\b/i.test(title);
},
/**
* 获取侧边卡片容器
*/
getHomeSideCardShell(item) {
return item.querySelector(
'ytd-rich-grid-media, yt-lockup-view-model, ytd-ad-slot-renderer, ytd-in-feed-ad-layout-renderer'
) || item.querySelector(':scope > #content') || item;
},
/**
* 查找打开面板按钮
*/
findOpenPanelButton() {
return Array.from(document.querySelectorAll('button, yt-button-shape button, tp-yt-paper-button')).find(
button => /open panel/i.test((button.innerText || button.textContent || '').trim())
) || null;
},
/**
* 安全获取 iframe 文档
*/
safeGetIframeDocument(frame) {
try {
return frame?.contentDocument || null;
} catch {
return null;
}
},
};
// ============================================================================
// 模块6: 样式管理
// ============================================================================
const StyleManager = {
/**
* 确保样式存在
*/
ensure() {
let style = document.getElementById(Constants.STYLE_ID);
if (style?.dataset.version === Constants.STYLE_VERSION) return;
if (!style) {
style = document.createElement('style');
style.id = Constants.STYLE_ID;
document.head.appendChild(style);
}
style.dataset.version = Constants.STYLE_VERSION;
style.textContent = this.generateCSS();
},
/**
* 生成 CSS
*/
generateCSS() {
const { Classes, Layout } = Constants;
const { HOME_MAX_LAYOUT_WIDTH, MAX_LAYOUT_WIDTH, HOME_SIDE_CARDS_STACK_MEDIA, HOME_SIDE_CARD_THUMB_DEFAULT } = Layout;
return `
/* 首页变量 */
html.tm-youtube-layout-plus-home {
--tm-guide-collapsed-width: 72px;
--tm-home-page-gutter: clamp(14px, 2.1vw, 28px);
--tm-home-available-width: calc(100vw - var(--tm-guide-collapsed-width));
--tm-home-layout-width: min(${HOME_MAX_LAYOUT_WIDTH}px, var(--tm-home-available-width));
--tm-hero-mix-object-position: center 82%;
--tm-card-bg: #f8f9fa;
--tm-card-border: rgba(15, 15, 15, 0.06);
--tm-card-shadow: 0 1px 2px rgba(15, 15, 15, 0.04), 0 6px 18px rgba(15, 15, 15, 0.05);
--tm-text-primary: #0f0f0f;
--tm-text-secondary: rgba(15, 15, 15, 0.62);
--tm-meta-secondary: rgba(15, 15, 15, 0.55);
--tm-chip-bg: rgba(15, 15, 15, 0.05);
--tm-chip-bg-hover: rgba(15, 15, 15, 0.09);
--tm-chip-bg-active: #0f0f0f;
--tm-chip-text: #0f0f0f;
--tm-chip-text-active: #ffffff;
--tm-font: 'Inter', -apple-system, BlinkMacSystemFont, 'SF Pro Display',
'Segoe UI', 'Helvetica Neue', Roboto, Arial, sans-serif;
}
/* 暗色模式变量 */
html[dark].tm-youtube-layout-plus-home {
--tm-card-bg: #1f1f1f;
--tm-card-border: rgba(255, 255, 255, 0.08);
--tm-card-shadow: 0 1px 2px rgba(0, 0, 0, 0.3), 0 6px 18px rgba(0, 0, 0, 0.18);
--tm-text-primary: #f1f1f1;
--tm-text-secondary: rgba(255, 255, 255, 0.72);
--tm-meta-secondary: rgba(255, 255, 255, 0.6);
--tm-chip-bg: rgba(255, 255, 255, 0.08);
--tm-chip-bg-hover: rgba(255, 255, 255, 0.14);
--tm-chip-bg-active: #ffffff;
--tm-chip-text: rgba(255, 255, 255, 0.92);
--tm-chip-text-active: #0f0f0f;
}
/* 隐藏重播提示 */
.${Classes.REPLAY_HIDE} {
display: none !important;
}
/* 主题切换器样式 */
#${Constants.THEME_SWITCHER_ID} {
position: relative;
display: flex;
align-items: center;
gap: 0;
margin-left: 12px;
padding: 4px 6px;
border: 1px solid var(--yt-spec-10-percent-layer, rgba(0, 0, 0, 0.1));
border-radius: 999px;
background: var(--yt-spec-badge-chip-background, rgba(0, 0, 0, 0.05));
}
#${Constants.THEME_STATUS_ID} {
position: fixed;
top: 72px;
right: 24px;
z-index: 2200;
max-width: 320px;
padding: 10px 14px;
border: 1px solid rgba(190, 60, 60, 0.28);
border-radius: 14px;
background: rgba(126, 28, 28, 0.92);
color: #fff;
font: 500 13px/1.4 Roboto, Arial, sans-serif;
box-shadow: 0 10px 24px rgba(0, 0, 0, 0.24);
opacity: 0;
transform: translateY(-6px);
pointer-events: none;
transition: opacity 160ms ease, transform 160ms ease;
}
#${Constants.THEME_STATUS_ID}[data-visible="true"] {
opacity: 1;
transform: translateY(0);
}
#${Constants.THEME_SWITCHER_ID} .tm-theme-switch-track {
display: inline-flex;
align-items: center;
gap: 4px;
}
#${Constants.THEME_SWITCHER_ID} .tm-theme-switch-option {
display: inline-flex;
align-items: center;
justify-content: center;
min-width: 52px;
height: 28px;
padding: 0 10px;
border: 0;
border-radius: 999px;
background: transparent;
color: var(--yt-spec-text-primary, #0f0f0f);
cursor: pointer;
font: 600 12px/1 'Inter', -apple-system, BlinkMacSystemFont, Roboto, Arial, sans-serif;
letter-spacing: 0;
transition: background 140ms ease, color 140ms ease, box-shadow 140ms ease;
}
#${Constants.THEME_SWITCHER_ID} .tm-theme-switch-option:hover {
background: var(--yt-spec-badge-chip-background-hover, rgba(0, 0, 0, 0.08));
}
#${Constants.THEME_SWITCHER_ID} .tm-theme-switch-option[data-active="true"] {
background: var(--yt-spec-brand-background-solid, rgba(15, 15, 15, 0.92));
color: var(--yt-spec-static-brand-white, #fff);
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.18);
}
html[dark] #${Constants.THEME_SWITCHER_ID} {
border-color: rgba(255, 255, 255, 0.14);
background: rgba(255, 255, 255, 0.04);
}
html[dark] #${Constants.THEME_SWITCHER_ID} .tm-theme-switch-option {
color: rgba(255, 255, 255, 0.92);
}
html[dark] #${Constants.THEME_SWITCHER_ID} .tm-theme-switch-option[data-active="true"] {
background: rgba(255, 255, 255, 0.14);
color: #fff;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.32);
}
/* 网格切换器样式 */
#${Constants.HOME_GRID_SWITCHER_ID} {
position: relative;
display: inline-flex;
align-items: center;
gap: 6px;
margin-left: 8px;
padding: 4px 6px;
border: 1px solid var(--yt-spec-10-percent-layer, rgba(0, 0, 0, 0.1));
border-radius: 999px;
background: var(--yt-spec-badge-chip-background, rgba(0, 0, 0, 0.05));
}
#${Constants.HOME_GRID_SWITCHER_ID} .tm-home-grid-option {
display: inline-flex;
align-items: center;
justify-content: center;
width: 28px;
height: 28px;
border: 0;
border-radius: 999px;
background: transparent;
color: var(--yt-spec-text-primary, #0f0f0f);
cursor: pointer;
font: 700 12px/1 'Inter', -apple-system, BlinkMacSystemFont, Roboto, Arial, sans-serif;
transition: background 140ms ease, color 140ms ease, box-shadow 140ms ease;
}
#${Constants.HOME_GRID_SWITCHER_ID} .tm-home-grid-option:hover {
background: var(--yt-spec-badge-chip-background-hover, rgba(0, 0, 0, 0.08));
}
#${Constants.HOME_GRID_SWITCHER_ID} .tm-home-grid-option[data-active="true"] {
background: var(--yt-spec-brand-background-solid, rgba(15, 15, 15, 0.92));
color: var(--yt-spec-static-brand-white, #fff);
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.18);
}
html[dark] #${Constants.HOME_GRID_SWITCHER_ID} {
border-color: rgba(255, 255, 255, 0.14);
background: rgba(255, 255, 255, 0.04);
}
html[dark] #${Constants.HOME_GRID_SWITCHER_ID} .tm-home-grid-option {
color: rgba(255, 255, 255, 0.92);
}
html[dark] #${Constants.HOME_GRID_SWITCHER_ID} .tm-home-grid-option[data-active="true"] {
background: rgba(255, 255, 255, 0.14);
color: #fff;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.32);
}
/* 剧院模式下的切换器样式 */
html.${Classes.WATCH_THEATER} #${Constants.THEME_SWITCHER_ID},
html.${Classes.WATCH_THEATER} #${Constants.HOME_GRID_SWITCHER_ID} {
border-color: rgba(255, 255, 255, 0.18) !important;
background: rgba(255, 255, 255, 0.06) !important;
}
html.${Classes.WATCH_THEATER} #${Constants.THEME_SWITCHER_ID} .tm-theme-switch-option,
html.${Classes.WATCH_THEATER} #${Constants.HOME_GRID_SWITCHER_ID} .tm-home-grid-option {
color: rgba(255, 255, 255, 0.92) !important;
}
html.${Classes.WATCH_THEATER} #${Constants.THEME_SWITCHER_ID} .tm-theme-switch-option:hover,
html.${Classes.WATCH_THEATER} #${Constants.HOME_GRID_SWITCHER_ID} .tm-home-grid-option:hover {
background: rgba(255, 255, 255, 0.1) !important;
}
html.${Classes.WATCH_THEATER} #${Constants.THEME_SWITCHER_ID} .tm-theme-switch-option[data-active="true"],
html.${Classes.WATCH_THEATER} #${Constants.HOME_GRID_SWITCHER_ID} .tm-home-grid-option[data-active="true"] {
background: rgba(255, 255, 255, 0.22) !important;
color: #fff !important;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.42) !important;
}
/* 首页芯片栏样式 */
html.tm-youtube-layout-plus-home ytd-app[mini-guide-visible]:not([guide-persistent-and-visible]) ytd-feed-filter-chip-bar-renderer,
html.tm-youtube-layout-plus-home ytd-app[mini-guide-visible]:not([guide-persistent-and-visible]) #chips-wrapper {
left: var(--tm-guide-collapsed-width) !important;
width: calc(100vw - var(--tm-guide-collapsed-width)) !important;
}
html.tm-youtube-layout-plus-home ytd-feed-filter-chip-bar-renderer #chips-wrapper {
top: 66px !important;
}
html.tm-youtube-layout-plus-home ytd-app[mini-guide-visible]:not([guide-persistent-and-visible]) ytd-page-manager {
margin-left: var(--tm-guide-collapsed-width) !important;
width: calc(100% - var(--tm-guide-collapsed-width)) !important;
}
html.tm-youtube-layout-plus-home ytd-browse {
overflow: visible !important;
}
html.tm-youtube-layout-plus-home ytd-app[mini-guide-visible]:not([guide-persistent-and-visible]) ytd-two-column-browse-results-renderer {
margin-left: 0 !important;
width: 100% !important;
min-width: 0 !important;
max-width: 100% !important;
box-sizing: border-box !important;
}
html.tm-youtube-layout-plus-home ytd-app[mini-guide-visible]:not([guide-persistent-and-visible]) ytd-rich-grid-renderer {
width: min(100%, var(--tm-home-layout-width)) !important;
max-width: var(--tm-home-layout-width) !important;
min-width: 0 !important;
margin-left: auto !important;
margin-right: auto !important;
box-sizing: border-box !important;
}
html.tm-youtube-layout-plus-home ytd-feed-filter-chip-bar-renderer {
padding: 20px 24px 6px !important;
background: transparent !important;
}
html.tm-youtube-layout-plus-home ytd-feed-filter-chip-bar-renderer #chips-wrapper,
html.tm-youtube-layout-plus-home ytd-feed-filter-chip-bar-renderer #chips {
align-items: center !important;
}
html.tm-youtube-layout-plus-home ytd-feed-filter-chip-bar-renderer #chips-content {
position: static !important;
overflow: visible !important;
isolation: auto !important;
padding: 0 !important;
margin: 0 !important;
border: 0 !important;
border-radius: 0 !important;
background: transparent !important;
backdrop-filter: none !important;
-webkit-backdrop-filter: none !important;
box-shadow: none !important;
}
html.tm-youtube-layout-plus-home ytd-feed-filter-chip-bar-renderer #chips-content::before,
html.tm-youtube-layout-plus-home ytd-feed-filter-chip-bar-renderer #chips-content::after {
content: none !important;
display: none !important;
}
html.tm-youtube-layout-plus-home ytd-feed-filter-chip-bar-renderer yt-chip-cloud-chip-renderer {
position: relative !important;
margin: 0 8px 0 0 !important;
padding: 0 !important;
}
html.tm-youtube-layout-plus-home ytd-feed-filter-chip-bar-renderer yt-chip-cloud-chip-renderer + yt-chip-cloud-chip-renderer::before {
display: none !important;
content: none !important;
}
html.tm-youtube-layout-plus-home ytd-feed-filter-chip-bar-renderer yt-chip-cloud-chip-renderer button.ytChipShapeButtonReset {
border-radius: 999px !important;
overflow: hidden !important;
}
html.tm-youtube-layout-plus-home ytd-feed-filter-chip-bar-renderer yt-chip-cloud-chip-renderer .ytChipShapeChip {
position: relative !important;
min-height: 34px !important;
padding: 0 14px !important;
border: 1px solid transparent !important;
border-radius: 999px !important;
background: var(--tm-chip-bg) !important;
color: var(--tm-chip-text) !important;
font-family: var(--tm-font) !important;
font-weight: 500 !important;
letter-spacing: 0 !important;
backdrop-filter: none !important;
-webkit-backdrop-filter: none !important;
box-shadow: none !important;
transition: background 140ms ease, color 140ms ease !important;
}
html.tm-youtube-layout-plus-home ytd-feed-filter-chip-bar-renderer yt-chip-cloud-chip-renderer .ytChipShapeChip > div {
font-size: 14px !important;
line-height: 32px !important;
}
html.tm-youtube-layout-plus-home ytd-feed-filter-chip-bar-renderer yt-chip-cloud-chip-renderer:hover .ytChipShapeChip,
html.tm-youtube-layout-plus-home ytd-feed-filter-chip-bar-renderer yt-chip-cloud-chip-renderer button:focus-visible .ytChipShapeChip {
background: var(--tm-chip-bg-hover) !important;
}
html.tm-youtube-layout-plus-home ytd-feed-filter-chip-bar-renderer yt-chip-cloud-chip-renderer[selected] .ytChipShapeChip,
html.tm-youtube-layout-plus-home ytd-feed-filter-chip-bar-renderer yt-chip-cloud-chip-renderer .ytChipShapeChip.ytChipShapeActive {
background: var(--tm-chip-bg-active) !important;
color: var(--tm-chip-text-active) !important;
border-color: transparent !important;
box-shadow: none !important;
}
html.tm-youtube-layout-plus-home ytd-feed-filter-chip-bar-renderer yt-chip-cloud-chip-renderer yt-touch-feedback-shape,
html.tm-youtube-layout-plus-home ytd-feed-filter-chip-bar-renderer yt-chip-cloud-chip-renderer .yt-spec-touch-feedback-shape__stroke,
html.tm-youtube-layout-plus-home ytd-feed-filter-chip-bar-renderer yt-chip-cloud-chip-renderer .yt-spec-touch-feedback-shape__fill {
border-radius: 999px !important;
}
html.tm-youtube-layout-plus-home ytd-feed-filter-chip-bar-renderer #right-arrow.ytd-feed-filter-chip-bar-renderer,
html.tm-youtube-layout-plus-home ytd-feed-filter-chip-bar-renderer #left-arrow.ytd-feed-filter-chip-bar-renderer {
top: 0 !important;
margin-top: 0 !important;
}
html.tm-youtube-layout-plus-home ytd-feed-filter-chip-bar-renderer #right-arrow button,
html.tm-youtube-layout-plus-home ytd-feed-filter-chip-bar-renderer #left-arrow button {
border: 0 !important;
border-radius: 999px !important;
background: var(--tm-chip-bg) !important;
backdrop-filter: none !important;
-webkit-backdrop-filter: none !important;
box-shadow: none !important;
transform: none !important;
}
/* 首页网格布局 */
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer {
display: grid !important;
grid-template-columns: repeat(20, minmax(0, 1fr)) !important;
grid-template-rows: repeat(4, minmax(0, 1fr)) !important;
grid-auto-rows: min-content !important;
gap: 8px 16px !important;
width: min(100%, var(--tm-home-layout-width)) !important;
max-width: var(--tm-home-layout-width) !important;
margin: 0 auto !important;
padding: 5px var(--tm-home-page-gutter) 40px var(--tm-home-page-gutter) !important;
box-sizing: border-box !important;
font-family: var(--tm-font) !important;
align-items: stretch !important;
min-width: 0 !important;
overflow-x: clip !important;
}
html.tm-youtube-layout-plus-home ytd-rich-grid-renderer {
--ytd-rich-grid-items-per-row: var(--tm-home-grid-items-per-row, 5) !important;
--ytd-rich-grid-posts-per-row: var(--tm-home-grid-items-per-row, 5) !important;
width: min(100%, var(--tm-home-layout-width)) !important;
max-width: var(--tm-home-layout-width) !important;
min-width: 0 !important;
margin: -20px auto 0 !important;
box-sizing: border-box !important;
}
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer {
width: auto !important;
min-width: 0 !important;
max-width: 100% !important;
margin: 0 !important;
padding: 0 !important;
box-sizing: border-box !important;
transform-origin: center top !important;
transition: transform 160ms ease, box-shadow 160ms ease !important;
will-change: transform !important;
}
html.tm-youtube-layout-plus-home ytd-rich-section-renderer,
html.tm-youtube-layout-plus-home ytd-rich-shelf-renderer,
html.tm-youtube-layout-plus-home ytd-reel-shelf-renderer {
display: none !important;
}
/* 首页 Hero 布局 */
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(1) {
grid-column: 1 / 13 !important;
grid-row: 1 / span 4 !important;
align-self: stretch !important;
height: auto !important;
}
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(1) > #content {
height: auto !important;
min-height: 0 !important;
max-height: none !important;
background: var(--tm-card-bg) !important;
border: 1px solid var(--tm-card-border) !important;
border-radius: 20px !important;
box-shadow: var(--tm-card-shadow) !important;
overflow: hidden !important;
}
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(1) ytd-rich-grid-media,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(1) yt-lockup-view-model {
height: auto !important;
max-height: none !important;
min-height: 0 !important;
}
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(1) ytd-rich-grid-media #dismissible,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(1) yt-lockup-view-model > div,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(1) .ytLockupViewModelHost,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(1) .yt-lockup-view-model-wiz {
display: grid !important;
grid-template-columns: minmax(0, 1fr) !important;
grid-template-rows: auto auto !important;
gap: 10px !important;
align-items: stretch !important;
height: auto !important;
min-height: 0 !important;
max-height: none !important;
overflow: visible !important;
}
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(1) ytd-thumbnail,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(1) #thumbnail,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(1) yt-thumbnail-view-model,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(1) yt-collection-thumbnail-view-model,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(1) .ytCollectionThumbnailViewModelHost,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(1) .ytLockupViewModelContentImage,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(1) .yt-lockup-view-model-wiz__content-image {
grid-column: 1 !important;
grid-row: 1 !important;
width: 100% !important;
max-width: 100% !important;
height: auto !important;
min-height: 0 !important;
max-height: none !important;
aspect-ratio: 16 / 9 !important;
margin: 0 !important;
border-radius: 18px !important;
overflow: hidden !important;
}
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:not(.${Classes.HERO_MIX}):nth-of-type(1) ytd-thumbnail a,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:not(.${Classes.HERO_MIX}):nth-of-type(1) #thumbnail a,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:not(.${Classes.HERO_MIX}):nth-of-type(1) ytd-thumbnail img,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:not(.${Classes.HERO_MIX}):nth-of-type(1) #thumbnail img,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:not(.${Classes.HERO_MIX}):nth-of-type(1) yt-thumbnail-view-model a,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:not(.${Classes.HERO_MIX}):nth-of-type(1) yt-thumbnail-view-model img,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:not(.${Classes.HERO_MIX}):nth-of-type(1) .ytLockupViewModelContentImage > *,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:not(.${Classes.HERO_MIX}):nth-of-type(1) .ytLockupViewModelContentImage img,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:not(.${Classes.HERO_MIX}):nth-of-type(1) .yt-lockup-view-model-wiz__content-image a,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:not(.${Classes.HERO_MIX}):nth-of-type(1) .yt-lockup-view-model-wiz__content-image img {
width: 100% !important;
height: 100% !important;
object-fit: cover !important;
object-position: var(--tm-hero-mix-object-position) !important;
}
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer.${Classes.HERO_MIX}:nth-of-type(1) ytd-thumbnail,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer.${Classes.HERO_MIX}:nth-of-type(1) #thumbnail,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer.${Classes.HERO_MIX}:nth-of-type(1) yt-thumbnail-view-model,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer.${Classes.HERO_MIX}:nth-of-type(1) yt-collection-thumbnail-view-model,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer.${Classes.HERO_MIX}:nth-of-type(1) .ytCollectionThumbnailViewModelHost,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer.${Classes.HERO_MIX}:nth-of-type(1) .ytLockupViewModelContentImage,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer.${Classes.HERO_MIX}:nth-of-type(1) .yt-lockup-view-model-wiz__content-image {
aspect-ratio: auto !important;
overflow: visible !important;
border-radius: 0 !important;
margin-top: 12px !important;
margin-left: 0 !important;
margin-right: 0 !important;
}
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer.${Classes.HERO_MIX}:nth-of-type(1) yt-collection-thumbnail-view-model,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer.${Classes.HERO_MIX}:nth-of-type(1) .ytCollectionThumbnailViewModelHost {
width: 100% !important;
height: auto !important;
max-width: none !important;
max-height: none !important;
}
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(1) #details,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(1) .ytLockupViewModelMetadata,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(1) .yt-lockup-view-model-wiz__metadata,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(1) yt-lockup-metadata-view-model {
grid-column: 1 !important;
grid-row: 2 !important;
display: block !important;
min-width: 0 !important;
width: 100% !important;
max-width: 100% !important;
min-height: 0 !important;
margin: 0 !important;
padding: 2px 10px 6px !important;
background: transparent !important;
box-sizing: border-box !important;
}
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(1) yt-lockup-metadata-view-model {
display: grid !important;
grid-template-columns: auto minmax(0, 1fr) auto !important;
grid-template-rows: auto auto !important;
column-gap: 12px !important;
row-gap: 2px !important;
align-items: start !important;
}
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(1) .ytLockupMetadataViewModelTextContainer {
grid-column: 2 !important;
grid-row: 1 / span 2 !important;
min-width: 0 !important;
}
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(1) .ytLockupMetadataViewModelAvatar {
grid-column: 1 !important;
grid-row: 1 / span 2 !important;
align-self: start !important;
margin: 0 !important;
}
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(1) .ytLockupMetadataViewModelMenuButton {
grid-column: 3 !important;
grid-row: 1 / span 2 !important;
align-self: start !important;
margin-top: -4px !important;
}
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(1) #details::after {
content: none !important;
display: none !important;
}
/* 侧边卡片布局 */
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(2) { grid-column: 13 / 21 !important; grid-row: 1 !important; }
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(3) { grid-column: 13 / 21 !important; grid-row: 2 !important; }
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(4) { grid-column: 13 / 21 !important; grid-row: 3 !important; }
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(5) { grid-column: 13 / 21 !important; grid-row: 4 !important; }
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) {
position: relative !important;
align-self: stretch !important;
height: 100% !important;
min-height: 0 !important;
padding: 0 !important;
margin: 0 !important;
}
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) > #content {
position: absolute !important;
top: 0 !important;
left: 0 !important;
right: 0 !important;
bottom: 0 !important;
width: 100% !important;
height: 100% !important;
min-height: 0 !important;
margin: 0 !important;
overflow: hidden !important;
}
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) ytd-rich-grid-media,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) yt-lockup-view-model,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) .yt-lockup-view-model-wiz,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) yt-lockup-view-model > div,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) ytd-ad-slot-renderer,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) ytd-in-feed-ad-layout-renderer {
height: 100% !important;
min-height: 0 !important;
margin: 0 !important;
}
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) ytd-rich-grid-media,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) yt-lockup-view-model,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) ytd-ad-slot-renderer,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) ytd-in-feed-ad-layout-renderer {
background: var(--tm-card-bg) !important;
border: 1px solid var(--tm-card-border) !important;
border-radius: 16px !important;
padding: 12px !important;
box-shadow: var(--tm-card-shadow) !important;
box-sizing: border-box !important;
overflow: hidden !important;
}
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) ytd-rich-grid-media #dismissible,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) .ytLockupViewModelHost,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) .yt-lockup-view-model-wiz,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) yt-lockup-view-model > div,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) ytd-ad-slot-renderer #dismissible,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) ytd-in-feed-ad-layout-renderer #dismissible,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) ytd-in-feed-ad-layout-renderer > div {
display: flex !important;
flex-direction: row !important;
gap: 12px !important;
align-items: center !important;
height: 100% !important;
min-height: 0 !important;
background: transparent !important;
border: 0 !important;
border-radius: 0 !important;
padding: 0 !important;
box-shadow: none !important;
box-sizing: border-box !important;
}
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) ytd-thumbnail,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) #thumbnail,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) yt-thumbnail-view-model,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) yt-collection-thumbnail-view-model,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) .ytCollectionThumbnailViewModelHost,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) .ytLockupViewModelContentImage,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) .yt-lockup-view-model-wiz__content-image,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) .yt-lockup-view-model-wiz__content,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) ytd-in-feed-ad-layout-renderer #thumbnail {
grid-column: 1 !important;
grid-row: 1 !important;
width: var(--tm-side-card-thumb-width, ${HOME_SIDE_CARD_THUMB_DEFAULT}) !important;
min-width: var(--tm-side-card-thumb-width, 96px) !important;
max-width: var(--tm-side-card-thumb-width, 180px) !important;
flex: 0 0 var(--tm-side-card-thumb-width, ${HOME_SIDE_CARD_THUMB_DEFAULT}) !important;
aspect-ratio: 16 / 9 !important;
height: auto !important;
align-self: center !important;
margin: 0 !important;
border-radius: 12px !important;
overflow: hidden !important;
box-sizing: border-box !important;
}
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) #avatar-link,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) #avatar,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) #avatar-container,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) #channel-thumbnail,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) ytd-channel-name yt-img-shadow {
display: none !important;
}
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) #details,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) #meta,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) .ytLockupViewModelMetadata,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) .yt-lockup-view-model-wiz__metadata,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) yt-lockup-metadata-view-model,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) ytd-in-feed-ad-layout-renderer #details,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) ytd-in-feed-ad-layout-renderer #meta {
padding: 0 !important;
margin: 0 !important;
min-width: 0 !important;
max-width: 100% !important;
grid-column: 2 !important;
grid-row: 1 !important;
flex: 1 1 auto !important;
display: flex !important;
flex-direction: column !important;
justify-content: center !important;
}
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) #video-title,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) yt-formatted-string#video-title,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) .yt-lockup-view-model-wiz__title,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) h3,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) .yt-lockup-view-model-wiz__title yt-core-attributed-string,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) .yt-lockup-view-model-wiz__title .yt-core-attributed-string,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) .yt-lockup-view-model-wiz__title yt-formatted-string {
--yt-core-attributed-string-font-size: clamp(10px, 0.7vw, 12px) !important;
--yt-core-attributed-string-line-height: 1.3 !important;
--yt-endpoint-font-size: clamp(12px, 0.8vw, 14px) !important;
font-family: var(--tm-font) !important;
font-size: clamp(10px, 0.8vw, 12px) !important;
font-weight: 700 !important;
line-height: 1.3 !important;
letter-spacing: 0 !important;
margin: 0 0 4px 0 !important;
color: var(--tm-text-primary) !important;
display: -webkit-box !important;
-webkit-line-clamp: 2 !important;
-webkit-box-orient: vertical !important;
overflow: hidden !important;
}
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) ytd-channel-name #text,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) ytd-channel-name a,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) #metadata-line,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) #metadata-line span,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) .yt-lockup-metadata-view-model-wiz__text-block,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) .yt-lockup-metadata-view-model-wiz__text-block yt-core-attributed-string,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) .yt-lockup-metadata-view-model-wiz__text-block .yt-core-attributed-string,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) .yt-lockup-metadata-view-model-wiz__text-block yt-formatted-string,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) yt-content-metadata-view-model,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) yt-content-metadata-view-model span {
--yt-core-attributed-string-font-size: clamp(10px, 0.7vw, 12px) !important;
--yt-core-attributed-string-line-height: 1.35 !important;
--yt-endpoint-font-size: clamp(10px, 0.7vw, 12px) !important;
font-family: var(--tm-font) !important;
font-size: clamp(10px, 0.7vw, 12px) !important;
line-height: 1.35 !important;
color: var(--tm-meta-secondary) !important;
}
/* 常规网格布局 */
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+6) {
grid-column: span var(--tm-home-grid-card-span, 4) !important;
}
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+6) ytd-thumbnail,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+6) #thumbnail {
border-radius: 12px !important;
overflow: hidden !important;
}
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+6) #video-title,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+6) yt-formatted-string#video-title {
font-family: var(--tm-font) !important;
font-weight: 600 !important;
letter-spacing: 0 !important;
color: var(--tm-text-primary) !important;
}
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+6) ytd-channel-name #text,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+6) #metadata-line {
font-family: var(--tm-font) !important;
color: var(--tm-meta-secondary) !important;
}
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:hover,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:focus-within {
transform: translateY(-2px) !important;
z-index: 4 !important;
}
/* 响应式布局 */
@media ${HOME_SIDE_CARDS_STACK_MEDIA} {
html.tm-youtube-layout-plus-home ytd-app[mini-guide-visible]:not([guide-persistent-and-visible]) ytd-rich-grid-renderer,
html.tm-youtube-layout-plus-home ytd-app[mini-guide-visible]:not([guide-persistent-and-visible]) #contents.ytd-rich-grid-renderer {
width: min(100%, var(--tm-home-available-width)) !important;
max-width: var(--tm-home-available-width) !important;
min-width: 0 !important;
box-sizing: border-box !important;
}
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer {
grid-template-rows: auto !important;
align-items: start !important;
width: 100% !important;
min-width: 0 !important;
max-width: 100% !important;
overflow-x: clip !important;
}
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(1) {
grid-column: 1 / 21 !important;
grid-row: auto !important;
align-self: start !important;
}
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(2),
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(3),
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(4),
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(5) {
grid-column: 1 / 21 !important;
grid-row: auto !important;
align-self: start !important;
height: auto !important;
width: 100% !important;
min-width: 0 !important;
max-width: 100% !important;
overflow: hidden !important;
box-sizing: border-box !important;
}
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) > #content {
position: relative !important;
width: 100% !important;
min-width: 0 !important;
max-width: 100% !important;
height: auto !important;
overflow: hidden !important;
box-sizing: border-box !important;
}
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) ytd-rich-grid-media,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) yt-lockup-view-model,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) .yt-lockup-view-model-wiz,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) yt-lockup-view-model > div,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) ytd-ad-slot-renderer,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) ytd-in-feed-ad-layout-renderer {
width: 100% !important;
min-width: 0 !important;
max-width: 100% !important;
height: auto !important;
box-sizing: border-box !important;
overflow: hidden !important;
}
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) ytd-rich-grid-media #dismissible,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) .ytLockupViewModelHost,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) .yt-lockup-view-model-wiz,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) yt-lockup-view-model > div,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) ytd-ad-slot-renderer #dismissible,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) ytd-in-feed-ad-layout-renderer #dismissible,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) ytd-in-feed-ad-layout-renderer > div {
width: 100% !important;
min-width: 0 !important;
max-width: 100% !important;
height: auto !important;
overflow: hidden !important;
box-sizing: border-box !important;
}
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) ytd-thumbnail,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) #thumbnail,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) yt-thumbnail-view-model,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) yt-collection-thumbnail-view-model,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) .ytCollectionThumbnailViewModelHost,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) .ytLockupViewModelContentImage,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) .yt-lockup-view-model-wiz__content-image,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) .yt-lockup-view-model-wiz__content,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) ytd-in-feed-ad-layout-renderer #thumbnail {
width: clamp(128px, 22vw, 220px) !important;
min-width: 0 !important;
max-width: 220px !important;
flex: 0 1 clamp(128px, 22vw, 220px) !important;
box-sizing: border-box !important;
}
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) #details,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) #meta,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) .ytLockupViewModelMetadata,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) .yt-lockup-view-model-wiz__metadata,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) yt-lockup-metadata-view-model,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) ytd-in-feed-ad-layout-renderer #details,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) ytd-in-feed-ad-layout-renderer #meta,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) .ytLockupMetadataViewModelTextContainer,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) .yt-lockup-metadata-view-model-wiz__text-block,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) yt-content-metadata-view-model {
min-width: 0 !important;
max-width: 100% !important;
overflow: hidden !important;
box-sizing: border-box !important;
}
}
@media (max-width: 760px) {
html.tm-youtube-layout-plus-home {
--tm-home-page-gutter: 14px;
}
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer {
padding: 12px var(--tm-home-page-gutter) 32px var(--tm-home-page-gutter) !important;
}
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(1),
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(2),
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(3),
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(4),
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(5),
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+6) {
grid-column: 1 / 21 !important;
grid-row: auto !important;
}
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) ytd-thumbnail,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) #thumbnail,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) yt-thumbnail-view-model,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) yt-collection-thumbnail-view-model,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) .ytCollectionThumbnailViewModelHost,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) .ytLockupViewModelContentImage,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) .yt-lockup-view-model-wiz__content-image,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) .yt-lockup-view-model-wiz__content,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5) ytd-in-feed-ad-layout-renderer #thumbnail {
width: clamp(108px, 34vw, 160px) !important;
flex: 0 1 clamp(108px, 34vw, 160px) !important;
}
}
/* 观看页面变量 */
html.tm-youtube-layout-plus-watch,
html.${Classes.ROUTE_TRANSITION} {
--tm-watch-edge-gutter: clamp(16px, 2.4vw, 40px);
--tm-watch-content-width: min(${MAX_LAYOUT_WIDTH}px, calc(100vw - var(--tm-watch-edge-gutter) - var(--tm-watch-edge-gutter)));
--tm-watch-vertical-content-width: min(760px, var(--tm-watch-content-width));
--tm-watch-vertical-player-width: min(460px, var(--tm-watch-content-width));
}
html.tm-youtube-layout-plus-watch,
html.tm-youtube-layout-plus-watch body,
html.tm-youtube-layout-plus-watch ytd-app,
html.tm-youtube-layout-plus-watch ytd-watch-flexy,
html.tm-youtube-layout-plus-watch ytd-watch-flexy #columns,
html.tm-youtube-layout-plus-watch ytd-watch-flexy #primary,
html.tm-youtube-layout-plus-watch ytd-watch-flexy #primary-inner,
html.tm-youtube-layout-plus-watch ytd-watch-flexy #below {
overflow-x: hidden !important;
overscroll-behavior-x: none !important;
max-width: 100% !important;
}
html.tm-youtube-layout-plus-watch ytd-watch-flexy[fullscreen],
html.tm-youtube-layout-plus-watch ytd-watch-flexy[fullscreen] #columns,
html.tm-youtube-layout-plus-watch ytd-watch-flexy[fullscreen] #primary,
html.tm-youtube-layout-plus-watch ytd-watch-flexy[fullscreen] #primary-inner {
overflow-x: visible !important;
max-width: none !important;
}
/* 隐藏推荐侧边栏 */
html:is(.tm-youtube-layout-plus-watch-plain, .tm-youtube-layout-plus-watch-chat)
ytd-watch-flexy #related,
html:is(.tm-youtube-layout-plus-watch-plain, .tm-youtube-layout-plus-watch-chat)
ytd-watch-next-secondary-results-renderer,
html:is(.tm-youtube-layout-plus-watch-plain, .tm-youtube-layout-plus-watch-chat)
ytd-playlist-panel-renderer,
html:is(.tm-youtube-layout-plus-watch-plain, .tm-youtube-layout-plus-watch-chat)
yt-playlist-panel-renderer,
html:is(.tm-youtube-layout-plus-watch-plain, .tm-youtube-layout-plus-watch-chat)
ytd-radio-renderer,
html:is(.tm-youtube-layout-plus-watch-plain, .tm-youtube-layout-plus-watch-chat)
ytd-compact-radio-renderer {
display: none !important;
}
html.${Classes.ROUTE_TRANSITION} ytd-watch-flexy #related,
html.${Classes.ROUTE_TRANSITION} ytd-watch-next-secondary-results-renderer,
html.${Classes.ROUTE_TRANSITION} ytd-playlist-panel-renderer,
html.${Classes.ROUTE_TRANSITION} yt-playlist-panel-renderer,
html.${Classes.ROUTE_TRANSITION} ytd-radio-renderer,
html.${Classes.ROUTE_TRANSITION} ytd-compact-radio-renderer,
html.${Classes.ROUTE_TRANSITION} ytd-watch-flexy :is(#secondary, #secondary-inner) {
display: none !important;
}
html.${Classes.ROUTE_TRANSITION} ytd-mini-guide-renderer,
html.${Classes.ROUTE_TRANSITION} tp-yt-app-drawer#guide {
display: none !important;
}
html.${Classes.ROUTE_TRANSITION} ytd-page-manager {
margin-left: 0 !important;
width: 100% !important;
}
html.${Classes.ROUTE_TRANSITION} ytd-watch-flexy :is(
ytd-watch-metadata,
#above-the-fold,
#bottom-row,
#below,
#comments,
#teaser-carousel,
ytd-comments,
ytd-comment-thread-renderer
) {
visibility: hidden !important;
pointer-events: none !important;
}
html:is(.tm-youtube-layout-plus-watch-plain, .tm-youtube-layout-plus-watch-chat-collapsed):not(.${Classes.WATCH_PANEL_OPEN})
ytd-watch-flexy:not([fullscreen]) :is(#secondary, #secondary-inner) {
display: none !important;
}
html:is(.tm-youtube-layout-plus-watch-plain, .tm-youtube-layout-plus-watch-chat-collapsed):not(.${Classes.WATCH_PANEL_OPEN})
ytd-watch-flexy:not([fullscreen]) #primary,
html.${Classes.ROUTE_TRANSITION} ytd-watch-flexy:not([fullscreen]) #primary {
max-width: none !important;
width: var(--tm-watch-content-width) !important;
margin-left: auto !important;
margin-right: auto !important;
box-sizing: border-box !important;
}
html:is(.tm-youtube-layout-plus-watch-plain, .tm-youtube-layout-plus-watch-chat-collapsed):not(.${Classes.WATCH_PANEL_OPEN})
ytd-watch-flexy:not([fullscreen]) #columns,
html.${Classes.ROUTE_TRANSITION} ytd-watch-flexy:not([fullscreen]) #columns {
display: block !important;
width: 100% !important;
max-width: 100% !important;
margin-left: 0 !important;
margin-right: 0 !important;
}
html:is(.tm-youtube-layout-plus-watch-plain, .tm-youtube-layout-plus-watch-chat-collapsed):not(.${Classes.WATCH_PANEL_OPEN})
ytd-watch-flexy:not([fullscreen]) :is(#primary-inner, #above-the-fold, #below, ytd-watch-metadata, #comments),
html.${Classes.ROUTE_TRANSITION} ytd-watch-flexy:not([fullscreen]) :is(#primary-inner, #above-the-fold, #below, ytd-watch-metadata, #comments) {
width: var(--tm-watch-content-width) !important;
max-width: var(--tm-watch-content-width) !important;
min-width: 0 !important;
margin-left: auto !important;
margin-right: auto !important;
box-sizing: border-box !important;
}
html:is(.tm-youtube-layout-plus-watch-plain, .tm-youtube-layout-plus-watch-chat-collapsed):not(.${Classes.WATCH_PANEL_OPEN})
ytd-watch-flexy:not([fullscreen]) :is(#player-theater-container, #player-full-bleed-container, #player-container-outer),
html.${Classes.ROUTE_TRANSITION} ytd-watch-flexy:not([fullscreen]) :is(#player-theater-container, #player-full-bleed-container, #player-container-outer) {
width: var(--tm-watch-content-width) !important;
max-width: var(--tm-watch-content-width) !important;
min-width: 0 !important;
margin-left: auto !important;
margin-right: auto !important;
box-sizing: border-box !important;
}
html:is(.tm-youtube-layout-plus-watch-plain, .tm-youtube-layout-plus-watch-chat-collapsed):not(.${Classes.WATCH_PANEL_OPEN})
ytd-watch-flexy:not([fullscreen]) :is(#player-container-inner, #player-container, #player, #player-api, #movie_player, .html5-video-player),
html.${Classes.ROUTE_TRANSITION} ytd-watch-flexy:not([fullscreen]) :is(#player-container-inner, #player-container, #player, #player-api, #movie_player, .html5-video-player) {
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
margin-left: 0 !important;
margin-right: 0 !important;
box-sizing: border-box !important;
}
/* 竖屏视频布局 */
html.${Classes.WATCH_VERTICAL}:is(.tm-youtube-layout-plus-watch-plain, .tm-youtube-layout-plus-watch-chat-collapsed):not(.${Classes.WATCH_PANEL_OPEN})
ytd-watch-flexy:not([fullscreen]) :is(#primary, #primary-inner, #above-the-fold, #below, ytd-watch-metadata, #comments),
html.${Classes.WATCH_VERTICAL}.${Classes.ROUTE_TRANSITION} ytd-watch-flexy:not([fullscreen]) :is(#primary, #primary-inner, #above-the-fold, #below, ytd-watch-metadata, #comments) {
width: var(--tm-watch-vertical-content-width) !important;
max-width: var(--tm-watch-vertical-content-width) !important;
margin-left: auto !important;
margin-right: auto !important;
}
html.${Classes.WATCH_VERTICAL}:is(.tm-youtube-layout-plus-watch-plain, .tm-youtube-layout-plus-watch-chat-collapsed):not(.${Classes.WATCH_PANEL_OPEN})
ytd-watch-flexy:not([fullscreen]) :is(#player-theater-container, #player-full-bleed-container, #player-container-outer),
html.${Classes.WATCH_VERTICAL}.${Classes.ROUTE_TRANSITION} ytd-watch-flexy:not([fullscreen]) :is(#player-theater-container, #player-full-bleed-container, #player-container-outer) {
width: var(--tm-watch-vertical-player-width) !important;
max-width: var(--tm-watch-vertical-player-width) !important;
min-width: 0 !important;
margin-left: auto !important;
margin-right: auto !important;
}
/* 路由过渡锁定 */
html.${Classes.ROUTE_TRANSITION} ytd-watch-flexy [data-tm-watch-transition-lock="true"] {
position: fixed !important;
top: var(--tm-watch-transition-player-top, auto) !important;
left: var(--tm-watch-transition-player-left, auto) !important;
width: var(--tm-watch-transition-player-width, var(--tm-watch-content-width)) !important;
height: var(--tm-watch-transition-player-height, auto) !important;
max-width: none !important;
min-width: 0 !important;
margin: 0 !important;
z-index: 2 !important;
box-sizing: border-box !important;
overflow: hidden !important;
}
/* 隐藏未准备好的内容 */
html:is(.tm-youtube-layout-plus-watch-plain, .tm-youtube-layout-plus-watch-chat-collapsed):not([${Constants.WATCH_READY_ATTR}])
ytd-watch-flexy:not([fullscreen]) :is(#below, ytd-watch-metadata, #comments) {
visibility: hidden !important;
}
`;
},
};
// ============================================================================
// 模块7: 首页布局管理
// ============================================================================
const HomeLayout = {
/**
* 应用首页布局
*/
apply() {
const richGrid = DOM.getRichGrid();
if (!richGrid) {
this.setLayoutClasses([]);
return;
}
this.setLayoutClasses(['tm-youtube-layout-plus-home']);
this.applyGridColumns();
this.applyHeroInlineLayout();
if (State.layout.lastAutoCollapsedHomeUrl !== location.href) {
this.collapseGuide();
State.layout.lastAutoCollapsedHomeUrl = location.href;
}
},
/**
* 设置布局类名
*/
setLayoutClasses(targetClasses) {
const target = new Set(targetClasses);
const root = document.documentElement;
for (const cls of Constants.Classes.LAYOUT_MODES) {
const shouldHave = target.has(cls);
const hasIt = root.classList.contains(cls);
if (shouldHave && !hasIt) root.classList.add(cls);
else if (!shouldHave && hasIt) root.classList.remove(cls);
}
},
/**
* 应用网格列数
*/
applyGridColumns() {
const columns = Storage.normalizeGridColumns(State.grid.currentColumns);
document.documentElement.style.setProperty('--tm-home-grid-items-per-row', String(columns));
document.documentElement.style.setProperty('--tm-home-grid-card-span', String(Constants.Layout.HOME_GRID_TRACK_COUNT / columns));
},
/**
* 应用 Hero 内联布局
*/
applyHeroInlineLayout() {
const items = DOM.getRichGridItems();
if (items.length < 5) return;
const stackSideCards = window.matchMedia(Constants.Layout.HOME_SIDE_CARDS_STACK_MEDIA).matches;
const heroIsMix = DOM.isHomeHeroMixCard(items[0]);
items[0].classList.toggle(Constants.Classes.HERO_MIX, heroIsMix);
items[0].style.setProperty('grid-column', stackSideCards ? '1 / 21' : '1 / 13', 'important');
items[0].style.setProperty('grid-row', stackSideCards ? 'auto' : '1 / span 4', 'important');
for (let i = 1; i < 5; i++) {
items[i].style.setProperty('grid-column', stackSideCards ? '1 / 21' : '13 / 21', 'important');
items[i].style.setProperty('grid-row', stackSideCards ? 'auto' : String(i), 'important');
}
this.upgradeHeroThumbnail();
this.scheduleSideCardThumbnailFit();
},
/**
* 升级 Hero 缩略图
*/
upgradeHeroThumbnail() {
const item = document.querySelector('#contents.ytd-rich-grid-renderer > ytd-rich-item-renderer');
if (!item) return;
const heroIsMix = DOM.isHomeHeroMixCard(item);
item.classList.toggle(Constants.Classes.HERO_MIX, heroIsMix);
const link = item.querySelector('a#thumbnail[href], a[href*="/watch?v="]');
const img = item.querySelector('img[src*="ytimg.com"]');
const videoId = Utils.extractVideoId(link?.href) || Utils.extractVideoId(img?.src);
if (!videoId) return;
const images = Array.from(item.querySelectorAll('img[src*="ytimg.com"], img'));
if (!images.length) return;
const key = `${heroIsMix ? 'mix' : 'video'}:${videoId}`;
const currentThumbUrl = item.dataset.tmHeroThumbUrl || '';
if (
item.dataset.tmHeroThumbKey === key &&
currentThumbUrl &&
images.some(img => img.src === currentThumbUrl || img.srcset.includes(currentThumbUrl))
) {
return;
}
const candidates = heroIsMix
? [
`https://i.ytimg.com/vi_webp/${videoId}/maxresdefault.webp`,
`https://i.ytimg.com/vi/${videoId}/maxresdefault.jpg`,
`https://i.ytimg.com/vi_webp/${videoId}/hq720.webp`,
`https://i.ytimg.com/vi/${videoId}/hq720.jpg`,
`https://i.ytimg.com/vi_webp/${videoId}/sddefault.webp`,
`https://i.ytimg.com/vi/${videoId}/sddefault.jpg`,
`https://i.ytimg.com/vi_webp/${videoId}/hqdefault.webp`,
`https://i.ytimg.com/vi/${videoId}/hqdefault.jpg`,
]
: [
`https://i.ytimg.com/vi/${videoId}/maxresdefault.jpg`,
`https://i.ytimg.com/vi/${videoId}/hq720.jpg`,
`https://i.ytimg.com/vi/${videoId}/sddefault.jpg`,
`https://i.ytimg.com/vi/${videoId}/hqdefault.jpg`,
];
const minimumWidth = heroIsMix ? 320 : 640;
const applyCandidate = (url, width) => {
item.dataset.tmHeroThumbKey = key;
item.dataset.tmHeroThumbUrl = url;
for (const image of images) {
image.src = url;
image.srcset = `${url} ${width || 1280}w`;
image.sizes = '(min-width: 1180px) 60vw, 100vw';
image.loading = 'eager';
image.fetchPriority = 'high';
image.decoding = 'async';
}
};
const tryCandidate = (index = 0) => {
const url = candidates[index];
if (!url) return;
const probe = new Image();
probe.onload = () => {
if (probe.naturalWidth >= minimumWidth || index === candidates.length - 1) {
applyCandidate(url, probe.naturalWidth);
} else {
tryCandidate(index + 1);
}
};
probe.onerror = () => tryCandidate(index + 1);
probe.src = url;
};
tryCandidate();
},
/**
* 计算侧边卡片缩略图宽度
*/
calculateSideCardThumbnailWidth(cardShell) {
const rect = cardShell.getBoundingClientRect();
if (rect.width <= 0 || rect.height <= 0) return null;
const style = window.getComputedStyle(cardShell);
const hPadding = Utils.getNumericStyle(style, 'padding-left') + Utils.getNumericStyle(style, 'padding-right');
const vPadding = Utils.getNumericStyle(style, 'padding-top') + Utils.getNumericStyle(style, 'padding-bottom');
const availableHeight = Math.max(54, rect.height - vPadding - 2);
const availableWidth = Math.max(160, rect.width - hPadding - 2);
const widthByHeight = availableHeight * (16 / 9);
const widthByTextReserve = availableWidth * (1 - Constants.Layout.HOME_SIDE_CARD_TEXT_WIDTH_RATIO);
const widthCap = window.innerWidth >= 1900
? Constants.Layout.HOME_SIDE_CARD_ULTRAWIDE_THUMB_CAP
: Constants.Layout.HOME_SIDE_CARD_WIDE_THUMB_CAP;
const minimumWidth = Math.min(180, Math.max(120, availableWidth * 0.22));
return Math.round(Math.max(minimumWidth, Math.min(widthByHeight, widthByTextReserve, widthCap)));
},
/**
* 应用侧边卡片缩略图适配
*/
applySideCardThumbnailFit() {
if (!DOM.isHomePage()) {
this.clearSideCardThumbnailFit();
return;
}
const items = Array.from(document.querySelectorAll(
'#contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5)'
));
if (!items.length) return;
if (window.matchMedia(Constants.Layout.HOME_SIDE_CARDS_STACK_MEDIA).matches) {
this.clearSideCardThumbnailFit(items);
return;
}
for (const item of items) {
const cardShell = DOM.getHomeSideCardShell(item);
const width = this.calculateSideCardThumbnailWidth(cardShell);
if (width) {
item.style.setProperty('--tm-side-card-thumb-width', `${width}px`);
}
}
},
/**
* 清除侧边卡片缩略图适配
*/
clearSideCardThumbnailFit(items) {
const targetItems = items || Array.from(document.querySelectorAll(
'#contents.ytd-rich-grid-renderer > ytd-rich-item-renderer:nth-of-type(n+2):nth-of-type(-n+5)'
));
for (const item of targetItems) {
item.style.removeProperty('--tm-side-card-thumb-width');
}
},
/**
* 调度侧边卡片缩略图适配
*/
scheduleSideCardThumbnailFit() {
if (!DOM.isHomePage()) return;
requestAnimationFrame(() => {
this.applySideCardThumbnailFit();
requestAnimationFrame(() => this.applySideCardThumbnailFit());
});
},
/**
* 折叠侧边栏
*/
collapseGuide() {
const app = DOM.getApp();
if (app) {
app.removeAttribute('guide-persistent-and-visible');
app.setAttribute('mini-guide-visible', '');
}
const drawer = document.querySelector('tp-yt-app-drawer#guide');
if (drawer) {
drawer.removeAttribute('opened');
drawer.style.width = '';
drawer.style.minWidth = '';
drawer.style.visibility = '';
}
const guideRenderer = document.querySelector('ytd-guide-renderer');
if (guideRenderer) {
guideRenderer.style.display = '';
guideRenderer.style.width = '';
guideRenderer.style.minWidth = '';
}
},
};
// ============================================================================
// 模块8: 观看页面布局管理
// ============================================================================
const WatchLayout = {
/**
* 应用观看页面布局
*/
apply() {
const watchFlexy = DOM.getWatchFlexy();
if (!watchFlexy) {
HomeLayout.setLayoutClasses([]);
this.resetState();
return;
}
this.syncPlayerSize();
this.attachObservers();
this.updateEngagementPanelState(watchFlexy);
this.updateTheaterModeState(watchFlexy);
if (DOM.hasWatchSidebarChat(watchFlexy)) {
HomeLayout.setLayoutClasses([
'tm-youtube-layout-plus-watch',
'tm-youtube-layout-plus-watch-chat',
]);
this.updateChatPanelState(watchFlexy);
this.autoCollapseLiveChatPanel(watchFlexy);
return;
}
HomeLayout.setLayoutClasses([
'tm-youtube-layout-plus-watch',
'tm-youtube-layout-plus-watch-plain',
]);
this.hideReplayPrompt();
},
/**
* 重置状态
*/
resetState({ clearSizing = true, preserveTransitionLayout = false } = {}) {
const root = document.documentElement;
State.layout.lastWatchChatExpanded = null;
State.layout.lastEngagementPanelOpen = null;
State.layout.lastTheaterMode = null;
State.layout.lastPlayerSyncKey = '';
root.removeAttribute(Constants.WATCH_READY_ATTR);
root.classList.remove(
Constants.Classes.WATCH_PANEL_OPEN,
Constants.Classes.WATCH_THEATER,
Constants.Classes.WATCH_CHAT_OPEN,
Constants.Classes.WATCH_CHAT_COLLAPSED
);
if (!preserveTransitionLayout) {
root.classList.remove(Constants.Classes.WATCH_VERTICAL);
}
if (clearSizing) {
root.style.removeProperty('--tm-watch-content-width');
root.style.removeProperty('--tm-watch-vertical-player-width');
this.clearRouteTransitionPlayerLock();
}
},
/**
* 更新视频方向
*/
updateVideoOrientation() {
if (!DOM.isWatchPage()) {
document.documentElement.classList.remove(Constants.Classes.WATCH_VERTICAL);
return false;
}
const video = document.querySelector(
'#movie_player video.html5-main-video, .html5-video-player video.html5-main-video, video.html5-main-video'
);
if (!video) {
document.documentElement.classList.remove(Constants.Classes.WATCH_VERTICAL);
return false;
}
if (video.dataset.tmYlpOrientationListener !== '1') {
const resync = () => {
this.updateVideoOrientation();
this.syncPlayerSize();
};
video.addEventListener('loadedmetadata', resync, { passive: true });
video.addEventListener('resize', resync, { passive: true });
video.dataset.tmYlpOrientationListener = '1';
}
const width = Number(video.videoWidth) || 0;
const height = Number(video.videoHeight) || 0;
const isVertical = width > 0 && height > 0 && height / width >= 1.12;
document.documentElement.classList.toggle(Constants.Classes.WATCH_VERTICAL, isVertical);
return isVertical;
},
/**
* 同步播放器尺寸
*/
syncPlayerSize() {
if (!DOM.isWatchPage()) {
this.resetState();
return;
}
const isVertical = this.updateVideoOrientation();
const gutter = Math.min(40, Math.max(16, window.innerWidth * 0.024));
const width = Math.min(Constants.Layout.MAX_LAYOUT_WIDTH, Math.max(320, Math.round(window.innerWidth - gutter * 2)));
const verticalPlayerWidth = Math.min(460, width);
const key = `${width}:${verticalPlayerWidth}:${isVertical ? 'v' : 'h'}`;
if (State.layout.lastPlayerSyncKey === key) {
if (!document.documentElement.hasAttribute(Constants.WATCH_READY_ATTR)) {
document.documentElement.setAttribute(Constants.WATCH_READY_ATTR, '1');
}
return;
}
State.layout.lastPlayerSyncKey = key;
document.documentElement.style.setProperty('--tm-watch-content-width', `${width}px`);
document.documentElement.style.setProperty('--tm-watch-vertical-player-width', `${verticalPlayerWidth}px`);
document.documentElement.setAttribute(Constants.WATCH_READY_ATTR, '1');
},
/**
* 附加观察者
*/
attachObservers() {
if (!DOM.isWatchPage()) {
this.detachObservers();
return;
}
const watchFlexy = DOM.getWatchFlexy();
if (watchFlexy && watchFlexy !== State.observers.watchFlexyObservedElement) {
State.observers.watchFlexyAttr?.disconnect();
State.observers.watchFlexyAttr = new MutationObserver(() => {
const flexy = DOM.getWatchFlexy();
if (!flexy) return;
this.syncPlayerSize();
this.updateTheaterModeState(flexy);
this.updateEngagementPanelState(flexy);
if (document.documentElement.classList.contains('tm-youtube-layout-plus-watch-chat')) {
this.updateChatPanelState(flexy);
}
});
try {
State.observers.watchFlexyAttr.observe(watchFlexy, {
attributes: true,
attributeFilter: [
'theater', 'is-two-columns_', 'live-chat-collapsed',
'is-live', 'is-live-content', 'fullscreen', 'hidden',
],
});
State.observers.watchFlexyObservedElement = watchFlexy;
} catch {
State.observers.watchFlexyObservedElement = null;
}
}
},
/**
* 分离观察者
*/
detachObservers() {
State.observers.watchFlexyAttr?.disconnect();
State.observers.watchFlexyAttr = null;
State.observers.watchFlexyObservedElement = null;
},
/**
* 更新互动面板状态
*/
updateEngagementPanelState(watchFlexy) {
const open = DOM.isWatchPage() && DOM.hasOpenEngagementPanel(watchFlexy);
document.documentElement.classList.toggle(Constants.Classes.WATCH_PANEL_OPEN, open);
State.layout.lastEngagementPanelOpen = open;
},
/**
* 更新剧院模式状态
*/
updateTheaterModeState(watchFlexy) {
const inTheater = DOM.isTheaterModeActive(watchFlexy);
document.documentElement.classList.toggle(Constants.Classes.WATCH_THEATER, inTheater);
State.layout.lastTheaterMode = inTheater;
},
/**
* 更新聊天面板状态
*/
updateChatPanelState(watchFlexy) {
const chatFrame = watchFlexy.querySelector('ytd-live-chat-frame#chat');
const openPanelButton = DOM.findOpenPanelButton();
const chatVisible = !!chatFrame && Utils.isVisible(chatFrame);
const panelExpanded = chatVisible || !!(openPanelButton && openPanelButton.disabled);
document.documentElement.classList.toggle(Constants.Classes.WATCH_CHAT_OPEN, panelExpanded);
document.documentElement.classList.toggle(Constants.Classes.WATCH_CHAT_COLLAPSED, !panelExpanded);
State.layout.lastWatchChatExpanded = panelExpanded;
},
/**
* 停止聊天状态同步
*/
stopChatStateSync() {
if (!State.timers.watchChatState) return;
clearInterval(State.timers.watchChatState);
State.timers.watchChatState = null;
},
/**
* 启动聊天状态同步
*/
startChatStateSync() {
this.stopChatStateSync();
if (!DOM.isWatchPage()) return;
State.timers.watchChatState = setInterval(() => {
if (!DOM.isWatchPage()) {
this.stopChatStateSync();
return;
}
const watchFlexy = DOM.getWatchFlexy();
if (!watchFlexy) return;
this.updateEngagementPanelState(watchFlexy);
this.updateTheaterModeState(watchFlexy);
const hasSidebarChat = DOM.hasWatchSidebarChat(watchFlexy);
const hasWatchChatClass = document.documentElement.classList.contains('tm-youtube-layout-plus-watch-chat');
if (hasSidebarChat && !hasWatchChatClass) {
Scheduler.scheduleApply();
return;
}
if (!hasSidebarChat || !hasWatchChatClass) return;
this.updateChatPanelState(watchFlexy);
}, 500);
},
/**
* 自动折叠直播聊天面板
*/
autoCollapseLiveChatPanel(watchFlexy) {
const watchPageKey = DOM.getWatchPageKey();
if (State.layout.lastAutoCollapsedWatchChatKey === watchPageKey) return;
const chatFrameHost = watchFlexy.querySelector('ytd-live-chat-frame#chat');
const openPanelButton = DOM.findOpenPanelButton();
if (openPanelButton && !openPanelButton.disabled) {
State.layout.lastAutoCollapsedWatchChatKey = watchPageKey;
return;
}
if (chatFrameHost?.hasAttribute('collapsed')) {
State.layout.lastAutoCollapsedWatchChatKey = watchPageKey;
return;
}
const hostToggleButton = chatFrameHost?.querySelector(
'#show-hide-button button, #show-hide-button yt-button-shape button, #show-hide-button tp-yt-paper-button'
);
if (hostToggleButton) {
hostToggleButton.click();
State.layout.lastAutoCollapsedWatchChatKey = watchPageKey;
setTimeout(() => Scheduler.scheduleApply(), 80);
return;
}
const chatFrame = watchFlexy.querySelector(
'ytd-live-chat-frame#chat #chatframe, ytd-live-chat-frame#chat iframe, #chatframe'
);
const chatDoc = DOM.safeGetIframeDocument(chatFrame);
if (!chatDoc) return;
const closeButton = Array.from(chatDoc.querySelectorAll('button')).find(
button => /close/i.test(button.getAttribute('aria-label') || '')
);
if (closeButton) {
closeButton.click();
State.layout.lastAutoCollapsedWatchChatKey = watchPageKey;
setTimeout(() => Scheduler.scheduleApply(), 80);
}
},
/**
* 隐藏重播提示
*/
hideReplayPrompt() {
const teaserCarousel = document.querySelector('ytd-watch-metadata #teaser-carousel');
if (!teaserCarousel) return;
const teaserText = DOM.getWatchTeaserText();
if (DOM.hasLiveWatchPrompt(teaserText)) {
teaserCarousel.classList.remove(Constants.Classes.REPLAY_HIDE);
return;
}
const watchFlexy = DOM.getWatchFlexy();
if (watchFlexy && DOM.hasReplayWatchPrompt(teaserText) && DOM.hasWatchSidebarChat(watchFlexy)) {
teaserCarousel.classList.remove(Constants.Classes.REPLAY_HIDE);
return;
}
const replayPrompt = Array.from(
teaserCarousel.querySelectorAll('yt-video-metadata-carousel-view-model')
).find(card => {
const text = (card.innerText || card.textContent || '').trim();
return /live chat replay/i.test(text) || /see what others said about this video while it was live/i.test(text);
});
if (!replayPrompt) {
teaserCarousel.classList.remove(Constants.Classes.REPLAY_HIDE);
} else {
teaserCarousel.classList.add(Constants.Classes.REPLAY_HIDE);
}
},
/**
* 清除隐藏的重播提示
*/
clearHiddenReplayPrompts() {
for (const el of document.querySelectorAll('.' + Constants.Classes.REPLAY_HIDE)) {
el.classList.remove(Constants.Classes.REPLAY_HIDE);
}
},
/**
* 获取播放器锁定元素
*/
getPlayerLockElement() {
const selectors = [
'ytd-watch-flexy #player-theater-container',
'ytd-watch-flexy #player-full-bleed-container',
'ytd-watch-flexy #player-container-outer',
'ytd-watch-flexy #player-container',
'ytd-watch-flexy #player',
];
return selectors
.map(selector => document.querySelector(selector))
.find(element => {
if (!element) return false;
const rect = element.getBoundingClientRect();
return rect.width >= 240 && rect.height >= 120;
}) || null;
},
/**
* 锁定路由过渡播放器
*/
lockRouteTransitionPlayer() {
if (DOM.isFullscreenActive()) return;
const player = this.getPlayerLockElement();
if (!player) return;
const rect = player.getBoundingClientRect();
const rootStyle = document.documentElement.style;
rootStyle.setProperty('--tm-watch-transition-player-top', `${Math.round(rect.top)}px`);
rootStyle.setProperty('--tm-watch-transition-player-left', `${Math.round(rect.left)}px`);
rootStyle.setProperty('--tm-watch-transition-player-width', `${Math.round(rect.width)}px`);
rootStyle.setProperty('--tm-watch-transition-player-height', `${Math.round(rect.height)}px`);
player.dataset.tmWatchTransitionLock = 'true';
},
/**
* 清除路由过渡播放器锁定
*/
clearRouteTransitionPlayerLock() {
const rootStyle = document.documentElement.style;
rootStyle.removeProperty('--tm-watch-transition-player-top');
rootStyle.removeProperty('--tm-watch-transition-player-left');
rootStyle.removeProperty('--tm-watch-transition-player-width');
rootStyle.removeProperty('--tm-watch-transition-player-height');
for (const element of document.querySelectorAll('[data-tm-watch-transition-lock="true"]')) {
delete element.dataset.tmWatchTransitionLock;
}
},
/**
* 启动引导
*/
startBootstrap() {
this.stopBootstrap();
if (!DOM.isWatchPage()) return;
State.layout.watchBootstrapStep = 0;
const run = () => {
if (!DOM.isWatchPage()) {
this.stopBootstrap();
return;
}
Scheduler.scheduleApply();
this.attachObservers();
this.syncPlayerSize();
const measured = !!State.layout.lastPlayerSyncKey;
const observersReady = !!State.observers.watchFlexyObservedElement;
if (measured && observersReady) {
this.stopBootstrap();
return;
}
if (State.layout.watchBootstrapStep >= Constants.Timing.WATCH_BOOTSTRAP_DELAYS.length - 1) {
this.stopBootstrap();
return;
}
State.layout.watchBootstrapStep += 1;
State.timers.watchBootstrap = setTimeout(run, Constants.Timing.WATCH_BOOTSTRAP_DELAYS[State.layout.watchBootstrapStep]);
};
run();
},
/**
* 停止引导
*/
stopBootstrap() {
if (!State.timers.watchBootstrap) return;
clearTimeout(State.timers.watchBootstrap);
State.timers.watchBootstrap = null;
},
};
// ============================================================================
// 模块9: 主题管理
// ============================================================================
const ThemeManager = {
/**
* 初始化
*/
init() {
State.theme.currentMode = Storage.loadThemeMode();
State.theme.lastPersistedMode = State.theme.currentMode;
},
/**
* 获取主题动作名
*/
getActionName(mode) {
return Constants.THEME_MODES.find(item => item.mode === mode)?.actionName || null;
},
/**
* 派发主题信号
*/
dispatchSignal(mode) {
const actionName = this.getActionName(mode);
if (!actionName) return false;
const target = DOM.getApp() || document.documentElement;
try {
target.dispatchEvent(new CustomEvent('yt-action', {
detail: {
actionName,
args: [],
optionalAction: false,
returnValue: [],
},
bubbles: true,
cancelable: false,
composed: true,
}));
return true;
} catch (error) {
console.debug('YouTube Layout Plus theme dispatch failed:', error);
return false;
}
},
/**
* 验证主题模式
*/
async verifyMode(mode, { attempts = 10, intervalMs = 120 } = {}) {
const expectedDarkAttr = mode === 'dark';
let lastResult = null;
for (let attempt = 0; attempt < attempts; attempt++) {
const cookieMode = Utils.getThemeModeFromCookie();
const hasDark = document.documentElement.hasAttribute('dark');
const actualMode = cookieMode || Utils.inferThemeMode();
const cookieConsistent = cookieMode ? cookieMode === mode : true;
const darkConsistent = mode === 'auto' ? true : hasDark === expectedDarkAttr;
lastResult = {
ok: cookieConsistent && darkConsistent,
actualMode,
cookieMode,
hasDark,
};
if (lastResult.ok) return lastResult;
await Utils.delay(intervalMs);
}
return lastResult || {
ok: false,
actualMode: Utils.getObservedThemeMode(),
cookieMode: Utils.getThemeModeFromCookie(),
hasDark: document.documentElement.hasAttribute('dark'),
};
},
/**
* 设置主题模式
*/
async setMode(mode) {
if (State.theme.switchInFlight) return;
if (!Constants.THEME_MODES.some(item => item.mode === mode)) return;
const previousMode = State.theme.currentMode || Storage.loadThemeMode() || Utils.getThemeModeFromCookie() || Utils.inferThemeMode();
const expectedDarkAttr = mode === 'dark' || (mode === 'auto' && window.matchMedia('(prefers-color-scheme: dark)').matches);
if (previousMode === mode && document.documentElement.hasAttribute('dark') === expectedDarkAttr) {
State.theme.currentMode = mode;
Storage.saveThemeMode(mode);
State.theme.pendingMode = null;
this.updateSwitcherUI();
return;
}
State.theme.switchInFlight = true;
State.theme.pendingMode = mode;
try {
this.updateSwitcherUI();
if (!this.dispatchSignal(mode)) {
State.theme.currentMode = previousMode;
Storage.saveThemeMode(previousMode);
this.showStatus(`Theme switch failed: unable to dispatch ${mode}.`);
return;
}
State.theme.currentMode = mode;
Storage.saveThemeMode(mode);
this.updateSwitcherUI();
let verification = await this.verifyMode(mode);
if (!verification.ok) {
this.dispatchSignal(mode);
verification = await this.verifyMode(mode, { attempts: 14, intervalMs: 140 });
}
if (!verification.ok) {
State.theme.currentMode = verification.actualMode || previousMode;
Storage.saveThemeMode(State.theme.currentMode);
this.showStatus(`Theme switch failed: expected ${mode}, actual ${State.theme.currentMode || 'unknown'}.`);
return;
}
State.theme.currentMode = verification.actualMode || mode;
Storage.saveThemeMode(State.theme.currentMode);
this.hideStatus();
} finally {
State.theme.switchInFlight = false;
State.theme.pendingMode = null;
State.theme.currentMode = State.theme.currentMode || Storage.loadThemeMode() || Utils.getThemeModeFromCookie() || previousMode;
this.updateSwitcherUI();
}
},
/**
* 更新切换器 UI
*/
updateSwitcherUI({ force = false } = {}) {
const switcher = document.getElementById(Constants.THEME_SWITCHER_ID);
if (!switcher) return;
if (!State.theme.pendingMode) {
const observedMode = Utils.getObservedThemeMode();
if (observedMode && observedMode !== State.theme.currentMode) {
State.theme.currentMode = observedMode;
Storage.saveThemeMode(observedMode);
}
} else if (!State.theme.currentMode) {
State.theme.currentMode = Storage.loadThemeMode() || Utils.inferThemeMode();
}
const visibleMode = State.theme.pendingMode || State.theme.currentMode;
const disabled = State.theme.switchInFlight;
if (!force && State.theme.lastRenderedMode === visibleMode && State.theme.lastRenderedDisabled === disabled) {
return;
}
State.theme.lastRenderedMode = visibleMode;
State.theme.lastRenderedDisabled = disabled;
const optionButtons = switcher.querySelectorAll('.tm-theme-switch-option[data-mode]');
for (const button of optionButtons) {
const isActive = button.dataset.mode === visibleMode;
button.dataset.active = String(isActive);
button.setAttribute('aria-pressed', String(isActive));
button.disabled = disabled;
}
},
/**
* 显示状态消息
*/
showStatus(message) {
let status = document.getElementById(Constants.THEME_STATUS_ID);
if (!status) {
status = document.createElement('div');
status.id = Constants.THEME_STATUS_ID;
status.dataset.visible = 'false';
document.body.appendChild(status);
}
status.textContent = message;
status.dataset.visible = 'true';
if (State.timers.themeStatusHide) clearTimeout(State.timers.themeStatusHide);
State.timers.themeStatusHide = setTimeout(() => {
status.dataset.visible = 'false';
State.timers.themeStatusHide = null;
}, 2600);
},
/**
* 隐藏状态消息
*/
hideStatus() {
const status = document.getElementById(Constants.THEME_STATUS_ID);
if (status) status.dataset.visible = 'false';
if (State.timers.themeStatusHide) {
clearTimeout(State.timers.themeStatusHide);
State.timers.themeStatusHide = null;
}
},
/**
* 确保切换器存在
*/
ensureSwitcher() {
const logoRenderer = DOM.getLogoRenderer();
if (!logoRenderer) return;
let switcher = document.getElementById(Constants.THEME_SWITCHER_ID);
let justCreated = false;
if (!switcher) {
const track = document.createElement('div');
track.className = 'tm-theme-switch-track';
track.setAttribute('role', 'group');
track.setAttribute('aria-label', 'Theme switcher');
switcher = document.createElement('div');
switcher.id = Constants.THEME_SWITCHER_ID;
for (const item of Constants.THEME_MODES) {
const button = document.createElement('button');
button.type = 'button';
button.className = 'tm-theme-switch-option';
button.dataset.mode = item.mode;
button.dataset.active = 'false';
button.textContent = item.label;
button.setAttribute('aria-pressed', 'false');
button.addEventListener('click', async (event) => {
event.preventDefault();
event.stopPropagation();
await this.setMode(item.mode);
});
track.appendChild(button);
}
switcher.append(track);
logoRenderer.insertAdjacentElement('afterend', switcher);
justCreated = true;
} else if (switcher.previousElementSibling !== logoRenderer) {
logoRenderer.insertAdjacentElement('afterend', switcher);
}
this.updateSwitcherUI({ force: justCreated });
},
};
// ============================================================================
// 模块10: 网格切换器管理
// ============================================================================
const GridSwitcher = {
/**
* 更新切换器 UI
*/
updateUI({ force = false } = {}) {
const switcher = document.getElementById(Constants.HOME_GRID_SWITCHER_ID);
if (!switcher) return;
const activeColumns = Storage.normalizeGridColumns(State.grid.currentColumns);
if (!force && State.grid.lastRenderedColumns === activeColumns) return;
State.grid.lastRenderedColumns = activeColumns;
for (const button of switcher.querySelectorAll('.tm-home-grid-option[data-columns]')) {
const isActive = Number(button.dataset.columns) === activeColumns;
button.dataset.active = String(isActive);
button.setAttribute('aria-pressed', String(isActive));
}
},
/**
* 设置列数
*/
setColumns(columns) {
const normalized = Storage.normalizeGridColumns(columns);
if (normalized === State.grid.currentColumns) return;
State.grid.currentColumns = normalized;
Storage.saveHomeGridColumns(normalized);
HomeLayout.applyGridColumns();
this.updateUI();
if (DOM.isHomePage()) {
Scheduler.scheduleApply();
}
},
/**
* 确保切换器存在
*/
ensureSwitcher() {
const anchor = document.getElementById(Constants.THEME_SWITCHER_ID) || DOM.getLogoRenderer();
if (!anchor) return;
let switcher = document.getElementById(Constants.HOME_GRID_SWITCHER_ID);
let justCreated = false;
if (!switcher) {
switcher = document.createElement('div');
switcher.id = Constants.HOME_GRID_SWITCHER_ID;
switcher.setAttribute('role', 'group');
switcher.setAttribute('aria-label', 'Home grid columns');
for (const columns of Constants.Layout.HOME_GRID_COLUMN_OPTIONS) {
const button = document.createElement('button');
button.type = 'button';
button.className = 'tm-home-grid-option';
button.dataset.columns = String(columns);
button.dataset.active = 'false';
button.textContent = String(columns);
button.setAttribute('aria-pressed', 'false');
button.addEventListener('click', (event) => {
event.preventDefault();
event.stopPropagation();
this.setColumns(columns);
});
switcher.appendChild(button);
}
anchor.insertAdjacentElement('afterend', switcher);
justCreated = true;
} else if (switcher.previousElementSibling !== anchor) {
anchor.insertAdjacentElement('afterend', switcher);
}
this.updateUI({ force: justCreated });
},
};
// ============================================================================
// 模块11: 调度器
// ============================================================================
const Scheduler = {
/**
* 应用布局
*/
applyLayout() {
StyleManager.ensure();
HomeLayout.applyGridColumns();
try {
ThemeManager.ensureSwitcher();
GridSwitcher.ensureSwitcher();
} catch (error) {
console.error('YouTube Layout Plus switcher insertion failed:', error);
}
if (DOM.isHomePage()) {
HomeLayout.apply();
return;
}
if (DOM.isWatchPage()) {
WatchLayout.apply();
return;
}
HomeLayout.setLayoutClasses([]);
HomeLayout.clearSideCardThumbnailFit();
WatchLayout.resetState();
},
/**
* 队列应用
*/
queueApply() {
if (State.applyFrame) return;
State.applyFrame = requestAnimationFrame(() => {
State.applyFrame = 0;
this.applyLayout();
});
},
/**
* 调度应用
*/
scheduleApply(delay = 0) {
if (delay > 0) {
clearTimeout(State.timers.applyDelay);
State.timers.applyDelay = setTimeout(() => {
State.timers.applyDelay = null;
this.queueApply();
}, delay);
return;
}
if (State.timers.applyDelay) {
clearTimeout(State.timers.applyDelay);
State.timers.applyDelay = null;
}
this.queueApply();
},
};
// ============================================================================
// 模块12: 路由管理
// ============================================================================
const Router = {
/**
* 开始路由过渡
*/
startTransition() {
if (!DOM.isWatchPage() && !DOM.getWatchFlexy()) return;
if (State.timers.routeTransition) {
clearTimeout(State.timers.routeTransition);
State.timers.routeTransition = null;
}
if (DOM.isWatchPage()) {
WatchLayout.syncPlayerSize();
WatchLayout.lockRouteTransitionPlayer();
}
document.documentElement.classList.add(Constants.Classes.ROUTE_TRANSITION);
},
/**
* 完成路由过渡
*/
finishTransition(delay = 220, attempts = 6) {
if (State.timers.routeTransition) {
clearTimeout(State.timers.routeTransition);
}
State.timers.routeTransition = setTimeout(() => {
if (!DOM.isWatchPage() && DOM.getWatchFlexy() && attempts > 0) {
State.timers.routeTransition = null;
this.finishTransition(100, attempts - 1);
return;
}
State.timers.routeTransition = null;
document.documentElement.classList.remove(Constants.Classes.ROUTE_TRANSITION);
WatchLayout.clearRouteTransitionPlayerLock();
if (!DOM.isWatchPage()) {
WatchLayout.resetState();
}
}, delay);
},
/**
* 处理路由变化
*/
handleChange(force = false) {
const nextUrl = location.href;
if (!force && nextUrl === State.currentUrl) {
this.finishTransition();
return;
}
State.currentUrl = nextUrl;
WatchLayout.clearHiddenReplayPrompts();
if (!DOM.isHomePage()) {
State.layout.lastAutoCollapsedHomeUrl = '';
}
if (!DOM.isWatchPage()) {
State.layout.lastAutoCollapsedWatchChatKey = '';
WatchLayout.stopBootstrap();
WatchLayout.stopChatStateSync();
WatchLayout.detachObservers();
WatchLayout.resetState({
clearSizing: !document.documentElement.classList.contains(Constants.Classes.ROUTE_TRANSITION),
preserveTransitionLayout: document.documentElement.classList.contains(Constants.Classes.ROUTE_TRANSITION),
});
} else {
WatchLayout.resetState({ clearSizing: false });
WatchLayout.detachObservers();
WatchLayout.startBootstrap();
WatchLayout.startChatStateSync();
}
// 动态管理 bodyObserver
if (DOM.isHomePage()) {
ObserverManager.startBody();
} else {
ObserverManager.stopBody();
}
Scheduler.scheduleApply();
this.finishTransition();
},
/**
* 启动路由监听
*/
startWatching() {
if (State.timers.route) return;
State.timers.route = setInterval(() => {
if (location.href === State.currentUrl) return;
this.handleChange();
}, Constants.Timing.ROUTE_POLL_INTERVAL_MS);
},
};
// ============================================================================
// 模块13: 观察者管理
// ============================================================================
const ObserverManager = {
/**
* 启动 body 观察者
*/
startBody() {
if (State.observers.body) return;
State.observers.body = new MutationObserver((mutations) => {
if (DOM.isWatchPage()) return;
const hasRelevantMutation = mutations.some((mutation) => {
const target = mutation.target instanceof Element ? mutation.target : mutation.target?.parentElement;
if (!target) return false;
if (target.closest('#movie_player, .html5-video-player, #chatframe')) return false;
return true;
});
if (hasRelevantMutation) {
Scheduler.scheduleApply(Constants.Timing.OBSERVER_APPLY_DEBOUNCE_MS);
}
});
State.observers.body.observe(document.body, {
childList: true,
subtree: true,
});
},
/**
* 停止 body 观察者
*/
stopBody() {
if (!State.observers.body) return;
State.observers.body.disconnect();
State.observers.body = null;
},
};
// ============================================================================
// 模块14: 事件监听器
// ============================================================================
const EventListeners = {
/**
* 启动导航监听
*/
startNavigation() {
document.addEventListener('yt-navigate-start', () => Router.startTransition(), true);
document.addEventListener('yt-navigate-finish', () => Router.handleChange(), true);
window.addEventListener('popstate', () => {
Router.startTransition();
Router.handleChange();
}, true);
},
/**
* 启动窗口监听
*/
startWindow() {
window.addEventListener('resize', (event) => {
if (event && event.isTrusted === false) return;
if (State.timers.resize) clearTimeout(State.timers.resize);
if (State.resizeFrame) cancelAnimationFrame(State.resizeFrame);
State.resizeFrame = requestAnimationFrame(() => {
State.resizeFrame = 0;
});
State.timers.resize = setTimeout(() => {
State.timers.resize = null;
if (DOM.isWatchPage()) WatchLayout.syncPlayerSize();
if (DOM.isHomePage()) HomeLayout.scheduleSideCardThumbnailFit();
Scheduler.scheduleApply();
}, 80);
}, true);
document.addEventListener('fullscreenchange', () => {
if (!DOM.isWatchPage()) return;
const watchFlexy = DOM.getWatchFlexy();
if (watchFlexy) {
WatchLayout.updateTheaterModeState(watchFlexy);
WatchLayout.updateEngagementPanelState(watchFlexy);
}
WatchLayout.syncPlayerSize();
Scheduler.scheduleApply();
}, true);
window.addEventListener('beforeunload', () => this.cleanupAll(), { once: true });
},
/**
* 启动交互监听
*/
startInteraction() {
document.addEventListener('click', (event) => {
const trigger = event.target instanceof Element
? event.target.closest('button, yt-button-shape button, tp-yt-paper-button')
: null;
if (!trigger) return;
const text = (trigger.innerText || trigger.textContent || '').trim();
if (/open panel/i.test(text) && DOM.isWatchPage()) {
State.layout.lastAutoCollapsedWatchChatKey = DOM.getWatchPageKey();
Scheduler.scheduleApply(80);
}
if (DOM.isWatchPage()) {
setTimeout(() => {
const watchFlexy = DOM.getWatchFlexy();
if (watchFlexy) {
WatchLayout.updateEngagementPanelState(watchFlexy);
WatchLayout.updateTheaterModeState(watchFlexy);
}
WatchLayout.syncPlayerSize();
}, 120);
setTimeout(() => {
if (DOM.isWatchPage()) WatchLayout.syncPlayerSize();
}, 360);
}
}, true);
document.addEventListener('keyup', (event) => {
if (!DOM.isWatchPage()) return;
if (event.key !== 't' && event.key !== 'T' && event.key !== 'f' && event.key !== 'F') return;
const target = event.target;
if (target instanceof HTMLElement) {
const tag = target.tagName;
if (tag === 'INPUT' || tag === 'TEXTAREA' || target.isContentEditable) return;
}
setTimeout(() => {
const watchFlexy = DOM.getWatchFlexy();
if (watchFlexy) WatchLayout.updateTheaterModeState(watchFlexy);
WatchLayout.syncPlayerSize();
}, 80);
}, true);
},
/**
* 清理所有资源
*/
cleanupAll() {
// 清理定时器
Object.values(State.timers).forEach(timer => {
if (timer) clearTimeout(timer);
});
Object.keys(State.timers).forEach(key => {
State.timers[key] = null;
});
// 清理观察者
ObserverManager.stopBody();
WatchLayout.detachObservers();
WatchLayout.stopBootstrap();
WatchLayout.stopChatStateSync();
// 清理动画帧
if (State.applyFrame) {
cancelAnimationFrame(State.applyFrame);
State.applyFrame = 0;
}
if (State.resizeFrame) {
cancelAnimationFrame(State.resizeFrame);
State.resizeFrame = 0;
}
// 清理缓存
State.elementDataCache.clear();
},
};
// ============================================================================
// 模块15: 初始化
// ============================================================================
const App = {
/**
* 初始化应用
*/
init() {
ThemeManager.init();
StyleManager.ensure();
Router.handleChange(true);
EventListeners.startNavigation();
EventListeners.startWindow();
EventListeners.startInteraction();
Router.startWatching();
},
};
// 启动应用
App.init();
})();