Compare commits
298 Commits
release-10
...
noavc
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
32906e8a9d | ||
|
|
1c13b436db | ||
|
|
d1bc4c079f | ||
|
|
e8fb89378f | ||
|
|
15bb9f8e24 | ||
|
|
801824523b | ||
|
|
bc9537d80f | ||
|
|
505c986f11 | ||
|
|
99091c083d | ||
|
|
08ab07ff0f | ||
|
|
2016e80765 | ||
|
|
c4082e28ee | ||
|
|
5ca77e1bcd | ||
|
|
63a719ad57 | ||
|
|
d00b9fe612 | ||
|
|
3374ad700a | ||
|
|
cdeda15d78 | ||
|
|
213c999c23 | ||
|
|
42d926e8e9 | ||
|
|
54a9d7b9b1 | ||
|
|
f6b7d9bce0 | ||
|
|
7cfc447c98 | ||
|
|
2936d512d9 | ||
|
|
b1fda390f5 | ||
|
|
f918c27b40 | ||
|
|
620bd2cded | ||
|
|
c9d8609ca3 | ||
|
|
311f3fdcf4 | ||
|
|
e8c7d50b42 | ||
|
|
471ee0158d | ||
|
|
36fa2c2e88 | ||
|
|
1bde84a537 | ||
|
|
678c6c4e75 | ||
|
|
5d307aafd8 | ||
|
|
96c97ecfe4 | ||
|
|
f0d194f8af | ||
|
|
1576b96cf0 | ||
|
|
7eb0b84955 | ||
|
|
0a6a05d7b7 | ||
|
|
a097427731 | ||
|
|
5ee73eec09 | ||
|
|
3a7e8a337c | ||
|
|
609c7debf8 | ||
|
|
e958cd75ea | ||
|
|
1f16bd7137 | ||
|
|
55f4a30151 | ||
|
|
0353a79c60 | ||
|
|
24c751eaca | ||
|
|
1da549bd54 | ||
|
|
a4225a217b | ||
|
|
63ef8b06b1 | ||
|
|
1c7f380ad2 | ||
|
|
c73bc9d843 | ||
|
|
89867d21da | ||
|
|
b4c171668d | ||
|
|
75c80d1833 | ||
|
|
5e1b7ea450 | ||
|
|
592e109163 | ||
|
|
c1faf48595 | ||
|
|
24f79373e3 | ||
|
|
8f381c289e | ||
|
|
a694d6c921 | ||
|
|
19abd4b3ba | ||
|
|
612dc28238 | ||
|
|
2ecab9052a | ||
|
|
ad5b79e9b0 | ||
|
|
2f7bfbd7b7 | ||
|
|
9a87920e38 | ||
|
|
ece8de3420 | ||
|
|
c0894697dc | ||
|
|
5d00939f18 | ||
|
|
d3db9ebc37 | ||
|
|
1c7438c035 | ||
|
|
edbd298499 | ||
|
|
f78c2922c4 | ||
|
|
9614495fde | ||
|
|
bfe5b7cc39 | ||
|
|
89f317ab62 | ||
|
|
5dbca32784 | ||
|
|
c8eed9a897 | ||
|
|
2dc995ad10 | ||
|
|
256a7b8b1d | ||
|
|
4c59f6c571 | ||
|
|
d0b198c6b3 | ||
|
|
11cd8dd434 | ||
|
|
ac8fb37c8c | ||
|
|
b22e49c0e8 | ||
|
|
712affbe98 | ||
|
|
d3e5041a58 | ||
|
|
225b2cd025 | ||
|
|
54a2dadbfc | ||
|
|
512878e735 | ||
|
|
b82ec18b0b | ||
|
|
2b220ff985 | ||
|
|
bdb184155c | ||
|
|
3dbbff9b33 | ||
|
|
89483b2f4c | ||
|
|
6e3fdbb122 | ||
|
|
c36c58e6ba | ||
|
|
de4d6b9d27 | ||
|
|
05bc77f407 | ||
|
|
7548106970 | ||
|
|
6a0111226e | ||
|
|
e24f9b77f7 | ||
|
|
0cf41f40f1 | ||
|
|
04e1a8aeba | ||
|
|
e3e9511cc3 | ||
|
|
268e161013 | ||
|
|
83f5a2314a | ||
|
|
6fd90b0c36 | ||
|
|
3c8f5e9387 | ||
|
|
052eb6d5ee | ||
|
|
b1b444a8e4 | ||
|
|
fb1ef7d905 | ||
|
|
9d7532ceab | ||
|
|
34d6589667 | ||
|
|
44eee5be6e | ||
|
|
19f604ee24 | ||
|
|
03cef65c88 | ||
|
|
e0e266d1a6 | ||
|
|
8ef78024b2 | ||
|
|
c3c278b9f2 | ||
|
|
39858bc103 | ||
|
|
94bbc8498d | ||
|
|
2cb722a588 | ||
|
|
a789df2add | ||
|
|
4385e1c937 | ||
|
|
0fa73a972b | ||
|
|
2a62554b7c | ||
|
|
8a0387d51c | ||
|
|
fd6cab45cc | ||
|
|
eee59078cd | ||
|
|
2fb7f92cba | ||
|
|
90ba7135e3 | ||
|
|
9be865f470 | ||
|
|
ad881412a7 | ||
|
|
672a6e9212 | ||
|
|
042f28fae7 | ||
|
|
39f5f952c2 | ||
|
|
caffdfd5fa | ||
|
|
a530389d54 | ||
|
|
bab9c86521 | ||
|
|
2072cca091 | ||
|
|
0826138ade | ||
|
|
2a8a4889d4 | ||
|
|
12d2cf31e2 | ||
|
|
c768653020 | ||
|
|
3a70d9208a | ||
|
|
031a9aac74 | ||
|
|
681ce0f8e4 | ||
|
|
92b60bde62 | ||
|
|
1ec4f9b479 | ||
|
|
8fea5c0da0 | ||
|
|
4cb00f35f8 | ||
|
|
7f64f72c92 | ||
|
|
b5b1f3bb06 | ||
|
|
0185eb226d | ||
|
|
bb89c40884 | ||
|
|
30117bcc86 | ||
|
|
793649e83f | ||
|
|
e39a7dc40b | ||
|
|
717d30cb56 | ||
|
|
cb48f6b15f | ||
|
|
3e7de3c580 | ||
|
|
53fdd8ec15 | ||
|
|
2b0f028b6f | ||
|
|
a88110fcad | ||
|
|
ffd7cad65c | ||
|
|
64f19c3bdd | ||
|
|
ca7311cb08 | ||
|
|
bc4d6c95d1 | ||
|
|
20fd822b8b | ||
|
|
4fed499c99 | ||
|
|
fbaab4e3c8 | ||
|
|
edacbb6c32 | ||
|
|
0d5e49e67b | ||
|
|
f0b7d7ad55 | ||
|
|
5c28f017ec | ||
|
|
06f2c226e1 | ||
|
|
6f6d6f22bc | ||
|
|
ca5f94df63 | ||
|
|
441494d5b2 | ||
|
|
b4b3028da1 | ||
|
|
f0fee2cfe5 | ||
|
|
c3d7401bc9 | ||
|
|
1c69ad4e6c | ||
|
|
fa8c542ad7 | ||
|
|
33b6106f26 | ||
|
|
e71d83af94 | ||
|
|
23a71cba44 | ||
|
|
a077acb7c8 | ||
|
|
7f904d5ac8 | ||
|
|
d2db4e52f6 | ||
|
|
2b86995fc7 | ||
|
|
1fd7bf0c51 | ||
|
|
275f896206 | ||
|
|
4a72478659 | ||
|
|
79fe2d7bba | ||
|
|
1ec222ed1d | ||
|
|
c29c71f839 | ||
|
|
3fc766b6b6 | ||
|
|
ff1d4fa45d | ||
|
|
f2474b5e44 | ||
|
|
0162c50213 | ||
|
|
ab1cf1e435 | ||
|
|
d63b1297c2 | ||
|
|
a965c14d77 | ||
|
|
5d49a96d9a | ||
|
|
8036190ce5 | ||
|
|
34df712cf8 | ||
|
|
d0a1fb2558 | ||
|
|
d2d6c64d5f | ||
|
|
08a852dee3 | ||
|
|
e640f0466e | ||
|
|
9b9006a6b5 | ||
|
|
bfa9562318 | ||
|
|
786d8c837d | ||
|
|
07eb8f9a15 | ||
|
|
79ae5c12bc | ||
|
|
6ed9857f68 | ||
|
|
ed4849367e | ||
|
|
76095a8a11 | ||
|
|
655a32f745 | ||
|
|
4caa8f7143 | ||
|
|
1fc8c2d683 | ||
|
|
9839f991d9 | ||
|
|
a0fdf53cc2 | ||
|
|
2c363b2610 | ||
|
|
f5df123ace | ||
|
|
00eacba5b4 | ||
|
|
901af6b07b | ||
|
|
42c21b96c2 | ||
|
|
43581367d0 | ||
|
|
c9c0d9587f | ||
|
|
4ce03b1887 | ||
|
|
08ad03275f | ||
|
|
e4f7529052 | ||
|
|
8a6491dff5 | ||
|
|
4a5c52a92b | ||
|
|
acbb626492 | ||
|
|
fc314790d3 | ||
|
|
1bbae0ef23 | ||
|
|
0ff58e81b0 | ||
|
|
4f17bfb5ed | ||
|
|
e153eeb6e7 | ||
|
|
bd7724b5fc | ||
|
|
cb656d7e98 | ||
|
|
fec00348d3 | ||
|
|
3cb0865628 | ||
|
|
0146f8e329 | ||
|
|
a22bf24e5e | ||
|
|
bf43cb3095 | ||
|
|
497b723d5c | ||
|
|
8991d38ba9 | ||
|
|
10c8ef160c | ||
|
|
686ed79eec | ||
|
|
f012c32859 | ||
|
|
3af4989987 | ||
|
|
60ab71d700 | ||
|
|
6a49fffa9a | ||
|
|
5537654911 | ||
|
|
d8ca158a78 | ||
|
|
bc7ec0e876 | ||
|
|
0c818d5fdd | ||
|
|
c3614a0c8c | ||
|
|
033e2edfdd | ||
|
|
4e1e737c0a | ||
|
|
955053c727 | ||
|
|
f4c6a10972 | ||
|
|
d0bc3e338e | ||
|
|
8f150d50c5 | ||
|
|
c57632fde0 | ||
|
|
1d2de7ad4b | ||
|
|
8c793172d7 | ||
|
|
af7664ca18 | ||
|
|
6cc27fff3e | ||
|
|
d549d0f0f9 | ||
|
|
9fbc37fbf3 | ||
|
|
c52c17e1bc | ||
|
|
6c80fadc1b | ||
|
|
d8de2cddc1 | ||
|
|
4d5fcb5d46 | ||
|
|
3a5a49e1f1 | ||
|
|
9a6cb89bae | ||
|
|
ecb8d7202a | ||
|
|
34c6cd2bd1 | ||
|
|
dd705c31d9 | ||
|
|
474c16f601 | ||
|
|
c92c012c7e | ||
|
|
7abb02454b | ||
|
|
118e08b820 | ||
|
|
acb814a027 | ||
|
|
d49b47e201 | ||
|
|
ece5f7d713 | ||
|
|
dc35c9d59e | ||
|
|
1400f20d75 | ||
|
|
fdccb5c915 | ||
|
|
f9092e0678 |
38
.eslintrc.js
38
.eslintrc.js
@@ -273,6 +273,44 @@ module.exports = {
|
||||
__WEBPACK_SERVE__: 'readonly'
|
||||
},
|
||||
rules: {
|
||||
'@typescript-eslint/naming-convention': [
|
||||
'error',
|
||||
{
|
||||
selector: 'default',
|
||||
format: [ 'camelCase', 'PascalCase' ],
|
||||
leadingUnderscore: 'allow'
|
||||
},
|
||||
{
|
||||
selector: 'variable',
|
||||
format: [ 'camelCase', 'PascalCase', 'UPPER_CASE' ],
|
||||
leadingUnderscore: 'allowSingleOrDouble',
|
||||
trailingUnderscore: 'allowSingleOrDouble'
|
||||
},
|
||||
{
|
||||
selector: 'typeLike',
|
||||
format: [ 'PascalCase' ]
|
||||
},
|
||||
{
|
||||
selector: 'enumMember',
|
||||
format: [ 'PascalCase', 'UPPER_CASE' ]
|
||||
},
|
||||
{
|
||||
selector: [ 'objectLiteralProperty', 'typeProperty' ],
|
||||
format: [ 'camelCase', 'PascalCase' ],
|
||||
leadingUnderscore: 'allowSingleOrDouble',
|
||||
trailingUnderscore: 'allowSingleOrDouble'
|
||||
},
|
||||
// Ignore numbers, locale strings (en-us), aria/data attributes, CSS selectors,
|
||||
// and api_key parameter
|
||||
{
|
||||
selector: [ 'objectLiteralProperty', 'typeProperty' ],
|
||||
format: null,
|
||||
filter: {
|
||||
regex: '[ &\\-]|^([0-9]+)$|^api_key$',
|
||||
match: true
|
||||
}
|
||||
}
|
||||
],
|
||||
'@typescript-eslint/prefer-string-starts-ends-with': ['error']
|
||||
}
|
||||
},
|
||||
|
||||
6
.github/workflows/__codeql.yml
vendored
6
.github/workflows/__codeql.yml
vendored
@@ -26,15 +26,15 @@ jobs:
|
||||
show-progress: false
|
||||
|
||||
- name: Initialize CodeQL 🛠️
|
||||
uses: github/codeql-action/init@662472033e021d55d94146f66f6058822b0b39fd # v3.27.0
|
||||
uses: github/codeql-action/init@48ab28a6f5dbc2a99bf1e0131198dd8f1df78169 # v3.28.0
|
||||
with:
|
||||
queries: security-and-quality
|
||||
languages: ${{ matrix.language }}
|
||||
|
||||
- name: Autobuild 📦
|
||||
uses: github/codeql-action/autobuild@662472033e021d55d94146f66f6058822b0b39fd # v3.27.0
|
||||
uses: github/codeql-action/autobuild@48ab28a6f5dbc2a99bf1e0131198dd8f1df78169 # v3.28.0
|
||||
|
||||
- name: Perform CodeQL Analysis 🧪
|
||||
uses: github/codeql-action/analyze@662472033e021d55d94146f66f6058822b0b39fd # v3.27.0
|
||||
uses: github/codeql-action/analyze@48ab28a6f5dbc2a99bf1e0131198dd8f1df78169 # v3.28.0
|
||||
with:
|
||||
category: '/language:${{matrix.language}}'
|
||||
|
||||
2
.github/workflows/__deploy.yml
vendored
2
.github/workflows/__deploy.yml
vendored
@@ -35,7 +35,7 @@ jobs:
|
||||
path: dist
|
||||
|
||||
- name: Publish to Cloudflare Pages 📃
|
||||
uses: cloudflare/wrangler-action@b2a0191ce60d21388e1a8dcc968b4e9966f938e1 # v3.11.0
|
||||
uses: cloudflare/wrangler-action@6d58852c35a27e6034745c5d0bc373d739014f7f # v3.13.0
|
||||
id: cf
|
||||
with:
|
||||
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
||||
|
||||
2
.github/workflows/__job_messages.yml
vendored
2
.github/workflows/__job_messages.yml
vendored
@@ -57,7 +57,7 @@ jobs:
|
||||
echo "EOF" >> $GITHUB_ENV
|
||||
|
||||
- name: Push comment to Pull Request 🔼
|
||||
uses: thollander/actions-comment-pull-request@e2c37e53a7d2227b61585343765f73a9ca57eda9 # v3.0.0
|
||||
uses: thollander/actions-comment-pull-request@24bffb9b452ba05a4f3f77933840a6a841d1b32b # v3.0.1
|
||||
if: ${{ inputs.comment && steps.compose.conclusion == 'success' }}
|
||||
with:
|
||||
github-token: ${{ secrets.JF_BOT_TOKEN }}
|
||||
|
||||
2
.github/workflows/__package.yml
vendored
2
.github/workflows/__package.yml
vendored
@@ -39,7 +39,7 @@ jobs:
|
||||
mv dist/config.tmp.json dist/config.json
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3
|
||||
uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4.5.0
|
||||
with:
|
||||
name: frontend
|
||||
path: dist
|
||||
|
||||
2
.github/workflows/__quality_checks.yml
vendored
2
.github/workflows/__quality_checks.yml
vendored
@@ -20,7 +20,7 @@ jobs:
|
||||
show-progress: false
|
||||
|
||||
- name: Scan
|
||||
uses: actions/dependency-review-action@a6993e2c61fd5dc440b409aa1d6904921c5e1894 # v4.3.5
|
||||
uses: actions/dependency-review-action@3b139cfc5fae8b618d3eae3675e383bb1769c019 # v4.5.0
|
||||
with:
|
||||
## Workaround from https://github.com/actions/dependency-review-action/issues/456
|
||||
## TODO: Remove when necessary
|
||||
|
||||
2
.github/workflows/push.yml
vendored
2
.github/workflows/push.yml
vendored
@@ -55,4 +55,4 @@ jobs:
|
||||
secrets: inherit
|
||||
with:
|
||||
branch: ${{ github.ref_name }}
|
||||
comment:
|
||||
comment: false
|
||||
|
||||
448
package-lock.json
generated
448
package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "jellyfin-web",
|
||||
"version": "10.10.7",
|
||||
"version": "10.11.0",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "jellyfin-web",
|
||||
"version": "10.10.7",
|
||||
"version": "10.11.0",
|
||||
"license": "GPL-2.0-or-later",
|
||||
"dependencies": {
|
||||
"@emotion/react": "11.13.3",
|
||||
@@ -18,14 +18,13 @@
|
||||
"@fontsource/noto-sans-sc": "5.1.0",
|
||||
"@fontsource/noto-sans-tc": "5.1.0",
|
||||
"@jellyfin/libass-wasm": "4.2.3",
|
||||
"@jellyfin/sdk": "0.0.0-unstable.202410250501",
|
||||
"@jellyfin/sdk": "0.0.0-unstable.202501020501",
|
||||
"@mui/icons-material": "5.16.7",
|
||||
"@mui/material": "5.16.7",
|
||||
"@mui/x-date-pickers": "7.20.0",
|
||||
"@react-hook/resize-observer": "2.0.2",
|
||||
"@tanstack/react-query": "5.59.13",
|
||||
"@tanstack/react-query-devtools": "5.59.13",
|
||||
"@types/react-lazy-load-image-component": "1.6.4",
|
||||
"abortcontroller-polyfill": "1.7.5",
|
||||
"blurhash": "2.0.5",
|
||||
"classlist.js": "https://github.com/eligrey/classList.js/archive/1.2.20180112.tar.gz",
|
||||
@@ -39,7 +38,7 @@
|
||||
"flv.js": "1.6.2",
|
||||
"headroom.js": "0.12.0",
|
||||
"history": "5.3.0",
|
||||
"hls.js": "1.5.16",
|
||||
"hls.js": "1.5.18",
|
||||
"intersection-observer": "0.12.2",
|
||||
"jellyfin-apiclient": "1.11.0",
|
||||
"jquery": "3.7.1",
|
||||
@@ -79,11 +78,12 @@
|
||||
"@types/markdown-it": "14.1.2",
|
||||
"@types/react": "18.3.11",
|
||||
"@types/react-dom": "18.3.1",
|
||||
"@types/react-lazy-load-image-component": "1.6.4",
|
||||
"@types/sortablejs": "1.15.8",
|
||||
"@typescript-eslint/eslint-plugin": "5.62.0",
|
||||
"@typescript-eslint/parser": "5.62.0",
|
||||
"@uupaa/dynamic-import-polyfill": "1.0.2",
|
||||
"@vitest/coverage-v8": "2.1.3",
|
||||
"@vitest/coverage-v8": "2.1.8",
|
||||
"autoprefixer": "10.4.20",
|
||||
"babel-loader": "9.2.1",
|
||||
"clean-webpack-plugin": "4.0.0",
|
||||
@@ -122,7 +122,7 @@
|
||||
"stylelint-scss": "5.3.2",
|
||||
"ts-loader": "9.5.1",
|
||||
"typescript": "5.6.3",
|
||||
"vitest": "2.1.3",
|
||||
"vitest": "2.1.8",
|
||||
"webpack": "5.95.0",
|
||||
"webpack-bundle-analyzer": "4.10.2",
|
||||
"webpack-cli": "5.1.4",
|
||||
@@ -4846,9 +4846,9 @@
|
||||
"license": "LGPL-2.1-or-later AND (FTL OR GPL-2.0-or-later) AND MIT AND MIT-Modern-Variant AND ISC AND NTP AND Zlib AND BSL-1.0"
|
||||
},
|
||||
"node_modules/@jellyfin/sdk": {
|
||||
"version": "0.0.0-unstable.202410250501",
|
||||
"resolved": "https://registry.npmjs.org/@jellyfin/sdk/-/sdk-0.0.0-unstable.202410250501.tgz",
|
||||
"integrity": "sha512-EKAUJM+1iVmeSJptY7Z0d4vnTSTzM6PPAdVpT24zhIqx0rgugRTiGFE8LPmLZZMBRDet+ZinyZ64kJE4EwEoQg==",
|
||||
"version": "0.0.0-unstable.202501020501",
|
||||
"resolved": "https://registry.npmjs.org/@jellyfin/sdk/-/sdk-0.0.0-unstable.202501020501.tgz",
|
||||
"integrity": "sha512-Ibu8L2pbdTmefgSinjf1RGbTAl5fkxpaOMzTpg+fs3L5OddoZlv4oHfaZI+h26fv8/5l+xMZO4lBh13CWu7isQ==",
|
||||
"license": "MPL-2.0",
|
||||
"peerDependencies": {
|
||||
"axios": "^1.3.4"
|
||||
@@ -6649,6 +6649,7 @@
|
||||
"version": "1.6.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-lazy-load-image-component/-/react-lazy-load-image-component-1.6.4.tgz",
|
||||
"integrity": "sha512-8pFPeDPF4yVG4lU1/ixZidJEEDZmEOYOTYDvmIu2IAabyuv97Q7n/93nMCocHvQ7vD1czKGiW+op55D9m3MkdA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/react": "*",
|
||||
@@ -7050,22 +7051,22 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@vitest/coverage-v8": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-2.1.3.tgz",
|
||||
"integrity": "sha512-2OJ3c7UPoFSmBZwqD2VEkUw6A/tzPF0LmW0ZZhhB8PFxuc+9IBG/FaSM+RLEenc7ljzFvGN+G0nGQoZnh7sy2A==",
|
||||
"version": "2.1.8",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-2.1.8.tgz",
|
||||
"integrity": "sha512-2Y7BPlKH18mAZYAW1tYByudlCYrQyl5RGvnnDYJKW5tCiO5qg3KSAy3XAxcxKz900a0ZXxWtKrMuZLe3lKBpJw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@ampproject/remapping": "^2.3.0",
|
||||
"@bcoe/v8-coverage": "^0.2.3",
|
||||
"debug": "^4.3.6",
|
||||
"debug": "^4.3.7",
|
||||
"istanbul-lib-coverage": "^3.2.2",
|
||||
"istanbul-lib-report": "^3.0.1",
|
||||
"istanbul-lib-source-maps": "^5.0.6",
|
||||
"istanbul-reports": "^3.1.7",
|
||||
"magic-string": "^0.30.11",
|
||||
"magicast": "^0.3.4",
|
||||
"std-env": "^3.7.0",
|
||||
"magic-string": "^0.30.12",
|
||||
"magicast": "^0.3.5",
|
||||
"std-env": "^3.8.0",
|
||||
"test-exclude": "^7.0.1",
|
||||
"tinyrainbow": "^1.2.0"
|
||||
},
|
||||
@@ -7073,8 +7074,8 @@
|
||||
"url": "https://opencollective.com/vitest"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@vitest/browser": "2.1.3",
|
||||
"vitest": "2.1.3"
|
||||
"@vitest/browser": "2.1.8",
|
||||
"vitest": "2.1.8"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@vitest/browser": {
|
||||
@@ -7083,15 +7084,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@vitest/expect": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-2.1.3.tgz",
|
||||
"integrity": "sha512-SNBoPubeCJhZ48agjXruCI57DvxcsivVDdWz+SSsmjTT4QN/DfHk3zB/xKsJqMs26bLZ/pNRLnCf0j679i0uWQ==",
|
||||
"version": "2.1.8",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-2.1.8.tgz",
|
||||
"integrity": "sha512-8ytZ/fFHq2g4PJVAtDX57mayemKgDR6X3Oa2Foro+EygiOJHUXhCqBAAKQYYajZpFoIfvBCF1j6R6IYRSIUFuw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vitest/spy": "2.1.3",
|
||||
"@vitest/utils": "2.1.3",
|
||||
"chai": "^5.1.1",
|
||||
"@vitest/spy": "2.1.8",
|
||||
"@vitest/utils": "2.1.8",
|
||||
"chai": "^5.1.2",
|
||||
"tinyrainbow": "^1.2.0"
|
||||
},
|
||||
"funding": {
|
||||
@@ -7099,22 +7100,21 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@vitest/mocker": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-2.1.3.tgz",
|
||||
"integrity": "sha512-eSpdY/eJDuOvuTA3ASzCjdithHa+GIF1L4PqtEELl6Qa3XafdMLBpBlZCIUCX2J+Q6sNmjmxtosAG62fK4BlqQ==",
|
||||
"version": "2.1.8",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-2.1.8.tgz",
|
||||
"integrity": "sha512-7guJ/47I6uqfttp33mgo6ga5Gr1VnL58rcqYKyShoRK9ebu8T5Rs6HN3s1NABiBeVTdWNrwUMcHH54uXZBN4zA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vitest/spy": "2.1.3",
|
||||
"@vitest/spy": "2.1.8",
|
||||
"estree-walker": "^3.0.3",
|
||||
"magic-string": "^0.30.11"
|
||||
"magic-string": "^0.30.12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/vitest"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@vitest/spy": "2.1.3",
|
||||
"msw": "^2.3.5",
|
||||
"msw": "^2.4.9",
|
||||
"vite": "^5.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
@@ -7127,9 +7127,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@vitest/pretty-format": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-2.1.3.tgz",
|
||||
"integrity": "sha512-XH1XdtoLZCpqV59KRbPrIhFCOO0hErxrQCMcvnQete3Vibb9UeIOX02uFPfVn3Z9ZXsq78etlfyhnkmIZSzIwQ==",
|
||||
"version": "2.1.8",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-2.1.8.tgz",
|
||||
"integrity": "sha512-9HiSZ9zpqNLKlbIDRWOnAWqgcA7xu+8YxXSekhr0Ykab7PAYFkhkwoqVArPOtJhPmYeE2YHgKZlj3CP36z2AJQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -7140,13 +7140,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@vitest/runner": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-2.1.3.tgz",
|
||||
"integrity": "sha512-JGzpWqmFJ4fq5ZKHtVO3Xuy1iF2rHGV4d/pdzgkYHm1+gOzNZtqjvyiaDGJytRyMU54qkxpNzCx+PErzJ1/JqQ==",
|
||||
"version": "2.1.8",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-2.1.8.tgz",
|
||||
"integrity": "sha512-17ub8vQstRnRlIU5k50bG+QOMLHRhYPAna5tw8tYbj+jzjcspnwnwtPtiOlkuKC4+ixDPTuLZiqiWWQ2PSXHVg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vitest/utils": "2.1.3",
|
||||
"@vitest/utils": "2.1.8",
|
||||
"pathe": "^1.1.2"
|
||||
},
|
||||
"funding": {
|
||||
@@ -7154,14 +7154,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@vitest/snapshot": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-2.1.3.tgz",
|
||||
"integrity": "sha512-qWC2mWc7VAXmjAkEKxrScWHWFyCQx/cmiZtuGqMi+WwqQJ2iURsVY4ZfAK6dVo6K2smKRU6l3BPwqEBvhnpQGg==",
|
||||
"version": "2.1.8",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-2.1.8.tgz",
|
||||
"integrity": "sha512-20T7xRFbmnkfcmgVEz+z3AU/3b0cEzZOt/zmnvZEctg64/QZbSDJEVm9fLnnlSi74KibmRsO9/Qabi+t0vCRPg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vitest/pretty-format": "2.1.3",
|
||||
"magic-string": "^0.30.11",
|
||||
"@vitest/pretty-format": "2.1.8",
|
||||
"magic-string": "^0.30.12",
|
||||
"pathe": "^1.1.2"
|
||||
},
|
||||
"funding": {
|
||||
@@ -7169,27 +7169,27 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@vitest/spy": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-2.1.3.tgz",
|
||||
"integrity": "sha512-Nb2UzbcUswzeSP7JksMDaqsI43Sj5+Kry6ry6jQJT4b5gAK+NS9NED6mDb8FlMRCX8m5guaHCDZmqYMMWRy5nQ==",
|
||||
"version": "2.1.8",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-2.1.8.tgz",
|
||||
"integrity": "sha512-5swjf2q95gXeYPevtW0BLk6H8+bPlMb4Vw/9Em4hFxDcaOxS+e0LOX4yqNxoHzMR2akEB2xfpnWUzkZokmgWDg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"tinyspy": "^3.0.0"
|
||||
"tinyspy": "^3.0.2"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/vitest"
|
||||
}
|
||||
},
|
||||
"node_modules/@vitest/utils": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-2.1.3.tgz",
|
||||
"integrity": "sha512-xpiVfDSg1RrYT0tX6czgerkpcKFmFOF/gCr30+Mve5V2kewCy4Prn1/NDMSRwaSmT7PRaOF83wu+bEtsY1wrvA==",
|
||||
"version": "2.1.8",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-2.1.8.tgz",
|
||||
"integrity": "sha512-dwSoui6djdwbfFmIgbIjX2ZhIoG7Ex/+xpxyiEgIGzjliY8xGkcpITKTlp6B4MgtGkF2ilvm97cPM96XZaAgcA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vitest/pretty-format": "2.1.3",
|
||||
"loupe": "^3.1.1",
|
||||
"@vitest/pretty-format": "2.1.8",
|
||||
"loupe": "^3.1.2",
|
||||
"tinyrainbow": "^1.2.0"
|
||||
},
|
||||
"funding": {
|
||||
@@ -8652,9 +8652,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/chai": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/chai/-/chai-5.1.1.tgz",
|
||||
"integrity": "sha512-pT1ZgP8rPNqUgieVaEY+ryQr6Q4HXNg8Ei9UnLUrjN4IA7dvQC5JB+/kxVcPNDHyBcc/26CXPkbNzq3qwrOEKA==",
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/chai/-/chai-5.1.2.tgz",
|
||||
"integrity": "sha512-aGtmf24DW6MLHHG5gCx4zaI3uBq3KRtxeVs0DjFH6Z0rDNbsvTxFASFvdj79pxjxZ8/5u3PIiN3IwEIQkiiuPw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -10629,10 +10629,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/es-module-lexer": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.2.1.tgz",
|
||||
"integrity": "sha512-9978wrXM50Y4rTMmW5kXIC09ZdXQZqkE4mxhwkd8VbzsGkXGPgV4zWuqQJgCEzYngdo2dYDa0l8xhX4fkSwJSg==",
|
||||
"dev": true
|
||||
"version": "1.5.4",
|
||||
"resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.4.tgz",
|
||||
"integrity": "sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/es-object-atoms": {
|
||||
"version": "1.0.0",
|
||||
@@ -11682,6 +11683,16 @@
|
||||
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/expect-type": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.1.0.tgz",
|
||||
"integrity": "sha512-bFi65yM+xZgk+u/KRIpekdSYkTB5W1pEf0Lt8Q8Msh7b+eQ7LXVtIB1Bkm4fvclDEL1b2CZkMhv2mOeF8tMdkA==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": ">=12.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/expose-loader": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/expose-loader/-/expose-loader-5.0.0.tgz",
|
||||
@@ -12776,16 +12787,6 @@
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/get-func-name": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz",
|
||||
"integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/get-intrinsic": {
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz",
|
||||
@@ -13249,9 +13250,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/hls.js": {
|
||||
"version": "1.5.16",
|
||||
"resolved": "https://registry.npmjs.org/hls.js/-/hls.js-1.5.16.tgz",
|
||||
"integrity": "sha512-+wAWr4aeRq9ODN8/Vgz0Cee1Cw6Ysr7vyEkZJCwOJYNwlld7CNmhKE+dLwfpUO2UuotYLGF0of6UFiN6zA7mig==",
|
||||
"version": "1.5.18",
|
||||
"resolved": "https://registry.npmjs.org/hls.js/-/hls.js-1.5.18.tgz",
|
||||
"integrity": "sha512-znxR+2jecWluu/0KOBqUcvVyAB5tLff10vjMGrpAlz1eFY+ZhF1bY3r82V+Bk7WJdk03iTjtja9KFFz5BrqjSA==",
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"node_modules/hoist-non-react-statics": {
|
||||
@@ -15327,14 +15328,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/loupe": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/loupe/-/loupe-3.1.1.tgz",
|
||||
"integrity": "sha512-edNu/8D5MKVfGVFRhFf8aAxiTM6Wumfz5XsaatSxlD3w4R1d/WEKUTydCdPGbl9K7QG/Ca3GnDV2sIKIpXRQcw==",
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/loupe/-/loupe-3.1.2.tgz",
|
||||
"integrity": "sha512-23I4pFZHmAemUnz8WZXbYRSKYj801VDaNv9ETuMh7IrMc7VuVVSo+Z9iLE3ni30+U48iDWfi30d3twAXBYmnCg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"get-func-name": "^2.0.1"
|
||||
}
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/lower-case": {
|
||||
"version": "2.0.2",
|
||||
@@ -15358,9 +15356,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/magic-string": {
|
||||
"version": "0.30.11",
|
||||
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.11.tgz",
|
||||
"integrity": "sha512-+Wri9p0QHMy+545hKww7YAu5NyzF8iomPL/RQazugQ9+Ez4Ic3mERMd8ZTX5rfK944j+560ZJi8iAwgak1Ac7A==",
|
||||
"version": "0.30.17",
|
||||
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz",
|
||||
"integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -15368,13 +15366,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/magicast": {
|
||||
"version": "0.3.4",
|
||||
"resolved": "https://registry.npmjs.org/magicast/-/magicast-0.3.4.tgz",
|
||||
"integrity": "sha512-TyDF/Pn36bBji9rWKHlZe+PZb6Mx5V8IHCSxk7X4aljM4e/vyDvZZYwHewdVaqiA0nb3ghfHU/6AUpDxWoER2Q==",
|
||||
"version": "0.3.5",
|
||||
"resolved": "https://registry.npmjs.org/magicast/-/magicast-0.3.5.tgz",
|
||||
"integrity": "sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/parser": "^7.24.4",
|
||||
"@babel/types": "^7.24.0",
|
||||
"@babel/parser": "^7.25.4",
|
||||
"@babel/types": "^7.25.4",
|
||||
"source-map-js": "^1.2.0"
|
||||
}
|
||||
},
|
||||
@@ -21750,10 +21749,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/std-env": {
|
||||
"version": "3.7.0",
|
||||
"resolved": "https://registry.npmjs.org/std-env/-/std-env-3.7.0.tgz",
|
||||
"integrity": "sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg==",
|
||||
"dev": true
|
||||
"version": "3.8.0",
|
||||
"resolved": "https://registry.npmjs.org/std-env/-/std-env-3.8.0.tgz",
|
||||
"integrity": "sha512-Bc3YwwCB+OzldMxOXJIIvC6cPRWr/LxOp48CdQTOkPyk/t4JWWJbrilwBd7RJzKV8QW7tJkcgAmeuLLJugl5/w==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/stop-iteration-iterator": {
|
||||
"version": "1.0.0",
|
||||
@@ -24647,16 +24647,16 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/tinyexec": {
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.0.tgz",
|
||||
"integrity": "sha512-tVGE0mVJPGb0chKhqmsoosjsS+qUnJVGJpZgsHYQcGoPlG3B51R3PouqTgEGH2Dc9jjFyOqOpix6ZHNMXp1FZg==",
|
||||
"version": "0.3.1",
|
||||
"resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.1.tgz",
|
||||
"integrity": "sha512-WiCJLEECkO18gwqIp6+hJg0//p23HXp4S+gGtAKu3mI2F2/sXC4FvHvXvB0zJVVaTPhx1/tOwdbRsa1sOBIKqQ==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/tinypool": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.0.0.tgz",
|
||||
"integrity": "sha512-KIKExllK7jp3uvrNtvRBYBWBOAXSX8ZvoaD8T+7KB/QHIuoJW3Pmr60zucywjAlMb5TeXUkcs/MWeWLu0qvuAQ==",
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.0.2.tgz",
|
||||
"integrity": "sha512-al6n+QEANGFOMf/dmUMsuS5/r9B06uwlyNjZZql/zv8J7ybHCgoihBNORZCY2mzUuAnomQa2JdhyHKzZxPCrFA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@@ -25704,14 +25704,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/vite-node": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/vite-node/-/vite-node-2.1.3.tgz",
|
||||
"integrity": "sha512-I1JadzO+xYX887S39Do+paRePCKoiDrWRRjp9kkG5he0t7RXNvPAJPCQSJqbGN4uCrFFeS3Kj3sLqY8NMYBEdA==",
|
||||
"version": "2.1.8",
|
||||
"resolved": "https://registry.npmjs.org/vite-node/-/vite-node-2.1.8.tgz",
|
||||
"integrity": "sha512-uPAwSr57kYjAUux+8E2j0q0Fxpn8M9VoyfGiRI8Kfktz9NcYMCenwY5RnZxnF1WTu3TGiYipirIzacLL3VVGFg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"cac": "^6.7.14",
|
||||
"debug": "^4.3.6",
|
||||
"debug": "^4.3.7",
|
||||
"es-module-lexer": "^1.5.4",
|
||||
"pathe": "^1.1.2",
|
||||
"vite": "^5.0.0"
|
||||
},
|
||||
@@ -25726,30 +25727,31 @@
|
||||
}
|
||||
},
|
||||
"node_modules/vitest": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/vitest/-/vitest-2.1.3.tgz",
|
||||
"integrity": "sha512-Zrxbg/WiIvUP2uEzelDNTXmEMJXuzJ1kCpbDvaKByFA9MNeO95V+7r/3ti0qzJzrxdyuUw5VduN7k+D3VmVOSA==",
|
||||
"version": "2.1.8",
|
||||
"resolved": "https://registry.npmjs.org/vitest/-/vitest-2.1.8.tgz",
|
||||
"integrity": "sha512-1vBKTZskHw/aosXqQUlVWWlGUxSJR8YtiyZDJAFeW2kPAeX6S3Sool0mjspO+kXLuxVWlEDDowBAeqeAQefqLQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vitest/expect": "2.1.3",
|
||||
"@vitest/mocker": "2.1.3",
|
||||
"@vitest/pretty-format": "^2.1.3",
|
||||
"@vitest/runner": "2.1.3",
|
||||
"@vitest/snapshot": "2.1.3",
|
||||
"@vitest/spy": "2.1.3",
|
||||
"@vitest/utils": "2.1.3",
|
||||
"chai": "^5.1.1",
|
||||
"debug": "^4.3.6",
|
||||
"magic-string": "^0.30.11",
|
||||
"@vitest/expect": "2.1.8",
|
||||
"@vitest/mocker": "2.1.8",
|
||||
"@vitest/pretty-format": "^2.1.8",
|
||||
"@vitest/runner": "2.1.8",
|
||||
"@vitest/snapshot": "2.1.8",
|
||||
"@vitest/spy": "2.1.8",
|
||||
"@vitest/utils": "2.1.8",
|
||||
"chai": "^5.1.2",
|
||||
"debug": "^4.3.7",
|
||||
"expect-type": "^1.1.0",
|
||||
"magic-string": "^0.30.12",
|
||||
"pathe": "^1.1.2",
|
||||
"std-env": "^3.7.0",
|
||||
"std-env": "^3.8.0",
|
||||
"tinybench": "^2.9.0",
|
||||
"tinyexec": "^0.3.0",
|
||||
"tinypool": "^1.0.0",
|
||||
"tinyexec": "^0.3.1",
|
||||
"tinypool": "^1.0.1",
|
||||
"tinyrainbow": "^1.2.0",
|
||||
"vite": "^5.0.0",
|
||||
"vite-node": "2.1.3",
|
||||
"vite-node": "2.1.8",
|
||||
"why-is-node-running": "^2.3.0"
|
||||
},
|
||||
"bin": {
|
||||
@@ -25764,8 +25766,8 @@
|
||||
"peerDependencies": {
|
||||
"@edge-runtime/vm": "*",
|
||||
"@types/node": "^18.0.0 || >=20.0.0",
|
||||
"@vitest/browser": "2.1.3",
|
||||
"@vitest/ui": "2.1.3",
|
||||
"@vitest/browser": "2.1.8",
|
||||
"@vitest/ui": "2.1.8",
|
||||
"happy-dom": "*",
|
||||
"jsdom": "*"
|
||||
},
|
||||
@@ -29214,9 +29216,9 @@
|
||||
"integrity": "sha512-C0OlBxIr9NdeFESMTA/OVDqNSWtog6Mi7wwzwH12xbZpxsMD0RgCupUcIP7zZgcpTNecW3fZq5d6xVo7Q8HEJw=="
|
||||
},
|
||||
"@jellyfin/sdk": {
|
||||
"version": "0.0.0-unstable.202410250501",
|
||||
"resolved": "https://registry.npmjs.org/@jellyfin/sdk/-/sdk-0.0.0-unstable.202410250501.tgz",
|
||||
"integrity": "sha512-EKAUJM+1iVmeSJptY7Z0d4vnTSTzM6PPAdVpT24zhIqx0rgugRTiGFE8LPmLZZMBRDet+ZinyZ64kJE4EwEoQg==",
|
||||
"version": "0.0.0-unstable.202501020501",
|
||||
"resolved": "https://registry.npmjs.org/@jellyfin/sdk/-/sdk-0.0.0-unstable.202501020501.tgz",
|
||||
"integrity": "sha512-Ibu8L2pbdTmefgSinjf1RGbTAl5fkxpaOMzTpg+fs3L5OddoZlv4oHfaZI+h26fv8/5l+xMZO4lBh13CWu7isQ==",
|
||||
"requires": {}
|
||||
},
|
||||
"@jridgewell/gen-mapping": {
|
||||
@@ -30259,6 +30261,7 @@
|
||||
"version": "1.6.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-lazy-load-image-component/-/react-lazy-load-image-component-1.6.4.tgz",
|
||||
"integrity": "sha512-8pFPeDPF4yVG4lU1/ixZidJEEDZmEOYOTYDvmIu2IAabyuv97Q7n/93nMCocHvQ7vD1czKGiW+op55D9m3MkdA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/react": "*",
|
||||
"csstype": "^3.0.2"
|
||||
@@ -30541,95 +30544,95 @@
|
||||
"dev": true
|
||||
},
|
||||
"@vitest/coverage-v8": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-2.1.3.tgz",
|
||||
"integrity": "sha512-2OJ3c7UPoFSmBZwqD2VEkUw6A/tzPF0LmW0ZZhhB8PFxuc+9IBG/FaSM+RLEenc7ljzFvGN+G0nGQoZnh7sy2A==",
|
||||
"version": "2.1.8",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-2.1.8.tgz",
|
||||
"integrity": "sha512-2Y7BPlKH18mAZYAW1tYByudlCYrQyl5RGvnnDYJKW5tCiO5qg3KSAy3XAxcxKz900a0ZXxWtKrMuZLe3lKBpJw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@ampproject/remapping": "^2.3.0",
|
||||
"@bcoe/v8-coverage": "^0.2.3",
|
||||
"debug": "^4.3.6",
|
||||
"debug": "^4.3.7",
|
||||
"istanbul-lib-coverage": "^3.2.2",
|
||||
"istanbul-lib-report": "^3.0.1",
|
||||
"istanbul-lib-source-maps": "^5.0.6",
|
||||
"istanbul-reports": "^3.1.7",
|
||||
"magic-string": "^0.30.11",
|
||||
"magicast": "^0.3.4",
|
||||
"std-env": "^3.7.0",
|
||||
"magic-string": "^0.30.12",
|
||||
"magicast": "^0.3.5",
|
||||
"std-env": "^3.8.0",
|
||||
"test-exclude": "^7.0.1",
|
||||
"tinyrainbow": "^1.2.0"
|
||||
}
|
||||
},
|
||||
"@vitest/expect": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-2.1.3.tgz",
|
||||
"integrity": "sha512-SNBoPubeCJhZ48agjXruCI57DvxcsivVDdWz+SSsmjTT4QN/DfHk3zB/xKsJqMs26bLZ/pNRLnCf0j679i0uWQ==",
|
||||
"version": "2.1.8",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-2.1.8.tgz",
|
||||
"integrity": "sha512-8ytZ/fFHq2g4PJVAtDX57mayemKgDR6X3Oa2Foro+EygiOJHUXhCqBAAKQYYajZpFoIfvBCF1j6R6IYRSIUFuw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@vitest/spy": "2.1.3",
|
||||
"@vitest/utils": "2.1.3",
|
||||
"chai": "^5.1.1",
|
||||
"@vitest/spy": "2.1.8",
|
||||
"@vitest/utils": "2.1.8",
|
||||
"chai": "^5.1.2",
|
||||
"tinyrainbow": "^1.2.0"
|
||||
}
|
||||
},
|
||||
"@vitest/mocker": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-2.1.3.tgz",
|
||||
"integrity": "sha512-eSpdY/eJDuOvuTA3ASzCjdithHa+GIF1L4PqtEELl6Qa3XafdMLBpBlZCIUCX2J+Q6sNmjmxtosAG62fK4BlqQ==",
|
||||
"version": "2.1.8",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-2.1.8.tgz",
|
||||
"integrity": "sha512-7guJ/47I6uqfttp33mgo6ga5Gr1VnL58rcqYKyShoRK9ebu8T5Rs6HN3s1NABiBeVTdWNrwUMcHH54uXZBN4zA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@vitest/spy": "2.1.3",
|
||||
"@vitest/spy": "2.1.8",
|
||||
"estree-walker": "^3.0.3",
|
||||
"magic-string": "^0.30.11"
|
||||
"magic-string": "^0.30.12"
|
||||
}
|
||||
},
|
||||
"@vitest/pretty-format": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-2.1.3.tgz",
|
||||
"integrity": "sha512-XH1XdtoLZCpqV59KRbPrIhFCOO0hErxrQCMcvnQete3Vibb9UeIOX02uFPfVn3Z9ZXsq78etlfyhnkmIZSzIwQ==",
|
||||
"version": "2.1.8",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-2.1.8.tgz",
|
||||
"integrity": "sha512-9HiSZ9zpqNLKlbIDRWOnAWqgcA7xu+8YxXSekhr0Ykab7PAYFkhkwoqVArPOtJhPmYeE2YHgKZlj3CP36z2AJQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"tinyrainbow": "^1.2.0"
|
||||
}
|
||||
},
|
||||
"@vitest/runner": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-2.1.3.tgz",
|
||||
"integrity": "sha512-JGzpWqmFJ4fq5ZKHtVO3Xuy1iF2rHGV4d/pdzgkYHm1+gOzNZtqjvyiaDGJytRyMU54qkxpNzCx+PErzJ1/JqQ==",
|
||||
"version": "2.1.8",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-2.1.8.tgz",
|
||||
"integrity": "sha512-17ub8vQstRnRlIU5k50bG+QOMLHRhYPAna5tw8tYbj+jzjcspnwnwtPtiOlkuKC4+ixDPTuLZiqiWWQ2PSXHVg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@vitest/utils": "2.1.3",
|
||||
"@vitest/utils": "2.1.8",
|
||||
"pathe": "^1.1.2"
|
||||
}
|
||||
},
|
||||
"@vitest/snapshot": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-2.1.3.tgz",
|
||||
"integrity": "sha512-qWC2mWc7VAXmjAkEKxrScWHWFyCQx/cmiZtuGqMi+WwqQJ2iURsVY4ZfAK6dVo6K2smKRU6l3BPwqEBvhnpQGg==",
|
||||
"version": "2.1.8",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-2.1.8.tgz",
|
||||
"integrity": "sha512-20T7xRFbmnkfcmgVEz+z3AU/3b0cEzZOt/zmnvZEctg64/QZbSDJEVm9fLnnlSi74KibmRsO9/Qabi+t0vCRPg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@vitest/pretty-format": "2.1.3",
|
||||
"magic-string": "^0.30.11",
|
||||
"@vitest/pretty-format": "2.1.8",
|
||||
"magic-string": "^0.30.12",
|
||||
"pathe": "^1.1.2"
|
||||
}
|
||||
},
|
||||
"@vitest/spy": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-2.1.3.tgz",
|
||||
"integrity": "sha512-Nb2UzbcUswzeSP7JksMDaqsI43Sj5+Kry6ry6jQJT4b5gAK+NS9NED6mDb8FlMRCX8m5guaHCDZmqYMMWRy5nQ==",
|
||||
"version": "2.1.8",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-2.1.8.tgz",
|
||||
"integrity": "sha512-5swjf2q95gXeYPevtW0BLk6H8+bPlMb4Vw/9Em4hFxDcaOxS+e0LOX4yqNxoHzMR2akEB2xfpnWUzkZokmgWDg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"tinyspy": "^3.0.0"
|
||||
"tinyspy": "^3.0.2"
|
||||
}
|
||||
},
|
||||
"@vitest/utils": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-2.1.3.tgz",
|
||||
"integrity": "sha512-xpiVfDSg1RrYT0tX6czgerkpcKFmFOF/gCr30+Mve5V2kewCy4Prn1/NDMSRwaSmT7PRaOF83wu+bEtsY1wrvA==",
|
||||
"version": "2.1.8",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-2.1.8.tgz",
|
||||
"integrity": "sha512-dwSoui6djdwbfFmIgbIjX2ZhIoG7Ex/+xpxyiEgIGzjliY8xGkcpITKTlp6B4MgtGkF2ilvm97cPM96XZaAgcA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@vitest/pretty-format": "2.1.3",
|
||||
"loupe": "^3.1.1",
|
||||
"@vitest/pretty-format": "2.1.8",
|
||||
"loupe": "^3.1.2",
|
||||
"tinyrainbow": "^1.2.0"
|
||||
}
|
||||
},
|
||||
@@ -31708,9 +31711,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"chai": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/chai/-/chai-5.1.1.tgz",
|
||||
"integrity": "sha512-pT1ZgP8rPNqUgieVaEY+ryQr6Q4HXNg8Ei9UnLUrjN4IA7dvQC5JB+/kxVcPNDHyBcc/26CXPkbNzq3qwrOEKA==",
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/chai/-/chai-5.1.2.tgz",
|
||||
"integrity": "sha512-aGtmf24DW6MLHHG5gCx4zaI3uBq3KRtxeVs0DjFH6Z0rDNbsvTxFASFvdj79pxjxZ8/5u3PIiN3IwEIQkiiuPw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"assertion-error": "^2.0.1",
|
||||
@@ -33126,9 +33129,9 @@
|
||||
}
|
||||
},
|
||||
"es-module-lexer": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.2.1.tgz",
|
||||
"integrity": "sha512-9978wrXM50Y4rTMmW5kXIC09ZdXQZqkE4mxhwkd8VbzsGkXGPgV4zWuqQJgCEzYngdo2dYDa0l8xhX4fkSwJSg==",
|
||||
"version": "1.5.4",
|
||||
"resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.4.tgz",
|
||||
"integrity": "sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==",
|
||||
"dev": true
|
||||
},
|
||||
"es-object-atoms": {
|
||||
@@ -33902,6 +33905,12 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"expect-type": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.1.0.tgz",
|
||||
"integrity": "sha512-bFi65yM+xZgk+u/KRIpekdSYkTB5W1pEf0Lt8Q8Msh7b+eQ7LXVtIB1Bkm4fvclDEL1b2CZkMhv2mOeF8tMdkA==",
|
||||
"dev": true
|
||||
},
|
||||
"expose-loader": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/expose-loader/-/expose-loader-5.0.0.tgz",
|
||||
@@ -34712,12 +34721,6 @@
|
||||
"integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==",
|
||||
"dev": true
|
||||
},
|
||||
"get-func-name": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz",
|
||||
"integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==",
|
||||
"dev": true
|
||||
},
|
||||
"get-intrinsic": {
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz",
|
||||
@@ -35061,9 +35064,9 @@
|
||||
}
|
||||
},
|
||||
"hls.js": {
|
||||
"version": "1.5.16",
|
||||
"resolved": "https://registry.npmjs.org/hls.js/-/hls.js-1.5.16.tgz",
|
||||
"integrity": "sha512-+wAWr4aeRq9ODN8/Vgz0Cee1Cw6Ysr7vyEkZJCwOJYNwlld7CNmhKE+dLwfpUO2UuotYLGF0of6UFiN6zA7mig=="
|
||||
"version": "1.5.18",
|
||||
"resolved": "https://registry.npmjs.org/hls.js/-/hls.js-1.5.18.tgz",
|
||||
"integrity": "sha512-znxR+2jecWluu/0KOBqUcvVyAB5tLff10vjMGrpAlz1eFY+ZhF1bY3r82V+Bk7WJdk03iTjtja9KFFz5BrqjSA=="
|
||||
},
|
||||
"hoist-non-react-statics": {
|
||||
"version": "3.3.2",
|
||||
@@ -36546,13 +36549,10 @@
|
||||
}
|
||||
},
|
||||
"loupe": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/loupe/-/loupe-3.1.1.tgz",
|
||||
"integrity": "sha512-edNu/8D5MKVfGVFRhFf8aAxiTM6Wumfz5XsaatSxlD3w4R1d/WEKUTydCdPGbl9K7QG/Ca3GnDV2sIKIpXRQcw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"get-func-name": "^2.0.1"
|
||||
}
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/loupe/-/loupe-3.1.2.tgz",
|
||||
"integrity": "sha512-23I4pFZHmAemUnz8WZXbYRSKYj801VDaNv9ETuMh7IrMc7VuVVSo+Z9iLE3ni30+U48iDWfi30d3twAXBYmnCg==",
|
||||
"dev": true
|
||||
},
|
||||
"lower-case": {
|
||||
"version": "2.0.2",
|
||||
@@ -36573,22 +36573,22 @@
|
||||
}
|
||||
},
|
||||
"magic-string": {
|
||||
"version": "0.30.11",
|
||||
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.11.tgz",
|
||||
"integrity": "sha512-+Wri9p0QHMy+545hKww7YAu5NyzF8iomPL/RQazugQ9+Ez4Ic3mERMd8ZTX5rfK944j+560ZJi8iAwgak1Ac7A==",
|
||||
"version": "0.30.17",
|
||||
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz",
|
||||
"integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@jridgewell/sourcemap-codec": "^1.5.0"
|
||||
}
|
||||
},
|
||||
"magicast": {
|
||||
"version": "0.3.4",
|
||||
"resolved": "https://registry.npmjs.org/magicast/-/magicast-0.3.4.tgz",
|
||||
"integrity": "sha512-TyDF/Pn36bBji9rWKHlZe+PZb6Mx5V8IHCSxk7X4aljM4e/vyDvZZYwHewdVaqiA0nb3ghfHU/6AUpDxWoER2Q==",
|
||||
"version": "0.3.5",
|
||||
"resolved": "https://registry.npmjs.org/magicast/-/magicast-0.3.5.tgz",
|
||||
"integrity": "sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/parser": "^7.24.4",
|
||||
"@babel/types": "^7.24.0",
|
||||
"@babel/parser": "^7.25.4",
|
||||
"@babel/types": "^7.25.4",
|
||||
"source-map-js": "^1.2.0"
|
||||
}
|
||||
},
|
||||
@@ -40727,9 +40727,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"std-env": {
|
||||
"version": "3.7.0",
|
||||
"resolved": "https://registry.npmjs.org/std-env/-/std-env-3.7.0.tgz",
|
||||
"integrity": "sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg==",
|
||||
"version": "3.8.0",
|
||||
"resolved": "https://registry.npmjs.org/std-env/-/std-env-3.8.0.tgz",
|
||||
"integrity": "sha512-Bc3YwwCB+OzldMxOXJIIvC6cPRWr/LxOp48CdQTOkPyk/t4JWWJbrilwBd7RJzKV8QW7tJkcgAmeuLLJugl5/w==",
|
||||
"dev": true
|
||||
},
|
||||
"stop-iteration-iterator": {
|
||||
@@ -42893,15 +42893,15 @@
|
||||
"dev": true
|
||||
},
|
||||
"tinyexec": {
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.0.tgz",
|
||||
"integrity": "sha512-tVGE0mVJPGb0chKhqmsoosjsS+qUnJVGJpZgsHYQcGoPlG3B51R3PouqTgEGH2Dc9jjFyOqOpix6ZHNMXp1FZg==",
|
||||
"version": "0.3.1",
|
||||
"resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.1.tgz",
|
||||
"integrity": "sha512-WiCJLEECkO18gwqIp6+hJg0//p23HXp4S+gGtAKu3mI2F2/sXC4FvHvXvB0zJVVaTPhx1/tOwdbRsa1sOBIKqQ==",
|
||||
"dev": true
|
||||
},
|
||||
"tinypool": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.0.0.tgz",
|
||||
"integrity": "sha512-KIKExllK7jp3uvrNtvRBYBWBOAXSX8ZvoaD8T+7KB/QHIuoJW3Pmr60zucywjAlMb5TeXUkcs/MWeWLu0qvuAQ==",
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.0.2.tgz",
|
||||
"integrity": "sha512-al6n+QEANGFOMf/dmUMsuS5/r9B06uwlyNjZZql/zv8J7ybHCgoihBNORZCY2mzUuAnomQa2JdhyHKzZxPCrFA==",
|
||||
"dev": true
|
||||
},
|
||||
"tinyrainbow": {
|
||||
@@ -43628,41 +43628,43 @@
|
||||
}
|
||||
},
|
||||
"vite-node": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/vite-node/-/vite-node-2.1.3.tgz",
|
||||
"integrity": "sha512-I1JadzO+xYX887S39Do+paRePCKoiDrWRRjp9kkG5he0t7RXNvPAJPCQSJqbGN4uCrFFeS3Kj3sLqY8NMYBEdA==",
|
||||
"version": "2.1.8",
|
||||
"resolved": "https://registry.npmjs.org/vite-node/-/vite-node-2.1.8.tgz",
|
||||
"integrity": "sha512-uPAwSr57kYjAUux+8E2j0q0Fxpn8M9VoyfGiRI8Kfktz9NcYMCenwY5RnZxnF1WTu3TGiYipirIzacLL3VVGFg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"cac": "^6.7.14",
|
||||
"debug": "^4.3.6",
|
||||
"debug": "^4.3.7",
|
||||
"es-module-lexer": "^1.5.4",
|
||||
"pathe": "^1.1.2",
|
||||
"vite": "^5.0.0"
|
||||
}
|
||||
},
|
||||
"vitest": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/vitest/-/vitest-2.1.3.tgz",
|
||||
"integrity": "sha512-Zrxbg/WiIvUP2uEzelDNTXmEMJXuzJ1kCpbDvaKByFA9MNeO95V+7r/3ti0qzJzrxdyuUw5VduN7k+D3VmVOSA==",
|
||||
"version": "2.1.8",
|
||||
"resolved": "https://registry.npmjs.org/vitest/-/vitest-2.1.8.tgz",
|
||||
"integrity": "sha512-1vBKTZskHw/aosXqQUlVWWlGUxSJR8YtiyZDJAFeW2kPAeX6S3Sool0mjspO+kXLuxVWlEDDowBAeqeAQefqLQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@vitest/expect": "2.1.3",
|
||||
"@vitest/mocker": "2.1.3",
|
||||
"@vitest/pretty-format": "^2.1.3",
|
||||
"@vitest/runner": "2.1.3",
|
||||
"@vitest/snapshot": "2.1.3",
|
||||
"@vitest/spy": "2.1.3",
|
||||
"@vitest/utils": "2.1.3",
|
||||
"chai": "^5.1.1",
|
||||
"debug": "^4.3.6",
|
||||
"magic-string": "^0.30.11",
|
||||
"@vitest/expect": "2.1.8",
|
||||
"@vitest/mocker": "2.1.8",
|
||||
"@vitest/pretty-format": "^2.1.8",
|
||||
"@vitest/runner": "2.1.8",
|
||||
"@vitest/snapshot": "2.1.8",
|
||||
"@vitest/spy": "2.1.8",
|
||||
"@vitest/utils": "2.1.8",
|
||||
"chai": "^5.1.2",
|
||||
"debug": "^4.3.7",
|
||||
"expect-type": "^1.1.0",
|
||||
"magic-string": "^0.30.12",
|
||||
"pathe": "^1.1.2",
|
||||
"std-env": "^3.7.0",
|
||||
"std-env": "^3.8.0",
|
||||
"tinybench": "^2.9.0",
|
||||
"tinyexec": "^0.3.0",
|
||||
"tinypool": "^1.0.0",
|
||||
"tinyexec": "^0.3.1",
|
||||
"tinypool": "^1.0.1",
|
||||
"tinyrainbow": "^1.2.0",
|
||||
"vite": "^5.0.0",
|
||||
"vite-node": "2.1.3",
|
||||
"vite-node": "2.1.8",
|
||||
"why-is-node-running": "^2.3.0"
|
||||
}
|
||||
},
|
||||
|
||||
12
package.json
12
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "jellyfin-web",
|
||||
"version": "10.10.7",
|
||||
"version": "10.11.0",
|
||||
"description": "Web interface for Jellyfin",
|
||||
"repository": "https://github.com/jellyfin/jellyfin-web",
|
||||
"license": "GPL-2.0-or-later",
|
||||
@@ -18,11 +18,12 @@
|
||||
"@types/markdown-it": "14.1.2",
|
||||
"@types/react": "18.3.11",
|
||||
"@types/react-dom": "18.3.1",
|
||||
"@types/react-lazy-load-image-component": "1.6.4",
|
||||
"@types/sortablejs": "1.15.8",
|
||||
"@typescript-eslint/eslint-plugin": "5.62.0",
|
||||
"@typescript-eslint/parser": "5.62.0",
|
||||
"@uupaa/dynamic-import-polyfill": "1.0.2",
|
||||
"@vitest/coverage-v8": "2.1.3",
|
||||
"@vitest/coverage-v8": "2.1.8",
|
||||
"autoprefixer": "10.4.20",
|
||||
"babel-loader": "9.2.1",
|
||||
"clean-webpack-plugin": "4.0.0",
|
||||
@@ -61,7 +62,7 @@
|
||||
"stylelint-scss": "5.3.2",
|
||||
"ts-loader": "9.5.1",
|
||||
"typescript": "5.6.3",
|
||||
"vitest": "2.1.3",
|
||||
"vitest": "2.1.8",
|
||||
"webpack": "5.95.0",
|
||||
"webpack-bundle-analyzer": "4.10.2",
|
||||
"webpack-cli": "5.1.4",
|
||||
@@ -79,14 +80,13 @@
|
||||
"@fontsource/noto-sans-sc": "5.1.0",
|
||||
"@fontsource/noto-sans-tc": "5.1.0",
|
||||
"@jellyfin/libass-wasm": "4.2.3",
|
||||
"@jellyfin/sdk": "0.0.0-unstable.202410250501",
|
||||
"@jellyfin/sdk": "0.0.0-unstable.202501020501",
|
||||
"@mui/icons-material": "5.16.7",
|
||||
"@mui/material": "5.16.7",
|
||||
"@mui/x-date-pickers": "7.20.0",
|
||||
"@react-hook/resize-observer": "2.0.2",
|
||||
"@tanstack/react-query": "5.59.13",
|
||||
"@tanstack/react-query-devtools": "5.59.13",
|
||||
"@types/react-lazy-load-image-component": "1.6.4",
|
||||
"abortcontroller-polyfill": "1.7.5",
|
||||
"blurhash": "2.0.5",
|
||||
"classlist.js": "https://github.com/eligrey/classList.js/archive/1.2.20180112.tar.gz",
|
||||
@@ -100,7 +100,7 @@
|
||||
"flv.js": "1.6.2",
|
||||
"headroom.js": "0.12.0",
|
||||
"history": "5.3.0",
|
||||
"hls.js": "1.5.16",
|
||||
"hls.js": "1.5.18",
|
||||
"intersection-observer": "0.12.2",
|
||||
"jellyfin-apiclient": "1.11.0",
|
||||
"jquery": "3.7.1",
|
||||
|
||||
@@ -16,6 +16,7 @@ import { useLocale } from 'hooks/useLocale';
|
||||
|
||||
import AppTabs from './components/AppTabs';
|
||||
import AppDrawer from './components/drawer/AppDrawer';
|
||||
import HelpButton from './components/toolbar/HelpButton';
|
||||
import { DASHBOARD_APP_PATHS } from './routes/routes';
|
||||
|
||||
import './AppOverrides.scss';
|
||||
@@ -68,6 +69,9 @@ export const Component: FC = () => {
|
||||
isDrawerAvailable={!isMediumScreen && isDrawerAvailable}
|
||||
isDrawerOpen={isDrawerOpen}
|
||||
onDrawerButtonClick={onToggleDrawer}
|
||||
buttons={
|
||||
<HelpButton />
|
||||
}
|
||||
>
|
||||
<AppTabs isDrawerOpen={isDrawerOpen} />
|
||||
</AppToolbar>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Dashboard, ExpandLess, ExpandMore, LibraryAdd, People, PlayCircle, Settings } from '@mui/icons-material';
|
||||
import Palette from '@mui/icons-material/Palette';
|
||||
import Collapse from '@mui/material/Collapse';
|
||||
import List from '@mui/material/List';
|
||||
import ListItem from '@mui/material/ListItem';
|
||||
@@ -6,7 +7,7 @@ import ListItemButton from '@mui/material/ListItemButton/ListItemButton';
|
||||
import ListItemIcon from '@mui/material/ListItemIcon';
|
||||
import ListItemText from '@mui/material/ListItemText';
|
||||
import ListSubheader from '@mui/material/ListSubheader';
|
||||
import React, { type MouseEvent, useCallback, useState } from 'react';
|
||||
import React, { useCallback, useState } from 'react';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
|
||||
import ListItemLink from 'components/ListItemLink';
|
||||
@@ -32,15 +33,11 @@ const ServerDrawerSection = () => {
|
||||
const [ isLibrarySectionOpen, setIsLibrarySectionOpen ] = useState(LIBRARY_PATHS.includes(location.pathname));
|
||||
const [ isPlaybackSectionOpen, setIsPlaybackSectionOpen ] = useState(PLAYBACK_PATHS.includes(location.pathname));
|
||||
|
||||
const onLibrarySectionClick = useCallback((e: MouseEvent) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
const onLibrarySectionClick = useCallback(() => {
|
||||
setIsLibrarySectionOpen(isOpen => !isOpen);
|
||||
}, []);
|
||||
|
||||
const onPlaybackSectionClick = useCallback((e: MouseEvent) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
const onPlaybackSectionClick = useCallback(() => {
|
||||
setIsPlaybackSectionOpen(isOpen => !isOpen);
|
||||
}, []);
|
||||
|
||||
@@ -69,6 +66,12 @@ const ServerDrawerSection = () => {
|
||||
<ListItemText primary={globalize.translate('General')} />
|
||||
</ListItemLink>
|
||||
</ListItem>
|
||||
<ListItemLink to='/dashboard/branding'>
|
||||
<ListItemIcon>
|
||||
<Palette />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary={globalize.translate('HeaderBranding')} />
|
||||
</ListItemLink>
|
||||
<ListItem disablePadding>
|
||||
<ListItemLink to='/dashboard/users'>
|
||||
<ListItemIcon>
|
||||
|
||||
36
src/apps/dashboard/components/toolbar/HelpButton.tsx
Normal file
36
src/apps/dashboard/components/toolbar/HelpButton.tsx
Normal file
@@ -0,0 +1,36 @@
|
||||
import HelpOutline from '@mui/icons-material/HelpOutline';
|
||||
import IconButton from '@mui/material/IconButton/IconButton';
|
||||
import Tooltip from '@mui/material/Tooltip/Tooltip';
|
||||
import React from 'react';
|
||||
import { Route, Routes } from 'react-router-dom';
|
||||
|
||||
import { HelpLinks } from 'apps/dashboard/constants/helpLinks';
|
||||
import globalize from 'lib/globalize';
|
||||
|
||||
const HelpButton = () => (
|
||||
<Routes>
|
||||
{
|
||||
HelpLinks.map(({ paths, url }) => paths.map(path => (
|
||||
<Route
|
||||
key={[url, path].join('-')}
|
||||
path={path}
|
||||
element={
|
||||
<Tooltip title={globalize.translate('Help')}>
|
||||
<IconButton
|
||||
href={url}
|
||||
rel='noopener noreferrer'
|
||||
target='_blank'
|
||||
size='large'
|
||||
color='inherit'
|
||||
>
|
||||
<HelpOutline />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
}
|
||||
/>
|
||||
))).flat()
|
||||
}
|
||||
</Routes>
|
||||
);
|
||||
|
||||
export default HelpButton;
|
||||
54
src/apps/dashboard/constants/helpLinks.ts
Normal file
54
src/apps/dashboard/constants/helpLinks.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
export const HelpLinks = [
|
||||
{
|
||||
paths: ['/dashboard/devices'],
|
||||
url: 'https://jellyfin.org/docs/general/server/devices'
|
||||
}, {
|
||||
paths: ['/dashboard/libraries'],
|
||||
url: 'https://jellyfin.org/docs/general/server/libraries'
|
||||
}, {
|
||||
paths: [
|
||||
'/dashboard/livetv',
|
||||
'/dashboard/livetv/tuner',
|
||||
'/dashboard/recordings'
|
||||
],
|
||||
url: 'https://jellyfin.org/docs/general/server/live-tv/'
|
||||
}, {
|
||||
paths: ['/dashboard/livetv/guide'],
|
||||
url: 'https://jellyfin.org/docs/general/server/live-tv/setup-guide#adding-guide-data'
|
||||
}, {
|
||||
paths: ['/dashboard/networking'],
|
||||
url: 'https://jellyfin.org/docs/general/networking/'
|
||||
}, {
|
||||
paths: ['/dashboard/playback/transcoding'],
|
||||
url: 'https://jellyfin.org/docs/general/server/transcoding'
|
||||
}, {
|
||||
paths: [
|
||||
'/dashboard/plugins',
|
||||
'/dashboard/plugins/catalog'
|
||||
],
|
||||
url: 'https://jellyfin.org/docs/general/server/plugins/'
|
||||
}, {
|
||||
paths: ['/dashboard/plugins/repositories'],
|
||||
url: 'https://jellyfin.org/docs/general/server/plugins/#repositories'
|
||||
}, {
|
||||
paths: [
|
||||
'/dashboard/branding',
|
||||
'/dashboard/settings'
|
||||
],
|
||||
url: 'https://jellyfin.org/docs/general/server/settings'
|
||||
}, {
|
||||
paths: ['/dashboard/tasks'],
|
||||
url: 'https://jellyfin.org/docs/general/server/tasks'
|
||||
}, {
|
||||
paths: ['/dashboard/users'],
|
||||
url: 'https://jellyfin.org/docs/general/server/users/adding-managing-users'
|
||||
}, {
|
||||
paths: [
|
||||
'/dashboard/users/access',
|
||||
'/dashboard/users/parentalcontrol',
|
||||
'/dashboard/users/password',
|
||||
'/dashboard/users/profile'
|
||||
],
|
||||
url: 'https://jellyfin.org/docs/general/server/users/'
|
||||
}
|
||||
];
|
||||
@@ -0,0 +1,35 @@
|
||||
import { Api } from '@jellyfin/sdk';
|
||||
import { getBrandingApi } from '@jellyfin/sdk/lib/utils/api/branding-api';
|
||||
import { queryOptions, useQuery } from '@tanstack/react-query';
|
||||
import type { AxiosRequestConfig } from 'axios';
|
||||
|
||||
import { useApi } from 'hooks/useApi';
|
||||
|
||||
export const QUERY_KEY = 'BrandingOptions';
|
||||
|
||||
const fetchBrandingOptions = async (
|
||||
api?: Api,
|
||||
options?: AxiosRequestConfig
|
||||
) => {
|
||||
if (!api) {
|
||||
console.error('[fetchBrandingOptions] no Api instance provided');
|
||||
throw new Error('No Api instance provided to fetchBrandingOptions');
|
||||
}
|
||||
|
||||
return getBrandingApi(api)
|
||||
.getBrandingOptions(options)
|
||||
.then(({ data }) => data);
|
||||
};
|
||||
|
||||
export const getBrandingOptionsQuery = (
|
||||
api?: Api
|
||||
) => queryOptions({
|
||||
queryKey: [ QUERY_KEY ],
|
||||
queryFn: ({ signal }) => fetchBrandingOptions(api, { signal }),
|
||||
enabled: !!api
|
||||
});
|
||||
|
||||
export const useBrandingOptions = () => {
|
||||
const { api } = useApi();
|
||||
return useQuery(getBrandingOptionsQuery(api));
|
||||
};
|
||||
@@ -2,6 +2,7 @@ import { AsyncRouteType, type AsyncRoute } from 'components/router/AsyncRoute';
|
||||
|
||||
export const ASYNC_ADMIN_ROUTES: AsyncRoute[] = [
|
||||
{ path: 'activity', type: AsyncRouteType.Dashboard },
|
||||
{ path: 'branding', type: AsyncRouteType.Dashboard },
|
||||
{ path: 'playback/trickplay', type: AsyncRouteType.Dashboard },
|
||||
{ path: 'plugins/:pluginId', page: 'plugins/plugin', type: AsyncRouteType.Dashboard },
|
||||
{ path: 'users', type: AsyncRouteType.Dashboard },
|
||||
|
||||
176
src/apps/dashboard/routes/branding/index.tsx
Normal file
176
src/apps/dashboard/routes/branding/index.tsx
Normal file
@@ -0,0 +1,176 @@
|
||||
import type { BrandingOptions } from '@jellyfin/sdk/lib/generated-client/models/branding-options';
|
||||
import { getConfigurationApi } from '@jellyfin/sdk/lib/utils/api/configuration-api';
|
||||
import Alert from '@mui/material/Alert';
|
||||
import Box from '@mui/material/Box';
|
||||
import Button from '@mui/material/Button';
|
||||
import FormControlLabel from '@mui/material/FormControlLabel';
|
||||
import Stack from '@mui/material/Stack';
|
||||
import Switch from '@mui/material/Switch';
|
||||
import TextField from '@mui/material/TextField';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import React, { useCallback, useEffect, useState } from 'react';
|
||||
import { type ActionFunctionArgs, Form, useActionData } from 'react-router-dom';
|
||||
|
||||
import { getBrandingOptionsQuery, QUERY_KEY, useBrandingOptions } from 'apps/dashboard/features/branding/api/useBrandingOptions';
|
||||
import Loading from 'components/loading/LoadingComponent';
|
||||
import Page from 'components/Page';
|
||||
import ServerConnections from 'components/ServerConnections';
|
||||
import globalize from 'lib/globalize';
|
||||
import { queryClient } from 'utils/query/queryClient';
|
||||
|
||||
interface ActionData {
|
||||
isSaved: boolean
|
||||
}
|
||||
|
||||
const BRANDING_CONFIG_KEY = 'branding';
|
||||
const BrandingOption = {
|
||||
CustomCss: 'CustomCss',
|
||||
LoginDisclaimer: 'LoginDisclaimer',
|
||||
SplashscreenEnabled: 'SplashscreenEnabled'
|
||||
};
|
||||
|
||||
export const action = async ({ request }: ActionFunctionArgs) => {
|
||||
const api = ServerConnections.getCurrentApi();
|
||||
if (!api) throw new Error('No Api instance available');
|
||||
|
||||
const formData = await request.formData();
|
||||
const data = Object.fromEntries(formData);
|
||||
|
||||
const brandingOptions: BrandingOptions = {
|
||||
CustomCss: data.CustomCss?.toString(),
|
||||
LoginDisclaimer: data.LoginDisclaimer?.toString(),
|
||||
SplashscreenEnabled: data.SplashscreenEnabled?.toString() === 'on'
|
||||
};
|
||||
|
||||
await getConfigurationApi(api)
|
||||
.updateNamedConfiguration({
|
||||
key: BRANDING_CONFIG_KEY,
|
||||
body: JSON.stringify(brandingOptions)
|
||||
});
|
||||
|
||||
void queryClient.invalidateQueries({
|
||||
queryKey: [ QUERY_KEY ]
|
||||
});
|
||||
|
||||
return {
|
||||
isSaved: true
|
||||
};
|
||||
};
|
||||
|
||||
export const loader = () => {
|
||||
return queryClient.ensureQueryData(
|
||||
getBrandingOptionsQuery(ServerConnections.getCurrentApi()));
|
||||
};
|
||||
|
||||
export const Component = () => {
|
||||
const actionData = useActionData() as ActionData | undefined;
|
||||
const [ isSubmitting, setIsSubmitting ] = useState(false);
|
||||
|
||||
const {
|
||||
data: defaultBrandingOptions,
|
||||
isPending
|
||||
} = useBrandingOptions();
|
||||
const [ brandingOptions, setBrandingOptions ] = useState(defaultBrandingOptions || {});
|
||||
|
||||
useEffect(() => {
|
||||
setIsSubmitting(false);
|
||||
}, [ actionData ]);
|
||||
|
||||
const onSubmit = useCallback(() => {
|
||||
setIsSubmitting(true);
|
||||
}, []);
|
||||
|
||||
const setSplashscreenEnabled = useCallback((_: React.ChangeEvent<HTMLInputElement>, isEnabled: boolean) => {
|
||||
setBrandingOptions({
|
||||
...brandingOptions,
|
||||
[BrandingOption.SplashscreenEnabled]: isEnabled
|
||||
});
|
||||
}, [ brandingOptions ]);
|
||||
|
||||
const setBrandingOption = useCallback((event: React.ChangeEvent<HTMLTextAreaElement | HTMLInputElement>) => {
|
||||
if (Object.keys(BrandingOption).includes(event.target.name)) {
|
||||
setBrandingOptions({
|
||||
...brandingOptions,
|
||||
[event.target.name]: event.target.value
|
||||
});
|
||||
}
|
||||
}, [ brandingOptions ]);
|
||||
|
||||
if (isPending) return <Loading />;
|
||||
|
||||
return (
|
||||
<Page
|
||||
id='brandingPage'
|
||||
className='mainAnimatedPage type-interior'
|
||||
>
|
||||
<Box className='content-primary'>
|
||||
<Form
|
||||
method='POST'
|
||||
onSubmit={onSubmit}
|
||||
>
|
||||
<Stack spacing={3}>
|
||||
<Typography variant='h1'>
|
||||
{globalize.translate('HeaderBranding')}
|
||||
</Typography>
|
||||
|
||||
{!isSubmitting && actionData?.isSaved && (
|
||||
<Alert severity='success'>
|
||||
{globalize.translate('SettingsSaved')}
|
||||
</Alert>
|
||||
)}
|
||||
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Switch
|
||||
name={BrandingOption.SplashscreenEnabled}
|
||||
checked={brandingOptions?.SplashscreenEnabled}
|
||||
onChange={setSplashscreenEnabled}
|
||||
/>
|
||||
}
|
||||
label={globalize.translate('EnableSplashScreen')}
|
||||
/>
|
||||
|
||||
<TextField
|
||||
fullWidth
|
||||
multiline
|
||||
minRows={5}
|
||||
maxRows={5}
|
||||
InputProps={{
|
||||
className: 'textarea-mono'
|
||||
}}
|
||||
name={BrandingOption.LoginDisclaimer}
|
||||
label={globalize.translate('LabelLoginDisclaimer')}
|
||||
helperText={globalize.translate('LabelLoginDisclaimerHelp')}
|
||||
value={brandingOptions?.LoginDisclaimer}
|
||||
onChange={setBrandingOption}
|
||||
/>
|
||||
|
||||
<TextField
|
||||
fullWidth
|
||||
multiline
|
||||
minRows={5}
|
||||
maxRows={20}
|
||||
InputProps={{
|
||||
className: 'textarea-mono'
|
||||
}}
|
||||
name={BrandingOption.CustomCss}
|
||||
label={globalize.translate('LabelCustomCss')}
|
||||
helperText={globalize.translate('LabelCustomCssHelp')}
|
||||
value={brandingOptions?.CustomCss}
|
||||
onChange={setBrandingOption}
|
||||
/>
|
||||
|
||||
<Button
|
||||
type='submit'
|
||||
size='large'
|
||||
>
|
||||
{globalize.translate('Save')}
|
||||
</Button>
|
||||
</Stack>
|
||||
</Form>
|
||||
</Box>
|
||||
</Page>
|
||||
);
|
||||
};
|
||||
|
||||
Component.displayName = 'BrandingPage';
|
||||
@@ -150,7 +150,6 @@ const PlaybackTrickplay: FC = () => {
|
||||
<div className='verticalSection'>
|
||||
<SectionTitleContainer
|
||||
title={globalize.translate('Trickplay')}
|
||||
isLinkVisible={false}
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -304,7 +304,6 @@ const PluginPage: FC = () => {
|
||||
return (
|
||||
<Page
|
||||
id='addPluginPage'
|
||||
title={pluginDetails?.name || pluginName}
|
||||
className='mainAnimatedPage type-interior'
|
||||
>
|
||||
<Container className='content-primary'>
|
||||
|
||||
@@ -247,7 +247,6 @@ const UserLibraryAccess = () => {
|
||||
<div className='verticalSection'>
|
||||
<SectionTitleContainer
|
||||
title={userName}
|
||||
url='https://jellyfin.org/docs/general/server/users/'
|
||||
/>
|
||||
</div>
|
||||
<SectionTabs activeTab='userlibraryaccess'/>
|
||||
|
||||
@@ -12,7 +12,7 @@ import AccessContainer from '../../../../components/dashboard/users/AccessContai
|
||||
import CheckBoxElement from '../../../../elements/CheckBoxElement';
|
||||
import Page from '../../../../components/Page';
|
||||
|
||||
type userInput = {
|
||||
type UserInput = {
|
||||
Name?: string;
|
||||
Password?: string;
|
||||
};
|
||||
@@ -110,7 +110,7 @@ const UserNew = () => {
|
||||
loadUser();
|
||||
|
||||
const saveUser = () => {
|
||||
const userInput: userInput = {};
|
||||
const userInput: UserInput = {};
|
||||
userInput.Name = (page.querySelector('#txtUsername') as HTMLInputElement).value;
|
||||
userInput.Password = (page.querySelector('#txtPassword') as HTMLInputElement).value;
|
||||
window.ApiClient.createUser(userInput).then(function (user) {
|
||||
@@ -188,7 +188,6 @@ const UserNew = () => {
|
||||
<div className='verticalSection'>
|
||||
<SectionTitleContainer
|
||||
title={globalize.translate('HeaderAddUser')}
|
||||
url='https://jellyfin.org/docs/general/server/users/'
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -170,7 +170,6 @@ const UserProfiles = () => {
|
||||
btnClassName='fab submit sectionTitleButton'
|
||||
btnTitle='ButtonAddUser'
|
||||
btnIcon='add'
|
||||
url='https://jellyfin.org/docs/general/server/users/adding-managing-users'
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -65,7 +65,6 @@ const UserParentalControl = () => {
|
||||
const [ userName, setUserName ] = useState('');
|
||||
const [ parentalRatings, setParentalRatings ] = useState<ParentalRating[]>([]);
|
||||
const [ unratedItems, setUnratedItems ] = useState<UnratedNamedItem[]>([]);
|
||||
const [ maxParentalRating, setMaxParentalRating ] = useState<string>();
|
||||
const [ accessSchedules, setAccessSchedules ] = useState<AccessSchedule[]>([]);
|
||||
const [ allowedTags, setAllowedTags ] = useState<string[]>([]);
|
||||
const [ blockedTags, setBlockedTags ] = useState<string[]>([]);
|
||||
@@ -164,13 +163,15 @@ const UserParentalControl = () => {
|
||||
populateRatings(allParentalRatings);
|
||||
|
||||
let ratingValue = '';
|
||||
allParentalRatings.forEach(rating => {
|
||||
if (rating.Value != null && user.Policy?.MaxParentalRating != null && user.Policy.MaxParentalRating >= rating.Value) {
|
||||
ratingValue = `${rating.Value}`;
|
||||
}
|
||||
});
|
||||
if (user.Policy?.MaxParentalRating) {
|
||||
allParentalRatings.forEach(rating => {
|
||||
if (rating.Value && user.Policy?.MaxParentalRating && user.Policy.MaxParentalRating >= rating.Value) {
|
||||
ratingValue = `${rating.Value}`;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
setMaxParentalRating(ratingValue);
|
||||
(page.querySelector('#selectMaxParentalRating') as HTMLSelectElement).value = String(ratingValue);
|
||||
|
||||
if (user.Policy?.IsAdministrator) {
|
||||
(page.querySelector('.accessScheduleSection') as HTMLDivElement).classList.add('hide');
|
||||
@@ -328,24 +329,11 @@ const UserParentalControl = () => {
|
||||
};
|
||||
}, [setAllowedTags, setBlockedTags, loadData, userId]);
|
||||
|
||||
useEffect(() => {
|
||||
const page = element.current;
|
||||
|
||||
if (!page) {
|
||||
console.error('[userparentalcontrol] Unexpected null page reference');
|
||||
return;
|
||||
}
|
||||
|
||||
(page.querySelector('#selectMaxParentalRating') as HTMLSelectElement).value = String(maxParentalRating);
|
||||
}, [maxParentalRating, parentalRatings]);
|
||||
|
||||
const optionMaxParentalRating = () => {
|
||||
let content = '';
|
||||
content += '<option value=\'\'></option>';
|
||||
for (const rating of parentalRatings) {
|
||||
if (rating.Value != null) {
|
||||
content += `<option value='${rating.Value}'>${escapeHTML(rating.Name)}</option>`;
|
||||
}
|
||||
content += `<option value='${rating.Value}'>${escapeHTML(rating.Name)}</option>`;
|
||||
}
|
||||
return content;
|
||||
};
|
||||
@@ -374,7 +362,6 @@ const UserParentalControl = () => {
|
||||
<div className='verticalSection'>
|
||||
<SectionTitleContainer
|
||||
title={userName}
|
||||
url='https://jellyfin.org/docs/general/server/users/'
|
||||
/>
|
||||
</div>
|
||||
<SectionTabs activeTab='userparentalcontrol'/>
|
||||
@@ -418,7 +405,6 @@ const UserParentalControl = () => {
|
||||
btnClassName='fab submit sectionTitleButton'
|
||||
btnTitle='Add'
|
||||
btnIcon='add'
|
||||
isLinkVisible={false}
|
||||
/>
|
||||
<div className='fieldDescription'>
|
||||
{globalize.translate('AllowContentWithTagsHelp')}
|
||||
@@ -443,7 +429,6 @@ const UserParentalControl = () => {
|
||||
btnClassName='fab submit sectionTitleButton'
|
||||
btnTitle='Add'
|
||||
btnIcon='add'
|
||||
isLinkVisible={false}
|
||||
/>
|
||||
<div className='fieldDescription'>
|
||||
{globalize.translate('BlockContentWithTagsHelp')}
|
||||
@@ -467,7 +452,6 @@ const UserParentalControl = () => {
|
||||
btnClassName='fab submit sectionTitleButton'
|
||||
btnTitle='Add'
|
||||
btnIcon='add'
|
||||
isLinkVisible={false}
|
||||
/>
|
||||
<p>{globalize.translate('HeaderAccessScheduleHelp')}</p>
|
||||
<div className='accessScheduleList paperList'>
|
||||
|
||||
@@ -42,7 +42,6 @@ const UserPassword = () => {
|
||||
<div className='verticalSection'>
|
||||
<SectionTitleContainer
|
||||
title={userName}
|
||||
url='https://jellyfin.org/docs/general/server/users/'
|
||||
/>
|
||||
</div>
|
||||
<SectionTabs activeTab='userpassword'/>
|
||||
|
||||
@@ -290,7 +290,6 @@ const UserEdit = () => {
|
||||
<div className='verticalSection'>
|
||||
<SectionTitleContainer
|
||||
title={userDto?.Name || ''}
|
||||
url='https://jellyfin.org/docs/general/server/users/'
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -65,17 +65,20 @@ const RemotePlayMenu: FC<RemotePlayMenuProps> = ({
|
||||
open={open}
|
||||
onClose={onMenuClose}
|
||||
>
|
||||
{!isChromecastPluginLoaded && ([
|
||||
<MenuItem key='cast-unsupported-item' disabled>
|
||||
{!isChromecastPluginLoaded && (
|
||||
<MenuItem disabled>
|
||||
<ListItemIcon>
|
||||
<Warning />
|
||||
</ListItemIcon>
|
||||
<ListItemText>
|
||||
{globalize.translate('GoogleCastUnsupported')}
|
||||
</ListItemText>
|
||||
</MenuItem>,
|
||||
<Divider key='cast-unsupported-divider' />
|
||||
])}
|
||||
</MenuItem>
|
||||
)}
|
||||
|
||||
{!isChromecastPluginLoaded && playbackTargets.length > 0 && (
|
||||
<Divider />
|
||||
)}
|
||||
|
||||
{playbackTargets.map(target => (
|
||||
<MenuItem
|
||||
|
||||
@@ -2,7 +2,7 @@ import { CollectionType } from '@jellyfin/sdk/lib/generated-client/models/collec
|
||||
import { ItemFields } from '@jellyfin/sdk/lib/generated-client/models/item-fields';
|
||||
import { ImageType } from '@jellyfin/sdk/lib/generated-client/models/image-type';
|
||||
import { BaseItemKind } from '@jellyfin/sdk/lib/generated-client/models/base-item-kind';
|
||||
import { ItemSortBy } from '@jellyfin/sdk/lib/models/api/item-sort-by';
|
||||
import { ItemSortBy } from '@jellyfin/sdk/lib/generated-client/models/item-sort-by';
|
||||
import { SortOrder } from '@jellyfin/sdk/lib/generated-client/models/sort-order';
|
||||
import React, { type FC } from 'react';
|
||||
import { useGetItems } from 'hooks/useFetchItems';
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { BaseItemKind } from '@jellyfin/sdk/lib/generated-client/models/base-item-kind';
|
||||
import { CollectionType } from '@jellyfin/sdk/lib/generated-client/models/collection-type';
|
||||
import { ImageType } from '@jellyfin/sdk/lib/generated-client';
|
||||
import { ItemSortBy } from '@jellyfin/sdk/lib/models/api/item-sort-by';
|
||||
import { ItemSortBy } from '@jellyfin/sdk/lib/generated-client/models/item-sort-by';
|
||||
import React, { type FC, useCallback } from 'react';
|
||||
import Box from '@mui/material/Box';
|
||||
import classNames from 'classnames';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { ItemSortBy } from '@jellyfin/sdk/lib/models/api/item-sort-by';
|
||||
import { ItemSortBy } from '@jellyfin/sdk/lib/generated-client/models/item-sort-by';
|
||||
import React, { FC, useCallback } from 'react';
|
||||
import { IconButton } from '@mui/material';
|
||||
import ShuffleIcon from '@mui/icons-material/Shuffle';
|
||||
|
||||
@@ -13,7 +13,7 @@ import SortByAlphaIcon from '@mui/icons-material/SortByAlpha';
|
||||
import globalize from 'lib/globalize';
|
||||
import { LibraryViewSettings } from 'types/library';
|
||||
import { LibraryTab } from 'types/libraryTab';
|
||||
import { ItemSortBy } from '@jellyfin/sdk/lib/models/api/item-sort-by';
|
||||
import { ItemSortBy } from '@jellyfin/sdk/lib/generated-client/models/item-sort-by';
|
||||
import { SortOrder } from '@jellyfin/sdk/lib/generated-client';
|
||||
|
||||
type SortOption = {
|
||||
|
||||
@@ -5,8 +5,6 @@ import globalize from '../../../lib/globalize';
|
||||
import { clearBackdrop } from '../../../components/backdrop/backdrop';
|
||||
import layoutManager from '../../../components/layoutManager';
|
||||
import Page from '../../../components/Page';
|
||||
import { EventType } from 'types/eventType';
|
||||
import Events from 'utils/events';
|
||||
|
||||
import '../../../elements/emby-tabs/emby-tabs';
|
||||
import '../../../elements/emby-button/emby-button';
|
||||
@@ -34,8 +32,6 @@ const Home = () => {
|
||||
const mainTabsManager = useMemo(() => import('../../../components/maintabsmanager'), []);
|
||||
const tabController = useRef<ControllerProps | null>();
|
||||
const tabControllers = useMemo<ControllerProps[]>(() => [], []);
|
||||
|
||||
const documentRef = useRef<Document>(document);
|
||||
const element = useRef<HTMLDivElement>(null);
|
||||
|
||||
const setTitle = async () => {
|
||||
@@ -126,7 +122,7 @@ const Home = () => {
|
||||
} else if (currentTabController?.onResume) {
|
||||
currentTabController.onResume({});
|
||||
}
|
||||
(documentRef.current.querySelector('.skinHeader') as HTMLDivElement).classList.add('noHomeButtonHeader');
|
||||
(document.querySelector('.skinHeader') as HTMLDivElement).classList.add('noHomeButtonHeader');
|
||||
}, [ initialTabIndex, mainTabsManager ]);
|
||||
|
||||
const onPause = useCallback(() => {
|
||||
@@ -134,32 +130,17 @@ const Home = () => {
|
||||
if (currentTabController?.onPause) {
|
||||
currentTabController.onPause();
|
||||
}
|
||||
(documentRef.current.querySelector('.skinHeader') as HTMLDivElement).classList.remove('noHomeButtonHeader');
|
||||
(document.querySelector('.skinHeader') as HTMLDivElement).classList.remove('noHomeButtonHeader');
|
||||
}, []);
|
||||
|
||||
const renderHome = useCallback(() => {
|
||||
void onSetTabs();
|
||||
void onResume();
|
||||
}, [ onResume, onSetTabs ]);
|
||||
|
||||
useEffect(() => {
|
||||
if (documentRef.current?.querySelector('.headerTabs')) {
|
||||
renderHome();
|
||||
}
|
||||
void onSetTabs();
|
||||
|
||||
void onResume();
|
||||
return () => {
|
||||
onPause();
|
||||
};
|
||||
}, [onPause, renderHome]);
|
||||
|
||||
useEffect(() => {
|
||||
const doc = documentRef.current;
|
||||
if (doc) Events.on(doc, EventType.HEADER_RENDERED, renderHome);
|
||||
|
||||
return () => {
|
||||
if (doc) Events.off(doc, EventType.HEADER_RENDERED, renderHome);
|
||||
};
|
||||
}, [ renderHome ]);
|
||||
}, [ onPause, onResume, onSetTabs ]);
|
||||
|
||||
return (
|
||||
<div ref={element}>
|
||||
|
||||
31
src/assets/img/devices/webos.svg
Normal file
31
src/assets/img/devices/webos.svg
Normal file
@@ -0,0 +1,31 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 174 43">
|
||||
<defs>
|
||||
<style>
|
||||
.cls-1 {
|
||||
fill: none;
|
||||
}
|
||||
|
||||
.cls-2 {
|
||||
fill: #fff;
|
||||
}
|
||||
</style>
|
||||
</defs>
|
||||
<!-- Generator: Adobe Illustrator 28.6.0, SVG Export Plug-In . SVG Version: 1.2.0 Build 709) -->
|
||||
<g>
|
||||
<g id="Layer_1">
|
||||
<g id="Group_2">
|
||||
<g id="webOS_OSE_logo_gray">
|
||||
<g id="Group_1">
|
||||
<path id="Path_1" class="cls-2" d="M142.8,28.9c0,8.9,6.1,13.3,14.9,13.3s14.9-3.9,14.9-10.5h0c0-7.6-5-9.2-14.9-12.1-6.9-1.8-10.9-3.6-10.9-8h0c0-5.1,3.8-7.4,10.8-7.4h0c6.6,0,10.9,2.3,10.9,9.2h3c0-8.9-5.5-12.2-13.8-12.2s-13.8,3.3-13.8,10,5,9,13.8,11.5c7.3,2,12,2.9,12,9s-4.4,7.5-12,7.5h0c-6.8,0-11.9-3.1-11.9-10.3h-3Z"/>
|
||||
<path id="Path_2" class="cls-2" d="M120.1,1.2c-11.3,0-20.5,9.2-20.5,20.5,0,11.3,9.2,20.5,20.5,20.5,11.3,0,20.5-9.2,20.5-20.5,0-11.3-9.2-20.5-20.5-20.5,0,0,0,0,0,0M120.1,39.2c-9.7,0-17.5-7.8-17.5-17.5,0-9.7,7.8-17.5,17.5-17.5,9.7,0,17.5,7.8,17.5,17.5,0,9.7-7.8,17.5-17.5,17.5"/>
|
||||
<path id="Path_3" class="cls-2" d="M84.2,12.3c-4.2,0-7.2,1.6-9.2,4.5V1.8h-3v25.5h3c0-7.5,3.3-12,9.2-12s9.2,4.4,9.2,12-3.3,12-9.2,12-7.4-2.5-8.6-7h-3.1c1.3,6.3,5.4,10,11.7,10s12.2-5.5,12.2-14.9-4.4-14.9-12.2-14.9"/>
|
||||
<path id="Path_4" class="cls-2" d="M55.4,39.1c-5.9,0-9.2-4.4-9.2-11.9h21.4c0-9.4-4.4-14.9-12.2-14.9s-12.2,5.5-12.2,14.9,4.4,14.9,12.2,14.9,10.4-3.6,11.7-10h-3.1c-1.2,4.4-4.2,6.9-8.6,6.9M55.4,15.3c5,0,8.2,3.3,9,8.9h-18c.8-5.7,4-8.9,9-8.9"/>
|
||||
<path id="Path_5" class="cls-2" d="M14.4,41.6l7.6-24.1,7.6,24.1h3.4l9.1-28.8h-3.1l-7.6,24.2-7.6-24.2h-3.3l-7.6,24.2L5.1,12.8H2l9.1,28.8h3.4Z"/>
|
||||
</g>
|
||||
</g>
|
||||
<rect id="Rectangle_1" class="cls-1" width="174" height="43"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.8 KiB |
@@ -150,25 +150,21 @@ const ConnectionRequired: FunctionComponent<ConnectionRequiredProps> = ({
|
||||
useEffect(() => {
|
||||
// Check connection status on initial page load
|
||||
const apiClient = ServerConnections.currentApiClient();
|
||||
const connection = Promise.resolve(ServerConnections.firstConnection ? null : ServerConnections.connect());
|
||||
connection.then(firstConnection => {
|
||||
console.debug('[ConnectionRequired] connection state', firstConnection?.State);
|
||||
ServerConnections.firstConnection = true;
|
||||
const firstConnection = ServerConnections.firstConnection;
|
||||
console.debug('[ConnectionRequired] connection state', firstConnection?.State);
|
||||
ServerConnections.firstConnection = null;
|
||||
|
||||
if (firstConnection && firstConnection.State !== ConnectionState.SignedIn && !apiClient?.isLoggedIn()) {
|
||||
handleIncompleteWizard(firstConnection)
|
||||
.catch(err => {
|
||||
console.error('[ConnectionRequired] could not start wizard', err);
|
||||
});
|
||||
} else {
|
||||
validateUserAccess()
|
||||
.catch(err => {
|
||||
console.error('[ConnectionRequired] could not validate user access', err);
|
||||
});
|
||||
}
|
||||
}).catch(err => {
|
||||
console.error('[ConnectionRequired] failed to connect', err);
|
||||
});
|
||||
if (firstConnection && firstConnection.State !== ConnectionState.SignedIn && !apiClient?.isLoggedIn()) {
|
||||
handleIncompleteWizard(firstConnection)
|
||||
.catch(err => {
|
||||
console.error('[ConnectionRequired] could not start wizard', err);
|
||||
});
|
||||
} else {
|
||||
validateUserAccess()
|
||||
.catch(err => {
|
||||
console.error('[ConnectionRequired] could not validate user access', err);
|
||||
});
|
||||
}
|
||||
}, [handleIncompleteWizard, validateUserAccess]);
|
||||
|
||||
if (isLoading) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { type FC, type PropsWithChildren, type HTMLAttributes, useEffect, useRef } from 'react';
|
||||
import React, { type FC, type PropsWithChildren, type HTMLAttributes, useEffect, useRef, StrictMode } from 'react';
|
||||
|
||||
import viewManager from './viewManager/viewManager';
|
||||
|
||||
@@ -57,18 +57,20 @@ const Page: FC<PropsWithChildren<PageProps & HTMLAttributes<HTMLDivElement>>> =
|
||||
}, [ element, isNowPlayingBarEnabled, isThemeMediaSupported ]);
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={element}
|
||||
id={id}
|
||||
data-role='page'
|
||||
className={`page ${className}`}
|
||||
data-title={title}
|
||||
data-backbutton={isBackButtonEnabled}
|
||||
data-menubutton={isMenuButtonEnabled}
|
||||
data-backdroptype={backDropType}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
<StrictMode>
|
||||
<div
|
||||
ref={element}
|
||||
id={id}
|
||||
data-role='page'
|
||||
className={`page ${className}`}
|
||||
data-title={title}
|
||||
data-backbutton={isBackButtonEnabled}
|
||||
data-menubutton={isMenuButtonEnabled}
|
||||
data-backdroptype={backDropType}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
</StrictMode>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// NOTE: This is used for jsdoc return type
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
import { Api } from '@jellyfin/sdk';
|
||||
import { MINIMUM_VERSION } from '@jellyfin/sdk/lib/versions';
|
||||
import { ConnectionManager, Credentials, ApiClient } from 'jellyfin-apiclient';
|
||||
|
||||
@@ -6,6 +9,7 @@ import Dashboard from '../utils/dashboard';
|
||||
import Events from '../utils/events.ts';
|
||||
import { setUserInfo } from '../scripts/settings/userSettings';
|
||||
import appSettings from '../scripts/settings/appSettings';
|
||||
import { toApi } from 'utils/jellyfin-apiclient/compat';
|
||||
|
||||
const normalizeImageOptions = options => {
|
||||
if (!options.quality && (options.maxWidth || options.width || options.maxHeight || options.height || options.fillWidth || options.fillHeight)) {
|
||||
@@ -111,6 +115,17 @@ class ServerConnections extends ConnectionManager {
|
||||
return apiClient;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the Api that is currently connected.
|
||||
* @returns {Api|undefined} The current Api instance.
|
||||
*/
|
||||
getCurrentApi() {
|
||||
const apiClient = this.currentApiClient();
|
||||
if (!apiClient) return;
|
||||
|
||||
return toApi(apiClient);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the ApiClient that is currently connected or throws if not defined.
|
||||
* @async
|
||||
|
||||
@@ -7,7 +7,7 @@ export default async function (text, title) {
|
||||
// Modals seem to be blocked on Web OS and Tizen 2.x
|
||||
const canUseNativeAlert = !!(
|
||||
!browser.web0s
|
||||
&& !(browser.tizenVersion && (browser.tizenVersion < 3 || browser.tizenVersion >= 8))
|
||||
&& !(browser.tizenVersion && browser.tizenVersion < 3)
|
||||
&& browser.tv
|
||||
&& window.alert
|
||||
);
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
@import '../../styles/mixins';
|
||||
|
||||
.alphaPicker {
|
||||
text-align: center;
|
||||
display: flex;
|
||||
@@ -13,8 +11,8 @@
|
||||
|
||||
.alphaPicker-fixed {
|
||||
position: fixed;
|
||||
|
||||
@include conditional-max(bottom, 5.5em, env(safe-area-inset-bottom));
|
||||
bottom: 5.5em;
|
||||
bottom: max(env(safe-area-inset-bottom), 5.5em);
|
||||
}
|
||||
|
||||
.alphaPickerRow {
|
||||
@@ -47,7 +45,8 @@
|
||||
|
||||
@media all and (max-height: 50em) {
|
||||
.alphaPicker-fixed {
|
||||
@include conditional-max(bottom, 5em, env(safe-area-inset-bottom));
|
||||
bottom: 5em;
|
||||
bottom: max(env(safe-area-inset-bottom), 5em);
|
||||
}
|
||||
|
||||
.alphaPickerButton-vertical {
|
||||
@@ -106,27 +105,32 @@
|
||||
}
|
||||
|
||||
.alphaPicker-fixed.alphaPicker-tv {
|
||||
@include conditional-max(bottom, 1%, env(safe-area-inset-bottom));
|
||||
bottom: 1%;
|
||||
bottom: max(env(safe-area-inset-bottom), 1%);
|
||||
}
|
||||
|
||||
.alphaPicker-fixed-right {
|
||||
[dir="ltr"] & {
|
||||
@include conditional-max(right, 0.4em, env(safe-area-inset-right));
|
||||
right: 0.4em;
|
||||
right: max(env(safe-area-inset-right), 0.4em);
|
||||
}
|
||||
|
||||
[dir="rtl"] & {
|
||||
@include conditional-max(left, 0.4em, env(safe-area-inset-left));
|
||||
left: 0.4em;
|
||||
left: max(env(safe-area-inset-left), 0.4em);
|
||||
}
|
||||
}
|
||||
|
||||
@media all and (min-width: 62.5em) {
|
||||
.alphaPicker-fixed-right {
|
||||
[dir="ltr"] & {
|
||||
@include conditional-max(right, 1em, env(safe-area-inset-right));
|
||||
right: 1em;
|
||||
right: max(env(safe-area-inset-right), 1em);
|
||||
}
|
||||
|
||||
[dir="rtl"] & {
|
||||
@include conditional-max(left, 1em, env(safe-area-inset-left));
|
||||
left: 1em;
|
||||
left: max(env(safe-area-inset-left), 1em);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ function useNativeConfirm() {
|
||||
// webOS seems to block modals
|
||||
// Tizen 2.x seems to block modals
|
||||
return !browser.web0s
|
||||
&& !(browser.tizenVersion && (browser.tizenVersion < 3 || browser.tizenVersion >= 8))
|
||||
&& !(browser.tizenVersion && browser.tizenVersion < 3)
|
||||
&& browser.tv
|
||||
&& window.confirm;
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ function tryRemoveElement(elem) {
|
||||
}
|
||||
}
|
||||
|
||||
function DialogHashHandler(dlg, hash, resolve) {
|
||||
function DialogHashHandler(dlg, hash, resolve, dlgOptions) {
|
||||
const self = this;
|
||||
self.originalUrl = window.location.href;
|
||||
const activeElement = document.activeElement;
|
||||
@@ -158,7 +158,7 @@ function DialogHashHandler(dlg, hash, resolve) {
|
||||
|
||||
dlg.classList.remove('hide');
|
||||
|
||||
addBackdropOverlay(dlg);
|
||||
addBackdropOverlay(dlg, dlgOptions);
|
||||
|
||||
dlg.classList.add('opened');
|
||||
dlg.dispatchEvent(new CustomEvent('open', {
|
||||
@@ -193,7 +193,7 @@ function DialogHashHandler(dlg, hash, resolve) {
|
||||
}
|
||||
}
|
||||
|
||||
function addBackdropOverlay(dlg) {
|
||||
function addBackdropOverlay(dlg, dlgOptions = {}) {
|
||||
const backdrop = document.createElement('div');
|
||||
backdrop.classList.add('dialogBackdrop');
|
||||
|
||||
@@ -205,35 +205,33 @@ function addBackdropOverlay(dlg) {
|
||||
void backdrop.offsetWidth;
|
||||
backdrop.classList.add('dialogBackdropOpened');
|
||||
|
||||
let clickedElement;
|
||||
if (!dlgOptions.preventCloseOnClick) {
|
||||
dom.addEventListener((dlg.dialogContainer || backdrop), 'click', e => {
|
||||
if (e.target === dlg.dialogContainer) {
|
||||
close(dlg);
|
||||
}
|
||||
}, {
|
||||
passive: true
|
||||
});
|
||||
}
|
||||
|
||||
dom.addEventListener((dlg.dialogContainer || backdrop), 'mousedown', e => {
|
||||
clickedElement = e.target;
|
||||
});
|
||||
|
||||
dom.addEventListener((dlg.dialogContainer || backdrop), 'click', e => {
|
||||
if (e.target === dlg.dialogContainer && e.target == clickedElement) {
|
||||
close(dlg);
|
||||
}
|
||||
}, {
|
||||
passive: true
|
||||
});
|
||||
|
||||
dom.addEventListener((dlg.dialogContainer || backdrop), 'contextmenu', e => {
|
||||
if (e.target === dlg.dialogContainer) {
|
||||
// Close the application dialog menu
|
||||
close(dlg);
|
||||
// Prevent the default browser context menu from appearing
|
||||
e.preventDefault();
|
||||
}
|
||||
});
|
||||
if (!dlgOptions.preventCloseOnRightClick) {
|
||||
dom.addEventListener((dlg.dialogContainer || backdrop), 'contextmenu', e => {
|
||||
if (e.target === dlg.dialogContainer) {
|
||||
// Close the application dialog menu
|
||||
close(dlg);
|
||||
// Prevent the default browser context menu from appearing
|
||||
e.preventDefault();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function isHistoryEnabled(dlg) {
|
||||
return dlg.getAttribute('data-history') === 'true';
|
||||
}
|
||||
|
||||
export function open(dlg) {
|
||||
export function open(dlg, dlgOptions) {
|
||||
if (globalOnOpenCallback) {
|
||||
globalOnOpenCallback(dlg);
|
||||
}
|
||||
@@ -250,7 +248,7 @@ export function open(dlg) {
|
||||
document.body.appendChild(dialogContainer);
|
||||
|
||||
return new Promise((resolve) => {
|
||||
new DialogHashHandler(dlg, `dlg${new Date().getTime()}`, resolve);
|
||||
new DialogHashHandler(dlg, `dlg${new Date().getTime()}`, resolve, dlgOptions);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -93,24 +93,22 @@ function isCurrentlyFocusableInternal(elem) {
|
||||
|
||||
// Determines if a focusable element can be focused at a given point in time
|
||||
function isCurrentlyFocusable(elem) {
|
||||
if (!elem.classList?.contains('focusable')) {
|
||||
if (elem.disabled) {
|
||||
if (elem.disabled) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (elem.getAttribute('tabindex') === '-1') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (elem.tagName === 'INPUT') {
|
||||
const type = elem.type;
|
||||
if (type === 'range') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (elem.getAttribute('tabindex') === '-1') {
|
||||
if (type === 'file') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (elem.tagName === 'INPUT') {
|
||||
const type = elem.type;
|
||||
if (type === 'range') {
|
||||
return false;
|
||||
}
|
||||
if (type === 'file') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return isCurrentlyFocusableInternal(elem);
|
||||
|
||||
@@ -107,7 +107,7 @@ function getMediaSourceHtml(user, item, version) {
|
||||
if (stream.CodecTag) {
|
||||
attributes.push(createAttribute(globalize.translate('MediaInfoCodecTag'), stream.CodecTag));
|
||||
}
|
||||
if (stream.IsAVC != null) {
|
||||
if (stream.Type === 'Video' && stream.IsAVC != null) {
|
||||
attributes.push(createAttribute('AVC', (stream.IsAVC ? 'Yes' : 'No')));
|
||||
}
|
||||
if (stream.Profile) {
|
||||
|
||||
@@ -1099,7 +1099,10 @@ function show(itemId, serverId, resolve) {
|
||||
centerFocus(dlg.querySelector('.formDialogContent'), false, true);
|
||||
}
|
||||
|
||||
dialogHelper.open(dlg);
|
||||
dialogHelper.open(dlg, {
|
||||
preventCloseOnClick : true,
|
||||
preventCloseOnRightClick : true
|
||||
});
|
||||
|
||||
dlg.addEventListener('close', function () {
|
||||
if (layoutManager.tv) {
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
@import '../../styles/mixins';
|
||||
|
||||
.itemSelectionPanel {
|
||||
position: absolute;
|
||||
@@ -15,14 +14,16 @@
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
padding-left: 0.5em;
|
||||
padding-left: max(env(safe-area-inset-left), 0.5em);
|
||||
padding-right: 0.5em;
|
||||
padding-right: max(env(safe-area-inset-right), 0.5em);
|
||||
padding-top: 1em;
|
||||
padding-top: max(env(safe-area-inset-top), 1em);
|
||||
padding-bottom: 1em;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
z-index: 99999;
|
||||
|
||||
@include conditional-max(padding-left, 0.5em, env(safe-area-inset-left));
|
||||
@include conditional-max(padding-right, 0.5em, env(safe-area-inset-right));
|
||||
@include conditional-max(padding-top, 1em, env(safe-area-inset-top));
|
||||
}
|
||||
|
||||
.itemSelectionCount {
|
||||
|
||||
@@ -27,6 +27,7 @@ import { MediaError } from 'types/mediaError';
|
||||
import { getMediaError } from 'utils/mediaError';
|
||||
import { toApi } from 'utils/jellyfin-apiclient/compat';
|
||||
import { BaseItemKind } from '@jellyfin/sdk/lib/generated-client/models/base-item-kind.js';
|
||||
import browser from 'scripts/browser.js';
|
||||
import { bindSkipSegment } from './skipsegment.ts';
|
||||
|
||||
const UNLIMITED_ITEMS = -1;
|
||||
@@ -851,31 +852,8 @@ export class PlaybackManager {
|
||||
self.getTargets = function () {
|
||||
const promises = players.filter(displayPlayerIndividually).map(getPlayerTargets);
|
||||
|
||||
return Promise.all(promises).then(function (responses) {
|
||||
return ServerConnections.currentApiClient().getCurrentUser().then(function (user) {
|
||||
const targets = [];
|
||||
|
||||
targets.push({
|
||||
name: globalize.translate('HeaderMyDevice'),
|
||||
id: 'localplayer',
|
||||
playerName: 'localplayer',
|
||||
playableMediaTypes: ['Audio', 'Video', 'Photo', 'Book'],
|
||||
isLocalPlayer: true,
|
||||
supportedCommands: self.getSupportedCommands({
|
||||
isLocalPlayer: true
|
||||
}),
|
||||
user: user
|
||||
});
|
||||
|
||||
for (const subTargets of responses) {
|
||||
for (const subTarget of subTargets) {
|
||||
targets.push(subTarget);
|
||||
}
|
||||
}
|
||||
|
||||
return targets.sort(sortPlayerTargets);
|
||||
});
|
||||
});
|
||||
return Promise.all(promises)
|
||||
.then(responses => responses.flat().sort(sortPlayerTargets));
|
||||
};
|
||||
|
||||
self.playerHasSecondarySubtitleSupport = function (player = self._currentPlayer) {
|
||||
@@ -2602,11 +2580,16 @@ export class PlaybackManager {
|
||||
});
|
||||
}
|
||||
|
||||
let mediaSourceId = playOptions.mediaSourceId;
|
||||
|
||||
const apiClient = ServerConnections.getApiClient(item.ServerId);
|
||||
let mediaSourceId;
|
||||
|
||||
const isLiveTv = [BaseItemKind.TvChannel, BaseItemKind.LiveTvChannel].includes(item.Type);
|
||||
const getMediaStreams = isLiveTv ? Promise.resolve([]) : apiClient.getItem(apiClient.getCurrentUserId(), mediaSourceId || item.Id)
|
||||
|
||||
if (!isLiveTv) {
|
||||
mediaSourceId = playOptions.mediaSourceId || item.Id;
|
||||
}
|
||||
|
||||
const getMediaStreams = isLiveTv ? Promise.resolve([]) : apiClient.getItem(apiClient.getCurrentUserId(), mediaSourceId)
|
||||
.then(fullItem => {
|
||||
return fullItem.MediaStreams;
|
||||
});
|
||||
@@ -2639,20 +2622,13 @@ export class PlaybackManager {
|
||||
playOptions.items = null;
|
||||
|
||||
const trackOptions = {};
|
||||
let isIdFallbackNeeded = false;
|
||||
|
||||
autoSetNextTracks(prevSource, mediaStreams, trackOptions, user.Configuration.RememberAudioSelections, user.Configuration.RememberSubtitleSelections);
|
||||
if (trackOptions.DefaultAudioStreamIndex != null) {
|
||||
options.audioStreamIndex = trackOptions.DefaultAudioStreamIndex;
|
||||
isIdFallbackNeeded = true;
|
||||
}
|
||||
if (trackOptions.DefaultSubtitleStreamIndex != null) {
|
||||
options.subtitleStreamIndex = trackOptions.DefaultSubtitleStreamIndex;
|
||||
isIdFallbackNeeded = true;
|
||||
}
|
||||
|
||||
if (isIdFallbackNeeded) {
|
||||
mediaSourceId ||= item.Id;
|
||||
}
|
||||
|
||||
return getPlaybackMediaSource(player, apiClient, deviceProfile, item, mediaSourceId, options).then(async (mediaSource) => {
|
||||
@@ -3688,7 +3664,9 @@ export class PlaybackManager {
|
||||
}
|
||||
|
||||
bindMediaSegmentManager(self);
|
||||
this._skipSegment = bindSkipSegment(self);
|
||||
if (!browser.tv && !browser.xboxOne && !browser.ps4) {
|
||||
this._skipSegment = bindSkipSegment(self);
|
||||
}
|
||||
}
|
||||
|
||||
getCurrentPlayer() {
|
||||
|
||||
@@ -1,17 +1,10 @@
|
||||
.skip-button-container {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 18%;
|
||||
pointer-events: none;
|
||||
z-index: 10000;
|
||||
}
|
||||
|
||||
.skip-button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-left: auto;
|
||||
margin-right: 16%;
|
||||
position: fixed;
|
||||
bottom: 18%;
|
||||
right: 16%;
|
||||
z-index: 10000;
|
||||
padding: 12px 20px;
|
||||
color: black;
|
||||
border: none;
|
||||
@@ -22,7 +15,6 @@
|
||||
gap: 3px;
|
||||
box-shadow: 7px 6px 15px -14px rgba(0, 0, 0, 0.65);
|
||||
cursor: pointer;
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
@media (orientation: landscape) and (max-height: 500px) {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { PlaybackManager } from './playbackmanager';
|
||||
import { TICKS_PER_MILLISECOND, TICKS_PER_SECOND } from 'constants/time';
|
||||
import type { MediaSegmentDto } from '@jellyfin/sdk/lib/generated-client/models/media-segment-dto';
|
||||
import type { PlaybackStopInfo } from 'types/playbackStopInfo';
|
||||
import { PlaybackSubscriber } from 'apps/stable/features/playback/utils/playbackSubscriber';
|
||||
import { isInSegment } from 'apps/stable/features/playback/utils/mediaSegments';
|
||||
import Events, { type Event } from 'utils/events';
|
||||
@@ -10,64 +9,49 @@ import './skipbutton.scss';
|
||||
import dom from 'scripts/dom';
|
||||
import globalize from 'lib/globalize';
|
||||
import * as userSettings from 'scripts/settings/userSettings';
|
||||
import focusManager from 'components/focusManager';
|
||||
import layoutManager from 'components/layoutManager';
|
||||
|
||||
interface ShowOptions {
|
||||
animate?: boolean;
|
||||
keep?: boolean;
|
||||
focus?: boolean;
|
||||
}
|
||||
|
||||
function onHideComplete(this: HTMLButtonElement) {
|
||||
if (this) {
|
||||
// Handle focus after the hide transition completes
|
||||
if (document.activeElement === this) {
|
||||
this.blur();
|
||||
const pauseButton = document.querySelector('.btnPause');
|
||||
if (pauseButton && focusManager.isCurrentlyFocusable(pauseButton)) {
|
||||
focusManager.focus(pauseButton);
|
||||
}
|
||||
}
|
||||
|
||||
this.classList.add('hide');
|
||||
}
|
||||
}
|
||||
|
||||
class SkipSegment extends PlaybackSubscriber {
|
||||
private skipElement: HTMLButtonElement | null;
|
||||
private skipElement: HTMLButtonElement | undefined;
|
||||
private currentSegment: MediaSegmentDto | null | undefined;
|
||||
private hideTimeout: ReturnType<typeof setTimeout> | null | undefined;
|
||||
|
||||
constructor(playbackManager: PlaybackManager) {
|
||||
super(playbackManager);
|
||||
|
||||
this.skipElement = null;
|
||||
this.onOsdChanged = this.onOsdChanged.bind(this);
|
||||
}
|
||||
|
||||
onHideComplete() {
|
||||
if (this.skipElement) {
|
||||
this.skipElement.classList.add('hide');
|
||||
}
|
||||
}
|
||||
|
||||
createSkipElement() {
|
||||
if (!this.skipElement && this.currentSegment) {
|
||||
let buttonHtml = '';
|
||||
const elem = document.createElement('button');
|
||||
elem.classList.add('skip-button');
|
||||
elem.classList.add('hide');
|
||||
elem.classList.add('skip-button-hidden');
|
||||
|
||||
// FIXME: Move skip button to the video OSD
|
||||
buttonHtml += '<div class="skip-button-container"><button is="emby-button" class="skip-button hide skip-button-hidden"></button></div>';
|
||||
|
||||
document.body.insertAdjacentHTML('beforeend', buttonHtml);
|
||||
|
||||
this.skipElement = document.body.querySelector('.skip-button');
|
||||
if (this.skipElement) {
|
||||
this.skipElement.addEventListener('click', () => {
|
||||
const time = this.playbackManager.currentTime() * TICKS_PER_MILLISECOND;
|
||||
if (this.currentSegment?.EndTicks) {
|
||||
if (time < this.currentSegment.EndTicks - TICKS_PER_SECOND) {
|
||||
this.playbackManager.seek(this.currentSegment.EndTicks);
|
||||
} else {
|
||||
this.hideSkipButton();
|
||||
}
|
||||
elem.addEventListener('click', () => {
|
||||
const time = this.playbackManager.currentTime() * TICKS_PER_MILLISECOND;
|
||||
if (this.currentSegment?.EndTicks) {
|
||||
if (time < this.currentSegment.EndTicks - TICKS_PER_SECOND) {
|
||||
this.playbackManager.seek(this.currentSegment.EndTicks);
|
||||
} else {
|
||||
this.hideSkipButton();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
document.body.appendChild(elem);
|
||||
this.skipElement = elem;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,7 +66,7 @@ class SkipSegment extends PlaybackSubscriber {
|
||||
const elem = this.skipElement;
|
||||
if (elem) {
|
||||
this.clearHideTimeout();
|
||||
dom.removeEventListener(elem, dom.whichTransitionEvent(), onHideComplete, {
|
||||
dom.removeEventListener(elem, dom.whichTransitionEvent(), this.onHideComplete, {
|
||||
once: true
|
||||
});
|
||||
elem.classList.remove('hide');
|
||||
@@ -94,11 +78,6 @@ class SkipSegment extends PlaybackSubscriber {
|
||||
|
||||
void elem.offsetWidth;
|
||||
|
||||
const hasFocus = document.activeElement && focusManager.isCurrentlyFocusable(document.activeElement);
|
||||
if (options.focus && !hasFocus) {
|
||||
focusManager.focus(elem);
|
||||
}
|
||||
|
||||
requestAnimationFrame(() => {
|
||||
elem.classList.remove('skip-button-hidden');
|
||||
|
||||
@@ -118,7 +97,7 @@ class SkipSegment extends PlaybackSubscriber {
|
||||
requestAnimationFrame(() => {
|
||||
elem.classList.add('skip-button-hidden');
|
||||
|
||||
dom.addEventListener(elem, dom.whichTransitionEvent(), onHideComplete, {
|
||||
dom.addEventListener(elem, dom.whichTransitionEvent(), this.onHideComplete, {
|
||||
once: true
|
||||
});
|
||||
});
|
||||
@@ -137,8 +116,7 @@ class SkipSegment extends PlaybackSubscriber {
|
||||
if (isOpen) {
|
||||
this.showSkipButton({
|
||||
animate: false,
|
||||
keep: true,
|
||||
focus: false
|
||||
keep: true
|
||||
});
|
||||
} else if (!this.hideTimeout) {
|
||||
this.hideSkipButton();
|
||||
@@ -162,10 +140,7 @@ class SkipSegment extends PlaybackSubscriber {
|
||||
|
||||
this.setButtonText();
|
||||
|
||||
this.showSkipButton({
|
||||
animate: true,
|
||||
focus: layoutManager.tv
|
||||
});
|
||||
this.showSkipButton({ animate: true });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -187,12 +162,10 @@ class SkipSegment extends PlaybackSubscriber {
|
||||
}
|
||||
}
|
||||
|
||||
onPlaybackStop(_e: Event, playbackStopInfo: PlaybackStopInfo) {
|
||||
onPlaybackStop() {
|
||||
this.currentSegment = null;
|
||||
this.hideSkipButton();
|
||||
if (!playbackStopInfo.nextItem) {
|
||||
Events.off(document, EventType.SHOW_VIDEO_OSD, this.onOsdChanged);
|
||||
}
|
||||
Events.off(document, EventType.SHOW_VIDEO_OSD, this.onOsdChanged);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
@import '../../styles/mixins';
|
||||
|
||||
.nowPlayingPage {
|
||||
padding: 5em 0 0 0 !important;
|
||||
}
|
||||
@@ -186,10 +184,11 @@
|
||||
left: 0;
|
||||
height: 4.2em;
|
||||
right: 0;
|
||||
padding-left: 7.3%;
|
||||
padding-left: max(env(safe-area-inset-left), 7.3%);
|
||||
padding-right: 7.3%;
|
||||
padding-right: max(env(safe-area-inset-right), 7.3%);
|
||||
padding-bottom: env(safe-area-inset-bottom);
|
||||
|
||||
@include conditional-max(padding-left, 7.3%, env(safe-area-inset-left));
|
||||
@include conditional-max(padding-right, 7.3%, env(safe-area-inset-right));
|
||||
}
|
||||
|
||||
.layout-desktop .playlistSectionButton,
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import React, { StrictMode } from 'react';
|
||||
import type { RouteObject } from 'react-router-dom';
|
||||
|
||||
export enum AsyncRouteType {
|
||||
@@ -19,7 +18,7 @@ export interface AsyncRoute {
|
||||
type?: AsyncRouteType
|
||||
}
|
||||
|
||||
const importPage = (page: string, type: AsyncRouteType) => {
|
||||
const importRoute = (page: string, type: AsyncRouteType) => {
|
||||
switch (type) {
|
||||
case AsyncRouteType.Dashboard:
|
||||
return import(/* webpackChunkName: "[request]" */ `../../apps/dashboard/routes/${page}`);
|
||||
@@ -38,13 +37,15 @@ export const toAsyncPageRoute = ({
|
||||
return {
|
||||
path,
|
||||
lazy: async () => {
|
||||
const { default: Page } = await importPage(page ?? path, type);
|
||||
const {
|
||||
// If there is a default export, use it as the Component for compatibility
|
||||
default: Component,
|
||||
...route
|
||||
} = await importRoute(page ?? path, type);
|
||||
|
||||
return {
|
||||
element: (
|
||||
<StrictMode>
|
||||
<Page />
|
||||
</StrictMode>
|
||||
)
|
||||
Component,
|
||||
...route
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,18 +1,17 @@
|
||||
@import '../../styles/mixins';
|
||||
|
||||
.toastContainer {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
pointer-events: none;
|
||||
z-index: 9999999;
|
||||
padding-left: 1em;
|
||||
padding-left: max(env(safe-area-inset-left), 1em);
|
||||
padding-right: 1em;
|
||||
padding-top: 1em;
|
||||
padding-bottom: 1em;
|
||||
padding-bottom: max(env(safe-area-inset-bottom), 1em);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
@include conditional-max(padding-left, 1em, env(safe-area-inset-left));
|
||||
@include conditional-max(padding-bottom, 1em, env(safe-area-inset-bottom));
|
||||
|
||||
[dir="ltr"] & {
|
||||
left: 0;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
<div class="verticalSection">
|
||||
<div class="sectionTitleContainer flex align-items-center">
|
||||
<h1 class="sectionTitle">Schedules Direct</h1>
|
||||
<a is="emby-linkbutton" rel="noopener noreferrer" class="raised button-alt headerHelpButton" target="_blank" href="https://jellyfin.org/docs/general/server/live-tv/setup-guide#adding-guide-data">${Help}</a>
|
||||
</div>
|
||||
<p class="createAccountHelp"></p>
|
||||
</div>
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
<div class="verticalSection">
|
||||
<div class="sectionTitleContainer flex align-items-center">
|
||||
<h1 class="sectionTitle">Xml TV</h1>
|
||||
<a is="emby-linkbutton" rel="noopener noreferrer" class="raised button-alt headerHelpButton" target="_blank" href="https://jellyfin.org/docs/general/server/live-tv/setup-guide#adding-guide-data">${Help}</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
<div class="verticalSection verticalSection-extrabottompadding">
|
||||
<div class="sectionTitleContainer flex align-items-center">
|
||||
<h2 class="sectionTitle reportedName"></h2>
|
||||
<a is="emby-linkbutton" rel="noopener noreferrer" class="raised button-alt headerHelpButton" target="_blank" href="https://jellyfin.org/docs/general/server/devices">${Help}</a>
|
||||
</div>
|
||||
|
||||
<div class="inputContainer">
|
||||
|
||||
@@ -4,8 +4,15 @@
|
||||
<div class="verticalSection verticalSection">
|
||||
<div class="sectionTitleContainer sectionTitleContainer-cards flex align-items-center">
|
||||
<h2 class="sectionTitle sectionTitle-cards">${HeaderDevices}</h2>
|
||||
<a is="emby-linkbutton" rel="noopener noreferrer" class="raised button-alt headerHelpButton" target="_blank" href="https://jellyfin.org/docs/general/server/devices">${Help}</a>
|
||||
<button id="deviceDeleteAll" is="emby-button" type="button" class="raised button-alt headerHelpButton">${DeleteAll}</button>
|
||||
<button
|
||||
id="deviceDeleteAll"
|
||||
is="emby-button"
|
||||
type="button"
|
||||
class="raised button-alt"
|
||||
style="margin-left: 1.25em !important; padding-bottom: 0.4em !important; padding-top: 0.4em !important;"
|
||||
>
|
||||
${DeleteAll}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div is="emby-itemscontainer" class="devicesList vertical-wrap" data-multiselect="false"></div>
|
||||
|
||||
@@ -99,7 +99,7 @@ function load(page, devices) {
|
||||
const iconUrl = imageHelper.getDeviceIcon(device);
|
||||
|
||||
if (iconUrl) {
|
||||
deviceHtml += '<div class="cardImage" style="background-image:url(\'' + iconUrl + "');background-size: auto 64%;background-position:center center;\">";
|
||||
deviceHtml += '<div class="cardImage" style="background-image:url(\'' + iconUrl + "');background-size:contain;background-position:center center;background-origin:content-box;padding:1em;\">";
|
||||
deviceHtml += '</div>';
|
||||
} else {
|
||||
deviceHtml += '<span class="cardImageIcon material-icons tablet_android" aria-hidden="true"></span>';
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
<div class="verticalSection">
|
||||
<div class="sectionTitleContainer flex align-items-center">
|
||||
<h2 class="sectionTitle">${Transcoding}</h2>
|
||||
<a is="emby-linkbutton" rel="noopener noreferrer" class="raised button-alt headerHelpButton" target="_blank" href="https://jellyfin.org/docs/general/server/transcoding">${Help}</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -183,7 +182,7 @@
|
||||
</div>
|
||||
|
||||
<div class="tonemappingOptions hide">
|
||||
<div class="checkboxListContainer checkboxContainer-withDescription fldTonemapCheckbox hide">
|
||||
<div class="checkboxListContainer checkboxContainer-withDescription">
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" id="chkTonemapping" />
|
||||
<span>${EnableTonemapping}</span>
|
||||
|
||||
@@ -207,15 +207,10 @@ $(document).on('pageinit', '#encodingSettingsPage', function () {
|
||||
}
|
||||
|
||||
const isHwaSelected = [ 'amf', 'nvenc', 'qsv', 'vaapi', 'rkmpp', 'videotoolbox' ].includes(this.value);
|
||||
if (this.value === 'none') {
|
||||
if (this.value === 'none' || isHwaSelected) {
|
||||
page.querySelector('.tonemappingOptions').classList.remove('hide');
|
||||
page.querySelector('.fldTonemapCheckbox').classList.add('hide');
|
||||
} else if (isHwaSelected) {
|
||||
page.querySelector('.tonemappingOptions').classList.remove('hide');
|
||||
page.querySelector('.fldTonemapCheckbox').classList.remove('hide');
|
||||
} else {
|
||||
page.querySelector('.tonemappingOptions').classList.add('hide');
|
||||
page.querySelector('.fldTonemapCheckbox').classList.add('hide');
|
||||
}
|
||||
|
||||
page.querySelector('.tonemappingModeOptions').classList.toggle('hide', !isHwaSelected);
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
<div class="verticalSection">
|
||||
<div class="sectionTitleContainer flex align-items-center">
|
||||
<h2 class="sectionTitle">${Settings}</h2>
|
||||
<a is="emby-linkbutton" rel="noopener noreferrer" class="raised button-alt headerHelpButton" target="_blank" href="https://jellyfin.org/docs/general/server/settings">${Help}</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -62,24 +61,6 @@
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="verticalSection">
|
||||
<h2>${HeaderBranding}</h2>
|
||||
<div class="inputContainer">
|
||||
<textarea is="emby-textarea" id="txtLoginDisclaimer" label="${LabelLoginDisclaimer}" class="textarea-mono"></textarea>
|
||||
<div class="fieldDescription">${LabelLoginDisclaimerHelp}</div>
|
||||
</div>
|
||||
<div class="inputContainer customCssContainer">
|
||||
<textarea is="emby-textarea" id="txtCustomCss" label="${LabelCustomCss}" class="textarea-mono"></textarea>
|
||||
<div class="fieldDescription">${LabelCustomCssHelp}</div>
|
||||
</div>
|
||||
<div class="checkboxList paperList" style="padding:.5em 1em;">
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" id="chkSplashScreenAvailable" />
|
||||
<span>${EnableSplashScreen}</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="verticalSection">
|
||||
<h2>${HeaderPerformance}</h2>
|
||||
<div class="inputContainer">
|
||||
|
||||
@@ -39,25 +39,17 @@ function onSubmit() {
|
||||
config.LibraryScanFanoutConcurrency = parseInt(form.querySelector('#txtLibraryScanFanoutConcurrency').value || '0', 10);
|
||||
config.ParallelImageEncodingLimit = parseInt(form.querySelector('#txtParallelImageEncodingLimit').value || '0', 10);
|
||||
|
||||
ApiClient.updateServerConfiguration(config).then(function() {
|
||||
ApiClient.getNamedConfiguration(brandingConfigKey).then(function(brandingConfig) {
|
||||
brandingConfig.LoginDisclaimer = form.querySelector('#txtLoginDisclaimer').value;
|
||||
brandingConfig.CustomCss = form.querySelector('#txtCustomCss').value;
|
||||
brandingConfig.SplashscreenEnabled = form.querySelector('#chkSplashScreenAvailable').checked;
|
||||
|
||||
ApiClient.updateNamedConfiguration(brandingConfigKey, brandingConfig).then(function () {
|
||||
Dashboard.processServerConfigurationUpdateResult();
|
||||
});
|
||||
return ApiClient.updateServerConfiguration(config)
|
||||
.then(() => {
|
||||
Dashboard.processServerConfigurationUpdateResult();
|
||||
}).catch(() => {
|
||||
loading.hide();
|
||||
alert(globalize.translate('ErrorDefault'));
|
||||
});
|
||||
}, function () {
|
||||
alert(globalize.translate('ErrorDefault'));
|
||||
Dashboard.processServerConfigurationUpdateResult();
|
||||
});
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
const brandingConfigKey = 'branding';
|
||||
export default function (view) {
|
||||
$('#btnSelectCachePath', view).on('click.selectDirectory', function () {
|
||||
import('../../components/directorybrowser/directorybrowser').then(({ default: DirectoryBrowser }) => {
|
||||
@@ -107,11 +99,6 @@ export default function (view) {
|
||||
Promise.all([promiseConfig, promiseLanguageOptions, promiseSystemInfo]).then(function (responses) {
|
||||
loadPage(view, responses[0], responses[1], responses[2]);
|
||||
});
|
||||
ApiClient.getNamedConfiguration(brandingConfigKey).then(function (config) {
|
||||
view.querySelector('#txtLoginDisclaimer').value = config.LoginDisclaimer || '';
|
||||
view.querySelector('#txtCustomCss').value = config.CustomCss || '';
|
||||
view.querySelector('#chkSplashScreenAvailable').checked = config.SplashscreenEnabled === true;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
<span>${ButtonScanAllLibraries}</span>
|
||||
</button>
|
||||
<progress max="100" min="0" style="display: inline-block; vertical-align: middle;" class="refreshProgress"></progress>
|
||||
<a is="emby-linkbutton" rel="noopener noreferrer" class="raised button-alt" target="_blank" href="https://jellyfin.org/docs/general/server/libraries">${Help}</a>
|
||||
</div>
|
||||
|
||||
<div id="divVirtualFolders"></div>
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
<div class="verticalSection verticalSection-extrabottompadding">
|
||||
<div class="sectionTitleContainer flex align-items-center">
|
||||
<h2 class="sectionTitle">${TabNetworking}</h2>
|
||||
<a is="emby-linkbutton" rel="noopener noreferrer" class="raised button-alt headerHelpButton" target="_blank" href="https://jellyfin.org/docs/general/networking/">${Help}</a>
|
||||
</div>
|
||||
|
||||
<fieldset class='verticalSection verticalSection-extrabottompadding'>
|
||||
@@ -97,14 +96,6 @@
|
||||
<option value="blacklist">${Blacklist}</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="checkboxContainer checkboxContainer-withDescription fldEnableUpnp hide">
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" id="chkEnableUpnp" />
|
||||
<span>${LabelEnableAutomaticPortMap}</span>
|
||||
</label>
|
||||
<div class="fieldDescription checkboxFieldDescription">${LabelEnableAutomaticPortMapHelp}</div>
|
||||
</div>
|
||||
<div class="inputContainer fldPublicHttpPort hide">
|
||||
<input is="emby-input" type="number" label="${LabelPublicHttpPort}" id="txtPublicHttpPort" pattern="[0-9]*" required="required" min="1" max="65535" />
|
||||
<div class="fieldDescription">${LabelPublicHttpPortHelp}</div>
|
||||
|
||||
@@ -8,8 +8,7 @@ import alert from '../../components/alert';
|
||||
function onSubmit(e) {
|
||||
const form = this;
|
||||
const localAddress = form.querySelector('#txtLocalAddress').value;
|
||||
const enableUpnp = form.querySelector('#chkEnableUpnp').checked;
|
||||
confirmSelections(localAddress, enableUpnp, function () {
|
||||
confirmSelections(localAddress, function () {
|
||||
const validationResult = getValidationAlert(form);
|
||||
|
||||
if (validationResult) {
|
||||
@@ -54,7 +53,6 @@ function onSubmit(e) {
|
||||
config.InternalHttpsPort = form.querySelector('#txtHttpsPort').value;
|
||||
config.EnableHttps = form.querySelector('#chkEnableHttps').checked;
|
||||
config.RequireHttps = form.querySelector('#chkRequireHttps').checked;
|
||||
config.EnableUPnP = enableUpnp;
|
||||
config.BaseUrl = form.querySelector('#txtBaseUrl').value;
|
||||
config.EnableRemoteAccess = form.querySelector('#chkRemoteAccess').checked;
|
||||
config.CertificatePath = form.querySelector('#txtCertificatePath').value || null;
|
||||
@@ -110,8 +108,8 @@ function showAlertText(options) {
|
||||
});
|
||||
}
|
||||
|
||||
function confirmSelections(localAddress, enableUpnp, callback) {
|
||||
if (localAddress || !enableUpnp) {
|
||||
function confirmSelections(localAddress, callback) {
|
||||
if (localAddress) {
|
||||
showAlertText({
|
||||
title: globalize.translate('TitleHostingSettings'),
|
||||
text: globalize.translate('SettingsWarning')
|
||||
@@ -139,7 +137,6 @@ export default function (view) {
|
||||
const txtCertificatePath = page.querySelector('#txtCertificatePath');
|
||||
txtCertificatePath.value = config.CertificatePath || '';
|
||||
page.querySelector('#txtCertPassword').value = config.CertificatePassword || '';
|
||||
page.querySelector('#chkEnableUpnp').checked = config.EnableUPnP;
|
||||
triggerChange(page.querySelector('#chkRemoteAccess'));
|
||||
page.querySelector('#chkAutodiscovery').checked = config.AutoDiscovery;
|
||||
page.querySelector('#chkEnableIP6').checked = config.EnableIPv6;
|
||||
@@ -154,13 +151,11 @@ export default function (view) {
|
||||
view.querySelector('.fldExternalAddressFilterMode').classList.remove('hide');
|
||||
view.querySelector('.fldPublicHttpPort').classList.remove('hide');
|
||||
view.querySelector('.fldPublicHttpsPort').classList.remove('hide');
|
||||
view.querySelector('.fldEnableUpnp').classList.remove('hide');
|
||||
} else {
|
||||
view.querySelector('.fldExternalAddressFilter').classList.add('hide');
|
||||
view.querySelector('.fldExternalAddressFilterMode').classList.add('hide');
|
||||
view.querySelector('.fldPublicHttpPort').classList.add('hide');
|
||||
view.querySelector('.fldPublicHttpsPort').classList.add('hide');
|
||||
view.querySelector('.fldEnableUpnp').classList.add('hide');
|
||||
}
|
||||
});
|
||||
view.querySelector('#btnSelectCertPath').addEventListener('click', function () {
|
||||
|
||||
@@ -6,9 +6,6 @@
|
||||
<a is="emby-linkbutton" class="fab" href="#/dashboard/plugins/repositories" style="margin-left:1em;" title="${Settings}">
|
||||
<span class="material-icons settings" aria-hidden="true"></span>
|
||||
</a>
|
||||
<a is="emby-linkbutton" rel="noopener noreferrer" class="raised button-alt headerHelpButton" target="_blank" href="https://jellyfin.org/docs/general/server/plugins/">
|
||||
${Help}
|
||||
</a>
|
||||
</div>
|
||||
<div class="inputContainer">
|
||||
<input id="txtSearchPlugins" name="txtSearchPlugins" type="text" is="emby-input" label="${Search}" />
|
||||
|
||||
@@ -3,9 +3,6 @@
|
||||
<div class="content-primary">
|
||||
<div class="sectionTitleContainer flex align-items-center">
|
||||
<h2 class="sectionTitle">${TabMyPlugins}</h2>
|
||||
<a is="emby-linkbutton" rel="noopener noreferrer" class="raised button-alt headerHelpButton" target="_blank" href="https://jellyfin.org/docs/general/server/plugins/">
|
||||
${Help}
|
||||
</a>
|
||||
</div>
|
||||
<div class="inputContainer">
|
||||
<input id="txtSearchPlugins" name="txtSearchPlugins" type="text" is="emby-input" label="${Search}" />
|
||||
|
||||
@@ -6,9 +6,6 @@
|
||||
<button is="emby-button" type="button" class="fab btnNewRepository submit" style="margin-left:1em;" title="${Add}">
|
||||
<span class="material-icons add" aria-hidden="true"></span>
|
||||
</button>
|
||||
<a is="emby-linkbutton" rel="noopener noreferrer" class="raised button-alt headerHelpButton" target="_blank" href="https://jellyfin.org/docs/general/server/plugins/#repositories">
|
||||
${Help}
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div id="repositories"></div>
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
<div class="verticalSection">
|
||||
<div class="sectionTitleContainer flex align-items-center">
|
||||
<h2 class="sectionTitle taskName"></h2>
|
||||
<a is="emby-linkbutton" rel="noopener noreferrer" class="raised button-alt headerHelpButton" target="_blank" href="https://jellyfin.org/docs/general/server/tasks">${Help}</a>
|
||||
</div>
|
||||
<p id="pTaskDescription"></p>
|
||||
</div>
|
||||
|
||||
@@ -33,8 +33,7 @@ function populateList(page, tasks) {
|
||||
|
||||
let currentCategory;
|
||||
let html = '';
|
||||
for (let i = 0; i < tasks.length; i++) {
|
||||
const task = tasks[i];
|
||||
for (const task of tasks) {
|
||||
if (task.Category != currentCategory) {
|
||||
currentCategory = task.Category;
|
||||
if (currentCategory) {
|
||||
@@ -46,9 +45,6 @@ function populateList(page, tasks) {
|
||||
html += '<h2 class="sectionTitle">';
|
||||
html += currentCategory;
|
||||
html += '</h2>';
|
||||
if (i === 0) {
|
||||
html += '<a is="emby-linkbutton" class="raised button-alt headerHelpButton" target="_blank" href="https://jellyfin.org/docs/general/server/tasks">' + globalize.translate('Help') + '</a>';
|
||||
}
|
||||
html += '</div>';
|
||||
html += '<div class="paperList">';
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
<div class="verticalSection">
|
||||
<div class="sectionTitleContainer flex align-items-center">
|
||||
<h2 class="sectionTitle">${HeaderDVR}</h2>
|
||||
<a is="emby-linkbutton" rel="noopener noreferrer" class="raised button-alt headerHelpButton" target="_blank" href="https://jellyfin.org/docs/general/server/live-tv/">${Help}</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
<button is="emby-button" type="button" class="fab btnAddDevice submit sectionTitleButton" style="margin-left:1em;" title="${Add}">
|
||||
<span class="material-icons add" aria-hidden="true"></span>
|
||||
</button>
|
||||
<a is="emby-linkbutton" rel="noopener noreferrer" style="margin-left:2em!important;" class="raised button-alt headerHelpButton" target="_blank" href="https://jellyfin.org/docs/general/server/live-tv/">${Help}</a>
|
||||
</div>
|
||||
<div class="devicesList itemsContainer vertical-wrap" data-hovermenu="false" data-multiselect="false" style="margin-top: .5em;"></div>
|
||||
</div>
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
<div class="verticalSection">
|
||||
<div class="sectionTitleContainer flex align-items-center">
|
||||
<h1 class="sectionTitle">${HeaderLiveTvTunerSetup}</h1>
|
||||
<a is="emby-linkbutton" rel="noopener noreferrer" class="raised button-alt headerHelpButton" target="_blank" href="https://jellyfin.org/docs/general/server/live-tv/">${Help}</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import escapeHtml from 'escape-html';
|
||||
import debounce from 'lodash-es/debounce';
|
||||
import { playbackManager } from '../../../components/playback/playbackmanager';
|
||||
import browser from '../../../scripts/browser';
|
||||
import dom from '../../../scripts/dom';
|
||||
@@ -303,15 +304,11 @@ export default function (view) {
|
||||
}
|
||||
|
||||
function slideDownToShow(elem) {
|
||||
clearHideAnimationEventListeners(elem);
|
||||
elem.classList.remove('hide');
|
||||
elem.classList.remove('osdHeader-hidden');
|
||||
}
|
||||
|
||||
function slideUpToHide(elem) {
|
||||
clearHideAnimationEventListeners(elem);
|
||||
elem.classList.add('osdHeader-hidden');
|
||||
elem.addEventListener(transitionEndEventName, onHideAnimationComplete);
|
||||
}
|
||||
|
||||
function clearHideAnimationEventListeners(elem) {
|
||||
@@ -320,21 +317,12 @@ export default function (view) {
|
||||
|
||||
function onHideAnimationComplete(e) {
|
||||
const elem = e.target;
|
||||
if (elem !== osdBottomElement && elem !== headerElement) return;
|
||||
if (elem != osdBottomElement) return;
|
||||
elem.classList.add('hide');
|
||||
elem.removeEventListener(transitionEndEventName, onHideAnimationComplete);
|
||||
}
|
||||
|
||||
const _focus = function (focusElement) {
|
||||
// If no focus element is provided, try to keep current focus if it's valid,
|
||||
// otherwise default to pause button
|
||||
const currentFocus = focusElement || document.activeElement;
|
||||
if (!currentFocus || !focusManager.isCurrentlyFocusable(currentFocus)) {
|
||||
focusElement = osdBottomElement.querySelector('.btnPause');
|
||||
}
|
||||
|
||||
if (focusElement) focusManager.focus(focusElement);
|
||||
};
|
||||
const _focus = debounce((focusElement) => focusManager.focus(focusElement), 50);
|
||||
|
||||
function showMainOsdControls(focusElement) {
|
||||
if (!currentVisibleMenu) {
|
||||
@@ -344,11 +332,13 @@ export default function (view) {
|
||||
elem.classList.remove('hide');
|
||||
elem.classList.remove('videoOsdBottom-hidden');
|
||||
|
||||
focusElement ||= elem.querySelector('.btnPause');
|
||||
|
||||
if (!layoutManager.mobile) {
|
||||
_focus(focusElement);
|
||||
}
|
||||
toggleSubtitleSync();
|
||||
} else if (currentVisibleMenu === 'osd' && !layoutManager.mobile) {
|
||||
} else if (currentVisibleMenu === 'osd' && focusElement && !layoutManager.mobile) {
|
||||
_focus(focusElement);
|
||||
}
|
||||
}
|
||||
@@ -364,8 +354,7 @@ export default function (view) {
|
||||
toggleSubtitleSync('hide');
|
||||
|
||||
// Firefox does not blur by itself
|
||||
if (osdBottomElement.contains(document.activeElement)
|
||||
|| headerElement.contains(document.activeElement)) {
|
||||
if (document.activeElement) {
|
||||
document.activeElement.blur();
|
||||
}
|
||||
}
|
||||
@@ -1243,17 +1232,13 @@ export default function (view) {
|
||||
case 'ArrowLeft':
|
||||
case 'ArrowRight':
|
||||
if (!e.shiftKey) {
|
||||
e.preventDefault();
|
||||
showOsd(nowPlayingPositionSlider);
|
||||
nowPlayingPositionSlider.dispatchEvent(new KeyboardEvent(e.type, e));
|
||||
}
|
||||
return;
|
||||
case 'Enter':
|
||||
if (e.target.tagName !== 'BUTTON') {
|
||||
e.preventDefault();
|
||||
playbackManager.playPause(currentPlayer);
|
||||
showOsd(btnPlayPause);
|
||||
}
|
||||
playbackManager.playPause(currentPlayer);
|
||||
showOsd(btnPlayPause);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -1963,47 +1948,47 @@ export default function (view) {
|
||||
|
||||
// Register to SyncPlay playback events and show big animated icon
|
||||
const showIcon = (action) => {
|
||||
let primary_icon_name = '';
|
||||
let secondary_icon_name = '';
|
||||
let animation_class = 'oneShotPulse';
|
||||
let primaryIconName = '';
|
||||
let secondaryIconName = '';
|
||||
let animationClass = 'oneShotPulse';
|
||||
let iconVisibilityTime = 1500;
|
||||
const syncPlayIcon = view.querySelector('#syncPlayIcon');
|
||||
|
||||
switch (action) {
|
||||
case 'schedule-play':
|
||||
primary_icon_name = 'sync spin';
|
||||
secondary_icon_name = 'play_arrow centered';
|
||||
animation_class = 'infinitePulse';
|
||||
primaryIconName = 'sync spin';
|
||||
secondaryIconName = 'play_arrow centered';
|
||||
animationClass = 'infinitePulse';
|
||||
iconVisibilityTime = -1;
|
||||
hideOsd();
|
||||
break;
|
||||
case 'unpause':
|
||||
primary_icon_name = 'play_circle_outline';
|
||||
primaryIconName = 'play_circle_outline';
|
||||
break;
|
||||
case 'pause':
|
||||
primary_icon_name = 'pause_circle_outline';
|
||||
primaryIconName = 'pause_circle_outline';
|
||||
showOsd();
|
||||
break;
|
||||
case 'seek':
|
||||
primary_icon_name = 'update';
|
||||
animation_class = 'infinitePulse';
|
||||
primaryIconName = 'update';
|
||||
animationClass = 'infinitePulse';
|
||||
iconVisibilityTime = -1;
|
||||
break;
|
||||
case 'buffering':
|
||||
primary_icon_name = 'schedule';
|
||||
animation_class = 'infinitePulse';
|
||||
primaryIconName = 'schedule';
|
||||
animationClass = 'infinitePulse';
|
||||
iconVisibilityTime = -1;
|
||||
break;
|
||||
case 'wait-pause':
|
||||
primary_icon_name = 'schedule';
|
||||
secondary_icon_name = 'pause shifted';
|
||||
animation_class = 'infinitePulse';
|
||||
primaryIconName = 'schedule';
|
||||
secondaryIconName = 'pause shifted';
|
||||
animationClass = 'infinitePulse';
|
||||
iconVisibilityTime = -1;
|
||||
break;
|
||||
case 'wait-unpause':
|
||||
primary_icon_name = 'schedule';
|
||||
secondary_icon_name = 'play_arrow shifted';
|
||||
animation_class = 'infinitePulse';
|
||||
primaryIconName = 'schedule';
|
||||
secondaryIconName = 'play_arrow shifted';
|
||||
animationClass = 'infinitePulse';
|
||||
iconVisibilityTime = -1;
|
||||
break;
|
||||
default: {
|
||||
@@ -2012,13 +1997,13 @@ export default function (view) {
|
||||
}
|
||||
}
|
||||
|
||||
syncPlayIcon.setAttribute('class', 'syncPlayIconCircle ' + animation_class);
|
||||
syncPlayIcon.setAttribute('class', 'syncPlayIconCircle ' + animationClass);
|
||||
|
||||
const primaryIcon = syncPlayIcon.querySelector('.primary-icon');
|
||||
primaryIcon.setAttribute('class', 'primary-icon material-icons ' + primary_icon_name);
|
||||
primaryIcon.setAttribute('class', 'primary-icon material-icons ' + primaryIconName);
|
||||
|
||||
const secondaryIcon = syncPlayIcon.querySelector('.secondary-icon');
|
||||
secondaryIcon.setAttribute('class', 'secondary-icon material-icons ' + secondary_icon_name);
|
||||
secondaryIcon.setAttribute('class', 'secondary-icon material-icons ' + secondaryIconName);
|
||||
|
||||
const clone = syncPlayIcon.cloneNode(true);
|
||||
clone.style.visibility = 'visible';
|
||||
|
||||
@@ -11,13 +11,6 @@
|
||||
</label>
|
||||
<div class="fieldDescription checkboxFieldDescription">${AllowRemoteAccessHelp}</div>
|
||||
</div>
|
||||
<div class="checkboxContainer checkboxContainer-withDescription">
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" id="chkEnableUpnp" />
|
||||
<span>${LabelEnableAutomaticPortMap}</span>
|
||||
</label>
|
||||
<div class="fieldDescription checkboxFieldDescription">${LabelEnableAutomaticPortMapHelp}</div>
|
||||
</div>
|
||||
<br />
|
||||
<div class="wizardNavigation">
|
||||
<button is="emby-button" type="button" class="raised button-cancel" onclick="history.back();">
|
||||
|
||||
@@ -8,8 +8,7 @@ function save(page) {
|
||||
loading.show();
|
||||
const apiClient = ApiClient;
|
||||
const config = {
|
||||
EnableRemoteAccess: page.querySelector('#chkRemoteAccess').checked,
|
||||
EnableAutomaticPortMapping: page.querySelector('#chkEnableUpnp').checked
|
||||
EnableRemoteAccess: page.querySelector('#chkRemoteAccess').checked
|
||||
};
|
||||
|
||||
apiClient.ajax({
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import React, { FunctionComponent } from 'react';
|
||||
import IconButtonElement from './IconButtonElement';
|
||||
import LinkButton from './emby-button/LinkButton';
|
||||
import globalize from 'lib/globalize';
|
||||
|
||||
type IProps = {
|
||||
SectionClassName?: string;
|
||||
@@ -11,10 +9,8 @@ type IProps = {
|
||||
btnClassName?: string;
|
||||
btnTitle?: string;
|
||||
btnIcon?: string;
|
||||
isLinkVisible?: boolean;
|
||||
url?: string;
|
||||
};
|
||||
const SectionTitleContainer: FunctionComponent<IProps> = ({ SectionClassName, title, isBtnVisible = false, btnId, btnClassName, btnTitle, btnIcon, isLinkVisible = true, url }: IProps) => {
|
||||
const SectionTitleContainer: FunctionComponent<IProps> = ({ SectionClassName, title, isBtnVisible = false, btnId, btnClassName, btnTitle, btnIcon }: IProps) => {
|
||||
return (
|
||||
<div className={`${SectionClassName} sectionTitleContainer flex align-items-center`}>
|
||||
<h2 className='sectionTitle'>
|
||||
@@ -29,14 +25,6 @@ const SectionTitleContainer: FunctionComponent<IProps> = ({ SectionClassName, ti
|
||||
icon={btnIcon}
|
||||
/>}
|
||||
|
||||
{isLinkVisible && <LinkButton
|
||||
className='raised button-alt headerHelpButton'
|
||||
target='_blank'
|
||||
rel='noopener noreferrer'
|
||||
href={url}>
|
||||
{globalize.translate('Help')}
|
||||
</LinkButton>}
|
||||
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
@import '../../styles/mixins';
|
||||
|
||||
.emby-scroller-container {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.emby-scroller {
|
||||
@include conditional-max(padding-left, 3.3%, env(safe-area-inset-left));
|
||||
@include conditional-max(padding-right, 3.3%, env(safe-area-inset-right));
|
||||
padding-left: 3.3%;
|
||||
padding-left: max(env(safe-area-inset-left), 3.3%);
|
||||
padding-right: 3.3%;
|
||||
padding-right: max(env(safe-area-inset-right), 3.3%);
|
||||
}
|
||||
|
||||
.servers > .card > .cardBox {
|
||||
|
||||
@@ -79,9 +79,23 @@ function onMouseDown(e) {
|
||||
}
|
||||
|
||||
function onKeyDown(e) {
|
||||
if (e.keyCode === 13 && !enableNativeMenu()) {
|
||||
e.preventDefault();
|
||||
showActionSheet(this);
|
||||
switch (e.keyCode) {
|
||||
case 13:
|
||||
if (!enableNativeMenu()) {
|
||||
e.preventDefault();
|
||||
showActionSheet(this);
|
||||
}
|
||||
return;
|
||||
case 37:
|
||||
case 38:
|
||||
case 39:
|
||||
case 40:
|
||||
if (layoutManager.tv) {
|
||||
e.preventDefault();
|
||||
}
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
/* Remove select styling */
|
||||
|
||||
/* Font size must the 16px or larger to prevent iOS page zoom on focus */
|
||||
font-size: inherit;
|
||||
font-size: 110%;
|
||||
|
||||
/* General select styles: change as needed */
|
||||
font-family: inherit;
|
||||
@@ -19,6 +19,9 @@
|
||||
outline: none !important;
|
||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||
width: 100%;
|
||||
|
||||
/* Make the height at least as tall as inputs */
|
||||
min-height: 2.5em;
|
||||
}
|
||||
|
||||
.emby-textarea::-moz-focus-inner {
|
||||
|
||||
@@ -4,8 +4,8 @@ import type { BaseItemKind } from '@jellyfin/sdk/lib/generated-client/models/bas
|
||||
import { ImageType } from '@jellyfin/sdk/lib/generated-client/models/image-type';
|
||||
import { ItemFields } from '@jellyfin/sdk/lib/generated-client/models/item-fields';
|
||||
import { ItemFilter } from '@jellyfin/sdk/lib/generated-client/models/item-filter';
|
||||
import { ItemSortBy } from '@jellyfin/sdk/lib/generated-client/models/item-sort-by';
|
||||
import { SortOrder } from '@jellyfin/sdk/lib/generated-client/models/sort-order';
|
||||
import { ItemSortBy } from '@jellyfin/sdk/lib/models/api/item-sort-by';
|
||||
import { getArtistsApi } from '@jellyfin/sdk/lib/utils/api/artists-api';
|
||||
import { getFilterApi } from '@jellyfin/sdk/lib/utils/api/filter-api';
|
||||
import { getGenresApi } from '@jellyfin/sdk/lib/utils/api/genres-api';
|
||||
|
||||
@@ -110,6 +110,9 @@ build: ${__JF_BUILD_VERSION__}`);
|
||||
Events.on(apiClient, 'requestfail', appRouter.onRequestFail);
|
||||
});
|
||||
|
||||
// Connect to server
|
||||
ServerConnections.firstConnection = await ServerConnections.connect();
|
||||
|
||||
// Render the app
|
||||
await renderApp();
|
||||
|
||||
|
||||
@@ -12,8 +12,8 @@
|
||||
(function (DOMParser) {
|
||||
'use strict';
|
||||
|
||||
const DOMParser_proto = DOMParser.prototype;
|
||||
const real_parseFromString = DOMParser_proto.parseFromString;
|
||||
const DOMParserPrototype = DOMParser.prototype;
|
||||
const realParseFromString = DOMParserPrototype.parseFromString;
|
||||
|
||||
// Firefox/Opera/IE throw errors on unsupported types
|
||||
try {
|
||||
@@ -24,13 +24,13 @@
|
||||
}
|
||||
} catch (ex) { /* noop */ }
|
||||
|
||||
DOMParser_proto.parseFromString = function (markup, type) {
|
||||
DOMParserPrototype.parseFromString = function (markup, type) {
|
||||
if (/^\s*text\/html\s*(?:;|$)/i.test(type)) {
|
||||
const doc = document.implementation.createHTMLDocument('');
|
||||
doc.documentElement.innerHTML = markup;
|
||||
return doc;
|
||||
} else {
|
||||
return real_parseFromString.apply(this, arguments);
|
||||
return realParseFromString.apply(this, arguments);
|
||||
}
|
||||
};
|
||||
}(DOMParser));
|
||||
|
||||
@@ -7,12 +7,12 @@
|
||||
(function (HTMLMediaElement) {
|
||||
'use strict';
|
||||
|
||||
const HTMLMediaElement_proto = HTMLMediaElement.prototype;
|
||||
const real_play = HTMLMediaElement_proto.play;
|
||||
const HTMLMediaElementPrototype = HTMLMediaElement.prototype;
|
||||
const realPlay = HTMLMediaElementPrototype.play;
|
||||
|
||||
HTMLMediaElement_proto.play = function () {
|
||||
HTMLMediaElementPrototype.play = function () {
|
||||
try {
|
||||
const promise = real_play.apply(this, arguments);
|
||||
const promise = realPlay.apply(this, arguments);
|
||||
|
||||
if (typeof promise?.then === 'function') {
|
||||
return promise;
|
||||
|
||||
@@ -119,12 +119,6 @@ function requireHlsPlayer(callback) {
|
||||
});
|
||||
}
|
||||
|
||||
function getMediaStreamVideoTracks(mediaSource) {
|
||||
return mediaSource.MediaStreams.filter(function (s) {
|
||||
return s.Type === 'Video';
|
||||
});
|
||||
}
|
||||
|
||||
function getMediaStreamAudioTracks(mediaSource) {
|
||||
return mediaSource.MediaStreams.filter(function (s) {
|
||||
return s.Type === 'Audio';
|
||||
@@ -1280,9 +1274,6 @@ export class HtmlVideoPlayer {
|
||||
});
|
||||
const htmlVideoPlayer = this;
|
||||
import('@jellyfin/libass-wasm').then(({ default: SubtitlesOctopus }) => {
|
||||
const mediaSource = this._currentPlayOptions.mediaSource;
|
||||
const videoStream = getMediaStreamVideoTracks(mediaSource)[0];
|
||||
|
||||
const options = {
|
||||
video: videoElement,
|
||||
subUrl: getTextTrackUrl(track, item),
|
||||
@@ -1305,7 +1296,7 @@ export class HtmlVideoPlayer {
|
||||
dropAllAnimations: false,
|
||||
libassMemoryLimit: 40,
|
||||
libassGlyphLimit: 40,
|
||||
targetFps: videoStream?.ReferenceFrameRate || videoStream?.RealFrameRate || 24,
|
||||
targetFps: 24,
|
||||
prescaleFactor: 0.8,
|
||||
prescaleHeightLimit: 1080,
|
||||
maxRenderHeight: 2160,
|
||||
|
||||
@@ -7,6 +7,10 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background: #000 !important;
|
||||
padding-left: env(safe-area-inset-left);
|
||||
padding-right: env(safe-area-inset-right);
|
||||
padding-top: env(safe-area-inset-top);
|
||||
padding-bottom: env(safe-area-inset-bottom);
|
||||
}
|
||||
|
||||
.videoPlayerContainer-onTop {
|
||||
|
||||
@@ -7,6 +7,10 @@
|
||||
right: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-left: env(safe-area-inset-left);
|
||||
padding-right: env(safe-area-inset-right);
|
||||
padding-top: env(safe-area-inset-top);
|
||||
padding-bottom: env(safe-area-inset-bottom);
|
||||
}
|
||||
|
||||
.youtubePlayerContainer.onTop {
|
||||
|
||||
@@ -204,7 +204,7 @@ const uaMatch = function (ua) {
|
||||
|
||||
const versionMatch = /(version)[ /]([\w.]+)/.exec(ua);
|
||||
|
||||
let platform_match = /(ipad)/.exec(ua)
|
||||
let platformMatch = /(ipad)/.exec(ua)
|
||||
|| /(iphone)/.exec(ua)
|
||||
|| /(windows)/.exec(ua)
|
||||
|| /(android)/.exec(ua)
|
||||
@@ -213,7 +213,7 @@ const uaMatch = function (ua) {
|
||||
let browser = match[1] || '';
|
||||
|
||||
if (browser === 'edge') {
|
||||
platform_match = [''];
|
||||
platformMatch = [''];
|
||||
}
|
||||
|
||||
if (browser === 'opr') {
|
||||
@@ -236,7 +236,7 @@ const uaMatch = function (ua) {
|
||||
return {
|
||||
browser: browser,
|
||||
version: version,
|
||||
platform: platform_match[0] || '',
|
||||
platform: platformMatch[0] || '',
|
||||
versionMajor: versionMajor
|
||||
};
|
||||
};
|
||||
@@ -298,8 +298,8 @@ if (browser.web0s) {
|
||||
delete browser.chrome;
|
||||
delete browser.safari;
|
||||
} else if (browser.tizen) {
|
||||
const v = /Tizen (\d+).(\d+)/.exec(userAgent);
|
||||
browser.tizenVersion = parseInt(v[1], 10) + parseInt(v[2], 10) / 10;
|
||||
const v = (navigator.appVersion).match(/Tizen (\d+).(\d+)/);
|
||||
browser.tizenVersion = parseInt(v[1], 10);
|
||||
|
||||
// UserAgent string contains 'Chrome' and 'Safari', but we only want 'tizen' to be true
|
||||
delete browser.chrome;
|
||||
|
||||
@@ -231,6 +231,7 @@ function supportsVc1(videoTestElement) {
|
||||
|
||||
function supportsHdr10(options) {
|
||||
return options.supportsHdr10 ?? (false // eslint-disable-line sonarjs/no-redundant-boolean
|
||||
|| browser.vidaa
|
||||
|| browser.tizen
|
||||
|| browser.web0s
|
||||
|| browser.safari && ((browser.iOS && browser.iOSVersion >= 11) || browser.osx)
|
||||
@@ -462,8 +463,7 @@ export function canPlaySecondaryAudio(videoTestElement) {
|
||||
// It doesn't work in Firefox 108 even with "media.track.enabled" enabled (it only sees the first audio track)
|
||||
&& !browser.firefox
|
||||
// It seems to work on Tizen 5.5+ (2020, Chrome 69+). See https://developer.tizen.org/forums/web-application-development/video-tag-not-work-audiotracks
|
||||
// There are reports that additional audio track (AudioTrack API) doesn't work on Tizen 8.
|
||||
&& (browser.tizenVersion >= 5.5 && browser.tizenVersion < 8 || !browser.tizen)
|
||||
&& (browser.tizenVersion >= 5.5 || !browser.tizen)
|
||||
&& (browser.web0sVersion >= 4.0 || !browser.web0sVersion);
|
||||
}
|
||||
|
||||
@@ -1029,48 +1029,6 @@ export default function (options) {
|
||||
profile.TranscodingProfiles.push(...flacTranscodingProfiles);
|
||||
}
|
||||
|
||||
if (safariSupportsOpus) {
|
||||
const opusConditions = [
|
||||
// Safari doesn't support opus with more than 2 channels
|
||||
{
|
||||
Condition: 'LessThanEqual',
|
||||
Property: 'AudioChannels',
|
||||
Value: '2',
|
||||
IsRequired: false
|
||||
}
|
||||
];
|
||||
|
||||
profile.CodecProfiles.push({
|
||||
Type: 'VideoAudio',
|
||||
Codec: 'opus',
|
||||
Conditions: opusConditions
|
||||
});
|
||||
|
||||
const opusTranscodingProfiles = [];
|
||||
|
||||
// Split each video transcoding profile with opus so that the containing opus is only applied to 2 channels audio
|
||||
profile.TranscodingProfiles.forEach(transcodingProfile => {
|
||||
if (transcodingProfile.Type !== 'Video') return;
|
||||
|
||||
const audioCodecs = transcodingProfile.AudioCodec.split(',');
|
||||
|
||||
if (!audioCodecs.includes('opus')) return;
|
||||
|
||||
const opusTranscodingProfile = { ...transcodingProfile };
|
||||
opusTranscodingProfile.AudioCodec = 'opus';
|
||||
opusTranscodingProfile.ApplyConditions = [
|
||||
...opusTranscodingProfile.ApplyConditions || [],
|
||||
...opusConditions
|
||||
];
|
||||
|
||||
opusTranscodingProfiles.push(opusTranscodingProfile);
|
||||
|
||||
transcodingProfile.AudioCodec = audioCodecs.filter(codec => codec != 'opus').join(',');
|
||||
});
|
||||
|
||||
profile.TranscodingProfiles.push(...opusTranscodingProfiles);
|
||||
}
|
||||
|
||||
let maxH264Level = 42;
|
||||
let h264Profiles = 'high|main|baseline|constrained baseline';
|
||||
|
||||
@@ -1163,7 +1121,7 @@ export default function (options) {
|
||||
vp9VideoRangeTypes += '|HDR10';
|
||||
av1VideoRangeTypes += '|HDR10';
|
||||
|
||||
if (browser.tizenVersion >= 3) {
|
||||
if (browser.tizenVersion >= 3 || browser.vidaa) {
|
||||
hevcVideoRangeTypes += '|DOVIWithHDR10';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,8 @@ import globalize from 'lib/globalize';
|
||||
import Dashboard from 'utils/dashboard';
|
||||
import { getParameterByName } from 'utils/url';
|
||||
|
||||
// Disable the naming rules since jstree requires snake_case variables
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
function getNode(item, folderState, selected) {
|
||||
const htmlName = getNodeInnerHtml(item);
|
||||
const node = {
|
||||
@@ -336,4 +338,4 @@ window.MetadataEditor = {
|
||||
getCurrentItemId: getCurrentItemId,
|
||||
setCurrentItemId: setCurrentItemId
|
||||
};
|
||||
|
||||
/* eslint-enable @typescript-eslint/naming-convention */
|
||||
|
||||
@@ -125,8 +125,6 @@ export function isInteractiveElement(element) {
|
||||
export function enable() {
|
||||
const hasMediaSession = 'mediaSession' in navigator;
|
||||
window.addEventListener('keydown', function (e) {
|
||||
if (e.defaultPrevented) return;
|
||||
|
||||
// Skip modified keys
|
||||
if (e.ctrlKey || e.altKey || e.metaKey || e.shiftKey) return;
|
||||
|
||||
|
||||
@@ -58,8 +58,6 @@ function renderHeader() {
|
||||
skinHeader.classList.add('skinHeader-blurred');
|
||||
skinHeader.innerHTML = html;
|
||||
|
||||
Events.trigger(document, EventType.HEADER_RENDERED);
|
||||
|
||||
headerBackButton = skinHeader.querySelector('.headerBackButton');
|
||||
headerHomeButton = skinHeader.querySelector('.headerHomeButton');
|
||||
mainDrawerButton = skinHeader.querySelector('.mainDrawerButton');
|
||||
|
||||
@@ -935,5 +935,23 @@
|
||||
"Author": "Skrywer",
|
||||
"FallbackMaxStreamingBitrateHelp": "Die maksimum stroom bitrate word as 'n terugval gebruik wanneer ffprobe nie in staat is om die brondstroom bitrate te bepaal nie. Dit help om te voorkom dat kliënte 'n buitensporig hoë transkodering bitrate aanvra, wat die speler kan laat faal en die kodeerder kan oorlaai.",
|
||||
"ErrorDeletingLyrics": "Daar was 'n fout om die lirieke van die bediener te verwyder. Kontroleer asseblief dat Jellyfin skryftoegang tot die media-gids het en probeer weer.",
|
||||
"HeaderAddLyrics": "Voeg Lirieke Toe"
|
||||
"HeaderAddLyrics": "Voeg Lirieke Toe",
|
||||
"Anime": "Anime",
|
||||
"HeaderVideoAdvanced": "Video Gevorderd",
|
||||
"IgnoreDts": "Ignoreer DTS (tydstempel dekodering)",
|
||||
"Illustrator": "Illustreerder",
|
||||
"HeaderNewPlaylist": "Nuwe Snitlys",
|
||||
"HeaderPreviewLyrics": "Lirieke Voorskou",
|
||||
"HeaderUploadLyrics": "Lirieke Oplaai",
|
||||
"HomeVideosPhotos": "Tuisvideo's en foto's",
|
||||
"HeaderRecordingMetadataSaving": "Metadata van die Opname",
|
||||
"HeaderGuestCast": "Byspelers",
|
||||
"HeaderEpisodesStatus": "Episodes se Status",
|
||||
"IgnoreDtsHelp": "Die deaktivering van hierdie opsie mag sommige probleme oplos, soos bv. geen oudio op kanale met aparte oudio- en videostrome.",
|
||||
"HeaderLyricDownloads": "Afgelaaide Lirieke",
|
||||
"HeaderMediaSegmentActions": "Mediasegmente-aksies",
|
||||
"HeaderNextItem": "Volgende {0}",
|
||||
"HeaderNextItemPlayingInValue": "Volgende {0} Speel in {1}",
|
||||
"HeaderNoLyrics": "Geen lirieke gevind nie",
|
||||
"HeaderPerformance": "Prestasie"
|
||||
}
|
||||
|
||||
@@ -118,7 +118,7 @@
|
||||
"BirthDateValue": "Нарадзіўся: {0}",
|
||||
"BirthPlaceValue": "Месца нараджэння: {0}",
|
||||
"BookLibraryHelp": "Падтрымліваюцца аўдыё і падручнікі. Праглядзіце {0} даведнік па назвах кніг {1}.",
|
||||
"BurnSubtitlesHelp": "Вызначце, ці павінен сервер запісваць субтытры непасрэдна на відеа кадры падчас перакадзіравання відэа. Пазбяганне гэтага значна палепшыць выкананне. Выберыце «Аўтаматычны», каб запісваць фарматы на аснове выяў (VobSub, PGS, SUB, IDX і г.д.) і пэўныя субтытры ASS або SSA.",
|
||||
"BurnSubtitlesHelp": "Вызначце, ці павінен сервер запісваць субтытры. Пазбяганне гэтага значна палепшыць выкананне. Выберыце «Аўтаматычны», каб запісваць фарматы на аснове выяў (VobSub, PGS, SUB, IDX і г.д.) і пэўныя субтытры ASS або SSA.",
|
||||
"ButtonArrowRight": "Справа",
|
||||
"ButtonRename": "Перайменаваць",
|
||||
"ButtonResume": "Працягнуць",
|
||||
@@ -1903,5 +1903,34 @@
|
||||
"LabelIsSynced": "Сінхранізавана",
|
||||
"LabelDuration": "Працягласць",
|
||||
"NoLyricsSearchResultsFound": "Тэксты песень не знойдзены.",
|
||||
"FallbackMaxStreamingBitrateHelp": "Максімальны бітрэйт плыні выкарыстоўваецца ў якасці запаснога, калі ffprobe не можа вызначыць бітрэйт зыходнага патоку. Гэта дапамагае прадухіліць кліенты ад запытаў празмерна высокага бітрэйту транскадавання, які можа прывесці да збою прайгравальніка і перагрузкі кадавальніка."
|
||||
"FallbackMaxStreamingBitrateHelp": "Максімальны бітрэйт трансляцыі выкарыстоўваецца ў якасці запаснога варыянту, калі ffprobe не можа вызначыць бітрэйт зыходнага патоку. Гэта дапамагае прадухіліць запыт кліентамі празмерна высокага бітрэйту транскодирования, што можа прывесці да збою прайгравальніка і перагрузкі кадавальнік.",
|
||||
"AllowTonemappingSoftwareHelp": "Адлюстраванне тонаў можа трансфармаваць дынамічны дыяпазон відэа з HDR у SDR, захоўваючы пры гэтым дэталі выявы і колеры, якія з'яўляюцца вельмі важнай інфармацыяй для прадстаўлення арыгінальнай сцэны. У цяперашні час працуе толькі з 10-бітнымі відэа HDR10, HLG і DoVi.",
|
||||
"AlwaysRemuxFlacAudioFilesHelp": "Калі ў вас ёсць файлы, якія ваш браўзер адмаўляецца прайграваць або ў якіх ён недакладна разлічвае пазнакі часу, уключыце гэта ў якасці абыходнага шляху.",
|
||||
"Anime": "Анімэ",
|
||||
"EditLyrics": "Рэдагаваць тэкст песні",
|
||||
"LabelAudioTagSettings": "Налады аўдыятэгаў",
|
||||
"AndOtherArtists": "{0} і {1} іншыя выканаўцы.",
|
||||
"HeaderNewPlaylist": "Новы плэйліст",
|
||||
"HeaderEditPlaylist": "Рэдагаваць плэйліст",
|
||||
"EnableHi10pHelp": "Уключыце, каб пазбегнуць перакадзіравання 10-бітных відэа H.264. Адключыце гэту опцыю, калі відэа паказвае пустыя кадры.",
|
||||
"HeaderAddLyrics": "Дадаць тэкст песні",
|
||||
"LabelAlwaysRemuxFlacAudioFiles": "Заўсёды рэмуксаваць аўдыяфайлы FLAC",
|
||||
"LabelAllowStreamSharing": "Дазволіць агульны доступ да патокаў",
|
||||
"LabelAlwaysRemuxMp3AudioFiles": "Заўсёды рэмуксаваць аўдыяфайлы MP3",
|
||||
"LabelCustomTagDelimiters": "Карыстацкі падзельнік тэгаў",
|
||||
"LabelCustomTagDelimitersHelp": "Сімвалы, якія будуць выкарыстоўвацца ў якасці падзельнікаў для падзелу тэгаў.",
|
||||
"LabelDelimiterWhitelist": "Белы спіс падзельнікаў",
|
||||
"AllowStreamSharingHelp": "Дазволіць Jellyfin дубліраваць паток mpegts з цюнэра і абагульваць гэты дубліраваны паток сваім кліентам. Гэта карысна, калі цюнэр мае ліміт агульнай колькасці патокаў, але таксама можа выклікаць праблемы з прайграваннем.",
|
||||
"LabelAllowFmp4TranscodingContainer": "Дазволіць перакадзіравання fMP4 кантэйнера",
|
||||
"AlwaysBurnInSubtitleWhenTranscoding": "Заўсёды запісваць субтытры пры перакадзіраванні",
|
||||
"AlwaysBurnInSubtitleWhenTranscodingHelp": "Запісваць усе субтытры пры запуску перакадзіравання. Гэта забяспечвае сінхранізацыю субтытраў пасля перакадзіравання за кошт зніжэння хуткасці перакадзіравання.",
|
||||
"AlwaysRemuxMp3AudioFilesHelp": "Калі ў вас ёсць файлы, для якіх ваш браўзер няправільна разлічвае пазнакі часу, уключыце гэта ў якасці абыходнага шляху.",
|
||||
"HeaderMediaSegmentActions": "Дзеянні з медыясегментамі",
|
||||
"MoveToBottom": "Перайсці ўніз",
|
||||
"VideoCodecTagNotSupported": "Тэг відэакодэка не падтрымліваецца",
|
||||
"MessageSplitVersionsError": "Падчас падзелу версій адбылася памылка",
|
||||
"MoveToTop": "Перайсці ўверх",
|
||||
"PasswordMissingSaveError": "Новы пароль не можа быць пустым.",
|
||||
"LabelTrickplayKeyFrameOnlyExtraction": "Стварэнне малюнкаў толькі на аснове ключавых кадраў",
|
||||
"UseCustomTagDelimiters": "Выкарыстоўвайце карыстацкі падзельнік тэгаў"
|
||||
}
|
||||
|
||||
@@ -642,7 +642,7 @@
|
||||
"ChannelNameOnly": "Només el canal {0}",
|
||||
"ChangingMetadataImageSettingsNewContent": "Els canvis als paràmetres de descàrrega de metadades o d'imatge només s'apliquen al contingut nou afegit a la biblioteca. Per aplicar els canvis als títols existents, haureu d'actualitzar les metadades manualment.",
|
||||
"ButtonTogglePlaylist": "Llista de reproducció",
|
||||
"BurnSubtitlesHelp": "Determina si el servidor hauria de gravar els subtítols en transcodificar vídeos. Evitar això millorarà molt el rendiment. Seleccioneu Automàtica per gravar formats basats en imatges (VobSub, PGS, SUB, IDX) i certs subtítols ASS o SSA.",
|
||||
"BurnSubtitlesHelp": "Determina si el servidor hauria de gravar els subtítols. Evitar això millorarà molt el rendiment. Seleccioneu Automàtica per gravar formats basats en imatges (VobSub, PGS, SUB, IDX) i certs subtítols ASS o SSA.",
|
||||
"Browse": "Navega",
|
||||
"BoxRear": "Caixa (posterior)",
|
||||
"BoxSet": "Col·leció",
|
||||
@@ -1185,7 +1185,7 @@
|
||||
"LabelRecordingPathHelp": "Especificar la ubicació per defecte per guardar els enregistraments. Si és buit, s'utilitzarà la carpeta de dades de programa de servidor.",
|
||||
"LabelReasonForTranscoding": "Motiu de transcodificació",
|
||||
"LabelQuickConnectCode": "Codi de Quick Connect",
|
||||
"LabelPublishedServerUriHelp": "Anul·lar l'URI utilitzat per Jellyfin, basat en la interfície, o l'adreça IP de client.",
|
||||
"LabelPublishedServerUriHelp": "Anul·lar l'URI utilitzat per Jellyfin, basat en la interfície, o l'adreça IP de client. Per exemple: internal=http://jellyfin.example.com, external=https://jellyfin.example.com, or all=https://jellyfin.example.com",
|
||||
"LabelPublishedServerUri": "URI servidor publicat",
|
||||
"LabelPublicHttpsPortHelp": "El número de port públic que hauria de ser assignada a l'port HTTPS local.",
|
||||
"LabelPublicHttpPortHelp": "El número de port públic que hauria de ser assignada a l'port local HTTP.",
|
||||
@@ -1396,7 +1396,7 @@
|
||||
"QuickConnectAuthorizeFail": "Codi de Quick Connect no reconegut",
|
||||
"QuickConnectAuthorizeCode": "Introduïu el codi {0} per iniciar sessió",
|
||||
"QuickConnectActivationSuccessful": "Activat amb èxit",
|
||||
"QuickConnect": "Connexió ràpida",
|
||||
"QuickConnect": "Quick Connect",
|
||||
"PluginFromRepo": "{0} des del repositori {1}",
|
||||
"Profile": "Perfil",
|
||||
"ProductionLocations": "Centres de producció",
|
||||
@@ -1763,7 +1763,7 @@
|
||||
"UnknownError": "S'ha produït un error desconegut.",
|
||||
"PleaseConfirmRepositoryInstallation": "Si us plau, prémi OK per confirmar que heu llegit l'anterior i voleu continuar amb l'instal·lació del repositori de complements.",
|
||||
"Unknown": "Desconegut",
|
||||
"SelectAudioNormalizationHelp": "Guany de pista - ajusta el volum de cada pista perquè la reproducció soni al mateix volum. Guany d'àlbum - ajusta el volum de totes les pistes d'un àlbum, mantenint el rang dinàmic de l'àlbum.",
|
||||
"SelectAudioNormalizationHelp": "Guany de pista - ajusta el volum de cada pista perquè la reproducció soni al mateix volum. Guany d'àlbum - ajusta el volum de totes les pistes d'un àlbum, mantenint el rang dinàmic de l'àlbum. Canviant entre “Apagat” i altres opcions requereix reiniciar la reproducció actual.",
|
||||
"HeaderConfirmRepositoryInstallation": "Confirmi l'instal·lació del repositori de complements",
|
||||
"LabelAlbumGain": "Guany de l'Àlbum",
|
||||
"LabelSelectAudioNormalization": "Normalització d'àudio",
|
||||
@@ -1855,7 +1855,7 @@
|
||||
"LabelQscaleHelp": "Escala de qualitat de les imatges generades per ffmpeg, sent 2 la qualitat més alta i 31 la més baixa.",
|
||||
"LabelTrickplayThreads": "Fils de FFmpeg",
|
||||
"ExtractTrickplayImagesHelp": "Les imatges de Trickplay són similars a les imatges de capítols, excepte que abasten tota la longitud del contingut i s'utilitzen per mostrar una vista prèvia quan es desplaça pels vídeos.",
|
||||
"LabelTrickplayAccelEncodingHelp": "En aquests moments només està disponible en QSV, VAAPI i VideoToolbox, aquesta opció no afecta els altres mètodes d'acceleració per maquinari.",
|
||||
"LabelTrickplayAccelEncodingHelp": "En aquests moments només està disponible en QSV, VAAPI, VideoToolbox i RKMPP, aquesta opció no afecta els altres mètodes d'acceleració per maquinari.",
|
||||
"LabelTrickplayAccelEncoding": "Habilitar codificació MJPEG accelerada per maquinari",
|
||||
"ConfirmDeleteLyrics": "L'esborrat d'aquestes lletres, les suprimirà tant del sistema de fitxers com de la vostra biblioteca multimèdia. Esteu segur que voleu continuar?",
|
||||
"ErrorDeletingLyrics": "S'ha produït un error en suprimir les lletres del servidor. Si us plau, comproveu que Jellyfin tingui accés d'escriptura a la carpeta multimèdia i torneu-ho a provar.",
|
||||
@@ -1928,5 +1928,62 @@
|
||||
"AllowTonemappingSoftwareHelp": "El mapatge de tons pot transformar el rang dinàmic d'un vídeo d'HDR a SDR mentre que manté els detalls i els colors de la imatge, que són informació molt important per representar l'escena original. Actualment, només funciona amb vídeos HDR10, HLG i DoVi de 10 bits.",
|
||||
"LabelDuration": "Duració",
|
||||
"LabelDropLyricsHere": "Arrossega i deixa anar les lletres aquí, o fes clic aquí per cercar-les.",
|
||||
"AllowFmp4TranscodingContainerHelp": "sintonitzador reproducció"
|
||||
"AllowFmp4TranscodingContainerHelp": "Permet la transcodificació fMP4 per aquest sincronitzador per permetre contingut HEVC i HDR. No tots els sincronitzadors són compatibles amb aquest contenidor. Desactiva-ho si experimentes problemes de reproducció.",
|
||||
"AllowStreamSharingHelp": "Permet que Jellyfin dupliqui el flux mpegts del sintonitzador i comparteixi aquest flux duplicat amb els seus clients. Això és útil quan el sintonitzador té un límit de recompte total de reproduccions, però també pot causar problemes de reproducció.",
|
||||
"LabelCustomTagDelimiters": "Limitador d'etiquetes personalitzat",
|
||||
"Anime": "Anime",
|
||||
"DisableVbrAudioEncodingHelp": "Evita que el servidor codifiqui àudio en VBR per a aquest client.",
|
||||
"EnableHi10p": "Activar perfil H.264 High 10",
|
||||
"HeaderEditPlaylist": "Edita la llista de reproducció",
|
||||
"HeaderNewPlaylist": "Llista de reproducció nova",
|
||||
"AlwaysRemuxFlacAudioFilesHelp": "Si el teu navegador es nega a reproduir certs tipus de fitxers o calcula erròniament les marques de temps, activa-ho per solucionar el problema.",
|
||||
"AlwaysRemuxMp3AudioFilesHelp": "Si el navegador calcula erròniament les marques de temps de certs fitxers, activa això per solucionar-ho.",
|
||||
"EnableHi10pHelp": "Activar per evitar transcodificació de vídeos en H.264 10-bits. Desactivar-ho si la reproducció del vídeo mostra fotogrames buits.",
|
||||
"DateModified": "Data de modificació",
|
||||
"HeaderAudioAdvanced": "Àudio avançat",
|
||||
"LabelAllowFmp4TranscodingContainer": "Permet el contenidor de transcodificació fMP4",
|
||||
"LabelAudioTagSettings": "Configuració de les etiquetes d'àudio",
|
||||
"LabelCustomTagDelimitersHelp": "Caràcters que es consideraran delimitadors per separar etiquetes.",
|
||||
"LabelQsvDevice": "Dispositiu QSV",
|
||||
"MediaSegmentAction.None": "Cap",
|
||||
"MediaSegmentAction.Skip": "Saltar",
|
||||
"MediaSegmentType.Intro": "Introducció",
|
||||
"LabelDelimiterWhitelist": "Llista blanca de delimitadors",
|
||||
"LabelDelimiterWhitelistHelp": "Elements a excloure de la divisió d'etiquetes. Un element per línia.",
|
||||
"LabelDisableVbrAudioEncoding": "Desactivar codificació d'àudio VBR",
|
||||
"LabelFallbackMaxStreamingBitrate": "Taxa de bitrate màxima de retorn (Mbps)",
|
||||
"MessageCancelSeriesTimerError": "S'ha produït un error cancel·lant el temporitzador de la sèrie",
|
||||
"MessageCancelTimerError": "S'ha produït un error cancel·lant el temporitzador",
|
||||
"MoviesAndShows": "Pel·lícules i Sèries",
|
||||
"LabelLyricDownloaders": "Descarregador de lletres",
|
||||
"LabelQsvDeviceHelp": "Específica el dispositiu Intel QSV en els sistemes amb múltiples GPU. En sistemes Linux, això és un node de renderitzat, per exemple, /dev/dri/renderD128. En Windows, és un índex de dispositiu que comença a 0. Deixar en blanc si no se sap el que s'està fent.",
|
||||
"LabelScreensaverTime": "Temps de l'estalvi de pantalla",
|
||||
"LabelScreensaverTimeHelp": "La quantitat de temps d'inactivitat en segons necessària per activar l'estalvi de pantalla.",
|
||||
"MediaSegmentAction.AskToSkip": "Solicitar saltar",
|
||||
"MediaSegmentSkipPrompt": "Saltar {0}",
|
||||
"MediaSegmentType.Commercial": "Comercial",
|
||||
"MediaSegmentType.Recap": "Recapitulació",
|
||||
"MediaSegmentType.Outro": "Tancament",
|
||||
"MediaSegmentType.Preview": "Previsualització",
|
||||
"PlaylistError.UpdateFailed": "Error en actualitzar la llista de reproducció",
|
||||
"LabelAlwaysRemuxFlacAudioFiles": "Sempre re-multiplexa els fitxers d'àudio FLAC",
|
||||
"LabelAlwaysRemuxMp3AudioFiles": "Sempre re-multiplexa els fitxers d'àudio MP3",
|
||||
"LabelSaveTrickplayLocally": "Desar imatges de trucs al costat dels mitjans",
|
||||
"LabelSaveTrickplayLocallyHelp": "Desar les imatges dels trucs dins de les carpetes dels mitjans les posarà al costat d'aquests per facilitar l'accés i la migració.",
|
||||
"LyricDownloadersHelp": "Activa i classifica els descarregadors de lletres preferits en ordre de prioritat.",
|
||||
"MessageSplitVersionsError": "S'ha produït un error separant les versions",
|
||||
"LabelAllowStreamSharing": "Permet la reproducció compartida",
|
||||
"AlwaysBurnInSubtitleWhenTranscoding": "Sempre grava els subtítols quan es transcodifiqui",
|
||||
"AlwaysBurnInSubtitleWhenTranscodingHelp": "Grava tots els subtítols quan la transcodificació s'activi. Això implica que es redueixi la velocitat de transcodificació, però assegura que els subtítols estiguin sincronitzats després de la transcodificació.",
|
||||
"HeaderMediaSegmentActions": "Accions dels segments dels mitjans",
|
||||
"LabelMediaSegmentsType": "{0} Segments",
|
||||
"PreferNonstandardArtistsTag": "Preferir l'etiqueta ARTISTS si estan disponibles",
|
||||
"ReplaceTrickplayImages": "Substitueix les imatges trickplay existents",
|
||||
"UseCustomTagDelimiters": "Utilitza delimitador d'etiquetes personalitzat",
|
||||
"PreferNonstandardArtistsTagHelp": "Utilitza l'etiqueta no estàndard ARTISTS en lloc de l'etiqueta ARTIST quan estigui disponible.",
|
||||
"UseCustomTagDelimitersHelp": "Separa les etiquetes artista/gènere amb caràcters personalitzats.",
|
||||
"RenderPgsSubtitle": "Renderitzat experimental de subtitols PGS",
|
||||
"VideoCodecTagNotSupported": "L'etiqueta del còdec de vídeo no és compatible",
|
||||
"RenderPgsSubtitleHelp": "Determina si el client ha de renderitzar els subtítols PGS en lloc d'usar els subtítols incrustats. Això pot evitar la transcodificació de part del servidor a canvi del rendiment de renderitzat de part del client.",
|
||||
"FallbackMaxStreamingBitrateHelp": "El bitrate màxim s'usa com a alternativa quan ffprobe no pot determinar el flux de l'origen. Això ajuda a prevenir que els clients sol·licitin un bitrate de transcodificació excessivament alt, el qual provocaria errors en el reproductor o sobrecarregar el codificador."
|
||||
}
|
||||
|
||||
@@ -1986,7 +1986,7 @@
|
||||
"PlaylistError.UpdateFailed": "Aktualizace seznamu skladeb se nezdařila",
|
||||
"HeaderMediaSegmentActions": "Akce segmentu médií",
|
||||
"LabelMediaSegmentsType": "{0} segmentů",
|
||||
"MediaSegmentSkipPrompt": "Přeskočit",
|
||||
"MediaSegmentSkipPrompt": "Přeskočit {0}",
|
||||
"MediaSegmentAction.AskToSkip": "Zeptat se, zda přeskočit",
|
||||
"Anime": "Anime",
|
||||
"MoviesAndShows": "Filmy a seriály"
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"Alerts": "Advarsler",
|
||||
"All": "Alle",
|
||||
"AllChannels": "Alle kanaler",
|
||||
"AllEpisodes": "Alle afsnit",
|
||||
"AllEpisodes": "Alle episoder",
|
||||
"AllLibraries": "Alle biblioteker",
|
||||
"AllowHWTranscodingHelp": "Tillad modtageren at omkode afspilninger på farten. Dette kan begrænse den ellers nødvendige omkodning af serveren.",
|
||||
"AllowMediaConversion": "Tillad mediekonvertering",
|
||||
@@ -920,7 +920,7 @@
|
||||
"XmlTvSportsCategoriesHelp": "Programmer med disse kategorier bliver vist som sportsprogrammer. Adskil flere med '|'.",
|
||||
"Yesterday": "I går",
|
||||
"AirDate": "Udgivelsesdato",
|
||||
"Albums": "Album",
|
||||
"Albums": "Albummer",
|
||||
"Artists": "Kunstnere",
|
||||
"Books": "Bøger",
|
||||
"Collections": "Samlinger",
|
||||
|
||||
@@ -1178,7 +1178,7 @@
|
||||
"OptionMax": "Maximum",
|
||||
"OptionSubstring": "Teilzeichenfolge",
|
||||
"Premiere": "Premiere",
|
||||
"Smart": "Schlau",
|
||||
"Smart": "Smart",
|
||||
"Tags": "Markierungen",
|
||||
"TagsValue": "Markierungen: {0}",
|
||||
"Thumb": "Miniaturansicht",
|
||||
@@ -1362,7 +1362,7 @@
|
||||
"MusicVideos": "Musikvideos",
|
||||
"Image": "Bild",
|
||||
"Data": "Daten",
|
||||
"SpecialFeatures": "Besonderheiten",
|
||||
"SpecialFeatures": "Bonusmaterial",
|
||||
"Poster": "Poster",
|
||||
"Photo": "Foto",
|
||||
"Other": "Sonstiges",
|
||||
@@ -1890,7 +1890,7 @@
|
||||
"SaveLyricsIntoMediaFolders": "Liedtexte in Medienordnern speichern",
|
||||
"SaveLyricsIntoMediaFoldersHelp": "Das Speichern von Liedtexten zusammen mit den Audiodateien ermöglicht eine einfachere Verwaltung.",
|
||||
"PlaylistPublic": "Erlaube öffentlichen Zugriff",
|
||||
"Colorist": "Colorist",
|
||||
"Colorist": "Kolorist",
|
||||
"Penciller": "Bleistiftzeichner",
|
||||
"Inker": "Inker",
|
||||
"Letterer": "Beschreiber",
|
||||
@@ -1950,7 +1950,7 @@
|
||||
"LabelFallbackMaxStreamingBitrate": "Maximale Fallback-Stream-Bitrate (Mbps)",
|
||||
"VideoCodecTagNotSupported": "Das Video-Codec-Tag wird nicht unterstützt",
|
||||
"LabelLyricDownloaders": "Songtext-Downloader",
|
||||
"LyricDownloadersHelp": "Aktivieren und ordnen Sie Ihre bevorzugten Untertitel-Downloader nach der Priorität.",
|
||||
"LyricDownloadersHelp": "Aktivieren und ordnen Sie Ihre bevorzugten Songtext-Downloader nach der Priorität.",
|
||||
"ReplaceTrickplayImages": "Ersetzen vorhandener Trickplay-Bilder",
|
||||
"LabelSaveTrickplayLocally": "Trickplay-Bilder bei den Medien speichern",
|
||||
"LabelSaveTrickplayLocallyHelp": "Wenn Sie Trickplay-Bilder in Medienordnern speichern, werden sie bei Ihren Medien abgelegt und ermöglichen so eine einfache Migration und den Zugriff.",
|
||||
@@ -1989,5 +1989,5 @@
|
||||
"MediaSegmentSkipPrompt": "{0} überspringen",
|
||||
"MediaSegmentAction.AskToSkip": "Vor dem Überspringen nachfragen",
|
||||
"Anime": "Anime",
|
||||
"MoviesAndShows": "Fime und Serien"
|
||||
"MoviesAndShows": "Filme und Serien"
|
||||
}
|
||||
|
||||
@@ -396,7 +396,7 @@
|
||||
"LabelCustomRating": "Προσαρμοσμένη αξιολόγηση",
|
||||
"LabelDashboardTheme": "Θέμα Εμφάνισης Πίνακα Ελέγχου Server",
|
||||
"LabelDateAdded": "Ημερνία προσθήκης",
|
||||
"LabelDateTimeLocale": "Ημερομηνία τοπική ώρα",
|
||||
"LabelDateTimeLocale": "Τοπική ημερομηνία και ώρα",
|
||||
"LabelDay": "Ημέρα της εβδομάδας",
|
||||
"LabelDeathDate": "Ημερομηνία Θανάτου",
|
||||
"LabelDefaultScreen": "Προεπιλεγμένη οθόνη",
|
||||
@@ -563,7 +563,7 @@
|
||||
"LabelSkipForwardLength": "Παράλειψη προς τα εμπρός",
|
||||
"LabelSkipIfAudioTrackPresent": "Παράλειψη εάν το προεπιλεγμένο ηχητικό κομμάτι ταιριάζει με τη γλώσσα λήψης",
|
||||
"LabelSkipIfGraphicalSubsPresent": "Παράλειψη εάν το βίντεο περιέχει ήδη ενσωματωμένους υπότιτλους",
|
||||
"LabelSkipIfGraphicalSubsPresentHelp": "Κρατώντας εκδόσεις κειμένου των υπότιτλων θα οδηγήσει σε πιο αποτελεσματική παράδοση και θα μειώσει την πιθανότητα της μετακωδικοποίησης βίντεο.",
|
||||
"LabelSkipIfGraphicalSubsPresentHelp": "Κρατώντας εκδόσεις κειμένου των υπότιτλων θα έχει ως αποτέλεσμα πιο την αποτελεσματική παράδοση και θα μειώσει την πιθανότητα της μετακωδικοποίησης βίντεο.",
|
||||
"LabelSonyAggregationFlagsHelp": "Καθορίζει το περιεχόμενο του στοιχείου 'aggregationFlags' στο 'urn:schemas-sonycom:av' namespace.",
|
||||
"LabelSortBy": "Ταξινόμηση κατά",
|
||||
"LabelSortOrder": "Σειρά ταξινόμησης",
|
||||
@@ -1409,7 +1409,7 @@
|
||||
"LabelHardwareEncodingOptions": "Επιλογές κωδικοποίησης υλικού",
|
||||
"OptionDateShowAdded": "Ημερομηνία Εμφάνιση Προσθήκης",
|
||||
"LabelMetadataSavers": "Εξοικονόμητες μεταδεδομένων",
|
||||
"Localization": "Τοπικόπησει",
|
||||
"Localization": "Γλωσσική τοπικοποίηση",
|
||||
"MediaInfoColorSpace": "Χρωματικός χώρος",
|
||||
"MediaInfoInterlaced": "Πεπλεγμένα",
|
||||
"MediaInfoVideoRange": "Εύρος βίντεο",
|
||||
@@ -1691,12 +1691,12 @@
|
||||
"LabelParallelImageEncodingLimit": "Όριο παράλληλης κωδικοποίησης εικόνας",
|
||||
"HeaderRecordingMetadataSaving": "Καταγραφή Μεταδεδομένων",
|
||||
"HeaderPerformance": "Επίδοση",
|
||||
"LabelDummyChapterDurationHelp": "Το διάστημα εξαγωγής εικόνων του κεφαλαίου σε δευτερόλεπτα.",
|
||||
"LabelDummyChapterDurationHelp": "Το διάστημα ανάμεσα στα ψεύτικα κεφάλαια. Ορισμός σε 0 για την απενεργοποίηση παραγωγής ψεύτικων κεφαλαίων. Η μεταβολή αυτού δεν θα έχει επίδραση στα ήδη υπάρχοντα ψεύτικα κεφάλαια.",
|
||||
"HeaderDummyChapter": "Εικόνες Κεφαλαίου",
|
||||
"LabelDummyChapterCount": "Όριο",
|
||||
"LabelDummyChapterCountHelp": "Ο μέγιστος αριθμός εικόνων κεφαλαίου που θα εξαχθεί για κάθε αρχείο πολυμέσων.",
|
||||
"LabelChapterImageResolution": "Ανάλυση",
|
||||
"LabelChapterImageResolutionHelp": "Η ανάλυση των εξαγόμενων εικόνων κεφαλαίου.",
|
||||
"LabelChapterImageResolutionHelp": "Η ανάλυση των εξαγόμενων εικόνων κεφαλαίου. Η μεταβολή αυτού δεν θα έχει επίδραση στα ήδη υπάρχοντα ψεύτικα κεφάλαια.",
|
||||
"AllowCollectionManagement": "Επίτρεψε στον χρήστη να διαχειρίζεται συλλογές",
|
||||
"AllowSegmentDeletion": "Διαγραφή τμημάτων",
|
||||
"HeaderEpisodesStatus": "Κατάσταση Επεισοδίου",
|
||||
@@ -1829,8 +1829,8 @@
|
||||
"LabelAlbumGain": "Ένταση Άλμπουμ",
|
||||
"HeaderLyricDownloads": "Λήψεις Στίχων",
|
||||
"HeaderMediaSegmentActions": "Δράσεις τμημάτων μέσων ενημέρωσης",
|
||||
"LabelAudioTagSettings": "Ρυθμίσεις tag ήχου",
|
||||
"LabelCustomTagDelimiters": "Προσαρμοσμένος διαχωριστής tag",
|
||||
"LabelAudioTagSettings": "Ρυθμίσεις ετικετών ήχου",
|
||||
"LabelCustomTagDelimiters": "Προσαρμοσμένος οριοθέτης ετικετών",
|
||||
"MediaSegmentAction.AskToSkip": "Ερώτηση για Παράληψη",
|
||||
"MediaSegmentAction.Skip": "Παράλειψη",
|
||||
"MediaSegmentSkipPrompt": "Παράλειψη {0}",
|
||||
@@ -1839,8 +1839,17 @@
|
||||
"MediaSegmentType.Outro": "Έξοδος",
|
||||
"MediaSegmentType.Preview": "Προεπισκόπηση",
|
||||
"MediaSegmentType.Recap": "Σύνοψη",
|
||||
"LabelAlwaysRemuxFlacAudioFiles": "Να γίνεται πάντα remux στα αρχεία ήχου FLAC",
|
||||
"LabelAlwaysRemuxMp3AudioFiles": "Να γίνεται πάντα remux στα αρχεία ήχου MP3",
|
||||
"LabelAlwaysRemuxFlacAudioFiles": "Να γίνεται πάντα επανακωδικοποίηση στα αρχεία ήχου FLAC",
|
||||
"LabelAlwaysRemuxMp3AudioFiles": "Να γίνεται πάντα επανακωδικοποίηση στα αρχεία ήχου MP3",
|
||||
"LabelSelectPreferredTranscodeVideoAudioCodec": "Προτιμώμενο codec διακωδικοποίησης ήχου για αναπαραγωγή βίντεο",
|
||||
"LabelAllowStreamSharing": "Επίτρεψε το stream sharing"
|
||||
"LabelAllowStreamSharing": "Επίτρεψε το stream sharing",
|
||||
"LabelWebVersion": "Έκδοση Web",
|
||||
"LabelEnablePlugin": "Ενεργοποίηση πρόσθετου",
|
||||
"Anime": "Anime",
|
||||
"MessageSplitVersionsError": "Ένα σφάλμα προέκυψε κατά τον διαχωρισμό εκδόσεων",
|
||||
"LabelBuildVersion": "Έκδοση build",
|
||||
"LabelCustomTagDelimitersHelp": "Χαρακτήρες που διαχωρίζουν ετικέτες.",
|
||||
"LabelServerVersion": "Έκδοση διακομιστή",
|
||||
"LabelDelimiterWhitelistHelp": "Στοιχεία που εξαιρούνται από τον διαχωρισμό ετικετών. Ένα στοιχείο ανά γραμμή.",
|
||||
"LabelDropLyricsHere": "Σύρε τους στίχους εδώ, ή κάνε κλικ για περιήγηση."
|
||||
}
|
||||
|
||||
@@ -1954,7 +1954,7 @@
|
||||
"RenderPgsSubtitle": "Experimental PGS subtitle rendering",
|
||||
"RenderPgsSubtitleHelp": "Determine if the client should render PGS subtitles instead of using burned in subtitles. This can avoid server-side transcoding in exchange of client-side rendering performance.",
|
||||
"LabelLyricDownloaders": "Lyric downloaders",
|
||||
"LyricDownloadersHelp": "Enable and rank your preferred subtitle downloaders in order of priority.",
|
||||
"LyricDownloadersHelp": "Enable and rank your preferred lyric downloaders in order of priority.",
|
||||
"LabelAudioTagSettings": "Audio Tag settings",
|
||||
"LabelCustomTagDelimiters": "Custom Tag Delimiter",
|
||||
"LabelCustomTagDelimitersHelp": "Characters to be treated as delimiters to separate tags.",
|
||||
@@ -1988,5 +1988,6 @@
|
||||
"PlaylistError.UpdateFailed": "Error updating playlist",
|
||||
"MediaSegmentAction.AskToSkip": "Ask To Skip",
|
||||
"MediaSegmentSkipPrompt": "Skip {0}",
|
||||
"Anime": "Anime"
|
||||
"Anime": "Anime",
|
||||
"MoviesAndShows": "Films and Programmes"
|
||||
}
|
||||
|
||||
@@ -452,7 +452,6 @@
|
||||
"HeaderMetadataSettings": "Metadata Settings",
|
||||
"HeaderMoreLikeThis": "More Like This",
|
||||
"HeaderMusicQuality": "Music Quality",
|
||||
"HeaderMyDevice": "My Device",
|
||||
"HeaderMyMedia": "My Media",
|
||||
"HeaderMyMediaSmall": "My Media (small)",
|
||||
"HeaderNavigation": "Navigation",
|
||||
@@ -683,8 +682,6 @@
|
||||
"LabelDynamicExternalId": "{0} Id",
|
||||
"LabelEnableAudioVbr": "Enable VBR audio encoding",
|
||||
"LabelEnableAudioVbrHelp": "Variable bitrate offers better quality to average bitrate ratio, but in some rare cases may cause buffering and compatibility issues.",
|
||||
"LabelEnableAutomaticPortMap": "Enable automatic port mapping",
|
||||
"LabelEnableAutomaticPortMapHelp": "Automatically forward public ports on your router to local ports on your server via UPnP. This may not work with some router models or network configurations. Changes will not apply until after a server restart.",
|
||||
"LabelEnableHardwareDecodingFor": "Enable hardware decoding for",
|
||||
"LabelEnableHttps": "Enable HTTPS",
|
||||
"LabelEnableHttpsHelp": "Listen on the configured HTTPS port. A valid certificate must also be supplied for this to take effect.",
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1760,7 +1760,7 @@
|
||||
"LabelThrottleDelaySecondsHelp": "Tiempo en segundos después de que la transcodificación entre en aceleración. Deben ser los suficientes para que el buffer del cliente siga operando. Unicamente funciona si la aceleración está habilitada.",
|
||||
"LabelSegmentKeepSeconds": "Tiempo para guardar segmentos",
|
||||
"LabelSegmentKeepSecondsHelp": "Tiempo en segundos durante el cual se deben conservar los segmentos antes de que se sobrescriban. Debe ser mayor que \"Aceleración después\" de la descarga por parte del cliente. Solo funciona si la eliminación de segmentos está habilitada.",
|
||||
"AllowAv1Encoding": "Permitir encodificación en formato AV1",
|
||||
"AllowAv1Encoding": "Permitir la codificación en formato AV1",
|
||||
"GoHome": "Ir a Inicio",
|
||||
"UnknownError": "Un error desconocido ocurrió.",
|
||||
"GridView": "Vista en Cuadrícula",
|
||||
@@ -1886,7 +1886,7 @@
|
||||
"LabelTileHeight": "Altura del Mosaico",
|
||||
"LabelTileHeightHelp": "Número máximo de imágenes por mosaico en la dirección Y.",
|
||||
"Reset": "Reinicializar",
|
||||
"HeaderNextItemPlayingInValue": "Siguiente {0} Jugando en {1}",
|
||||
"HeaderNextItemPlayingInValue": "Siguiente {0} Reproduciendo en {1}",
|
||||
"HeaderUploadLyrics": "Subir Letra",
|
||||
"HeaderNextItem": "Siguiente {0}",
|
||||
"NoLyricsSearchResultsFound": "No se encontraron letras.",
|
||||
@@ -1965,5 +1965,13 @@
|
||||
"UseCustomTagDelimiters": "Usar delimitador de etiquetas personalizado",
|
||||
"UseCustomTagDelimitersHelp": "Divida etiquetas de artista/género con caracteres personalizados.",
|
||||
"Trickplay": "truco",
|
||||
"LabelTrickplayKeyFrameOnlyExtractionHelp": "Extraiga fotogramas clave solo para un procesamiento significativamente más rápido con una sincronización menos precisa. Si el decodificador de hardware configurado no admite este modo, utilizará el decodificador de software en su lugar."
|
||||
"LabelTrickplayKeyFrameOnlyExtractionHelp": "Extraiga fotogramas clave solo para un procesamiento significativamente más rápido con una sincronización menos precisa. Si el decodificador de hardware configurado no admite este modo, utilizará el decodificador de software en su lugar.",
|
||||
"HeaderNewPlaylist": "Nueva lista de reproducción",
|
||||
"LabelQsvDeviceHelp": "Especifique el dispositivo para Intel QSV en un sistema con múltiples GPU. En Linux, este es el nodo de renderizado, por ejemplo, /dev/dri/renderD128. En Windows, este es el índice del dispositivo comenzando desde 0. Déjelo en blanco a menos que sepa lo que está haciendo.",
|
||||
"MediaSegmentSkipPrompt": "Saltar {0}",
|
||||
"LabelMediaSegmentsType": "{0} Segmentos",
|
||||
"HeaderEditPlaylist": "Editar lista de reproducción",
|
||||
"LabelQsvDevice": "Dispositivo QSV",
|
||||
"MediaSegmentAction.Skip": "Saltar",
|
||||
"MediaSegmentType.Commercial": "Comercial"
|
||||
}
|
||||
|
||||
@@ -1764,7 +1764,7 @@
|
||||
"LabelSegmentKeepSecondsHelp": "Tiempo en segundos durante el cual se deben conservar los segmentos después de que el cliente los descarga. Solo funciona si la eliminación de segmentos está habilitada.",
|
||||
"LabelBackdropScreensaverInterval": "Intervalo del fondo protector de pantalla",
|
||||
"LabelBackdropScreensaverIntervalHelp": "El tiempo en segundos entre diferentes fondos cuando se utiliza el fondo protector de pantalla.",
|
||||
"AllowAv1Encoding": "Permitir encodificación en formato AV1",
|
||||
"AllowAv1Encoding": "Permitir la codificación en formato AV1",
|
||||
"GoHome": "Ir a Inicio",
|
||||
"UnknownError": "Un error desconocido ocurrió.",
|
||||
"GridView": "Vista en Cuadrícula",
|
||||
@@ -1971,5 +1971,16 @@
|
||||
"MessageSplitVersionsError": "Ocurrió un error al dividir las versiones",
|
||||
"UseCustomTagDelimiters": "Usar delimitador de etiqueta personalizado",
|
||||
"UseCustomTagDelimitersHelp": "Separar etiquetas de artista/género con caracteres personalizados.",
|
||||
"VideoCodecTagNotSupported": "La etiqueta del códec de video no es compatible"
|
||||
"VideoCodecTagNotSupported": "La etiqueta del códec de video no es compatible",
|
||||
"MediaSegmentAction.AskToSkip": "Solicitar saltar",
|
||||
"HeaderEditPlaylist": "Editar lista de reproducción",
|
||||
"LabelMediaSegmentsType": "{0} Segmentos",
|
||||
"LabelQsvDevice": "Dispositivo QSV",
|
||||
"MediaSegmentType.Intro": "Introducción",
|
||||
"Anime": "Anime",
|
||||
"HeaderNewPlaylist": "Nueva lista de reproducción",
|
||||
"MediaSegmentAction.Skip": "Saltar",
|
||||
"MediaSegmentSkipPrompt": "Saltar {0}",
|
||||
"MediaSegmentType.Commercial": "Comercial",
|
||||
"MediaSegmentType.Preview": "Adelanto"
|
||||
}
|
||||
|
||||
@@ -109,7 +109,7 @@
|
||||
"ButtonNextTrack": "Seuraava raita",
|
||||
"ButtonOk": "Ok",
|
||||
"ButtonOpen": "Avaa",
|
||||
"BurnSubtitlesHelp": "Määritä polttaako palvelin tekstitykset transkoodauksen aikana suoraan videoon. Tämä kasvattaa palvelimen kuormitusta merkittävästi. 'Automaattinen' polttaa kuva- (mm. VobSub, PGS ja SUB/IDX) ja tietyt tekstipohjaiset (ASS/SSA) tekstitykset.",
|
||||
"BurnSubtitlesHelp": "Määritä polttaako palvelin tekstitykset suoraan videoon. Tämä kasvattaa palvelimen kuormitusta merkittävästi. 'Automaattinen' polttaa kuva- (mm. VobSub, PGS ja SUB/IDX) ja tietyt tekstipohjaiset (ASS/SSA) tekstitykset.",
|
||||
"ButtonParentalControl": "Lapsilukko",
|
||||
"ButtonPause": "Tauko",
|
||||
"ButtonPreviousTrack": "Edellinen raita",
|
||||
@@ -233,7 +233,7 @@
|
||||
"EnableStreamLooping": "Uudelleentoista suoralähetykset automaattisesti",
|
||||
"EnableNextVideoInfoOverlayHelp": "Näytä videotoiston lähestyessä loppua tietoja toistolistalta seuraavaksi toistettavasta videosta.",
|
||||
"ClientSettings": "Pääteasetukset",
|
||||
"AllowFfmpegThrottlingHelp": "Kun transkoodaus tai remuksaus ehtii riittävästi toiston edelle, keskeytä käsittely resurssien säästämiseksi. Tämä on hyödyllistä lähinnä katseltaessa ilman toistokohdan jatkuvia vaihteluita. Poista asetus käytöstä, mikäli toistossa ilmenee ongelmia.",
|
||||
"AllowFfmpegThrottlingHelp": "Tauota transkoodausta sen ehtiessä riittävästi toiston edelle. Hyödyllistä lähinnä katseltaessa ilman jatkuvaa toistokohdan muuttamista. Poista asetus käytöstä mikäli kohtaat ongelmia.",
|
||||
"AllowFfmpegThrottling": "Rajoita transkoodausta",
|
||||
"ErrorDeletingItem": "Poistettaessa tiedostoa palvelimelta tapahtui virhe. Varmista, että Jellyfinillä on kirjoitusoikeus mediakansioon ja yritä uudelleen.",
|
||||
"ErrorAddingXmlTvFile": "Käytettäessä XMLTV-tiedostoa tapahtui virhe. Varmista, että tiedosto on olemassa ja yritä uudelleen.",
|
||||
@@ -613,7 +613,7 @@
|
||||
"RefreshDialogHelp": "Metatiedot päivitetään hallintapaneelissa määritettyjen asetusten ja Internet-sisältölähteiden perusteella.",
|
||||
"Refresh": "Päivitä",
|
||||
"Recordings": "Tallennukset",
|
||||
"RecordingScheduled": "Tallennus ajoitettu.",
|
||||
"RecordingScheduled": "Tallennus ajastettu.",
|
||||
"RecordingCancelled": "Tallennus peruttu.",
|
||||
"RecordSeries": "Tallenna sarja",
|
||||
"Record": "Tallenna",
|
||||
@@ -742,7 +742,7 @@
|
||||
"LabelBirthDate": "Syntymäaika",
|
||||
"LabelArtists": "Esittäjät",
|
||||
"LabelAlbum": "Albumi",
|
||||
"LabelAirTime": "Lähetysaika",
|
||||
"LabelAirTime": "Esitysaika",
|
||||
"LabelAccessDay": "Viikonpäivä",
|
||||
"Label3DFormat": "3D-formaatti",
|
||||
"Kids": "Lapset",
|
||||
@@ -803,7 +803,7 @@
|
||||
"LabelHardwareAccelerationTypeHelp": "Laitteistokiihdytys vaatii lisämäärityksiä.",
|
||||
"LabelHardwareAccelerationType": "Laitteistokiihdytys",
|
||||
"LabelEncoderPreset": "Koodauksen esiasetus",
|
||||
"LabelH264Crf": "H.264-enkoodauksen CRF",
|
||||
"LabelH264Crf": "H.264 pakkauksen CRF",
|
||||
"LabelForgotPasswordUsernameHelp": "Anna käyttäjätunnuksesi, jos muistat sen.",
|
||||
"LabelEveryXMinutes": "Joka",
|
||||
"LabelEndDate": "Päättymispäivä",
|
||||
@@ -1025,7 +1025,7 @@
|
||||
"HeaderAccessSchedule": "Käyttöaikataulu",
|
||||
"HeaderAccessScheduleHelp": "Rajoita käyttö tiettyihin aikoihin luomalla käyttöaikataulu.",
|
||||
"HardwareAccelerationWarning": "Laitteistokiihdytyksen käyttöönotto voi joissain ympäristöissä aiheuttaa epävakautta. Varmista, että käyttöjärjestelmän ja näytönohjaimen ajurit ovat ajan tasalla. Mikäli huomaat videotoistossa ongelmia käyttöönoton jälkeen, palauta \"Ei mitään\" -asetus.",
|
||||
"EncoderPresetHelp": "Valitse nopeampi arvo kohentaaksesi suorituskykyä tai hitaampi arvo parantaaksesi kuvanlaatua.",
|
||||
"EncoderPresetHelp": "Nopeampi asetus parantaa transkoodauksen nopeutta kuvanlaadun kustannuksella, ja hitaampi kuvanlaatua nopeuden kustannuksella.",
|
||||
"H264CrfHelp": "Constant Rate Factor (CRF) on x264 -enkooderin kuvanlaadun vakioasetus. Voit valita arvon lukujen 0 ja 51 väliltä, jossa matalammat arvot tarkoittavat parempaa kuvanlaatua (suurempien tiedostokokojen hinnalla). Järkevät arvot ovat väliltä 18-28. Oletusarvo x264:lle on 23, joten voit käyttää sitä lähtökohtana.",
|
||||
"GuideProviderSelectListings": "Valitse luettelot",
|
||||
"GuideProviderLogin": "Kirjaudu",
|
||||
@@ -1058,15 +1058,15 @@
|
||||
"LabelEvent": "Tapahtuma",
|
||||
"LabelEnableSingleImageInDidlLimit": "Rajoita yhteen upotettuun kuvaan",
|
||||
"LabelEnableHttps": "Ota HTTPS käyttöön",
|
||||
"LabelEnableHardwareDecodingFor": "Käytä laitteistodekoodausta kohteelle",
|
||||
"LabelEnableHardwareDecodingFor": "Käytä laitteistopurkua valituille",
|
||||
"LabelDownMixAudioScale": "Äänen tehostus alasmiksatessa",
|
||||
"LabelDateAddedBehavior": "Uudelle sisällölle käytettävä päiväys",
|
||||
"LabelBlastMessageInterval": "Hereiläolo-viestin väli",
|
||||
"LabelBindToLocalNetworkAddress": "Sido lähiverkon osoitteeseen",
|
||||
"LabelAirsBeforeSeason": "Lähetetään ennen kautta",
|
||||
"LabelAirsBeforeEpisode": "Lähetetään ennen jaksoa",
|
||||
"LabelAirsAfterSeason": "Lähetetään kauden jälkeen",
|
||||
"LabelAirDays": "Lähetyspäivät",
|
||||
"LabelAirsBeforeSeason": "Esitetään ennen kautta",
|
||||
"LabelAirsBeforeEpisode": "Esitetään ennen jaksoa",
|
||||
"LabelAirsAfterSeason": "Esitetään kauden jälkeen",
|
||||
"LabelAirDays": "Esityspäivät",
|
||||
"LabelAccessStart": "Aloitusaika",
|
||||
"LabelAccessEnd": "Lopetusaika",
|
||||
"InstantMix": "Pikasekoitus",
|
||||
@@ -1104,7 +1104,7 @@
|
||||
"RepeatMode": "Toistomoodi",
|
||||
"RepeatOne": "Toista yksi",
|
||||
"ResetPassword": "Nollaa salasana",
|
||||
"Restart": "Aloita alusta",
|
||||
"Restart": "Käynnistä uudelleen",
|
||||
"Rewind": "Kelaa alkuun",
|
||||
"SaveChanges": "Tallenna muutokset",
|
||||
"Profile": "Profiili",
|
||||
@@ -1182,14 +1182,14 @@
|
||||
"EnableQuickConnect": "Salli Pikayhdistys tällä palvelimella",
|
||||
"ButtonUseQuickConnect": "Käytä Pikayhdistystä",
|
||||
"ImportMissingEpisodesHelp": "Tiedot kadonneista jaksoista tuodaan tietokantaan ja näytetään kausina ja sarjoina. Tämä voi aiheuttaa huomattavasti pidempiä kirjastojen tarkistusajoja.",
|
||||
"ImportFavoriteChannelsHelp": "Ainoastaan kanavat, jotka on merkitty suosikkiksi viritinlaitteessa, tuodaan.",
|
||||
"ImportFavoriteChannelsHelp": "Ainoastaan viritinlaitteessa suosikiksi merkityt kanavat tuodaan.",
|
||||
"HeaderTranscodingProfileHelp": "Lisää transkoodausprofiileja osoittamaan, mitä muotoja tulisi käyttää, kun transkoodaus on tarpeen.",
|
||||
"LabelAlbumArtMaxResHelp": "'upnp:albumArtURI'-tietueen välityksellä näytettävän albumitaiteen enimmäistarkkuus.",
|
||||
"KnownProxiesHelp": "Pilkulla eroteltu luettelo välityspalvelinten IP-osoitteista tai isäntänimistä, joita käytetään kun yhdistetään Jellyfin-palvelimeesi. Tämä vaaditaan 'X-Forwarded-For' otsikkojen oikeaan käyttöön. Tallennuksen jälkeen vaaditaan uudelleenkäynnistys.",
|
||||
"LabelInNetworkSignInWithEasyPasswordHelp": "Kirjaudu lähiverkon päätelaitteisiin Helppo PIN -koodilla. Tavallista salasanaa tarvitaan vain kirjauduttaessa etäverkoista. Jos PIN-koodia ei määritetä, ei lähiverkon kirjautumiseen tarvita salasanaa.",
|
||||
"LabelDateAddedBehaviorHelp": "Jos metatietoarvo löytyy, käytetään näiden valintojen sijaan sitä.",
|
||||
"LabelCurrentStatus": "Nykyinen tila",
|
||||
"LabelCachePathHelp": "Määritä välimuistitiedostojen, kuten kuvien, tiedostosijainti. Jätä tyhjäksi käyttääksesi palvelimen oletusta.",
|
||||
"LabelCachePathHelp": "Määritä välimuistitiedostojen, kuten kuvien tiedostosijainti. Jätä tyhjäksi käyttääksesi palvelimen oletusta.",
|
||||
"LabelBlastMessageIntervalHelp": "Määritä hereilläpitoviestien välinen aika sekunteina.",
|
||||
"LabelBindToLocalNetworkAddressHelp": "Korvaa HTTP-palvelimen paikallinen IP-osoite. Jos se on tyhjä, palvelin linkitetään kaikkiin käytettävissä oleviin osoitteisiin. Tämän arvon muuttaminen edellyttää uudelleenkäynnistystä.",
|
||||
"LabelDefaultUserHelp": "Määritä minkä käyttäjän kirjasto liitetyissä laitteissa näytetään. Asetus voidaan laiteprofiilien avulla ohittaa laitekohtaisesti.",
|
||||
@@ -1232,13 +1232,13 @@
|
||||
"EnableTonemapping": "Käytä sävykartoitusta",
|
||||
"EnableBlurHashHelp": "Kuvat, joita ladataan vielä, näytetään yksilöllisellä paikkamerkillä.",
|
||||
"EnableBlurHash": "Ota sumennetut paikkamerkit käyttöön kuville",
|
||||
"AllowTonemappingHelp": "Sävykartoitus voi muuttaa videon dynaamisen alueen HDR:stä SDR:ksi säilyttäen samalla kuvan yksityiskohdat ja värit, jotka ovat kohtauksen alkuperäisen ilmeen kannalta erittäin tärkeitä. Toimii tällä hetkellä vain 10-bit HDR10-, HLG- ja DoVi-videoiden kanssa ja edellyttää soveltuvaa OpenCL- tai CUDA-suoritusalustaa.",
|
||||
"AllowTonemappingHelp": "Sävykartoitus voi muuntaa videon dynaamisen alueen HDR:stä SDR:ksi pyrkien säilyttämään kuvan ilmeen mahdollisimman tarkasti. Toimii tällä hetkellä vain 10-bit HDR10-, HLG- ja DoVi-videoilla, ja edellyttää soveltuvaa suoritusalustaa.",
|
||||
"LabelffmpegPathHelp": "FFmpeg-sovellustiedoston tai -kansion tiedostosijainti.",
|
||||
"LabelKodiMetadataEnablePathSubstitutionHelp": "Mahdollistaa kuvien tiedostosijaintien korvauksen palvelimen korvausasetuksien perusteella.",
|
||||
"ThumbCard": "Pienoiskortti",
|
||||
"LabelKodiMetadataDateFormatHelp": "Kaikki NFO-tiedostojen päiväykset esitetään tässä muodossa.",
|
||||
"LabelIsForced": "Pakotettu",
|
||||
"LabelImageFetchersHelp": "Käytä ja järjestä kuvien lataajat haluamasi painotuksen perusteella. Alemman painotuksen lataajia käytetään vain puuttuvien tietojen täydennykseen.",
|
||||
"LabelImageFetchersHelp": "Valitse ja aseta kuvien lataajat haluamaasi järjestykseen. Alempia lataajia käytetään vain puuttuvien tietojen täydennykseen.",
|
||||
"LabelIdentificationFieldHelp": "Regex-lauseke tai alaotsikko (kirjainten koolla ei välillä).",
|
||||
"LabelIconMaxResHelp": "'upnp:icon'-tietueen välityksellä näytettävien kuvakkeiden enimmäistarkkuus.",
|
||||
"LabelTVHomeScreen": "Televisiotilan aloitusnäyttö",
|
||||
@@ -1246,12 +1246,12 @@
|
||||
"LabelHDHomerunPortRangeHelp": "Rajoittaa HD Homerun -laitteiden UDP-porttialueen tähän arvoon (oletus on 1024 - 65535).",
|
||||
"LabelExtractChaptersDuringLibraryScanHelp": "Pura kirjastopäivityksen yhteydessä tuotavien videoiden kappalekuvat. Muutoin tämä tapahtuu kappalekuvien purun ajoitetun tehtävän aikana, jolloin kirjaston perustarkastus nopeutuu.",
|
||||
"LabelHDHomerunPortRange": "HDHomeRun -portin alue",
|
||||
"LabelH265Crf": "H.265-koodauksen CRF",
|
||||
"LabelH265Crf": "H.265 pakkauksen CRF",
|
||||
"LabelGroupMoviesIntoCollectionsHelp": "Kokoelmiin kuuluvat elokuvat näytetään elokuvalistauksissa kokoelmiin ryhmiteltyinä.",
|
||||
"LabelEnableSSDPTracingHelp": "Ota käyttöön yksityiskohtainen SSDP-seurantaloki. <br/> <b> VAROITUS: </b> Tämä aiheuttaa vakavaa suorituskyvyn heikkenemistä.",
|
||||
"LabelDownMixAudioScaleHelp": "Vahvista ääni sekoitettaessa. Arvo yksi säilyttää alkuperäisen äänenvoimakkuuden.",
|
||||
"LabelAlbumArtHelp": "PN-merkintää käytetään albumitaiteena 'upnp:albumArtURI'-määritteessä kohteessa 'dlna:profileID'. Jotkin laitteet vaativat tietyn arvon kuvan koosta riippumatta.",
|
||||
"Bwdif": "BWDIF",
|
||||
"Bwdif": "Bob Weaver DeInterlacing Filter (BWDIF)",
|
||||
"LabelLineup": "Kokoonpano",
|
||||
"LabelKodiMetadataSaveImagePathsHelp": "Tämä on suositeltavaa, jos kuvatiedostojen nimet eivät noudata Kodin ohjeistuksia.",
|
||||
"LabelKodiMetadataEnableExtraThumbsHelp": "Noudettaessa mediakuvituksia, voidaan ne tallentaa sekä extrafanart-, että extrathumbs-mediakuvituksina parasta Kodi-ulkoasujen yhteensopivuutta varten.",
|
||||
@@ -1282,8 +1282,8 @@
|
||||
"LabelTonemappingPeak": "Sävykartoituksen huippu",
|
||||
"LabelTonemappingParamHelp": "Säädä sävykartoitusalgoritmia. Suositeltu ja oletusarvo on NaN. Tyypillisesti jätetään tyhjäksi.",
|
||||
"LabelTonemappingParam": "Sävykartoituksen parametrit",
|
||||
"LabelTonemappingDesatHelp": "Käytä desaturaatiota korostuksille, jotka ylittävät tämän kirkkaustason. Korkeampi arvo säilyttää enemmän värejä. Asetus auttaa estämään kirkkaiden kohtien epäluonnollisen ylikorostuneet värit muuttamalla ne (pehmeästi) valkoiseksi. Tekee kuvasta luonnollisemman vähentämällä teitoja väriavaruuden ulkopuolisista väreistä. Suositellut ja oletusarovot ovat 0 ja 0.5.",
|
||||
"LabelTonemappingDesat": "Sävykartoituksen desaturaatio",
|
||||
"LabelTonemappingDesatHelp": "Vähentää tämän tason ylittävien värien kylläisyyttä. Auttaa estämään ylikorostuneita värejä muuntamalla väriavaruuden ulkopuoliset värit tasaisesti kohti valkoista. Korkeampi arvo säilyttää enemmän värejä. Suositus- ja oletusarvot ovat 0 ja 0,5.",
|
||||
"LabelTonemappingDesat": "Sävykartoituksen kylläisyys",
|
||||
"LabelTonemappingAlgorithm": "Valitse käytettävä sävykartoitusalgoritmi",
|
||||
"LabelSyncPlayTimeSyncOffset": "Aika poikkeama",
|
||||
"LabelSyncPlayTimeSyncDevice": "Synkronoi aika",
|
||||
@@ -1322,7 +1322,7 @@
|
||||
"LabelRepositoryNameHelp": "Oma nimi, jolla tietovarasto erottuu palvelimen muista tietovarastoista.",
|
||||
"LabelRepositoryName": "Tietovaraston nimi",
|
||||
"LabelQuickConnectCode": "Pikayhdistyskoodi",
|
||||
"LabelPublishedServerUriHelp": "Ohita Jellyfinin käyttämä URI perustuen käyttöliittymän tai asiakasohjelman IP-osoitteeseen.",
|
||||
"LabelPublishedServerUriHelp": "Ohita Jellyfinin käyttämä URI perustuen käyttöliittymän tai asiakasohjelman IP-osoitteeseen",
|
||||
"LabelPublishedServerUri": "Julkaistut palvelimen URIt",
|
||||
"LabelPostProcessorArgumentsHelp": "Käytä sijaintia {path} tallenteen tiedostosijaintina.",
|
||||
"LabelOpenclDeviceHelp": "Tämä on sävykartoitukseen käytettävä OpenCL-laite. Pisteen vasemmalla puolella on alustanumero ja oikealla alustan laitenumero. Oletusarvo on 0.0. Vaatii OpenCL-laitteistokiihdytyksen sisältävän FFmpeg-ohjelmatiedoston.",
|
||||
@@ -1339,7 +1339,7 @@
|
||||
"LabelKodiMetadataUserHelp": "Tallenna NFO-tiedostoihin katselutiedot, joita muut sovellukset voivat hyödyntää.",
|
||||
"LabelKodiMetadataUser": "Käyttäjä, jonka katselutiedot tallennetaan NFO-tiedostoihin",
|
||||
"HeaderContinueReading": "Jatka lukemista",
|
||||
"OptionRequirePerfectSubtitleMatchHelp": "Täydellisen parin edellyttäminen suodattaa tulokset sisältämään vain ne tekstitykset, jotka on testattu ja vahvistettu juuri kyseiselle videotiedostolle. Tämän käytöstä poisto lisää tekstityksen löytymisen todennäköisyyttä, mutta kasvattaa myös virheellisesti ajoitettujen tai väärien tekstitysten todennäköisyyttä.",
|
||||
"OptionRequirePerfectSubtitleMatchHelp": "Täydellisesti sopivien tekstitysten edellyttäminen näyttää vain juuri kyseiselle videotiedostolle sopivat tekstitykset. Valinnan poistaminen lisää todennäköisyyttä löytää tekstityksiä, mutta ajoitukset eivät ehkä täsmää.",
|
||||
"OptionRequirePerfectSubtitleMatch": "Lataa vain videotiedostoille täydellisesti sopivat tekstitykset",
|
||||
"OptionReportByteRangeSeekingWhenTranscodingHelp": "Tämä tarvitaan joillekkin laitteille, jotka eivät hae aikajanalla kovin hyvin.",
|
||||
"OptionReportByteRangeSeekingWhenTranscoding": "Raportoi, että palvelin tukee tavuhakua transkoodatessa",
|
||||
@@ -1351,7 +1351,7 @@
|
||||
"OptionMaxActiveSessionsHelp": "Arvon 0 asettaminen poistaa ominaisuuden käytöstä.",
|
||||
"OptionMaxActiveSessions": "Määritä yhtäaikaisten käyttäjäistuntojen enimmäismäärä.",
|
||||
"OptionLoginAttemptsBeforeLockoutHelp": "Arvolla \"0\" peritään tavallisten käyttäjien \"3\" ja ylläpitäjien \"5\" yritystä. \"-1\" poistaa ominaisuuden käytöstä.",
|
||||
"OptionLoginAttemptsBeforeLockout": "Määritä montako virheellistä kirjautumisyritystä sallitaan, ennen käyttäjän estoa.",
|
||||
"OptionLoginAttemptsBeforeLockout": "Määritä montako virheellistä kirjautumisyritystä sallitaan ennen käyttäjän lukitsemista.",
|
||||
"OptionIgnoreTranscodeByteRangeRequestsHelp": "Nämä pyynnöt käsitellään mutta tavualuepyynnöt sivutetaan.",
|
||||
"OptionHideUserFromLoginHelp": "Hyödyllinen yksityisille ja piilotetuille ylläpitotileille. Käyttäjän on kirjauduttava manuaalisesti kirjoittamalla käyttäjätunnus ja salasana.",
|
||||
"OptionEstimateContentLength": "Arvioi sisällön pituus transkoodatessa",
|
||||
@@ -1403,7 +1403,7 @@
|
||||
"MapChannels": "Aseta kanavat",
|
||||
"ListPaging": "{0}-{1} / {2}",
|
||||
"LeaveBlankToNotSetAPassword": "Jättämällä tämän kentän tyhjäksi et aseta salasanaa.",
|
||||
"LanNetworksHelp": "Pilkulla erotettu lista IP-osoitteista tai IP/netmask merkinnöistä verkkoihin, jotka katsotaan olevan sisäverkossa kun asetetaan kaistarajoituksia. Jos asetettu, kaikki muut IP-osoitteet katsotaan olevan ulkoverkosta ja niihin käytetään ulkoverkon kaistarajoituksia. Jos jätetty tyhjäksi, vain palvelimen oma aliverkko katsotaan sisäverkoksi.",
|
||||
"LanNetworksHelp": "Pilkulla erotettu lista IP-osoitteista tai IP/netmask -merkinnöistä verkkoihin, jotka katsotaan olevan sisäverkossa kun asetetaan kaistarajoituksia. Jos asetettu, kaikki muut IP-osoitteet katsotaan olevan ulkoverkosta ja niihin käytetään ulkoverkon kaistarajoituksia. Jos jätetty tyhjäksi, vain palvelimen oma aliverkko katsotaan sisäverkoksi.",
|
||||
"LabelXDlnaDocHelp": "Määrittää 'X_DLNADOC'-elementin sisällön nimiavaruudessa 'urn:schemas-dlna-org:device-1-0'.",
|
||||
"LabelXDlnaCapHelp": "Määrittää 'X_DLNACAP'-elementin sisällön nimiavaruudessa 'urn:schemas-dlna-org:device-1-0'.",
|
||||
"LabelMaxAudiobookResumeHelp": "Raidat oletetaan täysin toistetuiksi jos toisto pysäytetään, kun jäljellä oleva kesto on vähemmän kuin tämä arvo.",
|
||||
@@ -1415,7 +1415,7 @@
|
||||
"HeaderSyncPlayPlaybackSettings": "Toisto",
|
||||
"HeaderSyncPlaySettings": "SyncPlayn asetukset",
|
||||
"Engineer": "Ääniteknikko",
|
||||
"LabelDisableCustomCss": "Poista palvelimen toimittamat mukautetut CSS-tyylimääritykset käytöstä.",
|
||||
"LabelDisableCustomCss": "Poista palvelimen asettamat mukautetut CSS-tyylimääritykset käytöstä.",
|
||||
"DisableCustomCss": "Älä käytä palvelimella määritettyä, mukautettua CSS-tyyliä",
|
||||
"Console": "Konsoli",
|
||||
"Conductor": "Kapellimestari",
|
||||
@@ -1426,7 +1426,7 @@
|
||||
"HeaderSyncPlayTimeSyncSettings": "Ajan synkronointi",
|
||||
"LabelMaxDaysForNextUpHelp": "Määritä enimmäisaika päivinä, jonka katsomaton sarja pysyy 'Seuraavaksi'-osiossa.",
|
||||
"LabelMaxDaysForNextUp": "'Seuraavaksi'-osion päivien enimmäismäärä",
|
||||
"LabelHardwareEncoding": "Laitteistoenkoodaus",
|
||||
"LabelHardwareEncoding": "Laitteistopakkaus",
|
||||
"SaveSubtitlesIntoMediaFoldersHelp": "Tekstitykset tallennetaan videotiedostojen kansioihin, jolloin niitä on helppo käsitellä.",
|
||||
"PerfectMatch": "Täydellinen pari",
|
||||
"SubtitleDownloadersHelp": "Käytä ja järjestä tekstitysten lataajat haluamasi painotuksen perusteella. Alemman painotuksen lataajia käytetään vain puuttuvien tietojen täydennykseen.",
|
||||
@@ -1437,8 +1437,8 @@
|
||||
"QuickConnectNotActive": "Pikayhdistys ei ole tällä palvelimella käytössä",
|
||||
"QuickConnectNotAvailable": "Pyydä palvelimen ylläpitoa ottamaan Pikayhdistys käyttöön",
|
||||
"QuickConnectInvalidCode": "Virheellinen Pikayhdistyskoodi",
|
||||
"QuickConnectDescription": "Kirjautuaksesi Pikayhdistyksellä, valitse 'Pikayhdistys' laitteelta, josta yrität kirjautua ja syötä näytettävä koodi alle.",
|
||||
"QuickConnectDeactivated": "Pikayhdistys katkaistiin ennen kirjautumispyynnön hyväksyntää",
|
||||
"QuickConnectDescription": "Kirjautuaksesi Pikayhdistyksellä, valitse 'Pikayhdistys' laitteella jolla yrität kirjautua, ja syötä koodi alle.",
|
||||
"QuickConnectDeactivated": "Pikayhdistys katkaistiin ennen kirjautumispyynnön hyväksymistä",
|
||||
"QuickConnectAuthorizeSuccess": "Laitteesi on todennettu!",
|
||||
"QuickConnectAuthorizeFail": "Tuntematon Pikayhdistyskoodi",
|
||||
"QuickConnectAuthorizeCode": "Kirjaudu syöttämällä koodi {0}",
|
||||
@@ -1598,7 +1598,7 @@
|
||||
"AllowEmbeddedSubtitlesAllowImageOption": "Salli kuva",
|
||||
"AllowEmbeddedSubtitlesAllowNoneOption": "Älä salli mitään",
|
||||
"AllowEmbeddedSubtitlesAllowAllOption": "Salli kaikki",
|
||||
"AllowEmbeddedSubtitlesHelp": "Älä käytä tekstityksiä, jotka on upotettu mediatiedostojen säiliöihin. Vaatii täyden kirjastopäivityksen.",
|
||||
"AllowEmbeddedSubtitlesHelp": "Älä käytä mediatiedostojen upotettuja tekstityksiä. Vaatii täyden kirjastopäivityksen.",
|
||||
"AllowEmbeddedSubtitles": "Poista eri tyyppiset upotetut tekstitykset käytöstä",
|
||||
"PreferEmbeddedEpisodeInfosOverFileNamesHelp": "Käytä ensisijaisesti upotettuja jaksojen tietoja, mikäli käytettävissä.",
|
||||
"PreferEmbeddedEpisodeInfosOverFileNames": "Suosi tiedostonimien sijaan upotettuja jaksojen tietoja",
|
||||
@@ -1668,7 +1668,7 @@
|
||||
"LabelVppTonemappingBrightnessHelp": "Käytä kirkkauden vahvistusta VPP-sävykartoituksen kanssa. Suositus- ja oletusarvot ovat 10 ja 0.",
|
||||
"LabelVppTonemappingContrast": "VPP-sävykartoituksen kontrastin vahvistus",
|
||||
"LabelVppTonemappingBrightness": "VPP-sävykartoituksen kirkkauden vahvistus",
|
||||
"IgnoreDtsHelp": "Valinnan käytöstä poisto voi korjata joitakin onhelmia, kuten puuttuvan äänen kanavilla, joilla on erilliset ääni- ja videokanavat.",
|
||||
"IgnoreDtsHelp": "Valinnan poistaminen voi korjata joitakin ongelmia, kuten puuttuvan äänen kanavilla joilla on erilliset ääni- ja videovirrat.",
|
||||
"IgnoreDts": "Ohita DTS (dekoodauksen aikaleima)",
|
||||
"OptionDateShowAdded": "Sarjan lisäysaika",
|
||||
"OptionDateEpisodeAdded": "Jakson lisäysaika",
|
||||
@@ -1718,7 +1718,7 @@
|
||||
"LabelParallelImageEncodingLimitHelp": "Rinnakkain suoritettavien kuvaenkoodauksien enimmäismäärä. Asettamalla arvoksi \"0\" rajoitus asetetaan automaattisesti järjestelmän perusteella.",
|
||||
"HeaderPerformance": "Suorituskyky",
|
||||
"LabelParallelImageEncodingLimit": "Rinnakkaisten kuvaenkoodauksien rajoitus",
|
||||
"LabelEnableAudioVbr": "Käytä äänen VBR-enkoodausta",
|
||||
"LabelEnableAudioVbr": "Käytä vaihtelevaa bittinopeutta äänen pakkaamiseen",
|
||||
"LabelEnableAudioVbrHelp": "Muuttuva bittinopeus (variable bitrate, VBR) tuottaa keskitasoista paremman laadun, mutta saattaa joissakin harvoissa tapauksissa aiheuttaa puskurointi ja yhteensopivuusongelmia.",
|
||||
"Select": "Valitse",
|
||||
"LabelTonemappingMode": "Sävykartoituksen tila",
|
||||
@@ -1787,7 +1787,7 @@
|
||||
"DlnaMovedMessage": "DLNA-ominaisuus on siirtynyt lisäosaan.",
|
||||
"LabelBuildVersion": "Käännetty versio",
|
||||
"LabelServerVersion": "Palvelimen versio",
|
||||
"LabelWebVersion": "Verkko versio",
|
||||
"LabelWebVersion": "Verkkoversio",
|
||||
"AllowVideoToolboxTonemappingHelp": "Laitteistokiihdytetty sävykartoitus VideoToolboxin tuottamana. Se toimii useampien HDR formaattien kanssa, kuten HDR10, HDR10+ ja HLG, mutta se ei toimi Dolby Vision Profile 5 kanssa. Tällä on korkeampi prioriteetti verrattuna muihin Metal käyttöönottoihin.",
|
||||
"ChannelResolutionSDPAL": "SD (PAL)",
|
||||
"ChannelResolutionFullHD": "Täysi HD",
|
||||
@@ -1801,7 +1801,7 @@
|
||||
"DeleteSeries": "Poista sarja",
|
||||
"DeleteEpisode": "Poista jakso",
|
||||
"DeleteName": "Poista {0}",
|
||||
"PlaybackError.ASS_RENDER_ERROR": "ASS/SSA tekstityksien esittäjässä ilmeni virhe.",
|
||||
"PlaybackError.ASS_RENDER_ERROR": "ASS/SSA tekstitysten esittämisessä ilmeni virhe.",
|
||||
"EnableSmoothScroll": "Käytä pehmeää vieritystä",
|
||||
"Lyric": "Sanoitus",
|
||||
"LimitSupportedVideoResolution": "Rajoita videon tuettua enimmäistarkkuutta",
|
||||
@@ -1818,12 +1818,12 @@
|
||||
"EnableLibraryHelp": "Kirjaston poistaminen käytöstä piilottaa sen kaikilta käyttäjiltä.",
|
||||
"LabelAllowContentWithTags": "Salli tagatut kohteet",
|
||||
"LimitSupportedVideoResolutionHelp": "Käytä 'Suurin sallittu videon transkoodaustarkkuus' suurimpana tuettuna videoresoluutiona.",
|
||||
"PlaybackError.MEDIA_DECODE_ERROR": "Toisto epäonnistui: Median dekoodausvirhe",
|
||||
"PlaybackError.MEDIA_DECODE_ERROR": "Toisto epäonnistui: Median purkamisessa tapahtui virhe.",
|
||||
"PlaybackError.MEDIA_NOT_SUPPORTED": "Toisto epäonnistui: Pääte ei tue mediaa.",
|
||||
"PlaybackError.NETWORK_ERROR": "Toisto epäonnistui: Verkkovirhe",
|
||||
"PlaybackError.NETWORK_ERROR": "Toisto epäonnistui: Verkkovirhe.",
|
||||
"PlaybackError.NO_MEDIA_ERROR": "Kelvollista medialähdettä ei löytynyt.",
|
||||
"PlaybackError.PLAYER_ERROR": "Toisto epäonnistui: kriittinen toistovirhe.",
|
||||
"PlaybackError.SERVER_ERROR": "Toisto epäonnistui: Palvelinvirhe",
|
||||
"PlaybackError.SERVER_ERROR": "Toisto epäonnistui: Palvelinvirhe.",
|
||||
"PlaybackError.NotAllowed": "Tämän median toisto ei ole sallittua.",
|
||||
"EnableVideoToolboxTonemapping": "Ota käyttöön VideoToolbox Tone mapping",
|
||||
"AllowMjpegEncoding": "Salli enkoodaus MJPEG formaattiin (käytetään trickplay luomisessa)",
|
||||
@@ -1881,12 +1881,12 @@
|
||||
"EnableDtsHelp": "Ota käyttöön ainoastaan, jos laitteesi tukee DTS ääniä, tai on kytkettynä yhteensopivaan vastaanottimeen. Median toisto saattaa muutoin epäonnistua.",
|
||||
"EnableTrueHd": "Ota TrueHD käyttöön",
|
||||
"HeaderNextItem": "Seuraava {0}",
|
||||
"HeaderNextItemPlayingInValue": "Seuraavaksi {0} joka soi {1}",
|
||||
"HeaderNextItemPlayingInValue": "Seuraavaksi {0} jonka alkuun {1}",
|
||||
"LabelTrickplayKeyFrameOnlyExtraction": "Luo kuvia ainoastaan avainkehyksistä",
|
||||
"PasswordMissingSaveError": "Uusi salasana ei voi olla tyhjä.",
|
||||
"SearchForLyrics": "Etsi sanoituksia",
|
||||
"LabelSelectPreferredTranscodeVideoCodec": "Ensisijainen transkoodaava videokoodekki",
|
||||
"LabelEnablePlugin": "Käyttöönota lisäosa",
|
||||
"LabelEnablePlugin": "Käytä lisäosaa",
|
||||
"MoveToBottom": "Siirrä alimmaiseksi",
|
||||
"MoveToTop": "Siirrä ylimmäiseksi",
|
||||
"PluginDisableError": "Virhe lisäosan käytöstä poistamisessa.",
|
||||
@@ -1898,7 +1898,7 @@
|
||||
"HeaderPreviewLyrics": "Esikatsele kappaleen sanoja",
|
||||
"HeaderUploadLyrics": "Lähetä sanoitukset",
|
||||
"LabelDuration": "Kesto",
|
||||
"LabelDropLyricsHere": "Raahaa sanat tänne, tai klikkaa selataksesi.",
|
||||
"LabelDropLyricsHere": "Pudota sanoitukset tähän, tai selaa painamalla.",
|
||||
"LabelInstalled": "Asennettu",
|
||||
"LabelNoChangelog": "Tälle julkaisuversiolle ei ole saatavilla muutoshistoriaa.",
|
||||
"LabelIsSynced": "On synkronisoitu",
|
||||
@@ -1914,10 +1914,10 @@
|
||||
"Penciller": "Piirtäjä",
|
||||
"Alternate": "Vaihtoehtoinen",
|
||||
"AlternateDVD": "Vaihtoehtoinen DVD",
|
||||
"Inker": "Inker",
|
||||
"Inker": "Värittäjä",
|
||||
"Regional": "Alueellinen",
|
||||
"LabelSelectPreferredTranscodeVideoAudioCodec": "Ensisijainen transkoodattu äänikoodekki videotoistossa",
|
||||
"AllowTonemappingSoftwareHelp": "Sävykartoitus voi muuttaa videon dynaamista aluetta HDR:stä SDR:ään säilyttäen silti kuvan yksityiskohdat ja värin, jotka ovat erittäin tärkeitä alkuperäisen kohtauksen tiedon säilyttämiseksi. Tällä hetkellä se toimii ainoastaan 10bit HDR10 and HLG videoiden kanssa.",
|
||||
"AllowTonemappingSoftwareHelp": "Sävykartoitus voi muuttaa videon dynaamista aluetta HDR:stä SDR:ään säilyttäen silti kuvan yksityiskohdat ja värin, jotka ovat erittäin tärkeitä alkuperäisen kohtauksen tiedon säilyttämiseksi. Tällä hetkellä se toimii ainoastaan 10bit HDR10, -HLG, ja DoVi-videoiden kanssa.",
|
||||
"Editor": "Ohjaus",
|
||||
"Letterer": "Kirjoittaja",
|
||||
"LibraryScanFanoutConcurrencyHelp": "Samanaikaisten suoritettavien kirjastoskannausten maksimimäärä. Mikäli tämä arvo on asetettu 0, määrä valitaan järjestelmän prosessorin säikeiden lukumäärän mukaan. VAROITUS: Tämän arvon asettaminen liian korkeaksi voi aiheuttaa ongelmia verkkotiedostojärjestelmissä. Jos koet ongelmatilanteista, laske tätä numeroa.",
|
||||
@@ -1939,5 +1939,39 @@
|
||||
"MediaSegmentType.Outro": "Lopputekstit",
|
||||
"MediaSegmentType.Preview": "Esikatselu",
|
||||
"MediaSegmentType.Recap": "Kertaus",
|
||||
"AllowFmp4TranscodingContainerHelp": "Salli tämän virittimen fMP4-transkoodaussäiliön tukea HEVC- ja HDR-koodattua sisältöä. Kaikki virittimet eivät ole yhteensopivia tämän tyyppisten säiliöiden kanssa. Poista tämä vaihtoehto käytöstä, jos sinulla on toistoongelmia."
|
||||
"AllowFmp4TranscodingContainerHelp": "Salli tämän virittimen fMP4-transkoodaussäiliön tukea HEVC- ja HDR-koodattua sisältöä. Kaikki virittimet eivät ole yhteensopivia tämän tyyppisten säiliöiden kanssa. Poista tämä vaihtoehto käytöstä, jos sinulla on toistoongelmia.",
|
||||
"LabelAudioTagSettings": "Äänitiedostojen tunnisteiden asetukset",
|
||||
"PreferNonstandardArtistsTagHelp": "Käytä epästandardia \"ARTISTIT\" tagia \"ARTISTI\" tagin sijaan.",
|
||||
"PreferNonstandardArtistsTag": "Suosi \"ARTISTIT\" tagia mikäli saatavilla",
|
||||
"RenderPgsSubtitle": "Kokeellinen PGS tekstitysten renderöinti",
|
||||
"LabelAllowStreamSharing": "Salli striimin jakaminen",
|
||||
"LabelCustomTagDelimiters": "Omien tunnisteiden erotin",
|
||||
"LabelCustomTagDelimitersHelp": "Merkit joita käytetään yksittäisten tunnisteiden erottajina.",
|
||||
"LabelDisableVbrAudioEncoding": "Älä käytä vaihtelevaa bittinopeutta äänen pakkaamiseen",
|
||||
"LabelFallbackMaxStreamingBitrate": "Vara-asetus striimin enimmäisbittinopeudelle (Mbps)",
|
||||
"AllowStreamSharingHelp": "Salli Jellyfinin kopioida sama mpegts striimi virittimeltä usealle käyttäjälle. Tämä on hyödyllistä jos virittimeltä saatava striimien määrä ei riitä, mutta voi myös aiheuttaa toisto-ongelmia.",
|
||||
"AlwaysBurnInSubtitleWhenTranscodingHelp": "Polta tekstitykset kiinteästi kuvaan aina transkoodatessa. Tämä varmistaa tekstitysten oikean ajoituksen, mutta transkoodausnopeus kärsii.",
|
||||
"AlwaysRemuxFlacAudioFilesHelp": "Jos selaimesi ei toista tiedostoa, tai aikaleimat ovat väärin, tämä asetus voi auttaa.",
|
||||
"AlwaysRemuxMp3AudioFilesHelp": "Jos selaimesi laskee aikaleimat väärin, tämän valitseminen voi auttaa.",
|
||||
"Anime": "Anime",
|
||||
"EnableHi10p": "Salli H.264 high 10 profiili",
|
||||
"LabelLyricDownloaders": "Sanoituksien lataajat",
|
||||
"LabelAlwaysRemuxFlacAudioFiles": "Muunna aina FLAC äänitiedostot.",
|
||||
"LabelAlwaysRemuxMp3AudioFiles": "Muunna aina MP3 äänitiedostot.",
|
||||
"LabelAllowFmp4TranscodingContainer": "Salli fMP4 säiliömuoto transkoodauksessa",
|
||||
"LabelMediaSegmentsType": "{0} Osiota",
|
||||
"LabelScreensaverTime": "Näytönsäästäjän aika",
|
||||
"LabelDelimiterWhitelist": "Huomiotta jätettävät erotusmerkit.",
|
||||
"LabelQsvDevice": "QSV Laite",
|
||||
"LabelQsvDeviceHelp": "Valitse käytettävä laite Intel Quick Sync Video:lle usean näytönohjaimen järjestelmissä. Linuxissa esim. \"/dev/dri/renderD128\". Ja Windowsissa laitteen numero alkaen nollasta. Jätä tyhjäksi ellet tiedä mitä teet.",
|
||||
"LabelSaveTrickplayLocally": "Tallenna trickplay kuvat samaan sijaintiin median kanssa.",
|
||||
"LibraryInvalidItemIdError": "Kirjasto on vikatilassa, eikä muutoksia voida tehdä. Kohtasit mahdollisesti bugin: polku tietokannassa ei vastaa oikeaa polkua tiedostolle.",
|
||||
"EnableHi10pHelp": "Ota käyttöön välttääksesi H.264 10-bit videoiden transkoodauksen. Poista käytöstä, mikäli videossa on tyhjiä ruutuja.",
|
||||
"FallbackMaxStreamingBitrateHelp": "Korkeinta striimauksen bittinopeuden asetusta käytetään varalla, mikäli ffprobe ei onnistu selvittämään todellista arvoa. Asetus estää asiakasohjelmia pyytämästä liian korkeita bittinopeuksia, jotka voivat aiheuttaa epävakautta.",
|
||||
"HeaderAudioAdvanced": "Äänen lisäasetukset",
|
||||
"LabelDelimiterWhitelistHelp": "Merkit jotka jätetään huomiotta tunnisteiden erottamisessa toisistaan. Yksi merkki per rivi.",
|
||||
"LabelSaveTrickplayLocallyHelp": "Trickplay kuvien tallentaminen median kanssa samaan sijaintiin helpottaa järjestelmien muutoksia, ja käsiksi pääsyä kuviin.",
|
||||
"LabelScreensaverTimeHelp": "Käyttämättömyyden aika sekunteina, joka vaaditaan näytönsäästäjän aktivoitumiseen.",
|
||||
"LyricDownloadersHelp": "Valitse, ja järjestele prioriteetin mukaan käytettävät sanoituksien lataajat.",
|
||||
"HeaderMediaSegmentActions": "Toimintatapa osioissa"
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user