Replace x with xcancel

Hacky solution to replace all x.com links with xcancel.

이 스크립트를 설치하려면 Tampermonkey, Greasemonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램을 설치해야 합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Userscripts와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 유저 스크립트 관리자 확장 프로그램이 필요합니다.

(이미 유저 스크립트 관리자가 설치되어 있습니다. 설치를 진행합니다!)

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

(이미 유저 스타일 관리자가 설치되어 있습니다. 설치를 진행합니다!)

// ==UserScript==
// @name         Replace x with xcancel
// @namespace    http://tampermonkey.net/
// @version      2026-01-11
// @description  Hacky solution to replace all x.com links with xcancel.
// @author       For You
// @match        https://www.destiny.gg/bigscreen
// @icon         https://www.google.com/s2/favicons?sz=64&domain=destiny.gg
// @grant        none
// @license      MIT
// ==/UserScript==

(function () {
  "use strict";

  const ORIGINAL_DOMAIN = "x.com";
  const REPLACEMENT_DOMAIN = "xcancel.com";

  const observer = new MutationObserver((mutations) => {
    for (const mutation of mutations) {
      for (const node of mutation.addedNodes) {
        if (node.querySelector) {
          const link = node.querySelector(".text a");
          replaceLink(link);
        }
      }
    }
  });

  function replaceLink(element) {
    if (!element?.innerText) return;

    element.innerText = element.innerText.replaceAll(ORIGINAL_DOMAIN, REPLACEMENT_DOMAIN);

    const href = element.getAttribute("href");
    if (href) {
      element.setAttribute("href", href.replace(ORIGINAL_DOMAIN, REPLACEMENT_DOMAIN));
    }
  }

  function register() {
    const chatFrame = document.querySelector("#chat-wrap > iframe");
    const chatDoc = chatFrame?.contentDocument;
    const chat = chatDoc?.querySelector("#chat");

    if (!chat) {
      // Dog ass loop to register the observer
      setTimeout(register, 1000);
      return;
    }

    chatDoc.querySelectorAll(".text a").forEach(replaceLink);

    observer.observe(chat, {
      subtree: true,
      childList: true,
    });
  }

  register();
})();