';
}
function renderSeriesTimerSchedule(page, apiClient, seriesTimerId) {
apiClient.getLiveTvTimers({
UserId: apiClient.getCurrentUserId(),
ImageTypeLimit: 1,
EnableImageTypes: 'Primary,Backdrop,Thumb',
SortBy: 'StartDate',
EnableTotalRecordCount: false,
EnableUserData: false,
SeriesTimerId: seriesTimerId,
Fields: 'ChannelInfo,ChannelImage'
}).then(function (result) {
if (result.Items.length && result.Items[0].SeriesTimerId != seriesTimerId) {
result.Items = [];
}
var html = getProgramScheduleHtml(result.Items);
var scheduleTab = page.querySelector('.seriesTimerSchedule');
scheduleTab.innerHTML = html;
imageLoader.lazyChildren(scheduleTab);
});
}
function renderTimerEditor(page, item, apiClient, user) {
if ('Recording' !== item.Type || !user.Policy.EnableLiveTvManagement || !item.TimerId || 'InProgress' !== item.Status) {
return void hideAll(page, 'btnCancelTimer');
}
hideAll(page, 'btnCancelTimer', true);
}
function renderSeriesTimerEditor(page, item, apiClient, user) {
if ('SeriesTimer' !== item.Type) {
return void hideAll(page, 'btnCancelSeriesTimer');
}
if (user.Policy.EnableLiveTvManagement) {
require(['seriesRecordingEditor'], function (seriesRecordingEditor) {
seriesRecordingEditor.embed(item, apiClient.serverId(), {
context: page.querySelector('.seriesRecordingEditor')
});
});
page.querySelector('.seriesTimerScheduleSection').classList.remove('hide');
hideAll(page, 'btnCancelSeriesTimer', true);
return void renderSeriesTimerSchedule(page, apiClient, item.Id);
}
page.querySelector('.seriesTimerScheduleSection').classList.add('hide');
return void hideAll(page, 'btnCancelSeriesTimer');
}
function renderTrackSelections(page, instance, item, forceReload) {
var select = page.querySelector('.selectSource');
if (!item.MediaSources || !itemHelper.supportsMediaSourceSelection(item) || -1 === playbackManager.getSupportedCommands().indexOf('PlayMediaSource') || !playbackManager.canPlay(item)) {
page.querySelector('.trackSelections').classList.add('hide');
select.innerHTML = '';
page.querySelector('.selectVideo').innerHTML = '';
page.querySelector('.selectAudio').innerHTML = '';
page.querySelector('.selectSubtitles').innerHTML = '';
return;
}
var mediaSources = item.MediaSources;
instance._currentPlaybackMediaSources = mediaSources;
page.querySelector('.trackSelections').classList.remove('hide');
select.setLabel(globalize.translate('LabelVersion'));
var currentValue = select.value;
var selectedId = mediaSources[0].Id;
select.innerHTML = mediaSources.map(function (v) {
var selected = v.Id === selectedId ? ' selected' : '';
return '';
}).join('');
if (mediaSources.length > 1) {
page.querySelector('.selectSourceContainer').classList.remove('hide');
} else {
page.querySelector('.selectSourceContainer').classList.add('hide');
}
if (select.value !== currentValue || forceReload) {
renderVideoSelections(page, mediaSources);
renderAudioSelections(page, mediaSources);
renderSubtitleSelections(page, mediaSources);
}
}
function renderVideoSelections(page, mediaSources) {
var mediaSourceId = page.querySelector('.selectSource').value;
var mediaSource = mediaSources.filter(function (m) {
return m.Id === mediaSourceId;
})[0];
var tracks = mediaSource.MediaStreams.filter(function (m) {
return 'Video' === m.Type;
});
var select = page.querySelector('.selectVideo');
select.setLabel(globalize.translate('LabelVideo'));
var selectedId = tracks.length ? tracks[0].Index : -1;
select.innerHTML = tracks.map(function (v) {
var selected = v.Index === selectedId ? ' selected' : '';
var titleParts = [];
var resolutionText = mediaInfo.getResolutionText(v);
if (resolutionText) {
titleParts.push(resolutionText);
}
if (v.Codec) {
titleParts.push(v.Codec.toUpperCase());
}
return '';
}).join('');
select.setAttribute('disabled', 'disabled');
if (tracks.length) {
page.querySelector('.selectVideoContainer').classList.remove('hide');
} else {
page.querySelector('.selectVideoContainer').classList.add('hide');
}
}
function renderAudioSelections(page, mediaSources) {
var mediaSourceId = page.querySelector('.selectSource').value;
var mediaSource = mediaSources.filter(function (m) {
return m.Id === mediaSourceId;
})[0];
var tracks = mediaSource.MediaStreams.filter(function (m) {
return 'Audio' === m.Type;
});
var select = page.querySelector('.selectAudio');
select.setLabel(globalize.translate('LabelAudio'));
var selectedId = mediaSource.DefaultAudioStreamIndex;
select.innerHTML = tracks.map(function (v) {
var selected = v.Index === selectedId ? ' selected' : '';
return '';
}).join('');
if (tracks.length > 1) {
select.removeAttribute('disabled');
} else {
select.setAttribute('disabled', 'disabled');
}
if (tracks.length) {
page.querySelector('.selectAudioContainer').classList.remove('hide');
} else {
page.querySelector('.selectAudioContainer').classList.add('hide');
}
}
function renderSubtitleSelections(page, mediaSources) {
var mediaSourceId = page.querySelector('.selectSource').value;
var mediaSource = mediaSources.filter(function (m) {
return m.Id === mediaSourceId;
})[0];
var tracks = mediaSource.MediaStreams.filter(function (m) {
return 'Subtitle' === m.Type;
});
var select = page.querySelector('.selectSubtitles');
select.setLabel(globalize.translate('LabelSubtitles'));
var selectedId = null == mediaSource.DefaultSubtitleStreamIndex ? -1 : mediaSource.DefaultSubtitleStreamIndex;
if (tracks.length) {
var selected = -1 === selectedId ? ' selected' : '';
select.innerHTML = '' + tracks.map(function (v) {
selected = v.Index === selectedId ? ' selected' : '';
return '';
}).join('');
page.querySelector('.selectSubtitlesContainer').classList.remove('hide');
} else {
select.innerHTML = '';
page.querySelector('.selectSubtitlesContainer').classList.add('hide');
}
}
function reloadPlayButtons(page, item) {
var canPlay = false;
if ('Program' == item.Type) {
var now = new Date();
if (now >= datetime.parseISO8601Date(item.StartDate, true) && now < datetime.parseISO8601Date(item.EndDate, true)) {
hideAll(page, 'btnPlay', true);
canPlay = true;
} else {
hideAll(page, 'btnPlay');
}
hideAll(page, 'btnResume');
hideAll(page, 'btnInstantMix');
hideAll(page, 'btnShuffle');
} else if (playbackManager.canPlay(item)) {
hideAll(page, 'btnPlay', true);
var enableInstantMix = -1 !== ['Audio', 'MusicAlbum', 'MusicGenre', 'MusicArtist'].indexOf(item.Type);
hideAll(page, 'btnInstantMix', enableInstantMix);
var enableShuffle = item.IsFolder || -1 !== ['MusicAlbum', 'MusicGenre', 'MusicArtist'].indexOf(item.Type);
hideAll(page, 'btnShuffle', enableShuffle);
canPlay = true;
hideAll(page, 'btnResume', item.UserData && item.UserData.PlaybackPositionTicks > 0);
} else {
hideAll(page, 'btnPlay');
hideAll(page, 'btnResume');
hideAll(page, 'btnInstantMix');
hideAll(page, 'btnShuffle');
}
return canPlay;
}
function reloadUserDataButtons(page, item) {
var i;
var length;
var btnPlaystates = page.querySelectorAll('.btnPlaystate');
for (i = 0, length = btnPlaystates.length; i < length; i++) {
var btnPlaystate = btnPlaystates[i];
if (itemHelper.canMarkPlayed(item)) {
btnPlaystate.classList.remove('hide');
btnPlaystate.setItem(item);
} else {
btnPlaystate.classList.add('hide');
btnPlaystate.setItem(null);
}
}
var btnUserRatings = page.querySelectorAll('.btnUserRating');
for (i = 0, length = btnUserRatings.length; i < length; i++) {
var btnUserRating = btnUserRatings[i];
if (itemHelper.canRate(item)) {
btnUserRating.classList.remove('hide');
btnUserRating.setItem(item);
} else {
btnUserRating.classList.add('hide');
btnUserRating.setItem(null);
}
}
}
function getArtistLinksHtml(artists, serverId, context) {
var html = [];
for (var i = 0, length = artists.length; i < length; i++) {
var artist = artists[i];
var href = appRouter.getRouteUrl(artist, {
context: context,
itemType: 'MusicArtist',
serverId: serverId
});
html.push('' + artist.Name + '');
}
return html = html.join(' / ');
}
function renderName(item, container, isStatic, context) {
var parentRoute;
var parentNameHtml = [];
var parentNameLast = false;
if (item.AlbumArtists) {
parentNameHtml.push(getArtistLinksHtml(item.AlbumArtists, item.ServerId, context));
parentNameLast = true;
} else if (item.ArtistItems && item.ArtistItems.length && 'MusicVideo' === item.Type) {
parentNameHtml.push(getArtistLinksHtml(item.ArtistItems, item.ServerId, context));
parentNameLast = true;
} else if (item.SeriesName && 'Episode' === item.Type) {
parentRoute = appRouter.getRouteUrl({
Id: item.SeriesId,
Name: item.SeriesName,
Type: 'Series',
IsFolder: true,
ServerId: item.ServerId
}, {
context: context
});
parentNameHtml.push('' + item.SeriesName + '');
} else if (item.IsSeries || item.EpisodeTitle) {
parentNameHtml.push(item.Name);
}
if (item.SeriesName && 'Season' === item.Type) {
parentRoute = appRouter.getRouteUrl({
Id: item.SeriesId,
Name: item.SeriesName,
Type: 'Series',
IsFolder: true,
ServerId: item.ServerId
}, {
context: context
});
parentNameHtml.push('' + item.SeriesName + '');
} else if (null != item.ParentIndexNumber && 'Episode' === item.Type) {
parentRoute = appRouter.getRouteUrl({
Id: item.SeasonId,
Name: item.SeasonName,
Type: 'Season',
IsFolder: true,
ServerId: item.ServerId
}, {
context: context
});
parentNameHtml.push('' + item.SeasonName + '');
} else if (null != item.ParentIndexNumber && item.IsSeries) {
parentNameHtml.push(item.SeasonName || 'S' + item.ParentIndexNumber);
} else if (item.Album && item.AlbumId && ('MusicVideo' === item.Type || 'Audio' === item.Type)) {
parentRoute = appRouter.getRouteUrl({
Id: item.AlbumId,
Name: item.Album,
Type: 'MusicAlbum',
IsFolder: true,
ServerId: item.ServerId
}, {
context: context
});
parentNameHtml.push('' + item.Album + '');
} else if (item.Album) {
parentNameHtml.push(item.Album);
}
// FIXME: This whole section needs some refactoring, so it becames easier to scale across all form factors. See GH #1022
var html = '';
var tvShowHtml = parentNameHtml[0];
var tvSeasonHtml = parentNameHtml[1];
if (parentNameHtml.length) {
if (parentNameLast) {
// Music
if (layoutManager.mobile) {
html = '
' + parentNameHtml.join('') + '
';
} else {
html = '
' + parentNameHtml.join(' - ') + '
';
}
} else {
if (layoutManager.mobile) {
html = '
' + parentNameHtml.join('') + '
';
} else {
html = '
' + tvShowHtml + '
';
}
}
}
var name = itemHelper.getDisplayName(item, {
includeParentInfo: false
});
if (html && !parentNameLast) {
if (!layoutManager.mobile && tvSeasonHtml) {
html += '
' + tvSeasonHtml + ' - ' + name + '
';
} else {
html += '
' + name + '
';
}
} else {
html = '
' + name + '
' + html;
}
if (item.OriginalTitle && item.OriginalTitle != item.Name) {
html += '
' + item.OriginalTitle + '
';
}
container.innerHTML = html;
if (html.length) {
container.classList.remove('hide');
} else {
container.classList.add('hide');
}
}
function setTrailerButtonVisibility(page, item) {
if ((item.LocalTrailerCount || item.RemoteTrailers && item.RemoteTrailers.length) && -1 !== playbackManager.getSupportedCommands().indexOf('PlayTrailers')) {
hideAll(page, 'btnPlayTrailer', true);
} else {
hideAll(page, 'btnPlayTrailer');
}
}
function renderBackdrop(item) {
if (dom.getWindowSize().innerWidth >= 1000) {
backdrop.setBackdrops([item]);
} else {
backdrop.clearBackdrop();
}
}
function renderDetailPageBackdrop(page, item, apiClient) {
var imgUrl;
var hasbackdrop = false;
var itemBackdropElement = page.querySelector('#itemBackdrop');
var usePrimaryImage = item.MediaType === 'Video' && item.Type !== 'Movie' && item.Type !== 'Trailer' ||
item.MediaType && item.MediaType !== 'Video' ||
item.Type === 'MusicAlbum' ||
item.Type === 'Person';
if (!layoutManager.mobile && !userSettings.detailsBanner()) {
return false;
}
if ('Program' === item.Type && item.ImageTags && item.ImageTags.Thumb) {
imgUrl = apiClient.getScaledImageUrl(item.Id, {
type: 'Thumb',
maxWidth: dom.getScreenWidth(),
index: 0,
tag: item.ImageTags.Thumb
});
page.classList.remove('noBackdrop');
imageLoader.lazyImage(itemBackdropElement, imgUrl);
hasbackdrop = true;
} else if (usePrimaryImage && item.ImageTags && item.ImageTags.Primary) {
imgUrl = apiClient.getScaledImageUrl(item.Id, {
type: 'Primary',
maxWidth: dom.getScreenWidth(),
index: 0,
tag: item.ImageTags.Primary
});
page.classList.remove('noBackdrop');
imageLoader.lazyImage(itemBackdropElement, imgUrl);
hasbackdrop = true;
} else if (item.BackdropImageTags && item.BackdropImageTags.length) {
imgUrl = apiClient.getScaledImageUrl(item.Id, {
type: 'Backdrop',
maxWidth: dom.getScreenWidth(),
index: 0,
tag: item.BackdropImageTags[0]
});
page.classList.remove('noBackdrop');
imageLoader.lazyImage(itemBackdropElement, imgUrl);
hasbackdrop = true;
} else if (item.ParentBackdropItemId && item.ParentBackdropImageTags && item.ParentBackdropImageTags.length) {
imgUrl = apiClient.getScaledImageUrl(item.ParentBackdropItemId, {
type: 'Backdrop',
maxWidth: dom.getScreenWidth(),
index: 0,
tag: item.ParentBackdropImageTags[0]
});
page.classList.remove('noBackdrop');
imageLoader.lazyImage(itemBackdropElement, imgUrl);
hasbackdrop = true;
} else if (item.ImageTags && item.ImageTags.Thumb) {
imgUrl = apiClient.getScaledImageUrl(item.Id, {
type: 'Thumb',
maxWidth: dom.getScreenWidth(),
index: 0,
tag: item.ImageTags.Thumb
});
page.classList.remove('noBackdrop');
imageLoader.lazyImage(itemBackdropElement, imgUrl);
hasbackdrop = true;
} else {
itemBackdropElement.style.backgroundImage = '';
}
if ('Person' === item.Type) {
// FIXME: This hides the backdrop on all persons to fix a margin issue. Ideally, a proper fix should be made.
page.classList.add('noBackdrop');
itemBackdropElement.classList.add('personBackdrop');
} else {
itemBackdropElement.classList.remove('personBackdrop');
}
return hasbackdrop;
}
function reloadFromItem(instance, page, params, item, user) {
var context = params.context;
page.querySelector('.detailPagePrimaryContainer').classList.add('detailSticky');
renderName(item, page.querySelector('.nameContainer'), false, context);
var apiClient = connectionManager.getApiClient(item.ServerId);
renderSeriesTimerEditor(page, item, apiClient, user);
renderTimerEditor(page, item, apiClient, user);
renderImage(page, item, apiClient, user);
renderLogo(page, item, apiClient);
Emby.Page.setTitle('');
setInitialCollapsibleState(page, item, apiClient, context, user);
renderDetails(page, item, apiClient, context);
renderTrackSelections(page, instance, item);
renderBackdrop(item);
renderDetailPageBackdrop(page, item, apiClient);
var canPlay = reloadPlayButtons(page, item);
if ((item.LocalTrailerCount || item.RemoteTrailers && item.RemoteTrailers.length) && -1 !== playbackManager.getSupportedCommands().indexOf('PlayTrailers')) {
hideAll(page, 'btnPlayTrailer', true);
} else {
hideAll(page, 'btnPlayTrailer');
}
setTrailerButtonVisibility(page, item);
if (item.CanDelete && !item.IsFolder) {
hideAll(page, 'btnDeleteItem', true);
} else {
hideAll(page, 'btnDeleteItem');
}
if ('Program' !== item.Type || canPlay) {
hideAll(page, 'mainDetailButtons', true);
} else {
hideAll(page, 'mainDetailButtons');
}
showRecordingFields(instance, page, item, user);
var groupedVersions = (item.MediaSources || []).filter(function (g) {
return 'Grouping' == g.Type;
});
if (user.Policy.IsAdministrator && groupedVersions.length) {
page.querySelector('.btnSplitVersions').classList.remove('hide');
} else {
page.querySelector('.btnSplitVersions').classList.add('hide');
}
if (itemContextMenu.getCommands(getContextMenuOptions(item, user)).length) {
hideAll(page, 'btnMoreCommands', true);
} else {
hideAll(page, 'btnMoreCommands');
}
var itemBirthday = page.querySelector('#itemBirthday');
if ('Person' == item.Type && item.PremiereDate) {
try {
var birthday = datetime.parseISO8601Date(item.PremiereDate, true).toDateString();
itemBirthday.classList.remove('hide');
itemBirthday.innerHTML = globalize.translate('BirthDateValue', birthday);
} catch (err) {
itemBirthday.classList.add('hide');
}
} else {
itemBirthday.classList.add('hide');
}
var itemDeathDate = page.querySelector('#itemDeathDate');
if ('Person' == item.Type && item.EndDate) {
try {
var deathday = datetime.parseISO8601Date(item.EndDate, true).toDateString();
itemDeathDate.classList.remove('hide');
itemDeathDate.innerHTML = globalize.translate('DeathDateValue', deathday);
} catch (err) {
itemDeathDate.classList.add('hide');
}
} else {
itemDeathDate.classList.add('hide');
}
var itemBirthLocation = page.querySelector('#itemBirthLocation');
if ('Person' == item.Type && item.ProductionLocations && item.ProductionLocations.length) {
var gmap = '' + item.ProductionLocations[0] + '';
itemBirthLocation.classList.remove('hide');
itemBirthLocation.innerHTML = globalize.translate('BirthPlaceValue', gmap);
} else {
itemBirthLocation.classList.add('hide');
}
setPeopleHeader(page, item);
loading.hide();
if (item.Type === 'Book') {
hideAll(page, 'btnDownload', true);
}
require(['autoFocuser'], function (autoFocuser) {
autoFocuser.autoFocus(page);
});
}
function logoImageUrl(item, apiClient, options) {
options = options || {};
options.type = 'Logo';
if (item.ImageTags && item.ImageTags.Logo) {
options.tag = item.ImageTags.Logo;
return apiClient.getScaledImageUrl(item.Id, options);
}
if (item.ParentLogoImageTag) {
options.tag = item.ParentLogoImageTag;
return apiClient.getScaledImageUrl(item.ParentLogoItemId, options);
}
return null;
}
function renderLogo(page, item, apiClient) {
var url = logoImageUrl(item, apiClient, {
maxWidth: 400
});
var detailLogo = page.querySelector('.detailLogo');
if (!layoutManager.mobile && !userSettings.enableBackdrops()) {
detailLogo.classList.add('hide');
} else if (url) {
detailLogo.classList.remove('hide');
detailLogo.classList.add('lazy');
detailLogo.setAttribute('data-src', url);
imageLoader.lazyImage(detailLogo);
} else {
detailLogo.classList.add('hide');
}
}
function showRecordingFields(instance, page, item, user) {
if (!instance.currentRecordingFields) {
var recordingFieldsElement = page.querySelector('.recordingFields');
if ('Program' == item.Type && user.Policy.EnableLiveTvManagement) {
require(['recordingFields'], function (recordingFields) {
instance.currentRecordingFields = new recordingFields({
parent: recordingFieldsElement,
programId: item.Id,
serverId: item.ServerId
});
recordingFieldsElement.classList.remove('hide');
});
} else {
recordingFieldsElement.classList.add('hide');
recordingFieldsElement.innerHTML = '';
}
}
}
function renderLinks(linksElem, item) {
var html = [];
var links = [];
if (!layoutManager.tv && item.HomePageUrl) {
links.push('' + globalize.translate('ButtonWebsite') + '');
}
if (item.ExternalUrls) {
for (var i = 0, length = item.ExternalUrls.length; i < length; i++) {
var url = item.ExternalUrls[i];
links.push('' + url.Name + '');
}
}
if (links.length) {
html.push(links.join(', '));
}
linksElem.innerHTML = html.join(', ');
if (html.length) {
linksElem.classList.remove('hide');
} else {
linksElem.classList.add('hide');
}
}
function renderDetailImage(page, elem, item, apiClient, editable, imageLoader, indicators) {
if ('SeriesTimer' === item.Type || 'Program' === item.Type) {
editable = false;
}
elem.classList.add('detailimg-hidemobile');
var imageTags = item.ImageTags || {};
if (item.PrimaryImageTag) {
imageTags.Primary = item.PrimaryImageTag;
}
var url;
var html = '';
var shape = 'portrait';
var detectRatio = false;
/* In the following section, getScreenWidth() is multiplied by 0.5 as the posters
are 25vw and we need double the resolution to counter Skia's scaling. */
// TODO: Find a reliable way to get the poster width
if (imageTags.Primary) {
url = apiClient.getScaledImageUrl(item.Id, {
type: 'Primary',
maxWidth: Math.round(dom.getScreenWidth() * 0.5),
tag: item.ImageTags.Primary
});
detectRatio = true;
} else if (item.BackdropImageTags && item.BackdropImageTags.length) {
url = apiClient.getScaledImageUrl(item.Id, {
type: 'Backdrop',
maxWidth: Math.round(dom.getScreenWidth() * 0.5),
tag: item.BackdropImageTags[0]
});
shape = 'thumb';
} else if (imageTags.Thumb) {
url = apiClient.getScaledImageUrl(item.Id, {
type: 'Thumb',
maxWidth: Math.round(dom.getScreenWidth() * 0.5),
tag: item.ImageTags.Thumb
});
shape = 'thumb';
} else if (imageTags.Disc) {
url = apiClient.getScaledImageUrl(item.Id, {
type: 'Disc',
maxWidth: Math.round(dom.getScreenWidth() * 0.5),
tag: item.ImageTags.Disc
});
shape = 'square';
} else if (item.AlbumId && item.AlbumPrimaryImageTag) {
url = apiClient.getScaledImageUrl(item.AlbumId, {
type: 'Primary',
maxWidth: Math.round(dom.getScreenWidth() * 0.5),
tag: item.AlbumPrimaryImageTag
});
shape = 'square';
} else if (item.SeriesId && item.SeriesPrimaryImageTag) {
url = apiClient.getScaledImageUrl(item.SeriesId, {
type: 'Primary',
maxWidth: Math.round(dom.getScreenWidth() * 0.5),
tag: item.SeriesPrimaryImageTag
});
} else if (item.ParentPrimaryImageItemId && item.ParentPrimaryImageTag) {
url = apiClient.getScaledImageUrl(item.ParentPrimaryImageItemId, {
type: 'Primary',
maxWidth: Math.round(dom.getScreenWidth() * 0.5),
tag: item.ParentPrimaryImageTag
});
}
if (editable && url === undefined) {
html += "";
} else if (!editable && url === undefined) {
html += "