x-twitter-add-to-list-button

1-click "add user to [xyz] list" button next to usernames while scrolling your x (twitter) feed (be sure to edit the variable "lists")

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

  1. // ==UserScript==
  2. // @name x-twitter-add-to-list-button
  3. // @name:ja x-twitter-add-to-list-button
  4. // @namespace x-twitter
  5. // @version 0.1.0
  6. // @description 1-click "add user to [xyz] list" button next to usernames while scrolling your x (twitter) feed (be sure to edit the variable "lists")
  7. // @description:ja リストにワンクリックで追加するボタンを表示します(変数"lists"を必ず編集してください)
  8. // @author fuwawascoco
  9. // @match https://twitter.com/*
  10. // @match https://mobile.twitter.com/*
  11. // @match https://x.com/*
  12. // @icon https://www.google.com/s2/favicons?sz=64&domain=twitter.com
  13. // @grant none
  14. // @license MIT
  15. // ==/UserScript==
  16.  
  17. // original script from https://greasyfork.org/en/scripts/485053-twitter-add-to-list-button
  18.  
  19. (function() {
  20. 'use strict';
  21.  
  22. const lists = ['test','illustrators','animators']; // be sure to change to the NAME of your lists (not IDs)
  23. // too many lists or too long names will look ugly so you can either
  24. // 1) shorten list names
  25. // 2) limit to few lists
  26. // 3) fix css below
  27.  
  28. const checkInterval = 512; // ms
  29. const tryInterval = 64; // ms
  30.  
  31.  
  32. function onClick(userProfile, list) {
  33. const newTab = open(userProfile);
  34. const intervalID = setInterval(()=>{
  35.  
  36. const moreButton = newTab.document.querySelector('div[aria-label="More"]');
  37. if (moreButton === null) return;
  38. clearInterval(intervalID);
  39. moreButton.click();
  40.  
  41. const listButton = newTab.document.querySelector('[href="/i/lists/add_member"]');
  42. listButton.click();
  43.  
  44. const listIntervalID = setInterval(()=>{
  45. const modal = newTab.document.querySelector('[aria-modal="true"]');
  46. if (modal === null) return;
  47.  
  48. const spans = modal.getElementsByTagName('span');
  49. let theListNameSpan = null;
  50. for (let i = 0; i < spans.length; ++i) {
  51. if (spans[i].textContent !== list) continue;
  52. theListNameSpan = spans[i];
  53. break;
  54. }
  55. if (theListNameSpan === null) {
  56. const checkbox = modal.querySelector('[aria-checked]');
  57. if (checkbox === null) return;
  58.  
  59. newTab.alert(`"${list}" was not found`);
  60. newTab.close();
  61. clearInterval(listIntervalID);
  62. return;
  63. }
  64. clearInterval(listIntervalID);
  65.  
  66. let checkbox = theListNameSpan;
  67. while (!checkbox.hasAttribute('aria-checked')) {
  68. checkbox = checkbox.parentElement;
  69. }
  70. if (checkbox.ariaChecked === 'false') {
  71. checkbox.click();
  72.  
  73. const saveButton = spans[2];
  74. saveButton.click();
  75. }
  76.  
  77. newTab.close();
  78. }, tryInterval);
  79. }, tryInterval);
  80. }
  81.  
  82.  
  83. function ListButton(userProfile, list) {
  84. const button = document.createElement('button');
  85. const styles = {
  86. fontSize: '90%',
  87. margin: '0 0.25em',
  88. };
  89. for (const prop in styles) {
  90. button.style[prop] = styles[prop];
  91. }
  92. button.textContent = list;
  93. button.addEventListener('click', onClick.bind(null, userProfile, list));
  94. return button;
  95. }
  96.  
  97.  
  98. function ListButtons(userProfile) {
  99. const buttons = document.createElement('div');
  100. const styles = {
  101. position: 'relative',
  102. left: '2%',
  103. opacity: 0.5,
  104. };
  105. for (const prop in styles) {
  106. buttons.style[prop] = styles[prop];
  107. }
  108. lists.forEach(list => {
  109. buttons.appendChild(ListButton(userProfile, list));
  110. });
  111. buttons.classList.add('listButtons');
  112. return buttons;
  113. }
  114.  
  115.  
  116. function addButtons() {
  117. const selector = '[data-testid="User-Name"]:not(:has(.listButtons))';
  118. const nodes = document.querySelectorAll(selector);
  119. nodes.forEach(node => {
  120. let userProfile = '';
  121. function rec(children) {
  122. for (const child of children) {
  123. if (child.nodeName === 'A') {
  124. userProfile = child.href;
  125. return;
  126. }
  127. rec(child.childNodes);
  128. if (userProfile !== '') return;
  129. }
  130. }
  131. rec(node.childNodes);
  132. node.appendChild(ListButtons(userProfile));
  133. });
  134. }
  135.  
  136.  
  137. setInterval(addButtons, checkInterval)
  138.  
  139. })();