您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Enhance PTT web image load performance
当前为
// ==UserScript== // @name PTT web image enhanced // @namespace 2CF9973A-28C9-11EC-9EA6-98F49F6E8EAB // @version 2.2 // @description Enhance PTT web image load performance // @author Rick0 // @match https://www.ptt.cc/bbs/*/*.html* // @match https://www.ptt.cc/ask/over18?* // @grant GM.xmlHttpRequest // @connect imgur.com // ==/UserScript== (function() { 'use strict' // == independent methods == function createElement(html) { let template = document.createElement('template') template.innerHTML = html return template.content.firstChild } function getHeaders (url, headers = {}) { return new Promise((resolve, reject) => { GM.xmlHttpRequest({ url, method: 'HEAD', headers, onload: function (res) { if ([200, 304].includes(res.status)) { let headers = res.responseHeaders .split(/\r?\n/) .slice(0, -1) .reduce((result, item) => { let [, key, val] = item.match(/(.+?): +(.+)/) result[key] = val return result }, {}) resolve(headers) } else { reject(res) } }, onerror: function (err) { reject(err) }, }) }) } function insertElementToTextNode (textNode, element) { if (textNode.nodeType === 3) { textNode.parentNode.replaceChild(element, textNode) let textMatchList = textNode.data.match(/^([^\n]*)\n?(.*)$/s) if (textMatchList[1] !== undefined) element.insertAdjacentText('beforebegin', textMatchList[1]) if (textMatchList[2] !== undefined) element.insertAdjacentText('afterend', textMatchList[2]) } else { textNode.insertAdjacentElement('beforebegin', element) } } function getTypeExt (type) { try { let ext = type.match(/[^\/]+?\/(.+)/)[1] switch (ext) { case 'jpeg': { ext = 'jpg' break } } return ext } catch (e) { return } } function getImgurInfo (originalUrl) { return new Promise((resolve, reject) => { let imgurInfo = { originalUrl, id: undefined, ext: undefined, get imgurUrl () { return [this.id, this.ext].includes(undefined) ? undefined : `https://i.imgur.com/${this.id}.${this.ext}` }, get embedUrl () { let quality = this.ext !== 'gif' ? 'h' : '' let ext = this.ext !== 'gif' ? 'jpg' : 'mp4' return [this.id, this.ext].includes(undefined) ? undefined : `https://i.imgur.com/${this.id}${quality}.${ext}` }, } let infoUrl let infoHeaders = { referer: 'https://imgur.com/', } let link = new URL(originalUrl) // URL 的 pathname 最少會有 / ,所以利用正則來去頭尾 / 後切割,最後面的 / 的後面如果沒有值不會被列入 let pathList = link.pathname !== '/' ? link.pathname.match(/^\/(.*?)\/?$/)[1].split('/') : [] // let imgurIdExtRegExp = /^(\w{7})\w?(?:\.(\w+))?$/ let imgurIdRegExp = /^\w{7}/ // 取得 id switch (pathList.length) { // 按照 pathname 的層數來分類處理 // 只有一層,只可能是 id / id.ext 的格式 case 1: { let idMatchList = pathList[0].match(imgurIdRegExp) if (idMatchList !== null) { imgurInfo.id = idMatchList[0] infoUrl = `https://i.imgur.com/${imgurInfo.id}.jpg` } else { reject(imgurInfo) retrun } break } default: reject(imgurInfo) retrun } // 取得 imgurInfo.ext getHeaders(infoUrl, infoHeaders) .then(headers => { imgurInfo.ext = getTypeExt(headers['content-type']) resolve(imgurInfo) }) .catch(err => { reject(imgurInfo) }) }) } // == dependent methods == function pttImageEnhanced () { function embedImg (href, richcontent) { getImgurInfo(href) .then(imgurInfo => { switch (imgurInfo.ext) { case 'gif': { richcontent.innerHTML = `<video data-src="${imgurInfo.embedUrl}" autoplay loop muted style="max-width: 100%;max-height: 800px;"></video>` videoLazyObserver.observe(richcontent.querySelector(':scope > video')) break } default: { richcontent.innerHTML = `<img src="${imgurInfo.embedUrl}" alt loading="lazy">` } } }) .catch(err => err) } // == 取消所有 ptt web 原生的 imgur 圖片載入 == for (let img of document.querySelectorAll('.richcontent > img[src*="imgur.com"]')) { img.src = '' } // == 取消外連資源的 referrer == document.head.appendChild(createElement('<meta name="referrer" content="no-referrer">')) // == 建立 video lazy observer == let onEnterView = function (entries, observer) { for (let entry of entries) { if (entry.isIntersecting) { // 目標進入畫面 let video = entry.target video.src = video.dataset.src video.removeAttribute('data-src') observer.unobserve(video) } } } let options = { rootMargin: '50%', } let videoLazyObserver = new IntersectionObserver(onEnterView, options) // == 處理內文的部分 == for (let a of document.querySelectorAll('.bbs-screen.bbs-content > a[href*="imgur.com"]')) { // 當不存在原生展開的圖片元素時,自行建立 if (!a.nextElementSibling.classList.contains('richcontent')) { insertElementToTextNode(a.nextSibling, createElement('<div class="richcontent"></div>')) } let richcontent = a.nextElementSibling embedImg(a.href, richcontent) } // == 處理推/噓文的部分 == for (let a of document.querySelectorAll('.f3.push-content > a[href*="imgur.com"]')) { // 當不存在原生展開的圖片元素時,自行建立 if (!a.closest('.push').nextElementSibling.classList.contains('richcontent')) { insertElementToTextNode(a.closest('.push').nextSibling, createElement('<div class="richcontent"></div>')) } let richcontent = a.closest('.push').nextElementSibling embedImg(a.href, richcontent) } } function agreeOver18 () { document.cookie = `over18=1;path=/;expires=${(new Date(2100, 0)).toUTCString()};` location.replace(`https://www.ptt.cc/${decodeURIComponent(location.search.replace(/\?from=([^&]+)/, '$1'))}`) } switch (location.hostname) { case 'www.ptt.cc': { switch (location.pathname) { case '/ask/over18': { agreeOver18() } break default: { pttImageEnhanced() } } } break } })()
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址