1
0
Fork 0
mirror of https://github.com/jellyfin/jellyfin-web synced 2025-03-30 19:56:21 +00:00

Merge branch 'master' into unavailable-yt-video-trailer-bug-fix

This commit is contained in:
matjaz321 2020-08-19 20:59:10 +02:00
commit 05bec3e16b
158 changed files with 3875 additions and 5955 deletions

View file

@ -40,13 +40,13 @@ module.exports = {
'no-multi-spaces': ['error'],
'no-multiple-empty-lines': ['error', { 'max': 1 }],
'no-trailing-spaces': ['error'],
'no-unused-expressions': ['error', { 'allowShortCircuit': true, 'allowTernary': true, 'allowTaggedTemplates': true }],
'no-unused-vars': ['error', { 'vars': 'all', 'args': 'none', 'ignoreRestSiblings': true }],
'@babel/no-unused-expressions': ['error', { 'allowShortCircuit': true, 'allowTernary': true, 'allowTaggedTemplates': true }],
//'no-unused-vars': ['error', { 'vars': 'all', 'args': 'none', 'ignoreRestSiblings': true }],
'one-var': ['error', 'never'],
'padded-blocks': ['error', 'never'],
//'prefer-const': ['error', {'destructuring': 'all'}],
'quotes': ['error', 'single', { 'avoidEscape': true, 'allowTemplateLiterals': false }],
'semi': ['error'],
'@babel/semi': ['error'],
'space-before-blocks': ['error'],
'space-infix-ops': 'error',
'yoda': 'error'
@ -106,6 +106,7 @@ module.exports = {
// TODO: Fix warnings and remove these rules
'no-redeclare': ['off'],
'no-useless-escape': ['off'],
'no-unused-vars': ['off'],
// TODO: Remove after ES6 migration is complete
'import/no-unresolved': ['off']
},

View file

@ -20,7 +20,7 @@
"css-loader": "^4.2.1",
"cssnano": "^4.1.10",
"del": "^5.1.0",
"eslint": "^7.6.0",
"eslint": "^7.7.0",
"eslint-plugin-compat": "^3.5.1",
"eslint-plugin-eslint-comments": "^3.2.0",
"eslint-plugin-import": "^2.21.2",
@ -96,6 +96,7 @@
"src/components/alphaPicker/alphaPicker.js",
"src/components/appFooter/appFooter.js",
"src/components/apphost.js",
"src/components/appRouter.js",
"src/components/autoFocuser.js",
"src/components/backdrop/backdrop.js",
"src/components/cardbuilder/cardBuilder.js",
@ -144,6 +145,7 @@
"src/components/multiSelect/multiSelect.js",
"src/components/notifications/notifications.js",
"src/components/nowPlayingBar/nowPlayingBar.js",
"src/components/packageManager.js",
"src/components/playback/brightnessosd.js",
"src/components/playback/mediasession.js",
"src/components/playback/nowplayinghelper.js",
@ -159,16 +161,21 @@
"src/components/playerstats/playerstats.js",
"src/components/playlisteditor/playlisteditor.js",
"src/components/playmenu.js",
"src/components/pluginManager.js",
"src/components/prompt/prompt.js",
"src/components/recordingcreator/recordingbutton.js",
"src/components/recordingcreator/recordingcreator.js",
"src/components/recordingcreator/seriesrecordingeditor.js",
"src/components/recordingcreator/recordinghelper.js",
"src/components/refreshdialog/refreshdialog.js",
"src/components/recordingcreator/recordingeditor.js",
"src/components/recordingcreator/recordingfields.js",
"src/components/qualityOptions.js",
"src/components/remotecontrol/remotecontrol.js",
"src/components/sanatizefilename.js",
"src/components/scrollManager.js",
"src/plugins/experimentalWarnings/plugin.js",
"src/plugins/sessionPlayer/plugin.js",
"src/plugins/htmlAudioPlayer/plugin.js",
"src/plugins/chromecastPlayer/plugin.js",
"src/components/slideshow/slideshow.js",
@ -318,6 +325,7 @@
"src/scripts/alphanumericshortcuts.js",
"src/scripts/autoBackdrops.js",
"src/scripts/browser.js",
"src/scripts/clientUtils.js",
"src/scripts/datetime.js",
"src/scripts/deleteHelper.js",
"src/scripts/dfnshelper.js",

View file

@ -1,5 +1,5 @@
<div class="formDialogHeader">
<button is="paper-icon-button-light" class="btnCancel autoSize" title="${LabelPrevious}" tabindex="-1">
<button is="paper-icon-button-light" class="btnCancel autoSize" title="${Previous}" tabindex="-1">
<span class="material-icons arrow_back" aria-hidden="true"></span>
</button>
<h3 class="formDialogHeaderTitle">
@ -12,13 +12,13 @@
<div class="selectContainer">
<select is="emby-select" id="selectDay" label="${LabelAccessDay}">
<option value="Sunday">${OptionSunday}</option>
<option value="Monday">${OptionMonday}</option>
<option value="Tuesday">${OptionTuesday}</option>
<option value="Wednesday">${OptionWednesday}</option>
<option value="Thursday">${OptionThursday}</option>
<option value="Friday">${OptionFriday}</option>
<option value="Saturday">${OptionSaturday}</option>
<option value="Sunday">${Sunday}</option>
<option value="Monday">${Monday}</option>
<option value="Tuesday">${Tuesday}</option>
<option value="Wednesday">${Wednesday}</option>
<option value="Thursday">${Thursday}</option>
<option value="Friday">${Friday}</option>
<option value="Saturday">${Saturday}</option>
<option value="Everyday">${OptionEveryday}</option>
<option value="Weekday">${OptionWeekdays}</option>
<option value="Weekend">${OptionWeekends}</option>

File diff suppressed because it is too large Load diff

View file

@ -1117,7 +1117,7 @@ import 'programStyles';
function importRefreshIndicator() {
if (!refreshIndicatorLoaded) {
refreshIndicatorLoaded = true;
/* eslint-disable-next-line no-unused-expressions */
/* eslint-disable-next-line @babel/no-unused-expressions */
import('emby-itemrefreshindicator');
}
}
@ -1449,7 +1449,7 @@ import 'programStyles';
const userData = item.UserData || {};
if (itemHelper.canMarkPlayed(item)) {
/* eslint-disable-next-line no-unused-expressions */
/* eslint-disable-next-line @babel/no-unused-expressions */
import('emby-playstatebutton');
html += '<button is="emby-playstatebutton" type="button" data-action="none" class="' + btnCssClass + '" data-id="' + item.Id + '" data-serverid="' + item.ServerId + '" data-itemtype="' + item.Type + '" data-played="' + (userData.Played) + '"><span class="material-icons cardOverlayButtonIcon cardOverlayButtonIcon-hover check"></span></button>';
}
@ -1457,7 +1457,7 @@ import 'programStyles';
if (itemHelper.canRate(item)) {
const likes = userData.Likes == null ? '' : userData.Likes;
/* eslint-disable-next-line no-unused-expressions */
/* eslint-disable-next-line @babel/no-unused-expressions */
import('emby-ratingbutton');
html += '<button is="emby-ratingbutton" type="button" data-action="none" class="' + btnCssClass + '" data-id="' + item.Id + '" data-serverid="' + item.ServerId + '" data-itemtype="' + item.Type + '" data-likes="' + likes + '" data-isfavorite="' + (userData.IsFavorite) + '"><span class="material-icons cardOverlayButtonIcon cardOverlayButtonIcon-hover favorite"></span></button>';
}

View file

@ -19,11 +19,11 @@ export default class channelMapper {
connectionManager.getApiClient(options.serverId).ajax({
type: 'POST',
url: ApiClient.getUrl('LiveTv/ChannelMappings'),
data: {
data: JSON.stringify({
providerId: providerId,
tunerChannelId: channelId,
providerChannelId: providerChannelId
},
}),
dataType: 'json'
}).then(mapping => {
const listItem = dom.parentWithClass(button, 'listItem');
@ -93,7 +93,7 @@ export default class channelMapper {
html += '<div class="formDialogContent smoothScrollY">';
html += '<div class="dialogContentInner dialog-content-centered">';
html += '<form style="margin:auto;">';
html += `<h1>${globalize.translate('HeaderChannels')}</h1>`;
html += `<h1>${globalize.translate('Channels')}</h1>`;
html += '<div class="channels paperList">';
html += '</div>';
html += '</form>';

View file

@ -375,7 +375,7 @@ import 'scrollStyles';
dlg.setAttribute('data-lockscroll', 'true');
}
if (options.enableHistory !== false && appRouter.enableNativeHistory()) {
if (options.enableHistory !== false) {
dlg.setAttribute('data-history', 'true');
}

View file

@ -125,7 +125,7 @@ import 'emby-button';
html += `<input is="emby-input" id="txtDirectoryPickerPath" type="text" required="required" ${readOnlyAttribute} label="${globalize.translate(labelKey)}"/>`;
html += '</div>';
if (!readOnlyAttribute) {
html += `<button type="button" is="paper-icon-button-light" class="btnRefreshDirectories emby-input-iconbutton" title="${globalize.translate('ButtonRefresh')}"><span class="material-icons search"></span></button>`;
html += `<button type="button" is="paper-icon-button-light" class="btnRefreshDirectories emby-input-iconbutton" title="${globalize.translate('Refresh')}"><span class="material-icons search"></span></button>`;
}
html += '</div>';
if (!readOnlyAttribute) {
@ -166,10 +166,10 @@ import 'emby-button';
return apiClient.ajax({
type: 'POST',
url: apiClient.getUrl('Environment/ValidatePath'),
data: {
data: JSON.stringify({
ValidateWriteable: validateWriteable,
Path: path
}
})
}).catch(response => {
if (response) {
if (response.status === 404) {

View file

@ -162,7 +162,7 @@
<div class="checkboxContainer checkboxContainer-withDescription fldBackdrops hide">
<label>
<input type="checkbox" is="emby-checkbox" id="chkBackdrops" />
<span>${EnableBackdrops}</span>
<span>${Backdrops}</span>
</label>
<div class="fieldDescription checkboxFieldDescription">${EnableBackdropsHelp}</div>
</div>
@ -170,7 +170,7 @@
<div class="checkboxContainer checkboxContainer-withDescription fldThemeSong hide">
<label>
<input type="checkbox" is="emby-checkbox" id="chkThemeSong" />
<span>${EnableThemeSongs}</span>
<span>${ThemeSongs}</span>
</label>
<div class="fieldDescription checkboxFieldDescription">${EnableThemeSongsHelp}</div>
</div>
@ -178,7 +178,7 @@
<div class="checkboxContainer checkboxContainer-withDescription fldThemeVideo hide">
<label>
<input type="checkbox" is="emby-checkbox" id="chkThemeVideo" />
<span>${EnableThemeVideos}</span>
<span>${ThemeVideos}</span>
</label>
<div class="fieldDescription checkboxFieldDescription">${EnableThemeVideosHelp}</div>
</div>

View file

@ -90,7 +90,7 @@
</div>
</div>
<div is="emby-collapse" title="${HeaderGenres}" class="genreFilters hide">
<div is="emby-collapse" title="${Genres}" class="genreFilters hide">
<div class="collapseContent filterOptions">
</div>
</div>

View file

@ -1,5 +1,5 @@
<div class="formDialogHeader">
<button is="paper-icon-button-light" class="btnCancel autoSize" title="${LabelPrevious}" tabindex="-1">
<button is="paper-icon-button-light" class="btnCancel autoSize" title="${Previous}" tabindex="-1">
<span class="material-icons arrow_back" aria-hidden="true"></span>
</button>
<h3 class="formDialogHeaderTitle">

View file

@ -547,7 +547,7 @@ function Guide(options) {
} else if (program.IsPremiere && options.showPremiereIndicator) {
indicatorHtml = '<span class="premiereTvProgram guideProgramIndicator">' + globalize.translate('Premiere') + '</span>';
} else if (program.IsSeries && !program.IsRepeat && options.showNewIndicator) {
indicatorHtml = '<span class="newTvProgram guideProgramIndicator">' + globalize.translate('AttributeNew') + '</span>';
indicatorHtml = '<span class="newTvProgram guideProgramIndicator">' + globalize.translate('New') + '</span>';
} else if (program.IsSeries && program.IsRepeat && options.showRepeatIndicator) {
indicatorHtml = '<span class="repeatTvProgram guideProgramIndicator">' + globalize.translate('Repeat') + '</span>';
}

View file

@ -29,10 +29,10 @@
</div>
<div class="guideOptions hide">
<button is="paper-icon-button-light" type="button" class="btnPreviousPage" title="${LabelPrevious}">
<button is="paper-icon-button-light" type="button" class="btnPreviousPage" title="${Previous}">
<span class="material-icons arrow_back" aria-hidden="true"></span>
</button>
<button is="paper-icon-button-light" type="button" class="btnNextPage" title="${LabelNext}">
<button is="paper-icon-button-light" type="button" class="btnNextPage" title="${Next}">
<span class="material-icons arrow_forward" aria-hidden="true"></span>
</button>
</div>

View file

@ -1,6 +1,6 @@
<form style="margin:0 auto;">
<div class="verticalSection verticalSection-extrabottompadding">
<h2 class="sectionTitle">${HeaderHome}</h2>
<h2 class="sectionTitle">${Home}</h2>
<div class="selectContainer hide selectTVHomeScreenContainer">
<select is="emby-select" class="selectTVHomeScreen" label="${LabelTVHomeScreen}">
@ -25,7 +25,7 @@
<option value="resume">${HeaderContinueWatching}</option>
<option value="resumeaudio">${HeaderContinueListening}</option>
<option value="latestmedia">${HeaderLatestMedia}</option>
<option value="nextup">${HeaderNextUp}</option>
<option value="nextup">${NextUp}</option>
<option value="livetv">${LiveTV}</option>
<option value="none">${None}</option>
</select>
@ -38,7 +38,7 @@
<option value="resume">${HeaderContinueWatching}</option>
<option value="resumeaudio">${HeaderContinueListening}</option>
<option value="latestmedia">${HeaderLatestMedia}</option>
<option value="nextup">${HeaderNextUp}</option>
<option value="nextup">${NextUp}</option>
<option value="livetv">${LiveTV}</option>
<option value="none">${None}</option>
</select>
@ -51,7 +51,7 @@
<option value="resume">${HeaderContinueWatching}</option>
<option value="resumeaudio">${HeaderContinueListening}</option>
<option value="latestmedia">${HeaderLatestMedia}</option>
<option value="nextup">${HeaderNextUp}</option>
<option value="nextup">${NextUp}</option>
<option value="livetv">${LiveTV}</option>
<option value="none">${None}</option>
</select>
@ -64,7 +64,7 @@
<option value="resume">${HeaderContinueWatching}</option>
<option value="resumeaudio">${HeaderContinueListening}</option>
<option value="latestmedia">${HeaderLatestMedia}</option>
<option value="nextup">${HeaderNextUp}</option>
<option value="nextup">${NextUp}</option>
<option value="livetv">${LiveTV}</option>
<option value="none">${None}</option>
</select>
@ -77,7 +77,7 @@
<option value="resume">${HeaderContinueWatching}</option>
<option value="resumeaudio">${HeaderContinueListening}</option>
<option value="latestmedia">${HeaderLatestMedia}</option>
<option value="nextup">${HeaderNextUp}</option>
<option value="nextup">${NextUp}</option>
<option value="livetv">${LiveTV}</option>
<option value="none">${None}</option>
</select>
@ -90,7 +90,7 @@
<option value="resume">${HeaderContinueWatching}</option>
<option value="resumeaudio">${HeaderContinueListening}</option>
<option value="latestmedia">${HeaderLatestMedia}</option>
<option value="nextup">${HeaderNextUp}</option>
<option value="nextup">${NextUp}</option>
<option value="livetv">${LiveTV}</option>
<option value="none">${None}</option>
</select>
@ -103,7 +103,7 @@
<option value="resume">${HeaderContinueWatching}</option>
<option value="resumeaudio">${HeaderContinueListening}</option>
<option value="latestmedia">${HeaderLatestMedia}</option>
<option value="nextup">${HeaderNextUp}</option>
<option value="nextup">${NextUp}</option>
<option value="livetv">${LiveTV}</option>
<option value="none">${None}</option>
</select>

View file

@ -696,12 +696,12 @@ import 'css!./homesections';
serverId: apiClient.serverId()
}) + '" class="button-flat button-flat-mini sectionTitleTextButton">';
html += '<h2 class="sectionTitle sectionTitle-cards">';
html += globalize.translate('HeaderNextUp');
html += globalize.translate('NextUp');
html += '</h2>';
html += '<span class="material-icons chevron_right"></span>';
html += '</a>';
} else {
html += '<h2 class="sectionTitle sectionTitle-cards">' + globalize.translate('HeaderNextUp') + '</h2>';
html += '<h2 class="sectionTitle sectionTitle-cards">' + globalize.translate('NextUp') + '</h2>';
}
html += '</div>';

View file

@ -8,7 +8,6 @@ import browser from 'browser';
import actionsheet from 'actionsheet';
/* eslint-disable indent */
export function getCommands(options) {
const item = options.item;
const user = options.user;

View file

@ -2,7 +2,7 @@
<button is="paper-icon-button-light" class="btnCancel autoSize" tabindex="-1">
<span class="material-icons arrow_back"></span>
</button>
<h3 class="formDialogHeaderTitle">${HeaderMediaInfo}</h3>
<h3 class="formDialogHeaderTitle">${MoreMediaInfo}</h3>
</div>
<div class="formDialogContent smoothScrollY">

View file

@ -75,9 +75,9 @@ import 'emby-input';
html += '</h3>';
html += '</div>';
if (i > 0) {
html += `<button type="button" is="paper-icon-button-light" title="${globalize.translate('ButtonUp')}" class="btnSortableMoveUp btnSortable" data-pluginindex="${i}"><span class="material-icons keyboard_arrow_up"></span></button>`;
html += `<button type="button" is="paper-icon-button-light" title="${globalize.translate('Up')}" class="btnSortableMoveUp btnSortable" data-pluginindex="${i}"><span class="material-icons keyboard_arrow_up"></span></button>`;
} else if (plugins.length > 1) {
html += `<button type="button" is="paper-icon-button-light" title="${globalize.translate('ButtonDown')}" class="btnSortableMoveDown btnSortable" data-pluginindex="${i}"><span class="material-icons keyboard_arrow_down"></span></button>`;
html += `<button type="button" is="paper-icon-button-light" title="${globalize.translate('Down')}" class="btnSortableMoveDown btnSortable" data-pluginindex="${i}"><span class="material-icons keyboard_arrow_down"></span></button>`;
}
html += '</div>';
}
@ -131,9 +131,9 @@ import 'emby-input';
html += '</h3>';
html += '</div>';
if (index > 0) {
html += '<button type="button" is="paper-icon-button-light" title="' + globalize.translate('ButtonUp') + '" class="btnSortableMoveUp btnSortable" data-pluginindex="' + index + '"><span class="material-icons keyboard_arrow_up"></span></button>';
html += '<button type="button" is="paper-icon-button-light" title="' + globalize.translate('Up') + '" class="btnSortableMoveUp btnSortable" data-pluginindex="' + index + '"><span class="material-icons keyboard_arrow_up"></span></button>';
} else if (plugins.length > 1) {
html += '<button type="button" is="paper-icon-button-light" title="' + globalize.translate('ButtonDown') + '" class="btnSortableMoveDown btnSortable" data-pluginindex="' + index + '"><span class="material-icons keyboard_arrow_down"></span></button>';
html += '<button type="button" is="paper-icon-button-light" title="' + globalize.translate('Down') + '" class="btnSortableMoveDown btnSortable" data-pluginindex="' + index + '"><span class="material-icons keyboard_arrow_down"></span></button>';
}
html += '</div>';
});
@ -197,9 +197,9 @@ import 'emby-input';
html += '</h3>';
html += '</div>';
if (i > 0) {
html += `<button type="button" is="paper-icon-button-light" title="${globalize.translate('ButtonUp')}" class="btnSortableMoveUp btnSortable" data-pluginindex="${i}"><span class="material-icons keyboard_arrow_up"></span></button>`;
html += `<button type="button" is="paper-icon-button-light" title="${globalize.translate('Up')}" class="btnSortableMoveUp btnSortable" data-pluginindex="${i}"><span class="material-icons keyboard_arrow_up"></span></button>`;
} else if (plugins.length > 1) {
html += `<button type="button" is="paper-icon-button-light" title="${globalize.translate('ButtonDown')}" class="btnSortableMoveDown btnSortable" data-pluginindex="${i}"><span class="material-icons keyboard_arrow_down"></span></button>`;
html += `<button type="button" is="paper-icon-button-light" title="${globalize.translate('Down')}" class="btnSortableMoveDown btnSortable" data-pluginindex="${i}"><span class="material-icons keyboard_arrow_down"></span></button>`;
}
html += '</div>';
}
@ -236,9 +236,9 @@ import 'emby-input';
html += '</h3>';
html += '</div>';
if (i > 0) {
html += '<button type="button" is="paper-icon-button-light" title="' + globalize.translate('ButtonUp') + '" class="btnSortableMoveUp btnSortable" data-pluginindex="' + i + '"><span class="material-icons keyboard_arrow_up"></span></button>';
html += '<button type="button" is="paper-icon-button-light" title="' + globalize.translate('Up') + '" class="btnSortableMoveUp btnSortable" data-pluginindex="' + i + '"><span class="material-icons keyboard_arrow_up"></span></button>';
} else if (plugins.length > 1) {
html += '<button type="button" is="paper-icon-button-light" title="' + globalize.translate('ButtonDown') + '" class="btnSortableMoveDown btnSortable" data-pluginindex="' + i + '"><span class="material-icons keyboard_arrow_down"></span></button>';
html += '<button type="button" is="paper-icon-button-light" title="' + globalize.translate('Down') + '" class="btnSortableMoveDown btnSortable" data-pluginindex="' + i + '"><span class="material-icons keyboard_arrow_down"></span></button>';
}
html += '</div>';
}
@ -291,13 +291,13 @@ import 'emby-input';
const btnSortable = elem.querySelector('.btnSortable');
const inner = btnSortable.querySelector('.material-icons');
if (elem.previousSibling) {
btnSortable.title = globalize.translate('ButtonUp');
btnSortable.title = globalize.translate('Up');
btnSortable.classList.add('btnSortableMoveUp');
btnSortable.classList.remove('btnSortableMoveDown');
inner.classList.remove('keyboard_arrow_down');
inner.classList.add('keyboard_arrow_up');
} else {
btnSortable.title = globalize.translate('ButtonDown');
btnSortable.title = globalize.translate('Down');
btnSortable.classList.remove('btnSortableMoveUp');
btnSortable.classList.add('btnSortableMoveDown');
inner.classList.remove('keyboard_arrow_up');

View file

@ -88,7 +88,7 @@
<div class="checkboxContainer checkboxContainer-withDescription hide chkImportMissingEpisodesContainer advanced">
<label>
<input is="emby-checkbox" type="checkbox" id="chkImportMissingEpisodes" />
<span>${LabelDisplayMissingEpisodesWithinSeasons}</span>
<span>${DisplayMissingEpisodesWithinSeasons}</span>
</label>
<div class="fieldDescription checkboxFieldDescription">${ImportMissingEpisodesHelp}</div>
</div>

View file

@ -24,7 +24,7 @@
<div class="folders">
<div style="display: flex; align-items: center;">
<h1 style="margin: .5em 0;">${HeadersFolders}</h1>
<h1 style="margin: .5em 0;">${Folders}</h1>
<button is="emby-button" type="button" class="fab btnAddFolder submit" style="margin-left:1em;" title="${Add}">
<span class="material-icons add"></span>
</button>

View file

@ -76,7 +76,7 @@ import 'flexStyles';
confirm({
title: globalize.translate('HeaderRemoveMediaLocation'),
text: globalize.translate('MessageConfirmRemoveMediaLocation'),
confirmText: globalize.translate('ButtonDelete'),
confirmText: globalize.translate('Delete'),
primary: 'delete'
}).then(() => {
const refreshAfterChange = currentOptions.refresh;

View file

@ -18,7 +18,7 @@
<div class="folders hide">
<div style="display: flex; align-items: center;">
<h1 style="margin: .5em 0;">${HeadersFolders}</h1>
<h1 style="margin: .5em 0;">${Folders}</h1>
<button is="emby-button" type="button" class="fab btnAddFolder submit" style="margin-left:1em;" title="${Add}">
<span class="material-icons add"></span>
</button>

View file

@ -9,7 +9,6 @@ import 'programStyles';
import 'emby-button';
/* eslint-disable indent */
function getTimerIndicator(item) {
let status;
@ -208,7 +207,7 @@ import 'emby-button';
});
} else if (item.IsSeries && !item.IsRepeat) {
miscInfo.push({
html: `<div class="mediaInfoProgramAttribute mediaInfoItem newTvProgram">${globalize.translate('AttributeNew')}</div>`
html: `<div class="mediaInfoProgramAttribute mediaInfoItem newTvProgram">${globalize.translate('New')}</div>`
});
} else if (item.IsSeries && item.IsRepeat) {
miscInfo.push({

View file

@ -198,7 +198,7 @@ import 'css!./multiSelect';
if (user.Policy.EnableContentDownloading && appHost.supports('filedownload')) {
menuItems.push({
name: globalize.translate('ButtonDownload'),
name: globalize.translate('Download'),
id: 'download',
icon: 'file_download'
});

View file

@ -1,134 +1,140 @@
define(['appSettings', 'pluginManager'], function (appSettings, pluginManager) {
'use strict';
import appSettings from 'appSettings';
import pluginManager from 'pluginManager';
/* eslint-disable indent */
var settingsKey = 'installedpackages1';
class PackageManager {
#packagesList = [];
#settingsKey = 'installedpackages1';
function addPackage(packageManager, pkg) {
packageManager.packagesList = packageManager.packagesList.filter(function (p) {
return p.name !== pkg.name;
});
init() {
console.groupCollapsed('loading packages');
var manifestUrls = JSON.parse(appSettings.get(this.#settingsKey) || '[]');
packageManager.packagesList.push(pkg);
}
return Promise.all(manifestUrls.map((url) => {
return this.loadPackage(url);
}))
.then(() => {
console.debug('finished loading packages');
return Promise.resolve();
})
.catch(() => {
return Promise.resolve();
}).finally(() => {
console.groupEnd('loading packages');
});
}
function removeUrl(url) {
var manifestUrls = JSON.parse(appSettings.get(settingsKey) || '[]');
get packages() {
return this.#packagesList.slice(0);
}
manifestUrls = manifestUrls.filter(function (i) {
return i !== url;
});
install(url) {
return this.loadPackage(url, true).then((pkg) => {
var manifestUrls = JSON.parse(appSettings.get(this.#settingsKey) || '[]');
appSettings.set(settingsKey, JSON.stringify(manifestUrls));
}
function loadPackage(packageManager, url, throwError) {
return new Promise(function (resolve, reject) {
var xhr = new XMLHttpRequest();
var originalUrl = url;
url += url.indexOf('?') === -1 ? '?' : '&';
url += 't=' + new Date().getTime();
xhr.open('GET', url, true);
var onError = function () {
if (throwError === true) {
reject();
} else {
removeUrl(originalUrl);
resolve();
if (!manifestUrls.includes(url)) {
manifestUrls.push(url);
appSettings.set(this.#settingsKey, JSON.stringify(manifestUrls));
}
};
xhr.onload = function (e) {
if (this.status < 400) {
var pkg = JSON.parse(this.response);
pkg.url = originalUrl;
return pkg;
});
}
addPackage(packageManager, pkg);
uninstall(name) {
var pkg = this.#packagesList.filter((p) => {
return p.name === name;
})[0];
var plugins = pkg.plugins || [];
if (pkg.plugin) {
plugins.push(pkg.plugin);
}
var promises = plugins.map(function (pluginUrl) {
return pluginManager.loadPlugin(packageManager.mapPath(pkg, pluginUrl));
});
Promise.all(promises).then(resolve, resolve);
} else {
onError();
}
};
if (pkg) {
this.#packagesList = this.#packagesList.filter((p) => {
return p.name !== name;
});
xhr.onerror = onError;
xhr.send();
});
}
function PackageManager() {
this.packagesList = [];
}
PackageManager.prototype.init = function () {
var manifestUrls = JSON.parse(appSettings.get(settingsKey) || '[]');
var instance = this;
return Promise.all(manifestUrls.map(function (u) {
return loadPackage(instance, u);
})).then(function () {
return Promise.resolve();
}, function () {
return Promise.resolve();
});
};
PackageManager.prototype.packages = function () {
return this.packagesList.slice(0);
};
PackageManager.prototype.install = function (url) {
return loadPackage(this, url, true).then(function (pkg) {
var manifestUrls = JSON.parse(appSettings.get(settingsKey) || '[]');
if (manifestUrls.indexOf(url) === -1) {
manifestUrls.push(url);
appSettings.set(settingsKey, JSON.stringify(manifestUrls));
this.removeUrl(pkg.url);
}
return pkg;
});
};
return Promise.resolve();
}
PackageManager.prototype.uninstall = function (name) {
var pkg = this.packagesList.filter(function (p) {
return p.name === name;
})[0];
mapPath(pkg, pluginUrl) {
var urlLower = pluginUrl.toLowerCase();
if (urlLower.startsWith('http:') || urlLower.startsWith('https:') || urlLower.startsWith('file:')) {
return pluginUrl;
}
if (pkg) {
this.packagesList = this.packagesList.filter(function (p) {
return p.name !== name;
var packageUrl = pkg.url;
packageUrl = packageUrl.substring(0, packageUrl.lastIndexOf('/'));
packageUrl += '/';
packageUrl += pluginUrl;
return packageUrl;
}
addPackage(pkg) {
this.#packagesList = this.#packagesList.filter((p) => {
return p.name !== pkg.name;
});
removeUrl(pkg.url);
this.#packagesList.push(pkg);
}
return Promise.resolve();
};
removeUrl(url) {
var manifestUrls = JSON.parse(appSettings.get(this.#settingsKey) || '[]');
PackageManager.prototype.mapPath = function (pkg, pluginUrl) {
var urlLower = pluginUrl.toLowerCase();
if (urlLower.indexOf('http:') === 0 || urlLower.indexOf('https:') === 0 || urlLower.indexOf('file:') === 0) {
return pluginUrl;
manifestUrls = manifestUrls.filter((i) => {
return i !== url;
});
appSettings.set(this.#settingsKey, JSON.stringify(manifestUrls));
}
var packageUrl = pkg.url;
packageUrl = packageUrl.substring(0, packageUrl.lastIndexOf('/'));
loadPackage(url, throwError = false) {
return new Promise((resolve, reject) => {
var xhr = new XMLHttpRequest();
var originalUrl = url;
url += url.indexOf('?') === -1 ? '?' : '&';
url += 't=' + new Date().getTime();
packageUrl += '/';
packageUrl += pluginUrl;
xhr.open('GET', url, true);
return packageUrl;
};
var onError = () => {
if (throwError === true) {
reject();
} else {
this.removeUrl(originalUrl);
resolve();
}
};
return new PackageManager();
});
xhr.onload = () => {
if (this.status < 400) {
var pkg = JSON.parse(this.response);
pkg.url = originalUrl;
this.addPackage(pkg);
var plugins = pkg.plugins || [];
if (pkg.plugin) {
plugins.push(pkg.plugin);
}
var promises = plugins.map((pluginUrl) => {
return pluginManager.loadPlugin(this.mapPath(pkg, pluginUrl));
});
Promise.all(promises).then(resolve, resolve);
} else {
onError();
}
};
xhr.onerror = onError;
xhr.send();
});
}
}
/* eslint-enable indent */
export default new PackageManager();

View file

@ -1112,6 +1112,52 @@ class PlaybackManager {
}
};
self.increasePlaybackRate = function (player) {
player = player || self._currentPlayer;
if (player) {
let current = self.getPlaybackRate(player);
let supported = self.getSupportedPlaybackRates(player);
let index = -1;
for (let i = 0, length = supported.length; i < length; i++) {
if (supported[i].id === current) {
index = i;
break;
}
}
index = Math.min(index + 1, supported.length - 1);
self.setPlaybackRate(supported[index].id, player);
}
};
self.decreasePlaybackRate = function (player) {
player = player || self._currentPlayer;
if (player) {
let current = self.getPlaybackRate(player);
let supported = self.getSupportedPlaybackRates(player);
let index = -1;
for (let i = 0, length = supported.length; i < length; i++) {
if (supported[i].id === current) {
index = i;
break;
}
}
index = Math.max(index - 1, 0);
self.setPlaybackRate(supported[index].id, player);
}
};
self.getSupportedPlaybackRates = function (player) {
player = player || self._currentPlayer;
if (player && player.getSupportedPlaybackRates) {
return player.getSupportedPlaybackRates();
}
return [];
};
let brightnessOsdLoaded;
self.setBrightness = function (val, player) {
player = player || self._currentPlayer;
@ -1416,8 +1462,8 @@ class PlaybackManager {
self.toggleFullscreen = function (player) {
player = player || self._currentPlayer;
if (!player.isLocalPlayer || player.toggleFulscreen) {
return player.toggleFulscreen();
if (!player.isLocalPlayer || player.toggleFullscreen) {
return player.toggleFullscreen();
}
if (screenfull.isEnabled) {
@ -3697,6 +3743,9 @@ class PlaybackManager {
case 'SetAspectRatio':
this.setAspectRatio(cmd.Arguments.AspectRatio, player);
break;
case 'PlaybackRate':
this.setPlaybackRate(cmd.Arguments.PlaybackRate, player);
break;
case 'SetBrightness':
this.setBrightness(cmd.Arguments.Brightness, player);
break;

View file

@ -149,6 +149,28 @@ function showAspectRatioMenu(player, btn) {
});
}
function showPlaybackRateMenu(player, btn) {
// each has a name and id
const currentId = playbackManager.getPlaybackRate(player);
const menuItems = playbackManager.getSupportedPlaybackRates(player).map(i => ({
id: i.id,
name: i.name,
selected: i.id === currentId
}));
return actionsheet.show({
items: menuItems,
positionTo: btn
}).then(function (id) {
if (id) {
playbackManager.setPlaybackRate(id, player);
return Promise.resolve();
}
return Promise.reject();
});
}
function showWithUser(options, player, user) {
var supportedCommands = playbackManager.getSupportedCommands(player);
@ -166,6 +188,17 @@ function showWithUser(options, player, user) {
});
}
if (supportedCommands.indexOf('PlaybackRate') !== -1) {
const currentPlaybackRateId = playbackManager.getPlaybackRate(player);
const currentPlaybackRate = playbackManager.getSupportedPlaybackRates(player).filter(i => i.id === currentPlaybackRateId)[0];
menuItems.push({
name: globalize.translate('PlaybackRate'),
id: 'playbackrate',
asideText: currentPlaybackRate ? currentPlaybackRate.name : null
});
}
if (user && user.Policy.EnableVideoPlaybackTranscoding) {
var secondaryQualityText = getQualitySecondaryText(player);
@ -230,6 +263,8 @@ function handleSelectedOption(id, options, player) {
return showQualityMenu(player, options.positionTo);
case 'aspectratio':
return showAspectRatioMenu(player, options.positionTo);
case 'playbackrate':
return showPlaybackRateMenu(player, options.positionTo);
case 'repeatmode':
return showRepeatModeMenu(player, options.positionTo);
case 'stats':

View file

@ -1,37 +1,38 @@
define(['events', 'globalize'], function (events, globalize) {
'use strict';
import events from 'events';
import globalize from 'globalize';
/* eslint-disable indent */
// TODO: replace with each plugin version
var cacheParam = new Date().getTime();
function loadStrings(plugin) {
var strings = plugin.getTranslations ? plugin.getTranslations() : [];
return globalize.loadStrings({
name: plugin.id || plugin.packageName,
strings: strings
});
}
class PluginManager {
pluginsList = [];
function definePluginRoute(pluginManager, route, plugin) {
route.contentPath = pluginManager.mapPath(plugin, route.path);
route.path = pluginManager.mapRoute(plugin, route);
get plugins() {
return this.pluginsList;
}
Emby.App.defineRoute(route, plugin.id);
}
#loadStrings(plugin) {
var strings = plugin.getTranslations ? plugin.getTranslations() : [];
return globalize.loadStrings({
name: plugin.id || plugin.packageName,
strings: strings
});
}
function PluginManager() {
this.pluginsList = [];
}
#definePluginRoute(route, plugin) {
route.contentPath = this.mapPath(plugin, route.path);
route.path = this.#mapRoute(plugin, route);
PluginManager.prototype.loadPlugin = function(pluginSpec) {
var instance = this;
Emby.App.defineRoute(route, plugin.id);
}
function registerPlugin(plugin) {
instance.register(plugin);
#registerPlugin(plugin) {
this.#register(plugin);
if (plugin.getRoutes) {
plugin.getRoutes().forEach(function (route) {
definePluginRoute(instance, route, plugin);
plugin.getRoutes().forEach((route) => {
this.#definePluginRoute(route, plugin);
});
}
@ -40,7 +41,7 @@ define(['events', 'globalize'], function (events, globalize) {
return Promise.resolve(plugin);
} else {
return new Promise((resolve, reject) => {
loadStrings(plugin)
this.#loadStrings(plugin)
.then(function () {
resolve(plugin);
})
@ -49,103 +50,102 @@ define(['events', 'globalize'], function (events, globalize) {
}
}
if (typeof pluginSpec === 'string') {
console.debug('Loading plugin (via deprecated requirejs method): ' + pluginSpec);
loadPlugin(pluginSpec) {
if (typeof pluginSpec === 'string') {
console.debug('Loading plugin (via deprecated requirejs method): ' + pluginSpec);
return new Promise(function (resolve, reject) {
require([pluginSpec], (pluginFactory) => {
var plugin = pluginFactory.default ? new pluginFactory.default() : new pluginFactory();
return new Promise((resolve, reject) => {
require([pluginSpec], (pluginFactory) => {
var plugin = pluginFactory.default ? new pluginFactory.default() : new pluginFactory();
// See if it's already installed
var existing = instance.pluginsList.filter(function (p) {
return p.id === plugin.id;
})[0];
// See if it's already installed
var existing = this.pluginsList.filter(function (p) {
return p.id === plugin.id;
})[0];
if (existing) {
resolve(pluginSpec);
}
if (existing) {
resolve(pluginSpec);
}
plugin.installUrl = pluginSpec;
plugin.installUrl = pluginSpec;
var separatorIndex = Math.max(pluginSpec.lastIndexOf('/'), pluginSpec.lastIndexOf('\\'));
plugin.baseUrl = pluginSpec.substring(0, separatorIndex);
var separatorIndex = Math.max(pluginSpec.lastIndexOf('/'), pluginSpec.lastIndexOf('\\'));
plugin.baseUrl = pluginSpec.substring(0, separatorIndex);
var paths = {};
paths[plugin.id] = plugin.baseUrl;
var paths = {};
paths[plugin.id] = plugin.baseUrl;
requirejs.config({
waitSeconds: 0,
paths: paths
requirejs.config({
waitSeconds: 0,
paths: paths
});
this.#registerPlugin(plugin).then(resolve).catch(reject);
});
registerPlugin(plugin).then(resolve).catch(reject);
});
} else if (pluginSpec.then) {
return pluginSpec.then(pluginBuilder => {
return pluginBuilder();
}).then((plugin) => {
console.debug(`Plugin loaded: ${plugin.id}`);
return this.#registerPlugin(plugin);
});
} else {
const err = new TypeError('Plugins have to be a Promise that resolves to a plugin builder function or a RequireJS url (deprecated)');
console.error(err);
return Promise.reject(err);
}
}
// In lieu of automatic discovery, plugins will register dynamic objects
// Each object will have the following properties:
// name
// type (skin, screensaver, etc)
#register(obj) {
this.pluginsList.push(obj);
events.trigger(this, 'registered', [obj]);
}
ofType(type) {
return this.pluginsList.filter((o) => {
return o.type === type;
});
} else if (pluginSpec.then) {
return pluginSpec.then(pluginBuilder => {
return pluginBuilder();
}).then(plugin => {
console.debug(`Plugin loaded: ${plugin.id}`);
return registerPlugin(plugin);
});
} else {
const err = new Error('Plugins have to be a Promise that resolves to a plugin builder function or a requirejs urls (deprecated)');
console.error(err);
return Promise.reject(err);
}
};
// In lieu of automatic discovery, plugins will register dynamic objects
// Each object will have the following properties:
// name
// type (skin, screensaver, etc)
PluginManager.prototype.register = function (obj) {
this.pluginsList.push(obj);
events.trigger(this, 'registered', [obj]);
};
PluginManager.prototype.ofType = function (type) {
return this.pluginsList.filter(function (o) {
return o.type === type;
});
};
PluginManager.prototype.plugins = function () {
return this.pluginsList;
};
PluginManager.prototype.mapRoute = function (plugin, route) {
if (typeof plugin === 'string') {
plugin = this.pluginsList.filter(function (p) {
return (p.id || p.packageName) === plugin;
})[0];
}
route = route.path || route;
#mapRoute(plugin, route) {
if (typeof plugin === 'string') {
plugin = this.pluginsList.filter((p) => {
return (p.id || p.packageName) === plugin;
})[0];
}
if (route.toLowerCase().indexOf('http') === 0) {
return route;
route = route.path || route;
if (route.toLowerCase().startsWith('http')) {
return route;
}
return '/plugins/' + plugin.id + '/' + route;
}
return '/plugins/' + plugin.id + '/' + route;
};
mapPath(plugin, path, addCacheParam) {
if (typeof plugin === 'string') {
plugin = this.pluginsList.filter((p) => {
return (p.id || p.packageName) === plugin;
})[0];
}
PluginManager.prototype.mapPath = function (plugin, path, addCacheParam) {
if (typeof plugin === 'string') {
plugin = this.pluginsList.filter(function (p) {
return (p.id || p.packageName) === plugin;
})[0];
var url = plugin.baseUrl + '/' + path;
if (addCacheParam) {
url += url.includes('?') ? '&' : '?';
url += 'v=' + cacheParam;
}
return url;
}
}
var url = plugin.baseUrl + '/' + path;
/* eslint-enable indent */
if (addCacheParam) {
url += url.indexOf('?') === -1 ? '?' : '&';
url += 'v=' + cacheParam;
}
return url;
};
return new PluginManager();
});
export default new PluginManager();

View file

@ -118,7 +118,7 @@ function reload(context, programId, serverId, refreshRecordingStateOnly) {
function executeCloseAction(action, programId, serverId) {
if (action === 'play') {
import('playbackManager').then(({default: playbackManager}) => {
import('playbackManager').then(({ default: playbackManager }) => {
const apiClient = connectionManager.getApiClient(serverId);
apiClient.getLiveTvProgram(programId, apiClient.getCurrentUserId()).then(function (item) {
@ -138,7 +138,7 @@ function showEditor(itemId, serverId) {
loading.show();
import('text!./recordingcreator.template.html').then(({default: template}) => {
import('text!./recordingcreator.template.html').then(({ default: template }) => {
const dialogOptions = {
removeOnClose: true,
scrollY: false

View file

@ -1,151 +1,155 @@
define(['dialogHelper', 'globalize', 'layoutManager', 'mediaInfo', 'apphost', 'connectionManager', 'require', 'loading', 'scrollHelper', 'imageLoader', 'scrollStyles', 'emby-button', 'emby-collapse', 'emby-input', 'paper-icon-button-light', 'css!./../formdialog', 'css!./recordingcreator', 'material-icons', 'flexStyles'], function (dialogHelper, globalize, layoutManager, mediaInfo, appHost, connectionManager, require, loading, scrollHelper, imageLoader) {
'use strict';
import dialogHelper from 'dialogHelper';
import globalize from 'globalize';
import layoutManager from 'layoutManager';
import connectionManager from 'connectionManager';
import loading from 'loading';
import scrollHelper from 'scrollHelper';
import 'scrollStyles';
import 'emby-button';
import 'emby-collapse';
import 'emby-input';
import 'paper-icon-button-light';
import 'css!./../formdialog';
import 'css!./recordingcreator';
import 'material-icons';
import 'flexStyles';
scrollHelper = scrollHelper.default || scrollHelper;
loading = loading.default || loading;
layoutManager = layoutManager.default || layoutManager;
let currentDialog;
let recordingDeleted = false;
let currentItemId;
let currentServerId;
let currentResolve;
var currentDialog;
var recordingDeleted = false;
var currentItemId;
var currentServerId;
var currentResolve;
function deleteTimer(apiClient, timerId) {
return import('recordingHelper').then(({ default: recordingHelper }) => {
recordingHelper.cancelTimerWithConfirmation(timerId, apiClient.serverId());
});
}
function deleteTimer(apiClient, timerId) {
return new Promise(function (resolve, reject) {
require(['recordingHelper'], function (recordingHelper) {
recordingHelper = recordingHelper.default || recordingHelper;
function renderTimer(context, item, apiClient) {
context.querySelector('#txtPrePaddingMinutes').value = item.PrePaddingSeconds / 60;
context.querySelector('#txtPostPaddingMinutes').value = item.PostPaddingSeconds / 60;
recordingHelper.cancelTimerWithConfirmation(timerId, apiClient.serverId()).then(resolve, reject);
});
loading.hide();
}
function closeDialog(isDeleted) {
recordingDeleted = isDeleted;
dialogHelper.close(currentDialog);
}
function onSubmit(e) {
const form = this;
const apiClient = connectionManager.getApiClient(currentServerId);
apiClient.getLiveTvTimer(currentItemId).then(function (item) {
item.PrePaddingSeconds = form.querySelector('#txtPrePaddingMinutes').value * 60;
item.PostPaddingSeconds = form.querySelector('#txtPostPaddingMinutes').value * 60;
apiClient.updateLiveTvTimer(item).then(currentResolve);
});
e.preventDefault();
// Disable default form submission
return false;
}
function init(context) {
context.querySelector('.btnCancel').addEventListener('click', function () {
closeDialog(false);
});
context.querySelector('.btnCancelRecording').addEventListener('click', function () {
const apiClient = connectionManager.getApiClient(currentServerId);
deleteTimer(apiClient, currentItemId).then(function () {
closeDialog(true);
});
}
});
function renderTimer(context, item, apiClient) {
context.querySelector('#txtPrePaddingMinutes').value = item.PrePaddingSeconds / 60;
context.querySelector('#txtPostPaddingMinutes').value = item.PostPaddingSeconds / 60;
context.querySelector('form').addEventListener('submit', onSubmit);
}
function reload(context, id) {
loading.show();
currentItemId = id;
const apiClient = connectionManager.getApiClient(currentServerId);
apiClient.getLiveTvTimer(id).then(function (result) {
renderTimer(context, result, apiClient);
loading.hide();
}
});
}
function closeDialog(isDeleted) {
recordingDeleted = isDeleted;
dialogHelper.close(currentDialog);
}
function onSubmit(e) {
var form = this;
var apiClient = connectionManager.getApiClient(currentServerId);
apiClient.getLiveTvTimer(currentItemId).then(function (item) {
item.PrePaddingSeconds = form.querySelector('#txtPrePaddingMinutes').value * 60;
item.PostPaddingSeconds = form.querySelector('#txtPostPaddingMinutes').value * 60;
apiClient.updateLiveTvTimer(item).then(currentResolve);
});
e.preventDefault();
// Disable default form submission
return false;
}
function init(context) {
context.querySelector('.btnCancel').addEventListener('click', function () {
closeDialog(false);
});
context.querySelector('.btnCancelRecording').addEventListener('click', function () {
var apiClient = connectionManager.getApiClient(currentServerId);
deleteTimer(apiClient, currentItemId).then(function () {
closeDialog(true);
});
});
context.querySelector('form').addEventListener('submit', onSubmit);
}
function reload(context, id) {
function showEditor(itemId, serverId, options) {
return new Promise(function (resolve, reject) {
recordingDeleted = false;
currentServerId = serverId;
loading.show();
currentItemId = id;
options = options || {};
currentResolve = resolve;
var apiClient = connectionManager.getApiClient(currentServerId);
apiClient.getLiveTvTimer(id).then(function (result) {
renderTimer(context, result, apiClient);
loading.hide();
});
}
import('text!./recordingeditor.template.html').then(({default: template}) => {
const dialogOptions = {
removeOnClose: true,
scrollY: false
};
function showEditor(itemId, serverId, options) {
return new Promise(function (resolve, reject) {
recordingDeleted = false;
currentServerId = serverId;
loading.show();
options = options || {};
currentResolve = resolve;
if (layoutManager.tv) {
dialogOptions.size = 'fullscreen';
}
require(['text!./recordingeditor.template.html'], function (template) {
var dialogOptions = {
removeOnClose: true,
scrollY: false
};
const dlg = dialogHelper.createDialog(dialogOptions);
if (layoutManager.tv) {
dialogOptions.size = 'fullscreen';
dlg.classList.add('formDialog');
dlg.classList.add('recordingDialog');
if (!layoutManager.tv) {
dlg.style['min-width'] = '20%';
dlg.classList.add('dialog-fullscreen-lowres');
}
let html = '';
html += globalize.translateHtml(template, 'core');
dlg.innerHTML = html;
if (options.enableCancel === false) {
dlg.querySelector('.formDialogFooter').classList.add('hide');
}
currentDialog = dlg;
dlg.addEventListener('closing', function () {
if (!recordingDeleted) {
dlg.querySelector('.btnSubmit').click();
}
var dlg = dialogHelper.createDialog(dialogOptions);
dlg.classList.add('formDialog');
dlg.classList.add('recordingDialog');
if (!layoutManager.tv) {
dlg.style['min-width'] = '20%';
dlg.classList.add('dialog-fullscreen-lowres');
}
var html = '';
html += globalize.translateHtml(template, 'core');
dlg.innerHTML = html;
if (options.enableCancel === false) {
dlg.querySelector('.formDialogFooter').classList.add('hide');
}
currentDialog = dlg;
dlg.addEventListener('closing', function () {
if (!recordingDeleted) {
dlg.querySelector('.btnSubmit').click();
}
});
dlg.addEventListener('close', function () {
if (recordingDeleted) {
resolve({
updated: true,
deleted: true
});
}
});
if (layoutManager.tv) {
scrollHelper.centerFocus.on(dlg.querySelector('.formDialogContent'), false);
}
init(dlg);
reload(dlg, itemId);
dialogHelper.open(dlg);
});
});
}
return {
show: showEditor
};
});
dlg.addEventListener('close', function () {
if (recordingDeleted) {
resolve({
updated: true,
deleted: true
});
}
});
if (layoutManager.tv) {
scrollHelper.centerFocus.on(dlg.querySelector('.formDialogContent'), false);
}
init(dlg);
reload(dlg, itemId);
dialogHelper.open(dlg);
});
});
}
export default {
show: showEditor
};

View file

@ -1,223 +1,126 @@
define(['globalize', 'connectionManager', 'serverNotifications', 'require', 'loading', 'apphost', 'dom', 'recordingHelper', 'events', 'paper-icon-button-light', 'emby-button', 'css!./recordingfields', 'flexStyles'], function (globalize, connectionManager, serverNotifications, require, loading, appHost, dom, recordingHelper, events) {
'use strict';
import globalize from 'globalize';
import connectionManager from 'connectionManager';
import serverNotifications from 'serverNotifications';
import loading from 'loading';
import dom from 'dom';
import recordingHelper from 'recordingHelper';
import events from 'events';
import 'paper-icon-button-light';
import 'emby-button';
import 'css!./recordingfields';
import 'flexStyles';
serverNotifications = serverNotifications.default || serverNotifications;
recordingHelper = recordingHelper.default || recordingHelper;
loading = loading.default || loading;
/*eslint prefer-const: "error"*/
function loadData(parent, program, apiClient) {
if (program.IsSeries) {
parent.querySelector('.recordSeriesContainer').classList.remove('hide');
function loadData(parent, program, apiClient) {
if (program.IsSeries) {
parent.querySelector('.recordSeriesContainer').classList.remove('hide');
} else {
parent.querySelector('.recordSeriesContainer').classList.add('hide');
}
if (program.SeriesTimerId) {
parent.querySelector('.btnManageSeriesRecording').classList.remove('hide');
parent.querySelector('.seriesRecordingButton .recordingIcon').classList.add('recordingIcon-active');
parent.querySelector('.seriesRecordingButton .buttonText').innerHTML = globalize.translate('CancelSeries');
} else {
parent.querySelector('.btnManageSeriesRecording').classList.add('hide');
parent.querySelector('.seriesRecordingButton .recordingIcon').classList.remove('recordingIcon-active');
parent.querySelector('.seriesRecordingButton .buttonText').innerHTML = globalize.translate('RecordSeries');
}
if (program.TimerId && program.Status !== 'Cancelled') {
parent.querySelector('.btnManageRecording').classList.remove('hide');
parent.querySelector('.singleRecordingButton .recordingIcon').classList.add('recordingIcon-active');
if (program.Status === 'InProgress') {
parent.querySelector('.singleRecordingButton .buttonText').innerHTML = globalize.translate('StopRecording');
} else {
parent.querySelector('.recordSeriesContainer').classList.add('hide');
parent.querySelector('.singleRecordingButton .buttonText').innerHTML = globalize.translate('DoNotRecord');
}
} else {
parent.querySelector('.btnManageRecording').classList.add('hide');
parent.querySelector('.singleRecordingButton .recordingIcon').classList.remove('recordingIcon-active');
parent.querySelector('.singleRecordingButton .buttonText').innerHTML = globalize.translate('Record');
}
}
if (program.SeriesTimerId) {
parent.querySelector('.btnManageSeriesRecording').classList.remove('hide');
parent.querySelector('.seriesRecordingButton .recordingIcon').classList.add('recordingIcon-active');
parent.querySelector('.seriesRecordingButton .buttonText').innerHTML = globalize.translate('CancelSeries');
} else {
parent.querySelector('.btnManageSeriesRecording').classList.add('hide');
parent.querySelector('.seriesRecordingButton .recordingIcon').classList.remove('recordingIcon-active');
parent.querySelector('.seriesRecordingButton .buttonText').innerHTML = globalize.translate('RecordSeries');
function fetchData(instance) {
const options = instance.options;
const apiClient = connectionManager.getApiClient(options.serverId);
options.parent.querySelector('.recordingFields').classList.remove('hide');
return apiClient.getLiveTvProgram(options.programId, apiClient.getCurrentUserId()).then(function (program) {
instance.TimerId = program.TimerId;
instance.Status = program.Status;
instance.SeriesTimerId = program.SeriesTimerId;
loadData(options.parent, program, apiClient);
});
}
function onTimerChangedExternally(e, apiClient, data) {
const options = this.options;
let refresh = false;
if (data.Id) {
if (this.TimerId === data.Id) {
refresh = true;
}
if (program.TimerId && program.Status !== 'Cancelled') {
parent.querySelector('.btnManageRecording').classList.remove('hide');
parent.querySelector('.singleRecordingButton .recordingIcon').classList.add('recordingIcon-active');
if (program.Status === 'InProgress') {
parent.querySelector('.singleRecordingButton .buttonText').innerHTML = globalize.translate('StopRecording');
} else {
parent.querySelector('.singleRecordingButton .buttonText').innerHTML = globalize.translate('DoNotRecord');
}
} else {
parent.querySelector('.btnManageRecording').classList.add('hide');
parent.querySelector('.singleRecordingButton .recordingIcon').classList.remove('recordingIcon-active');
parent.querySelector('.singleRecordingButton .buttonText').innerHTML = globalize.translate('Record');
}
if (data.ProgramId && options) {
if (options.programId === data.ProgramId) {
refresh = true;
}
}
function fetchData(instance) {
var options = instance.options;
var apiClient = connectionManager.getApiClient(options.serverId);
options.parent.querySelector('.recordingFields').classList.remove('hide');
return apiClient.getLiveTvProgram(options.programId, apiClient.getCurrentUserId()).then(function (program) {
instance.TimerId = program.TimerId;
instance.Status = program.Status;
instance.SeriesTimerId = program.SeriesTimerId;
loadData(options.parent, program, apiClient);
});
if (refresh) {
this.refresh();
}
}
function onTimerChangedExternally(e, apiClient, data) {
var options = this.options;
var refresh = false;
function onSeriesTimerChangedExternally(e, apiClient, data) {
const options = this.options;
let refresh = false;
if (data.Id) {
if (this.TimerId === data.Id) {
refresh = true;
}
if (data.Id) {
if (this.SeriesTimerId === data.Id) {
refresh = true;
}
if (data.ProgramId && options) {
if (options.programId === data.ProgramId) {
refresh = true;
}
}
if (refresh) {
this.refresh();
}
if (data.ProgramId && options) {
if (options.programId === data.ProgramId) {
refresh = true;
}
}
function onSeriesTimerChangedExternally(e, apiClient, data) {
var options = this.options;
var refresh = false;
if (data.Id) {
if (this.SeriesTimerId === data.Id) {
refresh = true;
}
}
if (data.ProgramId && options) {
if (options.programId === data.ProgramId) {
refresh = true;
}
}
if (refresh) {
this.refresh();
}
if (refresh) {
this.refresh();
}
}
function RecordingEditor(options) {
class RecordingEditor {
constructor(options) {
this.options = options;
this.embed();
var timerChangedHandler = onTimerChangedExternally.bind(this);
const timerChangedHandler = onTimerChangedExternally.bind(this);
this.timerChangedHandler = timerChangedHandler;
events.on(serverNotifications, 'TimerCreated', timerChangedHandler);
events.on(serverNotifications, 'TimerCancelled', timerChangedHandler);
var seriesTimerChangedHandler = onSeriesTimerChangedExternally.bind(this);
const seriesTimerChangedHandler = onSeriesTimerChangedExternally.bind(this);
this.seriesTimerChangedHandler = seriesTimerChangedHandler;
events.on(serverNotifications, 'SeriesTimerCreated', seriesTimerChangedHandler);
events.on(serverNotifications, 'SeriesTimerCancelled', seriesTimerChangedHandler);
}
function onManageRecordingClick(e) {
var options = this.options;
if (!this.TimerId || this.Status === 'Cancelled') {
return;
}
var self = this;
require(['recordingEditor'], function (recordingEditor) {
recordingEditor.show(self.TimerId, options.serverId, {
enableCancel: false
}).then(function () {
self.changed = true;
});
});
}
function onManageSeriesRecordingClick(e) {
var options = this.options;
if (!this.SeriesTimerId) {
return;
}
var self = this;
require(['seriesRecordingEditor'], function (seriesRecordingEditor) {
seriesRecordingEditor.show(self.SeriesTimerId, options.serverId, {
enableCancel: false
}).then(function () {
self.changed = true;
});
});
}
function onRecordChange(e) {
this.changed = true;
var self = this;
var options = this.options;
var apiClient = connectionManager.getApiClient(options.serverId);
var button = dom.parentWithTag(e.target, 'BUTTON');
var isChecked = !button.querySelector('.material-icons').classList.contains('recordingIcon-active');
var hasEnabledTimer = this.TimerId && this.Status !== 'Cancelled';
if (isChecked) {
if (!hasEnabledTimer) {
loading.show();
recordingHelper.createRecording(apiClient, options.programId, false).then(function () {
events.trigger(self, 'recordingchanged');
fetchData(self);
loading.hide();
});
}
} else {
if (hasEnabledTimer) {
loading.show();
recordingHelper.cancelTimer(apiClient, this.TimerId, true).then(function () {
events.trigger(self, 'recordingchanged');
fetchData(self);
loading.hide();
});
}
}
}
function sendToast(msg) {
require(['toast'], function (toast) {
toast(msg);
});
}
function onRecordSeriesChange(e) {
this.changed = true;
var self = this;
var options = this.options;
var apiClient = connectionManager.getApiClient(options.serverId);
var button = dom.parentWithTag(e.target, 'BUTTON');
var isChecked = !button.querySelector('.material-icons').classList.contains('recordingIcon-active');
if (isChecked) {
options.parent.querySelector('.recordSeriesContainer').classList.remove('hide');
if (!this.SeriesTimerId) {
var promise = this.TimerId ?
recordingHelper.changeRecordingToSeries(apiClient, this.TimerId, options.programId) :
recordingHelper.createRecording(apiClient, options.programId, true);
promise.then(function () {
fetchData(self);
});
}
} else {
if (this.SeriesTimerId) {
apiClient.cancelLiveTvSeriesTimer(this.SeriesTimerId).then(function () {
sendToast(globalize.translate('RecordingCancelled'));
fetchData(self);
});
}
}
}
RecordingEditor.prototype.embed = function () {
var self = this;
embed() {
const self = this;
return new Promise(function (resolve, reject) {
require(['text!./recordingfields.template.html'], function (template) {
var options = self.options;
var context = options.parent;
import('text!./recordingfields.template.html').then(({default: template}) => {
const options = self.options;
const context = options.parent;
context.innerHTML = globalize.translateHtml(template, 'core');
context.querySelector('.singleRecordingButton').addEventListener('click', onRecordChange.bind(self));
@ -228,29 +131,134 @@ define(['globalize', 'connectionManager', 'serverNotifications', 'require', 'loa
fetchData(self).then(resolve);
});
});
};
}
RecordingEditor.prototype.hasChanged = function () {
hasChanged() {
return this.changed;
};
}
RecordingEditor.prototype.refresh = function () {
refresh() {
fetchData(this);
};
}
RecordingEditor.prototype.destroy = function () {
var timerChangedHandler = this.timerChangedHandler;
destroy() {
const timerChangedHandler = this.timerChangedHandler;
this.timerChangedHandler = null;
events.off(serverNotifications, 'TimerCreated', timerChangedHandler);
events.off(serverNotifications, 'TimerCancelled', timerChangedHandler);
var seriesTimerChangedHandler = this.seriesTimerChangedHandler;
const seriesTimerChangedHandler = this.seriesTimerChangedHandler;
this.seriesTimerChangedHandler = null;
events.off(serverNotifications, 'SeriesTimerCreated', seriesTimerChangedHandler);
events.off(serverNotifications, 'SeriesTimerCancelled', seriesTimerChangedHandler);
};
}
}
return RecordingEditor;
});
function onManageRecordingClick(e) {
const options = this.options;
if (!this.TimerId || this.Status === 'Cancelled') {
return;
}
const self = this;
import('recordingEditor').then(({default: recordingEditor}) => {
recordingEditor.show(self.TimerId, options.serverId, {
enableCancel: false
}).then(function () {
self.changed = true;
});
});
}
function onManageSeriesRecordingClick(e) {
const options = this.options;
if (!this.SeriesTimerId) {
return;
}
const self = this;
import('seriesRecordingEditor').then(({default: seriesRecordingEditor}) => {
seriesRecordingEditor.show(self.SeriesTimerId, options.serverId, {
enableCancel: false
}).then(function () {
self.changed = true;
});
});
}
function onRecordChange(e) {
this.changed = true;
const self = this;
const options = this.options;
const apiClient = connectionManager.getApiClient(options.serverId);
const button = dom.parentWithTag(e.target, 'BUTTON');
const isChecked = !button.querySelector('.material-icons').classList.contains('recordingIcon-active');
const hasEnabledTimer = this.TimerId && this.Status !== 'Cancelled';
if (isChecked) {
if (!hasEnabledTimer) {
loading.show();
recordingHelper.createRecording(apiClient, options.programId, false).then(function () {
events.trigger(self, 'recordingchanged');
fetchData(self);
loading.hide();
});
}
} else {
if (hasEnabledTimer) {
loading.show();
recordingHelper.cancelTimer(apiClient, this.TimerId, true).then(function () {
events.trigger(self, 'recordingchanged');
fetchData(self);
loading.hide();
});
}
}
}
function sendToast(msg) {
import('toast').then(({default: toast}) => {
toast(msg);
});
}
function onRecordSeriesChange(e) {
this.changed = true;
const self = this;
const options = this.options;
const apiClient = connectionManager.getApiClient(options.serverId);
const button = dom.parentWithTag(e.target, 'BUTTON');
const isChecked = !button.querySelector('.material-icons').classList.contains('recordingIcon-active');
if (isChecked) {
options.parent.querySelector('.recordSeriesContainer').classList.remove('hide');
if (!this.SeriesTimerId) {
const promise = this.TimerId ?
recordingHelper.changeRecordingToSeries(apiClient, this.TimerId, options.programId) :
recordingHelper.createRecording(apiClient, options.programId, true);
promise.then(function () {
fetchData(self);
});
}
} else {
if (this.SeriesTimerId) {
apiClient.cancelLiveTvSeriesTimer(this.SeriesTimerId).then(function () {
sendToast(globalize.translate('RecordingCancelled'));
fetchData(self);
});
}
}
}
export default RecordingEditor;

View file

@ -66,7 +66,7 @@ function showSubtitleMenu(context, player, button, item) {
});
menuItems.unshift({
id: -1,
name: globalize.translate('ButtonOff'),
name: globalize.translate('Off'),
selected: currentIndex == null
});

View file

@ -14,7 +14,7 @@
<option value="Smart">${Smart}</option>
<option value="OnlyForced">${OnlyForcedSubtitles}</option>
<option value="Always">${AlwaysPlaySubtitles}</option>
<option value="None">${NoSubtitles}</option>
<option value="None">${None}</option>
</select>
<div class="fieldDescription subtitlesDefaultHelp subtitlesHelp hide">${DefaultSubtitlesHelp}</div>
<div class="fieldDescription subtitlesSmartHelp subtitlesHelp hide">${SmartSubtitlesHelp}</div>

View file

@ -737,7 +737,7 @@ import 'emby-itemscontainer';
shutdown: function (btn) {
import('confirm').then(({default: confirm}) => {
confirm({
title: globalize.translate('HeaderShutdown'),
title: globalize.translate('ButtonShutdown'),
text: globalize.translate('MessageConfirmShutdown'),
confirmText: globalize.translate('ButtonShutdown'),
primary: 'delete'

View file

@ -9,7 +9,7 @@
</div>
<div class="inputContainer">
<input is="emby-input" type="text" id="txtCustomName" label="${LabelCustomDeviceDisplayName}" />
<input is="emby-input" type="text" id="txtCustomName" label="${LabelDisplayName}" />
<div class="fieldDescription">${LabelCustomDeviceDisplayNameHelp}</div>
</div>
</div>

View file

@ -3,7 +3,7 @@
<div class="content-primary">
<div class="verticalSection verticalSection">
<div class="sectionTitleContainer sectionTitleContainer-cards flex align-items-center">
<h2 class="sectionTitle sectionTitle-cards">${TabDevices}</h2>
<h2 class="sectionTitle sectionTitle-cards">${HeaderDevices}</h2>
<a is="emby-linkbutton" rel="noopener noreferrer" class="raised button-alt headerHelpButton" target="_blank" href="https://docs.jellyfin.org/general/server/devices.html">${Help}</a>
</div>
</div>

View file

@ -21,7 +21,7 @@ import 'cardStyle';
confirm({
text: msg,
title: globalize.translate('HeaderDeleteDevice'),
confirmText: globalize.translate('ButtonDelete'),
confirmText: globalize.translate('Delete'),
primary: 'delete'
}).then(function () {
loading.show();

View file

@ -8,7 +8,7 @@
</div>
</div>
<div data-role="controlgroup" data-type="horizontal" data-mini="true">
<a href="#" is="emby-linkbutton" data-role="button" class="radioTabButton" id="radioInfo" data-value="tabInfo">${TabInfo}</a>
<a href="#" is="emby-linkbutton" data-role="button" class="radioTabButton" id="radioInfo" data-value="tabInfo">${ButtonInfo}</a>
<a href="#" is="emby-linkbutton" data-role="button" class="radioTabButton" id="radioDirectPlay" data-value="tabDirectPlayProfiles">${TabDirectPlay}</a>
<a href="#" is="emby-linkbutton" data-role="button" class="radioTabButton" id="radioTranscoding" data-value="tabTranscodingProfiles">${Transcoding}</a>
<a href="#" is="emby-linkbutton" data-role="button" class="radioTabButton" id="radioContainers" data-value="tabContainerProfiles">${TabContainers}</a>
@ -231,31 +231,31 @@
</div>
<div class="tabContent tabDirectPlayProfiles">
<p>${HeaderDirectPlayProfileHelp}</p>
<button is="emby-button" class="raised submit block btnAddDirectPlayProfile" type="button" data-mini="true" data-icon="plus">${ButtonNew}</button>
<button is="emby-button" class="raised submit block btnAddDirectPlayProfile" type="button" data-mini="true" data-icon="plus">${New}</button>
<br />
<div class="directPlayProfiles"></div>
</div>
<div class="tabContent tabTranscodingProfiles">
<p>${HeaderTranscodingProfileHelp}</p>
<button is="emby-button" class="raised submit block btnAddTranscodingProfile" type="button" data-mini="true" data-icon="plus">${ButtonNew}</button>
<button is="emby-button" class="raised submit block btnAddTranscodingProfile" type="button" data-mini="true" data-icon="plus">${New}</button>
<br />
<div class="transcodingProfiles"></div>
</div>
<div class="tabContent tabContainerProfiles">
<p>${HeaderContainerProfileHelp}</p>
<button is="emby-button" class="raised submit block btnAddContainerProfile" type="button" data-mini="true" data-icon="plus">${ButtonNew}</button>
<button is="emby-button" class="raised submit block btnAddContainerProfile" type="button" data-mini="true" data-icon="plus">${New}</button>
<br />
<div class="containerProfiles"></div>
</div>
<div class="tabContent tabCodecProfiles">
<p>${HeaderCodecProfileHelp}</p>
<button is="emby-button" class="raised submit block btnAddCodecProfile" type="button" data-icon="plus">${ButtonNew}</button>
<button is="emby-button" class="raised submit block btnAddCodecProfile" type="button" data-icon="plus">${New}</button>
<br />
<div class="codecProfiles"></div>
</div>
<div class="tabContent tabMediaProfiles">
<p>${HeaderResponseProfileHelp}</p>
<button is="emby-button" class="raised submit block btnAddResponseProfile" type="button" data-mini="true" data-icon="plus">${ButtonNew}</button>
<button is="emby-button" class="raised submit block btnAddResponseProfile" type="button" data-mini="true" data-icon="plus">${New}</button>
<br />
<div class="mediaProfiles"></div>
</div>
@ -319,7 +319,7 @@
<div data-role="content">
<div data-role="controlgroup" data-type="horizontal" data-mini="true">
<input type="radio" name="radioTranscodingTab" class="radioTabButton" id="radioTranscodingBasics" value="tabTranscodingBasics">
<label for="radioTranscodingBasics">${TabInfo}</label>
<label for="radioTranscodingBasics">${ButtonInfo}</label>
<input type="radio" name="radioTranscodingTab" class="radioTabButton" id="radioTranscodingAdvanced" value="tabTranscodingAdvanced">
<label for="radioTranscodingAdvanced">${TabAdvanced}</label>
</div>
@ -341,16 +341,16 @@
</div>
</div>
<div class="inputContainer">
<input is="emby-input" type="text" id="txtTranscodingContainer" label="${LabelTranscodingContainer}"; required="required" />
<input is="emby-input" type="text" id="txtTranscodingContainer" label="${LabelProfileContainer}"; required="required" />
</div>
<div id="fldTranscodingVideoCodec" style="margin: 1em 0;">
<div class="inputContainer">
<input is="emby-input" type="text" id="txtTranscodingVideoCodec" label="${LabelTranscodingVideoCodec}" />
<input is="emby-input" type="text" id="txtTranscodingVideoCodec" label="${LabelVideoCodec}" />
</div>
</div>
<div id="fldTranscodingAudioCodec" style="margin: 1em 0;">
<div class="inputContainer">
<input is="emby-input" type="text" id="txtTranscodingAudioCodec" label="${LabelTranscodingAudioCodec}" />
<input is="emby-input" type="text" id="txtTranscodingAudioCodec" label="${LabelAudioCodec}" />
</div>
</div>
</div>

View file

@ -46,7 +46,7 @@ import 'emby-button';
html += '</div>';
if (profile.Type == 'User') {
html += '<button type="button" is="paper-icon-button-light" class="btnDeleteProfile" data-profileid="' + profile.Id + '" title="' + globalize.translate('ButtonDelete') + '"><span class="material-icons delete"></span></button>';
html += '<button type="button" is="paper-icon-button-light" class="btnDeleteProfile" data-profileid="' + profile.Id + '" title="' + globalize.translate('Delete') + '"><span class="material-icons delete"></span></button>';
}
html += '</div>';

View file

@ -45,10 +45,10 @@ import libraryMenu from 'libraryMenu';
return ApiClient.ajax({
url: ApiClient.getUrl('System/MediaEncoder/Path'),
type: 'POST',
data: {
data: JSON.stringify({
Path: form.querySelector('.txtEncoderPath').value,
PathType: 'Custom'
}
})
}).then(Dashboard.processServerConfigurationUpdateResult, onSaveEncodingPathFailure);
});
}
@ -128,7 +128,7 @@ import libraryMenu from 'libraryMenu';
name: globalize.translate('Transcoding')
}, {
href: 'playbackconfiguration.html',
name: globalize.translate('TabResumeSettings')
name: globalize.translate('ButtonResume')
}, {
href: 'streamingsettings.html',
name: globalize.translate('TabStreaming')

View file

@ -17,9 +17,9 @@
<div class="selectContainer">
<select is="emby-select" id="selectLocalizationLanguage" label="${LabelPreferredDisplayLanguage}"></select>
<div class="fieldDescription">
<div>${LabelPreferredDisplayLanguageHelp}</div>
<div>${LabelDisplayLanguageHelp}</div>
<div style="margin-top: .25em;">
<a is="emby-linkbutton" rel="noopener noreferrer" class="button-link" href="https://docs.jellyfin.org/general/contributing/index.html" target="_blank">${LabelReadHowYouCanContribute}</a>
<a is="emby-linkbutton" rel="noopener noreferrer" class="button-link" href="https://docs.jellyfin.org/general/contributing/index.html" target="_blank">${LearnHowYouCanContribute}</a>
</div>
</div>
</div>

View file

@ -93,7 +93,7 @@ import 'emby-itemrefreshindicator';
const virtualFolder = virtualFolders[index];
const menuItems = [];
menuItems.push({
name: globalize.translate('ButtonEditImages'),
name: globalize.translate('EditImages'),
id: 'editimages',
icon: 'photo'
});

View file

@ -3,7 +3,7 @@
<div class="content-primary">
<form class="playbackConfigurationForm">
<div class="sectionTitleContainer flex align-items-center">
<h2 class="sectionTitle">${TabResumeSettings}</h2>
<h2 class="sectionTitle">${ButtonResume}</h2>
</div>
<div class="inputContainer">
<input is="emby-input" type="number" id="txtMinResumePct" name="txtMinResumePct" pattern="[0-9]*" required min="0" max="100" label="${LabelMinResumePercentage}"></input>

View file

@ -32,7 +32,7 @@ import globalize from 'globalize';
name: globalize.translate('Transcoding')
}, {
href: 'playbackconfiguration.html',
name: globalize.translate('TabResumeSettings')
name: globalize.translate('ButtonResume')
}, {
href: 'streamingsettings.html',
name: globalize.translate('TabStreaming')

View file

@ -28,7 +28,7 @@ function getHeaderText(category) {
} else if (category === 'Theme') {
category = 'Themes';
} else if (category === 'LiveTV') {
category = 'HeaderLiveTV';
category = 'LiveTV';
} else if (category === 'ScreenSaver') {
category = 'HeaderScreenSavers';
}

View file

@ -69,7 +69,7 @@ function getRepositoryHtml(repository) {
html += `<h3 class="listItemBodyText">${repository.Name}</h3>`;
html += `<div class="listItemBodyText secondary">${repository.Url}</div>`;
html += '</div>';
html += `<button type="button" is="paper-icon-button-light" id="${repository.Url}" class="btnDelete" title="${globalize.translate('ButtonDelete')}"><span class="material-icons delete"></span></button>`;
html += `<button type="button" is="paper-icon-button-light" id="${repository.Url}" class="btnDelete" title="${globalize.translate('Delete')}"><span class="material-icons delete"></span></button>`;
html += '</div>';
return html;

View file

@ -23,7 +23,7 @@
<div data-role="popup" id="popupAddTrigger" class="dialog dialog-fixedSize dialog-medium hide" style="position: fixed; top: 10%;">
<form class="addTriggerForm" style="padding:1em;">
<div class="ui-bar-a">
<h3>${HeaderAddScheduledTaskTrigger}</h3>
<h3>${ButtonAddScheduledTaskTrigger}</h3>
</div>
<div data-role="content">
<div class="selectContainer">
@ -31,18 +31,18 @@
<option value="DailyTrigger">${OptionDaily}</option>
<option value="WeeklyTrigger">${OptionWeekly}</option>
<option value="IntervalTrigger">${OptionOnInterval}</option>
<option value="StartupTrigger">${OptionOnAppStartup}</option>
<option value="StartupTrigger">${OnApplicationStartup}</option>
</select>
</div>
<div id="fldDayOfWeek" class="selectContainer">
<select is="emby-select" id="selectDayOfWeek" name="selectDayOfWeek" label="${LabelDay}">
<option value="Sunday">${OptionSunday}</option>
<option value="Monday">${OptionMonday}</option>
<option value="Tuesday">${OptionTuesday}</option>
<option value="Wednesday">${OptionWednesday}</option>
<option value="Thursday">${OptionThursday}</option>
<option value="Friday">${OptionFriday}</option>
<option value="Saturday">${OptionSaturday}</option>
<option value="Sunday">${Sunday}</option>
<option value="Monday">${Monday}</option>
<option value="Tuesday">${Tuesday}</option>
<option value="Wednesday">${Wednesday}</option>
<option value="Thursday">${Thursday}</option>
<option value="Friday">${Friday}</option>
<option value="Saturday">${Saturday}</option>
</select>
</div>
<div id="fldTimeOfDay" class="selectContainer">

View file

@ -75,7 +75,7 @@ import 'emby-select';
}
html += '</div>';
html += '<button class="btnDeleteTrigger" data-index="' + i + '" type="button" is="paper-icon-button-light" title="' + globalize.translate('ButtonDelete') + '"><span class="material-icons delete"></span></button>';
html += '<button class="btnDeleteTrigger" data-index="' + i + '" type="button" is="paper-icon-button-light" title="' + globalize.translate('Delete') + '"><span class="material-icons delete"></span></button>';
html += '</div>';
}

View file

@ -27,7 +27,7 @@ import globalize from 'globalize';
name: globalize.translate('Transcoding')
}, {
href: 'playbackconfiguration.html',
name: globalize.translate('TabResumeSettings')
name: globalize.translate('ButtonResume')
}, {
href: 'streamingsettings.html',
name: globalize.translate('TabStreaming')

View file

@ -14,7 +14,7 @@
<a href="#" is="emby-linkbutton" data-role="button" class="ui-btn-active">${TabProfile}</a>
<a href="#" is="emby-linkbutton" data-role="button" onclick="Dashboard.navigate('userlibraryaccess.html', true);">${TabAccess}</a>
<a href="#" is="emby-linkbutton" data-role="button" onclick="Dashboard.navigate('userparentalcontrol.html', true);">${TabParentalControl}</a>
<a href="#" is="emby-linkbutton" data-role="button" onclick="Dashboard.navigate('userpassword.html', true);">${TabPassword}</a>
<a href="#" is="emby-linkbutton" data-role="button" onclick="Dashboard.navigate('userpassword.html', true);">${HeaderPassword}</a>
</div>
<p class="lnkEditUserPreferencesContainer">
<a class="lnkEditUserPreferences button-link" href="#" is="emby-linkbutton">${ButtonEditOtherUserPreferences}</a>

View file

@ -14,7 +14,7 @@
<a is="emby-linkbutton" href="#" data-role="button" onclick="Dashboard.navigate('useredit.html', true);">${TabProfile}</a>
<a is="emby-linkbutton" href="#" data-role="button" onclick="Dashboard.navigate('userlibraryaccess.html', true);" class="ui-btn-active">${TabAccess}</a>
<a is="emby-linkbutton" href="#" data-role="button" onclick="Dashboard.navigate('userparentalcontrol.html', true);">${TabParentalControl}</a>
<a is="emby-linkbutton" href="#" data-role="button" onclick="Dashboard.navigate('userpassword.html', true);">${TabPassword}</a>
<a is="emby-linkbutton" href="#" data-role="button" onclick="Dashboard.navigate('userpassword.html', true);">${HeaderPassword}</a>
</div>
<form class="userLibraryAccessForm">

View file

@ -32,7 +32,7 @@ import globalize from 'globalize';
function loadChannels(page, user, channels) {
let html = '';
html += '<h3 class="checkboxListLabel">' + globalize.translate('HeaderChannels') + '</h3>';
html += '<h3 class="checkboxListLabel">' + globalize.translate('Channels') + '</h3>';
html += '<div class="checkboxList paperList checkboxList-paperList">';
for (let i = 0, length = channels.length; i < length; i++) {

View file

@ -4,7 +4,7 @@
<form class="newUserProfileForm">
<div class="verticalSection">
<div class="sectionTitleContainer flex align-items-center">
<h2 class="sectionTitle">${HeaderAddUser}</h2>
<h2 class="sectionTitle">${ButtonAddUser}</h2>
<a is="emby-linkbutton" rel="noopener noreferrer" class="raised button-alt headerHelpButton" target="_blank" href="https://docs.jellyfin.org/general/server/users/">${Help}</a>
</div>

View file

@ -22,7 +22,7 @@ import 'emby-checkbox';
function loadChannels(page, channels) {
let html = '';
html += '<h3 class="checkboxListLabel">' + globalize.translate('HeaderChannels') + '</h3>';
html += '<h3 class="checkboxListLabel">' + globalize.translate('Channels') + '</h3>';
html += '<div class="checkboxList paperList" style="padding:.5em 1em;">';
for (let i = 0; i < channels.length; i++) {

View file

@ -12,7 +12,7 @@
<a is="emby-linkbutton" href="#" data-role="button" onclick="Dashboard.navigate('useredit.html', true);">${TabProfile}</a>
<a is="emby-linkbutton" href="#" data-role="button" onclick="Dashboard.navigate('userlibraryaccess.html', true);">${TabAccess}</a>
<a is="emby-linkbutton" href="#" data-role="button" onclick="Dashboard.navigate('userparentalcontrol.html', true);" class="ui-btn-active">${TabParentalControl}</a>
<a is="emby-linkbutton" href="#" data-role="button" onclick="Dashboard.navigate('userpassword.html', true);">${TabPassword}</a>
<a is="emby-linkbutton" href="#" data-role="button" onclick="Dashboard.navigate('userpassword.html', true);">${HeaderPassword}</a>
</div>
<form class="userParentalControlForm">

View file

@ -12,7 +12,7 @@
<a is="emby-linkbutton" href="#" data-role="button" onclick="Dashboard.navigate('useredit.html', true);">${TabProfile}</a>
<a is="emby-linkbutton" href="#" data-role="button" onclick="Dashboard.navigate('userlibraryaccess.html', true);">${TabAccess}</a>
<a is="emby-linkbutton" href="#" data-role="button" onclick="Dashboard.navigate('userparentalcontrol.html', true);">${TabParentalControl}</a>
<a is="emby-linkbutton" href="#" data-role="button" onclick="Dashboard.navigate('userpassword.html', true);" class="ui-btn-active">${TabPassword}</a>
<a is="emby-linkbutton" href="#" data-role="button" onclick="Dashboard.navigate('userpassword.html', true);" class="ui-btn-active">${HeaderPassword}</a>
</div>
<div class="readOnlyContent">

View file

@ -83,7 +83,7 @@ import 'emby-button';
loading.hide();
import('toast').then(({default: toast}) => {
toast(globalize.translate('MessageSettingsSaved'));
toast(globalize.translate('SettingsSaved'));
});
loadUser(view, params);

View file

@ -18,7 +18,7 @@ import 'flexStyles';
confirm({
title: globalize.translate('DeleteUser'),
text: msg,
confirmText: globalize.translate('ButtonDelete'),
confirmText: globalize.translate('Delete'),
primary: 'delete'
}).then(function () {
loading.show();
@ -50,7 +50,7 @@ import 'flexStyles';
icon: 'person'
});
menuItems.push({
name: globalize.translate('ButtonDelete'),
name: globalize.translate('Delete'),
id: 'delete',
icon: 'delete'
});

View file

@ -18,13 +18,13 @@
</div>
</button>
<button is="emby-button" type="button" class="button-flat btnPlay hide detailButton" title="${ButtonPlay}" data-mode="play">
<button is="emby-button" type="button" class="button-flat btnPlay hide detailButton" title="${Play}" data-mode="play">
<div class="detailButton-content">
<span class="material-icons detailButton-icon play_arrow"></span>
</div>
</button>
<button is="emby-button" type="button" class="button-flat btnDownload hide detailButton" title="${ButtonDownload}">
<button is="emby-button" type="button" class="button-flat btnDownload hide detailButton" title="${Download}">
<div class="detailButton-content">
<span class="material-icons detailButton-icon get_app"></span>
</div>
@ -42,7 +42,7 @@
</div>
</button>
<button is="emby-button" type="button" class="button-flat btnShuffle hide detailButton" title="${ButtonShuffle}">
<button is="emby-button" type="button" class="button-flat btnShuffle hide detailButton" title="${Shuffle}">
<div class="detailButton-content">
<span class="material-icons detailButton-icon shuffle"></span>
</div>
@ -147,14 +147,14 @@
</div>
<div class="seriesTimerScheduleSection verticalSection detailVerticalSection hide" style="margin-top:-3em;">
<h2 class="sectionTitle">${HeaderSchedule}</h2>
<h2 class="sectionTitle">${Schedule}</h2>
<div class="seriesTimerSchedule padded-right"></div>
</div>
<div class="collectionItems hide"></div>
<div class="nextUpSection verticalSection detailVerticalSection hide">
<h2 class="sectionTitle sectionTitle-cards">${HeaderNextUp}</h2>
<h2 class="sectionTitle sectionTitle-cards">${NextUp}</h2>
<div is="emby-itemscontainer" class="nextUpItems vertical-wrap padded-right"></div>
</div>
@ -193,7 +193,7 @@
</div>
<div id="castCollapsible" class="verticalSection detailVerticalSection hide">
<h2 id="peopleHeader" class="sectionTitle sectionTitle-cards padded-right">${HeaderCastCrew}</h2>
<h2 id="peopleHeader" class="sectionTitle sectionTitle-cards padded-right">${HeaderCastAndCrew}</h2>
<div is="emby-scroller" class="padded-top-focusscale padded-bottom-focusscale" data-centerfocus="true">
<div id="castContent" is="emby-itemscontainer" class="scrollSlider focuscontainer-x itemsContainer"></div>
</div>

View file

@ -242,7 +242,7 @@ import 'emby-select';
return m.Type === 'Audio';
});
const select = page.querySelector('.selectAudio');
select.setLabel(globalize.translate('LabelAudio'));
select.setLabel(globalize.translate('Audio'));
const selectedId = mediaSource.DefaultAudioStreamIndex;
select.innerHTML = tracks.map(function (v) {
const selected = v.Index === selectedId ? ' selected' : '';
@ -271,7 +271,7 @@ import 'emby-select';
return m.Type === 'Subtitle';
});
const select = page.querySelector('.selectSubtitles');
select.setLabel(globalize.translate('LabelSubtitles'));
select.setLabel(globalize.translate('Subtitles'));
const selectedId = mediaSource.DefaultSubtitleStreamIndex == null ? -1 : mediaSource.DefaultSubtitleStreamIndex;
const videoTracks = mediaSource.MediaStreams.filter(function (m) {
@ -785,7 +785,7 @@ import 'emby-select';
function setPeopleHeader(page, item) {
if (item.MediaType == 'Audio' || item.Type == 'MusicAlbum' || item.MediaType == 'Book' || item.MediaType == 'Photo') {
page.querySelector('#peopleHeader').innerHTML = globalize.translate('HeaderPeople');
page.querySelector('#peopleHeader').innerHTML = globalize.translate('People');
} else {
page.querySelector('#peopleHeader').innerHTML = globalize.translate('HeaderCastAndCrew');
}
@ -1432,13 +1432,13 @@ import 'emby-select';
name: globalize.translate('HeaderVideos'),
mediaType: 'Video'
}, {
name: globalize.translate('HeaderSeries'),
name: globalize.translate('Series'),
type: 'Series'
}, {
name: globalize.translate('HeaderAlbums'),
name: globalize.translate('Albums'),
type: 'MusicAlbum'
}, {
name: globalize.translate('HeaderBooks'),
name: globalize.translate('Books'),
type: 'Book'
}];
renderCollectionItems(page, item, collectionItemTypes, result.Items);
@ -1446,13 +1446,13 @@ import 'emby-select';
});
if (item.Type == 'Season') {
page.querySelector('#childrenTitle').innerHTML = globalize.translate('HeaderEpisodes');
page.querySelector('#childrenTitle').innerHTML = globalize.translate('Episodes');
} else if (item.Type == 'Series') {
page.querySelector('#childrenTitle').innerHTML = globalize.translate('HeaderSeasons');
} else if (item.Type == 'MusicAlbum') {
page.querySelector('#childrenTitle').innerHTML = globalize.translate('HeaderTracks');
} else {
page.querySelector('#childrenTitle').innerHTML = globalize.translate('HeaderItems');
page.querySelector('#childrenTitle').innerHTML = globalize.translate('Items');
}
if (item.Type == 'MusicAlbum' || item.Type == 'Season') {
@ -1652,7 +1652,7 @@ import 'emby-select';
if (!items.length) {
renderCollectionItemType(page, parentItem, {
name: globalize.translate('HeaderItems')
name: globalize.translate('Items')
}, items);
}

View file

@ -1,4 +1,4 @@
<div id="liveTvSuggestedPage" data-dom-cache="true" data-role="page" class="page libraryPage liveTvPage pageWithAbsoluteTabs withTabs" data-title="${HeaderLiveTv}" data-backdroptype="series,movie">
<div id="liveTvSuggestedPage" data-dom-cache="true" data-role="page" class="page libraryPage liveTvPage pageWithAbsoluteTabs withTabs" data-title="${LiveTV}" data-backdroptype="series,movie">
<div class="liveTvContainer">
@ -15,7 +15,7 @@
<div id="upcomingEpisodes" class="verticalSection">
<div class="sectionTitleContainer sectionTitleContainer-cards padded-left">
<a href="list.html?type=Programs&IsSeries=true&IsMovie=false&IsNews=false" is="emby-linkbutton" class="button-flat button-flat-mini sectionTitleTextButton sectionTitleTextButton-programs">
<h2 class="sectionTitle sectionTitle-cards" style="display: inline-block; vertical-align: middle;">${TabShows}</h2>
<h2 class="sectionTitle sectionTitle-cards" style="display: inline-block; vertical-align: middle;">${Shows}</h2>
<span class="material-icons chevron_right"></span>
</a>
</div>
@ -24,7 +24,7 @@
<div id="upcomingTvMovies" class="verticalSection">
<div class="sectionTitleContainer sectionTitleContainer-cards padded-left">
<a href="list.html?type=Programs&IsMovie=true" is="emby-linkbutton" class="button-flat button-flat-mini sectionTitleTextButton sectionTitleTextButton-programs">
<h2 class="sectionTitle sectionTitle-cards" style="display: inline-block; vertical-align: middle;">${HeaderMovies}</h2>
<h2 class="sectionTitle sectionTitle-cards" style="display: inline-block; vertical-align: middle;">${Movies}</h2>
<span class="material-icons chevron_right"></span>
</a>
</div>
@ -63,7 +63,7 @@
<div class="pageTabContent" id="channelsTab" data-index="2">
<div class="flex align-items-center justify-content-center flex-wrap-wrap padded-top padded-left padded-right padded-bottom">
<div class="paging"></div>
<button is="paper-icon-button-light" class="btnFilter sectionTitleButton" title="${ButtonFilter}"><span class="material-icons filter_list"></span></button>
<button is="paper-icon-button-light" class="btnFilter sectionTitleButton" title="${Filter}"><span class="material-icons filter_list"></span></button>
</div>
<div is="emby-itemscontainer" id="items" class="itemsContainer vertical-wrap padded-left padded-right"></div>
</div>

View file

@ -168,15 +168,15 @@ function getTabs() {
return [{
name: globalize.translate('Programs')
}, {
name: globalize.translate('TabGuide')
name: globalize.translate('Guide')
}, {
name: globalize.translate('TabChannels')
name: globalize.translate('Channels')
}, {
name: globalize.translate('TabRecordings')
name: globalize.translate('Recordings')
}, {
name: globalize.translate('HeaderSchedule')
name: globalize.translate('Schedule')
}, {
name: globalize.translate('TabSeries')
name: globalize.translate('Series')
}];
}

View file

@ -11,7 +11,7 @@
<form class="liveTvSettingsForm">
<div class="selectContainer">
<select is="emby-select" id="selectGuideDays" label="${LabelNumberOfGuideDays}">
<option value="">${OptionAutomatic}</option>
<option value="">${OptionAuto}</option>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>

View file

@ -137,7 +137,7 @@ function renderProviders(page, providers) {
function showProviderOptions(page, providerId, button) {
const items = [];
items.push({
name: globalize.translate('ButtonDelete'),
name: globalize.translate('Delete'),
id: 'delete'
});
items.push({
@ -255,11 +255,11 @@ function addDevice(button) {
function showDeviceMenu(button, tunerDeviceId) {
const items = [];
items.push({
name: globalize.translate('ButtonDelete'),
name: globalize.translate('Delete'),
id: 'delete'
});
items.push({
name: globalize.translate('ButtonEdit'),
name: globalize.translate('Edit'),
id: 'edit'
});

View file

@ -4,8 +4,8 @@
<div class="flex align-items-center justify-content-center flex-wrap-wrap padded-top padded-left padded-right padded-bottom">
<div class="paging"></div>
<button is="paper-icon-button-light" class="btnSelectView autoSize" title="${ButtonSelectView}"><span class="material-icons view_comfy"></span></button>
<button is="paper-icon-button-light" class="btnSort autoSize" title="${ButtonSort}"><span class="material-icons sort_by_alpha"></span></button>
<button is="paper-icon-button-light" class="btnFilter autoSize" title="${ButtonFilter}"><span class="material-icons filter_list"></span></button>
<button is="paper-icon-button-light" class="btnSort autoSize" title="${Sort}"><span class="material-icons sort_by_alpha"></span></button>
<button is="paper-icon-button-light" class="btnFilter autoSize" title="${Filter}"><span class="material-icons filter_list"></span></button>
</div>
<div class="alphaPicker alphaPicker-fixed alphaPicker-vertical">
@ -46,8 +46,8 @@
<div class="pageTabContent" data-index="2">
<div class="flex align-items-center justify-content-center flex-wrap-wrap padded-top padded-left padded-right padded-bottom">
<div class="paging"></div>
<button is="paper-icon-button-light" class="btnSort autoSize" title="${ButtonSort}"><span class="material-icons sort_by_alpha"></span></button>
<button is="paper-icon-button-light" class="btnFilter autoSize" title="${ButtonFilter}"><span class="material-icons filter_list"></span></button>
<button is="paper-icon-button-light" class="btnSort autoSize" title="${Sort}"><span class="material-icons sort_by_alpha"></span></button>
<button is="paper-icon-button-light" class="btnFilter autoSize" title="${Filter}"><span class="material-icons filter_list"></span></button>
</div>
<div class="alphaPicker alphaPicker-fixed alphaPicker-fixed-right alphaPicker-vertical">
@ -75,7 +75,7 @@
<div class="flex align-items-center justify-content-center flex-wrap-wrap padded-top padded-left padded-right padded-bottom">
<div class="paging"></div>
<button is="paper-icon-button-light" class="btnSelectView autoSize" title="${ButtonSelectView}"><span class="material-icons view_comfy"></span></button>
<button is="paper-icon-button-light" class="btnSort autoSize" title="${ButtonSort}"><span class="material-icons sort_by_alpha"></span></button>
<button is="paper-icon-button-light" class="btnSort autoSize" title="${Sort}"><span class="material-icons sort_by_alpha"></span></button>
<button type="button" is="paper-icon-button-light" class="btnNewCollection autoSize"><span class="material-icons add"></span></button>
</div>

View file

@ -229,13 +229,13 @@ import 'emby-button';
}, {
name: globalize.translate('Suggestions')
}, {
name: globalize.translate('TabTrailers')
name: globalize.translate('Trailers')
}, {
name: globalize.translate('TabFavorites')
name: globalize.translate('Favorites')
}, {
name: globalize.translate('TabCollections')
name: globalize.translate('Collections')
}, {
name: globalize.translate('TabGenres')
name: globalize.translate('Genres')
}];
}
@ -403,8 +403,8 @@ import 'emby-button';
libraryMenu.setTitle(item.Name);
});
} else {
view.setAttribute('data-title', globalize.translate('TabMovies'));
libraryMenu.setTitle(globalize.translate('TabMovies'));
view.setAttribute('data-title', globalize.translate('Movies'));
libraryMenu.setTitle(globalize.translate('Movies'));
}
}

View file

@ -38,10 +38,10 @@
<div class="flex align-items-center justify-content-center flex-wrap-wrap padded-top padded-left padded-right padded-bottom">
<div class="paging"></div>
<button is="paper-icon-button-light" class="btnPlayAll musicglobalButton" title="${HeaderPlayAll}"><span class="material-icons play_arrow"></span></button>
<button is="paper-icon-button-light" class="btnShuffle musicglobalButton" title="${ButtonShuffle}"><span class="material-icons shuffle"></span></button>
<button is="paper-icon-button-light" class="btnShuffle musicglobalButton" title="${Shuffle}"><span class="material-icons shuffle"></span></button>
<button is="paper-icon-button-light" class="btnSelectView autoSize" title="${ButtonSelectView}"><span class="material-icons view_comfy"></span></button>
<button is="paper-icon-button-light" class="btnSort autoSize" title="${ButtonSort}"><span class="material-icons sort_by_alpha"></span></button>
<button is="paper-icon-button-light" class="btnFilter autoSize" title="${ButtonFilter}"><span class="material-icons filter_list"></span></button>
<button is="paper-icon-button-light" class="btnSort autoSize" title="${Sort}"><span class="material-icons sort_by_alpha"></span></button>
<button is="paper-icon-button-light" class="btnFilter autoSize" title="${Filter}"><span class="material-icons filter_list"></span></button>
</div>
<div class="alphaPicker alphaPicker-fixed alphaPicker-vertical">
@ -57,7 +57,7 @@
<div class="flex align-items-center justify-content-center flex-wrap-wrap padded-top padded-left padded-right padded-bottom">
<div class="paging"></div>
<button is="paper-icon-button-light" class="btnSelectView autoSize" title="${ButtonSelectView}"><span class="material-icons view_comfy"></span></button>
<button is="paper-icon-button-light" class="btnFilter autoSize" title="${ButtonFilter}"><span class="material-icons filter_list"></span></button>
<button is="paper-icon-button-light" class="btnFilter autoSize" title="${Filter}"><span class="material-icons filter_list"></span></button>
</div>
<div class="alphaPicker alphaPicker-fixed alphaPicker-vertical">
@ -73,7 +73,7 @@
<div class="flex align-items-center justify-content-center flex-wrap-wrap padded-top padded-left padded-right padded-bottom">
<div class="paging"></div>
<button is="paper-icon-button-light" class="btnSelectView autoSize" title="${ButtonSelectView}"><span class="material-icons view_comfy"></span></button>
<button is="paper-icon-button-light" class="btnFilter autoSize" title="${ButtonFilter}"><span class="material-icons filter_list"></span></button>
<button is="paper-icon-button-light" class="btnFilter autoSize" title="${Filter}"><span class="material-icons filter_list"></span></button>
</div>
<div class="alphaPicker alphaPicker-fixed alphaPicker-vertical">
@ -92,8 +92,8 @@
<div class="pageTabContent" id="songsTab" data-index="5">
<div class="flex align-items-center justify-content-center flex-wrap-wrap padded-top padded-left padded-right padded-bottom">
<div class="paging"></div>
<button is="paper-icon-button-light" class="btnSort autoSize" title="${ButtonSort}"><span class="material-icons sort_by_alpha"></span></button>
<button is="paper-icon-button-light" class="btnFilter autoSize" title="${ButtonFilter}"><span class="material-icons filter_list"></span></button>
<button is="paper-icon-button-light" class="btnSort autoSize" title="${Sort}"><span class="material-icons sort_by_alpha"></span></button>
<button is="paper-icon-button-light" class="btnFilter autoSize" title="${Filter}"><span class="material-icons filter_list"></span></button>
</div>
<div is="emby-itemscontainer" id="items" class="itemsContainer vertical-list" style="max-width:67.5em;margin: 0 auto;"></div>

View file

@ -179,17 +179,17 @@ import 'flexStyles';
return [{
name: globalize.translate('Suggestions')
}, {
name: globalize.translate('TabAlbums')
name: globalize.translate('Albums')
}, {
name: globalize.translate('TabAlbumArtists')
name: globalize.translate('HeaderAlbumArtists')
}, {
name: globalize.translate('Artists')
}, {
name: globalize.translate('TabPlaylists')
name: globalize.translate('Playlists')
}, {
name: globalize.translate('TabSongs')
name: globalize.translate('Songs')
}, {
name: globalize.translate('TabGenres')
name: globalize.translate('Genres')
}];
}

View file

@ -59,7 +59,7 @@
<span class="material-icons forward_30"></span>
</button>
<button is="paper-icon-button-light" class="btnShuffleQueue autoSize" title="${ButtonShuffle}">
<button is="paper-icon-button-light" class="btnShuffleQueue autoSize" title="${Shuffle}">
<span class="material-icons shuffle"></span>
</button>
@ -71,7 +71,7 @@
<span class="material-icons audiotrack"></span>
</button>
<button is="paper-icon-button-light" class="btnSubtitles videoButton btnPlayStateCommand autoSize" title="${ButtonSubtitles}" data-command="GoToSearch">
<button is="paper-icon-button-light" class="btnSubtitles videoButton btnPlayStateCommand autoSize" title="${Subtitles}" data-command="GoToSearch">
<span class="material-icons closed_caption"></span>
</button>
@ -81,7 +81,7 @@
<span class="material-icons fullscreen"></span>
</button>
<button is="paper-icon-button-light" class="btnShuffleQueue autoSize" title="${ButtonShuffle}">
<button is="paper-icon-button-light" class="btnShuffleQueue autoSize" title="${Shuffle}">
<span class="material-icons shuffle"></span>
</button>
@ -99,7 +99,7 @@
<div is="emby-collapse" title="${HeaderNavigation}">
<div class="collapseContent">
<div>
<button is="paper-icon-button-light" class="btnArrowUp btnCommand autoSize button-submit" title="${ButtonArrowUp}" data-command="MoveUp">
<button is="paper-icon-button-light" class="btnArrowUp btnCommand autoSize button-submit" title="${Up}" data-command="MoveUp">
<span class="material-icons keyboard_arrow_up"></span>
</button>
</div>
@ -120,7 +120,7 @@
<button is="paper-icon-button-light" class="btnBack btnCommand autoSize" title="${ButtonBack}" data-command="Back">
<span class="material-icons arrow_back"></span>
</button>
<button is="paper-icon-button-light" class="btnArrowDown btnCommand autoSize button-submit" title="${ButtonArrowDown}" data-command="MoveDown">
<button is="paper-icon-button-light" class="btnArrowDown btnCommand autoSize button-submit" title="${Down}" data-command="MoveDown">
<span class="material-icons keyboard_arrow_down"></span>
</button>
<button is="paper-icon-button-light" class="btnContextMenu btnCommand autoSize" title="${ButtonInfo}" data-command="ToggleContextMenu">
@ -129,7 +129,7 @@
</div>
<br />
<div>
<button is="paper-icon-button-light" class="btnGoHome btnCommand autoSize" title="${ButtonHome}" data-command="GoHome">
<button is="paper-icon-button-light" class="btnGoHome btnCommand autoSize" title="${Home}" data-command="GoHome">
<span class="material-icons home"></span>
</button>
<button is="paper-icon-button-light" class="btnShowSearch btnCommand autoSize" title="${Search}" data-command="GoToSearch">

View file

@ -767,7 +767,7 @@ import 'css!assets/css/videoosd';
if (isPaused) {
btnPlayPauseIcon.classList.add('play_arrow');
btnPlayPause.setAttribute('title', globalize.translate('ButtonPlay') + ' (k)');
btnPlayPause.setAttribute('title', globalize.translate('Play') + ' (k)');
} else {
btnPlayPauseIcon.classList.add('pause');
btnPlayPause.setAttribute('title', globalize.translate('ButtonPause') + ' (k)');
@ -1243,6 +1243,12 @@ import 'css!assets/css/videoosd';
}
break;
}
case '>':
playbackManager.increasePlaybackRate(currentPlayer);
break;
case '<':
playbackManager.decreasePlaybackRate(currentPlayer);
break;
}
}

View file

@ -8,7 +8,7 @@
</div>
<br />
<button is="emby-button" type="submit" class="raised button-submit block">
<span>${ButtonConnect}</span>
<span>${Connect}</span>
</button>
<button is="emby-button" type="button" class="raised button-cancel block btnCancel">
<span>${ButtonCancel}</span>

View file

@ -2,7 +2,7 @@
<div class="padded-left padded-right padded-bottom-page">
<form class="forgotPasswordForm" style="text-align: center; margin: 0 auto;">
<div style="text-align: left;">
<h1>${HeaderForgotPassword}</h1>
<h1>${ButtonForgotPassword}</h1>
<div class="inputContainer">
<input is="emby-input" type="text" id="txtName" label="${LabelUser}" autocomplete="off"/>

View file

@ -6,14 +6,14 @@ import globalize from 'globalize';
if (result.Action == 'ContactAdmin') {
return void Dashboard.alert({
message: globalize.translate('MessageContactAdminToResetPassword'),
title: globalize.translate('HeaderForgotPassword')
title: globalize.translate('ButtonForgotPassword')
});
}
if (result.Action == 'InNetworkRequired') {
return void Dashboard.alert({
message: globalize.translate('MessageForgotPasswordInNetworkRequired'),
title: globalize.translate('HeaderForgotPassword')
title: globalize.translate('ButtonForgotPassword')
});
}
@ -27,7 +27,7 @@ import globalize from 'globalize';
msg += '<br/>';
return void Dashboard.alert({
message: msg,
title: globalize.translate('HeaderForgotPassword'),
title: globalize.translate('ButtonForgotPassword'),
callback: function () {
Dashboard.navigate('forgotpasswordpin.html');
}
@ -41,9 +41,9 @@ import globalize from 'globalize';
type: 'POST',
url: ApiClient.getUrl('Users/ForgotPassword'),
dataType: 'json',
data: {
data: JSON.stringify({
EnteredUsername: view.querySelector('#txtName').value
}
})
}).then(processForgotPasswordResult);
e.preventDefault();
return false;

View file

@ -29,9 +29,9 @@ import globalize from 'globalize';
type: 'POST',
url: ApiClient.getUrl('Users/ForgotPassword/Pin'),
dataType: 'json',
data: {
data: JSON.stringify({
Pin: view.querySelector('#txtPin').value
}
})
}).then(processForgotPasswordResult);
e.preventDefault();
return false;

View file

@ -4,8 +4,8 @@
<div class="flex align-items-center justify-content-center flex-wrap-wrap padded-top padded-left padded-right padded-bottom">
<div class="paging"></div>
<button is="paper-icon-button-light" class="btnSelectView autoSize" title="${ButtonSelectView}"><span class="material-icons view_comfy"></span></button>
<button is="paper-icon-button-light" class="btnSort autoSize" title="${ButtonSort}"><span class="material-icons sort_by_alpha"></span></button>
<button is="paper-icon-button-light" class="btnFilter autoSize" title="${ButtonFilter}"><span class="material-icons filter_list"></span></button>
<button is="paper-icon-button-light" class="btnSort autoSize" title="${Sort}"><span class="material-icons sort_by_alpha"></span></button>
<button is="paper-icon-button-light" class="btnFilter autoSize" title="${Filter}"><span class="material-icons filter_list"></span></button>
</div>
<div is="emby-itemscontainer" class="itemsContainer padded-left padded-right"></div>
@ -26,7 +26,7 @@
<div class="verticalSection">
<div class="sectionTitleContainer sectionTitleContainer-cards">
<h2 class="sectionTitle sectionTitle-cards padded-left nextUpHeader">${HeaderNextUp}</h2>
<h2 class="sectionTitle sectionTitle-cards padded-left nextUpHeader">${NextUp}</h2>
</div>
<div is="emby-itemscontainer" id="nextUpItems" class="itemsContainer vertical-wrap padded-left padded-right">
</div>
@ -60,8 +60,8 @@
<div class="flex align-items-center justify-content-center flex-wrap-wrap padded-top padded-left padded-right padded-bottom">
<div class="paging"></div>
<button is="paper-icon-button-light" class="btnSelectView autoSize" title="${ButtonSelectView}"><span class="material-icons view_comfy"></span></button>
<button is="paper-icon-button-light" class="btnSort autoSize" title="${ButtonSort}"><span class="material-icons sort_by_alpha"></span></button>
<button is="paper-icon-button-light" class="btnFilter autoSize" title="${ButtonFilter}"><span class="material-icons filter_list"></span></button>
<button is="paper-icon-button-light" class="btnSort autoSize" title="${Sort}"><span class="material-icons sort_by_alpha"></span></button>
<button is="paper-icon-button-light" class="btnFilter autoSize" title="${Filter}"><span class="material-icons filter_list"></span></button>
</div>
<div is="emby-itemscontainer" class="itemsContainer vertical-wrap padded-left padded-right">
</div>

View file

@ -17,7 +17,7 @@ import 'emby-button';
function getTabs() {
return [{
name: globalize.translate('TabShows')
name: globalize.translate('Shows')
}, {
name: globalize.translate('Suggestions')
}, {
@ -25,11 +25,11 @@ import 'emby-button';
}, {
name: globalize.translate('TabUpcoming')
}, {
name: globalize.translate('TabGenres')
name: globalize.translate('Genres')
}, {
name: globalize.translate('TabNetworks')
}, {
name: globalize.translate('TabEpisodes')
name: globalize.translate('Episodes')
}];
}
@ -318,8 +318,8 @@ import 'emby-button';
libraryMenu.setTitle(item.Name);
});
} else {
view.setAttribute('data-title', globalize.translate('TabShows'));
libraryMenu.setTitle(globalize.translate('TabShows'));
view.setAttribute('data-title', globalize.translate('Shows'));
libraryMenu.setTitle(globalize.translate('Shows'));
}
}

View file

@ -1,4 +1,4 @@
<div id="homeScreenPreferencesPage" data-role="page" class="page libraryPage userPreferencesPage noSecondaryNavPage" data-title="${HeaderHome}" data-backbutton="true">
<div id="homeScreenPreferencesPage" data-role="page" class="page libraryPage userPreferencesPage noSecondaryNavPage" data-title="${Home}" data-backbutton="true">
<div class="homeScreenSettingsContainer padded-left padded-right padded-bottom-page">
</div>
</div>

View file

@ -25,7 +25,7 @@
<div class="listItem">
<span class="material-icons listItemIcon listItemIcon-transparent home"></span>
<div class="listItemBody">
<div class="listItemBodyText">${HeaderHome}</div>
<div class="listItemBodyText">${Home}</div>
</div>
</div>
</a>

View file

@ -12,7 +12,7 @@
<span>${ButtonAddImage}</span>
</button>
<button is="emby-button" type="button" class="raised hide" id="btnDeleteImage">
<span>${ButtonDeleteImage}</span>
<span>${DeleteImage}</span>
</button>
</div>
</div>

View file

@ -6,7 +6,7 @@
<div class="wizardNavigation">
<button is="emby-button" type="button" class="raised button-cancel" onclick="history.back();">
<span class="material-icons arrow_back"></span>
<span>${LabelPrevious}</span>
<span>${Previous}</span>
</button>
<button is="emby-button" type="button" class="raised btnWizardNext button-submit">
<span class="material-icons check"></span>

View file

@ -12,10 +12,10 @@
<div class="wizardNavigation">
<button is="emby-button" type="button" class="raised button-cancel" onclick="history.back();">
<span class="material-icons arrow_back"></span>
<span>${LabelPrevious}</span>
<span>${Previous}</span>
</button>
<button is="emby-button" type="button" class="raised button-submit" onclick="WizardLibraryPage.next();">
<span>${LabelNext}</span>
<span>${Next}</span>
<span class="material-icons arrow_forward"></span>
</button>
</div>

View file

@ -22,10 +22,10 @@
<div class="wizardNavigation">
<button is="emby-button" type="button" class="raised button-cancel" onclick="history.back();">
<span class="material-icons arrow_back"></span>
<span>${LabelPrevious}</span>
<span>${Previous}</span>
</button>
<button is="emby-button" type="submit" class="raised button-submit">
<span>${LabelNext}</span>
<span>${Next}</span>
<span class="material-icons arrow_forward"></span>
</button>
</div>

View file

@ -11,7 +11,7 @@ function save(page) {
config.EnableAutomaticPortMapping = page.querySelector('#chkEnableUpnp').checked;
apiClient.ajax({
type: 'POST',
data: config,
data: JSON.stringify(config),
url: apiClient.getUrl('Startup/RemoteAccess')
}).then(function () {
loading.hide();

View file

@ -17,10 +17,10 @@
<div class="wizardNavigation">
<button is="emby-button" type="button" class="raised button-cancel" onclick="history.back();">
<span class="material-icons arrow_back"></span>
<span>${LabelPrevious}</span>
<span>${Previous}</span>
</button>
<button is="emby-button" type="submit" class="raised button-submit">
<span>${LabelNext}</span>
<span>${Next}</span>
<span class="material-icons arrow_forward"></span>
</button>
</div>

View file

@ -11,7 +11,7 @@ function save(page) {
config.MetadataCountryCode = page.querySelector('#selectCountry').value;
apiClient.ajax({
type: 'POST',
data: config,
data: JSON.stringify(config),
url: apiClient.getUrl('Startup/Configuration')
}).then(function () {
loading.hide();

View file

@ -19,7 +19,7 @@
<div class="wizardNavigation" style="text-align:right;">
<button is="emby-button" type="submit" class="raised button-submit">
<span>${LabelNext}</span>
<span>${Next}</span>
<span class="material-icons arrow_forward"></span>
</button>
</div>

View file

@ -17,7 +17,7 @@ function save(page) {
config.UICulture = $('#selectLocalizationLanguage', page).val();
apiClient.ajax({
type: 'POST',
data: config,
data: JSON.stringify(config),
url: apiClient.getUrl('Startup/Configuration')
}).then(function () {
Dashboard.navigate('wizarduser.html');

View file

@ -23,10 +23,10 @@
<div class="wizardNavigation">
<button is="emby-button" type="button" class="raised button-cancel" onclick="history.back();">
<span class="material-icons arrow_back"></span>
<span>${LabelPrevious}</span>
<span>${Previous}</span>
</button>
<button is="emby-button" type="submit" class="raised button-submit">
<span>${LabelNext}</span>
<span>${Next}</span>
<span class="material-icons arrow_forward"></span>
</button>
</div>

View file

@ -23,10 +23,10 @@ function submit(form) {
const apiClient = getApiClient();
apiClient.ajax({
type: 'POST',
data: {
data: JSON.stringify({
Name: form.querySelector('#txtUsername').value,
Password: form.querySelector('#txtManualPassword').value
},
}),
url: apiClient.getUrl('Startup/User')
}).then(onUpdateUserComplete);
}

View file

@ -10,7 +10,7 @@ import 'webcomponents';
function onKeyDown(e) {
// Don't submit form on enter
// Real (non-emulator) Tizen does nothing on Space
if (e.keyCode === 13 || e.keyCode === 32) {
if (e.keyCode === 13 || (e.keyCode === 32 && browser.tizen)) {
e.preventDefault();
this.checked = !this.checked;

View file

@ -1,6 +1,7 @@
import layoutManager from 'layoutManager';
import 'css!./emby-radio';
import 'webcomponents';
import browser from 'browser';
/* eslint-disable indent */
@ -9,7 +10,7 @@ import 'webcomponents';
function onKeyDown(e) {
// Don't submit form on enter
// Real (non-emulator) Tizen does nothing on Space
if (e.keyCode === 13 || e.keyCode === 32) {
if (e.keyCode === 13 || (e.keyCode === 32 && browser.tizen)) {
e.preventDefault();
if (!this.checked) {

View file

@ -1,61 +1,61 @@
define(['connectionManager', 'globalize', 'userSettings', 'apphost'], function (connectionManager, globalize, userSettings, appHost) {
'use strict';
import globalize from 'globalize';
import * as userSettings from 'userSettings';
import appHost from 'apphost';
appHost = appHost.default || appHost;
// TODO: Replace with date-fns
// https://stackoverflow.com/questions/6117814/get-week-of-year-in-javascript-like-in-php
function getWeek(date) {
const d = new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()));
const dayNum = d.getUTCDay() || 7;
d.setUTCDate(d.getUTCDate() + 4 - dayNum);
const yearStart = new Date(Date.UTC(d.getUTCFullYear(), 0, 1));
return Math.ceil((((d - yearStart) / 86400000) + 1) / 7);
}
// TODO: Replace with date-fns
// https://stackoverflow.com/questions/6117814/get-week-of-year-in-javascript-like-in-php
function getWeek(date) {
var d = new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()));
var dayNum = d.getUTCDay() || 7;
d.setUTCDate(d.getUTCDate() + 4 - dayNum);
var yearStart = new Date(Date.UTC(d.getUTCFullYear(), 0, 1));
return Math.ceil((((d - yearStart) / 86400000) + 1) / 7);
function showMessage(text, userSettingsKey, appHostFeature) {
if (appHost.supports(appHostFeature)) {
return Promise.resolve();
}
function showMessage(text, userSettingsKey, appHostFeature) {
if (appHost.supports(appHostFeature)) {
return Promise.resolve();
}
const now = new Date();
var now = new Date();
// TODO: Use date-fns
userSettingsKey += now.getFullYear() + '-w' + getWeek(now);
// TODO: Use date-fns
userSettingsKey += now.getFullYear() + '-w' + getWeek(now);
if (userSettings.get(userSettingsKey, false) === '1') {
return Promise.resolve();
}
if (userSettings.get(userSettingsKey, false) === '1') {
return Promise.resolve();
}
return new Promise(function (resolve, reject) {
userSettings.set(userSettingsKey, '1', false);
return new Promise(function (resolve, reject) {
userSettings.set(userSettingsKey, '1', false);
require(['alert'], function (alert) {
return alert(text).then(resolve, resolve);
});
import('alert').then(({default: alert}) => {
return alert(text).then(resolve, resolve);
});
}
});
}
function showBlurayMessage() {
return showMessage(globalize.translate('UnsupportedPlayback'), 'blurayexpirementalinfo', 'nativeblurayplayback');
}
function showBlurayMessage() {
return showMessage(globalize.translate('UnsupportedPlayback'), 'blurayexpirementalinfo', 'nativeblurayplayback');
}
function showDvdMessage() {
return showMessage(globalize.translate('UnsupportedPlayback'), 'dvdexpirementalinfo', 'nativedvdplayback');
}
function showDvdMessage() {
return showMessage(globalize.translate('UnsupportedPlayback'), 'dvdexpirementalinfo', 'nativedvdplayback');
}
function showIsoMessage() {
return showMessage(globalize.translate('UnsupportedPlayback'), 'isoexpirementalinfo', 'nativeisoplayback');
}
function showIsoMessage() {
return showMessage(globalize.translate('UnsupportedPlayback'), 'isoexpirementalinfo', 'nativeisoplayback');
}
function ExpirementalPlaybackWarnings() {
class ExpirementalPlaybackWarnings {
constructor() {
this.name = 'Experimental playback warnings';
this.type = 'preplayintercept';
this.id = 'expirementalplaybackwarnings';
}
ExpirementalPlaybackWarnings.prototype.intercept = function (options) {
var item = options.item;
intercept(options) {
const item = options.item;
if (!item) {
return Promise.resolve();
}
@ -73,7 +73,7 @@ define(['connectionManager', 'globalize', 'userSettings', 'apphost'], function (
}
return Promise.resolve();
};
}
}
return ExpirementalPlaybackWarnings;
});
export default ExpirementalPlaybackWarnings;

View file

@ -150,7 +150,7 @@ function tryRemoveElement(elem) {
/**
* @type {string}
*/
name
name;
/**
* @type {string}
*/
@ -730,7 +730,7 @@ function tryRemoveElement(elem) {
const elem = e.target;
this.destroyCustomTrack(elem);
onEndedInternal(this, elem, this.onError);
}
};
/**
* @private
@ -760,7 +760,7 @@ function tryRemoveElement(elem) {
}
events.trigger(this, 'timeupdate');
}
};
/**
* @private
@ -773,7 +773,7 @@ function tryRemoveElement(elem) {
const elem = e.target;
saveVolume(elem.volume);
events.trigger(this, 'volumechange');
}
};
/**
* @private
@ -785,7 +785,7 @@ function tryRemoveElement(elem) {
this.onStartedAndNavigatedToOsd();
}
}
};
/**
* @private
@ -832,14 +832,14 @@ function tryRemoveElement(elem) {
}
}
events.trigger(this, 'playing');
}
};
/**
* @private
*/
onPlay = () => {
events.trigger(this, 'unpause');
}
};
/**
* @private
@ -865,21 +865,21 @@ function tryRemoveElement(elem) {
*/
onClick = () => {
events.trigger(this, 'click');
}
};
/**
* @private
*/
onDblClick = () => {
events.trigger(this, 'dblclick');
}
};
/**
* @private
*/
onPause = () => {
events.trigger(this, 'pause');
}
};
onWaiting() {
events.trigger(this, 'waiting');
@ -929,7 +929,7 @@ function tryRemoveElement(elem) {
}
onErrorInternal(this, type);
}
};
/**
* @private
@ -1634,6 +1634,31 @@ function tryRemoveElement(elem) {
return null;
}
getSupportedPlaybackRates() {
return [{
name: '0.5x',
id: 0.5
}, {
name: '0.75x',
id: 0.75
}, {
name: '1x',
id: 1.0
}, {
name: '1.25x',
id: 1.25
}, {
name: '1.5x',
id: 1.5
}, {
name: '1.75x',
id: 1.75
}, {
name: '2x',
id: 2.0
}];
}
setVolume(val) {
const mediaElement = this.#mediaElement;
if (mediaElement) {

View file

@ -1,132 +1,123 @@
define(['playbackManager', 'events', 'serverNotifications', 'connectionManager'], function (playbackManager, events, serverNotifications, connectionManager) {
'use strict';
import playbackManager from 'playbackManager';
import events from 'events';
import serverNotifications from 'serverNotifications';
import connectionManager from 'connectionManager';
serverNotifications = serverNotifications.default || serverNotifications;
playbackManager = playbackManager.default || playbackManager;
function getActivePlayerId() {
const info = playbackManager.getPlayerInfo();
return info ? info.id : null;
}
function getActivePlayerId() {
var info = playbackManager.getPlayerInfo();
return info ? info.id : null;
function sendPlayCommand(apiClient, options, playType) {
const sessionId = getActivePlayerId();
const ids = options.ids || options.items.map(function (i) {
return i.Id;
});
const remoteOptions = {
ItemIds: ids.join(','),
PlayCommand: playType
};
if (options.startPositionTicks) {
remoteOptions.StartPositionTicks = options.startPositionTicks;
}
function sendPlayCommand(apiClient, options, playType) {
var sessionId = getActivePlayerId();
var ids = options.ids || options.items.map(function (i) {
return i.Id;
});
var remoteOptions = {
ItemIds: ids.join(','),
PlayCommand: playType
};
if (options.startPositionTicks) {
remoteOptions.StartPositionTicks = options.startPositionTicks;
}
if (options.mediaSourceId) {
remoteOptions.MediaSourceId = options.mediaSourceId;
}
if (options.audioStreamIndex != null) {
remoteOptions.AudioStreamIndex = options.audioStreamIndex;
}
if (options.subtitleStreamIndex != null) {
remoteOptions.SubtitleStreamIndex = options.subtitleStreamIndex;
}
if (options.startIndex != null) {
remoteOptions.StartIndex = options.startIndex;
}
return apiClient.sendPlayCommand(sessionId, remoteOptions);
if (options.mediaSourceId) {
remoteOptions.MediaSourceId = options.mediaSourceId;
}
function sendPlayStateCommand(apiClient, command, options) {
var sessionId = getActivePlayerId();
apiClient.sendPlayStateCommand(sessionId, command, options);
if (options.audioStreamIndex != null) {
remoteOptions.AudioStreamIndex = options.audioStreamIndex;
}
function getCurrentApiClient(instance) {
var currentServerId = instance.currentServerId;
if (currentServerId) {
return connectionManager.getApiClient(currentServerId);
}
return connectionManager.currentApiClient();
if (options.subtitleStreamIndex != null) {
remoteOptions.SubtitleStreamIndex = options.subtitleStreamIndex;
}
function sendCommandByName(instance, name, options) {
var command = {
Name: name
};
if (options) {
command.Arguments = options;
}
instance.sendCommand(command);
if (options.startIndex != null) {
remoteOptions.StartIndex = options.startIndex;
}
function unsubscribeFromPlayerUpdates(instance) {
instance.isUpdating = true;
return apiClient.sendPlayCommand(sessionId, remoteOptions);
}
var apiClient = getCurrentApiClient(instance);
apiClient.sendMessage('SessionsStop');
if (instance.pollInterval) {
clearInterval(instance.pollInterval);
instance.pollInterval = null;
}
function sendPlayStateCommand(apiClient, command, options) {
const sessionId = getActivePlayerId();
apiClient.sendPlayStateCommand(sessionId, command, options);
}
function getCurrentApiClient(instance) {
const currentServerId = instance.currentServerId;
if (currentServerId) {
return connectionManager.getApiClient(currentServerId);
}
function processUpdatedSessions(instance, sessions, apiClient) {
var serverId = apiClient.serverId();
return connectionManager.currentApiClient();
}
sessions.map(function (s) {
if (s.NowPlayingItem) {
s.NowPlayingItem.ServerId = serverId;
}
});
function sendCommandByName(instance, name, options) {
const command = {
Name: name
};
var currentTargetId = getActivePlayerId();
var session = sessions.filter(function (s) {
return s.Id === currentTargetId;
})[0];
if (session) {
normalizeImages(session, apiClient);
var eventNames = getChangedEvents(instance.lastPlayerData, session);
instance.lastPlayerData = session;
for (var i = 0, length = eventNames.length; i < length; i++) {
events.trigger(instance, eventNames[i], [session]);
}
} else {
instance.lastPlayerData = session;
playbackManager.setDefaultPlayerActive();
}
if (options) {
command.Arguments = options;
}
function getChangedEvents(state1, state2) {
var names = [];
instance.sendCommand(command);
}
if (!state1) {
names.push('statechange');
names.push('timeupdate');
names.push('pause');
function unsubscribeFromPlayerUpdates(instance) {
instance.isUpdating = true;
return names;
const apiClient = getCurrentApiClient(instance);
apiClient.sendMessage('SessionsStop');
if (instance.pollInterval) {
clearInterval(instance.pollInterval);
instance.pollInterval = null;
}
}
function processUpdatedSessions(instance, sessions, apiClient) {
const serverId = apiClient.serverId();
sessions.map(function (s) {
if (s.NowPlayingItem) {
s.NowPlayingItem.ServerId = serverId;
}
});
// TODO: Trim these down to prevent the UI from over-refreshing
const currentTargetId = getActivePlayerId();
const session = sessions.filter(function (s) {
return s.Id === currentTargetId;
})[0];
if (session) {
normalizeImages(session, apiClient);
const eventNames = getChangedEvents(instance.lastPlayerData, session);
instance.lastPlayerData = session;
for (let i = 0, length = eventNames.length; i < length; i++) {
events.trigger(instance, eventNames[i], [session]);
}
} else {
instance.lastPlayerData = session;
playbackManager.setDefaultPlayerActive();
}
}
function getChangedEvents(state1, state2) {
const names = [];
if (!state1) {
names.push('statechange');
names.push('timeupdate');
names.push('pause');
@ -134,53 +125,62 @@ define(['playbackManager', 'events', 'serverNotifications', 'connectionManager']
return names;
}
function onPollIntervalFired() {
var instance = this;
var apiClient = getCurrentApiClient(instance);
if (!apiClient.isMessageChannelOpen()) {
apiClient.getSessions().then(function (sessions) {
processUpdatedSessions(instance, sessions, apiClient);
});
}
// TODO: Trim these down to prevent the UI from over-refreshing
names.push('statechange');
names.push('timeupdate');
names.push('pause');
return names;
}
function onPollIntervalFired() {
const instance = this;
const apiClient = getCurrentApiClient(instance);
if (!apiClient.isMessageChannelOpen()) {
apiClient.getSessions().then(function (sessions) {
processUpdatedSessions(instance, sessions, apiClient);
});
}
}
function subscribeToPlayerUpdates(instance) {
instance.isUpdating = true;
function subscribeToPlayerUpdates(instance) {
instance.isUpdating = true;
var apiClient = getCurrentApiClient(instance);
apiClient.sendMessage('SessionsStart', '100,800');
if (instance.pollInterval) {
clearInterval(instance.pollInterval);
instance.pollInterval = null;
}
instance.pollInterval = setInterval(onPollIntervalFired.bind(instance), 5000);
const apiClient = getCurrentApiClient(instance);
apiClient.sendMessage('SessionsStart', '100,800');
if (instance.pollInterval) {
clearInterval(instance.pollInterval);
instance.pollInterval = null;
}
instance.pollInterval = setInterval(onPollIntervalFired.bind(instance), 5000);
}
function normalizeImages(state, apiClient) {
if (state && state.NowPlayingItem) {
var item = state.NowPlayingItem;
function normalizeImages(state, apiClient) {
if (state && state.NowPlayingItem) {
const item = state.NowPlayingItem;
if (!item.ImageTags || !item.ImageTags.Primary) {
if (item.PrimaryImageTag) {
item.ImageTags = item.ImageTags || {};
item.ImageTags.Primary = item.PrimaryImageTag;
}
}
if (item.BackdropImageTag && item.BackdropItemId === item.Id) {
item.BackdropImageTags = [item.BackdropImageTag];
}
if (item.BackdropImageTag && item.BackdropItemId !== item.Id) {
item.ParentBackdropImageTags = [item.BackdropImageTag];
item.ParentBackdropItemId = item.BackdropItemId;
}
if (!item.ServerId) {
item.ServerId = apiClient.serverId();
if (!item.ImageTags || !item.ImageTags.Primary) {
if (item.PrimaryImageTag) {
item.ImageTags = item.ImageTags || {};
item.ImageTags.Primary = item.PrimaryImageTag;
}
}
if (item.BackdropImageTag && item.BackdropItemId === item.Id) {
item.BackdropImageTags = [item.BackdropImageTag];
}
if (item.BackdropImageTag && item.BackdropItemId !== item.Id) {
item.ParentBackdropImageTags = [item.BackdropImageTag];
item.ParentBackdropItemId = item.BackdropItemId;
}
if (!item.ServerId) {
item.ServerId = apiClient.serverId();
}
}
}
function SessionPlayer() {
var self = this;
class SessionPlayer {
constructor() {
const self = this;
this.name = 'Remote Control';
this.type = 'mediaplayer';
@ -192,7 +192,7 @@ define(['playbackManager', 'events', 'serverNotifications', 'connectionManager']
});
}
SessionPlayer.prototype.beginPlayerUpdates = function () {
beginPlayerUpdates() {
this.playerListenerCount = this.playerListenerCount || 0;
if (this.playerListenerCount <= 0) {
@ -202,9 +202,9 @@ define(['playbackManager', 'events', 'serverNotifications', 'connectionManager']
}
this.playerListenerCount++;
};
}
SessionPlayer.prototype.endPlayerUpdates = function () {
endPlayerUpdates() {
this.playerListenerCount = this.playerListenerCount || 0;
this.playerListenerCount--;
@ -212,21 +212,21 @@ define(['playbackManager', 'events', 'serverNotifications', 'connectionManager']
unsubscribeFromPlayerUpdates(this);
this.playerListenerCount = 0;
}
};
}
SessionPlayer.prototype.getPlayerState = function () {
getPlayerState() {
return this.lastPlayerData || {};
};
}
SessionPlayer.prototype.getTargets = function () {
var apiClient = getCurrentApiClient(this);
getTargets() {
const apiClient = getCurrentApiClient(this);
var sessionQuery = {
const sessionQuery = {
ControllableByUserId: apiClient.getCurrentUserId()
};
if (apiClient) {
var name = this.name;
const name = this.name;
return apiClient.getSessions(sessionQuery).then(function (sessions) {
return sessions.filter(function (s) {
@ -243,11 +243,9 @@ define(['playbackManager', 'events', 'serverNotifications', 'connectionManager']
isLocalPlayer: false,
supportedCommands: s.Capabilities.SupportedCommands,
user: s.UserId ? {
Id: s.UserId,
Name: s.UserName,
PrimaryImageTag: s.UserPrimaryImageTag
} : null
};
});
@ -255,16 +253,16 @@ define(['playbackManager', 'events', 'serverNotifications', 'connectionManager']
} else {
return Promise.resolve([]);
}
};
}
SessionPlayer.prototype.sendCommand = function (command) {
var sessionId = getActivePlayerId();
sendCommand(command) {
const sessionId = getActivePlayerId();
var apiClient = getCurrentApiClient(this);
const apiClient = getCurrentApiClient(this);
apiClient.sendCommand(sessionId, command);
};
}
SessionPlayer.prototype.play = function (options) {
play(options) {
options = Object.assign({}, options);
if (options.items) {
@ -276,251 +274,233 @@ define(['playbackManager', 'events', 'serverNotifications', 'connectionManager']
}
return sendPlayCommand(getCurrentApiClient(this), options, 'PlayNow');
};
}
SessionPlayer.prototype.shuffle = function (item) {
shuffle(item) {
sendPlayCommand(getCurrentApiClient(this), { ids: [item.Id] }, 'PlayShuffle');
};
}
SessionPlayer.prototype.instantMix = function (item) {
instantMix(item) {
sendPlayCommand(getCurrentApiClient(this), { ids: [item.Id] }, 'PlayInstantMix');
};
}
SessionPlayer.prototype.queue = function (options) {
queue(options) {
sendPlayCommand(getCurrentApiClient(this), options, 'PlayNext');
};
}
SessionPlayer.prototype.queueNext = function (options) {
queueNext(options) {
sendPlayCommand(getCurrentApiClient(this), options, 'PlayLast');
};
}
SessionPlayer.prototype.canPlayMediaType = function (mediaType) {
canPlayMediaType(mediaType) {
mediaType = (mediaType || '').toLowerCase();
return mediaType === 'audio' || mediaType === 'video';
};
}
SessionPlayer.prototype.canQueueMediaType = function (mediaType) {
canQueueMediaType(mediaType) {
return this.canPlayMediaType(mediaType);
};
}
SessionPlayer.prototype.stop = function () {
stop() {
sendPlayStateCommand(getCurrentApiClient(this), 'stop');
};
}
SessionPlayer.prototype.nextTrack = function () {
nextTrack() {
sendPlayStateCommand(getCurrentApiClient(this), 'nextTrack');
};
}
SessionPlayer.prototype.previousTrack = function () {
previousTrack() {
sendPlayStateCommand(getCurrentApiClient(this), 'previousTrack');
};
}
SessionPlayer.prototype.seek = function (positionTicks) {
seek(positionTicks) {
sendPlayStateCommand(getCurrentApiClient(this), 'seek',
{
SeekPositionTicks: positionTicks
});
};
}
SessionPlayer.prototype.currentTime = function (val) {
currentTime(val) {
if (val != null) {
return this.seek(val);
}
var state = this.lastPlayerData || {};
let state = this.lastPlayerData || {};
state = state.PlayState || {};
return state.PositionTicks;
};
}
SessionPlayer.prototype.duration = function () {
var state = this.lastPlayerData || {};
duration() {
let state = this.lastPlayerData || {};
state = state.NowPlayingItem || {};
return state.RunTimeTicks;
};
}
SessionPlayer.prototype.paused = function () {
var state = this.lastPlayerData || {};
paused() {
let state = this.lastPlayerData || {};
state = state.PlayState || {};
return state.IsPaused;
};
}
SessionPlayer.prototype.getVolume = function () {
var state = this.lastPlayerData || {};
getVolume() {
let state = this.lastPlayerData || {};
state = state.PlayState || {};
return state.VolumeLevel;
};
}
SessionPlayer.prototype.isMuted = function () {
var state = this.lastPlayerData || {};
isMuted() {
let state = this.lastPlayerData || {};
state = state.PlayState || {};
return state.IsMuted;
};
}
SessionPlayer.prototype.pause = function () {
pause() {
sendPlayStateCommand(getCurrentApiClient(this), 'Pause');
};
}
SessionPlayer.prototype.unpause = function () {
unpause() {
sendPlayStateCommand(getCurrentApiClient(this), 'Unpause');
};
}
SessionPlayer.prototype.playPause = function () {
playPause() {
sendPlayStateCommand(getCurrentApiClient(this), 'PlayPause');
};
}
SessionPlayer.prototype.setMute = function (isMuted) {
setMute(isMuted) {
if (isMuted) {
sendCommandByName(this, 'Mute');
} else {
sendCommandByName(this, 'Unmute');
}
};
}
SessionPlayer.prototype.toggleMute = function () {
toggleMute() {
sendCommandByName(this, 'ToggleMute');
};
}
SessionPlayer.prototype.setVolume = function (vol) {
setVolume(vol) {
sendCommandByName(this, 'SetVolume', {
Volume: vol
});
};
}
SessionPlayer.prototype.volumeUp = function () {
volumeUp() {
sendCommandByName(this, 'VolumeUp');
};
}
SessionPlayer.prototype.volumeDown = function () {
volumeDown() {
sendCommandByName(this, 'VolumeDown');
};
}
SessionPlayer.prototype.toggleFullscreen = function () {
toggleFullscreen() {
sendCommandByName(this, 'ToggleFullscreen');
};
}
SessionPlayer.prototype.audioTracks = function () {
var state = this.lastPlayerData || {};
audioTracks() {
let state = this.lastPlayerData || {};
state = state.NowPlayingItem || {};
var streams = state.MediaStreams || [];
const streams = state.MediaStreams || [];
return streams.filter(function (s) {
return s.Type === 'Audio';
});
};
}
SessionPlayer.prototype.getAudioStreamIndex = function () {
var state = this.lastPlayerData || {};
getAudioStreamIndex() {
let state = this.lastPlayerData || {};
state = state.PlayState || {};
return state.AudioStreamIndex;
};
}
SessionPlayer.prototype.playTrailers = function (item) {
playTrailers(item) {
sendCommandByName(this, 'PlayTrailers', {
ItemId: item.Id
});
};
}
SessionPlayer.prototype.setAudioStreamIndex = function (index) {
setAudioStreamIndex(index) {
sendCommandByName(this, 'SetAudioStreamIndex', {
Index: index
});
};
}
SessionPlayer.prototype.subtitleTracks = function () {
var state = this.lastPlayerData || {};
subtitleTracks() {
let state = this.lastPlayerData || {};
state = state.NowPlayingItem || {};
var streams = state.MediaStreams || [];
const streams = state.MediaStreams || [];
return streams.filter(function (s) {
return s.Type === 'Subtitle';
});
};
}
SessionPlayer.prototype.getSubtitleStreamIndex = function () {
var state = this.lastPlayerData || {};
getSubtitleStreamIndex() {
let state = this.lastPlayerData || {};
state = state.PlayState || {};
return state.SubtitleStreamIndex;
};
}
SessionPlayer.prototype.setSubtitleStreamIndex = function (index) {
setSubtitleStreamIndex(index) {
sendCommandByName(this, 'SetSubtitleStreamIndex', {
Index: index
});
};
}
SessionPlayer.prototype.getMaxStreamingBitrate = function () {
};
SessionPlayer.prototype.setMaxStreamingBitrate = function (options) {
};
SessionPlayer.prototype.isFullscreen = function () {
};
SessionPlayer.prototype.toggleFullscreen = function () {
};
SessionPlayer.prototype.getRepeatMode = function () {
};
SessionPlayer.prototype.setRepeatMode = function (mode) {
setRepeatMode(mode) {
sendCommandByName(this, 'SetRepeatMode', {
RepeatMode: mode
});
};
}
SessionPlayer.prototype.setQueueShuffleMode = function (mode) {
getRepeatMode() {
}
setQueueShuffleMode(mode) {
sendCommandByName(this, 'SetShuffleQueue', {
ShuffleMode: mode
});
};
}
SessionPlayer.prototype.getQueueShuffleMode = function () {
getQueueShuffleMode() {
}
};
SessionPlayer.prototype.displayContent = function (options) {
displayContent(options) {
sendCommandByName(this, 'DisplayContent', options);
};
}
SessionPlayer.prototype.isPlaying = function () {
var state = this.lastPlayerData || {};
isPlaying() {
const state = this.lastPlayerData || {};
return state.NowPlayingItem != null;
};
}
SessionPlayer.prototype.isPlayingVideo = function () {
var state = this.lastPlayerData || {};
isPlayingVideo() {
let state = this.lastPlayerData || {};
state = state.NowPlayingItem || {};
return state.MediaType === 'Video';
};
}
SessionPlayer.prototype.isPlayingAudio = function () {
var state = this.lastPlayerData || {};
isPlayingAudio() {
let state = this.lastPlayerData || {};
state = state.NowPlayingItem || {};
return state.MediaType === 'Audio';
};
}
SessionPlayer.prototype.getPlaylist = function () {
getPlaylist() {
return Promise.resolve([]);
};
}
SessionPlayer.prototype.getCurrentPlaylistItemId = function () {
};
getCurrentPlaylistItemId() {
}
SessionPlayer.prototype.setCurrentPlaylistItem = function (playlistItemId) {
setCurrentPlaylistItem(playlistItemId) {
return Promise.resolve();
};
}
SessionPlayer.prototype.removeFromPlaylist = function (playlistItemIds) {
removeFromPlaylist(playlistItemIds) {
return Promise.resolve();
};
}
SessionPlayer.prototype.tryPair = function (target) {
tryPair(target) {
return Promise.resolve();
};
}
}
return SessionPlayer;
});
export default SessionPlayer;

233
src/scripts/clientUtils.js Normal file
View file

@ -0,0 +1,233 @@
export function getCurrentUser() {
return window.ApiClient.getCurrentUser(false);
}
//TODO: investigate url prefix support for serverAddress function
export function serverAddress() {
if (AppInfo.isNativeApp) {
const apiClient = window.ApiClient;
if (apiClient) {
return apiClient.serverAddress();
}
return null;
}
const urlLower = window.location.href.toLowerCase();
const index = urlLower.lastIndexOf('/web');
if (index != -1) {
return urlLower.substring(0, index);
}
const loc = window.location;
let address = loc.protocol + '//' + loc.hostname;
if (loc.port) {
address += ':' + loc.port;
}
return address;
}
export function getCurrentUserId() {
const apiClient = window.ApiClient;
if (apiClient) {
return apiClient.getCurrentUserId();
}
return null;
}
export function onServerChanged(userId, accessToken, apiClient) {
apiClient = apiClient || window.ApiClient;
window.ApiClient = apiClient;
}
export function logout() {
ConnectionManager.logout().then(function () {
let loginPage;
if (AppInfo.isNativeApp) {
loginPage = 'selectserver.html';
window.ApiClient = null;
} else {
loginPage = 'login.html';
}
navigate(loginPage);
});
}
export function getConfigurationPageUrl(name) {
return 'configurationpage?name=' + encodeURIComponent(name);
}
export function getConfigurationResourceUrl(name) {
if (AppInfo.isNativeApp) {
return ApiClient.getUrl('web/ConfigurationPage', {
name: name
});
}
return getConfigurationPageUrl(name);
}
export function navigate(url, preserveQueryString) {
if (!url) {
throw new Error('url cannot be null or empty');
}
const queryString = getWindowLocationSearch();
if (preserveQueryString && queryString) {
url += queryString;
}
return new Promise(function (resolve, reject) {
import('appRouter').then(({default: appRouter}) => {
return appRouter.show(url).then(resolve, reject);
});
});
}
export function processPluginConfigurationUpdateResult() {
Promise.all([
import('loading'),
import('toast')
])
.then(([{default: loading}, {default: toast}]) => {
loading.hide();
toast(Globalize.translate('SettingsSaved'));
});
}
export function processServerConfigurationUpdateResult(result) {
Promise.all([
import('loading'),
import('toast')
])
.then(([{default: loading}, {default: toast}]) => {
loading.hide();
toast(Globalize.translate('SettingsSaved'));
});
}
export function processErrorResponse(response) {
import('loading').then(({default: loading}) => {
loading.hide();
});
let status = '' + response.status;
if (response.statusText) {
status = response.statusText;
}
alert({
title: status,
message: response.headers ? response.headers.get('X-Application-Error-Code') : null
});
}
export function alert(options) {
if (typeof options == 'string') {
return void import('toast').then(({default: toast}) => {
toast({
text: options
});
});
}
import('alert').then(({default: alert}) => {
alert({
title: options.title || Globalize.translate('HeaderAlert'),
text: options.message
}).then(options.callback || function () {});
});
}
export function capabilities(appHost) {
let capabilities = {
PlayableMediaTypes: ['Audio', 'Video'],
SupportedCommands: ['MoveUp', 'MoveDown', 'MoveLeft', 'MoveRight', 'PageUp', 'PageDown', 'PreviousLetter', 'NextLetter', 'ToggleOsd', 'ToggleContextMenu', 'Select', 'Back', 'SendKey', 'SendString', 'GoHome', 'GoToSettings', 'VolumeUp', 'VolumeDown', 'Mute', 'Unmute', 'ToggleMute', 'SetVolume', 'SetAudioStreamIndex', 'SetSubtitleStreamIndex', 'DisplayContent', 'GoToSearch', 'DisplayMessage', 'SetRepeatMode', 'SetShuffleQueue', 'ChannelUp', 'ChannelDown', 'PlayMediaSource', 'PlayTrailers'],
SupportsPersistentIdentifier: self.appMode === 'cordova' || self.appMode === 'android',
SupportsMediaControl: true
};
return Object.assign(capabilities, appHost.getPushTokenInfo());
}
export function selectServer() {
if (window.NativeShell && typeof window.NativeShell.selectServer === 'function') {
window.NativeShell.selectServer();
} else {
navigate('selectserver.html');
}
}
export function hideLoadingMsg() {
import('loading').then(({default: loading}) => {
loading.hide();
});
}
export function showLoadingMsg() {
import('loading').then(({default: loading}) => {
loading.show();
});
}
export function confirm(message, title, callback) {
import('confirm').then(({default: confirm}) => {
confirm(message, title).then(function() {
callback(!0);
}).catch(function() {
callback(!1);
});
});
}
// This is used in plugins and templates, so keep it defined for now.
// TODO: Remove once plugins don't need it
window.Dashboard = {
alert,
capabilities,
confirm,
getConfigurationPageUrl,
getConfigurationResourceUrl,
getCurrentUser,
getCurrentUserId,
hideLoadingMsg,
logout,
navigate,
onServerChanged,
processErrorResponse,
processPluginConfigurationUpdateResult,
processServerConfigurationUpdateResult,
selectServer,
serverAddress,
showLoadingMsg
};
export default {
alert,
capabilities,
confirm,
getConfigurationPageUrl,
getConfigurationResourceUrl,
getCurrentUser,
getCurrentUserId,
hideLoadingMsg,
logout,
navigate,
onServerChanged,
processErrorResponse,
processPluginConfigurationUpdateResult,
processServerConfigurationUpdateResult,
selectServer,
serverAddress,
showLoadingMsg
};

View file

@ -86,7 +86,7 @@ import 'material-icons';
if (result.TotalRecordCount) {
nodes.push({
id: 'livetv',
text: globalize.translate('HeaderLiveTV'),
text: globalize.translate('LiveTV'),
state: {
opened: false
},
@ -302,7 +302,7 @@ import 'material-icons';
$(document).on('itemsaved', '.metadataEditorPage', function (e, item) {
updateEditorNode(this, item);
}).on('pagebeforeshow', '.metadataEditorPage', function () {
/* eslint-disable-next-line no-unused-expressions */
/* eslint-disable-next-line @babel/no-unused-expressions */
import('css!assets/css/metadataeditor.css');
}).on('pagebeforeshow', '.metadataEditorPage', function () {
var page = this;

View file

@ -185,6 +185,12 @@ import appHost from 'apphost';
'changezoom': () => {
playbackManager.toggleAspectRatio();
},
'increaseplaybackrate': () => {
playbackManager.increasePlaybackRate();
},
'decreaseplaybackrate': () => {
playbackManager.decreasePlaybackRate();
},
'changeaudiotrack': () => {
playbackManager.changeAudioStream();
},

View file

@ -25,42 +25,42 @@ function renderItems(page, item) {
if (item.MovieCount) {
sections.push({
name: globalize.translate('TabMovies'),
name: globalize.translate('Movies'),
type: 'Movie'
});
}
if (item.SeriesCount) {
sections.push({
name: globalize.translate('TabShows'),
name: globalize.translate('Shows'),
type: 'Series'
});
}
if (item.EpisodeCount) {
sections.push({
name: globalize.translate('TabEpisodes'),
name: globalize.translate('Episodes'),
type: 'Episode'
});
}
if (item.TrailerCount) {
sections.push({
name: globalize.translate('TabTrailers'),
name: globalize.translate('Trailers'),
type: 'Trailer'
});
}
if (item.AlbumCount) {
sections.push({
name: globalize.translate('TabAlbums'),
name: globalize.translate('Albums'),
type: 'MusicAlbum'
});
}
if (item.MusicVideoCount) {
sections.push({
name: globalize.translate('TabMusicVideos'),
name: globalize.translate('HeaderMusicVideos'),
type: 'MusicVideo'
});
}

View file

@ -155,7 +155,7 @@ export function enable() {
function attachGamepadScript(e) {
console.log('Gamepad connected! Attaching gamepadtokey.js script');
window.removeEventListener('gamepadconnected', attachGamepadScript);
/* eslint-disable-next-line no-unused-expressions */
/* eslint-disable-next-line @babel/no-unused-expressions */
import('scripts/gamepadtokey');
}

View file

@ -105,11 +105,11 @@ export function getQueryPagingHtml (options) {
}
if (options.sortButton) {
html += '<button is="paper-icon-button-light" class="btnSort autoSize" title="' + globalize.translate('ButtonSort') + '"><span class="material-icons sort_by_alpha"></span></button>';
html += '<button is="paper-icon-button-light" class="btnSort autoSize" title="' + globalize.translate('Sort') + '"><span class="material-icons sort_by_alpha"></span></button>';
}
if (options.filterButton) {
html += '<button is="paper-icon-button-light" class="btnFilter autoSize" title="' + globalize.translate('ButtonFilter') + '"><span class="material-icons filter_list"></span></button>';
html += '<button is="paper-icon-button-light" class="btnFilter autoSize" title="' + globalize.translate('Filter') + '"><span class="material-icons filter_list"></span></button>';
}
html += '</div>';

Some files were not shown because too many files have changed in this diff Show more