Twitter Account Location Flag

Shows country flag emoji next to Twitter usernames based on account location

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

作者
Mega Dragonzord
日安装量
4
总安装量
34
评分
2 0 0
版本
1.0.2
创建于
2025-11-24
更新于
2025-11-24
大小
33.4 KB
许可证
MIT
适用于

Twitter / X 账号地区国旗标识脚本

在 Twitter / X 上自动为用户名旁边添加 所属国家 / 地区的国旗 + 低调跑马灯边框
让你一眼区分不同地区的账号,同时尽量保持 UI「原生风」与「低调骚」。


功能简介

这个 Userscript 会在你浏览 Twitter / X(https://x.com/* / https://twitter.com/*)时:

  1. 自动识别页面上的账号用户名(包括时间线、用户列表、推荐账号等)。
  2. 通过 Twitter 的内部 API(AboutAccountQuery)查询该账号的 Account location(account_based_in)
  3. 将 location 映射为:
    • 对应国家国旗(例如 Japan → 🇯🇵)
    • 或地区 emoji(例如 Europe & Central Asia → 🌍)
  4. 在用户名旁边插入一个带 低调灰色跑马灯边框 的小标签,例如:
   显示名   @username  🇯🇵
  1. 为了避免频繁请求:
  • 使用 本地缓存(GM_setValue) 存储已查询过的账号和位置信息(默认 30 天)。
  • 使用 请求队列 + 速率限制 避免触发 Twitter 风控。

环境要求

  • 浏览器:推荐使用最新版的 Chrome / Edge / Firefox 等现代浏览器
  • 油猴脚本管理器(至少一个):

    • Tampermonkey
    • 或 Violentmonkey、Greasemonkey 等兼容管理器
  • 账号已登录 Twitter / X,否则无法调用内部 API 获取位置信息


安装方式

  1. 安装 Tampermonkey / Violentmonkey 插件。
  2. 新建一个脚本,将你的完整代码粘贴进去:
  • 顶部的 // ==UserScript== 元数据保留
  • 所有逻辑代码原样复制

    1. 保存后,确保:
  • 脚本 已启用

  • 作用域包含:https://x.com/*https://twitter.com/*

    1. 打开 X / Twitter 时间线,刷新页面,你将逐渐看到用户名旁边出现国旗小标签(加载中会先显示灰色 shimmer 骨架)。

核心功能设计说明

1. 地区 / 国家 → Emoji 映射

脚本内置了两类映射:

  • 地区级别映射(REGION_EMOJIS) 示例:
  const REGION_EMOJIS = {
      "East Asia & Pacific": "🌏",
      "Europe & Central Asia": "🌍",
      "Latin America & Caribbean": "🌎",
      "Middle East & North Africa": "🕌",
      "North America": "🌎",
      "South Asia": "🌏",
      "Sub-Saharan Africa": "🌍",
      "Global": "🌐",
      "Worldwide": "🌐"
  };
  • 国家级别映射(COUNTRY_FLAGS) 支持绝大多数常见国家名称(包含 Czech Republic / Czechia 这种别名)。

匹配规则:

  1. 先尝试精确匹配地区名
  2. 再尝试精确匹配国家名
  3. 若没有,则进行一次 不区分大小写的匹配
  4. 仍找不到则返回 null 不显示国旗。

匹配逻辑封装在:

function getCountryFlag(locationName) { ... }

你可以在映射表中增加 / 修改自己的国家显示风格,比如把 Europe 强行显示为 🇪🇺 已经在代码中实现。


2. 缓存机制(避免重复请求)

脚本使用 GM_getValue / GM_setValue 做持久化缓存:

  • CACHE_KEY = 'twitter_location_cache'
  • CACHE_EXPIRY_DAYS = 30(默认缓存 30 天)

缓存结构大致为:

{
  "username1": {
    "location": "Japan",
    "expiry": 1730000000000,
    "cachedAt": 1727000000000
  },
  "username2": {
    "location": "Europe & Central Asia",
    "expiry": ...,
    "cachedAt": ...
  }
}

加载时:

  • 只会把 未过期location !== null 的缓存恢复到内存 Map 中。
  • 避免长时间保存「查不到位置的用户」造成无意义存储。

写入时:

  • 调用 saveCacheEntry(username, location) 更新 Map
  • 利用 setTimeout 延迟 5 秒批量持久化,避免频繁 GM_setValue

你可以修改:

const CACHE_EXPIRY_DAYS = 30;

来调整缓存有效期。


3. 速率限制与请求队列

为防止触发 X / Twitter 的风控、429 或其他限制,脚本实现了一个简单的 请求队列 + 限流

  • MIN_REQUEST_INTERVAL = 2000 毫秒(两次 API 请求之间最少间隔 2 秒)
  • MAX_CONCURRENT_REQUESTS = 2(最多同时处理两个请求)
  • 维护:

    • requestQueue:待处理用户名队列
    • activeRequests:当前正在处理的请求数量
    • lastRequestTime:上一次请求的时间
    • rateLimitResetTime:如果检测到官方限流,可以在这里记录恢复时间(预留逻辑)

每当需要查询某个用户位置时,会调用:

getUserLocation(screenName)  // 返回 Promise<string | null>

如果缓存中已有数据,直接返回;否则:

  • 将查询任务推入 requestQueue
  • processRequestQueue() 按照限流规则依次调用 makeLocationRequest(screenName)

4. Twitter 内部 API 调用(AboutAccountQuery)

脚本使用 GM_xmlhttpRequest 直接调用 Twitter / X 的 GraphQL 接口:

const url = 'https://x.com/i/api/graphql/XRqGa7EeokUU5kppkh13EA/AboutAccountQuery?variables=...';

关键点:

  1. CSRF Token 获取
   function getCsrfToken() {
       const cookies = document.cookie.split(';');
       for (let cookie of cookies) {
           const [name, value] = cookie.trim().split('=');
           if (name === 'ct0') {
               return value;
           }
       }
       return null;
   }

若获取不到 ct0,脚本会放弃请求(返回 null)。

  1. 使用 GM_xmlhttpRequest 自动携带 Cookie
   GM_xmlhttpRequest({
       method: 'GET',
       url: url,
       headers: {
           'Authorization': 'Bearer AAAAAAAAAA......',
           'X-Csrf-Token': csrfToken,
           'X-Twitter-Auth-Type': 'OAuth2Session',
           'X-Twitter-Active-User': 'yes',
           'Content-Type': 'application/json'
       },
       onload: (response) => { ... },
       onerror: () => resolve(null)
   });
  1. 返回数据解析:
   const location = data?.data?.user_result_by_screen_name?.result?.about_profile?.account_based_in || null;

⚠ 注意:

  • 这类内部 API 可能在未来随 X 的后端更新而变动,如失效需要更新 query id 或字段路径。
  • 本脚本仅在前端调用官方接口,不篡改请求,不向第三方服务器转发。

5. 用户名 DOM 解析与插入位置

脚本会在以下区域检索用户名容器:

article[data-testid="tweet"],
[data-testid="UserCell"],
[data-testid="User-Names"],
[data-testid="User-Name"]

并用 extractUsername(element) 尝试从中解析出 screenName

  • 优先从 data-testid="UserName" / "User-Name" 内的链接 href="/username" 获取
  • 过滤掉:

    • /home / /explore / /messages 等路由
    • hashtag / search 等特殊路径
    • 纯数字或 status/id 等非用户名
  • 也支持从文本中的 @username 正则匹配,并验证其是否对应 a[href="/username"]

解析成功后,会调用 addFlagToUsername(usernameElement, screenName)

  1. 插入一个 加载骨架 shimmer(灰色渐变条)
  2. 请求位置 → 显示国旗,替换 shimmer
  3. 如果用户已处理或失败,会标记 dataset.flagAdded 避免重复操作

插入位置尽量选择:

  • 用户名块中的:显示名 和 @handle 之间 或上下位置
  • 尽量贴合 Twitter 原生排版,不破坏布局

6. 动态内容监听(无限滚动兼容)

X / Twitter 的时间线是无限滚动 + 动态注入的,因此脚本使用 MutationObserver 实现自动刷新:

observer = new MutationObserver((mutations) => {
    let shouldProcess = false;
    for (const mutation of mutations) {
        if (mutation.addedNodes.length > 0) {
            shouldProcess = true;
        }
    }

    if (shouldProcess) {
        setTimeout(processUsernames, 500);
    }
});

额外还监听 URL 变化(单页应用路由):

  • 一旦检测到 location.href 改变,延迟 2 秒重新扫描用户名。

UI 与样式设计

1. 加载状态:骨架 shimmer

在查询位置期间,脚本会插入一个灰色的“小矩形 shimmer”作为占位符:

function createLoadingShimmer() {
    const shimmer = document.createElement('span');
    shimmer.setAttribute('data-twitter-flag-shimmer', 'true');
    shimmer.style.display = 'inline-block';
    shimmer.style.width = '20px';
    shimmer.style.height = '16px';
    shimmer.style.marginLeft = '4px';
    shimmer.style.marginRight = '4px';
    shimmer.style.verticalAlign = 'middle';
    shimmer.style.borderRadius = '2px';
    shimmer.style.background = 'linear-gradient(90deg, rgba(113, 118, 123, 0.2) 25%, rgba(113, 118, 123, 0.4) 50%, rgba(113, 118, 123, 0.2) 75%)';
    shimmer.style.backgroundSize = '200% 100%';
    shimmer.style.animation = 'shimmer 1.5s infinite';
    ...
}

并在 <head> 中自动注入 @keyframes shimmer

2. 低调跑马灯边框样式(推荐)

你可以采用类似这样的设置(示例,供 README 描述用):

flagSpan.style.marginLeft = '4px';
flagSpan.style.marginRight = '4px';
flagSpan.style.display = 'inline-block';
flagSpan.style.verticalAlign = 'middle';
flagSpan.style.color = 'inherit';

// 自动尺寸 + 小圆角
flagSpan.style.padding = '1px 6px';
flagSpan.style.borderRadius = '4px';
flagSpan.style.fontSize = '0.95em';
flagSpan.style.lineHeight = '1.2';
flagSpan.style.border = '1px solid transparent';

// 低调灰色跑马灯边框
flagSpan.style.backgroundImage =
    'linear-gradient(rgba(15,20,25,0.9), rgba(15,20,25,0.9)),' +
    'linear-gradient(120deg,' +
        'rgba(120,120,120,0.0),' +
        'rgba(180,180,180,0.7),' +
        'rgba(120,120,120,0.0)' +
    ')';
flagSpan.style.backgroundOrigin = 'border-box';
flagSpan.style.backgroundClip = 'padding-box, border-box';

// 宽度自动随内容变化
flagSpan.style.backgroundSize = '100% 100%, 200% 100%';

// 慢速低调动画
flagSpan.style.animation = 'marquee-border 6s linear infinite';

对应的 @keyframes 已经写在:

@keyframes marquee-border {
    0% { background-position: 0% 50%; }
    50% { background-position: 100% 50%; }
    100% { background-position: 0% 50%; }
}

整体效果:远看就是一小块淡灰色标签,仔细看边缘在慢慢流动,非常低调。

3. Emoji 字体指定(提高国旗兼容性)

如果系统默认字体对 emoji 支持不理想,可以通过 data-twitter-flag 设置字体族:

[data-twitter-flag] {
    font-family: "Apple Color Emoji","Segoe UI Emoji","Noto Color Emoji",
                 "Twemoji Mozilla","EmojiOne Color",system-ui,sans-serif !important;
}

这样可以尽量保证 🇯🇵 🇺🇸 等国旗 emoji 能被正常渲染出来。


隐私与安全说明

  • 本脚本:

    • 不会 将数据发送到任何第三方服务器
    • 只调用 Twitter / X 自身的公开接口(你本来就能在网页上访问)
    • 缓存数据(用户名 → location)存储在本地的油猴扩展存储中
  • 你可以随时手动清除缓存,例如在控制台或脚本中调用:

  GM_deleteValue('twitter_location_cache');

常见问题(FAQ)

Q1:为什么有些账号不显示国旗?

可能原因:

  1. 该账号没有设置 Account based in / Location
  2. Twitter 内部 API 对该账号未返回 about_profile.account_based_in
  3. 返回的字段在 REGION_EMOJIS / COUNTRY_FLAGS 中没有匹配项 → 你可以手动添加对应映射
  4. 请求失败或被限流,当次查询会失败(稍后刷新/滚动可能会重试)

Q2:如何清空所有已缓存的位置数据?

在脚本环境中执行:

GM_deleteValue('twitter_location_cache');

刷新页面后,会重新从 API 查询。


Q3:为什么国旗显示成方块 / 空白?

  • 说明当前系统字体对 emoji 的国旗组合支持不好;
  • 建议:

    • 确认系统中安装了 emoji 字体;
    • 利用上文提到的 font-family 强制使用 emoji 字体;
    • 若仍无法解决,只能考虑改用纯文本(如 JPUS)或通过图片 / SVG 的方案来实现。

如何自定义

几处常见可自定义点:

  1. 缓存时间
   const CACHE_EXPIRY_DAYS = 30;
  1. 请求间隔与并发数
   const MIN_REQUEST_INTERVAL = 2000;
   const MAX_CONCURRENT_REQUESTS = 2;
  1. 国旗/地区映射
  • REGION_EMOJISCOUNTRY_FLAGS 中增删改
  • 比如统一把某些模糊地区都映射到 🌐
  1. UI 风格
  • 调整 flagSpan.style.* 样式实现不同风格:

    • 极简无边框,仅 flag
    • 淡灰 pill
    • 浅蓝跑马灯、hover 才高亮 等

免责声明

  • 该脚本依赖于 X / Twitter 当前的页面结构与内部 API:

    • 页面结构变化(DOM / data-testid 更名)可能导致无法正确识别用户名
    • 内部 API(AboutAccountQuery)参数或字段变更可能导致查询失败
  • 如遇到报错或脚本失效,需要根据最新前端 / 网络请求调整对应逻辑。