Merge pull request #4285 from LokiLuciferase/feature/bookplayer

Add font size and theme selection controls to EPUB reader
This commit is contained in:
Bill Thornton 2023-03-28 15:01:56 -04:00 committed by GitHub
commit 273dfa0351
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 145 additions and 40 deletions

118
package-lock.json generated
View file

@ -24,7 +24,7 @@
"core-js": "3.29.0", "core-js": "3.29.0",
"date-fns": "2.29.3", "date-fns": "2.29.3",
"dompurify": "3.0.1", "dompurify": "3.0.1",
"epubjs": "0.4.2", "epubjs": "0.3.93",
"escape-html": "1.0.3", "escape-html": "1.0.3",
"fast-text-encoding": "1.0.6", "fast-text-encoding": "1.0.6",
"flv.js": "1.6.2", "flv.js": "1.6.2",
@ -3013,6 +3013,15 @@
"@types/react": "*" "@types/react": "*"
} }
}, },
"node_modules/@types/localforage": {
"version": "0.0.34",
"resolved": "https://registry.npmjs.org/@types/localforage/-/localforage-0.0.34.tgz",
"integrity": "sha512-tJxahnjm9dEI1X+hQSC5f2BSd/coZaqbIl1m3TCl0q9SVuC52XcXfV0XmoCU1+PmjyucuVITwoTnN8OlTbEXXA==",
"deprecated": "This is a stub types definition for localforage (https://github.com/localForage/localForage). localforage provides its own type definitions, so you don't need @types/localforage installed!",
"dependencies": {
"localforage": "*"
}
},
"node_modules/@types/lodash": { "node_modules/@types/lodash": {
"version": "4.14.178", "version": "4.14.178",
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.178.tgz", "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.178.tgz",
@ -3666,6 +3675,14 @@
} }
} }
}, },
"node_modules/@xmldom/xmldom": {
"version": "0.7.9",
"resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.7.9.tgz",
"integrity": "sha512-yceMpm/xd4W2a85iqZyO09gTnHvXF6pyiWjD2jcOJs7hRoZtNNOO1eJlhHj1ixA+xip2hOyGn+LgcvLCMo5zXA==",
"engines": {
"node": ">=10.0.0"
}
},
"node_modules/@xtuc/ieee754": { "node_modules/@xtuc/ieee754": {
"version": "1.2.0", "version": "1.2.0",
"resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz",
@ -6181,17 +6198,19 @@
} }
}, },
"node_modules/epubjs": { "node_modules/epubjs": {
"version": "0.4.2", "version": "0.3.93",
"resolved": "https://registry.npmjs.org/epubjs/-/epubjs-0.4.2.tgz", "resolved": "https://registry.npmjs.org/epubjs/-/epubjs-0.3.93.tgz",
"integrity": "sha512-ex+ntja2AmPeq++qgjYfwrEzrO8UUBbTch1RJcRftShUmn8no6qi4Cax75FH0QopLA+6L8HM6iR94M0/I8V3GQ==", "integrity": "sha512-c06pNSdBxcXv3dZSbXAVLE1/pmleRhOT6mXNZo6INKmvuKpYB65MwU/lO7830czCtjIiK9i+KR+3S+p0wtljrw==",
"dependencies": { "dependencies": {
"@types/localforage": "0.0.34",
"@xmldom/xmldom": "^0.7.5",
"core-js": "^3.18.3",
"event-emitter": "^0.3.5", "event-emitter": "^0.3.5",
"jszip": "^3.1.5", "jszip": "^3.7.1",
"lodash": "^4.17.5", "localforage": "^1.10.0",
"marks-pane": "^1.0.7", "lodash": "^4.17.21",
"path-webpack": "0.0.3", "marks-pane": "^1.0.9",
"stream-browserify": "^2.0.1", "path-webpack": "0.0.3"
"xmldom": "^0.1.27"
} }
}, },
"node_modules/error-ex": { "node_modules/error-ex": {
@ -9919,6 +9938,14 @@
"resolved": "https://registry.npmjs.org/libarchive.js/-/libarchive.js-1.3.0.tgz", "resolved": "https://registry.npmjs.org/libarchive.js/-/libarchive.js-1.3.0.tgz",
"integrity": "sha512-EkQfRXt9DhWwj6BnEA2TNpOf4jTnzSTUPGgE+iFxcdNqjktY8GitbDeHnx8qZA0/IukNyyBUR3oQKRdYkO+HFg==" "integrity": "sha512-EkQfRXt9DhWwj6BnEA2TNpOf4jTnzSTUPGgE+iFxcdNqjktY8GitbDeHnx8qZA0/IukNyyBUR3oQKRdYkO+HFg=="
}, },
"node_modules/lie": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/lie/-/lie-3.1.1.tgz",
"integrity": "sha512-RiNhHysUjhrDQntfYSfY4MU24coXXdEOgw9WGcKHNeEwffDYbF//u87M1EWaMGzuFoSbqW0C9C6lEEhDOAswfw==",
"dependencies": {
"immediate": "~3.0.5"
}
},
"node_modules/lilconfig": { "node_modules/lilconfig": {
"version": "2.0.4", "version": "2.0.4",
"resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.4.tgz", "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.4.tgz",
@ -9957,6 +9984,14 @@
"node": ">=8.9.0" "node": ">=8.9.0"
} }
}, },
"node_modules/localforage": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/localforage/-/localforage-1.10.0.tgz",
"integrity": "sha512-14/H1aX7hzBBmmh7sGPd+AOMkkIrHM3Z1PAyGgZigA1H1p5O5ANnMyWzvpAETtG68/dC4pC0ncy3+PPGzXZHPg==",
"dependencies": {
"lie": "3.1.1"
}
},
"node_modules/locate-path": { "node_modules/locate-path": {
"version": "5.0.0", "version": "5.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
@ -19214,15 +19249,6 @@
"integrity": "sha1-R0tQhlrzpJqcRlfwWs0UVFj3fYI=", "integrity": "sha1-R0tQhlrzpJqcRlfwWs0UVFj3fYI=",
"dev": true "dev": true
}, },
"node_modules/xmldom": {
"version": "0.1.31",
"resolved": "https://registry.npmjs.org/xmldom/-/xmldom-0.1.31.tgz",
"integrity": "sha512-yS2uJflVQs6n+CyjHoaBmVSqIDevTAWrzMmjG1Gc7h1qQ7uVozNhEPJAwZXWyGQ/Gafo3fCwrcaokezLPupVyQ==",
"deprecated": "Deprecated due to CVE-2021-21366 resolved in 0.5.0",
"engines": {
"node": ">=0.1"
}
},
"node_modules/xtend": { "node_modules/xtend": {
"version": "4.0.2", "version": "4.0.2",
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
@ -21251,6 +21277,14 @@
"@types/react": "*" "@types/react": "*"
} }
}, },
"@types/localforage": {
"version": "0.0.34",
"resolved": "https://registry.npmjs.org/@types/localforage/-/localforage-0.0.34.tgz",
"integrity": "sha512-tJxahnjm9dEI1X+hQSC5f2BSd/coZaqbIl1m3TCl0q9SVuC52XcXfV0XmoCU1+PmjyucuVITwoTnN8OlTbEXXA==",
"requires": {
"localforage": "*"
}
},
"@types/lodash": { "@types/lodash": {
"version": "4.14.178", "version": "4.14.178",
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.178.tgz", "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.178.tgz",
@ -21769,6 +21803,11 @@
"dev": true, "dev": true,
"requires": {} "requires": {}
}, },
"@xmldom/xmldom": {
"version": "0.7.9",
"resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.7.9.tgz",
"integrity": "sha512-yceMpm/xd4W2a85iqZyO09gTnHvXF6pyiWjD2jcOJs7hRoZtNNOO1eJlhHj1ixA+xip2hOyGn+LgcvLCMo5zXA=="
},
"@xtuc/ieee754": { "@xtuc/ieee754": {
"version": "1.2.0", "version": "1.2.0",
"resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz",
@ -23644,17 +23683,19 @@
"dev": true "dev": true
}, },
"epubjs": { "epubjs": {
"version": "0.4.2", "version": "0.3.93",
"resolved": "https://registry.npmjs.org/epubjs/-/epubjs-0.4.2.tgz", "resolved": "https://registry.npmjs.org/epubjs/-/epubjs-0.3.93.tgz",
"integrity": "sha512-ex+ntja2AmPeq++qgjYfwrEzrO8UUBbTch1RJcRftShUmn8no6qi4Cax75FH0QopLA+6L8HM6iR94M0/I8V3GQ==", "integrity": "sha512-c06pNSdBxcXv3dZSbXAVLE1/pmleRhOT6mXNZo6INKmvuKpYB65MwU/lO7830czCtjIiK9i+KR+3S+p0wtljrw==",
"requires": { "requires": {
"@types/localforage": "0.0.34",
"@xmldom/xmldom": "^0.7.5",
"core-js": "^3.18.3",
"event-emitter": "^0.3.5", "event-emitter": "^0.3.5",
"jszip": "^3.1.5", "jszip": "^3.7.1",
"lodash": "^4.17.5", "localforage": "^1.10.0",
"marks-pane": "^1.0.7", "lodash": "^4.17.21",
"path-webpack": "0.0.3", "marks-pane": "^1.0.9",
"stream-browserify": "^2.0.1", "path-webpack": "0.0.3"
"xmldom": "^0.1.27"
} }
}, },
"error-ex": { "error-ex": {
@ -26453,6 +26494,14 @@
"resolved": "https://registry.npmjs.org/libarchive.js/-/libarchive.js-1.3.0.tgz", "resolved": "https://registry.npmjs.org/libarchive.js/-/libarchive.js-1.3.0.tgz",
"integrity": "sha512-EkQfRXt9DhWwj6BnEA2TNpOf4jTnzSTUPGgE+iFxcdNqjktY8GitbDeHnx8qZA0/IukNyyBUR3oQKRdYkO+HFg==" "integrity": "sha512-EkQfRXt9DhWwj6BnEA2TNpOf4jTnzSTUPGgE+iFxcdNqjktY8GitbDeHnx8qZA0/IukNyyBUR3oQKRdYkO+HFg=="
}, },
"lie": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/lie/-/lie-3.1.1.tgz",
"integrity": "sha512-RiNhHysUjhrDQntfYSfY4MU24coXXdEOgw9WGcKHNeEwffDYbF//u87M1EWaMGzuFoSbqW0C9C6lEEhDOAswfw==",
"requires": {
"immediate": "~3.0.5"
}
},
"lilconfig": { "lilconfig": {
"version": "2.0.4", "version": "2.0.4",
"resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.4.tgz", "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.4.tgz",
@ -26482,6 +26531,14 @@
"json5": "^2.1.2" "json5": "^2.1.2"
} }
}, },
"localforage": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/localforage/-/localforage-1.10.0.tgz",
"integrity": "sha512-14/H1aX7hzBBmmh7sGPd+AOMkkIrHM3Z1PAyGgZigA1H1p5O5ANnMyWzvpAETtG68/dC4pC0ncy3+PPGzXZHPg==",
"requires": {
"lie": "3.1.1"
}
},
"locate-path": { "locate-path": {
"version": "5.0.0", "version": "5.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
@ -33479,11 +33536,6 @@
"integrity": "sha1-R0tQhlrzpJqcRlfwWs0UVFj3fYI=", "integrity": "sha1-R0tQhlrzpJqcRlfwWs0UVFj3fYI=",
"dev": true "dev": true
}, },
"xmldom": {
"version": "0.1.31",
"resolved": "https://registry.npmjs.org/xmldom/-/xmldom-0.1.31.tgz",
"integrity": "sha512-yS2uJflVQs6n+CyjHoaBmVSqIDevTAWrzMmjG1Gc7h1qQ7uVozNhEPJAwZXWyGQ/Gafo3fCwrcaokezLPupVyQ=="
},
"xtend": { "xtend": {
"version": "4.0.2", "version": "4.0.2",
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",

View file

@ -83,7 +83,7 @@
"core-js": "3.29.0", "core-js": "3.29.0",
"date-fns": "2.29.3", "date-fns": "2.29.3",
"dompurify": "3.0.1", "dompurify": "3.0.1",
"epubjs": "0.4.2", "epubjs": "0.3.93",
"escape-html": "1.0.3", "escape-html": "1.0.3",
"fast-text-encoding": "1.0.6", "fast-text-encoding": "1.0.6",
"flv.js": "1.6.2", "flv.js": "1.6.2",

View file

@ -17,15 +17,31 @@ import '../../elements/emby-button/paper-icon-button-light';
import html from './template.html'; import html from './template.html';
import './style.scss'; import './style.scss';
const THEMES = {
'dark': { 'body': { 'color': '#d8dadc', 'background': '#000', 'font-size': 'medium' } },
'sepia': { 'body': { 'color': '#d8a262', 'background': '#000', 'font-size': 'medium' } },
'light': { 'body': { 'color': '#000', 'background': '#fff', 'font-size': 'medium' } }
};
const THEME_ORDER = ['dark', 'sepia', 'light'];
const FONT_SIZES = ['x-small', 'small', 'medium', 'large', 'x-large'];
export class BookPlayer { export class BookPlayer {
constructor() { constructor() {
this.name = 'Book Player'; this.name = 'Book Player';
this.type = PluginType.MediaPlayer; this.type = PluginType.MediaPlayer;
this.id = 'bookplayer'; this.id = 'bookplayer';
this.priority = 1; this.priority = 1;
if (!userSettings.theme() || userSettings.theme() === 'dark') {
this.theme = 'dark';
} else {
this.theme = 'light';
}
this.fontSize = 'medium';
this.onDialogClosed = this.onDialogClosed.bind(this); this.onDialogClosed = this.onDialogClosed.bind(this);
this.openTableOfContents = this.openTableOfContents.bind(this); this.openTableOfContents = this.openTableOfContents.bind(this);
this.rotateTheme = this.rotateTheme.bind(this);
this.increaseFontSize = this.increaseFontSize.bind(this);
this.decreaseFontSize = this.decreaseFontSize.bind(this);
this.previous = this.previous.bind(this); this.previous = this.previous.bind(this);
this.next = this.next.bind(this); this.next = this.next.bind(this);
this.onWindowKeyUp = this.onWindowKeyUp.bind(this); this.onWindowKeyUp = this.onWindowKeyUp.bind(this);
@ -164,6 +180,9 @@ export class BookPlayer {
elem.querySelector('#btnBookplayerExit').addEventListener('click', this.onDialogClosed, { once: true }); elem.querySelector('#btnBookplayerExit').addEventListener('click', this.onDialogClosed, { once: true });
elem.querySelector('#btnBookplayerToc').addEventListener('click', this.openTableOfContents); elem.querySelector('#btnBookplayerToc').addEventListener('click', this.openTableOfContents);
elem.querySelector('#btnBookplayerFullscreen').addEventListener('click', this.toggleFullscreen); elem.querySelector('#btnBookplayerFullscreen').addEventListener('click', this.toggleFullscreen);
elem.querySelector('#btnBookplayerRotateTheme').addEventListener('click', this.rotateTheme);
elem.querySelector('#btnBookplayerIncreaseFontSize').addEventListener('click', this.increaseFontSize);
elem.querySelector('#btnBookplayerDecreaseFontSize').addEventListener('click', this.decreaseFontSize);
elem.querySelector('#btnBookplayerPrev')?.addEventListener('click', this.previous); elem.querySelector('#btnBookplayerPrev')?.addEventListener('click', this.previous);
elem.querySelector('#btnBookplayerNext')?.addEventListener('click', this.next); elem.querySelector('#btnBookplayerNext')?.addEventListener('click', this.next);
} }
@ -184,6 +203,9 @@ export class BookPlayer {
elem.querySelector('#btnBookplayerExit').removeEventListener('click', this.onDialogClosed); elem.querySelector('#btnBookplayerExit').removeEventListener('click', this.onDialogClosed);
elem.querySelector('#btnBookplayerToc').removeEventListener('click', this.openTableOfContents); elem.querySelector('#btnBookplayerToc').removeEventListener('click', this.openTableOfContents);
elem.querySelector('#btnBookplayerFullscreen').removeEventListener('click', this.toggleFullscreen); elem.querySelector('#btnBookplayerFullscreen').removeEventListener('click', this.toggleFullscreen);
elem.querySelector('#btnBookplayerRotateTheme').removeEventListener('click', this.rotateTheme);
elem.querySelector('#btnBookplayerIncreaseFontSize').removeEventListener('click', this.increaseFontSize);
elem.querySelector('#btnBookplayerDecreaseFontSize').removeEventListener('click', this.decreaseFontSize);
elem.querySelector('#btnBookplayerPrev')?.removeEventListener('click', this.previous); elem.querySelector('#btnBookplayerPrev')?.removeEventListener('click', this.previous);
elem.querySelector('#btnBookplayerNext')?.removeEventListener('click', this.next); elem.querySelector('#btnBookplayerNext')?.removeEventListener('click', this.next);
} }
@ -214,6 +236,31 @@ export class BookPlayer {
} }
} }
rotateTheme() {
if (this.loaded) {
const newTheme = THEME_ORDER[(THEME_ORDER.indexOf(this.theme) + 1) % THEME_ORDER.length];
this.rendition.themes.register('default', THEMES[newTheme]);
this.rendition.themes.update('default');
this.theme = newTheme;
}
}
increaseFontSize() {
if (this.loaded && this.fontSize !== FONT_SIZES[FONT_SIZES.length - 1]) {
const newFontSize = FONT_SIZES[(FONT_SIZES.indexOf(this.fontSize) + 1)];
this.rendition.themes.fontSize(newFontSize);
this.fontSize = newFontSize;
}
}
decreaseFontSize() {
if (this.loaded && this.fontSize !== FONT_SIZES[0]) {
const newFontSize = FONT_SIZES[(FONT_SIZES.indexOf(this.fontSize) - 1)];
this.rendition.themes.fontSize(newFontSize);
this.fontSize = newFontSize;
}
}
previous(e) { previous(e) {
e?.preventDefault(); e?.preventDefault();
if (this.rendition) { if (this.rendition) {
@ -296,11 +343,8 @@ export class BookPlayer {
this.currentSrc = downloadHref; this.currentSrc = downloadHref;
this.rendition = rendition; this.rendition = rendition;
rendition.themes.register('dark', { 'body': { 'color': '#fff' } }); rendition.themes.register('default', THEMES[this.theme]);
rendition.themes.select('default');
if (userSettings.theme(undefined) === 'dark' || userSettings.theme(undefined) === null) {
rendition.themes.select('dark');
}
return rendition.display().then(() => { return rendition.display().then(() => {
const epubElem = document.querySelector('.epub-container'); const epubElem = document.querySelector('.epub-container');

View file

@ -11,6 +11,15 @@
<button is="paper-icon-button-light" id="btnBookplayerExit" class="autoSize bookplayerButton hide-mouse-idle-tv" tabindex="-1"> <button is="paper-icon-button-light" id="btnBookplayerExit" class="autoSize bookplayerButton hide-mouse-idle-tv" tabindex="-1">
<span class="material-icons bookplayerButtonIcon close" aria-hidden="true"></span> <span class="material-icons bookplayerButtonIcon close" aria-hidden="true"></span>
</button> </button>
<button is="paper-icon-button-light" id="btnBookplayerRotateTheme" class="autoSize bookplayerButton hide-mouse-idle-tv" tabindex="-1">
<span class="material-icons bookplayerButtonIcon remove_red_eye" aria-hidden="true"></span>
</button>
<button is="paper-icon-button-light" id="btnBookplayerDecreaseFontSize" class="autoSize bookplayerButton hide-mouse-idle-tv" tabindex="-1">
<span class="material-icons bookplayerButtonIcon text_decrease" aria-hidden="true"></span>
</button>
<button is="paper-icon-button-light" id="btnBookplayerIncreaseFontSize" class="autoSize bookplayerButton hide-mouse-idle-tv" tabindex="-1">
<span class="material-icons bookplayerButtonIcon text_increase" aria-hidden="true"></span>
</button>
<button is="paper-icon-button-light" id="btnBookplayerFullscreen" class="autoSize bookplayerButton hide-mouse-idle-tv" tabindex="-1"> <button is="paper-icon-button-light" id="btnBookplayerFullscreen" class="autoSize bookplayerButton hide-mouse-idle-tv" tabindex="-1">
<span class="material-icons bookplayerButtonIcon fullscreen" aria-hidden="true"></span> <span class="material-icons bookplayerButtonIcon fullscreen" aria-hidden="true"></span>
</button> </button>