Greasy Fork

Greasy Fork is available in English.

Twitter Account Location Flag

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

当前为 2025-11-24 提交的版本,查看 最新版本

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

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

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

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

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

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

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

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

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

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

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

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

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

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

作者
Mega Dragonzord
评分
0 0 0
版本
1.0.1
创建于
2025-11-24
更新于
2025-11-24
大小
33.0 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)参数或字段变更可能导致查询失败
  • 如遇到报错或脚本失效,需要根据最新前端 / 网络请求调整对应逻辑。