From 343989f6108bd1b77295175c15669296d64b5b57 Mon Sep 17 00:00:00 2001 From: MrTimscampi Date: Sat, 11 Apr 2020 22:51:11 +0200 Subject: [PATCH 01/28] Add unloading capability to the image loader --- src/components/images/imageFetcher.js | 29 ++- src/components/images/imageLoader.js | 38 ++-- .../lazyloader-intersectionobserver.js | 43 +--- .../lazyloader/lazyloader-scroll.js | 185 ------------------ src/controllers/movies/moviegenres.js | 3 +- src/controllers/shows/tvgenres.js | 3 +- src/scripts/site.js | 7 +- 7 files changed, 49 insertions(+), 259 deletions(-) delete mode 100644 src/components/lazyloader/lazyloader-scroll.js diff --git a/src/components/images/imageFetcher.js b/src/components/images/imageFetcher.js index 1e13cebc77..c7deadc1bd 100644 --- a/src/components/images/imageFetcher.js +++ b/src/components/images/imageFetcher.js @@ -2,28 +2,36 @@ define(['dom'], function (dom) { 'use strict'; function loadImage(elem, url) { - if (!elem) { return Promise.reject('elem cannot be null'); } if (elem.tagName !== "IMG") { - elem.style.backgroundImage = "url('" + url + "')"; return Promise.resolve(); - - //return loadImageIntoImg(document.createElement('img'), url).then(function () { - // elem.style.backgroundImage = "url('" + url + "')"; - // return Promise.resolve(); - //}); - } return loadImageIntoImg(elem, url); } + function unloadImage(elem) { + if (!elem) { + return Promise.reject('elem cannot be null'); + } + + var url; + if (elem.tagName !== "IMG") { + url = elem.style.backgroundImage.slice(4, -1).replace(/"/g, ""); + elem.style.backgroundImage = 'none'; + } else { + url = elem.getAttribute("src"); + elem.setAttribute("src", ""); + } + + return Promise.resolve(url); + } + function loadImageIntoImg(elem, url) { return new Promise(function (resolve, reject) { - dom.addEventListener(elem, 'load', resolve, { once: true }); @@ -32,7 +40,8 @@ define(['dom'], function (dom) { } return { - loadImage: loadImage + loadImage: loadImage, + unloadImage: unloadImage }; }); diff --git a/src/components/images/imageLoader.js b/src/components/images/imageLoader.js index 28b6923c33..8e2bcedf82 100644 --- a/src/components/images/imageLoader.js +++ b/src/components/images/imageLoader.js @@ -3,40 +3,36 @@ define(['lazyLoader', 'imageFetcher', 'layoutManager', 'browser', 'appSettings', var self = {}; - function fillImage(elem, source, enableEffects) { - - if (!elem) { - throw new Error('elem cannot be null'); + function fillImage(entry) { + if (!entry) { + throw new Error('entry cannot be null'); } - if (!source) { - source = elem.getAttribute('data-src'); - } + var source = entry.target.getAttribute('data-src'); - if (!source) { - return; + if (entry.intersectionRatio > 0 && source) { + fillImageElement(entry.target, source); + } else if (!source) { + emptyImageElement(entry.target); } - - fillImageElement(elem, source, enableEffects); } - function fillImageElement(elem, source, enableEffects) { + function fillImageElement(elem, source) { imageFetcher.loadImage(elem, source).then(function () { - - if (enableEffects !== false) { - fadeIn(elem); + if (userSettings.enableFastFadein()) { + elem.classList.add('lazy-image-fadein-fast'); + } else { + elem.classList.add('lazy-image-fadein'); } elem.removeAttribute("data-src"); }); } - function fadeIn(elem) { - if (userSettings.enableFastFadein()) { - elem.classList.add('lazy-image-fadein-fast'); - } else { - elem.classList.add('lazy-image-fadein'); - } + function emptyImageElement(elem) { + imageFetcher.unloadImage(elem).then(function (url) { + elem.setAttribute("data-src", url); + }); } function lazyChildren(elem) { diff --git a/src/components/lazyloader/lazyloader-intersectionobserver.js b/src/components/lazyloader/lazyloader-intersectionobserver.js index 5f83742601..377e3d0cff 100644 --- a/src/components/lazyloader/lazyloader-intersectionobserver.js +++ b/src/components/lazyloader/lazyloader-intersectionobserver.js @@ -11,42 +11,15 @@ define(['require', 'browser'], function (require, browser) { } LazyLoader.prototype.createObserver = function () { + var callback = this.options.callback; - var observerOptions = {}; - var options = this.options; - var loadedCount = 0; - var callback = options.callback; - - observerOptions.rootMargin = "50%"; - - var observerId = 'obs' + new Date().getTime(); - - var self = this; - var observer = new IntersectionObserver(function (entries) { - for (var j = 0, length2 = entries.length; j < length2; j++) { - var entry = entries[j]; - - if (entry.intersectionRatio > 0) { - - // Stop watching and load the image - var target = entry.target; - - observer.unobserve(target); - - if (!target[observerId]) { - target[observerId] = 1; - callback(target); - loadedCount++; - - if (loadedCount >= self.elementCount) { - self.destroyObserver(); - } - } - } - } - }, - observerOptions - ); + var observer = new IntersectionObserver( + (entries, observer) => { + entries.forEach(entry => { + callback(entry); + }, + {rootMargin: "50%"}); + }); this.observer = observer; }; diff --git a/src/components/lazyloader/lazyloader-scroll.js b/src/components/lazyloader/lazyloader-scroll.js deleted file mode 100644 index 4930f6376c..0000000000 --- a/src/components/lazyloader/lazyloader-scroll.js +++ /dev/null @@ -1,185 +0,0 @@ -define(['visibleinviewport', 'dom', 'browser'], function (visibleinviewport, dom, browser) { - 'use strict'; - - var thresholdX; - var thresholdY; - - function resetThresholds() { - - var threshold = 0.3; - - thresholdX = screen.availWidth * threshold; - thresholdY = screen.availHeight * threshold; - } - - function resetThresholdsOnTimer() { - - setTimeout(resetThresholds, 500); - } - - if (browser.iOS) { - dom.addEventListener(window, "orientationchange", resetThresholdsOnTimer, { passive: true }); - dom.addEventListener(window, 'resize', resetThresholdsOnTimer, { passive: true }); - } else { - dom.addEventListener(window, "orientationchange", resetThresholds, { passive: true }); - dom.addEventListener(window, 'resize', resetThresholds, { passive: true }); - } - resetThresholds(); - - function isVisible(elem) { - return visibleinviewport(elem, true, thresholdX, thresholdY); - } - - var wheelEvent = (document.implementation.hasFeature('Event.wheel', '3.0') ? 'wheel' : 'mousewheel'); - var self = {}; - - function cancelAll(tokens) { - for (var i = 0, length = tokens.length; i < length; i++) { - - tokens[i] = true; - } - } - - function unveilElementsInternal(instance, callback) { - - var unveiledElements = []; - var cancellationTokens = []; - var loadedCount = 0; - - function unveilInternal(tokenIndex) { - - var anyFound = false; - var out = false; - - var elements = instance.elements; - // TODO: This out construct assumes left to right, top to bottom - - for (var i = 0, length = elements.length; i < length; i++) { - - if (cancellationTokens[tokenIndex]) { - return; - } - if (unveiledElements[i]) { - continue; - } - var elem = elements[i]; - if (!out && isVisible(elem)) { - anyFound = true; - unveiledElements[i] = true; - callback(elem); - loadedCount++; - } else { - - if (anyFound) { - out = true; - } - } - } - - if (loadedCount >= elements.length) { - dom.removeEventListener(document, 'focus', unveil, { - capture: true, - passive: true - }); - dom.removeEventListener(document, 'scroll', unveil, { - capture: true, - passive: true - }); - dom.removeEventListener(document, wheelEvent, unveil, { - capture: true, - passive: true - }); - dom.removeEventListener(window, 'resize', unveil, { - capture: true, - passive: true - }); - } - } - - function unveil() { - - cancelAll(cancellationTokens); - - var index = cancellationTokens.length; - cancellationTokens.length++; - - setTimeout(function () { - unveilInternal(index); - }, 1); - } - - dom.addEventListener(document, 'focus', unveil, { - capture: true, - passive: true - }); - dom.addEventListener(document, 'scroll', unveil, { - capture: true, - passive: true - }); - dom.addEventListener(document, wheelEvent, unveil, { - capture: true, - passive: true - }); - dom.addEventListener(window, 'resize', unveil, { - capture: true, - passive: true - }); - - unveil(); - } - - function LazyLoader(options) { - - this.options = options; - } - - LazyLoader.prototype.createObserver = function () { - - unveilElementsInternal(this, this.options.callback); - this.observer = 1; - }; - - LazyLoader.prototype.addElements = function (elements) { - - this.elements = this.elements || []; - - for (var i = 0, length = elements.length; i < length; i++) { - this.elements.push(elements[i]); - } - - var observer = this.observer; - - if (!observer) { - this.createObserver(); - } - - }; - - LazyLoader.prototype.destroyObserver = function (elements) { - - }; - - LazyLoader.prototype.destroy = function (elements) { - - this.destroyObserver(); - this.options = null; - }; - - function unveilElements(elements, root, callback) { - - if (!elements.length) { - return; - } - var lazyLoader = new LazyLoader({ - callback: callback - }); - lazyLoader.addElements(elements); - } - - LazyLoader.lazyChildren = function (elem, callback) { - - unveilElements(elem.getElementsByClassName('lazy'), elem, callback); - }; - - return LazyLoader; -}); diff --git a/src/controllers/movies/moviegenres.js b/src/controllers/movies/moviegenres.js index bb395f337c..f2c472dace 100644 --- a/src/controllers/movies/moviegenres.js +++ b/src/controllers/movies/moviegenres.js @@ -50,7 +50,8 @@ define(["layoutManager", "loading", "libraryBrowser", "cardBuilder", "lazyLoader return enableScrollX() ? "overflowPortrait" : "portrait"; } - function fillItemsContainer(elem) { + function fillItemsContainer(entry) { + var elem = entry.target; var id = elem.getAttribute("data-id"); var viewStyle = self.getCurrentViewStyle(); var limit = "Thumb" == viewStyle || "ThumbCard" == viewStyle ? 5 : 9; diff --git a/src/controllers/shows/tvgenres.js b/src/controllers/shows/tvgenres.js index 9a0823a6b9..aa46fd4361 100644 --- a/src/controllers/shows/tvgenres.js +++ b/src/controllers/shows/tvgenres.js @@ -50,7 +50,8 @@ define(["layoutManager", "loading", "libraryBrowser", "cardBuilder", "lazyLoader return enableScrollX() ? "overflowPortrait" : "portrait"; } - function fillItemsContainer(elem) { + function fillItemsContainer(entry) { + var elem = entry.target; var id = elem.getAttribute("data-id"); var viewStyle = self.getCurrentViewStyle(); var limit = "Thumb" == viewStyle || "ThumbCard" == viewStyle ? 5 : 9; diff --git a/src/scripts/site.js b/src/scripts/site.js index 90fa1d849f..8957481242 100644 --- a/src/scripts/site.js +++ b/src/scripts/site.js @@ -379,12 +379,7 @@ var AppInfo = {}; define("filesystem", [componentsPath + "/filesystem"], returnFirstDependency); - if (window.IntersectionObserver && !browser.edge) { - define("lazyLoader", [componentsPath + "/lazyloader/lazyloader-intersectionobserver"], returnFirstDependency); - } else { - define("lazyLoader", [componentsPath + "/lazyloader/lazyloader-scroll"], returnFirstDependency); - } - + define("lazyLoader", [componentsPath + "/lazyloader/lazyloader-intersectionobserver"], returnFirstDependency); define("shell", [componentsPath + "/shell"], returnFirstDependency); define("apiclient", [bowerPath + "/apiclient/apiclient"], returnFirstDependency); From e97c659dc00df753210de52d97b94824c65bedea Mon Sep 17 00:00:00 2001 From: MrTimscampi Date: Sun, 12 Apr 2020 00:23:16 +0200 Subject: [PATCH 02/28] Migrate lazyloader-intesctionobserver to ES6 --- package.json | 3 +- src/components/images/imageLoader.js | 1 - src/components/lazyloader/lazyedgehack.css | 5 - .../lazyloader-intersectionobserver.js | 99 +++++++++---------- 4 files changed, 49 insertions(+), 59 deletions(-) delete mode 100644 src/components/lazyloader/lazyedgehack.css diff --git a/package.json b/package.json index 8f42635adc..8de04b3628 100644 --- a/package.json +++ b/package.json @@ -99,7 +99,8 @@ "src/scripts/settings/webSettings.js", "src/scripts/dfnshelper.js", "src/scripts/imagehelper.js", - "src/scripts/inputManager.js" + "src/scripts/inputManager.js", + "src/components/lazyloader/lazyloader-intersectionobserver.js" ], "plugins": [ "@babel/plugin-transform-modules-amd" diff --git a/src/components/images/imageLoader.js b/src/components/images/imageLoader.js index 8e2bcedf82..37b9226f6a 100644 --- a/src/components/images/imageLoader.js +++ b/src/components/images/imageLoader.js @@ -36,7 +36,6 @@ define(['lazyLoader', 'imageFetcher', 'layoutManager', 'browser', 'appSettings', } function lazyChildren(elem) { - lazyLoader.lazyChildren(elem, fillImage); } diff --git a/src/components/lazyloader/lazyedgehack.css b/src/components/lazyloader/lazyedgehack.css deleted file mode 100644 index e358872f16..0000000000 --- a/src/components/lazyloader/lazyedgehack.css +++ /dev/null @@ -1,5 +0,0 @@ -.lazy { - /* In edge, intersection observer will not fire on 0px sized elements */ - min-width: 0.1em; - min-height: 0.1em; -} diff --git a/src/components/lazyloader/lazyloader-intersectionobserver.js b/src/components/lazyloader/lazyloader-intersectionobserver.js index 377e3d0cff..222192f244 100644 --- a/src/components/lazyloader/lazyloader-intersectionobserver.js +++ b/src/components/lazyloader/lazyloader-intersectionobserver.js @@ -1,76 +1,71 @@ -define(['require', 'browser'], function (require, browser) { - 'use strict'; +import require from 'require'; +import browser from 'browser'; +/* eslint-disable indent */ - function LazyLoader(options) { + export class LazyLoader { + constructor(options) { + this.options = options; + this.observer; + } - this.options = options; - } + createObserver() { + const callback = this.options.callback; - if (browser.edge) { - require(['css!./lazyedgehack']); - } + const observer = new IntersectionObserver( + (entries, observer) => { + entries.forEach(entry => { + callback(entry); + }, + {rootMargin: "50%"}); + }); - LazyLoader.prototype.createObserver = function () { - var callback = this.options.callback; + this.observer = observer; + } - var observer = new IntersectionObserver( - (entries, observer) => { - entries.forEach(entry => { - callback(entry); - }, - {rootMargin: "50%"}); + addElements(elements) { + let observer = this.observer; + + if (!observer) { + this.createObserver(); + observer = this.observer; + } + + Array.from(elements).forEach(element => { + observer.observe(element); }); - - this.observer = observer; - }; - - LazyLoader.prototype.addElements = function (elements) { - - var observer = this.observer; - - if (!observer) { - this.createObserver(); - observer = this.observer; } - this.elementCount = (this.elementCount || 0) + elements.length; + destroyObserver(elements) { + const observer = this.observer; - for (var i = 0, length = elements.length; i < length; i++) { - observer.observe(elements[i]); + if (observer) { + observer.disconnect(); + this.observer = null; + } } - }; - LazyLoader.prototype.destroyObserver = function (elements) { - - var observer = this.observer; - - if (observer) { - observer.disconnect(); - this.observer = null; + destroy(elements) { + this.destroyObserver(); + this.options = null; } - }; - - LazyLoader.prototype.destroy = function (elements) { - - this.destroyObserver(); - this.options = null; - }; + } function unveilElements(elements, root, callback) { - if (!elements.length) { return; } - var lazyLoader = new LazyLoader({ + const lazyLoader = new LazyLoader({ callback: callback }); lazyLoader.addElements(elements); } - LazyLoader.lazyChildren = function (elem, callback) { - + export function lazyChildren(elem, callback) { unveilElements(elem.getElementsByClassName('lazy'), elem, callback); - }; + } - return LazyLoader; -}); +/* eslint-enable indent */ +export default { + LazyLoader: LazyLoader, + lazyChildren: lazyChildren +}; From 17784043547d04009ce795ff0f926176def51ab3 Mon Sep 17 00:00:00 2001 From: MrTimscampi Date: Sun, 12 Apr 2020 00:29:33 +0200 Subject: [PATCH 03/28] Fix bug and code smells --- src/components/lazyloader/lazyloader-intersectionobserver.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/components/lazyloader/lazyloader-intersectionobserver.js b/src/components/lazyloader/lazyloader-intersectionobserver.js index 222192f244..d39bddf6ac 100644 --- a/src/components/lazyloader/lazyloader-intersectionobserver.js +++ b/src/components/lazyloader/lazyloader-intersectionobserver.js @@ -1,11 +1,7 @@ -import require from 'require'; -import browser from 'browser'; /* eslint-disable indent */ - export class LazyLoader { constructor(options) { this.options = options; - this.observer; } createObserver() { From fc6a11bb4bac7ed28ef70a57fc837c85ea60c22a Mon Sep 17 00:00:00 2001 From: MrTimscampi Date: Sun, 12 Apr 2020 03:49:42 +0200 Subject: [PATCH 04/28] Refactor the lazy loader for images --- src/components/images/imageFetcher.js | 47 --------------------------- src/components/images/imageLoader.js | 36 ++++++++++++++++---- src/components/images/style.css | 39 +++++----------------- src/scripts/site.js | 4 --- 4 files changed, 39 insertions(+), 87 deletions(-) delete mode 100644 src/components/images/imageFetcher.js diff --git a/src/components/images/imageFetcher.js b/src/components/images/imageFetcher.js deleted file mode 100644 index c7deadc1bd..0000000000 --- a/src/components/images/imageFetcher.js +++ /dev/null @@ -1,47 +0,0 @@ -define(['dom'], function (dom) { - 'use strict'; - - function loadImage(elem, url) { - if (!elem) { - return Promise.reject('elem cannot be null'); - } - - if (elem.tagName !== "IMG") { - elem.style.backgroundImage = "url('" + url + "')"; - return Promise.resolve(); - } - return loadImageIntoImg(elem, url); - } - - function unloadImage(elem) { - if (!elem) { - return Promise.reject('elem cannot be null'); - } - - var url; - if (elem.tagName !== "IMG") { - url = elem.style.backgroundImage.slice(4, -1).replace(/"/g, ""); - elem.style.backgroundImage = 'none'; - } else { - url = elem.getAttribute("src"); - elem.setAttribute("src", ""); - } - - return Promise.resolve(url); - } - - function loadImageIntoImg(elem, url) { - return new Promise(function (resolve, reject) { - dom.addEventListener(elem, 'load', resolve, { - once: true - }); - elem.setAttribute("src", url); - }); - } - - return { - loadImage: loadImage, - unloadImage: unloadImage - }; - -}); diff --git a/src/components/images/imageLoader.js b/src/components/images/imageLoader.js index 37b9226f6a..4d6a45d2d4 100644 --- a/src/components/images/imageLoader.js +++ b/src/components/images/imageLoader.js @@ -1,4 +1,4 @@ -define(['lazyLoader', 'imageFetcher', 'layoutManager', 'browser', 'appSettings', 'userSettings', 'require', 'css!./style'], function (lazyLoader, imageFetcher, layoutManager, browser, appSettings, userSettings, require) { +define(['lazyLoader', 'userSettings', 'css!./style'], function (lazyLoader, userSettings) { 'use strict'; var self = {}; @@ -17,8 +17,17 @@ define(['lazyLoader', 'imageFetcher', 'layoutManager', 'browser', 'appSettings', } } - function fillImageElement(elem, source) { - imageFetcher.loadImage(elem, source).then(function () { + function fillImageElement(elem, url) { + let preloaderImg = new Image(); + preloaderImg.src = url; + + preloaderImg.addEventListener('load', (event) => { + if (elem.tagName !== "IMG") { + elem.style.backgroundImage = "url('" + url + "')"; + } else { + elem.setAttribute("src", url); + } + if (userSettings.enableFastFadein()) { elem.classList.add('lazy-image-fadein-fast'); } else { @@ -26,13 +35,28 @@ define(['lazyLoader', 'imageFetcher', 'layoutManager', 'browser', 'appSettings', } elem.removeAttribute("data-src"); + preloaderImg = null; }); } function emptyImageElement(elem) { - imageFetcher.unloadImage(elem).then(function (url) { - elem.setAttribute("data-src", url); - }); + var url; + + if (elem.tagName !== "IMG") { + url = elem.style.backgroundImage.slice(4, -1).replace(/"/g, ""); + elem.style.backgroundImage = 'none'; + } else { + url = elem.getAttribute("src"); + elem.setAttribute("src", ""); + } + + elem.setAttribute("data-src", url); + + if (userSettings.enableFastFadein()) { + elem.classList.remove('lazy-image-fadein-fast'); + } else { + elem.classList.remove('lazy-image-fadein'); + } } function lazyChildren(elem) { diff --git a/src/components/images/style.css b/src/components/images/style.css index 2836dd0159..ef60f8b837 100644 --- a/src/components/images/style.css +++ b/src/components/images/style.css @@ -1,26 +1,15 @@ -.lazy-image-fadein { +.cardImageContainer.lazy { opacity: 0; - animation: lazy-image-fadein 330ms ease-in normal both; - -webkit-animation-duration: 0.8s; - -moz-animation-duration: 0.8s; - -o-animation-duration: 0.8s; - animation-duration: 0.8s; - -webkit-animation-name: popInAnimation; - -moz-animation-name: popInAnimation; - -o-animation-name: popInAnimation; - animation-name: popInAnimation; - -webkit-animation-fill-mode: forwards; - -moz-animation-fill-mode: forwards; - -o-animation-fill-mode: forwards; - animation-fill-mode: forwards; - -webkit-animation-timing-function: cubic-bezier(0, 0, 0.5, 1); - -moz-animation-timing-function: cubic-bezier(0, 0, 0.5, 1); - -o-animation-timing-function: cubic-bezier(0, 0, 0.5, 1); - animation-timing-function: cubic-bezier(0, 0, 0.5, 1); } -.lazy-image-fadein-fast { - animation: lazy-image-fadein 160ms ease-in normal both; +.cardImageContainer.lazy.lazy-image-fadein { + opacity: 1; + transition: opacity 1s; +} + +.cardImageContainer.lazy.lazy-image-fadein-fast { + opacity: 1; + transition: opacity 0.5s; } @keyframes lazy-image-fadein { @@ -32,13 +21,3 @@ opacity: 1; } } - -@keyframes popInAnimation { - 0% { - opacity: 0; - } - - 100% { - opacity: 1; - } -} diff --git a/src/scripts/site.js b/src/scripts/site.js index 8957481242..df1c0f33d1 100644 --- a/src/scripts/site.js +++ b/src/scripts/site.js @@ -392,10 +392,6 @@ var AppInfo = {}; define("registerElement", ["document-register-element"], returnFirstDependency); } - define("imageFetcher", [componentsPath + "/images/imageFetcher"], returnFirstDependency); - - var preferNativeAlerts = browser.tv; - define("alert", [componentsPath + "/alert"], returnFirstDependency); defineResizeObserver(); From 03b614266ea1ea8b1084b35981e745978342a5d8 Mon Sep 17 00:00:00 2001 From: MrTimscampi Date: Sun, 12 Apr 2020 03:54:09 +0200 Subject: [PATCH 05/28] Remove superfluous observer instance in lazyloader --- src/components/lazyloader/lazyloader-intersectionobserver.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/lazyloader/lazyloader-intersectionobserver.js b/src/components/lazyloader/lazyloader-intersectionobserver.js index d39bddf6ac..4282587902 100644 --- a/src/components/lazyloader/lazyloader-intersectionobserver.js +++ b/src/components/lazyloader/lazyloader-intersectionobserver.js @@ -8,7 +8,7 @@ const callback = this.options.callback; const observer = new IntersectionObserver( - (entries, observer) => { + (entries) => { entries.forEach(entry => { callback(entry); }, From a802079ba3e10bf312be640430b17bddc802e6ed Mon Sep 17 00:00:00 2001 From: MrTimscampi Date: Sun, 12 Apr 2020 05:47:19 +0200 Subject: [PATCH 06/28] Add default export to userSettings --- src/scripts/settings/userSettings.js | 30 ++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/scripts/settings/userSettings.js b/src/scripts/settings/userSettings.js index 6f115eeffa..d757dd8081 100644 --- a/src/scripts/settings/userSettings.js +++ b/src/scripts/settings/userSettings.js @@ -265,3 +265,33 @@ import events from 'events'; } /* eslint-enable indent */ +export default { + setUserInfo: setUserInfo, + getData: getData, + importFrom: importFrom, + set: set, + get: get, + serverConfig: serverConfig, + enableCinemaMode: enableCinemaMode, + enableNextVideoInfoOverlay: enableNextVideoInfoOverlay, + enableThemeSongs: enableThemeSongs, + enableThemeVideos: enableThemeVideos, + enableFastFadein: enableFastFadein, + enableBackdrops: enableBackdrops, + language: language, + dateTimeLocale: dateTimeLocale, + skipBackLength: skipBackLength, + skipForwardLength: skipForwardLength, + dashboardTheme: dashboardTheme, + skin: skin, + theme: theme, + screensaver: screensaver, + libraryPageSize: libraryPageSize, + soundEffects: soundEffects, + loadQuerySettings: loadQuerySettings, + saveQuerySettings: saveQuerySettings, + getSubtitleAppearanceSettings: getSubtitleAppearanceSettings, + setSubtitleAppearanceSettings: setSubtitleAppearanceSettings, + setFilter: setFilter, + getFilter: getFilter +}; From ac9668f9bb188830ca6fac5c411fd7328b3f8c92 Mon Sep 17 00:00:00 2001 From: MrTimscampi Date: Sun, 12 Apr 2020 05:47:41 +0200 Subject: [PATCH 07/28] Migrate imageLoader to ES6 --- package.json | 3 ++- src/components/images/imageLoader.js | 30 ++++++++++++++-------------- 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/package.json b/package.json index 8de04b3628..e33b447f82 100644 --- a/package.json +++ b/package.json @@ -100,7 +100,8 @@ "src/scripts/dfnshelper.js", "src/scripts/imagehelper.js", "src/scripts/inputManager.js", - "src/components/lazyloader/lazyloader-intersectionobserver.js" + "src/components/lazyloader/lazyloader-intersectionobserver.js", + "src/components/images/imageLoader.js" ], "plugins": [ "@babel/plugin-transform-modules-amd" diff --git a/src/components/images/imageLoader.js b/src/components/images/imageLoader.js index 4d6a45d2d4..fda6e54668 100644 --- a/src/components/images/imageLoader.js +++ b/src/components/images/imageLoader.js @@ -1,9 +1,9 @@ -define(['lazyLoader', 'userSettings', 'css!./style'], function (lazyLoader, userSettings) { - 'use strict'; +import lazyLoader from 'lazyLoader'; +import userSettings from 'userSettings'; +import 'css!./style'; +/* eslint-disable indent */ - var self = {}; - - function fillImage(entry) { + export function fillImage(entry) { if (!entry) { throw new Error('entry cannot be null'); } @@ -59,11 +59,11 @@ define(['lazyLoader', 'userSettings', 'css!./style'], function (lazyLoader, user } } - function lazyChildren(elem) { + export function lazyChildren(elem) { lazyLoader.lazyChildren(elem, fillImage); } - function getPrimaryImageAspectRatio(items) { + export function getPrimaryImageAspectRatio(items) { var values = []; @@ -123,7 +123,7 @@ define(['lazyLoader', 'userSettings', 'css!./style'], function (lazyLoader, user return result; } - function fillImages(elems) { + export function fillImages(elems) { for (var i = 0, length = elems.length; i < length; i++) { var elem = elems[0]; @@ -131,10 +131,10 @@ define(['lazyLoader', 'userSettings', 'css!./style'], function (lazyLoader, user } } - self.fillImages = fillImages; - self.lazyImage = fillImage; - self.lazyChildren = lazyChildren; - self.getPrimaryImageAspectRatio = getPrimaryImageAspectRatio; - - return self; -}); +/* eslint-enable indent */ +export default { + fillImages: fillImages, + lazyImage: fillImage, + lazyChildren: lazyChildren, + getPrimaryImageAspectRatio: getPrimaryImageAspectRatio +}; From 6dde11349acfae90a1c1ebffa637ed1227f19f5f Mon Sep 17 00:00:00 2001 From: MrTimscampi Date: Sun, 12 Apr 2020 14:25:12 +0200 Subject: [PATCH 08/28] Fix image loading on details pages --- src/components/images/imageLoader.js | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/src/components/images/imageLoader.js b/src/components/images/imageLoader.js index fda6e54668..80bb24bcfe 100644 --- a/src/components/images/imageLoader.js +++ b/src/components/images/imageLoader.js @@ -3,12 +3,33 @@ import userSettings from 'userSettings'; import 'css!./style'; /* eslint-disable indent */ + export function lazyImage(elem, source, enableEffects) { + + if (!elem) { + throw new Error('elem cannot be null'); + } + + if (!source) { + source = elem.getAttribute('data-src'); + } + + if (!source) { + return; + } + + fillImageElement(elem, source, enableEffects); + } + export function fillImage(entry) { if (!entry) { throw new Error('entry cannot be null'); } - var source = entry.target.getAttribute('data-src'); + if (entry.target) { + var source = entry.target.getAttribute('data-src'); + } else { + var source = entry; + } if (entry.intersectionRatio > 0 && source) { fillImageElement(entry.target, source); @@ -21,7 +42,7 @@ import 'css!./style'; let preloaderImg = new Image(); preloaderImg.src = url; - preloaderImg.addEventListener('load', (event) => { + preloaderImg.addEventListener('load', () => { if (elem.tagName !== "IMG") { elem.style.backgroundImage = "url('" + url + "')"; } else { @@ -134,7 +155,8 @@ import 'css!./style'; /* eslint-enable indent */ export default { fillImages: fillImages, - lazyImage: fillImage, + fillImage: fillImage, + lazyImage: lazyImage, lazyChildren: lazyChildren, getPrimaryImageAspectRatio: getPrimaryImageAspectRatio }; From 58d9037986cb07df54408b60f9927551fa4eca44 Mon Sep 17 00:00:00 2001 From: MrTimscampi Date: Sun, 12 Apr 2020 14:29:42 +0200 Subject: [PATCH 09/28] Remove useless parameter in lazyImage --- src/components/images/imageLoader.js | 9 ++------- src/controllers/itemdetailpage.js | 10 +++++----- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/src/components/images/imageLoader.js b/src/components/images/imageLoader.js index 80bb24bcfe..2166d6ccff 100644 --- a/src/components/images/imageLoader.js +++ b/src/components/images/imageLoader.js @@ -3,21 +3,16 @@ import userSettings from 'userSettings'; import 'css!./style'; /* eslint-disable indent */ - export function lazyImage(elem, source, enableEffects) { - + export function lazyImage(elem, source = elem.getAttribute('data-src')) { if (!elem) { throw new Error('elem cannot be null'); } - if (!source) { - source = elem.getAttribute('data-src'); - } - if (!source) { return; } - fillImageElement(elem, source, enableEffects); + fillImageElement(elem, source); } export function fillImage(entry) { diff --git a/src/controllers/itemdetailpage.js b/src/controllers/itemdetailpage.js index 178419e284..81314ce7c1 100644 --- a/src/controllers/itemdetailpage.js +++ b/src/controllers/itemdetailpage.js @@ -473,7 +473,7 @@ define(["loading", "appRouter", "layoutManager", "connectionManager", "userSetti tag: item.ImageTags.Thumb }); page.classList.remove("noBackdrop"); - imageLoader.lazyImage(itemBackdropElement, imgUrl, false); + imageLoader.lazyImage(itemBackdropElement, imgUrl); hasbackdrop = true; } else if (usePrimaryImage && item.ImageTags && item.ImageTags.Primary) { imgUrl = apiClient.getScaledImageUrl(item.Id, { @@ -483,7 +483,7 @@ define(["loading", "appRouter", "layoutManager", "connectionManager", "userSetti tag: item.ImageTags.Primary }); page.classList.remove("noBackdrop"); - imageLoader.lazyImage(itemBackdropElement, imgUrl, false); + imageLoader.lazyImage(itemBackdropElement, imgUrl); hasbackdrop = true; } else if (item.BackdropImageTags && item.BackdropImageTags.length) { imgUrl = apiClient.getScaledImageUrl(item.Id, { @@ -493,7 +493,7 @@ define(["loading", "appRouter", "layoutManager", "connectionManager", "userSetti tag: item.BackdropImageTags[0] }); page.classList.remove("noBackdrop"); - imageLoader.lazyImage(itemBackdropElement, imgUrl, false); + imageLoader.lazyImage(itemBackdropElement, imgUrl); hasbackdrop = true; } else if (item.ParentBackdropItemId && item.ParentBackdropImageTags && item.ParentBackdropImageTags.length) { imgUrl = apiClient.getScaledImageUrl(item.ParentBackdropItemId, { @@ -503,7 +503,7 @@ define(["loading", "appRouter", "layoutManager", "connectionManager", "userSetti tag: item.ParentBackdropImageTags[0] }); page.classList.remove("noBackdrop"); - imageLoader.lazyImage(itemBackdropElement, imgUrl, false); + imageLoader.lazyImage(itemBackdropElement, imgUrl); hasbackdrop = true; } else if (item.ImageTags && item.ImageTags.Thumb) { imgUrl = apiClient.getScaledImageUrl(item.Id, { @@ -513,7 +513,7 @@ define(["loading", "appRouter", "layoutManager", "connectionManager", "userSetti tag: item.ImageTags.Thumb }); page.classList.remove("noBackdrop"); - imageLoader.lazyImage(itemBackdropElement, imgUrl, false); + imageLoader.lazyImage(itemBackdropElement, imgUrl); hasbackdrop = true; } else { itemBackdropElement.style.backgroundImage = ""; From e256e64e68d9348ef7151d9be3a6bea3cc1eff46 Mon Sep 17 00:00:00 2001 From: MrTimscampi Date: Sun, 12 Apr 2020 14:34:51 +0200 Subject: [PATCH 10/28] Handle source properly in fillImage --- src/components/images/imageLoader.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/components/images/imageLoader.js b/src/components/images/imageLoader.js index 2166d6ccff..4247f2c0cb 100644 --- a/src/components/images/imageLoader.js +++ b/src/components/images/imageLoader.js @@ -20,10 +20,11 @@ import 'css!./style'; throw new Error('entry cannot be null'); } + var source = undefined; if (entry.target) { - var source = entry.target.getAttribute('data-src'); + source = entry.target.getAttribute('data-src'); } else { - var source = entry; + source = entry; } if (entry.intersectionRatio > 0 && source) { @@ -34,6 +35,10 @@ import 'css!./style'; } function fillImageElement(elem, url) { + if (url === undefined) { + throw new Error('url cannot be undefined'); + } + let preloaderImg = new Image(); preloaderImg.src = url; From 3dd141915e3fa91c5c166cacd2bc3d67f70a5187 Mon Sep 17 00:00:00 2001 From: MrTimscampi Date: Wed, 15 Apr 2020 07:54:33 +0200 Subject: [PATCH 11/28] Use full image for MediaSession --- src/components/playback/mediasession.js | 41 ++++++++----------------- 1 file changed, 12 insertions(+), 29 deletions(-) diff --git a/src/components/playback/mediasession.js b/src/components/playback/mediasession.js index c03420c85a..dbc2dcc9ba 100644 --- a/src/components/playback/mediasession.js +++ b/src/components/playback/mediasession.js @@ -11,13 +11,12 @@ define(['playbackManager', 'nowPlayingHelper', 'events', 'connectionManager'], f var currentPlayer; var lastUpdateTime = 0; - function seriesImageUrl(item, options) { + function seriesImageUrl(item, options = {}) { if (item.Type !== 'Episode') { return null; } - options = options || {}; options.type = options.type || "Primary"; if (options.type === 'Primary') { @@ -49,9 +48,7 @@ define(['playbackManager', 'nowPlayingHelper', 'events', 'connectionManager'], f return null; } - function imageUrl(item, options) { - - options = options || {}; + function imageUrl(item, options = {}) { options.type = options.type || "Primary"; if (item.ImageTags && item.ImageTags[options.type]) { @@ -69,29 +66,26 @@ define(['playbackManager', 'nowPlayingHelper', 'events', 'connectionManager'], f return null; } - function pushImageUrl(item, imageOptions, list) { + function pushImageUrl(item, imageOptions = {}) { var url = seriesImageUrl(item, imageOptions) || imageUrl(item, imageOptions); if (url) { var height = imageOptions.height || imageOptions.maxHeight; - list.push({ + return { src: url, sizes: height + 'x' + height - }); + }; } } function getImageUrls(item) { - var list = []; + const imageSizes = [96, 128, 192, 256, 384, 512]; - pushImageUrl(item, {height: 96}, list); - pushImageUrl(item, {height: 128}, list); - pushImageUrl(item, {height: 192}, list); - pushImageUrl(item, {height: 256}, list); - pushImageUrl(item, {height: 384}, list); - pushImageUrl(item, {height: 512}, list); + imageSizes.forEach((size) => { + list.push(pushImageUrl(item, {height: size})); + }); return list; } @@ -127,11 +121,6 @@ define(['playbackManager', 'nowPlayingHelper', 'events', 'connectionManager'], f var parts = nowPlayingHelper.getNowPlayingNames(item); var artist = parts[parts.length - 1].text; var title = parts.length === 1 ? '' : parts[0].text; - var albumArtist; - - if (item.AlbumArtists && item.AlbumArtists[0]) { - albumArtist = item.AlbumArtists[0].Name; - } var album = item.Album || ''; var itemId = item.Id; @@ -143,22 +132,16 @@ define(['playbackManager', 'nowPlayingHelper', 'events', 'connectionManager'], f var isPaused = playState.IsPaused || false; var canSeek = playState.CanSeek || false; - if (navigator.mediaSession) { + if ('mediaSession' in navigator) { navigator.mediaSession.metadata = new MediaMetadata({ title: title, artist: artist, album: album, - artwork: getImageUrls(item), - albumArtist: albumArtist, - currentTime: currentTime, - duration: duration, - paused: isPaused, - itemId: itemId, - mediaType: item.MediaType + artwork: getImageUrls(item) }); } else { var imageUrl = []; - pushImageUrl(item, {maxHeight: 400}, imageUrl); + imageUrl.push(pushImageUrl(item)); if (imageUrl.length) { imageUrl = imageUrl[0].src; From 9bcb270942ea8f4c3c5380138fab089028f898bf Mon Sep 17 00:00:00 2001 From: MrTimscampi Date: Wed, 15 Apr 2020 08:14:08 +0200 Subject: [PATCH 12/28] More MediaSession cleanup --- src/components/playback/mediasession.js | 73 ++++++------------------- 1 file changed, 18 insertions(+), 55 deletions(-) diff --git a/src/components/playback/mediasession.js b/src/components/playback/mediasession.js index dbc2dcc9ba..d77b02474a 100644 --- a/src/components/playback/mediasession.js +++ b/src/components/playback/mediasession.js @@ -9,36 +9,20 @@ define(['playbackManager', 'nowPlayingHelper', 'events', 'connectionManager'], f // Reports media playback to the device for lock screen control var currentPlayer; - var lastUpdateTime = 0; - - function seriesImageUrl(item, options = {}) { + function seriesImageUrl(item, options = {}, type = options.type || 'Primary') { if (item.Type !== 'Episode') { return null; - } - - options.type = options.type || "Primary"; - - if (options.type === 'Primary') { - - if (item.SeriesPrimaryImageTag) { - - options.tag = item.SeriesPrimaryImageTag; - - return connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.SeriesId, options); - } - } - - if (options.type === 'Thumb') { + } else if (type === 'Primary' && item.SeriesPrimaryImageTag) { + options.tag = item.SeriesPrimaryImageTag; + return connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.SeriesId, options); + } else if (type === 'Thumb') { if (item.SeriesThumbImageTag) { - options.tag = item.SeriesThumbImageTag; return connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.SeriesId, options); - } - if (item.ParentThumbImageTag) { - + } else if (item.ParentThumbImageTag) { options.tag = item.ParentThumbImageTag; return connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.ParentThumbItemId, options); @@ -48,18 +32,14 @@ define(['playbackManager', 'nowPlayingHelper', 'events', 'connectionManager'], f return null; } - function imageUrl(item, options = {}) { - options.type = options.type || "Primary"; + function imageUrl(item, options = {}, type = options.type || 'Primary') { + if (item.ImageTags && item.ImageTags[type]) { + options.tag = item.ImageTags[type]; - if (item.ImageTags && item.ImageTags[options.type]) { - - options.tag = item.ImageTags[options.type]; return connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.Id, options); - } - - if (item.AlbumId && item.AlbumPrimaryImageTag) { - + } else if (item.AlbumId && item.AlbumPrimaryImageTag) { options.tag = item.AlbumPrimaryImageTag; + return connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.AlbumId, options); } @@ -79,9 +59,8 @@ define(['playbackManager', 'nowPlayingHelper', 'events', 'connectionManager'], f } } - function getImageUrls(item) { + function getImageUrls(item, imageSizes = [96, 128, 192, 256, 384, 512]) { var list = []; - const imageSizes = [96, 128, 192, 256, 384, 512]; imageSizes.forEach((size) => { list.push(pushImageUrl(item, {height: size})); @@ -166,37 +145,25 @@ define(['playbackManager', 'nowPlayingHelper', 'events', 'connectionManager'], f } function onGeneralEvent(e) { + var state = playbackManager.getPlayerState(this); - var player = this; - var state = playbackManager.getPlayerState(player); - - updatePlayerState(player, state, e.type); + updatePlayerState(this, state, e.type); } function onStateChanged(e, state) { - - var player = this; - updatePlayerState(player, state, 'statechange'); + updatePlayerState(this, state, 'statechange'); } function onPlaybackStart(e, state) { - - var player = this; - - updatePlayerState(player, state, e.type); + updatePlayerState(this, state, e.type); } - function onPlaybackStopped(e, state) { - - var player = this; - + function onPlaybackStopped() { hideMediaControls(); } function releaseCurrentPlayer() { - if (currentPlayer) { - events.off(currentPlayer, 'playbackstart', onPlaybackStart); events.off(currentPlayer, 'playbackstop', onPlaybackStopped); events.off(currentPlayer, 'unpause', onGeneralEvent); @@ -211,8 +178,6 @@ define(['playbackManager', 'nowPlayingHelper', 'events', 'connectionManager'], f } function hideMediaControls() { - lastUpdateTime = 0; - if (navigator.mediaSession) { navigator.mediaSession.metadata = null; } else { @@ -221,7 +186,6 @@ define(['playbackManager', 'nowPlayingHelper', 'events', 'connectionManager'], f } function bindToPlayer(player) { - releaseCurrentPlayer(); if (!player) { @@ -244,8 +208,8 @@ define(['playbackManager', 'nowPlayingHelper', 'events', 'connectionManager'], f function execute(name) { playbackManager[name](currentPlayer); } - if (navigator.mediaSession) { + if (navigator.mediaSession) { navigator.mediaSession.setActionHandler('previoustrack', function () { execute('previousTrack'); }); @@ -272,7 +236,6 @@ define(['playbackManager', 'nowPlayingHelper', 'events', 'connectionManager'], f } events.on(playbackManager, 'playerchange', function () { - bindToPlayer(playbackManager.getCurrentPlayer()); }); From af7c87b9f64a7c3ca964a377f26dad2afb34dacc Mon Sep 17 00:00:00 2001 From: MrTimscampi Date: Wed, 15 Apr 2020 08:49:46 +0200 Subject: [PATCH 13/28] Migrate MediaSession to ES6 --- package.json | 1 + src/components/playback/mediasession.js | 59 ++++++++++++------------- 2 files changed, 30 insertions(+), 30 deletions(-) diff --git a/package.json b/package.json index 8f42635adc..693dac2e7c 100644 --- a/package.json +++ b/package.json @@ -92,6 +92,7 @@ "src/components/filedownloader.js", "src/components/filesystem.js", "src/components/input/keyboardnavigation.js", + "src/components/playback/mediasession.js", "src/components/sanatizefilename.js", "src/components/scrollManager.js", "src/scripts/settings/appSettings.js", diff --git a/src/components/playback/mediasession.js b/src/components/playback/mediasession.js index d77b02474a..65a61b91c8 100644 --- a/src/components/playback/mediasession.js +++ b/src/components/playback/mediasession.js @@ -1,14 +1,12 @@ -define(['playbackManager', 'nowPlayingHelper', 'events', 'connectionManager'], function (playbackManager, nowPlayingHelper, events, connectionManager) { - "use strict"; - - // no support for mediaSession - if (!navigator.mediaSession && !window.NativeShell) { - return; - } +import playbackManager from 'playbackManager'; +import nowPlayingHelper from 'nowPlayingHelper'; +import events from 'events'; +import connectionManager from 'connectionManager'; +/* eslint-disable indent */ // Reports media playback to the device for lock screen control - var currentPlayer; + let currentPlayer; function seriesImageUrl(item, options = {}, type = options.type || 'Primary') { if (item.Type !== 'Episode') { @@ -47,10 +45,10 @@ define(['playbackManager', 'nowPlayingHelper', 'events', 'connectionManager'], f } function pushImageUrl(item, imageOptions = {}) { - var url = seriesImageUrl(item, imageOptions) || imageUrl(item, imageOptions); + const url = seriesImageUrl(item, imageOptions) || imageUrl(item, imageOptions); if (url) { - var height = imageOptions.height || imageOptions.maxHeight; + const height = imageOptions.height || imageOptions.maxHeight; return { src: url, @@ -60,7 +58,7 @@ define(['playbackManager', 'nowPlayingHelper', 'events', 'connectionManager'], f } function getImageUrls(item, imageSizes = [96, 128, 192, 256, 384, 512]) { - var list = []; + const list = []; imageSizes.forEach((size) => { list.push(pushImageUrl(item, {height: size})); @@ -71,45 +69,45 @@ define(['playbackManager', 'nowPlayingHelper', 'events', 'connectionManager'], f function updatePlayerState(player, state, eventName) { // Don't go crazy reporting position changes - if (eventName == 'timeupdate') { + if (eventName === 'timeupdate') { // Only report if this item hasn't been reported yet, or if there's an actual playback change. // Don't report on simple time updates return; } - var item = state.NowPlayingItem; + const item = state.NowPlayingItem; if (!item) { hideMediaControls(); return; } - if (eventName == 'init') { // transform "init" event into "timeupdate" to restraint update rate + if (eventName === 'init') { // transform "init" event into "timeupdate" to restraint update rate eventName = 'timeupdate'; } - var isVideo = item.MediaType === 'Video'; - var isLocalPlayer = player.isLocalPlayer || false; + const isVideo = item.MediaType === 'Video'; + const isLocalPlayer = player.isLocalPlayer || false; // Local players do their own notifications if (isLocalPlayer && isVideo) { return; } - var playState = state.PlayState || {}; - var parts = nowPlayingHelper.getNowPlayingNames(item); - var artist = parts[parts.length - 1].text; - var title = parts.length === 1 ? '' : parts[0].text; + const playState = state.PlayState || {}; + const parts = nowPlayingHelper.getNowPlayingNames(item); + const artist = parts[parts.length - 1].text; + const title = parts.length === 1 ? '' : parts[0].text; - var album = item.Album || ''; - var itemId = item.Id; + const album = item.Album || ''; + const itemId = item.Id; // Convert to ms - var duration = parseInt(item.RunTimeTicks ? (item.RunTimeTicks / 10000) : 0); - var currentTime = parseInt(playState.PositionTicks ? (playState.PositionTicks / 10000) : 0); + const duration = parseInt(item.RunTimeTicks ? (item.RunTimeTicks / 10000) : 0); + const currentTime = parseInt(playState.PositionTicks ? (playState.PositionTicks / 10000) : 0); - var isPaused = playState.IsPaused || false; - var canSeek = playState.CanSeek || false; + const isPaused = playState.IsPaused || false; + const canSeek = playState.CanSeek || false; if ('mediaSession' in navigator) { navigator.mediaSession.metadata = new MediaMetadata({ @@ -119,7 +117,7 @@ define(['playbackManager', 'nowPlayingHelper', 'events', 'connectionManager'], f artwork: getImageUrls(item) }); } else { - var imageUrl = []; + let imageUrl = []; imageUrl.push(pushImageUrl(item)); if (imageUrl.length) { @@ -145,7 +143,7 @@ define(['playbackManager', 'nowPlayingHelper', 'events', 'connectionManager'], f } function onGeneralEvent(e) { - var state = playbackManager.getPlayerState(this); + const state = playbackManager.getPlayerState(this); updatePlayerState(this, state, e.type); } @@ -194,7 +192,7 @@ define(['playbackManager', 'nowPlayingHelper', 'events', 'connectionManager'], f currentPlayer = player; - var state = playbackManager.getPlayerState(player); + const state = playbackManager.getPlayerState(player); updatePlayerState(player, state, 'init'); events.on(currentPlayer, 'playbackstart', onPlaybackStart); @@ -240,4 +238,5 @@ define(['playbackManager', 'nowPlayingHelper', 'events', 'connectionManager'], f }); bindToPlayer(playbackManager.getCurrentPlayer()); -}); + +/* eslint-enable indent */ From 9cba01963fd2ee4b3718dbe10abcf5b42f56776a Mon Sep 17 00:00:00 2001 From: MrTimscampi Date: Wed, 15 Apr 2020 10:21:58 +0200 Subject: [PATCH 14/28] Fix code smell in mediasession --- src/components/playback/mediasession.js | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/components/playback/mediasession.js b/src/components/playback/mediasession.js index 65a61b91c8..8851601bdc 100644 --- a/src/components/playback/mediasession.js +++ b/src/components/playback/mediasession.js @@ -117,13 +117,9 @@ import connectionManager from 'connectionManager'; artwork: getImageUrls(item) }); } else { - let imageUrl = []; - imageUrl.push(pushImageUrl(item)); - - if (imageUrl.length) { - imageUrl = imageUrl[0].src; - } else { - imageUrl = null; + let itemImageUrl = seriesImageUrl(item) || imageUrl(item); + if (!itemImageUrl) { + itemImageUrl = null; } window.NativeShell.updateMediaSession({ @@ -135,7 +131,7 @@ import connectionManager from 'connectionManager'; album: album, duration: duration, position: currentTime, - imageUrl: imageUrl, + imageUrl: itemImageUrl, canSeek: canSeek, isPaused: isPaused }); From e0a71938eae6b07f523d0c843efddfba035d1ceb Mon Sep 17 00:00:00 2001 From: MrTimscampi Date: Wed, 15 Apr 2020 14:39:44 +0200 Subject: [PATCH 15/28] Adjust animation speed and remove useless arguments --- src/components/images/style.css | 14 ++------------ .../lazyloader/lazyloader-intersectionobserver.js | 4 ++-- 2 files changed, 4 insertions(+), 14 deletions(-) diff --git a/src/components/images/style.css b/src/components/images/style.css index ef60f8b837..2b9422d55b 100644 --- a/src/components/images/style.css +++ b/src/components/images/style.css @@ -4,20 +4,10 @@ .cardImageContainer.lazy.lazy-image-fadein { opacity: 1; - transition: opacity 1s; + transition: opacity 0.7s; } .cardImageContainer.lazy.lazy-image-fadein-fast { opacity: 1; - transition: opacity 0.5s; -} - -@keyframes lazy-image-fadein { - from { - opacity: 0; - } - - to { - opacity: 1; - } + transition: opacity 0.2s; } diff --git a/src/components/lazyloader/lazyloader-intersectionobserver.js b/src/components/lazyloader/lazyloader-intersectionobserver.js index 4282587902..68f1b11cbc 100644 --- a/src/components/lazyloader/lazyloader-intersectionobserver.js +++ b/src/components/lazyloader/lazyloader-intersectionobserver.js @@ -31,7 +31,7 @@ }); } - destroyObserver(elements) { + destroyObserver() { const observer = this.observer; if (observer) { @@ -40,7 +40,7 @@ } } - destroy(elements) { + destroy() { this.destroyObserver(); this.options = null; } From 96d5dd54cdae4123e0df1e7966d6d376c12b1e7a Mon Sep 17 00:00:00 2001 From: MrTimscampi Date: Thu, 16 Apr 2020 16:19:15 +0200 Subject: [PATCH 16/28] Set options.type in mediaSessions if unset --- src/components/playback/mediasession.js | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/components/playback/mediasession.js b/src/components/playback/mediasession.js index 8851601bdc..93ef044c98 100644 --- a/src/components/playback/mediasession.js +++ b/src/components/playback/mediasession.js @@ -8,14 +8,16 @@ import connectionManager from 'connectionManager'; let currentPlayer; - function seriesImageUrl(item, options = {}, type = options.type || 'Primary') { + function seriesImageUrl(item, options = {}) { + options.type = options.type || 'Primary'; + if (item.Type !== 'Episode') { return null; - } else if (type === 'Primary' && item.SeriesPrimaryImageTag) { + } else if (options.type === 'Primary' && item.SeriesPrimaryImageTag) { options.tag = item.SeriesPrimaryImageTag; return connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.SeriesId, options); - } else if (type === 'Thumb') { + } else if (options.type === 'Thumb') { if (item.SeriesThumbImageTag) { options.tag = item.SeriesThumbImageTag; @@ -30,9 +32,11 @@ import connectionManager from 'connectionManager'; return null; } - function imageUrl(item, options = {}, type = options.type || 'Primary') { - if (item.ImageTags && item.ImageTags[type]) { - options.tag = item.ImageTags[type]; + function imageUrl(item, options = {}) { + options.type = options.type || 'Primary'; + + if (item.ImageTags && item.ImageTags[options.type]) { + options.tag = item.ImageTags[options.type]; return connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.Id, options); } else if (item.AlbumId && item.AlbumPrimaryImageTag) { From fccd99d0ef909247660207b824a08b6f81542ff4 Mon Sep 17 00:00:00 2001 From: MrTimscampi Date: Thu, 16 Apr 2020 16:36:15 +0200 Subject: [PATCH 17/28] Fix suggestions --- src/components/playback/mediasession.js | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/components/playback/mediasession.js b/src/components/playback/mediasession.js index 93ef044c98..1f38345f3f 100644 --- a/src/components/playback/mediasession.js +++ b/src/components/playback/mediasession.js @@ -48,7 +48,7 @@ import connectionManager from 'connectionManager'; return null; } - function pushImageUrl(item, imageOptions = {}) { + function getImageUrl(item, imageOptions = {}) { const url = seriesImageUrl(item, imageOptions) || imageUrl(item, imageOptions); if (url) { @@ -58,6 +58,8 @@ import connectionManager from 'connectionManager'; src: url, sizes: height + 'x' + height }; + } else { + return null; } } @@ -65,7 +67,7 @@ import connectionManager from 'connectionManager'; const list = []; imageSizes.forEach((size) => { - list.push(pushImageUrl(item, {height: size})); + list.push(getImageUrl(item, {height: size})); }); return list; @@ -122,9 +124,6 @@ import connectionManager from 'connectionManager'; }); } else { let itemImageUrl = seriesImageUrl(item) || imageUrl(item); - if (!itemImageUrl) { - itemImageUrl = null; - } window.NativeShell.updateMediaSession({ action: eventName, From a224a87fc7091f559cc0abb35615a39f84c30277 Mon Sep 17 00:00:00 2001 From: MrTimscampi Date: Thu, 16 Apr 2020 16:39:41 +0200 Subject: [PATCH 18/28] Adjust mediaSession feature test for consistency --- src/components/playback/mediasession.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/playback/mediasession.js b/src/components/playback/mediasession.js index 1f38345f3f..470a9de2f6 100644 --- a/src/components/playback/mediasession.js +++ b/src/components/playback/mediasession.js @@ -175,7 +175,7 @@ import connectionManager from 'connectionManager'; } function hideMediaControls() { - if (navigator.mediaSession) { + if ('mediaSession' in navigator) { navigator.mediaSession.metadata = null; } else { window.NativeShell.hideMediaSession(); @@ -206,7 +206,7 @@ import connectionManager from 'connectionManager'; playbackManager[name](currentPlayer); } - if (navigator.mediaSession) { + if ('mediaSession' in navigator) { navigator.mediaSession.setActionHandler('previoustrack', function () { execute('previousTrack'); }); From a6732443f3088f4c0fa2b43e556d9f9bef572331 Mon Sep 17 00:00:00 2001 From: MrTimscampi Date: Thu, 16 Apr 2020 17:00:26 +0200 Subject: [PATCH 19/28] Only push image url to array if non-null --- src/components/playback/mediasession.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/components/playback/mediasession.js b/src/components/playback/mediasession.js index 470a9de2f6..8e24cc61db 100644 --- a/src/components/playback/mediasession.js +++ b/src/components/playback/mediasession.js @@ -67,7 +67,10 @@ import connectionManager from 'connectionManager'; const list = []; imageSizes.forEach((size) => { - list.push(getImageUrl(item, {height: size})); + const url = getImageUrl(item, {height: size}); + if (url !== null) { + list.push(url); + } }); return list; From 097802cd51bf9d28c85cf1356238fa73969a63be Mon Sep 17 00:00:00 2001 From: MrTimscampi Date: Mon, 20 Apr 2020 17:48:02 +0200 Subject: [PATCH 20/28] Add maxHeight for media session image --- src/components/playback/mediasession.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/playback/mediasession.js b/src/components/playback/mediasession.js index 8e24cc61db..2dd10b3484 100644 --- a/src/components/playback/mediasession.js +++ b/src/components/playback/mediasession.js @@ -126,7 +126,7 @@ import connectionManager from 'connectionManager'; artwork: getImageUrls(item) }); } else { - let itemImageUrl = seriesImageUrl(item) || imageUrl(item); + let itemImageUrl = seriesImageUrl(item, { maxHeight: 3000 }) || imageUrl(item, { maxHeight: 3000 }); window.NativeShell.updateMediaSession({ action: eventName, From 7860deac2382314caf62a0f67b9bf24dcd81dca6 Mon Sep 17 00:00:00 2001 From: MrTimscampi Date: Sat, 25 Apr 2020 20:23:51 +0200 Subject: [PATCH 21/28] Implement suggestions --- package.json | 10 +++++----- src/components/images/imageLoader.js | 11 ++--------- 2 files changed, 7 insertions(+), 14 deletions(-) diff --git a/package.json b/package.json index 7d33448d15..7e8969556d 100644 --- a/package.json +++ b/package.json @@ -93,17 +93,17 @@ "src/components/dom.js", "src/components/filedownloader.js", "src/components/filesystem.js", + "src/components/images/imageLoader.js", "src/components/input/keyboardnavigation.js", + "src/components/lazyloader/lazyloader-intersectionobserver.js", "src/components/sanatizefilename.js", "src/components/scrollManager.js", - "src/scripts/settings/appSettings.js", - "src/scripts/settings/userSettings.js", - "src/scripts/settings/webSettings.js", "src/scripts/dfnshelper.js", "src/scripts/imagehelper.js", "src/scripts/inputManager.js", - "src/components/lazyloader/lazyloader-intersectionobserver.js", - "src/components/images/imageLoader.js" + "src/scripts/settings/appSettings.js", + "src/scripts/settings/userSettings.js", + "src/scripts/settings/webSettings.js" ], "plugins": [ "@babel/plugin-transform-modules-amd" diff --git a/src/components/images/imageLoader.js b/src/components/images/imageLoader.js index 4247f2c0cb..d610b79938 100644 --- a/src/components/images/imageLoader.js +++ b/src/components/images/imageLoader.js @@ -4,10 +4,6 @@ import 'css!./style'; /* eslint-disable indent */ export function lazyImage(elem, source = elem.getAttribute('data-src')) { - if (!elem) { - throw new Error('elem cannot be null'); - } - if (!source) { return; } @@ -73,11 +69,8 @@ import 'css!./style'; elem.setAttribute("data-src", url); - if (userSettings.enableFastFadein()) { - elem.classList.remove('lazy-image-fadein-fast'); - } else { - elem.classList.remove('lazy-image-fadein'); - } + elem.classList.remove('lazy-image-fadein-fast'); + elem.classList.remove('lazy-image-fadein'); } export function lazyChildren(elem) { From b8422a24643c2b460e54d2f38fa02ca68000e939 Mon Sep 17 00:00:00 2001 From: MrTimscampi Date: Fri, 1 May 2020 15:01:56 +0200 Subject: [PATCH 22/28] Fix userSettings import --- src/components/images/imageLoader.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/components/images/imageLoader.js b/src/components/images/imageLoader.js index d610b79938..1254f71167 100644 --- a/src/components/images/imageLoader.js +++ b/src/components/images/imageLoader.js @@ -1,5 +1,5 @@ -import lazyLoader from 'lazyLoader'; -import userSettings from 'userSettings'; +import * as lazyLoader from 'lazyLoader'; +import * as userSettings from 'userSettings'; import 'css!./style'; /* eslint-disable indent */ @@ -45,6 +45,7 @@ import 'css!./style'; elem.setAttribute("src", url); } + console.warn(userSettings.enableFastFadein()); if (userSettings.enableFastFadein()) { elem.classList.add('lazy-image-fadein-fast'); } else { From ff7b69e5d64978fa5912e5ca4e472dce1e9b51b9 Mon Sep 17 00:00:00 2001 From: MrTimscampi Date: Fri, 1 May 2020 15:04:09 +0200 Subject: [PATCH 23/28] Remove unused file visibleinviewport.js --- src/libraries/visibleinviewport.js | 41 ------------------------------ src/scripts/site.js | 1 - 2 files changed, 42 deletions(-) delete mode 100644 src/libraries/visibleinviewport.js diff --git a/src/libraries/visibleinviewport.js b/src/libraries/visibleinviewport.js deleted file mode 100644 index a48dbd3a1d..0000000000 --- a/src/libraries/visibleinviewport.js +++ /dev/null @@ -1,41 +0,0 @@ -define(['dom'], function (dom) { - 'use strict'; - - /** - * Copyright 2012, Digital Fusion - * Licensed under the MIT license. - * http://teamdf.com/jquery-plugins/license/ - * - * @author Sam Sehnert - * @desc A small plugin that checks whether elements are within - * the user visible viewport of a web browser. - * only accounts for vertical position, not horizontal. - */ - function visibleInViewport(elem, partial, thresholdX, thresholdY) { - - thresholdX = thresholdX || 0; - thresholdY = thresholdY || 0; - - if (!elem.getBoundingClientRect) { - return true; - } - - var windowSize = dom.getWindowSize(); - - var vpWidth = windowSize.innerWidth; - var vpHeight = windowSize.innerHeight; - - // Use this native browser method, if available. - var rec = elem.getBoundingClientRect(); - var tViz = rec.top >= 0 && rec.top < vpHeight + thresholdY; - var bViz = rec.bottom > 0 && rec.bottom <= vpHeight + thresholdY; - var lViz = rec.left >= 0 && rec.left < vpWidth + thresholdX; - var rViz = rec.right > 0 && rec.right <= vpWidth + thresholdX; - var vVisible = partial ? tViz || bViz : tViz && bViz; - var hVisible = partial ? lViz || rViz : lViz && rViz; - - return vVisible && hVisible; - } - - return visibleInViewport; -}); diff --git a/src/scripts/site.js b/src/scripts/site.js index 5d5062c394..0583c5c676 100644 --- a/src/scripts/site.js +++ b/src/scripts/site.js @@ -646,7 +646,6 @@ var AppInfo = {}; medialibraryeditor: componentsPath + "/medialibraryeditor/medialibraryeditor", imageoptionseditor: componentsPath + "/imageoptionseditor/imageoptionseditor", apphost: componentsPath + "/apphost", - visibleinviewport: bowerPath + "/visibleinviewport", qualityoptions: componentsPath + "/qualityoptions", focusManager: componentsPath + "/focusManager", itemHelper: componentsPath + "/itemhelper", From 331341884bfc4709ad781e938b45576dcd1b7ec5 Mon Sep 17 00:00:00 2001 From: MrTimscampi Date: Fri, 1 May 2020 15:11:47 +0200 Subject: [PATCH 24/28] Remove console warning --- src/components/images/imageLoader.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/images/imageLoader.js b/src/components/images/imageLoader.js index 1254f71167..a3114f783c 100644 --- a/src/components/images/imageLoader.js +++ b/src/components/images/imageLoader.js @@ -45,7 +45,6 @@ import 'css!./style'; elem.setAttribute("src", url); } - console.warn(userSettings.enableFastFadein()); if (userSettings.enableFastFadein()) { elem.classList.add('lazy-image-fadein-fast'); } else { From 370a01f4afc33a99ea204403fc118b737db40947 Mon Sep 17 00:00:00 2001 From: MrTimscampi Date: Fri, 1 May 2020 16:13:46 +0200 Subject: [PATCH 25/28] Only load mediaSessions if available or if NativeShell --- src/scripts/site.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/scripts/site.js b/src/scripts/site.js index f861824797..e33cf25d6f 100644 --- a/src/scripts/site.js +++ b/src/scripts/site.js @@ -576,7 +576,10 @@ var AppInfo = {}; require(["components/playback/volumeosd"]); } - require(["mediaSession", "serverNotifications"]); + if (navigator.mediaSession || window.NativeShell) { + require(["mediaSession"]); + } + require(["serverNotifications"]); require(["date-fns", "date-fns/locale"]); if (!browser.tv && !browser.xboxOne) { From a7fe19832934e3a029fe7ce01355a8fba77353b4 Mon Sep 17 00:00:00 2001 From: MrTimscampi Date: Fri, 1 May 2020 17:06:50 +0200 Subject: [PATCH 26/28] Attempt to fix image loading issues --- src/components/images/imageLoader.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/images/imageLoader.js b/src/components/images/imageLoader.js index a3114f783c..52c65b85f0 100644 --- a/src/components/images/imageLoader.js +++ b/src/components/images/imageLoader.js @@ -23,7 +23,7 @@ import 'css!./style'; source = entry; } - if (entry.intersectionRatio > 0 && source) { + if (entry.intersectionRatio > 0) { fillImageElement(entry.target, source); } else if (!source) { emptyImageElement(entry.target); From 28f575755b18f8db864cdc768a3fe1f5f0b4703d Mon Sep 17 00:00:00 2001 From: MrTimscampi Date: Sat, 2 May 2020 19:44:27 +0200 Subject: [PATCH 27/28] Add check for source when loading images --- src/components/images/imageLoader.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/images/imageLoader.js b/src/components/images/imageLoader.js index 52c65b85f0..69ad01b606 100644 --- a/src/components/images/imageLoader.js +++ b/src/components/images/imageLoader.js @@ -24,7 +24,7 @@ import 'css!./style'; } if (entry.intersectionRatio > 0) { - fillImageElement(entry.target, source); + if (source) fillImageElement(entry.target, source); } else if (!source) { emptyImageElement(entry.target); } From 1e4dd8ec93a157f5222cb94f202327aa487f3b78 Mon Sep 17 00:00:00 2001 From: MrTimscampi Date: Thu, 7 May 2020 11:02:47 +0200 Subject: [PATCH 28/28] Remove lazyloader-scroll --- .../lazyloader/lazyloader-scroll.js | 185 ------------------ 1 file changed, 185 deletions(-) delete mode 100644 src/components/lazyloader/lazyloader-scroll.js diff --git a/src/components/lazyloader/lazyloader-scroll.js b/src/components/lazyloader/lazyloader-scroll.js deleted file mode 100644 index 2704c0f7be..0000000000 --- a/src/components/lazyloader/lazyloader-scroll.js +++ /dev/null @@ -1,185 +0,0 @@ -define(['visibleinviewport', 'dom', 'browser'], function (visibleinviewport, dom, browser) { - 'use strict'; - - var thresholdX; - var thresholdY; - - function resetThresholds() { - - var threshold = 0.3; - - thresholdX = screen.availWidth * threshold; - thresholdY = screen.availHeight * threshold; - } - - function resetThresholdsOnTimer() { - - setTimeout(resetThresholds, 500); - } - - if (browser.iOS) { - dom.addEventListener(window, 'orientationchange', resetThresholdsOnTimer, { passive: true }); - dom.addEventListener(window, 'resize', resetThresholdsOnTimer, { passive: true }); - } else { - dom.addEventListener(window, 'orientationchange', resetThresholds, { passive: true }); - dom.addEventListener(window, 'resize', resetThresholds, { passive: true }); - } - resetThresholds(); - - function isVisible(elem) { - return visibleinviewport(elem, true, thresholdX, thresholdY); - } - - var wheelEvent = (document.implementation.hasFeature('Event.wheel', '3.0') ? 'wheel' : 'mousewheel'); - var self = {}; - - function cancelAll(tokens) { - for (var i = 0, length = tokens.length; i < length; i++) { - - tokens[i] = true; - } - } - - function unveilElementsInternal(instance, callback) { - - var unveiledElements = []; - var cancellationTokens = []; - var loadedCount = 0; - - function unveilInternal(tokenIndex) { - - var anyFound = false; - var out = false; - - var elements = instance.elements; - // TODO: This out construct assumes left to right, top to bottom - - for (var i = 0, length = elements.length; i < length; i++) { - - if (cancellationTokens[tokenIndex]) { - return; - } - if (unveiledElements[i]) { - continue; - } - var elem = elements[i]; - if (!out && isVisible(elem)) { - anyFound = true; - unveiledElements[i] = true; - callback(elem); - loadedCount++; - } else { - - if (anyFound) { - out = true; - } - } - } - - if (loadedCount >= elements.length) { - dom.removeEventListener(document, 'focus', unveil, { - capture: true, - passive: true - }); - dom.removeEventListener(document, 'scroll', unveil, { - capture: true, - passive: true - }); - dom.removeEventListener(document, wheelEvent, unveil, { - capture: true, - passive: true - }); - dom.removeEventListener(window, 'resize', unveil, { - capture: true, - passive: true - }); - } - } - - function unveil() { - - cancelAll(cancellationTokens); - - var index = cancellationTokens.length; - cancellationTokens.length++; - - setTimeout(function () { - unveilInternal(index); - }, 1); - } - - dom.addEventListener(document, 'focus', unveil, { - capture: true, - passive: true - }); - dom.addEventListener(document, 'scroll', unveil, { - capture: true, - passive: true - }); - dom.addEventListener(document, wheelEvent, unveil, { - capture: true, - passive: true - }); - dom.addEventListener(window, 'resize', unveil, { - capture: true, - passive: true - }); - - unveil(); - } - - function LazyLoader(options) { - - this.options = options; - } - - LazyLoader.prototype.createObserver = function () { - - unveilElementsInternal(this, this.options.callback); - this.observer = 1; - }; - - LazyLoader.prototype.addElements = function (elements) { - - this.elements = this.elements || []; - - for (var i = 0, length = elements.length; i < length; i++) { - this.elements.push(elements[i]); - } - - var observer = this.observer; - - if (!observer) { - this.createObserver(); - } - - }; - - LazyLoader.prototype.destroyObserver = function (elements) { - - }; - - LazyLoader.prototype.destroy = function (elements) { - - this.destroyObserver(); - this.options = null; - }; - - function unveilElements(elements, root, callback) { - - if (!elements.length) { - return; - } - var lazyLoader = new LazyLoader({ - callback: callback - }); - lazyLoader.addElements(elements); - } - - LazyLoader.lazyChildren = function (elem, callback) { - - unveilElements(elem.getElementsByClassName('lazy'), elem, callback); - }; - - return LazyLoader; -});