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

View file

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

View file

@ -1,5 +1,5 @@
<div class="formDialogHeader"> <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> <span class="material-icons arrow_back" aria-hidden="true"></span>
</button> </button>
<h3 class="formDialogHeaderTitle"> <h3 class="formDialogHeaderTitle">
@ -12,13 +12,13 @@
<div class="selectContainer"> <div class="selectContainer">
<select is="emby-select" id="selectDay" label="${LabelAccessDay}"> <select is="emby-select" id="selectDay" label="${LabelAccessDay}">
<option value="Sunday">${OptionSunday}</option> <option value="Sunday">${Sunday}</option>
<option value="Monday">${OptionMonday}</option> <option value="Monday">${Monday}</option>
<option value="Tuesday">${OptionTuesday}</option> <option value="Tuesday">${Tuesday}</option>
<option value="Wednesday">${OptionWednesday}</option> <option value="Wednesday">${Wednesday}</option>
<option value="Thursday">${OptionThursday}</option> <option value="Thursday">${Thursday}</option>
<option value="Friday">${OptionFriday}</option> <option value="Friday">${Friday}</option>
<option value="Saturday">${OptionSaturday}</option> <option value="Saturday">${Saturday}</option>
<option value="Everyday">${OptionEveryday}</option> <option value="Everyday">${OptionEveryday}</option>
<option value="Weekday">${OptionWeekdays}</option> <option value="Weekday">${OptionWeekdays}</option>
<option value="Weekend">${OptionWeekends}</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() { function importRefreshIndicator() {
if (!refreshIndicatorLoaded) { if (!refreshIndicatorLoaded) {
refreshIndicatorLoaded = true; refreshIndicatorLoaded = true;
/* eslint-disable-next-line no-unused-expressions */ /* eslint-disable-next-line @babel/no-unused-expressions */
import('emby-itemrefreshindicator'); import('emby-itemrefreshindicator');
} }
} }
@ -1449,7 +1449,7 @@ import 'programStyles';
const userData = item.UserData || {}; const userData = item.UserData || {};
if (itemHelper.canMarkPlayed(item)) { if (itemHelper.canMarkPlayed(item)) {
/* eslint-disable-next-line no-unused-expressions */ /* eslint-disable-next-line @babel/no-unused-expressions */
import('emby-playstatebutton'); 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>'; 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)) { if (itemHelper.canRate(item)) {
const likes = userData.Likes == null ? '' : userData.Likes; 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'); 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>'; 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({ connectionManager.getApiClient(options.serverId).ajax({
type: 'POST', type: 'POST',
url: ApiClient.getUrl('LiveTv/ChannelMappings'), url: ApiClient.getUrl('LiveTv/ChannelMappings'),
data: { data: JSON.stringify({
providerId: providerId, providerId: providerId,
tunerChannelId: channelId, tunerChannelId: channelId,
providerChannelId: providerChannelId providerChannelId: providerChannelId
}, }),
dataType: 'json' dataType: 'json'
}).then(mapping => { }).then(mapping => {
const listItem = dom.parentWithClass(button, 'listItem'); const listItem = dom.parentWithClass(button, 'listItem');
@ -93,7 +93,7 @@ export default class channelMapper {
html += '<div class="formDialogContent smoothScrollY">'; html += '<div class="formDialogContent smoothScrollY">';
html += '<div class="dialogContentInner dialog-content-centered">'; html += '<div class="dialogContentInner dialog-content-centered">';
html += '<form style="margin:auto;">'; html += '<form style="margin:auto;">';
html += `<h1>${globalize.translate('HeaderChannels')}</h1>`; html += `<h1>${globalize.translate('Channels')}</h1>`;
html += '<div class="channels paperList">'; html += '<div class="channels paperList">';
html += '</div>'; html += '</div>';
html += '</form>'; html += '</form>';

View file

@ -375,7 +375,7 @@ import 'scrollStyles';
dlg.setAttribute('data-lockscroll', 'true'); dlg.setAttribute('data-lockscroll', 'true');
} }
if (options.enableHistory !== false && appRouter.enableNativeHistory()) { if (options.enableHistory !== false) {
dlg.setAttribute('data-history', 'true'); 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 += `<input is="emby-input" id="txtDirectoryPickerPath" type="text" required="required" ${readOnlyAttribute} label="${globalize.translate(labelKey)}"/>`;
html += '</div>'; html += '</div>';
if (!readOnlyAttribute) { 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>'; html += '</div>';
if (!readOnlyAttribute) { if (!readOnlyAttribute) {
@ -166,10 +166,10 @@ import 'emby-button';
return apiClient.ajax({ return apiClient.ajax({
type: 'POST', type: 'POST',
url: apiClient.getUrl('Environment/ValidatePath'), url: apiClient.getUrl('Environment/ValidatePath'),
data: { data: JSON.stringify({
ValidateWriteable: validateWriteable, ValidateWriteable: validateWriteable,
Path: path Path: path
} })
}).catch(response => { }).catch(response => {
if (response) { if (response) {
if (response.status === 404) { if (response.status === 404) {

View file

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

View file

@ -90,7 +90,7 @@
</div> </div>
</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 class="collapseContent filterOptions">
</div> </div>
</div> </div>

View file

@ -1,5 +1,5 @@
<div class="formDialogHeader"> <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> <span class="material-icons arrow_back" aria-hidden="true"></span>
</button> </button>
<h3 class="formDialogHeaderTitle"> <h3 class="formDialogHeaderTitle">

View file

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

View file

@ -29,10 +29,10 @@
</div> </div>
<div class="guideOptions hide"> <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> <span class="material-icons arrow_back" aria-hidden="true"></span>
</button> </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> <span class="material-icons arrow_forward" aria-hidden="true"></span>
</button> </button>
</div> </div>

View file

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

View file

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

View file

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

View file

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

View file

@ -75,9 +75,9 @@ import 'emby-input';
html += '</h3>'; html += '</h3>';
html += '</div>'; html += '</div>';
if (i > 0) { 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) { } 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>'; html += '</div>';
} }
@ -131,9 +131,9 @@ import 'emby-input';
html += '</h3>'; html += '</h3>';
html += '</div>'; html += '</div>';
if (index > 0) { 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) { } 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>'; html += '</div>';
}); });
@ -197,9 +197,9 @@ import 'emby-input';
html += '</h3>'; html += '</h3>';
html += '</div>'; html += '</div>';
if (i > 0) { 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) { } 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>'; html += '</div>';
} }
@ -236,9 +236,9 @@ import 'emby-input';
html += '</h3>'; html += '</h3>';
html += '</div>'; html += '</div>';
if (i > 0) { 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) { } 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>'; html += '</div>';
} }
@ -291,13 +291,13 @@ import 'emby-input';
const btnSortable = elem.querySelector('.btnSortable'); const btnSortable = elem.querySelector('.btnSortable');
const inner = btnSortable.querySelector('.material-icons'); const inner = btnSortable.querySelector('.material-icons');
if (elem.previousSibling) { if (elem.previousSibling) {
btnSortable.title = globalize.translate('ButtonUp'); btnSortable.title = globalize.translate('Up');
btnSortable.classList.add('btnSortableMoveUp'); btnSortable.classList.add('btnSortableMoveUp');
btnSortable.classList.remove('btnSortableMoveDown'); btnSortable.classList.remove('btnSortableMoveDown');
inner.classList.remove('keyboard_arrow_down'); inner.classList.remove('keyboard_arrow_down');
inner.classList.add('keyboard_arrow_up'); inner.classList.add('keyboard_arrow_up');
} else { } else {
btnSortable.title = globalize.translate('ButtonDown'); btnSortable.title = globalize.translate('Down');
btnSortable.classList.remove('btnSortableMoveUp'); btnSortable.classList.remove('btnSortableMoveUp');
btnSortable.classList.add('btnSortableMoveDown'); btnSortable.classList.add('btnSortableMoveDown');
inner.classList.remove('keyboard_arrow_up'); inner.classList.remove('keyboard_arrow_up');

View file

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

View file

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

View file

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

View file

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

View file

@ -9,7 +9,6 @@ import 'programStyles';
import 'emby-button'; import 'emby-button';
/* eslint-disable indent */ /* eslint-disable indent */
function getTimerIndicator(item) { function getTimerIndicator(item) {
let status; let status;
@ -208,7 +207,7 @@ import 'emby-button';
}); });
} else if (item.IsSeries && !item.IsRepeat) { } else if (item.IsSeries && !item.IsRepeat) {
miscInfo.push({ 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) { } else if (item.IsSeries && item.IsRepeat) {
miscInfo.push({ miscInfo.push({

View file

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

View file

@ -1,28 +1,97 @@
define(['appSettings', 'pluginManager'], function (appSettings, pluginManager) { import appSettings from 'appSettings';
'use strict'; import pluginManager from 'pluginManager';
/* eslint-disable indent */
var settingsKey = 'installedpackages1'; class PackageManager {
#packagesList = [];
#settingsKey = 'installedpackages1';
function addPackage(packageManager, pkg) { init() {
packageManager.packagesList = packageManager.packagesList.filter(function (p) { console.groupCollapsed('loading packages');
var manifestUrls = JSON.parse(appSettings.get(this.#settingsKey) || '[]');
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');
});
}
get packages() {
return this.#packagesList.slice(0);
}
install(url) {
return this.loadPackage(url, true).then((pkg) => {
var manifestUrls = JSON.parse(appSettings.get(this.#settingsKey) || '[]');
if (!manifestUrls.includes(url)) {
manifestUrls.push(url);
appSettings.set(this.#settingsKey, JSON.stringify(manifestUrls));
}
return pkg;
});
}
uninstall(name) {
var pkg = this.#packagesList.filter((p) => {
return p.name === name;
})[0];
if (pkg) {
this.#packagesList = this.#packagesList.filter((p) => {
return p.name !== name;
});
this.removeUrl(pkg.url);
}
return Promise.resolve();
}
mapPath(pkg, pluginUrl) {
var urlLower = pluginUrl.toLowerCase();
if (urlLower.startsWith('http:') || urlLower.startsWith('https:') || urlLower.startsWith('file:')) {
return pluginUrl;
}
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; return p.name !== pkg.name;
}); });
packageManager.packagesList.push(pkg); this.#packagesList.push(pkg);
} }
function removeUrl(url) { removeUrl(url) {
var manifestUrls = JSON.parse(appSettings.get(settingsKey) || '[]'); var manifestUrls = JSON.parse(appSettings.get(this.#settingsKey) || '[]');
manifestUrls = manifestUrls.filter(function (i) { manifestUrls = manifestUrls.filter((i) => {
return i !== url; return i !== url;
}); });
appSettings.set(settingsKey, JSON.stringify(manifestUrls)); appSettings.set(this.#settingsKey, JSON.stringify(manifestUrls));
} }
function loadPackage(packageManager, url, throwError) { loadPackage(url, throwError = false) {
return new Promise(function (resolve, reject) { return new Promise((resolve, reject) => {
var xhr = new XMLHttpRequest(); var xhr = new XMLHttpRequest();
var originalUrl = url; var originalUrl = url;
url += url.indexOf('?') === -1 ? '?' : '&'; url += url.indexOf('?') === -1 ? '?' : '&';
@ -30,28 +99,28 @@ define(['appSettings', 'pluginManager'], function (appSettings, pluginManager) {
xhr.open('GET', url, true); xhr.open('GET', url, true);
var onError = function () { var onError = () => {
if (throwError === true) { if (throwError === true) {
reject(); reject();
} else { } else {
removeUrl(originalUrl); this.removeUrl(originalUrl);
resolve(); resolve();
} }
}; };
xhr.onload = function (e) { xhr.onload = () => {
if (this.status < 400) { if (this.status < 400) {
var pkg = JSON.parse(this.response); var pkg = JSON.parse(this.response);
pkg.url = originalUrl; pkg.url = originalUrl;
addPackage(packageManager, pkg); this.addPackage(pkg);
var plugins = pkg.plugins || []; var plugins = pkg.plugins || [];
if (pkg.plugin) { if (pkg.plugin) {
plugins.push(pkg.plugin); plugins.push(pkg.plugin);
} }
var promises = plugins.map(function (pluginUrl) { var promises = plugins.map((pluginUrl) => {
return pluginManager.loadPlugin(packageManager.mapPath(pkg, pluginUrl)); return pluginManager.loadPlugin(this.mapPath(pkg, pluginUrl));
}); });
Promise.all(promises).then(resolve, resolve); Promise.all(promises).then(resolve, resolve);
} else { } else {
@ -64,71 +133,8 @@ define(['appSettings', 'pluginManager'], function (appSettings, pluginManager) {
xhr.send(); xhr.send();
}); });
} }
function PackageManager() {
this.packagesList = [];
} }
PackageManager.prototype.init = function () { /* eslint-enable indent */
var manifestUrls = JSON.parse(appSettings.get(settingsKey) || '[]');
var instance = this; export default new PackageManager();
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));
}
return pkg;
});
};
PackageManager.prototype.uninstall = function (name) {
var pkg = this.packagesList.filter(function (p) {
return p.name === name;
})[0];
if (pkg) {
this.packagesList = this.packagesList.filter(function (p) {
return p.name !== name;
});
removeUrl(pkg.url);
}
return Promise.resolve();
};
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;
}
var packageUrl = pkg.url;
packageUrl = packageUrl.substring(0, packageUrl.lastIndexOf('/'));
packageUrl += '/';
packageUrl += pluginUrl;
return packageUrl;
};
return 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; let brightnessOsdLoaded;
self.setBrightness = function (val, player) { self.setBrightness = function (val, player) {
player = player || self._currentPlayer; player = player || self._currentPlayer;
@ -1416,8 +1462,8 @@ class PlaybackManager {
self.toggleFullscreen = function (player) { self.toggleFullscreen = function (player) {
player = player || self._currentPlayer; player = player || self._currentPlayer;
if (!player.isLocalPlayer || player.toggleFulscreen) { if (!player.isLocalPlayer || player.toggleFullscreen) {
return player.toggleFulscreen(); return player.toggleFullscreen();
} }
if (screenfull.isEnabled) { if (screenfull.isEnabled) {
@ -3697,6 +3743,9 @@ class PlaybackManager {
case 'SetAspectRatio': case 'SetAspectRatio':
this.setAspectRatio(cmd.Arguments.AspectRatio, player); this.setAspectRatio(cmd.Arguments.AspectRatio, player);
break; break;
case 'PlaybackRate':
this.setPlaybackRate(cmd.Arguments.PlaybackRate, player);
break;
case 'SetBrightness': case 'SetBrightness':
this.setBrightness(cmd.Arguments.Brightness, player); this.setBrightness(cmd.Arguments.Brightness, player);
break; 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) { function showWithUser(options, player, user) {
var supportedCommands = playbackManager.getSupportedCommands(player); 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) { if (user && user.Policy.EnableVideoPlaybackTranscoding) {
var secondaryQualityText = getQualitySecondaryText(player); var secondaryQualityText = getQualitySecondaryText(player);
@ -230,6 +263,8 @@ function handleSelectedOption(id, options, player) {
return showQualityMenu(player, options.positionTo); return showQualityMenu(player, options.positionTo);
case 'aspectratio': case 'aspectratio':
return showAspectRatioMenu(player, options.positionTo); return showAspectRatioMenu(player, options.positionTo);
case 'playbackrate':
return showPlaybackRateMenu(player, options.positionTo);
case 'repeatmode': case 'repeatmode':
return showRepeatModeMenu(player, options.positionTo); return showRepeatModeMenu(player, options.positionTo);
case 'stats': case 'stats':

View file

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

View file

@ -1,23 +1,28 @@
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) { import dialogHelper from 'dialogHelper';
'use strict'; 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; let currentDialog;
loading = loading.default || loading; let recordingDeleted = false;
layoutManager = layoutManager.default || layoutManager; let currentItemId;
let currentServerId;
var currentDialog; let currentResolve;
var recordingDeleted = false;
var currentItemId;
var currentServerId;
var currentResolve;
function deleteTimer(apiClient, timerId) { function deleteTimer(apiClient, timerId) {
return new Promise(function (resolve, reject) { return import('recordingHelper').then(({ default: recordingHelper }) => {
require(['recordingHelper'], function (recordingHelper) { recordingHelper.cancelTimerWithConfirmation(timerId, apiClient.serverId());
recordingHelper = recordingHelper.default || recordingHelper;
recordingHelper.cancelTimerWithConfirmation(timerId, apiClient.serverId()).then(resolve, reject);
});
}); });
} }
@ -30,14 +35,13 @@ define(['dialogHelper', 'globalize', 'layoutManager', 'mediaInfo', 'apphost', 'c
function closeDialog(isDeleted) { function closeDialog(isDeleted) {
recordingDeleted = isDeleted; recordingDeleted = isDeleted;
dialogHelper.close(currentDialog); dialogHelper.close(currentDialog);
} }
function onSubmit(e) { function onSubmit(e) {
var form = this; const form = this;
var apiClient = connectionManager.getApiClient(currentServerId); const apiClient = connectionManager.getApiClient(currentServerId);
apiClient.getLiveTvTimer(currentItemId).then(function (item) { apiClient.getLiveTvTimer(currentItemId).then(function (item) {
item.PrePaddingSeconds = form.querySelector('#txtPrePaddingMinutes').value * 60; item.PrePaddingSeconds = form.querySelector('#txtPrePaddingMinutes').value * 60;
@ -57,7 +61,8 @@ define(['dialogHelper', 'globalize', 'layoutManager', 'mediaInfo', 'apphost', 'c
}); });
context.querySelector('.btnCancelRecording').addEventListener('click', function () { context.querySelector('.btnCancelRecording').addEventListener('click', function () {
var apiClient = connectionManager.getApiClient(currentServerId); const apiClient = connectionManager.getApiClient(currentServerId);
deleteTimer(apiClient, currentItemId).then(function () { deleteTimer(apiClient, currentItemId).then(function () {
closeDialog(true); closeDialog(true);
}); });
@ -70,7 +75,7 @@ define(['dialogHelper', 'globalize', 'layoutManager', 'mediaInfo', 'apphost', 'c
loading.show(); loading.show();
currentItemId = id; currentItemId = id;
var apiClient = connectionManager.getApiClient(currentServerId); const apiClient = connectionManager.getApiClient(currentServerId);
apiClient.getLiveTvTimer(id).then(function (result) { apiClient.getLiveTvTimer(id).then(function (result) {
renderTimer(context, result, apiClient); renderTimer(context, result, apiClient);
loading.hide(); loading.hide();
@ -85,8 +90,8 @@ define(['dialogHelper', 'globalize', 'layoutManager', 'mediaInfo', 'apphost', 'c
options = options || {}; options = options || {};
currentResolve = resolve; currentResolve = resolve;
require(['text!./recordingeditor.template.html'], function (template) { import('text!./recordingeditor.template.html').then(({default: template}) => {
var dialogOptions = { const dialogOptions = {
removeOnClose: true, removeOnClose: true,
scrollY: false scrollY: false
}; };
@ -95,7 +100,7 @@ define(['dialogHelper', 'globalize', 'layoutManager', 'mediaInfo', 'apphost', 'c
dialogOptions.size = 'fullscreen'; dialogOptions.size = 'fullscreen';
} }
var dlg = dialogHelper.createDialog(dialogOptions); const dlg = dialogHelper.createDialog(dialogOptions);
dlg.classList.add('formDialog'); dlg.classList.add('formDialog');
dlg.classList.add('recordingDialog'); dlg.classList.add('recordingDialog');
@ -105,7 +110,7 @@ define(['dialogHelper', 'globalize', 'layoutManager', 'mediaInfo', 'apphost', 'c
dlg.classList.add('dialog-fullscreen-lowres'); dlg.classList.add('dialog-fullscreen-lowres');
} }
var html = ''; let html = '';
html += globalize.translateHtml(template, 'core'); html += globalize.translateHtml(template, 'core');
@ -145,7 +150,6 @@ define(['dialogHelper', 'globalize', 'layoutManager', 'mediaInfo', 'apphost', 'c
}); });
} }
return { export default {
show: showEditor show: showEditor
}; };
});

View file

@ -1,9 +1,16 @@
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) { import globalize from 'globalize';
'use strict'; 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; /*eslint prefer-const: "error"*/
recordingHelper = recordingHelper.default || recordingHelper;
loading = loading.default || loading;
function loadData(parent, program, apiClient) { function loadData(parent, program, apiClient) {
if (program.IsSeries) { if (program.IsSeries) {
@ -38,8 +45,8 @@ define(['globalize', 'connectionManager', 'serverNotifications', 'require', 'loa
} }
function fetchData(instance) { function fetchData(instance) {
var options = instance.options; const options = instance.options;
var apiClient = connectionManager.getApiClient(options.serverId); const apiClient = connectionManager.getApiClient(options.serverId);
options.parent.querySelector('.recordingFields').classList.remove('hide'); options.parent.querySelector('.recordingFields').classList.remove('hide');
return apiClient.getLiveTvProgram(options.programId, apiClient.getCurrentUserId()).then(function (program) { return apiClient.getLiveTvProgram(options.programId, apiClient.getCurrentUserId()).then(function (program) {
@ -51,8 +58,8 @@ define(['globalize', 'connectionManager', 'serverNotifications', 'require', 'loa
} }
function onTimerChangedExternally(e, apiClient, data) { function onTimerChangedExternally(e, apiClient, data) {
var options = this.options; const options = this.options;
var refresh = false; let refresh = false;
if (data.Id) { if (data.Id) {
if (this.TimerId === data.Id) { if (this.TimerId === data.Id) {
@ -71,8 +78,8 @@ define(['globalize', 'connectionManager', 'serverNotifications', 'require', 'loa
} }
function onSeriesTimerChangedExternally(e, apiClient, data) { function onSeriesTimerChangedExternally(e, apiClient, data) {
var options = this.options; const options = this.options;
var refresh = false; let refresh = false;
if (data.Id) { if (data.Id) {
if (this.SeriesTimerId === data.Id) { if (this.SeriesTimerId === data.Id) {
@ -90,31 +97,73 @@ define(['globalize', 'connectionManager', 'serverNotifications', 'require', 'loa
} }
} }
function RecordingEditor(options) { class RecordingEditor {
constructor(options) {
this.options = options; this.options = options;
this.embed(); this.embed();
var timerChangedHandler = onTimerChangedExternally.bind(this); const timerChangedHandler = onTimerChangedExternally.bind(this);
this.timerChangedHandler = timerChangedHandler; this.timerChangedHandler = timerChangedHandler;
events.on(serverNotifications, 'TimerCreated', timerChangedHandler); events.on(serverNotifications, 'TimerCreated', timerChangedHandler);
events.on(serverNotifications, 'TimerCancelled', timerChangedHandler); events.on(serverNotifications, 'TimerCancelled', timerChangedHandler);
var seriesTimerChangedHandler = onSeriesTimerChangedExternally.bind(this); const seriesTimerChangedHandler = onSeriesTimerChangedExternally.bind(this);
this.seriesTimerChangedHandler = seriesTimerChangedHandler; this.seriesTimerChangedHandler = seriesTimerChangedHandler;
events.on(serverNotifications, 'SeriesTimerCreated', seriesTimerChangedHandler); events.on(serverNotifications, 'SeriesTimerCreated', seriesTimerChangedHandler);
events.on(serverNotifications, 'SeriesTimerCancelled', seriesTimerChangedHandler); events.on(serverNotifications, 'SeriesTimerCancelled', seriesTimerChangedHandler);
} }
embed() {
const self = this;
return new Promise(function (resolve, reject) {
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));
context.querySelector('.seriesRecordingButton').addEventListener('click', onRecordSeriesChange.bind(self));
context.querySelector('.btnManageRecording').addEventListener('click', onManageRecordingClick.bind(self));
context.querySelector('.btnManageSeriesRecording').addEventListener('click', onManageSeriesRecordingClick.bind(self));
fetchData(self).then(resolve);
});
});
}
hasChanged() {
return this.changed;
}
refresh() {
fetchData(this);
}
destroy() {
const timerChangedHandler = this.timerChangedHandler;
this.timerChangedHandler = null;
events.off(serverNotifications, 'TimerCreated', timerChangedHandler);
events.off(serverNotifications, 'TimerCancelled', timerChangedHandler);
const seriesTimerChangedHandler = this.seriesTimerChangedHandler;
this.seriesTimerChangedHandler = null;
events.off(serverNotifications, 'SeriesTimerCreated', seriesTimerChangedHandler);
events.off(serverNotifications, 'SeriesTimerCancelled', seriesTimerChangedHandler);
}
}
function onManageRecordingClick(e) { function onManageRecordingClick(e) {
var options = this.options; const options = this.options;
if (!this.TimerId || this.Status === 'Cancelled') { if (!this.TimerId || this.Status === 'Cancelled') {
return; return;
} }
var self = this; const self = this;
require(['recordingEditor'], function (recordingEditor) { import('recordingEditor').then(({default: recordingEditor}) => {
recordingEditor.show(self.TimerId, options.serverId, { recordingEditor.show(self.TimerId, options.serverId, {
enableCancel: false enableCancel: false
}).then(function () { }).then(function () {
@ -124,15 +173,15 @@ define(['globalize', 'connectionManager', 'serverNotifications', 'require', 'loa
} }
function onManageSeriesRecordingClick(e) { function onManageSeriesRecordingClick(e) {
var options = this.options; const options = this.options;
if (!this.SeriesTimerId) { if (!this.SeriesTimerId) {
return; return;
} }
var self = this; const self = this;
require(['seriesRecordingEditor'], function (seriesRecordingEditor) { import('seriesRecordingEditor').then(({default: seriesRecordingEditor}) => {
seriesRecordingEditor.show(self.SeriesTimerId, options.serverId, { seriesRecordingEditor.show(self.SeriesTimerId, options.serverId, {
enableCancel: false enableCancel: false
@ -146,14 +195,14 @@ define(['globalize', 'connectionManager', 'serverNotifications', 'require', 'loa
function onRecordChange(e) { function onRecordChange(e) {
this.changed = true; this.changed = true;
var self = this; const self = this;
var options = this.options; const options = this.options;
var apiClient = connectionManager.getApiClient(options.serverId); const apiClient = connectionManager.getApiClient(options.serverId);
var button = dom.parentWithTag(e.target, 'BUTTON'); const button = dom.parentWithTag(e.target, 'BUTTON');
var isChecked = !button.querySelector('.material-icons').classList.contains('recordingIcon-active'); const isChecked = !button.querySelector('.material-icons').classList.contains('recordingIcon-active');
var hasEnabledTimer = this.TimerId && this.Status !== 'Cancelled'; const hasEnabledTimer = this.TimerId && this.Status !== 'Cancelled';
if (isChecked) { if (isChecked) {
if (!hasEnabledTimer) { if (!hasEnabledTimer) {
@ -177,7 +226,7 @@ define(['globalize', 'connectionManager', 'serverNotifications', 'require', 'loa
} }
function sendToast(msg) { function sendToast(msg) {
require(['toast'], function (toast) { import('toast').then(({default: toast}) => {
toast(msg); toast(msg);
}); });
} }
@ -185,17 +234,17 @@ define(['globalize', 'connectionManager', 'serverNotifications', 'require', 'loa
function onRecordSeriesChange(e) { function onRecordSeriesChange(e) {
this.changed = true; this.changed = true;
var self = this; const self = this;
var options = this.options; const options = this.options;
var apiClient = connectionManager.getApiClient(options.serverId); const apiClient = connectionManager.getApiClient(options.serverId);
var button = dom.parentWithTag(e.target, 'BUTTON'); const button = dom.parentWithTag(e.target, 'BUTTON');
var isChecked = !button.querySelector('.material-icons').classList.contains('recordingIcon-active'); const isChecked = !button.querySelector('.material-icons').classList.contains('recordingIcon-active');
if (isChecked) { if (isChecked) {
options.parent.querySelector('.recordSeriesContainer').classList.remove('hide'); options.parent.querySelector('.recordSeriesContainer').classList.remove('hide');
if (!this.SeriesTimerId) { if (!this.SeriesTimerId) {
var promise = this.TimerId ? const promise = this.TimerId ?
recordingHelper.changeRecordingToSeries(apiClient, this.TimerId, options.programId) : recordingHelper.changeRecordingToSeries(apiClient, this.TimerId, options.programId) :
recordingHelper.createRecording(apiClient, options.programId, true); recordingHelper.createRecording(apiClient, options.programId, true);
promise.then(function () { promise.then(function () {
@ -212,45 +261,4 @@ define(['globalize', 'connectionManager', 'serverNotifications', 'require', 'loa
} }
} }
RecordingEditor.prototype.embed = function () { export default RecordingEditor;
var self = this;
return new Promise(function (resolve, reject) {
require(['text!./recordingfields.template.html'], function (template) {
var options = self.options;
var context = options.parent;
context.innerHTML = globalize.translateHtml(template, 'core');
context.querySelector('.singleRecordingButton').addEventListener('click', onRecordChange.bind(self));
context.querySelector('.seriesRecordingButton').addEventListener('click', onRecordSeriesChange.bind(self));
context.querySelector('.btnManageRecording').addEventListener('click', onManageRecordingClick.bind(self));
context.querySelector('.btnManageSeriesRecording').addEventListener('click', onManageSeriesRecordingClick.bind(self));
fetchData(self).then(resolve);
});
});
};
RecordingEditor.prototype.hasChanged = function () {
return this.changed;
};
RecordingEditor.prototype.refresh = function () {
fetchData(this);
};
RecordingEditor.prototype.destroy = function () {
var timerChangedHandler = this.timerChangedHandler;
this.timerChangedHandler = null;
events.off(serverNotifications, 'TimerCreated', timerChangedHandler);
events.off(serverNotifications, 'TimerCancelled', timerChangedHandler);
var seriesTimerChangedHandler = this.seriesTimerChangedHandler;
this.seriesTimerChangedHandler = null;
events.off(serverNotifications, 'SeriesTimerCreated', seriesTimerChangedHandler);
events.off(serverNotifications, 'SeriesTimerCancelled', seriesTimerChangedHandler);
};
return RecordingEditor;
});

View file

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

View file

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

View file

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

View file

@ -9,7 +9,7 @@
</div> </div>
<div class="inputContainer"> <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 class="fieldDescription">${LabelCustomDeviceDisplayNameHelp}</div>
</div> </div>
</div> </div>

View file

@ -3,7 +3,7 @@
<div class="content-primary"> <div class="content-primary">
<div class="verticalSection verticalSection"> <div class="verticalSection verticalSection">
<div class="sectionTitleContainer sectionTitleContainer-cards flex align-items-center"> <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> <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>
</div> </div>

View file

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

View file

@ -8,7 +8,7 @@
</div> </div>
</div> </div>
<div data-role="controlgroup" data-type="horizontal" data-mini="true"> <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="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="radioTranscoding" data-value="tabTranscodingProfiles">${Transcoding}</a>
<a href="#" is="emby-linkbutton" data-role="button" class="radioTabButton" id="radioContainers" data-value="tabContainerProfiles">${TabContainers}</a> <a href="#" is="emby-linkbutton" data-role="button" class="radioTabButton" id="radioContainers" data-value="tabContainerProfiles">${TabContainers}</a>
@ -231,31 +231,31 @@
</div> </div>
<div class="tabContent tabDirectPlayProfiles"> <div class="tabContent tabDirectPlayProfiles">
<p>${HeaderDirectPlayProfileHelp}</p> <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 /> <br />
<div class="directPlayProfiles"></div> <div class="directPlayProfiles"></div>
</div> </div>
<div class="tabContent tabTranscodingProfiles"> <div class="tabContent tabTranscodingProfiles">
<p>${HeaderTranscodingProfileHelp}</p> <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 /> <br />
<div class="transcodingProfiles"></div> <div class="transcodingProfiles"></div>
</div> </div>
<div class="tabContent tabContainerProfiles"> <div class="tabContent tabContainerProfiles">
<p>${HeaderContainerProfileHelp}</p> <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 /> <br />
<div class="containerProfiles"></div> <div class="containerProfiles"></div>
</div> </div>
<div class="tabContent tabCodecProfiles"> <div class="tabContent tabCodecProfiles">
<p>${HeaderCodecProfileHelp}</p> <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 /> <br />
<div class="codecProfiles"></div> <div class="codecProfiles"></div>
</div> </div>
<div class="tabContent tabMediaProfiles"> <div class="tabContent tabMediaProfiles">
<p>${HeaderResponseProfileHelp}</p> <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 /> <br />
<div class="mediaProfiles"></div> <div class="mediaProfiles"></div>
</div> </div>
@ -319,7 +319,7 @@
<div data-role="content"> <div data-role="content">
<div data-role="controlgroup" data-type="horizontal" data-mini="true"> <div data-role="controlgroup" data-type="horizontal" data-mini="true">
<input type="radio" name="radioTranscodingTab" class="radioTabButton" id="radioTranscodingBasics" value="tabTranscodingBasics"> <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"> <input type="radio" name="radioTranscodingTab" class="radioTabButton" id="radioTranscodingAdvanced" value="tabTranscodingAdvanced">
<label for="radioTranscodingAdvanced">${TabAdvanced}</label> <label for="radioTranscodingAdvanced">${TabAdvanced}</label>
</div> </div>
@ -341,16 +341,16 @@
</div> </div>
</div> </div>
<div class="inputContainer"> <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>
<div id="fldTranscodingVideoCodec" style="margin: 1em 0;"> <div id="fldTranscodingVideoCodec" style="margin: 1em 0;">
<div class="inputContainer"> <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> </div>
<div id="fldTranscodingAudioCodec" style="margin: 1em 0;"> <div id="fldTranscodingAudioCodec" style="margin: 1em 0;">
<div class="inputContainer"> <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> </div>
</div> </div>

View file

@ -46,7 +46,7 @@ import 'emby-button';
html += '</div>'; html += '</div>';
if (profile.Type == 'User') { 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>'; html += '</div>';

View file

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

View file

@ -17,9 +17,9 @@
<div class="selectContainer"> <div class="selectContainer">
<select is="emby-select" id="selectLocalizationLanguage" label="${LabelPreferredDisplayLanguage}"></select> <select is="emby-select" id="selectLocalizationLanguage" label="${LabelPreferredDisplayLanguage}"></select>
<div class="fieldDescription"> <div class="fieldDescription">
<div>${LabelPreferredDisplayLanguageHelp}</div> <div>${LabelDisplayLanguageHelp}</div>
<div style="margin-top: .25em;"> <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> </div>
</div> </div>

View file

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

View file

@ -3,7 +3,7 @@
<div class="content-primary"> <div class="content-primary">
<form class="playbackConfigurationForm"> <form class="playbackConfigurationForm">
<div class="sectionTitleContainer flex align-items-center"> <div class="sectionTitleContainer flex align-items-center">
<h2 class="sectionTitle">${TabResumeSettings}</h2> <h2 class="sectionTitle">${ButtonResume}</h2>
</div> </div>
<div class="inputContainer"> <div class="inputContainer">
<input is="emby-input" type="number" id="txtMinResumePct" name="txtMinResumePct" pattern="[0-9]*" required min="0" max="100" label="${LabelMinResumePercentage}"></input> <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') name: globalize.translate('Transcoding')
}, { }, {
href: 'playbackconfiguration.html', href: 'playbackconfiguration.html',
name: globalize.translate('TabResumeSettings') name: globalize.translate('ButtonResume')
}, { }, {
href: 'streamingsettings.html', href: 'streamingsettings.html',
name: globalize.translate('TabStreaming') name: globalize.translate('TabStreaming')

View file

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

View file

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

View file

@ -75,7 +75,7 @@ import 'emby-select';
} }
html += '</div>'; 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>'; html += '</div>';
} }

View file

@ -27,7 +27,7 @@ import globalize from 'globalize';
name: globalize.translate('Transcoding') name: globalize.translate('Transcoding')
}, { }, {
href: 'playbackconfiguration.html', href: 'playbackconfiguration.html',
name: globalize.translate('TabResumeSettings') name: globalize.translate('ButtonResume')
}, { }, {
href: 'streamingsettings.html', href: 'streamingsettings.html',
name: globalize.translate('TabStreaming') 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" 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('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('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> </div>
<p class="lnkEditUserPreferencesContainer"> <p class="lnkEditUserPreferencesContainer">
<a class="lnkEditUserPreferences button-link" href="#" is="emby-linkbutton">${ButtonEditOtherUserPreferences}</a> <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('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('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('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> </div>
<form class="userLibraryAccessForm"> <form class="userLibraryAccessForm">

View file

@ -32,7 +32,7 @@ import globalize from 'globalize';
function loadChannels(page, user, channels) { function loadChannels(page, user, channels) {
let html = ''; 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">'; html += '<div class="checkboxList paperList checkboxList-paperList">';
for (let i = 0, length = channels.length; i < length; i++) { for (let i = 0, length = channels.length; i < length; i++) {

View file

@ -4,7 +4,7 @@
<form class="newUserProfileForm"> <form class="newUserProfileForm">
<div class="verticalSection"> <div class="verticalSection">
<div class="sectionTitleContainer flex align-items-center"> <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> <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> </div>

View file

@ -22,7 +22,7 @@ import 'emby-checkbox';
function loadChannels(page, channels) { function loadChannels(page, channels) {
let html = ''; 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;">'; html += '<div class="checkboxList paperList" style="padding:.5em 1em;">';
for (let i = 0; i < channels.length; i++) { 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('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('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('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> </div>
<form class="userParentalControlForm"> <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('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('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('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>
<div class="readOnlyContent"> <div class="readOnlyContent">

View file

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

View file

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

View file

@ -18,13 +18,13 @@
</div> </div>
</button> </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"> <div class="detailButton-content">
<span class="material-icons detailButton-icon play_arrow"></span> <span class="material-icons detailButton-icon play_arrow"></span>
</div> </div>
</button> </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"> <div class="detailButton-content">
<span class="material-icons detailButton-icon get_app"></span> <span class="material-icons detailButton-icon get_app"></span>
</div> </div>
@ -42,7 +42,7 @@
</div> </div>
</button> </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"> <div class="detailButton-content">
<span class="material-icons detailButton-icon shuffle"></span> <span class="material-icons detailButton-icon shuffle"></span>
</div> </div>
@ -147,14 +147,14 @@
</div> </div>
<div class="seriesTimerScheduleSection verticalSection detailVerticalSection hide" style="margin-top:-3em;"> <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 class="seriesTimerSchedule padded-right"></div>
</div> </div>
<div class="collectionItems hide"></div> <div class="collectionItems hide"></div>
<div class="nextUpSection verticalSection detailVerticalSection hide"> <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 is="emby-itemscontainer" class="nextUpItems vertical-wrap padded-right"></div>
</div> </div>
@ -193,7 +193,7 @@
</div> </div>
<div id="castCollapsible" class="verticalSection detailVerticalSection hide"> <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 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 id="castContent" is="emby-itemscontainer" class="scrollSlider focuscontainer-x itemsContainer"></div>
</div> </div>

View file

@ -242,7 +242,7 @@ import 'emby-select';
return m.Type === 'Audio'; return m.Type === 'Audio';
}); });
const select = page.querySelector('.selectAudio'); const select = page.querySelector('.selectAudio');
select.setLabel(globalize.translate('LabelAudio')); select.setLabel(globalize.translate('Audio'));
const selectedId = mediaSource.DefaultAudioStreamIndex; const selectedId = mediaSource.DefaultAudioStreamIndex;
select.innerHTML = tracks.map(function (v) { select.innerHTML = tracks.map(function (v) {
const selected = v.Index === selectedId ? ' selected' : ''; const selected = v.Index === selectedId ? ' selected' : '';
@ -271,7 +271,7 @@ import 'emby-select';
return m.Type === 'Subtitle'; return m.Type === 'Subtitle';
}); });
const select = page.querySelector('.selectSubtitles'); const select = page.querySelector('.selectSubtitles');
select.setLabel(globalize.translate('LabelSubtitles')); select.setLabel(globalize.translate('Subtitles'));
const selectedId = mediaSource.DefaultSubtitleStreamIndex == null ? -1 : mediaSource.DefaultSubtitleStreamIndex; const selectedId = mediaSource.DefaultSubtitleStreamIndex == null ? -1 : mediaSource.DefaultSubtitleStreamIndex;
const videoTracks = mediaSource.MediaStreams.filter(function (m) { const videoTracks = mediaSource.MediaStreams.filter(function (m) {
@ -785,7 +785,7 @@ import 'emby-select';
function setPeopleHeader(page, item) { function setPeopleHeader(page, item) {
if (item.MediaType == 'Audio' || item.Type == 'MusicAlbum' || item.MediaType == 'Book' || item.MediaType == 'Photo') { 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 { } else {
page.querySelector('#peopleHeader').innerHTML = globalize.translate('HeaderCastAndCrew'); page.querySelector('#peopleHeader').innerHTML = globalize.translate('HeaderCastAndCrew');
} }
@ -1432,13 +1432,13 @@ import 'emby-select';
name: globalize.translate('HeaderVideos'), name: globalize.translate('HeaderVideos'),
mediaType: 'Video' mediaType: 'Video'
}, { }, {
name: globalize.translate('HeaderSeries'), name: globalize.translate('Series'),
type: 'Series' type: 'Series'
}, { }, {
name: globalize.translate('HeaderAlbums'), name: globalize.translate('Albums'),
type: 'MusicAlbum' type: 'MusicAlbum'
}, { }, {
name: globalize.translate('HeaderBooks'), name: globalize.translate('Books'),
type: 'Book' type: 'Book'
}]; }];
renderCollectionItems(page, item, collectionItemTypes, result.Items); renderCollectionItems(page, item, collectionItemTypes, result.Items);
@ -1446,13 +1446,13 @@ import 'emby-select';
}); });
if (item.Type == 'Season') { if (item.Type == 'Season') {
page.querySelector('#childrenTitle').innerHTML = globalize.translate('HeaderEpisodes'); page.querySelector('#childrenTitle').innerHTML = globalize.translate('Episodes');
} else if (item.Type == 'Series') { } else if (item.Type == 'Series') {
page.querySelector('#childrenTitle').innerHTML = globalize.translate('HeaderSeasons'); page.querySelector('#childrenTitle').innerHTML = globalize.translate('HeaderSeasons');
} else if (item.Type == 'MusicAlbum') { } else if (item.Type == 'MusicAlbum') {
page.querySelector('#childrenTitle').innerHTML = globalize.translate('HeaderTracks'); page.querySelector('#childrenTitle').innerHTML = globalize.translate('HeaderTracks');
} else { } else {
page.querySelector('#childrenTitle').innerHTML = globalize.translate('HeaderItems'); page.querySelector('#childrenTitle').innerHTML = globalize.translate('Items');
} }
if (item.Type == 'MusicAlbum' || item.Type == 'Season') { if (item.Type == 'MusicAlbum' || item.Type == 'Season') {
@ -1652,7 +1652,7 @@ import 'emby-select';
if (!items.length) { if (!items.length) {
renderCollectionItemType(page, parentItem, { renderCollectionItemType(page, parentItem, {
name: globalize.translate('HeaderItems') name: globalize.translate('Items')
}, 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"> <div class="liveTvContainer">
@ -15,7 +15,7 @@
<div id="upcomingEpisodes" class="verticalSection"> <div id="upcomingEpisodes" class="verticalSection">
<div class="sectionTitleContainer sectionTitleContainer-cards padded-left"> <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"> <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> <span class="material-icons chevron_right"></span>
</a> </a>
</div> </div>
@ -24,7 +24,7 @@
<div id="upcomingTvMovies" class="verticalSection"> <div id="upcomingTvMovies" class="verticalSection">
<div class="sectionTitleContainer sectionTitleContainer-cards padded-left"> <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"> <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> <span class="material-icons chevron_right"></span>
</a> </a>
</div> </div>
@ -63,7 +63,7 @@
<div class="pageTabContent" id="channelsTab" data-index="2"> <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="flex align-items-center justify-content-center flex-wrap-wrap padded-top padded-left padded-right padded-bottom">
<div class="paging"></div> <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>
<div is="emby-itemscontainer" id="items" class="itemsContainer vertical-wrap padded-left padded-right"></div> <div is="emby-itemscontainer" id="items" class="itemsContainer vertical-wrap padded-left padded-right"></div>
</div> </div>

View file

@ -168,15 +168,15 @@ function getTabs() {
return [{ return [{
name: globalize.translate('Programs') 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"> <form class="liveTvSettingsForm">
<div class="selectContainer"> <div class="selectContainer">
<select is="emby-select" id="selectGuideDays" label="${LabelNumberOfGuideDays}"> <select is="emby-select" id="selectGuideDays" label="${LabelNumberOfGuideDays}">
<option value="">${OptionAutomatic}</option> <option value="">${OptionAuto}</option>
<option value="1">1</option> <option value="1">1</option>
<option value="2">2</option> <option value="2">2</option>
<option value="3">3</option> <option value="3">3</option>

View file

@ -137,7 +137,7 @@ function renderProviders(page, providers) {
function showProviderOptions(page, providerId, button) { function showProviderOptions(page, providerId, button) {
const items = []; const items = [];
items.push({ items.push({
name: globalize.translate('ButtonDelete'), name: globalize.translate('Delete'),
id: 'delete' id: 'delete'
}); });
items.push({ items.push({
@ -255,11 +255,11 @@ function addDevice(button) {
function showDeviceMenu(button, tunerDeviceId) { function showDeviceMenu(button, tunerDeviceId) {
const items = []; const items = [];
items.push({ items.push({
name: globalize.translate('ButtonDelete'), name: globalize.translate('Delete'),
id: 'delete' id: 'delete'
}); });
items.push({ items.push({
name: globalize.translate('ButtonEdit'), name: globalize.translate('Edit'),
id: '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="flex align-items-center justify-content-center flex-wrap-wrap padded-top padded-left padded-right padded-bottom">
<div class="paging"></div> <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="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 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>
<div class="alphaPicker alphaPicker-fixed alphaPicker-vertical"> <div class="alphaPicker alphaPicker-fixed alphaPicker-vertical">
@ -46,8 +46,8 @@
<div class="pageTabContent" data-index="2"> <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="flex align-items-center justify-content-center flex-wrap-wrap padded-top padded-left padded-right padded-bottom">
<div class="paging"></div> <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="btnSort autoSize" title="${Sort}"><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="btnFilter autoSize" title="${Filter}"><span class="material-icons filter_list"></span></button>
</div> </div>
<div class="alphaPicker alphaPicker-fixed alphaPicker-fixed-right alphaPicker-vertical"> <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="flex align-items-center justify-content-center flex-wrap-wrap padded-top padded-left padded-right padded-bottom">
<div class="paging"></div> <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="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> <button type="button" is="paper-icon-button-light" class="btnNewCollection autoSize"><span class="material-icons add"></span></button>
</div> </div>

View file

@ -229,13 +229,13 @@ import 'emby-button';
}, { }, {
name: globalize.translate('Suggestions') 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); libraryMenu.setTitle(item.Name);
}); });
} else { } else {
view.setAttribute('data-title', globalize.translate('TabMovies')); view.setAttribute('data-title', globalize.translate('Movies'));
libraryMenu.setTitle(globalize.translate('TabMovies')); 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="flex align-items-center justify-content-center flex-wrap-wrap padded-top padded-left padded-right padded-bottom">
<div class="paging"></div> <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="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="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 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>
<div class="alphaPicker alphaPicker-fixed alphaPicker-vertical"> <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="flex align-items-center justify-content-center flex-wrap-wrap padded-top padded-left padded-right padded-bottom">
<div class="paging"></div> <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="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>
<div class="alphaPicker alphaPicker-fixed alphaPicker-vertical"> <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="flex align-items-center justify-content-center flex-wrap-wrap padded-top padded-left padded-right padded-bottom">
<div class="paging"></div> <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="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>
<div class="alphaPicker alphaPicker-fixed alphaPicker-vertical"> <div class="alphaPicker alphaPicker-fixed alphaPicker-vertical">
@ -92,8 +92,8 @@
<div class="pageTabContent" id="songsTab" data-index="5"> <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="flex align-items-center justify-content-center flex-wrap-wrap padded-top padded-left padded-right padded-bottom">
<div class="paging"></div> <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="btnSort autoSize" title="${Sort}"><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="btnFilter autoSize" title="${Filter}"><span class="material-icons filter_list"></span></button>
</div> </div>
<div is="emby-itemscontainer" id="items" class="itemsContainer vertical-list" style="max-width:67.5em;margin: 0 auto;"></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 [{ return [{
name: globalize.translate('Suggestions') 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('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> <span class="material-icons forward_30"></span>
</button> </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> <span class="material-icons shuffle"></span>
</button> </button>
@ -71,7 +71,7 @@
<span class="material-icons audiotrack"></span> <span class="material-icons audiotrack"></span>
</button> </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> <span class="material-icons closed_caption"></span>
</button> </button>
@ -81,7 +81,7 @@
<span class="material-icons fullscreen"></span> <span class="material-icons fullscreen"></span>
</button> </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> <span class="material-icons shuffle"></span>
</button> </button>
@ -99,7 +99,7 @@
<div is="emby-collapse" title="${HeaderNavigation}"> <div is="emby-collapse" title="${HeaderNavigation}">
<div class="collapseContent"> <div class="collapseContent">
<div> <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> <span class="material-icons keyboard_arrow_up"></span>
</button> </button>
</div> </div>
@ -120,7 +120,7 @@
<button is="paper-icon-button-light" class="btnBack btnCommand autoSize" title="${ButtonBack}" data-command="Back"> <button is="paper-icon-button-light" class="btnBack btnCommand autoSize" title="${ButtonBack}" data-command="Back">
<span class="material-icons arrow_back"></span> <span class="material-icons arrow_back"></span>
</button> </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> <span class="material-icons keyboard_arrow_down"></span>
</button> </button>
<button is="paper-icon-button-light" class="btnContextMenu btnCommand autoSize" title="${ButtonInfo}" data-command="ToggleContextMenu"> <button is="paper-icon-button-light" class="btnContextMenu btnCommand autoSize" title="${ButtonInfo}" data-command="ToggleContextMenu">
@ -129,7 +129,7 @@
</div> </div>
<br /> <br />
<div> <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> <span class="material-icons home"></span>
</button> </button>
<button is="paper-icon-button-light" class="btnShowSearch btnCommand autoSize" title="${Search}" data-command="GoToSearch"> <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) { if (isPaused) {
btnPlayPauseIcon.classList.add('play_arrow'); btnPlayPauseIcon.classList.add('play_arrow');
btnPlayPause.setAttribute('title', globalize.translate('ButtonPlay') + ' (k)'); btnPlayPause.setAttribute('title', globalize.translate('Play') + ' (k)');
} else { } else {
btnPlayPauseIcon.classList.add('pause'); btnPlayPauseIcon.classList.add('pause');
btnPlayPause.setAttribute('title', globalize.translate('ButtonPause') + ' (k)'); btnPlayPause.setAttribute('title', globalize.translate('ButtonPause') + ' (k)');
@ -1243,6 +1243,12 @@ import 'css!assets/css/videoosd';
} }
break; break;
} }
case '>':
playbackManager.increasePlaybackRate(currentPlayer);
break;
case '<':
playbackManager.decreasePlaybackRate(currentPlayer);
break;
} }
} }

View file

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

View file

@ -2,7 +2,7 @@
<div class="padded-left padded-right padded-bottom-page"> <div class="padded-left padded-right padded-bottom-page">
<form class="forgotPasswordForm" style="text-align: center; margin: 0 auto;"> <form class="forgotPasswordForm" style="text-align: center; margin: 0 auto;">
<div style="text-align: left;"> <div style="text-align: left;">
<h1>${HeaderForgotPassword}</h1> <h1>${ButtonForgotPassword}</h1>
<div class="inputContainer"> <div class="inputContainer">
<input is="emby-input" type="text" id="txtName" label="${LabelUser}" autocomplete="off"/> <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') { if (result.Action == 'ContactAdmin') {
return void Dashboard.alert({ return void Dashboard.alert({
message: globalize.translate('MessageContactAdminToResetPassword'), message: globalize.translate('MessageContactAdminToResetPassword'),
title: globalize.translate('HeaderForgotPassword') title: globalize.translate('ButtonForgotPassword')
}); });
} }
if (result.Action == 'InNetworkRequired') { if (result.Action == 'InNetworkRequired') {
return void Dashboard.alert({ return void Dashboard.alert({
message: globalize.translate('MessageForgotPasswordInNetworkRequired'), message: globalize.translate('MessageForgotPasswordInNetworkRequired'),
title: globalize.translate('HeaderForgotPassword') title: globalize.translate('ButtonForgotPassword')
}); });
} }
@ -27,7 +27,7 @@ import globalize from 'globalize';
msg += '<br/>'; msg += '<br/>';
return void Dashboard.alert({ return void Dashboard.alert({
message: msg, message: msg,
title: globalize.translate('HeaderForgotPassword'), title: globalize.translate('ButtonForgotPassword'),
callback: function () { callback: function () {
Dashboard.navigate('forgotpasswordpin.html'); Dashboard.navigate('forgotpasswordpin.html');
} }
@ -41,9 +41,9 @@ import globalize from 'globalize';
type: 'POST', type: 'POST',
url: ApiClient.getUrl('Users/ForgotPassword'), url: ApiClient.getUrl('Users/ForgotPassword'),
dataType: 'json', dataType: 'json',
data: { data: JSON.stringify({
EnteredUsername: view.querySelector('#txtName').value EnteredUsername: view.querySelector('#txtName').value
} })
}).then(processForgotPasswordResult); }).then(processForgotPasswordResult);
e.preventDefault(); e.preventDefault();
return false; return false;

View file

@ -29,9 +29,9 @@ import globalize from 'globalize';
type: 'POST', type: 'POST',
url: ApiClient.getUrl('Users/ForgotPassword/Pin'), url: ApiClient.getUrl('Users/ForgotPassword/Pin'),
dataType: 'json', dataType: 'json',
data: { data: JSON.stringify({
Pin: view.querySelector('#txtPin').value Pin: view.querySelector('#txtPin').value
} })
}).then(processForgotPasswordResult); }).then(processForgotPasswordResult);
e.preventDefault(); e.preventDefault();
return false; 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="flex align-items-center justify-content-center flex-wrap-wrap padded-top padded-left padded-right padded-bottom">
<div class="paging"></div> <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="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 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>
<div is="emby-itemscontainer" class="itemsContainer padded-left padded-right"></div> <div is="emby-itemscontainer" class="itemsContainer padded-left padded-right"></div>
@ -26,7 +26,7 @@
<div class="verticalSection"> <div class="verticalSection">
<div class="sectionTitleContainer sectionTitleContainer-cards"> <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>
<div is="emby-itemscontainer" id="nextUpItems" class="itemsContainer vertical-wrap padded-left padded-right"> <div is="emby-itemscontainer" id="nextUpItems" class="itemsContainer vertical-wrap padded-left padded-right">
</div> </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="flex align-items-center justify-content-center flex-wrap-wrap padded-top padded-left padded-right padded-bottom">
<div class="paging"></div> <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="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 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>
<div is="emby-itemscontainer" class="itemsContainer vertical-wrap padded-left padded-right"> <div is="emby-itemscontainer" class="itemsContainer vertical-wrap padded-left padded-right">
</div> </div>

View file

@ -17,7 +17,7 @@ import 'emby-button';
function getTabs() { function getTabs() {
return [{ return [{
name: globalize.translate('TabShows') name: globalize.translate('Shows')
}, { }, {
name: globalize.translate('Suggestions') name: globalize.translate('Suggestions')
}, { }, {
@ -25,11 +25,11 @@ import 'emby-button';
}, { }, {
name: globalize.translate('TabUpcoming') name: globalize.translate('TabUpcoming')
}, { }, {
name: globalize.translate('TabGenres') name: globalize.translate('Genres')
}, { }, {
name: globalize.translate('TabNetworks') name: globalize.translate('TabNetworks')
}, { }, {
name: globalize.translate('TabEpisodes') name: globalize.translate('Episodes')
}]; }];
} }
@ -318,8 +318,8 @@ import 'emby-button';
libraryMenu.setTitle(item.Name); libraryMenu.setTitle(item.Name);
}); });
} else { } else {
view.setAttribute('data-title', globalize.translate('TabShows')); view.setAttribute('data-title', globalize.translate('Shows'));
libraryMenu.setTitle(globalize.translate('TabShows')); 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 class="homeScreenSettingsContainer padded-left padded-right padded-bottom-page">
</div> </div>
</div> </div>

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -10,7 +10,7 @@ import 'webcomponents';
function onKeyDown(e) { function onKeyDown(e) {
// Don't submit form on enter // Don't submit form on enter
// Real (non-emulator) Tizen does nothing on Space // 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(); e.preventDefault();
this.checked = !this.checked; this.checked = !this.checked;

View file

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

View file

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

View file

@ -150,7 +150,7 @@ function tryRemoveElement(elem) {
/** /**
* @type {string} * @type {string}
*/ */
name name;
/** /**
* @type {string} * @type {string}
*/ */
@ -730,7 +730,7 @@ function tryRemoveElement(elem) {
const elem = e.target; const elem = e.target;
this.destroyCustomTrack(elem); this.destroyCustomTrack(elem);
onEndedInternal(this, elem, this.onError); onEndedInternal(this, elem, this.onError);
} };
/** /**
* @private * @private
@ -760,7 +760,7 @@ function tryRemoveElement(elem) {
} }
events.trigger(this, 'timeupdate'); events.trigger(this, 'timeupdate');
} };
/** /**
* @private * @private
@ -773,7 +773,7 @@ function tryRemoveElement(elem) {
const elem = e.target; const elem = e.target;
saveVolume(elem.volume); saveVolume(elem.volume);
events.trigger(this, 'volumechange'); events.trigger(this, 'volumechange');
} };
/** /**
* @private * @private
@ -785,7 +785,7 @@ function tryRemoveElement(elem) {
this.onStartedAndNavigatedToOsd(); this.onStartedAndNavigatedToOsd();
} }
} };
/** /**
* @private * @private
@ -832,14 +832,14 @@ function tryRemoveElement(elem) {
} }
} }
events.trigger(this, 'playing'); events.trigger(this, 'playing');
} };
/** /**
* @private * @private
*/ */
onPlay = () => { onPlay = () => {
events.trigger(this, 'unpause'); events.trigger(this, 'unpause');
} };
/** /**
* @private * @private
@ -865,21 +865,21 @@ function tryRemoveElement(elem) {
*/ */
onClick = () => { onClick = () => {
events.trigger(this, 'click'); events.trigger(this, 'click');
} };
/** /**
* @private * @private
*/ */
onDblClick = () => { onDblClick = () => {
events.trigger(this, 'dblclick'); events.trigger(this, 'dblclick');
} };
/** /**
* @private * @private
*/ */
onPause = () => { onPause = () => {
events.trigger(this, 'pause'); events.trigger(this, 'pause');
} };
onWaiting() { onWaiting() {
events.trigger(this, 'waiting'); events.trigger(this, 'waiting');
@ -929,7 +929,7 @@ function tryRemoveElement(elem) {
} }
onErrorInternal(this, type); onErrorInternal(this, type);
} };
/** /**
* @private * @private
@ -1634,6 +1634,31 @@ function tryRemoveElement(elem) {
return null; 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) { setVolume(val) {
const mediaElement = this.#mediaElement; const mediaElement = this.#mediaElement;
if (mediaElement) { if (mediaElement) {

View file

@ -1,22 +1,21 @@
define(['playbackManager', 'events', 'serverNotifications', 'connectionManager'], function (playbackManager, events, serverNotifications, connectionManager) { import playbackManager from 'playbackManager';
'use strict'; import events from 'events';
import serverNotifications from 'serverNotifications';
serverNotifications = serverNotifications.default || serverNotifications; import connectionManager from 'connectionManager';
playbackManager = playbackManager.default || playbackManager;
function getActivePlayerId() { function getActivePlayerId() {
var info = playbackManager.getPlayerInfo(); const info = playbackManager.getPlayerInfo();
return info ? info.id : null; return info ? info.id : null;
} }
function sendPlayCommand(apiClient, options, playType) { function sendPlayCommand(apiClient, options, playType) {
var sessionId = getActivePlayerId(); const sessionId = getActivePlayerId();
var ids = options.ids || options.items.map(function (i) { const ids = options.ids || options.items.map(function (i) {
return i.Id; return i.Id;
}); });
var remoteOptions = { const remoteOptions = {
ItemIds: ids.join(','), ItemIds: ids.join(','),
PlayCommand: playType PlayCommand: playType
@ -46,13 +45,13 @@ define(['playbackManager', 'events', 'serverNotifications', 'connectionManager']
} }
function sendPlayStateCommand(apiClient, command, options) { function sendPlayStateCommand(apiClient, command, options) {
var sessionId = getActivePlayerId(); const sessionId = getActivePlayerId();
apiClient.sendPlayStateCommand(sessionId, command, options); apiClient.sendPlayStateCommand(sessionId, command, options);
} }
function getCurrentApiClient(instance) { function getCurrentApiClient(instance) {
var currentServerId = instance.currentServerId; const currentServerId = instance.currentServerId;
if (currentServerId) { if (currentServerId) {
return connectionManager.getApiClient(currentServerId); return connectionManager.getApiClient(currentServerId);
@ -62,7 +61,7 @@ define(['playbackManager', 'events', 'serverNotifications', 'connectionManager']
} }
function sendCommandByName(instance, name, options) { function sendCommandByName(instance, name, options) {
var command = { const command = {
Name: name Name: name
}; };
@ -76,7 +75,7 @@ define(['playbackManager', 'events', 'serverNotifications', 'connectionManager']
function unsubscribeFromPlayerUpdates(instance) { function unsubscribeFromPlayerUpdates(instance) {
instance.isUpdating = true; instance.isUpdating = true;
var apiClient = getCurrentApiClient(instance); const apiClient = getCurrentApiClient(instance);
apiClient.sendMessage('SessionsStop'); apiClient.sendMessage('SessionsStop');
if (instance.pollInterval) { if (instance.pollInterval) {
clearInterval(instance.pollInterval); clearInterval(instance.pollInterval);
@ -85,7 +84,7 @@ define(['playbackManager', 'events', 'serverNotifications', 'connectionManager']
} }
function processUpdatedSessions(instance, sessions, apiClient) { function processUpdatedSessions(instance, sessions, apiClient) {
var serverId = apiClient.serverId(); const serverId = apiClient.serverId();
sessions.map(function (s) { sessions.map(function (s) {
if (s.NowPlayingItem) { if (s.NowPlayingItem) {
@ -93,19 +92,19 @@ define(['playbackManager', 'events', 'serverNotifications', 'connectionManager']
} }
}); });
var currentTargetId = getActivePlayerId(); const currentTargetId = getActivePlayerId();
var session = sessions.filter(function (s) { const session = sessions.filter(function (s) {
return s.Id === currentTargetId; return s.Id === currentTargetId;
})[0]; })[0];
if (session) { if (session) {
normalizeImages(session, apiClient); normalizeImages(session, apiClient);
var eventNames = getChangedEvents(instance.lastPlayerData, session); const eventNames = getChangedEvents(instance.lastPlayerData, session);
instance.lastPlayerData = session; instance.lastPlayerData = session;
for (var i = 0, length = eventNames.length; i < length; i++) { for (let i = 0, length = eventNames.length; i < length; i++) {
events.trigger(instance, eventNames[i], [session]); events.trigger(instance, eventNames[i], [session]);
} }
} else { } else {
@ -116,7 +115,7 @@ define(['playbackManager', 'events', 'serverNotifications', 'connectionManager']
} }
function getChangedEvents(state1, state2) { function getChangedEvents(state1, state2) {
var names = []; const names = [];
if (!state1) { if (!state1) {
names.push('statechange'); names.push('statechange');
@ -135,8 +134,8 @@ define(['playbackManager', 'events', 'serverNotifications', 'connectionManager']
} }
function onPollIntervalFired() { function onPollIntervalFired() {
var instance = this; const instance = this;
var apiClient = getCurrentApiClient(instance); const apiClient = getCurrentApiClient(instance);
if (!apiClient.isMessageChannelOpen()) { if (!apiClient.isMessageChannelOpen()) {
apiClient.getSessions().then(function (sessions) { apiClient.getSessions().then(function (sessions) {
processUpdatedSessions(instance, sessions, apiClient); processUpdatedSessions(instance, sessions, apiClient);
@ -147,7 +146,7 @@ define(['playbackManager', 'events', 'serverNotifications', 'connectionManager']
function subscribeToPlayerUpdates(instance) { function subscribeToPlayerUpdates(instance) {
instance.isUpdating = true; instance.isUpdating = true;
var apiClient = getCurrentApiClient(instance); const apiClient = getCurrentApiClient(instance);
apiClient.sendMessage('SessionsStart', '100,800'); apiClient.sendMessage('SessionsStart', '100,800');
if (instance.pollInterval) { if (instance.pollInterval) {
clearInterval(instance.pollInterval); clearInterval(instance.pollInterval);
@ -158,7 +157,7 @@ define(['playbackManager', 'events', 'serverNotifications', 'connectionManager']
function normalizeImages(state, apiClient) { function normalizeImages(state, apiClient) {
if (state && state.NowPlayingItem) { if (state && state.NowPlayingItem) {
var item = state.NowPlayingItem; const item = state.NowPlayingItem;
if (!item.ImageTags || !item.ImageTags.Primary) { if (!item.ImageTags || !item.ImageTags.Primary) {
if (item.PrimaryImageTag) { if (item.PrimaryImageTag) {
@ -179,8 +178,9 @@ define(['playbackManager', 'events', 'serverNotifications', 'connectionManager']
} }
} }
function SessionPlayer() { class SessionPlayer {
var self = this; constructor() {
const self = this;
this.name = 'Remote Control'; this.name = 'Remote Control';
this.type = 'mediaplayer'; this.type = 'mediaplayer';
@ -192,7 +192,7 @@ define(['playbackManager', 'events', 'serverNotifications', 'connectionManager']
}); });
} }
SessionPlayer.prototype.beginPlayerUpdates = function () { beginPlayerUpdates() {
this.playerListenerCount = this.playerListenerCount || 0; this.playerListenerCount = this.playerListenerCount || 0;
if (this.playerListenerCount <= 0) { if (this.playerListenerCount <= 0) {
@ -202,9 +202,9 @@ define(['playbackManager', 'events', 'serverNotifications', 'connectionManager']
} }
this.playerListenerCount++; this.playerListenerCount++;
}; }
SessionPlayer.prototype.endPlayerUpdates = function () { endPlayerUpdates() {
this.playerListenerCount = this.playerListenerCount || 0; this.playerListenerCount = this.playerListenerCount || 0;
this.playerListenerCount--; this.playerListenerCount--;
@ -212,21 +212,21 @@ define(['playbackManager', 'events', 'serverNotifications', 'connectionManager']
unsubscribeFromPlayerUpdates(this); unsubscribeFromPlayerUpdates(this);
this.playerListenerCount = 0; this.playerListenerCount = 0;
} }
}; }
SessionPlayer.prototype.getPlayerState = function () { getPlayerState() {
return this.lastPlayerData || {}; return this.lastPlayerData || {};
}; }
SessionPlayer.prototype.getTargets = function () { getTargets() {
var apiClient = getCurrentApiClient(this); const apiClient = getCurrentApiClient(this);
var sessionQuery = { const sessionQuery = {
ControllableByUserId: apiClient.getCurrentUserId() ControllableByUserId: apiClient.getCurrentUserId()
}; };
if (apiClient) { if (apiClient) {
var name = this.name; const name = this.name;
return apiClient.getSessions(sessionQuery).then(function (sessions) { return apiClient.getSessions(sessionQuery).then(function (sessions) {
return sessions.filter(function (s) { return sessions.filter(function (s) {
@ -243,11 +243,9 @@ define(['playbackManager', 'events', 'serverNotifications', 'connectionManager']
isLocalPlayer: false, isLocalPlayer: false,
supportedCommands: s.Capabilities.SupportedCommands, supportedCommands: s.Capabilities.SupportedCommands,
user: s.UserId ? { user: s.UserId ? {
Id: s.UserId, Id: s.UserId,
Name: s.UserName, Name: s.UserName,
PrimaryImageTag: s.UserPrimaryImageTag PrimaryImageTag: s.UserPrimaryImageTag
} : null } : null
}; };
}); });
@ -255,16 +253,16 @@ define(['playbackManager', 'events', 'serverNotifications', 'connectionManager']
} else { } else {
return Promise.resolve([]); return Promise.resolve([]);
} }
}; }
SessionPlayer.prototype.sendCommand = function (command) { sendCommand(command) {
var sessionId = getActivePlayerId(); const sessionId = getActivePlayerId();
var apiClient = getCurrentApiClient(this); const apiClient = getCurrentApiClient(this);
apiClient.sendCommand(sessionId, command); apiClient.sendCommand(sessionId, command);
}; }
SessionPlayer.prototype.play = function (options) { play(options) {
options = Object.assign({}, options); options = Object.assign({}, options);
if (options.items) { if (options.items) {
@ -276,251 +274,233 @@ define(['playbackManager', 'events', 'serverNotifications', 'connectionManager']
} }
return sendPlayCommand(getCurrentApiClient(this), options, 'PlayNow'); return sendPlayCommand(getCurrentApiClient(this), options, 'PlayNow');
}; }
SessionPlayer.prototype.shuffle = function (item) { shuffle(item) {
sendPlayCommand(getCurrentApiClient(this), { ids: [item.Id] }, 'PlayShuffle'); sendPlayCommand(getCurrentApiClient(this), { ids: [item.Id] }, 'PlayShuffle');
}; }
SessionPlayer.prototype.instantMix = function (item) { instantMix(item) {
sendPlayCommand(getCurrentApiClient(this), { ids: [item.Id] }, 'PlayInstantMix'); sendPlayCommand(getCurrentApiClient(this), { ids: [item.Id] }, 'PlayInstantMix');
}; }
SessionPlayer.prototype.queue = function (options) { queue(options) {
sendPlayCommand(getCurrentApiClient(this), options, 'PlayNext'); sendPlayCommand(getCurrentApiClient(this), options, 'PlayNext');
}; }
SessionPlayer.prototype.queueNext = function (options) { queueNext(options) {
sendPlayCommand(getCurrentApiClient(this), options, 'PlayLast'); sendPlayCommand(getCurrentApiClient(this), options, 'PlayLast');
}; }
SessionPlayer.prototype.canPlayMediaType = function (mediaType) { canPlayMediaType(mediaType) {
mediaType = (mediaType || '').toLowerCase(); mediaType = (mediaType || '').toLowerCase();
return mediaType === 'audio' || mediaType === 'video'; return mediaType === 'audio' || mediaType === 'video';
}; }
SessionPlayer.prototype.canQueueMediaType = function (mediaType) { canQueueMediaType(mediaType) {
return this.canPlayMediaType(mediaType); return this.canPlayMediaType(mediaType);
}; }
SessionPlayer.prototype.stop = function () { stop() {
sendPlayStateCommand(getCurrentApiClient(this), 'stop'); sendPlayStateCommand(getCurrentApiClient(this), 'stop');
}; }
SessionPlayer.prototype.nextTrack = function () { nextTrack() {
sendPlayStateCommand(getCurrentApiClient(this), 'nextTrack'); sendPlayStateCommand(getCurrentApiClient(this), 'nextTrack');
}; }
SessionPlayer.prototype.previousTrack = function () { previousTrack() {
sendPlayStateCommand(getCurrentApiClient(this), 'previousTrack'); sendPlayStateCommand(getCurrentApiClient(this), 'previousTrack');
}; }
SessionPlayer.prototype.seek = function (positionTicks) { seek(positionTicks) {
sendPlayStateCommand(getCurrentApiClient(this), 'seek', sendPlayStateCommand(getCurrentApiClient(this), 'seek',
{ {
SeekPositionTicks: positionTicks SeekPositionTicks: positionTicks
}); });
}; }
SessionPlayer.prototype.currentTime = function (val) { currentTime(val) {
if (val != null) { if (val != null) {
return this.seek(val); return this.seek(val);
} }
var state = this.lastPlayerData || {}; let state = this.lastPlayerData || {};
state = state.PlayState || {}; state = state.PlayState || {};
return state.PositionTicks; return state.PositionTicks;
}; }
SessionPlayer.prototype.duration = function () { duration() {
var state = this.lastPlayerData || {}; let state = this.lastPlayerData || {};
state = state.NowPlayingItem || {}; state = state.NowPlayingItem || {};
return state.RunTimeTicks; return state.RunTimeTicks;
}; }
SessionPlayer.prototype.paused = function () { paused() {
var state = this.lastPlayerData || {}; let state = this.lastPlayerData || {};
state = state.PlayState || {}; state = state.PlayState || {};
return state.IsPaused; return state.IsPaused;
}; }
SessionPlayer.prototype.getVolume = function () { getVolume() {
var state = this.lastPlayerData || {}; let state = this.lastPlayerData || {};
state = state.PlayState || {}; state = state.PlayState || {};
return state.VolumeLevel; return state.VolumeLevel;
}; }
SessionPlayer.prototype.isMuted = function () { isMuted() {
var state = this.lastPlayerData || {}; let state = this.lastPlayerData || {};
state = state.PlayState || {}; state = state.PlayState || {};
return state.IsMuted; return state.IsMuted;
}; }
SessionPlayer.prototype.pause = function () { pause() {
sendPlayStateCommand(getCurrentApiClient(this), 'Pause'); sendPlayStateCommand(getCurrentApiClient(this), 'Pause');
}; }
SessionPlayer.prototype.unpause = function () { unpause() {
sendPlayStateCommand(getCurrentApiClient(this), 'Unpause'); sendPlayStateCommand(getCurrentApiClient(this), 'Unpause');
}; }
SessionPlayer.prototype.playPause = function () { playPause() {
sendPlayStateCommand(getCurrentApiClient(this), 'PlayPause'); sendPlayStateCommand(getCurrentApiClient(this), 'PlayPause');
}; }
SessionPlayer.prototype.setMute = function (isMuted) { setMute(isMuted) {
if (isMuted) { if (isMuted) {
sendCommandByName(this, 'Mute'); sendCommandByName(this, 'Mute');
} else { } else {
sendCommandByName(this, 'Unmute'); sendCommandByName(this, 'Unmute');
} }
}; }
SessionPlayer.prototype.toggleMute = function () { toggleMute() {
sendCommandByName(this, 'ToggleMute'); sendCommandByName(this, 'ToggleMute');
}; }
SessionPlayer.prototype.setVolume = function (vol) { setVolume(vol) {
sendCommandByName(this, 'SetVolume', { sendCommandByName(this, 'SetVolume', {
Volume: vol Volume: vol
}); });
}; }
SessionPlayer.prototype.volumeUp = function () { volumeUp() {
sendCommandByName(this, 'VolumeUp'); sendCommandByName(this, 'VolumeUp');
}; }
SessionPlayer.prototype.volumeDown = function () { volumeDown() {
sendCommandByName(this, 'VolumeDown'); sendCommandByName(this, 'VolumeDown');
}; }
SessionPlayer.prototype.toggleFullscreen = function () { toggleFullscreen() {
sendCommandByName(this, 'ToggleFullscreen'); sendCommandByName(this, 'ToggleFullscreen');
}; }
SessionPlayer.prototype.audioTracks = function () { audioTracks() {
var state = this.lastPlayerData || {}; let state = this.lastPlayerData || {};
state = state.NowPlayingItem || {}; state = state.NowPlayingItem || {};
var streams = state.MediaStreams || []; const streams = state.MediaStreams || [];
return streams.filter(function (s) { return streams.filter(function (s) {
return s.Type === 'Audio'; return s.Type === 'Audio';
}); });
}; }
SessionPlayer.prototype.getAudioStreamIndex = function () { getAudioStreamIndex() {
var state = this.lastPlayerData || {}; let state = this.lastPlayerData || {};
state = state.PlayState || {}; state = state.PlayState || {};
return state.AudioStreamIndex; return state.AudioStreamIndex;
}; }
SessionPlayer.prototype.playTrailers = function (item) { playTrailers(item) {
sendCommandByName(this, 'PlayTrailers', { sendCommandByName(this, 'PlayTrailers', {
ItemId: item.Id ItemId: item.Id
}); });
}; }
SessionPlayer.prototype.setAudioStreamIndex = function (index) { setAudioStreamIndex(index) {
sendCommandByName(this, 'SetAudioStreamIndex', { sendCommandByName(this, 'SetAudioStreamIndex', {
Index: index Index: index
}); });
}; }
SessionPlayer.prototype.subtitleTracks = function () { subtitleTracks() {
var state = this.lastPlayerData || {}; let state = this.lastPlayerData || {};
state = state.NowPlayingItem || {}; state = state.NowPlayingItem || {};
var streams = state.MediaStreams || []; const streams = state.MediaStreams || [];
return streams.filter(function (s) { return streams.filter(function (s) {
return s.Type === 'Subtitle'; return s.Type === 'Subtitle';
}); });
}; }
SessionPlayer.prototype.getSubtitleStreamIndex = function () { getSubtitleStreamIndex() {
var state = this.lastPlayerData || {}; let state = this.lastPlayerData || {};
state = state.PlayState || {}; state = state.PlayState || {};
return state.SubtitleStreamIndex; return state.SubtitleStreamIndex;
}; }
SessionPlayer.prototype.setSubtitleStreamIndex = function (index) { setSubtitleStreamIndex(index) {
sendCommandByName(this, 'SetSubtitleStreamIndex', { sendCommandByName(this, 'SetSubtitleStreamIndex', {
Index: index Index: index
}); });
}; }
SessionPlayer.prototype.getMaxStreamingBitrate = function () { setRepeatMode(mode) {
};
SessionPlayer.prototype.setMaxStreamingBitrate = function (options) {
};
SessionPlayer.prototype.isFullscreen = function () {
};
SessionPlayer.prototype.toggleFullscreen = function () {
};
SessionPlayer.prototype.getRepeatMode = function () {
};
SessionPlayer.prototype.setRepeatMode = function (mode) {
sendCommandByName(this, 'SetRepeatMode', { sendCommandByName(this, 'SetRepeatMode', {
RepeatMode: mode RepeatMode: mode
}); });
}; }
SessionPlayer.prototype.setQueueShuffleMode = function (mode) { getRepeatMode() {
}
setQueueShuffleMode(mode) {
sendCommandByName(this, 'SetShuffleQueue', { sendCommandByName(this, 'SetShuffleQueue', {
ShuffleMode: mode ShuffleMode: mode
}); });
}; }
SessionPlayer.prototype.getQueueShuffleMode = function () { getQueueShuffleMode() {
}
}; displayContent(options) {
SessionPlayer.prototype.displayContent = function (options) {
sendCommandByName(this, 'DisplayContent', options); sendCommandByName(this, 'DisplayContent', options);
}; }
SessionPlayer.prototype.isPlaying = function () { isPlaying() {
var state = this.lastPlayerData || {}; const state = this.lastPlayerData || {};
return state.NowPlayingItem != null; return state.NowPlayingItem != null;
}; }
SessionPlayer.prototype.isPlayingVideo = function () { isPlayingVideo() {
var state = this.lastPlayerData || {}; let state = this.lastPlayerData || {};
state = state.NowPlayingItem || {}; state = state.NowPlayingItem || {};
return state.MediaType === 'Video'; return state.MediaType === 'Video';
}; }
SessionPlayer.prototype.isPlayingAudio = function () { isPlayingAudio() {
var state = this.lastPlayerData || {}; let state = this.lastPlayerData || {};
state = state.NowPlayingItem || {}; state = state.NowPlayingItem || {};
return state.MediaType === 'Audio'; return state.MediaType === 'Audio';
}; }
SessionPlayer.prototype.getPlaylist = function () { getPlaylist() {
return Promise.resolve([]); return Promise.resolve([]);
}; }
SessionPlayer.prototype.getCurrentPlaylistItemId = function () { getCurrentPlaylistItemId() {
}; }
SessionPlayer.prototype.setCurrentPlaylistItem = function (playlistItemId) { setCurrentPlaylistItem(playlistItemId) {
return Promise.resolve(); return Promise.resolve();
}; }
SessionPlayer.prototype.removeFromPlaylist = function (playlistItemIds) { removeFromPlaylist(playlistItemIds) {
return Promise.resolve(); return Promise.resolve();
}; }
SessionPlayer.prototype.tryPair = function (target) { tryPair(target) {
return Promise.resolve(); 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) { if (result.TotalRecordCount) {
nodes.push({ nodes.push({
id: 'livetv', id: 'livetv',
text: globalize.translate('HeaderLiveTV'), text: globalize.translate('LiveTV'),
state: { state: {
opened: false opened: false
}, },
@ -302,7 +302,7 @@ import 'material-icons';
$(document).on('itemsaved', '.metadataEditorPage', function (e, item) { $(document).on('itemsaved', '.metadataEditorPage', function (e, item) {
updateEditorNode(this, item); updateEditorNode(this, item);
}).on('pagebeforeshow', '.metadataEditorPage', function () { }).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'); import('css!assets/css/metadataeditor.css');
}).on('pagebeforeshow', '.metadataEditorPage', function () { }).on('pagebeforeshow', '.metadataEditorPage', function () {
var page = this; var page = this;

View file

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

View file

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

View file

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

View file

@ -105,11 +105,11 @@ export function getQueryPagingHtml (options) {
} }
if (options.sortButton) { 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) { 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>'; html += '</div>';

View file

@ -8,7 +8,7 @@ import appRouter from 'appRouter';
import appHost from 'apphost'; import appHost from 'apphost';
import playbackManager from 'playbackManager'; import playbackManager from 'playbackManager';
import syncPlayManager from 'syncPlayManager'; import syncPlayManager from 'syncPlayManager';
import groupSelectionMenu from 'groupSelectionMenu'; import * as groupSelectionMenu from 'groupSelectionMenu';
import browser from 'browser'; import browser from 'browser';
import globalize from 'globalize'; import globalize from 'globalize';
import imageHelper from 'scripts/imagehelper'; import imageHelper from 'scripts/imagehelper';
@ -270,7 +270,7 @@ import 'flexStyles';
function refreshLibraryInfoInDrawer(user, drawer) { function refreshLibraryInfoInDrawer(user, drawer) {
let html = ''; let html = '';
html += '<div style="height:.5em;"></div>'; html += '<div style="height:.5em;"></div>';
html += '<a is="emby-linkbutton" class="navMenuOption lnkMediaFolder" href="home.html"><span class="material-icons navMenuOptionIcon home"></span><span class="navMenuOptionText">' + globalize.translate('ButtonHome') + '</span></a>'; html += '<a is="emby-linkbutton" class="navMenuOption lnkMediaFolder" href="home.html"><span class="material-icons navMenuOptionIcon home"></span><span class="navMenuOptionText">' + globalize.translate('Home') + '</span></a>';
// libraries are added here // libraries are added here
html += '<div class="libraryMenuOptions">'; html += '<div class="libraryMenuOptions">';
@ -377,7 +377,7 @@ import 'flexStyles';
pageIds: ['dashboardGeneralPage'], pageIds: ['dashboardGeneralPage'],
icon: 'settings' icon: 'settings'
}, { }, {
name: globalize.translate('TabUsers'), name: globalize.translate('HeaderUsers'),
href: 'userprofiles.html', href: 'userprofiles.html',
pageIds: ['userProfilesPage', 'newUserPage', 'editUserPage', 'userLibraryAccessPage', 'userParentalControlPage', 'userPasswordPage'], pageIds: ['userProfilesPage', 'newUserPage', 'editUserPage', 'userLibraryAccessPage', 'userParentalControlPage', 'userPasswordPage'],
icon: 'people' icon: 'people'
@ -395,10 +395,10 @@ import 'flexStyles';
addPluginPagesToMainMenu(links, pluginItems, 'server'); addPluginPagesToMainMenu(links, pluginItems, 'server');
links.push({ links.push({
divider: true, divider: true,
name: globalize.translate('TabDevices') name: globalize.translate('HeaderDevices')
}); });
links.push({ links.push({
name: globalize.translate('TabDevices'), name: globalize.translate('HeaderDevices'),
href: 'devices.html', href: 'devices.html',
pageIds: ['devicesPage', 'devicePage'], pageIds: ['devicesPage', 'devicePage'],
icon: 'devices' icon: 'devices'
@ -417,16 +417,16 @@ import 'flexStyles';
}); });
links.push({ links.push({
divider: true, divider: true,
name: globalize.translate('TabLiveTV') name: globalize.translate('LiveTV')
}); });
links.push({ links.push({
name: globalize.translate('TabLiveTV'), name: globalize.translate('LiveTV'),
href: 'livetvstatus.html', href: 'livetvstatus.html',
pageIds: ['liveTvStatusPage', 'liveTvTunerPage'], pageIds: ['liveTvStatusPage', 'liveTvTunerPage'],
icon: 'live_tv' icon: 'live_tv'
}); });
links.push({ links.push({
name: globalize.translate('TabDVR'), name: globalize.translate('HeaderDVR'),
href: 'livetvsettings.html', href: 'livetvsettings.html',
pageIds: ['liveTvSettingsPage'], pageIds: ['liveTvSettingsPage'],
icon: 'dvr' icon: 'dvr'
@ -567,7 +567,7 @@ import 'flexStyles';
view.ImageTags = {}; view.ImageTags = {};
view.icon = 'live_tv'; view.icon = 'live_tv';
const guideView = Object.assign({}, view); const guideView = Object.assign({}, view);
guideView.Name = globalize.translate('ButtonGuide'); guideView.Name = globalize.translate('Guide');
guideView.ImageTags = {}; guideView.ImageTags = {};
guideView.icon = 'dvr'; guideView.icon = 'dvr';
guideView.url = 'livetv.html?tab=1'; guideView.url = 'livetv.html?tab=1';

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