diff --git a/src/assets/css/site.css b/src/assets/css/site.css index 467f48d4fd..627145abc1 100644 --- a/src/assets/css/site.css +++ b/src/assets/css/site.css @@ -96,14 +96,6 @@ div[data-role=page] { } } -#bookPlayer { - position: relative; - height: 100%; - overflow: auto; - z-index: 100; - background: #fff; -} - .headerHelpButton { margin-left: 1.25em !important; padding-bottom: 0.4em !important; diff --git a/src/components/bookPlayer/plugin.js b/src/components/bookPlayer/plugin.js new file mode 100644 index 0000000000..d0f040c4fd --- /dev/null +++ b/src/components/bookPlayer/plugin.js @@ -0,0 +1,133 @@ +define(['connectionManager', 'dom', 'loading', 'playbackManager', 'keyboardnavigation', 'dialogHelper', 'apphost', 'css!./style', 'material-icons', 'paper-icon-button-light'], function (connectionManager, dom, loading, playbackManager, keyboardnavigation, dialogHelper, appHost) { + 'use strict'; + + function BookPlayer() { + let self = this; + + self.name = 'Book Player'; + self.type = 'mediaplayer'; + self.id = 'bookplayer'; + self.priority = 1; + + self.play = function (options) { + loading.show(); + let elem = createMediaElement(); + return setCurrentSrc(elem, options); + }; + + self.stop = function () { + let elem = self._mediaElement; + let rendition = self._rendition; + + if (elem && rendition) { + rendition.destroy(); + + elem.remove(); + self._mediaElement = null; + } + }; + + function onWindowKeyUp(e) { + let key = keyboardnavigation.getKeyName(e); + let rendition = self._rendition; + let book = rendition.book; + + switch (key) { + case 'l': + case 'ArrowRight': + case 'Right': + book.package.metadata.direction === 'rtl' ? rendition.prev() : rendition.next(); + break; + case 'j': + case 'ArrowLeft': + case 'Left': + book.package.metadata.direction === 'rtl' ? rendition.next() : rendition.prev(); + break; + case 'Escape': + dialogHelper.close(self._mediaElement); + break; + } + } + + function onDialogClosed() { + self.stop(); + } + + function createMediaElement() { + let elem = self._mediaElement; + + if (elem) { + return elem; + } + + elem = document.getElementById('bookPlayer'); + + if (!elem) { + elem = dialogHelper.createDialog({ + exitAnimationDuration: 400, + size: 'fullscreen', + autoFocus: false, + scrollY: false, + exitAnimation: 'fadeout', + removeOnClose: true + }); + elem.id = 'bookPlayer'; + + let html = ''; + html += '
'; + html += ''; + html += '
'; + + elem.innerHTML = html; + + elem.querySelector('.btnBookplayerExit').addEventListener('click', function () { + dialogHelper.close(elem); + }); + + dialogHelper.open(elem); + + elem.addEventListener('close', onDialogClosed); + } + + self._mediaElement = elem; + + return elem; + } + + function setCurrentSrc(elem, options) { + let serverId = options.items[0].ServerId; + let apiClient = connectionManager.getApiClient(serverId); + + return new Promise(function (resolve, reject) { + require(['epubjs'], function (epubjs) { + let downloadHref = apiClient.getItemDownloadUrl(options.items[0].Id); + self._currentSrc = downloadHref; + + let book = epubjs.default(downloadHref, {openAs: 'epub'}); + + let rendition = book.renderTo(elem, {width: '100%', height: '97%'}); + self._rendition = rendition; + + return rendition.display().then(function () { + document.addEventListener('keyup', onWindowKeyUp); + // FIXME: I don't really get why document keyup event is not triggered when epub is in focus + self._rendition.on('keyup', onWindowKeyUp); + + loading.hide(); + + return resolve(); + }, function () { + console.error('Failed to display epub'); + return reject(); + }); + }); + }); + } + } + + BookPlayer.prototype.canPlayMediaType = function (mediaType) { + return (mediaType || '').toLowerCase() === 'book'; + }; + + return BookPlayer; +}); diff --git a/src/components/bookPlayer/style.css b/src/components/bookPlayer/style.css new file mode 100644 index 0000000000..295fae5c5b --- /dev/null +++ b/src/components/bookPlayer/style.css @@ -0,0 +1,20 @@ +#bookPlayer { + position: relative; + height: 100%; + width: 100%; + overflow: auto; + z-index: 100; + background: #fff; +} + +.topActionButtons { + right: 0.5vh; + top: 0.5vh; + z-index: 1002; + position: absolute; +} + +.bookplayerButtonIcon { + color: black; + opacity: 0.7; +} diff --git a/src/components/bookplayer/plugin.js b/src/components/bookplayer/plugin.js deleted file mode 100644 index c00b4b7c40..0000000000 --- a/src/components/bookplayer/plugin.js +++ /dev/null @@ -1,35 +0,0 @@ -define(['connectionManager', 'dom'], function (connectionManager, dom) { - 'use strict'; - - function BookPlayer() { - var self = this; - - self.name = 'Book Player'; - self.type = 'mediaplayer'; - self.id = 'bookplayer'; - self.priority = 1; - } - - BookPlayer.prototype.play = function (values) { - var serverId = values.items[0].ServerId - var apiClient = connectionManager.getApiClient(serverId); - var options = values; - - require(['epubjs', 'appFooter-shared'], function (epubjs, appFooter) { - appFooter.element.insertAdjacentHTML('beforebegin', '
'); - var element = document.getElementById('bookPlayer'); - - var downloadHref = apiClient.getItemDownloadUrl(options.items[0].Id); - - var book = epubjs.default(downloadHref, { openAs: 'epub' }); - var rendition = book.renderTo(element, { method: "continuous", width: "100%", height: "100%" }); - var displayed = rendition.display(); - }); - }; - - BookPlayer.prototype.canPlayMediaType = function (mediaType) { - return (mediaType || '').toLowerCase() === 'book'; - }; - - return BookPlayer; -}); diff --git a/src/scripts/site.js b/src/scripts/site.js index 0672ae0db5..dd86701724 100644 --- a/src/scripts/site.js +++ b/src/scripts/site.js @@ -484,7 +484,7 @@ var AppInfo = {}; 'components/htmlAudioPlayer/plugin', 'components/htmlVideoPlayer/plugin', 'components/photoPlayer/plugin', - 'components/bookplayer/plugin', + 'components/bookPlayer/plugin', 'components/youtubeplayer/plugin', 'components/backdropScreensaver/plugin', 'components/logoScreensaver/plugin' diff --git a/yarn.lock b/yarn.lock index 2be9c6baf9..3dac9c2dfb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -858,6 +858,20 @@ resolved "https://registry.yarnpkg.com/@types/html-minifier-terser/-/html-minifier-terser-5.1.0.tgz#551a4589b6ee2cc9c1dff08056128aec29b94880" integrity sha512-iYCgjm1dGPRuo12+BStjd1HiVQqhlRhWDOQigNxn023HcjnhsiFz9pc6CzJj4HwDCSQca9bxTL4PxJDbkdm3PA== +"@types/jszip@^3.4.1": + version "3.4.1" + resolved "https://registry.yarnpkg.com/@types/jszip/-/jszip-3.4.1.tgz#e7a4059486e494c949ef750933d009684227846f" + integrity sha512-TezXjmf3lj+zQ651r6hPqvSScqBLvyPI9FxdXBqpEwBijNGQ2NXpaFW/7joGzveYkKQUil7iiDHLo6LV71Pc0A== + dependencies: + jszip "*" + +"@types/localforage@0.0.34": + version "0.0.34" + resolved "https://registry.yarnpkg.com/@types/localforage/-/localforage-0.0.34.tgz#5e31c32dd8791ec4b9ff3ef47c9cb55b2d0d9438" + integrity sha1-XjHDLdh5HsS5/z70fJy1Wy0NlDg= + dependencies: + localforage "*" + "@types/minimatch@*": version "3.0.3" resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d" @@ -3822,6 +3836,23 @@ entities@^2.0.0: resolved "https://registry.yarnpkg.com/entities/-/entities-2.0.0.tgz#68d6084cab1b079767540d80e56a39b423e4abf4" integrity sha512-D9f7V0JSRwIxlRI2mjMqufDrRDnx8p+eEOz7aUM9SuvF8gsBzra0/6tbjl1m8eQHrZlYj6PxqE00hZ1SAIKPLw== +epubjs@^0.3.85: + version "0.3.87" + resolved "https://registry.yarnpkg.com/epubjs/-/epubjs-0.3.87.tgz#0a2a94e59777e04548deff49a1c713ccbf3378fc" + integrity sha512-UlzXj04JQaUJ4p6ux/glQcVC4ayBtnpHT7niw4ozGy8EOQTAr8+/z7UZEHUmqQj4yHIoPYC4qGXtmzNqImWx1A== + dependencies: + "@types/jszip" "^3.4.1" + "@types/localforage" "0.0.34" + event-emitter "^0.3.5" + jszip "^3.4.0" + localforage "^1.7.3" + lodash "^4.17.15" + marks-pane "^1.0.9" + path-webpack "0.0.3" + stream-browserify "^2.0.1" + url-polyfill "^1.1.9" + xmldom "^0.1.27" + errno@^0.1.3, errno@~0.1.7: version "0.1.7" resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.7.tgz#4684d71779ad39af177e3f007996f7c67c852618" @@ -5856,6 +5887,11 @@ imagemin@^7.0.0: p-pipe "^3.0.0" replace-ext "^1.0.0" +immediate@~3.0.5: + version "3.0.6" + resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b" + integrity sha1-nbHb0Pr43m++D13V5Wu2BigN5ps= + immutable@^3: version "3.8.2" resolved "https://registry.yarnpkg.com/immutable/-/immutable-3.8.2.tgz#c2439951455bb39913daf281376f1530e104adf3" @@ -6654,6 +6690,16 @@ jstree@^3.3.7: dependencies: jquery ">=1.9.1" +jszip@*, jszip@^3.4.0: + version "3.4.0" + resolved "https://registry.yarnpkg.com/jszip/-/jszip-3.4.0.tgz#1a69421fa5f0bb9bc222a46bca88182fba075350" + integrity sha512-gZAOYuPl4EhPTXT0GjhI3o+ZAz3su6EhLrKUoAivcKqyqC7laS5JEv4XWZND9BgcDcF83vI85yGbDmDR6UhrIg== + dependencies: + lie "~3.3.0" + pako "~1.0.2" + readable-stream "~2.3.6" + set-immediate-shim "~1.0.1" + junk@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/junk/-/junk-3.1.0.tgz#31499098d902b7e98c5d9b9c80f43457a88abfa1" @@ -6782,6 +6828,20 @@ levn@^0.3.0, levn@~0.3.0: version "4.0.0" resolved "https://github.com/jellyfin/JavascriptSubtitlesOctopus#58e9a3f1a7f7883556ee002545f445a430120639" +lie@3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/lie/-/lie-3.1.1.tgz#9a436b2cc7746ca59de7a41fa469b3efb76bd87e" + integrity sha1-mkNrLMd0bKWd56QfpGmz77dr2H4= + dependencies: + immediate "~3.0.5" + +lie@~3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/lie/-/lie-3.3.0.tgz#dcf82dee545f46074daf200c7c1c5a08e0f40f6a" + integrity sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ== + dependencies: + immediate "~3.0.5" + liftoff@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/liftoff/-/liftoff-3.1.0.tgz#c9ba6081f908670607ee79062d700df062c52ed3" @@ -6874,6 +6934,13 @@ loader-utils@^2.0.0: emojis-list "^3.0.0" json5 "^2.1.2" +localforage@*, localforage@^1.7.3: + version "1.7.3" + resolved "https://registry.yarnpkg.com/localforage/-/localforage-1.7.3.tgz#0082b3ca9734679e1bd534995bdd3b24cf10f204" + integrity sha512-1TulyYfc4udS7ECSBT2vwJksWbkwwTX8BzeUIiq8Y07Riy7bDAAnxDaPU/tWyOVmQAcWJIEIFP9lPfBGqVoPgQ== + dependencies: + lie "3.1.1" + localtunnel@1.9.2: version "1.9.2" resolved "https://registry.yarnpkg.com/localtunnel/-/localtunnel-1.9.2.tgz#0012fcabc29cf964c130a01858768aa2bb65b5af" @@ -7244,6 +7311,11 @@ markdown-table@^2.0.0: dependencies: repeat-string "^1.0.0" +marks-pane@^1.0.9: + version "1.0.9" + resolved "https://registry.yarnpkg.com/marks-pane/-/marks-pane-1.0.9.tgz#c0b5ab813384d8cd81faaeb3bbf3397dc809c1b3" + integrity sha512-Ahs4oeG90tbdPWwAJkAAoHg2lRR8lAs9mZXETNPO9hYg3AkjUJBKi1NQ4aaIQZVGrig7c/3NUV1jANl8rFTeMg== + matchdep@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/matchdep/-/matchdep-2.0.0.tgz#c6f34834a0d8dbc3b37c27ee8bbcb27c7775582e" @@ -8312,7 +8384,7 @@ page@^1.11.6: dependencies: path-to-regexp "~1.2.1" -pako@~1.0.5: +pako@~1.0.2, pako@~1.0.5: version "1.0.11" resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf" integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw== @@ -8559,6 +8631,11 @@ path-type@^4.0.0: resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== +path-webpack@0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/path-webpack/-/path-webpack-0.0.3.tgz#ff6dec749eec5a94605c04d5f63fc55607a03a16" + integrity sha1-/23sdJ7sWpRgXATV9j/FVgegOhY= + pbkdf2@^3.0.3: version "3.0.17" resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.0.17.tgz#976c206530617b14ebb32114239f7b09336e93a6" @@ -10510,6 +10587,11 @@ set-blocking@^2.0.0, set-blocking@~2.0.0: resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= +set-immediate-shim@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61" + integrity sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E= + set-value@^2.0.0, set-value@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b" @@ -12188,6 +12270,11 @@ url-parse@^1.4.3: querystringify "^2.1.1" requires-port "^1.0.0" +url-polyfill@^1.1.9: + version "1.1.9" + resolved "https://registry.yarnpkg.com/url-polyfill/-/url-polyfill-1.1.9.tgz#2c8d4224889a5c942800f708f5585368085603d9" + integrity sha512-q/R5sowGuRfKHm497swkV+s9cPYtZRkHxzpDjRhqLO58FwdWTIkt6Y/fJlznUD/exaKx/XnDzCYXz0V16ND7ow== + url-to-options@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/url-to-options/-/url-to-options-1.0.1.tgz#1505a03a289a48cbd7a434efbaeec5055f5633a9" @@ -12745,6 +12832,11 @@ x-is-string@^0.1.0: resolved "https://registry.yarnpkg.com/x-is-string/-/x-is-string-0.1.0.tgz#474b50865af3a49a9c4657f05acd145458f77d82" integrity sha1-R0tQhlrzpJqcRlfwWs0UVFj3fYI= +xmldom@^0.1.27: + version "0.1.31" + resolved "https://registry.yarnpkg.com/xmldom/-/xmldom-0.1.31.tgz#b76c9a1bd9f0a9737e5a72dc37231cf38375e2ff" + integrity sha512-yS2uJflVQs6n+CyjHoaBmVSqIDevTAWrzMmjG1Gc7h1qQ7uVozNhEPJAwZXWyGQ/Gafo3fCwrcaokezLPupVyQ== + xmlhttprequest-ssl@~1.5.4: version "1.5.5" resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz#c2876b06168aadc40e57d97e81191ac8f4398b3e"