// ==UserScript== // @name Country Flag Fixer // @namespace https://git.ponywave.de/Akamaru/Userscripts // @version 1.0 // @description Ersetzt Ländercodes mit echten Flaggen-Emojis unter Windows/Chromium // @author Akamaru // @match *://*/* // @grant GM_getResourceURL // @resource TwemojiCountryFlags https://cdn.jsdelivr.net/npm/country-flag-emoji-polyfill@0.1.8/dist/TwemojiCountryFlags.woff2 // @updateURL https://git.ponywave.de/Akamaru/Userscripts/raw/branch/master/country-flag-fixer.user.js // @downloadURL https://git.ponywave.de/Akamaru/Userscripts/raw/branch/master/country-flag-fixer.user.js // @run-at document-start // ==/UserScript== // Source: https://github.com/talkjs/country-flag-emoji-polyfill (function() { 'use strict'; const replacementFontName = "Twemoji Country Flags"; const extentionStyleTagId = "country-flag-fixer-ext"; const headStyleTagId = "country-flag-fixer-ext-head"; /** * Registriere die Custom Font-Face für Flaggen-Emojis */ const loadFontFace = () => { const fontUrl = GM_getResourceURL('TwemojiCountryFlags'); const style = document.createElement("style"); style.setAttribute("type", "text/css"); style.setAttribute("id", headStyleTagId); // Unicode range generiert von: https://wakamaifondue.com/beta/ style.textContent = ` @font-face { font-family: "${replacementFontName}"; font-style: normal; src: url('${fontUrl}') format('woff2'); unicode-range: U+1F1E6-1F1FF, U+1F3F4, U+E0062-E0063, U+E0065, U+E0067, U+E006C, U+E006E, U+E0073-E0074, U+E0077, U+E007F; } @font-face { font-family: "${replacementFontName}"; font-style: italic; /* Verhindert kursive Flaggen */ src: url('${fontUrl}') format('woff2'); unicode-range: U+1F1E6-1F1FF, U+1F3F4, U+E0062-E0063, U+E0065, U+E0067, U+E006C, U+E006E, U+E0073-E0074, U+E0077, U+E007F; } `; // Prüfe auf Fälle wie SVG-Dateien ohne head-Element if (document.head != undefined) { document.head.appendChild(style); } }; /** * Extrahiere font-family Regeln aus allen Stylesheets */ const extractFontFamilyRules = () => { const fontFamilyRules = []; for (const sheet of document.styleSheets) { // Ignoriere Styles von dieser Extension if (sheet.ownerNode?.id == extentionStyleTagId || sheet.ownerNode?.id == headStyleTagId) continue; // Ignoriere non-screen Stylesheets const sheetMediaBlacklist = ['print', 'speech', 'aural', 'braille', 'handheld', 'projection', 'tty']; if (sheetMediaBlacklist.includes(sheet.media.mediaText)) continue; try { // Loop durch jeden CSS-Selektor im Stylesheet for (const rule of sheet.cssRules) { if (!rule.style || !rule.style?.fontFamily) continue; const selectorText = rule.selectorText; const fontFamily = rule.style.fontFamily; // 'inherit' kann nicht mit anderen Fonts kombiniert werden if (fontFamily == 'inherit') continue; // Bereits modifizierte Selektoren ignorieren if (fontFamily.toLowerCase().includes(replacementFontName.toLowerCase())) continue; fontFamilyRules.push({ selectorText, fontFamily }); } } catch (e) { // Manche Stylesheets sind wegen CORS nicht zugreifbar } } return fontFamilyRules; }; /** * Erstelle neues Style-Tag mit überschriebenen font-family Regeln */ const createNewStyleTag = (fontFamilyRules) => { const style = document.createElement("style"); style.setAttribute("type", "text/css"); style.setAttribute("id", extentionStyleTagId); fontFamilyRules.forEach((rule) => { // Setze Country Flags Font als Hauptfont; Original als Fallback style.textContent += `${rule.selectorText} { font-family: '${replacementFontName}', ${rule.fontFamily} !important; }\n`; }); return style; }; /** * Wende Custom Font Styles auf die Seite an */ const applyCustomFontStyles = () => { const existingSheet = document.getElementById(extentionStyleTagId); const fontFamilyRules = extractFontFamilyRules(); const newStyleTag = createNewStyleTag(fontFamilyRules); // Schreibe überschriebene Styles komplett neu if (existingSheet) { existingSheet.parentNode.removeChild(existingSheet); } if (document.head == null) return; document.head.appendChild(newStyleTag); }; /** * Bewahre Custom Fonts in inline styles */ const preserveCustomFonts = (element) => { if (element == undefined) return; // Ignoriere Elemente ohne style-Attribut oder font-family const inlineStyle = element.getAttribute('style'); if (!inlineStyle || !inlineStyle.includes('font-family')) return; // Font family regex für Font (Gruppe 1) und !important Modifier (Gruppe 2) const fontFamilyRegex = /font-family\s*:\s*([^;]+?)(\s*!important)?\s*(;|$)/; const match = fontFamilyRegex.exec(inlineStyle); if (!match) return; const hasIsImportant = match[2] && match[2].includes('!important'); if (hasIsImportant) return; const currentFontFamily = match[1].trim(); element.style.setProperty('font-family', currentFontFamily, 'important'); }; /** * Initialisiere das Script */ const init = () => { // Lade Font-Face loadFontFace(); // Warte bis DOM bereit ist if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', () => { applyCustomFontStyles(); }); } else { applyCustomFontStyles(); } // Beobachte Dokument auf dynamisch hinzugefügte Styles let lastStyleSheets = new Set(Array.from(document.styleSheets).map(sheet => sheet.href || sheet.ownerNode?.textContent)); const observer = new MutationObserver((mutations) => { let stylesheetChanged = false; mutations.forEach(mutation => { // Fokussiere nur auf und