diff --git a/dashboard-ui/bower_components/emby-webcomponents/cardbuilder/card.css b/dashboard-ui/bower_components/emby-webcomponents/cardbuilder/card.css index b055fcc952..579af58d97 100644 --- a/dashboard-ui/bower_components/emby-webcomponents/cardbuilder/card.css +++ b/dashboard-ui/bower_components/emby-webcomponents/cardbuilder/card.css @@ -273,6 +273,7 @@ button { overflow: hidden; text-overflow: ellipsis; color: inherit; + text-align: left; } .singleCardText { diff --git a/dashboard-ui/bower_components/emby-webcomponents/cardbuilder/cardbuilder.js b/dashboard-ui/bower_components/emby-webcomponents/cardbuilder/cardbuilder.js index 94ba80f168..5426cb4e94 100644 --- a/dashboard-ui/bower_components/emby-webcomponents/cardbuilder/cardbuilder.js +++ b/dashboard-ui/bower_components/emby-webcomponents/cardbuilder/cardbuilder.js @@ -794,7 +794,7 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'mediaInfo } else { var parentTitle = item.SeriesName || item.Album || item.AlbumArtist || item.GameSystem || ""; - if (parentTitle || options.showParentTitle) { + if (parentTitle || showTitle) { lines.push(parentTitle); } } @@ -802,7 +802,12 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'mediaInfo } } - if (((showTitle || forceName) && !titleAdded) || (options.showParentTitleOrTitle && !lines.length)) { + var showMediaTitle = (showTitle && !titleAdded) || (options.showParentTitleOrTitle && !lines.length); + if (!showMediaTitle && showTitle && forceName && !titleAdded) { + showMediaTitle = true; + } + + if (showMediaTitle) { var name = options.showTitle === 'auto' && !item.IsFolder && item.MediaType === 'Photo' ? '' : itemHelper.getDisplayName(item); @@ -1267,7 +1272,7 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'mediaInfo } if (options.vibrant && imgUrl && !vibrantSwatch) { - cardImageContainerOpen = imgUrl ? ('
') : ('
'); + cardImageContainerOpen = '
'; var imgClass = 'cardImage cardImage-img lazy'; if (coveredImage) { @@ -1318,7 +1323,7 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'mediaInfo } if (!imgUrl) { - var defaultName = item.Type === 'Program' ? item.Name : itemHelper.getDisplayName(item); + var defaultName = item.Type === 'Program' || item.Type == 'Timer' || item.EpisodeTitle ? item.Name : itemHelper.getDisplayName(item); cardImageContainerOpen += '
' + defaultName + '
'; } diff --git a/dashboard-ui/bower_components/emby-webcomponents/dialog/dialog.template.html b/dashboard-ui/bower_components/emby-webcomponents/dialog/dialog.template.html index 96fc5ae5ed..7fa18c17ad 100644 --- a/dashboard-ui/bower_components/emby-webcomponents/dialog/dialog.template.html +++ b/dashboard-ui/bower_components/emby-webcomponents/dialog/dialog.template.html @@ -1,5 +1,5 @@ 
-

+

diff --git a/dashboard-ui/bower_components/emby-webcomponents/guide/guide.js b/dashboard-ui/bower_components/emby-webcomponents/guide/guide.js index a0c4187564..26cc3237f6 100644 --- a/dashboard-ui/bower_components/emby-webcomponents/guide/guide.js +++ b/dashboard-ui/bower_components/emby-webcomponents/guide/guide.js @@ -374,7 +374,7 @@ return ''; } - return ''; + return ''; } function getChannelProgramsHtml(context, date, channel, programs, options) { diff --git a/dashboard-ui/bower_components/emby-webcomponents/images/imagehelper.js b/dashboard-ui/bower_components/emby-webcomponents/images/imagehelper.js index 14972c29ff..accdea5740 100644 --- a/dashboard-ui/bower_components/emby-webcomponents/images/imagehelper.js +++ b/dashboard-ui/bower_components/emby-webcomponents/images/imagehelper.js @@ -52,9 +52,9 @@ define(['visibleinviewport', 'imageFetcher', 'layoutManager', 'events', 'browser imageFetcher.loadImage(elem, source).then(function () { - fillVibrant(elem, source); + var fillingVibrant = fillVibrant(elem, source); - if (enableFade && !layoutManager.tv && enableEffects !== false) { + if (enableFade && !layoutManager.tv && enableEffects !== false && !fillingVibrant) { fadeIn(elem); } @@ -66,30 +66,27 @@ define(['visibleinviewport', 'imageFetcher', 'layoutManager', 'events', 'browser function fillVibrant(img, url) { if (img.tagName != 'IMG') { - return; + return false; } var vibrantElement = img.getAttribute('data-vibrant'); if (!vibrantElement) { - return; + return false; } if (window.Vibrant) { fillVibrantOnLoaded(img, url, vibrantElement); - return; + return true; } require(['vibrant'], function () { fillVibrantOnLoaded(img, url, vibrantElement); }); + return true; } function fillVibrantOnLoaded(img, url, vibrantElement) { - if (img.tagName != 'IMG') { - return; - } - vibrantElement = document.getElementById(vibrantElement); if (!vibrantElement) { return; @@ -121,8 +118,7 @@ define(['visibleinviewport', 'imageFetcher', 'layoutManager', 'events', 'browser url = url.split('?')[0]; - console.log(url); - return 'vibrant3-' + url; + return 'vibrant5-' + url; } function getCachedVibrantInfo(url) { diff --git a/dashboard-ui/bower_components/emby-webcomponents/itemcontextmenu.js b/dashboard-ui/bower_components/emby-webcomponents/itemcontextmenu.js index 624b7ecffd..44e31c339e 100644 --- a/dashboard-ui/bower_components/emby-webcomponents/itemcontextmenu.js +++ b/dashboard-ui/bower_components/emby-webcomponents/itemcontextmenu.js @@ -29,13 +29,20 @@ define(['apphost', 'globalize', 'connectionManager', 'itemHelper', 'embyRouter', }); } - if ((item.Type == 'Timer') && user.Policy.EnableLiveTvManagement) { + if ((item.Type == 'Timer') && user.Policy.EnableLiveTvManagement && options.cancelTimer !== false) { commands.push({ name: globalize.translate('sharedcomponents#ButtonCancel'), id: 'canceltimer' }); } + if ((item.Type == 'SeriesTimer') && user.Policy.EnableLiveTvManagement && options.cancelTimer !== false) { + commands.push({ + name: globalize.translate('sharedcomponents#CancelSeries'), + id: 'cancelseriestimer' + }); + } + if (item.CanDelete) { if (item.Type == 'Playlist' || item.Type == 'BoxSet') { @@ -479,6 +486,9 @@ define(['apphost', 'globalize', 'connectionManager', 'itemHelper', 'embyRouter', case 'canceltimer': deleteTimer(apiClient, item, resolve, id); break; + case 'cancelseriestimer': + deleteSeriesTimer(apiClient, item, resolve, id); + break; default: reject(); break; @@ -488,25 +498,20 @@ define(['apphost', 'globalize', 'connectionManager', 'itemHelper', 'embyRouter', function deleteTimer(apiClient, item, resolve, command) { - require(['confirm'], function (confirm) { + require(['recordingHelper'], function (recordingHelper) { - confirm(globalize.translate('sharedcomponents#MessageConfirmRecordingCancellation'), globalize.translate('sharedcomponents#HeaderConfirmRecordingCancellation')).then(function () { + recordingHelper.cancelTimerWithConfirmation(item.Id, item.ServerId).then(function() { + getResolveFunction(resolve, command, true)(); + }); + }); + } - loading.show(); + function deleteSeriesTimer(apiClient, item, resolve, command) { - var promise = item.Type == 'SeriesTimer' ? - apiClient.cancelLiveTvSeriesTimer(item.Id) : - apiClient.cancelLiveTvTimer(item.Id); + require(['recordingHelper'], function (recordingHelper) { - promise.then(function () { - - require(['toast'], function (toast) { - toast(globalize.translate('sharedcomponents#RecordingCancelled')); - }); - - loading.hide(); - getResolveFunction(resolve, command, true)(); - }); + recordingHelper.cancelSeriesTimerWithConfirmation(item.Id, item.ServerId).then(function () { + getResolveFunction(resolve, command, true)(); }); }); } diff --git a/dashboard-ui/bower_components/emby-webcomponents/listview/listview.js b/dashboard-ui/bower_components/emby-webcomponents/listview/listview.js index a5db2d695c..ec5a8aa768 100644 --- a/dashboard-ui/bower_components/emby-webcomponents/listview/listview.js +++ b/dashboard-ui/bower_components/emby-webcomponents/listview/listview.js @@ -267,7 +267,7 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan textlines.push(datetime.getDisplayTime(datetime.parseISO8601Date(item.StartDate))); } - var parentTitle; + var parentTitle = null; if (options.showParentTitle) { if (item.Type == 'Episode') { @@ -287,8 +287,12 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan if (options.showParentTitle && options.parentTitleWithTitle) { - if (parentTitle && displayName) { - parentTitle += ' - ' + displayName; + if (displayName) { + + if (parentTitle) { + parentTitle += ' - '; + } + parentTitle = (parentTitle || '') + displayName; } textlines.push(parentTitle || ''); diff --git a/dashboard-ui/bower_components/emby-webcomponents/recordingcreator/recordingeditor.js b/dashboard-ui/bower_components/emby-webcomponents/recordingcreator/recordingeditor.js index a9e9b8fadc..7cf9fb0710 100644 --- a/dashboard-ui/bower_components/emby-webcomponents/recordingcreator/recordingeditor.js +++ b/dashboard-ui/bower_components/emby-webcomponents/recordingcreator/recordingeditor.js @@ -10,30 +10,9 @@ return new Promise(function (resolve, reject) { - require(['confirm'], function (confirm) { + require(['recordingHelper'], function (recordingHelper) { - confirm({ - - title: globalize.translate('sharedcomponents#HeaderConfirmRecordingCancellation'), - text: globalize.translate('sharedcomponents#MessageConfirmRecordingCancellation'), - confirmText: globalize.translate('sharedcomponents#HeaderCancelRecording'), - cancelText: globalize.translate('sharedcomponents#HeaderKeepRecording'), - primary: 'cancel' - - }).then(function () { - - loading.show(); - - apiClient.cancelLiveTvTimer(timerId).then(function () { - - require(['toast'], function (toast) { - toast(globalize.translate('sharedcomponents#RecordingCancelled')); - }); - - loading.hide(); - resolve(); - }); - }); + recordingHelper.cancelTimerWithConfirmation(timerId, apiClient.serverId()).then(resolve, reject); }); }); } diff --git a/dashboard-ui/bower_components/emby-webcomponents/recordingcreator/recordinghelper.js b/dashboard-ui/bower_components/emby-webcomponents/recordingcreator/recordinghelper.js index 687118076b..60d17a95f0 100644 --- a/dashboard-ui/bower_components/emby-webcomponents/recordingcreator/recordinghelper.js +++ b/dashboard-ui/bower_components/emby-webcomponents/recordingcreator/recordinghelper.js @@ -25,6 +25,72 @@ }); } + function cancelTimerWithConfirmation(timerId, serverId) { + + return new Promise(function (resolve, reject) { + + require(['confirm'], function (confirm) { + + confirm({ + + text: globalize.translate('sharedcomponents#MessageConfirmRecordingCancellation'), + primary: 'cancel', + confirmText: globalize.translate('sharedcomponents#HeaderCancelRecording'), + cancelText: globalize.translate('sharedcomponents#HeaderKeepRecording') + + }).then(function () { + + loading.show(); + + var apiClient = connectionManager.getApiClient(serverId); + apiClient.cancelLiveTvTimer(timerId).then(function () { + + require(['toast'], function (toast) { + toast(globalize.translate('sharedcomponents#RecordingCancelled')); + }); + + loading.hide(); + resolve(); + }, reject); + + }, reject); + }); + }); + } + + function cancelSeriesTimerWithConfirmation(timerId, serverId) { + + return new Promise(function (resolve, reject) { + + require(['confirm'], function (confirm) { + + confirm({ + + text: globalize.translate('sharedcomponents#MessageConfirmRecordingCancellation'), + primary: 'cancel', + confirmText: globalize.translate('sharedcomponents#HeaderCancelSeries'), + cancelText: globalize.translate('sharedcomponents#HeaderKeepSeries') + + }).then(function () { + + loading.show(); + + var apiClient = connectionManager.getApiClient(serverId); + apiClient.cancelLiveTvSeriesTimer(timerId).then(function () { + + require(['toast'], function (toast) { + toast(globalize.translate('sharedcomponents#SeriesCancelled')); + }); + + loading.hide(); + resolve(); + }, reject); + + }, reject); + }); + }); + } + function cancelTimer(apiClient, timerId, hideLoading) { loading.show(); return apiClient.cancelLiveTvTimer(timerId).then(function () { @@ -88,6 +154,8 @@ cancelTimer: cancelTimer, createRecording: createRecording, changeRecordingToSeries: changeRecordingToSeries, - toggleRecording: toggleRecording + toggleRecording: toggleRecording, + cancelTimerWithConfirmation: cancelTimerWithConfirmation, + cancelSeriesTimerWithConfirmation: cancelSeriesTimerWithConfirmation }; }); \ No newline at end of file diff --git a/dashboard-ui/bower_components/emby-webcomponents/recordingcreator/seriesrecordingeditor.js b/dashboard-ui/bower_components/emby-webcomponents/recordingcreator/seriesrecordingeditor.js index a91d31a8c3..15e7fe6450 100644 --- a/dashboard-ui/bower_components/emby-webcomponents/recordingcreator/seriesrecordingeditor.js +++ b/dashboard-ui/bower_components/emby-webcomponents/recordingcreator/seriesrecordingeditor.js @@ -10,30 +10,9 @@ return new Promise(function (resolve, reject) { - require(['confirm'], function (confirm) { + require(['recordingHelper'], function (recordingHelper) { - confirm({ - - title: globalize.translate('sharedcomponents#HeaderConfirmRecordingCancellation'), - text: globalize.translate('sharedcomponents#MessageConfirmRecordingCancellation'), - confirmText: globalize.translate('sharedcomponents#HeaderCancelRecording'), - cancelText: globalize.translate('sharedcomponents#HeaderKeepRecording'), - primary: 'cancel' - - }).then(function () { - - loading.show(); - - apiClient.cancelLiveSeriesTvTimer(timerId).then(function () { - - require(['toast'], function (toast) { - toast(globalize.translate('sharedcomponents#RecordingCancelled')); - }); - - loading.hide(); - resolve(); - }); - }); + recordingHelper.cancelSeriesTimerWithConfirmation(timerId, apiClient.serverId()).then(resolve, reject); }); }); } diff --git a/dashboard-ui/css/nowplayingbar.css b/dashboard-ui/css/nowplayingbar.css index cd3069903d..b7055e0512 100644 --- a/dashboard-ui/css/nowplayingbar.css +++ b/dashboard-ui/css/nowplayingbar.css @@ -49,7 +49,6 @@ .nowPlayingBar { /* Above everything, except for the video player and popup overlays */ color: #fff; - background: #222326; text-align: center; /*box-shadow: 0 -2px 2px 0 rgba(0,0,0,.14),-1px 5px 1px rgba(0,0,0,.12);*/ will-change: transform; diff --git a/dashboard-ui/scripts/htmlmediarenderer.js b/dashboard-ui/scripts/htmlmediarenderer.js index 01961b710f..68ece16c01 100644 --- a/dashboard-ui/scripts/htmlmediarenderer.js +++ b/dashboard-ui/scripts/htmlmediarenderer.js @@ -424,6 +424,27 @@ hls.on(Hls.Events.MANIFEST_PARSED, function () { elem.play(); }); + + hls.on(Hls.Events.ERROR, function (event, data) { + if (data.fatal) { + switch (data.type) { + case Hls.ErrorTypes.NETWORK_ERROR: + // try to recover network error + console.log("fatal network error encountered, try to recover"); + hls.startLoad(); + break; + case Hls.ErrorTypes.MEDIA_ERROR: + console.log("fatal media error encountered, try to recover"); + hls.recoverMediaError(); + break; + default: + // cannot recover + hls.destroy(); + break; + } + } + }); + hlsPlayer = hls; }); diff --git a/dashboard-ui/scripts/livetvitems.js b/dashboard-ui/scripts/livetvitems.js index 79bef3bf34..06c2249ea1 100644 --- a/dashboard-ui/scripts/livetvitems.js +++ b/dashboard-ui/scripts/livetvitems.js @@ -1,4 +1,4 @@ -define(['cardBuilder', 'emby-itemscontainer'], function (cardBuilder) { +define(['cardBuilder', 'apphost', 'emby-itemscontainer'], function (cardBuilder, appHost) { return function (view, params) { @@ -56,6 +56,8 @@ page.querySelector('.listTopPaging').innerHTML = pagingHtml; + var supportsImageAnalysis = appHost.supports('imageanalysis') && (params.type == 'Recordings' || params.type == 'RecordingSeries'); + html = cardBuilder.getCardsHtml({ items: result.Items, shape: query.IsMovie || params.type == 'RecordingSeries' ? 'portrait' : "backdrop", @@ -71,9 +73,11 @@ showAirTime: params.type != 'Recordings' && params.type != 'RecordingSeries', showAirDateTime: params.type != 'Recordings' && params.type != 'RecordingSeries', showChannelName: params.type != 'Recordings' && params.type != 'RecordingSeries', - overlayMoreButton: true, + overlayMoreButton: !supportsImageAnalysis, showYear: query.IsMovie && params.type == 'Recordings', - coverImage: true + coverImage: true, + cardLayout: supportsImageAnalysis, + vibrant: supportsImageAnalysis }); var elem = page.querySelector('.itemsContainer'); diff --git a/dashboard-ui/scripts/livetvseriestimers.js b/dashboard-ui/scripts/livetvseriestimers.js index cea15b472d..7e75d11584 100644 --- a/dashboard-ui/scripts/livetvseriestimers.js +++ b/dashboard-ui/scripts/livetvseriestimers.js @@ -36,7 +36,6 @@ showTitle: true, cardLayout: true, vibrant: true, - cardFooterAside: 'none', preferThumb: true, coverImage: true, overlayText: false, diff --git a/dashboard-ui/scripts/notificationsetting.js b/dashboard-ui/scripts/notificationsetting.js index 745e359baa..e45601bc84 100644 --- a/dashboard-ui/scripts/notificationsetting.js +++ b/dashboard-ui/scripts/notificationsetting.js @@ -1,4 +1,4 @@ -define(['jQuery', 'emby-checkbox'], function ($) { +define(['jQuery', 'emby-checkbox', 'fnchecked'], function ($) { var notificationsConfigurationKey = "notifications"; @@ -153,6 +153,7 @@ ApiClient.updateNamedConfiguration(notificationsConfigurationKey, notificationOptions).then(function (r) { + Dashboard.processServerConfigurationUpdateResult(); Dashboard.navigate('notificationsettings.html'); }); diff --git a/dashboard-ui/scripts/tvstudios.js b/dashboard-ui/scripts/tvstudios.js index 8282c2b4ee..6c4a193d23 100644 --- a/dashboard-ui/scripts/tvstudios.js +++ b/dashboard-ui/scripts/tvstudios.js @@ -1,4 +1,4 @@ -define(['libraryBrowser', 'cardBuilder'], function (libraryBrowser, cardBuilder) { +define(['libraryBrowser', 'cardBuilder', 'apphost'], function (libraryBrowser, cardBuilder, appHost) { // The base query options var data = {}; @@ -43,15 +43,20 @@ promise.then(function (result) { var elem = context.querySelector('#items'); + + var supportsImageAnalysis = appHost.supports('imageanalysis'); + cardBuilder.buildCards(result.Items, { itemsContainer: elem, shape: "backdrop", preferThumb: true, - showTitle: false, + showTitle: supportsImageAnalysis, scalable: true, showItemCounts: true, - centerText: true, - overlayMoreButton: true + centerText: !supportsImageAnalysis, + overlayMoreButton: !supportsImageAnalysis, + cardLayout: supportsImageAnalysis, + vibrant: supportsImageAnalysis }); Dashboard.hideLoadingMsg(); diff --git a/dashboard-ui/strings/en-US.json b/dashboard-ui/strings/en-US.json index f27609da2e..b0aad1c3fa 100644 --- a/dashboard-ui/strings/en-US.json +++ b/dashboard-ui/strings/en-US.json @@ -618,7 +618,6 @@ "NotificationOptionTaskFailed": "Scheduled task failure", "NotificationOptionInstallationFailed": "Installation failure", "NotificationOptionNewLibraryContent": "New content added", - "NotificationOptionNewLibraryContentMultiple": "New content added (multiple)", "NotificationOptionCameraImageUploaded": "Camera image uploaded", "NotificationOptionUserLockedOut": "User locked out", "HeaderSendNotificationHelp": "Notifications are delivered to your Emby inbox. Additional options can be installed from the Services tab.",