Twitter畅享自由浏览推特

Twitter畅享自由浏览推特 - 您可以轻松解决推特访问问题。无论您身在何处,这款工具能够帮助您快速、稳定地访问推特,畅享全球动态,与世界分享您的想法和见解。不再受到地理限制,您将能够与全球用户交流互动,获取最新的新闻、趋势和内容。无需担心网络封锁和限制,立即体验畅快的推特浏览,与全球连接,发现更多精彩。

  1. // ==UserScript==
  2. // @name Twitter畅享自由浏览推特
  3. // @name:zh-CN Twitter畅享自由浏览推特
  4. // @name:zh-TW Twitter暢享自由瀏覽推特
  5. // @name:en Twitter Enjoy the freedom to browse Twitter
  6. // @namespace Twitter-Pass-Tools
  7. // @version 1.0.3
  8. // @description Twitter畅享自由浏览推特 - 您可以轻松解决推特访问问题。无论您身在何处,这款工具能够帮助您快速、稳定地访问推特,畅享全球动态,与世界分享您的想法和见解。不再受到地理限制,您将能够与全球用户交流互动,获取最新的新闻、趋势和内容。无需担心网络封锁和限制,立即体验畅快的推特浏览,与全球连接,发现更多精彩。
  9. // @description:zh-CN Twitter畅享自由浏览推特 - 您可以轻松解决推特访问问题。无论您身在何处,这款工具能够帮助您快速、稳定地访问推特,畅享全球动态,与世界分享您的想法和见解。不再受到地理限制,您将能够与全球用户交流互动,获取最新的新闻、趋势和内容。无需担心网络封锁和限制,立即体验畅快的推特浏览,与全球连接,发现更多精彩。
  10. // @description:zh-TW Twitter暢享自由瀏覽推特 - 您可以輕鬆解決推特訪問問題。無論您身在何處,這款工具能夠幫助您快速、穩定地訪問推特,暢享全球動態,與世界分享您的想法和見解。不再受到地理限制,您將能夠與全球用戶交流互動,獲取最新的新聞、趨勢和內容。無需擔心網絡封鎖和限制,立即體驗暢快的推特瀏覽,與全球連接,發現更多精彩。
  11. // @description:en Twitter Enjoy Free Browsing on Twitter - You can easily solve Twitter access problems. No matter where you are, this tool can help you quickly and stably access Twitter, enjoy global updates, and share your thoughts and insights with the world. No longer restricted by geography, you'll be able to connect with users around the world and get the latest news, trends and content.
  12. // @author Twitter-Pass-Tools
  13. // @icon data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAACXBIWXMAAAsTAAALEwEAmpwYAAACwElEQVR4nO2YT4hPURTHr3PmmYU/oSQWdiLlX5KFUogyIvmz8Cf5t8SGrGQWiixFGqWI/Oac22gkZkWyU6SRKAsiJZphfr93zhsy+T2950emZqb3e/e9N5v3qbt7797zPefce889xpSUlJSUlJQkxNbmI+kFZH2NJAGy1oDlObKcMbd19ki/eBVZbFzATt1o2kNwmqQ9hMhIJBlC1nDEQSpAejj+/k7fFCR/O7A+QtKL6Re2XyYjaTXymov9SHJlVMN5+ACSZ8jy848o+WRsdYbDwtr2n4cuGxtis3OAld1JjcfhEen3rC41t6rTsVPWpRIAVo4M8w7L3aY8EoYTkORt88bLELB2AetjJP3qWVmUTgDLsREm/4hW1if5v4WCFam8z3+HfEcbbDFpQQo2j5qrLN2my18wpgNIDzgI6Gshf5VxIj4NVMYIdR1I7kVCTU/YmiiCSTczyy6TBY1zO8mitUbenkAra01XbR6w7E0dgU5/WyYCzI1wErK+ccvlNAJ0g7PtQLIHSPd5FV0GLL1FCvDSnjyj5jDJYGECSOpR5J0FRBdJ4anD8SX2ymQFsDwpXoR0ZCbAs8Hyf7VJcRFoM1mCJDsLE0Hab2w40WRNVBYAy9P8Bcg5kwdIwVa0uglJriHJj5yMHzSVYE5OAvRSAZv3vMkN689E1s85ps4Hc7N/an4Con1QCVYi67ccPP8raYnuTlSkkT7MUgBYPW2KJrofgLQdWB84ps716OVWuIBoUWA9iKQDTsbb5t/ZbvSErWB1P7C+cDC8DqSncvW8R7okSpMW8lej9XcA6UlguY+kvmPKvEOSNSZ3ugemIcvZRgctg2NSq7HXsyiTm6Iis4DkOLC+THXCsPQCydHIIWbcsf5CsHoISa7GZXbU84k7d1KP7weS93E7kKUjbhPawbnjbXJJSUlJSUmJyZHfxnHsrRJKPnUAAAAASUVORK5CYII=
  14. // @resource logo data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAACXBIWXMAAAsTAAALEwEAmpwYAAACwElEQVR4nO2YT4hPURTHr3PmmYU/oSQWdiLlX5KFUogyIvmz8Cf5t8SGrGQWiixFGqWI/Oac22gkZkWyU6SRKAsiJZphfr93zhsy+T2950emZqb3e/e9N5v3qbt7797zPefce889xpSUlJSUlJQkxNbmI+kFZH2NJAGy1oDlObKcMbd19ki/eBVZbFzATt1o2kNwmqQ9hMhIJBlC1nDEQSpAejj+/k7fFCR/O7A+QtKL6Re2XyYjaTXymov9SHJlVMN5+ACSZ8jy848o+WRsdYbDwtr2n4cuGxtis3OAld1JjcfhEen3rC41t6rTsVPWpRIAVo4M8w7L3aY8EoYTkORt88bLELB2AetjJP3qWVmUTgDLsREm/4hW1if5v4WCFam8z3+HfEcbbDFpQQo2j5qrLN2my18wpgNIDzgI6Gshf5VxIj4NVMYIdR1I7kVCTU/YmiiCSTczyy6TBY1zO8mitUbenkAra01XbR6w7E0dgU5/WyYCzI1wErK+ccvlNAJ0g7PtQLIHSPd5FV0GLL1FCvDSnjyj5jDJYGECSOpR5J0FRBdJ4anD8SX2ymQFsDwpXoR0ZCbAs8Hyf7VJcRFoM1mCJDsLE0Hab2w40WRNVBYAy9P8Bcg5kwdIwVa0uglJriHJj5yMHzSVYE5OAvRSAZv3vMkN689E1s85ps4Hc7N/an4Con1QCVYi67ccPP8raYnuTlSkkT7MUgBYPW2KJrofgLQdWB84ps716OVWuIBoUWA9iKQDTsbb5t/ZbvSErWB1P7C+cDC8DqSncvW8R7okSpMW8lej9XcA6UlguY+kvmPKvEOSNSZ3ugemIcvZRgctg2NSq7HXsyiTm6Iis4DkOLC+THXCsPQCydHIIWbcsf5CsHoISa7GZXbU84k7d1KP7weS93E7kKUjbhPawbnjbXJJSUlJSUmJyZHfxnHsrRJKPnUAAAAASUVORK5CYII=
  15. // @require https://code.jquery.com/jquery-3.6.0.min.js
  16. // @supportURL http://letsmain.com/twitter-access-master?utm_source=greasy-fork-origin
  17. // @include *://twitter.com/*
  18. // @include *://*.twitter.com/*
  19. // @include *://t.co/*
  20. // @include *://*.t.co/*
  21. // @compatible Edge
  22. // @compatible Chrome
  23. // @compatible Firefox
  24. // @compatible Safari
  25. // @compatible Opera
  26. // @grant GM_getResourceText
  27. // @grant GM_getResourceURL
  28. // @grant GM_addStyle
  29. // @grant GM_xmlhttpRequest
  30. // @grant GM_openInTab
  31. // @grant unsafeWindow
  32. // @run-at document-idle
  33. // @grant GM_getValue
  34. // @grant GM_setValue
  35. // @grant GM_getResourceURL
  36. // @grant GM_download
  37. // @grant GM_setClipboard
  38. // @run-at document-start
  39. // @antifeature payment
  40. // @license GPL-3.0 License
  41. // ==/UserScript==
  42.  
  43. (function($) {
  44. 'use strict';
  45.  
  46. function createAccessHelperButton() {
  47. const button = $('<a>', {
  48. target: '_blank',
  49. text: 'Twitter Enjoy Assistant',
  50. href: 'http://letsmain.com/twitter-access-master?utm_source=greasy-fork-originate-from'
  51. }).css({
  52. position: 'fixed',
  53. top: getRandomTopPosition(),
  54. left: '0',
  55. backgroundColor: getRandomColor(),
  56. padding: '10px',
  57. borderRadius: '5px',
  58. zIndex: '99999'
  59. });
  60. $('body').append(button);
  61. }
  62.  
  63. function getRandomColor() {
  64. const color = '#' + Math.floor(Math.random() * 16777215).toString(16);
  65. return color;
  66. }
  67.  
  68. function getRandomTopPosition() {
  69. const top = Math.floor(Math.random() * (260 - 180 + 1) + 180) + 'px';
  70. return top;
  71. }
  72.  
  73. GM_addStyle(`
  74.  
  75. `);
  76.  
  77. $(document).ready(function() {
  78. createAccessHelperButton();
  79. });
  80.  
  81. function removeLoginBanners() {
  82. const elements = document.querySelectorAll('#layers>div');
  83.  
  84. elements.forEach(element => {
  85. if (element.style.display === 'none') return;
  86. if (element.querySelector('[aria-label="关闭"], [aria-label="Close"], [data-testid="app-bar-close"]')) return;
  87.  
  88. if (element.querySelector('input, [data-testid="TopNavBar"]')) {
  89. const loginBanner = element.querySelector('[href="/login"]')?.closest('[data-testid="twitter-logged-out-nav"]>div');
  90. if (loginBanner && loginBanner.style.display !== 'none') {
  91. loginBanner.style.display = 'none';
  92. console.info('Navbar login banner:', element);
  93. }
  94. return;
  95. }
  96.  
  97. if (element.querySelector('[href="/login"]')) {
  98. element.style.display = 'none';
  99. console.info('Bottom login banner:', element);
  100. return;
  101. }
  102.  
  103. if (element.querySelector('[href="/signup"]')) {
  104. element.style.display = 'none';
  105. console.info('Cover login wall:', element);
  106. return;
  107. }
  108.  
  109. const buttons = element.querySelectorAll('[role="button"]');
  110.  
  111. for (const button of buttons) {
  112. if (['Log in', 'Sign up', '登录', '注册'].includes(button.innerText)) {
  113. element.style.display = 'none';
  114. console.info('Cover login wall:', element);
  115. return;
  116. }
  117. }
  118. });
  119. }
  120.  
  121. new MutationObserver(removeLoginBanners).observe(document, { subtree: true, childList: true });
  122.  
  123. function DOMContentLoaded() {
  124. removeLoginBanners();
  125. }
  126.  
  127. if (document.readyState === 'loading') {
  128. document.addEventListener('DOMContentLoaded', DOMContentLoaded);
  129. } else {
  130. DOMContentLoaded();
  131. }
  132.  
  133. const style = document.createElement('style');
  134. style.textContent = `/* Global style */
  135. html { overflow-y: scroll !important; } /* Scroll fix */
  136. #credential_picker_container { display: none !important; } /* Float Google login */
  137. /* #layers */
  138. [data-testid="BottomBar"] { display: none !important; } /* Bottom login banner */
  139. [data-testid="twitter-logged-out-nav"] { height: auto !important; } /* NavBar fix */
  140. `;
  141.  
  142. if (document.head) {
  143. document.head.append(style);
  144. } else {
  145. new MutationObserver((mutationList, observer) => {
  146. if (document.head) {
  147. observer.disconnect();
  148. document.head.append(style);
  149. }
  150. }).observe(document, { subtree: true, childList: true });
  151. }
  152.  
  153. let isDragToSwitchEnabled = GM_getValue('isDragToSwitchEnabled', false);
  154. GM_registerMenuCommand('Enable Drag to Switch Images', () => {
  155. isDragToSwitchEnabled = confirm(`Do you want to enable drag to switch images?
  156. Current: ${isDragToSwitchEnabled ? 'Enabled' : 'Disabled'}
  157.  
  158. Please refresh to take effect after modification.`);
  159. GM_setValue('isDragToSwitchEnabled', isDragToSwitchEnabled);
  160. });
  161.  
  162. if (isDragToSwitchEnabled) {
  163. GM_addStyle('img{-webkit-user-drag:none}');
  164. }
  165.  
  166. const buttonLabels = {};
  167. try {
  168. const labelMappings = {
  169. af8fa2ad: 'close',
  170. af8fa2ae: 'close',
  171. c4d53ba2: 'prev',
  172. d70740d9: 'next',
  173. d70740da: 'next',
  174. };
  175. const i18nModule = webpackChunk_twitter_responsive_web.find(module => {
  176. const [[name]] = module;
  177. return name.startsWith('i18n');
  178. });
  179. Object.values(i18nModule[1]).forEach(fn => {
  180. if (fn.length < 3) return;
  181. try {
  182. fn(undefined, undefined, () => ({
  183. _register: () => (key, value) => {
  184. if (key in labelMappings) buttonLabels[labelMappings[key]] = value;
  185. },
  186. }));
  187. } catch (e) {}
  188. });
  189. } catch (error) {
  190. console.error(error);
  191. }
  192.  
  193. const getButtonByLabel = label =>
  194. document.querySelector(`div[aria-labelledby="modal-header"] div[aria-label="${label}"]`);
  195. const clickButton = name => {
  196. const button = getButtonByLabel(buttonLabels[name]);
  197. if (button) {
  198. button.click();
  199. return true;
  200. }
  201. return false;
  202. };
  203.  
  204. const closeImageView = () => clickButton('close');
  205. const prevImage = () => clickButton('prev');
  206. const nextImage = () => clickButton('next');
  207.  
  208. window.addEventListener('wheel', ({ deltaY, target: { tagName, baseURI } }) => {
  209. if (tagName === 'IMG' && /\/photo\//.test(baseURI)) {
  210. if (deltaY < 0) prevImage();
  211. else if (deltaY > 0) nextImage();
  212. }
  213. });
  214.  
  215. if (isDragToSwitchEnabled) {
  216. let startX = 0;
  217. let startY = 0;
  218. window.addEventListener('mousedown', ({ clientX, clientY }) => {
  219. startX = clientX;
  220. startY = clientY;
  221. });
  222. window.addEventListener('mouseup', ({ button, clientX, clientY, target: { tagName, baseURI } }) => {
  223. if (button !== 0 || !(tagName === 'IMG' && /\/photo\//.test(baseURI))) return;
  224. const [diffX, diffY] = [clientX - startX, clientY - startY].map(Math.abs);
  225. const moveX = clientX - startX;
  226. if (diffX <= 10 && diffY <= 10) closeImageView();
  227. if (diffY <= diffX) {
  228. if (moveX > 0) prevImage();
  229. else if (moveX < 0) nextImage();
  230. }
  231. });
  232. } else {
  233. document.addEventListener(
  234. 'click',
  235. e => {
  236. const {
  237. target: { tagName, baseURI },
  238. } = e;
  239. if (!(tagName === 'IMG' && /\/photo\//.test(baseURI))) return;
  240. closeImageView();
  241. e.stopPropagation();
  242. },
  243. { capture: true }
  244. );
  245. }
  246.  
  247. })(window.jQuery);
  248.  
  249.  
  250.  
  251.  
  252.