Compare commits

...

347 Commits

Author SHA1 Message Date
Hasan Abdulaal
691c194152 Translated using Weblate (Arabic)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/ar/
2025-12-02 13:27:39 +00:00
Niels van Velzen
2f8896c375 Merge pull request #15538 from KarkaLT/master
Add subtitle extraction timeout configuration option
2025-12-02 13:50:42 +01:00
Niels van Velzen
6c507b77ae Remove DtoExtensions.AddClientFields (#15638) 2025-11-30 07:22:54 -07:00
renovate[bot]
6ed0ccd37c Update appleboy/ssh-action action to v1.2.4 (#15660)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-30 07:15:08 -07:00
Martín
80e1e42947 Added translation using Weblate (Occitan) 2025-11-28 20:01:20 +00:00
Niels van Velzen
6ace00eb6a Merge pull request #15227 from kevgrig/issue15226
Add milliseconds to default console output format
2025-11-27 16:33:38 +01:00
Niels van Velzen
a35ffbf17e Merge pull request #13977 from sususu98/fix/strm-local-subtitle-url
refactor(StreamInfo): reorganize subtitle URL logic and conditions
2025-11-27 16:33:19 +01:00
Niels van Velzen
8c02c3be93 Merge pull request #14824 from CodyEngel/fix-numeric-titles
Fix TV Series parsing containing only numbers.
2025-11-27 16:32:11 +01:00
Niels van Velzen
45669c9b30 Merge pull request #15437 from allmazz/feat/more_file_metadata_tags
Add support for more embedded metadata tags
2025-11-27 16:31:42 +01:00
Niels van Velzen
19c232809e Merge pull request #14950 from nielsvanvelzen/security-remove-has-password
Deprecate HasPassword property on UserDto
2025-11-27 16:31:05 +01:00
Niels van Velzen
301f65af48 Merge pull request #15559 from nielsvanvelzen/disable-legacy-auth
Disable legacy authorization methods by default
2025-11-27 16:30:45 +01:00
Bond-009
082ba58e51 Merge pull request #15630 from jellyfin/renovate/ci-deps
Update CI dependencies
2025-11-25 18:30:46 +01:00
Bond-009
3b5bdc6bc2 Merge pull request #15246 from JPVenson/feature/AddVersionDisplayStartupUi
Add version to StartupUI
2025-11-25 18:30:27 +01:00
Bond-009
b05e91dba1 Merge pull request #15614 from jellyfin/renovate/polly-monorepo
Update dependency Polly to 8.6.5
2025-11-25 18:26:41 +01:00
renovate[bot]
c7703242e5 Update CI dependencies 2025-11-25 06:39:50 +00:00
Bond-009
21042ad0c2 Merge pull request #15626 from jellyfin/renovate/ci-deps
Update github/codeql-action action to v4.31.5
2025-11-24 19:16:42 +01:00
renovate[bot]
8904551a59 Update github/codeql-action action to v4.31.5 2025-11-24 11:12:00 +00:00
renovate[bot]
cf1ef22367 Update dependency Polly to 8.6.5 2025-11-23 14:03:55 +00:00
rimasx
c08e81c52b Translated using Weblate (Estonian)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/et/
2025-11-23 10:43:48 +00:00
Bond-009
23e66ae1ea Merge pull request #15607 from jellyfin/renovate/z440.atl.core-7.x
Update dependency z440.atl.core to 7.9.0
2025-11-23 10:22:43 +01:00
renovate[bot]
37bbdf3fe7 Update dependency z440.atl.core to 7.9.0 2025-11-22 15:15:12 +00:00
Bond-009
f124223015 Merge pull request #15591 from jellyfin/renovate/actions-checkout-6.x
Update actions/checkout action to v6
2025-11-22 10:22:11 +01:00
Bond-009
9587a9b13c Merge pull request #15566 from jellyfin/renovate/ci-deps
Update github/codeql-action action to v4.31.4
2025-11-22 10:20:48 +01:00
Niels van Velzen
67c67df507 Use async migration 2025-11-20 22:11:55 +01:00
renovate[bot]
569f8cfcfc Update actions/checkout action to v6 2025-11-20 18:58:53 +00:00
Anthony Lavado
aa4ddd139a Add all 10.11 versions to issue template (#15565) 2025-11-18 21:05:43 -05:00
renovate[bot]
8ac97f5471 Update github/codeql-action action to v4.31.4 2025-11-19 01:37:24 +00:00
Bond-009
efabfbc931 Merge pull request #15542 from jellyfin/renovate/ci-deps
Update actions/checkout action to v5.0.1
2025-11-18 22:04:58 +01:00
Bond-009
6b5dc115e8 Merge pull request #15478 from jellyfin/renovate/microsoft
Update Microsoft
2025-11-18 22:01:56 +01:00
Bond-009
2dc0af667e Merge pull request #15477 from jellyfin/renovate/dotnet-monorepo
Update dependency dotnet-ef to v9.0.11
2025-11-18 22:01:49 +01:00
Niels van Velzen
196c243a7d Disable legacy authorization methods by default 2025-11-18 16:17:04 +01:00
Rufis72
55dbff8f30 Translated using Weblate (English (Pirate))
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/en@pirate/
2025-11-18 08:19:02 +00:00
theguymadmax
2af43e0131 Backport pull request #15529 from jellyfin/release-10.11.z
Fix movie titles using folder name when NFO saver is enabled

Original-merge: f8e012582a

Merged-by: crobibero <cody@robibe.ro>

Backported-by: Bond_009 <bond.009@outlook.com>
2025-11-17 14:09:14 -05:00
theguymadmax
faf1cea63e Backport pull request #15514 from jellyfin/release-10.11.z
Add 1 minute tolerance for NFO change detection

Original-merge: 6566188e45

Merged-by: crobibero <cody@robibe.ro>

Backported-by: Bond_009 <bond.009@outlook.com>
2025-11-17 14:09:13 -05:00
theguymadmax
7e25089c08 Backport pull request #15508 from jellyfin/release-10.11.z
Fix playlist DateCreated and DateLastMediaAdded not being set

Original-merge: 078f9584ed

Merged-by: crobibero <cody@robibe.ro>

Backported-by: Bond_009 <bond.009@outlook.com>
2025-11-17 14:09:12 -05:00
Iksas
8fa36a38e2 Backport pull request #15502 from jellyfin/release-10.11.z
Fix font extraction for certain transcoding settings

Original-merge: ee34c75386

Merged-by: crobibero <cody@robibe.ro>

Backported-by: Bond_009 <bond.009@outlook.com>
2025-11-17 14:09:10 -05:00
theguymadmax
5b3f29946b Backport pull request #15501 from jellyfin/release-10.11.z
Fix .ignore handling for directories

Original-merge: e8150428b6

Merged-by: crobibero <cody@robibe.ro>

Backported-by: Bond_009 <bond.009@outlook.com>
2025-11-17 14:09:09 -05:00
theguymadmax
c869b5b884 Backport pull request #15493 from jellyfin/release-10.11.z
Remove InheritedTags and update tag filtering logic

Original-merge: 4b38e35bbb

Merged-by: crobibero <cody@robibe.ro>

Backported-by: Bond_009 <bond.009@outlook.com>
2025-11-17 14:09:08 -05:00
CBPJ
a08b6ac266 Backport pull request #15487 from jellyfin/release-10.11.z
Fix gitignore-style not working properly on windows.

Original-merge: 435bb14bb2

Merged-by: crobibero <cody@robibe.ro>

Backported-by: Bond_009 <bond.009@outlook.com>
2025-11-17 14:09:07 -05:00
theguymadmax
4e68a5a078 Backport pull request #15472 from jellyfin/release-10.11.z
Fix series DateLastMediaAdded not updating when new episodes are added

Original-merge: abfbaca336

Merged-by: crobibero <cody@robibe.ro>

Backported-by: Bond_009 <bond.009@outlook.com>
2025-11-17 14:09:06 -05:00
Bond-009
99c68ddd50 Backport pull request #15468 from jellyfin/release-10.11.z
Check if target exists before trying to follow it

Original-merge: 5878b1ffc5

Merged-by: joshuaboniface <joshua@boniface.me>

Backported-by: Bond_009 <bond.009@outlook.com>
2025-11-17 14:09:05 -05:00
Bond-009
d7f628677e Backport pull request #15466 from jellyfin/release-10.11.z
Don't error out when searching for marker files fails

Original-merge: f4a846aa4d

Merged-by: crobibero <cody@robibe.ro>

Backported-by: Bond_009 <bond.009@outlook.com>
2025-11-17 14:09:03 -05:00
theguymadmax
e51680cf56 Backport pull request #15462 from jellyfin/release-10.11.z
Fix NullReferenceException in GetPathProtocol when path is null

Original-merge: 7c1063177f

Merged-by: joshuaboniface <joshua@boniface.me>

Backported-by: Bond_009 <bond.009@outlook.com>
2025-11-17 14:09:02 -05:00
theguymadmax
2e7d7752e9 Backport pull request #15446 from jellyfin/release-10.11.z
Fix AncestorIds not migrating

Original-merge: 177b6464ca

Merged-by: crobibero <cody@robibe.ro>

Backported-by: Bond_009 <bond.009@outlook.com>
2025-11-17 14:09:01 -05:00
IceStormNG
26ac2ccd74 Backport pull request #15441 from jellyfin/release-10.11.z
Fix System.NullReferenceException when people's role is null (10.11.z)

Original-merge: 5a9a8363f4

Merged-by: Bond-009 <bond.009@outlook.com>

Backported-by: Bond_009 <bond.009@outlook.com>
2025-11-17 14:08:59 -05:00
theguymadmax
de9e653b73 Backport pull request #15435 from jellyfin/release-10.11.z
Fix search terms using diacritics

Original-merge: 63a3e55297

Merged-by: crobibero <cody@robibe.ro>

Backported-by: Bond_009 <bond.009@outlook.com>
2025-11-17 14:08:58 -05:00
theguymadmax
e34e7a1d0b Backport pull request #15423 from jellyfin/release-10.11.z
Invalidate parent folder's cache on deletion/creation

Original-merge: 49efd68fc7

Merged-by: crobibero <cody@robibe.ro>

Backported-by: Bond_009 <bond.009@outlook.com>
2025-11-17 14:08:57 -05:00
nielsvanvelzen
5a30f108fe Backport pull request #15422 from jellyfin/release-10.11.z
Update branding in Swagger page

Original-merge: d140630208

Merged-by: crobibero <cody@robibe.ro>

Backported-by: Bond_009 <bond.009@outlook.com>
2025-11-17 14:08:56 -05:00
JPVenson
74c9629372 Backport pull request #15413 from jellyfin/release-10.11.z
Fixed missing sort argument

Original-merge: 91c3b1617e

Merged-by: crobibero <cody@robibe.ro>

Backported-by: Bond_009 <bond.009@outlook.com>
2025-11-17 14:08:55 -05:00
theguymadmax
6c5f448787 Backport pull request #15404 from jellyfin/release-10.11.z
Improve season folder parsing

Original-merge: 2e5ced5098

Merged-by: crobibero <cody@robibe.ro>

Backported-by: Bond_009 <bond.009@outlook.com>
2025-11-17 14:08:54 -05:00
Bond-009
f848b8f12c Backport pull request #15390 from jellyfin/release-10.11.z
Don't enforce a minimum amount of free space for the tmp and log dirs

Original-merge: 097cb87f6f

Merged-by: crobibero <cody@robibe.ro>

Backported-by: Bond_009 <bond.009@outlook.com>
2025-11-17 14:08:53 -05:00
theguymadmax
bcec5f2e44 Backport pull request #15381 from jellyfin/release-10.11.z
Fix name filters to use only SortName

Original-merge: 7222910b05

Merged-by: crobibero <cody@robibe.ro>

Backported-by: Bond_009 <bond.009@outlook.com>
2025-11-17 14:08:51 -05:00
theguymadmax
7d05c875f3 Backport pull request #15380 from jellyfin/release-10.11.z
Fix item count display for collapsed items

Original-merge: 8f71922734

Merged-by: crobibero <cody@robibe.ro>

Backported-by: Bond_009 <bond.009@outlook.com>
2025-11-17 14:08:50 -05:00
theguymadmax
c805c5e2b1 Backport pull request #15373 from jellyfin/release-10.11.z
Fix collection grouping in mixed libraries

Original-merge: 13c4517a66

Merged-by: crobibero <cody@robibe.ro>

Backported-by: Bond_009 <bond.009@outlook.com>
2025-11-17 14:08:49 -05:00
evanreichard
c2c4c0adbf Backport pull request #15369 from jellyfin/release-10.11.z
feat(sqlite): add timeout config

Original-merge: c2e5081d64

Merged-by: crobibero <cody@robibe.ro>

Backported-by: Bond_009 <bond.009@outlook.com>
2025-11-17 14:08:48 -05:00
revam
5ea3910af9 Backport pull request #15263 from jellyfin/release-10.11.z
Resolve symlinks for static media source infos

Original-merge: 3b2d64995a

Merged-by: crobibero <cody@robibe.ro>

Backported-by: Bond_009 <bond.009@outlook.com>
2025-11-17 14:08:47 -05:00
theguymadmax
06fb300cff Backport pull request #14955 from jellyfin/release-10.11.z
Fix tmdbid not detected in single movie folder

Original-merge: def5956cd1

Merged-by: crobibero <cody@robibe.ro>

Backported-by: Bond_009 <bond.009@outlook.com>
2025-11-17 14:08:45 -05:00
renovate[bot]
626ab7e00a Update actions/checkout action to v5.0.1 2025-11-17 18:40:00 +00:00
Bond-009
1d140645b0 Merge pull request #15528 from jellyfin/renovate/z440.atl.core-7.x
Update dependency z440.atl.core to 7.8.0
2025-11-17 19:38:20 +01:00
Karolis
5182aec13f Add subtitle extraction timeout configuration option 2025-11-17 15:18:29 +02:00
renovate[bot]
52f0c3dd24 Update dependency z440.atl.core to 7.8.0 2025-11-16 17:53:55 +00:00
Bond-009
b8327dbc9f Merge pull request #15480 from jellyfin/renovate/ci-deps
Update CI dependencies
2025-11-16 18:52:54 +01:00
hoanghuy309
d1722936c0 Translated using Weblate (Vietnamese)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/vi/
2025-11-15 06:48:18 +00:00
renovate[bot]
931240a3f5 Update CI dependencies 2025-11-14 01:24:06 +00:00
Grant Alexander
b216a27bfc Translated using Weblate (English (Pirate))
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/en@pirate/
2025-11-12 23:22:20 +00:00
renovate[bot]
8471a67bcd Update Microsoft 2025-11-11 18:42:18 +00:00
renovate[bot]
b8a409195f Update dependency dotnet-ef to v9.0.11 2025-11-11 18:42:10 +00:00
Bond-009
1da67e5e10 Merge pull request #15450 from jellyfin/renovate/fscheck.xunit-3.x
Update dependency FsCheck.Xunit to 3.3.2
2025-11-09 19:39:59 +01:00
Bond-009
ed1ec7ca6b Merge pull request #15448 from jellyfin/renovate/z440.atl.core-7.x
Update dependency z440.atl.core to 7.7.0
2025-11-09 17:57:55 +01:00
renovate[bot]
3d7a68beb1 Update dependency FsCheck.Xunit to 3.3.2 2025-11-09 15:40:14 +00:00
renovate[bot]
32fc57cf17 Update dependency z440.atl.core to 7.7.0 2025-11-09 10:59:00 +00:00
Bond-009
0598c6eaf6 Merge pull request #15438 from jellyfin/renovate/ci-deps
Update appleboy/ssh-action action to v1.2.3
2025-11-08 17:17:52 +01:00
Andrew
0d7b687da0 Update Jellyfin Server version in issue template (#15398) 2025-11-08 08:30:30 -07:00
renovate[bot]
e69754fd3a Update appleboy/ssh-action action to v1.2.3 2025-11-08 04:18:07 +00:00
Kirill Nikiforov
ac81ddd39a add support for more embedded metadata tags 2025-11-08 02:54:53 +04:00
Diogo Coelho
f693c9d39f Translated using Weblate (Portuguese (Portugal))
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/pt_PT/
2025-11-06 11:37:15 +00:00
Bond-009
96d72788a1 Merge pull request #15312 from jellyfin/renovate/ci-deps
Update github/codeql-action action to v4.31.2
2025-11-04 21:07:02 +01:00
Bond-009
0d74a95bb8 Merge pull request #15348 from jellyfin/renovate/serilog.sinks.console-6.x
Update dependency Serilog.Sinks.Console to 6.1.1
2025-11-04 21:05:17 +01:00
evanreichard
a7d039b7c6 Backport pull request #15328 from jellyfin/release-10.11.z
fix: in optimistic locking, key off table is locked

Original-merge: b5f0199a25

Merged-by: crobibero <cody@robibe.ro>

Backported-by: Joshua M. Boniface <joshua@boniface.me>
2025-11-02 21:58:46 -05:00
Shadowghost
87b02b1316 Backport pull request #15326 from jellyfin/release-10.11.z
Skip too large extracted season numbers

Original-merge: e7dbb3afec

Merged-by: crobibero <cody@robibe.ro>

Backported-by: Joshua M. Boniface <joshua@boniface.me>
2025-11-02 21:58:45 -05:00
vinnyspb
871de372ff Backport pull request #15325 from jellyfin/release-10.11.z
Update file size when refreshing metadata

Original-merge: f994dd6211

Merged-by: crobibero <cody@robibe.ro>

Backported-by: Joshua M. Boniface <joshua@boniface.me>
2025-11-02 21:58:44 -05:00
crobibero
c9d93b0745 Backport pull request #15322 from jellyfin/release-10.11.z
Fix legacy migration file checks

Original-merge: da254ee968

Merged-by: crobibero <cody@robibe.ro>

Backported-by: Joshua M. Boniface <joshua@boniface.me>
2025-11-02 21:58:43 -05:00
thornbill
1ccd10863e Backport pull request #15254 from jellyfin/release-10.11.z
Update password reset to always return the same response structure

Original-merge: 4ad3141875

Merged-by: crobibero <cody@robibe.ro>

Backported-by: Joshua M. Boniface <joshua@boniface.me>
2025-11-02 21:58:42 -05:00
nyanmisaka
4258df4485 Backport pull request #15247 from jellyfin/release-10.11.z
Ignore initial delay in audio-only containers

Original-merge: 6bf88c049e

Merged-by: crobibero <cody@robibe.ro>

Backported-by: Joshua M. Boniface <joshua@boniface.me>
2025-11-02 21:58:41 -05:00
renovate[bot]
63f06aad94 Update dependency Serilog.Sinks.Console to 6.1.1 2025-11-02 23:14:23 +00:00
Jacky He
ffe82be7a7 Translated using Weblate (Chinese (Traditional Han script, Hong Kong))
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/zh_Hant_HK/
2025-10-31 23:39:28 +00:00
Jacky He
23929a3e70 Translated using Weblate (Chinese (Traditional Han script, Hong Kong))
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/zh_Hant_HK/
2025-10-30 19:34:52 +00:00
renovate[bot]
83d0dbdbcb Update github/codeql-action action to v4.31.2 2025-10-30 18:35:55 +00:00
Battseren Badral
573ce9ceaa Translated using Weblate (Mongolian)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/mn/
2025-10-29 22:47:08 +00:00
Jacky He
f21fe9f95e Translated using Weblate (Chinese (Traditional Han script, Hong Kong))
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/zh_Hant_HK/
2025-10-29 22:47:08 +00:00
Battseren Badral
f92eca3efb Translated using Weblate (Mongolian)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/mn/
2025-10-29 00:03:00 +00:00
Pascal Wiesmann
7d778d7bef Translated using Weblate (Alemannic)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/gsw/
2025-10-28 09:23:31 +00:00
JJBlue
21f65e2e27 Backport pull request #15220 from jellyfin/release-10.11.z
Skip extracted files in migration if bad timestamp or no access

Original-merge: a305204cfa

Merged-by: crobibero <cody@robibe.ro>

Backported-by: Bond_009 <bond.009@outlook.com>
2025-10-27 15:43:31 -04:00
theguymadmax
28b0657608 Backport pull request #15217 from jellyfin/release-10.11.z
Normalize paths in database queries

Original-merge: 75f472e6a7

Merged-by: crobibero <cody@robibe.ro>

Backported-by: Bond_009 <bond.009@outlook.com>
2025-10-27 15:43:30 -04:00
crobibero
a489942454 Backport pull request #15212 from jellyfin/release-10.11.z
Skip invalid database migration

Original-merge: 2966d27c97

Merged-by: crobibero <cody@robibe.ro>

Backported-by: Bond_009 <bond.009@outlook.com>
2025-10-27 15:43:29 -04:00
Shadowghost
423c2654c0 Backport pull request #15209 from jellyfin/release-10.11.z
Improve symlink handling

Original-merge: e5656af1f2

Merged-by: crobibero <cody@robibe.ro>

Backported-by: Bond_009 <bond.009@outlook.com>
2025-10-27 15:43:27 -04:00
crobibero
4dc826644d Backport pull request #15197 from jellyfin/release-10.11.z
Filter plugins by id instead of name

Original-merge: 5691eee4f1

Merged-by: crobibero <cody@robibe.ro>

Backported-by: Bond_009 <bond.009@outlook.com>
2025-10-27 15:43:26 -04:00
crobibero
0f21222a0c Backport pull request #15196 from jellyfin/release-10.11.z
Skip directory entry when restoring from backup

Original-merge: 0e4031ae52

Merged-by: crobibero <cody@robibe.ro>

Backported-by: Bond_009 <bond.009@outlook.com>
2025-10-27 15:43:25 -04:00
crobibero
570b8b2eb9 Backport pull request #15194 from jellyfin/release-10.11.z
Initialize transcode marker during startup

Original-merge: 81b8b0ca4a

Merged-by: crobibero <cody@robibe.ro>

Backported-by: Bond_009 <bond.009@outlook.com>
2025-10-27 15:43:24 -04:00
Shadowghost
08fd175f5a Backport pull request #15187 from jellyfin/release-10.11.z
Fix pagination and sorting for folders

Original-merge: 7d1824ea27

Merged-by: crobibero <cody@robibe.ro>

Backported-by: Bond_009 <bond.009@outlook.com>
2025-10-27 15:43:23 -04:00
gnattu
511b5d9c53 Backport pull request #15177 from jellyfin/release-10.11.z
Make priority class setting more robust

Original-merge: 70c32a26fa

Merged-by: crobibero <cody@robibe.ro>

Backported-by: Bond_009 <bond.009@outlook.com>
2025-10-27 15:43:22 -04:00
CeruleanRed
6514196e8d Backport pull request #15176 from jellyfin/release-10.11.z
Only save chapters that are within the runtime of the video file

Original-merge: 442af96ed9

Merged-by: crobibero <cody@robibe.ro>

Backported-by: Bond_009 <bond.009@outlook.com>
2025-10-27 15:43:21 -04:00
crobibero
ed6cb30762 Backport pull request #15170 from jellyfin/release-10.11.z
Clean up BackupService

Original-merge: ac3fa3c376

Merged-by: crobibero <cody@robibe.ro>

Backported-by: Bond_009 <bond.009@outlook.com>
2025-10-27 15:43:20 -04:00
crobibero
232c0399e2 Backport pull request #15164 from jellyfin/release-10.11.z
Fix XmlOutputFormatter

Original-merge: 2b94bb54aa

Merged-by: crobibero <cody@robibe.ro>

Backported-by: Bond_009 <bond.009@outlook.com>
2025-10-27 15:43:19 -04:00
nyanmisaka
dbb015441f Backport pull request #15144 from jellyfin/release-10.11.z
Fix videos with cropping metadata are probed as anamorphic

Original-merge: 175ee12bbc

Merged-by: crobibero <cody@robibe.ro>

Backported-by: Bond_009 <bond.009@outlook.com>
2025-10-27 15:43:18 -04:00
theguymadmax
4c1c160990 Backport pull request #15133 from jellyfin/release-10.11.z
Play selected song first with instant mix

Original-merge: 1520a697ad

Merged-by: crobibero <cody@robibe.ro>

Backported-by: Bond_009 <bond.009@outlook.com>
2025-10-27 15:43:17 -04:00
MBR-0001
0931d6e4de Backport pull request #15126 from jellyfin/release-10.11.z
Fix Has(Imdb/Tmdb/Tvdb)Id checks

Original-merge: 14b3085ff1

Merged-by: crobibero <cody@robibe.ro>

Backported-by: Bond_009 <bond.009@outlook.com>
2025-10-27 15:43:15 -04:00
ivanjx
3f2ebc4179 Backport pull request #15113 from jellyfin/release-10.11.z
Add season number fallback for OMDB and TMDB plugins

Original-merge: 618ec4543e

Merged-by: crobibero <cody@robibe.ro>

Backported-by: Bond_009 <bond.009@outlook.com>
2025-10-27 15:43:14 -04:00
Shadowghost
14e8194581 Backport pull request #15112 from jellyfin/release-10.11.z
Skip extracted files in migration if bad timestamp or no access

Original-merge: 7a1c1cd342

Merged-by: crobibero <cody@robibe.ro>

Backported-by: Bond_009 <bond.009@outlook.com>
2025-10-27 15:43:13 -04:00
theguymadmax
3c4dc16003 Backport pull request #15102 from jellyfin/release-10.11.z
Make season paths case-insensitive

Original-merge: 305b0fdca3

Merged-by: crobibero <cody@robibe.ro>

Backported-by: Bond_009 <bond.009@outlook.com>
2025-10-27 15:43:12 -04:00
Bond-009
54d28d9842 Backport pull request #15098 from jellyfin/release-10.11.z
Lower required tmp dir size to 512MiB

Original-merge: 0a6e8146be

Merged-by: crobibero <cody@robibe.ro>

Backported-by: Bond_009 <bond.009@outlook.com>
2025-10-27 15:43:11 -04:00
theguymadmax
adfa520057 Backport pull request #15087 from jellyfin/release-10.11.z
Optimize WhereReferencedItemMultipleTypes filtering

Original-merge: a5bc4524d8

Merged-by: crobibero <cody@robibe.ro>

Backported-by: Bond_009 <bond.009@outlook.com>
2025-10-27 15:43:10 -04:00
theguymadmax
5deb69b23f Backport pull request #15083 from jellyfin/release-10.11.z
Fix LiveTV images not saving to database

Original-merge: d738386fe2

Merged-by: crobibero <cody@robibe.ro>

Backported-by: Bond_009 <bond.009@outlook.com>
2025-10-27 15:43:09 -04:00
nyanmisaka
348b2992d7 Backport pull request #15072 from jellyfin/release-10.11.z
Reject stream copy of HDR10+ video if the client does not support HDR10

Original-merge: a725220c21

Merged-by: crobibero <cody@robibe.ro>

Backported-by: Bond_009 <bond.009@outlook.com>
2025-10-27 15:43:08 -04:00
gnattu
9f8fb6d588 Backport pull request #15055 from jellyfin/release-10.11.z
Log the message more clear when network manager is not ready

Original-merge: a245605152

Merged-by: crobibero <cody@robibe.ro>

Backported-by: Bond_009 <bond.009@outlook.com>
2025-10-27 15:43:07 -04:00
Shadowghost
cee16d47cb Backport pull request #15054 from jellyfin/release-10.11.z
Speed-up trickplay migration

Original-merge: ca830d5be7

Merged-by: crobibero <cody@robibe.ro>

Backported-by: Bond_009 <bond.009@outlook.com>
2025-10-27 15:43:06 -04:00
Shadowghost
9e53f46ad2 Backport pull request #15032 from jellyfin/release-10.11.z
Skip invalid keyframe cache data

Original-merge: f4a53209f4

Merged-by: crobibero <cody@robibe.ro>

Backported-by: Bond_009 <bond.009@outlook.com>
2025-10-27 15:43:04 -04:00
Joshua M. Boniface
53dfcae1a6 Merge pull request #15236 from joshuaboniface/codeowners
Update CODEOWNERS to capture bump_version
2025-10-27 09:10:47 -04:00
JPVenson
81f1cc78b2 Add version to StartupUI 2025-10-27 13:01:52 +00:00
kreaxv
efd659412f Translated using Weblate (Mongolian)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/mn/
2025-10-27 09:41:00 +00:00
Joshua M. Boniface
c31ea251c4 Improve handling of .github dir 2025-10-26 22:17:33 -04:00
Joshua M. Boniface
285e7c6c4f Update CODEOWNERS to capture bump_version 2025-10-26 22:07:46 -04:00
Joshua M. Boniface
c274336563 Bump version to 10.12.0 (for real this time) 2025-10-26 21:52:03 -04:00
Joshua M. Boniface
d5fd5dfe6a Fix bump_version to handle spaced filename 2025-10-26 21:51:41 -04:00
Kevin G
42ddcfa565 Add milliseconds to default console output format
Signed-off-by: Kevin G <kevin@myplaceonline.com>
2025-10-26 10:29:29 -05:00
Bond-009
6fa69f9fe5 Merge pull request #15206 from jellyfin/renovate/ci-deps
Update danielpalme/ReportGenerator-GitHub-Action action to v5.4.18
2025-10-26 14:50:42 +01:00
Bond-009
0b876365a1 Merge pull request #15205 from jellyfin/renovate/z440.atl.core-7.x
Update dependency z440.atl.core to 7.6.0
2025-10-26 14:39:09 +01:00
Battseren Badral
cdc8325c7b Translated using Weblate (Mongolian)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/mn/
2025-10-25 21:55:13 +00:00
renovate[bot]
a6a8e29916 Update danielpalme/ReportGenerator-GitHub-Action action to v5.4.18 2025-10-25 15:32:59 +00:00
renovate[bot]
6fd3847298 Update dependency z440.atl.core to 7.6.0 2025-10-25 15:12:02 +00:00
Bond-009
3ff516a430 Merge pull request #15191 from jellyfin/renovate/ci-deps
Update github/codeql-action action to v4.31.0
2025-10-25 11:23:34 +02:00
Bond-009
d8591840f3 Merge pull request #15192 from jellyfin/renovate/major-github-artifact-actions
Update GitHub Artifact Actions (major)
2025-10-25 11:22:40 +02:00
HanHwanHo
c5affbbf71 Translated using Weblate (Korean)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/ko/
2025-10-25 07:46:36 +00:00
renovate[bot]
788f090f27 Update GitHub Artifact Actions 2025-10-24 23:59:16 +00:00
renovate[bot]
0e3b6652b3 Update github/codeql-action action to v4.31.0 2025-10-24 23:59:06 +00:00
desibooklover
d167d59c23 Translated using Weblate (Punjabi)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/pa/
2025-10-23 03:50:04 +00:00
desibooklover
f58b4860f7 Translated using Weblate (Hindi)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/hi/
2025-10-23 03:50:04 +00:00
Grant Alexander
96b7fc0ac0 Translated using Weblate (Spanish (Mexico))
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/es_MX/
2025-10-21 15:20:51 +00:00
oddife
c8ad861590 Translated using Weblate (Marathi)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/mr/
2025-10-20 21:27:58 +00:00
Jellyfin Release Bot
1a1a24cfff Bump version to 10.12.0 2025-10-19 20:45:13 -04:00
Bond-009
ace30afcf8 Merge pull request #15016 from jellyfin/renovate/ci-deps
Update github/codeql-action action to v4.30.9
2025-10-19 11:14:52 +02:00
Niels van Velzen
d43db230fa Add back UpdateUserPassword_Empty_RemoveSetPassword test 2025-10-19 09:45:55 +02:00
rimasx
fc056b6273 Translated using Weblate (Estonian)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/et/
2025-10-19 05:33:11 +00:00
rimasx
ac5efb4775 Translated using Weblate (Estonian)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/et/
2025-10-18 11:54:27 +00:00
renovate[bot]
fefd676adc Update github/codeql-action action to v4.30.9 2025-10-17 15:56:06 +00:00
Bond-009
59c17a663c Merge pull request #15006 from jellyfin/renovate/dotnet-monorepo
Update dependency dotnet-ef to v9.0.10
2025-10-15 17:39:47 +02:00
Bond-009
641551e164 Merge pull request #15007 from jellyfin/renovate/microsoft
Update Microsoft to 9.0.10
2025-10-15 17:39:32 +02:00
renovate[bot]
bd543d7ac3 Update Microsoft to 9.0.10 2025-10-15 00:34:53 +00:00
renovate[bot]
545e412259 Update dependency dotnet-ef to v9.0.10 2025-10-15 00:34:44 +00:00
Cody Robibero
7dff92bb82 Use TryAdd instead of Add (#14997) 2025-10-13 22:18:37 +02:00
Cody Robibero
b36aab9399 Validate encoder path (#14996) 2025-10-13 14:16:05 -06:00
Erik W
2c7d2d4719 Handle es-419 in TMDb (#14946) 2025-10-13 13:47:16 -06:00
Tim Eisele
5c519270b8 Remove chapters on file change (#14984) 2025-10-13 12:32:41 -06:00
theguymadmax
55047b1183 Fix exception when saving user data to NFO files (#14993) 2025-10-13 10:09:40 -06:00
theguymadmax
794e1361d7 Fix contributing artist query (#14991) 2025-10-13 09:09:09 -06:00
kreaxv
27c9c9c0ed Translated using Weblate (Mongolian)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/mn/
2025-10-13 12:42:46 +00:00
rimasx
68636b2390 Translated using Weblate (Estonian)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/et/
2025-10-12 18:15:54 +00:00
Joshua M. Boniface
2e6430c4f4 Merge pull request #14965 from KGT1/mapTmdbcol
add xmbc nfo uniqueid type norminalisation
2025-10-11 17:21:32 -04:00
Joshua M. Boniface
c88d792963 Merge pull request #14960 from karm235/13697-fix-lufs-detection
Fix LUFS detection deadlock per issue #13697
2025-10-11 17:20:52 -04:00
Joshua M. Boniface
73dbc9e89f Merge pull request #14978 from theguymadmax/fix-playlistfolder
Prevent PlaylistsFolder deletion during library removal
2025-10-11 17:20:40 -04:00
Joshua M. Boniface
cf3edd9875 Merge pull request #14971 from theguymadmax/skip-artist-album-persontype
Skip creating Person entities for Artist and AlbumArtist types
2025-10-11 17:20:31 -04:00
Joshua M. Boniface
ef0131ad69 Merge pull request #14976 from JPVenson/bugfix/ItemCounterSorting
apply sort on ItemValue query
2025-10-11 17:20:23 -04:00
rimasx
056c318f04 Translated using Weblate (Estonian)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/et/
2025-10-11 11:46:41 +00:00
theguymadmax
49c3443b0c Prevent PlaylistsFolder deletion during library removal 2025-10-10 18:34:37 -04:00
Bond-009
e415718fe7 Merge pull request #14975 from jellyfin/renovate/ci-deps
Update github/codeql-action action to v4.30.8
2025-10-10 22:09:46 +02:00
JPVenson
8abcfb2a80 Fix ordering query 2025-10-10 20:08:59 +00:00
Bond-009
9aadf97958 Merge pull request #14945 from jellyfin/renovate/asynckeyedlock-7.x
Update dependency AsyncKeyedLock to 7.1.7
2025-10-10 18:10:38 +02:00
renovate[bot]
9e57121171 Update github/codeql-action action to v4.30.8 2025-10-10 16:02:22 +00:00
Bond-009
b471811920 Merge pull request #14959 from jellyfin/renovate/github-codeql-action-4.x
Update github/codeql-action action to v4
2025-10-10 18:01:21 +02:00
renovate[bot]
3cb99add76 Update github/codeql-action action to v4 2025-10-10 15:51:16 +00:00
Bond-009
001f1c4377 Merge pull request #14954 from jellyfin/renovate/ci-deps
Update CI dependencies
2025-10-10 17:50:15 +02:00
Bond-009
9ef3706b44 Merge pull request #14969 from theguymadmax/fix-artist-external-id
Fix artist external Url
2025-10-10 17:49:39 +02:00
rimasx
864d6d0b8f Translated using Weblate (Estonian)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/et/
2025-10-10 10:58:43 +00:00
faquino
a565e4896e Translated using Weblate (Galician)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/gl/
2025-10-10 10:58:43 +00:00
JPVenson
ceef9143ad cleanup 2025-10-10 09:18:05 +00:00
JPVenson
a7a92509c7 fixes #14952 apply sort on ItemValue query 2025-10-10 09:10:21 +00:00
taham
e876e784da Translated using Weblate (Urdu)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/ur/
2025-10-10 05:25:11 +00:00
taham
9b7d5edc86 Translated using Weblate (Urdu (Pakistan))
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/ur_PK/
2025-10-10 05:25:10 +00:00
JPVenson
f01cddf273 Add migration attribute 2025-10-09 19:45:43 +00:00
JPVenson
0d4bd0495b Add migration to remove artist and album artists from database 2025-10-09 19:44:07 +00:00
theguymadmax
6f9c4dea6e Skip creating Person entities for Artist and AlbumArtist types 2025-10-09 11:00:36 -05:00
rimasx
8c51920911 Translated using Weblate (Estonian)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/et/
2025-10-09 12:39:38 +00:00
faquino
8f2fd65810 Translated using Weblate (Galician)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/gl/
2025-10-09 12:39:38 +00:00
rimasx
953659980f Translated using Weblate (Estonian)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/et/
2025-10-09 10:47:27 +00:00
renovate[bot]
8ab1fecb70 Update CI dependencies 2025-10-09 10:20:29 +00:00
theguymadmax
f5d42ee180 Fix artist external Url 2025-10-09 01:14:49 -05:00
KGT1
e28d547006 add test for new uniqueid nfo key normalisation 2025-10-08 15:32:30 +00:00
KGT1
b3b9f74014 also apply provider normalisation on uniqueid type tag 2025-10-08 15:23:50 +00:00
theguymadmax
07d31c6ba5 Improve performance on people query (#14963) 2025-10-08 09:23:20 -06:00
KGT1
a9198e865e map tmdbcol nfo property to TmdbCollection 2025-10-08 14:33:50 +00:00
theguymadmax
79ff0b0b00 Fix collections folder duplication (#14925) 2025-10-08 08:32:00 -06:00
theguymadmax
2b45a984dd Clean up missing image references (#14962) 2025-10-08 08:23:12 -06:00
Milo Ivir
739642b330 Translated using Weblate (Croatian)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/hr/
2025-10-07 19:45:38 +00:00
karm235
6097045d71 cleanup 2025-10-07 12:20:08 -05:00
karm235
51e20a14c2 Fix LUFS detection deadlock on albums with verbose output 2025-10-07 12:11:02 -05:00
rimasx
eb0d05cf1e Translated using Weblate (Estonian)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/et/
2025-10-06 08:38:24 +00:00
Bond-009
d3d5915f31 Truncate password reset file on open for writing (#14948) 2025-10-05 11:24:12 -06:00
Niels van Velzen
0fb6d930e1 Deprecate HasPassword property on UserDto 2025-10-05 11:10:36 +02:00
Bond-009
288640a5d0 Merge pull request #14940 from jellyfin/renovate/ci-deps
Update actions/stale action to v10.1.0
2025-10-04 21:15:57 +02:00
Cody Robibero
ff0a1b999f Handle xx as TMDb no language for backdrops (#14941) 2025-10-04 21:04:35 +02:00
renovate[bot]
da0fe7455e Update dependency AsyncKeyedLock to 7.1.7 2025-10-04 14:59:22 +00:00
Thomas Jones
bf69f9d8a8 Validate wizard-created libraries immediately instead of only doing it after a library refresh was triggered (#14942)
Co-authored-by: Derpipose <90276123+Derpipose@users.noreply.github.com>
2025-10-04 08:58:51 -06:00
Nyanmisaka
badf22fcc2 Limit decoder thread count on AMD AMF to save VRAM (#14943) 2025-10-04 08:04:25 -06:00
renovate[bot]
b59e9f90f0 Update actions/stale action to v10.1.0 2025-10-03 22:04:26 +00:00
renovate[bot]
056b92dbd5 Update dependency Microsoft.NET.Test.Sdk to v18 (#14930)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-02 17:34:06 -06:00
renovate[bot]
ba80f5e416 Update peter-evans/create-or-update-comment action to v5 (#14933)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-02 17:33:54 -06:00
lostb1t
97ec4c1da2 fix: get total count after grouping (#14931) 2025-10-02 17:33:50 -06:00
renovate[bot]
894ba1a410 Update github/codeql-action action to v3.30.6 (#14932)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-02 17:33:37 -06:00
gnattu
0a0aaefad5 Fix mka-style tagging key (#14936) 2025-10-02 17:33:31 -06:00
JPVenson
c8b97bf533 Readd wildcard search (#14934) 2025-10-02 17:33:01 -06:00
Bond-009
cfa4e357ea Merge pull request #14923 from jellyfin/renovate/peter-evans-find-comment-4.x
Update peter-evans/find-comment action to v4
2025-10-02 20:50:59 +02:00
theguymadmax
0f42aa892e Fix BoxSet sorting (#14919)
Co-authored-by: Cody Robibero <cody@robibe.ro>
2025-10-01 21:10:31 -06:00
JPVenson
cce6bf27e0 Add check for processing recursive data structures (#14897) 2025-10-01 17:26:56 -06:00
theguymadmax
d6cebf1e67 Add tag filtering and random sorting to GetSimilarItems (#14918) 2025-10-01 17:26:48 -06:00
theguymadmax
c053a6cd78 Fix parental ratings logic (#14909) 2025-10-01 17:26:30 -06:00
renovate[bot]
d8c62420bf Update peter-evans/find-comment action to v4 2025-10-01 22:51:24 +00:00
Joshua M. Boniface
d483c3efe6 Merge pull request #14887 from JPVenson/bugfix/fixMigrationReferences
Add explicit reference check to migration
2025-09-28 12:44:09 -04:00
Joshua M. Boniface
275c1a3cc1 Merge pull request #14883 from crobibero/code-analysis
Only include custom code analysis for debug builds
2025-09-28 12:34:21 -04:00
Joshua M. Boniface
4942b2c15f Merge pull request #14890 from nielsvanvelzen/destructive-migration
Fix AddProperParentChildRelationBaseItemWithCascade migration deleting all items
2025-09-28 12:26:40 -04:00
Niels van Velzen
3fc71293b4 Fix AddProperParentChildRelationBaseItemWithCascade migration deleting all items 2025-09-28 13:14:10 +02:00
JPVenson
8ea9bece03 Add explicit reference check to migration 2025-09-28 08:46:31 +00:00
Nicolas N
baa7f5f0b0 Translated using Weblate (Haitian)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/ht/
2025-09-28 06:47:40 +00:00
Cody Robibero
b9c96f3d2c Revert "Add Jellyfin.CodeAnalysis project to abi diff (#14875)"
This reverts commit 526ec83305.
2025-09-27 16:41:01 -06:00
Cody Robibero
08f9b932ac Only include CodeAnalysis in debug mode 2025-09-27 16:39:40 -06:00
daswesen123
e6cd73df03 Translated using Weblate (English (Pirate))
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/en@pirate/
2025-09-27 22:14:14 +00:00
Corentin Malbet
71ebb1f456 Fixing the UFID field value giving a warning and not being correctly processed (#14851) 2025-09-26 14:24:59 -06:00
Tim Eisele
9c298c52f5 Expose ExtractAllExtractableSubtitles (#14876) 2025-09-26 13:45:01 -06:00
Niels van Velzen
3e8db40901 Merge pull request #14874 from jellyfin/renovate/polly-monorepo
Update dependency Polly to 8.6.4
2025-09-26 21:39:47 +02:00
Niels van Velzen
f9ead9615c Merge pull request #14855 from jellyfin/renovate/ci-deps
Update CI dependencies
2025-09-26 21:39:16 +02:00
Niels van Velzen
93af2d6f67 Merge pull request #14873 from theguymadmax/use-listorder
Restore NFO/import ordering by using ListOrder instead of SortOrder
2025-09-26 21:38:29 +02:00
renovate[bot]
027c91949d Update CI dependencies 2025-09-26 17:50:59 +00:00
JPVenson
526ec83305 Add Jellyfin.CodeAnalysis project to abi diff (#14875) 2025-09-26 11:49:51 -06:00
renovate[bot]
dfcacce1b0 Update dependency Polly to 8.6.4 2025-09-26 15:13:09 +00:00
theguymadmax
2a54669a8a Restore NFO/import ordering by using ListOrder instead of SortOrder 2025-09-26 10:49:38 -04:00
JPVenson
54d48fa446 Fix people deduplication lookup (#14864) 2025-09-25 19:27:38 -06:00
JPVenson
1736a566cc Fixes FK on unconnected base items (#14863) 2025-09-25 19:27:17 -06:00
gnattu
04ab362e59 Revert "Update skiasharp monorepo (#14849)" (#14862) 2025-09-25 16:05:04 +02:00
JPVenson
e282b05b8f fixes #14859 Add Check for ItemValues (#14860) 2025-09-25 08:02:20 -06:00
JPVenson
2aa39226c6 Apply filter server side (#14856) 2025-09-24 18:15:10 -06:00
theguymadmax
60fbd39bb9 Fix people sort order (#14852) 2025-09-24 17:37:07 -06:00
JPVenson
740b9924a0 Include ListOrder on Import (#14854) 2025-09-24 15:22:05 -06:00
JPVenson
5a6d9180fe Add People Dedup and multiple progress fixes (#14848) 2025-09-24 15:20:30 -06:00
theguymadmax
897975fc57 Fix collections one-off (#14814) 2025-09-24 15:19:15 -06:00
Bond-009
7dab62616f Merge pull request #14827 from tjwalkr3/warnings-3
Fix CA1051 warning, Change public field to auto-property
2025-09-24 19:32:24 +02:00
renovate[bot]
f1bd9a40d5 Update skiasharp monorepo (#14849)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-24 08:28:46 +02:00
renovate[bot]
469e6e1bc8 Update danielpalme/ReportGenerator-GitHub-Action action to v5.4.15 (#14830)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-23 19:52:31 -06:00
JPVenson
38f5f8008a Fix ordering where exists (#14843) 2025-09-23 19:51:44 -06:00
Cody Engel
2508e8349b update summary docs
Signed-off-by: Cody Engel <cengel815@gmail.com>
2025-09-23 08:22:00 -06:00
JPVenson
7bb68d8610 Fix Image loading (#14842) 2025-09-23 07:02:30 -06:00
Cody Robibero
27047c35a4 Add schema to 503 headers (#14840) 2025-09-23 07:00:34 -06:00
Looooke
42003ca9d2 Translated using Weblate (Alemannic)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/gsw/
2025-09-22 22:16:10 +00:00
JPVenson
98f5e21bb8 Fix groupings not applied (#14826) 2025-09-22 15:31:21 -06:00
Mikal S.
162985bb23 fix: add back missing behavior for HasAnyProviderId (#14831) 2025-09-22 09:56:41 -06:00
Jan Zachar
0d2c551cce Translated using Weblate (Belarusian)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/be/
2025-09-22 12:04:53 +00:00
Janniry Belen
717e7cbd77 Translated using Weblate (Spanish (Dominican Republic))
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/es_DO/
2025-09-22 04:08:11 +00:00
Thomas Jones
58f9bdcf5c Added ourselves to CONTRIBUTORS.md
Co-authored-by: Derpipose <90276123+Derpipose@users.noreply.github.com>
2025-09-20 23:58:49 -06:00
Thomas Jones
2a499aaa95 Fix CA1051 warnings in EncodingJobInfo.cs
Convert public fields to auto-properties and fix member ordering

Co-authored-by: Derpipose <90276123+Derpipose@users.noreply.github.com>
2025-09-20 23:31:58 -06:00
Cody Engel
bd9a44ce7d remove explicit ‘-‘ support in series name 2025-09-20 18:00:44 -06:00
Cody Engel
da31d0c6a6 support series that are numeric only
updates SeriesResolver to handle series names that only contain numbers such as 1923.
2025-09-20 14:04:00 -06:00
evan314159
4246825239 Attach before updating/deleting to avoid DbUpdateConcurrencyException (#14746) 2025-09-20 07:23:04 -06:00
renovate[bot]
68810c690b Update dependency z440.atl.core to 7.5.0 (#14793) 2025-09-20 07:22:10 -06:00
Tim Eisele
b73ea1b99d Skip removed images (#14823) 2025-09-20 07:20:21 -06:00
JPVenson
59f77c24c9 Revert limit hack (#14820) 2025-09-20 07:19:26 -06:00
JPVenson
0949212993 Make migration handle parent cleanup (#14817)
* Make migration handle parent cleanup

* Remove speed improvement

* Update MigrateLibraryDb.cs
2025-09-19 13:17:31 -06:00
renovate[bot]
248aac9a3a Update dependency Svg.Skia to 3.2.1 (#14815)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-19 11:48:16 -06:00
JPVenson
a1b85a63e7 Fix root folder not being saved to Db if nessesary (#14819)
* Fix root folder not being saved to Db if nessesary

* Always update folder to Db
2025-09-19 11:47:41 -06:00
Kendall Garner
091cb1c34a Fix playlist move from smaller to larger index (#14794) 2025-09-18 08:37:31 -06:00
JPVenson
eaf33f01e1 #14751 Only migrate providerids that match assumption (#14810) 2025-09-17 18:33:23 -06:00
renovate[bot]
db2dbaa62b Update Microsoft to 4.14.0 (#14808)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-16 13:08:28 -06:00
renovate[bot]
1a7df6daf7 Update dependency Newtonsoft.Json to 13.0.4 (#14807)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-16 13:08:24 -06:00
JPVenson
a0b3e2b071 Optimize internal querying of UserData, other fixes (#14795) 2025-09-16 13:08:04 -06:00
evan314159
2618a5fba2 Fix sync disposal of async-created IAsyncDisposable objects (#14755) 2025-09-16 11:14:52 +02:00
Bond-009
2ee887a502 Merge pull request #14800 from jellyfin/renovate/tmdblib-2.x
Update dependency TMDbLib to 2.3.0
2025-09-16 11:13:01 +02:00
Bond-009
a17e157d44 Merge pull request #14799 from Shadowghost/add-ec3
Add ec3 to audio file extensions
2025-09-16 11:12:41 +02:00
renovate[bot]
6b6745b7fe Update dependency TMDbLib to 2.3.0 2025-09-15 02:51:21 +00:00
Shadowghost
594f9e4f6b Add ec3 to audio file extensions 2025-09-14 23:23:04 +02:00
Bond-009
4cda5f5ff2 Merge pull request #14790 from jellyfin/renovate/ci-deps
Update danielpalme/ReportGenerator-GitHub-Action action to v5.4.13
2025-09-14 21:39:20 +02:00
JPVenson
24410d8a2e Reenable common PRAGMA setters (#14791) 2025-09-14 11:24:35 -06:00
Cody Robibero
4d36bd635d Revert IsPlayed optimization, pass UserItemData to IsPlayed when available (#14786) 2025-09-14 11:18:21 -06:00
renovate[bot]
ef65534071 Update danielpalme/ReportGenerator-GitHub-Action action to v5.4.13 2025-09-12 23:56:20 +00:00
KGT1
7c6cedd90a Allow non-admin users to subscribe to their own Sessions (#13767) 2025-09-12 14:15:00 -06:00
theguymadmax
96590eea85 Fix duplicate media entries (#14404) 2025-09-12 13:58:42 -06:00
Bond-009
6796b3435d Avoid constant arrays as arguments (#14784) 2025-09-12 13:58:28 -06:00
Bond-009
8776a447d1 Various cleanups (#14785) 2025-09-12 13:58:23 -06:00
JPVenson
c02a24e32a Fix several Stackoverflows (#14783) 2025-09-12 13:58:16 -06:00
Bond-009
deee04ae38 Add fast path to check for empty ignore files (#14782) 2025-09-12 13:58:02 -06:00
Tim Eisele
580db0c1d2 Never replace BoxSet LinkedChildren on update (#14723) 2025-09-12 13:57:55 -06:00
Alex Collado
8fcc2496d9 Change Spanish order in iso6392.txt to favor Castillian (#14777) 2025-09-12 13:57:48 -06:00
JPVenson
f0e60a7ff3 Improve optimistic locking behavior (#14779) 2025-09-12 13:57:40 -06:00
JPVenson
a99e67544a Reenable pooling (#14778) 2025-09-12 13:57:33 -06:00
nenadsuperzmaj
bca6400bc3 Translated using Weblate (Serbian)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/sr/
2025-09-12 18:09:53 +00:00
theguymadmax
986a509955 Add 1-second tolerance to resume playback completion check (#14774) 2025-09-11 15:24:23 -06:00
theguymadmax
da19f02f7b Sort trailers before teasers (#14715) 2025-09-11 15:23:41 -06:00
Bond-009
3fad5eb069 Make private Emby.Naming.Video.StackResolver.StackMetadata sealed to silence compiler warning (#14764) 2025-09-11 10:18:47 +02:00
renovate[bot]
9923a51aed Update dependency dotnet-ef to v9.0.9 (#14768)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-11 10:18:20 +02:00
renovate[bot]
585e9a2fe2 Update Microsoft to 9.0.9 (#14769)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-11 10:18:06 +02:00
renovate[bot]
8e81737dba Update github/codeql-action action to v3.30.3 (#14767)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-11 10:09:59 +02:00
Tim Eisele
e4e578b37a Don't use ffprobe frame options on audio probe (#14773) 2025-09-10 20:32:14 -06:00
Looooke
387bc0c8eb Translated using Weblate (Alemannic)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/gsw/
2025-09-09 23:20:42 +00:00
Varoon Pazhyanur
cbb569a277 Make private Emby.Naming.Video.StackResolver.StackMetadata sealed to silence compiler warning 2025-09-08 21:21:43 -04:00
Adrián HM
1fa63b797b Translated using Weblate (Spanish (Mexico))
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/es_MX/
2025-09-08 22:32:30 +00:00
Magnus Antonsen
aa3a7c88a4 Translated using Weblate (Norwegian Bokmål)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/nb_NO/
2025-09-08 15:02:04 +00:00
evan314159
0a2cf69a55 Additional debug logging for SQLite connections (#14753) 2025-09-07 14:40:27 -06:00
theguymadmax
0845b0c258 Skip non-media folders in movie resolver (#14724)
* Skip non-media folders in movie resolver

* Ignorepatterns first
2025-09-07 13:02:52 +02:00
theguymadmax
e043f93a72 Preserve 3D format on metadata refresh (#14742) 2025-09-06 11:38:00 -06:00
Arty
6ac2d707cb Translated using Weblate (Russian)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/ru/
2025-09-06 04:51:32 +00:00
JPVenson
20f7ddbf8f Refactor Display preference manager (#14056) 2025-09-05 14:39:15 -06:00
renovate[bot]
4849486fa0 Update github/codeql-action action to v3.30.1 (#14748)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-05 17:13:46 +02:00
renovate[bot]
4ccd3da77a Update actions/stale action to v10 (#14741)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-05 11:10:59 +02:00
renovate[bot]
bc28dc11c0 Update actions/setup-python action to v6 (#14740)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-05 11:10:36 +02:00
theguymadmax
d9eaeed61d Fix latest items grouping by collection type (#14736)
* Fix latest items grouping by collection type

* Update Emby.Server.Implementations/Library/UserViewManager.cs

Co-authored-by: Bond-009 <bond.009@outlook.com>

---------

Co-authored-by: Bond-009 <bond.009@outlook.com>
2025-09-05 11:05:37 +02:00
Bond-009
c7320dc189 Add more robust error handling for AudioNormalizationTask (#14728) 2025-09-03 21:12:24 -06:00
Shane Powell
71048917dd AudioNormalizationTask db progress saving (#14550) 2025-09-03 21:11:58 -06:00
renovate[bot]
11eab1b663 Update actions/setup-dotnet action to v5 (#14738)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-03 21:10:21 -06:00
Md Ashikur Rahman
a17a0495d8 Translated using Weblate (Bengali)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/bn/
2025-09-03 20:51:22 +00:00
renovate[bot]
b3e57a5f7d Update github/codeql-action action to v3.30.0 (#14730)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-02 18:06:23 -06:00
renovate[bot]
65827cce6f Update dependency NEbml to 1.1.0.5 (#14732)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-02 10:05:05 +02:00
Milo Ivir
b5df0d2a34 Translated using Weblate (Croatian)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/hr/
2025-09-02 06:43:07 +00:00
ShalokShalom
339a31f0a5 Update .Net Core to .Net (#14718) 2025-09-01 11:45:24 -06:00
evan314159
a0d4ae1974 Correct Album Artists merge logic (#14655)
* Correct Album Artists merge logic and Artist equality checks

Correct Album Artists merge logic in MetadataService that causes empty
metadata sources to overwrite populated Album Artists arrays. This impacted
People-to-BaseItem relationships and caused orphaned records in Peoples.

Correct equality checks to be case-sensitive so Jelly metadata exactly
matches file metadata.

* use StringComparer.Ordinal

---------

Co-authored-by: Evan <evan@MacBook-Pro.local>
2025-09-01 13:22:55 +02:00
renovate[bot]
d65b18a7f3 Update dependency Polly to 8.6.3 (#14690)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-27 17:40:51 -06:00
renovate[bot]
cc93b44947 Update dependency Svg.Skia to 3.0.6 (#14691)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-27 17:40:36 -06:00
evan314159
e753adac2c fix ProbeProvider.HasChanged: if file date changed (#14674) 2025-08-27 17:34:51 -06:00
Marc Brooks
0b465842c8 Normalizer cleanup (#14711) 2025-08-27 17:34:00 -06:00
Cody Robibero
da3f3b09d9 Use existing userData (#14703) 2025-08-26 16:09:17 -06:00
Bond-009
7a9beb3745 Merge pull request #14701 from jellyfin/renovate/fscheck.xunit-3.x
Update dependency FsCheck.Xunit to 3.3.1
2025-08-24 21:26:46 +02:00
renovate[bot]
c7ee07b14a Update dependency FsCheck.Xunit to 3.3.1 2025-08-24 18:51:40 +00:00
Lucas
d8dfbc26f6 Translated using Weblate (Spanish (Argentina))
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/es_AR/
2025-08-23 16:48:55 +00:00
Shiva Prasad
88e0d35ed7 Translated using Weblate (Telugu)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/te/
2025-08-23 09:57:19 +00:00
evan314159
1eadb07a12 Fix GetSimilarItems to exclude the searched for item Id (#14686) 2025-08-22 19:00:29 -06:00
Gjelbrim Haskaj
26d9633fed Translated using Weblate (Albanian)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/sq/
2025-08-23 00:15:35 +00:00
spurdl
19aadd934b Translated using Weblate (Finnish)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/fi/
2025-08-22 20:57:15 +00:00
Bond-009
ce28374d40 Run background ffmpeg tasks as ProcessPriorityClass.BelowNormal (#14651)
Follow TrickPlay example of running other background ffmpeg tasks as ProcessPriorityClass.BelowNormal:

- Keyframe extraction
- Media info probing during library scans
- Audio normalization
- Image extraction

Co-authored-by: Evan <evan@MacBook-Pro.local>
2025-08-22 10:08:29 +02:00
evan314159
7aa1c46447 Merge pull request #14653 from evan314159/coremigration
Delay initialization of singleton services during migration CoreInitialisation stage
2025-08-22 10:06:39 +02:00
Bond-009
ffb7753f8d Merge pull request #14684 from jellyfin/renovate/ci-deps
Update github/codeql-action action to v3.29.11
2025-08-22 10:04:41 +02:00
renovate[bot]
14884f2628 Update github/codeql-action action to v3.29.11 2025-08-21 20:57:46 +00:00
intelligentdonut
41188ff054 Translated using Weblate (English (Pirate))
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/en@pirate/
2025-08-19 17:42:50 +00:00
Bond-009
cb6e38d830 Merge pull request #14670 from jellyfin/renovate/ci-deps
Update github/codeql-action action to v3.29.10
2025-08-19 17:16:37 +02:00
renovate[bot]
4ba34709d6 Update github/codeql-action action to v3.29.10 2025-08-18 16:34:37 +00:00
Gene
28b8d3ee29 fix: correct anamorphic video detection (#14640) (#14648) 2025-08-15 18:52:43 -06:00
MrPlow
9eaca73888 Translated using Weblate (German)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/de/
2025-08-15 16:24:00 +00:00
Evan
29e17b6bc0 Run background ffmpeg tasks as ProcessPriorityClass.BelowNormal
Follow TrickPlay example of running other background ffmpeg tasks as ProcessPriorityClass.BelowNormal:

- Keyframe extraction
- Media info probing during library scans
- Audio normalization
- Image extraction
2025-08-15 07:18:44 +08:00
Yago Raña Gayoso
84cde7383f Translated using Weblate (Galician)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/gl/
2025-08-14 18:32:52 +00:00
sususu98
aebabb1580 style: fix return statement indentation in StreamInfo.cs 2025-04-24 14:25:12 +08:00
sususu98
d5402718b7 Merge branch 'jellyfin:master' into fix/strm-local-subtitle-url 2025-04-24 14:18:17 +08:00
sususu98
fd108ff528 Style: Fix indentation in StreamInfo.cs 2025-04-24 14:17:33 +08:00
sususu98
22ce1f25d0 refactor(StreamInfo): reorganize subtitle URL logic and conditions
# Conflicts:
#	MediaBrowser.Model/Dlna/StreamInfo.cs
2025-04-23 18:18:38 +08:00
234 changed files with 7178 additions and 1954 deletions

View File

@@ -3,7 +3,7 @@
"isRoot": true,
"tools": {
"dotnet-ef": {
"version": "9.0.8",
"version": "9.0.11",
"commands": [
"dotnet-ef"
]

View File

@@ -294,6 +294,9 @@ dotnet_diagnostic.CA1854.severity = error
# error on CA1860: Avoid using 'Enumerable.Any()' extension method
dotnet_diagnostic.CA1860.severity = error
# error on CA1861: Avoid constant arrays as arguments
dotnet_diagnostic.CA1861.severity = error
# error on CA1862: Use the 'StringComparison' method overloads to perform case-insensitive string comparisons
dotnet_diagnostic.CA1862.severity = error

15
.github/CODEOWNERS vendored
View File

@@ -1,4 +1,11 @@
# Joshua must review all changes to deployment and build.sh
.ci/* @joshuaboniface
deployment/* @joshuaboniface
build.sh @joshuaboniface
# Joshua must review all changes to bump_version and any files it touches
bump_version @joshuaboniface
.github/ISSUE_TEMPLATE @joshuaboniface
MediaBrowser.Common/MediaBrowser.Common.csproj @joshuaboniface
Jellyfin.Data/Jellyfin.Data.csproj @joshuaboniface
MediaBrowser.Controller/MediaBrowser.Controller.csproj @joshuaboniface
MediaBrowser.Model/MediaBrowser.Model.csproj @joshuaboniface
Emby.Naming/Emby.Naming.csproj @joshuaboniface
src/Jellyfin.Extensions/Jellyfin.Extensions.csproj @joshuaboniface
# Core must approve all changes within the repo config
.github/ @jellyfin/core

View File

@@ -87,7 +87,10 @@ body:
label: Jellyfin Server version
description: What version of Jellyfin are you using?
options:
- 10.10.0+
- 10.11.3
- 10.11.2
- 10.11.1
- 10.11.0
- Master
- Unstable
- Older*

View File

@@ -20,18 +20,18 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
- name: Setup .NET
uses: actions/setup-dotnet@67a3573c9a986a3f9c594539f4ab511d57bb3ce9 # v4.3.1
uses: actions/setup-dotnet@2016bd2012dba4e32de620c46fe006a3ac9f0602 # v5.0.1
with:
dotnet-version: '9.0.x'
- name: Initialize CodeQL
uses: github/codeql-action/init@df559355d593797519d70b90fc8edd5db049e7a2 # v3.29.9
uses: github/codeql-action/init@fdbfb4d2750291e159f0156def62b853c2798ca2 # v4.31.5
with:
languages: ${{ matrix.language }}
queries: +security-extended
- name: Autobuild
uses: github/codeql-action/autobuild@df559355d593797519d70b90fc8edd5db049e7a2 # v3.29.9
uses: github/codeql-action/autobuild@fdbfb4d2750291e159f0156def62b853c2798ca2 # v4.31.5
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@df559355d593797519d70b90fc8edd5db049e7a2 # v3.29.9
uses: github/codeql-action/analyze@fdbfb4d2750291e159f0156def62b853c2798ca2 # v4.31.5

View File

@@ -11,13 +11,13 @@ jobs:
permissions: read-all
steps:
- name: Checkout repository
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
with:
ref: ${{ github.event.pull_request.head.sha }}
repository: ${{ github.event.pull_request.head.repo.full_name }}
- name: Setup .NET
uses: actions/setup-dotnet@67a3573c9a986a3f9c594539f4ab511d57bb3ce9 # v4.3.1
uses: actions/setup-dotnet@2016bd2012dba4e32de620c46fe006a3ac9f0602 # v5.0.1
with:
dotnet-version: '9.0.x'
@@ -26,7 +26,7 @@ jobs:
dotnet build Jellyfin.Server -o ./out
- name: Upload Head
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
with:
name: abi-head
retention-days: 14
@@ -40,14 +40,14 @@ jobs:
permissions: read-all
steps:
- name: Checkout repository
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
with:
ref: ${{ github.event.pull_request.head.sha }}
repository: ${{ github.event.pull_request.head.repo.full_name }}
fetch-depth: 0
- name: Setup .NET
uses: actions/setup-dotnet@67a3573c9a986a3f9c594539f4ab511d57bb3ce9 # v4.3.1
uses: actions/setup-dotnet@2016bd2012dba4e32de620c46fe006a3ac9f0602 # v5.0.1
with:
dotnet-version: '9.0.x'
@@ -65,7 +65,7 @@ jobs:
dotnet build Jellyfin.Server -o ./out
- name: Upload Head
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
with:
name: abi-base
retention-days: 14
@@ -85,13 +85,13 @@ jobs:
steps:
- name: Download abi-head
uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0
uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0
with:
name: abi-head
path: abi-head
- name: Download abi-base
uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0
uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0
with:
name: abi-base
path: abi-base
@@ -115,7 +115,7 @@ jobs:
} >> $GITHUB_OUTPUT
- name: Find difference comment
uses: peter-evans/find-comment@3eae4d37986fb5a8592848f6a574fdf654e61f9e # v3.1.0
uses: peter-evans/find-comment@b30e6a3c0ed37e7c023ccd3f1db5c6c0b0c23aad # v4.0.0
id: find-comment
with:
issue-number: ${{ github.event.pull_request.number }}
@@ -123,7 +123,7 @@ jobs:
body-includes: abi-diff-workflow-comment
- name: Reply or edit difference comment (changed)
uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4.0.0
uses: peter-evans/create-or-update-comment@e8674b075228eee787fea43ef493e45ece1004c9 # v5.0.0
if: ${{ steps.diff.outputs.body != '' }}
with:
issue-number: ${{ github.event.pull_request.number }}
@@ -142,7 +142,7 @@ jobs:
</details>
- name: Reply or edit difference comment (unchanged)
uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4.0.0
uses: peter-evans/create-or-update-comment@e8674b075228eee787fea43ef493e45ece1004c9 # v5.0.0
if: ${{ steps.diff.outputs.body == '' && steps.find-comment.outputs.comment-id != '' }}
with:
issue-number: ${{ github.event.pull_request.number }}

View File

@@ -16,18 +16,18 @@ jobs:
permissions: read-all
steps:
- name: Checkout repository
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
with:
ref: ${{ github.event.pull_request.head.sha }}
repository: ${{ github.event.pull_request.head.repo.full_name }}
- name: Setup .NET
uses: actions/setup-dotnet@67a3573c9a986a3f9c594539f4ab511d57bb3ce9 # v4.3.1
uses: actions/setup-dotnet@2016bd2012dba4e32de620c46fe006a3ac9f0602 # v5.0.1
with:
dotnet-version: '9.0.x'
- name: Generate openapi.json
run: dotnet test tests/Jellyfin.Server.Integration.Tests/Jellyfin.Server.Integration.Tests.csproj -c Release --filter "Jellyfin.Server.Integration.Tests.OpenApiSpecTests"
- name: Upload openapi.json
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
with:
name: openapi-head
retention-days: 14
@@ -41,7 +41,7 @@ jobs:
permissions: read-all
steps:
- name: Checkout repository
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
with:
ref: ${{ github.event.pull_request.head.sha }}
repository: ${{ github.event.pull_request.head.repo.full_name }}
@@ -55,13 +55,13 @@ jobs:
ANCESTOR_REF=$(git merge-base upstream/${{ github.base_ref }} origin/$HEAD_REF)
git checkout --progress --force $ANCESTOR_REF
- name: Setup .NET
uses: actions/setup-dotnet@67a3573c9a986a3f9c594539f4ab511d57bb3ce9 # v4.3.1
uses: actions/setup-dotnet@2016bd2012dba4e32de620c46fe006a3ac9f0602 # v5.0.1
with:
dotnet-version: '9.0.x'
- name: Generate openapi.json
run: dotnet test tests/Jellyfin.Server.Integration.Tests/Jellyfin.Server.Integration.Tests.csproj -c Release --filter "Jellyfin.Server.Integration.Tests.OpenApiSpecTests"
- name: Upload openapi.json
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
with:
name: openapi-base
retention-days: 14
@@ -80,12 +80,12 @@ jobs:
- openapi-base
steps:
- name: Download openapi-head
uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0
uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0
with:
name: openapi-head
path: openapi-head
- name: Download openapi-base
uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0
uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0
with:
name: openapi-base
path: openapi-base
@@ -120,14 +120,14 @@ jobs:
echo "" >> openapi-changes-reply.md
echo "</details>" >> openapi-changes-reply.md
- name: Find difference comment
uses: peter-evans/find-comment@3eae4d37986fb5a8592848f6a574fdf654e61f9e # v3.1.0
uses: peter-evans/find-comment@b30e6a3c0ed37e7c023ccd3f1db5c6c0b0c23aad # v4.0.0
id: find-comment
with:
issue-number: ${{ github.event.pull_request.number }}
direction: last
body-includes: openapi-diff-workflow-comment
- name: Reply or edit difference comment (changed)
uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4.0.0
uses: peter-evans/create-or-update-comment@e8674b075228eee787fea43ef493e45ece1004c9 # v5.0.0
if: ${{ steps.read-diff.outputs.ApiChanged == '1' }}
with:
issue-number: ${{ github.event.pull_request.number }}
@@ -135,7 +135,7 @@ jobs:
edit-mode: replace
body-path: openapi-changes-reply.md
- name: Edit difference comment (unchanged)
uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4.0.0
uses: peter-evans/create-or-update-comment@e8674b075228eee787fea43ef493e45ece1004c9 # v5.0.0
if: ${{ steps.read-diff.outputs.ApiChanged == '0' && steps.find-comment.outputs.comment-id != '' }}
with:
issue-number: ${{ github.event.pull_request.number }}
@@ -158,7 +158,7 @@ jobs:
run: |-
echo "JELLYFIN_VERSION=$(date +'%Y%m%d%H%M%S')" >> $GITHUB_ENV
- name: Download openapi-head
uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0
uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0
with:
name: openapi-head
path: openapi-head
@@ -172,7 +172,7 @@ jobs:
strip_components: 1
target: "/srv/incoming/openapi/unstable/jellyfin-openapi-${{ env.JELLYFIN_VERSION }}"
- name: Move openapi.json (unstable) into place
uses: appleboy/ssh-action@2ead5e36573f08b82fbfce1504f1a4b05a647c6f # v1.2.2
uses: appleboy/ssh-action@823bd89e131d8d508129f9443cad5855e9ba96f0 # v1.2.4
with:
host: "${{ secrets.REPO_HOST }}"
username: "${{ secrets.REPO_USER }}"
@@ -220,7 +220,7 @@ jobs:
run: |-
echo "JELLYFIN_VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_ENV
- name: Download openapi-head
uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0
uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0
with:
name: openapi-head
path: openapi-head
@@ -234,7 +234,7 @@ jobs:
strip_components: 1
target: "/srv/incoming/openapi/stable/jellyfin-openapi-${{ env.JELLYFIN_VERSION }}"
- name: Move openapi.json (stable) into place
uses: appleboy/ssh-action@2ead5e36573f08b82fbfce1504f1a4b05a647c6f # v1.2.2
uses: appleboy/ssh-action@823bd89e131d8d508129f9443cad5855e9ba96f0 # v1.2.4
with:
host: "${{ secrets.REPO_HOST }}"
username: "${{ secrets.REPO_USER }}"

View File

@@ -20,9 +20,9 @@ jobs:
runs-on: "${{ matrix.os }}"
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
- uses: actions/setup-dotnet@67a3573c9a986a3f9c594539f4ab511d57bb3ce9 # v4.3.1
- uses: actions/setup-dotnet@2016bd2012dba4e32de620c46fe006a3ac9f0602 # v5.0.1
with:
dotnet-version: ${{ env.SDK_VERSION }}
@@ -35,7 +35,7 @@ jobs:
--verbosity minimal
- name: Merge code coverage results
uses: danielpalme/ReportGenerator-GitHub-Action@c4c5175a441c6603ec614f5084386dabe0e2295b # v5.4.12
uses: danielpalme/ReportGenerator-GitHub-Action@dcdfb6e704e87df6b2ed0cf123a6c9f69e364869 # v5.5.0
with:
reports: "**/coverage.cobertura.xml"
targetdir: "merged/"

View File

@@ -17,14 +17,14 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Notify as seen
uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4.0.0
uses: peter-evans/create-or-update-comment@e8674b075228eee787fea43ef493e45ece1004c9 # v5.0.0
with:
token: ${{ secrets.JF_BOT_TOKEN }}
comment-id: ${{ github.event.comment.id }}
reactions: '+1'
- name: Checkout the latest code
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
with:
token: ${{ secrets.JF_BOT_TOKEN }}
fetch-depth: 0
@@ -40,13 +40,13 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: pull in script
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
with:
repository: jellyfin/jellyfin-triage-script
- name: install python
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0
with:
python-version: '3.13'
python-version: '3.14'
cache: 'pip'
- name: install python packages
run: pip install -r rename/requirements.txt

View File

@@ -16,7 +16,7 @@ jobs:
runs-on: ubuntu-latest
if: ${{ contains(github.repository, 'jellyfin/') }}
steps:
- uses: actions/stale@5bef64f19d7facfb25b37b414482c7164d639639 # v9.1.0
- uses: actions/stale@5f858e3efba33a5ca4407a664cc011ad407f2008 # v10.1.0
with:
repo-token: ${{ secrets.JF_BOT_TOKEN }}
ascending: true

View File

@@ -10,13 +10,13 @@ jobs:
issues: write
steps:
- name: pull in script
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
with:
repository: jellyfin/jellyfin-triage-script
- name: install python
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0
with:
python-version: '3.13'
python-version: '3.14'
cache: 'pip'
- name: install python packages
run: pip install -r main-repo-triage/requirements.txt

View File

@@ -15,7 +15,7 @@ jobs:
runs-on: ubuntu-latest
if: ${{ contains(github.repository, 'jellyfin/') }}
steps:
- uses: actions/stale@5bef64f19d7facfb25b37b414482c7164d639639 # v9.1.0
- uses: actions/stale@5f858e3efba33a5ca4407a664cc011ad407f2008 # v10.1.0
with:
repo-token: ${{ secrets.JF_BOT_TOKEN }}
ascending: true

View File

@@ -33,7 +33,7 @@ jobs:
yq-version: v4.9.8
- name: Checkout Repository
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
with:
ref: ${{ env.TAG_BRANCH }}
@@ -66,7 +66,7 @@ jobs:
NEXT_VERSION: ${{ github.event.inputs.NEXT_VERSION }}
steps:
- name: Checkout Repository
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
with:
ref: ${{ env.TAG_BRANCH }}

View File

@@ -31,6 +31,7 @@
- [DaveChild](https://github.com/DaveChild)
- [DavidFair](https://github.com/DavidFair)
- [Delgan](https://github.com/Delgan)
- [Derpipose](https://github.com/Derpipose)
- [dcrdev](https://github.com/dcrdev)
- [dhartung](https://github.com/dhartung)
- [dinki](https://github.com/dinki)
@@ -140,6 +141,7 @@
- [ThibaultNocchi](https://github.com/ThibaultNocchi)
- [thornbill](https://github.com/thornbill)
- [ThreeFive-O](https://github.com/ThreeFive-O)
- [tjwalkr3](https://github.com/tjwalkr3)
- [TrisMcC](https://github.com/TrisMcC)
- [trumblejoe](https://github.com/trumblejoe)
- [TtheCreator](https://github.com/TtheCreator)
@@ -202,6 +204,7 @@
- [Shoham Peller](https://github.com/spellr)
- [theshoeshiner](https://github.com/theshoeshiner)
- [TokerX](https://github.com/TokerX)
- [GeneMarks](https://github.com/GeneMarks)
# Emby Contributors

View File

@@ -19,4 +19,9 @@
<AdditionalFiles Include="$(MSBuildThisFileDirectory)/stylecop.json" />
</ItemGroup>
<!-- Custom Analyzers -->
<ItemGroup Condition=" '$(MSBuildProjectName)' != 'Jellyfin.CodeAnalysis' AND '$(Configuration)' == 'Debug' ">
<ProjectReference Include="$(MSBuildThisFileDirectory)src/Jellyfin.CodeAnalysis/Jellyfin.CodeAnalysis.csproj" OutputItemType="Analyzer" />
</ItemGroup>
</Project>

View File

@@ -4,7 +4,7 @@
</PropertyGroup>
<!-- Run "dotnet list package (dash,dash)outdated" to see the latest versions of each package.-->
<ItemGroup Label="Package Dependencies">
<PackageVersion Include="AsyncKeyedLock" Version="7.1.6" />
<PackageVersion Include="AsyncKeyedLock" Version="7.1.7" />
<PackageVersion Include="AutoFixture.AutoMoq" Version="4.18.1" />
<PackageVersion Include="AutoFixture.Xunit2" Version="4.18.1" />
<PackageVersion Include="AutoFixture" Version="4.18.1" />
@@ -17,7 +17,7 @@
<PackageVersion Include="Diacritics" Version="4.0.17" />
<PackageVersion Include="DiscUtils.Udf" Version="0.16.13" />
<PackageVersion Include="DotNet.Glob" Version="3.1.3" />
<PackageVersion Include="FsCheck.Xunit" Version="3.3.0" />
<PackageVersion Include="FsCheck.Xunit" Version="3.3.2" />
<PackageVersion Include="HarfBuzzSharp.NativeAssets.Linux" Version="8.3.1.1" />
<PackageVersion Include="ICU4N.Transliterator" Version="60.1.0-alpha.356" />
<PackageVersion Include="IDisposableAnalyzers" Version="4.0.8" />
@@ -26,71 +26,74 @@
<PackageVersion Include="libse" Version="4.0.12" />
<PackageVersion Include="LrcParser" Version="2025.623.0" />
<PackageVersion Include="MetaBrainz.MusicBrainz" Version="6.1.0" />
<PackageVersion Include="Microsoft.AspNetCore.Authorization" Version="9.0.8" />
<PackageVersion Include="Microsoft.AspNetCore.Mvc.Testing" Version="9.0.8" />
<PackageVersion Include="Microsoft.AspNetCore.Authorization" Version="9.0.11" />
<PackageVersion Include="Microsoft.AspNetCore.Mvc.Testing" Version="9.0.11" />
<PackageVersion Include="Microsoft.CodeAnalysis.BannedApiAnalyzers" Version="4.14.0" />
<PackageVersion Include="Microsoft.Data.Sqlite" Version="9.0.8" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.8" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Relational" Version="9.0.8" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Sqlite" Version="9.0.8" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Tools" Version="9.0.8" />
<PackageVersion Include="Microsoft.Extensions.Caching.Abstractions" Version="9.0.8" />
<PackageVersion Include="Microsoft.Extensions.Caching.Memory" Version="9.0.8" />
<PackageVersion Include="Microsoft.Extensions.Configuration.Abstractions" Version="9.0.8" />
<PackageVersion Include="Microsoft.Extensions.Configuration.Binder" Version="9.0.8" />
<PackageVersion Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="9.0.8" />
<PackageVersion Include="Microsoft.Extensions.Configuration.Json" Version="9.0.8" />
<PackageVersion Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="9.0.8" />
<PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="9.0.8" />
<PackageVersion Include="Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore" Version="9.0.8" />
<PackageVersion Include="Microsoft.Extensions.Diagnostics.HealthChecks" Version="9.0.8" />
<PackageVersion Include="Microsoft.Extensions.Hosting.Abstractions" Version="9.0.8" />
<PackageVersion Include="Microsoft.Extensions.Http" Version="9.0.8" />
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="9.0.8" />
<PackageVersion Include="Microsoft.Extensions.Logging" Version="9.0.8" />
<PackageVersion Include="Microsoft.Extensions.Options" Version="9.0.8" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
<PackageVersion Include="Microsoft.CodeAnalysis.Common" Version="4.14.0" />
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.14.0" />
<PackageVersion Include="Microsoft.CodeAnalysis.Analyzers" Version="3.11.0" />
<PackageVersion Include="Microsoft.Data.Sqlite" Version="9.0.11" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.11" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Relational" Version="9.0.11" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Sqlite" Version="9.0.11" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Tools" Version="9.0.11" />
<PackageVersion Include="Microsoft.Extensions.Caching.Abstractions" Version="9.0.11" />
<PackageVersion Include="Microsoft.Extensions.Caching.Memory" Version="9.0.11" />
<PackageVersion Include="Microsoft.Extensions.Configuration.Abstractions" Version="9.0.11" />
<PackageVersion Include="Microsoft.Extensions.Configuration.Binder" Version="9.0.11" />
<PackageVersion Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="9.0.11" />
<PackageVersion Include="Microsoft.Extensions.Configuration.Json" Version="9.0.11" />
<PackageVersion Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="9.0.11" />
<PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="9.0.11" />
<PackageVersion Include="Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore" Version="9.0.11" />
<PackageVersion Include="Microsoft.Extensions.Diagnostics.HealthChecks" Version="9.0.11" />
<PackageVersion Include="Microsoft.Extensions.Hosting.Abstractions" Version="9.0.11" />
<PackageVersion Include="Microsoft.Extensions.Http" Version="9.0.11" />
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="9.0.11" />
<PackageVersion Include="Microsoft.Extensions.Logging" Version="9.0.11" />
<PackageVersion Include="Microsoft.Extensions.Options" Version="9.0.11" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="18.0.1" />
<PackageVersion Include="MimeTypes" Version="2.5.2" />
<PackageVersion Include="Morestachio" Version="5.0.1.631" />
<PackageVersion Include="Moq" Version="4.18.4" />
<PackageVersion Include="NEbml" Version="1.0.0.3" />
<PackageVersion Include="Newtonsoft.Json" Version="13.0.3" />
<PackageVersion Include="NEbml" Version="1.1.0.5" />
<PackageVersion Include="Newtonsoft.Json" Version="13.0.4" />
<PackageVersion Include="PlaylistsNET" Version="1.4.1" />
<PackageVersion Include="prometheus-net.AspNetCore" Version="8.2.1" />
<PackageVersion Include="prometheus-net.DotNetRuntime" Version="4.4.1" />
<PackageVersion Include="prometheus-net" Version="8.2.1" />
<PackageVersion Include="Polly" Version="8.6.2" />
<PackageVersion Include="Polly" Version="8.6.5" />
<PackageVersion Include="Serilog.AspNetCore" Version="9.0.0" />
<PackageVersion Include="Serilog.Enrichers.Thread" Version="4.0.0" />
<PackageVersion Include="Serilog.Expressions" Version="5.0.0" />
<PackageVersion Include="Serilog.Settings.Configuration" Version="9.0.0" />
<PackageVersion Include="Serilog.Sinks.Async" Version="2.1.0" />
<PackageVersion Include="Serilog.Sinks.Console" Version="6.0.0" />
<PackageVersion Include="Serilog.Sinks.Console" Version="6.1.1" />
<PackageVersion Include="Serilog.Sinks.File" Version="7.0.0" />
<PackageVersion Include="Serilog.Sinks.Graylog" Version="3.1.1" />
<PackageVersion Include="SerilogAnalyzer" Version="0.15.0" />
<PackageVersion Include="SharpFuzz" Version="2.2.0" />
<!-- Pinned to 3.116.1 because https://github.com/jellyfin/jellyfin/pull/14255 -->
<!-- Pinned to 3.116.1 because https://github.com/jellyfin/jellyfin/pull/14255 -->
<PackageVersion Include="SkiaSharp" Version="3.116.1" />
<PackageVersion Include="SkiaSharp.HarfBuzz" Version="3.116.1" />
<PackageVersion Include="SkiaSharp.NativeAssets.Linux" Version="3.116.1" />
<PackageVersion Include="SmartAnalyzers.MultithreadingAnalyzer" Version="1.1.31" />
<PackageVersion Include="StyleCop.Analyzers" Version="1.2.0-beta.556" />
<PackageVersion Include="Svg.Skia" Version="3.0.5" />
<PackageVersion Include="Svg.Skia" Version="3.2.1" />
<PackageVersion Include="Swashbuckle.AspNetCore.ReDoc" Version="6.5.0" />
<PackageVersion Include="Swashbuckle.AspNetCore" Version="6.2.3" />
<PackageVersion Include="System.Globalization" Version="4.3.0" />
<PackageVersion Include="System.Linq.Async" Version="6.0.3" />
<PackageVersion Include="System.Text.Encoding.CodePages" Version="9.0.8" />
<PackageVersion Include="System.Text.Json" Version="9.0.8" />
<PackageVersion Include="System.Threading.Tasks.Dataflow" Version="9.0.8" />
<PackageVersion Include="System.Text.Encoding.CodePages" Version="9.0.11" />
<PackageVersion Include="System.Text.Json" Version="9.0.11" />
<PackageVersion Include="System.Threading.Tasks.Dataflow" Version="9.0.11" />
<PackageVersion Include="TagLibSharp" Version="2.3.0" />
<PackageVersion Include="z440.atl.core" Version="7.3.0" />
<PackageVersion Include="TMDbLib" Version="2.2.0" />
<PackageVersion Include="z440.atl.core" Version="7.9.0" />
<PackageVersion Include="TMDbLib" Version="2.3.0" />
<PackageVersion Include="UTF.Unknown" Version="2.6.0" />
<PackageVersion Include="Xunit.Priority" Version="1.1.6" />
<PackageVersion Include="xunit.runner.visualstudio" Version="2.8.2" />
<PackageVersion Include="Xunit.SkippableFact" Version="1.5.23" />
<PackageVersion Include="xunit" Version="2.9.3" />
</ItemGroup>
</Project>
</Project>

View File

@@ -21,8 +21,8 @@ namespace Emby.Naming.Common
/// </summary>
public NamingOptions()
{
VideoFileExtensions = new[]
{
VideoFileExtensions =
[
".001",
".3g2",
".3gp",
@@ -77,10 +77,10 @@ namespace Emby.Naming.Common
".wmv",
".wtv",
".xvid"
};
];
VideoFlagDelimiters = new[]
{
VideoFlagDelimiters =
[
'(',
')',
'-',
@@ -88,15 +88,15 @@ namespace Emby.Naming.Common
'_',
'[',
']'
};
];
StubFileExtensions = new[]
{
StubFileExtensions =
[
".disc"
};
];
StubTypes = new[]
{
StubTypes =
[
new StubTypeRule(
stubType: "dvd",
token: "dvd"),
@@ -136,32 +136,32 @@ namespace Emby.Naming.Common
new StubTypeRule(
stubType: "tv",
token: "DSR")
};
];
VideoFileStackingRules = new[]
{
VideoFileStackingRules =
[
new FileStackRule(@"^(?<filename>.*?)(?:(?<=[\]\)\}])|[ _.-]+)[\(\[]?(?<parttype>cd|dvd|part|pt|dis[ck])[ _.-]*(?<number>[0-9]+)[\)\]]?(?:\.[^.]+)?$", true),
new FileStackRule(@"^(?<filename>.*?)(?:(?<=[\]\)\}])|[ _.-]+)[\(\[]?(?<parttype>cd|dvd|part|pt|dis[ck])[ _.-]*(?<number>[a-d])[\)\]]?(?:\.[^.]+)?$", false)
};
];
CleanDateTimes = new[]
{
CleanDateTimes =
[
@"(.+[^_\,\.\(\)\[\]\-])[_\.\(\)\[\]\-](19[0-9]{2}|20[0-9]{2})(?![0-9]+|\W[0-9]{2}\W[0-9]{2})([ _\,\.\(\)\[\]\-][^0-9]|).*(19[0-9]{2}|20[0-9]{2})*",
@"(.+[^_\,\.\(\)\[\]\-])[ _\.\(\)\[\]\-]+(19[0-9]{2}|20[0-9]{2})(?![0-9]+|\W[0-9]{2}\W[0-9]{2})([ _\,\.\(\)\[\]\-][^0-9]|).*(19[0-9]{2}|20[0-9]{2})*"
};
];
CleanStrings = new[]
{
CleanStrings =
[
@"^\s*(?<cleaned>.+?)[ _\,\.\(\)\[\]\-](3d|sbs|tab|hsbs|htab|mvc|HDR|HDC|UHD|UltraHD|4k|ac3|dts|custom|dc|divx|divx5|dsr|dsrip|dutch|dvd|dvdrip|dvdscr|dvdscreener|screener|dvdivx|cam|fragment|fs|hdtv|hdrip|hdtvrip|internal|limited|multi|subs|ntsc|ogg|ogm|pal|pdtv|proper|repack|rerip|retail|cd[1-9]|r5|bd5|bd|se|svcd|swedish|german|read.nfo|nfofix|unrated|ws|telesync|ts|telecine|tc|brrip|bdrip|480p|480i|576p|576i|720p|720i|1080p|1080i|2160p|hrhd|hrhdtv|hddvd|bluray|blu-ray|x264|x265|h264|h265|xvid|xvidvd|xxx|www.www|AAC|DTS|\[.*\])([ _\,\.\(\)\[\]\-]|$)",
@"^(?<cleaned>.+?)(\[.*\])",
@"^\s*(?<cleaned>.+?)\WE[0-9]+(-|~)E?[0-9]+(\W|$)",
@"^\s*\[[^\]]+\](?!\.\w+$)\s*(?<cleaned>.+)",
@"^\s*(?<cleaned>.+?)\s+-\s+[0-9]+\s*$",
@"^\s*(?<cleaned>.+?)(([-._ ](trailer|sample))|-(scene|clip|behindthescenes|deleted|deletedscene|featurette|short|interview|other|extra))$"
};
];
SubtitleFileExtensions = new[]
{
SubtitleFileExtensions =
[
".ass",
".mks",
".sami",
@@ -171,17 +171,17 @@ namespace Emby.Naming.Common
".sub",
".sup",
".vtt",
};
];
LyricFileExtensions = new[]
{
LyricFileExtensions =
[
".lrc",
".elrc",
".txt"
};
];
AlbumStackingPrefixes = new[]
{
AlbumStackingPrefixes =
[
"cd",
"digital media",
"disc",
@@ -190,10 +190,10 @@ namespace Emby.Naming.Common
"volume",
"part",
"act"
};
];
ArtistSubfolders = new[]
{
ArtistSubfolders =
[
"albums",
"broadcasts",
"bootlegs",
@@ -208,10 +208,10 @@ namespace Emby.Naming.Common
"soundtracks",
"spokenwords",
"streets"
};
];
AudioFileExtensions = new[]
{
AudioFileExtensions =
[
".669",
".3gp",
".aa",
@@ -241,6 +241,7 @@ namespace Emby.Naming.Common
".dts",
".dvf",
".eac3",
".ec3",
".far",
".flac",
".gdm",
@@ -291,33 +292,33 @@ namespace Emby.Naming.Common
".xm",
".xsp",
".ymf"
};
];
MediaFlagDelimiters = new[]
{
MediaFlagDelimiters =
[
'.'
};
];
MediaForcedFlags = new[]
{
MediaForcedFlags =
[
"foreign",
"forced"
};
];
MediaDefaultFlags = new[]
{
MediaDefaultFlags =
[
"default"
};
];
MediaHearingImpairedFlags = new[]
{
MediaHearingImpairedFlags =
[
"cc",
"hi",
"sdh"
};
];
EpisodeExpressions = new[]
{
EpisodeExpressions =
[
// *** Begin Kodi Standard Naming
// <!-- foo.s01.e01, foo.s01_e01, S01E02 foo, S01 - E02 -->
new EpisodeExpression(@".*(\\|\/)(?<seriesname>((?![Ss]([0-9]+)[][ ._-]*[Ee]([0-9]+))[^\\\/])*)?[Ss](?<seasonnumber>[0-9]+)[][ ._-]*[Ee](?<epnumber>[0-9]+)([^\\/]*)$")
@@ -330,23 +331,23 @@ namespace Emby.Naming.Common
new EpisodeExpression(@"[^\\/]*?()\.?[Ee]([0-9]+)\.([^\\/]*)$"),
new EpisodeExpression("(?<year>[0-9]{4})[._ -](?<month>[0-9]{2})[._ -](?<day>[0-9]{2})", true)
{
DateTimeFormats = new[]
{
DateTimeFormats =
[
"yyyy.MM.dd",
"yyyy-MM-dd",
"yyyy_MM_dd",
"yyyy MM dd"
}
]
},
new EpisodeExpression("(?<day>[0-9]{2})[._ -](?<month>[0-9]{2})[._ -](?<year>[0-9]{4})", true)
{
DateTimeFormats = new[]
{
DateTimeFormats =
[
"dd.MM.yyyy",
"dd-MM-yyyy",
"dd_MM_yyyy",
"dd MM yyyy"
}
]
},
// This isn't a Kodi naming rule, but the expression below causes false episode numbers for
@@ -478,10 +479,10 @@ namespace Emby.Naming.Common
{
IsNamed = true
},
};
];
VideoExtraRules = new[]
{
VideoExtraRules =
[
new ExtraRule(
ExtraType.Trailer,
ExtraRuleType.DirectoryName,
@@ -691,14 +692,14 @@ namespace Emby.Naming.Common
ExtraRuleType.Suffix,
"-other",
MediaType.Video)
};
];
AllExtrasTypesFolderNames = VideoExtraRules
.Where(i => i.RuleType == ExtraRuleType.DirectoryName)
.ToDictionary(i => i.Token, i => i.ExtraType, StringComparer.OrdinalIgnoreCase);
Format3DRules = new[]
{
Format3DRules =
[
// Kodi rules:
new Format3DRule(
precedingToken: "3d",
@@ -725,10 +726,10 @@ namespace Emby.Naming.Common
new Format3DRule("tab"),
new Format3DRule("sbs3d"),
new Format3DRule("mvc")
};
];
AudioBookPartsExpressions = new[]
{
AudioBookPartsExpressions =
[
// Detect specified chapters, like CH 01
@"ch(?:apter)?[\s_-]?(?<chapter>[0-9]+)",
// Detect specified parts, like Part 02
@@ -741,14 +742,14 @@ namespace Emby.Naming.Common
"(?<chapter>[0-9]+)_(?<part>[0-9]+)",
// Some audiobooks are ripped from cd's, and will be named by disk number.
@"dis(?:c|k)[\s_-]?(?<chapter>[0-9]+)"
};
];
AudioBookNamesExpressions = new[]
{
AudioBookNamesExpressions =
[
// Detect year usually in brackets after name Batman (2020)
@"^(?<name>.+?)\s*\(\s*(?<year>[0-9]{4})\s*\)\s*$",
@"^\s*(?<name>[^ ].*?)\s*$"
};
];
MultipleEpisodeExpressions = new[]
{
@@ -888,12 +889,12 @@ namespace Emby.Naming.Common
/// <summary>
/// Gets list of clean datetime regular expressions.
/// </summary>
public Regex[] CleanDateTimeRegexes { get; private set; } = Array.Empty<Regex>();
public Regex[] CleanDateTimeRegexes { get; private set; } = [];
/// <summary>
/// Gets list of clean string regular expressions.
/// </summary>
public Regex[] CleanStringRegexes { get; private set; } = Array.Empty<Regex>();
public Regex[] CleanStringRegexes { get; private set; } = [];
/// <summary>
/// Compiles raw regex strings into regexes.

View File

@@ -36,7 +36,7 @@
<PropertyGroup>
<Authors>Jellyfin Contributors</Authors>
<PackageId>Jellyfin.Naming</PackageId>
<VersionPrefix>10.11.0</VersionPrefix>
<VersionPrefix>10.12.0</VersionPrefix>
<RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl>
<PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression>
</PropertyGroup>

View File

@@ -10,12 +10,17 @@ namespace Emby.Naming.TV
/// </summary>
public static partial class SeasonPathParser
{
[GeneratedRegex(@"^\s*((?<seasonnumber>(?>\d+))(?:st|nd|rd|th|\.)*(?!\s*[Ee]\d+))\s*(?:[[]*|[]*|[sS](?:eason|æson|aison|taffel|eries|tagione|äsong|eizoen|easong|ezon|ezona|ezóna|ezonul)*|[tT](?:emporada)*|[kK](?:ausi)*|[Сс](?:езон)*)\s*(?<rightpart>.*)$")]
private static readonly Regex CleanNameRegex = new(@"[ ._\-\[\]]", RegexOptions.Compiled);
[GeneratedRegex(@"^\s*((?<seasonnumber>(?>\d+))(?:st|nd|rd|th|\.)*(?!\s*[Ee]\d+))\s*(?:[[]*|[]*|[sS](?:eason|æson|aison|taffel|eries|tagione|äsong|eizoen|easong|ezon|ezona|ezóna|ezonul)*|[tT](?:emporada)*|[kK](?:ausi)*|[Сс](?:езон)*)\s*(?<rightpart>.*)$", RegexOptions.IgnoreCase)]
private static partial Regex ProcessPre();
[GeneratedRegex(@"^\s*(?:[[]*|[]*|[sS](?:eason|æson|aison|taffel|eries|tagione|äsong|eizoen|easong|ezon|ezona|ezóna|ezonul)*|[tT](?:emporada)*|[kK](?:ausi)*|[Сс](?:езон)*)\s*(?<seasonnumber>(?>\d+)(?!\s*[Ee]\d+))(?<rightpart>.*)$")]
[GeneratedRegex(@"^\s*(?:[[]*|[]*|[sS](?:eason|æson|aison|taffel|eries|tagione|äsong|eizoen|easong|ezon|ezona|ezóna|ezonul)*|[tT](?:emporada)*|[kK](?:ausi)*|[Сс](?:езон)*)\s*(?<seasonnumber>\d+?)(?=\d{3,4}p|[^\d]|$)(?!\s*[Ee]\d)(?<rightpart>.*)$", RegexOptions.IgnoreCase)]
private static partial Regex ProcessPost();
[GeneratedRegex(@"[sS](\d{1,4})(?!\d|[eE]\d)(?=\.|_|-|\[|\]|\s|$)", RegexOptions.None)]
private static partial Regex SeasonPrefix();
/// <summary>
/// Attempts to parse season number from path.
/// </summary>
@@ -56,44 +61,34 @@ namespace Emby.Naming.TV
bool supportSpecialAliases,
bool supportNumericSeasonFolders)
{
string filename = Path.GetFileName(path);
filename = Regex.Replace(filename, "[ ._-]", string.Empty);
var fileName = Path.GetFileName(path);
var seasonPrefixMatch = SeasonPrefix().Match(fileName);
if (seasonPrefixMatch.Success &&
int.TryParse(seasonPrefixMatch.Groups[1].Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var val))
{
return (val, true);
}
string filename = CleanNameRegex.Replace(fileName, string.Empty);
if (parentFolderName is not null)
{
parentFolderName = Regex.Replace(parentFolderName, "[ ._-]", string.Empty);
filename = filename.Replace(parentFolderName, string.Empty, StringComparison.OrdinalIgnoreCase);
var cleanParent = CleanNameRegex.Replace(parentFolderName, string.Empty);
filename = filename.Replace(cleanParent, string.Empty, StringComparison.OrdinalIgnoreCase);
}
if (supportSpecialAliases)
if (supportSpecialAliases &&
(filename.Equals("specials", StringComparison.OrdinalIgnoreCase) ||
filename.Equals("extras", StringComparison.OrdinalIgnoreCase)))
{
if (string.Equals(filename, "specials", StringComparison.OrdinalIgnoreCase))
{
return (0, true);
}
if (string.Equals(filename, "extras", StringComparison.OrdinalIgnoreCase))
{
return (0, true);
}
return (0, true);
}
if (supportNumericSeasonFolders)
if (supportNumericSeasonFolders &&
int.TryParse(filename, NumberStyles.Integer, CultureInfo.InvariantCulture, out val))
{
if (int.TryParse(filename, NumberStyles.Integer, CultureInfo.InvariantCulture, out var val))
{
return (val, true);
}
}
if (filename.StartsWith('s'))
{
var testFilename = filename.AsSpan()[1..];
if (int.TryParse(testFilename, NumberStyles.Integer, CultureInfo.InvariantCulture, out var val))
{
return (val, true);
}
return (val, true);
}
var preMatch = ProcessPre().Match(filename);
@@ -113,8 +108,10 @@ namespace Emby.Naming.TV
var numberString = match.Groups["seasonnumber"];
if (numberString.Success)
{
var seasonNumber = int.Parse(numberString.Value, CultureInfo.InvariantCulture);
return (seasonNumber, true);
if (int.TryParse(numberString.Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var seasonNumber))
{
return (seasonNumber, true);
}
}
return (null, false);

View File

@@ -17,6 +17,13 @@ namespace Emby.Naming.TV
[GeneratedRegex(@"((?<a>[^\._]{2,})[\._]*)|([\._](?<b>[^\._]{2,}))")]
private static partial Regex SeriesNameRegex();
/// <summary>
/// Regex that matches titles with year in parentheses. Captures the title (which may be
/// numeric) before the year, i.e. turns "1923 (2022)" into "1923".
/// </summary>
[GeneratedRegex(@"(?<title>.+?)\s*\(\d{4}\)")]
private static partial Regex TitleWithYearRegex();
/// <summary>
/// Resolve information about series from path.
/// </summary>
@@ -27,6 +34,20 @@ namespace Emby.Naming.TV
{
string seriesName = Path.GetFileName(path);
// First check if the filename matches a title with year pattern (handles numeric titles)
if (!string.IsNullOrEmpty(seriesName))
{
var titleWithYearMatch = TitleWithYearRegex().Match(seriesName);
if (titleWithYearMatch.Success)
{
seriesName = titleWithYearMatch.Groups["title"].Value.Trim();
return new SeriesInfo(path)
{
Name = seriesName
};
}
}
SeriesPathParserResult result = SeriesPathParser.Parse(options, path);
if (result.Success)
{

View File

@@ -132,7 +132,7 @@ namespace Emby.Naming.Video
}
}
private class StackMetadata
private sealed class StackMetadata
{
public StackMetadata(bool isDirectory, bool isNumerical, string partType)
{

View File

@@ -107,10 +107,20 @@ namespace Emby.Server.Implementations.AppBase
private void CheckOrCreateMarker(string path, string markerName, bool recursive = false)
{
var otherMarkers = GetMarkers(path, recursive).FirstOrDefault(e => Path.GetFileName(e) != markerName);
if (otherMarkers != null)
string? otherMarkers = null;
try
{
throw new InvalidOperationException($"Exepected to find only {markerName} but found marker for {otherMarkers}.");
otherMarkers = GetMarkers(path, recursive).FirstOrDefault(e => !Path.GetFileName(e.AsSpan()).Equals(markerName, StringComparison.OrdinalIgnoreCase));
}
catch
{
// Error while checking for marker files, assume none exist and keep going
// TODO: add some logging
}
if (otherMarkers is not null)
{
throw new InvalidOperationException($"Expected to find only {markerName} but found marker for {otherMarkers}.");
}
var markerPath = Path.Combine(path, markerName);

View File

@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Threading;
@@ -224,7 +223,7 @@ public class ChapterManager : IChapterManager
if (saveChapters && changesMade)
{
_chapterRepository.SaveChapters(video.Id, chapters);
SaveChapters(video, chapters);
}
DeleteDeadImages(currentImages, chapters);
@@ -235,7 +234,9 @@ public class ChapterManager : IChapterManager
/// <inheritdoc />
public void SaveChapters(Video video, IReadOnlyList<ChapterInfo> chapters)
{
_chapterRepository.SaveChapters(video.Id, chapters);
// Remove any chapters that are outside of the runtime of the video
var validChapters = chapters.Where(c => c.StartPositionTicks < video.RunTimeTicks).ToList();
_chapterRepository.SaveChapters(video.Id, validChapters);
}
/// <inheritdoc />
@@ -251,23 +252,9 @@ public class ChapterManager : IChapterManager
}
/// <inheritdoc />
public void DeleteChapterImages(Video video)
public async Task DeleteChapterDataAsync(Guid itemId, CancellationToken cancellationToken)
{
var path = _pathManager.GetChapterImageFolderPath(video);
try
{
if (Directory.Exists(path))
{
_logger.LogInformation("Removing chapter images for {Name} [{Id}]", video.Name, video.Id);
Directory.Delete(path, true);
}
}
catch (Exception ex)
{
_logger.LogWarning("Failed to remove chapter image folder for {Item}: {Exception}", video.Id, ex);
}
_chapterRepository.DeleteChapters(video.Id);
await _chapterRepository.DeleteChaptersAsync(itemId, cancellationToken).ConfigureAwait(false);
}
private IReadOnlyList<string> GetSavedChapterImages(Video video, IDirectoryService directoryService)

View File

@@ -104,6 +104,8 @@ namespace Emby.Server.Implementations.Collections
await _libraryManager.AddVirtualFolder(name, CollectionTypeOptions.boxsets, libraryOptions, true).ConfigureAwait(false);
_libraryManager.RootFolder.Children = null;
return FindFolders(path).First();
}

View File

@@ -50,6 +50,8 @@ public class CleanDatabaseScheduledTask : ILibraryPostScanTask
_logger.LogDebug("Cleaning {Number} items with dead parents", numItems);
IProgress<double> subProgress = new Progress<double>((val) => progress.Report(val / 2));
foreach (var itemId in itemIds)
{
cancellationToken.ThrowIfCancellationRequested();
@@ -95,9 +97,10 @@ public class CleanDatabaseScheduledTask : ILibraryPostScanTask
numComplete++;
double percent = numComplete;
percent /= numItems;
progress.Report(percent * 100);
subProgress.Report(percent * 100);
}
subProgress = new Progress<double>((val) => progress.Report((val / 2) + 50));
var context = await _dbProvider.CreateDbContextAsync(cancellationToken).ConfigureAwait(false);
await using (context.ConfigureAwait(false))
{
@@ -105,7 +108,9 @@ public class CleanDatabaseScheduledTask : ILibraryPostScanTask
await using (transaction.ConfigureAwait(false))
{
await context.ItemValues.Where(e => e.BaseItemsMap!.Count == 0).ExecuteDeleteAsync(cancellationToken).ConfigureAwait(false);
subProgress.Report(50);
await transaction.CommitAsync(cancellationToken).ConfigureAwait(false);
subProgress.Report(100);
}
}

View File

@@ -1051,30 +1051,15 @@ namespace Emby.Server.Implementations.Dto
// Include artists that are not in the database yet, e.g., just added via metadata editor
// var foundArtists = artistItems.Items.Select(i => i.Item1.Name).ToList();
dto.ArtistItems = hasArtist.Artists
// .Except(foundArtists, new DistinctNameComparer())
dto.ArtistItems = _libraryManager.GetArtists([.. hasArtist.Artists.Where(e => !string.IsNullOrWhiteSpace(e))])
.Where(e => e.Value.Length > 0)
.Select(i =>
{
// This should not be necessary but we're seeing some cases of it
if (string.IsNullOrEmpty(i))
return new NameGuidPair
{
return null;
}
var artist = _libraryManager.GetArtist(i, new DtoOptions(false)
{
EnableImages = false
});
if (artist is not null)
{
return new NameGuidPair
{
Name = artist.Name,
Id = artist.Id
};
}
return null;
Name = i.Key,
Id = i.Value.First().Id
};
}).Where(i => i is not null).ToArray();
}

View File

@@ -6,6 +6,7 @@ using System.Linq;
using System.Security;
using Jellyfin.Extensions;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Controller.IO;
using MediaBrowser.Model.IO;
using Microsoft.Extensions.Logging;
@@ -152,6 +153,10 @@ namespace Emby.Server.Implementations.IO
/// <inheritdoc />
public void MoveDirectory(string source, string destination)
{
// Make sure parent directory of target exists
var parent = Directory.GetParent(destination);
parent?.Create();
try
{
Directory.Move(source, destination);
@@ -248,47 +253,40 @@ namespace Emby.Server.Implementations.IO
{
result.IsDirectory = info is DirectoryInfo || (info.Attributes & FileAttributes.Directory) == FileAttributes.Directory;
// if (!result.IsDirectory)
// {
// result.IsHidden = (info.Attributes & FileAttributes.Hidden) == FileAttributes.Hidden;
// }
if (info is FileInfo fileInfo)
{
result.Length = fileInfo.Length;
// Issue #2354 get the size of files behind symbolic links. Also Enum.HasFlag is bad as it boxes!
if ((fileInfo.Attributes & FileAttributes.ReparsePoint) == FileAttributes.ReparsePoint)
result.CreationTimeUtc = GetCreationTimeUtc(info);
result.LastWriteTimeUtc = GetLastWriteTimeUtc(info);
if (fileInfo.LinkTarget is not null)
{
try
{
using (var fileHandle = File.OpenHandle(fileInfo.FullName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
var targetFileInfo = FileSystemHelper.ResolveLinkTarget(fileInfo, returnFinalTarget: true);
if (targetFileInfo is not null)
{
result.Length = RandomAccess.GetLength(fileHandle);
result.Exists = targetFileInfo.Exists;
if (result.Exists)
{
result.Length = targetFileInfo.Length;
result.CreationTimeUtc = GetCreationTimeUtc(targetFileInfo);
result.LastWriteTimeUtc = GetLastWriteTimeUtc(targetFileInfo);
}
}
else
{
result.Exists = false;
}
}
catch (FileNotFoundException ex)
{
// Dangling symlinks cannot be detected before opening the file unfortunately...
_logger.LogError(ex, "Reading the file size of the symlink at {Path} failed. Marking the file as not existing.", fileInfo.FullName);
result.Exists = false;
}
catch (UnauthorizedAccessException ex)
{
_logger.LogError(ex, "Reading the file at {Path} failed due to a permissions exception.", fileInfo.FullName);
}
catch (IOException ex)
{
// IOException generally means the file is not accessible due to filesystem issues
// Catch this exception and mark the file as not exist to ignore it
_logger.LogError(ex, "Reading the file at {Path} failed due to an IO Exception. Marking the file as not existing", fileInfo.FullName);
result.Exists = false;
}
}
else
{
result.Length = fileInfo.Length;
}
}
result.CreationTimeUtc = GetCreationTimeUtc(info);
result.LastWriteTimeUtc = GetLastWriteTimeUtc(info);
}
else
{

View File

@@ -37,6 +37,11 @@ namespace Emby.Server.Implementations.Library
return false;
}
if (IgnorePatterns.ShouldIgnore(fileInfo.FullName))
{
return true;
}
// Don't ignore top level folders
if (fileInfo.IsDirectory
&& (parent is AggregateFolder || (parent?.IsTopParent ?? false)))
@@ -44,11 +49,6 @@ namespace Emby.Server.Implementations.Library
return false;
}
if (IgnorePatterns.ShouldIgnore(fileInfo.FullName))
{
return true;
}
if (parent is null)
{
return false;

View File

@@ -1,6 +1,7 @@
using System;
using System.IO;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.IO;
using MediaBrowser.Controller.Resolvers;
using MediaBrowser.Model.IO;
@@ -11,28 +12,24 @@ namespace Emby.Server.Implementations.Library;
/// </summary>
public class DotIgnoreIgnoreRule : IResolverIgnoreRule
{
private static readonly bool IsWindows = OperatingSystem.IsWindows();
private static FileInfo? FindIgnoreFile(DirectoryInfo directory)
{
var ignoreFile = new FileInfo(Path.Join(directory.FullName, ".ignore"));
if (ignoreFile.Exists)
for (var current = directory; current is not null; current = current.Parent)
{
return ignoreFile;
var ignorePath = Path.Join(current.FullName, ".ignore");
if (File.Exists(ignorePath))
{
return new FileInfo(ignorePath);
}
}
var parentDir = directory.Parent;
if (parentDir is null)
{
return null;
}
return FindIgnoreFile(parentDir);
return null;
}
/// <inheritdoc />
public bool ShouldIgnore(FileSystemMetadata fileInfo, BaseItem? parent)
{
return IsIgnored(fileInfo, parent);
}
public bool ShouldIgnore(FileSystemMetadata fileInfo, BaseItem? parent) => IsIgnored(fileInfo, parent);
/// <summary>
/// Checks whether or not the file is ignored.
@@ -42,53 +39,58 @@ public class DotIgnoreIgnoreRule : IResolverIgnoreRule
/// <returns>True if the file should be ignored.</returns>
public static bool IsIgnored(FileSystemMetadata fileInfo, BaseItem? parent)
{
if (fileInfo.IsDirectory)
{
var dirIgnoreFile = FindIgnoreFile(new DirectoryInfo(fileInfo.FullName));
if (dirIgnoreFile is null)
{
return false;
}
var searchDirectory = fileInfo.IsDirectory
? new DirectoryInfo(fileInfo.FullName)
: new DirectoryInfo(Path.GetDirectoryName(fileInfo.FullName) ?? string.Empty);
// ignore the directory only if the .ignore file is empty
// evaluate individual files otherwise
return string.IsNullOrWhiteSpace(GetFileContent(dirIgnoreFile));
}
var parentDirPath = Path.GetDirectoryName(fileInfo.FullName);
if (string.IsNullOrEmpty(parentDirPath))
if (string.IsNullOrEmpty(searchDirectory.FullName))
{
return false;
}
var folder = new DirectoryInfo(parentDirPath);
var ignoreFile = FindIgnoreFile(folder);
var ignoreFile = FindIgnoreFile(searchDirectory);
if (ignoreFile is null)
{
return false;
}
string ignoreFileString = GetFileContent(ignoreFile);
if (string.IsNullOrWhiteSpace(ignoreFileString))
// Fast path in case the ignore files isn't a symlink and is empty
if (ignoreFile.LinkTarget is null && ignoreFile.Length == 0)
{
// Ignore directory if we just have the file
return true;
}
// If file has content, base ignoring off the content .gitignore-style rules
var ignoreRules = ignoreFileString.Split('\n', StringSplitOptions.RemoveEmptyEntries);
var ignore = new Ignore.Ignore();
ignore.Add(ignoreRules);
return ignore.IsIgnored(fileInfo.FullName);
var content = GetFileContent(ignoreFile);
return string.IsNullOrWhiteSpace(content)
|| CheckIgnoreRules(fileInfo.FullName, content, fileInfo.IsDirectory);
}
private static string GetFileContent(FileInfo dirIgnoreFile)
private static bool CheckIgnoreRules(string path, string ignoreFileContent, bool isDirectory)
{
using (var reader = dirIgnoreFile.OpenText())
// If file has content, base ignoring off the content .gitignore-style rules
var rules = ignoreFileContent.Split('\n', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
var ignore = new Ignore.Ignore();
ignore.Add(rules);
// Mitigate the problem of the Ignore library not handling Windows paths correctly.
// See https://github.com/jellyfin/jellyfin/issues/15484
var pathToCheck = IsWindows ? path.NormalizePath('/') : path;
// Add trailing slash for directories to match "folder/"
if (isDirectory)
{
return reader.ReadToEnd();
pathToCheck = string.Concat(pathToCheck.AsSpan().TrimEnd('/'), "/");
}
return ignore.IsIgnored(pathToCheck);
}
private static string GetFileContent(FileInfo ignoreFile)
{
ignoreFile = FileSystemHelper.ResolveLinkTarget(ignoreFile, returnFinalTarget: true) ?? ignoreFile;
return ignoreFile.Exists
? File.ReadAllText(ignoreFile.FullName)
: string.Empty;
}
}

View File

@@ -3,6 +3,7 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Controller.Chapters;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.IO;
using MediaBrowser.Controller.MediaSegments;
@@ -20,6 +21,7 @@ public class ExternalDataManager : IExternalDataManager
private readonly IMediaSegmentManager _mediaSegmentManager;
private readonly IPathManager _pathManager;
private readonly ITrickplayManager _trickplayManager;
private readonly IChapterManager _chapterManager;
private readonly ILogger<ExternalDataManager> _logger;
/// <summary>
@@ -29,18 +31,21 @@ public class ExternalDataManager : IExternalDataManager
/// <param name="mediaSegmentManager">The media segment manager.</param>
/// <param name="pathManager">The path manager.</param>
/// <param name="trickplayManager">The trickplay manager.</param>
/// <param name="chapterManager">The chapter manager.</param>
/// <param name="logger">The logger.</param>
public ExternalDataManager(
IKeyframeManager keyframeManager,
IMediaSegmentManager mediaSegmentManager,
IPathManager pathManager,
ITrickplayManager trickplayManager,
IChapterManager chapterManager,
ILogger<ExternalDataManager> logger)
{
_keyframeManager = keyframeManager;
_mediaSegmentManager = mediaSegmentManager;
_pathManager = pathManager;
_trickplayManager = trickplayManager;
_chapterManager = chapterManager;
_logger = logger;
}
@@ -67,5 +72,6 @@ public class ExternalDataManager : IExternalDataManager
await _keyframeManager.DeleteKeyframeDataAsync(itemId, cancellationToken).ConfigureAwait(false);
await _mediaSegmentManager.DeleteSegmentsAsync(itemId, cancellationToken).ConfigureAwait(false);
await _trickplayManager.DeleteTrickplayDataAsync(itemId, cancellationToken).ConfigureAwait(false);
await _chapterManager.DeleteChapterDataAsync(itemId, cancellationToken).ConfigureAwait(false);
}
}

View File

@@ -48,6 +48,8 @@ namespace Emby.Server.Implementations.Library
"**/.wd_tv",
"**/lost+found/**",
"**/lost+found",
"**/subs/**",
"**/subs",
// Trickplay files
"**/*.trickplay",

View File

@@ -327,6 +327,45 @@ namespace Emby.Server.Implementations.Library
DeleteItem(item, options, parent, notifyParentItem);
}
public void DeleteItemsUnsafeFast(IEnumerable<BaseItem> items)
{
var pathMaps = items.Select(e => (Item: e, InternalPath: GetInternalMetadataPaths(e), DeletePaths: e.GetDeletePaths())).ToArray();
foreach (var (item, internalPaths, pathsToDelete) in pathMaps)
{
foreach (var metadataPath in internalPaths)
{
if (!Directory.Exists(metadataPath))
{
continue;
}
_logger.LogDebug(
"Deleting metadata path, Type: {Type}, Name: {Name}, Path: {Path}, Id: {Id}",
item.GetType().Name,
item.Name ?? "Unknown name",
metadataPath,
item.Id);
try
{
Directory.Delete(metadataPath, true);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error deleting {MetadataPath}", metadataPath);
}
}
foreach (var fileSystemInfo in pathsToDelete)
{
DeleteItemPath(item, false, fileSystemInfo);
}
}
_itemRepository.DeleteItem([.. pathMaps.Select(f => f.Item.Id)]);
}
public void DeleteItem(BaseItem item, DeleteOptions options, BaseItem parent, bool notifyParentItem)
{
ArgumentNullException.ThrowIfNull(item);
@@ -403,59 +442,7 @@ namespace Emby.Server.Implementations.Library
foreach (var fileSystemInfo in item.GetDeletePaths())
{
if (Directory.Exists(fileSystemInfo.FullName) || File.Exists(fileSystemInfo.FullName))
{
try
{
_logger.LogInformation(
"Deleting item path, Type: {Type}, Name: {Name}, Path: {Path}, Id: {Id}",
item.GetType().Name,
item.Name ?? "Unknown name",
fileSystemInfo.FullName,
item.Id);
if (fileSystemInfo.IsDirectory)
{
Directory.Delete(fileSystemInfo.FullName, true);
}
else
{
File.Delete(fileSystemInfo.FullName);
}
}
catch (DirectoryNotFoundException)
{
_logger.LogInformation(
"Directory not found, only removing from database, Type: {Type}, Name: {Name}, Path: {Path}, Id: {Id}",
item.GetType().Name,
item.Name ?? "Unknown name",
fileSystemInfo.FullName,
item.Id);
}
catch (FileNotFoundException)
{
_logger.LogInformation(
"File not found, only removing from database, Type: {Type}, Name: {Name}, Path: {Path}, Id: {Id}",
item.GetType().Name,
item.Name ?? "Unknown name",
fileSystemInfo.FullName,
item.Id);
}
catch (IOException)
{
if (isRequiredForDelete)
{
throw;
}
}
catch (UnauthorizedAccessException)
{
if (isRequiredForDelete)
{
throw;
}
}
}
DeleteItemPath(item, isRequiredForDelete, fileSystemInfo);
isRequiredForDelete = false;
}
@@ -463,17 +450,79 @@ namespace Emby.Server.Implementations.Library
item.SetParent(null);
_itemRepository.DeleteItem(item.Id);
_itemRepository.DeleteItem([item.Id, .. children.Select(f => f.Id)]);
_cache.TryRemove(item.Id, out _);
foreach (var child in children)
{
_itemRepository.DeleteItem(child.Id);
_cache.TryRemove(child.Id, out _);
}
if (parent is Folder folder)
{
folder.Children = null;
folder.UserData = null;
}
ReportItemRemoved(item, parent);
}
private void DeleteItemPath(BaseItem item, bool isRequiredForDelete, FileSystemMetadata fileSystemInfo)
{
if (Directory.Exists(fileSystemInfo.FullName) || File.Exists(fileSystemInfo.FullName))
{
try
{
_logger.LogInformation(
"Deleting item path, Type: {Type}, Name: {Name}, Path: {Path}, Id: {Id}",
item.GetType().Name,
item.Name ?? "Unknown name",
fileSystemInfo.FullName,
item.Id);
if (fileSystemInfo.IsDirectory)
{
Directory.Delete(fileSystemInfo.FullName, true);
}
else
{
File.Delete(fileSystemInfo.FullName);
}
}
catch (DirectoryNotFoundException)
{
_logger.LogInformation(
"Directory not found, only removing from database, Type: {Type}, Name: {Name}, Path: {Path}, Id: {Id}",
item.GetType().Name,
item.Name ?? "Unknown name",
fileSystemInfo.FullName,
item.Id);
}
catch (FileNotFoundException)
{
_logger.LogInformation(
"File not found, only removing from database, Type: {Type}, Name: {Name}, Path: {Path}, Id: {Id}",
item.GetType().Name,
item.Name ?? "Unknown name",
fileSystemInfo.FullName,
item.Id);
}
catch (IOException)
{
if (isRequiredForDelete)
{
throw;
}
}
catch (UnauthorizedAccessException)
{
if (isRequiredForDelete)
{
throw;
}
}
}
}
private bool IsInternalItem(BaseItem item)
{
if (!item.IsFileProtocol)
@@ -485,7 +534,7 @@ namespace Emby.Server.Implementations.Library
{
Genre => _configurationManager.ApplicationPaths.GenrePath,
MusicArtist => _configurationManager.ApplicationPaths.ArtistsPath,
MusicGenre => _configurationManager.ApplicationPaths.GenrePath,
MusicGenre => _configurationManager.ApplicationPaths.MusicGenrePath,
Person => _configurationManager.ApplicationPaths.PeoplePath,
Studio => _configurationManager.ApplicationPaths.StudioPath,
Year => _configurationManager.ApplicationPaths.YearPath,
@@ -826,6 +875,7 @@ namespace Emby.Server.Implementations.Library
if (!folder.ParentId.Equals(rootFolder.Id))
{
rootFolder.UpdateToRepositoryAsync(ItemUpdateType.MetadataImport, CancellationToken.None).GetAwaiter().GetResult();
folder.ParentId = rootFolder.Id;
folder.UpdateToRepositoryAsync(ItemUpdateType.MetadataImport, CancellationToken.None).GetAwaiter().GetResult();
}
@@ -989,6 +1039,11 @@ namespace Emby.Server.Implementations.Library
return GetArtist(name, new DtoOptions(true));
}
public IReadOnlyDictionary<string, MusicArtist[]> GetArtists(IReadOnlyList<string> names)
{
return _itemRepository.FindArtists(names);
}
public MusicArtist GetArtist(string name, DtoOptions options)
{
return CreateItemByName<MusicArtist>(MusicArtist.GetPath, name, options);
@@ -1090,6 +1145,7 @@ namespace Emby.Server.Implementations.Library
public async Task ValidateTopLibraryFolders(CancellationToken cancellationToken, bool removeRoot = false)
{
RootFolder.Children = null;
await RootFolder.RefreshMetadata(cancellationToken).ConfigureAwait(false);
// Start by just validating the children of the root, but go no further
@@ -1100,9 +1156,12 @@ namespace Emby.Server.Implementations.Library
allowRemoveRoot: removeRoot,
cancellationToken: cancellationToken).ConfigureAwait(false);
await GetUserRootFolder().RefreshMetadata(cancellationToken).ConfigureAwait(false);
var rootFolder = GetUserRootFolder();
rootFolder.Children = null;
await GetUserRootFolder().ValidateChildren(
await rootFolder.RefreshMetadata(cancellationToken).ConfigureAwait(false);
await rootFolder.ValidateChildren(
new Progress<double>(),
new MetadataRefreshOptions(new DirectoryService(_fileSystem)),
recursive: false,
@@ -1110,18 +1169,24 @@ namespace Emby.Server.Implementations.Library
cancellationToken: cancellationToken).ConfigureAwait(false);
// Quickly scan CollectionFolders for changes
foreach (var child in GetUserRootFolder().Children.OfType<Folder>())
var toDelete = new List<Guid>();
foreach (var child in rootFolder.Children!.OfType<Folder>())
{
// If the user has somehow deleted the collection directory, remove the metadata from the database.
if (child is CollectionFolder collectionFolder && !Directory.Exists(collectionFolder.Path))
{
_itemRepository.DeleteItem(collectionFolder.Id);
toDelete.Add(collectionFolder.Id);
}
else
{
await child.RefreshMetadata(cancellationToken).ConfigureAwait(false);
}
}
if (toDelete.Count > 0)
{
_itemRepository.DeleteItem(toDelete.ToArray());
}
}
private async Task PerformLibraryValidation(IProgress<double> progress, CancellationToken cancellationToken)
@@ -1934,6 +1999,12 @@ namespace Emby.Server.Implementations.Library
RegisterItem(item);
}
if (parent is Folder folder)
{
folder.Children = null;
folder.UserData = null;
}
if (ItemAdded is not null)
{
foreach (var item in items)
@@ -2027,6 +2098,12 @@ namespace Emby.Server.Implementations.Library
}
}
if (!File.Exists(image.Path))
{
_logger.LogWarning("Image not found at {ImagePath}", image.Path);
continue;
}
ImageDimensions size;
try
{
@@ -2064,6 +2141,8 @@ namespace Emby.Server.Implementations.Library
}
}
item.ValidateImages();
_itemRepository.SaveImages(item);
RegisterItem(item);
@@ -2083,6 +2162,12 @@ namespace Emby.Server.Implementations.Library
_itemRepository.SaveItems(items, cancellationToken);
if (parent is Folder folder)
{
folder.Children = null;
folder.UserData = null;
}
if (ItemUpdated is not null)
{
foreach (var item in items)
@@ -2986,10 +3071,10 @@ namespace Emby.Server.Implementations.Library
}
finally
{
await ValidateTopLibraryFolders(CancellationToken.None).ConfigureAwait(false);
if (refreshLibrary)
{
await ValidateTopLibraryFolders(CancellationToken.None).ConfigureAwait(false);
StartScanInBackground();
}
else

View File

@@ -226,6 +226,11 @@ namespace Emby.Server.Implementations.Library
/// <inheritdoc />>
public MediaProtocol GetPathProtocol(string path)
{
if (string.IsNullOrEmpty(path))
{
return MediaProtocol.File;
}
if (path.StartsWith("Rtsp", StringComparison.OrdinalIgnoreCase))
{
return MediaProtocol.Rtsp;
@@ -657,7 +662,7 @@ namespace Emby.Server.Implementations.Library
}
catch (Exception ex)
{
_logger.LogDebug(ex, "_jsonSerializer.DeserializeFromFile threw an exception.");
_logger.LogDebug(ex, "Error parsing cached media info.");
}
finally
{

View File

@@ -28,7 +28,9 @@ namespace Emby.Server.Implementations.Library
public IReadOnlyList<BaseItem> GetInstantMixFromSong(Audio item, User? user, DtoOptions dtoOptions)
{
return GetInstantMixFromGenres(item.Genres, user, dtoOptions);
var instantMixItems = GetInstantMixFromGenres(item.Genres, user, dtoOptions);
return [item, .. instantMixItems.Where(i => !i.Id.Equals(item.Id))];
}
/// <inheritdoc />
@@ -45,11 +47,14 @@ namespace Emby.Server.Implementations.Library
public IReadOnlyList<BaseItem> GetInstantMixFromFolder(Folder item, User? user, DtoOptions dtoOptions)
{
var genres = item
.GetRecursiveChildren(user, new InternalItemsQuery(user)
{
IncludeItemTypes = [BaseItemKind.Audio],
DtoOptions = dtoOptions
})
.GetRecursiveChildren(
user,
new InternalItemsQuery(user)
{
IncludeItemTypes = [BaseItemKind.Audio],
DtoOptions = dtoOptions
},
out _)
.Cast<Audio>()
.SelectMany(i => i.Genres)
.Concat(item.Genres)

View File

@@ -369,13 +369,16 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
// We need to only look at the name of this actual item (not parents)
var justName = item.IsInMixedFolder ? Path.GetFileName(item.Path.AsSpan()) : Path.GetFileName(item.ContainingFolderPath.AsSpan());
if (!justName.IsEmpty)
var tmdbid = justName.GetAttributeValue("tmdbid");
// If not in a mixed folder and ID not found in folder path, check filename
if (string.IsNullOrEmpty(tmdbid) && !item.IsInMixedFolder)
{
// Check for TMDb id
var tmdbid = justName.GetAttributeValue("tmdbid");
item.TrySetProviderId(MetadataProvider.Tmdb, tmdbid);
tmdbid = Path.GetFileName(item.Path.AsSpan()).GetAttributeValue("tmdbid");
}
item.TrySetProviderId(MetadataProvider.Tmdb, tmdbid);
if (!string.IsNullOrEmpty(item.Path))
{
// Check for IMDb id - we use full media path, as we can assume that this will match in any use case (whether id in parent dir or in file name)
@@ -405,6 +408,11 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
if (child.IsDirectory)
{
if (NamingOptions.AllExtrasTypesFolderNames.ContainsKey(filename))
{
continue;
}
if (IsDvdDirectory(child.FullName, filename, directoryService))
{
var movie = new T

View File

@@ -80,6 +80,7 @@ namespace Emby.Server.Implementations.Library
var userId = user.InternalId;
var cacheKey = GetCacheKey(userId, item.Id);
_cache.AddOrUpdate(cacheKey, userData);
item.UserData = dbContext.UserData.Where(e => e.ItemId == item.Id).AsNoTracking().ToArray(); // rehydrate the cached userdata
UserDataSaved?.Invoke(this, new UserDataSaveEventArgs
{
@@ -159,7 +160,7 @@ namespace Emby.Server.Implementations.Library
};
}
private UserItemData Map(UserData dto)
private static UserItemData Map(UserData dto)
{
return new UserItemData()
{
@@ -237,7 +238,10 @@ namespace Emby.Server.Implementations.Library
/// <inheritdoc />
public UserItemData? GetUserData(User user, BaseItem item)
{
return GetUserData(user, item.Id, item.GetUserDataKeys());
return item.UserData?.Where(e => e.UserId.Equals(user.Id)).Select(Map).FirstOrDefault() ?? new UserItemData()
{
Key = item.GetUserDataKeys()[0],
};
}
/// <inheritdoc />
@@ -304,7 +308,7 @@ namespace Emby.Server.Implementations.Library
// ignore progress during the beginning
positionTicks = 0;
}
else if (pctIn > _config.Configuration.MaxResumePct || positionTicks >= runtimeTicks)
else if (pctIn > _config.Configuration.MaxResumePct || positionTicks >= (runtimeTicks - TimeSpan.TicksPerSecond))
{
// mark as completed close to the end
positionTicks = 0;

View File

@@ -374,13 +374,22 @@ namespace Emby.Server.Implementations.Library
if (request.GroupItems)
{
if (parents.OfType<ICollectionFolder>().All(i => i.CollectionType == CollectionType.tvshows))
var collectionType = parents
.Select(parent => parent switch
{
ICollectionFolder collectionFolder => collectionFolder.CollectionType,
UserView userView => userView.CollectionType,
_ => null
})
.FirstOrDefault(type => type is not null);
if (collectionType == CollectionType.tvshows)
{
query.Limit = limit;
return _libraryManager.GetLatestItemList(query, parents, CollectionType.tvshows);
}
if (parents.OfType<ICollectionFolder>().All(i => i.CollectionType == CollectionType.music))
if (collectionType == CollectionType.music)
{
query.Limit = limit;
return _libraryManager.GetLatestItemList(query, parents, CollectionType.music);

View File

@@ -1,5 +1,5 @@
using System;
using System.Globalization;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Jellyfin.Data.Enums;
@@ -55,6 +55,8 @@ public class PeopleValidator
var numPeople = people.Count;
IProgress<double> subProgress = new Progress<double>((val) => progress.Report(val / 2));
_logger.LogDebug("Will refresh {Amount} people", numPeople);
foreach (var person in people)
@@ -92,7 +94,7 @@ public class PeopleValidator
double percent = numComplete;
percent /= numPeople;
progress.Report(100 * percent);
subProgress.Report(100 * percent);
}
var deadEntities = _libraryManager.GetItemList(new InternalItemsQuery
@@ -102,17 +104,13 @@ public class PeopleValidator
IsLocked = false
});
foreach (var item in deadEntities)
{
_logger.LogInformation("Deleting dead {ItemType} {ItemId} {ItemName}", item.GetType().Name, item.Id.ToString("N", CultureInfo.InvariantCulture), item.Name);
subProgress = new Progress<double>((val) => progress.Report((val / 2) + 50));
_libraryManager.DeleteItem(
item,
new DeleteOptions
{
DeleteFileLocation = false
},
false);
var i = 0;
foreach (var item in deadEntities.Chunk(500))
{
_libraryManager.DeleteItemsUnsafeFast(item);
subProgress.Report(100f / deadEntities.Count * (i++ * 100));
}
progress.Report(100);

View File

@@ -16,7 +16,7 @@
"Folders": "المجلدات",
"Genres": "التصنيفات",
"HeaderAlbumArtists": "فناني الألبوم",
"HeaderContinueWatching": "إستئناف المشاهدة",
"HeaderContinueWatching": "أكمل المشاهدة",
"HeaderFavoriteAlbums": "الألبومات المفضلة",
"HeaderFavoriteArtists": "الفنانون المفضلون",
"HeaderFavoriteEpisodes": "الحلقات المفضلة",

View File

@@ -1,16 +1,16 @@
{
"Sync": "Сінхранізаваць",
"Playlists": "Спісы прайгравання",
"Latest": "Апошні",
"Playlists": "Плэй-лісты",
"Latest": "Апошняе",
"LabelIpAddressValue": "IP-адрас: {0}",
"ItemAddedWithName": "{0} быў дададзены ў бібліятэку",
"ItemAddedWithName": "{0} даданы ў бібліятэку",
"MessageApplicationUpdated": "Сервер Jellyfin абноўлены",
"NotificationOptionApplicationUpdateInstalled": "Абнаўленне прыкладання ўсталявана",
"NotificationOptionApplicationUpdateInstalled": "Абнаўленне праграмы ўсталявана",
"PluginInstalledWithName": "{0} быў усталяваны",
"UserCreatedWithName": "Карыстальнік {0} быў створаны",
"Albums": "Альбомы",
"Application": "Прыкладанне",
"AuthenticationSucceededWithUserName": "{0} паспяхова аўтэнтыфікаваны",
"Application": "Праграма",
"AuthenticationSucceededWithUserName": "{0} паспяхова аўтарызаваны",
"Channels": "Каналы",
"ChapterNameValue": "Раздзел {0}",
"Collections": "Калекцыі",
@@ -29,18 +29,18 @@
"HeaderAlbumArtists": "Выканаўцы альбома",
"LabelRunningTimeValue": "Працягласць: {0}",
"HomeVideos": "Хатнія відэа",
"ItemRemovedWithName": "{0} быў выдалены з бібліятэкі",
"MessageApplicationUpdatedTo": "Сервер Jellyfin абноўлены да {0}",
"ItemRemovedWithName": "{0} выдалены з бібліятэкі",
"MessageApplicationUpdatedTo": "Сервер Jellyfin абноўлены да версіі {0}",
"Movies": "Фільмы",
"Music": "Музыка",
"MusicVideos": "Музычныя кліпы",
"NameInstallFailed": "Устаноўка {0} не атрымалася",
"NameInstallFailed": "Усталяванне {0} не атрымалася",
"NameSeasonNumber": "Сезон {0}",
"NotificationOptionApplicationUpdateAvailable": "Даступна абнаўленне прыкладання",
"NotificationOptionApplicationUpdateAvailable": "Даступна абнаўленне праграмы",
"NotificationOptionPluginInstalled": "Плагін усталяваны",
"NotificationOptionPluginUpdateInstalled": "Абнаўленне плагіна усталявана",
"NotificationOptionPluginUpdateInstalled": "Абнаўленне плагіна ўсталявана",
"NotificationOptionServerRestartRequired": "Патрабуецца перазапуск сервера",
"Photos": атаграфіі",
"Photos": отаздымкі",
"Plugin": "Плагін",
"PluginUninstalledWithName": "{0} быў выдалены",
"PluginUpdatedWithName": "{0} быў абноўлены",
@@ -54,16 +54,16 @@
"Artists": "Выканаўцы",
"UserOfflineFromDevice": "{0} адлучыўся ад {1}",
"UserPolicyUpdatedWithName": "Палітыка карыстальніка абноўлена для {0}",
"TaskCleanActivityLogDescription": "Выдаляе старэйшыя за зададзены ўзрост запісы ў журнале актыўнасці.",
"TaskCleanActivityLogDescription": "Выдаляе запісы старэйшыя за зададзены ўзрост ў журнале актыўнасці.",
"TaskRefreshChapterImagesDescription": "Стварае мініяцюры для відэа, якія маюць раздзелы.",
"TaskCleanLogsDescription": "Выдаляе файлы журналу, якім больш за {0} дзён.",
"TaskUpdatePluginsDescription": "Спампоўвае і ўсталёўвае абнаўленні для плагінаў, якія настроены на аўтаматычнае абнаўленне.",
"TaskUpdatePluginsDescription": "Спампоўвае і ўсталёўвае абнаўленні для плагінаў, якія сканфігураваныя на аўтаматычнае абнаўленне.",
"TaskRefreshChannelsDescription": "Абнаўляе інфармацыю аб інтэрнэт-канале.",
"TaskDownloadMissingSubtitlesDescription": "Шукае ў інтэрнэце адсутныя субтытры на аснове канфігурацыі метададзеных.",
"TaskOptimizeDatabaseDescription": "Ушчыльняе базу дадзеных і скарачае вольную прастору. Выкананне гэтай задачы пасля сканавання бібліятэкі або ўнясення іншых змяненняў, якія прадугледжваюць мадыфікацыю базы дадзеных, можа палепшыць прадукцыйнасць.",
"TaskDownloadMissingSubtitlesDescription": "Шукае ў інтэрнэце адсутныя субцітры на аснове канфігурацыі метададзеных.",
"TaskOptimizeDatabaseDescription": "Ушчыльняе базу дадзеных і скарачае вольную прастору. Выкананне гэтай задачы пасля сканавання бібліятэкі або ўнясення іншых зменаў, якія прадугледжваюць мадыфікацыю базы дадзеных, можа палепшыць выдайнасць.",
"TaskKeyframeExtractor": "Экстрактар ключавых кадраў",
"TasksApplicationCategory": "Прыкладанне",
"AppDeviceValues": "Прыкладанне: {0}, Прылада: {1}",
"TasksApplicationCategory": "Праграма",
"AppDeviceValues": "Праграма: {0}, Прылада: {1}",
"Books": "Кнігі",
"CameraImageUploadedFrom": "Новая выява камеры была загружана з {0}",
"DeviceOfflineWithName": "{0} адлучыўся",
@@ -74,7 +74,7 @@
"HeaderFavoriteArtists": "Абраныя выканаўцы",
"HearingImpaired": "Са слабым слыхам",
"Inherit": "Атрымаць у спадчыну",
"MessageNamedServerConfigurationUpdatedWithValue": "Канфігурацыя сервера {0} абноўлена",
"MessageNamedServerConfigurationUpdatedWithValue": "Канфігурацыя сервера (секцыя {0}) абноўлена",
"MessageServerConfigurationUpdated": "Канфігурацыя сервера абноўлена",
"MixedContent": "Змешаны змест",
"NameSeasonUnknown": "Невядомы сезон",
@@ -92,48 +92,48 @@
"NotificationOptionVideoPlaybackStopped": "Прайграванне відэа спынена",
"ScheduledTaskFailedWithName": "{0} не атрымалася",
"ScheduledTaskStartedWithName": "{0} пачалося",
"ServerNameNeedsToBeRestarted": "{0} трэба перазапусціць",
"ServerNameNeedsToBeRestarted": "{0} патрабуе перазапуску",
"Shows": "Шоу",
"StartupEmbyServerIsLoading": "Jellyfin Server загружаецца. Калі ласка, паўтарыце спробу крыху пазней.",
"SubtitleDownloadFailureFromForItem": "Не атрымалася спампаваць субтытры з {0} для {1}",
"TvShows": "ТБ-шоу",
"TvShows": "Тэлепраграма",
"Undefined": "Нявызначана",
"UserLockedOutWithName": "Карыстальнік {0} быў заблакіраваны",
"UserOnlineFromDevice": "{0} падключаны з {1}",
"UserPasswordChangedWithName": "Пароль быў зменены для карыстальніка {0}",
"UserStartedPlayingItemWithValues": "{0} грае {1} на {2}",
"UserStartedPlayingItemWithValues": "{0} прайграваецца {1} на {2}",
"UserStoppedPlayingItemWithValues": "{0} скончыў прайграванне {1} на {2}",
"ValueHasBeenAddedToLibrary": "{0} быў дададзены ў вашу медыятэку",
"ValueSpecialEpisodeName": "Спецэпізод - {0}",
"VersionNumber": "Версія {0}",
"TasksMaintenanceCategory": "Абслугоўванне",
"TasksLibraryCategory": "Медыятэка",
"TasksLibraryCategory": "Бібліятэка",
"TasksChannelsCategory": "Інтэрнэт-каналы",
"TaskCleanActivityLog": "Ачысціць журнал актыўнасці",
"TaskCleanCache": "Ачысціць кэш",
"TaskCleanCacheDescription": "Выдаляе файлы кэша, якія больш не патрэбныя сістэме.",
"TaskRefreshChapterImages": "Выняць выявы раздзелаў",
"TaskRefreshLibrary": "Сканіраваць медыятэку",
"TaskRefreshLibraryDescription": "Сканіруе вашу медыятэку на наяўнасць новых файлаў і абнаўляе метададзеныя.",
"TaskCleanLogs": "Ачысціць часопіс",
"TaskRefreshPeople": "Абнавіць людзей",
"TaskRefreshChapterImages": "Вынуць выявы раздзелаў",
"TaskRefreshLibrary": "Сканаваць бібліятэку",
"TaskRefreshLibraryDescription": "Скануе вашу медыятэку на наяўнасць новых файлаў і абнаўляе метададзеныя.",
"TaskCleanLogs": "Ачысціць журнал",
"TaskRefreshPeople": "Абнавіць выканаўцаў",
"TaskRefreshPeopleDescription": "Абнаўленне метаданых для акцёраў і рэжысёраў у вашай медыятэцы.",
"TaskUpdatePlugins": "Абнавіць плагіны",
"TaskCleanTranscode": "Ачысціць каталог перакадзіравання",
"TaskCleanTranscodeDescription": "Выдаляе перакадзіраваныя файлы, старэйшыя за адзін дзень.",
"TaskRefreshChannels": "Абнавіць каналы",
"TaskDownloadMissingSubtitles": "Спампаваць адсутныя субтытры",
"TaskKeyframeExtractorDescription": "Выдае ключавыя кадры з відэафайлаў для стварэння больш дакладных спісаў прайгравання HLS. Гэта задача можа працаваць у працягу доўгага часу.",
"TaskRefreshTrickplayImages": "Стварыце выявы Trickplay",
"TaskRefreshTrickplayImagesDescription": "Стварае прагляд відэаролікаў для Trickplay у падключаных бібліятэках.",
"TaskCleanCollectionsAndPlaylists": "Ачысціце калекцыі і спісы прайгравання",
"TaskCleanCollectionsAndPlaylistsDescription": "Выдаляе элементы з калекцый і спісаў прайгравання, якія больш не існуюць.",
"TaskAudioNormalizationDescription": "Сканіруе файлы на прадмет нармалізацыі гуку.",
"TaskDownloadMissingSubtitles": "Спампаваць адсутныя субцітры",
"TaskKeyframeExtractorDescription": "Выдае ключавыя кадры з відэафайлаў для стварэння больш дакладных плэй-лістоў HLS. Гэта задача можа працягнуцца шмат часу.",
"TaskRefreshTrickplayImages": "Стварыць выявы Trickplay",
"TaskRefreshTrickplayImagesDescription": "Стварае перадпрагляды відэаролікаў для Trickplay у падключаных бібліятэках.",
"TaskCleanCollectionsAndPlaylists": "Ачысціце калекцыі і плэй-лісты",
"TaskCleanCollectionsAndPlaylistsDescription": "Выдаляе элементы з калекцый і плэй-лістоў, якія больш не існуюць.",
"TaskAudioNormalizationDescription": "Скануе файлы на прадмет нармалізацыі гуку.",
"TaskAudioNormalization": "Нармалізацыя гуку",
"TaskExtractMediaSegmentsDescription": "Выдае або атрымлівае медыясегменты з убудоў з падтрымкай MediaSegment.",
"TaskMoveTrickplayImagesDescription": "Перамяшчае існуючыя файлы trickplay у адпаведнасці з наладамі бібліятэкі.",
"TaskDownloadMissingLyrics": "Спампаваць зніклыя тэксты песень",
"TaskDownloadMissingLyricsDescription": "Спампоўвае тэксты для песень",
"TaskDownloadMissingLyrics": "Спампаваць адсутныя тэксты песняў",
"TaskDownloadMissingLyricsDescription": "Спампоўвае тэксты для песняў",
"TaskExtractMediaSegments": "Сканіраванне медыя-сегмента",
"TaskMoveTrickplayImages": "Перанесці месцазнаходжанне выявы Trickplay",
"CleanupUserDataTask": "Задача па ачыстцы дадзеных карыстальніка",

View File

@@ -15,7 +15,7 @@
"HeaderFavoriteAlbums": "প্রিয় এলবামগুলো",
"HeaderContinueWatching": "দেখতে থাকুন",
"HeaderAlbumArtists": "অ্যালবাম শিল্পীবৃন্দ",
"Genres": "জনরা",
"Genres": "ধরণ",
"Folders": "ফোল্ডারসমূহ",
"Favorites": "পছন্দসমূহ",
"FailedLoginAttemptWithUserName": "{0} লগিন করতে ব্যর্থ হয়েছে",
@@ -39,8 +39,8 @@
"Sync": "সমন্বয় করুন",
"SubtitleDownloadFailureFromForItem": "{0} থেকে {1} এর জন্য সাবটাইটেল ডাউনলোড ব্যর্থ হয়েছে",
"StartupEmbyServerIsLoading": "জেলিফিন সার্ভার লোড হচ্ছে। দয়া করে একটু পরে আবার চেষ্টা করুন।",
"Songs": "সঙ্গীতসমূহ",
"Shows": "টিভি পর্ব",
"Songs": "সঙ্গীত সমূহ",
"Shows": "শো সমূহ",
"ServerNameNeedsToBeRestarted": "{0} রিস্টার্ট করা প্রয়োজন",
"ScheduledTaskStartedWithName": "{0} শুরু হয়েছে",
"ScheduledTaskFailedWithName": "{0} ব্যর্থ",
@@ -51,9 +51,9 @@
"Plugin": "প্লাগিন",
"Playlists": "প্লে লিস্ট সমূহ",
"Photos": "ছবিসমূহ",
"NotificationOptionVideoPlaybackStopped": "ভিডিও বন্ধ হয়েছে",
"NotificationOptionVideoPlayback": "ভিডিও শুরু হেছে",
"NotificationOptionUserLockedOut": "ব্যবহারকারী ঢুকতে পারছে না",
"NotificationOptionVideoPlaybackStopped": "ভিডিও প্লেব্যাক বন্ধ হয়েছে",
"NotificationOptionVideoPlayback": "ভিডিও প্লেব্যাক শুরু হয়েছে",
"NotificationOptionUserLockedOut": "ব্যবহারকারী লক আউট হয়েছে",
"NotificationOptionTaskFailed": "পরিকল্পিত কাজটি ব্যর্থ",
"NotificationOptionServerRestartRequired": "সার্ভার রিস্টার্ট করা লাগবে",
"NotificationOptionPluginUpdateInstalled": "প্লাগিন আপডেট ইন্সটল হয়েছে",
@@ -85,7 +85,7 @@
"LabelIpAddressValue": "আইপি এড্রেস: {0}",
"ItemRemovedWithName": "{0} লাইব্রেরি থেকে বাদ দেয়া হয়েছে",
"ItemAddedWithName": "{0} লাইব্রেরিতে যোগ করা হয়েছে",
"Inherit": "মূল থেকে গ্রহণ করুন",
"Inherit": "উত্তরাধিকারসূত্র থেকে গ্রহণ করুন",
"HomeVideos": "হোম ভিডিও",
"HeaderNextUp": "এরপরে আসছে",
"HeaderLiveTV": "লাইভ টিভি",
@@ -126,16 +126,16 @@
"TaskKeyframeExtractorDescription": "ভিডিয়ো থেকে কি-ফ্রেম নিষ্কাশনের মাধ্যমে অধিকতর সঠিক HLS প্লে লিস্ট তৈরী করে। এই প্রক্রিয়া দীর্ঘ সময় ধরে চলতে পারে।",
"TaskRefreshTrickplayImages": "ট্রিকপ্লে ইমেজ তৈরি",
"TaskRefreshTrickplayImagesDescription": "সক্ষম লাইব্রেরিতে ভিডিওর জন্য ট্রিকপ্লে প্রিভিউ তৈরি করে।",
"TaskDownloadMissingLyricsDescription": "গানের লিরিকস ডাউনলোড কর",
"TaskDownloadMissingLyricsDescription": "গানের জন্য লিরিকস ডাউনলোড করুন",
"TaskCleanCollectionsAndPlaylists": "কালেকশন এবং প্লেলিস্ট পরিষ্কার করুন",
"TaskCleanCollectionsAndPlaylistsDescription": "কালেকশন এবং প্লেলিস্ট থেকে আইটেমগুলি সরিয়ে দেয় যা আর বিদ্যমান নেই।",
"TaskExtractMediaSegments": "মিডিয়া সেগমেন্ট স্ক্যান",
"TaskExtractMediaSegmentsDescription": "মিডিয়া সেগমেন্ট সক্রিয় প্লাগইনগুলি থেকে মিডিয়া সেগমেন্টগুলি বের করে বা প্রাপ্ত করে।",
"TaskExtractMediaSegmentsDescription": "মিডিয়া সেগমেন্ট সক্ষম প্লাগইনগুলি থেকে মিডিয়া সেগমেন্ট বের করে বা অর্জন করে।",
"TaskDownloadMissingLyrics": "অনুপস্থিত গান ডাউনলোড করুন",
"TaskMoveTrickplayImagesDescription": "লাইব্রেরির সেটিং অনুযায়ী বিদ্যমান ট্রিকপ্লে ফাইলগুলো সরিয়ে নেবে।",
"TaskAudioNormalizationDescription": "অডিও নর্মালাইজেশন তথ্যের জন্য ফাইল স্ক্যান করবে।",
"CleanupUserDataTaskDescription": "৯০ দিন বা তার বেশি সময় ধরে অনুপস্থিত মিডিয়া থেকে সকল ব্যবহারকারীর ডেটা (ওয়াচ স্টেট, ফেভারিট স্ট্যাটাস ইত্যাদি) মুছে ফেলবে।",
"TaskMoveTrickplayImages": "ট্রিকপ্লে ইমেজের অবস্থান পরিবর্তন",
"TaskAudioNormalization": "অডিও নর্মলাইজেশন",
"CleanupUserDataTask": "ব্যবহারকারীর ডেটা পরিষ্কারের কাজ"
"CleanupUserDataTask": "ইউজার ডেটা ক্লিনআপ কাজ"
}

View File

@@ -138,5 +138,5 @@
"TaskMoveTrickplayImages": "Verzeichnis für Trickplay-Bilder migrieren",
"TaskMoveTrickplayImagesDescription": "Trickplay-Bilder werden entsprechend der Bibliothekseinstellungen verschoben.",
"CleanupUserDataTask": "Aufgabe zur Bereinigung von Benutzerdaten",
"CleanupUserDataTaskDescription": "Löscht alle Benutzerdaten (Anschaustatus, Favoritenstatus, usw.) von Medien, die seit mindestens 90 Tagen nicht mehr vorhanden sind."
"CleanupUserDataTaskDescription": "Löscht alle Benutzerdaten (Abspielstatus, Favoritenstatus, usw.) von Medien, die seit mindestens 90 Tagen nicht mehr vorhanden sind."
}

View File

@@ -136,5 +136,7 @@
"TaskExtractMediaSegments": "Escanear Segmentos de Media",
"TaskExtractMediaSegmentsDescription": "Extrae u obtiene segmentos de medio de plugins habilitados para MediaSegment.",
"TaskMoveTrickplayImagesDescription": "Mueve archivos existentes de trickplay de acuerdo a la configuración de la biblioteca.",
"TaskMoveTrickplayImages": "Migrar Ubicación de Imagen de Trickplay"
"TaskMoveTrickplayImages": "Migrar Ubicación de Imagen de Trickplay",
"CleanupUserDataTaskDescription": "Limpia todos los datos del usuario (estado de visualización, estado de los favoritos, etc.) que no están presentes en la biblioteca por al menos 90 días.",
"CleanupUserDataTask": "Tarea de limpieza de datos de usuarios"
}

View File

@@ -30,7 +30,7 @@
"ItemAddedWithName": "{0} fue agregado a la biblioteca",
"ItemRemovedWithName": "{0} fue removido de la biblioteca",
"LabelIpAddressValue": "Dirección IP: {0}",
"LabelRunningTimeValue": "Tiempo de reproducción: {0}",
"LabelRunningTimeValue": "Tiempo corriendo: {0}",
"Latest": "Recientes",
"MessageApplicationUpdated": "El servidor Jellyfin ha sido actualizado",
"MessageApplicationUpdatedTo": "El servidor Jellyfin ha sido actualizado a {0}",
@@ -137,5 +137,6 @@
"TaskExtractMediaSegmentsDescription": "Extrae u obtiene segmentos de medios de plugins habilitados para MediaSegment.",
"TaskMoveTrickplayImages": "Migrar la ubicación de la imagen de Trickplay",
"TaskMoveTrickplayImagesDescription": "Mueve archivos de trickplay existentes según la configuración de la biblioteca.",
"CleanupUserDataTask": "Tarea de limpieza de los datos del usuario"
"CleanupUserDataTask": "Tarea de limpieza de los datos del usuario",
"CleanupUserDataTaskDescription": "Limpia toda la información de usuario (Estado de última vez visto, favoritos, etc) del archivo media que no está presente por los últimos 90 días."
}

View File

@@ -125,5 +125,11 @@
"Undefined": "Sin definir",
"TaskCleanActivityLogDescription": "Elimina las entradas del registro de actividad anteriores al periodo configurado.",
"TaskCleanCacheDescription": "Elimina archivos caché que ya no son necesarios para el sistema.",
"TaskCleanLogsDescription": "Elimina archivos de registro con más de {0} días de antigüedad."
"TaskCleanLogsDescription": "Elimina archivos de registro con más de {0} días de antigüedad.",
"NotificationOptionApplicationUpdateAvailable": "actualización disponible",
"TaskDownloadMissingLyrics": "Descargue letras desaparecidas",
"TaskDownloadMissingLyricsDescription": "Decarga letras para canciones",
"TaskMoveTrickplayImages": "Mover localización de foto vista previa",
"NotificationOptionApplicationUpdateInstalled": "Aplicación actualización disponible",
"CleanupUserDataTask": "Tarea de limpieza de los datos del usuario"
}

View File

@@ -1,14 +1,14 @@
{
"TaskCleanActivityLogDescription": "Kustutab määratud ajast vanemad tegevuslogi kirjed.",
"UserDownloadingItemWithValues": "{0} laeb alla {1}",
"UserDownloadingItemWithValues": "{0} laadib alla {1}",
"HeaderRecordingGroups": "Salvestusrühmad",
"TaskOptimizeDatabaseDescription": "Tihendab ja puhastab andmebaasi. Selle toimingu tegemine pärast meediakogu andmebaasiga seotud muudatuste skannimist võib jõudlust parandada.",
"TaskOptimizeDatabase": "Optimeeri andmebaasi",
"TaskDownloadMissingSubtitlesDescription": "Otsib veebist puuduvaid subtiitreid vastavalt määratud metaandmete seadetele.",
"TaskDownloadMissingSubtitles": "Laadi alla puuduvad subtiitrid",
"TaskDownloadMissingSubtitles": "Hangi puuduvad subtiitrid",
"TaskRefreshChannelsDescription": "Värskendab veebikanalite teavet.",
"TaskRefreshChannels": "Värskenda kanaleid",
"TaskCleanTranscodeDescription": "Kustutab üle ühe päeva vanused transkodeerimisfailid.",
"TaskCleanTranscodeDescription": "Kustutab üle ühe päeva vanused transkoodimisfailid.",
"TaskCleanTranscode": "Puhasta transkoodimise kataloog",
"TaskUpdatePluginsDescription": "Laadib alla ja paigaldab nende pluginate uuendused, mis on seadistatud automaatselt uuenduma.",
"TaskUpdatePlugins": "Uuenda pluginaid",
@@ -41,10 +41,10 @@
"StartupEmbyServerIsLoading": "Jellyfin server laadib. Proovi varsti uuesti.",
"User": "Kasutaja",
"Undefined": "Määratlemata",
"TvShows": "Seriaalid",
"TvShows": "Sarjad",
"System": "Süsteem",
"Sync": "Sünkrooni",
"Songs": "Laulud",
"Songs": "Lood",
"Shows": "Sarjad",
"ServerNameNeedsToBeRestarted": "{0} tuleb taaskäivitada",
"ScheduledTaskFailedWithName": "{0} nurjus",
@@ -92,7 +92,7 @@
"HeaderNextUp": "Järgmisena",
"HeaderLiveTV": "Otse TV",
"HeaderFavoriteSongs": "Lemmiklood",
"HeaderFavoriteShows": "Lemmikseriaalid",
"HeaderFavoriteShows": "Lemmiksarjad",
"HeaderFavoriteEpisodes": "Lemmikepisoodid",
"HeaderFavoriteArtists": "Lemmikesitajad",
"HeaderFavoriteAlbums": "Lemmikalbumid",
@@ -122,18 +122,20 @@
"UserOnlineFromDevice": "{0} on ühendatud seadmest {1}",
"External": "Väline",
"HearingImpaired": "Kuulmispuudega",
"TaskKeyframeExtractorDescription": "Eraldab videofailidest võtmekaadreid, et luua täpsemaid HLS-i esitusloendeid. See ülesanne võib kesta pikka aega.",
"TaskKeyframeExtractor": "Võtmekaadri ekstraktor",
"TaskRefreshTrickplayImages": "Loo eelvaate pildid",
"TaskRefreshTrickplayImagesDescription": "Loob eelvaated videotele, kus lubatud.",
"TaskAudioNormalization": "Heli Normaliseerimine",
"TaskAudioNormalizationDescription": "Skaneerib faile heli normaliseerimise andmete jaoks.",
"TaskCleanCollectionsAndPlaylistsDescription": "Eemaldab kogumikest ja esitusloenditest asjad, mida enam ei eksisteeri.",
"TaskKeyframeExtractorDescription": "Eraldab videofailidest võtmekaadrid, et luua täpsemaid HLS-i esitusloendeid. See võib kesta pikka aega.",
"TaskKeyframeExtractor": "Eralda võtmekaadrid",
"TaskRefreshTrickplayImages": "Loo trickplay pildid",
"TaskRefreshTrickplayImagesDescription": "Loob trickplay eelvaated videotele lubatud meediakogudes.",
"TaskAudioNormalization": "Normaliseeri helitugevus",
"TaskAudioNormalizationDescription": "Otsib failidest helitugevuse normaliseerimise teavet.",
"TaskCleanCollectionsAndPlaylistsDescription": "Eemaldab kogumikest ja esitusloenditest üksused, mida enam ei eksisteeri.",
"TaskCleanCollectionsAndPlaylists": "Puhasta kogumikud ja esitusloendid",
"TaskDownloadMissingLyrics": "Lae alla puuduolev lüürika",
"TaskDownloadMissingLyricsDescription": "Lae lauludele alla lüürika",
"TaskDownloadMissingLyrics": "Hangi puuduvad laulusõnad",
"TaskDownloadMissingLyricsDescription": "Laulusõnade allalaadimine",
"TaskMoveTrickplayImagesDescription": "Liigutab trickplay pildid meediakogu sätete kohaselt.",
"TaskExtractMediaSegments": "Meediasegmentide skaneerimine",
"TaskExtractMediaSegments": "Skaneeri meediasegmente",
"TaskExtractMediaSegmentsDescription": "Eraldab või võtab meediasegmendid MediaSegment'i lubavatest pluginatest.",
"TaskMoveTrickplayImages": "Migreeri trickplay piltide asukoht"
"TaskMoveTrickplayImages": "Muuda trickplay piltide asukoht",
"CleanupUserDataTask": "Puhasta kasutajaandmed",
"CleanupUserDataTaskDescription": "Puhastab kõik kasutajaandmed (vaatamise olek, lemmikute olek jne) meediast, mida pole enam vähemalt 90 päeva saadaval olnud."
}

View File

@@ -69,7 +69,7 @@
"TvShows": "Sarjat",
"Sync": "Synkronointi",
"SubtitleDownloadFailureFromForItem": "Tekstityksen lataus lähteestä \"{0}\" kohteelle \"{1}\" epäonnistui",
"StartupEmbyServerIsLoading": "Jellyfin-palvelin latautuu. Yritä hetken kuluttua uudelleen.",
"StartupEmbyServerIsLoading": "Jellyfin-palvelin on latautumassa. Yritä hetken kuluttua uudelleen.",
"Songs": "Kappaleet",
"Shows": "Sarjat",
"ServerNameNeedsToBeRestarted": "\"{0}\" on käynnistettävä uudelleen",
@@ -79,7 +79,7 @@
"NotificationOptionVideoPlayback": "Videon toisto aloitettu",
"NotificationOptionUserLockedOut": "Käyttäjä on lukittu",
"NotificationOptionTaskFailed": "Ajoitettu tehtävä epäonnistui",
"NotificationOptionServerRestartRequired": "Tarvitaan palvelimen uudelleenkäynnistys",
"NotificationOptionServerRestartRequired": "Palvelimen uudelleenkäynnistys vaaditaan",
"NotificationOptionPluginUpdateInstalled": "Lisäosa päivitettiin",
"NotificationOptionPluginUninstalled": "Lisäosa poistettiin",
"NotificationOptionPluginInstalled": "Lisäosa asennettiin",

View File

@@ -1,74 +1,74 @@
{
"Albums": "Álbumes",
"Albums": "Álbums",
"Collections": "Coleccións",
"ChapterNameValue": "Capítulo {0}",
"Channels": "Canles",
"CameraImageUploadedFrom": "Cargouse unha nova imaxe da cámara desde {0}",
"CameraImageUploadedFrom": "Cargouse unha nova imaxe de cámara dende {0}",
"Books": "Libros",
"AuthenticationSucceededWithUserName": "{0} autenticouse correctamente",
"Artists": "Artistas",
"Application": "Aplicativo",
"NotificationOptionServerRestartRequired": "Necesario un reinicio do servidor",
"NotificationOptionPluginUpdateInstalled": "Actualización do Plugin instalada",
"Application": "Aplicación",
"NotificationOptionServerRestartRequired": "Necesario o reinicio do servidor",
"NotificationOptionPluginUpdateInstalled": "Actualización do plugin instalada",
"NotificationOptionPluginUninstalled": "Plugin desinstalado",
"NotificationOptionPluginInstalled": "Plugin instalado",
"NotificationOptionPluginError": "Fallo do Plugin",
"NotificationOptionPluginError": "Fallo do plugin",
"NotificationOptionNewLibraryContent": "Novo contido engadido",
"NotificationOptionInstallationFailed": "Fallo na instalación",
"NotificationOptionCameraImageUploaded": "Imaxe da cámara subida",
"NotificationOptionAudioPlaybackStopped": "Reproducción de audio parada",
"NotificationOptionCameraImageUploaded": "Imaxe da cámara cargada",
"NotificationOptionAudioPlaybackStopped": "Reproducción de audio detida",
"NotificationOptionAudioPlayback": "Reproducción de audio comezada",
"NotificationOptionApplicationUpdateInstalled": "Actualización da aplicación instalada",
"NotificationOptionApplicationUpdateAvailable": "Actualización da aplicación dispoñible",
"NewVersionIsAvailable": "Unha nova versión do Servidor Jellyfin está dispoñible para descarga.",
"NewVersionIsAvailable": "Nova versión do Servidor Jellyfin dispoñible para descargar.",
"NameSeasonUnknown": "Tempada descoñecida",
"NameSeasonNumber": "Tempada {0}",
"NameInstallFailed": "{0} instalación fallida",
"MusicVideos": "Vídeos Musicais",
"MusicVideos": "Vídeos musicais",
"Music": "Música",
"Movies": "Películas",
"MixedContent": "Contido Mixto",
"MessageServerConfigurationUpdated": "A configuración do servidor foi actualizada",
"MessageNamedServerConfigurationUpdatedWithValue": "A sección de configuración {0} do servidor foi actualizada",
"MessageApplicationUpdatedTo": "O servidor Jellyfin foi actualizado a {0}",
"MessageApplicationUpdated": "O servidor Jellyfin foi actualizado",
"MixedContent": "Contido mixto",
"MessageServerConfigurationUpdated": "Actualizouse a configuración do servidor",
"MessageNamedServerConfigurationUpdatedWithValue": "Actualizouse a sección de configuración {0} do servidor",
"MessageApplicationUpdatedTo": "O servidor Jellyfin actualizouse a {0}",
"MessageApplicationUpdated": "O servidor Jellyfin actualizouse",
"Latest": "Último",
"LabelRunningTimeValue": "Tempo de execución: {0}",
"LabelRunningTimeValue": "Tempo en execución: {0}",
"LabelIpAddressValue": "Enderezo IP: {0}",
"ItemRemovedWithName": "{0} foi eliminado da biblioteca",
"ItemAddedWithName": "{0} foi engadido a biblioteca",
"ItemRemovedWithName": "{0} eliminouse da biblioteca",
"ItemAddedWithName": "{0} engadiuse á biblioteca",
"Inherit": "Herdar",
"HomeVideos": "Videos caseiros",
"HeaderRecordingGroups": "Grupos de Grabación",
"HeaderRecordingGroups": "Grupos de grabación",
"HeaderNextUp": "De seguido",
"HeaderLiveTV": "TV en directo",
"HeaderFavoriteSongs": "Cancións Favoritas",
"HeaderFavoriteShows": "Series de TV Favoritas",
"HeaderFavoriteEpisodes": "Episodios Favoritos",
"HeaderFavoriteArtists": "Artistas Favoritos",
"HeaderFavoriteAlbums": "Álbunes Favoritos",
"HeaderFavoriteSongs": "Cancións favoritas",
"HeaderFavoriteShows": "Series de TV favoritas",
"HeaderFavoriteEpisodes": "Episodios favoritos",
"HeaderFavoriteArtists": "Artistas favoritos",
"HeaderFavoriteAlbums": "Álbums favoritos",
"HeaderContinueWatching": "Seguir vendo",
"HeaderAlbumArtists": "Artistas do Album",
"HeaderAlbumArtists": "Artistas do álbum",
"Genres": "Xéneros",
"Forced": "Forzado",
"Folders": "Cartafoles",
"Favorites": "Favoritos",
"FailedLoginAttemptWithUserName": "Intento de incio de sesión fallido {0}",
"FailedLoginAttemptWithUserName": "Fallo de intento de inicio de sesión dende {0}",
"DeviceOnlineWithName": "{0} conectouse",
"DeviceOfflineWithName": "{0} desconectouse",
"Default": "Por defecto",
"AppDeviceValues": "Aplicación: {0}, Dispositivo: {1}",
"TaskCleanLogs": "Limpar Carpeta de Rexistros",
"TaskCleanActivityLog": "Limpar Rexistro de Actividade",
"TasksChannelsCategory": "Canáis de Internet",
"TaskUpdatePlugins": "Actualizar Plugins",
"TaskCleanLogs": "Limpar directorio de rexistros",
"TaskCleanActivityLog": "Limpar rexistro de actividade",
"TasksChannelsCategory": "Canles da Internet",
"TaskUpdatePlugins": "Actualizar plugins",
"User": "Usuario",
"Undefined": "Sen definir",
"TvShows": "Programas de TV",
"System": "Sistema",
"Sync": "Sincronizar",
"SubtitleDownloadFailureFromForItem": "Fallou a descarga de subtítulos para {1} dende {0}",
"StartupEmbyServerIsLoading": "O Servidor Jellyfin está cargando. Por favor, reinténteo en breve.",
"StartupEmbyServerIsLoading": "O servidor Jellyfin está cargando. Por favor, ténteo axiña outra vez.",
"Songs": "Cancións",
"Shows": "Programas",
"ServerNameNeedsToBeRestarted": "{0} precisa ser reiniciado",
@@ -85,56 +85,57 @@
"UserDeletedWithName": "O usuario {0} foi borrado",
"UserCreatedWithName": "O usuario {0} foi creado",
"Plugin": "Plugin",
"NotificationOptionVideoPlaybackStopped": "Reproducción de vídeo parada",
"NotificationOptionVideoPlaybackStopped": "Reproducción de vídeo detida",
"NotificationOptionVideoPlayback": "Reproducción de vídeo iniciada",
"NotificationOptionUserLockedOut": "Usuario bloqueado",
"NotificationOptionTaskFailed": "Falla na tarefa axendada",
"TaskCleanTranscodeDescription": "Borra os arquivos de transcode anteriores a un día.",
"TaskCleanTranscode": "Limpar Directorio de Transcode",
"TaskCleanTranscodeDescription": "Borra os ficheiros de transcodificación de hai más dun día.",
"TaskCleanTranscode": "Limpar o directorio de transcodificación",
"UserStoppedPlayingItemWithValues": "{0} rematou de reproducir {1} en {2}",
"UserStartedPlayingItemWithValues": "{0} está reproducindo {1} en {2}",
"TaskDownloadMissingSubtitlesDescription": "Busca en internet por subtítulos que faltan baseado na configuración de metadatos.",
"UserStartedPlayingItemWithValues": "{0} está a reproducir {1} en {2}",
"TaskDownloadMissingSubtitlesDescription": "Procura na internet os subtítulos que faltan segundo a configuración de metadatos.",
"TaskDownloadMissingSubtitles": "Descargar subtítulos que faltan",
"TaskRefreshChannelsDescription": "Refresca a información do canle de internet.",
"TaskRefreshChannels": "Refrescar Canles",
"TaskUpdatePluginsDescription": "Descarga e instala actualizacións para plugins que están configurados para actualizarse automáticamente.",
"TaskRefreshPeopleDescription": "Actualiza os metadatos dos actores e directores na túa libraría multimedia.",
"TaskRefreshPeople": "Refrescar Persoas",
"TaskCleanLogsDescription": "Borra arquivos de rexistro que son mais antigos que {0} días.",
"TaskRefreshLibraryDescription": "Escanea a tua libraría multimedia buscando novos arquivos e refrescando os metadatos.",
"TaskRefreshLibrary": "Escanear Libraría Multimedia",
"TaskRefreshChapterImagesDescription": "Crea previsualizacións para videos que teñen capítulos.",
"TaskRefreshChapterImages": "Extraer Imaxes dos Capítulos",
"TaskRefreshChannelsDescription": "Refresca a información da canle de internet.",
"TaskRefreshChannels": "Refrescar canles",
"TaskUpdatePluginsDescription": "Descarga e instala actualizacións dos plugins configurados para actualizarse automáticamente.",
"TaskRefreshPeopleDescription": "Actualiza os metadatos dos actores e directores na túa biblioteca de medios.",
"TaskRefreshPeople": "Refrescar persoas",
"TaskCleanLogsDescription": "Borra ficheiros de rexistro con máis de {0} días de antigüidade.",
"TaskRefreshLibraryDescription": "Escanea a túa biblioteca de medios á procura de novos ficheiros e refresca os metadatos.",
"TaskRefreshLibrary": "Escanear a biblioteca de medios",
"TaskRefreshChapterImagesDescription": "Crea miniaturas dos vídeos que teñen capítulos.",
"TaskRefreshChapterImages": "Extraer imaxes dos capítulos",
"TaskCleanCacheDescription": "Borra ficheiros da caché que xa non son necesarios para o sistema.",
"TaskCleanCache": "Limpa Directorio de Caché",
"TaskCleanActivityLogDescription": "Borra as entradas no rexistro de actividade anteriores á data configurada.",
"TaskCleanCache": "Limpar directorio de caché",
"TaskCleanActivityLogDescription": "Borra do rexistro de actividade as entradas anteriores á data configurada.",
"TasksApplicationCategory": "Aplicación",
"ValueSpecialEpisodeName": "Especial - {0}",
"ValueHasBeenAddedToLibrary": "{0} foi engadido a túa libraría multimedia",
"TasksLibraryCategory": "Libraría",
"ValueHasBeenAddedToLibrary": "{0} engadiuse á túa biblioteca de medios",
"TasksLibraryCategory": "Biblioteca",
"TasksMaintenanceCategory": "Mantemento",
"VersionNumber": "Versión {0}",
"UserPolicyUpdatedWithName": "A política de usuario foi actualizada para {0}",
"UserPasswordChangedWithName": "Cambiouse o contrasinal para o usuario {0}",
"UserOnlineFromDevice": "{0} está en liña desde {1}",
"UserOfflineFromDevice": "{0} desconectouse desde {1}",
"TaskOptimizeDatabaseDescription": "Compacta e libera o espazo libre da base de datos. Executar esta tarefa logo de realizar mudanzas que impliquen modificacións da base de datos ou despois de escanear a biblioteca pode traer mellorías de desempeño.",
"UserOfflineFromDevice": "{0} desconectouse dende {1}",
"TaskOptimizeDatabaseDescription": "Compacta e libera espazo na base de datos. Executar esta tarefa logo de facer cambios que muden a base de datos ou despois de escanear a biblioteca pode mellorar o rendemento.",
"TaskOptimizeDatabase": "Optimizar base de datos",
"TaskKeyframeExtractorDescription": "Extrae fragmentos do vídeo para crear listas de reprodución HLS máis precisas. Podería levarlle bastante tempo.",
"TaskKeyframeExtractorDescription": "Extrae fotogramas clave dos vídeos para crear listas de reprodución HLS máis precisas. Podería levar moito tempo.",
"External": "Externo",
"HearingImpaired": "Problemas de audición",
"TaskKeyframeExtractor": "Extractor de fragmentos",
"TaskAudioNormalization": "Normalización do audio",
"TaskRefreshTrickplayImagesDescription": "Crea vistas previas de reprodución con truco para vídeos en bibliotecas activadas.",
"TaskKeyframeExtractor": "Extractor de fotogramas clave",
"TaskAudioNormalization": "Normalización de volume",
"TaskRefreshTrickplayImagesDescription": "Crea miniaturas de previsualización para os vídeos nas bibliotecas habilitadas.",
"TaskDownloadMissingLyrics": "Descargar letras que faltan",
"TaskDownloadMissingLyricsDescription": "Descargas de letras das cancións",
"TaskDownloadMissingLyricsDescription": "Descarga as letras das cancións",
"TaskCleanCollectionsAndPlaylists": "Limpar coleccións e listas de reprodución",
"TaskCleanCollectionsAndPlaylistsDescription": "Elimina elementos de coleccións e listas de reprodución que xa non existen.",
"TaskExtractMediaSegmentsDescription": "Extrae ou obtén segmentos multimedia de complementos habilitados para o Segmento de medios.",
"TaskExtractMediaSegments": "Escaneo de segmentos multimedia",
"TaskMoveTrickplayImages": "Migrar a localización da imaxe de Trickplay",
"TaskMoveTrickplayImagesDescription": "Move os ficheiros de reprodución con trickplay existentes segundo a configuración da biblioteca.",
"TaskRefreshTrickplayImages": "Xerar imaxes de Trickplay",
"TaskAudioNormalizationDescription": "Analiza ficheiros para obter datos de normalización de audio.",
"CleanupUserDataTask": "Tarefa de limpeza de datos do usuario"
"TaskCleanCollectionsAndPlaylistsDescription": "Quita ítems que xa non existen das coleccións e listas de reprodución.",
"TaskExtractMediaSegmentsDescription": "Procura segmentos de medios cos plugins habilitados.",
"TaskExtractMediaSegments": "Escaneo de segmentos de medios",
"TaskMoveTrickplayImages": "Migrar as miniaturas de previsualización a outra ubicación",
"TaskMoveTrickplayImagesDescription": "Move as miniaturas de previsualización segundo a configuración da biblioteca.",
"TaskRefreshTrickplayImages": "Xerar miniaturas de previsualización",
"TaskAudioNormalizationDescription": "Escanea ficheiros á procura de datos de normalización de volume.",
"CleanupUserDataTask": "Tarefa de limpeza de datos dos usuarios",
"CleanupUserDataTaskDescription": "Limpa todos os datos do usuario (estado de visualización, de favorito etc.) dos medios ausentes polo menos 90 días."
}

View File

@@ -11,11 +11,11 @@
"Collections": "Sammlungen",
"DeviceOfflineWithName": "{0} wurde getrennt",
"DeviceOnlineWithName": "{0} ist verbunden",
"FailedLoginAttemptWithUserName": "Fehlgeschlagener Anmeldeversuch von {0}",
"Favorites": "Favoriten",
"FailedLoginAttemptWithUserName": "Fählgschlagene Ameldeversuech vo {0}",
"Favorites": "Favorite",
"Folders": "Ordner",
"Genres": "Genre",
"HeaderAlbumArtists": "Album-Künstler",
"HeaderAlbumArtists": "Album-Künschtler",
"HeaderContinueWatching": "weiter schauen",
"HeaderFavoriteAlbums": "Lieblingsalben",
"HeaderFavoriteArtists": "Lieblings-Künstler",

View File

@@ -129,5 +129,12 @@
"TaskAudioNormalization": "श्रव्य सामान्यीकरण",
"TaskAudioNormalizationDescription": "श्रव्य सामान्यीकरण के लिए फाइलें अन्वेषण करें",
"TaskDownloadMissingLyrics": "लापता गानों के बोल डाउनलोड करेँ",
"TaskDownloadMissingLyricsDescription": "गानों के बोल डाउनलोड करता है"
"TaskDownloadMissingLyricsDescription": "गानों के बोल डाउनलोड करता है",
"TaskExtractMediaSegments": "मीडिया सेगमेंट स्कैन",
"TaskExtractMediaSegmentsDescription": "मीडियासेगमेंट सक्षम प्लगइन्स से मीडिया सेगमेंट निकालता है या प्राप्त करता है।",
"TaskMoveTrickplayImages": "ट्रिकप्ले छवि स्थान माइग्रेट करें",
"TaskMoveTrickplayImagesDescription": "लाइब्रेरी सेटिंग्स के अनुसार मौजूदा ट्रिकप्ले फ़ाइलों को स्थानांतरित करता है।",
"TaskCleanCollectionsAndPlaylistsDescription": "संग्रहों और प्लेलिस्टों से उन आइटमों को हटाता है जो अब मौजूद नहीं हैं।",
"TaskCleanCollectionsAndPlaylists": "संग्रह और प्लेलिस्ट साफ़ करें",
"CleanupUserDataTask": "यूज़र डेटा की सफाई करता है।"
}

View File

@@ -125,8 +125,8 @@
"TaskKeyframeExtractor": "Izvoditelj ključnog okvira",
"TaskOptimizeDatabaseDescription": "Sažima bazu podataka i uklanja prazan prostor. Pokretanje ovog zadatka, može poboljšati performanse nakon provođenja indeksiranja biblioteke ili provođenja drugih promjena koje utječu na bazu podataka.",
"HearingImpaired": "Oštećen sluh",
"TaskRefreshTrickplayImages": "Generiraj Trickplay Slike",
"TaskRefreshTrickplayImagesDescription": "Kreira trickplay pretpreglede za videe u omogućenim knjižnicama.",
"TaskRefreshTrickplayImages": "Generiraj slike brzog pregledavanja",
"TaskRefreshTrickplayImagesDescription": "Stvara preglede brzog pregledavanja za videa u aktiviranim bibliotekama.",
"TaskAudioNormalization": "Normalizacija zvuka",
"TaskAudioNormalizationDescription": "Skenira datoteke u potrazi za podacima o normalizaciji zvuka.",
"TaskCleanCollectionsAndPlaylistsDescription": "Uklanja stavke iz zbirki i popisa za reprodukciju koje više ne postoje.",
@@ -135,6 +135,8 @@
"TaskDownloadMissingLyrics": "Preuzmi tekstove koji nedostaju",
"TaskDownloadMissingLyricsDescription": "Preuzmi tekstove pjesama",
"TaskExtractMediaSegmentsDescription": "Izvlači ili pribavlja dijelove medija iz omogućenih media pluginova.",
"TaskMoveTrickplayImages": "Preseli lokaciju Trickplay slika",
"TaskMoveTrickplayImagesDescription": "Preseli lokaciju Trickplay slika prema postavkama zbirke."
"TaskMoveTrickplayImages": "Premjesti mjesto slika brzog pregledavanja",
"TaskMoveTrickplayImagesDescription": "Premješta postojeće datoteke brzog pregledavanja prema postavkama biblioteke.",
"CleanupUserDataTask": "Zadatak čišćenja korisničkih podataka",
"CleanupUserDataTaskDescription": "Briše sve korisničke podatke (stanje gledanja, status favorita itd.) s medija koji više nisu prisutni najmanje 90 dana."
}

View File

@@ -1,3 +1,62 @@
{
"Books": "liv"
"Books": "Liv",
"TasksLibraryCategory": "Libreri",
"Albums": "Albòm yo",
"Artists": "Atis yo",
"Application": "Aplikasyon",
"Channels": "Kanal yo",
"ChapterNameValue": "Chapit {0}",
"Default": "Defo",
"DeviceOnlineWithName": "{0} konekte",
"DeviceOfflineWithName": "{0} dekonekte",
"External": "Extèn",
"Collections": "Koleksyon yo",
"Favorites": "Pi Renmen",
"Folders": "Dosye",
"Genres": "Jan yo",
"Forced": "Fòse",
"HeaderAlbumArtists": "Albòm Atis",
"HeaderContinueWatching": "Kontinye Kade",
"HeaderFavoriteAlbums": "Albòm Pi Renmen",
"HeaderFavoriteArtists": "Atis Pi Renmen",
"HeaderFavoriteEpisodes": "Epizòd Pi Renmen",
"HeaderFavoriteShows": "Emisyon Pi Renmen",
"HeaderFavoriteSongs": "Mizik Pi Renmen",
"HeaderLiveTV": "Televizyon an Direk",
"HeaderNextUp": "Pwochen an",
"HomeVideos": "Videyo Lakay",
"Latest": "Pi Resan",
"MessageApplicationUpdated": "Sèvè Jellyfin met a jou",
"MessageApplicationUpdatedTo": "Sèvè Jellyfin met a jou sou {0}",
"Movies": "Fim",
"MixedContent": "Kontni Melanje",
"Music": "Mizik",
"MusicVideos": "Videyo Mizik",
"NameInstallFailed": "{0} enstalasyon fe fayit",
"NameSeasonNumber": "Sezon {0}",
"NameSeasonUnknown": "Sezon Enkoni",
"NotificationOptionCameraImageUploaded": "Imaj Kamera telechaje",
"NotificationOptionInstallationFailed": "Enstalasyon echwe",
"Photos": "Foto",
"PluginInstalledWithName": "{0} te enstale",
"PluginUninstalledWithName": "{0} te dezenstale",
"PluginUpdatedWithName": "{0} te mi a jou",
"ScheduledTaskFailedWithName": "{0} echwe",
"ScheduledTaskStartedWithName": "{0} komanse",
"Songs": "Mizik yo",
"Shows": "Emisyon yo",
"System": "Sistèm",
"TvShows": "Emisyon Tele",
"User": "Itilizatè",
"UserCreatedWithName": "Itilizatè {0} kreye",
"UserDeletedWithName": "Itilizatè {0} a efase",
"UserDownloadingItemWithValues": "{0} ap telechaje {1}",
"UserOfflineFromDevice": "{0} dekonekte de {1}",
"UserStartedPlayingItemWithValues": "{0} ap jwe {1} sou {2}",
"UserStoppedPlayingItemWithValues": "{0} fin jwe {1} sou {2}",
"UserPasswordChangedWithName": "Modpas la chanje pou Itilizatè {0}",
"ValueSpecialEpisodeName": "Spesyal - {0}",
"VersionNumber": "Vesyon {0}",
"TasksApplicationCategory": "Aplikasyon",
"TasksMaintenanceCategory": "Antretyen"
}

View File

@@ -136,5 +136,7 @@
"TaskMoveTrickplayImages": "트릭플레이 이미지 위치 마이그레이션",
"TaskMoveTrickplayImagesDescription": "추출된 트릭플레이 이미지를 라이브러리 설정에 따라 이동합니다.",
"TaskDownloadMissingLyrics": "누락된 가사 다운로드",
"TaskDownloadMissingLyricsDescription": "가사 다운로드"
"TaskDownloadMissingLyricsDescription": "가사 다운로드",
"CleanupUserDataTask": "사용자 데이터 정리 작업",
"CleanupUserDataTaskDescription": "최소 90일 이상 존재하지 않는 미디어에 대한 사용자 데이터(시청 상태, 즐겨찾기 등)를 정리합니다."
}

View File

@@ -1,16 +1,16 @@
{
"Books": "Номууд",
"Books": "Номнууд",
"HeaderNextUp": "Дараа нь",
"HeaderContinueWatching": "Үргэлжлүүлэн үзэх",
"Songs": "Дуунууд",
"Playlists": "Тоглуулах жагсаалт",
"Movies": "Кино",
"Playlists": "Тоглуулах жагсаалтууд",
"Movies": "Кинонууд",
"Latest": "Сүүлийн үеийн",
"Genres": "Төрлүүд",
"Favorites": "Дуртай",
"Collections": "Багц",
"Collections": "Цуглуулгууд",
"Artists": "Уран бүтээлчид",
"Albums": "Цомгууд",
"Albums": "Дуут цомгууд",
"TaskExtractMediaSegments": "Медиа сегмент шалга",
"TaskExtractMediaSegmentsDescription": "MediaSegment идэвхжүүлсэн залгаасуудаас медиа сегментүүдийг задлах эсвэл олж авах.",
"TaskMoveTrickplayImages": "Трикплэй зургуудын байршлыг шилжүүлэх",
@@ -63,15 +63,15 @@
"CameraImageUploadedFrom": "{0}-с шинэ зураг байршуулагдлаа",
"Channels": "Сувгууд",
"ChapterNameValue": "{0}-р бүлэг",
"Default": "Өгөгдмөл",
"Default": "Анхдагч",
"DeviceOfflineWithName": "{0}-н холболт саллаа",
"DeviceOnlineWithName": "{0} холбогдлоо",
"FailedLoginAttemptWithUserName": "{0}-н нэвтрэх оролдлого амжилтгүй",
"Folders": "Хавтаснууд",
"Folders": "Хавтасууд",
"Forced": "Хүчээр",
"HeaderAlbumArtists": "Цомгийн уран бүтээлчид",
"HeaderFavoriteAlbums": "Дуртай цомгууд",
"HeaderLiveTV": "Шууд",
"HeaderLiveTV": "Шууд ТВ",
"HeaderRecordingGroups": "Бичлэгийн бүлгүүд",
"HearingImpaired": "Сонсголын бэрхшээлтэй",
"HomeVideos": "Үндсэн дүрсүүд",
@@ -84,8 +84,8 @@
"MessageApplicationUpdatedTo": "Jellyfin Server {0} болж шинэчлэгдлээ",
"MessageServerConfigurationUpdated": "Server-н тохиргоо шинэчлэгдлээ",
"MixedContent": "Холимог агуулга",
"Music": "Дуу",
"MusicVideos": "Дууны клип",
"Music": "Хөгжим",
"MusicVideos": "Дууны клипүүд",
"NameInstallFailed": "{0} суулгахад алдаа гарлаа",
"NameSeasonNumber": "{0}-р улирал",
"NameSeasonUnknown": "Улирал олдсонгүй",
@@ -101,15 +101,15 @@
"NotificationOptionUserLockedOut": "Хэрэглэгчийг түгжив",
"NotificationOptionVideoPlayback": "Бичлэгийг тоглуулж эхлэв",
"Photos": "Зургууд",
"Plugin": "Plugin",
"Plugin": "Плагин",
"PluginInstalledWithName": "{0}-г суулгалаа",
"PluginUninstalledWithName": "{0}-г устгалаа",
"PluginUpdatedWithName": "{0}-г шинэчиллээ",
"ProviderValue": "Нийлүүлэгч: {0}",
"ScheduledTaskStartedWithName": "{0}-г эхлүүлэв",
"ServerNameNeedsToBeRestarted": "{0}-г дахин асаана уу",
"Shows": "Нэвтрүүлгүүд",
"Sync": "Дахин",
"Shows": "Шоу",
"Sync": "Синхрончлох",
"System": "Систем",
"TvShows": "ТВ нэвтрүүлгүүд",
"Undefined": "Танисангүй",
@@ -122,7 +122,7 @@
"UserPolicyUpdatedWithName": "Хэрэглэгчийн журмыг {0}-д зориулан шинэчиллээ",
"UserStartedPlayingItemWithValues": "{0}-г {2} дээр {1}-г тоглуулж байна",
"UserStoppedPlayingItemWithValues": "{0}-г {2} дээр {1}-г тоглуулж дуусгалаа",
"ValueSpecialEpisodeName": "Тусгай - {0}",
"ValueSpecialEpisodeName": "Онцгой - {0}",
"VersionNumber": "Хувилбар {0}",
"TasksMaintenanceCategory": "Засвар",
"TasksLibraryCategory": "Сан",

View File

@@ -132,5 +132,10 @@
"TaskDownloadMissingLyrics": "उपलब्ध नसलेली गीतपट्टी (Lyrics) डाउनलोड करा",
"TaskAudioNormalization": "ऑडिओ सामान्यीकरण",
"TaskAudioNormalizationDescription": "ऑडिओ सामान्यीकरणाचा डाटा स्कॅन करतो.",
"TaskDownloadMissingLyricsDescription": "गाण्यांची गीतपट्टी (Lyrics) डाउनलोड करतो"
"TaskDownloadMissingLyricsDescription": "गाण्यांची गीतपट्टी (Lyrics) डाउनलोड करतो",
"TaskExtractMediaSegmentsDescription": "सक्रिय असलेल्या प्लगिनमधून मीडिया विभाग प्राप्त करते.",
"TaskMoveTrickplayImagesDescription": "लायब्ररीच्या सेटिंग्जप्रमाणे आधीपासून अस्तित्वात असलेल्या ट्रिकप्ले फाइल्सचे स्थान बदलते.",
"TaskCleanCollectionsAndPlaylistsDescription": "जे संग्रह आणि प्लेलिस्ट आता अस्तित्वात नाहीत, त्यांमधील घटक हटवते.",
"CleanupUserDataTask": "वापरकर्ता डेटाची स्वच्छता प्रक्रिया",
"CleanupUserDataTaskDescription": "९० दिवसांहून अधिक काळ अनुपस्थित असलेल्या माध्यमांवरील सर्व वापरकर्ता माहिती (जसे पाहण्याची स्थिती, आवडी इ.) हटवते."
}

View File

@@ -136,5 +136,7 @@
"TaskExtractMediaSegments": "Skann mediasegment",
"TaskMoveTrickplayImages": "Migrer bildeplassering for Trickplay",
"TaskMoveTrickplayImagesDescription": "Flytter eksisterende Trickplay-filer i henhold til biblioteksinstillingene.",
"TaskExtractMediaSegmentsDescription": "Trekker ut eller henter mediasegmenter fra plugins som støtter MediaSegment."
"TaskExtractMediaSegmentsDescription": "Trekker ut eller henter mediasegmenter fra plugins som støtter MediaSegment.",
"CleanupUserDataTaskDescription": "Sletter all brukerdata (avspillings-status, favoritter osv.) fra innhold som har vært utilgjengelig i minst 90 dager.",
"CleanupUserDataTask": "Oppgave for opprydding av brukerdata"
}

View File

@@ -0,0 +1 @@
{}

View File

@@ -134,6 +134,8 @@
"TaskCleanCollectionsAndPlaylistsDescription": "ਕਲੈਕਸ਼ਨਾਂ ਅਤੇ ਪਲੇਲਿਸਟਾਂ ਵਿੱਚੋਂ ਉਹ ਆਈਟਮ ਹਟਾਉਂਦਾ ਹੈ ਜੋ ਹੁਣ ਮੌਜੂਦ ਨਹੀਂ ਹਨ।",
"TaskCleanCollectionsAndPlaylists": "ਕਲੈਕਸ਼ਨਾਂ ਅਤੇ ਪਲੇਲਿਸਟਾਂ ਨੂੰ ਸਾਫ ਕਰੋ",
"TaskAudioNormalization": "ਆਵਾਜ਼ ਸਧਾਰਣੀਕਰਨ",
"TaskRefreshTrickplayImagesDescription": "ਚਲ ਰਹੀ ਲਾਇਬ੍ਰੇਰੀਆਂ ਵਿੱਚ ਵੀਡੀਓਜ਼ ਲਈ ਟ੍ਰਿਕਪਲੇ ਪ੍ਰੀਵਿਊ ਬਣਾਉਂਦਾ ਹੈ।",
"TaskKeyframeExtractorDescription": "ਕੀ-ਫ੍ਰੇਮਜ਼ ਨੂੰ ਵੀਡੀਓ ਫਾਈਲਾਂ ਵਿੱਚੋਂ ਨਿਕਾਲਦਾ ਹੈ ਤਾਂ ਜੋ ਹੋਰ ਜ਼ਿਆਦਾ ਸਟਿਕ ਹੋਣ ਵਾਲੀਆਂ HLS ਪਲੇਲਿਸਟਾਂ ਬਣਾਈਆਂ ਜਾ ਸਕਣ। ਇਹ ਕੰਮ ਲੰਬੇ ਸਮੇਂ ਤੱਕ ਚੱਲ ਸਕਦਾ ਹੈ।"
"TaskRefreshTrickplayImagesDescription": "ਵੀਡੀਓ ਲਈ ਟ੍ਰਿਕਪਲੇ ਪ੍ਰੀਵਿਊ ਬਣਾਉਂਦਾ ਹੈ (ਜੇ ਲਾਇਬ੍ਰੇਰੀ ਵਿੱਚ ਚੁਣਿਆ ਗਿਆ ਹੈ)।",
"TaskKeyframeExtractorDescription": "ਕੀ-ਫ੍ਰੇਮਜ਼ ਨੂੰ ਵੀਡੀਓ ਫਾਈਲਾਂ ਵਿੱਚੋਂ ਨਿਕਾਲਦਾ ਹੈ ਤਾਂ ਜੋ ਹੋਰ ਜ਼ਿਆਦਾ ਸਟਿਕ ਹੋਣ ਵਾਲੀਆਂ HLS ਪਲੇਲਿਸਟਾਂ ਬਣਾਈਆਂ ਜਾ ਸਕਣ। ਇਹ ਕੰਮ ਲੰਬੇ ਸਮੇਂ ਤੱਕ ਚੱਲ ਸਕਦਾ ਹੈ।",
"CleanupUserDataTaskDescription": "ਘੱਟੋ-ਘੱਟ 90 ਦਿਨਾਂ ਤੋਂ ਮੌਜੂਦ ਨਾ ਹੋਣ ਵਾਲੇ ਮੀਡੀਆ ਤੋਂ ਸਾਰੇ ਉਪਭੋਗਤਾ ਡੇਟਾ (ਵਾਚ ਸਟੇਟ, ਮਨਪਸੰਦ ਸਟੇਟਸ ਆਦਿ) ਨੂੰ ਸਾਫ਼ ਕਰਦਾ ਹੈ।",
"CleanupUserDataTask": "ਯੂਜ਼ਰ ਡਾਟਾ ਸਾਫ਼ ਕਰਨ ਦਾ ਕੰਮ"
}

View File

@@ -16,7 +16,7 @@
"Collections": "Barrels",
"ItemAddedWithName": "{0} is now with yer treasure",
"Default": "Normal-like",
"FailedLoginAttemptWithUserName": "Ye failed to get in, try from {0}",
"FailedLoginAttemptWithUserName": "Ye failed to enter from {0}",
"Favorites": "Finest Loot",
"ItemRemovedWithName": "{0} was taken from yer treasure",
"LabelIpAddressValue": "Ship's coordinates: {0}",
@@ -41,5 +41,82 @@
"MixedContent": "Jumbled loot",
"Music": "Tunes",
"NameInstallFailed": "Ye couldn't bring {0} aboard yer ship",
"MessageApplicationUpdatedTo": "Yer Map of the Seas has been scribbled with {0}"
"MessageApplicationUpdatedTo": "Yer Map of the Seas has been scribbled with {0}",
"MessageNamedServerConfigurationUpdatedWithValue": "Yer Map Drawer has been rescribbled to {0}",
"MessageServerConfigurationUpdated": "Yer Map drawer has been rescribbled",
"Inherit": "Carry on what be passed along",
"Latest": "Newfangled",
"Movies": "Moving pictures",
"NewVersionIsAvailable": "A fresh build o Jellyfin Server be waitin fer ye to fetch.",
"NotificationOptionPluginInstalled": "Plugin nailed down",
"NotificationOptionVideoPlayback": "Video playback be underway",
"ScheduledTaskFailedWithName": "{0} ran aground",
"StartupEmbyServerIsLoading": "Jellyfin Server be preparin the ship. Try yer luck again soon.",
"UserOfflineFromDevice": "{0} severed ties with {1}",
"UserDownloadingItemWithValues": "{0} be haulin in {1}",
"UserStartedPlayingItemWithValues": "{0} be playin {1} aboard {2}",
"ValueHasBeenAddedToLibrary": "{0} be stashed in yer treasure trove",
"TaskCleanCacheDescription": "Wipes away cache cargo no longer called fer.",
"TaskCleanLogsDescription": "Clears the logbook o entries older than {0} days.",
"TaskRefreshPeopleDescription": "Refreshes the charts fer actors an directors in yer Treasure Trove.",
"UserLockedOutWithName": "Matey {0} be denied boarding",
"TaskAudioNormalization": "Steadyin the shanties",
"TaskAudioNormalizationDescription": "Scans files fer shanty steadiyin data.",
"HeaderRecordingGroups": "Loggin' Groups",
"MusicVideos": "Shanty films",
"Playlists": "Lists o plunder",
"Plugin": "Extra sail",
"NotificationOptionVideoPlaybackStopped": "Video playback dropped anchor",
"NameSeasonNumber": "Saga {0}",
"NameSeasonUnknown": "Saga be Lost",
"NotificationOptionApplicationUpdateAvailable": "A fresh build awaits",
"NotificationOptionApplicationUpdateInstalled": "App upgrade be aboard",
"NotificationOptionAudioPlayback": "Audio playback be rollin",
"NotificationOptionAudioPlaybackStopped": "Audio playback dropped anchor",
"NotificationOptionCameraImageUploaded": "Spyglass shot be hoisted",
"NotificationOptionInstallationFailed": "Install be wrecked",
"NotificationOptionNewLibraryContent": "Fresh plunder ready to claim",
"NotificationOptionPluginError": "Plugin ran aground",
"NotificationOptionPluginUninstalled": "Plugin cast overboard",
"NotificationOptionPluginUpdateInstalled": "Plugin patched n ready",
"NotificationOptionServerRestartRequired": "Server be due fer a restart",
"NotificationOptionTaskFailed": "Set chore went overboard",
"TaskRefreshLibraryDescription": "Searches the Treasure Trove fer new plunder n updates the charts.",
"PluginInstalledWithName": "{0} nailed down",
"TaskCleanLogs": "Swab the Log Hold",
"TaskRefreshPeople": "Freshen the Mateys",
"PluginUninstalledWithName": "{0} sent t Davy Jones",
"PluginUpdatedWithName": "{0} patched n ready",
"ProviderValue": "Supplier o goods: {0}",
"ScheduledTaskStartedWithName": "{0} set sail",
"ServerNameNeedsToBeRestarted": "{0} be cravin a restart",
"Shows": "Sagas",
"SubtitleDownloadFailureFromForItem": "Subtitles be sunk fetchin from {0} fer {1}",
"Sync": "Match the tides",
"System": "The ships works",
"TvShows": "TV Sagas",
"Undefined": "Uncharted",
"User": "Matey",
"UserCreatedWithName": "Matey {0} joined the crew",
"UserDeletedWithName": "Matey {0} cast overboard",
"UserOnlineFromDevice": "{0} be aboard ship from {1}",
"UserPasswordChangedWithName": "New passphrase set fer Matey {0}",
"UserPolicyUpdatedWithName": "Ship rules be changed fer {0}",
"UserStoppedPlayingItemWithValues": "{0} be done playin {1} on {2",
"ValueSpecialEpisodeName": "Special Tale {0}",
"VersionNumber": "Edition {0}",
"TasksMaintenanceCategory": "Hull patchin",
"TasksLibraryCategory": "Treasure Trove",
"TasksApplicationCategory": "Ship",
"TaskCleanActivityLog": "Clear the Ships Log",
"TaskCleanActivityLogDescription": "Purges ships logs older than the chosen time.",
"TaskCleanCache": "Sweep the Cache Chest",
"TaskRefreshChapterImages": "Claim chapter portraits",
"TaskRefreshChapterImagesDescription": "Paints wee portraits fer videos that own chapters.",
"TaskRefreshLibrary": "Scan the Treasure Trove",
"TasksChannelsCategory": "Channels o' thy Internet",
"TaskRefreshTrickplayImages": "Summon the picture tricks",
"TaskRefreshTrickplayImagesDescription": "Summons picture trick previews for videos in ye enabled book roost",
"TaskUpdatePlugins": "Resummon yer Plugins",
"TaskCleanTranscode": "Swab Ye Transcode Directory"
}

View File

@@ -5,7 +5,7 @@
"Artists": "Artistas",
"AuthenticationSucceededWithUserName": "{0} autenticado com sucesso",
"Books": "Livros",
"CameraImageUploadedFrom": "Uma nova imagem de câmara foi enviada a partir de {0}",
"CameraImageUploadedFrom": "Uma nova imagem da câmara foi enviada a partir de {0}",
"Channels": "Canais",
"ChapterNameValue": "Capítulo {0}",
"Collections": "Coleções",

View File

@@ -70,7 +70,7 @@
"ScheduledTaskFailedWithName": "{0} - неудачна",
"ScheduledTaskStartedWithName": "{0} - запущена",
"ServerNameNeedsToBeRestarted": "Необходим перезапуск {0}",
"Shows": "Телешоу",
"Shows": "Сериалы",
"Songs": "Композиции",
"StartupEmbyServerIsLoading": "Jellyfin Server загружается. Повторите попытку в ближайшее время.",
"SubtitleDownloadFailureForItem": "Субтитры к {0} не удалось загрузить",

View File

@@ -135,5 +135,7 @@
"TaskCleanCollectionsAndPlaylists": "Pastron koleksionet dhe listat e këngëve",
"TaskCleanCollectionsAndPlaylistsDescription": "Heq elementet nga koleksionet dhe listat e këngëve që nuk ekzistojnë më.",
"TaskAudioNormalization": "Normalizimi i audios",
"TaskAudioNormalizationDescription": "Skannon skedarët për të dhëna të normalizimit të audios."
"TaskAudioNormalizationDescription": "Skannon skedarët për të dhëna të normalizimit të audios.",
"CleanupUserDataTaskDescription": "Pastron të gjitha të dhënat e përdorueseve (gjendja e shikimit, statusi i të preferuarave etj.) nga mediat që nuk janë më të pranishme për të paktën 90 ditë.",
"CleanupUserDataTask": "Veprim për pastrimin të dhënave të përdorueseve"
}

View File

@@ -126,5 +126,16 @@
"HearingImpaired": "ослабљен слух",
"TaskAudioNormalization": "Нормализација звука",
"TaskCleanCollectionsAndPlaylists": "Очистите колекције и плејлисте",
"TaskAudioNormalizationDescription": "Скенира датотеке за податке о нормализацији звука."
"TaskAudioNormalizationDescription": "Скенира датотеке за податке о нормализацији звука.",
"TaskRefreshTrickplayImages": "Направи сличице за визуелно премотавање",
"TaskRefreshTrickplayImagesDescription": "Прављење сличица које помажу код визуелног премотавања видео-снимака.",
"TaskDownloadMissingLyrics": "Преузми стихове који недостају",
"TaskCleanCollectionsAndPlaylistsDescription": "Уклања ставке које више не постоје из колекција и плејлиста.",
"TaskExtractMediaSegments": "Скенирај сегменте медија",
"TaskExtractMediaSegmentsDescription": "Извлачи или добавља сегменте медија у додацима који раде са MediaSegment-ом.",
"TaskMoveTrickplayImagesDescription": "Премешта постојеће сличице за визуелно премотавање сходно подешавањима библиотеке.",
"CleanupUserDataTask": "Задатак чишћења корисничких података",
"CleanupUserDataTaskDescription": "Чисти све корисничке податке (напредак гледања, ознаке за омиљено...) медија који нису доступни 90 дана или дуже.",
"TaskMoveTrickplayImages": "Промени локацију сличица за визуелно премотавање",
"TaskDownloadMissingLyricsDescription": "Преузми стихове песама"
}

View File

@@ -59,5 +59,6 @@
"NotificationOptionAudioPlayback": "ఆడియో ప్లే కావడం మొదలైంది",
"NotificationOptionCameraImageUploaded": "కెమెరా చిత్రాన్ని అప్లోడ్ చేశారు",
"NotificationOptionInstallationFailed": "ఇన్స్టాలేషన్ విఫలమైంది",
"NotificationOptionServerRestartRequired": "సర్వర్ రీస్టార్ట్ అవసరం"
"NotificationOptionServerRestartRequired": "సర్వర్ రీస్టార్ట్ అవసరం",
"Inherit": "సంక్రమించు"
}

View File

@@ -1,3 +1,16 @@
{
"Books": "کتابیں"
"Books": "کتابیں",
"AppDeviceValues": "ایپ: {0}، ڈیوائس: {1}",
"Albums": "البمز",
"Application": "ایپلی کیشن",
"Artists": "فنکار",
"AuthenticationSucceededWithUserName": "{0} کی کامیابی سے تصدیق ہو چکی ہے",
"CameraImageUploadedFrom": "ایک نئی کیمرے کی تصویر {0} سے اپ لوڈ کی گئی ہے",
"Channels": "چینلز",
"ChapterNameValue": "باب {0}",
"Collections": "مجموعے",
"Default": "ڈیفالٹ",
"DeviceOfflineWithName": "{0} نے رابطہ منقطع کر دیا ہے",
"DeviceOnlineWithName": "{0} منسلک ہے",
"External": "بیرونی"
}

View File

@@ -123,5 +123,9 @@
"TaskCleanActivityLogDescription": "تشکیل شدہ عمر سے زیادہ پرانی سرگرمی لاگ اندراجات کو حذف کرتا ہے۔",
"External": "بیرونی",
"HearingImpaired": "قوت سماعت سے محروم",
"TaskCleanActivityLog": "سرگرمی لاگ کو صاف کریں"
"TaskCleanActivityLog": "سرگرمی لاگ کو صاف کریں",
"TaskDownloadMissingLyrics": "غائب بول ڈاؤن لوڈ کریں",
"TaskDownloadMissingLyricsDescription": "گانے کے غائب بول ڈاؤن لوڈ کریں",
"TaskAudioNormalization": "آڈیو نارملائزیشن",
"TaskAudioNormalizationDescription": "آڈیو نارملائزیشن ڈیٹا کے لیے فائلوں کو سکین کرتا ہے۔"
}

View File

@@ -39,7 +39,7 @@
"TasksMaintenanceCategory": "Bảo Trì",
"VersionNumber": "Phiên Bản {0}",
"ValueHasBeenAddedToLibrary": "{0} đã được thêm vào thư viện của bạn",
"UserStoppedPlayingItemWithValues": "{0} đã phát xong {1} trên {2}",
"UserStoppedPlayingItemWithValues": "{0} đã kết thúc phát {1} trên {2}",
"UserStartedPlayingItemWithValues": "{0} đang phát {1} trên {2}",
"UserPolicyUpdatedWithName": "Chính sách người dùng đã được cập nhật cho {0}",
"UserPasswordChangedWithName": "Mật khẩu đã được thay đổi cho người dùng {0}",

View File

@@ -23,7 +23,7 @@
"HeaderFavoriteShows": "最愛的節目",
"HeaderFavoriteSongs": "最愛的歌曲",
"HeaderLiveTV": "電視直播",
"HeaderNextUp": "接著播放",
"HeaderNextUp": "繼續觀看",
"HeaderRecordingGroups": "錄製組",
"HomeVideos": "家庭影片",
"Inherit": "繼承",
@@ -127,8 +127,8 @@
"HearingImpaired": "聽力障礙",
"TaskRefreshTrickplayImages": "建立 Trickplay 圖像",
"TaskRefreshTrickplayImagesDescription": "為已啟用 Trickplay 的媒體庫內的影片建立 Trickplay 預覽圖。",
"TaskExtractMediaSegments": "掃描媒體段落",
"TaskExtractMediaSegmentsDescription": "從MediaSegment中被允許的插件獲取媒體段。",
"TaskExtractMediaSegments": "掃描媒體分段資訊",
"TaskExtractMediaSegmentsDescription": "從允許MediaSegment 功能的插件獲取媒體段。",
"TaskDownloadMissingLyrics": "下載欠缺歌詞",
"TaskDownloadMissingLyricsDescription": "下載歌詞",
"TaskCleanCollectionsAndPlaylists": "整理媒體與播放清單",
@@ -137,5 +137,6 @@
"TaskCleanCollectionsAndPlaylistsDescription": "從資料庫及播放清單中移除已不存在的項目。",
"TaskMoveTrickplayImagesDescription": "根據媒體庫設定移動現有的 Trickplay 檔案。",
"TaskMoveTrickplayImages": "轉移 Trickplay 影像位置",
"CleanupUserDataTask": "用戶資料清理工作"
"CleanupUserDataTask": "用戶資料清理工作",
"CleanupUserDataTaskDescription": "從用戶數據中清除已經被刪除超過 90 日的媒體相關資料。"
}

View File

@@ -402,8 +402,8 @@ sog|||Sogdian|sogdien
som||so|Somali|somali
son|||Songhai languages|songhai, langues
sot||st|Sotho, Southern|sotho du Sud
spa||es-419|Spanish; Latin|espagnol; Latin
spa||es|Spanish; Castilian|espagnol; castillan
spa||es-419|Spanish; Latin|espagnol; Latin
sqi|alb|sq|Albanian|albanais
srd||sc|Sardinian|sarde
srn|||Sranan Tongo|sranan tongo

View File

@@ -244,6 +244,7 @@ namespace Emby.Server.Implementations.Playlists
// Update the playlist in the repository
playlist.LinkedChildren = [.. playlist.LinkedChildren, .. childrenToAdd];
playlist.DateLastMediaAdded = DateTime.UtcNow;
await UpdatePlaylistInternal(playlist).ConfigureAwait(false);
@@ -314,7 +315,7 @@ namespace Emby.Server.Implementations.Playlists
return;
}
var newPriorItemIndex = newIndex > oldIndexAccessible ? newIndex : newIndex - 1 < 0 ? 0 : newIndex - 1;
var newPriorItemIndex = Math.Max(newIndex - 1, 0);
var newPriorItemId = accessibleChildren[newPriorItemIndex].Item1.ItemId;
var newPriorItemIndexOnAllChildren = children.FindIndex(c => c.Item1.ItemId.Equals(newPriorItemId));
var adjustedNewIndex = DetermineAdjustedIndex(newPriorItemIndexOnAllChildren, newIndex);

View File

@@ -33,6 +33,8 @@ public partial class AudioNormalizationTask : IScheduledTask
private readonly ILocalizationManager _localization;
private readonly ILogger<AudioNormalizationTask> _logger;
private static readonly TimeSpan _dbSaveInterval = TimeSpan.FromMinutes(5);
/// <summary>
/// Initializes a new instance of the <see cref="AudioNormalizationTask"/> class.
/// </summary>
@@ -82,7 +84,9 @@ public partial class AudioNormalizationTask : IScheduledTask
foreach (var library in libraries)
{
var startDbSaveInterval = Stopwatch.GetTimestamp();
var albums = _libraryManager.GetItemList(new InternalItemsQuery { IncludeItemTypes = [BaseItemKind.MusicAlbum], Parent = library, Recursive = true });
var toSaveDbItems = new List<BaseItem>();
double nextPercent = numComplete + 1;
nextPercent /= libraries.Length;
@@ -114,14 +118,33 @@ public partial class AudioNormalizationTask : IScheduledTask
string.Format(CultureInfo.InvariantCulture, "-f concat -safe 0 -i \"{0}\"", tempFile),
OperatingSystem.IsWindows(), // Wait for process to exit on Windows before we try deleting the concat file
cancellationToken).ConfigureAwait(false);
toSaveDbItems.Add(a);
}
finally
{
File.Delete(tempFile);
try
{
File.Delete(tempFile);
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to delete concat file: {FileName}.", tempFile);
}
}
}
}
if (Stopwatch.GetElapsedTime(startDbSaveInterval) > _dbSaveInterval)
{
if (toSaveDbItems.Count > 1)
{
_itemRepository.SaveItems(toSaveDbItems, cancellationToken);
toSaveDbItems.Clear();
}
startDbSaveInterval = Stopwatch.GetTimestamp();
}
// Update sub-progress for album gain
albumComplete++;
double albumPercent = albumComplete;
@@ -133,7 +156,13 @@ public partial class AudioNormalizationTask : IScheduledTask
// Update progress to start at the track gain percent calculation
percent += nextPercent;
_itemRepository.SaveItems(albums, cancellationToken);
if (toSaveDbItems.Count > 1)
{
_itemRepository.SaveItems(toSaveDbItems, cancellationToken);
toSaveDbItems.Clear();
}
startDbSaveInterval = Stopwatch.GetTimestamp();
// Track gain
var tracks = _libraryManager.GetItemList(new InternalItemsQuery { MediaTypes = [MediaType.Audio], IncludeItemTypes = [BaseItemKind.Audio], Parent = library, Recursive = true });
@@ -147,6 +176,18 @@ public partial class AudioNormalizationTask : IScheduledTask
string.Format(CultureInfo.InvariantCulture, "-i \"{0}\"", t.Path.Replace("\"", "\\\"", StringComparison.Ordinal)),
false,
cancellationToken).ConfigureAwait(false);
toSaveDbItems.Add(t);
}
if (Stopwatch.GetElapsedTime(startDbSaveInterval) > _dbSaveInterval)
{
if (toSaveDbItems.Count > 1)
{
_itemRepository.SaveItems(toSaveDbItems, cancellationToken);
toSaveDbItems.Clear();
}
startDbSaveInterval = Stopwatch.GetTimestamp();
}
// Update sub-progress for track gain
@@ -157,7 +198,10 @@ public partial class AudioNormalizationTask : IScheduledTask
progress.Report(100 * (percent + (trackPercent * nextPercent)));
}
_itemRepository.SaveItems(tracks, cancellationToken);
if (toSaveDbItems.Count > 1)
{
_itemRepository.SaveItems(toSaveDbItems, cancellationToken);
}
// Update progress
numComplete++;
@@ -195,9 +239,9 @@ public partial class AudioNormalizationTask : IScheduledTask
},
})
{
_logger.LogDebug("Starting ffmpeg with arguments: {Arguments}", args);
try
{
_logger.LogDebug("Starting ffmpeg with arguments: {Arguments}", args);
process.Start();
}
catch (Exception ex)
@@ -206,16 +250,33 @@ public partial class AudioNormalizationTask : IScheduledTask
return null;
}
try
{
process.PriorityClass = ProcessPriorityClass.BelowNormal;
}
catch (Exception ex)
{
_logger.LogWarning(ex, "Error setting ffmpeg process priority");
}
using var reader = process.StandardError;
float? lufs = null;
var foundLufs = false;
await foreach (var line in reader.ReadAllLinesAsync(cancellationToken).ConfigureAwait(false))
{
Match match = LUFSRegex().Match(line);
if (match.Success)
if (foundLufs)
{
lufs = float.Parse(match.Groups[1].ValueSpan, CultureInfo.InvariantCulture.NumberFormat);
break;
continue;
}
Match match = LUFSRegex().Match(line);
if (!match.Success)
{
continue;
}
lufs = float.Parse(match.Groups[1].ValueSpan, CultureInfo.InvariantCulture.NumberFormat);
foundLufs = true;
}
if (lufs is null)

View File

@@ -61,7 +61,7 @@ public class OptimizeDatabaseTask : IScheduledTask, IConfigurableScheduledTask
yield return new TaskTriggerInfo
{
Type = TaskTriggerInfoType.IntervalTrigger,
IntervalTicks = TimeSpan.FromHours(24).Ticks
IntervalTicks = TimeSpan.FromHours(6).Ticks
};
}

View File

@@ -1,10 +1,14 @@
using System;
using System.Buffers;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Jellyfin.Database.Implementations;
using MediaBrowser.Controller.Library;
using MediaBrowser.Model.Globalization;
using MediaBrowser.Model.Tasks;
using Microsoft.EntityFrameworkCore;
namespace Emby.Server.Implementations.ScheduledTasks.Tasks;
@@ -15,16 +19,19 @@ public class PeopleValidationTask : IScheduledTask, IConfigurableScheduledTask
{
private readonly ILibraryManager _libraryManager;
private readonly ILocalizationManager _localization;
private readonly IDbContextFactory<JellyfinDbContext> _dbContextFactory;
/// <summary>
/// Initializes a new instance of the <see cref="PeopleValidationTask" /> class.
/// </summary>
/// <param name="libraryManager">Instance of the <see cref="ILibraryManager"/> interface.</param>
/// <param name="localization">Instance of the <see cref="ILocalizationManager"/> interface.</param>
public PeopleValidationTask(ILibraryManager libraryManager, ILocalizationManager localization)
/// <param name="dbContextFactory">Instance of the <see cref="IDbContextFactory{TContext}"/> interface.</param>
public PeopleValidationTask(ILibraryManager libraryManager, ILocalizationManager localization, IDbContextFactory<JellyfinDbContext> dbContextFactory)
{
_libraryManager = libraryManager;
_localization = localization;
_dbContextFactory = dbContextFactory;
}
/// <inheritdoc />
@@ -62,8 +69,61 @@ public class PeopleValidationTask : IScheduledTask, IConfigurableScheduledTask
}
/// <inheritdoc />
public Task ExecuteAsync(IProgress<double> progress, CancellationToken cancellationToken)
public async Task ExecuteAsync(IProgress<double> progress, CancellationToken cancellationToken)
{
return _libraryManager.ValidatePeopleAsync(progress, cancellationToken);
IProgress<double> subProgress = new Progress<double>((val) => progress.Report(val / 2));
await _libraryManager.ValidatePeopleAsync(subProgress, cancellationToken).ConfigureAwait(false);
subProgress = new Progress<double>((val) => progress.Report((val / 2) + 50));
var context = await _dbContextFactory.CreateDbContextAsync(cancellationToken).ConfigureAwait(false);
await using (context.ConfigureAwait(false))
{
var dupQuery = context.Peoples
.GroupBy(e => new { e.Name, e.PersonType })
.Where(e => e.Count() > 1)
.Select(e => e.Select(f => f.Id).ToArray());
var total = dupQuery.Count();
const int PartitionSize = 100;
var iterator = 0;
int itemCounter;
var buffer = ArrayPool<Guid[]>.Shared.Rent(PartitionSize)!;
try
{
do
{
itemCounter = 0;
await foreach (var item in dupQuery
.Take(PartitionSize)
.AsAsyncEnumerable()
.WithCancellation(cancellationToken)
.ConfigureAwait(false))
{
buffer[itemCounter++] = item;
}
for (int i = 0; i < itemCounter; i++)
{
var item = buffer[i];
var reference = item[0];
var dups = item[1..];
await context.PeopleBaseItemMap.WhereOneOrMany(dups, e => e.PeopleId)
.ExecuteUpdateAsync(e => e.SetProperty(f => f.PeopleId, reference), cancellationToken)
.ConfigureAwait(false);
await context.Peoples.Where(e => dups.Contains(e.Id)).ExecuteDeleteAsync(cancellationToken).ConfigureAwait(false);
subProgress.Report(100f / total * ((iterator * PartitionSize) + i));
}
iterator++;
} while (itemCounter == PartitionSize && !cancellationToken.IsCancellationRequested);
}
finally
{
ArrayPool<Guid[]>.Shared.Return(buffer);
}
subProgress.Report(100);
}
}
}

View File

@@ -6,7 +6,6 @@ using Jellyfin.Database.Implementations.Entities;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Sorting;
using MediaBrowser.Model.Querying;
namespace Emby.Server.Implementations.Sorting
{
@@ -54,7 +53,7 @@ namespace Emby.Server.Implementations.Sorting
/// <returns>DateTime.</returns>
private int GetValue(BaseItem x)
{
return x.IsFavoriteOrLiked(User) ? 0 : 1;
return x.IsFavoriteOrLiked(User, userItemData: null) ? 0 : 1;
}
}
}

View File

@@ -7,7 +7,6 @@ using Jellyfin.Database.Implementations.Entities;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Sorting;
using MediaBrowser.Model.Querying;
namespace Emby.Server.Implementations.Sorting
{
@@ -55,7 +54,7 @@ namespace Emby.Server.Implementations.Sorting
/// <returns>DateTime.</returns>
private int GetValue(BaseItem x)
{
return x.IsPlayed(User) ? 0 : 1;
return x.IsPlayed(User, userItemData: null) ? 0 : 1;
}
}
}

View File

@@ -7,7 +7,6 @@ using Jellyfin.Database.Implementations.Entities;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Sorting;
using MediaBrowser.Model.Querying;
namespace Emby.Server.Implementations.Sorting
{
@@ -55,7 +54,7 @@ namespace Emby.Server.Implementations.Sorting
/// <returns>DateTime.</returns>
private int GetValue(BaseItem x)
{
return x.IsUnplayed(User) ? 0 : 1;
return x.IsUnplayed(User, userItemData: null) ? 0 : 1;
}
}
}

View File

@@ -223,15 +223,14 @@ namespace Emby.Server.Implementations.Updates
Guid id = default,
Version? specificVersion = null)
{
if (name is not null)
{
availablePackages = availablePackages.Where(x => x.Name.Equals(name, StringComparison.OrdinalIgnoreCase));
}
if (!id.IsEmpty())
{
availablePackages = availablePackages.Where(x => x.Id.Equals(id));
}
else if (name is not null)
{
availablePackages = availablePackages.Where(x => x.Name.Equals(name, StringComparison.OrdinalIgnoreCase));
}
if (specificVersion is not null)
{

View File

@@ -122,7 +122,6 @@ public class ArtistsController : BaseJellyfinApiController
{
userId = RequestHelpers.GetUserId(User, userId);
var dtoOptions = new DtoOptions { Fields = fields }
.AddClientFields(User)
.AddAdditionalDtoOptions(enableImages, enableUserData, imageTypeLimit, enableImageTypes);
User? user = null;
@@ -326,7 +325,6 @@ public class ArtistsController : BaseJellyfinApiController
{
userId = RequestHelpers.GetUserId(User, userId);
var dtoOptions = new DtoOptions { Fields = fields }
.AddClientFields(User)
.AddAdditionalDtoOptions(enableImages, enableUserData, imageTypeLimit, enableImageTypes);
User? user = null;
@@ -467,7 +465,7 @@ public class ArtistsController : BaseJellyfinApiController
public ActionResult<BaseItemDto> GetArtistByName([FromRoute, Required] string name, [FromQuery] Guid? userId)
{
userId = RequestHelpers.GetUserId(User, userId);
var dtoOptions = new DtoOptions().AddClientFields(User);
var dtoOptions = new DtoOptions();
var item = _libraryManager.GetArtist(name, dtoOptions);

View File

@@ -65,7 +65,7 @@ public class CollectionController : BaseJellyfinApiController
UserIds = new[] { userId }
}).ConfigureAwait(false);
var dtoOptions = new DtoOptions().AddClientFields(User);
var dtoOptions = new DtoOptions();
var dto = _dtoService.GetBaseItemDto(item, dtoOptions);

View File

@@ -96,9 +96,6 @@ public class DisplayPreferencesController : BaseJellyfinApiController
dto.CustomPrefs.TryAdd(key, value);
}
// This will essentially be a noop if no changes have been made, but new prefs must be saved at least.
_displayPreferencesManager.SaveChanges();
return dto;
}
@@ -210,8 +207,8 @@ public class DisplayPreferencesController : BaseJellyfinApiController
// Set all remaining custom preferences.
_displayPreferencesManager.SetCustomItemDisplayPreferences(userId.Value, itemId, existingDisplayPreferences.Client, displayPreferences.CustomPrefs);
_displayPreferencesManager.SaveChanges();
_displayPreferencesManager.UpdateItemDisplayPreferences(itemPrefs);
_displayPreferencesManager.UpdateDisplayPreferences(existingDisplayPreferences);
return NoContent();
}
}

View File

@@ -1625,8 +1625,11 @@ public class DynamicHlsController : BaseJellyfinApiController
var useLegacySegmentOption = _mediaEncoder.EncoderVersion < _minFFmpegHlsSegmentOptions;
// fMP4 needs this flag to write the audio packet DTS/PTS including the initial delay into MOOF::TRAF::TFDT
hlsArguments += $" {(useLegacySegmentOption ? "-hls_ts_options" : "-hls_segment_options")} movflags=+frag_discont";
if (state.VideoStream is not null && state.IsOutputVideo)
{
// fMP4 needs this flag to write the audio packet DTS/PTS including the initial delay into MOOF::TRAF::TFDT
hlsArguments += $" {(useLegacySegmentOption ? "-hls_ts_options" : "-hls_segment_options")} movflags=+frag_discont";
}
segmentFormat = "fmp4" + outputFmp4HeaderArg;
}

View File

@@ -94,7 +94,6 @@ public class GenresController : BaseJellyfinApiController
{
userId = RequestHelpers.GetUserId(User, userId);
var dtoOptions = new DtoOptions { Fields = fields }
.AddClientFields(User)
.AddAdditionalDtoOptions(enableImages, false, imageTypeLimit, enableImageTypes);
User? user = userId.IsNullOrEmpty()
@@ -159,8 +158,7 @@ public class GenresController : BaseJellyfinApiController
public ActionResult<BaseItemDto> GetGenre([FromRoute, Required] string genreName, [FromQuery] Guid? userId)
{
userId = RequestHelpers.GetUserId(User, userId);
var dtoOptions = new DtoOptions()
.AddClientFields(User);
var dtoOptions = new DtoOptions();
Genre? item;
if (genreName.Contains(BaseItem.SlugChar, StringComparison.OrdinalIgnoreCase))

View File

@@ -90,7 +90,6 @@ public class InstantMixController : BaseJellyfinApiController
}
var dtoOptions = new DtoOptions { Fields = fields }
.AddClientFields(User)
.AddAdditionalDtoOptions(enableImages, enableUserData, imageTypeLimit, enableImageTypes);
var items = _musicManager.GetInstantMixFromItem(item, user, dtoOptions);
return GetResult(items, user, limit, dtoOptions);
@@ -134,7 +133,6 @@ public class InstantMixController : BaseJellyfinApiController
}
var dtoOptions = new DtoOptions { Fields = fields }
.AddClientFields(User)
.AddAdditionalDtoOptions(enableImages, enableUserData, imageTypeLimit, enableImageTypes);
var items = _musicManager.GetInstantMixFromItem(item, user, dtoOptions);
return GetResult(items, user, limit, dtoOptions);
@@ -178,7 +176,6 @@ public class InstantMixController : BaseJellyfinApiController
}
var dtoOptions = new DtoOptions { Fields = fields }
.AddClientFields(User)
.AddAdditionalDtoOptions(enableImages, enableUserData, imageTypeLimit, enableImageTypes);
var items = _musicManager.GetInstantMixFromItem(item, user, dtoOptions);
return GetResult(items, user, limit, dtoOptions);
@@ -214,7 +211,6 @@ public class InstantMixController : BaseJellyfinApiController
? null
: _userManager.GetUserById(userId.Value);
var dtoOptions = new DtoOptions { Fields = fields }
.AddClientFields(User)
.AddAdditionalDtoOptions(enableImages, enableUserData, imageTypeLimit, enableImageTypes);
var items = _musicManager.GetInstantMixFromGenres(new[] { name }, user, dtoOptions);
return GetResult(items, user, limit, dtoOptions);
@@ -258,7 +254,6 @@ public class InstantMixController : BaseJellyfinApiController
}
var dtoOptions = new DtoOptions { Fields = fields }
.AddClientFields(User)
.AddAdditionalDtoOptions(enableImages, enableUserData, imageTypeLimit, enableImageTypes);
var items = _musicManager.GetInstantMixFromItem(item, user, dtoOptions);
return GetResult(items, user, limit, dtoOptions);
@@ -302,7 +297,6 @@ public class InstantMixController : BaseJellyfinApiController
}
var dtoOptions = new DtoOptions { Fields = fields }
.AddClientFields(User)
.AddAdditionalDtoOptions(enableImages, enableUserData, imageTypeLimit, enableImageTypes);
var items = _musicManager.GetInstantMixFromItem(item, user, dtoOptions);
return GetResult(items, user, limit, dtoOptions);
@@ -385,7 +379,6 @@ public class InstantMixController : BaseJellyfinApiController
}
var dtoOptions = new DtoOptions { Fields = fields }
.AddClientFields(User)
.AddAdditionalDtoOptions(enableImages, enableUserData, imageTypeLimit, enableImageTypes);
var items = _musicManager.GetInstantMixFromItem(item, user, dtoOptions);
return GetResult(items, user, limit, dtoOptions);

View File

@@ -268,7 +268,6 @@ public class ItemsController : BaseJellyfinApiController
}
var dtoOptions = new DtoOptions { Fields = fields }
.AddClientFields(User)
.AddAdditionalDtoOptions(enableImages, enableUserData, imageTypeLimit, enableImageTypes);
if (includeItemTypes.Length == 1
@@ -849,7 +848,6 @@ public class ItemsController : BaseJellyfinApiController
var parentIdGuid = parentId ?? Guid.Empty;
var dtoOptions = new DtoOptions { Fields = fields }
.AddClientFields(User)
.AddAdditionalDtoOptions(enableImages, enableUserData, imageTypeLimit, enableImageTypes);
var ancestorIds = Array.Empty<Guid>();

View File

@@ -187,7 +187,7 @@ public class LibraryController : BaseJellyfinApiController
item = parent;
}
var dtoOptions = new DtoOptions().AddClientFields(User);
var dtoOptions = new DtoOptions();
var items = themeItems
.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user, item))
.ToArray();
@@ -260,7 +260,7 @@ public class LibraryController : BaseJellyfinApiController
item = parent;
}
var dtoOptions = new DtoOptions().AddClientFields(User);
var dtoOptions = new DtoOptions();
var items = themeItems
.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user, item))
.ToArray();
@@ -496,7 +496,7 @@ public class LibraryController : BaseJellyfinApiController
var baseItemDtos = new List<BaseItemDto>();
var dtoOptions = new DtoOptions().AddClientFields(User);
var dtoOptions = new DtoOptions();
BaseItem? parent = item.GetParent();
while (parent is not null)
@@ -556,7 +556,7 @@ public class LibraryController : BaseJellyfinApiController
items = items.Where(i => i.IsHidden == val).ToList();
}
var dtoOptions = new DtoOptions().AddClientFields(User);
var dtoOptions = new DtoOptions();
var resultArray = _dtoService.GetBaseItemDtos(items, dtoOptions);
return new QueryResult<BaseItemDto>(resultArray);
}
@@ -747,8 +747,7 @@ public class LibraryController : BaseJellyfinApiController
return new QueryResult<BaseItemDto>();
}
var dtoOptions = new DtoOptions { Fields = fields }
.AddClientFields(User);
var dtoOptions = new DtoOptions { Fields = fields };
var program = item as IHasProgramAttributes;
bool? isMovie = item is Movie || (program is not null && program.IsMovie) || item is Trailer;
@@ -779,11 +778,14 @@ public class LibraryController : BaseJellyfinApiController
var query = new InternalItemsQuery(user)
{
Genres = item.Genres,
Tags = item.Tags,
Limit = limit,
IncludeItemTypes = includeItemTypes.ToArray(),
DtoOptions = dtoOptions,
EnableTotalRecordCount = !isMovie ?? true,
EnableGroupByMetadataKey = isMovie ?? false,
ExcludeItemIds = [itemId],
OrderBy = [(ItemSortBy.Random, SortOrder.Ascending)]
};
// ExcludeArtistIds

View File

@@ -170,7 +170,6 @@ public class LiveTvController : BaseJellyfinApiController
{
userId = RequestHelpers.GetUserId(User, userId);
var dtoOptions = new DtoOptions { Fields = fields }
.AddClientFields(User)
.AddAdditionalDtoOptions(enableImages, enableUserData, imageTypeLimit, enableImageTypes);
var channelResult = _liveTvManager.GetInternalChannels(
@@ -242,8 +241,7 @@ public class LiveTvController : BaseJellyfinApiController
return NotFound();
}
var dtoOptions = new DtoOptions()
.AddClientFields(User);
var dtoOptions = new DtoOptions();
return _dtoService.GetBaseItemDto(item, dtoOptions, user);
}
@@ -297,7 +295,6 @@ public class LiveTvController : BaseJellyfinApiController
{
userId = RequestHelpers.GetUserId(User, userId);
var dtoOptions = new DtoOptions { Fields = fields }
.AddClientFields(User)
.AddAdditionalDtoOptions(enableImages, enableUserData, imageTypeLimit, enableImageTypes);
return await _liveTvManager.GetRecordingsAsync(
@@ -444,8 +441,7 @@ public class LiveTvController : BaseJellyfinApiController
return NotFound();
}
var dtoOptions = new DtoOptions()
.AddClientFields(User);
var dtoOptions = new DtoOptions();
return _dtoService.GetBaseItemDto(item, dtoOptions, user);
}
@@ -635,7 +631,6 @@ public class LiveTvController : BaseJellyfinApiController
}
var dtoOptions = new DtoOptions { Fields = fields }
.AddClientFields(User)
.AddAdditionalDtoOptions(enableImages, enableUserData, imageTypeLimit, enableImageTypes);
return await _liveTvManager.GetPrograms(query, dtoOptions, CancellationToken.None).ConfigureAwait(false);
}
@@ -690,7 +685,6 @@ public class LiveTvController : BaseJellyfinApiController
}
var dtoOptions = new DtoOptions { Fields = body.Fields ?? [] }
.AddClientFields(User)
.AddAdditionalDtoOptions(body.EnableImages, body.EnableUserData, body.ImageTypeLimit, body.EnableImageTypes ?? []);
return await _liveTvManager.GetPrograms(query, dtoOptions, CancellationToken.None).ConfigureAwait(false);
}
@@ -760,7 +754,6 @@ public class LiveTvController : BaseJellyfinApiController
};
var dtoOptions = new DtoOptions { Fields = fields }
.AddClientFields(User)
.AddAdditionalDtoOptions(enableImages, enableUserData, imageTypeLimit, enableImageTypes);
return await _liveTvManager.GetRecommendedProgramsAsync(query, dtoOptions, CancellationToken.None).ConfigureAwait(false);
}

View File

@@ -74,8 +74,7 @@ public class MoviesController : BaseJellyfinApiController
var user = userId.IsNullOrEmpty()
? null
: _userManager.GetUserById(userId.Value);
var dtoOptions = new DtoOptions { Fields = fields }
.AddClientFields(User);
var dtoOptions = new DtoOptions { Fields = fields };
var categories = new List<RecommendationDto>();

View File

@@ -94,7 +94,6 @@ public class MusicGenresController : BaseJellyfinApiController
{
userId = RequestHelpers.GetUserId(User, userId);
var dtoOptions = new DtoOptions { Fields = fields }
.AddClientFields(User)
.AddAdditionalDtoOptions(enableImages, false, imageTypeLimit, enableImageTypes);
User? user = userId.IsNullOrEmpty()
@@ -148,7 +147,7 @@ public class MusicGenresController : BaseJellyfinApiController
public ActionResult<BaseItemDto> GetMusicGenre([FromRoute, Required] string genreName, [FromQuery] Guid? userId)
{
userId = RequestHelpers.GetUserId(User, userId);
var dtoOptions = new DtoOptions().AddClientFields(User);
var dtoOptions = new DtoOptions();
MusicGenre? item;

View File

@@ -81,7 +81,6 @@ public class PersonsController : BaseJellyfinApiController
{
userId = RequestHelpers.GetUserId(User, userId);
var dtoOptions = new DtoOptions { Fields = fields }
.AddClientFields(User)
.AddAdditionalDtoOptions(enableImages, enableUserData, imageTypeLimit, enableImageTypes);
User? user = userId.IsNullOrEmpty()
@@ -121,8 +120,7 @@ public class PersonsController : BaseJellyfinApiController
public ActionResult<BaseItemDto> GetPerson([FromRoute, Required] string name, [FromQuery] Guid? userId)
{
userId = RequestHelpers.GetUserId(User, userId);
var dtoOptions = new DtoOptions()
.AddClientFields(User);
var dtoOptions = new DtoOptions();
var item = _libraryManager.GetPerson(name);
if (item is null)

View File

@@ -548,7 +548,6 @@ public class PlaylistsController : BaseJellyfinApiController
}
var dtoOptions = new DtoOptions { Fields = fields }
.AddClientFields(User)
.AddAdditionalDtoOptions(enableImages, enableUserData, imageTypeLimit, enableImageTypes);
var dtos = _dtoService.GetBaseItemDtos(items.Select(i => i.Item2).ToList(), dtoOptions, user);

View File

@@ -89,7 +89,6 @@ public class StudiosController : BaseJellyfinApiController
{
userId = RequestHelpers.GetUserId(User, userId);
var dtoOptions = new DtoOptions { Fields = fields }
.AddClientFields(User)
.AddAdditionalDtoOptions(enableImages, enableUserData, imageTypeLimit, enableImageTypes);
User? user = userId.IsNullOrEmpty()
@@ -142,7 +141,7 @@ public class StudiosController : BaseJellyfinApiController
public ActionResult<BaseItemDto> GetStudio([FromRoute, Required] string name, [FromQuery] Guid? userId)
{
userId = RequestHelpers.GetUserId(User, userId);
var dtoOptions = new DtoOptions().AddClientFields(User);
var dtoOptions = new DtoOptions();
var item = _libraryManager.GetStudio(name);
if (!userId.IsNullOrEmpty())

View File

@@ -77,7 +77,7 @@ public class SuggestionsController : BaseJellyfinApiController
user = _userManager.GetUserById(requestUserId);
}
var dtoOptions = new DtoOptions().AddClientFields(User);
var dtoOptions = new DtoOptions();
var result = _libraryManager.GetItemsResult(new InternalItemsQuery(user)
{
OrderBy = new[] { (ItemSortBy.Random, SortOrder.Descending) },

View File

@@ -99,7 +99,6 @@ public class TvShowsController : BaseJellyfinApiController
}
var options = new DtoOptions { Fields = fields }
.AddClientFields(User)
.AddAdditionalDtoOptions(enableImages, enableUserData, imageTypeLimit, enableImageTypes);
var result = _tvSeriesManager.GetNextUp(
@@ -161,7 +160,6 @@ public class TvShowsController : BaseJellyfinApiController
var parentIdGuid = parentId ?? Guid.Empty;
var options = new DtoOptions { Fields = fields }
.AddClientFields(User)
.AddAdditionalDtoOptions(enableImages, enableUserData, imageTypeLimit, enableImageTypes);
var itemsResult = _libraryManager.GetItemList(new InternalItemsQuery(user)
@@ -231,7 +229,6 @@ public class TvShowsController : BaseJellyfinApiController
List<BaseItem> episodes;
var dtoOptions = new DtoOptions { Fields = fields }
.AddClientFields(User)
.AddAdditionalDtoOptions(enableImages, enableUserData, imageTypeLimit, enableImageTypes);
var shouldIncludeMissingEpisodes = (user is not null && user.DisplayMissingEpisodes) || User.GetIsApiKey();
@@ -360,7 +357,6 @@ public class TvShowsController : BaseJellyfinApiController
});
var dtoOptions = new DtoOptions { Fields = fields }
.AddClientFields(User)
.AddAdditionalDtoOptions(enableImages, enableUserData, imageTypeLimit, enableImageTypes);
var returnItems = _dtoService.GetBaseItemDtos(seasons, dtoOptions, user);

View File

@@ -94,7 +94,7 @@ public class UserLibraryController : BaseJellyfinApiController
await RefreshItemOnDemandIfNeeded(item).ConfigureAwait(false);
var dtoOptions = new DtoOptions().AddClientFields(User);
var dtoOptions = new DtoOptions();
return _dtoService.GetBaseItemDto(item, dtoOptions, user);
}
@@ -133,7 +133,7 @@ public class UserLibraryController : BaseJellyfinApiController
}
var item = _libraryManager.GetUserRootFolder();
var dtoOptions = new DtoOptions().AddClientFields(User);
var dtoOptions = new DtoOptions();
return _dtoService.GetBaseItemDto(item, dtoOptions, user);
}
@@ -180,7 +180,7 @@ public class UserLibraryController : BaseJellyfinApiController
}
var items = await _libraryManager.GetIntros(item, user).ConfigureAwait(false);
var dtoOptions = new DtoOptions().AddClientFields(User);
var dtoOptions = new DtoOptions();
var dtos = items.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user)).ToArray();
return new QueryResult<BaseItemDto>(dtos);
@@ -422,7 +422,7 @@ public class UserLibraryController : BaseJellyfinApiController
return NotFound();
}
var dtoOptions = new DtoOptions().AddClientFields(User);
var dtoOptions = new DtoOptions();
if (item is IHasTrailers hasTrailers)
{
var trailers = hasTrailers.LocalTrailers;
@@ -478,7 +478,7 @@ public class UserLibraryController : BaseJellyfinApiController
return NotFound();
}
var dtoOptions = new DtoOptions().AddClientFields(User);
var dtoOptions = new DtoOptions();
return Ok(item
.GetExtras()
@@ -549,7 +549,6 @@ public class UserLibraryController : BaseJellyfinApiController
}
var dtoOptions = new DtoOptions { Fields = fields }
.AddClientFields(User)
.AddAdditionalDtoOptions(enableImages, enableUserData, imageTypeLimit, enableImageTypes);
var list = _userViewManager.GetLatestItems(

View File

@@ -86,7 +86,7 @@ public class UserViewsController : BaseJellyfinApiController
var folders = _userViewManager.GetUserViews(query);
var dtoOptions = new DtoOptions().AddClientFields(User);
var dtoOptions = new DtoOptions();
dtoOptions.Fields = [..dtoOptions.Fields, ItemFields.PrimaryImageAspectRatio, ItemFields.DisplayPreferencesId];
var dtos = Array.ConvertAll(folders, i => _dtoService.GetBaseItemDto(i, dtoOptions, user));

View File

@@ -111,7 +111,6 @@ public class VideosController : BaseJellyfinApiController
}
var dtoOptions = new DtoOptions();
dtoOptions = dtoOptions.AddClientFields(User);
BaseItemDto[] items;
if (item is Video video)

View File

@@ -89,7 +89,6 @@ public class YearsController : BaseJellyfinApiController
{
userId = RequestHelpers.GetUserId(User, userId);
var dtoOptions = new DtoOptions { Fields = fields }
.AddClientFields(User)
.AddAdditionalDtoOptions(enableImages, enableUserData, imageTypeLimit, enableImageTypes);
User? user = userId.IsNullOrEmpty()
@@ -108,6 +107,7 @@ public class YearsController : BaseJellyfinApiController
bool Filter(BaseItem i) => FilterItem(i, excludeItemTypes, includeItemTypes, mediaTypes);
IReadOnlyList<BaseItem> items;
int totalCount = -1;
if (parentItem.IsFolder)
{
var folder = (Folder)parentItem;
@@ -118,7 +118,7 @@ public class YearsController : BaseJellyfinApiController
}
else
{
items = recursive ? folder.GetRecursiveChildren(user, query) : folder.GetChildren(user, true).Where(Filter).ToArray();
items = recursive ? folder.GetRecursiveChildren(user, query, out totalCount) : folder.GetChildren(user, true).Where(Filter).ToArray();
}
}
else
@@ -153,7 +153,7 @@ public class YearsController : BaseJellyfinApiController
var result = new QueryResult<BaseItemDto>(
startIndex,
ibnItemsArray.Count,
totalCount == -1 ? ibnItemsArray.Count : totalCount,
dtos.Where(i => i is not null).ToArray());
return result;
}
@@ -181,8 +181,7 @@ public class YearsController : BaseJellyfinApiController
return NotFound();
}
var dtoOptions = new DtoOptions()
.AddClientFields(User);
var dtoOptions = new DtoOptions();
if (!userId.IsNullOrEmpty())
{

View File

@@ -1,10 +1,6 @@
using System;
using System.Collections.Generic;
using System.Security.Claims;
using Jellyfin.Extensions;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Querying;
namespace Jellyfin.Api.Extensions;
@@ -13,55 +9,6 @@ namespace Jellyfin.Api.Extensions;
/// </summary>
public static class DtoExtensions
{
/// <summary>
/// Add additional fields depending on client.
/// </summary>
/// <remarks>
/// Use in place of GetDtoOptions.
/// Legacy order: 2.
/// </remarks>
/// <param name="dtoOptions">DtoOptions object.</param>
/// <param name="user">Current claims principal.</param>
/// <returns>Modified DtoOptions object.</returns>
internal static DtoOptions AddClientFields(
this DtoOptions dtoOptions, ClaimsPrincipal user)
{
string? client = user.GetClient();
// No client in claim
if (string.IsNullOrEmpty(client))
{
return dtoOptions;
}
if (!dtoOptions.ContainsField(ItemFields.RecursiveItemCount))
{
if (client.Contains("kodi", StringComparison.OrdinalIgnoreCase) ||
client.Contains("wmc", StringComparison.OrdinalIgnoreCase) ||
client.Contains("media center", StringComparison.OrdinalIgnoreCase) ||
client.Contains("classic", StringComparison.OrdinalIgnoreCase))
{
dtoOptions.Fields = [..dtoOptions.Fields, ItemFields.RecursiveItemCount];
}
}
if (!dtoOptions.ContainsField(ItemFields.ChildCount))
{
if (client.Contains("kodi", StringComparison.OrdinalIgnoreCase) ||
client.Contains("wmc", StringComparison.OrdinalIgnoreCase) ||
client.Contains("media center", StringComparison.OrdinalIgnoreCase) ||
client.Contains("classic", StringComparison.OrdinalIgnoreCase) ||
client.Contains("roku", StringComparison.OrdinalIgnoreCase) ||
client.Contains("samsung", StringComparison.OrdinalIgnoreCase) ||
client.Contains("androidtv", StringComparison.OrdinalIgnoreCase))
{
dtoOptions.Fields = [..dtoOptions.Fields, ItemFields.ChildCount];
}
}
return dtoOptions;
}
/// <summary>
/// Add additional DtoOptions.
/// </summary>

View File

@@ -1,4 +1,8 @@
using System;
using System.Net.Mime;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Formatters;
namespace Jellyfin.Api.Formatters;
@@ -6,7 +10,7 @@ namespace Jellyfin.Api.Formatters;
/// <summary>
/// Xml output formatter.
/// </summary>
public sealed class XmlOutputFormatter : StringOutputFormatter
public sealed class XmlOutputFormatter : TextOutputFormatter
{
/// <summary>
/// Initializes a new instance of the <see cref="XmlOutputFormatter"/> class.
@@ -15,5 +19,24 @@ public sealed class XmlOutputFormatter : StringOutputFormatter
{
SupportedMediaTypes.Clear();
SupportedMediaTypes.Add(MediaTypeNames.Text.Xml);
SupportedEncodings.Add(Encoding.UTF8);
SupportedEncodings.Add(Encoding.Unicode);
}
/// <inheritdoc />
public override async Task WriteResponseBodyAsync(OutputFormatterWriteContext context, Encoding selectedEncoding)
{
ArgumentNullException.ThrowIfNull(context);
ArgumentNullException.ThrowIfNull(selectedEncoding);
var valueAsString = context.Object?.ToString();
if (string.IsNullOrEmpty(valueAsString))
{
return;
}
var response = context.HttpContext.Response;
await response.WriteAsync(valueAsString, selectedEncoding).ConfigureAwait(false);
}
}

View File

@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Jellyfin.Data;
using Jellyfin.Database.Implementations.Enums;
@@ -56,6 +57,21 @@ public class SessionInfoWebSocketListener : BasePeriodicWebSocketListener<IEnume
return Task.FromResult(_sessionManager.Sessions);
}
/// <inheritdoc />
protected override Task<IEnumerable<SessionInfo>> GetDataToSendForConnection(IWebSocketConnection connection)
{
// For non-admin users, filter the sessions to only include their own sessions
if (connection.AuthorizationInfo?.User is not null &&
!connection.AuthorizationInfo.IsApiKey &&
!connection.AuthorizationInfo.User.HasPermission(PermissionKind.IsAdministrator))
{
var userId = connection.AuthorizationInfo.User.Id;
return Task.FromResult(_sessionManager.Sessions.Where(s => s.UserId.Equals(userId) || s.ContainsUser(userId)));
}
return Task.FromResult(_sessionManager.Sessions);
}
/// <inheritdoc />
protected override async ValueTask DisposeAsyncCore()
{
@@ -80,11 +96,10 @@ public class SessionInfoWebSocketListener : BasePeriodicWebSocketListener<IEnume
/// <param name="message">The message.</param>
protected override void Start(WebSocketMessageInfo message)
{
if (!message.Connection.AuthorizationInfo.IsApiKey
&& (message.Connection.AuthorizationInfo.User is null
|| !message.Connection.AuthorizationInfo.User.HasPermission(PermissionKind.IsAdministrator)))
// Allow all authenticated users to subscribe to session information
if (message.Connection.AuthorizationInfo.User is null && !message.Connection.AuthorizationInfo.IsApiKey)
{
throw new AuthenticationException("Only admin users can subscribe to session information.");
throw new AuthenticationException("User must be authenticated to subscribe to session Information.");
}
base.Start(message);

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