BlueSky Correct Terminology

Ensures BlueSky is using the correct terminology by replacing all instances of "post" with "skeet".

Vous devrez installer une extension telle que Tampermonkey, Greasemonkey ou Violentmonkey pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey ou Violentmonkey pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey ou Userscripts pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey pour installer ce script.

Vous devrez installer une extension de gestionnaire de script utilisateur pour installer ce script.

(J'ai déjà un gestionnaire de scripts utilisateur, laissez-moi l'installer !)

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

(J'ai déjà un gestionnaire de style utilisateur, laissez-moi l'installer!)

// ==UserScript==
// @name        BlueSky Correct Terminology
// @description Ensures BlueSky is using the correct terminology by replacing all instances of "post" with "skeet".
// @namespace   vivelin.net
// @match       https://bsky.app/*
// @grant       none
// @version     1.0.7
// @author      Vivelin
// @license     MIT
// ==/UserScript==
(function () {
    "use strict";

    /**
     * An object containing an array of RegExp patterns and string replacements for each language.
     */
    const allReplacements = {
        en: [
            { pattern: /\bPost(s)?\b/g, replacement: "Skeet$1" },
            { pattern: /\b([Rr]e)?post(s|ed)?\b/g, replacement: "$1skeet$2" },
        ],
    };

    /**
     * Controls whether user-generated content should be processed (true) or left alone (false, default).
     */
    const shouldReplaceSkeetContent = false;

    /**
     * Replaces the string, if necessary.
     * @param {string} text The original text to replace.
     * @param replacements An array of objects with the RegExp pattern and string replacement.
     * @returns {string} The replaced text.
     */
    function replaceText(text, replacements) {
        if (!text) return text;

        for (const replacement of replacements) {
            if (text.match(replacement.pattern)) {
                text = text.replaceAll(
                    replacement.pattern,
                    replacement.replacement,
                );
            }
        }

        return text;
    }

    /**
     * Recursively processes and replaces all instances of text.
     * @param {Node} node The node to process.
     * @returns {void}
     */
    function processNode(node, replacements) {
        node = node || document.body;

        if (node instanceof Text) {
            node.data = replaceText(node.data, replacements);
        } else if (node instanceof HTMLElement) {
            if (
                node.isContentEditable ||
                (!shouldReplaceSkeetContent &&
                    (node.dataset.wordWrap === "1" ||
                        node.dataset.testid === "profileHeaderDisplayName" ||
                        node.ariaLabel === "Expand alt text" ||
                        (node instanceof HTMLAnchorElement &&
                            node.href &&
                            node.href.match(/\/profile\//))))
            ) {
                return;
            }

            for (const child of node.childNodes) {
                processNode(child, replacements);
            }
        }
    }

    function observeCallback(_mutationList, _observer) {
        const lang = document.getElementsByTagName("html")[0].lang || "en";
        const replacements = allReplacements[lang];
        if (replacements) {
            processNode(document.body, replacements);
        }
    }

    const observer = new MutationObserver(observeCallback);
    observer.observe(document.body, { childList: true, subtree: true });
})();