Twitter - own tweets

Adds a link to users' pages to search for tweets only from them (no retweets without comment).

目前为 2020-06-17 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Twitter - own tweets
  3. // @version 2
  4. // @grant none
  5. // @require https://cdn.jsdelivr.net/npm/jquery@3.4.1/dist/jquery.min.js
  6. // @match https://twitter.com/*
  7. // @author monnef
  8. // @description Adds a link to users' pages to search for tweets only from them (no retweets without comment).
  9. // @namespace monnef.eu
  10. // ==/UserScript==
  11.  
  12. // config
  13. const debug = false;
  14. const numberOfAttempts = 5;
  15. const workInterval = 1000;
  16. // end of config
  17.  
  18. const linkMarker = 'monnef--no-retweets';
  19. const dLog = (...xs) => debug && console.log('[OwnTweets]', ...xs);
  20. const state = { lastUrl: null, attempts: 0 };
  21.  
  22. const insertLink = (nameEl) => {
  23. if (nameEl.parent().find(`.${linkMarker}`).length) return;
  24. const handle = nameEl.text();
  25. const linkEl = $("<a/>")
  26. .attr('href', `/search?q=from%3A%40${handle.slice(1)}&src=typed_query`)
  27. .text('own tweets')
  28. .addClass(linkMarker)
  29. .css('color', 'rgb(29, 161, 242)')
  30. .css('margin-left', '0.5em')
  31. ;
  32. nameEl.after(linkEl);
  33. };
  34.  
  35. const isHandleEl = (el) => el.length && el.text().startsWith('@');
  36.  
  37. const tryGetAndProcessNameEl = (x, y) => {
  38. const nameEl = $(document.elementFromPoint(x, y));
  39. const handle = nameEl.text();
  40. dLog('tryGetAndProcessNameEl', x, y, ';nameEl', nameEl, ';handle', handle);
  41. if (isHandleEl(nameEl)) {
  42. state.attempts = numberOfAttempts;
  43. insertLink(nameEl);
  44. return true;
  45. } else {
  46. return false;
  47. }
  48. }
  49.  
  50. const work = () => {
  51. const curUrl = window.location.href;
  52. if (state.lastUrl === curUrl) {
  53. state.attempts++;
  54. if (state.attempts >= numberOfAttempts) {
  55. dLog('work - url didn\'t change, skipping');
  56. return;
  57. }
  58. } else {
  59. state.attempts = 0;
  60. }
  61. dLog('work', curUrl, state.lastUrl, state.attempts);
  62. state.lastUrl = curUrl;
  63. // fragile as !@&# bc all twitter's css classes are obfuscated >:(
  64. const primEl = $('main > div > div > div > div:first-child');
  65. const followEl = $('[role=button]:contains(Follow)', primEl);
  66. const userInfoEl = followEl.parent().parent().parent().parent().parent();
  67. const uiPos = userInfoEl.offset()
  68. dLog('work', 'primEl', primEl, ';followEl', followEl, ';userInfoEl', userInfoEl, ';uiPos', uiPos);
  69. if (!tryGetAndProcessNameEl(uiPos.left + 20, uiPos.top + 90)) {
  70. // uncommon case when name is handle (e.g. https://twitter.com/TodfromPa)
  71. tryGetAndProcessNameEl(uiPos.left + 20, uiPos.top + 70);
  72. }
  73. }
  74.  
  75. $(() => setInterval(work, workInterval))