您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Remove t.co tracking links from Twitter
当前为
- // ==UserScript==
- // @name Twitter Direct
- // @description Remove t.co tracking links from Twitter
- // @author chocolateboy
- // @copyright chocolateboy
- // @version 0.0.1
- // @namespace https://github.com/chocolateboy/userscripts
- // @license GPL: https://www.gnu.org/copyleft/gpl.html
- // @include https://twitter.com/
- // @include https://twitter.com/*
- // @run-at document-start
- // @inject-into content
- // ==/UserScript==
- /*
- * scan a JSON response for tweets if its URL matches this pattern
- */
- const PATTERN = /^https:\/\/api\.twitter\.com\/([^/]+\/[^.]+\.json)\?/
- /*
- * compatibility shim needed for Violentmonkey:
- * https://github.com/violentmonkey/violentmonkey/issues/997#issuecomment-637700732
- */
- const Compat = {}
- /*
- * replace t.co URLs with the original URL in all locations within the document
- * which contain tweets
- */
- function transformLinks (path, data) {
- const objects = data.globalObjects || data.twitter_objects
- const tweets = objects ? objects.tweets : objects
- if (!tweets) {
- console.debug("can't find tweets in:", path)
- return
- }
- console.info(`scanning links in ${path}:`, data)
- for (const tweet of Object.values(tweets)) {
- const { entities, extended_entities = {} } = tweet
- const { urls = [], media = [] } = entities
- const { urls: extendedUrls = [], media: extendedMedia = [] } = extended_entities
- const locations = [urls, media, extendedUrls, extendedMedia]
- for (const location of locations) {
- for (const item of location) {
- item.url = item.expanded_url
- }
- }
- }
- return data
- }
- /*
- * parse and transform the JSON response, handling (catching and reporting) any
- * parse or processing errors
- */
- function transformResponse (json, path) {
- let parsed
- try {
- parsed = JSON.parse(json)
- } catch (e) {
- console.error("Can't parse response:", e)
- return
- }
- let transformed
- try {
- transformed = transformLinks(path, parsed)
- } catch (e) {
- console.error('error transforming JSON:', e)
- return
- }
- return transformed
- }
- /*
- * replacement for Twitter's default response handler which transforms the
- * response if it's a) JSON and b) contains tweet data; otherwise, we leave it
- * unchanged
- */
- function onReadyStateChange (xhr, url) {
- const match = url.match(PATTERN)
- if (!match) {
- console.debug("can't match URL:", url)
- return
- }
- const path = match[1]
- const transformed = transformResponse(xhr.responseText, path)
- if (transformed) {
- const descriptor = { value: JSON.stringify(transformed) }
- const clone = Compat.cloneInto(descriptor, Compat.unsafeWindow)
- Compat.unsafeWindow.Object.defineProperty(xhr, 'responseText', clone)
- }
- }
- /*
- * replace the built-in XHR#send method with our custom version which swaps in
- * our custom response handler. once done, we delegate to the original handler
- * (this.onreadystatechange)
- */
- function hookXHRSend (oldSend) {
- return function send () {
- const oldOnReadyStateChange = this.onreadystatechange
- this.onreadystatechange = function () {
- if (this.readyState === 4 && this.responseURL && this.status === 200) {
- onReadyStateChange(this, this.responseURL)
- }
- oldOnReadyStateChange.apply(this, arguments)
- }
- return oldSend.apply(this, arguments)
- }
- }
- /*
- * set up a cross-engine API to shield us from differences between engines so we
- * don't have to clutter the code with conditionals.
- *
- * XXX the functions are only needed for Violentmonkey, and are effectively
- * no-ops in other engines
- */
- if (GM_info.scriptHandler === 'Violentmonkey') {
- Compat.unsafeWindow = unsafeWindow.wrappedJSObject
- Compat.cloneInto = cloneInto
- Compat.exportFunction = exportFunction
- } else {
- Compat.cloneInto = Compat.exportFunction = value => value
- Compat.unsafeWindow = unsafeWindow
- }
- console.debug('hooking XHR#send:', Compat.unsafeWindow.XMLHttpRequest.prototype.send)
- /*
- * replace the default XHR#send with our custom version, which scans responses
- * for tweets and expands their URLs
- */
- Compat.unsafeWindow.XMLHttpRequest.prototype.send = Compat.exportFunction(
- hookXHRSend(window.XMLHttpRequest.prototype.send),
- Compat.unsafeWindow
- )