Twitter media-only filter toggle.

Toggle non-media tweets on and off on the home timeline, for the power-viewer!

当前为 2024-09-04 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Twitter media-only filter toggle.
  3. // @version 0.16
  4. // @description Toggle non-media tweets on and off on the home timeline, for the power-viewer!
  5. // @author Cro
  6. // @match https://*.twitter.com/*
  7. // @match https://*.x.com/*
  8. // @run-at document-idle
  9. // @grant GM_setValue
  10. // @grant GM_getValue
  11. // @namespace https://greasyfork.org/users/10865
  12. // @icon https://www.google.com/s2/favicons?domain=twitter.com
  13. // @license MIT
  14. // ==/UserScript==
  15. /* jshint esversion: 6 */
  16.  
  17. (function() {
  18. let storage_key = "cro-media-toggle";
  19. let show_all = GM_getValue(storage_key);
  20.  
  21. let create_ui = function(target)
  22. {
  23. let button = document.createElement("button");
  24. button.innerText = show_all ? "Showing all home tweets" : "Showing only media home tweets";
  25.  
  26. button.onclick = function(event)
  27. {
  28. show_all = !show_all;
  29. GM_setValue(storage_key, show_all);
  30. location.reload();
  31. };
  32.  
  33. target.prepend(button);
  34. };
  35.  
  36. let find_objects_at_keys = function(obj, keys)
  37. {
  38. let found = [];
  39. let stack = Object.entries(obj);
  40. while (stack.length > 0)
  41. {
  42. let current = stack.pop();
  43. if (keys.includes(current[0]))
  44. {
  45. found.push(current[1]);
  46. }
  47. if (current[1] != null && typeof(current[1]) == 'object')
  48. {
  49. stack = stack.concat(Object.entries(current[1]));
  50. }
  51. }
  52. return found;
  53. };
  54.  
  55. let has_media = function(obj)
  56. {
  57. if (obj.entryId.includes("tweet"))
  58. {
  59. return obj?.content?.itemContent?.tweet_results?.result?.legacy?.entities?.hasOwnProperty('media');
  60. }
  61. return true;
  62. };
  63.  
  64. let update_data = function(data)
  65. {
  66. if (show_all || location.pathname != '/home')
  67. {
  68. return;
  69. }
  70. for (let obj of find_objects_at_keys(data, ['instructions']))
  71. {
  72. for (let subobj of obj)
  73. {
  74. if (subobj.hasOwnProperty('entries'))
  75. {
  76. subobj.entries = subobj.entries.filter(has_media);
  77. }
  78. }
  79. }
  80. };
  81.  
  82. let old_parse = unsafeWindow.JSON.parse;
  83. let new_parse = function(string)
  84. {
  85. let data = JSON.parse(string);
  86. try
  87. {
  88. if (data != null)
  89. {
  90. update_data(data);
  91. }
  92. }
  93. catch(error)
  94. {
  95. console.log(error);
  96. }
  97. return old_parse(JSON.stringify(data));;
  98. };
  99. exportFunction(new_parse, unsafeWindow.JSON, { defineAs: "parse" });
  100.  
  101. // Wait for twitter's react crap finish loading things.
  102. let scan_interval = setInterval(function()
  103. {
  104. let target = document.body.querySelector("nav[role='navigation']");
  105. if (target)
  106. {
  107. clearInterval(scan_interval);
  108. create_ui(target);
  109. }
  110. }, 10);
  111. })();