NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript==
// @name Flag Replacer
// @version 1.9
// @description Adjustment of countries and regions.
// @author Leo79 (https://openuserjs.org/users/Leo79)
// @license MIT
// @updateURL https://openuserjs.org/meta/Leo79/Flag_Replacer.meta.js
// @downloadURL https://openuserjs.org/install/Leo79/Flag_Replacer.user.js
// @copyright 2026, Leo79 (https://openuserjs.org/users/Leo79)
// @match *://*.vlr.gg/*
// @run-at document-start
// @grant none
// ==/UserScript==
(function () {
'use strict';
const TW_FLAG = '';
const CN_FLAG = '';
const SKIPPED_TEXT_PARENT_SELECTOR = 'script, style, textarea, input, noscript';
const TARGET_FLAG_SELECTOR = '.flag.mod-tw, .flag.mod-hk, .flag.mod-mo';
const TEXT_REPLACEMENTS = [
[TW_FLAG, CN_FLAG],
[/\bTaiwan\b(?! Province, China)/gi, 'Taiwan Province, China'],
[/\bHong Kong\b(?! SAR, China)/gi, 'Hong Kong SAR, China'],
[/\bMaca[ou]\b(?! SAR, China)/gi, 'Macao SAR, China'],
];
// --- Text replacement (idempotent via negative lookaheads) ---
function replaceText(text, options = {}) {
let s = text;
for (const [pattern, replacement] of TEXT_REPLACEMENTS) {
s = s.replace(pattern, replacement);
}
if (options.replaceStandaloneCountryCode) {
s = s.replace(/^(\s*)TW(\s*)$/g, '$1Taiwan Province, China$2');
}
return s;
}
function shouldSkipTextNode(node) {
return Boolean(node.parentElement?.closest(SKIPPED_TEXT_PARENT_SELECTOR));
}
function hasNearbyTaiwanFlag(node) {
const parent = node.parentElement;
if (!parent) return false;
if (parent.querySelector?.('.flag.mod-tw')) return true;
return Boolean(parent.previousElementSibling?.matches?.('.flag.mod-tw'));
}
function replaceInTextNode(node) {
if (!node.nodeValue || shouldSkipTextNode(node)) return;
const newValue = replaceText(node.nodeValue, {
replaceStandaloneCountryCode: hasNearbyTaiwanFlag(node),
});
if (newValue !== node.nodeValue) {
node.nodeValue = newValue;
}
}
function walkTextNodes(root) {
const walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT, {
acceptNode(node) {
return shouldSkipTextNode(node) ? NodeFilter.FILTER_REJECT : NodeFilter.FILTER_ACCEPT;
},
});
while (walker.nextNode()) {
replaceInTextNode(walker.currentNode);
}
}
// --- Flag element replacement (vlr.gg CSS class based) ---
function fixFlagElement(el) {
if (!el || !el.classList || !el.classList.contains('flag')) return;
if (el.classList.contains('mod-tw')) {
el.classList.replace('mod-tw', 'mod-cn');
el.setAttribute('title', 'China');
}
else if (el.classList.contains('mod-hk')) {
el.setAttribute('title', 'Hong Kong SAR, China');
}
else if (el.classList.contains('mod-mo')) {
el.setAttribute('title', 'Macao SAR, China');
}
}
function fixFlagElements(root) {
if (!root.querySelectorAll) return;
const flags = root.querySelectorAll(TARGET_FLAG_SELECTOR);
for (const el of flags) {
fixFlagElement(el);
}
}
function processElement(el) {
walkTextNodes(el);
fixFlagElement(el);
fixFlagElements(el);
}
// --- MutationObserver ---
const observer = new MutationObserver((mutations) => {
for (const m of mutations) {
if (m.type === 'childList') {
for (const node of m.addedNodes) {
if (node.nodeType === Node.TEXT_NODE) {
replaceInTextNode(node);
}
else if (node.nodeType === Node.ELEMENT_NODE) {
processElement(node);
}
}
}
else if (m.type === 'characterData') {
replaceInTextNode(m.target);
}
else if (m.type === 'attributes') {
fixFlagElement(m.target);
}
}
});
// Start observing early, then let DOMContentLoaded/load do full-body passes.
observer.observe(document.documentElement || document, {
childList: true,
subtree: true,
characterData: true,
attributes: true,
attributeFilter: ['class'],
});
// --- Initialization ---
function init() {
if (document.body) processElement(document.body);
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init, {
once: true
});
}
else {
init();
}
// Safety net: re-scan after all resources are loaded
window.addEventListener('load', () => {
if (document.body) processElement(document.body);
}, {
once: true
});
})();