import escapeHtml from 'escape-html'; import datetime from '../../scripts/datetime'; import { Events } from 'jellyfin-apiclient'; import itemHelper from '../../components/itemHelper'; import serverNotifications from '../../scripts/serverNotifications'; import dom from '../../scripts/dom'; import globalize from '../../scripts/globalize'; import { formatDistanceToNow } from 'date-fns'; import { localeWithSuffix } from '../../scripts/dfnshelper'; import loading from '../../components/loading/loading'; import playMethodHelper from '../../components/playback/playmethodhelper'; import cardBuilder from '../../components/cardbuilder/cardBuilder'; import imageLoader from '../../components/images/imageLoader'; import ActivityLog from '../../components/activitylog'; import imageHelper from '../../scripts/imagehelper'; import indicators from '../../components/indicators/indicators'; import '../../components/listview/listview.scss'; import '../../elements/emby-button/emby-button'; import '../../assets/css/flexstyles.scss'; import '../../elements/emby-itemscontainer/emby-itemscontainer'; import taskButton from '../../scripts/taskbutton'; import Dashboard from '../../scripts/clientUtils'; import ServerConnections from '../../components/ServerConnections'; import alert from '../../components/alert'; import confirm from '../../components/confirm/confirm'; /* eslint-disable indent */ function showPlaybackInfo(btn, session) { let title; const text = []; const displayPlayMethod = playMethodHelper.getDisplayPlayMethod(session); if (displayPlayMethod === 'Remux') { title = globalize.translate('Remuxing'); text.push(globalize.translate('RemuxHelp1')); text.push('
'); text.push(globalize.translate('RemuxHelp2')); } else if (displayPlayMethod === 'DirectStream') { title = globalize.translate('DirectStreaming'); text.push(globalize.translate('DirectStreamHelp1')); text.push('
'); text.push(globalize.translate('DirectStreamHelp2')); } else if (displayPlayMethod === 'DirectPlay') { title = globalize.translate('DirectPlaying'); text.push(globalize.translate('DirectPlayHelp')); } else if (displayPlayMethod === 'Transcode') { title = globalize.translate('Transcoding'); text.push(globalize.translate('MediaIsBeingConverted')); text.push(DashboardPage.getSessionNowPlayingStreamInfo(session)); if (session.TranscodingInfo && session.TranscodingInfo.TranscodeReasons && session.TranscodingInfo.TranscodeReasons.length) { text.push('
'); text.push(globalize.translate('LabelReasonForTranscoding')); session.TranscodingInfo.TranscodeReasons.forEach(function (transcodeReason) { text.push(globalize.translate(transcodeReason)); }); } } alert({ text: text.join('
'), title: title }); } function showSendMessageForm(btn, session) { import('../../components/prompt/prompt').then(({default: prompt}) => { prompt({ title: globalize.translate('HeaderSendMessage'), label: globalize.translate('LabelMessageText'), confirmText: globalize.translate('ButtonSend') }).then(function (text) { if (text) { ServerConnections.getApiClient(session.ServerId).sendMessageCommand(session.Id, { Text: text, TimeoutMs: 5e3 }); } }); }); } function showOptionsMenu(btn, session) { import('../../components/actionSheet/actionSheet').then(({default: actionsheet}) => { const menuItems = []; if (session.ServerId && session.DeviceId !== ServerConnections.deviceId()) { menuItems.push({ name: globalize.translate('SendMessage'), id: 'sendmessage' }); } if (session.TranscodingInfo && session.TranscodingInfo.TranscodeReasons && session.TranscodingInfo.TranscodeReasons.length) { menuItems.push({ name: globalize.translate('ViewPlaybackInfo'), id: 'transcodinginfo' }); } return actionsheet.show({ items: menuItems, positionTo: btn }).then(function (id) { switch (id) { case 'sendmessage': showSendMessageForm(btn, session); break; case 'transcodinginfo': showPlaybackInfo(btn, session); break; } }); }); } function onActiveDevicesClick(evt) { const btn = dom.parentWithClass(evt.target, 'sessionCardButton'); if (btn) { const card = dom.parentWithClass(btn, 'card'); if (card) { const sessionId = card.id; const session = (DashboardPage.sessionsList || []).filter(function (dashboardSession) { return 'session' + dashboardSession.Id === sessionId; })[0]; if (session) { if (btn.classList.contains('btnCardOptions')) { showOptionsMenu(btn, session); } else if (btn.classList.contains('btnSessionInfo')) { showPlaybackInfo(btn, session); } else if (btn.classList.contains('btnSessionSendMessage')) { showSendMessageForm(btn, session); } else if (btn.classList.contains('btnSessionStop')) { ServerConnections.getApiClient(session.ServerId).sendPlayStateCommand(session.Id, 'Stop'); } else if (btn.classList.contains('btnSessionPlayPause') && session.PlayState) { ServerConnections.getApiClient(session.ServerId).sendPlayStateCommand(session.Id, 'PlayPause'); } } } } } function filterSessions(sessions) { const list = []; const minActiveDate = new Date().getTime() - 9e5; for (let i = 0, length = sessions.length; i < length; i++) { const session = sessions[i]; if (!session.NowPlayingItem && !session.UserId) { continue; } if (datetime.parseISO8601Date(session.LastActivityDate, true).getTime() >= minActiveDate) { list.push(session); } } return list; } function refreshActiveRecordings(view, apiClient) { apiClient.getLiveTvRecordings({ UserId: Dashboard.getCurrentUserId(), IsInProgress: true, Fields: 'CanDelete,PrimaryImageAspectRatio', EnableTotalRecordCount: false, EnableImageTypes: 'Primary,Thumb,Backdrop' }).then(function (result) { const itemsContainer = view.querySelector('.activeRecordingItems'); if (!result.Items.length) { view.querySelector('.activeRecordingsSection').classList.add('hide'); return void(itemsContainer.innerHTML = ''); } view.querySelector('.activeRecordingsSection').classList.remove('hide'); itemsContainer.innerHTML = cardBuilder.getCardsHtml({ items: result.Items, shape: 'auto', defaultShape: 'backdrop', showTitle: true, showParentTitle: true, coverImage: true, cardLayout: false, centerText: true, preferThumb: 'auto', overlayText: false, overlayMoreButton: true, action: 'none', centerPlayButton: true }); imageLoader.lazyChildren(itemsContainer); }); } function reloadSystemInfo(view, apiClient) { apiClient.getSystemInfo().then(function (systemInfo) { view.querySelector('#serverName').innerText = globalize.translate('DashboardServerName', systemInfo.ServerName); view.querySelector('#versionNumber').innerText = globalize.translate('DashboardVersionNumber', systemInfo.Version); view.querySelector('#operatingSystem').innerText = globalize.translate('DashboardOperatingSystem', systemInfo.OperatingSystem); view.querySelector('#architecture').innerText = globalize.translate('DashboardArchitecture', systemInfo.SystemArchitecture); if (systemInfo.CanSelfRestart) { view.querySelector('#btnRestartServer').classList.remove('hide'); } else { view.querySelector('#btnRestartServer').classList.add('hide'); } view.querySelector('#cachePath').innerText = systemInfo.CachePath; view.querySelector('#logPath').innerText = systemInfo.LogPath; view.querySelector('#transcodePath').innerText = systemInfo.TranscodingTempPath; view.querySelector('#metadataPath').innerText = systemInfo.InternalMetadataPath; view.querySelector('#webPath').innerText = systemInfo.WebPath; }); } function renderInfo(view, sessions) { sessions = filterSessions(sessions); renderActiveConnections(view, sessions); loading.hide(); } function pollForInfo(view, apiClient) { apiClient.getSessions({ ActiveWithinSeconds: 960 }).then(function (sessions) { renderInfo(view, sessions); }); apiClient.getScheduledTasks().then(function (tasks) { renderRunningTasks(view, tasks); }); } function renderActiveConnections(view, sessions) { let html = ''; DashboardPage.sessionsList = sessions; const parentElement = view.querySelector('.activeDevices'); const cardElem = parentElement.querySelector('.card'); if (cardElem) { cardElem.classList.add('deadSession'); } for (let i = 0, length = sessions.length; i < length; i++) { const session = sessions[i]; const rowId = 'session' + session.Id; const elem = view.querySelector('#' + rowId); if (elem) { DashboardPage.updateSession(elem, session); } else { const nowPlayingItem = session.NowPlayingItem; const className = 'scalableCard card activeSession backdropCard backdropCard-scalable'; const imgUrl = DashboardPage.getNowPlayingImageUrl(nowPlayingItem); html += '
'; html += '
'; html += '
'; html += '
'; html += `
`; if (imgUrl) { html += '
"; } else { html += '
'; } html += `
`; html += '
'; const clientImage = DashboardPage.getClientImage(session); if (clientImage) { html += clientImage; } html += '
'; html += '
' + escapeHtml(session.DeviceName) + '
'; html += '
' + escapeHtml(DashboardPage.getAppSecondaryText(session)) + '
'; html += '
'; html += '
'; html += '
'; const nowPlayingName = DashboardPage.getNowPlayingName(session); html += '
'; html += nowPlayingName.html; html += '
'; html += '
' + escapeHtml(DashboardPage.getSessionNowPlayingTime(session)) + '
'; html += '
'; let percent = 100 * session?.PlayState?.PositionTicks / nowPlayingItem?.RunTimeTicks; html += indicators.getProgressHtml(percent || 0, { containerClass: 'playbackProgress' }); percent = session?.TranscodingInfo?.CompletionPercentage?.toFixed(1); html += indicators.getProgressHtml(percent || 0, { containerClass: 'transcodingProgress' }); html += indicators.getProgressHtml(100, { containerClass: 'backgroundProgress' }); html += '
'; html += '
'; html += '
'; html += '
'; html += '
'; let btnCssClass = session.ServerId && session.NowPlayingItem && session.SupportsRemoteControl ? '' : ' hide'; const playIcon = session.PlayState.IsPaused ? 'pause' : 'play_arrow'; html += ''; html += ''; html += ''; btnCssClass = session.ServerId && session.SupportedCommands.indexOf('DisplayMessage') !== -1 && session.DeviceId !== ServerConnections.deviceId() ? '' : ' hide'; html += ''; html += '
'; html += '
'; const userImage = DashboardPage.getUserImage(session); html += userImage ? '
" : '
'; html += '
'; html += DashboardPage.getUsersHtml(session); html += '
'; html += '
'; html += '
'; html += '
'; html += '
'; } } parentElement.insertAdjacentHTML('beforeend', html); const deadSessionElem = parentElement.querySelector('.deadSession'); if (deadSessionElem) { deadSessionElem.parentNode.removeChild(deadSessionElem); } } function renderRunningTasks(view, tasks) { let html = ''; tasks = tasks.filter(function (task) { if (task.State != 'Idle') { return !task.IsHidden; } return false; }); if (tasks.length) { view.querySelector('.runningTasksContainer').classList.remove('hide'); } else { view.querySelector('.runningTasksContainer').classList.add('hide'); } for (let i = 0, length = tasks.length; i < length; i++) { const task = tasks[i]; html += '

'; html += task.Name + '
'; if (task.State === 'Running') { const progress = (task.CurrentProgressPercentage || 0).toFixed(1); html += ''; html += progress + '%'; html += ''; html += "" + progress + '%'; html += ''; } else if (task.State === 'Cancelling') { html += '' + globalize.translate('LabelStopping') + ''; } html += '

'; } view.querySelector('#divRunningTasks').innerHTML = html; } window.DashboardPage = { startInterval: function (apiClient) { apiClient.sendMessage('SessionsStart', '0,1500'); apiClient.sendMessage('ScheduledTasksInfoStart', '0,1000'); }, stopInterval: function (apiClient) { apiClient.sendMessage('SessionsStop'); apiClient.sendMessage('ScheduledTasksInfoStop'); }, getSessionNowPlayingStreamInfo: function (session) { let html = ''; let showTranscodingInfo = false; const displayPlayMethod = playMethodHelper.getDisplayPlayMethod(session); if (displayPlayMethod === 'DirectPlay') { html += globalize.translate('DirectPlaying'); } else if (displayPlayMethod === 'Remux') { html += globalize.translate('Remuxing'); } else if (displayPlayMethod === 'DirectStream') { html += globalize.translate('DirectStreaming'); } else if (displayPlayMethod === 'Transcode') { if (session.TranscodingInfo && session.TranscodingInfo.Framerate) { html += `${globalize.translate('Framerate')}: ${session.TranscodingInfo.Framerate}fps`; } showTranscodingInfo = true; } if (showTranscodingInfo) { const line = []; if (session.TranscodingInfo) { if (session.TranscodingInfo.Bitrate) { if (session.TranscodingInfo.Bitrate > 1e6) { line.push((session.TranscodingInfo.Bitrate / 1e6).toFixed(1) + ' Mbps'); } else { line.push(Math.floor(session.TranscodingInfo.Bitrate / 1e3) + ' Kbps'); } } if (session.TranscodingInfo.Container) { line.push(session.TranscodingInfo.Container.toUpperCase()); } if (session.TranscodingInfo.VideoCodec) { line.push(session.TranscodingInfo.VideoCodec.toUpperCase()); } if (session.TranscodingInfo.AudioCodec && session.TranscodingInfo.AudioCodec != session.TranscodingInfo.Container) { line.push(session.TranscodingInfo.AudioCodec.toUpperCase()); } } if (line.length) { html += '

' + line.join(' '); } } return html; }, getSessionNowPlayingTime: function (session) { const nowPlayingItem = session.NowPlayingItem; let html = ''; if (nowPlayingItem) { if (session.PlayState.PositionTicks) { html += datetime.getDisplayRunningTime(session.PlayState.PositionTicks); } else { html += '0:00'; } html += ' / '; if (nowPlayingItem && nowPlayingItem.RunTimeTicks) { html += datetime.getDisplayRunningTime(nowPlayingItem.RunTimeTicks); } else { html += '0:00'; } } return html; }, getAppSecondaryText: function (session) { return session.Client + ' ' + session.ApplicationVersion; }, getNowPlayingName: function (session) { let imgUrl = ''; const nowPlayingItem = session.NowPlayingItem; // FIXME: It seems that, sometimes, server sends date in the future, so date-fns displays messages like 'in less than a minute'. We should fix // how dates are returned by the server when the session is active and show something like 'Active now', instead of past/future sentences if (!nowPlayingItem) { return { html: globalize.translate('LastSeen', formatDistanceToNow(Date.parse(session.LastActivityDate), localeWithSuffix)), image: imgUrl }; } let topText = escapeHtml(itemHelper.getDisplayName(nowPlayingItem)); let bottomText = ''; if (nowPlayingItem.Artists && nowPlayingItem.Artists.length) { bottomText = topText; topText = escapeHtml(nowPlayingItem.Artists[0]); } else { if (nowPlayingItem.SeriesName || nowPlayingItem.Album) { bottomText = topText; topText = escapeHtml(nowPlayingItem.SeriesName || nowPlayingItem.Album); } else if (nowPlayingItem.ProductionYear) { bottomText = nowPlayingItem.ProductionYear; } } if (nowPlayingItem.ImageTags && nowPlayingItem.ImageTags.Logo) { imgUrl = ApiClient.getScaledImageUrl(nowPlayingItem.Id, { tag: nowPlayingItem.ImageTags.Logo, maxHeight: 24, maxWidth: 130, type: 'Logo' }); } else if (nowPlayingItem.ParentLogoImageTag) { imgUrl = ApiClient.getScaledImageUrl(nowPlayingItem.ParentLogoItemId, { tag: nowPlayingItem.ParentLogoImageTag, maxHeight: 24, maxWidth: 130, type: 'Logo' }); } if (imgUrl) { topText = ''; } return { html: bottomText ? topText + '
' + bottomText : topText, image: imgUrl }; }, getUsersHtml: function (session) { const html = []; if (session.UserId) { html.push(escapeHtml(session.UserName)); } for (let i = 0, length = session.AdditionalUsers.length; i < length; i++) { html.push(escapeHtml(session.AdditionalUsers[i].UserName)); } return html.join(', '); }, getUserImage: function (session) { if (session.UserId && session.UserPrimaryImageTag) { return ApiClient.getUserImageUrl(session.UserId, { tag: session.UserPrimaryImageTag, type: 'Primary' }); } return null; }, updateSession: function (row, session) { row.classList.remove('deadSession'); const nowPlayingItem = session.NowPlayingItem; if (nowPlayingItem) { row.classList.add('playingSession'); row.querySelector('.btnSessionInfo').classList.remove('hide'); } else { row.classList.remove('playingSession'); row.querySelector('.btnSessionInfo').classList.add('hide'); } if (session.ServerId && session.SupportedCommands.indexOf('DisplayMessage') !== -1) { row.querySelector('.btnSessionSendMessage').classList.remove('hide'); } else { row.querySelector('.btnSessionSendMessage').classList.add('hide'); } const btnSessionPlayPause = row.querySelector('.btnSessionPlayPause'); if (session.ServerId && nowPlayingItem && session.SupportsRemoteControl) { btnSessionPlayPause.classList.remove('hide'); row.querySelector('.btnSessionStop').classList.remove('hide'); } else { btnSessionPlayPause.classList.add('hide'); row.querySelector('.btnSessionStop').classList.add('hide'); } const btnSessionPlayPauseIcon = btnSessionPlayPause.querySelector('.material-icons'); btnSessionPlayPauseIcon.classList.remove('play_arrow', 'pause'); btnSessionPlayPauseIcon.classList.add(session.PlayState && session.PlayState.IsPaused ? 'play_arrow' : 'pause'); row.querySelector('.sessionNowPlayingTime').innerText = DashboardPage.getSessionNowPlayingTime(session); row.querySelector('.sessionUserName').innerHTML = DashboardPage.getUsersHtml(session); row.querySelector('.sessionAppSecondaryText').innerText = DashboardPage.getAppSecondaryText(session); const nowPlayingName = DashboardPage.getNowPlayingName(session); const nowPlayingInfoElem = row.querySelector('.sessionNowPlayingInfo'); if (!(nowPlayingName.image && nowPlayingName.image == nowPlayingInfoElem.getAttribute('data-imgsrc'))) { nowPlayingInfoElem.innerHTML = nowPlayingName.html; nowPlayingInfoElem.setAttribute('data-imgsrc', nowPlayingName.image || ''); } const playbackProgressElem = row.querySelector('.playbackProgress'); const transcodingProgress = row.querySelector('.transcodingProgress'); let percent = 100 * session?.PlayState?.PositionTicks / nowPlayingItem?.RunTimeTicks; playbackProgressElem.outerHTML = indicators.getProgressHtml(percent || 0, { containerClass: 'playbackProgress' }); percent = session?.TranscodingInfo?.CompletionPercentage?.toFixed(1); transcodingProgress.outerHTML = indicators.getProgressHtml(percent || 0, { containerClass: 'transcodingProgress' }); const imgUrl = DashboardPage.getNowPlayingImageUrl(nowPlayingItem) || ''; const imgElem = row.querySelector('.sessionNowPlayingContent'); if (imgUrl != imgElem.getAttribute('data-src')) { imgElem.style.backgroundImage = imgUrl ? "url('" + imgUrl + "')" : ''; imgElem.setAttribute('data-src', imgUrl); if (imgUrl) { imgElem.classList.add('sessionNowPlayingContent-withbackground'); row.querySelector('.sessionNowPlayingInnerContent').classList.add('darkenContent'); } else { imgElem.classList.remove('sessionNowPlayingContent-withbackground'); row.querySelector('.sessionNowPlayingInnerContent').classList.remove('darkenContent'); } } }, getClientImage: function (connection) { const iconUrl = imageHelper.getDeviceIcon(connection); return ""; }, getNowPlayingImageUrl: function (item) { /* Screen width is multiplied by 0.2, as the there is currently no way to get the width of elements that aren't created yet. */ if (item && item.BackdropImageTags && item.BackdropImageTags.length) { return ApiClient.getScaledImageUrl(item.Id, { maxWidth: Math.round(dom.getScreenWidth() * 0.20), type: 'Backdrop', tag: item.BackdropImageTags[0] }); } if (item && item.ParentBackdropImageTags && item.ParentBackdropImageTags.length) { return ApiClient.getScaledImageUrl(item.ParentBackdropItemId, { maxWidth: Math.round(dom.getScreenWidth() * 0.20), type: 'Backdrop', tag: item.ParentBackdropImageTags[0] }); } if (item && item.BackdropImageTag) { return ApiClient.getScaledImageUrl(item.BackdropItemId, { maxWidth: Math.round(dom.getScreenWidth() * 0.20), type: 'Backdrop', tag: item.BackdropImageTag }); } const imageTags = (item || {}).ImageTags || {}; if (item && imageTags.Thumb) { return ApiClient.getScaledImageUrl(item.Id, { maxWidth: Math.round(dom.getScreenWidth() * 0.20), type: 'Thumb', tag: imageTags.Thumb }); } if (item && item.ParentThumbImageTag) { return ApiClient.getScaledImageUrl(item.ParentThumbItemId, { maxWidth: Math.round(dom.getScreenWidth() * 0.20), type: 'Thumb', tag: item.ParentThumbImageTag }); } if (item && item.ThumbImageTag) { return ApiClient.getScaledImageUrl(item.ThumbItemId, { maxWidth: Math.round(dom.getScreenWidth() * 0.20), type: 'Thumb', tag: item.ThumbImageTag }); } if (item && imageTags.Primary) { return ApiClient.getScaledImageUrl(item.Id, { maxWidth: Math.round(dom.getScreenWidth() * 0.20), type: 'Primary', tag: imageTags.Primary }); } if (item && item.PrimaryImageTag) { return ApiClient.getScaledImageUrl(item.PrimaryImageItemId, { maxWidth: Math.round(dom.getScreenWidth() * 0.20), type: 'Primary', tag: item.PrimaryImageTag }); } if (item && item.AlbumPrimaryImageTag) { return ApiClient.getScaledImageUrl(item.AlbumId, { maxWidth: Math.round(dom.getScreenWidth() * 0.20), type: 'Primary', tag: item.AlbumPrimaryImageTag }); } return null; }, systemUpdateTaskKey: 'SystemUpdateTask', stopTask: function (btn, id) { const page = dom.parentWithClass(btn, 'page'); ApiClient.stopScheduledTask(id).then(function () { pollForInfo(page, ApiClient); }); }, restart: function (btn) { confirm({ title: globalize.translate('Restart'), text: globalize.translate('MessageConfirmRestart'), confirmText: globalize.translate('Restart'), primary: 'delete' }).then(function () { const page = dom.parentWithClass(btn, 'page'); page.querySelector('#btnRestartServer').disabled = true; page.querySelector('#btnShutdown').disabled = true; ApiClient.restartServer(); }); }, shutdown: function (btn) { confirm({ title: globalize.translate('ButtonShutdown'), text: globalize.translate('MessageConfirmShutdown'), confirmText: globalize.translate('ButtonShutdown'), primary: 'delete' }).then(function () { const page = dom.parentWithClass(btn, 'page'); page.querySelector('#btnRestartServer').disabled = true; page.querySelector('#btnShutdown').disabled = true; ApiClient.shutdownServer(); }); } }; export default function (view) { function onRestartRequired(evt, apiClient) { console.debug('onRestartRequired not implemented', evt, apiClient); } function onServerShuttingDown(evt, apiClient) { console.debug('onServerShuttingDown not implemented', evt, apiClient); } function onServerRestarting(evt, apiClient) { console.debug('onServerRestarting not implemented', evt, apiClient); } function onPackageInstalling(evt, apiClient) { if (apiClient.serverId() === serverId) { pollForInfo(view, apiClient); reloadSystemInfo(view, apiClient); } } function onPackageInstallationCompleted(evt, apiClient) { if (apiClient.serverId() === serverId) { pollForInfo(view, apiClient); reloadSystemInfo(view, apiClient); } } function onSessionsUpdate(evt, apiClient, info) { if (apiClient.serverId() === serverId) { renderInfo(view, info); } } function onScheduledTasksUpdate(evt, apiClient, info) { if (apiClient.serverId() === serverId) { renderRunningTasks(view, info); } } const serverId = ApiClient.serverId(); view.querySelector('.activeDevices').addEventListener('click', onActiveDevicesClick); view.addEventListener('viewshow', function () { const page = this; const apiClient = ApiClient; if (apiClient) { loading.show(); pollForInfo(page, apiClient); DashboardPage.startInterval(apiClient); Events.on(serverNotifications, 'RestartRequired', onRestartRequired); Events.on(serverNotifications, 'ServerShuttingDown', onServerShuttingDown); Events.on(serverNotifications, 'ServerRestarting', onServerRestarting); Events.on(serverNotifications, 'PackageInstalling', onPackageInstalling); Events.on(serverNotifications, 'PackageInstallationCompleted', onPackageInstallationCompleted); Events.on(serverNotifications, 'Sessions', onSessionsUpdate); Events.on(serverNotifications, 'ScheduledTasksInfo', onScheduledTasksUpdate); DashboardPage.lastAppUpdateCheck = null; reloadSystemInfo(page, ApiClient); if (!page.userActivityLog) { page.userActivityLog = new ActivityLog({ serverId: ApiClient.serverId(), element: page.querySelector('.userActivityItems') }); } if (ApiClient.isMinServerVersion('3.4.1.25')) { if (!page.serverActivityLog) { page.serverActivityLog = new ActivityLog({ serverId: ApiClient.serverId(), element: page.querySelector('.serverActivityItems') }); } } refreshActiveRecordings(view, apiClient); loading.hide(); } taskButton({ mode: 'on', taskKey: 'RefreshLibrary', button: page.querySelector('.btnRefresh') }); }); view.addEventListener('viewbeforehide', function () { const apiClient = ApiClient; const page = this; Events.off(serverNotifications, 'RestartRequired', onRestartRequired); Events.off(serverNotifications, 'ServerShuttingDown', onServerShuttingDown); Events.off(serverNotifications, 'ServerRestarting', onServerRestarting); Events.off(serverNotifications, 'PackageInstalling', onPackageInstalling); Events.off(serverNotifications, 'PackageInstallationCompleted', onPackageInstallationCompleted); Events.off(serverNotifications, 'Sessions', onSessionsUpdate); Events.off(serverNotifications, 'ScheduledTasksInfo', onScheduledTasksUpdate); if (apiClient) { DashboardPage.stopInterval(apiClient); } taskButton({ mode: 'off', taskKey: 'RefreshLibrary', button: page.querySelector('.btnRefresh') }); }); view.addEventListener('viewdestroy', function () { const page = this; const userActivityLog = page.userActivityLog; if (userActivityLog) { userActivityLog.destroy(); } const serverActivityLog = page.serverActivityLog; if (serverActivityLog) { serverActivityLog.destroy(); } }); } /* eslint-enable indent */