您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Enhance PTT web image load performance
当前为
- // ==UserScript==
- // @name PTT web image enhanced
- // @namespace 2CF9973A-28C9-11EC-9EA6-98F49F6E8EAB
- // @version 2.4
- // @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 isUrlExist (url, headers = {}) {
- return new Promise((resolve) => {
- GM.xmlHttpRequest({
- url,
- method: 'HEAD',
- headers,
- onload: function (res) {
- if ([200, 304].includes(res.status) && res.finalUrl !== 'https://i.imgur.com/removed.png') {
- resolve(true)
- } else {
- resolve(false)
- }
- },
- onerror: function (err) {
- resolve(false)
- },
- })
- })
- }
- function insertElementToNextLine (positionElement, element) {
- let positionNextSibling = positionElement.nextSibling
- switch (positionNextSibling?.nodeType) {
- case Node.TEXT_NODE:
- positionNextSibling.parentNode.replaceChild(element, positionNextSibling)
- let textMatchList = positionNextSibling.data.match(/^([^\n]*)\n?(.*)$/s)
- if (textMatchList[1] !== undefined) element.insertAdjacentText('beforebegin', textMatchList[1])
- if (textMatchList[2] !== undefined) element.insertAdjacentText('afterend', textMatchList[2])
- break
- case Node.ELEMENT_NODE:
- case undefined:
- positionElement.insertAdjacentElement('afterend', element)
- break
- default:
- throw new Error('insertElementToNextLine receive invalid positionElement')
- }
- }
- function getImgurInfo (originalUrl) {
- return new Promise((resolve, reject) => {
- let imgurInfo = {
- id: undefined,
- hasVideo: undefined,
- get imgurUrl () {
- return this.id !== undefined ? `https://i.imgur.com/${this.id}.jpg` : undefined
- },
- get embedUrl () {
- if (this.id !== undefined) {
- return this.hasVideo ? `https://i.imgur.com/${this.id}.mp4` : `https://i.imgur.com/${this.id}h.jpg`
- } else {
- return undefined
- }
- },
- }
- let infoHeaders = {
- referer: 'https://imgur.com/',
- }
- let link = new URL(originalUrl)
- // URL 的 pathname 最少會有 / ,所以利用正則來去頭尾 / 後切割,最後面的 / 的後面如果沒有值不會被列入
- let pathList = link.pathname !== '/' ? link.pathname.match(/^\/(.*?)\/?$/)[1].split('/') : []
- 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]
- } else {
- reject(imgurInfo)
- retrun
- }
- }
- break
- default:
- reject(imgurInfo)
- retrun
- }
- isUrlExist(`https://i.imgur.com/${imgurInfo.id}.mp4`, infoHeaders)
- // 確認是否有影片格式的存在
- .then(hasVideo => {
- imgurInfo.hasVideo = hasVideo
- resolve(imgurInfo)
- })
- .catch(err => {
- reject(imgurInfo)
- })
- })
- }
- function agreeOver18 () {
- document.cookie = `over18=1;path=/;expires=${(new Date(2100, 0)).toUTCString()}`
- location.replace(`https://www.ptt.cc/${decodeURIComponent(location.search.match(/[?&]from=([^&]+)/)[1])}`)
- }
- // == dependent methods ==
- function pttImageEnhanced () {
- function embedImg (href, prevRichcontentElement) {
- getImgurInfo(href)
- .then(imgurInfo => {
- let richcontent = createElement('<div class="richcontent"></div>')
- if (imgurInfo.hasVideo) {
- richcontent.innerHTML = `<video data-src="${imgurInfo.embedUrl}" autoplay loop muted style="max-width: 100%;max-height: 800px;"></video>`
- videoLazyObserver.observe(richcontent.querySelector(':scope > video'))
- } else {
- richcontent.innerHTML = `<img src="${imgurInfo.embedUrl}" alt loading="lazy">`
- }
- insertElementToNextLine(prevRichcontentElement, richcontent)
- })
- .catch(err => err)
- }
- // == 取消所有 ptt web 原生的 imgur 圖片載入 ==
- for (let img of document.querySelectorAll('.richcontent > img[src*="imgur.com"]')) {
- img.src = ''
- img.parentElement.remove()
- }
- // == 取消外連資源的 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"]')) {
- embedImg(a.href, a)
- }
- // == 處理推/噓文的部分 ==
- for (let a of document.querySelectorAll('.f3.push-content > a[href*="imgur.com"]')) {
- embedImg(a.href, a.closest('.push'))
- }
- }
- switch (location.hostname) {
- case 'www.ptt.cc': {
- switch (location.pathname) {
- case '/ask/over18': {
- agreeOver18()
- }
- break
- default: {
- pttImageEnhanced()
- }
- }
- }
- break
- }
- })()