mirror of
https://github.com/jellyfin/jellyfin-web
synced 2025-03-30 19:56:21 +00:00
update live stream management
This commit is contained in:
parent
170b720d0b
commit
04dda98be4
17 changed files with 159 additions and 94 deletions
|
@ -273,6 +273,7 @@ button {
|
|||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
color: inherit;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.singleCardText {
|
||||
|
|
|
@ -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 ? ('<div class="' + cardImageContainerClass + '">') : ('<div class="' + cardImageContainerClass + '">');
|
||||
cardImageContainerOpen = '<div class="' + cardImageContainerClass + '">';
|
||||
|
||||
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 += '<div class="cardText cardCenteredText">' + defaultName + '</div>';
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<div class="formDialogHeader formDialogHeader-clear" style="justify-content:center;">
|
||||
<h1 class="formDialogHeaderTitle" style="margin-left:0;margin-top: .5em;"></h1>
|
||||
<h1 class="formDialogHeaderTitle" style="margin-left:0;margin-top: .5em;padding: 0 1em;"></h1>
|
||||
</div>
|
||||
|
||||
<div class="formDialogContent smoothScrollY">
|
||||
|
|
|
@ -374,7 +374,7 @@
|
|||
return '<i class="md-icon programIcon seriesTimerIcon seriesTimerIcon-inactive"></i>';
|
||||
}
|
||||
|
||||
return '<i class="md-icon programIcon"></i>';
|
||||
return '<i class="md-icon programIcon timerIcon"></i>';
|
||||
}
|
||||
|
||||
function getChannelProgramsHtml(context, date, channel, programs, options) {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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,26 +498,21 @@ 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 () {
|
||||
|
||||
loading.show();
|
||||
|
||||
var promise = item.Type == 'SeriesTimer' ?
|
||||
apiClient.cancelLiveTvSeriesTimer(item.Id) :
|
||||
apiClient.cancelLiveTvTimer(item.Id);
|
||||
|
||||
promise.then(function () {
|
||||
|
||||
require(['toast'], function (toast) {
|
||||
toast(globalize.translate('sharedcomponents#RecordingCancelled'));
|
||||
});
|
||||
|
||||
loading.hide();
|
||||
recordingHelper.cancelTimerWithConfirmation(item.Id, item.ServerId).then(function() {
|
||||
getResolveFunction(resolve, command, true)();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function deleteSeriesTimer(apiClient, item, resolve, command) {
|
||||
|
||||
require(['recordingHelper'], function (recordingHelper) {
|
||||
|
||||
recordingHelper.cancelSeriesTimerWithConfirmation(item.Id, item.ServerId).then(function () {
|
||||
getResolveFunction(resolve, command, true)();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -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 || '');
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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
|
||||
};
|
||||
});
|
|
@ -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);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
});
|
||||
|
||||
|
|
|
@ -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');
|
||||
|
|
|
@ -36,7 +36,6 @@
|
|||
showTitle: true,
|
||||
cardLayout: true,
|
||||
vibrant: true,
|
||||
cardFooterAside: 'none',
|
||||
preferThumb: true,
|
||||
coverImage: true,
|
||||
overlayText: false,
|
||||
|
|
|
@ -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');
|
||||
});
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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.",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue