// ==UserScript== // @name Twitter media-only filter toggle. // @version 0.14 // @description Toggle non-media tweets on and off on the home timeline, for the power-viewer! // @author Cro // @match https://*.twitter.com/* // @match https://*.x.com/* // @run-at document-idle // @grant GM_setValue // @grant GM_getValue // @namespace https://greasyfork.org/users/10865 // @icon https://www.google.com/s2/favicons?domain=twitter.com // @license MIT // @downloadURL none // ==/UserScript== /* jshint esversion: 6 */ (function() { 'use strict'; let storage_key = "cro-media-toggle"; let show_all = GM_getValue(storage_key); let create_ui = function(target) { let button = document.createElement("button"); button.innerText = show_all ? "Showing all home tweets" : "Showing only media home tweets"; button.onclick = function(event) { show_all = !show_all; GM_setValue(storage_key, show_all); location.reload(); }; target.prepend(button); }; let find_objects_at_keys = function(obj, keys) { let found = []; let stack = Object.entries(obj); while (stack.length > 0) { let current = stack.pop(); if (keys.includes(current[0])) { found.push(current[1]); } if (current[1] != null && typeof(current[1]) == 'object') { stack = stack.concat(Object.entries(current[1])); } } return found; }; let has_media = function(obj) { if (obj.entryId.contains("tweet")) { return obj.content.itemContent.tweet_results.result.legacy.entities.hasOwnProperty('media'); } return true; }; let update_data = function(data) { if (show_all || location.pathname != '/home') { return; } for (let obj of find_objects_at_keys(data, ['instructions'])) { for (let subobj of obj) { subobj.entries = subobj.entries.filter(has_media); } }; }; // Intercept JSON parses to alter the sensitive media data. let old_parse = unsafeWindow.JSON.parse; let new_parse = function(string) { let data = old_parse(string); try { if (data != null) { update_data(data); } } catch(error) { console.log(error); } return data; }; exportFunction(new_parse, unsafeWindow.JSON, { defineAs: "parse" }); // Wait for twitter's react crap finish loading things. let scan_interval = setInterval(function() { let target = document.body.querySelector("h1[role='heading']"); if (target) { clearInterval(scan_interval); create_ui(target); } }, 10); })();