Emoji Tweet Buttons

ボタン一つで絵文字ツイートができます。

当前为 2024-05-28 提交的版本,查看 最新版本

// ==UserScript==
// @name         Emoji Tweet Buttons
// @namespace    http://tampermonkey.net/
// @version      1.0
// @description  ボタン一つで絵文字ツイートができます。
// @author       TwoSquirrels
// @license      MIT
// @match        https://twitter.com/*
// @match        https://x.com/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=x.com
// @grant        GM_getValue
// @grant        GM_setValue
// ==/UserScript==

// 指定したミリ秒待つ Promise 関数
const wait = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

// 絵文字設定
const EMOJI_PREFIX = 'background-image: url("https://abs.twimg.com/responsive-web/client-web-legacy/twemoji_sprite_high_res.8b274d9a.png"); ';
const emojis = GM_getValue("emojis", [
  EMOJI_PREFIX + "background-position: 0% 100%; background-size: 5000% 7200%;",
  EMOJI_PREFIX + "background-position: 95.9184% 18.3099%; background-size: 5000% 7200%;",
  EMOJI_PREFIX + "background-position: 24.4898% 53.5211%; background-size: 5000% 7200%;",
  EMOJI_PREFIX + "background-position: 75.5102% 52.1127%; background-size: 5000% 7200%;",
  EMOJI_PREFIX + "background-position: 2.04082% 66.1972%; background-size: 5000% 7200%;",
  "",
  "",
  "",
]);
let emojiVersion = 0;
const updateEmoji = (index, style) => {
  emojis[index] = style;
  GM_setValue("emojis", emojis);
  ++emojiVersion;
};
let selectingIndex = null;
const updateSelectingEmoji = (style) => {
  if (selectingIndex == null) return;
  updateEmoji(selectingIndex, style);
  selectingIndex = null;
};

// 絵文字をツイートする async 関数
async function tweetEmoji(tweetButton, emoji) {
  let emojiButton,
    timeout = false;
  wait(5000).then(() => {
    timeout = true;
  });
  while (true) {
    if (timeout) throw new Error(`Couldn't find the emoji: ${JSON.stringify(emoji)}`);
    const emojiPicker = document.querySelector("#emoji_picker_categories_dom_id > div");
    if (!emojiPicker) {
      document.querySelector(`[data-testid="ScrollSnap-List"] button[aria-haspopup="menu"]`).click();
      await wait(50);
      continue;
    }
    emojiButton = emojiPicker.querySelector(`[style=${JSON.stringify(emoji)}]`);
    if (emojiButton) break;
    // ランダムな絵文字タブを読み込む
    const emojiTabs = emojiPicker.parentNode.parentNode.childNodes[1].childNodes[0].childNodes;
    emojiTabs[Math.floor(emojiTabs.length * Math.random())].childNodes[0].click();
    await wait(50);
  }
  emojiButton.click();
  await wait(50);
  tweetButton.click();
}

// 二種類のツイートボタンの前に絵文字ボタンを追加
setInterval(() => {
  for (const tweetButtonId of ["tweetButton", "tweetButtonInline"]) {
    const emojiButtons = document.createElement("div");
    emojiButtons.id = "emoji_tweet-" + tweetButtonId;
    {
      let button;
      if ((button = document.getElementById(emojiButtons.id))) {
        if (Number(button.dataset.emojiVersion) < emojiVersion) button.remove();
        else continue;
      }
      emojiButtons.dataset.emojiVersion = emojiVersion;
    }
    const tweetButton = document.querySelector(`[data-testid=${JSON.stringify(tweetButtonId)}]`);
    if (!tweetButton || tweetButton.parentNode.parentNode.dataset.testid !== "toolBar") continue;

    // それぞれの絵文字ボタンを作る
    for (const emoji of emojis) {
      if (!emoji) continue;
      const button = document.createElement("button");
      const emojiElm = document.createElement("div");
      emojiElm.style = emoji;
      emojiElm.style.height = "20px";
      emojiElm.style.width = "20px";
      button.append(emojiElm);
      button.onclick = () => tweetEmoji(tweetButton, emoji);
      emojiButtons.append(button);
    }

    tweetButton.before(emojiButtons);
  }
}, 50);

// 絵文字設定画面を追加
setInterval(() => {
  const emojiSelectorContainer = document.createElement("div");
  emojiSelectorContainer.id = "emoji_tweet-selector";
  {
    let selector;
    if ((selector = document.getElementById(emojiSelectorContainer.id))) {
      if (Number(selector.dataset.emojiVersion) < emojiVersion) selector.remove();
      else return;
    }
    emojiSelectorContainer.dataset.emojiVersion = emojiVersion;
  }
  if (document.getElementById(emojiSelectorContainer.id)) return;
  const emojiPicker = document.querySelector("#emoji_picker_categories_dom_id > div");
  if (!emojiPicker || emojiPicker.childNodes.length <= 1) return;

  // 設定画面タイトル
  const emojiSelectorTitle = document.createElement("h3");
  emojiSelectorTitle.innerText = "Emoji Selector";

  // 絵文字削除ボタン
  const emojiDeleter = document.createElement("button");
  emojiDeleter.innerText = "Delete emoji";
  emojiDeleter.onclick = () => {
    updateSelectingEmoji("");
  };
  emojiDeleter.style.float = "right";
  emojiDeleter.style.margin = "1.5em 0 0.5em";
  emojiDeleter.style.color = "#FF5555";

  // 絵文字設定ボタン
  const emojiSelector = document.createElement("div");
  emojis.forEach((emoji, index) => {
    const button = document.createElement("button");
    const emojiElm = document.createElement("div");
    emojiElm.style = emoji;
    emojiElm.style.height = "20px";
    emojiElm.style.width = "20px";
    button.append(emojiElm);
    button.onclick = () => {
      if (selectingIndex != null) emojiSelector.childNodes[selectingIndex].style.backgroundColor = null;
      if (selectingIndex === index) selectingIndex = null;
      else emojiSelector.childNodes[(selectingIndex = index)].style.backgroundColor = "#AAFFAAAA";
    };
    if (index == selectingIndex) button.style.backgroundColor = "#AAFFAAAA";
    emojiSelector.append(button);
  });

  emojiSelectorContainer.append(emojiDeleter, emojiSelectorTitle, emojiSelector);
  emojiSelectorContainer.style.margin = "1em";
  emojiPicker.childNodes[1].after(emojiSelectorContainer);
}, 50);

// 絵文字設定モード
setInterval(() => {
  const emojiPicker = document.querySelector("#emoji_picker_categories_dom_id > div");
  if (!emojiPicker) return;

  for (const emoji of emojiPicker.querySelectorAll(`[role="option"] > [style^=${JSON.stringify(EMOJI_PREFIX)}]`)) {
    const emojiButton = emoji.parentNode;
    if (selectingIndex == null) {
      emojiButton.onclick = null;
      emojiButton.style.backgroundColor = null;
    } else {
      emojiButton.onclick = (event) => {
        event.stopPropagation();
        updateSelectingEmoji(emoji.style.cssText);
      };
      emojiButton.style.backgroundColor = "#AAFFAAAA";
    }
  }
}, 50);

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址