Twitter image viewing enhancement

Make Twitter photo viewing more humane

Od 13.05.2024.. Pogledajte najnovija verzija.

  1. // ==UserScript==
  2. // @name Twitter image viewing enhancement
  3. // @name:zh-CN Twitter 图片查看增强
  4. // @name:zh-TW Twitter 圖像查看增強
  5. // @icon https://twitter.com/favicon.ico
  6. // @namespace https://moe.best/
  7. // @version 1.3.0
  8. // @description Make Twitter photo viewing more humane
  9. // @description:zh-CN 让推特图片浏览更加人性化
  10. // @description:zh-TW 讓 Twitter 照片瀏覽更人性化
  11. // @author Jindai Kirin
  12. // @include https://twitter.com/*
  13. // @include https://mobile.twitter.com/*
  14. // @license MIT
  15. // @grant GM_addStyle
  16. // @grant GM_getValue
  17. // @grant GM_setValue
  18. // @grant GM_registerMenuCommand
  19. // @run-at document-end
  20. // ==/UserScript==
  21.  
  22. // 注意 NOTICE
  23. // v1.0.0 是一次重大更新,你将不再需要设置 aria-label,并且支持所有语言。如果某一天脚本突然无法正常工作,请于脚本页面反馈,或退回至 v0.6.3。
  24. // v1.0.0 is an major update, you will no longer need to set up aria-labels and it support all languages. If one day the script not work, please feedback on the script homepage or use v0.6.3.
  25.  
  26. (() => {
  27. 'use strict';
  28.  
  29. // 滑动切换图片
  30. let enableDragToSwitch = GM_getValue('enableDragToSwitch', false);
  31. GM_registerMenuCommand('Drag to switch images', () => {
  32. enableDragToSwitch = confirm(`Do you want to enable drag to switch images?
  33. Current: ${enableDragToSwitch ? 'Enabled' : 'Disabled'}
  34.  
  35. Please refresh to take effect after modification.`);
  36. GM_setValue('enableDragToSwitch', enableDragToSwitch);
  37. });
  38.  
  39. if (enableDragToSwitch) GM_addStyle('img{-webkit-user-drag:none}');
  40.  
  41. const labels = {};
  42. try {
  43. const kv = {
  44. af8fa2ad: 'close',
  45. af8fa2ae: 'close',
  46. c4d53ba2: 'prev',
  47. d70740d9: 'next',
  48. d70740da: 'next',
  49. };
  50. const i18nModule = webpackChunk_twitter_responsive_web.find(([[name]]) =>
  51. name.startsWith('i18n')
  52. );
  53. Object.values(i18nModule[1]).forEach(fn => {
  54. if (fn.length < 3) return;
  55. try {
  56. fn(undefined, undefined, () => ({
  57. _register: () => (k, v) => {
  58. if (k in kv) labels[kv[k]] = v;
  59. },
  60. }));
  61. } catch (e) {}
  62. });
  63. } catch (error) {
  64. console.error(error);
  65. }
  66.  
  67. const getBtnByLabel = label =>
  68. document.querySelector(`div[aria-labelledby="modal-header"] div[aria-label="${label}"]`);
  69. const clickBtn = name => {
  70. const $btn = getBtnByLabel(labels[name]);
  71. if ($btn) {
  72. $btn.click();
  73. return true;
  74. }
  75. return false;
  76. };
  77.  
  78. const closeImgView = () => clickBtn('close');
  79. const prevImg = () => clickBtn('prev');
  80. const nextImg = () => clickBtn('next');
  81.  
  82. /**
  83. * @param {HTMLElement} el
  84. */
  85. const isTwitterImg = el => el.tagName == 'IMG' && el.baseURI.includes('/photo/');
  86.  
  87. window.addEventListener(
  88. 'wheel',
  89. ({ deltaY, target }) => {
  90. if (isTwitterImg(target) || target.dataset.testid === 'swipe-to-dismiss') {
  91. if (deltaY < 0) prevImg();
  92. else if (deltaY > 0) nextImg();
  93. }
  94. },
  95. { passive: true }
  96. );
  97.  
  98. if (enableDragToSwitch) {
  99. let x = 0;
  100. let y = 0;
  101. window.addEventListener('mousedown', ({ clientX, clientY }) => {
  102. x = clientX;
  103. y = clientY;
  104. });
  105. window.addEventListener(
  106. 'mouseup',
  107. ({ button, clientX, clientY, target }) => {
  108. if (button !== 0 || !isTwitterImg(target)) return;
  109. const [sx, sy] = [clientX - x, clientY - y].map(Math.abs);
  110. const mx = clientX - x;
  111. if (sx <= 10 && sy <= 10) closeImgView();
  112. if (sy <= sx) {
  113. if (mx > 0) prevImg();
  114. else if (mx < 0) nextImg();
  115. }
  116. },
  117. { passive: true }
  118. );
  119. } else {
  120. document.addEventListener(
  121. 'click',
  122. e => {
  123. if (!isTwitterImg(e.target)) return;
  124. closeImgView();
  125. e.stopPropagation();
  126. },
  127. { capture: true, passive: true }
  128. );
  129. }
  130. })();