YtDLS: Youtube 双语字幕(改)

为YouTube添加双语字幕增强功能。

目前为 2023-08-15 提交的版本。查看 最新版本

// ==UserScript==
// @name                YtDLS: YouTube Dual Language Subtitle (Modified)
// @name:zh-CN          YtDLS: Youtube 双语字幕(改)
// @name:zh-TW          YtDLS: Youtube 雙語字幕(改)
// @version             2.0.0
// @description         Enhances YouTube with dual language subtitles.
// @description:zh-CN   为YouTube添加双语字幕增强功能。
// @description:zh-TW   增強YouTube的雙語字幕功能。
// @author              CY Fung
// @author              Coink Wang
// @match               https://www.youtube.com/*
// @require             https://cdn.jsdelivr.net/npm/[email protected]/dist/ajaxhook.min.js
// @grant               none
// @run-at              document-start
// @namespace           Y2BDoubleSubs
// @license             MIT
// @supportURL          https://github.com/cyfung1031/Y2BDoubleSubs/tree/translation-api
// ==/UserScript==

/* global ah */

(function () {
    let localeLang = document.documentElement.lang || navigator.language || 'en' // follow the language used in YouTube Page
    // localeLang = 'zh'  // uncomment this line to define the language you wish here
    let enableFullWidthSpaceSeparation = true
    function encodeFullwidthSpace(text) {
        if (!enableFullWidthSpaceSeparation) return text
        return text.replace(/\n/g, '\n1\n').replace(/\u3000/g, '\n2\n')
    }
    function decodeFullwidthSpace(text) {
        if (!enableFullWidthSpaceSeparation) return text
        return text.replace(/\n2\n/g, '\u3000').replace(/\n1\n/g, '\n')
    }
    ah.proxy({
        onRequest: (config, handler) => {
            handler.next(config);
        },
        onResponse: (response, handler) => {
            function defaultAction() {
                handler.resolve(response)
            }
            try {
                if (!response.config.url.includes('/api/timedtext') || response.config.url.includes('&translate_h00ked')) return defaultAction()
                let defaultJson = null
                if (response.response) {
                    const jsonResponse = JSON.parse(response.response)
                    if (jsonResponse.events) defaultJson = jsonResponse
                }
                if (defaultJson === null) return defaultAction()
                let lines = []
                for (const event of defaultJson.events) {
                    for (const seg of event.segs) {
                        if ('utf8' in seg && typeof seg.utf8 === 'string') {
                            lines.push(...seg.utf8.split('\n'))
                        }
                    }
                }
                let linesText = lines.join('\n')
                linesText = encodeFullwidthSpace(linesText)
                let q = encodeURIComponent(linesText)
                fetch(`https://translate.googleapis.com/translate_a/single?client=gtx&sl=auto&tl=${localeLang}&dj=1&dt=t&dt=rm&q=${q}`)
                    .then(res => {
                        return res.json()
                    })
                    .then(result => {
                        let resultText = result.sentences.map((function (s) {
                            return "trans" in s ? s.trans : "";
                        })).join("")
                        resultText = decodeFullwidthSpace(resultText)
                        return resultText.split("\n");
                    })
                    .then(translatedLines => {
                        const addTranslation = (line, idx) => {
                            if (line !== lines[i + idx]) return line
                            let translated = translatedLines[i + idx]
                            if (line === translated) return line
                            return `${line}\n${translated}`
                        }
                        let i = 0
                        for (const event of defaultJson.events) {
                            for (const seg of event.segs) {
                                if ('utf8' in seg && typeof seg.utf8 === 'string') {
                                    let s = seg.utf8.split('\n')
                                    let st = s.map(addTranslation)
                                    seg.utf8 = st.join('\n')
                                    i += s.length
                                }
                            }
                        }
                        response.response = JSON.stringify(defaultJson)
                        handler.resolve(response)
                    }).catch(e => {
                        console.warn(e)
                        defaultAction()
                    })
            } catch (e) {
                console.warn(e)
                defaultAction()
            }
        }
    })
})();

QingJ © 2025

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