Youtube Subtitle From Romaji to Hiragana

Translate the romaji subtitle to hiragana

当前为 2021-07-10 提交的版本,查看 最新版本

// ==UserScript==
// @name         Youtube Subtitle From Romaji to Hiragana
// @namespace    http://tampermonkey.net/
// @version      0.2
// @description  Translate the romaji subtitle to hiragana
// @author       CY Fung
// @match        https://www.youtube.com/*
// @icon         https://www.google.com/s2/favicons?domain=youtube.com
// @require      https://unpkg.com/[email protected]/umd/wanakana.min.js?charset=utf-8
// ==/UserScript==

(function() {
    'use strict';

    if(!window.WeakRef) throw 'This script only supports the latest browsers.';

    let cid, mto, elmWR;

    function fromNewText(oldText){


            let m=oldText.split(/([aiueokstnhmyrwmngzdbplyfxcjāēīōū]*[aeiouāēīōūn])/i);


            if(m.length<3)return null;


            if(m.some((str,i)=>{

                if(i%2)return false;
                if(/[a-zA-Zāēīōū]/.test(str))return true;

            }))return null;


            m=m.map((str,i)=>{

                if(!(i%2)){
                    if(str=='' || str==' ' || str==' ') return ' ';
                    if(/\s/.test(str))return str;
                    return ' '+str+' ';
                }

                let dstr=str;

                str=str.replace(/[āēīōū]/g,b=>{
                        let c;

                        switch(b){
                            case 'ā':
                                c='a';
                                return c+c;
                                break;
                            case 'ē':
                                c='e';
                                break;
                            case 'ī':
                                c='i';
                                return c+c;
                                break;
                            case 'ō':
                                c='o';
                                break;
                            case 'ū':
                                c='u';
                                return c+c;
                                break;
                            default:
                                return _;
                        }


                        return c+'5';


                    });


                    str=str.replace(/^[aiueokstnhmyrwmngzdbplyfxcj]*[aeioun]$/i,function(_){


                        return window.wanakana.toKana(_);

                    })

                        str=str.replace(/^[aiueokstnhmyrwmngzdbplyfxcj5]*[aeiou5n]$/i,function(_){

                        _=_.toUpperCase();
                        return _.split('5').map(t=>window.wanakana.toKana(t)).join('ー');

                    });

                if(/[a-zA-Zāēīōū]/.test(str))return dstr;

                return str;


            })


        return m.join('')

    }

    function targetCaptionWindow(pElm){

        if(pElm.style.width && pElm.style.marginLeft && pElm.style.left=='50%'){
            Promise.resolve(pElm).then(pElm=>{

                pElm.style.width='';
                pElm.style.transform='scaleX(0.8)';
                return pElm;
            }).then(pElm=>{
                requestAnimationFrame(()=> {
                    let w=pElm.offsetWidth+20
                    pElm.style.width=w+'px';
                    pElm.style.marginLeft= (-w/2).toFixed(2) +'px';
                } )
            })
        }
    }

    function mtoFunc(mutations, observer){


        for(const s of elmWR.deref().querySelectorAll('span.ytp-caption-segment')){




            let oldText=s.textContent||"";


            if(!oldText) continue;


            let newText = fromNewText(oldText);

            if(!newText) continue;


                if(newText !== oldText && !/[a-zA-Z]/.test(newText) ){


                    newText = newText
                        .replace(/[\!\?\,]/g,(_)=> String.fromCharCode(_.charCodeAt(0)+(0xFF1F-0x003F)))
                        .replace(/([\u3040-\u309F\u30A0-\u30FF])\s+([\uFF01-\uFF5E]+)/g,(_,a,b)=>a+b)
                        .replace(/([\u3040-\u309F\u30A0-\u30FF])\s*[,,]\s*([\u3040-\u309F\u30A0-\u30FF])/g,(_,a,b)=>a+'、'+b)
                        .replace(/ お\s*([ ""])/g,(_,a)=>'を'+a)
                        .replace(/([\u3040-\u309F\u30A0-\u30FF]) ([かてでにがのも]\s*([^\u3040-\u309F\u30A0-\u30FF]|$))/g,(_,a,b)=>a+b)
                        .replace(/([\u3040-\u309F\u30A0-\u30FF]) ([かてでにがのも]\s*([^\u3040-\u309F\u30A0-\u30FF]|$))/g,(_,a,b)=>a+b)
                        .replace(/([\u3040-\u309F\u30A0-\u30FF]) ([かてでにがのも]\s*([^\u3040-\u309F\u30A0-\u30FF]|$))/g,(_,a,b)=>a+b)


                    s.textContent = newText;

                    let pElm=s;
                    while(pElm && pElm.parentNode){

                        if(pElm.className.indexOf('caption-window')>=0) {

                            targetCaptionWindow(pElm);

                            break;
                        }
                        pElm=pElm.parentNode;
                    }


                }


        }


    }

    function onNavigationEnd(){

        if(!/https\:\/\/www\.youtube\.com\/watch?.*v=[^\?\&]+/.test(location.href))return;


        if(cid) cid=clearInterval(cid);
        if(mto) {
            mto.takeRecords()
            mto.disconnect()
            mto=null;
        }

        if(elmWR) {
            elmWR=null;
        }


        cid=setInterval(()=>{

            let s=document.querySelector('#ytp-caption-window-container');
            if(!s)return;

            cid=clearInterval(cid);

            elmWR = new window.WeakRef(s);

            mto = new MutationObserver(mtoFunc);

            mto.observe(elmWR.deref(),{subtree: true, childList: true, attributes:false});

        },400)


    }



    window.addEventListener("yt-navigate-finish", onNavigationEnd)

    // Your code here...
})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址