mirror of
https://github.com/ilyhalight/voice-over-translation.git
synced 2026-05-02 21:40:26 +00:00
first commit
This commit is contained in:
commit
f67afc19a8
5 changed files with 208 additions and 0 deletions
158
vot.user.js
Normal file
158
vot.user.js
Normal file
|
|
@ -0,0 +1,158 @@
|
|||
// ==UserScript==
|
||||
// @name voice-over-translation
|
||||
// @match *://*.youtube.com/*
|
||||
// @version 1.0
|
||||
// @require https://code.jquery.com/jquery-3.6.0.min.js
|
||||
// @resource styles https://raw.githubusercontent.com/sodapng/voice-over-translation/master/styles.css
|
||||
// @grant GM_getResourceText
|
||||
// @grant GM_addStyle
|
||||
// @grant GM_xmlhttpRequest
|
||||
// @updateURL https://raw.githubusercontent.com/sodapng/voice-over-translation/master/vot.user.js
|
||||
// @downloadURL https://raw.githubusercontent.com/sodapng/voice-over-translation/master/vot.user.js
|
||||
// @supportURL https://github.com/sodapng/voice-over-translation/issues
|
||||
// @homepageURL https://github.com/sodapng/voice-over-translation
|
||||
// ==/UserScript==
|
||||
|
||||
const styles = GM_getResourceText("styles");
|
||||
GM_addStyle(styles);
|
||||
|
||||
const fragment = new DocumentFragment();
|
||||
const span = $("<span>");
|
||||
|
||||
$(span).addClass("translation-btn");
|
||||
|
||||
fragment.appendChild(span[0]);
|
||||
const audio = new Audio();
|
||||
|
||||
const getVeideoId = () => {
|
||||
const url = new URL(window.location.href);
|
||||
|
||||
if (url.pathname.includes("watch")) {
|
||||
return url.searchParams.get("v");
|
||||
}
|
||||
|
||||
if (url.pathname.includes("embed")) {
|
||||
return url.pathname.substr(7, 11);
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
const getUrlAudio = (videoId) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
GM_xmlhttpRequest({
|
||||
url: "https://api.browser.yandex.ru/video-translation/translate",
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/x-protobuf",
|
||||
"User-Agent":
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.85 YaBrowser/21.11.2.773 Yowser/2.5 Safari/537.36",
|
||||
},
|
||||
data: `\x1A\x1Chttps://youtu.be/${videoId}\x28\x01`,
|
||||
onload: (res) => {
|
||||
if (res.total === 40 || res.total === 42) {
|
||||
return reject("VIDEO-TRANSLATION: can not translate");
|
||||
}
|
||||
|
||||
if (res.status === 200) {
|
||||
return resolve(res.response);
|
||||
}
|
||||
|
||||
return reject("VIDEO-TRANSLATION: bad request");
|
||||
},
|
||||
onerror: (err) => {
|
||||
return reject("VIDEO-TRANSLATION: connection error");
|
||||
},
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const deleteAudioSrc = () => {
|
||||
audio.src = "";
|
||||
audio.removeAttribute("src");
|
||||
};
|
||||
|
||||
$("body").on("yt-page-data-updated", function () {
|
||||
var video = $("video")[0];
|
||||
$(".html5-video-container").append(fragment);
|
||||
|
||||
const lipSync = (mode = false) => {
|
||||
audio.currentTime = video.currentTime;
|
||||
// audio.volume = video.volume
|
||||
|
||||
if (!mode) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mode === "play") {
|
||||
audio.play();
|
||||
}
|
||||
|
||||
if (mode === "pause") {
|
||||
audio.pause();
|
||||
}
|
||||
};
|
||||
|
||||
$(span).click(function (event) {
|
||||
event.stopPropagation();
|
||||
|
||||
if (audio.src) {
|
||||
deleteAudioSrc();
|
||||
event.stopImmediatePropagation();
|
||||
}
|
||||
});
|
||||
|
||||
$(span).click(async function (event) {
|
||||
try {
|
||||
event.stopPropagation();
|
||||
|
||||
const VIDEO_ID = getVeideoId();
|
||||
|
||||
if (!VIDEO_ID) {
|
||||
throw "VIDEO-TRANSLATION: not found video id";
|
||||
}
|
||||
|
||||
const rawResponse = await getUrlAudio(VIDEO_ID);
|
||||
|
||||
const URL_AUDIO = rawResponse.match(/https.*[a-z0-9]{64}|https.*mp3/);
|
||||
|
||||
if (!URL_AUDIO) {
|
||||
throw "VIDEO-TRANSLATION: raw string error";
|
||||
}
|
||||
|
||||
audio.src = URL_AUDIO[0];
|
||||
|
||||
$("body").one("yt-page-data-updated", function () {
|
||||
audio.pause();
|
||||
$("video").off(".translate");
|
||||
deleteAudioSrc();
|
||||
});
|
||||
|
||||
if (!video.paused) {
|
||||
lipSync("play");
|
||||
}
|
||||
|
||||
$("video").on("playing.translate", function () {
|
||||
lipSync();
|
||||
});
|
||||
|
||||
$("video").on("play.translate canplaythrough.translate", function () {
|
||||
lipSync();
|
||||
|
||||
if (!video.paused) {
|
||||
lipSync("play");
|
||||
}
|
||||
});
|
||||
|
||||
$("video").on("pause.translate waiting.translate", function () {
|
||||
lipSync("pause");
|
||||
});
|
||||
} catch (err) {
|
||||
if (!err) {
|
||||
console.error("something went wrong");
|
||||
}
|
||||
|
||||
console.error(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue