mirror of
https://github.com/jellyfin/jellyfin-web.git
synced 2025-02-21 06:51:32 +00:00
Merge branch 'master' into Search
This commit is contained in:
commit
5700219762
@ -64,6 +64,7 @@ module.exports = {
|
||||
'no-throw-literal': ['error'],
|
||||
'no-trailing-spaces': ['error'],
|
||||
'no-undef-init': ['error'],
|
||||
'no-unneeded-ternary': ['error'],
|
||||
'no-unused-expressions': ['off'],
|
||||
'@typescript-eslint/no-unused-expressions': ['error', { 'allowShortCircuit': true, 'allowTernary': true, 'allowTaggedTemplates': true }],
|
||||
'no-unused-private-class-members': ['error'],
|
||||
|
@ -66,11 +66,12 @@
|
||||
- [Fishbigger](https://github.com/fishbigger)
|
||||
- [sleepycatcoding](https://github.com/sleepycatcoding)
|
||||
- [TheMelmacian](https://github.com/TheMelmacian)
|
||||
- [v0idMrK](https://github.com/v0idMrK)
|
||||
- [tehciolo](https://github.com/tehciolo)
|
||||
- [scampower3](https://github.com/scampower3)
|
||||
- [LittleBigOwI] (https://github.com/LittleBigOwI/)
|
||||
- [Nate G](https://github.com/GGProGaming)
|
||||
|
||||
|
||||
# Emby Contributors
|
||||
|
||||
- [LukePulverenti](https://github.com/LukePulverenti)
|
||||
|
@ -71,8 +71,8 @@ const GenresSectionContainer: FC<GenresSectionContainerProps> = ({
|
||||
centerText: true,
|
||||
cardLayout: false,
|
||||
shape: itemType === BaseItemKind.MusicAlbum ? 'overflowSquare' : 'overflowPortrait',
|
||||
showParentTitle: itemType === BaseItemKind.MusicAlbum ? true : false,
|
||||
showYear: itemType === BaseItemKind.MusicAlbum ? false : true
|
||||
showParentTitle: itemType === BaseItemKind.MusicAlbum,
|
||||
showYear: itemType !== BaseItemKind.MusicAlbum
|
||||
}}
|
||||
/>;
|
||||
};
|
||||
|
@ -11,8 +11,8 @@ import browser from 'scripts/browser';
|
||||
import datetime from 'scripts/datetime';
|
||||
import dom from 'scripts/dom';
|
||||
import globalize from 'scripts/globalize';
|
||||
import imageHelper from 'scripts/imagehelper';
|
||||
import { getBackdropShape, getPortraitShape, getSquareShape } from 'utils/card';
|
||||
import imageHelper from 'utils/image';
|
||||
import { randomInt } from 'utils/number';
|
||||
|
||||
import focusManager from '../focusManager';
|
||||
|
@ -102,7 +102,15 @@ function onInputCommand(e) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
function saveValues(context, settings, settingsKey, setfilters) {
|
||||
function saveValues(context, settings, settingsKey) {
|
||||
context.querySelectorAll('.simpleFilter').forEach(elem => {
|
||||
if (elem.tagName === 'INPUT') {
|
||||
setBasicFilter(context, settingsKey + '-filter-' + elem.getAttribute('data-settingname'), elem);
|
||||
} else {
|
||||
setBasicFilter(context, settingsKey + '-filter-' + elem.getAttribute('data-settingname'), elem.querySelector('input'));
|
||||
}
|
||||
});
|
||||
|
||||
// Video type
|
||||
const videoTypes = [];
|
||||
context.querySelectorAll('.chkVideoTypeFilter').forEach(elem => {
|
||||
@ -111,6 +119,8 @@ function saveValues(context, settings, settingsKey, setfilters) {
|
||||
}
|
||||
});
|
||||
|
||||
userSettings.setFilter(settingsKey + '-filter-VideoTypes', videoTypes.join(','));
|
||||
|
||||
// Series status
|
||||
const seriesStatuses = [];
|
||||
context.querySelectorAll('.chkSeriesStatus').forEach(elem => {
|
||||
@ -119,6 +129,8 @@ function saveValues(context, settings, settingsKey, setfilters) {
|
||||
}
|
||||
});
|
||||
|
||||
userSettings.setFilter(`${settingsKey}-filter-SeriesStatus`, seriesStatuses.join(','));
|
||||
|
||||
// Genres
|
||||
const genres = [];
|
||||
context.querySelectorAll('.chkGenreFilter').forEach(elem => {
|
||||
@ -127,38 +139,7 @@ function saveValues(context, settings, settingsKey, setfilters) {
|
||||
}
|
||||
});
|
||||
|
||||
if (setfilters) {
|
||||
setfilters((prevState) => ({
|
||||
...prevState,
|
||||
StartIndex: 0,
|
||||
IsPlayed: context.querySelector('.chkPlayed').checked,
|
||||
IsUnplayed: context.querySelector('.chkUnplayed').checked,
|
||||
IsFavorite: context.querySelector('.chkFavorite').checked,
|
||||
IsResumable: context.querySelector('.chkResumable').checked,
|
||||
Is4K: context.querySelector('.chk4KFilter').checked,
|
||||
IsHD: context.querySelector('.chkHDFilter').checked,
|
||||
IsSD: context.querySelector('.chkSDFilter').checked,
|
||||
Is3D: context.querySelector('.chk3DFilter').checked,
|
||||
VideoTypes: videoTypes.join(','),
|
||||
SeriesStatus: seriesStatuses.join(','),
|
||||
HasSubtitles: context.querySelector('.chkSubtitle').checked,
|
||||
HasTrailer: context.querySelector('.chkTrailer').checked,
|
||||
HasSpecialFeature: context.querySelector('.chkSpecialFeature').checked,
|
||||
HasThemeSong: context.querySelector('.chkThemeSong').checked,
|
||||
HasThemeVideo: context.querySelector('.chkThemeVideo').checked,
|
||||
GenreIds: genres.join(',')
|
||||
}));
|
||||
} else {
|
||||
context.querySelectorAll('.simpleFilter').forEach(elem => {
|
||||
if (elem.tagName === 'INPUT') {
|
||||
setBasicFilter(context, settingsKey + '-filter-' + elem.getAttribute('data-settingname'), elem);
|
||||
} else {
|
||||
setBasicFilter(context, settingsKey + '-filter-' + elem.getAttribute('data-settingname'), elem.querySelector('input'));
|
||||
}
|
||||
});
|
||||
|
||||
userSettings.setFilter(settingsKey + '-filter-GenreIds', genres.join(','));
|
||||
}
|
||||
userSettings.setFilter(settingsKey + '-filter-GenreIds', genres.join(','));
|
||||
}
|
||||
function bindCheckboxInput(context, on) {
|
||||
const elems = context.querySelectorAll('.checkboxList-verticalwrap');
|
||||
@ -289,7 +270,7 @@ class FilterMenu {
|
||||
}
|
||||
|
||||
if (submitted) {
|
||||
saveValues(dlg, options.settings, options.settingsKey, options.setfilters);
|
||||
saveValues(dlg, options.settings, options.settingsKey);
|
||||
return resolve();
|
||||
}
|
||||
return resolve();
|
||||
|
@ -291,7 +291,7 @@ function Guide(options) {
|
||||
showPremiereIndicator: allowIndicators && userSettings.get('guide-indicator-premiere') !== 'false',
|
||||
showNewIndicator: allowIndicators && userSettings.get('guide-indicator-new') !== 'false',
|
||||
showRepeatIndicator: allowIndicators && userSettings.get('guide-indicator-repeat') === 'true',
|
||||
showEpisodeTitle: layoutManager.tv ? false : true
|
||||
showEpisodeTitle: !layoutManager.tv
|
||||
};
|
||||
|
||||
apiClient.getLiveTvChannels(channelQuery).then(function (channelsResult) {
|
||||
|
@ -4,7 +4,7 @@ import escapeHtml from 'escape-html';
|
||||
import imageLoader from 'components/images/imageLoader';
|
||||
import { appRouter } from 'components/router/appRouter';
|
||||
import globalize from 'scripts/globalize';
|
||||
import imageHelper from 'scripts/imagehelper';
|
||||
import imageHelper from 'utils/image';
|
||||
|
||||
function getLibraryButtonsHtml(items: BaseItemDto[]) {
|
||||
let html = '';
|
||||
|
@ -9,6 +9,7 @@ import itemHelper from './itemHelper';
|
||||
import { playbackManager } from './playback/playbackmanager';
|
||||
import ServerConnections from './ServerConnections';
|
||||
import toast from './toast/toast';
|
||||
import * as userSettings from '../scripts/settings/userSettings';
|
||||
|
||||
export function getCommands(options) {
|
||||
const item = options.item;
|
||||
@ -589,9 +590,16 @@ function play(item, resume, queue, queueNext) {
|
||||
serverId: item.ServerId
|
||||
});
|
||||
} else {
|
||||
const sortParentId = 'items-' + (item.IsFolder ? item.Id : item.ParentId) + '-Folder';
|
||||
const sortValues = userSettings.getSortValuesLegacy(sortParentId);
|
||||
|
||||
playbackManager[method]({
|
||||
items: [item],
|
||||
startPositionTicks: startPosition
|
||||
startPositionTicks: startPosition,
|
||||
queryOptions: {
|
||||
SortBy: sortValues.sortBy,
|
||||
SortOrder: sortValues.sortOrder
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -177,7 +177,7 @@ export function getListViewHtml(options) {
|
||||
const isLargeStyle = options.imageSize === 'large';
|
||||
const enableOverview = options.enableOverview;
|
||||
|
||||
const clickEntireItem = layoutManager.tv ? true : false;
|
||||
const clickEntireItem = layoutManager.tv;
|
||||
const outerTagName = clickEntireItem ? 'button' : 'div';
|
||||
const enableSideMediaInfo = options.enableSideMediaInfo != null ? options.enableSideMediaInfo : true;
|
||||
|
||||
|
@ -183,9 +183,9 @@ export function getMediaInfoHtml(item, options = {}) {
|
||||
if (item.EndDate) {
|
||||
try {
|
||||
const endYear = datetime.toLocaleString(datetime.parseISO8601Date(item.EndDate).getFullYear(), { useGrouping: false });
|
||||
|
||||
if (endYear !== item.ProductionYear) {
|
||||
text += `-${endYear}`;
|
||||
/* At this point, text will contain only the start year */
|
||||
if (endYear !== text) {
|
||||
text += ` - ${endYear}`;
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('error parsing date:', item.EndDate);
|
||||
|
@ -15,6 +15,7 @@ import { PluginType } from '../../types/plugin.ts';
|
||||
import { includesAny } from '../../utils/container.ts';
|
||||
import { getItems } from '../../utils/jellyfin-apiclient/getItems.ts';
|
||||
import { getItemBackdropImageUrl } from '../../utils/jellyfin-apiclient/backdropImage';
|
||||
import merge from 'lodash-es/merge';
|
||||
|
||||
const UNLIMITED_ITEMS = -1;
|
||||
|
||||
@ -145,7 +146,7 @@ function createStreamInfoFromUrlItem(item) {
|
||||
}
|
||||
|
||||
function mergePlaybackQueries(obj1, obj2) {
|
||||
const query = Object.assign(obj1, obj2);
|
||||
const query = merge({}, obj1, obj2);
|
||||
|
||||
const filters = query.Filters ? query.Filters.split(',') : [];
|
||||
if (filters.indexOf('IsNotFolder') === -1) {
|
||||
@ -1798,15 +1799,15 @@ class PlaybackManager {
|
||||
SortBy: options.shuffle ? 'Random' : null
|
||||
});
|
||||
} else if (firstItem.Type === 'MusicArtist') {
|
||||
promise = getItemsForPlayback(serverId, {
|
||||
promise = getItemsForPlayback(serverId, mergePlaybackQueries({
|
||||
ArtistIds: firstItem.Id,
|
||||
Filters: 'IsNotFolder',
|
||||
Recursive: true,
|
||||
SortBy: options.shuffle ? 'Random' : 'SortName',
|
||||
MediaTypes: 'Audio'
|
||||
});
|
||||
}, queryOptions));
|
||||
} else if (firstItem.MediaType === 'Photo') {
|
||||
promise = getItemsForPlayback(serverId, {
|
||||
promise = getItemsForPlayback(serverId, mergePlaybackQueries({
|
||||
ParentId: firstItem.ParentId,
|
||||
Filters: 'IsNotFolder',
|
||||
// Setting this to true may cause some incorrect sorting
|
||||
@ -1814,7 +1815,7 @@ class PlaybackManager {
|
||||
SortBy: options.shuffle ? 'Random' : 'SortName',
|
||||
MediaTypes: 'Photo,Video',
|
||||
Limit: UNLIMITED_ITEMS
|
||||
}).then(function (result) {
|
||||
}, queryOptions)).then(function (result) {
|
||||
const playbackItems = result.Items;
|
||||
|
||||
let index = playbackItems.map(function (i) {
|
||||
@ -1830,7 +1831,7 @@ class PlaybackManager {
|
||||
return Promise.resolve(result);
|
||||
});
|
||||
} else if (firstItem.Type === 'PhotoAlbum') {
|
||||
promise = getItemsForPlayback(serverId, {
|
||||
promise = getItemsForPlayback(serverId, mergePlaybackQueries({
|
||||
ParentId: firstItem.Id,
|
||||
Filters: 'IsNotFolder',
|
||||
// Setting this to true may cause some incorrect sorting
|
||||
@ -1839,15 +1840,15 @@ class PlaybackManager {
|
||||
// Only include Photos because we do not handle mixed queues currently
|
||||
MediaTypes: 'Photo',
|
||||
Limit: UNLIMITED_ITEMS
|
||||
});
|
||||
}, queryOptions));
|
||||
} else if (firstItem.Type === 'MusicGenre') {
|
||||
promise = getItemsForPlayback(serverId, {
|
||||
promise = getItemsForPlayback(serverId, mergePlaybackQueries({
|
||||
GenreIds: firstItem.Id,
|
||||
Filters: 'IsNotFolder',
|
||||
Recursive: true,
|
||||
SortBy: options.shuffle ? 'Random' : 'SortName',
|
||||
MediaTypes: 'Audio'
|
||||
});
|
||||
}, queryOptions));
|
||||
} else if (firstItem.Type === 'Series' || firstItem.Type === 'Season') {
|
||||
const apiClient = ServerConnections.getApiClient(firstItem.ServerId);
|
||||
|
||||
@ -2773,6 +2774,12 @@ class PlaybackManager {
|
||||
});
|
||||
});
|
||||
} else {
|
||||
if (item.AlbumId != null) {
|
||||
return apiClient.getItem(apiClient.getCurrentUserId(), item.AlbumId).then(function(result) {
|
||||
mediaSource.albumLUFS = result.LUFS;
|
||||
return mediaSource;
|
||||
});
|
||||
}
|
||||
return mediaSource;
|
||||
}
|
||||
} else {
|
||||
|
@ -46,7 +46,7 @@ function showQualityMenu(player, btn) {
|
||||
const bitrate = parseInt(id, 10);
|
||||
if (bitrate !== selectedBitrate) {
|
||||
playbackManager.setMaxStreamingBitrate({
|
||||
enableAutomaticBitrateDetection: bitrate ? false : true,
|
||||
enableAutomaticBitrateDetection: !bitrate,
|
||||
maxBitrate: bitrate
|
||||
}, player);
|
||||
}
|
||||
|
@ -173,7 +173,7 @@ function loadForm(context, user, userSettings, apiClient) {
|
||||
context.querySelector('.chkPlayDefaultAudioTrack').checked = user.Configuration.PlayDefaultAudioTrack || false;
|
||||
context.querySelector('.chkPreferFmp4HlsContainer').checked = userSettings.preferFmp4HlsContainer();
|
||||
context.querySelector('.chkEnableCinemaMode').checked = userSettings.enableCinemaMode();
|
||||
context.querySelector('.chkEnableAudioNormalization').checked = userSettings.enableAudioNormalization();
|
||||
context.querySelector('#selectAudioNormalization').value = userSettings.selectAudioNormalization();
|
||||
context.querySelector('.chkEnableNextVideoOverlay').checked = userSettings.enableNextVideoInfoOverlay();
|
||||
context.querySelector('.chkRememberAudioSelections').checked = user.Configuration.RememberAudioSelections || false;
|
||||
context.querySelector('.chkRememberSubtitleSelections').checked = user.Configuration.RememberSubtitleSelections || false;
|
||||
@ -218,7 +218,7 @@ function saveUser(context, user, userSettingsInstance, apiClient) {
|
||||
user.Configuration.EnableNextEpisodeAutoPlay = context.querySelector('.chkEpisodeAutoPlay').checked;
|
||||
userSettingsInstance.preferFmp4HlsContainer(context.querySelector('.chkPreferFmp4HlsContainer').checked);
|
||||
userSettingsInstance.enableCinemaMode(context.querySelector('.chkEnableCinemaMode').checked);
|
||||
userSettingsInstance.enableAudioNormalization(context.querySelector('.chkEnableAudioNormalization').checked);
|
||||
userSettingsInstance.selectAudioNormalization(context.querySelector('#selectAudioNormalization').value);
|
||||
userSettingsInstance.enableNextVideoInfoOverlay(context.querySelector('.chkEnableNextVideoOverlay').checked);
|
||||
user.Configuration.RememberAudioSelections = context.querySelector('.chkRememberAudioSelections').checked;
|
||||
user.Configuration.RememberSubtitleSelections = context.querySelector('.chkRememberSubtitleSelections').checked;
|
||||
|
@ -72,12 +72,13 @@
|
||||
${TabAdvanced}
|
||||
</h2>
|
||||
|
||||
<div class="checkboxContainer checkboxContainer-withDescription">
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" class="chkEnableAudioNormalization" />
|
||||
<span>${EnableAudioNormalization}</span>
|
||||
</label>
|
||||
<div class="fieldDescription checkboxFieldDescription">${EnableAudioNormalizationHelp}</div>
|
||||
<div class="selectContainer">
|
||||
<select is="emby-select" id="selectAudioNormalization" label="${LabelSelectAudioNormalization}">
|
||||
<option value="Off">${Off}</option>
|
||||
<option value="TrackGain">${LabelTrackGain}</option>
|
||||
<option value="AlbumGain">${LabelAlbumGain}</option>
|
||||
</select>
|
||||
<div class="fieldDescription">${SelectAudioNormalizationHelp}</div>
|
||||
</div>
|
||||
|
||||
<div class="checkboxContainer checkboxContainer-withDescription">
|
||||
|
@ -11,6 +11,7 @@ import dom from '../scripts/dom';
|
||||
import recordingHelper from './recordingcreator/recordinghelper';
|
||||
import ServerConnections from './ServerConnections';
|
||||
import toast from './toast/toast';
|
||||
import * as userSettings from '../scripts/settings/userSettings';
|
||||
|
||||
function playAllFromHere(card, serverId, queue) {
|
||||
const parent = card.parentNode;
|
||||
@ -177,6 +178,10 @@ function executeAction(card, target, action) {
|
||||
|
||||
const item = getItemInfoFromCard(card);
|
||||
|
||||
const itemsContainer = dom.parentWithClass(card, 'itemsContainer');
|
||||
|
||||
const sortParentId = 'items-' + (item.IsFolder ? item.Id : itemsContainer?.getAttribute('data-parentid')) + '-Folder';
|
||||
|
||||
const serverId = item.ServerId;
|
||||
const type = item.Type;
|
||||
|
||||
@ -200,12 +205,17 @@ function executeAction(card, target, action) {
|
||||
});
|
||||
} else if (action === 'play' || action === 'resume') {
|
||||
const startPositionTicks = parseInt(card.getAttribute('data-positionticks') || '0', 10);
|
||||
const sortValues = userSettings.getSortValuesLegacy(sortParentId, 'SortName');
|
||||
|
||||
if (playbackManager.canPlay(item)) {
|
||||
playbackManager.play({
|
||||
ids: [playableItemId],
|
||||
startPositionTicks: startPositionTicks,
|
||||
serverId: serverId
|
||||
serverId: serverId,
|
||||
queryOptions: {
|
||||
SortBy: sortValues.sortBy,
|
||||
SortOrder: sortValues.sortOrder
|
||||
}
|
||||
});
|
||||
} else {
|
||||
console.warn('Unable to play item', item);
|
||||
|
@ -18,8 +18,8 @@ function onSubmit(e) {
|
||||
function initEditor(context, settings) {
|
||||
context.querySelector('form').addEventListener('submit', onSubmit);
|
||||
|
||||
context.querySelector('.selectSortOrder').value = settings.SortOrder;
|
||||
context.querySelector('.selectSortBy').value = settings.SortBy;
|
||||
context.querySelector('.selectSortOrder').value = settings.sortOrder;
|
||||
context.querySelector('.selectSortBy').value = settings.sortBy;
|
||||
}
|
||||
|
||||
function centerFocus(elem, horiz, on) {
|
||||
@ -37,18 +37,9 @@ function fillSortBy(context, options) {
|
||||
}).join('');
|
||||
}
|
||||
|
||||
function saveValues(context, settingsKey, setSortValues) {
|
||||
if (setSortValues) {
|
||||
setSortValues((prevState) => ({
|
||||
...prevState,
|
||||
StartIndex: 0,
|
||||
SortBy: context.querySelector('.selectSortBy').value,
|
||||
SortOrder: context.querySelector('.selectSortOrder').value
|
||||
}));
|
||||
} else {
|
||||
userSettings.setFilter(settingsKey + '-sortorder', context.querySelector('.selectSortOrder').value);
|
||||
userSettings.setFilter(settingsKey + '-sortby', context.querySelector('.selectSortBy').value);
|
||||
}
|
||||
function saveValues(context, settingsKey) {
|
||||
userSettings.setFilter(settingsKey + '-sortorder', context.querySelector('.selectSortOrder').value);
|
||||
userSettings.setFilter(settingsKey + '-sortby', context.querySelector('.selectSortBy').value);
|
||||
}
|
||||
|
||||
class SortMenu {
|
||||
@ -104,7 +95,7 @@ class SortMenu {
|
||||
}
|
||||
|
||||
if (submitted) {
|
||||
saveValues(dlg, options.settingsKey, options.setSortValues);
|
||||
saveValues(dlg, options.settingsKey);
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ import Toolbar from '@mui/material/Toolbar';
|
||||
import Tooltip from '@mui/material/Tooltip';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import React, { FC, ReactNode } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { Link, useLocation } from 'react-router-dom';
|
||||
|
||||
import appIcon from 'assets/img/icon-transparent.png';
|
||||
import { appRouter } from 'components/router/appRouter';
|
||||
@ -38,9 +38,13 @@ const AppToolbar: FC<AppToolbarProps> = ({
|
||||
}) => {
|
||||
const { user } = useApi();
|
||||
const isUserLoggedIn = Boolean(user);
|
||||
const currentLocation = useLocation();
|
||||
|
||||
const isBackButtonAvailable = appRouter.canGoBack();
|
||||
|
||||
// Handles a specific case to hide the user menu on the select server page while authenticated
|
||||
const isUserMenuAvailable = currentLocation.pathname !== '/selectserver.html';
|
||||
|
||||
return (
|
||||
<Toolbar
|
||||
variant='dense'
|
||||
@ -111,7 +115,7 @@ const AppToolbar: FC<AppToolbarProps> = ({
|
||||
|
||||
{children}
|
||||
|
||||
{isUserLoggedIn && (
|
||||
{isUserLoggedIn && isUserMenuAvailable && (
|
||||
<>
|
||||
<Box sx={{ display: 'flex', flexGrow: 1, justifyContent: 'flex-end' }}>
|
||||
{buttons}
|
||||
|
@ -29,24 +29,13 @@ function initEditor(context, settings) {
|
||||
context.querySelector('.selectImageType').value = settings.imageType || 'primary';
|
||||
}
|
||||
|
||||
function saveValues(context, settings, settingsKey, setviewsettings) {
|
||||
if (setviewsettings) {
|
||||
setviewsettings((prevState) => ({
|
||||
...prevState,
|
||||
StartIndex: 0,
|
||||
imageType: context.querySelector('.selectImageType').value,
|
||||
showTitle: context.querySelector('.chkShowTitle').checked || false,
|
||||
showYear: context.querySelector('.chkShowYear').checked || false,
|
||||
cardLayout: context.querySelector('.chkEnableCardLayout').checked || false
|
||||
}));
|
||||
} else {
|
||||
const elems = context.querySelectorAll('.viewSetting-checkboxContainer');
|
||||
for (const elem of elems) {
|
||||
userSettings.set(settingsKey + '-' + elem.getAttribute('data-settingname'), elem.querySelector('input').checked);
|
||||
}
|
||||
|
||||
userSettings.set(settingsKey + '-imageType', context.querySelector('.selectImageType').value);
|
||||
function saveValues(context, settings, settingsKey) {
|
||||
const elems = context.querySelectorAll('.viewSetting-checkboxContainer');
|
||||
for (const elem of elems) {
|
||||
userSettings.set(settingsKey + '-' + elem.getAttribute('data-settingname'), elem.querySelector('input').checked);
|
||||
}
|
||||
|
||||
userSettings.set(settingsKey + '-imageType', context.querySelector('.selectImageType').value);
|
||||
}
|
||||
|
||||
function centerFocus(elem, horiz, on) {
|
||||
@ -112,7 +101,6 @@ class ViewSettings {
|
||||
dlg.querySelector('.selectImageType').addEventListener('change', function () {
|
||||
showIfAllowed(dlg, '.chkTitleContainer', this.value !== 'list' && this.value !== 'banner');
|
||||
showIfAllowed(dlg, '.chkYearContainer', this.value !== 'list' && this.value !== 'banner');
|
||||
showIfAllowed(dlg, '.chkCardLayoutContainer', this.value !== 'list' && this.value !== 'banner');
|
||||
});
|
||||
|
||||
dlg.querySelector('.btnCancel').addEventListener('click', function () {
|
||||
@ -137,7 +125,7 @@ class ViewSettings {
|
||||
}
|
||||
|
||||
if (submitted) {
|
||||
saveValues(dlg, options.settings, options.settingsKey, options.setviewsettings);
|
||||
saveValues(dlg, options.settings, options.settingsKey);
|
||||
return resolve();
|
||||
}
|
||||
|
||||
|
@ -35,13 +35,6 @@
|
||||
<span>${GroupBySeries}</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="checkboxContainer viewSetting viewSetting-checkboxContainer hide chkCardLayoutContainer" data-settingname="cardLayout">
|
||||
<label>
|
||||
<input is="emby-checkbox" type="checkbox" class="chkEnableCardLayout" />
|
||||
<span>${EnableCardLayout}</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
@ -12,7 +12,7 @@ import playMethodHelper from '../../components/playback/playmethodhelper';
|
||||
import cardBuilder from '../../components/cardbuilder/cardBuilder';
|
||||
import imageLoader from '../../components/images/imageLoader';
|
||||
import ActivityLog from '../../components/activitylog';
|
||||
import imageHelper from '../../scripts/imagehelper';
|
||||
import imageHelper from '../../utils/image';
|
||||
import indicators from '../../components/indicators/indicators';
|
||||
import '../../components/listview/listview.scss';
|
||||
import '../../elements/emby-button/emby-button';
|
||||
|
@ -3,7 +3,7 @@ import cardBuilder from '../../../components/cardbuilder/cardBuilder';
|
||||
import loading from '../../../components/loading/loading';
|
||||
import dom from '../../../scripts/dom';
|
||||
import globalize from '../../../scripts/globalize';
|
||||
import imageHelper from '../../../scripts/imagehelper';
|
||||
import imageHelper from '../../../utils/image';
|
||||
import { formatDistanceToNow } from 'date-fns';
|
||||
import { getLocaleWithSuffix } from '../../../utils/dateFnsLocale.ts';
|
||||
import '../../../elements/emby-button/emby-button';
|
||||
|
@ -254,7 +254,9 @@
|
||||
</div>
|
||||
<button type="button" is="paper-icon-button-light" id="btnSelectFallbackFontPath" class="emby-input-iconbutton"><span class="material-icons search" aria-hidden="true"></span></button>
|
||||
</div>
|
||||
<div class="fieldDescription">${LabelFallbackFontPathHelp}</div>
|
||||
<div class="fieldDescription">
|
||||
<a is="emby-linkbutton" rel="noopener noreferrer" class="button-link" href="https://jellyfin.org/docs/general/administration/configuration#fonts" target="_blank">${LabelFallbackFontPathHelp}</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="checkboxContainer checkboxContainer-withDescription">
|
||||
<label>
|
||||
|
@ -5,7 +5,7 @@ import loading from '../../components/loading/loading';
|
||||
import libraryMenu from '../../scripts/libraryMenu';
|
||||
import globalize from '../../scripts/globalize';
|
||||
import dom from '../../scripts/dom';
|
||||
import imageHelper from '../../scripts/imagehelper';
|
||||
import imageHelper from '../../utils/image';
|
||||
import '../../components/cardbuilder/card.scss';
|
||||
import '../../elements/emby-itemrefreshindicator/emby-itemrefreshindicator';
|
||||
import Dashboard, { pageClassOn, pageIdOn } from '../../utils/dashboard';
|
||||
|
@ -1374,8 +1374,8 @@ function renderChildren(page, item) {
|
||||
items: result.Items,
|
||||
showIndexNumber: false,
|
||||
enableOverview: true,
|
||||
enablePlayedButton: layoutManager.mobile ? false : true,
|
||||
infoButton: layoutManager.mobile ? false : true,
|
||||
enablePlayedButton: !layoutManager.mobile,
|
||||
infoButton: !layoutManager.mobile,
|
||||
imageSize: 'large',
|
||||
enableSideMediaInfo: false,
|
||||
highlight: false,
|
||||
|
@ -724,8 +724,13 @@ class ItemsView {
|
||||
const currentItem = self.currentItem;
|
||||
|
||||
if (currentItem && !self.hasFilters) {
|
||||
const values = self.getSortValues();
|
||||
playbackManager.play({
|
||||
items: [currentItem],
|
||||
queryOptions: {
|
||||
SortBy: values.sortBy,
|
||||
SortOrder: values.sortOrder
|
||||
},
|
||||
autoplay: true
|
||||
});
|
||||
} else {
|
||||
@ -960,10 +965,7 @@ class ItemsView {
|
||||
|
||||
getSortValues() {
|
||||
const basekey = this.getSettingsKey();
|
||||
return {
|
||||
sortBy: userSettings.getFilter(basekey + '-sortby') || this.getDefaultSortBy(),
|
||||
sortOrder: userSettings.getFilter(basekey + '-sortorder') === 'Descending' ? 'Descending' : 'Ascending'
|
||||
};
|
||||
return userSettings.getSortValuesLegacy(basekey, this.getDefaultSortBy());
|
||||
}
|
||||
|
||||
getDefaultSortBy() {
|
||||
|
@ -1,19 +1,48 @@
|
||||
import RemoteControl from '../../../components/remotecontrol/remotecontrol';
|
||||
import { playbackManager } from '../../../components/playback/playbackmanager';
|
||||
import libraryMenu from '../../../scripts/libraryMenu';
|
||||
import '../../../elements/emby-button/emby-button';
|
||||
|
||||
export default function (view) {
|
||||
const remoteControl = new RemoteControl();
|
||||
remoteControl.init(view, view.querySelector('.remoteControlContent'));
|
||||
|
||||
let currentPlayer;
|
||||
|
||||
function onKeyDown(e) {
|
||||
if (e.keyCode === 32 && e.target.tagName !== 'BUTTON') {
|
||||
playbackManager.playPause(currentPlayer);
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}
|
||||
}
|
||||
|
||||
function releaseCurrentPlayer() {
|
||||
const player = currentPlayer;
|
||||
if (player) currentPlayer = null;
|
||||
}
|
||||
|
||||
function bindToPlayer(player) {
|
||||
if (player !== currentPlayer) {
|
||||
releaseCurrentPlayer();
|
||||
currentPlayer = player;
|
||||
}
|
||||
}
|
||||
|
||||
view.addEventListener('viewshow', function () {
|
||||
libraryMenu.setTransparentMenu(true);
|
||||
bindToPlayer(playbackManager.getCurrentPlayer());
|
||||
document.addEventListener('keydown', onKeyDown);
|
||||
|
||||
if (remoteControl) {
|
||||
remoteControl.onShow();
|
||||
}
|
||||
});
|
||||
|
||||
view.addEventListener('viewbeforehide', function () {
|
||||
libraryMenu.setTransparentMenu(false);
|
||||
document.removeEventListener('keydown', onKeyDown);
|
||||
releaseCurrentPlayer();
|
||||
|
||||
if (remoteControl) {
|
||||
remoteControl.destroy();
|
||||
|
@ -21,7 +21,7 @@ function onKeyDown(e) {
|
||||
}
|
||||
}
|
||||
|
||||
const enableRefreshHack = browser.tizen || browser.orsay || browser.operaTv || browser.web0s ? true : false;
|
||||
const enableRefreshHack = browser.tizen || browser.orsay || browser.operaTv || browser.web0s;
|
||||
|
||||
function forceRefresh(loading) {
|
||||
const elem = this.parentNode;
|
||||
|
@ -3,11 +3,7 @@ import scrollerFactory from '../../libraries/scroller';
|
||||
import globalize from '../../scripts/globalize';
|
||||
import IconButton from '../emby-button/IconButton';
|
||||
import './emby-scrollbuttons.scss';
|
||||
|
||||
enum Direction {
|
||||
RIGHT,
|
||||
LEFT,
|
||||
}
|
||||
import { ScrollDirection, scrollerItemSlideIntoView } from './utils';
|
||||
|
||||
interface ScrollButtonsProps {
|
||||
scrollerFactoryRef: React.MutableRefObject<scrollerFactory | null>;
|
||||
@ -22,31 +18,16 @@ const ScrollButtons: FC<ScrollButtonsProps> = ({ scrollerFactoryRef, scrollState
|
||||
const [localeScrollPos, setLocaleScrollPos] = useState<number>(0);
|
||||
const scrollButtonsRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const scrollToPosition = useCallback((pos: number, immediate: boolean) => {
|
||||
if (scrollerFactoryRef.current) {
|
||||
scrollerFactoryRef.current.slideTo(pos, immediate, undefined );
|
||||
}
|
||||
}, [scrollerFactoryRef]);
|
||||
const onScrollButtonClick = useCallback((direction: ScrollDirection) => {
|
||||
scrollerItemSlideIntoView({
|
||||
direction,
|
||||
scroller: scrollerFactoryRef.current,
|
||||
scrollState
|
||||
});
|
||||
}, [scrollState, scrollerFactoryRef]);
|
||||
|
||||
const onScrollButtonClick = useCallback((direction: Direction) => {
|
||||
let newPos;
|
||||
if (direction === Direction.LEFT) {
|
||||
newPos = Math.max(0, scrollState.scrollPos - scrollState.scrollSize);
|
||||
} else {
|
||||
newPos = scrollState.scrollPos + scrollState.scrollSize;
|
||||
}
|
||||
|
||||
if (globalize.getIsRTL() && direction === Direction.LEFT) {
|
||||
newPos = scrollState.scrollPos + scrollState.scrollSize;
|
||||
} else if (globalize.getIsRTL()) {
|
||||
newPos = Math.min(0, scrollState.scrollPos - scrollState.scrollSize);
|
||||
}
|
||||
|
||||
scrollToPosition(newPos, false);
|
||||
}, [ scrollState.scrollPos, scrollState.scrollSize, scrollToPosition ]);
|
||||
|
||||
const triggerScrollLeft = useCallback(() => onScrollButtonClick(Direction.LEFT), [ onScrollButtonClick ]);
|
||||
const triggerScrollRight = useCallback(() => onScrollButtonClick(Direction.RIGHT), [ onScrollButtonClick ]);
|
||||
const triggerScrollLeft = useCallback(() => onScrollButtonClick(ScrollDirection.LEFT), [ onScrollButtonClick ]);
|
||||
const triggerScrollRight = useCallback(() => onScrollButtonClick(ScrollDirection.RIGHT), [ onScrollButtonClick ]);
|
||||
|
||||
useEffect(() => {
|
||||
const parent = scrollButtonsRef.current?.parentNode as HTMLDivElement;
|
||||
@ -67,7 +48,7 @@ const ScrollButtons: FC<ScrollButtonsProps> = ({ scrollerFactoryRef, scrollState
|
||||
className='emby-scrollbuttons-button btnPrev'
|
||||
onClick={triggerScrollLeft}
|
||||
icon='chevron_left'
|
||||
disabled={localeScrollPos > 0 ? false : true}
|
||||
disabled={localeScrollPos <= 0}
|
||||
/>
|
||||
|
||||
<IconButton
|
||||
@ -75,7 +56,7 @@ const ScrollButtons: FC<ScrollButtonsProps> = ({ scrollerFactoryRef, scrollState
|
||||
className='emby-scrollbuttons-button btnNext'
|
||||
onClick={triggerScrollRight}
|
||||
icon='chevron_right'
|
||||
disabled={scrollState.scrollWidth > 0 && localeScrollPos + scrollState.scrollSize >= scrollState.scrollWidth ? true : false}
|
||||
disabled={scrollState.scrollWidth > 0 && localeScrollPos + scrollState.scrollSize >= scrollState.scrollWidth}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
@ -2,6 +2,7 @@ import './emby-scrollbuttons.scss';
|
||||
import 'webcomponents.js/webcomponents-lite';
|
||||
import '../emby-button/paper-icon-button-light';
|
||||
import globalize from '../../scripts/globalize';
|
||||
import { scrollerItemSlideIntoView } from './utils';
|
||||
|
||||
const EmbyScrollButtonsPrototype = Object.create(HTMLDivElement.prototype);
|
||||
|
||||
@ -128,26 +129,16 @@ function getScrollSize(elem) {
|
||||
}
|
||||
|
||||
function onScrollButtonClick() {
|
||||
const scroller = this.parentNode.nextSibling;
|
||||
|
||||
const direction = this.getAttribute('data-direction');
|
||||
const scrollSize = getScrollSize(scroller);
|
||||
const scrollPos = getScrollPosition(scroller);
|
||||
|
||||
let newPos;
|
||||
if (direction === 'left') {
|
||||
newPos = Math.max(0, scrollPos - scrollSize);
|
||||
} else {
|
||||
newPos = scrollPos + scrollSize;
|
||||
}
|
||||
|
||||
if (globalize.getIsRTL() && direction === 'left') {
|
||||
newPos = scrollPos + scrollSize;
|
||||
} else if (globalize.getIsRTL()) {
|
||||
newPos = Math.min(0, scrollPos - scrollSize);
|
||||
}
|
||||
|
||||
scroller.scrollToPosition(newPos, false);
|
||||
const scroller = this.parentNode.nextSibling;
|
||||
const scrollPosition = getScrollPosition(scroller);
|
||||
scrollerItemSlideIntoView({
|
||||
direction,
|
||||
scroller,
|
||||
scrollState: {
|
||||
scrollPos: scrollPosition
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
EmbyScrollButtonsPrototype.attachedCallback = function () {
|
||||
|
103
src/elements/emby-scrollbuttons/utils.ts
Normal file
103
src/elements/emby-scrollbuttons/utils.ts
Normal file
@ -0,0 +1,103 @@
|
||||
import ScrollerFactory from 'libraries/scroller';
|
||||
import globalize from 'scripts/globalize';
|
||||
|
||||
export enum ScrollDirection {
|
||||
RIGHT = 'right',
|
||||
LEFT = 'left',
|
||||
}
|
||||
|
||||
interface ScrollState {
|
||||
scrollPos: number;
|
||||
}
|
||||
|
||||
interface ScrollerItemSlideIntoViewProps {
|
||||
direction: ScrollDirection;
|
||||
scroller: ScrollerFactory | null;
|
||||
scrollState: ScrollState;
|
||||
}
|
||||
|
||||
interface ScrollToWindowProps {
|
||||
scroller: ScrollerFactory;
|
||||
items: HTMLElement[];
|
||||
scrollState: ScrollState;
|
||||
direction: ScrollDirection
|
||||
}
|
||||
|
||||
export function scrollerItemSlideIntoView({ direction, scroller, scrollState }: ScrollerItemSlideIntoViewProps) {
|
||||
if (!scroller) {
|
||||
return;
|
||||
}
|
||||
|
||||
const slider: HTMLElement = scroller.getScrollSlider();
|
||||
const items = [...slider.children] as HTMLElement[];
|
||||
|
||||
scrollToWindow({
|
||||
scroller,
|
||||
items,
|
||||
scrollState,
|
||||
direction
|
||||
});
|
||||
}
|
||||
|
||||
function getFirstAndLastVisible(scrollFrame: HTMLElement, items: HTMLElement[], { scrollPos: scrollPosition }: ScrollState) {
|
||||
const isRTL = globalize.getIsRTL();
|
||||
const localeModifier = isRTL ? -1 : 1;
|
||||
|
||||
const currentScrollPos = scrollPosition * localeModifier;
|
||||
const scrollerWidth = scrollFrame.offsetWidth;
|
||||
const itemWidth = items[0].offsetWidth;
|
||||
|
||||
// Rounding down here will give us the first item index which is fully visible. We want the first partially visible
|
||||
// index so we'll subtract one.
|
||||
const firstVisibleIndex = Math.max(Math.floor(currentScrollPos / itemWidth) - 1, 0);
|
||||
// Rounding up will give us the last index which is at least partially visible (overflows at container end).
|
||||
const lastVisibleIndex = Math.floor((currentScrollPos + scrollerWidth) / itemWidth);
|
||||
|
||||
return [firstVisibleIndex, lastVisibleIndex];
|
||||
}
|
||||
|
||||
function scrollToWindow({
|
||||
scroller,
|
||||
items,
|
||||
scrollState,
|
||||
direction = ScrollDirection.RIGHT
|
||||
}: ScrollToWindowProps) {
|
||||
// When we're rendering RTL, scrolling toward the end of the container is toward the left so all of our scroll
|
||||
// positions need to be negative.
|
||||
const isRTL = globalize.getIsRTL();
|
||||
const localeModifier = isRTL ? -1 : 1;
|
||||
|
||||
// NOTE: The legacy scroller is passing in an Element which is the frame element and has some of the scroller
|
||||
// factory functions on it, but is not a true scroller factory. For legacy, we need to pass `scroller` directly
|
||||
// instead of getting the frame from the factory instance.
|
||||
const frame = scroller.getScrollFrame?.() ?? scroller;
|
||||
const [firstVisibleIndex, lastVisibleIndex] = getFirstAndLastVisible(frame, items, scrollState);
|
||||
|
||||
let scrollToPosition: number;
|
||||
|
||||
if (direction === ScrollDirection.RIGHT) {
|
||||
const nextItem = items[lastVisibleIndex];
|
||||
|
||||
// This will be the position to anchor the item at `lastVisibleIndex` to the start of the view window.
|
||||
const nextItemScrollOffset = lastVisibleIndex * nextItem.offsetWidth;
|
||||
scrollToPosition = nextItemScrollOffset * localeModifier;
|
||||
} else {
|
||||
const previousItem = items[firstVisibleIndex];
|
||||
const previousItemScrollOffset = firstVisibleIndex * previousItem.offsetWidth;
|
||||
|
||||
// Find the total number of items that can fit in a view window and subtract one to account for item at
|
||||
// `firstVisibleIndex`. The total width of these items is the amount that we need to adjust the scroll position by
|
||||
// to anchor item at `firstVisibleIndex` to the end of the view window.
|
||||
const offsetAdjustment = (Math.floor(frame.offsetWidth / previousItem.offsetWidth) - 1) * previousItem.offsetWidth;
|
||||
|
||||
// This will be the position to anchor the item at `firstVisibleIndex` to the end of the view window.
|
||||
scrollToPosition = (previousItemScrollOffset - offsetAdjustment) * localeModifier;
|
||||
}
|
||||
|
||||
if (scroller.slideTo) {
|
||||
scroller.slideTo(scrollToPosition, false, undefined);
|
||||
} else {
|
||||
// @ts-expect-error Legacy support passes in a `scroller` that isn't a ScrollFactory
|
||||
scroller.scrollToPosition(scrollToPosition);
|
||||
}
|
||||
}
|
@ -112,9 +112,14 @@ class HtmlAudioPlayer {
|
||||
let val = options.url;
|
||||
console.debug('playing url: ' + val);
|
||||
import('../../scripts/settings/userSettings').then((userSettings) => {
|
||||
if (userSettings.enableAudioNormalization() && options.item.LUFS != null) {
|
||||
if (userSettings.selectAudioNormalization() == 'TrackGain' && options.item.LUFS != null) {
|
||||
const dbGain = -18 - options.item.LUFS;
|
||||
self.gainNode.gain.value = Math.pow(10, (dbGain / 20));
|
||||
console.debug('[HtmlAudioPlayer] Using track gain');
|
||||
} else if (userSettings.selectAudioNormalization() == 'AlbumGain' && options.mediaSource.albumLUFS != null) {
|
||||
const dbGain = -18 - options.mediaSource.albumLUFS;
|
||||
self.gainNode.gain.value = Math.pow(10, (dbGain / 20));
|
||||
console.debug('[HtmlAudioPlayer] Using album gain');
|
||||
} else {
|
||||
self.gainNode.gain.value = 1;
|
||||
}
|
||||
|
@ -692,7 +692,7 @@ export default function (options) {
|
||||
|
||||
profile.TranscodingProfiles = [];
|
||||
|
||||
const hlsBreakOnNonKeyFrames = browser.iOS || browser.osx || browser.edge || !canPlayNativeHls() ? true : false;
|
||||
const hlsBreakOnNonKeyFrames = browser.iOS || browser.osx || browser.edge || !canPlayNativeHls();
|
||||
|
||||
if (canPlayHls() && browser.enableHlsAudio !== false) {
|
||||
profile.TranscodingProfiles.push({
|
||||
|
@ -125,7 +125,8 @@ function renderSection(item, element, type) {
|
||||
ArtistIds: '',
|
||||
AlbumArtistIds: '',
|
||||
Limit: 10,
|
||||
SortBy: 'SortName'
|
||||
SortOrder: 'Descending,Desending,Ascending',
|
||||
SortBy: 'PremiereDate,ProductionYear,SortName'
|
||||
}, {
|
||||
shape: 'overflowPortrait',
|
||||
showTitle: true,
|
||||
@ -194,7 +195,7 @@ function renderSection(item, element, type) {
|
||||
PersonTypes: '',
|
||||
ArtistIds: '',
|
||||
AlbumArtistIds: '',
|
||||
SortOrder: 'Descending',
|
||||
SortOrder: 'Descending,Desending,Ascending',
|
||||
SortBy: 'PremiereDate,ProductionYear,Sortname'
|
||||
}, {
|
||||
shape: 'overflowSquare',
|
||||
|
@ -12,7 +12,7 @@ import { pluginManager } from '../components/pluginManager';
|
||||
import groupSelectionMenu from '../plugins/syncPlay/ui/groupSelectionMenu';
|
||||
import browser from './browser';
|
||||
import globalize from './globalize';
|
||||
import imageHelper from './imagehelper';
|
||||
import imageHelper from '../utils/image';
|
||||
import { getMenuLinks } from '../scripts/settings/webSettings';
|
||||
import Dashboard, { pageClassOn } from '../utils/dashboard';
|
||||
import ServerConnections from '../components/ServerConnections';
|
||||
|
@ -158,15 +158,15 @@ export class UserSettings {
|
||||
|
||||
/**
|
||||
* Get or set 'Enable Audio Normalization' state.
|
||||
* @param {boolean|undefined} val - Flag to enable 'Enable Audio Normalization' or undefined.
|
||||
* @return {boolean} 'Enable Audio Normalization' state.
|
||||
* @param {string|undefined} val - Flag to enable 'Enable Audio Normalization' or undefined.
|
||||
* @return {string} 'Enable Audio Normalization' state.
|
||||
*/
|
||||
enableAudioNormalization(val) {
|
||||
selectAudioNormalization(val) {
|
||||
if (val !== undefined) {
|
||||
return this.set('enableAudioNormalization', val.toString(), false);
|
||||
return this.set('selectAudioNormalization', val, false);
|
||||
}
|
||||
|
||||
return toBoolean(this.get('enableAudioNormalization', false), true);
|
||||
return this.get('selectAudioNormalization', false) || 'TrackGain';
|
||||
}
|
||||
|
||||
/**
|
||||
@ -622,6 +622,21 @@ export class UserSettings {
|
||||
getFilter(key) {
|
||||
return this.get(key, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current sort values (Legacy - Non-JSON)
|
||||
* (old views such as list.js [Photos] will
|
||||
* use this one)
|
||||
* @param {string} key - Filter key.
|
||||
* @param {string} defaultSortBy - Default SortBy value.
|
||||
* @return {Object} sortOptions object
|
||||
*/
|
||||
getSortValuesLegacy(key, defaultSortBy) {
|
||||
return {
|
||||
sortBy: this.getFilter(key + '-sortby') || defaultSortBy,
|
||||
sortOrder: this.getFilter(key + '-sortorder') === 'Descending' ? 'Descending' : 'Ascending'
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export const currentSettings = new UserSettings;
|
||||
@ -636,7 +651,7 @@ export const serverConfig = currentSettings.serverConfig.bind(currentSettings);
|
||||
export const allowedAudioChannels = currentSettings.allowedAudioChannels.bind(currentSettings);
|
||||
export const preferFmp4HlsContainer = currentSettings.preferFmp4HlsContainer.bind(currentSettings);
|
||||
export const enableCinemaMode = currentSettings.enableCinemaMode.bind(currentSettings);
|
||||
export const enableAudioNormalization = currentSettings.enableAudioNormalization.bind(currentSettings);
|
||||
export const selectAudioNormalization = currentSettings.selectAudioNormalization.bind(currentSettings);
|
||||
export const enableNextVideoInfoOverlay = currentSettings.enableNextVideoInfoOverlay.bind(currentSettings);
|
||||
export const enableVideoRemainingTime = currentSettings.enableVideoRemainingTime.bind(currentSettings);
|
||||
export const enableThemeSongs = currentSettings.enableThemeSongs.bind(currentSettings);
|
||||
@ -672,3 +687,4 @@ export const customCss = currentSettings.customCss.bind(currentSettings);
|
||||
export const disableCustomCss = currentSettings.disableCustomCss.bind(currentSettings);
|
||||
export const getSavedView = currentSettings.getSavedView.bind(currentSettings);
|
||||
export const saveViewSetting = currentSettings.saveViewSetting.bind(currentSettings);
|
||||
export const getSortValuesLegacy = currentSettings.getSortValuesLegacy.bind(currentSettings);
|
||||
|
@ -1429,7 +1429,7 @@
|
||||
"DeleteAll": "Odstranit vše",
|
||||
"EnableFallbackFontHelp": "Povolit vlastní alternativní písma. Může vyřešit problémy s nesprávným vykreslením titulků.",
|
||||
"EnableFallbackFont": "Povolit záložní písma",
|
||||
"LabelFallbackFontPathHelp": "Zadejte cestu k náhradním písmům pro vykreslení titulků ve formátu ASS/SSA. Maximální celková velikost písma je 20 MB. Doporučujeme používat malé webové písma jako například formát woff2.",
|
||||
"LabelFallbackFontPathHelp": "Tato písma používají někteří klienti k vykreslení titulků. Více informací naleznete v dokumentaci.",
|
||||
"LabelFallbackFontPath": "Cesta k náhradním písmům",
|
||||
"HeaderSelectFallbackFontPathHelp": "Vyberte či zadejte cestu k záložním písmům pro vykreslení titulků ve formátu ASS/SSA.",
|
||||
"HeaderSelectFallbackFontPath": "Vybrat cestu k záložním fontům",
|
||||
@ -1776,5 +1776,9 @@
|
||||
"UnknownError": "Došlo k neznámé chybě.",
|
||||
"BackdropScreensaver": "Pozadí",
|
||||
"LogoScreensaver": "Logo",
|
||||
"LabelIsHearingImpaired": "Titulky pro neslyšící"
|
||||
"LabelIsHearingImpaired": "Titulky pro neslyšící",
|
||||
"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."
|
||||
}
|
||||
|
@ -138,7 +138,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.",
|
||||
"EnableAudioNormalizationHelp": "Audio normalization will add a constant gain to keep the average at a desired level (-18dB).",
|
||||
"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.",
|
||||
"ClearQueue": "Clear queue",
|
||||
"ClientSettings": "Client Settings",
|
||||
"Collections": "Collections",
|
||||
@ -226,7 +226,6 @@
|
||||
"EnableBlurHash": "Enable blurred placeholders for images",
|
||||
"EnableBlurHashHelp": "Images that are still being loaded will be displayed with a unique placeholder.",
|
||||
"EnableCinemaMode": "Cinema mode",
|
||||
"EnableAudioNormalization": "Audio Normalization",
|
||||
"EnableColorCodedBackgrounds": "Color coded backgrounds",
|
||||
"EnableDecodingColorDepth10Hevc": "Enable 10-bit hardware decoding for HEVC",
|
||||
"EnableDecodingColorDepth10Vp9": "Enable 10-bit hardware decoding for VP9",
|
||||
@ -549,6 +548,7 @@
|
||||
"LabelAlbumArtMaxResHelp": "Maximum resolution of album art exposed via the 'upnp:albumArtURI' property.",
|
||||
"LabelAlbumArtMaxWidth": "Album art max width",
|
||||
"LabelAlbumArtPN": "Album art PN",
|
||||
"LabelAlbumGain": "Album Gain",
|
||||
"LabelAllowedRemoteAddresses": "Remote IP address filter",
|
||||
"LabelAllowedRemoteAddressesMode": "Remote IP address filter mode",
|
||||
"LabelAllowHWTranscoding": "Allow hardware transcoding",
|
||||
@ -561,6 +561,7 @@
|
||||
"LabelAudioChannels": "Audio channels",
|
||||
"LabelAudioCodec": "Audio codec",
|
||||
"LabelAudioLanguagePreference": "Preferred audio language",
|
||||
"LabelSelectAudioNormalization": "Audio Normalization",
|
||||
"LabelAudioSampleRate": "Audio sample rate",
|
||||
"LabelAuthProvider": "Authentication Provider",
|
||||
"LabelAutomaticallyAddToCollection": "Automatically add to collection",
|
||||
@ -1625,7 +1626,7 @@
|
||||
"HeaderSelectFallbackFontPath": "Select Fallback Font Folder Path",
|
||||
"HeaderSelectFallbackFontPathHelp": "Browse or enter the path of the fallback font folder to use for rendering ASS/SSA subtitles.",
|
||||
"LabelFallbackFontPath": "Fallback font folder path",
|
||||
"LabelFallbackFontPathHelp": "Specify a path containing fallback fonts for rendering ASS/SSA subtitles. The maximum allowed total font size is 20 MB. Lightweight and web-friendly font formats such as woff2 are recommended.",
|
||||
"LabelFallbackFontPathHelp": "These fonts are used by some clients to render subtitles. Please refer to the documentation for more information.",
|
||||
"EnableFallbackFont": "Enable fallback fonts",
|
||||
"EnableFallbackFontHelp": "Enable custom alternate fonts. This can avoid the problem of incorrect subtitle rendering.",
|
||||
"AspectRatioCover": "Cover",
|
||||
@ -1636,6 +1637,7 @@
|
||||
"LabelPlaybackInfo": "Playback Info",
|
||||
"LabelAudioInfo": "Audio Info",
|
||||
"LabelVideoInfo": "Video Info",
|
||||
"LabelTrackGain": "Track Gain",
|
||||
"LabelTranscodingInfo": "Transcoding Info",
|
||||
"LabelDirectStreamingInfo": "Direct Streaming Info",
|
||||
"LabelRemuxingInfo": "Remuxing Info",
|
||||
|
@ -1450,7 +1450,7 @@
|
||||
"LabelAutomaticallyAddToCollectionHelp": "Kun ainakin kahdelle elokuvalle on ilmoitettu sama kokoelma, lisätään ne kokoelmaan automaattisesti.",
|
||||
"OptionSaveMetadataAsHiddenHelp": "Tämän muutos vaikuttaa vain jatkossa tehtäviin metatietojen tallennuksiin. Olemassa olevat metatietotiedostot päivitetään, kun palvelin tallentaa ne seuraavan kerran.",
|
||||
"SpecialFeatures": "Lisämateriaalit",
|
||||
"LabelFallbackFontPathHelp": "Määritä ASS/SSA-tekstitysten varmistusfonttien tiedostosijainti. Suurin sallittu fontin kokonaiskoko on 20 Mt. Kevyet verkkoystävälliset fontit, kuten woff2, ovat suositeltuja.",
|
||||
"LabelFallbackFontPathHelp": "Jotkin päätelaitteet käyttävät tekstityksille näitä fontteja. Katso lisätietoja käyttöoppaasta.",
|
||||
"HeaderSelectFallbackFontPathHelp": "Selaa tai syötä ASS/SSA-tekstitysten renderöintiin käytettävien varmistusfonttien tiedostosijainti.",
|
||||
"PathNotFound": "Tiedostosijaintia ei löydy. Varmista, että se on oikein ja yritä uudelleen.",
|
||||
"XmlTvPathHelp": "XMLTV-tiedoston sijainti. Jellyfin lukee tiedoston ajoittain muutosten varalta. Olet itse vastuussa tiedoston luonnista ja päivityksestä.",
|
||||
@ -1774,5 +1774,9 @@
|
||||
"UnknownError": "Tapahtui tuntematon virhe.",
|
||||
"BackdropScreensaver": "Backdrop-näytönsäästäjä",
|
||||
"LogoScreensaver": "Logo-näytönsäästäjä",
|
||||
"LabelIsHearingImpaired": "Kuulorajoitteisille (SDH)"
|
||||
"LabelIsHearingImpaired": "Kuulorajoitteisille (SDH)",
|
||||
"SelectAudioNormalizationHelp": "Kappalekohtainen vahvistus – jokaisen kappaleen äänenvoimakkuus pyritään säätämään samalle tasolle. Albumikohtainen vahvistus – kappaleiden äänenvoimakkuus pyritään tasaamaan albumikohtaisesti albumikohtaisen dynamiikan säilyttämiseksi.",
|
||||
"LabelAlbumGain": "Albumikohtainen vahvistus",
|
||||
"LabelSelectAudioNormalization": "Äänenvoimakkuuden normalisointi",
|
||||
"LabelTrackGain": "Kappelkohtainen vahvistus"
|
||||
}
|
||||
|
@ -27,7 +27,7 @@
|
||||
"AllowedRemoteAddressesHelp": "Liste séparée par des virgules des adresses IP autorisées à se connecter à distance. Une liste laissée vide signifie que toutes les adresses sont autorisées.",
|
||||
"AlwaysPlaySubtitles": "Toujours afficher",
|
||||
"AlwaysPlaySubtitlesHelp": "Les sous-titres correspondant à la langue préférée seront chargés indépendamment de la langue de l'audio.",
|
||||
"AnyLanguage": "N'importe quel langage",
|
||||
"AnyLanguage": "N'importe quelle langue",
|
||||
"Anytime": "N'importe quand",
|
||||
"AroundTime": "Aux environs de {0}",
|
||||
"Artists": "Artistes",
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -23,11 +23,11 @@
|
||||
"AddToFavorites": "Додади во омилени",
|
||||
"All": "Сите",
|
||||
"Add": "Додади",
|
||||
"Actor": "Актер",
|
||||
"Absolute": "Абсолутно",
|
||||
"Actor": "Глумец",
|
||||
"Absolute": "Апсолутно",
|
||||
"ButtonSubmit": "Испрати",
|
||||
"ButtonStop": "Стопирај",
|
||||
"ButtonStart": "Почеток",
|
||||
"ButtonStart": "Почни",
|
||||
"ButtonSplit": "Раздели",
|
||||
"ButtonExitApp": "Излези од апликацијата",
|
||||
"ButtonSignOut": "Одјави се",
|
||||
@ -44,50 +44,50 @@
|
||||
"ButtonRemove": "Отстрани",
|
||||
"ButtonRefreshGuideData": "Освежи податоци на водич",
|
||||
"ButtonQuickStartGuide": "Водич за брз почеток",
|
||||
"ButtonPreviousTrack": "Претходна трака",
|
||||
"ButtonPause": "Пауза",
|
||||
"ButtonPreviousTrack": "Претходна нумера",
|
||||
"ButtonPause": "Паузирај",
|
||||
"ButtonParentalControl": "Родителска контрола",
|
||||
"ButtonOpen": "Отвори",
|
||||
"ButtonOk": "Ок",
|
||||
"ButtonNextTrack": "Следна трака",
|
||||
"ButtonOk": "Во ред",
|
||||
"ButtonNextTrack": "Следна нумера",
|
||||
"ButtonMore": "Повеќе",
|
||||
"ButtonManualLogin": "Мануелна најава",
|
||||
"ButtonManualLogin": "Рачна најава",
|
||||
"ButtonLibraryAccess": "Пристап до библиотека",
|
||||
"ButtonInfo": "Инфо",
|
||||
"ButtonInfo": "Информации",
|
||||
"ButtonGotIt": "Потврдувам",
|
||||
"ButtonFullscreen": "Цел екран",
|
||||
"ButtonForgotPassword": "Заборавена лозинка",
|
||||
"ButtonEditOtherUserPreferences": "Ажурирај го профилот на овој корисник, слики и лични преференци.",
|
||||
"ButtonEditOtherUserPreferences": "Ажурирај го профилот на овој корисник, слики и лични поставки.",
|
||||
"ButtonClose": "Затвори",
|
||||
"ButtonChangeServer": "Смени сервер",
|
||||
"ButtonCast": "Проектирај на уред",
|
||||
"ButtonCancel": "Откажи",
|
||||
"ButtonBack": "Назад",
|
||||
"ButtonAudioTracks": "Аудио траки",
|
||||
"ButtonAudioTracks": "Јазик на звук",
|
||||
"ButtonArrowRight": "Десно",
|
||||
"ButtonArrowLeft": "Лево",
|
||||
"ButtonAddUser": "Додај корисник",
|
||||
"ButtonAddServer": "Додај сервер",
|
||||
"ButtonAddScheduledTaskTrigger": "Додај тригер",
|
||||
"ButtonAddMediaLibrary": "Додај медија библиотека",
|
||||
"ButtonAddScheduledTaskTrigger": "Додај прекинувач",
|
||||
"ButtonAddMediaLibrary": "Додај медиумска библиотека",
|
||||
"ButtonAddImage": "Додај слика",
|
||||
"ButtonActivate": "Активирај",
|
||||
"Browse": "Прелистувај",
|
||||
"Browse": "Пребарувај",
|
||||
"BoxSet": "Сет на кутии",
|
||||
"BoxRear": "Кутија (позади)",
|
||||
"Box": "Кутија",
|
||||
"BoxRear": "Омот (позади)",
|
||||
"Box": "Омот",
|
||||
"BookLibraryHelp": "Аудио и текстуални книги се поддржани. Проверете го {0} водич за именување на книги {1}.",
|
||||
"Blacklist": "Црна листа",
|
||||
"BirthPlaceValue": "Место на раѓање: {0}",
|
||||
"BirthLocation": "Место на раѓање",
|
||||
"BirthDateValue": "Роден: {0}",
|
||||
"Banner": "Банер",
|
||||
"Auto": "Ауто",
|
||||
"AuthProviderHelp": "Одбери автентикациски провајдер кој што ќе се користи за лозинката на овој корисник.",
|
||||
"Authorize": "Авторизирај",
|
||||
"Audio": "Аудио",
|
||||
"AspectRatio": "Соодно",
|
||||
"AsManyAsPossible": "Колку што е можно",
|
||||
"Auto": "Автоматски",
|
||||
"AuthProviderHelp": "Одбери провајдер за автентикација кој што ќе се користи за лозинката на овој корисник.",
|
||||
"Authorize": "Одобри",
|
||||
"Audio": "Звук",
|
||||
"AspectRatio": "Сооднос",
|
||||
"AsManyAsPossible": "Колку што е можно повеќе",
|
||||
"AskAdminToCreateLibrary": "Побарај од администратор да создаде библиотека.",
|
||||
"Ascending": "Растечки",
|
||||
"Artist": "Изведувач",
|
||||
@ -96,59 +96,59 @@
|
||||
"ApiKeysCaption": "Листа на моментално вклучени API клучеви",
|
||||
"Anytime": "Било кога",
|
||||
"AnyLanguage": "Било кој јазик",
|
||||
"AlwaysPlaySubtitlesHelp": "Преводи кои се совпаѓаат со јазичните преференци ќе бидат вчитани без разлика на јазикот на аудиото.",
|
||||
"AlwaysPlaySubtitlesHelp": "Преводи кои се совпаѓаат со претпочитаниот јазик ќе бидат вчитани без разлика на јазикот на звукот.",
|
||||
"AlwaysPlaySubtitles": "Пуштај секогаш",
|
||||
"AllowTonemappingHelp": "Тонско-мапирање може да го трансформира динамичкиот опсег на видео од HDR во SDR зачувајќи ги бојата и деталите на сликата, кои што се важни информации за репрезентирање на оригиналната сцена. Моментално функционира само со HDR10 или HLG видеа. Задолжителни се соодветните OpenCL или CUDA рантајм.",
|
||||
"AllowRemoteAccessHelp": "Ако не е штиклирано, сите далечински конекции ќе бидат блокирано.",
|
||||
"AllowRemoteAccess": "Дозволи далечински конекции до овој сервер",
|
||||
"AllowOnTheFlySubtitleExtractionHelp": "Вградени преводи може да бидат екстрахирани од видеа и испорачани на клиентите во обичен текст, со цел да се превентира видео транскодирање. На некои системи ова може да трае долго и да причини заглавување на видеото при екстракцијата. Оневозможете го ова за да ги имате вградените преводи во видео транскодирањето дури и кога не се нативно поддржани на клиент уредот.",
|
||||
"AllowOnTheFlySubtitleExtraction": "Дозволи екстракција на преводи во живо",
|
||||
"AllowMediaConversionHelp": "Додај или одземи пристап за конвертирање на медија.",
|
||||
"AllowMediaConversion": "Дозволи конверзија на медија",
|
||||
"AllowTonemappingHelp": "Тонско-мапирање може да го трансформира динамичкиот опсег на видео од HDR во SDR зачувувајќи ги бојата и деталите на сликата, кои што се важни информации за претставување на оригиналната сцена. Моментално функционира само со HDR10 или HLG видеа. Задолжителни се соодветните OpenCL или CUDA рантајм.",
|
||||
"AllowRemoteAccessHelp": "Ако не е штиклирано, сите далечински врски ќе бидат блокирани.",
|
||||
"AllowRemoteAccess": "Дозволи далечински врски до овој сервер",
|
||||
"AllowOnTheFlySubtitleExtractionHelp": "Вградени преводи може да бидат одвоени од видеа и испорачани на клиентите во обичен текст, со цел да се спречи видео транскодирање. На некои системи ова може да трае долго и да причини заглавување на видеото при екстракцијата. Оневозможете го ова за да ги имате вградените преводи во видео транскодирањето дури и кога не се нативно поддржани на клиент уредот.",
|
||||
"AllowOnTheFlySubtitleExtraction": "Дозволи екстракција на преводи во реално време",
|
||||
"AllowMediaConversionHelp": "Дозволи или забрани пристап за конвертирање.",
|
||||
"AllowMediaConversion": "Дозволи конверзија на медиумска содржина",
|
||||
"AllowHWTranscodingHelp": "Дозволи му на тјунерот да транскодира стримови во живо. Со ова може да се намали транскодирањето потребно од серверот.",
|
||||
"AllowFfmpegThrottlingHelp": "Кога транскодирање или ремукс е доволно пред моментална позиција на плејбек, паузирај го процесот за да конзумира помалку ресурси. Ова е најкорисно кога се гледа без често премотување. Изгасете го ова доколку имате проблеми со гледање и премотување.",
|
||||
"AllowFfmpegThrottling": "Пригуши транскодирања",
|
||||
"AllowedRemoteAddressesHelp": "Листа на IP адреси или IP/нетмаск парови кои ќе имаат дозвола да се конектираат далечински. Ако е оставено празно, сите адреси ќе ја имаат оваа дозвола.",
|
||||
"AllowedRemoteAddressesHelp": "Листа на IP адреси или IP/нетмаск парови кои ќе имаат дозвола да се поврзуваат далечински. Ако е оставено празно, сите адреси ќе ја имаат оваа дозвола.",
|
||||
"AllLibraries": "Сите библиотеки",
|
||||
"AllLanguages": "Сите јазици",
|
||||
"AllEpisodes": "Сите епизоди",
|
||||
"AllComplexFormats": "Сите комплексни формати (ASS, SSA, VobSub, PGS, SUB, IDX, …)",
|
||||
"AllComplexFormats": "Сите сложени формати (ASS, SSA, VobSub, PGS, SUB, IDX, …)",
|
||||
"AllChannels": "Сите канали",
|
||||
"Alerts": "Алармирања",
|
||||
"Alerts": "Предупредувања",
|
||||
"AlbumArtist": "Изведувач",
|
||||
"Album": "Албум",
|
||||
"Aired": "Емитувано",
|
||||
"AirDate": "Датум на емитување",
|
||||
"AgeValue": "({0} години)",
|
||||
"AddToPlayQueue": "Додај во редица за гледање",
|
||||
"AddToPlayQueue": "Додади во ред за пуштање",
|
||||
"AdditionalNotificationServices": "Пребарувајте низ каталогот за плугини за да инсталирате додатни сервиси за известувања.",
|
||||
"AddedOnValue": "Додадено {0}",
|
||||
"AccessRestrictedTryAgainLater": "Пристапот е моментално органичен. Ве молиме пробајте подоцна.",
|
||||
"DirectStreaming": "Директно стримање",
|
||||
"DirectStreamHelp2": "Моќта конзумирана со директно стримање најчесто е зависна од аудио профилот. Само видео стримот е без губење на квалитет.",
|
||||
"DirectStreamHelp1": "Видео стримот е компатибилен со овој уред, но има некомпатибилен аудио формат (DTS, Dolby TrueHD, etc.) или број на аудио канали. Видео стримот ќе биде препакуван без губење на квалитет во живо пред да биде пратен на уредот. Само аудио стримот ќе биде транскодиран.",
|
||||
"DirectStreaming": "Директен стрим",
|
||||
"DirectStreamHelp2": "Енергијата која се троши од директното стримување најчесто зависи од аудио профилот. Само видео стримот е без губење на квалитет.",
|
||||
"DirectStreamHelp1": "Видео стримот е компатибилен со овој уред, но има некомпатибилен формат на звук (DTS, Dolby TrueHD, etc.) или број на аудио канали. Видео стримот ќе биде препакуван без губење на квалитет во живо пред да биде пратен на уредот. Само аудио стримот ќе биде транскодиран.",
|
||||
"DirectPlayHelp": "Изворната датотека е комплетно компатибилна со овој клиент, и сесијата ја прима оваа датотека без модификации.",
|
||||
"DirectPlaying": "Директно гледање",
|
||||
"Directors": "Режисери",
|
||||
"Director": "Режисер",
|
||||
"Digital": "Дигитален",
|
||||
"DeviceAccessHelp": "Ова важи само за уреди кои што можат да бидат уникатно идентифицирани и нема да превентираат пристап на прелистувач. Филтерирање на кориснички пристап на уред ќе ги превентира од користење на нови уреди додека не се одобрени тука.",
|
||||
"DetectingDevices": "Детектирање на уреди",
|
||||
"Desktop": "Десктоп",
|
||||
"Digital": "Дигитално",
|
||||
"DeviceAccessHelp": "Ова важи само за уреди кои што можат да бидат уникатно препознаени и нема да спречат пристап до прелистувачот. Филтрирање на кориснички пристап на уред ќе спречи користење на нови уреди додека не се одобрат тука.",
|
||||
"DetectingDevices": "Откривање на уреди",
|
||||
"Desktop": "Работна површина",
|
||||
"Descending": "Опаѓачки",
|
||||
"DeleteUserConfirmation": "Дали сте сигурни дека сакате да го избришете овој корисник?",
|
||||
"DeleteUser": "Избриши корисник",
|
||||
"DeleteMedia": "Избриши медија",
|
||||
"DeleteMedia": "Избриши медиумска содржина",
|
||||
"DeleteImageConfirmation": "Дали сте сигурни дека сакате да ја избришете оваа слика?",
|
||||
"DeleteImage": "Избриши слика",
|
||||
"DeleteDevicesConfirmation": "Дали сте сигурни дека сакате да ги избришете сите уреди? Сите други сесии ќе бидат одјавени. Уредите ќе се појават повторно кога корисникот ќе се најави.",
|
||||
"DeleteDeviceConfirmation": "Дали сте сигурен дека сакате да го избришете овој уред? Ќе се појави следниот пат кога корисникот ќе се најави со него.",
|
||||
"DeleteAll": "Избриши ги сите",
|
||||
"DeleteDeviceConfirmation": "Дали сте сигурни дека сакате да го избришете овој уред? Ќе се појави повторно следниот пат кога корисникот ќе се најави со него.",
|
||||
"DeleteAll": "Избриши сѐ",
|
||||
"Delete": "Избриши",
|
||||
"DeinterlaceMethodHelp": "Одбери го методот за одпреплетување кога софтверски се транскодира преплетена содржина. Кога хардверска акцелерација која што поддржува хардверско одпреплетување е вклучено хардверскиот одпреплетувач ќе биде користен наместо ова подесување.",
|
||||
"DefaultSubtitlesHelp": "Преводите се вчитани базирано на стандардните и форсирани знаменца во вградената метадата. Преференците за јазик се земени во предвид кога има повеќе можни опции.",
|
||||
"DefaultMetadataLangaugeDescription": "Ова се вашите стандардни опции и можат да бидат прилагодени посебно за секоја библиотека.",
|
||||
"DeathDateValue": "Починал: {0}",
|
||||
"DeinterlaceMethodHelp": "Одбери го методот за одпреплетување кога софтверски се транскодира преплетена содржина. Кога хардверско забрзување кое што поддржува хардверско одпреплетување е вклучено, хардверскиот одпреплетувач ќе биде користен наместо оваа поставка.",
|
||||
"DefaultSubtitlesHelp": "Преводите се вчитани базирано на стандардните и форсирани знаменца во вградената метадата. Поставките за јазик се земени во предвид кога има повеќе можни опции.",
|
||||
"DefaultMetadataLangaugeDescription": "Ова се вашите зададени вредности и можат да бидат прилагодени посебно за секоја библиотека.",
|
||||
"DeathDateValue": "Починал/а: {0}",
|
||||
"DatePlayed": "Датум на гледање",
|
||||
"DateAdded": "Датум на додавање",
|
||||
"Data": "Податоци",
|
||||
@ -157,32 +157,32 @@
|
||||
"DashboardOperatingSystem": "Оперативен систем: {0}",
|
||||
"DashboardArchitecture": "Архитектура: {0}",
|
||||
"DailyAt": "Секој ден во {0}",
|
||||
"CustomDlnaProfilesHelp": "Создади прилагоден профил за таргетирање на нов уред или за прескокање на системски профил.",
|
||||
"Cursive": "Закосено",
|
||||
"CustomDlnaProfilesHelp": "Создадете прилагоден профил за да насочите нов уред или да го отфрлите системскиот профил.",
|
||||
"Cursive": "Ракописно",
|
||||
"CriticRating": "Оценка на критичари",
|
||||
"CopyStreamURLSuccess": "Успешно копирана адреса.",
|
||||
"CopyStreamURL": "Копирај адреса на стрим",
|
||||
"CopyFailed": "Неуспешно копирање",
|
||||
"Copy": "Копирај",
|
||||
"Copied": "Копирано",
|
||||
"Continuing": "Продолжување",
|
||||
"Continuing": "Продолжува",
|
||||
"ContinueWatching": "Продолжи со гледање",
|
||||
"Console": "Конзола",
|
||||
"Connect": "Поврзување",
|
||||
"ConfirmEndPlayerSession": "Дали сакате да го изгасите Jellyfin на {0}?",
|
||||
"Connect": "Поврзи",
|
||||
"ConfirmEndPlayerSession": "Дали сакате да го исклучите Jellyfin на {0}?",
|
||||
"ConfirmDeletion": "Потврди бришење",
|
||||
"ConfirmDeleteItems": "Бришење на овие ставки ќе ги избрише и од податочниот систем и од библиотеката. Дали сте сигурни дека сакате да продолжите?",
|
||||
"ConfirmDeleteItem": "Бришење на оваа ставка ќе го избрише и од податочниот систем и од библиотеката. Дали сте сигурни дека сакате да продолжите?",
|
||||
"ConfirmDeleteItems": "Бришењето на овие ставки ќе ги избрише и од податочниот систем и од библиотеката. Дали сте сигурни дека сакате да продолжите?",
|
||||
"ConfirmDeleteItem": "Бришењето на оваа ставка ќе го избрише и од податочниот систем и од библиотеката. Дали сте сигурни дека сакате да продолжите?",
|
||||
"ConfirmDeleteImage": "Избриши слика?",
|
||||
"ConfigureDateAdded": "Намести како метадатата за „датум на додавање“ е одредена во Контролна табла > Библиотеки > NFO подесувања",
|
||||
"Conductor": "Кондуктор",
|
||||
"ConfigureDateAdded": "Поставете како се одредуваат метаподатоците за „Датум на додадено“ во Контролна табла > Библиотеки > Поставки за NFO",
|
||||
"Conductor": "Диригент",
|
||||
"Composer": "Композитор",
|
||||
"CommunityRating": "Оценка на заедницата",
|
||||
"ColorTransfer": "Трансфер на бои",
|
||||
"ColorTransfer": "Пренос на бои",
|
||||
"ColorSpace": "Простор на бои",
|
||||
"ColorPrimaries": "Примарни бои",
|
||||
"ColorPrimaries": "Основни бои",
|
||||
"ClientSettings": "Кориснички поставувања",
|
||||
"ClearQueue": "Исчисти редица",
|
||||
"ClearQueue": "Исчисти ред",
|
||||
"CinemaModeConfigurationHelp": "Кино режин го носи кино искуството директно во вашата дневна соба со можноста на пуштање на трејлери и интра пред главните сцени.",
|
||||
"ChannelNumber": "Број на канал",
|
||||
"ChannelNameOnly": "Само канал {0}",
|
||||
@ -197,5 +197,108 @@
|
||||
"ButtonUseQuickConnect": "Користи „брзо поврзување“",
|
||||
"ButtonUninstall": "Деинсталирај",
|
||||
"ButtonTrailer": "Трејлер",
|
||||
"ButtonTogglePlaylist": "Плејлиста"
|
||||
"ButtonTogglePlaylist": "Плејлиста",
|
||||
"Backdrop": "Позадина",
|
||||
"LabelThrottleDelaySecondsHelp": "Време во секунди по кое транскодерот ќе биде пригушен. Мора да биде доволно долго за клиентот да одржува здрав бафер. Работи само ако е овозможено пригушување.",
|
||||
"Art": "Графика",
|
||||
"ButtonSyncPlay": "SyncPlay",
|
||||
"ButtonBackspace": "бек-спејс",
|
||||
"ButtonPlayer": "Плеер",
|
||||
"ButtonSpace": "Празно место",
|
||||
"BackdropScreensaver": "Заштитник на екран во позадина",
|
||||
"AllowCollectionManagement": "Дозволете овој корисник да управува со колекциите",
|
||||
"AllowSegmentDeletion": "Избриши сегменти",
|
||||
"AllowSegmentDeletionHelp": "Избришете ги старите сегменти откако ќе бидат испратени до клиентот. Ова го спречува складирањето на целата транскодирана датотека на дискот. Ќе работи само со овозможено пригушување. Исклучете го ова ако имате проблеми со репродукцијата.",
|
||||
"LabelThrottleDelaySeconds": "Пригуши после",
|
||||
"LabelSegmentKeepSeconds": "Време за чување на сегментите",
|
||||
"LabelSegmentKeepSecondsHelp": "Време во секунди за кое сегментите треба да се чуваат пред да бидат препишани. Мора да биде подолго од „Пригуши после“. Работи само ако е овозможено бришењето сегменти.",
|
||||
"Backdrops": "Позадини",
|
||||
"BurnSubtitlesHelp": "Определете дали серверот треба да вградува преводи додека транскодирате видеа. Избегнувањето на ова во голема мера ќе ги подобри перформансите. Изберете Автоматски за снимање на формати базирани на слики (VobSub, PGS, SUB, IDX, итн.) и одредени ASS или SSA преводи.",
|
||||
"DisableCustomCss": "Оневозможи приспособен CSS код обезбеден од серверот",
|
||||
"Download": "Преземи",
|
||||
"EditImages": "Уреди слики",
|
||||
"EditSubtitles": "Уреди превод",
|
||||
"EnableBackdropsHelp": "Прикажувајте ги заднините во заднината на некои страници додека ја прелистувате библиотеката.",
|
||||
"EnableBlurHashHelp": "Сликите што сè уште се вчитуваат ќе се прикажат со единствено место.",
|
||||
"EnableDisplayMirroring": "Пресликување на екранот",
|
||||
"EnableExternalVideoPlayers": "Надворешни видео плеери",
|
||||
"EnableExternalVideoPlayersHelp": "Ќе се прикаже мени за надворешен плеер кога ќе започнете со репродукција на видео.",
|
||||
"Episodes": "Епизоди",
|
||||
"ErrorAddingListingsToSchedulesDirect": "Настана грешка при додавањето на поставата на вашата сметка на Распореди Директно. Распореди Директно дозволува само ограничен број на постави по сметка. Можеби ќе треба да се најавите на веб-локацијата Распоред Директно и да ги отстраните другите списоци од вашата сметка пред да продолжите.",
|
||||
"ErrorGettingTvLineups": "Настана грешка при преземањето ТВ-постави. Проверете дали вашите информации се точни и обидете се повторно.",
|
||||
"EveryXHours": "Секои {0} часови",
|
||||
"ExtractChapterImagesHelp": "Извлекувањето слики од поглавја ќе им овозможи на клиентите да прикажуваат графички менија за избор на сцена. Процесот може да биде бавен, интензивен за ресурси и може да бара неколку гигабајти простор. Работи кога ќе се откријат видеата, а исто така и како ноќна закажана задача. Распоредот може да се конфигурира во областа за закажани задачи. Не се препорачува да се извршува оваа задача за време на максимални часови на употреба.",
|
||||
"FFmpegSavePathNotFound": "Не можеме да го најдеме FFmpeg користејќи ја патеката што ја внесовте. Потребна е и FFprobe и мора да постои во истата папка. Овие компоненти обично се заедно во истото преземање. Проверете ја патеката и обидете се повторно.",
|
||||
"FileNotFound": "Датотеката не е пронајдена.",
|
||||
"Disc": "Диск",
|
||||
"EnableDetailsBanner": "Детали за банер",
|
||||
"Extras": "Додатоци",
|
||||
"Features": "Можности",
|
||||
"File": "Датотека",
|
||||
"EnableFasterAnimationsHelp": "Користи побрзи анимации и транзиции.",
|
||||
"EnableFasterAnimations": "Побрзи анимации",
|
||||
"EnableHardwareEncoding": "Овозможи хардверско кодирање",
|
||||
"ErrorPlayerNotFound": "Не е пронајден плеер за бараните медиумски содржини.",
|
||||
"EveryHour": "Секој час",
|
||||
"EveryNDays": "Секои {0} дена",
|
||||
"EnablePlugin": "Овозможи",
|
||||
"DoNotRecord": "Не снимај",
|
||||
"DownloadsValue": "{0} преземања",
|
||||
"EnableBlurHash": "Овозможете заматени места за слики",
|
||||
"ErrorStartHourGreaterThanEnd": "Времето на завршување мора да биде поголемо од времето на започнување.",
|
||||
"ExitFullscreen": "Излези од приказ на цел екран",
|
||||
"ExtraLarge": "Екстра големо",
|
||||
"FastForward": "Премотај-напред",
|
||||
"Favorite": "Омилено",
|
||||
"DisplayInOtherHomeScreenSections": "Прикажување во деловите на почетниот екран како што се „Неодамна додадени медиуми“ и „Продолжи со гледање“",
|
||||
"EnableThemeSongsHelp": "Пуштете ги тематските песни во позадина додека ја прелистувате библиотеката.",
|
||||
"EnableRewatchingNextUp": "Овозможи повторно гледање во Следно",
|
||||
"EnableRewatchingNextUpHelp": "Овозможи прикажување на веќе гледаните епизоди во деловите „Следно“.",
|
||||
"Depressed": "Застарено",
|
||||
"DisablePlugin": "Оневозможи",
|
||||
"Disconnect": "Исклучи",
|
||||
"Display": "Прикажи",
|
||||
"DisplayInMyMedia": "Прикажи на почетен екран",
|
||||
"EnableStreamLooping": "Автоматско-повторување на преноси во живо",
|
||||
"EnableQuickConnect": "Овозможи Брзо Поврзување на овој сервер",
|
||||
"EnableNextVideoInfoOverlayHelp": "На крајот на видеото, прикажи информации за следното видео во моменталната плејлиста.",
|
||||
"Episode": "Епизода",
|
||||
"DisplayMissingEpisodesWithinSeasonsHelp": "Ова мора да биде овозможено и за ТВ библиотеките во конфигурацијата на серверот.",
|
||||
"Down": "Надолу",
|
||||
"Edit": "Уреди",
|
||||
"EditMetadata": "Уреди метаподатоци",
|
||||
"EnableAutoCast": "Постави за зададено",
|
||||
"EnableDecodingColorDepth10Vp9": "Овозможи 10-битно хардверско декодирање за VP9",
|
||||
"EnableCinemaMode": "Кино режим",
|
||||
"EnableDetailsBannerHelp": "Прикажете слика на банер на врвот на страницата со детали за ставката.",
|
||||
"EnableAudioNormalization": "Нормализација на звук",
|
||||
"EnableDecodingColorDepth10Hevc": "Овозможи 10-битно хардверско декодирање за HEVC",
|
||||
"EnableNextVideoInfoOverlay": "Прикажи ги информациите за следното видео за време на гледањето",
|
||||
"EncoderPresetHelp": "Изберете побрза вредност за подобрување на перформансите или побавна вредност за подобрување на квалитетот.",
|
||||
"Ended": "Завршено",
|
||||
"EndsAtValue": "Завршува во {0}",
|
||||
"Engineer": "Звучен инжинер",
|
||||
"ErrorAddingMediaPathToVirtualFolder": "Настана грешка при додавањето на патеката за медиумски содржини. Ве молиме проверете дали патеката е валидна и Jellyfin има пристап до таа локација.",
|
||||
"ErrorAddingTunerDevice": "Настана грешка при додавањето на тјунерот. Проверете дали е достапен и обидете се повторно.",
|
||||
"ErrorAddingXmlTvFile": "Настана грешка при пристапот до датотеката XMLTV. Проверете дали постои датотеката и обидете се повторно.",
|
||||
"ErrorDefault": "Настана грешка при обработката на барањето. Обидете се повторно подоцна.",
|
||||
"EveryXMinutes": "Секои {0} минути",
|
||||
"EnableAudioNormalizationHelp": "Нормализацијата на звукот ќе додаде постојано засилување за да го задржи просекот на посакуваното ниво (-18dB).",
|
||||
"DisplayModeHelp": "Изберете го стилот на распоред што го сакате за интерфејсот.",
|
||||
"Experimental": "Експериментално",
|
||||
"DropShadow": "Прикажи сенка",
|
||||
"EnablePhotos": "Прикажи фотографии",
|
||||
"EnablePhotosHelp": "Сликите ќе бидат откриени и прикажани заедно со други медиумски датотеки.",
|
||||
"ErrorDeletingItem": "Настана грешка при бришењето на ставката од серверот. Ве молиме проверете дали Jellyfin има пристап за пишување до медиумската папка и обидете се повторно.",
|
||||
"ErrorPleaseSelectLineup": "Изберете постава и обидете се повторно. Ако не се достапни постави, тогаш ве молиме проверете дали вашето корисничко име, лозинка и поштенски код се точни.",
|
||||
"ErrorSavingTvProvider": "Настана грешка при зачувувањето на ТВ-провајдерот. Проверете дали е достапен и обидете се повторно.",
|
||||
"EnableCardLayout": "Прикажи визуелен CardBox",
|
||||
"DownloadAll": "Преземи сѐ",
|
||||
"EnableColorCodedBackgrounds": "Позадини со кодирани бои",
|
||||
"DisplayMissingEpisodesWithinSeasons": "Прикажи ги епизодите што недостасуваат во сезоните",
|
||||
"EnableTonemapping": "Овозможи мапирање на тонови",
|
||||
"FetchingData": "Прибавување на додатни податоци",
|
||||
"EnableStreamLoopingHelp": "Овозможете го ова ако преносите во живо содржат само неколку секунди податоци и треба постојано да се бараат. Овозможувањето на ова кога не е потребно може да предизвика проблеми.",
|
||||
"EnableThemeVideosHelp": "Пуштете ги тематските видеа во заднина додека ја прелистувате библиотеката.",
|
||||
"DrmChannelsNotImported": "Канали со DRM заштита нема да бидат внесени."
|
||||
}
|
||||
|
@ -1454,7 +1454,7 @@
|
||||
"AspectRatioCover": "Okładka",
|
||||
"EnableFallbackFontHelp": "Włącz niestandardowe czcionki. Może pozwolić uniknąć problemów przy renderowaniu napisów.",
|
||||
"EnableFallbackFont": "Włącz czcionki zastępcze",
|
||||
"LabelFallbackFontPathHelp": "Sprecyzuj ścieżkę zawierającą zastępcze czcionki dla renderowania napisów ASS/SSA. Maksymalny dozwolony łączny rozmiar czcionki to 20 MB. Lekkie i przyjazne dla sieci (web-friendly) formaty czcionek takie jak woff2 są zalecane.",
|
||||
"LabelFallbackFontPathHelp": "Czcionki te są używane przez niektóre klienty do renderowania napisów. Aby uzyskać więcej informacji, zapoznaj się z dokumentacją.",
|
||||
"LabelFallbackFontPath": "Ścieżka folderu czcionki zastępczej",
|
||||
"HeaderSelectFallbackFontPathHelp": "Wyszukaj lub podaj ścieżkę folderu czcionki zastępczej do użycia przy renderowaniu napisów ASS/SAA.",
|
||||
"HeaderSelectFallbackFontPath": "Wybierz ścieżkę folderu czcionki zastępczej",
|
||||
@ -1776,5 +1776,9 @@
|
||||
"UnknownError": "Wystąpił nieznany błąd.",
|
||||
"BackdropScreensaver": "Wygaszacz ekranu z fototapetami",
|
||||
"LogoScreensaver": "Wygaszacz ekranu z logo",
|
||||
"LabelIsHearingImpaired": "Dla osób niedosłyszących"
|
||||
"LabelIsHearingImpaired": "Dla osób niedosłyszących",
|
||||
"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."
|
||||
}
|
||||
|
@ -23,5 +23,7 @@
|
||||
"AllChannels": "සියලුම නාලිකා",
|
||||
"AllComplexFormats": "සියලුම සංකීර්ණ ආකෘති (ASS, SSA, VobSub, PGS, SUB, IDX, …)",
|
||||
"AllEpisodes": "සියලුම කථාංග",
|
||||
"AllowedRemoteAddressesHelp": "දුරස්ථව සම්බන්ධ වීමට ඉඩ දෙන ජාල සඳහා කොමාවෙන් වෙන් කළ IP ලිපින ලැයිස්තුව හෝ IP/netmask ඇතුළත් කිරීම්. හිස්ව තැබුවහොත්, සියලු දුරස්ථ ලිපිනවලට ඉඩ දෙනු ලැබේ."
|
||||
"AllowedRemoteAddressesHelp": "දුරස්ථව සම්බන්ධ වීමට ඉඩ දෙන ජාල සඳහා කොමාවෙන් වෙන් කළ IP ලිපින ලැයිස්තුව හෝ IP/netmask ඇතුළත් කිරීම්. හිස්ව තැබුවහොත්, සියලු දුරස්ථ ලිපිනවලට ඉඩ දෙනු ලැබේ.",
|
||||
"AllowSegmentDeletion": "මේ කොටස මකන්න",
|
||||
"AllowSegmentDeletionHelp": "client වෙත යැවීමෙන් පසු පැරණි කොටස් මකන්න. මෙය සම්පූර්ණ ට්රාන්ස්කෝඩ් ගොනුව තැටියේ ගබඩා කිරීම වළක්වයි. ක්රියා කරන්නේ තෙරපුම සක්රීය කර පමණි. ඔබ පසුධාවන ගැටළු අත්විඳින්නේ නම් මෙය අක්රිය කරන්න."
|
||||
}
|
||||
|
@ -1454,7 +1454,7 @@
|
||||
"AspectRatioFill": "Vyplniť",
|
||||
"EnableFallbackFontHelp": "Povoliť vlastné alternatívne fonty. Toto môže vyriešiť problémy s nesprávnym vykreslením titulkov.",
|
||||
"EnableFallbackFont": "Povoliť záložné fonty",
|
||||
"LabelFallbackFontPathHelp": "Špecifikuje cestu obsahujúcu záložné fonty pre vykreslenie ASS/SSA tituliek. Maximálna povolená veľkosť fontu je 20 MB. Doporučujeme používať malé a webovo-priateľské formy fontov ako napr. woff2.",
|
||||
"LabelFallbackFontPathHelp": "Tieto písma používajú niektorí klienti na vykresľovanie titulkov. Viac informácií nájdete v dokumentácii.",
|
||||
"LabelFallbackFontPath": "Cesta k priečinku záložných fontov",
|
||||
"HeaderSelectFallbackFontPathHelp": "Vyberte alebo zadajte cestu k priečinku záložných fontov pre vykreslenie ASS/SSA titulkov.",
|
||||
"HeaderSelectFallbackFontPath": "Vybrať cestu k priečinku záložných fontov",
|
||||
@ -1776,5 +1776,9 @@
|
||||
"LabelSegmentKeepSeconds": "Doba ponechania segmentov",
|
||||
"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 odoslaní klientovi. Tým sa zabráni tomu, aby sa celý prekódovaný súbor musel ukladať na disk. Funguje len so zapnutou funkciou Obmedziť prekódovanie. Ak sa vyskytnú problémy s prehrávaním, vypnite túto funkciu.",
|
||||
"LabelSegmentKeepSecondsHelp": "Čas v sekundách, počas ktorého budú segmenty uložené. Musí byť dlhší ako je čas určený v \"Obmedziť po\". Funguje len vtedy, ak je povolená funkcia Zmazania segmentov."
|
||||
"LabelSegmentKeepSecondsHelp": "Čas v sekundách, počas ktorého budú segmenty uložené. Musí byť dlhší ako je čas určený v \"Obmedziť po\". Funguje len vtedy, ak je povolená funkcia Zmazania 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.",
|
||||
"LabelAlbumGain": "Zosilnenie pre album",
|
||||
"LabelSelectAudioNormalization": "Normalizácia hlasitosti",
|
||||
"LabelTrackGain": "Zosilnenie stopy"
|
||||
}
|
||||
|
@ -981,7 +981,7 @@
|
||||
"PreferEmbeddedTitlesOverFileNames": "Dosya adları yerine gömülü başlıkları tercih et",
|
||||
"LabelSpecialSeasonsDisplayName": "Görünen özel sezon adı",
|
||||
"SpecialFeatures": "Özel Özellikler",
|
||||
"LabelFallbackFontPathHelp": "ASS/SSA altyazılarını oluşturmak için yedek yazı tiplerini içeren bir yol belirtin. İzin verilen maksimum toplam yazı tipi boyutu 20 MB'dir. Woff2 gibi hafif ve web dostu yazı tipi formatları önerilir.",
|
||||
"LabelFallbackFontPathHelp": "Bu yazı tipleri bazı istemciler tarafından altyazıları oluşturmak için kullanılır. Daha fazla bilgi için lütfen belgelere bakın.",
|
||||
"HeaderSelectFallbackFontPathHelp": "ASS/SSA altyazılarının işlenmesinde kullanılacak yedek yazı tipi klasörünün yoluna göz atın veya girin.",
|
||||
"TheseSettingsAffectSubtitlesOnThisDevice": "Bu ayarlar, bu cihazdaki altyazıları etkiler",
|
||||
"Subtitles": "Altyazılar",
|
||||
@ -1768,5 +1768,9 @@
|
||||
"AiTranslated": "AI Çevirisi",
|
||||
"MachineTranslated": "Makine Çevirisi",
|
||||
"ForeignPartsOnly": "Gömülü/Yalnız yabancı parçalar",
|
||||
"HearingImpairedShort": "HI/SDH"
|
||||
"HearingImpairedShort": "HI/SDH",
|
||||
"SelectAudioNormalizationHelp": "Parça ses kazancı - her parçanın ses seviyesini, aynı ses yüksekliğinde çalınacak şekilde ayarlar. Albüm ses kazancı - albümün dinamik aralığını koruyarak yalnızca bir albümdeki tüm parçaların ses düzeyini ayarlar.",
|
||||
"LabelSelectAudioNormalization": "Ses Normalleştirme",
|
||||
"LabelAlbumGain": "Albüm Ses Kazancı",
|
||||
"LabelTrackGain": "Parça Ses Kazancı"
|
||||
}
|
||||
|
@ -640,7 +640,7 @@
|
||||
"AllowHevcEncoding": "Дозволити кодування у форматі HEVC",
|
||||
"PreferFmp4HlsContainerHelp": "Віддавайте перевагу використанню fMP4 як контейнера за умовчанням для HLS, що дає змогу направляти потоковий вміст HEVC на підтримувані пристрої.",
|
||||
"RemuxHelp1": "Носій даних знаходиться у несумісному контейнері файлів (MKV, AVI, WMV тощо), але і відеопотік, і аудіопотік сумісні з пристроєм. Носії будуть перепаковані без втрат на льоту перед надсиланням на пристрій.",
|
||||
"LabelFallbackFontPathHelp": "Вкажіть шлях, що містить резервні шрифти для відображення субтитрів ASS/SSA. Максимально допустимий загальний розмір шрифту - 20 МБ. Рекомендуються легкі та зручні для Інтернету формати шрифтів, такі як woff2.",
|
||||
"LabelFallbackFontPathHelp": "Ці шрифти використовуються деякими клієнтами для відтворення субтитрів. Будь ласка, зверніться до документації для отримання додаткової інформації.",
|
||||
"XmlTvPathHelp": "Шлях до файлу XMLTV. Jellyfin прочитає цей файл і періодично перевірятиме його на наявність оновлень. Ви несете відповідальність за створення та оновлення файлу.",
|
||||
"WriteAccessRequired": "Jellyfin вимагає доступу до запису в цю папку. Будь ласка, забезпечте доступ до запису та повторіть спробу.",
|
||||
"Watched": "Переглянуто",
|
||||
@ -1652,7 +1652,7 @@
|
||||
"HomeVideosPhotos": "Домашні відео та фото",
|
||||
"EnableSplashScreen": "Увімкнути заставку",
|
||||
"ScreenResolution": "Роздільна здатність екрану",
|
||||
"RememberSubtitleSelectionsHelp": "Спробувати обрати дорожку субтитрів, яка найбільше відповідає попередньому відео.",
|
||||
"RememberSubtitleSelectionsHelp": "Спробувати обрати доріжку субтитрів, яка найбільше відповідає попередньому відео.",
|
||||
"RememberSubtitleSelections": "Обрати дорожку субтитрів засновуючись на попередньому елементі",
|
||||
"RememberAudioSelectionsHelp": "Спробувати обрати звукову доріжку, яка найбільше відповідає попередньому відео.",
|
||||
"RememberAudioSelections": "Обрати звукову доріжку засновуючись на попередньому елементі",
|
||||
@ -1773,5 +1773,9 @@
|
||||
"GoHome": "На головну",
|
||||
"BackdropScreensaver": "Фонова заставка",
|
||||
"LogoScreensaver": "Заставка з логотипом",
|
||||
"LabelIsHearingImpaired": "Для людей з вадами слуху (SDH)"
|
||||
"LabelIsHearingImpaired": "Для людей з вадами слуху (SDH)",
|
||||
"SelectAudioNormalizationHelp": "Посилення треку - регулює гучність кожного треку так, щоб вони відтворювалися з однаковою гучністю. Посилення альбому - регулює гучність лише всіх треків в альбомі, зберігаючи динамічний діапазон альбому.",
|
||||
"LabelAlbumGain": "Посилення альбому",
|
||||
"LabelSelectAudioNormalization": "Нормалізація звуку",
|
||||
"LabelTrackGain": "Посилення треку"
|
||||
}
|
||||
|
@ -1429,7 +1429,7 @@
|
||||
"DeleteAll": "Xóa Hết",
|
||||
"EnableFallbackFontHelp": "Bật phông chữ thay thế tùy chỉnh. Điều này có thể tránh sự cố hiển thị phụ đề không chính xác.",
|
||||
"EnableFallbackFont": "Bật phông chữ dự phòng",
|
||||
"LabelFallbackFontPathHelp": "Chỉ định đường dẫn chứa phông chữ dự phòng để hiển thị phụ đề ASS / SSA. Tổng kích thước phông chữ tối đa được phép là 20 MB. Các định dạng phông chữ nhẹ và thân thiện với web như woff2 được khuyến khích.",
|
||||
"LabelFallbackFontPathHelp": "Những phông chữ này được một số máy khách sử dụng để hiển thị phụ đề. Vui lòng tham khảo tài liệu để biết thêm thông tin.",
|
||||
"LabelFallbackFontPath": "Đường dẫn thư mục phông chữ dự phòng",
|
||||
"HeaderSelectFallbackFontPathHelp": "Duyệt hoặc nhập đường dẫn của thư mục phông chữ dự phòng dùng để hiển thị phụ đề ASS/SSA.",
|
||||
"HeaderSelectFallbackFontPath": "Chọn Đường dẫn Thư mục Phông chữ Dự phòng",
|
||||
@ -1757,5 +1757,6 @@
|
||||
"HeaderGuestCast": "Ngôi Sao Khách Mời",
|
||||
"GoHome": "Về Trang Chủ",
|
||||
"AiTranslated": "Được AI Dịch",
|
||||
"MachineTranslated": "Được Máy Dịch"
|
||||
"MachineTranslated": "Được Máy Dịch",
|
||||
"LabelSelectAudioNormalization": "Chuẩn Hóa Âm Thanh"
|
||||
}
|
||||
|
@ -16,6 +16,8 @@ progress {
|
||||
appearance: none;
|
||||
margin: 0;
|
||||
background: #ccc !important;
|
||||
border-radius: 0.2em;
|
||||
border: none;
|
||||
}
|
||||
|
||||
progress[role]::after {
|
||||
|
@ -1,7 +1,10 @@
|
||||
import type { DeviceInfo } from '@jellyfin/sdk/lib/generated-client/models/device-info';
|
||||
import type { SessionInfo } from '@jellyfin/sdk/lib/generated-client/models/session-info';
|
||||
|
||||
const BASE_DEVICE_IMAGE_URL = 'assets/img/devices/';
|
||||
|
||||
// audit note: this module is expected to return safe text for use in HTML
|
||||
function getWebDeviceIcon(browser) {
|
||||
function getWebDeviceIcon(browser: string | null | undefined) {
|
||||
switch (browser) {
|
||||
case 'Opera':
|
||||
case 'Opera TV':
|
||||
@ -31,8 +34,8 @@ function getWebDeviceIcon(browser) {
|
||||
}
|
||||
}
|
||||
|
||||
export function getDeviceIcon(device) {
|
||||
switch (device.AppName || device.Client) {
|
||||
export function getDeviceIcon(info: DeviceInfo | SessionInfo) {
|
||||
switch ((info as DeviceInfo).AppName || (info as SessionInfo).Client) {
|
||||
case 'Samsung Smart TV':
|
||||
return BASE_DEVICE_IMAGE_URL + 'samsung.svg';
|
||||
case 'Xbox One':
|
||||
@ -58,13 +61,20 @@ export function getDeviceIcon(device) {
|
||||
case 'Finamp':
|
||||
return BASE_DEVICE_IMAGE_URL + 'finamp.svg';
|
||||
case 'Jellyfin Web':
|
||||
return getWebDeviceIcon(device.Name || device.DeviceName);
|
||||
return getWebDeviceIcon((info as DeviceInfo).Name || (info as SessionInfo).DeviceName);
|
||||
default:
|
||||
if (info.Capabilities?.IconUrl) {
|
||||
try {
|
||||
return new URL(info.Capabilities.IconUrl).toString();
|
||||
} catch (err) {
|
||||
console.error('[getDeviceIcon] device capabilities has invalid IconUrl', info, err);
|
||||
}
|
||||
}
|
||||
return BASE_DEVICE_IMAGE_URL + 'other.svg';
|
||||
}
|
||||
}
|
||||
|
||||
export function getLibraryIcon(library) {
|
||||
export function getLibraryIcon(library: string | null | undefined) {
|
||||
switch (library) {
|
||||
case 'movies':
|
||||
return 'video_library';
|
||||
@ -94,6 +104,6 @@ export function getLibraryIcon(library) {
|
||||
}
|
||||
|
||||
export default {
|
||||
getDeviceIcon: getDeviceIcon,
|
||||
getLibraryIcon: getLibraryIcon
|
||||
getDeviceIcon,
|
||||
getLibraryIcon
|
||||
};
|
Loading…
x
Reference in New Issue
Block a user