diff --git a/Chaturbate/chaturbate-thumbnails-2x.user.js b/Chaturbate/chaturbate-thumbnails-2x.user.js index 684ea43..79fd183 100644 --- a/Chaturbate/chaturbate-thumbnails-2x.user.js +++ b/Chaturbate/chaturbate-thumbnails-2x.user.js @@ -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); } diff --git a/tests/followed-dropdown-css.test.js b/tests/followed-dropdown-css.test.js index 492f758..104d2ac 100644 --- a/tests/followed-dropdown-css.test.js +++ b/tests/followed-dropdown-css.test.js @@ -136,6 +136,11 @@ assert.match( /#discover_root\s+\.room-list-carousel\s+\.room_thumbnail_container\s+img/, "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( capturedCss, /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, /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, /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.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");