diff --git a/Chaturbate/chaturbate-thumbnails-2x.user.js b/Chaturbate/chaturbate-thumbnails-2x.user.js index 0977528..0e96f3d 100644 --- a/Chaturbate/chaturbate-thumbnails-2x.user.js +++ b/Chaturbate/chaturbate-thumbnails-2x.user.js @@ -1,8 +1,8 @@ // ==UserScript== // @name Chaturbate 缩略图放大 2 倍 // @namespace https://chaturbate.com/ -// @version 0.1.1 -// @description 将房间列表缩略图按宽高 2 倍放大 +// @version 0.2.6 +// @description 通过放大 grid 最小列宽来放大房间列表缩略图,保留原站填满行为 // @match https://chaturbate.com/* // @match https://*.chaturbate.com/* // @run-at document-start @@ -13,173 +13,53 @@ "use strict"; // ========== 配置项 ========== - // 放大倍数(宽度和高度都会按此倍数放大) - const SCALE = 1.5; - - // 调试开关(true: 输出调试信息,false: 静默运行) - const DEBUG = false; + // 最小列宽倍数(原站约 174px / 180px,乘以该倍数后作为新的 minmax 最小值,1fr 仍填满整行) + const SCALE = 1.3; // =========================== - // ========== 内部常量 ========== - const SCALED_ATTR = "data-tm-scaled"; - const BASE_W_ATTR = "data-tm-base-w"; - const BASE_H_ATTR = "data-tm-base-h"; - // =========================== + const MIN_COL_MAIN = 174; // #main 下的 min + const MIN_COL_ROOT = 180; // #roomlist_root、频道页下方(180×101) 的 min + const minMain = Math.round(MIN_COL_MAIN * SCALE); + const minRoot = Math.round(MIN_COL_ROOT * SCALE); - // 提前注入 CSS,避免闪烁 - const injectCSS = () => { - const style = document.createElement("style"); - style.id = "tm-thumb-scale-style"; - const css = ` - img.room_thumbnail:not([${SCALED_ATTR}="1"]) { - opacity: 0; - transition: opacity 0.1s; - } - img.room_thumbnail[${SCALED_ATTR}="1"] { - opacity: 1; - } - ul.list, - ul.list.endless_page_template { - display: flex !important; - flex-wrap: wrap !important; - gap: 0 !important; - } - `; - - style.textContent = css; - const inject = () => { - if (!document.getElementById("tm-thumb-scale-style")) { - (document.head || document.documentElement).appendChild(style); - } - }; - if (document.head) { - inject(); - } else { - document.addEventListener("DOMContentLoaded", inject); + const style = document.createElement("style"); + style.id = "tm-thumb-scale-style"; + style.textContent = ` + #main #roomlist_root .roomlist_container ul.list, + #main #roomlist_root .placeholder_roomlist_container ul.list { + grid-template-columns: repeat(auto-fill, minmax(${minMain}px, 1fr)) !important; } - }; - injectCSS(); - - const relaxKnownOuter = () => { - // 确保列表容器能容纳更大的卡片 - document.querySelectorAll("ul.list, ul.list.endless_page_template").forEach((el) => { - el.style.width = "100%"; - el.style.maxWidth = "none"; - el.style.boxSizing = "border-box"; - el.style.overflow = "visible"; - }); - }; - - const scale = () => { - if (DEBUG) console.log("[tm] running on", location.href); - relaxKnownOuter(); - const items = document.querySelectorAll("a.room_thumbnail_container"); - if (DEBUG) console.log("[tm] containers:", items.length); - items.forEach((container) => { - const img = container.querySelector("img.room_thumbnail"); - if (DEBUG && !img) console.log("[tm] no img in container", container); - if (!img) return; - - const attrW = parseFloat(img.getAttribute("width")); - const attrH = parseFloat(img.getAttribute("height")); - const baseW = parseFloat(img.getAttribute(BASE_W_ATTR)) || attrW; - const baseH = parseFloat(img.getAttribute(BASE_H_ATTR)) || attrH; - if (!baseW || !baseH) return; - - if (!img.getAttribute(BASE_W_ATTR) || !img.getAttribute(BASE_H_ATTR)) { - img.setAttribute(BASE_W_ATTR, String(baseW)); - img.setAttribute(BASE_H_ATTR, String(baseH)); - } - - const scaledW = baseW * SCALE; - const scaledH = baseH * SCALE; - if (DEBUG) console.log("[tm] img size:", baseW, baseH, img); - - img.setAttribute("width", String(scaledW)); - img.setAttribute("height", String(scaledH)); - img.setAttribute(SCALED_ATTR, "1"); - img.style.width = `${scaledW}px`; - img.style.height = `${scaledH}px`; - img.style.maxWidth = "none"; - img.style.maxHeight = "none"; - img.style.display = "block"; - img.style.opacity = "1"; - - container.style.width = `${scaledW}px`; - container.style.height = `${scaledH}px`; - container.style.minWidth = `${scaledW}px`; - container.style.maxWidth = `${scaledW}px`; - container.style.minHeight = `${scaledH}px`; - container.style.overflow = "visible"; - container.style.display = "block"; - container.style.boxSizing = "border-box"; - container.style.flexShrink = "0"; - - const card = container.closest("li.roomCard"); - if (card) { - card.style.width = `${scaledW}px`; - card.style.minWidth = `${scaledW}px`; - card.style.maxWidth = `${scaledW}px`; - card.style.minHeight = `${scaledH}px`; - card.style.height = "auto"; - card.style.overflow = "visible"; - card.style.flexShrink = "0"; - card.style.flexGrow = "0"; - card.style.flexBasis = `${scaledW}px`; - card.style.boxSizing = "border-box"; - } - }); - }; - - const init = () => { - if (DEBUG) { - const thumbs = document.querySelectorAll("img.room_thumbnail"); - console.log("[tm] thumbnails:", thumbs.length, Array.from(thumbs)); + #roomlist_root .roomlist_container ul.list, + #roomlist_root .placeholder_roomlist_container ul.list { + grid-template-columns: repeat(auto-fill, minmax(${minRoot}px, 1fr)) !important; } - scale(); - }; - - // 立即执行(如果 DOM 已就绪) - if (document.readyState === "loading") { - document.addEventListener("DOMContentLoaded", init); - } else { - init(); - } - - // 延迟重试,处理动态加载 - window.setTimeout(scale, 100); - window.setTimeout(scale, 300); - window.setTimeout(scale, 600); - window.setTimeout(scale, 1000); - window.setTimeout(scale, 2000); - - // MutationObserver 监听动态添加的内容 - const observer = new MutationObserver((mutations) => { - for (const mutation of mutations) { - for (const node of mutation.addedNodes) { - if (node.nodeType === 1 && ( - node.matches?.("a.room_thumbnail_container, li.roomCard") || - node.querySelector?.("a.room_thumbnail_container") - )) { - if (DEBUG) console.log("[tm] new content detected, scaling..."); - scale(); - return; - } - } + /* 频道页下方:列表在 .BaseRoomContents 内,统一用该祖先即可 */ + .BaseRoomContents ul.list { + display: grid !important; + grid-gap: 0.6em 0.75em !important; + grid-template-columns: repeat(auto-fill, minmax(${minRoot}px, 1fr)) !important; } - }); - - // 开始观察 - const startObserving = () => { - const target = document.body || document.documentElement; - if (target) { - observer.observe(target, { childList: true, subtree: true }); - if (DEBUG) console.log("[tm] MutationObserver started"); + .BaseRoomContents ul.list li { + width: auto !important; + max-width: none !important; + max-height: none !important; } + .BaseRoomContents ul.list .room_thumbnail_container { + display: block !important; + width: 100% !important; + } + .BaseRoomContents ul.list .room_thumbnail_container img { + width: 100% !important; + height: auto !important; + display: block !important; + max-width: none !important; + } + `; + + const inject = () => { + if (!document.getElementById("tm-thumb-scale-style")) + (document.head || document.documentElement).appendChild(style); }; - if (document.body) { - startObserving(); - } else { - document.addEventListener("DOMContentLoaded", startObserving); - } + if (document.head) inject(); + else document.addEventListener("DOMContentLoaded", inject); })();