Merge branch 'master' into fix_jellyfin_sdk_type_errors
# Conflicts: # package-lock.json
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
{
|
||||
"name": "Node.js",
|
||||
// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
|
||||
"image": "mcr.microsoft.com/devcontainers/javascript-node:1-20-bullseye",
|
||||
"image": "mcr.microsoft.com/devcontainers/javascript-node:24-bookworm",
|
||||
|
||||
// Features to add to the dev container. More info: https://containers.dev/features.
|
||||
// "features": {},
|
||||
@@ -13,7 +13,7 @@
|
||||
|
||||
// Use 'postCreateCommand' to run commands after the container is created.
|
||||
//https://github.com/microsoft/vscode-dev-containers/issues/559
|
||||
"postCreateCommand": "source $NVM_DIR/nvm.sh && nvm install 20"
|
||||
"postCreateCommand": "source $NVM_DIR/nvm.sh && nvm install 24"
|
||||
|
||||
// Configure tool-specific properties.
|
||||
// "customizations": {},
|
||||
|
||||
@@ -19,9 +19,9 @@ jobs:
|
||||
ref: ${{ inputs.commit || github.sha }}
|
||||
|
||||
- name: Setup node environment
|
||||
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
||||
uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0
|
||||
with:
|
||||
node-version: 20
|
||||
node-version-file: .nvmrc
|
||||
cache: npm
|
||||
check-latest: true
|
||||
|
||||
|
||||
@@ -48,9 +48,9 @@ jobs:
|
||||
show-progress: false
|
||||
|
||||
- name: Setup node environment ⚙️
|
||||
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
||||
uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0
|
||||
with:
|
||||
node-version: 20
|
||||
node-version-file: .nvmrc
|
||||
cache: npm
|
||||
check-latest: true
|
||||
|
||||
|
||||
@@ -85,9 +85,9 @@ jobs:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
|
||||
- name: Setup node environment
|
||||
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
||||
uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0
|
||||
with:
|
||||
node-version: 20
|
||||
node-version-file: .nvmrc
|
||||
cache: npm
|
||||
check-latest: true
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
devShell = with pkgs;
|
||||
mkShell rec {
|
||||
buildInputs = [
|
||||
nodejs_20
|
||||
nodejs_24
|
||||
];
|
||||
|
||||
shellHook = ''
|
||||
|
||||
Generated
+8
-16374
File diff suppressed because it is too large
Load Diff
+2
-2
@@ -168,8 +168,8 @@
|
||||
"stylelint": "stylelint \"src/**/*.{css,scss}\""
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20.0.0",
|
||||
"npm": ">=9.6.4 <11.0.0",
|
||||
"node": ">=24.0.0",
|
||||
"npm": ">=11.0.0",
|
||||
"yarn": "YARN NO LONGER USED - use npm instead."
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,164 +98,166 @@ export const Component = () => {
|
||||
className='type-interior mainAnimatedPage'
|
||||
>
|
||||
<Box className='content-primary'>
|
||||
{isError ? (
|
||||
<Alert
|
||||
severity='error'
|
||||
sx={{ marginBottom: 2 }}
|
||||
<Stack spacing={2}>
|
||||
<Stack
|
||||
direction='row'
|
||||
sx={{
|
||||
flexWrap: {
|
||||
xs: 'wrap',
|
||||
sm: 'nowrap'
|
||||
}
|
||||
}}
|
||||
>
|
||||
{globalize.translate('PluginsLoadError')}
|
||||
</Alert>
|
||||
) : (
|
||||
<Stack spacing={2}>
|
||||
<Stack
|
||||
direction='row'
|
||||
<Typography
|
||||
variant='h1'
|
||||
component='span'
|
||||
sx={{
|
||||
flexWrap: {
|
||||
xs: 'wrap',
|
||||
sm: 'nowrap'
|
||||
flexGrow: 1,
|
||||
verticalAlign: 'middle'
|
||||
}}
|
||||
>
|
||||
{globalize.translate('TabPlugins')}
|
||||
</Typography>
|
||||
|
||||
<Button
|
||||
component={Link}
|
||||
to='/dashboard/plugins/repositories'
|
||||
variant='outlined'
|
||||
sx={{
|
||||
marginLeft: 2
|
||||
}}
|
||||
>
|
||||
{globalize.translate('ManageRepositories')}
|
||||
</Button>
|
||||
|
||||
<Box
|
||||
sx={{
|
||||
display: 'flex',
|
||||
justifyContent: 'end',
|
||||
marginTop: {
|
||||
xs: 2,
|
||||
sm: 0
|
||||
},
|
||||
marginLeft: {
|
||||
xs: 0,
|
||||
sm: 2
|
||||
},
|
||||
width: {
|
||||
xs: '100%',
|
||||
sm: 'auto'
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Typography
|
||||
variant='h1'
|
||||
component='span'
|
||||
sx={{
|
||||
flexGrow: 1,
|
||||
verticalAlign: 'middle'
|
||||
}}
|
||||
>
|
||||
{globalize.translate('TabPlugins')}
|
||||
</Typography>
|
||||
|
||||
<Button
|
||||
component={Link}
|
||||
to='/dashboard/plugins/repositories'
|
||||
variant='outlined'
|
||||
sx={{
|
||||
marginLeft: 2
|
||||
}}
|
||||
>
|
||||
{globalize.translate('ManageRepositories')}
|
||||
</Button>
|
||||
|
||||
<Box
|
||||
sx={{
|
||||
display: 'flex',
|
||||
justifyContent: 'end',
|
||||
marginTop: {
|
||||
xs: 2,
|
||||
sm: 0
|
||||
},
|
||||
marginLeft: {
|
||||
xs: 0,
|
||||
sm: 2
|
||||
},
|
||||
width: {
|
||||
xs: '100%',
|
||||
sm: 'auto'
|
||||
}
|
||||
}}
|
||||
>
|
||||
<SearchInput
|
||||
label={globalize.translate('Search')}
|
||||
value={searchQuery}
|
||||
onChange={onSearchChange}
|
||||
/>
|
||||
</Box>
|
||||
</Stack>
|
||||
|
||||
<Box>
|
||||
<Stack
|
||||
direction='row'
|
||||
spacing={1}
|
||||
sx={{
|
||||
marginLeft: '-1rem',
|
||||
marginRight: '-1rem',
|
||||
paddingLeft: '1rem',
|
||||
paddingRight: '1rem',
|
||||
paddingBottom: {
|
||||
xs: 1,
|
||||
md: 0.5
|
||||
},
|
||||
overflowX: 'auto'
|
||||
}}
|
||||
>
|
||||
<Chip
|
||||
color={status === PluginStatusOption.All ? 'primary' : undefined}
|
||||
// eslint-disable-next-line react/jsx-no-bind
|
||||
onClick={() => setStatus(PluginStatusOption.All)}
|
||||
label={globalize.translate('All')}
|
||||
/>
|
||||
|
||||
<Chip
|
||||
color={status === PluginStatusOption.Available ? 'primary' : undefined}
|
||||
// eslint-disable-next-line react/jsx-no-bind
|
||||
onClick={() => setStatus(PluginStatusOption.Available)}
|
||||
label={globalize.translate('LabelAvailable')}
|
||||
/>
|
||||
|
||||
<Chip
|
||||
color={status === PluginStatusOption.Installed ? 'primary' : undefined}
|
||||
// eslint-disable-next-line react/jsx-no-bind
|
||||
onClick={() => setStatus(PluginStatusOption.Installed)}
|
||||
label={globalize.translate('LabelInstalled')}
|
||||
/>
|
||||
|
||||
<Divider orientation='vertical' flexItem />
|
||||
|
||||
<Chip
|
||||
color={!category ? 'primary' : undefined}
|
||||
// eslint-disable-next-line react/jsx-no-bind
|
||||
onClick={() => setCategory('')}
|
||||
label={globalize.translate('All')}
|
||||
/>
|
||||
|
||||
{Object.values(PluginCategory).map(c => (
|
||||
<Chip
|
||||
key={c}
|
||||
color={category === c.toLowerCase() ? 'primary' : undefined}
|
||||
// eslint-disable-next-line react/jsx-no-bind
|
||||
onClick={() => setCategory(c.toLowerCase())}
|
||||
label={globalize.translate(CATEGORY_LABELS[c as PluginCategory])}
|
||||
/>
|
||||
))}
|
||||
</Stack>
|
||||
<Divider />
|
||||
</Box>
|
||||
|
||||
<Box>
|
||||
{filteredPlugins.length > 0 ? (
|
||||
// NOTE: Legacy Grid is required due to lack of gap support in JMP on some OSs
|
||||
// eslint-disable-next-line @typescript-eslint/no-deprecated
|
||||
<Grid container spacing={2}>
|
||||
{filteredPlugins.map(plugin => (
|
||||
// NOTE: Legacy Grid is required due to lack of gap support in JMP on some OSs
|
||||
// eslint-disable-next-line @typescript-eslint/no-deprecated
|
||||
<Grid
|
||||
key={plugin.id}
|
||||
item
|
||||
xs={12}
|
||||
sm={6}
|
||||
md={4}
|
||||
lg={3}
|
||||
xl={2}
|
||||
>
|
||||
<PluginCard
|
||||
plugin={plugin}
|
||||
/>
|
||||
</Grid>
|
||||
))}
|
||||
</Grid>
|
||||
) : (
|
||||
<NoPluginResults
|
||||
isFiltered={!!category || status !== PluginStatusOption.All}
|
||||
onViewAll={onViewAll}
|
||||
query={searchQuery}
|
||||
/>
|
||||
)}
|
||||
<SearchInput
|
||||
label={globalize.translate('Search')}
|
||||
value={searchQuery}
|
||||
onChange={onSearchChange}
|
||||
/>
|
||||
</Box>
|
||||
</Stack>
|
||||
)}
|
||||
|
||||
{isError ? (
|
||||
<Alert
|
||||
severity='error'
|
||||
sx={{ marginBottom: 2 }}
|
||||
>
|
||||
{globalize.translate('PluginsLoadError')}
|
||||
</Alert>
|
||||
) : (
|
||||
<>
|
||||
<Box>
|
||||
<Stack
|
||||
direction='row'
|
||||
spacing={1}
|
||||
sx={{
|
||||
marginLeft: '-1rem',
|
||||
marginRight: '-1rem',
|
||||
paddingLeft: '1rem',
|
||||
paddingRight: '1rem',
|
||||
paddingBottom: {
|
||||
xs: 1,
|
||||
md: 0.5
|
||||
},
|
||||
overflowX: 'auto'
|
||||
}}
|
||||
>
|
||||
<Chip
|
||||
color={status === PluginStatusOption.All ? 'primary' : undefined}
|
||||
// eslint-disable-next-line react/jsx-no-bind
|
||||
onClick={() => setStatus(PluginStatusOption.All)}
|
||||
label={globalize.translate('All')}
|
||||
/>
|
||||
|
||||
<Chip
|
||||
color={status === PluginStatusOption.Available ? 'primary' : undefined}
|
||||
// eslint-disable-next-line react/jsx-no-bind
|
||||
onClick={() => setStatus(PluginStatusOption.Available)}
|
||||
label={globalize.translate('LabelAvailable')}
|
||||
/>
|
||||
|
||||
<Chip
|
||||
color={status === PluginStatusOption.Installed ? 'primary' : undefined}
|
||||
// eslint-disable-next-line react/jsx-no-bind
|
||||
onClick={() => setStatus(PluginStatusOption.Installed)}
|
||||
label={globalize.translate('LabelInstalled')}
|
||||
/>
|
||||
|
||||
<Divider orientation='vertical' flexItem />
|
||||
|
||||
<Chip
|
||||
color={!category ? 'primary' : undefined}
|
||||
// eslint-disable-next-line react/jsx-no-bind
|
||||
onClick={() => setCategory('')}
|
||||
label={globalize.translate('All')}
|
||||
/>
|
||||
|
||||
{Object.values(PluginCategory).map(c => (
|
||||
<Chip
|
||||
key={c}
|
||||
color={category === c.toLowerCase() ? 'primary' : undefined}
|
||||
// eslint-disable-next-line react/jsx-no-bind
|
||||
onClick={() => setCategory(c.toLowerCase())}
|
||||
label={globalize.translate(CATEGORY_LABELS[c as PluginCategory])}
|
||||
/>
|
||||
))}
|
||||
</Stack>
|
||||
<Divider />
|
||||
</Box>
|
||||
|
||||
<Box>
|
||||
{filteredPlugins.length > 0 ? (
|
||||
// NOTE: Legacy Grid is required due to lack of gap support in JMP on some OSs
|
||||
// eslint-disable-next-line @typescript-eslint/no-deprecated
|
||||
<Grid container spacing={2}>
|
||||
{filteredPlugins.map(plugin => (
|
||||
// NOTE: Legacy Grid is required due to lack of gap support in JMP on some OSs
|
||||
// eslint-disable-next-line @typescript-eslint/no-deprecated
|
||||
<Grid
|
||||
key={plugin.id}
|
||||
item
|
||||
xs={12}
|
||||
sm={6}
|
||||
md={4}
|
||||
lg={3}
|
||||
xl={2}
|
||||
>
|
||||
<PluginCard
|
||||
plugin={plugin}
|
||||
/>
|
||||
</Grid>
|
||||
))}
|
||||
</Grid>
|
||||
) : (
|
||||
<NoPluginResults
|
||||
isFiltered={!!category || status !== PluginStatusOption.All}
|
||||
onViewAll={onViewAll}
|
||||
query={searchQuery}
|
||||
/>
|
||||
)}
|
||||
</Box>
|
||||
</>
|
||||
)}
|
||||
</Stack>
|
||||
</Box>
|
||||
</Page>
|
||||
);
|
||||
|
||||
@@ -2,6 +2,7 @@ import Stack from '@mui/material/Stack';
|
||||
import React, { type FC } from 'react';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
|
||||
import { appRouter, PUBLIC_PATHS } from 'components/router/appRouter';
|
||||
import AppToolbar from 'components/toolbar/AppToolbar';
|
||||
import ServerButton from 'components/toolbar/ServerButton';
|
||||
|
||||
@@ -16,14 +17,6 @@ interface AppToolbarProps {
|
||||
onDrawerButtonClick: (event: React.MouseEvent<HTMLElement>) => void
|
||||
}
|
||||
|
||||
const PUBLIC_PATHS = [
|
||||
'/addserver',
|
||||
'/selectserver',
|
||||
'/login',
|
||||
'/forgotpassword',
|
||||
'/forgotpasswordpin'
|
||||
];
|
||||
|
||||
const ExperimentalAppToolbar: FC<AppToolbarProps> = ({
|
||||
isDrawerAvailable,
|
||||
isDrawerOpen,
|
||||
@@ -34,6 +27,10 @@ const ExperimentalAppToolbar: FC<AppToolbarProps> = ({
|
||||
// The video osd does not show the standard toolbar
|
||||
if (location.pathname === '/video') return null;
|
||||
|
||||
// Only show the back button in apps when appropriate
|
||||
const isBackButtonAvailable = window.NativeShell && appRouter.canGoBack(location.pathname);
|
||||
|
||||
// Check if the current path is a public path to hide user content
|
||||
const isPublicPath = PUBLIC_PATHS.includes(location.pathname);
|
||||
|
||||
return (
|
||||
@@ -48,6 +45,7 @@ const ExperimentalAppToolbar: FC<AppToolbarProps> = ({
|
||||
isDrawerAvailable={isDrawerAvailable}
|
||||
isDrawerOpen={isDrawerOpen}
|
||||
onDrawerButtonClick={onDrawerButtonClick}
|
||||
isBackButtonAvailable={isBackButtonAvailable}
|
||||
isUserMenuAvailable={!isPublicPath}
|
||||
>
|
||||
{!isDrawerAvailable && (
|
||||
|
||||
@@ -222,9 +222,7 @@ const ItemsView: FC<ItemsViewProps> = ({
|
||||
const hasFilters = Object.values(libraryViewSettings.Filters ?? {}).some(
|
||||
(filter) => !!filter
|
||||
);
|
||||
const hasSortName = libraryViewSettings.SortBy.includes(
|
||||
ItemSortBy.SortName
|
||||
);
|
||||
const hasSortName = libraryViewSettings.SortBy !== ItemSortBy.Random;
|
||||
|
||||
const itemsContainerClass = classNames(
|
||||
'padded-left padded-right padded-right-withalphapicker',
|
||||
|
||||
@@ -22,6 +22,14 @@ type SortOption = {
|
||||
|
||||
type SortOptionsMapping = Record<string, SortOption[]>;
|
||||
|
||||
const collectionMovieOptions: SortOption[] = [
|
||||
{ label: 'Name', value: ItemSortBy.SortName },
|
||||
{ label: 'OptionCommunityRating', value: ItemSortBy.CommunityRating },
|
||||
{ label: 'OptionDateAdded', value: ItemSortBy.DateCreated },
|
||||
{ label: 'OptionParentalRating', value: ItemSortBy.OfficialRating },
|
||||
{ label: 'OptionReleaseDate', value: ItemSortBy.PremiereDate }
|
||||
];
|
||||
|
||||
const movieOrFavoriteOptions = [
|
||||
{ label: 'Name', value: ItemSortBy.SortName },
|
||||
{ label: 'OptionRandom', value: ItemSortBy.Random },
|
||||
@@ -43,6 +51,7 @@ const photosOrPhotoAlbumsOptions = [
|
||||
|
||||
const sortOptionsMapping: SortOptionsMapping = {
|
||||
[LibraryTab.Movies]: movieOrFavoriteOptions,
|
||||
[LibraryTab.Collections]: collectionMovieOptions,
|
||||
[LibraryTab.Favorites]: movieOrFavoriteOptions,
|
||||
[LibraryTab.Series]: [
|
||||
{ label: 'Name', value: ItemSortBy.SortName },
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Amazon Fire TV</title><path d="M20.196 15.12c.265.337-.294 1.73-.542 2.353-.077.19.085.266.257.123 1.106-.926 1.39-2.867 1.166-3.149-.226-.277-2.16-.516-3.341.314-.183.127-.151.304.05.279.665-.08 2.147-.257 2.41.08m-.858.981c-2.064 1.523-5.056 2.333-7.632 2.333-3.611 0-6.862-1.334-9.322-3.555-.194-.176-.02-.414.21-.28 2.655 1.545 5.939 2.477 9.328 2.477 2.287 0 4.803-.476 7.115-1.458.348-.147.642.231.3.483m2.034-3.155a.388.388 0 0 1-.201-.04c-.041-.026-.087-.1-.133-.225l-1.734-4.355a1.79 1.79 0 0 0-.046-.117.266.266 0 0 1-.023-.108c0-.084.049-.128.146-.128h.58c.098 0 .165.014.205.04.04.026.082.102.127.226l1.344 3.823 1.343-3.823c.046-.124.089-.2.128-.226a.402.402 0 0 1 .205-.04h.54c.1 0 .148.044.148.128a.3.3 0 0 1-.025.108c-.016.04-.032.078-.044.117l-1.727 4.355c-.045.124-.09.199-.132.225a.388.388 0 0 1-.201.04zm-3.644.068c-.929 0-1.392-.463-1.392-1.392V8.739h-.706c-.13 0-.197-.066-.197-.196v-.246a.22.22 0 0 1 .045-.147c.03-.031.086-.055.171-.067l.717-.09.127-1.215c.013-.13.082-.196.207-.196h.41c.13 0 .196.066.196.196v1.196h1.276c.13 0 .195.065.195.197v.372c0 .13-.064.196-.195.196h-1.276v2.834c0 .243.055.411.162.51.108.098.293.147.555.147.124 0 .277-.016.46-.049.099-.02.164-.03.197-.03.052 0 .088.014.108.044.02.03.029.077.029.142v.266a.366.366 0 0 1-.04.19c-.026.043-.078.078-.157.103a3.018 3.018 0 0 1-.892.118m-4.665-2.976c.006-.052.011-.137.011-.255 0-.399-.094-.698-.28-.901-.186-.204-.46-.306-.818-.306-.412 0-.732.123-.962.369-.228.245-.36.61-.392 1.093zm-.942 3.07c-.803 0-1.411-.222-1.824-.667-.412-.444-.616-1.102-.616-1.972 0-.83.204-1.475.616-1.937.413-.46.988-.691 1.728-.691.62 0 1.098.176 1.432.524.332.351.5.846.5 1.487 0 .21-.017.422-.05.638-.014.077-.034.13-.064.156-.029.027-.077.04-.142.04h-3.08c.013.563.154.977.418 1.245.265.268.674.403 1.23.403.196 0 .385-.014.564-.04a5.04 5.04 0 0 0 .682-.166l.117-.035a.284.284 0 0 1 .09-.016c.085 0 .125.06.125.177v.276c0 .085-.012.144-.037.18a.441.441 0 0 1-.167.114 3.38 3.38 0 0 1-.701.205 4.236 4.236 0 0 1-.82.079m-5.424-.147c-.13 0-.195-.066-.195-.197v-4.58c0-.13.064-.195.195-.195h.432c.064 0 .116.012.153.039.036.025.06.076.072.146l.07.55c.176-.19.343-.34.499-.452a1.725 1.725 0 0 1 1.02-.323c.079 0 .158.003.235.01.112.014.168.072.168.176v.53c0 .117-.058.177-.178.177-.058 0-.114-.004-.17-.01a1.638 1.638 0 0 0-.18-.01c-.524 0-.973.157-1.346.47v3.472c0 .131-.066.197-.195.197zm-2.249 0c-.13 0-.196-.066-.196-.197v-4.58c0-.13.066-.195.196-.195h.579c.13 0 .195.064.195.195v4.58c0 .131-.065.197-.195.197zm.295-5.856c-.19 0-.339-.054-.447-.16a.581.581 0 0 1-.161-.428c0-.176.054-.318.16-.426.11-.109.257-.163.448-.163.189 0 .337.054.446.163.107.108.16.25.16.426a.581.581 0 0 1-.16.427.608.608 0 0 1-.446.161m-3.625 5.856c-.132 0-.197-.066-.197-.197v-4.01H.195c-.13 0-.195-.066-.195-.197v-.245c0-.065.014-.114.043-.147.03-.033.088-.055.173-.07l.705-.087v-.804c0-1.091.523-1.638 1.57-1.638.248 0 .51.036.784.109.072.019.122.047.152.088.029.038.044.107.044.205v.255c0 .124-.048.186-.148.186-.058 0-.14-.01-.248-.029-.11-.02-.23-.03-.369-.03-.3 0-.51.057-.633.172-.121.115-.181.303-.181.564v.903h1.324c.131 0 .197.064.197.195v.373c0 .13-.066.197-.197.197H1.892v4.01c0 .131-.065.197-.196.197Z" fill="#fff"/></svg>
|
||||
|
After Width: | Height: | Size: 3.2 KiB |
@@ -14,6 +14,7 @@ const BrowserName = {
|
||||
tizen: 'Samsung Smart TV',
|
||||
web0s: 'LG Smart TV',
|
||||
titanos: 'Titan OS',
|
||||
vega: 'Vega OS',
|
||||
operaTv: 'Opera TV',
|
||||
xboxOne: 'Xbox One',
|
||||
ps4: 'Sony PS4',
|
||||
|
||||
@@ -578,9 +578,10 @@ function getCardFooterText(item, apiClient, options, footerClass, progressHtml,
|
||||
if (flags.isOuterFooter && item.AlbumArtists?.length) {
|
||||
const artistText = item.AlbumArtists
|
||||
.map(artist => {
|
||||
artist.ServerId = serverId;
|
||||
artist.Type = BaseItemKind.MusicArtist;
|
||||
artist.IsFolder = true;
|
||||
return getTextActionButton(artist, null, serverId);
|
||||
return getTextActionButton(artist);
|
||||
})
|
||||
.join(' / ');
|
||||
lines.push(artistText);
|
||||
|
||||
@@ -17,7 +17,7 @@ import { history } from 'RootAppRouter';
|
||||
const START_PAGE_PATHS = ['/home', '/login', '/selectserver'];
|
||||
|
||||
/** Pages that do not require a user to be logged in to view. */
|
||||
const PUBLIC_PATHS = [
|
||||
export const PUBLIC_PATHS = [
|
||||
'/addserver',
|
||||
'/selectserver',
|
||||
'/login',
|
||||
@@ -122,9 +122,7 @@ class AppRouter {
|
||||
return this.baseRoute;
|
||||
}
|
||||
|
||||
canGoBack() {
|
||||
const path = history.location.pathname;
|
||||
|
||||
canGoBack(path = history.location.pathname) {
|
||||
if (
|
||||
!document.querySelector('.dialogContainer')
|
||||
&& START_PAGE_PATHS.includes(path)
|
||||
@@ -262,15 +260,15 @@ class AppRouter {
|
||||
}
|
||||
|
||||
if (item === 'recordedtv') {
|
||||
return '#/livetv?tab=3&serverId=' + options.serverId;
|
||||
return '#/livetv?tab=3&serverId=' + serverId;
|
||||
}
|
||||
|
||||
if (item === 'nextup') {
|
||||
return '#/list?type=nextup&serverId=' + options.serverId;
|
||||
return '#/list?type=nextup&serverId=' + serverId;
|
||||
}
|
||||
|
||||
if (item === 'list') {
|
||||
let urlForList = '#/list?serverId=' + options.serverId + '&type=' + options.itemTypes;
|
||||
let urlForList = '#/list?serverId=' + serverId + '&type=' + options.itemTypes;
|
||||
|
||||
if (options.isFavorite) {
|
||||
urlForList += '&IsFavorite=true';
|
||||
@@ -305,49 +303,49 @@ class AppRouter {
|
||||
|
||||
if (item === 'livetv') {
|
||||
if (options.section === 'programs') {
|
||||
return '#/livetv?tab=0&serverId=' + options.serverId;
|
||||
return '#/livetv?tab=0&serverId=' + serverId;
|
||||
}
|
||||
if (options.section === 'guide') {
|
||||
return '#/livetv?tab=1&serverId=' + options.serverId;
|
||||
return '#/livetv?tab=1&serverId=' + serverId;
|
||||
}
|
||||
|
||||
if (options.section === 'movies') {
|
||||
return '#/list?type=Programs&IsMovie=true&serverId=' + options.serverId;
|
||||
return '#/list?type=Programs&IsMovie=true&serverId=' + serverId;
|
||||
}
|
||||
|
||||
if (options.section === 'shows') {
|
||||
return '#/list?type=Programs&IsSeries=true&IsMovie=false&IsNews=false&serverId=' + options.serverId;
|
||||
return '#/list?type=Programs&IsSeries=true&IsMovie=false&IsNews=false&serverId=' + serverId;
|
||||
}
|
||||
|
||||
if (options.section === 'sports') {
|
||||
return '#/list?type=Programs&IsSports=true&serverId=' + options.serverId;
|
||||
return '#/list?type=Programs&IsSports=true&serverId=' + serverId;
|
||||
}
|
||||
|
||||
if (options.section === 'kids') {
|
||||
return '#/list?type=Programs&IsKids=true&serverId=' + options.serverId;
|
||||
return '#/list?type=Programs&IsKids=true&serverId=' + serverId;
|
||||
}
|
||||
|
||||
if (options.section === 'news') {
|
||||
return '#/list?type=Programs&IsNews=true&serverId=' + options.serverId;
|
||||
return '#/list?type=Programs&IsNews=true&serverId=' + serverId;
|
||||
}
|
||||
|
||||
if (options.section === 'onnow') {
|
||||
return '#/list?type=Programs&IsAiring=true&serverId=' + options.serverId;
|
||||
return '#/list?type=Programs&IsAiring=true&serverId=' + serverId;
|
||||
}
|
||||
|
||||
if (options.section === 'channels') {
|
||||
return '#/livetv?tab=2&serverId=' + options.serverId;
|
||||
return '#/livetv?tab=2&serverId=' + serverId;
|
||||
}
|
||||
|
||||
if (options.section === 'dvrschedule') {
|
||||
return '#/livetv?tab=4&serverId=' + options.serverId;
|
||||
return '#/livetv?tab=4&serverId=' + serverId;
|
||||
}
|
||||
|
||||
if (options.section === 'seriesrecording') {
|
||||
return '#/livetv?tab=5&serverId=' + options.serverId;
|
||||
return '#/livetv?tab=5&serverId=' + serverId;
|
||||
}
|
||||
|
||||
return '#/livetv?serverId=' + options.serverId;
|
||||
return '#/livetv?serverId=' + serverId;
|
||||
}
|
||||
|
||||
if (itemType == 'SeriesTimer') {
|
||||
|
||||
Vendored
+1
@@ -21,6 +21,7 @@ declare namespace browser {
|
||||
export let animate: boolean;
|
||||
export let hisense: boolean;
|
||||
export let tizen: boolean;
|
||||
export let vega: boolean;
|
||||
export let vidaa: boolean;
|
||||
export let web0s: boolean;
|
||||
export let titanos: boolean;
|
||||
|
||||
+12
-5
@@ -235,10 +235,10 @@ const uaMatch = function (ua) {
|
||||
}
|
||||
|
||||
return {
|
||||
browser: browser,
|
||||
version: version,
|
||||
browser,
|
||||
version,
|
||||
platform: platformMatch[0] || '',
|
||||
versionMajor: versionMajor
|
||||
versionMajor
|
||||
};
|
||||
};
|
||||
|
||||
@@ -283,10 +283,11 @@ export const detectBrowser = (userAgent = navigator.userAgent) => {
|
||||
browser.animate = typeof document !== 'undefined' && document.documentElement.animate != null;
|
||||
browser.hisense = normalizedUA.includes('hisense');
|
||||
browser.tizen = normalizedUA.includes('tizen') || window.tizen != null;
|
||||
browser.vega = normalizedUA.includes('kepler');
|
||||
browser.vidaa = normalizedUA.includes('vidaa');
|
||||
browser.web0s = isWeb0s(normalizedUA);
|
||||
|
||||
browser.tv = browser.ps4 || browser.xboxOne || isTv(normalizedUA);
|
||||
browser.tv = browser.ps4 || browser.vega || browser.xboxOne || isTv(normalizedUA);
|
||||
browser.operaTv = browser.tv && normalizedUA.includes('opr/');
|
||||
|
||||
browser.edgeUwp = (browser.edge || browser.edgeChromium) && (normalizedUA.includes('msapphost') || normalizedUA.includes('webview'));
|
||||
@@ -305,9 +306,15 @@ export const detectBrowser = (userAgent = navigator.userAgent) => {
|
||||
delete browser.chrome;
|
||||
delete browser.safari;
|
||||
} else if (browser.titanos) {
|
||||
// UserAgent string contains 'Opr' and 'Safari', but we only want 'titanos' to be true
|
||||
// UserAgent string contains 'Opr' and 'Safari', but we only want 'titanos' to be true
|
||||
delete browser.operaTv;
|
||||
delete browser.safari;
|
||||
} else if (browser.vega) {
|
||||
// UserAgent string contains 'Chrome' and 'Safari', but we only want 'vega' to be true
|
||||
delete browser.chrome;
|
||||
delete browser.safari;
|
||||
// UserAgent string contains 'Mobile Chrome', but it is a TV
|
||||
delete browser.mobile;
|
||||
} else {
|
||||
browser.orsay = normalizedUA.includes('smarthub');
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ import { describe, expect, it } from 'vitest';
|
||||
import { detectBrowser } from './browser';
|
||||
|
||||
describe('Browser', () => {
|
||||
it('should identify TitanOS devices', async () => {
|
||||
it('should identify TitanOS devices', () => {
|
||||
// Ref: https://docs.titanos.tv/user-agents-specifications
|
||||
// Philips example
|
||||
let browser = detectBrowser('Mozilla/5.0 (Linux armv7l) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.4147.62 Safari/537.36 OPR/46.0.2207.0 OMI/4.24, TV_NT72690_2025_4K /<SW version> (Philips, <CTN>, wired) CE-HTML/1.0 NETTV/4.6.0.8 SignOn/2.0 SmartTvA/5.0.0 TitanOS/3.0 en Ginga');
|
||||
@@ -20,7 +20,17 @@ describe('Browser', () => {
|
||||
expect(browser.tv).toBe(true);
|
||||
});
|
||||
|
||||
it('should identify Xbox devices', async () => {
|
||||
it('should identify Vega devices', () => {
|
||||
// Ref: https://developer.amazon.com/docs/vega/0.21/webview-development-best-practices-tv.html#avoid-relying-on-the-useragent
|
||||
const browser = detectBrowser('Mozilla/5.0 (Linux; Kepler 1.1; AFTCA002 user/1234; wv) AppleWebKit/537.36 (KHTML, like Gecko) Mobile Chrome/130.0.6723.192 Safari/537.36');
|
||||
expect(browser.vega).toBe(true);
|
||||
expect(browser.chrome).toBeFalsy();
|
||||
expect(browser.safari).toBeFalsy();
|
||||
expect(browser.mobile).toBeFalsy();
|
||||
expect(browser.tv).toBe(true);
|
||||
});
|
||||
|
||||
it('should identify Xbox devices', () => {
|
||||
const browser = detectBrowser('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0 WebView2 Xbox');
|
||||
expect(browser.xboxOne).toBe(true);
|
||||
expect(browser.tv).toBe(true);
|
||||
|
||||
+15
-15
@@ -195,7 +195,7 @@
|
||||
"HeaderAddUser": "Дадаць карыстальніка",
|
||||
"HeaderPinCodeReset": "Скінуць Easy PIN-код",
|
||||
"HeaderPortRanges": "Налады брандмаўэра і проксі",
|
||||
"HeaderPreferredMetadataLanguage": "Пераважная мова метададзеных",
|
||||
"HeaderPreferredMetadataLanguage": "Прыярытэтная мова метаданых",
|
||||
"HeaderProfileInformation": "Інфармацыя аб профілі",
|
||||
"HeaderRecordingOptions": "Параметры запісу",
|
||||
"HeaderSelectPath": "Выберыце шлях",
|
||||
@@ -227,7 +227,7 @@
|
||||
"LabelTrackNumber": "Нумар дарожкі",
|
||||
"LabelTranscodes": "Перакадзіруе",
|
||||
"LabelTriggerType": "Тып трыгера",
|
||||
"LabelMetadataPath": "Шлях метададзеных",
|
||||
"LabelMetadataPath": "Шлях да метаданых",
|
||||
"LabelVersionInstalled": "{0} усталяваны",
|
||||
"LabelWeb": "Вэб",
|
||||
"Localization": "Лакалізацыя",
|
||||
@@ -334,8 +334,8 @@
|
||||
"LabelMaxResumePercentageHelp": "Лічыцца, што загалоўкі прайграныя цалкам, калі яны былі спынены пасля гэтага часу.",
|
||||
"LabelMessageTitle": "Назва паведамлення",
|
||||
"LabelMetadata": "Метаданыя",
|
||||
"LabelMetadataPathHelp": "Укажыце карыстацкае месцазнаходжанне для спампаваных ілюстрацый і метададзеных.",
|
||||
"LabelMetadataReaders": "Счытвальнікі метададзеных",
|
||||
"LabelMetadataPathHelp": "Укажыце ўласнае размяшчэнне для спампаваных ілюстрацый і метаданых.",
|
||||
"LabelMetadataReaders": "Чытальнікі метаданых",
|
||||
"LabelMetadataSavers": "Захавальнікі метаданых",
|
||||
"LabelOptionalNetworkPath": "Агульная сеткавая тэчка",
|
||||
"LabelParentNumber": "Бацькоўскі нумар",
|
||||
@@ -606,7 +606,7 @@
|
||||
"HeaderDVR": "DVR",
|
||||
"HeaderEditImages": "Рэдагаваць выявы",
|
||||
"HeaderFrequentlyPlayed": "Прайграныя часта",
|
||||
"HeaderGuideProviders": "Пастаўшчыкі дадзеных тэлегіда",
|
||||
"HeaderGuideProviders": "Пастаўшчыкі даных тэлегіда",
|
||||
"HeaderHttpsSettings": "Налады HTTPS",
|
||||
"HeaderIdentification": "Ідэнтыфікацыя",
|
||||
"HeaderIdentificationCriteriaHelp": "Увядзіце хаця б адзін крытэрый ідэнтыфікацыі.",
|
||||
@@ -639,7 +639,7 @@
|
||||
"HeaderScenes": "Сцэны",
|
||||
"HeaderSeasons": "Сезоны",
|
||||
"HeaderSelectCertificatePath": "Выберыце шлях да сертыфіката",
|
||||
"HeaderSelectMetadataPath": "Выберыце шлях да метададзеных",
|
||||
"HeaderSelectMetadataPath": "Выберыце шлях да метаданых",
|
||||
"HeaderSelectMetadataPathHelp": "Выберыце або ўвядзіце шлях, які хочаце выкарыстоўваць для метаданых. Папка павінна быць даступнай для запісу.",
|
||||
"HeaderSelectServerCachePath": "Выберыце шлях да кэша сервера",
|
||||
"HeaderSelectServerCachePathHelp": "Выберыце або ўвядзіце шлях для файлаў кэшу сервера. Папка павінна быць даступнай для запісу.",
|
||||
@@ -715,7 +715,7 @@
|
||||
"LabelDateTimeLocale": "Рэгіянальная налада даты і часу",
|
||||
"LabelDefaultScreen": "Экран па змаўчанні",
|
||||
"LabelDeinterlaceMethod": "Метад дэінтэрлейсінгу",
|
||||
"LabelDisplayLanguageHelp": "Праект па перакладзе Jellyfin працягваецца.",
|
||||
"LabelDisplayLanguageHelp": "Пераклад Jellyfin вядзецца на пастаяннай аснове.",
|
||||
"LabelDisplayMode": "Рэжым адлюстравання",
|
||||
"LabelDisplayName": "Адлюстраванае імя",
|
||||
"LabelDisplaySpecialsWithinSeasons": "Паказаць спецыяльныя прапановы сезонаў, у якіх яны трансліраваліся",
|
||||
@@ -848,7 +848,7 @@
|
||||
"LabelTitle": "Назва",
|
||||
"LabelTonemappingAlgorithm": "Выберыце алгарытм танальнага адлюстравання для выкарыстання",
|
||||
"LabelTonemappingDesat": "Тонавае адлюстраванне desat",
|
||||
"ChannelAccessHelp": "Выберыце каналы для агульнага доступу з гэтым карыстальнікам. Адміністратары змогуць рэдагаваць усе каналы з дапамогай мэнэджара метададзеных.",
|
||||
"ChannelAccessHelp": "Выберыце каналы для агульнага доступу з гэтым карыстальнікам. Адміністратары змогуць рэдагаваць усе каналы з дапамогай менеджара метаданых.",
|
||||
"ChannelNumber": "Нумар канала",
|
||||
"ClientSettings": "Налады кліента",
|
||||
"ColorPrimaries": "Асноўныя колеры",
|
||||
@@ -1073,7 +1073,7 @@
|
||||
"MillisecondsUnit": "мілісекунды",
|
||||
"LabelCustomDeviceDisplayNameHelp": "Увядзіце карыстальніцкае імя для адлюстравання або пакіньце пустым, каб выкарыстоўваць імя, паведамленае прыладай.",
|
||||
"LabelCustomRating": "Індывідуальны рэйтынг",
|
||||
"LabelDateAddedBehaviorHelp": "Калі прысутнічае значэнне метададзеных, яно заўсёды будзе выкарыстоўвацца перад любым з гэтых варыянтаў.",
|
||||
"LabelDateAddedBehaviorHelp": "Калі прысутнічае значэнне метаданых, яно заўсёды будзе выкарыстоўвацца перад любым з гэтых варыянтаў.",
|
||||
"MixedMoviesShows": "Змешаныя фільмы і серыялы",
|
||||
"LabelDidlMode": "Рэжым DIDL",
|
||||
"Mixer": "Міксер",
|
||||
@@ -1397,7 +1397,7 @@
|
||||
"MediaInfoDvBlSignalCompatibilityId": "Ідэнтыфікатар сумяшчальнасці сігналу DV bl",
|
||||
"YoutubeBadRequest": "Дрэнны запыт.",
|
||||
"EnableDisplayMirroring": "Дубліраванне адлюстравання",
|
||||
"FetchingData": "Атрыманне дадатковых дадзеных",
|
||||
"FetchingData": "Атрыманне дадатковых даных",
|
||||
"LabelSortOrder": "Парадак сартавання",
|
||||
"MarkPlayed": "Адзначыць як прайгранае",
|
||||
"HeaderAlert": "Абвестка",
|
||||
@@ -1480,7 +1480,7 @@
|
||||
"HeaderDefaultRecordingSettings": "Налады запісу па змаўчанні",
|
||||
"HeaderDeleteDevice": "Выдаліць прыладу",
|
||||
"HeaderDeleteDevices": "Выдаліць усе прылады",
|
||||
"HeaderEnabledFieldsHelp": "Зніміце галачку з поля, каб заблакіраваць яго і прадухіліць змяненне дадзеных.",
|
||||
"HeaderEnabledFieldsHelp": "Зніміце птушку з поля, каб зафіксаваць поле і абараніць яго даныя ад змянення.",
|
||||
"HeaderExternalIds": "Знешнія ідэнтыфікатары",
|
||||
"HeaderFeatureAccess": "Доступ да функцый",
|
||||
"HeaderFetcherSettings": "Налады выбаршчыка",
|
||||
@@ -1579,7 +1579,7 @@
|
||||
"LabelLocalCustomCss": "Карыстальніцкі код CSS для стылю, які прымяняецца толькі да гэтага кліента. Вы можаце адключыць карыстальніцкі CSS-код сервера.",
|
||||
"LabelLocalHttpServerPortNumber": "Нумар лакальнага порта HTTP",
|
||||
"LabelLocalHttpServerPortNumberHelp": "Нумар порта TCP для сервера HTTP.",
|
||||
"LabelLockItemToPreventChanges": "Заблакаваць гэты элемент, каб прадухіліць будучыя змяненні метададзеных",
|
||||
"LabelLockItemToPreventChanges": "Заблакіраваць гэты элемент, каб прадухіліць будучыя змяненні метаданых",
|
||||
"LabelLoginDisclaimer": "Адмова ад адказнасці пры ўваходзе",
|
||||
"LabelLoginDisclaimerHelp": "Паведамленне, якое будзе адлюстроўвацца ўнізе старонкі ўваходу.",
|
||||
"LabelLogs": "Журналы",
|
||||
@@ -1590,8 +1590,8 @@
|
||||
"LabelMaxAudiobookResumeHelp": "Лічыцца, што загалоўкі прайграны цалкам, калі іх спыніць, калі астатняя працягласць меншая за гэта значэнне.",
|
||||
"LabelMaxBackdropsPerItem": "Максімальная колькасць фонаў на элемент",
|
||||
"LabelMaxChromecastBitrate": "Якасць трансляцыі Google Cast",
|
||||
"LabelMetadataReadersHelp": "Ранжыруйце любімыя лакальныя крыніцы метададзеных у парадку прыярытэту. Будзе прачытаны першы знойдзены файл.",
|
||||
"LabelMetadataSaversHelp": "Выберыце фарматы файлаў для захавання метададзеных.",
|
||||
"LabelMetadataReadersHelp": "Ранжыруйце любімыя лакальныя крыніцы метаданых у парадку прыярытэту. Будзе прачытаны першы знойдзены файл.",
|
||||
"LabelMetadataSaversHelp": "Выберыце фарматы файлаў для захавання метаданых.",
|
||||
"LabelMethod": "Метад",
|
||||
"LabelMinAudiobookResume": "Мінімальнае ўзнаўленне аўдыякнігі ў хвілінах",
|
||||
"LabelMinAudiobookResumeHelp": "Лічыцца, што загалоўкі не прайграваюцца, калі яны былі спынены да гэтага часу.",
|
||||
@@ -2010,7 +2010,7 @@
|
||||
"LabelRestore": "Аднавіць",
|
||||
"LastActive": "Апошняя актыўнасць",
|
||||
"ButtonLearnMore": "Даведацца больш",
|
||||
"LabelDatabase": "База дадзеных",
|
||||
"LabelDatabase": "База даных",
|
||||
"LimitSegmentLengthHelp": "Уключэнне гэтай опцыі можа дапамагчы прадухіліць затрымкі ў HLS-плэеры падчас пракруткі на некаторых прыладах, напрыклад, на тэлевізарах webOS.",
|
||||
"LibraryNameInvalid": "Назва бібліятэкі не можа быць пустой.",
|
||||
"HeaderUpdateRequired": "Патрабуецца абнаўленне",
|
||||
|
||||
+15
-2
@@ -164,6 +164,19 @@
|
||||
"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 play back at the same loudness.\nAlbum gain: Adjusts the volume of all tracks in an album as a group, preserving the album’s original dynamic range. Switching between “Off” and other options requires restarting the current playback.",
|
||||
"ClearQueue": "Clear queue"
|
||||
"SelectAudioNormalizationHelp": "Track gain - Adjusts the volume of each track so they playback at the same loudness.\nAlbum gain: Adjusts the volume of all tracks in an album as a group, preserving the album’s original dynamic range. Switching between “Off” and other options requires restarting the current playback.",
|
||||
"ClearQueue": "Clear queue",
|
||||
"ClientSettings": "Client side settings",
|
||||
"Collections": "Collections",
|
||||
"Colorist": "Colorist",
|
||||
"ColorPrimaries": "Primary colors",
|
||||
"ColorSpace": "Color space",
|
||||
"ColorTransfer": "Transfer colors",
|
||||
"CommunityRating": "Community rating",
|
||||
"Composer": "Composer",
|
||||
"Conductor": "Conductor",
|
||||
"ConfigureDateAdded": "Setting up how metadata for 'Date added' is determined in the Dashboard >Libraries>Display",
|
||||
"ConfirmDeleteImage": "Do you want to delete this image?",
|
||||
"ConfirmDeleteItem": "Deleting this item will delete it from both the file system and the media library. Are you sure you wish to continue?",
|
||||
"ConfirmDeleteSeries": "Deleting this series will delete All{0} episodes from both the file system and your media library. Are you sure you wish to continue?"
|
||||
}
|
||||
|
||||
+1
-1
@@ -1676,7 +1676,7 @@
|
||||
"RememberSubtitleSelections": "Définir la piste de sous-titre en fonction de l'élément précédent",
|
||||
"RememberAudioSelectionsHelp": "Choisir la piste audio la plus proche de la dernière vidéo.",
|
||||
"RememberAudioSelections": "Définir la piste audio en fonction de l'élément précédent",
|
||||
"IgnoreDtsHelp": "Désactiver cette option peut résoudre certains problèmes, par exemple une piste audio manquante sur les chaînes avec flux audio et vidéo séparés.",
|
||||
"IgnoreDtsHelp": "Désactiver cette option peut résoudre certains problèmes, comme par exemple une piste audio manquante sur les chaînes avec flux audio et vidéo séparés.",
|
||||
"OptionDateShowAdded": "Date d'ajout de la série",
|
||||
"OptionDateEpisodeAdded": "Date d'ajout de l'épisode",
|
||||
"IgnoreDts": "Ignorer le DTS (horodatage de décodage)",
|
||||
|
||||
+10
-10
@@ -29,10 +29,10 @@
|
||||
"ButtonArrowLeft": "Vinstri",
|
||||
"ButtonArrowRight": "Hægri",
|
||||
"AllowOnTheFlySubtitleExtractionHelp": "Hægt er að sækja texta sem eru innbyggðir í myndaskrá og senda þá beint til notanda á textaformi til þess að sleppa við að umbreyta (transcode) myndaskránni. Í sumum tölvum getur þetta tekið langan tíma og valdið hikstum á meðan verið er að sækja textan. Afvirkjaðu þetta til þess að láta alla texta vera brennda inn í myndaskránna ef tæki notenda styður ekki að spila skránna beint.",
|
||||
"AccessRestrictedTryAgainLater": "Aðgangur bannaður í augnablikinu. Vinsamlegast reynið síðar.",
|
||||
"AccessRestrictedTryAgainLater": "Aðgangur er takmarkaður eins og er. Vinsamlegast reyndu aftur síðar.",
|
||||
"Actor": "Leikari",
|
||||
"Add": "Bæta við",
|
||||
"AddToCollection": "Bæta í safn",
|
||||
"AddToCollection": "Bæta við í safn",
|
||||
"MessageBrowsePluginCatalog": "Skoða viðbætur sem eru í boði í viðbóta safninu okkar.",
|
||||
"BurnSubtitlesHelp": "Ákveður hvort þjónninn eigi að brenna textann inn í myndaskránna þegar verið er að umbreyta skrársniðinu. Með því að forðast að brenna inn textann er hægt að minnka álag á þjóninn (tölvuna). Veljið sjálfkrafa til þess að brenna texta byggðan á myndum (VOBSUB, PGS, SUB/IDX, ofl) og ákveðna ASS/SSA texta.",
|
||||
"OptionSaveMetadataAsHidden": "Geyma gagnagögn (metadata) og myndir sem leynilegar skrár",
|
||||
@@ -49,15 +49,15 @@
|
||||
"OptionTvdbRating": "TheTVDB einkunn",
|
||||
"OptionWakeFromSleep": "Vekja frá svefni",
|
||||
"PackageInstallCancelled": "{0} (útgáfa {1}) hætt við uppsetningu.",
|
||||
"AddToPlayQueue": "Bæta í spilunarlista",
|
||||
"AddToPlayQueue": "Bæta við í spilunarbiðlista",
|
||||
"AddedOnValue": "Bætti við {0}",
|
||||
"AirDate": "Frumsýningardagur",
|
||||
"Aired": "Frumsýnt",
|
||||
"AddToPlaylist": "Bæta á spilunarlista",
|
||||
"AddToPlaylist": "Bæta við í spilunarlista",
|
||||
"AdditionalNotificationServices": "Skoða viðbætur til þess að bæta við fleiri tilkynningarþjónustum.",
|
||||
"Alerts": "Viðvaranir",
|
||||
"Albums": "Plötur",
|
||||
"AllChannels": "Allar stöðvar",
|
||||
"AllChannels": "Allar rásir",
|
||||
"AllEpisodes": "Allir þættir",
|
||||
"AllLanguages": "Öll tungumál",
|
||||
"AllowMediaConversion": "Leyfa umbreytingu á efni",
|
||||
@@ -203,7 +203,7 @@
|
||||
"AskAdminToCreateLibrary": "Biðjið stjórnanda að gera nýtt gagnasafn.",
|
||||
"MoreFromValue": "Meira frá {0}",
|
||||
"AlwaysPlaySubtitlesHelp": "Allir textar sem samsvara við túngumáli valið verða alltaf hlaðnir óháð hljóðmáls túngumáli.",
|
||||
"AllowedRemoteAddressesHelp": "Kommu aðskilinn listi yfir ip tölur eða ip-númeramát fyrir net sem mega fjartengjas. Ef þetta er autt eru allar fjartengingar leyfðar.",
|
||||
"AllowedRemoteAddressesHelp": "Kommuaðskilinn listi yfir IP-staðföng eða IP-/netmátsfærslur fyrir net sem mega tengjast fjarrænt. Ef þetta er autt verða öll fjarræn staðföng leyfð.",
|
||||
"AllowHWTranscodingHelp": "Leyfa viðtæki að umbreyta straumi í rauntíma. Þetta getur fækkað umbreytingum sem þjónninn þarf að framkvæma.",
|
||||
"ValueSpecialEpisodeName": "Sérstaktur - {0}",
|
||||
"Shows": "Þættir",
|
||||
@@ -448,7 +448,7 @@
|
||||
"MusicArtist": "Tónlistarmaður",
|
||||
"MusicAlbum": "Tónlistaralbúm",
|
||||
"ButtonCast": "Senda út í tæki",
|
||||
"AddToFavorites": "Bæta við eftirlæti",
|
||||
"AddToFavorites": "Bæta við í eftirlæti",
|
||||
"ButtonPlayer": "Spilari",
|
||||
"AgeValue": "({0} ára)",
|
||||
"ApiKeysCaption": "Listi yfir núverandi virkum API lyklum",
|
||||
@@ -479,14 +479,14 @@
|
||||
"ButtonUseQuickConnect": "Nota hraðtengingu",
|
||||
"Digital": "Stafrænt",
|
||||
"DownloadAll": "Sækja allt",
|
||||
"AllowCollectionManagement": "Leyfa þessum notanda að sýsla með söfn",
|
||||
"AllowContentWithTagsHelp": "Sýnir einungis efni sem hefur að minnsta kosti eitt af tilgreindum merkjum.",
|
||||
"AllowCollectionManagement": "Leyfa þessum notanda að stjórna söfnum",
|
||||
"AllowContentWithTagsHelp": "Sýnir einungis efni sem hefur að minnsta kosti eitt af hinum tilgreindu merkjum.",
|
||||
"AllowFfmpegThrottlingHelp": "Þegar umkóðun eða endurpökkun kemur nógu langt á undan núverandi spilunarstöðu, stoppar ferlið til að nota færri kerfisauðlindir. Þetta er gagnlegast þegar horft er á myndband án þess að spóla oft. Slökktu á þessu ef þú upplifir vandamál við spilun.",
|
||||
"Alternate": "Skipta um",
|
||||
"AlternateDVD": "Skipta um DVD",
|
||||
"AllowSegmentDeletion": "Eyða bútum",
|
||||
"AirPlay": "AirPlay",
|
||||
"AllowSubtitleManagement": "Leyfa þessum notanda að breyta textum",
|
||||
"AllowSubtitleManagement": "Leyfa þessum notanda að breyta skjátextum",
|
||||
"AllowSegmentDeletionHelp": "AfspilunEyða gömlum bútum eftir að biðlarinn halar þeim niður. Þetta kemur í veg fyrir að vefþjónninn geymir heila umbreytta skrá á disknum. Slökktu á þessu ef þú upplifar vandamál við spilun.",
|
||||
"LabelThrottleDelaySeconds": "Takmarka eftir",
|
||||
"LabelThrottleDelaySecondsHelp": "Tími í sekúndum þangað til að umkóðarinn verður takmarkaður. Þarf að vera nógu stórt til að viðhalda nægu biðminni í biðlaranum.",
|
||||
|
||||
+1
-1
@@ -862,7 +862,7 @@
|
||||
"LabelPreferredSubtitleLanguage": "선호하는 자막 언어",
|
||||
"LabelPostProcessorArgumentsHelp": "{path}에 녹화 파일을 저장합니다.",
|
||||
"LabelOriginalTitle": "원본 제목",
|
||||
"LabelPersonRole": "규칙",
|
||||
"LabelPersonRole": "역할",
|
||||
"LabelMovieCategories": "영화 카테고리",
|
||||
"LabelOptionalNetworkPath": "공유 네트워크 폴더",
|
||||
"LabelNewsCategories": "뉴스 카테고리",
|
||||
|
||||
+3
-1
@@ -2041,5 +2041,7 @@
|
||||
"ManageRepositories": "Pārvaldīt repozitorijus",
|
||||
"ViewAllPlugins": "Skatīt visus spraudņus",
|
||||
"ButtonAddTunerDevice": "Pievienot uztvērēja ierīci",
|
||||
"ButtonAddProvider": "Pievienot pakalpojuma sniedzēju"
|
||||
"ButtonAddProvider": "Pievienot pakalpojuma sniedzēju",
|
||||
"LabelSlideshowInterval": "Fotoattēlu slaidrādes intervāls",
|
||||
"LabelSlideshowIntervalHelp": "Katra fotoattēla laiks sekundēs tiek parādīts slaidšovā."
|
||||
}
|
||||
|
||||
+4
-4
@@ -499,7 +499,7 @@
|
||||
"LabelFriendlyName": "Gebruiksvriendelijke naam",
|
||||
"LabelServerNameHelp": "Deze naam wordt gebruikt om de server te identificeren; standaard is deze de hostnaam van de server.",
|
||||
"LabelGroupMoviesIntoCollections": "Films groeperen in collecties",
|
||||
"LabelGroupMoviesIntoCollectionsHelp": "Films in een collectie worden weergegeven als één gegroepeerd item bij het weergeven van filmlijsten.",
|
||||
"LabelGroupMoviesIntoCollectionsHelp": "Films in een collectie worden in overzichten als één item gegroepeerd weergegeven.",
|
||||
"LabelEncoderPreset": "Voorinstelling codering",
|
||||
"LabelHardwareAccelerationType": "Hardwareversnelling",
|
||||
"LabelHardwareAccelerationTypeHelp": "Hardwareversnelling vereist aanvullende configuratie.",
|
||||
@@ -833,7 +833,7 @@
|
||||
"OptionDisableUserHelp": "De server zal geen verbindingen van deze gebruiker toestaan. Bestaande verbindingen zullen abrupt worden beëindigd.",
|
||||
"OptionDislikes": "Niet leuk",
|
||||
"OptionDisplayFolderView": "Weergave met mappenstructuur tonen",
|
||||
"OptionDisplayFolderViewHelp": "Geef mappen weer naast je andere mediabibliotheken. Dit kan nuttig zijn als je een mappenstructuur wilt hebben.",
|
||||
"OptionDisplayFolderViewHelp": "Toon mappen naast je andere mediabibliotheken. Dit kan nuttig zijn als je een eenvoudige mapweergave wilt.",
|
||||
"OptionDownloadImagesInAdvance": "Download afbeeldingen van tevoren",
|
||||
"OptionDownloadImagesInAdvanceHelp": "Standaard worden de meeste afbeeldingen alleen gedownload wanneer ze opgevraagd worden door een client. Activeer deze optie om alle afbeeldingen van tevoren te downloaden bij het importeren van nieuwe media. Dit kan aanzienlijk langere bibliotheekscans veroorzaken.",
|
||||
"OptionEmbedSubtitles": "Insluiten in container",
|
||||
@@ -2014,8 +2014,8 @@
|
||||
"SettingsPageLoadError": "Laden van instellingenpagina mislukt",
|
||||
"RetryWithGlobalSearch": "Alles doorzoeken",
|
||||
"StreamCountExceedsLimit": "Het aantal streams overschrijdt de limiet",
|
||||
"LabelGroupShowsIntoCollectionsHelp": "Series in een collectie zullen worden getoond als één gegroepeerd item tijdens het weergeven van serielijsten.",
|
||||
"LabelGroupShowsIntoCollections": "Series in collecties groeperen",
|
||||
"LabelGroupShowsIntoCollectionsHelp": "Series in een collectie worden in overzichten als één item gegroepeerd weergegeven.",
|
||||
"LabelGroupShowsIntoCollections": "Series groeperen in collecties",
|
||||
"ImageUploadFailed": "Afbeelding uploaden mislukt",
|
||||
"ImageDeleteFailed": "Afbeelding verwijderen mislukt",
|
||||
"ImageUploadCancelled": "Uploaden afbeelding geannuleerd",
|
||||
|
||||
@@ -37,6 +37,9 @@
|
||||
|
||||
html {
|
||||
@include fullpage;
|
||||
|
||||
/* Set the default font for cases we don't load the brand font */
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
line-height: 1.35;
|
||||
}
|
||||
|
||||
|
||||
@@ -33,6 +33,8 @@ function getWebDeviceIcon(browser: string | null | undefined) {
|
||||
return BASE_DEVICE_IMAGE_URL + 'msie.svg';
|
||||
case 'Titan OS':
|
||||
return BASE_DEVICE_IMAGE_URL + 'titanos.svg';
|
||||
case 'Vega OS':
|
||||
return BASE_DEVICE_IMAGE_URL + 'firetv.svg';
|
||||
default:
|
||||
return BASE_DEVICE_IMAGE_URL + 'html5.svg';
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user