您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Change Twitter X Title
当前为
- // ==UserScript==
- // @name Twitter X Title
- // @namespace TwitterX
- // @match https://twitter.com/*
- // @grant none
- // @version 0.2.3
- // @author CY Fung
- // @description Change Twitter X Title
- // @run-at document-start
- // @license MIT
- // @unwrap
- // @inject-into page
- // ==/UserScript==
- (function () {
- 'use strict';
- let i18nXs = null;
- const i18nCache = new Set();
- function customTitle(p) {
- if (typeof p !== 'string' || !p.includes('X')) return p;
- if (!i18nXs && window.webpackChunk_twitter_responsive_web) {
- i18nXs = generateI18nXs();
- console.log('i18nXs', i18nXs)
- }
- let q = p.replace(/[\xA0\u1680\u180e\u2000-\u200a\u202f\u205f\u3000]/g, ' ');
- const mxLen = q.length;
- let skipI18N = false;
- if (q.replace(/[\(\d\)]/g, '').trim() === 'X') {
- q = q.replace('X', 'Twitter');
- skipI18N = true;
- } else if (q.endsWith(' / X')) {
- q = q.substring(0, q.length - ' / X'.length) + ' / Twitter';
- }
- if (!skipI18N) {
- let uv = null;
- for (const i18nX of i18nXs) {
- const { s, l, y, m } = i18nX;
- if (uv !== null && uv !== m) break;
- if (mxLen >= l && q.includes(s)) {
- const xc = s;
- const idx = q.indexOf(xc);
- if (idx >= 0 && idx >= y) {
- const tc = xc.replace(/\bX\b/g, 'Twitter');
- q = q.substring(0, idx) + tc + q.substring(idx + xc.length);
- uv = m;
- }
- }
- }
- if (typeof uv === 'string' && !i18nCache.has(uv)) {
- if (i18nCache.size > 12) i18nCache.clear();
- i18nCache.add(uv);
- moveToFront(i18nXs, uv);
- }
- }
- return q;
- }
- function generateI18nXs() {
- let i18nXs = [];
- let i18nFunction = null;
- for (const s of window.webpackChunk_twitter_responsive_web) {
- if (s && s[0] && s[0][0]) {
- const tag = s[0][0]
- if (typeof tag === 'string' && tag.startsWith('i18n/')) {
- if (s[1] && typeof s[1] === 'object') {
- let entries = Object.entries(s[1]);
- if (entries.length === 1 && typeof entries[0][1] === 'function') {
- i18nFunction = entries[0][1];
- }
- }
- break;
- }
- }
- }
- let i18nFunctionString = i18nFunction + "";
- let mFuncs = [...i18nFunctionString.matchAll(/function\([,a-zA-Z0-9$_]*\)\{return([^\{\}]+\bX\b[^\{\}]+)\}/g)].map(c => c[1]);
- for (const mfString of mFuncs) {
- let rk1 = mfString.includes('"');
- let rk2 = mfString.includes("'");
- let rt1 = rk1 && !rk2 ? '"' : !rk1 && rk2 ? "'" : '';
- let rt2 = rk1 && !rk2 ? "'" : !rk1 && rk2 ? '"' : '';
- if (!rt1 || !rt2) continue;
- if (mfString.includes(rt2) || mfString.includes("\\") || mfString.includes("&#")) continue;
- const p = mfString.split(rt1)
- if ((p.length % 2) !== 1) continue;
- let uLen = 0;
- let jLen = 0;
- const qm = [];
- for (let i = 1; i < p.length; i += 2) {
- p[i] = p[i].length > 0 ? p[i].replace(/[\xA0\u1680\u180e\u2000-\u200a\u202f\u205f\u3000]/g, ' ') : '';
- qm[i] = p[i].replace(/\bX\b/g, '_').replace(/\bTwitter\b/g, '_').length;
- uLen += qm[i];
- }
- for (let i = 1; i < p.length; i += 2) {
- if (/\bX\b/.test(p[i]) && !/\bTwitter\b/.test(p[i])) {
- i18nXs.push({
- s: p[i],
- y: jLen,
- l: uLen,
- m: mfString
- })
- }
- jLen += qm[i];
- }
- }
- return i18nXs;
- }
- function moveToFront(arr, value) {
- let insertAt = 0;
- for (let i = 0; i < arr.length;) {
- if (arr[i].m === value) {
- let start = i;
- do {
- i++;
- } while (i < arr.length && arr[i].m === value)
- let end = i;
- // Remove the segment from the array
- const matchedItems = arr.splice(start, end - start);
- // Insert the segment to the front at the offset
- arr.splice(insertAt, 0, ...matchedItems);
- insertAt += matchedItems.length;
- } else {
- i++;
- }
- }
- return arr;
- }
- const map = new Map();
- function fixTitle() {
- let p = document.title;
- if (!p) return;
- let q = map.get(p)
- if (q) {
- if (p !== q) {
- document.title = q;
- }
- return;
- }
- q = customTitle(p);
- if (map.size > 24 && p !== q) map.clear();
- map.set(p, q)
- if (p !== q) {
- map.set(q, q)
- document.title = q;
- }
- }
- function handleTitleChange(mutationsList) {
- console.log(document.title)
- let b = false;
- for (const mutation of mutationsList) {
- if (mutation.type === 'childList') {
- // Title has changed, do something here
- b = true;
- break;
- }
- }
- if (b) {
- // console.log('Title changed:', document.title);
- fixTitle();
- }
- }
- let observer = null;
- function doActionFn() {
- // Check if the title element has appeared
- const titleElement = document.querySelector('title');
- if (titleElement) {
- // Title element found, stop observing
- if (observer) observer.disconnect();
- // Now, create a new observer to monitor the title changes
- const titleObserver = new MutationObserver(handleTitleChange);
- // Configure the observer to monitor the title text changes
- const config = { childList: true, subtree: true };
- // Start observing the title element
- titleObserver.observe(titleElement, config);
- // Log the initial title
- // console.log('Initial Title:', titleElement.textContent);
- fixTitle()
- }
- }
- // Function to handle the title changes
- function mutCallback(mutationsList, observer) {
- let doAction = false;
- for (const mutation of mutationsList) {
- if (mutation.type === 'childList') {
- doAction = true;
- break;
- }
- }
- if (doAction) doActionFn();
- }
- if (document.querySelector('title')) {
- doActionFn();
- } else {
- // Create a new MutationObserver to monitor the document for the title element
- observer = new MutationObserver(mutCallback);
- // Configure the observer to monitor childList changes (new elements)
- const config = { childList: true, subtree: true };
- // Start observing the document
- observer.observe(document, config);
- }
- })();