您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Shows pictures and some videos right after the link, loads and expands comment threads.
当前为
// ==UserScript== // @name Reddit expand media and comments // @description Shows pictures and some videos right after the link, loads and expands comment threads. // @version 0.1.7 // @author wOxxOm // @namespace wOxxOm.scripts // @license MIT License // @match *://*.reddit.com/* // @grant GM_addStyle // @grant GM_xmlhttpRequest // @connect imgur.com // @connect gfycat.com // @connect streamable.com // @connect instagram.com // @connect ibb.co // @connect prntscr.com // @connect prnt.sc // ==/UserScript== const CLASS = 'reddit-inline-media'; const CLASS_ALBUM = CLASS + '-album'; const MORE_SELECTOR = '[id^="moreComments-"] p, .morecomments a'; const RULES = [ {r:/^https?:\/\/(i\.)?imgur\.com\/(?:a|gallery)\/(\w+)$/i, s:'https://imgur.com/ajaxalbums/getimages/$2/hit.json?all=true', q:(json, text) => Array.from(((json || {}).data || {}).images || []) .map(img => img && `https://i.imgur.com/${img.hash}${img.ext}`), }, {r:/^https?:\/\/(i\.)?imgur\.com\/\w+$/i, q:'link[rel="image_src"], meta[name="twitter:player:stream"]'}, {r:/^https?:\/\/streamable\.com\/.+/i, q:'video'}, {r:/^https?:\/\/gfycat\.com\/.+/i, q:'source[src*=".webm"]'}, {r:/^https?:\/\/(www\.)?instagram\.com\/p\/[^/]+\/?$/i, q:'meta[property="og:image"]'}, {r:/^https?:\/\/ibb\.co\/\w+$/i, q:'meta[property="og:image"]'}, {r:/^https?:\/\/prntscr\.com\/(\w+)$/i, s:'https://prnt.sc/$1', q:'meta[property="og:image"]', xhr:true}, {r:/^https?:\/\/prnt\.sc\/(\w+)$/i, q:'meta[property="og:image"]', xhr:true}, {r:/\.gifv(\?.*)?$/i, s:'.mp4'}, {r:/\.(jpe?g|png|gif|webm|mp4)(\?.*)?$/i}, ]; GM_addStyle(` .${CLASS} { max-width: 100%; display: block; } .${CLASS}[data-src] { padding-top: 300px; } .${CLASS}:hover { outline: 2px solid #3bbb62; } .${CLASS_ALBUM} { overflow-y: auto; max-height: calc(100vh - 100px); margin: .5em 0; -webkit-mask-image: linear-gradient(white, transparent); mask-image: linear-gradient(white, transparent); } .${CLASS_ALBUM}:hover { -webkit-mask-image: none; mask-image: none; } .${CLASS_ALBUM} > :nth-child(n + 2) { margin-top: 1em; } `); const isChrome = navigator.userAgent.includes('Chrom'); const REQUEST_THROTTLE_MS = location.hostname.startsWith('old.') ? 500 : 250; const ME = Symbol(GM_info.script.name); const more = []; new MutationObserver(onMutation) .observe(document.body, {subtree: true, childList: true}); onMutation([{ addedNodes: [document.body] }]); const scrollObserver = new IntersectionObserver(onScroll, { rootMargin: '200% 0px', }); function onMutation(mutations) { const items = []; let someElementsAdded = false; for (var i = 0, m; (m = mutations[i++]);) { for (var j = 0, added = m.addedNodes, node; (node = added[j++]);) { if (node.nodeType !== 1) continue; // Node.ELEMENT_NODE someElementsAdded = true; if (node.localName === 'a') { const data = preprocess(node); if (data) items.push(data); continue; } if (!node.children[0]) continue; var aa = node.getElementsByTagName('a'); for (var k = 0, a; (a = aa[k++]);) { const data = preprocess(a); if (data) items.push(data); } } } if (someElementsAdded) debounce(observeShowMore); if (items.length) setTimeout(process, 0, items); } function onScroll(entries, observer) { for (const e of entries) { if (!e.isIntersecting) continue; let el = e.target; if (el.localName === 'img' || el.localName === 'video') { observer.unobserve(el); el.src = el.dataset.src; delete el.dataset.src; continue; } if (el.localName === 'a') { // switch to an unfocusable element to prevent the link // from stealing focus and scrolling the view const el2 = document.createElement('span'); el2.setAttribute('onclick', el.getAttribute('onclick')); el2.setAttribute('id', el.id); el.parentNode.replaceChild(el2, el); el = el2; } expandNextComment(el); } } function preprocess(a) { let url = a.href; for (const {r, s, q} of RULES) { if (typeof r === 'string') { if (!url.includes(r)) continue; } else { if (!r.test(url)) continue; if (s) url = url.replace(r, s); } return {a, url, q}; } } function process(items) { for (const item of items) { const {a, url, q} = item; const {href} = a; const text = a.textContent.trim(); if ( text && !a.getElementsByTagName('img')[0] && !/^https?:\/\/\S+?\.{3}$/.test(text) && !a.closest('.scrollerItem,' + '[contenteditable="true"],' + '[data-test-id="post-content"],' + `a[href="${href}"] + * a[href="${href}"],` + `img[src="${href}"] + * a[href="${href}"]`) ) { (q ? expandRemote : expand)(item); } } } function expandRemote({a, url, q, xhr}) { GM_xmlhttpRequest({ url, method: 'GET', onload: r => { const isJSON = /^content-type:.*?json\s*$/mi.test(r.responseHeaders); const doc = isJSON ? tryJSONparse(r.response) : new DOMParser().parseFromString(r.response, 'text/html'); if (typeof q === 'string') { if (isJSON) return; const el = doc && doc.querySelector(q); const imageUrl = el && (el.href || el.src || el.content); if (imageUrl) { if (xhr) { GM_xmlhttpRequest({ imageUrl, method: 'GET', headers: {Referer: url}, responseType: 'arraybuffer', onload: r => { expand({a, url: arrayBufferToBase64(r.response, getMimeType(imageUrl))}); }, }); } else { expand({a, url: imageUrl}); } } return; } let urls; if (typeof q === 'function') { try { urls = q(doc, r.response); } catch (e) {} } if (!urls || !urls.length) return; urls = Array.isArray(urls) ? urls : [urls]; let observer; if (urls.length > 1) { observer = new IntersectionObserver(onScroll, {rootMargin: '200px 0px'}); a = a.insertAdjacentElement('afterEnd', document.createElement('div')); a.className = CLASS_ALBUM; } for (const url of urls) { if (url) a = expand({a, url}, observer); } }, }); } function expand({a, url = a.href}, observer = scrollObserver) { const isVideo = /(webm|gifv|mp4)(\?.*)?$/i.test(url); const el = document.createElement(isVideo ? 'video' : 'img'); el.dataset.src = url; el.className = CLASS; a.insertAdjacentElement(a.classList.contains(CLASS_ALBUM) ? 'beforeEnd' : 'afterEnd', el); if (isVideo) { el.controls = true; el.preload = 'metadata'; if (isChrome) el.addEventListener('click', playOnClick); } observer.observe(el); return el; } function observeShowMore() { const more = document.querySelector(MORE_SELECTOR); if (!more) return; for (const el of document.querySelectorAll(MORE_SELECTOR)) { scrollObserver.observe(el); } } function expandNextComment(el) { if (el) more.push(el); else more.shift(); if (more.length === 1 || !el && more.length) { more[0].dispatchEvent(new MouseEvent('click', {bubbles: true})); setTimeout(expandNextComment, REQUEST_THROTTLE_MS); } } function playOnClick(event, el, wasPaused) { if (!el) { setTimeout(playOnClick, 0, event, this, this.paused); } else if (el.paused === wasPaused) { wasPaused ? el.play() : el.pause(); } } function debounce(fn, timeout = 0, ...args) { clearTimeout(fn.__timeout); fn.__timeout = setTimeout(fn, timeout, ...args); } function tryJSONparse(str) { try { return JSON.parse(str); } catch (e) { return undefined; } } function arrayBufferToBase64(buffer, type) { return new Promise(resolve => { Object.assign(new FileReader(), { onload: e => resolve(e.target.result) }).readAsDataURL(new Blob([buffer], {type})); }); } function getMimeType(url) { const ext = (url.match(/\.(\w+)(\?.*)?$|$/)[1] || '').toLowerCase(); return 'image/' + (ext === 'jpg' ? 'jpeg' : ext); }
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址