Skip to content

Instantly share code, notes, and snippets.

@Altech
Last active May 21, 2023 03:01
Show Gist options
  • Save Altech/b2bcdedf31c124a42983a85991bd57b2 to your computer and use it in GitHub Desktop.
Save Altech/b2bcdedf31c124a42983a85991bd57b2 to your computer and use it in GitHub Desktop.
YouTube Transcription Overlay
// 目的: YouTube の字幕の機械翻訳の質が悪いので、DeepL を使いたい
// 機能: YouTube のメニューから開ける「文字起こし」の内容を動画にオーバーレイすることができる
// 使い方: 「文字起こし」を開いた状態で DeepL Chrome Extention でページ全体を翻訳することで、DeepL で翻訳された字幕が表示できる
// ※ コンソールから実行しているが、ブックマークレット形式にして使うのも良いかも
// ソース
// ------------------------------------
function setupCaption() {
const player = document.querySelector("#movie_player")
if (!player) {
console.error("No player found")
return null;
}
let container = document.getElementById('youtube-deepl-window-container');
if (!container) {
container = document.createElement('div');
container.id = 'youtube-deepl-window-container';
container.style.width = '100%';
container.style.height = '100%';
container.style.position = 'absolute';
container.style.top = '0';
container.style.pointerEvents = 'none';
player.appendChild(container);
}
let caption = document.getElementById('youtube-deepl-caption');
if (!caption) {
caption = document.createElement('div');
caption.id = 'youtube-deepl-caption';
caption.style.touchAction = 'none';
caption.style.textAlign = 'center';
caption.style.boxSizing = 'border-box';
caption.style.fontSize = '34px';
caption.style.padding = '0px 40px';
caption.style.width = '100%';
caption.style.bottom = '2%';
caption.style.background = '#7a7a7a57';
caption.style.marginBottom = '61px';
caption.style.position = 'absolute';
caption.style.lineHeight = 'normal';
caption.style.zIndex = '40';
caption.style.pointerEvents = 'auto';
caption.style.cursor = 'grab';
caption.style.userSelect = 'none';
container.appendChild(caption);
}
return caption;
}
function setupObserver(captionElement) {
const elements = document.querySelectorAll('#segments-container ytd-transcript-segment-renderer');
const observer = new MutationObserver((mutationsList, observer) => {
for (let mutation of mutationsList) {
if (mutation.type === 'attributes' && mutation.attributeName === 'class') {
const targetElement = mutation.target;
if (targetElement.classList.contains('active')) {
stringElement = targetElement.querySelector('yt-formatted-string')
if (!stringElement && targetElement.shadowRoot) { // Shadow DOM に対応
stringElement = targetElement.shadowRoot.querySelector('yt-formatted-string');
}
if (stringElement){
captionElement.innerText = stringElement.innerText;
} else {
window.debugElement = targetElement
console.error("stringElement was not found. targetElement was stored as window.debugElement")
}
}
}
}
});
for (let element of elements) {
observer.observe(element, { attributes: true });
}
}
// キャプション表示用の要素を作成
const caption = setupCaption()
if (!caption) {
console.error("No caption found");
} else {
// アクティブな要素を監視し、キャプションを更新
setupObserver(caption)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment