All X(Twitter) Images

Download all original images on X media time-line

  1. // ==UserScript==
  2. // @name All X(Twitter) Images
  3. // @namespace http://tampermonkey.net/
  4. // @version 1.2
  5. // @description Download all original images on X media time-line
  6. // @author Jimmy Chen
  7. // @match https://x.com/*/media*
  8. // @match https://twitter.com/*/media*
  9. // @icon https://www.google.com/s2/favicons?sz=64&domain=x.com
  10. // @grant GM_download
  11. // @run-at document-idle
  12. // @license MIT
  13.  
  14.  
  15. // ==/UserScript==
  16.  
  17. let user = '';
  18. let lastHeight = 0;
  19. let observer = new MutationObserver(resetTimer);
  20. let timer = setTimeout(action, 2000, observer);
  21. clearTimeout(timer);
  22. let images = {};
  23.  
  24. function addButton(text, onclick, cssObj, id) {
  25. const defaultCSS = {position: 'fixed', top: '7%', left:'50%', 'z-index': 3,
  26. "background-color": "#57cff7", "color": "white",
  27. "padding": "10px", "border": "0px",
  28. "font-size": "1rem","font-weight": "bold" }
  29. cssObj = Object.assign(defaultCSS, cssObj || {} )
  30. let button = document.createElement('button'), btnStyle = button.style;
  31. document.body.appendChild(button)
  32. button.innerHTML = text;
  33. button.onclick = onclick
  34. btnStyle.position = 'fixed';
  35. button.id = id;
  36. Object.keys(cssObj).forEach(key => btnStyle[key] = cssObj[key]);
  37. return button;
  38. }
  39.  
  40. function resetTimer(changes, observer) {
  41. clearTimeout(timer);
  42. timer = setTimeout(action, 2000, observer);
  43. }
  44.  
  45. function scrollToBottom() {
  46. window.scrollBy(0, window.innerHeight);
  47. //console.log("scroll to " + window.scrollY);
  48. //console.log("document height: " + document.body.scrollHeight);
  49. }
  50.  
  51. function action(observer) {
  52. getImageUrl();
  53. scrollToBottom();
  54. let currentHeight = window.scrollY + window.innerHeight;
  55. //console.log("current: " + currentHeight);
  56. if (currentHeight >= document.body.scrollHeight) {
  57. observer.disconnect();
  58. downloadAllImgs();
  59. return;
  60. }
  61. lastHeight = window.scrollHeight;
  62. }
  63.  
  64. function getImageUrl() {
  65. document.querySelectorAll('li[role="listitem"] img').forEach(image => {
  66. let url = URL.parse(image.src);
  67. let path = url.pathname.split('/').pop();
  68. let ext = url.searchParams.get('format');
  69. let name = user + '-' + path + '.' + ext;
  70. url.searchParams.set('name', 'large');
  71. images[name] = url.href;
  72. });
  73. }
  74.  
  75. function downloadAllImgs() {
  76. console.log("total images: " + Object.keys(images).length);
  77. Object.keys(images).forEach(key => {
  78. GM_download(images[key], key);
  79. });
  80. }
  81.  
  82. function begin() {
  83. observer.observe(document, {childList: true, subtree: true});
  84. scrollToBottom();
  85. }
  86.  
  87. (function() {
  88. 'use strict';
  89.  
  90. addButton("download all images", begin, {top: '7%'}, "a-begin-button");
  91.  
  92.  
  93. let fields = window.location.pathname.split('/');
  94. user = fields[1];
  95. })();