Compare commits

...

510 Commits

Author SHA1 Message Date
Joshua M. Boniface
d45d228b36 Bump version to 10.8.0-beta2 2022-04-17 15:52:43 -04:00
Cody Robibero
a280ff603f Merge pull request #7543 from daullmer/nfo-datefix 2022-04-17 06:40:28 -06:00
Cody Robibero
9beb3aff4e Merge pull request #7605 from crobibero/playback-start-stop
Add missing properties to PlaybackStart, PlaybackStop
2022-04-16 06:03:05 -06:00
Cody Robibero
066bdc1e72 Add missing properties to PlaybackStart, PlaybackStop 2022-04-15 17:44:30 -06:00
Cody Robibero
5833c70725 Merge pull request #7537 from dmitrylyzo/fix-streambuilder 2022-04-15 13:29:20 -06:00
Cody Robibero
cd93f49fa8 Merge pull request #7592 from 1337joe/live-tv-fixes 2022-04-15 13:29:10 -06:00
Cody Robibero
93009682b3 Merge pull request #7591 from 1337joe/update-xmltv 2022-04-15 13:29:00 -06:00
Joe Rogers
9001eaa67e Check cache file age directly and replace if old 2022-04-13 22:45:17 +02:00
Joe Rogers
76010e80dd Update Jellyfin.XmlTv to 10.8.0 2022-04-13 20:07:14 +02:00
Joshua M. Boniface
5778541d2f Merge pull request #7590 from crobibero/dotnet-6.0.4 2022-04-13 12:06:56 -04:00
Cody Robibero
cb0baddde3 Update to dotnet 6.0.4 2022-04-12 17:34:08 -06:00
Dmitry Lyzo
0ff37413b0 fix: Fix transcode reasons
Don't add codec failure reasons if the codec isn't supported.
2022-04-12 22:56:23 +03:00
Dmitry Lyzo
d5434988d7 test: Add tests for Tizen 3/4 2022-04-12 22:56:23 +03:00
Dmitry Lyzo
847518701d fix: Fix codec conditions
`ApplyConditions` is used to determine the applicability of
the current codec (`Conditions`).
`Conditions` is the actual conditions for the stream.

`CodecType.VideoAudio` (not `CodecType.Video`) must be used
for the audio tracks in the video.
2022-04-12 22:56:23 +03:00
Cody Robibero
c5212a20a3 Merge pull request #7580 from jellyfin/external-audio-map 2022-04-12 13:41:21 -06:00
Cody Robibero
385a0b9437 Merge pull request #7567 from cvium/fix_xmltv_caching 2022-04-12 13:40:05 -06:00
Nyanmisaka
884ba4f3ed Fix the wrong external audio map index if text subtitle exists 2022-04-10 22:49:40 +08:00
Cody Robibero
cba6a4e3f3 Merge pull request #7578 from Shadowghost/extension-parser-fix
Remove mp2 from video file extensions
2022-04-10 06:24:50 -06:00
Shadowghost
d5f44f7a5c Remove mp2 from video file extensions 2022-04-10 14:02:17 +02:00
Cody Robibero
bf1ccf7493 Merge pull request #7521 from 1337joe/image-mime-fallback
Add fallback for image downloads with bad reported MediaType
2022-04-09 08:46:06 -06:00
Cody Robibero
d7c548f3db Merge pull request #7561 from DMouse10462/named-config-api-fix
Fix NamedConfiguration API Generation
2022-04-09 08:45:13 -06:00
Joshua M. Boniface
a7abdca47a Merge pull request #7569 from crobibero/repo-auth 2022-04-08 11:23:30 -04:00
Cody Robibero
7a8eaa8811 Require elevation to save the list of plugin repositories 2022-04-08 08:46:55 -06:00
cvium
045dca49d0 fix: use the checksum as temp folder name when extracting xmltv listings 2022-04-07 22:12:12 +02:00
David Mouse
e9ce82445e Add ConfigurationType Types to generated OpenAPI
This allows clients to see and work with the associated types for each NamedConfiguration key, even if the UpdateNamedConfiguration endpoint doesn't properly advertise its types.
2022-04-05 23:19:27 -04:00
David Mouse
2133c6e348 Parameterize request body of UpdateNamedConfiguration
This gives OpenAPI clients the knowledge that they should provide a body of some kind.
2022-04-05 23:19:27 -04:00
Cody Robibero
5de2db9f52 Merge pull request #7507 from crobibero/studio-image-plugin
Fix StudioImageProvider
2022-04-05 05:52:48 -06:00
Cody Robibero
620625c4c1 Merge pull request #7557 from jellyfin/pgs-qsv-iris655 2022-04-04 16:05:50 -06:00
Nyanmisaka
e0b035e34e Apply suggestions from code review
Co-authored-by: Shadowghost <Shadowghost@users.noreply.github.com>
2022-04-05 00:02:13 +08:00
Nyanmisaka
1946414e14 Fix PGS burn-in on certain iGPU such as Iris Plus 655 2022-04-04 23:48:12 +08:00
Cody Robibero
132c85e554 Merge pull request #7542 from 1337joe/make-recording-stop
Make recording stop at scheduled stop time
2022-04-04 07:20:20 -06:00
Joe Rogers
9d1049e83f Make Record call block until finished as expected 2022-04-04 14:43:14 +02:00
Cody Robibero
72aca15191 Merge pull request #7548 from 1337joe/comparer-null-fix 2022-04-04 06:30:24 -06:00
Cody Robibero
577325b788 Merge pull request #7523 from crobibero/null-stream
Allow media without streams to playback
2022-04-04 05:45:45 -06:00
Cody Robibero
fec2cf5060 Merge pull request #7551 from cvium/fix_trailertype
fix: remove (incorrect) negation of bool expression
2022-04-04 05:02:58 -06:00
cvium
53b06ce4e3 fix: remove (incorrect) negation of bool expression 2022-04-04 08:35:41 +02:00
Cody Robibero
bdb85aeecf Merge pull request #7549 from cvium/fix_isinlocalnetwork 2022-04-03 16:38:04 -06:00
cvium
e299adc819 fix: use stdlib IPAddress.IsLoopback 2022-04-04 00:03:54 +02:00
Joe Rogers
0674f84e9e Add check so nulls will result in valid sort 2022-04-03 22:50:32 +02:00
David Ullmer
b6086398d3 Write Global Date to nfo files 2022-04-02 19:46:15 +02:00
Cody Robibero
1d585146d6 Merge pull request #7519 from nielsvanvelzen/resolverpriority-plugin2 2022-03-30 20:11:46 -06:00
Cody Robibero
aa1b1c6bbb Merge pull request #7527 from Shadowghost/mediaresolver-fix 2022-03-30 20:10:36 -06:00
Cody Robibero
bebe1808ce Merge pull request #7525 from 1337joe/fix-duplicate-library-media-paths 2022-03-30 20:10:12 -06:00
Shadowghost
fb2e4c2e1a Remove video file from file list before processing external files 2022-03-30 22:48:48 +02:00
Joe Rogers
784ed796ce Update name so media paths store to correct library 2022-03-30 15:20:57 +02:00
Cody Robibero
579155a571 Allow media without streams to playback 2022-03-29 20:17:12 -06:00
Joe Rogers
ca16a55a47 Add fallback for image downloads with bad MediaType 2022-03-29 21:42:54 +02:00
Niels van Velzen
e2ffd41141 Add new priority level to ResolverPriority for plugins 2022-03-29 20:00:50 +02:00
Cody Robibero
ca67a48140 Merge pull request #7512 from crobibero/update-plugin 2022-03-28 16:34:46 -06:00
Claus Vium
d2ce315c1d Merge pull request #7506 from crobibero/set-permissions
Safely get/set User permission/preference
2022-03-28 23:02:42 +02:00
Cody Robibero
6a6874aa16 Catch checksum mismatch when updating plugins 2022-03-28 06:48:21 -06:00
Cody Robibero
6f45848b51 Safely set/get user permission 2022-03-28 06:45:47 -06:00
Cody Robibero
23ba15ccfb Fix StudiosImageProvider 2022-03-27 21:42:35 -06:00
Joshua M. Boniface
5376c37d42 Bump packaging version to 10.8.0~beta1 2022-03-27 12:12:24 -04:00
Saiyd
a0eb1fd28b Translated using Weblate (Portuguese (Brazil))
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/pt_BR/
2022-03-26 19:06:12 -04:00
Cody Robibero
130c935bc3 Merge pull request #7495 from crobibero/fix-entrypoint 2022-03-26 14:33:02 -06:00
Cody Robibero
003c48e351 Merge pull request #7496 from crobibero/transcode-reason 2022-03-26 14:32:54 -06:00
Cody Robibero
96a03776e1 Fix TranscodeReasons property name 2022-03-26 12:20:29 -06:00
Cody Robibero
ac33adf219 Learn how DllImport works before making changes 2022-03-26 12:14:09 -06:00
Cody Robibero
4fa7f49ffc Merge pull request #7202 from knackebrot/unix-perms 2022-03-26 07:24:06 -06:00
Cody Robibero
0a068b924f Fix casing of chmod 2022-03-26 07:12:35 -06:00
Cody Robibero
d80c4ee381 Merge pull request #7492 from crobibero/sort-by 2022-03-25 13:33:29 -06:00
Cody Robibero
e6014bb8d3 Merge pull request #7493 from Shadowghost/dlna-fix 2022-03-25 13:33:20 -06:00
Cody Robibero
8056b0e961 Merge pull request #7443 from whiteowl3/strm-probe 2022-03-25 13:33:10 -06:00
whiteowl3
6a7775de6e empty line required by linter 2022-03-25 19:08:03 +00:00
Shadowghost
4e91c3ebdc Fix DLNA DirectPlay 2022-03-25 18:02:31 +01:00
Cody Robibero
78a8c26690 Don't allow unknown sort-by 2022-03-25 09:18:18 -06:00
Joshua M. Boniface
c229f3ae0a Merge pull request #7333 from eyezak/hls/audio-bitstream-fmp4 2022-03-25 10:13:58 -04:00
Nyanmisaka
3cea6c61f3 Apply suggestions from code review 2022-03-25 22:12:56 +08:00
Joshua M. Boniface
8197e5921e Merge pull request #7198 from dmitrylyzo/transcode-conditions 2022-03-25 10:11:45 -04:00
Jason S
5f7ffd7863 Translated using Weblate (Kannada)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/kn/
2022-03-25 05:51:28 -04:00
Jason S
c28025ba5e Added translation using Weblate (Kannada) 2022-03-25 04:44:39 -04:00
Rhodri
af5200857e Translated using Weblate (Welsh)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/cy/
2022-03-23 20:24:28 -04:00
Joshua M. Boniface
97d3212410 Merge pull request #7437 from Nalsai/mks-attachments 2022-03-23 20:19:32 -04:00
Rhodri
8780fc0ea1 Translated using Weblate (Welsh)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/cy/
2022-03-23 17:28:09 -04:00
Joshua M. Boniface
570660099b Merge pull request #7483 from jellyfin/swdec-cu-tonemap 2022-03-23 15:25:39 -04:00
Joshua M. Boniface
945fb8b72e Merge pull request #7488 from crobibero/flag-enum-openapi 2022-03-23 15:24:31 -04:00
whiteowl3
16a449a023 Apply suggestions from code review
Co-authored-by: Cody Robibero <cody@robibe.ro>
2022-03-23 13:19:05 -04:00
whiteowl3
669029595b Update MediaBrowser.Providers/MediaInfo/MediaInfoResolver.cs
Co-authored-by: Cody Robibero <cody@robibe.ro>
2022-03-23 13:18:34 -04:00
Cody Robibero
72cfa6d7c9 Fix spec generation for TranscodeReason 2022-03-23 08:32:33 -06:00
Cody Robibero
7fb21132dd Merge pull request #7487 from InvoxiPlayGames/dlna-fix 2022-03-22 19:10:08 -06:00
Mocanu Marian
3bf5a7b801 Translated using Weblate (Romanian)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/ro/
2022-03-22 20:13:37 -04:00
tokiedokie
74bdad82c1 Translated using Weblate (Japanese)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/ja/
2022-03-22 20:13:37 -04:00
nextlooper42
c59087606c Translated using Weblate (Slovak)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/sk/
2022-03-22 20:13:37 -04:00
Nils Fürniß
d7d36a102a Fix releasing lock 2022-03-22 19:17:49 +01:00
Nils Fürniß
b4bb82b6d7 Improve code 2022-03-22 19:17:48 +01:00
Nils Fürniß
eb44f892b8 Only extract attachments from external .mks file 2022-03-22 19:17:48 +01:00
Nils Fürniß
90463d5e4f Pass CancellationToken to ExtractAllAttachments 2022-03-22 19:17:48 +01:00
Nils Fürniß
6904edf68c add extracting attachments from external subs 2022-03-22 19:17:48 +01:00
InvoxiPlayGames
dc8fdb154a get DLNA profile in XML request, correctly format UUID 2022-03-22 16:04:55 +00:00
Cody Robibero
c512e783b3 Merge pull request #7480 from jellyfin/dependabot/nuget/StyleCop.Analyzers-1.2.0-beta.406 2022-03-21 11:10:06 -06:00
Cody Robibero
4398475aac Merge pull request #7481 from jellyfin/dependabot/nuget/libse-3.6.5 2022-03-21 11:09:38 -06:00
Nyanmisaka
fb8ae0e9a1 Improve fps for cuda tonemap in sw decoding
avoid second copy if subtitle is not applied.
2022-03-22 00:45:07 +08:00
dependabot[bot]
5d44e45b90 Bump libse from 3.6.4 to 3.6.5
Bumps [libse](https://github.com/SubtitleEdit/subtitleedit) from 3.6.4 to 3.6.5.
- [Release notes](https://github.com/SubtitleEdit/subtitleedit/releases)
- [Changelog](https://github.com/SubtitleEdit/subtitleedit/blob/master/Changelog.txt)
- [Commits](https://github.com/SubtitleEdit/subtitleedit/compare/3.6.4...3.6.5)

---
updated-dependencies:
- dependency-name: libse
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-21 12:22:20 +00:00
dependabot[bot]
dde984bd0e Bump StyleCop.Analyzers from 1.2.0-beta.376 to 1.2.0-beta.406
Bumps [StyleCop.Analyzers](https://github.com/DotNetAnalyzers/StyleCopAnalyzers) from 1.2.0-beta.376 to 1.2.0-beta.406.
- [Release notes](https://github.com/DotNetAnalyzers/StyleCopAnalyzers/releases)
- [Commits](https://github.com/DotNetAnalyzers/StyleCopAnalyzers/compare/1.2.0-beta.376...1.2.0-beta.406)

---
updated-dependencies:
- dependency-name: StyleCop.Analyzers
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-21 12:22:11 +00:00
Cody Robibero
ba11add83b Merge pull request #7445 from Bond-009/baseitem 2022-03-20 08:01:31 -06:00
lyaschuchenko
e86e64807d Translated using Weblate (Ukrainian)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/uk/
2022-03-20 04:13:37 -04:00
fatihbural
320ab8db6a Translated using Weblate (Turkish)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/tr/
2022-03-20 04:13:37 -04:00
Henrik Söderlund
60e0becc54 Translated using Weblate (Swedish)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/sv/
2022-03-20 04:13:37 -04:00
millallo
acd4a97e65 Translated using Weblate (Italian)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/it/
2022-03-20 04:13:37 -04:00
Joel Tony
009e3a6c72 Translated using Weblate (English (United Kingdom))
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/en_GB/
2022-03-20 04:13:37 -04:00
xnick
f8b5631d62 Translated using Weblate (Greek)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/el/
2022-03-20 04:13:37 -04:00
3ole
8871e5af4b Translated using Weblate (German)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/de/
2022-03-20 04:13:36 -04:00
Xavier Rosell
4c117b0259 Translated using Weblate (Catalan)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/ca/
2022-03-20 04:13:36 -04:00
Dmitry Lyzo
e4137a6279 Fix remuxing 2022-03-20 09:11:46 +03:00
Dmitry Lyzo
1fe82d0deb Add TranscodingProfile conditions 2022-03-20 09:11:46 +03:00
Cody Robibero
588c349eb4 Merge pull request #7477 from crobibero/requested-bitrate 2022-03-19 17:41:29 -06:00
Cody Robibero
b9c3a497d5 Use requested bitrate for calculations 2022-03-19 12:08:42 -06:00
Joshua M. Boniface
dd6845b8f3 Merge pull request #7476 from crobibero/tmdb-ended 2022-03-19 12:33:23 -04:00
Joshua M. Boniface
464ebf93dd Merge pull request #6985 from joshuaboniface/unharden-for-lxc 2022-03-19 12:31:33 -04:00
Joshua M. Boniface
93f569d286 Add comment about sysv options 2022-03-19 12:27:48 -04:00
Cody Robibero
0e2b20e6d6 tmdb - update available series end status 2022-03-18 18:49:12 -06:00
Cody Robibero
e1527857e9 Merge pull request #7468 from jakobkukla/master 2022-03-18 16:55:21 -06:00
Cody Robibero
6a567e8c76 Merge pull request #7474 from nielsvanvelzen/api-secure 2022-03-18 16:52:59 -06:00
dependabot[bot]
4b5148c69e Bump Swashbuckle.AspNetCore.ReDoc from 6.2.3 to 6.3.0 (#7457)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-03-18 22:38:55 +01:00
Niels van Velzen
8a827ba995 Update tests 2022-03-18 22:21:08 +01:00
Bond-009
bb7068cb63 Move StreamBuilderTests to correct project (#7461) 2022-03-18 22:19:02 +01:00
Niels van Velzen
46798cb918 Remove check for non-existent "emby rt" client in UserViewsController (#7470) 2022-03-18 22:16:08 +01:00
Niels van Velzen
5ece92d635 Add authorization attribute to UserViewsController 2022-03-18 21:56:42 +01:00
Niels van Velzen
9fbd675bed Add authorization attribute to GetConfigurationPages 2022-03-18 21:54:25 +01:00
Cody Robibero
5cf0c1b8f8 Merge pull request #7466 from jellyfin/prefer-cuvid
Prefer Cuvid to Nvdec by default for better performance
2022-03-18 05:45:41 -06:00
Josu Igoa
c8a8a85944 Translated using Weblate (Basque)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/eu/
2022-03-18 06:26:41 -04:00
Josu Igoa
9f147216be Translated using Weblate (Basque)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/eu/
2022-03-18 05:56:13 -04:00
Josu Igoa
db60c9da25 Added translation using Weblate (Basque) 2022-03-18 05:51:16 -04:00
jakobkukla
75475285da Fix supportsTranscoding not reflecting user permissions sometimes 2022-03-17 17:24:30 +01:00
Nyanmisaka
18c7dc210c Prefer Cuvid to Nvdec by default for better performance 2022-03-17 18:01:58 +08:00
Freethefire
ca517af0d9 Translated using Weblate (Swedish)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/sv/
2022-03-17 03:14:57 -04:00
SeanPai
fccf3ac3eb Translated using Weblate (Chinese (Traditional))
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/zh_Hant/
2022-03-17 01:13:34 -04:00
Joshua M. Boniface
1d7a524d82 Add SuccessExitStatus for exit 143
Fixes #3182
2022-03-15 20:27:38 -04:00
WWWesten
6a3da3a031 Translated using Weblate (Esperanto)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/eo/
2022-03-14 17:21:44 -04:00
hoanghuy309
456d95c878 Translated using Weblate (Vietnamese)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/vi/
2022-03-14 17:21:44 -04:00
Oatavandi
36040832cc Translated using Weblate (Tamil)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/ta/
2022-03-14 17:21:44 -04:00
Oskari Lavinto
cb91ad184e Translated using Weblate (Finnish)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/fi/
2022-03-14 17:21:44 -04:00
Magnetogenerator
122f6acb15 Translated using Weblate (Chinese (Simplified))
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/zh_Hans/
2022-03-14 17:21:44 -04:00
WWWesten
b4913aad30 Translated using Weblate (Russian)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/ru/
2022-03-14 17:21:44 -04:00
WWWesten
6fa38e300a Translated using Weblate (Kazakh)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/kk/
2022-03-14 17:21:44 -04:00
Csaba
fbbb0368f7 Translated using Weblate (Hungarian)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/hu/
2022-03-14 17:21:44 -04:00
Ali Dastpour
67a0a998cc Translated using Weblate (Persian)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/fa/
2022-03-14 17:21:44 -04:00
Lukáš Kucharczyk
95e97fea01 Translated using Weblate (Czech)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/cs/
2022-03-14 17:21:44 -04:00
Cody Robibero
cf47ee6261 Merge pull request #7449 from crobibero/revert-clamp 2022-03-13 12:46:30 -06:00
Cody Robibero
d29c7c1d9e Revert using Math.Clamp 2022-03-13 12:46:13 -06:00
Rasmus
72165ae96f Translated using Weblate (Pirate)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/pr/
2022-03-12 15:33:47 -05:00
WWWesten
34af6c48d7 Translated using Weblate (English (United Kingdom))
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/en_GB/
2022-03-12 15:33:47 -05:00
Cody Robibero
e6df698df1 Merge pull request #7325 from eyezak/issue/6450 2022-03-12 09:08:25 -07:00
Cody Robibero
8ddcdc7430 Merge pull request #7448 from nielsvanvelzen/itemfreshcontroller 2022-03-12 08:56:45 -07:00
Niels van Velzen
d659b9b9ab Restrict item refreshing to administrators 2022-03-12 15:47:30 +01:00
Niels van Velzen
6bb50d5728 Change operation name in ItemRefreshController 2022-03-12 15:43:29 +01:00
Cody Robibero
3ea4174d12 Fix flipped Clamp args 2022-03-12 07:17:59 -07:00
Cody Robibero
5319f1571f Merge pull request #7444 from Bond-009/baseurl 2022-03-11 18:42:14 -07:00
Joshua M. Boniface
6e80c9b25f Merge pull request #6528 from oledfish/additional-episode-orders 2022-03-11 14:35:29 -05:00
Bond_009
7fdc0e3c3d BaseItem: remove unused function 2022-03-11 16:21:32 +01:00
Cody Robibero
28223704f3 Merge pull request #7441 from 1337joe/add-external-stream-indicator
Add label for external audio/sub tracks
2022-03-11 07:48:23 -07:00
Bond_009
edeb198313 Add tests for BaseUrl normalization 2022-03-11 15:44:16 +01:00
Joe Rogers
f671eeb6b2 Add self to CONTRIBUTORS.md 2022-03-11 15:23:17 +01:00
xnick
3342c29f4f Translated using Weblate (Greek)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/el/
2022-03-11 09:13:33 -05:00
Shadowghost
b2188c8676 Translated using Weblate (German)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/de/
2022-03-11 09:13:33 -05:00
Claus Vium
53209830e7 Merge pull request #7346 from Bond-009/guid
Optimize Guid comparisons
2022-03-11 08:15:12 +01:00
Claus Vium
21ef6661d6 Merge pull request #7440 from 1337joe/fix-add-external-audio
Match external sub/audio stream adding logic
2022-03-11 08:03:18 +01:00
whiteowl3
6f25291931 allow strm probe to succeed 2022-03-11 06:54:25 +00:00
Joe Rogers
1a307db7eb Add label for external audio/sub tracks 2022-03-10 22:20:35 +01:00
Cody Robibero
a5ffde0e9c Merge pull request #7432 from Bond-009/socketfactory 2022-03-10 14:19:08 -07:00
Joe Rogers
ac83effd44 Match external sub/audio stream adding logic 2022-03-10 22:02:46 +01:00
Mayur Panchal
96de01ce01 ProbeResultNormalizer: fix framerate compare + tests (#7167) 2022-03-10 20:55:30 +01:00
Bond_009
470d175f32 ExclusiveAddressUse: cheated by the docs 2022-03-10 20:51:22 +01:00
Joshua M. Boniface
388e0cba9f Merge pull request #7434 from crobibero/dotnet-6.0.3 2022-03-10 12:47:18 -05:00
Joshua M. Boniface
11fc84eebe Merge pull request #7435 from nyanmisaka/seek-fmp4 2022-03-10 12:44:28 -05:00
sabretou
1e80ba0462 Translated using Weblate (Marathi)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/mr/
2022-03-09 22:12:40 -05:00
Cody Robibero
a397cec981 Merge pull request #7410 from MinecraftPlaye/show-diff-dts-versions 2022-03-09 07:18:13 -07:00
nyanmisaka
b2c58338f2 Fix the fMP4 HLS audio sync issue on Safari 2022-03-09 21:28:58 +08:00
Cody Robibero
965bf7332f Update to dotnet 6.0.3 2022-03-08 17:16:33 -07:00
Cody Robibero
dacbfc83ff Merge pull request #7431 from Bond-009/autodiscovery 2022-03-08 14:37:01 -07:00
Bond_009
1d018c5575 SocketFactory: Remove redundant code
ExclusiveAddressUse should be false by default afaik
2022-03-08 22:20:43 +01:00
Bond_009
16e0d46771 UdpServerEntryPoint: Fix typo 2022-03-08 22:11:06 +01:00
Nyanmisaka
4f1efb3996 Re-enable the legacy NVIDIA CUVID decoder in full HWA pipeline (#7413) 2022-03-08 16:36:30 +01:00
Bill Thornton
c5ca29d2e2 Remove unused poster support from StudiosImageProvider (#7423) 2022-03-08 16:36:05 +01:00
Bond-009
03f1eff21a Implement TransportState according to spec (#7426) 2022-03-08 16:12:03 +01:00
Mattias
e3ea899bcc Translated using Weblate (Swedish)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/sv/
2022-03-08 03:52:36 -05:00
Thomas Schwery
88c4e38ce2 Translated using Weblate (French)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/fr/
2022-03-07 17:54:08 -05:00
Cody Robibero
ea7e6aeae0 Merge pull request #7425 from Bond-009/aurating 2022-03-07 13:45:30 -07:00
Bond_009
f48c8d4802 Remove none existing Australian rating
I'm not sure the numbers here are correct
2022-03-07 21:00:13 +01:00
Ali Dastpour
0ef35286c5 Translated using Weblate (Persian)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/fa/
2022-03-07 11:58:16 -05:00
dependabot[bot]
1ec3e899d6 Bump actions/checkout from 2 to 3 (#7420)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-03-07 16:44:10 +01:00
dependabot[bot]
023eddbef5 Bump actions/stale from 4.1.0 to 5 (#7421)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-03-07 16:43:59 +01:00
Cody Robibero
10d1c7b25d Merge pull request #7418 from jellyfin/dependabot/nuget/prometheus-net.AspNetCore-6.0.0
Bump prometheus-net.AspNetCore from 5.0.2 to 6.0.0
2022-03-07 07:47:15 -07:00
dependabot[bot]
de766e687d Bump prometheus-net.AspNetCore from 5.0.2 to 6.0.0
Bumps [prometheus-net.AspNetCore](https://github.com/prometheus-net/prometheus-net) from 5.0.2 to 6.0.0.
- [Release notes](https://github.com/prometheus-net/prometheus-net/releases)
- [Changelog](https://github.com/prometheus-net/prometheus-net/blob/master/History)
- [Commits](https://github.com/prometheus-net/prometheus-net/compare/v5.0.2...v6.0.0)

---
updated-dependencies:
- dependency-name: prometheus-net.AspNetCore
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-07 13:25:23 +00:00
dependabot[bot]
bb83e9f2d9 Bump prometheus-net from 5.0.2 to 6.0.0 (#7417)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-03-07 14:24:21 +01:00
dependabot[bot]
4c4f5dfe81 Bump Moq from 4.17.1 to 4.17.2 (#7416)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-03-07 14:23:43 +01:00
Cody Robibero
da41cd365c Suggestions from review 2022-03-06 18:17:49 -07:00
Cody Robibero
dbea7cac67 Use Enum.GetValues<T>() 2022-03-06 18:13:54 -07:00
Cody Robibero
bbd5d11d3b Remove TranscodeReason.None, Add JsonFlagEnum tests 2022-03-06 18:13:54 -07:00
Cody Robibero
c331e11c24 Clean up EnumFlags serialization 2022-03-06 18:13:54 -07:00
Isaac Gordezky
9ebd521754 Update MediaBrowser.Model/Dlna/StreamBuilder.cs
Co-authored-by: Cody Robibero <cody@robibe.ro>
2022-03-06 18:13:54 -07:00
Isaac Gordezky
84a3db6f84 Fix transcode video matching and add tests for Transcode and Safari 2022-03-06 18:13:54 -07:00
Isaac Gordezky
5e779f20ee Series: issue-6450
Issue: https://github.com/jellyfin/jellyfin/issues/6450

Enable DirectPlay responses
Rewrite DirectPlay and DirectStream resolution
Prefer copy transcode video codec options
Enhance condition processor
Support DirectStream and Transcode with parity
Rework audio stream selection and add tests for ExternalAudio
Update MediaInfoHelper to only call StreamBuilder once
2022-03-06 18:13:54 -07:00
Isaac Gordezky
d871dded9f Convert TranscodeReason to Flags 2022-03-06 18:13:54 -07:00
Isaac Gordezky
a3057afde8 StreamBuilder basic tests 2022-03-06 18:13:54 -07:00
Patrick Farwick
27b81a535c Let the UI show which DTS profile is in use
There are different profiles for DTS. For example, both DTS and DTS-HD
MA use the same codec, but provide a different profile.

Some files may provide both a DTS and DTS-HD MA audio track. With this
change, the UI shows which track is using which profile to allow the
user to choose between them.
2022-03-06 19:11:02 +00:00
Cody Robibero
1dcd537ea2 Merge pull request #7411 from jellyfin/revert-7240-add-readonly-connection 2022-03-06 11:04:36 -07:00
Cody Robibero
0a8bec1af4 Revert "chore: Add a read only connection for routes like Shows/NextUp" 2022-03-06 09:30:47 -07:00
Cody Robibero
973781c482 Merge pull request #7406 from crobibero/fix-build
Fix build
2022-03-06 06:47:32 -07:00
Cody Robibero
b37052a4a6 Fix build 2022-03-06 06:34:04 -07:00
Cody Robibero
15cae4ef00 Merge pull request #7405 from StollD/fix-strm-files 2022-03-05 15:03:45 -07:00
Dorian Stoll
7af1cae883 Add myself to CONTRIBUTORS.md 2022-03-05 22:15:43 +01:00
Dorian Stoll
178d00b14d Readd .strm as an allowed extension for videos 2022-03-05 22:05:26 +01:00
Cody Robibero
bc3cb04c0b Merge pull request #7240 from jaysonsantos/add-readonly-connection 2022-03-05 13:36:40 -07:00
Bond-009
2579b2db56 Merge pull request #7137 from SenorSmartyPants/master 2022-03-05 20:54:36 +01:00
Cody Robibero
3dc0cfc36e Merge pull request #7388 from GermanCoding/iso639-undefined 2022-03-05 12:43:51 -07:00
Cody Robibero
4791d56f6c Merge pull request #7403 from 1337joe/fix-external-file-prefix-check 2022-03-05 12:43:29 -07:00
Cody Robibero
b705ace262 Apply suggestions from code review 2022-03-05 12:37:23 -07:00
Joshua M. Boniface
947ff9defe Merge pull request #7404 from nyanmisaka/omx 2022-03-05 14:35:41 -05:00
Joshua M. Boniface
414004f83d Merge pull request #7397 from jellyfin/intel-vaapi 2022-03-05 14:30:30 -05:00
Joshua M. Boniface
e3d9c53baa Merge pull request #7396 from thornbill/update-artwork-repository 2022-03-05 14:30:21 -05:00
Joshua M. Boniface
a123391e7e Merge pull request #7383 from thornbill/next-up-rewatching 2022-03-05 14:29:49 -05:00
Rhodri
9f027bae41 Translated using Weblate (Welsh)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/cy/
2022-03-05 13:13:31 -05:00
Ray Cheung
5eda32980c Translated using Weblate (Chinese (Hong Kong))
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/zh_Hant_HK/
2022-03-05 13:13:31 -05:00
Jorge IG
76019d3a34 Translated using Weblate (Spanish)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/es/
2022-03-05 13:13:31 -05:00
nyanmisaka
3bf83025f2 Fallback to no HWA when reporting transcoding info 2022-03-06 00:12:16 +08:00
nyanmisaka
bfc27e494b Remove the deprecated OMX and MMAL HWA 2022-03-05 21:47:59 +08:00
Joe Rogers
f7118bebfd Fix external file check for shorter names 2022-03-05 12:39:03 +01:00
Claus Vium
fab5f37e0e Merge pull request #7394 from 1337joe/remove-external-file-fuzzy-matching
Strip out external file fuzzy name matching
2022-03-05 09:26:55 +01:00
nyanmisaka
de4a084b03 Set the name of intel vaapi driver explicitly
Fix crashes on older intel gfx when both iHD and i965 driver are existed.
2022-03-05 01:32:06 +08:00
GermanCoding
3f6a14e1fd Use extension method for list search 2022-03-04 16:44:55 +01:00
Joe Rogers
dad7a6fdf6 Switch to using spans for string comparison 2022-03-04 15:58:01 +01:00
Joe Rogers
3205e97e1e Strip out external file fuzzy matching
Convert MediaFlagDelimiter back to char
2022-03-04 10:52:21 +01:00
Claus Vium
136eab9b1e Merge pull request #7370 from crobibero/internal-metadata-path
Only add internal files if the internal metadata path exists
2022-03-04 08:13:58 +01:00
Bill Thornton
46ef68d589 Update artwork repository urls 2022-03-04 01:39:21 -05:00
WWWesten
f712c554ab Translated using Weblate (Esperanto)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/eo/
2022-03-03 19:21:04 -05:00
hoanghuy309
e58f7ae5da Translated using Weblate (Vietnamese)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/vi/
2022-03-03 19:21:04 -05:00
Oatavandi
92fd6475fa Translated using Weblate (Tamil)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/ta/
2022-03-03 19:21:04 -05:00
Oskari Lavinto
8121635d8c Translated using Weblate (Finnish)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/fi/
2022-03-03 19:21:04 -05:00
小造xu_zh
9025cd13c5 Translated using Weblate (Chinese (Simplified))
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/zh_Hans/
2022-03-03 19:21:04 -05:00
WWWesten
2ce0389d59 Translated using Weblate (Russian)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/ru/
2022-03-03 19:21:04 -05:00
WWWesten
957199dcba Translated using Weblate (Kazakh)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/kk/
2022-03-03 19:21:03 -05:00
Csaba
73805e0b4a Translated using Weblate (Hungarian)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/hu/
2022-03-03 19:21:03 -05:00
Page Asgardius
f3de108617 Translated using Weblate (Spanish (Mexico))
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/es_MX/
2022-03-03 19:21:03 -05:00
Lukáš Kucharczyk
94793e6c6b Translated using Weblate (Czech)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/cs/
2022-03-03 19:21:03 -05:00
GermanCoding
e09641b452 Hide ISO 639-2 special codes in display titles
They are still shown in associated metadata, just hidden from the more visible display titles.
2022-03-04 00:55:20 +01:00
Bond-009
b356c2b212 Merge pull request #7324 from Maxr1998/sort-by-index 2022-03-03 13:55:45 +01:00
Bond-009
2dbb32976c Merge pull request #7380 from crobibero/general-command 2022-03-03 13:55:33 +01:00
Bond-009
6e91657f01 Merge pull request #7381 from crobibero/migrate-datetime 2022-03-03 13:55:09 +01:00
Cody Robibero
1b3e56bae3 Split DirectoryExists and FileExists 2022-03-02 19:55:44 -07:00
Bill Thornton
df70d7bdf1 Use IReadOnlyList for seriesKeys 2022-03-02 10:17:24 -05:00
DetermineAbsurd
d16bdfbc05 Translated using Weblate (Pirate)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/pr/
2022-03-02 08:13:30 -05:00
Aman Setia
fe53243cfb Translated using Weblate (Hindi)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/hi/
2022-03-02 08:13:30 -05:00
Claus Vium
6498a5baca Merge pull request #7387 from jellyfin/nvdec-threads 2022-03-01 16:53:23 +01:00
Cody Robibero
71a9ae3150 Update MediaBrowser.Controller/Providers/DirectoryService.cs
Co-authored-by: Joe Rogers <1337joe@users.noreply.github.com>
2022-03-01 08:30:26 -07:00
Nyanmisaka
4239f80c81 Lowering the VRAM usage on NVDEC decoder 2022-03-01 23:14:35 +08:00
Cody Robibero
f0c28019dc Merge pull request #7386 from jellyfin/fonts 2022-03-01 08:13:53 -07:00
Nyanmisaka
ba8e478a2f Fix the path to the extracted fonts on Windows 2022-03-01 22:41:54 +08:00
Cody Robibero
0a953aca8a Merge pull request #7372 from jellyfin/dependabot/github_actions/actions/setup-dotnet-2 2022-03-01 06:45:00 -07:00
Bond-009
7d226e8eef Merge pull request #7376 from GermanCoding/fix_soundhandler 2022-03-01 11:24:20 +01:00
Bond-009
eff3d3e67e Merge pull request #7275 from Nalsai/burn-subtitle-attached-fonts 2022-03-01 11:21:19 +01:00
Bond-009
ef99a53abb Merge pull request #7366 from 1337joe/filter-theme-song-and-video 2022-03-01 11:12:32 +01:00
Bond-009
1e98f168c9 Merge pull request #7363 from 1337joe/ffmpeg-5-long-chapter-id 2022-03-01 11:11:23 +01:00
Bond-009
2bc8383968 Merge pull request #7382 from crobibero/keyframe-extractor 2022-03-01 10:55:02 +01:00
Bill Thornton
055c63bdee Include played and unplayed results in the same next up request 2022-03-01 00:50:16 -05:00
Joshua M. Boniface
7c9aa63382 Merge pull request #6058 from ferferga/deprecate-queueitem 2022-02-28 23:54:50 -05:00
Cody Robibero
5e1f956fe0 Allow KeyframeExtractor to be localized 2022-02-28 20:59:36 -07:00
Cody Robibero
89c29a7ed8 Fix migration of DateTime to EF 2022-02-28 20:44:17 -07:00
Cody Robibero
fe99800bde Merge pull request #7221 from SenorSmartyPants/UserViewThumb 2022-02-28 20:17:30 -07:00
Cody Robibero
3c0c7572ef Merge pull request #7338 from mueslimak3r/hls-remove-seek-param 2022-02-28 20:16:19 -07:00
Cody Robibero
3f441a44ba Merge pull request #7374 from jellyfin/intel-ocl 2022-02-28 20:15:32 -07:00
Cody Robibero
aec1ee5869 Merge pull request #7375 from jellyfin/presets-nvenc 2022-02-28 20:15:14 -07:00
Cody Robibero
c0b02ff0e5 Merge pull request #7378 from thornbill/fix-default-home-sections 2022-02-28 20:15:04 -07:00
Cody Robibero
dc1b224667 Add JsonConstructor 2022-02-28 17:30:17 -07:00
Cody Robibero
fc5c6c0404 Use IFileSystem 2022-02-28 17:14:33 -07:00
Bill Thornton
f32b2cb592 Add resume book as default home section 2022-02-28 16:33:17 -05:00
Joe Rogers
1d367712bb Improve tests 2022-02-28 10:00:23 -07:00
Cody Robibero
c9d5cfff1d Update MediaBrowser.Providers/MediaInfo/MediaInfoResolver.cs
Co-authored-by: Joe Rogers <1337joe@users.noreply.github.com>
2022-02-28 09:58:11 -07:00
GermanCoding
847d705969 Update CONTRIBUTORS.md (adding myself) 2022-02-28 17:47:57 +01:00
GermanCoding
11bb834957 Remove superfluous "SoundHandler" from audio stream names 2022-02-28 17:44:23 +01:00
Cody Robibero
40e413d575 Only add internal files if the internal metadata path exists
Signed-off-by: Cody Robibero <cody@robibe.ro>
2022-02-28 08:22:52 -07:00
Bond-009
cd4d51a515 Merge pull request #7371 from jellyfin/dependabot/nuget/Moq-4.17.1 2022-02-28 16:12:16 +01:00
Cody Robibero
f1808f6ae4 Merge pull request #7369 from Bond-009/jellyplus 2022-02-28 08:09:59 -07:00
Nyanmisaka
9251c875b1 Update presets for NVENC encoder 2022-02-28 23:05:08 +08:00
Nyanmisaka
10282dc444 Update intel compute runtime to 22.08.22549 2022-02-28 22:50:27 +08:00
Nyanmisaka
3fb3d7159c Update intel compute runtime to 22.05.22297 2022-02-28 21:13:06 +08:00
dependabot[bot]
11092a72a4 Bump actions/setup-dotnet from 1 to 2
Bumps [actions/setup-dotnet](https://github.com/actions/setup-dotnet) from 1 to 2.
- [Release notes](https://github.com/actions/setup-dotnet/releases)
- [Commits](https://github.com/actions/setup-dotnet/compare/v1...v2)

---
updated-dependencies:
- dependency-name: actions/setup-dotnet
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-28 12:06:19 +00:00
dependabot[bot]
ee24b85f49 Bump Moq from 4.16.1 to 4.17.1
Bumps [Moq](https://github.com/moq/moq4) from 4.16.1 to 4.17.1.
- [Release notes](https://github.com/moq/moq4/releases)
- [Changelog](https://github.com/moq/moq4/blob/main/CHANGELOG.md)
- [Commits](https://github.com/moq/moq4/compare/v4.16.1...v4.17.1)

---
updated-dependencies:
- dependency-name: Moq
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-28 12:01:22 +00:00
Bond_009
acf30e00ce Remove obsolete code for premium plugins 2022-02-28 00:46:34 +01:00
Joe Rogers
354f22d065 Add post filtering for theme song and video 2022-02-27 23:38:00 +01:00
Joe Rogers
175ddff169 Switch chapter id to long to not break on ffmpeg 5.0 2022-02-27 21:04:11 +01:00
Joshua M. Boniface
e26446f9c0 Merge pull request #7112 from stanionascu/bdiso-playback 2022-02-26 12:53:34 -05:00
Cody Robibero
d7cbb25d0b Merge pull request #7291 from aolszowka/aolszowka-EncodingHelperChanges 2022-02-26 10:52:35 -07:00
Ali Dastpour
536ad62ea8 Translated using Weblate (Persian)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/fa/
2022-02-26 08:31:06 -05:00
Bond-009
ce62a4465a Merge pull request #7349 from 1337joe/MediaInfoResolver-tests 2022-02-22 19:44:36 +01:00
Joe Rogers
a9a3f6bf02 Split match/rejected tests, add wider sampling of extensions 2022-02-22 15:13:44 +01:00
Joe Rogers
cf033b25f8 Require delimiter immediately after filename match 2022-02-21 22:27:28 +01:00
Joe Rogers
15053516f8 Rewrite tests for coverage and less duplication
Address minor warnings
Revert making GetInternalMetadataPath mockable
2022-02-21 22:25:58 +01:00
Joshua M. Boniface
59040bfa7d Merge pull request #7255 from Shadowghost/external-sub-audio 2022-02-21 12:42:49 -05:00
Cody Robibero
d1f6a7f497 Merge pull request #7344 from jellyfin/dependabot/nuget/Microsoft.NET.Test.Sdk-17.1.0 2022-02-21 07:37:28 -07:00
Bond_009
f50a250cd9 Optimize Guid comparisons
* Use Guid.Equals(Guid) instead of the == override
* Ban the usage of Guid.Equals(Object) to prevent accidental boxing
* Compare to default(Guid) instead of Guid.Empty
2022-02-21 14:15:09 +01:00
Isaac Gordezky
def8500dd0 Update MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs
Co-authored-by: Cody Robibero <cody@robibe.ro>
2022-02-21 07:54:13 -05:00
dependabot[bot]
06f259001c Bump Microsoft.NET.Test.Sdk from 17.0.0 to 17.1.0
Bumps [Microsoft.NET.Test.Sdk](https://github.com/microsoft/vstest) from 17.0.0 to 17.1.0.
- [Release notes](https://github.com/microsoft/vstest/releases)
- [Commits](https://github.com/microsoft/vstest/compare/v17.0.0...v17.1.0)

---
updated-dependencies:
- dependency-name: Microsoft.NET.Test.Sdk
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-21 12:01:10 +00:00
SenorSmartyPants
bbac59c6d6 Rewatching next up (#7253) 2022-02-20 18:05:57 +01:00
Cody Robibero
a61b42f7ef Merge pull request #7332 from eyezak/transcode-reporting 2022-02-20 09:32:09 -07:00
Stanislav Ionascu
554d1b2ca8 Fix #7100 by catching the exception on opening invalid UDF images
When an invalid UDF image is opened by the UdfReader, it may throw
and exception. This change is to catch and log the exception.
2022-02-20 13:30:55 +00:00
Shadowghost
bbb3117f83 Update MediaBrowser.Providers/MediaInfo/MediaInfoResolver.cs
Co-authored-by: Bond-009 <bond.009@outlook.com>
2022-02-19 23:47:11 +01:00
Niels van Velzen
6a8a6a1325 Use sha hash instead of branch name for OpenAPI workflow head reference (#7340) 2022-02-19 17:36:53 +01:00
cameron
36cdeaa53c dont use noaccurate_seek for hls 2022-02-18 23:18:28 -08:00
Shadowghost
a36e34fbd2 fix(external-media): implement review suggestions 2022-02-18 22:19:33 +01:00
Shadowghost
719b707281 feat(external-media): refactor to generic provider, extend tests and file recognition, consolidate and extend NamingOptions 2022-02-18 22:19:33 +01:00
Joe Rogers
f1878c43a4 feat(external-media): add tests for external audio and subtitle provider 2022-02-18 22:19:33 +01:00
Shadowghost
ca5112f45a feat(external-media): refactor external subtitle and audio provider 2022-02-18 22:19:24 +01:00
Isaac Gordezky
151ddd400d [Bugfix] Provile bitStreamArgs for HLS fMP4
Enable the audio bitstream arguments to ffmpeg for both ts and fMP4 HLS streaming
2022-02-18 13:18:08 +00:00
Isaac Gordezky
48a7d3f48f [Bugfix] Report transcoding complete
Currently, when transcoding finishes it is not reported - leaving the UI with an incomplete transcode %
This change reports transcoding progress as empty / complete when the transcoding job finishes
2022-02-18 13:01:19 +00:00
Cody Robibero
b92e1baa3c Merge pull request #7326 from Bond-009/deadcode2 2022-02-17 18:07:49 -07:00
Bond_009
adad13b865 Remove some dead code 2022-02-17 08:15:26 +01:00
Cody Robibero
7ccf7e6157 Merge pull request #7322 from Bond-009/db2 2022-02-16 20:47:33 -07:00
Cody Robibero
9930efec22 Merge pull request #7321 from Bond-009/warn61 2022-02-16 20:47:22 -07:00
Maxr1998
0aaf2f470a Implement Comparers for (Parent)IndexNumber
Can be used in item queries to sort by ParentIndexNumber and IndexNumber (used for disc and track numbers for example).
2022-02-17 01:35:59 +01:00
Bond_009
23ea14aa27 Clean up SqliteItemRepository
* remove dead code
* reduce allocations
2022-02-15 22:27:38 +01:00
Bond_009
5732e6188c Fix some warnings 2022-02-15 18:59:46 +01:00
Lukáš Kucharczyk
5825a0572b Translated using Weblate (Czech)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/cs/
2022-02-15 01:13:23 -05:00
Cody Robibero
4ef0099598 Merge pull request #7233 from Bond-009/warn60 2022-02-14 16:57:00 -07:00
Cody Robibero
4acab00963 Merge pull request #7038 from Bond-009/serverdiscovery 2022-02-14 16:56:29 -07:00
Joshua M. Boniface
94b5334da5 Merge pull request #7290 from crobibero/dotnet-6.0.2 2022-02-14 11:01:55 -05:00
Victor Gambier
dbf9e49258 Increase timeout for subtitle extraction to 30min (#7153) 2022-02-14 16:33:11 +01:00
Bond_009
5d28c5547e Fix indentation 2022-02-14 16:31:07 +01:00
Bond_009
dbd7be091d Fix MediaStreamSelector 2022-02-14 15:03:08 +01:00
Bond_009
8b2556adba Fix display preferences 2022-02-14 14:46:04 +01:00
Bond_009
1c14c86b20 Fix some warnings 2022-02-14 14:46:04 +01:00
Bond_009
3cb49d6df0 Fix option to disable server discovery 2022-02-14 14:39:33 +01:00
dependabot[bot]
68e7072698 Bump MimeTypes from 2.2.1 to 2.3.0 (#7309)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-02-14 14:14:04 +01:00
Bond-009
69e7deb07d Merge pull request #7300 from cvium/fix_keepreading 2022-02-12 20:24:02 +01:00
cvium
8ec71c094a Change KeepReading to StopReading and use bytes read as an indicator 2022-02-12 09:51:47 +01:00
dottokuya
8a2ebae74d Translated using Weblate (Vietnamese)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/vi/
2022-02-11 23:21:28 -05:00
Cody Robibero
603b6fe173 Merge pull request #7054 from matthew-jones-uk/disable-embedded-subs 2022-02-11 13:20:37 -07:00
knackebrot
52c61bd06f Add option to change unix socket permissions
There is probably no way to do it when creating the socket
2022-02-10 02:07:12 +01:00
Nils Fürniß
ab40554759 add extracting attachments for ffmpeg to burn subs 2022-02-10 01:01:08 +01:00
Matthew Jones
b7cab46b4a Added values to EmbeddedSubtitleOptions enum 2022-02-09 23:33:46 +00:00
Bond-009
bb7916767c Merge pull request #7286 from daullmer/sonarr-thumb 2022-02-09 19:09:53 +01:00
David Ullmer
a00e6ff426 Update tests/Jellyfin.XbmcMetadata.Tests/Parsers/EpisodeNfoProviderTests.cs
Co-authored-by: Claus Vium <cvium@users.noreply.github.com>
2022-02-09 13:39:39 +01:00
Cody Robibero
b98cc71c3b Update to dotnet 6.0.2
Signed-off-by: Cody Robibero <cody@robibe.ro>
2022-02-08 17:36:20 -07:00
Cody Robibero
103a8e69a7 Merge pull request #7282 from jellyfin/dependabot/nuget/System.Linq.Async-6.0.1
Bump System.Linq.Async from 5.1.0 to 6.0.1
2022-02-08 05:43:53 -07:00
Cody Robibero
75cdfe4daf Merge pull request #7283 from jellyfin/dependabot/nuget/coverlet.collector-3.1.2
Bump coverlet.collector from 3.1.1 to 3.1.2
2022-02-08 05:43:08 -07:00
Cody Robibero
d855b6872a Merge pull request #7284 from jellyfin/dependabot/nuget/prometheus-net.DotNetRuntime-4.2.3
Bump prometheus-net.DotNetRuntime from 4.2.2 to 4.2.3
2022-02-08 05:42:46 -07:00
David Ullmer
fdfcb45c2a Add regression test for #7285 2022-02-08 09:09:33 +01:00
David Ullmer
7885167f54 Fix nfo thumb tags without aspect 2022-02-08 09:08:35 +01:00
Ace Olszowka
ea7e5e639d Fix h264_v4l2m2m acceleration in Raspberry Pi 4 2022-02-07 20:41:07 -07:00
dependabot[bot]
08e90039b1 Bump prometheus-net.DotNetRuntime from 4.2.2 to 4.2.3
Bumps [prometheus-net.DotNetRuntime](https://github.com/djluck/prometheus-net.DotNetRuntime) from 4.2.2 to 4.2.3.
- [Release notes](https://github.com/djluck/prometheus-net.DotNetRuntime/releases)
- [Commits](https://github.com/djluck/prometheus-net.DotNetRuntime/compare/4.2.2...4.2.3)

---
updated-dependencies:
- dependency-name: prometheus-net.DotNetRuntime
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-07 12:01:14 +00:00
dependabot[bot]
7649391b9d Bump coverlet.collector from 3.1.1 to 3.1.2
Bumps [coverlet.collector](https://github.com/coverlet-coverage/coverlet) from 3.1.1 to 3.1.2.
- [Release notes](https://github.com/coverlet-coverage/coverlet/releases)
- [Commits](https://github.com/coverlet-coverage/coverlet/commits)

---
updated-dependencies:
- dependency-name: coverlet.collector
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-07 12:01:11 +00:00
dependabot[bot]
0c89459d5b Bump System.Linq.Async from 5.1.0 to 6.0.1
Bumps [System.Linq.Async](https://github.com/dotnet/reactive) from 5.1.0 to 6.0.1.
- [Release notes](https://github.com/dotnet/reactive/releases)
- [Commits](https://github.com/dotnet/reactive/compare/ixnet-v5.1.0...ixnet-v6.0.1)

---
updated-dependencies:
- dependency-name: System.Linq.Async
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-07 12:01:03 +00:00
Cody Robibero
b6489e73ab Merge pull request #7241 from Bond-009/async5 2022-02-06 15:25:48 -07:00
Cody Robibero
10d52d16a8 Fix invalid cref (#7277) 2022-02-06 22:21:17 +01:00
Emil Manea
f3c3402984 Translated using Weblate (Romanian)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/ro/
2022-02-04 16:13:20 -05:00
SenorSmartyPants
2b769aae69 TV extras (#7178) 2022-02-04 20:44:38 +01:00
Cody Robibero
c16d71562e Prevent additional errors on startup/shutdown (#6788) 2022-02-04 20:36:17 +01:00
Cody Robibero
a2127a48ef Remove unused docker volumes (#7030) 2022-02-02 23:27:46 +01:00
SenorSmartyPants
509d66dcb5 Fix #7147: Don't return subtitles in mismatched format (#7149) 2022-02-02 23:24:10 +01:00
Nyanmisaka
6c53420fe3 Fix the broken fMP4 main playlist (#7263) 2022-02-01 22:30:19 +01:00
dependabot[bot]
6af7d5445f Bump coverlet.collector from 3.1.0 to 3.1.1 (#7266)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-02-01 22:29:41 +01:00
Cody Robibero
f863ca1f2d Merge pull request #7245 from h1dden-da3m0n/chore/stale-check-workflow 2022-01-28 08:12:44 -07:00
Cody Robibero
e5701c396a Merge pull request #6436 from daullmer/splashscreen 2022-01-28 08:12:21 -07:00
Claus Vium
488ce51032 Remove some allocations (#7246) 2022-01-28 12:21:40 +01:00
Bond-009
42724ef411 Merge pull request #7257 from Shadowghost/slash-artists 2022-01-28 12:17:08 +01:00
Shadowghost
4a3f1a51d2 chore(artist-split): add more artists to split whitelist 2022-01-27 22:01:40 +01:00
abdulla
83605affa0 Translated using Weblate (Uyghur)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/ug/
2022-01-27 07:13:16 -05:00
Matthew Jones
91d143d6ee Changed boolean options to enums 2022-01-26 16:09:05 +00:00
abdulla
29f92724ef Added translation using Weblate (Uyghur) 2022-01-26 05:56:56 -05:00
K3rnelPan1c
614abddd64 remove obsolete permissions block
we use the JF_BOT_TOKEN PAT and not the default GITHUB_TOKEN
2022-01-25 22:53:09 +01:00
K3rnelPan1c
fabe7e1fb9 add org filter to stale workflow 2022-01-25 18:32:46 +01:00
Yohann Yo
887beee614 Translated using Weblate (French)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/fr/
2022-01-25 11:29:36 -05:00
K3rnelPan1c
0c665af124 change PAT use for stale action 2022-01-23 18:19:39 +01:00
h1dden-da3m0n
28f4d574f7 add stale issue check workflow
this should replace the functionality of the discontinued stale-bot
2022-01-23 17:02:41 +01:00
Jayson Reis
09b8cde6aa fix: Avoid opening read connections without mutexes 2022-01-23 11:59:12 +01:00
Cody Robibero
ea3d79c0eb Merge pull request #7235 from Bond-009/async4 2022-01-22 15:52:12 -07:00
Cody Robibero
3c746f2743 Merge pull request #7236 from Bond-009/taskcompletionsource 2022-01-22 15:46:19 -07:00
Cody Robibero
da49437549 Merge pull request #7238 from 1337joe/ffprobe-metadata-merge 2022-01-22 15:46:04 -07:00
Cody Robibero
26ba99e420 Merge pull request #7239 from nielsvanvelzen/parent-guid 2022-01-22 15:44:55 -07:00
Bond_009
e7be01d7a5 Flush to disk async where possible 2022-01-22 23:36:42 +01:00
Jayson Reis
2e4dd02f76 chore: Add a read only connection for routes like Shows/NextUp 2022-01-22 21:52:30 +00:00
Niels van Velzen
2afcaa6ae1 Use Guid for BaseItemDto parent ids 2022-01-22 22:29:02 +01:00
Joe Rogers
fbd243e315 Make ffprobe consistent with MetadataService.MergeData 2022-01-22 21:59:17 +01:00
Bond-009
4f1eed862e Merge pull request #7234 from nielsvanvelzen/baseitemperson-guid 2022-01-22 17:08:02 +01:00
Bond_009
832da133d8 Always create TaskCompletionSource<T> with TaskCreationOptions.RunContinuationsAsynchronously 2022-01-22 17:06:57 +01:00
Bond_009
2dcb2f8a9f Ban the usage of Task.Result
If the calling function can't be made async easily you can still use
.GetAwaiter().GetResult(), which is way easier to find in the future
2022-01-22 16:48:31 +01:00
Niels van Velzen
e86f778c05 Use Guid for BaseItemPerson.Id 2022-01-22 15:46:12 +01:00
Bond-009
cd675475bc Merge pull request #7225 from crobibero/query-result 2022-01-21 19:50:08 +01:00
Cody Robibero
34ee6d82fb Merge pull request #6600 from cvium/keyframe_extraction_v1 2022-01-20 08:54:40 -07:00
Cody Robibero
a4246648f4 Merge pull request #7219 from 1337joe/tmdb-image-provider-logo 2022-01-20 08:54:07 -07:00
Cody Robibero
ee43b5117d Merge pull request #7217 from SenorSmartyPants/LibraryImages 2022-01-20 08:53:53 -07:00
Cody Robibero
a60cb280a3 Properly populate QueryResult 2022-01-20 08:53:06 -07:00
Joe Rogers
375903b215 Bump TMDbLib version 2022-01-20 11:43:26 +01:00
Lukáš Kucharczyk
cd4587b43f Translated using Weblate (Czech)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/cs/
2022-01-20 03:13:14 -05:00
SenorSmartyPants
5d9e1bfcea Shuffle items with images
They were always returning in the same order so thumb would never change.
2022-01-19 19:16:36 -06:00
SenorSmartyPants
b15ab397c7 User Backdrop for UserView, like CollectionFolder 2022-01-19 19:15:44 -06:00
Bond-009
3aeae150f8 Merge pull request #7176 from dmitrylyzo/fix-trailers-1 2022-01-19 22:47:08 +01:00
Claus Vium
8b36bc0ade Merge pull request #7203 from 1337joe/fix-resolving-local-alternates
Fix resolving local alternates
2022-01-19 14:36:50 +01:00
Joe Rogers
239b516659 Add TMDb logo handling 2022-01-19 09:54:52 +01:00
SenorSmartyPants
5c3119cf02 Generate cover image for music video type libraries. 2022-01-18 19:46:03 -06:00
Claus Vium
1a32153a31 Merge pull request #7197 from dmitrylyzo/fix-max-resolution
Fix maximum video resolution for dynamic HLS controller
2022-01-18 07:54:48 +01:00
oledfish
47269d5ec6 Add all TMDB episode orders 2022-01-18 01:02:45 -03:00
oledfish
3b075a5802 Merge branch 'jellyfin:master' into additional-episode-orders 2022-01-16 21:33:18 -03:00
Bond-009
ef0708d876 Merge pull request #7078 from 1337joe/metadata-merge-data 2022-01-16 23:17:40 +01:00
Joe Rogers
8b706cebef Add alternate resolver test, generate extra folder names 2022-01-16 23:00:30 +01:00
Joe Rogers
e762454787 Restore resolver that handles alternate videos
Co-authored-by: Cody Robibero <cody@robibe.ro>
2022-01-16 22:59:14 +01:00
cvium
90736ee346 Add pagination and fixes 2022-01-16 22:10:22 +01:00
Dmitry Lyzo
000b7ba62b Fix maximum video resolution for dynamic HLS controller 2022-01-16 21:42:04 +03:00
Joe Rogers
f87e780fb5 Address review comments
Co-authored-by: Bond-009 <bond.009@outlook.com>
2022-01-16 13:21:24 +01:00
Dmitry Lyzo
60fe77c089 Remove unnecessary array allocation
Co-authored-by: Claus Vium <cvium@users.noreply.github.com>
2022-01-16 13:34:52 +03:00
Suphanath Kaewboonrung
7500c2b28b Translated using Weblate (Thai)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/th/
2022-01-16 03:13:12 -05:00
Claus Vium
1d7ec1071f Merge pull request #7186 from 1337joe/extra-rule-reorder
Order extra rules so directory takes precedence over naming
2022-01-15 20:24:14 +01:00
Joe Rogers
19b9646d72 Add -extra suffix for consistency 2022-01-15 15:43:06 +01:00
Joe Rogers
f11fa59b15 Order rules so directory takes precedence over naming 2022-01-15 15:16:11 +01:00
Cody Robibero
d88e39b71d Merge pull request #7185 from dmitrylyzo/warn-sa1642
Fix SA1642 warning
2022-01-15 06:32:07 -07:00
Dmitry Lyzo
54549cd5b5 Remove unnecessary array allocation
Co-authored-by: Claus Vium <cvium@users.noreply.github.com>
2022-01-15 15:54:14 +03:00
Dmitry Lyzo
ea1f3fe6bd Fix SA1642 warning 2022-01-15 15:33:54 +03:00
Cody Robibero
ee32e46dde Merge pull request #7172 from SenorSmartyPants/SeasonName 2022-01-14 13:15:53 -07:00
Dmitry Lyzo
5aa748058e Fix duplication of local trailers 2022-01-14 23:06:45 +03:00
Dmitry Lyzo
112db30ff2 Fix duplication of remote trailers 2022-01-14 22:53:54 +03:00
Bond-009
3b486fc0ee Merge pull request #7175 from dmitrylyzo/fix-self-locking 2022-01-14 20:41:59 +01:00
Dmitry Lyzo
f28384ba30 Ignore JSON serialization for special features of movie.
When refreshing the metadata of the video with a local trailer, the server gets
stuck trying to read the database and save the item at the same time.
2022-01-14 22:15:14 +03:00
Cody Robibero
ee46754238 Fix build and clean up 2022-01-14 08:14:31 -07:00
Fernando Fernández
5df6058a8e Add FullNowPlayingQueue property 2022-01-14 14:40:27 +00:00
Matthew Jones
61d8d40a4a Added type options to disable embedded subs 2022-01-14 11:25:08 +00:00
Matt
126274c4ea Add video path to DisableEmbeddedSubtitles log
Co-authored-by: Cody Robibero <cody@robibe.ro>
2022-01-14 11:25:08 +00:00
Matthew Jones
3f7bd7b63e Changed DisableEmbeddedSubtitles logging to debug 2022-01-14 11:25:08 +00:00
Matthew Jones
aeed255bbf Update CONTRIBUTORS.md 2022-01-14 11:25:08 +00:00
Matthew Jones
4df7590e52 Add DisableEmbeddedSubtitles setting
Disables embedded subs being added to metadata
2022-01-14 11:25:08 +00:00
Claus Vium
70751722d2 Apply suggestions from code review
Co-authored-by: Cody Robibero <cody@robibe.ro>
2022-01-14 08:24:15 +01:00
SenorSmartyPants
c32db3ea26 Fix build error 2022-01-13 22:51:38 -06:00
SenorSmartyPants
a19b6a7f61 Config option to import season name from TMDB 2022-01-13 22:31:37 -06:00
Joe Rogers
62dc4a79ff Fix comment typo
Co-authored-by: Claus Vium <cvium@users.noreply.github.com>
2022-01-13 23:21:02 +01:00
Dzonkins
07e9568de8 Translated using Weblate (Serbian)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/sr/
2022-01-12 16:13:11 -05:00
cvium
7ba9a24736 Fix bool 2022-01-12 20:10:35 +01:00
cvium
b9d4cbf3e8 Fix progress 2022-01-12 18:35:55 +01:00
Claus Vium
768b76b999 Apply suggestions from code review
Co-authored-by: Cody Robibero <cody@robibe.ro>
2022-01-12 17:27:02 +01:00
Cody Robibero
a0f248e200 Merge pull request #7134 from adavier/trakt-episode-links 2022-01-11 16:11:25 -07:00
cvium
f92806c246 Use local var for the length 2022-01-11 23:32:39 +01:00
cvium
9a5a079f42 Add progress report 2022-01-11 23:31:55 +01:00
cvium
6ffa9539bb Refactor and add scheduled task 2022-01-11 23:30:30 +01:00
Cody Robibero
307679afef Merge pull request #7131 from Bond-009/warn58 2022-01-10 17:05:20 -07:00
Cody Robibero
8a36fe7ed5 Use png for storage 2022-01-10 17:01:17 -07:00
Cody Robibero
0d335082c8 suggestions from review 2022-01-10 10:59:32 -07:00
Cody Robibero
6520ad03f0 Fix release build 2022-01-10 08:30:55 -07:00
Cody Robibero
ecb73168b3 Suggestions from review 2022-01-10 08:26:30 -07:00
Bond-009
4823e68a94 Merge pull request #7151 from jellyfin/dependabot/nuget/FsCheck.Xunit-2.16.4 2022-01-10 14:19:16 +01:00
dependabot[bot]
88e02c5290 Bump FsCheck.Xunit from 2.16.3 to 2.16.4
Bumps [FsCheck.Xunit](https://github.com/fsharp/FsCheck) from 2.16.3 to 2.16.4.
- [Release notes](https://github.com/fsharp/FsCheck/releases)
- [Changelog](https://github.com/fscheck/FsCheck/blob/master/FsCheck%20Release%20Notes.md)
- [Commits](https://github.com/fsharp/FsCheck/compare/2.16.3...2.16.4)

---
updated-dependencies:
- dependency-name: FsCheck.Xunit
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-01-10 12:01:16 +00:00
Bond_009
05836c8cd3 Fix warning SA1414 and CA1849 2022-01-10 10:57:32 +01:00
Cody Robibero
d24683f0ab Merge pull request #7141 from nyanmisaka/seek-audio
Seek the external audio stream
2022-01-09 06:57:01 -07:00
nyanmisaka
8c3f98f41b Also seek the external audio stream 2022-01-09 13:49:40 +08:00
SenorSmartyPants
d5e7e75421 Remove unused httpContext parameter 2022-01-08 19:53:53 -06:00
Cody Robibero
54d24ddeaf Merge pull request #6866 from Bond-009/timeout 2022-01-08 10:53:58 -07:00
Cody Robibero
188f9632f8 Merge pull request #7138 from nyanmisaka/10bit-boxes 2022-01-08 08:55:52 -07:00
nyanmisaka
ddc2569258 Fix the wrong logic in HEVC VP9 10bit hwdec boxes 2022-01-08 22:31:45 +08:00
Joe Rogers
b43f46d5c9 Make identify flag describe purpose, not source 2022-01-08 14:03:59 +01:00
Cody Robibero
620a5d5e83 Merge pull request #7136 from 1337joe/fix-show-library-scan
Fix stuck show library scans
2022-01-08 04:46:19 -07:00
Cody Robibero
9b1965b48a Merge pull request #7101 from Bond-009/imagejpg
Remove incorrect mime type image/jpg
2022-01-08 04:45:58 -07:00
SenorSmartyPants
3ea54a8009 Remove isHeadRequest from GetStaticFile method signatures 2022-01-07 18:21:48 -06:00
SenorSmartyPants
bd2bec4d4a Remove special HTTP HEAD processing
removing this allows HTTP 206 Partial Content responses and lets some clients(popcorn hour namely) play videos from JF.
2022-01-07 16:29:22 -06:00
Joe Rogers
a26509a98a Keep from serializing trailers into database 2022-01-07 22:33:31 +01:00
Aragon
ce61dff4aa Translated using Weblate (Hebrew)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/he/
2022-01-07 15:13:09 -05:00
adavier
9574d13059 Implement trakt episode links using the implementation from Series.cs
The code is the same as `MediaBrowser.Controller/Entities/TV/Series.cs`, using the imdbID to generate Trakt links.
The trakt url for episodes is `https://trakt.tv/episodes/{0}`.
2022-01-07 19:47:36 +00:00
Anthony Lavado
565ebbb643 Merge pull request #7132 from Bond-009/readme
Update README.md
2022-01-07 09:11:15 -05:00
Bond_009
4234a657c8 Update README.md 2022-01-07 15:06:49 +01:00
Bond_009
3ab0afdc6b Remove task cancellation hacks 2022-01-07 11:24:36 +01:00
Bond-009
98962cc21f Merge pull request #7129 from crobibero/null-check 2022-01-07 10:31:19 +01:00
cvium
c658a883a2 Merge branch 'master' into keyframe_extraction_v1
# Conflicts:
#	Jellyfin.Api/Controllers/DynamicHlsController.cs
#	MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs
#	MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
2022-01-07 10:23:22 +01:00
Cody Robibero
82260e22a2 ADd more null check 2022-01-06 21:49:13 -07:00
Cody Robibero
6b4f5a8663 Merge pull request #7118 from crobibero/audio-stream-null 2022-01-06 10:36:10 -07:00
Shin Khant Maung
f8a6b3b27b Translated using Weblate (Burmese)
Translation: Jellyfin/Jellyfin
Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/my/
2022-01-06 10:18:40 -05:00
Cody Robibero
904efeaddc Add null check for audio stream 2022-01-06 08:15:37 -07:00
Cody Robibero
b6b7a89bf2 Merge pull request #7121 from Bond-009/warn57 2022-01-05 16:18:08 -07:00
Bond_009
77c615ba42 Error on SA1316 2022-01-05 10:58:57 +01:00
Joshua M. Boniface
a2b51d551f Merge pull request #7115 from joshuaboniface/i-hate-ci-in-code 2022-01-04 20:02:17 -05:00
Joshua M. Boniface
e300b98573 Remove bump-version junk
This didn't work, and won't matter for beta1 so just scrap it.
2022-01-04 19:58:20 -05:00
Cody Robibero
360fd70fc7 Clean up 2022-01-04 08:44:03 -07:00
Joe Rogers
b17fe35e2e Clean up list handling
Co-authored-by: Cody Robibero <cody@robibe.ro>
2022-01-04 16:25:36 +01:00
David Ullmer
9e0958d822 Apply suggestions from code review 2022-01-04 08:20:16 -07:00
David Ullmer
9e23af5636 Add missing xml doc 2022-01-04 08:20:16 -07:00
David Ullmer
6ad020acb2 Include Splashscreen url in the branding endpoint 2022-01-04 08:20:16 -07:00
David Ullmer
c70452b4a4 Add missing response code documentation 2022-01-04 08:20:16 -07:00
David Ullmer
045ef4b726 Generate Splashscreen during RefreshMediaLibrary scheduled task 2022-01-04 08:20:16 -07:00
David Ullmer
68db3be0e7 Remove darkening filter from Splashscreen
Using the foregroundLayer parameter has the same effect
2022-01-04 08:20:16 -07:00
David Ullmer
e026ba84c5 Add Splashscreen API endpoint to ImageController 2022-01-04 08:20:16 -07:00
David Ullmer
3fb3ee074a Remove splashscreen generation from IImageEncoder and add IImageGenerator 2022-01-04 08:20:16 -07:00
David Ullmer
0fd4ff4451 Always use 1080p, add max parental rating 2022-01-04 08:20:16 -07:00
David Ullmer
c934269a6e Add api controller for splashscreen 2022-01-04 08:20:16 -07:00
David Ullmer
4ba168c8a1 Add splashscreen builder 2022-01-04 08:20:16 -07:00
Bond_009
dc222b75c5 Remove incorrect mime type image/jpg 2022-01-04 10:40:16 +01:00
Joe Rogers
1dfbeae045 Embed ProviderUtils into MetadataService 2022-01-04 00:44:03 +01:00
Joe Rogers
19164378f2 Clean up warnings 2022-01-04 00:21:45 +01:00
Joe Rogers
c81d2e9dec Remove existing images when applying identify 2022-01-03 23:41:13 +01:00
Joe Rogers
ce66df2c92 Clean up warnings, simplify 2022-01-03 22:59:58 +01:00
Joe Rogers
29755c9384 Merge a couple tests, extract duplicate code 2022-01-02 22:24:04 +01:00
Joe Rogers
608a91162a Add test for #6830 2022-01-02 22:23:47 +01:00
Joe Rogers
853ef727da Add refresh flag to remove existing data/images
Fixes #7040
2022-01-02 22:21:05 +01:00
Joe Rogers
76e640b0b9 Add tests and documentation for ProviderUtils 2021-12-31 00:10:35 +01:00
Joe Rogers
e3a7c9238d Pull default MergeData implementation to parent 2021-12-28 15:12:09 +01:00
Cody Robibero
cecfdeeec3 Merge branch 'master' into unharden-for-lxc 2021-12-24 02:01:06 +00:00
Joshua M. Boniface
fcf5b9b46e Unify and standardize unit files between deb/rpm
Ensures that the RPM service unit has all the tweaks from the Deb
service unit, and some in the other direction too.
2021-12-12 17:01:35 -05:00
Joshua M. Boniface
9a2b88cb1f Revert some hardening that breaks LXC
For each of these, we should be OK since we run as an unprivileged user
anyways.
2021-12-12 16:57:35 -05:00
cvium
2899b77cd5 Implement FfProbeKeyframeExtractor and add tests for it 2021-09-26 21:07:30 +02:00
cvium
41383e6fe4 Review comment 2021-09-25 23:37:41 +02:00
cvium
64a13a5d42 Add ComputeSegments test 2021-09-25 23:28:10 +02:00
cvium
43ea4af30f Update to .net 6 2021-09-25 20:55:48 +02:00
cvium
30f3be1da0 Merge branch 'master' into keyframe_extraction_v1 2021-09-25 20:52:09 +02:00
cvium
3e5cb8e04e Add tests for ComputeEqualLengthSegments and fix bug 2021-09-25 11:47:44 +02:00
cvium
c7b25a9fe4 Add first test 2021-09-25 11:17:16 +02:00
cvium
fa38b741ce Restructure the code to make it more testable 2021-09-25 10:54:54 +02:00
cvium
be233b49b6 Fixes 2021-09-25 10:41:36 +02:00
cvium
35c0801d6c More fixes 2021-09-23 18:59:34 +02:00
cvium
ee8bd9b3b5 Fix xmldoc issues 2021-09-23 18:49:48 +02:00
cvium
30230aff73 Fix build? 2021-09-23 17:00:39 +02:00
cvium
d995f0e092 Add dto changes 2021-09-23 15:51:46 +02:00
cvium
6e77d50563 Remove path hinting 2021-09-23 15:39:49 +02:00
cvium
3531dc85ae Fix build 2021-09-23 15:37:33 +02:00
cvium
9c15f96e12 Add first draft of keyframe extraction for Matroska 2021-09-23 15:29:12 +02:00
oledfish
86a5e72a65 Add "Production" and "TV" episode orders. 2021-09-07 16:38:18 -03:00
480 changed files with 35049 additions and 5252 deletions

View File

@@ -43,10 +43,6 @@ jobs:
displayName: Set release version (stable)
condition: startsWith(variables['Build.SourceBranch'], 'refs/tags/v')
- script: './bump-version $(JellyfinVersion)'
displayName: Bump internal version (stable)
condition: startsWith(variables['Build.SourceBranch'], 'refs/tags/v')
- script: 'docker build -f deployment/Dockerfile.$(BuildConfiguration) -t jellyfin-server-$(BuildConfiguration) deployment'
displayName: 'Build Dockerfile'
@@ -92,10 +88,6 @@ jobs:
displayName: Set release version (stable)
condition: startsWith(variables['Build.SourceBranch'], 'refs/tags/v')
- script: './bump-version $(JellyfinVersion)'
displayName: Bump internal version (stable)
condition: startsWith(variables['Build.SourceBranch'], 'refs/tags/v')
- task: DownloadPipelineArtifact@2
displayName: 'Download OpenAPI Spec'
inputs:
@@ -143,10 +135,6 @@ jobs:
displayName: Set release version (stable)
condition: startsWith(variables['Build.SourceBranch'], 'refs/tags/v')
- script: './bump-version $(JellyfinVersion)'
displayName: Bump internal version (stable)
condition: startsWith(variables['Build.SourceBranch'], 'refs/tags/v')
- task: Docker@2
displayName: 'Push Unstable Image'
condition: startsWith(variables['Build.SourceBranch'], 'refs/heads/master')

29
.github/stale.yml vendored
View File

@@ -1,29 +0,0 @@
# Number of days of inactivity before an issue becomes stale
daysUntilStale: 120
# Number of days of inactivity before a stale issue is closed
daysUntilClose: 21
# Issues with these labels will never be considered stale
exemptLabels:
- regression
- security
- dotnet-3.0-future
- roadmap
- future
- feature
- enhancement
- confirmed
# Label to use when marking an issue as stale
staleLabel: stale
# Comment to post when marking an issue as stale. Set to `false` to disable
markComment: >
This issue has gone 120 days without comment. To avoid abandoned issues, it will be closed in 21 days if there are no new comments.
If you're the original submitter of this issue, please comment confirming if this issue still affects you in the latest release or nightlies, or close the issue if it has been fixed. If you're another user also affected by this bug, please comment confirming so. Either action will remove the stale label.
This bot exists to prevent issues from becoming stale and forgotten. Jellyfin is always moving forward, and bugs are often fixed as side effects of other changes. We therefore ask that bug report authors remain vigilant about their issues to ensure they are closed if fixed, or re-confirmed - perhaps with fresh logs or reproduction examples - regularly. If you have any questions you can reach us on [Matrix or Social Media](https://docs.jellyfin.org/general/getting-help.html).
# Comment to post when closing a stale issue. Set to `false` to disable
closeComment: false
# Disable automatic closing of pull requests
pulls:
daysUntilClose: false

View File

@@ -20,9 +20,9 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v2
uses: actions/checkout@v3
- name: Setup .NET Core
uses: actions/setup-dotnet@v1
uses: actions/setup-dotnet@v2
with:
dotnet-version: '6.0.x'

View File

@@ -23,7 +23,7 @@ jobs:
reactions: '+1'
- name: Checkout the latest code
uses: actions/checkout@v2
uses: actions/checkout@v3
with:
token: ${{ secrets.JF_BOT_TOKEN }}
fetch-depth: 0
@@ -47,7 +47,7 @@ jobs:
reactions: eyes
- name: Checkout the latest code
uses: actions/checkout@v2
uses: actions/checkout@v3
with:
token: ${{ secrets.JF_BOT_TOKEN }}
fetch-depth: 0

View File

@@ -12,12 +12,12 @@ jobs:
permissions: read-all
steps:
- name: Checkout repository
uses: actions/checkout@v2
uses: actions/checkout@v3
with:
ref: ${{ github.event.pull_request.head.ref }}
ref: ${{ github.event.pull_request.head.sha }}
repository: ${{ github.event.pull_request.head.repo.full_name }}
- name: Setup .NET Core
uses: actions/setup-dotnet@v1
uses: actions/setup-dotnet@v2
with:
dotnet-version: '6.0.x'
- name: Generate openapi.json
@@ -37,11 +37,11 @@ jobs:
permissions: read-all
steps:
- name: Checkout repository
uses: actions/checkout@v2
uses: actions/checkout@v3
with:
ref: ${{ github.base_ref }}
- name: Setup .NET Core
uses: actions/setup-dotnet@v1
uses: actions/setup-dotnet@v2
with:
dotnet-version: '6.0.x'
- name: Generate openapi.json

27
.github/workflows/repo-stale.yaml vendored Normal file
View File

@@ -0,0 +1,27 @@
name: Issue Stale Check
on:
schedule:
- cron: '30 1 * * *'
workflow_dispatch:
jobs:
stale:
runs-on: ubuntu-latest
if: ${{ contains(github.repository, 'jellyfin/') }}
steps:
- uses: actions/stale@v5
with:
repo-token: ${{ secrets.JF_BOT_TOKEN }}
days-before-stale: 120
days-before-pr-stale: -1
days-before-close: 21
days-before-pr-close: -1
exempt-issue-labels: regression,security,roadmap,future,feature,enhancement,confirmed
stale-issue-label: stale
stale-issue-message: |-
This issue has gone 120 days without comment. To avoid abandoned issues, it will be closed in 21 days if there are no new comments.
If you're the original submitter of this issue, please comment confirming if this issue still affects you in the latest release or master branch, or close the issue if it has been fixed. If you're another user also affected by this bug, please comment confirming so. Either action will remove the stale label.
This bot exists to prevent issues from becoming stale and forgotten. Jellyfin is always moving forward, and bugs are often fixed as side effects of other changes. We therefore ask that bug report authors remain vigilant about their issues to ensure they are closed if fixed, or re-confirmed - perhaps with fresh logs or reproduction examples - regularly. If you have any questions you can reach us on [Matrix or Social Media](https://docs.jellyfin.org/general/getting-help.html).

4
BannedSymbols.txt Normal file
View File

@@ -0,0 +1,4 @@
P:System.Threading.Tasks.Task`1.Result
M:System.Guid.op_Equality(System.Guid,System.Guid)
M:System.Guid.op_Inequality(System.Guid,System.Guid)
M:System.Guid.Equals(System.Object)

View File

@@ -1,5 +1,6 @@
# Jellyfin Contributors
- [1337joe](https://github.com/1337joe)
- [97carmine](https://github.com/97carmine)
- [Abbe98](https://github.com/Abbe98)
- [agrenott](https://github.com/agrenott)
@@ -45,6 +46,7 @@
- [Froghut](https://github.com/Froghut)
- [fruhnow](https://github.com/fruhnow)
- [geilername](https://github.com/geilername)
- [GermanCoding](https://github.com/GermanCoding)
- [gnattu](https://github.com/gnattu)
- [GodTamIt](https://github.com/GodTamIt)
- [grafixeyehero](https://github.com/grafixeyehero)
@@ -76,6 +78,7 @@
- [mitchfizz05](https://github.com/mitchfizz05)
- [MrTimscampi](https://github.com/MrTimscampi)
- [n8225](https://github.com/n8225)
- [Nalsai](https://github.com/Nalsai)
- [Narfinger](https://github.com/Narfinger)
- [NathanPickard](https://github.com/NathanPickard)
- [neilsb](https://github.com/neilsb)
@@ -115,6 +118,7 @@
- [ssenart](https://github.com/ssenart)
- [stanionascu](https://github.com/stanionascu)
- [stevehayles](https://github.com/stevehayles)
- [StollD](https://github.com/StollD)
- [SuperSandro2000](https://github.com/SuperSandro2000)
- [tbraeutigam](https://github.com/tbraeutigam)
- [teacupx](https://github.com/teacupx)
@@ -151,6 +155,8 @@
- [peterspenler](https://github.com/peterspenler)
- [MBR-0001](https://github.com/MBR-0001)
- [jonas-resch](https://github.com/jonas-resch)
- [vgambier](https://github.com/vgambier)
- [MinecraftPlaye](https://github.com/MinecraftPlaye)
# Emby Contributors
@@ -217,3 +223,5 @@
- [olsh](https://github.com/olsh)
- [lbenini](https://github.com/lbenini)
- [gnuyent](https://github.com/gnuyent)
- [Matthew Jones](https://github.com/matthew-jones-uk)
- [Jakob Kukla](https://github.com/jakobkukla)

View File

@@ -14,4 +14,8 @@
<AnalysisMode>AllEnabledByDefault</AnalysisMode>
</PropertyGroup>
<ItemGroup>
<AdditionalFiles Include="$(SolutionDir)/BannedSymbols.txt" />
</ItemGroup>
</Project>

View File

@@ -22,10 +22,10 @@ ARG APT_KEY_DONT_WARN_ON_DANGEROUS_USAGE=DontWarn
ENV NVIDIA_DRIVER_CAPABILITIES="compute,video,utility"
# https://github.com/intel/compute-runtime/releases
ARG GMMLIB_VERSION=21.2.1
ARG IGC_VERSION=1.0.8517
ARG NEO_VERSION=21.35.20826
ARG LEVEL_ZERO_VERSION=1.2.20826
ARG GMMLIB_VERSION=22.0.2
ARG IGC_VERSION=1.0.10395
ARG NEO_VERSION=22.08.22549
ARG LEVEL_ZERO_VERSION=1.3.22549
# Install dependencies:
# mesa-va-drivers: needed for AMD VAAPI. Mesa >= 20.1 is required for HEVC transcoding.
@@ -48,8 +48,7 @@ RUN apt-get update \
&& wget https://github.com/intel/compute-runtime/releases/download/${NEO_VERSION}/intel-gmmlib_${GMMLIB_VERSION}_amd64.deb \
&& wget https://github.com/intel/intel-graphics-compiler/releases/download/igc-${IGC_VERSION}/intel-igc-core_${IGC_VERSION}_amd64.deb \
&& wget https://github.com/intel/intel-graphics-compiler/releases/download/igc-${IGC_VERSION}/intel-igc-opencl_${IGC_VERSION}_amd64.deb \
&& wget https://github.com/intel/compute-runtime/releases/download/${NEO_VERSION}/intel-opencl_${NEO_VERSION}_amd64.deb \
&& wget https://github.com/intel/compute-runtime/releases/download/${NEO_VERSION}/intel-ocloc_${NEO_VERSION}_amd64.deb \
&& wget https://github.com/intel/compute-runtime/releases/download/${NEO_VERSION}/intel-opencl-icd_${NEO_VERSION}_amd64.deb \
&& wget https://github.com/intel/compute-runtime/releases/download/${NEO_VERSION}/intel-level-zero-gpu_${LEVEL_ZERO_VERSION}_amd64.deb \
&& dpkg -i *.deb \
&& cd .. \
@@ -83,7 +82,7 @@ COPY --from=builder /jellyfin /jellyfin
COPY --from=web-builder /dist /jellyfin/jellyfin-web
EXPOSE 8096
VOLUME /cache /config /media
VOLUME /cache /config
ENTRYPOINT ["./jellyfin/jellyfin", \
"--datadir", "/config", \
"--cachedir", "/cache", \

View File

@@ -74,7 +74,7 @@ COPY --from=builder /jellyfin /jellyfin
COPY --from=web-builder /dist /jellyfin/jellyfin-web
EXPOSE 8096
VOLUME /cache /config /media
VOLUME /cache /config
ENTRYPOINT ["./jellyfin/jellyfin", \
"--datadir", "/config", \
"--cachedir", "/cache", \

View File

@@ -65,7 +65,7 @@ COPY --from=builder /jellyfin /jellyfin
COPY --from=web-builder /dist /jellyfin/jellyfin-web
EXPOSE 8096
VOLUME /cache /config /media
VOLUME /cache /config
ENTRYPOINT ["./jellyfin/jellyfin", \
"--datadir", "/config", \
"--cachedir", "/cache", \

View File

@@ -619,7 +619,7 @@ namespace Emby.Dlna.ContentDirectory
var queryResult = folder.GetItems(query);
return ToResult(queryResult);
return ToResult(startIndex, queryResult);
}
/// <summary>
@@ -642,7 +642,7 @@ namespace Emby.Dlna.ContentDirectory
var result = _libraryManager.GetItemsResult(query);
return ToResult(result);
return ToResult(startIndex, result);
}
/// <summary>
@@ -707,11 +707,10 @@ namespace Emby.Dlna.ContentDirectory
serverItems = serverItems[..limit.Value];
}
return new QueryResult<ServerItem>
{
Items = serverItems,
TotalRecordCount = serverItems.Length
};
return new QueryResult<ServerItem>(
startIndex,
serverItems.Length,
serverItems);
}
/// <summary>
@@ -764,11 +763,10 @@ namespace Emby.Dlna.ContentDirectory
array = array[..limit.Value];
}
return new QueryResult<ServerItem>
{
Items = array,
TotalRecordCount = array.Length
};
return new QueryResult<ServerItem>(
startIndex,
array.Length,
array);
}
/// <summary>
@@ -790,11 +788,10 @@ namespace Emby.Dlna.ContentDirectory
.Select(i => new ServerItem(i, StubType.Folder))
.ToArray();
return new QueryResult<ServerItem>
{
Items = items,
TotalRecordCount = totalRecordCount
};
return new QueryResult<ServerItem>(
startIndex,
totalRecordCount,
items);
}
/// <summary>
@@ -850,11 +847,10 @@ namespace Emby.Dlna.ContentDirectory
serverItems = serverItems[..limit.Value];
}
return new QueryResult<ServerItem>
{
Items = serverItems,
TotalRecordCount = serverItems.Length
};
return new QueryResult<ServerItem>(
startIndex,
serverItems.Length,
serverItems);
}
/// <summary>
@@ -879,7 +875,7 @@ namespace Emby.Dlna.ContentDirectory
var result = _libraryManager.GetItemsResult(query);
return ToResult(result);
return ToResult(query.StartIndex, result);
}
/// <summary>
@@ -894,7 +890,7 @@ namespace Emby.Dlna.ContentDirectory
var result = _libraryManager.GetItemsResult(query);
return ToResult(result);
return ToResult(query.StartIndex, result);
}
/// <summary>
@@ -914,7 +910,7 @@ namespace Emby.Dlna.ContentDirectory
var result = _libraryManager.GetItemsResult(query);
return ToResult(result);
return ToResult(query.StartIndex, result);
}
/// <summary>
@@ -931,7 +927,7 @@ namespace Emby.Dlna.ContentDirectory
query.AncestorIds = new[] { parent.Id };
var genresResult = _libraryManager.GetGenres(query);
return ToResult(genresResult);
return ToResult(query.StartIndex, genresResult);
}
/// <summary>
@@ -947,7 +943,7 @@ namespace Emby.Dlna.ContentDirectory
query.AncestorIds = new[] { parent.Id };
var genresResult = _libraryManager.GetMusicGenres(query);
return ToResult(genresResult);
return ToResult(query.StartIndex, genresResult);
}
/// <summary>
@@ -963,7 +959,7 @@ namespace Emby.Dlna.ContentDirectory
query.AncestorIds = new[] { parent.Id };
var artists = _libraryManager.GetAlbumArtists(query);
return ToResult(artists);
return ToResult(query.StartIndex, artists);
}
/// <summary>
@@ -978,7 +974,7 @@ namespace Emby.Dlna.ContentDirectory
query.OrderBy = Array.Empty<(string, SortOrder)>();
query.AncestorIds = new[] { parent.Id };
var artists = _libraryManager.GetArtists(query);
return ToResult(artists);
return ToResult(query.StartIndex, artists);
}
/// <summary>
@@ -994,7 +990,7 @@ namespace Emby.Dlna.ContentDirectory
query.AncestorIds = new[] { parent.Id };
query.IsFavorite = true;
var artists = _libraryManager.GetArtists(query);
return ToResult(artists);
return ToResult(query.StartIndex, artists);
}
/// <summary>
@@ -1010,7 +1006,7 @@ namespace Emby.Dlna.ContentDirectory
var result = _libraryManager.GetItemsResult(query);
return ToResult(result);
return ToResult(query.StartIndex, result);
}
/// <summary>
@@ -1034,7 +1030,7 @@ namespace Emby.Dlna.ContentDirectory
new[] { parent },
query.DtoOptions);
return ToResult(result);
return ToResult(query.StartIndex, result);
}
/// <summary>
@@ -1060,7 +1056,7 @@ namespace Emby.Dlna.ContentDirectory
},
query.DtoOptions).Select(i => i.Item1 ?? i.Item2.FirstOrDefault()).Where(i => i != null).ToArray();
return ToResult(items);
return ToResult(query.StartIndex, items);
}
/// <summary>
@@ -1087,7 +1083,7 @@ namespace Emby.Dlna.ContentDirectory
var result = _libraryManager.GetItemsResult(query);
return ToResult(result);
return ToResult(startIndex, result);
}
/// <summary>
@@ -1118,7 +1114,7 @@ namespace Emby.Dlna.ContentDirectory
var result = _libraryManager.GetItemsResult(query);
return ToResult(result);
return ToResult(startIndex, result);
}
/// <summary>
@@ -1145,33 +1141,34 @@ namespace Emby.Dlna.ContentDirectory
var result = _libraryManager.GetItemsResult(query);
return ToResult(result);
return ToResult(startIndex, result);
}
/// <summary>
/// Converts <see cref="IReadOnlyCollection{BaseItem}"/> into a <see cref="QueryResult{ServerItem}"/>.
/// </summary>
/// <param name="startIndex">The start index.</param>
/// <param name="result">An array of <see cref="BaseItem"/>.</param>
/// <returns>A <see cref="QueryResult{ServerItem}"/>.</returns>
private static QueryResult<ServerItem> ToResult(IReadOnlyCollection<BaseItem> result)
private static QueryResult<ServerItem> ToResult(int? startIndex, IReadOnlyCollection<BaseItem> result)
{
var serverItems = result
.Select(i => new ServerItem(i, null))
.ToArray();
return new QueryResult<ServerItem>
{
TotalRecordCount = result.Count,
Items = serverItems
};
return new QueryResult<ServerItem>(
startIndex,
result.Count,
serverItems);
}
/// <summary>
/// Converts a <see cref="QueryResult{BaseItem}"/> to a <see cref="QueryResult{ServerItem}"/>.
/// </summary>
/// <param name="startIndex">The index the result started at.</param>
/// <param name="result">A <see cref="QueryResult{BaseItem}"/>.</param>
/// <returns>The <see cref="QueryResult{ServerItem}"/>.</returns>
private static QueryResult<ServerItem> ToResult(QueryResult<BaseItem> result)
private static QueryResult<ServerItem> ToResult(int? startIndex, QueryResult<BaseItem> result)
{
var length = result.Items.Count;
var serverItems = new ServerItem[length];
@@ -1180,32 +1177,31 @@ namespace Emby.Dlna.ContentDirectory
serverItems[i] = new ServerItem(result.Items[i], null);
}
return new QueryResult<ServerItem>
{
TotalRecordCount = result.TotalRecordCount,
Items = serverItems
};
return new QueryResult<ServerItem>(
startIndex,
result.TotalRecordCount,
serverItems);
}
/// <summary>
/// Converts a query result to a <see cref="QueryResult{ServerItem}"/>.
/// </summary>
/// <param name="startIndex">The start index.</param>
/// <param name="result">A <see cref="QueryResult{BaseItem}"/>.</param>
/// <returns>The <see cref="QueryResult{ServerItem}"/>.</returns>
private static QueryResult<ServerItem> ToResult(QueryResult<(BaseItem, ItemCounts)> result)
private static QueryResult<ServerItem> ToResult(int? startIndex, QueryResult<(BaseItem Item, ItemCounts ItemCounts)> result)
{
var length = result.Items.Count;
var serverItems = new ServerItem[length];
for (var i = 0; i < length; i++)
{
serverItems[i] = new ServerItem(result.Items[i].Item1, null);
serverItems[i] = new ServerItem(result.Items[i].Item, null);
}
return new QueryResult<ServerItem>
{
TotalRecordCount = result.TotalRecordCount,
Items = serverItems
};
return new QueryResult<ServerItem>(
startIndex,
result.TotalRecordCount,
serverItems);
}
/// <summary>
@@ -1213,7 +1209,7 @@ namespace Emby.Dlna.ContentDirectory
/// </summary>
/// <param name="sort">The <see cref="SortCriteria"/>.</param>
/// <param name="isPreSorted">True if pre-sorted.</param>
private static (string, SortOrder)[] GetOrderBy(SortCriteria sort, bool isPreSorted)
private static (string SortName, SortOrder SortOrder)[] GetOrderBy(SortCriteria sort, bool isPreSorted)
{
return isPreSorted ? Array.Empty<(string, SortOrder)>() : new[] { (ItemSortBy.SortName, sort.SortOrder) };
}

View File

@@ -160,7 +160,7 @@ namespace Emby.Dlna.Didl
else
{
var parent = item.DisplayParentId;
if (!parent.Equals(Guid.Empty))
if (!parent.Equals(default))
{
writer.WriteAttributeString("parentID", GetClientId(parent, null));
}
@@ -657,7 +657,7 @@ namespace Emby.Dlna.Didl
else
{
var parent = folder.DisplayParentId;
if (parent.Equals(Guid.Empty))
if (parent.Equals(default))
{
writer.WriteAttributeString("parentID", "0");
}
@@ -989,7 +989,7 @@ namespace Emby.Dlna.Didl
writer.WriteAttributeString("dlna", "profileID", NsDlna, _profile.AlbumArtPn);
}
writer.WriteString(albumArtUrlInfo.url);
writer.WriteString(albumArtUrlInfo.Url);
writer.WriteFullEndElement();
// TODO: Remove these default values
@@ -998,7 +998,7 @@ namespace Emby.Dlna.Didl
_profile.MaxIconWidth ?? 48,
_profile.MaxIconHeight ?? 48,
"jpg");
writer.WriteElementString("upnp", "icon", NsUpnp, iconUrlInfo.url);
writer.WriteElementString("upnp", "icon", NsUpnp, iconUrlInfo.Url);
if (!_profile.EnableAlbumArtInDidl)
{
@@ -1045,8 +1045,8 @@ namespace Emby.Dlna.Didl
// Images must have a reported size or many clients (Bubble upnp), will only use the first thumbnail
// rather than using a larger one when available
var width = albumartUrlInfo.width ?? maxWidth;
var height = albumartUrlInfo.height ?? maxHeight;
var width = albumartUrlInfo.Width ?? maxWidth;
var height = albumartUrlInfo.Height ?? maxHeight;
var contentFeatures = ContentFeatureBuilder.BuildImageHeader(_profile, format, width, height, imageInfo.IsDirectStream, org_Pn);
@@ -1062,7 +1062,7 @@ namespace Emby.Dlna.Didl
"resolution",
string.Format(CultureInfo.InvariantCulture, "{0}x{1}", width, height));
writer.WriteString(albumartUrlInfo.url);
writer.WriteString(albumartUrlInfo.Url);
writer.WriteFullEndElement();
}
@@ -1200,7 +1200,7 @@ namespace Emby.Dlna.Didl
return id;
}
private (string url, int? width, int? height) GetImageUrl(ImageDownloadInfo info, int maxWidth, int maxHeight, string format)
private (string Url, int? Width, int? Height) GetImageUrl(ImageDownloadInfo info, int maxWidth, int maxHeight, string format)
{
var url = string.Format(
CultureInfo.InvariantCulture,

View File

@@ -343,7 +343,8 @@ namespace Emby.Dlna
var fileOptions = AsyncFile.WriteOptions;
fileOptions.Mode = FileMode.Create;
fileOptions.PreallocationSize = length;
using (var fileStream = new FileStream(path, fileOptions))
var fileStream = new FileStream(path, fileOptions);
await using (fileStream.ConfigureAwait(false))
{
await stream.CopyToAsync(fileStream).ConfigureAwait(false);
}
@@ -455,7 +456,7 @@ namespace Emby.Dlna
/// <inheritdoc />
public string GetServerDescriptionXml(IHeaderDictionary headers, string serverUuId, string serverAddress)
{
var profile = GetDefaultProfile();
var profile = GetProfile(headers) ?? GetDefaultProfile();
var serverId = _appHost.SystemId;

View File

@@ -28,8 +28,12 @@
<!-- Code Analyzers-->
<ItemGroup Condition=" '$(Configuration)' == 'Debug' ">
<PackageReference Include="Microsoft.CodeAnalysis.BannedApiAnalyzers" Version="3.3.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
<PackageReference Include="SerilogAnalyzer" Version="0.15.0" PrivateAssets="All" />
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.376" PrivateAssets="All" />
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.406" PrivateAssets="All" />
<PackageReference Include="SmartAnalyzers.MultithreadingAnalyzer" Version="1.1.31" PrivateAssets="All" />
</ItemGroup>

View File

@@ -362,7 +362,7 @@ namespace Emby.Dlna.Main
guid = text.GetMD5();
}
return guid.ToString("N", CultureInfo.InvariantCulture);
return guid.ToString("D", CultureInfo.InvariantCulture);
}
private void SetProperies(SsdpDevice device, string fullDeviceType)

View File

@@ -69,11 +69,11 @@ namespace Emby.Dlna.PlayTo
public TransportState TransportState { get; private set; }
public bool IsPlaying => TransportState == TransportState.Playing;
public bool IsPlaying => TransportState == TransportState.PLAYING;
public bool IsPaused => TransportState == TransportState.Paused || TransportState == TransportState.PausedPlayback;
public bool IsPaused => TransportState == TransportState.PAUSED_PLAYBACK;
public bool IsStopped => TransportState == TransportState.Stopped;
public bool IsStopped => TransportState == TransportState.STOPPED;
public Action OnDeviceUnavailable { get; set; }
@@ -494,7 +494,7 @@ namespace Emby.Dlna.PlayTo
cancellationToken: cancellationToken)
.ConfigureAwait(false);
TransportState = TransportState.Paused;
TransportState = TransportState.PAUSED_PLAYBACK;
RestartTimer(true);
}
@@ -527,7 +527,7 @@ namespace Emby.Dlna.PlayTo
if (transportState.HasValue)
{
// If we're not playing anything no need to get additional data
if (transportState.Value == TransportState.Stopped)
if (transportState.Value == TransportState.STOPPED)
{
UpdateMediaInfo(null, transportState.Value);
}
@@ -535,9 +535,9 @@ namespace Emby.Dlna.PlayTo
{
var tuple = await GetPositionInfo(avCommands, cancellationToken).ConfigureAwait(false);
var currentObject = tuple.Item2;
var currentObject = tuple.Track;
if (tuple.Item1 && currentObject == null)
if (tuple.Success && currentObject == null)
{
currentObject = await GetMediaInfo(avCommands, cancellationToken).ConfigureAwait(false);
}
@@ -556,7 +556,7 @@ namespace Emby.Dlna.PlayTo
}
// If we're not playing anything make sure we don't get data more often than necessary to keep the Session alive
if (transportState.Value == TransportState.Stopped)
if (transportState.Value == TransportState.STOPPED)
{
RestartTimerInactive();
}
@@ -797,7 +797,7 @@ namespace Emby.Dlna.PlayTo
return null;
}
private async Task<(bool, UBaseObject)> GetPositionInfo(TransportCommands avCommands, CancellationToken cancellationToken)
private async Task<(bool Success, UBaseObject Track)> GetPositionInfo(TransportCommands avCommands, CancellationToken cancellationToken)
{
var command = avCommands.ServiceActions.FirstOrDefault(c => c.Name == "GetPositionInfo");
if (command == null)
@@ -1229,7 +1229,7 @@ namespace Emby.Dlna.PlayTo
}
else if (previousMediaInfo == null)
{
if (state != TransportState.Stopped)
if (state != TransportState.STOPPED)
{
OnPlaybackStart(mediaInfo);
}

View File

@@ -174,13 +174,13 @@ namespace Emby.Dlna.PlayTo
await _sessionManager.OnPlaybackStart(newItemProgress).ConfigureAwait(false);
// Send a message to the DLNA device to notify what is the next track in the playlist.
var currentItemIndex = _playlist.FindIndex(item => item.StreamInfo.ItemId == streamInfo.ItemId);
var currentItemIndex = _playlist.FindIndex(item => item.StreamInfo.ItemId.Equals(streamInfo.ItemId));
if (currentItemIndex >= 0)
{
_currentPlaylistIndex = currentItemIndex;
}
await SendNextTrackMessage(currentItemIndex, CancellationToken.None);
await SendNextTrackMessage(currentItemIndex, CancellationToken.None).ConfigureAwait(false);
}
catch (Exception ex)
{
@@ -349,7 +349,9 @@ namespace Emby.Dlna.PlayTo
{
_logger.LogDebug("{0} - Received PlayRequest: {1}", _session.DeviceName, command.PlayCommand);
var user = command.ControllingUserId.Equals(Guid.Empty) ? null : _userManager.GetUserById(command.ControllingUserId);
var user = command.ControllingUserId.Equals(default)
? null :
_userManager.GetUserById(command.ControllingUserId);
var items = new List<BaseItem>();
foreach (var id in command.ItemIds)
@@ -392,7 +394,7 @@ namespace Emby.Dlna.PlayTo
_playlist.AddRange(playlist);
}
if (!command.ControllingUserId.Equals(Guid.Empty))
if (!command.ControllingUserId.Equals(default))
{
_sessionManager.LogSessionActivity(
_session.Client,
@@ -446,14 +448,16 @@ namespace Emby.Dlna.PlayTo
if (info.Item != null && !EnableClientSideSeek(info))
{
var user = !_session.UserId.Equals(Guid.Empty) ? _userManager.GetUserById(_session.UserId) : null;
var user = _session.UserId.Equals(default)
? null
: _userManager.GetUserById(_session.UserId);
var newItem = CreatePlaylistItem(info.Item, user, newPosition, info.MediaSourceId, info.AudioStreamIndex, info.SubtitleStreamIndex);
await _device.SetAvTransport(newItem.StreamUrl, GetDlnaHeaders(newItem), newItem.Didl, CancellationToken.None).ConfigureAwait(false);
// Send a message to the DLNA device to notify what is the next track in the play list.
var newItemIndex = _playlist.FindIndex(item => item.StreamUrl == newItem.StreamUrl);
await SendNextTrackMessage(newItemIndex, CancellationToken.None);
await SendNextTrackMessage(newItemIndex, CancellationToken.None).ConfigureAwait(false);
return;
}
@@ -569,7 +573,7 @@ namespace Emby.Dlna.PlayTo
streamInfo.TargetVideoCodecTag,
streamInfo.IsTargetAVC);
return list.Count == 0 ? null : list[0];
return list.FirstOrDefault();
}
return null;
@@ -654,7 +658,7 @@ namespace Emby.Dlna.PlayTo
await _device.SetAvTransport(currentitem.StreamUrl, GetDlnaHeaders(currentitem), currentitem.Didl, cancellationToken).ConfigureAwait(false);
// Send a message to the DLNA device to notify what is the next track in the play list.
await SendNextTrackMessage(index, cancellationToken);
await SendNextTrackMessage(index, cancellationToken).ConfigureAwait(false);
var streamInfo = currentitem.StreamInfo;
if (streamInfo.StartPositionTicks > 0 && EnableClientSideSeek(streamInfo))
@@ -764,14 +768,16 @@ namespace Emby.Dlna.PlayTo
{
var newPosition = GetProgressPositionTicks(info) ?? 0;
var user = !_session.UserId.Equals(Guid.Empty) ? _userManager.GetUserById(_session.UserId) : null;
var user = _session.UserId.Equals(default)
? null
: _userManager.GetUserById(_session.UserId);
var newItem = CreatePlaylistItem(info.Item, user, newPosition, info.MediaSourceId, newIndex, info.SubtitleStreamIndex);
await _device.SetAvTransport(newItem.StreamUrl, GetDlnaHeaders(newItem), newItem.Didl, CancellationToken.None).ConfigureAwait(false);
// Send a message to the DLNA device to notify what is the next track in the play list.
var newItemIndex = _playlist.FindIndex(item => item.StreamUrl == newItem.StreamUrl);
await SendNextTrackMessage(newItemIndex, CancellationToken.None);
await SendNextTrackMessage(newItemIndex, CancellationToken.None).ConfigureAwait(false);
if (EnableClientSideSeek(newItem.StreamInfo))
{
@@ -793,14 +799,16 @@ namespace Emby.Dlna.PlayTo
{
var newPosition = GetProgressPositionTicks(info) ?? 0;
var user = !_session.UserId.Equals(Guid.Empty) ? _userManager.GetUserById(_session.UserId) : null;
var user = _session.UserId.Equals(default)
? null
: _userManager.GetUserById(_session.UserId);
var newItem = CreatePlaylistItem(info.Item, user, newPosition, info.MediaSourceId, info.AudioStreamIndex, newIndex);
await _device.SetAvTransport(newItem.StreamUrl, GetDlnaHeaders(newItem), newItem.Didl, CancellationToken.None).ConfigureAwait(false);
// Send a message to the DLNA device to notify what is the next track in the play list.
var newItemIndex = _playlist.FindIndex(item => item.StreamUrl == newItem.StreamUrl);
await SendNextTrackMessage(newItemIndex, CancellationToken.None);
await SendNextTrackMessage(newItemIndex, CancellationToken.None).ConfigureAwait(false);
if (EnableClientSideSeek(newItem.StreamInfo) && newPosition > 0)
{
@@ -816,7 +824,7 @@ namespace Emby.Dlna.PlayTo
const int Interval = 500;
var currentWait = 0;
while (_device.TransportState != TransportState.Playing && currentWait < MaxWait)
while (_device.TransportState != TransportState.PLAYING && currentWait < MaxWait)
{
await Task.Delay(Interval, cancellationToken).ConfigureAwait(false);
currentWait += Interval;
@@ -883,7 +891,7 @@ namespace Emby.Dlna.PlayTo
private class StreamParams
{
private MediaSourceInfo mediaSource;
private MediaSourceInfo _mediaSource;
private IMediaSourceManager _mediaSourceManager;
public Guid ItemId { get; set; }
@@ -908,24 +916,22 @@ namespace Emby.Dlna.PlayTo
public async Task<MediaSourceInfo> GetMediaSource(CancellationToken cancellationToken)
{
if (mediaSource != null)
if (_mediaSource != null)
{
return mediaSource;
return _mediaSource;
}
var hasMediaSources = Item as IHasMediaSources;
if (hasMediaSources == null)
if (Item is not IHasMediaSources)
{
return null;
}
if (_mediaSourceManager != null)
{
mediaSource = await _mediaSourceManager.GetMediaSource(Item, MediaSourceId, LiveStreamId, false, cancellationToken).ConfigureAwait(false);
_mediaSource = await _mediaSourceManager.GetMediaSource(Item, MediaSourceId, LiveStreamId, false, cancellationToken).ConfigureAwait(false);
}
return mediaSource;
return _mediaSource;
}
private static Guid GetItemId(string url)
@@ -951,7 +957,7 @@ namespace Emby.Dlna.PlayTo
}
}
return Guid.Empty;
return default;
}
public static StreamParams ParseFromUrl(string url, ILibraryManager libraryManager, IMediaSourceManager mediaSourceManager)
@@ -966,7 +972,7 @@ namespace Emby.Dlna.PlayTo
ItemId = GetItemId(url)
};
if (request.ItemId.Equals(Guid.Empty))
if (request.ItemId.Equals(default))
{
return request;
}

View File

@@ -2,12 +2,15 @@
namespace Emby.Dlna.PlayTo
{
/// <summary>
/// Core of the AVTransport service. It defines the conceptually top-
/// level state of the transport, for example, whether it is playing, recording, etc.
/// </summary>
public enum TransportState
{
Stopped,
Playing,
Transitioning,
PausedPlayback,
Paused
STOPPED,
PLAYING,
TRANSITIONING,
PAUSED_PLAYBACK
}
}

View File

@@ -47,7 +47,7 @@ namespace Emby.Dlna.Service
private async Task<ControlResponse> ProcessControlRequestInternalAsync(ControlRequest request)
{
ControlRequestInfo? requestInfo = null;
ControlRequestInfo requestInfo;
using (var streamReader = new StreamReader(request.InputXml, Encoding.UTF8))
{
@@ -66,6 +66,11 @@ namespace Emby.Dlna.Service
Logger.LogDebug("Received control request {LocalName}, params: {@Headers}", requestInfo.LocalName, requestInfo.Headers);
return CreateControlResponse(requestInfo);
}
private ControlResponse CreateControlResponse(ControlRequestInfo requestInfo)
{
var settings = new XmlWriterSettings
{
Encoding = Encoding.UTF8,
@@ -112,29 +117,19 @@ namespace Emby.Dlna.Service
{
if (reader.NodeType == XmlNodeType.Element)
{
switch (reader.LocalName)
if (string.Equals(reader.LocalName, "Body", StringComparison.Ordinal))
{
case "Body":
{
if (!reader.IsEmptyElement)
{
using var subReader = reader.ReadSubtree();
return await ParseBodyTagAsync(subReader).ConfigureAwait(false);
}
else
{
await reader.ReadAsync().ConfigureAwait(false);
}
if (reader.IsEmptyElement)
{
await reader.ReadAsync().ConfigureAwait(false);
continue;
}
break;
}
default:
{
await reader.SkipAsync().ConfigureAwait(false);
break;
}
using var subReader = reader.ReadSubtree();
return await ParseBodyTagAsync(subReader).ConfigureAwait(false);
}
await reader.SkipAsync().ConfigureAwait(false);
}
else
{
@@ -160,17 +155,17 @@ namespace Emby.Dlna.Service
localName = reader.LocalName;
namespaceURI = reader.NamespaceURI;
if (!reader.IsEmptyElement)
if (reader.IsEmptyElement)
{
await reader.ReadAsync().ConfigureAwait(false);
}
else
{
var result = new ControlRequestInfo(localName, namespaceURI);
using var subReader = reader.ReadSubtree();
await ParseFirstBodyChildAsync(subReader, result.Headers).ConfigureAwait(false);
return result;
}
else
{
await reader.ReadAsync().ConfigureAwait(false);
}
}
else
{

View File

@@ -27,8 +27,12 @@
<!-- Code analysers-->
<ItemGroup Condition=" '$(Configuration)' == 'Debug' ">
<PackageReference Include="Microsoft.CodeAnalysis.BannedApiAnalyzers" Version="3.3.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
<PackageReference Include="SerilogAnalyzer" Version="0.15.0" PrivateAssets="All" />
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.376" PrivateAssets="All" />
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.406" PrivateAssets="All" />
<PackageReference Include="SmartAnalyzers.MultithreadingAnalyzer" Version="1.1.31" PrivateAssets="All" />
</ItemGroup>

View File

@@ -43,6 +43,12 @@ namespace Emby.Drawing
throw new NotImplementedException();
}
/// <inheritdoc />
public void CreateSplashscreen(IReadOnlyList<string> posters, IReadOnlyList<string> backdrops)
{
throw new NotImplementedException();
}
/// <inheritdoc />
public string GetImageBlurHash(int xComp, int yComp, string path)
{

View File

@@ -23,47 +23,60 @@ namespace Emby.Naming.Common
{
VideoFileExtensions = new[]
{
".m4v",
".001",
".3g2",
".3gp",
".nsv",
".ts",
".ty",
".strm",
".rm",
".rmvb",
".ifo",
".mov",
".qt",
".divx",
".xvid",
".bivx",
".vob",
".nrg",
".img",
".iso",
".pva",
".wmv",
".amv",
".asf",
".asx",
".ogm",
".m2v",
".avi",
".bin",
".dvr-ms",
".mpg",
".mpeg",
".mp4",
".mkv",
".avc",
".vp3",
".svq3",
".nuv",
".viv",
".bivx",
".divx",
".dv",
".dvr-ms",
".f4v",
".fli",
".flv",
".001",
".tp"
".ifo",
".img",
".iso",
".m2t",
".m2ts",
".m2v",
".m4v",
".mkv",
".mk3d",
".mov",
".mp4",
".mpe",
".mpeg",
".mpg",
".mts",
".mxf",
".nrg",
".nsv",
".nuv",
".ogg",
".ogm",
".ogv",
".pva",
".qt",
".rec",
".rm",
".rmvb",
".strm",
".svq3",
".tp",
".ts",
".ty",
".viv",
".vob",
".vp3",
".webm",
".wmv",
".wtv",
".xvid"
};
VideoFlagDelimiters = new[]
@@ -149,32 +162,20 @@ namespace Emby.Naming.Common
SubtitleFileExtensions = new[]
{
".ass",
".mks",
".sami",
".smi",
".srt",
".ssa",
".ass",
".sub"
};
SubtitleFlagDelimiters = new[]
{
'.'
};
SubtitleForcedFlags = new[]
{
"foreign",
"forced"
};
SubtitleDefaultFlags = new[]
{
"default"
".sub",
".vtt",
};
AlbumStackingPrefixes = new[]
{
"disc",
"cd",
"disc",
"disk",
"vol",
"volume"
@@ -182,68 +183,101 @@ namespace Emby.Naming.Common
AudioFileExtensions = new[]
{
".nsv",
".m4a",
".flac",
".aac",
".strm",
".pls",
".rm",
".mpa",
".wav",
".wma",
".ogg",
".opus",
".mp3",
".mp2",
".mod",
".amf",
".669",
".3gp",
".aa",
".aac",
".aax",
".ac3",
".act",
".adp",
".adplug",
".adx",
".afc",
".amf",
".aif",
".aiff",
".alac",
".amr",
".ape",
".ast",
".au",
".awb",
".cda",
".cue",
".dmf",
".dsf",
".dsm",
".dsp",
".dts",
".dvf",
".far",
".flac",
".gdm",
".gsm",
".gym",
".hps",
".imf",
".it",
".m15",
".m4a",
".m4b",
".mac",
".med",
".mka",
".mmf",
".mod",
".mogg",
".mp2",
".mp3",
".mpa",
".mpc",
".mpp",
".mp+",
".msv",
".nmf",
".nsf",
".nsv",
".oga",
".ogg",
".okt",
".opus",
".pls",
".ra",
".rf64",
".rm",
".s3m",
".stm",
".sfx",
".shn",
".sid",
".spc",
".stm",
".strm",
".ult",
".uni",
".xm",
".sid",
".ac3",
".dts",
".cue",
".aif",
".aiff",
".ape",
".mac",
".mpc",
".mp+",
".mpp",
".shn",
".vox",
".wav",
".wma",
".wv",
".nsf",
".spc",
".gym",
".adplug",
".adx",
".dsp",
".adp",
".ymf",
".ast",
".afc",
".hps",
".xm",
".xsp",
".acc",
".m4b",
".oga",
".dsf",
".mka"
".ymf"
};
MediaFlagDelimiters = new[]
{
'.'
};
MediaForcedFlags = new[]
{
"foreign",
"forced"
};
MediaDefaultFlags = new[]
{
"default"
};
EpisodeExpressions = new[]
@@ -410,6 +444,66 @@ namespace Emby.Naming.Common
"trailers",
MediaType.Video),
new ExtraRule(
ExtraType.ThemeVideo,
ExtraRuleType.DirectoryName,
"backdrops",
MediaType.Video),
new ExtraRule(
ExtraType.ThemeSong,
ExtraRuleType.DirectoryName,
"theme-music",
MediaType.Audio),
new ExtraRule(
ExtraType.BehindTheScenes,
ExtraRuleType.DirectoryName,
"behind the scenes",
MediaType.Video),
new ExtraRule(
ExtraType.DeletedScene,
ExtraRuleType.DirectoryName,
"deleted scenes",
MediaType.Video),
new ExtraRule(
ExtraType.Interview,
ExtraRuleType.DirectoryName,
"interviews",
MediaType.Video),
new ExtraRule(
ExtraType.Scene,
ExtraRuleType.DirectoryName,
"scenes",
MediaType.Video),
new ExtraRule(
ExtraType.Sample,
ExtraRuleType.DirectoryName,
"samples",
MediaType.Video),
new ExtraRule(
ExtraType.Clip,
ExtraRuleType.DirectoryName,
"shorts",
MediaType.Video),
new ExtraRule(
ExtraType.Clip,
ExtraRuleType.DirectoryName,
"featurettes",
MediaType.Video),
new ExtraRule(
ExtraType.Unknown,
ExtraRuleType.DirectoryName,
"extras",
MediaType.Video),
new ExtraRule(
ExtraType.Trailer,
ExtraRuleType.Filename,
@@ -470,24 +564,12 @@ namespace Emby.Naming.Common
" sample",
MediaType.Video),
new ExtraRule(
ExtraType.ThemeVideo,
ExtraRuleType.DirectoryName,
"backdrops",
MediaType.Video),
new ExtraRule(
ExtraType.ThemeSong,
ExtraRuleType.Filename,
"theme",
MediaType.Audio),
new ExtraRule(
ExtraType.ThemeSong,
ExtraRuleType.DirectoryName,
"theme-music",
MediaType.Audio),
new ExtraRule(
ExtraType.Scene,
ExtraRuleType.Suffix,
@@ -536,55 +618,17 @@ namespace Emby.Naming.Common
"-short",
MediaType.Video),
new ExtraRule(
ExtraType.BehindTheScenes,
ExtraRuleType.DirectoryName,
"behind the scenes",
MediaType.Video),
new ExtraRule(
ExtraType.DeletedScene,
ExtraRuleType.DirectoryName,
"deleted scenes",
MediaType.Video),
new ExtraRule(
ExtraType.Interview,
ExtraRuleType.DirectoryName,
"interviews",
MediaType.Video),
new ExtraRule(
ExtraType.Scene,
ExtraRuleType.DirectoryName,
"scenes",
MediaType.Video),
new ExtraRule(
ExtraType.Sample,
ExtraRuleType.DirectoryName,
"samples",
MediaType.Video),
new ExtraRule(
ExtraType.Clip,
ExtraRuleType.DirectoryName,
"shorts",
MediaType.Video),
new ExtraRule(
ExtraType.Clip,
ExtraRuleType.DirectoryName,
"featurettes",
MediaType.Video),
new ExtraRule(
ExtraType.Unknown,
ExtraRuleType.DirectoryName,
"extras",
ExtraRuleType.Suffix,
"-extra",
MediaType.Video)
};
AllExtrasTypesFolderNames = VideoExtraRules
.Where(i => i.RuleType == ExtraRuleType.DirectoryName)
.ToDictionary(i => i.Token, i => i.ExtraType, StringComparer.OrdinalIgnoreCase);
Format3DRules = new[]
{
// Kodi rules:
@@ -638,41 +682,6 @@ namespace Emby.Naming.Common
@"^\s*(?<name>[^ ].*?)\s*$"
};
var extensions = VideoFileExtensions.ToList();
extensions.AddRange(new[]
{
".mkv",
".m2t",
".m2ts",
".img",
".iso",
".mk3d",
".ts",
".rmvb",
".mov",
".avi",
".mpg",
".mpeg",
".wmv",
".mp4",
".divx",
".dvr-ms",
".wtv",
".ogm",
".ogv",
".asf",
".m4v",
".flv",
".f4v",
".3gp",
".webm",
".mts",
".m2v",
".rec",
".mxf"
});
MultipleEpisodeExpressions = new[]
{
@".*(\\|\/)[sS]?(?<seasonnumber>[0-9]{1,4})[xX](?<epnumber>[0-9]{1,3})((-| - )[0-9]{1,4}[eExX](?<endingepnumber>[0-9]{1,3}))+[^\\\/]*$",
@@ -690,25 +699,6 @@ namespace Emby.Naming.Common
IsNamed = true
}).ToArray();
VideoFileExtensions = extensions
.Distinct(StringComparer.OrdinalIgnoreCase)
.ToArray();
AllExtrasTypesFolderNames = new Dictionary<string, ExtraType>(StringComparer.OrdinalIgnoreCase)
{
["trailers"] = ExtraType.Trailer,
["theme-music"] = ExtraType.ThemeSong,
["backdrops"] = ExtraType.ThemeVideo,
["extras"] = ExtraType.Unknown,
["behind the scenes"] = ExtraType.BehindTheScenes,
["deleted scenes"] = ExtraType.DeletedScene,
["interviews"] = ExtraType.Interview,
["scenes"] = ExtraType.Scene,
["samples"] = ExtraType.Sample,
["shorts"] = ExtraType.Clip,
["featurettes"] = ExtraType.Clip
};
Compile();
}
@@ -722,6 +712,21 @@ namespace Emby.Naming.Common
/// </summary>
public string[] AudioFileExtensions { get; set; }
/// <summary>
/// Gets or sets list of external media flag delimiters.
/// </summary>
public char[] MediaFlagDelimiters { get; set; }
/// <summary>
/// Gets or sets list of external media forced flags.
/// </summary>
public string[] MediaForcedFlags { get; set; }
/// <summary>
/// Gets or sets list of external media default flags.
/// </summary>
public string[] MediaDefaultFlags { get; set; }
/// <summary>
/// Gets or sets list of album stacking prefixes.
/// </summary>
@@ -732,21 +737,6 @@ namespace Emby.Naming.Common
/// </summary>
public string[] SubtitleFileExtensions { get; set; }
/// <summary>
/// Gets or sets list of subtitles flag delimiters.
/// </summary>
public char[] SubtitleFlagDelimiters { get; set; }
/// <summary>
/// Gets or sets list of subtitle forced flags.
/// </summary>
public string[] SubtitleForcedFlags { get; set; }
/// <summary>
/// Gets or sets list of subtitle default flags.
/// </summary>
public string[] SubtitleDefaultFlags { get; set; }
/// <summary>
/// Gets or sets list of episode regular expressions.
/// </summary>

View File

@@ -47,8 +47,12 @@
<!-- Code Analyzers-->
<ItemGroup Condition=" '$(Configuration)' == 'Debug' ">
<PackageReference Include="Microsoft.CodeAnalysis.BannedApiAnalyzers" Version="3.3.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
<PackageReference Include="SerilogAnalyzer" Version="0.15.0" PrivateAssets="All" />
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.376" PrivateAssets="All" />
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.406" PrivateAssets="All" />
<PackageReference Include="SmartAnalyzers.MultithreadingAnalyzer" Version="1.1.31" PrivateAssets="All" />
</ItemGroup>

View File

@@ -0,0 +1,116 @@
using System;
using System.IO;
using System.Linq;
using Emby.Naming.Common;
using Jellyfin.Extensions;
using MediaBrowser.Model.Dlna;
using MediaBrowser.Model.Globalization;
namespace Emby.Naming.ExternalFiles
{
/// <summary>
/// External media file parser class.
/// </summary>
public class ExternalPathParser
{
private readonly NamingOptions _namingOptions;
private readonly DlnaProfileType _type;
private readonly ILocalizationManager _localizationManager;
/// <summary>
/// Initializes a new instance of the <see cref="ExternalPathParser"/> class.
/// </summary>
/// <param name="localizationManager">The localization manager.</param>
/// <param name="namingOptions">The <see cref="NamingOptions"/> object containing FileExtensions, MediaDefaultFlags, MediaForcedFlags and MediaFlagDelimiters.</param>
/// <param name="type">The <see cref="DlnaProfileType"/> of the parsed file.</param>
public ExternalPathParser(NamingOptions namingOptions, ILocalizationManager localizationManager, DlnaProfileType type)
{
_localizationManager = localizationManager;
_namingOptions = namingOptions;
_type = type;
}
/// <summary>
/// Parse filename and extract information.
/// </summary>
/// <param name="path">Path to file.</param>
/// <param name="extraString">Part of the filename only containing the extra information.</param>
/// <returns>Returns null or an <see cref="ExternalPathParserResult"/> object if parsing is successful.</returns>
public ExternalPathParserResult? ParseFile(string path, string? extraString)
{
if (path.Length == 0)
{
return null;
}
var extension = Path.GetExtension(path);
if (!(_type == DlnaProfileType.Subtitle && _namingOptions.SubtitleFileExtensions.Contains(extension, StringComparison.OrdinalIgnoreCase))
&& !(_type == DlnaProfileType.Audio && _namingOptions.AudioFileExtensions.Contains(extension, StringComparison.OrdinalIgnoreCase)))
{
return null;
}
var pathInfo = new ExternalPathParserResult(path);
if (string.IsNullOrEmpty(extraString))
{
return pathInfo;
}
foreach (var separator in _namingOptions.MediaFlagDelimiters)
{
var languageString = extraString;
var titleString = string.Empty;
const int SeparatorLength = 1;
while (languageString.Length > 0)
{
int lastSeparator = languageString.LastIndexOf(separator);
if (lastSeparator == -1)
{
break;
}
string currentSlice = languageString[lastSeparator..];
string currentSliceWithoutSeparator = currentSlice[SeparatorLength..];
if (_namingOptions.MediaDefaultFlags.Any(s => currentSliceWithoutSeparator.Contains(s, StringComparison.OrdinalIgnoreCase)))
{
pathInfo.IsDefault = true;
extraString = extraString.Replace(currentSlice, string.Empty, StringComparison.OrdinalIgnoreCase);
languageString = languageString[..lastSeparator];
continue;
}
if (_namingOptions.MediaForcedFlags.Any(s => currentSliceWithoutSeparator.Contains(s, StringComparison.OrdinalIgnoreCase)))
{
pathInfo.IsForced = true;
extraString = extraString.Replace(currentSlice, string.Empty, StringComparison.OrdinalIgnoreCase);
languageString = languageString[..lastSeparator];
continue;
}
// Try to translate to three character code
var culture = _localizationManager.FindLanguageInfo(currentSliceWithoutSeparator);
if (culture != null && pathInfo.Language == null)
{
pathInfo.Language = culture.ThreeLetterISOLanguageName;
extraString = extraString.Replace(currentSlice, string.Empty, StringComparison.OrdinalIgnoreCase);
}
else
{
titleString = currentSlice + titleString;
}
languageString = languageString[..lastSeparator];
}
pathInfo.Title = titleString.Length >= SeparatorLength ? titleString[SeparatorLength..] : null;
}
return pathInfo;
}
}
}

View File

@@ -1,17 +1,17 @@
namespace Emby.Naming.Subtitles
namespace Emby.Naming.ExternalFiles
{
/// <summary>
/// Class holding information about subtitle.
/// Class holding information about external files.
/// </summary>
public class SubtitleInfo
public class ExternalPathParserResult
{
/// <summary>
/// Initializes a new instance of the <see cref="SubtitleInfo"/> class.
/// Initializes a new instance of the <see cref="ExternalPathParserResult"/> class.
/// </summary>
/// <param name="path">Path to file.</param>
/// <param name="isDefault">Is subtitle default.</param>
/// <param name="isForced">Is subtitle forced.</param>
public SubtitleInfo(string path, bool isDefault, bool isForced)
/// <param name="isDefault">Is default.</param>
/// <param name="isForced">Is forced.</param>
public ExternalPathParserResult(string path, bool isDefault = false, bool isForced = false)
{
Path = path;
IsDefault = isDefault;
@@ -30,6 +30,12 @@ namespace Emby.Naming.Subtitles
/// <value>The language.</value>
public string? Language { get; set; }
/// <summary>
/// Gets or sets the title.
/// </summary>
/// <value>The title.</value>
public string? Title { get; set; }
/// <summary>
/// Gets or sets a value indicating whether this instance is default.
/// </summary>

View File

@@ -1,71 +0,0 @@
using System;
using System.IO;
using System.Linq;
using Emby.Naming.Common;
using Jellyfin.Extensions;
namespace Emby.Naming.Subtitles
{
/// <summary>
/// Subtitle Parser class.
/// </summary>
public class SubtitleParser
{
private readonly NamingOptions _options;
/// <summary>
/// Initializes a new instance of the <see cref="SubtitleParser"/> class.
/// </summary>
/// <param name="options"><see cref="NamingOptions"/> object containing SubtitleFileExtensions, SubtitleDefaultFlags, SubtitleForcedFlags and SubtitleFlagDelimiters.</param>
public SubtitleParser(NamingOptions options)
{
_options = options;
}
/// <summary>
/// Parse file to determine if is subtitle and <see cref="SubtitleInfo"/>.
/// </summary>
/// <param name="path">Path to file.</param>
/// <returns>Returns null or <see cref="SubtitleInfo"/> object if parsing is successful.</returns>
public SubtitleInfo? ParseFile(string path)
{
if (path.Length == 0)
{
return null;
}
var extension = Path.GetExtension(path);
if (!_options.SubtitleFileExtensions.Contains(extension, StringComparison.OrdinalIgnoreCase))
{
return null;
}
var flags = GetFlags(path);
var info = new SubtitleInfo(
path,
_options.SubtitleDefaultFlags.Any(i => flags.Contains(i, StringComparison.OrdinalIgnoreCase)),
_options.SubtitleForcedFlags.Any(i => flags.Contains(i, StringComparison.OrdinalIgnoreCase)));
var parts = flags.Where(i => !_options.SubtitleDefaultFlags.Contains(i, StringComparison.OrdinalIgnoreCase)
&& !_options.SubtitleForcedFlags.Contains(i, StringComparison.OrdinalIgnoreCase))
.ToList();
// Should have a name, language and file extension
if (parts.Count >= 3)
{
info.Language = parts[^2];
}
return info;
}
private string[] GetFlags(string path)
{
// Note: the tags need be surrounded be either a space ( ), hyphen -, dot . or underscore _.
var file = Path.GetFileName(path);
return file.Split(_options.SubtitleFlagDelimiters, StringSplitOptions.RemoveEmptyEntries);
}
}
}

View File

@@ -23,8 +23,12 @@
<!-- Code analyzers-->
<ItemGroup Condition=" '$(Configuration)' == 'Debug' ">
<PackageReference Include="Microsoft.CodeAnalysis.BannedApiAnalyzers" Version="3.3.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
<PackageReference Include="SerilogAnalyzer" Version="0.15.0" PrivateAssets="All" />
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.376" PrivateAssets="All" />
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.406" PrivateAssets="All" />
<PackageReference Include="SmartAnalyzers.MultithreadingAnalyzer" Version="1.1.31" PrivateAssets="All" />
</ItemGroup>

View File

@@ -112,7 +112,7 @@ namespace Emby.Notifications
var userId = e.Argument.UserId;
if (!userId.Equals(Guid.Empty) && !GetOptions().IsEnabledToMonitorUser(type, userId))
if (!userId.Equals(default) && !GetOptions().IsEnabledToMonitorUser(type, userId))
{
return;
}

View File

@@ -26,7 +26,11 @@
<!-- Code Analyzers-->
<ItemGroup Condition=" '$(Configuration)' == 'Debug' ">
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.376" PrivateAssets="All" />
<PackageReference Include="Microsoft.CodeAnalysis.BannedApiAnalyzers" Version="3.3.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.406" PrivateAssets="All" />
<PackageReference Include="SerilogAnalyzer" Version="0.15.0" PrivateAssets="All" />
<PackageReference Include="SmartAnalyzers.MultithreadingAnalyzer" Version="1.1.31" PrivateAssets="All" />
</ItemGroup>

View File

@@ -398,6 +398,12 @@ namespace Emby.Server.Implementations.AppBase
});
}
/// <inheritdoc />
public ConfigurationStore[] GetConfigurationStores()
{
return _configurationStores;
}
/// <inheritdoc />
public Type GetConfigurationType(string key)
{

View File

@@ -44,9 +44,9 @@ using Emby.Server.Implementations.Serialization;
using Emby.Server.Implementations.Session;
using Emby.Server.Implementations.SyncPlay;
using Emby.Server.Implementations.TV;
using Emby.Server.Implementations.Udp;
using Emby.Server.Implementations.Updates;
using Jellyfin.Api.Helpers;
using Jellyfin.MediaEncoding.Hls.Playlist;
using Jellyfin.Networking.Configuration;
using Jellyfin.Networking.Manager;
using MediaBrowser.Common;
@@ -103,6 +103,7 @@ using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Prometheus.DotNetRuntime;
using static MediaBrowser.Controller.Extensions.ConfigurationExtensions;
using WebSocketManager = Emby.Server.Implementations.HttpServer.WebSocketManager;
namespace Emby.Server.Implementations
@@ -149,7 +150,7 @@ namespace Emby.Server.Implementations
/// <param name="loggerFactory">Instance of the <see cref="ILoggerFactory"/> interface.</param>
/// <param name="options">Instance of the <see cref="IStartupOptions"/> interface.</param>
/// <param name="startupConfig">The <see cref="IConfiguration" /> interface.</param>
public ApplicationHost(
protected ApplicationHost(
IServerApplicationPaths applicationPaths,
ILoggerFactory loggerFactory,
IStartupOptions options,
@@ -183,6 +184,11 @@ namespace Emby.Server.Implementations
/// </summary>
public event EventHandler HasPendingRestartChanged;
/// <summary>
/// Gets the value of the PublishedServerUrl setting.
/// </summary>
private string PublishedServerUrl => _startupConfig[AddressOverrideKey];
/// <summary>
/// Gets a value indicating whether this instance can self restart.
/// </summary>
@@ -259,11 +265,6 @@ namespace Emby.Server.Implementations
/// </summary>
public int HttpsPort { get; private set; }
/// <summary>
/// Gets the value of the PublishedServerUrl setting.
/// </summary>
public string PublishedServerUrl => _startupOptions.PublishedServerUrl ?? _startupConfig[UdpServer.AddressOverrideConfigKey];
/// <inheritdoc />
public Version ApplicationVersion { get; }
@@ -973,7 +974,7 @@ namespace Emby.Server.Implementations
yield return typeof(IServerApplicationHost).Assembly;
// Include composable parts in the Providers assembly
yield return typeof(ProviderUtils).Assembly;
yield return typeof(ProviderManager).Assembly;
// Include composable parts in the Photos assembly
yield return typeof(PhotoProvider).Assembly;
@@ -999,6 +1000,9 @@ namespace Emby.Server.Implementations
// Network
yield return typeof(NetworkManager).Assembly;
// Hls
yield return typeof(DynamicHlsPlaylistGenerator).Assembly;
foreach (var i in GetAssembliesWithPartsInternal())
{
yield return i;

View File

@@ -39,7 +39,7 @@ namespace Emby.Server.Implementations.Channels
/// <summary>
/// The LiveTV channel manager.
/// </summary>
public class ChannelManager : IChannelManager
public class ChannelManager : IChannelManager, IDisposable
{
private readonly IUserManager _userManager;
private readonly IUserDataManager _userDataManager;
@@ -52,6 +52,7 @@ namespace Emby.Server.Implementations.Channels
private readonly IMemoryCache _memoryCache;
private readonly SemaphoreSlim _resourcePool = new SemaphoreSlim(1, 1);
private readonly JsonSerializerOptions _jsonOptions = JsonDefaults.Options;
private bool _disposed = false;
/// <summary>
/// Initializes a new instance of the <see cref="ChannelManager"/> class.
@@ -161,7 +162,7 @@ namespace Emby.Server.Implementations.Channels
/// <inheritdoc />
public QueryResult<Channel> GetChannelsInternal(ChannelQuery query)
{
var user = query.UserId.Equals(Guid.Empty)
var user = query.UserId.Equals(default)
? null
: _userManager.GetUserById(query.UserId);
@@ -264,17 +265,16 @@ namespace Emby.Server.Implementations.Channels
}
}
return new QueryResult<Channel>
{
Items = all,
TotalRecordCount = totalCount
};
return new QueryResult<Channel>(
query.StartIndex,
totalCount,
all);
}
/// <inheritdoc />
public QueryResult<BaseItemDto> GetChannels(ChannelQuery query)
{
var user = query.UserId.Equals(Guid.Empty)
var user = query.UserId.Equals(default)
? null
: _userManager.GetUserById(query.UserId);
@@ -285,11 +285,10 @@ namespace Emby.Server.Implementations.Channels
// TODO Fix The co-variant conversion (internalResult.Items) between Folder[] and BaseItem[], this can generate runtime issues.
var returnItems = _dtoService.GetBaseItemDtos(internalResult.Items, dtoOptions, user);
var result = new QueryResult<BaseItemDto>
{
Items = returnItems,
TotalRecordCount = internalResult.TotalRecordCount
};
var result = new QueryResult<BaseItemDto>(
query.StartIndex,
internalResult.TotalRecordCount,
returnItems);
return result;
}
@@ -333,7 +332,7 @@ namespace Emby.Server.Implementations.Channels
private Channel GetChannelEntity(IChannel channel)
{
return GetChannel(GetInternalChannelId(channel.Name)) ?? GetChannel(channel, CancellationToken.None).Result;
return GetChannel(GetInternalChannelId(channel.Name)) ?? GetChannel(channel, CancellationToken.None).GetAwaiter().GetResult();
}
private MediaSourceInfo[] GetSavedMediaSources(BaseItem item)
@@ -475,7 +474,7 @@ namespace Emby.Server.Implementations.Channels
item.ChannelId = id;
if (item.ParentId != parentFolderId)
if (!item.ParentId.Equals(parentFolderId))
{
forceUpdate = true;
}
@@ -620,11 +619,10 @@ namespace Emby.Server.Implementations.Channels
var returnItems = _dtoService.GetBaseItemDtos(items, query.DtoOptions, query.User);
var result = new QueryResult<BaseItemDto>
{
Items = returnItems,
TotalRecordCount = totalRecordCount
};
var result = new QueryResult<BaseItemDto>(
query.StartIndex,
totalRecordCount,
returnItems);
return result;
}
@@ -717,7 +715,9 @@ namespace Emby.Server.Implementations.Channels
// Find the corresponding channel provider plugin
var channelProvider = GetChannelProvider(channel);
var parentItem = query.ParentId == Guid.Empty ? channel : _libraryManager.GetItemById(query.ParentId);
var parentItem = query.ParentId.Equals(default)
? channel
: _libraryManager.GetItemById(query.ParentId);
var itemsResult = await GetChannelItems(
channelProvider,
@@ -728,7 +728,7 @@ namespace Emby.Server.Implementations.Channels
cancellationToken)
.ConfigureAwait(false);
if (query.ParentId == Guid.Empty)
if (query.ParentId.Equals(default))
{
query.Parent = channel;
}
@@ -786,11 +786,10 @@ namespace Emby.Server.Implementations.Channels
var returnItems = _dtoService.GetBaseItemDtos(internalResult.Items, query.DtoOptions, query.User);
var result = new QueryResult<BaseItemDto>
{
Items = returnItems,
TotalRecordCount = internalResult.TotalRecordCount
};
var result = new QueryResult<BaseItemDto>(
query.StartIndex,
internalResult.TotalRecordCount,
returnItems);
return result;
}
@@ -1217,5 +1216,31 @@ namespace Emby.Server.Implementations.Channels
return result;
}
/// <inheritdoc />
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
/// <summary>
/// Releases unmanaged and optionally managed resources.
/// </summary>
/// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
protected virtual void Dispose(bool disposing)
{
if (_disposed)
{
return;
}
if (disposing)
{
_resourcePool?.Dispose();
}
_disposed = true;
}
}
}

View File

@@ -62,7 +62,7 @@ namespace Emby.Server.Implementations.Channels
public string Key => "RefreshInternetChannels";
/// <inheritdoc />
public async Task Execute(CancellationToken cancellationToken, IProgress<double> progress)
public async Task ExecuteAsync(IProgress<double> progress, CancellationToken cancellationToken)
{
var manager = (ChannelManager)_channelManager;

View File

@@ -265,7 +265,7 @@ namespace Emby.Server.Implementations.Collections
{
var childItem = _libraryManager.GetItemById(guidId);
var child = collection.LinkedChildren.FirstOrDefault(i => (i.ItemId.HasValue && i.ItemId.Value == guidId) || (childItem != null && string.Equals(childItem.Path, i.Path, StringComparison.OrdinalIgnoreCase)));
var child = collection.LinkedChildren.FirstOrDefault(i => (i.ItemId.HasValue && i.ItemId.Value.Equals(guidId)) || (childItem != null && string.Equals(childItem.Path, i.Path, StringComparison.OrdinalIgnoreCase)));
if (child == null)
{

View File

@@ -317,11 +317,6 @@ namespace Emby.Server.Implementations.Data
IImageProcessor imageProcessor)
: base(logger)
{
if (config == null)
{
throw new ArgumentNullException(nameof(config));
}
_config = config;
_appHost = appHost;
_localization = localization;
@@ -333,9 +328,6 @@ namespace Emby.Server.Implementations.Data
DbFilePath = Path.Combine(_config.ApplicationPaths.DataPath, "library.db");
}
/// <inheritdoc />
public string Name => "SQLite";
/// <inheritdoc />
protected override int? CacheSize => 20000;
@@ -573,22 +565,6 @@ namespace Emby.Server.Implementations.Data
userDataRepo.Initialize(userManager, WriteLock, WriteConnection);
}
/// <summary>
/// Save a standard item in the repo.
/// </summary>
/// <param name="item">The item.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <exception cref="ArgumentNullException"><paramref name="item"/> is <c>null</c>.</exception>
public void SaveItem(BaseItem item, CancellationToken cancellationToken)
{
if (item == null)
{
throw new ArgumentNullException(nameof(item));
}
SaveItems(new[] { item }, cancellationToken);
}
public void SaveImages(BaseItem item)
{
if (item == null)
@@ -605,7 +581,7 @@ namespace Emby.Server.Implementations.Data
{
using (var saveImagesStatement = PrepareStatement(db, "Update TypedBaseItems set Images=@Images where guid=@Id"))
{
saveImagesStatement.TryBind("@Id", item.Id.ToByteArray());
saveImagesStatement.TryBind("@Id", item.Id);
saveImagesStatement.TryBind("@Images", SerializeImages(item.ImageInfos));
saveImagesStatement.MoveNext();
@@ -750,7 +726,7 @@ namespace Emby.Server.Implementations.Data
saveItemStatement.TryBindNull("@EndDate");
}
saveItemStatement.TryBind("@ChannelId", item.ChannelId.Equals(Guid.Empty) ? null : item.ChannelId.ToString("N", CultureInfo.InvariantCulture));
saveItemStatement.TryBind("@ChannelId", item.ChannelId.Equals(default) ? null : item.ChannelId.ToString("N", CultureInfo.InvariantCulture));
if (item is IHasProgramAttributes hasProgramAttributes)
{
@@ -780,7 +756,7 @@ namespace Emby.Server.Implementations.Data
saveItemStatement.TryBind("@ProductionYear", item.ProductionYear);
var parentId = item.ParentId;
if (parentId.Equals(Guid.Empty))
if (parentId.Equals(default))
{
saveItemStatement.TryBindNull("@ParentId");
}
@@ -975,7 +951,7 @@ namespace Emby.Server.Implementations.Data
{
saveItemStatement.TryBind("@SeasonName", episode.SeasonName);
var nullableSeasonId = episode.SeasonId == Guid.Empty ? (Guid?)null : episode.SeasonId;
var nullableSeasonId = episode.SeasonId.Equals(default) ? (Guid?)null : episode.SeasonId;
saveItemStatement.TryBind("@SeasonId", nullableSeasonId);
}
@@ -987,7 +963,7 @@ namespace Emby.Server.Implementations.Data
if (item is IHasSeries hasSeries)
{
var nullableSeriesId = hasSeries.SeriesId.Equals(Guid.Empty) ? (Guid?)null : hasSeries.SeriesId;
var nullableSeriesId = hasSeries.SeriesId.Equals(default) ? (Guid?)null : hasSeries.SeriesId;
saveItemStatement.TryBind("@SeriesId", nullableSeriesId);
saveItemStatement.TryBind("@SeriesPresentationUniqueKey", hasSeries.SeriesPresentationUniqueKey);
@@ -1060,7 +1036,7 @@ namespace Emby.Server.Implementations.Data
}
Guid ownerId = item.OwnerId;
if (ownerId == Guid.Empty)
if (ownerId.Equals(default))
{
saveItemStatement.TryBindNull("@OwnerId");
}
@@ -1198,13 +1174,15 @@ namespace Emby.Server.Implementations.Data
bldr.Append(Delimiter)
// Replace delimiters with other characters.
// This can be removed when we migrate to a proper DB.
.Append(hash.Replace('*', '/').Replace('|', '\\'));
.Append(hash.Replace(Delimiter, '/').Replace('|', '\\'));
}
}
internal ItemImageInfo ItemImageInfoFromValueString(ReadOnlySpan<char> value)
{
var nextSegment = value.IndexOf('*');
const char Delimiter = '*';
var nextSegment = value.IndexOf(Delimiter);
if (nextSegment == -1)
{
return null;
@@ -1212,7 +1190,7 @@ namespace Emby.Server.Implementations.Data
ReadOnlySpan<char> path = value[..nextSegment];
value = value[(nextSegment + 1)..];
nextSegment = value.IndexOf('*');
nextSegment = value.IndexOf(Delimiter);
if (nextSegment == -1)
{
return null;
@@ -1220,7 +1198,7 @@ namespace Emby.Server.Implementations.Data
ReadOnlySpan<char> dateModified = value[..nextSegment];
value = value[(nextSegment + 1)..];
nextSegment = value.IndexOf('*');
nextSegment = value.IndexOf(Delimiter);
if (nextSegment == -1)
{
nextSegment = value.Length;
@@ -1257,7 +1235,7 @@ namespace Emby.Server.Implementations.Data
if (nextSegment + 1 < value.Length - 1)
{
value = value[(nextSegment + 1)..];
nextSegment = value.IndexOf('*');
nextSegment = value.IndexOf(Delimiter);
if (nextSegment == -1 || nextSegment == value.Length)
{
return image;
@@ -1266,7 +1244,7 @@ namespace Emby.Server.Implementations.Data
ReadOnlySpan<char> widthSpan = value[..nextSegment];
value = value[(nextSegment + 1)..];
nextSegment = value.IndexOf('*');
nextSegment = value.IndexOf(Delimiter);
if (nextSegment == -1)
{
nextSegment = value.Length;
@@ -1292,7 +1270,7 @@ namespace Emby.Server.Implementations.Data
var c = value[i];
blurHashSpan[i] = c switch
{
'/' => '*',
'/' => Delimiter,
'\\' => '|',
_ => c
};
@@ -1314,7 +1292,7 @@ namespace Emby.Server.Implementations.Data
/// <exception cref="ArgumentException"><paramr name="id"/> is <seealso cref="Guid.Empty"/>.</exception>
public BaseItem RetrieveItem(Guid id)
{
if (id == Guid.Empty)
if (id.Equals(default))
{
throw new ArgumentException("Guid can't be empty", nameof(id));
}
@@ -2086,7 +2064,7 @@ namespace Emby.Server.Implementations.Data
{
CheckDisposed();
if (id.Equals(Guid.Empty))
if (id.Equals(default))
{
throw new ArgumentNullException(nameof(id));
}
@@ -2492,12 +2470,12 @@ namespace Emby.Server.Implementations.Data
searchTerm = GetCleanValue(searchTerm);
var commandText = statement.SQL;
if (commandText.IndexOf("@SearchTermStartsWith", StringComparison.OrdinalIgnoreCase) != -1)
if (commandText.Contains("@SearchTermStartsWith", StringComparison.OrdinalIgnoreCase))
{
statement.TryBind("@SearchTermStartsWith", searchTerm + "%");
}
if (commandText.IndexOf("@SearchTermContains", StringComparison.OrdinalIgnoreCase) != -1)
if (commandText.Contains("@SearchTermContains", StringComparison.OrdinalIgnoreCase))
{
statement.TryBind("@SearchTermContains", "%" + searchTerm + "%");
}
@@ -2514,17 +2492,17 @@ namespace Emby.Server.Implementations.Data
var commandText = statement.SQL;
if (commandText.IndexOf("@ItemOfficialRating", StringComparison.OrdinalIgnoreCase) != -1)
if (commandText.Contains("@ItemOfficialRating", StringComparison.OrdinalIgnoreCase))
{
statement.TryBind("@ItemOfficialRating", item.OfficialRating);
}
if (commandText.IndexOf("@ItemProductionYear", StringComparison.OrdinalIgnoreCase) != -1)
if (commandText.Contains("@ItemProductionYear", StringComparison.OrdinalIgnoreCase))
{
statement.TryBind("@ItemProductionYear", item.ProductionYear ?? 0);
}
if (commandText.IndexOf("@SimilarItemId", StringComparison.OrdinalIgnoreCase) != -1)
if (commandText.Contains("@SimilarItemId", StringComparison.OrdinalIgnoreCase))
{
statement.TryBind("@SimilarItemId", item.Id);
}
@@ -2758,12 +2736,12 @@ namespace Emby.Server.Implementations.Data
foreach (var providerId in newItem.ProviderIds)
{
if (providerId.Key == MetadataProvider.TmdbCollection.ToString())
if (string.Equals(providerId.Key, nameof(MetadataProvider.TmdbCollection), StringComparison.Ordinal))
{
continue;
}
if (item.GetProviderId(providerId.Key) == providerId.Value)
if (string.Equals(item.GetProviderId(providerId.Key), providerId.Value, StringComparison.Ordinal))
{
if (newItem.SourceType == SourceType.Library)
{
@@ -2810,11 +2788,10 @@ namespace Emby.Server.Implementations.Data
if (!query.EnableTotalRecordCount || (!query.Limit.HasValue && (query.StartIndex ?? 0) == 0))
{
var returnList = GetItemList(query);
return new QueryResult<BaseItem>
{
Items = returnList,
TotalRecordCount = returnList.Count
};
return new QueryResult<BaseItem>(
query.StartIndex,
returnList.Count,
returnList);
}
var now = DateTime.UtcNow;
@@ -2978,6 +2955,7 @@ namespace Emby.Server.Implementations.Data
ReadTransactionMode);
}
result.StartIndex = query.StartIndex ?? 0;
result.Items = list;
return result;
}
@@ -3051,7 +3029,7 @@ namespace Emby.Server.Implementations.Data
if (string.Equals(name, ItemSortBy.PlayCount, StringComparison.OrdinalIgnoreCase))
{
return "PlayCount";
return ItemSortBy.PlayCount;
}
if (string.Equals(name, ItemSortBy.IsFavoriteOrLiked, StringComparison.OrdinalIgnoreCase))
@@ -3061,7 +3039,7 @@ namespace Emby.Server.Implementations.Data
if (string.Equals(name, ItemSortBy.IsFolder, StringComparison.OrdinalIgnoreCase))
{
return "IsFolder";
return ItemSortBy.IsFolder;
}
if (string.Equals(name, ItemSortBy.IsPlayed, StringComparison.OrdinalIgnoreCase))
@@ -3109,7 +3087,68 @@ namespace Emby.Server.Implementations.Data
return "SeriesName";
}
return name;
if (string.Equals(name, ItemSortBy.AiredEpisodeOrder, StringComparison.OrdinalIgnoreCase))
{
return ItemSortBy.AiredEpisodeOrder;
}
if (string.Equals(name, ItemSortBy.Album, StringComparison.OrdinalIgnoreCase))
{
return ItemSortBy.Album;
}
if (string.Equals(name, ItemSortBy.DateCreated, StringComparison.OrdinalIgnoreCase))
{
return ItemSortBy.DateCreated;
}
if (string.Equals(name, ItemSortBy.PremiereDate, StringComparison.OrdinalIgnoreCase))
{
return ItemSortBy.PremiereDate;
}
if (string.Equals(name, ItemSortBy.StartDate, StringComparison.OrdinalIgnoreCase))
{
return ItemSortBy.StartDate;
}
if (string.Equals(name, ItemSortBy.Name, StringComparison.OrdinalIgnoreCase))
{
return ItemSortBy.Name;
}
if (string.Equals(name, ItemSortBy.CommunityRating, StringComparison.OrdinalIgnoreCase))
{
return ItemSortBy.CommunityRating;
}
if (string.Equals(name, ItemSortBy.ProductionYear, StringComparison.OrdinalIgnoreCase))
{
return ItemSortBy.ProductionYear;
}
if (string.Equals(name, ItemSortBy.CriticRating, StringComparison.OrdinalIgnoreCase))
{
return ItemSortBy.CriticRating;
}
if (string.Equals(name, ItemSortBy.VideoBitRate, StringComparison.OrdinalIgnoreCase))
{
return ItemSortBy.VideoBitRate;
}
if (string.Equals(name, ItemSortBy.ParentIndexNumber, StringComparison.OrdinalIgnoreCase))
{
return ItemSortBy.ParentIndexNumber;
}
if (string.Equals(name, ItemSortBy.IndexNumber, StringComparison.OrdinalIgnoreCase))
{
return ItemSortBy.IndexNumber;
}
// Unknown SortBy, just sort by the SortName.
return ItemSortBy.SortName;
}
public List<Guid> GetItemIdsList(InternalItemsQuery query)
@@ -3185,220 +3224,6 @@ namespace Emby.Server.Implementations.Data
return list;
}
public List<Tuple<Guid, string>> GetItemIdsWithPath(InternalItemsQuery query)
{
if (query == null)
{
throw new ArgumentNullException(nameof(query));
}
CheckDisposed();
var now = DateTime.UtcNow;
var columns = new List<string> { "guid", "path" };
SetFinalColumnsToSelect(query, columns);
var commandText = "select " + string.Join(',', columns) + FromText;
var whereClauses = GetWhereClauses(query, null);
if (whereClauses.Count != 0)
{
commandText += " where " + string.Join(" AND ", whereClauses);
}
commandText += GetGroupBy(query)
+ GetOrderByText(query);
if (query.Limit.HasValue || query.StartIndex.HasValue)
{
var offset = query.StartIndex ?? 0;
if (query.Limit.HasValue || offset > 0)
{
commandText += " LIMIT " + (query.Limit ?? int.MaxValue).ToString(CultureInfo.InvariantCulture);
}
if (offset > 0)
{
commandText += " OFFSET " + offset.ToString(CultureInfo.InvariantCulture);
}
}
var list = new List<Tuple<Guid, string>>();
using (var connection = GetConnection(true))
{
using (var statement = PrepareStatement(connection, commandText))
{
if (EnableJoinUserData(query))
{
statement.TryBind("@UserId", query.User.InternalId);
}
// Running this again will bind the params
GetWhereClauses(query, statement);
foreach (var row in statement.ExecuteQuery())
{
var id = row.GetGuid(0);
row.TryGetString(1, out var path);
list.Add(new Tuple<Guid, string>(id, path));
}
}
}
LogQueryTime("GetItemIdsWithPath", commandText, now);
return list;
}
public QueryResult<Guid> GetItemIds(InternalItemsQuery query)
{
if (query == null)
{
throw new ArgumentNullException(nameof(query));
}
CheckDisposed();
if (!query.EnableTotalRecordCount || (!query.Limit.HasValue && (query.StartIndex ?? 0) == 0))
{
var returnList = GetItemIdsList(query);
return new QueryResult<Guid>
{
Items = returnList,
TotalRecordCount = returnList.Count
};
}
var now = DateTime.UtcNow;
var columns = new List<string> { "guid" };
SetFinalColumnsToSelect(query, columns);
var commandText = "select "
+ string.Join(',', columns)
+ FromText
+ GetJoinUserDataText(query);
var whereClauses = GetWhereClauses(query, null);
var whereText = whereClauses.Count == 0 ?
string.Empty :
" where " + string.Join(" AND ", whereClauses);
commandText += whereText
+ GetGroupBy(query)
+ GetOrderByText(query);
if (query.Limit.HasValue || query.StartIndex.HasValue)
{
var offset = query.StartIndex ?? 0;
if (query.Limit.HasValue || offset > 0)
{
commandText += " LIMIT " + (query.Limit ?? int.MaxValue).ToString(CultureInfo.InvariantCulture);
}
if (offset > 0)
{
commandText += " OFFSET " + offset.ToString(CultureInfo.InvariantCulture);
}
}
var isReturningZeroItems = query.Limit.HasValue && query.Limit <= 0;
var statementTexts = new List<string>();
if (!isReturningZeroItems)
{
statementTexts.Add(commandText);
}
if (query.EnableTotalRecordCount)
{
commandText = string.Empty;
List<string> columnsToSelect;
if (EnableGroupByPresentationUniqueKey(query))
{
columnsToSelect = new List<string> { "count (distinct PresentationUniqueKey)" };
}
else if (query.GroupBySeriesPresentationUniqueKey)
{
columnsToSelect = new List<string> { "count (distinct SeriesPresentationUniqueKey)" };
}
else
{
columnsToSelect = new List<string> { "count (guid)" };
}
SetFinalColumnsToSelect(query, columnsToSelect);
commandText += " select " + string.Join(',', columnsToSelect) + FromText;
commandText += GetJoinUserDataText(query)
+ whereText;
statementTexts.Add(commandText);
}
var list = new List<Guid>();
var result = new QueryResult<Guid>();
using (var connection = GetConnection(true))
{
connection.RunInTransaction(
db =>
{
var statements = PrepareAll(db, statementTexts);
if (!isReturningZeroItems)
{
using (var statement = statements[0])
{
if (EnableJoinUserData(query))
{
statement.TryBind("@UserId", query.User.InternalId);
}
BindSimilarParams(query, statement);
BindSearchParams(query, statement);
// Running this again will bind the params
GetWhereClauses(query, statement);
foreach (var row in statement.ExecuteQuery())
{
list.Add(row[0].ReadGuidFromBlob());
}
}
}
if (query.EnableTotalRecordCount)
{
using (var statement = statements[statements.Length - 1])
{
if (EnableJoinUserData(query))
{
statement.TryBind("@UserId", query.User.InternalId);
}
BindSimilarParams(query, statement);
BindSearchParams(query, statement);
// Running this again will bind the params
GetWhereClauses(query, statement);
result.TotalRecordCount = statement.ExecuteQuery().SelectScalarInt().First();
}
}
},
ReadTransactionMode);
}
LogQueryTime("GetItemIds", commandText, now);
result.Items = list;
return result;
}
private bool IsAlphaNumeric(string str)
{
if (string.IsNullOrWhiteSpace(str))
@@ -3665,7 +3490,7 @@ namespace Emby.Server.Implementations.Data
whereClauses.Add($"ChannelId in ({inClause})");
}
if (!query.ParentId.Equals(Guid.Empty))
if (!query.ParentId.Equals(default))
{
whereClauses.Add("ParentId=@ParentId");
statement?.TryBind("@ParentId", query.ParentId);
@@ -4025,7 +3850,7 @@ namespace Emby.Server.Implementations.Data
clauses.Add("(guid in (select itemid from itemvalues where CleanValue = (select CleanName from TypedBaseItems where guid=" + paramName + ") and Type<=1))");
if (statement != null)
{
statement.TryBind(paramName, artistId.ToByteArray());
statement.TryBind(paramName, artistId);
}
index++;
@@ -4046,7 +3871,7 @@ namespace Emby.Server.Implementations.Data
clauses.Add("(guid in (select itemid from itemvalues where CleanValue = (select CleanName from TypedBaseItems where guid=" + paramName + ") and Type=1))");
if (statement != null)
{
statement.TryBind(paramName, artistId.ToByteArray());
statement.TryBind(paramName, artistId);
}
index++;
@@ -4067,7 +3892,7 @@ namespace Emby.Server.Implementations.Data
clauses.Add("((select CleanName from TypedBaseItems where guid=" + paramName + ") in (select CleanValue from itemvalues where ItemId=Guid and Type=0) AND (select CleanName from TypedBaseItems where guid=" + paramName + ") not in (select CleanValue from itemvalues where ItemId=Guid and Type=1))");
if (statement != null)
{
statement.TryBind(paramName, artistId.ToByteArray());
statement.TryBind(paramName, artistId);
}
index++;
@@ -4088,7 +3913,7 @@ namespace Emby.Server.Implementations.Data
clauses.Add("Album in (select Name from typedbaseitems where guid=" + paramName + ")");
if (statement != null)
{
statement.TryBind(paramName, albumId.ToByteArray());
statement.TryBind(paramName, albumId);
}
index++;
@@ -4109,7 +3934,7 @@ namespace Emby.Server.Implementations.Data
clauses.Add("(guid not in (select itemid from itemvalues where CleanValue = (select CleanName from TypedBaseItems where guid=" + paramName + ") and Type<=1))");
if (statement != null)
{
statement.TryBind(paramName, artistId.ToByteArray());
statement.TryBind(paramName, artistId);
}
index++;
@@ -4130,7 +3955,7 @@ namespace Emby.Server.Implementations.Data
clauses.Add("(guid in (select itemid from itemvalues where CleanValue = (select CleanName from TypedBaseItems where guid=" + paramName + ") and Type=2))");
if (statement != null)
{
statement.TryBind(paramName, genreId.ToByteArray());
statement.TryBind(paramName, genreId);
}
index++;
@@ -4209,7 +4034,7 @@ namespace Emby.Server.Implementations.Data
if (statement != null)
{
statement.TryBind(paramName, studioId.ToByteArray());
statement.TryBind(paramName, studioId);
}
index++;
@@ -4494,7 +4319,7 @@ namespace Emby.Server.Implementations.Data
var index = 0;
foreach (var pair in query.ExcludeProviderIds)
{
if (string.Equals(pair.Key, MetadataProvider.TmdbCollection.ToString(), StringComparison.OrdinalIgnoreCase))
if (string.Equals(pair.Key, nameof(MetadataProvider.TmdbCollection), StringComparison.OrdinalIgnoreCase))
{
continue;
}
@@ -4524,7 +4349,7 @@ namespace Emby.Server.Implementations.Data
var index = 0;
foreach (var pair in query.HasAnyProviderId)
{
if (string.Equals(pair.Key, MetadataProvider.TmdbCollection.ToString(), StringComparison.OrdinalIgnoreCase))
if (string.Equals(pair.Key, nameof(MetadataProvider.TmdbCollection), StringComparison.OrdinalIgnoreCase))
{
continue;
}
@@ -4942,7 +4767,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
public void DeleteItem(Guid id)
{
if (id == Guid.Empty)
if (id.Equals(default))
{
throw new ArgumentNullException(nameof(id));
}
@@ -4954,7 +4779,8 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
connection.RunInTransaction(
db =>
{
var idBlob = id.ToByteArray();
Span<byte> idBlob = stackalloc byte[16];
id.TryWriteBytes(idBlob);
// Delete people
ExecuteWithSingleParam(db, "delete from People where ItemId=@Id", idBlob);
@@ -5003,7 +4829,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
if (whereClauses.Count != 0)
{
commandText.Append(" where ").Append(string.Join(" AND ", whereClauses));
commandText.Append(" where ").AppendJoin(" AND ", whereClauses);
}
commandText.Append(" order by ListOrder");
@@ -5089,16 +4915,16 @@ AND Type = @InternalPersonType)");
statement?.TryBind("@InternalPersonType", typeof(Person).FullName);
}
if (!query.ItemId.Equals(Guid.Empty))
if (!query.ItemId.Equals(default))
{
whereClauses.Add("ItemId=@ItemId");
statement?.TryBind("@ItemId", query.ItemId.ToByteArray());
statement?.TryBind("@ItemId", query.ItemId);
}
if (!query.AppearsInItemId.Equals(Guid.Empty))
if (!query.AppearsInItemId.Equals(default))
{
whereClauses.Add("p.Name in (Select Name from People where ItemId=@AppearsInItemId)");
statement?.TryBind("@AppearsInItemId", query.AppearsInItemId.ToByteArray());
statement?.TryBind("@AppearsInItemId", query.AppearsInItemId);
}
var queryPersonTypes = query.PersonTypes.Where(IsValidPersonType).ToList();
@@ -5151,7 +4977,7 @@ AND Type = @InternalPersonType)");
private void UpdateAncestors(Guid itemId, List<Guid> ancestorIds, IDatabaseConnection db, IStatement deleteAncestorsStatement)
{
if (itemId.Equals(Guid.Empty))
if (itemId.Equals(default))
{
throw new ArgumentNullException(nameof(itemId));
}
@@ -5599,6 +5425,7 @@ AND Type = @InternalPersonType)");
result.TotalRecordCount = list.Count;
}
result.StartIndex = query.StartIndex ?? 0;
result.Items = list;
return result;
@@ -5682,7 +5509,7 @@ AND Type = @InternalPersonType)");
private void UpdateItemValues(Guid itemId, List<(int MagicNumber, string Value)> values, IDatabaseConnection db)
{
if (itemId.Equals(Guid.Empty))
if (itemId.Equals(default))
{
throw new ArgumentNullException(nameof(itemId));
}
@@ -5758,7 +5585,7 @@ AND Type = @InternalPersonType)");
public void UpdatePeople(Guid itemId, List<PersonInfo> people)
{
if (itemId.Equals(Guid.Empty))
if (itemId.Equals(default))
{
throw new ArgumentNullException(nameof(itemId));
}
@@ -5891,7 +5718,7 @@ AND Type = @InternalPersonType)");
using (var statement = PrepareStatement(connection, cmdText))
{
statement.TryBind("@ItemId", query.ItemId.ToByteArray());
statement.TryBind("@ItemId", query.ItemId);
if (query.Type.HasValue)
{
@@ -5913,11 +5740,11 @@ AND Type = @InternalPersonType)");
}
}
public void SaveMediaStreams(Guid id, List<MediaStream> streams, CancellationToken cancellationToken)
public void SaveMediaStreams(Guid id, IReadOnlyList<MediaStream> streams, CancellationToken cancellationToken)
{
CheckDisposed();
if (id == Guid.Empty)
if (id.Equals(default))
{
throw new ArgumentNullException(nameof(id));
}
@@ -5945,7 +5772,7 @@ AND Type = @InternalPersonType)");
}
}
private void InsertMediaStreams(byte[] idBlob, List<MediaStream> streams, IDatabaseConnection db)
private void InsertMediaStreams(byte[] idBlob, IReadOnlyList<MediaStream> streams, IDatabaseConnection db)
{
const int Limit = 10;
var startIndex = 0;
@@ -6204,6 +6031,7 @@ AND Type = @InternalPersonType)");
item.LocalizedUndefined = _localization.GetLocalizedString("Undefined");
item.LocalizedDefault = _localization.GetLocalizedString("Default");
item.LocalizedForced = _localization.GetLocalizedString("Forced");
item.LocalizedExternal = _localization.GetLocalizedString("External");
}
return item;
@@ -6253,7 +6081,7 @@ AND Type = @InternalPersonType)");
CancellationToken cancellationToken)
{
CheckDisposed();
if (id == Guid.Empty)
if (id.Equals(default))
{
throw new ArgumentException("Guid can't be empty.", nameof(id));
}

View File

@@ -26,9 +26,6 @@ namespace Emby.Server.Implementations.Data
DbFilePath = Path.Combine(appPaths.DataPath, "library.db");
}
/// <inheritdoc />
public string Name => "SQLite";
/// <summary>
/// Opens the connection to the database.
/// </summary>
@@ -102,7 +99,7 @@ namespace Emby.Server.Implementations.Data
continue;
}
statement.TryBind("@UserId", user.Id.ToByteArray());
statement.TryBind("@UserId", user.Id);
statement.TryBind("@InternalUserId", user.InternalId);
statement.MoveNext();
@@ -390,6 +387,7 @@ namespace Emby.Server.Implementations.Data
return userData;
}
#pragma warning disable CA2215
/// <inheritdoc/>
/// <remarks>
/// There is nothing to dispose here since <see cref="BaseSqliteRepository.WriteLock"/> and
@@ -398,6 +396,10 @@ namespace Emby.Server.Implementations.Data
/// </remarks>
protected override void Dispose(bool dispose)
{
// The write lock and connection for the item repository are shared with the user data repository
// since they point to the same database. The item repo has responsibility for disposing these two objects,
// so the user data repo should not attempt to dispose them as well
}
#pragma warning restore CA2215
}
}

View File

@@ -21,7 +21,6 @@ using MediaBrowser.Controller.LiveTv;
using MediaBrowser.Controller.Persistence;
using MediaBrowser.Controller.Playlists;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Drawing;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Querying;
@@ -458,11 +457,6 @@ namespace Emby.Server.Implementations.Dto
}
}
private string GetDtoId(BaseItem item)
{
return item.Id.ToString("N", CultureInfo.InvariantCulture);
}
private void SetMusicVideoProperties(BaseItemDto dto, MusicVideo item)
{
if (!string.IsNullOrEmpty(item.Album))
@@ -584,7 +578,7 @@ namespace Emby.Server.Implementations.Dto
if (dictionary.TryGetValue(person.Name, out Person entity))
{
baseItemPerson.PrimaryImageTag = GetTagAndFillBlurhash(dto, entity, ImageType.Primary);
baseItemPerson.Id = entity.Id.ToString("N", CultureInfo.InvariantCulture);
baseItemPerson.Id = entity.Id;
if (dto.ImageBlurHashes != null)
{
// Only add BlurHash for the person's image.
@@ -743,8 +737,7 @@ namespace Emby.Server.Implementations.Dto
dto.Tags = item.Tags;
}
var hasAspectRatio = item as IHasAspectRatio;
if (hasAspectRatio != null)
if (item is IHasAspectRatio hasAspectRatio)
{
dto.AspectRatio = hasAspectRatio.AspectRatio;
}
@@ -894,15 +887,13 @@ namespace Emby.Server.Implementations.Dto
dto.CommunityRating = item.CommunityRating;
}
var supportsPlaceHolders = item as ISupportsPlaceHolders;
if (supportsPlaceHolders != null && supportsPlaceHolders.IsPlaceHolder)
if (item is ISupportsPlaceHolders supportsPlaceHolders && supportsPlaceHolders.IsPlaceHolder)
{
dto.IsPlaceHolder = supportsPlaceHolders.IsPlaceHolder;
}
// Add audio info
var audio = item as Audio;
if (audio != null)
if (item is Audio audio)
{
dto.Album = audio.Album;
if (audio.ExtraType.HasValue)
@@ -975,8 +966,7 @@ namespace Emby.Server.Implementations.Dto
}).Where(i => i != null).ToArray();
}
var hasAlbumArtist = item as IHasAlbumArtist;
if (hasAlbumArtist != null)
if (item is IHasAlbumArtist hasAlbumArtist)
{
dto.AlbumArtist = hasAlbumArtist.AlbumArtists.FirstOrDefault();
@@ -1102,12 +1092,13 @@ namespace Emby.Server.Implementations.Dto
if (options.ContainsField(ItemFields.LocalTrailerCount))
{
allExtras ??= item.GetExtras().ToArray();
dto.LocalTrailerCount = allExtras.Count(i => i.ExtraType == ExtraType.Trailer);
if (item is IHasTrailers hasTrailers)
{
dto.LocalTrailerCount += hasTrailers.GetTrailerCount();
dto.LocalTrailerCount = hasTrailers.GetTrailerCount();
}
else
{
dto.LocalTrailerCount = (allExtras ?? item.GetExtras()).Count(i => i.ExtraType == ExtraType.Trailer);
}
}
@@ -1317,35 +1308,35 @@ namespace Emby.Server.Implementations.Dto
var allImages = parent.ImageInfos;
if (logoLimit > 0 && !(imageTags != null && imageTags.ContainsKey(ImageType.Logo)) && dto.ParentLogoItemId == null)
if (logoLimit > 0 && !(imageTags != null && imageTags.ContainsKey(ImageType.Logo)) && dto.ParentLogoItemId is null)
{
var image = allImages.FirstOrDefault(i => i.Type == ImageType.Logo);
if (image != null)
{
dto.ParentLogoItemId = GetDtoId(parent);
dto.ParentLogoItemId = parent.Id;
dto.ParentLogoImageTag = GetTagAndFillBlurhash(dto, parent, image);
}
}
if (artLimit > 0 && !(imageTags != null && imageTags.ContainsKey(ImageType.Art)) && dto.ParentArtItemId == null)
if (artLimit > 0 && !(imageTags != null && imageTags.ContainsKey(ImageType.Art)) && dto.ParentArtItemId is null)
{
var image = allImages.FirstOrDefault(i => i.Type == ImageType.Art);
if (image != null)
{
dto.ParentArtItemId = GetDtoId(parent);
dto.ParentArtItemId = parent.Id;
dto.ParentArtImageTag = GetTagAndFillBlurhash(dto, parent, image);
}
}
if (thumbLimit > 0 && !(imageTags != null && imageTags.ContainsKey(ImageType.Thumb)) && (dto.ParentThumbItemId == null || parent is Series) && parent is not ICollectionFolder && parent is not UserView)
if (thumbLimit > 0 && !(imageTags != null && imageTags.ContainsKey(ImageType.Thumb)) && (dto.ParentThumbItemId is null || parent is Series) && parent is not ICollectionFolder && parent is not UserView)
{
var image = allImages.FirstOrDefault(i => i.Type == ImageType.Thumb);
if (image != null)
{
dto.ParentThumbItemId = GetDtoId(parent);
dto.ParentThumbItemId = parent.Id;
dto.ParentThumbImageTag = GetTagAndFillBlurhash(dto, parent, image);
}
}
@@ -1356,7 +1347,7 @@ namespace Emby.Server.Implementations.Dto
if (images.Count > 0)
{
dto.ParentBackdropItemId = GetDtoId(parent);
dto.ParentBackdropItemId = parent.Id;
dto.ParentBackdropImageTags = GetTagsAndFillBlurhashes(dto, parent, ImageType.Backdrop, images);
}
}

View File

@@ -24,14 +24,14 @@
<ItemGroup>
<PackageReference Include="DiscUtils.Udf" Version="0.16.13" />
<PackageReference Include="Jellyfin.XmlTv" Version="10.6.2" />
<PackageReference Include="Jellyfin.XmlTv" Version="10.8.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="6.0.1" />
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="6.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="6.0.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="6.0.4" />
<PackageReference Include="Mono.Nat" Version="3.0.2" />
<PackageReference Include="prometheus-net.DotNetRuntime" Version="4.2.2" />
<PackageReference Include="prometheus-net.DotNetRuntime" Version="4.2.3" />
<PackageReference Include="sharpcompress" Version="0.30.1" />
<PackageReference Include="SQLitePCL.pretty.netstandard" Version="3.1.0" />
<PackageReference Include="DotNet.Glob" Version="3.1.3" />
@@ -55,8 +55,12 @@
<!-- Code Analyzers-->
<ItemGroup Condition=" '$(Configuration)' == 'Debug' ">
<PackageReference Include="Microsoft.CodeAnalysis.BannedApiAnalyzers" Version="3.3.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
<PackageReference Include="SerilogAnalyzer" Version="0.15.0" PrivateAssets="All" />
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.376" PrivateAssets="All" />
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.406" PrivateAssets="All" />
<PackageReference Include="SmartAnalyzers.MultithreadingAnalyzer" Version="1.1.31" PrivateAssets="All" />
</ItemGroup>

View File

@@ -326,7 +326,7 @@ namespace Emby.Server.Implementations.EntryPoints
{
var userIds = _sessionManager.Sessions
.Select(i => i.UserId)
.Where(i => !i.Equals(Guid.Empty))
.Where(i => !i.Equals(default))
.Distinct()
.ToArray();

View File

@@ -3,6 +3,8 @@ using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;
using Emby.Server.Implementations.Udp;
using Jellyfin.Networking.Configuration;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Controller;
using MediaBrowser.Controller.Plugins;
using Microsoft.Extensions.Configuration;
@@ -26,6 +28,7 @@ namespace Emby.Server.Implementations.EntryPoints
private readonly ILogger<UdpServerEntryPoint> _logger;
private readonly IServerApplicationHost _appHost;
private readonly IConfiguration _config;
private readonly IConfigurationManager _configurationManager;
/// <summary>
/// The UDP server.
@@ -40,14 +43,17 @@ namespace Emby.Server.Implementations.EntryPoints
/// <param name="logger">Instance of the <see cref="ILogger{UdpServerEntryPoint}"/> interface.</param>
/// <param name="appHost">Instance of the <see cref="IServerApplicationHost"/> interface.</param>
/// <param name="configuration">Instance of the <see cref="IConfiguration"/> interface.</param>
/// <param name="configurationManager">Instance of the <see cref="IConfigurationManager"/> interface.</param>
public UdpServerEntryPoint(
ILogger<UdpServerEntryPoint> logger,
IServerApplicationHost appHost,
IConfiguration configuration)
IConfiguration configuration,
IConfigurationManager configurationManager)
{
_logger = logger;
_appHost = appHost;
_config = configuration;
_configurationManager = configurationManager;
}
/// <inheritdoc />
@@ -55,6 +61,11 @@ namespace Emby.Server.Implementations.EntryPoints
{
CheckDisposed();
if (!_configurationManager.GetNetworkConfiguration().AutoDiscovery)
{
return Task.CompletedTask;
}
try
{
_udpServer = new UdpServer(_logger, _appHost, _config, PortNumber);

View File

@@ -47,7 +47,9 @@ namespace Emby.Server.Implementations.HttpServer.Security
{
var session = await GetSession(requestContext).ConfigureAwait(false);
return session.UserId.Equals(Guid.Empty) ? null : _userManager.GetUserById(session.UserId);
return session.UserId.Equals(default)
? null
: _userManager.GetUserById(session.UserId);
}
public Task<User?> GetUser(object requestContext)

View File

@@ -581,7 +581,7 @@ namespace Emby.Server.Implementations.IO
}
/// <inheritdoc />
public virtual List<FileSystemMetadata> GetDrives()
public virtual IEnumerable<FileSystemMetadata> GetDrives()
{
// check for ready state to avoid waiting for drives to timeout
// some drives on linux have no actual size or are used for other purposes
@@ -595,7 +595,7 @@ namespace Emby.Server.Implementations.IO
Name = d.Name,
FullName = d.RootDirectory.FullName,
IsDirectory = true
}).ToList();
});
}
/// <inheritdoc />
@@ -704,6 +704,18 @@ namespace Emby.Server.Implementations.IO
return Directory.EnumerateFileSystemEntries(path, "*", GetEnumerationOptions(recursive));
}
/// <inheritdoc />
public virtual bool DirectoryExists(string path)
{
return Directory.Exists(path);
}
/// <inheritdoc />
public virtual bool FileExists(string path)
{
return File.Exists(path);
}
private EnumerationOptions GetEnumerationOptions(bool recursive)
{
return new EnumerationOptions

View File

@@ -135,7 +135,7 @@ namespace Emby.Server.Implementations.Images
protected virtual IEnumerable<string> GetStripCollageImagePaths(BaseItem primaryItem, IEnumerable<BaseItem> items)
{
var useBackdrop = primaryItem is CollectionFolder;
var useBackdrop = primaryItem is CollectionFolder || primaryItem is UserView;
return items
.Select(i =>
{

View File

@@ -22,7 +22,7 @@ namespace Emby.Server.Implementations.Images
{
private readonly ILibraryManager _libraryManager;
public BaseFolderImageProvider(IFileSystem fileSystem, IProviderManager providerManager, IApplicationPaths applicationPaths, IImageProcessor imageProcessor, ILibraryManager libraryManager)
protected BaseFolderImageProvider(IFileSystem fileSystem, IProviderManager providerManager, IApplicationPaths applicationPaths, IImageProcessor imageProcessor, ILibraryManager libraryManager)
: base(fileSystem, providerManager, applicationPaths, imageProcessor)
{
_libraryManager = libraryManager;

View File

@@ -42,6 +42,10 @@ namespace Emby.Server.Implementations.Images
{
includeItemTypes = new[] { BaseItemKind.MusicAlbum };
}
else if (string.Equals(viewType, CollectionType.MusicVideos, StringComparison.Ordinal))
{
includeItemTypes = new[] { BaseItemKind.MusicVideo };
}
else if (string.Equals(viewType, CollectionType.Books, StringComparison.Ordinal))
{
includeItemTypes = new[] { BaseItemKind.Book, BaseItemKind.AudioBook };

View File

@@ -84,16 +84,20 @@ namespace Emby.Server.Implementations.Images
}).GroupBy(x => x.Id)
.Select(x => x.First());
List<BaseItem> returnItems;
if (isUsingCollectionStrip)
{
return items
returnItems = items
.Where(i => i.HasImage(ImageType.Primary) || i.HasImage(ImageType.Thumb))
.ToList();
returnItems.Shuffle();
return returnItems;
}
return items
returnItems = items
.Where(i => i.HasImage(ImageType.Primary))
.ToList();
returnItems.Shuffle();
return returnItems;
}
protected override bool Supports(BaseItem item)

View File

@@ -45,8 +45,8 @@ using MediaBrowser.Model.IO;
using MediaBrowser.Model.Library;
using MediaBrowser.Model.Querying;
using MediaBrowser.Model.Tasks;
using MediaBrowser.Providers.MediaInfo;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Episode = MediaBrowser.Controller.Entities.TV.Episode;
using EpisodeInfo = Emby.Naming.TV.EpisodeInfo;
@@ -100,7 +100,7 @@ namespace Emby.Server.Implementations.Library
/// Initializes a new instance of the <see cref="LibraryManager" /> class.
/// </summary>
/// <param name="appHost">The application host.</param>
/// <param name="logger">The logger.</param>
/// <param name="loggerFactory">The logger factory.</param>
/// <param name="taskManager">The task manager.</param>
/// <param name="userManager">The user manager.</param>
/// <param name="configurationManager">The configuration manager.</param>
@@ -116,7 +116,7 @@ namespace Emby.Server.Implementations.Library
/// <param name="namingOptions">The naming options.</param>
public LibraryManager(
IServerApplicationHost appHost,
ILogger<LibraryManager> logger,
ILoggerFactory loggerFactory,
ITaskManager taskManager,
IUserManager userManager,
IServerConfigurationManager configurationManager,
@@ -132,7 +132,7 @@ namespace Emby.Server.Implementations.Library
NamingOptions namingOptions)
{
_appHost = appHost;
_logger = logger;
_logger = loggerFactory.CreateLogger<LibraryManager>();
_taskManager = taskManager;
_userManager = userManager;
_configurationManager = configurationManager;
@@ -147,7 +147,7 @@ namespace Emby.Server.Implementations.Library
_memoryCache = memoryCache;
_namingOptions = namingOptions;
_extraResolver = new ExtraResolver(namingOptions);
_extraResolver = new ExtraResolver(loggerFactory.CreateLogger<ExtraResolver>(), namingOptions);
_configurationManager.ConfigurationUpdated += ConfigurationUpdated;
@@ -680,9 +680,7 @@ namespace Emby.Server.Implementations.Library
if (result?.Items.Count > 0)
{
var items = new List<BaseItem>();
items.AddRange(result.Items);
var items = result.Items;
foreach (var item in items)
{
ResolverHelper.SetInitialItemValues(item, parent, this, directoryService);
@@ -758,7 +756,7 @@ namespace Emby.Server.Implementations.Library
Path = path
};
if (folder.Id.Equals(Guid.Empty))
if (folder.Id.Equals(default))
{
if (string.IsNullOrEmpty(folder.Path))
{
@@ -777,7 +775,7 @@ namespace Emby.Server.Implementations.Library
folder = dbItem;
}
if (folder.ParentId != rootFolder.Id)
if (!folder.ParentId.Equals(rootFolder.Id))
{
folder.ParentId = rootFolder.Id;
folder.UpdateToRepositoryAsync(ItemUpdateType.MetadataImport, CancellationToken.None).GetAwaiter().GetResult();
@@ -1007,14 +1005,8 @@ namespace Emby.Server.Implementations.Library
return GetNewItemIdInternal(path, typeof(T), forceCaseInsensitiveId);
}
/// <summary>
/// Validate and refresh the People sub-set of the IBN.
/// The items are stored in the db but not loaded into memory until actually requested by an operation.
/// </summary>
/// <param name="cancellationToken">The cancellation token.</param>
/// <param name="progress">The progress.</param>
/// <returns>Task.</returns>
public Task ValidatePeople(CancellationToken cancellationToken, IProgress<double> progress)
/// <inheritdoc />
public Task ValidatePeopleAsync(IProgress<double> progress, CancellationToken cancellationToken)
{
// Ensure the location is available.
Directory.CreateDirectory(_configurationManager.ApplicationPaths.PeoplePath);
@@ -1036,15 +1028,6 @@ namespace Emby.Server.Implementations.Library
return Task.CompletedTask;
}
/// <summary>
/// Queues the library scan.
/// </summary>
public void QueueLibraryScan()
{
// Just run the scheduled task so that the user can see it
_taskManager.QueueScheduledTask<RefreshMediaLibraryTask>();
}
/// <summary>
/// Validates the media library internal.
/// </summary>
@@ -1270,7 +1253,7 @@ namespace Emby.Server.Implementations.Library
/// <exception cref="ArgumentNullException"><paramref name="id"/> is <c>null</c>.</exception>
public BaseItem GetItemById(Guid id)
{
if (id == Guid.Empty)
if (id.Equals(default))
{
throw new ArgumentException("Guid can't be empty", nameof(id));
}
@@ -1292,7 +1275,7 @@ namespace Emby.Server.Implementations.Library
public List<BaseItem> GetItemList(InternalItemsQuery query, bool allowExternalContent)
{
if (query.Recursive && query.ParentId != Guid.Empty)
if (query.Recursive && !query.ParentId.Equals(default))
{
var parent = GetItemById(query.ParentId);
if (parent != null)
@@ -1316,7 +1299,7 @@ namespace Emby.Server.Implementations.Library
public int GetCount(InternalItemsQuery query)
{
if (query.Recursive && !query.ParentId.Equals(Guid.Empty))
if (query.Recursive && !query.ParentId.Equals(default))
{
var parent = GetItemById(query.ParentId);
if (parent != null)
@@ -1360,10 +1343,10 @@ namespace Emby.Server.Implementations.Library
return _itemRepository.GetItems(query);
}
return new QueryResult<BaseItem>
{
Items = _itemRepository.GetItemList(query)
};
return new QueryResult<BaseItem>(
query.StartIndex,
null,
_itemRepository.GetItemList(query));
}
public List<Guid> GetItemIds(InternalItemsQuery query)
@@ -1444,7 +1427,7 @@ namespace Emby.Server.Implementations.Library
for (int i = 0; i < len; i++)
{
parents[i] = GetItemById(ancestorIds[i]);
if (!(parents[i] is ICollectionFolder || parents[i] is UserView))
if (parents[i] is not (ICollectionFolder or UserView))
{
return;
}
@@ -1474,7 +1457,7 @@ namespace Emby.Server.Implementations.Library
public QueryResult<BaseItem> GetItemsResult(InternalItemsQuery query)
{
if (query.Recursive && !query.ParentId.Equals(Guid.Empty))
if (query.Recursive && !query.ParentId.Equals(default))
{
var parent = GetItemById(query.ParentId);
if (parent != null)
@@ -1493,10 +1476,10 @@ namespace Emby.Server.Implementations.Library
return _itemRepository.GetItems(query);
}
return new QueryResult<BaseItem>
{
Items = _itemRepository.GetItemList(query)
};
return new QueryResult<BaseItem>(
query.StartIndex,
null,
_itemRepository.GetItemList(query));
}
private void SetTopParentIdsOrAncestors(InternalItemsQuery query, List<BaseItem> parents)
@@ -1530,7 +1513,7 @@ namespace Emby.Server.Implementations.Library
private void AddUserToQuery(InternalItemsQuery query, User user, bool allowExternalContent = true)
{
if (query.AncestorIds.Length == 0 &&
query.ParentId.Equals(Guid.Empty) &&
query.ParentId.Equals(default) &&
query.ChannelIds.Count == 0 &&
query.TopParentIds.Length == 0 &&
string.IsNullOrEmpty(query.AncestorWithPresentationUniqueKey) &&
@@ -1558,7 +1541,7 @@ namespace Emby.Server.Implementations.Library
}
// Translate view into folders
if (!view.DisplayParentId.Equals(Guid.Empty))
if (!view.DisplayParentId.Equals(default))
{
var displayParent = GetItemById(view.DisplayParentId);
if (displayParent != null)
@@ -1569,7 +1552,7 @@ namespace Emby.Server.Implementations.Library
return Array.Empty<Guid>();
}
if (!view.ParentId.Equals(Guid.Empty))
if (!view.ParentId.Equals(default))
{
var displayParent = GetItemById(view.ParentId);
if (displayParent != null)
@@ -1650,27 +1633,6 @@ namespace Emby.Server.Implementations.Library
}
}
/// <summary>
/// Gets all intro files.
/// </summary>
/// <returns>IEnumerable{System.String}.</returns>
public IEnumerable<string> GetAllIntroFiles()
{
return IntroProviders.SelectMany(i =>
{
try
{
return i.GetAllIntroFiles().ToList();
}
catch (Exception ex)
{
_logger.LogError(ex, "Error getting intro files");
return new List<string>();
}
});
}
/// <summary>
/// Resolves the intro.
/// </summary>
@@ -2014,16 +1976,16 @@ namespace Emby.Server.Implementations.Library
public Task UpdateItemAsync(BaseItem item, BaseItem parent, ItemUpdateType updateReason, CancellationToken cancellationToken)
=> UpdateItemsAsync(new[] { item }, parent, updateReason, cancellationToken);
public Task RunMetadataSavers(BaseItem item, ItemUpdateType updateReason)
public async Task RunMetadataSavers(BaseItem item, ItemUpdateType updateReason)
{
if (item.IsFileProtocol)
{
ProviderManager.SaveMetadata(item, updateReason);
await ProviderManager.SaveMetadataAsync(item, updateReason).ConfigureAwait(false);
}
item.DateLastSaved = DateTime.UtcNow;
return UpdateImagesAsync(item, updateReason >= ItemUpdateType.ImageUpdate);
await UpdateImagesAsync(item, updateReason >= ItemUpdateType.ImageUpdate).ConfigureAwait(false);
}
/// <summary>
@@ -2192,7 +2154,7 @@ namespace Emby.Server.Implementations.Library
return null;
}
while (!item.ParentId.Equals(Guid.Empty))
while (!item.ParentId.Equals(default))
{
var parent = item.GetParent();
if (parent == null || parent is AggregateFolder)
@@ -2270,7 +2232,9 @@ namespace Emby.Server.Implementations.Library
string viewType,
string sortName)
{
var parentIdString = parentId.Equals(Guid.Empty) ? null : parentId.ToString("N", CultureInfo.InvariantCulture);
var parentIdString = parentId.Equals(default)
? null
: parentId.ToString("N", CultureInfo.InvariantCulture);
var idValues = "38_namedview_" + name + user.Id.ToString("N", CultureInfo.InvariantCulture) + (parentIdString ?? string.Empty) + (viewType ?? string.Empty);
var id = GetNewItemId(idValues, typeof(UserView));
@@ -2304,7 +2268,7 @@ namespace Emby.Server.Implementations.Library
var refresh = isNew || DateTime.UtcNow - item.DateLastRefreshed >= _viewRefreshInterval;
if (!refresh && !item.DisplayParentId.Equals(Guid.Empty))
if (!refresh && !item.DisplayParentId.Equals(default))
{
var displayParent = GetItemById(item.DisplayParentId);
refresh = displayParent != null && displayParent.DateLastSaved > item.DateLastRefreshed;
@@ -2371,7 +2335,7 @@ namespace Emby.Server.Implementations.Library
var refresh = isNew || DateTime.UtcNow - item.DateLastRefreshed >= _viewRefreshInterval;
if (!refresh && !item.DisplayParentId.Equals(Guid.Empty))
if (!refresh && !item.DisplayParentId.Equals(default))
{
var displayParent = GetItemById(item.DisplayParentId);
refresh = displayParent != null && displayParent.DateLastSaved > item.DateLastRefreshed;
@@ -2404,7 +2368,9 @@ namespace Emby.Server.Implementations.Library
throw new ArgumentNullException(nameof(name));
}
var parentIdString = parentId.Equals(Guid.Empty) ? null : parentId.ToString("N", CultureInfo.InvariantCulture);
var parentIdString = parentId.Equals(default)
? null
: parentId.ToString("N", CultureInfo.InvariantCulture);
var idValues = "37_namedview_" + name + (parentIdString ?? string.Empty) + (viewType ?? string.Empty);
if (!string.IsNullOrEmpty(uniqueId))
{
@@ -2448,7 +2414,7 @@ namespace Emby.Server.Implementations.Library
var refresh = isNew || DateTime.UtcNow - item.DateLastRefreshed >= _viewRefreshInterval;
if (!refresh && !item.DisplayParentId.Equals(Guid.Empty))
if (!refresh && !item.DisplayParentId.Equals(default))
{
var displayParent = GetItemById(item.DisplayParentId);
refresh = displayParent != null && displayParent.DateLastSaved > item.DateLastRefreshed;
@@ -2469,24 +2435,6 @@ namespace Emby.Server.Implementations.Library
return item;
}
public void AddExternalSubtitleStreams(
List<MediaStream> streams,
string videoPath,
string[] files)
{
new SubtitleResolver(BaseItem.LocalizationManager).AddExternalSubtitleStreams(streams, videoPath, streams.Count, files);
}
public BaseItem GetParentItem(string parentId, Guid? userId)
{
if (string.IsNullOrEmpty(parentId))
{
return GetParentItem((Guid?)null, userId);
}
return GetParentItem(new Guid(parentId), userId);
}
public BaseItem GetParentItem(Guid? parentId, Guid? userId)
{
if (parentId.HasValue)
@@ -2494,7 +2442,7 @@ namespace Emby.Server.Implementations.Library
return GetItemById(parentId.Value);
}
if (userId.HasValue && userId != Guid.Empty)
if (userId.HasValue && !userId.Equals(default))
{
return GetUserRootFolder();
}
@@ -2686,7 +2634,7 @@ namespace Emby.Server.Implementations.Library
};
}
public IEnumerable<BaseItem> FindExtras(BaseItem owner, List<FileSystemMetadata> fileSystemChildren, IDirectoryService directoryService)
public IEnumerable<BaseItem> FindExtras(BaseItem owner, IReadOnlyList<FileSystemMetadata> fileSystemChildren, IDirectoryService directoryService)
{
var ownerVideoInfo = VideoResolver.Resolve(owner.Path, owner.IsFolder, _namingOptions);
if (ownerVideoInfo == null)
@@ -2784,16 +2732,6 @@ namespace Emby.Server.Implementations.Library
return path;
}
public string SubstitutePath(string path, string from, string to)
{
if (path.TryReplaceSubPath(from, to, out var newPath))
{
return newPath;
}
return path;
}
public List<PersonInfo> GetPeople(InternalPeopleQuery query)
{
return _itemRepository.GetPeople(query);
@@ -2902,10 +2840,12 @@ namespace Emby.Server.Implementations.Library
var existingNameCount = 1; // first numbered name will be 2
var virtualFolderPath = Path.Combine(rootFolderPath, name);
var originalName = name;
while (Directory.Exists(virtualFolderPath))
{
existingNameCount++;
virtualFolderPath = Path.Combine(rootFolderPath, name + " " + existingNameCount);
name = originalName + existingNameCount;
virtualFolderPath = Path.Combine(rootFolderPath, name);
}
var mediaPathInfos = options.PathInfos;
@@ -3007,7 +2947,10 @@ namespace Emby.Server.Implementations.Library
}
}
CreateItems(personsToSave, null, CancellationToken.None);
if (personsToSave.Count > 0)
{
CreateItems(personsToSave, null, CancellationToken.None);
}
}
private void StartScanInBackground()

View File

@@ -172,24 +172,16 @@ namespace Emby.Server.Implementations.Library
foreach (var source in dynamicMediaSources)
{
if (user != null)
{
SetDefaultAudioAndSubtitleStreamIndexes(item, source, user);
}
// Validate that this is actually possible
if (source.SupportsDirectStream)
{
source.SupportsDirectStream = SupportsDirectStream(source.Path, source.Protocol);
}
list.Add(source);
}
if (user != null)
{
foreach (var source in list)
if (user != null)
{
SetDefaultAudioAndSubtitleStreamIndexes(item, source, user);
if (string.Equals(item.MediaType, MediaType.Audio, StringComparison.OrdinalIgnoreCase))
{
source.SupportsTranscoding = user.HasPermission(PermissionKind.EnableAudioPlaybackTranscoding);
@@ -200,6 +192,8 @@ namespace Emby.Server.Implementations.Library
source.SupportsDirectStream = user.HasPermission(PermissionKind.EnablePlaybackRemuxing);
}
}
list.Add(source);
}
return SortMediaSources(list);
@@ -338,13 +332,23 @@ namespace Emby.Server.Implementations.Library
foreach (var source in sources)
{
SetDefaultAudioAndSubtitleStreamIndexes(item, source, user);
if (string.Equals(item.MediaType, MediaType.Audio, StringComparison.OrdinalIgnoreCase))
{
source.SupportsTranscoding = user.HasPermission(PermissionKind.EnableAudioPlaybackTranscoding);
}
else if (string.Equals(item.MediaType, MediaType.Video, StringComparison.OrdinalIgnoreCase))
{
source.SupportsTranscoding = user.HasPermission(PermissionKind.EnableVideoPlaybackTranscoding);
source.SupportsDirectStream = user.HasPermission(PermissionKind.EnablePlaybackRemuxing);
}
}
}
return sources;
}
private string[] NormalizeLanguage(string language)
private IReadOnlyList<string> NormalizeLanguage(string language)
{
if (string.IsNullOrEmpty(language))
{
@@ -514,10 +518,10 @@ namespace Emby.Server.Implementations.Library
_logger.LogInformation("Live stream opened: {@MediaSource}", mediaSource);
var clone = JsonSerializer.Deserialize<MediaSourceInfo>(json, _jsonOptions);
if (!request.UserId.Equals(Guid.Empty))
if (!request.UserId.Equals(default))
{
var user = _userManager.GetUserById(request.UserId);
var item = request.ItemId.Equals(Guid.Empty)
var item = request.ItemId.Equals(default)
? null
: _libraryManager.GetItemById(request.ItemId);
SetDefaultAudioAndSubtitleStreamIndexes(item, clone, user);

View File

@@ -1,5 +1,3 @@
#nullable disable
#pragma warning disable CS1591
using System;
@@ -13,10 +11,9 @@ namespace Emby.Server.Implementations.Library
{
public static class MediaStreamSelector
{
public static int? GetDefaultAudioStreamIndex(List<MediaStream> streams, string[] preferredLanguages, bool preferDefaultTrack)
public static int? GetDefaultAudioStreamIndex(IReadOnlyList<MediaStream> streams, IReadOnlyList<string> preferredLanguages, bool preferDefaultTrack)
{
streams = GetSortedStreams(streams, MediaStreamType.Audio, preferredLanguages)
.ToList();
var sortedStreams = GetSortedStreams(streams, MediaStreamType.Audio, preferredLanguages);
if (preferDefaultTrack)
{
@@ -28,24 +25,15 @@ namespace Emby.Server.Implementations.Library
}
}
var stream = streams.FirstOrDefault();
if (stream != null)
{
return stream.Index;
}
return null;
return sortedStreams.FirstOrDefault()?.Index;
}
public static int? GetDefaultSubtitleStreamIndex(
IEnumerable<MediaStream> streams,
string[] preferredLanguages,
IReadOnlyList<string> preferredLanguages,
SubtitlePlaybackMode mode,
string audioTrackLanguage)
{
MediaStream stream = null;
if (mode == SubtitlePlaybackMode.None)
{
return null;
@@ -59,6 +47,7 @@ namespace Emby.Server.Implementations.Library
.ThenByDescending(x => x.IsDefault)
.ToList();
MediaStream? stream = null;
if (mode == SubtitlePlaybackMode.Default)
{
// Prefer embedded metadata over smart logic
@@ -95,26 +84,27 @@ namespace Emby.Server.Implementations.Library
return stream?.Index;
}
private static IEnumerable<MediaStream> GetSortedStreams(IEnumerable<MediaStream> streams, MediaStreamType type, string[] languagePreferences)
private static IEnumerable<MediaStream> GetSortedStreams(IEnumerable<MediaStream> streams, MediaStreamType type, IReadOnlyList<string> languagePreferences)
{
// Give some preference to external text subs for better performance
return streams.Where(i => i.Type == type)
return streams
.Where(i => i.Type == type)
.OrderBy(i =>
{
var index = FindIndex(languagePreferences, i.Language);
{
var index = languagePreferences.FindIndex(x => string.Equals(x, i.Language, StringComparison.OrdinalIgnoreCase));
return index == -1 ? 100 : index;
})
.ThenBy(i => GetBooleanOrderBy(i.IsDefault))
.ThenBy(i => GetBooleanOrderBy(i.SupportsExternalStream))
.ThenBy(i => GetBooleanOrderBy(i.IsTextSubtitleStream))
.ThenBy(i => GetBooleanOrderBy(i.IsExternal))
.ThenBy(i => i.Index);
return index == -1 ? 100 : index;
})
.ThenBy(i => GetBooleanOrderBy(i.IsDefault))
.ThenBy(i => GetBooleanOrderBy(i.SupportsExternalStream))
.ThenBy(i => GetBooleanOrderBy(i.IsTextSubtitleStream))
.ThenBy(i => GetBooleanOrderBy(i.IsExternal))
.ThenBy(i => i.Index);
}
public static void SetSubtitleStreamScores(
List<MediaStream> streams,
string[] preferredLanguages,
IReadOnlyList<MediaStream> streams,
IReadOnlyList<string> preferredLanguages,
SubtitlePlaybackMode mode,
string audioTrackLanguage)
{
@@ -123,15 +113,14 @@ namespace Emby.Server.Implementations.Library
return;
}
streams = GetSortedStreams(streams, MediaStreamType.Subtitle, preferredLanguages)
.ToList();
var sortedStreams = GetSortedStreams(streams, MediaStreamType.Subtitle, preferredLanguages);
var filteredStreams = new List<MediaStream>();
if (mode == SubtitlePlaybackMode.Default)
{
// Prefer embedded metadata over smart logic
filteredStreams = streams.Where(s => s.IsForced || s.IsDefault)
filteredStreams = sortedStreams.Where(s => s.IsForced || s.IsDefault)
.ToList();
}
else if (mode == SubtitlePlaybackMode.Smart)
@@ -139,54 +128,37 @@ namespace Emby.Server.Implementations.Library
// Prefer smart logic over embedded metadata
if (!preferredLanguages.Contains(audioTrackLanguage, StringComparison.OrdinalIgnoreCase))
{
filteredStreams = streams.Where(s => !s.IsForced && preferredLanguages.Contains(s.Language, StringComparison.OrdinalIgnoreCase))
filteredStreams = sortedStreams.Where(s => !s.IsForced && preferredLanguages.Contains(s.Language, StringComparison.OrdinalIgnoreCase))
.ToList();
}
}
else if (mode == SubtitlePlaybackMode.Always)
{
// always load the most suitable full subtitles
filteredStreams = streams.Where(s => !s.IsForced)
.ToList();
filteredStreams = sortedStreams.Where(s => !s.IsForced).ToList();
}
else if (mode == SubtitlePlaybackMode.OnlyForced)
{
// always load the most suitable full subtitles
filteredStreams = streams.Where(s => s.IsForced).ToList();
filteredStreams = sortedStreams.Where(s => s.IsForced).ToList();
}
// load forced subs if we have found no suitable full subtitles
if (filteredStreams.Count == 0)
{
filteredStreams = streams
.Where(s => s.IsForced && string.Equals(s.Language, audioTrackLanguage, StringComparison.OrdinalIgnoreCase))
.ToList();
}
var iterStreams = filteredStreams.Count == 0
? sortedStreams.Where(s => s.IsForced && string.Equals(s.Language, audioTrackLanguage, StringComparison.OrdinalIgnoreCase))
: filteredStreams;
foreach (var stream in filteredStreams)
foreach (var stream in iterStreams)
{
stream.Score = GetSubtitleScore(stream, preferredLanguages);
}
}
private static int FindIndex(string[] list, string value)
{
for (var i = 0; i < list.Length; i++)
{
if (string.Equals(list[i], value, StringComparison.OrdinalIgnoreCase))
{
return i;
}
}
return -1;
}
private static int GetSubtitleScore(MediaStream stream, string[] languagePreferences)
private static int GetSubtitleScore(MediaStream stream, IReadOnlyList<string> languagePreferences)
{
var values = new List<int>();
var index = FindIndex(languagePreferences, stream.Language);
var index = languagePreferences.FindIndex(x => string.Equals(x, stream.Language, StringComparison.OrdinalIgnoreCase));
values.Add(index == -1 ? 0 : 100 - index);

View File

@@ -80,7 +80,7 @@ namespace Emby.Server.Implementations.Library
{
return Guid.Empty;
}
}).Where(i => !i.Equals(Guid.Empty)).ToArray();
}).Where(i => !i.Equals(default)).ToArray();
return GetInstantMixFromGenreIds(genreIds, user, dtoOptions);
}

View File

@@ -12,6 +12,7 @@ using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities;
using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.Library.Resolvers
{
@@ -22,8 +23,11 @@ namespace Emby.Server.Implementations.Library.Resolvers
public abstract class BaseVideoResolver<T> : MediaBrowser.Controller.Resolvers.ItemResolver<T>
where T : Video, new()
{
protected BaseVideoResolver(NamingOptions namingOptions)
private readonly ILogger _logger;
protected BaseVideoResolver(ILogger logger, NamingOptions namingOptions)
{
_logger = logger;
NamingOptions = namingOptions;
}
@@ -156,19 +160,26 @@ namespace Emby.Server.Implementations.Library.Resolvers
}
else
{
// use disc-utils, both DVDs and BDs use UDF filesystem
using (var videoFileStream = File.Open(video.Path, FileMode.Open, FileAccess.Read))
using (UdfReader udfReader = new UdfReader(videoFileStream))
try
{
if (udfReader.DirectoryExists("VIDEO_TS"))
// use disc-utils, both DVDs and BDs use UDF filesystem
using (var videoFileStream = File.Open(video.Path, FileMode.Open, FileAccess.Read))
using (UdfReader udfReader = new UdfReader(videoFileStream))
{
video.IsoType = IsoType.Dvd;
}
else if (udfReader.DirectoryExists("BDMV"))
{
video.IsoType = IsoType.BluRay;
if (udfReader.DirectoryExists("VIDEO_TS"))
{
video.IsoType = IsoType.Dvd;
}
else if (udfReader.DirectoryExists("BDMV"))
{
video.IsoType = IsoType.BluRay;
}
}
}
catch (Exception ex)
{
_logger.LogError(ex, "Error opening UDF/ISO image: {Value}", video.Path ?? video.Name);
}
}
}
}

View File

@@ -6,6 +6,7 @@ using Emby.Naming.Video;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Resolvers;
using MediaBrowser.Model.Entities;
using Microsoft.Extensions.Logging;
using static Emby.Naming.Video.ExtraRuleResolver;
namespace Emby.Server.Implementations.Library.Resolvers
@@ -20,14 +21,15 @@ namespace Emby.Server.Implementations.Library.Resolvers
private readonly IItemResolver[] _videoResolvers;
/// <summary>
/// Initializes an new instance of the <see cref="ExtraResolver"/> class.
/// Initializes a new instance of the <see cref="ExtraResolver"/> class.
/// </summary>
/// <param name="logger">The logger.</param>
/// <param name="namingOptions">An instance of <see cref="NamingOptions"/>.</param>
public ExtraResolver(NamingOptions namingOptions)
public ExtraResolver(ILogger<ExtraResolver> logger, NamingOptions namingOptions)
{
_namingOptions = namingOptions;
_trailerResolvers = new IItemResolver[] { new GenericVideoResolver<Trailer>(namingOptions) };
_videoResolvers = new IItemResolver[] { new GenericVideoResolver<Video>(namingOptions) };
_trailerResolvers = new IItemResolver[] { new GenericVideoResolver<Trailer>(logger, namingOptions) };
_videoResolvers = new IItemResolver[] { new GenericVideoResolver<Video>(logger, namingOptions) };
}
/// <summary>

View File

@@ -1,7 +1,8 @@
#nullable disable
#nullable disable
using Emby.Naming.Common;
using MediaBrowser.Controller.Entities;
using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.Library.Resolvers
{
@@ -15,9 +16,10 @@ namespace Emby.Server.Implementations.Library.Resolvers
/// <summary>
/// Initializes a new instance of the <see cref="GenericVideoResolver{T}"/> class.
/// </summary>
/// <param name="logger">The logger.</param>
/// <param name="namingOptions">The naming options.</param>
public GenericVideoResolver(NamingOptions namingOptions)
: base(namingOptions)
public GenericVideoResolver(ILogger logger, NamingOptions namingOptions)
: base(logger, namingOptions)
{
}
}

View File

@@ -17,6 +17,7 @@ using MediaBrowser.Controller.Providers;
using MediaBrowser.Controller.Resolvers;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.IO;
using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.Library.Resolvers.Movies
{
@@ -32,7 +33,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
CollectionType.Movies,
CollectionType.HomeVideos,
CollectionType.MusicVideos,
CollectionType.Movies,
CollectionType.TvShows,
CollectionType.Photos
};
@@ -40,9 +41,10 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
/// Initializes a new instance of the <see cref="MovieResolver"/> class.
/// </summary>
/// <param name="imageProcessor">The image processor.</param>
/// <param name="logger">The logger.</param>
/// <param name="namingOptions">The naming options.</param>
public MovieResolver(IImageProcessor imageProcessor, NamingOptions namingOptions)
: base(namingOptions)
public MovieResolver(IImageProcessor imageProcessor, ILogger<MovieResolver> logger, NamingOptions namingOptions)
: base(logger, namingOptions)
{
_imageProcessor = imageProcessor;
}
@@ -128,10 +130,9 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
return movie?.ExtraType == null ? movie : null;
}
// Owned items will be caught by the video extra resolver
if (args.Parent == null)
{
return null;
return base.Resolve(args);
}
if (IsInvalid(args.Parent, collectionType))
@@ -222,6 +223,11 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
return ResolveVideos<Movie>(parent, files, true, collectionType, true);
}
if (string.Equals(collectionType, CollectionType.TvShows, StringComparison.OrdinalIgnoreCase))
{
return ResolveVideos<Episode>(parent, files, true, collectionType, true);
}
return null;
}

View File

@@ -6,6 +6,7 @@ using Emby.Naming.Common;
using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Library;
using MediaBrowser.Model.Entities;
using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.Library.Resolvers.TV
{
@@ -17,9 +18,10 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV
/// <summary>
/// Initializes a new instance of the <see cref="EpisodeResolver"/> class.
/// </summary>
/// <param name="logger">The logger.</param>
/// <param name="namingOptions">The naming options.</param>
public EpisodeResolver(NamingOptions namingOptions)
: base(namingOptions)
public EpisodeResolver(ILogger<EpisodeResolver> logger, NamingOptions namingOptions)
: base(logger, namingOptions)
{
}

View File

@@ -30,7 +30,7 @@ namespace Emby.Server.Implementations.Library
public QueryResult<SearchHintInfo> GetSearchHints(SearchQuery query)
{
User user = null;
if (query.UserId != Guid.Empty)
if (!query.UserId.Equals(default))
{
user = _userManager.GetUserById(query.UserId);
}
@@ -48,12 +48,10 @@ namespace Emby.Server.Implementations.Library
results = results.GetRange(0, Math.Min(query.Limit.Value, results.Count));
}
return new QueryResult<SearchHintInfo>
{
TotalRecordCount = totalRecordCount,
Items = results
};
return new QueryResult<SearchHintInfo>(
query.StartIndex,
totalRecordCount,
results);
}
private static void AddIfMissing(List<BaseItemKind> list, BaseItemKind value)
@@ -170,10 +168,10 @@ namespace Emby.Server.Implementations.Library
{
Fields = new ItemFields[]
{
ItemFields.AirTime,
ItemFields.DateCreated,
ItemFields.ChannelInfo,
ItemFields.ParentId
ItemFields.AirTime,
ItemFields.DateCreated,
ItemFields.ChannelInfo,
ItemFields.ParentId
}
}
};
@@ -182,12 +180,12 @@ namespace Emby.Server.Implementations.Library
if (searchQuery.IncludeItemTypes.Length == 1 && searchQuery.IncludeItemTypes[0] == BaseItemKind.MusicArtist)
{
if (!searchQuery.ParentId.Equals(Guid.Empty))
if (!searchQuery.ParentId.Equals(default))
{
searchQuery.AncestorIds = new[] { searchQuery.ParentId };
searchQuery.ParentId = Guid.Empty;
}
searchQuery.ParentId = Guid.Empty;
searchQuery.IncludeItemsByName = true;
searchQuery.IncludeItemTypes = Array.Empty<BaseItemKind>();
mediaItems = _libraryManager.GetAllArtists(searchQuery).Items.Select(i => i.Item).ToList();

View File

@@ -0,0 +1,79 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Jellyfin.Data.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;
/// <summary>
/// The splashscreen post scan task.
/// </summary>
public class SplashscreenPostScanTask : ILibraryPostScanTask
{
private readonly IItemRepository _itemRepository;
private readonly IImageEncoder _imageEncoder;
private readonly ILogger<SplashscreenPostScanTask> _logger;
/// <summary>
/// Initializes a new instance of the <see cref="SplashscreenPostScanTask"/> class.
/// </summary>
/// <param name="itemRepository">Instance of the <see cref="IItemRepository"/> interface.</param>
/// <param name="imageEncoder">Instance of the <see cref="IImageEncoder"/> interface.</param>
/// <param name="logger">Instance of the <see cref="ILogger{SplashscreenPostScanTask}"/> interface.</param>
public SplashscreenPostScanTask(
IItemRepository itemRepository,
IImageEncoder imageEncoder,
ILogger<SplashscreenPostScanTask> logger)
{
_itemRepository = itemRepository;
_imageEncoder = imageEncoder;
_logger = logger;
}
/// <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();
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();
}
_imageEncoder.CreateSplashscreen(posters, backdrops);
return Task.CompletedTask;
}
private IReadOnlyList<BaseItem> GetItemsWithImageType(ImageType imageType)
{
// TODO make included libraries configurable
return _itemRepository.GetItemList(new InternalItemsQuery
{
CollapseBoxSetItems = false,
Recursive = true,
DtoOptions = new DtoOptions(false),
ImageTypes = new[] { imageType },
Limit = 30,
// TODO max parental rating configurable
MaxParentalRating = 10,
OrderBy = new[]
{
(ItemSortBy.Random, SortOrder.Ascending)
},
IncludeItemTypes = new[] { BaseItemKind.Movie, BaseItemKind.Series }
});
}
}

View File

@@ -142,7 +142,7 @@ namespace Emby.Server.Implementations.Library
if (index == -1
&& i is UserView view
&& view.DisplayParentId != Guid.Empty)
&& !view.DisplayParentId.Equals(default))
{
index = Array.IndexOf(orders, view.DisplayParentId);
}
@@ -214,7 +214,7 @@ namespace Emby.Server.Implementations.Library
}
else
{
var current = list.FirstOrDefault(i => i.Item1 != null && i.Item1.Id == container.Id);
var current = list.FirstOrDefault(i => i.Item1 != null && i.Item1.Id.Equals(container.Id));
if (current != null)
{
@@ -244,7 +244,7 @@ namespace Emby.Server.Implementations.Library
var parents = new List<BaseItem>();
if (!parentId.Equals(Guid.Empty))
if (!parentId.Equals(default))
{
var parentItem = _libraryManager.GetItemById(parentId);
if (parentItem is Channel)

View File

@@ -46,7 +46,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
{
Directory.CreateDirectory(Path.GetDirectoryName(targetFile) ?? throw new ArgumentException("Path can't be a root directory.", nameof(targetFile)));
using (var output = new FileStream(targetFile, FileMode.CreateNew, FileAccess.Write, FileShare.Read, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous))
await using (var output = new FileStream(targetFile, FileMode.CreateNew, FileAccess.Write, FileShare.Read, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous))
{
onStarted();
@@ -56,14 +56,16 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
using var durationToken = new CancellationTokenSource(duration);
using var cancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, durationToken.Token);
var linkedCancellationToken = cancellationTokenSource.Token;
await using var fileStream = new ProgressiveFileStream(directStreamProvider.GetStream());
await _streamHelper.CopyToAsync(
fileStream,
output,
IODefaults.CopyToBufferSize,
1000,
linkedCancellationToken).ConfigureAwait(false);
var fileStream = new ProgressiveFileStream(directStreamProvider.GetStream());
await using (fileStream.ConfigureAwait(false))
{
await _streamHelper.CopyToAsync(
fileStream,
output,
IODefaults.CopyToBufferSize,
1000,
linkedCancellationToken).ConfigureAwait(false);
}
}
_logger.LogInformation("Recording completed: {FilePath}", targetFile);

View File

@@ -1819,16 +1819,16 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
if (timer.IsProgramSeries)
{
SaveSeriesNfo(timer, seriesPath);
SaveVideoNfo(timer, recordingPath, program, false);
await SaveSeriesNfoAsync(timer, seriesPath).ConfigureAwait(false);
await SaveVideoNfoAsync(timer, recordingPath, program, false).ConfigureAwait(false);
}
else if (!timer.IsMovie || timer.IsSports || timer.IsNews)
{
SaveVideoNfo(timer, recordingPath, program, true);
await SaveVideoNfoAsync(timer, recordingPath, program, true).ConfigureAwait(false);
}
else
{
SaveVideoNfo(timer, recordingPath, program, false);
await SaveVideoNfoAsync(timer, recordingPath, program, false).ConfigureAwait(false);
}
await SaveRecordingImages(recordingPath, program).ConfigureAwait(false);
@@ -1839,7 +1839,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
}
}
private void SaveSeriesNfo(TimerInfo timer, string seriesPath)
private async Task SaveSeriesNfoAsync(TimerInfo timer, string seriesPath)
{
var nfoPath = Path.Combine(seriesPath, "tvshow.nfo");
@@ -1848,61 +1848,62 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
return;
}
using (var stream = new FileStream(nfoPath, FileMode.CreateNew, FileAccess.Write, FileShare.None))
await using (var stream = new FileStream(nfoPath, FileMode.CreateNew, FileAccess.Write, FileShare.None))
{
var settings = new XmlWriterSettings
{
Indent = true,
Encoding = Encoding.UTF8
Encoding = Encoding.UTF8,
Async = true
};
using (var writer = XmlWriter.Create(stream, settings))
await using (var writer = XmlWriter.Create(stream, settings))
{
writer.WriteStartDocument(true);
writer.WriteStartElement("tvshow");
await writer.WriteStartDocumentAsync(true).ConfigureAwait(false);
await writer.WriteStartElementAsync(null, "tvshow", null).ConfigureAwait(false);
string id;
if (timer.SeriesProviderIds.TryGetValue(MetadataProvider.Tvdb.ToString(), out id))
{
writer.WriteElementString("id", id);
await writer.WriteElementStringAsync(null, "id", null, id).ConfigureAwait(false);
}
if (timer.SeriesProviderIds.TryGetValue(MetadataProvider.Imdb.ToString(), out id))
{
writer.WriteElementString("imdb_id", id);
await writer.WriteElementStringAsync(null, "imdb_id", null, id).ConfigureAwait(false);
}
if (timer.SeriesProviderIds.TryGetValue(MetadataProvider.Tmdb.ToString(), out id))
{
writer.WriteElementString("tmdbid", id);
await writer.WriteElementStringAsync(null, "tmdbid", null, id).ConfigureAwait(false);
}
if (timer.SeriesProviderIds.TryGetValue(MetadataProvider.Zap2It.ToString(), out id))
{
writer.WriteElementString("zap2itid", id);
await writer.WriteElementStringAsync(null, "zap2itid", null, id).ConfigureAwait(false);
}
if (!string.IsNullOrWhiteSpace(timer.Name))
{
writer.WriteElementString("title", timer.Name);
await writer.WriteElementStringAsync(null, "title", null, timer.Name).ConfigureAwait(false);
}
if (!string.IsNullOrWhiteSpace(timer.OfficialRating))
{
writer.WriteElementString("mpaa", timer.OfficialRating);
await writer.WriteElementStringAsync(null, "mpaa", null, timer.OfficialRating).ConfigureAwait(false);
}
foreach (var genre in timer.Genres)
{
writer.WriteElementString("genre", genre);
await writer.WriteElementStringAsync(null, "genre", null, genre).ConfigureAwait(false);
}
writer.WriteEndElement();
writer.WriteEndDocument();
await writer.WriteEndElementAsync().ConfigureAwait(false);
await writer.WriteEndDocumentAsync().ConfigureAwait(false);
}
}
}
private void SaveVideoNfo(TimerInfo timer, string recordingPath, BaseItem item, bool lockData)
private async Task SaveVideoNfoAsync(TimerInfo timer, string recordingPath, BaseItem item, bool lockData)
{
var nfoPath = Path.ChangeExtension(recordingPath, ".nfo");
@@ -1911,29 +1912,30 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
return;
}
using (var stream = new FileStream(nfoPath, FileMode.CreateNew, FileAccess.Write, FileShare.None))
await using (var stream = new FileStream(nfoPath, FileMode.CreateNew, FileAccess.Write, FileShare.None))
{
var settings = new XmlWriterSettings
{
Indent = true,
Encoding = Encoding.UTF8
Encoding = Encoding.UTF8,
Async = true
};
var options = _config.GetNfoConfiguration();
var isSeriesEpisode = timer.IsProgramSeries;
using (var writer = XmlWriter.Create(stream, settings))
await using (var writer = XmlWriter.Create(stream, settings))
{
writer.WriteStartDocument(true);
await writer.WriteStartDocumentAsync(true).ConfigureAwait(false);
if (isSeriesEpisode)
{
writer.WriteStartElement("episodedetails");
await writer.WriteStartElementAsync(null, "episodedetails", null).ConfigureAwait(false);
if (!string.IsNullOrWhiteSpace(timer.EpisodeTitle))
{
writer.WriteElementString("title", timer.EpisodeTitle);
await writer.WriteElementStringAsync(null, "title", null, timer.EpisodeTitle).ConfigureAwait(false);
}
var premiereDate = item.PremiereDate ?? (!timer.IsRepeat ? DateTime.UtcNow : null);
@@ -1942,79 +1944,87 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
{
var formatString = options.ReleaseDateFormat;
writer.WriteElementString(
await writer.WriteElementStringAsync(
null,
"aired",
premiereDate.Value.ToLocalTime().ToString(formatString, CultureInfo.InvariantCulture));
null,
premiereDate.Value.ToLocalTime().ToString(formatString, CultureInfo.InvariantCulture)).ConfigureAwait(false);
}
if (item.IndexNumber.HasValue)
{
writer.WriteElementString("episode", item.IndexNumber.Value.ToString(CultureInfo.InvariantCulture));
await writer.WriteElementStringAsync(null, "episode", null, item.IndexNumber.Value.ToString(CultureInfo.InvariantCulture)).ConfigureAwait(false);
}
if (item.ParentIndexNumber.HasValue)
{
writer.WriteElementString("season", item.ParentIndexNumber.Value.ToString(CultureInfo.InvariantCulture));
await writer.WriteElementStringAsync(null, "season", null, item.ParentIndexNumber.Value.ToString(CultureInfo.InvariantCulture)).ConfigureAwait(false);
}
}
else
{
writer.WriteStartElement("movie");
await writer.WriteStartElementAsync(null, "movie", null);
if (!string.IsNullOrWhiteSpace(item.Name))
{
writer.WriteElementString("title", item.Name);
await writer.WriteElementStringAsync(null, "title", null, item.Name).ConfigureAwait(false);
}
if (!string.IsNullOrWhiteSpace(item.OriginalTitle))
{
writer.WriteElementString("originaltitle", item.OriginalTitle);
await writer.WriteElementStringAsync(null, "originaltitle", null, item.OriginalTitle).ConfigureAwait(false);
}
if (item.PremiereDate.HasValue)
{
var formatString = options.ReleaseDateFormat;
writer.WriteElementString(
await writer.WriteElementStringAsync(
null,
"premiered",
item.PremiereDate.Value.ToLocalTime().ToString(formatString, CultureInfo.InvariantCulture));
writer.WriteElementString(
null,
item.PremiereDate.Value.ToLocalTime().ToString(formatString, CultureInfo.InvariantCulture)).ConfigureAwait(false);
await writer.WriteElementStringAsync(
null,
"releasedate",
item.PremiereDate.Value.ToLocalTime().ToString(formatString, CultureInfo.InvariantCulture));
null,
item.PremiereDate.Value.ToLocalTime().ToString(formatString, CultureInfo.InvariantCulture)).ConfigureAwait(false);
}
}
writer.WriteElementString(
await writer.WriteElementStringAsync(
null,
"dateadded",
DateTime.Now.ToString(DateAddedFormat, CultureInfo.InvariantCulture));
null,
DateTime.Now.ToString(DateAddedFormat, CultureInfo.InvariantCulture)).ConfigureAwait(false);
if (item.ProductionYear.HasValue)
{
writer.WriteElementString("year", item.ProductionYear.Value.ToString(CultureInfo.InvariantCulture));
await writer.WriteElementStringAsync(null, "year", null, item.ProductionYear.Value.ToString(CultureInfo.InvariantCulture)).ConfigureAwait(false);
}
if (!string.IsNullOrEmpty(item.OfficialRating))
{
writer.WriteElementString("mpaa", item.OfficialRating);
await writer.WriteElementStringAsync(null, "mpaa", null, item.OfficialRating).ConfigureAwait(false);
}
var overview = (item.Overview ?? string.Empty)
.StripHtml()
.Replace("&quot;", "'", StringComparison.Ordinal);
writer.WriteElementString("plot", overview);
await writer.WriteElementStringAsync(null, "plot", null, overview).ConfigureAwait(false);
if (item.CommunityRating.HasValue)
{
writer.WriteElementString("rating", item.CommunityRating.Value.ToString(CultureInfo.InvariantCulture));
await writer.WriteElementStringAsync(null, "rating", null, item.CommunityRating.Value.ToString(CultureInfo.InvariantCulture)).ConfigureAwait(false);
}
foreach (var genre in item.Genres)
{
writer.WriteElementString("genre", genre);
await writer.WriteElementStringAsync(null, "genre", null, genre).ConfigureAwait(false);
}
var people = item.Id.Equals(Guid.Empty) ? new List<PersonInfo>() : _libraryManager.GetPeople(item);
var people = item.Id.Equals(default) ? new List<PersonInfo>() : _libraryManager.GetPeople(item);
var directors = people
.Where(i => IsPersonType(i, PersonType.Director))
@@ -2023,7 +2033,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
foreach (var person in directors)
{
writer.WriteElementString("director", person);
await writer.WriteElementStringAsync(null, "director", null, person).ConfigureAwait(false);
}
var writers = people
@@ -2034,19 +2044,19 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
foreach (var person in writers)
{
writer.WriteElementString("writer", person);
await writer.WriteElementStringAsync(null, "writer", null, person).ConfigureAwait(false);
}
foreach (var person in writers)
{
writer.WriteElementString("credits", person);
await writer.WriteElementStringAsync(null, "credits", null, person).ConfigureAwait(false);
}
var tmdbCollection = item.GetProviderId(MetadataProvider.TmdbCollection);
if (!string.IsNullOrEmpty(tmdbCollection))
{
writer.WriteElementString("collectionnumber", tmdbCollection);
await writer.WriteElementStringAsync(null, "collectionnumber", null, tmdbCollection).ConfigureAwait(false);
}
var imdb = item.GetProviderId(MetadataProvider.Imdb);
@@ -2054,10 +2064,10 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
{
if (!isSeriesEpisode)
{
writer.WriteElementString("id", imdb);
await writer.WriteElementStringAsync(null, "id", null, imdb).ConfigureAwait(false);
}
writer.WriteElementString("imdbid", imdb);
await writer.WriteElementStringAsync(null, "imdbid", null, imdb).ConfigureAwait(false);
// No need to lock if we have identified the content already
lockData = false;
@@ -2066,7 +2076,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
var tvdb = item.GetProviderId(MetadataProvider.Tvdb);
if (!string.IsNullOrEmpty(tvdb))
{
writer.WriteElementString("tvdbid", tvdb);
await writer.WriteElementStringAsync(null, "tvdbid", null, tvdb).ConfigureAwait(false);
// No need to lock if we have identified the content already
lockData = false;
@@ -2075,7 +2085,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
var tmdb = item.GetProviderId(MetadataProvider.Tmdb);
if (!string.IsNullOrEmpty(tmdb))
{
writer.WriteElementString("tmdbid", tmdb);
await writer.WriteElementStringAsync(null, "tmdbid", null, tmdb).ConfigureAwait(false);
// No need to lock if we have identified the content already
lockData = false;
@@ -2083,26 +2093,26 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
if (lockData)
{
writer.WriteElementString("lockdata", true.ToString(CultureInfo.InvariantCulture).ToLowerInvariant());
await writer.WriteElementStringAsync(null, "lockdata", null, "true").ConfigureAwait(false);
}
if (item.CriticRating.HasValue)
{
writer.WriteElementString("criticrating", item.CriticRating.Value.ToString(CultureInfo.InvariantCulture));
await writer.WriteElementStringAsync(null, "criticrating", null, item.CriticRating.Value.ToString(CultureInfo.InvariantCulture)).ConfigureAwait(false);
}
if (!string.IsNullOrWhiteSpace(item.Tagline))
{
writer.WriteElementString("tagline", item.Tagline);
await writer.WriteElementStringAsync(null, "tagline", null, item.Tagline).ConfigureAwait(false);
}
foreach (var studio in item.Studios)
{
writer.WriteElementString("studio", studio);
await writer.WriteElementStringAsync(null, "studio", null, studio).ConfigureAwait(false);
}
writer.WriteEndElement();
writer.WriteEndDocument();
await writer.WriteEndElementAsync().ConfigureAwait(false);
await writer.WriteEndDocumentAsync().ConfigureAwait(false);
}
}
}
@@ -2372,7 +2382,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
{
string channelId = seriesTimer.RecordAnyChannel ? null : seriesTimer.ChannelId;
if (string.IsNullOrWhiteSpace(channelId) && !parent.ChannelId.Equals(Guid.Empty))
if (string.IsNullOrWhiteSpace(channelId) && !parent.ChannelId.Equals(default))
{
if (!tempChannelCache.TryGetValue(parent.ChannelId, out LiveTvChannel channel))
{
@@ -2431,7 +2441,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
{
string channelId = null;
if (!programInfo.ChannelId.Equals(Guid.Empty))
if (!programInfo.ChannelId.Equals(default))
{
if (!tempChannelCache.TryGetValue(programInfo.ChannelId, out LiveTvChannel channel))
{

View File

@@ -24,18 +24,19 @@ using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.LiveTv.EmbyTV
{
public class EncodedRecorder : IRecorder
public class EncodedRecorder : IRecorder, IDisposable
{
private readonly ILogger _logger;
private readonly IMediaEncoder _mediaEncoder;
private readonly IServerApplicationPaths _appPaths;
private readonly TaskCompletionSource<bool> _taskCompletionSource = new TaskCompletionSource<bool>();
private readonly TaskCompletionSource<bool> _taskCompletionSource = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
private readonly IServerConfigurationManager _serverConfigurationManager;
private readonly JsonSerializerOptions _jsonOptions = JsonDefaults.Options;
private bool _hasExited;
private Stream _logFileStream;
private string _targetPath;
private Process _process;
private bool _disposed = false;
public EncodedRecorder(
ILogger logger,
@@ -64,7 +65,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
await RecordFromFile(mediaSource, mediaSource.Path, targetFile, onStarted, cancellationTokenSource.Token).ConfigureAwait(false);
_logger.LogInformation("Recording completed to file {0}", targetFile);
_logger.LogInformation("Recording completed to file {Path}", targetFile);
}
private async Task RecordFromFile(MediaSourceInfo mediaSource, string inputFile, string targetFile, Action onStarted, CancellationToken cancellationToken)
@@ -114,7 +115,10 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
// Important - don't await the log task or we won't be able to kill ffmpeg when the user stops playback
_ = StartStreamingLog(_process.StandardError.BaseStream, _logFileStream);
_logger.LogInformation("ffmpeg recording process started for {0}", _targetPath);
_logger.LogInformation("ffmpeg recording process started for {Path}", _targetPath);
// Block until ffmpeg exits
await _taskCompletionSource.Task.ConfigureAwait(false);
}
private string GetCommandLineArgs(MediaSourceInfo mediaSource, string inputTempFile, string targetFile)
@@ -323,5 +327,35 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
_logger.LogError(ex, "Error reading ffmpeg recording log");
}
}
/// <inheritdoc />
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
/// <summary>
/// Releases unmanaged and optionally managed resources.
/// </summary>
/// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
protected virtual void Dispose(bool disposing)
{
if (_disposed)
{
return;
}
if (disposing)
{
_logFileStream?.Dispose();
_process?.Dispose();
}
_logFileStream = null;
_process = null;
_disposed = true;
}
}
}

View File

@@ -28,7 +28,7 @@ using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.LiveTv.Listings
{
public class SchedulesDirect : IListingsProvider
public class SchedulesDirect : IListingsProvider, IDisposable
{
private const string ApiUrl = "https://json.schedulesdirect.org/20141201";
@@ -39,6 +39,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
private readonly ConcurrentDictionary<string, NameValuePair> _tokens = new ConcurrentDictionary<string, NameValuePair>();
private readonly JsonSerializerOptions _jsonOptions = JsonDefaults.Options;
private DateTime _lastErrorResponse;
private bool _disposed = false;
public SchedulesDirect(
ILogger<SchedulesDirect> logger,
@@ -58,8 +59,8 @@ namespace Emby.Server.Implementations.LiveTv.Listings
{
var dates = new List<string>();
var start = new List<DateTime> { startDateUtc, startDateUtc.ToLocalTime() }.Min().Date;
var end = new List<DateTime> { endDateUtc, endDateUtc.ToLocalTime() }.Max().Date;
var start = new[] { startDateUtc, startDateUtc.ToLocalTime() }.Min().Date;
var end = new[] { endDateUtc, endDateUtc.ToLocalTime() }.Max().Date;
while (start <= end)
{
@@ -822,5 +823,31 @@ namespace Emby.Server.Implementations.LiveTv.Listings
return list;
}
/// <inheritdoc />
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
/// <summary>
/// Releases unmanaged and optionally managed resources.
/// </summary>
/// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
protected virtual void Dispose(bool disposing)
{
if (_disposed)
{
return;
}
if (disposing)
{
_tokenSemaphore?.Dispose();
}
_disposed = true;
}
}
}

View File

@@ -8,6 +8,7 @@ using System.Globalization;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Security.Cryptography;
using System.Threading;
using System.Threading.Tasks;
using Jellyfin.Extensions;
@@ -26,6 +27,8 @@ namespace Emby.Server.Implementations.LiveTv.Listings
{
public class XmlTvListingsProvider : IListingsProvider
{
private static readonly TimeSpan _maxCacheAge = TimeSpan.FromHours(1);
private readonly IServerConfigurationManager _config;
private readonly IHttpClientFactory _httpClientFactory;
private readonly ILogger<XmlTvListingsProvider> _logger;
@@ -69,13 +72,14 @@ namespace Emby.Server.Implementations.LiveTv.Listings
return UnzipIfNeeded(info.Path, info.Path);
}
string cacheFilename = DateTime.UtcNow.DayOfYear.ToString(CultureInfo.InvariantCulture) + "-" + DateTime.UtcNow.Hour.ToString(CultureInfo.InvariantCulture) + "-" + info.Id + ".xml";
string cacheFilename = info.Id + ".xml";
string cacheFile = Path.Combine(_config.ApplicationPaths.CachePath, "xmltv", cacheFilename);
if (File.Exists(cacheFile))
if (File.Exists(cacheFile) && File.GetLastWriteTimeUtc(cacheFile) >= DateTime.UtcNow.Subtract(_maxCacheAge))
{
return UnzipIfNeeded(info.Path, cacheFile);
}
File.Delete(cacheFile);
_logger.LogInformation("Downloading xmltv listings from {Path}", info.Path);
Directory.CreateDirectory(Path.GetDirectoryName(cacheFile));
@@ -124,7 +128,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
{
using (var stream = File.OpenRead(file))
{
string tempFolder = Path.Combine(_config.ApplicationPaths.TempDirectory, Guid.NewGuid().ToString());
string tempFolder = GetTempFolderPath(stream);
Directory.CreateDirectory(tempFolder);
_zipClient.ExtractFirstFileFromGz(stream, tempFolder, "data.xml");
@@ -137,7 +141,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
{
using (var stream = File.OpenRead(file))
{
string tempFolder = Path.Combine(_config.ApplicationPaths.TempDirectory, Guid.NewGuid().ToString());
string tempFolder = GetTempFolderPath(stream);
Directory.CreateDirectory(tempFolder);
_zipClient.ExtractAllFromGz(stream, tempFolder, true);
@@ -146,6 +150,16 @@ namespace Emby.Server.Implementations.LiveTv.Listings
}
}
private string GetTempFolderPath(Stream stream)
{
#pragma warning disable CA5351
using var md5 = MD5.Create();
#pragma warning restore CA5351
var checksum = Convert.ToHexString(md5.ComputeHash(stream));
stream.Position = 0;
return Path.Combine(_config.ApplicationPaths.TempDirectory, checksum);
}
private string FindXmlFile(string directory)
{
return _fileSystem.GetFiles(directory, true)

View File

@@ -176,7 +176,7 @@ namespace Emby.Server.Implementations.LiveTv
try
{
dto.ParentThumbImageTag = _imageProcessor.GetImageCacheTag(librarySeries, image);
dto.ParentThumbItemId = librarySeries.Id.ToString("N", CultureInfo.InvariantCulture);
dto.ParentThumbItemId = librarySeries.Id;
}
catch (Exception ex)
{
@@ -193,7 +193,7 @@ namespace Emby.Server.Implementations.LiveTv
{
_imageProcessor.GetImageCacheTag(librarySeries, image)
};
dto.ParentBackdropItemId = librarySeries.Id.ToString("N", CultureInfo.InvariantCulture);
dto.ParentBackdropItemId = librarySeries.Id;
}
catch (Exception ex)
{
@@ -240,7 +240,7 @@ namespace Emby.Server.Implementations.LiveTv
_imageProcessor.GetImageCacheTag(program, image)
};
dto.ParentBackdropItemId = program.Id.ToString("N", CultureInfo.InvariantCulture);
dto.ParentBackdropItemId = program.Id;
}
catch (Exception ex)
{
@@ -456,7 +456,7 @@ namespace Emby.Server.Implementations.LiveTv
info.Id = timer.ExternalId;
}
if (!dto.ChannelId.Equals(Guid.Empty) && string.IsNullOrEmpty(info.ChannelId))
if (!dto.ChannelId.Equals(default) && string.IsNullOrEmpty(info.ChannelId))
{
var channel = _libraryManager.GetItemById(dto.ChannelId);
@@ -522,7 +522,7 @@ namespace Emby.Server.Implementations.LiveTv
info.Id = timer.ExternalId;
}
if (!dto.ChannelId.Equals(Guid.Empty) && string.IsNullOrEmpty(info.ChannelId))
if (!dto.ChannelId.Equals(default) && string.IsNullOrEmpty(info.ChannelId))
{
var channel = _libraryManager.GetItemById(dto.ChannelId);

View File

@@ -39,7 +39,7 @@ namespace Emby.Server.Implementations.LiveTv
/// <summary>
/// Class LiveTvManager.
/// </summary>
public class LiveTvManager : ILiveTvManager, IDisposable
public class LiveTvManager : ILiveTvManager
{
private const int MaxGuideDays = 14;
private const string ExternalServiceTag = "ExternalServiceId";
@@ -63,8 +63,6 @@ namespace Emby.Server.Implementations.LiveTv
private ITunerHost[] _tunerHosts = Array.Empty<ITunerHost>();
private IListingsProvider[] _listingProviders = Array.Empty<IListingsProvider>();
private bool _disposed = false;
public LiveTvManager(
IServerConfigurationManager config,
ILogger<LiveTvManager> logger,
@@ -178,7 +176,9 @@ namespace Emby.Server.Implementations.LiveTv
public QueryResult<BaseItem> GetInternalChannels(LiveTvChannelQuery query, DtoOptions dtoOptions, CancellationToken cancellationToken)
{
var user = query.UserId == Guid.Empty ? null : _userManager.GetUserById(query.UserId);
var user = query.UserId.Equals(default)
? null
: _userManager.GetUserById(query.UserId);
var topFolder = GetInternalLiveTvFolder(cancellationToken);
@@ -312,7 +312,7 @@ namespace Emby.Server.Implementations.LiveTv
{
if (isVideo)
{
mediaSource.MediaStreams.AddRange(new List<MediaStream>
mediaSource.MediaStreams = new MediaStream[]
{
new MediaStream
{
@@ -329,11 +329,11 @@ namespace Emby.Server.Implementations.LiveTv
// Set the index to -1 because we don't know the exact index of the audio stream within the container
Index = -1
}
});
};
}
else
{
mediaSource.MediaStreams.AddRange(new List<MediaStream>
mediaSource.MediaStreams = new MediaStream[]
{
new MediaStream
{
@@ -341,7 +341,7 @@ namespace Emby.Server.Implementations.LiveTv
// Set the index to -1 because we don't know the exact index of the audio stream within the container
Index = -1
}
});
};
}
}
@@ -857,11 +857,10 @@ namespace Emby.Server.Implementations.LiveTv
var returnArray = _dtoService.GetBaseItemDtos(queryResult.Items, options, user);
return new QueryResult<BaseItemDto>
{
Items = returnArray,
TotalRecordCount = queryResult.TotalRecordCount
};
return new QueryResult<BaseItemDto>(
query.StartIndex,
queryResult.TotalRecordCount,
returnArray);
}
public QueryResult<BaseItem> GetRecommendedProgramsInternal(InternalItemsQuery query, DtoOptions options, CancellationToken cancellationToken)
@@ -910,29 +909,27 @@ namespace Emby.Server.Implementations.LiveTv
programs = programs.Take(query.Limit.Value);
}
return new QueryResult<BaseItem>
{
Items = programs.ToArray(),
TotalRecordCount = totalCount
};
return new QueryResult<BaseItem>(
query.StartIndex,
totalCount,
programs.ToArray());
}
public QueryResult<BaseItemDto> GetRecommendedPrograms(InternalItemsQuery query, DtoOptions options, CancellationToken cancellationToken)
public Task<QueryResult<BaseItemDto>> GetRecommendedProgramsAsync(InternalItemsQuery query, DtoOptions options, CancellationToken cancellationToken)
{
if (!(query.IsAiring ?? false))
{
return GetPrograms(query, options, cancellationToken).Result;
return GetPrograms(query, options, cancellationToken);
}
RemoveFields(options);
var internalResult = GetRecommendedProgramsInternal(query, options, cancellationToken);
return new QueryResult<BaseItemDto>
{
Items = _dtoService.GetBaseItemDtos(internalResult.Items, options, query.User),
TotalRecordCount = internalResult.TotalRecordCount
};
return Task.FromResult(new QueryResult<BaseItemDto>(
query.StartIndex,
internalResult.TotalRecordCount,
_dtoService.GetBaseItemDtos(internalResult.Items, options, query.User)));
}
private int GetRecommendationScore(LiveTvProgram program, User user, bool factorChannelWatchCount)
@@ -1273,7 +1270,7 @@ namespace Emby.Server.Implementations.LiveTv
{
cancellationToken.ThrowIfCancellationRequested();
if (itemId.Equals(Guid.Empty))
if (itemId.Equals(default))
{
// Somehow some invalid data got into the db. It probably predates the boundary checking
continue;
@@ -1533,7 +1530,9 @@ namespace Emby.Server.Implementations.LiveTv
public QueryResult<BaseItemDto> GetRecordings(RecordingQuery query, DtoOptions options)
{
var user = query.UserId.Equals(Guid.Empty) ? null : _userManager.GetUserById(query.UserId);
var user = query.UserId.Equals(default)
? null
: _userManager.GetUserById(query.UserId);
RemoveFields(options);
@@ -1541,11 +1540,10 @@ namespace Emby.Server.Implementations.LiveTv
var returnArray = _dtoService.GetBaseItemDtos(internalResult.Items, options, user);
return new QueryResult<BaseItemDto>
{
Items = returnArray,
TotalRecordCount = internalResult.TotalRecordCount
};
return new QueryResult<BaseItemDto>(
query.StartIndex,
internalResult.TotalRecordCount,
returnArray);
}
private async Task<QueryResult<TimerInfo>> GetTimersInternal(TimerQuery query, CancellationToken cancellationToken)
@@ -1593,7 +1591,7 @@ namespace Emby.Server.Implementations.LiveTv
if (!string.IsNullOrEmpty(query.ChannelId))
{
var guid = new Guid(query.ChannelId);
timers = timers.Where(i => guid == _tvDtoService.GetInternalChannelId(i.Item2.Name, i.Item1.ChannelId));
timers = timers.Where(i => _tvDtoService.GetInternalChannelId(i.Item2.Name, i.Item1.ChannelId).Equals(guid));
}
if (!string.IsNullOrEmpty(query.SeriesTimerId))
@@ -1601,7 +1599,7 @@ namespace Emby.Server.Implementations.LiveTv
var guid = new Guid(query.SeriesTimerId);
timers = timers
.Where(i => _tvDtoService.GetInternalSeriesTimerId(i.Item1.SeriesTimerId) == guid);
.Where(i => _tvDtoService.GetInternalSeriesTimerId(i.Item1.SeriesTimerId).Equals(guid));
}
if (!string.IsNullOrEmpty(query.Id))
@@ -1615,11 +1613,7 @@ namespace Emby.Server.Implementations.LiveTv
.OrderBy(i => i.StartDate)
.ToArray();
return new QueryResult<TimerInfo>
{
Items = returnArray,
TotalRecordCount = returnArray.Length
};
return new QueryResult<TimerInfo>(returnArray);
}
public async Task<QueryResult<TimerInfoDto>> GetTimers(TimerQuery query, CancellationToken cancellationToken)
@@ -1667,7 +1661,7 @@ namespace Emby.Server.Implementations.LiveTv
if (!string.IsNullOrEmpty(query.ChannelId))
{
var guid = new Guid(query.ChannelId);
timers = timers.Where(i => guid == _tvDtoService.GetInternalChannelId(i.Item2.Name, i.Item1.ChannelId));
timers = timers.Where(i => _tvDtoService.GetInternalChannelId(i.Item2.Name, i.Item1.ChannelId).Equals(guid));
}
if (!string.IsNullOrEmpty(query.SeriesTimerId))
@@ -1675,7 +1669,7 @@ namespace Emby.Server.Implementations.LiveTv
var guid = new Guid(query.SeriesTimerId);
timers = timers
.Where(i => _tvDtoService.GetInternalSeriesTimerId(i.Item1.SeriesTimerId) == guid);
.Where(i => _tvDtoService.GetInternalSeriesTimerId(i.Item1.SeriesTimerId).Equals(guid));
}
if (!string.IsNullOrEmpty(query.Id))
@@ -1701,11 +1695,7 @@ namespace Emby.Server.Implementations.LiveTv
.OrderBy(i => i.StartDate)
.ToArray();
return new QueryResult<TimerInfoDto>
{
Items = returnArray,
TotalRecordCount = returnArray.Length
};
return new QueryResult<TimerInfoDto>(returnArray);
}
public async Task CancelTimer(string id)
@@ -1801,11 +1791,7 @@ namespace Emby.Server.Implementations.LiveTv
.Select(i => i.Item1)
.ToArray();
return new QueryResult<SeriesTimerInfo>
{
Items = returnArray,
TotalRecordCount = returnArray.Length
};
return new QueryResult<SeriesTimerInfo>(returnArray);
}
public async Task<QueryResult<SeriesTimerInfoDto>> GetSeriesTimers(SeriesTimerQuery query, CancellationToken cancellationToken)
@@ -1855,11 +1841,7 @@ namespace Emby.Server.Implementations.LiveTv
})
.ToArray();
return new QueryResult<SeriesTimerInfoDto>
{
Items = returnArray,
TotalRecordCount = returnArray.Length
};
return new QueryResult<SeriesTimerInfoDto>(returnArray);
}
public BaseItem GetLiveTvChannel(TimerInfo timer, ILiveTvService service)
@@ -2112,36 +2094,6 @@ namespace Emby.Server.Implementations.LiveTv
};
}
/// <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)
{
// TODO: Dispose stuff
}
_services = null;
_listingProviders = null;
_tunerHosts = null;
_disposed = true;
}
private LiveTvServiceInfo[] GetServiceInfos()
{
return Services.Select(GetServiceInfo).ToArray();

View File

@@ -50,7 +50,7 @@ namespace Emby.Server.Implementations.LiveTv
public string Key => "RefreshGuide";
/// <inheritdoc />
public Task Execute(CancellationToken cancellationToken, IProgress<double> progress)
public Task ExecuteAsync(IProgress<double> progress, CancellationToken cancellationToken)
{
var manager = (LiveTvManager)_liveTvManager;

View File

@@ -446,7 +446,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
{
Path = url,
Protocol = MediaProtocol.Udp,
MediaStreams = new List<MediaStream>
MediaStreams = new MediaStream[]
{
new MediaStream
{

View File

@@ -80,7 +80,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
_remoteEndPoint = new IPEndPoint(remoteIp, HdHomeRunPort);
_tcpClient = new TcpClient();
_tcpClient.Connect(_remoteEndPoint);
await _tcpClient.ConnectAsync(_remoteEndPoint, cancellationToken).ConfigureAwait(false);
if (!_lockkey.HasValue)
{
@@ -158,7 +158,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
}
using var tcpClient = new TcpClient();
tcpClient.Connect(_remoteEndPoint);
await tcpClient.ConnectAsync(_remoteEndPoint, cancellationToken).ConfigureAwait(false);
using var stream = tcpClient.GetStream();
var commandList = commands.GetCommands();

View File

@@ -133,7 +133,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
}
}
var taskCompletionSource = new TaskCompletionSource<bool>();
var taskCompletionSource = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
_ = StartStreaming(
udpClient,
@@ -165,7 +165,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
{
await CopyTo(udpClient, TempFilePath, openTaskCompletionSource, cancellationToken).ConfigureAwait(false);
}
catch (OperationCanceledException ex)
catch (Exception ex) when (ex is OperationCanceledException || ex is TimeoutException)
{
Logger.LogInformation("HDHR UDP stream cancelled or timed out from {0}", remoteAddress);
openTaskCompletionSource.TrySetException(ex);
@@ -186,41 +186,30 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
{
var resolved = false;
using (var fileStream = new FileStream(file, FileMode.Create, FileAccess.Write, FileShare.Read))
var fileStream = new FileStream(file, FileMode.Create, FileAccess.Write, FileShare.Read);
await using (fileStream.ConfigureAwait(false))
{
while (true)
{
cancellationToken.ThrowIfCancellationRequested();
using (var timeOutSource = new CancellationTokenSource())
using (var linkedSource = CancellationTokenSource.CreateLinkedTokenSource(
cancellationToken,
timeOutSource.Token))
var res = await udpClient.ReceiveAsync(cancellationToken)
.AsTask()
.WaitAsync(TimeSpan.FromMilliseconds(30000), CancellationToken.None)
.ConfigureAwait(false);
var buffer = res.Buffer;
var read = buffer.Length - RtpHeaderBytes;
if (read > 0)
{
var resTask = udpClient.ReceiveAsync(linkedSource.Token).AsTask();
if (await Task.WhenAny(resTask, Task.Delay(30000, linkedSource.Token)).ConfigureAwait(false) != resTask)
{
resTask.Dispose();
break;
}
await fileStream.WriteAsync(buffer.AsMemory(RtpHeaderBytes, read), cancellationToken).ConfigureAwait(false);
}
// We don't want all these delay tasks to keep running
timeOutSource.Cancel();
var res = await resTask.ConfigureAwait(false);
var buffer = res.Buffer;
var read = buffer.Length - RtpHeaderBytes;
if (read > 0)
{
await fileStream.WriteAsync(buffer.AsMemory(RtpHeaderBytes, read), linkedSource.Token).ConfigureAwait(false);
}
if (!resolved)
{
resolved = true;
DateOpened = DateTime.UtcNow;
openTaskCompletionSource.TrySetResult(true);
}
if (!resolved)
{
resolved = true;
DateOpened = DateTime.UtcNow;
openTaskCompletionSource.TrySetResult(true);
}
}
}

View File

@@ -97,7 +97,14 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
public Stream GetStream()
{
var stream = GetInputStream(TempFilePath);
var stream = new FileStream(
TempFilePath,
FileMode.Open,
FileAccess.Read,
FileShare.ReadWrite,
IODefaults.FileStreamBufferSize,
FileOptions.SequentialScan | FileOptions.Asynchronous);
bool seekFile = (DateTime.UtcNow - DateOpened).TotalSeconds > 10;
if (seekFile)
{
@@ -107,15 +114,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
return stream;
}
protected FileStream GetInputStream(string path)
=> new FileStream(
path,
FileMode.Open,
FileAccess.Read,
FileShare.ReadWrite,
IODefaults.FileStreamBufferSize,
FileOptions.SequentialScan | FileOptions.Asynchronous);
protected async Task DeleteTempFiles(string path, int retryCount = 0)
{
if (retryCount == 0)

View File

@@ -170,7 +170,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
{
Path = path,
Protocol = protocol,
MediaStreams = new List<MediaStream>
MediaStreams = new MediaStream[]
{
new MediaStream
{

View File

@@ -1,5 +1,3 @@
#nullable disable
#pragma warning disable CS1591
using System;
@@ -51,7 +49,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
var url = mediaSource.Path;
Directory.CreateDirectory(Path.GetDirectoryName(TempFilePath));
Directory.CreateDirectory(Path.GetDirectoryName(TempFilePath) ?? throw new InvalidOperationException("Path can't be a root directory."));
var typeName = GetType().Name;
Logger.LogInformation("Opening {StreamType} Live stream from {Url}", typeName, url);
@@ -75,7 +73,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
SetTempFilePath("ts");
var taskCompletionSource = new TaskCompletionSource<bool>();
var taskCompletionSource = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
_ = StartStreaming(response, taskCompletionSource, LiveStreamCancellationTokenSource.Token);
@@ -94,14 +92,8 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
// OpenedMediaSource.SupportsDirectPlay = false;
// OpenedMediaSource.SupportsDirectStream = true;
// OpenedMediaSource.SupportsTranscoding = true;
await taskCompletionSource.Task.ConfigureAwait(false);
if (taskCompletionSource.Task.Exception != null)
{
// Error happened while opening the stream so raise the exception again to inform the caller
throw taskCompletionSource.Task.Exception;
}
if (!taskCompletionSource.Task.Result)
var res = await taskCompletionSource.Task.ConfigureAwait(false);
if (!res)
{
Logger.LogWarning("Zero bytes copied from stream {StreamType} to {FilePath} but no exception raised", GetType().Name, TempFilePath);
throw new EndOfStreamException(string.Format(CultureInfo.InvariantCulture, "Zero bytes copied from stream {0}", GetType().Name));

View File

@@ -120,5 +120,8 @@
"Forced": "Forçat",
"Default": "Defecto",
"TaskOptimizeDatabaseDescription": "Compacta la base de dades i trunca l'espai lliure. Executar aquesta tasca després descanejar la biblioteca o fer altres canvis que impliquin modificacions a la base de dades pot millorar el rendiment.",
"TaskOptimizeDatabase": "Optimitzar la base de dades"
"TaskOptimizeDatabase": "Optimitzar la base de dades",
"TaskKeyframeExtractorDescription": "Extreu fotogrames clau dels fitxers de vídeo per crear llistes de reproducció HLS més precises. Aquesta tasca pot durar molt de temps.",
"TaskKeyframeExtractor": "Extractor de fotogrames clau",
"External": "Extern"
}

View File

@@ -23,7 +23,7 @@
"HeaderFavoriteShows": "Oblíbené seriály",
"HeaderFavoriteSongs": "Oblíbená hudba",
"HeaderLiveTV": "Televize",
"HeaderNextUp": "Nadcházející",
"HeaderNextUp": "Další díly",
"HeaderRecordingGroups": "Skupiny nahrávek",
"HomeVideos": "Domácí videa",
"Inherit": "Zdědit",
@@ -77,7 +77,7 @@
"SubtitleDownloadFailureFromForItem": "Stažení titulků pro {1} z {0} selhalo",
"Sync": "Synchronizace",
"System": "Systém",
"TvShows": "TV seriály",
"TvShows": "Seriály",
"User": "Uživatel",
"UserCreatedWithName": "Uživatel {0} byl vytvořen",
"UserDeletedWithName": "Uživatel {0} byl smazán",
@@ -120,5 +120,8 @@
"Forced": "Vynucené",
"Default": "Výchozí",
"TaskOptimizeDatabaseDescription": "Zmenší databázi a odstraní prázdné místo. Spuštění této úlohy po skenování knihovny či jiných změnách databáze může zlepšit výkon.",
"TaskOptimizeDatabase": "Optimalizovat databázi"
"TaskOptimizeDatabase": "Optimalizovat databázi",
"TaskKeyframeExtractorDescription": "Vytahuje klíčové snímky ze souborů videa za účelem vytváření přesnějších seznamů přehrávání HLS. Tento úkol může trvat velmi dlouho.",
"TaskKeyframeExtractor": "Vytahovač klíčových snímků",
"External": "Externí"
}

View File

@@ -15,7 +15,7 @@
"Folders": "Ffolderi",
"Favorites": "Ffefrynnau",
"LabelRunningTimeValue": "Amser rhedeg: {0}",
"TaskOptimizeDatabase": "Cronfa ddata Optimeiddio",
"TaskOptimizeDatabase": "Optimeiddio cronfa ddata",
"TaskRefreshChannels": "Adnewyddu Sianeli",
"TaskRefreshPeople": "Adnewyddu Pobl",
"TasksChannelsCategory": "Sianeli Internet",
@@ -54,5 +54,73 @@
"Undefined": "Heb ddiffiniad",
"TvShows": "Rhaglenni teledu",
"HeaderLiveTV": "Teledu Byw",
"User": "Defnyddiwr"
"User": "Defnyddiwr",
"TaskCleanLogsDescription": "Dileu ffeiliau log sy'n fwy na {0} diwrnod oed.",
"TaskCleanLogs": "Glanhau ffolder log",
"TaskRefreshLibraryDescription": "Sganio'ch llyfrgell gyfryngau am ffeiliau newydd ac yn adnewyddu metaddata.",
"TaskRefreshLibrary": "Sganwich Llyfrgell Cyfryngau",
"TaskCleanActivityLogDescription": "Yn dileu cofnodion log gweithgaredd sy'n hŷn na'r oedran a nodwyd.",
"TaskCleanActivityLog": "Glanhau Log Gweithgaredd",
"SubtitleDownloadFailureFromForItem": "Methodd is-deitlau lawrlwytho o {0} ar gyfer {1}",
"NotificationOptionPluginError": "Methodd ategyn",
"NotificationOptionAudioPlaybackStopped": "Stopiwyd chwarae sain",
"NotificationOptionAudioPlayback": "Dechreuwyd chwarae sain",
"MessageServerConfigurationUpdated": "Mae gosodiadau gweinydd wedi'i ddiweddaru",
"MessageNamedServerConfigurationUpdatedWithValue": "Mae adran gosodiadau gweinydd {0} wedi'i diweddaru",
"FailedLoginAttemptWithUserName": "Cais mewngofnodi wedi methu gan {0}",
"ValueHasBeenAddedToLibrary": "{0} wedi'i hychwanegu at eich llyfrgell gyfryngau",
"UserStoppedPlayingItemWithValues": "{0} wedi gorffen chwarae {1} ar {2}",
"UserStartedPlayingItemWithValues": "{0} yn chwarae {1} ar {2}",
"UserPolicyUpdatedWithName": "Polisi defnyddiwr wedi'i newid ar gyfer {0}",
"UserPasswordChangedWithName": "Cyfrinair wedi'i newid ar gyfer defnyddiwr {0}",
"UserOnlineFromDevice": "Mae {0} ar-lein o {1}",
"UserOfflineFromDevice": "Mae {0} wedi datgysylltu o {1}",
"UserLockedOutWithName": "Mae defnyddiwr {0} wedi'i gloi allan",
"UserDownloadingItemWithValues": "Mae {0} yn lawrlwytho {1}",
"UserDeletedWithName": "Defnyddiwr {0} wedi'i ddileu",
"UserCreatedWithName": "Defnyddiwr {0} wedi'i greu",
"StartupEmbyServerIsLoading": "Gweinydd Jellyfin yn llwytho. Triwch eto mewn ychydig.",
"ServerNameNeedsToBeRestarted": "Mae angen ailddechrau {0}",
"PluginUpdatedWithName": "{0} wedi'i ddiweddaru",
"PluginUninstalledWithName": "{0} wedi'i ddadosod",
"PluginInstalledWithName": "{0} wedi'i osod",
"NotificationOptionVideoPlaybackStopped": "Stopiwyd chwarae fideo",
"NotificationOptionVideoPlayback": "Dechreuwyd chwarae fideo",
"NotificationOptionUserLockedOut": "Defnyddiwr wedi'i gloi allan",
"NotificationOptionTaskFailed": "Methwyd cyflawni y dasg a drefnwyd",
"NotificationOptionServerRestartRequired": "Mae angen ailgychwyn y gweinydd",
"NotificationOptionPluginUpdateInstalled": "Diweddariad ategyn wedi'i osod",
"NotificationOptionPluginUninstalled": "Ategyn wedi'i ddadosod",
"NotificationOptionPluginInstalled": "Ategyn wedi'i osod",
"NotificationOptionNewLibraryContent": "Cynnwys newydd ar gael",
"NotificationOptionCameraImageUploaded": "Llun camera wedi'i huwchlwytho",
"NotificationOptionApplicationUpdateInstalled": "Diweddariad ap wedi'i osod",
"NotificationOptionApplicationUpdateAvailable": "Diweddariad ap ar gael",
"NewVersionIsAvailable": "Mae fersiwn diweddarach o'r gweinydd Jellyfin ar gael.",
"NameInstallFailed": "Gosodiad {0} wedi methu",
"MessageApplicationUpdatedTo": "Gweinydd Jellyfin wedi'i ddiweddaru i {0}",
"MessageApplicationUpdated": "Gweinydd Jellyfin wedi'i ddiweddaru",
"LabelIpAddressValue": "Cyfeiriad IP: {0}",
"ItemRemovedWithName": "{0} wedi'i dynnu o'r llyfrgell",
"ItemAddedWithName": "{0} wedi'i adio i'r llyfrgell",
"HeaderRecordingGroups": "Grwpiau Recordio",
"HeaderFavoriteSongs": "Ffefryn Ganeuon",
"HeaderFavoriteShows": "Ffefryn Shoeau",
"HeaderFavoriteEpisodes": "Ffefryn Rhaglenni",
"TaskDownloadMissingSubtitlesDescription": "Chwilio'r rhyngrwyd am is-deitlau coll yn seiliedig ar gosodiadau metaddata.",
"TaskDownloadMissingSubtitles": "Lawrlwytho isdeitlau coll",
"TaskCleanTranscodeDescription": "Dileu ffeiliau trawsgodio fwy nag un diwrnod oed.",
"External": "Allanol",
"TaskKeyframeExtractorDescription": "Echdynnu fframiau o ffeiliau fideo i greu rhestrau chwarae HLS mwy manwl gywir. Gall y dasg hon redeg am amser hir.",
"TaskKeyframeExtractor": "Echdynnwr ffram-allwedd",
"TaskOptimizeDatabaseDescription": "Crynhoi cronfa ddata ac yn cwtogi'r gofod rhydd. Gallai rhedeg y dasg hon ar ôl sganio'r llyfrgell neu wneud newidiadau eraill sy'n addasu'r cronfa ddata wella perfformiad.",
"TaskRefreshChannelsDescription": "Diweddaru gwybodaeth sianeli rhyngrwyd.",
"TaskCleanTranscode": "Gwaghau Ffolder Trawsgodau",
"TaskUpdatePluginsDescription": "Lawrlwytho ac yn gosod diweddariadau ar gyfer ategion sydd wedi'u gosod i'w diweddaru'n awtomatig.",
"TaskUpdatePlugins": "Diweddaru Ategion",
"TaskRefreshPeopleDescription": "Yn diweddaru metaddata ar gyfer actorion a chyfarwyddwyr yn eich llyfrgell gyfryngau.",
"TaskRefreshChapterImagesDescription": "Creu mân-luniau ar gyfer fideos sydd â phenodau.",
"TaskRefreshChapterImages": "Echdynnu Lluniau Pennod",
"TaskCleanCacheDescription": "Dileu ffeiliau cache nad oes eu hangen ar y system mwyach.",
"TaskCleanCache": "Gwaghau Ffolder Cache"
}

View File

@@ -120,5 +120,8 @@
"Forced": "Erzwungen",
"Default": "Standard",
"TaskOptimizeDatabaseDescription": "Komprimiert die Datenbank und trimmt den freien Speicherplatz. Die Ausführung dieser Aufgabe nach dem Scannen der Bibliothek oder nach anderen Änderungen, die Datenbankänderungen implizieren, kann die Leistung verbessern.",
"TaskOptimizeDatabase": "Datenbank optimieren"
"TaskOptimizeDatabase": "Datenbank optimieren",
"TaskKeyframeExtractorDescription": "Extrahiere Keyframes aus Videodateien, um präzisere HLS-Playlisten zu erzeugen. Diese Aufgabe kann sehr lange dauern.",
"TaskKeyframeExtractor": "Keyframe Extraktor",
"External": "Extern"
}

View File

@@ -120,5 +120,8 @@
"Forced": "Εξαναγκασμένο",
"Default": "Προεπιλογή",
"TaskOptimizeDatabaseDescription": "Συμπιέζει τη βάση δεδομένων και δημιουργεί ελεύθερο χώρο. Η εκτέλεση αυτής της εργασίας μετά τη σάρωση της βιβλιοθήκης ή την πραγματοποίηση άλλων αλλαγών που συνεπάγονται τροποποιήσεις της βάσης δεδομένων μπορεί να βελτιώσει την απόδοση.",
"TaskOptimizeDatabase": "Βελτιστοποίηση βάσης δεδομένων"
"TaskOptimizeDatabase": "Βελτιστοποίηση βάσης δεδομένων",
"TaskKeyframeExtractorDescription": "Εξάγει τα βασικά καρέ από αρχεία βίντεο για να δημιουργήσει πιο ακριβείς HLS λίστες αναπαραγωγής. Αυτή η εργασία μπορεί να διαρκέσει πολλή ώρα.",
"TaskKeyframeExtractor": "Εξαγωγέας βασικών καρέ βίντεο",
"External": "Εξωτερικό"
}

View File

@@ -120,5 +120,8 @@
"Forced": "Forced",
"Default": "Default",
"TaskOptimizeDatabaseDescription": "Compacts database and truncates free space. Running this task after scanning the library or doing other changes that imply database modifications might improve performance.",
"TaskOptimizeDatabase": "Optimise database"
"TaskOptimizeDatabase": "Optimise database",
"TaskKeyframeExtractorDescription": "Extracts keyframes from video files to create more precise HLS playlists. This task may run for a long time.",
"TaskKeyframeExtractor": "Keyframe Extractor",
"External": "External"
}

View File

@@ -12,6 +12,7 @@
"Default": "Default",
"DeviceOfflineWithName": "{0} has disconnected",
"DeviceOnlineWithName": "{0} is connected",
"External": "External",
"FailedLoginAttemptWithUserName": "Failed login try from {0}",
"Favorites": "Favorites",
"Folders": "Folders",
@@ -119,5 +120,7 @@
"TaskDownloadMissingSubtitles": "Download missing subtitles",
"TaskDownloadMissingSubtitlesDescription": "Searches the internet for missing subtitles based on metadata configuration.",
"TaskOptimizeDatabase": "Optimize database",
"TaskOptimizeDatabaseDescription": "Compacts database and truncates free space. Running this task after scanning the library or doing other changes that imply database modifications might improve performance."
"TaskOptimizeDatabaseDescription": "Compacts database and truncates free space. Running this task after scanning the library or doing other changes that imply database modifications might improve performance.",
"TaskKeyframeExtractor": "Keyframe Extractor",
"TaskKeyframeExtractorDescription": "Extracts keyframes from video files to create more precise HLS playlists. This task may run for a long time."
}

View File

@@ -119,5 +119,8 @@
"HeaderRecordingGroups": "Rikordadaj Grupoj",
"FailedLoginAttemptWithUserName": "Malsukcesa ensaluta provo de {0}",
"CameraImageUploadedFrom": "Nova kamera bildo estis alŝutita de {0}",
"AuthenticationSucceededWithUserName": "{0} sukcese aŭtentikigis"
"AuthenticationSucceededWithUserName": "{0} sukcese aŭtentikigis",
"TaskKeyframeExtractorDescription": "Eltiras ĉefkadrojn el videodosieroj por krei pli precizajn HLS-ludlistojn. Ĉi tiu tasko povas funkcii dum longa tempo.",
"TaskKeyframeExtractor": "Eltiri Ĉefkadrojn",
"External": "Ekstera"
}

View File

@@ -120,5 +120,7 @@
"Forced": "Forzado",
"Default": "Predeterminado",
"TaskOptimizeDatabase": "Optimizar base de datos",
"TaskOptimizeDatabaseDescription": "Compacta la base de datos y trunca el espacio libre. Puede mejorar el rendimiento si se realiza esta tarea después de escanear la biblioteca o después de realizar otros cambios que impliquen modificar la base de datos."
"TaskOptimizeDatabaseDescription": "Compacta la base de datos y trunca el espacio libre. Puede mejorar el rendimiento si se realiza esta tarea después de escanear la biblioteca o después de realizar otros cambios que impliquen modificar la base de datos.",
"TaskKeyframeExtractorDescription": "Extrae los cuadros clave de los archivos de vídeo para crear listas HLS más precisas. Esta tarea puede tardar un buen rato.",
"TaskKeyframeExtractor": "Extractor de Cuadros Clave"
}

View File

@@ -120,5 +120,7 @@
"Forced": "Forzado",
"Default": "Predeterminado",
"TaskOptimizeDatabase": "Optimizar la base de datos",
"TaskOptimizeDatabaseDescription": "Compacta y libera el espacio libre en la base de datos. Ejecutar esta tarea tras escanear la biblioteca o hacer cambios que impliquen modificaciones en la base de datos puede mejorar el rendimiento."
"TaskOptimizeDatabaseDescription": "Compacta y libera el espacio libre en la base de datos. Ejecutar esta tarea tras escanear la biblioteca o hacer cambios que impliquen modificaciones en la base de datos puede mejorar el rendimiento.",
"TaskKeyframeExtractorDescription": "Extrae los fotogramas clave de los archivos de vídeo para crear listas HLS más precisas. Esta tarea puede tardar mucho tiempo.",
"TaskKeyframeExtractor": "Extractor de Fotogramas Clave"
}

View File

@@ -0,0 +1,120 @@
{
"ValueSpecialEpisodeName": "Berezia - {0}",
"Sync": "Sinkronizatu",
"Songs": "Abestiak",
"Shows": "Serieak",
"Playlists": "Erreprodukzio-zerrendak",
"Photos": "Argazkiak",
"MusicVideos": "Bideo musikalak",
"Movies": "Filmak",
"HeaderContinueWatching": "Ikusten jarraitu",
"HeaderAlbumArtists": "Albumeko artistak",
"Genres": "Generoak",
"Folders": "Karpetak",
"Favorites": "Gogokoak",
"Default": "Lehenetsia",
"Collections": "Bildumak",
"Channels": "Kanalak",
"Books": "Liburuak",
"Artists": "Artistak",
"Albums": "Albumak",
"TaskOptimizeDatabase": "Datu basea optimizatu",
"TaskDownloadMissingSubtitlesDescription": "Metadataren konfigurazioan oinarrituta falta diren azpitituluak bilatzen ditu interneten.",
"TaskDownloadMissingSubtitles": "Falta diren azpitituluak deskargatu",
"TaskRefreshChannelsDescription": "Internet kanalen informazioa eguneratu.",
"TaskRefreshChannels": "Kanalak eguneratu",
"TaskCleanTranscodeDescription": "Egun bat baino zaharragoak diren transcode fitxategiak ezabatzen ditu.",
"TaskCleanTranscode": "Transcode direktorioa garbitu",
"TaskUpdatePluginsDescription": "Automatikoki eguneratzeko konfiguratutako pluginen eguneraketak deskargatu eta instalatzen ditu.",
"TaskUpdatePlugins": "Pluginak eguneratu",
"TaskRefreshPeopleDescription": "Zure liburutegiko aktore eta zuzendarien metadata eguneratzen du.",
"TaskRefreshPeople": "Jendea eguneratu",
"TaskCleanLogsDescription": "{0} egun baino zaharragoak diren log fitxategiak ezabatzen ditu.",
"TaskCleanLogs": "Log direktorioa garbitu",
"TaskRefreshLibraryDescription": "Zure multimedia liburutegia eskaneatzen du fitxategi berriak eta metadatak eguneratzeko.",
"TaskRefreshLibrary": "Multimedia Liburutegia eskaneatu",
"TaskRefreshChapterImagesDescription": "Kapituluak dituzten bideoen miniaturak sortzen ditu.",
"TaskRefreshChapterImages": "Kapituluen irudiak erauzi",
"TaskCleanCacheDescription": "Sistemak behar ez dituen cache fitxategiak ezabatzen ditu.",
"TaskCleanCache": "Cache Directorioa garbitu",
"TaskCleanActivityLogDescription": "Konfiguratuta data baino zaharragoak diren log-ak ezabatu.",
"TaskCleanActivityLog": "Erabilera Log-a garbitu",
"TasksChannelsCategory": "Internet Kanalak",
"TasksApplicationCategory": "Aplikazioa",
"TasksLibraryCategory": "Liburutegia",
"TasksMaintenanceCategory": "Mantenua",
"VersionNumber": "Bertsioa {0}",
"ValueHasBeenAddedToLibrary": "{0} zure multimedia liburutegian gehitu da",
"UserStoppedPlayingItemWithValues": "{0}-ek {1} ikusteaz bukatu du {2}-(a)n",
"UserStartedPlayingItemWithValues": "{0} {1} ikusten ari da {2}-(a)n",
"UserPolicyUpdatedWithName": "{0} Erabiltzailearen politikak aldatu dira",
"UserPasswordChangedWithName": "{0} Erabiltzailearen pasahitza aldatu da",
"UserOnlineFromDevice": "{0} online dago {1}-tik",
"UserOfflineFromDevice": "{0} {1}-tik deskonektatu da",
"UserLockedOutWithName": "{0} Erabiltzailea blokeatu da",
"UserDownloadingItemWithValues": "{1} {0}-tik deskargatzen",
"UserDeletedWithName": "{0} Erabiltzailea ezabatu da",
"UserCreatedWithName": "{0} Erabiltzailea sortu da",
"User": "Erabiltzailea",
"Undefined": "Ezezaguna",
"TvShows": "TB showak",
"System": "Sistema",
"SubtitleDownloadFailureFromForItem": "{1}-en azpitutuluak {0} deskargatzean huts egin du",
"StartupEmbyServerIsLoading": "Jellyfin zerbitzaria kargatzen. Saiatu berriro beranduxeago.",
"ServerNameNeedsToBeRestarted": "{0} berrabiarazi behar da",
"ScheduledTaskStartedWithName": "{0} hasi da",
"ScheduledTaskFailedWithName": "{0} huts egin du",
"PluginUpdatedWithName": "{0} eguneratu da",
"PluginUninstalledWithName": "{0} desinstalatu da",
"PluginInstalledWithName": "{0} instalatu da",
"Plugin": "Plugin",
"NotificationOptionVideoPlaybackStopped": "Bideoa geldituta",
"NotificationOptionVideoPlayback": "Bideoa martxan",
"NotificationOptionUserLockedOut": "Erabiltzailea blokeatua",
"NotificationOptionTaskFailed": "Programatutako atazak huts egin du",
"NotificationOptionServerRestartRequired": "Zerbitzaria berrabiarazi behar da",
"NotificationOptionPluginUpdateInstalled": "Pluginaren eguneraketa instalatua",
"NotificationOptionPluginUninstalled": "Plugina desinstalatua",
"NotificationOptionPluginInstalled": "Plugina instalatua",
"NotificationOptionPluginError": "Pluginak huts egin du",
"NotificationOptionNewLibraryContent": "Eduki berria gehitua",
"NotificationOptionInstallationFailed": "Instalazioak huts egin du",
"NotificationOptionCameraImageUploaded": "Kamerako irudia igota",
"NotificationOptionAudioPlaybackStopped": "Audioa gelditua",
"NotificationOptionAudioPlayback": "Audioa martxan",
"NotificationOptionApplicationUpdateInstalled": "Aplikazioaren eguneraketa instalatua",
"NotificationOptionApplicationUpdateAvailable": "Aplikazioaren eguneraketa eskuragarri",
"NewVersionIsAvailable": "Jellyfin zerbitzariaren bertsio berria deskargatzeko eskuragarri dago.",
"NameSeasonUnknown": "Denboraldi ezezaguna",
"NameSeasonNumber": "{0} Denboraldia",
"NameInstallFailed": "{0} instalazioak huts egin du",
"Music": "Musika",
"MixedContent": "Denetariko edukia",
"MessageServerConfigurationUpdated": "Zerbitzariaren konfigurazioa eguneratu da",
"MessageNamedServerConfigurationUpdatedWithValue": "Zerbitzariaren konfigurazio {0} atala eguneratu da",
"MessageApplicationUpdatedTo": "Jellyfin zerbitzaria {0}-ra eguneratu da",
"MessageApplicationUpdated": "Jellyfin zerbitzaria eguneratu da",
"Latest": "Azkena",
"LabelRunningTimeValue": "Denbora martxan: {0}",
"LabelIpAddressValue": "IP helbidea: {0}",
"ItemRemovedWithName": "{0} liburutegitik ezabatu da",
"ItemAddedWithName": "{0} liburutegira gehitu da",
"HomeVideos": "Etxeko bideoak",
"HeaderNextUp": "Hurrengoa",
"HeaderLiveTV": "Zuzeneko TB",
"HeaderFavoriteSongs": "Gogoko abestiak",
"HeaderFavoriteShows": "Gogoko showak",
"HeaderFavoriteEpisodes": "Gogoko atalak",
"HeaderFavoriteArtists": "Gogoko artistak",
"HeaderFavoriteAlbums": "Gogoko albumak",
"Forced": "Behartuta",
"FailedLoginAttemptWithUserName": "Login egiten akatsa, saiatu hemen {0}",
"External": "Kanpokoa",
"DeviceOnlineWithName": "{0} konektatu da",
"DeviceOfflineWithName": "{0} deskonektatu da",
"ChapterNameValue": "{0} Kapitulua",
"CameraImageUploadedFrom": "{0}-tik kamera irudi berri bat igo da",
"AuthenticationSucceededWithUserName": "{0} ongi autentifikatu da",
"Application": "Aplikazioa",
"AppDeviceValues": "App: {0}, Gailua: {1}"
}

View File

@@ -119,5 +119,9 @@
"TaskCleanActivityLogDescription": "ورودی‌های قدیمی‌تر از سن تنظیم شده در سیاهه فعالیت را حذف می‌کند.",
"TaskCleanActivityLog": "پاکسازی سیاهه فعالیت",
"Undefined": "تعریف نشده",
"TaskOptimizeDatabase": "بهینه سازی پایگاه داده"
"TaskOptimizeDatabase": "بهینه سازی پایگاه داده",
"TaskOptimizeDatabaseDescription": "فشرده سازی پایگاه داده و باز کردن فضای آزاد.اجرای این گزینه بعد از اسکن کردن کتابخانه یا تغییرات دیگر که روی پایگاه داده تأثیر میگذارند میتواند کارایی را بهبود ببخشد.",
"TaskKeyframeExtractorDescription": "فریم های کلیدی را از فایل های ویدئویی استخراج می کند تا لیست های پخش HLS دقیق تری ایجاد کند. این کار ممکن است برای مدت طولانی اجرا شود.",
"TaskKeyframeExtractor": "استخراج کننده فریم کلیدی",
"External": "خارجی"
}

View File

@@ -119,5 +119,8 @@
"TaskCleanActivityLog": "Tyhjennä toimintahistoria",
"Undefined": "Määrittelemätön",
"TaskOptimizeDatabaseDescription": "Tiivistää ja puhdistaa tietokannan. Tämän toiminnon suorittaminen kirjastojen skannauksen tai muiden tietokantaan liittyvien muutoksien jälkeen voi parantaa suorituskykyä.",
"TaskOptimizeDatabase": "Optimoi tietokanta"
"TaskOptimizeDatabase": "Optimoi tietokanta",
"TaskKeyframeExtractorDescription": "Purkaa videotiedostojen avainkuvat tarkempien HLS-toistolistojen luomiseksi. Tehtävä saattaa kestää huomattavan pitkään.",
"TaskKeyframeExtractor": "Avainkuvien purkain",
"External": "Ulkoinen"
}

View File

@@ -1,7 +1,7 @@
{
"Albums": "Albums",
"AppDeviceValues": "Application : {0}, Appareil : {1}",
"Application": "Applications",
"Application": "Application",
"Artists": "Artistes",
"AuthenticationSucceededWithUserName": "{0} authentifié avec succès",
"Books": "Livres",
@@ -120,5 +120,7 @@
"Forced": "Forcé",
"Default": "Par défaut",
"TaskOptimizeDatabaseDescription": "Réduit les espaces vides/inutiles et compacte la base de données. Utiliser cette fonction après une mise à jour de la bibliothèque ou toute autre modification de la base de données peut améliorer les performances du serveur.",
"TaskOptimizeDatabase": "Optimiser la base de données"
"TaskOptimizeDatabase": "Optimiser la base de données",
"TaskKeyframeExtractorDescription": "Extrait les images clés des fichiers vidéo pour créer des listes de lecture HLS plus précises. Cette tâche peut durer très longtemps.",
"TaskKeyframeExtractor": "Extracteur d'image clé"
}

View File

@@ -119,5 +119,6 @@
"Undefined": "לא מוגדר",
"Forced": "כפוי",
"Default": "ברירת מחדל",
"TaskOptimizeDatabase": "מיטוב מסד נתונים"
"TaskOptimizeDatabase": "מיטוב מסד נתונים",
"TaskOptimizeDatabaseDescription": "דוחס את מסד הנתונים ומוריד את שטח האחסון שבשימוש. הרצה של פעולה זו לאחר סריקת הספרייה או שינויים אחרים שמשפיעים על מסד הנתונים יכולה לשפר ביצועים."
}

View File

@@ -61,5 +61,10 @@
"LabelRunningTimeValue": "चलने का समय: {0}",
"ItemAddedWithName": "{0} को लाइब्रेरी में जोड़ा गया",
"Inherit": "इनहेरिट",
"NotificationOptionVideoPlaybackStopped": "चलचित्र रुका हुआ"
"NotificationOptionVideoPlaybackStopped": "चलचित्र रुका हुआ",
"PluginUninstalledWithName": "{0} अनइंस्टॉल हुए",
"PluginInstalledWithName": "{0} इंस्टॉल हुए",
"Plugin": "प्लग-इन",
"Playlists": "प्लेलिस्ट",
"Photos": "तस्वीरें"
}

View File

@@ -120,5 +120,8 @@
"Forced": "Kényszerített",
"Default": "Alapértelmezett",
"TaskOptimizeDatabaseDescription": "Tömöríti az adatbázist és csonkolja a szabad helyet. A feladat futtatása a könyvtár beolvasása után, vagy egyéb, adatbázis-módosítást igénylő változtatások végrehajtása javíthatja a teljesítményt.",
"TaskOptimizeDatabase": "Adatbázis optimalizálása"
"TaskOptimizeDatabase": "Adatbázis optimalizálása",
"TaskKeyframeExtractor": "Kulcskockák kibontása",
"TaskKeyframeExtractorDescription": "Kulcskockákat bont ki a videofájlokból, hogy pontosabb HLS lejátszási listákat hozzon létre. Ez a feladat hosszú ideig tarthat.",
"External": "Külső"
}

View File

@@ -120,5 +120,7 @@
"Forced": "Forzato",
"Default": "Predefinito",
"TaskOptimizeDatabaseDescription": "Compatta Database e tronca spazi liberi. Eseguire questa azione dopo la scansione o dopo aver fatto altri cambiamenti inerenti il database potrebbe aumentarne la performance.",
"TaskOptimizeDatabase": "Ottimizza Database"
"TaskOptimizeDatabase": "Ottimizza Database",
"TaskKeyframeExtractor": "Estrattore di Keyframe",
"TaskKeyframeExtractorDescription": "Estrae i keyframe dai video per creare migliori playlist HLS. Questa procedura potrebbe richiedere molto tempo."
}

View File

@@ -119,5 +119,8 @@
"Forced": "強制",
"Default": "デフォルト",
"TaskOptimizeDatabaseDescription": "データベースをコンパクトにして、空き領域を切り詰めます。メディアライブラリのスキャン後でこのタスクを実行するとパフォーマンスが向上する可能性があります。",
"TaskOptimizeDatabase": "データベースの最適化"
"TaskOptimizeDatabase": "データベースの最適化",
"TaskKeyframeExtractorDescription": "より正確なHLSプレイリストを作成するため、動画ファイルからキーフレームを抽出する。この処理には時間がかかる場合があります。",
"TaskKeyframeExtractor": "キーフレーム抽出",
"External": "外部"
}

View File

@@ -120,5 +120,8 @@
"TaskCleanCacheDescription": "Jüiede qajet emes keştelgen faildardy joiady.",
"TaskCleanActivityLogDescription": "Äreket jūrnalyndağy teñşelgen jasynan asqan jazbalary joiady.",
"TaskOptimizeDatabaseDescription": "Derekqordy qysyp, bos oryndy qysqartady. Būl tapsyrmany tasyğyşhanany skanerlegennen keiın nemese derekqorğa meñzeitın basqa özgertuler ıstelgennen keiın oryndau önımdılıktı damytuy mümkın.",
"TaskOptimizeDatabase": "Derekqordy oñtailandyru"
"TaskOptimizeDatabase": "Derekqordy oñtailandyru",
"TaskKeyframeExtractorDescription": "Naqtyraq HLS oynatu tızımderın jasau üşın beinefaildardan negızgı kadrlardy şyğarady. Būl tapsyrma ūzaq uaqytqa sozyluy mümkın.",
"TaskKeyframeExtractor": "Negızgı kadrlardy şyğaru",
"External": "Syrtqy"
}

View File

@@ -0,0 +1,7 @@
{
"TaskDownloadMissingSubtitlesDescription": "ಮೆಟಾಡೇಟಾ ಕಾನ್ಫಿಗರೇಶನ್ ಆಧಾರದ ಮೇಲೆ ಕಾಣೆಯಾದ ಉಪಶೀರ್ಷಿಕೆಗಳಿಗಾಗಿ ಅಂತರ್ಜಾಲದಲ್ಲಿ ಹುಡುಕುತ್ತದೆ.",
"TaskOptimizeDatabase": "ಡೇಟಾಬೇಸ್ ಅನ್ನು ಆಪ್ಟಿಮೈಜ್ ಮಾಡಿ",
"TaskOptimizeDatabaseDescription": "ಡೇಟಾಬೇಸ್ ಅನ್ನು ಕಾಂಪ್ಯಾಕ್ಟ್ ಮಾಡುತ್ತದೆ ಮತ್ತು ಮುಕ್ತ ಜಾಗವನ್ನು ಮೊಟಕುಗೊಳಿಸುತ್ತದೆ. ಲೈಬ್ರರಿಯನ್ನು ಸ್ಕ್ಯಾನ್ ಮಾಡಿದ ನಂತರ ಈ ಕಾರ್ಯವನ್ನು ನಡೆಸುವುದು ಅಥವಾ ಡೇಟಾಬೇಸ್ ಮಾರ್ಪಾಡುಗಳನ್ನು ಸೂಚಿಸುವ ಇತರ ಬದಲಾವಣೆಗಳನ್ನು ಮಾಡುವುದರಿಂದ ಕಾರ್ಯಕ್ಷಮತೆಯನ್ನು ಸುಧಾರಿಸಬಹುದು.",
"TaskKeyframeExtractor": "ಕೀಫ್ರೇಮ್ ಎಕ್ಸ್‌ಟ್ರಾಕ್ಟರ್",
"TaskKeyframeExtractorDescription": "ಹೆಚ್ಚು ನಿಖರವಾದ HLS ಪ್ಲೇಪಟ್ಟಿಗಳನ್ನು ರಚಿಸಲು ವೀಡಿಯೊ ಫೈಲ್‌ಗಳಿಂದ ಕೀಫ್ರೇಮ್‌ಗಳನ್ನು ಹೊರತೆಗೆಯುತ್ತದೆ. ಈ ಕಾರ್ಯವು ದೀರ್ಘಕಾಲದವರೆಗೆ ನಡೆಯಬಹುದು."
}

View File

@@ -58,5 +58,47 @@
"Application": "अ‍ॅप्लिकेशन",
"AppDeviceValues": "अ‍ॅप: {0}, यंत्र: {1}",
"Collections": "संग्रह",
"ChapterNameValue": "धडा {0}"
"ChapterNameValue": "धडा {0}",
"TaskDownloadMissingSubtitlesDescription": "नसलेल्या उपशिर्षकांचा मेटाडॅटा कॉन्फिग्युरेशनप्रमाणे इन्टरनेटवर शोध घेतो.",
"TaskRefreshChannelsDescription": "इन्टरनेट वाहिन्यांची माहिती ताजी करतो.",
"TaskUpdatePluginsDescription": "आपोआप अपडेट करण्यासाठी कॉन्फिगर केलेल्या प्लगइनसाठी अपडेट डाउनलोड करून इन्स्टॉल करतो.",
"TaskRefreshChannels": "वाहिन्या ताज्या करा",
"TaskRefreshPeopleDescription": "आपल्या माध्यम संग्रहातील अभिनेत्यांचा व दिग्दर्शकांचा मेटाडॅटा ताजा करतो.",
"TaskRefreshPeople": "लोकांची माहिती ताजी करा",
"TaskRefreshLibraryDescription": "माध्यम संग्रह स्कॅन करून नवीन फायली शोधतो व मेटाडॅटा ताजे करतो.",
"TaskRefreshLibrary": "माध्यम संग्रह स्कॅन करा",
"TaskRefreshChapterImagesDescription": "अध्याय असलेल्या व्हिडियोंसाठी थंबनेल चित्र बनवतो.",
"TaskRefreshChapterImages": "अध्याय चित्र काढून घ्या",
"TasksMaintenanceCategory": "देखरेख",
"ValueHasBeenAddedToLibrary": "{0} हे तुमच्या माध्यम संग्रहात जोडण्यात आले आहे",
"UserStoppedPlayingItemWithValues": "{0} यांचं {2} वर {1} पूर्णपणे प्ले करून झालं आहे",
"UserStartedPlayingItemWithValues": "{0} हे {2} वर {1} प्ले करत आहे",
"UserDownloadingItemWithValues": "{0} हे {1} डाउनलोड करत आहे",
"System": "प्रणाली",
"Undefined": "अव्याख्यात",
"Sync": "सिंक",
"ServerNameNeedsToBeRestarted": "{0} याला बंद करून पुन्हा सुरू करायची गरज आहे",
"SubtitleDownloadFailureFromForItem": "{0} येथून {1} यासाठी उपशिर्षक डाउनलोड करण्यात अपयश",
"ScheduledTaskStartedWithName": "{0} सुरू झाले",
"ScheduledTaskFailedWithName": "{0} अपयशी झाले",
"ProviderValue": "पुरवणारा: {0}",
"PluginUpdatedWithName": "{0} अपडेट केले",
"PluginUninstalledWithName": "{0} अनिन्स्टॉल केले",
"PluginInstalledWithName": "{0} इन्स्टॉल केले",
"NotificationOptionVideoPlaybackStopped": "व्हिडियो प्लेबॅक बंद केले",
"NotificationOptionVideoPlayback": "व्हिडियो प्लेबॅक सुरू केले",
"NotificationOptionTaskFailed": "अनुसूचित कार्यात अपयश",
"NotificationOptionServerRestartRequired": "सर्व्हर बंद करून पुन्हा सुरू करावा लागेल",
"NotificationOptionPluginUpdateInstalled": "प्लगइन अपडेट इन्स्टॉल झाले",
"NotificationOptionPluginUninstalled": "प्लगइन अनिन्स्टॉल झाले",
"NotificationOptionPluginInstalled": "प्लगइन इन्स्टॉल झाले",
"NotificationOptionPluginError": "प्लगइनमध्ये अपयश",
"NotificationOptionNewLibraryContent": "नवीन सामग्री जोडली गेली",
"NotificationOptionInstallationFailed": "इन्स्टॉल करण्यात अपयश",
"NotificationOptionAudioPlayback": "ऑडियो प्लेबॅक सुरू झाले",
"NotificationOptionAudioPlaybackStopped": "ऑडियो प्लेबॅक बंद झाले",
"MixedContent": "मिश्रित सामग्री",
"LabelRunningTimeValue": "चालू काल: {0}",
"HeaderContinueWatching": "बघणे चालू ठेवा",
"Default": "डीफॉल्ट"
}

View File

@@ -4,5 +4,120 @@
"Channels": "ချန်နယ်များ",
"Books": "စာအုပ်များ",
"Artists": "အနုပညာရှင်များ",
"Albums": "အခွေများ"
"Albums": "အခွေများ",
"TaskOptimizeDatabaseDescription": "ဒေတာဘေ့စ်ကို ကျစ်လစ်စေပြီး နေရာလွတ်များကို ဖြတ်တောက်ပေးသည်။ စာကြည့်တိုက်ကို စကင်န်ဖတ်ပြီးနောက် ဤလုပ်ငန်းကို လုပ်ဆောင်ခြင်း သို့မဟုတ် ဒေတာဘေ့စ်မွမ်းမံမှုများ စွမ်းဆောင်ရည်ကို မြှင့်တင်ပေးနိုင်သည်ဟု ရည်ညွှန်းသော အခြားပြောင်းလဲမှုများကို လုပ်ဆောင်ခြင်း။.",
"TaskOptimizeDatabase": "ဒေတာဘေ့စ်ကို အကောင်းဆုံးဖြစ်အောင်လုပ်ပါ။",
"TaskDownloadMissingSubtitlesDescription": "မက်တာဒေတာ ဖွဲ့စည်းမှုပုံစံအပေါ် အခြေခံ၍ ပျောက်ဆုံးနေသော စာတန်းထိုးများအတွက် အင်တာနက်ကို ရှာဖွေသည်။",
"TaskDownloadMissingSubtitles": "ပျောက်ဆုံးနေသော စာတန်းထိုးများကို ဒေါင်းလုဒ်လုပ်ပါ။",
"TaskRefreshChannelsDescription": "အင်တာနက်ချန်နယ်အချက်အလက်ကို ပြန်လည်စတင်သည်။",
"TaskRefreshChannels": "ချန်နယ်များကို ပြန်လည်စတင်ပါ။",
"TaskCleanTranscodeDescription": "သက်တမ်း တစ်ရက်ထက်ပိုသော အသွင်ပြောင်းကုဒ်ဖိုင်များကို ဖျက်ပါ။",
"TaskCleanTranscode": "Transcode လမ်းညွှန်ကို သန့်ရှင်းပါ။",
"TaskUpdatePluginsDescription": "အလိုအလျောက် အပ်ဒိတ်လုပ်ရန် စီစဉ်ထားသော ပလပ်အင်များအတွက် အပ်ဒိတ်များကို ဒေါင်းလုဒ်လုပ်ပြီး ထည့်သွင်းပါ။",
"TaskUpdatePlugins": "ပလပ်အင်များကို အပ်ဒိတ်လုပ်ပါ။",
"TaskRefreshPeopleDescription": "သင့်မီဒီယာစာကြည့်တိုက်ရှိ သရုပ်ဆောင်များနှင့် ဒါရိုက်တာများအတွက် မက်တာဒေတာကို အပ်ဒိတ်လုပ်ပါ။",
"TaskRefreshPeople": "လူများကို ပြန်လည်ဆန်းသစ်ပါ။",
"TaskCleanLogsDescription": "{0} ရက်ထက်ပိုသော မှတ်တမ်းဖိုင်များကို ဖျက်သည်။",
"TaskCleanLogs": "မှတ်တမ်းလမ်းညွှန်ကို သန့်ရှင်းပါ။",
"TaskRefreshLibraryDescription": "ဖိုင်အသစ်များအတွက် သင့်မီဒီယာဒစ်ဂျစ်တိုက်ကို စကင်န်ဖတ်ပြီး မက်တာဒေတာကို ပြန်လည်စတင်ပါ။",
"TaskRefreshLibrary": "မီဒီယာစာကြည့်တိုက်ကို စကင်န်ဖတ်ပါ။",
"TaskRefreshChapterImagesDescription": "အခန်းများပါရှိသော ဗီဒီယိုများအတွက် ပုံသေးများကို ဖန်တီးပါ။",
"TaskRefreshChapterImages": "အခန်းပုံများကို ထုတ်ယူပါ။",
"TaskCleanCacheDescription": "စနစ်မှ မလိုအပ်တော့သော ကက်ရှ်ဖိုင်များကို ဖျက်ပါ။.",
"TaskCleanCache": "Cache Directory ကို ရှင်းပါ။",
"TaskCleanActivityLogDescription": "စီစဉ်သတ်မှတ်ထားသော အသက်ထက် ပိုကြီးသော လုပ်ဆောင်ချက်မှတ်တမ်းများကို ဖျက်ပါ။",
"TaskCleanActivityLog": "လုပ်ဆောင်ချက်မှတ်တမ်းကို ရှင်းလင်းပါ။",
"TasksChannelsCategory": "အင်တာနက်ချန်နယ်များ",
"TasksApplicationCategory": "အပလီကေးရှင်း",
"TasksLibraryCategory": "စာကြည့်တိုက်",
"TasksMaintenanceCategory": "ထိန်းသိမ်းခြင်း",
"VersionNumber": "ဗားရှင်း {0}",
"ValueSpecialEpisodeName": "အထူး- {0}",
"ValueHasBeenAddedToLibrary": "{0} ကို သင့်မီဒီယာဒစ်ဂျစ်တိုက်သို့ ပေါင်းထည့်လိုက်ပါပြီ။",
"UserStoppedPlayingItemWithValues": "{0} သည် {1} ကို {2} တွင် ဖွင့်ပြီးပါပြီ",
"UserStartedPlayingItemWithValues": "{0} သည် {1} ကို {2} တွင် ပြသနေသည်",
"UserPolicyUpdatedWithName": "{0} အတွက် အသုံးပြုသူမူဝါဒကို အပ်ဒိတ်လုပ်ပြီးပါပြီ",
"UserPasswordChangedWithName": "အသုံးပြုသူ {0} အတွက် စကားဝှက်ကို ပြောင်းထားသည်",
"UserOnlineFromDevice": "{0} သည် {1} မှ အွန်လိုင်းဖြစ်သည်",
"UserOfflineFromDevice": "{0} သည် {1} မှ ချိတ်ဆက်မှုပြတ်တောက်သွားသည်",
"UserLockedOutWithName": "အသုံးပြုသူ {0} အား လော့ခ်ချထားသည်။",
"UserDownloadingItemWithValues": "{0} သည် {1} ကို ဒေါင်းလုဒ်လုပ်နေသည်",
"UserDeletedWithName": "အသုံးပြုသူ {0} ကို ဖျက်လိုက်ပါပြီ။",
"UserCreatedWithName": "အသုံးပြုသူ {0} ကို ဖန်တီးပြီးပါပြီ။",
"User": "အသုံးပြုသူ",
"Undefined": "သတ်မှတ်မထားသော",
"TvShows": "တီဗီရှိုးများ",
"System": "စနစ်",
"Sync": "ထပ်တူကျသည်။",
"SubtitleDownloadFailureFromForItem": "စာတန်းထိုးများကို {1} အတွက် {0} မှ ဒေါင်းလုဒ်လုပ်၍ မရပါ",
"StartupEmbyServerIsLoading": "Jellyfin ဆာဗာကို ဖွင့်နေပါသည်။ ခဏနေ ထပ်စမ်းကြည့်ပါ။",
"Songs": "သီချင်းများ",
"Shows": "ရှိုးပွဲ",
"ServerNameNeedsToBeRestarted": "{0} ကို ပြန်လည်စတင်ရန် လိုအပ်သည်။",
"ScheduledTaskStartedWithName": "{0} စတင်ခဲ့သည်။",
"ScheduledTaskFailedWithName": "{0} မအောင်မြင်ပါ။",
"ProviderValue": "ဝန်ဆောင်မှုပေးသူ- {0}",
"PluginUpdatedWithName": "{0} ကို အပ်ဒိတ်လုပ်ထားသည်။",
"PluginUninstalledWithName": "{0} ကို ဖြုတ်လိုက်ပါပြီ။",
"PluginInstalledWithName": "{0} ကို ထည့်သွင်းခဲ့သည်။",
"Plugin": "ပလပ်အင်",
"Playlists": "အစီအစဉ်များ",
"Photos": "ဓာတ်ပုံများ",
"NotificationOptionVideoPlaybackStopped": "ဗီဒီယိုပြန်ဖွင့်ခြင်းကို ရပ်သွားသည်။",
"NotificationOptionVideoPlayback": "ဗီဒီယိုဖွင့်ခြင်း စတင်ပါပြီ။",
"NotificationOptionUserLockedOut": "အသုံးပြုသူ ထွက်သွားသည်။",
"NotificationOptionTaskFailed": "စီစဉ်ထားသော အလုပ်ပျက်ကွက်",
"NotificationOptionServerRestartRequired": "ဆာဗာ ပြန်လည်စတင်ရန် လိုအပ်သည်။",
"NotificationOptionPluginUpdateInstalled": "ပလပ်အင် အပ်ဒိတ် ထည့်သွင်းပြီးပါပြီ။",
"NotificationOptionPluginUninstalled": "ပလပ်အင်ကို ဖြုတ်လိုက်ပါပြီ။",
"NotificationOptionPluginInstalled": "ပလပ်အင် ထည့်သွင်းထားသည်။",
"NotificationOptionPluginError": "ပလပ်အင် ချို့ယွင်းခြင်း။",
"NotificationOptionNewLibraryContent": "အကြောင်းအရာအသစ် ထပ်ထည့်ထားပါတယ်။",
"NotificationOptionInstallationFailed": "တပ်ဆင်မှု မအောင်မြင်ပါ။",
"NotificationOptionCameraImageUploaded": "ကင်မရာပုံ အပ်လုဒ်လုပ်ထားသည်။",
"NotificationOptionAudioPlaybackStopped": "အသံပြန်ဖွင့်ခြင်းကို ရပ်သွားသည်။",
"NotificationOptionAudioPlayback": "အသံပြန်ဖွင့်ခြင်း စတင်ပါပြီ။",
"NotificationOptionApplicationUpdateInstalled": "အပလီကေးရှင်း အပ်ဒိတ်ကို ထည့်သွင်းထားသည်။",
"NotificationOptionApplicationUpdateAvailable": "အပလီကေးရှင်း အပ်ဒိတ် ရနိုင်ပါပြီ။",
"NewVersionIsAvailable": "Jellyfin Server ၏ ဗားရှင်းအသစ်ကို ဒေါင်းလုဒ်လုပ်နိုင်ပါသည်။",
"NameSeasonUnknown": "အမည််မသိ ဇာတ်လမ်းတွဲ",
"NameSeasonNumber": "ဇာတ်လမ်းတွဲ {0}",
"NameInstallFailed": "{0} ထည့်သွင်းမှု မအောင်မြင်ပါ။",
"MusicVideos": "ဂီတဗီဒီယိုများ",
"Music": "တေးဂီတ",
"Movies": "ရုပ်ရှင်များ",
"MixedContent": "ရောနှောပါဝင်မှု",
"MessageServerConfigurationUpdated": "ဆာဗာဖွဲ့စည်းပုံကို အပ်ဒိတ်လုပ်ပြီးပါပြီ။",
"MessageNamedServerConfigurationUpdatedWithValue": "ဆာဗာဖွဲ့စည်းပုံကဏ္ဍ {0} ကို အပ်ဒိတ်လုပ်ပြီးပါပြီ။",
"MessageApplicationUpdatedTo": "Jellyfin ဆာဗာကို {0} သို့ အပ်ဒိတ်လုပ်ထားသည်",
"MessageApplicationUpdated": "Jellyfin ဆာဗာကို အပ်ဒိတ်လုပ်ပြီးပါပြီ။",
"Latest": "နောက်ဆုံး",
"LabelRunningTimeValue": "လည်ပတ်ချိန်- {0}",
"LabelIpAddressValue": "IP လိပ်စာ- {0}",
"ItemRemovedWithName": "{0} ကို ဒစ်ဂျစ်တိုက်မှ ဖယ်ရှားခဲ့သည်။",
"ItemAddedWithName": "{0} ကို စာကြည့်တိုက်သို့ ထည့်ထားသည်။",
"Inherit": "ဆက်လက် လုပ်ဆောင်သည်။",
"HomeVideos": "ပင်မဗီဒီယိုများ",
"HeaderRecordingGroups": "အသံဖမ်းအဖွဲ့များ",
"HeaderNextUp": "နောက်ထပ်",
"HeaderLiveTV": "Live TV",
"HeaderFavoriteSongs": "အကြိုက်ဆုံးသီချင်းများ",
"HeaderFavoriteShows": "အကြိုက်ဆုံးရှိုးများ",
"HeaderFavoriteEpisodes": "အကြိုက်ဆုံးအပိုင်းများ",
"HeaderFavoriteArtists": "အကြိုက်ဆုံးအနုပညာရှင်များ",
"HeaderFavoriteAlbums": "အကြိုက်ဆုံး အယ်လ်ဘမ်များ",
"HeaderContinueWatching": "ဆက်လက်ကြည့်ရှုပါ။",
"HeaderAlbumArtists": "အယ်လ်ဘမ်အနုပညာရှင်များ",
"Genres": "အမျိုးအစားများ",
"Forced": "အတင်းအကြပ်",
"Folders": "ဖိုဒါများ",
"Favorites": "အကြိုက်ဆုံးများ",
"FailedLoginAttemptWithUserName": "{0} မှ အကောင့်ဝင်ရန် မအောင်မြင်ပါ",
"DeviceOnlineWithName": "{0} ကို ချိတ်ဆက်ထားသည်။",
"DeviceOfflineWithName": "{0} နှင့် အဆက်ပြတ်သွားပါပြီ။",
"ChapterNameValue": "အခန်း {0}",
"CameraImageUploadedFrom": "ကင်မရာပုံအသစ်ကို {0} မှ အပ်လုဒ်လုပ်ထားသည်",
"AuthenticationSucceededWithUserName": "{0} စစ်မှန်ကြောင်း အောင်မြင်စွာ အတည်ပြုပြီးပါပြီ။",
"Application": "အပလီကေးရှင်း",
"AppDeviceValues": "အက်ပ်- {0}၊ စက်- {1}"
}

View File

@@ -1,7 +1,17 @@
{
"Books": "Libros",
"AuthenticationSucceededWithUserName": "{0} autentificado correctamente",
"Books": "Scrolls",
"AuthenticationSucceededWithUserName": "{0} passed yer trial",
"Artists": "Artistas",
"Songs": "Shantees",
"Albums": "Ships"
"Albums": "Tomes",
"Photos": "Paintings",
"NotificationOptionUserLockedOut": "Crewmate sent to the brig",
"HeaderContinueWatching": "Continue Yer Journey",
"Folders": "Chests",
"Application": "Captain",
"DeviceOnlineWithName": "{0} joined yer crew",
"DeviceOfflineWithName": "{0} abandoned ship",
"AppDeviceValues": "Captain: {0}, Ship: {1}",
"CameraImageUploadedFrom": "Yer looking glass has glimpsed another painting from {0}",
"Collections": "Barrels"
}

View File

@@ -120,5 +120,8 @@
"Forced": "Forçado",
"Default": "Padrão",
"TaskOptimizeDatabaseDescription": "Compactar base de dados e liberar espaço livre. Executar esta tarefa após realizar mudanças que impliquem em modificações da base de dados pode trazer melhorias de desempenho.",
"TaskOptimizeDatabase": "Otimizar base de dados"
"TaskOptimizeDatabase": "Otimizar base de dados",
"TaskKeyframeExtractor": "Extrator de quadro-chave",
"TaskKeyframeExtractorDescription": "Extrai quadros-chave de arquivos de vídeo para criar listas de reprodução HLS mais precisas. Esta tarefa pode ser executada por um longo tempo.",
"External": "Externo"
}

View File

@@ -117,5 +117,9 @@
"TaskCleanActivityLog": "Curăță Jurnalul de Activitate",
"Undefined": "Nedefinit",
"Forced": "Forțat",
"Default": "Implicit"
"Default": "Implicit",
"TaskOptimizeDatabaseDescription": "Compactează baza de date și trunchiază spațiul liber. Rularea acestei sarcini după scanarea bibliotecii sau după efectuarea altor modificări care implică modificări ale bazei de date poate îmbunătăți performanța.",
"TaskOptimizeDatabase": "Optimizează baza de date",
"TaskKeyframeExtractorDescription": "Extrage cadrele cheie din fișierele video pentru a crea liste de redare HLS mai precise. Această sarcină poate rula o perioadă lungă de timp.",
"External": "Extern"
}

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