Greasy Fork

Greasy Fork is available in English.

添加有道发音

百度翻译页面添加有道发音

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

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

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         添加有道发音
// @namespace    https://github.com/nameldk/user-script
// @version      0.2.2
// @description  百度翻译页面添加有道发音
// @author       nameldk
// @match        https://fanyi.baidu.com/
// @grant        none
// @note         2021.07.21  v0.2.2 修复不能获取最新输入内容的问题
// @note         2021.05.28  v0.2.1 添加加载中效果
// @note         2021.05.27  v0.2 手机访问时添加发音
// ==/UserScript==

(function () {
    'use strict';
    const fromMobile = navigator.userAgent.match(/Android|iPhone|iPad|iPod|Opera Mini|IEMobile/i);
    let curAudio;
    let curIcon;
    let curText;

    function readText(text, elIcon) {
        if (!text || !elIcon)
            return;
        let url = 'https://dict.youdao.com/dictvoice?audio=' + text + '&le=eng';
        let clsActive = 'sound-active';
        let clsLoading = 'sound-load';

        if (elIcon.classList.contains(clsLoading)) {
            return;
        }

        if (curAudio) {
            if (elIcon === curIcon && curText === text) {
                curAudio.currentTime = 0;
                curAudio.play();
                return;
            }
            if (!curAudio.paused) {
                curAudio.pause();
            }
            curIcon.classList.remove(clsActive);
            curIcon.classList.remove(clsLoading);
        }

        let audio = new Audio(url);
        elIcon.classList.add(clsLoading);

        audio.addEventListener('canplay', () => {
            elIcon.classList.remove(clsLoading);
            elIcon.classList.add(clsActive);
        });

        audio.addEventListener('ended', () => {
            elIcon.classList.remove(clsActive);
        });

        audio.addEventListener('canplaythrough', () => {
            audio.play();
            curAudio = audio;
            curIcon = elIcon;
            curText = text;
        });
    }

    function queryAll(selector, parent, cb) {
        if (parent && parent.querySelectorAll) {
            parent.querySelectorAll(selector).forEach((el) => cb(el));
        }
    }

    function observer(targetNode, cb) {
        if (!targetNode)
            return;

        function callback(mutationsList, observer) {
            for (const mutation of mutationsList) {
                if (mutation.type === 'childList') {
                    if (mutation.addedNodes.length) {
                        mutation.addedNodes.forEach((el) => cb(el));
                    }
                }
            }
        }

        const config = {attributes: false, childList: true, subtree: true};
        const observer = new MutationObserver(callback);

        observer.observe(targetNode, config);
    }

    function processPc() {
        let style = `<style>
@-webkit-keyframes loading{0%{-webkit-transform:rotate(0deg)}
25%{-webkit-transform:rotate(90deg)}
50%{-webkit-transform:rotate(180deg)}
75%{-webkit-transform:rotate(270deg)}
100%{-webkit-transform:rotate(360deg)}}
@keyframes loading{0%{-webkit-transform:rotate(0deg)}
25%{-webkit-transform:rotate(90deg)}
50%{-webkit-transform:rotate(180deg)}
75%{-webkit-transform:rotate(270deg)}
100%{-webkit-transform:rotate(360deg)}}
span.yd-voice {
    position: relative;
    display: inline-block;
    top: 2px;
    cursor:pointer;
}
span.yd-voice.sound-active {
    background-image: url(https://fanyi-cdn.cdn.bcebos.com/static/translation/img/translate/output/sound2x_d6f553d.gif);
    background-image: url(https://fanyi-cdn.cdn.bcebos.com/static/translation/img/translate/output/sound1x_a31f763.gif) \\9;
    -moz-background-size: 22px 21px;
    -o-background-size: 22px 21px;
    background-size: 22px 21px;
    background-repeat: no-repeat;
    background-position: 0 -3px;
    padding: 0;
}
span.yd-voice.sound-load {
    background: url(//fanyi.baidu.com/static/translate-mobile/widget/input/load_3ddd478.png) no-repeat;
    background-size: 18px;
    -webkit-animation: loading 1s linear infinite;
    animation: loading 1s linear infinite;
}
</style>`;
        document.body.insertAdjacentHTML('beforeend', style);

        function processIcon(elIcon, text) {
            if (!elIcon)
                return;
            let elParent = elIcon.parentNode;
            let elNext = elParent.nextElementSibling;
            if (elNext && elNext.classList.contains('yd-voice') || elParent.querySelector('.yd-voice')) {
                return;
            }
            text = text || elParent.dataset.soundText;
            if (!text) {
                text = elParent.parentElement.innerText;
            }
            if (!text) {
                return;
            }
            let elA = document.createElement('span');
            elA.className = 'icon-sound yd-voice';
            elA.addEventListener('mouseover', () => {
                readText(getText(text), elA);
            });
            elA.addEventListener('click', () => {
                readText(getText(text), elA);
            });
            if (elNext) {
                elParent.parentNode.insertBefore(elA, elNext);
            } else {
                elParent.parentNode.append(elA);
            }
        }

        function getText(text) {
            if (typeof text === 'function') {
                return text();
            }
            return text;
        }

        queryAll('.icon-sound', document, el => {
            processIcon(el)
        });

        observer(document.querySelector('#left-result-container'), el => {
            queryAll('.icon-sound', el, el => {
                processIcon(el)
            });
        });

        setTimeout(function () {
            let elWrap = document.querySelector('.trans-input-wrap');
            let elInput = document.querySelector('#baidu_translate_input');
            if (elWrap.querySelector('.icon-sound') && elInput) {
                processIcon(elWrap.querySelector('.icon-sound'), () => {
                    return elInput.value;
                });
            }
        }, 1000)
    }

    function processMobile() {
        let style = `<style>
a.yd-voice {
    height: 24px;
    display: flex;
    align-items: center;
    right: 0px;
    position: absolute;
    top: 0px;
}
a.yd-voice span {
    vertical-align: text-bottom;
    background: url(//fanyi.baidu.com/static/translate-mobile/widget/input/sound_59915b5.png) no-repeat;
    background-size: 18px;
    width: 18px;
    height: 18px;
}
a.yd-voice.sound-active span {
    background: url(//fanyi.baidu.com/static/translate-mobile/widget/input/sound_52b079a.gif) -14px -11px no-repeat;
    background-size: 48px;
}
a.yd-voice.sound-load span {
    background: url(//fanyi.baidu.com/static/translate-mobile/widget/input/load_3ddd478.png) no-repeat;
    background-size: 18px;
    -webkit-animation: loading 1s linear infinite;
    animation: loading 1s linear infinite;
}
.entry-idg .yd-voice, #j-transoper .yd-voice{
    position: relative;
}
</style>`;
        document.body.insertAdjacentHTML('beforeend', style);

        function processIcon(elIcon) {
            if (!elIcon)
                return;
            let elParent = elIcon.parentNode;
            if (!elParent)
                return;
            let text = elParent.innerText;
            if (!text) {
                return;
            }
            let elA = genElA(() => {
                return text;
            });

            if (elIcon.nextElementSibling) {
                let el = elIcon.nextElementSibling;
                elParent.insertBefore(elA, el);
                el.style.display = 'none';
            } else {
                elParent.parentNode.append(elA);
            }
        }

        function genElA(cbText) {
            let elA = document.createElement('a');
            elA.appendChild(document.createElement('span'));
            elA.className = 'yd-voice';
            elA.addEventListener('click', () => {
                readText(cbText(), elA);
            });
            return elA;
        }

        setTimeout(function () {
            let elIcon = document.querySelector('#single-sound');
            if (!elIcon || !elIcon.parentNode || !elIcon.nextElementSibling) {
                return;
            }
            let elA = genElA(() => {
                return document.querySelector('#j-textarea').value;
            });
            elIcon.parentNode.insertBefore(elA, elIcon.nextElementSibling);
        }, 1000);

        observer(document.querySelector('#j-extendOutput'), el => {
            queryAll('.sound-btn', el, el => {
                processIcon(el);
            });
        });
    }

    if (fromMobile) {
        processMobile();
    } else {
        processPc();
    }
})();