From c23547137d5b89bf5f90ce3791c6443e968273ad Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Wed, 9 Sep 2015 13:49:44 -0400 Subject: [PATCH] update sync processes --- dashboard-ui/apiclient/alt/ajax.js | 126 ----------------- dashboard-ui/apiclient/apiclient.js | 128 +++++++++++++----- dashboard-ui/apiclient/connectionmanager.js | 20 ++- .../apiclient/sync/contentuploader.js | 55 ++++++++ .../apiclient/sync/multiserversync.js | 58 ++++++++ dashboard-ui/apiclient/sync/serversync.js | 64 +++++++++ .../iron-behaviors/.bower.json | 6 +- .../iron-flex-layout/.bower.json | 6 +- .../bower_components/paper-slider/.bower.json | 8 +- .../bower_components/paper-slider/bower.json | 2 +- .../paper-slider/paper-slider.css | 2 +- .../cordova/android/androidcredentials.js | 111 --------------- dashboard-ui/cordova/localassetmanager.js | 11 ++ dashboard-ui/css/librarybrowser.css | 4 +- dashboard-ui/css/librarymenu.css | 5 + dashboard-ui/scripts/mediaplayer-video.js | 20 ++- dashboard-ui/scripts/mediaplayer.js | 26 ++-- dashboard-ui/scripts/site.js | 24 +++- dashboard-ui/tvproviders/schedulesdirect.js | 50 +++---- 19 files changed, 400 insertions(+), 326 deletions(-) delete mode 100644 dashboard-ui/apiclient/alt/ajax.js create mode 100644 dashboard-ui/apiclient/sync/contentuploader.js create mode 100644 dashboard-ui/apiclient/sync/multiserversync.js create mode 100644 dashboard-ui/apiclient/sync/serversync.js create mode 100644 dashboard-ui/cordova/localassetmanager.js diff --git a/dashboard-ui/apiclient/alt/ajax.js b/dashboard-ui/apiclient/alt/ajax.js deleted file mode 100644 index 43f47bc5d5..0000000000 --- a/dashboard-ui/apiclient/alt/ajax.js +++ /dev/null @@ -1,126 +0,0 @@ -(function (globalScope, angular) { - - globalScope.HttpClient = { - - param: function(params) { - return serialize(params); - }, - - send: function(options) { - var request = getAngularRequest(options), - defer = globalScope.DeferredBuilder.Deferred(); - - request.then(function(results) { - defer.resolve(results.data); - }, function() { - defer.reject(); - }); - - return defer.promise(); - } - - }; - - // Code from: http://stackoverflow.com/questions/1714786/querystring-encoding-of-a-javascript-object - function serialize (obj, prefix) { - var str = []; - for(var p in obj) { - if (obj.hasOwnProperty(p)) { - var k = prefix ? prefix + "[" + p + "]" : p, v = obj[p]; - str.push(typeof v == "object" ? - serialize(v, k) : - encodeURIComponent(k) + "=" + encodeURIComponent(v)); - } - } - return str.join("&"); - } - - var $http = angular.injector(['ng']).get('$http'); - - function getAngularRequest(jParams) { - var optionTransforms = [], - promiseTransforms = [], - options = {}, - // paramMap houses the param transforms in one of the following formats: - // string - This means there is a direct mapping from jQuery option to Angular option, but allows for a different option name - // function - This means some logic is required in applying this option to the Angular request. Functions should add functions - // to the optionTransforms or promiseTransforms arrays, which will be executed after direct mappings are complete. - paramMap = { - 'accepts': undefined, - 'async': undefined, - 'beforeSend': undefined, - 'cache': undefined, - 'complete': undefined, - 'contents': undefined, - 'contentType': function(val) { - optionTransforms.push(function(opt) { - opt.headers = opt.headers || {}; - opt.headers['Content-Type'] = val; - return opt; - }); - }, - 'context': undefined, - 'converters': undefined, - 'crossDomain': undefined, - 'data': 'data', - 'dataFilter': undefined, - 'dataType': 'responseType', - 'error': undefined, - 'global': undefined, - 'headers': 'headers', - 'ifModified': undefined, - 'isLocal': undefined, - 'jsonp': undefined, - 'jsonpCallback': undefined, - 'mimeType': undefined, - 'password': undefined, - 'processData': undefined, - 'scriptCharset': undefined, - 'statusCode': undefined, - 'success': undefined, - 'timeout': 'timeout', - 'traditional': undefined, - 'type': 'method', - 'url': 'url', - 'username': undefined, - 'xhr': undefined, - 'xhrFields': undefined, - }; - - // Iterate through each key in the jQuery format options object - for (var key in jParams) { - if (!paramMap[key]) { - // This parameter hasn't been implemented in the paramMap object - Logger.log('ERROR: ajax option property "' + key + '" not implemented by HttpClient.'); - continue; - } - - if (typeof paramMap[key] === 'string') { - // Direct mapping between two properties - options[paramMap[key]] = jParams[key]; - continue; - } - - if (typeof paramMap[key] === 'function') { - // Extra logic required. Execute the function with the jQuery option as the only function argument - paramMap[key](jParams[key]); - } - } - - // Iterate through any optionTransforms functions and execute them with the options object as argument - while (optionTransforms.length > 0) { - options = optionTransforms.pop()(options); - } - - // Create the Angular http request (returns the request's promise object) - var promise = $http(options); - - // Iterate through any promiseTransforms functions and execute them with the promise as argument. - while (promiseTransforms.length > 0) { - promiseTransforms.pop()(promise); - } - - return promise; - } - -})(window, angular); \ No newline at end of file diff --git a/dashboard-ui/apiclient/apiclient.js b/dashboard-ui/apiclient/apiclient.js index 865e626739..9ca03640b4 100644 --- a/dashboard-ui/apiclient/apiclient.js +++ b/dashboard-ui/apiclient/apiclient.js @@ -533,7 +533,7 @@ } else { // If that produced a fairly high speed, try again with a larger size to get a more accurate result - self.getDownloadSpeed(3000000).done(function (bitrate) { + self.getDownloadSpeed(2400000).done(function (bitrate) { deferred.resolveWith(null, [Math.round(bitrate * .8)]); @@ -1587,6 +1587,36 @@ }); }; + /** + * Gets the current server configuration + */ + self.getDevicesOptions = function () { + + var url = self.getUrl("System/Configuration/devices"); + + return self.ajax({ + type: "GET", + url: url, + dataType: "json" + }); + }; + + /** + * Gets the current server configuration + */ + self.getContentUploadHistory = function () { + + var url = self.getUrl("Devices/CameraUploads", { + DeviceId: self.deviceId() + }); + + return self.ajax({ + type: "GET", + url: url, + dataType: "json" + }); + }; + self.getNamedConfiguration = function (name) { var url = self.getUrl("System/Configuration/" + name); @@ -2538,29 +2568,31 @@ var url = self.getUrl("Users/authenticatebyname"); - var postData = { - password: CryptoJS.SHA1(password || "").toString(), - Username: name - }; + require(["cryptojs-sha1"], function () { + var postData = { + password: CryptoJS.SHA1(password || "").toString(), + Username: name + }; - self.ajax({ - type: "POST", - url: url, - data: JSON.stringify(postData), - dataType: "json", - contentType: "application/json" + self.ajax({ + type: "POST", + url: url, + data: JSON.stringify(postData), + dataType: "json", + contentType: "application/json" - }).done(function (result) { + }).done(function (result) { - if (self.onAuthenticated) { - self.onAuthenticated(self, result); - } + if (self.onAuthenticated) { + self.onAuthenticated(self, result); + } - deferred.resolveWith(null, [result]); + deferred.resolveWith(null, [result]); - }).fail(function () { + }).fail(function () { - deferred.reject(); + deferred.reject(); + }); }); return deferred.promise(); @@ -2574,20 +2606,35 @@ */ self.updateUserPassword = function (userId, currentPassword, newPassword) { + var deferred = DeferredBuilder.Deferred(); + if (!userId) { - throw new Error("null userId"); + deferred.reject(); + return deferred.promise(); } var url = self.getUrl("Users/" + userId + "/Password"); - return self.ajax({ - type: "POST", - url: url, - data: { - currentPassword: CryptoJS.SHA1(currentPassword).toString(), - newPassword: CryptoJS.SHA1(newPassword).toString() - } + require(["cryptojs-sha1"], function () { + + self.ajax({ + type: "POST", + url: url, + data: { + currentPassword: CryptoJS.SHA1(currentPassword).toString(), + newPassword: CryptoJS.SHA1(newPassword).toString() + } + }).done(function (result) { + + deferred.resolveWith(null, [result]); + + }).fail(function () { + + deferred.reject(); + }); }); + + return deferred.promise(); }; /** @@ -2597,19 +2644,34 @@ */ self.updateEasyPassword = function (userId, newPassword) { + var deferred = DeferredBuilder.Deferred(); + if (!userId) { - throw new Error("null userId"); + deferred.reject(); + return deferred.promise(); } var url = self.getUrl("Users/" + userId + "/EasyPassword"); - return self.ajax({ - type: "POST", - url: url, - data: { - newPassword: CryptoJS.SHA1(newPassword).toString() - } + require(["cryptojs-sha1"], function () { + + self.ajax({ + type: "POST", + url: url, + data: { + newPassword: CryptoJS.SHA1(newPassword).toString() + } + }).done(function (result) { + + deferred.resolveWith(null, [result]); + + }).fail(function () { + + deferred.reject(); + }); }); + + return deferred.promise(); }; /** diff --git a/dashboard-ui/apiclient/connectionmanager.js b/dashboard-ui/apiclient/connectionmanager.js index 9c261cbc9e..c16bd64caa 100644 --- a/dashboard-ui/apiclient/connectionmanager.js +++ b/dashboard-ui/apiclient/connectionmanager.js @@ -126,6 +126,17 @@ return credentialProvider.credentials().ConnectAccessToken; }; + self.getServerInfo = function (id) { + + var servers = credentialProvider.credentials().Servers; + + return servers.filter(function () { + + return s.Id == id; + + })[0]; + }; + self.getLastUsedServer = function () { var servers = credentialProvider.credentials().Servers; @@ -287,7 +298,9 @@ var server = servers.length ? servers[0] : apiClient.serverInfo(); - server.DateLastAccessed = new Date().getTime(); + if (options.updateDateLastAccessed !== false) { + server.DateLastAccessed = new Date().getTime(); + } server.Id = result.ServerId; if (saveCredentials) { @@ -879,6 +892,7 @@ var wakeOnLanSendTime = new Date().getTime(); + options = options || {}; testNextConnectionMode(tests, 0, server, wakeOnLanSendTime, options, deferred); return deferred.promise(); @@ -987,7 +1001,9 @@ updateServerInfo(server, systemInfo); - server.DateLastAccessed = new Date().getTime(); + if (options.updateDateLastAccessed !== false) { + server.DateLastAccessed = new Date().getTime(); + } server.LastConnectionMode = connectionMode; credentialProvider.addOrUpdateServer(credentials.Servers, server); credentialProvider.credentials(credentials); diff --git a/dashboard-ui/apiclient/sync/contentuploader.js b/dashboard-ui/apiclient/sync/contentuploader.js new file mode 100644 index 0000000000..e1aeddf69b --- /dev/null +++ b/dashboard-ui/apiclient/sync/contentuploader.js @@ -0,0 +1,55 @@ +(function (globalScope) { + + function contentUploader(connectionManager) { + + self.uploadImages = function (server) { + + var deferred = DeferredBuilder.Deferred(); + + var apiClient = self.getApiClient(server.Id); + + apiClient.getDevicesOptions().done(function (devicesOptions) { + + if (!devicesOptions.EnabledCameraUploadDevices || devicesOptions.EnabledCameraUploadDevices.indexOf(apiClient.deviceId()) == -1) { + Logger.log("Camera upload is not enabled for this device."); + deferred.reject(); + } + else { + uploadImagesInternal(server, apiClient, deferred); + } + + }).fail(function () { + deferred.reject(); + }); + + return deferred.promise(); + }; + + function uploadImagesInternal(server, apiClient, deferred) { + + apiClient.getContentUploadHistory().done(function (result) { + + uploadImagesWithHistory(server, result, apiClient, deferred); + + }).fail(function () { + deferred.reject(); + }); + } + + function uploadImagesWithHistory(server, uploadHistory, apiClient, deferred) { + + require(['localassetmanager'], function () { + + // TODO: Mimic java version of ContentUploader.UploadImagesInternal + deferred.resolve(); + }); + } + } + + if (!globalScope.MediaBrowser) { + globalScope.MediaBrowser = {}; + } + + globalScope.MediaBrowser.ContentUploader = contentUploader; + +})(this); \ No newline at end of file diff --git a/dashboard-ui/apiclient/sync/multiserversync.js b/dashboard-ui/apiclient/sync/multiserversync.js new file mode 100644 index 0000000000..16ec513f39 --- /dev/null +++ b/dashboard-ui/apiclient/sync/multiserversync.js @@ -0,0 +1,58 @@ +(function (globalScope) { + + function multiServerSync(connectionManager) { + + self.sync = function () { + + var deferred = DeferredBuilder.Deferred(); + + connectionManager.getAvailableServers().done(function (result) { + syncNext(result, 0, deferred); + }); + + return deferred.promise(); + }; + + function syncNext(servers, index, deferred) { + + var length = servers.length; + + if (index >= length) { + + deferred.resolve(); + return; + } + + if (progress.isCancelled) { + deferred.reject(); + return; + } + + var server = servers[index]; + + // get fresh info from connection manager + server = connectionManager.getServerInfo(server.Id) || server; + + Logger.log("Creating ServerSync to server: " + server.Id); + + require(['serversync'], function () { + + new MediaBrowser.ServerSync(connectionManager).sync(server).done(function () { + + syncNext(servers, index + 1, deferred); + + }).fail(function () { + + syncNext(servers, index + 1, deferred); + }); + }); + } + } + + if (!globalScope.MediaBrowser) { + globalScope.MediaBrowser = {}; + } + + globalScope.MediaBrowser.MultiServerSync = multiServerSync; + +})(this); \ No newline at end of file diff --git a/dashboard-ui/apiclient/sync/serversync.js b/dashboard-ui/apiclient/sync/serversync.js new file mode 100644 index 0000000000..9352f416e6 --- /dev/null +++ b/dashboard-ui/apiclient/sync/serversync.js @@ -0,0 +1,64 @@ +(function (globalScope) { + + function serverSync(connectionManager) { + + self.sync = function (server) { + + var deferred = DeferredBuilder.Deferred(); + + if (!server.AccessToken && !server.ExchangeToken) { + + Logger.log('Skipping sync to server ' + server.Id + ' because there is no saved authentication information.'); + deferred.resolve(); + return; + } + + var connectionOptions = { + updateDateLastAccessed: false, + enableWebSocket: false, + reportCapabilities: false + }; + + connectionManager.connectToServer(server, connectionOptions).done(function (result) { + + if (result.State == MediaBrowser.ConnectionState.SignedIn) { + performSync(server, deferred); + } else { + Logger.log('Unable to connect to server id: ' + server.Id); + deferred.reject(); + } + + }).fail(function () { + + Logger.log('Unable to connect to server id: ' + server.Id); + deferred.reject(); + }); + + return deferred.promise(); + }; + + function performSync(server, deferred) { + + Logger.log("Creating ContentUploader to server: " + server.Id); + + require(['contentuploader'], function () { + + new MediaBrowser.ContentUploader(connectionManager).uploadImages(server).done(function () { + + deferred.resolve(); + + }).fail(function () { + + deferred.resolve(); + }); + }); + } + } + + if (!globalScope.MediaBrowser) { + globalScope.MediaBrowser = {}; + } + + globalScope.MediaBrowser.ServerSync = serverSync; + +})(this); \ No newline at end of file diff --git a/dashboard-ui/bower_components/iron-behaviors/.bower.json b/dashboard-ui/bower_components/iron-behaviors/.bower.json index 5d7b926afb..f499351883 100644 --- a/dashboard-ui/bower_components/iron-behaviors/.bower.json +++ b/dashboard-ui/bower_components/iron-behaviors/.bower.json @@ -27,14 +27,14 @@ "web-component-tester": "*", "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0" }, - "homepage": "https://github.com/polymerelements/iron-behaviors", + "homepage": "https://github.com/PolymerElements/iron-behaviors", "_release": "1.0.8", "_resolution": { "type": "version", "tag": "v1.0.8", "commit": "663ad706b43989f4961d945b8116cf4db346532f" }, - "_source": "git://github.com/polymerelements/iron-behaviors.git", + "_source": "git://github.com/PolymerElements/iron-behaviors.git", "_target": "^1.0.0", - "_originalSource": "polymerelements/iron-behaviors" + "_originalSource": "PolymerElements/iron-behaviors" } \ No newline at end of file diff --git a/dashboard-ui/bower_components/iron-flex-layout/.bower.json b/dashboard-ui/bower_components/iron-flex-layout/.bower.json index 90b7b9e929..6533803466 100644 --- a/dashboard-ui/bower_components/iron-flex-layout/.bower.json +++ b/dashboard-ui/bower_components/iron-flex-layout/.bower.json @@ -23,14 +23,14 @@ "paper-styles": "polymerelements/paper-styles#^1.0.0", "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0" }, - "homepage": "https://github.com/polymerelements/iron-flex-layout", + "homepage": "https://github.com/PolymerElements/iron-flex-layout", "_release": "1.0.3", "_resolution": { "type": "version", "tag": "v1.0.3", "commit": "e6c2cfec18354973ac03e70dcd8afcc3c72d09b9" }, - "_source": "git://github.com/polymerelements/iron-flex-layout.git", + "_source": "git://github.com/PolymerElements/iron-flex-layout.git", "_target": "^1.0.0", - "_originalSource": "polymerelements/iron-flex-layout" + "_originalSource": "PolymerElements/iron-flex-layout" } \ No newline at end of file diff --git a/dashboard-ui/bower_components/paper-slider/.bower.json b/dashboard-ui/bower_components/paper-slider/.bower.json index 31116d71ac..74ed6d845c 100644 --- a/dashboard-ui/bower_components/paper-slider/.bower.json +++ b/dashboard-ui/bower_components/paper-slider/.bower.json @@ -1,6 +1,6 @@ { "name": "paper-slider", - "version": "1.0.4", + "version": "1.0.5", "description": "A material design-style slider", "license": "http://polymer.github.io/LICENSE.txt", "authors": "The Polymer Authors", @@ -37,11 +37,11 @@ "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0" }, "homepage": "https://github.com/PolymerElements/paper-slider", - "_release": "1.0.4", + "_release": "1.0.5", "_resolution": { "type": "version", - "tag": "v1.0.4", - "commit": "e1307d8323c2f91a3f2a514c210b4d7dd498e3ac" + "tag": "v1.0.5", + "commit": "8672cf9466fe8387f04ef5065ea83a4a18f8b06d" }, "_source": "git://github.com/PolymerElements/paper-slider.git", "_target": "~1.0.3", diff --git a/dashboard-ui/bower_components/paper-slider/bower.json b/dashboard-ui/bower_components/paper-slider/bower.json index 162b87abbd..8143d6bf70 100644 --- a/dashboard-ui/bower_components/paper-slider/bower.json +++ b/dashboard-ui/bower_components/paper-slider/bower.json @@ -1,6 +1,6 @@ { "name": "paper-slider", - "version": "1.0.4", + "version": "1.0.5", "description": "A material design-style slider", "license": "http://polymer.github.io/LICENSE.txt", "authors": "The Polymer Authors", diff --git a/dashboard-ui/bower_components/paper-slider/paper-slider.css b/dashboard-ui/bower_components/paper-slider/paper-slider.css index d8282c38ed..4091230f5d 100644 --- a/dashboard-ui/bower_components/paper-slider/paper-slider.css +++ b/dashboard-ui/bower_components/paper-slider/paper-slider.css @@ -79,11 +79,11 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN position: absolute; top: 15px; left: 0; - height: 2px; width: 100%; padding: 8px 0; margin: -8px 0; background-color: var(--paper-slider-bar-color, transparent); + --paper-progress-height: 2px; } .ring #sliderBar { diff --git a/dashboard-ui/cordova/android/androidcredentials.js b/dashboard-ui/cordova/android/androidcredentials.js index 24ef6f2439..6b3decf4ef 100644 --- a/dashboard-ui/cordova/android/androidcredentials.js +++ b/dashboard-ui/cordova/android/androidcredentials.js @@ -26,109 +26,6 @@ var capabilities = ConnectionManager.capabilities(); ApiClientBridge.init(AppInfo.appName, AppInfo.appVersion, AppInfo.deviceId, AppInfo.deviceName, JSON.stringify(capabilities)); - - initAjax(); - } - - var baseAjaxMethod; - var currentId = 0; - function getNewRequestId() { - var id = currentId++; - return id.toString(); - } - function initAjax() { - baseAjaxMethod = HttpClient.send; - HttpClient.send = sendRequest; - } - - function sendRequest(request) { - - // For now, we can only handle json responses - if (request.dataType) { - if (request.dataType != 'json') { - return baseAjaxMethod(request); - } - } - - if (request.data) { - // For now, we can only handle request bodies that are strings - if (typeof (request.data) != 'string') { - return baseAjaxMethod(request); - } - } - - var deferred = DeferredBuilder.Deferred(); - - var id = getNewRequestId(); - - request.headers = request.headers || {}; - - if (request.dataType == 'json') { - request.headers.accept = 'application/json'; - } - - var method = request.type || "GET"; - - var javaRequest = { - Method: method, - Url: request.url, - RequestHeaders: request.headers - }; - - if (request.timeout) { - javaRequest.Timeout = request.timeout; - } - - if (request.data) { - javaRequest.RequestContent = request.data; - } - - if (request.contentType) { - javaRequest.RequestContentType = request.contentType; - } - - Logger.log("Sending request: " + JSON.stringify(javaRequest)); - - ApiClientBridge.sendRequest(JSON.stringify(javaRequest), request.dataType, id); - - Events.on(AndroidAjax, 'response' + id, function (e, isSuccess, response) { - - Events.off(AndroidAjax, 'response' + id); - - if (isSuccess) { - - if (response) { - deferred.resolveWith(null, [response]); - } else { - deferred.resolve(); - } - } - else { - - // Need to mimic the jquery ajax error response - deferred.rejectWith(request, [getErrorResponse(response)]); - } - - }); - - return deferred.promise(); - } - - function getErrorResponse(response) { - - var error = {}; - - if (response.StatusCode) { - error.status = response.StatusCode; - } - - error.ResponseHeaders = response.ResponseHeaders || {}; - - error.getResponseHeader = function (name) { - return error.ResponseHeaders[name]; - }; - - return error; } function getDownloadSpeed(bytes, url) { @@ -181,14 +78,6 @@ window.AndroidAjax = { - onResponse: function (id, response) { - - Events.trigger(AndroidAjax, 'response' + id, [true, response]); - }, - onError: function (id, response) { - - Events.trigger(AndroidAjax, 'response' + id, [false, response]); - }, onDownloadSpeedResponse: function (response) { Events.trigger(AndroidAjax, 'downloadspeedresponse', [response]); diff --git a/dashboard-ui/cordova/localassetmanager.js b/dashboard-ui/cordova/localassetmanager.js new file mode 100644 index 0000000000..749e5286f3 --- /dev/null +++ b/dashboard-ui/cordova/localassetmanager.js @@ -0,0 +1,11 @@ +(function () { + + function getLocalMediaSource(serverId, itemId) { + return null; + } + + window.LocalAssetManager = { + getLocalMediaSource: getLocalMediaSource + }; + +})(); \ No newline at end of file diff --git a/dashboard-ui/css/librarybrowser.css b/dashboard-ui/css/librarybrowser.css index 5ef8fa33f4..1f74bb03e1 100644 --- a/dashboard-ui/css/librarybrowser.css +++ b/dashboard-ui/css/librarybrowser.css @@ -1549,7 +1549,7 @@ span.itemCommunityRating:not(:empty) + .userDataIcons { width: 80px; height: 80px; background-repeat: no-repeat; - background-size: cover; + background-size: contain; background-position: center center; } @@ -1557,7 +1557,7 @@ span.itemCommunityRating:not(:empty) + .userDataIcons { width: 70px; height: 70px; background-repeat: no-repeat; - background-size: cover; + background-size: contain; background-position: center center; } diff --git a/dashboard-ui/css/librarymenu.css b/dashboard-ui/css/librarymenu.css index 36fe44f07f..57fcb3512d 100644 --- a/dashboard-ui/css/librarymenu.css +++ b/dashboard-ui/css/librarymenu.css @@ -193,6 +193,11 @@ -webkit-overflow-scrolling: touch; } + .libraryViewNav::-webkit-scrollbar { + height: 0 !important; + display: none; + } + .libraryViewNavWithMinHeight { min-height: 48px; } diff --git a/dashboard-ui/scripts/mediaplayer-video.js b/dashboard-ui/scripts/mediaplayer-video.js index bf1a5a512d..32f8da39d3 100644 --- a/dashboard-ui/scripts/mediaplayer-video.js +++ b/dashboard-ui/scripts/mediaplayer-video.js @@ -568,11 +568,24 @@ return html; } + function getSeekableDuration() { + + if (self.currentMediaSource && self.currentMediaSource.RunTimeTicks) { + return self.currentMediaSource.RunTimeTicks; + } + + if (self.currentMediaRenderer) { + return self.getCurrentTicks(self.currentMediaRenderer); + } + + return null; + } + function onPositionSliderChange() { var newPercent = parseInt(this.value); - var newPositionTicks = (newPercent / 100) * self.currentMediaSource.RunTimeTicks; + var newPositionTicks = (newPercent / 100) * getSeekableDuration(); self.changeStream(Math.floor(newPositionTicks)); } @@ -718,12 +731,13 @@ positionSlider._setPinValue = function (value) { - if (!self.currentMediaSource || !self.currentMediaSource.RunTimeTicks) { + var seekableDuration = getSeekableDuration(); + if (!self.currentMediaSource || !seekableDuration) { this.pinValue = '--:--'; return; } - var ticks = self.currentMediaSource.RunTimeTicks; + var ticks = seekableDuration; ticks /= 100; ticks *= value; diff --git a/dashboard-ui/scripts/mediaplayer.js b/dashboard-ui/scripts/mediaplayer.js index ab883ed1ba..a8e09d0898 100644 --- a/dashboard-ui/scripts/mediaplayer.js +++ b/dashboard-ui/scripts/mediaplayer.js @@ -503,9 +503,14 @@ self.updateCanClientSeek = function (mediaRenderer) { - var duration = mediaRenderer.duration(); + var currentSrc = self.getCurrentSrc(mediaRenderer); - canClientSeek = duration && !isNaN(duration) && duration != Number.POSITIVE_INFINITY && duration != Number.NEGATIVE_INFINITY; + if ((currentSrc || '').indexOf('.m3u8') != -1) { + canClientSeek = true; + } else { + var duration = mediaRenderer.duration(); + canClientSeek = duration && !isNaN(duration) && duration != Number.POSITIVE_INFINITY && duration != Number.NEGATIVE_INFINITY; + } }; self.getCurrentSrc = function (mediaRenderer) { @@ -709,6 +714,7 @@ ticks = Math.floor(ticks); var timeText = Dashboard.getDisplayTime(ticks); + var mediaRenderer = self.currentMediaRenderer; if (self.currentDurationTicks) { @@ -719,22 +725,20 @@ var percent = ticks / self.currentDurationTicks; percent *= 100; - positionSlider.disabled = false; positionSlider.value = percent; } - } else { + } - if (positionSlider) { + if (positionSlider) { - positionSlider.disabled = true; - } + positionSlider.disabled = !canClientSeek; } if (currentTimeElement) { currentTimeElement.html(timeText); } - var state = self.getPlayerStateInternal(self.currentMediaRenderer, self.currentItem, self.currentMediaSource); + var state = self.getPlayerStateInternal(mediaRenderer, self.currentItem, self.currentMediaSource); Events.trigger(self, 'positionchange', [state]); }; @@ -1552,6 +1556,8 @@ PlayState: {} }; + var currentSrc = mediaRenderer ? mediaRenderer.currentSrc() : null; + if (mediaRenderer) { state.PlayState.VolumeLevel = mediaRenderer.volume() * 100; @@ -1560,8 +1566,6 @@ state.PlayState.PositionTicks = self.getCurrentTicks(mediaRenderer); state.PlayState.RepeatMode = self.getRepeatMode(); - var currentSrc = mediaRenderer.currentSrc(); - if (currentSrc) { var audioStreamIndex = getParameterByName('AudioStreamIndex', currentSrc); @@ -1588,7 +1592,7 @@ RunTimeTicks: mediaSource.RunTimeTicks }; - state.PlayState.CanSeek = mediaSource.RunTimeTicks && mediaSource.RunTimeTicks > 0; + state.PlayState.CanSeek = (mediaSource.RunTimeTicks || 0) > 0 || canClientSeek; } if (item) { diff --git a/dashboard-ui/scripts/site.js b/dashboard-ui/scripts/site.js index fe1465c0fc..09d51a5b7d 100644 --- a/dashboard-ui/scripts/site.js +++ b/dashboard-ui/scripts/site.js @@ -1763,7 +1763,6 @@ var AppInfo = {}; AppInfo.enableUserImage = true; AppInfo.hasPhysicalVolumeButtons = isCordova || isMobile; - AppInfo.hasPhysicalVolumeButtons = true; AppInfo.enableBackButton = isIOS && (window.navigator.standalone || AppInfo.isNativeApp); AppInfo.supportsFullScreen = isCordova && isAndroid; @@ -2009,6 +2008,8 @@ var AppInfo = {}; if (Dashboard.isRunningInCordova() && $.browser.android) { define("localassetmanager", ["cordova/android/localassetmanager"]); + } else if (Dashboard.isRunningInCordova()) { + define("localassetmanager", ["cordova/localassetmanager"]); } else { define("localassetmanager", ["apiclient/localassetmanager"]); } @@ -2135,7 +2136,26 @@ var AppInfo = {}; return Hammer; }); - $.extend(AppInfo, Dashboard.getAppInfo(appName, deviceId, deviceName)); + define("cryptojs-sha1", ["apiclient/sha1"]); + + define("contentuploader", ["apiclient/contentuploader"]); + define("serversync", ["apiclient/serversync"]); + define("multiserversync", ["apiclient/multiserversync"]); + + var deps = []; + + if (!deviceId) { + deps.push('cryptojs-sha1'); + } + + require(deps, function () { + $.extend(AppInfo, Dashboard.getAppInfo(appName, deviceId, deviceName)); + + initAfterDependencies(deferred, capabilities); + }); + } + + function initAfterDependencies(deferred, capabilities) { var drawer = document.querySelector('.mainDrawerPanel'); drawer.classList.remove('mainDrawerPanelPreInit'); diff --git a/dashboard-ui/tvproviders/schedulesdirect.js b/dashboard-ui/tvproviders/schedulesdirect.js index 37c62316f4..9ecd3478af 100644 --- a/dashboard-ui/tvproviders/schedulesdirect.js +++ b/dashboard-ui/tvproviders/schedulesdirect.js @@ -80,38 +80,40 @@ Dashboard.showLoadingMsg(); - var info = { - Type: 'SchedulesDirect', - Username: page.querySelector('.txtUser').value, - Password: CryptoJS.SHA1(page.querySelector('.txtPass').value).toString() - }; + require(["cryptojs-sha1"], function () { - var id = providerId; + var info = { + Type: 'SchedulesDirect', + Username: page.querySelector('.txtUser').value, + Password: CryptoJS.SHA1(page.querySelector('.txtPass').value).toString() + }; - if (id) { - info.Id = id; - } + var id = providerId; - ApiClient.ajax({ - type: "POST", - url: ApiClient.getUrl('LiveTv/ListingProviders', { - ValidateLogin: true - }), - data: JSON.stringify(info), - contentType: "application/json" + if (id) { + info.Id = id; + } - }).done(function (result) { + ApiClient.ajax({ + type: "POST", + url: ApiClient.getUrl('LiveTv/ListingProviders', { + ValidateLogin: true + }), + data: JSON.stringify(info), + contentType: "application/json" - Dashboard.processServerConfigurationUpdateResult(); - providerId = result.Id; - reload(); + }).done(function (result) { - }).fail(function () { - Dashboard.alert({ - message: Globalize.translate('ErrorSavingTvProvider') + Dashboard.processServerConfigurationUpdateResult(); + providerId = result.Id; + reload(); + + }).fail(function () { + Dashboard.alert({ + message: Globalize.translate('ErrorSavingTvProvider') + }); }); }); - } function submitListingsForm() {