Fix discover carousel scaling
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
// ==UserScript==
|
// ==UserScript==
|
||||||
// @name Chaturbate 缩略图放大 2 倍
|
// @name Chaturbate 缩略图放大 2 倍
|
||||||
// @namespace https://chaturbate.com/
|
// @namespace https://chaturbate.com/
|
||||||
// @version 0.12.0
|
// @version 0.12.2
|
||||||
// @description 放大当前 Chaturbate 房间列表, 发现页轮播, 关注下拉与悬停预览缩略图
|
// @description 放大当前 Chaturbate 房间列表, 发现页轮播, 关注下拉与悬停预览缩略图
|
||||||
// @match https://chaturbate.com/*
|
// @match https://chaturbate.com/*
|
||||||
// @match https://*.chaturbate.com/*
|
// @match https://*.chaturbate.com/*
|
||||||
@@ -58,7 +58,7 @@
|
|||||||
const DEBUG = true;
|
const DEBUG = true;
|
||||||
// ===========================
|
// ===========================
|
||||||
|
|
||||||
const VER = "0.12.0";
|
const VER = "0.12.2";
|
||||||
// 旧版本用过 localStorage 尺寸缓存.当前版本不再读写缓存, 避免旧探测值污染新布局.
|
// 旧版本用过 localStorage 尺寸缓存.当前版本不再读写缓存, 避免旧探测值污染新布局.
|
||||||
const LEGACY_CACHE_PREFIX = "tm-thumb-scale:size-cache:";
|
const LEGACY_CACHE_PREFIX = "tm-thumb-scale:size-cache:";
|
||||||
const log = (...args) => {
|
const log = (...args) => {
|
||||||
@@ -304,19 +304,22 @@
|
|||||||
* - 探测值:
|
* - 探测值:
|
||||||
* 1. li 卡片宽高;
|
* 1. li 卡片宽高;
|
||||||
* 2. 缩略图容器高度;
|
* 2. 缩略图容器高度;
|
||||||
* 3. triple/double/single 三种轮播 ul 高度;
|
* 3. triple/double/single 三种轮播 ul 高度.
|
||||||
* 4. 对应箭头容器高度.
|
* - 放大方式: 图片宽高和卡片宽度乘 THUMBNAIL_SCALE.
|
||||||
* - 放大方式: 图片宽高和卡片宽度乘 THUMBNAIL_SCALE; 卡片高度, 轮播容器高度, 箭头高度乘 CARD_HEIGHT_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"] .carousel-root .triple-rows ul.list,
|
||||||
html[data-tm-thumb-scale-discover="1"] #discover_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;
|
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"] .carousel-root .triple-rows .carousel-arrow-container,
|
||||||
html[data-tm-thumb-scale-discover="1"] #discover_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;
|
height: var(--tm-thumb-discover-triple-arrow) !important;
|
||||||
}
|
}
|
||||||
html[data-tm-thumb-scale-discover="1"] .carousel-root .double-rows ul.list,
|
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 {
|
html[data-tm-thumb-scale-discover="1"] #discover_root .room-list-carousel .room_thumbnail_container {
|
||||||
display: block !important;
|
display: block !important;
|
||||||
width: var(--tm-thumb-discover-thumb-width) !important;
|
width: var(--tm-thumb-discover-thumb-width) !important;
|
||||||
|
height: var(--tm-thumb-discover-height) !important;
|
||||||
max-width: none !important;
|
max-width: none !important;
|
||||||
box-sizing: border-box !important;
|
box-sizing: border-box !important;
|
||||||
}
|
}
|
||||||
@@ -410,6 +414,24 @@
|
|||||||
const nonThumbHeight = Math.max(0, cardHeight - thumbHeight);
|
const nonThumbHeight = Math.max(0, cardHeight - thumbHeight);
|
||||||
return `${Math.round((thumbHeight * THUMBNAIL_SCALE) + nonThumbHeight)}px`;
|
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 scaledCardHeightFromThumbWithScalePx = (cardHeight, thumbHeight, scale) => {
|
||||||
const nonThumbHeight = Math.max(0, cardHeight - thumbHeight);
|
const nonThumbHeight = Math.max(0, cardHeight - thumbHeight);
|
||||||
return `${Math.round((thumbHeight * scale) + nonThumbHeight)}px`;
|
return `${Math.round((thumbHeight * scale) + nonThumbHeight)}px`;
|
||||||
@@ -443,6 +465,18 @@
|
|||||||
style.setProperty(name, scaledCardHeightFromThumbPx(cardHeight, thumbHeight));
|
style.setProperty(name, scaledCardHeightFromThumbPx(cardHeight, thumbHeight));
|
||||||
return true;
|
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 setListScaleVars = (columnsName, cardHeightName, thumbHeightName, metrics, cardWidth, cardHeight, thumbHeight) => {
|
||||||
const style = rootStyle();
|
const style = rootStyle();
|
||||||
if (
|
if (
|
||||||
@@ -649,16 +683,13 @@
|
|||||||
followThumb: moduleReady.follow ? null : firstRect(".FollowedDropdown__room-image"),
|
followThumb: moduleReady.follow ? null : firstRect(".FollowedDropdown__room-image"),
|
||||||
// 悬浮预览: tooltip 是 portal 动态插入, 也靠 mutation 捕捉.
|
// 悬浮预览: 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"]'),
|
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"),
|
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"),
|
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"),
|
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"),
|
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"),
|
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) {
|
if (!moduleReady.home && !followingListPage) {
|
||||||
@@ -726,19 +757,37 @@
|
|||||||
if (!moduleReady.discover) {
|
if (!moduleReady.discover) {
|
||||||
// 发现页要求更严格: 少一个高度都不开启, 宁可不放大, 也不要错位.
|
// 发现页要求更严格: 少一个高度都不开启, 宁可不放大, 也不要错位.
|
||||||
const discoverWidthReady = setVar("--tm-thumb-discover-width", measured.discoverCard && measured.discoverCard.width);
|
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 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 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 discoverTripleReady = setDiscoverStackHeightVars(
|
||||||
const discoverTripleArrowReady = setCardHeightVar("--tm-thumb-discover-triple-arrow", measured.discoverTripleArrow && measured.discoverTripleArrow.height);
|
"--tm-thumb-discover-triple-ul",
|
||||||
const discoverDoubleUlReady = setCardHeightVar("--tm-thumb-discover-double-ul", measured.discoverDoubleUl && measured.discoverDoubleUl.height);
|
"--tm-thumb-discover-triple-arrow",
|
||||||
const discoverDoubleArrowReady = setCardHeightVar("--tm-thumb-discover-double-arrow", measured.discoverDoubleArrow && measured.discoverDoubleArrow.height);
|
measured.discoverTripleUl && measured.discoverTripleUl.height,
|
||||||
const discoverSingleUlReady = setCardHeightVar("--tm-thumb-discover-single-ul", measured.discoverSingleUl && measured.discoverSingleUl.height);
|
measured.discoverCard && measured.discoverCard.height,
|
||||||
const discoverSingleArrowReady = setCardHeightVar("--tm-thumb-discover-single-arrow", measured.discoverSingleArrow && measured.discoverSingleArrow.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
|
moduleReady.discover = discoverWidthReady && discoverCardHeightReady && discoverThumbWidthReady && discoverHeightReady
|
||||||
&& discoverTripleUlReady && discoverTripleArrowReady
|
&& discoverTripleReady
|
||||||
&& discoverDoubleUlReady && discoverDoubleArrowReady
|
&& discoverDoubleReady
|
||||||
&& discoverSingleUlReady && discoverSingleArrowReady;
|
&& discoverSingleReady;
|
||||||
setModuleReady("discover", moduleReady.discover);
|
setModuleReady("discover", moduleReady.discover);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -136,6 +136,11 @@ assert.match(
|
|||||||
/#discover_root\s+\.room-list-carousel\s+\.room_thumbnail_container\s+img/,
|
/#discover_root\s+\.room-list-carousel\s+\.room_thumbnail_container\s+img/,
|
||||||
"discover carousel thumbnail images should fill enlarged items",
|
"discover carousel thumbnail images should fill enlarged items",
|
||||||
);
|
);
|
||||||
|
assert.match(
|
||||||
|
capturedCss,
|
||||||
|
/#discover_root\s+\.room-list-carousel\s+\.room_thumbnail_container[\s\S]*height:\s*var\(--tm-thumb-discover-height\)\s*!important/,
|
||||||
|
"discover carousel thumbnail containers should use detected scaled height",
|
||||||
|
);
|
||||||
assert.match(
|
assert.match(
|
||||||
capturedCss,
|
capturedCss,
|
||||||
/height:\s*var\(--tm-thumb-discover-triple-ul\)\s*!important/,
|
/height:\s*var\(--tm-thumb-discover-triple-ul\)\s*!important/,
|
||||||
@@ -176,6 +181,9 @@ assert.match(source, /detectAndApplySizes/, "script should detect original sizes
|
|||||||
assert.match(source, /moduleReady/, "script should lock each module after detecting its original size");
|
assert.match(source, /moduleReady/, "script should lock each module after detecting its original size");
|
||||||
assert.match(source, /CARD_HEIGHT_SCALE/, "script should use a separate scale for card heights");
|
assert.match(source, /CARD_HEIGHT_SCALE/, "script should use a separate scale for card heights");
|
||||||
assert.match(source, /setCardHeightVar/, "script should apply card height scaling separately from thumbnail scaling");
|
assert.match(source, /setCardHeightVar/, "script should apply card height scaling separately from thumbnail scaling");
|
||||||
|
assert.match(source, /setDiscoverStackHeightVars/, "discover carousel stack heights should be derived from scaled card rows");
|
||||||
|
assert.match(source, /setCardHeightFromThumbVar\("--tm-thumb-discover-card-height"/, "discover card height should scale the thumbnail area and keep metadata height");
|
||||||
|
assert.match(source, /stackHeight == null\) return true/, "discover should not require every carousel row type to exist before enabling");
|
||||||
assert.doesNotMatch(source, /localStorage\.setItem/, "script should not write detected sizes to localStorage");
|
assert.doesNotMatch(source, /localStorage\.setItem/, "script should not write detected sizes to localStorage");
|
||||||
assert.match(source, /LEGACY_CACHE_PREFIX/, "script should only keep legacy cache cleanup support");
|
assert.match(source, /LEGACY_CACHE_PREFIX/, "script should only keep legacy cache cleanup support");
|
||||||
assert.match(source, /scheduleMeasure\("after-800ms"\)/, "script should delay the first page measurement until original layout can render");
|
assert.match(source, /scheduleMeasure\("after-800ms"\)/, "script should delay the first page measurement until original layout can render");
|
||||||
|
|||||||
Reference in New Issue
Block a user