Fix thumbnail scaling heights
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.11.3
|
// @version 0.12.0
|
||||||
// @description 放大当前 Chaturbate 房间列表, 发现页轮播, 关注下拉与悬停预览缩略图
|
// @description 放大当前 Chaturbate 房间列表, 发现页轮播, 关注下拉与悬停预览缩略图
|
||||||
// @match https://chaturbate.com/*
|
// @match https://chaturbate.com/*
|
||||||
// @match https://*.chaturbate.com/*
|
// @match https://*.chaturbate.com/*
|
||||||
@@ -35,9 +35,9 @@
|
|||||||
* CSS 先注入但所有模块默认关闭; 等页面原始 DOM 渲染后, 逐个模块探测原始尺寸, 成功后才打开该模块.
|
* CSS 先注入但所有模块默认关闭; 等页面原始 DOM 渲染后, 逐个模块探测原始尺寸, 成功后才打开该模块.
|
||||||
* 模块一旦探测成功就锁定, 避免后续 mutation 把已经放大的尺寸当成原始值再次相乘.
|
* 模块一旦探测成功就锁定, 避免后续 mutation 把已经放大的尺寸当成原始值再次相乘.
|
||||||
*
|
*
|
||||||
* 4) 探测结果缓存的是"原始尺寸", 不是放大后的尺寸.
|
* 4) 不再缓存探测结果.
|
||||||
* 缓存按模块保存; 命中缓存就直接设置 CSS 变量并启用模块, 未命中才延迟探测.
|
* Chaturbate 的列表宽度会随页面/窗口变化, 缓存旧尺寸容易污染新布局.
|
||||||
* 油猴菜单可清除缓存, 清除后刷新页面即可重新探测.
|
* 当前版本每次页面加载都重新探测; 油猴菜单只用于清除旧版本遗留的 localStorage 缓存.
|
||||||
*
|
*
|
||||||
* 5) 顶部"关注"弹窗的 FOLLOW_DROPDOWN_SHIFT_X 只是位置微调, 不属于缩略图倍率.
|
* 5) 顶部"关注"弹窗的 FOLLOW_DROPDOWN_SHIFT_X 只是位置微调, 不属于缩略图倍率.
|
||||||
*
|
*
|
||||||
@@ -58,11 +58,9 @@
|
|||||||
const DEBUG = true;
|
const DEBUG = true;
|
||||||
// ===========================
|
// ===========================
|
||||||
|
|
||||||
const VER = "0.11.3";
|
const VER = "0.12.0";
|
||||||
// 缓存只保存"站点原始尺寸", 不要保存乘过倍率后的尺寸.
|
// 旧版本用过 localStorage 尺寸缓存.当前版本不再读写缓存, 避免旧探测值污染新布局.
|
||||||
// 这样以后只改 THUMBNAIL_SCALE / CARD_HEIGHT_SCALE 时, 可以让缓存自动失效并重新探测, 避免旧倍率污染新布局.
|
const LEGACY_CACHE_PREFIX = "tm-thumb-scale:size-cache:";
|
||||||
const CACHE_KEY = "tm-thumb-scale:size-cache:v11";
|
|
||||||
const CACHE_SCHEMA = 11;
|
|
||||||
const log = (...args) => {
|
const log = (...args) => {
|
||||||
if (DEBUG) console.log("[tm-thumb-scale]", ...args);
|
if (DEBUG) console.log("[tm-thumb-scale]", ...args);
|
||||||
};
|
};
|
||||||
@@ -87,9 +85,9 @@
|
|||||||
/*
|
/*
|
||||||
* home 模块:
|
* home 模块:
|
||||||
* - 适用范围: 主页, 分类页等普通 #roomlist_root 房间列表.
|
* - 适用范围: 主页, 分类页等普通 #roomlist_root 房间列表.
|
||||||
* - 探测值: 卡片原始宽高 + 缩略图原始宽高.
|
* - 探测值: 站点 CSS 里的 grid 最小列宽 + 卡片原始高度 + 缩略图原始高度.
|
||||||
* - 放大方式: grid 列宽按 THUMBNAIL_SCALE 放大一次; 缩略图宽度保持 100%; 缩略图高度按 THUMBNAIL_SCALE 放大.
|
* - 放大方式: 原站列数除以 THUMBNAIL_SCALE; 每列仍用 1fr 均分, 保留原站对齐方式.
|
||||||
* - 注意: 关注页列表单独用 followingList 模块, 不和 home 共用缓存.
|
* - 注意: 关注页列表单独用 followingList 模块, 不和 home 共用探测结果.
|
||||||
*/
|
*/
|
||||||
html[data-tm-thumb-scale-home="1"] #main #roomlist_root ul.RoomCardGrid,
|
html[data-tm-thumb-scale-home="1"] #main #roomlist_root ul.RoomCardGrid,
|
||||||
html[data-tm-thumb-scale-home="1"] #roomlist_root ul.RoomCardGrid,
|
html[data-tm-thumb-scale-home="1"] #roomlist_root ul.RoomCardGrid,
|
||||||
@@ -97,8 +95,10 @@
|
|||||||
html[data-tm-thumb-scale-home="1"] #roomlist_root ul.list:has(li.roomCard) {
|
html[data-tm-thumb-scale-home="1"] #roomlist_root ul.list:has(li.roomCard) {
|
||||||
/* 改成 grid, 是为了让放大后的卡片按新宽度自然换行. */
|
/* 改成 grid, 是为了让放大后的卡片按新宽度自然换行. */
|
||||||
display: grid !important;
|
display: grid !important;
|
||||||
/* --tm-thumb-home-width 来自当前页面原始卡片宽度, JS 写入时已经乘过倍率. */
|
/* --tm-thumb-home-columns 来自原站自然列数, JS 写入时已经除过倍率. */
|
||||||
grid-template-columns: repeat(auto-fill, minmax(var(--tm-thumb-home-width), 1fr)) !important;
|
grid-template-columns: repeat(var(--tm-thumb-home-columns), minmax(0, 1fr)) !important;
|
||||||
|
justify-content: stretch !important;
|
||||||
|
align-items: start !important;
|
||||||
/* 保留一个稳定间距, 避免放大后卡片互相贴住. */
|
/* 保留一个稳定间距, 避免放大后卡片互相贴住. */
|
||||||
gap: 0.6em 0.75em !important;
|
gap: 0.6em 0.75em !important;
|
||||||
}
|
}
|
||||||
@@ -106,6 +106,7 @@
|
|||||||
html[data-tm-thumb-scale-home="1"] #roomlist_root ul.list:has(li.roomCard) li.roomCard {
|
html[data-tm-thumb-scale-home="1"] #roomlist_root ul.list:has(li.roomCard) li.roomCard {
|
||||||
/* 列宽交给 grid 控制, 清掉站点原本写死的 li 宽度限制. */
|
/* 列宽交给 grid 控制, 清掉站点原本写死的 li 宽度限制. */
|
||||||
width: auto !important;
|
width: auto !important;
|
||||||
|
justify-self: stretch !important;
|
||||||
min-width: 0 !important;
|
min-width: 0 !important;
|
||||||
max-width: none !important;
|
max-width: none !important;
|
||||||
height: var(--tm-thumb-home-card-height) !important;
|
height: var(--tm-thumb-home-card-height) !important;
|
||||||
@@ -136,23 +137,24 @@
|
|||||||
* followingList 模块:
|
* followingList 模块:
|
||||||
* - 适用范围: /followed-cams/ 关注页里的 #roomlist_root 房间列表.
|
* - 适用范围: /followed-cams/ 关注页里的 #roomlist_root 房间列表.
|
||||||
* - 为什么和 home 分开: 两者 DOM 选择器很像, 但站点可能给不同页面不同原始列宽.
|
* - 为什么和 home 分开: 两者 DOM 选择器很像, 但站点可能给不同页面不同原始列宽.
|
||||||
* - 缓存也单独存 followingList, 避免首页探测值污染关注页.
|
* - followingList 单独探测, 避免首页探测值污染关注页.
|
||||||
* - 探测值: 卡片原始宽高 + 缩略图原始宽高.
|
* - 探测值: 站点 CSS 里的 grid 最小列宽 + 卡片原始高度 + 缩略图原始高度.
|
||||||
* - 和 home 一样, grid 列宽按 THUMBNAIL_SCALE 放大一次; 缩略图宽度保持 100%; 缩略图高度按 THUMBNAIL_SCALE 放大.
|
* - 和 home 一样, 原站列数除以 THUMBNAIL_SCALE; 每列仍用 1fr 均分, 保留原站对齐方式.
|
||||||
* - 注意: 这里仍保留 minmax(..., 1fr), 让站点原来的整行拉伸/对齐逻辑继续工作.
|
|
||||||
* 不能改成固定列宽, 否则宽屏下会出现大空洞, 看起来比原站更乱.
|
|
||||||
*/
|
*/
|
||||||
html[data-tm-thumb-scale-following-list="1"] #main #roomlist_root ul.RoomCardGrid,
|
html[data-tm-thumb-scale-following-list="1"] #main #roomlist_root ul.RoomCardGrid,
|
||||||
html[data-tm-thumb-scale-following-list="1"] #roomlist_root ul.RoomCardGrid,
|
html[data-tm-thumb-scale-following-list="1"] #roomlist_root ul.RoomCardGrid,
|
||||||
html[data-tm-thumb-scale-following-list="1"] #main #roomlist_root ul.list:has(li.roomCard),
|
html[data-tm-thumb-scale-following-list="1"] #main #roomlist_root ul.list:has(li.roomCard),
|
||||||
html[data-tm-thumb-scale-following-list="1"] #roomlist_root ul.list:has(li.roomCard) {
|
html[data-tm-thumb-scale-following-list="1"] #roomlist_root ul.list:has(li.roomCard) {
|
||||||
display: grid !important;
|
display: grid !important;
|
||||||
grid-template-columns: repeat(auto-fill, minmax(var(--tm-thumb-following-list-width), 1fr)) !important;
|
grid-template-columns: repeat(var(--tm-thumb-following-list-columns), minmax(0, 1fr)) !important;
|
||||||
|
justify-content: stretch !important;
|
||||||
|
align-items: start !important;
|
||||||
gap: 0.6em 0.75em !important;
|
gap: 0.6em 0.75em !important;
|
||||||
}
|
}
|
||||||
html[data-tm-thumb-scale-following-list="1"] #roomlist_root ul.RoomCardGrid > li.RoomCard,
|
html[data-tm-thumb-scale-following-list="1"] #roomlist_root ul.RoomCardGrid > li.RoomCard,
|
||||||
html[data-tm-thumb-scale-following-list="1"] #roomlist_root ul.list:has(li.roomCard) li.roomCard {
|
html[data-tm-thumb-scale-following-list="1"] #roomlist_root ul.list:has(li.roomCard) li.roomCard {
|
||||||
width: auto !important;
|
width: auto !important;
|
||||||
|
justify-self: stretch !important;
|
||||||
min-width: 0 !important;
|
min-width: 0 !important;
|
||||||
max-width: none !important;
|
max-width: none !important;
|
||||||
height: var(--tm-thumb-following-list-card-height) !important;
|
height: var(--tm-thumb-following-list-card-height) !important;
|
||||||
@@ -180,22 +182,27 @@
|
|||||||
/*
|
/*
|
||||||
* related 模块:
|
* related 模块:
|
||||||
* - 适用范围: 直播间页面底部"更多这样的房间".
|
* - 适用范围: 直播间页面底部"更多这样的房间".
|
||||||
* - 探测值: 卡片原始宽高 + 缩略图原始宽高.
|
* - 探测值: 卡片原始宽度 + 卡片原始高度 + 缩略图原始高度.
|
||||||
* - 放大方式: 卡片和缩略图分别按自己的原始宽高乘倍率, 避免把 card 宽度误当 thumb 宽度.
|
* - 放大方式: 卡片宽度按 THUMBNAIL_SCALE 固定放大; 缩略图宽度跟随卡片宽度.
|
||||||
|
* - 为什么不按列数: 这个区域是频道页里的局部推荐列表, 容器宽度和首页/关注页不同,
|
||||||
|
* 用"列数除倍率"会把卡片拉成容器均分宽度, 导致"更多这样的房间"宽高比例失真.
|
||||||
*/
|
*/
|
||||||
html[data-tm-thumb-scale-related="1"] .BaseRoomContents ul.RoomCardGrid,
|
html[data-tm-thumb-scale-related="1"] .BaseRoomContents ul.RoomCardGrid,
|
||||||
html[data-tm-thumb-scale-related="1"] #main.roomPage ul.list:has(li.roomCard),
|
html[data-tm-thumb-scale-related="1"] #main.roomPage ul.list:has(li.roomCard),
|
||||||
html[data-tm-thumb-scale-related="1"] .BaseRoomContents ul.list:has(li.roomCard) {
|
html[data-tm-thumb-scale-related="1"] .BaseRoomContents ul.list:has(li.roomCard) {
|
||||||
display: grid !important;
|
display: grid !important;
|
||||||
grid-template-columns: repeat(auto-fill, minmax(var(--tm-thumb-related-width), 1fr)) !important;
|
grid-template-columns: repeat(auto-fill, var(--tm-thumb-related-width)) !important;
|
||||||
|
justify-content: start !important;
|
||||||
|
align-items: start !important;
|
||||||
gap: 0.6em 0.75em !important;
|
gap: 0.6em 0.75em !important;
|
||||||
}
|
}
|
||||||
html[data-tm-thumb-scale-related="1"] .BaseRoomContents ul.RoomCardGrid > li.RoomCard,
|
html[data-tm-thumb-scale-related="1"] .BaseRoomContents ul.RoomCardGrid > li.RoomCard,
|
||||||
html[data-tm-thumb-scale-related="1"] #main.roomPage ul.list:has(li.roomCard) li.roomCard,
|
html[data-tm-thumb-scale-related="1"] #main.roomPage ul.list:has(li.roomCard) li.roomCard,
|
||||||
html[data-tm-thumb-scale-related="1"] .BaseRoomContents ul.list:has(li.roomCard) li.roomCard {
|
html[data-tm-thumb-scale-related="1"] .BaseRoomContents ul.list:has(li.roomCard) li.roomCard {
|
||||||
width: auto !important;
|
width: var(--tm-thumb-related-width) !important;
|
||||||
|
justify-self: start !important;
|
||||||
min-width: 0 !important;
|
min-width: 0 !important;
|
||||||
max-width: none !important;
|
max-width: var(--tm-thumb-related-width) !important;
|
||||||
/* 卡片整体高度也要放大; 只放大缩略图高度时, 下方用户名/人数栏可能被压住. */
|
/* 卡片整体高度也要放大; 只放大缩略图高度时, 下方用户名/人数栏可能被压住. */
|
||||||
height: var(--tm-thumb-related-card-height) !important;
|
height: var(--tm-thumb-related-card-height) !important;
|
||||||
min-height: var(--tm-thumb-related-card-height) !important;
|
min-height: var(--tm-thumb-related-card-height) !important;
|
||||||
@@ -204,8 +211,7 @@
|
|||||||
html[data-tm-thumb-scale-related="1"] .BaseRoomContents ul.RoomCardGrid .RoomCardThumbnail,
|
html[data-tm-thumb-scale-related="1"] .BaseRoomContents ul.RoomCardGrid .RoomCardThumbnail,
|
||||||
html[data-tm-thumb-scale-related="1"] #main.roomPage ul.list:has(li.roomCard) .room_thumbnail_container,
|
html[data-tm-thumb-scale-related="1"] #main.roomPage ul.list:has(li.roomCard) .room_thumbnail_container,
|
||||||
html[data-tm-thumb-scale-related="1"] .BaseRoomContents ul.list:has(li.roomCard) .room_thumbnail_container {
|
html[data-tm-thumb-scale-related="1"] .BaseRoomContents ul.list:has(li.roomCard) .room_thumbnail_container {
|
||||||
/* --tm-thumb-related-thumb-width 来自原始缩略图宽度, 不直接复用卡片宽度. */
|
width: 100% !important;
|
||||||
width: var(--tm-thumb-related-thumb-width) !important;
|
|
||||||
/* --tm-thumb-related-height 来自原始缩略图容器高度. */
|
/* --tm-thumb-related-height 来自原始缩略图容器高度. */
|
||||||
height: var(--tm-thumb-related-height) !important;
|
height: var(--tm-thumb-related-height) !important;
|
||||||
display: block !important;
|
display: block !important;
|
||||||
@@ -217,8 +223,7 @@
|
|||||||
html[data-tm-thumb-scale-related="1"] #main.roomPage ul.list:has(li.roomCard) .room_thumbnail,
|
html[data-tm-thumb-scale-related="1"] #main.roomPage ul.list:has(li.roomCard) .room_thumbnail,
|
||||||
html[data-tm-thumb-scale-related="1"] .BaseRoomContents ul.list:has(li.roomCard) .room_thumbnail_container img,
|
html[data-tm-thumb-scale-related="1"] .BaseRoomContents ul.list:has(li.roomCard) .room_thumbnail_container img,
|
||||||
html[data-tm-thumb-scale-related="1"] .BaseRoomContents ul.list:has(li.roomCard) .room_thumbnail {
|
html[data-tm-thumb-scale-related="1"] .BaseRoomContents ul.list:has(li.roomCard) .room_thumbnail {
|
||||||
/* 图片宽度也按原始缩略图宽度放大, 避免卡片边框/间隙被算进图片宽度. */
|
width: 100% !important;
|
||||||
width: var(--tm-thumb-related-thumb-width) !important;
|
|
||||||
/* 图片和容器使用同一个高度, 避免图片溢出或下方信息栏错位. */
|
/* 图片和容器使用同一个高度, 避免图片溢出或下方信息栏错位. */
|
||||||
height: var(--tm-thumb-related-height) !important;
|
height: var(--tm-thumb-related-height) !important;
|
||||||
display: block !important;
|
display: block !important;
|
||||||
@@ -249,7 +254,9 @@
|
|||||||
html[data-tm-thumb-scale-follow="1"] .FollowedDropdown__rooms {
|
html[data-tm-thumb-scale-follow="1"] .FollowedDropdown__rooms {
|
||||||
display: grid !important;
|
display: grid !important;
|
||||||
/* 当前设计保持两列, 列宽来自原始卡片宽度 * 倍率. */
|
/* 当前设计保持两列, 列宽来自原始卡片宽度 * 倍率. */
|
||||||
grid-template-columns: repeat(2, minmax(var(--tm-thumb-follow-card-width), 1fr)) !important;
|
grid-template-columns: repeat(2, var(--tm-thumb-follow-card-width)) !important;
|
||||||
|
justify-content: start !important;
|
||||||
|
align-items: start !important;
|
||||||
grid-gap: 0.6em 0.75em !important;
|
grid-gap: 0.6em 0.75em !important;
|
||||||
}
|
}
|
||||||
html[data-tm-thumb-scale-follow="1"] .FollowedDropdown__room {
|
html[data-tm-thumb-scale-follow="1"] .FollowedDropdown__room {
|
||||||
@@ -266,7 +273,7 @@
|
|||||||
display: block !important;
|
display: block !important;
|
||||||
}
|
}
|
||||||
html[data-tm-thumb-scale-follow="1"] .FollowedDropdown__room-image {
|
html[data-tm-thumb-scale-follow="1"] .FollowedDropdown__room-image {
|
||||||
width: var(--tm-thumb-follow-thumb-width) !important;
|
width: 100% !important;
|
||||||
height: var(--tm-thumb-follow-thumb-height) !important;
|
height: var(--tm-thumb-follow-thumb-height) !important;
|
||||||
display: block !important;
|
display: block !important;
|
||||||
max-width: none !important;
|
max-width: none !important;
|
||||||
@@ -380,7 +387,7 @@
|
|||||||
let lastReport = null;
|
let lastReport = null;
|
||||||
// 最近一次尺寸探测结果, 控制台里排错主要看这个.
|
// 最近一次尺寸探测结果, 控制台里排错主要看这个.
|
||||||
let lastMeasure = null;
|
let lastMeasure = null;
|
||||||
// 模块锁: 某模块一旦成功应用缓存或探测值, 就不再重新探测.
|
// 模块锁: 某模块一旦成功应用探测值, 就不再重新探测.
|
||||||
const moduleReady = {
|
const moduleReady = {
|
||||||
home: false,
|
home: false,
|
||||||
followingList: false,
|
followingList: false,
|
||||||
@@ -403,6 +410,10 @@
|
|||||||
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 scaledCardHeightFromThumbWithScalePx = (cardHeight, thumbHeight, scale) => {
|
||||||
|
const nonThumbHeight = Math.max(0, cardHeight - thumbHeight);
|
||||||
|
return `${Math.round((thumbHeight * scale) + nonThumbHeight)}px`;
|
||||||
|
};
|
||||||
const rootStyle = () => document.documentElement && document.documentElement.style;
|
const rootStyle = () => document.documentElement && document.documentElement.style;
|
||||||
const isFollowingListPage = () => {
|
const isFollowingListPage = () => {
|
||||||
try {
|
try {
|
||||||
@@ -432,6 +443,37 @@
|
|||||||
style.setProperty(name, scaledCardHeightFromThumbPx(cardHeight, thumbHeight));
|
style.setProperty(name, scaledCardHeightFromThumbPx(cardHeight, thumbHeight));
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
const setListScaleVars = (columnsName, cardHeightName, thumbHeightName, metrics, cardWidth, cardHeight, thumbHeight) => {
|
||||||
|
const style = rootStyle();
|
||||||
|
if (
|
||||||
|
!style
|
||||||
|
|| !metrics
|
||||||
|
|| !Number.isFinite(metrics.columns)
|
||||||
|
|| !Number.isFinite(cardWidth)
|
||||||
|
|| !Number.isFinite(cardHeight)
|
||||||
|
|| !Number.isFinite(thumbHeight)
|
||||||
|
|| metrics.columns <= 0
|
||||||
|
|| cardWidth <= 0
|
||||||
|
|| cardHeight <= 0
|
||||||
|
|| thumbHeight <= 0
|
||||||
|
) return false;
|
||||||
|
const scaledColumns = Math.max(1, Math.floor(metrics.columns / THUMBNAIL_SCALE));
|
||||||
|
const targetCardWidth = (
|
||||||
|
Number.isFinite(metrics.width)
|
||||||
|
&& metrics.width > 0
|
||||||
|
&& Number.isFinite(metrics.columnGap)
|
||||||
|
&& metrics.columnGap >= 0
|
||||||
|
)
|
||||||
|
? (metrics.width - (metrics.columnGap * Math.max(0, scaledColumns - 1))) / scaledColumns
|
||||||
|
: null;
|
||||||
|
const effectiveScale = targetCardWidth && targetCardWidth > 0
|
||||||
|
? targetCardWidth / cardWidth
|
||||||
|
: THUMBNAIL_SCALE;
|
||||||
|
style.setProperty(columnsName, String(scaledColumns));
|
||||||
|
style.setProperty(cardHeightName, scaledCardHeightFromThumbWithScalePx(cardHeight, thumbHeight, effectiveScale));
|
||||||
|
style.setProperty(thumbHeightName, `${Math.round(thumbHeight * effectiveScale)}px`);
|
||||||
|
return true;
|
||||||
|
};
|
||||||
// 每个模块的 CSS 都由 html[data-tm-thumb-scale-模块名="1"] 控制.
|
// 每个模块的 CSS 都由 html[data-tm-thumb-scale-模块名="1"] 控制.
|
||||||
// 未探测到原始值时不设置开关, 对应模块完全不放大, 避免用错误尺寸猜页面.
|
// 未探测到原始值时不设置开关, 对应模块完全不放大, 避免用错误尺寸猜页面.
|
||||||
const setModuleReady = (name, ready) => {
|
const setModuleReady = (name, ready) => {
|
||||||
@@ -443,66 +485,21 @@
|
|||||||
} catch (_) {}
|
} catch (_) {}
|
||||||
};
|
};
|
||||||
const isRect = (value) => (
|
const isRect = (value) => (
|
||||||
// 缓存读取时做最低限度校验, 防止坏数据进入 CSS 变量.
|
|
||||||
value
|
value
|
||||||
&& Number.isFinite(value.width)
|
&& Number.isFinite(value.width)
|
||||||
&& Number.isFinite(value.height)
|
&& Number.isFinite(value.height)
|
||||||
&& value.width > 0
|
&& value.width > 0
|
||||||
&& value.height > 0
|
&& value.height > 0
|
||||||
);
|
);
|
||||||
const cloneRect = (value) => (isRect(value) ? {
|
|
||||||
// 缓存不需要亚像素无限精度, 保留两位小数足够复现布局.
|
|
||||||
width: Math.round(value.width * 100) / 100,
|
|
||||||
height: Math.round(value.height * 100) / 100,
|
|
||||||
} : null);
|
|
||||||
const readCache = () => {
|
|
||||||
try {
|
|
||||||
// localStorage 可能被浏览器策略禁用, 所以所有缓存操作都要 try/catch.
|
|
||||||
if (typeof localStorage === "undefined") return null;
|
|
||||||
// 缓存格式错误, 倍率不同, 结构版本不同, 都视为无缓存.
|
|
||||||
const parsed = JSON.parse(localStorage.getItem(CACHE_KEY) || "null");
|
|
||||||
if (
|
|
||||||
!parsed
|
|
||||||
|| parsed.schema !== CACHE_SCHEMA
|
|
||||||
|| parsed.scale !== THUMBNAIL_SCALE
|
|
||||||
|| parsed.cardHeightScale !== CARD_HEIGHT_SCALE
|
|
||||||
|| !parsed.modules
|
|
||||||
) return null;
|
|
||||||
return parsed;
|
|
||||||
} catch (_) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const writeCache = (cache) => {
|
|
||||||
try {
|
|
||||||
// 写入失败不影响脚本运行, 只是下次还会重新探测.
|
|
||||||
if (typeof localStorage === "undefined") return false;
|
|
||||||
localStorage.setItem(CACHE_KEY, JSON.stringify(cache));
|
|
||||||
return true;
|
|
||||||
} catch (_) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const updateCacheModule = (name, data) => {
|
|
||||||
// 模块级缓存: 发现页, 首页, 关注下拉等互不影响.
|
|
||||||
// 只更新当前模块, 保留其它模块已经探测好的原始尺寸.
|
|
||||||
const cache = readCache() || {
|
|
||||||
schema: CACHE_SCHEMA,
|
|
||||||
scale: THUMBNAIL_SCALE,
|
|
||||||
cardHeightScale: CARD_HEIGHT_SCALE,
|
|
||||||
updatedAt: 0,
|
|
||||||
modules: {},
|
|
||||||
};
|
|
||||||
cache.updatedAt = Date.now();
|
|
||||||
cache.modules[name] = data;
|
|
||||||
writeCache(cache);
|
|
||||||
};
|
|
||||||
const clearCache = () => {
|
const clearCache = () => {
|
||||||
try {
|
try {
|
||||||
// 油猴菜单调用这里; 清完后不强制刷新, 由用户自己刷新页面重新探测.
|
if (typeof localStorage !== "undefined") {
|
||||||
if (typeof localStorage !== "undefined") localStorage.removeItem(CACHE_KEY);
|
Object.keys(localStorage)
|
||||||
|
.filter((key) => key.indexOf(LEGACY_CACHE_PREFIX) === 0)
|
||||||
|
.forEach((key) => localStorage.removeItem(key));
|
||||||
|
}
|
||||||
} catch (_) {}
|
} catch (_) {}
|
||||||
log("cache cleared; refresh page to detect sizes again");
|
log("legacy cache cleared; current version always detects sizes fresh");
|
||||||
};
|
};
|
||||||
const registerMenu = () => {
|
const registerMenu = () => {
|
||||||
try {
|
try {
|
||||||
@@ -512,90 +509,6 @@
|
|||||||
}
|
}
|
||||||
} catch (_) {}
|
} catch (_) {}
|
||||||
};
|
};
|
||||||
const applyCachedModule = (name, data) => {
|
|
||||||
if (!data || moduleReady[name]) return false;
|
|
||||||
|
|
||||||
// 缓存命中时直接写 CSS 变量并打开模块开关.
|
|
||||||
// 这里仍然通过 setVar() 乘倍率, 因此缓存中始终保持原始尺寸.
|
|
||||||
if (name === "home" && !isFollowingListPage() && isRect(data.homeCard) && isRect(data.homeThumb)) {
|
|
||||||
moduleReady.home = [
|
|
||||||
setVar("--tm-thumb-home-width", data.homeCard.width),
|
|
||||||
setCardHeightFromThumbVar("--tm-thumb-home-card-height", data.homeCard.height, data.homeThumb.height),
|
|
||||||
setVar("--tm-thumb-home-thumb-height", data.homeThumb.height),
|
|
||||||
].every(Boolean);
|
|
||||||
} else if (name === "followingList" && isFollowingListPage() && isRect(data.followingListCard) && isRect(data.followingListThumb)) {
|
|
||||||
moduleReady.followingList = [
|
|
||||||
setVar("--tm-thumb-following-list-width", data.followingListCard.width),
|
|
||||||
setCardHeightFromThumbVar("--tm-thumb-following-list-card-height", data.followingListCard.height, data.followingListThumb.height),
|
|
||||||
setVar("--tm-thumb-following-list-thumb-height", data.followingListThumb.height),
|
|
||||||
].every(Boolean);
|
|
||||||
} else if (name === "related" && isRect(data.relatedCard) && isRect(data.relatedThumb)) {
|
|
||||||
const widthReady = setVar("--tm-thumb-related-width", data.relatedCard.width);
|
|
||||||
const cardHeightReady = setCardHeightVar("--tm-thumb-related-card-height", data.relatedCard.height);
|
|
||||||
const thumbWidthReady = setVar("--tm-thumb-related-thumb-width", data.relatedThumb.width);
|
|
||||||
const heightReady = setVar("--tm-thumb-related-height", data.relatedThumb.height);
|
|
||||||
moduleReady.related = widthReady && cardHeightReady && thumbWidthReady && heightReady;
|
|
||||||
} else if (name === "follow" && isRect(data.followCard) && isRect(data.followThumb)) {
|
|
||||||
const followReady = [
|
|
||||||
setVar("--tm-thumb-follow-card-width", data.followCard.width),
|
|
||||||
setCardHeightFromThumbVar("--tm-thumb-follow-card-height", data.followCard.height, data.followThumb.height),
|
|
||||||
setVar("--tm-thumb-follow-thumb-width", data.followThumb.width),
|
|
||||||
setVar("--tm-thumb-follow-thumb-height", data.followThumb.height),
|
|
||||||
].every(Boolean);
|
|
||||||
const style = rootStyle();
|
|
||||||
if (followReady && style) {
|
|
||||||
style.setProperty("--tm-thumb-follow-width", `calc(${Math.round(data.followCard.width * THUMBNAIL_SCALE * 2)}px + 2em)`);
|
|
||||||
}
|
|
||||||
moduleReady.follow = followReady;
|
|
||||||
} else if (name === "tooltip" && isRect(data.tooltipThumb)) {
|
|
||||||
moduleReady.tooltip = [
|
|
||||||
setVar("--tm-thumb-tooltip-width", data.tooltipThumb.width),
|
|
||||||
setVar("--tm-thumb-tooltip-height", data.tooltipThumb.height),
|
|
||||||
].every(Boolean);
|
|
||||||
} else if (
|
|
||||||
name === "discover"
|
|
||||||
&& isRect(data.discoverCard)
|
|
||||||
&& isRect(data.discoverThumb)
|
|
||||||
&& isRect(data.discoverTripleUl)
|
|
||||||
&& isRect(data.discoverTripleArrow)
|
|
||||||
&& isRect(data.discoverDoubleUl)
|
|
||||||
&& isRect(data.discoverDoubleArrow)
|
|
||||||
&& isRect(data.discoverSingleUl)
|
|
||||||
&& isRect(data.discoverSingleArrow)
|
|
||||||
) {
|
|
||||||
const ready = [
|
|
||||||
setVar("--tm-thumb-discover-width", data.discoverCard.width),
|
|
||||||
setCardHeightVar("--tm-thumb-discover-card-height", data.discoverCard.height),
|
|
||||||
setVar("--tm-thumb-discover-thumb-width", data.discoverThumb.width),
|
|
||||||
setVar("--tm-thumb-discover-height", data.discoverThumb.height),
|
|
||||||
setCardHeightVar("--tm-thumb-discover-triple-ul", data.discoverTripleUl.height),
|
|
||||||
setCardHeightVar("--tm-thumb-discover-triple-arrow", data.discoverTripleArrow.height),
|
|
||||||
setCardHeightVar("--tm-thumb-discover-double-ul", data.discoverDoubleUl.height),
|
|
||||||
setCardHeightVar("--tm-thumb-discover-double-arrow", data.discoverDoubleArrow.height),
|
|
||||||
setCardHeightVar("--tm-thumb-discover-single-ul", data.discoverSingleUl.height),
|
|
||||||
setCardHeightVar("--tm-thumb-discover-single-arrow", data.discoverSingleArrow.height),
|
|
||||||
];
|
|
||||||
moduleReady.discover = ready.every(Boolean);
|
|
||||||
}
|
|
||||||
|
|
||||||
setModuleReady(name, moduleReady[name]);
|
|
||||||
return moduleReady[name];
|
|
||||||
};
|
|
||||||
const applyCachedSizes = () => {
|
|
||||||
const cache = readCache();
|
|
||||||
if (!cache) return false;
|
|
||||||
const modules = cache.modules || {};
|
|
||||||
const applied = {
|
|
||||||
home: applyCachedModule("home", modules.home),
|
|
||||||
followingList: applyCachedModule("followingList", modules.followingList),
|
|
||||||
related: applyCachedModule("related", modules.related),
|
|
||||||
follow: applyCachedModule("follow", modules.follow),
|
|
||||||
tooltip: applyCachedModule("tooltip", modules.tooltip),
|
|
||||||
discover: applyCachedModule("discover", modules.discover),
|
|
||||||
};
|
|
||||||
if (DEBUG) log("cache applied", applied);
|
|
||||||
return Object.values(applied).some(Boolean);
|
|
||||||
};
|
|
||||||
const rectOf = (el) => {
|
const rectOf = (el) => {
|
||||||
// getBoundingClientRect 能拿到 CSS 布局后的实际渲染尺寸.
|
// getBoundingClientRect 能拿到 CSS 布局后的实际渲染尺寸.
|
||||||
if (!el || !el.getBoundingClientRect) return null;
|
if (!el || !el.getBoundingClientRect) return null;
|
||||||
@@ -618,24 +531,117 @@
|
|||||||
} catch (_) {}
|
} catch (_) {}
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
const firstElement = (selector) => {
|
||||||
|
try {
|
||||||
|
if (!document.querySelector) return null;
|
||||||
|
return document.querySelector(selector);
|
||||||
|
} catch (_) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const parseMinmaxPx = (value) => {
|
||||||
|
if (!value) return null;
|
||||||
|
const match = String(value).match(/minmax\(\s*([0-9.]+)px\s*,\s*1fr\s*\)/i);
|
||||||
|
if (!match) return null;
|
||||||
|
const width = Number.parseFloat(match[1]);
|
||||||
|
return Number.isFinite(width) && width > 0 ? width : null;
|
||||||
|
};
|
||||||
|
const selectorMatches = (el, selectorText) => {
|
||||||
|
try {
|
||||||
|
return !!(el && selectorText && el.matches && el.matches(selectorText));
|
||||||
|
} catch (_) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const ruleGridMinColumn = (el, rules) => {
|
||||||
|
if (!el || !rules) return null;
|
||||||
|
for (const rule of rules) {
|
||||||
|
if (rule && rule.cssRules) {
|
||||||
|
const nested = ruleGridMinColumn(el, rule.cssRules);
|
||||||
|
if (nested) return nested;
|
||||||
|
}
|
||||||
|
if (!rule || !rule.style || !rule.selectorText) continue;
|
||||||
|
if (!selectorMatches(el, rule.selectorText)) continue;
|
||||||
|
const value = rule.style.getPropertyValue("grid-template-columns");
|
||||||
|
const width = parseMinmaxPx(value);
|
||||||
|
if (width) return width;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
const gridMinColumnFor = (selector) => {
|
||||||
|
const el = firstElement(selector);
|
||||||
|
if (!el || !document.styleSheets) return null;
|
||||||
|
for (const sheet of Array.from(document.styleSheets)) {
|
||||||
|
let rules = null;
|
||||||
|
try {
|
||||||
|
rules = sheet.cssRules;
|
||||||
|
} catch (_) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const width = ruleGridMinColumn(el, rules);
|
||||||
|
if (width) return width;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
const computedGridColumnCount = (selector) => {
|
||||||
|
const el = firstElement(selector);
|
||||||
|
if (!el) return null;
|
||||||
|
try {
|
||||||
|
const value = getComputedStyle(el).getPropertyValue("grid-template-columns");
|
||||||
|
const count = String(value).split(/\s+/).filter(Boolean).length;
|
||||||
|
return Number.isFinite(count) && count > 0 ? count : null;
|
||||||
|
} catch (_) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const naturalGridMetrics = (selector) => {
|
||||||
|
const minColumn = gridMinColumnFor(selector);
|
||||||
|
const el = firstElement(selector);
|
||||||
|
const rect = rectOf(el);
|
||||||
|
let columnGap = 0;
|
||||||
|
try {
|
||||||
|
if (el && typeof getComputedStyle === "function") {
|
||||||
|
const styles = getComputedStyle(el);
|
||||||
|
const parsedGap = Number.parseFloat(styles.columnGap || styles.gap || "0");
|
||||||
|
columnGap = Number.isFinite(parsedGap) && parsedGap > 0 ? parsedGap : 0;
|
||||||
|
}
|
||||||
|
} catch (_) {}
|
||||||
|
if (Number.isFinite(minColumn) && minColumn > 0 && rect && rect.width > 0) {
|
||||||
|
return {
|
||||||
|
columns: Math.max(1, Math.floor((rect.width + columnGap) / (minColumn + columnGap))),
|
||||||
|
width: rect.width,
|
||||||
|
columnGap,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const columns = computedGridColumnCount(selector);
|
||||||
|
return Number.isFinite(columns) && columns > 0 ? {
|
||||||
|
columns,
|
||||||
|
width: rect && rect.width,
|
||||||
|
columnGap,
|
||||||
|
} : null;
|
||||||
|
};
|
||||||
const detectAndApplySizes = (stage = "detect") => {
|
const detectAndApplySizes = (stage = "detect") => {
|
||||||
/*
|
/*
|
||||||
* 探测策略:
|
* 探测策略:
|
||||||
*
|
*
|
||||||
* 1) CSS 已经注入, 但各模块默认关闭, 所以页面先按站点原始布局渲染.
|
* 1) CSS 已经注入, 但各模块默认关闭, 所以页面先按站点原始布局渲染.
|
||||||
* 2) 延迟/MutationObserver 触发后, 读取还没 ready 的模块尺寸.
|
* 2) 延迟/MutationObserver 触发后, 读取还没 ready 的模块尺寸.
|
||||||
* 3) 某个模块探测成功后, 写入 CSS 变量, 打开模块开关, 写入缓存, 并把 moduleReady 锁住.
|
* 3) 某个模块探测成功后, 写入 CSS 变量, 打开模块开关, 并把 moduleReady 锁住.
|
||||||
* 4) 锁住后的模块后续不再探测, 避免把已放大的尺寸再次当成原始尺寸.
|
* 4) 锁住后的模块后续不再探测, 避免把已放大的尺寸再次当成原始尺寸.
|
||||||
*/
|
*/
|
||||||
const followingListPage = isFollowingListPage();
|
const followingListPage = isFollowingListPage();
|
||||||
|
const homeMetrics = moduleReady.home || followingListPage ? null : naturalGridMetrics("#roomlist_root ul.RoomCardGrid, #roomlist_root ul.list:has(li.roomCard)");
|
||||||
|
const followingListMetrics = moduleReady.followingList || !followingListPage ? null : naturalGridMetrics("#roomlist_root ul.RoomCardGrid, #roomlist_root ul.list:has(li.roomCard)");
|
||||||
const measured = {
|
const measured = {
|
||||||
// 首页普通房间列表: 卡片宽高 + 缩略图宽高四项独立探测.
|
// 首页普通房间列表: 列宽来自站点 CSS 的 minmax 最小值, 避免读取到 1fr 拉伸后的当前渲染宽度.
|
||||||
|
homeMetrics,
|
||||||
homeCard: moduleReady.home || followingListPage ? null : firstRect("#roomlist_root li.RoomCard, #roomlist_root li.roomCard"),
|
homeCard: moduleReady.home || followingListPage ? null : firstRect("#roomlist_root li.RoomCard, #roomlist_root li.roomCard"),
|
||||||
homeThumb: moduleReady.home || followingListPage ? null : firstRect("#roomlist_root .RoomCardThumbnail, #roomlist_root .room_thumbnail_container"),
|
homeThumb: moduleReady.home || followingListPage ? null : firstRect("#roomlist_root .RoomCardThumbnail, #roomlist_root .room_thumbnail_container"),
|
||||||
// 关注页房间列表: 选择器和首页相似, 但独立探测, 独立缓存, 独立 CSS 变量.
|
// 关注页房间列表: 同样必须读 CSS 最小列宽, 否则会把已拉伸宽度再乘倍率.
|
||||||
|
followingListMetrics,
|
||||||
followingListCard: moduleReady.followingList || !followingListPage ? null : firstRect("#roomlist_root li.RoomCard, #roomlist_root li.roomCard"),
|
followingListCard: moduleReady.followingList || !followingListPage ? null : firstRect("#roomlist_root li.RoomCard, #roomlist_root li.roomCard"),
|
||||||
followingListThumb: moduleReady.followingList || !followingListPage ? null : firstRect("#roomlist_root .RoomCardThumbnail, #roomlist_root .room_thumbnail_container"),
|
followingListThumb: moduleReady.followingList || !followingListPage ? null : firstRect("#roomlist_root .RoomCardThumbnail, #roomlist_root .room_thumbnail_container"),
|
||||||
// 频道页"更多这样的房间": 卡片宽高和缩略图宽高都要探测, 否则放大后行高容易不齐.
|
// 频道页"更多这样的房间": 使用局部推荐区自己的卡片原始宽度和高度, 不套用首页列数算法.
|
||||||
relatedCard: moduleReady.related ? null : firstRect(".BaseRoomContents ul.RoomCardGrid > li.RoomCard, #main.roomPage ul.list:has(li.roomCard) li.roomCard, .BaseRoomContents ul.list:has(li.roomCard) li.roomCard"),
|
relatedCard: moduleReady.related ? null : firstRect(".BaseRoomContents ul.RoomCardGrid > li.RoomCard, #main.roomPage ul.list:has(li.roomCard) li.roomCard, .BaseRoomContents ul.list:has(li.roomCard) li.roomCard"),
|
||||||
relatedThumb: moduleReady.related ? null : firstRect(".BaseRoomContents ul.RoomCardGrid .RoomCardThumbnail, #main.roomPage ul.list:has(li.roomCard) .room_thumbnail_container, .BaseRoomContents ul.list:has(li.roomCard) .room_thumbnail_container"),
|
relatedThumb: moduleReady.related ? null : firstRect(".BaseRoomContents ul.RoomCardGrid .RoomCardThumbnail, #main.roomPage ul.list:has(li.roomCard) .room_thumbnail_container, .BaseRoomContents ul.list:has(li.roomCard) .room_thumbnail_container"),
|
||||||
// 顶部"关注"弹窗: 通常弹出后才有 DOM, 靠 mutation 触发探测.
|
// 顶部"关注"弹窗: 通常弹出后才有 DOM, 靠 mutation 触发探测.
|
||||||
@@ -656,51 +662,41 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (!moduleReady.home && !followingListPage) {
|
if (!moduleReady.home && !followingListPage) {
|
||||||
// home 依赖 card/thumb 各自宽高; 成功后立刻缓存, 后续普通列表页面可直接套用.
|
// home 依赖当前页面的自然列数和原始高度; 每次加载重新探测.
|
||||||
moduleReady.home = [
|
moduleReady.home = setListScaleVars(
|
||||||
setVar("--tm-thumb-home-width", measured.homeCard && measured.homeCard.width),
|
"--tm-thumb-home-columns",
|
||||||
setCardHeightFromThumbVar("--tm-thumb-home-card-height", measured.homeCard && measured.homeCard.height, measured.homeThumb && measured.homeThumb.height),
|
"--tm-thumb-home-card-height",
|
||||||
setVar("--tm-thumb-home-thumb-height", measured.homeThumb && measured.homeThumb.height),
|
"--tm-thumb-home-thumb-height",
|
||||||
].every(Boolean);
|
measured.homeMetrics,
|
||||||
|
measured.homeCard && measured.homeCard.width,
|
||||||
|
measured.homeCard && measured.homeCard.height,
|
||||||
|
measured.homeThumb && measured.homeThumb.height,
|
||||||
|
);
|
||||||
setModuleReady("home", moduleReady.home);
|
setModuleReady("home", moduleReady.home);
|
||||||
if (moduleReady.home) {
|
|
||||||
updateCacheModule("home", {
|
|
||||||
homeCard: cloneRect(measured.homeCard),
|
|
||||||
homeThumb: cloneRect(measured.homeThumb),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!moduleReady.followingList && followingListPage) {
|
if (!moduleReady.followingList && followingListPage) {
|
||||||
// followingList 单独缓存, 避免关注页拿到首页的原始宽度.
|
// followingList 单独探测, 避免关注页拿到首页的列数.
|
||||||
moduleReady.followingList = [
|
moduleReady.followingList = setListScaleVars(
|
||||||
setVar("--tm-thumb-following-list-width", measured.followingListCard && measured.followingListCard.width),
|
"--tm-thumb-following-list-columns",
|
||||||
setCardHeightFromThumbVar("--tm-thumb-following-list-card-height", measured.followingListCard && measured.followingListCard.height, measured.followingListThumb && measured.followingListThumb.height),
|
"--tm-thumb-following-list-card-height",
|
||||||
setVar("--tm-thumb-following-list-thumb-height", measured.followingListThumb && measured.followingListThumb.height),
|
"--tm-thumb-following-list-thumb-height",
|
||||||
].every(Boolean);
|
measured.followingListMetrics,
|
||||||
|
measured.followingListCard && measured.followingListCard.width,
|
||||||
|
measured.followingListCard && measured.followingListCard.height,
|
||||||
|
measured.followingListThumb && measured.followingListThumb.height,
|
||||||
|
);
|
||||||
setModuleReady("followingList", moduleReady.followingList);
|
setModuleReady("followingList", moduleReady.followingList);
|
||||||
if (moduleReady.followingList) {
|
|
||||||
updateCacheModule("followingList", {
|
|
||||||
followingListCard: cloneRect(measured.followingListCard),
|
|
||||||
followingListThumb: cloneRect(measured.followingListThumb),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!moduleReady.related) {
|
if (!moduleReady.related) {
|
||||||
// related 同时依赖卡片宽度, 卡片高度, 缩略图宽度和缩略图高度; 四者缺一不可.
|
// related 同时依赖卡片宽度, 卡片高度和缩略图高度; 三者缺一不可.
|
||||||
const relatedWidthReady = setVar("--tm-thumb-related-width", measured.relatedCard && measured.relatedCard.width);
|
moduleReady.related = [
|
||||||
const relatedCardHeightReady = setCardHeightVar("--tm-thumb-related-card-height", measured.relatedCard && measured.relatedCard.height);
|
setVar("--tm-thumb-related-width", measured.relatedCard && measured.relatedCard.width),
|
||||||
const relatedThumbWidthReady = setVar("--tm-thumb-related-thumb-width", measured.relatedThumb && measured.relatedThumb.width);
|
setCardHeightFromThumbVar("--tm-thumb-related-card-height", measured.relatedCard && measured.relatedCard.height, measured.relatedThumb && measured.relatedThumb.height),
|
||||||
const relatedHeightReady = setVar("--tm-thumb-related-height", measured.relatedThumb && measured.relatedThumb.height);
|
setVar("--tm-thumb-related-height", measured.relatedThumb && measured.relatedThumb.height),
|
||||||
moduleReady.related = relatedWidthReady && relatedCardHeightReady && relatedThumbWidthReady && relatedHeightReady;
|
].every(Boolean);
|
||||||
setModuleReady("related", moduleReady.related);
|
setModuleReady("related", moduleReady.related);
|
||||||
if (moduleReady.related) {
|
|
||||||
updateCacheModule("related", {
|
|
||||||
relatedCard: cloneRect(measured.relatedCard),
|
|
||||||
relatedThumb: cloneRect(measured.relatedThumb),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!moduleReady.follow) {
|
if (!moduleReady.follow) {
|
||||||
@@ -708,7 +704,6 @@
|
|||||||
const followReady = [
|
const followReady = [
|
||||||
setVar("--tm-thumb-follow-card-width", measured.followCard && measured.followCard.width),
|
setVar("--tm-thumb-follow-card-width", measured.followCard && measured.followCard.width),
|
||||||
setCardHeightFromThumbVar("--tm-thumb-follow-card-height", measured.followCard && measured.followCard.height, measured.followThumb && measured.followThumb.height),
|
setCardHeightFromThumbVar("--tm-thumb-follow-card-height", measured.followCard && measured.followCard.height, measured.followThumb && measured.followThumb.height),
|
||||||
setVar("--tm-thumb-follow-thumb-width", measured.followThumb && measured.followThumb.width),
|
|
||||||
setVar("--tm-thumb-follow-thumb-height", measured.followThumb && measured.followThumb.height),
|
setVar("--tm-thumb-follow-thumb-height", measured.followThumb && measured.followThumb.height),
|
||||||
].every(Boolean);
|
].every(Boolean);
|
||||||
moduleReady.follow = followReady;
|
moduleReady.follow = followReady;
|
||||||
@@ -717,12 +712,6 @@
|
|||||||
style.setProperty("--tm-thumb-follow-width", `calc(${Math.round(measured.followCard.width * THUMBNAIL_SCALE * 2)}px + 2em)`);
|
style.setProperty("--tm-thumb-follow-width", `calc(${Math.round(measured.followCard.width * THUMBNAIL_SCALE * 2)}px + 2em)`);
|
||||||
}
|
}
|
||||||
setModuleReady("follow", moduleReady.follow);
|
setModuleReady("follow", moduleReady.follow);
|
||||||
if (moduleReady.follow) {
|
|
||||||
updateCacheModule("follow", {
|
|
||||||
followCard: cloneRect(measured.followCard),
|
|
||||||
followThumb: cloneRect(measured.followThumb),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!moduleReady.tooltip) {
|
if (!moduleReady.tooltip) {
|
||||||
@@ -732,9 +721,6 @@
|
|||||||
setVar("--tm-thumb-tooltip-height", measured.tooltipThumb && measured.tooltipThumb.height),
|
setVar("--tm-thumb-tooltip-height", measured.tooltipThumb && measured.tooltipThumb.height),
|
||||||
].every(Boolean);
|
].every(Boolean);
|
||||||
setModuleReady("tooltip", moduleReady.tooltip);
|
setModuleReady("tooltip", moduleReady.tooltip);
|
||||||
if (moduleReady.tooltip) {
|
|
||||||
updateCacheModule("tooltip", { tooltipThumb: cloneRect(measured.tooltipThumb) });
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!moduleReady.discover) {
|
if (!moduleReady.discover) {
|
||||||
@@ -754,18 +740,6 @@
|
|||||||
&& discoverDoubleUlReady && discoverDoubleArrowReady
|
&& discoverDoubleUlReady && discoverDoubleArrowReady
|
||||||
&& discoverSingleUlReady && discoverSingleArrowReady;
|
&& discoverSingleUlReady && discoverSingleArrowReady;
|
||||||
setModuleReady("discover", moduleReady.discover);
|
setModuleReady("discover", moduleReady.discover);
|
||||||
if (moduleReady.discover) {
|
|
||||||
updateCacheModule("discover", {
|
|
||||||
discoverCard: cloneRect(measured.discoverCard),
|
|
||||||
discoverThumb: cloneRect(measured.discoverThumb),
|
|
||||||
discoverTripleUl: cloneRect(measured.discoverTripleUl),
|
|
||||||
discoverTripleArrow: cloneRect(measured.discoverTripleArrow),
|
|
||||||
discoverDoubleUl: cloneRect(measured.discoverDoubleUl),
|
|
||||||
discoverDoubleArrow: cloneRect(measured.discoverDoubleArrow),
|
|
||||||
discoverSingleUl: cloneRect(measured.discoverSingleUl),
|
|
||||||
discoverSingleArrow: cloneRect(measured.discoverSingleArrow),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
lastMeasure = { stage, moduleReady: { ...moduleReady }, measured };
|
lastMeasure = { stage, moduleReady: { ...moduleReady }, measured };
|
||||||
@@ -850,35 +824,22 @@
|
|||||||
injectCount,
|
injectCount,
|
||||||
lastInjectMethod,
|
lastInjectMethod,
|
||||||
cssLength: css.length,
|
cssLength: css.length,
|
||||||
cache: (() => {
|
cache: "disabled",
|
||||||
const cache = readCache();
|
|
||||||
return cache ? {
|
|
||||||
schema: cache.schema,
|
|
||||||
scale: cache.scale,
|
|
||||||
cardHeightScale: cache.cardHeightScale,
|
|
||||||
updatedAt: cache.updatedAt,
|
|
||||||
modules: Object.keys(cache.modules || {}),
|
|
||||||
} : null;
|
|
||||||
})(),
|
|
||||||
cssVars: (() => {
|
cssVars: (() => {
|
||||||
try {
|
try {
|
||||||
const style = getComputedStyle(document.documentElement);
|
const style = getComputedStyle(document.documentElement);
|
||||||
return {
|
return {
|
||||||
homeWidth: style.getPropertyValue("--tm-thumb-home-width").trim(),
|
homeColumns: style.getPropertyValue("--tm-thumb-home-columns").trim(),
|
||||||
homeCardHeight: style.getPropertyValue("--tm-thumb-home-card-height").trim(),
|
homeCardHeight: style.getPropertyValue("--tm-thumb-home-card-height").trim(),
|
||||||
homeThumbWidth: style.getPropertyValue("--tm-thumb-home-thumb-width").trim(),
|
|
||||||
homeThumbHeight: style.getPropertyValue("--tm-thumb-home-thumb-height").trim(),
|
homeThumbHeight: style.getPropertyValue("--tm-thumb-home-thumb-height").trim(),
|
||||||
followingListWidth: style.getPropertyValue("--tm-thumb-following-list-width").trim(),
|
followingListColumns: style.getPropertyValue("--tm-thumb-following-list-columns").trim(),
|
||||||
followingListCardHeight: style.getPropertyValue("--tm-thumb-following-list-card-height").trim(),
|
followingListCardHeight: style.getPropertyValue("--tm-thumb-following-list-card-height").trim(),
|
||||||
followingListThumbWidth: style.getPropertyValue("--tm-thumb-following-list-thumb-width").trim(),
|
|
||||||
followingListThumbHeight: style.getPropertyValue("--tm-thumb-following-list-thumb-height").trim(),
|
followingListThumbHeight: style.getPropertyValue("--tm-thumb-following-list-thumb-height").trim(),
|
||||||
relatedWidth: style.getPropertyValue("--tm-thumb-related-width").trim(),
|
relatedWidth: style.getPropertyValue("--tm-thumb-related-width").trim(),
|
||||||
relatedCardHeight: style.getPropertyValue("--tm-thumb-related-card-height").trim(),
|
relatedCardHeight: style.getPropertyValue("--tm-thumb-related-card-height").trim(),
|
||||||
relatedThumbWidth: style.getPropertyValue("--tm-thumb-related-thumb-width").trim(),
|
|
||||||
relatedHeight: style.getPropertyValue("--tm-thumb-related-height").trim(),
|
relatedHeight: style.getPropertyValue("--tm-thumb-related-height").trim(),
|
||||||
followWidth: style.getPropertyValue("--tm-thumb-follow-width").trim(),
|
followWidth: style.getPropertyValue("--tm-thumb-follow-width").trim(),
|
||||||
followCardHeight: style.getPropertyValue("--tm-thumb-follow-card-height").trim(),
|
followCardHeight: style.getPropertyValue("--tm-thumb-follow-card-height").trim(),
|
||||||
followThumbWidth: style.getPropertyValue("--tm-thumb-follow-thumb-width").trim(),
|
|
||||||
followThumbHeight: style.getPropertyValue("--tm-thumb-follow-thumb-height").trim(),
|
followThumbHeight: style.getPropertyValue("--tm-thumb-follow-thumb-height").trim(),
|
||||||
discoverWidth: style.getPropertyValue("--tm-thumb-discover-width").trim(),
|
discoverWidth: style.getPropertyValue("--tm-thumb-discover-width").trim(),
|
||||||
discoverCardHeight: style.getPropertyValue("--tm-thumb-discover-card-height").trim(),
|
discoverCardHeight: style.getPropertyValue("--tm-thumb-discover-card-height").trim(),
|
||||||
@@ -1017,13 +978,11 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
log("start v" + VER);
|
log("start v" + VER);
|
||||||
// 注册油猴菜单; 用户需要重测布局时, 可从菜单清除 localStorage 缓存.
|
// 注册油猴菜单; 只用于清除旧版本遗留的 localStorage 缓存.
|
||||||
registerMenu();
|
registerMenu();
|
||||||
// 尽早尝试应用缓存.缓存命中的模块会立即设置 CSS 变量和 data 开关.
|
|
||||||
applyCachedSizes();
|
|
||||||
// 暴露调试 API, 方便后续在控制台手动检查.
|
// 暴露调试 API, 方便后续在控制台手动检查.
|
||||||
exposeDebugApi();
|
exposeDebugApi();
|
||||||
// 第一次报告: 记录启动时是否有缓存, CSS 变量是否已经设置.
|
// 第一次报告: 记录启动时 CSS 变量是否已经设置.
|
||||||
reportDiagnostics("start-before-inject");
|
reportDiagnostics("start-before-inject");
|
||||||
|
|
||||||
// 注入 CSS.因为模块默认关闭, 即使 CSS 很早注入, 也不会改变原始布局.
|
// 注入 CSS.因为模块默认关闭, 即使 CSS 很早注入, 也不会改变原始布局.
|
||||||
@@ -1049,7 +1008,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (typeof setTimeout === "function") {
|
if (typeof setTimeout === "function") {
|
||||||
// 固定时间点探测用于覆盖: 缓存未命中, React 首屏慢, 图片容器稍后才出现等情况.
|
// 固定时间点探测用于覆盖: React 首屏慢, 图片容器稍后才出现等情况.
|
||||||
setTimeout(() => { scheduleMeasure("after-800ms"); reportDiagnostics("after-800ms"); startPageObserver(); }, 800);
|
setTimeout(() => { scheduleMeasure("after-800ms"); reportDiagnostics("after-800ms"); startPageObserver(); }, 800);
|
||||||
// 第二次探测给慢一点的页面留余量.
|
// 第二次探测给慢一点的页面留余量.
|
||||||
setTimeout(() => { scheduleMeasure("after-2000ms"); reportDiagnostics("after-2000ms"); startPageObserver(); }, 2000);
|
setTimeout(() => { scheduleMeasure("after-2000ms"); reportDiagnostics("after-2000ms"); startPageObserver(); }, 2000);
|
||||||
|
|||||||
@@ -86,39 +86,44 @@ assert.match(
|
|||||||
);
|
);
|
||||||
assert.match(
|
assert.match(
|
||||||
capturedCss,
|
capturedCss,
|
||||||
/data-tm-thumb-scale-following-list="1"[\s\S]*--tm-thumb-following-list-width/,
|
/data-tm-thumb-scale-following-list="1"[\s\S]*--tm-thumb-following-list-columns/,
|
||||||
"followed-cams list should be separated from homepage list sizing",
|
"followed-cams list should be separated from homepage list column count",
|
||||||
);
|
);
|
||||||
assert.match(
|
assert.match(
|
||||||
capturedCss,
|
capturedCss,
|
||||||
/data-tm-thumb-scale-following-list="1"[\s\S]*grid-template-columns:\s*repeat\(auto-fill,\s*minmax\(var\(--tm-thumb-following-list-width\),\s*1fr\)\)\s*!important/,
|
/data-tm-thumb-scale-following-list="1"[\s\S]*grid-template-columns:\s*repeat\(var\(--tm-thumb-following-list-columns\),\s*minmax\(0,\s*1fr\)\)\s*!important/,
|
||||||
"followed-cams list should keep the site's stretching grid alignment while using detected minimum width",
|
"followed-cams list should reduce the original column count and keep 1fr alignment",
|
||||||
);
|
);
|
||||||
assert.match(
|
assert.match(
|
||||||
capturedCss,
|
capturedCss,
|
||||||
/#main\.roomPage\s+ul\.list:has\(li\.roomCard\)\s+\.room_thumbnail_container[\s\S]*width:\s*var\(--tm-thumb-related-thumb-width\)\s*!important[\s\S]*height:\s*var\(--tm-thumb-related-height\)\s*!important/,
|
/#main\.roomPage\s+ul\.list:has\(li\.roomCard\)\s+\.room_thumbnail_container[\s\S]*width:\s*100%\s*!important[\s\S]*height:\s*var\(--tm-thumb-related-height\)\s*!important/,
|
||||||
"room page related rooms thumbnail containers should use detected thumb width and height",
|
"room page related rooms thumbnail containers should follow card width and use detected height",
|
||||||
);
|
);
|
||||||
assert.match(
|
assert.match(
|
||||||
capturedCss,
|
capturedCss,
|
||||||
/\.BaseRoomContents\s+ul\.list:has\(li\.roomCard\)\s+\.room_thumbnail[\s\S]*width:\s*var\(--tm-thumb-related-thumb-width\)\s*!important[\s\S]*height:\s*var\(--tm-thumb-related-height\)\s*!important/,
|
/\.BaseRoomContents\s+ul\.list:has\(li\.roomCard\)\s+\.room_thumbnail[\s\S]*width:\s*100%\s*!important[\s\S]*height:\s*var\(--tm-thumb-related-height\)\s*!important/,
|
||||||
"base room related thumbnails should use detected thumb width and height",
|
"base room related thumbnails should follow card width and use detected height",
|
||||||
);
|
);
|
||||||
assert.match(
|
assert.match(
|
||||||
capturedCss,
|
capturedCss,
|
||||||
/\.BaseRoomContents\s+ul\.RoomCardGrid[\s\S]*grid-template-columns:\s*repeat\(auto-fill,\s*minmax\(var\(--tm-thumb-related-width\),\s*1fr\)\)\s*!important/,
|
/\.BaseRoomContents\s+ul\.RoomCardGrid[\s\S]*grid-template-columns:\s*repeat\(auto-fill,\s*var\(--tm-thumb-related-width\)\)\s*!important/,
|
||||||
"base room RoomCardGrid related rooms should use detected width",
|
"base room RoomCardGrid related rooms should use detected card width",
|
||||||
);
|
);
|
||||||
assert.match(
|
assert.match(
|
||||||
capturedCss,
|
capturedCss,
|
||||||
/\.BaseRoomContents\s+ul\.RoomCardGrid\s+\.RoomCardThumbnail[\s\S]*width:\s*var\(--tm-thumb-related-thumb-width\)\s*!important[\s\S]*height:\s*var\(--tm-thumb-related-height\)\s*!important/,
|
/\.BaseRoomContents\s+ul\.RoomCardGrid\s+\.RoomCardThumbnail[\s\S]*width:\s*100%\s*!important[\s\S]*height:\s*var\(--tm-thumb-related-height\)\s*!important/,
|
||||||
"base room RoomCardGrid thumbnails should use detected thumb width and height",
|
"base room RoomCardGrid thumbnails should follow card width and use detected height",
|
||||||
);
|
);
|
||||||
assert.match(
|
assert.match(
|
||||||
capturedCss,
|
capturedCss,
|
||||||
/\.BaseRoomContents\s+ul\.RoomCardGrid\s*>\s*li\.RoomCard[\s\S]*height:\s*var\(--tm-thumb-related-card-height\)\s*!important/,
|
/\.BaseRoomContents\s+ul\.RoomCardGrid\s*>\s*li\.RoomCard[\s\S]*height:\s*var\(--tm-thumb-related-card-height\)\s*!important/,
|
||||||
"base room RoomCardGrid related cards should use detected card height",
|
"base room RoomCardGrid related cards should use detected card height",
|
||||||
);
|
);
|
||||||
|
assert.match(
|
||||||
|
capturedCss,
|
||||||
|
/\.BaseRoomContents\s+ul\.RoomCardGrid\s*>\s*li\.RoomCard[\s\S]*width:\s*var\(--tm-thumb-related-width\)\s*!important/,
|
||||||
|
"base room RoomCardGrid related cards should use detected card width",
|
||||||
|
);
|
||||||
assert.doesNotMatch(capturedCss, /--tm-thumb-min-root:\s*\d+px;/, "script should not hard-code a root thumbnail fallback width");
|
assert.doesNotMatch(capturedCss, /--tm-thumb-min-root:\s*\d+px;/, "script should not hard-code a root thumbnail fallback width");
|
||||||
assert.doesNotMatch(capturedCss, /--tm-thumb-height-root:\s*\d+px;/, "script should not hard-code a root thumbnail fallback height");
|
assert.doesNotMatch(capturedCss, /--tm-thumb-height-root:\s*\d+px;/, "script should not hard-code a root thumbnail fallback height");
|
||||||
assert.match(
|
assert.match(
|
||||||
@@ -153,8 +158,8 @@ assert.match(
|
|||||||
);
|
);
|
||||||
assert.match(
|
assert.match(
|
||||||
capturedCss,
|
capturedCss,
|
||||||
/\.FollowedDropdown__room-image[\s\S]*width:\s*var\(--tm-thumb-follow-thumb-width\)\s*!important[\s\S]*height:\s*var\(--tm-thumb-follow-thumb-height\)\s*!important/,
|
/\.FollowedDropdown__room-image[\s\S]*width:\s*100%\s*!important[\s\S]*height:\s*var\(--tm-thumb-follow-thumb-height\)\s*!important/,
|
||||||
"follow dropdown images should use detected original thumb width and height",
|
"follow dropdown images should follow fixed card width and use detected height",
|
||||||
);
|
);
|
||||||
assert.match(
|
assert.match(
|
||||||
capturedCss,
|
capturedCss,
|
||||||
@@ -169,11 +174,10 @@ assert.match(
|
|||||||
assert.doesNotMatch(source, /withOwnStyleDisabled/, "script should not disable its own style while measuring");
|
assert.doesNotMatch(source, /withOwnStyleDisabled/, "script should not disable its own style while measuring");
|
||||||
assert.match(source, /detectAndApplySizes/, "script should detect original sizes before applying scaled variables");
|
assert.match(source, /detectAndApplySizes/, "script should detect original sizes before applying scaled variables");
|
||||||
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, /CACHE_KEY/, "script should cache detected original sizes");
|
|
||||||
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, /localStorage\.setItem\(CACHE_KEY/, "script should save detected sizes in localStorage");
|
assert.doesNotMatch(source, /localStorage\.setItem/, "script should not write detected sizes to localStorage");
|
||||||
assert.match(source, /localStorage\.removeItem\(CACHE_KEY/, "script should clear cached sizes from the menu command");
|
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");
|
||||||
assert.doesNotMatch(
|
assert.doesNotMatch(
|
||||||
capturedCss,
|
capturedCss,
|
||||||
@@ -226,93 +230,6 @@ assert.equal(earlyAppendedTarget, null, "GM_addStyle should avoid manual documen
|
|||||||
assert.equal(typeof earlyDomContentLoadedHandler, "function", "script should reinject after head becomes available");
|
assert.equal(typeof earlyDomContentLoadedHandler, "function", "script should reinject after head becomes available");
|
||||||
assert.equal(earlyObservedTarget, null, "script should not observe a missing head");
|
assert.equal(earlyObservedTarget, null, "script should not observe a missing head");
|
||||||
|
|
||||||
const styleVars = new Map();
|
|
||||||
const attrs = new Map();
|
|
||||||
const cacheFakeDocument = {
|
|
||||||
documentElement: {
|
|
||||||
style: {
|
|
||||||
setProperty(name, value) {
|
|
||||||
styleVars.set(name, value);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
setAttribute(name, value) {
|
|
||||||
attrs.set(name, value);
|
|
||||||
},
|
|
||||||
removeAttribute(name) {
|
|
||||||
attrs.delete(name);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
head: {},
|
|
||||||
body: {},
|
|
||||||
createElement() {
|
|
||||||
return { id: "", textContent: "", setAttribute() {} };
|
|
||||||
},
|
|
||||||
getElementById() {
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
querySelectorAll() {
|
|
||||||
return [];
|
|
||||||
},
|
|
||||||
addEventListener() {},
|
|
||||||
};
|
|
||||||
const cacheStore = new Map([
|
|
||||||
["tm-thumb-scale:size-cache:v11", JSON.stringify({
|
|
||||||
schema: 11,
|
|
||||||
scale: 2,
|
|
||||||
cardHeightScale: 1.55,
|
|
||||||
modules: {
|
|
||||||
discover: {
|
|
||||||
discoverCard: { width: 182, height: 176 },
|
|
||||||
discoverThumb: { width: 180, height: 101 },
|
|
||||||
discoverTripleUl: { width: 1904, height: 550 },
|
|
||||||
discoverTripleArrow: { width: 35, height: 534 },
|
|
||||||
discoverDoubleUl: { width: 1904, height: 366 },
|
|
||||||
discoverDoubleArrow: { width: 35, height: 350 },
|
|
||||||
discoverSingleUl: { width: 2127, height: 182 },
|
|
||||||
discoverSingleArrow: { width: 35, height: 166 },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})],
|
|
||||||
]);
|
|
||||||
|
|
||||||
vm.runInNewContext(source, {
|
|
||||||
console,
|
|
||||||
document: cacheFakeDocument,
|
|
||||||
localStorage: {
|
|
||||||
getItem(key) {
|
|
||||||
return cacheStore.get(key) || null;
|
|
||||||
},
|
|
||||||
setItem(key, value) {
|
|
||||||
cacheStore.set(key, value);
|
|
||||||
},
|
|
||||||
removeItem(key) {
|
|
||||||
cacheStore.delete(key);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
getComputedStyle() {
|
|
||||||
return {
|
|
||||||
getPropertyValue(name) {
|
|
||||||
return styleVars.get(name) || "";
|
|
||||||
},
|
|
||||||
};
|
|
||||||
},
|
|
||||||
GM_addStyle() {
|
|
||||||
return { id: "", textContent: "", setAttribute() {} };
|
|
||||||
},
|
|
||||||
GM_registerMenuCommand() {},
|
|
||||||
MutationObserver: class {
|
|
||||||
observe() {}
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
assert.equal(attrs.get("data-tm-thumb-scale-discover"), "1", "discover should be enabled directly from cached original sizes");
|
|
||||||
assert.equal(styleVars.get("--tm-thumb-discover-width"), "364px");
|
|
||||||
assert.equal(styleVars.get("--tm-thumb-discover-card-height"), "273px");
|
|
||||||
assert.equal(styleVars.get("--tm-thumb-discover-thumb-width"), "360px");
|
|
||||||
assert.equal(styleVars.get("--tm-thumb-discover-height"), "202px");
|
|
||||||
assert.equal(styleVars.get("--tm-thumb-discover-single-ul"), "282px");
|
|
||||||
assert.equal(styleVars.get("--tm-thumb-discover-triple-ul"), "853px");
|
|
||||||
|
|
||||||
const followingVars = new Map();
|
const followingVars = new Map();
|
||||||
const followingAttrs = new Map();
|
const followingAttrs = new Map();
|
||||||
const followingFakeDocument = {
|
const followingFakeDocument = {
|
||||||
@@ -350,15 +267,17 @@ vm.runInNewContext(source, {
|
|||||||
localStorage: {
|
localStorage: {
|
||||||
getItem() {
|
getItem() {
|
||||||
return JSON.stringify({
|
return JSON.stringify({
|
||||||
schema: 11,
|
schema: 15,
|
||||||
scale: 2,
|
scale: 2,
|
||||||
cardHeightScale: 1.55,
|
cardHeightScale: 1.55,
|
||||||
modules: {
|
modules: {
|
||||||
home: {
|
home: {
|
||||||
|
homeColumns: 7,
|
||||||
homeCard: { width: 174, height: 120 },
|
homeCard: { width: 174, height: 120 },
|
||||||
homeThumb: { width: 174, height: 98 },
|
homeThumb: { width: 174, height: 98 },
|
||||||
},
|
},
|
||||||
followingList: {
|
followingList: {
|
||||||
|
followingListColumns: 7,
|
||||||
followingListCard: { width: 190, height: 120 },
|
followingListCard: { width: 190, height: 120 },
|
||||||
followingListThumb: { width: 188, height: 106 },
|
followingListThumb: { width: 188, height: 106 },
|
||||||
},
|
},
|
||||||
@@ -384,10 +303,10 @@ vm.runInNewContext(source, {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
assert.equal(followingAttrs.get("data-tm-thumb-scale-following-list"), "1", "followed-cams should use its own cached list module");
|
assert.equal(followingAttrs.get("data-tm-thumb-scale-following-list"), undefined, "followed-cams should not apply legacy cached list module");
|
||||||
assert.equal(followingAttrs.get("data-tm-thumb-scale-home"), undefined, "followed-cams should not apply homepage cache");
|
assert.equal(followingAttrs.get("data-tm-thumb-scale-home"), undefined, "followed-cams should not apply legacy homepage cache");
|
||||||
assert.equal(followingVars.get("--tm-thumb-following-list-width"), "380px");
|
assert.equal(followingVars.get("--tm-thumb-following-list-columns"), undefined);
|
||||||
assert.equal(followingVars.get("--tm-thumb-following-list-card-height"), "226px");
|
assert.equal(followingVars.get("--tm-thumb-following-list-card-height"), undefined);
|
||||||
assert.equal(followingVars.get("--tm-thumb-following-list-thumb-width"), undefined);
|
assert.equal(followingVars.get("--tm-thumb-following-list-thumb-width"), undefined);
|
||||||
assert.equal(followingVars.get("--tm-thumb-following-list-thumb-height"), "212px");
|
assert.equal(followingVars.get("--tm-thumb-following-list-thumb-height"), undefined);
|
||||||
assert.equal(followingVars.get("--tm-thumb-home-width"), undefined);
|
assert.equal(followingVars.get("--tm-thumb-home-columns"), undefined);
|
||||||
|
|||||||
Reference in New Issue
Block a user