1
0
Fork 0
mirror of https://github.com/futurepress/epub.js.git synced 2025-10-02 14:49:16 +02:00
epub.js/espark_reader/reader.js
2022-07-29 13:19:07 -05:00

186 lines
No EOL
6.1 KiB
JavaScript

var book = ePub();
var rendition;
var inputElement;
var audioClips = [];
var currentWord = 0;
var isPlaying = false;
function init() {
inputElement = document.getElementById("input");
inputElement.addEventListener('change', function (e) {
var file = e.target.files[0];
if (window.FileReader) {
var reader = new FileReader();
reader.onload = openBook;
reader.readAsArrayBuffer(file);
}
});
}
function openBook(e) {
var bookData = e.target.result;
var title = document.getElementById("title");
var next = document.getElementById("next");
var prev = document.getElementById("prev");
book.open(bookData, "binary");
/* console.log("opened book")
console.log(book) */
var rendition = book.renderTo("viewer", {
//manager: "continuous",
flow: "paginated",
width: "100%",
height: "100%",
snap: true
});
rendition.display();
var keyListener = function (e) {
// Left Key
if ((e.keyCode || e.which) == 37) {
rendition.prev();
}
// Right Key
if ((e.keyCode || e.which) == 39) {
rendition.next();
}
};
rendition.on("keyup", keyListener);
rendition.on("relocated", function (location) {
console.log(location);
initAudio();
});
next.addEventListener("click", function (e) {
rendition.next();
e.preventDefault();
}, false);
prev.addEventListener("click", function (e) {
rendition.prev();
e.preventDefault();
}, false);
document.addEventListener("keyup", keyListener, false);
}
function initAudio() {
var iframeList = document.getElementsByTagName("iframe");
audioClips = [];
for (let iframe of iframeList) {
var iframeDoc = iframe.contentDocument;
//get audio information
iframeDoc.querySelectorAll('par').forEach(par => {
var text = par.getElementsByTagName("text")[0]; //should only be one
var audio = par.getElementsByTagName("audio")[0]; //should only be one
var textId = text.getAttribute("src").split("#")[1];//text source format is page.xhtml#word
var textRef = iframeDoc.getElementById(textId);
var audioSrc = audio.getAttribute("src");
const contentType = "audio/mp3";
/*var sound = new Howl({
src: [`data:${contentType};base64,${audioSrc}`]
});*/
audioClips.push({
textId: textId,
text: textRef,
audio: audio,
clipBegin: parseFloat(audio.getAttribute("clipbegin")),
clipEnd: parseFloat(audio.getAttribute("clipend"))
//duration: 1000 * (parseFloat(audio.getAttribute("clipend")) - parseFloat(audio.getAttribute("clipbegin")))
})
});
//add next clip's start to the duration to account for pauses
for (let i = 0; i < audioClips.length - 1; i++) {
audioClips[i].duration = 1000 * (audioClips[i + 1].clipBegin - audioClips[i].clipBegin);
}
if (audioClips.length > 0) {
document.getElementById("audioplayer").style.visibility = "visible";
resetAudioToStart();
}
else {
document.getElementById("audioplayer").style.visibility = "hidden";
}
}
}
/**
* This is where the audio play/pause function should load and play everything on the page.
* Needs to loop through all available iframes because there may be 1-2 pages loaded separately on the page.
* I believe the audio tags will be in order per epub spec. Could look at play start and check if that's not the case.
* To play audio and go through highlighting the text and stopping at the right point, need to look at the clipBegin/clipEnd properties
* You could go through each audio tag and play/stop for each one but I think that'd cause some choppy behavior. Probably would be smoother to get the start/end for the page,
* and then track the time so that you can track the word for highlighting and pausing.
*
*
* Something to consider: will tracking the pages like this get messed up if the device rotates and only shows one page?
*/
function playPause() {
if (audioClips.length > 0) {
if (isPlaying) {
pauseAudio();
}
else {
playAudio();
}
}
}
/**
* The audio is the same for the whole book, need to play/pause the same audio tag
*/
function playAudio() {
isPlaying = true;
highlightWord();
audioClips[0].audio.play();
document.getElementById("playButton").textContent = "Pause";
}
function pauseAudio() {
isPlaying = false;
audioClips[0].audio.pause();
document.getElementById("playButton").textContent = "Play";
}
function resetAudioToStart() {
if (currentWord > 0)
audioClips[currentWord - 1].text.setAttribute("style", "");
currentWord = 0;
pauseAudio();
audioClips[0].audio.currentTime = audioClips[currentWord].clipBegin;
}
function resetAudioToWord() {
audioClips[0].audio.currentTime = audioClips[currentWord].clipBegin;
}
/**
* To highlight text with audio, search for the span with the id that matches the #id in the text src wrapping the audio. Each par tag has a text with source and the audio.
* Add a css highlight class to the span, then remove when moving to the next word.
*/
function highlightWord() {
//don't increment words if the audio is ended
if (currentWord >= audioClips.length) {
resetAudioToStart();
return;
}
if (!isPlaying) {
return;
}
/**
* note: using class add/remove doesn't work with iframes because the css is separate
*/
//highlight current word
if (currentWord > 0)
audioClips[currentWord - 1].text.setAttribute("style", "");
audioClips[currentWord].text.setAttribute("style", "background-color:yellow;");
//setup timer for when word is done being read
const myTimeout = setTimeout(highlightWord, audioClips[currentWord].duration);
//increment word index
currentWord++;
}