Skip to content

Instantly share code, notes, and snippets.

@ppkn
Created August 12, 2022 21:24
Show Gist options
  • Save ppkn/c64d704cd608741952d54dd656aa2f1c to your computer and use it in GitHub Desktop.
Save ppkn/c64d704cd608741952d54dd656aa2f1c to your computer and use it in GitHub Desktop.

Inspired by Cristóbal Sciutto's recent blog post on "home-cooked meal" style applications, I made a quick prototype for seeking through audio/transcript bidirectionally.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Merriweather&display=swap" rel="stylesheet">
<title>Interactive Transcripts</title>
</head>
<style>
body {
font-family: 'Merriweather', sans-serif;
background-color: sandybrown;
}
.container {
display: flex;
margin: 0 -4px;
}
.container > * {
margin: 0 4px;
background-color: aliceblue;
flex: 1;
}
#script {
padding: 8px;
}
.block:hover {
background-color: aquamarine;
cursor: pointer;
}
</style>
<body>
<div class="container">
<div id="script"></div>
<div>
<audio id="audio" src="49-software-longevity.mp3" controls></audio>
</div>
</div>
</body>
<script>
let blockElements;
let currentBlock;
const parseSrt = (text) => {
return text.split(/\n\s*\n/).map(parseBlock);
};
const parseBlock = (block) => {
[id, times, ...content] = block.split("\n");
[startTime, endTime] = parseTimes(times);
content = content.join(" ");
return {
id,
startTime,
endTime,
content,
}
};
const parseTimes = (times) => {
return times.split(" --> ").map(timeToSeconds);
};
const timeToSeconds = (time) => {
let [hours, minutes, seconds, milliseconds] = time.split(/[:,]/).map(Number);
return hours * 360 + minutes * 60 + seconds + milliseconds / 1000;
};
const blockToElement = (block) => {
let p = document.createElement("p");
p.dataset.startTime = block.startTime;
p.dataset.endTime = block.endTime;
p.classList.add("block");
let innerText = document.createTextNode(block.content);
p.appendChild(innerText);
p.addEventListener('click', clickBlock);
return p;
};
fetch('49__Software longevity.srt')
.then(response => response.text())
.then(text => {
blockElements = parseSrt(text).map(blockToElement);
currentBlock = blockElements[0];
let scriptBody = document.createDocumentFragment();
for (element of blockElements) {
scriptBody.appendChild(element);
}
document.getElementById("script").appendChild(scriptBody);
});
const timeChange = (e) => {
console.log("timeChange triggered!")
let currentTime = e.target.currentTime;
if (currentTime > currentBlock.dataset.startTime && currentTime < currentBlock.dataset.endTime) {
} else {
currentBlock.style.backgroundColor = 'initial';
let lastBlock = currentBlock;
currentBlock = blockElements.find(block => currentTime > block.dataset.startTime && currentTime < block.dataset.endTime)
if (currentBlock) {
currentBlock.style.backgroundColor = 'yellow';
} else {
currentBlock = lastBlock;
}
}
}
document.getElementById("audio").addEventListener("timeupdate", timeChange);
const clickBlock = e => {
let audio = document.getElementById("audio");
audio.currentTime = e.target.dataset.startTime;
if (audio.paused) {
audio.play();
}
}
</script>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment