r2-navigator-js
Version:
Readium 2 'navigator' for NodeJS (TypeScript)
298 lines • 12.2 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.setupAudioBook = setupAudioBook;
const tslib_1 = require("tslib");
const debounce = require("debounce");
const electron_1 = require("electron");
const audiobook_1 = require("../../common/audiobook");
const events_1 = require("../../common/events");
const styles_1 = require("../../common/styles");
const win = global.window;
let __locEventID = 0;
function throttle(fn, time) {
let called = false;
return (...args) => {
if (!called) {
fn(...args);
called = true;
setTimeout(() => {
called = false;
}, time);
}
};
}
function setupAudioBook(_docTitle, audioPlaybackRate) {
win.document.documentElement.classList.add(styles_1.AUDIO_PROGRESS_CLASS);
const coverElement = win.document.getElementById(styles_1.AUDIO_COVER_ID);
const audioElement = win.document.getElementById(styles_1.AUDIO_ID);
const sliderElement = win.document.getElementById(styles_1.AUDIO_SLIDER_ID);
const timeElement = win.document.getElementById(styles_1.AUDIO_TIME_ID);
const percentElement = win.document.getElementById(styles_1.AUDIO_PERCENT_ID);
const playPauseElement = win.document.getElementById(styles_1.AUDIO_PLAYPAUSE_ID);
const previousElement = win.document.getElementById(styles_1.AUDIO_PREVIOUS_ID);
const nextElement = win.document.getElementById(styles_1.AUDIO_NEXT_ID);
const rewindElement = win.document.getElementById(styles_1.AUDIO_REWIND_ID);
const forwardElement = win.document.getElementById(styles_1.AUDIO_FORWARD_ID);
const rateElement = win.document.getElementById(styles_1.AUDIO_RATE_ID);
if (audioPlaybackRate) {
rateElement.value = `${audioPlaybackRate}`;
}
else {
rateElement.value = `${audioElement.playbackRate}`;
}
rateElement.addEventListener("change", () => {
const speed = parseFloat(rateElement.value);
audioElement.playbackRate = speed;
const payload = {
speed,
};
electron_1.ipcRenderer.sendToHost(events_1.R2_EVENT_AUDIO_PLAYBACK_RATE, payload);
});
function refreshTimeElements(p) {
const prettyPercent = percentElement.displayAlt ? `${p}%` : `${formatTime(audioElement.duration)}`;
percentElement.innerText = prettyPercent;
const prettyTime = timeElement.displayAlt ?
`-${formatTime(audioElement.duration - audioElement.currentTime)}` :
`${formatTime(audioElement.currentTime)}`;
timeElement.innerText = prettyTime;
}
function onTimeElementsClick(el) {
if (el.displayAlt) {
el.displayAlt = false;
}
else {
el.displayAlt = true;
}
const percent = audioElement.currentTime / audioElement.duration;
const p = Math.round(percent * 100);
refreshTimeElements(p);
}
timeElement.addEventListener("click", () => {
onTimeElementsClick(timeElement);
});
percentElement.addEventListener("click", () => {
onTimeElementsClick(percentElement);
});
const bufferCanvasElement = audiobook_1.DEBUG_AUDIO ?
win.document.getElementById(styles_1.AUDIO_BUFFER_CANVAS_ID) : undefined;
if (bufferCanvasElement) {
const context = bufferCanvasElement.getContext("2d");
if (context) {
const refreshBufferCanvas = () => {
const pixelsPerSecond = bufferCanvasElement.width / audioElement.duration;
context.fillStyle = "red";
context.fillRect(0, 0, bufferCanvasElement.width, bufferCanvasElement.height);
context.fillStyle = "green";
context.strokeStyle = "magenta";
console.log(`audio -- buffered.length: ${audioElement.buffered.length}`);
for (let i = 0; i < audioElement.buffered.length; i++) {
const start = audioElement.buffered.start(i);
const end = audioElement.buffered.end(i);
console.log(`audio -- buffered: ${start} ... ${end}`);
const x1 = start * pixelsPerSecond;
const x2 = end * pixelsPerSecond;
const w = x2 - x1;
context.fillRect(x1, 0, w, bufferCanvasElement.height);
context.rect(x1, 0, w, bufferCanvasElement.height);
context.stroke();
}
};
const refreshBufferCanvasThrottled = throttle(() => {
refreshBufferCanvas();
}, 500);
context.fillStyle = "silver";
context.fillRect(0, 0, bufferCanvasElement.width, bufferCanvasElement.height);
audioElement.addEventListener("timeupdate", () => {
if (audioElement.duration <= 0) {
return;
}
refreshBufferCanvasThrottled();
});
}
}
function rewind() {
const newTime = Math.max(0, audioElement.currentTime - 30);
audioElement.currentTime = newTime;
}
rewindElement.addEventListener("click", () => {
rewind();
});
function forward() {
const newTime = Math.min(audioElement.duration, audioElement.currentTime + 30);
audioElement.currentTime = newTime;
}
forwardElement.addEventListener("click", () => {
forward();
});
previousElement.addEventListener("click", () => {
const payload = {
go: "PREVIOUS",
};
electron_1.ipcRenderer.sendToHost(events_1.R2_EVENT_PAGE_TURN_RES, payload);
});
nextElement.addEventListener("click", () => {
const payload = {
go: "NEXT",
};
electron_1.ipcRenderer.sendToHost(events_1.R2_EVENT_PAGE_TURN_RES, payload);
});
sliderElement.addEventListener("input", () => {
const p = sliderElement.valueAsNumber / 100;
audioElement.currentTime = audioElement.duration * p;
sliderElement.style.setProperty("--audiopercent", `${sliderElement.valueAsNumber}%`);
});
function togglePlayPause() {
if (win.READIUM2.locationHashOverrideInfo &&
win.READIUM2.locationHashOverrideInfo.audioPlaybackInfo) {
const isPlaying = win.READIUM2.locationHashOverrideInfo.audioPlaybackInfo.isPlaying;
if (isPlaying) {
audioElement.pause();
}
else {
if (audioElement.currentTime >= audioElement.duration - 0.5) {
const payload = {
go: "NEXT",
};
electron_1.ipcRenderer.sendToHost(events_1.R2_EVENT_PAGE_TURN_RES, payload);
}
else {
setTimeout(() => tslib_1.__awaiter(this, void 0, void 0, function* () {
yield audioElement.play();
}), 0);
}
}
}
}
if (coverElement) {
coverElement.addEventListener("mouseup", (ev) => {
if (ev.button === 0) {
togglePlayPause();
}
});
}
playPauseElement.addEventListener("click", () => {
togglePlayPause();
});
function formatTime(seconds) {
const secondsPerMinute = 60;
const minutesPerHours = 60;
const secondsPerHour = minutesPerHours * secondsPerMinute;
let remainingSeconds = seconds;
const nHours = Math.floor(remainingSeconds / secondsPerHour);
remainingSeconds -= (nHours * secondsPerHour);
if (remainingSeconds < 0) {
remainingSeconds = 0;
}
const nMinutes = Math.floor(remainingSeconds / secondsPerMinute);
remainingSeconds -= (nMinutes * secondsPerMinute);
if (remainingSeconds < 0) {
remainingSeconds = 0;
}
remainingSeconds = Math.floor(remainingSeconds);
return `${nHours > 0 ? (nHours.toString().padStart(2, "0") + ":") : ""}${nMinutes > 0 ? (nMinutes.toString().padStart(2, "0") + ":") : "00:"}${remainingSeconds > 0 ? (remainingSeconds.toString().padStart(2, "0")) : "00"}`;
}
function notifyPlaybackLocation() {
const percent = audioElement.currentTime / audioElement.duration;
const p = Math.round(percent * 100);
refreshTimeElements(p);
sliderElement.valueAsNumber = p;
sliderElement.style.setProperty("--audiopercent", `${p}%`);
if (__locEventID >= Number.MAX_SAFE_INTEGER) {
__locEventID = 0;
}
win.READIUM2.locationHashOverrideInfo = {
locEventID: ++__locEventID,
audioPlaybackInfo: {
globalDuration: undefined,
globalProgression: undefined,
globalTime: undefined,
isPlaying: audioElement.isPlaying,
localDuration: audioElement.duration,
localProgression: percent,
localTime: audioElement.currentTime,
},
docInfo: {
isFixedLayout: false,
isRightToLeft: false,
isVerticalWritingMode: false,
},
epubPage: undefined,
epubPageID: undefined,
headings: undefined,
href: "",
locations: {
cfi: undefined,
cssSelector: undefined,
position: undefined,
progression: percent,
},
paginationInfo: undefined,
secondWebViewHref: undefined,
selectionInfo: undefined,
selectionIsNew: undefined,
text: undefined,
title: _docTitle,
userInteract: false,
};
const payload = win.READIUM2.locationHashOverrideInfo;
electron_1.ipcRenderer.sendToHost(events_1.R2_EVENT_READING_LOCATION, payload);
}
const notifyPlaybackLocationThrottled = throttle(() => {
notifyPlaybackLocation();
}, 1000);
const progressDebounced = debounce((progress) => {
if (progress) {
win.document.documentElement.classList.add(styles_1.AUDIO_PROGRESS_CLASS);
}
else {
win.document.documentElement.classList.remove(styles_1.AUDIO_PROGRESS_CLASS);
}
}, 150);
audioElement.addEventListener("play", () => {
audioElement.isPlaying = true;
playPauseElement.classList.add("pause");
notifyPlaybackLocation();
});
audioElement.addEventListener("pause", () => {
audioElement.isPlaying = false;
playPauseElement.classList.remove("pause");
notifyPlaybackLocation();
});
audioElement.addEventListener("seeking", () => {
progressDebounced(true);
});
audioElement.addEventListener("canplay", () => {
progressDebounced(false);
});
audioElement.addEventListener("ended", () => {
audioElement.isPlaying = false;
playPauseElement.classList.remove("pause");
notifyPlaybackLocation();
const payload = {
go: "NEXT",
};
electron_1.ipcRenderer.sendToHost(events_1.R2_EVENT_PAGE_TURN_RES, payload);
});
audioElement.addEventListener("timeupdate", () => {
notifyPlaybackLocationThrottled();
});
electron_1.ipcRenderer.on(events_1.R2_EVENT_AUDIO_DO_PLAY, (_event) => tslib_1.__awaiter(this, void 0, void 0, function* () {
yield audioElement.play();
}));
electron_1.ipcRenderer.on(events_1.R2_EVENT_AUDIO_DO_PAUSE, (_event) => {
audioElement.pause();
});
electron_1.ipcRenderer.on(events_1.R2_EVENT_AUDIO_DO_PLAY, (_event) => tslib_1.__awaiter(this, void 0, void 0, function* () {
yield audioElement.play();
}));
electron_1.ipcRenderer.on(events_1.R2_EVENT_AUDIO_TOGGLE_PLAY_PAUSE, (_event) => {
togglePlayPause();
});
electron_1.ipcRenderer.on(events_1.R2_EVENT_AUDIO_REWIND, (_event) => {
rewind();
});
electron_1.ipcRenderer.on(events_1.R2_EVENT_AUDIO_FORWARD, (_event) => {
forward();
});
}
//# sourceMappingURL=audiobook.js.map