您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Remove URL redirections added by some social networks. Use HTTPS for other shorteners. Improve privacy.
- // ==UserScript==
- // @name Canonical links
- // @author Guillaume
- // @description Remove URL redirections added by some social networks. Use HTTPS for other shorteners. Improve privacy.
- // @namespace https://greasyfork.org/fr/users/11386-guillaume
- // @include https://twitter.com/*
- // @include https://identi.ca/*
- // @include https://microca.st/*
- // @include https://m.facebook.com/*
- // @version 1.5
- // @grant none
- // @run-at document-start
- // @license CC by-sa http://creativecommons.org/licenses/by-sa/3.0/
- // ==/UserScript==
- // Credits:
- //
- // - getVisibleText, textContentVisible:
- // This is derived from a work by Ethan Brown.
- // Original license: cc-by sa
- // Source: http://stackoverflow.com/questions/19985306/get-the-innertext-of-an-element-but-exclude-hidden-children
- function getVisibleText( node )
- {
- if ( node.nodeType === 1 ) // Element
- {
- var rect = node.getBoundingClientRect();
- if ( rect.width === 0 || rect.height === 0 )
- return '';
- }
- else if ( node.nodeType === 3 ) // Text
- {
- return node.textContent;
- }
- var text = '';
- for( var i = 0; i < node.childNodes.length; i++ )
- text += getVisibleText( node.childNodes[i] );
- return text;
- }
- if ( ! Node.prototype.hasOwnProperty('textContentVisible') )
- {
- Object.defineProperty(Node.prototype, 'textContentVisible', {
- get: function() {
- return getVisibleText( this );
- },
- enumerable: true
- });
- }
- if ( ! HTMLAnchorElement.prototype.hasOwnProperty('getSearchParam') )
- {
- Object.defineProperty(HTMLAnchorElement.prototype, 'getSearchParam', {
- get: function()
- {
- var a = this;
- return function(b)
- {
- var res = a.search.match('[\?&]' + b + '=([^=]*)(?:&[^;=]*=|$)') || [];
- return res[1];
- }
- },
- enumerable: true
- });
- }
- var hostRules = {};
- var applyHostRules = function(el)
- {
- // normalize host
- el.host = el.host;
- var i = 0;
- var limit = 3;
- while ( hostRules[el.hostname] && i < limit )
- {
- var urlFactory = hostRules[el.hostname];
- el = urlFactory(el);
- i++;
- }
- }
- hostRules['youtu.be'] = function(el)
- {
- el.href = 'https://www.youtube.com/watch?v=' + el.pathname.substr(1);
- return el;
- };
- hostRules['lm.facebook.com']
- = hostRules['m.facebook.com']
- = function(el)
- {
- var uParam = el.getSearchParam('u');
- if ( el.pathname == '/l.php' && uParam !== undefined )
- {
- el.href = unescape(uParam);
- }
- return el;
- };
- var makeLinkHTTPS = function(el)
- {
- if ( el.protocol == 'http:' )
- el.protocol = 'https:';
- return el;
- }
- hostRules = [
- 'ask.fm', 'awe.sm', 'bit.ly', 'bc.vc',
- 'd.pr', 'db.tt', 'dlvr.it',
- 'fb.me',
- 'goo.gl', 'grnpc.org',
- 'identi.ca', 'is.gd', 'j.mp',
- 'lnkd.in', 't.co',
- 'tinyurl.com', 'tr.im',
- 'v.gd', 'vur.me',
- 'wp.me', 'x.co'
- ].reduce(function(o, a) { o[a] = makeLinkHTTPS; return o; }, hostRules);
- var makeLinkExpanded = function(el)
- {
- var textNode = document.createTextNode(el.textContentVisible);
- var url = el.dataset.expandedUrl;
- var newLink = document.createElement('a');
- newLink.href = url;
- newLink.title = el.title;
- newLink.className = el.className;
- newLink.dir = el.dir;
- newLink.appendChild(textNode);
- el.parentNode.replaceChild(newLink, el);
- };
- var makeLinkFromTitle = function(el)
- {
- var url = el.title;
- var text = el.textContentVisible;
- if ( text.indexOf('http:') === 0 || text.indexOf('https:') )
- text = url;
- var textNode = document.createTextNode(text);
- var newLink = document.createElement('a');
- newLink.href = url;
- newLink.title = el.title;
- newLink.className = el.className;
- newLink.dir = el.dir;
- newLink.appendChild(textNode);
- el.parentNode.replaceChild(newLink, el);
- };
- var onLink = function(el)
- {
- var updateText = false;
- if ( el.childNodes.length == 1
- && el.childNodes[0].nodeType === 3
- && el.childNodes[0].textContent == el.href )
- updateText = true;
- applyHostRules(el);
- // disable referers
- el.rel = 'noreferrer';
- if ( updateText )
- {
- var textNode = document.createTextNode(el.href);
- el.replaceChild(textNode, el.childNodes[0]);
- }
- }
- var onTwitterLink = function(el)
- {
- makeLinkExpanded(el);
- }
- var onPumpIOLink = function(el)
- {
- makeLinkFromTitle(el);
- }
- window.addEventListener("load", function(ev) {
- // unshadow for better debugging
- delete console.log;
- // initial pass
- if ( window.Pump )
- [].slice.call(document.querySelectorAll('a[title^=http]')).forEach(onPumpIOLink);
- [].slice.call(document.querySelectorAll('a[data-expanded-url]')).forEach(onTwitterLink);
- [].slice.call(document.querySelectorAll('a[href]')).forEach(onLink);
- // watch changes
- var observer = new MutationObserver(function(mutations)
- {
- mutations.forEach(function(mutation)
- {
- for ( var i = 0; i < mutation.addedNodes.length; i++ )
- {
- var node = mutation.addedNodes[i];
- if ( node.querySelectorAll )
- {
- [].slice.call(node.querySelectorAll('a[data-expanded-url]')).forEach(onTwitterLink);
- [].slice.call(node.querySelectorAll('a[href]')).forEach(onLink);
- }
- }
- });
- });
- var config = { childList: true, subtree: true };
- observer.observe(document, config);
- }, true);