Last active
November 11, 2021 09:10
-
-
Save syusui-s/67a81c0b7357e86b9531746bc84f22ce to your computer and use it in GitHub Desktop.
StackExchange Source Highlight: 転載サイトで StackOverflow, SuperUser等のStackExchangeサービスへのリンクをハイライトするUserScriptです(Chrome拡張機能)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // ==UserScript== | |
| // @name StackExchange Source Highlight | |
| // @namespace https://gist.github.com/syusui-s/67a81c0b7357e86b9531746bc84f22ce/ | |
| // @version 1.4.0 | |
| // @description 転載サイトで StackOverflow, SuperUser等のStackExchangeサービスへのリンクをハイライトします | |
| // @license CC0-1.0 | |
| // @author syusui-s | |
| // @match https://codeday.me/* | |
| // @match https://*.coder.work/* | |
| // @match https://www.366service.com/jp/qa/* | |
| // @match https://www.codeflow.site/ja/article/* | |
| // @match https://www.it-swarm-ja.tech/ja/* | |
| // @match https://qastack.jp/* | |
| // @match https://python5.com/* | |
| // @match https://www.py4u.net/discuss/* | |
| // @match https://code.i-harness.com/* | |
| // @match https://stackoverrun.com/* | |
| // @match http://*.uwenku.com/* | |
| // @match https://steakrecords.com/* | |
| // @match https://living-sun.com/* | |
| // @match https://jpcloud.net/q/* | |
| // @match https://*.ojit.com/so/* | |
| // @match https://www.javaer101.com/* | |
| // @match https://www.debugcn.com/* | |
| // @match https://www.fixes.pub/* | |
| // @match https://cloud6.net/* | |
| // @match https://www.it-mure.jp.net/* | |
| // @match https://base64.work/* | |
| // @match https://webdevqa.jp.net/* | |
| // @match https://www.titanwolf.org/* | |
| // @grant none | |
| // @run-at document-end | |
| // @downloadURL https://gist.github.com/syusui-s/67a81c0b7357e86b9531746bc84f22ce/raw/highlight_stackexchange_source.user.js | |
| // @updateURL https://gist.github.com/syusui-s/67a81c0b7357e86b9531746bc84f22ce/raw/highlight_stackexchange_source.user.js | |
| // ==/UserScript== | |
| (function() { | |
| 'use strict'; | |
| function xPathSelectorAllUnordered(xpath, doc) { | |
| const xPathResult = document.evaluate(xpath, doc, null, XPathResult.UNORDERED_NODE_ITERATOR_TYPE); | |
| const results = []; | |
| for (;;) { | |
| const node = xPathResult.iterateNext(); | |
| if (node == undefined) break; | |
| results.push(node); | |
| } | |
| return results; | |
| } | |
| const markClass = '__stackexchange_source_highlight__'; | |
| const illegalLicenseOrigins = ['https://code.i-harness.com', 'https://living-sun.com/']; | |
| const query = 'a[href^="https://stackoverflow.com/"], a[href^="http://stackoverflow.com/"], a[href*="stackexchange.com/"], a[href^="https://superuser.com/"], a[href^="https://serverfault.com/"]'; | |
| const xPathQuery = "//a[contains(text(), '原文') or contains(text(), 'ソース') or contains(text(), 'source') or contains(text(), 'Source')]"; | |
| const style = document.createElement('style'); | |
| style.textContent = `@keyframes blink { 65% { opacity: 0.0; } }`; | |
| document.head.appendChild(style); | |
| const linkStyle = { | |
| fontSize: '1em', | |
| color: 'red', | |
| animation: 'blink 1s step-end infinite', | |
| textDecoration: 'underline', | |
| fontWeight: 'bold', | |
| fontSize: '1.25em', | |
| }; | |
| const sources = [...document.querySelectorAll(query)] | |
| .filter(elem => !elem.classList.contains(markClass)) | |
| .filter((elem) => { | |
| // User page should be ignored | |
| if (/\/users\/\d+\/[\w-]+/.test(elem.href)) { | |
| return false; | |
| } | |
| return true; | |
| }) | |
| .map((elem) => { | |
| // qastackはリンク先が間違っていることがあるので修正 | |
| if (location.host === 'qastack.jp') { | |
| elem.href = elem.href.replace(/^https?:\/\/stackoverflow.com\/\/(.*)$/, '$1'); | |
| elem.href = elem.href.replace(/^https?:\/\/qastack.jp\/\w+\/\d+\/(.*)$/, 'https://$1'); | |
| elem.href = elem.href.replace(/^(https?:\/\/stackoverflow.com\/)(?!questions)\w+(\/\d+\/.*)$/, '$1questions$2'); | |
| } | |
| return elem; | |
| }); | |
| [...sources].forEach(elem => { | |
| Object.assign(elem.style, linkStyle); | |
| elem.appendChild(document.createTextNode('(転載元に移動)')); | |
| elem.classList.add(markClass); | |
| }); | |
| const maybeSources = [...xPathSelectorAllUnordered(xPathQuery, document)] | |
| .filter(elem => !elem.classList.contains(markClass)); | |
| [...maybeSources].forEach(elem => { | |
| Object.assign(elem.style, linkStyle, { color: 'darkorange' }); | |
| elem.appendChild(document.createTextNode('(恐らく転載元)')); | |
| elem.classList.add(markClass); | |
| }); | |
| const hasSource = (sources.length > 0 || maybeSources.length > 0) && !illegalLicenseOrigins.includes(location.origin); | |
| const warn = document.createElement('div'); | |
| Object.assign(warn.style, { | |
| position: 'fixed', | |
| top: 0, | |
| padding: '10px', | |
| fontSize: '16px', | |
| textAlign: 'center', | |
| color: 'red', | |
| background: 'white', | |
| width: '100vw', | |
| border: '5px solid red', | |
| opacity: '0.9', | |
| zIndex: '2147483647', | |
| }); | |
| const text = document.createElement('span'); | |
| Object.assign(text.style, { | |
| animation: 'blink 1s ease-out infinite', | |
| fontSize: '32px', | |
| fontWeight: 'bold', | |
| }); | |
| if (hasSource) { | |
| text.textContent = 'このサイトは転載サイトです。'; | |
| } else { | |
| text.textContent = '⚠原典へのリンクが見つかりませんでした。ライセンス違反サイトの可能性があります。'; | |
| } | |
| warn.appendChild(text); | |
| const createListFromLink = (el) => { | |
| const li = document.createElement('li'); | |
| const link = document.createElement('a'); | |
| Object.assign(link, { href: el.href, textContent: el.textContent }); | |
| li.appendChild(link); | |
| return li; | |
| }; | |
| const sourcesDiv = document.createElement('div'); | |
| const sourcesElem = document.createElement('ul'); | |
| sourcesDiv.appendChild(document.createTextNode('転載元へのリンク')); | |
| [...sources].map(createListFromLink).forEach((e) => sourcesElem.appendChild(e)); | |
| sourcesDiv.appendChild(sourcesElem); | |
| sourcesDiv.appendChild(document.createTextNode('転載元の可能性があるリンク')); | |
| const maybeSourcesElem = document.createElement('ul'); | |
| [...maybeSources].map(createListFromLink).forEach((e) => maybeSourcesElem.appendChild(e)); | |
| sourcesDiv.appendChild(maybeSourcesElem); | |
| warn.appendChild(sourcesDiv); | |
| const br = document.createElement('br'); | |
| warn.appendChild(br); | |
| const back = document.createElement('button'); | |
| back.addEventListener('click', () => history.back()); | |
| back.textContent = '🔙前のページに戻る'; | |
| warn.appendChild(back); | |
| const proceed = document.createElement('button'); | |
| proceed.addEventListener('click', () => warn.remove()); | |
| proceed.textContent = '➡️閲覧を続ける'; | |
| warn.appendChild(proceed); | |
| document.body.appendChild(warn); | |
| })(); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| code.i-harness.com hard | |
| codeday.me hard | |
| ja.coder.work hard | |
| python5.com hard | |
| qastack.jp hard | |
| stackoverrun.com hard | |
| www.366service.com hard | |
| www.codeflow.site hard | |
| www.it-swarm-ja.tech hard | |
| ja.it-reply.net hard | |
| ja.uwenku.com hard | |
| living-sun.com hard | |
| steakrecords.com hard | |
| jpcloud.net hard | |
| ja.ojit.com hard | |
| www.javaer101.com hard | |
| www.debugcn.com hard | |
| www.py4u.net hard | |
| www.fixes.pub hard | |
| cloud6.net hard | |
| www.it-mure.jp.net hard | |
| base64.work hard | |
| webdevqa.jp.net hard | |
| www.titanwolf.org hard |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment