mirror of
https://github.com/jellyfin/jellyfin-web
synced 2025-03-30 19:56:21 +00:00
Merge branch 'master' into audio-normalization
This commit is contained in:
commit
8d5475a21b
143 changed files with 1557 additions and 1079 deletions
|
@ -1,5 +1,5 @@
|
|||
import React, { FunctionComponent, useEffect, useState } from 'react';
|
||||
import { Outlet, useNavigate } from 'react-router-dom';
|
||||
import { Outlet, useLocation, useNavigate } from 'react-router-dom';
|
||||
import type { ConnectResponse } from 'jellyfin-apiclient';
|
||||
|
||||
import alert from './alert';
|
||||
|
@ -31,11 +31,11 @@ const ConnectionRequired: FunctionComponent<ConnectionRequiredProps> = ({
|
|||
isUserRequired = true
|
||||
}) => {
|
||||
const navigate = useNavigate();
|
||||
const location = useLocation();
|
||||
|
||||
const [ isLoading, setIsLoading ] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const bounce = async (connectionResponse: ConnectResponse) => {
|
||||
switch (connectionResponse.State) {
|
||||
case ConnectionState.SignedIn:
|
||||
|
@ -45,12 +45,12 @@ const ConnectionRequired: FunctionComponent<ConnectionRequiredProps> = ({
|
|||
return;
|
||||
case ConnectionState.ServerSignIn:
|
||||
// Bounce to the login page
|
||||
console.debug('[ConnectionRequired] not logged in, redirecting to login page');
|
||||
navigate(BounceRoutes.Login, {
|
||||
state: {
|
||||
serverid: connectionResponse.ApiClient.serverId()
|
||||
}
|
||||
});
|
||||
if (location.pathname === BounceRoutes.Login) {
|
||||
setIsLoading(false);
|
||||
} else {
|
||||
console.debug('[ConnectionRequired] not logged in, redirecting to login page');
|
||||
navigate(`${BounceRoutes.Login}?serverid=${connectionResponse.ApiClient.serverId()}`);
|
||||
}
|
||||
return;
|
||||
case ConnectionState.ServerSelection:
|
||||
// Bounce to select server page
|
||||
|
@ -144,7 +144,7 @@ const ConnectionRequired: FunctionComponent<ConnectionRequiredProps> = ({
|
|||
};
|
||||
|
||||
validateConnection();
|
||||
}, [ isAdminRequired, isUserRequired, navigate ]);
|
||||
}, [ isAdminRequired, isUserRequired, location.pathname, navigate ]);
|
||||
|
||||
if (isLoading) {
|
||||
return <Loading />;
|
||||
|
|
|
@ -19,7 +19,7 @@ import template from './accessSchedule.template.html';
|
|||
const pct = hours % 1;
|
||||
|
||||
if (pct) {
|
||||
minutes = parseInt(60 * pct);
|
||||
minutes = parseInt(60 * pct, 10);
|
||||
}
|
||||
|
||||
return datetime.getDisplayTime(new Date(2000, 1, 1, hours, minutes, 0, 0));
|
||||
|
|
|
@ -6,7 +6,7 @@ import dom from '../../scripts/dom';
|
|||
import '../../elements/emby-button/emby-button';
|
||||
import './actionSheet.scss';
|
||||
import 'material-design-icons-iconfont';
|
||||
import '../../assets/css/scrollstyles.scss';
|
||||
import '../../styles/scrollstyles.scss';
|
||||
import '../../components/listview/listview.scss';
|
||||
|
||||
function getOffsets(elems) {
|
||||
|
|
|
@ -64,10 +64,10 @@ import { toBoolean } from '../utils/string.ts';
|
|||
|
||||
function reloadData(instance, elem, apiClient, startIndex, limit) {
|
||||
if (startIndex == null) {
|
||||
startIndex = parseInt(elem.getAttribute('data-activitystartindex') || '0');
|
||||
startIndex = parseInt(elem.getAttribute('data-activitystartindex') || '0', 10);
|
||||
}
|
||||
|
||||
limit = limit || parseInt(elem.getAttribute('data-activitylimit') || '7');
|
||||
limit = limit || parseInt(elem.getAttribute('data-activitylimit') || '7', 10);
|
||||
const minDate = new Date();
|
||||
const hasUserId = toBoolean(elem.getAttribute('data-useractivity'), true);
|
||||
|
||||
|
|
|
@ -124,7 +124,7 @@ class AppRouter {
|
|||
isBack: action === Action.Pop
|
||||
});
|
||||
} else {
|
||||
console.info('[appRouter] "%s" route not found', normalizedPath, location);
|
||||
// The route is not registered here, so it should be handled by react-router
|
||||
this.currentRouteInfo = {
|
||||
route: {},
|
||||
path: normalizedPath + location.search
|
||||
|
|
|
@ -663,7 +663,7 @@ import { appRouter } from '../appRouter';
|
|||
const character = String(str.slice(charIndex, charIndex + 1).charCodeAt());
|
||||
let sum = 0;
|
||||
for (let i = 0; i < character.length; i++) {
|
||||
sum += parseInt(character.charAt(i));
|
||||
sum += parseInt(character.charAt(i), 10);
|
||||
}
|
||||
const index = String(sum).slice(-1);
|
||||
|
||||
|
@ -773,27 +773,24 @@ import { appRouter } from '../appRouter';
|
|||
* @param {Object} item - Item used to generate the footer text.
|
||||
* @param {Object} apiClient - API client instance.
|
||||
* @param {Object} options - Options used to generate the footer text.
|
||||
* @param {string} showTitle - Flag to show the title in the footer.
|
||||
* @param {boolean} forceName - Flag to force showing the name of the item.
|
||||
* @param {boolean} overlayText - Flag to show overlay text.
|
||||
* @param {Object} imgUrl - Object representing the card's image URL.
|
||||
* @param {string} footerClass - CSS classes of the footer element.
|
||||
* @param {string} progressHtml - HTML markup of the progress bar element.
|
||||
* @param {string} logoUrl - URL of the logo for the item.
|
||||
* @param {boolean} isOuterFooter - Flag to mark the text as outer footer.
|
||||
* @param {Object} flags - Various flags for the footer
|
||||
* @param {Object} urls - Various urls for the footer
|
||||
* @returns {string} HTML markup of the card's footer text element.
|
||||
*/
|
||||
function getCardFooterText(item, apiClient, options, showTitle, forceName, overlayText, imgUrl, footerClass, progressHtml, logoUrl, isOuterFooter) {
|
||||
function getCardFooterText(item, apiClient, options, footerClass, progressHtml, flags, urls) {
|
||||
item = item.ProgramInfo || item;
|
||||
let html = '';
|
||||
|
||||
if (logoUrl) {
|
||||
html += '<div class="lazy cardFooterLogo" data-src="' + logoUrl + '"></div>';
|
||||
if (urls.logoUrl) {
|
||||
html += '<div class="lazy cardFooterLogo" data-src="' + urls.logoUrl + '"></div>';
|
||||
}
|
||||
|
||||
const showOtherText = isOuterFooter ? !overlayText : overlayText;
|
||||
const showTitle = options.showTitle === 'auto' ? true : (options.showTitle || item.Type === 'PhotoAlbum' || item.Type === 'Folder');
|
||||
const showOtherText = flags.isOuterFooter ? !flags.overlayText : flags.overlayText;
|
||||
|
||||
if (isOuterFooter && options.cardLayout && layoutManager.mobile && options.cardFooterAside !== 'none') {
|
||||
if (flags.isOuterFooter && options.cardLayout && layoutManager.mobile && options.cardFooterAside !== 'none') {
|
||||
html += `<button is="paper-icon-button-light" class="itemAction btnCardOptions cardText-secondary" data-action="menu" title="${globalize.translate('ButtonMore')}"><span class="material-icons more_vert" aria-hidden="true"></span></button>`;
|
||||
}
|
||||
|
||||
|
@ -805,7 +802,7 @@ import { appRouter } from '../appRouter';
|
|||
let titleAdded;
|
||||
|
||||
if (showOtherText && (options.showParentTitle || options.showParentTitleOrTitle) && !parentTitleUnderneath) {
|
||||
if (isOuterFooter && item.Type === 'Episode' && item.SeriesName) {
|
||||
if (flags.isOuterFooter && item.Type === 'Episode' && item.SeriesName) {
|
||||
if (item.SeriesId) {
|
||||
lines.push(getTextActionButton({
|
||||
Id: item.SeriesId,
|
||||
|
@ -835,7 +832,7 @@ import { appRouter } from '../appRouter';
|
|||
}
|
||||
|
||||
let showMediaTitle = (showTitle && !titleAdded) || (options.showParentTitleOrTitle && !lines.length);
|
||||
if (!showMediaTitle && !titleAdded && (showTitle || forceName)) {
|
||||
if (!showMediaTitle && !titleAdded && (showTitle || flags.forceName)) {
|
||||
showMediaTitle = true;
|
||||
}
|
||||
|
||||
|
@ -856,7 +853,7 @@ import { appRouter } from '../appRouter';
|
|||
|
||||
if (showOtherText) {
|
||||
if (options.showParentTitle && parentTitleUnderneath) {
|
||||
if (isOuterFooter && item.AlbumArtists && item.AlbumArtists.length) {
|
||||
if (flags.isOuterFooter && item.AlbumArtists && item.AlbumArtists.length) {
|
||||
item.AlbumArtists[0].Type = 'MusicArtist';
|
||||
item.AlbumArtists[0].IsFolder = true;
|
||||
lines.push(getTextActionButton(item.AlbumArtists[0], null, serverId));
|
||||
|
@ -991,23 +988,23 @@ import { appRouter } from '../appRouter';
|
|||
}
|
||||
}
|
||||
|
||||
if ((showTitle || !imgUrl) && forceName && overlayText && lines.length === 1) {
|
||||
if ((showTitle || !urls.imgUrl) && flags.forceName && flags.overlayText && lines.length === 1) {
|
||||
lines = [];
|
||||
}
|
||||
|
||||
if (overlayText && showTitle) {
|
||||
if (flags.overlayText && showTitle) {
|
||||
lines = [escapeHtml(item.Name)];
|
||||
}
|
||||
|
||||
const addRightTextMargin = isOuterFooter && options.cardLayout && !options.centerText && options.cardFooterAside !== 'none' && layoutManager.mobile;
|
||||
const addRightTextMargin = flags.isOuterFooter && options.cardLayout && !options.centerText && options.cardFooterAside !== 'none' && layoutManager.mobile;
|
||||
|
||||
html += getCardTextLines(lines, cssClass, !options.overlayText, isOuterFooter, options.cardLayout, addRightTextMargin, options.lines);
|
||||
html += getCardTextLines(lines, cssClass, !options.overlayText, flags.isOuterFooter, options.cardLayout, addRightTextMargin, options.lines);
|
||||
|
||||
if (progressHtml) {
|
||||
html += progressHtml;
|
||||
}
|
||||
|
||||
if (html && (!isOuterFooter || logoUrl || options.cardLayout)) {
|
||||
if (html && (!flags.isOuterFooter || urls.logoUrl || options.cardLayout)) {
|
||||
html = '<div class="' + footerClass + '">' + html;
|
||||
|
||||
//cardFooter
|
||||
|
@ -1217,7 +1214,6 @@ import { appRouter } from '../appRouter';
|
|||
|
||||
const forceName = imgInfo.forceName;
|
||||
|
||||
const showTitle = options.showTitle === 'auto' ? true : (options.showTitle || item.Type === 'PhotoAlbum' || item.Type === 'Folder');
|
||||
const overlayText = options.overlayText;
|
||||
|
||||
let cardImageContainerClass = 'cardImageContainer';
|
||||
|
@ -1265,7 +1261,7 @@ import { appRouter } from '../appRouter';
|
|||
logoUrl = null;
|
||||
|
||||
footerCssClass = progressHtml ? 'innerCardFooter fullInnerCardFooter' : 'innerCardFooter';
|
||||
innerCardFooter += getCardFooterText(item, apiClient, options, showTitle, forceName, overlayText, imgUrl, footerCssClass, progressHtml, logoUrl, false);
|
||||
innerCardFooter += getCardFooterText(item, apiClient, options, footerCssClass, progressHtml, { forceName, overlayText, isOuterFooter: false }, { imgUrl, logoUrl });
|
||||
footerOverlayed = true;
|
||||
} else if (progressHtml) {
|
||||
innerCardFooter += '<div class="innerCardFooter fullInnerCardFooter innerCardFooterClear">';
|
||||
|
@ -1292,7 +1288,7 @@ import { appRouter } from '../appRouter';
|
|||
logoUrl = null;
|
||||
}
|
||||
|
||||
outerCardFooter = getCardFooterText(item, apiClient, options, showTitle, forceName, overlayText, imgUrl, footerCssClass, progressHtml, logoUrl, true);
|
||||
outerCardFooter = getCardFooterText(item, apiClient, options, footerCssClass, progressHtml, { forceName, overlayText, isOuterFooter: true }, { imgUrl, logoUrl });
|
||||
}
|
||||
|
||||
if (outerCardFooter && !options.cardLayout) {
|
||||
|
|
|
@ -12,7 +12,7 @@ import '../../elements/emby-input/emby-input';
|
|||
import '../../elements/emby-select/emby-select';
|
||||
import 'material-design-icons-iconfont';
|
||||
import '../formdialog.scss';
|
||||
import '../../assets/css/flexstyles.scss';
|
||||
import '../../styles/flexstyles.scss';
|
||||
import ServerConnections from '../ServerConnections';
|
||||
import toast from '../toast/toast';
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ import '../../elements/emby-button/emby-button';
|
|||
import '../../elements/emby-button/paper-icon-button-light';
|
||||
import '../../elements/emby-input/emby-input';
|
||||
import '../formdialog.scss';
|
||||
import '../../assets/css/flexstyles.scss';
|
||||
import '../../styles/flexstyles.scss';
|
||||
import template from './dialog.template.html';
|
||||
|
||||
/* eslint-disable indent */
|
||||
|
|
|
@ -7,7 +7,7 @@ import { toBoolean } from '../../utils/string.ts';
|
|||
import dom from '../../scripts/dom';
|
||||
|
||||
import './dialoghelper.scss';
|
||||
import '../../assets/css/scrollstyles.scss';
|
||||
import '../../styles/scrollstyles.scss';
|
||||
|
||||
/* eslint-disable indent */
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ import datetime from '../../scripts/datetime';
|
|||
import globalize from '../../scripts/globalize';
|
||||
import loading from '../loading/loading';
|
||||
import skinManager from '../../scripts/themeManager';
|
||||
import { PluginType } from '../../types/plugin.ts';
|
||||
import Events from '../../utils/events.ts';
|
||||
import '../../elements/emby-select/emby-select';
|
||||
import '../../elements/emby-checkbox/emby-checkbox';
|
||||
|
@ -35,7 +36,7 @@ import template from './displaySettings.template.html';
|
|||
|
||||
function loadScreensavers(context, userSettings) {
|
||||
const selectScreensaver = context.querySelector('.selectScreensaver');
|
||||
const options = pluginManager.ofType('screensaver').map(plugin => {
|
||||
const options = pluginManager.ofType(PluginType.Screensaver).map(plugin => {
|
||||
return {
|
||||
name: plugin.name,
|
||||
value: plugin.id
|
||||
|
|
|
@ -6,7 +6,7 @@ import imageLoader from './images/imageLoader';
|
|||
import globalize from '../scripts/globalize';
|
||||
import layoutManager from './layoutManager';
|
||||
import { getParameterByName } from '../utils/url.ts';
|
||||
import '../assets/css/scrollstyles.scss';
|
||||
import '../styles/scrollstyles.scss';
|
||||
import '../elements/emby-itemscontainer/emby-itemscontainer';
|
||||
|
||||
/* eslint-disable indent */
|
||||
|
|
|
@ -13,7 +13,7 @@ import '../../elements/emby-button/paper-icon-button-light';
|
|||
import '../../elements/emby-select/emby-select';
|
||||
import 'material-design-icons-iconfont';
|
||||
import '../formdialog.scss';
|
||||
import '../../assets/css/flexstyles.scss';
|
||||
import '../../styles/flexstyles.scss';
|
||||
import ServerConnections from '../ServerConnections';
|
||||
import template from './filtermenu.template.html';
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ import ServerConnections from './ServerConnections';
|
|||
const playedIndicator = card.querySelector('.playedIndicator');
|
||||
const playedIndicatorHtml = playedIndicator ? playedIndicator.innerHTML : null;
|
||||
const options = {
|
||||
Limit: parseInt(playedIndicatorHtml || '10'),
|
||||
Limit: parseInt(playedIndicatorHtml || '10', 10),
|
||||
Fields: 'PrimaryImageAspectRatio,DateCreated',
|
||||
ParentId: itemId,
|
||||
GroupItems: false
|
||||
|
|
|
@ -17,13 +17,13 @@ import dom from '../../scripts/dom';
|
|||
import './guide.scss';
|
||||
import './programs.scss';
|
||||
import 'material-design-icons-iconfont';
|
||||
import '../../assets/css/scrollstyles.scss';
|
||||
import '../../styles/scrollstyles.scss';
|
||||
import '../../elements/emby-programcell/emby-programcell';
|
||||
import '../../elements/emby-button/emby-button';
|
||||
import '../../elements/emby-button/paper-icon-button-light';
|
||||
import '../../elements/emby-tabs/emby-tabs';
|
||||
import '../../elements/emby-scroller/emby-scroller';
|
||||
import '../../assets/css/flexstyles.scss';
|
||||
import '../../styles/flexstyles.scss';
|
||||
import 'webcomponents.js/webcomponents-lite';
|
||||
import ServerConnections from '../ServerConnections';
|
||||
import template from './tvguide.template.html';
|
||||
|
@ -345,7 +345,9 @@ function Guide(options) {
|
|||
}
|
||||
|
||||
apiClient.getLiveTvPrograms(programQuery).then(function (programsResult) {
|
||||
renderGuide(context, date, channelsResult.Items, programsResult.Items, renderOptions, apiClient, scrollToTimeMs, focusToTimeMs, startTimeOfDayMs, focusProgramOnRender);
|
||||
const guideOptions = { focusProgramOnRender, scrollToTimeMs, focusToTimeMs, startTimeOfDayMs };
|
||||
|
||||
renderGuide(context, date, channelsResult.Items, programsResult.Items, renderOptions, guideOptions, apiClient);
|
||||
|
||||
hideLoading();
|
||||
});
|
||||
|
@ -667,7 +669,7 @@ function Guide(options) {
|
|||
return (channelIndex * 10000000) + (start.getTime() / 60000);
|
||||
}
|
||||
|
||||
function renderGuide(context, date, channels, programs, renderOptions, apiClient, scrollToTimeMs, focusToTimeMs, startTimeOfDayMs, focusProgramOnRender) {
|
||||
function renderGuide(context, date, channels, programs, renderOptions, guideOptions, apiClient) {
|
||||
programs.sort(function (a, b) {
|
||||
return getProgramSortOrder(a, channels) - getProgramSortOrder(b, channels);
|
||||
});
|
||||
|
@ -689,11 +691,11 @@ function Guide(options) {
|
|||
items = {};
|
||||
renderPrograms(context, date, channels, programs, renderOptions);
|
||||
|
||||
if (focusProgramOnRender) {
|
||||
focusProgram(context, itemId, channelRowId, focusToTimeMs, startTimeOfDayMs);
|
||||
if (guideOptions.focusProgramOnRender) {
|
||||
focusProgram(context, itemId, channelRowId, guideOptions.focusToTimeMs, guideOptions.startTimeOfDayMs);
|
||||
}
|
||||
|
||||
scrollProgramGridToTimeMs(context, scrollToTimeMs, startTimeOfDayMs);
|
||||
scrollProgramGridToTimeMs(context, guideOptions.scrollToTimeMs, guideOptions.startTimeOfDayMs);
|
||||
}
|
||||
|
||||
function scrollProgramGridToTimeMs(context, scrollToTimeMs, startTimeOfDayMs) {
|
||||
|
@ -1147,12 +1149,12 @@ function Guide(options) {
|
|||
guideContext.querySelector('.guideDateTabs').addEventListener('tabchange', function (e) {
|
||||
const allTabButtons = e.target.querySelectorAll('.guide-date-tab-button');
|
||||
|
||||
const tabButton = allTabButtons[parseInt(e.detail.selectedTabIndex)];
|
||||
const tabButton = allTabButtons[parseInt(e.detail.selectedTabIndex, 10)];
|
||||
if (tabButton) {
|
||||
const previousButton = e.detail.previousIndex == null ? null : allTabButtons[parseInt(e.detail.previousIndex)];
|
||||
const previousButton = e.detail.previousIndex == null ? null : allTabButtons[parseInt(e.detail.previousIndex, 10)];
|
||||
|
||||
const date = new Date();
|
||||
date.setTime(parseInt(tabButton.getAttribute('data-date')));
|
||||
date.setTime(parseInt(tabButton.getAttribute('data-date'), 10));
|
||||
|
||||
const scrollWidth = programGrid.scrollWidth;
|
||||
let scrollToTimeMs;
|
||||
|
@ -1164,7 +1166,7 @@ function Guide(options) {
|
|||
|
||||
if (previousButton) {
|
||||
const previousDate = new Date();
|
||||
previousDate.setTime(parseInt(previousButton.getAttribute('data-date')));
|
||||
previousDate.setTime(parseInt(previousButton.getAttribute('data-date'), 10));
|
||||
|
||||
scrollToTimeMs += (previousDate.getHours() * 60 * 60 * 1000);
|
||||
scrollToTimeMs += (previousDate.getMinutes() * 60 * 1000);
|
||||
|
|
|
@ -96,7 +96,7 @@ import template from './imageeditor.template.html';
|
|||
return apiClient.getScaledImageUrl(item.Id || item.ItemId, options);
|
||||
}
|
||||
|
||||
function getCardHtml(image, index, numImages, apiClient, imageProviders, imageSize, tagName, enableFooterButtons) {
|
||||
function getCardHtml(image, apiClient, options) {
|
||||
// TODO move card creation code to Card component
|
||||
|
||||
let html = '';
|
||||
|
@ -106,7 +106,7 @@ import template from './imageeditor.template.html';
|
|||
|
||||
cssClass += ' backdropCard backdropCard-scalable';
|
||||
|
||||
if (tagName === 'button') {
|
||||
if (options.tagName === 'button') {
|
||||
cssClass += ' btnImageCard';
|
||||
|
||||
if (layoutManager.tv) {
|
||||
|
@ -122,7 +122,7 @@ import template from './imageeditor.template.html';
|
|||
html += '<div class="' + cssClass + '"';
|
||||
}
|
||||
|
||||
html += ' data-id="' + currentItem.Id + '" data-serverid="' + apiClient.serverId() + '" data-index="' + index + '" data-numimages="' + numImages + '" data-imagetype="' + image.ImageType + '" data-providers="' + imageProviders.length + '"';
|
||||
html += ' data-id="' + currentItem.Id + '" data-serverid="' + apiClient.serverId() + '" data-index="' + options.index + '" data-numimages="' + options.numImages + '" data-imagetype="' + image.ImageType + '" data-providers="' + options.imageProviders.length + '"';
|
||||
|
||||
html += '>';
|
||||
|
||||
|
@ -132,7 +132,7 @@ import template from './imageeditor.template.html';
|
|||
|
||||
html += '<div class="cardContent">';
|
||||
|
||||
const imageUrl = getImageUrl(currentItem, apiClient, image.ImageType, image.ImageIndex, { maxWidth: imageSize });
|
||||
const imageUrl = getImageUrl(currentItem, apiClient, image.ImageType, image.ImageIndex, { maxWidth: options.imageSize });
|
||||
|
||||
html += '<div class="cardImageContainer" style="background-image:url(\'' + imageUrl + '\');background-position:center center;background-size:contain;"></div>';
|
||||
|
||||
|
@ -151,23 +151,23 @@ import template from './imageeditor.template.html';
|
|||
}
|
||||
html += '</div>';
|
||||
|
||||
if (enableFooterButtons) {
|
||||
if (options.enableFooterButtons) {
|
||||
html += '<div class="cardText cardTextCentered">';
|
||||
|
||||
if (image.ImageType === 'Backdrop') {
|
||||
if (index > 0) {
|
||||
if (options.index > 0) {
|
||||
html += '<button type="button" is="paper-icon-button-light" class="btnMoveImage autoSize" data-imagetype="' + image.ImageType + '" data-index="' + image.ImageIndex + '" data-newindex="' + (image.ImageIndex - 1) + '" title="' + globalize.translate('MoveLeft') + '"><span class="material-icons chevron_left"></span></button>';
|
||||
} else {
|
||||
html += '<button type="button" is="paper-icon-button-light" class="autoSize" disabled title="' + globalize.translate('MoveLeft') + '"><span class="material-icons chevron_left" aria-hidden="true"></span></button>';
|
||||
}
|
||||
|
||||
if (index < numImages - 1) {
|
||||
if (options.index < options.numImages - 1) {
|
||||
html += '<button type="button" is="paper-icon-button-light" class="btnMoveImage autoSize" data-imagetype="' + image.ImageType + '" data-index="' + image.ImageIndex + '" data-newindex="' + (image.ImageIndex + 1) + '" title="' + globalize.translate('MoveRight') + '"><span class="material-icons chevron_right" aria-hidden="true"></span></button>';
|
||||
} else {
|
||||
html += '<button type="button" is="paper-icon-button-light" class="autoSize" disabled title="' + globalize.translate('MoveRight') + '"><span class="material-icons chevron_right" aria-hidden="true"></span></button>';
|
||||
}
|
||||
} else {
|
||||
if (imageProviders.length) {
|
||||
if (options.imageProviders.length) {
|
||||
html += '<button type="button" is="paper-icon-button-light" data-imagetype="' + image.ImageType + '" class="btnSearchImages autoSize" title="' + globalize.translate('Search') + '"><span class="material-icons search" aria-hidden="true"></span></button>';
|
||||
}
|
||||
}
|
||||
|
@ -178,7 +178,7 @@ import template from './imageeditor.template.html';
|
|||
|
||||
html += '</div>';
|
||||
html += '</div>';
|
||||
html += '</' + tagName + '>';
|
||||
html += '</' + options.tagName + '>';
|
||||
|
||||
return html;
|
||||
}
|
||||
|
@ -226,7 +226,8 @@ import template from './imageeditor.template.html';
|
|||
|
||||
for (let i = 0, length = images.length; i < length; i++) {
|
||||
const image = images[i];
|
||||
html += getCardHtml(image, i, length, apiClient, imageProviders, imageSize, tagName, enableFooterButtons);
|
||||
const options = { index: i, numImages: length, imageProviders, imageSize, tagName, enableFooterButtons };
|
||||
html += getCardHtml(image, apiClient, options);
|
||||
}
|
||||
|
||||
elem.innerHTML = html;
|
||||
|
@ -277,9 +278,9 @@ import template from './imageeditor.template.html';
|
|||
const apiClient = ServerConnections.getApiClient(serverId);
|
||||
|
||||
const type = imageCard.getAttribute('data-imagetype');
|
||||
const index = parseInt(imageCard.getAttribute('data-index'));
|
||||
const providerCount = parseInt(imageCard.getAttribute('data-providers'));
|
||||
const numImages = parseInt(imageCard.getAttribute('data-numimages'));
|
||||
const index = parseInt(imageCard.getAttribute('data-index'), 10);
|
||||
const providerCount = parseInt(imageCard.getAttribute('data-providers'), 10);
|
||||
const numImages = parseInt(imageCard.getAttribute('data-numimages'), 10);
|
||||
|
||||
import('../actionSheet/actionSheet').then(({default: actionSheet}) => {
|
||||
const commands = [];
|
||||
|
@ -384,7 +385,7 @@ import template from './imageeditor.template.html';
|
|||
addListeners(context, 'btnDeleteImage', 'click', function () {
|
||||
const type = this.getAttribute('data-imagetype');
|
||||
let index = this.getAttribute('data-index');
|
||||
index = index === 'null' ? null : parseInt(index);
|
||||
index = index === 'null' ? null : parseInt(index, 10);
|
||||
const apiClient = ServerConnections.getApiClient(currentItem.ServerId);
|
||||
deleteImage(context, currentItem.Id, type, index, apiClient, true);
|
||||
});
|
||||
|
|
|
@ -20,7 +20,7 @@ import '../../elements/emby-button/emby-button';
|
|||
import '../../elements/emby-button/paper-icon-button-light';
|
||||
import '../formdialog.scss';
|
||||
import 'material-design-icons-iconfont';
|
||||
import '../../assets/css/flexstyles.scss';
|
||||
import '../../styles/flexstyles.scss';
|
||||
import ServerConnections from '../ServerConnections';
|
||||
import template from './itemMediaInfo.template.html';
|
||||
|
||||
|
@ -138,7 +138,7 @@ const attributeDelimiterHtml = layoutManager.tv ? '' : '<span class="hide">: </s
|
|||
attributes.push(createAttribute(globalize.translate('MediaInfoChannels'), `${stream.Channels} ch`));
|
||||
}
|
||||
if (stream.BitRate) {
|
||||
attributes.push(createAttribute(globalize.translate('MediaInfoBitrate'), `${parseInt(stream.BitRate / 1000)} kbps`));
|
||||
attributes.push(createAttribute(globalize.translate('MediaInfoBitrate'), `${parseInt(stream.BitRate / 1000, 10)} kbps`));
|
||||
}
|
||||
if (stream.SampleRate) {
|
||||
attributes.push(createAttribute(globalize.translate('MediaInfoSampleRate'), `${stream.SampleRate} Hz`));
|
||||
|
|
|
@ -52,7 +52,7 @@ import datetime from '../../scripts/datetime';
|
|||
|
||||
if (value) {
|
||||
if (identifyField[i].type === 'number') {
|
||||
value = parseInt(value);
|
||||
value = parseInt(value, 10);
|
||||
}
|
||||
|
||||
lookupInfo[identifyField[i].getAttribute('data-lookup')] = value;
|
||||
|
@ -123,7 +123,7 @@ import datetime from '../../scripts/datetime';
|
|||
elem.innerHTML = html;
|
||||
|
||||
function onSearchImageClick() {
|
||||
const index = parseInt(this.getAttribute('data-index'));
|
||||
const index = parseInt(this.getAttribute('data-index'), 10);
|
||||
|
||||
const currentResult = results[index];
|
||||
|
||||
|
|
|
@ -531,7 +531,7 @@ import template from './libraryoptionseditor.template.html';
|
|||
PreferredMetadataLanguage: parent.querySelector('#selectLanguage').value,
|
||||
MetadataCountryCode: parent.querySelector('#selectCountry').value,
|
||||
SeasonZeroDisplayName: parent.querySelector('#txtSeasonZeroName').value,
|
||||
AutomaticRefreshIntervalDays: parseInt(parent.querySelector('#selectAutoRefreshInterval').value),
|
||||
AutomaticRefreshIntervalDays: parseInt(parent.querySelector('#selectAutoRefreshInterval').value, 10),
|
||||
EnableEmbeddedTitles: parent.querySelector('#chkEnableEmbeddedTitles').checked,
|
||||
EnableEmbeddedExtrasTitles: parent.querySelector('#chkEnableEmbeddedExtrasTitles').checked,
|
||||
EnableEmbeddedEpisodeInfos: parent.querySelector('#chkEnableEmbeddedEpisodeInfos').checked,
|
||||
|
|
|
@ -19,7 +19,7 @@ import '../../elements/emby-select/emby-select';
|
|||
import '../../elements/emby-toggle/emby-toggle';
|
||||
import '../listview/listview.scss';
|
||||
import '../formdialog.scss';
|
||||
import '../../assets/css/flexstyles.scss';
|
||||
import '../../styles/flexstyles.scss';
|
||||
import './style.scss';
|
||||
import toast from '../toast/toast';
|
||||
import alert from '../alert';
|
||||
|
@ -168,7 +168,7 @@ import template from './mediaLibraryCreator.template.html';
|
|||
|
||||
function onRemoveClick(e) {
|
||||
const button = dom.parentWithClass(e.target, 'btnRemovePath');
|
||||
const index = parseInt(button.getAttribute('data-index'));
|
||||
const index = parseInt(button.getAttribute('data-index'), 10);
|
||||
const location = pathInfos[index].Path;
|
||||
const locationLower = location.toLowerCase();
|
||||
pathInfos = pathInfos.filter(p => {
|
||||
|
|
|
@ -17,7 +17,7 @@ import '../listview/listview.scss';
|
|||
import '../../elements/emby-button/paper-icon-button-light';
|
||||
import '../formdialog.scss';
|
||||
import '../../elements/emby-toggle/emby-toggle';
|
||||
import '../../assets/css/flexstyles.scss';
|
||||
import '../../styles/flexstyles.scss';
|
||||
import './style.scss';
|
||||
import toast from '../toast/toast';
|
||||
import confirm from '../confirm/confirm';
|
||||
|
@ -93,7 +93,7 @@ import template from './mediaLibraryEditor.template.html';
|
|||
const listItem = dom.parentWithClass(e.target, 'listItem');
|
||||
|
||||
if (listItem) {
|
||||
const index = parseInt(listItem.getAttribute('data-index'));
|
||||
const index = parseInt(listItem.getAttribute('data-index'), 10);
|
||||
const pathInfos = (currentOptions.library.LibraryOptions || {}).PathInfos || [];
|
||||
const pathInfo = index == null ? {} : pathInfos[index] || {};
|
||||
const originalPath = pathInfo.Path || (index == null ? null : currentOptions.library.Locations[index]);
|
||||
|
|
|
@ -15,8 +15,8 @@ import '../../elements/emby-textarea/emby-textarea';
|
|||
import '../../elements/emby-button/emby-button';
|
||||
import '../../elements/emby-button/paper-icon-button-light';
|
||||
import '../formdialog.scss';
|
||||
import '../../assets/css/clearbutton.scss';
|
||||
import '../../assets/css/flexstyles.scss';
|
||||
import '../../styles/clearbutton.scss';
|
||||
import '../../styles/flexstyles.scss';
|
||||
import './style.scss';
|
||||
import ServerConnections from '../ServerConnections';
|
||||
import toast from '../toast/toast';
|
||||
|
@ -357,14 +357,14 @@ import template from './metadataEditor.template.html';
|
|||
let index;
|
||||
const btnDeletePerson = dom.parentWithClass(e.target, 'btnDeletePerson');
|
||||
if (btnDeletePerson) {
|
||||
index = parseInt(btnDeletePerson.getAttribute('data-index'));
|
||||
index = parseInt(btnDeletePerson.getAttribute('data-index'), 10);
|
||||
currentItem.People.splice(index, 1);
|
||||
populatePeople(context, currentItem.People);
|
||||
}
|
||||
|
||||
const btnEditPerson = dom.parentWithClass(e.target, 'btnEditPerson');
|
||||
if (btnEditPerson) {
|
||||
index = parseInt(btnEditPerson.getAttribute('data-index'));
|
||||
index = parseInt(btnEditPerson.getAttribute('data-index'), 10);
|
||||
editPerson(context, currentItem.People[index], index);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -114,8 +114,8 @@ import shell from '../../scripts/shell';
|
|||
const itemId = item.Id;
|
||||
|
||||
// Convert to ms
|
||||
const duration = parseInt(item.RunTimeTicks ? (item.RunTimeTicks / 10000) : 0);
|
||||
const currentTime = parseInt(playState.PositionTicks ? (playState.PositionTicks / 10000) : 0);
|
||||
const duration = parseInt(item.RunTimeTicks ? (item.RunTimeTicks / 10000) : 0, 10);
|
||||
const currentTime = parseInt(playState.PositionTicks ? (playState.PositionTicks / 10000) : 0, 10);
|
||||
|
||||
const isPaused = playState.IsPaused || false;
|
||||
const canSeek = playState.CanSeek || false;
|
||||
|
@ -247,7 +247,7 @@ import shell from '../../scripts/shell';
|
|||
navigator.mediaSession.setActionHandler('seekto', function (object) {
|
||||
const item = playbackManager.getPlayerState(currentPlayer).NowPlayingItem;
|
||||
// Convert to ms
|
||||
const duration = parseInt(item.RunTimeTicks ? (item.RunTimeTicks / 10000) : 0);
|
||||
const duration = parseInt(item.RunTimeTicks ? (item.RunTimeTicks / 10000) : 0, 10);
|
||||
const wantedTime = object.seekTime * 1000;
|
||||
playbackManager.seekPercent(wantedTime / duration * 100, currentPlayer);
|
||||
});
|
||||
|
|
|
@ -11,6 +11,7 @@ import { appHost } from '../apphost';
|
|||
import Screenfull from 'screenfull';
|
||||
import ServerConnections from '../ServerConnections';
|
||||
import alert from '../alert';
|
||||
import { PluginType } from '../../types/plugin.ts';
|
||||
import { includesAny } from '../../utils/container.ts';
|
||||
|
||||
const UNLIMITED_ITEMS = -1;
|
||||
|
@ -299,20 +300,20 @@ function getAudioMaxValues(deviceProfile) {
|
|||
}
|
||||
|
||||
let startingPlaySession = new Date().getTime();
|
||||
function getAudioStreamUrl(item, transcodingProfile, directPlayContainers, maxBitrate, apiClient, maxAudioSampleRate, maxAudioBitDepth, maxAudioBitrate, startPosition) {
|
||||
function getAudioStreamUrl(item, transcodingProfile, directPlayContainers, apiClient, startPosition, maxValues) {
|
||||
const url = 'Audio/' + item.Id + '/universal';
|
||||
|
||||
startingPlaySession++;
|
||||
return apiClient.getUrl(url, {
|
||||
UserId: apiClient.getCurrentUserId(),
|
||||
DeviceId: apiClient.deviceId(),
|
||||
MaxStreamingBitrate: maxAudioBitrate || maxBitrate,
|
||||
MaxStreamingBitrate: maxValues.maxAudioBitrate || maxValues.maxBitrate,
|
||||
Container: directPlayContainers,
|
||||
TranscodingContainer: transcodingProfile.Container || null,
|
||||
TranscodingProtocol: transcodingProfile.Protocol || null,
|
||||
AudioCodec: transcodingProfile.AudioCodec,
|
||||
MaxAudioSampleRate: maxAudioSampleRate,
|
||||
MaxAudioBitDepth: maxAudioBitDepth,
|
||||
MaxAudioSampleRate: maxValues.maxAudioSampleRate,
|
||||
MaxAudioBitDepth: maxValues.maxAudioBitDepth,
|
||||
api_key: apiClient.accessToken(),
|
||||
PlaySessionId: startingPlaySession,
|
||||
StartTimeTicks: startPosition || 0,
|
||||
|
@ -344,7 +345,7 @@ function getAudioStreamUrlFromDeviceProfile(item, deviceProfile, maxBitrate, api
|
|||
|
||||
const maxValues = getAudioMaxValues(deviceProfile);
|
||||
|
||||
return getAudioStreamUrl(item, transcodingProfile, directPlayContainers, maxBitrate, apiClient, maxValues.maxAudioSampleRate, maxValues.maxAudioBitDepth, maxValues.maxAudioBitrate, startPosition);
|
||||
return getAudioStreamUrl(item, transcodingProfile, directPlayContainers, apiClient, startPosition, { maxBitrate, ...maxValues });
|
||||
}
|
||||
|
||||
function getStreamUrls(items, deviceProfile, maxBitrate, apiClient, startPosition) {
|
||||
|
@ -377,7 +378,7 @@ function getStreamUrls(items, deviceProfile, maxBitrate, apiClient, startPositio
|
|||
let streamUrl;
|
||||
|
||||
if (item.MediaType === 'Audio' && !itemHelper.isLocalItem(item)) {
|
||||
streamUrl = getAudioStreamUrl(item, audioTranscodingProfile, audioDirectPlayContainers, maxBitrate, apiClient, maxValues.maxAudioSampleRate, maxValues.maxAudioBitDepth, maxValues.maxAudioBitrate, startPosition);
|
||||
streamUrl = getAudioStreamUrl(item, audioTranscodingProfile, audioDirectPlayContainers, apiClient, startPosition, { maxBitrate, ...maxValues });
|
||||
}
|
||||
|
||||
streamUrls.push(streamUrl || '');
|
||||
|
@ -408,27 +409,12 @@ function setStreamUrls(items, deviceProfile, maxBitrate, apiClient, startPositio
|
|||
});
|
||||
}
|
||||
|
||||
function getPlaybackInfo(player,
|
||||
apiClient,
|
||||
item,
|
||||
deviceProfile,
|
||||
maxBitrate,
|
||||
startPosition,
|
||||
isPlayback,
|
||||
mediaSourceId,
|
||||
audioStreamIndex,
|
||||
subtitleStreamIndex,
|
||||
liveStreamId,
|
||||
enableDirectPlay,
|
||||
enableDirectStream,
|
||||
allowVideoStreamCopy,
|
||||
allowAudioStreamCopy,
|
||||
secondarySubtitleStreamIndex) {
|
||||
function getPlaybackInfo(player, apiClient, item, deviceProfile, mediaSourceId, liveStreamId, options) {
|
||||
if (!itemHelper.isLocalItem(item) && item.MediaType === 'Audio' && !player.useServerPlaybackInfoForAudio) {
|
||||
return Promise.resolve({
|
||||
MediaSources: [
|
||||
{
|
||||
StreamUrl: getAudioStreamUrlFromDeviceProfile(item, deviceProfile, maxBitrate, apiClient, startPosition),
|
||||
StreamUrl: getAudioStreamUrlFromDeviceProfile(item, deviceProfile, options.maxBitrate, apiClient, options.startPosition),
|
||||
Id: item.Id,
|
||||
MediaStreams: [],
|
||||
RunTimeTicks: item.RunTimeTicks
|
||||
|
@ -446,10 +432,10 @@ function getPlaybackInfo(player,
|
|||
|
||||
const query = {
|
||||
UserId: apiClient.getCurrentUserId(),
|
||||
StartTimeTicks: startPosition || 0
|
||||
StartTimeTicks: options.startPosition || 0
|
||||
};
|
||||
|
||||
if (isPlayback) {
|
||||
if (options.isPlayback) {
|
||||
query.IsPlayback = true;
|
||||
query.AutoOpenLiveStream = true;
|
||||
} else {
|
||||
|
@ -457,27 +443,26 @@ function getPlaybackInfo(player,
|
|||
query.AutoOpenLiveStream = false;
|
||||
}
|
||||
|
||||
if (audioStreamIndex != null) {
|
||||
query.AudioStreamIndex = audioStreamIndex;
|
||||
if (options.audioStreamIndex != null) {
|
||||
query.AudioStreamIndex = options.audioStreamIndex;
|
||||
}
|
||||
if (subtitleStreamIndex != null) {
|
||||
query.SubtitleStreamIndex = subtitleStreamIndex;
|
||||
if (options.subtitleStreamIndex != null) {
|
||||
query.SubtitleStreamIndex = options.subtitleStreamIndex;
|
||||
}
|
||||
if (secondarySubtitleStreamIndex != null) {
|
||||
query.SecondarySubtitleStreamIndex = secondarySubtitleStreamIndex;
|
||||
if (options.secondarySubtitleStreamIndex != null) {
|
||||
query.SecondarySubtitleStreamIndex = options.secondarySubtitleStreamIndex;
|
||||
}
|
||||
if (enableDirectPlay != null) {
|
||||
query.EnableDirectPlay = enableDirectPlay;
|
||||
if (options.enableDirectPlay != null) {
|
||||
query.EnableDirectPlay = options.enableDirectPlay;
|
||||
}
|
||||
|
||||
if (enableDirectStream != null) {
|
||||
query.EnableDirectStream = enableDirectStream;
|
||||
if (options.enableDirectStream != null) {
|
||||
query.EnableDirectStream = options.enableDirectStream;
|
||||
}
|
||||
if (allowVideoStreamCopy != null) {
|
||||
query.AllowVideoStreamCopy = allowVideoStreamCopy;
|
||||
if (options.allowVideoStreamCopy != null) {
|
||||
query.AllowVideoStreamCopy = options.allowVideoStreamCopy;
|
||||
}
|
||||
if (allowAudioStreamCopy != null) {
|
||||
query.AllowAudioStreamCopy = allowAudioStreamCopy;
|
||||
if (options.allowAudioStreamCopy != null) {
|
||||
query.AllowAudioStreamCopy = options.allowAudioStreamCopy;
|
||||
}
|
||||
if (mediaSourceId) {
|
||||
query.MediaSourceId = mediaSourceId;
|
||||
|
@ -485,8 +470,8 @@ function getPlaybackInfo(player,
|
|||
if (liveStreamId) {
|
||||
query.LiveStreamId = liveStreamId;
|
||||
}
|
||||
if (maxBitrate) {
|
||||
query.MaxStreamingBitrate = maxBitrate;
|
||||
if (options.maxBitrate) {
|
||||
query.MaxStreamingBitrate = options.maxBitrate;
|
||||
}
|
||||
if (player.enableMediaProbe && !player.enableMediaProbe(item)) {
|
||||
query.EnableMediaProbe = false;
|
||||
|
@ -537,7 +522,7 @@ function getOptimalMediaSource(apiClient, item, versions) {
|
|||
});
|
||||
}
|
||||
|
||||
function getLiveStream(player, apiClient, item, playSessionId, deviceProfile, maxBitrate, startPosition, mediaSource, audioStreamIndex, subtitleStreamIndex) {
|
||||
function getLiveStream(player, apiClient, item, playSessionId, deviceProfile, mediaSource, options) {
|
||||
const postData = {
|
||||
DeviceProfile: deviceProfile,
|
||||
OpenToken: mediaSource.OpenToken
|
||||
|
@ -545,19 +530,19 @@ function getLiveStream(player, apiClient, item, playSessionId, deviceProfile, ma
|
|||
|
||||
const query = {
|
||||
UserId: apiClient.getCurrentUserId(),
|
||||
StartTimeTicks: startPosition || 0,
|
||||
StartTimeTicks: options.startPosition || 0,
|
||||
ItemId: item.Id,
|
||||
PlaySessionId: playSessionId
|
||||
};
|
||||
|
||||
if (maxBitrate) {
|
||||
query.MaxStreamingBitrate = maxBitrate;
|
||||
if (options.maxBitrate) {
|
||||
query.MaxStreamingBitrate = options.maxBitrate;
|
||||
}
|
||||
if (audioStreamIndex != null) {
|
||||
query.AudioStreamIndex = audioStreamIndex;
|
||||
if (options.audioStreamIndex != null) {
|
||||
query.AudioStreamIndex = options.audioStreamIndex;
|
||||
}
|
||||
if (subtitleStreamIndex != null) {
|
||||
query.SubtitleStreamIndex = subtitleStreamIndex;
|
||||
if (options.subtitleStreamIndex != null) {
|
||||
query.SubtitleStreamIndex = options.subtitleStreamIndex;
|
||||
}
|
||||
|
||||
// lastly, enforce player overrides for special situations
|
||||
|
@ -1706,7 +1691,7 @@ class PlaybackManager {
|
|||
|
||||
function changeStream(player, ticks, params) {
|
||||
if (canPlayerSeek(player) && params == null) {
|
||||
player.currentTime(parseInt(ticks / 10000));
|
||||
player.currentTime(parseInt(ticks / 10000, 10));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1730,20 +1715,33 @@ class PlaybackManager {
|
|||
const apiClient = ServerConnections.getApiClient(currentItem.ServerId);
|
||||
|
||||
if (ticks) {
|
||||
ticks = parseInt(ticks);
|
||||
ticks = parseInt(ticks, 10);
|
||||
}
|
||||
|
||||
const maxBitrate = params.MaxStreamingBitrate || self.getMaxStreamingBitrate(player);
|
||||
|
||||
const currentPlayOptions = currentItem.playOptions || getDefaultPlayOptions();
|
||||
|
||||
getPlaybackInfo(player, apiClient, currentItem, deviceProfile, maxBitrate, ticks, true, currentMediaSource.Id, audioStreamIndex, subtitleStreamIndex, liveStreamId, params.EnableDirectPlay, params.EnableDirectStream, params.AllowVideoStreamCopy, params.AllowAudioStreamCopy).then(function (result) {
|
||||
const options = {
|
||||
maxBitrate,
|
||||
startPosition: ticks,
|
||||
isPlayback: true,
|
||||
audioStreamIndex,
|
||||
subtitleStreamIndex,
|
||||
enableDirectPlay: params.EnableDirectPlay,
|
||||
enableDirectStream: params.EnableDirectStream,
|
||||
allowVideoStreamCopy: params.AllowVideoStreamCopy,
|
||||
allowAudioStreamCopy: params.AllowAudioStreamCopy
|
||||
};
|
||||
|
||||
getPlaybackInfo(player, apiClient, currentItem, deviceProfile, currentMediaSource.Id, liveStreamId, options).then(function (result) {
|
||||
if (validatePlaybackInfoResult(self, result)) {
|
||||
currentMediaSource = result.MediaSources[0];
|
||||
|
||||
const streamInfo = createStreamInfo(apiClient, currentItem.MediaType, currentItem, currentMediaSource, ticks, player);
|
||||
streamInfo.fullscreen = currentPlayOptions.fullscreen;
|
||||
streamInfo.lastMediaInfoQuery = lastMediaInfoQuery;
|
||||
streamInfo.resetSubtitleOffset = false;
|
||||
|
||||
if (!streamInfo.url) {
|
||||
showPlaybackInfoErrorMessage(self, 'PlaybackErrorNoCompatibleStream');
|
||||
|
@ -2268,7 +2266,7 @@ class PlaybackManager {
|
|||
|
||||
function runInterceptors(item, playOptions) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
const interceptors = pluginManager.ofType('preplayintercept');
|
||||
const interceptors = pluginManager.ofType(PluginType.PreplayIntercept);
|
||||
|
||||
interceptors.sort(function (a, b) {
|
||||
return (a.order || 0) - (b.order || 0);
|
||||
|
@ -2303,17 +2301,17 @@ class PlaybackManager {
|
|||
}, reject);
|
||||
}
|
||||
|
||||
function sendPlaybackListToPlayer(player, items, deviceProfile, maxBitrate, apiClient, startPositionTicks, mediaSourceId, audioStreamIndex, subtitleStreamIndex, startIndex) {
|
||||
return setStreamUrls(items, deviceProfile, maxBitrate, apiClient, startPositionTicks).then(function () {
|
||||
function sendPlaybackListToPlayer(player, items, deviceProfile, apiClient, mediaSourceId, options) {
|
||||
return setStreamUrls(items, deviceProfile, options.maxBitrate, apiClient, options.startPosition).then(function () {
|
||||
loading.hide();
|
||||
|
||||
return player.play({
|
||||
items: items,
|
||||
startPositionTicks: startPositionTicks || 0,
|
||||
mediaSourceId: mediaSourceId,
|
||||
audioStreamIndex: audioStreamIndex,
|
||||
subtitleStreamIndex: subtitleStreamIndex,
|
||||
startIndex: startIndex
|
||||
items,
|
||||
startPositionTicks: options.startPosition || 0,
|
||||
mediaSourceId,
|
||||
audioStreamIndex: options.audioStreamIndex,
|
||||
subtitleStreamIndex: options.subtitleStreamIndex,
|
||||
startIndex: options.startIndex
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -2474,15 +2472,27 @@ class PlaybackManager {
|
|||
const mediaSourceId = playOptions.mediaSourceId;
|
||||
const audioStreamIndex = playOptions.audioStreamIndex;
|
||||
const subtitleStreamIndex = playOptions.subtitleStreamIndex;
|
||||
const options = {
|
||||
maxBitrate,
|
||||
startPosition,
|
||||
isPlayback: null,
|
||||
audioStreamIndex,
|
||||
subtitleStreamIndex,
|
||||
startIndex: playOptions.startIndex,
|
||||
enableDirectPlay: null,
|
||||
enableDirectStream: null,
|
||||
allowVideoStreamCopy: null,
|
||||
allowAudioStreamCopy: null
|
||||
};
|
||||
|
||||
if (player && !enableLocalPlaylistManagement(player)) {
|
||||
return sendPlaybackListToPlayer(player, playOptions.items, deviceProfile, maxBitrate, apiClient, startPosition, mediaSourceId, audioStreamIndex, subtitleStreamIndex, playOptions.startIndex);
|
||||
return sendPlaybackListToPlayer(player, playOptions.items, deviceProfile, apiClient, mediaSourceId, options);
|
||||
}
|
||||
|
||||
// this reference was only needed by sendPlaybackListToPlayer
|
||||
playOptions.items = null;
|
||||
|
||||
return getPlaybackMediaSource(player, apiClient, deviceProfile, maxBitrate, item, startPosition, mediaSourceId, audioStreamIndex, subtitleStreamIndex).then(async (mediaSource) => {
|
||||
return getPlaybackMediaSource(player, apiClient, deviceProfile, item, mediaSourceId, options).then(async (mediaSource) => {
|
||||
const user = await apiClient.getCurrentUser();
|
||||
autoSetNextTracks(prevSource, mediaSource, user.Configuration.RememberAudioSelections, user.Configuration.RememberSubtitleSelections);
|
||||
|
||||
|
@ -2540,7 +2550,20 @@ class PlaybackManager {
|
|||
const maxBitrate = getSavedMaxStreamingBitrate(ServerConnections.getApiClient(item.ServerId), mediaType);
|
||||
|
||||
return player.getDeviceProfile(item).then(function (deviceProfile) {
|
||||
return getPlaybackMediaSource(player, apiClient, deviceProfile, maxBitrate, item, startPosition, options.mediaSourceId, options.audioStreamIndex, options.subtitleStreamIndex).then(function (mediaSource) {
|
||||
const mediaOptions = {
|
||||
maxBitrate,
|
||||
startPosition,
|
||||
isPlayback: null,
|
||||
audioStreamIndex: options.audioStreamIndex,
|
||||
subtitleStreamIndex: options.subtitleStreamIndex,
|
||||
startIndex: null,
|
||||
enableDirectPlay: null,
|
||||
enableDirectStream: null,
|
||||
allowVideoStreamCopy: null,
|
||||
allowAudioStreamCopy: null
|
||||
};
|
||||
|
||||
return getPlaybackMediaSource(player, apiClient, deviceProfile, item, options.mediaSourceId, mediaOptions).then(function (mediaSource) {
|
||||
return createStreamInfo(apiClient, item.MediaType, item, mediaSource, startPosition, player);
|
||||
});
|
||||
});
|
||||
|
@ -2560,7 +2583,19 @@ class PlaybackManager {
|
|||
const maxBitrate = getSavedMaxStreamingBitrate(ServerConnections.getApiClient(item.ServerId), mediaType);
|
||||
|
||||
return player.getDeviceProfile(item).then(function (deviceProfile) {
|
||||
return getPlaybackInfo(player, apiClient, item, deviceProfile, maxBitrate, startPosition, false, null, null, null, null).then(function (playbackInfoResult) {
|
||||
const mediaOptions = {
|
||||
maxBitrate,
|
||||
startPosition,
|
||||
isPlayback: true,
|
||||
audioStreamIndex: null,
|
||||
subtitleStreamIndex: null,
|
||||
enableDirectPlay: null,
|
||||
enableDirectStream: null,
|
||||
allowVideoStreamCopy: null,
|
||||
allowAudioStreamCopy: null
|
||||
};
|
||||
|
||||
return getPlaybackInfo(player, apiClient, item, deviceProfile, null, null, mediaOptions).then(function (playbackInfoResult) {
|
||||
return playbackInfoResult.MediaSources;
|
||||
});
|
||||
});
|
||||
|
@ -2701,13 +2736,18 @@ class PlaybackManager {
|
|||
return tracks;
|
||||
}
|
||||
|
||||
function getPlaybackMediaSource(player, apiClient, deviceProfile, maxBitrate, item, startPosition, mediaSourceId, audioStreamIndex, subtitleStreamIndex) {
|
||||
return getPlaybackInfo(player, apiClient, item, deviceProfile, maxBitrate, startPosition, true, mediaSourceId, audioStreamIndex, subtitleStreamIndex, null).then(function (playbackInfoResult) {
|
||||
function getPlaybackMediaSource(player, apiClient, deviceProfile, item, mediaSourceId, options) {
|
||||
options.isPlayback = true;
|
||||
|
||||
return getPlaybackInfo(player, apiClient, item, deviceProfile, mediaSourceId, null, options).then(function (playbackInfoResult) {
|
||||
if (validatePlaybackInfoResult(self, playbackInfoResult)) {
|
||||
return getOptimalMediaSource(apiClient, item, playbackInfoResult.MediaSources).then(function (mediaSource) {
|
||||
if (mediaSource) {
|
||||
if (mediaSource.RequiresOpening && !mediaSource.LiveStreamId) {
|
||||
return getLiveStream(player, apiClient, item, playbackInfoResult.PlaySessionId, deviceProfile, maxBitrate, startPosition, mediaSource, null, null).then(function (openLiveStreamResult) {
|
||||
options.audioStreamIndex = null;
|
||||
options.subtitleStreamIndex = null;
|
||||
|
||||
return getLiveStream(player, apiClient, item, playbackInfoResult.PlaySessionId, deviceProfile, mediaSource, options).then(function (openLiveStreamResult) {
|
||||
return supportsDirectPlay(apiClient, item, openLiveStreamResult.MediaSource).then(function (result) {
|
||||
openLiveStreamResult.MediaSource.enableDirectPlay = result;
|
||||
return openLiveStreamResult.MediaSource;
|
||||
|
@ -3387,12 +3427,12 @@ class PlaybackManager {
|
|||
}
|
||||
|
||||
Events.on(pluginManager, 'registered', function (e, plugin) {
|
||||
if (plugin.type === 'mediaplayer') {
|
||||
if (plugin.type === PluginType.MediaPlayer) {
|
||||
initMediaPlayer(plugin);
|
||||
}
|
||||
});
|
||||
|
||||
pluginManager.ofType('mediaplayer').forEach(initMediaPlayer);
|
||||
pluginManager.ofType(PluginType.MediaPlayer).forEach(initMediaPlayer);
|
||||
|
||||
function sendProgressUpdate(player, progressEventName, reportPlaylist) {
|
||||
if (!player) {
|
||||
|
@ -3423,12 +3463,6 @@ class PlaybackManager {
|
|||
|
||||
streamInfo.lastMediaInfoQuery = new Date().getTime();
|
||||
|
||||
const apiClient = ServerConnections.getApiClient(serverId);
|
||||
|
||||
if (!apiClient.isMinServerVersion('3.2.70.7')) {
|
||||
return;
|
||||
}
|
||||
|
||||
ServerConnections.getApiClient(serverId).getLiveStreamMediaInfo(liveStreamId).then(function (info) {
|
||||
mediaSource.MediaStreams = info.MediaStreams;
|
||||
Events.trigger(player, 'mediastreamschange');
|
||||
|
@ -3613,7 +3647,7 @@ class PlaybackManager {
|
|||
|
||||
percent /= 100;
|
||||
ticks *= percent;
|
||||
this.seek(parseInt(ticks), player);
|
||||
this.seek(parseInt(ticks, 10), player);
|
||||
}
|
||||
|
||||
seekMs(ms, player = this._currentPlayer) {
|
||||
|
@ -4000,13 +4034,13 @@ class PlaybackManager {
|
|||
this.setBrightness(cmd.Arguments.Brightness, player);
|
||||
break;
|
||||
case 'SetAudioStreamIndex':
|
||||
this.setAudioStreamIndex(parseInt(cmd.Arguments.Index), player);
|
||||
this.setAudioStreamIndex(parseInt(cmd.Arguments.Index, 10), player);
|
||||
break;
|
||||
case 'SetSubtitleStreamIndex':
|
||||
this.setSubtitleStreamIndex(parseInt(cmd.Arguments.Index), player);
|
||||
this.setSubtitleStreamIndex(parseInt(cmd.Arguments.Index, 10), player);
|
||||
break;
|
||||
case 'SetMaxStreamingBitrate':
|
||||
this.setMaxStreamingBitrate(parseInt(cmd.Arguments.Bitrate), player);
|
||||
this.setMaxStreamingBitrate(parseInt(cmd.Arguments.Bitrate, 10), player);
|
||||
break;
|
||||
case 'ToggleFullscreen':
|
||||
this.toggleFullscreen(player);
|
||||
|
|
|
@ -43,7 +43,7 @@ function showQualityMenu(player, btn) {
|
|||
items: menuItems,
|
||||
positionTo: btn
|
||||
}).then(function (id) {
|
||||
const bitrate = parseInt(id);
|
||||
const bitrate = parseInt(id, 10);
|
||||
if (bitrate !== selectedBitrate) {
|
||||
playbackManager.setMaxStreamingBitrate({
|
||||
enableAutomaticBitrateDetection: bitrate ? false : true,
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
/*eslint prefer-const: "error"*/
|
||||
|
||||
let currentId = 0;
|
||||
function addUniquePlaylistItemId(item) {
|
||||
if (!item.PlaylistItemId) {
|
||||
|
|
|
@ -8,6 +8,8 @@ import { appRouter } from '../components/appRouter';
|
|||
import * as inputManager from '../scripts/inputManager';
|
||||
import toast from '../components/toast/toast';
|
||||
import confirm from '../components/confirm/confirm';
|
||||
import * as dashboard from '../utils/dashboard';
|
||||
import ServerConnections from '../components/ServerConnections';
|
||||
|
||||
// TODO: replace with each plugin version
|
||||
const cacheParam = new Date().getTime();
|
||||
|
@ -86,7 +88,9 @@ class PluginManager {
|
|||
appRouter,
|
||||
inputManager,
|
||||
toast,
|
||||
confirm
|
||||
confirm,
|
||||
dashboard,
|
||||
ServerConnections
|
||||
});
|
||||
} else {
|
||||
console.debug(`Loading plugin (via dynamic import): ${pluginSpec}`);
|
||||
|
|
|
@ -4,7 +4,7 @@ import globalize from '../../scripts/globalize';
|
|||
import layoutManager from '../layoutManager';
|
||||
import loading from '../loading/loading';
|
||||
import scrollHelper from '../../scripts/scrollHelper';
|
||||
import '../../assets/css/scrollstyles.scss';
|
||||
import '../../styles/scrollstyles.scss';
|
||||
import '../../elements/emby-button/emby-button';
|
||||
import '../../elements/emby-collapse/emby-collapse';
|
||||
import '../../elements/emby-input/emby-input';
|
||||
|
@ -12,7 +12,7 @@ import '../../elements/emby-button/paper-icon-button-light';
|
|||
import '../formdialog.scss';
|
||||
import './recordingcreator.scss';
|
||||
import 'material-design-icons-iconfont';
|
||||
import '../../assets/css/flexstyles.scss';
|
||||
import '../../styles/flexstyles.scss';
|
||||
import ServerConnections from '../ServerConnections';
|
||||
import template from './recordingeditor.template.html';
|
||||
|
||||
|
|
|
@ -7,13 +7,11 @@ import recordingHelper from './recordinghelper';
|
|||
import '../../elements/emby-button/emby-button';
|
||||
import '../../elements/emby-button/paper-icon-button-light';
|
||||
import './recordingfields.scss';
|
||||
import '../../assets/css/flexstyles.scss';
|
||||
import '../../styles/flexstyles.scss';
|
||||
import ServerConnections from '../ServerConnections';
|
||||
import toast from '../toast/toast';
|
||||
import template from './recordingfields.template.html';
|
||||
|
||||
/*eslint prefer-const: "error"*/
|
||||
|
||||
function loadData(parent, program) {
|
||||
if (program.IsSeries) {
|
||||
parent.querySelector('.recordSeriesContainer').classList.remove('hide');
|
||||
|
|
|
@ -5,8 +5,6 @@ import toast from '../toast/toast';
|
|||
import confirm from '../confirm/confirm';
|
||||
import dialog from '../dialog/dialog';
|
||||
|
||||
/*eslint prefer-const: "error"*/
|
||||
|
||||
function changeRecordingToSeries(apiClient, timerId, programId, confirmTimerCancellation) {
|
||||
loading.show();
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ import layoutManager from '../layoutManager';
|
|||
import loading from '../loading/loading';
|
||||
import scrollHelper from '../../scripts/scrollHelper';
|
||||
import datetime from '../../scripts/datetime';
|
||||
import '../../assets/css/scrollstyles.scss';
|
||||
import '../../styles/scrollstyles.scss';
|
||||
import '../../elements/emby-button/emby-button';
|
||||
import '../../elements/emby-checkbox/emby-checkbox';
|
||||
import '../../elements/emby-input/emby-input';
|
||||
|
@ -13,12 +13,10 @@ import '../../elements/emby-button/paper-icon-button-light';
|
|||
import '../formdialog.scss';
|
||||
import './recordingcreator.scss';
|
||||
import 'material-design-icons-iconfont';
|
||||
import '../../assets/css/flexstyles.scss';
|
||||
import '../../styles/flexstyles.scss';
|
||||
import ServerConnections from '../ServerConnections';
|
||||
import template from './seriesrecordingeditor.template.html';
|
||||
|
||||
/*eslint prefer-const: "error"*/
|
||||
|
||||
let currentDialog;
|
||||
let recordingUpdated = false;
|
||||
let recordingDeleted = false;
|
||||
|
|
|
@ -13,8 +13,6 @@ import '../formdialog.scss';
|
|||
import ServerConnections from '../ServerConnections';
|
||||
import toast from '../toast/toast';
|
||||
|
||||
/*eslint prefer-const: "error"*/
|
||||
|
||||
function getEditorHtml() {
|
||||
let html = '';
|
||||
|
||||
|
|
|
@ -20,8 +20,6 @@ import ServerConnections from '../ServerConnections';
|
|||
import toast from '../toast/toast';
|
||||
import { appRouter } from '../appRouter';
|
||||
|
||||
/*eslint prefer-const: "error"*/
|
||||
|
||||
let showMuteButton = true;
|
||||
let showVolumeSlider = true;
|
||||
|
||||
|
@ -46,7 +44,7 @@ function showAudioMenu(context, player, button) {
|
|||
items: menuItems,
|
||||
positionTo: button,
|
||||
callback: function (id) {
|
||||
playbackManager.setAudioStreamIndex(parseInt(id), player);
|
||||
playbackManager.setAudioStreamIndex(parseInt(id, 10), player);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
@ -78,7 +76,7 @@ function showSubtitleMenu(context, player, button) {
|
|||
items: menuItems,
|
||||
positionTo: button,
|
||||
callback: function (id) {
|
||||
playbackManager.setSubtitleStreamIndex(parseInt(id), player);
|
||||
playbackManager.setSubtitleStreamIndex(parseInt(id, 10), player);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
@ -7,7 +7,7 @@ import globalize from '../../scripts/globalize';
|
|||
import 'material-design-icons-iconfont';
|
||||
|
||||
import '../../elements/emby-input/emby-input';
|
||||
import '../../assets/css/flexstyles.scss';
|
||||
import '../../styles/flexstyles.scss';
|
||||
import './searchfields.scss';
|
||||
import layoutManager from '../layoutManager';
|
||||
import browser from '../../scripts/browser';
|
||||
|
|
|
@ -150,7 +150,7 @@ import toast from './toast/toast';
|
|||
StartDate: card.getAttribute('data-startdate'),
|
||||
EndDate: card.getAttribute('data-enddate'),
|
||||
UserData: {
|
||||
PlaybackPositionTicks: parseInt(card.getAttribute('data-positionticks') || '0')
|
||||
PlaybackPositionTicks: parseInt(card.getAttribute('data-positionticks') || '0', 10)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -201,7 +201,7 @@ import toast from './toast/toast';
|
|||
ServerId: serverId
|
||||
});
|
||||
} else if (action === 'play' || action === 'resume') {
|
||||
const startPositionTicks = parseInt(card.getAttribute('data-positionticks') || '0');
|
||||
const startPositionTicks = parseInt(card.getAttribute('data-positionticks') || '0', 10);
|
||||
|
||||
if (playbackManager.canPlay(item)) {
|
||||
playbackManager.play({
|
||||
|
|
|
@ -7,7 +7,7 @@ import '../../elements/emby-button/paper-icon-button-light';
|
|||
import 'material-design-icons-iconfont';
|
||||
import '../formdialog.scss';
|
||||
import '../../elements/emby-button/emby-button';
|
||||
import '../../assets/css/flexstyles.scss';
|
||||
import '../../styles/flexstyles.scss';
|
||||
import template from './sortmenu.template.html';
|
||||
|
||||
function onSubmit(e) {
|
||||
|
|
|
@ -14,7 +14,7 @@ import '../formdialog.scss';
|
|||
import 'material-design-icons-iconfont';
|
||||
import './subtitleeditor.scss';
|
||||
import '../../elements/emby-button/emby-button';
|
||||
import '../../assets/css/flexstyles.scss';
|
||||
import '../../styles/flexstyles.scss';
|
||||
import ServerConnections from '../ServerConnections';
|
||||
import toast from '../toast/toast';
|
||||
import confirm from '../confirm/confirm';
|
||||
|
|
|
@ -13,7 +13,7 @@ import '../../elements/emby-select/emby-select';
|
|||
import '../../elements/emby-slider/emby-slider';
|
||||
import '../../elements/emby-input/emby-input';
|
||||
import '../../elements/emby-checkbox/emby-checkbox';
|
||||
import '../../assets/css/flexstyles.scss';
|
||||
import '../../styles/flexstyles.scss';
|
||||
import './subtitlesettings.scss';
|
||||
import ServerConnections from '../ServerConnections';
|
||||
import toast from '../toast/toast';
|
||||
|
|
|
@ -101,14 +101,16 @@
|
|||
|
||||
<div class="selectContainer hide">
|
||||
<select is="emby-select" id="selectTextColor" label="${LabelTextColor}">
|
||||
<option value="#ffffff">${White}</option>
|
||||
<option value="#ffff00">${Yellow}</option>
|
||||
<option value="#008000">${Green}</option>
|
||||
<option value="#00ffff">${Cyan}</option>
|
||||
<option value="#0000ff">${Blue}</option>
|
||||
<option value="#ff00ff">${Magenta}</option>
|
||||
<option value="#ff0000">${Red}</option>
|
||||
<option value="#000000">${Black}</option>
|
||||
<option value="#ffffff">${SubtitleWhite}</option>
|
||||
<option value="#d3d3d3">${SubtitleLightGray}</option>
|
||||
<option value="#808080">${SubtitleGray}</option>
|
||||
<option value="#ffff00">${SubtitleYellow}</option>
|
||||
<option value="#008000">${SubtitleGreen}</option>
|
||||
<option value="#00ffff">${SubtitleCyan}</option>
|
||||
<option value="#0000ff">${SubtitleBlue}</option>
|
||||
<option value="#ff00ff">${SubtitleMagenta}</option>
|
||||
<option value="#ff0000">${SubtitleRed}</option>
|
||||
<option value="#000000">${SubtitleBlack}</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ import '../listview/listview.scss';
|
|||
import '../../elements/emby-button/paper-icon-button-light';
|
||||
import '../../elements/emby-select/emby-select';
|
||||
import '../../elements/emby-button/emby-button';
|
||||
import '../../assets/css/flexstyles.scss';
|
||||
import '../../styles/flexstyles.scss';
|
||||
import './style.scss';
|
||||
import Dashboard from '../../utils/dashboard';
|
||||
import Events from '../../utils/events.ts';
|
||||
|
|
|
@ -8,7 +8,7 @@ import globalize from '../../scripts/globalize';
|
|||
import itemHelper from '../itemHelper';
|
||||
import './upnextdialog.scss';
|
||||
import '../../elements/emby-button/emby-button';
|
||||
import '../../assets/css/flexstyles.scss';
|
||||
import '../../styles/flexstyles.scss';
|
||||
|
||||
/* eslint-disable indent */
|
||||
|
||||
|
|
|
@ -28,9 +28,9 @@
|
|||
|
||||
.upNextDialog-countdownText {
|
||||
font-weight: 500;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.upNextDialog-nextVideoText,
|
||||
.upNextDialog-title {
|
||||
width: 25.5em;
|
||||
white-space: nowrap;
|
||||
|
|
|
@ -12,7 +12,10 @@ const userDataMethods = {
|
|||
markFavorite: markFavorite
|
||||
};
|
||||
|
||||
function getUserDataButtonHtml(method, itemId, serverId, buttonCssClass, iconCssClass, icon, tooltip, style) {
|
||||
function getUserDataButtonHtml(method, itemId, serverId, icon, tooltip, style, classes) {
|
||||
let buttonCssClass = classes.buttonCssClass;
|
||||
let iconCssClass = classes.iconCssClass;
|
||||
|
||||
if (style === 'fab-mini') {
|
||||
style = 'fab';
|
||||
buttonCssClass = buttonCssClass ? (buttonCssClass + ' mini') : 'mini';
|
||||
|
@ -96,7 +99,7 @@ function getIconsHtml(options) {
|
|||
}
|
||||
|
||||
const iconCssClass = options.iconCssClass;
|
||||
|
||||
const classes = { buttonCssClass: btnCssClass, iconCssClass: iconCssClass };
|
||||
const serverId = item.ServerId;
|
||||
|
||||
if (includePlayed !== false) {
|
||||
|
@ -104,18 +107,21 @@ function getIconsHtml(options) {
|
|||
|
||||
if (itemHelper.canMarkPlayed(item)) {
|
||||
if (userData.Played) {
|
||||
html += getUserDataButtonHtml('markPlayed', itemId, serverId, btnCssClass + ' btnUserDataOn', iconCssClass, 'check', tooltipPlayed, style);
|
||||
const buttonCssClass = classes.buttonCssClass + ' btnUserDataOn';
|
||||
html += getUserDataButtonHtml('markPlayed', itemId, serverId, 'check', tooltipPlayed, style, { buttonCssClass, ...classes });
|
||||
} else {
|
||||
html += getUserDataButtonHtml('markPlayed', itemId, serverId, btnCssClass, iconCssClass, 'check', tooltipPlayed, style);
|
||||
html += getUserDataButtonHtml('markPlayed', itemId, serverId, 'check', tooltipPlayed, style, classes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const tooltipFavorite = globalize.translate('Favorite');
|
||||
if (userData.IsFavorite) {
|
||||
html += getUserDataButtonHtml('markFavorite', itemId, serverId, btnCssClass + ' btnUserData btnUserDataOn', iconCssClass, 'favorite', tooltipFavorite, style);
|
||||
const buttonCssClass = classes.buttonCssClass + ' btnUserData btnUserDataOn';
|
||||
html += getUserDataButtonHtml('markFavorite', itemId, serverId, 'favorite', tooltipFavorite, style, { buttonCssClass, ...classes });
|
||||
} else {
|
||||
html += getUserDataButtonHtml('markFavorite', itemId, serverId, btnCssClass + ' btnUserData', iconCssClass, 'favorite', tooltipFavorite, style);
|
||||
classes.buttonCssClass += ' btnUserData';
|
||||
html += getUserDataButtonHtml('markFavorite', itemId, serverId, 'favorite', tooltipFavorite, style, classes);
|
||||
}
|
||||
|
||||
return html;
|
||||
|
|
|
@ -9,7 +9,7 @@ import '../../elements/emby-button/paper-icon-button-light';
|
|||
import '../../elements/emby-select/emby-select';
|
||||
import 'material-design-icons-iconfont';
|
||||
import '../formdialog.scss';
|
||||
import '../../assets/css/flexstyles.scss';
|
||||
import '../../styles/flexstyles.scss';
|
||||
import template from './viewSettings.template.html';
|
||||
|
||||
function onSubmit(e) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue