Tweet Diff

Diff checker on tweet edit history

Tendrás que instalar una extensión para tu navegador como Tampermonkey, Greasemonkey o Violentmonkey si quieres utilizar este script.

Necesitarás instalar una extensión como Tampermonkey o Violentmonkey para instalar este script.

Necesitarás instalar una extensión como Tampermonkey o Violentmonkey para instalar este script.

Necesitarás instalar una extensión como Tampermonkey o Userscripts para instalar este script.

Necesitará instalar una extensión como Tampermonkey para instalar este script.

Necesitarás instalar una extensión para administrar scripts de usuario si quieres instalar este script.

(Ya tengo un administrador de scripts de usuario, déjame instalarlo)

Necesitará instalar una extensión como Stylus para instalar este estilo.

Necesitará instalar una extensión como Stylus para instalar este estilo.

Necesitará instalar una extensión como Stylus para instalar este estilo.

Necesitará instalar una extensión del gestor de estilos de usuario para instalar este estilo.

Necesitará instalar una extensión del gestor de estilos de usuario para instalar este estilo.

Necesitará instalar una extensión del gestor de estilos de usuario para instalar este estilo.

(Ya tengo un administrador de estilos de usuario, déjame instalarlo)

// ==UserScript==
// @name         Tweet Diff
// @namespace    http://tampermonkey.net/
// @version      1.0.1
// @description  Diff checker on tweet edit history
// @author       Snazzah
// @license      MIT
// @match        https://x.com/*
// @icon         https://raw.githubusercontent.com/Snazzah/TweetDiff/v1.0.1/icons/icon128.png
// @grant        none
// ==/UserScript==

(function() {'use strict';
// node_modules/diff/lib/index.mjs
var Diff = function() {
};
var buildValues = function(diff, lastComponent, newString, oldString, useLongestToken) {
  var components = [];
  var nextComponent;
  while (lastComponent) {
    components.push(lastComponent);
    nextComponent = lastComponent.previousComponent;
    delete lastComponent.previousComponent;
    lastComponent = nextComponent;
  }
  components.reverse();
  var componentPos = 0, componentLen = components.length, newPos = 0, oldPos = 0;
  for (;componentPos < componentLen; componentPos++) {
    var component = components[componentPos];
    if (!component.removed) {
      if (!component.added && useLongestToken) {
        var value = newString.slice(newPos, newPos + component.count);
        value = value.map(function(value2, i) {
          var oldValue = oldString[oldPos + i];
          return oldValue.length > value2.length ? oldValue : value2;
        });
        component.value = diff.join(value);
      } else {
        component.value = diff.join(newString.slice(newPos, newPos + component.count));
      }
      newPos += component.count;
      if (!component.added) {
        oldPos += component.count;
      }
    } else {
      component.value = diff.join(oldString.slice(oldPos, oldPos + component.count));
      oldPos += component.count;
      if (componentPos && components[componentPos - 1].added) {
        var tmp = components[componentPos - 1];
        components[componentPos - 1] = components[componentPos];
        components[componentPos] = tmp;
      }
    }
  }
  var finalComponent = components[componentLen - 1];
  if (componentLen > 1 && typeof finalComponent.value === "string" && (finalComponent.added || finalComponent.removed) && diff.equals("", finalComponent.value)) {
    components[componentLen - 2].value += finalComponent.value;
    components.pop();
  }
  return components;
};
var generateOptions = function(options, defaults) {
  if (typeof options === "function") {
    defaults.callback = options;
  } else if (options) {
    for (var name in options) {
      if (options.hasOwnProperty(name)) {
        defaults[name] = options[name];
      }
    }
  }
  return defaults;
};
var diffWords = function(oldStr, newStr, options) {
  options = generateOptions(options, {
    ignoreWhitespace: true
  });
  return wordDiff.diff(oldStr, newStr, options);
};
var _typeof = function(obj) {
  "@babel/helpers - typeof";
  if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {
    _typeof = function(obj2) {
      return typeof obj2;
    };
  } else {
    _typeof = function(obj2) {
      return obj2 && typeof Symbol === "function" && obj2.constructor === Symbol && obj2 !== Symbol.prototype ? "symbol" : typeof obj2;
    };
  }
  return _typeof(obj);
};
var canonicalize = function(obj, stack, replacementStack, replacer, key) {
  stack = stack || [];
  replacementStack = replacementStack || [];
  if (replacer) {
    obj = replacer(key, obj);
  }
  var i;
  for (i = 0;i < stack.length; i += 1) {
    if (stack[i] === obj) {
      return replacementStack[i];
    }
  }
  var canonicalizedObj;
  if (objectPrototypeToString.call(obj) === "[object Array]") {
    stack.push(obj);
    canonicalizedObj = new Array(obj.length);
    replacementStack.push(canonicalizedObj);
    for (i = 0;i < obj.length; i += 1) {
      canonicalizedObj[i] = canonicalize(obj[i], stack, replacementStack, replacer, key);
    }
    stack.pop();
    replacementStack.pop();
    return canonicalizedObj;
  }
  if (obj && obj.toJSON) {
    obj = obj.toJSON();
  }
  if (_typeof(obj) === "object" && obj !== null) {
    stack.push(obj);
    canonicalizedObj = {};
    replacementStack.push(canonicalizedObj);
    var sortedKeys = [], _key;
    for (_key in obj) {
      if (obj.hasOwnProperty(_key)) {
        sortedKeys.push(_key);
      }
    }
    sortedKeys.sort();
    for (i = 0;i < sortedKeys.length; i += 1) {
      _key = sortedKeys[i];
      canonicalizedObj[_key] = canonicalize(obj[_key], stack, replacementStack, replacer, _key);
    }
    stack.pop();
    replacementStack.pop();
  } else {
    canonicalizedObj = obj;
  }
  return canonicalizedObj;
};
Diff.prototype = {
  diff: function diff(oldString, newString) {
    var _options$timeout;
    var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
    var callback = options.callback;
    if (typeof options === "function") {
      callback = options;
      options = {};
    }
    this.options = options;
    var self = this;
    function done(value) {
      if (callback) {
        setTimeout(function() {
          callback(undefined, value);
        }, 0);
        return true;
      } else {
        return value;
      }
    }
    oldString = this.castInput(oldString);
    newString = this.castInput(newString);
    oldString = this.removeEmpty(this.tokenize(oldString));
    newString = this.removeEmpty(this.tokenize(newString));
    var newLen = newString.length, oldLen = oldString.length;
    var editLength = 1;
    var maxEditLength = newLen + oldLen;
    if (options.maxEditLength) {
      maxEditLength = Math.min(maxEditLength, options.maxEditLength);
    }
    var maxExecutionTime = (_options$timeout = options.timeout) !== null && _options$timeout !== undefined ? _options$timeout : Infinity;
    var abortAfterTimestamp = Date.now() + maxExecutionTime;
    var bestPath = [{
      oldPos: -1,
      lastComponent: undefined
    }];
    var newPos = this.extractCommon(bestPath[0], newString, oldString, 0);
    if (bestPath[0].oldPos + 1 >= oldLen && newPos + 1 >= newLen) {
      return done([{
        value: this.join(newString),
        count: newString.length
      }]);
    }
    var minDiagonalToConsider = -Infinity, maxDiagonalToConsider = Infinity;
    function execEditLength() {
      for (var diagonalPath = Math.max(minDiagonalToConsider, -editLength);diagonalPath <= Math.min(maxDiagonalToConsider, editLength); diagonalPath += 2) {
        var basePath = undefined;
        var removePath = bestPath[diagonalPath - 1], addPath = bestPath[diagonalPath + 1];
        if (removePath) {
          bestPath[diagonalPath - 1] = undefined;
        }
        var canAdd = false;
        if (addPath) {
          var addPathNewPos = addPath.oldPos - diagonalPath;
          canAdd = addPath && 0 <= addPathNewPos && addPathNewPos < newLen;
        }
        var canRemove = removePath && removePath.oldPos + 1 < oldLen;
        if (!canAdd && !canRemove) {
          bestPath[diagonalPath] = undefined;
          continue;
        }
        if (!canRemove || canAdd && removePath.oldPos + 1 < addPath.oldPos) {
          basePath = self.addToPath(addPath, true, undefined, 0);
        } else {
          basePath = self.addToPath(removePath, undefined, true, 1);
        }
        newPos = self.extractCommon(basePath, newString, oldString, diagonalPath);
        if (basePath.oldPos + 1 >= oldLen && newPos + 1 >= newLen) {
          return done(buildValues(self, basePath.lastComponent, newString, oldString, self.useLongestToken));
        } else {
          bestPath[diagonalPath] = basePath;
          if (basePath.oldPos + 1 >= oldLen) {
            maxDiagonalToConsider = Math.min(maxDiagonalToConsider, diagonalPath - 1);
          }
          if (newPos + 1 >= newLen) {
            minDiagonalToConsider = Math.max(minDiagonalToConsider, diagonalPath + 1);
          }
        }
      }
      editLength++;
    }
    if (callback) {
      (function exec() {
        setTimeout(function() {
          if (editLength > maxEditLength || Date.now() > abortAfterTimestamp) {
            return callback();
          }
          if (!execEditLength()) {
            exec();
          }
        }, 0);
      })();
    } else {
      while (editLength <= maxEditLength && Date.now() <= abortAfterTimestamp) {
        var ret = execEditLength();
        if (ret) {
          return ret;
        }
      }
    }
  },
  addToPath: function addToPath(path, added, removed, oldPosInc) {
    var last = path.lastComponent;
    if (last && last.added === added && last.removed === removed) {
      return {
        oldPos: path.oldPos + oldPosInc,
        lastComponent: {
          count: last.count + 1,
          added,
          removed,
          previousComponent: last.previousComponent
        }
      };
    } else {
      return {
        oldPos: path.oldPos + oldPosInc,
        lastComponent: {
          count: 1,
          added,
          removed,
          previousComponent: last
        }
      };
    }
  },
  extractCommon: function extractCommon(basePath, newString, oldString, diagonalPath) {
    var newLen = newString.length, oldLen = oldString.length, oldPos = basePath.oldPos, newPos = oldPos - diagonalPath, commonCount = 0;
    while (newPos + 1 < newLen && oldPos + 1 < oldLen && this.equals(newString[newPos + 1], oldString[oldPos + 1])) {
      newPos++;
      oldPos++;
      commonCount++;
    }
    if (commonCount) {
      basePath.lastComponent = {
        count: commonCount,
        previousComponent: basePath.lastComponent
      };
    }
    basePath.oldPos = oldPos;
    return newPos;
  },
  equals: function equals(left, right) {
    if (this.options.comparator) {
      return this.options.comparator(left, right);
    } else {
      return left === right || this.options.ignoreCase && left.toLowerCase() === right.toLowerCase();
    }
  },
  removeEmpty: function removeEmpty(array) {
    var ret = [];
    for (var i = 0;i < array.length; i++) {
      if (array[i]) {
        ret.push(array[i]);
      }
    }
    return ret;
  },
  castInput: function castInput(value) {
    return value;
  },
  tokenize: function tokenize(value) {
    return value.split("");
  },
  join: function join(chars) {
    return chars.join("");
  }
};
var characterDiff = new Diff;
var extendedWordChars = /^[A-Za-z\xC0-\u02C6\u02C8-\u02D7\u02DE-\u02FF\u1E00-\u1EFF]+$/;
var reWhitespace = /\S/;
var wordDiff = new Diff;
wordDiff.equals = function(left, right) {
  if (this.options.ignoreCase) {
    left = left.toLowerCase();
    right = right.toLowerCase();
  }
  return left === right || this.options.ignoreWhitespace && !reWhitespace.test(left) && !reWhitespace.test(right);
};
wordDiff.tokenize = function(value) {
  var tokens = value.split(/([^\S\r\n]+|[()[\]{}'"\r\n]|\b)/);
  for (var i = 0;i < tokens.length - 1; i++) {
    if (!tokens[i + 1] && tokens[i + 2] && extendedWordChars.test(tokens[i]) && extendedWordChars.test(tokens[i + 2])) {
      tokens[i] += tokens[i + 2];
      tokens.splice(i + 1, 2);
      i--;
    }
  }
  return tokens;
};
var lineDiff = new Diff;
lineDiff.tokenize = function(value) {
  if (this.options.stripTrailingCr) {
    value = value.replace(/\r\n/g, "\n");
  }
  var retLines = [], linesAndNewlines = value.split(/(\n|\r\n)/);
  if (!linesAndNewlines[linesAndNewlines.length - 1]) {
    linesAndNewlines.pop();
  }
  for (var i = 0;i < linesAndNewlines.length; i++) {
    var line = linesAndNewlines[i];
    if (i % 2 && !this.options.newlineIsToken) {
      retLines[retLines.length - 1] += line;
    } else {
      if (this.options.ignoreWhitespace) {
        line = line.trim();
      }
      retLines.push(line);
    }
  }
  return retLines;
};
var sentenceDiff = new Diff;
sentenceDiff.tokenize = function(value) {
  return value.split(/(\S.+?[.!?])(?=\s+|$)/);
};
var cssDiff = new Diff;
cssDiff.tokenize = function(value) {
  return value.split(/([{}:;,]|\s+)/);
};
var objectPrototypeToString = Object.prototype.toString;
var jsonDiff = new Diff;
jsonDiff.useLongestToken = true;
jsonDiff.tokenize = lineDiff.tokenize;
jsonDiff.castInput = function(value) {
  var _this$options = this.options, undefinedReplacement = _this$options.undefinedReplacement, _this$options$stringi = _this$options.stringifyReplacer, stringifyReplacer = _this$options$stringi === undefined ? function(k, v) {
    return typeof v === "undefined" ? undefinedReplacement : v;
  } : _this$options$stringi;
  return typeof value === "string" ? value : JSON.stringify(canonicalize(value, null, null, stringifyReplacer), stringifyReplacer, "  ");
};
jsonDiff.equals = function(left, right) {
  return Diff.prototype.equals.call(jsonDiff, left.replace(/,([\r\n])/g, "$1"), right.replace(/,([\r\n])/g, "$1"));
};
var arrayDiff = new Diff;
arrayDiff.tokenize = function(value) {
  return value.slice();
};
arrayDiff.join = arrayDiff.removeEmpty = function(value) {
  return value;
};

// src/style.css
var style_default = "body {\n  --twdiff-background-color: 255, 255, 255;\n  --twdiff-text-color: rgb(0, 0, 0);\n}\nbody[style^=\"background-color: rgb(21, 32, 43);\"], body.body-dark {\n  --twdiff-background-color: 21, 32, 43;\n  --twdiff-text-color: rgb(255, 255, 255);\n}\nbody[style^=\"background-color: rgb(0, 0, 0);\"], body.body-pitch-black {\n  --twdiff-background-color: 0, 0, 0;\n  --twdiff-text-color: rgb(255, 255, 255);\n}\n\n.twdiff-button {\n  font-family: TwitterChirp, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif;\n  cursor: pointer;\n  border-radius: 8px;\n  border: 1px solid rgb(47, 51, 54);\n  background-color: transparent;\n  margin-top: 10px;\n  padding: 10px 15px;\n  display: flex;\n  font-size: 15px;\n  gap: 2px;\n  color: #d8dbde;\n  transition-duration: 0.2s;\n  transition-property: background-color;\n}\n\n.twdiff-button:hover {\n  background-color: rgb(255, 255, 255, 0.03);\n}\n\n.twdiff-add-preview {\n  color: #57ab5a;\n  font-weight: 700;\n}\n\n.twdiff-remove-preview {\n  color: #e5534b;\n  font-weight: 700;\n}\n\n.twdiff-modal {\n  position: fixed;\n  z-index: 100;\n  top: 0;\n  bottom: 0;\n  left: 0;\n  right: 0;\n  background-color: rgba(91, 112, 131, 0.4);\n  color: var(--twdiff-text-color);\n  display: flex;\n  align-items: center;\n  justify-content: center;\n}\n\n.twdiff-inner-modal {\n  position: relative;\n  background-color: rgb(var(--twdiff-background-color));\n  border-radius: 8px;\n  max-width: 600px;\n  max-height: 650px;\n  width: 100%;\n  margin: 10px;\n  overflow: auto;\n  font-family: TwitterChirp, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif;\n}\n\n.twdiff-header {\n  height: 50px;\n  position: sticky;\n  top: 0;\n  left: 0;\n  right: 0;\n  padding: 0 16px;\n  font-size: 20px;\n  align-content: center;\n  font-weight: 700;\n  backdrop-filter: blur(12px);\n  background-color: rgba(var(--twdiff-background-color), 0.65);\n  display: flex;\n  justify-content: space-between;\n  align-items: center;\n}\n\n.twdiff-header h2 {\n  flex: 1;\n  margin: 0;\n  font-size: 20px;\n}\n\n.twdiff-header > .twdiff-remove-preview {\n  margin-left: 4px;\n}\n\n.twdiff-close-button {\n  color: rgb(239, 243, 244);\n  background-color: transparent;\n  border: none;\n  width: 36px;\n  height: 36px;\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  cursor: pointer;\n  border-radius: 999px;\n  transition-duration: 0.2s;\n  margin-left: -8px;\n  margin-right: 20px;\n}\n\n.twdiff-close-button:hover {\n  background-color: rgba(239, 243, 244, 0.1);\n}\n\n.twdiff-close-button svg {\n  fill: currentColor;\n}\n\n.twdiff-close-button svg {\n  width: 20px;\n  height: 20px;\n}\n\n.twdiff-tweet {\n  padding: 12px 16px;\n  padding-bottom: 24px;\n  display: flex;\n  gap: 8px;\n}\n\n.twdiff-tweet-avy {\n  flex: none;\n  width: 40px;\n  height: 40px;\n  border-radius: 999px;\n\tuser-drag: none;\n\tuser-select: none;\n\t-moz-user-select: none;\n\t-webkit-user-drag: none;\n\t-webkit-user-select: none;\n\t-ms-user-select: none;\n}\n\n.twdiff-tweet-content {\n  display: flex;\n  flex-direction: column;\n  font-size: 15px;\n  gap: 2px;\n  flex: 1;\n  overflow: hidden;\n}\n\n.twdiff-tweet-user {\n  font-weight: 700;\n  display: flex;\n  gap: 2px;\n}\n\n.twdiff-user-verified {\n  color: rgb(29, 155, 240);\n  height: 1.25em;\n  fill: currentcolor;\n  max-width: 20px;\n  max-height: 20px;\n  height: 1.25em;\n  vertical-align: text-bottom;\n}\n\n.twdiff-tweet-handle {\n  color: rgb(113, 118, 123);\n  font-weight: 400;\n}\n\n.twdiff-tweet-text {\n  white-space: pre-wrap;\n  overflow-wrap: break-word;\n}\n\n.twdiff-add {\n  background-color: #0a04;\n}\n\n.twdiff-remove {\n  background-color: #a004;\n  text-decoration: line-through;\n}";

// src/index.ts
var getCsrf = function() {
  let csrf = document.cookie.match(/(?:^|;\s*)ct0=([0-9a-f]+)\s*(?:;|$)/);
  return csrf ? csrf[1] : "";
};
var fetchHistory = function(id) {
  const path = `https://${location.hostname}/i/api/graphql/1I20d3k4y_2gALXHj967Xg/TweetEditHistory?variables=%7B%22tweetId%22%3A%22${id}%22,%22withQuickPromoteEligibilityTweetFields%22%3Atrue%7D&features=%7B%22communities_web_enable_tweet_community_results_fetch%22%3Atrue,%22c9s_tweet_anatomy_moderator_badge_enabled%22%3Atrue,%22freedom_of_speech_not_reach_fetch_enabled%22%3Atrue,%22standardized_nudges_misinfo%22%3Atrue,%22tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled%22%3Atrue,%22tweetypie_unmention_optimization_enabled%22%3Atrue,%22responsive_web_edit_tweet_api_enabled%22%3Atrue,%22graphql_is_translatable_rweb_tweet_is_translatable_enabled%22%3Atrue,%22view_counts_everywhere_api_enabled%22%3Atrue,%22longform_notetweets_consumption_enabled%22%3Atrue,%22responsive_web_twitter_article_tweet_consumption_enabled%22%3Atrue,%22tweet_awards_web_tipping_enabled%22%3Afalse,%22creator_subscriptions_quote_tweet_preview_enabled%22%3Afalse,%22longform_notetweets_rich_text_read_enabled%22%3Atrue,%22longform_notetweets_inline_media_enabled%22%3Atrue,%22articles_preview_enabled%22%3Atrue,%22rweb_video_timestamps_enabled%22%3Atrue,%22rweb_tipjar_consumption_enabled%22%3Atrue,%22responsive_web_graphql_exclude_directive_enabled%22%3Atrue,%22verified_phone_label_enabled%22%3Afalse,%22responsive_web_graphql_timeline_navigation_enabled%22%3Atrue,%22creator_subscriptions_tweet_preview_api_enabled%22%3Atrue,%22responsive_web_graphql_skip_user_profile_image_extensions_enabled%22%3Afalse,%22responsive_web_enhance_cards_enabled%22%3Afalse%7D`;
  return fetch(path, {
    headers: {
      authorization: publicToken,
      "x-csrf-token": getCsrf(),
      "x-twitter-auth-type": "OAuth2Session",
      "content-type": "application/json",
      "x-twitter-client-language": navigator.language ? navigator.language : "en"
    },
    credentials: "include"
  }).then((r) => r.json());
};
var createButton = function(diffOpts) {
  const diff2 = diffWords(diffOpts.oldText, diffOpts.newText);
  let addCount = 0;
  let removeCount = 0;
  diff2.forEach((p) => {
    if (p.added)
      addCount++;
    else if (p.removed)
      removeCount++;
  });
  function click() {
    const modal = document.createElement("div");
    modal.className = "twdiff-modal";
    modal.addEventListener("click", (e) => {
      if (e.target === modal)
        modal.remove();
    });
    const verifiedTick = '<svg viewBox="0 0 22 22" aria-label="Verified account" role="img" data-testid="icon-verified" class="twdiff-user-verified"><g><path d="M20.396 11c-.018-.646-.215-1.275-.57-1.816-.354-.54-.852-.972-1.438-1.246.223-.607.27-1.264.14-1.897-.131-.634-.437-1.218-.882-1.687-.47-.445-1.053-.75-1.687-.882-.633-.13-1.29-.083-1.897.14-.273-.587-.704-1.086-1.245-1.44S11.647 1.62 11 1.604c-.646.017-1.273.213-1.813.568s-.969.854-1.24 1.44c-.608-.223-1.267-.272-1.902-.14-.635.13-1.22.436-1.69.882-.445.47-.749 1.055-.878 1.688-.13.633-.08 1.29.144 1.896-.587.274-1.087.705-1.443 1.245-.356.54-.555 1.17-.574 1.817.02.647.218 1.276.574 1.817.356.54.856.972 1.443 1.245-.224.606-.274 1.263-.144 1.896.13.634.433 1.218.877 1.688.47.443 1.054.747 1.687.878.633.132 1.29.084 1.897-.136.274.586.705 1.084 1.246 1.439.54.354 1.17.551 1.816.569.647-.016 1.276-.213 1.817-.567s.972-.854 1.245-1.44c.604.239 1.266.296 1.903.164.636-.132 1.22-.447 1.68-.907.46-.46.776-1.044.908-1.681s.075-1.299-.165-1.903c.586-.274 1.084-.705 1.439-1.246.354-.54.551-1.17.569-1.816zM9.662 14.85l-3.429-3.428 1.293-1.302 2.072 2.072 4.4-4.794 1.347 1.246z"></path></g></svg>';
    modal.innerHTML = `
      <div class="twdiff-inner-modal">
        <div class="twdiff-header">
          <button class="twdiff-close-button">
            <svg viewBox="0 0 24 24" aria-hidden="true"><g><path d="M10.59 12L4.54 5.96l1.42-1.42L12 10.59l6.04-6.05 1.42 1.42L13.41 12l6.05 6.04-1.42 1.42L12 13.41l-6.04 6.05-1.42-1.42L10.59 12z"></path></g></svg>
          </button>
          <h2>Tweet Diff</h2>
          <div>
            <span class="twdiff-add-preview"></span>
            <span class="twdiff-remove-preview"></span>
          </div>
        </div>
        <div class="twdiff-tweet">
          <img class="twdiff-tweet-avy">
          <div class="twdiff-tweet-content">
            <div class="twdiff-tweet-user">
              <span class="twdiff-tweet-username"></span>
              ${diffOpts.user?.is_blue_verified ? verifiedTick : ""}
              <span class="twdiff-tweet-handle"></span>
            </div>
            <div class="twdiff-tweet-text"></div>
          </div>
        </div>
      </div>
    `;
    modal.querySelector(".twdiff-close-button").addEventListener("click", () => modal.remove());
    if (diffOpts.user) {
      modal.querySelector(".twdiff-tweet-handle").innerText = "@" + diffOpts.user.legacy.screen_name;
      modal.querySelector(".twdiff-tweet-username").innerText = diffOpts.user.legacy.name;
      modal.querySelector(".twdiff-tweet-avy").src = diffOpts.user.legacy.profile_image_url_https;
    }
    if (addCount !== 0)
      modal.querySelector(".twdiff-add-preview").innerText = "+" + addCount.toLocaleString();
    if (removeCount !== 0)
      modal.querySelector(".twdiff-remove-preview").innerText = "-" + removeCount.toLocaleString();
    const tweetText = modal.querySelector(".twdiff-tweet-text");
    for (const part of diff2) {
      const span = document.createElement("span");
      if (part.added)
        span.classList.add("twdiff-add");
      else if (part.removed)
        span.classList.add("twdiff-remove");
      span.innerText = part.value;
      tweetText.appendChild(span);
    }
    document.body.appendChild(modal);
  }
  const button = document.createElement("button");
  button.className = "twdiff-button";
  if (addCount === 0 && removeCount === 0) {
    button.innerText = "No difference found";
    button.disabled = true;
  } else {
    button.innerHTML = '<span class="twdiff-add-preview"></span><span class="twdiff-remove-preview"></span><span>\xB7 Show Diff</span>';
    if (addCount !== 0)
      button.querySelector(".twdiff-add-preview").innerText = "+" + addCount.toLocaleString();
    if (removeCount !== 0)
      button.querySelector(".twdiff-remove-preview").innerText = "-" + removeCount.toLocaleString();
    button.addEventListener("click", click);
  }
  return button;
};
var getTweetElements = function(username) {
  const tweets = Array.from(document.querySelectorAll('article[data-testid="tweet"]'));
  let sortedTweets = {};
  for (const tweet of tweets) {
    const link = tweet.querySelector(`a[href^="/${username}/status/"`);
    if (!link)
      continue;
    const tweetId = link.href.split("/").reverse()[0];
    if (/^\d+$/.test(tweetId))
      sortedTweets[tweetId] = tweet;
  }
  return sortedTweets;
};
async function hookIntoTweets() {
  const [_, username, __, tweetId] = location.pathname.split("/");
  console.log("Starting to hook into tweet", username, tweetId);
  const tweetElems = getTweetElements(username);
  const data = await fetchHistory(tweetId);
  const editHistory = data.data.tweet_result_by_rest_id.result.edit_history_timeline.timeline.instructions[1].entries;
  const user = editHistory[0].content.items[0].item.itemContent.tweet_results.result.core.user_results.result;
  const tweets = [
    editHistory[0].content.items[0].item.itemContent.tweet_results.result,
    ...editHistory[1].content.items.map((e) => e.item.itemContent.tweet_results.result.tweet)
  ].map((t, i) => ({ index: i, id: t.rest_id, text: t.note_tweet?.note_tweet_results?.result.text ?? t.legacy.full_text }));
  for (const tweet of tweets) {
    if (tweet.index >= tweets.length - 1)
      break;
    if (!tweetElems[tweet.id] || tweetElems[tweet.id].dataset.twdiff === "1")
      continue;
    const prevTweet = tweets[tweet.index + 1];
    const parentElem = tweetElems[tweet.id].querySelector('[data-testid="tweetText"]').parentElement;
    parentElem.appendChild(createButton({
      oldText: prevTweet.text,
      newText: tweet.text,
      user
    }));
    tweetElems[tweet.id].dataset.twdiff = "1";
  }
}
var onReady = function() {
  const style2 = document.createElement("style");
  const head = document.head || document.getElementsByTagName("head")[0];
  style2.innerHTML = style_default;
  head.appendChild(style2);
  let lastHistory = "";
  setInterval(() => {
    const [_, username, userType, tweetId, tweetType] = location.pathname.split("/");
    const isOnHistory = username !== "home" && username !== "i" && userType === "status" && tweetType === "history" && !!document.querySelector('section[aria-labelledby^="accessible-list-"] h2[aria-level="2"][role="heading"]');
    if (!isOnHistory)
      lastHistory = "";
    else if (lastHistory !== tweetId) {
      lastHistory = tweetId;
      try {
        hookIntoTweets();
      } catch (e) {
        console.log("Failed to hook tweetdiff", e);
      }
    }
  }, 1000);
};
var publicToken = "Bearer AAAAAAAAAAAAAAAAAAAAANRILgAAAAAAnNwIzUejRCOuH5E6I8xnZz4puTs%3D1Zv7ttfk8LF81IUq16cHjhLTvJu4FA33AGWWjCpTnA";
document.addEventListener("readystatechange", () => {
  if (document.readyState === "complete")
    onReady();
});

})();