Compare commits

..

8 Commits

Author SHA1 Message Date
90a7f95fd2 Add userscript documentation 2026-06-06 13:15:00 +08:00
b4f0b1838e Rename Chaturbate thumbnail userscript 2026-06-06 12:50:08 +08:00
73d9d380f5 Add Chaturbate thumbnail controls and chat hiding 2026-06-06 12:17:53 +08:00
5d6a0d7d41 Make Chaturbate thumbnail grids responsive 2026-06-06 10:18:54 +08:00
bde00f27d3 Translate Chaturbate tag pages 2026-06-03 13:33:16 +08:00
893fe47ace Fix discover carousel scaling 2026-06-02 01:36:29 +08:00
d078339288 Fix thumbnail scaling heights 2026-06-02 01:19:17 +08:00
ac8e88fe66 Prevent double scaling on home thumbnails 2026-06-01 13:35:45 +08:00
6 changed files with 3284 additions and 1122 deletions

82
Chaturbate/README.md Normal file
View File

@@ -0,0 +1,82 @@
# Chaturbate 缩略图自定义缩放
这个油猴脚本用于自定义调整 Chaturbate 页面中的缩略图和房间卡片尺寸,让首页、关注页、发现页、频道页相关推荐、关注下拉和悬停预览在大屏上更容易浏览。
## 安装地址
[https://gitea.jackadam.top/jack/Tampermonkey_scripts/raw/branch/main/Chaturbate/chaturbate-thumbnails-custom.user.js](https://gitea.jackadam.top/jack/Tampermonkey_scripts/raw/branch/main/Chaturbate/chaturbate-thumbnails-custom.user.js)
脚本元信息中的 `@updateURL``@downloadURL` 都指向上面的 Gitea raw 地址,因此安装后可以通过 Tampermonkey 自动更新。
## 主要功能
- 自定义放大首页和关注页房间列表。
- 自定义放大发现页横向轮播区域。
- 自定义放大频道页“更多这样的直播间”。
- 自定义放大顶部“关注”下拉弹层中的预览卡片。
- 修正关注下拉弹层放大后可能超出屏幕左侧的问题。
- 翻译 `tags` 页面中以 `#` 开头的主题标签。
- 在页面右下角提供缩放控制面板。
- 可选自动隐藏频道页直播画面上方的小聊天浮窗。
## 页面控制项
脚本加载后会在页面右下角显示控制面板:
| 控制项 | 作用 |
| --- | --- |
| 响应式 | 用于首页、关注页、频道页相关推荐等需要跟随浏览器宽度自动换列的区域。 |
| 固定式 | 用于关注下拉、悬停预览等固定尺寸弹层。 |
| 隐藏聊天窗 | 只隐藏频道页直播画面上方的小聊天浮窗,不隐藏主直播画面。 |
| 恢复原始尺寸 | 将响应式和固定式倍率恢复为 `1.0`。 |
倍率支持小数点后一位。设置会保存到浏览器 `localStorage`,下次打开页面继续生效。
## 放大逻辑
脚本尽量保留网站原有响应式布局,只改变尺寸倍率:
- 响应式列表不固定列数,而是提高卡片的最小宽度,让浏览器按窗口宽度自动决定列数。
- 缩略图宽高按倍率放大,避免只改宽度导致比例失衡。
- 卡片整体高度使用自动布局,避免文字区被强行拉高或压扁。
- 固定弹层只在必要时调整位置,弹层放大后如果超出屏幕左侧,才向右移动到可见范围内。
## 适用页面
- `https://chaturbate.com/*`
- `https://*.chaturbate.com/*`
常用中文页面包括:
- `https://zh-hans.chaturbate.com/`
- `https://zh-hans.chaturbate.com/followed-cams/`
- `https://zh-hans.chaturbate.com/discover/`
- `https://zh-hans.chaturbate.com/tags/`
- `https://zh-hans.chaturbate.com/tags/female/`
- 各主播频道页,例如 `https://zh-hans.chaturbate.com/example_room/`
## 调试
脚本保留控制台调试入口:
```js
tmThumbScaleDebug()
tmThumbScaleInspectRecommendations()
tmThumbScaleInspectRoomChat()
tmThumbScaleSetScales(1.8, 1.5)
```
如果页面布局异常,可以先在控制台执行 `tmThumbScaleDebug()`查看当前页面识别到的区域、CSS 变量和脚本版本。
## 本地验证
```powershell
node --check .\Chaturbate\chaturbate-thumbnails-custom.user.js
node .\tests\followed-dropdown-css.test.js
```
## 维护注意
- 修改脚本名或文件名时,同步更新 `@updateURL``@downloadURL`、根目录 README 和测试文件路径。
- 不要把本机 `127.0.0.1` 调试地址写进 `@updateURL``@downloadURL`
- 若 Chaturbate 页面结构变更,应优先在浏览器中检查真实 DOM再调整选择器。

View File

File diff suppressed because it is too large Load Diff

View File

File diff suppressed because it is too large Load Diff

31
README.md Normal file
View File

@@ -0,0 +1,31 @@
# Tampermonkey Scripts
个人维护的油猴脚本集合。当前主要脚本用于改造 Chaturbate 页面展示,方便在较大屏幕上浏览房间列表、发现页轮播、关注下拉和频道页相关推荐。
## 脚本列表
| 脚本 | 说明 | 安装 / 更新 |
| --- | --- | --- |
| [Chaturbate 缩略图自定义缩放](./Chaturbate/README.md) | 自定义放大 Chaturbate 缩略图和房间卡片,支持页面控制面板、标签中文化、频道页小聊天窗隐藏。 | [安装地址](https://gitea.jackadam.top/jack/Tampermonkey_scripts/raw/branch/main/Chaturbate/chaturbate-thumbnails-custom.user.js) |
## 使用方式
1. 安装 Tampermonkey 或兼容的用户脚本管理器。
2. 打开上表中的安装地址。
3. 在 Tampermonkey 安装页确认安装。
4. 后续脚本会通过 `@updateURL` 从本仓库自动检查更新。
## 开发与测试
当前脚本为纯 JavaScript userscript不需要构建步骤。
```powershell
node --check .\Chaturbate\chaturbate-thumbnails-custom.user.js
node .\tests\followed-dropdown-css.test.js
```
## 维护约定
- 脚本文件放在对应站点目录下。
- 每个脚本目录应包含自己的 `README.md`,说明功能、安装地址和主要行为。
- 发布前确认 `@updateURL``@downloadURL` 指向可公开访问的 raw 地址,而不是本机调试地址。

View File

@@ -1 +0,0 @@
油猴脚本

View File

@@ -2,7 +2,7 @@ const assert = require("node:assert/strict");
const fs = require("node:fs");
const vm = require("node:vm");
const source = fs.readFileSync("Chaturbate/chaturbate-thumbnails-2x.user.js", "utf8");
const source = fs.readFileSync("Chaturbate/chaturbate-thumbnails-custom.user.js", "utf8");
let capturedCss = "";
let gmAddStyleCalls = 0;
let menuCommandName = "";
@@ -86,38 +86,43 @@ assert.match(
);
assert.match(
capturedCss,
/data-tm-thumb-scale-following-list="1"[\s\S]*--tm-thumb-following-list-width/,
"followed-cams list should be separated from homepage list sizing",
/data-tm-thumb-scale-following-list="1"[\s\S]*--tm-thumb-following-list-min-width/,
"followed-cams list should use its own detected minimum column width",
);
assert.match(
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/,
"followed-cams list should keep the site's stretching grid alignment while using detected minimum width",
/data-tm-thumb-scale-following-list="1"[\s\S]*grid-template-columns:\s*repeat\(auto-fill,\s*minmax\(var\(--tm-thumb-following-list-min-width\),\s*1fr\)\)\s*!important/,
"followed-cams list should reduce columns responsively using scaled minimum width",
);
assert.match(
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/,
"room page related rooms thumbnail containers should use detected thumb width and height",
/#main\.roomPage\s+ul\.list:has\(li\.roomCard\)\s+\.room_thumbnail_container[\s\S]*width:\s*100%\s*!important[\s\S]*height:\s*auto\s*!important/,
"room page related rooms thumbnail containers should follow card width and automatic height",
);
assert.match(
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/,
"base room related thumbnails should use detected thumb width and height",
/\.BaseRoomContents\s+ul\.list:has\(li\.roomCard\)\s+\.room_thumbnail[\s\S]*width:\s*100%\s*!important[\s\S]*height:\s*auto\s*!important/,
"base room related thumbnails should follow card width and automatic height",
);
assert.match(
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/,
"base room RoomCardGrid related rooms should use detected width",
"base room RoomCardGrid related rooms should fill the row using detected scaled minimum width",
);
assert.match(
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/,
"base room RoomCardGrid thumbnails should use detected thumb width and height",
/\.BaseRoomContents\s+ul\.RoomCardGrid\s+\.RoomCardThumbnail[\s\S]*width:\s*100%\s*!important[\s\S]*height:\s*auto\s*!important/,
"base room RoomCardGrid thumbnails should follow card width and automatic height",
);
assert.match(
capturedCss,
/\.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",
/\.BaseRoomContents\s+ul\.RoomCardGrid\s*>\s*li\.RoomCard[\s\S]*height:\s*auto\s*!important[\s\S]*max-height:\s*none\s*!important/,
"base room RoomCardGrid related cards should use automatic height",
);
assert.match(
capturedCss,
/\.BaseRoomContents\s+ul\.RoomCardGrid\s*>\s*li\.RoomCard[\s\S]*width:\s*auto\s*!important[\s\S]*justify-self:\s*stretch\s*!important[\s\S]*max-width:\s*none\s*!important/,
"base room RoomCardGrid related cards should stretch to fill responsive columns",
);
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");
@@ -131,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/,
@@ -141,6 +151,36 @@ assert.match(
/height:\s*var\(--tm-thumb-discover-double-arrow\)\s*!important/,
"discover carousel arrow heights should use detected original heights",
);
assert.match(
capturedCss,
/data-tm-thumb-scale-followed-page="1"[\s\S]*\.carousel-root\s+\.single-row\s+ul\.list[\s\S]*height:\s*auto\s*!important[\s\S]*max-height:\s*none\s*!important[\s\S]*overflow:\s*visible\s*!important/,
"followed-cams recommendations should release carousel list height after scaling",
);
assert.match(
capturedCss,
/data-tm-thumb-scale-followed-page="1"[\s\S]*grid-template-columns:\s*repeat\(auto-fill,\s*minmax\(var\(--tm-thumb-discover-width\),\s*1fr\)\)\s*!important/,
"followed-cams legacy recommendations should use responsive scaled minimum width",
);
assert.doesNotMatch(
capturedCss,
/data-tm-thumb-scale-followed-page="1"[\s\S]*grid-template-columns:\s*repeat\(2,/,
"followed-cams recommendations should not force a hard-coded two-column layout",
);
assert.match(
capturedCss,
/data-tm-thumb-scale-followed-recommendations="1"[\s\S]*data-tm-thumb-followed-recommendations-list="1"[\s\S]*grid-template-columns:\s*repeat\(auto-fill,\s*minmax\(var\(--tm-thumb-followed-recommendations-width\),\s*1fr\)\)\s*!important[\s\S]*grid-auto-rows:\s*auto\s*!important/,
"title-detected followed recommendations should use responsive scaled minimum columns and automatic row height",
);
assert.match(
capturedCss,
/data-tm-thumb-scale-followed-recommendations="1"[\s\S]*data-tm-thumb-followed-recommendations-card="1"[\s\S]*width:\s*auto\s*!important[\s\S]*max-width:\s*none\s*!important[\s\S]*height:\s*auto\s*!important[\s\S]*max-height:\s*none\s*!important/,
"title-detected followed recommendation cards should stretch responsively and grow naturally",
);
assert.match(
capturedCss,
/data-tm-thumb-scale-followed-recommendations="1"[\s\S]*data-tm-thumb-followed-recommendations-thumb="1"[\s\S]*height:\s*auto\s*!important/,
"title-detected followed recommendation thumbnails should keep automatic height",
);
assert.match(
capturedCss,
/#discover_root\s+\.room-list-carousel\s+\.room_thumbnail[\s\S]*height:\s*var\(--tm-thumb-discover-height\)\s*!important/,
@@ -153,9 +193,12 @@ assert.match(
);
assert.match(
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/,
"follow dropdown images should use detected original thumb width and height",
/\.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 follow fixed card width and use detected height",
);
assert.doesNotMatch(capturedCss, /translateX\(/, "follow dropdown should not use a fixed horizontal offset");
assert.match(source, /adjustFollowDropdownPosition/, "script should adjust follow dropdown position only when it overflows");
assert.match(source, /viewportPadding - rect\.left/, "follow dropdown adjustment should be based on left viewport overflow");
assert.match(
capturedCss,
/react-tooltip[\s\S]*width:\s*var\(--tm-thumb-tooltip-width\)\s*!important[\s\S]*height:\s*var\(--tm-thumb-tooltip-height\)\s*!important/,
@@ -169,11 +212,21 @@ assert.match(
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, /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, /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.match(source, /localStorage\.removeItem\(CACHE_KEY/, "script should clear cached sizes from the menu command");
assert.match(source, /DEFAULT_RESPONSIVE_SCALE/, "script should expose a default responsive scale");
assert.match(source, /DEFAULT_FIXED_SCALE/, "script should expose a default fixed scale");
assert.match(source, /tmThumbScaleSetScales/, "script should expose a debug API for changing both scales");
assert.match(capturedCss, /#tm-thumb-scale-controls[\s\S]*position:\s*fixed\s*!important/, "script should render a fixed page control panel");
assert.match(capturedCss, /data-tm-thumb-scale-auto-hide-room-chat="1"[\s\S]*data-tm-thumb-room-chat-overlay="1"[\s\S]*display:\s*none\s*!important/, "script should hide marked room chat overlays when enabled");
assert.match(source, /hideRoomChat/, "script should persist the room chat auto-hide setting");
assert.match(source, /applyRoomChatAutoHide/, "script should apply automatic room chat hiding");
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.match(source, /TAG_TRANSLATIONS/, "script should include a centralized tag translation table");
assert.match(source, /translateTagsPage/, "script should translate the Chaturbate tags page");
assert.doesNotMatch(source, /localStorage\.setItem\([^,]*LEGACY_CACHE_PREFIX/, "script should not write detected sizes to localStorage");
assert.match(source, /SETTINGS_KEY/, "script may persist user-adjustable scale settings");
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.doesNotMatch(
capturedCss,
@@ -226,23 +279,87 @@ assert.equal(earlyAppendedTarget, null, "GM_addStyle should avoid manual documen
assert.equal(typeof earlyDomContentLoadedHandler, "function", "script should reinject after head becomes available");
assert.equal(earlyObservedTarget, null, "script should not observe a missing head");
const styleVars = new Map();
const attrs = new Map();
const cacheFakeDocument = {
const tagAnchors = [
{
href: "https://zh-hans.chaturbate.com/tag/asian/",
textContent: "#asian",
dataset: {},
title: "",
getAttribute(name) {
return name === "href" ? this.href : "";
},
},
{
href: "https://zh-hans.chaturbate.com/tag/bigboobs/",
textContent: "#bigboobs",
dataset: {},
title: "",
getAttribute(name) {
return name === "href" ? this.href : "";
},
},
{
href: "https://zh-hans.chaturbate.com/tag/ebony/female/",
textContent: "#ebony",
dataset: {},
title: "",
getAttribute(name) {
return name === "href" ? this.href : "";
},
},
{
href: "https://zh-hans.chaturbate.com/tag/not-in-table/",
textContent: "Not In Table",
dataset: {},
title: "",
getAttribute(name) {
return name === "href" ? this.href : "";
},
},
{
href: "https://zh-hans.chaturbate.com/tag/new-custom-tag/",
textContent: "#new-custom-tag",
dataset: {},
title: "",
getAttribute(name) {
return name === "href" ? this.href : "";
},
},
{
href: "https://zh-hans.chaturbate.com/tag/colombiana/female/",
textContent: "#colombiana",
dataset: {},
title: "",
getAttribute(name) {
return name === "href" ? this.href : "";
},
},
{
href: "https://zh-hans.chaturbate.com/tag/untranslated-example/",
textContent: "#untranslated-example",
dataset: {},
title: "",
getAttribute(name) {
return name === "href" ? this.href : "";
},
},
{
href: "https://zh-hans.chaturbate.com/tags/female/?page=2",
textContent: "2",
dataset: {},
title: "",
getAttribute(name) {
return name === "href" ? this.href : "";
},
},
];
const tagFakeDocument = {
documentElement: {
style: {
setProperty(name, value) {
styleVars.set(name, value);
setAttribute() {},
},
head: {
appendChild() {},
},
setAttribute(name, value) {
attrs.set(name, value);
},
removeAttribute(name) {
attrs.delete(name);
},
},
head: {},
body: {},
createElement() {
return { id: "", textContent: "", setAttribute() {} };
@@ -250,52 +367,20 @@ const cacheFakeDocument = {
getElementById() {
return null;
},
querySelectorAll() {
return [];
querySelectorAll(selector) {
return selector.includes("/tag") ? tagAnchors : [];
},
addEventListener() {},
};
const cacheStore = new Map([
["tm-thumb-scale:size-cache:v9", JSON.stringify({
schema: 9,
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, {
const runTagsPageTranslationTest = (pathname = "/tags/") => 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) || "";
},
};
document: tagFakeDocument,
location: {
href: `https://zh-hans.chaturbate.com${pathname}`,
pathname,
},
URL,
GM_addStyle() {
return { id: "", textContent: "", setAttribute() {} };
},
@@ -305,13 +390,32 @@ vm.runInNewContext(source, {
},
});
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");
runTagsPageTranslationTest();
assert.equal(tagAnchors[0].textContent, "亚洲", "tags page should translate known tag link text");
assert.equal(tagAnchors[0].dataset.tmTagOriginal, "#asian", "translated tags should keep the original label in dataset");
assert.equal(tagAnchors[0].title, "#asian", "translated tags should expose the original label in title");
assert.equal(tagAnchors[1].textContent, "大胸", "tags page should translate compact multi-word tag slugs");
assert.equal(tagAnchors[2].textContent, "黑人", "gender-scoped tag links should translate by the first slug segment");
assert.equal(tagAnchors[3].textContent, "Not In Table", "unknown tags should remain unchanged");
assert.equal(tagAnchors[4].textContent, "新自定义标签", "untranslated hashtag-style tags should use slug word translation");
assert.equal(tagAnchors[5].textContent, "哥伦比亚女性", "known gendered nationality tags should be translated");
assert.equal(tagAnchors[6].textContent, "#untranslated-example", "untranslated hashtag-style tags should keep the original slug");
assert.equal(tagAnchors[7].textContent, "2", "tags pagination links should not be translated");
tagAnchors.forEach((anchor, index) => {
anchor.textContent = ["#asian", "#bigboobs", "#ebony", "Not In Table", "#new-custom-tag", "#colombiana", "#untranslated-example", "2"][index];
anchor.dataset = {};
anchor.title = "";
});
runTagsPageTranslationTest("/tags/female/");
assert.equal(tagAnchors[0].textContent, "亚洲", "tag category pages under /tags/ should also translate links");
assert.equal(tagAnchors[1].textContent, "大胸", "tag category pages should translate compact slugs too");
assert.equal(tagAnchors[2].textContent, "黑人", "tag category pages should translate /tag/slug/gender/ links");
assert.equal(tagAnchors[5].textContent, "哥伦比亚女性", "tag category pages should translate gendered nationality links");
assert.equal(tagAnchors[6].textContent, "#untranslated-example", "tag category pages should preserve unknown hashtag-style tags");
assert.equal(tagAnchors[7].textContent, "2", "tag category page pagination should keep page numbers");
const followingVars = new Map();
const followingAttrs = new Map();
@@ -350,15 +454,19 @@ vm.runInNewContext(source, {
localStorage: {
getItem() {
return JSON.stringify({
schema: 9,
schema: 15,
scale: 2,
cardHeightScale: 1.55,
modules: {
home: {
homeMinWidth: 190,
homeCard: { width: 174, height: 120 },
homeThumb: { width: 174, height: 98 },
},
followingList: {
followingListMinWidth: 190,
followingListCard: { width: 190, height: 120 },
followingListThumb: { width: 188, height: 106 },
},
},
});
@@ -382,10 +490,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-home"), undefined, "followed-cams should not apply homepage cache");
assert.equal(followingVars.get("--tm-thumb-following-list-width"), "380px");
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 legacy homepage cache");
assert.equal(followingVars.get("--tm-thumb-following-list-min-width"), undefined);
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-height"), undefined);
assert.equal(followingVars.get("--tm-thumb-home-width"), undefined);
assert.equal(followingVars.get("--tm-thumb-home-min-width"), undefined);