date-fns#formatDistanceToNow JavaScript Examples
The following examples show how to use
date-fns#formatDistanceToNow.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: scheduledtasks.js From jellyfin-web-jmp with GNU General Public License v2.0 | 6 votes |
function getTaskProgressHtml(task) {
let html = '';
if (task.State === 'Idle') {
if (task.LastExecutionResult) {
const endtime = Date.parse(task.LastExecutionResult.EndTimeUtc);
const starttime = Date.parse(task.LastExecutionResult.StartTimeUtc);
html += globalize.translate('LabelScheduledTaskLastRan', formatDistanceToNow(endtime, localeWithSuffix),
formatDistance(starttime, endtime, { locale: getLocale() }));
if (task.LastExecutionResult.Status === 'Failed') {
html += " <span style='color:#FF0000;'>(" + globalize.translate('LabelFailed') + ')</span>';
} else if (task.LastExecutionResult.Status === 'Cancelled') {
html += " <span style='color:#0026FF;'>(" + globalize.translate('LabelCancelled') + ')</span>';
} else if (task.LastExecutionResult.Status === 'Aborted') {
html += " <span style='color:#FF0000;'>" + globalize.translate('LabelAbortedByServerShutdown') + '</span>';
}
}
} else if (task.State === 'Running') {
const progress = (task.CurrentProgressPercentage || 0).toFixed(1);
html += '<div style="display:flex;align-items:center;">';
html += '<div class="taskProgressOuter" title="' + progress + '%" style="flex-grow:1;">';
html += '<div class="taskProgressInner" style="width:' + progress + '%;">';
html += '</div>';
html += '</div>';
html += "<span style='color:#00a4dc;margin-left:5px;'>" + progress + '%</span>';
html += '</div>';
} else {
html += "<span style='color:#FF0000;'>" + globalize.translate('LabelStopping') + '</span>';
}
return html;
}
Example #2
Source File: scheduledtasks.js From veso-web with GNU General Public License v2.0 | 6 votes |
function getTaskProgressHtml(task) {
let html = '';
if (task.State === 'Idle') {
if (task.LastExecutionResult) {
const endtime = Date.parse(task.LastExecutionResult.EndTimeUtc);
const starttime = Date.parse(task.LastExecutionResult.StartTimeUtc);
html += globalize.translate('LabelScheduledTaskLastRan', formatDistanceToNow(endtime, localeWithSuffix),
formatDistance(starttime, endtime, { locale: getLocale() }));
if (task.LastExecutionResult.Status === 'Failed') {
html += " <span style='color:#FF0000;'>(" + globalize.translate('LabelFailed') + ')</span>';
} else if (task.LastExecutionResult.Status === 'Cancelled') {
html += " <span style='color:#0026FF;'>(" + globalize.translate('LabelCancelled') + ')</span>';
} else if (task.LastExecutionResult.Status === 'Aborted') {
html += " <span style='color:#FF0000;'>" + globalize.translate('LabelAbortedByServerShutdown') + '</span>';
}
}
} else if (task.State === 'Running') {
const progress = (task.CurrentProgressPercentage || 0).toFixed(1);
html += '<div style="display:flex;align-items:center;">';
html += '<div class="taskProgressOuter" title="' + progress + '%" style="flex-grow:1;">';
html += '<div class="taskProgressInner" style="width:' + progress + '%;">';
html += '</div>';
html += '</div>';
html += "<span style='color:#d61e30;margin-left:5px;'>" + progress + '%</span>';
html += '</div>';
} else {
html += "<span style='color:#FF0000;'>" + globalize.translate('LabelStopping') + '</span>';
}
return html;
}
Example #3
Source File: Profile.jsx From airdrop with MIT License | 6 votes |
function Profile({ user }) {
const [isOpen, setIsOpen] = useState(false);
return (
<>
<div
style={{ gridTemplateColumns: '60px 1fr 30px' }}
className="grid p-3 gap-1 cursor-pointer"
onClick={() => setIsOpen(true)}
>
<div className="w-12 h-12 bg-secondary rounded-full">
<img src={user.photoURL} className="rounded-full" alt="Your Profile" />
</div>
<div
className={`w-auto font-sans flex flex-col justify-between ${Styles.borderBorder} pb-2`}
>
<div className="text-white text-lg">
<span>{user.isAnonymous && '~ '}</span>
<span>{user?.displayName || 'User'}</span>
</div>
<div className="text-light text-xs">
Last login{' '}
{user.metadata.lastSignInTime &&
formatDistanceToNow(new Date(user.metadata.lastSignInTime), {
addSuffix: true,
})}
</div>
</div>
<div>
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5 text-light" viewBox="0 0 20 20" fill="currentColor">
<path d="M17.414 2.586a2 2 0 00-2.828 0L7 10.172V13h2.828l7.586-7.586a2 2 0 000-2.828z" />
<path fillRule="evenodd" d="M2 6a2 2 0 012-2h4a1 1 0 010 2H4v10h10v-4a1 1 0 112 0v4a2 2 0 01-2 2H4a2 2 0 01-2-2V6z" clipRule="evenodd" />
</svg>
</div>
</div>
<EditProfile isOpen={isOpen} setIsOpen={setIsOpen}/>
</>
);
}
Example #4
Source File: date-time.js From tisn.app with GNU Affero General Public License v3.0 | 5 votes |
distanceToNow = (dateTimeString) =>
formatDistanceToNow(parseISO(dateTimeString), { locale: getLocale() })
Example #5
Source File: locale.js From treetracker-admin-client with GNU Affero General Public License v3.0 | 5 votes |
timeAgoFormatDate = (date) => {
let timeStr = formatDistanceToNow(date).replace(/about/, '');
return timeStr;
}
Example #6
Source File: NotificationsPopover.js From course-manager with MIT License | 5 votes |
function NotificationItem({ notification }) {
const { avatar, title } = renderContent(notification);
return (
<ListItem
button
to="#"
disableGutters
component={RouterLink}
sx={{
py: 1.5,
px: 2.5,
mt: '1px',
...(notification.isUnRead && {
bgcolor: 'action.selected'
})
}}
>
<ListItemAvatar>
<Avatar sx={{ bgcolor: 'background.neutral' }}>{avatar}</Avatar>
</ListItemAvatar>
<ListItemText
primary={title}
secondary={
<Typography
variant="caption"
sx={{
mt: 0.5,
display: 'flex',
alignItems: 'center',
color: 'text.disabled'
}}
>
<Box component={Icon} icon={clockFill} sx={{ mr: 0.5, width: 16, height: 16 }} />
{formatDistanceToNow(new Date(notification.createdAt))}
</Typography>
}
/>
</ListItem>
);
}
Example #7
Source File: formatTime.js From course-manager with MIT License | 5 votes |
export function fToNow(date) {
return formatDistanceToNow(new Date(date), {
addSuffix: true
});
}
Example #8
Source File: formatDate.js From Mumble with Apache License 2.0 | 5 votes |
distanceDate = (date) =>
formatDistanceToNow(sqlDateToJsDate(date), { addSuffix: true })
Example #9
Source File: Item.jsx From killed-by-microsoft with MIT License | 5 votes |
timePhrase() {
const { dateClose } = this.props;
const relativeDate = formatDistanceToNow(parseISO(dateClose), new Date());
if (!this.isPast()) {
return <span>{`${soonToDieIdiom()} in ${relativeDate}, `}</span>;
}
return <span>{`Killed ${relativeDate} ago, `}</span>;
}
Example #10
Source File: formatTime.js From Django-REST-Framework-React-BoilerPlate with MIT License | 5 votes |
export function fToNow(date) {
return formatDistanceToNow(new Date(date), {
addSuffix: true,
});
}
Example #11
Source File: devices.js From jellyfin-web-jmp with GNU General Public License v2.0 | 5 votes |
function load(page, devices) {
let html = '';
html += devices.map(function (device) {
let deviceHtml = '';
deviceHtml += "<div data-id='" + device.Id + "' class='card backdropCard'>";
deviceHtml += '<div class="cardBox visualCardBox">';
deviceHtml += '<div class="cardScalable">';
deviceHtml += '<div class="cardPadder cardPadder-backdrop"></div>';
deviceHtml += `<a is="emby-linkbutton" href="${canEdit ? '#!/device.html?id=' + device.Id : '#'}" class="cardContent cardImageContainer ${cardBuilder.getDefaultBackgroundClass()}">`;
const iconUrl = imageHelper.getDeviceIcon(device);
if (iconUrl) {
deviceHtml += '<div class="cardImage" style="background-image:url(\'' + iconUrl + "');background-size: auto 64%;background-position:center center;\">";
deviceHtml += '</div>';
} else {
deviceHtml += '<span class="cardImageIcon material-icons tablet_android" aria-hidden="true"></span>';
}
deviceHtml += '</a>';
deviceHtml += '</div>';
deviceHtml += '<div class="cardFooter">';
if (canEdit || canDelete(device.Id)) {
deviceHtml += '<div style="text-align:right; float:right;padding-top:5px;">';
deviceHtml += '<button type="button" is="paper-icon-button-light" data-id="' + device.Id + '" title="' + globalize.translate('Menu') + '" class="btnDeviceMenu"><span class="material-icons more_vert" aria-hidden="true"></span></button>';
deviceHtml += '</div>';
}
deviceHtml += "<div class='cardText'>";
deviceHtml += escapeHtml(device.Name);
deviceHtml += '</div>';
deviceHtml += "<div class='cardText cardText-secondary'>";
deviceHtml += escapeHtml(device.AppName + ' ' + device.AppVersion);
deviceHtml += '</div>';
deviceHtml += "<div class='cardText cardText-secondary'>";
if (device.LastUserName) {
deviceHtml += escapeHtml(device.LastUserName);
deviceHtml += ', ' + formatDistanceToNow(Date.parse(device.DateLastActivity), localeWithSuffix);
}
deviceHtml += ' ';
deviceHtml += '</div>';
deviceHtml += '</div>';
deviceHtml += '</div>';
deviceHtml += '</div>';
return deviceHtml;
}).join('');
page.querySelector('.devicesList').innerHTML = html;
}
Example #12
Source File: jobs.js From remotebear with GNU Affero General Public License v3.0 | 5 votes |
export function getJobs({ query, locationId, departmentId, companyId }) {
return allJobs
.filter((job) => {
const company = allCompaniesById[job.companyId];
const disabled = job?.status === "disabled";
let satisfiesQuery = true;
if (query) {
satisfiesQuery =
searchInString(job.title, query) ||
searchInString(job.location, query) ||
searchInString(company.name, query);
}
let satisfiesLocationId = true;
if (!job.normalizedLocation.length) {
satisfiesLocationId = false;
} else if (locationId) {
satisfiesLocationId =
job.normalizedLocation.includes(locationIds.global) ||
job.normalizedLocation.includes(locationId);
}
let satisfiesDepartmentId = true;
if (departmentId) {
satisfiesDepartmentId =
departmentId === departmentIds.engineering
? job.normalizedDepartment === departmentId
: !job.normalizedDepartment;
}
let satisfiesCompanyId = true;
if (companyId) {
satisfiesCompanyId = job.companyId === companyId;
}
return (
satisfiesQuery &&
satisfiesLocationId &&
satisfiesDepartmentId &&
satisfiesCompanyId &&
!disabled
);
})
.map((job) => {
// Add a new "formattedCreatedAt" field holding a human readable date
let formattedCreatedAt;
if (isToday(job.createdAt)) {
formattedCreatedAt = "Today";
} else if (isYesterday(job.createdAt)) {
formattedCreatedAt = "Yesterday";
} else {
formattedCreatedAt = formatDistanceToNow(job.createdAt, {
addSuffix: true,
});
}
// Capitalize
formattedCreatedAt = `${formattedCreatedAt
.charAt(0)
.toUpperCase()}${formattedCreatedAt.slice(1)}`;
// Denormalize the company infos into "company" to avoid loading them
// on the client side
const iconName = companyFaviconPathsByCompanyIds[job.companyId];
const company = {
id: allCompaniesById[job.companyId].id,
name: allCompaniesById[job.companyId].name,
iconUrl: `/company-favicons/${iconName}`,
};
return { ...job, company, formattedCreatedAt };
});
}
Example #13
Source File: DrawLastUpdated.js From covid19japan with MIT License | 5 votes |
getLocalizedRelativeTime = (lastUpdated, language) => {
const locale = LOCALES[language];
return formatDistanceToNow(lastUpdated, {
locale,
addSuffix: true,
});
}
Example #14
Source File: devices.js From veso-web with GNU General Public License v2.0 | 5 votes |
function load(page, devices) {
let html = '';
html += devices.map(function (device) {
let deviceHtml = '';
deviceHtml += "<div data-id='" + device.Id + "' class='card backdropCard'>";
deviceHtml += '<div class="cardBox visualCardBox">';
deviceHtml += '<div class="cardScalable">';
deviceHtml += '<div class="cardPadder cardPadder-backdrop"></div>';
deviceHtml += `<a is="emby-linkbutton" href="${canEdit ? '#/device.html?id=' + device.Id : '#'}" class="cardContent cardImageContainer ${cardBuilder.getDefaultBackgroundClass()}">`;
const iconUrl = imageHelper.getDeviceIcon(device);
if (iconUrl) {
deviceHtml += '<div class="cardImage" style="background-image:url(\'' + iconUrl + "');background-size: auto 64%;background-position:center center;\">";
deviceHtml += '</div>';
} else {
deviceHtml += '<span class="cardImageIcon material-icons tablet_android" aria-hidden="true"></span>';
}
deviceHtml += '</a>';
deviceHtml += '</div>';
deviceHtml += '<div class="cardFooter">';
if (canEdit || canDelete(device.Id)) {
deviceHtml += '<div style="text-align:right; float:right;padding-top:5px;">';
deviceHtml += '<button type="button" is="paper-icon-button-light" data-id="' + device.Id + '" title="' + globalize.translate('Menu') + '" class="btnDeviceMenu"><span class="material-icons more_vert" aria-hidden="true"></span></button>';
deviceHtml += '</div>';
}
deviceHtml += "<div class='cardText'>";
deviceHtml += escapeHtml(device.Name);
deviceHtml += '</div>';
deviceHtml += "<div class='cardText cardText-secondary'>";
deviceHtml += escapeHtml(device.AppName + ' ' + device.AppVersion);
deviceHtml += '</div>';
deviceHtml += "<div class='cardText cardText-secondary'>";
if (device.LastUserName) {
deviceHtml += escapeHtml(device.LastUserName);
deviceHtml += ', ' + formatDistanceToNow(Date.parse(device.DateLastActivity), localeWithSuffix);
}
deviceHtml += ' ';
deviceHtml += '</div>';
deviceHtml += '</div>';
deviceHtml += '</div>';
deviceHtml += '</div>';
return deviceHtml;
}).join('');
page.querySelector('.devicesList').innerHTML = html;
}
Example #15
Source File: dashboard.js From jellyfin-web-jmp with GNU General Public License v2.0 | 4 votes |
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 += '<br/><br/>' + 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 = '<img src="' + imgUrl + '" style="max-height:24px;max-width:130px;" />';
}
return {
html: bottomText ? topText + '<br/>' + 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 "<img src='" + iconUrl + "' />";
},
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();
});
}
};
Example #16
Source File: dashboard.js From veso-web with GNU General Public License v2.0 | 4 votes |
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 += '<br/><br/>' + 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 = '<img src="' + imgUrl + '" style="max-height:24px;max-width:130px;" />';
}
return {
html: bottomText ? topText + '<br/>' + 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 "<img src='" + iconUrl + "' />";
},
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();
});
}
};