mirror of
https://github.com/jellyfin/jellyfin-web
synced 2025-03-30 19:56:21 +00:00
Merge pull request #5255 from thornbill/remove-dlna-pages
Remove DLNA configuration pages pages
This commit is contained in:
commit
a3552b2d07
13 changed files with 57 additions and 1851 deletions
|
@ -1,26 +1,15 @@
|
||||||
import { Devices, Analytics, Input, ExpandLess, ExpandMore } from '@mui/icons-material';
|
import { Devices, Analytics, Input } from '@mui/icons-material';
|
||||||
import Collapse from '@mui/material/Collapse';
|
|
||||||
import List from '@mui/material/List';
|
import List from '@mui/material/List';
|
||||||
import ListItem from '@mui/material/ListItem';
|
import ListItem from '@mui/material/ListItem';
|
||||||
import ListItemIcon from '@mui/material/ListItemIcon';
|
import ListItemIcon from '@mui/material/ListItemIcon';
|
||||||
import ListItemText from '@mui/material/ListItemText';
|
import ListItemText from '@mui/material/ListItemText';
|
||||||
import ListSubheader from '@mui/material/ListSubheader';
|
import ListSubheader from '@mui/material/ListSubheader';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { useLocation } from 'react-router-dom';
|
|
||||||
|
|
||||||
import ListItemLink from 'components/ListItemLink';
|
import ListItemLink from 'components/ListItemLink';
|
||||||
import globalize from 'scripts/globalize';
|
import globalize from 'scripts/globalize';
|
||||||
|
|
||||||
const DLNA_PATHS = [
|
|
||||||
'/dashboard/dlna',
|
|
||||||
'/dashboard/dlna/profiles'
|
|
||||||
];
|
|
||||||
|
|
||||||
const DevicesDrawerSection = () => {
|
const DevicesDrawerSection = () => {
|
||||||
const location = useLocation();
|
|
||||||
|
|
||||||
const isDlnaSectionOpen = DLNA_PATHS.includes(location.pathname);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<List
|
<List
|
||||||
aria-labelledby='devices-subheader'
|
aria-labelledby='devices-subheader'
|
||||||
|
@ -47,24 +36,13 @@ const DevicesDrawerSection = () => {
|
||||||
</ListItemLink>
|
</ListItemLink>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
<ListItem disablePadding>
|
<ListItem disablePadding>
|
||||||
<ListItemLink to='/dashboard/dlna' selected={false}>
|
<ListItemLink to='/dashboard/dlna'>
|
||||||
<ListItemIcon>
|
<ListItemIcon>
|
||||||
<Input />
|
<Input />
|
||||||
</ListItemIcon>
|
</ListItemIcon>
|
||||||
<ListItemText primary={'DLNA'} />
|
<ListItemText primary={'DLNA'} />
|
||||||
{isDlnaSectionOpen ? <ExpandLess /> : <ExpandMore />}
|
|
||||||
</ListItemLink>
|
</ListItemLink>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
<Collapse in={isDlnaSectionOpen} timeout='auto' unmountOnExit>
|
|
||||||
<List component='div' disablePadding>
|
|
||||||
<ListItemLink to='/dashboard/dlna' sx={{ pl: 4 }}>
|
|
||||||
<ListItemText inset primary={globalize.translate('Settings')} />
|
|
||||||
</ListItemLink>
|
|
||||||
<ListItemLink to='/dashboard/dlna/profiles' sx={{ pl: 4 }}>
|
|
||||||
<ListItemText inset primary={globalize.translate('TabProfiles')} />
|
|
||||||
</ListItemLink>
|
|
||||||
</List>
|
|
||||||
</Collapse>
|
|
||||||
</List>
|
</List>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -2,6 +2,7 @@ import { AsyncRouteType, type AsyncRoute } from 'components/router/AsyncRoute';
|
||||||
|
|
||||||
export const ASYNC_ADMIN_ROUTES: AsyncRoute[] = [
|
export const ASYNC_ADMIN_ROUTES: AsyncRoute[] = [
|
||||||
{ path: 'activity', type: AsyncRouteType.Dashboard },
|
{ path: 'activity', type: AsyncRouteType.Dashboard },
|
||||||
|
{ path: 'dlna', type: AsyncRouteType.Dashboard },
|
||||||
{ path: 'notifications', type: AsyncRouteType.Dashboard },
|
{ path: 'notifications', type: AsyncRouteType.Dashboard },
|
||||||
{ path: 'users', type: AsyncRouteType.Dashboard },
|
{ path: 'users', type: AsyncRouteType.Dashboard },
|
||||||
{ path: 'users/access', type: AsyncRouteType.Dashboard },
|
{ path: 'users/access', type: AsyncRouteType.Dashboard },
|
||||||
|
|
|
@ -31,24 +31,6 @@ export const LEGACY_ADMIN_ROUTES: LegacyRoute[] = [
|
||||||
controller: 'dashboard/devices/device',
|
controller: 'dashboard/devices/device',
|
||||||
view: 'dashboard/devices/device.html'
|
view: 'dashboard/devices/device.html'
|
||||||
}
|
}
|
||||||
}, {
|
|
||||||
path: 'dlna/profiles/edit',
|
|
||||||
pageProps: {
|
|
||||||
controller: 'dashboard/dlna/profile',
|
|
||||||
view: 'dashboard/dlna/profile.html'
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
path: 'dlna/profiles',
|
|
||||||
pageProps: {
|
|
||||||
controller: 'dashboard/dlna/profiles',
|
|
||||||
view: 'dashboard/dlna/profiles.html'
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
path: 'dlna',
|
|
||||||
pageProps: {
|
|
||||||
controller: 'dashboard/dlna/settings',
|
|
||||||
view: 'dashboard/dlna/settings.html'
|
|
||||||
}
|
|
||||||
}, {
|
}, {
|
||||||
path: 'plugins/add',
|
path: 'plugins/add',
|
||||||
pageProps: {
|
pageProps: {
|
||||||
|
|
|
@ -8,8 +8,8 @@ export const REDIRECTS: Redirect[] = [
|
||||||
{ from: 'dashboardgeneral.html', to: '/dashboard/settings' },
|
{ from: 'dashboardgeneral.html', to: '/dashboard/settings' },
|
||||||
{ from: 'device.html', to: '/dashboard/devices/edit' },
|
{ from: 'device.html', to: '/dashboard/devices/edit' },
|
||||||
{ from: 'devices.html', to: '/dashboard/devices' },
|
{ from: 'devices.html', to: '/dashboard/devices' },
|
||||||
{ from: 'dlnaprofile.html', to: '/dashboard/dlna/profiles/edit' },
|
{ from: 'dlnaprofile.html', to: '/dashboard/dlna' },
|
||||||
{ from: 'dlnaprofiles.html', to: '/dashboard/dlna/profiles' },
|
{ from: 'dlnaprofiles.html', to: '/dashboard/dlna' },
|
||||||
{ from: 'dlnasettings.html', to: '/dashboard/dlna' },
|
{ from: 'dlnasettings.html', to: '/dashboard/dlna' },
|
||||||
{ from: 'edititemmetadata.html', to: '/metadata' },
|
{ from: 'edititemmetadata.html', to: '/metadata' },
|
||||||
{ from: 'encodingsettings.html', to: '/dashboard/playback/transcoding' },
|
{ from: 'encodingsettings.html', to: '/dashboard/playback/transcoding' },
|
||||||
|
|
33
src/apps/dashboard/routes/dlna.tsx
Normal file
33
src/apps/dashboard/routes/dlna.tsx
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
import Alert from '@mui/material/Alert/Alert';
|
||||||
|
import Box from '@mui/material/Box/Box';
|
||||||
|
import Button from '@mui/material/Button/Button';
|
||||||
|
import React from 'react';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
|
||||||
|
import Page from 'components/Page';
|
||||||
|
import globalize from 'scripts/globalize';
|
||||||
|
|
||||||
|
const DlnaPage = () => (
|
||||||
|
<Page
|
||||||
|
id='dlnaSettingsPage'
|
||||||
|
title='DLNA'
|
||||||
|
className='mainAnimatedPage type-interior'
|
||||||
|
>
|
||||||
|
<div className='content-primary'>
|
||||||
|
<h2>DLNA</h2>
|
||||||
|
<Alert severity='info'>
|
||||||
|
<Box sx={{ marginBottom: 2 }}>
|
||||||
|
{globalize.translate('DlnaMovedMessage')}
|
||||||
|
</Box>
|
||||||
|
<Button
|
||||||
|
component={Link}
|
||||||
|
to='/dashboard/plugins/add?name=DLNA&guid=33eba9cd7da14720967fdd7dae7b74a1'
|
||||||
|
>
|
||||||
|
{globalize.translate('GetThePlugin')}
|
||||||
|
</Button>
|
||||||
|
</Alert>
|
||||||
|
</div>
|
||||||
|
</Page>
|
||||||
|
);
|
||||||
|
|
||||||
|
export default DlnaPage;
|
|
@ -1,23 +1,13 @@
|
||||||
|
import Alert from '@mui/material/Alert/Alert';
|
||||||
|
import Box from '@mui/material/Box/Box';
|
||||||
|
import Button from '@mui/material/Button/Button';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
|
||||||
import Page from 'components/Page';
|
import Page from 'components/Page';
|
||||||
import globalize from 'scripts/globalize';
|
import globalize from 'scripts/globalize';
|
||||||
|
|
||||||
const PluginLink = () => (
|
const NotificationsPage = () => (
|
||||||
<div
|
|
||||||
dangerouslySetInnerHTML={{
|
|
||||||
__html: `<a
|
|
||||||
is='emby-linkbutton'
|
|
||||||
class='button-link'
|
|
||||||
href='#/dashboard/plugins/add?name=Webhook&guid=71552a5a5c5c4350a2aeebe451a30173'
|
|
||||||
>
|
|
||||||
${globalize.translate('GetThePlugin')}
|
|
||||||
</a>`
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
|
|
||||||
const Notifications = () => (
|
|
||||||
<Page
|
<Page
|
||||||
id='notificationSettingPage'
|
id='notificationSettingPage'
|
||||||
title={globalize.translate('Notifications')}
|
title={globalize.translate('Notifications')}
|
||||||
|
@ -25,12 +15,20 @@ const Notifications = () => (
|
||||||
>
|
>
|
||||||
<div className='content-primary'>
|
<div className='content-primary'>
|
||||||
<h2>{globalize.translate('Notifications')}</h2>
|
<h2>{globalize.translate('Notifications')}</h2>
|
||||||
<p>
|
|
||||||
|
<Alert severity='info'>
|
||||||
|
<Box sx={{ marginBottom: 2 }}>
|
||||||
{globalize.translate('NotificationsMovedMessage')}
|
{globalize.translate('NotificationsMovedMessage')}
|
||||||
</p>
|
</Box>
|
||||||
<PluginLink />
|
<Button
|
||||||
|
component={Link}
|
||||||
|
to='/dashboard/plugins/add?name=Webhook&guid=71552a5a5c5c4350a2aeebe451a30173'
|
||||||
|
>
|
||||||
|
{globalize.translate('GetThePlugin')}
|
||||||
|
</Button>
|
||||||
|
</Alert>
|
||||||
</div>
|
</div>
|
||||||
</Page>
|
</Page>
|
||||||
);
|
);
|
||||||
|
|
||||||
export default Notifications;
|
export default NotificationsPage;
|
||||||
|
|
|
@ -1,584 +0,0 @@
|
||||||
<div id="dlnaProfilePage" data-role="page" class="page type-interior dlnaPage withTabs">
|
|
||||||
<div data-role="content">
|
|
||||||
<div class="content-primary">
|
|
||||||
<form class="dlnaProfileForm" style="max-width: 650px;">
|
|
||||||
<div class="verticalSection">
|
|
||||||
<div class="sectionTitleContainer flex align-items-center">
|
|
||||||
<h2 class="sectionTitle">${HeaderProfileInformation}</h2>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div data-role="controlgroup" data-type="horizontal" data-mini="true">
|
|
||||||
<a href="#" is="emby-linkbutton" data-role="button" class="radioTabButton" id="radioInfo" data-value="tabInfo">${ButtonInfo}</a>
|
|
||||||
<a href="#" is="emby-linkbutton" data-role="button" class="radioTabButton" id="radioDirectPlay" data-value="tabDirectPlayProfiles">${TabDirectPlay}</a>
|
|
||||||
<a href="#" is="emby-linkbutton" data-role="button" class="radioTabButton" id="radioTranscoding" data-value="tabTranscodingProfiles">${Transcoding}</a>
|
|
||||||
<a href="#" is="emby-linkbutton" data-role="button" class="radioTabButton" id="radioContainers" data-value="tabContainerProfiles">${TabContainers}</a>
|
|
||||||
<a href="#" is="emby-linkbutton" data-role="button" class="radioTabButton" id="radioCodecs" data-value="tabCodecProfiles">${TabCodecs}</a>
|
|
||||||
<a href="#" is="emby-linkbutton" data-role="button" class="radioTabButton" id="radioMediaProfiles" data-value="tabMediaProfiles">${TabResponses}</a>
|
|
||||||
</div>
|
|
||||||
<br />
|
|
||||||
<div class="tabContent tabInfo">
|
|
||||||
<div class="inputContainer">
|
|
||||||
<input is="emby-input" type="text" id="txtName" required="required" label="${LabelName}" />
|
|
||||||
</div>
|
|
||||||
<div class="selectContainer">
|
|
||||||
<select is="emby-select" id="selectUser" label="${LabelUserLibrary}"></select>
|
|
||||||
<div class="fieldDescription">${LabelUserLibraryHelp}</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<h3 class="checkboxListLabel">${LabelSupportedMediaTypes}</h3>
|
|
||||||
<div class="checkboxList paperList checkboxList-paperList">
|
|
||||||
<label>
|
|
||||||
<input is="emby-checkbox" type="checkbox" id="chkAudio" data-value="Audio" class="chkMediaType" />
|
|
||||||
<span>${Audio}</span>
|
|
||||||
</label>
|
|
||||||
<label>
|
|
||||||
<input is="emby-checkbox" type="checkbox" id="chkPhoto" data-value="Photo" class="chkMediaType" />
|
|
||||||
<span>${Photo}</span>
|
|
||||||
</label>
|
|
||||||
<label>
|
|
||||||
<input is="emby-checkbox" type="checkbox" id="chkVideo" data-value="Video" class="chkMediaType" />
|
|
||||||
<span>${Video}</span>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<br />
|
|
||||||
<div class="inputContainer">
|
|
||||||
<input is="emby-input" type="number" id="txtMaxAllowedBitrate" pattern="[0-9]*" min="1" label="${LabelMaxStreamingBitrate}" />
|
|
||||||
<div class="fieldDescription">${LabelMaxStreamingBitrateHelp}</div>
|
|
||||||
</div>
|
|
||||||
<div class="inputContainer">
|
|
||||||
<input is="emby-input" type="number" id="txtMusicStreamingTranscodingBitrate" pattern="[0-9]*" min="1" label="${LabelMusicStreamingTranscodingBitrate}" />
|
|
||||||
<div class="fieldDescription">${LabelMusicStreamingTranscodingBitrateHelp}</div>
|
|
||||||
</div>
|
|
||||||
<div style="display:none;">
|
|
||||||
<label for="chkIgnoreTranscodeByteRangeRequests">${OptionIgnoreTranscodeByteRangeRequests}</label>
|
|
||||||
<input type="checkbox" id="chkIgnoreTranscodeByteRangeRequests" data-mini="true" />
|
|
||||||
<div class="fieldDescription">${OptionIgnoreTranscodeByteRangeRequestsHelp}</div>
|
|
||||||
</div>
|
|
||||||
<div is="emby-collapse" title="${HeaderIdentification}">
|
|
||||||
<div class="collapseContent">
|
|
||||||
<h3>${HeaderIdentificationCriteriaHelp}</h3>
|
|
||||||
<div class="inputContainer">
|
|
||||||
<input is="emby-input" type="text" id="txtIdFriendlyName" label="${LabelFriendlyName}" />
|
|
||||||
<div class="fieldDescription">${LabelIdentificationFieldHelp}</div>
|
|
||||||
</div>
|
|
||||||
<div class="inputContainer">
|
|
||||||
<input is="emby-input" type="text" id="txtIdManufacturer" label="${LabelManufacturer}" />
|
|
||||||
<div class="fieldDescription">${LabelIdentificationFieldHelp}</div>
|
|
||||||
</div>
|
|
||||||
<div class="inputContainer">
|
|
||||||
<input is="emby-input" type="text" id="txtIdManufacturerUrl" label="${LabelManufacturerUrl}" />
|
|
||||||
<div class="fieldDescription">${LabelIdentificationFieldHelp}</div>
|
|
||||||
</div>
|
|
||||||
<div class="inputContainer">
|
|
||||||
<input is="emby-input" type="text" id="txtIdModelName" label="${LabelModelName}" />
|
|
||||||
<div class="fieldDescription">${LabelIdentificationFieldHelp}</div>
|
|
||||||
</div>
|
|
||||||
<div class="inputContainer">
|
|
||||||
<input is="emby-input" type="text" id="txtIdModelNumber" label="${LabelModelNumber}" />
|
|
||||||
<div class="fieldDescription">${LabelIdentificationFieldHelp}</div>
|
|
||||||
</div>
|
|
||||||
<div class="inputContainer">
|
|
||||||
<input is="emby-input" type="text" id="txtIdModelDesription" label="${LabelModelDescription}" />
|
|
||||||
<div class="fieldDescription">${LabelIdentificationFieldHelp}</div>
|
|
||||||
</div>
|
|
||||||
<div class="inputContainer">
|
|
||||||
<input is="emby-input" type="text" id="txtIdModelUrl" label="${LabelModelUrl}" />
|
|
||||||
<div class="fieldDescription">${LabelIdentificationFieldHelp}</div>
|
|
||||||
</div>
|
|
||||||
<div class="inputContainer">
|
|
||||||
<input is="emby-input" type="text" id="txtIdSerialNumber" label="${LabelSerialNumber}" />
|
|
||||||
<div class="fieldDescription">${LabelIdentificationFieldHelp}</div>
|
|
||||||
</div>
|
|
||||||
<div class="inputContainer">
|
|
||||||
<input is="emby-input" type="text" id="txtIdDeviceDescription" label="${LabelDeviceDescription}" />
|
|
||||||
<div class="fieldDescription">${LabelIdentificationFieldHelp}</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<h2 style="vertical-align:middle;display:inline-block;">${HeaderHttpHeaders}</h2>
|
|
||||||
<button is="emby-button" type="button" class="fab btnAddIdentificationHttpHeader submit sectionTitleButton" style="margin-left:1em;" title="${Add}">
|
|
||||||
<span class="material-icons add" aria-hidden="true"></span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div class="httpHeaderIdentificationList"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div is="emby-collapse" title="${Display}">
|
|
||||||
<div class="collapseContent">
|
|
||||||
<br />
|
|
||||||
<div class="checkboxContainer checkboxContainer-withDescription">
|
|
||||||
<label>
|
|
||||||
<input is="emby-checkbox" type="checkbox" id="chkRequiresPlainFolders" />
|
|
||||||
<span>${OptionPlainStorageFolders}</span>
|
|
||||||
</label>
|
|
||||||
<div class="fieldDescription checkboxFieldDescription">${OptionPlainStorageFoldersHelp}</div>
|
|
||||||
</div>
|
|
||||||
<div class="checkboxContainer checkboxContainer-withDescription">
|
|
||||||
<label>
|
|
||||||
<input is="emby-checkbox" type="checkbox" id="chkRequiresPlainVideoItems" />
|
|
||||||
<span>${OptionPlainVideoItems}</span>
|
|
||||||
</label>
|
|
||||||
<div class="fieldDescription checkboxFieldDescription">${OptionPlainVideoItemsHelp}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div is="emby-collapse" title="${HeaderImageSettings}">
|
|
||||||
<div class="collapseContent">
|
|
||||||
<div class="checkboxContainer checkboxContainer-withDescription">
|
|
||||||
<label>
|
|
||||||
<input is="emby-checkbox" type="checkbox" id="chkEnableAlbumArtInDidl" data-mini="true" />
|
|
||||||
<span>${LabelEmbedAlbumArtDidl}</span>
|
|
||||||
</label>
|
|
||||||
<div class="fieldDescription checkboxFieldDescription">${LabelEmbedAlbumArtDidlHelp}</div>
|
|
||||||
</div>
|
|
||||||
<div class="checkboxContainer checkboxContainer-withDescription">
|
|
||||||
<label>
|
|
||||||
<input is="emby-checkbox" type="checkbox" id="chkEnableSingleImageLimit" data-mini="true" />
|
|
||||||
<span>${LabelEnableSingleImageInDidlLimit}</span>
|
|
||||||
</label>
|
|
||||||
<div class="fieldDescription checkboxFieldDescription">${LabelEnableSingleImageInDidlLimitHelp}</div>
|
|
||||||
</div>
|
|
||||||
<div class="inputContainer">
|
|
||||||
<input type="text" is="emby-input" id="txtAlbumArtPn" label="${LabelAlbumArtPN}" />
|
|
||||||
<div class="fieldDescription">${LabelAlbumArtHelp}</div>
|
|
||||||
</div>
|
|
||||||
<div class="inputContainer">
|
|
||||||
<input type="number" is="emby-input" id="txtAlbumArtMaxWidth" pattern="[0-9]*" min="1" label="${LabelAlbumArtMaxWidth}" />
|
|
||||||
<div class="fieldDescription">${LabelAlbumArtMaxResHelp}</div>
|
|
||||||
</div>
|
|
||||||
<div class="inputContainer">
|
|
||||||
<input type="number" is="emby-input" id="txtAlbumArtMaxHeight" pattern="[0-9]*" min="1" label="${LabelAlbumArtMaxHeight}" />
|
|
||||||
<div class="fieldDescription">${LabelAlbumArtMaxResHelp}</div>
|
|
||||||
</div>
|
|
||||||
<div class="inputContainer">
|
|
||||||
<input type="number" is="emby-input" id="txtIconMaxWidth" pattern="[0-9]*" min="1" label="${LabelIconMaxWidth}" />
|
|
||||||
<div class="fieldDescription">${LabelIconMaxResHelp}</div>
|
|
||||||
</div>
|
|
||||||
<div class="inputContainer">
|
|
||||||
<input type="number" is="emby-input" id="txtIconMaxHeight" pattern="[0-9]*" min="1" label="${LabelIconMaxHeight}" />
|
|
||||||
<div class="fieldDescription">${LabelIconMaxResHelp}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div is="emby-collapse" title="${HeaderServerSettings}">
|
|
||||||
<div class="collapseContent">
|
|
||||||
<p>${HeaderProfileServerSettingsHelp}</p>
|
|
||||||
<div class="inputContainer">
|
|
||||||
<input is="emby-input" type="text" id="txtInfoFriendlyName" label="${LabelFriendlyName}" />
|
|
||||||
</div>
|
|
||||||
<div class="inputContainer">
|
|
||||||
<input is="emby-input" type="text" id="txtInfoManufacturer" label="${LabelManufacturer}" />
|
|
||||||
</div>
|
|
||||||
<div class="inputContainer">
|
|
||||||
<input is="emby-input" type="text" id="txtInfoManufacturerUrl" label="${LabelManufacturerUrl}" />
|
|
||||||
</div>
|
|
||||||
<div class="inputContainer">
|
|
||||||
<input is="emby-input" type="text" id="txtInfoModelName" label="${LabelModelName}" />
|
|
||||||
</div>
|
|
||||||
<div class="inputContainer">
|
|
||||||
<input is="emby-input" type="text" id="txtInfoModelNumber" label="${LabelModelNumber}" />
|
|
||||||
</div>
|
|
||||||
<div class="inputContainer">
|
|
||||||
<input is="emby-input" type="text" id="txtInfoModelDesription" label="${LabelModelDescription}" />
|
|
||||||
</div>
|
|
||||||
<div class="inputContainer">
|
|
||||||
<input is="emby-input" type="text" id="txtInfoModelUrl" label="${LabelModelUrl}" />
|
|
||||||
</div>
|
|
||||||
<div class="inputContainer">
|
|
||||||
<input is="emby-input" type="text" id="txtInfoSerialNumber" label="${LabelSerialNumber}" />
|
|
||||||
</div>
|
|
||||||
<div class="inputContainer">
|
|
||||||
<input is="emby-input" type="text" id="txtProtocolInfo" label="${LabelProtocolInfo}" />
|
|
||||||
<div class="fieldDescription">${LabelProtocolInfoHelp}</div>
|
|
||||||
</div>
|
|
||||||
<div class="inputContainer">
|
|
||||||
<input is="emby-input" type="text" id="txtXDlnaCap" label="${LabelXDlnaCap}" />
|
|
||||||
<div class="fieldDescription">${LabelXDlnaCapHelp}</div>
|
|
||||||
</div>
|
|
||||||
<div class="inputContainer">
|
|
||||||
<input is="emby-input" type="text" id="txtXDlnaDoc" label="${LabelXDlnaDoc}" />
|
|
||||||
<div class="fieldDescription">${LabelXDlnaDocHelp}</div>
|
|
||||||
</div>
|
|
||||||
<div class="inputContainer">
|
|
||||||
<input is="emby-input" type="text" id="txtSonyAggregationFlags" label="${LabelSonyAggregationFlags}" />
|
|
||||||
<div class="fieldDescription">${LabelSonyAggregationFlagsHelp}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div is="emby-collapse" title="${HeaderSubtitleProfiles}">
|
|
||||||
<div class="collapseContent">
|
|
||||||
<p>${HeaderSubtitleProfilesHelp}</p>
|
|
||||||
<button is="emby-button" type="button" class="raised submit block btnAddSubtitleProfile">
|
|
||||||
<span>${Add}</span>
|
|
||||||
</button>
|
|
||||||
<div class="subtitleProfileList"></div>
|
|
||||||
<br />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div is="emby-collapse" title="${HeaderXmlSettings}">
|
|
||||||
<div class="collapseContent">
|
|
||||||
<div>
|
|
||||||
<h2 style="vertical-align:middle;display:inline-block;">${HeaderXmlDocumentAttributes}</h2>
|
|
||||||
<button is="emby-button" type="button" class="fab btnAddXmlDocumentAttribute submit sectionTitleButton" style="margin-left:1em;" title="${Add}">
|
|
||||||
<span class="material-icons add" aria-hidden="true"></span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div class="xmlDocumentAttributeList"></div>
|
|
||||||
<div class="fieldDescription">${XmlDocumentAttributeListHelp}</div>
|
|
||||||
<br />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="tabContent tabDirectPlayProfiles">
|
|
||||||
<p>${HeaderDirectPlayProfileHelp}</p>
|
|
||||||
<button is="emby-button" class="raised submit block btnAddDirectPlayProfile" type="button" data-mini="true" data-icon="plus">${New}</button>
|
|
||||||
<br />
|
|
||||||
<div class="directPlayProfiles"></div>
|
|
||||||
</div>
|
|
||||||
<div class="tabContent tabTranscodingProfiles">
|
|
||||||
<p>${HeaderTranscodingProfileHelp}</p>
|
|
||||||
<button is="emby-button" class="raised submit block btnAddTranscodingProfile" type="button" data-mini="true" data-icon="plus">${New}</button>
|
|
||||||
<br />
|
|
||||||
<div class="transcodingProfiles"></div>
|
|
||||||
</div>
|
|
||||||
<div class="tabContent tabContainerProfiles">
|
|
||||||
<p>${HeaderContainerProfileHelp}</p>
|
|
||||||
<button is="emby-button" class="raised submit block btnAddContainerProfile" type="button" data-mini="true" data-icon="plus">${New}</button>
|
|
||||||
<br />
|
|
||||||
<div class="containerProfiles"></div>
|
|
||||||
</div>
|
|
||||||
<div class="tabContent tabCodecProfiles">
|
|
||||||
<p>${HeaderCodecProfileHelp}</p>
|
|
||||||
<button is="emby-button" class="raised submit block btnAddCodecProfile" type="button" data-icon="plus">${New}</button>
|
|
||||||
<br />
|
|
||||||
<div class="codecProfiles"></div>
|
|
||||||
</div>
|
|
||||||
<div class="tabContent tabMediaProfiles">
|
|
||||||
<p>${HeaderResponseProfileHelp}</p>
|
|
||||||
<button is="emby-button" class="raised submit block btnAddResponseProfile" type="button" data-mini="true" data-icon="plus">${New}</button>
|
|
||||||
<br />
|
|
||||||
<div class="mediaProfiles"></div>
|
|
||||||
</div>
|
|
||||||
<br />
|
|
||||||
<div>
|
|
||||||
<button is="emby-button" type="submit" class="raised button-submit block">
|
|
||||||
<span>${Save}</span>
|
|
||||||
</button>
|
|
||||||
<button is="emby-button" type="button" class="button-cancel raised block" onclick="Dashboard.navigate('dashboard/dlna/profiles');">
|
|
||||||
<span>${ButtonCancel}</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div data-role="popup" id="popupEditDirectPlayProfile" class="dialog dialog-fixedSize dialog-medium hide" style="position: fixed; top: 10%;">
|
|
||||||
<form class="editDirectPlayProfileForm" style="padding:1em;">
|
|
||||||
<div class="ui-bar-a">
|
|
||||||
<h3 class="sectionTitle">${HeaderDirectPlayProfile}</h3>
|
|
||||||
</div>
|
|
||||||
<div data-role="content">
|
|
||||||
<div class="selectContainer">
|
|
||||||
<select id="selectDirectPlayProfileType" name="selectDirectPlayProfileType" is="emby-select" label="${LabelType}">
|
|
||||||
<option value="Audio">${Audio}</option>
|
|
||||||
<option value="Photo">${Photo}</option>
|
|
||||||
<option value="Video">${Video}</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div class="inputContainer">
|
|
||||||
<input is="emby-input" type="text" id="txtDirectPlayContainer" label="${LabelProfileContainer}" />
|
|
||||||
<div class="fieldDescription">${LabelProfileContainersHelp}</div>
|
|
||||||
</div>
|
|
||||||
<div id="fldDirectPlayVideoCodec" style="margin: 1em 0;">
|
|
||||||
<div class="inputContainer">
|
|
||||||
<input is="emby-input" type="text" id="txtDirectPlayVideoCodec" label="${LabelProfileVideoCodecs}" />
|
|
||||||
<div class="fieldDescription">${LabelProfileCodecsHelp}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="fldDirectPlayAudioCodec" style="margin: 1em 0 2em;">
|
|
||||||
<div class="inputContainer">
|
|
||||||
<input is="emby-input" type="text" id="txtDirectPlayAudioCodec" label="${LabelProfileAudioCodecs}" />
|
|
||||||
<div class="fieldDescription">${LabelProfileCodecsHelp}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<p>
|
|
||||||
<button is="emby-button" type="submit" class="raised button-submit block" data-icon="check" data-mini="true">
|
|
||||||
<span>${ButtonOk}</span>
|
|
||||||
</button>
|
|
||||||
<button is="emby-button" type="button" class="raised button-cancel block" data-icon="delete" onclick="$(this).parents('.dialog').addClass('hide');" data-mini="true">
|
|
||||||
<span>${ButtonCancel}</span>
|
|
||||||
</button>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
<div data-role="popup" id="transcodingProfilePopup" class="dialog dialog-fixedSize dialog-medium hide" style="position: fixed; top: 10%;">
|
|
||||||
<form class="transcodingProfileForm" style="padding:1em;">
|
|
||||||
<div class="ui-bar-a">
|
|
||||||
<h3 class="sectionTitle">${HeaderTranscodingProfile}</h3>
|
|
||||||
</div>
|
|
||||||
<div data-role="content">
|
|
||||||
<div data-role="controlgroup" data-type="horizontal" data-mini="true">
|
|
||||||
<input type="radio" name="radioTranscodingTab" class="radioTabButton" id="radioTranscodingBasics" value="tabTranscodingBasics">
|
|
||||||
<label for="radioTranscodingBasics">${ButtonInfo}</label>
|
|
||||||
<input type="radio" name="radioTranscodingTab" class="radioTabButton" id="radioTranscodingAdvanced" value="tabTranscodingAdvanced">
|
|
||||||
<label for="radioTranscodingAdvanced">${TabAdvanced}</label>
|
|
||||||
</div>
|
|
||||||
<br />
|
|
||||||
<div class="tabContent tabTranscodingBasics" style="display: none;">
|
|
||||||
<div class="selectContainer">
|
|
||||||
<select id="selectTranscodingProfileType" name="selectTranscodingProfileType" is="emby-select" label="${LabelType}">
|
|
||||||
<option value="Audio">${Audio}</option>
|
|
||||||
<option value="Photo">${Photo}</option>
|
|
||||||
<option value="Video">${Video}</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div id="fldTranscodingProtocol" style="margin: 1em 0;">
|
|
||||||
<div class="selectContainer">
|
|
||||||
<select id="selectTranscodingProtocol" name="selectTranscodingProtocol" is="emby-select" label="${LabelProtocol}">
|
|
||||||
<option value="Http">${OptionProtocolHttp}</option>
|
|
||||||
<option value="Hls">${OptionProtocolHls}</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="inputContainer">
|
|
||||||
<input is="emby-input" type="text" id="txtTranscodingContainer" label="${LabelProfileContainer}"; required="required" />
|
|
||||||
</div>
|
|
||||||
<div id="fldTranscodingVideoCodec" style="margin: 1em 0;">
|
|
||||||
<div class="inputContainer">
|
|
||||||
<input is="emby-input" type="text" id="txtTranscodingVideoCodec" label="${LabelVideoCodec}" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="fldTranscodingAudioCodec" style="margin: 1em 0;">
|
|
||||||
<div class="inputContainer">
|
|
||||||
<input is="emby-input" type="text" id="txtTranscodingAudioCodec" label="${LabelAudioCodec}" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="tabContent tabTranscodingAdvanced" style="display: none;">
|
|
||||||
<div id="fldEnableMpegtsM2TsMode" style="margin: 1em 0;">
|
|
||||||
<div class="checkboxContainer checkboxContainer-withDescription">
|
|
||||||
<label>
|
|
||||||
<input is="emby-checkbox" type="checkbox" id="chkEnableMpegtsM2TsMode" />
|
|
||||||
<span>${OptionEnableM2tsMode}</span>
|
|
||||||
</label>
|
|
||||||
<div class="fieldDescription checkboxFieldDescription">${OptionEnableM2tsModeHelp}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="fldEstimateContentLength" style="margin: 1em 0;">
|
|
||||||
<div class="checkboxContainer checkboxContainer-withDescription">
|
|
||||||
<label>
|
|
||||||
<input is="emby-checkbox" type="checkbox" id="chkEstimateContentLength" />
|
|
||||||
<span>${OptionEstimateContentLength}</span>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="fldReportByteRangeRequests" style="margin: 1em 0;">
|
|
||||||
<div class="checkboxContainer checkboxContainer-withDescription">
|
|
||||||
<label>
|
|
||||||
<input is="emby-checkbox" type="checkbox" id="chkReportByteRangeRequests" />
|
|
||||||
<span>${OptionReportByteRangeSeekingWhenTranscoding}</span>
|
|
||||||
</label>
|
|
||||||
<div class="fieldDescription checkboxFieldDescription">${OptionReportByteRangeSeekingWhenTranscodingHelp}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<p>
|
|
||||||
<button is="emby-button" type="submit" class="raised button-submit block" data-icon="check" data-mini="true">
|
|
||||||
<span>${ButtonOk}</span>
|
|
||||||
</button>
|
|
||||||
<button is="emby-button" type="button" class="raised button-cancel block" data-icon="delete" onclick="$(this).parents('.dialog').addClass('hide');" data-mini="true">
|
|
||||||
<span>${ButtonCancel}</span>
|
|
||||||
</button>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
<div data-role="popup" id="containerProfilePopup" class="dialog dialog-fixedSize dialog-medium hide" style="position: fixed; top: 10%;">
|
|
||||||
<form class="containerProfileForm" style="padding:1em;">
|
|
||||||
<div class="ui-bar-a">
|
|
||||||
<h3 class="sectionTitle">${HeaderContainerProfile}</h3>
|
|
||||||
</div>
|
|
||||||
<div data-role="content">
|
|
||||||
<p>${HeaderContainerProfileHelp}</p>
|
|
||||||
<div class="tabContent tabContainerBasics">
|
|
||||||
<div class="selectContainer">
|
|
||||||
<select id="selectContainerProfileType" name="selectContainerProfileType" is="emby-select" label="${LabelType}">
|
|
||||||
<option value="Audio">${Audio}</option>
|
|
||||||
<option value="Photo">${Photo}</option>
|
|
||||||
<option value="Video">${Video}</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div class="inputContainer">
|
|
||||||
<input is="emby-input" type="text" id="txtContainerProfileContainer" label="${LabelProfileContainer}" />
|
|
||||||
<div class="fieldDescription">${LabelProfileContainersHelp}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="tabContent tabContainerConditions" style="display: none;"></div>
|
|
||||||
<p>
|
|
||||||
<button is="emby-button" type="submit" class="raised button-submit block" data-icon="check" data-mini="true">
|
|
||||||
<span>${ButtonOk}</span>
|
|
||||||
</button>
|
|
||||||
<button is="emby-button" type="button" class="raised button-cancel block" data-icon="delete" onclick="$(this).parents('.dialog').addClass('hide');" data-mini="true">
|
|
||||||
<span>${ButtonCancel}</span>
|
|
||||||
</button>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
<div data-role="popup" id="codecProfilePopup" class="dialog dialog-fixedSize dialog-medium hide" style="position: fixed; top: 10%;">
|
|
||||||
<form class="codecProfileForm" style="padding:1em;">
|
|
||||||
<div class="ui-bar-a">
|
|
||||||
<h3 class="sectionTitle">${HeaderCodecProfile}</h3>
|
|
||||||
</div>
|
|
||||||
<div data-role="content">
|
|
||||||
<p>${HeaderCodecProfileHelp}</p>
|
|
||||||
<div class="selectContainer">
|
|
||||||
<select id="selectCodecProfileType" name="selectCodecProfileType" is="emby-select" label="${LabelType}">
|
|
||||||
<option value="Video">${Video}</option>
|
|
||||||
<option value="VideoAudio">${VideoAudio}</option>
|
|
||||||
<option value="Audio">${Audio}</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div class="inputContainer">
|
|
||||||
<input is="emby-input" type="text" id="txtCodecProfileCodec" label="${LabelProfileCodecs}" />
|
|
||||||
<div class="fieldDescription">${LabelProfileCodecsHelp}</div>
|
|
||||||
</div>
|
|
||||||
<p>
|
|
||||||
<button is="emby-button" type="submit" class="raised button-submit block" data-icon="check" data-mini="true">
|
|
||||||
<span>${ButtonOk}</span>
|
|
||||||
</button>
|
|
||||||
<button is="emby-button" type="button" class="raised button-cancel block" data-icon="delete" onclick="$(this).parents('.dialog').addClass('hide');" data-mini="true">
|
|
||||||
<span>${ButtonCancel}</span>
|
|
||||||
</button>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
<div data-role="popup" id="responseProfilePopup" class="dialog dialog-fixedSize dialog-medium hide" style="position: fixed; top: 10%;">
|
|
||||||
<form class="editResponseProfileForm" style="padding:1em;">
|
|
||||||
<div class="ui-bar-a">
|
|
||||||
<h3 class="sectionTitle">${HeaderResponseProfile}</h3>
|
|
||||||
</div>
|
|
||||||
<div data-role="content">
|
|
||||||
<div class="selectContainer">
|
|
||||||
<select id="selectResponseProfileType" name="selectResponseProfileType" is="emby-select" label="${LabelType}">
|
|
||||||
<option value="Audio">${Audio}</option>
|
|
||||||
<option value="Photo">${Photo}</option>
|
|
||||||
<option value="Video">${Video}</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div class="inputContainer">
|
|
||||||
<input is="emby-input" type="text" id="txtResponseProfileContainer" label="${LabelProfileContainer}" />
|
|
||||||
<div class="fieldDescription">${LabelProfileContainersHelp}</div>
|
|
||||||
</div>
|
|
||||||
<div id="fldResponseProfileVideoCodec" style="margin: 1em 0;">
|
|
||||||
<div class="inputContainer">
|
|
||||||
<input is="emby-input" type="text" id="txtResponseProfileVideoCodec" label="${LabelProfileVideoCodecs}" />
|
|
||||||
<div class="fieldDescription">${LabelProfileCodecsHelp}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="fldResponseProfileAudioCodec" style="margin: 1em 0 2em;">
|
|
||||||
<div class="inputContainer">
|
|
||||||
<input is="emby-input" type="text" id="txtResponseProfileAudioCodec" label="${LabelProfileAudioCodecs}" />
|
|
||||||
<div class="fieldDescription">${LabelProfileCodecsHelp}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<p>
|
|
||||||
<button is="emby-button" type="submit" class="raised button-submit block" data-icon="check" data-mini="true">
|
|
||||||
<span>${ButtonOk}</span>
|
|
||||||
</button>
|
|
||||||
<button is="emby-button" type="button" class="raised button-cancel block" data-icon="delete" onclick="$(this).parents('.dialog').addClass('hide');" data-mini="true">
|
|
||||||
<span>${ButtonCancel}</span>
|
|
||||||
</button>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
<div data-role="popup" id="identificationHeaderPopup" class="dialog dialog-fixedSize dialog-medium hide" style="position: fixed; top: 10%;">
|
|
||||||
<form class="identificationHeaderForm" style="padding:1em;">
|
|
||||||
<div class="ui-bar-a">
|
|
||||||
<h3 class="sectionTitle">${HeaderIdentificationHeader}</h3>
|
|
||||||
</div>
|
|
||||||
<div data-role="content">
|
|
||||||
<div class="inputContainer">
|
|
||||||
<input is="emby-input" type="text" id="txtIdentificationHeaderName" label="${LabelName}" />
|
|
||||||
</div>
|
|
||||||
<div class="inputContainer">
|
|
||||||
<input is="emby-input" type="text" id="txtIdentificationHeaderValue" label="${LabelValue}" />
|
|
||||||
</div>
|
|
||||||
<div class="selectContainer">
|
|
||||||
<select id="selectMatchType" name="selectMatchType" is="emby-select" label="${LabelMatchType}">
|
|
||||||
<option value="Equals">${OptionEquals}</option>
|
|
||||||
<option value="Regex">${OptionRegex}</option>
|
|
||||||
<option value="Substring">${OptionSubstring}</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<p>
|
|
||||||
<button is="emby-button" type="submit" class="raised button-submit block" data-icon="check" data-mini="true">
|
|
||||||
<span>${ButtonOk}</span>
|
|
||||||
</button>
|
|
||||||
<button is="emby-button" type="button" class="raised button-cancel block" data-icon="delete" onclick="$(this).parents('.dialog').addClass('hide');" data-mini="true">
|
|
||||||
<span>${ButtonCancel}</span>
|
|
||||||
</button>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
<div data-role="popup" id="xmlAttributePopup" class="dialog dialog-fixedSize dialog-medium hide" style="position: fixed; top: 10%;">
|
|
||||||
<form class="xmlAttributeForm" style="padding:1em;">
|
|
||||||
<div class="ui-bar-a">
|
|
||||||
<h3 class="sectionTitle">${HeaderXmlDocumentAttribute}</h3>
|
|
||||||
</div>
|
|
||||||
<div data-role="content">
|
|
||||||
<div class="inputContainer">
|
|
||||||
<input is="emby-input" type="text" id="txtXmlAttributeName" label="${LabelName}" />
|
|
||||||
</div>
|
|
||||||
<div class="inputContainer">
|
|
||||||
<input is="emby-input" type="text" id="txtXmlAttributeValue" label="${LabelValue}" />
|
|
||||||
</div>
|
|
||||||
<p>
|
|
||||||
<button is="emby-button" type="submit" class="raised button-submit block" data-icon="check" data-mini="true">
|
|
||||||
<span>${ButtonOk}</span>
|
|
||||||
</button>
|
|
||||||
<button is="emby-button" type="button" class="raised button-cancel block" data-icon="delete" onclick="$(this).parents('.dialog').addClass('hide');" data-mini="true">
|
|
||||||
<span>${ButtonCancel}</span>
|
|
||||||
</button>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
<div data-role="popup" id="subtitleProfilePopup" class="dialog dialog-fixedSize dialog-medium hide" style="position: fixed; top: 10%;">
|
|
||||||
<form class="subtitleProfileForm" style="padding:1em;">
|
|
||||||
<div class="ui-bar-a">
|
|
||||||
<h3 class="sectionTitle">${HeaderSubtitleProfile}</h3>
|
|
||||||
</div>
|
|
||||||
<div data-role="content">
|
|
||||||
<div class="inputContainer">
|
|
||||||
<input is="emby-input" type="text" id="txtSubtitleProfileFormat" label="${LabelFormat}" />
|
|
||||||
<div class="fieldDescription">${LabelSubtitleFormatHelp}</div>
|
|
||||||
</div>
|
|
||||||
<div class="selectContainer">
|
|
||||||
<select id="selectSubtitleProfileMethod" name="selectSubtitleProfileMethod" is="emby-select" label="${LabelMethod}">
|
|
||||||
<option value="Embed">${OptionEmbedSubtitles}</option>
|
|
||||||
<option value="External">${OptionExternallyDownloaded}</option>
|
|
||||||
<option value="Hls">${OptionHlsSegmentedSubtitles}</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div class="selectContainer">
|
|
||||||
<select id="selectSubtitleProfileDidlMode" name="selectSubtitleProfileDidlMode" is="emby-select" label="${LabelDidlMode}">
|
|
||||||
<option value="">${OptionResElement}</option>
|
|
||||||
<option value="CaptionInfoEx">${OptionCaptionInfoExSamsung}</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<p>
|
|
||||||
<button is="emby-button" type="submit" class="raised button-submit block" data-icon="check" data-mini="true">
|
|
||||||
<span>${ButtonOk}</span>
|
|
||||||
</button>
|
|
||||||
<button is="emby-button" type="button" class="raised button-cancel block" data-icon="delete" onclick="$(this).parents('.dialog').addClass('hide');" data-mini="true">
|
|
||||||
<span>${ButtonCancel}</span>
|
|
||||||
</button>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
|
@ -1,830 +0,0 @@
|
||||||
import escapeHtml from 'escape-html';
|
|
||||||
import 'jquery';
|
|
||||||
import loading from '../../../components/loading/loading';
|
|
||||||
import globalize from '../../../scripts/globalize';
|
|
||||||
import '../../../elements/emby-select/emby-select';
|
|
||||||
import '../../../elements/emby-button/emby-button';
|
|
||||||
import '../../../elements/emby-input/emby-input';
|
|
||||||
import '../../../elements/emby-checkbox/emby-checkbox';
|
|
||||||
import '../../../components/listview/listview.scss';
|
|
||||||
import Dashboard from '../../../utils/dashboard';
|
|
||||||
import toast from '../../../components/toast/toast';
|
|
||||||
import { getParameterByName } from '../../../utils/url.ts';
|
|
||||||
|
|
||||||
function loadProfile(page) {
|
|
||||||
loading.show();
|
|
||||||
const promise1 = getProfile();
|
|
||||||
const promise2 = ApiClient.getUsers();
|
|
||||||
Promise.all([promise1, promise2]).then(function (responses) {
|
|
||||||
currentProfile = responses[0];
|
|
||||||
renderProfile(page, currentProfile, responses[1]);
|
|
||||||
loading.hide();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function getProfile() {
|
|
||||||
const id = getParameterByName('id');
|
|
||||||
const url = id ? 'Dlna/Profiles/' + id : 'Dlna/Profiles/Default';
|
|
||||||
return ApiClient.getJSON(ApiClient.getUrl(url));
|
|
||||||
}
|
|
||||||
|
|
||||||
function renderProfile(page, profile, users) {
|
|
||||||
$('#txtName', page).val(profile.Name);
|
|
||||||
$('.chkMediaType', page).each(function () {
|
|
||||||
this.checked = (profile.SupportedMediaTypes || '').split(',').indexOf(this.getAttribute('data-value')) != -1;
|
|
||||||
});
|
|
||||||
$('#chkEnableAlbumArtInDidl', page).prop('checked', profile.EnableAlbumArtInDidl);
|
|
||||||
$('#chkEnableSingleImageLimit', page).prop('checked', profile.EnableSingleAlbumArtLimit);
|
|
||||||
renderXmlDocumentAttributes(page, profile.XmlRootAttributes || []);
|
|
||||||
const idInfo = profile.Identification || {};
|
|
||||||
renderIdentificationHeaders(page, idInfo.Headers || []);
|
|
||||||
renderSubtitleProfiles(page, profile.SubtitleProfiles || []);
|
|
||||||
$('#txtInfoFriendlyName', page).val(profile.FriendlyName || '');
|
|
||||||
$('#txtInfoModelName', page).val(profile.ModelName || '');
|
|
||||||
$('#txtInfoModelNumber', page).val(profile.ModelNumber || '');
|
|
||||||
$('#txtInfoModelDescription', page).val(profile.ModelDescription || '');
|
|
||||||
$('#txtInfoModelUrl', page).val(profile.ModelUrl || '');
|
|
||||||
$('#txtInfoManufacturer', page).val(profile.Manufacturer || '');
|
|
||||||
$('#txtInfoManufacturerUrl', page).val(profile.ManufacturerUrl || '');
|
|
||||||
$('#txtInfoSerialNumber', page).val(profile.SerialNumber || '');
|
|
||||||
$('#txtIdFriendlyName', page).val(idInfo.FriendlyName || '');
|
|
||||||
$('#txtIdModelName', page).val(idInfo.ModelName || '');
|
|
||||||
$('#txtIdModelNumber', page).val(idInfo.ModelNumber || '');
|
|
||||||
$('#txtIdModelDescription', page).val(idInfo.ModelDescription || '');
|
|
||||||
$('#txtIdModelUrl', page).val(idInfo.ModelUrl || '');
|
|
||||||
$('#txtIdManufacturer', page).val(idInfo.Manufacturer || '');
|
|
||||||
$('#txtIdManufacturerUrl', page).val(idInfo.ManufacturerUrl || '');
|
|
||||||
$('#txtIdSerialNumber', page).val(idInfo.SerialNumber || '');
|
|
||||||
$('#txtIdDeviceDescription', page).val(idInfo.DeviceDescription || '');
|
|
||||||
$('#txtAlbumArtPn', page).val(profile.AlbumArtPn || '');
|
|
||||||
$('#txtAlbumArtMaxWidth', page).val(profile.MaxAlbumArtWidth || '');
|
|
||||||
$('#txtAlbumArtMaxHeight', page).val(profile.MaxAlbumArtHeight || '');
|
|
||||||
$('#txtIconMaxWidth', page).val(profile.MaxIconWidth || '');
|
|
||||||
$('#txtIconMaxHeight', page).val(profile.MaxIconHeight || '');
|
|
||||||
$('#chkIgnoreTranscodeByteRangeRequests', page).prop('checked', profile.IgnoreTranscodeByteRangeRequests);
|
|
||||||
$('#txtMaxAllowedBitrate', page).val(profile.MaxStreamingBitrate || '');
|
|
||||||
$('#txtMusicStreamingTranscodingBitrate', page).val(profile.MusicStreamingTranscodingBitrate || '');
|
|
||||||
$('#chkRequiresPlainFolders', page).prop('checked', profile.RequiresPlainFolders);
|
|
||||||
$('#chkRequiresPlainVideoItems', page).prop('checked', profile.RequiresPlainVideoItems);
|
|
||||||
$('#txtProtocolInfo', page).val(profile.ProtocolInfo || '');
|
|
||||||
$('#txtXDlnaCap', page).val(profile.XDlnaCap || '');
|
|
||||||
$('#txtXDlnaDoc', page).val(profile.XDlnaDoc || '');
|
|
||||||
$('#txtSonyAggregationFlags', page).val(profile.SonyAggregationFlags || '');
|
|
||||||
profile.DirectPlayProfiles = profile.DirectPlayProfiles || [];
|
|
||||||
profile.TranscodingProfiles = profile.TranscodingProfiles || [];
|
|
||||||
profile.ContainerProfiles = profile.ContainerProfiles || [];
|
|
||||||
profile.CodecProfiles = profile.CodecProfiles || [];
|
|
||||||
profile.ResponseProfiles = profile.ResponseProfiles || [];
|
|
||||||
const usersHtml = '<option></option>' + users.map(function (u) {
|
|
||||||
return '<option value="' + u.Id + '">' + escapeHtml(u.Name) + '</option>';
|
|
||||||
}).join('');
|
|
||||||
$('#selectUser', page).html(usersHtml).val(profile.UserId || '');
|
|
||||||
renderSubProfiles(page, profile);
|
|
||||||
}
|
|
||||||
|
|
||||||
function renderIdentificationHeaders(page, headers) {
|
|
||||||
let index = 0;
|
|
||||||
const html = '<div class="paperList">' + headers.map(function (h) {
|
|
||||||
let li = '<div class="listItem">';
|
|
||||||
li += '<span class="material-icons listItemIcon info" aria-hidden="true"></span>';
|
|
||||||
li += '<div class="listItemBody">';
|
|
||||||
li += '<h3 class="listItemBodyText">' + escapeHtml(h.Name + ': ' + (h.Value || '')) + '</h3>';
|
|
||||||
li += '<div class="listItemBodyText secondary">' + escapeHtml(h.Match || '') + '</div>';
|
|
||||||
li += '</div>';
|
|
||||||
li += '<button type="button" is="paper-icon-button-light" class="btnDeleteIdentificationHeader listItemButton" data-index="' + index + '"><span class="material-icons delete" aria-hidden="true"></span></button>';
|
|
||||||
li += '</div>';
|
|
||||||
index++;
|
|
||||||
return li;
|
|
||||||
}).join('') + '</div>';
|
|
||||||
const elem = $('.httpHeaderIdentificationList', page).html(html).trigger('create');
|
|
||||||
$('.btnDeleteIdentificationHeader', elem).on('click', function () {
|
|
||||||
const itemIndex = parseInt(this.getAttribute('data-index'), 10);
|
|
||||||
currentProfile.Identification.Headers.splice(itemIndex, 1);
|
|
||||||
renderIdentificationHeaders(page, currentProfile.Identification.Headers);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function openPopup(elem) {
|
|
||||||
elem.classList.remove('hide');
|
|
||||||
}
|
|
||||||
|
|
||||||
function closePopup(elem) {
|
|
||||||
elem.classList.add('hide');
|
|
||||||
}
|
|
||||||
|
|
||||||
function editIdentificationHeader(page, header) {
|
|
||||||
isSubProfileNew = header == null;
|
|
||||||
header = header || {};
|
|
||||||
currentSubProfile = header;
|
|
||||||
const popup = $('#identificationHeaderPopup', page);
|
|
||||||
$('#txtIdentificationHeaderName', popup).val(header.Name || '');
|
|
||||||
$('#txtIdentificationHeaderValue', popup).val(header.Value || '');
|
|
||||||
$('#selectMatchType', popup).val(header.Match || 'Equals');
|
|
||||||
openPopup(popup[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
function saveIdentificationHeader(page) {
|
|
||||||
currentSubProfile.Name = $('#txtIdentificationHeaderName', page).val();
|
|
||||||
currentSubProfile.Value = $('#txtIdentificationHeaderValue', page).val();
|
|
||||||
currentSubProfile.Match = $('#selectMatchType', page).val();
|
|
||||||
|
|
||||||
if (isSubProfileNew) {
|
|
||||||
currentProfile.Identification = currentProfile.Identification || {};
|
|
||||||
currentProfile.Identification.Headers = currentProfile.Identification.Headers || [];
|
|
||||||
currentProfile.Identification.Headers.push(currentSubProfile);
|
|
||||||
}
|
|
||||||
|
|
||||||
renderIdentificationHeaders(page, currentProfile.Identification.Headers);
|
|
||||||
currentSubProfile = null;
|
|
||||||
closePopup($('#identificationHeaderPopup', page)[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
function renderXmlDocumentAttributes(page, attribute) {
|
|
||||||
const html = '<div class="paperList">' + attribute.map(function (h) {
|
|
||||||
let li = '<div class="listItem">';
|
|
||||||
li += '<span class="material-icons listItemIcon info" aria-hidden="true"></span>';
|
|
||||||
li += '<div class="listItemBody">';
|
|
||||||
li += '<h3 class="listItemBodyText">' + escapeHtml(h.Name + ' = ' + (h.Value || '')) + '</h3>';
|
|
||||||
li += '</div>';
|
|
||||||
li += '<button type="button" is="paper-icon-button-light" class="btnDeleteXmlAttribute listItemButton" data-index="0"><span class="material-icons delete" aria-hidden="true"></span></button>';
|
|
||||||
li += '</div>';
|
|
||||||
return li;
|
|
||||||
}).join('') + '</div>';
|
|
||||||
const elem = $('.xmlDocumentAttributeList', page).html(html).trigger('create');
|
|
||||||
$('.btnDeleteXmlAttribute', elem).on('click', function () {
|
|
||||||
const itemIndex = parseInt(this.getAttribute('data-index'), 10);
|
|
||||||
currentProfile.XmlRootAttributes.splice(itemIndex, 1);
|
|
||||||
renderXmlDocumentAttributes(page, currentProfile.XmlRootAttributes);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function editXmlDocumentAttribute(page, attribute) {
|
|
||||||
isSubProfileNew = attribute == null;
|
|
||||||
attribute = attribute || {};
|
|
||||||
currentSubProfile = attribute;
|
|
||||||
const popup = $('#xmlAttributePopup', page);
|
|
||||||
$('#txtXmlAttributeName', popup).val(attribute.Name || '');
|
|
||||||
$('#txtXmlAttributeValue', popup).val(attribute.Value || '');
|
|
||||||
openPopup(popup[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
function saveXmlDocumentAttribute(page) {
|
|
||||||
currentSubProfile.Name = $('#txtXmlAttributeName', page).val();
|
|
||||||
currentSubProfile.Value = $('#txtXmlAttributeValue', page).val();
|
|
||||||
|
|
||||||
if (isSubProfileNew) {
|
|
||||||
currentProfile.XmlRootAttributes.push(currentSubProfile);
|
|
||||||
}
|
|
||||||
|
|
||||||
renderXmlDocumentAttributes(page, currentProfile.XmlRootAttributes);
|
|
||||||
currentSubProfile = null;
|
|
||||||
closePopup($('#xmlAttributePopup', page)[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
function renderSubtitleProfiles(page, profiles) {
|
|
||||||
let index = 0;
|
|
||||||
const html = '<div class="paperList">' + profiles.map(function (h) {
|
|
||||||
let li = '<div class="listItem lnkEditSubProfile" data-index="' + index + '">';
|
|
||||||
li += '<span class="material-icons listItemIcon info" aria-hidden="true"></span>';
|
|
||||||
li += '<div class="listItemBody">';
|
|
||||||
li += '<h3 class="listItemBodyText">' + escapeHtml(h.Format || '') + '</h3>';
|
|
||||||
li += '</div>';
|
|
||||||
li += '<button type="button" is="paper-icon-button-light" class="btnDeleteProfile listItemButton" data-index="' + index + '"><span class="material-icons delete" aria-hidden="true"></span></button>';
|
|
||||||
li += '</div>';
|
|
||||||
index++;
|
|
||||||
return li;
|
|
||||||
}).join('') + '</div>';
|
|
||||||
const elem = $('.subtitleProfileList', page).html(html).trigger('create');
|
|
||||||
$('.btnDeleteProfile', elem).on('click', function () {
|
|
||||||
const itemIndex = parseInt(this.getAttribute('data-index'), 10);
|
|
||||||
currentProfile.SubtitleProfiles.splice(itemIndex, 1);
|
|
||||||
renderSubtitleProfiles(page, currentProfile.SubtitleProfiles);
|
|
||||||
});
|
|
||||||
$('.lnkEditSubProfile', elem).on('click', function () {
|
|
||||||
const itemIndex = parseInt(this.getAttribute('data-index'), 10);
|
|
||||||
editSubtitleProfile(page, currentProfile.SubtitleProfiles[itemIndex]);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function editSubtitleProfile(page, profile) {
|
|
||||||
isSubProfileNew = profile == null;
|
|
||||||
profile = profile || {};
|
|
||||||
currentSubProfile = profile;
|
|
||||||
const popup = $('#subtitleProfilePopup', page);
|
|
||||||
$('#txtSubtitleProfileFormat', popup).val(profile.Format || '');
|
|
||||||
$('#selectSubtitleProfileMethod', popup).val(profile.Method || '');
|
|
||||||
$('#selectSubtitleProfileDidlMode', popup).val(profile.DidlMode || '');
|
|
||||||
openPopup(popup[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
function saveSubtitleProfile(page) {
|
|
||||||
currentSubProfile.Format = $('#txtSubtitleProfileFormat', page).val();
|
|
||||||
currentSubProfile.Method = $('#selectSubtitleProfileMethod', page).val();
|
|
||||||
currentSubProfile.DidlMode = $('#selectSubtitleProfileDidlMode', page).val();
|
|
||||||
|
|
||||||
if (isSubProfileNew) {
|
|
||||||
currentProfile.SubtitleProfiles.push(currentSubProfile);
|
|
||||||
}
|
|
||||||
|
|
||||||
renderSubtitleProfiles(page, currentProfile.SubtitleProfiles);
|
|
||||||
currentSubProfile = null;
|
|
||||||
closePopup($('#subtitleProfilePopup', page)[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
function renderSubProfiles(page, profile) {
|
|
||||||
renderDirectPlayProfiles(page, profile.DirectPlayProfiles);
|
|
||||||
renderTranscodingProfiles(page, profile.TranscodingProfiles);
|
|
||||||
renderContainerProfiles(page, profile.ContainerProfiles);
|
|
||||||
renderCodecProfiles(page, profile.CodecProfiles);
|
|
||||||
renderResponseProfiles(page, profile.ResponseProfiles);
|
|
||||||
}
|
|
||||||
|
|
||||||
function saveDirectPlayProfile(page) {
|
|
||||||
currentSubProfile.Type = $('#selectDirectPlayProfileType', page).val();
|
|
||||||
currentSubProfile.Container = $('#txtDirectPlayContainer', page).val();
|
|
||||||
currentSubProfile.AudioCodec = $('#txtDirectPlayAudioCodec', page).val();
|
|
||||||
currentSubProfile.VideoCodec = $('#txtDirectPlayVideoCodec', page).val();
|
|
||||||
|
|
||||||
if (isSubProfileNew) {
|
|
||||||
currentProfile.DirectPlayProfiles.push(currentSubProfile);
|
|
||||||
}
|
|
||||||
|
|
||||||
renderSubProfiles(page, currentProfile);
|
|
||||||
currentSubProfile = null;
|
|
||||||
closePopup($('#popupEditDirectPlayProfile', page)[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
function renderDirectPlayProfiles(page, profiles) {
|
|
||||||
let html = '';
|
|
||||||
html += '<ul data-role="listview" data-inset="true" data-split-icon="delete">';
|
|
||||||
let currentType;
|
|
||||||
|
|
||||||
for (const [index, profile] of profiles.entries()) {
|
|
||||||
if (profile.Type !== currentType) {
|
|
||||||
html += '<li data-role="list-divider">' + profile.Type + '</li>';
|
|
||||||
currentType = profile.Type;
|
|
||||||
}
|
|
||||||
|
|
||||||
html += '<div>';
|
|
||||||
html += '<a is="emby-linkbutton" href="#" class="lnkEditSubProfile" data-profileindex="' + index + '">';
|
|
||||||
html += '<p>' + globalize.translate('ValueContainer', profile.Container || allText) + '</p>';
|
|
||||||
|
|
||||||
if (profile.Type == 'Video') {
|
|
||||||
html += '<p>' + globalize.translate('ValueVideoCodec', profile.VideoCodec || allText) + '</p>';
|
|
||||||
html += '<p>' + globalize.translate('ValueAudioCodec', profile.AudioCodec || allText) + '</p>';
|
|
||||||
} else if (profile.Type == 'Audio') {
|
|
||||||
html += '<p>' + globalize.translate('ValueCodec', profile.AudioCodec || allText) + '</p>';
|
|
||||||
}
|
|
||||||
|
|
||||||
html += '</a>';
|
|
||||||
html += '<button type="button" is="paper-icon-button-light" class="btnDeleteProfile listItemButton" data-profileindex="' + index + '"><span class="material-icons delete" aria-hidden="true"></span></button>';
|
|
||||||
html += '</div>';
|
|
||||||
}
|
|
||||||
|
|
||||||
html += '</ul>';
|
|
||||||
const elem = $('.directPlayProfiles', page).html(html).trigger('create');
|
|
||||||
$('.btnDeleteProfile', elem).on('click', function () {
|
|
||||||
const index = this.getAttribute('data-profileindex');
|
|
||||||
deleteDirectPlayProfile(page, index);
|
|
||||||
});
|
|
||||||
$('.lnkEditSubProfile', elem).on('click', function () {
|
|
||||||
const index = parseInt(this.getAttribute('data-profileindex'), 10);
|
|
||||||
editDirectPlayProfile(page, currentProfile.DirectPlayProfiles[index]);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function deleteDirectPlayProfile(page, index) {
|
|
||||||
currentProfile.DirectPlayProfiles.splice(index, 1);
|
|
||||||
renderDirectPlayProfiles(page, currentProfile.DirectPlayProfiles);
|
|
||||||
}
|
|
||||||
|
|
||||||
function editDirectPlayProfile(page, directPlayProfile) {
|
|
||||||
isSubProfileNew = directPlayProfile == null;
|
|
||||||
directPlayProfile = directPlayProfile || {};
|
|
||||||
currentSubProfile = directPlayProfile;
|
|
||||||
const popup = $('#popupEditDirectPlayProfile', page);
|
|
||||||
$('#selectDirectPlayProfileType', popup).val(directPlayProfile.Type || 'Video').trigger('change');
|
|
||||||
$('#txtDirectPlayContainer', popup).val(directPlayProfile.Container || '');
|
|
||||||
$('#txtDirectPlayAudioCodec', popup).val(directPlayProfile.AudioCodec || '');
|
|
||||||
$('#txtDirectPlayVideoCodec', popup).val(directPlayProfile.VideoCodec || '');
|
|
||||||
openPopup(popup[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
function renderTranscodingProfiles(page, profiles) {
|
|
||||||
let html = '';
|
|
||||||
html += '<ul data-role="listview" data-inset="true" data-split-icon="delete">';
|
|
||||||
let currentType;
|
|
||||||
|
|
||||||
for (let i = 0, length = profiles.length; i < length; i++) {
|
|
||||||
const profile = profiles[i];
|
|
||||||
|
|
||||||
if (profile.Type !== currentType) {
|
|
||||||
html += '<li data-role="list-divider">' + profile.Type + '</li>';
|
|
||||||
currentType = profile.Type;
|
|
||||||
}
|
|
||||||
|
|
||||||
html += '<div>';
|
|
||||||
html += '<a is="emby-linkbutton" href="#" class="lnkEditSubProfile" data-profileindex="' + i + '">';
|
|
||||||
html += '<p>Protocol: ' + (profile.Protocol || 'Http') + '</p>';
|
|
||||||
html += '<p>' + globalize.translate('ValueContainer', profile.Container || allText) + '</p>';
|
|
||||||
|
|
||||||
if (profile.Type == 'Video') {
|
|
||||||
html += '<p>' + globalize.translate('ValueVideoCodec', profile.VideoCodec || allText) + '</p>';
|
|
||||||
html += '<p>' + globalize.translate('ValueAudioCodec', profile.AudioCodec || allText) + '</p>';
|
|
||||||
} else if (profile.Type == 'Audio') {
|
|
||||||
html += '<p>' + globalize.translate('ValueCodec', profile.AudioCodec || allText) + '</p>';
|
|
||||||
}
|
|
||||||
|
|
||||||
html += '</a>';
|
|
||||||
html += '<button type="button" is="paper-icon-button-light" class="btnDeleteProfile listItemButton" data-profileindex="' + i + '"><span class="material-icons delete" aria-hidden="true"></span></button>';
|
|
||||||
html += '</div>';
|
|
||||||
}
|
|
||||||
|
|
||||||
html += '</ul>';
|
|
||||||
const elem = $('.transcodingProfiles', page).html(html).trigger('create');
|
|
||||||
$('.btnDeleteProfile', elem).on('click', function () {
|
|
||||||
const index = this.getAttribute('data-profileindex');
|
|
||||||
deleteTranscodingProfile(page, index);
|
|
||||||
});
|
|
||||||
$('.lnkEditSubProfile', elem).on('click', function () {
|
|
||||||
const index = parseInt(this.getAttribute('data-profileindex'), 10);
|
|
||||||
editTranscodingProfile(page, currentProfile.TranscodingProfiles[index]);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function editTranscodingProfile(page, transcodingProfile) {
|
|
||||||
isSubProfileNew = transcodingProfile == null;
|
|
||||||
transcodingProfile = transcodingProfile || {};
|
|
||||||
currentSubProfile = transcodingProfile;
|
|
||||||
const popup = $('#transcodingProfilePopup', page);
|
|
||||||
$('#selectTranscodingProfileType', popup).val(transcodingProfile.Type || 'Video').trigger('change');
|
|
||||||
$('#txtTranscodingContainer', popup).val(transcodingProfile.Container || '');
|
|
||||||
$('#txtTranscodingAudioCodec', popup).val(transcodingProfile.AudioCodec || '');
|
|
||||||
$('#txtTranscodingVideoCodec', popup).val(transcodingProfile.VideoCodec || '');
|
|
||||||
$('#selectTranscodingProtocol', popup).val(transcodingProfile.Protocol || 'Http');
|
|
||||||
$('#chkEnableMpegtsM2TsMode', popup).prop('checked', transcodingProfile.EnableMpegtsM2TsMode || false);
|
|
||||||
$('#chkEstimateContentLength', popup).prop('checked', transcodingProfile.EstimateContentLength || false);
|
|
||||||
$('#chkReportByteRangeRequests', popup).prop('checked', transcodingProfile.TranscodeSeekInfo == 'Bytes');
|
|
||||||
$('.radioTabButton:first', popup).trigger('click');
|
|
||||||
openPopup(popup[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
function deleteTranscodingProfile(page, index) {
|
|
||||||
currentProfile.TranscodingProfiles.splice(index, 1);
|
|
||||||
renderTranscodingProfiles(page, currentProfile.TranscodingProfiles);
|
|
||||||
}
|
|
||||||
|
|
||||||
function saveTranscodingProfile(page) {
|
|
||||||
currentSubProfile.Type = $('#selectTranscodingProfileType', page).val();
|
|
||||||
currentSubProfile.Container = $('#txtTranscodingContainer', page).val();
|
|
||||||
currentSubProfile.AudioCodec = $('#txtTranscodingAudioCodec', page).val();
|
|
||||||
currentSubProfile.VideoCodec = $('#txtTranscodingVideoCodec', page).val();
|
|
||||||
currentSubProfile.Protocol = $('#selectTranscodingProtocol', page).val();
|
|
||||||
currentSubProfile.Context = 'Streaming';
|
|
||||||
currentSubProfile.EnableMpegtsM2TsMode = $('#chkEnableMpegtsM2TsMode', page).is(':checked');
|
|
||||||
currentSubProfile.EstimateContentLength = $('#chkEstimateContentLength', page).is(':checked');
|
|
||||||
currentSubProfile.TranscodeSeekInfo = $('#chkReportByteRangeRequests', page).is(':checked') ? 'Bytes' : 'Auto';
|
|
||||||
|
|
||||||
if (isSubProfileNew) {
|
|
||||||
currentProfile.TranscodingProfiles.push(currentSubProfile);
|
|
||||||
}
|
|
||||||
|
|
||||||
renderSubProfiles(page, currentProfile);
|
|
||||||
currentSubProfile = null;
|
|
||||||
closePopup($('#transcodingProfilePopup', page)[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
function renderContainerProfiles(page, profiles) {
|
|
||||||
let html = '';
|
|
||||||
html += '<ul data-role="listview" data-inset="true" data-split-icon="delete">';
|
|
||||||
let currentType;
|
|
||||||
|
|
||||||
for (let i = 0, length = profiles.length; i < length; i++) {
|
|
||||||
const profile = profiles[i];
|
|
||||||
|
|
||||||
if (profile.Type !== currentType) {
|
|
||||||
html += '<li data-role="list-divider">' + profile.Type + '</li>';
|
|
||||||
currentType = profile.Type;
|
|
||||||
}
|
|
||||||
|
|
||||||
html += '<div>';
|
|
||||||
html += '<a is="emby-linkbutton" href="#" class="lnkEditSubProfile" data-profileindex="' + i + '">';
|
|
||||||
html += '<p>' + globalize.translate('ValueContainer', profile.Container || allText) + '</p>';
|
|
||||||
|
|
||||||
if (profile.Conditions?.length) {
|
|
||||||
html += '<p>';
|
|
||||||
html += globalize.translate('ValueConditions', profile.Conditions.map(function (c) {
|
|
||||||
return c.Property;
|
|
||||||
}).join(', '));
|
|
||||||
html += '</p>';
|
|
||||||
}
|
|
||||||
|
|
||||||
html += '</a>';
|
|
||||||
html += '<button type="button" is="paper-icon-button-light" class="btnDeleteProfile listItemButton" data-profileindex="' + i + '"><span class="material-icons delete" aria-hidden="true"></span></button>';
|
|
||||||
html += '</div>';
|
|
||||||
}
|
|
||||||
|
|
||||||
html += '</ul>';
|
|
||||||
const elem = $('.containerProfiles', page).html(html).trigger('create');
|
|
||||||
$('.btnDeleteProfile', elem).on('click', function () {
|
|
||||||
const index = this.getAttribute('data-profileindex');
|
|
||||||
deleteContainerProfile(page, index);
|
|
||||||
});
|
|
||||||
$('.lnkEditSubProfile', elem).on('click', function () {
|
|
||||||
const index = parseInt(this.getAttribute('data-profileindex'), 10);
|
|
||||||
editContainerProfile(page, currentProfile.ContainerProfiles[index]);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function deleteContainerProfile(page, index) {
|
|
||||||
currentProfile.ContainerProfiles.splice(index, 1);
|
|
||||||
renderContainerProfiles(page, currentProfile.ContainerProfiles);
|
|
||||||
}
|
|
||||||
|
|
||||||
function editContainerProfile(page, containerProfile) {
|
|
||||||
isSubProfileNew = containerProfile == null;
|
|
||||||
containerProfile = containerProfile || {};
|
|
||||||
currentSubProfile = containerProfile;
|
|
||||||
const popup = $('#containerProfilePopup', page);
|
|
||||||
$('#selectContainerProfileType', popup).val(containerProfile.Type || 'Video').trigger('change');
|
|
||||||
$('#txtContainerProfileContainer', popup).val(containerProfile.Container || '');
|
|
||||||
$('.radioTabButton:first', popup).trigger('click');
|
|
||||||
openPopup(popup[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
function saveContainerProfile(page) {
|
|
||||||
currentSubProfile.Type = $('#selectContainerProfileType', page).val();
|
|
||||||
currentSubProfile.Container = $('#txtContainerProfileContainer', page).val();
|
|
||||||
|
|
||||||
if (isSubProfileNew) {
|
|
||||||
currentProfile.ContainerProfiles.push(currentSubProfile);
|
|
||||||
}
|
|
||||||
|
|
||||||
renderSubProfiles(page, currentProfile);
|
|
||||||
currentSubProfile = null;
|
|
||||||
closePopup($('#containerProfilePopup', page)[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
function renderCodecProfiles(page, profiles) {
|
|
||||||
let html = '';
|
|
||||||
html += '<ul data-role="listview" data-inset="true" data-split-icon="delete">';
|
|
||||||
let currentType;
|
|
||||||
|
|
||||||
for (let i = 0, length = profiles.length; i < length; i++) {
|
|
||||||
const profile = profiles[i];
|
|
||||||
const type = profile.Type.replace('VideoAudio', 'Video Audio');
|
|
||||||
|
|
||||||
if (type !== currentType) {
|
|
||||||
html += '<li data-role="list-divider">' + type + '</li>';
|
|
||||||
currentType = type;
|
|
||||||
}
|
|
||||||
|
|
||||||
html += '<div>';
|
|
||||||
html += '<a is="emby-linkbutton" href="#" class="lnkEditSubProfile" data-profileindex="' + i + '">';
|
|
||||||
html += '<p>' + globalize.translate('ValueCodec', profile.Codec || allText) + '</p>';
|
|
||||||
|
|
||||||
if (profile.Conditions?.length) {
|
|
||||||
html += '<p>';
|
|
||||||
html += globalize.translate('ValueConditions', profile.Conditions.map(function (c) {
|
|
||||||
return c.Property;
|
|
||||||
}).join(', '));
|
|
||||||
html += '</p>';
|
|
||||||
}
|
|
||||||
|
|
||||||
html += '</a>';
|
|
||||||
html += '<button type="button" is="paper-icon-button-light" class="btnDeleteProfile listItemButton" data-profileindex="' + i + '"><span class="material-icons delete" aria-hidden="true"></span></button>';
|
|
||||||
html += '</div>';
|
|
||||||
}
|
|
||||||
|
|
||||||
html += '</ul>';
|
|
||||||
const elem = $('.codecProfiles', page).html(html).trigger('create');
|
|
||||||
$('.btnDeleteProfile', elem).on('click', function () {
|
|
||||||
const index = this.getAttribute('data-profileindex');
|
|
||||||
deleteCodecProfile(page, index);
|
|
||||||
});
|
|
||||||
$('.lnkEditSubProfile', elem).on('click', function () {
|
|
||||||
const index = parseInt(this.getAttribute('data-profileindex'), 10);
|
|
||||||
editCodecProfile(page, currentProfile.CodecProfiles[index]);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function deleteCodecProfile(page, index) {
|
|
||||||
currentProfile.CodecProfiles.splice(index, 1);
|
|
||||||
renderCodecProfiles(page, currentProfile.CodecProfiles);
|
|
||||||
}
|
|
||||||
|
|
||||||
function editCodecProfile(page, codecProfile) {
|
|
||||||
isSubProfileNew = codecProfile == null;
|
|
||||||
codecProfile = codecProfile || {};
|
|
||||||
currentSubProfile = codecProfile;
|
|
||||||
const popup = $('#codecProfilePopup', page);
|
|
||||||
$('#selectCodecProfileType', popup).val(codecProfile.Type || 'Video').trigger('change');
|
|
||||||
$('#txtCodecProfileCodec', popup).val(codecProfile.Codec || '');
|
|
||||||
$('.radioTabButton:first', popup).trigger('click');
|
|
||||||
openPopup(popup[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
function saveCodecProfile(page) {
|
|
||||||
currentSubProfile.Type = $('#selectCodecProfileType', page).val();
|
|
||||||
currentSubProfile.Codec = $('#txtCodecProfileCodec', page).val();
|
|
||||||
|
|
||||||
if (isSubProfileNew) {
|
|
||||||
currentProfile.CodecProfiles.push(currentSubProfile);
|
|
||||||
}
|
|
||||||
|
|
||||||
renderSubProfiles(page, currentProfile);
|
|
||||||
currentSubProfile = null;
|
|
||||||
closePopup($('#codecProfilePopup', page)[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
function renderResponseProfiles(page, profiles) {
|
|
||||||
let html = '';
|
|
||||||
html += '<ul data-role="listview" data-inset="true" data-split-icon="delete">';
|
|
||||||
let currentType;
|
|
||||||
|
|
||||||
for (let i = 0, length = profiles.length; i < length; i++) {
|
|
||||||
const profile = profiles[i];
|
|
||||||
|
|
||||||
if (profile.Type !== currentType) {
|
|
||||||
html += '<li data-role="list-divider">' + profile.Type + '</li>';
|
|
||||||
currentType = profile.Type;
|
|
||||||
}
|
|
||||||
|
|
||||||
html += '<div>';
|
|
||||||
html += '<a is="emby-linkbutton" href="#" class="lnkEditSubProfile" data-profileindex="' + i + '">';
|
|
||||||
html += '<p>' + globalize.translate('ValueContainer', profile.Container || allText) + '</p>';
|
|
||||||
|
|
||||||
if (profile.Type == 'Video') {
|
|
||||||
html += '<p>' + globalize.translate('ValueVideoCodec', profile.VideoCodec || allText) + '</p>';
|
|
||||||
html += '<p>' + globalize.translate('ValueAudioCodec', profile.AudioCodec || allText) + '</p>';
|
|
||||||
} else if (profile.Type == 'Audio') {
|
|
||||||
html += '<p>' + globalize.translate('ValueCodec', profile.AudioCodec || allText) + '</p>';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (profile.Conditions?.length) {
|
|
||||||
html += '<p>';
|
|
||||||
html += globalize.translate('ValueConditions', profile.Conditions.map(function (c) {
|
|
||||||
return c.Property;
|
|
||||||
}).join(', '));
|
|
||||||
html += '</p>';
|
|
||||||
}
|
|
||||||
|
|
||||||
html += '</a>';
|
|
||||||
html += '<button type="button" is="paper-icon-button-light" class="btnDeleteProfile listItemButton" data-profileindex="' + i + '"><span class="material-icons delete" aria-hidden="true"></span></button>';
|
|
||||||
html += '</div>';
|
|
||||||
}
|
|
||||||
|
|
||||||
html += '</ul>';
|
|
||||||
const elem = $('.mediaProfiles', page).html(html).trigger('create');
|
|
||||||
$('.btnDeleteProfile', elem).on('click', function () {
|
|
||||||
const index = this.getAttribute('data-profileindex');
|
|
||||||
deleteResponseProfile(page, index);
|
|
||||||
});
|
|
||||||
$('.lnkEditSubProfile', elem).on('click', function () {
|
|
||||||
const index = parseInt(this.getAttribute('data-profileindex'), 10);
|
|
||||||
editResponseProfile(page, currentProfile.ResponseProfiles[index]);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function deleteResponseProfile(page, index) {
|
|
||||||
currentProfile.ResponseProfiles.splice(index, 1);
|
|
||||||
renderResponseProfiles(page, currentProfile.ResponseProfiles);
|
|
||||||
}
|
|
||||||
|
|
||||||
function editResponseProfile(page, responseProfile) {
|
|
||||||
isSubProfileNew = responseProfile == null;
|
|
||||||
responseProfile = responseProfile || {};
|
|
||||||
currentSubProfile = responseProfile;
|
|
||||||
const popup = $('#responseProfilePopup', page);
|
|
||||||
$('#selectResponseProfileType', popup).val(responseProfile.Type || 'Video').trigger('change');
|
|
||||||
$('#txtResponseProfileContainer', popup).val(responseProfile.Container || '');
|
|
||||||
$('#txtResponseProfileAudioCodec', popup).val(responseProfile.AudioCodec || '');
|
|
||||||
$('#txtResponseProfileVideoCodec', popup).val(responseProfile.VideoCodec || '');
|
|
||||||
$('.radioTabButton:first', popup).trigger('click');
|
|
||||||
openPopup(popup[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
function saveResponseProfile(page) {
|
|
||||||
currentSubProfile.Type = $('#selectResponseProfileType', page).val();
|
|
||||||
currentSubProfile.Container = $('#txtResponseProfileContainer', page).val();
|
|
||||||
currentSubProfile.AudioCodec = $('#txtResponseProfileAudioCodec', page).val();
|
|
||||||
currentSubProfile.VideoCodec = $('#txtResponseProfileVideoCodec', page).val();
|
|
||||||
|
|
||||||
if (isSubProfileNew) {
|
|
||||||
currentProfile.ResponseProfiles.push(currentSubProfile);
|
|
||||||
}
|
|
||||||
|
|
||||||
renderSubProfiles(page, currentProfile);
|
|
||||||
currentSubProfile = null;
|
|
||||||
closePopup($('#responseProfilePopup', page)[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
function saveProfile(page, profile) {
|
|
||||||
updateProfile(page, profile);
|
|
||||||
const id = getParameterByName('id');
|
|
||||||
|
|
||||||
if (id) {
|
|
||||||
ApiClient.ajax({
|
|
||||||
type: 'POST',
|
|
||||||
url: ApiClient.getUrl('Dlna/Profiles/' + id),
|
|
||||||
data: JSON.stringify(profile),
|
|
||||||
contentType: 'application/json'
|
|
||||||
}).then(function () {
|
|
||||||
toast(globalize.translate('SettingsSaved'));
|
|
||||||
}, Dashboard.processErrorResponse);
|
|
||||||
} else {
|
|
||||||
ApiClient.ajax({
|
|
||||||
type: 'POST',
|
|
||||||
url: ApiClient.getUrl('Dlna/Profiles'),
|
|
||||||
data: JSON.stringify(profile),
|
|
||||||
contentType: 'application/json'
|
|
||||||
}).then(function () {
|
|
||||||
Dashboard.navigate('dashboard/dlna/profiles');
|
|
||||||
}, Dashboard.processErrorResponse);
|
|
||||||
}
|
|
||||||
|
|
||||||
loading.hide();
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateProfile(page, profile) {
|
|
||||||
profile.Name = $('#txtName', page).val();
|
|
||||||
profile.EnableAlbumArtInDidl = $('#chkEnableAlbumArtInDidl', page).is(':checked');
|
|
||||||
profile.EnableSingleAlbumArtLimit = $('#chkEnableSingleImageLimit', page).is(':checked');
|
|
||||||
profile.SupportedMediaTypes = $('.chkMediaType:checked', page).get().map(function (c) {
|
|
||||||
return c.getAttribute('data-value');
|
|
||||||
}).join(',');
|
|
||||||
profile.Identification = profile.Identification || {};
|
|
||||||
profile.FriendlyName = $('#txtInfoFriendlyName', page).val();
|
|
||||||
profile.ModelName = $('#txtInfoModelName', page).val();
|
|
||||||
profile.ModelNumber = $('#txtInfoModelNumber', page).val();
|
|
||||||
profile.ModelDescription = $('#txtInfoModelDescription', page).val();
|
|
||||||
profile.ModelUrl = $('#txtInfoModelUrl', page).val();
|
|
||||||
profile.Manufacturer = $('#txtInfoManufacturer', page).val();
|
|
||||||
profile.ManufacturerUrl = $('#txtInfoManufacturerUrl', page).val();
|
|
||||||
profile.SerialNumber = $('#txtInfoSerialNumber', page).val();
|
|
||||||
profile.Identification.FriendlyName = $('#txtIdFriendlyName', page).val();
|
|
||||||
profile.Identification.ModelName = $('#txtIdModelName', page).val();
|
|
||||||
profile.Identification.ModelNumber = $('#txtIdModelNumber', page).val();
|
|
||||||
profile.Identification.ModelDescription = $('#txtIdModelDescription', page).val();
|
|
||||||
profile.Identification.ModelUrl = $('#txtIdModelUrl', page).val();
|
|
||||||
profile.Identification.Manufacturer = $('#txtIdManufacturer', page).val();
|
|
||||||
profile.Identification.ManufacturerUrl = $('#txtIdManufacturerUrl', page).val();
|
|
||||||
profile.Identification.SerialNumber = $('#txtIdSerialNumber', page).val();
|
|
||||||
profile.Identification.DeviceDescription = $('#txtIdDeviceDescription', page).val();
|
|
||||||
profile.AlbumArtPn = $('#txtAlbumArtPn', page).val();
|
|
||||||
profile.MaxAlbumArtWidth = $('#txtAlbumArtMaxWidth', page).val();
|
|
||||||
profile.MaxAlbumArtHeight = $('#txtAlbumArtMaxHeight', page).val();
|
|
||||||
profile.MaxIconWidth = $('#txtIconMaxWidth', page).val();
|
|
||||||
profile.MaxIconHeight = $('#txtIconMaxHeight', page).val();
|
|
||||||
profile.RequiresPlainFolders = $('#chkRequiresPlainFolders', page).is(':checked');
|
|
||||||
profile.RequiresPlainVideoItems = $('#chkRequiresPlainVideoItems', page).is(':checked');
|
|
||||||
profile.IgnoreTranscodeByteRangeRequests = $('#chkIgnoreTranscodeByteRangeRequests', page).is(':checked');
|
|
||||||
profile.MaxStreamingBitrate = $('#txtMaxAllowedBitrate', page).val();
|
|
||||||
profile.MusicStreamingTranscodingBitrate = $('#txtMusicStreamingTranscodingBitrate', page).val();
|
|
||||||
profile.ProtocolInfo = $('#txtProtocolInfo', page).val();
|
|
||||||
profile.XDlnaCap = $('#txtXDlnaCap', page).val();
|
|
||||||
profile.XDlnaDoc = $('#txtXDlnaDoc', page).val();
|
|
||||||
profile.SonyAggregationFlags = $('#txtSonyAggregationFlags', page).val();
|
|
||||||
profile.UserId = $('#selectUser', page).val();
|
|
||||||
}
|
|
||||||
|
|
||||||
let currentProfile;
|
|
||||||
let currentSubProfile;
|
|
||||||
let isSubProfileNew;
|
|
||||||
const allText = globalize.translate('All');
|
|
||||||
|
|
||||||
$(document).on('pageinit', '#dlnaProfilePage', function () {
|
|
||||||
const page = this;
|
|
||||||
$('.radioTabButton', page).on('click', function () {
|
|
||||||
$(this).siblings().removeClass('ui-btn-active');
|
|
||||||
$(this).addClass('ui-btn-active');
|
|
||||||
const value = this.tagName == 'A' ? this.getAttribute('data-value') : this.value;
|
|
||||||
const elem = $('.' + value, page);
|
|
||||||
elem.siblings('.tabContent').hide();
|
|
||||||
elem.show();
|
|
||||||
});
|
|
||||||
$('#selectDirectPlayProfileType', page).on('change', function () {
|
|
||||||
if (this.value == 'Video') {
|
|
||||||
$('#fldDirectPlayVideoCodec', page).show();
|
|
||||||
} else {
|
|
||||||
$('#fldDirectPlayVideoCodec', page).hide();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.value == 'Photo') {
|
|
||||||
$('#fldDirectPlayAudioCodec', page).hide();
|
|
||||||
} else {
|
|
||||||
$('#fldDirectPlayAudioCodec', page).show();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
$('#selectTranscodingProfileType', page).on('change', function () {
|
|
||||||
if (this.value == 'Video') {
|
|
||||||
$('#fldTranscodingVideoCodec', page).show();
|
|
||||||
$('#fldTranscodingProtocol', page).show();
|
|
||||||
$('#fldEnableMpegtsM2TsMode', page).show();
|
|
||||||
} else {
|
|
||||||
$('#fldTranscodingVideoCodec', page).hide();
|
|
||||||
$('#fldTranscodingProtocol', page).hide();
|
|
||||||
$('#fldEnableMpegtsM2TsMode', page).hide();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.value == 'Photo') {
|
|
||||||
$('#fldTranscodingAudioCodec', page).hide();
|
|
||||||
$('#fldEstimateContentLength', page).hide();
|
|
||||||
$('#fldReportByteRangeRequests', page).hide();
|
|
||||||
} else {
|
|
||||||
$('#fldTranscodingAudioCodec', page).show();
|
|
||||||
$('#fldEstimateContentLength', page).show();
|
|
||||||
$('#fldReportByteRangeRequests', page).show();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
$('#selectResponseProfileType', page).on('change', function () {
|
|
||||||
if (this.value == 'Video') {
|
|
||||||
$('#fldResponseProfileVideoCodec', page).show();
|
|
||||||
} else {
|
|
||||||
$('#fldResponseProfileVideoCodec', page).hide();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.value == 'Photo') {
|
|
||||||
$('#fldResponseProfileAudioCodec', page).hide();
|
|
||||||
} else {
|
|
||||||
$('#fldResponseProfileAudioCodec', page).show();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
$('.btnAddDirectPlayProfile', page).on('click', function () {
|
|
||||||
editDirectPlayProfile(page);
|
|
||||||
});
|
|
||||||
$('.btnAddTranscodingProfile', page).on('click', function () {
|
|
||||||
editTranscodingProfile(page);
|
|
||||||
});
|
|
||||||
$('.btnAddContainerProfile', page).on('click', function () {
|
|
||||||
editContainerProfile(page);
|
|
||||||
});
|
|
||||||
$('.btnAddCodecProfile', page).on('click', function () {
|
|
||||||
editCodecProfile(page);
|
|
||||||
});
|
|
||||||
$('.btnAddResponseProfile', page).on('click', function () {
|
|
||||||
editResponseProfile(page);
|
|
||||||
});
|
|
||||||
$('.btnAddIdentificationHttpHeader', page).on('click', function () {
|
|
||||||
editIdentificationHeader(page);
|
|
||||||
});
|
|
||||||
$('.btnAddXmlDocumentAttribute', page).on('click', function () {
|
|
||||||
editXmlDocumentAttribute(page);
|
|
||||||
});
|
|
||||||
$('.btnAddSubtitleProfile', page).on('click', function () {
|
|
||||||
editSubtitleProfile(page);
|
|
||||||
});
|
|
||||||
$('.dlnaProfileForm').off('submit', DlnaProfilePage.onSubmit).on('submit', DlnaProfilePage.onSubmit);
|
|
||||||
$('.editDirectPlayProfileForm').off('submit', DlnaProfilePage.onDirectPlayFormSubmit).on('submit', DlnaProfilePage.onDirectPlayFormSubmit);
|
|
||||||
$('.transcodingProfileForm').off('submit', DlnaProfilePage.onTranscodingProfileFormSubmit).on('submit', DlnaProfilePage.onTranscodingProfileFormSubmit);
|
|
||||||
$('.containerProfileForm').off('submit', DlnaProfilePage.onContainerProfileFormSubmit).on('submit', DlnaProfilePage.onContainerProfileFormSubmit);
|
|
||||||
$('.codecProfileForm').off('submit', DlnaProfilePage.onCodecProfileFormSubmit).on('submit', DlnaProfilePage.onCodecProfileFormSubmit);
|
|
||||||
$('.editResponseProfileForm').off('submit', DlnaProfilePage.onResponseProfileFormSubmit).on('submit', DlnaProfilePage.onResponseProfileFormSubmit);
|
|
||||||
$('.identificationHeaderForm').off('submit', DlnaProfilePage.onIdentificationHeaderFormSubmit).on('submit', DlnaProfilePage.onIdentificationHeaderFormSubmit);
|
|
||||||
$('.xmlAttributeForm').off('submit', DlnaProfilePage.onXmlAttributeFormSubmit).on('submit', DlnaProfilePage.onXmlAttributeFormSubmit);
|
|
||||||
$('.subtitleProfileForm').off('submit', DlnaProfilePage.onSubtitleProfileFormSubmit).on('submit', DlnaProfilePage.onSubtitleProfileFormSubmit);
|
|
||||||
}).on('pageshow', '#dlnaProfilePage', function () {
|
|
||||||
const page = this;
|
|
||||||
$('#radioInfo', page).trigger('click');
|
|
||||||
loadProfile(page);
|
|
||||||
});
|
|
||||||
window.DlnaProfilePage = {
|
|
||||||
onSubmit: function () {
|
|
||||||
loading.show();
|
|
||||||
saveProfile($(this).parents('.page'), currentProfile);
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
onDirectPlayFormSubmit: function () {
|
|
||||||
saveDirectPlayProfile($(this).parents('.page'));
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
onTranscodingProfileFormSubmit: function () {
|
|
||||||
saveTranscodingProfile($(this).parents('.page'));
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
onContainerProfileFormSubmit: function () {
|
|
||||||
saveContainerProfile($(this).parents('.page'));
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
onCodecProfileFormSubmit: function () {
|
|
||||||
saveCodecProfile($(this).parents('.page'));
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
onResponseProfileFormSubmit: function () {
|
|
||||||
saveResponseProfile($(this).parents('.page'));
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
onIdentificationHeaderFormSubmit: function () {
|
|
||||||
saveIdentificationHeader($(this).parents('.page'));
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
onXmlAttributeFormSubmit: function () {
|
|
||||||
saveXmlDocumentAttribute($(this).parents('.page'));
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
onSubtitleProfileFormSubmit: function () {
|
|
||||||
saveSubtitleProfile($(this).parents('.page'));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
|
@ -1,32 +0,0 @@
|
||||||
<div id="dlnaProfilesPage" data-role="page" class="page type-interior dlnaPage withTabs">
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<div class="content-primary">
|
|
||||||
|
|
||||||
<div class="readOnlyContent">
|
|
||||||
|
|
||||||
<div class="verticalSection verticalSection-extrabottompadding">
|
|
||||||
<div class="sectionTitleContainer flex align-items-center">
|
|
||||||
<h2 class="sectionTitle">${HeaderCustomDlnaProfiles}</h2>
|
|
||||||
<a is="emby-linkbutton" href="#/dashboard/dlna/profiles/edit" class="fab submit" style="margin:0 0 0 1em">
|
|
||||||
<span class="material-icons add" aria-hidden="true"></span>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<p>${CustomDlnaProfilesHelp}</p>
|
|
||||||
<div class="customProfiles"></div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<div class="verticalSection">
|
|
||||||
<div class="sectionTitleContainer flex align-items-center">
|
|
||||||
<h2 class="sectionTitle">${HeaderSystemDlnaProfiles}</h2>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<p>${SystemDlnaProfilesHelp}</p>
|
|
||||||
<div class="systemProfiles"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
|
@ -1,93 +0,0 @@
|
||||||
import escapeHtml from 'escape-html';
|
|
||||||
import 'jquery';
|
|
||||||
import globalize from '../../../scripts/globalize';
|
|
||||||
import loading from '../../../components/loading/loading';
|
|
||||||
import libraryMenu from '../../../scripts/libraryMenu';
|
|
||||||
import '../../../components/listview/listview.scss';
|
|
||||||
import '../../../elements/emby-button/emby-button';
|
|
||||||
import confirm from '../../../components/confirm/confirm';
|
|
||||||
|
|
||||||
function loadProfiles(page) {
|
|
||||||
loading.show();
|
|
||||||
ApiClient.getJSON(ApiClient.getUrl('Dlna/ProfileInfos')).then(function (result) {
|
|
||||||
renderUserProfiles(page, result);
|
|
||||||
renderSystemProfiles(page, result);
|
|
||||||
loading.hide();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function renderUserProfiles(page, profiles) {
|
|
||||||
renderProfiles(page, page.querySelector('.customProfiles'), profiles.filter(function (p) {
|
|
||||||
return p.Type == 'User';
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
function renderSystemProfiles(page, profiles) {
|
|
||||||
renderProfiles(page, page.querySelector('.systemProfiles'), profiles.filter(function (p) {
|
|
||||||
return p.Type == 'System';
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
function renderProfiles(page, element, profiles) {
|
|
||||||
let html = '';
|
|
||||||
|
|
||||||
if (profiles.length) {
|
|
||||||
html += '<div class="paperList">';
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let i = 0, length = profiles.length; i < length; i++) {
|
|
||||||
const profile = profiles[i];
|
|
||||||
html += '<div class="listItem listItem-border">';
|
|
||||||
html += '<span class="listItemIcon material-icons live_tv" aria-hidden="true"></span>';
|
|
||||||
html += '<div class="listItemBody two-line">';
|
|
||||||
html += "<a is='emby-linkbutton' style='padding:0;margin:0;' data-ripple='false' class='clearLink' href='#/dashboard/dlna/profiles/edit?id=" + profile.Id + "'>";
|
|
||||||
html += '<div>' + escapeHtml(profile.Name) + '</div>';
|
|
||||||
html += '</a>';
|
|
||||||
html += '</div>';
|
|
||||||
|
|
||||||
if (profile.Type == 'User') {
|
|
||||||
html += '<button type="button" is="paper-icon-button-light" class="btnDeleteProfile" data-profileid="' + profile.Id + '" title="' + globalize.translate('Delete') + '"><span class="material-icons delete" aria-hidden="true"></span></button>';
|
|
||||||
}
|
|
||||||
|
|
||||||
html += '</div>';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (profiles.length) {
|
|
||||||
html += '</div>';
|
|
||||||
}
|
|
||||||
|
|
||||||
element.innerHTML = html;
|
|
||||||
$('.btnDeleteProfile', element).on('click', function () {
|
|
||||||
const id = this.getAttribute('data-profileid');
|
|
||||||
deleteProfile(page, id);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function deleteProfile(page, id) {
|
|
||||||
confirm(globalize.translate('MessageConfirmProfileDeletion'), globalize.translate('HeaderConfirmProfileDeletion')).then(function () {
|
|
||||||
loading.show();
|
|
||||||
ApiClient.ajax({
|
|
||||||
type: 'DELETE',
|
|
||||||
url: ApiClient.getUrl('Dlna/Profiles/' + id)
|
|
||||||
}).then(function () {
|
|
||||||
loading.hide();
|
|
||||||
loadProfiles(page);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function getTabs() {
|
|
||||||
return [{
|
|
||||||
href: '#/dashboard/dlna',
|
|
||||||
name: globalize.translate('Settings')
|
|
||||||
}, {
|
|
||||||
href: '#/dashboard/dlna/profiles',
|
|
||||||
name: globalize.translate('TabProfiles')
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
|
|
||||||
$(document).on('pageshow', '#dlnaProfilesPage', function () {
|
|
||||||
libraryMenu.setTabs('dlna', 1, getTabs);
|
|
||||||
loadProfiles(this);
|
|
||||||
});
|
|
||||||
|
|
|
@ -1,69 +0,0 @@
|
||||||
<div id="dlnaSettingsPage" data-role="page" class="page type-interior withTabs">
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<div class="content-primary">
|
|
||||||
|
|
||||||
<form class="dlnaSettingsForm">
|
|
||||||
|
|
||||||
<div class="verticalSection">
|
|
||||||
<div class="sectionTitleContainer flex align-items-center">
|
|
||||||
<h2 class="sectionTitle">${Settings}</h2>
|
|
||||||
<a is="emby-linkbutton" rel="noopener noreferrer" class="raised button-alt headerHelpButton" target="_blank" href="https://jellyfin.org/docs/general/networking/dlna">${Help}</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="checkboxContainer checkboxContainer-withDescription">
|
|
||||||
<label>
|
|
||||||
<input type="checkbox" is="emby-checkbox" id="chkEnablePlayTo" />
|
|
||||||
<span>${LabelEnableDlnaPlayTo}</span>
|
|
||||||
</label>
|
|
||||||
<div class="fieldDescription checkboxFieldDescription">${LabelEnableDlnaPlayToHelp}</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="checkboxContainer checkboxContainer-withDescription">
|
|
||||||
<label>
|
|
||||||
<input type="checkbox" is="emby-checkbox" id="chkEnableDlnaDebugLogging" />
|
|
||||||
<span>${LabelEnableDlnaDebugLogging}</span>
|
|
||||||
</label>
|
|
||||||
<div class="fieldDescription checkboxFieldDescription">${LabelEnableDlnaDebugLoggingHelp}</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="inputContainer">
|
|
||||||
<input is="emby-input" type="number" id="txtClientDiscoveryInterval" min="1" max="300" label="${LabelEnableDlnaClientDiscoveryInterval}" />
|
|
||||||
<div class="fieldDescription">${LabelEnableDlnaClientDiscoveryIntervalHelp}</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="checkboxContainer checkboxContainer-withDescription">
|
|
||||||
<label>
|
|
||||||
<input type="checkbox" is="emby-checkbox" id="chkEnableServer" />
|
|
||||||
<span>${LabelEnableDlnaServer}</span>
|
|
||||||
</label>
|
|
||||||
<div class="fieldDescription checkboxFieldDescription">${LabelEnableDlnaServerHelp}</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="checkboxContainer checkboxContainer-withDescription">
|
|
||||||
<label>
|
|
||||||
<input type="checkbox" is="emby-checkbox" id="chkBlastAliveMessages" />
|
|
||||||
<span>${LabelEnableBlastAliveMessages}</span>
|
|
||||||
</label>
|
|
||||||
<div class="fieldDescription checkboxFieldDescription">${LabelEnableBlastAliveMessagesHelp}</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="inputContainer">
|
|
||||||
<input is="emby-input" type="number" id="txtBlastInterval" min="1" max="3600" label="${LabelBlastMessageInterval}" />
|
|
||||||
<div class="fieldDescription">${LabelBlastMessageIntervalHelp}</div>
|
|
||||||
</div>
|
|
||||||
<div class="selectContainer">
|
|
||||||
<select is="emby-select" id="selectUser" data-mini="true" label="${LabelDefaultUser}"></select>
|
|
||||||
<div class="fieldDescription">${LabelDefaultUserHelp}</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<button is="emby-button" type="submit" class="raised button-submit block">
|
|
||||||
<span>${Save}</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
|
@ -1,60 +0,0 @@
|
||||||
import escapeHtml from 'escape-html';
|
|
||||||
import 'jquery';
|
|
||||||
import loading from '../../../components/loading/loading';
|
|
||||||
import libraryMenu from '../../../scripts/libraryMenu';
|
|
||||||
import globalize from '../../../scripts/globalize';
|
|
||||||
import Dashboard from '../../../utils/dashboard';
|
|
||||||
|
|
||||||
function loadPage(page, config, users) {
|
|
||||||
page.querySelector('#chkEnablePlayTo').checked = config.EnablePlayTo;
|
|
||||||
page.querySelector('#chkEnableDlnaDebugLogging').checked = config.EnableDebugLog;
|
|
||||||
$('#txtClientDiscoveryInterval', page).val(config.ClientDiscoveryIntervalSeconds);
|
|
||||||
$('#chkEnableServer', page).prop('checked', config.EnableServer);
|
|
||||||
$('#chkBlastAliveMessages', page).prop('checked', config.BlastAliveMessages);
|
|
||||||
$('#txtBlastInterval', page).val(config.BlastAliveMessageIntervalSeconds);
|
|
||||||
const usersHtml = users.map(function (u) {
|
|
||||||
return '<option value="' + u.Id + '">' + escapeHtml(u.Name) + '</option>';
|
|
||||||
}).join('');
|
|
||||||
$('#selectUser', page).html(usersHtml).val(config.DefaultUserId || '');
|
|
||||||
loading.hide();
|
|
||||||
}
|
|
||||||
|
|
||||||
function onSubmit() {
|
|
||||||
loading.show();
|
|
||||||
const form = this;
|
|
||||||
ApiClient.getNamedConfiguration('dlna').then(function (config) {
|
|
||||||
config.EnablePlayTo = form.querySelector('#chkEnablePlayTo').checked;
|
|
||||||
config.EnableDebugLog = form.querySelector('#chkEnableDlnaDebugLogging').checked;
|
|
||||||
config.ClientDiscoveryIntervalSeconds = $('#txtClientDiscoveryInterval', form).val();
|
|
||||||
config.EnableServer = $('#chkEnableServer', form).is(':checked');
|
|
||||||
config.BlastAliveMessages = $('#chkBlastAliveMessages', form).is(':checked');
|
|
||||||
config.BlastAliveMessageIntervalSeconds = $('#txtBlastInterval', form).val();
|
|
||||||
config.DefaultUserId = $('#selectUser', form).val();
|
|
||||||
ApiClient.updateNamedConfiguration('dlna', config).then(Dashboard.processServerConfigurationUpdateResult);
|
|
||||||
});
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getTabs() {
|
|
||||||
return [{
|
|
||||||
href: '#/dashboard/dlna',
|
|
||||||
name: globalize.translate('Settings')
|
|
||||||
}, {
|
|
||||||
href: '#/dashboard/dlna/profiles',
|
|
||||||
name: globalize.translate('TabProfiles')
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
|
|
||||||
$(document).on('pageinit', '#dlnaSettingsPage', function () {
|
|
||||||
$('.dlnaSettingsForm').off('submit', onSubmit).on('submit', onSubmit);
|
|
||||||
}).on('pageshow', '#dlnaSettingsPage', function () {
|
|
||||||
libraryMenu.setTabs('dlna', 0, getTabs);
|
|
||||||
loading.show();
|
|
||||||
const page = this;
|
|
||||||
const promise1 = ApiClient.getNamedConfiguration('dlna');
|
|
||||||
const promise2 = ApiClient.getUsers();
|
|
||||||
Promise.all([promise1, promise2]).then(function (responses) {
|
|
||||||
loadPage(page, responses[0], responses[1]);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
|
@ -165,7 +165,6 @@
|
||||||
"CopyStreamURLSuccess": "URL copied successfully.",
|
"CopyStreamURLSuccess": "URL copied successfully.",
|
||||||
"CriticRating": "Critics rating",
|
"CriticRating": "Critics rating",
|
||||||
"Cursive": "Cursive",
|
"Cursive": "Cursive",
|
||||||
"CustomDlnaProfilesHelp": "Create a custom profile to target a new device or override a system profile.",
|
|
||||||
"DailyAt": "Daily at {0}",
|
"DailyAt": "Daily at {0}",
|
||||||
"Data": "Data",
|
"Data": "Data",
|
||||||
"DateAdded": "Date added",
|
"DateAdded": "Date added",
|
||||||
|
@ -208,6 +207,7 @@
|
||||||
"DisplayMissingEpisodesWithinSeasons": "Display missing episodes within seasons",
|
"DisplayMissingEpisodesWithinSeasons": "Display missing episodes within seasons",
|
||||||
"DisplayMissingEpisodesWithinSeasonsHelp": "This must also be enabled for TV libraries in the server configuration.",
|
"DisplayMissingEpisodesWithinSeasonsHelp": "This must also be enabled for TV libraries in the server configuration.",
|
||||||
"DisplayModeHelp": "Select the layout style you want for the interface.",
|
"DisplayModeHelp": "Select the layout style you want for the interface.",
|
||||||
|
"DlnaMovedMessage": "The DLNA functionality has moved to a plugin.",
|
||||||
"DoNotRecord": "Do not record",
|
"DoNotRecord": "Do not record",
|
||||||
"Down": "Down",
|
"Down": "Down",
|
||||||
"Download": "Download",
|
"Download": "Download",
|
||||||
|
@ -338,21 +338,15 @@
|
||||||
"HeaderCastAndCrew": "Cast & Crew",
|
"HeaderCastAndCrew": "Cast & Crew",
|
||||||
"HeaderChannelAccess": "Channel Access",
|
"HeaderChannelAccess": "Channel Access",
|
||||||
"HeaderChapterImages": "Chapter Images",
|
"HeaderChapterImages": "Chapter Images",
|
||||||
"HeaderCodecProfile": "Codec Profile",
|
|
||||||
"HeaderCodecProfileHelp": "Codec profiles indicate the limitations of a device when playing specific codecs. If a limitation applies then the media will be transcoded, even if the codec is configured for direct playback.",
|
|
||||||
"HeaderConfigureRemoteAccess": "Set up Remote Access",
|
"HeaderConfigureRemoteAccess": "Set up Remote Access",
|
||||||
"HeaderConfirmPluginInstallation": "Confirm Plugin Installation",
|
"HeaderConfirmPluginInstallation": "Confirm Plugin Installation",
|
||||||
"HeaderConfirmRepositoryInstallation": "Confirm Plugin Repository Installation",
|
"HeaderConfirmRepositoryInstallation": "Confirm Plugin Repository Installation",
|
||||||
"HeaderConfirmProfileDeletion": "Confirm Profile Deletion",
|
|
||||||
"HeaderConfirmRevokeApiKey": "Revoke API Key",
|
"HeaderConfirmRevokeApiKey": "Revoke API Key",
|
||||||
"HeaderConnectionFailure": "Connection Failure",
|
"HeaderConnectionFailure": "Connection Failure",
|
||||||
"HeaderConnectToServer": "Connect to Server",
|
"HeaderConnectToServer": "Connect to Server",
|
||||||
"HeaderContainerProfile": "Container Profile",
|
|
||||||
"HeaderContainerProfileHelp": "Container profiles indicate the limitations of a device when playing specific formats. If a limitation applies then the media will be transcoded, even if the format is configured for direct playback.",
|
|
||||||
"HeaderContinueListening": "Continue Listening",
|
"HeaderContinueListening": "Continue Listening",
|
||||||
"HeaderContinueWatching": "Continue Watching",
|
"HeaderContinueWatching": "Continue Watching",
|
||||||
"HeaderContinueReading": "Continue Reading",
|
"HeaderContinueReading": "Continue Reading",
|
||||||
"HeaderCustomDlnaProfiles": "Custom Profiles",
|
|
||||||
"HeaderDateIssued": "Date Issued",
|
"HeaderDateIssued": "Date Issued",
|
||||||
"HeaderDefaultRecordingSettings": "Default Recording Settings",
|
"HeaderDefaultRecordingSettings": "Default Recording Settings",
|
||||||
"HeaderDeleteDevice": "Delete Device",
|
"HeaderDeleteDevice": "Delete Device",
|
||||||
|
@ -365,8 +359,6 @@
|
||||||
"HeaderDeveloperInfo": "Developer Info",
|
"HeaderDeveloperInfo": "Developer Info",
|
||||||
"HeaderDeviceAccess": "Device Access",
|
"HeaderDeviceAccess": "Device Access",
|
||||||
"HeaderDevices": "Devices",
|
"HeaderDevices": "Devices",
|
||||||
"HeaderDirectPlayProfile": "Direct Playback Profile",
|
|
||||||
"HeaderDirectPlayProfileHelp": "Add direct playback profiles to indicate which formats the device can handle natively.",
|
|
||||||
"HeaderDownloadSync": "Download & Sync",
|
"HeaderDownloadSync": "Download & Sync",
|
||||||
"HeaderDummyChapter": "Chapter Images",
|
"HeaderDummyChapter": "Chapter Images",
|
||||||
"HeaderDVR": "DVR",
|
"HeaderDVR": "DVR",
|
||||||
|
@ -383,14 +375,9 @@
|
||||||
"HeaderFrequentlyPlayed": "Frequently Played",
|
"HeaderFrequentlyPlayed": "Frequently Played",
|
||||||
"HeaderGuestCast": "Guest Stars",
|
"HeaderGuestCast": "Guest Stars",
|
||||||
"HeaderGuideProviders": "TV Guide Data Providers",
|
"HeaderGuideProviders": "TV Guide Data Providers",
|
||||||
"HeaderHttpHeaders": "HTTP Headers",
|
|
||||||
"HeaderHttpsSettings": "HTTPS Settings",
|
"HeaderHttpsSettings": "HTTPS Settings",
|
||||||
"HeaderIdentification": "Identification",
|
|
||||||
"HeaderIdentificationCriteriaHelp": "Enter at least one identification criteria.",
|
|
||||||
"HeaderIdentificationHeader": "Identification Header",
|
|
||||||
"HeaderIdentifyItemHelp": "Enter one or more search criteria. Remove criteria to increase search results.",
|
"HeaderIdentifyItemHelp": "Enter one or more search criteria. Remove criteria to increase search results.",
|
||||||
"HeaderImageOptions": "Image Options",
|
"HeaderImageOptions": "Image Options",
|
||||||
"HeaderImageSettings": "Image Settings",
|
|
||||||
"HeaderInstall": "Install",
|
"HeaderInstall": "Install",
|
||||||
"HeaderInstantMix": "Instant Mix",
|
"HeaderInstantMix": "Instant Mix",
|
||||||
"HeaderKeepRecording": "Keep Recording",
|
"HeaderKeepRecording": "Keep Recording",
|
||||||
|
@ -439,8 +426,6 @@
|
||||||
"HeaderPluginInstallation": "Plugin Installation",
|
"HeaderPluginInstallation": "Plugin Installation",
|
||||||
"HeaderPortRanges": "Firewall and Proxy Settings",
|
"HeaderPortRanges": "Firewall and Proxy Settings",
|
||||||
"HeaderPreferredMetadataLanguage": "Preferred Metadata Language",
|
"HeaderPreferredMetadataLanguage": "Preferred Metadata Language",
|
||||||
"HeaderProfileInformation": "Profile Information",
|
|
||||||
"HeaderProfileServerSettingsHelp": "These values control how the server will present itself to clients.",
|
|
||||||
"HeaderRecentlyPlayed": "Recently Played",
|
"HeaderRecentlyPlayed": "Recently Played",
|
||||||
"HeaderRecordingMetadataSaving": "Recording Metadata",
|
"HeaderRecordingMetadataSaving": "Recording Metadata",
|
||||||
"HeaderRecordingOptions": "Recording Options",
|
"HeaderRecordingOptions": "Recording Options",
|
||||||
|
@ -449,8 +434,6 @@
|
||||||
"HeaderRemoteControl": "Remote Control",
|
"HeaderRemoteControl": "Remote Control",
|
||||||
"HeaderRemoveMediaFolder": "Remove Media Folder",
|
"HeaderRemoveMediaFolder": "Remove Media Folder",
|
||||||
"HeaderRemoveMediaLocation": "Remove Media Location",
|
"HeaderRemoveMediaLocation": "Remove Media Location",
|
||||||
"HeaderResponseProfile": "Response Profile",
|
|
||||||
"HeaderResponseProfileHelp": "Response profiles provide a way to customize information sent to the device when playing certain kinds of media.",
|
|
||||||
"HeaderRevisionHistory": "Revision History",
|
"HeaderRevisionHistory": "Revision History",
|
||||||
"HeaderRunningTasks": "Running Tasks",
|
"HeaderRunningTasks": "Running Tasks",
|
||||||
"HeaderScenes": "Scenes",
|
"HeaderScenes": "Scenes",
|
||||||
|
@ -468,7 +451,6 @@
|
||||||
"HeaderSeriesOptions": "Series Options",
|
"HeaderSeriesOptions": "Series Options",
|
||||||
"HeaderSeriesStatus": "Series Status",
|
"HeaderSeriesStatus": "Series Status",
|
||||||
"HeaderServerAddressSettings": "Server Address Settings",
|
"HeaderServerAddressSettings": "Server Address Settings",
|
||||||
"HeaderServerSettings": "Server Settings",
|
|
||||||
"HeaderSetupLibrary": "Setup your media libraries",
|
"HeaderSetupLibrary": "Setup your media libraries",
|
||||||
"HeaderSortBy": "Sort By",
|
"HeaderSortBy": "Sort By",
|
||||||
"HeaderSortOrder": "Sort Order",
|
"HeaderSortOrder": "Sort Order",
|
||||||
|
@ -478,20 +460,14 @@
|
||||||
"HeaderStopRecording": "Stop Recording",
|
"HeaderStopRecording": "Stop Recording",
|
||||||
"HeaderSubtitleAppearance": "Subtitle Appearance",
|
"HeaderSubtitleAppearance": "Subtitle Appearance",
|
||||||
"HeaderSubtitleDownloads": "Subtitle Downloads",
|
"HeaderSubtitleDownloads": "Subtitle Downloads",
|
||||||
"HeaderSubtitleProfile": "Subtitle Profile",
|
|
||||||
"HeaderSubtitleProfiles": "Subtitle Profiles",
|
|
||||||
"HeaderSubtitleProfilesHelp": "Subtitle profiles describe the subtitle formats supported by the device.",
|
|
||||||
"HeaderSyncPlayEnabled": "SyncPlay enabled",
|
"HeaderSyncPlayEnabled": "SyncPlay enabled",
|
||||||
"HeaderSyncPlaySelectGroup": "Join a group",
|
"HeaderSyncPlaySelectGroup": "Join a group",
|
||||||
"HeaderSyncPlaySettings": "SyncPlay Settings",
|
"HeaderSyncPlaySettings": "SyncPlay Settings",
|
||||||
"HeaderSyncPlayPlaybackSettings": "Playback",
|
"HeaderSyncPlayPlaybackSettings": "Playback",
|
||||||
"HeaderSyncPlayTimeSyncSettings": "Time sync",
|
"HeaderSyncPlayTimeSyncSettings": "Time sync",
|
||||||
"HeaderSystemDlnaProfiles": "System Profiles",
|
|
||||||
"HeaderTaskTriggers": "Task Triggers",
|
"HeaderTaskTriggers": "Task Triggers",
|
||||||
"HeaderThisUserIsCurrentlyDisabled": "This user is currently disabled",
|
"HeaderThisUserIsCurrentlyDisabled": "This user is currently disabled",
|
||||||
"HeaderTracks": "Tracks",
|
"HeaderTracks": "Tracks",
|
||||||
"HeaderTranscodingProfile": "Transcoding Profile",
|
|
||||||
"HeaderTranscodingProfileHelp": "Add transcoding profiles to indicate which formats should be used when transcoding is required.",
|
|
||||||
"HeaderTunerDevices": "Tuner Devices",
|
"HeaderTunerDevices": "Tuner Devices",
|
||||||
"HeaderTuners": "Tuners",
|
"HeaderTuners": "Tuners",
|
||||||
"HeaderTypeImageFetchers": "Image fetchers ({0})",
|
"HeaderTypeImageFetchers": "Image fetchers ({0})",
|
||||||
|
@ -506,9 +482,6 @@
|
||||||
"HeaderVideos": "Videos",
|
"HeaderVideos": "Videos",
|
||||||
"HeaderVideoType": "Video Type",
|
"HeaderVideoType": "Video Type",
|
||||||
"HeaderVideoTypes": "Video Types",
|
"HeaderVideoTypes": "Video Types",
|
||||||
"HeaderXmlDocumentAttribute": "XML Document Attribute",
|
|
||||||
"HeaderXmlDocumentAttributes": "XML Document Attributes",
|
|
||||||
"HeaderXmlSettings": "XML Settings",
|
|
||||||
"HeaderYears": "Years",
|
"HeaderYears": "Years",
|
||||||
"Help": "Help",
|
"Help": "Help",
|
||||||
"Hide": "Hide",
|
"Hide": "Hide",
|
||||||
|
@ -541,12 +514,7 @@
|
||||||
"LabelAirsBeforeSeason": "Airs before season",
|
"LabelAirsBeforeSeason": "Airs before season",
|
||||||
"LabelAirTime": "Air time",
|
"LabelAirTime": "Air time",
|
||||||
"LabelAlbum": "Album",
|
"LabelAlbum": "Album",
|
||||||
"LabelAlbumArtHelp": "PN used for album art, within the 'dlna:profileID' attribute on 'upnp:albumArtURI'. Some devices require a specific value, regardless of the size of the image.",
|
|
||||||
"LabelAlbumArtists": "Album artists",
|
"LabelAlbumArtists": "Album artists",
|
||||||
"LabelAlbumArtMaxHeight": "Album art max height",
|
|
||||||
"LabelAlbumArtMaxResHelp": "Maximum resolution of album art exposed via the 'upnp:albumArtURI' property.",
|
|
||||||
"LabelAlbumArtMaxWidth": "Album art max width",
|
|
||||||
"LabelAlbumArtPN": "Album art PN",
|
|
||||||
"LabelAlbumGain": "Album Gain",
|
"LabelAlbumGain": "Album Gain",
|
||||||
"LabelAllowedRemoteAddresses": "Remote IP address filter",
|
"LabelAllowedRemoteAddresses": "Remote IP address filter",
|
||||||
"LabelAllowedRemoteAddressesMode": "Remote IP address filter mode",
|
"LabelAllowedRemoteAddressesMode": "Remote IP address filter mode",
|
||||||
|
@ -618,12 +586,8 @@
|
||||||
"LabelDay": "Day of week",
|
"LabelDay": "Day of week",
|
||||||
"LabelDeathDate": "Death date",
|
"LabelDeathDate": "Death date",
|
||||||
"LabelDefaultScreen": "Default screen",
|
"LabelDefaultScreen": "Default screen",
|
||||||
"LabelDefaultUser": "Default user",
|
|
||||||
"LabelDefaultUserHelp": "Determine which user library should be displayed on connected devices. This can be overridden for each device using profiles.",
|
|
||||||
"LabelDeinterlaceMethod": "Deinterlacing method",
|
"LabelDeinterlaceMethod": "Deinterlacing method",
|
||||||
"LabelDeveloper": "Developer",
|
"LabelDeveloper": "Developer",
|
||||||
"LabelDeviceDescription": "Device description",
|
|
||||||
"LabelDidlMode": "DIDL mode",
|
|
||||||
"LabelDisableCustomCss": "Disable custom CSS code for theming/branding provided from the server.",
|
"LabelDisableCustomCss": "Disable custom CSS code for theming/branding provided from the server.",
|
||||||
"LabelDiscNumber": "Disc number",
|
"LabelDiscNumber": "Disc number",
|
||||||
"LabelDisplayLanguage": "Display language",
|
"LabelDisplayLanguage": "Display language",
|
||||||
|
@ -645,22 +609,10 @@
|
||||||
"LabelChapterImageResolution": "Resolution",
|
"LabelChapterImageResolution": "Resolution",
|
||||||
"LabelChapterImageResolutionHelp": "The resolution of the extracted chapter images. Changing this will have no effect on existing dummy chapters.",
|
"LabelChapterImageResolutionHelp": "The resolution of the extracted chapter images. Changing this will have no effect on existing dummy chapters.",
|
||||||
"LabelDynamicExternalId": "{0} Id",
|
"LabelDynamicExternalId": "{0} Id",
|
||||||
"LabelEmbedAlbumArtDidl": "Embed album art in DIDL",
|
|
||||||
"LabelEmbedAlbumArtDidlHelp": "Some devices prefer this method for getting the album art. Others may fail to play with this option enabled.",
|
|
||||||
"LabelEnableAudioVbr": "Enable VBR audio encoding",
|
"LabelEnableAudioVbr": "Enable VBR audio encoding",
|
||||||
"LabelEnableAudioVbrHelp": "Variable bitrate offers better quality to average bitrate ratio, but in some rare cases may cause buffering and compatibility issues.",
|
"LabelEnableAudioVbrHelp": "Variable bitrate offers better quality to average bitrate ratio, but in some rare cases may cause buffering and compatibility issues.",
|
||||||
"LabelEnableAutomaticPortMap": "Enable automatic port mapping",
|
"LabelEnableAutomaticPortMap": "Enable automatic port mapping",
|
||||||
"LabelEnableAutomaticPortMapHelp": "Automatically forward public ports on your router to local ports on your server via UPnP. This may not work with some router models or network configurations. Changes will not apply until after a server restart.",
|
"LabelEnableAutomaticPortMapHelp": "Automatically forward public ports on your router to local ports on your server via UPnP. This may not work with some router models or network configurations. Changes will not apply until after a server restart.",
|
||||||
"LabelEnableBlastAliveMessages": "Blast alive messages",
|
|
||||||
"LabelEnableBlastAliveMessagesHelp": "Enable this if the server is not detected reliably by other UPnP devices on your network.",
|
|
||||||
"LabelEnableDlnaClientDiscoveryInterval": "Client discovery interval",
|
|
||||||
"LabelEnableDlnaClientDiscoveryIntervalHelp": "Determine the duration in seconds between two SSDP searches.",
|
|
||||||
"LabelEnableDlnaDebugLogging": "Enable DLNA debug logging",
|
|
||||||
"LabelEnableDlnaDebugLoggingHelp": "Create large log files and should only be used as needed for troubleshooting purposes.",
|
|
||||||
"LabelEnableDlnaPlayTo": "Enable 'Play To' DLNA feature",
|
|
||||||
"LabelEnableDlnaPlayToHelp": "Detect devices within your network and offer the ability to control them remotely.",
|
|
||||||
"LabelEnableDlnaServer": "Enable DLNA server",
|
|
||||||
"LabelEnableDlnaServerHelp": "Allow UPnP devices on your network to browse and play content.",
|
|
||||||
"LabelEnableHardwareDecodingFor": "Enable hardware decoding for",
|
"LabelEnableHardwareDecodingFor": "Enable hardware decoding for",
|
||||||
"LabelEnableHttps": "Enable HTTPS",
|
"LabelEnableHttps": "Enable HTTPS",
|
||||||
"LabelEnableHttpsHelp": "Listen on the configured HTTPS port. A valid certificate must also be supplied for this to take effect.",
|
"LabelEnableHttpsHelp": "Listen on the configured HTTPS port. A valid certificate must also be supplied for this to take effect.",
|
||||||
|
@ -672,8 +624,6 @@
|
||||||
"LabelEnableLUFSScanHelp": "Clients can normalize audio playback to get equal loudness across tracks. This will make library scans longer and take more resources.",
|
"LabelEnableLUFSScanHelp": "Clients can normalize audio playback to get equal loudness across tracks. This will make library scans longer and take more resources.",
|
||||||
"LabelEnableRealtimeMonitor": "Enable real time monitoring",
|
"LabelEnableRealtimeMonitor": "Enable real time monitoring",
|
||||||
"LabelEnableRealtimeMonitorHelp": "Changes to files will be processed immediately on supported file systems.",
|
"LabelEnableRealtimeMonitorHelp": "Changes to files will be processed immediately on supported file systems.",
|
||||||
"LabelEnableSingleImageInDidlLimit": "Limit to single embedded image",
|
|
||||||
"LabelEnableSingleImageInDidlLimitHelp": "Some devices will not render properly if multiple images are embedded within DIDL.",
|
|
||||||
"LabelEncoderPreset": "Encoding preset",
|
"LabelEncoderPreset": "Encoding preset",
|
||||||
"LabelEndDate": "End date",
|
"LabelEndDate": "End date",
|
||||||
"LabelEpisodeNumber": "Episode number",
|
"LabelEpisodeNumber": "Episode number",
|
||||||
|
@ -702,10 +652,6 @@
|
||||||
"LabelHomeScreenSectionValue": "Home screen section {0}",
|
"LabelHomeScreenSectionValue": "Home screen section {0}",
|
||||||
"LabelHttpsPort": "Local HTTPS port number",
|
"LabelHttpsPort": "Local HTTPS port number",
|
||||||
"LabelHttpsPortHelp": "The TCP port number for the HTTPS server.",
|
"LabelHttpsPortHelp": "The TCP port number for the HTTPS server.",
|
||||||
"LabelIconMaxHeight": "Icon maximum height",
|
|
||||||
"LabelIconMaxResHelp": "Maximum resolution of icons exposed via the 'upnp:icon' property.",
|
|
||||||
"LabelIconMaxWidth": "Icon maximum width",
|
|
||||||
"LabelIdentificationFieldHelp": "A case-insensitive substring or regex expression.",
|
|
||||||
"LabelImageFetchersHelp": "Enable and rank your preferred image fetchers in order of priority.",
|
"LabelImageFetchersHelp": "Enable and rank your preferred image fetchers in order of priority.",
|
||||||
"LabelImageType": "Image type",
|
"LabelImageType": "Image type",
|
||||||
"LabelImportOnlyFavoriteChannels": "Restrict to channels marked as favorite",
|
"LabelImportOnlyFavoriteChannels": "Restrict to channels marked as favorite",
|
||||||
|
@ -741,9 +687,6 @@
|
||||||
"LabelLoginDisclaimer": "Login disclaimer",
|
"LabelLoginDisclaimer": "Login disclaimer",
|
||||||
"LabelLoginDisclaimerHelp": "A message that will be displayed at the bottom of the login page.",
|
"LabelLoginDisclaimerHelp": "A message that will be displayed at the bottom of the login page.",
|
||||||
"LabelLogs": "Logs",
|
"LabelLogs": "Logs",
|
||||||
"LabelManufacturer": "Manufacturer",
|
|
||||||
"LabelManufacturerUrl": "Manufacturer URL",
|
|
||||||
"LabelMatchType": "Match type",
|
|
||||||
"LabelMaxAudiobookResume": "Audiobook remaining minutes to resume",
|
"LabelMaxAudiobookResume": "Audiobook remaining minutes to resume",
|
||||||
"LabelMaxAudiobookResumeHelp": "Titles are assumed fully played if stopped when the remaining duration is less than this value.",
|
"LabelMaxAudiobookResumeHelp": "Titles are assumed fully played if stopped when the remaining duration is less than this value.",
|
||||||
"LabelMaxBackdropsPerItem": "Maximum number of backdrops per item",
|
"LabelMaxBackdropsPerItem": "Maximum number of backdrops per item",
|
||||||
|
@ -753,8 +696,6 @@
|
||||||
"LabelMaxParentalRating": "Maximum allowed parental rating",
|
"LabelMaxParentalRating": "Maximum allowed parental rating",
|
||||||
"LabelMaxResumePercentage": "Maximum resume percentage",
|
"LabelMaxResumePercentage": "Maximum resume percentage",
|
||||||
"LabelMaxResumePercentageHelp": "Titles are assumed fully played if stopped after this time.",
|
"LabelMaxResumePercentageHelp": "Titles are assumed fully played if stopped after this time.",
|
||||||
"LabelMaxStreamingBitrate": "Maximum streaming quality",
|
|
||||||
"LabelMaxStreamingBitrateHelp": "Specify a maximum bitrate when streaming.",
|
|
||||||
"LabelMessageText": "Message text",
|
"LabelMessageText": "Message text",
|
||||||
"LabelMessageTitle": "Message title",
|
"LabelMessageTitle": "Message title",
|
||||||
"LabelMetadata": "Metadata",
|
"LabelMetadata": "Metadata",
|
||||||
|
@ -766,7 +707,6 @@
|
||||||
"LabelMetadataReadersHelp": "Rank your preferred local metadata sources in order of priority. The first file found will be read.",
|
"LabelMetadataReadersHelp": "Rank your preferred local metadata sources in order of priority. The first file found will be read.",
|
||||||
"LabelMetadataSavers": "Metadata savers",
|
"LabelMetadataSavers": "Metadata savers",
|
||||||
"LabelMetadataSaversHelp": "Pick the file formats to use when saving your metadata.",
|
"LabelMetadataSaversHelp": "Pick the file formats to use when saving your metadata.",
|
||||||
"LabelMethod": "Method",
|
|
||||||
"LabelMinAudiobookResume": "Minimum Audiobook resume in minutes",
|
"LabelMinAudiobookResume": "Minimum Audiobook resume in minutes",
|
||||||
"LabelMinAudiobookResumeHelp": "Titles are assumed unplayed if stopped before this time.",
|
"LabelMinAudiobookResumeHelp": "Titles are assumed unplayed if stopped before this time.",
|
||||||
"LabelMinBackdropDownloadWidth": "Minimum backdrop download width",
|
"LabelMinBackdropDownloadWidth": "Minimum backdrop download width",
|
||||||
|
@ -774,16 +714,10 @@
|
||||||
"LabelMinResumeDurationHelp": "The shortest video length in seconds that will save playback location and let you resume.",
|
"LabelMinResumeDurationHelp": "The shortest video length in seconds that will save playback location and let you resume.",
|
||||||
"LabelMinResumePercentage": "Minimum resume percentage",
|
"LabelMinResumePercentage": "Minimum resume percentage",
|
||||||
"LabelMinResumePercentageHelp": "Titles are assumed unplayed if stopped before this time.",
|
"LabelMinResumePercentageHelp": "Titles are assumed unplayed if stopped before this time.",
|
||||||
"LabelModelDescription": "Model description",
|
|
||||||
"LabelModelName": "Model name",
|
|
||||||
"LabelModelNumber": "Model number",
|
|
||||||
"LabelModelUrl": "Model URL",
|
|
||||||
"LabelMovieCategories": "Movie categories",
|
"LabelMovieCategories": "Movie categories",
|
||||||
"LabelMoviePrefix": "Movie prefix",
|
"LabelMoviePrefix": "Movie prefix",
|
||||||
"LabelMoviePrefixHelp": "If a prefix is applied to movie titles, enter it here so the server can handle it properly.",
|
"LabelMoviePrefixHelp": "If a prefix is applied to movie titles, enter it here so the server can handle it properly.",
|
||||||
"LabelMovieRecordingPath": "Movie recording path",
|
"LabelMovieRecordingPath": "Movie recording path",
|
||||||
"LabelMusicStreamingTranscodingBitrate": "Music transcoding bitrate",
|
|
||||||
"LabelMusicStreamingTranscodingBitrateHelp": "Specify a maximum bitrate when streaming music.",
|
|
||||||
"LabelName": "Name",
|
"LabelName": "Name",
|
||||||
"LabelNewName": "New name",
|
"LabelNewName": "New name",
|
||||||
"LabelNewPassword": "New password",
|
"LabelNewPassword": "New password",
|
||||||
|
@ -823,15 +757,8 @@
|
||||||
"LabelPostProcessorArgumentsHelp": "Use {path} as the path to the recording file.",
|
"LabelPostProcessorArgumentsHelp": "Use {path} as the path to the recording file.",
|
||||||
"LabelPreferredDisplayLanguage": "Preferred display language",
|
"LabelPreferredDisplayLanguage": "Preferred display language",
|
||||||
"LabelPreferredSubtitleLanguage": "Preferred subtitle language",
|
"LabelPreferredSubtitleLanguage": "Preferred subtitle language",
|
||||||
"LabelProfileAudioCodecs": "Audio codecs",
|
|
||||||
"LabelProfileCodecs": "Codecs",
|
|
||||||
"LabelProfileCodecsHelp": "Separated by comma. This can be left empty to apply to all codecs.",
|
|
||||||
"LabelProfileContainer": "Container",
|
"LabelProfileContainer": "Container",
|
||||||
"LabelProfileContainersHelp": "Separated by comma. This can be left empty to apply to all containers.",
|
|
||||||
"LabelProfileVideoCodecs": "Video codecs",
|
|
||||||
"LabelProtocol": "Protocol",
|
"LabelProtocol": "Protocol",
|
||||||
"LabelProtocolInfo": "Protocol info",
|
|
||||||
"LabelProtocolInfoHelp": "The value that will be used when responding to GetProtocolInfo requests from the device.",
|
|
||||||
"LabelPublicHttpPort": "Public HTTP port number",
|
"LabelPublicHttpPort": "Public HTTP port number",
|
||||||
"LabelPublicHttpPortHelp": "The public port number that should be mapped to the local HTTP port.",
|
"LabelPublicHttpPortHelp": "The public port number that should be mapped to the local HTTP port.",
|
||||||
"LabelPublicHttpsPort": "Public HTTPS port number",
|
"LabelPublicHttpsPort": "Public HTTPS port number",
|
||||||
|
@ -862,7 +789,6 @@
|
||||||
"LabelSelectFolderGroups": "Automatically group content from the following folders into views such as 'Movies', 'Music' and 'TV'",
|
"LabelSelectFolderGroups": "Automatically group content from the following folders into views such as 'Movies', 'Music' and 'TV'",
|
||||||
"LabelSelectFolderGroupsHelp": "Folders that are unchecked will be displayed by themselves in their own view.",
|
"LabelSelectFolderGroupsHelp": "Folders that are unchecked will be displayed by themselves in their own view.",
|
||||||
"LabelSelectVersionToInstall": "Select version to install",
|
"LabelSelectVersionToInstall": "Select version to install",
|
||||||
"LabelSerialNumber": "Serial number",
|
|
||||||
"LabelSeriesRecordingPath": "Series recording path",
|
"LabelSeriesRecordingPath": "Series recording path",
|
||||||
"LabelServerHost": "Host",
|
"LabelServerHost": "Host",
|
||||||
"LabelServerHostHelp": "192.168.1.100:8096 or https://myserver.com",
|
"LabelServerHostHelp": "192.168.1.100:8096 or https://myserver.com",
|
||||||
|
@ -879,8 +805,6 @@
|
||||||
"LabelSkipIfGraphicalSubsPresentHelp": "Keeping text versions of subtitles will result in more efficient delivery and decrease the likelihood of video transcoding.",
|
"LabelSkipIfGraphicalSubsPresentHelp": "Keeping text versions of subtitles will result in more efficient delivery and decrease the likelihood of video transcoding.",
|
||||||
"LabelSlowResponseEnabled": "Log a warning message if the server was slow to answer",
|
"LabelSlowResponseEnabled": "Log a warning message if the server was slow to answer",
|
||||||
"LabelSlowResponseTime": "Time in ms after which a response is considered slow",
|
"LabelSlowResponseTime": "Time in ms after which a response is considered slow",
|
||||||
"LabelSonyAggregationFlags": "Sony aggregation flags",
|
|
||||||
"LabelSonyAggregationFlagsHelp": "Determine the content of the 'aggregationFlags' element in the 'urn:schemas-sonycom:av' namespace.",
|
|
||||||
"LabelSortBy": "Sort by",
|
"LabelSortBy": "Sort by",
|
||||||
"LabelSortName": "Sort name",
|
"LabelSortName": "Sort name",
|
||||||
"LabelSortOrder": "Sort order",
|
"LabelSortOrder": "Sort order",
|
||||||
|
@ -895,10 +819,8 @@
|
||||||
"LabelStopWhenPossible": "Stop when possible",
|
"LabelStopWhenPossible": "Stop when possible",
|
||||||
"LabelStreamType": "Stream type",
|
"LabelStreamType": "Stream type",
|
||||||
"LabelSubtitleDownloaders": "Subtitle downloaders",
|
"LabelSubtitleDownloaders": "Subtitle downloaders",
|
||||||
"LabelSubtitleFormatHelp": "Example: srt",
|
|
||||||
"LabelSubtitlePlaybackMode": "Subtitle mode",
|
"LabelSubtitlePlaybackMode": "Subtitle mode",
|
||||||
"LabelSubtitleVerticalPosition": "Vertical position",
|
"LabelSubtitleVerticalPosition": "Vertical position",
|
||||||
"LabelSupportedMediaTypes": "Supported Media Types",
|
|
||||||
"LabelSyncPlayAccess": "SyncPlay access",
|
"LabelSyncPlayAccess": "SyncPlay access",
|
||||||
"LabelSyncPlayAccessCreateAndJoinGroups": "Allow user to create and join groups",
|
"LabelSyncPlayAccessCreateAndJoinGroups": "Allow user to create and join groups",
|
||||||
"LabelSyncPlayAccessJoinGroups": "Allow user to join groups",
|
"LabelSyncPlayAccessJoinGroups": "Allow user to join groups",
|
||||||
|
@ -973,8 +895,6 @@
|
||||||
"LabelUnstable": "Unstable",
|
"LabelUnstable": "Unstable",
|
||||||
"LabelUser": "User",
|
"LabelUser": "User",
|
||||||
"LabelUserAgent": "User agent",
|
"LabelUserAgent": "User agent",
|
||||||
"LabelUserLibrary": "User library",
|
|
||||||
"LabelUserLibraryHelp": "Select which user library to display to the device. Leave empty to inherit the default setting.",
|
|
||||||
"LabelUserLoginAttemptsBeforeLockout": "Failed login tries before user is locked out",
|
"LabelUserLoginAttemptsBeforeLockout": "Failed login tries before user is locked out",
|
||||||
"LabelUserMaxActiveSessions": "Maximum number of simultaneous user sessions",
|
"LabelUserMaxActiveSessions": "Maximum number of simultaneous user sessions",
|
||||||
"LabelUsername": "Username",
|
"LabelUsername": "Username",
|
||||||
|
@ -990,10 +910,6 @@
|
||||||
"LabelVideoResolution": "Video resolution",
|
"LabelVideoResolution": "Video resolution",
|
||||||
"LabelWeb": "Web",
|
"LabelWeb": "Web",
|
||||||
"LabelWebVersion": "Web version",
|
"LabelWebVersion": "Web version",
|
||||||
"LabelXDlnaCap": "Device Capability ID",
|
|
||||||
"LabelXDlnaCapHelp": "Determine the content of the 'X_DLNACAP' element in the 'urn:schemas-dlna-org:device-1-0' namespace.",
|
|
||||||
"LabelXDlnaDoc": "Device Class ID",
|
|
||||||
"LabelXDlnaDocHelp": "Determine the content of the 'X_DLNADOC' element in the 'urn:schemas-dlna-org:device-1-0' namespace.",
|
|
||||||
"LabelYear": "Year",
|
"LabelYear": "Year",
|
||||||
"LabelYoureDone": "You're Done!",
|
"LabelYoureDone": "You're Done!",
|
||||||
"LabelZipCode": "Zip Code",
|
"LabelZipCode": "Zip Code",
|
||||||
|
@ -1070,7 +986,6 @@
|
||||||
"MessageConfirmAppExit": "Do you want to exit?",
|
"MessageConfirmAppExit": "Do you want to exit?",
|
||||||
"MessageConfirmDeleteGuideProvider": "Are you sure you wish to delete this guide provider?",
|
"MessageConfirmDeleteGuideProvider": "Are you sure you wish to delete this guide provider?",
|
||||||
"MessageConfirmDeleteTunerDevice": "Are you sure you wish to delete this device?",
|
"MessageConfirmDeleteTunerDevice": "Are you sure you wish to delete this device?",
|
||||||
"MessageConfirmProfileDeletion": "Are you sure you wish to delete this profile?",
|
|
||||||
"MessageConfirmRecordingCancellation": "Cancel recording?",
|
"MessageConfirmRecordingCancellation": "Cancel recording?",
|
||||||
"MessageConfirmRemoveMediaLocation": "Are you sure you wish to remove this location?",
|
"MessageConfirmRemoveMediaLocation": "Are you sure you wish to remove this location?",
|
||||||
"MessageConfirmRestart": "Are you sure you wish to restart Jellyfin?",
|
"MessageConfirmRestart": "Are you sure you wish to restart Jellyfin?",
|
||||||
|
@ -1215,7 +1130,6 @@
|
||||||
"OptionAutomaticallyGroupSeries": "Automatically merge series that are spread across multiple folders",
|
"OptionAutomaticallyGroupSeries": "Automatically merge series that are spread across multiple folders",
|
||||||
"OptionAutomaticallyGroupSeriesHelp": "Series that are spread across multiple folders within this library will be automatically merged into a single series.",
|
"OptionAutomaticallyGroupSeriesHelp": "Series that are spread across multiple folders within this library will be automatically merged into a single series.",
|
||||||
"OptionBluray": "BD",
|
"OptionBluray": "BD",
|
||||||
"OptionCaptionInfoExSamsung": "CaptionInfoEx (Samsung)",
|
|
||||||
"OptionCommunityRating": "Community Rating",
|
"OptionCommunityRating": "Community Rating",
|
||||||
"OptionCriticRating": "Critics Rating",
|
"OptionCriticRating": "Critics Rating",
|
||||||
"OptionDaily": "Daily",
|
"OptionDaily": "Daily",
|
||||||
|
@ -1230,28 +1144,19 @@
|
||||||
"OptionDisplayFolderView": "Display a folder view to show plain media folders",
|
"OptionDisplayFolderView": "Display a folder view to show plain media folders",
|
||||||
"OptionDisplayFolderViewHelp": "Display folders alongside your other media libraries. This can be useful if you'd like to have a plain folder view.",
|
"OptionDisplayFolderViewHelp": "Display folders alongside your other media libraries. This can be useful if you'd like to have a plain folder view.",
|
||||||
"OptionDvd": "DVD",
|
"OptionDvd": "DVD",
|
||||||
"OptionEmbedSubtitles": "Embed within container",
|
|
||||||
"OptionEnableAccessFromAllDevices": "Enable access from all devices",
|
"OptionEnableAccessFromAllDevices": "Enable access from all devices",
|
||||||
"OptionEnableAccessToAllChannels": "Enable access to all channels",
|
"OptionEnableAccessToAllChannels": "Enable access to all channels",
|
||||||
"OptionEnableAccessToAllLibraries": "Enable access to all libraries",
|
"OptionEnableAccessToAllLibraries": "Enable access to all libraries",
|
||||||
"OptionEnableExternalContentInSuggestions": "Enable external content in suggestions",
|
"OptionEnableExternalContentInSuggestions": "Enable external content in suggestions",
|
||||||
"OptionEnableExternalContentInSuggestionsHelp": "Allow internet trailers and live TV programs to be included within suggested content.",
|
"OptionEnableExternalContentInSuggestionsHelp": "Allow internet trailers and live TV programs to be included within suggested content.",
|
||||||
"OptionEnableForAllTuners": "Enable for all tuner devices",
|
"OptionEnableForAllTuners": "Enable for all tuner devices",
|
||||||
"OptionEnableM2tsMode": "Enable M2TS mode",
|
|
||||||
"OptionEnableM2tsModeHelp": "Enable M2TS mode when encoding to MPEG-TS.",
|
|
||||||
"OptionEquals": "Equals",
|
|
||||||
"OptionEstimateContentLength": "Estimate content length when transcoding",
|
|
||||||
"OptionEveryday": "Every day",
|
"OptionEveryday": "Every day",
|
||||||
"OptionExternallyDownloaded": "External download",
|
|
||||||
"OptionExtractChapterImage": "Enable chapter image extraction",
|
"OptionExtractChapterImage": "Enable chapter image extraction",
|
||||||
"OptionForceRemoteSourceTranscoding": "Force transcoding of remote media sources such as Live TV",
|
"OptionForceRemoteSourceTranscoding": "Force transcoding of remote media sources such as Live TV",
|
||||||
"OptionHasThemeSong": "Theme Song",
|
"OptionHasThemeSong": "Theme Song",
|
||||||
"OptionHasThemeVideo": "Theme Video",
|
"OptionHasThemeVideo": "Theme Video",
|
||||||
"OptionHideUser": "Hide this user from login screens",
|
"OptionHideUser": "Hide this user from login screens",
|
||||||
"OptionHideUserFromLoginHelp": "Useful for private or hidden administrator accounts. The user will need to sign in manually by entering their username and password.",
|
"OptionHideUserFromLoginHelp": "Useful for private or hidden administrator accounts. The user will need to sign in manually by entering their username and password.",
|
||||||
"OptionHlsSegmentedSubtitles": "HLS segmented subtitles",
|
|
||||||
"OptionIgnoreTranscodeByteRangeRequests": "Ignore transcode byte range requests",
|
|
||||||
"OptionIgnoreTranscodeByteRangeRequestsHelp": "These requests will be honored but will ignore the byte range header.",
|
|
||||||
"OptionImdbRating": "IMDb Rating",
|
"OptionImdbRating": "IMDb Rating",
|
||||||
"OptionIsHD": "HD",
|
"OptionIsHD": "HD",
|
||||||
"OptionIsSD": "SD",
|
"OptionIsSD": "SD",
|
||||||
|
@ -1264,27 +1169,16 @@
|
||||||
"OptionNew": "New…",
|
"OptionNew": "New…",
|
||||||
"OptionOnInterval": "On an interval",
|
"OptionOnInterval": "On an interval",
|
||||||
"OptionParentalRating": "Parental Rating",
|
"OptionParentalRating": "Parental Rating",
|
||||||
"OptionPlainStorageFolders": "Display all folders as plain storage folders",
|
|
||||||
"OptionPlainStorageFoldersHelp": "All folders are represented in DIDL as 'object.container.storageFolder' instead of a more specific type, such as 'object.container.person.musicArtist'.",
|
|
||||||
"OptionPlainVideoItems": "Display all videos as plain video items",
|
|
||||||
"OptionPlainVideoItemsHelp": "All videos are represented in DIDL as 'object.item.videoItem' instead of a more specific type, such as 'object.item.videoItem.movie'.",
|
|
||||||
"OptionPlayCount": "Play Count",
|
"OptionPlayCount": "Play Count",
|
||||||
"OptionPremiereDate": "Premiere Date",
|
"OptionPremiereDate": "Premiere Date",
|
||||||
"OptionProtocolHls": "HTTP Live Streaming (HLS)",
|
|
||||||
"OptionProtocolHttp": "HTTP",
|
|
||||||
"OptionRandom": "Random",
|
"OptionRandom": "Random",
|
||||||
"OptionRegex": "Regex",
|
|
||||||
"OptionReleaseDate": "Release Date",
|
"OptionReleaseDate": "Release Date",
|
||||||
"OptionReportByteRangeSeekingWhenTranscoding": "Report that the server supports byte seeking when transcoding",
|
|
||||||
"OptionReportByteRangeSeekingWhenTranscodingHelp": "This is required for some devices that don't time seek very well.",
|
|
||||||
"OptionRequirePerfectSubtitleMatch": "Only download subtitles that are a perfect match for video files",
|
"OptionRequirePerfectSubtitleMatch": "Only download subtitles that are a perfect match for video files",
|
||||||
"OptionRequirePerfectSubtitleMatchHelp": "Requiring a perfect match will filter subtitles to include only those that have been tested and verified with your exact video file. Unchecking this will increase the likelihood of subtitles being downloaded, but will increase the chances of mistimed or incorrect subtitle text.",
|
"OptionRequirePerfectSubtitleMatchHelp": "Requiring a perfect match will filter subtitles to include only those that have been tested and verified with your exact video file. Unchecking this will increase the likelihood of subtitles being downloaded, but will increase the chances of mistimed or incorrect subtitle text.",
|
||||||
"OptionResElement": "'res' element",
|
|
||||||
"OptionResumable": "Resumable",
|
"OptionResumable": "Resumable",
|
||||||
"OptionSaveMetadataAsHidden": "Save metadata and images as hidden files",
|
"OptionSaveMetadataAsHidden": "Save metadata and images as hidden files",
|
||||||
"OptionSaveMetadataAsHiddenHelp": "Changing this will apply to new metadata saved going forward. Existing metadata files will be updated the next time they are saved by the server.",
|
"OptionSaveMetadataAsHiddenHelp": "Changing this will apply to new metadata saved going forward. Existing metadata files will be updated the next time they are saved by the server.",
|
||||||
"OptionSpecialEpisode": "Specials",
|
"OptionSpecialEpisode": "Specials",
|
||||||
"OptionSubstring": "Substring",
|
|
||||||
"OptionTrackName": "Track Name",
|
"OptionTrackName": "Track Name",
|
||||||
"OptionTvdbRating": "TheTVDB Rating",
|
"OptionTvdbRating": "TheTVDB Rating",
|
||||||
"OptionUnairedEpisode": "Unaired Episodes",
|
"OptionUnairedEpisode": "Unaired Episodes",
|
||||||
|
@ -1501,14 +1395,10 @@
|
||||||
"Sunday": "Sunday",
|
"Sunday": "Sunday",
|
||||||
"SyncPlayAccessHelp": "The SyncPlay feature enables to sync playback with other devices. Select the level of access this user has to the SyncPlay.",
|
"SyncPlayAccessHelp": "The SyncPlay feature enables to sync playback with other devices. Select the level of access this user has to the SyncPlay.",
|
||||||
"SyncPlayGroupDefaultTitle": "{0}'s group",
|
"SyncPlayGroupDefaultTitle": "{0}'s group",
|
||||||
"SystemDlnaProfilesHelp": "System profiles are read-only. Changes to a system profile will be saved to a new custom profile.",
|
|
||||||
"TabAccess": "Access",
|
"TabAccess": "Access",
|
||||||
"TabAdvanced": "Advanced",
|
"TabAdvanced": "Advanced",
|
||||||
"TabCatalog": "Catalog",
|
"TabCatalog": "Catalog",
|
||||||
"TabCodecs": "Codecs",
|
|
||||||
"TabContainers": "Containers",
|
|
||||||
"TabDashboard": "Dashboard",
|
"TabDashboard": "Dashboard",
|
||||||
"TabDirectPlay": "Direct Playback",
|
|
||||||
"TabLatest": "Recently Added",
|
"TabLatest": "Recently Added",
|
||||||
"TabLogs": "Logs",
|
"TabLogs": "Logs",
|
||||||
"TabMusic": "Music",
|
"TabMusic": "Music",
|
||||||
|
@ -1519,9 +1409,7 @@
|
||||||
"TabOther": "Other",
|
"TabOther": "Other",
|
||||||
"TabParentalControl": "Parental Control",
|
"TabParentalControl": "Parental Control",
|
||||||
"TabPlugins": "Plugins",
|
"TabPlugins": "Plugins",
|
||||||
"TabProfiles": "Profiles",
|
|
||||||
"TabRepositories": "Repositories",
|
"TabRepositories": "Repositories",
|
||||||
"TabResponses": "Responses",
|
|
||||||
"TabScheduledTasks": "Scheduled Tasks",
|
"TabScheduledTasks": "Scheduled Tasks",
|
||||||
"TabServer": "Server",
|
"TabServer": "Server",
|
||||||
"TabStreaming": "Streaming",
|
"TabStreaming": "Streaming",
|
||||||
|
@ -1578,10 +1466,6 @@
|
||||||
"UserMenu": "User Menu",
|
"UserMenu": "User Menu",
|
||||||
"UserProfilesIntro": "Jellyfin includes support for user profiles with granular display settings, play state, and parental controls.",
|
"UserProfilesIntro": "Jellyfin includes support for user profiles with granular display settings, play state, and parental controls.",
|
||||||
"ValueAlbumCount": "{0} albums",
|
"ValueAlbumCount": "{0} albums",
|
||||||
"ValueAudioCodec": "Audio Codec: {0}",
|
|
||||||
"ValueCodec": "Codec: {0}",
|
|
||||||
"ValueConditions": "Conditions: {0}",
|
|
||||||
"ValueContainer": "Container: {0}",
|
|
||||||
"ValueDiscNumber": "Disc {0}",
|
"ValueDiscNumber": "Disc {0}",
|
||||||
"ValueEpisodeCount": "{0} episodes",
|
"ValueEpisodeCount": "{0} episodes",
|
||||||
"ValueMinutes": "{0} min",
|
"ValueMinutes": "{0} min",
|
||||||
|
@ -1599,7 +1483,6 @@
|
||||||
"ValueSpecialEpisodeName": "Special - {0}",
|
"ValueSpecialEpisodeName": "Special - {0}",
|
||||||
"ValueTimeLimitMultiHour": "Time limit: {0} hours",
|
"ValueTimeLimitMultiHour": "Time limit: {0} hours",
|
||||||
"ValueTimeLimitSingleHour": "Time limit: 1 hour",
|
"ValueTimeLimitSingleHour": "Time limit: 1 hour",
|
||||||
"ValueVideoCodec": "Video Codec: {0}",
|
|
||||||
"Vertical": "Vertical",
|
"Vertical": "Vertical",
|
||||||
"Video": "Video",
|
"Video": "Video",
|
||||||
"VideoAudio": "Video Audio",
|
"VideoAudio": "Video Audio",
|
||||||
|
@ -1615,7 +1498,6 @@
|
||||||
"WriteAccessRequired": "Jellyfin requires write access to this folder. Please ensure write access and try again.",
|
"WriteAccessRequired": "Jellyfin requires write access to this folder. Please ensure write access and try again.",
|
||||||
"Writer": "Writer",
|
"Writer": "Writer",
|
||||||
"Writers": "Writers",
|
"Writers": "Writers",
|
||||||
"XmlDocumentAttributeListHelp": "These attributes are applied to the root element of every XML response.",
|
|
||||||
"XmlTvKidsCategoriesHelp": "Programs with these categories will be displayed as programs for children. Separate multiple with '|'.",
|
"XmlTvKidsCategoriesHelp": "Programs with these categories will be displayed as programs for children. Separate multiple with '|'.",
|
||||||
"XmlTvMovieCategoriesHelp": "Programs with these categories will be displayed as movies. Separate multiple with '|'.",
|
"XmlTvMovieCategoriesHelp": "Programs with these categories will be displayed as movies. Separate multiple with '|'.",
|
||||||
"XmlTvNewsCategoriesHelp": "Programs with these categories will be displayed as news programs. Separate multiple with '|'.",
|
"XmlTvNewsCategoriesHelp": "Programs with these categories will be displayed as news programs. Separate multiple with '|'.",
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue