Superscript Pinyin for Chinese Characters with API

Adds superscript pinyin to all Chinese characters on a webpage using an external API with accurate processing and placement. Includes a toggle shortcut. Uses superscript to show the pinyin next to the character. Toggles on and off with ctrl + shift + p. Defaults to off. Perfectly reversible.

От 20.08.2024. Виж последната версия.

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey, Greasemonkey или Violentmonkey.

You will need to install an extension such as Tampermonkey to install this script.

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey или Violentmonkey.

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey или Userscripts.

За да инсталирате скрипта, трябва да инсталирате разширение като Tampermonkey.

За да инсталирате този скрипт, трябва да имате инсталиран скриптов мениджър.

(Вече имам скриптов мениджър, искам да го инсталирам!)

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

(Вече имам инсталиран мениджър на стиловете, искам да го инсталирам!)

// ==UserScript==
// @name         Superscript Pinyin for Chinese Characters with API
// @namespace    http://tampermonkey.net/
// @version      2.6
// @description  Adds superscript pinyin to all Chinese characters on a webpage using an external API with accurate processing and placement. Includes a toggle shortcut. Uses superscript to show the pinyin next to the character. Toggles on and off with ctrl + shift + p. Defaults to off. Perfectly reversible.
// @author       Louis
// @match        *://*/*
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    // Cache for storing pinyin results to avoid duplicate API calls
    const pinyinCache = new Map(Object.entries({'的':'de','一':'yī','是':'shì','不':'bù','了':'le','在':'zài','人':'rén','有':'yǒu','我':'wǒ','他':'tā','这':'zhè','个':'gè','们':'men','中':'zhōng','来':'lái','上':'shàng','大':'dà','为':'wèi','和':'hé','国':'guó','地':'de','到':'dào','以':'yǐ','说':'shuō','时':'shí','要':'yào','就':'jiù','出':'chū','会':'huì','可':'kě','也':'yě','你':'nǐ','对':'duì','生':'shēng','能':'néng','而':'ér','子':'zi','那':'nà','得':'dé','于':'yú','着':'zhe','下':'xià','自':'zì','之':'zhī','年':'nián','过':'guò','发':'fā','后':'hòu','作':'zuò','里':'lǐ','用':'yòng','道':'dào','行':'xíng','所':'suǒ','然':'rán','家':'jiā','种':'zhǒng','事':'shì','成':'chéng','方':'fāng','多':'duō','经':'jīng','么':'me','去':'qù','法':'fǎ','学':'xué','如':'rú','都':'dōu','同':'tóng','现':'xiàn','当':'dāng','没':'méi','动':'dòng','面':'miàn','起':'qǐ','看':'kàn','定':'dìng','天':'tiān','分':'fēn','还':'hái','进':'jìn','好':'hǎo','小':'xiǎo','部':'bù','其':'qí','些':'xiē','主':'zhǔ','样':'yàng','理':'lǐ','心':'xīn','她':'tā','本':'běn','前':'qián','开':'kāi','但':'dàn','因':'yīn','只':'zhǐ','从':'cóng','想':'xiǎng','实':'shí','日':'rì','军':'jūn','者':'zhě','意':'yì','无':'wú','力':'lì','它':'tā','与':'yǔ','长':'zhǎng','把':'bǎ','机':'jī','十':'shí','民':'mín','第':'dì','公':'gōng','此':'cǐ','已':'yǐ','工':'gōng','使':'shǐ','情':'qíng','明':'míng','性':'xìng','知':'zhī','全':'quán','三':'sān','又':'yòu','关':'guān','点':'diǎn','正':'zhèng','业':'yè','外':'wài','将':'jiāng','两':'liǎng','高':'gāo','间':'jiān','由':'yóu','问':'wèn','很':'hěn','最':'zuì','重':'zhòng','并':'bìng','物':'wù','手':'shǒu','应':'yīng','战':'zhàn','向':'xiàng','头':'tóu','文':'wén','体':'tǐ','政':'zhèng','美':'měi','相':'xiāng','见':'jiàn','被':'bèi','利':'lì','什':'shén','二':'èr','等':'děng','产':'chǎn','或':'huò','新':'xīn','己':'jǐ','制':'zhì','身':'shēn','果':'guǒ','加':'jiā','西':'xī','斯':'sī','月':'yuè','话':'huà','合':'hé','回':'huí','特':'tè','代':'dài','内':'nèi','信':'xìn','表':'biǎo','化':'huà','老':'lǎo','给':'gěi','世':'shì','位':'wèi','次':'cì','度':'dù','门':'mén','任':'rèn','常':'cháng','先':'xiān','海':'hǎi','通':'tōng','教':'jiào','儿':'ér','原':'yuán','东':'dōng','声':'shēng','提':'tí','立':'lì','及':'jí','比':'bǐ','员':'yuán','解':'jiě','水':'shuǐ','名':'míng','真':'zhēn','论':'lùn','处':'chù','走':'zǒu','义':'yì','各':'gè','入':'rù','几':'jǐ','口':'kǒu','认':'rèn','条':'tiáo','平':'píng','系':'xì','气':'qì','题':'tí','活':'huó','尔':'ěr','更':'gèng','别':'bié','打':'dǎ','女':'nǚ','变':'biàn','四':'sì','神':'shén','总':'zǒng','何':'hé','电':'diàn','数':'shù','安':'ān','少':'shǎo','报':'bào','才':'cái','结':'jié','反':'fǎn','受':'shòu','目':'mù','太':'tài','量':'liàng','再':'zài','感':'gǎn','建':'jiàn','务':'wù','做':'zuò','接':'jiē','必':'bì','场':'chǎng','件':'jiàn','计':'jì','管':'guǎn','期':'qī','市':'shì','直':'zhí','德':'dé','资':'zī','命':'mìng','山':'shān','金':'jīn','指':'zhǐ','克':'kè','许':'xǔ','统':'tǒng','区':'qū','保':'bǎo','至':'zhì','队':'duì','形':'xíng','社':'shè','便':'biàn','空':'kōng','决':'jué','治':'zhì','展':'zhǎn','马':'mǎ','科':'kē','司':'sī','五':'wǔ','基':'jī','眼':'yǎn','书':'shū','非':'fēi','则':'zé','听':'tīng','白':'bái','却':'què','界':'jiè','达':'dá','光':'guāng','放':'fàng','强':'qiáng','即':'jí','像':'xiàng','难':'nán','且':'qiě','权':'quán','思':'sī','王':'wáng','象':'xiàng','完':'wán','设':'shè','式':'shì','色':'sè','路':'lù','记':'jì','南':'nán','品':'pǐn','住':'zhù','告':'gào','类':'lèi','求':'qiú','据':'jù','程':'chéng','北':'běi','边':'biān','死':'sǐ','张':'zhāng','该':'gāi','交':'jiāo','规':'guī','万':'wàn','取':'qǔ','拉':'lā','格':'gé','望':'wàng','觉':'jué','术':'shù','领':'lǐng','共':'gòng','确':'què','传':'chuán','师':'shī','观':'guān','清':'qīng','今':'jīn','切':'qiè','院':'yuàn','让':'ràng','识':'shí','候':'hòu','带':'dài','导':'dǎo','争':'zhēng','运':'yùn','笑':'xiào','飞':'fēi','风':'fēng','步':'bù','改':'gǎi','收':'shōu','根':'gēn','干':'gàn','造':'zào','言':'yán','联':'lián','持':'chí','组':'zǔ','每':'měi','济':'jì','车':'chē','亲':'qīn','极':'jí','林':'lín','服':'fú','快':'kuài','办':'bàn','议':'yì','往':'wǎng','元':'yuán','英':'yīng','士':'shì','证':'zhèng','近':'jìn','失':'shī','转':'zhuǎn','夫':'fū','令':'lìng','准':'zhǔn','布':'bù','始':'shǐ','怎':'zěn','呢':'ne','存':'cún','未':'wèi','远':'yuǎn','叫':'jiào','台':'tái','单':'dān','影':'yǐng','具':'jù','罗':'luō','字':'zì','爱':'ài','击':'jī','流':'liú','备':'bèi','兵':'bīng','连':'lián','调':'diào','深':'shēn','商':'shāng','算':'suàn','质':'zhì','团':'tuán','集':'jí','百':'bǎi','需':'xū','价':'jià','花':'huā','党':'dǎng','华':'huá','城':'chéng','石':'shí','级':'jí','整':'zhěng','府':'fǔ','离':'lí','况':'kuàng','亚':'yà','请':'qǐng','技':'jì','际':'jì','约':'yuē','示':'shì','复':'fù','病':'bìng','息':'xī','究':'jiū','线':'xiàn','似':'shì','官':'guān','火':'huǒ','断':'duàn','精':'jīng','满':'mǎn','支':'zhī','视':'shì','消':'xiāo','越':'yuè','器':'qì','容':'róng','照':'zhào','须':'xū','九':'jiǔ','增':'zēng','研':'yán','写':'xiě','称':'chēng','企':'qǐ','八':'bā','功':'gōng','吗':'ma','包':'bāo','片':'piàn','史':'shǐ','委':'wěi','乎':'hū','查':'chá','轻':'qīng','易':'yì','早':'zǎo','曾':'céng','除':'chú','农':'nóng','找':'zhǎo','装':'zhuāng','广':'guǎng','显':'xiǎn','吧':'ba','阿':'ā','李':'lǐ','标':'biāo','谈':'tán','吃':'chī','图':'tú','念':'niàn','六':'liù','引':'yǐn','历':'lì','首':'shǒu','医':'yī','局':'jú','突':'tū','专':'zhuān','费':'fèi','号':'hào','尽':'jǐn','另':'lìng','周':'zhōu','较':'jiào','注':'zhù','语':'yǔ','仅':'jǐn','考':'kǎo','落':'luò','青':'qīng','随':'suí','选':'xuǎn','列':'liè','武':'wǔ','红':'hóng','响':'xiǎng','虽':'suī','推':'tuī','势':'shì','参':'cān','希':'xī','古':'gǔ','众':'zhòng','构':'gòu','房':'fáng','半':'bàn','节':'jié','土':'tǔ','投':'tóu','某':'mǒu','案':'àn','黑':'hēi','维':'wéi','革':'gé','划':'huà','敌':'dí','致':'zhì','陈':'chén','律':'lǜ','足':'zú','态':'tài','护':'hù','七':'qī','兴':'xìng','派':'pài','孩':'hái','验':'yàn','责':'zé','营':'yíng','星':'xīng','够':'gòu','章':'zhāng','音':'yīn','跟':'gēn','志':'zhì','底':'dǐ','站':'zhàn','严':'yán','巴':'bā','例':'lì','防':'fáng','族':'zú','供':'gōng','效':'xiào','续':'xù','施':'shī','留':'liú','讲':'jiǎng','型':'xíng','料':'liào','终':'zhōng','答':'dá','紧':'jǐn','黄':'huáng','绝':'jué','奇':'qí','察':'chá','母':'mǔ','京':'jīng','段':'duàn','依':'yī','批':'pī','群':'qún','项':'xiàng','故':'gù','按':'àn','河':'hé','米':'mǐ','围':'wéi','江':'jiāng','织':'zhī','害':'hài','斗':'dòu','双':'shuāng','境':'jìng','客':'kè','纪':'jì','采':'cǎi','举':'jǔ','杀':'shā','攻':'gōng','父':'fù','苏':'sū','密':'mì','低':'dī','朝':'cháo','友':'yǒu','诉':'sù','止':'zhǐ','细':'xì','愿':'yuàn','千':'qiān','值':'zhí','仍':'réng','男':'nán','钱':'qián','破':'pò','网':'wǎng','热':'rè','助':'zhù','倒':'dào','育':'yù','属':'shǔ','坐':'zuò','帝':'dì','限':'xiàn','船':'chuán','脸':'liǎn','职':'zhí','速':'sù','刻':'kè','乐':'lè','否':'fǒu','刚':'gāng','威':'wēi','毛':'máo','状':'zhuàng','率':'lǜ','甚':'shén','独':'dú','球':'qiú','般':'bān','普':'pǔ','怕':'pà','弹':'dàn','校':'xiào','苦':'kǔ','创':'chuàng','假':'jiǎ','久':'jiǔ','错':'cuò','承':'chéng','印':'yìn','晚':'wǎn','兰':'lán','试':'shì','股':'gǔ','拿':'ná','脑':'nǎo','预':'yù','谁':'shuí','益':'yì','阳':'yáng','若':'ruò','哪':'nǎ','微':'wēi','尼':'ní','继':'jì','送':'sòng','急':'jí','血':'xuè','惊':'jīng','伤':'shāng','素':'sù','药':'yào','适':'shì','波':'bō','夜':'yè','省':'shěng','初':'chū','喜':'xǐ','卫':'wèi','源':'yuán','食':'shí','险':'xiǎn','待':'dài','述':'shù','陆':'lù','习':'xí','置':'zhì','居':'jū','劳':'láo','财':'cái','环':'huán','排':'pái','福':'fú','纳':'nà','欢':'huān','雷':'léi','警':'jǐng','获':'huò','模':'mó','充':'chōng','负':'fù','云':'yún','停':'tíng','木':'mù','游':'yóu','龙':'lóng','树':'shù','疑':'yí','层':'céng','冷':'lěng','洲':'zhōu','冲':'chōng','射':'shè','略':'lüè','范':'fàn','竟':'jìng','句':'jù','室':'shì','异':'yì','激':'jī','汉':'hàn','村':'cūn','哈':'hā','策':'cè','演':'yǎn','简':'jiǎn','卡':'kǎ','罪':'zuì','判':'pàn','担':'dān','州':'zhōu','静':'jìng','退':'tuì','既':'jì','衣':'yī','您':'nín','宗':'zōng','积':'jī','余':'yú','痛':'tòng','检':'jiǎn','差':'chà','富':'fù','灵':'líng','协':'xié','角':'jiǎo','占':'zhàn','配':'pèi','征':'zhēng','修':'xiū','皮':'pí','挥':'huī','胜':'shèng','降':'jiàng','阶':'jiē','审':'shěn','沉':'chén','坚':'jiān','善':'shàn','妈':'mā','刘':'liú','读':'dú','啊':'a','超':'chāo','免':'miǎn','压':'yā','银':'yín','买':'mǎi','皇':'huáng','养':'yǎng','伊':'yī','怀':'huái','执':'zhí','副':'fù','乱':'luàn','抗':'kàng','犯':'fàn','追':'zhuī','帮':'bāng','宣':'xuān','佛':'fú','岁':'suì','航':'háng','优':'yōu','怪':'guài','香':'xiāng','著':'zhe','田':'tián','铁':'tiě','控':'kòng','税':'shuì','左':'zuǒ','右':'yòu','份':'fèn','穿':'chuān','艺':'yì','背':'bèi','阵':'zhèn','草':'cǎo','脚':'jiǎo','概':'gài','恶':'è','块':'kuài','顿':'dùn','敢':'gǎn','守':'shǒu','酒':'jiǔ','岛':'dǎo','托':'tuō','央':'yāng','户':'hù','烈':'liè','洋':'yáng','哥':'gē','索':'suǒ','胡':'hú','款':'kuǎn','靠':'kào','评':'píng','版':'bǎn','宝':'bǎo','座':'zuò','释':'shì','景':'jǐng','顾':'gù','弟':'dì','登':'dēng','货':'huò','互':'hù','付':'fù','伯':'bó','慢':'màn','欧':'ōu','换':'huàn','闻':'wén','危':'wēi','忙':'máng','核':'hé','暗':'àn','姐':'jiě','介':'jiè','坏':'huài','讨':'tǎo','丽':'lì','良':'liáng','序':'xù','升':'shēng','监':'jiān','临':'lín','亮':'liàng','露':'lù','永':'yǒng','呼':'hū','味':'wèi','野':'yě','架':'jià','域':'yù','沙':'shā','掉':'diào','括':'kuò','舰':'jiàn','鱼':'yú','杂':'zá','误':'wù','湾':'wān','吉':'jí','减':'jiǎn','编':'biān','楚':'chǔ','肯':'kěn','测':'cè','败':'bài','屋':'wū','跑':'pǎo','梦':'mèng','散':'sàn','温':'wēn','困':'kùn','剑':'jiàn','渐':'jiàn','封':'fēng','救':'jiù','贵':'guì','枪':'qiāng','缺':'quē','楼':'lóu','县':'xiàn','尚':'shàng','毫':'háo','移':'yí','娘':'niáng','朋':'péng','画':'huà','班':'bān','智':'zhì','亦':'yì','耳':'ěr','恩':'ēn','短':'duǎn','掌':'zhǎng','恐':'kǒng','遗':'yí','固':'gù','席':'xí','松':'sōng','秘':'mì','谢':'xiè','鲁':'lǔ','遇':'yù','康':'kāng','虑':'lǜ','幸':'xìng','均':'jūn','销':'xiāo','钟':'zhōng','诗':'shī','藏':'cáng','赶':'gǎn','剧':'jù','票':'piào','损':'sǔn','忽':'hū','巨':'jù','炮':'pào','旧':'jiù','端':'duān','探':'tàn','湖':'hú','录':'lù','叶':'yè','春':'chūn','乡':'xiāng','附':'fù','吸':'xī','予':'yǔ','礼':'lǐ','港':'gǎng','雨':'yǔ','呀':'ya','板':'bǎn','庭':'tíng','妇':'fù','归':'guī','睛':'jīng','饭':'fàn','额':'é','含':'hán','顺':'shùn','输':'shū','摇':'yáo','招':'zhāo','婚':'hūn','脱':'tuō','补':'bǔ','谓':'wèi','督':'dū','毒':'dú','油':'yóu','疗':'liáo','旅':'lǚ','泽':'zé','材':'cái','灭':'miè','逐':'zhú','莫':'mò','笔':'bǐ','亡':'wáng','鲜':'xiān','词':'cí','圣':'shèng','择':'zé','寻':'xún','厂':'chǎng','睡':'shuì','博':'bó','勒':'lēi','烟':'yān','授':'shòu','诺':'nuò','伦':'lún','岸':'àn','奥':'ào','唐':'táng','卖':'mài','俄':'é','炸':'zhà','载':'zài','洛':'luò','健':'jiàn','堂':'táng','旁':'páng','宫':'gōng','喝':'hē','借':'jiè','君':'jūn','禁':'jìn','阴':'yīn','园':'yuán','谋':'móu','宋':'sòng','避':'bì','抓':'zhuā','荣':'róng','姑':'gū','孙':'sūn','逃':'táo','牙':'yá','束':'shù','跳':'tiào','顶':'dǐng'}));

    // Variable to track whether pinyin superscript is enabled or disabled
    let pinyinEnabled = false;
    let mutationObserver = null;

    // Expanded cache with common Chinese characters and their pinyin
    const initialCache = {};

    // Pre-fill the cache with initial data
    Object.entries(initialCache).forEach(([char, pinyin]) => pinyinCache.set(char, pinyin));

    // Function to make a request to the pinyin API
    async function fetchPinyin(char) {
        if (pinyinCache.has(char)) {
            return pinyinCache.get(char);
        }

        try {
            const response = await fetch(`https://12.yvelin.net/pinyin.php?text=${encodeURIComponent(char)}`);
            const result = await response.json();
            const pinyin = result && result.pinyin ? result.pinyin : '';
            pinyinCache.set(char, pinyin);
            return pinyin;
        } catch (e) {
            console.error(`Failed to fetch pinyin for character: "${char}"`, e);
            return '';
        }
    }

    // Function to apply pinyin superscripts to a given text node
    async function applyPinyin(node) {
        if (node.nodeType === Node.TEXT_NODE) {
            const text = node.textContent;
            const parent = node.parentNode;
            const fragment = document.createDocumentFragment();

            let currentIndex = 0;

            while (currentIndex < text.length) {
                const char = text[currentIndex];
                if (/[\u4e00-\u9fff]/.test(char)) { // Check if the character is Chinese
                    const pinyin = await fetchPinyin(char);

                    // Split the text node and insert the original character and its pinyin as <sup>
                    const charNode = document.createTextNode(char);
                    const supNode = document.createElement('sup');
                    supNode.textContent = pinyin;
                    supNode.setAttribute('data-custom-pinyin-superscript', 'true'); // Set the custom attribute

                    fragment.appendChild(charNode);
                    fragment.appendChild(supNode);
                } else {
                    fragment.appendChild(document.createTextNode(char));
                }
                currentIndex++;
            }

            // Replace the original text node with the fragment
            parent.replaceChild(fragment, node);
        }
    }

    // Function to handle text nodes within an element
    async function processElement(element) {
        const walker = document.createTreeWalker(element, NodeFilter.SHOW_TEXT, null, false);
        const nodes = [];
        while (walker.nextNode()) {
            nodes.push(walker.currentNode);
        }

        for (const node of nodes) {
            await applyPinyin(node);
        }
    }

    // Function to enable or disable the pinyin display
    async function togglePinyin() {
        if (pinyinEnabled) {
            // Remove all <sup> elements with the data attribute
            const superscripts = document.querySelectorAll('sup[data-custom-pinyin-superscript]');
            superscripts.forEach(sup => {
                const parent = sup.parentNode;
                if (parent) {
                    parent.removeChild(sup); // Remove the superscript pinyin
                }
            });
            pinyinEnabled = false;
        } else {
            await processElement(document.body);
            pinyinEnabled = true;

            // Observe for changes to dynamically added content
            mutationObserver = new MutationObserver(async mutations => {
                for (const mutation of mutations) {
                    if (mutation.type === 'childList') {
                        for (const node of mutation.addedNodes) {
                            if (node.nodeType === Node.ELEMENT_NODE) {
                                await processElement(node);
                            }
                        }
                    }
                }
            });
            mutationObserver.observe(document.body, { childList: true, subtree: true });
        }
    }

    // Add CSS for pinyin display (optional, you can style it differently)
    function addCSS() {
        const style = document.createElement('style');
        style.textContent = `
            sup[data-custom-pinyin-superscript] {
                font-size: 0.8em;
                vertical-align: super;
                color: #888;
            }
        `;
        document.head.appendChild(style);
    }

    // Initialize CSS
    addCSS();

    // Listen for keyboard shortcut to toggle pinyin
    document.addEventListener('keydown', (event) => {
        if (event.ctrlKey && event.shiftKey && event.key === 'P') {
            event.preventDefault();
            togglePinyin();
        }
    });

})();