Compare commits

...

1490 Commits

Author SHA1 Message Date
Bond-009
45cb5a0008 Merge pull request #15704 from theguymadmax/add-cpu-to-template
Add CPU to issue template
2025-12-05 20:50:59 +01:00
Bond-009
ea097fb1a3 Merge pull request #15706 from jellyfin/renovate/ci-deps
Update CI dependencies
2025-12-05 20:47:46 +01:00
renovate[bot]
a25b48b151 Update CI dependencies 2025-12-05 18:58:06 +00:00
Furqaan Dawood
873f1d9e83 Added translation using Weblate (Swahili) 2025-12-04 14:41:47 +00:00
Bond-009
294439bf74 Merge pull request #15682 from jellyfin/renovate/ci-deps
Update CI dependencies
2025-12-03 20:05:29 +01:00
crobibero
6e74be0d46 Backport pull request #15672 from jellyfin/release-10.11.z
Cache OpenApi document generation

Original-merge: 8cd5652157

Merged-by: anthonylavado <anthony@lavado.ca>

Backported-by: Bond_009 <bond.009@outlook.com>
2025-12-03 14:04:28 -05:00
nyanmisaka
deb81eae10 Backport pull request #15670 from jellyfin/release-10.11.z
Fix the empty output of trickplay on RK3576

Original-merge: 98d1d0cb35

Merged-by: nielsvanvelzen <nielsvanvelzen@users.noreply.github.com>

Backported-by: Bond_009 <bond.009@outlook.com>
2025-12-03 14:04:27 -05:00
theguymadmax
70dcf3f7b3 Backport pull request #15594 from jellyfin/release-10.11.z
Fix isMovie filter logic

Original-merge: 94f3725208

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

Backported-by: Bond_009 <bond.009@outlook.com>
2025-12-03 14:04:25 -05:00
QuintonQu
ebcfed83c4 Backport pull request #15582 from jellyfin/release-10.11.z
Add hidden file check in BdInfoDirectoryInfo.cs.

Original-merge: 29b3aa8543

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

Backported-by: Bond_009 <bond.009@outlook.com>
2025-12-03 14:04:24 -05:00
theguymadmax
5d46278584 Backport pull request #15568 from jellyfin/release-10.11.z
Fix ResolveLinkTarget crashing on exFAT drives

Original-merge: fbb9a0b2c7

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

Backported-by: Bond_009 <bond.009@outlook.com>
2025-12-03 14:04:23 -05:00
theguymadmax
4f020a947a Backport pull request #15564 from jellyfin/release-10.11.z
Fix locked fields not saving

Original-merge: 0ee81e87be

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

Backported-by: Bond_009 <bond.009@outlook.com>
2025-12-03 14:04:22 -05:00
theguymadmax
3460d1de3c Backport pull request #15563 from jellyfin/release-10.11.z
Save item to database before providers run to prevent FK errors

Original-merge: c491a918c2

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

Backported-by: Bond_009 <bond.009@outlook.com>
2025-12-03 14:04:20 -05:00
gnattu
7d2e4cd817 Backport pull request #15557 from jellyfin/release-10.11.z
Restrict first video frame probing to file protocol

Original-merge: ee7ad83427

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

Backported-by: Bond_009 <bond.009@outlook.com>
2025-12-03 14:04:19 -05:00
gnattu
8cd6ef37c4 Backport pull request #15556 from jellyfin/release-10.11.z
Prevent copying HDR streams when only SDR is supported

Original-merge: 1e7e46cb82

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

Backported-by: Bond_009 <bond.009@outlook.com>
2025-12-03 14:04:18 -05:00
theguymadmax
e4daaf0d83 Backport pull request #15548 from jellyfin/release-10.11.z
Fix NullReferenceException in filesystem path comparison

Original-merge: 5ae444d96d

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

Backported-by: Bond_009 <bond.009@outlook.com>
2025-12-03 14:04:17 -05:00
theguymadmax
69c98af9f9 Add CPU to issue template 2025-12-03 09:45:50 -05:00
renovate[bot]
7425a493ee Update CI dependencies 2025-12-03 05:30:25 +00:00
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
Joshua M. Boniface
a2c0799489 Merge commit from fork
Remove server side processing for profile picture and splash screen
2025-08-13 18:08:43 -04:00
evan314159
ad133eb6b9 Fix AlbumArtistIds filter to use correct ItemValueType (#14641) 2025-08-13 05:52:54 -06:00
Alex Collado
50180adc53 Change Spanish; Latin code acording to BCP 47 specification (#14639) 2025-08-13 07:33:58 +02:00
Cody Robibero
bd94ca3071 Merge pull request #14634 from crobibero/itemname-counts 2025-08-12 20:20:54 -06:00
Bond-009
869b4f8bbf Merge pull request #14636 from jellyfin/renovate/ci-deps
Update github/codeql-action action to v3.29.9
2025-08-12 23:22:55 +02:00
renovate[bot]
a4d856360b Update github/codeql-action action to v3.29.9 2025-08-12 15:49:37 +00:00
Cody Robibero
beca405ad4 Refactor to pull item counts in a single query 2025-08-11 21:06:04 -06:00
renovate[bot]
c0be325b89 Update actions/checkout action to v5 (#14631)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-11 13:06:47 -06:00
renovate[bot]
dea500b26b Update dependency UTF.Unknown to 2.6.0 (#14599)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Bond_009 <bond.009@outlook.com>
2025-08-11 13:06:24 -06:00
evan314159
47634e731a Refactor query from EXISTS to JOIN to avoid API timeouts with large libraries (#14557) 2025-08-11 13:05:13 -06:00
Bond-009
cd1d11366e Merge pull request #14615 from jellyfin/renovate/z440.atl.core-7.x
Update dependency z440.atl.core to 7.3.0
2025-08-11 18:25:32 +02:00
Bond-009
76dfaead8b Merge pull request #14612 from jellyfin/renovate/ci-deps
Update CI dependencies
2025-08-11 18:06:01 +02:00
Evan
5eef85f027 move new TaggedItemCounts to its own file 2025-08-11 20:49:06 +08:00
renovate[bot]
e6a7530ced Update CI dependencies 2025-08-11 11:22:48 +00:00
renovate[bot]
00be664b9e Update dependency z440.atl.core to 7.3.0 2025-08-10 15:15:27 +00:00
Thunderstrike116
e1d0f7d1e5 Translated using Weblate (Greek)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/el/
2025-08-10 13:57:29 +00:00
Evan
0a4ff3f3c0 Fix GetBaseItemDto to return related item counts via SQL count
For API call /Items/{item id} GetBaseItemDto will return the counts of related items e.g. artists, albums, songs.  GetBaseItemDto currently does this by calling GetTaggedItems which retrieves the objects into memory to count them.  Replace with SQL count.

Fixes:
This should be an improvement for any large libraries, but especially large music libraries.  Example:

Request Library -> Genres -> any very popular genre in your large library, e.g. Classical
Number of albums = 1552, songs = 23515, ...

- Before change: Try to retrieve 1552 albums, 23515 songs, ... in memory, API never returns, database on fire
- After change: API returns in 367ms and Genre view opens with 200 albums in 2 seconds

I verified the numbers returned are correct but note that there is a bug somewhere else in Jellyfin that is setting TopParentId to NULL for a large portion of my MusicArtists, which causes them to not be counted by the existing GetCount().  This is not related to this change, also happens with the existing code, and does not seem to affect the Web UI.

Includes Cory's changes in:
- https://github.com/jellyfin/jellyfin/pull/14610#issuecomment-3172211468
- https://github.com/jellyfin/jellyfin/pull/14610#issuecomment-3172239154
2025-08-10 18:02:17 +08:00
NarohC
21f214b1a6 Translated using Weblate (Spanish (Mexico))
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/es_MX/
2025-08-10 07:38:46 +00:00
Tim Eisele
0650666497 Always save images (#14600) 2025-08-09 08:24:26 -06:00
Bond-009
877899dcc2 Merge pull request #14583 from jellyfin/renovate/dotnet-monorepo
Update dependency dotnet-ef to 9.0.8
2025-08-08 19:41:37 +02:00
Bond-009
bf2f8ec633 Merge pull request #14584 from jellyfin/renovate/microsoft
Update Microsoft to 9.0.8
2025-08-08 19:41:16 +02:00
Bond-009
2eff03b03e Merge pull request #14606 from jellyfin/renovate/ci-deps
Update github/codeql-action action to v3.29.8
2025-08-08 19:26:18 +02:00
renovate[bot]
103932e4fb Update github/codeql-action action to v3.29.8 2025-08-08 14:31:59 +00:00
Niels van Velzen
2b94b3b5f6 Merge pull request #14597 from jellyfin/renovate/svg.skia-3.x
Update dependency Svg.Skia to 3.0.5
2025-08-07 22:05:37 +02:00
Niels van Velzen
64032e8656 Merge pull request #14604 from jellyfin/renovate/ci-deps
Update github/codeql-action action to v3.29.6
2025-08-07 22:04:24 +02:00
renovate[bot]
329ce8d4c2 Update Microsoft to 9.0.8 2025-08-07 19:51:21 +00:00
renovate[bot]
2a7c924904 Update github/codeql-action action to v3.29.6 2025-08-07 19:51:15 +00:00
renovate[bot]
72664a68bc Update dependency Svg.Skia to 3.0.5 2025-08-07 19:51:12 +00:00
renovate[bot]
3ec123b616 Update dependency dotnet-ef to 9.0.8 2025-08-07 19:51:05 +00:00
Niels van Velzen
376220661b Merge pull request #14593 from Bond-009/revert
Revert "Merge pull request #13604 from Jxiced/master"
2025-08-07 21:49:59 +02:00
Lotine Guille
9e88121647 Translated using Weblate (English (Pirate))
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/en@pirate/
2025-08-07 01:15:12 +00:00
Bond_009
c7c7b30d28 Revert "Merge pull request #13604 from Jxiced/master"
This reverts commit ce78af2ed4, reversing
changes made to db7465e83d.
2025-08-06 15:49:40 +02:00
Bond-009
601ce4c3b1 Merge pull request #14590 from jellyfin/renovate/major-github-artifact-actions
Update actions/download-artifact action to v5
2025-08-06 15:45:12 +02:00
Nick
fcc7f53e81 Translated using Weblate (Uzbek)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/uz/
2025-08-06 05:11:07 +00:00
newton181
e3acf08acc Translated using Weblate (Spanish (Latin America))
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/es_419/
2025-08-06 05:11:07 +00:00
renovate[bot]
c60139a32c Update actions/download-artifact action to v5 2025-08-05 22:10:49 +00:00
Niels van Velzen
6d4efe6523 Translated using Weblate (Norwegian Nynorsk)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/nn/
2025-08-05 05:28:20 +00:00
Erick Marx
43a955dded Translated using Weblate (Portuguese)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/pt/
2025-08-04 13:27:28 +00:00
Joshua M. Boniface
5cae44fdf7 Merge pull request #12718 from IceStormNG/extract-mks-subtitles
Extract subtitles of MKS aux files if they're extractable.
2025-08-03 17:31:13 -04:00
Joshua M. Boniface
c3cb5fd2f9 Merge pull request #14021 from sususu98/enhancement/strmSeek
Enhanced HTTP Range request support for. strm file
2025-08-03 17:30:45 -04:00
Joshua M. Boniface
1262ac31dc Merge pull request #14410 from dyphire/language
Further refinement of BCP 47 language labeling support
2025-08-03 17:29:40 -04:00
Joshua M. Boniface
0f5bb5cf76 Merge pull request #14540 from TokerX/issue-8641
Improve extra rule resolution and file handling
2025-08-03 17:29:04 -04:00
Joshua M. Boniface
ce78af2ed4 Merge pull request #13604 from Jxiced/master
Prevent whitespaces in username during wizard setup
2025-08-03 17:27:50 -04:00
Joshua M. Boniface
4b6fb6c4bb Merge branch 'master' into master 2025-08-03 17:27:17 -04:00
Niels van Velzen
db7465e83d Merge pull request #14567 from Shadowghost/skip-image-failure
Don't fail image saving on missing BaseItem
2025-08-03 18:47:50 +02:00
Shadowghost
803e87ca5f Don't fail image saving on missing BaseItem 2025-08-02 22:10:39 +02:00
Bond-009
9e36fa4263 Merge pull request #14553 from nyanmisaka/fix-fmp4-ignore-audio-delay
Add extra movflags to fMP4 to take initial audio delay into account
2025-08-01 10:31:00 +02:00
Bond-009
a52a230778 Merge pull request #14467 from jkhsjdhjs/keyframe-only-trickplay-extraction-fallback
Add fallback for keyframe-only trickplay extraction
2025-08-01 10:30:24 +02:00
Niels van Velzen
b00e381109 Merge pull request #14554 from JPVenson/feature/FixIsFolderMigration
Also migrate IsFolder
2025-07-31 16:07:48 +02:00
Hestadgard
b8fb8bd608 Translated using Weblate (Norwegian Nynorsk)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/nn/
2025-07-31 07:52:58 +00:00
nomener
34c9adef80 Translated using Weblate (German)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/de/
2025-07-31 07:25:36 +00:00
JPVenson
c8d2f43660 Add logging 2025-07-30 20:14:24 +00:00
JPVenson
ef733c5ace use guid instead 2025-07-30 20:10:26 +00:00
JPVenson
a1eb04dc0b Add full migration for IsFolder flag 2025-07-30 19:58:56 +00:00
JPVenson
711e649e35 Also migrate IsFolder 2025-07-30 19:41:34 +00:00
Hestadgard
1d408a1503 Translated using Weblate (Norwegian Nynorsk)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/nn/
2025-07-30 17:29:30 +00:00
Hestadgard
6391dd9570 Translated using Weblate (Norwegian Bokmål)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/nb_NO/
2025-07-30 17:29:29 +00:00
dyphire
2007815fa6 Further refinement of BCP 47 language labeling support 2025-07-30 22:15:37 +08:00
nyanmisaka
a5b4eca804 Add extra movflags to fMP4 to take initial audio delay into account
Signed-off-by: nyanmisaka <nst799610810@gmail.com>
2025-07-30 18:00:14 +08:00
Bond-009
76d498ac9d Merge pull request #14530 from jellyfin/renovate/ci-deps
Update CI dependencies
2025-07-30 10:55:40 +02:00
dikson804
90b4345cfd 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-07-30 05:11:20 +00:00
renovate[bot]
317192c23d Update CI dependencies 2025-07-30 03:59:51 +00:00
Ghouri
dcb12a73fb Translated using Weblate (Norwegian Nynorsk)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/nn/
2025-07-29 08:13:35 +00:00
Hossain Rizbi
b15abddfd7 Translated using Weblate (Bengali)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/bn/
2025-07-28 21:19:19 +00:00
Hossain Rizbi
cfde5af3b0 Translated using Weblate (Bengali)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/bn/
2025-07-28 20:57:07 +00:00
Troj@
26a6cfaf65 Translated using Weblate (Belarusian)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/be/
2025-07-28 16:45:43 +00:00
theguymadmax
8a8018f0de Preserve interpunct (·) (#14543) 2025-07-27 20:09:50 -06:00
evan314159
6f49782b7b fix file modification date comparisons (#14503) 2025-07-27 20:08:06 -06:00
theguymadmax
536437bbe3 Fix allow and block queries (#14482) 2025-07-27 19:28:04 -06:00
Shane Powell
ba54cda774 Add progress reporting to AudioNormalizationTask. (#14306) 2025-07-27 19:27:24 -06:00
Piyush Rungta
e86315128d Ignore directory if empty .ignore file is present (#14536) 2025-07-27 19:22:12 -06:00
JPVenson
7320e10329 readd Format for splashscreen and user image 2025-07-27 23:12:40 +00:00
JPVenson
5b544bf1ed Remove even obsoleter code 2025-07-27 21:17:20 +00:00
JPVenson
1a1d9b2404 Remove obsolete code 2025-07-27 21:16:45 +00:00
JPVenson
96a05276a6 Removed all server side processing options from public endpoints for image gen 2025-07-27 21:15:18 +00:00
Bas
dfab2fb6e2 Translated using Weblate (Dutch)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/nl/
2025-07-27 18:34:20 +00:00
Sven Cazier
7785b51f57 Enhance extra rules for video and audio file naming; update tests for new naming conventions 2025-07-26 23:24:58 +02:00
Tim Eisele
a068f75623 Set DateLastSaved after running metadata savers (#14531) 2025-07-25 08:20:19 -06:00
Gargotaire
1ed191c5b3 Translated using Weblate (Catalan)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/ca/
2025-07-24 20:32:31 +00:00
Gargotaire
0e3fbb6abd Translated using Weblate (Catalan)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/ca/
2025-07-24 17:27:34 +00:00
Gargotaire
583a861b32 Translated using Weblate (Catalan)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/ca/
2025-07-24 02:15:06 +00:00
Zhelyan Radoev
3bcfe13652 Translated using Weblate (Bulgarian)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/bg/
2025-07-24 02:15:06 +00:00
Bond-009
f5a135a1db Merge pull request #14521 from jellyfin/renovate/ci-deps
Update github/codeql-action action to v3.29.4
2025-07-23 18:11:07 +02:00
renovate[bot]
0cea853b45 Update github/codeql-action action to v3.29.4 2025-07-23 15:32:24 +00:00
jkhsjdhjs
663087b155 Fix trickplay extraction ffmpeg error-handling (#14493) 2025-07-22 17:13:38 -06:00
Dan Watson
dddeea1f7b Fix issue with EncodedRecorder streams not showing up under "Active Recordings" (#14357) 2025-07-22 17:13:01 -06:00
renovate[bot]
a148a4ad02 Update dependency Svg.Skia to 3.0.4 (#14515) 2025-07-22 17:10:46 -06:00
JPVenson
57d077d08e Supress transaction (#14514) 2025-07-22 17:09:31 -06:00
Mylan1173
774be151aa Translated using Weblate (Hungarian)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/hu/
2025-07-22 12:19:37 +00:00
Bond-009
7569ac65a8 Merge pull request #14508 from jellyfin/renovate/ci-deps
Update github/codeql-action action to v3.29.3
2025-07-22 10:33:32 +02:00
zag
4621a99c7c Translated using Weblate (Malay)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/ms/
2025-07-22 08:21:51 +00:00
renovate[bot]
1e796e0b7a Update github/codeql-action action to v3.29.3 2025-07-21 21:06:53 +00:00
Jacob Rasmussen
4da5483ef4 Translated using Weblate (Danish)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/da/
2025-07-21 08:07:29 +00:00
theguymadmax
eea0872980 Fix Serbian ISO 639-2 codes (#14476) 2025-07-20 20:01:31 -06:00
Cody Robibero
36c90ce2ce Clean up and fix backup/restore (#14489) 2025-07-20 20:01:13 -06:00
Niels van Velzen
48e93dcbce Use RequestHelpers.GetSession in SessionWebSocketListener (#14494) 2025-07-20 20:00:47 -06:00
Gargotaire
6cee66119e Translated using Weblate (Catalan)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/ca/
2025-07-19 22:22:01 +00:00
JPVenson
c62a07405e improve userdata migration (#14488) 2025-07-19 11:34:51 -06:00
renovate[bot]
7bd08ab290 Update dependency NEbml to v1 (#14490) 2025-07-19 11:34:33 -06:00
renovate[bot]
088ef0d37a Update dependency z440.atl.core to 7.2.0 (#14496) 2025-07-19 11:34:11 -06:00
SaddFox
ba0f61ef2d Translated using Weblate (Slovenian)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/sl/
2025-07-18 21:18:23 +00:00
SaddFox
c70f6bffcf Translated using Weblate (Slovenian)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/sl/
2025-07-18 21:18:09 +00:00
JPVenson
21a6d6f0d6 Delete old migrations on restore (#14486) 2025-07-17 17:19:41 -06:00
queukat
aa77dfb92d Drawing: make SkiaEncoder more robust when reading image dimensions (#14481) 2025-07-17 17:19:33 -06:00
Stephan Sundermann
2ad37fe021 Ensure UserData stays unique on delete (#14475) 2025-07-17 17:19:26 -06:00
renovate[bot]
fd5205a6eb Update danielpalme/ReportGenerator-GitHub-Action action to v5.4.9 (#14485)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-17 09:20:39 +02:00
EinarGisla
60cfa65cdc Translated using Weblate (Icelandic)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/is/
2025-07-16 22:41:15 +00:00
madman38
e5139e1004 Translated using Weblate (Turkish)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/tr/
2025-07-16 14:41:36 +00:00
renovate[bot]
aa1abf8b94 Update dependency Diacritics to 4.0.17 (#14477) 2025-07-15 06:58:00 -06:00
sharanchius
742b5637fa Translated using Weblate (Lithuanian)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/lt/
2025-07-15 01:50:30 +00:00
Nyanmisaka
25a362345d Fix refreshing the library cannot delete old attachments (#14461) 2025-07-14 18:40:37 -06:00
JPVenson
310a54f090 Allow loading of Database options for DB provider (#14466) 2025-07-14 18:39:43 -06:00
renovate[bot]
e9d92bdcb0 Update dependency z440.atl.core to 7.1.0 (#14469)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-14 18:37:22 -06:00
FJOX.win
dc39a51475 vob file support (#14471) 2025-07-14 18:36:54 -06:00
JPVenson
c51f3a3342 Use IDatabaseCreator instead of relying on History repository (#14465) 2025-07-14 18:36:36 -06:00
sharanchius
7ece959f4e Translated using Weblate (Lithuanian)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/lt/
2025-07-14 15:23:01 +00:00
sharanchius
c96e828002 Translated using Weblate (Lithuanian)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/lt/
2025-07-14 13:43:39 +00:00
felix920506
ab56ceaa16 Translated using Weblate (Chinese (Traditional Han script))
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/zh_Hant/
2025-07-14 09:38:42 +00:00
sharanchius
4645633acf Translated using Weblate (Lithuanian)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/lt/
2025-07-14 09:38:42 +00:00
jkhsjdhjs
d6f93759ea Add myself to CONTRIBUTORS.md
I have contributed previously, but forgot to add myself last time.
2025-07-14 00:09:46 +02:00
jkhsjdhjs
bf3f37e3d0 Add fallback for keyframe-only trickplay extraction
Keyframe-only trickplay image extraction can fail for some media
files. The current behavior is to skip the media file and try again
on the next run, which will fail again.

This adds a fallback to regular non-keyframe-only extraction for
failed runs, so the extraction can complete.
2025-07-14 00:09:43 +02:00
renovate[bot]
982e0c9370 Update dependency Polly to 8.6.2 (#14455)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-12 09:47:56 +02:00
JPVenson
55e681b9a6 Add SerilogExpressions reference (#14438) 2025-07-11 23:38:41 -06:00
JPVenson
7ba77804c4 Added advanced parallel process calculation (#14437) 2025-07-11 23:27:13 -06:00
Bas
af6f5a8ed0 Translated using Weblate (Dutch)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/nl/
2025-07-11 18:13:18 +00:00
Ella Veter
1162fcebf8 Translated using Weblate (Dutch)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/nl/
2025-07-11 16:50:00 +00:00
renovate[bot]
38d0367c42 Update dependency dotnet-ef to 9.0.7 (#14440)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-09 00:47:46 +02:00
renovate[bot]
7d3372018f Update Microsoft to 9.0.7 (#14441)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-09 00:46:44 +02:00
renovate[bot]
8629831658 Update dependency z440.atl.core to v7 (#14391) 2025-07-07 18:10:48 -06:00
Nyanmisaka
db55d983f8 Only enable VAAPI MJPEG encoder on Intel iHD driver (#14433) 2025-07-07 18:05:14 -06:00
JPVenson
4d5ba8d7a5 Only save images when changed (#14425) 2025-07-07 09:14:01 -06:00
Bond-009
6d4169a449 Update dependency Diacritics to v4 (#14418)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-05 11:08:38 +02:00
Shane Powell
8dcb0bfecb Merge pull request #14309 from shanepowell/MediaInfoFixs
Fix PeopleHelper.AddPerson Exceptions due to bad meta-data extracts.
2025-07-04 19:22:27 +02:00
Bond-009
844d69ab64 Read ALBUMARTISTS in preference to ARTISTS when PreferNonstandardArtistsTag set (#14413)
Jellyfin implemented ARTISTS multivalue tag but did not implement the equivalent ALBUMARTISTS multivalue tag.  This change adds ALBUMARTISTS support.  If present and PreferNonstandardArtistsTag is set, ALBUMARTISTS will be used in preference to ALBUMARTIST.  As with ARTISTS, the intent is to offer support for multiple album artists without affecting software that does not read ALBUMARTIST as a multivalued tag.

Example album before/after:

    ALBUM           : Amici e Rivali
    ARTIST          : Lawrence Brownlee / Michael Spyres
    album_artist    : Lawrence Brownlee
    ARTISTS         : Lawrence Brownlee;Michael Spyres
    ALBUMARTISTS    : Lawrence Brownlee;Michael Spyres

Before ALBUMARTISTS support, Jellyfin reports:
    Album Artist: Lawrence Brownlee [hyperlinked]
    On each track Artist: Lawrence Brownlee, Michael Spyres

After ALBUMARTISTS support, Jellyfin reoprts:
    Album Artist: Lawrence Brownlee [hyperlinked], Michael Spyres [hyperlinked]
    On each track Artist: none shown (no other artists in source metadata)

This is ideal as both key artists are hyperlinkable from their albums.

References to other products implementing ALBUMARTISTS:
- Navidrome: https://www.navidrome.org/docs/usage/tagging-guidelines/#handling-multiple-artists-and-collaborations
- Kodi: https://kodi.wiki/view/Music_tagging#albumartists
- MusicBrainz Picard: https://picard-docs.musicbrainz.org/en/variables/variables_basic.html (_albumartists tag)

Co-authored-by: Evan <evan@MacBook-Pro.local>
2025-07-04 19:19:26 +02:00
Bond-009
5c36b44484 Fix seasons random (#13224) (#14335)
Sorting was always enabled so removed the `enableSorting` parameter
in QueryResult method.

Co-authored-by: Maxime <>
2025-07-04 19:18:38 +02:00
renovate[bot]
4e4d7e7764 Update github/codeql-action action to v3.29.2 (#14400)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-03 17:18:29 +02:00
renovate[bot]
4c268a3579 Update dependency Diacritics to v4 2025-07-03 15:15:02 +00:00
Yago Raña Gayoso
77bcd2f5f6 Translated using Weblate (Galician)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/gl/
2025-07-02 19:07:02 +00:00
Bill Thornton
8406924471 Merge pull request #14414 from thornbill/revert-pt-translations
Revert invalid Portuguese translations
2025-07-02 10:52:11 -04:00
Bill Thornton
67fd4ce187 Revert "Translated using Weblate (Portuguese)"
This reverts commit dde306b170.
2025-07-02 10:47:44 -04:00
Bill Thornton
b37b39773a Revert "Translated using Weblate (Portuguese)"
This reverts commit 9c817a97a9.
2025-07-02 10:47:31 -04:00
akshay
6f98767aed Translated using Weblate (Marathi)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/mr/
2025-07-02 09:49:41 +00:00
Tal Sarid
643460f484 Translated using Weblate (Hebrew)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/he/
2025-07-02 08:16:42 +00:00
Evan
a4231bf428 Read ALBUMARTISTS in preference to ARTISTS when PreferNonstandardArtistsTag set
Jellyfin implemented ARTISTS multivalue tag but did not implement the equivalent ALBUMARTISTS multivalue tag.  This change adds ALBUMARTISTS support.  If present and PreferNonstandardArtistsTag is set, ALBUMARTISTS will be used in preference to ALBUMARTIST.  As with ARTISTS, the intent is to offer support for multiple album artists without affecting software that does not read ALBUMARTIST as a multivalued tag.

Example album before/after:

    ALBUM           : Amici e Rivali
    ARTIST          : Lawrence Brownlee / Michael Spyres
    album_artist    : Lawrence Brownlee
    ARTISTS         : Lawrence Brownlee;Michael Spyres
    ALBUMARTISTS    : Lawrence Brownlee;Michael Spyres

Before ALBUMARTISTS support, Jellyfin reports:
    Album Artist: Lawrence Brownlee [hyperlinked]
    On each track Artist: Lawrence Brownlee, Michael Spyres

After ALBUMARTISTS support, Jellyfin reoprts:
    Album Artist: Lawrence Brownlee [hyperlinked], Michael Spyres [hyperlinked]
    On each track Artist: none shown (no other artists in source metadata)

This is ideal as both key artists are hyperlinkable from their albums.

References to other products implementing ALBUMARTISTS:
- Navidrome: https://www.navidrome.org/docs/usage/tagging-guidelines/#handling-multiple-artists-and-collaborations
- Kodi: https://kodi.wiki/view/Music_tagging#albumartists
- MusicBrainz Picard: https://picard-docs.musicbrainz.org/en/variables/variables_basic.html (_albumartists tag)
2025-07-02 07:55:24 +08:00
Edson
9c817a97a9 Translated using Weblate (Portuguese)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/pt/
2025-07-01 18:43:41 +00:00
dyphire
f9c4c9b345 Add additional chinese languages 2025-07-01 16:47:13 +08:00
Deleted User
dde306b170 Translated using Weblate (Portuguese)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/pt/
2025-07-01 08:19:32 +00:00
Tal Sarid
e2b61d951b Translated using Weblate (Hebrew)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/he/
2025-07-01 00:32:48 +00:00
Gargotaire
9eff25bfed Translated using Weblate (Catalan)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/ca/
2025-07-01 00:32:47 +00:00
Tommaso Morganti
ff4484eb4a Translated using Weblate (Italian)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/it/
2025-06-29 16:35:11 +00:00
Gargotaire
62b2adbf66 Translated using Weblate (Catalan)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/ca/
2025-06-29 16:35:11 +00:00
gnattu
9ac8c2a2fa Fix compiler warning for CodeMigration.cs (#14390) 2025-06-29 08:00:29 -06:00
renovate[bot]
90e72fb687 Update dependency BitFaster.Caching to 2.5.4 (#14392)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-29 10:23:38 +02:00
Acrotos
630846798d Translated using Weblate (Romanian)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/ro/
2025-06-28 20:50:29 +00:00
Petrică Andrei-Cosmin
9d5be19a27 Translated using Weblate (Romanian)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/ro/
2025-06-28 20:50:29 +00:00
renovate[bot]
6058ab50f8 Update github/codeql-action action to v3.29.1 (#14389)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-28 11:23:12 +02:00
Ruben Teixeira
e3b379052d Translated using Weblate (Portuguese (Portugal))
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/pt_PT/
2025-06-28 00:39:50 +00:00
Nirwan
0b6f4b2bd9 Translated using Weblate (Indonesian)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/id/
2025-06-27 11:27:47 +00:00
Varun Sudarshan
4f6db1bc22 Translated using Weblate (Kannada)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/kn/
2025-06-27 02:51:17 +00:00
Oatavandi
8c8c71125c Translated using Weblate (Tamil)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/ta/
2025-06-27 02:51:17 +00:00
Tim Eisele
c6e568692e Fix modification checks and make sure to use UTC (#14347) 2025-06-26 17:50:37 -06:00
Archie
d5a76bdff8 Changed misspell of 'temporarily' in 503 response (#14377) 2025-06-26 17:49:07 -06:00
Nyanmisaka
ebdc756547 Fix -fps_mode option being applied on input (#14379) 2025-06-26 17:48:43 -06:00
stelle
10d0cec7b9 Translated using Weblate (Malay)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/ms/
2025-06-25 13:51:17 +00:00
Hasan Abdulaal
10cc651790 Translated using Weblate (Arabic)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/ar/
2025-06-25 13:51:16 +00:00
theguymadmax
7d18f3d6ed Improve cast and crew handling (#14370) 2025-06-24 17:48:36 -06:00
Max Rumpf
9b8c12d433 Adapt LrcLyricParser to new LrcParser version (#14263) 2025-06-24 16:59:09 -06:00
JPVenson
ba0eb87371 Add migration to migrate disconnected UserData too (#14339) 2025-06-23 08:36:49 -06:00
Mason Weigand
d561cef81f RemoveNowPlayingItem should also set FullNowPlayingItem to null (#14360) bb 2025-06-23 08:31:25 -06:00
theguymadmax
b528c1100f Fix missing music genre metadata (#14332) 2025-06-23 08:30:59 -06:00
Tim Eisele
96c9f4fdad Make keyframe extraction task cancellable (#14368) 2025-06-23 08:29:42 -06:00
Onni Saarni
6d077fcf40 Translated using Weblate (Finnish)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/fi/
2025-06-22 07:12:05 +00:00
Niels van Velzen
ab99b2bad3 Merge pull request #14341 from Shadowghost/misc
Cleanup Migration
2025-06-22 08:49:24 +02:00
Tim Eisele
db36be7a6b Skip missing images when creating collages (#14344)
* Skip missing images when creating collages
2025-06-21 12:23:08 +02:00
Romulo Alves
85f158e1dd Translated using Weblate (Portuguese (Brazil))
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/pt_BR/
2025-06-20 03:36:14 +00:00
RingoJet
e1365bd253 Translated using Weblate (Arabic)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/ar/
2025-06-20 03:36:14 +00:00
Shoham Peller
1ec66adc30 fix(devcontainer): correct apt-packages path (#14235)
Feature path was incorrect, which failed the creation of the
devcontainer
2025-06-19 14:46:55 +02:00
Shadowghost
af0bcbc652 Fixup 2025-06-19 12:33:46 +02:00
Tim Eisele
b2312466e1 Update Jellyfin.Server.Implementations/Item/BaseItemRepository.cs
Co-authored-by: Bond-009 <bond.009@outlook.com>
2025-06-19 11:40:40 +02:00
Bond-009
cc7915c2e6 Merge pull request #14338 from jellyfin/renovate/polly-monorepo
Update dependency Polly to 8.6.1
2025-06-19 11:28:13 +02:00
Bond-009
a537c66da1 Merge pull request #14322 from gnattu/disable-hdr-non-hdr-clients
Don't check dynamic metadata removal for static HDR formats
2025-06-19 11:27:23 +02:00
Bond-009
a43adf42f3 Merge pull request #14324 from jellyfin/renovate/microsoft
Update dependency System.Linq.Async to 6.0.3
2025-06-19 11:26:54 +02:00
Bond-009
6996c8a1de Merge pull request #14330 from jellyfin/qsv-dx11-static-pool
Fix QSV "static surface pool size exceeded" on Windows
2025-06-19 11:26:37 +02:00
Bond-009
f976630003 Merge pull request #14333 from theguymadmax/add-act-naming-option
Add act as a stacking option for music albums
2025-06-19 11:25:46 +02:00
Bond-009
965cf93419 Merge pull request #14328 from crobibero/trickplay-info
Use dto instead of db object when returning trickplay
2025-06-19 11:24:03 +02:00
Bond-009
70ea3f863a Merge pull request #14327 from crobibero/fix-startup
Fix startup logger, startup health check
2025-06-19 11:20:35 +02:00
Tim Eisele
989aef18af Update Jellyfin.Server.Implementations/Item/BaseItemRepository.cs
Co-authored-by: Niels van Velzen <nielsvanvelzen@users.noreply.github.com>
2025-06-18 23:08:05 +02:00
Shadowghost
ccb917b8df Cleanup logging and user data import skip on missing user 2025-06-18 21:33:32 +02:00
queeup
7cf6389ab5 Translated using Weblate (Turkish)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/tr/
2025-06-18 15:47:10 +00:00
renovate[bot]
2473b89a8d Update dependency Polly to 8.6.1 2025-06-18 09:36:02 +00:00
Yusuke, Hirota
6575c69a4e Translated using Weblate (Japanese)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/ja/
2025-06-18 09:01:34 +00:00
nextlooper42
66d594836c Translated using Weblate (Slovak)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/sk/
2025-06-18 09:01:34 +00:00
Roi Gabay
43028f735f Translated using Weblate (Hebrew)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/he/
2025-06-18 09:01:34 +00:00
Maxime
e83b992eef Fix seasons random (#13224)
Sorting was always enabled so removed the `enableSorting` parameter
in QueryResult method.
2025-06-18 00:41:09 +02:00
theguymadmax
8368d10d1b Add act as a stacking option for music albums 2025-06-17 12:16:32 -04:00
Nyanmisaka
e8291fc856 Fix QSV "static surface pool size exceeded" on Windows
d3d11va doesn't support dynamic pool size, use vpp filter ctx to relay to prevent encoder async and bframes from exhausting the decoder pool.
2025-06-17 15:02:13 +08:00
Aindriú Mac Giolla Eoin
308707476d Translated using Weblate (Irish)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/ga/
2025-06-17 01:01:35 +00:00
Daniel Szente
e252589900 Translated using Weblate (Hungarian)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/hu/
2025-06-17 01:01:34 +00:00
Mathieu Funk
1220cac255 Translated using Weblate (English (United Kingdom))
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/en_GB/
2025-06-17 01:01:34 +00:00
Gallyam Biktashev
7218d82c21 Translated using Weblate (Russian)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/ru/
2025-06-17 01:01:34 +00:00
bdubz
a4524eb2ad Translated using Weblate (Spanish)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/es/
2025-06-17 01:01:34 +00:00
Thadah D. Denyse
553ba56389 Translated using Weblate (Basque)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/eu/
2025-06-17 01:01:34 +00:00
Cody Robibero
afa2103d42 Use dto instead of db object when returning trickplay 2025-06-16 18:55:21 -06:00
Cody Robibero
7256c9c89d Fix startup logger, startup health check 2025-06-16 18:32:29 -06:00
renovate[bot]
f3cdaeaa12 Update dependency System.Linq.Async to 6.0.3 2025-06-16 21:23:20 +00:00
gnattu
368808eba4 Don't check dynamic metadata removal for static HDR formats
Those videos have no metadata to be removed at all, just force transcoding when the client does not support it.
2025-06-17 02:29:16 +08:00
renovate[bot]
0fc8ed6aeb Update danielpalme/ReportGenerator-GitHub-Action action to v5.4.8 (#14316) 2025-06-16 09:15:23 +02:00
gnattu
f60281d8fd Use square root scaling for high framerate videos' bitrate requirements (#14314) 2025-06-15 15:22:49 -06:00
renovate[bot]
2936588c0f Update dependency z440.atl.core to 6.26.0 (#14315) 2025-06-15 15:21:38 -06:00
JPVenson
0e1be6ce30 Use proper scheduler that honors the parallel task limit (#14281) 2025-06-15 15:21:11 -06:00
JPVenson
4cd0a2ed8d Always set update action when item does not exist (#14304) 2025-06-15 15:19:57 -06:00
Tim Eisele
aa05185917 Only remove image file if it exists (#14302) 2025-06-15 15:19:30 -06:00
JPVenson
2d9257b203 Add explicit check for placeholder ID (#14298) 2025-06-15 12:07:19 -06:00
JPVenson
d1d9c8ed06 Remove appsettings.json loading component from startup server (#14275) 2025-06-13 15:26:09 -06:00
Ēvalds Zemturis
23c25289da Translated using Weblate (Latvian)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/lv/
2025-06-12 18:48:11 +00:00
DyingSlacker
aad6bca955 Translated using Weblate (Chinese (Simplified Han script))
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/zh_Hans/
2025-06-12 18:48:11 +00:00
Tim Eisele
9f0f9a276f Fix People Issues (#14284) 2025-06-12 05:21:01 -06:00
Bond-009
6016159860 Merge pull request #14287 from jellyfin/renovate/ci-deps
Update github/codeql-action action to v3.29.0
2025-06-12 13:13:04 +02:00
renovate[bot]
6ffc044af1 Update github/codeql-action action to v3.29.0 2025-06-11 23:31:43 +00:00
Tim Eisele
c22f24319b Properly handle file access issues in some cases (#14272) 2025-06-11 17:31:14 -06:00
JPVenson
1c4c9cf733 Fix UserData cleanup task and queries (#14280) 2025-06-11 17:30:57 -06:00
Battseren Badral
ea34a38f09 Translated using Weblate (Mongolian)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/mn/
2025-06-11 23:01:34 +00:00
stanol
bbcfb2f421 Translated using Weblate (Ukrainian)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/uk/
2025-06-11 23:01:34 +00:00
cmpsb
0873fa8a86 Translated using Weblate (Swedish)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/sv/
2025-06-11 23:01:34 +00:00
st7105
9dc50b4ac6 Translated using Weblate (Russian)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/ru/
2025-06-11 23:01:34 +00:00
Martin Just
617ab0d0ca Translated using Weblate (German)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/de/
2025-06-11 23:01:34 +00:00
Gargotaire
dee9629037 Translated using Weblate (Catalan)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/ca/
2025-06-11 23:01:33 +00:00
Bond-009
31f3b5f6bb Merge pull request #14279 from jellyfin/renovate/polly-8.x
Update dependency Polly to 8.6.0
2025-06-11 10:50:36 +02:00
renovate[bot]
2ac6a7ba3f Update dependency Polly to 8.6.0 2025-06-11 04:50:21 +00:00
hoanghuy309
ece77779f8 Translated using Weblate (Vietnamese)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/vi/
2025-06-10 22:37:54 +00:00
Dan Tsivinsky
c15c1f82a3 Translated using Weblate (Russian)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/ru/
2025-06-10 22:37:54 +00:00
Kityn
a15352b80c Translated using Weblate (Polish)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/pl/
2025-06-10 22:37:53 +00:00
Bas
304b944152 Translated using Weblate (Dutch)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/nl/
2025-06-10 22:37:53 +00:00
myrad2267
e81c8ac6d1 Translated using Weblate (French)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/fr/
2025-06-10 22:37:53 +00:00
myrad2267
97c1cb2f26 Translated using Weblate (French (Canada))
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/fr_CA/
2025-06-10 22:37:53 +00:00
Lukáš Kucharczyk
ac9d84f602 Translated using Weblate (Czech)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/cs/
2025-06-10 22:37:53 +00:00
Gargotaire
f3bf3c9853 Translated using Weblate (Catalan)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/ca/
2025-06-10 22:37:53 +00:00
renovate[bot]
644245bb7c Update dependency dotnet-ef to 9.0.6 (#14273)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-10 15:23:15 -06:00
renovate[bot]
a18c0007b4 Update Microsoft to 9.0.6 (#14274)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-10 15:22:59 -06:00
Niels van Velzen
c8a51160b4 Merge pull request #14269 from JPVenson/bugfix/BackupTableNames
Fix schema name on backup
2025-06-10 17:34:16 +02:00
JPVenson
4a0a45a045 Use explicit naming 2025-06-10 14:33:41 +00:00
JPVenson
91da1c035d Fix schema name on backup 2025-06-10 14:31:01 +00:00
ThunderClapLP
6b5ce934b3 Fix existing media segments not being handled on scan (#14218) 2025-06-10 07:45:09 -06:00
Niels van Velzen
7174bb6a93 Merge pull request #14264 from IDisposable/patch-1
chore/typo
2025-06-10 07:17:15 +02:00
Marc Brooks
7037121bd0 chore/typo
s/entires/entries
2025-06-09 19:58:25 -05:00
renovate[bot]
7417da0e5c Update dependency z440.atl.core to 6.25.0 (#14257)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-09 17:34:08 -06:00
Sid K
1e8bf1ce8d fix(Session): don't query DB if queue hasn't changed (#14244) 2025-06-09 17:33:28 -06:00
Dario Ackermann
d4c3d24e52 fix(collection): Do not lock newly created collections (#14259) 2025-06-09 17:32:31 -06:00
JPVenson
d3ad2aec60 Feature/persistent watch data (#14262) 2025-06-09 17:14:27 -06:00
JPVenson
3554f068fb Ignore null key virtual folders (#14253) 2025-06-09 06:20:04 -06:00
Niels van Velzen
6dac1fde0a Merge pull request #14255 from gnattu/pin-skia-3116
Pin Skiasharp version to 3.116.1
2025-06-09 12:15:59 +02:00
gnattu
56fe4a158e Add comment for version pin
Co-authored-by: JPVenson <ger-delta-07@hotmail.de>
2025-06-09 18:14:51 +08:00
Chatcharin Sangbutsarakum
c2332d340c Translated using Weblate (Thai)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/th/
2025-06-09 06:22:06 +00:00
gnattu
d5b5c71baf Pin Skiasharp version to 3.116.1
Any prebuilt version newer than that does not work with debian based arm64 system and currently build from source is the only way to use those versions. Pin the latest good version for now instead to make our life and our downstream packagers' life easier.
2025-06-09 10:15:44 +08:00
JPVenson
7aee5b1e70 Fix ExcludeItemId, ExcludeProviderIds and HasAnyProviderId filter (#14249) 2025-06-08 19:53:18 -06:00
JPVenson
a8601b3797 util forward headers on startup api (#14246) 2025-06-08 19:52:48 -06:00
JPVenson
1e9e4ffda9 Rework startup topic handling and reenable output to logging framework (#14243) 2025-06-08 19:52:39 -06:00
theguymadmax
d7faf9a327 Use filename for single videos (non-movie/null collections) in MovieResolver (#14162) 2025-06-08 19:52:25 -06:00
gnattu
bdb3adeb30 Don't attempt to do metadata removal for dovi without fallback (#14240) 2025-06-08 07:29:17 -06:00
JPVenson
1f5cfb1e23 Only show log in Local network (#14241) 2025-06-08 07:28:37 -06:00
Niels van Velzen
c2cc27a8a9 Merge pull request #12908 from scampower3/search-for-missing-overrides-existing
Fix search for missing metadata overriding existing metadata
2025-06-07 21:56:46 +02:00
Niels van Velzen
f4bce38ddb Merge pull request #14209 from theguymadmax/themoviedb-year-cache-key
Add year parameter to TMDB series cache key
2025-06-07 21:56:30 +02:00
Niels van Velzen
547b8cafb1 Merge pull request #13307 from qiqian/master
always sort season by index number
2025-06-07 21:52:01 +02:00
Carsten Braun
98daf4aedb Use string.IsNullOrEmpty instead of regular null check. 2025-06-07 21:51:08 +02:00
Carsten Braun
fcf56b73cb When subtitle is embedded in the main video file, the path will be null. 2025-06-07 21:51:08 +02:00
Carsten Braun
e8239a7ee2 Do not attempt to extract internal subtitles if there are only MKS subtitles. 2025-06-07 21:51:08 +02:00
Carsten Braun
84cebeae64 Skip early if subtitle is in MKS to avoid unnecessary function calls. 2025-06-07 21:51:08 +02:00
Carsten Braun
c0e2875818 If subtitles are part of an MKS, it is not an error. Just log for debug purpose and continue. 2025-06-07 21:51:08 +02:00
Carsten Braun
411ba03bf0 Fixed formatting 2025-06-07 21:51:08 +02:00
Carsten Braun
b2e19c0306 Also extract subtitles of MKS aux files if they're extractable. 2025-06-07 21:51:08 +02:00
Joshua M. Boniface
6d287d5627 Merge pull request #14228 from JPVenson/bugfix/StartupLookup
Fix source directory for setup template
2025-06-06 17:18:46 -04:00
theguymadmax
4f3b49472a Fix broken chapter image placeholders when no image is present (#14230) 2025-06-06 13:52:00 -06:00
felix920506
ef90fe9157 Update issue report.yml (#14099) 2025-06-06 06:56:29 -06:00
Mohammed Alhaddar
97f9d0c7e6 Fixing race condition in GetSessionInfo (#14131) 2025-06-06 06:55:05 -06:00
sharinganthief
9ab22e9f8b Add try catch (#14154) 2025-06-06 06:54:53 -06:00
JPVenson
04422250eb Fix source directory for setup template 2025-06-06 10:59:15 +00:00
wzrd
a702b62553 Translated using Weblate (German)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/de/
2025-06-06 02:11:36 +00:00
theguymadmax
5d7ae6a134 Fix metadata not refreshing in negative UTC timezones (#14225) 2025-06-05 15:58:20 -06:00
theguymadmax
5ac0260e5f Fix DirectoryNotFoundException for backdrop folders in trickplay (#14223) 2025-06-05 15:57:31 -06:00
JPVenson
88332e89c4 Feature/version check in library migration (#14105) 2025-06-05 08:59:11 -06:00
JPVenson
a3578caa8c Migrate all known old migrations even when not applied in migration.xml (#14217) 2025-06-05 08:46:50 -06:00
Blackspirits
b45e5463c1 Translated using Weblate (Portuguese)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/pt/
2025-06-05 02:37:16 +00:00
Blackspirits
10ab381e62 Translated using Weblate (Portuguese (Portugal))
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/pt_PT/
2025-06-05 02:37:15 +00:00
AfmanS
fa363f6276 Translated using Weblate (Portuguese (Portugal))
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/pt_PT/
2025-06-04 21:23:55 +00:00
Joshua M. Boniface
57214dafe8 Merge pull request #14222 from JPVenson/feature/DisableCacheForIndex
Add cache-control: no-cache to index.html if selfhosted
2025-06-04 14:04:37 -04:00
JPVenson
9ed9347cde Add cache-control: no-cache to index.html if selfhosted 2025-06-04 16:07:33 +00:00
JPVenson
916e897ed2 Allow custom plugin provided database providers to be loaded (#14171) 2025-06-03 16:53:37 -06:00
JPVenson
d5672ce407 Add declarative backups for migrations (#14135) 2025-06-03 16:49:41 -06:00
James
0c46431cbb Update XmlTv tests to use UTC date formats. (#14163) 2025-06-03 15:30:08 -06:00
Tim Eisele
e1a5c16404 Prune trickplay data on regenerate and scan (#14085) 2025-06-03 15:25:09 -06:00
jade
44b5de1568 Fix missing logging of connections by disallowed IPs (#14011) 2025-06-03 15:22:30 -06:00
Shane Powell
08b2ffeaab fixes #14193 (#14203) 2025-06-03 15:21:35 -06:00
JPVenson
48825f468e Fix server not auto restarting (#14215) 2025-06-03 15:16:35 -06:00
renovate[bot]
56d6e4b4cc Update dependency FsCheck.Xunit to 3.3.0 (#14216)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-03 15:16:00 -06:00
JPVenson
697bb6a480 Backup MigrationHistory as well (#14136) 2025-06-03 15:15:46 -06:00
JPVenson
a1d72deba2 Add multiple options for internal locking (#14047) 2025-06-03 15:15:22 -06:00
JPVenson
9456d7168f Add partition helper (#14039) 2025-06-03 15:15:04 -06:00
renovate[bot]
ae5e6431c5 Update github/codeql-action action to v3.28.19 (#14212)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-03 15:14:53 -06:00
renovate[bot]
e2ee58f29d Update dependency Microsoft.NET.Test.Sdk to 17.14.1 (#14211)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-03 15:14:12 -06:00
Niels van Velzen
bd3ee9f1e4 Merge pull request #14202 from shanepowell/fix-unittests
Fix unittests
2025-06-03 23:07:22 +02:00
theguymadmax
7ef3f73ce4 Add year parameter to TMDB series cache key 2025-06-03 11:04:43 -04:00
General-c4
4bc336091e Translated using Weblate (Arabic)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/ar/
2025-06-03 09:34:14 +00:00
Bond-009
c75f1e2987 Merge pull request #14030 from baka0815/iso639txt-pt
Localization/iso6392.txt: Correct the Portuguese entries
2025-06-02 15:39:48 +02:00
Shane Powell
4a4ed1b5d5 Merge branch 'jellyfin:master' into fix-unittests 2025-06-02 09:42:45 +12:00
Bond-009
eea80e5735 Merge pull request #13145 from SenorSmartyPants/RemoteImageSorting
Round RemoteImage CommunityRating to nearest tenths when sorting
2025-06-01 20:14:39 +02:00
Bond-009
c565010f28 Merge pull request #14179 from nyanmisaka/offload-sub-scale-to-rkrga
Offload 1080p+ subtitle scaling to RKRGA
2025-06-01 20:07:26 +02:00
XLi
285cd708f6 Translated using Weblate (Literary Chinese)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/lzh/
2025-05-31 14:57:34 +00:00
Shane Powell
3330465337 Fix failing unit tests on machines where the local timezone offset is far enough away from the test data day to be off by a day.
Change the test startdate to specifically be utc instead of local machine timezone.
2025-05-31 10:41:26 +12:00
wheremygit
4ba95b9ac4 Translated using Weblate (Marathi)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/mr/
2025-05-28 16:00:37 +00:00
nyanmisaka
1ee705f3e1 Fix RKRGA 2pass scaling issue caused by auto AR reduction
Signed-off-by: nyanmisaka <nst799610810@gmail.com>
2025-05-26 23:49:04 +08:00
nyanmisaka
0e0c7c5c59 Offload 1080p+ subtitle scaling to RKRGA
Signed-off-by: nyanmisaka <nst799610810@gmail.com>
2025-05-26 23:49:04 +08:00
Bond-009
4993234a7d Merge pull request #13933 from jellyfin/renovate/svg.skia-3.x
Update dependency Svg.Skia to 3.0.3
2025-05-25 14:02:38 +02:00
renovate[bot]
ed9affb14c Update dependency Svg.Skia to 3.0.3 2025-05-25 00:57:06 +00:00
theguymadmax
41b9eb8c0a Add SVG to transparent image types (#14160) 2025-05-23 11:30:35 -06:00
Napaul Intrarasing
605b8bb7aa Translated using Weblate (Thai)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/th/
2025-05-22 21:01:32 +00:00
Bond-009
538d0b622a Merge pull request #14153 from theguymadmax/name-case-insensitivity
Make name sorting case-insensitive
2025-05-22 17:58:07 +02:00
Max
8cb077402f Use CleanName for sorting case insensitive 2025-05-22 10:32:40 -04:00
theguymadmax
0cea039445 Fix media detection for single video files with subfolders (#14140) 2025-05-22 07:05:23 -06:00
theguymadmax
c3762186da Fix collection behavior when sorting by rating or runtime (#14148)
Co-authored-by: Max <no@example.com>
2025-05-22 07:05:14 -06:00
Bond-009
44981cd823 Enable OpenCL deinterlacer for AMF on Windows when available (#14144)
Signed-off-by: nyanmisaka <nst799610810@gmail.com>
2025-05-22 12:58:57 +02:00
Max
709d0bb231 Make name sorting case insensitive 2025-05-21 11:18:34 -04:00
nyanmisaka
56231222df Enable OpenCL deinterlacer for AMF on Windows when available
Signed-off-by: nyanmisaka <nst799610810@gmail.com>
2025-05-20 22:07:00 +08:00
theguymadmax
a6a89f7953 Fix ArgumentNullException when downloading season logos (#14141) 2025-05-20 06:03:04 -06:00
renovate[bot]
8339111732 Update dependency Microsoft.NET.Test.Sdk to 17.14.0 (#14143)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-20 13:57:49 +02:00
Tal Sarid
87e50025a9 Translated using Weblate (Hebrew)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/he/
2025-05-19 22:41:32 +00:00
gnattu
9d601f8e9b Terminate at null char for audio tags (#14100) 2025-05-18 18:40:18 -06:00
JPVenson
fe2596dc0e Add Full system backup feature (#13945) 2025-05-18 18:39:04 -06:00
renovate[bot]
cdbf4752b9 Update skiasharp monorepo (major) (#13369) 2025-05-18 18:38:26 -06:00
theguymadmax
43659f011c Fix ArgumentNullException in TmdbExternalUrlProvider (#14130) 2025-05-18 18:35:12 -06:00
Tal Sarid
8d781a0966 Added translation using Weblate (Hebrew (Israel)) 2025-05-17 13:44:36 +00:00
renovate[bot]
7217b09cda Update dependency Microsoft.CodeAnalysis.BannedApiAnalyzers to v4 (#14113)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-17 06:55:12 -06:00
renovate[bot]
f577dd6d64 Update github/codeql-action action to v3.28.18 (#14119)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-17 06:55:04 -06:00
renovate[bot]
9afb441361 Update dependency z440.atl.core to 6.24.0 (#14122)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-17 06:54:33 -06:00
Alexander Miller
29fc7711a1 Merge pull request #14094 from allesmi/fix/ancestor-ids-parent-child-relation
Translate query by AncestorIds correctly
2025-05-15 11:48:20 +02:00
Bond-009
265cc50144 Merge pull request #14102 from jellyfin/renovate/dotnet-monorepo
Update dependency dotnet-ef to 9.0.5
2025-05-14 11:48:00 +02:00
Bond-009
07b8247784 Merge pull request #14103 from jellyfin/renovate/microsoft
Update Microsoft to 9.0.5
2025-05-14 11:47:49 +02:00
renovate[bot]
16e04970f7 Update Microsoft to 9.0.5 2025-05-13 20:32:08 +00:00
renovate[bot]
61b928bc34 Update dependency dotnet-ef to 9.0.5 2025-05-13 18:51:06 +00:00
Blackspirits
4014b262d9 Translated using Weblate (Portuguese (Portugal))
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/pt_PT/
2025-05-13 01:02:29 +00:00
Blackspirits
8bc0123f42 Translated using Weblate (Portuguese (Portugal))
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/pt_PT/
2025-05-12 14:01:06 +00:00
renovate[bot]
28602af328 Update appleboy/scp-action action to v1 (#14012) 2025-05-11 21:15:10 -06:00
Tim Eisele
1b34ebc0fc Fix extracted data cleanup in cleanup post scan task (#14083) 2025-05-11 21:11:21 -06:00
renovate[bot]
14f142faa8 Update danielpalme/ReportGenerator-GitHub-Action action to v5.4.7 (#14090) 2025-05-11 21:10:56 -06:00
Alesaaq
fc2ecf9c93 Translated using Weblate (Galician)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/gl/
2025-05-11 11:28:25 +00:00
SoumyadipAuddy
86917cd167 added different countries parental ratings (#14069) 2025-05-09 20:23:54 -06:00
theguymadmax
6c57ad4772 Fix Blu-ray metadata processing: preserve external streams and language metadata (#14077) 2025-05-09 08:35:54 -06:00
gnattu
140de04f94 Reject invalid replaygain tag value (#14082) 2025-05-09 08:35:41 -06:00
Tim Eisele
49c6a99e00 Cleanup external item data cleanup (#14072) 2025-05-09 08:35:29 -06:00
Nyanmisaka
07093c84c8 Use VBR and MBBRC in QSV encoders for better quality (#14079) 2025-05-08 14:43:13 -06:00
JPVenson
a7bb3ea214 Only consider migrations that have key set for migration.xml migration (#14061) 2025-05-05 17:23:23 -06:00
Bond-009
28e2f5bb08 Add tests for ManagedFileSystem.MoveDirectory (#14065) 2025-05-05 15:39:06 -06:00
gnattu
dec5814a6a Fix cross filesystem dir moving (#14063) 2025-05-05 14:22:43 -06:00
Tim Eisele
d976f13970 Recognize file changes and remove data on change (#13839) 2025-05-04 21:21:44 -06:00
Bond-009
0c3ba30de2 Cleanup file related code (#14023) 2025-05-04 08:40:34 -06:00
JPVenson
4096c973c6 fix #14034 Readd Context provider on Initialise (#14040) 2025-05-04 08:27:03 -06:00
Bond-009
ce0a6b2df8 Merge pull request #14058 from jellyfin/renovate/ci-deps
Update danielpalme/ReportGenerator-GitHub-Action action to v5.4.6
2025-05-04 15:13:21 +02:00
renovate[bot]
06b7f88d6c Update danielpalme/ReportGenerator-GitHub-Action action to v5.4.6 2025-05-04 11:28:17 +00:00
Blackspirits
5e5fdf6173 Translated using Weblate (Portuguese)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/pt/
2025-05-04 07:31:23 +00:00
Blackspirits
0cd039b65c Translated using Weblate (Portuguese (Portugal))
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/pt_PT/
2025-05-04 07:31:23 +00:00
Bond-009
3ec5b7efaa Merge pull request #14017 from jellyfin/renovate/serilog.sinks.file-7.x
Update dependency Serilog.Sinks.File to v7
2025-05-03 16:52:05 +02:00
Nyanmisaka
4199f7acc2 Fix the transparency issue of ASS subtitle rendering in HWA (#14024) 2025-05-03 08:21:08 -06:00
theguymadmax
70dbf837c5 Add albumart as recognized filename for music artwork (#14048) 2025-05-03 08:19:59 -06:00
SoumyadipAuddy
7e6d4424b2 added parental ratings as per Indian Central Board of Film Certification norms (#14050) 2025-05-03 08:19:24 -06:00
harry-hart
930a4d0f60 Update NamingOptions.cs to include "part" (#14022) 2025-05-02 07:54:34 -06:00
renovate[bot]
d894b91d46 Update dependency z440.atl.core to 6.23.0 (#14045)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-02 07:51:56 -06:00
theguymadmax
57716833b8 Fix trickplay directory path construction (#14036) 2025-05-02 07:01:23 -06:00
Bond-009
e5c40ea98d Merge pull request #14046 from jellyfin/renovate/ci-deps
Update github/codeql-action action to v3.28.17
2025-05-02 14:56:44 +02:00
Bond-009
b4a58ee13a Merge pull request #14028 from Shadowghost/cleanup-tasks
Cleanup Tasks and Validators
2025-05-02 14:47:53 +02:00
renovate[bot]
2803d4941b Update github/codeql-action action to v3.28.17 2025-05-02 11:44:36 +00:00
Niels van Velzen
dbedb9096b Merge pull request #14044 from theguymadmax/fix-log-file
Fix startup logger log file order
2025-05-02 13:43:54 +02:00
theguymadmax
3cf213c4fb Fix startup logger log file order 2025-05-01 21:20:35 -04:00
Jothi Prasath
3cc4e8a88a Translated using Weblate (Tamil)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/ta/
2025-05-01 17:46:24 +00:00
Christoph "baka0815" Schwerdtfeger
9050a094a7 Localization/iso6392.txt: change pob and pop
pob and pop are not valid iso 639 codes for Portuguese. "pob" seems to be Poqomchi' and "pop" is Pwapwâ.
So just change them to both reference por which is the 3-letter-code for portuguese.
2025-04-30 20:16:45 +02:00
Shadowghost
5c9f70c375 Cleanup Tasks and Validators 2025-04-30 09:29:13 +02:00
Bond-009
aa24d08d33 Fix image extractor with more strict ffmpeg requirement (#14013)
* Correctly handle retry when I frame only failed

* Use full range output for image

* Don't trim image extractor option
2025-04-29 14:10:24 +02:00
sususu98
a7891b3f2d Enhanced HTTP Range request support for. strm file
Forward the Range, Accept-Ranges, and Content-
Range headers, improve User-Agent handling,
and adjust the default Content-Type.
2025-04-29 17:08:50 +08:00
besart-hajdari
0a0fcd3b19 Translated using Weblate (Albanian)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/sq/
2025-04-28 14:29:03 +00:00
Joshua M. Boniface
055d466d16 Merge pull request #14016 from crobibero/upd-projects
Add new nuget packages to abi diff
2025-04-27 21:16:20 -04:00
renovate[bot]
5dc7962995 Update dependency Serilog.Sinks.File to v7 2025-04-28 00:43:47 +00:00
JPVenson
e66c76fc34 Unified migration handling (#13950) 2025-04-27 18:18:08 -06:00
Cody Robibero
e57a95e9cd Add required nuget properties 2025-04-27 18:11:22 -06:00
Cody Robibero
2b854fb365 Add new nuget packages to abi diff 2025-04-27 18:02:42 -06:00
gnattu
f436743f9f Don't trim image extractor option 2025-04-27 21:37:44 +08:00
gnattu
77bb1a726e Use full range output for image 2025-04-27 21:36:57 +08:00
gnattu
6637102162 Correctly handle retry when I frame only failed 2025-04-27 21:30:02 +08:00
JPVenson
1c4b5199b8 Fix ItemValue query (#13939) 2025-04-26 19:10:54 -06:00
Tim Eisele
f576783ae1 Fix distinction queries (#14007) 2025-04-26 18:49:30 -06:00
Rasko
67110b512a Translated using Weblate (Norwegian Bokmål)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/nb_NO/
2025-04-26 19:22:49 +00:00
renovate[bot]
1264254301 Update dependency z440.atl.core to 6.22.0 (#13995)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-26 09:37:23 -06:00
gnattu
2e467f29de Don't pass through timestamp for image extractor (#13999) 2025-04-26 09:36:40 -06:00
Tim Eisele
9092130350 Optimize migrations (#13855) 2025-04-26 09:36:17 -06:00
Tim Eisele
a0b3b7335f Add .gitignore style ignoring (#13906) 2025-04-26 09:35:57 -06:00
JPVenson
5d65cfcd99 improved performance of save operations (#13889) 2025-04-26 09:32:12 -06:00
JPVenson
2ea7af777b Create directory before checking for size (#13962) 2025-04-26 09:30:57 -06:00
JPVenson
8ee358de2c Check for path overlaps (#12832) 2025-04-26 09:30:25 -06:00
Tim Eisele
df5671263f Merge pull request #13847 from Shadowghost/rework-chapter-management
Rework chapter management
2025-04-26 14:01:12 +02:00
Bond-009
f35b8dd33d Merge pull request #13536 from tkloy24/13250-Extras-Delete-Whole-Folder
Fix IsInMixedFolder not being set for Extras
2025-04-26 12:07:45 +02:00
Bond-009
8f1ebfc4cd Merge pull request #13378 from felix920506/patch-1
Only run merge conflict labler action on pull requests
2025-04-26 12:06:15 +02:00
Bond-009
dbaa3e458d Merge pull request #13993 from nielsvanvelzen/api-deprecate-old-playstate
Deprecate OnPlaybackXXX API operations in favor of ReportPlaybackXXX
2025-04-26 11:28:45 +02:00
Bond-009
d62cf7f7cb Merge pull request #13981 from jellyfin/renovate/ci-deps
Update CI dependencies
2025-04-25 17:30:08 +02:00
renovate[bot]
cf0220f183 Update CI dependencies 2025-04-24 18:06:11 +00:00
Teja Chundru
317d76e97c Translated using Weblate (Telugu)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/te/
2025-04-24 13:30:32 +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
Fernando Fernández
c4cb41f3b2 Temporarily ignore NonTransactionalMigrationOperation warnings (#13972) 2025-04-23 21:31:03 -06:00
Niels van Velzen
32887adff3 Deprecate OnPlaybackXXX API operations in favor of ReportPlaybackXXX 2025-04-23 22:00:07 +02: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
Bond-009
fca048fe18 Merge pull request #13967 from jellyfin/renovate/z440.atl.core-6.x
Update dependency z440.atl.core to 6.21.0
2025-04-23 09:20:53 +02:00
renovate[bot]
1dd3808147 Update dependency z440.atl.core to 6.21.0 2025-04-22 17:34:25 +00:00
JPVenson
a0931baa8e Add Api and startup check for sufficient storage capacity (#13888) 2025-04-20 20:06:50 -06:00
Niels van Velzen
5e4bd744c0 Return SyncPlay group info after creation, add GET group endpoint (#13935) 2025-04-20 19:40:23 -06:00
MrPlow
576f6d411a Translated using Weblate (German)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/de/
2025-04-20 13:03:46 +00:00
MrPlow
51b54f5695 Translated using Weblate (German)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/de/
2025-04-20 10:12:14 +00:00
Bond-009
74230131a1 Fix OverflowException when scanning media with a very short duration (#13949) 2025-04-19 13:08:29 -06:00
JPVenson
7df6e0b16f Add port awareness to startup server (#13913) 2025-04-19 13:08:24 -06:00
Niels van Velzen
269508be9f Fix SyncPlay WebSocket OpenAPI schemas (#13946) 2025-04-19 13:08:15 -06:00
theguymadmax
1c190f7952 Improve video resolution filtering and classification logic (#13332) 2025-04-19 10:45:19 -06:00
Nyanmisaka
e84826297d Fix thumbnail extraction of mpegts videos in FFmpeg 7.1+ (#13942) 2025-04-19 10:41:30 -06:00
Bond-009
86b81c912d Merge pull request #13928 from jellyfin/renovate/libse-4.x
Update dependency libse to 4.0.12
2025-04-16 11:56:42 +02:00
renovate[bot]
ccc49b109f Update dependency libse to 4.0.12 2025-04-15 17:48:45 +00:00
Tim Eisele
6e9e2f500f Fix Genre cleanup (#13916) 2025-04-14 20:43:38 -06:00
Nyanmisaka
8be8ea60f1 Add DoVi Profile 5 support for Rockchip RKMPP (#13911) 2025-04-13 07:43:58 -06:00
renovate[bot]
22c816de0a Update dependency Svg.Skia to 2.0.0.8 (#13907) 2025-04-13 07:43:44 -06:00
Tim Eisele
61cb53999e Safeguard against null value trimming in tag results (#13908) 2025-04-13 07:43:06 -06:00
Bond-009
5eefbb6bf6 Merge pull request #13905 from jellyfin/renovate/asynckeyedlock-7.x
Update dependency AsyncKeyedLock to 7.1.6
2025-04-12 16:19:45 +02:00
Bill Thornton
afdde7b243 Remove the hashed password from startup users response (#13904) 2025-04-12 07:12:33 -06:00
renovate[bot]
d6fbdcc0f8 Update dependency AsyncKeyedLock to 7.1.6 2025-04-12 09:14:07 +00:00
Bill Thornton
5020c09640 Merge pull request #13901 from thornbill/add-startup-name 2025-04-11 18:04:20 -04:00
Bill Thornton
874f6895a2 Add ServerName to startup configuration 2025-04-11 13:58:34 -04:00
Rafał Stępień
c972047566 Add polish age ratings (#13851) 2025-04-11 10:25:53 -06:00
Bond-009
dbf0edf4f8 Merge pull request #13898 from jellyfin/renovate/fscheck.xunit-3.x
Update dependency FsCheck.Xunit to 3.2.0
2025-04-11 12:07:57 +02:00
Bond-009
4d7f85f14a Merge pull request #13897 from jellyfin/renovate/svg.skia-2.x
Update dependency Svg.Skia to 2.0.0.7
2025-04-11 12:07:37 +02:00
renovate[bot]
9ec8790faa Update dependency Svg.Skia to 2.0.0.7 2025-04-11 09:10:17 +00:00
renovate[bot]
9a806cf3a4 Update dependency FsCheck.Xunit to 3.2.0 2025-04-11 00:29:23 +00:00
Tim Eisele
cad8de9701 Add Genre cleanup and fix cleanup filter queries (#13891) 2025-04-09 18:40:16 -06:00
stelle
294b2f90d1 Translated using Weblate (Malay)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/ms/
2025-04-09 16:01:04 +00:00
gnattu
32fe92d8f5 Only reselect audio streams when user preference is respected (#13832) 2025-04-08 19:22:30 -06:00
Markus Prettner
c152f610ce Fix negated IP addresses without subnet mask not being parsed correctly (#13854) 2025-04-08 19:21:57 -06:00
renovate[bot]
0bbc6bb31d Update dependency dotnet-ef to 9.0.4 (#13879)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-08 19:21:28 -06:00
renovate[bot]
cb59a017a5 Update Microsoft to 9.0.4 (#13878)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-08 19:19:21 -06:00
JPVenson
070abcd8ff Fix InheritedParentalRatingSubValue not set (#13880) 2025-04-08 19:19:01 -06:00
Niels van Velzen
16dc1e2260 Use Guid for parentPrimaryImageItemId (#13874) 2025-04-08 14:59:21 -06:00
Nyanmisaka
98697e75ca Fix seeking beyond EOF again (#13871) 2025-04-08 14:58:55 -06:00
Bond-009
1e10cd003d Merge pull request #13869 from jellyfin/renovate/ci-deps
Update github/codeql-action action to v3.28.15
2025-04-08 15:02:24 +02:00
baka0815
5fc1b1c862 Translate the ISO-639-2/B codes to ISO-639-2/T. (#13068)
* Translate the ISO-639-2/B codes to ISO-639-2/T.

This enables 19 additional languages to be displayed correctly.

* Convert the 2-dimensional array to a dictionary

* Added the French language to the list of ISO-639-2/B codes

* Don't change the property, use a local variable instead.

* When creating the MediaStream in the MediaStreamRepository ensure that the ISO 639-2/T (f.e. deu) code is used for the language as that is the one the .NET culture info knows.
The other code is most likely the ISO 639-2/B code (f.e. ger) which is unknown to the .NET culture info and will result in just displaying the code instead of the display name.

* Move the substitution of ISO 639-2/B to /T to the localization manager.
Some language (like Chinese) have multiple entries in the iso6392.txt file (f.e. zho|chi|zh|..., zho|chi|zh-tw|...) but the conversation between /T and /B is the same so use .TryAdd.

* Change the method definition from GetISO6392TFromB to TryGetISO6392TFromB and return true if a case was found.

* Add unit tests for TryGetISO6392TFromB.
2025-04-07 21:29:12 -06:00
renovate[bot]
4fa1a9cb97 Update github/codeql-action action to v3.28.15 2025-04-08 01:06:31 +00:00
JPVenson
77ad7f6139 Fix the migration as the new constraint now uses Value as unique key (#13867) 2025-04-07 14:42:01 -06:00
Alex
82a561b87d Add API support for ELRC word-based lyrics (#12941)
* Add API support for ELRC word-based lyrics

Adds support for word-based timestamps from within ELRC files.

* Create TimeTags object

* redo TimeTag implementation

Change TimeTag to long, redo TimeTag implementation
Make timestamp not nullable
Update MediaBrowser.Model/Lyrics/LyricLine.cs
Make TimeTag list IReadOnlyList
Remove nullable Timestamp
Update TimeTag description

Co-Authored-By: Cody Robibero <cody@robibe.ro>

* Changes to LyricLineTimeTag

Moved TimeTag to LyricLineTimeTag
Change "timestamp" to "start" for consistency
Change plural "TimeTags" to "Cues"
Change comments

* Change LyricLineTimeTag to LyricLineCue, include info about end times

* Remove width

* Remove width tag

* Rewrite cue parser and add tests

---------

Co-authored-by: Cody Robibero <cody@robibe.ro>
2025-04-07 08:59:18 -06:00
JPVenson
04ca27ad07 Fix backup not written to correct directory (#13853)
* Fix backup not written to correct directory

* Improve restore handling and only restore on actual error

* Fix first failed migration not causing a rollback
2025-04-07 08:59:00 -06:00
Bond-009
e1ef4290af Merge pull request #13863 from jellyfin/renovate/ci-deps
Update github/codeql-action action to v3.28.14
2025-04-07 15:58:37 +02:00
renovate[bot]
1ef0a41066 Update github/codeql-action action to v3.28.14 2025-04-07 12:11:49 +00:00
Tim Eisele
b65e03da9a Fix Genre type (#13862) 2025-04-07 06:11:05 -06:00
JQ
fe79384cd5 Returns album artists apart from artist names when doing a lyrics search (#13852) 2025-04-06 14:18:39 -06:00
Joshua M. Boniface
2c9c9f591d Merge commit from fork
Fix not trusting all sources for forward headers if none are configured
2025-04-05 14:44:42 -04:00
Joshua M. Boniface
7d705249ca Merge commit from fork
Fix validation of API parameters passed to FFmpeg
2025-04-05 14:44:19 -04:00
Tim Eisele
de3d1445c0 Fix ancestors (#13827) 2025-04-05 10:49:29 -06:00
Tim Eisele
0e7ae0e9a4 Fix indices and update of ItemValues (#13843) 2025-04-05 09:57:58 -06:00
Tim Eisele
2264d58ae7 Use subdirectories to organize extracted data (#13838)
* Use subdirectories to organize extracted data

* Apply suggestions from code review
2025-04-05 07:53:17 -06:00
HigherLevel
f7021d04eb Translated using Weblate (Afrikaans)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/af/
2025-04-04 13:01:03 +00:00
Bond-009
1c2b48182a Fix ArgumentNullException on playlist creation (#13837)
mediaSourceId can be null, the IDE doesn't know this as nullable is disabled for BaseEncodingJobOptions
2025-04-03 17:44:47 -06:00
Tim Eisele
d0c1ef8002 Update MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs
Co-authored-by: Cody Robibero <cody@robibe.ro>
2025-04-03 20:42:33 +02:00
timminator
d1ed6593ad Make ReadInputAtNativeFramerate configurable for M3U tuner (#13773) 2025-04-03 09:18:00 -06:00
Tim Eisele
596b635511 Cleanup extracted files (#13760)
* Cleanup extracted files

* Pagination and fixes

* Add migration for attachments to MigrateLibraryDb

* Unify attachment handling

* Don't extract again if files were already extracted

* Fix MKS attachment extraction

* Always run full extraction on mks

* Don't try to extract mjpeg streams as attachments

* Fallback to check if attachments were extracted to cache folder

* Fixup
2025-04-03 09:17:14 -06:00
Tim Eisele
0bde7bae05 Only remove keyframe cache dir if it exists (#13834) 2025-04-03 08:47:31 -06:00
JPVenson
a18d60d2de Trim library names (#13828) 2025-04-02 18:19:31 -06:00
Tim Eisele
0573999d5e Import Keyframes into database (#13771)
* Migrate keyframe data into database

* Clear database table before import to handle failed migrations
2025-04-02 18:06:40 -06:00
gnattu
49ac705867 Improve dynamic HDR metadata handling (#13277)
* Add support for bitstream filter to remove dynamic hdr metadata

* Add support for ffprobe's only_first_vframe for HDR10+ detection

* Add BitStreamFilterOptionType for metadata removal check

* Map HDR10+ metadata to VideoRangeType.cs

Current implementation uses a hack that abuses the EL flag to avoid database schema changes. Should add proper field once EFCore migration is merged.

* Add more Dolby Vision Range types

Out of spec ones are problematic and should be marked as a dedicated invalid type and handled by the server to not crash the player.

Profile 7 videos should not be treated as normal HDR10 videos at all and should remove the metadata before serving.

* Remove dynamic hdr metadata when necessary

* Allow direct playback of HDR10+ videos on HDR10 clients

* Only use dovi codec tag when dovi metadata is not removed

* Handle DV Profile 7 Videos better

* Fix HDR10+ with new bitmask

* Indicate the presence of HDR10+ in HLS SUPPLEMENTAL-CODECS

* Fix Dovi 8.4 not labeled as HLG in HLS

* Fallback to dovi_rpu bsf for av1 when possible

* Fix dovi_rpu cli for av1

* Use correct EFCore db column for HDR10+

* Undo outdated migration

* Add proper hdr10+ migration

* Remove outdated migration

* Rebase to new db code

* Add migrations for Hdr10PlusPresentFlag

* Directly use bsf enum

* Add xmldocs for SupportsBitStreamFilterWithOption

* Make `VideoRangeType.Unknown` explicitly default on api models.

* Unset default for non-api model class

* Use tuples for bsf dictionary for now
2025-04-02 18:06:02 -06:00
KGT1
9c7cf808aa allow admin users to get Splashscreen even when disabled (#13825)
refactor
2025-04-02 16:32:53 -06:00
Niels van Velzen
767ee2b5c4 Merge pull request #13822 from thornbill/missing-system-info
Add missing public properties to SystemInfo response
2025-04-01 20:04:50 +02:00
Tim Eisele
086fbd49cf Cleanup ItemFields (#13818)
* Cleanup ItemFields

* Update MediaBrowser.Model/Querying/ItemFields.cs
2025-03-31 17:46:21 -06:00
KGT1
14b785d188 Preserve SplashscreenLocation when updating branding config (#13756)
* add BrandingOptionsDto and add branding endpoints

* refactor new HttpGet Configuration Branding into existing API calls

* Add BrandingOptions to _ignoredConfigurations for openAPI

* rename BrandOptionsDto to BrandingOptionsDto
2025-03-31 17:46:01 -06:00
Dmitry Lyzo
940c4e8ba8 Add Dolby Vision tests for Tizen (#12670)
* Fix Tizen H264 profiles

* Add Dolby Vision tests for Tizen

* Allow Dolby Vision fallback layer on Tizen 3+
2025-03-31 17:45:14 -06:00
Fernando Fernández
2b742a5966 Reduce SKImage to SKBitmap conversion, high quality canvas (#5366) 2025-03-31 17:45:03 -06:00
Tim Eisele
5769c398c6 Fix Tmdb external URL generation (#13817)
* Fix Tmdb external URL generation

* Update MediaBrowser.Providers/Plugins/Tmdb/TmdbExternalUrlProvider.cs
2025-03-31 17:44:06 -06:00
gnattu
4a4fef830e Explicitly set default value for enums used in API models (#13821)
Enums in response model with no nullability or default value will make the API very fragile as each extension to the enum will break the API for some clients, but a lot of enums actually do have an unknown value which should be used as a default. This set all model properties that are non-nullable using an enum that has an Unknown member in 10.10, except MediaStream.VideoRangeType which is refactored in #13277
2025-03-31 17:43:31 -06:00
Bond-009
e9729a536f Use pattern matching for null checks (#13793)
Fix the few that slipped through
2025-03-31 17:38:25 -06:00
Bill Thornton
d9a79b5eef Add missing public properties to SystemInfo response 2025-03-31 18:26:34 -04:00
Tim Eisele
3fc3b04daf Rework parental ratings (#12615) 2025-03-30 21:51:54 -06:00
Quyet Vu
2ace880345 Fix playlist order (#13730)
* Fix playlist order move

* Remove extra space

* Added more test cases

* Change namespace to file-scoped
2025-03-30 21:39:51 -06:00
Tim Eisele
d7b786e777 Fix MoveTrickplayFiles migration (#13807) 2025-03-30 21:38:50 -06:00
renovate[bot]
150094e3a4 Update dependency z440.atl.core to 6.20.0 (#13811)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-30 21:38:36 -06:00
Tim Eisele
824bafc32d Fix StreamInfo.ToUrl (#13808) 2025-03-30 21:37:58 -06:00
JPVenson
90a6cca92b Library.db migration impovements (#13809)
* Fixes cleanup of wrong table in migration

* use dedicated context for each step

* Use prepared Context

* Fix measurement of UserData migration time

* Update logging and combine cleanup to its own stage

* fix people map not logging
migrate only readonly database

* Add id blacklisting in migration to avoid duplicated log entires
2025-03-30 21:36:27 -06:00
Bond-009
476a0d6932 Merge pull request #13194 from gnattu/av1-videotoolbox
Enable VideoToolbox AV1 decode
2025-03-30 23:12:53 +02:00
JPVenson
d75216cf3a Fixes cleanup of wrong table in migration (#13796) 2025-03-29 10:00:19 -06:00
LJQ
c906c1ca0d rebase 2025-03-29 02:33:58 +08:00
gnattu
c69e9d8f2c Gate the macOS only functions 2025-03-28 21:30:39 +08:00
gnattu
384134fd25 Use string literal 2025-03-28 21:22:00 +08:00
Johannes Heuel
2c499d1e86 feat: allow grouping shows into collections (#13236)
* feat: allow grouping shows into collections

* add pre-startup routine to rename EnableGroupingIntoCollections

* Update Jellyfin.Server/Migrations/PreStartupRoutines/RenameEnableGroupingIntoCollections.cs
2025-03-28 06:54:12 -06:00
Tim Eisele
9657708b38 Reduce allocations, simplifed code, faster implementation, included tests - StreamInfo.ToUrl (#9369)
* Rework PR 6168

* Fix test
2025-03-28 06:51:44 -06:00
Dmitry Lyzo
cb931e0062 Add profile condition to limit the number of streams (#13583) 2025-03-28 06:51:22 -06:00
Shadowghost
3df7d7a809 Add validation for level input 2025-03-28 08:21:37 +01:00
Shadowghost
1fcc79316d Rename ValidationRegex to ContainerValidationRegex 2025-03-28 08:21:37 +01:00
Shadowghost
6d7950bddc Fix container parameter validation 2025-03-28 08:21:37 +01:00
JPVenson
a2ef0e4abe Fix trusting all sources for forward headers if none are configured 2025-03-28 08:08:18 +01:00
Niels van Velzen
7f5cc544df Merge pull request #13790 from crobibero/fix-build
Fix build and tests
2025-03-28 07:21:59 +01:00
Cody Robibero
15465afd8e Revert changes to DirectoryService 2025-03-27 21:13:27 -06:00
Cody Robibero
6c46b06c75 Fix merged namespace error 2025-03-27 19:46:45 -06:00
Michael McElroy
f02190c394 Fix for Issue #12142: Fix ExtraRuleResolver filtering out top level folders (#12170)
* Fix ExtraRuleResolver to stop filtering out libraries where the name of the base folder matches an 'videos extras' rule with an ExtraRuleType of DirectoryName

Currently the ExtraRuleResolver code doesn't know anything about the root folder of the current library. As a result, when we're attempting to add items in a library where the root folder has a name with a match in Emby.Naming.Common.NamingOptions.VideoExtraRules, the entire library is being ignored as a Video Extras folder.

Need to pass in the root folder of the current library to compare to the path of the current item being evaluated, and if we match the current item's folder to the root folder, then we ignore the ExtraRules with a type of DirectoryName and we continue to scan deeper in the library. Filters still apply to subfolders within the library itself.

* Update CONTRIBUTORS.md

* Update Emby.Naming/Video/ExtraRuleResolver.cs

* Update ExtraTests.cs

Add tests for this fix.

Also add missing tests in TestKodiExtras, TestExpandedExtras, and TestSample, and expanded TestDirectories into TestDirectoriesAudioExtras and TestDirectoriesVideoExtras. There were no checks for the theme-music folder name previously.

* Update ExtraTests.cs

Removed unnecessary "using System"

* In MediaBrowser.Model, upgrade System.Text.Json from 8.0.3 (vulnerable - high risk) to 8.0.4

* Update ExtraTests.cs

Remove empty lines in usings

* Revert "In MediaBrowser.Model, upgrade System.Text.Json from 8.0.3 (vulnerable - high risk) to 8.0.4"
2025-03-27 18:18:19 -06:00
Cody Robibero
88ceaa39b0 Implement limiting caches (#13605)
* Implement basic expiring cache for LibraryManager

* Add expiring cache to more places

* Rider why

* Make DirectoryService caches static

* Use FastConcurrentLru

* Reduce default cache size

* Simplify DirectoryService caches

* Make directory service cache size at least 128
2025-03-27 18:16:54 -06:00
gnattu
e9331fe9d7 Improve SkiaEncoder's font handling (#13231)
* Improve SkiaEncoder's font handling

Our previous approach didn’t work with some complex library names, even when the required fonts were present, because the font handling logic was too simplistic. Modern Unicode and the fonts have become quite complex, making it challenging to implement it correctly. This improved implementation still isn’t the most correct way, but it’s better than it used to be. It now falls back to multiple fonts to find the best one and also handles extended grapheme clusters that were incorrectly processed before.

* Fix space

* Remove redundant comment

* Make _typefaces an array

* Make Measure and Draw text function name clear

* Fix rename
2025-03-27 18:07:54 -06:00
Kevin Jilissen
9f70578997 Add channel queries to series (#13356)
Currently, the IChannel interface can deliver channel result folders which are interpreted as series and seasons. However, Jellyfin does not query for the contents of these folders when viewing said serie of season. This results in empty series in the API.
2025-03-27 18:06:10 -06:00
Jacob Warren
07f07ba6bc Fix Sort by Year Bug (#12101) (#13733) 2025-03-27 18:05:03 -06:00
Nyanmisaka
a123a2cb22 Fix validation of VAAPI/QSV render node path (#13786)
Signed-off-by: nyanmisaka <nst799610810@gmail.com>
2025-03-27 17:59:32 -06:00
timminator
181a37a8cd Fix consumer count off by one when closing a browser tab with a livestream that is transcoding (#13220)
Rework Implementation
Fix review issues
Add missing nullorempty check
Fix closely related #13721
2025-03-27 17:59:08 -06:00
Tobias Kloy
7717d2e261 Avoid multiple enumerations 2025-03-27 17:51:31 +01:00
Tobias Kloy
b108a8cfc5 Fix IsInMixedFolder not being set for Extras in mixed subfolders 2025-03-27 17:51:31 +01:00
theguymadmax
ae4b35da46 Include UnratedType in LibraryDb migration query (#13783) 2025-03-27 10:43:39 -06:00
theguymadmax
f6b98d0faf Add eac3 as audio name format (#13784) 2025-03-27 10:43:25 -06:00
JPVenson
9e4abb7319 Add override for migration if old library still exists (#13779) 2025-03-27 05:34:59 -06:00
JQ
d06ce1f1e0 Fix only returning one item from /Item/Latest api. (#12492)
* Updated to EFcore

* Remove unused using

* Dont use DateCreated not from episode type or music type

* use TranslateQuery to filter out instead and then do the grouping and retrival of min and max datecreated instead

* Album also
2025-03-26 20:26:47 -06:00
baka0815
cafb7cd002 Change the order of the iso6392.txt file (#13314)
* Change the order of the ISO-639-2 list

Now the ISO 639-2/T (terminological) comes first (which is the same as the ISO 639-3 code) and the second column is for the ISO 639-2/B (bibliograpihc) code.
The terminological code is derived from the native name for the language while the bibliographic code is more of a "legacy feature" where the code is derived from the English name for the language.

The format of the file is now

ISO 639-2/T (or ISO 639-3) | ISO 639-2/B (where applicable) | ISO 639-1 (two-letter code) | English name | French name

* Sort the ISO list by the first column
2025-03-26 20:25:53 -06:00
Dmitry Lyzo
777e0823ba Extract container, video and audio compatibility checks (#12678)
* Extract container, video and audio compatibility checks

* Extract audio compatibility checks

* Extract CheckVideoConditions

* Simplify direct audio stream check
2025-03-26 20:24:16 -06:00
JPVenson
296b17bf44 Feature/backup on migration (#13754)
* Added generalised backup for migrations

* Added backup strategy to MigrateLibraryDb

* Added missing namespace

* Fix merge issues

* Fixed style issue

* change fast backup key to timestamp

* Update src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/SqliteDatabaseProvider.cs

* Update Fields

* applied review comments
2025-03-26 20:23:36 -06:00
renovate[bot]
08dbb5c842 Update CI dependencies (#13766) 2025-03-26 06:02:58 -06:00
Cody Robibero
d848faeb75 Merge pull request #13589 from JPVenson/feature/DatabaseRefactor
[Feature] Database code refactor
2025-03-25 21:34:26 -06:00
Cody Robibero
1b388d7296 Clean up csproj 2025-03-25 21:25:27 -06:00
JPVenson
bfff1b9be2 Fix reference 2025-03-25 16:55:26 +01:00
JPVenson
42bdb22bfb Fixed namespaces 2025-03-25 16:45:00 +01:00
JPVenson
160020c551 WIP fixed namespaces 2025-03-25 15:30:22 +00:00
JPVenson
7cd059c033 Merge remote-tracking branch 'origin/master' into feature/DatabaseRefactor 2025-03-25 15:13:32 +00:00
JPVenson
850f1c79f1 Merge branch 'master' into feature/DatabaseRefactor 2025-03-25 15:12:48 +00:00
Niels van Velzen
035ecbdde3 Merge pull request #13769 from JPVenson/Bugfix/FixCleanupTaskNotAwaiting
Fix Cleanup task not awaiting async methods
2025-03-24 19:15:10 +01:00
Niels van Velzen
2c0ecd6775 Merge pull request #13764 from JPVenson/bugfix/FixOpenApiFor503
Add OpenAPI spec for #12880
2025-03-24 19:14:41 +01:00
JPVenson
cd5f18a084 Fix Cleanup task not awaiting async methods 2025-03-24 17:23:16 +00:00
JPVenson
daf8eca8ae update header api description and values 2025-03-24 16:56:36 +00:00
Niels van Velzen
8680170706 Merge pull request #13616 from Lampan-git/fix_people_role
Include PeopleBaseItemMap in GetPeople to inlcude Role and SortOrder
2025-03-24 15:29:28 +01:00
Bond-009
480244e111 Merge pull request #13691 from NooNameR/noonamer/add_pattern_search
Add ability to provide search pattern to GetFiles
2025-03-24 14:15:42 +01:00
Bond-009
64a5a8419d Merge pull request #13765 from JPVenson/bugfix/DisableFlakyTests
Disabled flaky tests
2025-03-24 14:09:03 +01:00
Bond-009
592f278ee2 Merge pull request #13759 from jellyfin/renovate/ci-deps
Update danielpalme/ReportGenerator-GitHub-Action action to v5.4.5
2025-03-24 11:23:26 +01:00
JPVenson
ef7f6fc8a9 fixed typo 2025-03-24 10:16:25 +00:00
JPVenson
8d49a396e8 Fixed readme 2025-03-24 10:15:28 +00:00
JPVenson
8e9b57aea9 Fixed naming scheme 2025-03-24 10:14:16 +00:00
JPVenson
ea8f1ffb7c renamed SqLite to Sqlite 2025-03-24 10:07:52 +00:00
JPVenson
e4b11c664c Disabled flaky tests 2025-03-24 08:38:17 +00:00
JPVenson
a026a3722c Clarified retry value type 2025-03-24 08:31:52 +00:00
JPVenson
aa4936c59c Added OpenAPI spec for #12880 2025-03-24 08:27:21 +00:00
JPVenson
3c2d3ac18b Update src/Jellyfin.Database/readme.md
Co-authored-by: Tim Eisele <Tim_Eisele@web.de>
2025-03-24 09:19:00 +01:00
JPVenson
671d801d9f #13540 Fixed (#13757)
#13508 Partially fixed

Co-authored-by: JPVenson <github@jpb.software>
2025-03-23 19:52:34 -06:00
Niels van Velzen
516754c2a6 Merge pull request #13761 from Shadowghost/fix-runtime
Add missing singleton
2025-03-23 23:17:37 +01:00
Shadowghost
ea6130b354 Add missing singleton 2025-03-23 23:10:16 +01:00
renovate[bot]
b3b2da681f Update danielpalme/ReportGenerator-GitHub-Action action to v5.4.5 2025-03-23 20:36:11 +00:00
Joshua M. Boniface
35f8720251 Merge pull request #12880 from JPVenson/feature/10.10/DetachedMigration
Added Setup overlay app to communicate status of startup
2025-03-23 12:41:28 -04:00
Tim Eisele
dfb485d1f2 Rework season folder parsing (#11748) 2025-03-23 10:05:40 -06:00
Tim Eisele
8db6a39e92 Remove all DB data on item removal, delete internal trickplay files (#13753) 2025-03-23 10:05:13 -06:00
Adil
8b6aec7ce5 Rename Pakistan to select dropdown accessible name (#13752) 2025-03-23 08:31:26 -06:00
Fernando Fernández
c77a0719c2 Clear dictionaries when not needed, use set for finding existing base items (#13749) 2025-03-22 18:30:32 -06:00
timminator
350983e03c Fix OnPlaybackStopped task erroring out (#13226) 2025-03-20 07:10:48 -06:00
Lampan-git
aabaf1a656 Backport pull request #13720 from jellyfin/release-10.10.z
Fix regression where "Search for missing metadata" not handling cast having multiple roles

Original-merge: 91ca81eca7

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

Backported-by: Bond_009 <bond.009@outlook.com>
2025-03-20 05:55:51 -04:00
Bond-009
69b07c9f31 Merge pull request #13724 from theguymadmax/imdb-person-url
Fix IMDb URL for People
2025-03-20 10:44:56 +01:00
Bond-009
c6178c63bf Merge pull request #13738 from jellyfin/renovate/ci-deps
Update CI dependencies
2025-03-19 22:13:13 +01:00
renovate[bot]
3eca221cc6 Update CI dependencies 2025-03-19 18:27:37 +00:00
renovate[bot]
11fbca45ff Update actions/download-artifact action to v4.2.0 (#13734)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-18 17:41:02 -06:00
timminator
c24d0c1240 Respect preferred language when selecting forced subtitles (#13098)
Rework subtitle selection logic
2025-03-18 17:40:06 -06:00
Cody Robibero
85b5bebda4 Add fast-path to getting just the SeriesPresentationUniqueKey for NextUp (#13687)
* Add more optimized query to calculate series that should be processed for next up

* Filter series based on last watched date
2025-03-18 17:37:04 -06:00
Blackspirits
e1392ca1b6 Translated using Weblate (Portuguese (Portugal))
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/pt_PT/
2025-03-18 16:01:01 -04:00
Thunderstrike116
62fc2b8d0d Translated using Weblate (Greek)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/el/
2025-03-17 06:01:02 -04:00
Bond-009
2d9549dbbc Merge pull request #13727 from jellyfin/renovate/ci-deps
Update actions/setup-dotnet action to v4.3.1
2025-03-17 09:26:59 +01:00
renovate[bot]
747fa4699a Update actions/setup-dotnet action to v4.3.1 2025-03-17 04:59:58 +00:00
theguymadmax
407935d181 Fix IMDb URL for People 2025-03-16 19:00:00 -04:00
Joesph boukolos
6104d8d5f9 Translated using Weblate (Esperanto)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/eo/
2025-03-16 02:24:41 -04:00
Cody Robibero
8a6d1402d2 Merge pull request #13493 from gnattu/fix-subnet-check-master 2025-03-15 08:35:55 -06:00
Bond-009
e684f26c97 Add start index to /Programs/Recommended endpoint (#13696) 2025-03-15 08:35:08 -06:00
Lampan-git
cf1f251f2a Preserve null sortOrder during migration 2025-03-14 21:07:34 +01:00
Tim Eisele
0eed5ee79b Fix build and tests (#13718) 2025-03-14 08:17:18 -06:00
renovate[bot]
7d6bf5cb0d Update dependency python to 3.13 (#13701)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-13 19:36:41 -06:00
renovate[bot]
14e3b2214a Update dependency dotnet-ef to 9.0.3 (#13703)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-13 19:36:31 -06:00
renovate[bot]
b346d12e1c Update Microsoft to 9.0.3 (#13702)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-13 19:36:21 -06:00
Joshua M. Boniface
79437f85c5 Merge pull request #13175 from Shadowghost/external-url-providers
Migrate to IExternalUrlProvider
2025-03-13 21:08:18 -04:00
Thunderstrike116
8cb5ea60d6 Translated using Weblate (Greek)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/el/
2025-03-13 07:47:27 -04:00
gnattu
cbca153132 More typos 2025-03-13 06:27:12 +08:00
Joshua M. Boniface
f87150bb3d Merge pull request #9560 from IDisposable/sort-nfo-data
Sort embedded collections in Nfo files
2025-03-12 18:14:04 -04:00
Marc Brooks
a5f3d942f6 Merge branch 'master' into sort-nfo-data 2025-03-12 10:33:27 -05:00
gnattu
237e7bd44b Backport pull request #13694 from jellyfin/release-10.10.z
Clone fallback audio tags instead of use ATL.Track.set

Original-merge: 9eb2044eae

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

Backported-by: Bond_009 <bond.009@outlook.com>
2025-03-12 08:40:33 -04:00
Bond-009
28fc0e4796 Merge pull request #13690 from theguymadmax/add-cleanName
Include CleanName in LibraryDb migration query
2025-03-12 13:32:24 +01:00
Thunderstrike116
490e087b46 Translated using Weblate (Greek)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/el/
2025-03-12 06:53:53 -04:00
denys.kozhevnikov
4325c67e89 Add ability to provide search pattern 2025-03-11 21:04:12 +00:00
theguymadmax
f1dd065eca Include CleanName in LibraryDb migration query 2025-03-10 11:50:28 -04:00
congerh
de5b6470be Backport pull request #13659 from jellyfin/release-10.10.z
Upgrade LrcParser to 2025.228.1

Original-merge: ae6a7acf14

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

Backported-by: Bond_009 <bond.009@outlook.com>
2025-03-10 06:56:51 -04:00
Bond-009
6331de2e13 Merge pull request #13406 from Shadowghost/extract-trickplay-master
Extract trickplay files into own subdirectory
2025-03-10 11:00:12 +01:00
Bond-009
9c5a304142 Merge pull request #13675 from te9c/master
Include SortName in LibraryDb migration query
2025-03-10 10:52:30 +01:00
Bond-009
ea8be12dea Merge pull request #13683 from jellyfin/renovate/z440.atl.core-6.x
Update dependency z440.atl.core to 6.19.0
2025-03-10 10:50:49 +01:00
Bond-009
ab99572eb2 Merge pull request #13671 from jellyfin/renovate/ci-deps
Update CI dependencies
2025-03-10 10:48:26 +01:00
Thunderstrike116
0d7eb48930 Translated using Weblate (Greek)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/el/
2025-03-09 16:25:43 -04:00
Thunderstrike116
8ef7b4f9b5 Translated using Weblate (Greek)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/el/
2025-03-09 16:08:08 -04:00
renovate[bot]
f5adbc0296 Update CI dependencies 2025-03-09 17:00:13 +00:00
renovate[bot]
cb650c69b8 Update dependency z440.atl.core to 6.19.0 2025-03-09 12:45:55 +00:00
Roman Dordzheev
70b8fa73f0 Include SortName in LibraryDb migration query 2025-03-08 13:55:21 +03:00
Lampan-git
7abb94d8a2 Move mapping assignment to Map 2025-03-05 22:37:18 +01:00
Lampan-git
e137a06362 Change PeopleBaseItemMap query from GroupJoin to Include 2025-03-05 16:59:49 +01:00
Lampan-git
4e3d7383f5 Change GetPeople PeopleBaseItemMap code to query 2025-03-05 16:59:31 +01:00
Troj@
ab369f27f7 Translated using Weblate (Belarusian)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/be/
2025-03-04 14:47:09 -05:00
Troj@
728819780a Translated using Weblate (Belarusian)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/be/
2025-03-04 08:58:12 -05:00
IDisposable
efb901c369 Backport pull request #13639 from jellyfin/release-10.10.z
Support more rating formats

Original-merge: 4f94d23011

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

Backported-by: Bond_009 <bond.009@outlook.com>
2025-03-02 11:23:02 -05:00
Lampan-git
aad7506e85 Backport pull request #13618 from jellyfin/release-10.10.z
Include Role and SortOrder in MergePeople to fix "Search for missing metadata"

Original-merge: fcdef875a2

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

Backported-by: Bond_009 <bond.009@outlook.com>
2025-03-02 11:23:01 -05:00
Bond-009
d116f989a8 Merge pull request #13643 from l2dy/patch-1
Fix possible NullReferenceException in playlist warning
2025-03-02 17:21:58 +01:00
Zero King
82b3135dd9 Fix possible NullReferenceException in playlist warning 2025-03-02 01:03:55 +08:00
Bond-009
a8d9607298 Merge pull request #13608 from jellyfin/renovate/z440.atl.core-6.x
Update dependency z440.atl.core to 6.18.0
2025-03-01 16:01:32 +01:00
JPVenson
feea5af2f3 Merge remote-tracking branch 'jellyfinorigin/master' into feature/DatabaseRefactor 2025-03-01 14:16:49 +00:00
JPVenson
a6b4d124d7 Replicated changes made from #13492 2025-03-01 14:16:02 +00:00
Bond-009
04f7cd6011 Merge pull request #13492 from gnattu/dont-use-returning-clause
Don't use RETURNING clause with EFCore
2025-03-01 14:54:51 +01:00
Bond-009
710c253318 Merge pull request #13606 from nielsvanvelzen/goodbye-wal
Remove deprecated GetWakeOnLanInfo endpoint
2025-03-01 14:53:19 +01:00
Marc Brooks
f035b11625 Better exception message when folders or folder items are missing (#13632)
Emit the not-found Id in the exception for easier diagnosis
2025-02-28 23:01:21 -07:00
Dominik Krivohlavek
93dd5551df Add support for reading and storing Recording MBIDs from file metadata (#12173)
* Add recording metadata provider

* Add recording MBID

* Save recording MBID during probing

* Set recording ID in probe result normalizer

* Add recording external media type

* Reimplement after changes in upstream

* Rename variable

* Rename variable

* Revert "Set recording ID in probe result normalizer"

This reverts commit 9dd18c8aba.

* Fix setting provider ID

* Simplify code

* Fix comment

* Add missing using
2025-02-28 23:00:52 -07:00
Bond-009
f6603018d6 Merge pull request #13625 from jellyfin/renovate/ci-deps
Update actions/download-artifact action to v4.1.9
2025-02-28 21:51:56 +01:00
Balázs Meskó
0803600afd Translated using Weblate (Hungarian)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/hu/
2025-02-26 06:01:18 -05:00
renovate[bot]
c38e887ea5 Update actions/download-artifact action to v4.1.9 2025-02-26 00:31:28 +00:00
Bond-009
1131b051d8 Backport pull request #13601 from jellyfin/release-10.10.z
Delete children from cache on parent delete

Original-merge: 767a5e6193

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

Backported-by: Bond_009 <bond.009@outlook.com>
2025-02-25 15:32:03 -05:00
Bond-009
33e8c18136 Backport pull request #13593 from jellyfin/release-10.10.z
Wait for ffmpeg to exit on Windows before we try deleting the concat file

Original-merge: 346f36bc09

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

Backported-by: Bond_009 <bond.009@outlook.com>
2025-02-25 15:32:02 -05:00
Shadowghost
06be4998e1 Backport pull request #13611 from jellyfin/release-10.10.z
Remove empty ParentIndexNumber workaround

Original-merge: 1daf761aec

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

Backported-by: Bond_009 <bond.009@outlook.com>
2025-02-25 15:26:47 -05:00
Lampan-git
d28ee96f06 Include PeopleBaseItemMap in GetPeople 2025-02-25 18:10:50 +01:00
Marc Brooks
114591c1aa Clean up usings and honor SortName 2025-02-25 01:51:38 -06:00
Jxiced
e7bc86ebb8 Move throw into interface to use in wizard, check for null and invalid username. 2025-02-23 22:16:35 +00:00
millallo
068bc68764 Translated using Weblate (Italian)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/it/
2025-02-23 07:55:12 -05:00
renovate[bot]
7f8eb179a6 Update dependency z440.atl.core to 6.18.0 2025-02-23 12:38:16 +00:00
Jxiced
7aa96dfc20 Update contributors. 2025-02-22 22:34:41 +00:00
Tim Eisele
260f1323d8 Apply suggestions from code review
Co-authored-by: Cody Robibero <cody@robibe.ro>
2025-02-22 18:59:37 +01:00
Bond-009
10c6266989 Merge pull request #13603 from jellyfin/renovate/ci-deps
Update CI dependencies
2025-02-22 17:01:14 +01:00
Niels van Velzen
d18066f0f2 Remove GetMacAddresses from NetworkManager 2025-02-22 10:27:42 +01:00
Niels van Velzen
83b2c47237 Remove deprecated GetWakeOnLanInfo endpoint 2025-02-22 10:23:33 +01:00
Jxiced
70d07b830d Prevent whitespaces in username during wizard setup. 2025-02-21 21:19:20 +00:00
renovate[bot]
a4aefc8a80 Update CI dependencies 2025-02-21 20:25:39 +00:00
Bond-009
a9f84b92df Merge pull request #13584 from jellyfin/renovate/ci-deps
Update appleboy/ssh-action action to v1.2.1
2025-02-21 16:06:20 +01:00
JPVenson
8c0b0d9102 Merge remote-tracking branch 'jellyfinorigin/master' into feature/10.10/DetachedMigration 2025-02-21 11:08:09 +00:00
JPVenson
963f2357a9 simplified logfile path 2025-02-21 11:06:28 +00:00
JPVenson
7735aafef5 renaming of jfHost
usings cleanup
2025-02-21 11:05:47 +00:00
JPVenson
a05b3be1b3 Fixed nullability on startupService 2025-02-21 11:00:01 +00:00
Shadowghost
5ff2767012 Use TryGetProviderId where possible 2025-02-21 11:58:46 +01:00
theguymadmax
7ca09c4081 Backport pull request #13594 from jellyfin/release-10.10.z
Fix 4K filtering when grouping movies into collections

Original-merge: 317d7a9f4f

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

Backported-by: Bond_009 <bond.009@outlook.com>
2025-02-21 05:39:38 -05:00
JPVenson
05f5d19ff4 fixed new project paths 2025-02-20 19:56:59 +00:00
Bond-009
51e0ce7ea4 Merge pull request #13556 from Jxiced/master
Don't allow usernames to have leading or trailing spaces
2025-02-20 12:04:43 +01:00
JPVenson
3e223ead1e Fixed references for database projects 2025-02-20 10:02:47 +00:00
JPVenson
69e3e4c468 Fixed readme for migrations 2025-02-20 09:59:21 +00:00
JPVenson
44dfe554a8 Moved Database projects under /src
removed old pgsql references
2025-02-20 09:55:02 +00:00
Bond-009
0dbd875dd0 Merge pull request #13567 from jellyfin/renovate/z440.atl.core-6.x
Update dependency z440.atl.core to 6.17.0
2025-02-20 10:36:31 +01:00
Shadowghost
5303445c9b Migrate to IExternalUrlProvider 2025-02-20 10:13:27 +01:00
JPVenson
f07e1f4aae Reverted Comparison code for name check 2025-02-19 18:30:18 +00:00
JPVenson
d8030147ff Merge remote-tracking branch 'jellyfinorigin/master' into feature/DatabaseRefactor 2025-02-19 18:25:00 +00:00
JPVenson
ddc20b74bf Removed pgsql from refactor 2025-02-19 18:21:23 +00:00
JPVenson
8b07c1f53d Fixed gitignore for pgsql data 2025-02-19 15:38:32 +00:00
renovate[bot]
a085b90e05 Update appleboy/ssh-action action to v1.2.1 2025-02-19 12:53:13 +00:00
Cody Robibero
712908d53c Revert nullability of MediaStream.IsHearingImpaired (#13573) 2025-02-17 19:20:18 -07:00
renovate[bot]
523123dd36 Update dependency z440.atl.core to 6.17.0 2025-02-16 16:26:43 +00:00
pbf801
03a2b2f2e8 Translated using Weblate (Catalan)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/ca/
2025-02-16 06:01:18 -05:00
Cody Robibero
06527fae6e Disallow incremental updates to JellyfinDbModelSnapshot (#13564) 2025-02-15 18:33:45 -07:00
Bond-009
66e571cd97 Merge pull request #13553 from crobibero/efcore-livetv-epg
Change BaseItemEntity ChannelId to nullable Guid
2025-02-15 19:21:16 +01:00
Jxiced
84450bb297 Update Jellyfin.Server.Implementations/Users/UserManager.cs
Co-authored-by: gnattu <gnattu@users.noreply.github.com>
2025-02-14 18:13:05 +00:00
Jxiced
b5fcbfc15e Update test cases. 2025-02-14 17:49:25 +00:00
Jxiced
237c1d9b97 Update regex and revert previous changes to ThrowIfInvalidUsername. 2025-02-14 17:46:23 +00:00
Jxiced
a0ab0eb875 Update ThrowIfInvalidUsername to include whitespaces. 2025-02-14 17:01:01 +00:00
Bond-009
2db0750abb Make the JsonConverters for delimited arrays more generic (#13396)
* Make the JsonConverters for delimited arrays more generic

Also adds some tests for serialization (with different types) as we didn't have any before.

* Ignore warnings
2025-02-13 20:24:55 -07:00
choyakawa
fb69b976bf Fix the issue where the external audio track always defaults. (#13132) 2025-02-13 20:24:39 -07:00
gnattu
fa97e8e183 Write only for query columns to EFCore db (#13542)
* Write only for query columns to EFCore db.

We currently don't write the columns that do not exist on the BaseItem class definition in db. However, columns like `CleanName` is still useful and being used by internal queries and current behavior would cause such query to return nothing.

The only exception is the UserDataKey which is not even being used for internal query that can be omitted.

* Update comment
2025-02-13 20:19:24 -07:00
Cody Robibero
debc499711 Change BaseItemEntity ChannelId to nullable Guid 2025-02-13 20:17:25 -07:00
renovate[bot]
b2a2fd6fcc Update danielpalme/ReportGenerator-GitHub-Action action to v5.4.4 (#13528)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-13 19:13:40 -07:00
renovate[bot]
475bfd3e32 Update Microsoft (#13534)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-13 19:13:22 -07:00
renovate[bot]
fb9f983d20 Update dependency dotnet-ef to 9.0.2 (#13548)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-13 19:13:03 -07:00
gnattu
1ebef57508 Backport pull request #13532 from jellyfin/release-10.10.z
Fix image encoding concurrency limit

Original-merge: 3f539472f3

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

Backported-by: Bond_009 <bond.009@outlook.com>
2025-02-13 09:49:58 -05:00
Bond-009
17e78c0d40 Merge pull request #13539 from gnattu/mimic-old-get-item-value-names
Simulate old GetItemValueNames behavior
2025-02-13 13:37:05 +01:00
Cody Robibero
dd7a804cfb Merge pull request #13516 from tkloy24/13510-Search-Results-Case-Insensitive-For-People
Fix Search results are case-sensitive for people
2025-02-12 07:55:17 -07:00
gnattu
d2e7ab1c1a Simulate old GetItemValueNames behavior
The GetItemValueNames function in the old implementation was intended to retrieve the original value rather than the cleaned value. The old implementation lacked a clear specification regarding which value to return for the non-cleaned value in a group and relied on an undefined behavior of SQLite, and this implementation assumes the first one is the desired one.
2025-02-11 11:45:53 +08:00
Loris Laera
f12acb014a Translated using Weblate (Luxembourgish)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/lb/
2025-02-10 11:01:19 -05:00
Thadah D. Denyse
b91f63ce8b Translated using Weblate (Basque)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/eu/
2025-02-10 11:01:19 -05:00
Abdullah Khaled
2b5cb5f9f4 Translated using Weblate (Arabic)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/ar/
2025-02-10 11:01:19 -05:00
Bond-009
dc654065f2 Merge pull request #13527 from Bond-009/fixbuildagain
Rename CreateOrUpdateItems back to CreateItems
2025-02-10 12:31:47 +01:00
Bond-009
ccaaaca712 Merge pull request #13521 from jellyfin/renovate/z440.atl.core-6.x
Update dependency z440.atl.core to 6.16.0
2025-02-10 12:03:03 +01:00
Bond_009
ce76817020 Rename CreateOrUpdateItems back to CreateItems
Reverts the name change of this function made in the EFCore PR. This hopefully
reduces the amount of merge conflicts while backporting and makes it consistent
with the CreateItem function.
2025-02-09 18:30:53 +01:00
IDisposable
c9c90050d9 Backport pull request #13504 from jellyfin/release-10.10.z
Fix LiveTV Guide Backdrop image not updating

Original-merge: 8544e7fc72

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

Backported-by: Bond_009 <bond.009@outlook.com>
2025-02-09 12:22:49 -05:00
Shadowghost
9e13003fbb Backport pull request #13469 from jellyfin/release-10.10.z
Fix SchedulesDirect image prefetching

Original-merge: 21e398ba0c

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

Backported-by: Bond_009 <bond.009@outlook.com>
2025-02-09 12:22:48 -05:00
elfalem
ba46608ffe Backport pull request #12721 from jellyfin/release-10.10.z
Skip allowed tags check for parents of an item

Original-merge: d1fbdcee34

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

Backported-by: Bond_009 <bond.009@outlook.com>
2025-02-09 12:19:51 -05:00
renovate[bot]
b6dad55ad3 Update dependency z440.atl.core to 6.16.0 2025-02-09 16:52:53 +00:00
renovate[bot]
6922fd0a38 Update github/codeql-action action to v3.28.9 (#13517)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-09 09:50:12 -07:00
gnattu
7a5a4ad7da Handle empty image lists gracefully in SplashscreenPostScanTask (#13498)
The current linq will just throw when there is no image candidates. Just pass empty lists to `CreateSplashscreen` as this case is already handled there.
2025-02-09 09:45:16 -07:00
Joshua M. Boniface
075fec6fc6 Remove check-backport CI action (#13523)
This has not worked reliably in a long time, and results in the majority
of PRs having a failing CI status. Just remove it; we'll handle
backports manually as needed.
2025-02-09 09:30:34 -07:00
Loris Laera
75c0a7a107 Added translation using Weblate (Luxembourgish) 2025-02-09 10:13:07 -05:00
Thadah D. Denyse
e1dd2dce92 Translated using Weblate (Basque)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/eu/
2025-02-09 10:13:07 -05:00
crobibero
b11de39c34 Backport pull request #13499 from jellyfin/release-10.10.z
Allow api key to subscribe to admin websockets

Original-merge: 03082e90f9

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

Backported-by: Bond_009 <bond.009@outlook.com>
2025-02-09 08:50:53 -05:00
gnattu
f4a2679177 Backport pull request #13490 from jellyfin/release-10.10.z
Correctly handle audio number tag fallbacks

Original-merge: 117d2082aa

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

Backported-by: Bond_009 <bond.009@outlook.com>
2025-02-09 08:39:56 -05:00
JPVenson
db2167178a Backport pull request #13459 from jellyfin/release-10.10.z
Fixed Websocket not locking state correctly

Original-merge: 49bb5a6442

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

Backported-by: Bond_009 <bond.009@outlook.com>
2025-02-09 08:39:55 -05:00
Bond-009
69784b2f17 Backport pull request #13439 from jellyfin/release-10.10.z
Fall back to calculating mime type from path when needed

Original-merge: 8aa4e2e320

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

Backported-by: Bond_009 <bond.009@outlook.com>
2025-02-09 08:39:54 -05:00
Tobias Kloy
83f0f3d629 Optimise string handling in PeopleRepository filtering. 2025-02-07 22:20:35 +01:00
Tobias Kloy
3a4d67319a Disable Warnings similar as in BaseItemRepository 2025-02-07 20:37:35 +01:00
tkloy24
7f41cc53ca Update Jellyfin.Server.Implementations/Item/PeopleRepository.cs
Co-authored-by: JPVenson <ger-delta-07@hotmail.de>
2025-02-07 19:46:38 +01:00
Tobias Kloy
0a4ca33d4f Fix Search results are case-sensitive for people 2025-02-07 14:38:33 +01:00
gnattu
341bb02422 Order MediaStream query by StreamIndex (#13506)
Our stream index calculation logic implemented in #7529, assumes an in-order array. However, our current query may return out-of-order items, leading the server to pass an incorrect index to ffmpeg, causing the transcoding to crash.
2025-02-06 07:15:29 -07:00
Marc Brooks
4e64b261a8 Moved Trimmed to Jellyfin.Extensions.StringExtensions 2025-02-05 18:13:28 -06:00
CrimsonBlue
ead7de18df Translated using Weblate (Haitian)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/ht/
2025-02-05 18:01:17 -05:00
JPVenson
dfdef511a5 Merge remote-tracking branch 'jellyfinorigin/master' into feature/pgsql_provider 2025-02-05 18:32:13 +00:00
Bond-009
00b66a06ea Enable nullable for AuthorizationInfo (#13485) 2025-02-04 17:10:39 -07:00
gnattu
9aec576c76 Typo
Co-authored-by: Cody Robibero <cody@robibe.ro>
2025-02-05 08:04:29 +08:00
gnattu
2de04cb07c Make StartDate/EndDate nullable (#13494)
These dates are used as birthdate and death date for person (ask luke for why) and a non-nullable column would cause the null date become 1901-01-01, making all living people dead.
2025-02-04 17:02:07 -07:00
CrimsonBlue
e7f32fb174 Added translation using Weblate (Haitian) 2025-02-04 17:22:58 -05:00
Bond-009
1acefa6182 Update dependency FsCheck.Xunit to 3.1.0 (#13463)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-04 15:00:35 +01:00
gnattu
533ceeaaf2 Fix subnet contains check
We are still using `Subnet.Contains` a lot but that does not handle IPv4 mapped to IPv6 addresses at all. It was partially fixed by #12094 in local network checking, but it may not always happen on LAN.

Also make all local network checking to use IsInLocalNetwork method instead of just performing `Subnet.Contains` which is not accurate.

Filter out all link-local addresses for external interface matching.
2025-02-04 16:52:17 +08:00
gnattu
b0e853070b Don't use RETURNING clause with EFCore
The RETURNING clause helps with performance and is now default of EFCore. However, EFCore cannot automatically perform retry when the table was locked/busy. Disable it as a workaround for the locking issues of very huge databases.
2025-02-04 15:57:57 +08:00
Marc Brooks
e8cbcde02e Merge branch 'master' into sort-nfo-data 2025-02-03 19:48:59 -06:00
Bond-009
d376b5fbc7 Fix build after backports due to EFCore change (#13488) 2025-02-03 16:37:39 -07:00
Shadowghost
c77b3fa258 Backport pull request #13448 from jellyfin/release-10.10.z
Fix interface ordering again

Original-merge: 731874429c

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

Backported-by: Bond_009 <bond.009@outlook.com>
2025-02-03 17:07:13 -05:00
Bond-009
10f4f8b2ab Backport pull request #13425 from jellyfin/release-10.10.z
Open files with FileShare.Read for BlurHash calculations

Original-merge: bfe0fdbcdc

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

Backported-by: Bond_009 <bond.009@outlook.com>
2025-02-03 17:07:12 -05:00
gnattu
c05a41cc3c Backport pull request #13423 from jellyfin/release-10.10.z
Don't select audio stream and codec explicitly for copy when bitrate exceeds limit

Original-merge: e8514de33b

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

Backported-by: Bond_009 <bond.009@outlook.com>
2025-02-03 17:07:11 -05:00
gnattu
24be951b75 Backport pull request #13411 from jellyfin/release-10.10.z
Use WriteThrough for ImageSaver

Original-merge: 6329de4fc3

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

Backported-by: Bond_009 <bond.009@outlook.com>
2025-02-03 17:07:10 -05:00
gnattu
dc28056450 Backport pull request #13390 from jellyfin/release-10.10.z
Catch IOExceptions for GetFileSystemMetadata

Original-merge: 3766a88bea

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

Backported-by: Bond_009 <bond.009@outlook.com>
2025-02-03 17:07:09 -05:00
Shadowghost
abdb5ab79e Backport pull request #13388 from jellyfin/release-10.10.z
Fix rating levels

Original-merge: 53a45c6033

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

Backported-by: Bond_009 <bond.009@outlook.com>
2025-02-03 17:07:08 -05:00
alltilla
eb4162f9ec Backport pull request #13384 from jellyfin/release-10.10.z
Fix parallel use of not thread-safe SubtitleFormat instance

Original-merge: 0b2a59e963

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

Backported-by: Bond_009 <bond.009@outlook.com>
2025-02-03 16:59:08 -05:00
Shadowghost
608c44d5b3 Backport pull request #13382 from jellyfin/release-10.10.z
Fix interface selection

Original-merge: 0394965753

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

Backported-by: Bond_009 <bond.009@outlook.com>
2025-02-03 16:59:07 -05:00
gnattu
ceba3475fb Backport pull request #13345 from jellyfin/release-10.10.z
Never treat matroska as webm for audio playback

Original-merge: 344cc8b97b

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

Backported-by: Bond_009 <bond.009@outlook.com>
2025-02-03 16:59:06 -05:00
gnattu
d52ab30ae9 Backport pull request #13313 from jellyfin/release-10.10.z
Use nv15 as intermediate format for 2-pass rkrga scaling

Original-merge: 5c6317f68d

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

Backported-by: Bond_009 <bond.009@outlook.com>
2025-02-03 16:59:05 -05:00
Shadowghost
e79fc6b851 Backport pull request #13288 from jellyfin/release-10.10.z
Fix DTS in HLS

Original-merge: cea0c95942

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

Backported-by: Bond_009 <bond.009@outlook.com>
2025-02-03 16:59:04 -05:00
gnattu
4595625f19 Backport pull request #13262 from jellyfin/release-10.10.z
Don't use custom params on ultrafast x265 preset

Original-merge: 86160cd99c

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

Backported-by: Bond_009 <bond.009@outlook.com>
2025-02-03 16:59:03 -05:00
Shadowghost
c44006c20d Backport pull request #13227 from jellyfin/release-10.10.z
Fix EPG image caching

Original-merge: b9881b8bdf

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

Backported-by: Bond_009 <bond.009@outlook.com>
2025-02-03 16:59:01 -05:00
Shadowghost
eac491fbd3 Backport pull request #13218 from jellyfin/release-10.10.z
Fix missing episode removal

Original-merge: 4e28f4fe03

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

Backported-by: Bond_009 <bond.009@outlook.com>
2025-02-03 16:56:03 -05:00
gnattu
8cb11692a9 Backport pull request #13209 from jellyfin/release-10.10.z
Transcode to audio codec satisfied other conditions when copy check failed.

Original-merge: 8aa41d5904

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

Backported-by: Bond_009 <bond.009@outlook.com>
2025-02-03 16:56:01 -05:00
Bond-009
533464e186 Backport pull request #13188 from jellyfin/release-10.10.z
Fix possible infinite loops in incomplete MKV files

Original-merge: 6f7ce439d3

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

Backported-by: Bond_009 <bond.009@outlook.com>
2025-02-03 16:56:00 -05:00
gnattu
2392290b72 Backport pull request #13187 from jellyfin/release-10.10.z
Properly check LAN IP in HasRemoteAccess

Original-merge: eb5f8d49dd

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

Backported-by: Bond_009 <bond.009@outlook.com>
2025-02-03 16:55:59 -05:00
gnattu
144e62027d Backport pull request #13183 from jellyfin/release-10.10.z
Don't generate trickplay for backdrops

Original-merge: 80940c0c57

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

Backported-by: Bond_009 <bond.009@outlook.com>
2025-02-03 16:55:58 -05:00
gnattu
4c17498369 Backport pull request #13182 from jellyfin/release-10.10.z
Don't fall back to ffprobe results for multi-value audio tags

Original-merge: f97f38585b

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

Backported-by: Bond_009 <bond.009@outlook.com>
2025-02-03 16:55:56 -05:00
gnattu
b79f96e98b Backport pull request #13169 from jellyfin/release-10.10.z
Check if the video has an audio track before codec fallback

Original-merge: ff4f3b0441

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

Backported-by: Bond_009 <bond.009@outlook.com>
2025-02-03 16:55:55 -05:00
Shadowghost
f46cb112f7 Backport pull request #13167 from jellyfin/release-10.10.z
Fix NFO ID parsing

Original-merge: f0e9b2fb96

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

Backported-by: Bond_009 <bond.009@outlook.com>
2025-02-03 16:55:54 -05:00
nyanmisaka
bc1419728f Backport pull request #13151 from jellyfin/release-10.10.z
Always do tone-mapping for HDR transcoding when software pipeline is used

Original-merge: b31f1696f2

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

Backported-by: Bond_009 <bond.009@outlook.com>
2025-02-03 16:55:53 -05:00
gnattu
39cd3dcbd1 Backport pull request #13127 from jellyfin/release-10.10.z
Fallback to lossy audio codec for bitrate limit

Original-merge: 65f722f23c

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

Backported-by: Bond_009 <bond.009@outlook.com>
2025-02-03 16:54:36 -05:00
TheMelmacian
51207edf44 Backport pull request #13092 from jellyfin/release-10.10.z
Fix: handling of <set> elements in NfoParser

Original-merge: f333ef74b3

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

Backported-by: Bond_009 <bond.009@outlook.com>
2025-02-03 16:54:35 -05:00
JPVenson
078587d232 Added Version string to application name connection for pgsql 2025-02-03 20:20:37 +00:00
JPVenson
df8f352d65 Made key lookup case insensitive 2025-02-03 20:16:58 +00:00
JPVenson
c9237ae731 Applied review suggestions 2025-02-03 20:15:36 +00:00
renovate[bot]
cfeb879519 Update dependency z440.atl.core to 6.15.0 (#13477)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-03 16:38:29 +01:00
JPVenson
efb402b1d2 Fixed shutdown behavior 2025-02-02 02:32:28 +00:00
JPVenson
61b2ad7f49 Added missing assembly info and fixed migration tests 2025-02-02 02:21:34 +00:00
JPVenson
2e5ff6842a Added collation migration in SqLite 2025-02-02 02:13:37 +00:00
JPVenson
4b57f2bdbb Fixed whitespace formatting 2025-02-02 02:10:14 +00:00
JPVenson
17003f4d76 Merge remote-tracking branch 'jellyfinorigin/master' into feature/pgsql_provider 2025-02-02 02:09:14 +00:00
JPVenson
ebe89c07b3 Fixed collation and pgsql container 2025-02-02 02:07:04 +00:00
renovate[bot]
6a757ac0e5 Update dependency FsCheck.Xunit to 3.1.0 2025-01-31 01:44:19 +00:00
sinterdev
ce64dbc034 Removing CollectionFolders from cache when they are deleted on disk. (#13315) 2025-01-30 18:43:37 -07:00
renovate[bot]
4fa2f2475c Update CI dependencies (#13460)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-30 13:59:24 +01:00
JPVenson
379a104cfb Changed UserName to non-deterministic field 2025-01-29 20:17:50 +00:00
renovate[bot]
d583d9a313 Update github/codeql-action action to v3.28.7 (#13458)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-29 18:41:17 +01:00
luzpaz
6fda268892 Merge pull request #13453 from luzpaz/extentions-typo
Fix source typo
2025-01-29 16:56:25 +01:00
LK HO
350b7feefa 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-01-29 10:01:17 -05:00
Bond-009
9734892322 Merge pull request #12925 from Bond-009/await
Always await instead of directly returning Task
2025-01-28 11:29:46 +01:00
Bond-009
bcdffa74a8 Remove useless checks and dead code (#13405)
* Remove useless checks and dead code

* Enable adaptive bitrate streaming again

* Disable adaptive bitrate streaming by default
2025-01-28 11:29:22 +01:00
Josh Soref
0869a4f1f6 chore(ci): Let CI fail independently on each platform (#13446)
Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>
2025-01-28 11:27:52 +01:00
Josh Soref
40da2ccac5 Fix spelling (#13444)
* spelling: anamorphic

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: associated

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: channelinfo

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: eagerly

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: enumerable

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: greater than/less than

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: greater

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: lineup

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: logs out

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: names

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: paging

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: playlist

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: sanitized

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: saving

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

---------

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>
2025-01-28 11:27:34 +01:00
renovate[bot]
e806fec902 Update CI dependencies (#13452)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-28 11:24:10 +01:00
myrad2267
44173cc802 Translated using Weblate (French (Canada))
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/fr_CA/
2025-01-28 05:20:20 -05:00
JPVenson
d07e1a13b3 Fixed collation settings 2025-01-27 20:55:39 +00:00
JPVenson
74858042fc Added devcontainer for pgsql development 2025-01-27 19:14:11 +00:00
JPVenson
4ce0d498ab Added pgsql devcontainer 2025-01-27 18:32:36 +00:00
JPVenson
ce00bc076e Fixed postgres sql provider 2025-01-27 18:21:47 +00:00
JPVenson
433640d985 Added pgsql support for jellyfin 🎉 2025-01-27 17:43:34 +00:00
JPVenson
844646e2fe Fixed migration runner and added docs for adding migrations 2025-01-27 17:20:14 +00:00
JPVenson
9d1c4ea169 Fixed DbContext usage on Provider 2025-01-27 16:35:46 +00:00
Bond-009
2e080087e6 Merge pull request #13438 from luzpaz/typos-various
Fix typos
2025-01-27 14:13:31 +01:00
Bond-009
7684986fa1 Use MediaTypeNames where possible (#13440) 2025-01-26 21:06:24 -07:00
JPVenson
aa811eb1e3 Prepared Seperation of Database components for future multi provider support 2025-01-26 20:45:28 +00:00
Anrijs Vitolins
7e9ce78849 Translated using Weblate (Latvian)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/lv/
2025-01-26 14:01:17 -05:00
luzpaz
b37bc9016f Fix typos
Found via `codespell -q 3 -D ../../dictionary.txt -S "./Emby.Server.Implementations/Localization" -L allready,childrens,groupe,inh,raisons,re-use,som,supercede,superceded,thirdparty,whoknows`
2025-01-26 11:14:03 -05:00
Bond-009
0541808c25 Merge pull request #13431 from jellyfin/renovate/z440.atl.core-6.x
Update dependency z440.atl.core to 6.14.0
2025-01-26 16:55:55 +01:00
Bond-009
ab124bec88 Merge pull request #13436 from luzpaz/typos
Fix various typos
2025-01-26 16:54:53 +01:00
Bond-009
8b180aca3a Merge pull request #11103 from jsoref/spelling
Fix spelling
2025-01-26 16:54:43 +01:00
Shadowghost
6454a35ef8 Extract trickplay files into own subdirectory 2025-01-26 11:56:19 +01:00
luzpaz
c877ffa5ad Fix various typos
Found via `codespell -q 3 -S "./Emby.Server.Implementations/Localization" -L inh,som`
2025-01-25 21:04:37 -05:00
Josh Soref
044cf9fb85 chore: fix spelling
* a
* acceleration
* addition
* altogether
* api clients
* artist
* associated
* bandwidth
* cannot
* capabilities
* case-insensitive
* case-sensitive
* configuration
* delimiter
* dependent
* diacritics
* directors
* enable
* explicitly
* filters
* finish
* have
* hierarchy
* implicit
* include
* information
* into
* its
* keepalive
* localization
* macos
* manual
* matching
* metadata
* nonexistent
* options
* overridden
* parsed
* parser
* playback
* preferring
* processes
* processing
* provider
* ratings
* retrieval
* running
* segments
* separate
* should
* station
* subdirectories
* superseded
* supported
* system
* than
* the
* throws
* transpose
* valid
* was

link: forum or chat rooms

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>
2025-01-25 20:05:15 -05:00
renovate[bot]
cace593472 Update dependency z440.atl.core to 6.14.0 2025-01-25 21:51:07 +00:00
Bond-009
b318f33599 Remove the ability to auto port forward (#13222) 2025-01-25 09:34:06 -07:00
Bond-009
cc284afb47 Merge pull request #13410 from jellyfin/renovate/ci-deps
Update github/codeql-action action to v3.28.5
2025-01-25 11:27:31 +01:00
Joshua M. Boniface
93b8eade61 Merge pull request #12798 from JPVenson/feature/EFUserData
Refactor library.db into jellyfin.db and EFCore
2025-01-25 02:08:44 -05:00
renovate[bot]
4cdb2c7cfa Update github/codeql-action action to v3.28.5 2025-01-24 19:00:34 +00:00
Blackspirits
679ee960d3 Translated using Weblate (Portuguese)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/pt/
2025-01-24 03:39:55 -05:00
Bond-009
07dce33452 Merge pull request #13407 from jellyfin/renovate/fscheck.xunit-3.x
Update dependency FsCheck.Xunit to 3.0.1
2025-01-23 10:56:35 +01:00
Bond-009
8c01b64a83 Merge pull request #13408 from jellyfin/renovate/ci-deps
Update github/codeql-action action to v3.28.3
2025-01-23 10:44:01 +01:00
Bond_009
a70200af14 Disable adaptive bitrate streaming by default 2025-01-23 10:42:53 +01:00
lotko lol
87432e2368 Translated using Weblate (Slovenian)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/sl/
2025-01-22 17:26:23 -05:00
renovate[bot]
45412639fa Update github/codeql-action action to v3.28.3 2025-01-22 21:34:49 +00:00
renovate[bot]
724d9c18f7 Update dependency FsCheck.Xunit to 3.0.1 2025-01-22 21:34:44 +00:00
Bond-009
13c9880100 Merge pull request #13360 from reuterma24/doc-improvement-container-helper
improve documentation for ContainerHelper class
2025-01-22 17:44:37 +01:00
Bond-009
cd2255a3ad Add support for .gzip files and handle URL redirection (#13319)
Co-authored-by: Max <@>
2025-01-22 17:44:16 +01:00
renovate[bot]
e7c130abcf Update CI dependencies (#13400)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-22 17:41:08 +01:00
renovate[bot]
579b0f6565 Update dependency z440.atl.core to 6.13.0 (#13403)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-22 17:40:44 +01:00
Bond_009
3aa1ebb500 Enable adaptive bitrate streaming again 2025-01-22 17:36:26 +01:00
Bond_009
47f798827b Remove useless checks and dead code 2025-01-22 17:31:52 +01:00
renovate[bot]
5612d2187b Update dependency coverlet.collector to 6.0.4 (#13395)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-20 10:13:21 +01:00
JPVenson
64cf67f1ac Fixed ordering by artist 2025-01-19 13:03:09 +00:00
JPVenson
caa1a06dec Merge branch 'feature/EFUserData' of https://github.com/JPVenson/jellyfin into feature/EFUserData 2025-01-19 12:41:11 +00:00
JPVenson
48ae3bc0df Fixed tests again 2025-01-19 12:41:11 +00:00
JPVenson
7d1a9dcc61 Update Jellyfin.Server.Implementations/Item/BaseItemRepository.cs
Co-authored-by: Bond-009 <bond.009@outlook.com>
2025-01-19 13:30:31 +01:00
JPVenson
cd75df6521 Applied review comments 2025-01-19 12:29:14 +00:00
JPVenson
56a4aa180b Fixed codesmell 2025-01-18 16:22:05 +00:00
JPVenson
2f306358c0 applied review comments 2025-01-18 16:17:26 +00:00
PalmarHealer
b908fb5788 Translated using Weblate (German)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/de/
2025-01-18 10:28:51 -05:00
JPVenson
96e4d8ca78 worsen comment 2025-01-17 19:19:24 +00:00
felix920506
294190bb21 Update pull-request-conflict.yml 2025-01-16 08:05:56 -05:00
JPVenson
a7ad5dfc80 Reverted doc change 2025-01-15 20:34:24 +00:00
JPVenson
b33810534b Applied review comments 2025-01-15 20:12:41 +00:00
Sven Giermann
2624021d67 Add ability to remove a ChannelMapping (#12970)
* Add ability to remove a ChannelMapping

Remove a ChannelMapping by selecting the same mapping again.
This should be an intuitive way to de-select a mapping which currently requires the manual editing of a config file:
https://forum.jellyfin.org/t-how-to-unmap-livetv-channels

---------

Co-authored-by: Bond-009 <bond.009@outlook.com>
2025-01-15 11:26:39 +01:00
Bond-009
37e6ed5feb Merge pull request #13354 from jellyfin/renovate/sharpfuzz-2.x
Update dependency SharpFuzz to 2.2.0
2025-01-15 11:19:22 +01:00
Bond-009
c166387a5a Merge pull request #13374 from jellyfin/renovate/dotnet-monorepo
Update dependency dotnet-ef to 9.0.1
2025-01-15 11:15:34 +01:00
Bond-009
3cb7c48f85 Merge pull request #13373 from jellyfin/renovate/microsoft
Update Microsoft to 9.0.1
2025-01-15 11:10:21 +01:00
renovate[bot]
5b962534be Update dependency dotnet-ef to 9.0.1 2025-01-14 23:02:30 +00:00
renovate[bot]
04fe74ce8f Update Microsoft to 9.0.1 2025-01-14 23:02:12 +00:00
Bond-009
85e0cad5f3 Merge pull request #13353 from jellyfin/renovate/z440.atl.core-6.x
Update dependency z440.atl.core to 6.12.0
2025-01-13 11:07:44 +01:00
marudosurdo
0409849cc7 Translated using Weblate (Japanese)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/ja/
2025-01-13 00:01:16 -05:00
reuterma24
5a02ea4a31 added myself to CONTRIBUTORS.md 2025-01-12 18:57:29 +01:00
reuterma24
fdb489ae47 improve parameter documentation for ContainsContainer method in ContainerHelper class 2025-01-12 18:54:19 +01:00
renovate[bot]
6282455ff0 Update dependency SharpFuzz to 2.2.0 2025-01-12 00:33:12 +00:00
renovate[bot]
4c1a47bc53 Update dependency z440.atl.core to 6.12.0 2025-01-11 20:26:51 +00:00
JPVenson
d716a53ec2 Applied review comments 2025-01-11 18:13:16 +00:00
renovate[bot]
fb5da641f4 Update dependency FsCheck.Xunit to v3 (#13333)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Cody Robibero <cody@robibe.ro>
2025-01-11 09:37:28 -07:00
Niels van Velzen
fd3057b549 Add option to disable deprecated legacy authorization options (#13306) 2025-01-11 09:37:13 -07:00
Niels van Velzen
3b8e614819 Prefer ApiKey over api_key in generated URL's (#13342) 2025-01-11 09:35:44 -07:00
Bond-009
17bbe4a2cd Merge pull request #13347 from jellyfin/renovate/ci-deps
Update CI dependencies
2025-01-11 13:34:28 +01:00
stelle
42c1d7a915 Translated using Weblate (Malay)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/ms/
2025-01-11 05:01:16 -05:00
zzdovydas
8cf1a50b2e Translated using Weblate (Lithuanian)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/lt/
2025-01-11 05:01:16 -05:00
az2oo1
25ef02d8df Translated using Weblate (Arabic)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/ar/
2025-01-11 05:01:16 -05:00
renovate[bot]
ac9bafa7e7 Update CI dependencies 2025-01-10 20:48:35 +00:00
Bond-009
a4e41c751a Merge pull request #13339 from jellyfin/renovate/xunit-dotnet-monorepo
Update dependency xunit to 2.9.3
2025-01-09 16:58:22 +01:00
renovate[bot]
878e778fbc Update dependency xunit to 2.9.3 2025-01-08 20:42:37 +00:00
zichichi
5b63d093b1 Translated using Weblate (Italian)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/it/
2025-01-07 11:01:16 -05:00
Kachelkaiser
814264f62c Translated using Weblate (German)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/de/
2025-01-07 11:01:16 -05:00
Bond-009
649d41914f Merge pull request #13327 from jellyfin/renovate/ci-deps
Update eps1lon/actions-label-merge-conflict action to v3.0.3
2025-01-06 18:03:20 +01:00
renovate[bot]
b077d378fb Update eps1lon/actions-label-merge-conflict action to v3.0.3 2025-01-06 14:49:15 +00:00
Jashanpreet Singh
d22094be03 Translated using Weblate (Punjabi)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/pa/
2025-01-05 16:07:39 -05:00
Frederiks Kronbergs
4e87af6d03 Translated using Weblate (Latvian)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/lv/
2025-01-05 16:07:39 -05:00
Franco Castillo
07185bc32b Translated using Weblate (Spanish (Argentina))
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/es_AR/
2025-01-05 16:07:38 -05:00
Max
ab38009069 Add support for .gzip files and handle URL redirection 2025-01-04 02:12:29 -05:00
SamCurant453
c07bce97a1 Translated using Weblate (Bengali)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/bn/
2025-01-02 14:36:01 -05:00
Qian Qian
e16ea7b236 always sort season by index number 2025-01-01 11:47:14 +08:00
Bond-009
02358a662e Merge pull request #13304 from jellyfin/renovate/coverlet.collector-6.x
Update dependency coverlet.collector to 6.0.3
2024-12-31 11:16:32 +01:00
renovate[bot]
b5b7bd2959 Update dependency coverlet.collector to 6.0.3 2024-12-31 02:14:37 +00:00
Bond-009
b07231ae33 Merge pull request #13291 from jellyfin/renovate/ci-deps 2024-12-29 11:14:09 +01:00
renovate[bot]
0d8b387e71 Update danielpalme/ReportGenerator-GitHub-Action action to v5.4.3 2024-12-28 21:39:46 +00:00
theoverlordbamse
80d98379de Translated using Weblate (Danish)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/da/
2024-12-28 13:01:15 -05:00
dtalens
a9d299253e Translated using Weblate (Catalan)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/ca/
2024-12-28 13:01:15 -05:00
Bond-009
c966ad906c Merge pull request #13286 from jellyfin/renovate/ci-deps
Update actions/setup-dotnet action to v4.2.0
2024-12-27 10:39:11 +01:00
renovate[bot]
50463d2d17 Update actions/setup-dotnet action to v4.2.0 2024-12-26 23:13:41 +00:00
robertscerri
5774b601f5 Translated using Weblate (Maltese)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/mt/
2024-12-24 09:32:00 -05:00
Bond-009
4cbdb01c3d Merge pull request #13271 from jellyfin/renovate/libse-4.x
Update dependency libse to 4.0.10
2024-12-23 09:23:04 +01:00
Bond-009
c8c544dc5e Merge pull request #13272 from jellyfin/renovate/z440.atl.core-6.x
Update dependency z440.atl.core to 6.11.0
2024-12-23 09:22:49 +01:00
renovate[bot]
c0fd8dab22 Update dependency z440.atl.core to 6.11.0 2024-12-22 15:43:47 +00:00
renovate[bot]
b73e3637de Update dependency libse to 4.0.10 2024-12-22 15:43:38 +00:00
Bond-009
f8e2b866b3 Merge pull request #13263 from jellyfin/renovate/ci-deps 2024-12-22 00:31:15 +01:00
renovate[bot]
9ed55affa6 Update danielpalme/ReportGenerator-GitHub-Action action to v5.4.2 2024-12-21 21:07:47 +00:00
Bond-009
00163ce167 Merge pull request #13258 from jellyfin/renovate/ci-deps 2024-12-21 12:08:34 +01:00
renovate[bot]
87612ef20d Update github/codeql-action action to v3.28.0 2024-12-20 21:16:32 +00:00
Bond-009
c4d4419800 Merge pull request #13213 from Ich1goSan/master
move to new System.Threading.Lock type for better performance
2024-12-20 22:15:45 +01:00
Zigi84
17f0643147 Translated using Weblate (Serbian)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/sr/
2024-12-20 12:56:40 -05:00
Bond-009
170368f9c9 Merge pull request #13230 from jellyfin/renovate/z440.atl.core-6.x
Update dependency z440.atl.core to 6.10.0
2024-12-19 17:53:06 +01:00
Lai, Wei-Chen
ea0a78dd0b Translated using Weblate (Chinese (Traditional Han script))
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/zh_Hant/
2024-12-19 00:51:49 -05:00
JPVenson
dcfbf55794 Fixed linter 2024-12-19 00:10:47 +00:00
Bond-009
73a1259382 Merge pull request #13248 from jellyfin/renovate/ci-deps
Update actions/upload-artifact action to v4.5.0
2024-12-18 17:31:35 +01:00
renovate[bot]
695aa594f2 Update actions/upload-artifact action to v4.5.0 2024-12-17 23:45:40 +00:00
renovate[bot]
1143d9509f Update dependency z440.atl.core to 6.10.0 2024-12-15 16:11:40 +00:00
JPVenson
a0c568bc6c Applied review comments 2024-12-15 14:46:40 +00:00
JPVenson
1c3196dd5f Merge remote-tracking branch 'origin/master' into feature/EFUserData 2024-12-15 14:15:43 +00:00
Bond-009
55f5eaf0e3 Merge pull request #13193 from jellyfin/renovate/serilog.aspnetcore-9.x
Update dependency Serilog.AspNetCore to v9
2024-12-14 13:42:07 +01:00
renovate[bot]
6a91c80f12 Update dependency Serilog.AspNetCore to v9 2024-12-14 10:27:01 +00:00
Bond-009
23cf4bc94e Merge pull request #13195 from Shadowghost/merge-ruleset-editorconf
Migrate rulesets to .editorconf
2024-12-14 11:18:50 +01:00
Bond-009
fa5b8ee863 Merge pull request #13215 from jellyfin/renovate/ci-deps
Update github/codeql-action action to v3.27.9
2024-12-14 11:18:31 +01:00
renovate[bot]
e0d563782e Update github/codeql-action action to v3.27.9 2024-12-13 00:23:33 +00:00
Daniyar Alpyspayev
2614fecf8d move to new System.Threading.Lock type for better performance 2024-12-12 18:10:06 +05:00
Luca-Foglieni
b89877554c Translated using Weblate (Italian)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/it/
2024-12-11 11:46:33 -05:00
Bond-009
623d0cd8ad Merge pull request #13203 from jellyfin/renovate/ci-deps
Update github/codeql-action action to v3.27.7
2024-12-10 20:10:52 +01:00
Bond-009
9322e37b95 Merge pull request #13192 from jellyfin/renovate/serilog.settings.configuration-9.x
Update dependency Serilog.Settings.Configuration to v9
2024-12-10 18:47:43 +01:00
renovate[bot]
82cbd01354 Update github/codeql-action action to v3.27.7 2024-12-10 15:24:42 +00:00
Tim Eisele
6d74b97836 Update .editorconfig
Co-authored-by: Erwin de Haan <1627021+EraYaN@users.noreply.github.com>
2024-12-09 19:38:54 +01:00
Tim Eisele
4b11cad6d4 Cleanup 2024-12-09 17:25:51 +01:00
Tim Eisele
08027b1008 Migrate rulesets to .editorconf 2024-12-09 14:42:27 +01:00
gnattu
0fc288936d Enable VideoToolbox AV1 decode
This decoder differs from others provided by VideoToolbox in that it lacks any software fallback. To achieve consistent behavior with other VideoToolbox decoders, this PR implemented additional checking on the server to simulate the software fallback provided by VideoToolbox.

The current fallback checking mechanism is a temporary solution. In the long term, it should be replaced with a more capable hardware capability checking system.
2024-12-09 16:17:49 +08:00
renovate[bot]
692e7bd4c4 Update dependency Serilog.Settings.Configuration to v9 2024-12-09 00:40:57 +00:00
Bond-009
6691380c04 Merge pull request #13076 from theguymadmax/tv-icon-image-fix
Determine tv image type by extension if content-type is unavailable
2024-12-08 12:17:36 +01:00
Bond-009
f9aa93406b Merge pull request #13024 from jellyfin/renovate/major-dotnet-monorepo
Update dependency dotnet-ef to v9
2024-12-07 11:53:54 +01:00
renovate[bot]
88b8a13ecd Update dependency dotnet-ef to v9 2024-12-07 10:29:34 +00:00
JPVenson
fe1aab034e Merge branch 'jellyfin:master' into feature/EFUserData 2024-12-06 17:59:27 +01:00
Max
43fff5799b Fix code 2024-12-05 17:14:28 -05:00
Max
630de12e5e Apply review changes 2024-12-04 10:08:41 -05:00
Bond-009
1feceea508 Merge pull request #13152 from jellyfin/renovate/ci-deps
Update github/codeql-action action to v3.27.6
2024-12-04 09:33:39 +01:00
Bond-009
bd1eee5e27 Merge pull request #13141 from jellyfin/renovate/z440.atl.core-6.x
Update dependency z440.atl.core to 6.9.0
2024-12-03 19:33:31 +01:00
renovate[bot]
37f7bda3cc Update github/codeql-action action to v3.27.6 2024-12-03 14:47:46 +00:00
VC
3d819b74bd 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/
2024-12-02 06:32:10 -05:00
SenorSmartyPants
12c14ddb24 Round CommunityRating to nearest tenths 2024-12-01 22:08:15 -06:00
renovate[bot]
a7e5f43a8a Update dependency Xunit.SkippableFact to 1.5.23 (#13134)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-01 17:10:29 -07:00
RealGreenDragon
f1e020c0b0 Removed RemoveOldPlugins configuration flag (#13102) 2024-12-01 17:09:30 -07:00
Ethan Pippin
06923cbf2b Implement TaskTriggerInfoType enum (#12783) 2024-12-01 17:08:37 -07:00
renovate[bot]
b8c7cd5aa7 Update dependency z440.atl.core to 6.9.0 2024-12-01 15:48:40 +00:00
Bond-009
9ae1ac2513 Merge pull request #11222 from jellyfin/renovate/mimetypes-2.x
Update dependency MimeTypes to 2.5.2
2024-12-01 00:06:53 +01:00
gnattu
b7f6ccc306 Backport pull request #13113 from jellyfin/release-10.10.z
Only do DoVi remux when the client supports profiles without fallbacks

Original-merge: 9464f9e622

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

Backported-by: Bond_009 <bond.009@outlook.com>
2024-11-30 17:59:39 -05:00
Bond_009
5cbe71a1b2 Resolve audio/x-aac to .aac 2024-11-30 23:40:18 +01:00
Andrijan Jovanovski
ea45804213 Translated using Weblate (Macedonian)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/mk/
2024-11-30 15:31:41 -05:00
Bond-009
a1e635809b Merge pull request #12867 from Dessyreqt/master
Move TV-PG ratings to be in line with PG rating.
2024-11-30 12:10:14 +01:00
Kenneth Cochran
e922fe8582 Added test for ListsingsManager.DeleteListingsProvider(). (#12793)
* Added test for DeleteListingsProvider().

* Added myself to CONTRIBUTORS.md

* Removed unintentionally committed test SaveListingProvider_SavesProviderAndReturnsInfo()

* Cleaned up test in response to PR feedback.
2024-11-30 12:08:19 +01:00
JPVenson
556f4c4bfb Updated DevContainer to Bookworm Debian (#13037)
* Updated DevContainer to Bookworm Debian
Removed dual container and made FFmpeg install default

* Update .devcontainer/devcontainer.json

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

* Fixed Tabs

---------

Co-authored-by: Bond-009 <bond.009@outlook.com>
2024-11-30 12:07:48 +01:00
1hitsong
b03f478867 Fix typo in guide info endpoint comment (#13117) 2024-11-29 10:32:00 -07:00
DragoPrime
1272bb9a84 Translated using Weblate (Romanian)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/ro/
2024-11-26 15:00:03 -05:00
Bond-009
572c5e24fa Merge pull request #13097 from nielsvanvelzen/venson-cant-spell
Fix typo in LibraryOptions
2024-11-26 19:42:47 +01:00
Bond-009
9fef0b7e5f Merge pull request #13100 from jellyfin/renovate/svg.skia-2.x
Update dependency Svg.Skia to 2.0.0.4
2024-11-26 19:41:45 +01:00
renovate[bot]
a0746c9a46 Update dependency Svg.Skia to 2.0.0.4 2024-11-24 18:17:11 +00:00
renovate[bot]
1399e6be38 Update dependency MimeTypes to 2.5.2 2024-11-24 14:27:29 +00:00
Niels van Velzen
1c77e9606e Fix typo in LibraryOptions 2024-11-24 14:53:08 +01:00
Bond-009
4254c5acf6 Merge pull request #13089 from jellyfin/renovate/asynckeyedlock-7.x
Update dependency AsyncKeyedLock to 7.1.4
2024-11-24 13:33:18 +01:00
Bond-009
e688e3f1da Merge pull request #13072 from jellyfin/renovate/microsoft
Update dependency Microsoft.NET.Test.Sdk to 17.12.0
2024-11-24 13:33:05 +01:00
Bond-009
cd6f52a29f Merge pull request #13056 from jellyfin/renovate/ci-deps
Update CI dependencies
2024-11-24 13:32:55 +01:00
JPVenson
3b18a36ba5 removed unused 2024-11-24 10:59:05 +00:00
JPVenson
6a08361f6f Applied review comments 2024-11-24 10:58:09 +00:00
JPVenson
80cace4321 Updated usage of internal user Id 2024-11-23 22:39:39 +00:00
renovate[bot]
edb30ee543 Update dependency AsyncKeyedLock to 7.1.4 2024-11-22 11:21:27 +00:00
renovate[bot]
f932c4efa7 Update CI dependencies 2024-11-20 14:40:19 +00:00
Max
1ba0b88703 Use .net constants 2024-11-19 21:28:15 -05:00
JPVenson
0dd6dacc4f Merge remote-tracking branch 'origin/master' into feature/EFUserData 2024-11-19 20:53:38 +00:00
Shadowghost
06c603428b Backport pull request #13059 from jellyfin/release-10.10.z
Exclude file system based library playlists from migration

Original-merge: 23de7e517e

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

Backported-by: Joshua M. Boniface <joshua@boniface.me>
2024-11-19 15:43:33 -05:00
goknsh
924c80a209 Backport pull request #13033 from jellyfin/release-10.10.z
Respect cancellation token/HTTP request aborts correctly in `SymlinkFollowingPhysicalFileResultExecutor`

Original-merge: 293e0f5faf

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

Backported-by: Joshua M. Boniface <joshua@boniface.me>
2024-11-19 15:43:32 -05:00
gnattu
7f81bbd42f Backport pull request #13030 from jellyfin/release-10.10.z
Always cleanup trickplay temp for ffmpeg failures

Original-merge: 9e61a6fd72

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

Backported-by: Joshua M. Boniface <joshua@boniface.me>
2024-11-19 15:43:31 -05:00
nyanmisaka
9f86f8748c Backport pull request #13026 from jellyfin/release-10.10.z
Fix missing procamp vaapi filter

Original-merge: cf11a2dc1e

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

Backported-by: Joshua M. Boniface <joshua@boniface.me>
2024-11-19 15:43:29 -05:00
gnattu
7f296d06e6 Backport pull request #13003 from jellyfin/release-10.10.z
Only set first MusicBrainz ID for audio tags

Original-merge: e2434d38c5

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

Backported-by: Joshua M. Boniface <joshua@boniface.me>
2024-11-19 15:43:28 -05:00
gnattu
fbdbf77a59 Backport pull request #12991 from jellyfin/release-10.10.z
Use invariant culture for tonemap options

Original-merge: d292fde9e2

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

Backported-by: Joshua M. Boniface <joshua@boniface.me>
2024-11-19 15:43:27 -05:00
nyanmisaka
661caa62e2 Backport pull request #12989 from jellyfin/release-10.10.z
Fix InvariantCulture in VPP tonemap options

Original-merge: 25321d7f80

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

Backported-by: Joshua M. Boniface <joshua@boniface.me>
2024-11-19 15:43:26 -05:00
nyanmisaka
87a3c5d11c Backport pull request #12973 from jellyfin/release-10.10.z
Fix pixel format in HEVC RExt SDR transcoding

Original-merge: aa08d3f2bf

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

Backported-by: Joshua M. Boniface <joshua@boniface.me>
2024-11-19 15:43:24 -05:00
nyanmisaka
547d393af0 Backport pull request #12964 from jellyfin/release-10.10.z
Fix height of imported trickplay tiles

Original-merge: 09c377fb6c

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

Backported-by: Joshua M. Boniface <joshua@boniface.me>
2024-11-19 15:43:23 -05:00
Max
96cf13060d Extension lookup tv icons 2024-11-19 15:43:22 -05:00
gnattu
ee66c74527 Backport pull request #12962 from jellyfin/release-10.10.z
Always consider null char as delimiter for ID3v2

Original-merge: 97dc02b163

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

Backported-by: Joshua M. Boniface <joshua@boniface.me>
2024-11-19 15:43:22 -05:00
gnattu
882f3374ed Backport pull request #12955 from jellyfin/release-10.10.z
Fix trickplay images never being replaced

Original-merge: 9c6454ec46

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

Backported-by: Joshua M. Boniface <joshua@boniface.me>
2024-11-19 15:43:21 -05:00
gnattu
19c5c95f4e Backport pull request #12949 from jellyfin/release-10.10.z
Fix json array string writer in JsonDelimitedArrayConverter

Original-merge: 3089e9e40a

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

Backported-by: Joshua M. Boniface <joshua@boniface.me>
2024-11-19 15:43:20 -05:00
gnattu
4f562d67b0 Backport pull request #12947 from jellyfin/release-10.10.z
Add a small tolerance value to remux fps check

Original-merge: 954950dc14

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

Backported-by: Joshua M. Boniface <joshua@boniface.me>
2024-11-19 15:43:19 -05:00
Shadowghost
6e7118eff1 Backport pull request #12934 from jellyfin/release-10.10.z
Fix playlists

Original-merge: 8bee67f1f8

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

Backported-by: Joshua M. Boniface <joshua@boniface.me>
2024-11-19 15:43:18 -05:00
JPVenson
27b044493a Backport pull request #12916 from jellyfin/release-10.10.z
Added query filter to disregard disabled Providers

Original-merge: 38c08c4fad

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

Backported-by: Joshua M. Boniface <joshua@boniface.me>
2024-11-19 15:43:17 -05:00
renovate[bot]
2a8ebccd16 Update dependency Microsoft.NET.Test.Sdk to 17.12.0 2024-11-19 17:10:28 +00:00
koreapyj
d1d5ea9c80 Translated using Weblate (Korean)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/ko/
2024-11-18 03:00:02 -05:00
JPVenson
136a7995f7 Fixed server side distinct filter 2024-11-17 15:42:35 +00:00
dkanada
4c65e0d397 make playlist creation private by default (#12853) 2024-11-17 08:13:01 -07:00
JPVenson
e8761044c2 Fixed segment providers never presented to UI (#13060) 2024-11-17 08:12:43 -07:00
JPVenson
25f8e2259a Fixed ChapterRepository not set 2024-11-17 14:14:14 +00:00
JPVenson
fa5faa09c0 Merge remote-tracking branch 'origin/master' into feature/EFUserData 2024-11-17 11:54:19 +00:00
Bond-009
cf79b072a7 Merge pull request #13022 from jellyfin/renovate/major-microsoft
Update Microsoft to v9 (major)
2024-11-17 12:43:38 +01:00
JPVenson
68252ffa1b Merge branch 'feature/EFUserData' of https://github.com/JPVenson/jellyfin into feature/EFUserData 2024-11-17 11:05:14 +00:00
JPVenson
c71dc380bf Fixed error 2024-11-17 11:05:13 +00:00
JPVenson
b39553611d Applied coding style 2024-11-17 11:03:43 +00:00
JPVenson
427359deee Merge branch 'master' into feature/EFUserData 2024-11-17 01:23:26 +01:00
JPVenson
17e4485b94 Removed grouping key for testing 2024-11-16 23:33:04 +00:00
JPVenson
b6177363e9 Fixed search case sensitivity 2024-11-16 22:10:07 +00:00
JPVenson
9f7f9cc0ff Fixed metadata refresh not working 2024-11-16 20:30:43 +00:00
Cody Robibero
9e05abcc85 Add dotnet9 to abi compat workflow (#13046) 2024-11-16 19:01:32 +01:00
Bond-009
ceb850c770 Update projects to .NET 9 (#13023) 2024-11-16 10:11:01 -07:00
JPVenson
c925f8688e Filter duplicate BaseItems on save 2024-11-15 18:30:26 +00:00
renovate[bot]
2831882054 Update Microsoft to v9 2024-11-15 17:52:48 +00:00
Bond-009
5e8c0fe40c Merge pull request #13021 from jellyfin/renovate/microsoft
Update Microsoft to 8.0.11
2024-11-15 18:52:01 +01:00
Bond-009
3a8b27eb1e Merge pull request #12986 from jellyfin/renovate/skiasharp-monorepo
Update skiasharp monorepo
2024-11-15 18:37:24 +01:00
Bond-009
33c253268e Merge pull request #13019 from jellyfin/renovate/ci-deps
Update CI dependencies
2024-11-15 18:35:44 +01:00
Bond-009
6e022465e9 Merge pull request #12792 from jellyfin/renovate/dotnet-monorepo
Update dotnet monorepo
2024-11-15 18:34:52 +01:00
JPVenson
77bae62acc Added migration filtering 2024-11-15 16:24:38 +00:00
Jamoliddin Rakhmonberdiev
1be18114a9 Translated using Weblate (Uzbek)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/uz/
2024-11-15 11:00:02 -05:00
Johan Dixelius
ae721542cc Translated using Weblate (Swedish)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/sv/
2024-11-15 11:00:00 -05:00
JPVenson
3eedbae506 Fixed Item query 2024-11-15 14:33:07 +00:00
JPVenson
03e08412d7 Fixed paging not beeing applied 2024-11-15 14:17:25 +00:00
JPVenson
19e55f4309 Fixed migration referencing non-existing Items 2024-11-15 09:08:27 +00:00
JPVenson
92eb983c61 Fixed Query Distinct 2024-11-15 09:00:13 +00:00
JPVenson
0ff1ee951d Fixed compiler error 2024-11-14 22:01:51 +00:00
JPVenson
37129f7952 Fixed Transaction for Userdata 2024-11-14 21:48:21 +00:00
JPVenson
d4aca84581 Disabled sqlite pooling 2024-11-14 21:47:42 +00:00
JPVenson
e8be7ab011 Merge branch 'jellyfin:master' into feature/EFUserData 2024-11-14 21:56:18 +01:00
JPVenson
30ba35aa0c attempted to fix multi insert for Itemvalues 2024-11-14 20:36:27 +00:00
JPVenson
b60cd378d9 Updated order of saving for Items 2024-11-14 20:03:23 +00:00
JPVenson
060aa4719e Fixed NextUp and Latest query performance 2024-11-14 19:53:59 +00:00
JPVenson
96d9bb83a3 Fixed Movie RecentlyAdded 2024-11-14 18:09:04 +00:00
JPVenson
b830c42fca There can be also NULL people? 2024-11-14 16:10:43 +00:00
renovate[bot]
023838f3c8 Update CI dependencies 2024-11-14 15:58:14 +00:00
JPVenson
75d40e69b5 removed dbg code 2024-11-14 15:37:22 +00:00
JPVenson
f81d124019 Fixed items can be null saving 2024-11-14 15:23:59 +00:00
JPVenson
5167333602 Fixed base items not saved before Metadata 2024-11-14 14:07:36 +00:00
JPVenson
93adddd7a9 reverted dbg code 2024-11-14 10:25:49 +00:00
JPVenson
aea255f910 Deterministic tests my *** 2024-11-14 10:14:41 +00:00
JPVenson
432cfba2e2 Reverted Test code 2024-11-14 09:55:32 +00:00
JPVenson
c5488f8ead Fixed tests message 2024-11-14 09:25:55 +00:00
JPVenson
7d137a8e8a Updated test dbg message 2024-11-14 09:20:12 +00:00
JPVenson
056dcf7e81 Added Pipeline debug code 2024-11-14 09:04:35 +00:00
JPVenson
5f2be93e19 Fixed Tests 2024-11-14 08:48:53 +00:00
JPVenson
6bcc7aa79f Updated comments/TODOs 2024-11-14 06:06:09 +00:00
JPVenson
ffc18a2044 Updated comments/TODOs 2024-11-14 05:58:32 +00:00
JPVenson
a71187ebcc Fixed FUCKING TopParentId 2024-11-13 22:58:17 +00:00
JPVenson
7c51b37ca0 Fixed Person creation 2024-11-13 22:05:23 +00:00
JPVenson
6b371ba04f Fixed storage of Person images 2024-11-13 22:04:03 +00:00
JPVenson
e43e34eab8 Fixed Scan saving library items 2024-11-13 20:28:52 +00:00
JPVenson
2060d0ca2c Fixed DeadPeople query 2024-11-13 19:09:39 +00:00
renovate[bot]
16bc1ebc8b Update dotnet monorepo 2024-11-13 18:05:16 +00:00
George Vella
53683809d9 Translated using Weblate (Maltese)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/mt/
2024-11-13 12:00:03 -05:00
JPVenson
7b81a39ee1 Fix Deduplication and Save of Items 2024-11-13 14:25:26 +00:00
JPVenson
fcb1dfc010 Remove unmapped fields 2024-11-13 10:45:37 +00:00
JPVenson
5fb4d6a169 Merge branch 'feature/EFUserData' of https://github.com/JPVenson/jellyfin into feature/EFUserData 2024-11-13 10:43:11 +00:00
JPVenson
4747edd635 Merge branch 'feature/EFUserData' of https://github.com/JPVenson/jellyfin into feature/EFUserData 2024-11-13 10:34:09 +00:00
JPVenson
11388c0144 Removed unmapped joins again 2024-11-13 10:31:51 +00:00
JPVenson
cafc74c64c Removed unmapped joins again 2024-11-13 10:29:13 +00:00
JPVenson
c7f63a0da1 removed unmapped queried fields 2024-11-13 10:28:22 +00:00
JPVenson
07455dfb4d Readded External fields on request 2024-11-13 10:07:45 +00:00
JPVenson
3b8e177ba8 Removed duplicated code 2024-11-13 01:08:20 +00:00
JPVenson
8165813414 Fixed people saving 2024-11-13 00:49:39 +00:00
JPVenson
acd878e67e Fixed null reference being created by EfCore 2024-11-13 00:40:10 +00:00
JPVenson
b744ceabaa Added Check for arguments 2024-11-13 00:23:06 +00:00
JPVenson
d073e2c664 Fixed invalid columns on MediaStreams 2024-11-12 23:53:05 +00:00
JPVenson
46905ac66a Fixed NameStartsOrGreater filter 2024-11-12 20:50:23 +00:00
renovate[bot]
dc90b0edb9 Update Microsoft to 8.0.11 2024-11-12 20:06:37 +00:00
JPVenson
22515ad647 Fixed app paths not being expanded 2024-11-12 17:23:41 +00:00
JPVenson
d3174b5171 Fixed userdata lookup 2024-11-12 16:14:17 +00:00
JPVenson
85b8b2573b Fixed AncestorIds
Fixed Sorting, NextUp and Continue Watching
2024-11-12 15:37:01 +00:00
JPVenson
a7a2257ccb Fixed Search ordering and NextUp 2024-11-12 13:29:29 +00:00
JPVenson
510b29f2a4 Fixed dangling connections keept open on window migration 2024-11-12 07:16:24 +00:00
renovate[bot]
817ca1775a Update dependency AsyncKeyedLock to 7.1.3 (#13007)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-11 17:15:53 -07:00
JPVenson
00c4f23276 Fixed image save method transaction commit 2024-11-11 23:14:06 +00:00
JPVenson
43a2ec990c Refactored array usage 2024-11-11 23:11:17 +00:00
JPVenson
efe5b59517 Cleaned up BaseItem querying 2024-11-11 22:29:44 +00:00
JPVenson
508b27f156 Fixed Duplicate returns on grouping
Fixed UserDataKey not stored
2024-11-11 17:39:50 +00:00
JPVenson
bdab5e549e Fixed WAL lock on program exit 2024-11-11 17:39:20 +00:00
Bond-009
8f3410c81c Merge pull request #12994 from jellyfin/renovate/z440.atl.core-6.x
Update dependency z440.atl.core to 6.8.0
2024-11-11 12:53:30 +01:00
Bas
2d28b2ff6e Translated using Weblate (Dutch)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/nl/
2024-11-11 04:00:05 -05:00
Aindriú Mac Giolla Eoin
772e9a6d4a Translated using Weblate (Irish)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/ga/
2024-11-11 04:00:05 -05:00
darkabella
a5e05a7f14 Translated using Weblate (Catalan)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/ca/
2024-11-11 04:00:05 -05:00
koreapyj
ceefb71fe9 Translated using Weblate (Korean)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/ko/
2024-11-11 04:00:05 -05:00
JPVenson
741397f1be Fixed images not loading 2024-11-11 07:00:51 +00:00
JPVenson
c6e67edd86 Fixed ItemSorting 2024-11-11 06:21:43 +00:00
JPVenson
fb48d0790f Fixed Library DB lookup 2024-11-11 06:14:08 +00:00
JPVenson
8dbbb3e243 Fixed user Index 2024-11-11 05:34:11 +00:00
JPVenson
2d4f7f725f Fixed TopParent not beeing migrated 2024-11-11 00:27:30 +00:00
JPVenson
911139e2d5 Fixed provider Ids not queried with baseItems 2024-11-10 21:06:15 +00:00
JPVenson
6b777f9d43 Fixed filter query 2024-11-10 21:01:16 +00:00
JPVenson
67d8e8c7da fixed ExtraIds not returned as empty list 2024-11-10 20:42:27 +00:00
JPVenson
efc6611072 Refixed timing for migration 2024-11-10 20:40:24 +00:00
JPVenson
fb88d48374 Fixed out of order unittests 2024-11-10 20:18:36 +00:00
JPVenson
dfbbbf023d reverted tag enumeration 2024-11-10 20:10:59 +00:00
JPVenson
4b0a5ea8e9 Fixed reference aggregate collections nullable when empty 2024-11-10 19:31:22 +00:00
JPVenson
4959232b27 Fixed tags aggregation 2024-11-10 19:28:41 +00:00
JPVenson
73ddbeb4c1 Fixed migration timer 2024-11-10 19:25:17 +00:00
JPVenson
b5bb2261bc Who thought it be a good idea to let indexes start 1 one please step forward!!! 2024-11-10 19:19:35 +00:00
JPVenson
cec4ad9b65 Improved Logging 2024-11-10 18:36:46 +00:00
JPVenson
b0b14e6edd Fixed order of column selects 2024-11-10 18:01:51 +00:00
JPVenson
6efcd6b873 Fixed GUID selector for typed based item 2024-11-10 18:01:04 +00:00
Bond-009
fabf616a5a Merge pull request #12992 from jellyfin/renovate/ci-deps
Update github/codeql-action action to v3.27.1
2024-11-10 12:10:14 +01:00
renovate[bot]
9ee8642813 Update dependency z440.atl.core to 6.8.0 2024-11-08 22:29:58 +00:00
renovate[bot]
71daa3e5a1 Update github/codeql-action action to v3.27.1 2024-11-08 19:19:17 +00:00
renovate[bot]
dacb407bec Update skiasharp monorepo 2024-11-07 18:41:26 +00:00
VC
257d8d12b8 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/
2024-11-06 21:00:00 -05:00
newton181
bf00899f92 Translated using Weblate (Spanish (Latin America))
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/es_419/
2024-11-05 01:00:02 -05:00
Tomi
e34ea6400b Translated using Weblate (Finnish)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/fi/
2024-11-05 01:00:02 -05:00
guroww
5776163d6e Translated using Weblate (Bulgarian)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/bg/
2024-11-05 01:00:02 -05:00
renovate[bot]
1dd3792984 Update dependency z440.atl.core to 6.7.0 (#12943)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-03 10:51:06 -07:00
gnattu
46fb6c1579 Backport pull request #12940 from jellyfin/release-10.10.z
Remove DynamicImageResponse local image after saved to metadata folder

Original-merge: 3a9b48a2aa

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

Backported-by: Joshua M. Boniface <joshua@boniface.me>
2024-11-03 10:55:53 -05:00
gnattu
9e386ecc27 Backport pull request #12931 from jellyfin/release-10.10.z
Set AudioCodec when building stream

Original-merge: a165883999

Merged-by: nielsvanvelzen <nielsvanvelzen@users.noreply.github.com>

Backported-by: Joshua M. Boniface <joshua@boniface.me>
2024-11-03 10:55:51 -05:00
JPVenson
d81fec6b7c Backport pull request #12915 from jellyfin/release-10.10.z
Fixed possible NullReferenceException in SessionManager

Original-merge: 3592c629e7

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

Backported-by: Joshua M. Boniface <joshua@boniface.me>
2024-11-03 10:55:50 -05:00
revam
510312045a Backport pull request #12909 from jellyfin/release-10.10.z
Don't try to prune images for virtual episodes.

Original-merge: f99e0407fd

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

Backported-by: Joshua M. Boniface <joshua@boniface.me>
2024-11-03 10:55:49 -05:00
benedikt257
600a09f1fc Backport pull request #12891 from jellyfin/release-10.10.z
Fix TMDB import failing when no IMDB ID is set for a movie

Original-merge: c6629aebf8

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

Backported-by: Joshua M. Boniface <joshua@boniface.me>
2024-11-03 10:55:48 -05:00
Bond-009
725c414682 Merge pull request #12778 from TonyBotongChu/anime-parse
Add EpisodeExpression for anime file names
2024-11-03 15:44:20 +01:00
SethPattee
a416c438da Added + in username regex validator, Test + in username, issue #10414 (#12819) 2024-11-03 15:43:27 +01:00
Roi Gabay
30e20a0146 Translated using Weblate (Hebrew)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/he/
2024-11-03 04:00:00 -05:00
Bas
66aad36d1f Translated using Weblate (Dutch)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/nl/
2024-11-01 14:41:38 -04:00
Roi Gabay
258ae9d4c2 Translated using Weblate (Hebrew)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/he/
2024-11-01 14:41:38 -04:00
Bond_009
d2db700402 Always await instead of directly returning Task
https://github.com/davidfowl/AspNetCoreDiagnosticScenarios/blob/master/AsyncGuidance.md#prefer-asyncawait-over-directly-returning-task

The performance impact is negligible (and it's me saying that!)
2024-10-31 17:02:06 +01:00
Bond-009
282784cbb6 Merge pull request #12922 from jellyfin/renovate/svg.skia-2.x
Update dependency Svg.Skia to 2.0.0.2
2024-10-31 16:39:23 +01:00
renovate[bot]
9259623abb Update dependency Svg.Skia to 2.0.0.2 2024-10-31 13:15:18 +00:00
TalalSh
d4e8c641ea Translated using Weblate (Arabic)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/ar/
2024-10-29 22:12:32 -04:00
JPVenson
0639758abd Updated all instances of ImmutableList to ImmutableArray 2024-10-28 14:34:29 +00:00
JPVenson
f80fa96453 Removed unused Using 2024-10-28 11:54:58 +00:00
JPVenson
76df4c48bc Changed from ImmuntableList to ImmutableArray 2024-10-28 11:54:39 +00:00
JPVenson
9342a6a9d6 Reverted Primary Constructor 2024-10-28 11:54:08 +00:00
akshay
0bce3500fb Translated using Weblate (Hindi)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/hi/
2024-10-28 07:41:38 -04:00
Spiros Vita
12db844d14 Translated using Weblate (Greek)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/el/
2024-10-28 07:41:38 -04:00
Frederik Palmø
6392970066 Translated using Weblate (Danish)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/da/
2024-10-28 07:41:38 -04:00
JPVenson
a3ae055779 Change ChannelId and OwnerId to be expected strings 2024-10-28 09:24:12 +00:00
JPVenson
07ed9a3ea4 Updated TryGetGuid for migration 2024-10-28 09:22:32 +00:00
JPVenson
3d87d0faa2 Fixed migration not loading guid for items 2024-10-28 09:02:24 +00:00
Joshua M. Boniface
0437511931 Merge pull request #12893 from HadrienPatte/auto-update-issue-template-version
Auto update issue template version on new release
2024-10-27 19:28:00 -04:00
Hadrien Patte
9d676f8836 Auto update issue template version on new release 2024-10-27 18:58:20 +01:00
Bond-009
f0700b76d5 Merge pull request #12882 from HadrienPatte/update-issue-template-version
Update issue template version from 10.9.11 to 10.10.0
2024-10-27 10:57:59 +01:00
Hadrien Patte
6b135ea209 Update issue template version from 10.9.11 to 10.10.0 2024-10-26 21:19:46 +02:00
Jellyfin Release Bot
a0c634a6ed Bump version to 10.11.0 2024-10-26 13:32:51 -04:00
JPVenson
41c27d4e7e ATV requested endpoint mock 2024-10-26 16:59:12 +00:00
JPVenson
dc029d549c removed double dispose 2024-10-26 11:08:20 +00:00
JPVenson
ebabaac6b1 removed dbg timeout 2024-10-26 10:47:38 +00:00
JPVenson
cd81a698a6 Reverted change to network manager 2024-10-26 10:34:11 +00:00
JPVenson
1e7acec017 Added Setup overlay app to communicate status of startup 2024-10-26 10:31:01 +00:00
David Carroll
d6d6ebe3fb Update UUID for Rating Level migration 2024-10-23 09:21:53 -05:00
David Carroll
6f268736f0 Move TV-PG ratings to be in line with PG rating. 2024-10-22 23:20:59 -05:00
JPVenson
421b49dee9 Adapted Review sugestions 2024-10-22 11:47:05 +00:00
JPVenson
a9f387f19b Reverted ImmutableList change 2024-10-22 10:56:02 +00:00
JPVenson
bf7e6858d5 Reverted ToImmutableList change 2024-10-22 10:54:22 +00:00
JPVenson
c2a0dfb1e5 Reodered Context creation 2024-10-22 10:53:39 +00:00
JPVenson
447ff1d23c Made Clean task async 2024-10-22 10:52:34 +00:00
JPVenson
e331dc35ac Fixed tests 2024-10-20 11:04:54 +00:00
JPVenson
d4ca8d58c4 Fixed Migrations 2024-10-20 10:31:43 +00:00
JPVenson
10a2a316a4 i have too much time.
Refactored BaseItem and UserData relation
2024-10-20 10:11:24 +00:00
JPVenson
cd2e043472 Readded old library move in migration 2024-10-20 09:43:40 +00:00
TonyB
5957790ce8 Use [0-9] instead of \d 2024-10-12 17:09:18 +08:00
TonyB
79ee36ee15 Add EpisodeExpression for anime file names 2024-10-12 17:09:18 +08:00
JPVenson
e20ecfc670 applied review comments 2024-10-11 14:16:42 +00:00
JPVenson
058a567e00 Removed unused mapping tables 2024-10-11 11:46:43 +00:00
JPVenson
05ffa7b413 Applied Review Comments 2024-10-11 11:42:49 +00:00
JPVenson
b73985e04f Expanded People architecture and fixed migration 2024-10-11 11:11:15 +00:00
JPVenson
f397fc5b98 Fixed CustomType serialisation 2024-10-10 20:03:15 +00:00
JPVenson
ae641b7f3a Applied review comments 2024-10-10 19:27:26 +00:00
JPVenson
9c5599f81b Applied review comments 2024-10-10 18:30:08 +00:00
JPVenson
439a997fca Readded custom serialisation 2024-10-10 18:01:14 +00:00
JPVenson
ea4c208fde fixed string concat 2024-10-10 17:35:51 +00:00
JPVenson
5e922f1c10 Aggregated Migrations 2024-10-10 16:09:29 +00:00
JPVenson
441b995189 Applied Review Suggestions 2024-10-10 15:27:13 +00:00
JPVenson
f58a24f005 Fixed tests 2024-10-10 15:23:34 +00:00
JPVenson
ee0dad6f43 Refactored ItemValue structure 2024-10-10 14:32:49 +00:00
JPVenson
3e7ce5e1df Removed obsolete Score and Similiarity values for search 2024-10-10 00:57:19 +00:00
JPVenson
7f03f39bcc Fixed tests 2024-10-10 00:49:06 +00:00
JPVenson
7a5c7e70f6 Update comments 2024-10-10 00:02:16 +00:00
JPVenson
868bb9ea25 Update comments 2024-10-10 00:01:02 +00:00
JPVenson
2c2e33dd82 Updated .AsNoTracking() where applicable 2024-10-09 23:58:55 +00:00
JPVenson
fe9c96d052 Used enum value for ItemValueType 2024-10-09 23:55:28 +00:00
JPVenson
4c86642c00 Added comments 2024-10-09 23:22:21 +00:00
JPVenson
2955f2f562 Fixed AncestorIds and applied review comments 2024-10-09 23:19:24 +00:00
JPVenson
eb601e944c Expanded BaseItem aggregate types 2024-10-09 23:01:54 +00:00
JPVenson
f1ae764041 Merge branch 'jellyfin:master' into feature/EFUserData 2024-10-09 21:05:27 +02:00
JPVenson
473628ba3a Apply suggestions from code review
Co-authored-by: Cody Robibero <cody@robibe.ro>
2024-10-09 21:03:57 +02:00
JPVenson
5267851e64 Add migration for library.db to jellyfin.db 2024-10-09 17:04:58 +00:00
JPVenson
01d834f21a Fixed (most) tests 2024-10-09 15:20:42 +00:00
JPVenson
c2844bda3b Added EF BaseItem migration 2024-10-09 11:22:52 +00:00
JPVenson
3dc4024338 Added BaseItem Configuration 2024-10-09 11:02:47 +00:00
JPVenson
2014fa56b8 Ported new Item Repository architecture 2024-10-09 10:41:54 +00:00
JPVenson
b09a41ad1f WIP porting new Repository structure 2024-10-09 10:36:08 +00:00
JPVenson
be48cdd9e9 Naming refactoring and WIP porting of new interface repositories 2024-10-09 09:53:39 +00:00
JPVenson
15bf43e3ad Removed BaseSqliteRepository 2024-10-08 19:53:26 +00:00
JPVenson
6acd146d17 WIP migration sqlite item repository to efcore 2024-10-08 19:11:31 +00:00
JPVenson
ea81db67f4 Added Sorting and Grouping 2024-10-08 16:27:47 +00:00
JPVenson
90103165e2 Removed SimilarityScore and ported Search function 2024-10-08 15:16:03 +00:00
JPVenson
527998cd0c WIP port search function 2024-10-08 13:46:21 +00:00
JPVenson
d5409a26ea WIP Search refactoring and Provider ID refactoring 2024-10-08 13:18:48 +00:00
JPVenson
6c819fe516 WIP BaseItem search refactoring 2024-10-08 12:27:27 +00:00
JPVenson
d3a3d9fce3 Merge remote-tracking branch 'jellyfinorigin/master' into feature/EFUserData 2024-10-08 09:34:34 +00:00
Marc Brooks
6dc61a430b Sort embedded collections in Nfo files
Because the Nfo files emit the collections as they are in-memory, the
files are not stable in format, genres, tags, albums, people, etc. are emitted in random orders. Add ordering of the collections when emitting the Nfo files so the file remains stable (unchanged) when underlying media information doesn't change.

In the process of this, it became clear that most of the providers and probes don't trim the strings like people's names, genre names, etc. so did a pass of Trim cleanup too.

Specific ordering: (alphabetical/numeric ascending after trimming blanks and defaulting to zero for missing numbers)

BaseItem: Directors, Writers, Trailers (by Url), Production Locations, Genres, Studios, Tags, Custom Provider Data (by key), Linked Children  (by Path>LibraryItemId), Backdrop Images (by path), Actors (by SortOrder>Name)

AlbumNfo: Artists, Album Artists, Tracks (by ParentIndexNumber>IndexNumber>Name)

ArtistNfo: Albums (by Production Year>SortName>Name)

MovieNfo: Artists

Fix Debug build lint


Fix CI debug build lint issue.


Fix review issues

Fixed debug-build lint issues.
Emits the `disc` number to NFO for tracks with a non-zero ParentIndexNumber and only emit `position` if non-zero.
Removed the exception filtering I put in for testing.

Don't emit actors for MusicAlbums or MusicArtists


Swap from String.Trimmed() to ?.Trim()
Addressing PR feedback

Can't use ReadOnlySpan in an async method

Removed now-unused namespace
2024-09-18 20:33:18 -05:00
JPVenson
ee1bdf4e22 WIP move baseitem to jellyfin.db 2024-09-08 16:56:14 +00:00
JPVenson
d0b4b2ddb3 Migrated UserData from library sqlite db to jellyfin.db 2024-09-07 19:07:34 +00:00
1205 changed files with 77172 additions and 22219 deletions

View File

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

View File

@@ -1,28 +0,0 @@
{
"name": "Development Jellyfin Server - FFmpeg",
"image":"mcr.microsoft.com/devcontainers/dotnet:8.0-jammy",
// restores nuget packages, installs the dotnet workloads and installs the dev https certificate
"postStartCommand": "dotnet restore; dotnet workload update; dotnet dev-certs https --trust; sudo bash \"./.devcontainer/Dev - Server Ffmpeg/install-ffmpeg.sh\"",
// reads the extensions list and installs them
"postAttachCommand": "cat .vscode/extensions.json | jq -r .recommendations[] | xargs -n 1 code --install-extension",
"features": {
"ghcr.io/devcontainers/features/dotnet:2": {
"version": "none",
"dotnetRuntimeVersions": "8.0",
"aspNetCoreRuntimeVersions": "8.0"
},
"ghcr.io/devcontainers-contrib/features/apt-packages:1": {
"preserve_apt_list": false,
"packages": ["libfontconfig1"]
},
"ghcr.io/devcontainers/features/docker-in-docker:2": {
"dockerDashComposeVersion": "v2"
},
"ghcr.io/devcontainers/features/github-cli:1": {},
"ghcr.io/eitsupi/devcontainer-features/jq-likes:2": {}
},
"hostRequirements": {
"memory": "8gb",
"cpus": 4
}
}

View File

@@ -1,19 +1,23 @@
{
"name": "Development Jellyfin Server",
"image":"mcr.microsoft.com/devcontainers/dotnet:8.0-jammy",
"image": "mcr.microsoft.com/devcontainers/dotnet:9.0-bookworm",
"service": "app",
"workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}",
// restores nuget packages, installs the dotnet workloads and installs the dev https certificate
"postStartCommand": "dotnet restore; dotnet workload update; dotnet dev-certs https --trust",
"postStartCommand": "sudo dotnet restore; sudo dotnet workload update; sudo dotnet dev-certs https --trust; sudo bash \"./.devcontainer/install-ffmpeg.sh\"",
// reads the extensions list and installs them
"postAttachCommand": "cat .vscode/extensions.json | jq -r .recommendations[] | xargs -n 1 code --install-extension",
"features": {
"ghcr.io/devcontainers/features/dotnet:2": {
"version": "none",
"dotnetRuntimeVersions": "8.0",
"aspNetCoreRuntimeVersions": "8.0"
"dotnetRuntimeVersions": "9.0",
"aspNetCoreRuntimeVersions": "9.0"
},
"ghcr.io/devcontainers-contrib/features/apt-packages:1": {
"ghcr.io/devcontainers-extra/features/apt-packages:1": {
"preserve_apt_list": false,
"packages": ["libfontconfig1"]
"packages": [
"libfontconfig1"
]
},
"ghcr.io/devcontainers/features/docker-in-docker:2": {
"dockerDashComposeVersion": "v2"

View File

@@ -1,6 +1,6 @@
#!/bin/bash
## configure the following for a manuall install of a specific version from the repo
## configure the following for a manual install of a specific version from the repo
# wget https://repo.jellyfin.org/releases/server/ubuntu/versions/jellyfin-ffmpeg/6.0.1-1/jellyfin-ffmpeg6_6.0.1-1-jammy_amd64.deb -O ffmpeg.deb
@@ -29,4 +29,4 @@ Signed-By: /etc/apt/keyrings/jellyfin.gpg
EOF
sudo apt update -y
sudo apt install jellyfin-ffmpeg6 -y
sudo apt install jellyfin-ffmpeg7 -y

View File

@@ -192,3 +192,344 @@ csharp_space_between_method_call_empty_parameter_list_parentheses = false
# Wrapping preferences
csharp_preserve_single_line_statements = true
csharp_preserve_single_line_blocks = true
###############################
# C# Analyzer Rules #
###############################
### ERROR #
###########
# error on SA1000: The keyword 'new' should be followed by a space
dotnet_diagnostic.SA1000.severity = error
# error on SA1001: Commas should not be preceded by whitespace
dotnet_diagnostic.SA1001.severity = error
# error on SA1106: Code should not contain empty statements
dotnet_diagnostic.SA1106.severity = error
# error on SA1107: Code should not contain multiple statements on one line
dotnet_diagnostic.SA1107.severity = error
# error on SA1028: Code should not contain trailing whitespace
dotnet_diagnostic.SA1028.severity = error
# error on SA1117: The parameters should all be placed on the same line or each parameter should be placed on its own line
dotnet_diagnostic.SA1117.severity = error
# error on SA1137: Elements should have the same indentation
dotnet_diagnostic.SA1137.severity = error
# error on SA1142: Refer to tuple fields by name
dotnet_diagnostic.SA1142.severity = error
# error on SA1210: Using directives should be ordered alphabetically by the namespaces
dotnet_diagnostic.SA1210.severity = error
# error on SA1316: Tuple element names should use correct casing
dotnet_diagnostic.SA1316.severity = error
# error on SA1414: Tuple types in signatures should have element names
dotnet_diagnostic.SA1414.severity = error
# disable warning SA1513: Closing brace should be followed by blank line
dotnet_diagnostic.SA1513.severity = error
# error on SA1518: File is required to end with a single newline character
dotnet_diagnostic.SA1518.severity = error
# error on SA1629: Documentation text should end with a period
dotnet_diagnostic.SA1629.severity = error
# error on CA1001: Types that own disposable fields should be disposable
dotnet_diagnostic.CA1001.severity = error
# error on CA1012: Abstract types should not have public constructors
dotnet_diagnostic.CA1012.severity = error
# error on CA1063: Implement IDisposable correctly
dotnet_diagnostic.CA1063.severity = error
# error on CA1305: Specify IFormatProvider
dotnet_diagnostic.CA1305.severity = error
# error on CA1307: Specify StringComparison for clarity
dotnet_diagnostic.CA1307.severity = error
# error on CA1309: Use ordinal StringComparison
dotnet_diagnostic.CA1309.severity = error
# error on CA1310: Specify StringComparison for correctness
dotnet_diagnostic.CA1310.severity = error
# error on CA1513: Use 'ObjectDisposedException.ThrowIf' instead of explicitly throwing a new exception instance
dotnet_diagnostic.CA1513.severity = error
# error on CA1725: Parameter names should match base declaration
dotnet_diagnostic.CA1725.severity = error
# error on CA1725: Call async methods when in an async method
dotnet_diagnostic.CA1727.severity = error
# error on CA1813: Avoid unsealed attributes
dotnet_diagnostic.CA1813.severity = error
# error on CA1834: Use 'StringBuilder.Append(char)' instead of 'StringBuilder.Append(string)' when the input is a constant unit string
dotnet_diagnostic.CA1834.severity = error
# error on CA1843: Do not use 'WaitAll' with a single task
dotnet_diagnostic.CA1843.severity = error
# error on CA1845: Use span-based 'string.Concat'
dotnet_diagnostic.CA1845.severity = error
# error on CA1849: Call async methods when in an async method
dotnet_diagnostic.CA1849.severity = error
# error on CA1851: Possible multiple enumerations of IEnumerable collection
dotnet_diagnostic.CA1851.severity = error
# error on CA1854: Prefer a 'TryGetValue' call over a Dictionary indexer access guarded by a 'ContainsKey' check to avoid double lookup
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
# error on CA1863: Use 'CompositeFormat'
dotnet_diagnostic.CA1863.severity = error
# error on CA1864: Prefer the 'IDictionary.TryAdd(TKey, TValue)' method
dotnet_diagnostic.CA1864.severity = error
# error on CA1865-CA1867: Use 'string.Method(char)' instead of 'string.Method(string)' for string with single char
dotnet_diagnostic.CA1865.severity = error
dotnet_diagnostic.CA1866.severity = error
dotnet_diagnostic.CA1867.severity = error
# error on CA1868: Unnecessary call to 'Contains' for sets
dotnet_diagnostic.CA1868.severity = error
# error on CA1869: Cache and reuse 'JsonSerializerOptions' instances
dotnet_diagnostic.CA1869.severity = error
# error on CA1870: Use a cached 'SearchValues' instance
dotnet_diagnostic.CA1870.severity = error
# error on CA1871: Do not pass a nullable struct to 'ArgumentNullException.ThrowIfNull'
dotnet_diagnostic.CA1871.severity = error
# error on CA1872: Prefer 'Convert.ToHexString' and 'Convert.ToHexStringLower' over call chains based on 'BitConverter.ToString'
dotnet_diagnostic.CA1872.severity = error
# error on CA2016: Forward the CancellationToken parameter to methods that take one
# or pass in 'CancellationToken.None' explicitly to indicate intentionally not propagating the token
dotnet_diagnostic.CA2016.severity = error
# error on CA2201: Exception type System.Exception is not sufficiently specific
dotnet_diagnostic.CA2201.severity = error
# error on CA2215: Dispose methods should call base class dispose
dotnet_diagnostic.CA2215.severity = error
# error on CA2249: Use 'string.Contains' instead of 'string.IndexOf' to improve readability
dotnet_diagnostic.CA2249.severity = error
# error on CA2254: Template should be a static expression
dotnet_diagnostic.CA2254.severity = error
################
### SUGGESTION #
################
# disable warning CA1014: Mark assemblies with CLSCompliantAttribute
dotnet_diagnostic.CA1014.severity = suggestion
# disable warning CA1024: Use properties where appropriate
dotnet_diagnostic.CA1024.severity = suggestion
# disable warning CA1031: Do not catch general exception types
dotnet_diagnostic.CA1031.severity = suggestion
# disable warning CA1032: Implement standard exception constructors
dotnet_diagnostic.CA1032.severity = suggestion
# disable warning CA1040: Avoid empty interfaces
dotnet_diagnostic.CA1040.severity = suggestion
# disable warning CA1062: Validate arguments of public methods
dotnet_diagnostic.CA1062.severity = suggestion
# TODO: enable when false positives are fixed
# disable warning CA1508: Avoid dead conditional code
dotnet_diagnostic.CA1508.severity = suggestion
# disable warning CA1515: Consider making public types internal
dotnet_diagnostic.CA1515.severity = suggestion
# disable warning CA1716: Identifiers should not match keywords
dotnet_diagnostic.CA1716.severity = suggestion
# disable warning CA1720: Identifiers should not contain type names
dotnet_diagnostic.CA1720.severity = suggestion
# disable warning CA1724: Type names should not match namespaces
dotnet_diagnostic.CA1724.severity = suggestion
# disable warning CA1805: Do not initialize unnecessarily
dotnet_diagnostic.CA1805.severity = suggestion
# disable warning CA1812: internal class that is apparently never instantiated.
# If so, remove the code from the assembly.
# If this class is intended to contain only static members, make it static
dotnet_diagnostic.CA1812.severity = suggestion
# disable warning CA1822: Member does not access instance data and can be marked as static
dotnet_diagnostic.CA1822.severity = suggestion
# CA1859: Use concrete types when possible for improved performance
dotnet_diagnostic.CA1859.severity = suggestion
# TODO: Enable
# CA1861: Prefer 'static readonly' fields over constant array arguments if the called method is called repeatedly and is not mutating the passed array
dotnet_diagnostic.CA1861.severity = suggestion
# disable warning CA2000: Dispose objects before losing scope
dotnet_diagnostic.CA2000.severity = suggestion
# disable warning CA2253: Named placeholders should not be numeric values
dotnet_diagnostic.CA2253.severity = suggestion
# disable warning CA5394: Do not use insecure randomness
dotnet_diagnostic.CA5394.severity = suggestion
# error on CA3003: Review code for file path injection vulnerabilities
dotnet_diagnostic.CA3003.severity = suggestion
# error on CA3006: Review code for process command injection vulnerabilities
dotnet_diagnostic.CA3006.severity = suggestion
###############
### DISABLED #
###############
# disable warning SA1009: Closing parenthesis should be followed by a space.
dotnet_diagnostic.SA1009.severity = none
# disable warning SA1011: Closing square bracket should be followed by a space.
dotnet_diagnostic.SA1011.severity = none
# disable warning SA1101: Prefix local calls with 'this.'
dotnet_diagnostic.SA1101.severity = none
# disable warning SA1108: Block statements should not contain embedded comments
dotnet_diagnostic.SA1108.severity = none
# disable warning SA1118: Parameter must not span multiple lines.
dotnet_diagnostic.SA1118.severity = none
# disable warning SA1128:: Put constructor initializers on their own line
dotnet_diagnostic.SA1128.severity = none
# disable warning SA1130: Use lambda syntax
dotnet_diagnostic.SA1130.severity = none
# disable warning SA1200: 'using' directive must appear within a namespace declaration
dotnet_diagnostic.SA1200.severity = none
# disable warning SA1202: 'public' members must come before 'private' members
dotnet_diagnostic.SA1202.severity = none
# disable warning SA1204: Static members must appear before non-static members
dotnet_diagnostic.SA1204.severity = none
# disable warning SA1309: Fields must not begin with an underscore
dotnet_diagnostic.SA1309.severity = none
# disable warning SA1311: Static readonly fields should begin with upper-case letter
dotnet_diagnostic.SA1311.severity = none
# disable warning SA1413: Use trailing comma in multi-line initializers
dotnet_diagnostic.SA1413.severity = none
# disable warning SA1512: Single-line comments must not be followed by blank line
dotnet_diagnostic.SA1512.severity = none
# disable warning SA1515: Single-line comment should be preceded by blank line
dotnet_diagnostic.SA1515.severity = none
# disable warning SA1600: Elements should be documented
dotnet_diagnostic.SA1600.severity = none
# disable warning SA1601: Partial elements should be documented
dotnet_diagnostic.SA1601.severity = none
# disable warning SA1602: Enumeration items should be documented
dotnet_diagnostic.SA1602.severity = none
# disable warning SA1633: The file header is missing or not located at the top of the file
dotnet_diagnostic.SA1633.severity = none
# disable warning CA1054: Change the type of parameter url from string to System.Uri
dotnet_diagnostic.CA1054.severity = none
# disable warning CA1055: URI return values should not be strings
dotnet_diagnostic.CA1055.severity = none
# disable warning CA1056: URI properties should not be strings
dotnet_diagnostic.CA1056.severity = none
# disable warning CA1303: Do not pass literals as localized parameters
dotnet_diagnostic.CA1303.severity = none
# disable warning CA1308: Normalize strings to uppercase
dotnet_diagnostic.CA1308.severity = none
# disable warning CA1848: Use the LoggerMessage delegates
dotnet_diagnostic.CA1848.severity = none
# disable warning CA2101: Specify marshaling for P/Invoke string arguments
dotnet_diagnostic.CA2101.severity = none
# disable warning CA2234: Pass System.Uri objects instead of strings
dotnet_diagnostic.CA2234.severity = none
# error on RS0030: Do not used banned APIs
dotnet_diagnostic.RS0030.severity = error
# disable warning IDISP001: Dispose created
dotnet_diagnostic.IDISP001.severity = suggestion
# TODO: Enable when false positives are fixed
# disable warning IDISP003: Dispose previous before re-assigning
dotnet_diagnostic.IDISP003.severity = suggestion
# disable warning IDISP004: Don't ignore created IDisposable
dotnet_diagnostic.IDISP004.severity = suggestion
# disable warning IDISP007: Don't dispose injected
dotnet_diagnostic.IDISP007.severity = suggestion
# disable warning IDISP008: Don't assign member with injected and created disposables
dotnet_diagnostic.IDISP008.severity = suggestion
[tests/**.{cs,vb}]
# disable warning SA0001: XML comment analysis is disabled due to project configuration
dotnet_diagnostic.SA0001.severity = none
# disable warning CA1707: Identifiers should not contain underscores
dotnet_diagnostic.CA1707.severity = none
# disable warning CA2007: Consider calling ConfigureAwait on the awaited task
dotnet_diagnostic.CA2007.severity = none
# disable warning CA2234: Pass system uri objects instead of strings
dotnet_diagnostic.CA2234.severity = suggestion
# disable warning xUnit1028: Test methods must have a supported return type.
dotnet_diagnostic.xUnit1028.severity = none
# CA1826: Do not use Enumerable methods on indexable collections
dotnet_diagnostic.CA1826.severity = suggestion

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

@@ -1,6 +1,7 @@
name: Issue Report
description: File an issue report
labels: [bug, triage]
type: Bug
body:
- type: markdown
id: introduction
@@ -14,7 +15,7 @@ body:
label: "This issue respects the following points:"
description: All conditions are **required**. Failure to comply with any of these conditions may cause your issue to be closed without comment.
options:
- label: This is a **bug**, not a question or a configuration issue; Please visit our forum or chat rooms first to troubleshoot with volunteers, before creating a report. The links can be found [here](https://jellyfin.org/contact/).
- label: This is a **bug**, not a question or a configuration issue; Please visit our [forum or chat rooms](https://jellyfin.org/contact/) first to troubleshoot with volunteers, before creating a report.
required: true
- label: This issue is **not** already reported on [GitHub](https://github.com/jellyfin/jellyfin/issues?q=is%3Aopen+is%3Aissue) _(I've searched it)_.
required: true
@@ -86,7 +87,11 @@ body:
label: Jellyfin Server version
description: What version of Jellyfin are you using?
options:
- 10.9.11+
- 10.11.4
- 10.11.3
- 10.11.2
- 10.11.1
- 10.11.0
- Master
- Unstable
- Older*
@@ -135,12 +140,15 @@ body:
- **FFmpeg Version**: [e.g. 5.1.2-Jellyfin]
- **Playback**: [Direct Play, Remux, Direct Stream, Transcode]
- **Hardware Acceleration**: [e.g. none, VAAPI, NVENC, etc.]
- **CPU Model**: [e.g. AMD Ryzen 5 9600X, Intel Core i7-8565U, etc.]
- **GPU Model**: [e.g. none, UHD630, GTX1050, etc.]
- **Installed Plugins**: [e.g. none, Fanart, Anime, etc.]
- **Reverse Proxy**: [e.g. none, nginx, apache, etc.]
- **Base URL**: [e.g. none, yes: /example]
- **Networking**: [e.g. Host, Bridge/NAT]
- **Storage**: [e.g. local, NFS, cloud]
- **Jellyfin Data Storage & Filesystem**: [e.g. local SATA SSD - ext4, local HDD - NTFS]
- **Media Storage & Filesystem**: [e.g. Local HDD - ext4, SMB Share]
- **External Integrations**: [e.g. Jellystat, Jellyseerr]
value: |
- OS:
- Linux Kernel:
@@ -150,12 +158,15 @@ body:
- FFmpeg Version:
- Playback Method:
- Hardware Acceleration:
- CPU Model:
- GPU Model:
- Plugins:
- Reverse Proxy:
- Base URL:
- Networking:
- Storage:
- Jellyfin Data Storage & Filesystem:
- Media Storage & Filesystem:
- External Integrations:
render: markdown
validations:
required: true

View File

@@ -20,18 +20,18 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- name: Setup .NET
uses: actions/setup-dotnet@3e891b0cb619bf60e2c25674b222b8940e2c1c25 # v4.1.0
uses: actions/setup-dotnet@2016bd2012dba4e32de620c46fe006a3ac9f0602 # v5.0.1
with:
dotnet-version: '8.0.x'
dotnet-version: '9.0.x'
- name: Initialize CodeQL
uses: github/codeql-action/init@662472033e021d55d94146f66f6058822b0b39fd # v3.27.0
uses: github/codeql-action/init@cf1bb45a277cb3c205638b2cd5c984db1c46a412 # v4.31.7
with:
languages: ${{ matrix.language }}
queries: +security-extended
- name: Autobuild
uses: github/codeql-action/autobuild@662472033e021d55d94146f66f6058822b0b39fd # v3.27.0
uses: github/codeql-action/autobuild@cf1bb45a277cb3c205638b2cd5c984db1c46a412 # v4.31.7
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@662472033e021d55d94146f66f6058822b0b39fd # v3.27.0
uses: github/codeql-action/analyze@cf1bb45a277cb3c205638b2cd5c984db1c46a412 # v4.31.7

View File

@@ -11,17 +11,22 @@ jobs:
permissions: read-all
steps:
- name: Checkout repository
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
ref: ${{ github.event.pull_request.head.sha }}
repository: ${{ github.event.pull_request.head.repo.full_name }}
- name: Setup .NET
uses: actions/setup-dotnet@2016bd2012dba4e32de620c46fe006a3ac9f0602 # v5.0.1
with:
dotnet-version: '9.0.x'
- name: Build
run: |
dotnet build Jellyfin.Server -o ./out
- name: Upload Head
uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
with:
name: abi-head
retention-days: 14
@@ -35,12 +40,17 @@ jobs:
permissions: read-all
steps:
- name: Checkout repository
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
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@2016bd2012dba4e32de620c46fe006a3ac9f0602 # v5.0.1
with:
dotnet-version: '9.0.x'
- name: Checkout common ancestor
env:
HEAD_REF: ${{ github.head_ref }}
@@ -55,7 +65,7 @@ jobs:
dotnet build Jellyfin.Server -o ./out
- name: Upload Head
uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
with:
name: abi-base
retention-days: 14
@@ -75,13 +85,13 @@ jobs:
steps:
- name: Download abi-head
uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8
uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0
with:
name: abi-head
path: abi-head
- name: Download abi-base
uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8
uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0
with:
name: abi-base
path: abi-base
@@ -95,7 +105,7 @@ jobs:
run: |
{
echo 'body<<EOF'
for file in Jellyfin.Data.dll MediaBrowser.Common.dll MediaBrowser.Controller.dll MediaBrowser.Model.dll Emby.Naming.dll Jellyfin.Extensions.dll; do
for file in Jellyfin.Data.dll MediaBrowser.Common.dll MediaBrowser.Controller.dll MediaBrowser.Model.dll Emby.Naming.dll Jellyfin.Extensions.dll Jellyfin.MediaEncoding.Keyframes.dll Jellyfin.Database.Implementations.dll; do
COMPAT_OUTPUT="$( { apicompat --left ./abi-base/${file} --right ./abi-head/${file}; } 2>&1 )"
if [ "APICompat ran successfully without finding any breaking changes." != "${COMPAT_OUTPUT}" ]; then
printf "\n${file}\n${COMPAT_OUTPUT}\n"
@@ -105,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 }}
@@ -113,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 }}
@@ -132,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,23 +16,23 @@ jobs:
permissions: read-all
steps:
- name: Checkout repository
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
ref: ${{ github.event.pull_request.head.sha }}
repository: ${{ github.event.pull_request.head.repo.full_name }}
- name: Setup .NET
uses: actions/setup-dotnet@3e891b0cb619bf60e2c25674b222b8940e2c1c25 # v4.1.0
uses: actions/setup-dotnet@2016bd2012dba4e32de620c46fe006a3ac9f0602 # v5.0.1
with:
dotnet-version: '8.0.x'
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@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
with:
name: openapi-head
retention-days: 14
if-no-files-found: error
path: tests/Jellyfin.Server.Integration.Tests/bin/Release/net8.0/openapi.json
path: tests/Jellyfin.Server.Integration.Tests/bin/Release/net9.0/openapi.json
openapi-base:
name: OpenAPI - BASE
@@ -41,7 +41,7 @@ jobs:
permissions: read-all
steps:
- name: Checkout repository
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
ref: ${{ github.event.pull_request.head.sha }}
repository: ${{ github.event.pull_request.head.repo.full_name }}
@@ -55,18 +55,18 @@ 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@3e891b0cb619bf60e2c25674b222b8940e2c1c25 # v4.1.0
uses: actions/setup-dotnet@2016bd2012dba4e32de620c46fe006a3ac9f0602 # v5.0.1
with:
dotnet-version: '8.0.x'
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@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
with:
name: openapi-base
retention-days: 14
if-no-files-found: error
path: tests/Jellyfin.Server.Integration.Tests/bin/Release/net8.0/openapi.json
path: tests/Jellyfin.Server.Integration.Tests/bin/Release/net9.0/openapi.json
openapi-diff:
permissions:
@@ -80,12 +80,12 @@ jobs:
- openapi-base
steps:
- name: Download openapi-head
uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8
uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0
with:
name: openapi-head
path: openapi-head
- name: Download openapi-base
uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8
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,12 +158,12 @@ jobs:
run: |-
echo "JELLYFIN_VERSION=$(date +'%Y%m%d%H%M%S')" >> $GITHUB_ENV
- name: Download openapi-head
uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8
uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0
with:
name: openapi-head
path: openapi-head
- name: Upload openapi.json (unstable) to repository server
uses: appleboy/scp-action@917f8b81dfc1ccd331fef9e2d61bdc6c8be94634 # v0.1.7
uses: appleboy/scp-action@ff85246acaad7bdce478db94a363cd2bf7c90345 # v1.0.0
with:
host: "${{ secrets.REPO_HOST }}"
username: "${{ secrets.REPO_USER }}"
@@ -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@25ce8cbbcb08177468c7ff7ec5cbfa236f9341e1 # v1.1.0
uses: appleboy/ssh-action@823bd89e131d8d508129f9443cad5855e9ba96f0 # v1.2.4
with:
host: "${{ secrets.REPO_HOST }}"
username: "${{ secrets.REPO_USER }}"
@@ -220,12 +220,12 @@ jobs:
run: |-
echo "JELLYFIN_VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_ENV
- name: Download openapi-head
uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8
uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0
with:
name: openapi-head
path: openapi-head
- name: Upload openapi.json (stable) to repository server
uses: appleboy/scp-action@917f8b81dfc1ccd331fef9e2d61bdc6c8be94634 # v0.1.7
uses: appleboy/scp-action@ff85246acaad7bdce478db94a363cd2bf7c90345 # v1.0.0
with:
host: "${{ secrets.REPO_HOST }}"
username: "${{ secrets.REPO_USER }}"
@@ -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@25ce8cbbcb08177468c7ff7ec5cbfa236f9341e1 # v1.1.0
uses: appleboy/ssh-action@823bd89e131d8d508129f9443cad5855e9ba96f0 # v1.2.4
with:
host: "${{ secrets.REPO_HOST }}"
username: "${{ secrets.REPO_USER }}"

View File

@@ -9,19 +9,20 @@ on:
pull_request:
env:
SDK_VERSION: "8.0.x"
SDK_VERSION: "9.0.x"
jobs:
run-tests:
strategy:
matrix:
os: ["ubuntu-latest", "macos-latest", "windows-latest"]
fail-fast: false
runs-on: "${{ matrix.os }}"
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- uses: actions/setup-dotnet@3e891b0cb619bf60e2c25674b222b8940e2c1c25 # v4.1.0
- uses: actions/setup-dotnet@2016bd2012dba4e32de620c46fe006a3ac9f0602 # v5.0.1
with:
dotnet-version: ${{ env.SDK_VERSION }}
@@ -34,7 +35,7 @@ jobs:
--verbosity minimal
- name: Merge code coverage results
uses: danielpalme/ReportGenerator-GitHub-Action@62f9e70ab348d56eee76d446b4db903a85ab0ea8 # v5.3.11
uses: danielpalme/ReportGenerator-GitHub-Action@ee0ae774f6d3afedcbd1683c1ab21b83670bdf8e # v5.5.1
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@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
token: ${{ secrets.JF_BOT_TOKEN }}
fetch-depth: 0
@@ -34,107 +34,19 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.JF_BOT_TOKEN }}
check-backport:
permissions:
contents: read
name: Check Backport
if: ${{ ( github.event.issue.pull_request && contains(github.event.comment.body, '@jellyfin-bot check backport') ) || github.event.label.name == 'stable backport' || contains(github.event.pull_request.labels.*.name, 'stable backport' ) }}
runs-on: ubuntu-latest
steps:
- name: Notify as seen
uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4.0.0
if: ${{ github.event.comment != null }}
with:
token: ${{ secrets.JF_BOT_TOKEN }}
comment-id: ${{ github.event.comment.id }}
reactions: eyes
- name: Checkout the latest code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
token: ${{ secrets.JF_BOT_TOKEN }}
fetch-depth: 0
- name: Notify as running
id: comment_running
uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4.0.0
if: ${{ github.event.comment != null }}
with:
token: ${{ secrets.JF_BOT_TOKEN }}
issue-number: ${{ github.event.issue.number }}
body: |
Running backport tests...
- name: Perform test backport
id: run_tests
run: |
set +o errexit
git config --global user.name "Jellyfin Bot"
git config --global user.email "team@jellyfin.org"
CURRENT_BRANCH="origin/${GITHUB_HEAD_REF}"
git checkout master
git merge --no-ff ${CURRENT_BRANCH}
MERGE_COMMIT_HASH=$( git log -q -1 | head -1 | awk '{ print $2 }' )
git fetch --all
CURRENT_STABLE=$( git branch -r | grep 'origin/release' | sort -rV | head -1 | awk -F '/' '{ print $NF }' )
stable_branch="Current stable release branch: ${CURRENT_STABLE}"
echo ${stable_branch}
echo ::set-output name=branch::${stable_branch}
git checkout -t origin/${CURRENT_STABLE} -b ${CURRENT_STABLE}
git cherry-pick -sx -m1 ${MERGE_COMMIT_HASH} &>output.txt
retcode=$?
cat output.txt | grep -v 'hint:'
output="$( grep -v 'hint:' output.txt )"
output="${output//'%'/'%25'}"
output="${output//$'\n'/'%0A'}"
output="${output//$'\r'/'%0D'}"
echo ::set-output name=output::$output
exit ${retcode}
- name: Notify with result success
uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4.0.0
if: ${{ github.event.comment != null && success() }}
with:
token: ${{ secrets.JF_BOT_TOKEN }}
comment-id: ${{ steps.comment_running.outputs.comment-id }}
body: |
${{ steps.run_tests.outputs.branch }}
Output from `git cherry-pick`:
---
${{ steps.run_tests.outputs.output }}
reactions: hooray
- name: Notify with result failure
uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4.0.0
if: ${{ github.event.comment != null && failure() }}
with:
token: ${{ secrets.JF_BOT_TOKEN }}
comment-id: ${{ steps.comment_running.outputs.comment-id }}
body: |
${{ steps.run_tests.outputs.branch }}
Output from `git cherry-pick`:
---
${{ steps.run_tests.outputs.output }}
reactions: confused
rename:
name: Rename
if: contains(github.event.comment.body, '@jellyfin-bot rename') && github.event.comment.author_association == 'MEMBER'
runs-on: ubuntu-latest
steps:
- name: pull in script
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
repository: jellyfin/jellyfin-triage-script
- name: install python
uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0
uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0
with:
python-version: '3.12'
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@28ca1036281a5e5922ead5184a1bbf96e5fc984e # v9.0.0
- uses: actions/stale@997185467fa4f803885201cee163a9f38240193d # v10.1.1
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@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
repository: jellyfin/jellyfin-triage-script
- name: install python
uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0
uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0
with:
python-version: '3.12'
python-version: '3.14'
cache: 'pip'
- name: install python packages
run: pip install -r main-repo-triage/requirements.txt

View File

@@ -12,10 +12,10 @@ jobs:
label:
name: Labeling
runs-on: ubuntu-latest
if: ${{ github.repository == 'jellyfin/jellyfin' }}
if: ${{ github.repository == 'jellyfin/jellyfin' && github.event.issue.pull_request }}
steps:
- name: Apply label
uses: eps1lon/actions-label-merge-conflict@1b1b1fcde06a9b3d089f3464c96417961dde1168 # v3.0.2
uses: eps1lon/actions-label-merge-conflict@1df065ebe6e3310545d4f4c4e862e43bdca146f0 # v3.0.3
if: ${{ github.event_name == 'push' || github.event_name == 'pull_request_target'}}
with:
dirtyLabel: 'merge conflict'

View File

@@ -15,7 +15,7 @@ jobs:
runs-on: ubuntu-latest
if: ${{ contains(github.repository, 'jellyfin/') }}
steps:
- uses: actions/stale@28ca1036281a5e5922ead5184a1bbf96e5fc984e # v9.0.0
- uses: actions/stale@997185467fa4f803885201cee163a9f38240193d # v10.1.1
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@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
ref: ${{ env.TAG_BRANCH }}
@@ -66,7 +66,7 @@ jobs:
NEXT_VERSION: ${{ github.event.inputs.NEXT_VERSION }}
steps:
- name: Checkout Repository
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
ref: ${{ env.TAG_BRANCH }}

View File

@@ -1,12 +1,13 @@
{
"recommendations": [
"recommendations": [
"ms-dotnettools.csharp",
"editorconfig.editorconfig",
"github.vscode-github-actions",
"ms-dotnettools.vscode-dotnet-runtime",
"ms-dotnettools.csdevkit"
],
"unwantedRecommendations": [
"ms-dotnettools.csdevkit",
"alexcvzz.vscode-sqlite"
],
"unwantedRecommendations": [
]
]
}

6
.vscode/launch.json vendored
View File

@@ -6,7 +6,7 @@
"type": "coreclr",
"request": "launch",
"preLaunchTask": "build",
"program": "${workspaceFolder}/Jellyfin.Server/bin/Debug/net8.0/jellyfin.dll",
"program": "${workspaceFolder}/Jellyfin.Server/bin/Debug/net9.0/jellyfin.dll",
"args": [],
"cwd": "${workspaceFolder}/Jellyfin.Server",
"console": "internalConsole",
@@ -22,7 +22,7 @@
"type": "coreclr",
"request": "launch",
"preLaunchTask": "build",
"program": "${workspaceFolder}/Jellyfin.Server/bin/Debug/net8.0/jellyfin.dll",
"program": "${workspaceFolder}/Jellyfin.Server/bin/Debug/net9.0/jellyfin.dll",
"args": ["--nowebclient"],
"cwd": "${workspaceFolder}/Jellyfin.Server",
"console": "internalConsole",
@@ -34,7 +34,7 @@
"type": "coreclr",
"request": "launch",
"preLaunchTask": "build",
"program": "${workspaceFolder}/Jellyfin.Server/bin/Debug/net8.0/jellyfin.dll",
"program": "${workspaceFolder}/Jellyfin.Server/bin/Debug/net9.0/jellyfin.dll",
"args": ["--nowebclient", "--ffmpeg", "/usr/lib/jellyfin-ffmpeg/ffmpeg"],
"cwd": "${workspaceFolder}/Jellyfin.Server",
"console": "internalConsole",

3
.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,3 @@
{
"dotnet.preferVisualStudioCodeFileSystemWatcher": true
}

View File

@@ -27,9 +27,11 @@
- [cryptobank](https://github.com/cryptobank)
- [cvium](https://github.com/cvium)
- [dannymichel](https://github.com/dannymichel)
- [darioackermann](https://github.com/darioackermann)
- [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)
@@ -60,6 +62,7 @@
- [ikomhoog](https://github.com/ikomhoog)
- [iwalton3](https://github.com/iwalton3)
- [jftuga](https://github.com/jftuga)
- [jkhsjdhjs](https://github.com/jkhsjdhjs)
- [jmshrv](https://github.com/jmshrv)
- [joern-h](https://github.com/joern-h)
- [joshuaboniface](https://github.com/joshuaboniface)
@@ -138,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)
@@ -192,6 +196,15 @@
- [jaina heartles](https://github.com/heartles)
- [oxixes](https://github.com/oxixes)
- [elfalem](https://github.com/elfalem)
- [Kenneth Cochran](https://github.com/kennethcochran)
- [benedikt257](https://github.com/benedikt257)
- [revam](https://github.com/revam)
- [allesmi](https://github.com/allesmi)
- [ThunderClapLP](https://github.com/ThunderClapLP)
- [Shoham Peller](https://github.com/spellr)
- [theshoeshiner](https://github.com/theshoeshiner)
- [TokerX](https://github.com/TokerX)
- [GeneMarks](https://github.com/GeneMarks)
# Emby Contributors
@@ -265,3 +278,6 @@
- [0x25CBFC4F](https://github.com/0x25CBFC4F)
- [Robert Lützner](https://github.com/rluetzner)
- [Nathan McCrina](https://github.com/nfmccrina)
- [Martin Reuter](https://github.com/reuterma24)
- [Michael McElroy](https://github.com/mcmcelro)
- [Soumyadip Auddy](https://github.com/SoumyadipAuddy)

View File

@@ -3,11 +3,11 @@
<PropertyGroup>
<Nullable>enable</Nullable>
<CodeAnalysisRuleSet>$(MSBuildThisFileDirectory)/jellyfin.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<WarningsNotAsErrors>NU1902;NU1903</WarningsNotAsErrors>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
@@ -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,88 +4,96 @@
</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.0.2" />
<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" />
<PackageVersion Include="BDInfo" Version="0.8.0" />
<PackageVersion Include="BlurHashSharp.SkiaSharp" Version="1.3.3" />
<PackageVersion Include="BlurHashSharp" Version="1.3.3" />
<PackageVersion Include="BitFaster.Caching" Version="2.5.4" />
<PackageVersion Include="BlurHashSharp.SkiaSharp" Version="1.4.0-pre.1" />
<PackageVersion Include="BlurHashSharp" Version="1.4.0-pre.1" />
<PackageVersion Include="CommandLineParser" Version="2.9.1" />
<PackageVersion Include="coverlet.collector" Version="6.0.2" />
<PackageVersion Include="Diacritics" Version="3.3.29" />
<PackageVersion Include="coverlet.collector" Version="6.0.4" />
<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="2.16.6" />
<PackageVersion Include="HarfBuzzSharp.NativeAssets.Linux" Version="7.3.0.2" />
<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" />
<PackageVersion Include="Ignore" Version="0.2.1" />
<PackageVersion Include="Jellyfin.XmlTv" Version="10.8.0" />
<PackageVersion Include="libse" Version="4.0.8" />
<PackageVersion Include="LrcParser" Version="2024.0728.2" />
<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="8.0.10" />
<PackageVersion Include="Microsoft.AspNetCore.Mvc.Testing" Version="8.0.10" />
<PackageVersion Include="Microsoft.CodeAnalysis.BannedApiAnalyzers" Version="3.3.4" />
<PackageVersion Include="Microsoft.Data.Sqlite" Version="8.0.10" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.10" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Relational" Version="8.0.10" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Sqlite" Version="8.0.10" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.10" />
<PackageVersion Include="Microsoft.Extensions.Caching.Abstractions" Version="8.0.0" />
<PackageVersion Include="Microsoft.Extensions.Caching.Memory" Version="8.0.1" />
<PackageVersion Include="Microsoft.Extensions.Configuration.Abstractions" Version="8.0.0" />
<PackageVersion Include="Microsoft.Extensions.Configuration.Binder" Version="8.0.2" />
<PackageVersion Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="8.0.0" />
<PackageVersion Include="Microsoft.Extensions.Configuration.Json" Version="8.0.1" />
<PackageVersion Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.2" />
<PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="8.0.1" />
<PackageVersion Include="Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore" Version="8.0.10" />
<PackageVersion Include="Microsoft.Extensions.Diagnostics.HealthChecks" Version="8.0.10" />
<PackageVersion Include="Microsoft.Extensions.Hosting.Abstractions" Version="8.0.1" />
<PackageVersion Include="Microsoft.Extensions.Http" Version="8.0.1" />
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.2" />
<PackageVersion Include="Microsoft.Extensions.Logging" Version="8.0.1" />
<PackageVersion Include="Microsoft.Extensions.Options" Version="8.0.2" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.11.1" />
<PackageVersion Include="MimeTypes" Version="2.4.0" />
<PackageVersion Include="Mono.Nat" Version="3.0.4" />
<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.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="0.11.0" />
<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="Serilog.AspNetCore" Version="8.0.3" />
<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.Settings.Configuration" Version="8.0.4" />
<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.File" 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.1.1" />
<PackageVersion Include="SkiaSharp" Version="2.88.8" />
<PackageVersion Include="SkiaSharp.HarfBuzz" Version="2.88.8" />
<PackageVersion Include="SkiaSharp.NativeAssets.Linux" Version="2.88.8" />
<PackageVersion Include="SharpFuzz" Version="2.2.0" />
<!-- 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="2.0.0.1" />
<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.1" />
<PackageVersion Include="System.Text.Encoding.CodePages" Version="8.0.0" />
<PackageVersion Include="System.Text.Json" Version="8.0.5" />
<PackageVersion Include="System.Threading.Tasks.Dataflow" Version="8.0.1" />
<PackageVersion Include="System.Linq.Async" Version="6.0.3" />
<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="6.6.0" />
<PackageVersion Include="TMDbLib" Version="2.2.0" />
<PackageVersion Include="UTF.Unknown" Version="2.5.1" />
<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.4.13" />
<PackageVersion Include="xunit" Version="2.9.2" />
<PackageVersion Include="Xunit.SkippableFact" Version="1.5.23" />
<PackageVersion Include="xunit" Version="2.9.3" />
</ItemGroup>
</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,27 +171,29 @@ namespace Emby.Naming.Common
".sub",
".sup",
".vtt",
};
];
LyricFileExtensions = new[]
{
LyricFileExtensions =
[
".lrc",
".elrc",
".txt"
};
];
AlbumStackingPrefixes = new[]
{
AlbumStackingPrefixes =
[
"cd",
"digital media",
"disc",
"disk",
"vol",
"volume"
};
"volume",
"part",
"act"
];
ArtistSubfolders = new[]
{
ArtistSubfolders =
[
"albums",
"broadcasts",
"bootlegs",
@@ -206,10 +208,10 @@ namespace Emby.Naming.Common
"soundtracks",
"spokenwords",
"streets"
};
];
AudioFileExtensions = new[]
{
AudioFileExtensions =
[
".669",
".3gp",
".aa",
@@ -238,6 +240,8 @@ namespace Emby.Naming.Common
".dsp",
".dts",
".dvf",
".eac3",
".ec3",
".far",
".flac",
".gdm",
@@ -288,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]+)([^\\/]*)$")
@@ -327,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
@@ -467,10 +471,18 @@ namespace Emby.Naming.Common
{
IsNamed = true
},
};
VideoExtraRules = new[]
{
// Anime style expression
// "[Group][Series Name][21][1080p][FLAC][HASH]"
// "[Group] Series Name [04][BDRIP]"
new EpisodeExpression(@"(?:\[(?:[^\]]+)\]\s*)?(?<seriesname>\[[^\]]+\]|[^[\]]+)\s*\[(?<epnumber>[0-9]+)\]")
{
IsNamed = true
},
];
VideoExtraRules =
[
new ExtraRule(
ExtraType.Trailer,
ExtraRuleType.DirectoryName,
@@ -561,6 +573,18 @@ namespace Emby.Naming.Common
"trailer",
MediaType.Video),
new ExtraRule(
ExtraType.Sample,
ExtraRuleType.Filename,
"sample",
MediaType.Video),
new ExtraRule(
ExtraType.ThemeSong,
ExtraRuleType.Filename,
"theme",
MediaType.Audio),
new ExtraRule(
ExtraType.Trailer,
ExtraRuleType.Suffix,
@@ -582,13 +606,7 @@ namespace Emby.Naming.Common
new ExtraRule(
ExtraType.Trailer,
ExtraRuleType.Suffix,
" trailer",
MediaType.Video),
new ExtraRule(
ExtraType.Sample,
ExtraRuleType.Filename,
"sample",
"- trailer",
MediaType.Video),
new ExtraRule(
@@ -612,15 +630,9 @@ namespace Emby.Naming.Common
new ExtraRule(
ExtraType.Sample,
ExtraRuleType.Suffix,
" sample",
"- sample",
MediaType.Video),
new ExtraRule(
ExtraType.ThemeSong,
ExtraRuleType.Filename,
"theme",
MediaType.Audio),
new ExtraRule(
ExtraType.Scene,
ExtraRuleType.Suffix,
@@ -680,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",
@@ -714,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
@@ -730,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[]
{
@@ -877,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

@@ -6,7 +6,7 @@
</PropertyGroup>
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net9.0</TargetFramework>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<PublishRepositoryUrl>true</PublishRepositoryUrl>
@@ -36,7 +36,7 @@
<PropertyGroup>
<Authors>Jellyfin Contributors</Authors>
<PackageId>Jellyfin.Naming</PackageId>
<VersionPrefix>10.10.0</VersionPrefix>
<VersionPrefix>10.12.0</VersionPrefix>
<RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl>
<PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression>
</PropertyGroup>

View File

@@ -97,14 +97,18 @@ namespace Emby.Naming.ExternalFiles
if (culture is not null && pathInfo.Language is null)
{
pathInfo.Language = culture.ThreeLetterISOLanguageName;
pathInfo.Language = culture.Name.Contains('-', StringComparison.OrdinalIgnoreCase)
? culture.Name
: culture.ThreeLetterISOLanguageName;
extraString = extraString.Replace(currentSlice, string.Empty, StringComparison.OrdinalIgnoreCase);
}
else if (culture is not null && pathInfo.Language == "hin")
{
// Hindi language code "hi" collides with a hearing impaired flag - use as Hindi only if no other language is set
pathInfo.IsHearingImpaired = true;
pathInfo.Language = culture.ThreeLetterISOLanguageName;
pathInfo.Language = culture.Name.Contains('-', StringComparison.OrdinalIgnoreCase)
? culture.Name
: culture.ThreeLetterISOLanguageName;
extraString = extraString.Replace(currentSlice, string.Empty, StringComparison.OrdinalIgnoreCase);
}
else if (_namingOptions.MediaHearingImpairedFlags.Any(s => currentSliceWithoutSeparator.Equals(s, StringComparison.OrdinalIgnoreCase)))

View File

@@ -1,43 +1,40 @@
using System;
using System.Globalization;
using System.IO;
using System.Text.RegularExpressions;
namespace Emby.Naming.TV
{
/// <summary>
/// Class to parse season paths.
/// </summary>
public static class SeasonPathParser
public static partial class SeasonPathParser
{
/// <summary>
/// A season folder must contain one of these somewhere in the name.
/// </summary>
private static readonly string[] _seasonFolderNames =
{
"season",
"sæson",
"temporada",
"saison",
"staffel",
"series",
"сезон",
"stagione"
};
private static readonly Regex CleanNameRegex = new(@"[ ._\-\[\]]", RegexOptions.Compiled);
private static readonly char[] _splitChars = ['.', '_', ' ', '-'];
[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+?)(?=\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>
/// <param name="path">Path to season.</param>
/// <param name="parentPath">Folder name of the parent.</param>
/// <param name="supportSpecialAliases">Support special aliases when parsing.</param>
/// <param name="supportNumericSeasonFolders">Support numeric season folders when parsing.</param>
/// <returns>Returns <see cref="SeasonPathParserResult"/> object.</returns>
public static SeasonPathParserResult Parse(string path, bool supportSpecialAliases, bool supportNumericSeasonFolders)
public static SeasonPathParserResult Parse(string path, string? parentPath, bool supportSpecialAliases, bool supportNumericSeasonFolders)
{
var result = new SeasonPathParserResult();
var parentFolderName = parentPath is null ? null : new DirectoryInfo(parentPath).Name;
var (seasonNumber, isSeasonFolder) = GetSeasonNumberFromPath(path, supportSpecialAliases, supportNumericSeasonFolders);
var (seasonNumber, isSeasonFolder) = GetSeasonNumberFromPath(path, parentFolderName, supportSpecialAliases, supportNumericSeasonFolders);
result.SeasonNumber = seasonNumber;
@@ -54,84 +51,70 @@ namespace Emby.Naming.TV
/// Gets the season number from path.
/// </summary>
/// <param name="path">The path.</param>
/// <param name="parentFolderName">The parent folder name.</param>
/// <param name="supportSpecialAliases">if set to <c>true</c> [support special aliases].</param>
/// <param name="supportNumericSeasonFolders">if set to <c>true</c> [support numeric season folders].</param>
/// <returns>System.Nullable{System.Int32}.</returns>
private static (int? SeasonNumber, bool IsSeasonFolder) GetSeasonNumberFromPath(
string path,
string? parentFolderName,
bool supportSpecialAliases,
bool supportNumericSeasonFolders)
{
string filename = Path.GetFileName(path);
var fileName = Path.GetFileName(path);
if (supportSpecialAliases)
var seasonPrefixMatch = SeasonPrefix().Match(fileName);
if (seasonPrefixMatch.Success &&
int.TryParse(seasonPrefixMatch.Groups[1].Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var val))
{
if (string.Equals(filename, "specials", StringComparison.OrdinalIgnoreCase))
{
return (0, true);
}
if (string.Equals(filename, "extras", StringComparison.OrdinalIgnoreCase))
{
return (0, true);
}
return (val, true);
}
if (supportNumericSeasonFolders)
string filename = CleanNameRegex.Replace(fileName, string.Empty);
if (parentFolderName is not null)
{
if (int.TryParse(filename, NumberStyles.Integer, CultureInfo.InvariantCulture, out var val))
{
return (val, true);
}
var cleanParent = CleanNameRegex.Replace(parentFolderName, string.Empty);
filename = filename.Replace(cleanParent, string.Empty, StringComparison.OrdinalIgnoreCase);
}
if (TryGetSeasonNumberFromPart(filename, out int seasonNumber))
if (supportSpecialAliases &&
(filename.Equals("specials", StringComparison.OrdinalIgnoreCase) ||
filename.Equals("extras", StringComparison.OrdinalIgnoreCase)))
{
return (seasonNumber, true);
return (0, true);
}
// Look for one of the season folder names
foreach (var name in _seasonFolderNames)
if (supportNumericSeasonFolders &&
int.TryParse(filename, NumberStyles.Integer, CultureInfo.InvariantCulture, out val))
{
if (filename.Contains(name, StringComparison.OrdinalIgnoreCase))
{
var result = GetSeasonNumberFromPathSubstring(filename.Replace(name, " ", StringComparison.OrdinalIgnoreCase));
if (result.SeasonNumber.HasValue)
{
return result;
}
break;
}
return (val, true);
}
var parts = filename.Split(_splitChars, StringSplitOptions.RemoveEmptyEntries);
foreach (var part in parts)
var preMatch = ProcessPre().Match(filename);
if (preMatch.Success)
{
if (TryGetSeasonNumberFromPart(part, out seasonNumber))
return CheckMatch(preMatch);
}
else
{
var postMatch = ProcessPost().Match(filename);
return CheckMatch(postMatch);
}
}
private static (int? SeasonNumber, bool IsSeasonFolder) CheckMatch(Match match)
{
var numberString = match.Groups["seasonnumber"];
if (numberString.Success)
{
if (int.TryParse(numberString.Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var seasonNumber))
{
return (seasonNumber, true);
}
}
return (null, true);
}
private static bool TryGetSeasonNumberFromPart(ReadOnlySpan<char> part, out int seasonNumber)
{
seasonNumber = 0;
if (part.Length < 2 || !part.StartsWith("s", StringComparison.OrdinalIgnoreCase))
{
return false;
}
if (int.TryParse(part.Slice(1), NumberStyles.Integer, CultureInfo.InvariantCulture, out var value))
{
seasonNumber = value;
return true;
}
return false;
return (null, false);
}
/// <summary>

View File

@@ -12,11 +12,18 @@ namespace Emby.Naming.TV
/// <summary>
/// Regex that matches strings of at least 2 characters separated by a dot or underscore.
/// Used for removing separators between words, i.e turns "The_show" into "The show" while
/// preserving namings like "S.H.O.W".
/// preserving names like "S.H.O.W".
/// </summary>
[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

@@ -18,68 +18,49 @@ namespace Emby.Naming.Video
/// </summary>
/// <param name="path">Path to file.</param>
/// <param name="namingOptions">The naming options.</param>
/// <param name="libraryRoot">Top-level folder for the containing library.</param>
/// <returns>Returns <see cref="ExtraResult"/> object.</returns>
public static ExtraResult GetExtraInfo(string path, NamingOptions namingOptions)
public static ExtraResult GetExtraInfo(string path, NamingOptions namingOptions, string? libraryRoot = "")
{
var result = new ExtraResult();
ExtraResult result = new ExtraResult();
for (var i = 0; i < namingOptions.VideoExtraRules.Length; i++)
bool isAudioFile = AudioFileParser.IsAudioFile(path, namingOptions);
bool isVideoFile = VideoResolver.IsVideoFile(path, namingOptions);
ReadOnlySpan<char> pathSpan = path.AsSpan();
ReadOnlySpan<char> fileName = Path.GetFileName(pathSpan);
ReadOnlySpan<char> fileNameWithoutExtension = Path.GetFileNameWithoutExtension(pathSpan);
// Trim the digits from the end of the filename so we can recognize things like -trailer2
ReadOnlySpan<char> trimmedFileNameWithoutExtension = fileNameWithoutExtension.TrimEnd(_digits);
ReadOnlySpan<char> directoryName = Path.GetFileName(Path.GetDirectoryName(pathSpan));
string fullDirectory = Path.GetDirectoryName(pathSpan).ToString();
foreach (ExtraRule rule in namingOptions.VideoExtraRules)
{
var rule = namingOptions.VideoExtraRules[i];
if ((rule.MediaType == MediaType.Audio && !AudioFileParser.IsAudioFile(path, namingOptions))
|| (rule.MediaType == MediaType.Video && !VideoResolver.IsVideoFile(path, namingOptions)))
if ((rule.MediaType == MediaType.Audio && !isAudioFile)
|| (rule.MediaType == MediaType.Video && !isVideoFile))
{
continue;
}
var pathSpan = path.AsSpan();
if (rule.RuleType == ExtraRuleType.Filename)
bool isMatch = rule.RuleType switch
{
var filename = Path.GetFileNameWithoutExtension(pathSpan);
ExtraRuleType.Filename => fileNameWithoutExtension.Equals(rule.Token, StringComparison.OrdinalIgnoreCase),
ExtraRuleType.Suffix => trimmedFileNameWithoutExtension.EndsWith(rule.Token, StringComparison.OrdinalIgnoreCase),
ExtraRuleType.Regex => Regex.IsMatch(fileName, rule.Token, RegexOptions.IgnoreCase | RegexOptions.Compiled),
ExtraRuleType.DirectoryName => directoryName.Equals(rule.Token, StringComparison.OrdinalIgnoreCase)
&& !string.Equals(fullDirectory, libraryRoot, StringComparison.OrdinalIgnoreCase),
_ => false,
};
if (filename.Equals(rule.Token, StringComparison.OrdinalIgnoreCase))
{
result.ExtraType = rule.ExtraType;
result.Rule = rule;
}
}
else if (rule.RuleType == ExtraRuleType.Suffix)
if (!isMatch)
{
// Trim the digits from the end of the filename so we can recognize things like -trailer2
var filename = Path.GetFileNameWithoutExtension(pathSpan).TrimEnd(_digits);
if (filename.EndsWith(rule.Token, StringComparison.OrdinalIgnoreCase))
{
result.ExtraType = rule.ExtraType;
result.Rule = rule;
}
}
else if (rule.RuleType == ExtraRuleType.Regex)
{
var filename = Path.GetFileName(path.AsSpan());
var isMatch = Regex.IsMatch(filename, rule.Token, RegexOptions.IgnoreCase | RegexOptions.Compiled);
if (isMatch)
{
result.ExtraType = rule.ExtraType;
result.Rule = rule;
}
}
else if (rule.RuleType == ExtraRuleType.DirectoryName)
{
var directoryName = Path.GetFileName(Path.GetDirectoryName(pathSpan));
if (directoryName.Equals(rule.Token, StringComparison.OrdinalIgnoreCase))
{
result.ExtraType = rule.ExtraType;
result.Rule = rule;
}
continue;
}
if (result.ExtraType is not null)
{
return result;
}
result.ExtraType = rule.ExtraType;
result.Rule = rule;
return result;
}
return result;

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

@@ -27,8 +27,9 @@ namespace Emby.Naming.Video
/// <param name="namingOptions">The naming options.</param>
/// <param name="supportMultiVersion">Indication we should consider multi-versions of content.</param>
/// <param name="parseName">Whether to parse the name or use the filename.</param>
/// <param name="libraryRoot">Top-level folder for the containing library.</param>
/// <returns>Returns enumerable of <see cref="VideoInfo"/> which groups files together when related.</returns>
public static IReadOnlyList<VideoInfo> Resolve(IReadOnlyList<VideoFileInfo> videoInfos, NamingOptions namingOptions, bool supportMultiVersion = true, bool parseName = true)
public static IReadOnlyList<VideoInfo> Resolve(IReadOnlyList<VideoFileInfo> videoInfos, NamingOptions namingOptions, bool supportMultiVersion = true, bool parseName = true, string? libraryRoot = "")
{
// Filter out all extras, otherwise they could cause stacks to not be resolved
// See the unit test TestStackedWithTrailer
@@ -65,7 +66,7 @@ namespace Emby.Naming.Video
{
var info = new VideoInfo(stack.Name)
{
Files = stack.Files.Select(i => VideoResolver.Resolve(i, stack.IsDirectoryStack, namingOptions, parseName))
Files = stack.Files.Select(i => VideoResolver.Resolve(i, stack.IsDirectoryStack, namingOptions, parseName, libraryRoot))
.OfType<VideoFileInfo>()
.ToList()
};

View File

@@ -17,10 +17,11 @@ namespace Emby.Naming.Video
/// <param name="path">The path.</param>
/// <param name="namingOptions">The naming options.</param>
/// <param name="parseName">Whether to parse the name or use the filename.</param>
/// <param name="libraryRoot">Top-level folder for the containing library.</param>
/// <returns>VideoFileInfo.</returns>
public static VideoFileInfo? ResolveDirectory(string? path, NamingOptions namingOptions, bool parseName = true)
public static VideoFileInfo? ResolveDirectory(string? path, NamingOptions namingOptions, bool parseName = true, string? libraryRoot = "")
{
return Resolve(path, true, namingOptions, parseName);
return Resolve(path, true, namingOptions, parseName, libraryRoot);
}
/// <summary>
@@ -28,10 +29,11 @@ namespace Emby.Naming.Video
/// </summary>
/// <param name="path">The path.</param>
/// <param name="namingOptions">The naming options.</param>
/// <param name="libraryRoot">Top-level folder for the containing library.</param>
/// <returns>VideoFileInfo.</returns>
public static VideoFileInfo? ResolveFile(string? path, NamingOptions namingOptions)
public static VideoFileInfo? ResolveFile(string? path, NamingOptions namingOptions, string? libraryRoot = "")
{
return Resolve(path, false, namingOptions);
return Resolve(path, false, namingOptions, libraryRoot: libraryRoot);
}
/// <summary>
@@ -41,9 +43,10 @@ namespace Emby.Naming.Video
/// <param name="isDirectory">if set to <c>true</c> [is folder].</param>
/// <param name="namingOptions">The naming options.</param>
/// <param name="parseName">Whether or not the name should be parsed for info.</param>
/// <param name="libraryRoot">Top-level folder for the containing library.</param>
/// <returns>VideoFileInfo.</returns>
/// <exception cref="ArgumentNullException"><c>path</c> is <c>null</c>.</exception>
public static VideoFileInfo? Resolve(string? path, bool isDirectory, NamingOptions namingOptions, bool parseName = true)
public static VideoFileInfo? Resolve(string? path, bool isDirectory, NamingOptions namingOptions, bool parseName = true, string? libraryRoot = "")
{
if (string.IsNullOrEmpty(path))
{
@@ -75,7 +78,7 @@ namespace Emby.Naming.Video
var format3DResult = Format3DParser.Parse(path, namingOptions);
var extraResult = ExtraRuleResolver.GetExtraInfo(path, namingOptions);
var extraResult = ExtraRuleResolver.GetExtraInfo(path, namingOptions, libraryRoot);
var name = Path.GetFileNameWithoutExtension(path);

View File

@@ -19,7 +19,7 @@
</ItemGroup>
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net9.0</TargetFramework>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
</PropertyGroup>

View File

@@ -49,7 +49,7 @@ public class PhotoProvider : ICustomMetadataProvider<Photo>, IForcedProvider, IH
if (item.IsFileProtocol)
{
var file = directoryService.GetFile(item.Path);
return file is not null && file.LastWriteTimeUtc != item.DateModified;
return file is not null && item.HasChanged(file.LastWriteTimeUtc);
}
return false;
@@ -108,7 +108,7 @@ public class PhotoProvider : ICustomMetadataProvider<Photo>, IForcedProvider, IH
var dateTaken = image.ImageTag.DateTime;
if (dateTaken.HasValue)
{
item.DateCreated = dateTaken.Value;
item.DateCreated = dateTaken.Value.ToUniversalTime();
item.PremiereDate = dateTaken.Value;
item.ProductionYear = dateTaken.Value.Year;
}

View File

@@ -1,5 +1,8 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Jellyfin.Extensions;
using MediaBrowser.Common.Configuration;
namespace Emby.Server.Implementations.AppBase
@@ -30,80 +33,101 @@ namespace Emby.Server.Implementations.AppBase
ConfigurationDirectoryPath = configurationDirectoryPath;
CachePath = cacheDirectoryPath;
WebPath = webDirectoryPath;
DataPath = Directory.CreateDirectory(Path.Combine(ProgramDataPath, "data")).FullName;
}
/// <summary>
/// Gets the path to the program data folder.
/// </summary>
/// <value>The program data path.</value>
/// <inheritdoc/>
public string ProgramDataPath { get; }
/// <inheritdoc/>
public string WebPath { get; }
/// <summary>
/// Gets the path to the system folder.
/// </summary>
/// <value>The path to the system folder.</value>
/// <inheritdoc/>
public string ProgramSystemPath { get; } = AppContext.BaseDirectory;
/// <summary>
/// Gets the folder path to the data directory.
/// </summary>
/// <value>The data directory.</value>
/// <inheritdoc/>
public string DataPath { get; }
/// <inheritdoc />
public string VirtualDataPath => "%AppDataPath%";
/// <summary>
/// Gets the image cache path.
/// </summary>
/// <value>The image cache path.</value>
/// <inheritdoc/>
public string ImageCachePath => Path.Combine(CachePath, "images");
/// <summary>
/// Gets the path to the plugin directory.
/// </summary>
/// <value>The plugins path.</value>
/// <inheritdoc/>
public string PluginsPath => Path.Combine(ProgramDataPath, "plugins");
/// <summary>
/// Gets the path to the plugin configurations directory.
/// </summary>
/// <value>The plugin configurations path.</value>
/// <inheritdoc/>
public string PluginConfigurationsPath => Path.Combine(PluginsPath, "configurations");
/// <summary>
/// Gets the path to the log directory.
/// </summary>
/// <value>The log directory path.</value>
/// <inheritdoc/>
public string LogDirectoryPath { get; }
/// <summary>
/// Gets the path to the application configuration root directory.
/// </summary>
/// <value>The configuration directory path.</value>
/// <inheritdoc/>
public string ConfigurationDirectoryPath { get; }
/// <summary>
/// Gets the path to the system configuration file.
/// </summary>
/// <value>The system configuration file path.</value>
/// <inheritdoc/>
public string SystemConfigurationFilePath => Path.Combine(ConfigurationDirectoryPath, "system.xml");
/// <summary>
/// Gets or sets the folder path to the cache directory.
/// </summary>
/// <value>The cache directory.</value>
/// <inheritdoc/>
public string CachePath { get; set; }
/// <summary>
/// Gets the folder path to the temp directory within the cache folder.
/// </summary>
/// <value>The temp directory.</value>
/// <inheritdoc/>
public string TempDirectory => Path.Join(Path.GetTempPath(), "jellyfin");
/// <inheritdoc />
public string TrickplayPath => Path.Combine(DataPath, "trickplay");
/// <inheritdoc />
public string BackupPath => Path.Combine(DataPath, "backups");
/// <inheritdoc />
public virtual void MakeSanityCheckOrThrow()
{
CreateAndCheckMarker(ConfigurationDirectoryPath, "config");
CreateAndCheckMarker(LogDirectoryPath, "log");
CreateAndCheckMarker(PluginsPath, "plugin");
CreateAndCheckMarker(ProgramDataPath, "data");
CreateAndCheckMarker(CachePath, "cache");
CreateAndCheckMarker(DataPath, "data");
}
/// <inheritdoc />
public void CreateAndCheckMarker(string path, string markerName, bool recursive = false)
{
Directory.CreateDirectory(path);
CheckOrCreateMarker(path, $".jellyfin-{markerName}", recursive);
}
private IEnumerable<string> GetMarkers(string path, bool recursive = false)
{
return Directory.EnumerateFiles(path, ".jellyfin-*", recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly);
}
private void CheckOrCreateMarker(string path, string markerName, bool recursive = false)
{
string? otherMarkers = null;
try
{
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);
if (!File.Exists(markerPath))
{
FileHelper.CreateEmpty(markerPath);
}
}
}
}

View File

@@ -4,6 +4,7 @@ using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Threading;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Events;
using MediaBrowser.Common.Extensions;
@@ -19,7 +20,7 @@ namespace Emby.Server.Implementations.AppBase
public abstract class BaseConfigurationManager : IConfigurationManager
{
private readonly ConcurrentDictionary<string, object> _configurations = new();
private readonly object _configurationSyncLock = new();
private readonly Lock _configurationSyncLock = new();
private ConfigurationStore[] _configurationStores = Array.Empty<ConfigurationStore>();
private IConfigurationFactory[] _configurationFactories = Array.Empty<IConfigurationFactory>();
@@ -226,6 +227,7 @@ namespace Emby.Server.Implementations.AppBase
Logger.LogInformation("Setting cache path: {Path}", cachePath);
((BaseApplicationPaths)CommonApplicationPaths).CachePath = cachePath;
CommonApplicationPaths.CreateAndCheckMarker(((BaseApplicationPaths)CommonApplicationPaths).CachePath, "cache");
}
/// <summary>

View File

@@ -15,6 +15,7 @@ using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks;
using Emby.Naming.Common;
using Emby.Photos;
using Emby.Server.Implementations.Chapters;
using Emby.Server.Implementations.Collections;
using Emby.Server.Implementations.Configuration;
using Emby.Server.Implementations.Cryptography;
@@ -39,8 +40,10 @@ using Jellyfin.Drawing;
using Jellyfin.MediaEncoding.Hls.Playlist;
using Jellyfin.Networking.Manager;
using Jellyfin.Networking.Udp;
using Jellyfin.Server.Implementations;
using Jellyfin.Server.Implementations.FullSystemBackup;
using Jellyfin.Server.Implementations.Item;
using Jellyfin.Server.Implementations.MediaSegments;
using Jellyfin.Server.Implementations.SystemBackupService;
using MediaBrowser.Common;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Events;
@@ -56,10 +59,14 @@ using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Drawing;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.IO;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.LibraryTaskScheduler;
using MediaBrowser.Controller.LiveTv;
using MediaBrowser.Controller.Lyrics;
using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.Controller.MediaSegments;
using MediaBrowser.Controller.Net;
using MediaBrowser.Controller.Persistence;
using MediaBrowser.Controller.Playlists;
@@ -83,7 +90,6 @@ using MediaBrowser.Model.Net;
using MediaBrowser.Model.Serialization;
using MediaBrowser.Model.System;
using MediaBrowser.Model.Tasks;
using MediaBrowser.Providers.Chapters;
using MediaBrowser.Providers.Lyric;
using MediaBrowser.Providers.Manager;
using MediaBrowser.Providers.Plugins.Tmdb;
@@ -91,7 +97,6 @@ using MediaBrowser.Providers.Subtitles;
using MediaBrowser.XbmcMetadata.Providers;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
@@ -266,8 +271,15 @@ namespace Emby.Server.Implementations
? Environment.MachineName
: ConfigurationManager.Configuration.ServerName;
public string RestoreBackupPath { get; set; }
public string ExpandVirtualPath(string path)
{
if (path is null)
{
return null;
}
var appPaths = ApplicationPaths;
return path.Replace(appPaths.VirtualDataPath, appPaths.DataPath, StringComparison.OrdinalIgnoreCase)
@@ -465,6 +477,7 @@ namespace Emby.Server.Implementations
serviceCollection.AddSingleton<IApplicationHost>(this);
serviceCollection.AddSingleton<IPluginManager>(_pluginManager);
serviceCollection.AddSingleton<IApplicationPaths>(ApplicationPaths);
serviceCollection.AddSingleton<IBackupService, BackupService>();
serviceCollection.AddSingleton<IFileSystem, ManagedFileSystem>();
serviceCollection.AddSingleton<IShortcutHandler, MbLinkShortcutHandler>();
@@ -492,13 +505,20 @@ namespace Emby.Server.Implementations
serviceCollection.AddSingleton<IBlurayExaminer, BdInfoExaminer>();
serviceCollection.AddSingleton<IUserDataRepository, SqliteUserDataRepository>();
serviceCollection.AddSingleton<IUserDataManager, UserDataManager>();
serviceCollection.AddSingleton<IItemRepository, SqliteItemRepository>();
serviceCollection.AddSingleton<IItemRepository, BaseItemRepository>();
serviceCollection.AddSingleton<IPeopleRepository, PeopleRepository>();
serviceCollection.AddSingleton<IChapterRepository, ChapterRepository>();
serviceCollection.AddSingleton<IMediaAttachmentRepository, MediaAttachmentRepository>();
serviceCollection.AddSingleton<IMediaStreamRepository, MediaStreamRepository>();
serviceCollection.AddSingleton<IKeyframeRepository, KeyframeRepository>();
serviceCollection.AddSingleton<IItemTypeLookup, ItemTypeLookup>();
serviceCollection.AddSingleton<IMediaEncoder, MediaBrowser.MediaEncoding.Encoder.MediaEncoder>();
serviceCollection.AddSingleton<EncodingHelper>();
serviceCollection.AddSingleton<IPathManager, PathManager>();
serviceCollection.AddSingleton<IExternalDataManager, ExternalDataManager>();
// TODO: Refactor to eliminate the circular dependencies here so that Lazy<T> isn't required
serviceCollection.AddTransient(provider => new Lazy<ILibraryMonitor>(provider.GetRequiredService<ILibraryMonitor>));
@@ -533,6 +553,7 @@ namespace Emby.Server.Implementations
serviceCollection.AddSingleton<ISessionManager, SessionManager>();
serviceCollection.AddSingleton<ICollectionManager, CollectionManager>();
serviceCollection.AddSingleton<ILimitedConcurrencyLibraryScheduler, LimitedConcurrencyLibraryScheduler>();
serviceCollection.AddSingleton<IPlaylistManager, PlaylistManager>();
@@ -542,13 +563,12 @@ namespace Emby.Server.Implementations
serviceCollection.AddSingleton<IChapterManager, ChapterManager>();
serviceCollection.AddSingleton<IEncodingManager, MediaEncoder.EncodingManager>();
serviceCollection.AddSingleton<IAuthService, AuthService>();
serviceCollection.AddSingleton<IQuickConnect, QuickConnectManager>();
serviceCollection.AddSingleton<ISubtitleParser, SubtitleEditParser>();
serviceCollection.AddSingleton<ISubtitleEncoder, SubtitleEncoder>();
serviceCollection.AddSingleton<IKeyframeManager, KeyframeManager>();
serviceCollection.AddSingleton<IAttachmentExtractor, MediaBrowser.MediaEncoding.Attachments.AttachmentExtractor>();
@@ -565,23 +585,10 @@ namespace Emby.Server.Implementations
/// <summary>
/// Create services registered with the service container that need to be initialized at application startup.
/// </summary>
/// <param name="startupConfig">The configuration used to initialise the application.</param>
/// <returns>A task representing the service initialization operation.</returns>
public async Task InitializeServices()
public async Task InitializeServices(IConfiguration startupConfig)
{
var jellyfinDb = await Resolve<IDbContextFactory<JellyfinDbContext>>().CreateDbContextAsync().ConfigureAwait(false);
await using (jellyfinDb.ConfigureAwait(false))
{
if ((await jellyfinDb.Database.GetPendingMigrationsAsync().ConfigureAwait(false)).Any())
{
Logger.LogInformation("There are pending EFCore migrations in the database. Applying... (This may take a while, do not stop Jellyfin)");
await jellyfinDb.Database.MigrateAsync().ConfigureAwait(false);
Logger.LogInformation("EFCore migrations applied successfully");
}
}
((SqliteItemRepository)Resolve<IItemRepository>()).Initialize();
((SqliteUserDataRepository)Resolve<IUserDataRepository>()).Initialize();
var localizationManager = (LocalizationManager)Resolve<ILocalizationManager>();
await localizationManager.LoadAll().ConfigureAwait(false);
@@ -607,7 +614,7 @@ namespace Emby.Server.Implementations
// Don't use an empty string password
password = string.IsNullOrWhiteSpace(password) ? null : password;
var localCert = new X509Certificate2(path, password, X509KeyStorageFlags.UserKeySet);
var localCert = X509CertificateLoader.LoadPkcs12FromFile(path, password, X509KeyStorageFlags.UserKeySet);
if (!localCert.HasPrivateKey)
{
Logger.LogError("No private key included in SSL cert {CertificateLocation}.", path);
@@ -629,23 +636,26 @@ namespace Emby.Server.Implementations
private void SetStaticProperties()
{
// For now there's no real way to inject these properly
BaseItem.Logger = Resolve<ILogger<BaseItem>>();
BaseItem.ConfigurationManager = ConfigurationManager;
BaseItem.LibraryManager = Resolve<ILibraryManager>();
BaseItem.ProviderManager = Resolve<IProviderManager>();
BaseItem.LocalizationManager = Resolve<ILocalizationManager>();
BaseItem.ItemRepository = Resolve<IItemRepository>();
BaseItem.FileSystem = Resolve<IFileSystem>();
BaseItem.UserDataManager = Resolve<IUserDataManager>();
BaseItem.ChapterManager = Resolve<IChapterManager>();
BaseItem.ChannelManager = Resolve<IChannelManager>();
Video.RecordingsManager = Resolve<IRecordingsManager>();
Folder.UserViewManager = Resolve<IUserViewManager>();
UserView.TVSeriesManager = Resolve<ITVSeriesManager>();
UserView.CollectionManager = Resolve<ICollectionManager>();
BaseItem.MediaSourceManager = Resolve<IMediaSourceManager>();
BaseItem.ConfigurationManager = ConfigurationManager;
BaseItem.FileSystem = Resolve<IFileSystem>();
BaseItem.ItemRepository = Resolve<IItemRepository>();
BaseItem.LibraryManager = Resolve<ILibraryManager>();
BaseItem.LocalizationManager = Resolve<ILocalizationManager>();
BaseItem.Logger = Resolve<ILogger<BaseItem>>();
BaseItem.MediaSegmentManager = Resolve<IMediaSegmentManager>();
BaseItem.MediaSourceManager = Resolve<IMediaSourceManager>();
BaseItem.ProviderManager = Resolve<IProviderManager>();
BaseItem.UserDataManager = Resolve<IUserDataManager>();
CollectionFolder.XmlSerializer = _xmlSerializer;
CollectionFolder.ApplicationHost = this;
Folder.UserViewManager = Resolve<IUserViewManager>();
Folder.CollectionManager = Resolve<ICollectionManager>();
Folder.LimitedConcurrencyLibraryScheduler = Resolve<ILimitedConcurrencyLibraryScheduler>();
Episode.MediaEncoder = Resolve<IMediaEncoder>();
UserView.TVSeriesManager = Resolve<ITVSeriesManager>();
Video.RecordingsManager = Resolve<IRecordingsManager>();
}
/// <summary>

View File

@@ -0,0 +1,300 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Jellyfin.Extensions;
using MediaBrowser.Controller.Chapters;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.IO;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.Controller.Persistence;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.MediaInfo;
using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.Chapters;
/// <summary>
/// The chapter manager.
/// </summary>
public class ChapterManager : IChapterManager
{
private readonly IFileSystem _fileSystem;
private readonly ILogger<ChapterManager> _logger;
private readonly IMediaEncoder _encoder;
private readonly IChapterRepository _chapterRepository;
private readonly ILibraryManager _libraryManager;
private readonly IPathManager _pathManager;
/// <summary>
/// The first chapter ticks.
/// </summary>
private static readonly long _firstChapterTicks = TimeSpan.FromSeconds(15).Ticks;
/// <summary>
/// Initializes a new instance of the <see cref="ChapterManager"/> class.
/// </summary>
/// <param name="logger">The <see cref="ILogger{ChapterManager}"/>.</param>
/// <param name="fileSystem">The <see cref="IFileSystem"/>.</param>
/// <param name="encoder">The <see cref="IMediaEncoder"/>.</param>
/// <param name="chapterRepository">The <see cref="IChapterRepository"/>.</param>
/// <param name="libraryManager">The <see cref="ILibraryManager"/>.</param>
/// <param name="pathManager">The <see cref="IPathManager"/>.</param>
public ChapterManager(
ILogger<ChapterManager> logger,
IFileSystem fileSystem,
IMediaEncoder encoder,
IChapterRepository chapterRepository,
ILibraryManager libraryManager,
IPathManager pathManager)
{
_logger = logger;
_fileSystem = fileSystem;
_encoder = encoder;
_chapterRepository = chapterRepository;
_libraryManager = libraryManager;
_pathManager = pathManager;
}
/// <summary>
/// Determines whether [is eligible for chapter image extraction] [the specified video].
/// </summary>
/// <param name="video">The video.</param>
/// <param name="libraryOptions">The library options for the video.</param>
/// <returns><c>true</c> if [is eligible for chapter image extraction] [the specified video]; otherwise, <c>false</c>.</returns>
private bool IsEligibleForChapterImageExtraction(Video video, LibraryOptions libraryOptions)
{
if (video.IsPlaceHolder)
{
return false;
}
if (libraryOptions is null || !libraryOptions.EnableChapterImageExtraction)
{
return false;
}
if (video.IsShortcut)
{
return false;
}
if (!video.IsCompleteMedia)
{
return false;
}
// Can't extract images if there are no video streams
return video.DefaultVideoStreamIndex.HasValue;
}
private long GetAverageDurationBetweenChapters(IReadOnlyList<ChapterInfo> chapters)
{
if (chapters.Count < 2)
{
return 0;
}
long sum = 0;
for (int i = 1; i < chapters.Count; i++)
{
sum += chapters[i].StartPositionTicks - chapters[i - 1].StartPositionTicks;
}
return sum / chapters.Count;
}
/// <inheritdoc />
public async Task<bool> RefreshChapterImages(Video video, IDirectoryService directoryService, IReadOnlyList<ChapterInfo> chapters, bool extractImages, bool saveChapters, CancellationToken cancellationToken)
{
if (chapters.Count == 0)
{
return true;
}
var libraryOptions = _libraryManager.GetLibraryOptions(video);
if (!IsEligibleForChapterImageExtraction(video, libraryOptions))
{
extractImages = false;
}
var averageChapterDuration = GetAverageDurationBetweenChapters(chapters);
var threshold = TimeSpan.FromSeconds(1).Ticks;
if (averageChapterDuration < threshold)
{
_logger.LogInformation("Skipping chapter image extraction for {Video} as the average chapter duration {AverageDuration} was lower than the minimum threshold {Threshold}", video.Name, averageChapterDuration, threshold);
extractImages = false;
}
var success = true;
var changesMade = false;
var runtimeTicks = video.RunTimeTicks ?? 0;
var currentImages = GetSavedChapterImages(video, directoryService);
foreach (var chapter in chapters)
{
if (chapter.StartPositionTicks >= runtimeTicks)
{
_logger.LogInformation("Stopping chapter extraction for {0} because a chapter was found with a position greater than the runtime.", video.Name);
break;
}
var path = _pathManager.GetChapterImagePath(video, chapter.StartPositionTicks);
if (!currentImages.Contains(path, StringComparison.OrdinalIgnoreCase))
{
if (extractImages)
{
cancellationToken.ThrowIfCancellationRequested();
try
{
// Add some time for the first chapter to make sure we don't end up with a black image
var time = chapter.StartPositionTicks == 0 ? TimeSpan.FromTicks(Math.Min(_firstChapterTicks, video.RunTimeTicks ?? 0)) : TimeSpan.FromTicks(chapter.StartPositionTicks);
var inputPath = video.Path;
var directoryPath = Path.GetDirectoryName(path);
if (!string.IsNullOrEmpty(directoryPath))
{
Directory.CreateDirectory(directoryPath);
}
var container = video.Container;
var mediaSource = new MediaSourceInfo
{
VideoType = video.VideoType,
IsoType = video.IsoType,
Protocol = video.PathProtocol ?? MediaProtocol.File,
};
_logger.LogInformation("Extracting chapter image for {Name} at {Path}", video.Name, inputPath);
var tempFile = await _encoder.ExtractVideoImage(inputPath, container, mediaSource, video.GetDefaultVideoStream(), video.Video3DFormat, time, cancellationToken).ConfigureAwait(false);
File.Copy(tempFile, path, true);
try
{
_fileSystem.DeleteFile(tempFile);
}
catch (IOException ex)
{
_logger.LogError(ex, "Error deleting temporary chapter image encoding file {Path}", tempFile);
}
chapter.ImagePath = path;
chapter.ImageDateModified = _fileSystem.GetLastWriteTimeUtc(path);
changesMade = true;
}
catch (Exception ex)
{
_logger.LogError(ex, "Error extracting chapter images for {0}", string.Join(',', video.Path));
success = false;
break;
}
}
else if (!string.IsNullOrEmpty(chapter.ImagePath))
{
chapter.ImagePath = null;
changesMade = true;
}
}
else if (!string.Equals(path, chapter.ImagePath, StringComparison.OrdinalIgnoreCase))
{
chapter.ImagePath = path;
chapter.ImageDateModified = _fileSystem.GetLastWriteTimeUtc(path);
changesMade = true;
}
else if (libraryOptions?.EnableChapterImageExtraction != true)
{
// We have an image for the current chapter but the user has disabled chapter image extraction -> delete this chapter's image
chapter.ImagePath = null;
changesMade = true;
}
}
if (saveChapters && changesMade)
{
SaveChapters(video, chapters);
}
DeleteDeadImages(currentImages, chapters);
return success;
}
/// <inheritdoc />
public void SaveChapters(Video video, IReadOnlyList<ChapterInfo> 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 />
public ChapterInfo? GetChapter(Guid baseItemId, int index)
{
return _chapterRepository.GetChapter(baseItemId, index);
}
/// <inheritdoc />
public IReadOnlyList<ChapterInfo> GetChapters(Guid baseItemId)
{
return _chapterRepository.GetChapters(baseItemId);
}
/// <inheritdoc />
public async Task DeleteChapterDataAsync(Guid itemId, CancellationToken cancellationToken)
{
await _chapterRepository.DeleteChaptersAsync(itemId, cancellationToken).ConfigureAwait(false);
}
private IReadOnlyList<string> GetSavedChapterImages(Video video, IDirectoryService directoryService)
{
var path = _pathManager.GetChapterImageFolderPath(video);
if (!Directory.Exists(path))
{
return [];
}
try
{
return directoryService.GetFilePaths(path);
}
catch (IOException)
{
return [];
}
}
private void DeleteDeadImages(IEnumerable<string> images, IEnumerable<ChapterInfo> chapters)
{
var existingImages = chapters.Select(i => i.ImagePath).Where(i => !string.IsNullOrEmpty(i));
var deadImages = images
.Except(existingImages, StringComparer.OrdinalIgnoreCase)
.Where(i => BaseItem.SupportedImageExtensions.Contains(Path.GetExtension(i.AsSpan()), StringComparison.OrdinalIgnoreCase))
.ToList();
foreach (var image in deadImages)
{
_logger.LogDebug("Deleting dead chapter image {Path}", image);
try
{
_fileSystem.DeleteFile(image!);
}
catch (IOException ex)
{
_logger.LogError(ex, "Error deleting {Path}.", image);
}
}
}
}

View File

@@ -4,7 +4,7 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Jellyfin.Data.Entities;
using Jellyfin.Database.Implementations.Entities;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Controller.Collections;
using MediaBrowser.Controller.Entities;
@@ -95,7 +95,7 @@ namespace Emby.Server.Implementations.Collections
var libraryOptions = new LibraryOptions
{
PathInfos = new[] { new MediaPathInfo(path) },
PathInfos = [new MediaPathInfo(path)],
EnableRealtimeMonitor = false,
SaveLocalMetadata = true
};
@@ -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();
}
@@ -150,15 +152,15 @@ namespace Emby.Server.Implementations.Collections
try
{
Directory.CreateDirectory(path);
var info = Directory.CreateDirectory(path);
var collection = new BoxSet
{
Name = name,
Path = path,
IsLocked = options.IsLocked,
ProviderIds = options.ProviderIds,
DateCreated = DateTime.UtcNow
DateCreated = info.CreationTimeUtc,
DateModified = info.LastWriteTimeUtc
};
parentFolder.AddChild(collection);
@@ -204,7 +206,7 @@ namespace Emby.Server.Implementations.Collections
{
if (_libraryManager.GetItemById(collectionId) is not BoxSet collection)
{
throw new ArgumentException("No collection exists with the supplied Id");
throw new ArgumentException("No collection exists with the supplied collectionId " + collectionId);
}
List<BaseItem>? itemList = null;
@@ -218,7 +220,7 @@ namespace Emby.Server.Implementations.Collections
if (item is null)
{
throw new ArgumentException("No item exists with the supplied Id");
throw new ArgumentException("No item exists with the supplied Id " + id);
}
if (!currentLinkedChildrenIds.Contains(id))

View File

@@ -17,7 +17,6 @@ namespace Emby.Server.Implementations
{ DefaultRedirectKey, "web/" },
{ FfmpegProbeSizeKey, "1G" },
{ FfmpegAnalyzeDurationKey, "200M" },
{ PlaylistsAllowDuplicatesKey, bool.FalseString },
{ BindToUnixSocketKey, bool.FalseString },
{ SqliteCacheSizeKey, "20000" },
{ FfmpegSkipValidationKey, bool.FalseString },

View File

@@ -1,269 +0,0 @@
#nullable disable
#pragma warning disable CS1591
using System;
using System.Collections.Generic;
using System.Threading;
using Jellyfin.Extensions;
using Microsoft.Data.Sqlite;
using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.Data
{
public abstract class BaseSqliteRepository : IDisposable
{
private bool _disposed = false;
private SemaphoreSlim _writeLock = new SemaphoreSlim(1, 1);
private SqliteConnection _writeConnection;
/// <summary>
/// Initializes a new instance of the <see cref="BaseSqliteRepository"/> class.
/// </summary>
/// <param name="logger">The logger.</param>
protected BaseSqliteRepository(ILogger<BaseSqliteRepository> logger)
{
Logger = logger;
}
/// <summary>
/// Gets or sets the path to the DB file.
/// </summary>
protected string DbFilePath { get; set; }
/// <summary>
/// Gets the logger.
/// </summary>
/// <value>The logger.</value>
protected ILogger<BaseSqliteRepository> Logger { get; }
/// <summary>
/// Gets the cache size.
/// </summary>
/// <value>The cache size or null.</value>
protected virtual int? CacheSize => null;
/// <summary>
/// Gets the locking mode. <see href="https://www.sqlite.org/pragma.html#pragma_locking_mode" />.
/// </summary>
protected virtual string LockingMode => "NORMAL";
/// <summary>
/// Gets the journal mode. <see href="https://www.sqlite.org/pragma.html#pragma_journal_mode" />.
/// </summary>
/// <value>The journal mode.</value>
protected virtual string JournalMode => "WAL";
/// <summary>
/// Gets the journal size limit. <see href="https://www.sqlite.org/pragma.html#pragma_journal_size_limit" />.
/// The default (-1) is overridden to prevent unconstrained WAL size, as reported by users.
/// </summary>
/// <value>The journal size limit.</value>
protected virtual int? JournalSizeLimit => 134_217_728; // 128MiB
/// <summary>
/// Gets the page size.
/// </summary>
/// <value>The page size or null.</value>
protected virtual int? PageSize => null;
/// <summary>
/// Gets the temp store mode.
/// </summary>
/// <value>The temp store mode.</value>
/// <see cref="TempStoreMode"/>
protected virtual TempStoreMode TempStore => TempStoreMode.Memory;
/// <summary>
/// Gets the synchronous mode.
/// </summary>
/// <value>The synchronous mode or null.</value>
/// <see cref="SynchronousMode"/>
protected virtual SynchronousMode? Synchronous => SynchronousMode.Normal;
public virtual void Initialize()
{
// Configuration and pragmas can affect VACUUM so it needs to be last.
using (var connection = GetConnection())
{
connection.Execute("VACUUM");
}
}
protected ManagedConnection GetConnection(bool readOnly = false)
{
if (!readOnly)
{
_writeLock.Wait();
if (_writeConnection is not null)
{
return new ManagedConnection(_writeConnection, _writeLock);
}
var writeConnection = new SqliteConnection($"Filename={DbFilePath};Pooling=False");
writeConnection.Open();
if (CacheSize.HasValue)
{
writeConnection.Execute("PRAGMA cache_size=" + CacheSize.Value);
}
if (!string.IsNullOrWhiteSpace(LockingMode))
{
writeConnection.Execute("PRAGMA locking_mode=" + LockingMode);
}
if (!string.IsNullOrWhiteSpace(JournalMode))
{
writeConnection.Execute("PRAGMA journal_mode=" + JournalMode);
}
if (JournalSizeLimit.HasValue)
{
writeConnection.Execute("PRAGMA journal_size_limit=" + JournalSizeLimit.Value);
}
if (Synchronous.HasValue)
{
writeConnection.Execute("PRAGMA synchronous=" + (int)Synchronous.Value);
}
if (PageSize.HasValue)
{
writeConnection.Execute("PRAGMA page_size=" + PageSize.Value);
}
writeConnection.Execute("PRAGMA temp_store=" + (int)TempStore);
return new ManagedConnection(_writeConnection = writeConnection, _writeLock);
}
var connection = new SqliteConnection($"Filename={DbFilePath};Mode=ReadOnly");
connection.Open();
if (CacheSize.HasValue)
{
connection.Execute("PRAGMA cache_size=" + CacheSize.Value);
}
if (!string.IsNullOrWhiteSpace(LockingMode))
{
connection.Execute("PRAGMA locking_mode=" + LockingMode);
}
if (!string.IsNullOrWhiteSpace(JournalMode))
{
connection.Execute("PRAGMA journal_mode=" + JournalMode);
}
if (JournalSizeLimit.HasValue)
{
connection.Execute("PRAGMA journal_size_limit=" + JournalSizeLimit.Value);
}
if (Synchronous.HasValue)
{
connection.Execute("PRAGMA synchronous=" + (int)Synchronous.Value);
}
if (PageSize.HasValue)
{
connection.Execute("PRAGMA page_size=" + PageSize.Value);
}
connection.Execute("PRAGMA temp_store=" + (int)TempStore);
return new ManagedConnection(connection, null);
}
public SqliteCommand PrepareStatement(ManagedConnection connection, string sql)
{
var command = connection.CreateCommand();
command.CommandText = sql;
return command;
}
protected bool TableExists(ManagedConnection connection, string name)
{
using var statement = PrepareStatement(connection, "select DISTINCT tbl_name from sqlite_master");
foreach (var row in statement.ExecuteQuery())
{
if (string.Equals(name, row.GetString(0), StringComparison.OrdinalIgnoreCase))
{
return true;
}
}
return false;
}
protected List<string> GetColumnNames(ManagedConnection connection, string table)
{
var columnNames = new List<string>();
foreach (var row in connection.Query("PRAGMA table_info(" + table + ")"))
{
if (row.TryGetString(1, out var columnName))
{
columnNames.Add(columnName);
}
}
return columnNames;
}
protected void AddColumn(ManagedConnection connection, string table, string columnName, string type, List<string> existingColumnNames)
{
if (existingColumnNames.Contains(columnName, StringComparison.OrdinalIgnoreCase))
{
return;
}
connection.Execute("alter table " + table + " add column " + columnName + " " + type + " NULL");
}
protected void CheckDisposed()
{
ObjectDisposedException.ThrowIf(_disposed, this);
}
/// <inheritdoc />
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
/// <summary>
/// Releases unmanaged and - optionally - managed resources.
/// </summary>
/// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
protected virtual void Dispose(bool dispose)
{
if (_disposed)
{
return;
}
if (dispose)
{
_writeLock.Wait();
try
{
_writeConnection.Dispose();
}
finally
{
_writeLock.Release();
}
_writeLock.Dispose();
}
_writeConnection = null;
_writeLock = null;
_disposed = true;
}
}
}

View File

@@ -1,66 +1,119 @@
#pragma warning disable CS1591
using System;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Jellyfin.Database.Implementations;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.IO;
using MediaBrowser.Controller.Library;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.Data
namespace Emby.Server.Implementations.Data;
public class CleanDatabaseScheduledTask : ILibraryPostScanTask
{
public class CleanDatabaseScheduledTask : ILibraryPostScanTask
private readonly ILibraryManager _libraryManager;
private readonly ILogger<CleanDatabaseScheduledTask> _logger;
private readonly IDbContextFactory<JellyfinDbContext> _dbProvider;
private readonly IPathManager _pathManager;
public CleanDatabaseScheduledTask(
ILibraryManager libraryManager,
ILogger<CleanDatabaseScheduledTask> logger,
IDbContextFactory<JellyfinDbContext> dbProvider,
IPathManager pathManager)
{
private readonly ILibraryManager _libraryManager;
private readonly ILogger<CleanDatabaseScheduledTask> _logger;
_libraryManager = libraryManager;
_logger = logger;
_dbProvider = dbProvider;
_pathManager = pathManager;
}
public CleanDatabaseScheduledTask(ILibraryManager libraryManager, ILogger<CleanDatabaseScheduledTask> logger)
{
_libraryManager = libraryManager;
_logger = logger;
}
public async Task Run(IProgress<double> progress, CancellationToken cancellationToken)
{
await CleanDeadItems(cancellationToken, progress).ConfigureAwait(false);
}
public Task Run(IProgress<double> progress, CancellationToken cancellationToken)
private async Task CleanDeadItems(CancellationToken cancellationToken, IProgress<double> progress)
{
var itemIds = _libraryManager.GetItemIds(new InternalItemsQuery
{
CleanDeadItems(cancellationToken, progress);
return Task.CompletedTask;
}
HasDeadParentId = true
});
private void CleanDeadItems(CancellationToken cancellationToken, IProgress<double> progress)
var numComplete = 0;
var numItems = itemIds.Count + 1;
_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)
{
var itemIds = _libraryManager.GetItemIds(new InternalItemsQuery
cancellationToken.ThrowIfCancellationRequested();
var item = _libraryManager.GetItemById(itemId);
if (item is not null)
{
HasDeadParentId = true
});
_logger.LogInformation("Cleaning item {Item} type: {Type} path: {Path}", item.Name, item.GetType().Name, item.Path ?? string.Empty);
var numComplete = 0;
var numItems = itemIds.Count;
_logger.LogDebug("Cleaning {0} items with dead parent links", numItems);
foreach (var itemId in itemIds)
{
cancellationToken.ThrowIfCancellationRequested();
var item = _libraryManager.GetItemById(itemId);
if (item is not null)
foreach (var mediaSource in item.GetMediaSources(false))
{
_logger.LogInformation("Cleaning item {0} type: {1} path: {2}", item.Name, item.GetType().Name, item.Path ?? string.Empty);
_libraryManager.DeleteItem(item, new DeleteOptions
// Delete extracted data
var mediaSourceItem = _libraryManager.GetItemById(mediaSource.Id);
if (mediaSourceItem is null)
{
DeleteFileLocation = false
});
continue;
}
var extractedDataFolders = _pathManager.GetExtractedDataPaths(mediaSourceItem);
foreach (var folder in extractedDataFolders)
{
if (Directory.Exists(folder))
{
try
{
Directory.Delete(folder, true);
}
catch (Exception e)
{
_logger.LogWarning("Failed to remove {Folder}: {Exception}", folder, e.Message);
}
}
}
}
numComplete++;
double percent = numComplete;
percent /= numItems;
progress.Report(percent * 100);
// Delete item
_libraryManager.DeleteItem(item, new DeleteOptions
{
DeleteFileLocation = false
});
}
progress.Report(100);
numComplete++;
double percent = numComplete;
percent /= numItems;
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))
{
var transaction = await context.Database.BeginTransactionAsync(cancellationToken).ConfigureAwait(false);
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);
}
}
progress.Report(100);
}
}

View File

@@ -0,0 +1,64 @@
using System.Collections.Frozen;
using System.Collections.Generic;
using System.Threading.Channels;
using Emby.Server.Implementations.Playlists;
using Jellyfin.Data.Enums;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Entities.Movies;
using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.LiveTv;
using MediaBrowser.Controller.Persistence;
using MediaBrowser.Controller.Playlists;
namespace Emby.Server.Implementations.Data;
/// <inheritdoc />
public class ItemTypeLookup : IItemTypeLookup
{
/// <inheritdoc />
public IReadOnlyList<string> MusicGenreTypes { get; } = [
typeof(Audio).FullName!,
typeof(MusicVideo).FullName!,
typeof(MusicAlbum).FullName!,
typeof(MusicArtist).FullName!,
];
/// <inheritdoc />
public IReadOnlyDictionary<BaseItemKind, string> BaseItemKindNames { get; } = new Dictionary<BaseItemKind, string>()
{
{ BaseItemKind.AggregateFolder, typeof(AggregateFolder).FullName! },
{ BaseItemKind.Audio, typeof(Audio).FullName! },
{ BaseItemKind.AudioBook, typeof(AudioBook).FullName! },
{ BaseItemKind.BasePluginFolder, typeof(BasePluginFolder).FullName! },
{ BaseItemKind.Book, typeof(Book).FullName! },
{ BaseItemKind.BoxSet, typeof(BoxSet).FullName! },
{ BaseItemKind.Channel, typeof(Channel).FullName! },
{ BaseItemKind.CollectionFolder, typeof(CollectionFolder).FullName! },
{ BaseItemKind.Episode, typeof(Episode).FullName! },
{ BaseItemKind.Folder, typeof(Folder).FullName! },
{ BaseItemKind.Genre, typeof(Genre).FullName! },
{ BaseItemKind.Movie, typeof(Movie).FullName! },
{ BaseItemKind.LiveTvChannel, typeof(LiveTvChannel).FullName! },
{ BaseItemKind.LiveTvProgram, typeof(LiveTvProgram).FullName! },
{ BaseItemKind.MusicAlbum, typeof(MusicAlbum).FullName! },
{ BaseItemKind.MusicArtist, typeof(MusicArtist).FullName! },
{ BaseItemKind.MusicGenre, typeof(MusicGenre).FullName! },
{ BaseItemKind.MusicVideo, typeof(MusicVideo).FullName! },
{ BaseItemKind.Person, typeof(Person).FullName! },
{ BaseItemKind.Photo, typeof(Photo).FullName! },
{ BaseItemKind.PhotoAlbum, typeof(PhotoAlbum).FullName! },
{ BaseItemKind.Playlist, typeof(Playlist).FullName! },
{ BaseItemKind.PlaylistsFolder, typeof(PlaylistsFolder).FullName! },
{ BaseItemKind.Season, typeof(Season).FullName! },
{ BaseItemKind.Series, typeof(Series).FullName! },
{ BaseItemKind.Studio, typeof(Studio).FullName! },
{ BaseItemKind.Trailer, typeof(Trailer).FullName! },
{ BaseItemKind.TvChannel, typeof(LiveTvChannel).FullName! },
{ BaseItemKind.TvProgram, typeof(LiveTvProgram).FullName! },
{ BaseItemKind.UserRootFolder, typeof(UserRootFolder).FullName! },
{ BaseItemKind.UserView, typeof(UserView).FullName! },
{ BaseItemKind.Video, typeof(Video).FullName! },
{ BaseItemKind.Year, typeof(Year).FullName! }
}.ToFrozenDictionary();
}

View File

@@ -1,62 +0,0 @@
#pragma warning disable CS1591
using System;
using System.Collections.Generic;
using System.Threading;
using Microsoft.Data.Sqlite;
namespace Emby.Server.Implementations.Data;
public sealed class ManagedConnection : IDisposable
{
private readonly SemaphoreSlim? _writeLock;
private SqliteConnection _db;
private bool _disposed = false;
public ManagedConnection(SqliteConnection db, SemaphoreSlim? writeLock)
{
_db = db;
_writeLock = writeLock;
}
public SqliteTransaction BeginTransaction()
=> _db.BeginTransaction();
public SqliteCommand CreateCommand()
=> _db.CreateCommand();
public void Execute(string commandText)
=> _db.Execute(commandText);
public SqliteCommand PrepareStatement(string sql)
=> _db.PrepareStatement(sql);
public IEnumerable<SqliteDataReader> Query(string commandText)
=> _db.Query(commandText);
public void Dispose()
{
if (_disposed)
{
return;
}
if (_writeLock is null)
{
// Read connections are managed with an internal pool
_db.Dispose();
}
else
{
// Write lock is managed by BaseSqliteRepository
// Don't dispose here
_writeLock.Release();
}
_db = null!;
_disposed = true;
}
}

View File

@@ -127,8 +127,16 @@ namespace Emby.Server.Implementations.Data
return false;
}
result = reader.GetGuid(index);
return true;
try
{
result = reader.GetGuid(index);
return true;
}
catch
{
result = Guid.Empty;
return false;
}
}
public static bool TryGetString(this SqliteDataReader reader, int index, out string result)

File diff suppressed because it is too large Load Diff

View File

@@ -1,369 +0,0 @@
#nullable disable
#pragma warning disable CS1591
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using Jellyfin.Data.Entities;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Persistence;
using Microsoft.Data.Sqlite;
using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.Data
{
public class SqliteUserDataRepository : BaseSqliteRepository, IUserDataRepository
{
private readonly IUserManager _userManager;
public SqliteUserDataRepository(
ILogger<SqliteUserDataRepository> logger,
IServerConfigurationManager config,
IUserManager userManager)
: base(logger)
{
_userManager = userManager;
DbFilePath = Path.Combine(config.ApplicationPaths.DataPath, "library.db");
}
/// <summary>
/// Opens the connection to the database.
/// </summary>
public override void Initialize()
{
base.Initialize();
using (var connection = GetConnection())
{
var userDatasTableExists = TableExists(connection, "UserDatas");
var userDataTableExists = TableExists(connection, "userdata");
var users = userDatasTableExists ? null : _userManager.Users;
using var transaction = connection.BeginTransaction();
connection.Execute(string.Join(
';',
"create table if not exists UserDatas (key nvarchar not null, userId INT not null, rating float null, played bit not null, playCount int not null, isFavorite bit not null, playbackPositionTicks bigint not null, lastPlayedDate datetime null, AudioStreamIndex INT, SubtitleStreamIndex INT)",
"drop index if exists idx_userdata",
"drop index if exists idx_userdata1",
"drop index if exists idx_userdata2",
"drop index if exists userdataindex1",
"drop index if exists userdataindex",
"drop index if exists userdataindex3",
"drop index if exists userdataindex4",
"create unique index if not exists UserDatasIndex1 on UserDatas (key, userId)",
"create index if not exists UserDatasIndex2 on UserDatas (key, userId, played)",
"create index if not exists UserDatasIndex3 on UserDatas (key, userId, playbackPositionTicks)",
"create index if not exists UserDatasIndex4 on UserDatas (key, userId, isFavorite)",
"create index if not exists UserDatasIndex5 on UserDatas (key, userId, lastPlayedDate)"));
if (!userDataTableExists)
{
transaction.Commit();
return;
}
var existingColumnNames = GetColumnNames(connection, "userdata");
AddColumn(connection, "userdata", "InternalUserId", "int", existingColumnNames);
AddColumn(connection, "userdata", "AudioStreamIndex", "int", existingColumnNames);
AddColumn(connection, "userdata", "SubtitleStreamIndex", "int", existingColumnNames);
if (userDatasTableExists)
{
return;
}
ImportUserIds(connection, users);
connection.Execute("INSERT INTO UserDatas (key, userId, rating, played, playCount, isFavorite, playbackPositionTicks, lastPlayedDate, AudioStreamIndex, SubtitleStreamIndex) SELECT key, InternalUserId, rating, played, playCount, isFavorite, playbackPositionTicks, lastPlayedDate, AudioStreamIndex, SubtitleStreamIndex from userdata where InternalUserId not null");
transaction.Commit();
}
}
private void ImportUserIds(ManagedConnection db, IEnumerable<User> users)
{
var userIdsWithUserData = GetAllUserIdsWithUserData(db);
using (var statement = db.PrepareStatement("update userdata set InternalUserId=@InternalUserId where UserId=@UserId"))
{
foreach (var user in users)
{
if (!userIdsWithUserData.Contains(user.Id))
{
continue;
}
statement.TryBind("@UserId", user.Id);
statement.TryBind("@InternalUserId", user.InternalId);
statement.ExecuteNonQuery();
}
}
}
private List<Guid> GetAllUserIdsWithUserData(ManagedConnection db)
{
var list = new List<Guid>();
using (var statement = PrepareStatement(db, "select DISTINCT UserId from UserData where UserId not null"))
{
foreach (var row in statement.ExecuteQuery())
{
try
{
list.Add(row.GetGuid(0));
}
catch (Exception ex)
{
Logger.LogError(ex, "Error while getting user");
}
}
}
return list;
}
/// <inheritdoc />
public void SaveUserData(long userId, string key, UserItemData userData, CancellationToken cancellationToken)
{
ArgumentNullException.ThrowIfNull(userData);
if (userId <= 0)
{
throw new ArgumentNullException(nameof(userId));
}
ArgumentException.ThrowIfNullOrEmpty(key);
PersistUserData(userId, key, userData, cancellationToken);
}
/// <inheritdoc />
public void SaveAllUserData(long userId, UserItemData[] userData, CancellationToken cancellationToken)
{
ArgumentNullException.ThrowIfNull(userData);
if (userId <= 0)
{
throw new ArgumentNullException(nameof(userId));
}
PersistAllUserData(userId, userData, cancellationToken);
}
/// <summary>
/// Persists the user data.
/// </summary>
/// <param name="internalUserId">The user id.</param>
/// <param name="key">The key.</param>
/// <param name="userData">The user data.</param>
/// <param name="cancellationToken">The cancellation token.</param>
public void PersistUserData(long internalUserId, string key, UserItemData userData, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
using (var connection = GetConnection())
using (var transaction = connection.BeginTransaction())
{
SaveUserData(connection, internalUserId, key, userData);
transaction.Commit();
}
}
private static void SaveUserData(ManagedConnection db, long internalUserId, string key, UserItemData userData)
{
using (var statement = db.PrepareStatement("replace into UserDatas (key, userId, rating,played,playCount,isFavorite,playbackPositionTicks,lastPlayedDate,AudioStreamIndex,SubtitleStreamIndex) values (@key, @userId, @rating,@played,@playCount,@isFavorite,@playbackPositionTicks,@lastPlayedDate,@AudioStreamIndex,@SubtitleStreamIndex)"))
{
statement.TryBind("@userId", internalUserId);
statement.TryBind("@key", key);
if (userData.Rating.HasValue)
{
statement.TryBind("@rating", userData.Rating.Value);
}
else
{
statement.TryBindNull("@rating");
}
statement.TryBind("@played", userData.Played);
statement.TryBind("@playCount", userData.PlayCount);
statement.TryBind("@isFavorite", userData.IsFavorite);
statement.TryBind("@playbackPositionTicks", userData.PlaybackPositionTicks);
if (userData.LastPlayedDate.HasValue)
{
statement.TryBind("@lastPlayedDate", userData.LastPlayedDate.Value.ToDateTimeParamValue());
}
else
{
statement.TryBindNull("@lastPlayedDate");
}
if (userData.AudioStreamIndex.HasValue)
{
statement.TryBind("@AudioStreamIndex", userData.AudioStreamIndex.Value);
}
else
{
statement.TryBindNull("@AudioStreamIndex");
}
if (userData.SubtitleStreamIndex.HasValue)
{
statement.TryBind("@SubtitleStreamIndex", userData.SubtitleStreamIndex.Value);
}
else
{
statement.TryBindNull("@SubtitleStreamIndex");
}
statement.ExecuteNonQuery();
}
}
/// <summary>
/// Persist all user data for the specified user.
/// </summary>
private void PersistAllUserData(long internalUserId, UserItemData[] userDataList, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
using (var connection = GetConnection())
using (var transaction = connection.BeginTransaction())
{
foreach (var userItemData in userDataList)
{
SaveUserData(connection, internalUserId, userItemData.Key, userItemData);
}
transaction.Commit();
}
}
/// <summary>
/// Gets the user data.
/// </summary>
/// <param name="userId">The user id.</param>
/// <param name="key">The key.</param>
/// <returns>Task{UserItemData}.</returns>
/// <exception cref="ArgumentNullException">
/// userId
/// or
/// key.
/// </exception>
public UserItemData GetUserData(long userId, string key)
{
if (userId <= 0)
{
throw new ArgumentNullException(nameof(userId));
}
ArgumentException.ThrowIfNullOrEmpty(key);
using (var connection = GetConnection(true))
{
using (var statement = connection.PrepareStatement("select key,userid,rating,played,playCount,isFavorite,playbackPositionTicks,lastPlayedDate,AudioStreamIndex,SubtitleStreamIndex from UserDatas where key =@Key and userId=@UserId"))
{
statement.TryBind("@UserId", userId);
statement.TryBind("@Key", key);
foreach (var row in statement.ExecuteQuery())
{
return ReadRow(row);
}
}
return null;
}
}
public UserItemData GetUserData(long userId, List<string> keys)
{
ArgumentNullException.ThrowIfNull(keys);
if (keys.Count == 0)
{
return null;
}
return GetUserData(userId, keys[0]);
}
/// <summary>
/// Return all user-data associated with the given user.
/// </summary>
/// <param name="userId">The internal user id.</param>
/// <returns>The list of user item data.</returns>
public List<UserItemData> GetAllUserData(long userId)
{
if (userId <= 0)
{
throw new ArgumentNullException(nameof(userId));
}
var list = new List<UserItemData>();
using (var connection = GetConnection())
{
using (var statement = connection.PrepareStatement("select key,userid,rating,played,playCount,isFavorite,playbackPositionTicks,lastPlayedDate,AudioStreamIndex,SubtitleStreamIndex from UserDatas where userId=@UserId"))
{
statement.TryBind("@UserId", userId);
foreach (var row in statement.ExecuteQuery())
{
list.Add(ReadRow(row));
}
}
}
return list;
}
/// <summary>
/// Read a row from the specified reader into the provided userData object.
/// </summary>
/// <param name="reader">The list of result set values.</param>
/// <returns>The user item data.</returns>
private UserItemData ReadRow(SqliteDataReader reader)
{
var userData = new UserItemData
{
Key = reader.GetString(0)
};
if (reader.TryGetDouble(2, out var rating))
{
userData.Rating = rating;
}
userData.Played = reader.GetBoolean(3);
userData.PlayCount = reader.GetInt32(4);
userData.IsFavorite = reader.GetBoolean(5);
userData.PlaybackPositionTicks = reader.GetInt64(6);
if (reader.TryReadDateTime(7, out var lastPlayedDate))
{
userData.LastPlayedDate = lastPlayedDate;
}
if (reader.TryGetInt32(8, out var audioStreamIndex))
{
userData.AudioStreamIndex = audioStreamIndex;
}
if (reader.TryGetInt32(9, out var subtitleStreamIndex))
{
userData.SubtitleStreamIndex = subtitleStreamIndex;
}
return userData;
}
}
}

View File

@@ -1,30 +0,0 @@
namespace Emby.Server.Implementations.Data;
/// <summary>
/// The disk synchronization mode, controls how aggressively SQLite will write data
/// all the way out to physical storage.
/// </summary>
public enum SynchronousMode
{
/// <summary>
/// SQLite continues without syncing as soon as it has handed data off to the operating system.
/// </summary>
Off = 0,
/// <summary>
/// SQLite database engine will still sync at the most critical moments.
/// </summary>
Normal = 1,
/// <summary>
/// SQLite database engine will use the xSync method of the VFS
/// to ensure that all content is safely written to the disk surface prior to continuing.
/// </summary>
Full = 2,
/// <summary>
/// EXTRA synchronous is like FULL with the addition that the directory containing a rollback journal
/// is synced after that journal is unlinked to commit a transaction in DELETE mode.
/// </summary>
Extra = 3
}

View File

@@ -1,23 +0,0 @@
namespace Emby.Server.Implementations.Data;
/// <summary>
/// Storage mode used by temporary database files.
/// </summary>
public enum TempStoreMode
{
/// <summary>
/// The compile-time C preprocessor macro SQLITE_TEMP_STORE
/// is used to determine where temporary tables and indices are stored.
/// </summary>
Default = 0,
/// <summary>
/// Temporary tables and indices are stored in a file.
/// </summary>
File = 1,
/// <summary>
/// Temporary tables and indices are kept in as if they were pure in-memory databases memory.
/// </summary>
Memory = 2
}

View File

@@ -4,6 +4,7 @@ using System;
using System.Globalization;
using System.IO;
using System.Text;
using System.Threading;
using MediaBrowser.Common.Configuration;
using Microsoft.Extensions.Logging;
@@ -13,7 +14,7 @@ namespace Emby.Server.Implementations.Devices
{
private readonly IApplicationPaths _appPaths;
private readonly ILogger<DeviceId> _logger;
private readonly object _syncLock = new object();
private readonly Lock _syncLock = new();
private string? _id;

View File

@@ -1,22 +1,23 @@
#pragma warning disable CS1591
using System;
using System.Collections.Frozen;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using Jellyfin.Data.Entities;
using Jellyfin.Data.Enums;
using Jellyfin.Database.Implementations.Entities;
using Jellyfin.Extensions;
using MediaBrowser.Common;
using MediaBrowser.Controller.Channels;
using MediaBrowser.Controller.Chapters;
using MediaBrowser.Controller.Drawing;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.LiveTv;
using MediaBrowser.Controller.Persistence;
using MediaBrowser.Controller.Playlists;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Controller.Trickplay;
@@ -37,10 +38,80 @@ namespace Emby.Server.Implementations.Dto
{
public class DtoService : IDtoService
{
private static readonly FrozenDictionary<BaseItemKind, BaseItemKind[]> _relatedItemKinds = new Dictionary<BaseItemKind, BaseItemKind[]>
{
{
BaseItemKind.Genre, [
BaseItemKind.Audio,
BaseItemKind.Episode,
BaseItemKind.Movie,
BaseItemKind.LiveTvProgram,
BaseItemKind.MusicAlbum,
BaseItemKind.MusicArtist,
BaseItemKind.MusicVideo,
BaseItemKind.Series,
BaseItemKind.Trailer
]
},
{
BaseItemKind.MusicArtist, [
BaseItemKind.Audio,
BaseItemKind.MusicAlbum,
BaseItemKind.MusicVideo
]
},
{
BaseItemKind.MusicGenre, [
BaseItemKind.Audio,
BaseItemKind.MusicAlbum,
BaseItemKind.MusicArtist,
BaseItemKind.MusicVideo
]
},
{
BaseItemKind.Person, [
BaseItemKind.Audio,
BaseItemKind.Episode,
BaseItemKind.Movie,
BaseItemKind.LiveTvProgram,
BaseItemKind.MusicAlbum,
BaseItemKind.MusicArtist,
BaseItemKind.MusicVideo,
BaseItemKind.Series,
BaseItemKind.Trailer
]
},
{
BaseItemKind.Studio, [
BaseItemKind.Audio,
BaseItemKind.Episode,
BaseItemKind.Movie,
BaseItemKind.LiveTvProgram,
BaseItemKind.MusicAlbum,
BaseItemKind.MusicArtist,
BaseItemKind.MusicVideo,
BaseItemKind.Series,
BaseItemKind.Trailer
]
},
{
BaseItemKind.Year, [
BaseItemKind.Audio,
BaseItemKind.Episode,
BaseItemKind.Movie,
BaseItemKind.LiveTvProgram,
BaseItemKind.MusicAlbum,
BaseItemKind.MusicArtist,
BaseItemKind.MusicVideo,
BaseItemKind.Series,
BaseItemKind.Trailer
]
}
}.ToFrozenDictionary();
private readonly ILogger<DtoService> _logger;
private readonly ILibraryManager _libraryManager;
private readonly IUserDataManager _userDataRepository;
private readonly IItemRepository _itemRepo;
private readonly IImageProcessor _imageProcessor;
private readonly IProviderManager _providerManager;
@@ -51,24 +122,24 @@ namespace Emby.Server.Implementations.Dto
private readonly Lazy<ILiveTvManager> _livetvManagerFactory;
private readonly ITrickplayManager _trickplayManager;
private readonly IChapterManager _chapterManager;
public DtoService(
ILogger<DtoService> logger,
ILibraryManager libraryManager,
IUserDataManager userDataRepository,
IItemRepository itemRepo,
IImageProcessor imageProcessor,
IProviderManager providerManager,
IRecordingsManager recordingsManager,
IApplicationHost appHost,
IMediaSourceManager mediaSourceManager,
Lazy<ILiveTvManager> livetvManagerFactory,
ITrickplayManager trickplayManager)
ITrickplayManager trickplayManager,
IChapterManager chapterManager)
{
_logger = logger;
_libraryManager = libraryManager;
_userDataRepository = userDataRepository;
_itemRepo = itemRepo;
_imageProcessor = imageProcessor;
_providerManager = providerManager;
_recordingsManager = recordingsManager;
@@ -76,6 +147,7 @@ namespace Emby.Server.Implementations.Dto
_mediaSourceManager = mediaSourceManager;
_livetvManagerFactory = livetvManagerFactory;
_trickplayManager = trickplayManager;
_chapterManager = chapterManager;
}
private ILiveTvManager LivetvManager => _livetvManagerFactory.Value;
@@ -95,28 +167,16 @@ namespace Emby.Server.Implementations.Dto
if (item is LiveTvChannel tvChannel)
{
(channelTuples ??= new()).Add((dto, tvChannel));
(channelTuples ??= []).Add((dto, tvChannel));
}
else if (item is LiveTvProgram)
{
(programTuples ??= new()).Add((item, dto));
(programTuples ??= []).Add((item, dto));
}
if (item is IItemByName byName)
if (options.ContainsField(ItemFields.ItemCounts))
{
if (options.ContainsField(ItemFields.ItemCounts))
{
var libraryItems = byName.GetTaggedItems(new InternalItemsQuery(user)
{
Recursive = true,
DtoOptions = new DtoOptions(false)
{
EnableImages = false
}
});
SetItemByNameInfo(item, dto, libraryItems);
}
SetItemByNameInfo(dto, user);
}
returnItems[index] = dto;
@@ -147,34 +207,14 @@ namespace Emby.Server.Implementations.Dto
LivetvManager.AddInfoToProgramDto(new[] { (item, dto) }, options.Fields, user).GetAwaiter().GetResult();
}
if (item is IItemByName itemByName
&& options.ContainsField(ItemFields.ItemCounts))
if (options.ContainsField(ItemFields.ItemCounts))
{
SetItemByNameInfo(
item,
dto,
GetTaggedItems(
itemByName,
user,
new DtoOptions(false)
{
EnableImages = false
}));
SetItemByNameInfo(dto, user);
}
return dto;
}
private static IList<BaseItem> GetTaggedItems(IItemByName byName, User? user, DtoOptions options)
{
return byName.GetTaggedItems(
new InternalItemsQuery(user)
{
Recursive = true,
DtoOptions = options
});
}
private BaseItemDto GetBaseItemDtoInternal(BaseItem item, DtoOptions options, User? user = null, BaseItem? owner = null)
{
var dto = new BaseItemDto
@@ -315,11 +355,15 @@ namespace Emby.Server.Implementations.Dto
}
/// <inheritdoc />
/// TODO refactor this to use the new SetItemByNameInfo.
/// Some callers already have the counts extracted so no reason to retrieve them again.
public BaseItemDto GetItemByNameDto(BaseItem item, DtoOptions options, List<BaseItem>? taggedItems, User? user = null)
{
var dto = GetBaseItemDtoInternal(item, options, user);
if (taggedItems is not null && options.ContainsField(ItemFields.ItemCounts))
if (options.ContainsField(ItemFields.ItemCounts)
&& taggedItems is not null
&& taggedItems.Count != 0)
{
SetItemByNameInfo(item, dto, taggedItems);
}
@@ -327,7 +371,58 @@ namespace Emby.Server.Implementations.Dto
return dto;
}
private static void SetItemByNameInfo(BaseItem item, BaseItemDto dto, IList<BaseItem> taggedItems)
private void SetItemByNameInfo(BaseItemDto dto, User? user)
{
if (!_relatedItemKinds.TryGetValue(dto.Type, out var relatedItemKinds))
{
return;
}
var query = new InternalItemsQuery(user)
{
Recursive = true,
DtoOptions = new DtoOptions(false) { EnableImages = false },
IncludeItemTypes = relatedItemKinds
};
switch (dto.Type)
{
case BaseItemKind.Genre:
case BaseItemKind.MusicGenre:
query.GenreIds = [dto.Id];
break;
case BaseItemKind.MusicArtist:
query.ArtistIds = [dto.Id];
break;
case BaseItemKind.Person:
query.PersonIds = [dto.Id];
break;
case BaseItemKind.Studio:
query.StudioIds = [dto.Id];
break;
case BaseItemKind.Year
when int.TryParse(dto.Name, NumberStyles.Integer, CultureInfo.InvariantCulture, out var year):
query.Years = [year];
break;
default:
return;
}
var counts = _libraryManager.GetItemCounts(query);
dto.AlbumCount = counts.AlbumCount;
dto.ArtistCount = counts.ArtistCount;
dto.EpisodeCount = counts.EpisodeCount;
dto.MovieCount = counts.MovieCount;
dto.MusicVideoCount = counts.MusicVideoCount;
dto.ProgramCount = counts.ProgramCount;
dto.SeriesCount = counts.SeriesCount;
dto.SongCount = counts.SongCount;
dto.TrailerCount = counts.TrailerCount;
dto.ChildCount = counts.TotalItemCount();
}
private static void SetItemByNameInfo(BaseItem item, BaseItemDto dto, IReadOnlyList<BaseItem> taggedItems)
{
if (item is MusicArtist)
{
@@ -586,12 +681,12 @@ namespace Emby.Server.Implementations.Dto
if (dto.ImageBlurHashes is not null)
{
// Only add BlurHash for the person's image.
baseItemPerson.ImageBlurHashes = new Dictionary<ImageType, Dictionary<string, string>>();
baseItemPerson.ImageBlurHashes = [];
foreach (var (imageType, blurHash) in dto.ImageBlurHashes)
{
if (blurHash is not null)
{
baseItemPerson.ImageBlurHashes[imageType] = new Dictionary<string, string>();
baseItemPerson.ImageBlurHashes[imageType] = [];
foreach (var (imageId, blurHashValue) in blurHash)
{
if (string.Equals(baseItemPerson.PrimaryImageTag, imageId, StringComparison.OrdinalIgnoreCase))
@@ -670,11 +765,11 @@ namespace Emby.Server.Implementations.Dto
if (!string.IsNullOrEmpty(image.BlurHash))
{
dto.ImageBlurHashes ??= new Dictionary<ImageType, Dictionary<string, string>>();
dto.ImageBlurHashes ??= [];
if (!dto.ImageBlurHashes.TryGetValue(image.Type, out var value))
{
value = new Dictionary<string, string>();
value = [];
dto.ImageBlurHashes[image.Type] = value;
}
@@ -705,7 +800,7 @@ namespace Emby.Server.Implementations.Dto
if (hashes.Count > 0)
{
dto.ImageBlurHashes ??= new Dictionary<ImageType, Dictionary<string, string>>();
dto.ImageBlurHashes ??= [];
dto.ImageBlurHashes[imageType] = hashes;
}
@@ -752,7 +847,7 @@ namespace Emby.Server.Implementations.Dto
dto.AspectRatio = hasAspectRatio.AspectRatio;
}
dto.ImageBlurHashes = new Dictionary<ImageType, Dictionary<string, string>>();
dto.ImageBlurHashes = [];
var backdropLimit = options.GetImageLimit(ImageType.Backdrop);
if (backdropLimit > 0)
@@ -768,7 +863,7 @@ namespace Emby.Server.Implementations.Dto
if (options.EnableImages)
{
dto.ImageTags = new Dictionary<ImageType, string>();
dto.ImageTags = [];
// Prevent implicitly captured closure
var currentItem = item;
@@ -956,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();
}
@@ -1060,12 +1140,17 @@ namespace Emby.Server.Implementations.Dto
if (options.ContainsField(ItemFields.Chapters))
{
dto.Chapters = _itemRepo.GetChapters(item);
dto.Chapters = _chapterManager.GetChapters(item.Id).ToList();
}
if (options.ContainsField(ItemFields.Trickplay))
{
dto.Trickplay = _trickplayManager.GetTrickplayManifest(item).GetAwaiter().GetResult();
var trickplay = _trickplayManager.GetTrickplayManifest(item).GetAwaiter().GetResult();
dto.Trickplay = trickplay.ToDictionary(
mediaStream => mediaStream.Key,
mediaStream => mediaStream.Value.ToDictionary(
width => width.Key,
width => new TrickplayInfoDto(width.Value)));
}
dto.ExtraType = video.ExtraType;

View File

@@ -18,9 +18,11 @@
<ProjectReference Include="..\Emby.Photos\Emby.Photos.csproj" />
<ProjectReference Include="..\src\Jellyfin.Drawing\Jellyfin.Drawing.csproj" />
<ProjectReference Include="..\MediaBrowser.MediaEncoding\MediaBrowser.MediaEncoding.csproj" />
<ProjectReference Include="..\src\Jellyfin.Database\Jellyfin.Database.Implementations\Jellyfin.Database.Implementations.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="BitFaster.Caching" />
<PackageReference Include="DiscUtils.Udf" />
<PackageReference Include="Microsoft.Data.Sqlite" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" />
@@ -37,7 +39,7 @@
</ItemGroup>
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net9.0</TargetFramework>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
</PropertyGroup>
@@ -62,10 +64,14 @@
<PackageReference Include="SmartAnalyzers.MultithreadingAnalyzer" PrivateAssets="All" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Ignore" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Localization\iso6392.txt" />
<EmbeddedResource Include="Localization\countries.json" />
<EmbeddedResource Include="Localization\Core\*.json" />
<EmbeddedResource Include="Localization\Ratings\*.csv" />
<EmbeddedResource Include="Localization\Ratings\*.json" />
</ItemGroup>
</Project>

View File

@@ -5,8 +5,8 @@ using System.Globalization;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Jellyfin.Data.Entities;
using Jellyfin.Data.Events;
using Jellyfin.Database.Implementations.Entities;
using Jellyfin.Extensions;
using MediaBrowser.Controller.Channels;
using MediaBrowser.Controller.Configuration;
@@ -34,7 +34,7 @@ public sealed class LibraryChangedNotifier : IHostedService, IDisposable
private readonly IUserManager _userManager;
private readonly ILogger<LibraryChangedNotifier> _logger;
private readonly object _libraryChangedSyncLock = new();
private readonly Lock _libraryChangedSyncLock = new();
private readonly List<Folder> _foldersAddedTo = new();
private readonly List<Folder> _foldersRemovedFrom = new();
private readonly List<BaseItem> _itemsAdded = new();

View File

@@ -24,7 +24,7 @@ namespace Emby.Server.Implementations.EntryPoints
private readonly IUserManager _userManager;
private readonly Dictionary<Guid, List<BaseItem>> _changedItems = new();
private readonly object _syncLock = new();
private readonly Lock _syncLock = new();
private Timer? _updateTimer;
@@ -144,9 +144,15 @@ namespace Emby.Server.Implementations.EntryPoints
.Select(i =>
{
var dto = _userDataManager.GetUserDataDto(i, user);
if (dto is null)
{
return null!;
}
dto.ItemId = i.Id;
return dto;
})
.Where(e => e is not null)
.ToArray()
};
}

View File

@@ -1,7 +1,8 @@
#pragma warning disable CS1591
using System.Threading.Tasks;
using Jellyfin.Data.Enums;
using Jellyfin.Data;
using Jellyfin.Database.Implementations.Enums;
using MediaBrowser.Controller.Net;
using Microsoft.AspNetCore.Http;

View File

@@ -57,7 +57,7 @@ namespace Emby.Server.Implementations.HttpServer
RemoteEndPoint = remoteEndPoint;
_jsonOptions = JsonDefaults.Options;
LastActivityDate = DateTime.Now;
LastActivityDate = DateTime.UtcNow;
}
/// <inheritdoc />
@@ -82,17 +82,17 @@ namespace Emby.Server.Implementations.HttpServer
public WebSocketState State => _socket.State;
/// <inheritdoc />
public Task SendAsync(OutboundWebSocketMessage message, CancellationToken cancellationToken)
public async Task SendAsync(OutboundWebSocketMessage message, CancellationToken cancellationToken)
{
var json = JsonSerializer.SerializeToUtf8Bytes(message, _jsonOptions);
return _socket.SendAsync(json, WebSocketMessageType.Text, true, cancellationToken);
await _socket.SendAsync(json, WebSocketMessageType.Text, true, cancellationToken).ConfigureAwait(false);
}
/// <inheritdoc />
public Task SendAsync<T>(OutboundWebSocketMessage<T> message, CancellationToken cancellationToken)
public async Task SendAsync<T>(OutboundWebSocketMessage<T> message, CancellationToken cancellationToken)
{
var json = JsonSerializer.SerializeToUtf8Bytes(message, _jsonOptions);
return _socket.SendAsync(json, WebSocketMessageType.Text, true, cancellationToken);
await _socket.SendAsync(json, WebSocketMessageType.Text, true, cancellationToken).ConfigureAwait(false);
}
/// <inheritdoc />
@@ -224,12 +224,12 @@ namespace Emby.Server.Implementations.HttpServer
return ret;
}
private Task SendKeepAliveResponse()
private async Task SendKeepAliveResponse()
{
LastKeepAliveDate = DateTime.UtcNow;
return SendAsync(
await SendAsync(
new OutboundKeepAliveMessage(),
CancellationToken.None);
CancellationToken.None).ConfigureAwait(false);
}
/// <inheritdoc />

View File

@@ -84,7 +84,7 @@ namespace Emby.Server.Implementations.HttpServer
/// Processes the web socket message received.
/// </summary>
/// <param name="result">The result.</param>
private Task ProcessWebSocketMessageReceived(WebSocketMessageInfo result)
private async Task ProcessWebSocketMessageReceived(WebSocketMessageInfo result)
{
var tasks = new Task[_webSocketListeners.Length];
for (var i = 0; i < _webSocketListeners.Length; ++i)
@@ -92,7 +92,7 @@ namespace Emby.Server.Implementations.HttpServer
tasks[i] = _webSocketListeners[i].ProcessMessageAsync(result);
}
return Task.WhenAll(tasks);
await Task.WhenAll(tasks).ConfigureAwait(false);
}
}
}

View File

@@ -18,8 +18,8 @@ namespace Emby.Server.Implementations.IO
private readonly ILibraryManager _libraryManager;
private readonly IServerConfigurationManager _configurationManager;
private readonly List<string> _affectedPaths = new List<string>();
private readonly object _timerLock = new object();
private readonly List<string> _affectedPaths = new();
private readonly Lock _timerLock = new();
private Timer? _timer;
private bool _disposed;
@@ -130,7 +130,7 @@ namespace Emby.Server.Implementations.IO
private void ProcessPathChanges(List<string> paths)
{
IEnumerable<BaseItem> itemsToRefresh = paths
.Distinct(StringComparer.OrdinalIgnoreCase)
.Distinct()
.Select(GetAffectedBaseItem)
.Where(item => item is not null)
.DistinctBy(x => x!.Id)!; // Removed null values in the previous .Where()

View File

@@ -121,7 +121,7 @@ namespace Emby.Server.Implementations.IO
.Where(IsLibraryMonitorEnabled)
.OfType<Folder>()
.SelectMany(f => f.PhysicalLocations)
.Distinct(StringComparer.OrdinalIgnoreCase)
.Distinct()
.Order();
foreach (var path in paths)

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);
@@ -160,12 +165,13 @@ namespace Emby.Server.Implementations.IO
{
// Cross device move requires a copy
Directory.CreateDirectory(destination);
foreach (string file in Directory.GetFiles(source))
var sourceDir = new DirectoryInfo(source);
foreach (var file in sourceDir.EnumerateFiles())
{
File.Copy(file, Path.Combine(destination, Path.GetFileName(file)), true);
file.CopyTo(Path.Combine(destination, file.Name), true);
}
Directory.Delete(source, true);
sourceDir.Delete(true);
}
}
@@ -247,40 +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);
}
}
else
{
result.Length = fileInfo.Length;
}
}
result.CreationTimeUtc = GetCreationTimeUtc(info);
result.LastWriteTimeUtc = GetLastWriteTimeUtc(info);
}
else
{
@@ -491,8 +497,17 @@ namespace Emby.Server.Implementations.IO
/// <inheritdoc />
public virtual bool AreEqual(string path1, string path2)
{
return Path.TrimEndingDirectorySeparator(path1).Equals(
Path.TrimEndingDirectorySeparator(path2),
if (string.IsNullOrWhiteSpace(path1) || string.IsNullOrWhiteSpace(path2))
{
return false;
}
var normalized1 = Path.TrimEndingDirectorySeparator(path1);
var normalized2 = Path.TrimEndingDirectorySeparator(path2);
return string.Equals(
normalized1,
normalized2,
_isEnvironmentCaseInsensitive ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal);
}
@@ -534,8 +549,8 @@ namespace Emby.Server.Implementations.IO
return DriveInfo.GetDrives()
.Where(
d => (d.DriveType == DriveType.Fixed || d.DriveType == DriveType.Network || d.DriveType == DriveType.Removable)
&& d.IsReady
&& d.TotalSize != 0)
&& d.IsReady
&& d.TotalSize != 0)
.Select(d => new FileSystemMetadata
{
Name = d.Name,
@@ -553,22 +568,36 @@ namespace Emby.Server.Implementations.IO
/// <inheritdoc />
public virtual IEnumerable<FileSystemMetadata> GetFiles(string path, bool recursive = false)
{
return GetFiles(path, null, false, recursive);
return GetFiles(path, "*", recursive);
}
/// <inheritdoc />
public virtual IEnumerable<FileSystemMetadata> GetFiles(string path, IReadOnlyList<string>? extensions, bool enableCaseSensitiveExtensions, bool recursive = false)
public virtual IEnumerable<FileSystemMetadata> GetFiles(string path, string searchPattern, bool recursive = false)
{
return GetFiles(path, searchPattern, null, false, recursive);
}
/// <inheritdoc />
public virtual IEnumerable<FileSystemMetadata> GetFiles(string path, IReadOnlyList<string>? extensions, bool enableCaseSensitiveExtensions, bool recursive)
{
return GetFiles(path, "*", extensions, enableCaseSensitiveExtensions, recursive);
}
/// <inheritdoc />
public virtual IEnumerable<FileSystemMetadata> GetFiles(string path, string searchPattern, IReadOnlyList<string>? extensions, bool enableCaseSensitiveExtensions, bool recursive = false)
{
var enumerationOptions = GetEnumerationOptions(recursive);
// On linux and osx the search pattern is case sensitive
// On linux and macOS the search pattern is case-sensitive
// If we're OK with case-sensitivity, and we're only filtering for one extension, then use the native method
if ((enableCaseSensitiveExtensions || _isEnvironmentCaseInsensitive) && extensions is not null && extensions.Count == 1)
{
return ToMetadata(new DirectoryInfo(path).EnumerateFiles("*" + extensions[0], enumerationOptions));
searchPattern = searchPattern.EndsWith(extensions[0], StringComparison.Ordinal) ? searchPattern : searchPattern + extensions[0];
return ToMetadata(new DirectoryInfo(path).EnumerateFiles(searchPattern, enumerationOptions));
}
var files = new DirectoryInfo(path).EnumerateFiles("*", enumerationOptions);
var files = new DirectoryInfo(path).EnumerateFiles(searchPattern, enumerationOptions);
if (extensions is not null && extensions.Count > 0)
{
@@ -590,6 +619,9 @@ namespace Emby.Server.Implementations.IO
/// <inheritdoc />
public virtual IEnumerable<FileSystemMetadata> GetFileSystemEntries(string path, bool recursive = false)
{
// Note: any of unhandled exceptions thrown by this method may cause the caller to believe the whole path is not accessible.
// But what causing the exception may be a single file under that path. This could lead to unexpected behavior.
// For example, the scanner will remove everything in that path due to unhandled errors.
var directoryInfo = new DirectoryInfo(path);
var enumerationOptions = GetEnumerationOptions(recursive);
@@ -618,7 +650,7 @@ namespace Emby.Server.Implementations.IO
{
var enumerationOptions = GetEnumerationOptions(recursive);
// On linux and osx the search pattern is case sensitive
// On linux and macOS the search pattern is case-sensitive
// If we're OK with case-sensitivity, and we're only filtering for one extension, then use the native method
if ((enableCaseSensitiveExtensions || _isEnvironmentCaseInsensitive) && extensions is not null && extensions.Length == 1)
{

View File

@@ -7,6 +7,7 @@ using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net.Mime;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Common.Configuration;
@@ -42,13 +43,11 @@ namespace Emby.Server.Implementations.Images
protected IImageProcessor ImageProcessor { get; set; }
protected virtual IReadOnlyCollection<ImageType> SupportedImages { get; }
= new ImageType[] { ImageType.Primary };
= [ImageType.Primary];
/// <inheritdoc />
public string Name => "Dynamic Image Provider";
protected virtual int MaxImageAgeDays => 7;
public int Order => 0;
protected virtual bool Supports(BaseItem item) => true;
@@ -116,13 +115,12 @@ namespace Emby.Server.Implementations.Images
var mimeType = MimeTypes.GetMimeType(outputPath);
if (string.Equals(mimeType, "application/octet-stream", StringComparison.OrdinalIgnoreCase))
if (string.Equals(mimeType, MediaTypeNames.Application.Octet, StringComparison.OrdinalIgnoreCase))
{
mimeType = "image/png";
mimeType = MediaTypeNames.Image.Png;
}
await ProviderManager.SaveImage(item, outputPath, mimeType, imageType, null, false, cancellationToken).ConfigureAwait(false);
File.Delete(outputPath);
return ItemUpdateType.ImageUpdate;
}
@@ -292,8 +290,14 @@ namespace Emby.Server.Implementations.Images
protected virtual bool HasChangedByDate(BaseItem item, ItemImageInfo image)
{
var age = DateTime.UtcNow - image.DateModified;
return age.TotalDays > MaxImageAgeDays;
var path = image.Path;
if (!string.IsNullOrEmpty(path))
{
var modificationDate = FileSystem.GetLastWriteTimeUtc(path);
return image.DateModified != modificationDate;
}
return false;
}
protected string CreateSingleImage(IEnumerable<BaseItem> itemsWithImages, string outputPathWithoutExtension, ImageType imageType)

View File

@@ -2,6 +2,7 @@
using System.Collections.Generic;
using Jellyfin.Data.Enums;
using Jellyfin.Database.Implementations.Enums;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Controller.Drawing;
using MediaBrowser.Controller.Dto;

View File

@@ -6,6 +6,7 @@ using System;
using System.Collections.Generic;
using System.IO;
using Jellyfin.Data.Enums;
using Jellyfin.Database.Implementations.Enums;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Controller.Drawing;
using MediaBrowser.Controller.Dto;

View File

@@ -2,6 +2,7 @@
using System.Collections.Generic;
using Jellyfin.Data.Enums;
using Jellyfin.Database.Implementations.Enums;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Controller.Drawing;
using MediaBrowser.Controller.Dto;

View File

@@ -4,6 +4,7 @@
using System.Collections.Generic;
using Jellyfin.Data.Enums;
using Jellyfin.Database.Implementations.Enums;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Controller.Drawing;
using MediaBrowser.Controller.Dto;

View File

@@ -37,46 +37,33 @@ namespace Emby.Server.Implementations.Library
return false;
}
// Don't ignore top level folders
if (fileInfo.IsDirectory && parent is AggregateFolder)
{
return false;
}
if (IgnorePatterns.ShouldIgnore(fileInfo.FullName))
{
return true;
}
var filename = fileInfo.Name;
// Don't ignore top level folders
if (fileInfo.IsDirectory
&& (parent is AggregateFolder || (parent?.IsTopParent ?? false)))
{
return false;
}
if (parent is null)
{
return false;
}
if (fileInfo.IsDirectory)
{
if (parent is not null)
{
// Ignore extras folders but allow it at the collection level
if (_namingOptions.AllExtrasTypesFolderNames.ContainsKey(filename)
&& parent is not AggregateFolder
&& parent is not UserRootFolder)
{
return true;
}
}
}
else
{
if (parent is not null)
{
// Don't resolve these into audio files
if (Path.GetFileNameWithoutExtension(filename.AsSpan()).Equals(BaseItem.ThemeSongFileName, StringComparison.Ordinal)
&& AudioFileParser.IsAudioFile(filename, _namingOptions))
{
return true;
}
}
// Ignore extras for unsupported types
return _namingOptions.AllExtrasTypesFolderNames.ContainsKey(fileInfo.Name)
&& parent is not UserRootFolder;
}
return false;
// Don't resolve theme songs
return Path.GetFileNameWithoutExtension(fileInfo.Name.AsSpan()).Equals(BaseItem.ThemeSongFileName, StringComparison.Ordinal)
&& AudioFileParser.IsAudioFile(fileInfo.Name, _namingOptions);
}
}
}

View File

@@ -0,0 +1,96 @@
using System;
using System.IO;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.IO;
using MediaBrowser.Controller.Resolvers;
using MediaBrowser.Model.IO;
namespace Emby.Server.Implementations.Library;
/// <summary>
/// Resolver rule class for ignoring files via .ignore.
/// </summary>
public class DotIgnoreIgnoreRule : IResolverIgnoreRule
{
private static readonly bool IsWindows = OperatingSystem.IsWindows();
private static FileInfo? FindIgnoreFile(DirectoryInfo directory)
{
for (var current = directory; current is not null; current = current.Parent)
{
var ignorePath = Path.Join(current.FullName, ".ignore");
if (File.Exists(ignorePath))
{
return new FileInfo(ignorePath);
}
}
return null;
}
/// <inheritdoc />
public bool ShouldIgnore(FileSystemMetadata fileInfo, BaseItem? parent) => IsIgnored(fileInfo, parent);
/// <summary>
/// Checks whether or not the file is ignored.
/// </summary>
/// <param name="fileInfo">The file information.</param>
/// <param name="parent">The parent BaseItem.</param>
/// <returns>True if the file should be ignored.</returns>
public static bool IsIgnored(FileSystemMetadata fileInfo, BaseItem? parent)
{
var searchDirectory = fileInfo.IsDirectory
? new DirectoryInfo(fileInfo.FullName)
: new DirectoryInfo(Path.GetDirectoryName(fileInfo.FullName) ?? string.Empty);
if (string.IsNullOrEmpty(searchDirectory.FullName))
{
return false;
}
var ignoreFile = FindIgnoreFile(searchDirectory);
if (ignoreFile is null)
{
return false;
}
// 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;
}
var content = GetFileContent(ignoreFile);
return string.IsNullOrWhiteSpace(content)
|| CheckIgnoreRules(fileInfo.FullName, content, fileInfo.IsDirectory);
}
private static bool CheckIgnoreRules(string path, string ignoreFileContent, bool isDirectory)
{
// 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)
{
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

@@ -0,0 +1,77 @@
using System;
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;
using MediaBrowser.Controller.Trickplay;
using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.Library;
/// <summary>
/// IExternalDataManager implementation.
/// </summary>
public class ExternalDataManager : IExternalDataManager
{
private readonly IKeyframeManager _keyframeManager;
private readonly IMediaSegmentManager _mediaSegmentManager;
private readonly IPathManager _pathManager;
private readonly ITrickplayManager _trickplayManager;
private readonly IChapterManager _chapterManager;
private readonly ILogger<ExternalDataManager> _logger;
/// <summary>
/// Initializes a new instance of the <see cref="ExternalDataManager"/> class.
/// </summary>
/// <param name="keyframeManager">The keyframe manager.</param>
/// <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;
}
/// <inheritdoc/>
public async Task DeleteExternalItemDataAsync(BaseItem item, CancellationToken cancellationToken)
{
var validPaths = _pathManager.GetExtractedDataPaths(item).Where(Directory.Exists).ToList();
var itemId = item.Id;
if (validPaths.Count > 0)
{
foreach (var path in validPaths)
{
try
{
Directory.Delete(path, true);
}
catch (Exception ex)
{
_logger.LogWarning("Unable to prune external item data at {Path}: {Exception}", path, ex);
}
}
}
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

@@ -1,5 +1,4 @@
using System;
using System.Linq;
using DotNet.Globbing;
namespace Emby.Server.Implementations.Library
@@ -49,6 +48,8 @@ namespace Emby.Server.Implementations.Library
"**/.wd_tv",
"**/lost+found/**",
"**/lost+found",
"**/subs/**",
"**/subs",
// Trickplay files
"**/*.trickplay",

View File

@@ -0,0 +1,44 @@
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Jellyfin.MediaEncoding.Keyframes;
using MediaBrowser.Controller.IO;
using MediaBrowser.Controller.Persistence;
namespace Emby.Server.Implementations.Library;
/// <summary>
/// Manager for Keyframe data.
/// </summary>
public class KeyframeManager : IKeyframeManager
{
private readonly IKeyframeRepository _repository;
/// <summary>
/// Initializes a new instance of the <see cref="KeyframeManager"/> class.
/// </summary>
/// <param name="repository">The keyframe repository.</param>
public KeyframeManager(IKeyframeRepository repository)
{
_repository = repository;
}
/// <inheritdoc />
public IReadOnlyList<KeyframeData> GetKeyframeData(Guid itemId)
{
return _repository.GetKeyframeData(itemId);
}
/// <inheritdoc />
public async Task SaveKeyframeDataAsync(Guid itemId, KeyframeData data, CancellationToken cancellationToken)
{
await _repository.SaveKeyframeDataAsync(itemId, data, cancellationToken).ConfigureAwait(false);
}
/// <inheritdoc />
public async Task DeleteKeyframeDataAsync(Guid itemId, CancellationToken cancellationToken)
{
await _repository.DeleteKeyframeDataAsync(itemId, cancellationToken).ConfigureAwait(false);
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -5,6 +5,7 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Globalization;
using System.IO;
using System.Linq;
@@ -12,8 +13,10 @@ using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using AsyncKeyedLock;
using Jellyfin.Data.Entities;
using Jellyfin.Data;
using Jellyfin.Data.Enums;
using Jellyfin.Database.Implementations.Entities;
using Jellyfin.Database.Implementations.Enums;
using Jellyfin.Extensions;
using Jellyfin.Extensions.Json;
using MediaBrowser.Common.Configuration;
@@ -38,7 +41,7 @@ namespace Emby.Server.Implementations.Library
public class MediaSourceManager : IMediaSourceManager, IDisposable
{
// Do not use a pipe here because Roku http requests to the server will fail, without any explicit error message.
private const char LiveStreamIdDelimeter = '_';
private const char LiveStreamIdDelimiter = '_';
private readonly IServerApplicationHost _appHost;
private readonly IItemRepository _itemRepo;
@@ -51,7 +54,8 @@ namespace Emby.Server.Implementations.Library
private readonly ILocalizationManager _localizationManager;
private readonly IApplicationPaths _appPaths;
private readonly IDirectoryService _directoryService;
private readonly IMediaStreamRepository _mediaStreamRepository;
private readonly IMediaAttachmentRepository _mediaAttachmentRepository;
private readonly ConcurrentDictionary<string, ILiveStream> _openStreams = new ConcurrentDictionary<string, ILiveStream>(StringComparer.OrdinalIgnoreCase);
private readonly AsyncNonKeyedLocker _liveStreamLocker = new(1);
private readonly JsonSerializerOptions _jsonOptions = JsonDefaults.Options;
@@ -69,7 +73,9 @@ namespace Emby.Server.Implementations.Library
IFileSystem fileSystem,
IUserDataManager userDataManager,
IMediaEncoder mediaEncoder,
IDirectoryService directoryService)
IDirectoryService directoryService,
IMediaStreamRepository mediaStreamRepository,
IMediaAttachmentRepository mediaAttachmentRepository)
{
_appHost = appHost;
_itemRepo = itemRepo;
@@ -82,6 +88,8 @@ namespace Emby.Server.Implementations.Library
_localizationManager = localizationManager;
_appPaths = applicationPaths;
_directoryService = directoryService;
_mediaStreamRepository = mediaStreamRepository;
_mediaAttachmentRepository = mediaAttachmentRepository;
}
public void AddParts(IEnumerable<IMediaSourceProvider> providers)
@@ -89,9 +97,9 @@ namespace Emby.Server.Implementations.Library
_providers = providers.ToArray();
}
public List<MediaStream> GetMediaStreams(MediaStreamQuery query)
public IReadOnlyList<MediaStream> GetMediaStreams(MediaStreamQuery query)
{
var list = _itemRepo.GetMediaStreams(query);
var list = _mediaStreamRepository.GetMediaStreams(query);
foreach (var stream in list)
{
@@ -121,7 +129,7 @@ namespace Emby.Server.Implementations.Library
return false;
}
public List<MediaStream> GetMediaStreams(Guid itemId)
public IReadOnlyList<MediaStream> GetMediaStreams(Guid itemId)
{
var list = GetMediaStreams(new MediaStreamQuery
{
@@ -131,7 +139,7 @@ namespace Emby.Server.Implementations.Library
return GetMediaStreamsForItem(list);
}
private List<MediaStream> GetMediaStreamsForItem(List<MediaStream> streams)
private IReadOnlyList<MediaStream> GetMediaStreamsForItem(IReadOnlyList<MediaStream> streams)
{
foreach (var stream in streams)
{
@@ -145,13 +153,13 @@ namespace Emby.Server.Implementations.Library
}
/// <inheritdoc />
public List<MediaAttachment> GetMediaAttachments(MediaAttachmentQuery query)
public IReadOnlyList<MediaAttachment> GetMediaAttachments(MediaAttachmentQuery query)
{
return _itemRepo.GetMediaAttachments(query);
return _mediaAttachmentRepository.GetMediaAttachments(query);
}
/// <inheritdoc />
public List<MediaAttachment> GetMediaAttachments(Guid itemId)
public IReadOnlyList<MediaAttachment> GetMediaAttachments(Guid itemId)
{
return GetMediaAttachments(new MediaAttachmentQuery
{
@@ -159,7 +167,7 @@ namespace Emby.Server.Implementations.Library
});
}
public async Task<List<MediaSourceInfo>> GetPlaybackMediaSources(BaseItem item, User user, bool allowMediaProbe, bool enablePathSubstitution, CancellationToken cancellationToken)
public async Task<IReadOnlyList<MediaSourceInfo>> GetPlaybackMediaSources(BaseItem item, User user, bool allowMediaProbe, bool enablePathSubstitution, CancellationToken cancellationToken)
{
var mediaSources = GetStaticMediaSources(item, enablePathSubstitution, user);
@@ -212,12 +220,17 @@ namespace Emby.Server.Implementations.Library
list.Add(source);
}
return SortMediaSources(list);
return SortMediaSources(list).ToArray();
}
/// <inheritdoc />>
public MediaProtocol GetPathProtocol(string path)
{
if (string.IsNullOrEmpty(path))
{
return MediaProtocol.File;
}
if (path.StartsWith("Rtsp", StringComparison.OrdinalIgnoreCase))
{
return MediaProtocol.Rtsp;
@@ -307,7 +320,7 @@ namespace Emby.Server.Implementations.Library
private static void SetKeyProperties(IMediaSourceProvider provider, MediaSourceInfo mediaSource)
{
var prefix = provider.GetType().FullName.GetMD5().ToString("N", CultureInfo.InvariantCulture) + LiveStreamIdDelimeter;
var prefix = provider.GetType().FullName.GetMD5().ToString("N", CultureInfo.InvariantCulture) + LiveStreamIdDelimiter;
if (!string.IsNullOrEmpty(mediaSource.OpenToken) && !mediaSource.OpenToken.StartsWith(prefix, StringComparison.OrdinalIgnoreCase))
{
@@ -332,7 +345,7 @@ namespace Emby.Server.Implementations.Library
return sources.FirstOrDefault(i => string.Equals(i.Id, mediaSourceId, StringComparison.OrdinalIgnoreCase));
}
public List<MediaSourceInfo> GetStaticMediaSources(BaseItem item, bool enablePathSubstitution, User user = null)
public IReadOnlyList<MediaSourceInfo> GetStaticMediaSources(BaseItem item, bool enablePathSubstitution, User user = null)
{
ArgumentNullException.ThrowIfNull(item);
@@ -371,7 +384,7 @@ namespace Emby.Server.Implementations.Library
var culture = _localizationManager.FindLanguageInfo(language);
if (culture is not null)
{
return culture.ThreeLetterISOLanguageNames;
return culture.Name.Contains('-', StringComparison.OrdinalIgnoreCase) ? [culture.Name] : culture.ThreeLetterISOLanguageNames;
}
return [language];
@@ -419,6 +432,7 @@ namespace Emby.Server.Implementations.Library
if (source.MediaStreams.Any(i => i.Type == MediaStreamType.Audio && i.Index == index))
{
source.DefaultAudioStreamIndex = index;
source.DefaultAudioIndexSource = AudioIndexSource.User;
return;
}
}
@@ -426,6 +440,15 @@ namespace Emby.Server.Implementations.Library
var preferredAudio = NormalizeLanguage(user.AudioLanguagePreference);
source.DefaultAudioStreamIndex = MediaStreamSelector.GetDefaultAudioStreamIndex(source.MediaStreams, preferredAudio, user.PlayDefaultAudioTrack);
if (user.PlayDefaultAudioTrack)
{
source.DefaultAudioIndexSource |= AudioIndexSource.Default;
}
if (preferredAudio.Count > 0)
{
source.DefaultAudioIndexSource |= AudioIndexSource.Language;
}
}
public void SetDefaultAudioAndSubtitleStreamIndices(BaseItem item, MediaSourceInfo source, User user)
@@ -453,7 +476,7 @@ namespace Emby.Server.Implementations.Library
}
}
private static List<MediaSourceInfo> SortMediaSources(IEnumerable<MediaSourceInfo> sources)
private static IEnumerable<MediaSourceInfo> SortMediaSources(IEnumerable<MediaSourceInfo> sources)
{
return sources.OrderBy(i =>
{
@@ -470,8 +493,7 @@ namespace Emby.Server.Implementations.Library
return stream?.Width ?? 0;
})
.Where(i => i.Type != MediaSourceType.Placeholder)
.ToList();
.Where(i => i.Type != MediaSourceType.Placeholder);
}
public async Task<Tuple<LiveStreamResponse, IDirectStreamProvider>> OpenLiveStreamInternal(LiveStreamRequest request, CancellationToken cancellationToken)
@@ -640,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
{
@@ -664,17 +686,17 @@ namespace Emby.Server.Implementations.Library
mediaInfo = await _mediaEncoder.GetMediaInfo(
new MediaInfoRequest
{
MediaSource = mediaSource,
MediaType = isAudio ? DlnaProfileType.Audio : DlnaProfileType.Video,
ExtractChapters = false
},
{
MediaSource = mediaSource,
MediaType = isAudio ? DlnaProfileType.Audio : DlnaProfileType.Video,
ExtractChapters = false
},
cancellationToken).ConfigureAwait(false);
if (cacheFilePath is not null)
{
Directory.CreateDirectory(Path.GetDirectoryName(cacheFilePath));
FileStream createStream = File.Create(cacheFilePath);
FileStream createStream = AsyncFile.Create(cacheFilePath);
await using (createStream.ConfigureAwait(false))
{
await JsonSerializer.SerializeAsync(createStream, mediaInfo, _jsonOptions, cancellationToken).ConfigureAwait(false);
@@ -777,9 +799,13 @@ namespace Emby.Server.Implementations.Library
{
ArgumentException.ThrowIfNullOrEmpty(id);
// TODO probably shouldn't throw here but it is kept for "backwards compatibility"
var info = GetLiveStreamInfo(id) ?? throw new ResourceNotFoundException();
return Task.FromResult(new Tuple<MediaSourceInfo, IDirectStreamProvider>(info.MediaSource, info as IDirectStreamProvider));
var info = GetLiveStreamInfo(id);
if (info is null)
{
return Task.FromResult<Tuple<MediaSourceInfo, IDirectStreamProvider>>(new Tuple<MediaSourceInfo, IDirectStreamProvider>(null, null));
}
return Task.FromResult<Tuple<MediaSourceInfo, IDirectStreamProvider>>(new Tuple<MediaSourceInfo, IDirectStreamProvider>(info.MediaSource, info as IDirectStreamProvider));
}
public ILiveStream GetLiveStreamInfo(string id)
@@ -806,7 +832,7 @@ namespace Emby.Server.Implementations.Library
return result.Item1;
}
public async Task<List<MediaSourceInfo>> GetRecordingStreamMediaSources(ActiveRecordingInfo info, CancellationToken cancellationToken)
public async Task<IReadOnlyList<MediaSourceInfo>> GetRecordingStreamMediaSources(ActiveRecordingInfo info, CancellationToken cancellationToken)
{
var stream = new MediaSourceInfo
{
@@ -829,10 +855,7 @@ namespace Emby.Server.Implementations.Library
await new LiveStreamHelper(_mediaEncoder, _logger, _appPaths)
.AddMediaInfoWithProbe(stream, false, false, cancellationToken).ConfigureAwait(false);
return new List<MediaSourceInfo>
{
stream
};
return [stream];
}
public async Task CloseLiveStream(string id)
@@ -864,11 +887,11 @@ namespace Emby.Server.Implementations.Library
{
ArgumentException.ThrowIfNullOrEmpty(key);
var keys = key.Split(LiveStreamIdDelimeter, 2);
var keys = key.Split(LiveStreamIdDelimiter, 2);
var provider = _providers.FirstOrDefault(i => string.Equals(i.GetType().FullName.GetMD5().ToString("N", CultureInfo.InvariantCulture), keys[0], StringComparison.OrdinalIgnoreCase));
var splitIndex = key.IndexOf(LiveStreamIdDelimeter, StringComparison.Ordinal);
var splitIndex = key.IndexOf(LiveStreamIdDelimiter, StringComparison.Ordinal);
var keyId = key.Substring(splitIndex + 1);
return (provider, keyId);

View File

@@ -3,7 +3,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Jellyfin.Data.Enums;
using Jellyfin.Database.Implementations.Enums;
using Jellyfin.Extensions;
using MediaBrowser.Model.Entities;
@@ -39,46 +39,48 @@ namespace Emby.Server.Implementations.Library
return null;
}
// Sort in the following order: Default > No tag > Forced
var sortedStreams = streams
.Where(i => i.Type == MediaStreamType.Subtitle)
.OrderByDescending(x => x.IsExternal)
.ThenByDescending(x => x.IsForced && string.Equals(x.Language, audioTrackLanguage, StringComparison.OrdinalIgnoreCase))
.ThenByDescending(x => x.IsForced)
.ThenByDescending(x => x.IsDefault)
.ThenByDescending(x => preferredLanguages.Contains(x.Language, StringComparison.OrdinalIgnoreCase))
.ThenByDescending(x => !x.IsForced && MatchesPreferredLanguage(x.Language, preferredLanguages))
.ThenByDescending(x => x.IsForced && MatchesPreferredLanguage(x.Language, preferredLanguages))
.ThenByDescending(x => x.IsForced && IsLanguageUndefined(x.Language))
.ThenByDescending(x => x.IsForced)
.ToList();
MediaStream? stream = null;
if (mode == SubtitlePlaybackMode.Default)
{
// Load subtitles according to external, forced and default flags.
stream = sortedStreams.FirstOrDefault(x => x.IsExternal || x.IsForced || x.IsDefault);
// Load subtitles according to external, default and forced flags.
stream = sortedStreams.FirstOrDefault(x => x.IsExternal || x.IsDefault || x.IsForced);
}
else if (mode == SubtitlePlaybackMode.Smart)
{
// Only attempt to load subtitles if the audio language is not one of the user's preferred subtitle languages.
// If no subtitles of preferred language available, use default behaviour.
// If no subtitles of preferred language available, use none.
// If the audio language is one of the user's preferred subtitle languages behave like OnlyForced.
if (!preferredLanguages.Contains(audioTrackLanguage, StringComparison.OrdinalIgnoreCase))
{
stream = sortedStreams.FirstOrDefault(x => preferredLanguages.Contains(x.Language, StringComparison.OrdinalIgnoreCase)) ??
sortedStreams.FirstOrDefault(x => x.IsExternal || x.IsForced || x.IsDefault);
stream = sortedStreams.FirstOrDefault(x => MatchesPreferredLanguage(x.Language, preferredLanguages));
}
else
{
// Respect forced flag.
stream = sortedStreams.FirstOrDefault(x => x.IsForced);
stream = BehaviorOnlyForced(sortedStreams, preferredLanguages).FirstOrDefault();
}
}
else if (mode == SubtitlePlaybackMode.Always)
{
// Always load (full/non-forced) subtitles of the user's preferred subtitle language if possible, otherwise default behaviour.
stream = sortedStreams.FirstOrDefault(x => !x.IsForced && preferredLanguages.Contains(x.Language, StringComparison.OrdinalIgnoreCase)) ??
sortedStreams.FirstOrDefault(x => x.IsExternal || x.IsForced || x.IsDefault);
// Always load (full/non-forced) subtitles of the user's preferred subtitle language if possible, otherwise OnlyForced behaviour.
stream = sortedStreams.FirstOrDefault(x => !x.IsForced && MatchesPreferredLanguage(x.Language, preferredLanguages)) ??
BehaviorOnlyForced(sortedStreams, preferredLanguages).FirstOrDefault();
}
else if (mode == SubtitlePlaybackMode.OnlyForced)
{
// Only load subtitles that are flagged forced.
stream = sortedStreams.FirstOrDefault(x => x.IsForced);
// Load subtitles that are flagged forced of the user's preferred subtitle language or with an undefined language
stream = BehaviorOnlyForced(sortedStreams, preferredLanguages).FirstOrDefault();
}
return stream?.Index;
@@ -110,40 +112,72 @@ namespace Emby.Server.Implementations.Library
if (mode == SubtitlePlaybackMode.Default)
{
// Prefer embedded metadata over smart logic
filteredStreams = sortedStreams.Where(s => s.IsForced || s.IsDefault)
// Load subtitles according to external, default, and forced flags.
filteredStreams = sortedStreams.Where(s => s.IsExternal || s.IsDefault || s.IsForced)
.ToList();
}
else if (mode == SubtitlePlaybackMode.Smart)
{
// Prefer smart logic over embedded metadata
// Only attempt to load subtitles if the audio language is not one of the user's preferred subtitle languages, otherwise OnlyForced behavior.
if (!preferredLanguages.Contains(audioTrackLanguage, StringComparison.OrdinalIgnoreCase))
{
filteredStreams = sortedStreams.Where(s => !s.IsForced && preferredLanguages.Contains(s.Language, StringComparison.OrdinalIgnoreCase))
filteredStreams = sortedStreams.Where(s => MatchesPreferredLanguage(s.Language, preferredLanguages))
.ToList();
}
else
{
filteredStreams = BehaviorOnlyForced(sortedStreams, preferredLanguages);
}
}
else if (mode == SubtitlePlaybackMode.Always)
{
// Always load the most suitable full subtitles
filteredStreams = sortedStreams.Where(s => !s.IsForced).ToList();
// Always load (full/non-forced) subtitles of the user's preferred subtitle language if possible, otherwise OnlyForced behavior.
filteredStreams = sortedStreams.Where(s => !s.IsForced && MatchesPreferredLanguage(s.Language, preferredLanguages))
.ToList() ?? BehaviorOnlyForced(sortedStreams, preferredLanguages);
}
else if (mode == SubtitlePlaybackMode.OnlyForced)
{
// Always load the most suitable full subtitles
filteredStreams = sortedStreams.Where(s => s.IsForced).ToList();
// Load subtitles that are flagged forced of the user's preferred subtitle language or with an undefined language
filteredStreams = BehaviorOnlyForced(sortedStreams, preferredLanguages);
}
// Load forced subs if we have found no suitable full subtitles
var iterStreams = filteredStreams is null || filteredStreams.Count == 0
? sortedStreams.Where(s => s.IsForced && string.Equals(s.Language, audioTrackLanguage, StringComparison.OrdinalIgnoreCase))
: filteredStreams;
// If filteredStreams is null, initialize it as an empty list to avoid null reference errors
filteredStreams ??= new List<MediaStream>();
foreach (var stream in iterStreams)
foreach (var stream in filteredStreams)
{
stream.Score = GetStreamScore(stream, preferredLanguages);
}
}
private static bool MatchesPreferredLanguage(string language, IReadOnlyList<string> preferredLanguages)
{
// If preferredLanguages is empty, treat it as "any language" (wildcard)
return preferredLanguages.Count == 0 ||
preferredLanguages.Contains(language, StringComparison.OrdinalIgnoreCase);
}
private static bool IsLanguageUndefined(string language)
{
// Check for null, empty, or known placeholders
return string.IsNullOrEmpty(language) ||
language.Equals("und", StringComparison.OrdinalIgnoreCase) ||
language.Equals("unknown", StringComparison.OrdinalIgnoreCase) ||
language.Equals("undetermined", StringComparison.OrdinalIgnoreCase) ||
language.Equals("mul", StringComparison.OrdinalIgnoreCase) ||
language.Equals("zxx", StringComparison.OrdinalIgnoreCase);
}
private static List<MediaStream> BehaviorOnlyForced(IEnumerable<MediaStream> sortedStreams, IReadOnlyList<string> preferredLanguages)
{
return sortedStreams
.Where(s => s.IsForced && (MatchesPreferredLanguage(s.Language, preferredLanguages) || IsLanguageUndefined(s.Language)))
.OrderByDescending(s => MatchesPreferredLanguage(s.Language, preferredLanguages))
.ThenByDescending(s => IsLanguageUndefined(s.Language))
.ToList();
}
internal static int GetStreamScore(MediaStream stream, IReadOnlyList<string> languagePreferences)
{
var index = languagePreferences.FindIndex(x => string.Equals(x, stream.Language, StringComparison.OrdinalIgnoreCase));

View File

@@ -2,9 +2,11 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using Jellyfin.Data.Entities;
using Jellyfin.Data.Enums;
using Jellyfin.Database.Implementations.Entities;
using Jellyfin.Database.Implementations.Enums;
using Jellyfin.Extensions;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities;
@@ -24,37 +26,35 @@ namespace Emby.Server.Implementations.Library
_libraryManager = libraryManager;
}
public List<BaseItem> GetInstantMixFromSong(Audio item, User? user, DtoOptions dtoOptions)
public IReadOnlyList<BaseItem> GetInstantMixFromSong(Audio item, User? user, DtoOptions dtoOptions)
{
var list = new List<BaseItem>
{
item
};
var instantMixItems = GetInstantMixFromGenres(item.Genres, user, dtoOptions);
list.AddRange(GetInstantMixFromGenres(item.Genres, user, dtoOptions));
return list;
return [item, .. instantMixItems.Where(i => !i.Id.Equals(item.Id))];
}
/// <inheritdoc />
public List<BaseItem> GetInstantMixFromArtist(MusicArtist artist, User? user, DtoOptions dtoOptions)
public IReadOnlyList<BaseItem> GetInstantMixFromArtist(MusicArtist artist, User? user, DtoOptions dtoOptions)
{
return GetInstantMixFromGenres(artist.Genres, user, dtoOptions);
}
public List<BaseItem> GetInstantMixFromAlbum(MusicAlbum item, User? user, DtoOptions dtoOptions)
public IReadOnlyList<BaseItem> GetInstantMixFromAlbum(MusicAlbum item, User? user, DtoOptions dtoOptions)
{
return GetInstantMixFromGenres(item.Genres, user, dtoOptions);
}
public List<BaseItem> GetInstantMixFromFolder(Folder item, User? user, DtoOptions dtoOptions)
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)
@@ -63,12 +63,12 @@ namespace Emby.Server.Implementations.Library
return GetInstantMixFromGenres(genres, user, dtoOptions);
}
public List<BaseItem> GetInstantMixFromPlaylist(Playlist item, User? user, DtoOptions dtoOptions)
public IReadOnlyList<BaseItem> GetInstantMixFromPlaylist(Playlist item, User? user, DtoOptions dtoOptions)
{
return GetInstantMixFromGenres(item.Genres, user, dtoOptions);
}
public List<BaseItem> GetInstantMixFromGenres(IEnumerable<string> genres, User? user, DtoOptions dtoOptions)
public IReadOnlyList<BaseItem> GetInstantMixFromGenres(IEnumerable<string> genres, User? user, DtoOptions dtoOptions)
{
var genreIds = genres.DistinctNames().Select(i =>
{
@@ -85,7 +85,7 @@ namespace Emby.Server.Implementations.Library
return GetInstantMixFromGenreIds(genreIds, user, dtoOptions);
}
public List<BaseItem> GetInstantMixFromGenreIds(Guid[] genreIds, User? user, DtoOptions dtoOptions)
public IReadOnlyList<BaseItem> GetInstantMixFromGenreIds(Guid[] genreIds, User? user, DtoOptions dtoOptions)
{
return _libraryManager.GetItemList(new InternalItemsQuery(user)
{
@@ -97,7 +97,7 @@ namespace Emby.Server.Implementations.Library
});
}
public List<BaseItem> GetInstantMixFromItem(BaseItem item, User? user, DtoOptions dtoOptions)
public IReadOnlyList<BaseItem> GetInstantMixFromItem(BaseItem item, User? user, DtoOptions dtoOptions)
{
if (item is MusicGenre)
{

View File

@@ -0,0 +1,101 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.IO;
namespace Emby.Server.Implementations.Library;
/// <summary>
/// IPathManager implementation.
/// </summary>
public class PathManager : IPathManager
{
private readonly IServerConfigurationManager _config;
private readonly IApplicationPaths _appPaths;
/// <summary>
/// Initializes a new instance of the <see cref="PathManager"/> class.
/// </summary>
/// <param name="config">The server configuration manager.</param>
/// <param name="appPaths">The application paths.</param>
public PathManager(
IServerConfigurationManager config,
IApplicationPaths appPaths)
{
_config = config;
_appPaths = appPaths;
}
private string SubtitleCachePath => Path.Combine(_appPaths.DataPath, "subtitles");
private string AttachmentCachePath => Path.Combine(_appPaths.DataPath, "attachments");
/// <inheritdoc />
public string GetAttachmentPath(string mediaSourceId, string fileName)
{
return Path.Combine(GetAttachmentFolderPath(mediaSourceId), fileName);
}
/// <inheritdoc />
public string GetAttachmentFolderPath(string mediaSourceId)
{
var id = Guid.Parse(mediaSourceId).ToString("D", CultureInfo.InvariantCulture).AsSpan();
return Path.Join(AttachmentCachePath, id[..2], id);
}
/// <inheritdoc />
public string GetSubtitleFolderPath(string mediaSourceId)
{
var id = Guid.Parse(mediaSourceId).ToString("D", CultureInfo.InvariantCulture).AsSpan();
return Path.Join(SubtitleCachePath, id[..2], id);
}
/// <inheritdoc />
public string GetSubtitlePath(string mediaSourceId, int streamIndex, string extension)
{
return Path.Combine(GetSubtitleFolderPath(mediaSourceId), streamIndex.ToString(CultureInfo.InvariantCulture) + extension);
}
/// <inheritdoc />
public string GetTrickplayDirectory(BaseItem item, bool saveWithMedia = false)
{
var id = item.Id.ToString("D", CultureInfo.InvariantCulture).AsSpan();
return saveWithMedia
? Path.Combine(item.ContainingFolderPath, Path.ChangeExtension(Path.GetFileName(item.Path), ".trickplay"))
: Path.Join(_config.ApplicationPaths.TrickplayPath, id[..2], id);
}
/// <inheritdoc/>
public string GetChapterImageFolderPath(BaseItem item)
{
return Path.Combine(item.GetInternalMetadataPath(), "chapters");
}
/// <inheritdoc/>
public string GetChapterImagePath(BaseItem item, long chapterPositionTicks)
{
var filename = item.DateModified.Ticks.ToString(CultureInfo.InvariantCulture) + "_" + chapterPositionTicks.ToString(CultureInfo.InvariantCulture) + ".jpg";
return Path.Combine(GetChapterImageFolderPath(item), filename);
}
/// <inheritdoc/>
public IReadOnlyList<string> GetExtractedDataPaths(BaseItem item)
{
var mediaSourceId = item.Id.ToString("N", CultureInfo.InvariantCulture);
return [
GetAttachmentFolderPath(mediaSourceId),
GetSubtitleFolderPath(mediaSourceId),
GetTrickplayDirectory(item, false),
GetTrickplayDirectory(item, true),
GetChapterImageFolderPath(item)
];
}
}

View File

@@ -136,23 +136,33 @@ namespace Emby.Server.Implementations.Library
if (config.UseFileCreationTimeForDateAdded)
{
// directoryService.getFile may return null
if (info is not null)
var fileCreationDate = info?.CreationTimeUtc;
if (fileCreationDate is not null)
{
var dateCreated = info.CreationTimeUtc;
if (dateCreated.Equals(DateTime.MinValue))
var dateCreated = fileCreationDate;
if (dateCreated == DateTime.MinValue)
{
dateCreated = DateTime.UtcNow;
}
item.DateCreated = dateCreated;
item.DateCreated = dateCreated.Value;
}
}
else
{
item.DateCreated = DateTime.UtcNow;
}
if (info is not null && !info.IsDirectory)
{
item.Size = info.Length;
}
var fileModificationDate = info?.LastWriteTimeUtc;
if (fileModificationDate.HasValue)
{
item.DateModified = fileModificationDate.Value;
}
}
}
}

View File

@@ -54,9 +54,9 @@ namespace Emby.Server.Implementations.Library.Resolvers
_ => _videoResolvers
};
public bool TryGetExtraTypeForOwner(string path, VideoFileInfo ownerVideoFileInfo, [NotNullWhen(true)] out ExtraType? extraType)
public bool TryGetExtraTypeForOwner(string path, VideoFileInfo ownerVideoFileInfo, [NotNullWhen(true)] out ExtraType? extraType, string? libraryRoot = "")
{
var extraResult = GetExtraInfo(path, _namingOptions);
var extraResult = GetExtraInfo(path, _namingOptions, libraryRoot);
if (extraResult.ExtraType is null)
{
extraType = null;

View File

@@ -270,11 +270,11 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
}
var videoInfos = files
.Select(i => VideoResolver.Resolve(i.FullName, i.IsDirectory, NamingOptions, parseName))
.Select(i => VideoResolver.Resolve(i.FullName, i.IsDirectory, NamingOptions, parseName, parent.ContainingFolderPath))
.Where(f => f is not null)
.ToList();
var resolverResult = VideoListResolver.Resolve(videoInfos, NamingOptions, supportMultiEditions, parseName);
var resolverResult = VideoListResolver.Resolve(videoInfos, NamingOptions, supportMultiEditions, parseName, parent.ContainingFolderPath);
var result = new MultiItemResolverResult
{
@@ -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
@@ -456,12 +464,17 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
{
var videoPath = result.Items[0].Path;
var hasPhotos = photos.Any(i => !PhotoResolver.IsOwnedByResolvedMedia(videoPath, i.Name));
var hasOtherSubfolders = multiDiscFolders.Count > 0;
if (!hasPhotos)
if (!hasPhotos && !hasOtherSubfolders)
{
var movie = (T)result.Items[0];
movie.IsInMixedFolder = false;
movie.Name = Path.GetFileName(movie.ContainingFolderPath);
if (collectionType == CollectionType.movies || collectionType is null)
{
movie.Name = Path.GetFileName(movie.ContainingFolderPath);
}
return movie;
}
}

View File

@@ -28,7 +28,7 @@ namespace Emby.Server.Implementations.Library.Resolvers
{
if (args.IsDirectory)
{
// It's a boxset if the path is a directory with [playlist] in its name
// It's a playlist if the path is a directory with [playlist] in its name
var filename = Path.GetFileName(Path.TrimEndingDirectorySeparator(args.Path));
if (string.IsNullOrEmpty(filename))
{

View File

@@ -48,7 +48,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV
var path = args.Path;
var seasonParserResult = SeasonPathParser.Parse(path, true, true);
var seasonParserResult = SeasonPathParser.Parse(path, series.ContainingFolderPath, true, true);
var season = new Season
{

View File

@@ -118,7 +118,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV
{
if (child.IsDirectory)
{
if (IsSeasonFolder(child.FullName, isTvContentType))
if (IsSeasonFolder(child.FullName, path, isTvContentType))
{
_logger.LogDebug("{Path} is a series because of season folder {Dir}.", path, child.FullName);
return true;
@@ -155,11 +155,12 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV
/// Determines whether [is season folder] [the specified path].
/// </summary>
/// <param name="path">The path.</param>
/// <param name="parentPath">The parentpath.</param>
/// <param name="isTvContentType">if set to <c>true</c> [is tv content type].</param>
/// <returns><c>true</c> if [is season folder] [the specified path]; otherwise, <c>false</c>.</returns>
private static bool IsSeasonFolder(string path, bool isTvContentType)
private static bool IsSeasonFolder(string path, string parentPath, bool isTvContentType)
{
var seasonNumber = SeasonPathParser.Parse(path, isTvContentType, isTvContentType).SeasonNumber;
var seasonNumber = SeasonPathParser.Parse(path, parentPath, isTvContentType, isTvContentType).SeasonNumber;
return seasonNumber.HasValue;
}

View File

@@ -3,8 +3,9 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Jellyfin.Data.Entities;
using Jellyfin.Data.Enums;
using Jellyfin.Database.Implementations.Entities;
using Jellyfin.Database.Implementations.Enums;
using Jellyfin.Extensions;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities;
@@ -171,7 +172,7 @@ namespace Emby.Server.Implementations.Library
}
};
List<BaseItem> mediaItems;
IReadOnlyList<BaseItem> mediaItems;
if (searchQuery.IncludeItemTypes.Length == 1 && searchQuery.IncludeItemTypes[0] == BaseItemKind.MusicArtist)
{

View File

@@ -4,13 +4,13 @@ using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Jellyfin.Data.Enums;
using Jellyfin.Database.Implementations.Enums;
using MediaBrowser.Controller.Drawing;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Persistence;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Querying;
using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.Library;
@@ -43,14 +43,26 @@ public class SplashscreenPostScanTask : ILibraryPostScanTask
/// <inheritdoc />
public Task Run(IProgress<double> progress, CancellationToken cancellationToken)
{
var posters = GetItemsWithImageType(ImageType.Primary).Select(x => x.GetImages(ImageType.Primary).First().Path).ToList();
var backdrops = GetItemsWithImageType(ImageType.Thumb).Select(x => x.GetImages(ImageType.Thumb).First().Path).ToList();
var posters = GetItemsWithImageType(ImageType.Primary)
.Select(x => x.GetImages(ImageType.Primary).FirstOrDefault()?.Path)
.Where(path => !string.IsNullOrEmpty(path))
.Select(path => path!)
.ToList();
var backdrops = GetItemsWithImageType(ImageType.Thumb)
.Select(x => x.GetImages(ImageType.Thumb).FirstOrDefault()?.Path)
.Where(path => !string.IsNullOrEmpty(path))
.Select(path => path!)
.ToList();
if (backdrops.Count == 0)
{
// Thumb images fit better because they include the title in the image but are not provided with TMDb.
// Using backdrops as a fallback to generate an image at all
_logger.LogDebug("No thumb images found. Using backdrops to generate splashscreen");
backdrops = GetItemsWithImageType(ImageType.Backdrop).Select(x => x.GetImages(ImageType.Backdrop).First().Path).ToList();
backdrops = GetItemsWithImageType(ImageType.Backdrop)
.Select(x => x.GetImages(ImageType.Backdrop).FirstOrDefault()?.Path)
.Where(path => !string.IsNullOrEmpty(path))
.Select(path => path!)
.ToList();
}
_imageEncoder.CreateSplashscreen(posters, backdrops);
@@ -65,15 +77,15 @@ public class SplashscreenPostScanTask : ILibraryPostScanTask
CollapseBoxSetItems = false,
Recursive = true,
DtoOptions = new DtoOptions(false),
ImageTypes = new[] { imageType },
ImageTypes = [imageType],
Limit = 30,
// TODO max parental rating configurable
MaxParentalRating = 10,
OrderBy = new[]
{
MaxParentalRating = new(10, null),
OrderBy =
[
(ItemSortBy.Random, SortOrder.Ascending)
},
IncludeItemTypes = new[] { BaseItemKind.Movie, BaseItemKind.Series }
],
IncludeItemTypes = [BaseItemKind.Movie, BaseItemKind.Series]
});
}
}

View File

@@ -1,17 +1,20 @@
#pragma warning disable RS0030 // Do not use banned APIs
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Threading;
using Jellyfin.Data.Entities;
using BitFaster.Caching.Lru;
using Jellyfin.Database.Implementations;
using Jellyfin.Database.Implementations.Entities;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Persistence;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
using Microsoft.EntityFrameworkCore;
using AudioBook = MediaBrowser.Controller.Entities.AudioBook;
using Book = MediaBrowser.Controller.Entities.Book;
@@ -22,27 +25,22 @@ namespace Emby.Server.Implementations.Library
/// </summary>
public class UserDataManager : IUserDataManager
{
private readonly ConcurrentDictionary<string, UserItemData> _userData =
new ConcurrentDictionary<string, UserItemData>(StringComparer.OrdinalIgnoreCase);
private readonly IServerConfigurationManager _config;
private readonly IUserManager _userManager;
private readonly IUserDataRepository _repository;
private readonly IDbContextFactory<JellyfinDbContext> _repository;
private readonly FastConcurrentLru<string, UserItemData> _cache;
/// <summary>
/// Initializes a new instance of the <see cref="UserDataManager"/> class.
/// </summary>
/// <param name="config">Instance of the <see cref="IServerConfigurationManager"/> interface.</param>
/// <param name="userManager">Instance of the <see cref="IUserManager"/> interface.</param>
/// <param name="repository">Instance of the <see cref="IUserDataRepository"/> interface.</param>
/// <param name="repository">Instance of the <see cref="IDbContextFactory{JellyfinDbContext}"/> interface.</param>
public UserDataManager(
IServerConfigurationManager config,
IUserManager userManager,
IUserDataRepository repository)
IDbContextFactory<JellyfinDbContext> repository)
{
_config = config;
_userManager = userManager;
_repository = repository;
_cache = new FastConcurrentLru<string, UserItemData>(Environment.ProcessorCount, _config.Configuration.CacheSize, StringComparer.OrdinalIgnoreCase);
}
/// <inheritdoc />
@@ -59,15 +57,30 @@ namespace Emby.Server.Implementations.Library
var keys = item.GetUserDataKeys();
var userId = user.InternalId;
using var dbContext = _repository.CreateDbContext();
using var transaction = dbContext.Database.BeginTransaction();
foreach (var key in keys)
{
_repository.SaveUserData(userId, key, userData, cancellationToken);
userData.Key = key;
var userDataEntry = Map(userData, user.Id, item.Id);
if (dbContext.UserData.Any(f => f.ItemId == userDataEntry.ItemId && f.UserId == userDataEntry.UserId && f.CustomDataKey == userDataEntry.CustomDataKey))
{
dbContext.UserData.Attach(userDataEntry).State = EntityState.Modified;
}
else
{
dbContext.UserData.Add(userDataEntry);
}
}
dbContext.SaveChanges();
transaction.Commit();
var userId = user.InternalId;
var cacheKey = GetCacheKey(userId, item.Id);
_userData.AddOrUpdate(cacheKey, userData, (_, _) => userData);
_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
{
@@ -84,10 +97,9 @@ namespace Emby.Server.Implementations.Library
{
ArgumentNullException.ThrowIfNull(user);
ArgumentNullException.ThrowIfNull(item);
ArgumentNullException.ThrowIfNull(reason);
ArgumentNullException.ThrowIfNull(userDataDto);
var userData = GetUserData(user, item);
var userData = GetUserData(user, item) ?? throw new InvalidOperationException("UserData should not be null.");
if (userDataDto.PlaybackPositionTicks.HasValue)
{
@@ -127,33 +139,91 @@ namespace Emby.Server.Implementations.Library
SaveUserData(user, item, userData, reason, CancellationToken.None);
}
private UserItemData GetUserData(User user, Guid itemId, List<string> keys)
private UserData Map(UserItemData dto, Guid userId, Guid itemId)
{
var userId = user.InternalId;
var cacheKey = GetCacheKey(userId, itemId);
return _userData.GetOrAdd(cacheKey, _ => GetUserDataInternal(userId, keys));
return new UserData()
{
ItemId = itemId,
CustomDataKey = dto.Key,
Item = null,
User = null,
AudioStreamIndex = dto.AudioStreamIndex,
IsFavorite = dto.IsFavorite,
LastPlayedDate = dto.LastPlayedDate,
Likes = dto.Likes,
PlaybackPositionTicks = dto.PlaybackPositionTicks,
PlayCount = dto.PlayCount,
Played = dto.Played,
Rating = dto.Rating,
UserId = userId,
SubtitleStreamIndex = dto.SubtitleStreamIndex,
};
}
private UserItemData GetUserDataInternal(long internalUserId, List<string> keys)
private static UserItemData Map(UserData dto)
{
var userData = _repository.GetUserData(internalUserId, keys);
if (userData is not null)
return new UserItemData()
{
return userData;
Key = dto.CustomDataKey!,
AudioStreamIndex = dto.AudioStreamIndex,
IsFavorite = dto.IsFavorite,
LastPlayedDate = dto.LastPlayedDate,
Likes = dto.Likes,
PlaybackPositionTicks = dto.PlaybackPositionTicks,
PlayCount = dto.PlayCount,
Played = dto.Played,
Rating = dto.Rating,
SubtitleStreamIndex = dto.SubtitleStreamIndex,
};
}
private UserItemData? GetUserData(User user, Guid itemId, List<string> keys)
{
var cacheKey = GetCacheKey(user.InternalId, itemId);
if (_cache.TryGet(cacheKey, out var data))
{
return data;
}
if (keys.Count > 0)
data = GetUserDataInternal(user.Id, itemId, keys);
if (data is null)
{
return new UserItemData
return new UserItemData()
{
Key = keys[0]
Key = keys[0],
};
}
throw new UnreachableException();
return _cache.GetOrAdd(cacheKey, _ => data);
}
private UserItemData? GetUserDataInternal(Guid userId, Guid itemId, List<string> keys)
{
if (keys.Count == 0)
{
return null;
}
using var context = _repository.CreateDbContext();
var userData = context.UserData.AsNoTracking().Where(e => e.ItemId == itemId && keys.Contains(e.CustomDataKey) && e.UserId.Equals(userId)).ToArray();
if (userData.Length > 0)
{
var directDataReference = userData.FirstOrDefault(e => e.CustomDataKey == itemId.ToString("N"));
if (directDataReference is not null)
{
return Map(directDataReference);
}
return Map(userData.First());
}
return new UserItemData
{
Key = keys.Last()!
};
}
/// <summary>
@@ -166,20 +236,28 @@ namespace Emby.Server.Implementations.Library
}
/// <inheritdoc />
public UserItemData GetUserData(User user, BaseItem item)
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 />
public UserItemDataDto GetUserDataDto(BaseItem item, User user)
public UserItemDataDto? GetUserDataDto(BaseItem item, User user)
=> GetUserDataDto(item, null, user, new DtoOptions());
/// <inheritdoc />
public UserItemDataDto GetUserDataDto(BaseItem item, BaseItemDto? itemDto, User user, DtoOptions options)
public UserItemDataDto? GetUserDataDto(BaseItem item, BaseItemDto? itemDto, User user, DtoOptions options)
{
var userData = GetUserData(user, item);
var dto = GetUserItemDataDto(userData);
if (userData is null)
{
return null;
}
var dto = GetUserItemDataDto(userData, item.Id);
item.FillUserDataDtoValues(dto, userData, itemDto, user, options);
return dto;
@@ -189,9 +267,10 @@ namespace Emby.Server.Implementations.Library
/// Converts a UserItemData to a DTOUserItemData.
/// </summary>
/// <param name="data">The data.</param>
/// <param name="itemId">The reference key to an Item.</param>
/// <returns>DtoUserItemData.</returns>
/// <exception cref="ArgumentNullException"><paramref name="data"/> is <c>null</c>.</exception>
private UserItemDataDto GetUserItemDataDto(UserItemData data)
private UserItemDataDto GetUserItemDataDto(UserItemData data, Guid itemId)
{
ArgumentNullException.ThrowIfNull(data);
@@ -204,6 +283,7 @@ namespace Emby.Server.Implementations.Library
Rating = data.Rating,
Played = data.Played,
LastPlayedDate = data.LastPlayedDate,
ItemId = itemId,
Key = data.Key
};
}
@@ -228,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

@@ -6,8 +6,10 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using Jellyfin.Data.Entities;
using Jellyfin.Data;
using Jellyfin.Data.Enums;
using Jellyfin.Database.Implementations.Entities;
using Jellyfin.Database.Implementations.Enums;
using Jellyfin.Extensions;
using MediaBrowser.Controller.Channels;
using MediaBrowser.Controller.Configuration;
@@ -308,39 +310,40 @@ namespace Emby.Server.Implementations.Library
}
}
var mediaTypes = new List<MediaType>();
MediaType[] mediaTypes = [];
if (includeItemTypes.Length == 0)
{
HashSet<MediaType> tmpMediaTypes = [];
foreach (var parent in parents.OfType<ICollectionFolder>())
{
switch (parent.CollectionType)
{
case CollectionType.books:
mediaTypes.Add(MediaType.Book);
mediaTypes.Add(MediaType.Audio);
tmpMediaTypes.Add(MediaType.Book);
tmpMediaTypes.Add(MediaType.Audio);
break;
case CollectionType.music:
mediaTypes.Add(MediaType.Audio);
tmpMediaTypes.Add(MediaType.Audio);
break;
case CollectionType.photos:
mediaTypes.Add(MediaType.Photo);
mediaTypes.Add(MediaType.Video);
tmpMediaTypes.Add(MediaType.Photo);
tmpMediaTypes.Add(MediaType.Video);
break;
case CollectionType.homevideos:
mediaTypes.Add(MediaType.Photo);
mediaTypes.Add(MediaType.Video);
tmpMediaTypes.Add(MediaType.Photo);
tmpMediaTypes.Add(MediaType.Video);
break;
default:
mediaTypes.Add(MediaType.Video);
tmpMediaTypes.Add(MediaType.Video);
break;
}
}
mediaTypes = mediaTypes.Distinct().ToList();
mediaTypes = tmpMediaTypes.ToArray();
}
var excludeItemTypes = includeItemTypes.Length == 0 && mediaTypes.Count == 0
var excludeItemTypes = includeItemTypes.Length == 0 && mediaTypes.Length == 0
? new[]
{
BaseItemKind.Person,
@@ -366,12 +369,31 @@ namespace Emby.Server.Implementations.Library
Limit = limit * 5,
IsPlayed = isPlayed,
DtoOptions = options,
MediaTypes = mediaTypes.ToArray()
MediaTypes = mediaTypes
};
if (parents.Count == 0)
if (request.GroupItems)
{
return _libraryManager.GetItemList(query, false);
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 (collectionType == CollectionType.music)
{
query.Limit = limit;
return _libraryManager.GetLatestItemList(query, parents, CollectionType.music);
}
}
return _libraryManager.GetItemList(query, parents);

View File

@@ -5,45 +5,44 @@ using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Persistence;
using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.Library.Validators
namespace Emby.Server.Implementations.Library.Validators;
/// <summary>
/// Class ArtistsPostScanTask.
/// </summary>
public class ArtistsPostScanTask : ILibraryPostScanTask
{
/// <summary>
/// Class ArtistsPostScanTask.
/// The _library manager.
/// </summary>
public class ArtistsPostScanTask : ILibraryPostScanTask
private readonly ILibraryManager _libraryManager;
private readonly ILogger<ArtistsValidator> _logger;
private readonly IItemRepository _itemRepo;
/// <summary>
/// Initializes a new instance of the <see cref="ArtistsPostScanTask" /> class.
/// </summary>
/// <param name="libraryManager">The library manager.</param>
/// <param name="logger">The logger.</param>
/// <param name="itemRepo">The item repository.</param>
public ArtistsPostScanTask(
ILibraryManager libraryManager,
ILogger<ArtistsValidator> logger,
IItemRepository itemRepo)
{
/// <summary>
/// The _library manager.
/// </summary>
private readonly ILibraryManager _libraryManager;
private readonly ILogger<ArtistsValidator> _logger;
private readonly IItemRepository _itemRepo;
_libraryManager = libraryManager;
_logger = logger;
_itemRepo = itemRepo;
}
/// <summary>
/// Initializes a new instance of the <see cref="ArtistsPostScanTask" /> class.
/// </summary>
/// <param name="libraryManager">The library manager.</param>
/// <param name="logger">The logger.</param>
/// <param name="itemRepo">The item repository.</param>
public ArtistsPostScanTask(
ILibraryManager libraryManager,
ILogger<ArtistsValidator> logger,
IItemRepository itemRepo)
{
_libraryManager = libraryManager;
_logger = logger;
_itemRepo = itemRepo;
}
/// <summary>
/// Runs the specified progress.
/// </summary>
/// <param name="progress">The progress.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
public Task Run(IProgress<double> progress, CancellationToken cancellationToken)
{
return new ArtistsValidator(_libraryManager, _logger, _itemRepo).Run(progress, cancellationToken);
}
/// <summary>
/// Runs the specified progress.
/// </summary>
/// <param name="progress">The progress.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
public Task Run(IProgress<double> progress, CancellationToken cancellationToken)
{
return new ArtistsValidator(_libraryManager, _logger, _itemRepo).Run(progress, cancellationToken);
}
}

View File

@@ -10,102 +10,101 @@ using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Persistence;
using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.Library.Validators
namespace Emby.Server.Implementations.Library.Validators;
/// <summary>
/// Class ArtistsValidator.
/// </summary>
public class ArtistsValidator
{
/// <summary>
/// Class ArtistsValidator.
/// The library manager.
/// </summary>
public class ArtistsValidator
private readonly ILibraryManager _libraryManager;
/// <summary>
/// The logger.
/// </summary>
private readonly ILogger<ArtistsValidator> _logger;
private readonly IItemRepository _itemRepo;
/// <summary>
/// Initializes a new instance of the <see cref="ArtistsValidator" /> class.
/// </summary>
/// <param name="libraryManager">The library manager.</param>
/// <param name="logger">The logger.</param>
/// <param name="itemRepo">The item repository.</param>
public ArtistsValidator(ILibraryManager libraryManager, ILogger<ArtistsValidator> logger, IItemRepository itemRepo)
{
/// <summary>
/// The library manager.
/// </summary>
private readonly ILibraryManager _libraryManager;
_libraryManager = libraryManager;
_logger = logger;
_itemRepo = itemRepo;
}
/// <summary>
/// The logger.
/// </summary>
private readonly ILogger<ArtistsValidator> _logger;
private readonly IItemRepository _itemRepo;
/// <summary>
/// Runs the specified progress.
/// </summary>
/// <param name="progress">The progress.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
public async Task Run(IProgress<double> progress, CancellationToken cancellationToken)
{
var names = _itemRepo.GetAllArtistNames();
/// <summary>
/// Initializes a new instance of the <see cref="ArtistsValidator" /> class.
/// </summary>
/// <param name="libraryManager">The library manager.</param>
/// <param name="logger">The logger.</param>
/// <param name="itemRepo">The item repository.</param>
public ArtistsValidator(ILibraryManager libraryManager, ILogger<ArtistsValidator> logger, IItemRepository itemRepo)
var numComplete = 0;
var count = names.Count;
foreach (var name in names)
{
_libraryManager = libraryManager;
_logger = logger;
_itemRepo = itemRepo;
}
/// <summary>
/// Runs the specified progress.
/// </summary>
/// <param name="progress">The progress.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
public async Task Run(IProgress<double> progress, CancellationToken cancellationToken)
{
var names = _itemRepo.GetAllArtistNames();
var numComplete = 0;
var count = names.Count;
foreach (var name in names)
try
{
try
{
var item = _libraryManager.GetArtist(name);
var item = _libraryManager.GetArtist(name);
await item.RefreshMetadata(cancellationToken).ConfigureAwait(false);
}
catch (OperationCanceledException)
{
// Don't clutter the log
throw;
}
catch (Exception ex)
{
_logger.LogError(ex, "Error refreshing {ArtistName}", name);
}
numComplete++;
double percent = numComplete;
percent /= count;
percent *= 100;
progress.Report(percent);
await item.RefreshMetadata(cancellationToken).ConfigureAwait(false);
}
catch (OperationCanceledException)
{
// Don't clutter the log
throw;
}
catch (Exception ex)
{
_logger.LogError(ex, "Error refreshing {ArtistName}", name);
}
var deadEntities = _libraryManager.GetItemList(new InternalItemsQuery
numComplete++;
double percent = numComplete;
percent /= count;
percent *= 100;
progress.Report(percent);
}
var deadEntities = _libraryManager.GetItemList(new InternalItemsQuery
{
IncludeItemTypes = [BaseItemKind.MusicArtist],
IsDeadArtist = true,
IsLocked = false
}).Cast<MusicArtist>().ToList();
foreach (var item in deadEntities)
{
if (!item.IsAccessedByName)
{
IncludeItemTypes = new[] { BaseItemKind.MusicArtist },
IsDeadArtist = true,
IsLocked = false
}).Cast<MusicArtist>().ToList();
foreach (var item in deadEntities)
{
if (!item.IsAccessedByName)
{
continue;
}
_logger.LogInformation("Deleting dead {2} {0} {1}.", item.Id.ToString("N", CultureInfo.InvariantCulture), item.Name, item.GetType().Name);
_libraryManager.DeleteItem(
item,
new DeleteOptions
{
DeleteFileLocation = false
},
false);
continue;
}
progress.Report(100);
_logger.LogInformation("Deleting dead {ItemType} {ItemId} {ItemName}", item.GetType().Name, item.Id.ToString("N", CultureInfo.InvariantCulture), item.Name);
_libraryManager.DeleteItem(
item,
new DeleteOptions
{
DeleteFileLocation = false
},
false);
}
progress.Report(100);
}
}

View File

@@ -4,153 +4,150 @@ using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Jellyfin.Data.Enums;
using Jellyfin.Database.Implementations.Enums;
using MediaBrowser.Controller.Collections;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Movies;
using MediaBrowser.Controller.Library;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Querying;
using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.Library.Validators
namespace Emby.Server.Implementations.Library.Validators;
/// <summary>
/// Class CollectionPostScanTask.
/// </summary>
public class CollectionPostScanTask : ILibraryPostScanTask
{
private readonly ILibraryManager _libraryManager;
private readonly ICollectionManager _collectionManager;
private readonly ILogger<CollectionPostScanTask> _logger;
/// <summary>
/// Class CollectionPostScanTask.
/// Initializes a new instance of the <see cref="CollectionPostScanTask" /> class.
/// </summary>
public class CollectionPostScanTask : ILibraryPostScanTask
/// <param name="libraryManager">The library manager.</param>
/// <param name="collectionManager">The collection manager.</param>
/// <param name="logger">The logger.</param>
public CollectionPostScanTask(
ILibraryManager libraryManager,
ICollectionManager collectionManager,
ILogger<CollectionPostScanTask> logger)
{
private readonly ILibraryManager _libraryManager;
private readonly ICollectionManager _collectionManager;
private readonly ILogger<CollectionPostScanTask> _logger;
_libraryManager = libraryManager;
_collectionManager = collectionManager;
_logger = logger;
}
/// <summary>
/// Initializes a new instance of the <see cref="CollectionPostScanTask" /> class.
/// </summary>
/// <param name="libraryManager">The library manager.</param>
/// <param name="collectionManager">The collection manager.</param>
/// <param name="logger">The logger.</param>
public CollectionPostScanTask(
ILibraryManager libraryManager,
ICollectionManager collectionManager,
ILogger<CollectionPostScanTask> logger)
/// <summary>
/// Runs the specified progress.
/// </summary>
/// <param name="progress">The progress.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
public async Task Run(IProgress<double> progress, CancellationToken cancellationToken)
{
var collectionNameMoviesMap = new Dictionary<string, HashSet<Guid>>();
foreach (var library in _libraryManager.RootFolder.Children)
{
_libraryManager = libraryManager;
_collectionManager = collectionManager;
_logger = logger;
if (!_libraryManager.GetLibraryOptions(library).AutomaticallyAddToCollection)
{
continue;
}
var startIndex = 0;
var pagesize = 1000;
while (true)
{
var movies = _libraryManager.GetItemList(new InternalItemsQuery
{
MediaTypes = [MediaType.Video],
IncludeItemTypes = [BaseItemKind.Movie],
IsVirtualItem = false,
OrderBy = [(ItemSortBy.SortName, SortOrder.Ascending)],
Parent = library,
StartIndex = startIndex,
Limit = pagesize,
Recursive = true
});
foreach (var m in movies)
{
if (m is Movie movie && !string.IsNullOrEmpty(movie.CollectionName))
{
if (collectionNameMoviesMap.TryGetValue(movie.CollectionName, out var movieList))
{
movieList.Add(movie.Id);
}
else
{
collectionNameMoviesMap[movie.CollectionName] = new HashSet<Guid> { movie.Id };
}
}
}
if (movies.Count < pagesize)
{
break;
}
startIndex += pagesize;
}
}
/// <summary>
/// Runs the specified progress.
/// </summary>
/// <param name="progress">The progress.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
public async Task Run(IProgress<double> progress, CancellationToken cancellationToken)
var numComplete = 0;
var count = collectionNameMoviesMap.Count;
if (count == 0)
{
var collectionNameMoviesMap = new Dictionary<string, HashSet<Guid>>();
foreach (var library in _libraryManager.RootFolder.Children)
{
if (!_libraryManager.GetLibraryOptions(library).AutomaticallyAddToCollection)
{
continue;
}
var startIndex = 0;
var pagesize = 1000;
while (true)
{
var movies = _libraryManager.GetItemList(new InternalItemsQuery
{
MediaTypes = new[] { MediaType.Video },
IncludeItemTypes = new[] { BaseItemKind.Movie },
IsVirtualItem = false,
OrderBy = new[] { (ItemSortBy.SortName, SortOrder.Ascending) },
Parent = library,
StartIndex = startIndex,
Limit = pagesize,
Recursive = true
});
foreach (var m in movies)
{
if (m is Movie movie && !string.IsNullOrEmpty(movie.CollectionName))
{
if (collectionNameMoviesMap.TryGetValue(movie.CollectionName, out var movieList))
{
movieList.Add(movie.Id);
}
else
{
collectionNameMoviesMap[movie.CollectionName] = new HashSet<Guid> { movie.Id };
}
}
}
if (movies.Count < pagesize)
{
break;
}
startIndex += pagesize;
}
}
var numComplete = 0;
var count = collectionNameMoviesMap.Count;
if (count == 0)
{
progress.Report(100);
return;
}
var boxSets = _libraryManager.GetItemList(new InternalItemsQuery
{
IncludeItemTypes = new[] { BaseItemKind.BoxSet },
CollapseBoxSetItems = false,
Recursive = true
});
foreach (var (collectionName, movieIds) in collectionNameMoviesMap)
{
try
{
var boxSet = boxSets.FirstOrDefault(b => b?.Name == collectionName) as BoxSet;
if (boxSet is null)
{
// won't automatically create collection if only one movie in it
if (movieIds.Count >= 2)
{
boxSet = await _collectionManager.CreateCollectionAsync(new CollectionCreationOptions
{
Name = collectionName,
IsLocked = true
});
await _collectionManager.AddToCollectionAsync(boxSet.Id, movieIds);
}
}
else
{
await _collectionManager.AddToCollectionAsync(boxSet.Id, movieIds);
}
numComplete++;
double percent = numComplete;
percent /= count;
percent *= 100;
progress.Report(percent);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error refreshing {CollectionName} with {@MovieIds}", collectionName, movieIds);
}
}
progress.Report(100);
return;
}
var boxSets = _libraryManager.GetItemList(new InternalItemsQuery
{
IncludeItemTypes = [BaseItemKind.BoxSet],
CollapseBoxSetItems = false,
Recursive = true
});
foreach (var (collectionName, movieIds) in collectionNameMoviesMap)
{
try
{
var boxSet = boxSets.FirstOrDefault(b => b?.Name == collectionName) as BoxSet;
if (boxSet is null)
{
// won't automatically create collection if only one movie in it
if (movieIds.Count >= 2)
{
boxSet = await _collectionManager.CreateCollectionAsync(new CollectionCreationOptions
{
Name = collectionName,
}).ConfigureAwait(false);
await _collectionManager.AddToCollectionAsync(boxSet.Id, movieIds).ConfigureAwait(false);
}
}
else
{
await _collectionManager.AddToCollectionAsync(boxSet.Id, movieIds).ConfigureAwait(false);
}
numComplete++;
double percent = numComplete;
percent /= count;
percent *= 100;
progress.Report(percent);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error refreshing {CollectionName} with {@MovieIds}", collectionName, movieIds);
}
}
progress.Report(100);
}
}

View File

@@ -5,45 +5,44 @@ using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Persistence;
using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.Library.Validators
namespace Emby.Server.Implementations.Library.Validators;
/// <summary>
/// Class GenresPostScanTask.
/// </summary>
public class GenresPostScanTask : ILibraryPostScanTask
{
/// <summary>
/// Class GenresPostScanTask.
/// The _library manager.
/// </summary>
public class GenresPostScanTask : ILibraryPostScanTask
private readonly ILibraryManager _libraryManager;
private readonly ILogger<GenresValidator> _logger;
private readonly IItemRepository _itemRepo;
/// <summary>
/// Initializes a new instance of the <see cref="GenresPostScanTask" /> class.
/// </summary>
/// <param name="libraryManager">The library manager.</param>
/// <param name="logger">The logger.</param>
/// <param name="itemRepo">The item repository.</param>
public GenresPostScanTask(
ILibraryManager libraryManager,
ILogger<GenresValidator> logger,
IItemRepository itemRepo)
{
/// <summary>
/// The _library manager.
/// </summary>
private readonly ILibraryManager _libraryManager;
private readonly ILogger<GenresValidator> _logger;
private readonly IItemRepository _itemRepo;
_libraryManager = libraryManager;
_logger = logger;
_itemRepo = itemRepo;
}
/// <summary>
/// Initializes a new instance of the <see cref="GenresPostScanTask" /> class.
/// </summary>
/// <param name="libraryManager">The library manager.</param>
/// <param name="logger">The logger.</param>
/// <param name="itemRepo">The item repository.</param>
public GenresPostScanTask(
ILibraryManager libraryManager,
ILogger<GenresValidator> logger,
IItemRepository itemRepo)
{
_libraryManager = libraryManager;
_logger = logger;
_itemRepo = itemRepo;
}
/// <summary>
/// Runs the specified progress.
/// </summary>
/// <param name="progress">The progress.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
public Task Run(IProgress<double> progress, CancellationToken cancellationToken)
{
return new GenresValidator(_libraryManager, _logger, _itemRepo).Run(progress, cancellationToken);
}
/// <summary>
/// Runs the specified progress.
/// </summary>
/// <param name="progress">The progress.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
public Task Run(IProgress<double> progress, CancellationToken cancellationToken)
{
return new GenresValidator(_libraryManager, _logger, _itemRepo).Run(progress, cancellationToken);
}
}

View File

@@ -1,81 +1,103 @@
using System;
using System.Globalization;
using System.Threading;
using System.Threading.Tasks;
using Jellyfin.Data.Enums;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Persistence;
using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.Library.Validators
namespace Emby.Server.Implementations.Library.Validators;
/// <summary>
/// Class GenresValidator.
/// </summary>
public class GenresValidator
{
/// <summary>
/// Class GenresValidator.
/// The library manager.
/// </summary>
public class GenresValidator
private readonly ILibraryManager _libraryManager;
private readonly IItemRepository _itemRepo;
/// <summary>
/// The logger.
/// </summary>
private readonly ILogger<GenresValidator> _logger;
/// <summary>
/// Initializes a new instance of the <see cref="GenresValidator"/> class.
/// </summary>
/// <param name="libraryManager">The library manager.</param>
/// <param name="logger">The logger.</param>
/// <param name="itemRepo">The item repository.</param>
public GenresValidator(ILibraryManager libraryManager, ILogger<GenresValidator> logger, IItemRepository itemRepo)
{
/// <summary>
/// The library manager.
/// </summary>
private readonly ILibraryManager _libraryManager;
private readonly IItemRepository _itemRepo;
_libraryManager = libraryManager;
_logger = logger;
_itemRepo = itemRepo;
}
/// <summary>
/// The logger.
/// </summary>
private readonly ILogger<GenresValidator> _logger;
/// <summary>
/// Runs the specified progress.
/// </summary>
/// <param name="progress">The progress.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
public async Task Run(IProgress<double> progress, CancellationToken cancellationToken)
{
var names = _itemRepo.GetGenreNames();
/// <summary>
/// Initializes a new instance of the <see cref="GenresValidator"/> class.
/// </summary>
/// <param name="libraryManager">The library manager.</param>
/// <param name="logger">The logger.</param>
/// <param name="itemRepo">The item repository.</param>
public GenresValidator(ILibraryManager libraryManager, ILogger<GenresValidator> logger, IItemRepository itemRepo)
var numComplete = 0;
var count = names.Count;
foreach (var name in names)
{
_libraryManager = libraryManager;
_logger = logger;
_itemRepo = itemRepo;
}
/// <summary>
/// Runs the specified progress.
/// </summary>
/// <param name="progress">The progress.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
public async Task Run(IProgress<double> progress, CancellationToken cancellationToken)
{
var names = _itemRepo.GetGenreNames();
var numComplete = 0;
var count = names.Count;
foreach (var name in names)
try
{
try
{
var item = _libraryManager.GetGenre(name);
var item = _libraryManager.GetGenre(name);
await item.RefreshMetadata(cancellationToken).ConfigureAwait(false);
}
catch (OperationCanceledException)
{
// Don't clutter the log
throw;
}
catch (Exception ex)
{
_logger.LogError(ex, "Error refreshing {GenreName}", name);
}
numComplete++;
double percent = numComplete;
percent /= count;
percent *= 100;
progress.Report(percent);
await item.RefreshMetadata(cancellationToken).ConfigureAwait(false);
}
catch (OperationCanceledException)
{
// Don't clutter the log
throw;
}
catch (Exception ex)
{
_logger.LogError(ex, "Error refreshing {GenreName}", name);
}
progress.Report(100);
numComplete++;
double percent = numComplete;
percent /= count;
percent *= 100;
progress.Report(percent);
}
var deadEntities = _libraryManager.GetItemList(new InternalItemsQuery
{
IncludeItemTypes = [BaseItemKind.Genre, BaseItemKind.MusicGenre],
IsDeadGenre = true,
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);
_libraryManager.DeleteItem(
item,
new DeleteOptions
{
DeleteFileLocation = false
},
false);
}
progress.Report(100);
}
}

View File

@@ -5,45 +5,44 @@ using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Persistence;
using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.Library.Validators
namespace Emby.Server.Implementations.Library.Validators;
/// <summary>
/// Class MusicGenresPostScanTask.
/// </summary>
public class MusicGenresPostScanTask : ILibraryPostScanTask
{
/// <summary>
/// Class MusicGenresPostScanTask.
/// The library manager.
/// </summary>
public class MusicGenresPostScanTask : ILibraryPostScanTask
private readonly ILibraryManager _libraryManager;
private readonly ILogger<MusicGenresValidator> _logger;
private readonly IItemRepository _itemRepo;
/// <summary>
/// Initializes a new instance of the <see cref="MusicGenresPostScanTask" /> class.
/// </summary>
/// <param name="libraryManager">The library manager.</param>
/// <param name="logger">The logger.</param>
/// <param name="itemRepo">The item repository.</param>
public MusicGenresPostScanTask(
ILibraryManager libraryManager,
ILogger<MusicGenresValidator> logger,
IItemRepository itemRepo)
{
/// <summary>
/// The library manager.
/// </summary>
private readonly ILibraryManager _libraryManager;
private readonly ILogger<MusicGenresValidator> _logger;
private readonly IItemRepository _itemRepo;
_libraryManager = libraryManager;
_logger = logger;
_itemRepo = itemRepo;
}
/// <summary>
/// Initializes a new instance of the <see cref="MusicGenresPostScanTask" /> class.
/// </summary>
/// <param name="libraryManager">The library manager.</param>
/// <param name="logger">The logger.</param>
/// <param name="itemRepo">The item repository.</param>
public MusicGenresPostScanTask(
ILibraryManager libraryManager,
ILogger<MusicGenresValidator> logger,
IItemRepository itemRepo)
{
_libraryManager = libraryManager;
_logger = logger;
_itemRepo = itemRepo;
}
/// <summary>
/// Runs the specified progress.
/// </summary>
/// <param name="progress">The progress.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
public Task Run(IProgress<double> progress, CancellationToken cancellationToken)
{
return new MusicGenresValidator(_libraryManager, _logger, _itemRepo).Run(progress, cancellationToken);
}
/// <summary>
/// Runs the specified progress.
/// </summary>
/// <param name="progress">The progress.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
public Task Run(IProgress<double> progress, CancellationToken cancellationToken)
{
return new MusicGenresValidator(_libraryManager, _logger, _itemRepo).Run(progress, cancellationToken);
}
}

View File

@@ -5,77 +5,76 @@ using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Persistence;
using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.Library.Validators
namespace Emby.Server.Implementations.Library.Validators;
/// <summary>
/// Class MusicGenresValidator.
/// </summary>
public class MusicGenresValidator
{
/// <summary>
/// Class MusicGenresValidator.
/// The library manager.
/// </summary>
public class MusicGenresValidator
private readonly ILibraryManager _libraryManager;
/// <summary>
/// The logger.
/// </summary>
private readonly ILogger<MusicGenresValidator> _logger;
private readonly IItemRepository _itemRepo;
/// <summary>
/// Initializes a new instance of the <see cref="MusicGenresValidator" /> class.
/// </summary>
/// <param name="libraryManager">The library manager.</param>
/// <param name="logger">The logger.</param>
/// <param name="itemRepo">The item repository.</param>
public MusicGenresValidator(ILibraryManager libraryManager, ILogger<MusicGenresValidator> logger, IItemRepository itemRepo)
{
/// <summary>
/// The library manager.
/// </summary>
private readonly ILibraryManager _libraryManager;
_libraryManager = libraryManager;
_logger = logger;
_itemRepo = itemRepo;
}
/// <summary>
/// The logger.
/// </summary>
private readonly ILogger<MusicGenresValidator> _logger;
private readonly IItemRepository _itemRepo;
/// <summary>
/// Runs the specified progress.
/// </summary>
/// <param name="progress">The progress.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
public async Task Run(IProgress<double> progress, CancellationToken cancellationToken)
{
var names = _itemRepo.GetMusicGenreNames();
/// <summary>
/// Initializes a new instance of the <see cref="MusicGenresValidator" /> class.
/// </summary>
/// <param name="libraryManager">The library manager.</param>
/// <param name="logger">The logger.</param>
/// <param name="itemRepo">The item repository.</param>
public MusicGenresValidator(ILibraryManager libraryManager, ILogger<MusicGenresValidator> logger, IItemRepository itemRepo)
var numComplete = 0;
var count = names.Count;
foreach (var name in names)
{
_libraryManager = libraryManager;
_logger = logger;
_itemRepo = itemRepo;
}
/// <summary>
/// Runs the specified progress.
/// </summary>
/// <param name="progress">The progress.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
public async Task Run(IProgress<double> progress, CancellationToken cancellationToken)
{
var names = _itemRepo.GetMusicGenreNames();
var numComplete = 0;
var count = names.Count;
foreach (var name in names)
try
{
try
{
var item = _libraryManager.GetMusicGenre(name);
var item = _libraryManager.GetMusicGenre(name);
await item.RefreshMetadata(cancellationToken).ConfigureAwait(false);
}
catch (OperationCanceledException)
{
// Don't clutter the log
throw;
}
catch (Exception ex)
{
_logger.LogError(ex, "Error refreshing {GenreName}", name);
}
numComplete++;
double percent = numComplete;
percent /= count;
percent *= 100;
progress.Report(percent);
await item.RefreshMetadata(cancellationToken).ConfigureAwait(false);
}
catch (OperationCanceledException)
{
// Don't clutter the log
throw;
}
catch (Exception ex)
{
_logger.LogError(ex, "Error refreshing {GenreName}", name);
}
progress.Report(100);
numComplete++;
double percent = numComplete;
percent /= count;
percent *= 100;
progress.Report(percent);
}
progress.Report(100);
}
}

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;
@@ -9,119 +9,112 @@ using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.IO;
using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.Library.Validators
namespace Emby.Server.Implementations.Library.Validators;
/// <summary>
/// Class PeopleValidator.
/// </summary>
public class PeopleValidator
{
/// <summary>
/// Class PeopleValidator.
/// The _library manager.
/// </summary>
public class PeopleValidator
private readonly ILibraryManager _libraryManager;
/// <summary>
/// The _logger.
/// </summary>
private readonly ILogger _logger;
private readonly IFileSystem _fileSystem;
/// <summary>
/// Initializes a new instance of the <see cref="PeopleValidator" /> class.
/// </summary>
/// <param name="libraryManager">The library manager.</param>
/// <param name="logger">The logger.</param>
/// <param name="fileSystem">The file system.</param>
public PeopleValidator(ILibraryManager libraryManager, ILogger logger, IFileSystem fileSystem)
{
/// <summary>
/// The _library manager.
/// </summary>
private readonly ILibraryManager _libraryManager;
_libraryManager = libraryManager;
_logger = logger;
_fileSystem = fileSystem;
}
/// <summary>
/// The _logger.
/// </summary>
private readonly ILogger _logger;
/// <summary>
/// Validates the people.
/// </summary>
/// <param name="cancellationToken">The cancellation token.</param>
/// <param name="progress">The progress.</param>
/// <returns>Task.</returns>
public async Task ValidatePeople(CancellationToken cancellationToken, IProgress<double> progress)
{
var people = _libraryManager.GetPeopleNames(new InternalPeopleQuery());
private readonly IFileSystem _fileSystem;
var numComplete = 0;
/// <summary>
/// Initializes a new instance of the <see cref="PeopleValidator" /> class.
/// </summary>
/// <param name="libraryManager">The library manager.</param>
/// <param name="logger">The logger.</param>
/// <param name="fileSystem">The file system.</param>
public PeopleValidator(ILibraryManager libraryManager, ILogger logger, IFileSystem fileSystem)
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)
{
_libraryManager = libraryManager;
_logger = logger;
_fileSystem = fileSystem;
}
cancellationToken.ThrowIfCancellationRequested();
/// <summary>
/// Validates the people.
/// </summary>
/// <param name="cancellationToken">The cancellation token.</param>
/// <param name="progress">The progress.</param>
/// <returns>Task.</returns>
public async Task ValidatePeople(CancellationToken cancellationToken, IProgress<double> progress)
{
var people = _libraryManager.GetPeopleNames(new InternalPeopleQuery());
var numComplete = 0;
var numPeople = people.Count;
_logger.LogDebug("Will refresh {0} people", numPeople);
foreach (var person in people)
try
{
cancellationToken.ThrowIfCancellationRequested();
try
var item = _libraryManager.GetPerson(person);
if (item is null)
{
var item = _libraryManager.GetPerson(person);
if (item is null)
{
_logger.LogWarning("Failed to get person: {Name}", person);
continue;
}
var options = new MetadataRefreshOptions(new DirectoryService(_fileSystem))
{
ImageRefreshMode = MetadataRefreshMode.ValidationOnly,
MetadataRefreshMode = MetadataRefreshMode.ValidationOnly
};
await item.RefreshMetadata(options, cancellationToken).ConfigureAwait(false);
}
catch (OperationCanceledException)
{
throw;
}
catch (Exception ex)
{
_logger.LogError(ex, "Error validating IBN entry {Person}", person);
_logger.LogWarning("Failed to get person: {Name}", person);
continue;
}
// Update progress
numComplete++;
double percent = numComplete;
percent /= numPeople;
var options = new MetadataRefreshOptions(new DirectoryService(_fileSystem))
{
ImageRefreshMode = MetadataRefreshMode.ValidationOnly,
MetadataRefreshMode = MetadataRefreshMode.ValidationOnly
};
progress.Report(100 * percent);
await item.RefreshMetadata(options, cancellationToken).ConfigureAwait(false);
}
catch (OperationCanceledException)
{
throw;
}
catch (Exception ex)
{
_logger.LogError(ex, "Error validating IBN entry {Person}", person);
}
var deadEntities = _libraryManager.GetItemList(new InternalItemsQuery
{
IncludeItemTypes = [BaseItemKind.Person],
IsDeadPerson = true,
IsLocked = false
});
// Update progress
numComplete++;
double percent = numComplete;
percent /= numPeople;
foreach (var item in deadEntities)
{
_logger.LogInformation(
"Deleting dead {2} {0} {1}.",
item.Id.ToString("N", CultureInfo.InvariantCulture),
item.Name,
item.GetType().Name);
_libraryManager.DeleteItem(
item,
new DeleteOptions
{
DeleteFileLocation = false
},
false);
}
progress.Report(100);
_logger.LogInformation("People validation complete");
subProgress.Report(100 * percent);
}
var deadEntities = _libraryManager.GetItemList(new InternalItemsQuery
{
IncludeItemTypes = [BaseItemKind.Person],
IsDeadPerson = true,
IsLocked = false
});
subProgress = new Progress<double>((val) => progress.Report((val / 2) + 50));
var i = 0;
foreach (var item in deadEntities.Chunk(500))
{
_libraryManager.DeleteItemsUnsafeFast(item);
subProgress.Report(100f / deadEntities.Count * (i++ * 100));
}
progress.Report(100);
_logger.LogInformation("People validation complete");
}
}

View File

@@ -5,46 +5,45 @@ using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Persistence;
using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.Library.Validators
namespace Emby.Server.Implementations.Library.Validators;
/// <summary>
/// Class MusicGenresPostScanTask.
/// </summary>
public class StudiosPostScanTask : ILibraryPostScanTask
{
/// <summary>
/// Class MusicGenresPostScanTask.
/// The _library manager.
/// </summary>
public class StudiosPostScanTask : ILibraryPostScanTask
private readonly ILibraryManager _libraryManager;
private readonly ILogger<StudiosValidator> _logger;
private readonly IItemRepository _itemRepo;
/// <summary>
/// Initializes a new instance of the <see cref="StudiosPostScanTask" /> class.
/// </summary>
/// <param name="libraryManager">The library manager.</param>
/// <param name="logger">The logger.</param>
/// <param name="itemRepo">The item repository.</param>
public StudiosPostScanTask(
ILibraryManager libraryManager,
ILogger<StudiosValidator> logger,
IItemRepository itemRepo)
{
/// <summary>
/// The _library manager.
/// </summary>
private readonly ILibraryManager _libraryManager;
_libraryManager = libraryManager;
_logger = logger;
_itemRepo = itemRepo;
}
private readonly ILogger<StudiosValidator> _logger;
private readonly IItemRepository _itemRepo;
/// <summary>
/// Initializes a new instance of the <see cref="StudiosPostScanTask" /> class.
/// </summary>
/// <param name="libraryManager">The library manager.</param>
/// <param name="logger">The logger.</param>
/// <param name="itemRepo">The item repository.</param>
public StudiosPostScanTask(
ILibraryManager libraryManager,
ILogger<StudiosValidator> logger,
IItemRepository itemRepo)
{
_libraryManager = libraryManager;
_logger = logger;
_itemRepo = itemRepo;
}
/// <summary>
/// Runs the specified progress.
/// </summary>
/// <param name="progress">The progress.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
public Task Run(IProgress<double> progress, CancellationToken cancellationToken)
{
return new StudiosValidator(_libraryManager, _logger, _itemRepo).Run(progress, cancellationToken);
}
/// <summary>
/// Runs the specified progress.
/// </summary>
/// <param name="progress">The progress.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
public Task Run(IProgress<double> progress, CancellationToken cancellationToken)
{
return new StudiosValidator(_libraryManager, _logger, _itemRepo).Run(progress, cancellationToken);
}
}

View File

@@ -8,98 +8,97 @@ using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Persistence;
using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.Library.Validators
namespace Emby.Server.Implementations.Library.Validators;
/// <summary>
/// Class StudiosValidator.
/// </summary>
public class StudiosValidator
{
/// <summary>
/// Class StudiosValidator.
/// The library manager.
/// </summary>
public class StudiosValidator
private readonly ILibraryManager _libraryManager;
private readonly IItemRepository _itemRepo;
/// <summary>
/// The logger.
/// </summary>
private readonly ILogger<StudiosValidator> _logger;
/// <summary>
/// Initializes a new instance of the <see cref="StudiosValidator" /> class.
/// </summary>
/// <param name="libraryManager">The library manager.</param>
/// <param name="logger">The logger.</param>
/// <param name="itemRepo">The item repository.</param>
public StudiosValidator(ILibraryManager libraryManager, ILogger<StudiosValidator> logger, IItemRepository itemRepo)
{
/// <summary>
/// The library manager.
/// </summary>
private readonly ILibraryManager _libraryManager;
_libraryManager = libraryManager;
_logger = logger;
_itemRepo = itemRepo;
}
private readonly IItemRepository _itemRepo;
/// <summary>
/// Runs the specified progress.
/// </summary>
/// <param name="progress">The progress.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
public async Task Run(IProgress<double> progress, CancellationToken cancellationToken)
{
var names = _itemRepo.GetStudioNames();
/// <summary>
/// The logger.
/// </summary>
private readonly ILogger<StudiosValidator> _logger;
var numComplete = 0;
var count = names.Count;
/// <summary>
/// Initializes a new instance of the <see cref="StudiosValidator" /> class.
/// </summary>
/// <param name="libraryManager">The library manager.</param>
/// <param name="logger">The logger.</param>
/// <param name="itemRepo">The item repository.</param>
public StudiosValidator(ILibraryManager libraryManager, ILogger<StudiosValidator> logger, IItemRepository itemRepo)
foreach (var name in names)
{
_libraryManager = libraryManager;
_logger = logger;
_itemRepo = itemRepo;
}
/// <summary>
/// Runs the specified progress.
/// </summary>
/// <param name="progress">The progress.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
public async Task Run(IProgress<double> progress, CancellationToken cancellationToken)
{
var names = _itemRepo.GetStudioNames();
var numComplete = 0;
var count = names.Count;
foreach (var name in names)
try
{
try
{
var item = _libraryManager.GetStudio(name);
var item = _libraryManager.GetStudio(name);
await item.RefreshMetadata(cancellationToken).ConfigureAwait(false);
}
catch (OperationCanceledException)
{
// Don't clutter the log
throw;
}
catch (Exception ex)
{
_logger.LogError(ex, "Error refreshing {StudioName}", name);
}
numComplete++;
double percent = numComplete;
percent /= count;
percent *= 100;
progress.Report(percent);
await item.RefreshMetadata(cancellationToken).ConfigureAwait(false);
}
catch (OperationCanceledException)
{
// Don't clutter the log
throw;
}
catch (Exception ex)
{
_logger.LogError(ex, "Error refreshing {StudioName}", name);
}
var deadEntities = _libraryManager.GetItemList(new InternalItemsQuery
{
IncludeItemTypes = new[] { BaseItemKind.Studio },
IsDeadStudio = true,
IsLocked = false
});
numComplete++;
double percent = numComplete;
percent /= count;
percent *= 100;
foreach (var item in deadEntities)
{
_logger.LogInformation("Deleting dead {ItemType} {ItemId} {ItemName}", item.GetType().Name, item.Id.ToString("N", CultureInfo.InvariantCulture), item.Name);
_libraryManager.DeleteItem(
item,
new DeleteOptions
{
DeleteFileLocation = false
},
false);
}
progress.Report(100);
progress.Report(percent);
}
var deadEntities = _libraryManager.GetItemList(new InternalItemsQuery
{
IncludeItemTypes = [BaseItemKind.Studio],
IsDeadStudio = true,
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);
_libraryManager.DeleteItem(
item,
new DeleteOptions
{
DeleteFileLocation = false
},
false);
}
progress.Report(100);
}
}

View File

@@ -129,5 +129,11 @@
"TaskAudioNormalizationDescription": "Skandeer lêers vir oudio-normaliseringsdata.",
"TaskAudioNormalization": "Odio Normalisering",
"TaskCleanCollectionsAndPlaylists": "Maak versamelings en snitlyste skoon",
"TaskCleanCollectionsAndPlaylistsDescription": "Verwyder items uit versamelings en snitlyste wat nie meer bestaan nie."
"TaskCleanCollectionsAndPlaylistsDescription": "Verwyder items uit versamelings en snitlyste wat nie meer bestaan nie.",
"TaskDownloadMissingLyrics": "Laai tekorte lirieke af",
"TaskDownloadMissingLyricsDescription": "Laai lirieke af vir liedjies",
"TaskExtractMediaSegments": "Media Segment Skandeer",
"TaskExtractMediaSegmentsDescription": "Onttrek of verkry mediasegmente van MediaSegment-geaktiveerde inproppe.",
"TaskMoveTrickplayImages": "Migreer Trickplay Beeldligging",
"TaskMoveTrickplayImagesDescription": "Skuif ontstaande trickplay lêers volgens die biblioteekinstellings."
}

View File

@@ -16,7 +16,7 @@
"Folders": "المجلدات",
"Genres": "التصنيفات",
"HeaderAlbumArtists": "فناني الألبوم",
"HeaderContinueWatching": "استئناف المشاهدة",
"HeaderContinueWatching": "أكمل المشاهدة",
"HeaderFavoriteAlbums": "الألبومات المفضلة",
"HeaderFavoriteArtists": "الفنانون المفضلون",
"HeaderFavoriteEpisodes": "الحلقات المفضلة",
@@ -31,7 +31,7 @@
"ItemRemovedWithName": "أُزيل {0} من المكتبة",
"LabelIpAddressValue": "عنوان الآي بي: {0}",
"LabelRunningTimeValue": "مدة التشغيل: {0}",
"Latest": "أحدث",
"Latest": "الأحدث",
"MessageApplicationUpdated": "حُدث خادم Jellyfin",
"MessageApplicationUpdatedTo": "حُدث خادم Jellyfin إلى {0}",
"MessageNamedServerConfigurationUpdatedWithValue": "حُدثت إعدادات الخادم في قسم {0}",
@@ -52,7 +52,7 @@
"NotificationOptionInstallationFailed": "فشل في التثبيت",
"NotificationOptionNewLibraryContent": "أُضيف محتوى جديدا",
"NotificationOptionPluginError": "فشل في الملحق",
"NotificationOptionPluginInstalled": "ثُبتت المكونات الإضافية",
"NotificationOptionPluginInstalled": "ثُبتت الملحق",
"NotificationOptionPluginUninstalled": "تمت إزالة الملحق",
"NotificationOptionPluginUpdateInstalled": "تم تثبيت تحديثات الملحق",
"NotificationOptionServerRestartRequired": "يجب إعادة تشغيل الخادم",
@@ -90,10 +90,10 @@
"UserStartedPlayingItemWithValues": "قام {0} ببدء تشغيل {1} على {2}",
"UserStoppedPlayingItemWithValues": "قام {0} بإيقاف تشغيل {1} على {2}",
"ValueHasBeenAddedToLibrary": "تمت اضافت {0} إلى مكتبة الوسائط",
"ValueSpecialEpisodeName": "حلقه خاصه - {0}",
"ValueSpecialEpisodeName": "حلقة خاصه - {0}",
"VersionNumber": "الإصدار {0}",
"TaskCleanCacheDescription": "يحذف الملفات المؤقتة التي لم يعد النظام بحاجة إليها.",
"TaskCleanCache": "احذف ما بمجلد الملفات المؤقتة",
"TaskCleanCache": "حذف الملفات المؤقتة",
"TasksChannelsCategory": "قنوات الإنترنت",
"TasksLibraryCategory": "مكتبة",
"TasksMaintenanceCategory": "صيانة",
@@ -125,11 +125,18 @@
"TaskKeyframeExtractor": "مستخرج الإطار الرئيسي",
"External": "خارجي",
"HearingImpaired": "ضعاف السمع",
"TaskRefreshTrickplayImages": "توليد صور Trickplay",
"TaskRefreshTrickplayImagesDescription": "يُنشئ معاينات Trickplay لمقاطع الفيديو في المكتبات المُمكّنة.",
"TaskRefreshTrickplayImages": "توليد صور المعاينة السريعة",
"TaskRefreshTrickplayImagesDescription": "يُولّد معاينات تنقل سريع لمقاطع الفيديو ضمن المكتبات المفعّلة.",
"TaskCleanCollectionsAndPlaylists": "حذف المجموعات وقوائم التشغيل",
"TaskCleanCollectionsAndPlaylistsDescription": "حذف عناصر من المجموعات وقوائم التشغيل التي لم تعد موجودة.",
"TaskAudioNormalization": طبيع الصوت",
"TaskAudioNormalization": سوية الصوت",
"TaskAudioNormalizationDescription": "مسح الملفات لتطبيع بيانات الصوت.",
"TaskDownloadMissingLyrics": "تنزيل عبارات القصيدة"
"TaskDownloadMissingLyrics": "تنزيل عبارات القصيدة",
"TaskDownloadMissingLyricsDescription": "كلمات",
"TaskExtractMediaSegments": "فحص مقاطع الوسائط",
"TaskExtractMediaSegmentsDescription": "يستخرج مقاطع وسائط من إضافات MediaSegment المُفعّلة.",
"TaskMoveTrickplayImages": "تغيير مكان صور المعاينة السريعة",
"TaskMoveTrickplayImagesDescription": "تُنقل ملفات التشغيل السريع الحالية بناءً على إعدادات المكتبة.",
"CleanupUserDataTask": "مهمة تنظيف بيانات المستخدم",
"CleanupUserDataTaskDescription": "مسح جميع بيانات المستخدم (حالة المشاهدة، والحالة المفضلة وما إلى ذلك) من الوسائط التي لم تعد موجودة لمدة 90 يومًا على الأقل."
}

View File

@@ -1,22 +1,22 @@
{
"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": "Калекцыі",
"Default": "Па змаўчанні",
"FailedLoginAttemptWithUserName": "Няўдалая спроба ўваходу з {0}",
"Folders": "Папкі",
"Folders": "Тэчкі",
"Favorites": "Абранае",
"External": "Знешні",
"Genres": "Жанры",
@@ -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,50 @@
"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"
"TaskMoveTrickplayImages": "Перанесці месцазнаходжанне выявы Trickplay",
"CleanupUserDataTask": "Задача па ачыстцы дадзеных карыстальніка",
"CleanupUserDataTaskDescription": "Ачысьціць усе дадзеныя карыстальніка (стан прагляду, абранае і г.д.) для медыяфайлаў, што адсутнічаюць больш за 90 дзён."
}

View File

@@ -121,7 +121,7 @@
"TaskCleanActivityLog": "Изчисти дневника с активност",
"TaskOptimizeDatabaseDescription": "Прави базата данни по-компактна и освобождава място. Пускането на тази задача след сканиране на библиотеката или правене на други промени, свързани с модификации на базата данни, може да подобри производителността.",
"TaskOptimizeDatabase": "Оптимизирай базата данни",
"TaskKeyframeExtractorDescription": "Извличат се ключови кадри от видеофайловете ,за да се създаде по точен ХЛС списък . Задачата може да отнеме много време.",
"TaskKeyframeExtractorDescription": "Извличат се ключови кадри от видеофайловете ,за да се създаде по точен HLS списък . Задачата може да отнеме много време.",
"TaskKeyframeExtractor": "Извличане на ключови кадри",
"External": "Външен",
"HearingImpaired": "Увреден слух",
@@ -129,8 +129,14 @@
"TaskRefreshTrickplayImagesDescription": "Създава прегледи на Trickplay за видеа в активирани библиотеки.",
"TaskDownloadMissingLyrics": "Свали липсващи текстове",
"TaskDownloadMissingLyricsDescription": "Свали текстове за песни",
"TaskCleanCollectionsAndPlaylists": "Изчисти колекциите и плейлистовете",
"TaskCleanCollectionsAndPlaylists": "Изчисти колекциите и плейлистите",
"TaskCleanCollectionsAndPlaylistsDescription": "Премахни несъществуващи файлове в колекциите и плейлистите.",
"TaskAudioNormalization": "Нормализиране на звука",
"TaskAudioNormalizationDescription": "Сканирай файловете за нормализация на звука."
"TaskAudioNormalizationDescription": "Сканирай файловете за нормализация на звука.",
"TaskExtractMediaSegmentsDescription": "Изважда медиини сегменти от MediaSegment плъгини.",
"TaskMoveTrickplayImages": "Мигриране на Локацията за Trickplay изображения",
"TaskMoveTrickplayImagesDescription": "Премества съществуващите trickplay изображения спрямо настройките на библиотеката.",
"TaskExtractMediaSegments": "Сканиране за сегменти",
"CleanupUserDataTask": "Задача за почистване на потребителски данни",
"CleanupUserDataTaskDescription": "Почиства всички потребителски данни (статус на гледане, любими и т.н.) от медия, която вече не е налична от поне 90 дни."
}

View File

@@ -6,29 +6,29 @@
"Channels": "চ্যানেলসমূহ",
"CameraImageUploadedFrom": "{0} থেকে একটি নতুন ক্যামেরার চিত্র আপলোড করা হয়েছে",
"Books": "পুস্তকসমূহ",
"AuthenticationSucceededWithUserName": "{0} অনুমোদন সফল",
"AuthenticationSucceededWithUserName": "{0} সফলভাবে অথেন্টিকেট করেছেন",
"Artists": "শিল্পীগণ",
"Application": "অ্যাপ্লিকেশন",
"Albums": "অ্যালবামসমূহ",
"HeaderFavoriteEpisodes": "প্রি পর্বগুলো",
"HeaderFavoriteEpisodes": "প্রিয় পর্বগুলো",
"HeaderFavoriteArtists": "প্রিয় শিল্পীরা",
"HeaderFavoriteAlbums": "প্রিয় এলবামগুলো",
"HeaderContinueWatching": "দেখতে থাকুন",
"HeaderAlbumArtists": "অ্যালবাম শিল্পীবৃন্দ",
"Genres": "শৈলীধারাসমূহ",
"Genres": "ধরণ",
"Folders": "ফোল্ডারসমূহ",
"Favorites": "পছন্দসমূহ",
"FailedLoginAttemptWithUserName": "{0} লগিন করতে ব্যর্থ হয়েছে",
"AppDeviceValues": "অ্যাপ: {0}, ডিভাইস: {0}",
"AppDeviceValues": "অ্যাপ: {0}, ডিভাইস: {1}",
"VersionNumber": "সংস্করণ {0}",
"ValueSpecialEpisodeName": "বিশেষ পর্ব - {0}",
"ValueHasBeenAddedToLibrary": "আপনার লাইব্রেরিতে {0} যোগ করা হয়েছে",
"UserStoppedPlayingItemWithValues": "{2}তে {1} বাজানো শেষ করেছেন {0}",
"UserStartedPlayingItemWithValues": "{2}তে {1} বাজাচ্ছেন {0}",
"UserStoppedPlayingItemWithValues": "{2}তে {1} প্লে শেষ করেছেন {0}",
"UserStartedPlayingItemWithValues": "{2}তে {1} প্লে করেছেন {0}",
"UserPolicyUpdatedWithName": "{0} এর জন্য ব্যবহার নীতি আপডেট করা হয়েছে",
"UserPasswordChangedWithName": "ব্যবহারকারী {0} এর পাসওয়ার্ড পরিবর্তিত হয়েছে",
"UserOnlineFromDevice": "{0}, {1} থেকে অনলাইন",
"UserOfflineFromDevice": "{0} {1} থেকে বিযুক্ত হয়ে গেছে",
"UserOnlineFromDevice": "{0}, {1} থেকে অনলাইন আছে",
"UserOfflineFromDevice": "{0} {1} থেকে বিচ্ছিন্ন হয়ে গেছে",
"UserLockedOutWithName": "ব্যবহারকারী {0} ঢুকতে পারছে না",
"UserDownloadingItemWithValues": "{0}, {1} ডাউনলোড করছে",
"UserDeletedWithName": "ব্যবহারকারী {0}কে বাদ দেয়া হয়েছে",
@@ -36,28 +36,28 @@
"User": "ব্যবহারকারী",
"TvShows": "টিভি শোগুলো",
"System": "সিস্টেম",
"Sync": "সমলয় স্থাপন",
"SubtitleDownloadFailureFromForItem": "{2} থেকে {1} এর জন্য সাবটাইটেল ডাউনলোড ব্যর্থ",
"Sync": "সমন্বয় করুন",
"SubtitleDownloadFailureFromForItem": "{0} থেকে {1} এর জন্য সাবটাইটেল ডাউনলোড ব্যর্থ হয়েছে",
"StartupEmbyServerIsLoading": "জেলিফিন সার্ভার লোড হচ্ছে। দয়া করে একটু পরে আবার চেষ্টা করুন।",
"Songs": "সঙ্গীতসমূহ",
"Shows": "টিভি পর্ব",
"Songs": "সঙ্গীত সমূহ",
"Shows": "শো সমূহ",
"ServerNameNeedsToBeRestarted": "{0} রিস্টার্ট করা প্রয়োজন",
"ScheduledTaskStartedWithName": "{0} শুরু হয়েছে",
"ScheduledTaskFailedWithName": "{0} ব্যর্থ",
"ProviderValue": "প্রদানকারী: {0}",
"PluginUpdatedWithName": "{0} আপডেট করা হয়েছে",
"PluginUninstalledWithName": "{0} বাদ দেয়া হয়েছে",
"PluginInstalledWithName": "{0} ইন্সটল করা হয়েছে",
"PluginUninstalledWithName": "{0} আনইন্সটল হয়েছে",
"PluginInstalledWithName": "{0} ইন্সটল হয়েছে",
"Plugin": "প্লাগিন",
"Playlists": "প্লে লিস্ট সমূহ",
"Photos": "চিত্রসমূহ",
"NotificationOptionVideoPlaybackStopped": "ভিডিও চলা বন্ধ",
"NotificationOptionVideoPlayback": "ভিডিও চলা শুরু হেছে",
"NotificationOptionUserLockedOut": "ব্যবহারকারী ঢুকতে পারছে না",
"Photos": "ছবিসমূহ",
"NotificationOptionVideoPlaybackStopped": "ভিডিও প্লেব্যাক বন্ধ হয়েছে",
"NotificationOptionVideoPlayback": "ভিডিও প্লেব্যাক শুরু হয়েছে",
"NotificationOptionUserLockedOut": "ব্যবহারকারী লক আউট হয়েছে",
"NotificationOptionTaskFailed": "পরিকল্পিত কাজটি ব্যর্থ",
"NotificationOptionServerRestartRequired": "সার্ভার রিস্টার্ট বাধ্যতামূলক",
"NotificationOptionPluginUpdateInstalled": "প্লাগিন আপডেট ইন্সটল করা হয়েছে",
"NotificationOptionPluginUninstalled": "প্লাগিন বাদ দেয়া হয়েছে",
"NotificationOptionServerRestartRequired": "সার্ভার রিস্টার্ট করা লাগবে",
"NotificationOptionPluginUpdateInstalled": "প্লাগিন আপডেট ইন্সটল হয়েছে",
"NotificationOptionPluginUninstalled": "প্লাগিন আনইনষ্টল হয়েছে",
"NotificationOptionPluginInstalled": "প্লাগিন ইন্সটল করা হয়েছে",
"NotificationOptionPluginError": "প্লাগিন ব্যর্থ",
"NotificationOptionNewLibraryContent": "নতুন কন্টেন্ট যোগ করা হয়েছে",
@@ -76,8 +76,8 @@
"Movies": "চলচ্চিত্রসমূহ",
"MixedContent": "মিশ্র কন্টেন্ট",
"MessageServerConfigurationUpdated": "সার্ভারের কনফিগারেশন আপডেট করা হয়েছে",
"HeaderRecordingGroups": "রেকর্ডিং দল",
"MessageNamedServerConfigurationUpdatedWithValue": "সার্ভারের {0} কনফিগারেসনের অংশ আপডেট করা হয়েছে",
"HeaderRecordingGroups": "রেকর্ডিং গ্রুপগুলো",
"MessageNamedServerConfigurationUpdatedWithValue": "সার্ভার কনফিগারেশন সেকশন {0} আপডেট করা হয়েছে",
"MessageApplicationUpdatedTo": "জেলিফিন সার্ভার {0} তে আপডেট করা হয়েছে",
"MessageApplicationUpdated": "জেলিফিন সার্ভার আপডেট করা হয়েছে",
"Latest": "সর্বশেষ",
@@ -85,45 +85,57 @@
"LabelIpAddressValue": "আইপি এড্রেস: {0}",
"ItemRemovedWithName": "{0} লাইব্রেরি থেকে বাদ দেয়া হয়েছে",
"ItemAddedWithName": "{0} লাইব্রেরিতে যোগ করা হয়েছে",
"Inherit": "থেকে পাওয়া",
"Inherit": "উত্তরাধিকারসূত্র থেকে গ্রহণ করুন",
"HomeVideos": "হোম ভিডিও",
"HeaderNextUp": "এরপরে আসছে",
"HeaderLiveTV": "লাইভ টিভি",
"HeaderFavoriteSongs": "প্রিয় গানগুলো",
"HeaderFavoriteShows": "প্রিয় শোগুলো",
"TasksLibraryCategory": "গ্রন্থাগার",
"TasksLibraryCategory": "লাইব্রেরি",
"TasksMaintenanceCategory": "রক্ষণাবেক্ষণ",
"TaskRefreshLibrary": "স্ক্যান মিডিয়া লাইব্রেরি",
"TaskRefreshChapterImagesDescription": "অধ্যায়গুলিতে থাকা ভিডিওগুলির জন্য থাম্বনেইল তৈরি ।",
"TaskRefreshChapterImages": "অধ্যায়ের চিত্রগুলি বের করুন",
"TaskCleanCacheDescription": "সিস্টেমের প্রয়োজন নেই ক্যাশ, ফাইলগুলি মুছে ফেলুন।",
"TaskRefreshChapterImagesDescription": "যেসব ভিডিওতে চ্যাপ্টার রয়েছে, তাদের জন্য থাম্বনেইল তৈরি করবে।",
"TaskRefreshChapterImages": "্যাপ্টার ইমেজ বের করুন",
"TaskCleanCacheDescription": "সিস্টেমের প্রয়োজনীয় ক্যাশ ফাইলগুল মুছে ফেলবে।",
"TaskCleanCache": "ক্লিন ক্যাশ ডিরেক্টরি",
"TasksChannelsCategory": "ইন্টারনেট চ্যানেল",
"TasksApplicationCategory": "আবেদন",
"TasksApplicationCategory": "অ্যাপ্লিকেশন",
"TaskDownloadMissingSubtitlesDescription": "মেটাডেটা কনফিগারেশনের উপর ভিত্তি করে অনুপস্থিত সাবটাইটেলগুলির জন্য ইন্টারনেট অনুসন্ধান করে।",
"TaskDownloadMissingSubtitles": "অনুপস্থিত সাবটাইটেলগুলি ডাউনলোড করুন",
"TaskRefreshChannelsDescription": "ইন্টারনেট চ্যানেল তথ্য রিফ্রেশ করুন।",
"TaskRefreshChannels": "চ্যানেল রিফ্রেশ করুন",
"TaskCleanTranscodeDescription": "এক দিনেরও বেশি পুরানো ট্রান্সকোড ফাইলগুলি মুছে ফেলুন।",
"TaskCleanTranscodeDescription": "এক দিনেরও বেশি পুরানো ট্রান্সকোড ফাইলগুলি মুছে ফেলবে।",
"TaskCleanTranscode": "ট্রান্সকোড ডিরেক্টরি ক্লিন করুন",
"TaskUpdatePluginsDescription": "স্বয়ংক্রিয়ভাবে আপডেট কনফিগার করা প্লাগইনগুলির জন্য আপডেট ডাউনলোড এবং ইনস্টল করুন।",
"TaskUpdatePlugins": "প্লাগইন আপডেট করুন",
"TaskRefreshPeopleDescription": "আপনার মিডিয়া লাইব্রেরিতে অভিনেতা এবং পরিচালকদের জন্য মেটাডাটা আপডেট করুন।",
"TaskRefreshPeople": "পিপল রিফ্রেশ করুন",
"TaskCleanLogsDescription": "{0} দিনের বেশী পুরানো লগ ফাইলগুলি মুছে ফেলুন।",
"TaskCleanLogs": "লগ ডিরেক্টরি ক্লিন করুন",
"TaskRefreshLibraryDescription": "নতুন ফাইলের জন্য মিডিয়া লাইব্রেরি স্ক্যান এবং মেটাডাটা রিফ্রেশ করুন।",
"TaskUpdatePlugins": "আপডেট প্লাগইন",
"TaskRefreshPeopleDescription": "আপনার মিডিয়া লাইব্রেরিতে অভিনেতা এবং পরিচালকদের জন্য মেটাডাটা আপডেট করবে।",
"TaskRefreshPeople": "ব্যক্তিদের তথ্য রিফ্রেশ",
"TaskCleanLogsDescription": "{0} দিনের বেশী পুরানো লগ ফাইলগুলি মুছে ফেলবে।",
"TaskCleanLogs": "ক্লিন লগ ডিরেক্টরি",
"TaskRefreshLibraryDescription": "নতুন ফাইলের জন্য মিডিয়া লাইব্রেরি স্ক্যান এবং মেটাডাটা রিফ্রেশ করবে।",
"Undefined": "অসঙ্গায়িত",
"Forced": "জোরকরে",
"TaskCleanActivityLogDescription": "নির্ধারিত সময়ের আগের কাজের হিসাব মুছে দিন খালি করুন.",
"TaskCleanActivityLog": "কাজের ফাইল খালি করুন",
"TaskCleanActivityLogDescription": "নির্ধারিত সময়ের আগের অ্যাক্টিভিটি লগ মুছে দিবে।",
"TaskCleanActivityLog": "অ্যাক্টিভিটি লগ মুছুন",
"Default": "ডিফল্ট",
"HearingImpaired": "দুর্বল শ্রবণক্ষমতাধরদের জন্য",
"HearingImpaired": "শ্রবণ প্রতিবন্ধী",
"TaskOptimizeDatabaseDescription": "তথ্যভাণ্ডার সুবিন্যস্ত করে ও অব্যবহৃত জায়গা ছেড়ে দেয়। লাইব্রেরী স্ক্যান অথবা যেকোনো তথ্যভাণ্ডার পরিবর্তনের পর এই প্রক্রিয়া চালালে তথ্যভাণ্ডারের তথ্য প্রদান দ্রুততর হতে পারে।",
"External": "বাহ্যিক",
"TaskOptimizeDatabase": "তথ্যভাণ্ডার সুবিন্যাস",
"TaskKeyframeExtractor": "কি-ফ্রেম নিষ্কাশক",
"TaskKeyframeExtractorDescription": "ভিডিয়ো থেকে কি-ফ্রেম নিষ্কাশনের মাধ্যমে অধিকতর সঠিক HLS প্লে লিস্ট তৈরী করে। এই প্রক্রিয়া দীর্ঘ সময় ধরে চলতে পারে।",
"TaskRefreshTrickplayImages": "ট্রিকপ্লে ইমেজ তৈরি করুন",
"TaskRefreshTrickplayImagesDescription": "সক্ষম লাইব্রেরিতে ভিডিওর জন্য ট্রিকপ্লে প্রিভিউ তৈরি করে।"
"TaskRefreshTrickplayImages": "ট্রিকপ্লে ইমেজ তৈরি",
"TaskRefreshTrickplayImagesDescription": "সক্ষম লাইব্রেরিতে ভিডিওর জন্য ট্রিকপ্লে প্রিভিউ তৈরি করে।",
"TaskDownloadMissingLyricsDescription": "গানের জন্য লিরিকস ডাউনলোড করুন",
"TaskCleanCollectionsAndPlaylists": "কালেকশন এবং প্লেলিস্ট পরিষ্কার করুন",
"TaskCleanCollectionsAndPlaylistsDescription": "কালেকশন এবং প্লেলিস্ট থেকে আইটেমগুলি সরিয়ে দেয় যা আর বিদ্যমান নেই।",
"TaskExtractMediaSegments": "মিডিয়া সেগমেন্ট স্ক্যান",
"TaskExtractMediaSegmentsDescription": "মিডিয়া সেগমেন্ট সক্ষম প্লাগইনগুলি থেকে মিডিয়া সেগমেন্ট বের করে বা অর্জন করে।",
"TaskDownloadMissingLyrics": "অনুপস্থিত গান ডাউনলোড করুন",
"TaskMoveTrickplayImagesDescription": "লাইব্রেরির সেটিং অনুযায়ী বিদ্যমান ট্রিকপ্লে ফাইলগুলো সরিয়ে নেবে।",
"TaskAudioNormalizationDescription": "অডিও নর্মালাইজেশন তথ্যের জন্য ফাইল স্ক্যান করবে।",
"CleanupUserDataTaskDescription": "৯০ দিন বা তার বেশি সময় ধরে অনুপস্থিত মিডিয়া থেকে সকল ব্যবহারকারীর ডেটা (ওয়াচ স্টেট, ফেভারিট স্ট্যাটাস ইত্যাদি) মুছে ফেলবে।",
"TaskMoveTrickplayImages": "ট্রিকপ্লে ইমেজের অবস্থান পরিবর্তন",
"TaskAudioNormalization": "অডিও নর্মলাইজেশন",
"CleanupUserDataTask": "ইউজার ডেটা ক্লিনআপ কাজ"
}

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