// ==UserScript== // @name X.com 媒体缩放 // @namespace Lecrp.com // @version 2.1 // @description 时间线+媒体宽高调整,单图/视频/多图适配 // @author jcjyids & Gemini // @match https://x.com/* // @icon https://www.google.com/s2/favicons?sz=64&domain=x.com // @license GPL-3.0-or-later // @grant none // @downloadURL https://update.greasyfork.icu/scripts/564907/Xcom%20%E5%AA%92%E4%BD%93%E7%BC%A9%E6%94%BE.user.js // @updateURL https://update.greasyfork.icu/scripts/564907/Xcom%20%E5%AA%92%E4%BD%93%E7%BC%A9%E6%94%BE.meta.js // ==/UserScript== (function() { 'use strict'; // --- 配置项 --- const MAX_WIDTH = 900; //预期宽度 const MAX_HEIGHT = 800; //预期高度 const sidebarColumn_WIDTH = 280; //右侧栏宽度 const EXCLUDE_DETAILS_PAGE = true; // 开关:true 则在推文详情页不执行缩放逻辑 // --- 1. 独立布局补丁 (不受开关限制) --- const applyLayoutPatch = () => { const mainContentWidth = MAX_WIDTH + 80; const outerContainerWidth = mainContentWidth + sidebarColumn_WIDTH + 100; const styleId = 'x-layout-patch'; let style = document.getElementById(styleId); if (!style) { style = document.createElement('style'); style.id = styleId; document.documentElement.appendChild(style); } style.textContent = ` .r-113js5t { width: ${outerContainerWidth}px !important; } .r-1hycxz { width: ${sidebarColumn_WIDTH}px !important; } .r-1ye8kvj { max-width: ${mainContentWidth}px !important; } `; }; applyLayoutPatch(); // --- 2. 环境判定 --- const isDetailsPage = () => { // 匹配 x.com/user/status/123456... return /\/status\/\d+/.test(window.location.pathname); }; // --- 3. 核心缩放逻辑 --- const processTweet = (tweet) => { // 如果开关开启且处于详情页,直接退出 if (EXCLUDE_DETAILS_PAGE && isDetailsPage()) return; const mainContainer = tweet.querySelector('[aria-labelledby]'); if (!mainContainer) return; const photos = Array.from(mainContainer.querySelectorAll('[data-testid="tweetPhoto"]')); const totalCount = photos.length; const anchor = mainContainer.querySelector('div[style*="max-width"]'); if (totalCount > 2) { handleMultiMedia(mainContainer, totalCount); } else if (totalCount === 0 || totalCount === 1) { if (!anchor) return; handleSingleMedia(anchor, mainContainer); } }; function handleSingleMedia(anchor, mainContainer) { const validA = Array.from(anchor.querySelectorAll('a')).find(a => { let current = a; while (current && current !== anchor) { if (current.hasAttribute('aria-label')) return false; current = current.parentElement; } return true; }); const videoPlayer = anchor.querySelector('[data-testid="videoPlayer"]'); const ratioEl = anchor.querySelector('[style*="padding-bottom"]'); if (ratioEl && ratioEl.style.paddingBottom) { const ratio = parseFloat(ratioEl.style.paddingBottom) / 100; if (isNaN(ratio)) return; const { finalWidth, finalHeight } = calculateSize(ratio); const wPx = `${Math.round(finalWidth)}px`; if (anchor.style.maxWidth !== wPx) { anchor.style.setProperty('max-width', wPx, 'important'); } if (validA && !videoPlayer) { const targetContainer = validA.firstElementChild; if (targetContainer) { const anchorFirstChild = anchor.firstElementChild; if (anchorFirstChild) anchorFirstChild.classList.add('r-k200y'); if (targetContainer.style.width !== wPx) { targetContainer.style.width = wPx; targetContainer.style.height = `${Math.round(finalHeight)}px`; } } } } } function handleMultiMedia(container, count) { const firstRatio = container.querySelector('[style*="padding-bottom"]'); if (firstRatio) { const targetPadding = count === 3 ? '70%' : '100%'; if (firstRatio.style.paddingBottom !== targetPadding) { firstRatio.style.setProperty('padding-bottom', targetPadding, 'important'); } } } function calculateSize(ratio) { const containerRatio = MAX_HEIGHT / MAX_WIDTH; let finalWidth, finalHeight; if (ratio > containerRatio) { finalHeight = MAX_HEIGHT; finalWidth = MAX_HEIGHT / ratio; } else { finalWidth = MAX_WIDTH; finalHeight = MAX_WIDTH * ratio; } return { finalWidth, finalHeight }; } // --- 4. 调度与执行 --- let rafId = null; const fastExecute = () => { if (rafId) cancelAnimationFrame(rafId); rafId = requestAnimationFrame(() => { document.querySelectorAll('[data-testid="tweet"]').forEach(processTweet); }); }; const observer = new MutationObserver(fastExecute); observer.observe(document.body, { childList: true, subtree: true }); window.addEventListener('popstate', () => { applyLayoutPatch(); // 切换页面时重新计算布局 let count = 0; const retry = setInterval(() => { fastExecute(); if (++count > 12) clearInterval(retry); }, 100); }); fastExecute(); })();