Twitter 图片查看增强

让推特图片浏览更加人性化

目前为 2020-03-27 提交的版本,查看 最新版本

  1. // 注意 NOTICE
  2. // v0.5.1 开始包含一些重大更新,如果你的推特界面语言不是 简体中文、繁体中文、英语、日语 中的一个,请访问脚本主页以了解这一变更,否则你可能无法正常使用。
  3. // There are some significant changes in v0.5.1, please visit the homepage of this script for more information if your twitter display language is not one of English, Japanese, Simplified Chinese, Traditional Chinese.
  4. // ==UserScript==
  5. // @name Twitter image viewing enhancement
  6. // @name:zh-CN Twitter 图片查看增强
  7. // @name:zh-TW Twitter 圖像查看增強
  8. // @icon https://twitter.com/favicon.ico
  9. // @namespace https://moe.best/
  10. // @version 0.5.1
  11. // @description Make Twitter photo viewing more humane
  12. // @description:zh-CN 让推特图片浏览更加人性化
  13. // @description:zh-TW 讓 Twitter 照片瀏覽更人性化
  14. // @author Jindai Kirin
  15. // @include https://twitter.com/*
  16. // @license MIT
  17. // @grant GM_getValue
  18. // @grant GM_setValue
  19. // @grant GM_registerMenuCommand
  20. // @grant GM_openInTab
  21. // @run-at document-end
  22. // @require https://cdn.jsdelivr.net/npm/jquery@3.4.1/dist/jquery.min.js
  23. // @require https://cdn.jsdelivr.net/npm/jquery-mousewheel@3.1.13/jquery.mousewheel.min.js
  24. // ==/UserScript==
  25.  
  26. (function() {
  27. 'use strict';
  28.  
  29. const safetyParseJSON = str => {
  30. try {
  31. return JSON.parse(str);
  32. } catch (error) {}
  33. };
  34.  
  35. const defaultLabelsByLang = {
  36. zh: { close: '关闭', prev: '上一个', next: '下一步' },
  37. 'zh-Hant': { close: '關閉', prev: '上一個', next: '下一步' },
  38. en: { close: 'Close', prev: 'Previous', next: 'Next' },
  39. ja: { close: '閉じる', prev: '前', next: '次' },
  40. };
  41.  
  42. const defaultLabels = defaultLabelsByLang[$('html').attr('lang')] || defaultLabelsByLang.zh;
  43. const labels = (() => {
  44. const setting = GM_getValue('labels', '');
  45. return setting ? safetyParseJSON(setting) || defaultLabels : defaultLabels;
  46. })();
  47. console.log('aria-labels', labels);
  48. GM_registerMenuCommand('Set aria-labels', () => {
  49. let input, list;
  50. let error = false;
  51. do {
  52. const current = GM_getValue('labels', '');
  53. input = prompt(`Please input the aria-label of Close, Previous, Next button and join them by comma (,). Submit an empty string will reset it to default.${error ? '\n\nINPUT ERROR' : ''}`, input || current ? Object.values(safetyParseJSON(current) || {}).join(',') : '');
  54. if (input === null) return;
  55. input = input.trim();
  56. if (input.length === 0) list = Object.values(defaultLabels);
  57. else list = input.split(',').map(label => label.trim());
  58. error = list.length !== Object.keys(labels).length;
  59. } while (error);
  60. Object.keys(labels).forEach((key, index) => {
  61. labels[key] = list[index];
  62. });
  63. GM_setValue('labels', input.length ? JSON.stringify(labels) : '');
  64. console.log('aria-labels-setting', GM_getValue('labels'));
  65. console.log('aria-labels', labels);
  66. });
  67.  
  68. const getBtnByLabel = label => $(`div[aria-labelledby="modal-header"] div[aria-label="${label}"]`);
  69.  
  70. const closeImgView = () => {
  71. const $btn = getBtnByLabel(labels.close);
  72. if ($btn.length) $btn.click();
  73. else if (confirm("It seems that you haven't set the right aria-labels yet. Please visit the homepage of this script for more information.")) GM_openInTab('https://greasyfork.org/zh-CN/scripts/387918', false);
  74. };
  75. const prevImg = () => getBtnByLabel(labels.prev).click();
  76. const nextImg = () => getBtnByLabel(labels.next).click();
  77.  
  78. $(document).mousewheel(({ deltaY, target: { tagName, baseURI } }) => {
  79. if (tagName == 'IMG' && /\/photo\//.test(baseURI)) {
  80. switch (deltaY) {
  81. case 1:
  82. prevImg();
  83. break;
  84. case -1:
  85. nextImg();
  86. break;
  87. }
  88. }
  89. });
  90.  
  91. let x = 0;
  92. let y = 0;
  93. $(document).mousedown(({ clientX, clientY }) => {
  94. x = clientX;
  95. y = clientY;
  96. });
  97. $(document).mouseup(({ button, clientX, clientY, target: { tagName, baseURI } }) => {
  98. if (button !== 0 || !(tagName == 'IMG' && /\/photo\//.test(baseURI))) return;
  99. const [sx, sy] = [clientX - x, clientY - y].map(Math.abs);
  100. const mx = clientX - x;
  101. if (sx <= 10 && sy <= 10) closeImgView();
  102. if (sy <= sx) {
  103. if (mx > 0) prevImg();
  104. else if (mx < 0) nextImg();
  105. }
  106. });
  107. })();