diff --git a/dashboard-ui/bower_components/emby-webcomponents/cardbuilder/card.css b/dashboard-ui/bower_components/emby-webcomponents/cardbuilder/card.css index 2f596b3424..7bb9d4f511 100644 --- a/dashboard-ui/bower_components/emby-webcomponents/cardbuilder/card.css +++ b/dashboard-ui/bower_components/emby-webcomponents/cardbuilder/card.css @@ -237,7 +237,7 @@ } .cardText { - padding: .35em .5em; + padding: .25em .5em; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; diff --git a/dashboard-ui/css/mediaplayer-video.css b/dashboard-ui/css/mediaplayer-video.css index 4d57cad8ee..39c44be1a5 100644 --- a/dashboard-ui/css/mediaplayer-video.css +++ b/dashboard-ui/css/mediaplayer-video.css @@ -167,6 +167,10 @@ overflow-x: auto; } +.tabScenes, .tabCast { + display: flex; +} + #videoPlayer .nowPlayingText { font-weight: normal; margin: 0 0 0 1em; @@ -186,6 +190,7 @@ .videoNowPlayingOverview, .videoNowPlayingRating { margin: 1em 0; + display: flex; } .videoTopControlsLogo { diff --git a/dashboard-ui/css/nowplayingbar.css b/dashboard-ui/css/nowplayingbar.css index 150d755261..cd3069903d 100644 --- a/dashboard-ui/css/nowplayingbar.css +++ b/dashboard-ui/css/nowplayingbar.css @@ -11,11 +11,6 @@ max-width: 130px; } -.mediaButton.infoButton { - width: 34px; - height: 34px; -} - .mediaButton.active { color: #52B54B; } diff --git a/dashboard-ui/livetvseriestimer.html b/dashboard-ui/livetvseriestimer.html index 3bf58d862d..d3b736bb5d 100644 --- a/dashboard-ui/livetvseriestimer.html +++ b/dashboard-ui/livetvseriestimer.html @@ -18,7 +18,16 @@
-
+ +

${HeaderSchedule}

+
+ +
${WillRecord}
+ +
${NotScheduledToRecord}
+
+
+
diff --git a/dashboard-ui/scripts/livetvcomponents.js b/dashboard-ui/scripts/livetvcomponents.js index bb2b8e8f8d..f70e03f397 100644 --- a/dashboard-ui/scripts/livetvcomponents.js +++ b/dashboard-ui/scripts/livetvcomponents.js @@ -8,6 +8,101 @@ return enableScrollX() ? 'overflowBackdrop' : 'backdrop'; } + function getProgramScheduleHtml(items, options) { + + options = options || {}; + + var groups = []; + + var currentGroupName = ''; + var currentGroup = []; + + var i, length; + + for (i = 0, length = items.length; i < length; i++) { + + var item = items[i]; + + var dateText = ''; + + if (options.indexByDate !== false && item.StartDate) { + try { + + var premiereDate = datetime.parseISO8601Date(item.StartDate, true); + + dateText = LibraryBrowser.getFutureDateText(premiereDate, true); + + } catch (err) { + } + } + + if (dateText != currentGroupName) { + + if (currentGroup.length) { + groups.push({ + name: currentGroupName, + items: currentGroup + }); + } + + currentGroupName = dateText; + currentGroup = [item]; + } else { + currentGroup.push(item); + } + } + + if (currentGroup.length) { + groups.push({ + name: currentGroupName, + items: currentGroup + }); + } + + var html = ''; + + for (i = 0, length = groups.length; i < length; i++) { + + var group = groups[i]; + + if (group.name) { + html += '
'; + + html += '

' + group.name + '

'; + } + + if (enableScrollX()) { + html += '
'; + } else { + html += '
'; + } + + html += cardBuilder.getCardsHtml({ + items: group.items, + shape: getBackdropShape(), + preferThumb: true, + showTitle: true, + showAirTime: true, + showAirEndTime: true, + showChannelName: true, + cardLayout: true, + action: 'programdialog', + cardFooterAside: 'none', + preferThumb: true, + coverImage: true, + overlayText: false + + }); + html += '
'; + + if (group.name) { + html += '
'; + } + } + + return Promise.resolve(html); + } + function getTimersHtml(timers, options) { options = options || {}; @@ -109,29 +204,8 @@ window.LiveTvHelpers = { - getDaysOfWeek: function () { - - var days = [ - 'Sunday', - 'Monday', - 'Tuesday', - 'Wednesday', - 'Thursday', - 'Friday', - 'Saturday' - ]; - - return days.map(function (d) { - - return { - name: d, - value: d - }; - - }); - }, - - getTimersHtml: getTimersHtml + getTimersHtml: getTimersHtml, + getProgramScheduleHtml: getProgramScheduleHtml }; }); \ No newline at end of file diff --git a/dashboard-ui/scripts/livetvseriestimer.js b/dashboard-ui/scripts/livetvseriestimer.js index ab29c4a0ca..82b4f685d2 100644 --- a/dashboard-ui/scripts/livetvseriestimer.js +++ b/dashboard-ui/scripts/livetvseriestimer.js @@ -9,17 +9,38 @@ Dashboard.hideLoadingMsg(); } - function renderSchedule(page, result) { + function renderSchedule(page) { - var timers = result.Items; + ApiClient.getLiveTvPrograms({ + UserId: ApiClient.getCurrentUserId(), + ImageTypeLimit: 1, + EnableImageTypes: "Primary,Backdrop,Thumb", + SortBy: "StartDate", + EnableTotalRecordCount: false, + EnableUserData: false, + SeriesTimerId: params.id, + Fields: "ChannelInfo" - LiveTvHelpers.getTimersHtml(timers).then(function (html) { + }).then(function (result) { - var scheduleTab = page.querySelector('.scheduleTab'); - scheduleTab.innerHTML = html; + LiveTvHelpers.getProgramScheduleHtml(result.Items).then(function (html) { - ImageLoader.lazyChildren(scheduleTab); + var scheduleTab = page.querySelector('.scheduleTab'); + scheduleTab.innerHTML = html; + + ImageLoader.lazyChildren(scheduleTab); + }); }); + + //var timers = result.Items; + + //LiveTvHelpers.getTimersHtml(timers).then(function (html) { + + // var scheduleTab = page.querySelector('.scheduleTab'); + // scheduleTab.innerHTML = html; + + // ImageLoader.lazyChildren(scheduleTab); + //}); } function reload() { @@ -33,15 +54,7 @@ }); - ApiClient.getLiveTvTimers({ - - seriesTimerId: id - - }).then(function (timerResult) { - - renderSchedule(view, timerResult); - - }); + renderSchedule(view); } seriesRecordingEditor.embed(params.id, ApiClient.serverId(), { diff --git a/dashboard-ui/scripts/livetvsuggested.js b/dashboard-ui/scripts/livetvsuggested.js index 59a60ae3ce..38992c60a8 100644 --- a/dashboard-ui/scripts/livetvsuggested.js +++ b/dashboard-ui/scripts/livetvsuggested.js @@ -1,4 +1,4 @@ -define(['libraryBrowser', 'cardBuilder', 'scrollStyles', 'emby-itemscontainer', 'emby-tabs', 'emby-button'], function (libraryBrowser, cardBuilder) { +define(['libraryBrowser', 'cardBuilder', 'dom', 'scrollStyles', 'emby-itemscontainer', 'emby-tabs', 'emby-button'], function (libraryBrowser, cardBuilder, dom) { function enableScrollX() { return browserInfo.mobile && AppInfo.enableAppLayouts; @@ -29,6 +29,7 @@ limit: limit, ImageTypeLimit: 1, EnableImageTypes: "Primary,Thumb,Backdrop", + EnableTotalRecordCount: false, Fields: "ChannelInfo" }).then(function (result) { diff --git a/dashboard-ui/scripts/mediacontroller.js b/dashboard-ui/scripts/mediacontroller.js index 02adea5deb..5a22b41e98 100644 --- a/dashboard-ui/scripts/mediacontroller.js +++ b/dashboard-ui/scripts/mediacontroller.js @@ -376,19 +376,19 @@ if (playerInfo.supportedCommands.indexOf('EndSession') != -1) { - var menuItems = []; - - menuItems.push({ - name: Globalize.translate('ButtonYes'), - id: 'yes' - }); - menuItems.push({ - name: Globalize.translate('ButtonNo'), - id: 'no' - }); - require(['dialog'], function (dialog) { + var menuItems = []; + + menuItems.push({ + name: Globalize.translate('ButtonYes'), + id: 'yes' + }); + menuItems.push({ + name: Globalize.translate('ButtonNo'), + id: 'no' + }); + dialog({ buttons: menuItems, //positionTo: positionTo, diff --git a/dashboard-ui/scripts/mediaplayer-video.js b/dashboard-ui/scripts/mediaplayer-video.js index e64eb61a9b..ba3b9e2b46 100644 --- a/dashboard-ui/scripts/mediaplayer-video.js +++ b/dashboard-ui/scripts/mediaplayer-video.js @@ -413,7 +413,24 @@ var elem = mediaControls.querySelector('.nowPlayingTabs'); elem.innerHTML = getNowPlayingTabsHtml(item.CurrentProgram || item); - ImageLoader.lazyChildren(elem); + + var tabCast = elem.querySelector('.tabCast'); + if (tabCast) { + require(['peoplecardbuilder'], function (peoplecardbuilder) { + + peoplecardbuilder.buildPeopleCards((item.CurrentProgram || item).People || [], { + itemsContainer: tabCast, + coverImage: true, + serverId: ApiClient.serverId(), + width: 160, + shape: 'portrait' + }); + ImageLoader.lazyChildren(elem); + }); + } + else { + ImageLoader.lazyChildren(elem); + } function onTabButtonClick() { if (!this.classList.contains('selectedNowPlayingTabButton')) { @@ -540,55 +557,6 @@ if (item.People && item.People.length) { html += '
'; - html += item.People.map(function (cast) { - - var personHtml = '
'; - - var imgUrl; - var height = 150; - - if (cast.PrimaryImageTag) { - - imgUrl = ApiClient.getScaledImageUrl(cast.Id, { - height: height, - tag: cast.PrimaryImageTag, - type: "primary", - minScale: 2 - }); - - personHtml += '
'; - } else { - - imgUrl = "css/images/items/list/person.png"; - personHtml += '
'; - } - - personHtml += '
'; - - personHtml += '

' + cast.Name + '

'; - - var role = cast.Role ? Globalize.translate('ValueAsRole', cast.Role) : cast.Type; - - if (role == "GuestStar") { - role = Globalize.translate('ValueGuestStar'); - } - - role = role || ""; - - var maxlength = 40; - - if (role.length > maxlength) { - role = role.substring(0, maxlength - 3) + '...'; - } - - personHtml += '

' + role + '

'; - - personHtml += '
'; - - personHtml += '
'; - return personHtml; - - }).join(''); html += '
'; } diff --git a/dashboard-ui/scripts/mediaplayer.js b/dashboard-ui/scripts/mediaplayer.js index cbe5c6e7bf..21a875f147 100644 --- a/dashboard-ui/scripts/mediaplayer.js +++ b/dashboard-ui/scripts/mediaplayer.js @@ -146,6 +146,25 @@ define(['appSettings', 'userSettings', 'appStorage', 'datetime'], function (appS return window.MediaSource != null; }; + function getProfileOptions(item) { + + var disableVideoAudioCodecs = []; + if (!AppInfo.isNativeApp && !item.RunTimeTicks) { + disableVideoAudioCodecs.push('ac3'); + } + + var options = {}; + + if (!AppInfo.isNativeApp) { + options.enableMkvProgressive = item.RunTimeTicks != null; + options.enableTsProgressive = item.RunTimeTicks != null; + options.enableHls = !browserInfo.firefox || item.RunTimeTicks == null; + options.disableVideoAudioCodecs = disableVideoAudioCodecs; + } + + return options; + } + self.changeStream = function (ticks, params) { var mediaRenderer = self.currentMediaRenderer; @@ -163,19 +182,7 @@ define(['appSettings', 'userSettings', 'appStorage', 'datetime'], function (appS var playSessionId = getParameterByName('PlaySessionId', currentSrc); var liveStreamId = getParameterByName('LiveStreamId', currentSrc); - var disableVideoAudioCodecs = []; - if (!AppInfo.isNativeApp && !self.currentMediaSource.RunTimeTicks) { - disableVideoAudioCodecs.push('ac3'); - } - - Dashboard.getDeviceProfile(null, { - - enableMkvProgressive: self.currentMediaSource.RunTimeTicks != null, - enableTsProgressive: self.currentMediaSource.RunTimeTicks != null, - enableHls: !browserInfo.firefox || self.currentMediaSource.RunTimeTicks == null, - disableVideoAudioCodecs: disableVideoAudioCodecs - - }).then(function (deviceProfile) { + Dashboard.getDeviceProfile(null, getProfileOptions(self.currentMediaSource)).then(function (deviceProfile) { var audioStreamIndex = params.AudioStreamIndex == null ? (getParameterByName('AudioStreamIndex', currentSrc) || null) : params.AudioStreamIndex; if (typeof (audioStreamIndex) == 'string') { @@ -683,19 +690,7 @@ define(['appSettings', 'userSettings', 'appStorage', 'datetime'], function (appS var onBitrateDetected = function () { - var disableVideoAudioCodecs = []; - - if (!AppInfo.isNativeApp && !item.RunTimeTicks) { - disableVideoAudioCodecs.push('ac3'); - } - - Dashboard.getDeviceProfile(null, { - - enableMkvProgressive: item.RunTimeTicks != null, - enableTsProgressive: item.RunTimeTicks != null, - disableVideoAudioCodecs: disableVideoAudioCodecs - - }).then(function (deviceProfile) { + Dashboard.getDeviceProfile(null, getProfileOptions(item)).then(function (deviceProfile) { playOnDeviceProfileCreated(deviceProfile, item, startPosition, callback); }); }; diff --git a/dashboard-ui/scripts/moviesrecommended.js b/dashboard-ui/scripts/moviesrecommended.js index 139ca6eb2e..f4dd17cf03 100644 --- a/dashboard-ui/scripts/moviesrecommended.js +++ b/dashboard-ui/scripts/moviesrecommended.js @@ -50,7 +50,7 @@ SortOrder: "Descending", IncludeItemTypes: "Movie", Filters: "IsResumable", - Limit: screenWidth >= 1920 ? 5 : (screenWidth >= 1600 ? 4 : 3), + Limit: screenWidth >= 1920 ? 5 : (screenWidth >= 1600 ? 5 : 3), Recursive: true, Fields: "PrimaryImageAspectRatio,MediaSourceCount,BasicSyncInfo", CollapseBoxSetItems: false, diff --git a/dashboard-ui/scripts/taskbutton.js b/dashboard-ui/scripts/taskbutton.js index add214ac57..8ce744e84a 100644 --- a/dashboard-ui/scripts/taskbutton.js +++ b/dashboard-ui/scripts/taskbutton.js @@ -1,4 +1,4 @@ -define(['appStorage', 'emby-button'], function (appStorage) { +define(['userSettings', 'emby-button'], function (userSettings) { return function (options) { @@ -77,32 +77,54 @@ function onButtonClick() { var button = this; - var id = button.getAttribute('data-taskid'); + var buttonTextElement = this.querySelector('span') || this; + var text = buttonTextElement.textContent || buttonTextElement.innerText; + var taskId = button.getAttribute('data-taskid'); var key = 'scheduledTaskButton' + options.taskKey; var expectedValue = new Date().getMonth() + '6'; - if (appStorage.getItem(key) == expectedValue) { - onScheduledTaskMessageConfirmed(id); + if (userSettings.get(key) == expectedValue) { + onScheduledTaskMessageConfirmed(taskId); } else { - var msg = Globalize.translate('ConfirmMessageScheduledTaskButton'); - msg += '
'; - msg += '
'; - msg += ''; - msg += '
'; + require(['dialog'], function (dialog) { - require(['confirm'], function (confirm) { + var msg = Globalize.translate('ConfirmMessageScheduledTaskButton'); - confirm({ + var menuItems = []; - title: Globalize.translate('HeaderConfirmation'), - html: msg, - text: Globalize.translate('ConfirmMessageScheduledTaskButton') + "\n\n" + Globalize.translate('ButtonScheduledTasks') + menuItems.push({ + name: text, + id: 'task' + }); + menuItems.push({ + name: Globalize.translate('ButtonScheduledTasks'), + id: 'tasks' + }); + menuItems.push({ + name: Globalize.translate('ButtonCancel'), + id: 'cancel' + }); - }).then(function () { - appStorage.setItem(key, expectedValue); - onScheduledTaskMessageConfirmed(id); + dialog({ + buttons: menuItems, + text: msg + + }).then(function (id) { + switch (id) { + + case 'task': + userSettings.set(key, expectedValue); + onScheduledTaskMessageConfirmed(taskId); + break; + case 'tasks': + userSettings.set(key, expectedValue); + Dashboard.navigate('scheduledtasks.html'); + break; + default: + break; + } }); }); @@ -161,7 +183,7 @@ Events.off(ApiClient, 'websocketopen', onSocketOpen); stopInterval(); - } else { + } else { button.addEventListener('click', onButtonClick); diff --git a/dashboard-ui/scripts/tvrecommended.js b/dashboard-ui/scripts/tvrecommended.js index 1f2ab1495f..8a5b2934da 100644 --- a/dashboard-ui/scripts/tvrecommended.js +++ b/dashboard-ui/scripts/tvrecommended.js @@ -1,4 +1,4 @@ -define(['libraryBrowser', 'components/categorysyncbuttons', 'cardBuilder', 'scrollStyles', 'emby-itemscontainer', 'emby-tabs', 'emby-button'], function (libraryBrowser, categorysyncbuttons, cardBuilder) { +define(['libraryBrowser', 'dom', 'components/categorysyncbuttons', 'cardBuilder', 'scrollStyles', 'emby-itemscontainer', 'emby-tabs', 'emby-button'], function (libraryBrowser, dom, categorysyncbuttons, cardBuilder) { return function (view, params) { @@ -62,7 +62,8 @@ var parentId = LibraryMenu.getTopParentId(); - var limit = 6; + var screenWidth = dom.getWindowSize().innerWidth; + var limit = screenWidth >= 1600 ? 5 : 6; var options = { diff --git a/dashboard-ui/strings/en-US.json b/dashboard-ui/strings/en-US.json index 2cc53f46fa..e6b9f5f51b 100644 --- a/dashboard-ui/strings/en-US.json +++ b/dashboard-ui/strings/en-US.json @@ -57,7 +57,6 @@ "HeaderAvailableServices": "Available Services", "MessageNoServicesInstalled": "No services are currently installed.", "HeaderToAccessPleaseEnterEasyPinCode": "To access, please enter your easy pin code", - "KidsModeAdultInstruction": "Click the lock icon in the bottom right to configure or leave kids mode. Your pin code will be required.", "ButtonConfigurePinCode": "Configure pin code", "RegisterWithPayPal": "Register with PayPal", "HeaderEnjoyDayTrial": "Enjoy a 14 Day Free Trial", @@ -1431,7 +1430,7 @@ "ButtonScheduledTasks": "Scheduled tasks", "MessageItemsAdded": "Items added", "HeaderSelectCertificatePath": "Select Certificate Path", - "ConfirmMessageScheduledTaskButton": "This operation normally runs automatically as a scheduled task and does not require any manual effort. To configure the scheduled task, see:", + "ConfirmMessageScheduledTaskButton": "This operation normally runs automatically as a scheduled task and does not require any manual effort. To configure the scheduled task, click Scheduled Tasks.", "HeaderSupporterBenefit": "An active Emby Premiere subscription provides additional benefits such as access to sync, premium plugins, internet channel content, and more. {0}Learn more{1}.", "HeaderWelcomeToProjectServerDashboard": "Welcome to the Emby Server Dashboard", "HeaderWelcomeToProjectWebClient": "Welcome to Emby", @@ -2141,5 +2140,7 @@ "HeaderUpcomingOnTV": "Upcoming On TV", "LabelOptionalNetworkPath": "(Optional) Shared network folder:", "LabelOptionalNetworkPathHelp": "If this folder is shared on your network, supplying the network share path can allow Emby apps on other devices to access media files directly.", - "ButtonPlayExternalPlayer": "Play with external player" + "ButtonPlayExternalPlayer": "Play with external player", + "WillRecord": "Will record", + "NotScheduledToRecord": "Not scheduled to record" }