Merge branch 'master' into blurred-pdf-fixed

This commit is contained in:
Zourlo 2023-03-10 17:40:27 +09:00 committed by GitHub
commit 2848f6295b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
109 changed files with 2259 additions and 1324 deletions

View File

@ -46,6 +46,7 @@ module.exports = {
'keyword-spacing': ['error'],
'no-throw-literal': ['error'],
'max-statements-per-line': ['error'],
'max-params': ['error', 7],
'no-duplicate-imports': ['error'],
'no-empty-function': ['error'],
'no-floating-decimal': ['error'],

View File

@ -21,11 +21,11 @@ jobs:
- name: Checkout repository
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
- name: Initialize CodeQL
uses: github/codeql-action/init@17573ee1cc1b9d061760f3a006fc4aac4f944fd5 # v2.2.4
uses: github/codeql-action/init@32dc499307d133bb5085bae78498c0ac2cf762d5 # v2.2.5
with:
languages: ${{ matrix.language }}
queries: +security-extended
- name: Autobuild
uses: github/codeql-action/autobuild@17573ee1cc1b9d061760f3a006fc4aac4f944fd5 # v2.2.4
uses: github/codeql-action/autobuild@32dc499307d133bb5085bae78498c0ac2cf762d5 # v2.2.5
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@17573ee1cc1b9d061760f3a006fc4aac4f944fd5 # v2.2.4
uses: github/codeql-action/analyze@32dc499307d133bb5085bae78498c0ac2cf762d5 # v2.2.5

View File

@ -59,6 +59,7 @@
- [Vankerkom](https://github.com/vankerkom)
- [edvwib](https://github.com/edvwib)
- [Rob Farraher](https://github.com/farraherbg)
- [Pier-Luc Ducharme](https://github.com/pl-ducharme)
# Emby Contributors

1235
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -5,7 +5,7 @@
"repository": "https://github.com/jellyfin/jellyfin-web",
"license": "GPL-2.0-or-later",
"devDependencies": {
"@babel/core": "7.20.12",
"@babel/core": "7.21.0",
"@babel/eslint-parser": "7.19.1",
"@babel/eslint-plugin": "7.19.1",
"@babel/plugin-proposal-class-properties": "7.18.6",
@ -13,14 +13,14 @@
"@babel/plugin-transform-modules-umd": "7.18.6",
"@babel/preset-env": "7.20.2",
"@babel/preset-react": "7.18.6",
"@babel/preset-typescript": "7.18.6",
"@babel/preset-typescript": "7.21.0",
"@types/escape-html": "1.0.2",
"@types/loadable__component": "5.13.4",
"@types/lodash-es": "4.17.6",
"@types/react": "17.0.53",
"@types/react-dom": "17.0.18",
"@typescript-eslint/eslint-plugin": "5.50.0",
"@typescript-eslint/parser": "5.50.0",
"@types/react-dom": "17.0.19",
"@typescript-eslint/eslint-plugin": "5.54.0",
"@typescript-eslint/parser": "5.54.0",
"@uupaa/dynamic-import-polyfill": "1.0.2",
"autoprefixer": "10.4.13",
"babel-loader": "9.1.2",
@ -30,10 +30,10 @@
"copy-webpack-plugin": "11.0.0",
"cross-env": "7.0.3",
"css-loader": "6.7.3",
"cssnano": "5.1.14",
"cssnano": "5.1.15",
"es-check": "7.1.0",
"eslint": "8.33.0",
"eslint-plugin-compat": "4.0.2",
"eslint": "8.35.0",
"eslint-plugin-compat": "4.1.2",
"eslint-plugin-eslint-comments": "3.2.0",
"eslint-plugin-import": "2.27.5",
"eslint-plugin-jsx-a11y": "6.7.1",
@ -49,15 +49,15 @@
"postcss-loader": "7.0.2",
"postcss-preset-env": "8.0.1",
"postcss-scss": "4.0.6",
"sass": "1.58.0",
"sass": "1.58.3",
"sass-loader": "13.2.0",
"source-map-loader": "4.0.1",
"style-loader": "3.3.1",
"stylelint": "14.16.1",
"stylelint": "15.2.0",
"stylelint-config-rational-order": "0.1.2",
"stylelint-no-browser-hacks": "1.2.1",
"stylelint-order": "6.0.1",
"stylelint-scss": "4.3.0",
"stylelint-order": "6.0.2",
"stylelint-scss": "4.4.0",
"ts-loader": "9.4.2",
"typescript": "4.9.5",
"webpack": "5.75.0",
@ -77,23 +77,23 @@
"@jellyfin/libass-wasm": "4.1.1",
"@jellyfin/sdk": "unstable",
"@loadable/component": "5.15.3",
"blurhash": "2.0.4",
"blurhash": "2.0.5",
"classlist.js": "https://github.com/eligrey/classList.js/archive/1.2.20180112.tar.gz",
"classnames": "2.3.2",
"core-js": "3.27.2",
"core-js": "3.29.0",
"date-fns": "2.29.3",
"dompurify": "2.4.3",
"dompurify": "2.4.4",
"epubjs": "0.4.2",
"escape-html": "1.0.3",
"fast-text-encoding": "1.0.6",
"flv.js": "1.6.2",
"headroom.js": "0.12.0",
"history": "5.3.0",
"hls.js": "0.14.17",
"hls.js": "1.3.4",
"intersection-observer": "0.12.2",
"jellyfin-apiclient": "1.10.0",
"jquery": "3.6.3",
"jstree": "3.3.14",
"jstree": "3.3.15",
"libarchive.js": "1.3.0",
"lodash-es": "4.17.21",
"marked": "4.2.12",
@ -102,7 +102,7 @@
"pdfjs-dist": "2.16.105",
"react": "17.0.2",
"react-dom": "17.0.2",
"react-router-dom": "6.8.0",
"react-router-dom": "6.8.2",
"resize-observer-polyfill": "1.5.1",
"screenfull": "6.0.2",
"sortablejs": "1.15.0",

View File

@ -1,5 +1,5 @@
import React, { FunctionComponent, useEffect, useState } from 'react';
import { Outlet, useNavigate } from 'react-router-dom';
import { Outlet, useLocation, useNavigate } from 'react-router-dom';
import type { ConnectResponse } from 'jellyfin-apiclient';
import alert from './alert';
@ -31,11 +31,11 @@ const ConnectionRequired: FunctionComponent<ConnectionRequiredProps> = ({
isUserRequired = true
}) => {
const navigate = useNavigate();
const location = useLocation();
const [ isLoading, setIsLoading ] = useState(true);
useEffect(() => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const bounce = async (connectionResponse: ConnectResponse) => {
switch (connectionResponse.State) {
case ConnectionState.SignedIn:
@ -45,12 +45,12 @@ const ConnectionRequired: FunctionComponent<ConnectionRequiredProps> = ({
return;
case ConnectionState.ServerSignIn:
// Bounce to the login page
console.debug('[ConnectionRequired] not logged in, redirecting to login page');
navigate(BounceRoutes.Login, {
state: {
serverid: connectionResponse.ApiClient.serverId()
}
});
if (location.pathname === BounceRoutes.Login) {
setIsLoading(false);
} else {
console.debug('[ConnectionRequired] not logged in, redirecting to login page');
navigate(`${BounceRoutes.Login}?serverid=${connectionResponse.ApiClient.serverId()}`);
}
return;
case ConnectionState.ServerSelection:
// Bounce to select server page
@ -144,7 +144,7 @@ const ConnectionRequired: FunctionComponent<ConnectionRequiredProps> = ({
};
validateConnection();
}, [ isAdminRequired, isUserRequired, navigate ]);
}, [ isAdminRequired, isUserRequired, location.pathname, navigate ]);
if (isLoading) {
return <Loading />;

View File

@ -6,7 +6,7 @@ import dom from '../../scripts/dom';
import '../../elements/emby-button/emby-button';
import './actionSheet.scss';
import 'material-design-icons-iconfont';
import '../../assets/css/scrollstyles.scss';
import '../../styles/scrollstyles.scss';
import '../../components/listview/listview.scss';
function getOffsets(elems) {

View File

@ -124,7 +124,7 @@ class AppRouter {
isBack: action === Action.Pop
});
} else {
console.info('[appRouter] "%s" route not found', normalizedPath, location);
// The route is not registered here, so it should be handled by react-router
this.currentRouteInfo = {
route: {},
path: normalizedPath + location.search

View File

@ -773,27 +773,24 @@ import { appRouter } from '../appRouter';
* @param {Object} item - Item used to generate the footer text.
* @param {Object} apiClient - API client instance.
* @param {Object} options - Options used to generate the footer text.
* @param {string} showTitle - Flag to show the title in the footer.
* @param {boolean} forceName - Flag to force showing the name of the item.
* @param {boolean} overlayText - Flag to show overlay text.
* @param {Object} imgUrl - Object representing the card's image URL.
* @param {string} footerClass - CSS classes of the footer element.
* @param {string} progressHtml - HTML markup of the progress bar element.
* @param {string} logoUrl - URL of the logo for the item.
* @param {boolean} isOuterFooter - Flag to mark the text as outer footer.
* @param {Object} flags - Various flags for the footer
* @param {Object} urls - Various urls for the footer
* @returns {string} HTML markup of the card's footer text element.
*/
function getCardFooterText(item, apiClient, options, showTitle, forceName, overlayText, imgUrl, footerClass, progressHtml, logoUrl, isOuterFooter) {
function getCardFooterText(item, apiClient, options, footerClass, progressHtml, flags, urls) {
item = item.ProgramInfo || item;
let html = '';
if (logoUrl) {
html += '<div class="lazy cardFooterLogo" data-src="' + logoUrl + '"></div>';
if (urls.logoUrl) {
html += '<div class="lazy cardFooterLogo" data-src="' + urls.logoUrl + '"></div>';
}
const showOtherText = isOuterFooter ? !overlayText : overlayText;
const showTitle = options.showTitle === 'auto' ? true : (options.showTitle || item.Type === 'PhotoAlbum' || item.Type === 'Folder');
const showOtherText = flags.isOuterFooter ? !flags.overlayText : flags.overlayText;
if (isOuterFooter && options.cardLayout && layoutManager.mobile && options.cardFooterAside !== 'none') {
if (flags.isOuterFooter && options.cardLayout && layoutManager.mobile && options.cardFooterAside !== 'none') {
html += `<button is="paper-icon-button-light" class="itemAction btnCardOptions cardText-secondary" data-action="menu" title="${globalize.translate('ButtonMore')}"><span class="material-icons more_vert" aria-hidden="true"></span></button>`;
}
@ -805,7 +802,7 @@ import { appRouter } from '../appRouter';
let titleAdded;
if (showOtherText && (options.showParentTitle || options.showParentTitleOrTitle) && !parentTitleUnderneath) {
if (isOuterFooter && item.Type === 'Episode' && item.SeriesName) {
if (flags.isOuterFooter && item.Type === 'Episode' && item.SeriesName) {
if (item.SeriesId) {
lines.push(getTextActionButton({
Id: item.SeriesId,
@ -835,7 +832,7 @@ import { appRouter } from '../appRouter';
}
let showMediaTitle = (showTitle && !titleAdded) || (options.showParentTitleOrTitle && !lines.length);
if (!showMediaTitle && !titleAdded && (showTitle || forceName)) {
if (!showMediaTitle && !titleAdded && (showTitle || flags.forceName)) {
showMediaTitle = true;
}
@ -856,7 +853,7 @@ import { appRouter } from '../appRouter';
if (showOtherText) {
if (options.showParentTitle && parentTitleUnderneath) {
if (isOuterFooter && item.AlbumArtists && item.AlbumArtists.length) {
if (flags.isOuterFooter && item.AlbumArtists && item.AlbumArtists.length) {
item.AlbumArtists[0].Type = 'MusicArtist';
item.AlbumArtists[0].IsFolder = true;
lines.push(getTextActionButton(item.AlbumArtists[0], null, serverId));
@ -991,23 +988,23 @@ import { appRouter } from '../appRouter';
}
}
if ((showTitle || !imgUrl) && forceName && overlayText && lines.length === 1) {
if ((showTitle || !urls.imgUrl) && flags.forceName && flags.overlayText && lines.length === 1) {
lines = [];
}
if (overlayText && showTitle) {
if (flags.overlayText && showTitle) {
lines = [escapeHtml(item.Name)];
}
const addRightTextMargin = isOuterFooter && options.cardLayout && !options.centerText && options.cardFooterAside !== 'none' && layoutManager.mobile;
const addRightTextMargin = flags.isOuterFooter && options.cardLayout && !options.centerText && options.cardFooterAside !== 'none' && layoutManager.mobile;
html += getCardTextLines(lines, cssClass, !options.overlayText, isOuterFooter, options.cardLayout, addRightTextMargin, options.lines);
html += getCardTextLines(lines, cssClass, !options.overlayText, flags.isOuterFooter, options.cardLayout, addRightTextMargin, options.lines);
if (progressHtml) {
html += progressHtml;
}
if (html && (!isOuterFooter || logoUrl || options.cardLayout)) {
if (html && (!flags.isOuterFooter || urls.logoUrl || options.cardLayout)) {
html = '<div class="' + footerClass + '">' + html;
//cardFooter
@ -1217,7 +1214,6 @@ import { appRouter } from '../appRouter';
const forceName = imgInfo.forceName;
const showTitle = options.showTitle === 'auto' ? true : (options.showTitle || item.Type === 'PhotoAlbum' || item.Type === 'Folder');
const overlayText = options.overlayText;
let cardImageContainerClass = 'cardImageContainer';
@ -1265,7 +1261,7 @@ import { appRouter } from '../appRouter';
logoUrl = null;
footerCssClass = progressHtml ? 'innerCardFooter fullInnerCardFooter' : 'innerCardFooter';
innerCardFooter += getCardFooterText(item, apiClient, options, showTitle, forceName, overlayText, imgUrl, footerCssClass, progressHtml, logoUrl, false);
innerCardFooter += getCardFooterText(item, apiClient, options, footerCssClass, progressHtml, { forceName, overlayText, isOuterFooter: false }, { imgUrl, logoUrl });
footerOverlayed = true;
} else if (progressHtml) {
innerCardFooter += '<div class="innerCardFooter fullInnerCardFooter innerCardFooterClear">';
@ -1292,7 +1288,7 @@ import { appRouter } from '../appRouter';
logoUrl = null;
}
outerCardFooter = getCardFooterText(item, apiClient, options, showTitle, forceName, overlayText, imgUrl, footerCssClass, progressHtml, logoUrl, true);
outerCardFooter = getCardFooterText(item, apiClient, options, footerCssClass, progressHtml, { forceName, overlayText, isOuterFooter: true }, { imgUrl, logoUrl });
}
if (outerCardFooter && !options.cardLayout) {

View File

@ -12,7 +12,7 @@ import '../../elements/emby-input/emby-input';
import '../../elements/emby-select/emby-select';
import 'material-design-icons-iconfont';
import '../formdialog.scss';
import '../../assets/css/flexstyles.scss';
import '../../styles/flexstyles.scss';
import ServerConnections from '../ServerConnections';
import toast from '../toast/toast';

View File

@ -10,7 +10,7 @@ import '../../elements/emby-button/emby-button';
import '../../elements/emby-button/paper-icon-button-light';
import '../../elements/emby-input/emby-input';
import '../formdialog.scss';
import '../../assets/css/flexstyles.scss';
import '../../styles/flexstyles.scss';
import template from './dialog.template.html';
/* eslint-disable indent */

View File

@ -7,7 +7,7 @@ import { toBoolean } from '../../utils/string.ts';
import dom from '../../scripts/dom';
import './dialoghelper.scss';
import '../../assets/css/scrollstyles.scss';
import '../../styles/scrollstyles.scss';
/* eslint-disable indent */

View File

@ -6,7 +6,7 @@ import imageLoader from './images/imageLoader';
import globalize from '../scripts/globalize';
import layoutManager from './layoutManager';
import { getParameterByName } from '../utils/url.ts';
import '../assets/css/scrollstyles.scss';
import '../styles/scrollstyles.scss';
import '../elements/emby-itemscontainer/emby-itemscontainer';
/* eslint-disable indent */

View File

@ -13,7 +13,7 @@ import '../../elements/emby-button/paper-icon-button-light';
import '../../elements/emby-select/emby-select';
import 'material-design-icons-iconfont';
import '../formdialog.scss';
import '../../assets/css/flexstyles.scss';
import '../../styles/flexstyles.scss';
import ServerConnections from '../ServerConnections';
import template from './filtermenu.template.html';

View File

@ -17,13 +17,13 @@ import dom from '../../scripts/dom';
import './guide.scss';
import './programs.scss';
import 'material-design-icons-iconfont';
import '../../assets/css/scrollstyles.scss';
import '../../styles/scrollstyles.scss';
import '../../elements/emby-programcell/emby-programcell';
import '../../elements/emby-button/emby-button';
import '../../elements/emby-button/paper-icon-button-light';
import '../../elements/emby-tabs/emby-tabs';
import '../../elements/emby-scroller/emby-scroller';
import '../../assets/css/flexstyles.scss';
import '../../styles/flexstyles.scss';
import 'webcomponents.js/webcomponents-lite';
import ServerConnections from '../ServerConnections';
import template from './tvguide.template.html';
@ -345,7 +345,9 @@ function Guide(options) {
}
apiClient.getLiveTvPrograms(programQuery).then(function (programsResult) {
renderGuide(context, date, channelsResult.Items, programsResult.Items, renderOptions, apiClient, scrollToTimeMs, focusToTimeMs, startTimeOfDayMs, focusProgramOnRender);
const guideOptions = { focusProgramOnRender, scrollToTimeMs, focusToTimeMs, startTimeOfDayMs };
renderGuide(context, date, channelsResult.Items, programsResult.Items, renderOptions, guideOptions, apiClient);
hideLoading();
});
@ -667,7 +669,7 @@ function Guide(options) {
return (channelIndex * 10000000) + (start.getTime() / 60000);
}
function renderGuide(context, date, channels, programs, renderOptions, apiClient, scrollToTimeMs, focusToTimeMs, startTimeOfDayMs, focusProgramOnRender) {
function renderGuide(context, date, channels, programs, renderOptions, guideOptions, apiClient) {
programs.sort(function (a, b) {
return getProgramSortOrder(a, channels) - getProgramSortOrder(b, channels);
});
@ -689,11 +691,11 @@ function Guide(options) {
items = {};
renderPrograms(context, date, channels, programs, renderOptions);
if (focusProgramOnRender) {
focusProgram(context, itemId, channelRowId, focusToTimeMs, startTimeOfDayMs);
if (guideOptions.focusProgramOnRender) {
focusProgram(context, itemId, channelRowId, guideOptions.focusToTimeMs, guideOptions.startTimeOfDayMs);
}
scrollProgramGridToTimeMs(context, scrollToTimeMs, startTimeOfDayMs);
scrollProgramGridToTimeMs(context, guideOptions.scrollToTimeMs, guideOptions.startTimeOfDayMs);
}
function scrollProgramGridToTimeMs(context, scrollToTimeMs, startTimeOfDayMs) {

View File

@ -96,7 +96,7 @@ import template from './imageeditor.template.html';
return apiClient.getScaledImageUrl(item.Id || item.ItemId, options);
}
function getCardHtml(image, index, numImages, apiClient, imageProviders, imageSize, tagName, enableFooterButtons) {
function getCardHtml(image, apiClient, options) {
// TODO move card creation code to Card component
let html = '';
@ -106,7 +106,7 @@ import template from './imageeditor.template.html';
cssClass += ' backdropCard backdropCard-scalable';
if (tagName === 'button') {
if (options.tagName === 'button') {
cssClass += ' btnImageCard';
if (layoutManager.tv) {
@ -122,7 +122,7 @@ import template from './imageeditor.template.html';
html += '<div class="' + cssClass + '"';
}
html += ' data-id="' + currentItem.Id + '" data-serverid="' + apiClient.serverId() + '" data-index="' + index + '" data-numimages="' + numImages + '" data-imagetype="' + image.ImageType + '" data-providers="' + imageProviders.length + '"';
html += ' data-id="' + currentItem.Id + '" data-serverid="' + apiClient.serverId() + '" data-index="' + options.index + '" data-numimages="' + options.numImages + '" data-imagetype="' + image.ImageType + '" data-providers="' + options.imageProviders.length + '"';
html += '>';
@ -132,7 +132,7 @@ import template from './imageeditor.template.html';
html += '<div class="cardContent">';
const imageUrl = getImageUrl(currentItem, apiClient, image.ImageType, image.ImageIndex, { maxWidth: imageSize });
const imageUrl = getImageUrl(currentItem, apiClient, image.ImageType, image.ImageIndex, { maxWidth: options.imageSize });
html += '<div class="cardImageContainer" style="background-image:url(\'' + imageUrl + '\');background-position:center center;background-size:contain;"></div>';
@ -151,23 +151,23 @@ import template from './imageeditor.template.html';
}
html += '</div>';
if (enableFooterButtons) {
if (options.enableFooterButtons) {
html += '<div class="cardText cardTextCentered">';
if (image.ImageType === 'Backdrop') {
if (index > 0) {
if (options.index > 0) {
html += '<button type="button" is="paper-icon-button-light" class="btnMoveImage autoSize" data-imagetype="' + image.ImageType + '" data-index="' + image.ImageIndex + '" data-newindex="' + (image.ImageIndex - 1) + '" title="' + globalize.translate('MoveLeft') + '"><span class="material-icons chevron_left"></span></button>';
} else {
html += '<button type="button" is="paper-icon-button-light" class="autoSize" disabled title="' + globalize.translate('MoveLeft') + '"><span class="material-icons chevron_left" aria-hidden="true"></span></button>';
}
if (index < numImages - 1) {
if (options.index < options.numImages - 1) {
html += '<button type="button" is="paper-icon-button-light" class="btnMoveImage autoSize" data-imagetype="' + image.ImageType + '" data-index="' + image.ImageIndex + '" data-newindex="' + (image.ImageIndex + 1) + '" title="' + globalize.translate('MoveRight') + '"><span class="material-icons chevron_right" aria-hidden="true"></span></button>';
} else {
html += '<button type="button" is="paper-icon-button-light" class="autoSize" disabled title="' + globalize.translate('MoveRight') + '"><span class="material-icons chevron_right" aria-hidden="true"></span></button>';
}
} else {
if (imageProviders.length) {
if (options.imageProviders.length) {
html += '<button type="button" is="paper-icon-button-light" data-imagetype="' + image.ImageType + '" class="btnSearchImages autoSize" title="' + globalize.translate('Search') + '"><span class="material-icons search" aria-hidden="true"></span></button>';
}
}
@ -178,7 +178,7 @@ import template from './imageeditor.template.html';
html += '</div>';
html += '</div>';
html += '</' + tagName + '>';
html += '</' + options.tagName + '>';
return html;
}
@ -226,7 +226,8 @@ import template from './imageeditor.template.html';
for (let i = 0, length = images.length; i < length; i++) {
const image = images[i];
html += getCardHtml(image, i, length, apiClient, imageProviders, imageSize, tagName, enableFooterButtons);
const options = { index: i, numImages: length, imageProviders, imageSize, tagName, enableFooterButtons };
html += getCardHtml(image, apiClient, options);
}
elem.innerHTML = html;

View File

@ -20,7 +20,7 @@ import '../../elements/emby-button/emby-button';
import '../../elements/emby-button/paper-icon-button-light';
import '../formdialog.scss';
import 'material-design-icons-iconfont';
import '../../assets/css/flexstyles.scss';
import '../../styles/flexstyles.scss';
import ServerConnections from '../ServerConnections';
import template from './itemMediaInfo.template.html';

View File

@ -19,7 +19,7 @@ import '../../elements/emby-select/emby-select';
import '../../elements/emby-toggle/emby-toggle';
import '../listview/listview.scss';
import '../formdialog.scss';
import '../../assets/css/flexstyles.scss';
import '../../styles/flexstyles.scss';
import './style.scss';
import toast from '../toast/toast';
import alert from '../alert';

View File

@ -17,7 +17,7 @@ import '../listview/listview.scss';
import '../../elements/emby-button/paper-icon-button-light';
import '../formdialog.scss';
import '../../elements/emby-toggle/emby-toggle';
import '../../assets/css/flexstyles.scss';
import '../../styles/flexstyles.scss';
import './style.scss';
import toast from '../toast/toast';
import confirm from '../confirm/confirm';

View File

@ -15,8 +15,8 @@ import '../../elements/emby-textarea/emby-textarea';
import '../../elements/emby-button/emby-button';
import '../../elements/emby-button/paper-icon-button-light';
import '../formdialog.scss';
import '../../assets/css/clearbutton.scss';
import '../../assets/css/flexstyles.scss';
import '../../styles/clearbutton.scss';
import '../../styles/flexstyles.scss';
import './style.scss';
import ServerConnections from '../ServerConnections';
import toast from '../toast/toast';

View File

@ -299,20 +299,20 @@ function getAudioMaxValues(deviceProfile) {
}
let startingPlaySession = new Date().getTime();
function getAudioStreamUrl(item, transcodingProfile, directPlayContainers, maxBitrate, apiClient, maxAudioSampleRate, maxAudioBitDepth, maxAudioBitrate, startPosition) {
function getAudioStreamUrl(item, transcodingProfile, directPlayContainers, apiClient, startPosition, maxValues) {
const url = 'Audio/' + item.Id + '/universal';
startingPlaySession++;
return apiClient.getUrl(url, {
UserId: apiClient.getCurrentUserId(),
DeviceId: apiClient.deviceId(),
MaxStreamingBitrate: maxAudioBitrate || maxBitrate,
MaxStreamingBitrate: maxValues.maxAudioBitrate || maxValues.maxBitrate,
Container: directPlayContainers,
TranscodingContainer: transcodingProfile.Container || null,
TranscodingProtocol: transcodingProfile.Protocol || null,
AudioCodec: transcodingProfile.AudioCodec,
MaxAudioSampleRate: maxAudioSampleRate,
MaxAudioBitDepth: maxAudioBitDepth,
MaxAudioSampleRate: maxValues.maxAudioSampleRate,
MaxAudioBitDepth: maxValues.maxAudioBitDepth,
api_key: apiClient.accessToken(),
PlaySessionId: startingPlaySession,
StartTimeTicks: startPosition || 0,
@ -344,7 +344,7 @@ function getAudioStreamUrlFromDeviceProfile(item, deviceProfile, maxBitrate, api
const maxValues = getAudioMaxValues(deviceProfile);
return getAudioStreamUrl(item, transcodingProfile, directPlayContainers, maxBitrate, apiClient, maxValues.maxAudioSampleRate, maxValues.maxAudioBitDepth, maxValues.maxAudioBitrate, startPosition);
return getAudioStreamUrl(item, transcodingProfile, directPlayContainers, apiClient, startPosition, { maxBitrate, ...maxValues });
}
function getStreamUrls(items, deviceProfile, maxBitrate, apiClient, startPosition) {
@ -377,7 +377,7 @@ function getStreamUrls(items, deviceProfile, maxBitrate, apiClient, startPositio
let streamUrl;
if (item.MediaType === 'Audio' && !itemHelper.isLocalItem(item)) {
streamUrl = getAudioStreamUrl(item, audioTranscodingProfile, audioDirectPlayContainers, maxBitrate, apiClient, maxValues.maxAudioSampleRate, maxValues.maxAudioBitDepth, maxValues.maxAudioBitrate, startPosition);
streamUrl = getAudioStreamUrl(item, audioTranscodingProfile, audioDirectPlayContainers, apiClient, startPosition, { maxBitrate, ...maxValues });
}
streamUrls.push(streamUrl || '');
@ -408,26 +408,12 @@ function setStreamUrls(items, deviceProfile, maxBitrate, apiClient, startPositio
});
}
function getPlaybackInfo(player,
apiClient,
item,
deviceProfile,
maxBitrate,
startPosition,
isPlayback,
mediaSourceId,
audioStreamIndex,
subtitleStreamIndex,
liveStreamId,
enableDirectPlay,
enableDirectStream,
allowVideoStreamCopy,
allowAudioStreamCopy) {
function getPlaybackInfo(player, apiClient, item, deviceProfile, mediaSourceId, liveStreamId, options) {
if (!itemHelper.isLocalItem(item) && item.MediaType === 'Audio' && !player.useServerPlaybackInfoForAudio) {
return Promise.resolve({
MediaSources: [
{
StreamUrl: getAudioStreamUrlFromDeviceProfile(item, deviceProfile, maxBitrate, apiClient, startPosition),
StreamUrl: getAudioStreamUrlFromDeviceProfile(item, deviceProfile, options.maxBitrate, apiClient, options.startPosition),
Id: item.Id,
MediaStreams: [],
RunTimeTicks: item.RunTimeTicks
@ -445,10 +431,10 @@ function getPlaybackInfo(player,
const query = {
UserId: apiClient.getCurrentUserId(),
StartTimeTicks: startPosition || 0
StartTimeTicks: options.startPosition || 0
};
if (isPlayback) {
if (options.isPlayback) {
query.IsPlayback = true;
query.AutoOpenLiveStream = true;
} else {
@ -456,24 +442,26 @@ function getPlaybackInfo(player,
query.AutoOpenLiveStream = false;
}
if (audioStreamIndex != null) {
query.AudioStreamIndex = audioStreamIndex;
if (options.audioStreamIndex != null) {
query.AudioStreamIndex = options.audioStreamIndex;
}
if (subtitleStreamIndex != null) {
query.SubtitleStreamIndex = subtitleStreamIndex;
if (options.subtitleStreamIndex != null) {
query.SubtitleStreamIndex = options.subtitleStreamIndex;
}
if (enableDirectPlay != null) {
query.EnableDirectPlay = enableDirectPlay;
if (options.secondarySubtitleStreamIndex != null) {
query.SecondarySubtitleStreamIndex = options.secondarySubtitleStreamIndex;
}
if (enableDirectStream != null) {
query.EnableDirectStream = enableDirectStream;
if (options.enableDirectPlay != null) {
query.EnableDirectPlay = options.enableDirectPlay;
}
if (allowVideoStreamCopy != null) {
query.AllowVideoStreamCopy = allowVideoStreamCopy;
if (options.enableDirectStream != null) {
query.EnableDirectStream = options.enableDirectStream;
}
if (allowAudioStreamCopy != null) {
query.AllowAudioStreamCopy = allowAudioStreamCopy;
if (options.allowVideoStreamCopy != null) {
query.AllowVideoStreamCopy = options.allowVideoStreamCopy;
}
if (options.allowAudioStreamCopy != null) {
query.AllowAudioStreamCopy = options.allowAudioStreamCopy;
}
if (mediaSourceId) {
query.MediaSourceId = mediaSourceId;
@ -481,8 +469,8 @@ function getPlaybackInfo(player,
if (liveStreamId) {
query.LiveStreamId = liveStreamId;
}
if (maxBitrate) {
query.MaxStreamingBitrate = maxBitrate;
if (options.maxBitrate) {
query.MaxStreamingBitrate = options.maxBitrate;
}
if (player.enableMediaProbe && !player.enableMediaProbe(item)) {
query.EnableMediaProbe = false;
@ -533,7 +521,7 @@ function getOptimalMediaSource(apiClient, item, versions) {
});
}
function getLiveStream(player, apiClient, item, playSessionId, deviceProfile, maxBitrate, startPosition, mediaSource, audioStreamIndex, subtitleStreamIndex) {
function getLiveStream(player, apiClient, item, playSessionId, deviceProfile, mediaSource, options) {
const postData = {
DeviceProfile: deviceProfile,
OpenToken: mediaSource.OpenToken
@ -541,19 +529,19 @@ function getLiveStream(player, apiClient, item, playSessionId, deviceProfile, ma
const query = {
UserId: apiClient.getCurrentUserId(),
StartTimeTicks: startPosition || 0,
StartTimeTicks: options.startPosition || 0,
ItemId: item.Id,
PlaySessionId: playSessionId
};
if (maxBitrate) {
query.MaxStreamingBitrate = maxBitrate;
if (options.maxBitrate) {
query.MaxStreamingBitrate = options.maxBitrate;
}
if (audioStreamIndex != null) {
query.AudioStreamIndex = audioStreamIndex;
if (options.audioStreamIndex != null) {
query.AudioStreamIndex = options.audioStreamIndex;
}
if (subtitleStreamIndex != null) {
query.SubtitleStreamIndex = subtitleStreamIndex;
if (options.subtitleStreamIndex != null) {
query.SubtitleStreamIndex = options.subtitleStreamIndex;
}
// lastly, enforce player overrides for special situations
@ -876,25 +864,49 @@ class PlaybackManager {
});
};
function getCurrentSubtitleStream(player) {
self.playerHasSecondarySubtitleSupport = function (player = self._currentPlayer) {
if (!player) return false;
return Boolean(player.supports('SecondarySubtitles'));
};
/**
* Checks if:
* - the track can be used directly as a secondary subtitle
* - or if it can be paired with a secondary subtitle when used as a primary subtitle
*/
self.trackHasSecondarySubtitleSupport = function (track, player = self._currentPlayer) {
if (!player || !track) return false;
const format = (track.Codec || '').toLowerCase();
// Currently, only non-SSA/non-ASS external subtitles are supported.
// Showing secondary subtitles does not work with any SSA/ASS subtitle combinations because
// of the complexity of how they are rendered and the risk of the subtitles overlapping
return format !== 'ssa' && format !== 'ass' && getDeliveryMethod(track) === 'External';
};
self.secondarySubtitleTracks = function (player = self._currentPlayer) {
const streams = self.subtitleTracks(player);
return streams.filter((stream) => self.trackHasSecondarySubtitleSupport(stream, player));
};
function getCurrentSubtitleStream(player, isSecondaryStream = false) {
if (!player) {
throw new Error('player cannot be null');
}
const index = getPlayerData(player).subtitleStreamIndex;
const index = isSecondaryStream ? getPlayerData(player).secondarySubtitleStreamIndex : getPlayerData(player).subtitleStreamIndex;
if (index == null || index === -1) {
return null;
}
return getSubtitleStream(player, index);
return self.getSubtitleStream(player, index);
}
function getSubtitleStream(player, index) {
self.getSubtitleStream = function (player, index) {
return self.subtitleTracks(player).filter(function (s) {
return s.Type === 'Subtitle' && s.Index === index;
})[0];
}
};
self.getPlaylist = function (player) {
player = player || self._currentPlayer;
@ -1463,6 +1475,24 @@ class PlaybackManager {
return getPlayerData(player).subtitleStreamIndex;
};
self.getSecondarySubtitleStreamIndex = function (player) {
player = player || self._currentPlayer;
if (!player) {
throw new Error('player cannot be null');
}
try {
if (!enableLocalPlaylistManagement(player)) {
return player.getSecondarySubtitleStreamIndex();
}
} catch (e) {
console.error('[playbackmanager] Failed to get secondary stream index:', e);
}
return getPlayerData(player).secondarySubtitleStreamIndex;
};
function getDeliveryMethod(subtitleStream) {
// This will be null for internal subs for local items
if (subtitleStream.DeliveryMethod) {
@ -1480,7 +1510,7 @@ class PlaybackManager {
const currentStream = getCurrentSubtitleStream(player);
const newStream = getSubtitleStream(player, index);
const newStream = self.getSubtitleStream(player, index);
if (!currentStream && !newStream) {
return;
@ -1522,9 +1552,48 @@ class PlaybackManager {
player.setSubtitleStreamIndex(selectedTrackElementIndex);
// Also disable secondary subtitles when disabling the primary
// subtitles, or if it doesn't support a secondary pair
if (selectedTrackElementIndex === -1 || !self.trackHasSecondarySubtitleSupport(newStream)) {
self.setSecondarySubtitleStreamIndex(-1);
}
getPlayerData(player).subtitleStreamIndex = index;
};
self.setSecondarySubtitleStreamIndex = function (index, player) {
player = player || self._currentPlayer;
if (!self.playerHasSecondarySubtitleSupport(player)) return;
if (player && !enableLocalPlaylistManagement(player)) {
try {
return player.setSecondarySubtitleStreamIndex(index);
} catch (e) {
console.error('[playbackmanager] AutoSet - Failed to set secondary track:', e);
}
}
const currentStream = getCurrentSubtitleStream(player, true);
const newStream = self.getSubtitleStream(player, index);
if (!currentStream && !newStream) {
return;
}
// Secondary subtitles are currently only handled client side
// Changes to the server code are required before we can handle other delivery methods
if (newStream && !self.trackHasSecondarySubtitleSupport(newStream, player)) {
return;
}
try {
player.setSecondarySubtitleStreamIndex(index);
getPlayerData(player).secondarySubtitleStreamIndex = index;
} catch (e) {
console.error('[playbackmanager] AutoSet - Failed to set secondary track:', e);
}
};
self.supportSubtitleOffset = function (player) {
player = player || self._currentPlayer;
return player && 'setSubtitleOffset' in player;
@ -1548,7 +1617,7 @@ class PlaybackManager {
};
self.isSubtitleStreamExternal = function (index, player) {
const stream = getSubtitleStream(player, index);
const stream = self.getSubtitleStream(player, index);
return stream ? getDeliveryMethod(stream) === 'External' : false;
};
@ -1639,6 +1708,7 @@ class PlaybackManager {
}).then(function (deviceProfile) {
const audioStreamIndex = params.AudioStreamIndex == null ? getPlayerData(player).audioStreamIndex : params.AudioStreamIndex;
const subtitleStreamIndex = params.SubtitleStreamIndex == null ? getPlayerData(player).subtitleStreamIndex : params.SubtitleStreamIndex;
const secondarySubtitleStreamIndex = params.SecondarySubtitleStreamIndex == null ? getPlayerData(player).secondarySubtitleStreamIndex : params.SecondarySubtitleStreamIndex;
let currentMediaSource = self.currentMediaSource(player);
const apiClient = ServerConnections.getApiClient(currentItem.ServerId);
@ -1651,13 +1721,26 @@ class PlaybackManager {
const currentPlayOptions = currentItem.playOptions || getDefaultPlayOptions();
getPlaybackInfo(player, apiClient, currentItem, deviceProfile, maxBitrate, ticks, true, currentMediaSource.Id, audioStreamIndex, subtitleStreamIndex, liveStreamId, params.EnableDirectPlay, params.EnableDirectStream, params.AllowVideoStreamCopy, params.AllowAudioStreamCopy).then(function (result) {
const options = {
maxBitrate,
startPosition: ticks,
isPlayback: true,
audioStreamIndex,
subtitleStreamIndex,
enableDirectPlay: params.EnableDirectPlay,
enableDirectStream: params.EnableDirectStream,
allowVideoStreamCopy: params.AllowVideoStreamCopy,
allowAudioStreamCopy: params.AllowAudioStreamCopy
};
getPlaybackInfo(player, apiClient, currentItem, deviceProfile, currentMediaSource.Id, liveStreamId, options).then(function (result) {
if (validatePlaybackInfoResult(self, result)) {
currentMediaSource = result.MediaSources[0];
const streamInfo = createStreamInfo(apiClient, currentItem.MediaType, currentItem, currentMediaSource, ticks, player);
streamInfo.fullscreen = currentPlayOptions.fullscreen;
streamInfo.lastMediaInfoQuery = lastMediaInfoQuery;
streamInfo.resetSubtitleOffset = false;
if (!streamInfo.url) {
showPlaybackInfoErrorMessage(self, 'PlaybackErrorNoCompatibleStream');
@ -1665,6 +1748,7 @@ class PlaybackManager {
}
getPlayerData(player).subtitleStreamIndex = subtitleStreamIndex;
getPlayerData(player).secondarySubtitleStreamIndex = secondarySubtitleStreamIndex;
getPlayerData(player).audioStreamIndex = audioStreamIndex;
getPlayerData(player).maxStreamingBitrate = maxBitrate;
@ -1950,6 +2034,7 @@ class PlaybackManager {
state.PlayState.PlaybackRate = self.getPlaybackRate(player);
state.PlayState.SubtitleStreamIndex = self.getSubtitleStreamIndex(player);
state.PlayState.SecondarySubtitleStreamIndex = self.getSecondarySubtitleStreamIndex(player);
state.PlayState.AudioStreamIndex = self.getAudioStreamIndex(player);
state.PlayState.BufferedRanges = self.getBufferedRanges(player);
@ -2215,26 +2300,31 @@ class PlaybackManager {
}, reject);
}
function sendPlaybackListToPlayer(player, items, deviceProfile, maxBitrate, apiClient, startPositionTicks, mediaSourceId, audioStreamIndex, subtitleStreamIndex, startIndex) {
return setStreamUrls(items, deviceProfile, maxBitrate, apiClient, startPositionTicks).then(function () {
function sendPlaybackListToPlayer(player, items, deviceProfile, apiClient, mediaSourceId, options) {
return setStreamUrls(items, deviceProfile, options.maxBitrate, apiClient, options.startPosition).then(function () {
loading.hide();
return player.play({
items: items,
startPositionTicks: startPositionTicks || 0,
mediaSourceId: mediaSourceId,
audioStreamIndex: audioStreamIndex,
subtitleStreamIndex: subtitleStreamIndex,
startIndex: startIndex
items,
startPositionTicks: options.startPosition || 0,
mediaSourceId,
audioStreamIndex: options.audioStreamIndex,
subtitleStreamIndex: options.subtitleStreamIndex,
startIndex: options.startIndex
});
});
}
function rankStreamType(prevIndex, prevSource, mediaSource, streamType) {
function rankStreamType(prevIndex, prevSource, mediaSource, streamType, isSecondarySubtitle) {
if (prevIndex == -1) {
console.debug(`AutoSet ${streamType} - No Stream Set`);
if (streamType == 'Subtitle')
mediaSource.DefaultSubtitleStreamIndex = -1;
if (streamType == 'Subtitle') {
if (isSecondarySubtitle) {
mediaSource.DefaultSecondarySubtitleStreamIndex = -1;
} else {
mediaSource.DefaultSubtitleStreamIndex = -1;
}
}
return;
}
@ -2292,8 +2382,13 @@ class PlaybackManager {
if (bestStreamIndex != null) {
console.debug(`AutoSet ${streamType} - Using ${bestStreamIndex} score ${bestStreamScore}.`);
if (streamType == 'Subtitle')
mediaSource.DefaultSubtitleStreamIndex = bestStreamIndex;
if (streamType == 'Subtitle') {
if (isSecondarySubtitle) {
mediaSource.DefaultSecondarySubtitleStreamIndex = bestStreamIndex;
} else {
mediaSource.DefaultSubtitleStreamIndex = bestStreamIndex;
}
}
if (streamType == 'Audio')
mediaSource.DefaultAudioStreamIndex = bestStreamIndex;
} else {
@ -2317,6 +2412,10 @@ class PlaybackManager {
if (subtitle && typeof prevSource.DefaultSubtitleStreamIndex == 'number') {
rankStreamType(prevSource.DefaultSubtitleStreamIndex, prevSource, mediaSource, 'Subtitle');
}
if (subtitle && typeof prevSource.DefaultSecondarySubtitleStreamIndex == 'number') {
rankStreamType(prevSource.DefaultSecondarySubtitleStreamIndex, prevSource, mediaSource, 'Subtitle', true);
}
} catch (e) {
console.error(`AutoSet - Caught unexpected error: ${e}`);
}
@ -2372,18 +2471,43 @@ class PlaybackManager {
const mediaSourceId = playOptions.mediaSourceId;
const audioStreamIndex = playOptions.audioStreamIndex;
const subtitleStreamIndex = playOptions.subtitleStreamIndex;
const options = {
maxBitrate,
startPosition,
isPlayback: null,
audioStreamIndex,
subtitleStreamIndex,
startIndex: playOptions.startIndex,
enableDirectPlay: null,
enableDirectStream: null,
allowVideoStreamCopy: null,
allowAudioStreamCopy: null
};
if (player && !enableLocalPlaylistManagement(player)) {
return sendPlaybackListToPlayer(player, playOptions.items, deviceProfile, maxBitrate, apiClient, startPosition, mediaSourceId, audioStreamIndex, subtitleStreamIndex, playOptions.startIndex);
return sendPlaybackListToPlayer(player, playOptions.items, deviceProfile, apiClient, mediaSourceId, options);
}
// this reference was only needed by sendPlaybackListToPlayer
playOptions.items = null;
return getPlaybackMediaSource(player, apiClient, deviceProfile, maxBitrate, item, startPosition, mediaSourceId, audioStreamIndex, subtitleStreamIndex).then(async (mediaSource) => {
return getPlaybackMediaSource(player, apiClient, deviceProfile, item, mediaSourceId, options).then(async (mediaSource) => {
const user = await apiClient.getCurrentUser();
autoSetNextTracks(prevSource, mediaSource, user.Configuration.RememberAudioSelections, user.Configuration.RememberSubtitleSelections);
if (mediaSource.DefaultSubtitleStreamIndex == null || mediaSource.DefaultSubtitleStreamIndex < 0) {
mediaSource.DefaultSubtitleStreamIndex = mediaSource.DefaultSecondarySubtitleStreamIndex;
mediaSource.DefaultSecondarySubtitleStreamIndex = -1;
}
const subtitleTrack1 = mediaSource.MediaStreams[mediaSource.DefaultSubtitleStreamIndex];
const subtitleTrack2 = mediaSource.MediaStreams[mediaSource.DefaultSecondarySubtitleStreamIndex];
if (!self.trackHasSecondarySubtitleSupport(subtitleTrack1, player)
|| !self.trackHasSecondarySubtitleSupport(subtitleTrack2, player)) {
mediaSource.DefaultSecondarySubtitleStreamIndex = -1;
}
const streamInfo = createStreamInfo(apiClient, item.MediaType, item, mediaSource, startPosition, player);
streamInfo.fullscreen = playOptions.fullscreen;
@ -2425,7 +2549,20 @@ class PlaybackManager {
const maxBitrate = getSavedMaxStreamingBitrate(ServerConnections.getApiClient(item.ServerId), mediaType);
return player.getDeviceProfile(item).then(function (deviceProfile) {
return getPlaybackMediaSource(player, apiClient, deviceProfile, maxBitrate, item, startPosition, options.mediaSourceId, options.audioStreamIndex, options.subtitleStreamIndex).then(function (mediaSource) {
const mediaOptions = {
maxBitrate,
startPosition,
isPlayback: null,
audioStreamIndex: options.audioStreamIndex,
subtitleStreamIndex: options.subtitleStreamIndex,
startIndex: null,
enableDirectPlay: null,
enableDirectStream: null,
allowVideoStreamCopy: null,
allowAudioStreamCopy: null
};
return getPlaybackMediaSource(player, apiClient, deviceProfile, item, options.mediaSourceId, mediaOptions).then(function (mediaSource) {
return createStreamInfo(apiClient, item.MediaType, item, mediaSource, startPosition, player);
});
});
@ -2445,7 +2582,19 @@ class PlaybackManager {
const maxBitrate = getSavedMaxStreamingBitrate(ServerConnections.getApiClient(item.ServerId), mediaType);
return player.getDeviceProfile(item).then(function (deviceProfile) {
return getPlaybackInfo(player, apiClient, item, deviceProfile, maxBitrate, startPosition, false, null, null, null, null).then(function (playbackInfoResult) {
const mediaOptions = {
maxBitrate,
startPosition,
isPlayback: true,
audioStreamIndex: null,
subtitleStreamIndex: null,
enableDirectPlay: null,
enableDirectStream: null,
allowVideoStreamCopy: null,
allowAudioStreamCopy: null
};
return getPlaybackInfo(player, apiClient, item, deviceProfile, null, null, mediaOptions).then(function (playbackInfoResult) {
return playbackInfoResult.MediaSources;
});
});
@ -2586,13 +2735,18 @@ class PlaybackManager {
return tracks;
}
function getPlaybackMediaSource(player, apiClient, deviceProfile, maxBitrate, item, startPosition, mediaSourceId, audioStreamIndex, subtitleStreamIndex) {
return getPlaybackInfo(player, apiClient, item, deviceProfile, maxBitrate, startPosition, true, mediaSourceId, audioStreamIndex, subtitleStreamIndex, null).then(function (playbackInfoResult) {
function getPlaybackMediaSource(player, apiClient, deviceProfile, item, mediaSourceId, options) {
options.isPlayback = true;
return getPlaybackInfo(player, apiClient, item, deviceProfile, mediaSourceId, null, options).then(function (playbackInfoResult) {
if (validatePlaybackInfoResult(self, playbackInfoResult)) {
return getOptimalMediaSource(apiClient, item, playbackInfoResult.MediaSources).then(function (mediaSource) {
if (mediaSource) {
if (mediaSource.RequiresOpening && !mediaSource.LiveStreamId) {
return getLiveStream(player, apiClient, item, playbackInfoResult.PlaySessionId, deviceProfile, maxBitrate, startPosition, mediaSource, null, null).then(function (openLiveStreamResult) {
options.audioStreamIndex = null;
options.subtitleStreamIndex = null;
return getLiveStream(player, apiClient, item, playbackInfoResult.PlaySessionId, deviceProfile, mediaSource, options).then(function (openLiveStreamResult) {
return supportsDirectPlay(apiClient, item, openLiveStreamResult.MediaSource).then(function (result) {
openLiveStreamResult.MediaSource.enableDirectPlay = result;
return openLiveStreamResult.MediaSource;
@ -2751,7 +2905,8 @@ class PlaybackManager {
return {
...prevSource,
DefaultAudioStreamIndex: prevPlayerData.audioStreamIndex,
DefaultSubtitleStreamIndex: prevPlayerData.subtitleStreamIndex
DefaultSubtitleStreamIndex: prevPlayerData.subtitleStreamIndex,
DefaultSecondarySubtitleStreamIndex: prevPlayerData.secondarySubtitleStreamIndex
};
}
@ -2910,9 +3065,11 @@ class PlaybackManager {
if (mediaSource) {
playerData.audioStreamIndex = mediaSource.DefaultAudioStreamIndex;
playerData.subtitleStreamIndex = mediaSource.DefaultSubtitleStreamIndex;
playerData.secondarySubtitleStreamIndex = mediaSource.DefaultSecondarySubtitleStreamIndex;
} else {
playerData.audioStreamIndex = null;
playerData.subtitleStreamIndex = null;
playerData.secondarySubtitleStreamIndex = null;
}
self._playNextAfterEnded = true;
@ -3305,12 +3462,6 @@ class PlaybackManager {
streamInfo.lastMediaInfoQuery = new Date().getTime();
const apiClient = ServerConnections.getApiClient(serverId);
if (!apiClient.isMinServerVersion('3.2.70.7')) {
return;
}
ServerConnections.getApiClient(serverId).getLiveStreamMediaInfo(liveStreamId).then(function (info) {
mediaSource.MediaStreams = info.MediaStreams;
Events.trigger(player, 'mediastreamschange');

View File

@ -8,6 +8,8 @@ import { appRouter } from '../components/appRouter';
import * as inputManager from '../scripts/inputManager';
import toast from '../components/toast/toast';
import confirm from '../components/confirm/confirm';
import * as dashboard from '../utils/dashboard';
import ServerConnections from '../components/ServerConnections';
// TODO: replace with each plugin version
const cacheParam = new Date().getTime();
@ -86,7 +88,9 @@ class PluginManager {
appRouter,
inputManager,
toast,
confirm
confirm,
dashboard,
ServerConnections
});
} else {
console.debug(`Loading plugin (via dynamic import): ${pluginSpec}`);

View File

@ -4,7 +4,7 @@ import globalize from '../../scripts/globalize';
import layoutManager from '../layoutManager';
import loading from '../loading/loading';
import scrollHelper from '../../scripts/scrollHelper';
import '../../assets/css/scrollstyles.scss';
import '../../styles/scrollstyles.scss';
import '../../elements/emby-button/emby-button';
import '../../elements/emby-collapse/emby-collapse';
import '../../elements/emby-input/emby-input';
@ -12,7 +12,7 @@ import '../../elements/emby-button/paper-icon-button-light';
import '../formdialog.scss';
import './recordingcreator.scss';
import 'material-design-icons-iconfont';
import '../../assets/css/flexstyles.scss';
import '../../styles/flexstyles.scss';
import ServerConnections from '../ServerConnections';
import template from './recordingeditor.template.html';

View File

@ -7,7 +7,7 @@ import recordingHelper from './recordinghelper';
import '../../elements/emby-button/emby-button';
import '../../elements/emby-button/paper-icon-button-light';
import './recordingfields.scss';
import '../../assets/css/flexstyles.scss';
import '../../styles/flexstyles.scss';
import ServerConnections from '../ServerConnections';
import toast from '../toast/toast';
import template from './recordingfields.template.html';

View File

@ -4,7 +4,7 @@ import layoutManager from '../layoutManager';
import loading from '../loading/loading';
import scrollHelper from '../../scripts/scrollHelper';
import datetime from '../../scripts/datetime';
import '../../assets/css/scrollstyles.scss';
import '../../styles/scrollstyles.scss';
import '../../elements/emby-button/emby-button';
import '../../elements/emby-checkbox/emby-checkbox';
import '../../elements/emby-input/emby-input';
@ -13,7 +13,7 @@ import '../../elements/emby-button/paper-icon-button-light';
import '../formdialog.scss';
import './recordingcreator.scss';
import 'material-design-icons-iconfont';
import '../../assets/css/flexstyles.scss';
import '../../styles/flexstyles.scss';
import ServerConnections from '../ServerConnections';
import template from './seriesrecordingeditor.template.html';

View File

@ -7,7 +7,7 @@ import globalize from '../../scripts/globalize';
import 'material-design-icons-iconfont';
import '../../elements/emby-input/emby-input';
import '../../assets/css/flexstyles.scss';
import '../../styles/flexstyles.scss';
import './searchfields.scss';
import layoutManager from '../layoutManager';
import browser from '../../scripts/browser';

View File

@ -7,7 +7,7 @@ import '../../elements/emby-button/paper-icon-button-light';
import 'material-design-icons-iconfont';
import '../formdialog.scss';
import '../../elements/emby-button/emby-button';
import '../../assets/css/flexstyles.scss';
import '../../styles/flexstyles.scss';
import template from './sortmenu.template.html';
function onSubmit(e) {

View File

@ -14,7 +14,7 @@ import '../formdialog.scss';
import 'material-design-icons-iconfont';
import './subtitleeditor.scss';
import '../../elements/emby-button/emby-button';
import '../../assets/css/flexstyles.scss';
import '../../styles/flexstyles.scss';
import ServerConnections from '../ServerConnections';
import toast from '../toast/toast';
import confirm from '../confirm/confirm';

View File

@ -13,7 +13,7 @@ import '../../elements/emby-select/emby-select';
import '../../elements/emby-slider/emby-slider';
import '../../elements/emby-input/emby-input';
import '../../elements/emby-checkbox/emby-checkbox';
import '../../assets/css/flexstyles.scss';
import '../../styles/flexstyles.scss';
import './subtitlesettings.scss';
import ServerConnections from '../ServerConnections';
import toast from '../toast/toast';

View File

@ -101,14 +101,16 @@
<div class="selectContainer hide">
<select is="emby-select" id="selectTextColor" label="${LabelTextColor}">
<option value="#ffffff">${White}</option>
<option value="#ffff00">${Yellow}</option>
<option value="#008000">${Green}</option>
<option value="#00ffff">${Cyan}</option>
<option value="#0000ff">${Blue}</option>
<option value="#ff00ff">${Magenta}</option>
<option value="#ff0000">${Red}</option>
<option value="#000000">${Black}</option>
<option value="#ffffff">${SubtitleWhite}</option>
<option value="#d3d3d3">${SubtitleLightGray}</option>
<option value="#808080">${SubtitleGray}</option>
<option value="#ffff00">${SubtitleYellow}</option>
<option value="#008000">${SubtitleGreen}</option>
<option value="#00ffff">${SubtitleCyan}</option>
<option value="#0000ff">${SubtitleBlue}</option>
<option value="#ff00ff">${SubtitleMagenta}</option>
<option value="#ff0000">${SubtitleRed}</option>
<option value="#000000">${SubtitleBlack}</option>
</select>
</div>

View File

@ -7,7 +7,7 @@ import '../listview/listview.scss';
import '../../elements/emby-button/paper-icon-button-light';
import '../../elements/emby-select/emby-select';
import '../../elements/emby-button/emby-button';
import '../../assets/css/flexstyles.scss';
import '../../styles/flexstyles.scss';
import './style.scss';
import Dashboard from '../../utils/dashboard';
import Events from '../../utils/events.ts';

View File

@ -8,7 +8,7 @@ import globalize from '../../scripts/globalize';
import itemHelper from '../itemHelper';
import './upnextdialog.scss';
import '../../elements/emby-button/emby-button';
import '../../assets/css/flexstyles.scss';
import '../../styles/flexstyles.scss';
/* eslint-disable indent */

View File

@ -28,9 +28,9 @@
.upNextDialog-countdownText {
font-weight: 500;
white-space: nowrap;
}
.upNextDialog-nextVideoText,
.upNextDialog-title {
width: 25.5em;
white-space: nowrap;

View File

@ -12,7 +12,10 @@ const userDataMethods = {
markFavorite: markFavorite
};
function getUserDataButtonHtml(method, itemId, serverId, buttonCssClass, iconCssClass, icon, tooltip, style) {
function getUserDataButtonHtml(method, itemId, serverId, icon, tooltip, style, classes) {
let buttonCssClass = classes.buttonCssClass;
let iconCssClass = classes.iconCssClass;
if (style === 'fab-mini') {
style = 'fab';
buttonCssClass = buttonCssClass ? (buttonCssClass + ' mini') : 'mini';
@ -96,7 +99,7 @@ function getIconsHtml(options) {
}
const iconCssClass = options.iconCssClass;
const classes = { buttonCssClass: btnCssClass, iconCssClass: iconCssClass };
const serverId = item.ServerId;
if (includePlayed !== false) {
@ -104,18 +107,21 @@ function getIconsHtml(options) {
if (itemHelper.canMarkPlayed(item)) {
if (userData.Played) {
html += getUserDataButtonHtml('markPlayed', itemId, serverId, btnCssClass + ' btnUserDataOn', iconCssClass, 'check', tooltipPlayed, style);
const buttonCssClass = classes.buttonCssClass + ' btnUserDataOn';
html += getUserDataButtonHtml('markPlayed', itemId, serverId, 'check', tooltipPlayed, style, { buttonCssClass, ...classes });
} else {
html += getUserDataButtonHtml('markPlayed', itemId, serverId, btnCssClass, iconCssClass, 'check', tooltipPlayed, style);
html += getUserDataButtonHtml('markPlayed', itemId, serverId, 'check', tooltipPlayed, style, classes);
}
}
}
const tooltipFavorite = globalize.translate('Favorite');
if (userData.IsFavorite) {
html += getUserDataButtonHtml('markFavorite', itemId, serverId, btnCssClass + ' btnUserData btnUserDataOn', iconCssClass, 'favorite', tooltipFavorite, style);
const buttonCssClass = classes.buttonCssClass + ' btnUserData btnUserDataOn';
html += getUserDataButtonHtml('markFavorite', itemId, serverId, 'favorite', tooltipFavorite, style, { buttonCssClass, ...classes });
} else {
html += getUserDataButtonHtml('markFavorite', itemId, serverId, btnCssClass + ' btnUserData', iconCssClass, 'favorite', tooltipFavorite, style);
classes.buttonCssClass += ' btnUserData';
html += getUserDataButtonHtml('markFavorite', itemId, serverId, 'favorite', tooltipFavorite, style, classes);
}
return html;

View File

@ -9,7 +9,7 @@ import '../../elements/emby-button/paper-icon-button-light';
import '../../elements/emby-select/emby-select';
import 'material-design-icons-iconfont';
import '../formdialog.scss';
import '../../assets/css/flexstyles.scss';
import '../../styles/flexstyles.scss';
import template from './viewSettings.template.html';
function onSubmit(e) {

View File

@ -16,7 +16,7 @@ import imageHelper from '../../scripts/imagehelper';
import indicators from '../../components/indicators/indicators';
import '../../components/listview/listview.scss';
import '../../elements/emby-button/emby-button';
import '../../assets/css/flexstyles.scss';
import '../../styles/flexstyles.scss';
import '../../elements/emby-itemscontainer/emby-itemscontainer';
import taskButton from '../../scripts/taskbutton';
import Dashboard from '../../utils/dashboard';

View File

@ -54,15 +54,11 @@ import confirm from '../../../components/confirm/confirm';
}
function showDeviceMenu(view, btn, deviceId) {
const menuItems = [];
if (canEdit) {
menuItems.push({
name: globalize.translate('Edit'),
id: 'open',
icon: 'mode_edit'
});
}
const menuItems = [{
name: globalize.translate('Edit'),
id: 'open',
icon: 'mode_edit'
}];
if (canDelete(deviceId)) {
menuItems.push({
@ -100,7 +96,7 @@ import confirm from '../../../components/confirm/confirm';
deviceHtml += '<div class="cardBox visualCardBox">';
deviceHtml += '<div class="cardScalable">';
deviceHtml += '<div class="cardPadder cardPadder-backdrop"></div>';
deviceHtml += `<a is="emby-linkbutton" href="${canEdit ? '#/device.html?id=' + device.Id : '#'}" class="cardContent cardImageContainer ${cardBuilder.getDefaultBackgroundClass()}">`;
deviceHtml += `<a is="emby-linkbutton" href="#/device.html?id=${device.Id}" class="cardContent cardImageContainer ${cardBuilder.getDefaultBackgroundClass()}">`;
const iconUrl = imageHelper.getDeviceIcon(device);
if (iconUrl) {
@ -114,7 +110,7 @@ import confirm from '../../../components/confirm/confirm';
deviceHtml += '</div>';
deviceHtml += '<div class="cardFooter">';
if (canEdit || canDelete(device.Id)) {
if (canDelete(device.Id)) {
if (globalize.getIsRTL())
deviceHtml += '<div style="text-align:left; float:left;padding-top:5px;">';
else
@ -155,7 +151,6 @@ import confirm from '../../../components/confirm/confirm';
});
}
const canEdit = ApiClient.isMinServerVersion('3.4.1.31');
export default function (view) {
view.querySelector('.devicesList').addEventListener('click', function (e) {
const btnDeviceMenu = dom.parentWithClass(e.target, 'btnDeviceMenu');

View File

@ -3,7 +3,7 @@ import loading from '../../components/loading/loading';
import globalize from '../../scripts/globalize';
import '../../elements/emby-button/emby-button';
import '../../components/listview/listview.scss';
import '../../assets/css/flexstyles.scss';
import '../../styles/flexstyles.scss';
import Dashboard from '../../utils/dashboard';
import alert from '../../components/alert';

View File

@ -26,7 +26,7 @@
<div class="fieldDescription">${LabelDummyChapterDurationHelp}</div>
</div>
<div class="inputContainer">
<input is="emby-input" type="number" id="valDummyChapterCount" label="${LabelDummyChapterCount}" min="1"></input>
<input is="emby-input" type="number" id="valDummyChapterCount" label="${LabelDummyChapterCount}" min="0"></input>
<div class="fieldDescription">${LabelDummyChapterCountHelp}</div>
</div>
<div class="selectContainer">

View File

@ -68,7 +68,7 @@ function renderPackage(pkg, installedPlugins, page) {
if (installedPlugin) {
const currentVersionText = globalize.translate('MessageYouHaveVersionInstalled', '<strong>' + installedPlugin.Version + '</strong>');
$('#pCurrentVersion', page).show().text(currentVersionText);
$('#pCurrentVersion', page).show().html(currentVersionText);
} else {
$('#pCurrentVersion', page).hide().text('');
}

View File

@ -1,5 +1,6 @@
import { intervalToDuration } from 'date-fns';
import DOMPurify from 'dompurify';
import { marked } from 'marked';
import escapeHtml from 'escape-html';
import isEqual from 'lodash-es/isEqual';
@ -22,7 +23,7 @@ import libraryMenu from '../../scripts/libraryMenu';
import globalize from '../../scripts/globalize';
import browser from '../../scripts/browser';
import { playbackManager } from '../../components/playback/playbackmanager';
import '../../assets/css/scrollstyles.scss';
import '../../styles/scrollstyles.scss';
import '../../elements/emby-itemscontainer/emby-itemscontainer';
import '../../elements/emby-checkbox/emby-checkbox';
import '../../elements/emby-button/emby-button';
@ -177,34 +178,7 @@ function renderTrackSelections(page, instance, item, forceReload) {
return;
}
let mediaSources = item.MediaSources;
const resolutionNames = [];
const sourceNames = [];
mediaSources.forEach(function (v) {
(v.Name.endsWith('p') || v.Name.endsWith('i')) && !Number.isNaN(parseInt(v.Name, 10)) ? resolutionNames.push(v) : sourceNames.push(v);
});
resolutionNames.sort((a, b) => parseInt(b.Name, 10) - parseInt(a.Name, 10));
sourceNames.sort((a, b) => {
const nameA = a.Name.toUpperCase();
const nameB = b.Name.toUpperCase();
if (nameA < nameB) {
return -1;
} else if (nameA > nameB) {
return 1;
}
return 0;
});
mediaSources = [];
resolutionNames.forEach(v => {
mediaSources.push(v);
});
sourceNames.forEach(v => {
mediaSources.push(v);
});
const mediaSources = item.MediaSources;
instance._currentPlaybackMediaSources = mediaSources;
page.querySelector('.trackSelections').classList.remove('hide');
@ -904,7 +878,7 @@ function renderOverview(page, item) {
const overviewElements = page.querySelectorAll('.overview');
if (overviewElements.length > 0) {
const overview = DOMPurify.sanitize(item.Overview || '');
const overview = DOMPurify.sanitize(marked(item.Overview || ''));
if (overview) {
for (const overviewElemnt of overviewElements) {
@ -1090,7 +1064,7 @@ function renderTagline(page, item) {
}
}
function renderDetails(page, item, apiClient, context, isStatic) {
function renderDetails(page, item, apiClient, context) {
renderSimilarItems(page, item, context);
renderMoreFromSeason(page, item, apiClient);
renderMoreFromArtist(page, item, apiClient);
@ -1110,7 +1084,7 @@ function renderDetails(page, item, apiClient, context, isStatic) {
}
renderTags(page, item);
renderSeriesAirTime(page, item, isStatic);
renderSeriesAirTime(page, item);
}
function enableScrollX() {
@ -1183,12 +1157,7 @@ function renderMoreFromArtist(view, item, apiClient) {
const section = view.querySelector('.moreFromArtistSection');
if (section) {
if (item.Type === 'MusicArtist') {
if (!apiClient.isMinServerVersion('3.4.1.19')) {
section.classList.add('hide');
return;
}
} else if (item.Type !== 'MusicAlbum' || !item.AlbumArtists || !item.AlbumArtists.length) {
if (item.Type !== 'MusicArtist' && (item.Type !== 'MusicAlbum' || !item.AlbumArtists || !item.AlbumArtists.length)) {
section.classList.add('hide');
return;
}
@ -1289,7 +1258,7 @@ function renderSimilarItems(page, item, context) {
}
}
function renderSeriesAirTime(page, item, isStatic) {
function renderSeriesAirTime(page, item) {
const seriesAirTime = page.querySelector('#seriesAirTime');
if (item.Type != 'Series') {
seriesAirTime.classList.add('hide');
@ -1308,19 +1277,6 @@ function renderSeriesAirTime(page, item, isStatic) {
if (item.AirTime) {
html += ' at ' + item.AirTime;
}
if (item.Studios.length) {
if (isStatic) {
html += ' on ' + escapeHtml(item.Studios[0].Name);
} else {
const context = inferContext(item);
const href = appRouter.getRouteUrl(item.Studios[0], {
context: context,
itemType: 'Studio',
serverId: item.ServerId
});
html += ' on <a class="textlink button-link" is="emby-linkbutton" href="' + href + '">' + escapeHtml(item.Studios[0].Name) + '</a>';
}
}
if (html) {
html = (item.Status == 'Ended' ? 'Aired ' : 'Airs ') + html;
seriesAirTime.innerHTML = html;

View File

@ -6,7 +6,7 @@ import globalize from '../../scripts/globalize';
import * as mainTabsManager from '../../components/maintabsmanager';
import cardBuilder from '../../components/cardbuilder/cardBuilder';
import imageLoader from '../../components/images/imageLoader';
import '../../assets/css/scrollstyles.scss';
import '../../styles/scrollstyles.scss';
import '../../elements/emby-itemscontainer/emby-itemscontainer';
import '../../elements/emby-tabs/emby-tabs';
import '../../elements/emby-button/emby-button';

View File

@ -7,7 +7,7 @@ import layoutManager from '../components/layoutManager';
import loading from '../components/loading/loading';
import browser from '../scripts/browser';
import '../components/listview/listview.scss';
import '../assets/css/flexstyles.scss';
import '../styles/flexstyles.scss';
import '../elements/emby-itemscontainer/emby-itemscontainer';
import '../components/cardbuilder/card.scss';
import 'material-design-icons-iconfont';

View File

@ -9,11 +9,11 @@ import imageLoader from '../../components/images/imageLoader';
import libraryMenu from '../../scripts/libraryMenu';
import * as mainTabsManager from '../../components/maintabsmanager';
import globalize from '../../scripts/globalize';
import '../../assets/css/scrollstyles.scss';
import '../../styles/scrollstyles.scss';
import '../../elements/emby-itemscontainer/emby-itemscontainer';
import '../../elements/emby-tabs/emby-tabs';
import '../../elements/emby-button/emby-button';
import '../../assets/css/flexstyles.scss';
import '../../styles/flexstyles.scss';
import Dashboard from '../../utils/dashboard';
/* eslint-disable indent */

View File

@ -15,10 +15,10 @@ import { appHost } from '../../../components/apphost';
import layoutManager from '../../../components/layoutManager';
import * as userSettings from '../../../scripts/settings/userSettings';
import keyboardnavigation from '../../../scripts/keyboardNavigation';
import '../../../assets/css/scrollstyles.scss';
import '../../../styles/scrollstyles.scss';
import '../../../elements/emby-slider/emby-slider';
import '../../../elements/emby-button/paper-icon-button-light';
import '../../../assets/css/videoosd.scss';
import '../../../styles/videoosd.scss';
import ServerConnections from '../../../components/ServerConnections';
import shell from '../../../scripts/shell';
import SubtitleSync from '../../../components/subtitlesync/subtitlesync';
@ -988,9 +988,57 @@ import { setBackdropTransparency, TRANSPARENCY_LEVEL } from '../../../components
});
}
function showSecondarySubtitlesMenu(actionsheet, positionTo) {
const player = currentPlayer;
if (!playbackManager.playerHasSecondarySubtitleSupport(player)) return;
let currentIndex = playbackManager.getSecondarySubtitleStreamIndex(player);
const streams = playbackManager.secondarySubtitleTracks(player);
if (currentIndex == null) {
currentIndex = -1;
}
streams.unshift({
Index: -1,
DisplayTitle: globalize.translate('Off')
});
const menuItems = streams.map(function (stream) {
const opt = {
name: stream.DisplayTitle,
id: stream.Index
};
if (stream.Index === currentIndex) {
opt.selected = true;
}
return opt;
});
actionsheet.show({
title: globalize.translate('SecondarySubtitles'),
items: menuItems,
positionTo
}).then(function (id) {
if (id) {
const index = parseInt(id);
if (index !== currentIndex) {
playbackManager.setSecondarySubtitleStreamIndex(index, player);
}
}
})
.finally(() => {
resetIdle();
});
setTimeout(resetIdle, 0);
}
function showSubtitleTrackSelection() {
const player = currentPlayer;
const streams = playbackManager.subtitleTracks(player);
const secondaryStreams = playbackManager.secondarySubtitleTracks(player);
let currentIndex = playbackManager.getSubtitleStreamIndex(player);
if (currentIndex == null) {
@ -1013,6 +1061,29 @@ import { setBackdropTransparency, TRANSPARENCY_LEVEL } from '../../../components
return opt;
});
/**
* Only show option if:
* - player has support
* - has more than 1 subtitle track
* - has valid secondary tracks
* - primary subtitle is not off
* - primary subtitle has support
*/
const currentTrackCanAddSecondarySubtitle = playbackManager.playerHasSecondarySubtitleSupport(player)
&& streams.length > 1
&& secondaryStreams.length > 0
&& currentIndex !== -1
&& playbackManager.trackHasSecondarySubtitleSupport(playbackManager.getSubtitleStream(player, currentIndex), player);
if (currentTrackCanAddSecondarySubtitle) {
const secondarySubtitleMenuItem = {
name: globalize.translate('SecondarySubtitles'),
id: 'secondarysubtitle'
};
menuItems.unshift(secondarySubtitleMenuItem);
}
const positionTo = this;
import('../../../components/actionSheet/actionSheet').then(({default: actionsheet}) => {
@ -1021,10 +1092,18 @@ import { setBackdropTransparency, TRANSPARENCY_LEVEL } from '../../../components
items: menuItems,
positionTo: positionTo
}).then(function (id) {
const index = parseInt(id);
if (id === 'secondarysubtitle') {
try {
showSecondarySubtitlesMenu(actionsheet, positionTo);
} catch (e) {
console.error(e);
}
} else {
const index = parseInt(id);
if (index !== currentIndex) {
playbackManager.setSubtitleStreamIndex(index, player);
if (index !== currentIndex) {
playbackManager.setSubtitleStreamIndex(index, player);
}
}
toggleSubtitleSync();

View File

@ -10,7 +10,7 @@ import actionSheet from '../../../components/actionSheet/actionSheet';
import dom from '../../../scripts/dom';
import browser from '../../../scripts/browser';
import 'material-design-icons-iconfont';
import '../../../assets/css/flexstyles.scss';
import '../../../styles/flexstyles.scss';
import '../../../elements/emby-scroller/emby-scroller';
import '../../../elements/emby-itemscontainer/emby-itemscontainer';
import '../../../components/cardbuilder/card.scss';

View File

@ -9,7 +9,7 @@ import cardBuilder from '../../components/cardbuilder/cardBuilder';
import { playbackManager } from '../../components/playback/playbackmanager';
import * as mainTabsManager from '../../components/maintabsmanager';
import globalize from '../../scripts/globalize';
import '../../assets/css/scrollstyles.scss';
import '../../styles/scrollstyles.scss';
import '../../elements/emby-itemscontainer/emby-itemscontainer';
import '../../elements/emby-button/emby-button';
import Dashboard from '../../utils/dashboard';

View File

@ -4,7 +4,7 @@ import datetime from '../../scripts/datetime';
import cardBuilder from '../../components/cardbuilder/cardBuilder';
import imageLoader from '../../components/images/imageLoader';
import globalize from '../../scripts/globalize';
import '../../assets/css/scrollstyles.scss';
import '../../styles/scrollstyles.scss';
import '../../elements/emby-itemscontainer/emby-itemscontainer';
/* eslint-disable indent */

View File

@ -1,6 +1,6 @@
import loading from '../../../components/loading/loading';
import globalize from '../../../scripts/globalize';
import '../../../assets/css/dashboard.scss';
import '../../../styles/dashboard.scss';
import '../../../elements/emby-input/emby-input';
import '../../../elements/emby-button/emby-button';
import Dashboard from '../../../utils/dashboard';

View File

@ -5,7 +5,7 @@ import browser from '../../scripts/browser';
import focusManager from '../../components/focusManager';
import layoutManager from '../../components/layoutManager';
import './emby-tabs.scss';
import '../../assets/css/scrollstyles.scss';
import '../../styles/scrollstyles.scss';
/* eslint-disable indent */
const EmbyTabs = Object.create(HTMLDivElement.prototype);

View File

@ -6,7 +6,7 @@ import 'intersection-observer';
import 'classlist.js';
import 'whatwg-fetch';
import 'resize-observer-polyfill';
import './assets/css/site.scss';
import './styles/site.scss';
import React, { StrictMode } from 'react';
import * as ReactDOM from 'react-dom';
import Events from './utils/events.ts';
@ -24,7 +24,6 @@ import { appRouter, history } from './components/appRouter';
import './elements/emby-button/emby-button';
import './scripts/autoThemes';
import './scripts/libraryMenu';
import './scripts/routes';
import './components/themeMediaPlayer';
import './scripts/autoBackdrops';
import { pageClassOn, serverAddress } from './utils/dashboard';
@ -39,6 +38,10 @@ import { currentSettings } from './scripts/settings/userSettings';
import taskButton from './scripts/taskbutton';
import App from './App.tsx';
import './styles/livetv.scss';
import './styles/dashboard.scss';
import './styles/detailtable.scss';
function loadCoreDictionary() {
const languages = ['af', 'ar', 'be-by', 'bg-bg', 'bn_bd', 'ca', 'cs', 'cy', 'da', 'de', 'el', 'en-gb', 'en-us', 'eo', 'es', 'es_419', 'es-ar', 'es_do', 'es-mx', 'et', 'eu', 'fa', 'fi', 'fil', 'fr', 'fr-ca', 'gl', 'gsw', 'he', 'hi-in', 'hr', 'hu', 'id', 'it', 'ja', 'kk', 'ko', 'lt-lt', 'lv', 'mr', 'ms', 'nb', 'nl', 'nn', 'pl', 'pr', 'pt', 'pt-br', 'pt-pt', 'ro', 'ru', 'sk', 'sl-si', 'sq', 'sv', 'ta', 'th', 'tr', 'uk', 'ur_pk', 'vi', 'zh-cn', 'zh-hk', 'zh-tw'];
const translations = languages.map(function (language) {
@ -89,13 +92,13 @@ function onGlobalizeInit() {
if (browser.tv && !browser.android) {
console.debug('using system fonts with explicit sizes');
import('./assets/css/fonts.sized.scss');
import('./styles/fonts.sized.scss');
} else {
console.debug('using default fonts');
import('./assets/css/fonts.scss');
import('./styles/fonts.scss');
}
import('./assets/css/librarybrowser.scss');
import('./styles/librarybrowser.scss');
loadPlugins().then(onAppReady);
}
@ -135,7 +138,7 @@ async function onAppReady() {
console.debug('onAppReady: loading dependencies');
if (browser.iOS) {
import('./assets/css/ios.scss');
import('./styles/ios.scss');
}
Events.on(appHost, 'resume', () => {

View File

@ -6,7 +6,7 @@
import browser from '../../scripts/browser';
import dom from '../../scripts/dom';
import './navdrawer.scss';
import '../../assets/css/scrollstyles.scss';
import '../../styles/scrollstyles.scss';
import globalize from '../../scripts/globalize';
function getTouches(e) {

View File

@ -8,7 +8,7 @@ import layoutManager from '../components/layoutManager';
import dom from '../scripts/dom';
import focusManager from '../components/focusManager';
import ResizeObserver from 'resize-observer-polyfill';
import '../assets/css/scrollstyles.scss';
import '../styles/scrollstyles.scss';
import globalize from '../scripts/globalize';
/**

View File

@ -48,6 +48,9 @@ function supportsFade() {
function requireHlsPlayer(callback) {
import('hls.js').then(({ default: hls }) => {
hls.DefaultConfig.lowLatencyMode = false;
hls.DefaultConfig.backBufferLength = Infinity;
hls.DefaultConfig.liveBackBufferLength = 90;
window.Hls = hls;
callback();
});

View File

@ -32,6 +32,7 @@ import { getIncludeCorsCredentials } from '../../scripts/settings/webSettings';
import { setBackdropTransparency, TRANSPARENCY_LEVEL } from '../../components/backdrop/backdrop';
import Events from '../../utils/events.ts';
import { includesAny } from '../../utils/container.ts';
import debounce from 'lodash-es/debounce';
/**
* Returns resolved URL.
@ -106,6 +107,9 @@ function tryRemoveElement(elem) {
function requireHlsPlayer(callback) {
import('hls.js').then(({default: hls}) => {
hls.DefaultConfig.lowLatencyMode = false;
hls.DefaultConfig.backBufferLength = Infinity;
hls.DefaultConfig.liveBackBufferLength = 90;
window.Hls = hls;
callback();
});
@ -155,6 +159,9 @@ function tryRemoveElement(elem) {
return profileBuilder({});
}
const PRIMARY_TEXT_TRACK_INDEX = 0;
const SECONDARY_TEXT_TRACK_INDEX = 1;
export class HtmlVideoPlayer {
/**
* @type {string}
@ -178,7 +185,6 @@ function tryRemoveElement(elem) {
* @type {boolean}
*/
isFetching = false;
/**
* @type {HTMLDivElement | null | undefined}
*/
@ -187,6 +193,10 @@ function tryRemoveElement(elem) {
* @type {number | undefined}
*/
#subtitleTrackIndexToSetOnPlaying;
/**
* @type {number | undefined}
*/
#secondarySubtitleTrackIndexToSetOnPlaying;
/**
* @type {number | null}
*/
@ -207,6 +217,10 @@ function tryRemoveElement(elem) {
* @type {number | undefined}
*/
#customTrackIndex;
/**
* @type {number | undefined}
*/
#customSecondaryTrackIndex;
/**
* @type {boolean | undefined}
*/
@ -215,14 +229,26 @@ function tryRemoveElement(elem) {
* @type {number | undefined}
*/
#currentTrackOffset;
/**
* @type {HTMLElement | null | undefined}
*/
#secondaryTrackOffset;
/**
* @type {HTMLElement | null | undefined}
*/
#videoSubtitlesElem;
/**
* @type {HTMLElement | null | undefined}
*/
#videoSecondarySubtitlesElem;
/**
* @type {any | null | undefined}
*/
#currentTrackEvents;
/**
* @type {any | null | undefined}
*/
#currentSecondaryTrackEvents;
/**
* @type {string[] | undefined}
*/
@ -356,7 +382,7 @@ function tryRemoveElement(elem) {
this.#currentTime = null;
this.resetSubtitleOffset();
if (options.resetSubtitleOffset !== false) this.resetSubtitleOffset();
return this.createMediaElement(options).then(elem => {
return this.updateVideoUrl(options).then(() => {
@ -448,18 +474,39 @@ function tryRemoveElement(elem) {
destroyFlvPlayer(this);
destroyCastPlayer(this);
let secondaryTrackValid = true;
this.#subtitleTrackIndexToSetOnPlaying = options.mediaSource.DefaultSubtitleStreamIndex == null ? -1 : options.mediaSource.DefaultSubtitleStreamIndex;
if (this.#subtitleTrackIndexToSetOnPlaying != null && this.#subtitleTrackIndexToSetOnPlaying >= 0) {
const initialSubtitleStream = options.mediaSource.MediaStreams[this.#subtitleTrackIndexToSetOnPlaying];
if (!initialSubtitleStream || initialSubtitleStream.DeliveryMethod === 'Encode') {
this.#subtitleTrackIndexToSetOnPlaying = -1;
secondaryTrackValid = false;
}
// secondary track should not be shown if primary track is no longer a valid pair
if (initialSubtitleStream && !playbackManager.trackHasSecondarySubtitleSupport(initialSubtitleStream, this)) {
secondaryTrackValid = false;
}
} else {
secondaryTrackValid = false;
}
this.#audioTrackIndexToSetOnPlaying = options.playMethod === 'Transcode' ? null : options.mediaSource.DefaultAudioStreamIndex;
this._currentPlayOptions = options;
if (secondaryTrackValid) {
this.#secondarySubtitleTrackIndexToSetOnPlaying = options.mediaSource.DefaultSecondarySubtitleStreamIndex == null ? -1 : options.mediaSource.DefaultSecondarySubtitleStreamIndex;
if (this.#secondarySubtitleTrackIndexToSetOnPlaying != null && this.#secondarySubtitleTrackIndexToSetOnPlaying >= 0) {
const initialSecondarySubtitleStream = options.mediaSource.MediaStreams[this.#secondarySubtitleTrackIndexToSetOnPlaying];
if (!initialSecondarySubtitleStream || !playbackManager.trackHasSecondarySubtitleSupport(initialSecondarySubtitleStream, this)) {
this.#secondarySubtitleTrackIndexToSetOnPlaying = -1;
}
}
} else {
this.#secondarySubtitleTrackIndexToSetOnPlaying = -1;
}
const crossOrigin = getCrossOriginValue(options.mediaSource);
if (crossOrigin) {
elem.crossOrigin = crossOrigin;
@ -490,8 +537,13 @@ function tryRemoveElement(elem) {
this.setCurrentTrackElement(index);
}
setSecondarySubtitleStreamIndex(index) {
this.setCurrentTrackElement(index, SECONDARY_TEXT_TRACK_INDEX);
}
resetSubtitleOffset() {
this.#currentTrackOffset = 0;
this.#secondaryTrackOffset = 0;
this.#showTrackOffset = false;
}
@ -510,11 +562,11 @@ function tryRemoveElement(elem) {
/**
* @private
*/
getTextTrack() {
getTextTracks() {
const videoElement = this.#mediaElement;
if (videoElement) {
return Array.from(videoElement.textTracks)
.find(function (trackElement) {
.filter(function (trackElement) {
// get showing .vtt textTack
return trackElement.mode === 'showing';
});
@ -523,10 +575,12 @@ function tryRemoveElement(elem) {
}
}
setSubtitleOffset = debounce(this._setSubtitleOffset, 100);
/**
* @private
*/
setSubtitleOffset(offset) {
_setSubtitleOffset(offset) {
const offsetValue = parseFloat(offset);
// if .ass currently rendering
@ -534,12 +588,15 @@ function tryRemoveElement(elem) {
this.updateCurrentTrackOffset(offsetValue);
this.#currentSubtitlesOctopus.timeOffset = (this._currentPlayOptions.transcodingOffsetTicks || 0) / 10000000 + offsetValue;
} else {
const trackElement = this.getTextTrack();
const trackElements = this.getTextTracks();
// if .vtt currently rendering
if (trackElement) {
this.setTextTrackSubtitleOffset(trackElement, offsetValue);
} else if (this.#currentTrackEvents) {
this.setTrackEventsSubtitleOffset(this.#currentTrackEvents, offsetValue);
if (trackElements?.length > 0) {
trackElements.forEach((trackElement, index) => {
this.setTextTrackSubtitleOffset(trackElement, offsetValue, index);
});
} else if (this.#currentTrackEvents || this.#currentSecondaryTrackEvents) {
this.#currentTrackEvents && this.setTrackEventsSubtitleOffset(this.#currentTrackEvents, offsetValue, PRIMARY_TEXT_TRACK_INDEX);
this.#currentSecondaryTrackEvents && this.setTrackEventsSubtitleOffset(this.#currentSecondaryTrackEvents, offsetValue, SECONDARY_TEXT_TRACK_INDEX);
} else {
console.debug('No available track, cannot apply offset: ', offsetValue);
}
@ -549,37 +606,100 @@ function tryRemoveElement(elem) {
/**
* @private
*/
updateCurrentTrackOffset(offsetValue) {
updateCurrentTrackOffset(offsetValue, currentTrackIndex = PRIMARY_TEXT_TRACK_INDEX) {
let offsetToCompare = this.#currentTrackOffset;
if (this.isSecondaryTrack(currentTrackIndex)) {
offsetToCompare = this.#secondaryTrackOffset;
}
let relativeOffset = offsetValue;
const newTrackOffset = offsetValue;
if (this.#currentTrackOffset) {
relativeOffset -= this.#currentTrackOffset;
if (offsetToCompare) {
relativeOffset -= offsetToCompare;
}
this.#currentTrackOffset = newTrackOffset;
if (this.isSecondaryTrack(currentTrackIndex)) {
this.#secondaryTrackOffset = newTrackOffset;
} else {
this.#currentTrackOffset = newTrackOffset;
}
// relative to currentTrackOffset
return relativeOffset;
}
/**
* @private
* These browsers will not clear the existing active cue when setting an offset
* for native TextTracks.
* Any previous text tracks that are on the screen when the offset changes will remain next
* to the new tracks until they reach the end time of the new offset's instance of the track.
*/
setTextTrackSubtitleOffset(currentTrack, offsetValue) {
if (currentTrack.cues) {
offsetValue = this.updateCurrentTrackOffset(offsetValue);
Array.from(currentTrack.cues)
.forEach(function (cue) {
cue.startTime -= offsetValue;
cue.endTime -= offsetValue;
});
requiresHidingActiveCuesOnOffsetChange() {
return !!browser.firefox;
}
/**
* @private
*/
hideTextTrackWithActiveCues(currentTrack) {
if (currentTrack.activeCues) {
currentTrack.mode = 'hidden';
}
}
/**
* Forces the active cue to clear by disabling then re-enabling the track.
* The track mode is reverted inside of a 0ms timeout to free up the track
* and allow it to disable and clear the active cue.
* @private
*/
forceClearTextTrackActiveCues(currentTrack) {
if (currentTrack.activeCues) {
currentTrack.mode = 'disabled';
setTimeout(() => {
currentTrack.mode = 'showing';
}, 0);
}
}
/**
* @private
*/
setTrackEventsSubtitleOffset(trackEvents, offsetValue) {
setTextTrackSubtitleOffset(currentTrack, offsetValue, currentTrackIndex) {
if (currentTrack.cues) {
offsetValue = this.updateCurrentTrackOffset(offsetValue, currentTrackIndex);
if (offsetValue === 0) {
return;
}
const shouldClearActiveCues = this.requiresHidingActiveCuesOnOffsetChange();
if (shouldClearActiveCues) {
this.hideTextTrackWithActiveCues(currentTrack);
}
Array.from(currentTrack.cues)
.forEach(function (cue) {
cue.startTime -= offsetValue;
cue.endTime -= offsetValue;
});
if (shouldClearActiveCues) {
this.forceClearTextTrackActiveCues(currentTrack);
}
}
}
/**
* @private
*/
setTrackEventsSubtitleOffset(trackEvents, offsetValue, currentTrackIndex) {
if (Array.isArray(trackEvents)) {
offsetValue = this.updateCurrentTrackOffset(offsetValue) * 1e7; // ticks
offsetValue = this.updateCurrentTrackOffset(offsetValue, currentTrackIndex) * 1e7; // ticks
if (offsetValue === 0) {
return;
}
trackEvents.forEach(function (trackEvent) {
trackEvent.StartPositionTicks -= offsetValue;
trackEvent.EndPositionTicks -= offsetValue;
@ -591,6 +711,14 @@ function tryRemoveElement(elem) {
return this.#currentTrackOffset;
}
isPrimaryTrack(textTrackIndex) {
return textTrackIndex === PRIMARY_TEXT_TRACK_INDEX;
}
isSecondaryTrack(textTrackIndex) {
return textTrackIndex === SECONDARY_TEXT_TRACK_INDEX;
}
/**
* @private
*/
@ -697,6 +825,8 @@ function tryRemoveElement(elem) {
}
destroy() {
this.setSubtitleOffset.cancel();
destroyHlsPlayer(this);
destroyFlvPlayer(this);
@ -819,6 +949,16 @@ function tryRemoveElement(elem) {
if (this.#audioTrackIndexToSetOnPlaying != null && this.canSetAudioStreamIndex()) {
this.setAudioStreamIndex(this.#audioTrackIndexToSetOnPlaying);
}
if (this.#secondarySubtitleTrackIndexToSetOnPlaying != null && this.#secondarySubtitleTrackIndexToSetOnPlaying >= 0) {
/**
* Using a 0ms timeout to set the secondary subtitles because of some weird race condition when
* setting both primary and secondary tracks at the same time.
* The `TextTrack` content and cues will somehow get mixed up and each track will play a mix of both languages.
* Putting this in a timeout fixes it completely.
*/
setTimeout(() => this.setSecondarySubtitleStreamIndex(this.#secondarySubtitleTrackIndexToSetOnPlaying), 0);
}
}
/**
@ -956,27 +1096,75 @@ function tryRemoveElement(elem) {
/**
* @private
*/
destroyCustomTrack(videoElement) {
if (this.#videoSubtitlesElem) {
const subtitlesContainer = this.#videoSubtitlesElem.parentNode;
if (subtitlesContainer) {
tryRemoveElement(subtitlesContainer);
destroyCustomRenderedTrackElements(targetTrackIndex) {
if (this.isPrimaryTrack(targetTrackIndex)) {
if (this.#videoSubtitlesElem) {
tryRemoveElement(this.#videoSubtitlesElem);
this.#videoSubtitlesElem = null;
}
} else if (this.isSecondaryTrack(targetTrackIndex)) {
if (this.#videoSecondarySubtitlesElem) {
tryRemoveElement(this.#videoSecondarySubtitlesElem);
this.#videoSecondarySubtitlesElem = null;
}
} else { // destroy all
if (this.#videoSubtitlesElem) {
const subtitlesContainer = this.#videoSubtitlesElem.parentNode;
if (subtitlesContainer) {
tryRemoveElement(subtitlesContainer);
}
this.#videoSubtitlesElem = null;
this.#videoSecondarySubtitlesElem = null;
}
this.#videoSubtitlesElem = null;
}
}
this.#currentTrackEvents = null;
/**
* @private
*/
destroyNativeTracks(videoElement, targetTrackIndex) {
if (videoElement) {
const destroySingleTrack = typeof targetTrackIndex === 'number';
const allTracks = videoElement.textTracks || []; // get list of tracks
for (const track of allTracks) {
for (let index = 0; index < allTracks.length; index++) {
const track = allTracks[index];
// Skip all other tracks if we are targeting just one
if (destroySingleTrack && targetTrackIndex !== index) {
continue;
}
if (track.label.includes('manualTrack')) {
track.mode = 'disabled';
}
}
}
}
/**
* @private
*/
destroyStoredTrackInfo(targetTrackIndex) {
if (this.isPrimaryTrack(targetTrackIndex)) {
this.#customTrackIndex = -1;
this.#currentTrackEvents = null;
} else if (this.isSecondaryTrack(targetTrackIndex)) {
this.#customSecondaryTrackIndex = -1;
this.#currentSecondaryTrackEvents = null;
} else { // destroy all
this.#customTrackIndex = -1;
this.#customSecondaryTrackIndex = -1;
this.#currentTrackEvents = null;
this.#currentSecondaryTrackEvents = null;
}
}
/**
* @private
*/
destroyCustomTrack(videoElement, targetTrackIndex) {
this.destroyCustomRenderedTrackElements(targetTrackIndex);
this.destroyNativeTracks(videoElement, targetTrackIndex);
this.destroyStoredTrackInfo(targetTrackIndex);
this.#customTrackIndex = -1;
this.#currentClock = null;
this._currentAspectRatio = null;
@ -1029,23 +1217,34 @@ function tryRemoveElement(elem) {
/**
* @private
*/
setTrackForDisplay(videoElement, track) {
setTrackForDisplay(videoElement, track, targetTextTrackIndex = PRIMARY_TEXT_TRACK_INDEX) {
if (!track) {
this.destroyCustomTrack(videoElement);
// Destroy all tracks by passing undefined if there is no valid primary track
this.destroyCustomTrack(videoElement, this.isSecondaryTrack(targetTextTrackIndex) ? targetTextTrackIndex : undefined);
return;
}
let targetTrackIndex = this.#customTrackIndex;
if (this.isSecondaryTrack(targetTextTrackIndex)) {
targetTrackIndex = this.#customSecondaryTrackIndex;
}
// skip if already playing this track
if (this.#customTrackIndex === track.Index) {
if (targetTrackIndex === track.Index) {
return;
}
this.resetSubtitleOffset();
const item = this._currentPlayOptions.item;
this.destroyCustomTrack(videoElement);
this.#customTrackIndex = track.Index;
this.renderTracksEvents(videoElement, track, item);
this.destroyCustomTrack(videoElement, targetTextTrackIndex);
if (this.isSecondaryTrack(targetTextTrackIndex)) {
this.#customSecondaryTrackIndex = track.Index;
} else {
this.#customTrackIndex = track.Index;
}
this.renderTracksEvents(videoElement, track, item, targetTextTrackIndex);
}
/**
@ -1155,16 +1354,39 @@ function tryRemoveElement(elem) {
/**
* @private
*/
renderSubtitlesWithCustomElement(videoElement, track, item) {
this.fetchSubtitles(track, item).then((data) => {
if (!this.#videoSubtitlesElem) {
const subtitlesContainer = document.createElement('div');
subtitlesContainer.classList.add('videoSubtitles');
subtitlesContainer.innerHTML = '<div class="videoSubtitlesInner"></div>';
this.#videoSubtitlesElem = subtitlesContainer.querySelector('.videoSubtitlesInner');
renderSubtitlesWithCustomElement(videoElement, track, item, targetTextTrackIndex) {
Promise.all([import('../../scripts/settings/userSettings'), this.fetchSubtitles(track, item)]).then((results) => {
const [userSettings, subtitleData] = results;
const subtitleAppearance = userSettings.getSubtitleAppearanceSettings();
const subtitleVerticalPosition = parseInt(subtitleAppearance.verticalPosition, 10);
if (!this.#videoSubtitlesElem && !this.isSecondaryTrack(targetTextTrackIndex)) {
let subtitlesContainer = document.querySelector('.videoSubtitles');
if (!subtitlesContainer) {
subtitlesContainer = document.createElement('div');
subtitlesContainer.classList.add('videoSubtitles');
}
const subtitlesElement = document.createElement('div');
subtitlesElement.classList.add('videoSubtitlesInner');
subtitlesContainer.appendChild(subtitlesElement);
this.#videoSubtitlesElem = subtitlesElement;
this.setSubtitleAppearance(subtitlesContainer, this.#videoSubtitlesElem);
videoElement.parentNode.appendChild(subtitlesContainer);
this.#currentTrackEvents = data.TrackEvents;
this.#currentTrackEvents = subtitleData.TrackEvents;
} else if (!this.#videoSecondarySubtitlesElem && this.isSecondaryTrack(targetTextTrackIndex)) {
const subtitlesContainer = document.querySelector('.videoSubtitles');
if (!subtitlesContainer) return;
const secondarySubtitlesElement = document.createElement('div');
secondarySubtitlesElement.classList.add('videoSecondarySubtitlesInner');
// determine the order of the subtitles
if (subtitleVerticalPosition < 0) {
subtitlesContainer.insertBefore(secondarySubtitlesElement, subtitlesContainer.firstChild);
} else {
subtitlesContainer.appendChild(secondarySubtitlesElement);
}
this.#videoSecondarySubtitlesElem = secondarySubtitlesElement;
this.setSubtitleAppearance(subtitlesContainer, this.#videoSecondarySubtitlesElem);
this.#currentSecondaryTrackEvents = subtitleData.TrackEvents;
}
});
}
@ -1211,7 +1433,7 @@ function tryRemoveElement(elem) {
/**
* @private
*/
renderTracksEvents(videoElement, track, item) {
renderTracksEvents(videoElement, track, item, targetTextTrackIndex = PRIMARY_TEXT_TRACK_INDEX) {
if (!itemHelper.isLocalItem(item) || track.IsExternal) {
const format = (track.Codec || '').toLowerCase();
if (format === 'ssa' || format === 'ass') {
@ -1220,15 +1442,15 @@ function tryRemoveElement(elem) {
}
if (this.requiresCustomSubtitlesElement()) {
this.renderSubtitlesWithCustomElement(videoElement, track, item);
this.renderSubtitlesWithCustomElement(videoElement, track, item, targetTextTrackIndex);
return;
}
}
let trackElement = null;
if (videoElement.textTracks && videoElement.textTracks.length > 0) {
trackElement = videoElement.textTracks[0];
const updatingTrack = videoElement.textTracks && videoElement.textTracks.length > (this.isSecondaryTrack(targetTextTrackIndex) ? 1 : 0);
if (updatingTrack) {
trackElement = videoElement.textTracks[targetTextTrackIndex];
// This throws an error in IE, but is fine in chrome
// In IE it's not necessary anyway because changing the src seems to be enough
try {
@ -1288,24 +1510,29 @@ function tryRemoveElement(elem) {
return;
}
const trackEvents = this.#currentTrackEvents;
const subtitleTextElement = this.#videoSubtitlesElem;
const allTrackEvents = [this.#currentTrackEvents, this.#currentSecondaryTrackEvents];
const subtitleTextElements = [this.#videoSubtitlesElem, this.#videoSecondarySubtitlesElem];
if (trackEvents && subtitleTextElement) {
const ticks = timeMs * 10000;
let selectedTrackEvent;
for (const trackEvent of trackEvents) {
if (trackEvent.StartPositionTicks <= ticks && trackEvent.EndPositionTicks >= ticks) {
selectedTrackEvent = trackEvent;
break;
for (let i = 0; i < allTrackEvents.length; i++) {
const trackEvents = allTrackEvents[i];
const subtitleTextElement = subtitleTextElements[i];
if (trackEvents && subtitleTextElement) {
const ticks = timeMs * 10000;
let selectedTrackEvent;
for (const trackEvent of trackEvents) {
if (trackEvent.StartPositionTicks <= ticks && trackEvent.EndPositionTicks >= ticks) {
selectedTrackEvent = trackEvent;
break;
}
}
}
if (selectedTrackEvent && selectedTrackEvent.Text) {
subtitleTextElement.innerHTML = normalizeTrackEventText(selectedTrackEvent.Text, true);
subtitleTextElement.classList.remove('hide');
} else {
subtitleTextElement.classList.add('hide');
if (selectedTrackEvent && selectedTrackEvent.Text) {
subtitleTextElement.innerHTML = normalizeTrackEventText(selectedTrackEvent.Text, true);
subtitleTextElement.classList.remove('hide');
} else {
subtitleTextElement.classList.add('hide');
}
}
}
}
@ -1313,7 +1540,7 @@ function tryRemoveElement(elem) {
/**
* @private
*/
setCurrentTrackElement(streamIndex) {
setCurrentTrackElement(streamIndex, targetTextTrackIndex) {
console.debug(`setting new text track index to: ${streamIndex}`);
const mediaStreamTextTracks = getMediaStreamTextTracks(this._currentPlayOptions.mediaSource);
@ -1322,7 +1549,7 @@ function tryRemoveElement(elem) {
return t.Index === streamIndex;
})[0];
this.setTrackForDisplay(this.#mediaElement, track);
this.setTrackForDisplay(this.#mediaElement, track, targetTextTrackIndex);
if (enableNativeTrackSupport(this.#currentSrc, track)) {
if (streamIndex !== -1) {
this.setCueAppearance();
@ -1500,6 +1727,7 @@ function tryRemoveElement(elem) {
list.push('SetBrightness');
list.push('SetAspectRatio');
list.push('SecondarySubtitles');
return list;
}

View File

@ -65,13 +65,22 @@ video[controls]::-webkit-media-controls {
padding-left: env(safe-area-inset-left);
padding-right: env(safe-area-inset-right);
padding-bottom: env(safe-area-inset-bottom);
display: flex;
flex-direction: column;
align-items: center;
}
.videoSubtitlesInner {
max-width: 70%;
background-color: rgba(0, 0, 0, 0.8);
margin: auto;
display: inline-block;
}
.videoSecondarySubtitlesInner {
max-width: 70%;
background-color: rgba(0, 0, 0, 0.8);
min-height: 0 !important;
margin-top: 0.5em !important;
margin-bottom: 0.5em !important;
}
@keyframes htmlvideoplayer-zoomin {

View File

@ -4,7 +4,7 @@ import { Navigate, Route, Routes } from 'react-router-dom';
import { ASYNC_ADMIN_ROUTES, ASYNC_USER_ROUTES, toAsyncPageRoute } from './asyncRoutes';
import ConnectionRequired from '../components/ConnectionRequired';
import ServerContentPage from '../components/ServerContentPage';
import { LEGACY_ADMIN_ROUTES, LEGACY_USER_ROUTES, toViewManagerPageRoute } from './legacyRoutes';
import { LEGACY_ADMIN_ROUTES, LEGACY_PUBLIC_ROUTES, LEGACY_USER_ROUTES, toViewManagerPageRoute } from './legacyRoutes';
const AppRoutes = () => (
<Routes>
@ -28,6 +28,8 @@ const AppRoutes = () => (
{/* Public routes */}
<Route path='/' element={<ConnectionRequired isUserRequired={false} />}>
<Route index element={<Navigate replace to='/home.html' />} />
{LEGACY_PUBLIC_ROUTES.map(toViewManagerPageRoute)}
</Route>
{/* Suppress warnings for unhandled routes */}

View File

@ -21,4 +21,5 @@ export function toViewManagerPageRoute(route: LegacyRoute) {
}
export * from './admin';
export * from './public';
export * from './user';

View File

@ -0,0 +1,81 @@
import { LegacyRoute } from '.';
export const LEGACY_PUBLIC_ROUTES: LegacyRoute[] = [
{
path: 'addserver.html',
pageProps: {
controller: 'session/addServer/index',
view: 'session/addServer/index.html'
}
},
{
path: 'selectserver.html',
pageProps: {
controller: 'session/selectServer/index',
view: 'session/selectServer/index.html'
}
},
{
path: 'login.html',
pageProps: {
controller: 'session/login/index',
view: 'session/login/index.html'
}
},
{
path: 'forgotpassword.html',
pageProps: {
controller: 'session/forgotPassword/index',
view: 'session/forgotPassword/index.html'
}
},
{
path: 'forgotpasswordpin.html',
pageProps: {
controller: 'session/resetPassword/index',
view: 'session/resetPassword/index.html'
}
},
{
path: 'wizardremoteaccess.html',
pageProps: {
controller: 'wizard/remote/index',
view: 'wizard/remote/index.html'
}
},
{
path: 'wizardfinish.html',
pageProps: {
controller: 'wizard/finish/index',
view: 'wizard/finish/index.html'
}
},
{
path: 'wizardlibrary.html',
pageProps: {
controller: 'dashboard/library',
view: 'wizard/library.html'
}
},
{
path: 'wizardsettings.html',
pageProps: {
controller: 'wizard/settings/index',
view: 'wizard/settings/index.html'
}
},
{
path: 'wizardstart.html',
pageProps: {
controller: 'wizard/start/index',
view: 'wizard/start/index.html'
}
},
{
path: 'wizarduser.html',
pageProps: {
controller: 'wizard/user/index',
view: 'wizard/user/index.html'
}
}
];

View File

@ -11,7 +11,7 @@ import '../../elements/emby-button/emby-button';
import '../../elements/emby-button/paper-icon-button-light';
import '../../components/cardbuilder/card.scss';
import '../../components/indicators/indicators.scss';
import '../../assets/css/flexstyles.scss';
import '../../styles/flexstyles.scss';
import Page from '../../components/Page';
type MenuEntry = {

View File

@ -303,7 +303,7 @@ import { getParameterByName } from '../utils/url.ts';
updateEditorNode(this, item);
}).on('pagebeforeshow', '.metadataEditorPage', function () {
/* eslint-disable-next-line @babel/no-unused-expressions */
import('../assets/css/metadataeditor.scss');
import('../styles/metadataeditor.scss');
}).on('pagebeforeshow', '.metadataEditorPage', function () {
const page = this;
Dashboard.getCurrentUser().then(function (user) {

View File

@ -50,6 +50,11 @@ const NavigationKeys = ['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown'];
*/
const InteractiveElements = ['INPUT', 'TEXTAREA'];
/**
* Types of INPUT element for which navigation shouldn't be constrained.
*/
const NonInteractiveInputElements = ['button', 'checkbox', 'color', 'file', 'hidden', 'image', 'radio', 'reset', 'submit'];
let hasFieldKey = false;
try {
hasFieldKey = 'key' in new KeyboardEvent('keydown');
@ -84,6 +89,24 @@ export function isNavigationKey(key) {
return NavigationKeys.indexOf(key) != -1;
}
/**
* Returns _true_ if the element is interactive.
*
* @param {Element} element - Element.
* @return {boolean} _true_ if the element is interactive.
*/
export function isInteractiveElement(element) {
if (element && InteractiveElements.includes(element.tagName)) {
if (element.tagName === 'INPUT') {
return !NonInteractiveInputElements.includes(element.type);
}
return true;
}
return false;
}
export function enable() {
window.addEventListener('keydown', function (e) {
const key = getKeyName(e);
@ -97,7 +120,7 @@ export function enable() {
switch (key) {
case 'ArrowLeft':
if (!InteractiveElements.includes(document.activeElement?.tagName)) {
if (!isInteractiveElement(document.activeElement)) {
inputManager.handleCommand('left');
} else {
capture = false;
@ -107,7 +130,7 @@ export function enable() {
inputManager.handleCommand('up');
break;
case 'ArrowRight':
if (!InteractiveElements.includes(document.activeElement?.tagName)) {
if (!isInteractiveElement(document.activeElement)) {
inputManager.handleCommand('right');
} else {
capture = false;

View File

@ -22,8 +22,8 @@ import { getParameterByName } from '../utils/url.ts';
import '../elements/emby-button/paper-icon-button-light';
import 'material-design-icons-iconfont';
import '../assets/css/scrollstyles.scss';
import '../assets/css/flexstyles.scss';
import '../styles/scrollstyles.scss';
import '../styles/flexstyles.scss';
/* eslint-disable indent */

View File

@ -1,123 +0,0 @@
import '../elements/emby-button/emby-button';
import '../elements/emby-input/emby-input';
import '../scripts/livetvcomponents';
import '../elements/emby-button/paper-icon-button-light';
import '../elements/emby-itemscontainer/emby-itemscontainer';
import '../elements/emby-collapse/emby-collapse';
import '../elements/emby-select/emby-select';
import '../elements/emby-checkbox/emby-checkbox';
import '../elements/emby-slider/emby-slider';
import '../assets/css/livetv.scss';
import '../components/listview/listview.scss';
import '../assets/css/dashboard.scss';
import '../assets/css/detailtable.scss';
import { appRouter } from '../components/appRouter';
/* eslint-disable indent */
console.groupCollapsed('defining core routes');
function defineRoute(newRoute) {
const path = newRoute.alias ? newRoute.alias : newRoute.path;
console.debug('defining route: ' + path);
newRoute.dictionary = 'core';
appRouter.addRoute(path, newRoute);
}
defineRoute({
alias: '/addserver.html',
path: 'session/addServer/index.html',
autoFocus: false,
anonymous: true,
startup: true,
controller: 'session/addServer/index'
});
defineRoute({
alias: '/selectserver.html',
path: 'session/selectServer/index.html',
autoFocus: false,
anonymous: true,
startup: true,
controller: 'session/selectServer/index',
type: 'selectserver'
});
defineRoute({
alias: '/login.html',
path: 'session/login/index.html',
autoFocus: false,
anonymous: true,
startup: true,
controller: 'session/login/index',
type: 'login'
});
defineRoute({
alias: '/forgotpassword.html',
path: 'session/forgotPassword/index.html',
anonymous: true,
startup: true,
controller: 'session/forgotPassword/index'
});
defineRoute({
alias: '/forgotpasswordpin.html',
path: 'session/resetPassword/index.html',
autoFocus: false,
anonymous: true,
startup: true,
controller: 'session/resetPassword/index'
});
defineRoute({
alias: '/wizardremoteaccess.html',
path: 'wizard/remote/index.html',
autoFocus: false,
anonymous: true,
controller: 'wizard/remote/index'
});
defineRoute({
alias: '/wizardfinish.html',
path: 'wizard/finish/index.html',
autoFocus: false,
anonymous: true,
controller: 'wizard/finish/index'
});
defineRoute({
alias: '/wizardlibrary.html',
path: 'wizard/library.html',
autoFocus: false,
anonymous: true,
controller: 'dashboard/library'
});
defineRoute({
alias: '/wizardsettings.html',
path: 'wizard/settings/index.html',
autoFocus: false,
anonymous: true,
controller: 'wizard/settings/index'
});
defineRoute({
alias: '/wizardstart.html',
path: 'wizard/start/index.html',
autoFocus: false,
anonymous: true,
controller: 'wizard/start/index'
});
defineRoute({
alias: '/wizarduser.html',
path: 'wizard/user/index.html',
controller: 'wizard/user/index',
autoFocus: false,
anonymous: true
});
console.groupEnd('defining core routes');
/* eslint-enable indent */

View File

@ -1,6 +1,6 @@
import focusManager from '../components/focusManager';
import dom from './dom';
import '../assets/css/scrollstyles.scss';
import '../styles/scrollstyles.scss';
function getBoundingClientRect(elem) {
// Support: BlackBerry 5, iOS 3 (original iPhone)

View File

@ -54,7 +54,7 @@
"BehindTheScenes": "За кулісамі",
"EnableEnhancedNvdecDecoderHelp": "Эксперыментальная рэалізацыя NVDEC, не ўключайце гэту опцыю, калі вы не сутыкнуліся з памылкамі дэкадавання.",
"LabelYear": "Год:",
"LatestFromLibrary": "Апошнія {0}",
"LatestFromLibrary": "Нядаўна дададзеныя ў {0}",
"Lyricist": "Аўтар тэкстаў",
"ManageRecording": "Кіраванне запісам",
"Logo": "Лагатып",
@ -612,7 +612,7 @@
"HeaderIdentificationCriteriaHelp": "Увядзіце хаця б адзін крытэрый ідэнтыфікацыі.",
"HeaderIdentifyItemHelp": "Увядзіце адзін або некалькі крытэрыяў пошуку. Выдаліце крытэрыі, каб павялічыць вынікі пошуку.",
"HeaderKodiMetadataHelp": "Каб уключыць або выключыць метададзеныя NFO, адрэдагуйце бібліятэку і знайдзіце раздзел «Захоўвальнікі метададзеных».",
"HeaderLatestEpisodes": "Новыя серыі",
"HeaderLatestEpisodes": "Нядаўна дададзеныя эпізоды",
"HeaderLiveTvTunerSetup": "Налада ТБ-цюнэра ў прамым эфіры",
"HeaderLoginFailure": "Памылка ўваходу",
"HeaderMedia": "Медыя",
@ -887,7 +887,7 @@
"EnablePlugin": "Уключыць",
"DisableCustomCss": "Адключыць карыстальніцкі код CSS, прадастаўлены серверам",
"DisablePlugin": "Адключыць",
"DisplayInOtherHomeScreenSections": "Паказаць ў раздзелах галоўнага экрана такія секцыі як \"Апошнія медыя\" і \"Працягнуць прагляд\"",
"DisplayInOtherHomeScreenSections": "Паказаць ў раздзелах галоўнага экрана такія секцыі як \"Нядаўна дададзеныя мультымедыя\" і \"Працягнуць прагляд\"",
"DisplayMissingEpisodesWithinSeasons": "Паказаць адсутныя серыі ў сезону",
"DrmChannelsNotImported": "Каналы з DRM не будуць імпартаваны.",
"DropShadow": "Цень",
@ -1303,7 +1303,7 @@
"ShowAdvancedSettings": "Паказаць дадатковыя налады",
"Suggestions": "Прапановы",
"TabDashboard": "Панэль кіравання",
"TabLatest": "Апошні",
"TabLatest": "Нядаўна дададзены",
"TabLogs": "Журналы",
"TabMusic": "Музыка",
"TabParentalControl": "Бацькоўскі кантроль",
@ -1435,7 +1435,7 @@
"Studios": "Студыі",
"Subtitle": "Падзагаловак",
"SubtitleVerticalPositionHelp": "Нумар радка, дзе з'яўляецца тэкст. Дадатныя лічбы паказваюць зверху ўніз. Адмоўныя лічбы паказваюць знізу ўверх.",
"HideWatchedContentFromLatestMedia": "Схаваць прагледжанае змесціва з \"Апошніх медыя\"",
"HideWatchedContentFromLatestMedia": "Схаваць прагледжанае змесціва з \"Нядаўна дададзеных медыя\"",
"MessageRenameMediaFolder": "Перайменаванне медыятэкі прывядзе да страты ўсіх метададзеных, будзьце асцярожныя.",
"LabelMaxDaysForNextUpHelp": "Усталюйце максімальную колькасць дзён, на працягу якіх шоу павінна заставацца ў спісе \"Далей\", без яго прагляду.",
"MessageTheFollowingLocationWillBeRemovedFromLibrary": "Наступныя медыя-месцы будуць выдалены з вашай бібліятэкі:",
@ -1492,10 +1492,10 @@
"HeaderInstall": "Усталяваць",
"HeaderInstantMix": "Імгненны мікс",
"HeaderKeepSeries": "Захоўвацт серыял",
"HeaderLatestMedia": "Новыя медыя",
"HeaderLatestMovies": "Апошнія фільмы",
"HeaderLatestMusic": "Новая музыка",
"HeaderLatestRecordings": "Апошнія запісы",
"HeaderLatestMedia": "Нядаўна дададзеныя медыя",
"HeaderLatestMovies": "Нядаўна дададзеныя фільмы",
"HeaderLatestMusic": "Нядаўна дададзеная музыка",
"HeaderLatestRecordings": "Нядаўна дададзеныя запісы",
"HeaderLibraries": "Медыятэкі",
"HeaderLibraryFolders": "Папкі медыятэкі",
"HeaderLibraryOrder": "Парадак медыятэк",
@ -1679,5 +1679,26 @@
"SaveRecordingNFO": "Захаваць метададзеныя запісу EPG у NFO",
"SaveRecordingNFOHelp": "Захоўвайце метаданыя ад пастаўшчыка спісаў EPG разам з медыяфайламі.",
"SaveRecordingImages": "Захаванне запісу EPG выяў",
"SaveRecordingImagesHelp": "Захоўвайце выявы з спісаў EPG разам з мультымедыя."
"SaveRecordingImagesHelp": "Захоўвайце выявы з спісаў EPG разам з мультымедыя.",
"PreferEmbeddedExtrasTitlesOverFileNames": "Аддавайце перавагу ўбудаваным загалоўкам, а не імёнам файлаў для extras",
"PreferEmbeddedExtrasTitlesOverFileNamesHelp": "Extras часта маюць такое ж убудаванае імя, што і бацькоўскі, пазначце гэта, каб у любым выпадку выкарыстоўваць для іх убудаваныя загалоўкі.",
"HeaderDummyChapter": "Выявы раздзела",
"LabelDummyChapterDuration": "Інтэрвал:",
"LabelDummyChapterDurationHelp": "Інтэрвал вымання выявы главы ў секундах.",
"LabelDummyChapterCount": "Ліміт:",
"LabelDummyChapterCountHelp": "Максімальная колькасць выяваў раздзелаў, якія будуць выняты для кожнага медыяфайла.",
"LabelChapterImageResolution": "Дазвол:",
"LabelChapterImageResolutionHelp": "Дазвол вынятых малюнкаў раздзелаў.",
"ResolutionMatchSource": "Супадзенне з крыніцай",
"SecondarySubtitles": "Дадатковыя субтытры",
"SubtitleBlack": "Чорны",
"SubtitleBlue": "Сіні",
"SubtitleCyan": "Блакітны",
"SubtitleGray": "Шэры",
"SubtitleGreen": "Зялёны",
"SubtitleLightGray": "Светла-шэры",
"SubtitleMagenta": "Пурпурны",
"SubtitleRed": "Чырвоны",
"SubtitleWhite": "Белы",
"SubtitleYellow": "Жоўты"
}

View File

@ -1703,5 +1703,16 @@
"LabelChapterImageResolutionHelp": "Rozližení extrahovaných obrázků kapitol.",
"ResolutionMatchSource": "Stejné jako zdroj",
"PreferEmbeddedExtrasTitlesOverFileNames": "Preferovat vložené názvy před názvy souborů pro doplňky",
"PreferEmbeddedExtrasTitlesOverFileNamesHelp": "Doplňky většinou mají stejný vložený název jako nadřazená položka. Zaškrtnutím je i přesto můžete upřednostnit."
"PreferEmbeddedExtrasTitlesOverFileNamesHelp": "Doplňky většinou mají stejný vložený název jako nadřazená položka. Zaškrtnutím je i přesto můžete upřednostnit.",
"SecondarySubtitles": "Sekundární titulky",
"SubtitleBlack": "Černá",
"SubtitleBlue": "Modrá",
"SubtitleCyan": "Tyrkysová",
"SubtitleGray": "Šedá",
"SubtitleGreen": "Zelená",
"SubtitleLightGray": "Světle šedá",
"SubtitleMagenta": "Fialová",
"SubtitleRed": "Červená",
"SubtitleWhite": "Bílá",
"SubtitleYellow": "Žlutá"
}

View File

@ -121,7 +121,7 @@
"DeleteMedia": "Medien löschen",
"DeleteUser": "Benutzer löschen",
"DeleteUserConfirmation": "Bist du dir sicher, dass du diesen Benutzer löschen willst?",
"Depressed": "gedrückt",
"Depressed": "Gedrückt",
"Descending": "Absteigend",
"DetectingDevices": "Suche Geräte",
"DeviceAccessHelp": "Dies wird nur auf Geräte angewendet, die eindeutig identifiziert werden können, und verhindert nicht den Web-Zugriff. Gefilterter Zugriff auf Geräte verhindert die Nutzung neuer Geräte solange, bis der Zugriff für diese freigegeben wird.",
@ -279,11 +279,11 @@
"HeaderKeepRecording": "Aufnahme behalten",
"HeaderKeepSeries": "Serie behalten",
"HeaderKodiMetadataHelp": "Um NFO-Metadaten zu aktivieren oder zu deaktivieren, bearbeite eine Bibliothek und finde den Abschnitt zum Speichern von Metadaten.",
"HeaderLatestEpisodes": "Neueste Episoden",
"HeaderLatestMedia": "Neueste Medien",
"HeaderLatestMovies": "Neueste Filme",
"HeaderLatestMusic": "Neueste Musik",
"HeaderLatestRecordings": "Neueste Aufnahmen",
"HeaderLatestEpisodes": "Kürzlich hinzugefügte Episoden",
"HeaderLatestMedia": "Kürzlich hinzugefügte Medien",
"HeaderLatestMovies": "Kürzlich hinzugefügte Filme",
"HeaderLatestMusic": "Kürzlich hinzugefügte Musik",
"HeaderLatestRecordings": "Kürzlich hinzugefügte Aufnahmen",
"HeaderLibraries": "Bibliotheken",
"HeaderLibraryAccess": "Bibliothekszugriff",
"HeaderLibraryFolders": "Bibliotheksverzeichnisse",
@ -301,7 +301,7 @@
"HeaderMyMediaSmall": "Meine Medien (Klein)",
"HeaderNewApiKey": "Neuer API-Schlüssel",
"HeaderNewDevices": "Neue Geräte",
"HeaderNextEpisodePlayingInValue": "Nächste Episode wird abgespielt in {0}",
"HeaderNextEpisodePlayingInValue": "Nächste Episode in {0}",
"HeaderNextVideoPlayingInValue": "Nächstes Video wird abgespielt in {0}",
"HeaderOnNow": "Gerade läuft",
"HeaderOtherItems": "Andere Inhalte",
@ -696,7 +696,7 @@
"LabelffmpegPathHelp": "Verzeichnis zur FFmpeg-Applikationsdatei oder zum Ordner, der FFmpeg enthält.",
"LanNetworksHelp": "Komma separierte Liste von IP-Adressen oder IP/Netzmasken die als lokale Netzwerke behandelt werden sollen, um Bandbreitenlimitationen auszusetzen. Wenn gesetzt, werden alle anderen IP-Adressen als extern behandelt und unterliegen den Bandbreitenlimitationen für externe Verbindungen. Wenn leer, wird nur das Subnetz des Servers als lokales Netzwerk behandelt.",
"Large": "Groß",
"LatestFromLibrary": "Neueste {0}",
"LatestFromLibrary": "Kürzlich hinzugefügt in {0}",
"LearnHowYouCanContribute": "Erfahre, wie du unterstützen kannst.",
"LibraryAccessHelp": "Wähle die Bibliotheken aus, die du mit diesem Benutzer teilen möchtest. Administratoren können den Metadaten-Manager verwenden um alle Ordner zu bearbeiten.",
"List": "Liste",
@ -1023,7 +1023,7 @@
"TabContainers": "Container",
"TabDashboard": "Übersicht",
"TabDirectPlay": "Direktwiedergabe",
"TabLatest": "Neueste",
"TabLatest": "Kürzlich hinzugefügt",
"TabMusic": "Musik",
"TabMyPlugins": "Meine Plugins",
"TabNetworks": "Fernsehsender",
@ -1688,5 +1688,31 @@
"DownloadAll": "Alle Herunterladen",
"LabelStereoDownmixAlgorithm": "Stereo Downmix Algorithmus",
"StereoDownmixAlgorithmHelp": "Algorithmus um Mehrkanal-Audio zu Stereo-Audio umzuwandeln.",
"Experimental": "Experimentell"
"Experimental": "Experimentell",
"SaveRecordingNFO": "Speichern der EPG-Metadaten in NFO",
"SaveRecordingNFOHelp": "Speichern Sie Metadaten von EPG-Anbietern zusammen mit den Medien.",
"ResolutionMatchSource": "Quelle der Übereinstimmung",
"PreferEmbeddedExtrasTitlesOverFileNames": "Eingebettete Titel gegenüber Dateinamen für Extras bevorzugen",
"PreferEmbeddedExtrasTitlesOverFileNamesHelp": "Extras haben oft denselben eingebetteten Namen wie die übergeordnete Datei. Aktivieren Sie diese Option, um trotzdem eingebettete Titel für sie zu verwenden.",
"SaveRecordingImages": "Speichern der EPG-Bilder der Aufnahme",
"SaveRecordingImagesHelp": "Speichern Sie Bilder von EPG-Anbietern zusammen mit den Medien.",
"SecondarySubtitles": "Sekundäre Untertitel",
"HeaderDummyChapter": "Kapitel Bilder",
"HeaderRecordingMetadataSaving": "Aufzeichnung von Metadaten",
"LabelDummyChapterDuration": "Intervall:",
"LabelDummyChapterDurationHelp": "Das Intervall für die Extraktion des Kapitelbildes in Sekunden.",
"LabelDummyChapterCount": "Limit:",
"LabelDummyChapterCountHelp": "Die maximale Anzahl von Kapitelbildern, die für jede Mediendatei extrahiert werden.",
"LabelChapterImageResolution": "Auflösung:",
"LabelChapterImageResolutionHelp": "Die Auflösung der extrahierten Kapitelbilder.",
"SubtitleBlack": "Schwarz",
"SubtitleBlue": "Blau",
"SubtitleCyan": "Cyan",
"SubtitleGray": "Grau",
"SubtitleGreen": "Grün",
"SubtitleLightGray": "Hellgrau",
"SubtitleMagenta": "Magenta",
"SubtitleRed": "Rot",
"SubtitleWhite": "Weiß",
"SubtitleYellow": "Gelb"
}

View File

@ -1701,5 +1701,18 @@
"LabelChapterImageResolution": "Resolution:",
"LabelChapterImageResolutionHelp": "The resolution of the extracted chapter images.",
"ResolutionMatchSource": "Match Source",
"SaveRecordingNFO": "Save recording EPG metadata in NFO"
"SaveRecordingNFO": "Save recording EPG metadata in NFO",
"PreferEmbeddedExtrasTitlesOverFileNames": "Prefer embedded titles over filenames for extras",
"PreferEmbeddedExtrasTitlesOverFileNamesHelp": "Extras often have the same embedded name as the parent, check this to use embedded titles for them anyway.",
"SecondarySubtitles": "Secondary Subtitles",
"SubtitleBlack": "Black",
"SubtitleBlue": "Blue",
"SubtitleCyan": "Cyan",
"SubtitleGray": "Grey",
"SubtitleGreen": "Green",
"SubtitleLightGray": "Light Grey",
"SubtitleMagenta": "Magenta",
"SubtitleRed": "Red",
"SubtitleWhite": "White",
"SubtitleYellow": "Yellow"
}

View File

@ -1412,6 +1412,7 @@
"SearchForSubtitles": "Search for Subtitles",
"SearchResults": "Search Results",
"Season": "Season",
"SecondarySubtitles": "Secondary Subtitles",
"SelectAdminUsername": "Please select a username for the admin account.",
"SelectServer": "Select Server",
"SendMessage": "Send message",
@ -1461,10 +1462,20 @@
"Subtitle": "Subtitle",
"SubtitleAppearanceSettingsAlsoPassedToCastDevices": "These settings also apply to any Google Cast playback started by this device.",
"SubtitleAppearanceSettingsDisclaimer": "Following settings do not apply to the graphical subtitles mentioned above or ASS/SSA subtitles that embed their own styles.",
"SubtitleBlack": "Black",
"SubtitleBlue": "Blue",
"SubtitleCyan": "Cyan",
"SubtitleDownloadersHelp": "Enable and rank your preferred subtitle downloaders in order of priority.",
"SubtitleGray": "Gray",
"SubtitleGreen": "Green",
"SubtitleLightGray": "Light Gray",
"SubtitleMagenta": "Magenta",
"SubtitleOffset": "Subtitle Offset",
"SubtitleRed": "Red",
"Subtitles": "Subtitles",
"SubtitleVerticalPositionHelp": "Line number where text appears. Positive numbers indicate top down. Negative numbers indicate bottom up.",
"SubtitleWhite": "White",
"SubtitleYellow": "Yellow",
"Suggestions": "Suggestions",
"Sunday": "Sunday",
"Sync": "Sync",

View File

@ -154,7 +154,7 @@
"DateAdded": "Fecha agregada",
"DatePlayed": "Fecha de reproducción",
"DeathDateValue": "Muerte: {0}",
"Default": "Por Defecto",
"Default": "Predeterminado",
"ErrorDefault": "Hubo un error procesando la solicitud. Por favor intentalo nuevamente mas tarde.",
"DefaultMetadataLangaugeDescription": "Estos son tus predeterminados y pueden ser personalizados por librería únicamente.",
"Delete": "Borrar",
@ -1235,7 +1235,7 @@
"TitleHostingSettings": "Configuraciones de alojamiento",
"TitleHardwareAcceleration": "Aceleración por hardware",
"Thursday": "Jueves",
"Thumb": "Pulgar",
"Thumb": "Miniatura",
"TheseSettingsAffectSubtitlesOnThisDevice": "Esta configuración afecta los subtítulos en este dispositivo",
"ThemeVideos": "Videos temáticos",
"ThemeSongs": "Canciones temáticas",
@ -1353,7 +1353,7 @@
"NextTrack": "Pasar al siguiente",
"LabelUnstable": "Inestable",
"Video": "Video",
"ThumbCard": "Tarjeta de pulgar",
"ThumbCard": "Tarjeta de miniatura",
"Subtitle": "Subtítulo",
"SpecialFeatures": "Características especiales",
"SelectServer": "Seleccionar servidor",
@ -1517,7 +1517,7 @@
"MessageSent": "Mensaje enviado.",
"LabelSlowResponseTime": "Tiempo en ms después de lo cual una respuesta es considerada lenta:",
"LabelSlowResponseEnabled": "Log de alarma si la respuesta del servidor fue lenta",
"UseEpisodeImagesInNextUpHelp": "Las secciones Siguiente y Continuar viendo utilizaran imagenes del episodio como miniaturas en lugar de miniaturas del show.",
"UseEpisodeImagesInNextUpHelp": "Las secciones 'Siguiente' y 'Continuar viendo' utilizarán imágenes del episodio como miniaturas en lugar de miniaturas del show.",
"UseEpisodeImagesInNextUp": "Usar imágenes de los episodios en \"Siguiente\" y \"Continuar Viendo\"",
"LabelAutomaticallyAddToCollection": "Agregar automáticamente a la colección",
"HeaderSyncPlayTimeSyncSettings": "Sincronización de tiempo",
@ -1687,5 +1687,13 @@
"DownloadAll": "Descargar todo",
"Experimental": "Experimental",
"LabelStereoDownmixAlgorithm": "Algoritmo de mezcla estéreo",
"StereoDownmixAlgorithmHelp": "Algoritmo utilizado para mezclar audio multicanal a estéreo."
"StereoDownmixAlgorithmHelp": "Algoritmo utilizado para mezclar audio multicanal a estéreo.",
"LabelDummyChapterDurationHelp": "El intervalo de extracción de la imagen del capítulo en segundos.",
"HeaderRecordingMetadataSaving": "Grabando metadatos",
"HeaderDummyChapter": "Imágenes del capítulo",
"LabelDummyChapterDuration": "Intervalo:",
"LabelDummyChapterCount": "Límite:",
"LabelDummyChapterCountHelp": "El número máximo de imágenes de capítulos que se extraerán para cada archivo multimedia.",
"LabelChapterImageResolution": "Resolución:",
"LabelChapterImageResolutionHelp": "La resolución de las imágenes de los capítulos extraídos."
}

View File

@ -248,11 +248,11 @@
"HeaderKeepRecording": "Mantener grabación",
"HeaderKeepSeries": "Mantener series",
"HeaderKodiMetadataHelp": "Para habilitar o deshabilitar los metadatos NFO, edite una biblioteca y busque la sección 'Guardadores de metadatos'.",
"HeaderLatestEpisodes": "Últimos episodios",
"HeaderLatestMedia": "Últimos",
"HeaderLatestMovies": "Últimas películas",
"HeaderLatestMusic": "Última música",
"HeaderLatestRecordings": "Últimas grabaciones",
"HeaderLatestEpisodes": "Últimos episodios añadidos",
"HeaderLatestMedia": "Últimos elementos añadidos",
"HeaderLatestMovies": "Últimas películas añadidas",
"HeaderLatestMusic": "Última música añadida",
"HeaderLatestRecordings": "Últimas grabaciones añadidas",
"HeaderLibraries": "Bibliotecas",
"HeaderLibraryAccess": "Acceso a la biblioteca",
"HeaderLibraryFolders": "Carpetas de la biblioteca",
@ -344,7 +344,7 @@
"HeaderYears": "Años",
"Help": "Ayuda",
"Hide": "Ocultar",
"HideWatchedContentFromLatestMedia": "Esconder contenido visto de \"Últimos\"",
"HideWatchedContentFromLatestMedia": "Esconder contenido visto de \"Últimos elementos\"",
"HttpsRequiresCert": "Para activar la conexión segura, necesitas un certificado SSL de confianza, como Let's Encrypt. De lo contrario, desactive las conexiones seguras.",
"Identify": "Identificar",
"Images": "Imágenes",
@ -1078,7 +1078,7 @@
"Directors": "Directores",
"Display": "Visualización",
"DisplayInMyMedia": "Mostrar en la pantalla de inicio",
"DisplayInOtherHomeScreenSections": "Mostrar en las secciones de la pantalla de inicio como \"Últimos\" y \"Continuar viendo\"",
"DisplayInOtherHomeScreenSections": "Mostrar en la pantalla de inicio secciones como \"Últimos elementos añadidos\" y \"Continuar viendo\"",
"DisplayMissingEpisodesWithinSeasons": "Mostrar episodios ausentes en las temporadas",
"DisplayMissingEpisodesWithinSeasonsHelp": "Esto también debe ser habilitado para la biblioteca de TV en la configuración del servidor.",
"DropShadow": "Eliminar sombra",
@ -1693,5 +1693,9 @@
"SaveRecordingNFO": "Guardar grabación de metadatos EPG en NFO",
"SaveRecordingNFOHelp": "Guardar metadatos del proveedor de listados EPG junto con los archivos multimedia.",
"SaveRecordingImages": "Guardar grabación de imágenes EPG",
"SaveRecordingImagesHelp": "Guardar imágenes del proveedor de listados EPG junto con los archivos multimedia."
"SaveRecordingImagesHelp": "Guardar imágenes del proveedor de listados EPG junto con los archivos multimedia.",
"LabelDummyChapterDuration": "Intervalo:",
"LabelDummyChapterDurationHelp": "Intervalo de extracción de imágenes de los capítulos en segundos",
"HeaderDummyChapter": "Imágenes de capítulos",
"LabelDummyChapterCount": "Límite:"
}

View File

@ -16,7 +16,7 @@
"Books": "Libros",
"Artists": "Artistas",
"Albums": "Álbumes",
"TabLatest": "Recientes",
"TabLatest": "Agregado recientemente",
"HeaderUser": "Usuario",
"AlbumArtist": "Artista del álbum",
"Album": "Álbum",
@ -309,7 +309,7 @@
"LibraryAccessHelp": "Selecciona las bibliotecas que deseas compartir con este usuario. Los administradores podrán editar todas las carpetas utilizando el gestor de metadatos.",
"LeaveBlankToNotSetAPassword": "Puedes dejar este campo en blanco para no establecer ninguna contraseña.",
"LearnHowYouCanContribute": "Aprende cómo puedes contribuir.",
"LatestFromLibrary": "Últimas - {0}",
"LatestFromLibrary": "Agregado recientemente en {0}",
"Large": "Grande",
"LanNetworksHelp": "Lista separada por comas de direcciones IP o entradas de IP/máscara de red para las redes que se considerarán en la red local al aplicar las restricciones de ancho de banda. Si se establecen, todas las demás direcciones IP se considerarán como parte de la red externa y estarán sujetas a las restricciones de ancho de banda externa. Si se deja en blanco, solo se considera a la subred del servidor estar en la red local.",
"LabelffmpegPathHelp": "La ruta hacia el archivo ejecutable FFmpeg, o la carpeta que contenga FFmpeg.",
@ -571,7 +571,7 @@
"LabelSelectVersionToInstall": "Seleccionar versión a instalar:",
"LabelSelectUsers": "Seleccionar usuarios:",
"LabelSelectFolderGroupsHelp": "Las carpetas sin marcar serán mostradas individualmente en su propia vista.",
"LabelSelectFolderGroups": "Agrupar automáticamente el contenido de las siguientes carpetas a vistas como Películas, Música y TV:",
"LabelSelectFolderGroups": "Agrupar automáticamente el contenido de las siguientes carpetas a vistas como «Películas», «Música» y «TV»:",
"LabelSeasonNumber": "Temporada número:",
"LabelScreensaver": "Protector de pantalla:",
"LabelScheduledTaskLastRan": "Última ejecución {0}, tomando {1}.",
@ -875,7 +875,7 @@
"HttpsRequiresCert": "Para habilitar las conexiones seguras, necesitarás proporcionar un certificado SSL de confianza, como el de Let's Encrypt. Por favor, proporciona un certificado o desactiva las conexiones seguras.",
"Horizontal": "Horizontal",
"Home": "Inicio",
"HideWatchedContentFromLatestMedia": "Ocultar contenido ya visto de «Últimos medios»",
"HideWatchedContentFromLatestMedia": "Ocultar contenido ya visto de «Medios agregados recientemente»",
"Hide": "Ocultar",
"Help": "Ayuda",
"HeaderYears": "Años",
@ -970,11 +970,11 @@
"HeaderLibraryFolders": "Carpetas de bibliotecas",
"HeaderLibraryAccess": "Acceso a bibliotecas",
"HeaderLibraries": "Bibliotecas",
"HeaderLatestRecordings": "Últimas grabaciones",
"HeaderLatestMusic": "Última música",
"HeaderLatestMovies": "Últimas películas",
"HeaderLatestMedia": "Últimos medios",
"HeaderLatestEpisodes": "Últimos episodios",
"HeaderLatestRecordings": "Grabaciones agregadas recientemente",
"HeaderLatestMusic": "Música agregada recientemente",
"HeaderLatestMovies": "Películas agregadas recientemente",
"HeaderLatestMedia": "Medios agregados recientemente",
"HeaderLatestEpisodes": "Episodios agregados recientemente",
"HeaderKodiMetadataHelp": "Para habilitar o deshabilitar los metadatos NFO, edita una biblioteca y ubica la sección de 'Grabadores de metadatos'.",
"HeaderKeepSeries": "Conservar serie",
"HeaderKeepRecording": "Conservar grabación",
@ -1006,7 +1006,7 @@
"LabelMaxResumePercentageHelp": "Los medios se consideran totalmente reproducidos si se detienen después de este tiempo.",
"LabelMaxResumePercentage": "Porcentaje máximo para la reanudación:",
"LabelMaxParentalRating": "Máxima clasificación parental permitida:",
"LabelMaxChromecastBitrate": "Calidad de transmisión de Chromecast:",
"LabelMaxChromecastBitrate": "Calidad de transmisión de Google Cast:",
"LabelMaxBackdropsPerItem": "Número máximo de imágenes de fondo por elemento:",
"LabelMatchType": "Tipo de coincidencia:",
"LabelManufacturerUrl": "URL del fabricante:",
@ -1022,7 +1022,7 @@
"LabelLibraryPageSize": "Tamaño de las páginas de las bibliotecas:",
"LabelLanguage": "Idioma:",
"LabelLanNetworks": "Redes LAN:",
"LabelKodiMetadataUserHelp": "Guarda los datos de visto en archivos NFO para que otras aplicaciones los utilicen.",
"LabelKodiMetadataUserHelp": "Guarda los datos de visualización en los archivos NFO para que otras aplicaciones lo usen.",
"LabelKodiMetadataUser": "Guardar los datos de visto del usuario en archivos NFO para:",
"LabelKodiMetadataSaveImagePathsHelp": "Esto se recomienda si tienes nombres de imágenes que no se ajustan a los lineamientos de Kodi.",
"LabelKodiMetadataSaveImagePaths": "Guardar las rutas de las imágenes en los archivos NFO",
@ -1166,7 +1166,7 @@
"DisplayModeHelp": "Selecciona el estilo de diseño que desea para la interfaz.",
"DisplayMissingEpisodesWithinSeasonsHelp": "Esto también debe estar habilitado para las bibliotecas de TV en la configuración del servidor.",
"DisplayMissingEpisodesWithinSeasons": "Mostrar episodios faltantes en las temporadas",
"DisplayInOtherHomeScreenSections": "Mostrar en las secciones de la pantalla de inicio como «Recientes» o «Continuar viendo»",
"DisplayInOtherHomeScreenSections": "Mostrar en las secciones de la pantalla de inicio como «Medios agregados recientemente» o «Continuar viendo»",
"DisplayInMyMedia": "Mostrar en la pantalla de inicio",
"Display": "Pantalla",
"Disconnect": "Desconectar",
@ -1354,7 +1354,7 @@
"MessagePluginInstallError": "Ocurrió un error instalando el complemento.",
"PlaybackRate": "Tasa de reproducción",
"Data": "Datos",
"ButtonUseQuickConnect": "Usar conexión rápida",
"ButtonUseQuickConnect": "Usar «Conexión rápida»",
"ButtonActivate": "Activar",
"Authorize": "Autorizar",
"LabelCurrentStatus": "Estado actual:",
@ -1366,7 +1366,7 @@
"TonemappingAlgorithmHelp": "El mapeo de tonos puede ser modificado. Si no estas familiarizado con estas opciones, solo manten el predeterminado. El valor recomendado es Hable.",
"LabelTonemappingThresholdHelp": "El algoritmo de mapeo de tonos puede ser finamente ajustado para cada escena. Y el umbral es usado para detectar si la escena ha cambiado. Si los valores entre el promedio de brillo del fotograma actual y el promedio actual excede el valor de umbral, se vuelve a calcular el brillo promedio y máximo. Los valores recomendados y por defecto son entre 0.2 y 0.8.",
"ThumbCard": "Miniatura",
"LabelMaxMuxingQueueSizeHelp": "Numero máximo de paquetes que pueden estar en búfer mientras se espera a que se inicialicen todas las trasmisiones. Intenta incrementarlos si encuentras el error \"Too many packets buffered for output stream\" en los registros de ffmpeg. El valor recomendado es 2048.",
"LabelMaxMuxingQueueSizeHelp": "Numero máximo de paquetes que pueden estar en búfer mientras se espera a que se inicialicen todas las trasmisiones. Intenta incrementarlos si encuentras el error «Too many packets buffered for output stream» en los registros de ffmpeg. El valor recomendado es 2048.",
"LabelMaxMuxingQueueSize": "Tamaño máximo cola de mezclado:",
"LabelTonemappingParamHelp": "Modifica el algoritmo de mapeo de tonos. Los valores recomendados y por defecto son NaN. Se puede dejar en blanco.",
"LabelTonemappingParam": "Parámetro Mapeo de tonos:",
@ -1380,7 +1380,7 @@
"LabelTonemappingAlgorithm": "Seleccione el algoritmo de mapeo de tonos:",
"AllowTonemappingHelp": "El mapeo de tonos puede transformar el rango dinámico de un video de HDR a SDR manteniendo la calidad de imagen y los colores, que son datos muy importantes para mostrar la imagen original. Actualmente solo funciona con videos HDR10 o HLG. Esto requiere los tiempos de ejecución OpenCL o CUDA correspondientes.",
"EnableTonemapping": "Habilitar mapeo de tonos",
"LabelOpenclDeviceHelp": "Este es el dispositivo OpenCL que se utiliza para el mapeo de tonos. El lado izquierdo del punto es el número de plataforma y el lado derecho es el número de dispositivo en la plataforma. El valor predeterminado es 0.0. Se requiere la aplicación ffmpeg que contiene el método de aceleración de hardware OpenCL.",
"LabelOpenclDeviceHelp": "Este es el dispositivo OpenCL que se utiliza para el mapeo de tonos. El lado izquierdo del punto es el número de plataforma y el lado derecho es el número de dispositivo en la plataforma. El valor predeterminado es 0.0. Se requiere la aplicación FFmpeg que contiene el método de aceleración de hardware OpenCL.",
"LabelOpenclDevice": "Dispositivo OpenCL:",
"LabelColorPrimaries": "Colores primarios:",
"LabelColorTransfer": "Transferencia de Color:",
@ -1400,22 +1400,22 @@
"SelectServer": "Seleccionar Servidor",
"Restart": "Reiniciar",
"ResetPassword": "Resetear contraseña",
"QuickConnectNotActive": "Conexión Rápida no esta habilitado en el servidor",
"QuickConnectNotAvailable": "Pregunte al administrador del servidor para habilitar Conexión Rápida",
"QuickConnectInvalidCode": "Código Conexión Rápida inválido",
"QuickConnectDescription": "Para ingresar con Conexión Rápida, seleccione el botón Conexión Rápida en el dispositivo del cual estas ingresando e ingrese el siguiente código.",
"QuickConnectDeactivated": "Conexión Rápida se desactivó antes de que se pudiera aprobar la solicitud de inicio de sesión",
"QuickConnectAuthorizeFail": "Código Conexión Rápida desconocido",
"QuickConnectAuthorizeSuccess": "Requiere autorización",
"QuickConnectNotActive": "«Conexión rápida» no está habilitado en este servidor",
"QuickConnectNotAvailable": "Pide al administrador del servidor que habilite la «Conexión rápida»",
"QuickConnectInvalidCode": "Código de «Conexión rápida» inválido",
"QuickConnectDescription": "Para ingresar con «Conexión rápida», seleccione el botón «Conexión rápida» en el dispositivo del cual estas ingresando e ingrese el código mostrado a continuación.",
"QuickConnectDeactivated": "La «Conexión rápida» se desactivó antes de que se pudiera aprobar la solicitud de inicio de sesión",
"QuickConnectAuthorizeFail": "Código de «Conexión rápida» desconocido",
"QuickConnectAuthorizeSuccess": "Solicitud autorizada",
"QuickConnectAuthorizeCode": "Ingrese el código {0} para acceder",
"QuickConnectActivationSuccessful": "Activación Exitosa",
"QuickConnect": "Conexión Rápida",
"QuickConnectActivationSuccessful": "Activado exitosamente",
"QuickConnect": "Conexión rápida",
"Profile": "Perfil",
"PosterCard": "Imagen del Cartel",
"Poster": "Cartel",
"Photo": "Foto",
"MusicVideos": "Videos musicales",
"LabelQuickConnectCode": "Código conexión rápida:",
"LabelQuickConnectCode": "Código de «Conexión rápida»:",
"LabelKnownProxies": "Proxies conocidos:",
"LabelIconMaxResHelp": "Resolución maxima de los iconos por medio de la función 'upnp:icon'.",
"EnableAutoCast": "Establecer como Predeterminado",
@ -1519,7 +1519,7 @@
"LabelSlowResponseEnabled": "Log de alarma si la respuesta del servidor fue lenta",
"UseEpisodeImagesInNextUpHelp": "Las secciones Siguiente y Continuar viendo utilizaran imagenes del episodio como miniaturas en lugar de miniaturas del show.",
"UseEpisodeImagesInNextUp": "Usar imágenes de los episodios en \"Siguiente\" y \"Continuar Viendo\"",
"LabelLocalCustomCss": "El CSS personalizado aplica solo a este cliente. Puede quieras deshabilitar el CSS del servidor.",
"LabelLocalCustomCss": "Código CSS personalizado para estilo que aplica solo a este cliente. Puede que quiera deshabilitar el código CSS personalizado del servidor.",
"LabelDisableCustomCss": "Desactivar el código CSS personalizado para la tematización/marca proporcionada desde el servidor.",
"DisableCustomCss": "Deshabilitar CSS proveniente del servidor",
"LabelAutomaticallyAddToCollectionHelp": "Cuando al menos 2 películas tengan el mismo nombre de colección, se añadirán automáticamente a dicha colección.",
@ -1564,5 +1564,16 @@
"LabelSyncPlaySettingsSyncCorrection": "Corrección de sincronización",
"LabelSyncPlaySettingsExtraTimeOffset": "Desfase de tiempo extra:",
"LabelSyncPlaySettingsMinDelaySpeedToSync": "Retraso mínimo de SpeedToSync:",
"LabelOriginalName": "Nombre original:"
"LabelOriginalName": "Nombre original:",
"Experimental": "Experimental",
"HeaderRecordingMetadataSaving": "Metadatos de grabación",
"LabelStereoDownmixAlgorithm": "Algoritmo de downmix estéreo",
"LabelDummyChapterDuration": "Intervalo:",
"LabelDummyChapterCountHelp": "El máximo número de imágenes de capítulos que serán extraídas por cada archivo de medios.",
"HeaderDummyChapter": "Imágenes de capítulos",
"LabelDummyChapterDurationHelp": "El intervalo de la extracción de las imágenes de los capítulos, en segundos.",
"LabelDummyChapterCount": "Límite:",
"LabelChapterImageResolution": "Resolución:",
"LabelChapterImageResolutionHelp": "La resolución de las imágenes de capítulos extraídas.",
"LabelMaxDaysForNextUp": "Días máximos en «A continuación»:"
}

View File

@ -129,7 +129,7 @@
"ValueCodec": "Kodeka: {0}",
"ValueAudioCodec": "Audio-kodeka: {0}",
"ValueAlbumCount": "{0} album",
"UserProfilesIntro": "Jellyfinek erabiltzaileen profilentzako euskarria barne hartzen du, eta erabiltzaile bakoitzak bere doikuntzak, ugaltze-egoera eta gurasoen kontrola izatea ahalbidetzen du.",
"UserProfilesIntro": "Jellyfinek erabiltzaileen profilentzako euskarria barne hartzen du, eta erabiltzaile bakoitzak bere ezarpenak, ugaltze-egoera eta gurasoen kontrola izatea ahalbidetzen du.",
"UserAgentHelp": "Eman 'User-Agent' pertsonalizatutako http goiburu bat.",
"UseEpisodeImagesInNextUpHelp": "\"Nobedadeak\" eta \"Ikusten jarraitu\" ataletan kapituluen irudiak agertuko dira miniatura gisa, seriearen miniatura nagusiaren ordez.",
"UseEpisodeImagesInNextUp": "Erabili kapituluen irudiak \"Nobedadeak\" eta \"Ikusten jarraitu\" ataletan",
@ -188,7 +188,7 @@
"TabParentalControl": "Gurasoen kontrola",
"TabOther": "Bestelakoak",
"TabNotifications": "Jakinarazpenak",
"TabNfoSettings": "NFO doikuntzak",
"TabNfoSettings": "NFO ezarpenak",
"TabNetworks": "Kate TB",
"TabNetworking": "Sareak",
"TabMyPlugins": "Nire osagarriak",
@ -212,7 +212,7 @@
"Subtitles": "Azpitituluak",
"SubtitleOffset": "Azpitituluak lekualdatzea",
"SubtitleDownloadersHelp": "Gaitu eta sailkatu hobetsitako azpitituluen deskargagailuak lehentasun-ordenaren arabera.",
"SubtitleAppearanceSettingsDisclaimer": "Ondorengo doikuntzak ez zaizkie aplikatuko aurretik aipatutako azpititulu grafikoei, ezta ASS/SSA azpitituluei ere, baldin eta beren estiloak badituzte.",
"SubtitleAppearanceSettingsDisclaimer": "Ondorengo ezarpenak ez zaizkie aplikatuko aurretik aipatutako azpititulu grafikoei, ezta ASS/SSA azpitituluei ere, baldin eta beren estiloak badituzte.",
"SubtitleAppearanceSettingsAlsoPassedToCastDevices": "Doikuntza horiek gailu honek hasitako Chromecast edozein erreprodukziori ere aplikatzen zaizkio.",
"Subtitle": "Azpititulua",
"Studios": "Ikasketak",
@ -246,13 +246,13 @@
"SetUsingLastTracks": "Audioko/azpitituluetako pista aurreko itemarekin ezartzea",
"SettingsWarning": "Balio horiek aldatzeak ezegonkortasuna edo konektagarritasun-akatsak eragin ditzake. Arazoren bat izanez gero, berriz ere bere balio lehenetsira aldatzea gomendatzen dizugu.",
"SettingsSaved": "Konfigurazio gordea.",
"Settings": "Doikuntzak",
"Settings": "Ezarpenak",
"ServerUpdateNeeded": "Zerbitzaria eguneratu egin behar da. Azken bertsioa deskargatzeko, bisitatu {0}",
"ServerRestartNeededAfterPluginInstall": "Jellyfin berriz hasi beharko da osagarri bat instalatu ondoren.",
"ServerNameIsShuttingDown": "{0}(e)ko zerbitzaria itzaltzen ari da.",
"ServerNameIsRestarting": "{0}(e)ko zerbitzaria berrabiarazten ari da.",
"SeriesYearToPresent": "{0} - Gaur egun",
"SeriesSettings": "Serie-doikuntzak",
"SeriesSettings": "Serie ezarpenak",
"SeriesRecordingScheduled": "Programatutako serieak grabatzea.",
"SeriesDisplayOrderHelp": "Ordenatu kapituluak jaulkipen-dataren, DVD-ordenaren edo zenbaki absolutuaren arabera.",
"SeriesCancelled": "Serie ezeztatua.",
@ -911,7 +911,7 @@
"Hide": "Ezkutatu",
"Help": "Laguntza",
"HeaderYears": "Urteak",
"HeaderXmlSettings": "XML doikuntzak",
"HeaderXmlSettings": "XML ezarpenak",
"HeaderXmlDocumentAttributes": "XML dokumentuaren atributuak",
"HeaderXmlDocumentAttribute": "XML dokumentuaren atributua",
"HeaderVideoTypes": "Bideo motak",
@ -953,7 +953,7 @@
"LibraryAccessHelp": "Aukeratu erabiltzaile honekin partekatu beharreko liburutegiak. Administratzaileek karpeta guztiak editatu ahal izango dituzte metadatuen kudeatzailea erabiliz.",
"LeaveBlankToNotSetAPassword": "Hutsik utz dezakezu pasahitza ez konfiguratzeko.",
"LearnHowYouCanContribute": "Ezagutu nola lagundu dezakezun.",
"LatestFromLibrary": "Duela gutxi {0} liburutegian",
"LatestFromLibrary": "Duela gutxi gehituta: {0}",
"LastSeen": "Azkenekoz ikusita {0}",
"Larger": "Handiagoa",
"Large": "Handia",
@ -1113,7 +1113,7 @@
"HeaderSortOrder": "Agindua",
"HeaderSortBy": "Ordenatu",
"HeaderSetupLibrary": "Konfiguratu zure multimedia-liburutegiak",
"HeaderServerSettings": "Zerbitzariaren doikuntzak",
"HeaderServerSettings": "Zerbitzariaren ezarpenak",
"HeaderServerAddressSettings": "Zerbitzariaren helbidea konfiguratzea",
"HeaderSeriesStatus": "Serieen egoera",
"HeaderSeriesOptions": "Serieen aukerak",
@ -1138,7 +1138,7 @@
"HeaderRemoteControl": "Urrutiko kontrola",
"HeaderRemoteAccessSettings": "Urruneko sarbide-aukerak",
"HeaderRecordingPostProcessing": "Prozesatu osteko grabazioa",
"HeaderRecordingOptions": "Grabazio-doikuntzak",
"HeaderRecordingOptions": "Grabazio ezarpenak",
"HeaderRecentlyPlayed": "Duela gutxi erreproduzitua",
"HeaderProfileServerSettingsHelp": "Balio horiek zerbitzaria bezeroei nola aurkeztuko zaien kontrolatzen dute.",
"HeaderProfileInformation": "Profilari buruzko informazioa",
@ -1169,12 +1169,12 @@
"HeaderMyDevice": "Nire gailua",
"HeaderMusicQuality": "Soinuaren kalitatea",
"HeaderMoreLikeThis": "Hau bezalakoa",
"HeaderMetadataSettings": "Metadatuen doikuntzak",
"HeaderMetadataSettings": "Metadatuen ezarpenak",
"HeaderMediaFolders": "Multimedia karpetak",
"HeaderMedia": "Multimedia",
"HeaderLoginFailure": "Saioaren hasierako akatsa",
"HeaderLiveTvTunerSetup": "Telebista-sintonizadorearen doikuntzak",
"HeaderLibrarySettings": "Liburutegiaren doikuntzak",
"HeaderLiveTvTunerSetup": "Telebista-sintonizadorearen ezarpenak",
"HeaderLibrarySettings": "Liburutegiaren ezarpenak",
"HeaderLibraryOrder": "Liburutegiaren agindua",
"HeaderLibraryFolders": "Liburutegiko karpetak",
"HeaderLibraryAccess": "Liburutegirako sarbidea",
@ -1184,24 +1184,24 @@
"HeaderLatestMovies": "Azken filmak",
"HeaderLatestMedia": "Berriki gehituak",
"HeaderLatestEpisodes": "Azken kapituluak",
"HeaderKodiMetadataHelp": "NFO formatuko metadatuak aktibatu edo desaktibatu ditzakezu, liburutegi baten konfigurazioa irekiz eta metadatuen ataleko doikuntzak berrikusiz.",
"HeaderKodiMetadataHelp": "NFO formatuko metadatuak aktibatu edo desaktibatu ditzakezu, liburutegi baten konfigurazioa irekiz eta metadatuen ataleko ezarpenak berrikusiz.",
"HeaderKeepSeries": "Serieak mantentzea",
"HeaderKeepRecording": "Grabazioa mantendu",
"HeaderInstantMix": "Bat-bateko nahasketa",
"HeaderInstall": "Instalatu",
"HeaderImageSettings": "Irudi-doikuntzak",
"HeaderImageSettings": "Irudi ezarpenak",
"HeaderImageOptions": "Irudi-aukerak",
"HeaderIdentifyItemHelp": "Sartu bilaketa-parametro bat edo gehiago. Bilaketaren emaitzen kopurua handitzeko parametroak ezabatzen ditu.",
"HeaderIdentificationHeader": "Identifikazio-goiburua",
"HeaderIdentificationCriteriaHelp": "Gutxienez identifikazio-irizpide bat sartzen du.",
"HeaderIdentification": "Identifikazioa",
"HeaderHttpsSettings": "https aukerak",
"HeaderHttpHeaders": "http buruak",
"HeaderHttpsSettings": "HTTPS aukerak",
"HeaderHttpHeaders": "HTTP buruak",
"HeaderGuideProviders": "Gida-hornitzaileak",
"HeaderFrequentlyPlayed": "Maiz erreproduzitua",
"HeaderForKids": "Haurrentzat",
"HeaderFetchImages": "Bilatu irudiak:",
"HeaderFetcherSettings": "Harrapatzailearen doikuntzak",
"HeaderFetcherSettings": "Harrapatzailearen ezarpenak",
"HeaderFeatureAccess": "Sartzeko baimenak:",
"HeaderExternalIds": "Kanpoko IDS:",
"HeaderError": "Errorea",
@ -1421,8 +1421,8 @@
"DeleteAll": "Ezabatu dena",
"Delete": "Ezabatu",
"DeinterlaceMethodHelp": "Hautatu bihurketan zehar elkarri lotuta dagoen edukia askatzeko aplikatuko den iragazki mota. Lotura kentzeko hardware bidezko azelerazioa aktibatuta badago, iragazki horren ordez erabiliko da.",
"DefaultSubtitlesHelp": "Erabiliko diren azpitituluak fitxategien pistetan txertatutako metadatuen araberakoak izango dira (bai \"lehenetsita\" edo \"behartuta\"). Hizkuntza-doikuntzak kontuan hartzen dira hainbat aukera eskuragarri daudenean.",
"DefaultMetadataLangaugeDescription": "Hauek dira zure doikuntzak eta liburutegi bakoitzerako pertsonalizatu daitezke.",
"DefaultSubtitlesHelp": "Erabiliko diren azpitituluak fitxategien pistetan txertatutako metadatuen araberakoak izango dira (bai \"lehenetsita\" edo \"behartuta\"). Hizkuntza ezarpenak kontuan hartzen dira hainbat aukera eskuragarri daudenean.",
"DefaultMetadataLangaugeDescription": "Hauek dira zure ezarpenak eta liburutegi bakoitzerako pertsonalizatu daitezke.",
"Default": "Lehenetsia",
"DeathDateValue": "Hil egin zen: {0}",
"DatePlayed": "Erreproduzitua",
@ -1455,7 +1455,7 @@
"ColorSpace": "Kolore-espazioa",
"ColorPrimaries": "Kolore primarioak",
"Collections": "Bildumak",
"ClientSettings": "Bezeroaren doikuntzak",
"ClientSettings": "Bezeroaren ezarpenak",
"ClearQueue": "Ezabatu buztana",
"CinemaModeConfigurationHelp": "Zinema moduak zinemaren esperientzia zuzenean ematen du bere aretoan, funtzio nagusiaren aurretik trailerrak eta sarrera pertsonalizatuak erreproduzitzeko gaitasunarekin.",
"Channels": "Kanalak",
@ -1547,7 +1547,7 @@
"HeaderBranding": "Itxura pertsonalizatzea",
"HeaderBlockItemsWithNoRating": "Baloraziorik gabeko edo ezezagunak diren artikuluak blokeatzea:",
"HeaderAutoDiscovery": "Sarearen aurkikuntza",
"HeaderAudioSettings": "Audio-doikuntzak",
"HeaderAudioSettings": "Audio ezarpenak",
"HeaderAudioBooks": "Audioliburuak",
"HeaderAppearsOn": "Hemen agertzen da",
"HeaderApp": "Aplikazioa",
@ -1626,5 +1626,9 @@
"ButtonSpace": "Hutsunea",
"EnableRewatchingNextUp": "Gaitu berriz ikustea Nobedadeak atalekoentzat",
"EnableRewatchingNextUpHelp": "Gaitu jada ikusitako kapituluak \"Nobedadeak\" atalean agertzea.",
"LabelMaxVideoResolution": "Onartutako bideo-transkodetzearen bereizmen maximoa:"
"LabelMaxVideoResolution": "Onartutako bideo-transkodetzearen bereizmen maximoa:",
"EnableCardLayout": "Erakutsi CardBox ikusgai",
"GoogleCastUnsupported": "Google Cast ez da bateragarria",
"Experimental": "Esperimentala",
"DownloadAll": "Deskargatu dena"
}

View File

@ -343,7 +343,7 @@
"LabelAbortedByServerShutdown": "(Keskeytetty palvelimen sammutuksen takia)",
"Identify": "Tunnista",
"Horizontal": "Horisontaalinen",
"HideWatchedContentFromLatestMedia": "Piilota toistettu sisältö 'Hiljattain lisätty media' -osiosta",
"HideWatchedContentFromLatestMedia": "Piilota toistettu sisältö 'Viimeksi lisätty media' -osiosta",
"HeaderUpcomingOnTV": "Tulossa televisiosta",
"HeaderTypeImageFetchers": "Kuvien lataajat ({0}):",
"HeaderTranscodingProfile": "Transkoodausprofiili",
@ -411,11 +411,11 @@
"HeaderMediaFolders": "Mediakansiot",
"HeaderMedia": "Media",
"HeaderLibraryFolders": "Kirjaston kansiot",
"HeaderLatestMedia": "Hiljattain lisätty media",
"HeaderLatestRecordings": "Hiljattain lisätyt tallenteet",
"HeaderLatestMusic": "Hiljattain lisätty musiikki",
"HeaderLatestMovies": "Hiljattain lisätyt elokuvat",
"HeaderLatestEpisodes": "Hiljattain lisätyt jaksot",
"HeaderLatestMedia": "Viimeksi lisätty media",
"HeaderLatestRecordings": "Viimeksi lisätyt tallenteet",
"HeaderLatestMusic": "Viimeksi lisätty musiikki",
"HeaderLatestMovies": "Viimeksi lisätyt elokuvat",
"HeaderLatestEpisodes": "Viimeksi lisätyt jaksot",
"HeaderInstall": "Asenna",
"HeaderFrequentlyPlayed": "Usein toistetut",
"HeaderFetcherSettings": "Lataajan asetukset",
@ -562,7 +562,7 @@
"TabMyPlugins": "Omat lisäosat",
"TabMusic": "Musiikki",
"TabLogs": "Lokit",
"TabLatest": "Hiljattain lisätyt",
"TabLatest": "Viimeksi lisätyt",
"TabDirectPlay": "Muuntamaton toisto",
"TabDashboard": "Hallintapaneeli",
"TabCatalog": "Luettelo",
@ -1264,7 +1264,7 @@
"LabelMinAudiobookResumeHelp": "Kohteita pidetään toistamattomina, jos toisto keskeytetään ennen tätä aikaa.",
"LabelMaxStreamingBitrate": "Suoratoiston enimmäislaatu:",
"MoreFromValue": "Lisää kohteesta {0}",
"LatestFromLibrary": "Hiljattain lisätty: '{0}'",
"LatestFromLibrary": "Viimeksi lisätty: {0}",
"LabelVideoRange": "Videon alue:",
"LabelVaapiDeviceHelp": "Tämä on renderöintinoodi, jota käytetään laitteistokiihdytykseen.",
"LabelUserRemoteClientBitrateLimitHelp": "Korvaa globaali arvo asetusten kohdasta Ohjauspaneeli > Toisto > Suoratoisto.",
@ -1696,5 +1696,6 @@
"LabelChapterImageResolutionHelp": "Purettujen kappalekuvien resoluutio.",
"ResolutionMatchSource": "Vastaa lähdettä",
"PreferEmbeddedExtrasTitlesOverFileNames": "Suosi lisämateriaaleille upotettuja otsikoita tiedostonimien sijaan",
"PreferEmbeddedExtrasTitlesOverFileNamesHelp": "Lisämateriaaleilla on usein sama otsikko kuin niiden isännällä. Valitse tämä käyttääksesi silti upotettuja otsikoita."
"PreferEmbeddedExtrasTitlesOverFileNamesHelp": "Lisämateriaaleilla on usein sama otsikko kuin niiden isännällä. Valitse tämä käyttääksesi silti upotettuja otsikoita.",
"SecondarySubtitles": "Toissijaiset tekstitykset"
}

View File

@ -334,7 +334,7 @@
"DownloadsValue": "{0} téléchargements",
"DisplayModeHelp": "Sélectionner l'agencement que vous désirez pour l'interface.",
"DisplayMissingEpisodesWithinSeasons": "Afficher les épisodes manquants dans les saisons",
"DisplayInOtherHomeScreenSections": "Afficher dans les sections de lécran daccueil comme « Ajouts récents » et reprendre le visionnement",
"DisplayInOtherHomeScreenSections": "Afficher dans les sections de lécran daccueil comme « Ajouts récents » et «Reprendre le visionnement»",
"Directors": "Réalisateurs",
"Director": "Réalisateur",
"DetectingDevices": "Détection des appareils",
@ -349,7 +349,7 @@
"HeaderCodecProfile": "Profil de codec",
"HeaderChapterImages": "Images des chapitres",
"HeaderChannelAccess": "Accès aux chaînes",
"LatestFromLibrary": "{0}, ajouts récents",
"LatestFromLibrary": "{0} ajouts récents",
"HideWatchedContentFromLatestMedia": "Masquer le contenu déjà vu dans les 'Derniers Médias'",
"HeaderLatestRecordings": "Derniers enregistrements",
"HeaderLatestMusic": "Dernière musique",
@ -1020,5 +1020,25 @@
"LabelMaxParentalRating": "Classification parentale maximale :",
"SpecialFeatures": "Bonus",
"Sort": "Trier",
"SortByValue": "Trier par"
"SortByValue": "Trier par",
"LabelMovieCategories": "Catégories de films:",
"LabelNewPassword": "Nouveau mot de passe:",
"LabelOriginalName": "Nom original:",
"LabelPasswordRecoveryPinCode": "Code NIP:",
"LabelOriginalTitle": "Titre original:",
"LabelMaxStreamingBitrate": "Qualité maximale de streaming:",
"LabelNotificationEnabled": "Activer cette notification",
"LabelNewName": "Nouveau nom:",
"LabelNewPasswordConfirm": "Confirmer le nouveau mot de passe:",
"LabelPersonRole": "Rôle:",
"LabelPasswordConfirm": "Confirmer le mot de passe:",
"LabelPersonRoleHelp": "Exemple: Conducteur de camion à crème glacée",
"LabelPleaseRestart": "Les changements prendront effets après avoir rechargé manuellement le client web.",
"LabelMinAudiobookResumeHelp": "Les titres sont considérés comme non joué s'ils sont arrêtés avant cette durée.",
"LabelPassword": "Mot de passe:",
"LabelPath": "Chemin:",
"LabelMetadataPath": "Chemin des métadonnées:",
"LabelDummyChapterDuration": "Intervalle:",
"LabelDummyChapterCount": "Limite:",
"LabelChapterImageResolution": "Résolution:"
}

View File

@ -1703,5 +1703,16 @@
"LabelDummyChapterDuration": "Intervalle :",
"LabelDummyChapterCountHelp": "Nombre maximal dimages de chapitre à extraire pour chaque fichier multimédia.",
"PreferEmbeddedExtrasTitlesOverFileNames": "Préférer les titres intégrés aux médias pour les bonus",
"PreferEmbeddedExtrasTitlesOverFileNamesHelp": "Les bonus possèdent souvent un titre intégré identique au média parent, cocher l'option pour utiliser ce titre quoi qu'il en soit."
"PreferEmbeddedExtrasTitlesOverFileNamesHelp": "Les bonus possèdent souvent un titre intégré identique au média parent, cocher l'option pour utiliser ce titre quoi qu'il en soit.",
"SecondarySubtitles": "Sous-titres secondaires",
"SubtitleBlack": "Noir",
"SubtitleBlue": "Bleu",
"SubtitleCyan": "Cyan",
"SubtitleGray": "Gris",
"SubtitleGreen": "Vert",
"SubtitleLightGray": "Gris clair",
"SubtitleMagenta": "Magenta",
"SubtitleRed": "Rouge",
"SubtitleWhite": "Blanc",
"SubtitleYellow": "Jaune"
}

View File

@ -773,7 +773,7 @@
"EnableDecodingColorDepth10Hevc": "אפשר פענוח חומרה של 10 סיביות עבור HEVC",
"EnableBackdropsHelp": "הצג את התפאורות ברקע של כמה דפים בעת גלישה בספרייה.",
"DisplayMissingEpisodesWithinSeasonsHelp": "יש להפעיל זאת גם עבור ספריות טלוויזיה בתצורת השרת.",
"DisplayInOtherHomeScreenSections": "הצג בקטעי מסך הבית כגון המדיה העדכנית והמשיך בצפייה",
"DisplayInOtherHomeScreenSections": "הצג במסך הבית מחיצות כגון \"התוכן, שנוסף לאחרונה\" ו-\"המשיך בצפייה\"",
"DeinterlaceMethodHelp": "בחר בשיטת deinterlacing לשימוש בהמרת תוכנה מקושרת לתוכן. כאשר מופעלת האצת חומרה התומכת בפירוק חומרה של חומרה, ישתמש במתקן החומרה במקום בהגדרה זו.",
"DefaultSubtitlesHelp": "כתוביות נטענות על סמך ברירת המחדל והדגלים המאולצים במטא הנתונים המוטמעים. העדפות שפה נחשבות כאשר קיימות אפשרויות מרובות.",
"ColorTransfer": "העברת צבע",
@ -1049,5 +1049,6 @@
"DownloadAll": "הורד הכל",
"Experimental": "ניסיוני",
"LabelDisableCustomCss": "אפשר קוד css מותאם אישית בשביל עיצובים מהשרת",
"LabelEasyPinCode": "קוד PIN קל"
"LabelEasyPinCode": "קוד PIN קל",
"EnableCardLayout": "הצג מערך ארגז חזותי"
}

View File

@ -17,16 +17,16 @@
"AddToCollection": "संग्रह में जोड़ें",
"Add": "जोड़ें",
"Actor": "अभिनेता",
"AccessRestrictedTryAgainLater": "वर्तमान में पहुंच प्रतिबंधित है। कृपया बाद में पुनः प्रयास करें.",
"AccessRestrictedTryAgainLater": "पहुंच प्रतिबंधित है। कृपया बाद में प्रयास करें.",
"AllowHWTranscodingHelp": "ट्यूनर को निरंतर रूप से धाराओं को ट्रांसकोड करने दें। यह सर्वर द्वारा ट्रांसकोडिंग को कम करने में मदद कर सकता है।",
"AllLanguages": "सभी भाषाएं",
"AllEpisodes": "सभी प्रकरण",
"AllComplexFormats": "सभी जटिल प्रारूप (ASS, SSA, VobSub, PGS, SUB, IDX, …)",
"AllComplexFormats": "सभी प्रारूप (ASS, SSA, VobSub, PGS, SUB, IDX, …)",
"AllChannels": "सभी चैनल्स",
"Alerts": "चेतावनियां",
"Albums": "एल्बम",
"Aired": "प्रसारित हो चुका",
"AdditionalNotificationServices": "अतिरिक्त सूचना सेवाओं को स्थापित करने के लिए प्लगइन सूची पर नज़र डालें।",
"Aired": "प्रसारित हो चुका है",
"AdditionalNotificationServices": "दी गयी सूची में से प्लगिन इनस्टॉल करें|",
"AddedOnValue": "जोड़ दिया",
"AddToPlaylist": "प्लेलिस्ट में जोड़ें",
"AllowMediaConversionHelp": "मीडिया परिवर्तन के लिये अनुमति दें या इनकार करें.",
@ -86,7 +86,7 @@
"AllowFfmpegThrottlingHelp": "जब एक ट्रांसकोड या रीमूक्स वर्तमान प्लेबैक स्थिति से काफी आगे हो जाता है, तो प्रक्रिया को रोकें ताकि यह कम संसाधनों का उपभोग करेगा। अक्सर मांग किए बिना देखने पर यह सबसे उपयोगी है। यदि आप प्लेबैक समस्याओं का अनुभव करते हैं तो इसे बंद कर दें।",
"AllowFfmpegThrottling": "थ्रोटल ट्रांसकोड",
"AllowOnTheFlySubtitleExtractionHelp": "वीडियो ट्रांसकोडिंग को रोकने में मदद करने के लिए एंबेडेड सबटाइटल वीडियो से निकाले जा सकते हैं और सादे पाठ में ग्राहकों तक पहुंचाए जाते हैं। कुछ प्रणालियों पर यह एक लंबा समय ले सकता है और निष्कर्षण प्रक्रिया के दौरान वीडियो प्लेबैक को स्टाल करने का कारण बन सकता है। जब वे क्लाइंट डिवाइस द्वारा मूल रूप से समर्थित नहीं होते हैं, तो वीडियो ट्रांसकोडिंग के साथ जले हुए एम्बेडेड उपशीर्षक को अक्षम करें।",
"AlbumArtist": "चित्राधार कलाकार",
"AlbumArtist": "एल्बम कलाकार",
"AllowOnTheFlySubtitleExtraction": "मक्खी पर उपशीर्षक निष्कर्षण की अनुमति दें",
"Album": "एल्बम",
"ButtonSyncPlay": "SyncPlay",
@ -129,5 +129,23 @@
"MusicVideos": "संगीत वीडियो",
"OptionBluray": "BD",
"Playlists": "प्लेलिस्ट",
"Photos": "तस्वीरें"
"Photos": "तस्वीरें",
"AgeValue": "({0} साल पुराना)",
"ButtonClose": "बंद करें",
"AddToFavorites": "पसंदीदो में शामिल करे",
"ButtonExitApp": "ऐप को बंद करें",
"ButtonSpace": "स्पेस",
"ButtonSplit": "विभाजित करें",
"ButtonStart": "शुरु करें",
"ButtonStop": "रोकें",
"ButtonSubmit": "प्रस्तुत करें",
"ButtonTogglePlaylist": "प्लेलिस्ट",
"ButtonUninstall": "ऐप हटाएं",
"ButtonTrailer": "ट्रेलर",
"Large": "बड़ा",
"Small": "छोटा",
"Normal": "सामान्य",
"Songs": "गाने",
"Larger": "और बड़ा",
"ListPaging": "{2} का {0}-{1}"
}

View File

@ -107,9 +107,9 @@
"HeaderIdentifyItemHelp": "Adj meg egy vagy több keresési kritériumot. Távolítsd el a kritériumokat a keresési eredmények növelése érdekében.",
"HeaderImageSettings": "Kép beállítások",
"HeaderInstall": "Telepítés",
"HeaderLatestEpisodes": "Legújabb epizódok",
"HeaderLatestMedia": "Legújabb média",
"HeaderLatestMovies": "Legújabb filmek",
"HeaderLatestEpisodes": "Nemrég hozzáadott epizódok",
"HeaderLatestMedia": "Nemrég hozzáadott tartalmak",
"HeaderLatestMovies": "Nemrég hozzáadott filmek",
"HeaderLibraries": "Könyvtárak",
"HeaderLibraryAccess": "Könyvtár hozzáférés",
"HeaderLibraryFolders": "Médiatár mappák",
@ -156,7 +156,7 @@
"HeaderVideos": "Videók",
"HeaderYears": "Év",
"Help": "Súgó",
"HideWatchedContentFromLatestMedia": "A megtekintett tartalom elrejtése a \"Legújabb Média\"-ból",
"HideWatchedContentFromLatestMedia": "A megtekintett tartalom elrejtése a \"Nemrég hozzáadott felvételek\"-ből",
"Home": "Kezdőlap",
"Identify": "Azonosítás",
"Images": "Képek",
@ -395,7 +395,7 @@
"TabCodecs": "Kódek",
"TabContainers": "Tároló",
"TabDashboard": "Vezérlőpult",
"TabLatest": "Legújabb",
"TabLatest": "Nemrég hozzáadott",
"TabLogs": "Naplók",
"TabMusic": "Zene",
"TabMyPlugins": "Telepített bővítmények",
@ -519,7 +519,7 @@
"Disc": "Lemez",
"Disconnect": "Bontás",
"DisplayInMyMedia": "Megjelenítés a kezdőképernyőn",
"DisplayInOtherHomeScreenSections": "Megjelenítés a kezdőképernyőn, mint például a 'Legújabb Média', és a 'Folyamatban lévő filmek'",
"DisplayInOtherHomeScreenSections": "Megjelenítés a kezdőképernyőn, mint például a 'Nemrég hozzáadott', és a 'Korábban megtekintett'",
"DisplayModeHelp": "Válaszd ki a használni kívánt elrendezést.",
"DoNotRecord": "Ne rögzítsen",
"DownloadsValue": "{0} letöltés",
@ -604,8 +604,8 @@
"HeaderInstantMix": "Azonnali keverés",
"HeaderKeepRecording": "Felvétel készítése",
"HeaderKodiMetadataHelp": "Az NFO-metaadatok engedélyezéséhez vagy letiltásához szerkesszen egy könyvtárat, és keresse meg a „Metaadat-mentők” részt.",
"HeaderLatestMusic": "Legújabb zenék",
"HeaderLatestRecordings": "Legújabb felvételek",
"HeaderLatestMusic": "Nemrég hozzáadott zenék",
"HeaderLatestRecordings": "Nemrég hozzáadott felvételek",
"HeaderLoginFailure": "Bejelentkezési hiba",
"HeaderMusicQuality": "Zene minősége",
"HeaderNewApiKey": "Új API kulcs",
@ -1510,7 +1510,7 @@
"Framerate": "Képkockasebesség",
"DirectPlayHelp": "A forrásfájl teljes mértékben kompatibilis ezzel az klienssel, és a munkamenet módosítások nélkül fogadja a fájlt.",
"HeaderContinueReading": "Olvasás folytatása",
"EnableGamepadHelp": "Figyeljen bármilyen csatlakoztatott kontroller bemenetére.",
"EnableGamepadHelp": "Figyeljen bármilyen csatlakoztatott bemenetre. (Szükséges: TV megjelenítési mód)",
"LabelEnableGamepad": "Engedélyezze a Gamepad-ot",
"Controls": "Vezérlők",
"TextSent": "Szöveg elküldve.",
@ -1685,5 +1685,30 @@
"MessageNoItemsAvailable": "Jelenleg nincs elérhető elem.",
"MessageNoFavoritesAvailable": "Jelenleg nincs elérhető kedvenc.",
"Unreleased": "Még nem jelent meg",
"DownloadAll": "Összes letöltése"
"DownloadAll": "Összes letöltése",
"PreferEmbeddedExtrasTitlesOverFileNamesHelp": "Beágyazott címek használata.",
"SaveRecordingNFO": "A rögzített EPG metaadatok mentése NFO-ba",
"SubtitleBlack": "Fekete",
"SubtitleBlue": "Kék",
"SubtitleCyan": "Cián",
"SubtitleGray": "Szürke",
"SubtitleGreen": "Zöld",
"SubtitleLightGray": "Világos szürke",
"SubtitleMagenta": "Bíborvörös",
"SubtitleRed": "Piros",
"SubtitleWhite": "Fehér",
"SubtitleYellow": "Sárga",
"SecondarySubtitles": "Másodlagos feliratok",
"StereoDownmixAlgorithmHelp": "Többcsatornás hangot sztereóvá keverő algoritmus használata.",
"LabelDummyChapterCountHelp": "Az egyes médiafájlokból kibontható fejezetképek maximális száma.",
"PreferEmbeddedExtrasTitlesOverFileNames": "Részesítse előnyben a beágyazott címeket a fájlnevekkel szemben",
"SaveRecordingImages": "Rögzített EPG-képek mentése",
"Experimental": "Tapasztalati",
"LabelStereoDownmixAlgorithm": "Térhatású csatornák egyesítése",
"HeaderDummyChapter": "Fejezetképek",
"HeaderRecordingMetadataSaving": "Metaadatok rögzítése",
"LabelDummyChapterDuration": "Intervallum:",
"LabelDummyChapterCount": "Határvonal:",
"LabelChapterImageResolution": "Felbontás:",
"LabelChapterImageResolutionHelp": "A kinyert fejezetképek felbontása."
}

View File

@ -447,6 +447,36 @@
"Mute": "Þagga",
"MusicArtist": "Tónlistarmaður",
"MusicAlbum": "Tónlistaralbúm",
"ButtonCast": "Senda efni út í tæki",
"AddToFavorites": "Bæta við eftirlæti"
"ButtonCast": "Senda út í tæki",
"AddToFavorites": "Bæta við eftirlæti",
"ButtonPlayer": "Spilari",
"AgeValue": "({0} ára)",
"ApiKeysCaption": "Listi yfir núverandi virkum API lyklum",
"ButtonActivate": "Virkja",
"ButtonClose": "Loka",
"ButtonSpace": "Bil",
"Authorize": "Heimila",
"ChangingMetadataImageSettingsNewContent": "Breytingar á niðurhali lýsigögnum eða myndum mun aðeins gilda um ný efni sem bætt hafa verið í safnið. Til að breyta núverandi titla þarftu að endurnýja lýsigögnin handvirkt.",
"ColorTransfer": "Litaflutningur",
"Data": "Gögn",
"ClearQueue": "Hreinsa biðröð",
"DailyAt": "Daglega um {0}",
"DashboardServerName": "Þjónn: {0}",
"DashboardVersionNumber": "Útgáfa: {0}",
"ColorSpace": "Litarými",
"Copied": "Aftritað",
"Copy": "Afrita",
"CopyFailed": "Gat ekki afritað",
"ButtonExitApp": "Fara úr forriti",
"EnableFasterAnimations": "Hraðari hreyfimyndir",
"EnablePlugin": "Virkja",
"Bwdif": "BWDIF",
"DisablePlugin": "Slökkva",
"EnableAutoCast": "Setja sem Sjálfgefið",
"EnableDetailsBanner": "Upplýsingar borði",
"DeleteAll": "Eyða Öllu",
"ButtonBackspace": "Backspace",
"ButtonUseQuickConnect": "Nota hraðtengingu",
"Digital": "Stafrænt",
"DownloadAll": "Sækja allt"
}

View File

@ -137,7 +137,7 @@
"Disconnect": "Disconnetti",
"Display": "Schermo",
"DisplayInMyMedia": "Visualizza nella schermata di home",
"DisplayInOtherHomeScreenSections": "Mostra le sezioni della schermata home come 'Ultimi media' e 'Continua a guardare'",
"DisplayInOtherHomeScreenSections": "Visualizza nelle sezioni della schermata iniziale come \"Media aggiunti di recente\" e \"Continua a guardare\"",
"DisplayMissingEpisodesWithinSeasons": "Visualizza gli episodi mancanti nelle stagioni",
"DisplayMissingEpisodesWithinSeasonsHelp": "Questo deve anche essere abilitato per le librerie TV nella configurazione del server.",
"DisplayModeHelp": "Seleziona lo stile del layout che vuoi per l'interfaccia.",

View File

@ -144,8 +144,8 @@
"DirectStreamHelp1": "ビデオストリームは、お使いのデバイスとの互換性がありますが、DTS、Dolby TrueHDなどのオーディオフォーマットまたはオーディオチャンネル数で互換性がありません。ビデオストリームは、デバイスに送信される前に、ロスレスに再パッケージされ、音声ストリームのみをトランスコードします。",
"DirectStreamHelp2": "ダイレクトストリーミングによって消費される電力はオーディオプロファイルによります。動画のストリームのみが可逆圧縮です。",
"DirectStreaming": "ダイレクトストリーミング",
"Director": "ディレクター",
"Directors": "ディレクターズ",
"Director": "監督",
"Directors": "監督",
"Disc": "ディスク",
"Disconnect": "切断",
"Display": "ディスプレイ",

View File

@ -115,7 +115,7 @@
"Identify": "Identifikuoti",
"Images": "Atvaizdai",
"InstallingPackage": "Diegiama {0} (versija {1})",
"InstantMix": "Leisti miksą",
"InstantMix": "Maišyti",
"ItemCount": "{0} elementų",
"Kids": "Vaikams",
"Label3DFormat": "3D formatas:",
@ -809,7 +809,7 @@
"LabelProtocol": "Protokolas:",
"LabelProtocolInfo": "Apie protokolą:",
"HeaderCodecProfileHelp": "Kodekų profiliai nurodo įrenginio apribojimus, kai medija leidžiama su konkrečiais kodekais. Jei taikomas apribojimas, laikmena perkoduojama, net jei kodekas sukonfigūruotas tiesioginiam atkūrimui.",
"HeaderInstantMix": "auto miksavimas",
"HeaderInstantMix": "Maišyti",
"HeaderLibraryAccess": "Mediatekos prieigos teisės",
"HeaderLibraryOrder": "Mediatekos eiliškumas",
"HeaderLibrarySettings": "Mediatekos nustatymai",

42
src/strings/mg.json Normal file
View File

@ -0,0 +1,42 @@
{
"Add": "Manampy",
"AddToPlaylist": "Ampiana ao amin'ny playlist",
"AddToPlayQueue": "Ampiana ao amin'ny filaharana",
"AirDate": "Daty fandefasana",
"Aired": "Nalefa",
"AlbumArtist": "Artista tompon'ny Album",
"Alerts": "Lakolosy",
"AllChannels": "Fahitalavitra rehetra",
"AllowMediaConversion": "Avela hiasa hanao famadiahana format",
"AllowEmbeddedSubtitlesAllowNoneOption": "Tsy asiana mihitsy",
"AllowEmbeddedSubtitlesAllowTextOption": "Asiana soratra",
"Absolute": "Feno",
"AccessRestrictedTryAgainLater": "Voafetra ny fidirana amin'izao fotoana izao. Andramo indray afaka fotoana fohy.",
"Actor": "Mpilalao",
"AddedOnValue": "Nampiana",
"AdditionalNotificationServices": "Tsidiho ny katalaogin'ny plugin raha hanampy serivisy fampahafantarana fanampiny.",
"AddToCollection": "Ampiana ao amin'ny fitahirizana",
"AddToFavorites": "Ampiana ao amin'ireo ankafihizina",
"AgeValue": "({0} taona)",
"Album": "Album",
"Albums": "Albums",
"All": "Rehetra",
"AllComplexFormats": "Ireo endrika sarotra rehetra (ASS, SSA, VobSub, PGS, SUB, IDX, …)",
"AllEpisodes": "Fizaràna rehetra",
"AllLanguages": "Tenim-pirenena rehetra",
"AllLibraries": "Tahiry rehetra",
"AllowedRemoteAddressesHelp": "Lisitry ny adiresy IP na IP/netmask nosarahan'ny faingo ho an'ny tambajotra izay avela hifandray lavitra. Raha avela ho banga dia afaka miditra avokoa ny IP rehetra.",
"AllowEmbeddedSubtitles": "Atsahatra ny karazana dikanteny ao anatiny",
"AllowEmbeddedSubtitlesAllowAllOption": "Avela malalaka",
"AllowEmbeddedSubtitlesAllowImageOption": "Asiana sary",
"AllowEmbeddedSubtitlesHelp": "Atsahatra ny dikanteny raikitra ao anaty media. Mila fanavaozana ny tahiry rehetra.",
"AllowFfmpegThrottling": "Ahena ny asa famadihana format",
"AllowFfmpegThrottlingHelp": "Rehefa lasa lavitra mihoatra ny playback ny asa famadihana format dia atsahatra kely ny fampiasana CPU. Tena ilaina izany rehefa mijery fotsiny fa tsy mandingana na mamerina matetika. Aza alefa raha mahita olana amin'ny playback.",
"AllowHevcEncoding": "Avela hamadika format HEVC",
"AllowHWTranscodingHelp": "Avela ny tuner hiasa sady mamadika format. Mety hanampy amin'ny fampihenana ny asa takian'ny serveur izany.",
"AllowMediaConversionHelp": "Avela na lavina ny fidirana amin'ny asa famadihana format.",
"AllowOnTheFlySubtitleExtraction": "Avela hamaky dikanteny eny ampandehanana.",
"AllowOnTheFlySubtitleExtractionHelp": "Azo alaina avy amin'ilay video ny dikanteny ao anatiny ary aseho amin'ny soratra tsotra, mba hisorohana ny famadihana video. Mety haharitra ela izany ka hampiato ny famakiana horonan-tsary mandritra ny dingan'ny fitrandrahana. Atsaharo raha avela ho dikanteny miaraka amin'ny famadihana horonan-tsary.",
"AllowRemoteAccess": "Avela hifandray amin'ny hafa ity serveur ity",
"AllowRemoteAccessHelp": "Raha tsy marihina dia ho voasakana ny fifandraisana lavitra rehetra."
}

View File

@ -1525,7 +1525,7 @@
"VideoFramerateNotSupported": "Videoens bildefrekvens støttes ikke",
"VideoBitDepthNotSupported": "Videoens bitdybde støttes ikke",
"RefFramesNotSupported": "Referanse-bilder støttes ikke",
"EnableGamepadHelp": "Lytt til inndata fra tilkoblet kontroller.",
"EnableGamepadHelp": "Lytt til inndata fra tilkoblet kontroller. (Krever: \"TV\"-visningsmodus)",
"LabelEnableGamepad": "Aktiver spillkontroller",
"AudioBitDepthNotSupported": "Lydens bitdybde støttes ikke",
"ThemeSong": "Tema-låt",
@ -1685,5 +1685,12 @@
"MessageNoItemsAvailable": "Ingen filer er tilgjengelige for øyeblikket.",
"OptionDateShowAdded": "Dato serien ble lagt til",
"Experimental": "Eksperimentell",
"DownloadAll": "Laste ned alt"
"DownloadAll": "Laste ned alt",
"LabelDummyChapterCountHelp": "Maksimalt antall kapittelbilder som vil bli ekstrahert for hver mediefil.",
"LabelStereoDownmixAlgorithm": "Stereo nedmiksingsalgoritme",
"HeaderDummyChapter": "Kapittel Bilder",
"LabelDummyChapterCount": "Grense:",
"LabelChapterImageResolution": "Oppløsning:",
"LabelDummyChapterDuration": "Intervall:",
"HeaderRecordingMetadataSaving": "Opptak metadata"
}

View File

@ -107,7 +107,7 @@
"ConfirmDeletion": "Bevestigen Verwijdering",
"ConfirmEndPlayerSession": "Wilt u Jellyfin afsluiten op {0}?",
"Connect": "Verbind",
"ContinueWatching": "Verder kijken",
"ContinueWatching": "Verderkijken",
"Continuing": "Wordt vervolgd",
"CriticRating": "Critici-beoordeling",
"CustomDlnaProfilesHelp": "Maak een aangepast profiel om een nieuw apparaat aan te maken of overschrijf een systeemprofiel.",
@ -139,7 +139,7 @@
"Disconnect": "Loskoppelen",
"Display": "Weergave",
"DisplayInMyMedia": "Op het startscherm weergeven",
"DisplayInOtherHomeScreenSections": "In secties van het startscherm weergeven, zoals \"Recente media\" en \"Verder kijken\"",
"DisplayInOtherHomeScreenSections": "In secties van het startscherm weergeven, zoals 'Onlangs toegevoegde media' en 'Verderkijken'",
"DisplayMissingEpisodesWithinSeasons": "Toon ontbrekende afleveringen binnen een seizoen",
"DisplayMissingEpisodesWithinSeasonsHelp": "Dit moet ook worden ingeschakeld voor tv-bibliotheken in de serverconfiguratie.",
"DisplayModeHelp": "Selecteer het schermtype waar Jellyfin op draait.",
@ -284,11 +284,11 @@
"HeaderKeepRecording": "Bewaar opname",
"HeaderKeepSeries": "Series behouden",
"HeaderKodiMetadataHelp": "Om NFO-metadata in of uit te schakelen, bewerk een bibliotheek en zoek in de metadata-downloaders sectie.",
"HeaderLatestEpisodes": "Nieuwste afleveringen",
"HeaderLatestMedia": "Nieuwste media",
"HeaderLatestMovies": "Nieuwste films",
"HeaderLatestMusic": "Nieuwste muziek",
"HeaderLatestRecordings": "Nieuwste opnames",
"HeaderLatestEpisodes": "Onlangs toegevoegde afleveringen",
"HeaderLatestMedia": "Onlangs toegevoegde media",
"HeaderLatestMovies": "Onlangs toegevoegde films",
"HeaderLatestMusic": "Onlangs toegevoegde muziek",
"HeaderLatestRecordings": "Onlangs toegevoegde opnamen",
"HeaderLibraries": "Bibliotheken",
"HeaderLibraryAccess": "Bibliotheek toegang",
"HeaderLibraryFolders": "Bibliotheekmappen",
@ -324,7 +324,7 @@
"HeaderPreferredMetadataLanguage": "Gewenste metadata taal",
"HeaderProfileInformation": "Profiel Informatie",
"HeaderProfileServerSettingsHelp": "Deze waarden bepalen hoe de server zich zal presenteren aan het apparaat.",
"HeaderRecentlyPlayed": "Recent afgespeeld",
"HeaderRecentlyPlayed": "Onlangs afgespeeld",
"HeaderRecordingOptions": "Opname instellingen",
"HeaderRecordingPostProcessing": "Nabewerking opname",
"HeaderRemoteControl": "Afstandsbediening",
@ -366,7 +366,7 @@
"HeaderTranscodingProfile": "Direct Afspelen Profiel",
"HeaderTranscodingProfileHelp": "Transcoding profielen toevoegen om aan te geven welke indelingen moeten worden gebruikt wanneer transcoding vereist is.",
"HeaderTunerDevices": "Tuner apparaten",
"HeaderTypeImageFetchers": "Afbeelding downloaders ({0}):",
"HeaderTypeImageFetchers": "Ophalers afbeeldingen ({0}):",
"HeaderTypeText": "Voer tekst in",
"HeaderUpcomingOnTV": "Binnenkort op tv",
"HeaderUploadImage": "Afbeelding Uploaden",
@ -382,7 +382,7 @@
"HeaderYears": "Jaren",
"Help": "Hulp",
"Hide": "Verbergen",
"HideWatchedContentFromLatestMedia": "Verberg bekeken inhoud uit 'Nieuwste media'",
"HideWatchedContentFromLatestMedia": "Bekeken inhoud verbergen uit 'Onlangs toegevoegde media'",
"Home": "Start",
"Horizontal": "Horizontaal",
"HttpsRequiresCert": "Om beveiligde verbindingen in te schakelen, is een vertrouwd SSL-certificaat vereist (zoals Let's Encrypt). Geef een certificaat op of schakel beveiligde verbindingen uit.",
@ -488,7 +488,7 @@
"LabelEpisodeNumber": "Afleveringsnummer:",
"LabelEvent": "Gebeurtenis:",
"LabelEveryXMinutes": "Iedere:",
"LabelExtractChaptersDuringLibraryScan": "Hoofdstukafbeeldingen uitpakken tijdens het scannen van de bibliotheek",
"LabelExtractChaptersDuringLibraryScan": "Hoofdstukafbeeldingen uitpakken tijdens bibliotheekscan",
"LabelExtractChaptersDuringLibraryScanHelp": "Genereer hoofdstuk afbeeldingen wanneer video's geïmporteerd worden tijdens het scannen van de bibliotheek. Zo niet, zullen deze gegenereerd worden tijdens een geplande taak, hierdoor zal reguliere bibliotheek scan sneller voltooien.",
"LabelFailed": "Mislukt",
"LabelFileOrUrl": "Bestand of URL:",
@ -504,7 +504,7 @@
"LabelHardwareAccelerationType": "Hardware acceleratie:",
"LabelHardwareAccelerationTypeHelp": "Hardwarematige versnelling vereist extra configuratie.",
"LabelHomeNetworkQuality": "Thuisnetwerk kwaliteit:",
"LabelHomeScreenSectionValue": "Beginscherm sectie {0}:",
"LabelHomeScreenSectionValue": "Beginschermsectie {0}:",
"LabelHttpsPort": "Lokale HTTPS poort nummer:",
"LabelHttpsPortHelp": "Het TCP poort nummer voor de HTTPS server.",
"LabelIconMaxHeight": "Pictogram maximum hoogte:",
@ -694,7 +694,7 @@
"LabelffmpegPathHelp": "Het pad naar het FFmpeg applicatiebestand, of de folder die FFmpeg bevat.",
"LanNetworksHelp": "Komma-gescheiden lijst van IP-adressen of IP/netmask adressen voor netwerken die als lokaal gezien worden wanneer bandbreedtebeperkingen van toepassing zijn. Indien ingesteld, worden alle overige IP-adressen gezien als externe adressen en zullen worden onderworpen aan de bandbreedte-instellingen voor externe adressen. Indien blanco, zal alleen het subnet van de server als lokaal netwerk gezien worden.",
"Large": "Groot",
"LatestFromLibrary": "Nieuwste {0}",
"LatestFromLibrary": "Onlangs toegevoegd aan {0}",
"LearnHowYouCanContribute": "Lees meer over hoe u kunt bijdragen.",
"LibraryAccessHelp": "Selecteer de bibliotheken om met deze gebruiker te delen. Beheerders kunnen alle mappen bewerken via de metadata-beheerder.",
"List": "Lijst",
@ -735,7 +735,7 @@
"MessageConfirmRevokeApiKey": "Weet u zeker dat u deze API-sleutel in wilt trekken? De verbinding van de applicatie met deze server zal plotseling verbroken worden.",
"MessageConfirmShutdown": "Weet u zeker dat u de server wilt afsluiten?",
"MessageContactAdminToResetPassword": "Neem contact op met de serverbeheerder om uw wachtwoord te resetten.",
"MessageCreateAccountAt": "Maak een account bij {0}",
"MessageCreateAccountAt": "Account aanmaken bij {0}",
"MessageDeleteTaskTrigger": "Weet u zeker dat u deze signaal taak wilt verwijderen?",
"MessageDirectoryPickerBSDInstruction": "Voor BSD moet u mogelijk de opslag in uw FreeNAS Jail opzetten, zodat Jellyfin toegang heeft tot uw media.",
"MessageDirectoryPickerLinuxInstruction": "Voor Linux op Arch Linux, CentOS, Debian, Fedora, openSUSE, of Ubuntu, moet u de service-gebruiker ten minste leestoegang tot uw opslaglocaties verlenen.",
@ -928,8 +928,8 @@
"Raised": "Verhoogd",
"Rate": "Waardeer",
"RecentlyWatched": "Onlangs bekeken",
"RecommendationBecauseYouLike": "Omdat u {0} leuk vond",
"RecommendationBecauseYouWatched": "Omdat u keek naar {0}",
"RecommendationBecauseYouLike": "Omdat je {0} leuk vindt",
"RecommendationBecauseYouWatched": "Omdat je keek naar {0}",
"RecommendationDirectedBy": "Geregisseerd door {0}",
"RecommendationStarring": "In de hoofdrollen {0}",
"Record": "Opnemen",
@ -991,7 +991,7 @@
"Shuffle": "Willekeurig",
"SimultaneousConnectionLimitHelp": "Het maximum aantal toegestane gelijktijdige streams. Geef 0 in voor geen limiet.",
"SkipEpisodesAlreadyInMyLibrary": "Neem geen afleveringen op die al in mijn bibliotheek aanwezig zijn",
"SkipEpisodesAlreadyInMyLibraryHelp": "Afleveringen zullen worden vergeleken met behulp van seizoen en aflevering nummers, indien beschikbaar.",
"SkipEpisodesAlreadyInMyLibraryHelp": "Afleveringen zullen worden vergeleken met behulp van seizoens- en afleveringsnummers, indien beschikbaar.",
"Small": "Klein",
"SmallCaps": "Kleine letters",
"Smaller": "Kleiner",
@ -1017,7 +1017,7 @@
"TabAdvanced": "Geavanceerd",
"TabCatalog": "Catalogus",
"TabDirectPlay": "Direct Afspelen",
"TabLatest": "Nieuwste",
"TabLatest": "Onlangs toegevoegd",
"TabLogs": "Logboeken",
"TabMusic": "Muziek",
"TabMyPlugins": "Mijn plug-ins",
@ -1059,7 +1059,7 @@
"ValueConditions": "Voorwaarden: {0}",
"ValueEpisodeCount": "{0} afleveringen",
"ValueMovieCount": "{0} films",
"ValueMusicVideoCount": "{0} muziek video's",
"ValueMusicVideoCount": "{0} muziekvideo's",
"ValueOneEpisode": "1 aflevering",
"ValueOneMovie": "1 film",
"ValueOneMusicVideo": "1 muziekvideo",
@ -1265,7 +1265,7 @@
"EveryXMinutes": "Elke {0} minuten",
"OnWakeFromSleep": "Op het wakker worden vanuit slaapstand",
"WeeklyAt": "{0}s op {1}",
"DailyAt": "Dagelijks op {0}",
"DailyAt": "Dagelijks om {0}",
"LastSeen": "Laatst gezien {0}",
"PersonRole": "als {0}",
"ListPaging": "{0}-{1} van de {2}",
@ -1292,7 +1292,7 @@
"MessageSyncPlayGroupDoesNotExist": "Kan niet deelnemen aan de groep omdat deze niet bestaat.",
"MessageSyncPlayPlaybackPermissionRequired": "Afspeelrechten vereist.",
"MessageSyncPlayGroupWait": "{0} is aan het bufferen…",
"MessageSyncPlayUserLeft": "{0} i heeft de groep verlaten.",
"MessageSyncPlayUserLeft": "{0} heeft de groep verlaten.",
"MessageSyncPlayUserJoined": "{0} is lid geworden van de groep.",
"MessageSyncPlayDisabled": "SyncPlay uitgeschakeld.",
"MessageSyncPlayEnabled": "SyncPlay ingeschakeld.",
@ -1544,7 +1544,7 @@
"LabelSyncPlaySettingsSkipToSyncHelp": "Synchronisatie correctiemethode die bestaat uit het zoeken naar de geschatte positie. Synchronisatie Correctie moet ingeschakeld zijn.",
"MessageSent": "Bericht verzonden.",
"Mixer": "Mixer",
"UseEpisodeImagesInNextUpHelp": "'Hierna'- en 'Verder kijken'-secties zullen afleveringsafbeeldingen gebruiken als thumbnails in plaats van de primaire thumbnail van de serie.",
"UseEpisodeImagesInNextUpHelp": "'Hierna'- en 'Verderkijken'-secties zullen afleveringsafbeeldingen gebruiken als thumbnails in plaats van de primaire thumbnail van de serie.",
"SetUsingLastTracks": "Ondertitel/Audio-sporen instellen met vorig item",
"SetUsingLastTracksHelp": "Probeer de ondertiteling/het audiospoor in te stellen op de video die het meest overeenkomt met de laatste video.",
"TextSent": "Tekst verzonden.",
@ -1560,7 +1560,7 @@
"LabelMaxDaysForNextUpHelp": "Zet het maximaal aantal dagen dat een serie in de 'Hierna'-lijst staat zonder het te kijken.",
"PreviousChapter": "Vorig hoofdstuk",
"Remixer": "Remixer",
"UseEpisodeImagesInNextUp": "Gebruik afleveringscovers in de secties 'Hierna' en 'Verder kijken'",
"UseEpisodeImagesInNextUp": "Gebruik afleveringscovers in de secties 'Hierna' en 'Verderkijken'",
"EnableGamepadHelp": "Luister naar input van alle aangesloten controllers. (Vereist weergavemodus 'Tv')",
"VideoCodecNotSupported": "De videocodec wordt niet ondersteund",
"AudioBitrateNotSupported": "De bitrate van de audio wordt niet ondersteund",
@ -1687,5 +1687,31 @@
"DownloadAll": "Alles downloaden",
"Experimental": "Experimenteel",
"StereoDownmixAlgorithmHelp": "Algoritme dat gebruikt wordt om multikanaals geluid naar stereo te downmixen.",
"LabelStereoDownmixAlgorithm": "Stereo-downmix-algoritme"
"LabelStereoDownmixAlgorithm": "Stereo-downmix-algoritme",
"LabelChapterImageResolutionHelp": "De resolutie van de uitgepakte hoofdstukafbeeldingen.",
"LabelDummyChapterDuration": "Interval:",
"LabelDummyChapterCount": "Limiet:",
"LabelDummyChapterCountHelp": "Het maximum aantal hoofdstukafbeeldingen dat wordt opgehaald uit ieder mediabestand.",
"LabelChapterImageResolution": "Resolutie:",
"PreferEmbeddedExtrasTitlesOverFileNames": "Ingesloten titels boven bestandsnamen verkiezen voor extra's",
"PreferEmbeddedExtrasTitlesOverFileNamesHelp": "Extra's hebben vaak dezelfde ingesloten naam als de hoofdinhoud; vink dit aan om toch de ingesloten titels te gebruiken.",
"SaveRecordingImagesHelp": "Afbeeldingen uit EPG-vermeldingen naast media opslaan.",
"SaveRecordingNFO": "EPG-metadata in NFO opslaan",
"SaveRecordingNFOHelp": "Metadata uit de EPG-vermeldingen naast media opslaan.",
"SaveRecordingImages": "EPG-afbeeldingen opslaan",
"HeaderDummyChapter": "Hoofdstukafbeeldingen",
"LabelDummyChapterDurationHelp": "De extractieinterval voor hoofdstukafbeeldingen in seconden.",
"ResolutionMatchSource": "Gelijk aan bron",
"HeaderRecordingMetadataSaving": "Metadata opname",
"SecondarySubtitles": "Secundaire ondertiteling",
"SubtitleBlack": "Zwart",
"SubtitleBlue": "Blauw",
"SubtitleCyan": "Cyaan",
"SubtitleGray": "Grijs",
"SubtitleGreen": "Groen",
"SubtitleLightGray": "Lichtgrijs",
"SubtitleMagenta": "Magenta",
"SubtitleRed": "Rood",
"SubtitleWhite": "Wit",
"SubtitleYellow": "Geel"
}

View File

@ -150,7 +150,7 @@
"Disconnect": "Rozłącz",
"Display": "Wyświetlanie",
"DisplayInMyMedia": "Wyświetlaj na ekranie startowym",
"DisplayInOtherHomeScreenSections": "Wyświetlaj na ekranie startowym sekcje 'Ostatnio dodane' i 'Kontynuuj odtwarzanie'",
"DisplayInOtherHomeScreenSections": "Wyświetlaj w sekcjach ekranu startowego, jak \"Ostatnio dodane media\" i \"Oglądaj dalej\"",
"DisplayMissingEpisodesWithinSeasons": "Wyświetlaj w sezonach brakujące odcinki",
"DisplayMissingEpisodesWithinSeasonsHelp": "Ta opcja musi zostać dodatkowo aktywowana w bibliotece seriali, w konfiguracji serwera.",
"DisplayModeHelp": "Wybierz styl układu interfejsu.",
@ -301,11 +301,11 @@
"HeaderKeepRecording": "Zachowaj nagranie",
"HeaderKeepSeries": "Zachowaj nagranie serialu",
"HeaderKodiMetadataHelp": "By aktywować lub dezaktywować metadane NFO, edytuj ustawienia biblioteki w sekcji 'dostawcy metadanych'.",
"HeaderLatestEpisodes": "Odcinki ostatnio dodane",
"HeaderLatestMedia": "Media ostatnio dodane",
"HeaderLatestMovies": "Filmy ostatnio dodane",
"HeaderLatestMusic": "Muzyka ostatnio dodana",
"HeaderLatestRecordings": "Nagrania ostatnio dodane",
"HeaderLatestEpisodes": "Ostatnio dodane odcinki",
"HeaderLatestMedia": "Ostatnio dodane media",
"HeaderLatestMovies": "Ostatnio dodane filmy",
"HeaderLatestMusic": "Ostatnio dodana muzyka",
"HeaderLatestRecordings": "Ostatnio dodane nagrania",
"HeaderLibraries": "Biblioteki",
"HeaderLibraryAccess": "Dostęp do Bibliotek",
"HeaderLibraryFolders": "Foldery biblioteki",
@ -1701,5 +1701,18 @@
"SaveRecordingNFO": "Zapisz nagrane metadane EPG w NFO",
"SaveRecordingImages": "Zapisywanie obrazów EPG",
"SaveRecordingImagesHelp": "Zapisz obrazy od dostawcy list EPG razem z mediami.",
"HeaderRecordingMetadataSaving": "Nagrywanie metadanych"
"HeaderRecordingMetadataSaving": "Nagrywanie metadanych",
"PreferEmbeddedExtrasTitlesOverFileNames": "Preferuj wbudowane tytuły zamiast nazw plików w materiałach dodatkowych",
"PreferEmbeddedExtrasTitlesOverFileNamesHelp": "Materiały dodatkowe często mają tę samą wbudowaną nazwę co rodzic, zaznacz, aby mimo to używać dla nich wbudowanych tytułów.",
"SubtitleBlack": "Czarny",
"SubtitleGreen": "Zielony",
"SubtitleMagenta": "Magenta",
"SubtitleBlue": "Niebieski",
"SubtitleCyan": "Cyjanowy",
"SubtitleGray": "Szary",
"SubtitleLightGray": "Jasnoszary",
"SubtitleRed": "Czerwony",
"SubtitleWhite": "Biały",
"SubtitleYellow": "Żółty",
"SecondarySubtitles": "Napisy drugorzędne"
}

View File

@ -30,7 +30,7 @@
"AlwaysPlaySubtitlesHelp": "Субтитры, соответствующие настройке языка, будут загружаться независимо от языка аудио.",
"AnyLanguage": "Любой язык",
"Anytime": "В любое время",
"AroundTime": "Около",
"AroundTime": "Около {0}",
"Art": "Вырезка",
"Artists": "Исполнители",
"AsManyAsPossible": "Как можно больше",
@ -79,20 +79,20 @@
"ButtonPreviousTrack": "Предыдущая дорожка",
"ButtonQuickStartGuide": "Руководство по запуску",
"ButtonRefreshGuideData": "Обновить данные телегида",
"ButtonRemove": "Изъять",
"ButtonRemove": "Удалить",
"ButtonRename": "Переименовать",
"ButtonResetEasyPassword": "Сбросить простой PIN-код",
"ButtonResume": "Возобновление",
"ButtonResume": "Возобновить",
"ButtonRevoke": "Отозвать",
"ButtonScanAllLibraries": "Сканировать все медиатеки",
"ButtonSelectDirectory": "Выбрать каталог",
"ButtonSelectView": "Выбрать представление",
"ButtonSend": "Отправить",
"ButtonShutdown": "Завершить работу",
"ButtonSignIn": "Вход",
"ButtonSignIn": "Войти",
"ButtonSignOut": "Выйти",
"ButtonStart": "Запустить",
"ButtonStop": "Стоп",
"ButtonStop": "Остановить",
"ButtonSubmit": "Подтвердить",
"ButtonTogglePlaylist": "Плей-лист",
"ButtonTrailer": "Трейлер",
@ -116,10 +116,10 @@
"ConfirmDeleteImage": "Удалить изображение?",
"ConfirmDeleteItem": "При удалении данного элемента, он удалится и из файловой системы, и из медиатеки. Вы действительно хотите продолжить?",
"ConfirmDeleteItems": "При удалении данных элементов, он удалится и из файловой системы, и из медиатеки. Вы действительно хотите продолжить?",
"ConfirmDeletion": "Подтверждение удаления",
"ConfirmDeletion": "Подтверить удаление",
"ConfirmEndPlayerSession": "Вы хотите завершить работу Jellyfin на {0}?",
"Connect": "Соединиться",
"ContinueWatching": "Продолжение просмотра",
"ContinueWatching": "Продолжить просмотр",
"Continuing": "Продолжаемое",
"Copied": "Скопировано",
"Copy": "Копировать",
@ -155,7 +155,7 @@
"Disconnect": "Разъединиться",
"Display": "Отображение",
"DisplayInMyMedia": "Показывать на главном экране",
"DisplayInOtherHomeScreenSections": "Показывать в разделах главного экрана как \"Новые медиаданные\", \"Продолжение просмотра\"",
"DisplayInOtherHomeScreenSections": "Показывать в разделах главного экрана как \"Новые медиаданные\", \"Продолжить просмотр\"",
"DisplayMissingEpisodesWithinSeasons": "Отображать отсутствующие эпизоды в пределах сезонов",
"DisplayMissingEpisodesWithinSeasonsHelp": "Это также должно быть включено для ТВ-медиатек в конфигурации сервера.",
"DisplayModeHelp": "Выберите желательный стиль разметки для интерфейса.",
@ -204,7 +204,7 @@
"Extras": "Допматериалы",
"FFmpegSavePathNotFound": "Мы не смогли найти FFmpeg по введённому вами пути. FFprobe также необходим и должен быть в той же самой папке. Эти компоненты обычно поставляются вместе в одном загрузочном пакете. Проверьте путь и повторите попытку.",
"FastForward": "Быстро вперёд",
"Favorite": "Избранное",
"Favorite": "Избранный",
"Favorites": "Избранное",
"Features": "Средства",
"File": "Файл",
@ -214,12 +214,12 @@
"Filters": "Фильтры",
"Folders": "Папки",
"FormatValue": "Формат: {0}",
"Friday": "пятница",
"Friday": "Пятница",
"Fullscreen": "Полный экран",
"General": "Общие",
"Genre": "Жанр",
"Genres": "Жанры",
"GroupBySeries": "Группирование по сериалам",
"GroupBySeries": "Сгруппировать по сериалам",
"GroupVersions": "Сгруппировать версии",
"GuestStar": "Приглашенный актёр",
"Guide": "Телегид",
@ -267,7 +267,7 @@
"HeaderContainerProfile": "Профиль контейнера",
"HeaderContainerProfileHelp": "Профили контейнеров обозначают ограничения устройства при воспроизведении определённых форматов. Если применяется ограничение, то медиаданные перекодируются, даже если формат настроен для прямого воспроизведения.",
"HeaderContinueListening": "Продолжение прослушивания",
"HeaderContinueWatching": "Продолжение просмотра",
"HeaderContinueWatching": "Продолжить просмотр",
"HeaderCustomDlnaProfiles": "Настраиваемые профили",
"HeaderDateIssued": "Дата выдачи",
"HeaderDefaultRecordingSettings": "Стандартные параметры записи",
@ -307,11 +307,11 @@
"HeaderKeepRecording": "Продолжать запись",
"HeaderKeepSeries": "Хранение сериала",
"HeaderKodiMetadataHelp": "Для включения или отключения NFO-метаданных, правьте медиатеку и найдите раздел \"Хранители метаданных\".",
"HeaderLatestEpisodes": "Новые эпизоды",
"HeaderLatestMedia": "Новые медиаданные",
"HeaderLatestMovies": "Новые фильмы",
"HeaderLatestMusic": "Новая музыка",
"HeaderLatestRecordings": "Новые записи",
"HeaderLatestEpisodes": "Недавно добавленные эпизоды",
"HeaderLatestMedia": "Недавно добавленные медиаданные",
"HeaderLatestMovies": "Недавно добавленные фильмы",
"HeaderLatestMusic": "Недавно добавленная музыка",
"HeaderLatestRecordings": "Недавно добавленные записи",
"HeaderLibraries": "Медиатеки",
"HeaderLibraryAccess": "Доступ к медиатеке",
"HeaderLibraryFolders": "Медиатечные папки",
@ -409,7 +409,7 @@
"HeaderYears": "Годы",
"Help": "Справка",
"Hide": "Скрыть",
"HideWatchedContentFromLatestMedia": "Скрыть просмотренное содержание в разделе «Новые медиаданные»",
"HideWatchedContentFromLatestMedia": "Скрыть просмотренное содержание в разделе «Недавно добавленные медиаданные»",
"Home": "Главное",
"Horizontal": "Горизонтально",
"HttpsRequiresCert": "Чтобы включить HTTPS для внешних подключений, вам нужно будет предоставить доверенный SSL-cертификат, например, Let's Encrypt. Предоставьте сертификат или отключите защищенные соединения.",
@ -743,7 +743,7 @@
"LabelffmpegPathHelp": "Путь к файлу приложения FFmpeg или к папке содержащей FFmpeg.",
"LanNetworksHelp": "Список разделённых запятыми IP-адресов или записей IP/netmask для сетей, которые будут считаться находящимися в локальной сети, когда принудительно ограничивается пропускная способность. Если так установлено, то все остальные IP-адреса будут считаться находящимися во внешней сети и будут подлежать ограничениям внешней полосы пропускания. Если не заполнять, то считается, что только подсеть сервера находится в локальной сети.",
"Large": "Крупный",
"LatestFromLibrary": "Новые: {0}",
"LatestFromLibrary": "Недавно добавленные в: {0}",
"LearnHowYouCanContribute": "Изучите, как вы можете внести свой вклад.",
"LibraryAccessHelp": "Выделите медиатеки, чтобы дать доступ этому пользователю. Администраторы могут изменять все папки с помощью «Диспетчера метаданных».",
"List": "Список",
@ -1060,7 +1060,7 @@
"ShowIndicatorsFor": "Показывать метки для:",
"ShowTitle": "Отображать название",
"ShowYear": "Отображать год",
"Shows": "Передачи",
"Shows": "Телешоу",
"Shuffle": "Перемешать",
"New": "Новое",
"Filter": "Фильтрать",
@ -1096,7 +1096,7 @@
"TabContainers": "Контейнеры",
"TabDashboard": "Панель",
"TabDirectPlay": "Прямое воспроизведение",
"TabLatest": "Последние",
"TabLatest": "Недавно добавленные",
"TabLogs": "Журналы",
"TabMusic": "Музыка",
"TabMyPlugins": "Мои плагины",
@ -1247,7 +1247,7 @@
"OptionForceRemoteSourceTranscoding": "Перекодировать принудительно удалённые источники медиаданных (нпр., эфирное ТВ)",
"NoCreatedLibraries": "Похоже, вы еще не создали ни одной медиатеки. {0}Желаете создать её сейчас?{1}",
"AskAdminToCreateLibrary": "Попросите администратора создать медиатеку.",
"AllowFfmpegThrottling": "Дросселировать перекодировки",
"AllowFfmpegThrottling": "Ограничить перекодировки",
"PlaybackErrorNoCompatibleStream": "Этот клиент несовместим с медиаданными, а сервер не отправляет медиаданные в совместимом формате.",
"AllowFfmpegThrottlingHelp": "Когда перекодировка или ремуксинг заметно опережают текущую позицию воспроизведения, процесс приостанавливается, чтобы потреблять меньше ресурсов. Это очень полезно, когда вы редко перематываете видео при просмотре. Выключите это, если возникают проблемы с воспроизведением.",
"OnWakeFromSleep": "При пробуждении ото сна",
@ -1281,7 +1281,7 @@
"UnsupportedPlayback": "Jellyfin не может расшифровать содержимое, защищенное DRM, но в любом случае будет предпринята попытка расшифровки всего содержимого, включая защищенные заголовки. Некоторые файлы могут выглядеть полностью черными из-за шифрования или других неподдерживаемых средств, таких как интерактивные заголовки.",
"LabelRequireHttpsHelp": "Если этот флажок установлен, сервер будет автоматически перенаправлять все запросы через HTTP на HTTPS. Это не имеет никакого эффекта, если сервер не слушает HTTPS.",
"LabelEnableHttpsHelp": "Прослушивается указанный HTTPS-порт. Чтобы это вступило в силу, также необходимо предоставить действительный сертификат.",
"ApiKeysCaption": "Список действующих текущих API-ключей",
"ApiKeysCaption": "Список действующих API-ключей",
"SaveChanges": "Изменить",
"LabelRequireHttps": "Требуется HTTPS",
"LabelStable": "Стабильная",
@ -1328,7 +1328,7 @@
"EnableBlurHashHelp": "Рисунки, которые всё ещё загружаются, будут отображаться с уникальным заполнением.",
"EnableBlurHash": "Включить размытые заполнители для изображений",
"ButtonSyncPlay": "Совместный просмотр",
"ButtonCast": "Трансляция на устройство",
"ButtonCast": "Транслировать на устройство",
"TabRepositories": "Репозитории",
"MessageNoGenresAvailable": "Включаются какие-либо поставщики метаданных для получения жанров из интернета.",
"MessageAddRepository": "Если вы хотите добавить репозиторий, нажмите кнопку рядом с заголовком и заполните необходимую информацию.",
@ -1412,7 +1412,7 @@
"EnableQuickConnect": "Разрешить быстрое подключение",
"EnableAutoCast": "Задать по умолчанию",
"ButtonUseQuickConnect": "Использовать быстрое подключение",
"ButtonActivate": "Активация",
"ButtonActivate": "Активировать",
"Authorize": "Авторизовать",
"LabelUserMaxActiveSessions": "Максимальное количество одновременных пользовательских сессий:",
"OptionMaxActiveSessionsHelp": "Значение 0 отключит эту функцию.",
@ -1510,7 +1510,7 @@
"EnableEnhancedNvdecDecoder": "Включить улучшенный декодер NVDEC",
"DisablePlugin": "Отключить",
"EnablePlugin": "Включить",
"Framerate": -та кадров",
"Framerate": астота кадров",
"DirectPlayHelp": "Исходный файл полностью совместим с этим клиентом, а сеанс получает файл без изменений.",
"HeaderContinueReading": "Продолжение чтения",
"EnableGamepadHelp": "Слушать ввод от любых подключенных контроллеров. (Необходим режим отображения \"TV\")",
@ -1520,8 +1520,8 @@
"MessageSent": "Сообщение отправлено.",
"LabelSlowResponseTime": "Время, после которого ответ считается медленным, мс:",
"LabelSlowResponseEnabled": "Журналировать предупреждающее сообщение, если сервер отвечал медленно",
"UseEpisodeImagesInNextUpHelp": "В разделах \"Следующие серии\" и \"Продолжение просмотра\" будут использоваться как эскизы рисунки эпизодов вместо головного эскиза сериала.",
"UseEpisodeImagesInNextUp": "Использовать рисунки эпизодов в разделах \"Следующие серии\" и \"Продолжение просмотра\"",
"UseEpisodeImagesInNextUpHelp": "В разделах \"Следующие серии\" и \"Продолжить просмотр\" будут использоваться как эскизы рисунки эпизодов вместо головного эскиза сериала.",
"UseEpisodeImagesInNextUp": "Использовать рисунки эпизодов в разделах \"Следующие серии\" и \"Продолжить просмотр\"",
"LabelLocalCustomCss": "Настраиваемый CSS-код для стилизации, применимый только к этому клиенту. Вы можете отключить настраиваемый CSS-код сервера.",
"LabelDisableCustomCss": "Отключает настраиваемый CSS-код для тематирования/брендирования, предоставляемый сервером.",
"DisableCustomCss": "Отключить предоставляемый сервером настраиваемый CSS-код",
@ -1588,7 +1588,7 @@
"Typewriter": "Машинописный",
"Print": "Типографский",
"Larger": "Очень крупный",
"Console": "Консольный",
"Console": "Консоль",
"Casual": "Неформальный",
"TypeOptionPluralVideo": "Видео элементы",
"TypeOptionPluralSeries": "ТВ-передачи",
@ -1603,7 +1603,7 @@
"TypeOptionPluralAudio": "Аудио элементы",
"LabelAutomaticallyAddToCollectionHelp": "Если хотя бы два фильма имеют одинаковое название коллекции, они будут автоматически добавлены в коллекцию.",
"LabelAutomaticallyAddToCollection": "Автоматически добавлять в коллекцию",
"Cursive": "Курсивный",
"Cursive": "Курсив",
"PreferSystemNativeHwDecoder": "Предпочитать из декодеров встроенный в ОС DXVA или аппаратный VA-API",
"LabelHardwareEncodingOptions": "Опции аппаратного кодирования:",
"IntelLowPowerEncHelp": "Энергосберегающее кодирование может оставить ненужную синхронизацию CPU-GPU. В Linux они должны быть отключены, если микропрограмма i915 HuC не настроена.",
@ -1625,7 +1625,7 @@
"BehindTheScenes": "За кадром",
"Trailer": "Трейлер",
"Clip": "Отрывок",
"ButtonExitApp": "Выход из приложения",
"ButtonExitApp": "Выйти из приложения",
"AllowEmbeddedSubtitlesAllowTextOption": "Разрешить текст",
"AllowEmbeddedSubtitlesAllowImageOption": "Разрешить рисунок",
"AllowEmbeddedSubtitlesAllowNoneOption": "Ничего не разрешать",
@ -1688,5 +1688,10 @@
"DownloadAll": "Скачать все",
"StereoDownmixAlgorithmHelp": "Алгоритм используемый для смешивания многоканального аудио в стерео.",
"LabelStereoDownmixAlgorithm": "Алгоритм смешивания стерео",
"Experimental": "Экспериментальные"
"Experimental": "Экспериментальные",
"LabelDummyChapterDuration": "Интервал:",
"LabelChapterImageResolution": "Разрешение изображения:",
"HeaderDummyChapter": "Изображения глав",
"LabelDummyChapterCount": "Лимит:",
"HeaderRecordingMetadataSaving": "Метаданные записей"
}

View File

@ -173,11 +173,11 @@
"HeaderImageSettings": "Nastavenia obrázkov",
"HeaderInstall": "Inštalovať",
"HeaderInstantMix": "Okamžitý mix",
"HeaderLatestEpisodes": "Najnovšie epizódy",
"HeaderLatestMedia": "Najnovšie médiá",
"HeaderLatestMovies": "Najnovšie filmy",
"HeaderLatestMusic": "Najnovšia hudba",
"HeaderLatestRecordings": "Najnovšie nahrávky",
"HeaderLatestEpisodes": "Najnovšie pridané epizódy",
"HeaderLatestMedia": "Najnovšie pridané médiá",
"HeaderLatestMovies": "Najnovšie pridané filmy",
"HeaderLatestMusic": "Najnovšia pridaná hudba",
"HeaderLatestRecordings": "Najnovšie pridané nahrávky",
"HeaderLibraries": "Knižnice",
"HeaderLibraryAccess": "Prístup ku knižnici",
"HeaderLibraryFolders": "Priečinky knižnice",
@ -659,7 +659,7 @@
"TabCodecs": "Kodeky",
"TabContainers": "Kontajnery",
"TabDashboard": "Dashboard",
"TabLatest": "Najnovšie",
"TabLatest": "Najnovšie pridané",
"TabMusic": "Hudba",
"TabMyPlugins": "Moje zásuvné moduly",
"TabNetworks": "TV Siete",
@ -723,7 +723,7 @@
"ButtonRevoke": "Odvolať",
"ButtonSelectView": "Výber zobrazenia",
"CancelRecording": "Zrušiť nahrávanie",
"AirDate": "Dátum vysielania",
"AirDate": "Dátum prvého vysielania",
"Aired": "Odvysielané",
"Alerts": "Upozornenia",
"AllowOnTheFlySubtitleExtraction": "Povoliť extrahovanie titulkov za behu",
@ -968,7 +968,7 @@
"EnableStreamLooping": "Autom. slučka živého vysielania",
"EnableExternalVideoPlayersHelp": "Ponuka externého prehrávača sa zobrazí pri spustení prehrávania videa.",
"EnableBackdropsHelp": "Zobraziť pozadia pre niektoré stránky pri prechádzaní knižnice.",
"DisplayInOtherHomeScreenSections": "Zobraziť v sekciách domovskej obrazovky, ako sú najnovšie médiá a pokračovať v pozeraní",
"DisplayInOtherHomeScreenSections": "Zobraziť 'Najnovšie pridané médiá' a 'Pokračovať v pozeraní' v sekciách domovskej obrazovky",
"DirectStreamHelp1": "Video je kompatibilné zo zariadením, ale zvuková stopa je v nekompatibilnom formáte (DTS, Dolby TrueHD, atď.) alebo má nekompatibilný počet kanálov. Video bude pred odoslaním do zariadenia za behu bezstrátovo prebalené. Iba zvuk bude prekódovaný.",
"Depressed": "Stlačený",
"DefaultSubtitlesHelp": "Titulky sú načítané v závislosti od predvolených a vynútených nastavení vo vložených metadátach. Jazykové predvoľby sú zobrané do úvahy až vtedy, keď je k dispozícií viacero možností.",
@ -1701,5 +1701,6 @@
"LabelDummyChapterDurationHelp": "Interval extrakcie obrázkov kapitol v sekundách.",
"SaveRecordingNFO": "Uložiť metadáta nahrávky zo sprievodcu EPG do NFO",
"SaveRecordingImagesHelp": "Uloží obrázky z EPG položiek sprievodcu spolu s médiami.",
"HeaderRecordingMetadataSaving": "Metadáta nahrávok"
"HeaderRecordingMetadataSaving": "Metadáta nahrávok",
"SecondarySubtitles": "Sekundárne titulky"
}

View File

@ -1686,5 +1686,18 @@
"StereoDownmixAlgorithmHelp": "Algoritem uporabljen za downmix večkanalnega zvoka v stereo.",
"Experimental": "Poskusno",
"LabelStereoDownmixAlgorithm": "Stereo Downmix algoritem",
"DownloadAll": "Prenesi vse"
"DownloadAll": "Prenesi vse",
"HeaderDummyChapter": "Slike poglavja",
"SaveRecordingNFO": "Shrani posnete EPG metapodatke v NFO",
"SaveRecordingImagesHelp": "Shrani prenešene slike v mapo datoteke.",
"PreferEmbeddedExtrasTitlesOverFileNames": "Raje uporabi vdelane naslove kot imena datotek",
"SaveRecordingNFOHelp": "Shrani metapodatke v isto mapo",
"LabelDummyChapterDuration": "interval:",
"LabelDummyChapterDurationHelp": "Interval ekstrakcije slike poglavja v sekundah.",
"LabelDummyChapterCount": "Limit:",
"LabelDummyChapterCountHelp": "Največje število slik poglavij, ki bodo ekstrahirane za vsako medijsko datoteko.",
"LabelChapterImageResolution": "Resolucija:",
"LabelChapterImageResolutionHelp": "Ločljivost slik poglavij.",
"ResolutionMatchSource": "ujemanje z virom",
"HeaderRecordingMetadataSaving": "Snemanje metapodatkov"
}

View File

@ -8,10 +8,10 @@
"DeathDateValue": "Помер: {0}",
"Favorite": "Обране",
"HeaderDeleteDevice": "Видаліть пристрій",
"HeaderLatestEpisodes": "Нещодавно переглянуті епізоди",
"HeaderLatestMedia": "Нещодавно переглянуті",
"HeaderLatestMovies": "Нещодавні фільми",
"HeaderLatestMusic": "Остання музика",
"HeaderLatestEpisodes": "Нещодавно додані серії",
"HeaderLatestMedia": "Нещодавно додані медіа",
"HeaderLatestMovies": "Нещодавно додані фільми",
"HeaderLatestMusic": "Нещодавно додана музика",
"HeaderSeasons": "Сезони",
"HeaderTracks": "Доріжки",
"HeaderUsers": "Користувачі",
@ -274,7 +274,7 @@
"DrmChannelsNotImported": "Канали з DRM не імпортуватимуться.",
"DisplayModeHelp": "Виберіть бажаний стиль макету інтерфейсу.",
"DisplayMissingEpisodesWithinSeasonsHelp": "Також, це має бути включено для ТВ-медіатек у конфігурації сервера.",
"DisplayInOtherHomeScreenSections": "Показувати на головному екрані такі розділи як \"Останні медіа\" і \"Продовження перегляду\"",
"DisplayInOtherHomeScreenSections": "Відображення в розділах головного екрана, таких як «Нещодавно додані медіа» та «Продовжити перегляд»",
"DeleteDevicesConfirmation": "Ви впевнені, що хочете видалити всі пристрої? Усі інші сеанси будуть завершені. Пристрої знову з’являться, після того як користувач увійде в систему.",
"DeleteAll": "Видалити все",
"Data": "Дані",
@ -351,7 +351,7 @@
"EnablePhotosHelp": "Зображення будуть виявлені та відображені разом з іншими медіафайлами.",
"EnableNextVideoInfoOverlayHelp": "Наприкінці відео відображати інформацію про наступне відео у поточному списку відтворення.",
"EnableNextVideoInfoOverlay": "Показувати інформацію про наступне відео під час відтворення",
"EnableFasterAnimationsHelp": "Використовуйте швидші анімації та переходи.",
"EnableFasterAnimationsHelp": "Використовувати швидші анімації та переходи.",
"EnableFasterAnimations": "Прискорена анімація",
"EnableExternalVideoPlayersHelp": "Меню зовнішнього плеєра буде показано під час запуску відтворення відео.",
"LabelCollection": "Добірка:",
@ -382,7 +382,7 @@
"LabelAlbumArtMaxHeight": "Максимальна висота зображення альбому:",
"LabelAlbum": "Альбом:",
"ErrorDeletingItem": "Сталася помилка під час видалення елемента з сервера. Перевірте, що Jellyfin має доступ до папки з медіа, та спробуйте ще раз.",
"ErrorAddingXmlTvFile": "Сталася помилка під час доступу к XMLTV файлу. Переконайтесь, що файл існує, та спробуйте ще раз.",
"ErrorAddingXmlTvFile": "Сталася помилка під час доступу до XMLTV файлу. Переконайтесь, що файл існує, та спробуйте ще раз.",
"ErrorAddingTunerDevice": "Сталася помилка під час додавання тюнера. Переконайтесь, що пристрій доступний, та спробуйте ще раз.",
"ErrorAddingMediaPathToVirtualFolder": "Сталася помилка під чам додавання шляха медіа. Переконайтесь, що шлях вірний, та Jellyfin має до нього доступ.",
"EncoderPresetHelp": "Виберіть більше значення, щоб покращити швидкість, або менше, щоб поліпшити якість.",
@ -467,7 +467,7 @@
"Guide": "Посібник",
"FFmpegSavePathNotFound": "Неможливо знайти FFmpeg в відомих системних директоріях. Додаток FFprobe також потрібен для роботи і мусить знаходитись в тій самій директорії. Ці компоненти зазвичай постачаються разом. Будь ласка перевірте шлях до них.",
"ErrorStartHourGreaterThanEnd": "Час закінчення має бути більшим за час початку.",
"ErrorGettingTvLineups": "Сталася помилка під час завантаження списку телеканалів. Будь ласка перевірте корректність інформації та спробуйте ще раз.",
"ErrorGettingTvLineups": "Сталася помилка під час завантаження списку телеканалів. Будь ласка перевірте коректність інформації та спробуйте ще раз.",
"LabelLogs": "Журнали:",
"LabelOptionalNetworkPathHelp": "Якщо ця папка є спільною у вашій мережі, надання шляхів спільного доступу до мережі може дозволити клієнтам на інших пристроях отримувати прямий доступ до медіафайлів. Наприклад, {0} або {1}.",
"LabelOptionalNetworkPath": "Спільна мережева тека:",
@ -494,7 +494,7 @@
"LabelMinResumeDurationHelp": "Найкоротша тривалість відео в секундах, з збереженням місця продовження перегляду.",
"LabelMinResumeDuration": "Мінімальна відрізок для відновлення:",
"LabelMetadataDownloadLanguage": "Бажана мова завантаження:",
"LabelMetadataDownloadersHelp": "Увімкніть та ранжуйте бажані завантажувачі метаданих у порядку їх пріоритетності. Завантажувачі нижчого пріоритету будуть використовуватися лише для заповнення відсутньої інформації.",
"LabelMetadataDownloadersHelp": "Увімкнути та ранжувати бажані завантажувачі метаданих у порядку їх пріоритетності. Завантажувачі нижчого пріоритету будуть використовуватися лише для заповнення відсутньої інформації.",
"LabelMetadata": "Метадані:",
"LabelMessageTitle": "Назва повідомлення:",
"LabelMessageText": "Текст повідомлення:",
@ -514,7 +514,7 @@
"LabelManufacturer": "Виробник:",
"LabelLoginDisclaimerHelp": "Повідомлення, яке відображатиметься внизу сторінки для входу.",
"LabelLoginDisclaimer": "Відмова від відповідальності:",
"LabelLockItemToPreventChanges": "Заблокуйте цей елемент, щоб запобігти майбутнім змінам",
"LabelLockItemToPreventChanges": "Заблокувати цей елемент, щоб запобігти майбутнім змінам",
"LabelLocalHttpServerPortNumberHelp": "Номер порту TCP для сервера HTTP.",
"LabelLocalHttpServerPortNumber": "Номер локального порту HTTP:",
"LabelLineup": "Склад:",
@ -535,11 +535,11 @@
"LabelKeepUpTo": "Дотримуйтесь до:",
"LabelIsForced": "Примусово",
"LabelInternetQuality": "Якість в Інтернет:",
"LabelInNetworkSignInWithEasyPasswordHelp": "Використовуйте простий PIN-код для входу з клієнтів у вашій локальній мережі. Ваш звичайний пароль знадобиться лише далеко від дому. Якщо PIN-код залишити порожнім, вам не знадобиться пароль у вашій домашній мережі.",
"LabelInNetworkSignInWithEasyPasswordHelp": "Використовувати простий PIN-код для входу з клієнтів у вашій локальній мережі. Ваш звичайний пароль знадобиться лише далеко від дому. Якщо PIN-код залишити порожнім, вам не знадобиться пароль у вашій домашній мережі.",
"LabelInNetworkSignInWithEasyPassword": "Увімкнути вхід у мережу за допомогою мого простого PIN-коду",
"LabelImportOnlyFavoriteChannels": "Обмежити до каналів, позначених як обрані",
"LabelImageType": "Тип зображення:",
"LabelImageFetchersHelp": "Увімкніть та ранжируйте вибрані програми збору зображень у порядку пріоритету.",
"LabelImageFetchersHelp": "Увімкнути та ранжувати вибрані програми збору зображень у порядку пріоритету.",
"LabelIdentificationFieldHelp": "Підрядок або регулярний вираз, що не чутливий до регістру.",
"LabelIconMaxWidth": "Максимальна ширина значка:",
"LabelCreateHttpPortMap": "Увімкніть автоматичне зіставлення портів для трафіку HTTP, а також HTTPS.",
@ -583,7 +583,7 @@
"Identify": "Ідентифікувати",
"Horizontal": "Горизонтально",
"Home": "Головна",
"HideWatchedContentFromLatestMedia": "Приховати переглянуте з останніх медіа",
"HideWatchedContentFromLatestMedia": "Приховати переглянутий вміст із «Нещодавно доданих медіа»",
"Hide": "Приховати",
"Help": "Допомога",
"HeaderYears": "Роки",
@ -684,8 +684,8 @@
"LanNetworksHelp": "Список IP -адрес або записів IP/маски мережі, розділених комами, для мереж, які будуть враховуватися у локальній мережі під час застосування обмежень пропускної здатності. Якщо встановлено, усі інші IP -адреси вважатимуться зовнішніми мережами і на них поширюватимуться обмеження зовнішньої пропускної здатності. Якщо залишити це поле пустим, у локальній мережі вважається лише підмережа сервера.",
"LabelTranscodingThreadCountHelp": "Виберіть максимальну кількість потоків для використання при перекодуванні. Зменшення кількості потоків знизить використання процесора, але може перетворити його недостатньо швидко для плавного відтворення.",
"LabelTonemappingThresholdHelp": "Параметри алгоритму тонального відображення налаштовуються для кожної сцени. Поріг використовується для визначення того, змінилася сцена чи ні. Якщо відстань між поточною середньою яскравістю кадру та поточною середньою частотою перевищує порогове значення, ми б повторно обчислили середню сцену та пікову яскравість. Рекомендовані та стандартні значення - 0,8 та 0,2.",
"LabelTonemappingDesatHelp": "Застосовуйте десатурацію для світлих тонів, які перевищують цей рівень яскравості. Чим вище параметр, тим більше інформації про колір буде збережено. Це налаштування допомагає запобігти неприродним стиранням кольорів для надсвітків, шляхом (плавного) перетворення на білий. Це робить зображення більш природними, за рахунок зменшення інформації про кольори, що виходять за межі діапазону. Рекомендовані та стандартні значення - 0 та 0,5.",
"LabelSelectFolderGroups": "Автоматично групуйте вміст із таких папок у види, такі як Фільми, Музика та ТБ:",
"LabelTonemappingDesatHelp": "Застосувати десатурацію для світлих тонів, які перевищують цей рівень яскравості. Чим вище параметр, тим більше інформації про колір буде збережено. Це налаштування допомагає запобігти неприродним стиранням кольорів для надсвітків, шляхом (плавного) перетворення на білий. Це робить зображення більш природними, за рахунок зменшення інформації про кольори, що виходять за межі діапазону. Рекомендовані та стандартні значення - 0 та 0,5.",
"LabelSelectFolderGroups": "Автоматично групувати вміст із таких папок у види, такі як Фільми, Музика та ТБ:",
"LabelSaveLocalMetadataHelp": "Збереження творів мистецтва в папках для медіа помістить їх у місце, де їх можна легко редагувати.",
"LabelRequireHttpsHelp": "Якщо цей прапорець встановлено, сервер автоматично перенаправлятиме всі запити через HTTP на HTTPS. Це не впливає, якщо сервер не прослуховує протокол HTTPS.",
"LabelRepositoryNameHelp": "Спеціальна назва, щоб відрізняти це сховище від будь -яких інших, доданих на ваш сервер.",
@ -723,10 +723,10 @@
"HeaderLibraryAccess": "Доступ до медіатеки",
"HeaderLibraryFolders": "Папки медіатеки",
"HeaderLibraryOrder": "Порядок медіатек",
"HeaderLatestRecordings": "Останні записи",
"HeaderLatestRecordings": "Нещодавно додані записи",
"HeaderKodiMetadataHelp": "Щоб увімкнути або вимкнути метадані NFO, відкрийте меню редагування медіатеки та знайдіть розділ \"Збереження метаданих\".",
"HeaderKeepSeries": "Зберегти серіал",
"HeaderKeepRecording": "Продовжуйте записувати",
"HeaderKeepRecording": "Продовжувати записувати",
"HeaderInstantMix": "Миттєвий мікс",
"HeaderInstall": "Встановити",
"HeaderImageSettings": "Налаштування зображення",
@ -778,7 +778,7 @@
"Large": "Більший",
"LabelHDHomerunPortRangeHelp": "Обмежує діапазон портів UDP HD-HomeRun до цього значення. (За замовчуванням 1024 - 65535).",
"HeaderSelectServerCachePathHelp": "Перегляньте або введіть шлях для файлів кешу сервера. Тека має бути з дозволом запису.",
"LabelSyncPlaySettingsExtraTimeOffsetHelp": "Вручну налаштуйте зсув часу (в мілісекундах) з вибраним пристроєм для синхронізації часу. Налаштуйте обережно.",
"LabelSyncPlaySettingsExtraTimeOffsetHelp": "Ручне налаштування зсуву часу (в мілісекундах) з вибраним пристроєм для синхронізації часу. Налаштовуйте обережно.",
"LabelLocalCustomCss": "Спеціальний CSS-код для стилю, який стосується лише цього клієнта. Ви можете вимкнути користувацький CSS-код сервера.",
"LabelMaxAudiobookResumeHelp": "Назви вважаються повністю відтвореними, якщо їх зупинити, коли тривалість, що залишилася, менша за це значення.",
"LabelLibraryPageSizeHelp": "Встановлює кількість елементів для показу на сторінці медіатеки. Встановіть 0, щоб вимкнути підкачування сторінок.",
@ -797,7 +797,7 @@
"LabelH265Crf": "H.265, що кодує CRF:",
"LabelH264Crf": "H.264, що кодує CRF:",
"LabelGroupMoviesIntoCollectionsHelp": "Під час відображення списків фільмів фільми в добірці відображатимуться як один згрупований елемент.",
"LabelGroupMoviesIntoCollections": "Групуйте фільми у добірки",
"LabelGroupMoviesIntoCollections": "Групувати фільми у добірки",
"LabelFriendlyName": "Спрощене ім'я:",
"LabelFormat": "Формат:",
"LabelForgotPasswordUsernameHelp": "Введіть своє ім’я користувача, якщо ви його пам’ятаєте.",
@ -808,7 +808,7 @@
"LabelffmpegPathHelp": "Шлях до файлу або папки програми FFmpeg, що містить FFmpeg.",
"LabelffmpegPath": "Шлях FFmpeg:",
"LabelFailed": "Не вдалося",
"LabelExtractChaptersDuringLibraryScan": "Витягуйте зображення розділів під час сканування медіатеки",
"LabelExtractChaptersDuringLibraryScan": "Витягувати зображення розділів під час сканування медіатеки",
"LabelEvent": "Подія:",
"LabelEveryXMinutes": "Кожен:",
"LabelEpisodeNumber": "Номер епізоду:",
@ -829,7 +829,7 @@
"LabelEnableHardwareDecodingFor": "Увімкнути апаратне декодування для:",
"LabelEnableDlnaServerHelp": "Дозволяє пристроям UPnP у вашій мережі переглядати та відтворювати вміст.",
"LabelEnableDlnaServer": "Увімкнути сервер DLNA",
"LabelEnableDlnaPlayToHelp": "Виявляйте пристрої у вашій мережі та пропонуйте можливість керувати ними віддалено.",
"LabelEnableDlnaPlayToHelp": "Виявляти пристрої у вашій мережі та пропонувати можливість керувати ними віддалено.",
"LabelEnableDlnaPlayTo": "Увімкніть функцію DLNA \"Play To\"",
"LabelEnableDlnaDebugLoggingHelp": "Створює великі файли журналу, і їх слід використовувати лише за потреби для усунення несправностей.",
"LabelEnableDlnaDebugLogging": "Увімкнути запис дебагу DLNA",
@ -849,7 +849,7 @@
"LabelDropImageHere": "Перетягніть зображення сюди або натисніть, щоб переглянути.",
"LabelDownMixAudioScale": "Підсилення звуку під час мікшування:",
"LabelDownloadLanguages": "Завантажити мови:",
"LabelDisplaySpecialsWithinSeasons": "Показуйте спеціальні пропозиції протягом сезонів, в яких вони виходили в етер",
"LabelDisplaySpecialsWithinSeasons": "Показувати спеціальні пропозиції протягом сезонів, в яких вони виходили в етер",
"LabelDisplayOrder": "Порядок відображення:",
"LabelDisplayName": "Відображуване ім'я:",
"LabelDisplayMode": "Режим відображення:",
@ -868,7 +868,7 @@
"LabelDateAdded": "Дата додання:",
"LabelDashboardTheme": "Тема інфопанелі сервера:",
"LabelCustomRating": "Спеціальний рейтинг:",
"LabelCustomCssHelp": "Застосуйте свій власний код CSS для створення тем/брендингу у веб-інтерфейсі.",
"LabelCustomCssHelp": "Застосувати свій власний код CSS для створення тем/брендингу у веб-інтерфейсі.",
"LabelCustomDeviceDisplayNameHelp": "Введіть спеціальне відображуване ім'я або залиште поле порожнім, щоб використовувати ім'я, повідомлене пристроєм.",
"LabelCustomCss": "Кастомний CSS-код:",
"LabelCustomCertificatePathHelp": "Шлях до файлу PKCS #12, що містить сертифікат та приватний ключ, щоб увімкнути підтримку TLS у користувацькому домені.",
@ -909,7 +909,7 @@
"LibraryAccessHelp": "Виберіть медіатеки, якими хочете поділитися з цим користувачем. Адміністратори зможуть редагувати всі папки за допомогою менеджера метаданих.",
"LeaveBlankToNotSetAPassword": "Ви можете залишити це поле порожнім, щоб не встановлювати пароль.",
"LearnHowYouCanContribute": "Дізнайтеся, як ви можете зробити свій внесок.",
"LatestFromLibrary": "Нове в {0}",
"LatestFromLibrary": "Нещодавно додано в {0}",
"LastSeen": "Востаннє був {0}",
"Larger": "Більший",
"LabelZipCode": "Індекс:",
@ -960,7 +960,7 @@
"LabelTonemappingRange": "Діапазон тонального відображення:",
"LabelTonemappingPeakHelp": "Замінити сигнал/номінальний/еталонний пік за допомогою цього значення. Корисно, коли вбудована інформація про піки в метаданих дисплея не є надійною або коли тонове відображення з нижчого діапазону в більш високий діапазон. Рекомендовані значення і значення за замовчуванням 100 і 0.",
"LabelTonemappingPeak": "Пік тонального відображення:",
"LabelTonemappingParamHelp": "Налаштуйте алгоритм тонального відображення. Рекомендованим і стандартним значенням є NaN. Зазвичай залиште його порожнім.",
"LabelTonemappingParamHelp": "Налаштувати алгоритм тонального відображення. Рекомендованим і стандартним значенням є NaN. Зазвичай залишайте його порожнім.",
"LabelTonemappingParam": "Параметр тонального відображення:",
"LabelTonemappingDesat": "Відображення тональних даних:",
"LabelTonemappingAlgorithm": "Виберіть алгоритм тонального відображення для використання:",
@ -999,7 +999,7 @@
"LabelSyncPlayNewGroup": "Нова група",
"LabelSyncPlayLeaveGroupDescription": "Вимкніть SyncPlay",
"LabelSyncPlayLeaveGroup": "Покинути групу",
"LabelSyncPlayHaltPlaybackDescription": "І ігноруйте поточні оновлення списку відтворення",
"LabelSyncPlayHaltPlaybackDescription": "Та ігнорувати поточні оновлення списку відтворення",
"LabelSyncPlayHaltPlayback": "Зупинити локальне відтворення",
"LabelSyncPlayAccessNone": "Вимкнено для цього користувача",
"LabelSyncPlayAccessJoinGroups": "Дозволити користувачам приєднуватися до груп",
@ -1028,7 +1028,7 @@
"LabelSonyAggregationFlagsHelp": "Визначте вміст елемента 'aggregationFlags' в просторі імен 'urn:schemas-sonycom:av'.",
"LabelSonyAggregationFlags": "Прапори агрегації Sony:",
"LabelSlowResponseTime": "Час у мс, після якого відповідь вважається повільною:",
"LabelSlowResponseEnabled": "Зареєструйте попередження, якщо сервер повільно відповідає",
"LabelSlowResponseEnabled": "Зареєструвати попередження, якщо сервер повільно відповідає",
"LabelSkipIfGraphicalSubsPresentHelp": "Збереження текстових версій субтитрів призведе до ефективнішої доставки та зменшить ймовірність перекодування відео.",
"LabelSkipIfGraphicalSubsPresent": "Пропустити, якщо відео вже містить вбудовані субтитри",
"LabelSkipIfAudioTrackPresentHelp": "Зніміть прапорець, щоб переконатися, що всі відео мають субтитри, незалежно від мови аудіо.",
@ -1049,7 +1049,7 @@
"LabelSelectFolderGroupsHelp": "Папки, для яких не встановлено прапорець, відображатимуться самі по собі у власному поданні.",
"LabelSeasonNumber": "Номер сезону:",
"LabelScreensaver": "Заставка:",
"LabelScheduledTaskLastRan": "Останній раз запускалося: {0}, час виконання: {1}.",
"LabelScheduledTaskLastRan": "Останній запуск: {0}, час виконання: {1}.",
"LabelSaveLocalMetadata": "Збережіть ілюстрацію в медіа-папках",
"LabelRuntimeMinutes": "Час виконання:",
"LabelRequireHttps": "Вимагати HTTPS",
@ -1077,7 +1077,7 @@
"LabelProfileAudioCodecs": "Аудіокодеки:",
"LabelPreferredSubtitleLanguage": "Бажана мова субтитрів:",
"LabelPreferredDisplayLanguage": "Бажана мова відображення:",
"LabelPostProcessorArgumentsHelp": "Використовуйте {path} як шлях до файлу запису.",
"LabelPostProcessorArgumentsHelp": "Використовувати {path} як шлях до файлу запису.",
"LabelPostProcessorArguments": "Аргументи командного рядка постпроцесора:",
"LabelPostProcessor": "Додаток для постобробки:",
"LabelPleaseRestart": "Зміни набудуть чинності після ручного перезавантаження веб-клієнта.",
@ -1250,7 +1250,7 @@
"Premiere": "Прем'єра",
"PreferEmbeddedTitlesOverFileNamesHelp": "Визначте заголовок відображення, який використовуватиметься, коли немає доступних Інтернет-метаданих або локальних метаданих.",
"PreferEmbeddedTitlesOverFileNames": "Віддавайте перевагу вбудованим заголовкам над іменами файлів",
"PreferEmbeddedEpisodeInfosOverFileNamesHelp": "Використовуйте інформацію про епізод із вбудованих метаданих, якщо є.",
"PreferEmbeddedEpisodeInfosOverFileNamesHelp": "Використовувати інформацію про епізод із вбудованих метаданих, якщо є.",
"PreferEmbeddedEpisodeInfosOverFileNames": "Віддавайте перевагу вбудованій інформації про епізоди над іменами файлів",
"PosterCard": "Картка постеру",
"Poster": "Постер",
@ -1284,13 +1284,13 @@
"PackageInstallFailed": "Помилка встановлення {0} (версія {1}).",
"PackageInstallCompleted": "Установлення {0} (версія {1}) завершено.",
"PackageInstallCancelled": "Установлення {0} (версія {1}) скасовано.",
"OtherArtist": "Інший художник",
"OtherArtist": "Інший виконавець",
"OriginalAirDateValue": "Початкова дата ефіру: {0}",
"OptionWakeFromSleep": "Пробудити",
"OptionUnairedEpisode": "Невипущені епізоди",
"OptionSpecialEpisode": "Спец",
"OptionResumable": "Відновлюється",
"OptionRequirePerfectSubtitleMatch": "Завантажуйте лише субтитри, які ідеально підходять для відеофайлів",
"OptionRequirePerfectSubtitleMatch": "Завантажувати лише субтитри, які ідеально підходять для відеофайлів",
"OptionReportByteRangeSeekingWhenTranscodingHelp": "Це потрібно для деяких пристроїв, які не дуже швидко шукають.",
"OptionReportByteRangeSeekingWhenTranscoding": "Повідомте, що сервер підтримує пошук байтів під час перекодування",
"OptionReleaseDate": "Дата випуску",
@ -1329,7 +1329,7 @@
"OptionEnableM2tsMode": "Увімкнути режим M2TS",
"OptionEnableForAllTuners": "Увімкнути для всіх пристроїв тюнера",
"OptionEnableExternalContentInSuggestionsHelp": "Дозволити включати інтернет-трейлери та телепрограми в прямому ефірі до запропонованого вмісту.",
"OptionCaptionInfoExSamsung": "CaptionInfoEx (Samsung)",
"OptionCaptionInfoExSamsung": "Функція CaptionInfoEx (Samsung)",
"OptionEnableExternalContentInSuggestions": "Увімкнути зовнішній вміст у пропозиціях",
"OptionEnableAccessToAllLibraries": "Увімкнути доступ до всіх медіатек",
"OptionEnableAccessToAllChannels": "Увімкнути доступ до всіх каналів",
@ -1339,8 +1339,8 @@
"OptionDisableUserHelp": "Сервер не дозволить жодних з'єднань від цього користувача. Існуючі з’єднання будуть раптово обірвані.",
"OptionDisableUser": "Вимкнути цього користувача",
"OptionDatePlayed": "Дата відтворення",
"OptionDateAddedImportTime": "Використовуйте дату відсканування в медіатеку",
"OptionDateAddedFileTime": "Використовуйте дату створення файлу",
"OptionDateAddedImportTime": "Використовувати дату відсканування в медіатеку",
"OptionDateAddedFileTime": "Використовувати дату створення файлу",
"OptionDateAdded": "Дата додавання",
"OptionDaily": "Кожен день",
"OptionCustomUsers": "Користувацький",
@ -1422,7 +1422,7 @@
"TabMyPlugins": "Мої плагіни",
"TabMusic": "Музика",
"TabLogs": "Журнали",
"TabLatest": "Останні",
"TabLatest": "Нещодавно додані",
"TabDashboard": "Панель",
"TabContainers": "Контейнери",
"TabCodecs": "Кодеки",
@ -1439,7 +1439,7 @@
"SubtitleDownloadersHelp": "Увімкніть та оцініть бажані завантажувачі субтитрів у порядку пріоритету.",
"SubtitleAppearanceSettingsDisclaimer": "Наведені нижче налаштування не застосовуються до графічних субтитрів, згаданих вище, або субтитрів ASS/SSA, які вбудовують власні стилі.",
"SubtitleAppearanceSettingsAlsoPassedToCastDevices": "Ці налаштування також застосовуються до будь-якого відтворення Google Cast, запущеного цим пристроєм.",
"Subtitle": "Підзаголовок",
"Subtitle": "Субтитри",
"Studios": "Студії",
"StopRecording": "Зупинити запис",
"StopPlayback": "Зупинити відтворення",
@ -1453,7 +1453,7 @@
"Smaller": "Менший",
"SmallCaps": "Маленькі літери",
"SkipEpisodesAlreadyInMyLibraryHelp": "Епізоди порівнюватимуться з використанням номерів сезонів та епізодів, якщо вони доступні.",
"SkipEpisodesAlreadyInMyLibrary": "Не записуйте епізоди, які вже є в моїй медіатеці",
"SkipEpisodesAlreadyInMyLibrary": "Не записувати епізоди, які вже є в моїй медіатеці",
"SimultaneousConnectionLimitHelp": "Максимальна кількість дозволених одночасних потоків. Введіть 0 без обмежень.",
"Shuffle": "Перемішати",
"ShowMore": "Показати більше",
@ -1470,7 +1470,7 @@
"SeriesYearToPresent": "{0} понині",
"SeriesSettings": "Параметри серіалу",
"SeriesRecordingScheduled": "Планується запис серіалу.",
"SeriesDisplayOrderHelp": "Упорядковуйте епізоди за датою ефіру, порядком DVD або абсолютною нумерацією.",
"SeriesDisplayOrderHelp": "Упорядковувати епізоди за датою ефіру, порядком DVD або абсолютною нумерацією.",
"SeriesCancelled": "Серіал скасовано.",
"Series": "Серіал",
"SendMessage": "Відправити повідомлення",
@ -1518,7 +1518,7 @@
"SubtitleCodecNotSupported": "Кодек субтитрів не підтримується",
"ContainerNotSupported": "Контейнер не підтримується",
"AudioCodecNotSupported": "Аудіокодек не підтримується",
"EnableGamepadHelp": "Слухайте вхід з будь-яких підключених контролерів.",
"EnableGamepadHelp": "Очікувати вхідних даних від будь-яких підключених контролерів. (Вимагається: режим відображення «TV»)",
"LabelEnableGamepad": "Увімкнути геймпад",
"Controls": "Елементи керування",
"AllowVppTonemappingHelp": "Повне відображення тонів на основі драйверів Intel. Наразі працює лише на певному обладнанні з відео HDR10. Це має вищий пріоритет порівняно з іншою реалізацією OpenCL.",
@ -1559,8 +1559,8 @@
"XmlTvMovieCategoriesHelp": "Програми з цими категоріями відображатимуться як фільми. Розділіть множинні символом \"|\".",
"XmlTvKidsCategoriesHelp": "Програми з цими категоріями відображатимуться як програми для дітей. Розділіть множинні символом \"|\".",
"XmlDocumentAttributeListHelp": "Ці атрибути застосовуються до кореневого елемента кожної відповіді XML.",
"Writers": "Письменники",
"Writer": "Письменник",
"Writers": "Сценаристи",
"Writer": "Сценарист",
"WizardCompleted": "Це все, що нам зараз потрібно. Jellyfin почав збирати інформацію про вашу медіатеку. Перегляньте деякі з наших програм, а потім натисніть <b>Готово</b>, щоб переглянути <b>інформаційну панель</b>.",
"Whitelist": "Білий список",
"WelcomeToProject": "Ласкаво просимо до Jellyfin!",
@ -1583,7 +1583,7 @@
"UserProfilesIntro": "Jellyfin включає підтримку профілів користувачів із детальними налаштуваннями відображення, станом відтворення та батьківським контролем.",
"UserAgentHelp": "Надайте спеціальний HTTP-заголовок «User-Agent».",
"UseEpisodeImagesInNextUpHelp": "Розділи «Далі» та «Продовжити перегляд» використовуватимуть зображення епізодів як ескізи замість основного ескізу шоу.",
"UseEpisodeImagesInNextUp": "Використовуйте зображення епізодів у розділах «Далі» та «Продовжити перегляд»",
"UseEpisodeImagesInNextUp": "Використовувати зображення епізодів у розділах «Далі» та «Продовжити перегляд»",
"UseDoubleRateDeinterlacing": "Подвоїте частоту кадрів під час деінтерлейсу",
"Upload": "Завантажити",
"Up": "Вгору",
@ -1685,5 +1685,31 @@
"MessageNoFavoritesAvailable": "Зараз немає доступних улюблених.",
"Experimental": "Експериментальний",
"LabelStereoDownmixAlgorithm": "Stereo Downmix алгоритм",
"StereoDownmixAlgorithmHelp": "Алгоритм мікшування багатоканального аудіо у стерео."
"StereoDownmixAlgorithmHelp": "Алгоритм мікшування багатоканального аудіо у стерео.",
"LabelChapterImageResolutionHelp": "Роздільна здатність витягнутих зображень розділу.",
"PreferEmbeddedExtrasTitlesOverFileNames": "Віддавайте перевагу вбудованим назвам, а не назвам файлів для додаткових функцій",
"PreferEmbeddedExtrasTitlesOverFileNamesHelp": "Додатки часто мають таке ж вбудоване ім’я, що й батьківське, позначте це, щоб усе одно використовувати для них вбудовані заголовки.",
"ResolutionMatchSource": "Джерело відповідності",
"SaveRecordingNFO": "Збережіть метадані EPG запису в NFO",
"SaveRecordingNFOHelp": "Зберігайте метадані від постачальника списків EPG разом із бічними носіями.",
"SaveRecordingImages": "Зберегти записані зображення EPG",
"SaveRecordingImagesHelp": "Зберігайте зображення з постачальника списків EPG разом із носієм.",
"HeaderDummyChapter": "Зображення розділів",
"LabelDummyChapterDuration": "Інтервал:",
"LabelDummyChapterDurationHelp": "Інтервал вилучення зображення розділу в секундах.",
"LabelDummyChapterCount": "Ліміт:",
"LabelDummyChapterCountHelp": "Максимальна кількість зображень розділів, які буде видобуто для кожного медіафайлу.",
"LabelChapterImageResolution": "Роздільна здатність:",
"HeaderRecordingMetadataSaving": "Метадані запису",
"SubtitleBlack": "Чорний",
"SubtitleBlue": "Синій",
"SubtitleCyan": "Блакитний",
"SubtitleGray": "Сірий",
"SubtitleLightGray": "Світло-сірий",
"SubtitleMagenta": "Пурпуровий",
"SubtitleRed": "Червоний",
"SubtitleWhite": "Білий",
"SubtitleYellow": "Жовтий",
"SecondarySubtitles": "Додаткові субтитри",
"SubtitleGreen": "Зелений"
}

View File

@ -14,20 +14,20 @@
"FileNotFound": "Không tìm thấy tệp tin.",
"FileReadCancelled": "Tệp đọc đã bị hủy.",
"FileReadError": "Có một lỗi xảy ra khi đọc tệp tin này.",
"HeaderCustomDlnaProfiles": "Hồ sơ khách hàng",
"HeaderCustomDlnaProfiles": "Cấu Hình Tùy Chỉnh",
"HeaderFeatureAccess": "Truy cập tính năng:",
"HeaderFrequentlyPlayed": "Phát thường xuyên",
"HeaderLatestEpisodes": "Tập Phim Thêm Gần Đây",
"HeaderLatestMovies": "Phim Thêm Gần Đây",
"HeaderRecentlyPlayed": "Phát gần đây",
"HeaderStatus": "Trạng thái",
"HeaderSystemDlnaProfiles": "Hồ sơ hệ thống",
"HeaderSystemDlnaProfiles": "Cấu Hình Hệ Thống",
"HeaderUsers": "Người dùng",
"LabelAudioLanguagePreference": "Ngôn ngữ thoại ưa thích:",
"LabelCountry": "Quốc gia:",
"LabelCurrentPassword": "Mật khẩu hiện tại:",
"LabelDay": "Ngày trong tuần:",
"LabelEnableDlnaPlayTo": "Bật tính năng 'Phát tới' DLNA",
"LabelEnableDlnaPlayTo": "Bật tính năng 'Phát Với' DLNA",
"LabelEvent": "Sự kiện:",
"LabelFinish": "Xong",
"LabelLanguage": "Ngôn ngữ:",
@ -175,7 +175,7 @@
"DeathDateValue": "Đã chết: {0}",
"DatePlayed": "Ngày phát",
"DateAdded": "Ngày thêm",
"CustomDlnaProfilesHelp": "Tạo một bộ thiết lập tuỳ chọn dành cho một thiết bị mới hoặc thay thế một thiết lập hệ thống.",
"CustomDlnaProfilesHelp": "Tạo cấu hình tùy chỉnh nhắm đến thiết bị mới hoặc ghi đè cấu hình hệ thống.",
"CriticRating": "Đánh giá của nhà phê bình",
"CopyStreamURLSuccess": "Đã sao chép URL thành công.",
"CopyStreamURL": "Sao chép URL luồng phát",
@ -254,7 +254,7 @@
"HeaderDateIssued": "Ngày Phát Hành",
"HeaderContinueWatching": "Xem Tiếp",
"HeaderContinueListening": "Tiếp Tục Nghe",
"HeaderCodecProfileHelp": "Hồ sơ mã hóa chỉ ra những kiểu mã hoá nhất định mà một thiết bị có thể phát. Nếu một nội dung không thể phát, nó sẽ được chuyển mã, thậm chí nếu kiểu mã hoá đó được cấu hình để phát lại trực tiếp.",
"HeaderCodecProfileHelp": "Cấu hình mã hóa cho biết các giới hạn của thiết bị khi phát các bộ mã hóa. Nếu giới hạn được áp dụng thì phương tiện sẽ được chuyển mã, ngay cả khi bộ mã hóa được cấu hình để phát lại trực tiếp.",
"HeaderContainerProfileHelp": "Cấu hình vùng chứa cho biết các giới hạn của thiết bị khi phát các định dạng cụ thể. Nếu giới hạn được áp dụng thì phương tiện sẽ được chuyển mã, ngay cả khi định dạng được định cấu hình để phát lại trực tiếp.",
"HeaderContainerProfile": "Hồ Sơ Định Dạng",
"HeaderConnectionFailure": "Kế Nối Thất Bại",
@ -452,9 +452,9 @@
"HeaderTracks": "Bản ghi",
"HeaderThisUserIsCurrentlyDisabled": "Người dùng này hiện tại đang bị khoá",
"HeaderTaskTriggers": "Kích Hoạt Tác Vụ",
"HeaderSubtitleProfilesHelp": "Hồ sơ phụ đề chỉ ra những định dạng phụ đề được hỗ trợ bởi thiết bị phát.",
"HeaderSubtitleProfiles": "Hồ Sơ Phụ Đề",
"HeaderSubtitleProfile": "Hồ Sơ Phụ Đề",
"HeaderSubtitleProfilesHelp": "Cấu hình phụ đề chỉ ra những định dạng phụ đề được hỗ trợ bởi thiết bị phát.",
"HeaderSubtitleProfiles": "Cấu Hình Phụ Đề",
"HeaderSubtitleProfile": "Cấu Hình Phụ Đề",
"HeaderSubtitleDownloads": "Tải Phụ Đề",
"HeaderSubtitleAppearance": "Giao Diện Phụ Đề",
"HeaderStopRecording": "Ngừng Ghi Hình/Ghi Âm",
@ -503,7 +503,7 @@
"LabelAlbumArtPN": "Bìa Tuyển Tập PN:",
"LabelAlbumArtMaxWidth": "Chiều rộng tối đa bìa tuyển tập:",
"LabelAlbumArtMaxHeight": "Chiều cao tối đa bìa tuyển tập:",
"LabelAlbumArtHelp": "PN được sử dụng cho bìa tuyển tập, trong 'dlna:profileID' thuộc tính upnp:albumArtURI. Một vài thiết bị phát cần một giá trị đặc biệt, không ảnh hưởng đến kích thước của hình ảnh.",
"LabelAlbumArtHelp": "PN được dùng cho ảnh bìa album, trong thuộc tính 'dlna:profileID' trên 'upnp:albumArtURI'. Một số thiết bị yêu cầu một giá trị cụ thể, bất kể kích thước của hình ảnh.",
"LabelAlbum": "Tuyển Tập:",
"LabelAirsBeforeSeason": "Phát sóng trước phần:",
"LabelAirsBeforeEpisode": "Phát sóng trước tập:",
@ -544,8 +544,8 @@
"HeaderTypeImageFetchers": "Trình tìm nạp hình ảnh ({0}):",
"HeaderTuners": "Bộ Điều Khiển Thu Phát Sóng",
"HeaderTunerDevices": "Thiết Bị Dò",
"HeaderTranscodingProfileHelp": "Thêm hồ sơ chuyển mã để chỉ ra những định dạng nên dùng khi cần chuyển mã.",
"HeaderTranscodingProfile": "Hồ Sơ Chuyển Mã",
"HeaderTranscodingProfileHelp": "Thêm cấu hình chuyển mã để cho biết định dạng nào sẽ được sử dụng khi cần chuyển mã.",
"HeaderTranscodingProfile": "Cấu Hình Chuyển Mã",
"LabelEnableAutomaticPortMap": "Kích hoạt tính năng tự động kết nối các port",
"LabelEmbedAlbumArtDidlHelp": "Một số thiết bị thích cách này hơn để tải ảnh bìa album. Số khác có thể bị lỗi nếu tuỳ chọn này được bật.",
"LabelEmbedAlbumArtDidl": "Bìa tuyển tập trong DIDL",
@ -567,7 +567,7 @@
"LabelDidlMode": "Chế độ DIDL:",
"LabelDeviceDescription": "Mô tả thiết bị:",
"LabelDeinterlaceMethod": "Phương pháp khử xen kẽ:",
"LabelDefaultUserHelp": "Xác định thư viện người dùng sẽ hiển thị trên các thiết bị được kết nối. Tuỳ chọn này có thể được ghi đè trên hồ sơ của từng thiết bị.",
"LabelDefaultUserHelp": "Xác định thư viện người dùng sẽ hiển thị trên các thiết bị được kết nối. Điều này có thể được ghi đè trên cấu hình từng thiết bị.",
"LabelDefaultUser": "Người dùng mặc định:",
"LabelDefaultScreen": "Màn hình mặc định:",
"LabelDeathDate": "Ngày mất:",
@ -590,10 +590,10 @@
"LabelEnableHttps": "Bật HTTPS",
"LabelEnableHardwareDecodingFor": "Bật giải mã phần cứng cho:",
"LabelEnableDlnaServerHelp": "Cho phép các thiết bị UPnP trong mạng của bạn duyệt và phát nội dung.",
"LabelEnableDlnaServer": "Bật tính năng máy chủ DLNA",
"LabelEnableDlnaServer": "Bật máy chủ DLNA",
"LabelEnableDlnaPlayToHelp": "Phát hiện các thiết bị trong mạng của bạn và cung cấp khả năng điều khiển chúng từ xa.",
"LabelEnableDlnaDebugLoggingHelp": "Tạo tệp nhật ký lớn và chỉ nên dùng khi cần thiết để xử lý sự cố.",
"LabelEnableDlnaDebugLogging": "Bật tính năng gỡ lỗi DLNA",
"LabelEnableDlnaDebugLogging": "Bật ghi nhật ký gỡ lỗi DLNA",
"LabelEnableDlnaClientDiscoveryIntervalHelp": "Xác định thời gian tính bằng giây giữa hai lần tìm kiếm SSDP.",
"LabelEnableDlnaClientDiscoveryInterval": "Thời gian dò tìm máy khách:",
"LabelEnableBlastAliveMessagesHelp": "Bật cái này nếu máy chủ không được các thiết bị UPnP khác trên mạng của bạn tìm ra một cách đáng tin cậy.",
@ -837,7 +837,7 @@
"LabelProfileVideoCodecs": "Mã hóa video:",
"LabelProfileContainersHelp": "Phân cách bằng dấu phẩy. Để trống để áp dụng cho tất cả các định dạng.",
"LabelProfileContainer": "Định dạng:",
"LabelProfileCodecsHelp": "Phân cách bằng dấu phẩy. Điều này có thể được để trống để áp dụng cho tất cả các mã hóa.",
"LabelProfileCodecsHelp": "Phân cách bằng dấu phẩy. Có thể để trống để dùng tất cả các mã hóa.",
"LabelProfileCodecs": "Mã hóa:",
"LabelProfileAudioCodecs": "Mã hóa âm thanh:",
"LabelPreferredSubtitleLanguage": "Ngôn ngữ phụ đề ưu tiên:",
@ -1271,7 +1271,7 @@
"Transcoding": "Chuyển mã",
"Trailers": "Đoạn giới thiệu",
"TabAccess": "Truy cập",
"SystemDlnaProfilesHelp": "Cấu hình hệ thống ở chế độ chỉ đọc. Các thay đổi đối với cấu hình hệ thống sẽ được lưu vào cấu hình tùy chỉnh mới.",
"SystemDlnaProfilesHelp": "Cấu hình hệ thống ở chế độ chỉ đọc. Thay đổi cấu hình hệ thống sẽ được lưu vào cấu hình tùy chỉnh mới.",
"Sports": "Thể thao",
"SpecialFeatures": "Các tính năng đặc biệt",
"SortName": "Sắp xếp tên",
@ -1532,7 +1532,7 @@
"InterlacedVideoNotSupported": "Video xen kẽ không được hỗ trợ",
"AnamorphicVideoNotSupported": "Video Anamorphic không được hỗ trợ",
"AudioSampleRateNotSupported": "Tốc độ mẫu của âm thanh không được hỗ trợ",
"AudioProfileNotSupported": "Cấu hình của mã hóa âm thanh không được hỗ trợ",
"AudioProfileNotSupported": "Cấu hình mã hóa âm thanh không được hỗ trợ",
"VideoResolutionNotSupported": "Độ phân giải của video không được hỗ trợ",
"AudioChannelsNotSupported": "Số kênh âm thanh không được hỗ trợ",
"AudioBitrateNotSupported": "Tốc độ bit của âm thanh không được hỗ trợ",
@ -1695,5 +1695,15 @@
"PreferEmbeddedExtrasTitlesOverFileNames": "Ưu tiên tiêu đề được nhúng hơn tên tệp cho các tính năng bổ sung",
"PreferEmbeddedExtrasTitlesOverFileNamesHelp": "Phần bổ sung thường có cùng tên được nhúng với phần gốc, hãy kiểm tra điều này để sử dụng các tiêu đề được nhúng cho chúng.",
"HeaderDummyChapter": "Hình Ảnh Phân Đoạn",
"HeaderRecordingMetadataSaving": "Dữ Liệu Mô Tả Bản Ghi"
"HeaderRecordingMetadataSaving": "Dữ Liệu Mô Tả Bản Ghi",
"SubtitleYellow": "Vàng",
"SubtitleBlack": "Đen",
"SubtitleBlue": "Xanh lam",
"SubtitleCyan": "Lục lam",
"SubtitleGray": "Xám",
"SubtitleGreen": "Xanh lá",
"SubtitleLightGray": "Xám Nhạt",
"SubtitleMagenta": "Đỏ Sậm",
"SubtitleRed": "Đỏ",
"SubtitleWhite": "Trắng"
}

View File

@ -135,7 +135,7 @@
"Disconnect": "断开连接",
"Display": "显示",
"DisplayInMyMedia": "在主屏幕显示",
"DisplayInOtherHomeScreenSections": "在“新媒体”和“继续观看“等主屏幕模块中显示",
"DisplayInOtherHomeScreenSections": "在“媒体”和“继续观看“等主屏幕模块中显示",
"DisplayMissingEpisodesWithinSeasons": "显示每季里缺少的剧集",
"DisplayMissingEpisodesWithinSeasonsHelp": "必须在服务器的 TV 媒体库设置中也启用该功能。",
"DoNotRecord": "不录制",
@ -273,11 +273,11 @@
"HeaderInstall": "安装",
"HeaderInstantMix": "速成合辑",
"HeaderKodiMetadataHelp": "要启用或禁用 NFO 元数据,请编辑库并找到“元数据保护程序”部分。",
"HeaderLatestEpisodes": "新剧集",
"HeaderLatestMedia": "新媒体",
"HeaderLatestMovies": "新电影",
"HeaderLatestMusic": "新音乐",
"HeaderLatestRecordings": "新录制的节目",
"HeaderLatestEpisodes": "剧集",
"HeaderLatestMedia": "媒体",
"HeaderLatestMovies": "电影",
"HeaderLatestMusic": "音乐",
"HeaderLatestRecordings": "录制",
"HeaderLibraries": "媒体库",
"HeaderLibraryAccess": "媒体库访问",
"HeaderLibraryFolders": "媒体文件夹",
@ -368,7 +368,7 @@
"HeaderYears": "年份",
"Help": "帮助",
"Hide": "隐藏",
"HideWatchedContentFromLatestMedia": "隐藏来自“新媒体”的观看内容",
"HideWatchedContentFromLatestMedia": "隐藏来自“媒体”的观看内容",
"Home": "首页",
"HttpsRequiresCert": "要启用安全连接, 您需要提供一个受信任的 SSL 证书, 如 \"Let's Encrypt\"。请提供证书或禁用安全连接。",
"Identify": "识别",
@ -705,7 +705,7 @@
"LabelffmpegPathHelp": "FFmpeg 应用文件或包含 FFmpeg 的文件夹的路径。",
"LanNetworksHelp": "在强制带宽限制时,认作本地网络上的 IP 地址或 IP/网络掩码条目的逗号分隔列表。如果设置此项,所有其它 IP 地址将被视为在外部网络上,并且将受到外部带宽限制。如果保留为空,则只将服务器的子网视为本地网络。",
"Large": "大",
"LatestFromLibrary": "最近添加于{0}",
"LatestFromLibrary": "最近添加于 {0}",
"LearnHowYouCanContribute": "了解如何贡献。",
"LibraryAccessHelp": "选择共享给此用户的媒体库。管理员有权使用媒体资料管理器来编辑所有文件夹。",
"List": "列表",
@ -1036,7 +1036,7 @@
"TabContainers": "媒体载体",
"TabDashboard": "控制台",
"TabDirectPlay": "直接播放",
"TabLatest": "新",
"TabLatest": "",
"TabLogs": "日志",
"TabMusic": "音乐",
"TabMyPlugins": "我的插件",
@ -1689,5 +1689,30 @@
"Experimental": "实验功能",
"LabelStereoDownmixAlgorithm": "立体声降混算法",
"StereoDownmixAlgorithmHelp": "用于将多声道下降混合为立体声的算法。",
"HeaderRecordingMetadataSaving": "记录元数据"
"HeaderRecordingMetadataSaving": "记录元数据",
"LabelDummyChapterDuration": "间隔:",
"LabelDummyChapterDurationHelp": "章节图像提取间隔,以秒为单位。",
"PreferEmbeddedExtrasTitlesOverFileNames": "对额外内容优先使用内置的标题而不是文件名",
"PreferEmbeddedExtrasTitlesOverFileNamesHelp": "额外内容通常与父项有相同的内置标题,勾选此项来对它们使用内置标题。",
"SaveRecordingNFO": "在 NFO 中保存录制的 EPG 元数据",
"SaveRecordingNFOHelp": "将 EPG 列表提供者提供的元数据与媒体一起保存。",
"ResolutionMatchSource": "匹配来源",
"SaveRecordingImagesHelp": "将 EPG 列表提供者提供的图像与媒体一起保存。",
"SaveRecordingImages": "保存录制的 EPG 图像",
"HeaderDummyChapter": "章节图片",
"LabelDummyChapterCount": "限制:",
"LabelDummyChapterCountHelp": "每个媒体文件的最大章节图像提取数。",
"LabelChapterImageResolution": "分辨率:",
"LabelChapterImageResolutionHelp": "提取的章节图像的分辨率。",
"SecondarySubtitles": "次字幕",
"SubtitleBlack": "黑色",
"SubtitleGray": "灰色",
"SubtitleLightGray": "淡灰色",
"SubtitleWhite": "白色",
"SubtitleBlue": "蓝色",
"SubtitleCyan": "青色",
"SubtitleGreen": "绿色",
"SubtitleMagenta": "品红色",
"SubtitleRed": "红色",
"SubtitleYellow": "黄色"
}

View File

@ -570,9 +570,9 @@
"LabelAccessStart": "開始時間:",
"LabelAirDays": "播出日期:",
"LabelAirTime": "播出時間:",
"LabelAirsAfterSeason": "已播放劇集季度",
"LabelAirsBeforeEpisode": "集播出",
"LabelAirsBeforeSeason": "尚未播放劇集季度",
"LabelAirsAfterSeason": "在季度後播出",
"LabelAirsBeforeEpisode": "數前播出:",
"LabelAirsBeforeSeason": "在季度前播出",
"LabelAlbum": "專輯:",
"LabelAlbumArtHelp": "PN 在 upnp:albumArtURI 裡的 dlna:profileID 屬性用於專輯封面。某些設備不管圖像的尺寸大小,都會要求特定的值。",
"LabelAlbumArtMaxHeight": "專輯封面最大高度:",
@ -1169,7 +1169,7 @@
"LabelOptionalNetworkPathHelp": "如果這個資料夾在網路上分享,提供網路分享路徑可以供其他應用程式直接存取媒體檔案,例如 {0} 或者 {1}。",
"LabelOriginalAspectRatio": "原始長寬比:",
"LabelOverview": "內容概述:",
"LabelParentalRating": "家長分級:",
"LabelParentalRating": "分級:",
"LabelPasswordConfirm": "確認密碼:",
"LabelPasswordResetProvider": "密碼重設提供者:",
"LabelPasswordRecoveryPinCode": "PIN 碼:",

View File

@ -1,4 +1,4 @@
@import "../../styles/noto-sans/index.scss";
@import "../styles/noto-sans/index.scss";
@mixin font($weight: null, $size: null) {
font-weight: $weight;

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