Twitter - own tweets

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

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

// ==UserScript==
// @name     Twitter - own tweets
// @version  2
// @grant    none
// @require  https://cdn.jsdelivr.net/npm/[email protected]/dist/jquery.min.js
// @match    https://twitter.com/*
// @author   monnef
// @description Adds a link to users' pages to search for tweets only from them (no retweets without comment).
// @namespace   monnef.eu
// ==/UserScript==

// config
const debug = false;
const numberOfAttempts = 5;
const workInterval = 1000;
// end of config

const linkMarker = 'monnef--no-retweets';
const dLog = (...xs) => debug && console.log('[OwnTweets]', ...xs);
const state = { lastUrl: null, attempts: 0 };

const insertLink = (nameEl) => {
  if (nameEl.parent().find(`.${linkMarker}`).length) return;
  const handle = nameEl.text();
  const linkEl = $("<a/>")
    .attr('href', `/search?q=from%3A%40${handle.slice(1)}&src=typed_query`)
    .text('own tweets')
    .addClass(linkMarker)
    .css('color', 'rgb(29, 161, 242)')
    .css('margin-left', '0.5em')
  ;
  nameEl.after(linkEl);
};

const isHandleEl = (el) => el.length && el.text().startsWith('@');

const tryGetAndProcessNameEl = (x, y) => {
  const nameEl = $(document.elementFromPoint(x, y));
  const handle = nameEl.text();
  dLog('tryGetAndProcessNameEl', x, y, ';nameEl', nameEl, ';handle', handle);
  if (isHandleEl(nameEl)) {
    state.attempts = numberOfAttempts;
    insertLink(nameEl);
    return true;
  } else {
    return false;
  }
}

const work = () => {
  const curUrl = window.location.href;
  if (state.lastUrl === curUrl) {
    state.attempts++;
    if (state.attempts >= numberOfAttempts) {
    	dLog('work - url didn\'t change, skipping');
    	return;
    }
  } else {
    state.attempts = 0;
  }
  dLog('work', curUrl, state.lastUrl, state.attempts);
  state.lastUrl = curUrl;
  // fragile as !@&# bc all twitter's css classes are obfuscated >:(
  const primEl = $('main > div > div > div > div:first-child');
  const followEl = $('[role=button]:contains(Follow)', primEl);
  const userInfoEl = followEl.parent().parent().parent().parent().parent();
  const uiPos = userInfoEl.offset()
  dLog('work', 'primEl', primEl, ';followEl', followEl, ';userInfoEl', userInfoEl, ';uiPos', uiPos);
  if (!tryGetAndProcessNameEl(uiPos.left + 20, uiPos.top + 90)) {
    // uncommon case when name is handle (e.g. https://twitter.com/TodfromPa)
    tryGetAndProcessNameEl(uiPos.left + 20, uiPos.top + 70);
  }
}

$(() => setInterval(work, workInterval))