Fix discover carousel scaling

This commit is contained in:
2026-06-02 01:36:29 +08:00
parent d078339288
commit 893fe47ace
2 changed files with 79 additions and 22 deletions

View File

@@ -1,7 +1,7 @@
// ==UserScript==
// @name Chaturbate 缩略图放大 2 倍
// @namespace https://chaturbate.com/
// @version 0.12.0
// @version 0.12.2
// @description 放大当前 Chaturbate 房间列表, 发现页轮播, 关注下拉与悬停预览缩略图
// @match https://chaturbate.com/*
// @match https://*.chaturbate.com/*
@@ -58,7 +58,7 @@
const DEBUG = true;
// ===========================
const VER = "0.12.0";
const VER = "0.12.2";
// 旧版本用过 localStorage 尺寸缓存.当前版本不再读写缓存, 避免旧探测值污染新布局.
const LEGACY_CACHE_PREFIX = "tm-thumb-scale:size-cache:";
const log = (...args) => {
@@ -304,19 +304,22 @@
* - 探测值:
* 1. li 卡片宽高;
* 2. 缩略图容器高度;
* 3. triple/double/single 三种轮播 ul 高度;
* 4. 对应箭头容器高度.
* - 放大方式: 图片宽高和卡片宽度乘 THUMBNAIL_SCALE; 卡片高度, 轮播容器高度, 箭头高度乘 CARD_HEIGHT_SCALE.
* - 启用条件: 全部值都探测到才打开发现页放大, 缺一项就不动, 避免局部放大导致错位.
* 3. triple/double/single 三种轮播 ul 高度.
* - 放大方式: 图片宽高和卡片宽度乘 THUMBNAIL_SCALE.
* - 卡片高度: 只把缩略图区域乘 THUMBNAIL_SCALE, 用户名/人数等信息栏保留原始高度.
* - 轮播高度: triple/double/single 按 3/2/1 行卡片高度重新计算, 保留原始行间距.
* - 箭头高度: 跟对应轮播高度同步, 避免右侧箭头与轮播内容错位.
* - 启用条件: 卡片和缩略图探测到就先启用; 某种行数的轮播不存在时跳过对应高度变量.
* 不能强制要求 triple/double/single 全部存在, 否则页面少一种轮播就会导致发现页完全不放大.
*/
html[data-tm-thumb-scale-discover="1"] .carousel-root .triple-rows ul.list,
html[data-tm-thumb-scale-discover="1"] #discover_root .triple-rows ul.list {
/* 三行轮播的整体高度按 CARD_HEIGHT_SCALE 放大, 避免卡片下方出现过多空白. */
/* 三行轮播高度由"放大后卡片高度 * 3 + 原始行间距"推导. */
height: var(--tm-thumb-discover-triple-ul) !important;
}
html[data-tm-thumb-scale-discover="1"] .carousel-root .triple-rows .carousel-arrow-container,
html[data-tm-thumb-scale-discover="1"] #discover_root .triple-rows .carousel-arrow-container {
/* 箭头容器也按 CARD_HEIGHT_SCALE 放大, 否则右侧箭头会和轮播高度不一致. */
/* 箭头容器跟轮播高度一致, 否则右侧箭头会和轮播内容错位. */
height: var(--tm-thumb-discover-triple-arrow) !important;
}
html[data-tm-thumb-scale-discover="1"] .carousel-root .double-rows ul.list,
@@ -354,6 +357,7 @@
html[data-tm-thumb-scale-discover="1"] #discover_root .room-list-carousel .room_thumbnail_container {
display: block !important;
width: var(--tm-thumb-discover-thumb-width) !important;
height: var(--tm-thumb-discover-height) !important;
max-width: none !important;
box-sizing: border-box !important;
}
@@ -410,6 +414,24 @@
const nonThumbHeight = Math.max(0, cardHeight - thumbHeight);
return `${Math.round((thumbHeight * THUMBNAIL_SCALE) + nonThumbHeight)}px`;
};
const scaledCardHeightFromThumbValue = (cardHeight, thumbHeight) => {
const nonThumbHeight = Math.max(0, cardHeight - thumbHeight);
return Math.round((thumbHeight * THUMBNAIL_SCALE) + nonThumbHeight);
};
const scaledStackHeightFromCardValue = (stackHeight, cardHeight, thumbHeight, rows) => {
if (
!Number.isFinite(stackHeight)
|| !Number.isFinite(cardHeight)
|| !Number.isFinite(thumbHeight)
|| !Number.isFinite(rows)
|| stackHeight <= 0
|| cardHeight <= 0
|| thumbHeight <= 0
|| rows <= 0
) return null;
const originalNonCardSpace = Math.max(0, stackHeight - (cardHeight * rows));
return Math.round((scaledCardHeightFromThumbValue(cardHeight, thumbHeight) * rows) + originalNonCardSpace);
};
const scaledCardHeightFromThumbWithScalePx = (cardHeight, thumbHeight, scale) => {
const nonThumbHeight = Math.max(0, cardHeight - thumbHeight);
return `${Math.round((thumbHeight * scale) + nonThumbHeight)}px`;
@@ -443,6 +465,18 @@
style.setProperty(name, scaledCardHeightFromThumbPx(cardHeight, thumbHeight));
return true;
};
const setDiscoverStackHeightVars = (ulName, arrowName, stackHeight, cardHeight, thumbHeight, rows) => {
const style = rootStyle();
// 发现页并不保证 triple/double/single 三种轮播同时存在.
// 缺少某一种时直接视为完成, 避免一个缺失行把整个发现页放大总开关卡住.
if (stackHeight == null) return true;
const height = scaledStackHeightFromCardValue(stackHeight, cardHeight, thumbHeight, rows);
if (!style || !height) return false;
const value = `${height}px`;
style.setProperty(ulName, value);
style.setProperty(arrowName, value);
return true;
};
const setListScaleVars = (columnsName, cardHeightName, thumbHeightName, metrics, cardWidth, cardHeight, thumbHeight) => {
const style = rootStyle();
if (
@@ -649,16 +683,13 @@
followThumb: moduleReady.follow ? null : firstRect(".FollowedDropdown__room-image"),
// 悬浮预览: tooltip 是 portal 动态插入, 也靠 mutation 捕捉.
tooltipThumb: moduleReady.tooltip ? null : firstRect('body > div[id^="react-tooltip"] img[src*="live.mmcdn.com"], body > div[id^="react-tooltip"] img[src*="thumb.live.mmcdn"], [data-floating-ui-portal] img[src*="live.mmcdn.com"]'),
// 发现页 carousel: 必须同时探测 card, thumb, 行容器和箭头高度, 全部成功后才启用.
// 发现页 carousel: 必须同时探测 card, thumb 行容器高度, 全部成功后才启用.
// 这样"最受欢迎"等多行轮播能保持站点原来的对齐关系, 只是整体按倍率放大.
discoverCard: moduleReady.discover ? null : firstRect(".carousel-root .room-list-carousel ul.list > li, #discover_root .room-list-carousel ul.list > li"),
discoverThumb: moduleReady.discover ? null : firstRect(".carousel-root .room-list-carousel .room_thumbnail_container, #discover_root .room-list-carousel .room_thumbnail_container"),
discoverTripleUl: moduleReady.discover ? null : firstRect(".carousel-root .triple-rows ul.list, #discover_root .triple-rows ul.list"),
discoverTripleArrow: moduleReady.discover ? null : firstRect(".carousel-root .triple-rows .carousel-arrow-container, #discover_root .triple-rows .carousel-arrow-container"),
discoverDoubleUl: moduleReady.discover ? null : firstRect(".carousel-root .double-rows ul.list, #discover_root .double-rows ul.list"),
discoverDoubleArrow: moduleReady.discover ? null : firstRect(".carousel-root .double-rows .carousel-arrow-container, #discover_root .double-rows .carousel-arrow-container"),
discoverSingleUl: moduleReady.discover ? null : firstRect(".carousel-root .single-row ul.list, #discover_root .single-row ul.list"),
discoverSingleArrow: moduleReady.discover ? null : firstRect(".carousel-root .single-row .carousel-arrow-container, #discover_root .single-row .carousel-arrow-container"),
};
if (!moduleReady.home && !followingListPage) {
@@ -726,19 +757,37 @@
if (!moduleReady.discover) {
// 发现页要求更严格: 少一个高度都不开启, 宁可不放大, 也不要错位.
const discoverWidthReady = setVar("--tm-thumb-discover-width", measured.discoverCard && measured.discoverCard.width);
const discoverCardHeightReady = setCardHeightVar("--tm-thumb-discover-card-height", measured.discoverCard && measured.discoverCard.height);
const discoverCardHeightReady = setCardHeightFromThumbVar("--tm-thumb-discover-card-height", measured.discoverCard && measured.discoverCard.height, measured.discoverThumb && measured.discoverThumb.height);
const discoverThumbWidthReady = setVar("--tm-thumb-discover-thumb-width", measured.discoverThumb && measured.discoverThumb.width);
const discoverHeightReady = setVar("--tm-thumb-discover-height", measured.discoverThumb && measured.discoverThumb.height);
const discoverTripleUlReady = setCardHeightVar("--tm-thumb-discover-triple-ul", measured.discoverTripleUl && measured.discoverTripleUl.height);
const discoverTripleArrowReady = setCardHeightVar("--tm-thumb-discover-triple-arrow", measured.discoverTripleArrow && measured.discoverTripleArrow.height);
const discoverDoubleUlReady = setCardHeightVar("--tm-thumb-discover-double-ul", measured.discoverDoubleUl && measured.discoverDoubleUl.height);
const discoverDoubleArrowReady = setCardHeightVar("--tm-thumb-discover-double-arrow", measured.discoverDoubleArrow && measured.discoverDoubleArrow.height);
const discoverSingleUlReady = setCardHeightVar("--tm-thumb-discover-single-ul", measured.discoverSingleUl && measured.discoverSingleUl.height);
const discoverSingleArrowReady = setCardHeightVar("--tm-thumb-discover-single-arrow", measured.discoverSingleArrow && measured.discoverSingleArrow.height);
const discoverTripleReady = setDiscoverStackHeightVars(
"--tm-thumb-discover-triple-ul",
"--tm-thumb-discover-triple-arrow",
measured.discoverTripleUl && measured.discoverTripleUl.height,
measured.discoverCard && measured.discoverCard.height,
measured.discoverThumb && measured.discoverThumb.height,
3,
);
const discoverDoubleReady = setDiscoverStackHeightVars(
"--tm-thumb-discover-double-ul",
"--tm-thumb-discover-double-arrow",
measured.discoverDoubleUl && measured.discoverDoubleUl.height,
measured.discoverCard && measured.discoverCard.height,
measured.discoverThumb && measured.discoverThumb.height,
2,
);
const discoverSingleReady = setDiscoverStackHeightVars(
"--tm-thumb-discover-single-ul",
"--tm-thumb-discover-single-arrow",
measured.discoverSingleUl && measured.discoverSingleUl.height,
measured.discoverCard && measured.discoverCard.height,
measured.discoverThumb && measured.discoverThumb.height,
1,
);
moduleReady.discover = discoverWidthReady && discoverCardHeightReady && discoverThumbWidthReady && discoverHeightReady
&& discoverTripleUlReady && discoverTripleArrowReady
&& discoverDoubleUlReady && discoverDoubleArrowReady
&& discoverSingleUlReady && discoverSingleArrowReady;
&& discoverTripleReady
&& discoverDoubleReady
&& discoverSingleReady;
setModuleReady("discover", moduleReady.discover);
}