Created
November 15, 2020 13:28
-
-
Save kyle-seongwoo-jun/38d703355bb0db53c0a86ff860c6a8a2 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
async function initYoutubeCaptions() { | |
const video = document.querySelector('video') | |
const captions = await getYoutubeCaptions() | |
addCaptions(video, captions) | |
} | |
function selectYoutubeCaption(language) { | |
const video = document.querySelector('video') | |
Array.prototype.forEach.call(video.textTracks, track => { | |
if (track.mode == "disabled") return | |
track.mode = track.language == language ? "showing" : "hidden" | |
}) | |
video.webkitClosedCaptionsVisible = true | |
} | |
function availableLanguages() { | |
const video = document.querySelector('video') | |
const languages = Array.prototype.filter.call(video.textTracks, track => track.mode != "disabled") | |
.map(track => track.language) | |
return languages | |
} | |
async function getYoutubeCaptions() { | |
const youtubeArgs = ytplayer.config.args | |
if (youtubeArgs === undefined) { | |
console.warn('No Youtube player configuarion found.') | |
return [] | |
} | |
const videoId = new URLSearchParams(window.location.search).get('v') | |
if (videoId !== youtubeArgs.video_id) { | |
console.warn('video id is not matched. Please refresh and try again.') | |
console.debug('v:', videoId, 'video_id:', youtubeArgs.video_id) | |
return [] | |
} | |
const { captionTracks } = JSON.parse(youtubeArgs.player_response).captions.playerCaptionsTracklistRenderer | |
if (captionTracks.length === 0) { | |
console.warn('No captions found.') | |
return [] | |
} | |
const captions = await Promise.all( | |
captionTracks.map(async caption => { | |
// request caption as xml | |
const fetchUrl = caption.baseUrl | |
const xmlString = await fetch(fetchUrl).then(res => res.text()) | |
const cues = parseXml(xmlString) | |
return { | |
label: caption.name.simpleText, | |
language: caption.languageCode, | |
cues, | |
} | |
}) | |
) | |
return captions | |
} | |
let AVOID_CONCURRENT_CAPTIONS = true | |
function parseXml(xmlString) { | |
// parse xml | |
const xmlParsed = new window.DOMParser().parseFromString(xmlString, 'text/xml') | |
const textElements = xmlParsed.querySelector('transcript').childNodes | |
var tempNode = document.createElement('div') | |
const cues = Array.prototype.map.call(textElements, (text, index) => { | |
const start = Number(text.getAttribute('start')) | |
let end = start + Number(text.getAttribute('dur')) | |
if (AVOID_CONCURRENT_CAPTIONS && index + 1 < textElements.length) { | |
// youtube captions overlap so this gets rid of that | |
const nextStart = Number(textElements[index + 1].getAttribute('start')) | |
end = Math.min(end, nextStart) | |
} | |
// remove font tags from caption content | |
const content = text.textContent.replace(/<[^>]+>/g, '') | |
tempNode.innerHTML = content | |
// create cue | |
return new VTTCue(start, end, tempNode.textContent) | |
}) | |
return cues | |
} | |
function addCaptions(video, captions) { | |
// disable all of tracks | |
Array.prototype.forEach.call(video.textTracks, track => track.mode = "disabled") | |
// add tracks | |
captions.forEach(caption => { | |
const track = video.addTextTrack('subtitles', caption.label, caption.language) | |
caption.cues.forEach(cue => track.addCue(cue)) | |
}) | |
} | |
// await initYoutubeCaptions() | |
// availableLanguages() | |
// selectYoutubeCaption('ko') |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment