├── README.md ├── LICENSE └── imgur-links-rewriting-on-ptt.user.js /README.md: -------------------------------------------------------------------------------- 1 | # imgur-links-rewriting-on-ptt 2 | 3 | Rewrite Imgur links on Ptt web to bypass `Referer` check. 4 | 5 | 改寫 Ptt 網頁版上的 Imgur 連結,繞過 `Referer` 檢查。 6 | 7 | ## Features 8 | 9 | * Support `https://imgur.com/a/` & `https://imgur.com/gallery/` (i.e. album links) to show the first image. 10 | * Use WebP image format. 11 | * Use original size images. 12 | * Rewrite images cached by `cache.ptt.cc`, to `i.imgur.com` directly. 13 | 14 | ## Install 15 | 16 | * https://greasyfork.org/en/scripts/431157-imgur-links-rewriting-on-ptt 17 | * https://openuserjs.org/scripts/gslin/Imgur_links_rewriting_on_Ptt 18 | 19 | ## Links 20 | 21 | * [重寫 Ptt 上的 Imgur Userscript 解決圖片出不來的問題](https://blog.gslin.org/archives/2021/08/22/10287/%e9%87%8d%e5%af%ab-ptt-%e4%b8%8a%e7%9a%84-imgur-userscript-%e8%a7%a3%e6%b1%ba%e5%9c%96%e7%89%87%e5%87%ba%e4%b8%8d%e4%be%86%e7%9a%84%e5%95%8f%e9%a1%8c/) (Chinese) 22 | 23 | ## License 24 | 25 | See [LICENSE](LICENSE). 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2021 Gea-Suan Lin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /imgur-links-rewriting-on-ptt.user.js: -------------------------------------------------------------------------------- 1 | // ==UserScript== 2 | // @name Imgur links rewriting on Ptt 3 | // @namespace https://github.com/gslin/imgur-links-rewriting-on-ptt 4 | // @match https://www.ptt.cc/bbs/* 5 | // @match https://www.ptt.cc/man/* 6 | // @grant GM_xmlhttpRequest 7 | // @version 0.20240912.1 8 | // @author Gea-Suan Lin 9 | // @description Rewrite imgur links to bypass referrer check. 10 | // @license MIT 11 | // ==/UserScript== 12 | 13 | (() => { 14 | 'use strict'; 15 | 16 | const get_imgur_id_suffix = url => { 17 | const a = url.match(/^https?:\/\/(i\.|m\.)?imgur\.com\/(\w+)\.?(\w+)?/); 18 | return [a[2], a[3]]; 19 | }; 20 | const re_imgur_album = /^https?:\/\/imgur\.com\/(a|gallery)\//; 21 | 22 | document.querySelectorAll('a[href*="//imgur.com/"], a[href*="//i.imgur.com/"], a[href*="//m.imgur.com/"]').forEach(async el => { 23 | // Remove ".richcontent" if existing. 24 | const next = el.nextElementSibling; 25 | if (next && next.classList.contains('richcontent')) { 26 | next.remove(); 27 | } 28 | 29 | // Remove ".richcontent" if existing. 30 | const next2 = el.parentElement.nextElementSibling; 31 | if (next2 && next2.classList.contains('richcontent')) { 32 | next2.remove(); 33 | } 34 | 35 | // Remove ".richcontent" for ".push" case. 36 | const el_p2 = el.parentElement.parentElement; 37 | if (el_p2 && el_p2.classList.contains('push')) { 38 | const el_p2_next = el_p2.nextElementSibling; 39 | if (el_p2_next && el_p2_next.classList.contains('richcontent')) { 40 | el_p2_next.remove(); 41 | } 42 | } 43 | 44 | const href = el.getAttribute('href'); 45 | let imgur_id = ''; 46 | let imgur_suffix = ''; 47 | 48 | if (href.match(re_imgur_album)) { 49 | // album case. 50 | const res = await new Promise(resolve => { 51 | GM_xmlhttpRequest({ 52 | 'anonymous': true, 53 | 'headers': { 54 | 'Referer': 'https://imgur.com/', 55 | }, 56 | 'method': 'GET', 57 | 'onload': res => { 58 | resolve(res.responseText); 59 | }, 60 | 'url': href, 61 | }); 62 | }); 63 | 64 | const parser = new DOMParser(); 65 | const doc = parser.parseFromString(res, 'text/html'); 66 | 67 | const og_image = doc.querySelector('meta[property="og:image"]'); 68 | const img_url = og_image.getAttribute('content'); 69 | 70 | [imgur_id, imgur_suffix] = get_imgur_id_suffix(img_url); 71 | } else { 72 | // image case. 73 | [imgur_id, imgur_suffix] = get_imgur_id_suffix(href); 74 | } 75 | 76 | // Change to webp only if it's not gif. 77 | if (imgur_suffix !== 'gif') { 78 | imgur_suffix = 'webp'; 79 | } 80 | 81 | const container = document.createElement('div'); 82 | container.setAttribute('style', 'margin-top:0.5em;text-align:center;'); 83 | 84 | const img = document.createElement('img'); 85 | img.setAttribute('referrerpolicy', 'no-referrer'); 86 | img.setAttribute('src', 'https://i.imgur.com/' + imgur_id + '.' + imgur_suffix); 87 | container.appendChild(img); 88 | 89 | el.insertAdjacentElement('afterend', container); 90 | }); 91 | })(); 92 | --------------------------------------------------------------------------------