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

Merge branch 'master' into burn-subtitle-transcoding

This commit is contained in:
gnattu 2024-10-09 06:53:18 +08:00 committed by GitHub
commit da4265eb46
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
89 changed files with 3292 additions and 1480 deletions

View file

@ -2,7 +2,14 @@
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": [
"github>jellyfin/.github//renovate-presets/nodejs",
":semanticCommitsDisabled",
":dependencyDashboard"
],
"packageRules": [
{
"matchPackageNames": [ "@jellyfin/sdk" ],
"followTag": "unstable",
"minimumReleaseAge": null,
"schedule": [ "after 7:00 am" ]
}
]
}

View file

@ -1,52 +0,0 @@
name: Update the Jellyfin SDK
on:
schedule:
- cron: '0 7 * * *'
workflow_dispatch:
concurrency:
group: unstable-sdk-pr
cancel-in-progress: true
jobs:
update:
runs-on: ubuntu-latest
if: ${{ github.repository == 'jellyfin/jellyfin-web' }}
steps:
- name: Check out Git repository
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
with:
ref: master
token: ${{ secrets.JF_BOT_TOKEN }}
- name: Set up Node.js
uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3
with:
node-version: 20
check-latest: true
cache: npm
- name: Install latest unstable SDK
run: |
npm i --save @jellyfin/sdk@unstable
VERSION=$(jq -r '.dependencies["@jellyfin/sdk"]' package.json)
echo "JF_SDK_VERSION=${VERSION}" >> $GITHUB_ENV
- name: Open a pull request
uses: peter-evans/create-pull-request@8867c4aba1b742c39f8d0ba35429c2dfa4b6cb20 # v7.0.1
with:
token: ${{ secrets.JF_BOT_TOKEN }}
commit-message: Update @jellyfin/sdk to ${{env.JF_SDK_VERSION}}
committer: jellyfin-bot <team@jellyfin.org>
author: jellyfin-bot <team@jellyfin.org>
branch: update-jf-sdk
delete-branch: true
title: Update @jellyfin/sdk to ${{env.JF_SDK_VERSION}}
body: |
**Changes**
Updates to the latest unstable @jellyfin/sdk build
labels: |
dependencies
npm

1761
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -16,15 +16,15 @@
"@types/loadable__component": "5.13.9",
"@types/lodash-es": "4.17.12",
"@types/markdown-it": "14.1.2",
"@types/react": "18.3.5",
"@types/react": "18.3.8",
"@types/react-dom": "18.3.0",
"@types/sortablejs": "1.15.8",
"@typescript-eslint/eslint-plugin": "5.62.0",
"@typescript-eslint/parser": "5.62.0",
"@uupaa/dynamic-import-polyfill": "1.0.2",
"@vitest/coverage-v8": "2.0.5",
"@vitest/coverage-v8": "2.1.1",
"autoprefixer": "10.4.20",
"babel-loader": "9.1.3",
"babel-loader": "9.2.1",
"clean-webpack-plugin": "4.0.0",
"confusing-browser-globals": "1.0.11",
"copy-webpack-plugin": "12.0.2",
@ -32,7 +32,7 @@
"css-loader": "7.1.2",
"cssnano": "7.0.6",
"es-check": "7.2.1",
"eslint": "8.57.0",
"eslint": "8.57.1",
"eslint-plugin-compat": "4.2.0",
"eslint-plugin-import": "2.30.0",
"eslint-plugin-jsx-a11y": "6.10.0",
@ -45,12 +45,12 @@
"html-webpack-plugin": "5.6.0",
"jsdom": "25.0.0",
"mini-css-extract-plugin": "2.9.1",
"postcss": "8.4.40",
"postcss": "8.4.47",
"postcss-loader": "8.1.1",
"postcss-preset-env": "10.0.3",
"postcss-scss": "4.0.9",
"sass": "1.78.0",
"sass-loader": "16.0.1",
"sass": "1.79.3",
"sass-loader": "16.0.2",
"source-map-loader": "5.0.0",
"speed-measure-webpack-plugin": "1.5.0",
"style-loader": "4.0.0",
@ -60,8 +60,8 @@
"stylelint-order": "6.0.4",
"stylelint-scss": "5.3.2",
"ts-loader": "9.5.1",
"typescript": "5.5.4",
"vitest": "2.0.5",
"typescript": "5.6.2",
"vitest": "2.1.1",
"webpack": "5.94.0",
"webpack-bundle-analyzer": "4.10.2",
"webpack-cli": "5.1.4",
@ -72,20 +72,20 @@
"dependencies": {
"@emotion/react": "11.13.3",
"@emotion/styled": "11.13.0",
"@fontsource/noto-sans": "5.0.22",
"@fontsource/noto-sans-hk": "5.0.20",
"@fontsource/noto-sans-jp": "5.0.20",
"@fontsource/noto-sans-kr": "5.0.19",
"@fontsource/noto-sans-sc": "5.0.20",
"@fontsource/noto-sans-tc": "5.0.20",
"@jellyfin/libass-wasm": "4.2.2",
"@jellyfin/sdk": "0.0.0-unstable.202409080303",
"@fontsource/noto-sans": "5.1.0",
"@fontsource/noto-sans-hk": "5.1.0",
"@fontsource/noto-sans-jp": "5.1.0",
"@fontsource/noto-sans-kr": "5.1.0",
"@fontsource/noto-sans-sc": "5.1.0",
"@fontsource/noto-sans-tc": "5.1.0",
"@jellyfin/libass-wasm": "4.2.3",
"@jellyfin/sdk": "0.0.0-unstable.202410080502",
"@mui/icons-material": "5.16.7",
"@mui/material": "5.16.7",
"@mui/x-date-pickers": "7.15.0",
"@mui/x-date-pickers": "7.18.0",
"@react-hook/resize-observer": "2.0.2",
"@tanstack/react-query": "5.55.4",
"@tanstack/react-query-devtools": "5.55.4",
"@tanstack/react-query": "5.56.2",
"@tanstack/react-query-devtools": "5.56.2",
"@types/react-lazy-load-image-component": "1.6.4",
"abortcontroller-polyfill": "1.7.5",
"blurhash": "2.0.5",
@ -121,13 +121,13 @@
"resize-observer-polyfill": "1.5.1",
"screenfull": "6.0.2",
"sortablejs": "1.15.3",
"swiper": "11.1.12",
"swiper": "11.1.14",
"usehooks-ts": "3.1.0",
"webcomponents.js": "0.7.24",
"whatwg-fetch": "3.6.20"
},
"optionalDependencies": {
"sass-embedded": "1.78.0"
"sass-embedded": "1.79.3"
},
"browserslist": [
"last 2 Firefox versions",

View file

@ -2,10 +2,11 @@ import { Dashboard, ExpandLess, ExpandMore, LibraryAdd, People, PlayCircle, Sett
import Collapse from '@mui/material/Collapse';
import List from '@mui/material/List';
import ListItem from '@mui/material/ListItem';
import ListItemButton from '@mui/material/ListItemButton/ListItemButton';
import ListItemIcon from '@mui/material/ListItemIcon';
import ListItemText from '@mui/material/ListItemText';
import ListSubheader from '@mui/material/ListSubheader';
import React from 'react';
import React, { useCallback, useState } from 'react';
import { useLocation } from 'react-router-dom';
import ListItemLink from 'components/ListItemLink';
@ -28,8 +29,16 @@ const PLAYBACK_PATHS = [
const ServerDrawerSection = () => {
const location = useLocation();
const isLibrarySectionOpen = LIBRARY_PATHS.includes(location.pathname);
const isPlaybackSectionOpen = PLAYBACK_PATHS.includes(location.pathname);
const [ isLibrarySectionOpen, setIsLibrarySectionOpen ] = useState(LIBRARY_PATHS.includes(location.pathname));
const [ isPlaybackSectionOpen, setIsPlaybackSectionOpen ] = useState(PLAYBACK_PATHS.includes(location.pathname));
const onLibrarySectionClick = useCallback(() => {
setIsLibrarySectionOpen(isOpen => !isOpen);
}, []);
const onPlaybackSectionClick = useCallback(() => {
setIsPlaybackSectionOpen(isOpen => !isOpen);
}, []);
return (
<List
@ -65,13 +74,13 @@ const ServerDrawerSection = () => {
</ListItemLink>
</ListItem>
<ListItem disablePadding>
<ListItemLink to='/dashboard/libraries' selected={false}>
<ListItemButton onClick={onLibrarySectionClick}>
<ListItemIcon>
<LibraryAdd />
</ListItemIcon>
<ListItemText primary={globalize.translate('HeaderLibraries')} />
{isLibrarySectionOpen ? <ExpandLess /> : <ExpandMore />}
</ListItemLink>
</ListItemButton>
</ListItem>
<Collapse in={isLibrarySectionOpen} timeout='auto' unmountOnExit>
<List component='div' disablePadding>
@ -90,13 +99,13 @@ const ServerDrawerSection = () => {
</List>
</Collapse>
<ListItem disablePadding>
<ListItemLink to='/dashboard/playback/transcoding' selected={false}>
<ListItemButton onClick={onPlaybackSectionClick}>
<ListItemIcon>
<PlayCircle />
</ListItemIcon>
<ListItemText primary={globalize.translate('TitlePlayback')} />
{isPlaybackSectionOpen ? <ExpandLess /> : <ExpandMore />}
</ListItemLink>
</ListItemButton>
</ListItem>
<Collapse in={isPlaybackSectionOpen} timeout='auto' unmountOnExit>
<List component='div' disablePadding>

View file

@ -1,9 +1,8 @@
import type { BaseItemDto, DeviceInfo, UserDto } from '@jellyfin/sdk/lib/generated-client';
import React, { useCallback, useEffect, useState, useRef } from 'react';
import type { BaseItemDto, DeviceInfoDto, UserDto } from '@jellyfin/sdk/lib/generated-client';
import React, { useCallback, useEffect, useState, useRef, useMemo } from 'react';
import { useSearchParams } from 'react-router-dom';
import loading from '../../../../components/loading/loading';
import libraryMenu from '../../../../scripts/libraryMenu';
import globalize from '../../../../lib/globalize';
import toast from '../../../../components/toast/toast';
import SectionTabs from '../../../../components/dashboard/users/SectionTabs';
@ -17,6 +16,7 @@ type ItemsArr = {
Name?: string | null;
Id?: string | null;
AppName?: string | null;
CustomName?: string | null;
checkedAttribute?: string
};
@ -27,6 +27,7 @@ const UserLibraryAccess = () => {
const [channelsItems, setChannelsItems] = useState<ItemsArr[]>([]);
const [mediaFoldersItems, setMediaFoldersItems] = useState<ItemsArr[]>([]);
const [devicesItems, setDevicesItems] = useState<ItemsArr[]>([]);
const libraryMenu = useMemo(async () => ((await import('../../../../scripts/libraryMenu')).default), []);
const element = useRef<HTMLDivElement>(null);
@ -95,7 +96,7 @@ const UserLibraryAccess = () => {
triggerChange(chkEnableAllChannels);
}, []);
const loadDevices = useCallback((user: UserDto, devices: DeviceInfo[]) => {
const loadDevices = useCallback((user: UserDto, devices: DeviceInfoDto[]) => {
const page = element.current;
if (!page) {
@ -112,6 +113,7 @@ const UserLibraryAccess = () => {
Id: device.Id,
Name: device.Name,
AppName: device.AppName,
CustomName: device.CustomName,
checkedAttribute: checkedAttribute
});
}
@ -129,9 +131,9 @@ const UserLibraryAccess = () => {
}
}, []);
const loadUser = useCallback((user: UserDto, mediaFolders: BaseItemDto[], channels: BaseItemDto[], devices: DeviceInfo[]) => {
const loadUser = useCallback((user: UserDto, mediaFolders: BaseItemDto[], channels: BaseItemDto[], devices: DeviceInfoDto[]) => {
setUserName(user.Name || '');
libraryMenu.setTitle(user.Name);
void libraryMenu.then(menu => menu.setTitle(user.Name));
loadChannels(user, channels);
loadMediaFolders(user, mediaFolders);
loadDevices(user, devices);
@ -307,7 +309,7 @@ const UserLibraryAccess = () => {
key={Item.Id}
className='chkDevice'
itemId={Item.Id}
itemName={Item.Name}
itemName={Item.CustomName || Item.Name}
itemAppName={Item.AppName}
itemCheckedAttribute={Item.checkedAttribute}
/>

View file

@ -2,11 +2,10 @@ import type { AccessSchedule, ParentalRating, UserDto } from '@jellyfin/sdk/lib/
import { UnratedItem } from '@jellyfin/sdk/lib/generated-client/models/unrated-item';
import { DynamicDayOfWeek } from '@jellyfin/sdk/lib/generated-client/models/dynamic-day-of-week';
import escapeHTML from 'escape-html';
import React, { useCallback, useEffect, useState, useRef } from 'react';
import React, { useCallback, useEffect, useState, useRef, useMemo } from 'react';
import { useSearchParams } from 'react-router-dom';
import globalize from '../../../../lib/globalize';
import LibraryMenu from '../../../../scripts/libraryMenu';
import AccessScheduleList from '../../../../components/dashboard/users/AccessScheduleList';
import TagList from '../../../../components/dashboard/users/TagList';
import ButtonElement from '../../../../elements/ButtonElement';
@ -69,6 +68,7 @@ const UserParentalControl = () => {
const [ accessSchedules, setAccessSchedules ] = useState<AccessSchedule[]>([]);
const [ allowedTags, setAllowedTags ] = useState<string[]>([]);
const [ blockedTags, setBlockedTags ] = useState<string[]>([]);
const libraryMenu = useMemo(async () => ((await import('../../../../scripts/libraryMenu')).default), []);
const element = useRef<HTMLDivElement>(null);
@ -219,7 +219,7 @@ const UserParentalControl = () => {
}
setUserName(user.Name || '');
LibraryMenu.setTitle(user.Name);
void libraryMenu.then(menu => menu.setTitle(user.Name));
loadUnratedItems(user);
loadAllowedTags(user.Policy?.AllowedTags || []);

View file

@ -1,15 +1,14 @@
import type { BaseItemDto, NameIdPair, SyncPlayUserAccessType, UserDto } from '@jellyfin/sdk/lib/generated-client';
import escapeHTML from 'escape-html';
import React, { useCallback, useEffect, useState, useRef } from 'react';
import React, { useCallback, useEffect, useState, useRef, useMemo } from 'react';
import { useSearchParams } from 'react-router-dom';
import Dashboard from '../../../../utils/dashboard';
import globalize from '../../../../lib/globalize';
import LibraryMenu from '../../../../scripts/libraryMenu';
import ButtonElement from '../../../../elements/ButtonElement';
import CheckBoxElement from '../../../../elements/CheckBoxElement';
import InputElement from '../../../../elements/InputElement';
import LinkEditUserPreferences from '../../../../components/dashboard/users/LinkEditUserPreferences';
import LinkButton from '../../../../elements/emby-button/LinkButton';
import SectionTitleContainer from '../../../../elements/SectionTitleContainer';
import SectionTabs from '../../../../components/dashboard/users/SectionTabs';
import loading from '../../../../components/loading/loading';
@ -38,10 +37,11 @@ function onSaveComplete() {
const UserEdit = () => {
const [ searchParams ] = useSearchParams();
const userId = searchParams.get('userId');
const [ userName, setUserName ] = useState('');
const [ userDto, setUserDto ] = useState<UserDto>();
const [ deleteFoldersAccess, setDeleteFoldersAccess ] = useState<ResetProvider[]>([]);
const [ authProviders, setAuthProviders ] = useState<NameIdPair[]>([]);
const [ passwordResetProviders, setPasswordResetProviders ] = useState<NameIdPair[]>([]);
const libraryMenu = useMemo(async () => ((await import('../../../../scripts/libraryMenu')).default), []);
const [ authenticationProviderId, setAuthenticationProviderId ] = useState('');
const [ passwordResetProviderId, setPasswordResetProviderId ] = useState('');
@ -147,10 +147,9 @@ const UserEdit = () => {
txtUserName.disabled = false;
txtUserName.removeAttribute('disabled');
const lnkEditUserPreferences = page.querySelector('.lnkEditUserPreferences') as HTMLDivElement;
lnkEditUserPreferences.setAttribute('href', 'mypreferencesmenu.html?userId=' + user.Id);
LibraryMenu.setTitle(user.Name);
setUserName(user.Name || '');
void libraryMenu.then(menu => menu.setTitle(user.Name));
setUserDto(user);
(page.querySelector('#txtUserName') as HTMLInputElement).value = user.Name || '';
(page.querySelector('.chkIsAdmin') as HTMLInputElement).checked = !!user.Policy?.IsAdministrator;
(page.querySelector('.chkDisabled') as HTMLInputElement).checked = !!user.Policy?.IsDisabled;
@ -170,8 +169,8 @@ const UserEdit = () => {
(page.querySelector('.chkRemoteAccess') as HTMLInputElement).checked = user.Policy?.EnableRemoteAccess == null || user.Policy?.EnableRemoteAccess;
(page.querySelector('#txtRemoteClientBitrateLimit') as HTMLInputElement).value = user.Policy?.RemoteClientBitrateLimit && user.Policy?.RemoteClientBitrateLimit > 0 ?
(user.Policy?.RemoteClientBitrateLimit / 1e6).toLocaleString(undefined, { maximumFractionDigits: 6 }) : '';
(page.querySelector('#txtLoginAttemptsBeforeLockout') as HTMLInputElement).value = String(user.Policy?.MaxActiveSessions) || '0';
(page.querySelector('#txtMaxActiveSessions') as HTMLInputElement).value = String(user.Policy?.SyncPlayAccess) || '0';
(page.querySelector('#txtLoginAttemptsBeforeLockout') as HTMLInputElement).value = String(user.Policy?.LoginAttemptsBeforeLockout) || '-1';
(page.querySelector('#txtMaxActiveSessions') as HTMLInputElement).value = String(user.Policy?.MaxActiveSessions) || '0';
if (window.ApiClient.isMinServerVersion('10.6.0')) {
(page.querySelector('#selectSyncPlayAccess') as HTMLSelectElement).value = String(user.Policy?.SyncPlayAccess);
}
@ -292,7 +291,7 @@ const UserEdit = () => {
<div ref={element} className='content-primary'>
<div className='verticalSection'>
<SectionTitleContainer
title={userName}
title={userDto?.Name || ''}
url='https://jellyfin.org/docs/general/server/users/'
/>
</div>
@ -302,10 +301,9 @@ const UserEdit = () => {
className='lnkEditUserPreferencesContainer'
style={{ paddingBottom: '1em' }}
>
<LinkEditUserPreferences
className= 'lnkEditUserPreferences button-link'
title= 'ButtonEditOtherUserPreferences'
/>
<LinkButton className='lnkEditUserPreferences button-link' href={userDto?.Id ? `mypreferencesmenu.html?userId=${userDto.Id}` : undefined}>
{globalize.translate('ButtonEditOtherUserPreferences')}
</LinkButton>
</div>
<form className='editUserProfileForm'>
<div className='disabledUserBanner hide'>

View file

@ -1,4 +1,5 @@
import type { BaseItemDto } from '@jellyfin/sdk/lib/generated-client';
import { CollectionType } from '@jellyfin/sdk/lib/generated-client/models/collection-type';
import Movie from '@mui/icons-material/Movie';
import MusicNote from '@mui/icons-material/MusicNote';
import Photo from '@mui/icons-material/Photo';
@ -7,11 +8,11 @@ import Tv from '@mui/icons-material/Tv';
import Theaters from '@mui/icons-material/Theaters';
import MusicVideo from '@mui/icons-material/MusicVideo';
import Book from '@mui/icons-material/Book';
import Collections from '@mui/icons-material/Collections';
import Queue from '@mui/icons-material/Queue';
import Quiz from '@mui/icons-material/Quiz';
import VideoLibrary from '@mui/icons-material/VideoLibrary';
import Folder from '@mui/icons-material/Folder';
import React, { FC } from 'react';
import { CollectionType } from '@jellyfin/sdk/lib/generated-client/models/collection-type';
interface LibraryIconProps {
item: BaseItemDto
@ -39,9 +40,11 @@ const LibraryIcon: FC<LibraryIconProps> = ({
case CollectionType.Books:
return <Book />;
case CollectionType.Boxsets:
return <Collections />;
return <VideoLibrary />;
case CollectionType.Playlists:
return <Queue />;
case undefined:
return <Quiz />;
default:
return <Folder />;
}

View file

@ -0,0 +1,68 @@
import React, { FC, useCallback } from 'react';
import { useNavigate } from 'react-router-dom';
import { IconButton } from '@mui/material';
import DeleteIcon from '@mui/icons-material/Delete';
import { useCancelSeriesTimer } from 'hooks/api/liveTvHooks';
import globalize from 'lib/globalize';
import loading from 'components/loading/loading';
import toast from 'components/toast/toast';
import confirm from 'components/confirm/confirm';
interface CancelSeriesTimerButtonProps {
itemId: string;
}
const CancelSeriesTimerButton: FC<CancelSeriesTimerButtonProps> = ({
itemId
}) => {
const navigate = useNavigate();
const cancelSeriesTimer = useCancelSeriesTimer();
const onCancelSeriesTimerClick = useCallback(() => {
confirm({
text: globalize.translate('MessageConfirmRecordingCancellation'),
primary: 'delete',
confirmText: globalize.translate('HeaderCancelSeries'),
cancelText: globalize.translate('HeaderKeepSeries')
})
.then(function () {
loading.show();
cancelSeriesTimer.mutate(
{
timerId: itemId
},
{
onSuccess: async () => {
toast(globalize.translate('SeriesCancelled'));
loading.hide();
navigate('/livetv.html');
},
onError: (err: unknown) => {
loading.hide();
toast(globalize.translate('MessageCancelSeriesTimerError'));
console.error(
'[cancelSeriesTimer] failed to cancel series timer',
err
);
}
}
);
})
.catch(() => {
// confirm dialog closed
});
}, [cancelSeriesTimer, navigate, itemId]);
return (
<IconButton
className='button-flat btnCancelSeriesTimer'
title={globalize.translate('CancelSeries')}
onClick={onCancelSeriesTimerClick}
>
<DeleteIcon />
</IconButton>
);
};
export default CancelSeriesTimerButton;

View file

@ -0,0 +1,60 @@
import React, { FC, useCallback } from 'react';
import { IconButton } from '@mui/material';
import StopIcon from '@mui/icons-material/Stop';
import { useQueryClient } from '@tanstack/react-query';
import { useCancelTimer } from 'hooks/api/liveTvHooks';
import globalize from 'lib/globalize';
import loading from 'components/loading/loading';
import toast from 'components/toast/toast';
interface CancelTimerButtonProps {
timerId: string;
queryKey?: string[];
}
const CancelTimerButton: FC<CancelTimerButtonProps> = ({
timerId,
queryKey
}) => {
const queryClient = useQueryClient();
const cancelTimer = useCancelTimer();
const onCancelTimerClick = useCallback(() => {
loading.show();
cancelTimer.mutate(
{
timerId: timerId
},
{
onSuccess: async () => {
toast(globalize.translate('RecordingCancelled'));
loading.hide();
await queryClient.invalidateQueries({
queryKey
});
},
onError: (err: unknown) => {
loading.hide();
toast(globalize.translate('MessageCancelTimerError'));
console.error(
'[cancelTimer] failed to cancel timer',
err
);
}
}
);
}, [cancelTimer, queryClient, queryKey, timerId]);
return (
<IconButton
className='button-flat btnCancelTimer'
title={globalize.translate('StopRecording')}
onClick={onCancelTimerClick}
>
<StopIcon />
</IconButton>
);
};
export default CancelTimerButton;

View file

@ -0,0 +1,42 @@
import React, { FC, useCallback } from 'react';
import { IconButton } from '@mui/material';
import FileDownloadIcon from '@mui/icons-material/FileDownload';
import { useGetDownload } from 'hooks/api/libraryHooks';
import globalize from 'lib/globalize';
import { download } from 'scripts/fileDownloader';
import type { NullableString } from 'types/base/common/shared/types';
interface DownloadButtonProps {
itemId: string;
itemServerId: NullableString,
itemName: NullableString,
itemPath: NullableString,
}
const DownloadButton: FC<DownloadButtonProps> = ({ itemId, itemServerId, itemName, itemPath }) => {
const { data: downloadHref } = useGetDownload({ itemId });
const onDownloadClick = useCallback(async () => {
download([
{
url: downloadHref,
itemId: itemId,
serverId: itemServerId,
title: itemName,
filename: itemPath?.replace(/^.*[\\/]/, '')
}
]);
}, [downloadHref, itemId, itemName, itemPath, itemServerId]);
return (
<IconButton
className='button-flat btnDownload'
title={globalize.translate('Download')}
onClick={onDownloadClick}
>
<FileDownloadIcon />
</IconButton>
);
};
export default DownloadButton;

View file

@ -0,0 +1,28 @@
import React, { FC, useCallback } from 'react';
import { IconButton } from '@mui/material';
import ExploreIcon from '@mui/icons-material/Explore';
import { playbackManager } from 'components/playback/playbackmanager';
import globalize from 'lib/globalize';
import type { ItemDto } from 'types/base/models/item-dto';
interface InstantMixButtonProps {
item?: ItemDto;
}
const InstantMixButton: FC<InstantMixButtonProps> = ({ item }) => {
const onInstantMixClick = useCallback(() => {
playbackManager.instantMix(item);
}, [item]);
return (
<IconButton
className='button-flat btnInstantMix'
title={globalize.translate('HeaderInstantMix')}
onClick={onInstantMixClick}
>
<ExploreIcon />
</IconButton>
);
};
export default InstantMixButton;

View file

@ -0,0 +1,219 @@
import React, { FC, useCallback, useMemo } from 'react';
import { IconButton } from '@mui/material';
import MoreVertIcon from '@mui/icons-material/MoreVert';
import { useQueryClient } from '@tanstack/react-query';
import { useApi } from 'hooks/useApi';
import { useGetItemByType } from '../../hooks/api/useGetItemByType';
import globalize from 'lib/globalize';
import itemContextMenu from 'components/itemContextMenu';
import { playbackManager } from 'components/playback/playbackmanager';
import { appRouter } from 'components/router/appRouter';
import { ItemKind } from 'types/base/models/item-kind';
import type { NullableString } from 'types/base/common/shared/types';
import type { ItemDto } from 'types/base/models/item-dto';
interface PlayAllFromHereOptions {
item: ItemDto;
items: ItemDto[];
serverId: NullableString;
queue?: boolean;
}
function playAllFromHere(opts: PlayAllFromHereOptions) {
const { item, items, serverId, queue } = opts;
const ids = [];
let foundCard = false;
let startIndex;
for (let i = 0, length = items?.length; i < length; i++) {
if (items[i] === item) {
foundCard = true;
startIndex = i;
}
if (foundCard || !queue) {
ids.push(items[i].Id);
}
}
if (!ids.length) {
return;
}
if (queue) {
return playbackManager.queue({
ids,
serverId
});
} else {
return playbackManager.play({
ids,
serverId,
startIndex
});
}
}
export interface ContextMenuOpts {
open?: boolean;
play?: boolean;
playAllFromHere?: boolean;
queueAllFromHere?: boolean;
cancelTimer?: boolean;
record?: boolean;
deleteItem?: boolean;
shuffle?: boolean;
instantMix?: boolean;
share?: boolean;
stopPlayback?: boolean;
clearQueue?: boolean;
queue?: boolean;
playlist?: boolean;
edit?: boolean;
editImages?: boolean;
editSubtitles?: boolean;
identify?: boolean;
moremediainfo?: boolean;
openAlbum?: boolean;
openArtist?: boolean;
openLyrics?: boolean;
}
interface MoreCommandsButtonProps {
itemType: ItemKind;
selectedItemId?: string;
itemId?: string;
items?: ItemDto[] | null;
collectionId?: NullableString;
playlistId?: NullableString;
canEditPlaylist?: boolean;
itemPlaylistItemId?: NullableString;
contextMenuOpts?: ContextMenuOpts;
queryKey?: string[];
}
const MoreCommandsButton: FC<MoreCommandsButtonProps> = ({
itemType,
selectedItemId,
itemId,
collectionId,
playlistId,
canEditPlaylist,
itemPlaylistItemId,
contextMenuOpts,
items,
queryKey
}) => {
const { user } = useApi();
const queryClient = useQueryClient();
const { data: item } = useGetItemByType({
itemType,
itemId: selectedItemId || itemId || ''
});
const parentId = item?.SeasonId || item?.SeriesId || item?.ParentId;
const playlistItem = useMemo(() => {
let PlaylistItemId: string | null = null;
let PlaylistIndex = -1;
let PlaylistItemCount = 0;
if (playlistId) {
PlaylistItemId = itemPlaylistItemId || null;
if (items?.length) {
PlaylistItemCount = items.length;
PlaylistIndex = items.findIndex(listItem => listItem.PlaylistItemId === PlaylistItemId);
}
}
return { PlaylistItemId, PlaylistIndex, PlaylistItemCount };
}, [itemPlaylistItemId, items, playlistId]);
const defaultMenuOptions = useMemo(() => {
return {
item: {
...item,
...playlistItem
},
user: user,
play: true,
queue: true,
playAllFromHere: item?.Type === ItemKind.Season || !item?.IsFolder,
queueAllFromHere: !item?.IsFolder,
canEditPlaylist: canEditPlaylist,
playlistId: playlistId,
collectionId: collectionId,
...contextMenuOpts
};
}, [canEditPlaylist, collectionId, contextMenuOpts, item, playlistId, playlistItem, user]);
const onMoreCommandsClick = useCallback(
async (e: React.MouseEvent<HTMLElement>) => {
itemContextMenu
.show({
...defaultMenuOptions,
positionTo: e.currentTarget
})
.then(async function (result) {
if (result.command === 'playallfromhere') {
console.log('handleItemClick', {
item,
items: items || [],
serverId: item?.ServerId
});
playAllFromHere({
item: item || {},
items: items || [],
serverId: item?.ServerId
});
} else if (result.command === 'queueallfromhere') {
playAllFromHere({
item: item || {},
items: items || [],
serverId: item?.ServerId,
queue: true
});
} else if (result.deleted) {
if (result?.itemId !== itemId) {
await queryClient.invalidateQueries({
queryKey
});
} else if (parentId) {
appRouter.showItem(parentId, item?.ServerId);
} else {
await appRouter.goHome();
}
} else if (result.updated) {
await queryClient.invalidateQueries({
queryKey
});
}
})
.catch(() => {
/* no-op */
});
},
[defaultMenuOptions, item, itemId, items, parentId, queryClient, queryKey]
);
if (
item
&& itemContextMenu.getCommands(defaultMenuOptions).length
) {
return (
<IconButton
className='button-flat btnMoreCommands'
title={globalize.translate('ButtonMore')}
onClick={onMoreCommandsClick}
>
<MoreVertIcon />
</IconButton>
);
}
return null;
};
export default MoreCommandsButton;

View file

@ -0,0 +1,87 @@
import React, { FC, useCallback, useMemo } from 'react';
import { IconButton } from '@mui/material';
import PlayArrowIcon from '@mui/icons-material/PlayArrow';
import ReplayIcon from '@mui/icons-material/Replay';
import { useQueryClient } from '@tanstack/react-query';
import { useApi } from 'hooks/useApi';
import { getChannelQuery } from 'hooks/api/liveTvHooks/useGetChannel';
import globalize from 'lib/globalize';
import { playbackManager } from 'components/playback/playbackmanager';
import type { ItemDto } from 'types/base/models/item-dto';
import { ItemKind } from 'types/base/models/item-kind';
import itemHelper from 'components/itemHelper';
interface PlayOrResumeButtonProps {
item: ItemDto;
isResumable?: boolean;
selectedMediaSourceId?: string | null;
selectedAudioTrack?: number;
selectedSubtitleTrack?: number;
}
const PlayOrResumeButton: FC<PlayOrResumeButtonProps> = ({
item,
isResumable,
selectedMediaSourceId,
selectedAudioTrack,
selectedSubtitleTrack
}) => {
const apiContext = useApi();
const queryClient = useQueryClient();
const playOptions = useMemo(() => {
if (itemHelper.supportsMediaSourceSelection(item)) {
return {
startPositionTicks:
item.UserData && isResumable ?
item.UserData.PlaybackPositionTicks :
0,
mediaSourceId: selectedMediaSourceId,
audioStreamIndex: selectedAudioTrack || null,
subtitleStreamIndex: selectedSubtitleTrack
};
}
}, [
item,
isResumable,
selectedMediaSourceId,
selectedAudioTrack,
selectedSubtitleTrack
]);
const onPlayClick = useCallback(async () => {
if (item.Type === ItemKind.Program && item.ChannelId) {
const channel = await queryClient.fetchQuery(
getChannelQuery(apiContext, {
channelId: item.ChannelId
})
);
playbackManager.play({
items: [channel]
});
return;
}
playbackManager.play({
items: [item],
...playOptions
});
}, [apiContext, item, playOptions, queryClient]);
return (
<IconButton
className='button-flat btnPlayOrResume'
data-action={isResumable ? 'resume' : 'play'}
title={
isResumable ?
globalize.translate('ButtonResume') :
globalize.translate('Play')
}
onClick={onPlayClick}
>
{isResumable ? <ReplayIcon /> : <PlayArrowIcon />}
</IconButton>
);
};
export default PlayOrResumeButton;

View file

@ -0,0 +1,28 @@
import React, { FC, useCallback } from 'react';
import { IconButton } from '@mui/material';
import TheatersIcon from '@mui/icons-material/Theaters';
import { playbackManager } from 'components/playback/playbackmanager';
import globalize from 'lib/globalize';
import type { ItemDto } from 'types/base/models/item-dto';
interface PlayTrailerButtonProps {
item?: ItemDto;
}
const PlayTrailerButton: FC<PlayTrailerButtonProps> = ({ item }) => {
const onPlayTrailerClick = useCallback(async () => {
await playbackManager.playTrailers(item);
}, [item]);
return (
<IconButton
className='button-flat btnPlayTrailer'
title={globalize.translate('ButtonTrailer')}
onClick={onPlayTrailerClick}
>
<TheatersIcon />
</IconButton>
);
};
export default PlayTrailerButton;

View file

@ -0,0 +1,29 @@
import React, { FC, useCallback } from 'react';
import { IconButton } from '@mui/material';
import ShuffleIcon from '@mui/icons-material/Shuffle';
import { playbackManager } from 'components/playback/playbackmanager';
import globalize from 'lib/globalize';
import type { ItemDto } from 'types/base/models/item-dto';
interface ShuffleButtonProps {
item: ItemDto;
}
const ShuffleButton: FC<ShuffleButtonProps> = ({ item }) => {
const shuffle = useCallback(() => {
playbackManager.shuffle(item);
}, [item]);
return (
<IconButton
title={globalize.translate('Shuffle')}
className='button-flat btnShuffle'
onClick={shuffle}
>
<ShuffleIcon />
</IconButton>
);
};
export default ShuffleButton;

View file

@ -0,0 +1,68 @@
import React, { FC, useCallback } from 'react';
import { IconButton } from '@mui/material';
import CallSplitIcon from '@mui/icons-material/CallSplit';
import { useQueryClient } from '@tanstack/react-query';
import { useDeleteAlternateSources } from 'hooks/api/videosHooks';
import globalize from 'lib/globalize';
import confirm from 'components/confirm/confirm';
import loading from 'components/loading/loading';
import toast from 'components/toast/toast';
interface SplitVersionsButtonProps {
paramId: string;
queryKey?: string[];
}
const SplitVersionsButton: FC<SplitVersionsButtonProps> = ({
paramId,
queryKey
}) => {
const queryClient = useQueryClient();
const deleteAlternateSources = useDeleteAlternateSources();
const splitVersions = useCallback(() => {
confirm({
title: globalize.translate('HeaderSplitMediaApart'),
text: globalize.translate('MessageConfirmSplitMediaSources')
})
.then(function () {
loading.show();
deleteAlternateSources.mutate(
{
itemId: paramId
},
{
onSuccess: async () => {
loading.hide();
await queryClient.invalidateQueries({
queryKey
});
},
onError: (err: unknown) => {
loading.hide();
toast(globalize.translate('MessageSplitVersionsError'));
console.error(
'[splitVersions] failed to split versions',
err
);
}
}
);
})
.catch(() => {
// confirm dialog closed
});
}, [deleteAlternateSources, paramId, queryClient, queryKey]);
return (
<IconButton
className='button-flat btnSplitVersions'
title={globalize.translate('ButtonSplit')}
onClick={splitVersions}
>
<CallSplitIcon />
</IconButton>
);
};
export default SplitVersionsButton;

View file

@ -0,0 +1,62 @@
import type { AxiosRequestConfig } from 'axios';
import { getUserLibraryApi } from '@jellyfin/sdk/lib/utils/api/user-library-api';
import { getLiveTvApi } from '@jellyfin/sdk/lib/utils/api/live-tv-api';
import { useQuery } from '@tanstack/react-query';
import { type JellyfinApiContext, useApi } from 'hooks/useApi';
import type { ItemDto } from 'types/base/models/item-dto';
import { ItemKind } from 'types/base/models/item-kind';
const getItemByType = async (
apiContext: JellyfinApiContext,
itemType: ItemKind,
itemId: string,
options?: AxiosRequestConfig
) => {
const { api, user } = apiContext;
if (!api) throw new Error('[getItemByType] No API instance available');
if (!user?.Id) throw new Error('[getItemByType] No User ID provided');
let response;
switch (itemType) {
case ItemKind.Timer: {
response = await getLiveTvApi(api).getTimer(
{ timerId: itemId },
options
);
break;
}
case ItemKind.SeriesTimer:
response = await getLiveTvApi(api).getSeriesTimer(
{ timerId: itemId },
options
);
break;
default: {
response = await getUserLibraryApi(api).getItem(
{ userId: user.Id, itemId },
options
);
break;
}
}
return response.data as ItemDto;
};
interface UseGetItemByTypeProps {
itemType: ItemKind;
itemId: string;
}
export const useGetItemByType = ({
itemType,
itemId
}: UseGetItemByTypeProps) => {
const apiContext = useApi();
return useQuery({
queryKey: ['ItemByType', { itemType, itemId }],
queryFn: ({ signal }) =>
getItemByType(apiContext, itemType, itemId, { signal }),
enabled: !!apiContext.api && !!apiContext.user?.Id && !!itemId
});
};

View file

@ -0,0 +1,14 @@
/**
* Events triggered by PlaybackManager.
*/
export enum PlaybackManagerEvent {
Pairing = 'pairing',
Paired = 'paired',
PairError = 'pairerror',
PlaybackCancelled = 'playbackcancelled',
PlaybackError = 'playbackerror',
PlaybackStart = 'playbackstart',
PlaybackStop = 'playbackstop',
PlayerChange = 'playerchange',
ReportPlayback = 'reportplayback'
}

View file

@ -0,0 +1,23 @@
/**
* Events triggered by media player plugins.
* TODO: This list is incomplete
*/
export enum PlayerEvent {
Error = 'error',
FullscreenChange = 'fullscreenchange',
ItemStarted = 'itemstarted',
ItemStopped = 'itemstopped',
MediaStreamsChange = 'mediastreamschange',
Pause = 'pause',
PlaybackStart = 'playbackstart',
PlaybackStop = 'playbackstop',
PlaylistItemAdd = 'playlistitemadd',
PlaylistItemMove = 'playlistitemmove',
PlaylistItemRemove = 'playlistitemremove',
RepeatModeChange = 'repeatmodechange',
ShuffleModeChange = 'shufflequeuemodechange',
Stopped = 'stopped',
TimeUpdate = 'timeupdate',
Unpause = 'unpause',
VolumeChange = 'volumechange'
}

View file

@ -0,0 +1,33 @@
import type { BaseItemDto } from '@jellyfin/sdk/lib/generated-client/models/base-item-dto';
import type { MediaSourceInfo } from '@jellyfin/sdk/lib/generated-client/models/media-source-info';
import type { MediaType } from '@jellyfin/sdk/lib/generated-client/models/media-type';
import type { StreamInfo } from './streamInfo';
export interface ManagedPlayerStopInfo {
item: BaseItemDto
mediaSource: MediaSourceInfo
nextItem?: BaseItemDto | null
nextMediaType?: MediaType | null
positionMs?: number
}
export interface MovedItem {
newIndex: number
playlistItemId: string
}
export type PlayerErrorCode = string;
export interface PlayerStopInfo {
src?: URL | BaseItemDto
}
export interface PlayerError {
streamInfo?: StreamInfo
type: MediaError | string
}
export interface RemovedItems {
playlistItemIds: string[]
}

View file

@ -0,0 +1,34 @@
import type { BaseItemDto } from '@jellyfin/sdk/lib/generated-client/models/base-item-dto';
import type { MediaSourceInfo } from '@jellyfin/sdk/lib/generated-client/models/media-source-info';
import type { MediaType } from '@jellyfin/sdk/lib/generated-client/models/media-type';
import type { PlayMethod } from '@jellyfin/sdk/lib/generated-client/models/play-method';
export interface StreamInfo {
ended?: boolean
fullscreen?: boolean
item?: BaseItemDto
lastMediaInfoQuery?: number
liveStreamId?: string
mediaSource?: MediaSourceInfo
mediaType?: MediaType
mimeType?: string
playMethod?: PlayMethod
playSessionId?: string
playbackStartTimeTicks?: number
playerStartPositionTicks?: number
resetSubtitleOffset?: boolean
started?: boolean
textTracks?: TrackInfo[]
title?: string
tracks?: TrackInfo[]
transcodingOffsetTicks?: number
url?: string
}
interface TrackInfo {
url: string
language: string
isDefault: boolean
index: number
format: string
}

View file

@ -0,0 +1,101 @@
import type { BaseItemDto } from '@jellyfin/sdk/lib/generated-client/models/base-item-dto';
import type { MediaSourceInfo } from '@jellyfin/sdk/lib/generated-client/models/media-source-info';
import type { PlaybackManager } from 'components/playback/playbackmanager';
import type { MediaError } from 'types/mediaError';
import type { PlayTarget } from 'types/playTarget';
import type { PlaybackStopInfo, PlayerState } from 'types/playbackStopInfo';
import type { Plugin } from 'types/plugin';
import Events, { type Event } from 'utils/events';
import { PlaybackManagerEvent } from '../constants/playbackManagerEvent';
import { PlayerEvent } from '../constants/playerEvent';
import type { ManagedPlayerStopInfo, MovedItem, PlayerError, PlayerErrorCode, PlayerStopInfo, RemovedItems } from '../types/callbacks';
export interface PlaybackSubscriber {
onPlaybackCancelled?(e: Event): void
onPlaybackError?(e: Event, errorType: MediaError): void
onPlaybackStart?(e: Event, player: Plugin, state: PlayerState): void
onPlaybackStop?(e: Event, info: PlaybackStopInfo): void
onPlayerChange?(e: Event, player: Plugin, target: PlayTarget, previousPlayer: Plugin): void
onPlayerError?(e: Event, error: PlayerError): void
onPlayerFullscreenChange?(e: Event): void
onPlayerItemStarted?(e: Event, item?: BaseItemDto, mediaSource?: MediaSourceInfo): void
onPlayerItemStopped?(e: Event, info: ManagedPlayerStopInfo): void
onPlayerMediaStreamsChange?(e: Event): void
onPlayerPause?(e: Event): void
onPlayerPlaybackStart?(e: Event, state: PlayerState): void
onPlayerPlaybackStop?(e: Event, state: PlayerState): void
onPlayerPlaylistItemAdd?(e: Event): void
onPlayerPlaylistItemMove?(e: Event, item: MovedItem): void
onPlayerPlaylistItemRemove?(e: Event, items?: RemovedItems): void
onPlayerRepeatModeChange?(e: Event): void
onPlayerShuffleModeChange?(e: Event): void
onPlayerStopped?(e: Event, info?: PlayerStopInfo | PlayerErrorCode): void
onPlayerTimeUpdate?(e: Event): void
onPlayerUnpause?(e: Event): void
onPlayerVolumeChange?(e: Event): void
onReportPlayback?(e: Event, isServerItem: boolean): void
}
export abstract class PlaybackSubscriber {
private player: Plugin | undefined;
private readonly playbackManagerEvents = {
[PlaybackManagerEvent.PlaybackCancelled]: this.onPlaybackCancelled,
[PlaybackManagerEvent.PlaybackError]: this.onPlaybackError,
[PlaybackManagerEvent.PlaybackStart]: this.onPlaybackStart,
[PlaybackManagerEvent.PlaybackStop]: this.onPlaybackStop,
[PlaybackManagerEvent.PlayerChange]: this.onPlayerChange,
[PlaybackManagerEvent.ReportPlayback]: this.onReportPlayback
};
private readonly playerEvents = {
[PlayerEvent.Error]: this.onPlayerError,
[PlayerEvent.FullscreenChange]: this.onPlayerFullscreenChange,
[PlayerEvent.ItemStarted]: this.onPlayerItemStarted,
[PlayerEvent.ItemStopped]: this.onPlayerItemStopped,
[PlayerEvent.MediaStreamsChange]: this.onPlayerMediaStreamsChange,
[PlayerEvent.Pause]: this.onPlayerPause,
[PlayerEvent.PlaybackStart]: this.onPlayerPlaybackStart,
[PlayerEvent.PlaybackStop]: this.onPlayerPlaybackStop,
[PlayerEvent.PlaylistItemAdd]: this.onPlayerPlaylistItemAdd,
[PlayerEvent.PlaylistItemMove]: this.onPlayerPlaylistItemMove,
[PlayerEvent.PlaylistItemRemove]: this.onPlayerPlaylistItemRemove,
[PlayerEvent.RepeatModeChange]: this.onPlayerRepeatModeChange,
[PlayerEvent.ShuffleModeChange]: this.onPlayerShuffleModeChange,
[PlayerEvent.Stopped]: this.onPlayerStopped,
[PlayerEvent.TimeUpdate]: this.onPlayerTimeUpdate,
[PlayerEvent.Unpause]: this.onPlayerUnpause,
[PlayerEvent.VolumeChange]: this.onPlayerVolumeChange
};
constructor(
protected readonly playbackManager: PlaybackManager
) {
Object.entries(this.playbackManagerEvents).forEach(([event, handler]) => {
if (handler) Events.on(playbackManager, event, handler);
});
this.bindPlayerEvents();
Events.on(playbackManager, PlaybackManagerEvent.PlayerChange, this.bindPlayerEvents.bind(this));
}
private bindPlayerEvents() {
const newPlayer = this.playbackManager.getCurrentPlayer();
if (this.player === newPlayer) return;
if (this.player) {
Object.entries(this.playerEvents).forEach(([event, handler]) => {
if (handler) Events.off(this.player, event, handler);
});
}
this.player = newPlayer;
if (!this.player) return;
Object.entries(this.playerEvents).forEach(([event, handler]) => {
if (handler) Events.on(this.player, event, handler);
});
}
}

View file

@ -1,11 +1,10 @@
import type { UserDto } from '@jellyfin/sdk/lib/generated-client';
import { ImageType } from '@jellyfin/sdk/lib/generated-client/models/image-type';
import React, { FunctionComponent, useEffect, useState, useRef, useCallback } from 'react';
import React, { FunctionComponent, useEffect, useState, useRef, useCallback, useMemo } from 'react';
import { useSearchParams } from 'react-router-dom';
import Dashboard from '../../../../utils/dashboard';
import globalize from '../../../../lib/globalize';
import LibraryMenu from '../../../../scripts/libraryMenu';
import { appHost } from '../../../../components/apphost';
import confirm from '../../../../components/confirm/confirm';
import ButtonElement from '../../../../elements/ButtonElement';
@ -18,6 +17,7 @@ const UserProfile: FunctionComponent = () => {
const [ searchParams ] = useSearchParams();
const userId = searchParams.get('userId');
const [ userName, setUserName ] = useState('');
const libraryMenu = useMemo(async () => ((await import('../../../../scripts/libraryMenu')).default), []);
const element = useRef<HTMLDivElement>(null);
@ -41,7 +41,7 @@ const UserProfile: FunctionComponent = () => {
}
setUserName(user.Name);
LibraryMenu.setTitle(user.Name);
void libraryMenu.then(menu => menu.setTitle(user.Name));
let imageUrl = 'assets/img/avatar.png';
if (user.PrimaryImageTag) {

View file

@ -4,6 +4,7 @@
* @module components/cardBuilder/cardBuilder
*/
import { BaseItemKind } from '@jellyfin/sdk/lib/generated-client/models/base-item-kind';
import { PersonKind } from '@jellyfin/sdk/lib/generated-client/models/person-kind';
import escapeHtml from 'escape-html';
@ -12,7 +13,7 @@ import datetime from 'scripts/datetime';
import dom from 'scripts/dom';
import globalize from 'lib/globalize';
import { getBackdropShape, getPortraitShape, getSquareShape } from 'utils/card';
import imageHelper from 'utils/image';
import { getItemTypeIcon, getLibraryIcon } from 'utils/image';
import focusManager from '../focusManager';
import imageLoader from '../images/imageLoader';
@ -1053,7 +1054,7 @@ function buildCard(index, item, apiClient, options) {
indicatorsHtml += indicators.getPlayedIndicatorHtml(item);
}
if (item.Type === 'CollectionFolder' || item.CollectionType) {
if (item.Type === BaseItemKind.CollectionFolder || item.CollectionType) {
const refreshClass = item.RefreshProgress ? '' : ' class="hide"';
indicatorsHtml += '<div is="emby-itemrefreshindicator"' + refreshClass + ' data-progress="' + (item.RefreshProgress || 0) + '" data-status="' + item.RefreshStatus + '"></div>';
importRefreshIndicator();
@ -1180,41 +1181,18 @@ function getHoverMenuHtml(item, action) {
* @returns {string} HTML markup of the card overlay.
*/
export function getDefaultText(item, options) {
if (item.CollectionType) {
return '<span class="cardImageIcon material-icons ' + imageHelper.getLibraryIcon(item.CollectionType) + '" aria-hidden="true"></span>';
let icon;
if (item.Type === BaseItemKind.CollectionFolder || item.CollectionType) {
icon = getLibraryIcon(item.CollectionType);
}
switch (item.Type) {
case 'MusicAlbum':
return '<span class="cardImageIcon material-icons album" aria-hidden="true"></span>';
case 'MusicArtist':
case 'Person':
return '<span class="cardImageIcon material-icons person" aria-hidden="true"></span>';
case 'Audio':
return '<span class="cardImageIcon material-icons audiotrack" aria-hidden="true"></span>';
case 'Movie':
return '<span class="cardImageIcon material-icons movie" aria-hidden="true"></span>';
case 'Episode':
case 'Series':
return '<span class="cardImageIcon material-icons tv" aria-hidden="true"></span>';
case 'Program':
return '<span class="cardImageIcon material-icons live_tv" aria-hidden="true"></span>';
case 'Book':
return '<span class="cardImageIcon material-icons book" aria-hidden="true"></span>';
case 'Folder':
return '<span class="cardImageIcon material-icons folder" aria-hidden="true"></span>';
case 'BoxSet':
return '<span class="cardImageIcon material-icons collections" aria-hidden="true"></span>';
case 'Playlist':
return '<span class="cardImageIcon material-icons view_list" aria-hidden="true"></span>';
case 'Photo':
return '<span class="cardImageIcon material-icons photo" aria-hidden="true"></span>';
case 'PhotoAlbum':
return '<span class="cardImageIcon material-icons photo_album" aria-hidden="true"></span>';
if (!icon) {
icon = getItemTypeIcon(item.Type, options?.defaultCardImageIcon);
}
if (options?.defaultCardImageIcon) {
return '<span class="cardImageIcon material-icons ' + options.defaultCardImageIcon + '" aria-hidden="true"></span>';
if (icon) {
return `<span class="cardImageIcon material-icons ${icon}" aria-hidden="true"></span>`;
}
const defaultName = isUsingLiveTvNaming(item.Type) ? item.Name : itemHelper.getDisplayName(item);

View file

@ -1,7 +1,7 @@
import { BaseItemKind } from '@jellyfin/sdk/lib/generated-client/models/base-item-kind';
import React, { type FC } from 'react';
import Icon from '@mui/material/Icon';
import imageHelper from 'utils/image';
import { getItemTypeIcon, getLibraryIcon } from 'utils/image';
import DefaultName from './DefaultName';
import type { ItemDto } from 'types/base/models/item-dto';
@ -14,38 +14,24 @@ const DefaultIconText: FC<DefaultIconTextProps> = ({
item,
defaultCardImageIcon
}) => {
if (item.CollectionType) {
return (
<Icon
className='cardImageIcon'
sx={{ color: 'inherit', fontSize: '5em' }}
aria-hidden='true'
>
{imageHelper.getLibraryIcon(item.CollectionType)}
</Icon>
);
let icon;
if (item.Type === BaseItemKind.CollectionFolder || item.CollectionType) {
icon = getLibraryIcon(item.CollectionType);
}
if (item.Type && !(item.Type === BaseItemKind.TvChannel || item.Type === BaseItemKind.Studio )) {
return (
<Icon
className='cardImageIcon'
sx={{ color: 'inherit', fontSize: '5em' }}
aria-hidden='true'
>
{imageHelper.getItemTypeIcon(item.Type)}
</Icon>
);
if (!icon) {
icon = getItemTypeIcon(item.Type, defaultCardImageIcon);
}
if (defaultCardImageIcon) {
if (icon) {
return (
<Icon
className='cardImageIcon'
sx={{ color: 'inherit', fontSize: '5em' }}
aria-hidden='true'
>
{defaultCardImageIcon}
{icon}
</Icon>
);
}

View file

@ -1,30 +0,0 @@
import React, { FunctionComponent } from 'react';
import globalize from 'lib/globalize';
type IProps = {
title?: string;
className?: string;
};
const createLinkElement = ({ className, title }: IProps) => ({
__html: `<a
is="emby-linkbutton"
class="${className}"
href='#'
>
${title}
</a>`
});
const LinkEditUserPreferences: FunctionComponent<IProps> = ({ className, title }: IProps) => {
return (
<div
dangerouslySetInnerHTML={createLinkElement({
className: className,
title: globalize.translate(title)
})}
/>
);
};
export default LinkEditUserPreferences;

View file

@ -1,49 +1,60 @@
import React, { FunctionComponent } from 'react';
import globalize from 'lib/globalize';
import { navigate } from '../../../utils/dashboard';
import LinkButton from '../../../elements/emby-button/LinkButton';
type IProps = {
activeTab: string;
};
const createLinkElement = (activeTab: string) => ({
__html: `<a href="#"
is="emby-linkbutton"
data-role="button"
class="${activeTab === 'useredit' ? 'ui-btn-active' : ''}"
onclick="Dashboard.navigate('/dashboard/users/profile', true);">
${globalize.translate('Profile')}
</a>
<a href="#"
is="emby-linkbutton"
data-role="button"
class="${activeTab === 'userlibraryaccess' ? 'ui-btn-active' : ''}"
onclick="Dashboard.navigate('/dashboard/users/access', true);">
${globalize.translate('TabAccess')}
</a>
<a href="#"
is="emby-linkbutton"
data-role="button"
class="${activeTab === 'userparentalcontrol' ? 'ui-btn-active' : ''}"
onclick="Dashboard.navigate('/dashboard/users/parentalcontrol', true);">
${globalize.translate('TabParentalControl')}
</a>
<a href="#"
is="emby-linkbutton"
data-role="button"
class="${activeTab === 'userpassword' ? 'ui-btn-active' : ''}"
onclick="Dashboard.navigate('/dashboard/users/password', true);">
${globalize.translate('HeaderPassword')}
</a>`
});
function useNavigate(url: string): () => void {
return React.useCallback(() => {
navigate(url, true).catch(err => {
console.warn('Error navigating to dashboard url', err);
});
}, [url]);
}
const SectionTabs: FunctionComponent<IProps> = ({ activeTab }: IProps) => {
const onClickProfile = useNavigate('/dashboard/users/profile');
const onClickAccess = useNavigate('/dashboard/users/access');
const onClickParentalControl = useNavigate('/dashboard/users/parentalcontrol');
const clickPassword = useNavigate('/dashboard/users/password');
return (
<div
data-role='controlgroup'
data-type='horizontal'
className='localnav'
dangerouslySetInnerHTML={createLinkElement(activeTab)}
/>
className='localnav'>
<LinkButton
href='#'
data-role='button'
className={activeTab === 'useredit' ? 'ui-btn-active' : ''}
onClick={onClickProfile}>
{globalize.translate('Profile')}
</LinkButton>
<LinkButton
href='#'
data-role='button'
className={activeTab === 'userlibraryaccess' ? 'ui-btn-active' : ''}
onClick={onClickAccess}>
{globalize.translate('TabAccess')}
</LinkButton>
<LinkButton
href='#'
data-role='button'
className={activeTab === 'userparentalcontrol' ? 'ui-btn-active' : ''}
onClick={onClickParentalControl}>
{globalize.translate('TabParentalControl')}
</LinkButton>
<LinkButton
href='#'
data-role='button'
className={activeTab === 'userpassword' ? 'ui-btn-active' : ''}
onClick={clickPassword}>
{globalize.translate('HeaderPassword')}
</LinkButton>
</div>
);
};

View file

@ -4,19 +4,9 @@ import { formatDistanceToNow } from 'date-fns';
import { getLocaleWithSuffix } from '../../../utils/dateFnsLocale';
import globalize from '../../../lib/globalize';
import IconButtonElement from '../../../elements/IconButtonElement';
import escapeHTML from 'escape-html';
import LinkButton from '../../../elements/emby-button/LinkButton';
import { getDefaultBackgroundClass } from '../../cardbuilder/cardBuilderUtils';
const createLinkElement = ({ user, renderImgUrl }: { user: UserDto, renderImgUrl: string }) => ({
__html: `<a
is="emby-linkbutton"
class="cardContent"
href="#/dashboard/users/profile?userId=${user.Id}"
>
${renderImgUrl}
</a>`
});
type IProps = {
user?: UserDto;
};
@ -55,22 +45,21 @@ const UserCardBox: FunctionComponent<IProps> = ({ user = {} }: IProps) => {
const lastSeen = getLastSeenText(user.LastActivityDate);
const renderImgUrl = imgUrl ?
`<div class='${imageClass}' style='background-image:url(${imgUrl})'></div>` :
`<div class='${imageClass} ${getDefaultBackgroundClass(user.Name)} flex align-items-center justify-content-center'>
<span class='material-icons cardImageIcon person' aria-hidden='true'></span>
</div>`;
<div className={imageClass} style={{ backgroundImage: `url(${imgUrl})` }} /> :
<div className={`${imageClass} ${getDefaultBackgroundClass(user.Name)} flex align-items-center justify-content-center`}>
<span className='material-icons cardImageIcon person' aria-hidden='true'></span>
</div>;
return (
<div data-userid={user.Id} data-username={user.Name} className={cssClass}>
<div className='cardBox visualCardBox'>
<div className='cardScalable visualCardBox-cardScalable'>
<div className='cardPadder cardPadder-square'></div>
<div
dangerouslySetInnerHTML={createLinkElement({
user: user,
renderImgUrl: renderImgUrl
})}
/>
<LinkButton
className='cardContent'
href={`#/dashboard/users/profile?userId=${user.Id}`}>
{renderImgUrl}
</LinkButton>
</div>
<div className='cardFooter visualCardBox-cardFooter'>
<div
@ -83,7 +72,7 @@ const UserCardBox: FunctionComponent<IProps> = ({ user = {} }: IProps) => {
/>
</div>
<div className='cardText'>
<span>{escapeHTML(user.Name)}</span>
<span>{user.Name}</span>
</div>
<div className='cardText cardText-secondary'>
<span>{lastSeen != '' ? lastSeen : ''}</span>

View file

@ -1,8 +1,7 @@
import React, { FunctionComponent, useCallback, useEffect, useRef } from 'react';
import React, { FunctionComponent, useCallback, useEffect, useMemo, useRef } from 'react';
import type { UserDto } from '@jellyfin/sdk/lib/generated-client';
import Dashboard from '../../../utils/dashboard';
import globalize from '../../../lib/globalize';
import LibraryMenu from '../../../scripts/libraryMenu';
import confirm from '../../confirm/confirm';
import loading from '../../loading/loading';
import toast from '../../toast/toast';
@ -16,6 +15,7 @@ type IProps = {
const UserPasswordForm: FunctionComponent<IProps> = ({ userId }: IProps) => {
const element = useRef<HTMLDivElement>(null);
const user = useRef<UserDto>();
const libraryMenu = useMemo(async () => ((await import('../../../scripts/libraryMenu')).default), []);
const loadUser = useCallback(async () => {
const page = element.current;
@ -37,7 +37,7 @@ const UserPasswordForm: FunctionComponent<IProps> = ({ userId }: IProps) => {
throw new Error('Unexpected null user policy or configuration');
}
LibraryMenu.setTitle(user.current.Name);
(await libraryMenu).setTitle(user.current.Name);
if (user.current.HasConfiguredPassword) {
if (!user.current.Policy?.IsAdministrator) {

View file

@ -20,7 +20,7 @@ import toast from '../toast/toast';
import template from './homeScreenSettings.template.html';
import { LibraryTab } from '../../types/libraryTab.ts';
const numConfigurableSections = 7;
const numConfigurableSections = 10;
function renderViews(page, user, result) {
let folderHtml = '';
@ -204,15 +204,15 @@ function renderViewOrder(context, user, result) {
}
function updateHomeSectionValues(context, userSettings) {
for (let i = 1; i <= 7; i++) {
for (let i = 1; i <= numConfigurableSections; i++) {
const select = context.querySelector(`#selectHomeSection${i}`);
const defaultValue = homeSections.getDefaultSection(i - 1);
const option = select.querySelector(`option[value=${defaultValue}]`) || select.querySelector('option[value=""]');
const option = select.querySelector(`option[value="${defaultValue}"]`) || select.querySelector('option[value=""]');
const userValue = userSettings.get(`homesection${i - 1}`);
option.value = '';
if (option) option.value = '';
if (userValue === defaultValue || !userValue) {
select.value = '';
@ -390,6 +390,9 @@ function saveUser(context, user, userSettingsInstance, apiClient) {
userSettingsInstance.set('homesection4', context.querySelector('#selectHomeSection5').value);
userSettingsInstance.set('homesection5', context.querySelector('#selectHomeSection6').value);
userSettingsInstance.set('homesection6', context.querySelector('#selectHomeSection7').value);
userSettingsInstance.set('homesection7', context.querySelector('#selectHomeSection8').value);
userSettingsInstance.set('homesection8', context.querySelector('#selectHomeSection9').value);
userSettingsInstance.set('homesection9', context.querySelector('#selectHomeSection10').value);
const selectLandings = context.querySelectorAll('.selectLanding');
for (i = 0, length = selectLandings.length; i < length; i++) {

View file

@ -115,6 +115,48 @@
<option value="none">${None}</option>
</select>
</div>
<div class="selectContainer">
<select is="emby-select" id="selectHomeSection8" label="{section8label}">
<option value="smalllibrarytiles">${HeaderMyMedia}</option>
<option value="librarybuttons">${HeaderMyMediaSmall}</option>
<option value="activerecordings">${HeaderActiveRecordings}</option>
<option value="resume">${HeaderContinueWatching}</option>
<option value="resumeaudio">${HeaderContinueListening}</option>
<option value="resumebook">${HeaderContinueReading}</option>
<option value="latestmedia">${HeaderLatestMedia}</option>
<option value="nextup">${NextUp}</option>
<option value="livetv">${LiveTV}</option>
<option value="none">${None}</option>
</select>
</div>
<div class="selectContainer">
<select is="emby-select" id="selectHomeSection9" label="{section9label}">
<option value="smalllibrarytiles">${HeaderMyMedia}</option>
<option value="librarybuttons">${HeaderMyMediaSmall}</option>
<option value="activerecordings">${HeaderActiveRecordings}</option>
<option value="resume">${HeaderContinueWatching}</option>
<option value="resumeaudio">${HeaderContinueListening}</option>
<option value="resumebook">${HeaderContinueReading}</option>
<option value="latestmedia">${HeaderLatestMedia}</option>
<option value="nextup">${NextUp}</option>
<option value="livetv">${LiveTV}</option>
<option value="none">${None}</option>
</select>
</div>
<div class="selectContainer">
<select is="emby-select" id="selectHomeSection10" label="{section10label}">
<option value="smalllibrarytiles">${HeaderMyMedia}</option>
<option value="librarybuttons">${HeaderMyMediaSmall}</option>
<option value="activerecordings">${HeaderActiveRecordings}</option>
<option value="resume">${HeaderContinueWatching}</option>
<option value="resumeaudio">${HeaderContinueListening}</option>
<option value="resumebook">${HeaderContinueReading}</option>
<option value="latestmedia">${HeaderLatestMedia}</option>
<option value="nextup">${NextUp}</option>
<option value="livetv">${LiveTV}</option>
<option value="none">${None}</option>
</select>
</div>
</div>
<div class="verticalSection verticalSection-extrabottompadding">

View file

@ -61,7 +61,7 @@ export function loadSections(elem, apiClient, user, userSettings) {
let html = '';
if (userViews.length) {
const userSectionCount = 7;
const userSectionCount = 10;
// TV layout can have an extra section to ensure libraries are visible
const totalSectionCount = layoutManager.tv ? userSectionCount + 1 : userSectionCount;
for (let i = 0; i < totalSectionCount; i++) {

View file

@ -351,12 +351,13 @@ export function getCommands(options) {
return commands;
}
function getResolveFunction(resolve, id, changed, deleted) {
function getResolveFunction(resolve, commandId, changed, deleted, itemId) {
return function () {
resolve({
command: id,
command: commandId,
updated: changed,
deleted: deleted
deleted: deleted,
itemId: itemId
});
};
}
@ -533,7 +534,7 @@ function executeCommand(item, id, options) {
getResolveFunction(resolve, id)();
break;
case 'delete':
deleteItem(apiClient, item).then(getResolveFunction(resolve, id, true, true), getResolveFunction(resolve, id));
deleteItem(apiClient, item).then(getResolveFunction(resolve, id, true, true, itemId), getResolveFunction(resolve, id));
break;
case 'share':
navigator.share({

View file

@ -12,6 +12,7 @@ import dom from '../../scripts/dom';
import '../../elements/emby-checkbox/emby-checkbox';
import '../../elements/emby-select/emby-select';
import '../../elements/emby-input/emby-input';
import '../../elements/emby-textarea/emby-textarea';
import './style.scss';
import template from './libraryoptionseditor.template.html';
@ -473,8 +474,10 @@ export function setContentType(parent, contentType) {
if (contentType === 'music') {
parent.querySelector('.lyricSettingsSection').classList.remove('hide');
parent.querySelector('.audioTagSettingsSection').classList.remove('hide');
} else {
parent.querySelector('.lyricSettingsSection').classList.add('hide');
parent.querySelector('.audioTagSettingsSection').classList.add('hide');
}
parent.querySelector('.chkAutomaticallyAddToCollectionContainer').classList.toggle('hide', contentType !== 'movies' && contentType !== 'mixed');
@ -597,6 +600,8 @@ export function getLibraryOptions(parent) {
SaveLyricsWithMedia: parent.querySelector('#chkSaveLyricsLocally').checked,
RequirePerfectSubtitleMatch: parent.querySelector('#chkRequirePerfectMatch').checked,
AutomaticallyAddToCollection: parent.querySelector('#chkAutomaticallyAddToCollection').checked,
PreferNonstandardArtistsTag: parent.querySelector('#chkPreferNonstandardArtistsTag').checked,
UseCustomTagDelimiters: parent.querySelector('#chkUseCustomTagDelimiters').checked,
MetadataSavers: Array.prototype.map.call(Array.prototype.filter.call(parent.querySelectorAll('.chkMetadataSaver'), elem => {
return elem.checked;
}), elem => {
@ -613,6 +618,8 @@ export function getLibraryOptions(parent) {
}), elem => {
return elem.getAttribute('data-lang');
});
options.CustomTagDelimiters = parent.querySelector('#customTagDelimitersInput').value.split('');
options.DelimiterWhitelist = parent.querySelector('#tagDelimiterWhitelist').value.split('\n').filter(item => item.trim());
setSubtitleFetchersIntoOptions(parent, options);
setLyricFetchersIntoOptions(parent, options);
setMetadataFetchersIntoOptions(parent, options);
@ -661,12 +668,16 @@ export function setLibraryOptions(parent, options) {
parent.querySelector('#chkSkipIfAudioTrackPresent').checked = options.SkipSubtitlesIfAudioTrackMatches;
parent.querySelector('#chkRequirePerfectMatch').checked = options.RequirePerfectSubtitleMatch;
parent.querySelector('#chkAutomaticallyAddToCollection').checked = options.AutomaticallyAddToCollection;
parent.querySelector('#chkPreferNonstandardArtistsTag').checked = options.PreferNonstandardArtistsTag;
parent.querySelector('#chkUseCustomTagDelimiters').checked = options.UseCustomTagDelimiters;
Array.prototype.forEach.call(parent.querySelectorAll('.chkMetadataSaver'), elem => {
elem.checked = options.MetadataSavers ? options.MetadataSavers.includes(elem.getAttribute('data-pluginname')) : elem.getAttribute('data-defaultenabled') === 'true';
});
Array.prototype.forEach.call(parent.querySelectorAll('.chkSubtitleLanguage'), elem => {
elem.checked = !!options.SubtitleDownloadLanguages && options.SubtitleDownloadLanguages.includes(elem.getAttribute('data-lang'));
});
parent.querySelector('#customTagDelimitersInput').value = options.CustomTagDelimiters.join('');
parent.querySelector('#tagDelimiterWhitelist').value = options.DelimiterWhitelist.filter(item => item.trim()).join('\n');
renderMetadataReaders(parent, getOrderedPlugins(parent.availableOptions.MetadataReaders, options.LocalMetadataReaderOrder || []));
renderMetadataFetchers(parent, parent.availableOptions, options);
renderImageFetchers(parent, parent.availableOptions, options);

View file

@ -216,3 +216,29 @@
<div class="fieldDescription checkboxFieldDescription">${SaveLyricsIntoMediaFoldersHelp}</div>
</div>
</div>
<div class="audioTagSettingsSection hide">
<h2>${LabelAudioTagSettings}</h2>
<div class="checkboxContainer checkboxContainer-withDescription advanced">
<label>
<input type="checkbox" is="emby-checkbox" id="chkPreferNonstandardArtistsTag" />
<span>${PreferNonStandardArtistsTag}</span>
</label>
<div class="fieldDescription checkboxFieldDescription">${PreferNonstandardArtistsTagHelp}</div>
</div>
<div class="checkboxContainer checkboxContainer-withDescription advanced">
<label>
<input type="checkbox" is="emby-checkbox" id="chkUseCustomTagDelimiters" />
<span>${UseCustomTagDelimiters}</span>
</label>
<div class="fieldDescription checkboxFieldDescription">${UseCustomTagDelimitersHelp}</div>
</div>
<div class="inputContainer">
<input type="text" is="emby-input" id="customTagDelimitersInput" label="${LabelCustomTagDelimiters}" value="/|;\"/>
<div class="fieldDescription">${LabelCustomTagDelimitersHelp}</div>
</div>
<div class="inputContainer">
<textarea is="emby-textarea" id="tagDelimiterWhitelist" label="${LabelDelimiterWhitelist}" class="textarea-mono" style="resize: none;min-height:2.5em"></textarea>
<div class="fieldDescription">${LabelDelimiterWhitelistHelp}</div>
</div>
</div>

View file

@ -21,7 +21,8 @@ import ServerConnections from '../ServerConnections';
import toast from '../toast/toast';
import { appRouter } from '../router/appRouter';
import template from './metadataEditor.template.html';
import { SeriesStatus } from '@jellyfin/sdk/lib/generated-client';
import { BaseItemKind } from '@jellyfin/sdk/lib/generated-client/models/base-item-kind';
import { SeriesStatus } from '@jellyfin/sdk/lib/generated-client/models/series-status';
let currentContext;
let metadataEditorInfo;
@ -541,7 +542,7 @@ function setFieldVisibilities(context, item) {
hideElement('#fldPath', context);
}
if (item.Type === 'Series' || item.Type === 'Movie' || item.Type === 'Trailer' || item.Type === 'Person') {
if ([BaseItemKind.Series, BaseItemKind.Season, BaseItemKind.Episode, BaseItemKind.Movie, BaseItemKind.Trailer, BaseItemKind.Person].includes(item.Type)) {
showElement('#fldOriginalName', context);
} else {
hideElement('#fldOriginalName', context);
@ -717,7 +718,7 @@ function setFieldVisibilities(context, item) {
showElement('#fldDisplayOrder', context);
hideElement('.seriesDisplayOrderDescription', context);
context.querySelector('#selectDisplayOrder').innerHTML = '<option value="SortName">' + globalize.translate('SortName') + '</option><option value="PremiereDate">' + globalize.translate('ReleaseDate') + '</option>';
context.querySelector('#selectDisplayOrder').innerHTML = '<option value="Default">' + globalize.translate('DateModified') + '<option value="SortName">' + globalize.translate('SortName') + '</option><option value="PremiereDate">' + globalize.translate('ReleaseDate') + '</option>';
} else if (item.Type === 'Series') {
showElement('#fldDisplayOrder', context);
showElement('.seriesDisplayOrderDescription', context);

View file

@ -87,7 +87,7 @@ function onSelectionChange() {
updateItemSelection(this, this.checked);
}
function showSelection(item, isChecked) {
function showSelection(item, isChecked, addInitialCheck) {
let itemSelectionPanel = item.querySelector('.itemSelectionPanel');
if (!itemSelectionPanel) {
@ -99,7 +99,7 @@ function showSelection(item, isChecked) {
parent.appendChild(itemSelectionPanel);
let cssClass = 'chkItemSelect';
if (isChecked) {
if (isChecked && addInitialCheck) {
cssClass += ' checkedInitial';
}
const checkedAttribute = isChecked ? ' checked' : '';
@ -361,11 +361,11 @@ function combineVersions(apiClient, selection) {
});
}
function showSelections(initialCard) {
function showSelections(initialCard, addInitialCheck) {
import('../../elements/emby-checkbox/emby-checkbox').then(() => {
const cards = document.querySelectorAll('.card');
for (let i = 0, length = cards.length; i < length; i++) {
showSelection(cards[i], initialCard === cards[i]);
showSelection(cards[i], initialCard === cards[i], addInitialCheck);
}
showSelectionCommands();
@ -402,7 +402,7 @@ export default function (options) {
const card = dom.parentWithClass(e.target, 'card');
if (card) {
showSelections(card);
showSelections(card, true);
}
e.preventDefault();
@ -500,7 +500,7 @@ export default function (options) {
touchTarget = null;
if (card) {
showSelections(card);
showSelections(card, true);
}
}
@ -569,7 +569,7 @@ export default function (options) {
}
export const startMultiSelect = (card) => {
showSelections(card);
showSelections(card, false);
};
export const stopMultiSelect = () => {

View file

@ -24,6 +24,7 @@ import { MediaType } from '@jellyfin/sdk/lib/generated-client/models/media-type'
import { MediaError } from 'types/mediaError';
import { getMediaError } from 'utils/mediaError';
import { toApi } from 'utils/jellyfin-apiclient/compat';
import { BaseItemKind } from '@jellyfin/sdk/lib/generated-client/models/base-item-kind.js';
const UNLIMITED_ITEMS = -1;
@ -697,7 +698,7 @@ function sortPlayerTargets(a, b) {
return aVal.localeCompare(bVal);
}
class PlaybackManager {
export class PlaybackManager {
constructor() {
const self = this;
@ -2417,20 +2418,20 @@ class PlaybackManager {
});
}
function rankStreamType(prevIndex, prevSource, mediaSource, streamType, isSecondarySubtitle) {
function rankStreamType(prevIndex, prevSource, mediaStreams, trackOptions, streamType, isSecondarySubtitle) {
if (prevIndex == -1) {
console.debug(`AutoSet ${streamType} - No Stream Set`);
if (streamType == 'Subtitle') {
if (isSecondarySubtitle) {
mediaSource.DefaultSecondarySubtitleStreamIndex = -1;
trackOptions.DefaultSecondarySubtitleStreamIndex = -1;
} else {
mediaSource.DefaultSubtitleStreamIndex = -1;
trackOptions.DefaultSubtitleStreamIndex = -1;
}
}
return;
}
if (!prevSource.MediaStreams || !mediaSource.MediaStreams) {
if (!prevSource.MediaStreams || !mediaStreams) {
console.debug(`AutoSet ${streamType} - No MediaStreams`);
return;
}
@ -2456,7 +2457,7 @@ class PlaybackManager {
}
let newRelIndex = 0;
for (const stream of mediaSource.MediaStreams) {
for (const stream of mediaStreams) {
if (stream.Type != streamType) continue;
let score = 0;
@ -2479,38 +2480,38 @@ class PlaybackManager {
console.debug(`AutoSet ${streamType} - Using ${bestStreamIndex} score ${bestStreamScore}.`);
if (streamType == 'Subtitle') {
if (isSecondarySubtitle) {
mediaSource.DefaultSecondarySubtitleStreamIndex = bestStreamIndex;
trackOptions.DefaultSecondarySubtitleStreamIndex = bestStreamIndex;
} else {
mediaSource.DefaultSubtitleStreamIndex = bestStreamIndex;
trackOptions.DefaultSubtitleStreamIndex = bestStreamIndex;
}
}
if (streamType == 'Audio') {
mediaSource.DefaultAudioStreamIndex = bestStreamIndex;
trackOptions.DefaultAudioStreamIndex = bestStreamIndex;
}
} else {
console.debug(`AutoSet ${streamType} - Threshold not met. Using default.`);
}
}
function autoSetNextTracks(prevSource, mediaSource, audio, subtitle) {
function autoSetNextTracks(prevSource, mediaStreams, trackOptions, audio, subtitle) {
try {
if (!prevSource) return;
if (!mediaSource) {
console.warn('AutoSet - No mediaSource');
if (!mediaStreams) {
console.warn('AutoSet - No mediaStreams');
return;
}
if (audio && typeof prevSource.DefaultAudioStreamIndex == 'number') {
rankStreamType(prevSource.DefaultAudioStreamIndex, prevSource, mediaSource, 'Audio');
rankStreamType(prevSource.DefaultAudioStreamIndex, prevSource, mediaStreams, trackOptions, 'Audio');
}
if (subtitle && typeof prevSource.DefaultSubtitleStreamIndex == 'number') {
rankStreamType(prevSource.DefaultSubtitleStreamIndex, prevSource, mediaSource, 'Subtitle');
rankStreamType(prevSource.DefaultSubtitleStreamIndex, prevSource, mediaStreams, trackOptions, 'Subtitle');
}
if (subtitle && typeof prevSource.DefaultSecondarySubtitleStreamIndex == 'number') {
rankStreamType(prevSource.DefaultSecondarySubtitleStreamIndex, prevSource, mediaSource, 'Subtitle', true);
rankStreamType(prevSource.DefaultSecondarySubtitleStreamIndex, prevSource, mediaStreams, trackOptions, 'Subtitle', true);
}
} catch (e) {
console.error(`AutoSet - Caught unexpected error: ${e}`);
@ -2582,12 +2583,25 @@ class PlaybackManager {
});
}
return Promise.all([promise, player.getDeviceProfile(item)]).then(function (responses) {
const deviceProfile = responses[1];
const apiClient = ServerConnections.getApiClient(item.ServerId);
let mediaSourceId;
const isLiveTv = [BaseItemKind.TvChannel, BaseItemKind.LiveTvChannel].includes(item.Type);
if (!isLiveTv) {
mediaSourceId = playOptions.mediaSourceId || item.Id;
}
const getMediaStreams = isLiveTv ? Promise.resolve([]) : apiClient.getItem(apiClient.getCurrentUserId(), mediaSourceId)
.then(fullItem => {
return fullItem.MediaStreams;
});
return Promise.all([promise, player.getDeviceProfile(item), apiClient.getCurrentUser(), getMediaStreams]).then(function (responses) {
const deviceProfile = responses[1];
const user = responses[2];
const mediaStreams = responses[3];
const mediaSourceId = playOptions.mediaSourceId;
const audioStreamIndex = playOptions.audioStreamIndex;
const subtitleStreamIndex = playOptions.subtitleStreamIndex;
const options = {
@ -2610,9 +2624,20 @@ class PlaybackManager {
// this reference was only needed by sendPlaybackListToPlayer
playOptions.items = null;
const trackOptions = {};
autoSetNextTracks(prevSource, mediaStreams, trackOptions, user.Configuration.RememberAudioSelections, user.Configuration.RememberSubtitleSelections);
if (trackOptions.DefaultAudioStreamIndex != null) {
options.audioStreamIndex = trackOptions.DefaultAudioStreamIndex;
}
if (trackOptions.DefaultSubtitleStreamIndex != null) {
options.subtitleStreamIndex = trackOptions.DefaultSubtitleStreamIndex;
}
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 (trackOptions.DefaultSecondarySubtitleStreamIndex != null) {
mediaSource.DefaultSecondarySubtitleStreamIndex = trackOptions.DefaultSecondarySubtitleStreamIndex;
}
if (mediaSource.DefaultSubtitleStreamIndex == null || mediaSource.DefaultSubtitleStreamIndex < 0) {
mediaSource.DefaultSubtitleStreamIndex = mediaSource.DefaultSecondarySubtitleStreamIndex;

View file

@ -1,17 +1,19 @@
import React, { type FC } from 'react';
import { useSearchSuggestions } from 'hooks/searchHook';
import React, { FunctionComponent } from 'react';
import Loading from 'components/loading/LoadingComponent';
import { appRouter } from '../router/appRouter';
import globalize from '../../lib/globalize';
import LinkButton from 'elements/emby-button/LinkButton';
import { useSearchSuggestions } from 'hooks/searchHook/useSearchSuggestions';
import globalize from 'lib/globalize';
import LinkButton from '../../elements/emby-button/LinkButton';
import '../../elements/emby-button/emby-button';
interface SearchSuggestionsProps {
parentId?: string;
}
type SearchSuggestionsProps = {
parentId?: string | null;
};
const SearchSuggestions: FC<SearchSuggestionsProps> = ({ parentId }) => {
const { isLoading, data: suggestions } = useSearchSuggestions(parentId);
const SearchSuggestions: FunctionComponent<SearchSuggestionsProps> = ({ parentId }) => {
const { isLoading, data: suggestions } = useSearchSuggestions(parentId || undefined);
if (isLoading) return <Loading />;
@ -27,15 +29,12 @@ const SearchSuggestions: FC<SearchSuggestionsProps> = ({ parentId }) => {
</div>
<div className='searchSuggestionsList padded-left padded-right'>
{suggestions?.map((item) => (
<div key={`suggestion-${item.Id}`}>
{suggestions?.map(item => (
<div key={item.Id}>
<LinkButton
className='button-link'
style={{ display: 'inline-block', padding: '0.5em 1em' }}
href={appRouter.getRouteUrl(item)}
style={{
display: 'inline-block',
padding: '0.5em 1em'
}}
>
{item.Name}
</LinkButton>

View file

@ -6,7 +6,7 @@ import Dashboard from '../../../utils/dashboard';
import { getParameterByName } from '../../../utils/url.ts';
function load(page, device, deviceOptions) {
page.querySelector('#txtCustomName', page).value = deviceOptions.CustomName || '';
page.querySelector('#txtCustomName', page).value = deviceOptions?.CustomName || '';
page.querySelector('.reportedName', page).innerText = device.Name || '';
}
@ -14,13 +14,13 @@ function loadData() {
const page = this;
loading.show();
const id = getParameterByName('id');
const promise1 = ApiClient.getJSON(ApiClient.getUrl('Devices/Info', {
const device = ApiClient.getJSON(ApiClient.getUrl('Devices/Info', {
Id: id
}));
const promise2 = ApiClient.getJSON(ApiClient.getUrl('Devices/Options', {
const deviceOptions = ApiClient.getJSON(ApiClient.getUrl('Devices/Options', {
Id: id
}));
Promise.all([promise1, promise2]).then(function (responses) {
})).catch(() => undefined);
Promise.all([device, deviceOptions]).then(function (responses) {
load(page, responses[0], responses[1]);
loading.hide();
});

View file

@ -20,7 +20,7 @@ function loadPage(page, config, systemInfo) {
page.querySelector('#chkHardwareEncoding').checked = config.EnableHardwareEncoding;
page.querySelector('#chkAllowHevcEncoding').checked = config.AllowHevcEncoding;
page.querySelector('#chkAllowAv1Encoding').checked = config.AllowAv1Encoding;
$('#selectVideoDecoder', page).val(config.HardwareAccelerationType);
$('#selectVideoDecoder', page).val(config.HardwareAccelerationType || 'none');
$('#selectThreadCount', page).val(config.EncodingThreadCount);
page.querySelector('#chkEnableAudioVbr').checked = config.EnableAudioVbr;
$('#txtDownMixAudioBoost', page).val(config.DownMixAudioBoost);
@ -34,18 +34,18 @@ function loadPage(page, config, systemInfo) {
page.querySelector('#chkTonemapping').checked = config.EnableTonemapping;
page.querySelector('#chkVppTonemapping').checked = config.EnableVppTonemapping;
page.querySelector('#chkVideoToolboxTonemapping').checked = config.EnableVideoToolboxTonemapping;
page.querySelector('#selectTonemappingAlgorithm').value = config.TonemappingAlgorithm;
page.querySelector('#selectTonemappingMode').value = config.TonemappingMode;
page.querySelector('#selectTonemappingRange').value = config.TonemappingRange;
page.querySelector('#selectTonemappingAlgorithm').value = config.TonemappingAlgorithm || 'none';
page.querySelector('#selectTonemappingMode').value = config.TonemappingMode || 'auto';
page.querySelector('#selectTonemappingRange').value = config.TonemappingRange || 'auto';
page.querySelector('#txtTonemappingDesat').value = config.TonemappingDesat;
page.querySelector('#txtTonemappingPeak').value = config.TonemappingPeak;
page.querySelector('#txtTonemappingParam').value = config.TonemappingParam || '';
page.querySelector('#txtVppTonemappingBrightness').value = config.VppTonemappingBrightness;
page.querySelector('#txtVppTonemappingContrast').value = config.VppTonemappingContrast;
page.querySelector('#selectEncoderPreset').value = config.EncoderPreset || '';
page.querySelector('#selectEncoderPreset').value = config.EncoderPreset || 'auto';
page.querySelector('#txtH264Crf').value = config.H264Crf || '';
page.querySelector('#txtH265Crf').value = config.H265Crf || '';
page.querySelector('#selectDeinterlaceMethod').value = config.DeinterlaceMethod || '';
page.querySelector('#selectDeinterlaceMethod').value = config.DeinterlaceMethod || 'yadif';
page.querySelector('#chkDoubleRateDeinterlacing').checked = config.DeinterlaceDoubleRate;
page.querySelector('#chkEnableSubtitleExtraction').checked = config.EnableSubtitleExtraction || false;
page.querySelector('#chkEnableThrottling').checked = config.EnableThrottling || false;
@ -139,7 +139,7 @@ function onSubmit() {
});
};
if ($('#selectVideoDecoder', form).val()) {
if ($('#selectVideoDecoder', form).val() !== 'none') {
alert({
title: globalize.translate('TitleHardwareAcceleration'),
text: globalize.translate('HardwareAccelerationWarning')
@ -205,7 +205,7 @@ $(document).on('pageinit', '#encodingSettingsPage', function () {
}
const isHwaSelected = [ 'amf', 'nvenc', 'qsv', 'vaapi', 'rkmpp', 'videotoolbox' ].includes(this.value);
if (this.value === '' || isHwaSelected) {
if (this.value === 'none' || isHwaSelected) {
page.querySelector('.tonemappingOptions').classList.remove('hide');
} else {
page.querySelector('.tonemappingOptions').classList.add('hide');
@ -245,7 +245,7 @@ $(document).on('pageinit', '#encodingSettingsPage', function () {
page.querySelector('.fldEnhancedNvdec').classList.add('hide');
}
if (this.value) {
if (this.value !== 'none') {
page.querySelector('.hardwareAccelerationOptions').classList.remove('hide');
} else {
page.querySelector('.hardwareAccelerationOptions').classList.add('hide');

View file

@ -1735,7 +1735,7 @@ function renderCollectionItemType(page, parentItem, type, items) {
items: items,
shape: shape,
showTitle: true,
showYear: type.mediaType === 'Video' || type.type === 'Series',
showYear: type.mediaType === 'Video' || type.type === 'Series' || type.type === 'Movie',
centerText: true,
lazy: true,
showDetailsMenu: true,

View file

@ -31,11 +31,16 @@ export default function (view, params, tabContent, options) {
}
function shuffle() {
ApiClient.getItem(
ApiClient.getCurrentUserId(),
params.topParentId
).then((item) => {
playbackManager.shuffle(item);
isLoading = true;
loading.show();
const newQuery = { ...query, SortBy: 'Random', StartIndex: 0, Limit: 300 };
return ApiClient.getItems(ApiClient.getCurrentUserId(), newQuery).then(({ Items }) => {
playbackManager.play({
items: Items,
autoplay: true
});
}).finally(() => {
isLoading = false;
});
}

View file

@ -1,6 +1,7 @@
import React, { FunctionComponent } from 'react';
import IconButtonElement from './IconButtonElement';
import SectionTitleLinkElement from './SectionTitleLinkElement';
import LinkButton from './emby-button/LinkButton';
import globalize from 'lib/globalize';
type IProps = {
SectionClassName?: string;
@ -28,11 +29,13 @@ const SectionTitleContainer: FunctionComponent<IProps> = ({ SectionClassName, ti
icon={btnIcon}
/>}
{isLinkVisible && <SectionTitleLinkElement
{isLinkVisible && <LinkButton
className='raised button-alt headerHelpButton'
title='Help'
url={url}
/>}
target='_blank'
rel='noopener noreferrer'
href={url}>
{globalize.translate('Help')}
</LinkButton>}
</div>
);

View file

@ -1,35 +0,0 @@
import React, { FunctionComponent } from 'react';
import globalize from 'lib/globalize';
const createLinkElement = ({ className, title, href }: { className?: string, title?: string, href?: string }) => ({
__html: `<a
is="emby-linkbutton"
rel="noopener noreferrer"
class="${className}"
target="_blank"
href="${href}"
>
${title}
</a>`
});
type IProps = {
title?: string;
className?: string;
url?: string
};
const SectionTitleLinkElement: FunctionComponent<IProps> = ({ className, title, url }: IProps) => {
return (
<div
dangerouslySetInnerHTML={createLinkElement({
className: className,
title: globalize.translate(title),
href: url
})}
/>
);
};
export default SectionTitleLinkElement;

View file

@ -20,6 +20,7 @@ const LinkButton: React.FC<LinkButtonProps> = ({
isAutoHideEnabled,
href,
target,
onClick,
children,
...rest
}) => {
@ -41,7 +42,8 @@ const LinkButton: React.FC<LinkButtonProps> = ({
} else {
e.preventDefault();
}
}, [ href, target ]);
onClick?.(e);
}, [ href, target, onClick ]);
if (isAutoHideEnabled === true && !appHost.supports('externallinks')) {
return null;

View file

@ -0,0 +1 @@
export * from './useGetDownload';

View file

@ -0,0 +1,34 @@
import type { AxiosRequestConfig } from 'axios';
import type { LibraryApiGetDownloadRequest } from '@jellyfin/sdk/lib/generated-client';
import { getLibraryApi } from '@jellyfin/sdk/lib/utils/api/library-api';
import { queryOptions, useQuery } from '@tanstack/react-query';
import { type JellyfinApiContext, useApi } from 'hooks/useApi';
const getDownload = async (
apiContext: JellyfinApiContext,
params: LibraryApiGetDownloadRequest,
options?: AxiosRequestConfig
) => {
const { api, user } = apiContext;
if (!api) throw new Error('[getDownload] No API instance available');
if (!user?.Id) throw new Error('[getDownload] No User ID provided');
const response = await getLibraryApi(api).getDownload(params, options);
return response.data;
};
export const getDownloadQuery = (
apiContext: JellyfinApiContext,
params: LibraryApiGetDownloadRequest
) =>
queryOptions({
queryKey: ['Download', params.itemId],
queryFn: ({ signal }) => getDownload(apiContext, params, { signal }),
enabled: !!apiContext.api && !!apiContext.user?.Id && !!params.itemId
});
export const useGetDownload = (params: LibraryApiGetDownloadRequest) => {
const apiContext = useApi();
return useQuery(getDownloadQuery(apiContext, params));
};

View file

@ -0,0 +1,5 @@
export * from './useCancelSeriesTimer';
export * from './useCancelTimer';
export * from './useGetChannel';
export * from './useGetSeriesTimer';
export * from './useGetTimer';

View file

@ -0,0 +1,24 @@
import type { LiveTvApiCancelSeriesTimerRequest } from '@jellyfin/sdk/lib/generated-client';
import { getLiveTvApi } from '@jellyfin/sdk/lib/utils/api/live-tv-api';
import { useMutation } from '@tanstack/react-query';
import { type JellyfinApiContext, useApi } from 'hooks/useApi';
const cancelSeriesTimer = async (
apiContext: JellyfinApiContext,
params: LiveTvApiCancelSeriesTimerRequest
) => {
const { api } = apiContext;
if (!api) throw new Error('[cancelSeriesTimer] No API instance available');
const response = await getLiveTvApi(api).cancelSeriesTimer(params);
return response.data;
};
export const useCancelSeriesTimer = () => {
const apiContext = useApi();
return useMutation({
mutationFn: (params: LiveTvApiCancelSeriesTimerRequest) =>
cancelSeriesTimer(apiContext, params)
});
};

View file

@ -0,0 +1,24 @@
import type { LiveTvApiCancelTimerRequest } from '@jellyfin/sdk/lib/generated-client';
import { getLiveTvApi } from '@jellyfin/sdk/lib/utils/api/live-tv-api';
import { useMutation } from '@tanstack/react-query';
import { type JellyfinApiContext, useApi } from 'hooks/useApi';
const cancelTimer = async (
apiContext: JellyfinApiContext,
params: LiveTvApiCancelTimerRequest
) => {
const { api } = apiContext;
if (!api) throw new Error('[cancelTimer] No API instance available');
const response = await getLiveTvApi(api).cancelTimer(params);
return response.data;
};
export const useCancelTimer = () => {
const apiContext = useApi();
return useMutation({
mutationFn: (params: LiveTvApiCancelTimerRequest) =>
cancelTimer(apiContext, params)
});
};

View file

@ -0,0 +1,41 @@
import type { AxiosRequestConfig } from 'axios';
import type { LiveTvApiGetChannelRequest } from '@jellyfin/sdk/lib/generated-client';
import { getLiveTvApi } from '@jellyfin/sdk/lib/utils/api/live-tv-api';
import { queryOptions, useQuery } from '@tanstack/react-query';
import { type JellyfinApiContext, useApi } from 'hooks/useApi';
const getChannel = async (
apiContext: JellyfinApiContext,
params: LiveTvApiGetChannelRequest,
options?: AxiosRequestConfig
) => {
const { api, user } = apiContext;
if (!api) throw new Error('[getChannel] No API instance available');
if (!user?.Id) throw new Error('[getChannel] No User ID provided');
const response = await getLiveTvApi(api).getChannel(
{
userId: user.Id,
...params
},
options
);
return response.data;
};
export const getChannelQuery = (
apiContext: JellyfinApiContext,
params: LiveTvApiGetChannelRequest
) =>
queryOptions({
queryKey: ['Channel', params.channelId],
queryFn: ({ signal }) => getChannel(apiContext, params, { signal }),
enabled:
!!apiContext.api && !!apiContext.user?.Id && !!params.channelId
});
export const useGetChannel = (params: LiveTvApiGetChannelRequest) => {
const apiContext = useApi();
return useQuery(getChannelQuery(apiContext, params));
};

View file

@ -0,0 +1,35 @@
import type { AxiosRequestConfig } from 'axios';
import type { LiveTvApiGetSeriesTimerRequest } from '@jellyfin/sdk/lib/generated-client';
import { getLiveTvApi } from '@jellyfin/sdk/lib/utils/api/live-tv-api';
import { queryOptions, useQuery } from '@tanstack/react-query';
import { type JellyfinApiContext, useApi } from 'hooks/useApi';
const getSeriesTimer = async (
apiContext: JellyfinApiContext,
params: LiveTvApiGetSeriesTimerRequest,
options?: AxiosRequestConfig
) => {
const { api } = apiContext;
if (!api) throw new Error('[getSeriesTimer] No API instance available');
const response = await getLiveTvApi(api).getSeriesTimer(params, options);
return response.data;
};
export const getSeriesTimerQuery = (
apiContext: JellyfinApiContext,
params: LiveTvApiGetSeriesTimerRequest
) =>
queryOptions({
queryKey: ['SeriesTimer', params.timerId],
queryFn: ({ signal }) => getSeriesTimer(apiContext, params, { signal }),
enabled: !!apiContext.api && !!apiContext.user?.Id && !!params.timerId
});
export const useGetSeriesTimer = (
requestParameters: LiveTvApiGetSeriesTimerRequest
) => {
const apiContext = useApi();
return useQuery(getSeriesTimerQuery(apiContext, requestParameters));
};

View file

@ -0,0 +1,33 @@
import type { AxiosRequestConfig } from 'axios';
import type { LiveTvApiGetTimerRequest } from '@jellyfin/sdk/lib/generated-client';
import { getLiveTvApi } from '@jellyfin/sdk/lib/utils/api/live-tv-api';
import { queryOptions, useQuery } from '@tanstack/react-query';
import { type JellyfinApiContext, useApi } from 'hooks/useApi';
const getTimer = async (
currentApi: JellyfinApiContext,
params: LiveTvApiGetTimerRequest,
options?: AxiosRequestConfig
) => {
const { api } = currentApi;
if (!api) throw new Error('[getTimer] No API instance available');
const response = await getLiveTvApi(api).getTimer(params, options);
return response.data;
};
export const getTimerQuery = (
apiContext: JellyfinApiContext,
params: LiveTvApiGetTimerRequest
) =>
queryOptions({
queryKey: ['Timer', params.timerId],
queryFn: ({ signal }) => getTimer(apiContext, params, { signal }),
enabled: !!apiContext.api && !!apiContext.user?.Id && !!params.timerId
});
export const useGetTimer = (requestParameters: LiveTvApiGetTimerRequest) => {
const apiContext = useApi();
return useQuery(getTimerQuery(apiContext, requestParameters));
};

View file

@ -0,0 +1 @@
export * from './useDeleteAlternateSources';

View file

@ -0,0 +1,24 @@
import type { VideosApiDeleteAlternateSourcesRequest } from '@jellyfin/sdk/lib/generated-client';
import { getVideosApi } from '@jellyfin/sdk/lib/utils/api/videos-api';
import { useMutation } from '@tanstack/react-query';
import { type JellyfinApiContext, useApi } from 'hooks/useApi';
const deleteAlternateSources = async (
apiContext: JellyfinApiContext,
params: VideosApiDeleteAlternateSourcesRequest
) => {
const { api } = apiContext;
if (!api) throw new Error('[deleteAlternateSources] No API instance available');
const response = await getVideosApi(api).deleteAlternateSources(params);
return response.data;
};
export const useDeleteAlternateSources = () => {
const apiContext = useApi();
return useMutation({
mutationFn: (params: VideosApiDeleteAlternateSourcesRequest) =>
deleteAlternateSources(apiContext, params)
});
};

View file

@ -121,6 +121,14 @@ class HtmlAudioPlayer {
normalizationGain =
options.mediaSource.albumNormalizationGain
?? options.item.NormalizationGain;
} else {
console.debug('normalization disabled');
return;
}
if (!self.gainNode) {
addGainElement(elem);
if (!self.gainNode) return;
}
if (normalizationGain) {
@ -276,8 +284,6 @@ class HtmlAudioPlayer {
self._mediaElement = elem;
addGainElement(elem);
return elem;
}
@ -317,7 +323,7 @@ class HtmlAudioPlayer {
function onVolumeChange() {
if (!self._isFadingOut) {
htmlMediaHelper.saveVolume(this.volume);
if (browser.safari) {
if (browser.safari && self.gainNode) {
self.gainNode.gain.value = this.volume * self.normalizationGain;
}
Events.trigger(self, 'volumechange');

View file

@ -1107,16 +1107,28 @@ export default function (options) {
let vp9VideoRangeTypes = 'SDR';
let av1VideoRangeTypes = 'SDR';
if (browser.tizenVersion >= 3) {
hevcVideoRangeTypes += '|DOVIWithSDR';
}
if (supportsHdr10(options)) {
hevcVideoRangeTypes += '|HDR10';
vp9VideoRangeTypes += '|HDR10';
av1VideoRangeTypes += '|HDR10';
if (browser.tizenVersion >= 3) {
hevcVideoRangeTypes += '|DOVIWithHDR10';
}
}
if (supportsHlg(options)) {
hevcVideoRangeTypes += '|HLG';
vp9VideoRangeTypes += '|HLG';
av1VideoRangeTypes += '|HLG';
if (browser.tizenVersion >= 3) {
hevcVideoRangeTypes += '|DOVIWithHLG';
}
}
if (supportsDolbyVision(options)) {

View file

@ -43,7 +43,7 @@ const KeyNames = {
/**
* Keys used for keyboard navigation.
*/
const NavigationKeys = ['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown'];
const NavigationKeys = ['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown', 'BrowserHome', 'Find'];
/**
* Keys used for media playback control.
@ -185,6 +185,13 @@ export function enable() {
}
break;
case 'Find':
inputManager.handleCommand('search');
break;
case 'BrowserHome':
inputManager.handleCommand('home');
break;
case 'MediaPlay':
inputManager.handleCommand('play');
break;

View file

@ -311,7 +311,7 @@
"HeaderYears": "Гады",
"LabelValue": "Значэнне",
"Image": "Малюнак",
"LastSeen": "Апошні раз бачылі {0}",
"LastSeen": "Апошняе дзеянне {0}",
"List": "Спіс",
"Live": "Трансляцыя",
"MediaInfoAnamorphic": "Анаморфны",
@ -1760,7 +1760,7 @@
"LogLevel.Error": "Памылка",
"LabelTrackGain": "Узмацненне дарожкі",
"GoHome": "На галоўную",
"SelectAudioNormalizationHelp": "Узмацненне дарожкі - рэгулюе гучнасць кожнай дарожкі, каб яны прайграваліся з аднолькавай гучнасцю. Узмацненне альбома - рэгулюе гучнасць толькі ўсіх дарожак у альбоме, захоўваючы дынамічны дыяпазон альбома.",
"SelectAudioNormalizationHelp": "Узмацненне дарожкі - рэгулюе гучнасць кожнай дарожкі, каб яны прайграваліся з аднолькавай гучнасцю. Узмацненне альбома - рэгулюе гучнасць толькі ўсіх дарожак у альбоме, захоўваючы дынамічны дыяпазон альбома. Пераключэнне паміж \"Выкл\" і іншымі опцыямі патрабуе перазапуску бягучага прайгравання.",
"SearchResultsEmpty": "Выбачайце! Няма вынікаў для \"{0}\"",
"UnknownError": "Адбылася невядомая памылка.",
"LabelIsHearingImpaired": "Для людзей з парушэннем слыху (SDH)",
@ -1893,5 +1893,15 @@
"PluginEnableError": "Адбылася памылка пры ўключэнні плагіна.",
"PluginLoadConfigError": "Адбылася памылка падчас атрымання старонак канфігурацыі плагіна.",
"PluginLoadRepoError": "Адбылася памылка падчас атрымання дэталяў плагіна з рэпазітара.",
"PluginUninstallError": "Адбылася памылка пры выдаленні плагіна."
"PluginUninstallError": "Адбылася памылка пры выдаленні плагіна.",
"HeaderAudioAdvanced": "Пашыраны аўдыё",
"EnableHi10p": "Уключыць профіль H.264 High 10",
"HeaderUploadLyrics": "Спампаваць тэксты песень",
"DateModified": "Дата змяненняў",
"DisableVbrAudioEncodingHelp": "Забараніць серверу кадаваць аўдыя з VBR для гэтага кліента.",
"HeaderPreviewLyrics": "Папярэдні прагляд тэкстаў песень",
"LabelIsSynced": "Сінхранізавана",
"LabelDuration": "Працягласць",
"NoLyricsSearchResultsFound": "Тэксты песень не знойдзены.",
"FallbackMaxStreamingBitrateHelp": "Максімальны бітрэйт плыні выкарыстоўваецца ў якасці запаснога, калі ffprobe не можа вызначыць бітрэйт зыходнага патоку. Гэта дапамагае прадухіліць кліенты ад запытаў празмерна высокага бітрэйту транскадавання, які можа прывесці да збою прайгравальніка і перагрузкі кадавальніка."
}

View file

@ -326,5 +326,10 @@
"ColorPrimaries": "কালার প্রাইমারি",
"AllowCollectionManagement": "এই ব্যবহারকারীকে কালেকশন্স গুলি পরিচালনা করার অনুমতি দিন",
"AllowSegmentDeletion": "অংশগুলি মুছে ফেলুন",
"AllowSegmentDeletionHelp": "পুরানো বিভাগগুলি ক্লায়েন্টের কাছে পাঠানোর পরে মুছে ফেলুন। এটি ডিস্কে পুরো ট্রান্সকোডেড ফাইল সংরক্ষণ করতে বাধা দেয়। এটি কেবল থ্রোটলিং সক্ষম করে কাজ করবে। আপনি যদি প্লেব্যাক সমস্যার সম্মুখীন হন তবে এটি বন্ধ করুন।"
"AllowSegmentDeletionHelp": "পুরানো বিভাগগুলি ক্লায়েন্টের কাছে পাঠানোর পরে মুছে ফেলুন। এটি ডিস্কে পুরো ট্রান্সকোডেড ফাইল সংরক্ষণ করতে বাধা দেয়। এটি কেবল থ্রোটলিং সক্ষম করে কাজ করবে। আপনি যদি প্লেব্যাক সমস্যার সম্মুখীন হন তবে এটি বন্ধ করুন।",
"AirPlay": "এয়ারপ্লে",
"AllowContentWithTagsHelp": "শুধুমাত্র নির্দিষ্ট ট্যাগগুলির মধ্যে অন্তত একটি সহ মিডিয়া দেখান।",
"Alternate": "বিকল্প",
"AllowSubtitleManagement": "এই ব্যবহারকারীকে সাবটাইটেল সম্পাদনা করার অনুমতি দিন",
"AllowFmp4TranscodingContainerHelp": "HEVC এবং HDR বিষয়বস্তু সক্ষম করতে এই টিউনারটির জন্য fMP4 ট্রান্সকোডিং কন্টেইনারকে অনুমতি দিন। সমস্ত টিউনার এই ধারকটির সাথে সামঞ্জস্যপূর্ণ নয়৷ আপনি যদি প্লেব্যাক সমস্যা অনুভব করেন তবে এটি অক্ষম করুন।"
}

View file

@ -1780,7 +1780,7 @@
"LabelSelectAudioNormalization": "Normalizace hlasitosti",
"LabelAlbumGain": "Na úrovni alba",
"LabelTrackGain": "Na úrovni skladby",
"SelectAudioNormalizationHelp": "Normalizace na úrovni skladby upraví hlasitost všech skladeb tak, aby byla všude stejná. Normalizace na úrovni alba upraví hlasitost všech skladeb tak, aby byla hlasitost stejná v rámci jednotlivých alb.",
"SelectAudioNormalizationHelp": "Normalizace na úrovni skladby upraví hlasitost všech skladeb tak, aby byla všude stejná. Normalizace na úrovni alba upraví hlasitost všech skladeb tak, aby byla hlasitost stejná v rámci jednotlivých alb. Vypnutí a následné zapnutí vyžaduje restart aktuálně hrající skladby.",
"SearchResultsEmpty": "Pro “{0}” nebylo nic nalezeno",
"HeaderAllRecordings": "Všechny nahrávky",
"LabelBuildVersion": "Verze sestavení",
@ -1858,7 +1858,7 @@
"LabelEncodingFormatOptions": "Možnosti formátu kódování",
"EncodingFormatHelp": "Vyberte formát, do kterého by měly být překódovány videa. Pokud není k dispozici hardwarová akcelerace pro vybraný formát, bude použito softwarové kódování. Kódování do formátu H.264 bude vždy povoleno.",
"LabelTrickplayAccelEncoding": "Povolit hardwarově akcelerované kódování MJPEG",
"LabelTrickplayAccelEncodingHelp": "Tato možnost je momentálně dostupná pouze při použití QSV, VAAPI a VideoToolbox. Nemá vliv na ostatní hardwarovou akceleraci.",
"LabelTrickplayAccelEncodingHelp": "Tato možnost je momentálně dostupná pouze při použití QSV, VA-API, VideoToolbox a RKMPP. Nemá vliv na ostatní hardwarovou akceleraci.",
"EnableLibrary": "Povolit knihovnu",
"EnableLibraryHelp": "Vypnutím knihovny ji skryjete ze všech míst, kde je uživateli zobrazena.",
"ConfirmDeleteLyrics": "Písně budou odstraněny ze systému i knihovny médií. Opravdu chcete pokračovat?",
@ -1950,5 +1950,22 @@
"AllowFmp4TranscodingContainerHelp": "Povolením kontejneru fMP4 pro překódování umožníte tomuto tuneru pracovat s obsahem ve formátu HEVC a s HDR. Kompatibilní jsou jen některé tunery. Pokud máte potíže s přehráváním, tuto možnost vypněte.",
"LabelSaveTrickplayLocally": "Uložit obrázky trickplay k médiím",
"LabelSaveTrickplayLocallyHelp": "Uložením obrázků trickplay do složek s médii se usnadní jejich přesun a přístup k nim.",
"ReplaceTrickplayImages": "Nahradit existující obrázky trickplay"
"ReplaceTrickplayImages": "Nahradit existující obrázky trickplay",
"MessageCancelSeriesTimerError": "Při rušení časovače seriálu došlo k chybě",
"DateModified": "Datum upravení",
"LabelAudioTagSettings": "Nastavení zvukových značek",
"LabelCustomTagDelimiters": "Vlastní oddělovač značek",
"LabelCustomTagDelimitersHelp": "Znaky, které budou považovány za oddělovače značek.",
"LabelDelimiterWhitelistHelp": "Položky, které budou vyloučeny z rozdělování značek. Každý řádek je jedna položka.",
"LabelDelimiterWhitelist": "Seznam výjimek při oddělování",
"LabelLyricDownloaders": "Stahovače textů písní",
"LyricDownloadersHelp": "Povolit a seřadit své stahovače textů písní podle preferovaného pořadí.",
"MessageCancelTimerError": "Při rušení časovače došlo k chybě",
"MessageSplitVersionsError": "Při rozdělování verzí došlo k chybě",
"PreferNonstandardArtistsTag": "Preferovat značku ARTISTS, pokud existuje",
"PreferNonstandardArtistsTagHelp": "Použít nestandardní značku ARTISTS místo ARTIST, pokud je k dispozici.",
"RenderPgsSubtitle": "Experimentální rendrování titulků ve formátu PGS",
"RenderPgsSubtitleHelp": "Zda má klient zobrazit titulky ve formátu PGS místo jejich vypálení do obrazu. Můžete se tak vyhnout překódování na serveru výměnou za horší výkon klienta.",
"UseCustomTagDelimiters": "Použít vlastní oddělovač značek",
"UseCustomTagDelimitersHelp": "Rozdělit značky pro umělce a žánry pomocí vlastních znaků."
}

View file

@ -1085,7 +1085,7 @@
"LearnHowYouCanContribute": "Lær hvordan du kan bidrage.",
"LeaveBlankToNotSetAPassword": "Du kan lade dette felt være tomt hvis du ikke ønsker adgangskode.",
"List": "Liste",
"Live": "Live",
"Live": "Direkte",
"LiveTV": "Direkte TV",
"Logo": "Logo",
"ManageRecording": "Håndtér optagelse",
@ -1095,7 +1095,7 @@
"MediaInfoInterlaced": "Interlaceret",
"MediaInfoLayout": "Udlæg",
"MediaInfoRefFrames": "Ref billeder",
"MediaInfoSampleRate": "Sample rate",
"MediaInfoSampleRate": "Samplingsfrekvens",
"MediaIsBeingConverted": "Mediet bliver konverteret til et format der er kompatibel med enheden der afspiller mediet.",
"Menu": "Menu",
"MessageImageFileTypeAllowed": "Kun JPEG og PNG filer er understøttet.",
@ -1341,9 +1341,9 @@
"MessagePlaybackError": "Der opstod en fejl under afspilning af denne fil på din Google Cast modtager.",
"MessageChromecastConnectionError": "Din Google Cast modtager kan ikke komme i kontakt med Jellyfin serveren. Undersøg venligst forbindelsen og prøv igen.",
"LabelPlaybackInfo": "Afspilningsinformation",
"Remuxing": "Remuxing",
"Remuxing": "Ompakning",
"AspectRatioFill": "Udfyld",
"AspectRatioCover": "Cover",
"AspectRatioCover": "Omslag",
"EnableFallbackFont": "Aktiver fald tilbage på skrifttype",
"Writers": "Forfattere",
"ViewAlbumArtist": "Vis album kunstner",
@ -1369,7 +1369,7 @@
"QuickConnectAuthorizeFail": "Ukendt Quick Connect kode",
"QuickConnectAuthorizeCode": "Angiv kode {0} for at logge ind",
"QuickConnectActivationSuccessful": "Aktivering blev gennemført",
"QuickConnect": "Quick Connect",
"QuickConnect": "Hurtigtilkobling",
"PluginFromRepo": "{0} fra arkiv {1}",
"Profile": "Profil",
"PreviousTrack": "Gå til forrige",
@ -1603,7 +1603,7 @@
"Remixer": "Remixer",
"ReleaseGroup": "Udgivelsesgruppe",
"Production": "Produktion",
"Print": "Print",
"Print": "Udskriv",
"PreviousChapter": "Sidste kapitel",
"AllowEmbeddedSubtitlesAllowTextOption": "Tillad tekst",
"AllowEmbeddedSubtitlesAllowImageOption": "Tillad billede",
@ -1749,7 +1749,7 @@
"Notifications": "Notifikationer",
"PleaseConfirmRepositoryInstallation": "Venligst klik OK for at bekræfte at du har læst ovenstående og ønsker at fortsætte med installationen af plugin repository.",
"SaveRecordingImagesHelp": "Gem billeder fra EPG listings udbyder samt billeder fra side media.",
"SelectAudioNormalizationHelp": "Track gain - justerer volumen for hvert track så de afspiller med samme volume. Album gain - justerer volumen kun volumen for alle tracks i et album, samt bevarer albummets dynamic range.",
"SelectAudioNormalizationHelp": "Track gain - justerer volumen for hvert track så de afspiller med samme volume. Album gain - justerer volumen kun volumen for alle tracks i et album, samt bevarer albummets dynamic range. Skift mellem \"Fra\" og andre muligheder kræver genstart af den indeværende afspilning.",
"Select": "Vælg",
"LabelLevel": "Niveau",
"LabelMediaDetails": "Media detaljer",
@ -1875,7 +1875,7 @@
"Translator": "Oversætter",
"ViewLyrics": "Se sangtekst",
"LabelTrickplayAccelEncoding": "Aktivér hardware acceleret MJPEG kodning",
"LabelTrickplayAccelEncodingHelp": "På nuværende tidspunkt kun tilgængeligt på QSV, VAAPI og VideoToolbox; denne indstilling har ingen effekt på andre hardware accelerationsmetoder.",
"LabelTrickplayAccelEncodingHelp": "På nuværende tidspunkt kun tilgængeligt på QSV, VA-API, VideoToolbox og RKMPP; denne indstilling har ingen effekt på andre hardware accelerationsmetoder.",
"HeaderNoLyrics": "Ingen sangtekst blev fundet",
"HeaderVideoAdvanced": "Video Avanceret",
"PlaylistPublic": "Tillad offentlig adgang",
@ -1924,7 +1924,7 @@
"PreviewLyrics": "Gennemse sangtekster",
"SearchForLyrics": "Find sangtekster",
"LabelRepository": "Arkiv",
"AllowTonemappingSoftwareHelp": "Tone-mapping kan transformere det dynamiske område af en video fra HDR til SDR, uden tab af billeddetalje og farver, hvilket er meget vigtige informationer for at representere den originale scene. Virker lige nu kun med 10bit HDR10 og HLG videoer.",
"AllowTonemappingSoftwareHelp": "Tone-mapping kan transformere det dynamiske område af en video fra HDR til SDR, uden tab af billeddetalje og farver, hvilket er meget vigtige informationer for at repræsentere den originale scene. Virker lige nu kun med 10bit HDR10-, HLG- og DoVi-videoer.",
"HeaderAddLyrics": "Tilføj sangtekst",
"LabelNoChangelog": "Ingen ændringer fortaget for denne udgivelse.",
"LabelSelectPreferredTranscodeVideoCodec": "Fforetrukne video codec til omkodning",

View file

@ -134,8 +134,8 @@
"Disc": "Disk",
"Disconnect": "Verbindung trennen",
"Display": "Anzeige",
"DisplayInMyMedia": "Auf Homescreen anzeigen",
"DisplayInOtherHomeScreenSections": "Bereiche wie 'Neueste Medien' oder 'Weiterschauen' auf dem Homescreen anzeigen",
"DisplayInMyMedia": "Auf Startbildschirm anzeigen",
"DisplayInOtherHomeScreenSections": "Bereiche wie 'Neueste Medien' oder 'Weiterschauen' auf dem Startbildschirm anzeigen",
"DisplayMissingEpisodesWithinSeasons": "Fehlende Folgen innerhalb von Staffeln anzeigen",
"DisplayMissingEpisodesWithinSeasonsHelp": "Dies muss in den Servereinstellungen auch für TV-Bibliotheken aktiviert werden.",
"DisplayModeHelp": "Wähle den für die Oberfläche zu verwendenden Layoutstil.",
@ -1860,7 +1860,7 @@
"NonBlockingScan": "Non Blocking - reiht Erstellung ein, kehrt dann zurück",
"BlockingScan": "Blocking - reiht Erstellung ein, blockiert Scan bis fertig",
"LabelTrickplayAccelEncoding": "Hardwarebeschleunigte MJPEG-Enkodierung aktivieren",
"LabelTrickplayAccelEncodingHelp": "Momentan nur für QSV und VAAPI verfügbar. Diese Option hat für andere Methoden keine Auswirkungen.",
"LabelTrickplayAccelEncodingHelp": "Derzeit nur auf QSV, VA-API, VideoToolbox und RKMPP verfügbar, diese Option hat keine Auswirkungen auf andere Methoden zur Hardwarebeschleunigung.",
"Lyrics": "Songtexte",
"ConfirmDeleteLyrics": "Das Löschen dieses Songtextes löscht die Datei vom Laufwerk und in deiner Medienbibliothek. Bist du wirklich sicher?",
"DeleteLyrics": "Songtexte löschen",
@ -1940,5 +1940,28 @@
"DisableVbrAudioEncodingHelp": "Verhindern Sie, dass der Server Audio mit VBR für diesen Client kodiert.",
"HeaderAudioAdvanced": "Erweiterter Ton",
"LabelAlwaysRemuxFlacAudioFiles": "FLAC-Audiodateien immer wieder neu mischen",
"LabelAlwaysRemuxMp3AudioFiles": "MP3-Audiodateien immer wieder neu mischen"
"LabelAlwaysRemuxMp3AudioFiles": "MP3-Audiodateien immer wieder neu mischen",
"LabelAllowFmp4TranscodingContainer": "fMP4-Transkodierungscontainer zulassen",
"FallbackMaxStreamingBitrateHelp": "Die maximale Streaming-Bitrate wird als Fallback verwendet, wenn ffprobe die Bitrate des Quellstreams nicht ermitteln kann. Dadurch wird verhindert, dass Clients eine zu hohe Transcodierungs-Bitrate anfordern, was zu einem Ausfall des Players und einer Überlastung des Encoders führen könnte.",
"AllowFmp4TranscodingContainerHelp": "Erlauben Sie den fMP4-Transcodierungscontainer für diesen Tuner, um HEVC- und HDR-Inhalte zu aktivieren. Nicht alle Tuner sind mit diesem Container kompatibel. Deaktivieren Sie dies, wenn bei der Wiedergabe Probleme auftreten.",
"AllowStreamSharingHelp": "Erlauben Sie Jellyfin, den MPEG-Stream vom Tuner zu duplizieren und diesen duplizierten Stream an seine Clients weiterzugeben. Dies ist nützlich, wenn der Tuner eine Gesamtstreamanzahlbegrenzung hat, kann aber auch zu Wiedergabeproblemen führen.",
"RenderPgsSubtitleHelp": "Legen Sie fest, ob der Client PGS-Untertitel rendern soll, anstatt eingebaute Untertitel zu verwenden. Dadurch kann eine serverseitige Transkodierung vermieden und die clientseitige Rendering-Leistung verbessert werden.",
"LabelAllowStreamSharing": "Stream-Sharing zulassen",
"LabelFallbackMaxStreamingBitrate": "Maximale Fallback-Stream-Bitrate (Mbps)",
"VideoCodecTagNotSupported": "Das Video-Codec-Tag wird nicht unterstützt",
"LabelLyricDownloaders": "Songtext-Downloader",
"LyricDownloadersHelp": "Aktivieren und ordnen Sie Ihre bevorzugten Untertitel-Downloader nach der Priorität.",
"ReplaceTrickplayImages": "Ersetzen vorhandener Trickplay-Bilder",
"LabelSaveTrickplayLocally": "Trickplay-Bilder bei den Medien speichern",
"LabelSaveTrickplayLocallyHelp": "Wenn Sie Trickplay-Bilder in Medienordnern speichern, werden sie bei Ihren Medien abgelegt und ermöglichen so eine einfache Migration und den Zugriff.",
"RenderPgsSubtitle": "Experimentelles PGS-Untertitel-Rendering",
"LabelAudioTagSettings": "Audio-Tag Einstellungen",
"LabelCustomTagDelimitersHelp": "Zeichen die zur Trennung von Tags verwendet werden sollen.",
"LabelDelimiterWhitelistHelp": "Artikel, die vom Tag-Splitting ausgeschlossen werden sollen. Ein Artikel pro Zeile.",
"PreferNonstandardArtistsTag": "Bevorzuge KÜNSTLER-Tag, falls vorhanden",
"PreferNonstandardArtistsTagHelp": "Verwenden Sie den nicht standardisierten ARTISTS-Tag anstelle des ARTIST-Tags, sofern verfügbar.",
"UseCustomTagDelimitersHelp": "Trennen Sie Künstler-/Genre-Tags mit benutzerdefinierten Zeichen.",
"LabelCustomTagDelimiters": "Benutzerdefinierte Tag-Begrenzung",
"LabelDelimiterWhitelist": "Trennzeichen Whitelist",
"UseCustomTagDelimiters": "Benutzerdefinierte Tag-Begrenzung verwenden"
}

View file

@ -1777,7 +1777,7 @@
"LabelIsHearingImpaired": "For hearing impaired (SDH)",
"BackdropScreensaver": "Backdrop Screensaver",
"LogoScreensaver": "Logo Screensaver",
"SelectAudioNormalizationHelp": "Track gain - adjusts the volume of each track so they playback with the same loudness. Album gain - adjusts the volume of all the tracks in an album only, keeping the album's dynamic range.",
"SelectAudioNormalizationHelp": "Track gain - adjusts the volume of each track so they playback with the same loudness. Album gain - adjusts the volume of all the tracks in an album only, keeping the album's dynamic range. Switching between \"Off\" and other options requires restarting the current playback.",
"LabelAlbumGain": "Album Gain",
"SearchResultsEmpty": "Sorry! No results found for \"{0}\"",
"LabelSelectAudioNormalization": "Audio Normalisation",
@ -1846,7 +1846,7 @@
"LabelAllowContentWithTags": "Allow items with tags",
"EnableSmoothScroll": "Enable smooth scroll",
"EncodingFormatHelp": "Select the video encoding that Jellyfin should transcode to. Jellyfin will use software encoding when hardware acceleration for the selected format is not available. H264 encoding will always be enabled.",
"LabelTrickplayAccelEncodingHelp": "Currently only available on QSV, VAAPI and VideoToolbox, this option has no effect on other hardware acceleration methods.",
"LabelTrickplayAccelEncodingHelp": "Currently only available on QSV, VA-API, VideoToolbox and RKMPP, this option has no effect on other hardware acceleration methods.",
"LabelEncodingFormatOptions": "Encoding format options",
"LabelTrickplayAccelEncoding": "Enable hardware accelerated MJPEG encoding",
"LimitSupportedVideoResolutionHelp": "Use 'Maximum Allowed Video Transcoding Resolution' as maximum supported video resolution.",
@ -1950,5 +1950,22 @@
"VideoCodecTagNotSupported": "The video codec tag is not supported",
"LabelSaveTrickplayLocally": "Save trickplay images next to media",
"LabelSaveTrickplayLocallyHelp": "Saving trickplay images into media folders will put them next to your media for easy migration and access.",
"ReplaceTrickplayImages": "Replace existing trickplay images"
"ReplaceTrickplayImages": "Replace existing trickplay images",
"RenderPgsSubtitle": "Experimental PGS subtitle rendering",
"RenderPgsSubtitleHelp": "Determine if the client should render PGS subtitles instead of using burned in subtitles. This can avoid server-side transcoding in exchange of client-side rendering performance.",
"LabelLyricDownloaders": "Lyric downloaders",
"LyricDownloadersHelp": "Enable and rank your preferred subtitle downloaders in order of priority.",
"LabelAudioTagSettings": "Audio Tag settings",
"LabelCustomTagDelimiters": "Custom Tag Delimiter",
"LabelCustomTagDelimitersHelp": "Characters to be treated as delimiters to separate tags.",
"LabelDelimiterWhitelist": "Delimiter Whitelist",
"LabelDelimiterWhitelistHelp": "Items to be excluded from tag splitting. One item per line.",
"PreferNonstandardArtistsTag": "Prefer ARTISTS tag if available",
"PreferNonstandardArtistsTagHelp": "Use the non-standard ARTISTS tag instead of ARTIST tag when available.",
"UseCustomTagDelimiters": "Use custom tag delimiter",
"UseCustomTagDelimitersHelp": "Split artist/genre tags with custom characters.",
"DateModified": "Date modified",
"MessageCancelSeriesTimerError": "An error occurred while cancelling the series timer",
"MessageCancelTimerError": "An error occurred while cancelling the timer",
"MessageSplitVersionsError": "An error occurred while splitting versions"
}

View file

@ -158,7 +158,7 @@
"ChannelNumber": "Channel number",
"Channels": "Channels",
"CinemaModeConfigurationHelp": "Cinema mode brings the theater experience straight to your living room with the ability to play trailers and custom intros before the main feature.",
"SelectAudioNormalizationHelp": "Track gain - adjusts the volume of each track so they playback with the same loudness. Album gain - adjusts the volume of all the tracks in an album only, keeping the album's dynamic range.",
"SelectAudioNormalizationHelp": "Track gain - adjusts the volume of each track so they playback with the same loudness. Album gain - adjusts the volume of all the tracks in an album only, keeping the album's dynamic range. Switching between \"Off\" and other options requires restarting the current playback.",
"ClearQueue": "Clear queue",
"ClientSettings": "Client Settings",
"Collections": "Collections",
@ -193,6 +193,7 @@
"DailyAt": "Daily at {0}",
"Data": "Data",
"DateAdded": "Date added",
"DateModified": "Date modified",
"DatePlayed": "Date played",
"DeathDateValue": "Died: {0}",
"Default": "Default",
@ -586,6 +587,7 @@
"LabelAudioChannels": "Audio channels",
"LabelAudioCodec": "Audio codec",
"LabelAudioLanguagePreference": "Preferred audio language",
"LabelAudioTagSettings": "Audio Tag settings",
"LabelSelectAudioNormalization": "Audio Normalization",
"LabelSelectPreferredTranscodeVideoAudioCodec": "Preferred transcode audio codec in video playback",
"LabelAudioSampleRate": "Audio sample rate",
@ -636,6 +638,8 @@
"LabelCustomCssHelp": "Apply your custom CSS code for theming/branding on the web interface.",
"LabelCustomDeviceDisplayNameHelp": "Supply a custom display name or leave empty to use the name reported by the device.",
"LabelCustomRating": "Custom rating",
"LabelCustomTagDelimiters": "Custom Tag Delimiter",
"LabelCustomTagDelimitersHelp": "Characters to be treated as delimiters to separate tags.",
"LabelDashboardTheme": "Server Dashboard theme",
"LabelDate": "Date",
"LabelDateAdded": "Date added",
@ -646,6 +650,8 @@
"LabelDeathDate": "Death date",
"LabelDefaultScreen": "Default screen",
"LabelDeinterlaceMethod": "Deinterlacing method",
"LabelDelimiterWhitelist": "Delimiter Whitelist",
"LabelDelimiterWhitelistHelp": "Items to be excluded from tag splitting. One item per line.",
"LabelDeveloper": "Developer",
"LabelDisableCustomCss": "Disable custom CSS code for theming/branding provided from the server.",
"LabelDisableVbrAudioEncoding": "Disable VBR audio encoding",
@ -1064,6 +1070,8 @@
"MessageAreYouSureDeleteSubtitles": "Are you sure you wish to delete this subtitle file?",
"MessageAreYouSureYouWishToRemoveMediaFolder": "Are you sure you wish to remove this media folder?",
"MessageBrowsePluginCatalog": "Browse our plugin catalog to view available plugins.",
"MessageCancelSeriesTimerError": "An error occurred while canceling the series timer",
"MessageCancelTimerError": "An error occurred while canceling the timer",
"MessageChangeRecordingPath": "Changing your recording folder will not migrate existing recordings from the old location to the new. You'll need to move them manually if desired.",
"MessageConfirmAppExit": "Do you want to exit?",
"MessageConfirmDeleteGuideProvider": "Are you sure you wish to delete this guide provider?",
@ -1116,6 +1124,7 @@
"MessageRenameMediaFolder": "Renaming a media library will cause all metadata to be lost, proceed with caution.",
"MessageRepositoryInstallDisclaimer": "WARNING: Installing a third party plugin repository carries risks. It may contain unstable or malicious code, and may change at any time. Only install repositories from authors that you trust.",
"MessageSent": "Message sent.",
"MessageSplitVersionsError": "An error occurred while splitting versions",
"MessageSyncPlayCreateGroupDenied": "Permission required to create a group.",
"MessageSyncPlayDisabled": "SyncPlay disabled.",
"MessageSyncPlayEnabled": "SyncPlay enabled.",
@ -1337,6 +1346,8 @@
"PreferEmbeddedExtrasTitlesOverFileNamesHelp": "Extras often have the same embedded name as the parent, check this to use embedded titles for them anyway.",
"PreferEmbeddedTitlesOverFileNames": "Prefer embedded titles over filenames",
"PreferEmbeddedTitlesOverFileNamesHelp": "Determine the display title to use when no internet metadata or local metadata is available.",
"PreferNonstandardArtistsTag": "Prefer ARTISTS tag if available",
"PreferNonstandardArtistsTagHelp": "Use the non-standard ARTISTS tag instead of ARTIST tag when available.",
"AllowEmbeddedSubtitles": "Disable different types of embedded subtitles",
"AllowEmbeddedSubtitlesHelp": "Disable subtitles that are packaged within media containers. Requires a full library refresh.",
"AllowEmbeddedSubtitlesAllowAllOption": "Allow All",
@ -1571,6 +1582,8 @@
"UnsupportedPlayback": "Jellyfin cannot decrypt content protected by DRM but all content will be tried regardless, including protected titles. Some files may appear completely black due to encryption or other unsupported features, such as interactive titles.",
"Up": "Up",
"Upload": "Upload",
"UseCustomTagDelimiters": "Use custom tag delimiter",
"UseCustomTagDelimitersHelp": "Split artist/genre tags with custom characters.",
"UseDoubleRateDeinterlacing": "Double the frame rate when deinterlacing",
"UseDoubleRateDeinterlacingHelp": "This setting uses the field rate when deinterlacing, often referred to as bob deinterlacing, which doubles the frame rate of the video to provide full motion like what you would see when viewing interlaced video on a TV.",
"UseEpisodeImagesInNextUp": "Use episode images in 'Next Up' and 'Continue Watching' sections",
@ -1737,7 +1750,7 @@
"Trickplay": "Trickplay",
"LabelTrickplayAccel": "Enable hardware decoding",
"LabelTrickplayAccelEncoding": "Enable hardware accelerated MJPEG encoding",
"LabelTrickplayAccelEncodingHelp": "Currently only available on QSV, VAAPI and VideoToolbox, this option has no effect on other hardware acceleration methods.",
"LabelTrickplayAccelEncodingHelp": "Currently only available on QSV, VA-API, VideoToolbox and RKMPP, this option has no effect on other hardware acceleration methods.",
"LabelTrickplayKeyFrameOnlyExtraction": "Only generate images from key frames",
"LabelTrickplayKeyFrameOnlyExtractionHelp": "Extract key frames only for significantly faster processing with less accurate timing. If the configured hardware decoder does not support this mode, will use the software decoder instead.",
"NonBlockingScan": "Non Blocking - queues generation, then returns",

View file

@ -1935,5 +1935,12 @@
"AlwaysRemuxMp3AudioFilesHelp": "Si tienes archivos en los que tu navegador calcula incorrectamente las marcas de tiempo, habilita esta opción como solución temporal.",
"AllowFmp4TranscodingContainerHelp": "Permitir el contenedor de transcodificación fMP4 para este sintonizador para habilitar contenidos HEVC y HDR. No todos los sintonizadores son compatibles con este contenedor. Deshabilítelo si experimenta problemas de reproducción.",
"AllowStreamSharingHelp": "Permitir que Jellyfin duplique la transmisión mpegts del sintonizador y comparta esta transmisión duplicada con sus clientes. Esto es útil cuando el sintonizador tiene un límite en la cantidad total de transmisiones, pero también puede causar problemas de reproducción.",
"AlwaysRemuxFlacAudioFilesHelp": "Si tienes archivos que tu navegador rechaza reproducir o en los que calcula incorrectamente las marcas de tiempo, habilita esta opción como solución temporal."
"AlwaysRemuxFlacAudioFilesHelp": "Si tienes archivos que tu navegador rechaza reproducir o en los que calcula incorrectamente las marcas de tiempo, habilita esta opción como solución temporal.",
"LabelDisableVbrAudioEncoding": "Deshabilitar la codificación de audio VBR",
"LabelAllowStreamSharing": "Permitir compartir transmisión",
"LabelLyricDownloaders": "Descargar letras",
"LyricDownloadersHelp": "Habilite y clasifique sus descargadores de subtítulos preferidos en orden de prioridad.",
"DisableVbrAudioEncodingHelp": "Evitar que el servidor codifique audio con VBR para este cliente.",
"EnableHi10p": "Habilitar perfil H.264 High 10",
"EnableHi10pHelp": "Habilite esta opción para evitar la transcodificación de videos H.264 de 10 bits. Desactive esta opción si el video muestra fotogramas en blanco."
}

View file

@ -285,7 +285,7 @@
"CustomDlnaProfilesHelp": "Loo kohandatud profiil uue seadme jaoks või tühista süsteemi profiil.",
"ConfigureDateAdded": "Seadista, kuidas lisamise kuupäev kuvatakse juhtpaneeli meediakogu seadetes",
"Banner": "Bänner",
"AllowTonemappingHelp": "Värvikaardistus võib muuta video dünaamilise ulatuse HDR -st SDR -ks, säilitades samal ajal pildi üksikasjad ja värvid, mis on algse stseeni kujutamisel väga oluline teave. Praegu töötab ainult 10-bitise HDR10, HLG ja DoVi videotega. See vajab vastavat GPGPU käitusaega.",
"AllowTonemappingHelp": "Värvikaardistus võib muuta video dünaamilise ulatuse HDR -st SDR -ks, säilitades samal ajal pildi üksikasjad ja värvid, mis on algse stseeni kujutamisel väga oluline teave. Praegu töötab ainult 10-bitise HDR10, HLG ja DoVi videotega. See vajab vastavat GPGPU rakendust.",
"HeaderDirectPlayProfile": "Otse-esituse profiil",
"HeaderContainerProfileHelp": "Konteineri profiilid näitavad seadme piiranguid teatud vormingute esitamisel. Kui kehtib piirang, meedium transkooditakse, isegi kui vorming on seadistatud otse-esituseks.",
"HeaderCodecProfileHelp": "Koodeki profiilid näitavad seadme piiranguid konkreetsete koodekite esitamisel. Kui kehtivad piirangud, transkooditakse meedia, isegi kui koodek on seadistatud otse-esituseks.",
@ -539,7 +539,7 @@
"Categories": "Kategooriad",
"CancelSeries": "Tühista sari",
"CancelRecording": "Tühista salvestamine",
"Bwdif": "BWDIF",
"Bwdif": "Bob Weaveri lõimingu filter(BWDIF)",
"ButtonWebsite": "Veebisait",
"ButtonUseQuickConnect": "Kasuta kiirühendamist",
"ButtonUninstall": "Eemalda",
@ -624,10 +624,10 @@
"AllowRemoteAccess": "Luba kaugühendused selle serveriga",
"AllowOnTheFlySubtitleExtractionHelp": "Manustatud subtiitreid saab videost eraldada ja klientidele lihttekstina edastada, et vältida video transkoodimist. Mõnes süsteemis võib see võtta kaua aega ja põhjustada video taasesituse seiskumise eraldamise ajal. Keela see, et manustatud subtiitrid põletataks video transkoodimisel sisse, kui klientseade ei toeta subtiitreid.",
"AllowOnTheFlySubtitleExtraction": "Luba subtiitrite eraldamine lennult",
"AllowMediaConversionHelp": "Luba või keela meedia teisendamine.",
"AllowMediaConversionHelp": "Luba või keela ligipääs meedia teisendamine featuurile.",
"AllowMediaConversion": "Luba meedia teisendamine",
"AllowHWTranscodingHelp": "Luba tuuneril voogesituse ajal transkoodida. See võib aidata vähendada serveri nõutavat transkoodimist.",
"AllowFfmpegThrottlingHelp": "Kui transkoodimine jõuab taasesituskohast ette, peata protsess ressursside säästmiseks. See on kasulik, kui enamasti vaatad filme otsimata. Lülita see välja, kui taasesitusega tekib probleeme.",
"AllowHWTranscodingHelp": "Luba tuuneril voogesituse ajal striime transkoodeerida. See võib aidata vähendada serveri nõutavat transkoodimist.",
"AllowFfmpegThrottlingHelp": "Kui transkodeerimine jõuab taasesituskohast ette, peata protsess ressursside säästmiseks. See on kasulik, kui enamasti vaatad filme otsimata. Kui taasesitusega tekib probleeme siis lülita see välja.",
"AllowFfmpegThrottling": "Piira transkoodimist",
"AllowedRemoteAddressesHelp": "Komaga eraldatud IP-aadresside loend või IP/võrgumaski kirjed võrkudele, millel on lubatud kaugühendus luua. Kui see tühjaks jäetakse, on kõik kaugaadressid lubatud.",
"AgeValue": "({0} aastat vana)",
@ -1100,7 +1100,7 @@
"LeaveBlankToNotSetAPassword": "Parooli määramata jätmiseks võid selle välja tühjaks jätta.",
"LearnHowYouCanContribute": "Uuri, kuidas ise panustada.",
"LatestFromLibrary": "Uusimad {0}",
"LastSeen": "Viimati nähtud {0}",
"LastSeen": "Viimane tegevus {0}",
"Large": "Suur",
"LanNetworksHelp": "Komadega eraldatud loend IP aadressidest või IP/võrgumaski kirjetest võrkude jaoks, mida loetakse olevat kohalikus võrgus, ribalaiuse piirangute jõustamisel. Kui see on määratud, loetakse kõik teised IP aadressid välisvõrgus olevateks ja nendele kehtivad välise ribalaiuse piirangud. Kui see tühjaks jätta, loetakse kohalikus võrgus olevaks ainult serveri alamvõrk.",
"LabelZipCode": "Postiindeks",
@ -1497,7 +1497,7 @@
"HeaderSelectFallbackFontPath": "Vali varufondi kausta rada",
"Yesterday": "Eile",
"Yes": "Jah",
"Yadif": "YADIF",
"Yadif": "Yet Another DeInterlacing Filter (YADIF)",
"XmlTvSportsCategoriesHelp": "Nende kategooriatega saateid kuvatakse spordisaadetena. Eralda mitu märgiga '|'.",
"XmlTvPathHelp": "XMLTV-faili rada. Jellyfin loeb seda faili ja kontrollib perioodiliselt värskendusi. Sinu vastutada on faili loomine ja värskendamine.",
"XmlTvNewsCategoriesHelp": "Nende kategooriatega saateid kuvatakse uudistena. Eralda mitu märgiga '|'.",
@ -1584,7 +1584,7 @@
"LabelH264Crf": "H.264 kodeerimise CRF",
"LabelAutomaticallyAddToCollectionHelp": "Kui vähemalt kahel filmil on sama kogumiku nimi, lisatakse need automaatselt kogumikku.",
"LabelAutomaticallyAddToCollection": "Lisa automaatselt kogumikku",
"H264CrfHelp": "'Constant Rate Factor' (CRF) on x264 ja x265 kodeerija vaikekvaliteediseade. Võimalikud on väärtused vahemikus 0 kuni 51, kus madalamad väärtused tooksid kaasa parema kvaliteedi (suurema failimahu arvelt). Mõistlikud väärtused on vahemikus 18 kuni 28. Vaikeväärtus x264 jaoks on 23 ja x265 jaoks 28, nii et seda saab kasutada lähtepunktina.",
"H264CrfHelp": "'Constant Rate Factor' (CRF) on x264 ja x265 tarkvaralise kodeerija vaikekvaliteediseade. Võimalikud on väärtused vahemikus 0 kuni 51, kus madalamad väärtused tooksid kaasa parema kvaliteedi (suurema failimahu arvelt). Mõistlikud väärtused on vahemikus 18 kuni 28. Vaikeväärtus x264 jaoks on 23 ja x265 jaoks 28, nii et seda saab kasutada lähtepunktina. Riistvaralised kodeerijad ei kasuta seda sätet.",
"Cursive": "Kursiiv",
"ButtonCast": "Esita seadmes",
"ButtonExitApp": "Lahku rakendusest",
@ -1656,7 +1656,7 @@
"Select": "Vali",
"EnableIntelLowPowerH264HwEncoder": "Luba Intel Low-Power H.264 riistvara kodeerija",
"HeaderDummyChapter": "Peatükipildid",
"LabelSegmentKeepSecondsHelp": "Aeg sekundites, kui kaua segmente tuleks hoida, peale seda kui need on kliendi poolt alla laetud. Töötab ainult siis, kui segmendi kustutamine on lubatud.",
"LabelSegmentKeepSecondsHelp": "Aeg sekundites, kui kaua segmente tuleks hoida, peale seda kui need on kliendi poolt alla laetud. Töötab ainult siis, kui segmentide kustutamine on lubatud.",
"DeinterlaceMethodHelp": "Valige lahtipõimitud sisu tarkvara ümberkodeerimisel kasutatav lahtipõimimis meetod. Kui riistvaralist lahtipõimimist toetav riistvarakiirendus on lubatud, kasutatakse selle sätte asemel riistvaralist lahtipõimijat.",
"EnableRewatchingNextUp": "Luba uuesti vaatamine Järgmises",
"IntelLowPowerEncHelp": "Madala võimsusega kodeering võib hoida tarbetut CPU-GPU sünkroonimist. Linuxis tuleb need keelata, kui i915 HuC püsivara pole konfigureeritud.",
@ -1666,10 +1666,10 @@
"PreferSystemNativeHwDecoder": "Eelistage OS-i DXVA või VA-API riistvaradekoodereid",
"AllowCollectionManagement": "Luba sellel kasutajal kogusid hallata",
"AllowSegmentDeletion": "Kustuta segmendid",
"AllowSegmentDeletionHelp": "Kustuta vanad segmendid pärast nende alla laadimist kliendi poolt. See hoiab ära kogu ümberkodeeritud faili kettale salvestamise. Lülita see välja, kui taasesitusega tekib probleeme.",
"LabelThrottleDelaySeconds": "Drossel pärast",
"LabelThrottleDelaySecondsHelp": "Aeg sekundites, mille järel transkooder pidurdatakse. Peab olema piisavalt suur, et klient säilitaks terve puhvri. Töötab ainult siis, kui drossel on lubatud.",
"LabelSegmentKeepSeconds": "Aeg hoida segmente",
"AllowSegmentDeletionHelp": "Kustuta vanad segmendid peale kliendipoolset allalaadimist. See hoiab ära kogu ümberkodeeritud faili kettale salvestamise. Lülita see välja, kui taasesitusega tekib probleeme.",
"LabelThrottleDelaySeconds": "Aeglusta peale",
"LabelThrottleDelaySecondsHelp": "Aeg sekundites, mille järel transkooder pidurdatakse. Peab olema piisavalt suur, et klient säilitaks terve puhvri. Töötab ainult siis, kui piiramine on lubatud.",
"LabelSegmentKeepSeconds": "Segmentide eluiga",
"Author": "Autor",
"BlockContentWithTagsHelp": "Peida meedia, millel on vähemalt üks antud silt.",
"ButtonEditUser": "Redigeeri kasutajat",
@ -1694,11 +1694,262 @@
"DeleteEpisode": "Kustuta episood",
"Editor": "Toimetaja",
"EnableTrueHd": "Luba TrueHD",
"EnableTrueHdHelp": "Luba TrueHD ainult siis, kui sinu seade või sellega ühendatud audioresiiver seda toetab. Vastasel juhul võib esitlus ebaõnnestuda.",
"AllowContentWithTagsHelp": "Näita ainult meediat, millel on vähemalt üks sisestatud silt",
"EnableTrueHdHelp": "Luba TrueHD ainult siis, kui sinu seade või sellega ühendatud audioresiiver seda toetab. Vastasel juhul võib see põhjustada esitluse ebaõnnestumist.",
"AllowContentWithTagsHelp": "Näita ainult meediat, millel on vähemalt üks sisestatud silt.",
"ChannelResolutionSD": "SD",
"ChannelResolutionSDPAL": "SD (PAL)",
"ChannelResolutionHD": "HD",
"ChannelResolutionFullHD": "Full HD",
"EnableSmoothScroll": "Luba sujuv kerimine"
"EnableSmoothScroll": "Luba sujuv kerimine",
"AllowFmp4TranscodingContainerHelp": "Luba sellel tuuneril fMP4 transkodeerimise konteiner, et lubada HEVC ja HDR sisu. Kõik tuunerid ei ühildu selle konteineriga, kui taasesitusega tekib probleeme siis lülita see välja.",
"AllowStreamSharingHelp": "Luba Jellyfin'il duplikeerida mpegts striim ja jagada seda striimi klientidele. See on kasulik kui tuuneril on piirang striimide hulgale kuid see võib põhjustada probleeme taasesitamisega.",
"AllowTonemappingSoftwareHelp": "Toonikaardistus suudab teisendada dünaamilise HDR sisu SDR'iks säilitades pildi detailid ja värvid mis on oluline et säiliks originaalstseen. Hetkel toimib vaid 10bit HDR10, HLG ja DoVi videotega.",
"AlwaysRemuxFlacAudioFilesHelp": "Kui sul on faile mida su brauser et mängi või kus ajatemplid arvutatakse valesti siis lubage see lahenduseks.",
"AlwaysRemuxMp3AudioFilesHelp": "Kui sul on faile kus brauser arvutab ajatemplid valesti siis lubage see lahenduseks.",
"AndOtherArtists": "{0} ja{1} teist artisti.",
"FallbackMaxStreamingBitrateHelp": "Maksimaalset voogesituse bitikiirust kasutatakse varuvariandina, kui ffprobe ei suuda määrata lähtevoo bitikiirust. See aitab vältida seda, et kliendid küsiksid liiga suurt transkodeerimise bitikiirust, mis võib põhjustada mängija tõrkeid ja kodeerija ülekoormust.",
"EditLyrics": "Muuda lüürikat",
"HeaderNextItem": "Järgmine {0}",
"HeaderPreviewLyrics": "Laulusõnade eelvaade",
"HeaderAddLyrics": "Lisa laulusõnu",
"DisableVbrAudioEncodingHelp": "Keela selle kliendi puhul serveril VBR heli kodeerimine.",
"GoHome": "Mine avalehele",
"HeaderAudioAdvanced": "Täpsemad helisätted",
"Colorist": "Kolorist",
"GridView": "Ruudukujuline vaade",
"HeaderEpisodesStatus": "Episoodide staatus",
"HeaderGuestCast": "Külalisstaarid",
"HeaderDeleteSeries": "Kustuta sari",
"HeaderLyricDownloads": "Laulusõnade allalaadimised",
"HeaderNoLyrics": "Laulusõnu ei leitud",
"EnableHi10p": "Luba H.264 High 10 profiil",
"EnableHi10pHelp": "Luba et takistada H.264 10-bit videofailide transkodeermine. Keela kui näed videodes tühje kaadreid.",
"ErrorAddingListingsToSchedulesDirect": "Tekkis viga koosseisu lisamisel teie Schedules Directi kontole. Schedules Direct lubab ainult piiratud arvu koosseise konto kohta. Võimalik, et peate enne jätkamist Schedules Directi veebisaidile sisse logima ja eemaldama oma kontolt teised koosseisud.",
"HeaderNextItemPlayingInValue": "Järgmine {0} alustab {1}",
"ErrorDeletingLyrics": "Serverist tekstide kustutamisel tekkis viga. Palun kontrollige, et Jellyfinil oleks meedia kausta kirjutamisõigus ja proovige uuesti.",
"HeaderDeleteLyrics": "Kustuta laulusõnad",
"HeaderAllRecordings": "Kõik salvestised",
"HeaderConfirmRepositoryInstallation": "Kinnitage pluginate kataloogi paigaldamine",
"Inker": "Tintija",
"HeaderVideoAdvanced": "Täpsemad videosätted",
"LabelAllowFmp4TranscodingContainer": "Luba fMP4 transkodeerimise konteiner",
"LabelAllowStreamSharing": "Luba striimi jagamine",
"LabelAlwaysRemuxFlacAudioFiles": "Alati remuxi FLAC audiofailid",
"LabelAlwaysRemuxMp3AudioFiles": "Alati remuxi MP3 failid",
"Illustrator": "Illustreerija",
"LabelAlbumGain": "Albumi helivõimendus",
"LabelAllowContentWithTags": "Lubage siltidega objektid",
"LabelSelectAudioNormalization": "Heli normaliseerimine",
"IgnoreDtsHelp": "Selle valiku väljalülitamine võib lahendada mõned probleemid, nt puuduv heli eraldi heli- ja videovoogudega kanalitel.",
"HeaderUploadLyrics": "Lae laulusõnad üles",
"LabelBuildVersion": "Buildi versioon",
"LabelDuration": "Kestus",
"LabelDropLyricsHere": "Tiri laulusõnad siia või vajuta failide valimiseks.",
"LabelDate": "Kuupäev",
"LabelDisableVbrAudioEncoding": "Keela VBR helikodeering",
"LabelBackdropScreensaverInterval": "Taustakuva ekraanisäästja intervall",
"LabelBackdropScreensaverIntervalHelp": "Aeg sekundites erinevate taustapiltide vahel, kui kasutate taustapildi ekraanisäästjat.",
"LabelSelectPreferredTranscodeVideoAudioCodec": "Eelistatud heli transkodeerimise koodek video taasesitamisel",
"LabelStereoDownmixAlgorithm": "Stereo Downmixi algorütm",
"LabelDummyChapterDuration": "Intervall",
"LabelDeveloper": "Arendaja",
"LabelChapterImageResolution": "Resolutsioon",
"LabelDummyChapterDurationHelp": "Intervall fiktiivsete peatükkide vahel. Seadista 0, et keelata fiktiivsete peatükkide genereerimine. Selle muutmine ei mõjuta olemasolevaid fiktiivseid peatükke.",
"LabelEnableAudioVbr": "Luba VBR helikodeering",
"LabelChapterImageResolutionHelp": "Eraldatud peatükipiltide resolutsioon. Selle muutmine ei mõjuta olemasolevaid fiktiivseid peatükke.",
"LabelEnableLUFSScanHelp": "Kliendid saavad normaliseerida heli taasesituse, et saavutada võrdne helitugevus kõigis lugudes. See muudab meediakogu skaneerimise aeglasemaks ja kasutab rohkem ressursse.",
"LibraryScanFanoutConcurrencyHelp": "Paralleelsete tööde maksimaalne arv raamatukogu skaneerimise ajal. Selle väärtuse 0'ks seadmine valib piirangu, mis põhineb teie süsteemi tuumade arvul. HOIATUS: Selle arvu liiga suureks seadmine võib põhjustada probleeme võrgu failisüsteemidega (NFS, Samba); kui teil tekib probleeme, vähendage seda arvu.",
"PreferEmbeddedExtrasTitlesOverFileNames": "Eelistage lisade sisseehitatud pealkirju failinimede asemel",
"LabelEnableAudioVbrHelp": "Muutuv bitikiirus pakub paremat kvaliteedi ja keskmise bitikiiruse suhet, kuid võib põhjustada puhverdamis- ja ühilduvusprobleeme.",
"LabelIsSynced": "Sünkroniseeritud",
"LabelSystem": "Süsteem",
"LogLevel.Information": "Information",
"LogLevel.Error": "Error",
"LabelRepository": "Hoidla",
"LogoScreensaver": "Ekraanisäästja logo",
"MenuOpen": "Ava menüü",
"LabelFallbackMaxStreamingBitrate": "Maksimaalne striimi voogedastuse kiiruse varuvariant (Mbps)",
"LabelNoChangelog": "Selle versiooni kohta pole muudatustelogi.",
"LabelWebVersion": "Veebi versioon",
"LogLevel.Trace": "Trace",
"LabelSelectPreferredTranscodeVideoCodec": "Eelistatud transkodeerimise videokoodek",
"LogLevel.Debug": "Debug",
"NoLyricsSearchResultsFound": "Laulusõnu ei leitud.",
"Penciller": "Joonistaja",
"PlaybackError.ASS_RENDER_ERROR": "ASS/SSA subtiitrite renderijas ilmnes viga.",
"MoveToBottom": "Liiguta viimaseks",
"PlaybackError.RateLimitExceeded": "Seda meediat ei saa hetkel mängida kiirusepiirangute tõttu.",
"Letterer": "Kirjutaja",
"SaveLyricsIntoMediaFoldersHelp": "Laulusõnade salvestamine helifailide kõrvale võimaldab neid hõlpsamini hallata.",
"LogLevel.Warning": "Warning",
"LogLevel.None": "None",
"LibraryInvalidItemIdError": "Meediakogu on vigases olekus ja seda ei saa muuta. Võimalik, et tegemist on veaga: andmebaasis olev asukoht ei ole toimiv viide failisüsteemis.",
"PluginLoadRepoError": "Tekkis viga plugina andmete hankimisel.",
"PluginUninstallError": "Plugina eemaldamisel tekkis viga.",
"MenuClose": "Sulge menüü",
"PleaseConfirmRepositoryInstallation": "Palun klõpsake OK, et kinnitada, et olete ülaltoodut lugenud ja soovite jätkata pluginate repositooriumi paigaldamist.",
"LogLevel.Critical": "Critical",
"LabelLyricDownloaders": "Laulusõnade allalaadijad",
"LyricDownloadersHelp": "Lubage ja järjestage oma subtiitrite allalaadimisprogrammide eelistuse järjekord.",
"MoveToTop": "Liiguta esimeseks",
"PlaybackError.NotAllowed": "Selle meedia taasesitamine ei ole lubatud.",
"LabelEnableLUFSScan": "Luba LUFS skaneerimine",
"LabelInstalled": "Installitud",
"LabelNotInstalled": "Installimata",
"MediaInfoRotation": "Rotatsioon",
"PasswordRequiredForAdmin": "Admin kasutajatel peab olema parool.",
"PasswordMissingSaveError": "Uus parool ei tohi olla tühi.",
"PlaybackError.MEDIA_DECODE_ERROR": "Taasesitus ebaõnnestus meedia dekodeerimise vea tõttu.",
"PlaybackError.MEDIA_NOT_SUPPORTED": "Taasesitus ebaõnnestus, sest see klient ei toeta seda meediatüüpi.",
"PlaybackError.NETWORK_ERROR": "Taasesitus ebaõnnestus võrguvea tõttu.",
"PlaybackError.PLAYER_ERROR": "Taasesitus ebaõnnestus fataalse pleierivea tõttu.",
"PlaylistError.CreateFailed": "Viga esitusloendi loomisel",
"PlaylistError.AddFailed": "Viga esitusloendisse lisamisel",
"PluginDisableError": "Plugina väljalülitamisel tekkis viga.",
"PluginEnableError": "Plugina sisselülitamisel tekkis viga.",
"PluginLoadConfigError": "Plugina konfiguratsioonilehtede kättesaamisel tekkis viga.",
"LabelLevel": "Tase",
"LabelServerVersion": "Serveri versioon",
"LabelSyncPlayNoGroups": "Gruppe pole",
"LibraryScanFanoutConcurrency": "Paralleelsete meediakogu skaneerimiste piirang",
"LimitSupportedVideoResolutionHelp": "Kasutage 'Piirake maksimaalset toetatud videoresolutsiooni' kui maksimaalne toetatud video resolutsioon.",
"ListView": "Listivaade",
"MessageRepositoryInstallDisclaimer": "HOIATUS: Kolmanda osapoole pluginate hoidla paigaldamisega kaasnevad riskid. See võib sisaldada ebastabiilset või pahatahtlikku koodi ning võib igal ajal muutuda. Installige ainult nende autorite repositooriume, keda te usaldate.",
"LabelMediaDetails": "Meediadetailid",
"LabelParallelImageEncodingLimit": "Paralleelne pildi kodeerimise piirang",
"LabelParallelImageEncodingLimitHelp": "Maksimaalne arv pildi kodeeringuid, mida on lubatud paralleelselt käivitada. Selle väärtuse 0'ks seadmine valib piirangu, mis põhineb teie süsteemi tuumade arvul.",
"Lyrics": "Laulusõnad",
"Lyric": "Laulusõna",
"PlaybackError.SERVER_ERROR": "Taasesitus ebaõnnestus serveri vea tõttu.",
"LabelEnablePlugin": "Luba plugin",
"PlaybackError.NO_MEDIA_ERROR": "Ei leia mängimiseks sobivat meediafaili.",
"LabelSaveTrickplayLocally": "Salvesta trickplay pildid videofailide juurde",
"LabelSaveTrickplayLocallyHelp": "Trickplay piltide salvestamine meediakogu kausta võimaldab neid hõlpsamini hallata.",
"PlaybackError.FATAL_HLS_ERROR": "HLS-striimis ilmnes fataalne viga.",
"PlaylistPublic": "Luba avalik juurdepääs",
"PlaylistPublicDescription": "Lubage seda esitusloendit vaadata kõigil sisselogitud kasutajatel.",
"LimitSupportedVideoResolution": "Piirake maksimaalset toetatud videoresolutsiooni",
"PreferEmbeddedExtrasTitlesOverFileNamesHelp": "Lisadel on sageli sama sisseehitatud nimi kui originaalil, lubage, et kasutada nende jaoks ikkagi sisseehitatud.",
"SaveRecordingNFOHelp": "Salvesta EPG pakkuja poolt saadud metaandmed meedia kõrvale.",
"ReplaceTrickplayImages": "Asendage olemasolevad trickplay pildid",
"SaveLyricsIntoMediaFolders": "Salvesta laulusõnad meediakaustadesse",
"SearchResultsEmpty": "Vabandame! Ei leidnud vastet otsingule \"{0}\"",
"Remixer": "Remixija",
"SavePassword": "Salvesta parool",
"SecondarySubtitles": "Teisesed subtiitrid",
"Reset": "Lähtesta",
"SearchForLyrics": "Otsi laulusõnu",
"SaveRecordingNFO": "Salvesta salvestuse EPG metaandmed NFO-sse",
"SaveRecordingImages": "Salvesta salvestise EPG pildid",
"SaveRecordingImagesHelp": "Salvesta EPG pakkuja poolt saadud pildid meedia kõrvale.",
"PreviewLyrics": "Laulusõnade eelvaade",
"ResolutionMatchSource": "Vaste algallikas",
"Regional": "Regionaalne",
"RenderPgsSubtitle": "Eksperimentaalne PGS subtiitrite esitamine",
"RenderPgsSubtitleHelp": "Määrake, kas klient peaks PGS-subtiitreid renderdama, selle asemel et kasutada sissepõletatud subtiitreid. Sellega saab vältida serveri poolset transkodeerimist, et saavutada tulemuslikum kliendipoolne renderdamine.",
"Production": "Toodang",
"ReleaseGroup": "Väljaandja rühmitus",
"SubtitleGreen": "Roheline",
"SubtitleBlue": "Sinine",
"SubtitleCyan": "Tsüüan",
"Translator": "Tõlkija",
"SubtitleWhite": "Valge",
"SubtitleYellow": "Kollane",
"UnknownError": "Tekkis tundmatu viga.",
"SubtitleLightGray": "Helehall",
"SubtitleBlack": "Must",
"SubtitleGray": "Hall",
"StereoDownmixAlgorithmHelp": "Algoritm, mida kasutatakse mitme kanaliga heli allasegamiseks stereoks.",
"StoryArc": "Narratiiv",
"SubtitleMagenta": "Magenta",
"SelectPreferredTranscodeVideoCodecHelp": "Vali transkodeerimiseks eelistatud videokoodek. Kui eelisatud koodek pole toetatud kasutab server järgmist saadaolevat koodekit.",
"SelectPreferredTranscodeVideoAudioCodecHelp": "Vali videofailide transkodeerimiseks eelistatud audiokoodek. Kui eelisatud koodek pole toetatud kasutab server järgmist saadaolevat koodekit.",
"Studio": "Stuudio",
"SubtitleRed": "Punane",
"UseDoubleRateDeinterlacingHelp": "See seadistus kasutab lahti põimimise puhul välissagedust, mida sageli nimetatakse \"bob deinterlacing'iks\", mis kahekordistab video kaadrisageduse, et pakkuda täielikku liikumist, nagu seda näeksite põimitud video vaatamisel telerist.",
"HearingImpairedShort": "HI/SDH",
"LabelTrickplayAccel": "Luba riistvaraline dekodeerimine",
"LabelTrickplayKeyFrameOnlyExtraction": "Looge pilte ainult võtmekaadritest",
"UserMenu": "Kasutajamenüü",
"LabelTrackGain": "Loo võimendus",
"EnableEnhancedNvdecDecoderHelp": "Täiustatud NVDEC implementatsioon, lülitage see valik välja, et kasutada CUVIDi, kui teil esineb dekodeerimisvigu.",
"LabelTonemappingMode": "Toonikaardistamise režiim",
"VideoCodecTagNotSupported": "Videokoodeksi silt ei ole toetatud",
"Featurette": "Peatükk",
"MediaInfoElPresentFlag": "DV el eelseadistuse lipuke",
"Short": "Lühifilm",
"LabelVppTonemappingBrightnessHelp": "Rakendage heleduse võimendust VPP toonikaardistamisel. Soovituslikud ja vaikimisi väärtused on 16 ja 0.",
"MediaInfoDoViTitle": "DV nimetus",
"MediaInfoDvVersionMajor": "DV peamine versioon",
"MediaInfoDvVersionMinor": "DV alamversioon",
"Unknown": "Tundmatu",
"LabelIsHearingImpaired": "Vaegkuuljate jaoks (SDH)",
"ViewLyrics": "Vaata laulusõnu",
"AllowVideoToolboxTonemappingHelp": "VideoToolboxi poolt pakutav riistvaraline toonikaardistamine. See töötab enamiku HDR-formaatidega, sealhulgas HDR10, HDR10+ ja HLG, kuid ei tööta Dolby Vision Profile 5ga. See on võrreldes teise Metali rakendusega kõrgema prioriteediga.",
"LabelEncodingFormatOptions": "Kodeerimisformaadi valikud",
"UnknownVideoStreamInfo": "Videovoo info on tundmatu",
"UnknownAudioStreamInfo": "Audiovoo info on tundmatu",
"LabelTrickplayAccelEncoding": "Luba riistvaraliselt kiirendatud MJPEG-kodeering",
"LabelTrickplayAccelEncodingHelp": "Praegu saadaval ainult QSV, VA-API, VideoToolbox ja RKMPP puhul, see valik ei mõjuta teisi riistvarakiirenduse meetodeid.",
"Clip": "Klipp",
"LabelVppTonemappingBrightness": "VPP toonikaardistamise heleduse võimendus",
"EnableVideoToolboxTonemapping": "Luba VideoToolbox toonide kaardistamine",
"EncodingFormatHelp": "Valige videokodeering, milliseks Jellyfin peaks transkodeerima. Jellyfin kasutab tarkvaralist kodeerimist, kui valitud formaadi jaoks ei ole riistvaraline kiirendus saadaval. H264 kodeerimine on alati lubatud.",
"DirectPlayError": "Otsese taasesituse käivitamisel tekkis viga",
"MediaInfoBlPresentFlag": "DV bl eelseadistuse lipuke",
"MediaInfoDvBlSignalCompatibilityId": "DV bl signaali ühilduvuse id",
"TonemappingModeHelp": "Valige toonikaardistamise režiim. Kui teil on eredalt esilekerkinud heledad kohad, proovige kasutada RGB-režiimi.",
"AllowAv1Encoding": "Luba kodeerimine AV1-vormingus",
"EnableIntelLowPowerHevcHwEncoder": "Inteli madala enegiakasutusega HEVC riistvaralise kodeerija lubamine",
"LabelHardwareEncodingOptions": "Riistvaralise kodeerimise valikud",
"Trickplay": "Trickplay",
"AiTranslated": "AI tõlgitud",
"MachineTranslated": "Masintõlgitud",
"ForeignPartsOnly": "Ainult sunnitud/võõrosad",
"LabelVppTonemappingContrast": "VPP toonikaardistamise kontrasti võimendus",
"LabelVppTonemappingContrastHelp": "Rakendage VPP toonikaardistamisel kontrasti võimendust. Nii soovitatud kui ka vaikimisi väärtus on 1.",
"MediaInfoRpuPresentFlag": "DV rpu eelseadistuse lipuke",
"LabelTrickplayKeyFrameOnlyExtractionHelp": "Eralda ainult põhikaadrid oluliselt kiiremaks töötlemiseks, vähem täpse ajastusega. Kui seadistatud riistvaraline dekooder seda režiimi ei toeta kasutatakse selle asemel tarkvaralist dekooderit.",
"LabelScanBehavior": "Skaneerimise käitumine",
"NonBlockingScan": "Mitteblokeeriv - ootab genereerimist, seejärel naaseb",
"BlockingScan": "Blokeeriv - järjekorras genereerimine, blokeerib skaneerimise kuni selle lõpetamiseni",
"LabelScanBehaviorHelp": "Vaikimisi käitumine on mitteblokeeriv, see lisab meedia meediakogusse enne trickplay failide genereerimist. Blokeerimine tagab, et trickplay failid genereeritakse enne meedia meediakogusse lisamist, kuid teeb skaneerimise oluliselt aeglasemaks.",
"LabelTileWidth": "Ruudu laius",
"LabelProcessPriorityHelp": "Selle madalamaks või kõrgemaks seadistamine määrab kuidas CPU prioritiseerib trickplay piltide genereerimise. Kui märkad trickplay piltide genereerimise aeglustumist aga tahad seda ikka kasutada siis proovi lisaks selle alandamisele ka lõimesid vähendada.",
"LabelTileHeight": "Ruudu kõrgus",
"LabelTrickplayThreads": "FFmpeg lõimed",
"LabelWidthResolutions": "Laiuseraldused",
"LabelJpegQuality": "JPEG kvaliteet",
"LabelProcessPriority": "Protsessi prioriteet",
"LabelTileHeightHelp": "Piltide maksimaalne arv ühe ruudu kohta Y-suunas.",
"LabelJpegQualityHelp": "JPEG-kompressiooni kvaliteet trickplay piltide puhul.",
"LabelTrickplayThreadsHelp": "Lõimede arv, mis antakse üle ffmpeg'i argumendile '-threads'.",
"LabelImageInterval": "Pildiintervall",
"LabelQscale": "Qscale",
"LabelQscaleHelp": "ffmpeg'i poolt väljastatavate piltide kvaliteediskaala, kus 2 on kõrgeima kvaliteediga ja 31 madalaima kvaliteediga.",
"PriorityHigh": "Kõrge",
"PriorityBelowNormal": "Alla normaalväärtuse",
"LabelExtractTrickplayDuringLibraryScanHelp": "Genereeri trickplay pildid meediakogu skaneerimise ajal vastasel korral genereeritakse need trickplay piltide ajastatud ülesannete raames. Kui genereerimine on seaditatud mitteblokeerivaks ei mõjuta see meediakogu skaneerimisele kuluvat aega.",
"LabelWidthResolutionsHelp": "Komadega eraldatud loetelu laiustest (px), millega trickplay-pildid genereeritakse. Kõik pildid peaksid olema proportsioonis allikaga, nii et laius 320 16:9 videol on umbes 320x180.",
"OptionExtractTrickplayImage": "Luba trickplay piltide genereerimine",
"LabelExtractTrickplayDuringLibraryScan": "Genereeri trickplay pildid meediakogu skaneerimise ajal",
"PriorityIdle": "Vaba",
"LabelImageIntervalHelp": "Ajavahemik (ms) iga uue trickplay pildi vahel.",
"PriorityNormal": "Normaalväärtus",
"PriorityAboveNormal": "Üle normaalväärtuse",
"LabelTileWidthHelp": "Piltide maksimaalne arv ühe ruudu kohta X-suunas.",
"ExtractTrickplayImagesHelp": "Trickplay-pildid on sarnased peatükkide piltidega, kuid need hõlmavad kogu sisu. Neid kasutatakse videote skriinimisel eelvaate kuvamiseks.",
"LabelDelimiterWhitelistHelp": "Üksused, mida siltideks jagamisel ignoreeritakse. Iga üksus omaette real.",
"PreferNonstandardArtistsTag": "Eelista ARTISTS silti kui see saadaval on",
"LabelAudioTagSettings": "Audiosiltide seadistused",
"DateModified": "Muutmiskuupäev",
"LabelCustomTagDelimiters": "Kohandatud siltide eraldaja",
"LabelCustomTagDelimitersHelp": "Tähemärgid mida kasutatakse siltide eraldajana.",
"LabelDelimiterWhitelist": "Lubatud eraldusmärgid",
"MessageCancelSeriesTimerError": "Sarja taimeri tühistamisel ilmnes viga",
"MessageCancelTimerError": "Taimeri tühistamisel ilmnes viga",
"MessageSplitVersionsError": "Versioonideks jagamisel tekkis viga",
"PreferNonstandardArtistsTagHelp": "Kasuta ARTIST sildi asemel ebastandartset ARTISTS silti kui see saadaval on.",
"UseCustomTagDelimiters": "Kasuta kohandatud siltide eraldajat",
"UseCustomTagDelimitersHelp": "Kasuta siltideks jagamisel kohandatud tähemärke."
}

View file

@ -1926,5 +1926,6 @@
"LabelTrickplayAccelEncoding": "Käyttöönota rautakiihdytetty MJPEG enkoodaus",
"LabelTrickplayAccelEncodingHelp": "Tällä hetkellä ainoastaan käytettävissä QSV, VAAPI ja VideoToolbox, tällä valinnalla ei ole vaikutusta muihin rautakiihdytysmetodeihin.",
"HeaderVideoAdvanced": "Edistynyt video",
"PlaylistPublicDescription": "Salli tämän soittolistan katsominen jokaiselle kirjautuneelle käyttäjälle."
"PlaylistPublicDescription": "Salli tämän soittolistan katsominen jokaiselle kirjautuneelle käyttäjälle.",
"DateModified": "Muokkauspäivämäärä"
}

View file

@ -1267,7 +1267,7 @@
"OnWakeFromSleep": "À la sortie de veille",
"WeeklyAt": "{0} à {1}",
"DailyAt": "Tous les jours à {0}",
"LastSeen": "Vu {0}",
"LastSeen": "Dernière activité {0}",
"PersonRole": "est {0}",
"ListPaging": "{0}-{1} de {2}",
"WriteAccessRequired": "Jellyfin a besoin d'un accès en écriture à ce dossier. Merci de vérifier les permissions de ce-dernier puis de réessayer.",
@ -1778,7 +1778,7 @@
"HeaderGuestCast": "Invités vedettes",
"LabelIsHearingImpaired": "Sous-titrage pour sourds et malentendants",
"SearchResultsEmpty": "Désolé ! Aucun résultat trouvé pour \"{0}\"",
"SelectAudioNormalizationHelp": "Gain de piste - permet de régler le volume de chaque piste de manière à ce qu'elles soient lues avec la même intensité sonore. Gain de l'album - ajuste le volume de toutes les pistes d'un album uniquement, en conservant la plage dynamique de l'album.",
"SelectAudioNormalizationHelp": "Gain de piste - permet de régler le volume de chaque piste de manière à ce qu'elles soient lues avec la même intensité sonore. Gain de l'album - ajuste le volume de toutes les pistes d'un album uniquement, en conservant la plage dynamique de l'album. Passer de \"Off\" à une autre option, requiert le redémarrage la lecture en cours.",
"LabelAlbumGain": "Gain de l'album",
"LabelSelectAudioNormalization": "Normalisation de l'audio",
"LabelTrackGain": "Gain de piste",
@ -1860,7 +1860,7 @@
"PlaybackError.NO_MEDIA_ERROR": "Impossible de trouver une source multimédia valide à lire.",
"PlaybackError.PLAYER_ERROR": "La lecture a échoué en raison d'une erreur fatale du lecteur.",
"LabelTrickplayAccelEncoding": "Activer l'encodage MJPEG accéléré par le matériel",
"LabelTrickplayAccelEncodingHelp": "Actuellement disponible uniquement sur QSV et VAAPI, cette option n'a aucun effet sur les autres méthodes d'accélération matérielle.",
"LabelTrickplayAccelEncodingHelp": "Actuellement disponible uniquement avec QSV, VA-API, VideoToolbox et RKMPP, cette option n'a aucun effet sur les autres méthodes d'accélération matérielle.",
"ErrorDeletingLyrics": "Une erreur est survenu lors de la suppression des paroles du serveur. S'il vous plaît verifier que Jellyfin peut modifier les fichier dans le dossier multimedia et réessayez.",
"HeaderDeleteLyrics": "Suppression des paroles",
"ConfirmDeleteLyrics": "En supprimant ces paroles vous les supprimez a la fois de votre systeme de fichier et de votre bibliothèque. Êtes vous sure de vouloir continuez ?",
@ -1925,5 +1925,47 @@
"PreviewLyrics": "Prévisualiser les paroles",
"SearchForLyrics": "Chercher les paroles",
"NoLyricsSearchResultsFound": "Pas de paroles trouvées.",
"HeaderUploadLyrics": "Téléverser des paroles"
"HeaderUploadLyrics": "Téléverser des paroles",
"DisableVbrAudioEncodingHelp": "Empêche le serveur d'encoder l'audio avec VBR pour ce client.",
"EnableHi10p": "Active le profil H.264 High 10",
"EnableHi10pHelp": "Activer pour éviter l'encodage des vidéos H.264 10-bits. Désactiver cette option si la vidéo affiche des images vides.",
"AlwaysRemuxFlacAudioFilesHelp": "Si votre navigateur refuse de lire des fichiers ou s'il calcule incorrectement l'horodatage, activer ceci en guise d'alternative.",
"AlwaysRemuxMp3AudioFilesHelp": "Si votre navigateur calcule incorrectement l'horodatage de certains fichiers, activer ceci en guise d'alternative.",
"DateModified": "Date modifiée",
"FallbackMaxStreamingBitrateHelp": "Le débit maximum de streaming est utilisé par défaut quand ffprobe ne peut pas déterminer le débit du flux source. Cela aide à éviter que les clients demandent un débit de transcodage excessivement élevé, ce qui pourrait mener le lecteur à échouer et surcharger l'encodeur.",
"LabelAlwaysRemuxFlacAudioFiles": "Toujours remultiplexer les fichiers audio FLAC",
"LabelAlwaysRemuxMp3AudioFiles": "Toujours remultiplexer les fichiers audio MP3",
"LabelAllowStreamSharing": "Autoriser le partage de flux",
"MessageCancelSeriesTimerError": "Une erreur est survenue lors de l'annulation du minuteur de série",
"AllowStreamSharingHelp": "Autoriser Jellyfin à dupliquer le flux mpegts provenant du tuner et à partager ce flux dupliqué avec ses clients. Cela est utile lorsque le tuner a une limite de nombre total de flux, mais peut également causer des problèmes de lecture.",
"Reset": "Réinitialiser",
"UseCustomTagDelimitersHelp": "Diviser les balises d'artiste/genre avec des caractères personnalisés.",
"HeaderAudioAdvanced": "Audio Avancé",
"LabelAudioTagSettings": "Paramètres des balises audio",
"LabelCustomTagDelimiters": "Délimiteur de balise personnalisé",
"LabelCustomTagDelimitersHelp": "Caractères à traiter comme délimiteurs pour séparer les balises.",
"LabelLyricDownloaders": "Téléchargeurs de paroles",
"LabelDelimiterWhitelist": "Liste blanche des délimiteurs",
"LabelDelimiterWhitelistHelp": "Éléments à exclure de la division des balises. Un élément par ligne.",
"LabelDisableVbrAudioEncoding": "Désactiver l'encodage audio VBR",
"LabelSaveTrickplayLocally": "Enregistrer les images de prévisualisation (trickplay) au même emplacement que les médias",
"LabelSaveTrickplayLocallyHelp": "Enregistrer les images trickplay dans les dossiers de médias les placera à côté de vos médias pour une migration et un accès faciles.",
"MediaInfoRotation": "Rotation",
"RenderPgsSubtitle": "Rendu expérimental des sous-titres PGS",
"ReplaceTrickplayImages": "Remplacer les images trickplay existantes",
"LibraryInvalidItemIdError": "La bibliothèque est dans un état invalide et ne peut pas être modifiée. Vous rencontrez probablement un bug : le chemin dans la base de données n'est pas le bon chemin sur le système de fichiers.",
"MessageCancelTimerError": "Une erreur est survenue lors de l'annulation du minuteur",
"MessageSplitVersionsError": "Une erreur s'est produite lors de la division des versions",
"PreferNonstandardArtistsTag": "Préférer la balise ARTISTS si disponible",
"PreferNonstandardArtistsTagHelp": "Utiliser la balise non standard ARTISTS au lieu de la balise ARTIST lorsqu'elle est disponible.",
"RenderPgsSubtitleHelp": "Détermine si le client doit rendre les sous-titres PGS au lieu d'utiliser des sous-titres incrustés. Cela peut éviter le transcodage côté serveur au profit de la performance de rendu côté client.",
"UseCustomTagDelimiters": "Utiliser un délimiteur de balise personnalisé",
"VideoCodecTagNotSupported": "La balise de codec vidéo n'est pas prise en charge",
"LabelFallbackMaxStreamingBitrate": "Bitrate de flux maximum de repli (Mbps)",
"LyricDownloadersHelp": "Activez et classez vos téléchargeurs de sous-titres préférés par ordre de priorité.",
"LabelAllowFmp4TranscodingContainer": "Autoriser le conteneur de transcodage fMP4",
"AllowTonemappingSoftwareHelp": "Le tone-mapping peut transformer la plage dynamique d'une vidéo de HDR à SDR tout en conservant les détails et les couleurs de l'image, qui sont des informations très importantes pour représenter la scène originale. Fonctionne uniquement avec les vidéos 10 bits HDR10, HLG et DoVi.",
"LabelTrickplayKeyFrameOnlyExtraction": "Générer uniquement des images à partir des images clés",
"LabelTrickplayKeyFrameOnlyExtractionHelp": "Extraire uniquement les images clés pour un traitement beaucoup plus rapide avec un minutage moins précis. Si le décodeur matériel configuré ne prend pas en charge ce mode, il utilisera le décodeur logiciel à la place.",
"AllowFmp4TranscodingContainerHelp": "Autoriser le conteneur de transcodage fMP4 pour ce tuner afin d'activer les contenus HEVC et HDR. Tous les tuners ne sont pas compatibles avec ce conteneur. Désactivez ceci si vous rencontrez des problèmes de lecture."
}

View file

@ -3,7 +3,7 @@
"Add": "הוסף",
"AddToCollection": "הוסף לאוסף",
"AddToPlayQueue": "הוסף לתור ברשימת ניגון",
"AddToPlaylist": "הוסף לרשימת ניגון",
"AddToPlaylist": "הוסף לרשימת השמעה",
"AdditionalNotificationServices": "עיין ברשימת התוספים להתקנת שירותי התראות נוספים.",
"All": "הכול",
"AllChannels": "כל הערוצים",
@ -67,7 +67,7 @@
"HeaderActiveDevices": "מכשירים פעילים",
"HeaderActiveRecordings": "הקלטות פעילות",
"HeaderAddToCollection": "להוסיף לאוסף",
"HeaderAddToPlaylist": "הוסף לרשימת ניגון",
"HeaderAddToPlaylist": "הוסף לרשימת השמעה",
"HeaderAdditionalParts": "חלקים נוספים",
"HeaderCancelRecording": "ביטול הקלטה",
"HeaderCancelSeries": "בטל סדרה",
@ -103,7 +103,7 @@
"HeaderScenes": "סצנות",
"HeaderSeriesOptions": "אפשרויות סדרה",
"HeaderServerSettings": "הגדרות שרת",
"HeaderSetupLibrary": "הגדר את ספריית המדיה שלך",
"HeaderSetupLibrary": "הגדרת ספריות המדיה שלך",
"HeaderSpecialEpisodeInfo": "פרטי אפיזודות מיוחדות",
"HeaderStatus": "מצב",
"HeaderSystemDlnaProfiles": "פרופילי מערכת",
@ -477,7 +477,7 @@
"ButtonAddImage": "הוסף תמונה",
"AskAdminToCreateLibrary": "בקש ממנהל ליצור ספרייה.",
"Ascending": "בסדר עולה",
"Photos": "תמונות",
"Photos": "צילומים",
"MessageConfirmShutdown": "‫האם אתה בטוח שברצונך לכבות את השרת?",
"MessageConfirmRestart": "‫האם אתה בטוח שברצונך לאתחל את שרת ה-Jellyfin?",
"HeaderThisUserIsCurrentlyDisabled": "משתמש זה אינו פעיל כרגע",
@ -584,7 +584,7 @@
"BookLibraryHelp": "ניתן להוסיף ספרים מוקלטים וספרים כתובים. עיינו {0} במדריך מתן שמות לספרים {1}.",
"Desktop": "שולחן עבודה",
"MessageDeleteTaskTrigger": "האם אתה בטוח כי ברצונך למחוק את מפעיל משימה זה?",
"LastSeen": "נראה לאחרונה ב-{0}",
"LastSeen": "פעילות אחרונה ב-{0}",
"PersonRole": "כ-{0}",
"ListPaging": "{0}-{1} מתוך {2}",
"EveryXHours": "בכל {0} שעות",
@ -840,7 +840,7 @@
"HeaderDeleteDevices": "מחק את כל המכשירים",
"HeaderApiKeysHelp": "תוכנות חיצוניות נדרשות להשתמש במפתח API חיצוני על מנת לתקשר עם השרת. מפתחות מונפקים ע\"י התחברות עם משתמש רגיל, או באמצעות הנפקה ידנית של מפתח לתוכנה.",
"EncoderPresetHelp": "בחר ערך מהיר יותר לשיפור ביצועים, או ערך איטי יותר לשיפור איכות.",
"H264CrfHelp": "Constant Rate Factor (CRF) הוא הגדרת איכות ברירת המחדל של מקודדי ה-x264 ו-x265. ניתן לקבוע ערך בין 0 ל-51, כשערך נמוך יותר יביא לאיכות גבוהה יותר (על חשבון קבצים גדולים יותר). ההגדרות המומלצות הן בין 18 ל-28. ערך ברירת המחדל של x264 הוא 23, ושל x265 הוא 28, אז ניתן לראות בכך נקודת התחלה.",
"H264CrfHelp": "Constant Rate Factor (CRF) הוא הגדרת איכות ברירת המחדל של מקודדי התוכנה x264 ו-x265. ניתן לקבוע ערך בין 0 ל-51, כשערך נמוך יותר יביא לאיכות גבוהה יותר (על חשבון קבצים גדולים יותר). ההגדרות המומלצות הן בין 18 ל-28. ערך ברירת המחדל של x264 הוא 23, ושל x265 הוא 28, אז ניתן לראות בכך נקודת התחלה. מקודדי חומרה לא משתמשים בהגדרות אלה.",
"FFmpegSavePathNotFound": "תיקיית FFmpeg לא נמצאה באמצעות נתיב התיקייה שהוכנס. FFprobe נדרש וצריך גם הוא להימצא באותה התיקייה. רכיבים אלו בד\"כ נמצאים ביחד באותה ההורדה. אנא בדוק את נתיב בתיקייה ונסה שנית.",
"DeleteDevicesConfirmation": "האם אתה בטוח כי ברצונך למחוק את כל המכשירים? כל החיבורים האחרים ינותקו. מכשירים יופיעו מחדש בפעם הבאה שיתחברו דרכם.",
"DeleteAll": "מחק הכל",
@ -851,7 +851,7 @@
"EnableFasterAnimations": "אנימציות מהירות",
"EnableBlurHash": "הפעל מצייני מיקום מטושטשים לתמונות",
"EnableBlurHashHelp": "תמונות שעדיין נטענות יוצגו עם מציין מיקום ייחודי.",
"Bwdif": "BWDIF",
"Bwdif": "Bob Weaver DeInterlacing Filter (BWDIF)",
"ButtonCast": "שדר למכשיר",
"AllowTonemappingHelp": "מיפוי-טונים מאפשר המרה של וידאו מ-HDR ל-SDR תוך שמירה על פרטי וצבעי תמונה, החשובים לשימור מידע מהסצנה המקורית. כרגע עובד רק בקידוד קבצים של HDR10, HLG ו-DoVi. תכונה זו מצריכה הרצה של GPGPU בהתאם.",
"Subtitle": "כתובית",
@ -866,7 +866,7 @@
"ShowLess": "הצג פחות",
"ShowAdvancedSettings": "הצג הגדרות מתקדמות",
"SettingsWarning": "שינוי ערכים אלו עלול לגרום לחוסר יציבות או בעיות חיבור. אם אתה נתקל בבעיות, אנו ממליצים להחזיר אותם לערכי ברירת המחדל.",
"ServerRestartNeededAfterPluginInstall": "Jellyfin יצטרך לאתחל לאחר התקנת תוסף.",
"ServerRestartNeededAfterPluginInstall": "Jellyfin יצטרך לאתחל לאחר התקנת התוסף.",
"SeriesDisplayOrderHelp": "סדר פרקים על פי תאריך שידור, סדר DVD, או מספרים אבסולוטיים.",
"Series": "סדרה",
"SendMessage": "שלח הודעה",
@ -904,7 +904,7 @@
"SubtitleOffset": "קיזוז כתוביות",
"SubtitleAppearanceSettingsDisclaimer": "הגדרות אלו לא יחולו את קבצי כתוביות גרפיים (DVD ,PGS, וכו') או כתוביות SSA\\ASS עם סגנונות מוטמעים.",
"LabelAutoDiscoveryTracing": "אפשר מעקב אחר גילוי אוטומטי.",
"LabelAppNameExample": "דוגמא: Sickbeard, Sonarr",
"LabelAppNameExample": "שם לזיהוי מפתחות API. הגדרה זו לא תשנה התנהגות.",
"LabelAllowHWTranscoding": "אפשר קידוד חומרה",
"LabelAlbumArtMaxWidth": "רוחב מירבי של אומנות אלבום",
"LabelAlbumArtMaxHeight": "גובה מירבי של אומנות אלבום",
@ -1129,7 +1129,7 @@
"TypeOptionPluralBook": "ספרים",
"TypeOptionPluralAudio": "קטעי שמע",
"Video": "סרטון",
"Yadif": "YADIF",
"Yadif": "Yet Another DeInterlacing Filter (YADIF)",
"LabelMaxChromecastBitrate": "איכות הזרמת Google Cast",
"LabelMethod": "שיטה",
"LabelNewsCategories": "קטגוריות חדשות",
@ -1269,7 +1269,7 @@
"DeleteSeries": "מחיקת סידרה",
"DeleteEpisode": "מחיקת פרק",
"DeleteName": "מחיקת {0}",
"SelectAudioNormalizationHelp": "עוצמת רצועת שמע - משנה את העוצמה של כל רצועה כך שהם יתנגנו בעוצמת קול זהה. עוצמת אלבום - משנה את העוצמה של כל רצועות השמע באלבום בלבד, תוך שמירה על התחום הדינמי של האלבום.",
"SelectAudioNormalizationHelp": "עוצמת רצועת שמע - משנה את העוצמה של כל רצועה כך שעוצמת הקול תישאר זהה. עוצמת אלבום - משנה את העוצמה של רצועות השמע באלבום בלבד, תוך שמירה על התחום הדינמי של האלבום. החלפה בין \"כבוי\" ושאר האפשרויות דורשת ריסוט המנגינה.",
"LabelAllowContentWithTags": "אפשר פריטים עם תגיות",
"EnableSmoothScroll": "הפעל גלילה חלקה",
"HeaderDeleteSeries": "מחק סדרה",
@ -1278,11 +1278,11 @@
"LabelMaxDaysForNextUpHelp": "הגדר את מספר הימים המקסימלי שתכנית צריכה להישאר ברשימת 'הבא בתור' מבלי לצפות בה.",
"LabelMaxVideoResolution": "רזולוצייה מקסימלית המותרת להמרת קידוד וידאו",
"LabelLocalCustomCss": "קוד CSS לעיצוב מותאם אישית ללקוח זה בלבד. ייתכן שתרצה להשבית את קוד ה-CSS המסופק על ידי השרת.",
"LabelMaxAudiobookResume": "דקות נותרות בספר המוקלט להמשך",
"LabelMaxAudiobookResume": "דקות שנותרו להמשך הספר המוקלט",
"LabelMaxAudiobookResumeHelp": "כותרים נחשבים כנוגנו במלואם כאשר משך הזמן הנותר קטן יותר מערך זה.",
"LabelMetadataReaders": "קוראי מטא-דאטה",
"LabelMetadataSavers": "שומרי מטא-דאטה",
"PlaybackError.RateLimitExceeded": "מדיה",
"PlaybackError.RateLimitExceeded": "לא ניתן לנגן את המדיה כרגע עקבת מגבלה על קצב השימוש.",
"CoverArtist": "אמן קאבר",
"Colorist": "רשימת צבעים",
"Author": "יוצר",

View file

@ -164,7 +164,7 @@
"Label3DFormat": "3D formátum",
"LabelAlbumArtists": "Album előadók",
"LabelArtists": "Előadók",
"LabelAudioLanguagePreference": "Audió nyelvének beállítása",
"LabelAudioLanguagePreference": "Hang előnyben részesített nyelve",
"LabelBirthYear": "Születési év",
"LabelCachePath": "Gyorsítótár útvonal",
"LabelCollection": "Gyűjtemény",
@ -683,8 +683,8 @@
"LabelAllowHWTranscoding": "Hardveres átkódolás engedélyezése",
"LabelAllowedRemoteAddresses": "Távoli IP cím szűrő",
"LabelAllowedRemoteAddressesMode": "Távoli IP cím szűrő mód",
"LabelAppName": "App neve",
"LabelAppNameExample": "Például: Sickbeard, Sonarr",
"LabelAppName": "Alkalmazás neve",
"LabelAppNameExample": "Ember számára olvasható név az API -kulcsok azonosításához. Ez a beállítás nincs hatással a működésre.",
"LabelAutomaticallyRefreshInternetMetadataEvery": "A metaadatok automatikus frissítése az internetről",
"LabelBindToLocalNetworkAddress": "Kötés a helyi hálózati címhez",
"LabelBindToLocalNetworkAddressHelp": "A helyi IP cím felülbírálása a HTTP szerverhez való csatlakozáshoz. Ha üres marad, a szerver minden elérhető címhez kötődik. Az érték megváltoztatásához a szerver újraindítása szükséges.",
@ -1148,11 +1148,11 @@
"XmlDocumentAttributeListHelp": "Ezek a tulajdonságok minden XML válaszüzenet gyökér elemére alkalmazásra kerülnek.",
"Thumb": "Miniatűr",
"LabelBitrate": "Bitráta",
"LabelAudioSampleRate": "Audió mintavételi ráta",
"LabelAudioCodec": "Audió kódek",
"LabelAudioChannels": "Audió csatorna",
"LabelAudioBitrate": "Audió bitráta",
"LabelAudioBitDepth": "Audió bitmélység",
"LabelAudioSampleRate": "Hang mintavételi sebessége",
"LabelAudioCodec": "Hangkodek",
"LabelAudioChannels": "Hangcsatornák",
"LabelAudioBitrate": "Hang bitsebessége",
"LabelAudioBitDepth": "Hang bitmélysége",
"CopyStreamURLSuccess": "URL másolása sikeres.",
"CopyStreamURL": "Stream URL másolása",
"PlaybackData": "Lejátszási információk",
@ -1269,7 +1269,7 @@
"Album": "Album",
"LabelLibraryPageSizeHelp": "Az oldalnként megmutatott elemek száma. Nullára állítva a lapozási funkció ki lesz kapcsolva.",
"LabelLibraryPageSize": "Könyvtár oldalméret",
"LabelDeinterlaceMethod": "Deinterlacing mód",
"LabelDeinterlaceMethod": "Váltottsorosság-mentesítő mód",
"DeinterlaceMethodHelp": "Válaszd ki a szétválasztási módot, amelyet a váltott soros tartalom szoftveres átkódolásához használ. Ha engedélyezed a hardveres deinterlace-t támogató hardveres gyorsítást, akkor a hardveres deinterlacer lesz használva e beállítás helyett.",
"UnsupportedPlayback": "A Jellyfin nem tudja feloldani a DRM-mel védett tartalmak titkosítását, de ettől függetlenül mindig megpróbálja a lejátszást, a védett címek esetén is. Néhány fájl emiatt teljesen feketeként jelenhet meg a titkosítás vagy a nem támogatott funkciók miatt, például az interaktív címeknél.",
"Yadif": "YADIF",
@ -1373,7 +1373,7 @@
"ButtonUseQuickConnect": "Gyors kapcsolódás használata",
"ButtonActivate": "Aktiválás",
"Authorize": "Engedélyezés",
"Bwdif": "BWDIF",
"Bwdif": "Bob Weaver váltottsorosság-mentesítő szűrő (BWDIF)",
"SpecialFeatures": "Speciális tartalmak",
"QuickConnectNotActive": "A gyors csatlakozás nem engedélyezett ezen a szerveren",
"QuickConnectNotAvailable": "Kérd meg a szerver adminisztrátorát, hogy engedélyezze a gyors csatlakozást",
@ -1773,9 +1773,9 @@
"LabelIsHearingImpaired": "Hallássérültek számára (SDH)",
"GoHome": "Kezdőlapra",
"BackdropScreensaver": "Háttér képernyővédő",
"SelectAudioNormalizationHelp": "Sáverősítés - az egyes sávok hangerejét állítja be, hogy azonos hangerővel játsszák le őket. Album gain - csak az album összes zeneszámának hangerejét állítja be, megtartva az album dinamikatartományát.",
"SelectAudioNormalizationHelp": "Számerősítés az egyes számok hangerejét állítja be, hogy azonos hangerővel legyenek lejátszva. Albumerősítés az album összes számának hangerejét állítja, megtartva az album dinamikatartományát.",
"LabelAlbumGain": "Album nyereség",
"LabelSelectAudioNormalization": "Hang normalizálás",
"LabelSelectAudioNormalization": "Hangnormalizálás",
"LogoScreensaver": "Logo képernyővédő",
"UnknownError": "Ismeretlen hiba történt.",
"LabelTrackGain": "Címnyereség",
@ -1868,5 +1868,43 @@
"Creator": "Készítő",
"Editor": "Szerkesztő",
"EnableDtsHelp": "Csak akkor engedélyezze, hogyha az eszköze támogatja a DTS-t vagy ha csatlakoztatott egy megfelelő audió vevőkészüléket. Ellenkező esetben visszajátszási problémákat okozhat.",
"Author": "Szerző"
"Author": "Szerző",
"AllowStreamSharingHelp": "Engedélyezés, hogy a Jellyfin megkettőzze a tunerből származó mpegts adatfolyamot, és megossza azt a kliensekkel. Ez akkor hasznos, ha a tuner korlátozott számú adatfolyamot támogat, de ez egyéb lejátszási problémákat okozhat.",
"AllowFmp4TranscodingContainerHelp": "Az fMP4 átkódolási konténer engedélyezése ehhez a tunerhez, a HEVC és HDR tartalmak engedélyezéséhez. Nem minden tuner kompatibilis ezzel a tárolóval. Tiltsa le, ha lejátszási problémákat tapasztal.",
"Alternate": "Alternatív",
"AlternateDVD": "Alternatív DVD",
"AllowTonemappingSoftwareHelp": "A tónusleképzés képes a HDR videók dinamika tartományát SDR tartományba átalakítani, miközben megtartja a kép színét és részleteit, ami elengedhetetlen az eredeti jelenet megőrzéséhez. Jelenleg csak 10 bites HDR10, HLG és DoVi tartalmakon működik.",
"DateModified": "Dátum módosítva",
"EditLyrics": "Dalszöveg módosítása",
"DisableVbrAudioEncodingHelp": "Megakadályozza a szervert hogy a hangot VBR-rel kódolja a kliensnek.",
"HeaderAddLyrics": "Dalszöveg hozzáadása",
"EnableHi10p": "H.264 High 10 profil bekapcsolása",
"EnableHi10pHelp": "Kapcsold be hogy megakadályozd a H.264 10-bites videók transzkódolását. Kapcsold ki ezt a beállítást ha a videó üres képkockákat jelenít meg.",
"HeaderAudioAdvanced": "Haladó Hang",
"EnableTrueHdHelp": "Csak akkor kapcsold be ha az eszköz támogatja a TrueHD-t vagy csatlakoztatva van egy kompatibilis hang vevőhöz, egyébként lejátszási hibát okozhat.",
"HeaderPreviewLyrics": "Dalszöveg Előnézet",
"HeaderLyricDownloads": "Dalszöveg Letöltések",
"HeaderUploadLyrics": "Dalszöveg Feltöltése",
"HeaderNextItemPlayingInValue": "Következő: {0} Lejátszás kezdődik: {1}",
"Inker": "Színező",
"LabelAllowFmp4TranscodingContainer": "fMP4 transzkódoló container engedélyezése",
"Colorist": "Kolorista",
"AlwaysRemuxFlacAudioFilesHelp": "Ha vannak olyan fájlok amiket a böngésző nem játszik le vagy helytelenül számítja ki az időbélyegeket akkor kapcsold be ezt mint megoldás.",
"AlwaysRemuxMp3AudioFilesHelp": "Ha vannak olyan fájlok amikben a böngésző helytelenül számítja ki az időbélyegeket akkor kapcsold be ezt mint megoldás.",
"CoverArtist": "Borító művész",
"AndOtherArtists": "{0} és {1} további művész.",
"EnableDts": "DTS (DCA) bekapcsolása",
"EnableTrueHd": "TrueHD bekapcsolása",
"HeaderNextItem": "Következő {0}",
"HeaderVideoAdvanced": "Haladó VIdeó",
"Illustrator": "Illusztrátor",
"LabelAlwaysRemuxFlacAudioFiles": "Mindig remuxolja a FLAC-hangfájlokat",
"LabelAlwaysRemuxMp3AudioFiles": "Mindig remuxolja az MP3-hangfájlokat",
"LabelCustomTagDelimiters": "Egyéni címkeelválasztó",
"LabelCustomTagDelimitersHelp": "A címkék elválasztójaként kezelendő karakterek.",
"LabelDuration": "Hossz",
"LabelAudioTagSettings": "Hangcímke-beállítások",
"LabelDelimiterWhitelist": "Elválasztók engedélyezési listája",
"LabelDelimiterWhitelistHelp": "Elemek, melyek nem lesznek figyelembe véve a címkefelosztásnál. Soronként egy elem.",
"LabelDisableVbrAudioEncoding": "Változó bitsebességű hangfelvétel letiltása"
}

View file

@ -1860,7 +1860,7 @@
"LabelWidthResolutionsHelp": "Elenco separato da virgole delle larghezze (px) con cui saranno generate le immagini di Trickplay. Tutte le immagini devono essere generate in modo proporzionale alla sorgente, quindi una larghezza di 320 su un video 16:9 finisce per essere circa 320x180.",
"LabelTileHeight": "Altezza Riquadro",
"LabelTrickplayAccelEncoding": "Abilita l'accelerazione hardware della codifica MJPEG",
"LabelTrickplayAccelEncodingHelp": "Disponibile solo per QSV, VAAPI e VideoToolbox. Questa opzione non ha alcun effetto sugli altri metodi di accelerazione hardware.",
"LabelTrickplayAccelEncodingHelp": "Disponibile solo per QSV, VAAPI, VideoToolbox e RKMPP. Questa opzione non ha alcun effetto sugli altri metodi di accelerazione hardware.",
"ConfirmDeleteLyrics": "Cancellare questi testi li rimuoverà sia dalle cartelle del sistema che dalla tua libreria multimediale. Sei sicuro di continuare?",
"DeleteLyrics": "Cancella testi",
"ErrorDeletingLyrics": "C'è stato un errore nel cancellare i testi dal server. Perfavore controlla che Jellyfin abbia accesso alla scrittura della cartella dei media e riprova.",
@ -1943,5 +1943,8 @@
"EnableHi10pHelp": "Abilita per evitare la transcodifica dei video H.264 a 10 bit. Disabilitare quest'opzione se il video mostra fotogrammi vuoti.",
"LabelSaveTrickplayLocally": "Salva le immagini trickplay accanto ai media",
"LabelSaveTrickplayLocallyHelp": "Salvare le immagini trickplay nella stessa cartella del video ti permetterà di spostarle e accederle più facilmente.",
"ReplaceTrickplayImages": "Sostituisci le immagini trickplay"
"ReplaceTrickplayImages": "Sostituisci le immagini trickplay",
"FallbackMaxStreamingBitrateHelp": "Il bitrate massimo dello streaming viene utilizzato quando ffprobe non è in grado di determinare il bitrate sorgente. Ciò aiuta a impedire che i client richiedano un bitrate di transcodifica troppo alto che potrebbe causare il fallimento del player e il sovraccarico dell'encoder.",
"LabelFallbackMaxStreamingBitrate": "Bitrate massimo di ripiego (Mbps)",
"DateModified": "Data di modifica"
}

View file

@ -1011,7 +1011,7 @@
"Filters": "Filtre",
"HeaderExternalIds": "Eksterne IDer",
"HeaderFetcherSettings": "Henteinnstillinger",
"TabServer": "Server",
"TabServer": "Tjener",
"TabStreaming": "Strømming",
"TagsValue": "Tagger: {0}",
"ThemeSongs": "Temamusikk",
@ -1901,5 +1901,66 @@
"FallbackMaxStreamingBitrateHelp": "Den maksimale strømmingbitraten brukes som en fallback når ffprobe ikke klarer å bestemme kildestrømmens bitrate. Dette bidrar til å forhindre at klienter ber om en for høy transkodingsbitrate, noe som kan føre til at spilleren mislykkes og overbelaste enkoderen.",
"LabelAllowFmp4TranscodingContainer": "Tillat fMP4 omkoderbeholder",
"LabelAllowStreamSharing": "Tillat strømdeling",
"LabelFallbackMaxStreamingBitrate": "Fallback maksimum strømbitrate (Mb/s)"
"LabelFallbackMaxStreamingBitrate": "Fallback maksimum strømbitrate (Mb/s)",
"LabelLyricDownloaders": "Sangtekstnedlasetere",
"LibraryScanFanoutConcurrencyHelp": "Maksimalt antall parallelle oppgaver under bibliotekskanning. Hvis du setter dette til 0, velges en grense basert på antall kjerner i systemet. ADVARSEL: Hvis du setter dette tallet for høyt, kan det føre til problemer med nettverksfilsystemer. Hvis du støter på problemer, senk dette tallet.",
"RenderPgsSubtitle": "Eksperimentell PGS-undertekstgjengivelse",
"RenderPgsSubtitleHelp": "Bestem om klienten skal gjengi PGS-undertekster i stedet for å bruke innbrente undertekster. Dette kan unngå transkoding på tjenersiden i bytte mot gjengivelsesytelse på klientsiden.",
"PlaybackError.NO_MEDIA_ERROR": "Kan ikke finne en gyldig mediekilde å spille av.",
"LyricDownloadersHelp": "Aktiver og ranger dine foretrukne undertekstnedlastere i prioritert rekkefølge.",
"PlaylistPublic": "Tillat allmenntilgang",
"PluginEnableError": "Det oppstod en feil under aktivering av pluginen.",
"PluginDisableError": "Det oppstod en feil under deaktivering av pluginen.",
"PluginLoadConfigError": "Det oppsto en feil under henting av konfigurasjonssidene for pluginen.",
"PluginUninstallError": "Det oppstod en feil under avinstallering av pluginen.",
"PlaybackError.RateLimitExceeded": "Dette mediet kan ikke spilles av på dette tidspunktet på grunn av hastighetsbegrensninger.",
"SelectPreferredTranscodeVideoCodecHelp": "Velg den foretrukne videokodeken å transkode til. Hvis den foretrukne kodeken ikke støttes, bruker serveren den nest beste tilgjengelige kodeken.",
"PlaybackError.SERVER_ERROR": "Avspilling mislyktes på grunn av en tjenerfeil.",
"VideoCodecTagNotSupported": "Videokodek-taggen støttes ikke",
"LibraryInvalidItemIdError": "Biblioteket er i en ugyldig tilstand og kan ikke redigeres. Du støter muligens på en feil: banen i databasen er ikke den riktige banen på filsystemet.",
"LimitSupportedVideoResolutionHelp": "Bruk 'Maksimal tillatt videoomkodingsoppløsning' som maksimal støttet videooppløsning.",
"AllowVideoToolboxTonemappingHelp": "Maskinvare-akselerert tone-mapping levert av VideoToolbox. Den fungerer med de fleste HDR-formater, inkludert HDR10, HDR10+, og HLG, men fungerer ikke med Dolby Vision Profile 5. Dette har høyere prioritet sammenlignet med en annen Metal-implementering.",
"PlaybackError.ASS_RENDER_ERROR": "Det oppsto en feil i ASS/SSA-undertekstgjengivelsen.",
"PlaybackError.MEDIA_DECODE_ERROR": "Avspilling mislyktes på grunn av en feil ved dekoding av mediet.",
"PluginLoadRepoError": "Det oppstop en feil under henting av repo-detaljer for pluginen.",
"EnableVideoToolboxTonemapping": "Aktiver VideoToolbox-tonemapping",
"LabelSaveTrickplayLocallyHelp": "Lagring av trickplay-bilder i mediemapper vil plassere dem ved siden av mediene dine for enkel migrering og tilgang.",
"LabelTrickplayKeyFrameOnlyExtractionHelp": "Trekk ut nøkkelrammer bare for betydelig raskere behandling med mindre nøyaktig timing. Hvis den konfigurerte maskinvaredekoderen ikke støtter denne modusen, vil programvaredekoderen brukes i stedet.",
"PlaybackError.MEDIA_NOT_SUPPORTED": "Avspilling mislyktes fordi media ikke støttes av denne klienten.",
"PlaybackError.PLAYER_ERROR": "Avspilling mislyktes på grunn av en fatal feil i avspilleren.",
"PlaybackError.NotAllowed": "Avspilling av dette media er ikke tillatt.",
"PlaylistError.AddFailed": "Feil ved tilføying til spilleliste",
"PlaylistError.CreateFailed": "Feil ved opprettelse av spilleliste",
"PlaylistPublicDescription": "Tillat denne spillelisten å bli sett av alle påloggede brukere.",
"SelectPreferredTranscodeVideoAudioCodecHelp": "Velg den foretrukne lydkodeken som skal transkodes til for videoinnhold. Hvis den foretrukne kodeken ikke støttes, bruker tjeneren den nest beste tilgjengelige kodeken.",
"EncodingFormatHelp": "Velg videokodingen som Jellyfin skal omkode til. Jellyfin bruker programvarekoding når maskinvareakselerasjon for valgt format ikke er tilgjengelig. H264-koding vil alltid være aktivert.",
"LabelTrickplayAccelEncodingHelp": "Foreløpig kun tilgjengelig på QSV, VA-API, VideoToolbox og RKMPP, dette alternativet har ingen effekt på andre maskinvareakselerasjonsmetoder.",
"NonBlockingScan": "Non Blocking - køgenerering, og returnerer deretter",
"BlockingScan": "Blocking - generering settes i kø, blokker skanning til den er fullført",
"LabelProcessPriorityHelp": "Å sette denne lavere eller høyere vil avgjøre hvordan prosessoren prioriterer ffmpeg trickplay generasjonsprosessen i forhold til andre prosesser. Hvis du legger merke til nedgang mens du genererer trickplay-bilder, men ikke ønsker å stoppe generasjonen deres, kan du prøve å senke dette samt antall tråder.",
"LabelScanBehaviorHelp": "Standardoppførselen er non-blocking, som vil legge til media til biblioteket før trickplay-generering er ferdig. Blocking vil sikre at trickplay-filer genereres før media legges til biblioteket, men vil gjøre skanningene betydelig lengre.",
"LabelImageIntervalHelp": "Tidsintervall (ms) mellom hvert nytt trickplay-bilde.",
"LabelTrickplayThreadsHelp": "Antall tråder som skal passeres til '-threads'-argumentet til ffmpeg.",
"ExtractTrickplayImagesHelp": "Trickplay-bilder ligner på kapittelbilder, bortsett fra at de spenner over hele lengden av innholdet og brukes til å vise en forhåndsvisning når du scrubber gjennom videoer.",
"LabelExtractTrickplayDuringLibraryScanHelp": "Generer trickplay-bilder når videoer importeres under biblioteksskanningen. Ellers vil de bli trukket ut under den planlagte oppgaven med trickplay-bilder. Hvis generering er satt til non-blocking, vil dette ikke påvirke tiden det tar å fullføre en bibliotekskanning.",
"LabelQscaleHelp": "Kvalitetsskalaen til bilder som sendes ut av ffmpeg, med 2 som høyeste kvalitet og 31 er den laveste.",
"LabelExtractTrickplayDuringLibraryScan": "Trekk ut trickplay-bilder under skanningen av biblioteket",
"OptionExtractTrickplayImage": "Aktiver uttrekking av trickplay-bilde",
"LabelWidthResolutionsHelp": "Kommaseparert liste over breddene (px) som trickplay-bilder vil bli generert med. Alle bilder skal genereres proporsjonalt med kilden, så en bredde på 320 på en 16:9-video ender opp på rundt 320x180.",
"LabelTileWidthHelp": "Maksimalt antall bilder per rad i X-retningen.",
"LabelTileHeightHelp": "Maksimalt antall bilder per kolonne i Y-retningen.",
"LabelJpegQualityHelp": "JPEG-komprimeringskvaliteten for trickplay-bilder.",
"LabelAudioTagSettings": "Innstillinger for lydtager",
"LabelCustomTagDelimiters": "Egendefinert skilletegn for tagger",
"LabelCustomTagDelimitersHelp": "Tegn som skal behandles som skilletegn for å separere tagger.",
"LabelDelimiterWhitelist": "Hviteliste for skilletegn",
"LabelDelimiterWhitelistHelp": "Objekter som skal ekskluderes fra tagdeling. Ett objekt per linje.",
"PreferNonstandardArtistsTag": "Foretrekk ARTISTER-tag om tilgjengelig",
"PreferNonstandardArtistsTagHelp": "Bruk ikke-standard ARTISTS-taggen istedenfor ARTIST-taggen når den er tilgjengelig.",
"UseCustomTagDelimiters": "Bruk egendefinert skilletegn for tagger",
"UseCustomTagDelimitersHelp": "Del artist- og sjanger-tagger med egendefinert tegn.",
"DateModified": "Data modifisert",
"MessageCancelSeriesTimerError": "Det oppstod en feil under avbryting av serietidtakeren",
"MessageCancelTimerError": "Det oppstod en feil under avbryting av tidtakeren",
"MessageSplitVersionsError": "Det oppsto en feil under oppdeling av versjoner"
}

View file

@ -1182,7 +1182,7 @@
"ValueCodec": "Codec: {0}",
"ValueContainer": "Container: {0}",
"ValueVideoCodec": "Videocodec: {0}",
"Whitelist": "Whitelist",
"Whitelist": "Positieflijst",
"MediaInfoCodec": "Codec",
"Menu": "Menu",
"LabelTranscodingFramerate": "Verversingssnelheid transcoderen",
@ -1205,7 +1205,7 @@
"LabelWeb": "Web",
"LeaveBlankToNotSetAPassword": "Je kunt dit veld leeg laten om geen wachtwoord in te stellen.",
"DashboardServerName": "Server: {0}",
"LabelVideoBitrate": "Beeldbitsnelheid",
"LabelVideoBitrate": "Bitsnelheid beeld",
"LabelVideoCodec": "Beeldcodec",
"LabelXDlnaCap": "Device Capability-id",
"DashboardVersionNumber": "Versie: {0}",
@ -1442,7 +1442,7 @@
"PreferFmp4HlsContainerHelp": "Gebruik fMP4 als de standaardcontainer voor HLS, waardoor direct streamen van HEVC- en AV1-inhoud op ondersteunde apparaten mogelijk wordt.",
"PreferFmp4HlsContainer": "fMP4-HLS-mediacontainer verkiezen",
"LabelSyncPlayInfo": "SyncPlay-informatie",
"LabelOriginalMediaInfo": "Informatie oorspronkelijke media",
"LabelOriginalMediaInfo": "Oorspronkelijke media-informatie",
"LabelRemuxingInfo": "Remux-informatie",
"LabelDirectStreamingInfo": "Informatie direct streamen",
"LabelTranscodingInfo": "Transcoderingsinformatie",
@ -1776,7 +1776,7 @@
"BackdropScreensaver": "Schermbeveiliging met achtergronden",
"LogoScreensaver": "Schermbeveiliging met logo",
"LabelIsHearingImpaired": "Voor slechthorenden (ODS)",
"SelectAudioNormalizationHelp": "Nummerversterking regelt het volume van elk individueel nummer zodat alle nummers even luid afspelen. Albumversterking regelt het volume van alle nummers op een album, zodat het dynamische bereik van het album behouden blijft.",
"SelectAudioNormalizationHelp": "Nummerversterking regelt het volume van elk individueel nummer zodat alle nummers even luid afspelen. Albumversterking regelt het volume van alle nummers op een album, waarbij het dynamische bereik van het album behouden blijft. Na het wisselen tussen deze opties moet het afspelen herstart worden.",
"LabelAlbumGain": "Albumversterking",
"LabelSelectAudioNormalization": "Geluidsnormalisatie",
"LabelTrackGain": "Nummerversterking",
@ -1859,7 +1859,7 @@
"EnableLibrary": "Bibliotheek inschakelen",
"EnableLibraryHelp": "Het uitschakelen van een bibliotheek verbergt deze voor alle gebruikers.",
"LabelTrickplayAccelEncoding": "Hardwareversnelde MJPEG-codering inschakelen",
"LabelTrickplayAccelEncodingHelp": "Momenteel enkel beschikbaar op QSV, VAAPI en VideoToolbox; deze optie heeft geen effect bij andere methoden voor hardwareversnelling.",
"LabelTrickplayAccelEncodingHelp": "Momenteel enkel beschikbaar op QSV, VA-API, VideoToolbox en RKMPP; deze optie heeft geen effect bij andere methoden voor hardwareversnelling.",
"ViewLyrics": "Liedtekst weergeven",
"ErrorDeletingLyrics": "Er is een fout opgetreden bij het verwijderen van de liedtekst van de server. Controleer of Jellyfin schrijfrechten heeft in de mediamap en probeer het opnieuw.",
"HeaderDeleteLyrics": "Liedtekst verwijderen",
@ -1951,5 +1951,20 @@
"LabelAllowStreamSharing": "Streamdelen toestaan",
"LabelFallbackMaxStreamingBitrate": "Maximale terugvalbitsnelheid voor streamen (Mbps)",
"LabelLyricDownloaders": "Ophalers voor liedteksten",
"LyricDownloadersHelp": "Rangschik je voorkeursophalers voor liedteksten op volgorde van prioritieit."
"LyricDownloadersHelp": "Rangschik je voorkeursophalers voor liedteksten op volgorde van prioritieit.",
"RenderPgsSubtitle": "PGS-ondertiteling weergeven (experimenteel)",
"RenderPgsSubtitleHelp": "Bepaal of de cliënt PGS-ondertiteling zelf moet weergeven in plaats van ingebrande ondertiteling te gebruiken. Dit voorkomt transcoderen aan de serverkant maar kan de weergaveprestaties aan de cliëntkant beïnvloeden.",
"LabelAudioTagSettings": "Instellingen voor geluidstags",
"LabelCustomTagDelimiters": "Aangepast scheidingsteken voor tags",
"LabelCustomTagDelimitersHelp": "Tekens die als scheidingsteken worden gezien om tags van elkaar te scheiden.",
"LabelDelimiterWhitelist": "Positieflijst scheidingstekens",
"LabelDelimiterWhitelistHelp": "Items die worden uitgesloten van het splitsen van tags. Eén item per regel.",
"UseCustomTagDelimiters": "Aangepast scheidingsteken voor tags gebruiken",
"UseCustomTagDelimitersHelp": "Artiest- en genre-tags splitsen met aangepaste tekens.",
"PreferNonstandardArtistsTagHelp": "Gebruik de incourante ARTISTS-tag in plaats van de ARTIST-tag indien beschikbaar.",
"PreferNonstandardArtistsTag": "ARTISTS-tag verkiezen indien beschikbaar",
"MessageCancelTimerError": "Er is een fout opgetreden bij het annuleren van de tijdklok",
"MessageSplitVersionsError": "Er is een fout opgetreden bij het splitsen van de versies",
"MessageCancelSeriesTimerError": "Er is een fout opgetreden bij het annuleren van de serietijdklok",
"DateModified": "Datum gewijzigd"
}

View file

@ -1780,7 +1780,7 @@
"LabelAlbumGain": "Wzmocnienie albumu",
"LabelSelectAudioNormalization": "Normalizacja dźwięku",
"LabelTrackGain": "Wzmocnienie utworu",
"SelectAudioNormalizationHelp": "Wzmocnienie utworu reguluje głośność każdego utworu tak, aby odtwarzał się z tą samą głośnością. Wzmocnienie albumu reguluje głośność tylko wszystkich utworów w albumie, zachowując zakres dynamiki albumu.",
"SelectAudioNormalizationHelp": "Wzmocnienie utworu reguluje głośność każdego utworu tak, aby odtwarzał się z tą samą głośnością. Wzmocnienie albumu reguluje głośność tylko wszystkich utworów w albumie, zachowując zakres dynamiki albumu. Przełączanie między opcją \"Wyłączone\" a innymi wymaga ponownego uruchomienia bieżącego odtwarzania.",
"SearchResultsEmpty": "Wybacz! Nie znaleziono wyników dla „{0}”",
"HeaderAllRecordings": "Wszystkie nagrania",
"LabelBuildVersion": "Wersja kompilacji",
@ -1859,7 +1859,7 @@
"EncodingFormatHelp": "Wybierz kodowanie wideo, którym Jellyfin powinien transkodować. Jellyfin użyje kodowania programowego, gdy akceleracja sprzętowa dla wybranego formatu nie jest dostępna. Kodowanie H264 będzie zawsze włączone.",
"EnableLibrary": "Włącz bibliotekę",
"EnableLibraryHelp": "Wyłączenie biblioteki spowoduje ukrycie jej przed wszystkimi widokami użytkowników.",
"LabelTrickplayAccelEncodingHelp": "Opcja ta jest obecnie dostępna tylko przy użyciu QSV, VAAPI i VideoToolbox, nie ma wpływu na inne metody akceleracji sprzętowej.",
"LabelTrickplayAccelEncodingHelp": "Opcja ta jest obecnie dostępna tylko przy użyciu QSV, VA-API, VideoToolbox i RKMPP, nie ma wpływu na inne metody akceleracji sprzętowej.",
"LabelTrickplayAccelEncoding": "Włącz kodowanie MJPEG z akceleracją sprzętową",
"ConfirmDeleteLyrics": "Usunięcie tych słów spowoduje ich usunięcie zarówno z systemu plików, jak i biblioteki multimediów. Czy na pewno chcesz kontynuować?",
"HeaderNoLyrics": "Nie znaleziono słów",
@ -1950,5 +1950,22 @@
"LabelAllowFmp4TranscodingContainer": "Zezwalaj na kontener transkodowania fMP4",
"LabelAllowStreamSharing": "Zezwalaj na udostępnianie strumieniowe",
"LabelFallbackMaxStreamingBitrate": "Zastępcze maksimum przepływności strumienia (Mbps)",
"VideoCodecTagNotSupported": "Tag kodeka wideo nie jest obsługiwany"
"VideoCodecTagNotSupported": "Tag kodeka wideo nie jest obsługiwany",
"LabelLyricDownloaders": "Dostawcy słów",
"LyricDownloadersHelp": "Umożliwia aktywowanie i używanie dostawców napisów w preferowanej kolejności.",
"RenderPgsSubtitle": "Eksperymentalne renderowanie napisów PGS",
"RenderPgsSubtitleHelp": "Określ, czy klient powinien renderować napisy PGS zamiast używać wypalonych napisów. Dzięki temu można uniknąć transkodowania po stronie serwera w zamian za wydajność renderowania po stronie klienta.",
"LabelAudioTagSettings": "Ustawienia tagów audio",
"LabelDelimiterWhitelist": "Biała lista ograniczników",
"LabelDelimiterWhitelistHelp": "Elementy, które należy wykluczyć z podziału tagów. Jeden element w wierszu.",
"PreferNonstandardArtistsTag": "Preferuj tag WYKONAWCY, jeśli jest dostępny",
"UseCustomTagDelimiters": "Użyj niestandardowego ogranicznika tagów",
"LabelCustomTagDelimitersHelp": "Znaki, które należy traktować jako ograniczniki oddzielające tagi.",
"PreferNonstandardArtistsTagHelp": "Jeśli jest dostępny, użyj niestandardowego tagu WYKONAWCY zamiast tagu WYKONAWCA.",
"UseCustomTagDelimitersHelp": "Podziel tagi wykonawcy/gatunku za pomocą niestandardowych znaków.",
"LabelCustomTagDelimiters": "Niestandardowy ogranicznik tagów",
"MessageCancelSeriesTimerError": "Wystąpił błąd podczas anulowania timera serialu",
"MessageCancelTimerError": "Wystąpił błąd podczas anulowania timera",
"MessageSplitVersionsError": "Wystąpił błąd podczas podziału wersji",
"DateModified": "Data modyfikacji"
}

View file

@ -1821,7 +1821,7 @@
"EnableLibraryHelp": "Se desativares a biblioteca, ela será ocultada de todas as visualizações do utilizador.",
"EnableLibrary": "Ativar a biblioteca",
"LabelTrickplayAccelEncoding": "Ativar a codificação MJPEG acelerada por hardware",
"LabelTrickplayAccelEncodingHelp": "Atualmente apenas disponível em QSV e VAAPI, esta opção não tem efeito noutros métodos de aceleração de hardware.",
"LabelTrickplayAccelEncodingHelp": "Atualmente apenas disponível em QSV, VA-API, VideoToolbox e RKMPP, esta opção não tem efeito noutros métodos de aceleração de hardware.",
"ChannelResolutionUHD4K": "UHD (4K)",
"Lyrics": "Letras",
"DeleteLyrics": "Eliminar letras",

View file

@ -1823,7 +1823,7 @@
"LimitSupportedVideoResolutionHelp": "Utiliza 'Resolução máxima permitida para transcodificação de vídeo' como resolução máxima de vídeo suportada.",
"EnableLibraryHelp": "Se desativares a biblioteca, ela será ocultada de todas as visualizações do utilizador.",
"EnableLibrary": "Ativar a biblioteca",
"LabelTrickplayAccelEncodingHelp": "Atualmente apenas disponível em QSV e VAAPI, esta opção não tem efeito noutros métodos de aceleração de hardware.",
"LabelTrickplayAccelEncodingHelp": "Atualmente apenas disponível em QSV, VA-API, VideoToolbox e RKMPP, esta opção não tem efeito noutros métodos de aceleração de hardware.",
"LabelTrickplayAccelEncoding": "Ativar a codificação MJPEG acelerada por hardware",
"ConfirmDeleteLyrics": "A eliminação destas letras irá apagá-las do sistema de ficheiros e da tua biblioteca multimédia. Tens a certeza de que queres continuar?",
"ChannelResolutionFullHD": "Full HD",

View file

@ -1102,7 +1102,7 @@
"MediaInfoPixelFormat": "Pixel formát",
"MediaInfoFramerate": "Snímková frekvencia",
"MediaInfoDefault": "Predvolený",
"MediaInfoCodecTag": "Štítok kodeku",
"MediaInfoCodecTag": "Tag kodeku",
"MediaInfoBitrate": "Dátový tok",
"MediaInfoAnamorphic": "Anamorfné",
"MapChannels": "Mapovať kanály",
@ -1256,7 +1256,7 @@
"OnWakeFromSleep": "Pri prebúdzaní zo spánku",
"WeeklyAt": "{0}s na {1}",
"DailyAt": "Denne o {0}",
"LastSeen": "Naposledy videný {0}",
"LastSeen": "Posledná aktivita {0}",
"PersonRole": "ako {0}",
"ListPaging": "{0}-{1} z {2}",
"WriteAccessRequired": "Server vyžaduje práva na zapisovanie do tohoto priečinku. Prosím, uistite sa že má práva na zapisovanie a skúste to znova.",
@ -1777,7 +1777,7 @@
"LabelThrottleDelaySecondsHelp": "Čas v sekundách, po ktorom bude prekódovanie obmedzené. Musí byť dostatočne veľký, aby mal klient v rezerve dostatočné množstvo prehrávaného súboru. Funguje len vtedy, ak je povolená funkcia Obmedziť prekódovanie.",
"AllowSegmentDeletionHelp": "Odstránenie starých segmentov po ich stiahnutí klientom. Tým sa zabráni tomu, aby sa celý prekódovaný súbor uložil na disk. Ak sa vyskytnú problémy s prehrávaním, vypnite túto funkciu.",
"LabelSegmentKeepSecondsHelp": "Čas v sekundách, počas ktorého sa majú segmenty uchovávať po ich stiahnutí klientom. Funguje len vtedy, ak je povolené mazanie segmentov.",
"SelectAudioNormalizationHelp": "Zosilnenie stopy - upravuje hlasitosť jednotlivých stôp tak, aby sa prehrávali s rovnakou hlasitosťou. Zosilnenie pre album - upravuje hlasitosť všetkých skladieb iba v albume, pričom zachováva dynamický rozsah albumu.",
"SelectAudioNormalizationHelp": "Zosilnenie stopy - upravuje hlasitosť jednotlivých stôp tak, aby sa prehrávali s rovnakou hlasitosťou. Zosilnenie pre album - upravuje hlasitosť všetkých skladieb iba v albume, pričom zachováva dynamický rozsah albumu. Vypnutie a následné zapnutie si vyžaduje reštartovanie aktuálne prehrávanej skladby.",
"LabelAlbumGain": "Zosilnenie pre album",
"LabelSelectAudioNormalization": "Normalizácia hlasitosti",
"LabelTrackGain": "Zosilnenie stopy",
@ -1861,7 +1861,7 @@
"EnableLibraryHelp": "Zakázaním knižnice ju skryjete zo všetkých zobrazení používateľa.",
"Lyrics": "Texty piesní",
"LabelTrickplayAccelEncoding": "Povoliť hardvérovú akceleráciu kódovania MJPEG",
"LabelTrickplayAccelEncodingHelp": "Táto možnosť je v súčasnosti dostupná len pre QSV a VAAPI, na ostatné metódy hardvérovej akcelerácie nemá žiadny vplyv.",
"LabelTrickplayAccelEncodingHelp": "Táto možnosť je v súčasnosti k dispozícii len pre QSV, VA-API, VideoToolbox a RKMPP, na ostatné metódy hardvérovej akcelerácie nemá žiadny vplyv.",
"DeleteLyrics": "Odstrániť texty piesní",
"ConfirmDeleteLyrics": "Texty piesní budú odstránené zo systému a aj z knižnice médií. Ste si istí, že chcete pokračovať?",
"ErrorDeletingLyrics": "Pri odstraňovaní textov piesní zo servera došlo k chybe. Skontrolujte, či má Jellyfin prístup na zápis do priečinka médií, a skúste to znova.",
@ -1899,5 +1899,73 @@
"Regional": "Regionálne",
"AlternateDVD": "Alternatívne DVD",
"LabelSelectPreferredTranscodeVideoCodec": "Preferovaný video kodek pre prekódovanie",
"HeaderNextItem": "Nasleduje {0}"
"HeaderNextItem": "Nasleduje {0}",
"DisableVbrAudioEncodingHelp": "Zabrániť serveru kódovať zvuk pomocou VBR pre tohto klienta.",
"DateModified": "Dátum úpravy",
"HeaderAudioAdvanced": "Pokročilé nastavenia zvuku",
"HeaderPreviewLyrics": "Náhľad textov piesní",
"LabelAllowStreamSharing": "Povoliť zdieľanie streamu",
"LabelDuration": "Dĺžka",
"LabelDisableVbrAudioEncoding": "Zakázať kódovanie zvuku VBR",
"LabelEnablePlugin": "Povoliť zásuvný modul",
"LabelInstalled": "Nainštalované",
"LabelNotInstalled": "Nie je nainštalované",
"LabelRepository": "Repozitár",
"MediaInfoRotation": "Rotácia",
"MoveToBottom": "Presunúť na spodnú časť",
"MoveToTop": "Presunúť na vrchnú časť",
"PreferNonstandardArtistsTagHelp": "Ak je to možné, použiť neštandardný tag ARTISTS namiesto tagu ARTIST.",
"PreviewLyrics": "Náhľad textov piesní",
"Reset": "Resetovať",
"ReplaceTrickplayImages": "Nahradiť existujúce obrázky trickplay",
"LabelLyricDownloaders": "Sťahovače textov piesní",
"EditLyrics": "Upraviť texty piesní",
"HeaderAddLyrics": "Pridať texty piesní",
"HeaderUploadLyrics": "Nahrať texty piesní",
"LabelIsSynced": "Je synchronizovaný",
"NoLyricsSearchResultsFound": "Nenašli sa žiadne texty piesní.",
"PluginLoadRepoError": "Pri získavaní údajov o zásuvnom module z repozitáru došlo k chybe.",
"LabelAudioTagSettings": "Nastavenia zvukových štítkov",
"LyricDownloadersHelp": "Povoliť a zoradiť preferované sťahovače titulkov podľa priority.",
"SearchForLyrics": "Vyhľadávať texty piesní",
"EnableHi10pHelp": "Povoľte, aby ste zabránili prekódovaniu 10-bitových videí kodeku H.264. Túto možnosť zakážte, ak sa vo videu zobrazujú prázdne snímky.",
"LabelTrickplayKeyFrameOnlyExtractionHelp": "Extrahovať iba kľúčové snímky pre výrazne rýchlejšie spracovanie na úkor presnosti časovania. Ak nakonfigurovaný hardvérový dekodér nepodporuje tento režim, použije sa namiesto neho softvérový dekodér.",
"FallbackMaxStreamingBitrateHelp": "Maximálny dátový tok sa používa ako záložná hodnota, keď ffprobe nedokáže určiť dátový tok zdrojového streamu. Pomáha to zabrániť tomu, aby klienti požadovali príliš vysoký dátový tok prekódovania, čo by mohlo spôsobiť zlyhanie prehrávača a preťaženie kodéra.",
"EnableHi10p": "Povoliť profil H.264 High 10",
"LabelAllowFmp4TranscodingContainer": "Povoliť kontajner fMP4 na prekódovanie",
"LabelAlwaysRemuxFlacAudioFiles": "Vždy remuxovať zvukové súbory FLAC",
"LabelAlwaysRemuxMp3AudioFiles": "Vždy remuxovať zvukové súbory MP3",
"LabelSaveTrickplayLocallyHelp": "Uložením obrázkov trickplay do priečinkov médií sa uľahčí ich migrácia a prístup k nim.",
"LibraryInvalidItemIdError": "Knižnica je v neplatnom stave a nie je možné ju upravovať. Pravdepodobne sa stretávate s chybou: cesta v databáze nie je správna cesta v súborovom systéme.",
"SelectPreferredTranscodeVideoCodecHelp": "Vybrať preferovaný kodek videa, do ktorého sa má prekódovať. Ak preferovaný kodek nie je podporovaný, server použije ďalší najlepší dostupný kodek.",
"LabelCustomTagDelimiters": "Vlastný oddeľovač tagov",
"LabelCustomTagDelimitersHelp": "Znaky, ktoré sa majú považovať za oddeľovače na oddelenie tagov.",
"LabelDelimiterWhitelist": "Biela listina oddeľovačov",
"RenderPgsSubtitleHelp": "Určite, či má klient vykresľovať titulky formátu PGS namiesto použitia vpálených titulkov. Tým sa možno vyhnúť prekódovaniu na strane servera výmenou za horší výkon na strane klienta.",
"AllowFmp4TranscodingContainerHelp": "Povolením kontajneru fMP4 pre prekódovanie umožníte tomuto tuneru spracovať obsah vo formáte HEVC a HDR. Nie všetky tunery sú kompatibilné s týmto kontajnerom. Ak sa vyskytnú problémy s prehrávaním, zakažte ho.",
"AllowStreamSharingHelp": "Umožniť aplikácii Jellyfin duplikovať mpegts stream z tunera a zdieľať tento duplikovaný stream so svojimi klientmi. Je to užitočné, keď má tuner limit celkového počtu streamov, ale môže to spôsobiť aj problémy s prehrávaním.",
"AndOtherArtists": "{0} a {1} ďalších umelcov.",
"AlwaysRemuxMp3AudioFilesHelp": "Ak máte súbory, ktorých časové značky váš prehliadač vypočítava nepresne, povoľte túto možnosť ako dočasné riešenie.",
"AlwaysRemuxFlacAudioFilesHelp": "Ak máte súbory, ktoré prehliadač odmieta prehrávať alebo pri ktorých nepresne počíta časové značky, povoľte túto funkciu ako dočasné riešenie.",
"AllowTonemappingSoftwareHelp": "Mapovanie tónov dokáže transformovať dynamický rozsah videa z HDR na SDR pri zachovaní detailov obrazu a farieb, ktoré sú veľmi dôležitými informáciami na zobrazenie pôvodnej scény. V súčasnosti funguje len s 10bitovými videami HDR10, HLG a DoVi.",
"LabelDropLyricsHere": "Pretiahnite texty piesní sem alebo kliknutím vyberte súbor.",
"LabelFallbackMaxStreamingBitrate": "Záložný maximálny dátový tok (Mbps)",
"LabelSaveTrickplayLocally": "Uložit obrázky trickplay k médiám",
"LabelDelimiterWhitelistHelp": "Položky, ktoré sa majú vylúčiť z oddelovania tagov. Jedna položka na riadok.",
"LabelNoChangelog": "Pre túto verziu nie je k dispozícii žiadny zoznam zmien.",
"HeaderNextItemPlayingInValue": "Nasleduje {0} Prehrávanie za {1}",
"MessageSplitVersionsError": "Pri rozdeľovaní verzií došlo k chybe",
"PasswordMissingSaveError": "Nové heslo nesmie byť prázdne.",
"PluginLoadConfigError": "Pri získavaní konfigurácie zásuvného modulu došlo k chybe.",
"UseCustomTagDelimiters": "Použiť vlastný oddeľovač tagov",
"UseCustomTagDelimitersHelp": "Rozdeliť tagy umelcov/žánrov pomocou vlastných znakov.",
"LabelTrickplayKeyFrameOnlyExtraction": "Generovať obrázky len z kľúčových snímkov",
"MessageCancelSeriesTimerError": "Pri rušení časovača seriálu došlo k chybe",
"MessageCancelTimerError": "Pri rušení časovača došlo k chybe",
"PluginDisableError": "Pri zakazovaní zásuvného modulu došlo k chybe.",
"PluginEnableError": "Pri povoľovaní zásuvného modulu došlo k chybe.",
"PluginUninstallError": "Pri odinštalovaní zásuvného modulu došlo k chybe.",
"PreferNonstandardArtistsTag": "Preferovať tag ARTISTS, ak je k dispozícii",
"RenderPgsSubtitle": "Experimentálne vykresľovanie titulkov formátu PGS",
"VideoCodecTagNotSupported": "Tag video kodeku nie je podporovaný"
}

View file

@ -1754,9 +1754,9 @@
"AllowSegmentDeletion": "Radera segment",
"AllowSegmentDeletionHelp": "Radera gamla segment efter att de har laddats ner av användaren. Detta förhindrar att hela den transkodade filen behöver lagras på hårddisken. Stäng av detta om du upplever uppspelningsproblem.",
"LabelThrottleDelaySeconds": "Begränsa efter",
"LabelThrottleDelaySecondsHelp": "Tid i sekunder efter vilken transkodern kommer att strypas. Måste vara tillräckligt stor för att klienten ska kunna upprätthålla en sund buffert. Fungerar endast om strypning är aktiverat.",
"LabelSegmentKeepSeconds": "Tid för att behålla segment",
"LabelSegmentKeepSecondsHelp": "Tid i sekunder där segment ska sparas efter laddats ner av användaren. Fungerar endast om segmentradering är aktiverat.",
"LabelThrottleDelaySecondsHelp": "Tid i sekunder efter vilken transkodern kommer att strypas. Måste vara tillräckligt stor för att klienten ska kunna upprätthålla en tillräcklig buffert. Fungerar endast om strypning är aktiverat.",
"LabelSegmentKeepSeconds": "Tid att behålla segment",
"LabelSegmentKeepSecondsHelp": "Tid i sekunder då segment ska sparas efter att ha laddats ner av användaren. Fungerar endast om segmentradering är aktiverat.",
"LabelDeveloper": "Utväcklare",
"Notifications": "Notifieringar",
"UserMenu": "Användarmeny",
@ -1890,9 +1890,9 @@
"LabelImageIntervalHelp": "Intervall av tid (ms) mellan varje ny trickplay-bild.",
"LabelQscale": "qscale",
"HeaderLyricDownloads": "Låttextnedladdningar",
"AlternateDVD": "Växla DVD",
"AlternateDVD": "Alternativ DVD",
"Regional": "Regional",
"Alternate": "Växla",
"Alternate": "Alternativ",
"LabelInstalled": "Installerad",
"LabelEnablePlugin": "Aktivera tillägg",
"LabelNoChangelog": "Ingen versionshistorik har tillhandahållits för denna version.",
@ -1912,7 +1912,7 @@
"LabelDuration": "Varaktighet",
"LabelDropLyricsHere": "Släpp sångtext här, eller klicka för att bläddra.",
"LabelIsSynced": "Är synkroniserad",
"AllowTonemappingSoftwareHelp": "Tonmappning kan konvertera det dynamiska omfånget för en video från HDR till SDR samtidigt som bilddetaljer och färger bibehålls, vilket är mycket viktig information för att representera den ursprungliga scenen. Fungerar för närvarande endast med 10-bitars HDR10- och HLG-videor.",
"AllowTonemappingSoftwareHelp": "Tonmappning kan konvertera det dynamiska omfånget för en video från HDR till SDR samtidigt som bilddetaljer och färger bibehålls, vilket är mycket viktig information för att representera den ursprungliga scenen. Fungerar för närvarande endast med 10-bitars HDR10-, DoVi- och HLG-videor.",
"HeaderPreviewLyrics": "Förhandsgranska sångtext",
"LibraryInvalidItemIdError": "Biblioteket är i ett ogiltigt tillstånd och kan inte redigeras. Det är möjligt att du stött på en bugg: sökvägen i databasen är inte rätt sökväg i filsystemet.",
"MoveToTop": "Flytta längst upp",
@ -1933,5 +1933,12 @@
"LabelDisableVbrAudioEncoding": "Inaktivera VBR-ljudkodning",
"AlwaysRemuxFlacAudioFilesHelp": "Om du har filer som din webbläsare vägrar att spela upp eller där den beräknar tidsstämplar felaktigt, aktivera detta som en lösning.",
"AlwaysRemuxMp3AudioFilesHelp": "Om du har filer som din webbläsare beräknar tidsstämplar felaktigt, aktivera detta som en lösning.",
"DisableVbrAudioEncodingHelp": "Förhindra servern från att koda ljud med VBR för den här klienten."
"DisableVbrAudioEncodingHelp": "Förhindra servern från att koda ljud med VBR för den här klienten.",
"RenderPgsSubtitle": "Experimental PGS-textrendering",
"FallbackMaxStreamingBitrateHelp": "Den högsta uppspelningsbithastigheten används ifall ffprobe inte lyckas fastställa källans bithastighet. Detta gör så att klienter inte efterfrågar en för hög omkodningsbithastighet, vilket kan resultera i att mediespelaren kraschar och överbelastar omkodaren.",
"LabelAllowFmp4TranscodingContainer": "Tillåt fMP4 omkodningscontainer",
"LabelAlwaysRemuxMp3AudioFiles": "Remux:a alltid MP3-ljudfiler",
"LabelAlwaysRemuxFlacAudioFiles": "Remux:a alltid FLAC-ljudfiler",
"AllowFmp4TranscodingContainerHelp": "Tillåt fMP4-omkodande container för denna tuner för att stödja HEVC- och HDR-kodat innehåll. Inte alla tuners är kompatibla med denna sortens container. Avaktivera detta valet ifall du upplever problem med uppspelning.",
"AllowStreamSharingHelp": "Tillåt Jellyfin att duplicera MPEG-transportströmmen från tunern, och att dela den duplicerade strömmen till sina klienter. Detta är användbart när tunern har en maxgräns för antalet strömmar, men kan samtidigt orsaka problem med uppspelning."
}

View file

@ -1774,7 +1774,7 @@
"BackdropScreensaver": "Заставка «Задники»",
"LogoScreensaver": "Заставка з логотипом",
"LabelIsHearingImpaired": "Для людей з вадами слуху (SDH)",
"SelectAudioNormalizationHelp": "Посилення треку - регулює гучність кожного треку так, щоб вони відтворювалися з однаковою гучністю. Посилення альбому - регулює гучність лише всіх треків в альбомі, зберігаючи динамічний діапазон альбому.",
"SelectAudioNormalizationHelp": "Посилення треку - регулює гучність кожного треку так, щоб вони відтворювалися з однаковою гучністю. Посилення альбому - регулює гучність лише всіх треків в альбомі, зберігаючи динамічний діапазон альбому. Перемикання між «Вимкнено» та іншими опціями вимагає перезапуску поточного відтворення.",
"LabelAlbumGain": "Посилення альбому",
"LabelSelectAudioNormalization": "Нормалізація звуку",
"LabelTrackGain": "Посилення треку",
@ -1857,7 +1857,7 @@
"EnableLibrary": "Увімкнути медіатеку",
"EnableLibraryHelp": "Якщо вимкнути бібліотеку, її буде приховано від усіх користувачів.",
"LabelTrickplayAccelEncoding": "Увімкнути апаратне прискорення кодування MJPEG",
"LabelTrickplayAccelEncodingHelp": "Наразі ця опція доступна лише для QSV, VAAPI та VideoToolbox, вона не впливає на інші методи апаратного прискорення.",
"LabelTrickplayAccelEncodingHelp": "Наразі ця опція доступна лише для QSV, VA-API, VideoToolbox та RKMPP, вона не впливає на інші методи апаратного прискорення.",
"DeleteLyrics": "Видалити текст пісні",
"ConfirmDeleteLyrics": "Видалення цих текстів пісні призведе до видалення їх як з файлової системи, так і з вашої медіатеки. Ви впевнені, що хочете продовжити?",
"ErrorDeletingLyrics": "Виникла помилка при видаленні тексту пісні з сервера. Будь ласка, перевірте, чи має Jellyfin доступ на запис до теки з медіафайлами, і спробуйте ще раз.",
@ -1947,5 +1947,22 @@
"LabelAllowStreamSharing": "Дозволити спільний доступ до потоку",
"LabelFallbackMaxStreamingBitrate": "Резервна максимальна швидкість потоку (Мбіт/с)",
"VideoCodecTagNotSupported": "Тег відеокодека не підтримується",
"HeaderAudioAdvanced": "Розширене аудіо"
"HeaderAudioAdvanced": "Розширене аудіо",
"LabelLyricDownloaders": "Завантажувачі текстів пісень",
"LabelAudioTagSettings": "Налаштування аудіотегів",
"LabelCustomTagDelimiters": "Користувацький роздільник тегів",
"LabelCustomTagDelimitersHelp": "Символи, які слід розглядати як роздільники для розділення тегів.",
"LabelDelimiterWhitelist": "Білий список роздільників",
"LabelDelimiterWhitelistHelp": "Елементи, які слід виключити з розбиття тегів. По одному елементу в рядку.",
"LyricDownloadersHelp": "Увімкніть та розташуйте бажані програми для завантаження субтитрів у порядку пріоритету.",
"RenderPgsSubtitleHelp": "Визначає, чи повинен клієнт відтворювати субтитри PGS замість записаних субтитрів. Це дозволить уникнути перекодування на стороні сервера в обмін на продуктивність рендерингу на стороні клієнта.",
"RenderPgsSubtitle": "Експериментальне відображення субтитрів PGS",
"PreferNonstandardArtistsTag": "Надавати перевагу тегу ARTISTS, якщо він доступний",
"PreferNonstandardArtistsTagHelp": "Використовувати нестандартний тег ARTISTS замість тега ARTIST, якщо він доступний.",
"UseCustomTagDelimiters": "Використовувати власний роздільник тегів",
"UseCustomTagDelimitersHelp": "Розділіть теги виконавця/жанру за допомогою спеціальних символів.",
"DateModified": "Дату змінено",
"MessageCancelSeriesTimerError": "Виникла помилка під час скасування таймера серіалу",
"MessageCancelTimerError": "Виникла помилка під час скасування таймера",
"MessageSplitVersionsError": "Виникла помилка під час розділення версій"
}

View file

@ -1269,7 +1269,7 @@
"TvLibraryHelp": "Xem lại {0} hướng dẫn đặt tên TV {1}.",
"Tuesday": "Thứ ba",
"Transcoding": "Chuyển mã",
"Trailers": "Đoạn giới thiệu",
"Trailers": "Trailers",
"TabAccess": "Truy cập",
"SystemDlnaProfilesHelp": "Cấu hình hệ thống là 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",
@ -1403,7 +1403,7 @@
"EnableAutoCast": "Đặt mặc định",
"Studios": "Hãng Phim",
"Bwdif": "Bộ Lọc Khử Xen Kẽ Bob Weaver (BWDIF)",
"Yadif": "Bộ lọc giải giao điểm khác (YADIF): là bộ lọc giải giao điểm giúp chuyển đổi video giao điểm thành video toàn màn hình, cải thiện chất lượng hình ảnh bằng cách loại bỏ các dòng giao điểm và làm mịn video.",
"Yadif": "Một bộ lọc khử xen kẽ khác (YADIF)",
"Writers": "Người viết",
"Writer": "Người viết",
"Video": "Video",
@ -1764,7 +1764,7 @@
"LabelTrackGain": "Điều Chỉnh Nhạc",
"GridView": "Xem Lưới",
"ListView": "Xem Danh Sách",
"SelectAudioNormalizationHelp": "Điều chỉnh nhạc - điều chỉnh âm lượng của mỗi bản nhạc để chúng phát lại với cùng một độ to. Điều chỉnh album - điều chỉnh âm lượng tất cả bản nhạc trong album, giữ nguyên dải động của album.",
"SelectAudioNormalizationHelp": "Chỉnh nhạc - điều chỉnh âm lượng mỗi bản nhạc để chúng phát với cùng một độ to. Chỉnh album - điều chỉnh âm lượng tất cả bản nhạc trong album, giữ nguyên dải động của album. Việc chuyển đổi giữa \"Tắt\" và các tùy chọn khác yêu cầu khởi động lại quá trình phát lại hiện tại.",
"LabelAlbumGain": "Điều Chỉnh Album",
"LabelSegmentKeepSecondsHelp": "Thời gian tính bằng giây mà các phân đoạn cần được giữ lại sau khi chúng được khách hàng tải xuống.. Chỉ hoạt động nếu tính năng xóa phân đoạn được bật.",
"MenuClose": "Đóng Menu",
@ -1796,8 +1796,8 @@
"Lyric": "Lời bài hát",
"HeaderLyricDownloads": "Tải Xuống Lời Bài Hát",
"LabelSelectPreferredTranscodeVideoAudioCodec": "Bộ giải mã âm thanh chuyển mã ưa thích khi phát lại video",
"LibraryScanFanoutConcurrency": "Giới hạn số lượng tác vụ quét thư viện song song",
"LibraryScanFanoutConcurrencyHelp": "Số lượng tác vụ song song tối đa trong quá trình quét thư viện. Đặt giá trị này thành 0 sẽ chọn một giới hạn dựa trên số lõi của hệ thống của bạn. CẢNH BÁO: Đặt số này quá cao có thể gây ra vấn đề với hệ thống tệp mạng; nếu gặp sự cố, hãy giảm số này.",
"LibraryScanFanoutConcurrency": "Giới hạn tác vụ quét thư viện song song",
"LibraryScanFanoutConcurrencyHelp": "Số lượng tác vụ song song tối đa trong quá trình quét thư viện. Đặt là 0 sẽ chọn một giới hạn dựa trên số lõi trên hệ thống của bạn. CẢNH BÁO: Đặt số này quá cao có thể gây ra vấn đề với hệ thống tệp mạng; nếu gặp sự cố, hãy giảm số này xuống thấp.",
"Lyrics": "Lời bài hát",
"PlaybackError.ASS_RENDER_ERROR": "Đã xảy ra lỗi trong trình kết xuất phụ đề ASS/SSA.",
"PlaybackError.FATAL_HLS_ERROR": "Đã xảy ra lỗi nghiêm trọng trong luồng HLS.",
@ -1829,16 +1829,16 @@
"DeleteLyrics": "Xóa lời bài hát",
"ErrorDeletingLyrics": "Đã xảy ra lỗi khi xóa lời bài hát khỏi máy chủ. Vui lòng kiểm tra xem Jellyfin có quyền ghi vào thư mục phương tiện hay không và thử lại.",
"HeaderNoLyrics": "Không tìm thấy lời bài hát",
"LabelExtractTrickplayDuringLibraryScan": "Trích xuất hình ảnh đánh lừa trong quá trình quét thư viện",
"LabelExtractTrickplayDuringLibraryScan": "Trích xuất ảnh tua nhanh trong quá trình quét thư viện",
"HeaderVideoAdvanced": "Video Nâng Cao",
"LabelExtractTrickplayDuringLibraryScanHelp": "Tạo hình ảnh đánh lừa khi video được nhập trong quá trình quét thư viện. Nếu không, chúng sẽ được trích xuất trong quá trình thực hiện nhiệm vụ theo lịch trình hình ảnh đánh lừa. Nếu việc tạo được đặt thành không chặn thì điều này sẽ không ảnh hưởng đến thời gian hoàn tất quá trình quét thư viện.",
"LabelExtractTrickplayDuringLibraryScanHelp": "Tạo ảnh tua nhanh khi video được nhập trong quá trình quét thư viện. Nếu không, nó sẽ được trích xuất trong khi chạy theo lịch trình hình ảnh tua nhanh. Nếu việc tạo được đặt là không chặn thì điều này sẽ không ảnh hưởng đến thời gian hoàn tất quá trình quét thư viện.",
"EnableTrueHd": "Bật TrueHD",
"EnableDts": "Bật DTS (DCA)",
"EncodingFormatHelp": "Chọn mã hóa video mà Jellyfin sẽ chuyển mã sang. Jellyfin sẽ sử dụng mã hóa phần mềm khi không thể tăng tốc phần cứng cho định dạng đã chọn. Mã hóa H264 sẽ luôn được bật.",
"LabelScanBehaviorHelp": "Hành vi mặc định là không chặn, thao tác này sẽ thêm phương tiện vào thư viện trước khi quá trình tạo trò lừa được thực hiện. Việc chặn sẽ đảm bảo các tệp đánh lừa được tạo trước khi phương tiện được thêm vào thư viện nhưng sẽ khiến quá trình quét mất nhiều thời gian hơn.",
"LabelProcessPriorityHelp": "Việc đặt mức này thấp hơn hoặc cao hơn sẽ xác định cách CPU ưu tiên quá trình tạo trò chơi lừa ffmpeg so với các quy trình khác. Nếu bạn nhận thấy sự chậm lại trong khi tạo hình ảnh đánh lừa nhưng không muốn dừng hoàn toàn quá trình tạo hình ảnh, hãy thử giảm tốc độ này cũng như số lượng chuỗi.",
"LabelWidthResolutionsHelp": "Danh sách chiều rộng (px) được phân tách bằng dấu phẩy mà hình ảnh đánh lừa sẽ được tạo tại đó. Tất cả hình ảnh phải được tạo theo tỷ lệ với nguồn, do đó chiều rộng 320 trên video 16:9 sẽ có kích thước khoảng 320x180.",
"LabelTrickplayThreads": "Số lượng luồng FFmpeg: được sử dụng khi mã hóa hoặc giải mã video bằng FFmpeg, giúp cải thiện hiệu suất xử lý",
"LabelScanBehaviorHelp": "Mặc định là không chặn, thao tác này sẽ thêm phương tiện vào thư viện trước khi quá trình tạo ảnh tua nhanh được thực hiện. Việc chặn sẽ đảm bảo các tệp ảnh tua nhanh được tạo trước khi phương tiện được thêm vào thư viện nhưng sẽ khiến quá trình quét mất nhiều thời gian hơn.",
"LabelProcessPriorityHelp": "Đặt mức này thấp hoặc cao hơn sẽ xác định cách CPU ưu tiên quá trình tạo ảnh tua nhanh ffmpeg so với các quy trình khác. Nếu bạn thấy chậm trong khi tạo ảnh tua nhanh nhưng không muốn dừng hoàn toàn, hãy thử giảm tốc độ này cũng như số lượng luồng.",
"LabelWidthResolutionsHelp": "Danh sách chiều rộng (px) được phân tách bằng dấu phẩy mà hình ảnh tua nhanh sẽ được tạo tại đó. Tất cả hình ảnh phải được tạo theo tỷ lệ với nguồn, do đó chiều rộng 320 trên video 16:9 sẽ có kích thước khoảng 320x180.",
"LabelTrickplayThreads": "Luồng FFmpeg",
"SelectPreferredTranscodeVideoAudioCodecHelp": "Chọn mã hóa âm thanh ưa thích để chuyển mã nội dung video. Nếu bộ mã hóa ưu tiên không được hỗ trợ, máy chủ sẽ sử dụng bộ mã hóa tốt nhất hiện có tiếp theo.",
"LabelEncodingFormatOptions": "Tùy chọn định dạng mã hóa",
"LabelTrickplayAccelEncoding": "Bật mã hóa MJPEG được tăng tốc phần cứng",
@ -1850,18 +1850,18 @@
"PriorityNormal": "Bình Thường",
"PriorityBelowNormal": "Dưới Bình Thường",
"LabelProcessPriority": "Quá Trình Ưu Tiên",
"LabelImageIntervalHelp": "Khoảng thời gian (ms) giữa mỗi hình ảnh đánh lừa mới.",
"LabelImageIntervalHelp": "Khoảng thời gian (ms) giữa mỗi hình ảnh tua nhanh mới.",
"LabelWidthResolutions": "Độ Phân Giải Chiều Rộng",
"LabelTileWidthHelp": "Số lượng hình ảnh tối đa trên mỗi ô theo hướng X.",
"LabelJpegQuality": "Chất lượng JPEG",
"LabelJpegQualityHelp": "Chất lượng nén JPEG cho hình ảnh đánh lừa.",
"LabelJpegQualityHelp": "Chất lượng nén JPEG cho hình ảnh tua nhanh.",
"LabelTrickplayThreadsHelp": "Số lượng luồng cần chuyển tới đối số '-threads' của ffmpeg.",
"ExtractTrickplayImagesHelp": "Hình ảnh Trickplay tương tự như hình ảnh chương, ngoại trừ việc chúng kéo dài toàn bộ nội dung và được dùng để hiển thị bản xem trước khi xem qua video.",
"ExtractTrickplayImagesHelp": "Hình ảnh Tua Nhanh tương tự như hình ảnh chương, ngoại trừ việc chúng kéo dài toàn bộ nội dung và được dùng để hiển thị bản xem trước khi xem qua video.",
"LabelTileHeightHelp": "Số lượng hình ảnh tối đa trên mỗi ô theo hướng Y.",
"LabelTrickplayAccel": "Kích hoạt giải mã phần cứng",
"LabelTrickplayAccelEncodingHelp": "Hiện chỉ có trên QSV, VAAPI và VideoToolbox, tùy chọn này không có tác dụng với các loại tăng tốc phần cứng khác.",
"LabelTrickplayAccelEncodingHelp": "Hiện chỉ có trên QSV, VA-API, VideoToolbox và RKMPP, tùy chọn này vô dụng với các loại tăng tốc phần cứng khác.",
"LabelImageInterval": "Khoảng Cách Ảnh",
"OptionExtractTrickplayImage": "Bật trích xuất hình ảnh đánh lừa",
"OptionExtractTrickplayImage": "Bật trích xuất hình ảnh tua nhanh",
"EnableVideoToolboxTonemapping": "Bật ánh xạ tông màu VideoToolbox",
"AllowVideoToolboxTonemappingHelp": "Ánh xạ tông màu được tăng tốc phần cứng do VideoToolbox cung cấp. Nó hoạt động với hầu hết các định dạng HDR, bao gồm HDR10, HDR10+ và HLG, nhưng không hoạt động với Dolby Vision Profile 5. Định dạng này có mức độ ưu tiên cao hơn so với triển khai Metal khác.",
"Translator": "Người phiên dịch",
@ -1875,10 +1875,10 @@
"HeaderNextItemPlayingInValue": "Kế tiếp {0} Đang phát trong {1}",
"PluginLoadRepoError": "Đã xảy ra lỗi khi tải thông tin chi tiết tính năng mở rộng từ kho lưu trữ.",
"HeaderNextItem": "Kế tiếp {0}",
"AirPlay": "Phát qua AirPlay",
"AirPlay": "AirPlay",
"Featurette": "Quảng Bá",
"LabelSelectPreferredTranscodeVideoCodec": "Bộ mã hóa video chuyển mã ưa thích",
"Trickplay": "Tua nhanh",
"Trickplay": "Ảnh Tua Nhanh",
"LabelEnablePlugin": "Bật Tính Năng Mở Rộng",
"LabelInstalled": "Đã cài đặt",
"LabelNoChangelog": "Không có nhật ký thay đổi nào được cung cấp cho phiên bản này.",
@ -1915,7 +1915,7 @@
"ChannelResolutionFullHD": "Full HD",
"ChannelResolutionSD": "SD",
"ChannelResolutionHD": "HD",
"AllowTonemappingSoftwareHelp": "Tone-mapping có thể chuyển đổi dải động của video từ HDR sang SDR trong khi vẫn giữ được chi tiết hình ảnh và màu sắc, đây là những thông tin rất quan trọng để thể hiện cảnh gốc. Hiện tại, tính năng này chỉ hoạt động với video 10bit HDR10, HLG và HLGDoVi.",
"AllowTonemappingSoftwareHelp": "Tone-mapping có thể chuyển đổi dải động của video từ HDR sang SDR trong khi vẫn giữ được chi tiết hình ảnh và màu sắc, đây là những thông tin rất quan trọng để thể hiện cảnh gốc. Hiện chỉ hoạt động với video 10bit HDR10, HLG và DoVi.",
"MediaInfoRotation": "Xoay",
"LabelTrickplayKeyFrameOnlyExtraction": "Chỉ tạo hình ảnh từ các khung hình chính",
"ForeignPartsOnly": "Chỉ phần Ngoài/Bắt buộc",
@ -1926,9 +1926,43 @@
"HearingImpairedShort": "HI/SDH",
"LabelTileHeight": "Chiều Cao Ô",
"Clip": "Clip",
"LabelQscale": "Chỉ số chất lượng (Qscale)",
"LabelQscale": "Qscale",
"LabelTrickplayKeyFrameOnlyExtractionHelp": "Chỉ trích xuất các khung hình chính để xử lý nhanh hơn đáng kể với thời gian kém chính xác hơn. Nếu bộ giải mã phần cứng được cấu hình không hỗ trợ chế độ này, thay vào đó sẽ sử dụng bộ giải mã phần mềm.",
"LibraryInvalidItemIdError": "Thư viện đang ở trạng thái không hợp lệ và không thể chỉnh sửa. Bạn có thể đang gặp phải lỗi: đường dẫn trong cơ sở dữ liệu không khớp với đường dẫn trên hệ thống tệp.",
"EnableHi10pHelp": "Bật để tránh chuyển mã video H.264 10-bit. Tắt tùy chọn này nếu video hiển thị khung hình trống.",
"EnableHi10p": "Kích hoạt cấu hình H.264 High 10"
"EnableHi10p": "Kích hoạt cấu hình H.264 High 10",
"AllowFmp4TranscodingContainerHelp": "Cho phép bộ chứa chuyển mã fMP4 cho bộ điều chỉnh này để bật nội dung HEVC và HDR. Không phải tất cả các bộ chỉnh đều tương thích với vùng chứa này. Tắt tính năng này nếu bạn gặp sự cố phát lại.",
"AllowStreamSharingHelp": "Cho phép Jellyfin sao chép luồng mpegts từ bộ dò sóng và chia sẻ luồng trùng lặp này với các máy khách của nó. Điều này hữu ích khi bộ dò có tổng giới hạn số lượng luồng nhưng cũng có thể gây ra sự cố phát lại.",
"FallbackMaxStreamingBitrateHelp": "Tốc độ bit phát trực tuyến tối đa được sử dụng làm dự phòng khi ffprobe không thể xác định tốc độ bit của luồng nguồn. Điều này giúp ngăn khách hàng yêu cầu tốc độ bit chuyển mã quá cao, điều này có thể khiến trình phát bị lỗi và khiến bộ mã hóa bị quá tải.",
"AlwaysRemuxFlacAudioFilesHelp": "Nếu bạn có các tệp mà trình duyệt của bạn từ chối phát hoặc nơi nó tính toán dấu thời gian không chính xác, hãy bật tính năng này như một giải pháp thay thế.",
"AlwaysRemuxMp3AudioFilesHelp": "Nếu bạn có các tệp mà trình duyệt của bạn tính toán dấu thời gian không chính xác, hãy kích hoạt tính năng này như một giải pháp thay thế.",
"DisableVbrAudioEncodingHelp": "Ngăn máy chủ mã hóa âm thanh bằng VBR cho máy khách này.",
"LyricDownloadersHelp": "Kích hoạt và xếp hạng các trình tải xuống phụ đề ưa thích của bạn theo thứ tự ưu tiên.",
"RenderPgsSubtitle": "Kết xuất phụ đề PGS thử nghiệm",
"RenderPgsSubtitleHelp": "Xác định xem khách hàng có nên hiển thị phụ đề PGS thay vì sử dụng phụ đề ghi sẵn hay không. Điều này có thể tránh việc chuyển mã phía máy chủ để đổi lấy hiệu suất hiển thị phía máy khách.",
"LabelLyricDownloaders": "Trình tải lời bài hát",
"LabelAllowFmp4TranscodingContainer": "Cho phép vùng chứa chuyển mã fMP4",
"LabelAllowStreamSharing": "Cho phép chia sẻ luồng",
"LabelFallbackMaxStreamingBitrate": "Tốc độ bit luồng tối đa dự phòng (Mbps)",
"HeaderAudioAdvanced": "Âm Thanh Nâng Cao",
"LabelAlwaysRemuxFlacAudioFiles": "Luôn làm lại các tập tin âm thanh FLAC",
"LabelDisableVbrAudioEncoding": "Tắt mã hóa âm thanh VBR",
"VideoCodecTagNotSupported": "Thẻ mã hóa video không được hỗ trợ",
"LabelAudioTagSettings": "Cài Đặt Thẻ Âm Thanh",
"LabelCustomTagDelimiters": "Dấu Phân Cách Thẻ Tùy Chỉnh",
"LabelCustomTagDelimitersHelp": "Các ký tự được coi là dấu phân cách để phân tách các thẻ.",
"LabelDelimiterWhitelist": "Danh Sách Trắng Phân Cách",
"LabelDelimiterWhitelistHelp": "Các mục được loại trừ khỏi việc chia thẻ. Một mục trên mỗi dòng.",
"PreferNonstandardArtistsTagHelp": "Sử dụng thẻ ARTISTS không chuẩn thay vì thẻ ARTIST khi có sẵn.",
"PreferNonstandardArtistsTag": "Ưu tiên thẻ ARTISTS nếu có",
"UseCustomTagDelimiters": "Sử dụng dấu phân cách thẻ tùy chỉnh",
"UseCustomTagDelimitersHelp": "Tách thẻ nghệ sĩ/thể loại với các ký tự tùy chỉnh.",
"ReplaceTrickplayImages": "Thay thế ảnh tua nhanh hiện có",
"LabelAlwaysRemuxMp3AudioFiles": "Luôn làm lại các tập tin âm thanh MP3",
"LabelSaveTrickplayLocally": "Lưu ảnh tua nhanh bên cạnh phương tiện",
"LabelSaveTrickplayLocallyHelp": "Việc lưu ảnh tua anh vào thư mục phương tiện sẽ đặt chúng kế bên phương tiện của bạn để dễ di chuyển và truy cập.",
"DateModified": "Ngày sửa đổi",
"MessageCancelSeriesTimerError": "Đã xảy ra lỗi khi hủy bộ hẹn giờ chuỗi",
"MessageCancelTimerError": "Đã xảy ra lỗi khi hủy bộ hẹn giờ",
"MessageSplitVersionsError": "Đã xảy ra lỗi khi chia nhỏ các phiên bản"
}

View file

@ -197,7 +197,7 @@
"GuestStar": "特邀明星",
"GuideProviderLogin": "登入",
"GuideProviderSelectListings": "选择列表",
"H264CrfHelp": "恒定速率因子 (CRF) 是 x264 软件编码的默认质量设置。您可以设置介于0和51之间的值 其中较低的值将导致更好的质量 (以更高的文件大小为代价)。正常值介于 18 和 28 之间。x264 的默认值为 23x265 的默认值为 28因此可以将其用作起始点。硬件编码器不使用这些设置。",
"H264CrfHelp": "恒定速率因子 (CRF) 是 x264 和x265 软件编码的默认质量设置。您可以设置介于0和51之间的值 较低的数值会带来更高的画质,但同时也会导致文件大小的增加。正常值介于 18 和 28 之间。x264 的默认值为 23x265 的默认值为 28因此可以用它作为初始参考值。硬件编码不使用这些设置。",
"EncoderPresetHelp": "选择较快的值以提高性能,或选择较慢的值以提高质量。",
"HDPrograms": "高清节目",
"HardwareAccelerationWarning": "启动硬件加速可能在某些环境下导致系统不稳定。请确认你的操作系统和显卡驱动程序是最新的。如果你在开启此项后播放视频时遇到困难,那么你需要将此选项设置回“没有”。",
@ -1019,7 +1019,7 @@
"SortName": "排序名称",
"Sports": "体育",
"StopRecording": "停止录制",
"Studios": "制片发行商",
"Studios": "工作室",
"SubtitleAppearanceSettingsAlsoPassedToCastDevices": "这些设置也会被应用于任何通过此设备发起的 Google Cast 播放。",
"SubtitleAppearanceSettingsDisclaimer": "以下设置不适用于上述图形字幕或嵌入其自身样式的 ASS/SSA 字幕。",
"SubtitleDownloadersHelp": "按优先顺序启用并排列您的首选字幕下载程序。",
@ -1728,7 +1728,7 @@
"MenuOpen": "打开菜单",
"MenuClose": "关闭菜单",
"UserMenu": "用户菜单",
"Studio": "制片发行商",
"Studio": "工作室",
"AllowCollectionManagement": "允许该用户管理收藏夹",
"EnableAudioNormalizationHelp": "音频标准化将添加一个恒定的增益,以保持平均音量在所需的级别(-18dB。",
"EnableAudioNormalization": "音频标准化",
@ -1779,7 +1779,7 @@
"LabelIsHearingImpaired": "用于听障/聋哑人士",
"SearchResultsEmpty": "抱歉!未找到与\"{0}\"相关的结果",
"LabelTrackGain": "音轨增益",
"SelectAudioNormalizationHelp": "音轨增益 - 调整每个音轨的音量,使它们播放时具有相同的响度。专辑增益 - 只调整专辑中所有音轨的音量,保持专辑的动态范围。",
"SelectAudioNormalizationHelp": "音轨增益 - 调整每个音轨的音量,使它们播放时具有相同的响度。专辑增益 - 只调整专辑中所有音轨的音量,保持专辑的动态范围。在“关闭”和其他选项之间切换后需要重新启动当前播放。",
"LabelAlbumGain": "专辑增益",
"LabelSelectAudioNormalization": "音频标准化",
"HeaderAllRecordings": "所有录制的节目",
@ -1802,28 +1802,28 @@
"AllowMjpegEncoding": "允许以 MJPEG 格式编码(用于生成特技播放预览图)",
"LabelTrickplayAccelHelp": "如果您的硬件支持,请确保在转码中启用“允许 MJPEG 格式编码”。",
"NonBlockingScan": "非阻塞 - 将预览图生成添加到任务队列,然后返回",
"Trickplay": "特技播放",
"Trickplay": "进度条预览图",
"LabelTrickplayAccel": "启用硬件解码",
"BlockingScan": "阻塞 - 将预览图生成添加到任务队列,阻塞扫描直至完成",
"LabelScanBehavior": "扫描方式",
"LabelScanBehaviorHelp": "默认行为是非阻塞,即在生成特技播放预览图之前将媒体添加到库中。阻塞将确保在将媒体添加到库中之前生成特技播放预览图文件,但会使扫描时间明显变长。",
"LabelScanBehaviorHelp": "默认行为是非阻塞,即在生成进度条预览图之前将媒体添加到库中。阻塞将确保在将媒体添加到库中之前生成进度条预览图,但会使扫描时间明显变长。",
"PriorityHigh": "高",
"PriorityAboveNormal": "高于正常",
"PriorityNormal": "正常",
"PriorityBelowNormal": "低于正常",
"PriorityIdle": "闲时",
"LabelProcessPriority": "进程优先级",
"LabelProcessPriorityHelp": "将此值设置得更低或更高将决定 CPU 如何优先处理 FFmpeg 特技播放预览图生成过程与其他过程的关系。如果您在生成特技播放图像时发现运行缓慢,但又不想完全停止生成,请尝试降低此值以及线程数。",
"LabelProcessPriorityHelp": "将此值设置得更低或更高将决定 CPU 如何优先处理 FFmpeg 进度条预览图生成过程与其他过程的关系。如果您在生成预览图时发现运行缓慢,但又不想完全停止生成,请尝试降低此值以及线程数。",
"LabelImageInterval": "图像间隔",
"LabelImageIntervalHelp": "每个新的特技播放预览图之间的时间间隔(毫秒)。",
"LabelImageIntervalHelp": "每个新的进度条预览图之间的时间间隔(毫秒)。",
"LabelWidthResolutions": "宽度分辨率",
"LabelWidthResolutionsHelp": "以逗号分隔的列表,列出将生成特技播放预览图的宽度 (以像素为单位)。所有图像都应按源比例生成,因此 16:9 视频的宽度 320 最终约为 320x180。",
"LabelWidthResolutionsHelp": "以逗号分隔的列表,列出将生成的进度条预览图的宽度 (以像素为单位)。所有图像都应按源比例生成,因此 16:9 视频的宽度 320 最终约为 320x180。",
"LabelTrickplayThreadsHelp": "传递给 FFmpeg 的“-threads”参数的线程数。",
"OptionExtractTrickplayImage": "启用特技播放预览图提取",
"ExtractTrickplayImagesHelp": "特技播放预览图与章节图像类似,不同之处在于它们跨越整个内容的长度并用于在浏览视频时显示预览。",
"OptionExtractTrickplayImage": "启用进度条预览图提取",
"ExtractTrickplayImagesHelp": "进度条预览图与章节图像类似,不同之处在于它们跨越整个内容的长度并用于在浏览视频时显示预览。",
"LabelTileHeightHelp": "Y 方向上每个图块的最大图像数量。",
"LabelJpegQuality": "JPEG 质量",
"LabelJpegQualityHelp": "特技播放预览图的 JPEG 压缩质量。",
"LabelJpegQualityHelp": "进度条预览图的 JPEG 压缩质量。",
"LabelQscale": "质量因数Qscale",
"LabelQscaleHelp": "FFmpeg 输出图片的质量等级2 为最高品质31 为最低品质。",
"LabelTrickplayThreads": "FFmpeg 线程数",
@ -1834,9 +1834,9 @@
"LabelTileWidthHelp": "X 方向上每个图块的最大图像数量。",
"LabelTileWidth": "图块宽度",
"LabelTileHeight": "图块高度",
"LabelExtractTrickplayDuringLibraryScan": "在媒体库扫描期间提取特技播放预览图",
"LabelExtractTrickplayDuringLibraryScan": "在媒体库扫描期间提取进度条预览图",
"ConfirmDeleteSeries": "删除此系列将从文件系统和媒体库中删除共计 {0} 集。您确定要继续吗?",
"LabelExtractTrickplayDuringLibraryScanHelp": "在媒体库扫描期间导入视频时生成特技播放预览图。否则,它们将在特技播放预览图计划任务期间被提取。如果生成设置为非阻塞,则不会影响库扫描完成所需的时间。",
"LabelExtractTrickplayDuringLibraryScanHelp": "在媒体库扫描期间导入视频时生成进度条预览图。否则,它们将在进度条预览图的计划任务期间被提取。如果生成设置为非阻塞,则不会影响库扫描完成所需的时间。",
"Lyric": "歌词",
"PlaybackError.RateLimitExceeded": "由于速率限制,该媒体目前无法播放。",
"PlaybackError.ASS_RENDER_ERROR": "ASS/SSA 字幕渲染器遇到错误。",
@ -1862,7 +1862,7 @@
"ErrorDeletingLyrics": "从服务器中删除歌词时出现了错误。请检查Jellyfin是否具有对应媒体文件夹的写入权限然后重试。",
"Lyrics": "歌词",
"LabelTrickplayAccelEncoding": "启用硬件加速的 MJPEG 编码",
"LabelTrickplayAccelEncodingHelp": "目前仅适用于 QSVVA-API 和 VideoToolbox,此选项对其他硬件加速方法不起作用。",
"LabelTrickplayAccelEncodingHelp": "目前仅适用于 QSVVA-APIVideoToolbox 和 RKMPP,此选项对其他硬件加速方法不起作用。",
"ConfirmDeleteLyrics": "删除这些歌词将同时从文件系统和媒体库中删除它们。您确定要继续吗?",
"DeleteLyrics": "删除歌词",
"HeaderDeleteLyrics": "删除歌词",
@ -1941,14 +1941,31 @@
"LabelAlwaysRemuxMp3AudioFiles": "总是重新混合 MP3 音频文件",
"LabelAlwaysRemuxFlacAudioFiles": "总是重新混合 FLAC 音频文件",
"LabelDisableVbrAudioEncoding": "禁用 VBR 音频编码",
"LabelSaveTrickplayLocally": "将特技播放图像保存在媒体旁边",
"LabelSaveTrickplayLocallyHelp": "将特技播放图像保存到媒体文件夹中会将它们放在媒体旁边,以便于迁移和访问。",
"ReplaceTrickplayImages": "替换现有的特技图像",
"LabelSaveTrickplayLocally": "将进度条预览图保存在媒体旁边",
"LabelSaveTrickplayLocallyHelp": "将进度条预览图保存到媒体文件夹中会将它们放在媒体旁边,以便于迁移和访问。",
"ReplaceTrickplayImages": "替换现有的进度条预览图",
"AllowFmp4TranscodingContainerHelp": "允许此调谐器使用 fMP4 转码容器来启用 HEVC 和 HDR 内容。并非所有调谐器都兼容此容器。如果您遇到播放问题,请禁用此功能。",
"AllowStreamSharingHelp": "允许 Jellyfin 复制调谐器中的 mpegts 流并将此复制的流共享给其客户端。当调谐器的总流数有限制时,这很有用,但也可能导致播放问题。",
"FallbackMaxStreamingBitrateHelp": "当 ffprobe 无法确定源流比特率时,最大流比特率将用作后备。这有助于防止客户端请求过高的转码比特率,这可能会导致播放器失败并使编码器过载。",
"LabelAllowFmp4TranscodingContainer": "允许 fMP4 转码容器",
"LabelAllowStreamSharing": "允许流共享",
"LabelFallbackMaxStreamingBitrate": "回退最大流比特率 (Mbps)",
"VideoCodecTagNotSupported": "不支持视频编解码器标签"
"VideoCodecTagNotSupported": "视频编码标签不支持",
"LabelLyricDownloaders": "歌词下载",
"LyricDownloadersHelp": "启用并按优先级顺序排列您喜欢的下载器。",
"RenderPgsSubtitle": "实验性 PGS 字幕渲染",
"RenderPgsSubtitleHelp": "在客户端渲染 PGS 字幕,而不是烧录字幕。这以降低客户端渲染性能为代价来避免服务器端转码。",
"LabelAudioTagSettings": "音频标签设置",
"LabelCustomTagDelimiters": "自定义标签分隔符",
"LabelCustomTagDelimitersHelp": "作为分隔符来分隔标签的字符。",
"LabelDelimiterWhitelist": "分隔符白名单",
"UseCustomTagDelimiters": "使用自定义标签分隔符",
"LabelDelimiterWhitelistHelp": "从标签分隔中排除的项目。每行一项。",
"PreferNonstandardArtistsTag": "可用时首选的艺术家标签",
"PreferNonstandardArtistsTagHelp": "如果可用,使用非标准的艺术家标签代替艺术家标签。",
"UseCustomTagDelimitersHelp": "使用自定义字符分割\"艺术家/类型\"标签。",
"MessageCancelSeriesTimerError": "取消节目计时器时发生错误",
"MessageCancelTimerError": "取消计时器时发生错误",
"MessageSplitVersionsError": "分割版本时发生错误",
"DateModified": "修改日期"
}

View file

@ -1939,5 +1939,32 @@
"LabelDropLyricsHere": "將歌詞拖曳至此處,或點擊以瀏覽。",
"LabelAlwaysRemuxFlacAudioFiles": "總是重新封裝 FLAC 音訊",
"LabelAlwaysRemuxMp3AudioFiles": "總是重新封裝 MP3 音訊",
"LabelDisableVbrAudioEncoding": "停用可變位元率 (VBR) 音訊編碼"
"LabelDisableVbrAudioEncoding": "停用可變位元率 (VBR) 音訊編碼",
"DateModified": "修改日期",
"FallbackMaxStreamingBitrateHelp": "當 ffprobe 無法判斷來源位元率時,將使用最大串流位元率。可以避免用戶端請求過高的轉檔位元率,進而導致播放失敗或編碼器過載。",
"LabelAudioTagSettings": "音訊標籤設定",
"LabelCustomTagDelimiters": "自訂標籤分隔字元",
"LabelCustomTagDelimitersHelp": "用來分隔標籤的字元。",
"LabelFallbackMaxStreamingBitrate": "備用最大串流位元率 (Mbps)",
"LabelAllowFmp4TranscodingContainer": "允許使用 fMP4 容器轉檔",
"MessageCancelSeriesTimerError": "取消節目計時器時發生錯誤",
"MessageCancelTimerError": "取消計時器時發生錯誤",
"MessageSplitVersionsError": "分割版本時發生錯誤",
"LabelLyricDownloaders": "歌詞下載器",
"LyricDownloadersHelp": "啟用並依照偏好排序字幕下載器。",
"RenderPgsSubtitle": "實驗性 PGS 字幕渲染",
"RenderPgsSubtitleHelp": "在用戶端渲染 PGS 字幕,代替伺服器端燒錄字幕。以降低用戶端效能為代價避免伺服器端轉檔。",
"PreferNonstandardArtistsTag": "可用時偏好 ARTISTS 標籤",
"PreferNonstandardArtistsTagHelp": "可用時使用非標準的 ARTISTS 標籤代替 ARTIST 標籤。",
"ReplaceTrickplayImages": "替換現有的快轉縮圖",
"UseCustomTagDelimiters": "使用自訂標籤分隔字元",
"UseCustomTagDelimitersHelp": "使用自訂的字元分割藝術家、風格標籤。",
"AllowFmp4TranscodingContainerHelp": "允許使用 fMP4 容器轉檔來自此解碼器的內容以啟用 HEVC 和 HDR。並非所有解碼器都和此容器相容。如果遇到播放問題請停用此設定。",
"LabelSaveTrickplayLocally": "將快轉縮圖儲存在媒體旁邊",
"LabelSaveTrickplayLocallyHelp": "將快轉縮圖儲存在媒體資料夾會將它們放在媒體旁邊,以便遷移和存取。",
"VideoCodecTagNotSupported": "不支援的視訊編碼標籤",
"LabelDelimiterWhitelist": "分隔字元白名單",
"LabelDelimiterWhitelistHelp": "從標籤分隔中排除的項目。每行一項。",
"AllowStreamSharingHelp": "允許 Jellyfin 複製解碼器中的 MPEGTS 串流並共用給多個用戶端。當解碼器有總串流數量限制時很有用,但是可能導致播放問題。",
"LabelAllowStreamSharing": "允許串流共用"
}

View file

@ -1,3 +1,4 @@
import type { MediaType } from '@jellyfin/sdk/lib/generated-client/models/media-type';
import type { UserDto } from '@jellyfin/sdk/lib/generated-client/models/user-dto';
export interface PlayTarget {
@ -7,5 +8,7 @@ export interface PlayTarget {
playerName?: string
deviceType?: string
isLocalPlayer?: boolean
playableMediaTypes: MediaType[]
supportedCommands?: string[]
user?: UserDto
}

101
src/utils/image.test.ts Normal file
View file

@ -0,0 +1,101 @@
import { BaseItemKind } from '@jellyfin/sdk/lib/generated-client/models/base-item-kind';
import { describe, expect, it } from 'vitest';
import { getItemTypeIcon, getLibraryIcon } from './image';
import { CollectionType } from '@jellyfin/sdk/lib/generated-client/models/collection-type';
const ITEM_ICON_MAP: Record<string, string | undefined> = {
AggregateFolder: undefined,
Audio: 'audiotrack',
AudioBook: undefined,
BasePluginFolder: undefined,
Book: 'book',
BoxSet: 'video_library',
Channel: undefined,
ChannelFolderItem: undefined,
CollectionFolder: undefined,
Episode: 'tv',
Folder: 'folder',
Genre: undefined,
LiveTvChannel: undefined,
LiveTvProgram: undefined,
ManualPlaylistsFolder: undefined,
Movie: 'movie',
MusicAlbum: 'album',
MusicArtist: 'person',
MusicGenre: undefined,
MusicVideo: undefined,
Person: 'person',
Photo: 'photo',
PhotoAlbum: 'photo_album',
Playlist: 'queue',
PlaylistsFolder: undefined,
Program: 'live_tv',
Recording: undefined,
Season: undefined,
Series: 'tv',
Studio: undefined,
Trailer: undefined,
TvChannel: undefined,
TvProgram: undefined,
UserRootFolder: undefined,
UserView: undefined,
Video: undefined,
Year: undefined
};
const LIBRARY_ICON_MAP: Record<string, string | undefined> = {
Books: 'book',
Boxsets: 'video_library',
Folders: 'folder',
Homevideos: 'photo',
Livetv: 'live_tv',
Movies: 'movie',
Music: 'music_note',
Musicvideos: 'music_video',
Photos: 'photo',
Playlists: 'queue',
Trailers: 'theaters',
Tvshows: 'tv',
Unknown: 'folder'
};
describe('getItemTypeIcon()', () => {
it('Should return the correct icon for item type', () => {
Object.entries(BaseItemKind).forEach(([key, value]) => {
expect(Object.prototype.hasOwnProperty.call(ITEM_ICON_MAP, key)).toBe(true);
expect(`${key}=${getItemTypeIcon(value)}`).toBe(`${key}=${ITEM_ICON_MAP[key]}`);
});
});
it('Should return the default icon for unknown type if provided', () => {
expect(getItemTypeIcon('foobar', 'default'))
.toBe('default');
});
it('Should return undefined for unknown type', () => {
expect(getItemTypeIcon('foobar'))
.toBeUndefined();
});
});
describe('getLibraryIcon()', () => {
it('Should return the correct icon for collection type', () => {
Object.entries(CollectionType).forEach(([key, value]) => {
expect(Object.prototype.hasOwnProperty.call(LIBRARY_ICON_MAP, key)).toBe(true);
expect(`${key}=${getLibraryIcon(value)}`).toBe(`${key}=${LIBRARY_ICON_MAP[key]}`);
});
});
it('Should return the correct icon for nonstandard types', () => {
expect(getLibraryIcon(undefined))
.toBe('quiz');
expect(getLibraryIcon('channels'))
.toBe('videocam');
});
it('Should return the default icon for unknown types', () => {
expect(getLibraryIcon('foobar'))
.toBe('folder');
});
});

View file

@ -1,3 +1,4 @@
import { CollectionType } from '@jellyfin/sdk/lib/generated-client/models/collection-type';
import { BaseItemKind } from '@jellyfin/sdk/lib/generated-client/models/base-item-kind';
import type { DeviceInfo } from '@jellyfin/sdk/lib/generated-client/models/device-info';
import type { SessionInfo } from '@jellyfin/sdk/lib/generated-client/models/session-info';
@ -75,36 +76,39 @@ export function getDeviceIcon(info: DeviceInfo | SessionInfo) {
}
}
export function getLibraryIcon(library: string | null | undefined) {
export function getLibraryIcon(library: CollectionType | string | null | undefined) {
switch (library) {
case 'movies':
return 'video_library';
case 'music':
return 'library_music';
case 'photos':
return 'photo_library';
case 'livetv':
case CollectionType.Movies:
return 'movie';
case CollectionType.Music:
return 'music_note';
case CollectionType.Homevideos:
case CollectionType.Photos:
return 'photo';
case CollectionType.Livetv:
return 'live_tv';
case 'tvshows':
case CollectionType.Tvshows:
return 'tv';
case 'trailers':
return 'local_movies';
case 'homevideos':
return 'photo_library';
case 'musicvideos':
case CollectionType.Trailers:
return 'theaters';
case CollectionType.Musicvideos:
return 'music_video';
case 'books':
return 'library_books';
case CollectionType.Books:
return 'book';
case CollectionType.Boxsets:
return 'video_library';
case CollectionType.Playlists:
return 'queue';
case 'channels':
return 'videocam';
case 'playlists':
return 'view_list';
case undefined:
return 'quiz';
default:
return 'folder';
}
}
export function getItemTypeIcon(itemType: BaseItemKind | string) {
export function getItemTypeIcon(itemType: BaseItemKind | string | undefined, defaultIcon?: string) {
switch (itemType) {
case BaseItemKind.MusicAlbum:
return 'album';
@ -125,15 +129,15 @@ export function getItemTypeIcon(itemType: BaseItemKind | string) {
case BaseItemKind.Folder:
return 'folder';
case BaseItemKind.BoxSet:
return 'collections';
return 'video_library';
case BaseItemKind.Playlist:
return 'view_list';
return 'queue';
case BaseItemKind.Photo:
return 'photo';
case BaseItemKind.PhotoAlbum:
return 'photo_album';
default:
return 'folder';
return defaultIcon;
}
}