您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Diff checker on tweet edit history
// ==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(); }); })();