aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/ISSUE_TEMPLATE/bug_report.md20
-rw-r--r--CONTRIBUTORS.md2
-rw-r--r--Dockerfile2
-rw-r--r--Dockerfile.arm10
-rw-r--r--Dockerfile.arm6411
-rw-r--r--Emby.Dlna/Api/DlnaServerService.cs3
-rw-r--r--Emby.Dlna/Api/DlnaService.cs3
-rw-r--r--Emby.Dlna/Common/Argument.cs2
-rw-r--r--Emby.Dlna/Common/DeviceIcon.cs11
-rw-r--r--Emby.Dlna/Common/DeviceService.cs7
-rw-r--r--Emby.Dlna/Common/ServiceAction.cs14
-rw-r--r--Emby.Dlna/Common/StateVariable.cs18
-rw-r--r--Emby.Dlna/Configuration/DlnaOptions.cs27
-rw-r--r--Emby.Dlna/ConfigurationExtension.cs3
-rw-r--r--Emby.Dlna/ConnectionManager/ConnectionManager.cs3
-rw-r--r--Emby.Dlna/ConnectionManager/ConnectionManagerXmlBuilder.cs3
-rw-r--r--Emby.Dlna/ConnectionManager/ControlHandler.cs31
-rw-r--r--Emby.Dlna/ConnectionManager/ServiceActionListBuilder.cs3
-rw-r--r--Emby.Dlna/ContentDirectory/ContentDirectory.cs3
-rw-r--r--Emby.Dlna/ContentDirectory/ContentDirectoryXmlBuilder.cs3
-rw-r--r--Emby.Dlna/ContentDirectory/ControlHandler.cs365
-rw-r--r--Emby.Dlna/ContentDirectory/ServiceActionListBuilder.cs3
-rw-r--r--Emby.Dlna/ControlRequest.cs3
-rw-r--r--Emby.Dlna/ControlResponse.cs13
-rw-r--r--Emby.Dlna/Didl/DidlBuilder.cs5
-rw-r--r--Emby.Dlna/Didl/Filter.cs3
-rw-r--r--Emby.Dlna/Didl/StringWriterWithEncoding.cs3
-rw-r--r--Emby.Dlna/DlnaManager.cs3
-rw-r--r--Emby.Dlna/Emby.Dlna.csproj13
-rw-r--r--Emby.Dlna/EventSubscriptionResponse.cs14
-rw-r--r--Emby.Dlna/Eventing/EventManager.cs6
-rw-r--r--Emby.Dlna/Eventing/EventSubscription.cs7
-rw-r--r--Emby.Dlna/IConnectionManager.cs2
-rw-r--r--Emby.Dlna/IContentDirectory.cs2
-rw-r--r--Emby.Dlna/IEventManager.cs2
-rw-r--r--Emby.Dlna/IMediaReceiverRegistrar.cs2
-rw-r--r--Emby.Dlna/IUpnpService.cs3
-rw-r--r--Emby.Dlna/Main/DlnaEntryPoint.cs3
-rw-r--r--Emby.Dlna/MediaReceiverRegistrar/ControlHandler.cs44
-rw-r--r--Emby.Dlna/MediaReceiverRegistrar/MediaReceiverRegistrar.cs3
-rw-r--r--Emby.Dlna/MediaReceiverRegistrar/MediaReceiverRegistrarXmlBuilder.cs3
-rw-r--r--Emby.Dlna/MediaReceiverRegistrar/ServiceActionListBuilder.cs3
-rw-r--r--Emby.Dlna/PlayTo/Device.cs33
-rw-r--r--Emby.Dlna/PlayTo/DeviceInfo.cs3
-rw-r--r--Emby.Dlna/PlayTo/PlayToController.cs3
-rw-r--r--Emby.Dlna/PlayTo/PlayToManager.cs11
-rw-r--r--Emby.Dlna/PlayTo/PlaybackProgressEventArgs.cs3
-rw-r--r--Emby.Dlna/PlayTo/PlaybackStartEventArgs.cs3
-rw-r--r--Emby.Dlna/PlayTo/PlaybackStoppedEventArgs.cs3
-rw-r--r--Emby.Dlna/PlayTo/PlaylistItem.cs3
-rw-r--r--Emby.Dlna/PlayTo/PlaylistItemFactory.cs3
-rw-r--r--Emby.Dlna/PlayTo/SsdpHttpClient.cs15
-rw-r--r--Emby.Dlna/PlayTo/TRANSPORTSTATE.cs3
-rw-r--r--Emby.Dlna/PlayTo/TransportCommands.cs3
-rw-r--r--Emby.Dlna/PlayTo/UpnpContainer.cs3
-rw-r--r--Emby.Dlna/PlayTo/uBaseObject.cs3
-rw-r--r--Emby.Dlna/PlayTo/uPnpNamespaces.cs3
-rw-r--r--Emby.Dlna/Profiles/DefaultProfile.cs3
-rw-r--r--Emby.Dlna/Profiles/DenonAvrProfile.cs3
-rw-r--r--Emby.Dlna/Profiles/DirectTvProfile.cs3
-rw-r--r--Emby.Dlna/Profiles/DishHopperJoeyProfile.cs3
-rw-r--r--Emby.Dlna/Profiles/Foobar2000Profile.cs3
-rw-r--r--Emby.Dlna/Profiles/LgTvProfile.cs3
-rw-r--r--Emby.Dlna/Profiles/LinksysDMA2100Profile.cs3
-rw-r--r--Emby.Dlna/Profiles/MarantzProfile.cs3
-rw-r--r--Emby.Dlna/Profiles/MediaMonkeyProfile.cs3
-rw-r--r--Emby.Dlna/Profiles/PanasonicVieraProfile.cs3
-rw-r--r--Emby.Dlna/Profiles/PopcornHourProfile.cs3
-rw-r--r--Emby.Dlna/Profiles/SamsungSmartTvProfile.cs3
-rw-r--r--Emby.Dlna/Profiles/SharpSmartTvProfile.cs3
-rw-r--r--Emby.Dlna/Profiles/SonyBlurayPlayer2013.cs3
-rw-r--r--Emby.Dlna/Profiles/SonyBlurayPlayer2014.cs3
-rw-r--r--Emby.Dlna/Profiles/SonyBlurayPlayer2015.cs3
-rw-r--r--Emby.Dlna/Profiles/SonyBlurayPlayer2016.cs3
-rw-r--r--Emby.Dlna/Profiles/SonyBlurayPlayerProfile.cs3
-rw-r--r--Emby.Dlna/Profiles/SonyBravia2010Profile.cs3
-rw-r--r--Emby.Dlna/Profiles/SonyBravia2011Profile.cs3
-rw-r--r--Emby.Dlna/Profiles/SonyBravia2012Profile.cs3
-rw-r--r--Emby.Dlna/Profiles/SonyBravia2013Profile.cs3
-rw-r--r--Emby.Dlna/Profiles/SonyBravia2014Profile.cs3
-rw-r--r--Emby.Dlna/Profiles/SonyPs3Profile.cs3
-rw-r--r--Emby.Dlna/Profiles/SonyPs4Profile.cs3
-rw-r--r--Emby.Dlna/Profiles/WdtvLiveProfile.cs3
-rw-r--r--Emby.Dlna/Profiles/XboxOneProfile.cs3
-rw-r--r--Emby.Dlna/Server/DescriptionXmlBuilder.cs3
-rw-r--r--Emby.Dlna/Service/BaseControlHandler.cs18
-rw-r--r--Emby.Dlna/Service/BaseService.cs3
-rw-r--r--Emby.Dlna/Service/ControlErrorHandler.cs3
-rw-r--r--Emby.Dlna/Service/ServiceXmlBuilder.cs3
-rw-r--r--Emby.Dlna/Ssdp/DeviceDiscovery.cs15
-rw-r--r--Emby.Dlna/Ssdp/Extensions.cs3
-rw-r--r--Emby.Drawing/Emby.Drawing.csproj12
-rw-r--r--Emby.Drawing/ImageProcessor.cs348
-rw-r--r--Emby.Naming/Audio/AudioFileParser.cs13
-rw-r--r--Emby.Naming/Common/NamingOptions.cs2
-rw-r--r--Emby.Naming/TV/SeasonPathParser.cs44
-rw-r--r--Emby.Naming/Video/ExtraResolver.cs2
-rw-r--r--Emby.Naming/Video/StackResolver.cs4
-rw-r--r--Emby.Server.Implementations/ApplicationHost.cs41
-rw-r--r--Emby.Server.Implementations/Data/SqliteItemRepository.cs49
-rw-r--r--Emby.Server.Implementations/Devices/DeviceManager.cs15
-rw-r--r--Emby.Server.Implementations/Dto/DtoService.cs47
-rw-r--r--Emby.Server.Implementations/EntryPoints/RecordingNotifier.cs34
-rw-r--r--Emby.Server.Implementations/EntryPoints/RefreshUsersMetadata.cs9
-rw-r--r--Emby.Server.Implementations/EntryPoints/StartupWizard.cs15
-rw-r--r--Emby.Server.Implementations/EntryPoints/UdpServerEntryPoint.cs6
-rw-r--r--Emby.Server.Implementations/EntryPoints/UserDataChangeNotifier.cs44
-rw-r--r--Emby.Server.Implementations/HttpClientManager/HttpClientManager.cs2
-rw-r--r--Emby.Server.Implementations/HttpServer/HttpListenerHost.cs27
-rw-r--r--Emby.Server.Implementations/IO/ExtendedFileSystemInfo.cs2
-rw-r--r--Emby.Server.Implementations/IO/FileRefresher.cs40
-rw-r--r--Emby.Server.Implementations/Library/LibraryManager.cs96
-rw-r--r--Emby.Server.Implementations/Library/Resolvers/Audio/AudioResolver.cs6
-rw-r--r--Emby.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs12
-rw-r--r--Emby.Server.Implementations/Library/Resolvers/Audio/MusicArtistResolver.cs7
-rw-r--r--Emby.Server.Implementations/Library/Resolvers/BaseVideoResolver.cs3
-rw-r--r--Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs14
-rw-r--r--Emby.Server.Implementations/Library/Resolvers/PhotoAlbumResolver.cs3
-rw-r--r--Emby.Server.Implementations/Library/Resolvers/PhotoResolver.cs12
-rw-r--r--Emby.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs18
-rw-r--r--Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs3
-rw-r--r--Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs1
-rw-r--r--Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs3
-rw-r--r--Emby.Server.Implementations/LiveTv/EmbyTV/EntryPoint.cs5
-rw-r--r--Emby.Server.Implementations/LiveTv/EmbyTV/IRecorder.cs3
-rw-r--r--Emby.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs3
-rw-r--r--Emby.Server.Implementations/LiveTv/EmbyTV/RecordingHelper.cs18
-rw-r--r--Emby.Server.Implementations/LiveTv/EmbyTV/SeriesTimerManager.cs4
-rw-r--r--Emby.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs3
-rw-r--r--Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs3
-rw-r--r--Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs7
-rw-r--r--Emby.Server.Implementations/LiveTv/LiveTvConfigurationFactory.cs3
-rw-r--r--Emby.Server.Implementations/LiveTv/LiveTvDtoService.cs3
-rw-r--r--Emby.Server.Implementations/LiveTv/LiveTvManager.cs2
-rw-r--r--Emby.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs48
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs3
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs3
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunManager.cs3
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs3
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs3
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs3
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs3
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs3
-rw-r--r--Emby.Server.Implementations/Localization/Core/bn.json96
-rw-r--r--Emby.Server.Implementations/Localization/Core/es_DO.json14
-rw-r--r--Emby.Server.Implementations/Localization/Core/fi.json72
-rw-r--r--Emby.Server.Implementations/Localization/Core/hu.json8
-rw-r--r--Emby.Server.Implementations/Localization/Core/id.json7
-rw-r--r--Emby.Server.Implementations/Localization/Core/is.json36
-rw-r--r--Emby.Server.Implementations/Localization/Core/nn.json1
-rw-r--r--Emby.Server.Implementations/Localization/Core/zh-CN.json4
-rw-r--r--Emby.Server.Implementations/Localization/Core/zh-HK.json174
-rw-r--r--Emby.Server.Implementations/Localization/Core/zh-TW.json8
-rw-r--r--Emby.Server.Implementations/Session/SessionManager.cs283
-rw-r--r--Jellyfin.Drawing.Skia/SkiaEncoder.cs20
-rw-r--r--Jellyfin.Server/Program.cs11
-rw-r--r--MediaBrowser.Api/Images/ImageService.cs26
-rw-r--r--MediaBrowser.Api/Playback/BaseStreamingService.cs24
-rw-r--r--MediaBrowser.Api/Sessions/ApiKeyService.cs85
-rw-r--r--MediaBrowser.Api/Sessions/SessionInfoWebSocketListener.cs (renamed from MediaBrowser.Api/Session/SessionInfoWebSocketListener.cs)2
-rw-r--r--MediaBrowser.Api/Sessions/SessionService.cs (renamed from MediaBrowser.Api/Session/SessionsService.cs)100
-rw-r--r--MediaBrowser.Api/UserLibrary/PlaystateService.cs4
-rw-r--r--MediaBrowser.Api/UserService.cs2
-rw-r--r--MediaBrowser.Common/Configuration/IConfigurationFactory.cs28
-rw-r--r--MediaBrowser.Controller/Drawing/IImageProcessor.cs35
-rw-r--r--MediaBrowser.Controller/Drawing/ImageHelper.cs2
-rw-r--r--MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs3
-rw-r--r--MediaBrowser.Controller/Entities/Photo.cs8
-rw-r--r--MediaBrowser.Controller/Library/ILibraryManager.cs6
-rw-r--r--MediaBrowser.Controller/Library/IMediaSourceProvider.cs3
-rw-r--r--MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs12
-rw-r--r--MediaBrowser.Controller/Net/IAuthService.cs4
-rw-r--r--MediaBrowser.Controller/Plugins/IServerEntryPoint.cs10
-rw-r--r--MediaBrowser.Controller/Providers/IImageEnhancer.cs61
-rw-r--r--MediaBrowser.Controller/Session/SessionInfo.cs7
-rw-r--r--MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs3
-rw-r--r--MediaBrowser.Model/Configuration/LibraryOptions.cs1
-rw-r--r--MediaBrowser.Model/Configuration/ServerConfiguration.cs1
-rw-r--r--MediaBrowser.Model/Drawing/ImageDimensions.cs31
-rw-r--r--MediaBrowser.Model/MediaInfo/MediaInfo.cs1
-rw-r--r--MediaBrowser.Model/Querying/QueryResult.cs6
-rw-r--r--MediaBrowser.Model/Services/ApiMemberAttribute.cs6
-rw-r--r--deployment/fedora-package-x64/Dockerfile6
-rw-r--r--tests/Jellyfin.Api.Tests/Auth/CustomAuthenticationHandlerTests.cs2
-rw-r--r--tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj2
-rw-r--r--tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj2
-rw-r--r--tests/Jellyfin.MediaEncoding.Tests/EncoderValidatorTests.cs16
-rw-r--r--tests/Jellyfin.MediaEncoding.Tests/Jellyfin.MediaEncoding.Tests.csproj2
-rw-r--r--tests/Jellyfin.Naming.Tests/Jellyfin.Naming.Tests.csproj1
-rw-r--r--tests/Jellyfin.Naming.Tests/TV/EpisodeNumberTests.cs19
-rw-r--r--tests/Jellyfin.Naming.Tests/TV/SeasonNumberTests.cs16
-rw-r--r--tests/Jellyfin.Server.Implementations.Tests/Jellyfin.Server.Implementations.Tests.csproj2
192 files changed, 1739 insertions, 1502 deletions
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
index bd13d4b00..d67e1c98b 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.md
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -10,6 +10,19 @@ assignees: ''
**Describe the bug**
<!-- A clear and concise description of what the bug is. -->
+**System (please complete the following information):**
+ - OS: [e.g. Debian, Windows]
+ - Virtualization: [e.g. Docker, KVM, LXC]
+ - Clients: [Browser, Android, Fire Stick, etc.]
+ - Browser: [e.g. Firefox 72, Chrome 80, Safari 13]
+ - Jellyfin Version: [e.g. 10.4.3, nightly 20191231]
+ - Playback: [Direct Play, Remux, Direct Stream, Transcode]
+ - Installed Plugins: [e.g. none, Fanart, Anime, etc.]
+ - Reverse Proxy: [e.g. none, nginx, apache, etc.]
+ - Base URL: [e.g. none, yes: /example]
+ - Networking: [e.g. Host, Bridge/NAT]
+ - Storage: [e.g. local, NFS, cloud]
+
**To Reproduce**
<!-- Steps to reproduce the behavior: -->
1. Go to '...'
@@ -26,12 +39,5 @@ assignees: ''
**Screenshots**
<!-- If applicable, add screenshots to help explain your problem. -->
-**System (please complete the following information):**
- - OS: [e.g. Docker, Debian, Windows]
- - Browser: [e.g. Firefox, Chrome, Safari]
- - Jellyfin Version: [e.g. 10.0.1]
- - Installed Plugins: [e.g. none, Fanart, Anime, etc.]
- - Reverse proxy: [e.g. no, nginx, apache, etc.]
-
**Additional context**
<!-- Add any other context about the problem here. -->
diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md
index 800b3d51f..2a9779cd5 100644
--- a/CONTRIBUTORS.md
+++ b/CONTRIBUTORS.md
@@ -32,8 +32,10 @@
- [nevado](https://github.com/nevado)
- [mark-monteiro](https://github.com/mark-monteiro)
- [ullmie02](https://github.com/ullmie02)
+ - [geilername](https://github.com/geilername)
- [pR0Ps](https://github.com/pR0Ps)
+
# Emby Contributors
- [LukePulverenti](https://github.com/LukePulverenti)
diff --git a/Dockerfile b/Dockerfile
index 0bccd9d64..1029a4cee 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -3,7 +3,7 @@ ARG FFMPEG_VERSION=latest
FROM node:alpine as web-builder
ARG JELLYFIN_WEB_VERSION=master
-RUN apk add curl \
+RUN apk add curl git \
&& curl -L https://github.com/jellyfin/jellyfin-web/archive/${JELLYFIN_WEB_VERSION}.tar.gz | tar zxf - \
&& cd jellyfin-web-* \
&& yarn install \
diff --git a/Dockerfile.arm b/Dockerfile.arm
index e7cbb0909..5847de918 100644
--- a/Dockerfile.arm
+++ b/Dockerfile.arm
@@ -1,9 +1,13 @@
+# DESIGNED FOR BUILDING ON AMD64 ONLY
+#####################################
+# Requires binfm_misc registration
+# https://github.com/multiarch/qemu-user-static#binfmt_misc-register
ARG DOTNET_VERSION=3.1
FROM node:alpine as web-builder
ARG JELLYFIN_WEB_VERSION=master
-RUN apk add curl \
+RUN apk add curl git \
&& curl -L https://github.com/jellyfin/jellyfin-web/archive/${JELLYFIN_WEB_VERSION}.tar.gz | tar zxf - \
&& cd jellyfin-web-* \
&& yarn install \
@@ -21,7 +25,9 @@ RUN find . -type d -name obj | xargs -r rm -r
RUN dotnet publish Jellyfin.Server --configuration Release --output="/jellyfin" --self-contained --runtime linux-arm "-p:GenerateDocumentationFile=false;DebugSymbols=false;DebugType=none"
-FROM debian:buster-slim
+FROM multiarch/qemu-user-static:x86_64-arm as qemu
+FROM arm32v7/debian:buster-slim
+COPY --from=qemu /usr/bin/qemu-arm-static /usr/bin
RUN apt-get update \
&& apt-get install --no-install-recommends --no-install-suggests -y ffmpeg \
libssl-dev ca-certificates \
diff --git a/Dockerfile.arm64 b/Dockerfile.arm64
index a0cd0dacc..a9f6c50d9 100644
--- a/Dockerfile.arm64
+++ b/Dockerfile.arm64
@@ -1,9 +1,13 @@
+# DESIGNED FOR BUILDING ON AMD64 ONLY
+#####################################
+# Requires binfm_misc registration
+# https://github.com/multiarch/qemu-user-static#binfmt_misc-register
ARG DOTNET_VERSION=3.1
FROM node:alpine as web-builder
ARG JELLYFIN_WEB_VERSION=master
-RUN apk add curl \
+RUN apk add curl git \
&& curl -L https://github.com/jellyfin/jellyfin-web/archive/${JELLYFIN_WEB_VERSION}.tar.gz | tar zxf - \
&& cd jellyfin-web-* \
&& yarn install \
@@ -20,8 +24,9 @@ RUN find . -type d -name obj | xargs -r rm -r
# Build
RUN dotnet publish Jellyfin.Server --configuration Release --output="/jellyfin" --self-contained --runtime linux-arm64 "-p:GenerateDocumentationFile=false;DebugSymbols=false;DebugType=none"
-
-FROM debian:buster-slim
+FROM multiarch/qemu-user-static:x86_64-aarch64 as qemu
+FROM arm64v8/debian:buster-slim
+COPY --from=qemu /usr/bin/qemu-aarch64-static /usr/bin
RUN apt-get update \
&& apt-get install --no-install-recommends --no-install-suggests -y ffmpeg \
libssl-dev ca-certificates \
diff --git a/Emby.Dlna/Api/DlnaServerService.cs b/Emby.Dlna/Api/DlnaServerService.cs
index a7ff6e9cf..4d9933a0c 100644
--- a/Emby.Dlna/Api/DlnaServerService.cs
+++ b/Emby.Dlna/Api/DlnaServerService.cs
@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using System;
using System.IO;
using System.Text;
diff --git a/Emby.Dlna/Api/DlnaService.cs b/Emby.Dlna/Api/DlnaService.cs
index 7f51f477a..f10695541 100644
--- a/Emby.Dlna/Api/DlnaService.cs
+++ b/Emby.Dlna/Api/DlnaService.cs
@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using System.Linq;
using MediaBrowser.Controller.Dlna;
using MediaBrowser.Controller.Net;
diff --git a/Emby.Dlna/Common/Argument.cs b/Emby.Dlna/Common/Argument.cs
index 3e325c41c..c6ab9959e 100644
--- a/Emby.Dlna/Common/Argument.cs
+++ b/Emby.Dlna/Common/Argument.cs
@@ -1,3 +1,5 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
namespace Emby.Dlna.Common
{
diff --git a/Emby.Dlna/Common/DeviceIcon.cs b/Emby.Dlna/Common/DeviceIcon.cs
index 3a91b952e..49d19992d 100644
--- a/Emby.Dlna/Common/DeviceIcon.cs
+++ b/Emby.Dlna/Common/DeviceIcon.cs
@@ -1,3 +1,7 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
+using System.Globalization;
namespace Emby.Dlna.Common
{
@@ -13,9 +17,14 @@ namespace Emby.Dlna.Common
public string Depth { get; set; }
+ /// <inheritdoc />
public override string ToString()
{
- return string.Format("{0}x{1}", Height, Width);
+ return string.Format(
+ CultureInfo.InvariantCulture,
+ "{0}x{1}",
+ Height,
+ Width);
}
}
}
diff --git a/Emby.Dlna/Common/DeviceService.cs b/Emby.Dlna/Common/DeviceService.cs
index c60d65291..9947ec6b9 100644
--- a/Emby.Dlna/Common/DeviceService.cs
+++ b/Emby.Dlna/Common/DeviceService.cs
@@ -1,3 +1,5 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
namespace Emby.Dlna.Common
{
@@ -13,9 +15,8 @@ namespace Emby.Dlna.Common
public string EventSubUrl { get; set; }
+ /// <inheritdoc />
public override string ToString()
- {
- return string.Format("{0}", ServiceId);
- }
+ => ServiceId;
}
}
diff --git a/Emby.Dlna/Common/ServiceAction.cs b/Emby.Dlna/Common/ServiceAction.cs
index 5e030d396..15c4be809 100644
--- a/Emby.Dlna/Common/ServiceAction.cs
+++ b/Emby.Dlna/Common/ServiceAction.cs
@@ -1,21 +1,25 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using System.Collections.Generic;
namespace Emby.Dlna.Common
{
public class ServiceAction
{
+ public ServiceAction()
+ {
+ ArgumentList = new List<Argument>();
+ }
+
public string Name { get; set; }
public List<Argument> ArgumentList { get; set; }
+ /// <inheritdoc />
public override string ToString()
{
return Name;
}
-
- public ServiceAction()
- {
- ArgumentList = new List<Argument>();
- }
}
}
diff --git a/Emby.Dlna/Common/StateVariable.cs b/Emby.Dlna/Common/StateVariable.cs
index 4ca84bf51..bade28e4b 100644
--- a/Emby.Dlna/Common/StateVariable.cs
+++ b/Emby.Dlna/Common/StateVariable.cs
@@ -1,9 +1,17 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using System;
namespace Emby.Dlna.Common
{
public class StateVariable
{
+ public StateVariable()
+ {
+ AllowedValues = Array.Empty<string>();
+ }
+
public string Name { get; set; }
public string DataType { get; set; }
@@ -12,14 +20,8 @@ namespace Emby.Dlna.Common
public string[] AllowedValues { get; set; }
+ /// <inheritdoc />
public override string ToString()
- {
- return Name;
- }
-
- public StateVariable()
- {
- AllowedValues = Array.Empty<string>();
- }
+ => Name;
}
}
diff --git a/Emby.Dlna/Configuration/DlnaOptions.cs b/Emby.Dlna/Configuration/DlnaOptions.cs
index c7cb364a8..84587a7ce 100644
--- a/Emby.Dlna/Configuration/DlnaOptions.cs
+++ b/Emby.Dlna/Configuration/DlnaOptions.cs
@@ -1,17 +1,10 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
namespace Emby.Dlna.Configuration
{
public class DlnaOptions
{
- public bool EnablePlayTo { get; set; }
- public bool EnableServer { get; set; }
- public bool EnableDebugLog { get; set; }
- public bool BlastAliveMessages { get; set; }
- public bool SendOnlyMatchedHost { get; set; }
- public int ClientDiscoveryIntervalSeconds { get; set; }
- public int BlastAliveMessageIntervalSeconds { get; set; }
- public string DefaultUserId { get; set; }
-
public DlnaOptions()
{
EnablePlayTo = true;
@@ -21,5 +14,21 @@ namespace Emby.Dlna.Configuration
ClientDiscoveryIntervalSeconds = 60;
BlastAliveMessageIntervalSeconds = 1800;
}
+
+ public bool EnablePlayTo { get; set; }
+
+ public bool EnableServer { get; set; }
+
+ public bool EnableDebugLog { get; set; }
+
+ public bool BlastAliveMessages { get; set; }
+
+ public bool SendOnlyMatchedHost { get; set; }
+
+ public int ClientDiscoveryIntervalSeconds { get; set; }
+
+ public int BlastAliveMessageIntervalSeconds { get; set; }
+
+ public string DefaultUserId { get; set; }
}
}
diff --git a/Emby.Dlna/ConfigurationExtension.cs b/Emby.Dlna/ConfigurationExtension.cs
index 82d726e01..f8125c12c 100644
--- a/Emby.Dlna/ConfigurationExtension.cs
+++ b/Emby.Dlna/ConfigurationExtension.cs
@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using System.Collections.Generic;
using Emby.Dlna.Configuration;
using MediaBrowser.Common.Configuration;
diff --git a/Emby.Dlna/ConnectionManager/ConnectionManager.cs b/Emby.Dlna/ConnectionManager/ConnectionManager.cs
index 934b353c2..365249c54 100644
--- a/Emby.Dlna/ConnectionManager/ConnectionManager.cs
+++ b/Emby.Dlna/ConnectionManager/ConnectionManager.cs
@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using System.Threading.Tasks;
using Emby.Dlna.Service;
using MediaBrowser.Common.Net;
diff --git a/Emby.Dlna/ConnectionManager/ConnectionManagerXmlBuilder.cs b/Emby.Dlna/ConnectionManager/ConnectionManagerXmlBuilder.cs
index f5873455a..c8c97c79c 100644
--- a/Emby.Dlna/ConnectionManager/ConnectionManagerXmlBuilder.cs
+++ b/Emby.Dlna/ConnectionManager/ConnectionManagerXmlBuilder.cs
@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using System.Collections.Generic;
using Emby.Dlna.Common;
using Emby.Dlna.Service;
diff --git a/Emby.Dlna/ConnectionManager/ControlHandler.cs b/Emby.Dlna/ConnectionManager/ControlHandler.cs
index 2e1104748..b390515b8 100644
--- a/Emby.Dlna/ConnectionManager/ControlHandler.cs
+++ b/Emby.Dlna/ConnectionManager/ControlHandler.cs
@@ -1,5 +1,9 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using System;
using System.Collections.Generic;
+using System.Xml;
using Emby.Dlna.Service;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Controller.Configuration;
@@ -12,29 +16,28 @@ namespace Emby.Dlna.ConnectionManager
{
private readonly DeviceProfile _profile;
- protected override IEnumerable<KeyValuePair<string, string>> GetResult(string methodName, IDictionary<string, string> methodParams)
+ public ControlHandler(IServerConfigurationManager config, ILogger logger, DeviceProfile profile)
+ : base(config, logger)
+ {
+ _profile = profile;
+ }
+
+ /// <inheritdoc />
+ protected override void WriteResult(string methodName, IDictionary<string, string> methodParams, XmlWriter xmlWriter)
{
if (string.Equals(methodName, "GetProtocolInfo", StringComparison.OrdinalIgnoreCase))
{
- return HandleGetProtocolInfo();
+ HandleGetProtocolInfo(xmlWriter);
+ return;
}
throw new ResourceNotFoundException("Unexpected control request name: " + methodName);
}
- private IEnumerable<KeyValuePair<string, string>> HandleGetProtocolInfo()
+ private void HandleGetProtocolInfo(XmlWriter xmlWriter)
{
- return new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
- {
- { "Source", _profile.ProtocolInfo },
- { "Sink", "" }
- };
- }
-
- public ControlHandler(IServerConfigurationManager config, ILogger logger, DeviceProfile profile)
- : base(config, logger)
- {
- _profile = profile;
+ xmlWriter.WriteElementString("Source", _profile.ProtocolInfo);
+ xmlWriter.WriteElementString("Sink", string.Empty);
}
}
}
diff --git a/Emby.Dlna/ConnectionManager/ServiceActionListBuilder.cs b/Emby.Dlna/ConnectionManager/ServiceActionListBuilder.cs
index b7727b558..019a0f80f 100644
--- a/Emby.Dlna/ConnectionManager/ServiceActionListBuilder.cs
+++ b/Emby.Dlna/ConnectionManager/ServiceActionListBuilder.cs
@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using System.Collections.Generic;
using Emby.Dlna.Common;
diff --git a/Emby.Dlna/ContentDirectory/ContentDirectory.cs b/Emby.Dlna/ContentDirectory/ContentDirectory.cs
index a3062b18f..523430e43 100644
--- a/Emby.Dlna/ContentDirectory/ContentDirectory.cs
+++ b/Emby.Dlna/ContentDirectory/ContentDirectory.cs
@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using System;
using System.Threading.Tasks;
using Emby.Dlna.Service;
diff --git a/Emby.Dlna/ContentDirectory/ContentDirectoryXmlBuilder.cs b/Emby.Dlna/ContentDirectory/ContentDirectoryXmlBuilder.cs
index 15fdb36c4..282a47c73 100644
--- a/Emby.Dlna/ContentDirectory/ContentDirectoryXmlBuilder.cs
+++ b/Emby.Dlna/ContentDirectory/ContentDirectoryXmlBuilder.cs
@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using System.Collections.Generic;
using Emby.Dlna.Common;
using Emby.Dlna.Service;
diff --git a/Emby.Dlna/ContentDirectory/ControlHandler.cs b/Emby.Dlna/ContentDirectory/ControlHandler.cs
index 396649c5e..1278b367c 100644
--- a/Emby.Dlna/ContentDirectory/ControlHandler.cs
+++ b/Emby.Dlna/ContentDirectory/ControlHandler.cs
@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using System;
using System.Collections.Generic;
using System.Globalization;
@@ -44,7 +47,6 @@ namespace Emby.Dlna.ContentDirectory
private const string NS_UPNP = "urn:schemas-upnp-org:metadata-1-0/upnp/";
private readonly int _systemUpdateId;
- private readonly CultureInfo _usCulture = new CultureInfo("en-US");
private readonly DidlBuilder _didlBuilder;
@@ -58,7 +60,8 @@ namespace Emby.Dlna.ContentDirectory
string accessToken,
IImageProcessor imageProcessor,
IUserDataManager userDataManager,
- User user, int systemUpdateId,
+ User user,
+ int systemUpdateId,
IServerConfigurationManager config,
ILocalizationManager localization,
IMediaSourceManager mediaSourceManager,
@@ -79,114 +82,129 @@ namespace Emby.Dlna.ContentDirectory
_didlBuilder = new DidlBuilder(profile, user, imageProcessor, serverAddress, accessToken, userDataManager, localization, mediaSourceManager, Logger, mediaEncoder);
}
- protected override IEnumerable<KeyValuePair<string, string>> GetResult(string methodName, IDictionary<string, string> methodParams)
+ /// <inheritdoc />
+ protected override void WriteResult(string methodName, IDictionary<string, string> methodParams, XmlWriter xmlWriter)
{
- var deviceId = "test";
-
- var user = _user;
+ const string DeviceId = "test";
if (string.Equals(methodName, "GetSearchCapabilities", StringComparison.OrdinalIgnoreCase))
- return HandleGetSearchCapabilities();
+ {
+ HandleGetSearchCapabilities(xmlWriter);
+ return;
+ }
if (string.Equals(methodName, "GetSortCapabilities", StringComparison.OrdinalIgnoreCase))
- return HandleGetSortCapabilities();
+ {
+ HandleGetSortCapabilities(xmlWriter);
+ return;
+ }
if (string.Equals(methodName, "GetSortExtensionCapabilities", StringComparison.OrdinalIgnoreCase))
- return HandleGetSortExtensionCapabilities();
+ {
+ HandleGetSortExtensionCapabilities(xmlWriter);
+ return;
+ }
if (string.Equals(methodName, "GetSystemUpdateID", StringComparison.OrdinalIgnoreCase))
- return HandleGetSystemUpdateID();
+ {
+ HandleGetSystemUpdateID(xmlWriter);
+ return;
+ }
if (string.Equals(methodName, "Browse", StringComparison.OrdinalIgnoreCase))
- return HandleBrowse(methodParams, user, deviceId);
+ {
+ HandleBrowse(xmlWriter, methodParams, DeviceId);
+ return;
+ }
if (string.Equals(methodName, "X_GetFeatureList", StringComparison.OrdinalIgnoreCase))
- return HandleXGetFeatureList();
+ {
+ HandleXGetFeatureList(xmlWriter);
+ return;
+ }
if (string.Equals(methodName, "GetFeatureList", StringComparison.OrdinalIgnoreCase))
- return HandleGetFeatureList();
+ {
+ HandleGetFeatureList(xmlWriter);
+ return;
+ }
if (string.Equals(methodName, "X_SetBookmark", StringComparison.OrdinalIgnoreCase))
- return HandleXSetBookmark(methodParams, user);
+ {
+ HandleXSetBookmark(methodParams);
+ return;
+ }
if (string.Equals(methodName, "Search", StringComparison.OrdinalIgnoreCase))
- return HandleSearch(methodParams, user, deviceId);
+ {
+ HandleSearch(xmlWriter, methodParams, DeviceId);
+ return;
+ }
if (string.Equals(methodName, "X_BrowseByLetter", StringComparison.OrdinalIgnoreCase))
- return HandleX_BrowseByLetter(methodParams, user, deviceId);
+ {
+ HandleXBrowseByLetter(xmlWriter, methodParams, DeviceId);
+ return;
+ }
throw new ResourceNotFoundException("Unexpected control request name: " + methodName);
}
- private IEnumerable<KeyValuePair<string, string>> HandleXSetBookmark(IDictionary<string, string> sparams, User user)
+ private void HandleXSetBookmark(IDictionary<string, string> sparams)
{
var id = sparams["ObjectID"];
- var serverItem = GetItemFromObjectId(id, user);
+ var serverItem = GetItemFromObjectId(id, _user);
var item = serverItem.Item;
- var newbookmark = int.Parse(sparams["PosSecond"], _usCulture);
+ var newbookmark = int.Parse(sparams["PosSecond"], CultureInfo.InvariantCulture);
- var userdata = _userDataManager.GetUserData(user, item);
+ var userdata = _userDataManager.GetUserData(_user, item);
userdata.PlaybackPositionTicks = TimeSpan.FromSeconds(newbookmark).Ticks;
- _userDataManager.SaveUserData(user, item, userdata, UserDataSaveReason.TogglePlayed,
+ _userDataManager.SaveUserData(_user, item, userdata, UserDataSaveReason.TogglePlayed,
CancellationToken.None);
-
- return new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
}
- private IEnumerable<KeyValuePair<string, string>> HandleGetSearchCapabilities()
+ private void HandleGetSearchCapabilities(XmlWriter xmlWriter)
{
- return new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
- {
- { "SearchCaps", "res@resolution,res@size,res@duration,dc:title,dc:creator,upnp:actor,upnp:artist,upnp:genre,upnp:album,dc:date,upnp:class,@id,@refID,@protocolInfo,upnp:author,dc:description,pv:avKeywords" }
- };
+ xmlWriter.WriteElementString(
+ "SearchCaps",
+ "res@resolution,res@size,res@duration,dc:title,dc:creator,upnp:actor,upnp:artist,upnp:genre,upnp:album,dc:date,upnp:class,@id,@refID,@protocolInfo,upnp:author,dc:description,pv:avKeywords");
}
- private IEnumerable<KeyValuePair<string, string>> HandleGetSortCapabilities()
+ private void HandleGetSortCapabilities(XmlWriter xmlWriter)
{
- return new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
- {
- { "SortCaps", "res@duration,res@size,res@bitrate,dc:date,dc:title,dc:size,upnp:album,upnp:artist,upnp:albumArtist,upnp:episodeNumber,upnp:genre,upnp:originalTrackNumber,upnp:rating" }
- };
+ xmlWriter.WriteElementString(
+ "SortCaps",
+ "res@duration,res@size,res@bitrate,dc:date,dc:title,dc:size,upnp:album,upnp:artist,upnp:albumArtist,upnp:episodeNumber,upnp:genre,upnp:originalTrackNumber,upnp:rating");
}
- private IEnumerable<KeyValuePair<string, string>> HandleGetSortExtensionCapabilities()
+ private void HandleGetSortExtensionCapabilities(XmlWriter xmlWriter)
{
- return new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
- {
- { "SortExtensionCaps", "res@duration,res@size,res@bitrate,dc:date,dc:title,dc:size,upnp:album,upnp:artist,upnp:albumArtist,upnp:episodeNumber,upnp:genre,upnp:originalTrackNumber,upnp:rating" }
- };
+ xmlWriter.WriteElementString(
+ "SortExtensionCaps",
+ "res@duration,res@size,res@bitrate,dc:date,dc:title,dc:size,upnp:album,upnp:artist,upnp:albumArtist,upnp:episodeNumber,upnp:genre,upnp:originalTrackNumber,upnp:rating");
}
- private IEnumerable<KeyValuePair<string, string>> HandleGetSystemUpdateID()
+ private void HandleGetSystemUpdateID(XmlWriter xmlWriter)
{
- var headers = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
- headers.Add("Id", _systemUpdateId.ToString(_usCulture));
- return headers;
+ xmlWriter.WriteElementString("Id", _systemUpdateId.ToString(CultureInfo.InvariantCulture));
}
- private IEnumerable<KeyValuePair<string, string>> HandleGetFeatureList()
+ private void HandleGetFeatureList(XmlWriter xmlWriter)
{
- return new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
- {
- { "FeatureList", GetFeatureListXml() }
- };
+ xmlWriter.WriteElementString("FeatureList", WriteFeatureListXml());
}
- private IEnumerable<KeyValuePair<string, string>> HandleXGetFeatureList()
- {
- return new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
- {
- { "FeatureList", GetFeatureListXml() }
- };
- }
+ private void HandleXGetFeatureList(XmlWriter xmlWriter)
+ => HandleGetFeatureList(xmlWriter);
- private string GetFeatureListXml()
+ private string WriteFeatureListXml()
{
+ // TODO: clean this up
var builder = new StringBuilder();
builder.Append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
@@ -213,7 +231,7 @@ namespace Emby.Dlna.ContentDirectory
return defaultValue;
}
- private IEnumerable<KeyValuePair<string, string>> HandleBrowse(IDictionary<string, string> sparams, User user, string deviceId)
+ private void HandleBrowse(XmlWriter xmlWriter, IDictionary<string, string> sparams, string deviceId)
{
var id = sparams["ObjectID"];
var flag = sparams["BrowseFlag"];
@@ -237,101 +255,95 @@ namespace Emby.Dlna.ContentDirectory
start = startVal;
}
- var settings = new XmlWriterSettings
- {
- Encoding = Encoding.UTF8,
- CloseOutput = false,
- OmitXmlDeclaration = true,
- ConformanceLevel = ConformanceLevel.Fragment
- };
-
- StringWriter builder = new StringWriterWithEncoding(Encoding.UTF8);
-
int totalCount;
- var dlnaOptions = _config.GetDlnaConfiguration();
-
- using (var writer = XmlWriter.Create(builder, settings))
+ using (StringWriter builder = new StringWriterWithEncoding(Encoding.UTF8))
{
- //writer.WriteStartDocument();
-
- writer.WriteStartElement(string.Empty, "DIDL-Lite", NS_DIDL);
-
- writer.WriteAttributeString("xmlns", "dc", null, NS_DC);
- writer.WriteAttributeString("xmlns", "dlna", null, NS_DLNA);
- writer.WriteAttributeString("xmlns", "upnp", null, NS_UPNP);
- //didl.SetAttribute("xmlns:sec", NS_SEC);
-
- DidlBuilder.WriteXmlRootAttributes(_profile, writer);
-
- var serverItem = GetItemFromObjectId(id, user);
- var item = serverItem.Item;
+ var settings = new XmlWriterSettings()
+ {
+ Encoding = Encoding.UTF8,
+ CloseOutput = false,
+ OmitXmlDeclaration = true,
+ ConformanceLevel = ConformanceLevel.Fragment
+ };
- if (string.Equals(flag, "BrowseMetadata"))
+ using (var writer = XmlWriter.Create(builder, settings))
{
- totalCount = 1;
+ writer.WriteStartElement(string.Empty, "DIDL-Lite", NS_DIDL);
- if (item.IsDisplayedAsFolder || serverItem.StubType.HasValue)
- {
- var childrenResult = GetUserItems(item, serverItem.StubType, user, sortCriteria, start, requestedCount);
+ writer.WriteAttributeString("xmlns", "dc", null, NS_DC);
+ writer.WriteAttributeString("xmlns", "dlna", null, NS_DLNA);
+ writer.WriteAttributeString("xmlns", "upnp", null, NS_UPNP);
- _didlBuilder.WriteFolderElement(writer, item, serverItem.StubType, null, childrenResult.TotalRecordCount, filter, id);
- }
- else
- {
- _didlBuilder.WriteItemElement(dlnaOptions, writer, item, user, null, null, deviceId, filter);
- }
+ DidlBuilder.WriteXmlRootAttributes(_profile, writer);
- provided++;
- }
- else
- {
- var childrenResult = GetUserItems(item, serverItem.StubType, user, sortCriteria, start, requestedCount);
- totalCount = childrenResult.TotalRecordCount;
+ var serverItem = GetItemFromObjectId(id, _user);
+ var item = serverItem.Item;
- provided = childrenResult.Items.Count;
- foreach (var i in childrenResult.Items)
+ if (string.Equals(flag, "BrowseMetadata", StringComparison.Ordinal))
{
- var childItem = i.Item;
- var displayStubType = i.StubType;
+ totalCount = 1;
- if (childItem.IsDisplayedAsFolder || displayStubType.HasValue)
+ if (item.IsDisplayedAsFolder || serverItem.StubType.HasValue)
{
- var childCount = (GetUserItems(childItem, displayStubType, user, sortCriteria, null, 0))
- .TotalRecordCount;
+ var childrenResult = GetUserItems(item, serverItem.StubType, _user, sortCriteria, start, requestedCount);
- _didlBuilder.WriteFolderElement(writer, childItem, displayStubType, item, childCount, filter);
+ _didlBuilder.WriteFolderElement(writer, item, serverItem.StubType, null, childrenResult.TotalRecordCount, filter, id);
}
else
{
- _didlBuilder.WriteItemElement(dlnaOptions, writer, childItem, user, item, serverItem.StubType, deviceId, filter);
+ var dlnaOptions = _config.GetDlnaConfiguration();
+ _didlBuilder.WriteItemElement(dlnaOptions, writer, item, _user, null, null, deviceId, filter);
}
+
+ provided++;
}
+ else
+ {
+ var childrenResult = GetUserItems(item, serverItem.StubType, _user, sortCriteria, start, requestedCount);
+ totalCount = childrenResult.TotalRecordCount;
+
+ provided = childrenResult.Items.Count;
+
+ var dlnaOptions = _config.GetDlnaConfiguration();
+ foreach (var i in childrenResult.Items)
+ {
+ var childItem = i.Item;
+ var displayStubType = i.StubType;
+
+ if (childItem.IsDisplayedAsFolder || displayStubType.HasValue)
+ {
+ var childCount = GetUserItems(childItem, displayStubType, _user, sortCriteria, null, 0)
+ .TotalRecordCount;
+
+ _didlBuilder.WriteFolderElement(writer, childItem, displayStubType, item, childCount, filter);
+ }
+ else
+ {
+ _didlBuilder.WriteItemElement(dlnaOptions, writer, childItem, _user, item, serverItem.StubType, deviceId, filter);
+ }
+ }
+ }
+
+ writer.WriteFullEndElement();
}
- writer.WriteFullEndElement();
- //writer.WriteEndDocument();
+ xmlWriter.WriteElementString("Result", builder.ToString());
}
- var resXML = builder.ToString();
-
- return new[]
- {
- new KeyValuePair<string,string>("Result", resXML),
- new KeyValuePair<string,string>("NumberReturned", provided.ToString(_usCulture)),
- new KeyValuePair<string,string>("TotalMatches", totalCount.ToString(_usCulture)),
- new KeyValuePair<string,string>("UpdateID", _systemUpdateId.ToString(_usCulture))
- };
+ xmlWriter.WriteElementString("NumberReturned", provided.ToString(CultureInfo.InvariantCulture));
+ xmlWriter.WriteElementString("TotalMatches", totalCount.ToString(CultureInfo.InvariantCulture));
+ xmlWriter.WriteElementString("UpdateID", _systemUpdateId.ToString(CultureInfo.InvariantCulture));
}
- private IEnumerable<KeyValuePair<string, string>> HandleX_BrowseByLetter(IDictionary<string, string> sparams, User user, string deviceId)
+ private void HandleXBrowseByLetter(XmlWriter xmlWriter, IDictionary<string, string> sparams, string deviceId)
{
// TODO: Implement this method
- return HandleSearch(sparams, user, deviceId);
+ HandleSearch(xmlWriter, sparams, deviceId);
}
- private IEnumerable<KeyValuePair<string, string>> HandleSearch(IDictionary<string, string> sparams, User user, string deviceId)
+ private void HandleSearch(XmlWriter xmlWriter, IDictionary<string, string> sparams, string deviceId)
{
var searchCriteria = new SearchCriteria(GetValueOrDefault(sparams, "SearchCriteria", ""));
var sortCriteria = new SortCriteria(GetValueOrDefault(sparams, "SortCriteria", ""));
@@ -354,99 +366,86 @@ namespace Emby.Dlna.ContentDirectory
start = startVal;
}
- var settings = new XmlWriterSettings
- {
- Encoding = Encoding.UTF8,
- CloseOutput = false,
- OmitXmlDeclaration = true,
- ConformanceLevel = ConformanceLevel.Fragment
- };
-
- StringWriter builder = new StringWriterWithEncoding(Encoding.UTF8);
- int totalCount = 0;
- int provided = 0;
+ QueryResult<BaseItem> childrenResult;
- using (var writer = XmlWriter.Create(builder, settings))
+ using (StringWriter builder = new StringWriterWithEncoding(Encoding.UTF8))
{
- //writer.WriteStartDocument();
-
- writer.WriteStartElement(string.Empty, "DIDL-Lite", NS_DIDL);
-
- writer.WriteAttributeString("xmlns", "dc", null, NS_DC);
- writer.WriteAttributeString("xmlns", "dlna", null, NS_DLNA);
- writer.WriteAttributeString("xmlns", "upnp", null, NS_UPNP);
- //didl.SetAttribute("xmlns:sec", NS_SEC);
+ var settings = new XmlWriterSettings()
+ {
+ Encoding = Encoding.UTF8,
+ CloseOutput = false,
+ OmitXmlDeclaration = true,
+ ConformanceLevel = ConformanceLevel.Fragment
+ };
- DidlBuilder.WriteXmlRootAttributes(_profile, writer);
+ using (var writer = XmlWriter.Create(builder, settings))
+ {
+ writer.WriteStartElement(string.Empty, "DIDL-Lite", NS_DIDL);
- var serverItem = GetItemFromObjectId(sparams["ContainerID"], user);
+ writer.WriteAttributeString("xmlns", "dc", null, NS_DC);
+ writer.WriteAttributeString("xmlns", "dlna", null, NS_DLNA);
+ writer.WriteAttributeString("xmlns", "upnp", null, NS_UPNP);
- var item = serverItem.Item;
+ DidlBuilder.WriteXmlRootAttributes(_profile, writer);
- var childrenResult = (GetChildrenSorted(item, user, searchCriteria, sortCriteria, start, requestedCount));
+ var serverItem = GetItemFromObjectId(sparams["ContainerID"], _user);
- totalCount = childrenResult.TotalRecordCount;
+ var item = serverItem.Item;
- provided = childrenResult.Items.Count;
+ childrenResult = GetChildrenSorted(item, _user, searchCriteria, sortCriteria, start, requestedCount);
- var dlnaOptions = _config.GetDlnaConfiguration();
+ var dlnaOptions = _config.GetDlnaConfiguration();
- foreach (var i in childrenResult.Items)
- {
- if (i.IsDisplayedAsFolder)
+ foreach (var i in childrenResult.Items)
{
- var childCount = (GetChildrenSorted(i, user, searchCriteria, sortCriteria, null, 0))
- .TotalRecordCount;
+ if (i.IsDisplayedAsFolder)
+ {
+ var childCount = GetChildrenSorted(i, _user, searchCriteria, sortCriteria, null, 0)
+ .TotalRecordCount;
- _didlBuilder.WriteFolderElement(writer, i, null, item, childCount, filter);
- }
- else
- {
- _didlBuilder.WriteItemElement(dlnaOptions, writer, i, user, item, serverItem.StubType, deviceId, filter);
+ _didlBuilder.WriteFolderElement(writer, i, null, item, childCount, filter);
+ }
+ else
+ {
+ _didlBuilder.WriteItemElement(dlnaOptions, writer, i, _user, item, serverItem.StubType, deviceId, filter);
+ }
}
+
+ writer.WriteFullEndElement();
}
- writer.WriteFullEndElement();
- //writer.WriteEndDocument();
+ xmlWriter.WriteElementString("Result", builder.ToString());
}
- var resXML = builder.ToString();
-
- return new List<KeyValuePair<string, string>>
- {
- new KeyValuePair<string,string>("Result", resXML),
- new KeyValuePair<string,string>("NumberReturned", provided.ToString(_usCulture)),
- new KeyValuePair<string,string>("TotalMatches", totalCount.ToString(_usCulture)),
- new KeyValuePair<string,string>("UpdateID", _systemUpdateId.ToString(_usCulture))
- };
+ xmlWriter.WriteElementString("NumberReturned", childrenResult.Items.Count.ToString(CultureInfo.InvariantCulture));
+ xmlWriter.WriteElementString("TotalMatches", childrenResult.TotalRecordCount.ToString(CultureInfo.InvariantCulture));
+ xmlWriter.WriteElementString("UpdateID", _systemUpdateId.ToString(CultureInfo.InvariantCulture));
}
private QueryResult<BaseItem> GetChildrenSorted(BaseItem item, User user, SearchCriteria search, SortCriteria sort, int? startIndex, int? limit)
{
var folder = (Folder)item;
- var sortOrders = new List<(string, SortOrder)>();
- if (!folder.IsPreSorted)
- {
- sortOrders.Add((ItemSortBy.SortName, sort.SortOrder));
- }
+ var sortOrders = folder.IsPreSorted
+ ? Array.Empty<(string, SortOrder)>()
+ : new[] { (ItemSortBy.SortName, sort.SortOrder) };
- var mediaTypes = new List<string>();
+ string[] mediaTypes = Array.Empty<string>();
bool? isFolder = null;
if (search.SearchType == SearchType.Audio)
{
- mediaTypes.Add(MediaType.Audio);
+ mediaTypes = new[] { MediaType.Audio };
isFolder = false;
}
else if (search.SearchType == SearchType.Video)
{
- mediaTypes.Add(MediaType.Video);
+ mediaTypes = new[] { MediaType.Video };
isFolder = false;
}
else if (search.SearchType == SearchType.Image)
{
- mediaTypes.Add(MediaType.Photo);
+ mediaTypes = new[] { MediaType.Photo };
isFolder = false;
}
else if (search.SearchType == SearchType.Playlist)
@@ -470,7 +469,7 @@ namespace Emby.Dlna.ContentDirectory
IsMissing = false,
ExcludeItemTypes = new[] { typeof(Book).Name },
IsFolder = isFolder,
- MediaTypes = mediaTypes.ToArray(),
+ MediaTypes = mediaTypes,
DtoOptions = GetDtoOptions()
});
}
@@ -1304,11 +1303,11 @@ namespace Emby.Dlna.ContentDirectory
StubType? stubType = null;
// After using PlayTo, MediaMonkey sends a request to the server trying to get item info
- const string paramsSrch = "Params=";
- var paramsIndex = id.IndexOf(paramsSrch, StringComparison.OrdinalIgnoreCase);
+ const string ParamsSrch = "Params=";
+ var paramsIndex = id.IndexOf(ParamsSrch, StringComparison.OrdinalIgnoreCase);
if (paramsIndex != -1)
{
- id = id.Substring(paramsIndex + paramsSrch.Length);
+ id = id.Substring(paramsIndex + ParamsSrch.Length);
var parts = id.Split(';');
id = parts[23];
diff --git a/Emby.Dlna/ContentDirectory/ServiceActionListBuilder.cs b/Emby.Dlna/ContentDirectory/ServiceActionListBuilder.cs
index e999314fa..a385a74cf 100644
--- a/Emby.Dlna/ContentDirectory/ServiceActionListBuilder.cs
+++ b/Emby.Dlna/ContentDirectory/ServiceActionListBuilder.cs
@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using System.Collections.Generic;
using Emby.Dlna.Common;
diff --git a/Emby.Dlna/ControlRequest.cs b/Emby.Dlna/ControlRequest.cs
index 8c227159c..97ad41c83 100644
--- a/Emby.Dlna/ControlRequest.cs
+++ b/Emby.Dlna/ControlRequest.cs
@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using System.IO;
using Microsoft.AspNetCore.Http;
diff --git a/Emby.Dlna/ControlResponse.cs b/Emby.Dlna/ControlResponse.cs
index d2b79fc58..0215a5e38 100644
--- a/Emby.Dlna/ControlResponse.cs
+++ b/Emby.Dlna/ControlResponse.cs
@@ -1,18 +1,21 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using System.Collections.Generic;
namespace Emby.Dlna
{
public class ControlResponse
{
+ public ControlResponse()
+ {
+ Headers = new Dictionary<string, string>();
+ }
+
public IDictionary<string, string> Headers { get; set; }
public string Xml { get; set; }
public bool IsSuccessful { get; set; }
-
- public ControlResponse()
- {
- Headers = new Dictionary<string, string>();
- }
}
}
diff --git a/Emby.Dlna/Didl/DidlBuilder.cs b/Emby.Dlna/Didl/DidlBuilder.cs
index a5e46df78..145639ab0 100644
--- a/Emby.Dlna/Didl/DidlBuilder.cs
+++ b/Emby.Dlna/Didl/DidlBuilder.cs
@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using System;
using System.Globalization;
using System.IO;
@@ -631,7 +634,7 @@ namespace Emby.Dlna.Didl
{
if (item.PremiereDate.HasValue)
{
- AddValue(writer, "dc", "date", item.PremiereDate.Value.ToString("o"), NS_DC);
+ AddValue(writer, "dc", "date", item.PremiereDate.Value.ToString("o", CultureInfo.InvariantCulture), NS_DC);
}
}
diff --git a/Emby.Dlna/Didl/Filter.cs b/Emby.Dlna/Didl/Filter.cs
index e7f9577ee..792d79770 100644
--- a/Emby.Dlna/Didl/Filter.cs
+++ b/Emby.Dlna/Didl/Filter.cs
@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using System;
using MediaBrowser.Model.Extensions;
diff --git a/Emby.Dlna/Didl/StringWriterWithEncoding.cs b/Emby.Dlna/Didl/StringWriterWithEncoding.cs
index c3c4bd393..edc258899 100644
--- a/Emby.Dlna/Didl/StringWriterWithEncoding.cs
+++ b/Emby.Dlna/Didl/StringWriterWithEncoding.cs
@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using System;
using System.IO;
using System.Text;
diff --git a/Emby.Dlna/DlnaManager.cs b/Emby.Dlna/DlnaManager.cs
index 7e744e0aa..c5b9e5fbe 100644
--- a/Emby.Dlna/DlnaManager.cs
+++ b/Emby.Dlna/DlnaManager.cs
@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using System;
using System.Collections.Generic;
using System.Globalization;
diff --git a/Emby.Dlna/Emby.Dlna.csproj b/Emby.Dlna/Emby.Dlna.csproj
index 8d6fabdb4..0cabe43d5 100644
--- a/Emby.Dlna/Emby.Dlna.csproj
+++ b/Emby.Dlna/Emby.Dlna.csproj
@@ -15,6 +15,19 @@
<TargetFramework>netstandard2.1</TargetFramework>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
+ <TreatWarningsAsErrors Condition=" '$(Configuration)' == 'Release'" >true</TreatWarningsAsErrors>
+ </PropertyGroup>
+
+ <!-- Code Analyzers-->
+ <ItemGroup Condition=" '$(Configuration)' == 'Debug' ">
+ <PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.9.8" PrivateAssets="All" />
+ <PackageReference Include="SerilogAnalyzer" Version="0.15.0" PrivateAssets="All" />
+ <PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="All" />
+ <PackageReference Include="SmartAnalyzers.MultithreadingAnalyzer" Version="1.1.31" PrivateAssets="All" />
+ </ItemGroup>
+
+ <PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
+ <CodeAnalysisRuleSet>../jellyfin.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
diff --git a/Emby.Dlna/EventSubscriptionResponse.cs b/Emby.Dlna/EventSubscriptionResponse.cs
index 6dc1aacf4..f90d273c4 100644
--- a/Emby.Dlna/EventSubscriptionResponse.cs
+++ b/Emby.Dlna/EventSubscriptionResponse.cs
@@ -1,17 +1,21 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using System.Collections.Generic;
namespace Emby.Dlna
{
public class EventSubscriptionResponse
{
- public string Content { get; set; }
- public string ContentType { get; set; }
-
- public Dictionary<string, string> Headers { get; set; }
-
public EventSubscriptionResponse()
{
Headers = new Dictionary<string, string>();
}
+
+ public string Content { get; set; }
+
+ public string ContentType { get; set; }
+
+ public Dictionary<string, string> Headers { get; set; }
}
}
diff --git a/Emby.Dlna/Eventing/EventManager.cs b/Emby.Dlna/Eventing/EventManager.cs
index b76a0066d..788189880 100644
--- a/Emby.Dlna/Eventing/EventManager.cs
+++ b/Emby.Dlna/Eventing/EventManager.cs
@@ -1,8 +1,12 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
+using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using MediaBrowser.Common.Extensions;
@@ -164,7 +168,7 @@ namespace Emby.Dlna.Eventing
try
{
- using (await _httpClient.SendAsync(options, "NOTIFY").ConfigureAwait(false))
+ using (await _httpClient.SendAsync(options, new HttpMethod("NOTIFY")).ConfigureAwait(false))
{
}
diff --git a/Emby.Dlna/Eventing/EventSubscription.cs b/Emby.Dlna/Eventing/EventSubscription.cs
index eb8781e0c..108ab4830 100644
--- a/Emby.Dlna/Eventing/EventSubscription.cs
+++ b/Emby.Dlna/Eventing/EventSubscription.cs
@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using System;
namespace Emby.Dlna.Eventing
@@ -13,6 +16,8 @@ namespace Emby.Dlna.Eventing
public long TriggerCount { get; set; }
+ public bool IsExpired => SubscriptionTime.AddSeconds(TimeoutSeconds) >= DateTime.UtcNow;
+
public void IncrementTriggerCount()
{
if (TriggerCount == long.MaxValue)
@@ -22,7 +27,5 @@ namespace Emby.Dlna.Eventing
TriggerCount++;
}
-
- public bool IsExpired => SubscriptionTime.AddSeconds(TimeoutSeconds) >= DateTime.UtcNow;
}
}
diff --git a/Emby.Dlna/IConnectionManager.cs b/Emby.Dlna/IConnectionManager.cs
index 855c4454d..01fb869f5 100644
--- a/Emby.Dlna/IConnectionManager.cs
+++ b/Emby.Dlna/IConnectionManager.cs
@@ -1,3 +1,5 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
namespace Emby.Dlna
{
diff --git a/Emby.Dlna/IContentDirectory.cs b/Emby.Dlna/IContentDirectory.cs
index b54a17c00..a28ad2b9c 100644
--- a/Emby.Dlna/IContentDirectory.cs
+++ b/Emby.Dlna/IContentDirectory.cs
@@ -1,3 +1,5 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
namespace Emby.Dlna
{
diff --git a/Emby.Dlna/IEventManager.cs b/Emby.Dlna/IEventManager.cs
index 4f67a1b9b..d0960aa16 100644
--- a/Emby.Dlna/IEventManager.cs
+++ b/Emby.Dlna/IEventManager.cs
@@ -1,3 +1,5 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
namespace Emby.Dlna
{
diff --git a/Emby.Dlna/IMediaReceiverRegistrar.cs b/Emby.Dlna/IMediaReceiverRegistrar.cs
index 5dde01f58..d2aaa8f55 100644
--- a/Emby.Dlna/IMediaReceiverRegistrar.cs
+++ b/Emby.Dlna/IMediaReceiverRegistrar.cs
@@ -1,3 +1,5 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
namespace Emby.Dlna
{
diff --git a/Emby.Dlna/IUpnpService.cs b/Emby.Dlna/IUpnpService.cs
index 0f3d327ed..289e2df78 100644
--- a/Emby.Dlna/IUpnpService.cs
+++ b/Emby.Dlna/IUpnpService.cs
@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using System.Threading.Tasks;
namespace Emby.Dlna
diff --git a/Emby.Dlna/Main/DlnaEntryPoint.cs b/Emby.Dlna/Main/DlnaEntryPoint.cs
index 77bde0ca2..1ee4151e4 100644
--- a/Emby.Dlna/Main/DlnaEntryPoint.cs
+++ b/Emby.Dlna/Main/DlnaEntryPoint.cs
@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using System;
using System.Net.Sockets;
using System.Globalization;
diff --git a/Emby.Dlna/MediaReceiverRegistrar/ControlHandler.cs b/Emby.Dlna/MediaReceiverRegistrar/ControlHandler.cs
index 7381e5258..815aac5c7 100644
--- a/Emby.Dlna/MediaReceiverRegistrar/ControlHandler.cs
+++ b/Emby.Dlna/MediaReceiverRegistrar/ControlHandler.cs
@@ -1,5 +1,9 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using System;
using System.Collections.Generic;
+using System.Xml;
using Emby.Dlna.Service;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Controller.Configuration;
@@ -9,35 +13,33 @@ namespace Emby.Dlna.MediaReceiverRegistrar
{
public class ControlHandler : BaseControlHandler
{
- protected override IEnumerable<KeyValuePair<string, string>> GetResult(string methodName, IDictionary<string, string> methodParams)
+ public ControlHandler(IServerConfigurationManager config, ILogger logger)
+ : base(config, logger)
{
- if (string.Equals(methodName, "IsAuthorized", StringComparison.OrdinalIgnoreCase))
- return HandleIsAuthorized();
- if (string.Equals(methodName, "IsValidated", StringComparison.OrdinalIgnoreCase))
- return HandleIsValidated();
-
- throw new ResourceNotFoundException("Unexpected control request name: " + methodName);
}
- private static IEnumerable<KeyValuePair<string, string>> HandleIsAuthorized()
+ /// <inheritdoc />
+ protected override void WriteResult(string methodName, IDictionary<string, string> methodParams, XmlWriter xmlWriter)
{
- return new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
+ if (string.Equals(methodName, "IsAuthorized", StringComparison.OrdinalIgnoreCase))
{
- { "Result", "1" }
- };
- }
+ HandleIsAuthorized(xmlWriter);
+ return;
+ }
- private static IEnumerable<KeyValuePair<string, string>> HandleIsValidated()
- {
- return new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
+ if (string.Equals(methodName, "IsValidated", StringComparison.OrdinalIgnoreCase))
{
- { "Result", "1" }
- };
- }
+ HandleIsValidated(xmlWriter);
+ return;
+ }
- public ControlHandler(IServerConfigurationManager config, ILogger logger)
- : base(config, logger)
- {
+ throw new ResourceNotFoundException("Unexpected control request name: " + methodName);
}
+
+ private static void HandleIsAuthorized(XmlWriter xmlWriter)
+ => xmlWriter.WriteElementString("Result", "1");
+
+ private static void HandleIsValidated(XmlWriter xmlWriter)
+ => xmlWriter.WriteElementString("Result", "1");
}
}
diff --git a/Emby.Dlna/MediaReceiverRegistrar/MediaReceiverRegistrar.cs b/Emby.Dlna/MediaReceiverRegistrar/MediaReceiverRegistrar.cs
index 5eab6aee0..e2d48bc01 100644
--- a/Emby.Dlna/MediaReceiverRegistrar/MediaReceiverRegistrar.cs
+++ b/Emby.Dlna/MediaReceiverRegistrar/MediaReceiverRegistrar.cs
@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using System.Threading.Tasks;
using Emby.Dlna.Service;
using MediaBrowser.Common.Net;
diff --git a/Emby.Dlna/MediaReceiverRegistrar/MediaReceiverRegistrarXmlBuilder.cs b/Emby.Dlna/MediaReceiverRegistrar/MediaReceiverRegistrarXmlBuilder.cs
index 641341185..465b08f58 100644
--- a/Emby.Dlna/MediaReceiverRegistrar/MediaReceiverRegistrarXmlBuilder.cs
+++ b/Emby.Dlna/MediaReceiverRegistrar/MediaReceiverRegistrarXmlBuilder.cs
@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using System.Collections.Generic;
using Emby.Dlna.Common;
using Emby.Dlna.Service;
diff --git a/Emby.Dlna/MediaReceiverRegistrar/ServiceActionListBuilder.cs b/Emby.Dlna/MediaReceiverRegistrar/ServiceActionListBuilder.cs
index 86429f605..3e8b2dbd8 100644
--- a/Emby.Dlna/MediaReceiverRegistrar/ServiceActionListBuilder.cs
+++ b/Emby.Dlna/MediaReceiverRegistrar/ServiceActionListBuilder.cs
@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using System.Collections.Generic;
using Emby.Dlna.Common;
diff --git a/Emby.Dlna/PlayTo/Device.cs b/Emby.Dlna/PlayTo/Device.cs
index 0c5ddee65..61db264a2 100644
--- a/Emby.Dlna/PlayTo/Device.cs
+++ b/Emby.Dlna/PlayTo/Device.cs
@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using System;
using System.Collections.Generic;
using System.Globalization;
@@ -221,7 +224,7 @@ namespace Emby.Dlna.PlayTo
_logger.LogDebug("Setting mute");
var value = mute ? 1 : 0;
- await new SsdpHttpClient(_httpClient, _config).SendCommandAsync(Properties.BaseUrl, service, command.Name, rendererCommands.BuildPost(command, service.ServiceType, value))
+ await new SsdpHttpClient(_httpClient).SendCommandAsync(Properties.BaseUrl, service, command.Name, rendererCommands.BuildPost(command, service.ServiceType, value))
.ConfigureAwait(false);
IsMuted = mute;
@@ -251,7 +254,7 @@ namespace Emby.Dlna.PlayTo
// Remote control will perform better
Volume = value;
- await new SsdpHttpClient(_httpClient, _config).SendCommandAsync(Properties.BaseUrl, service, command.Name, rendererCommands.BuildPost(command, service.ServiceType, value))
+ await new SsdpHttpClient(_httpClient).SendCommandAsync(Properties.BaseUrl, service, command.Name, rendererCommands.BuildPost(command, service.ServiceType, value))
.ConfigureAwait(false);
}
@@ -270,7 +273,7 @@ namespace Emby.Dlna.PlayTo
throw new InvalidOperationException("Unable to find service");
}
- await new SsdpHttpClient(_httpClient, _config).SendCommandAsync(Properties.BaseUrl, service, command.Name, avCommands.BuildPost(command, service.ServiceType, string.Format("{0:hh}:{0:mm}:{0:ss}", value), "REL_TIME"))
+ await new SsdpHttpClient(_httpClient).SendCommandAsync(Properties.BaseUrl, service, command.Name, avCommands.BuildPost(command, service.ServiceType, string.Format("{0:hh}:{0:mm}:{0:ss}", value), "REL_TIME"))
.ConfigureAwait(false);
RestartTimer(true);
@@ -302,7 +305,7 @@ namespace Emby.Dlna.PlayTo
}
var post = avCommands.BuildPost(command, service.ServiceType, url, dictionary);
- await new SsdpHttpClient(_httpClient, _config).SendCommandAsync(Properties.BaseUrl, service, command.Name, post, header: header)
+ await new SsdpHttpClient(_httpClient).SendCommandAsync(Properties.BaseUrl, service, command.Name, post, header: header)
.ConfigureAwait(false);
await Task.Delay(50).ConfigureAwait(false);
@@ -344,7 +347,7 @@ namespace Emby.Dlna.PlayTo
throw new InvalidOperationException("Unable to find service");
}
- return new SsdpHttpClient(_httpClient, _config).SendCommandAsync(Properties.BaseUrl, service, command.Name, avCommands.BuildPost(command, service.ServiceType, 1));
+ return new SsdpHttpClient(_httpClient).SendCommandAsync(Properties.BaseUrl, service, command.Name, avCommands.BuildPost(command, service.ServiceType, 1));
}
public async Task SetPlay(CancellationToken cancellationToken)
@@ -368,7 +371,7 @@ namespace Emby.Dlna.PlayTo
var service = GetAvTransportService();
- await new SsdpHttpClient(_httpClient, _config).SendCommandAsync(Properties.BaseUrl, service, command.Name, avCommands.BuildPost(command, service.ServiceType, 1))
+ await new SsdpHttpClient(_httpClient).SendCommandAsync(Properties.BaseUrl, service, command.Name, avCommands.BuildPost(command, service.ServiceType, 1))
.ConfigureAwait(false);
RestartTimer(true);
@@ -386,7 +389,7 @@ namespace Emby.Dlna.PlayTo
var service = GetAvTransportService();
- await new SsdpHttpClient(_httpClient, _config).SendCommandAsync(Properties.BaseUrl, service, command.Name, avCommands.BuildPost(command, service.ServiceType, 1))
+ await new SsdpHttpClient(_httpClient).SendCommandAsync(Properties.BaseUrl, service, command.Name, avCommands.BuildPost(command, service.ServiceType, 1))
.ConfigureAwait(false);
TransportState = TRANSPORTSTATE.PAUSED;
@@ -513,7 +516,7 @@ namespace Emby.Dlna.PlayTo
return;
}
- var result = await new SsdpHttpClient(_httpClient, _config).SendCommandAsync(Properties.BaseUrl, service, command.Name, rendererCommands.BuildPost(command, service.ServiceType), true)
+ var result = await new SsdpHttpClient(_httpClient).SendCommandAsync(Properties.BaseUrl, service, command.Name, rendererCommands.BuildPost(command, service.ServiceType), true)
.ConfigureAwait(false);
if (result == null || result.Document == null)
@@ -559,7 +562,7 @@ namespace Emby.Dlna.PlayTo
return;
}
- var result = await new SsdpHttpClient(_httpClient, _config).SendCommandAsync(Properties.BaseUrl, service, command.Name, rendererCommands.BuildPost(command, service.ServiceType), true)
+ var result = await new SsdpHttpClient(_httpClient).SendCommandAsync(Properties.BaseUrl, service, command.Name, rendererCommands.BuildPost(command, service.ServiceType), true)
.ConfigureAwait(false);
if (result == null || result.Document == null)
@@ -586,7 +589,7 @@ namespace Emby.Dlna.PlayTo
return null;
}
- var result = await new SsdpHttpClient(_httpClient, _config).SendCommandAsync(Properties.BaseUrl, service, command.Name, avCommands.BuildPost(command, service.ServiceType), false)
+ var result = await new SsdpHttpClient(_httpClient).SendCommandAsync(Properties.BaseUrl, service, command.Name, avCommands.BuildPost(command, service.ServiceType), false)
.ConfigureAwait(false);
if (result == null || result.Document == null)
@@ -624,7 +627,7 @@ namespace Emby.Dlna.PlayTo
var rendererCommands = await GetRenderingProtocolAsync(cancellationToken).ConfigureAwait(false);
- var result = await new SsdpHttpClient(_httpClient, _config).SendCommandAsync(Properties.BaseUrl, service, command.Name, rendererCommands.BuildPost(command, service.ServiceType), false)
+ var result = await new SsdpHttpClient(_httpClient).SendCommandAsync(Properties.BaseUrl, service, command.Name, rendererCommands.BuildPost(command, service.ServiceType), false)
.ConfigureAwait(false);
if (result == null || result.Document == null)
@@ -687,7 +690,7 @@ namespace Emby.Dlna.PlayTo
var rendererCommands = await GetRenderingProtocolAsync(cancellationToken).ConfigureAwait(false);
- var result = await new SsdpHttpClient(_httpClient, _config).SendCommandAsync(Properties.BaseUrl, service, command.Name, rendererCommands.BuildPost(command, service.ServiceType), false)
+ var result = await new SsdpHttpClient(_httpClient).SendCommandAsync(Properties.BaseUrl, service, command.Name, rendererCommands.BuildPost(command, service.ServiceType), false)
.ConfigureAwait(false);
if (result == null || result.Document == null)
@@ -868,7 +871,7 @@ namespace Emby.Dlna.PlayTo
string url = NormalizeUrl(Properties.BaseUrl, avService.ScpdUrl);
- var httpClient = new SsdpHttpClient(_httpClient, _config);
+ var httpClient = new SsdpHttpClient(_httpClient);
var document = await httpClient.GetDataAsync(url, cancellationToken).ConfigureAwait(false);
@@ -896,7 +899,7 @@ namespace Emby.Dlna.PlayTo
string url = NormalizeUrl(Properties.BaseUrl, avService.ScpdUrl);
- var httpClient = new SsdpHttpClient(_httpClient, _config);
+ var httpClient = new SsdpHttpClient(_httpClient);
_logger.LogDebug("Dlna Device.GetRenderingProtocolAsync");
var document = await httpClient.GetDataAsync(url, cancellationToken).ConfigureAwait(false);
@@ -931,7 +934,7 @@ namespace Emby.Dlna.PlayTo
public static async Task<Device> CreateuPnpDeviceAsync(Uri url, IHttpClient httpClient, IServerConfigurationManager config, ILogger logger, CancellationToken cancellationToken)
{
- var ssdpHttpClient = new SsdpHttpClient(httpClient, config);
+ var ssdpHttpClient = new SsdpHttpClient(httpClient);
var document = await ssdpHttpClient.GetDataAsync(url.ToString(), cancellationToken).ConfigureAwait(false);
diff --git a/Emby.Dlna/PlayTo/DeviceInfo.cs b/Emby.Dlna/PlayTo/DeviceInfo.cs
index 9e7c04bdb..c36f89096 100644
--- a/Emby.Dlna/PlayTo/DeviceInfo.cs
+++ b/Emby.Dlna/PlayTo/DeviceInfo.cs
@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using System.Collections.Generic;
using Emby.Dlna.Common;
using MediaBrowser.Model.Dlna;
diff --git a/Emby.Dlna/PlayTo/PlayToController.cs b/Emby.Dlna/PlayTo/PlayToController.cs
index d378c2c30..0dbf1a3e6 100644
--- a/Emby.Dlna/PlayTo/PlayToController.cs
+++ b/Emby.Dlna/PlayTo/PlayToController.cs
@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using System;
using System.Collections.Generic;
using System.Globalization;
diff --git a/Emby.Dlna/PlayTo/PlayToManager.cs b/Emby.Dlna/PlayTo/PlayToManager.cs
index 2ca44b7ea..5d75e3360 100644
--- a/Emby.Dlna/PlayTo/PlayToManager.cs
+++ b/Emby.Dlna/PlayTo/PlayToManager.cs
@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using System;
using System.Globalization;
using System.Linq;
@@ -21,7 +24,7 @@ using Microsoft.Extensions.Logging;
namespace Emby.Dlna.PlayTo
{
- class PlayToManager : IDisposable
+ public class PlayToManager : IDisposable
{
private readonly ILogger _logger;
private readonly ISessionManager _sessionManager;
@@ -64,10 +67,10 @@ namespace Emby.Dlna.PlayTo
public void Start()
{
- _deviceDiscovery.DeviceDiscovered += _deviceDiscovery_DeviceDiscovered;
+ _deviceDiscovery.DeviceDiscovered += OnDeviceDiscoveryDeviceDiscovered;
}
- async void _deviceDiscovery_DeviceDiscovered(object sender, GenericEventArgs<UpnpDeviceInfo> e)
+ private async void OnDeviceDiscoveryDeviceDiscovered(object sender, GenericEventArgs<UpnpDeviceInfo> e)
{
if (_disposed)
{
@@ -231,7 +234,7 @@ namespace Emby.Dlna.PlayTo
public void Dispose()
{
- _deviceDiscovery.DeviceDiscovered -= _deviceDiscovery_DeviceDiscovered;
+ _deviceDiscovery.DeviceDiscovered -= OnDeviceDiscoveryDeviceDiscovered;
try
{
diff --git a/Emby.Dlna/PlayTo/PlaybackProgressEventArgs.cs b/Emby.Dlna/PlayTo/PlaybackProgressEventArgs.cs
index ffa56419b..bdd2a6c3e 100644
--- a/Emby.Dlna/PlayTo/PlaybackProgressEventArgs.cs
+++ b/Emby.Dlna/PlayTo/PlaybackProgressEventArgs.cs
@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using System;
namespace Emby.Dlna.PlayTo
diff --git a/Emby.Dlna/PlayTo/PlaybackStartEventArgs.cs b/Emby.Dlna/PlayTo/PlaybackStartEventArgs.cs
index 8cd8b47ac..485f7ec10 100644
--- a/Emby.Dlna/PlayTo/PlaybackStartEventArgs.cs
+++ b/Emby.Dlna/PlayTo/PlaybackStartEventArgs.cs
@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using System;
namespace Emby.Dlna.PlayTo
diff --git a/Emby.Dlna/PlayTo/PlaybackStoppedEventArgs.cs b/Emby.Dlna/PlayTo/PlaybackStoppedEventArgs.cs
index 2afdc324d..2eddb125d 100644
--- a/Emby.Dlna/PlayTo/PlaybackStoppedEventArgs.cs
+++ b/Emby.Dlna/PlayTo/PlaybackStoppedEventArgs.cs
@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using System;
namespace Emby.Dlna.PlayTo
diff --git a/Emby.Dlna/PlayTo/PlaylistItem.cs b/Emby.Dlna/PlayTo/PlaylistItem.cs
index 1e62b61e9..42d73c38c 100644
--- a/Emby.Dlna/PlayTo/PlaylistItem.cs
+++ b/Emby.Dlna/PlayTo/PlaylistItem.cs
@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using MediaBrowser.Model.Dlna;
namespace Emby.Dlna.PlayTo
diff --git a/Emby.Dlna/PlayTo/PlaylistItemFactory.cs b/Emby.Dlna/PlayTo/PlaylistItemFactory.cs
index 3b1cbab62..f7a750d21 100644
--- a/Emby.Dlna/PlayTo/PlaylistItemFactory.cs
+++ b/Emby.Dlna/PlayTo/PlaylistItemFactory.cs
@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using System.IO;
using System.Linq;
using MediaBrowser.Controller.Entities;
diff --git a/Emby.Dlna/PlayTo/SsdpHttpClient.cs b/Emby.Dlna/PlayTo/SsdpHttpClient.cs
index 66c634150..757e713e1 100644
--- a/Emby.Dlna/PlayTo/SsdpHttpClient.cs
+++ b/Emby.Dlna/PlayTo/SsdpHttpClient.cs
@@ -1,13 +1,16 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using System;
using System.Globalization;
using System.IO;
+using System.Net.Http;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Xml.Linq;
using Emby.Dlna.Common;
using MediaBrowser.Common.Net;
-using MediaBrowser.Controller.Configuration;
namespace Emby.Dlna.PlayTo
{
@@ -19,12 +22,10 @@ namespace Emby.Dlna.PlayTo
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
private readonly IHttpClient _httpClient;
- private readonly IServerConfigurationManager _config;
- public SsdpHttpClient(IHttpClient httpClient, IServerConfigurationManager config)
+ public SsdpHttpClient(IHttpClient httpClient)
{
_httpClient = httpClient;
- _config = config;
}
public async Task<XDocument> SendCommandAsync(
@@ -64,7 +65,9 @@ namespace Emby.Dlna.PlayTo
}
if (!serviceUrl.StartsWith("/"))
+ {
serviceUrl = "/" + serviceUrl;
+ }
return baseUrl + serviceUrl;
}
@@ -90,7 +93,7 @@ namespace Emby.Dlna.PlayTo
options.RequestHeaders["NT"] = "upnp:event";
options.RequestHeaders["TIMEOUT"] = "Second-" + timeOut.ToString(_usCulture);
- using (await _httpClient.SendAsync(options, "SUBSCRIBE").ConfigureAwait(false))
+ using (await _httpClient.SendAsync(options, new HttpMethod("SUBSCRIBE")).ConfigureAwait(false))
{
}
@@ -110,7 +113,7 @@ namespace Emby.Dlna.PlayTo
options.RequestHeaders["FriendlyName.DLNA.ORG"] = FriendlyName;
- using (var response = await _httpClient.SendAsync(options, "GET").ConfigureAwait(false))
+ using (var response = await _httpClient.SendAsync(options, HttpMethod.Get).ConfigureAwait(false))
using (var stream = response.Content)
using (var reader = new StreamReader(stream, Encoding.UTF8))
{
diff --git a/Emby.Dlna/PlayTo/TRANSPORTSTATE.cs b/Emby.Dlna/PlayTo/TRANSPORTSTATE.cs
index 9f1690b04..b312c8b6e 100644
--- a/Emby.Dlna/PlayTo/TRANSPORTSTATE.cs
+++ b/Emby.Dlna/PlayTo/TRANSPORTSTATE.cs
@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
namespace Emby.Dlna.PlayTo
{
public enum TRANSPORTSTATE
diff --git a/Emby.Dlna/PlayTo/TransportCommands.cs b/Emby.Dlna/PlayTo/TransportCommands.cs
index 4f9e398e9..a00d154f7 100644
--- a/Emby.Dlna/PlayTo/TransportCommands.cs
+++ b/Emby.Dlna/PlayTo/TransportCommands.cs
@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using System;
using System.Collections.Generic;
using System.Linq;
diff --git a/Emby.Dlna/PlayTo/UpnpContainer.cs b/Emby.Dlna/PlayTo/UpnpContainer.cs
index 943e0347b..9700d8a5d 100644
--- a/Emby.Dlna/PlayTo/UpnpContainer.cs
+++ b/Emby.Dlna/PlayTo/UpnpContainer.cs
@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using System;
using System.Xml.Linq;
using Emby.Dlna.Ssdp;
diff --git a/Emby.Dlna/PlayTo/uBaseObject.cs b/Emby.Dlna/PlayTo/uBaseObject.cs
index f29a126df..6e2e31dc4 100644
--- a/Emby.Dlna/PlayTo/uBaseObject.cs
+++ b/Emby.Dlna/PlayTo/uBaseObject.cs
@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using System;
namespace Emby.Dlna.PlayTo
diff --git a/Emby.Dlna/PlayTo/uPnpNamespaces.cs b/Emby.Dlna/PlayTo/uPnpNamespaces.cs
index 7132ecd15..fc0f0f704 100644
--- a/Emby.Dlna/PlayTo/uPnpNamespaces.cs
+++ b/Emby.Dlna/PlayTo/uPnpNamespaces.cs
@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using System.Xml.Linq;
namespace Emby.Dlna.PlayTo
diff --git a/Emby.Dlna/Profiles/DefaultProfile.cs b/Emby.Dlna/Profiles/DefaultProfile.cs
index ea50bd4a7..97286e347 100644
--- a/Emby.Dlna/Profiles/DefaultProfile.cs
+++ b/Emby.Dlna/Profiles/DefaultProfile.cs
@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using System.Linq;
using MediaBrowser.Model.Dlna;
diff --git a/Emby.Dlna/Profiles/DenonAvrProfile.cs b/Emby.Dlna/Profiles/DenonAvrProfile.cs
index a73885191..3be980528 100644
--- a/Emby.Dlna/Profiles/DenonAvrProfile.cs
+++ b/Emby.Dlna/Profiles/DenonAvrProfile.cs
@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using MediaBrowser.Model.Dlna;
namespace Emby.Dlna.Profiles
diff --git a/Emby.Dlna/Profiles/DirectTvProfile.cs b/Emby.Dlna/Profiles/DirectTvProfile.cs
index 317c0976a..33bcae604 100644
--- a/Emby.Dlna/Profiles/DirectTvProfile.cs
+++ b/Emby.Dlna/Profiles/DirectTvProfile.cs
@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using MediaBrowser.Model.Dlna;
namespace Emby.Dlna.Profiles
diff --git a/Emby.Dlna/Profiles/DishHopperJoeyProfile.cs b/Emby.Dlna/Profiles/DishHopperJoeyProfile.cs
index 8d8ab41ca..26654b803 100644
--- a/Emby.Dlna/Profiles/DishHopperJoeyProfile.cs
+++ b/Emby.Dlna/Profiles/DishHopperJoeyProfile.cs
@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using MediaBrowser.Model.Dlna;
namespace Emby.Dlna.Profiles
diff --git a/Emby.Dlna/Profiles/Foobar2000Profile.cs b/Emby.Dlna/Profiles/Foobar2000Profile.cs
index 947194bce..c1aece8c8 100644
--- a/Emby.Dlna/Profiles/Foobar2000Profile.cs
+++ b/Emby.Dlna/Profiles/Foobar2000Profile.cs
@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using MediaBrowser.Model.Dlna;
namespace Emby.Dlna.Profiles
diff --git a/Emby.Dlna/Profiles/LgTvProfile.cs b/Emby.Dlna/Profiles/LgTvProfile.cs
index 145685ab1..63b5b6f31 100644
--- a/Emby.Dlna/Profiles/LgTvProfile.cs
+++ b/Emby.Dlna/Profiles/LgTvProfile.cs
@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using MediaBrowser.Model.Dlna;
namespace Emby.Dlna.Profiles
diff --git a/Emby.Dlna/Profiles/LinksysDMA2100Profile.cs b/Emby.Dlna/Profiles/LinksysDMA2100Profile.cs
index 3f0bb4263..3a9744e38 100644
--- a/Emby.Dlna/Profiles/LinksysDMA2100Profile.cs
+++ b/Emby.Dlna/Profiles/LinksysDMA2100Profile.cs
@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using MediaBrowser.Model.Dlna;
namespace Emby.Dlna.Profiles
diff --git a/Emby.Dlna/Profiles/MarantzProfile.cs b/Emby.Dlna/Profiles/MarantzProfile.cs
index 162e284be..05f94a206 100644
--- a/Emby.Dlna/Profiles/MarantzProfile.cs
+++ b/Emby.Dlna/Profiles/MarantzProfile.cs
@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using MediaBrowser.Model.Dlna;
namespace Emby.Dlna.Profiles
diff --git a/Emby.Dlna/Profiles/MediaMonkeyProfile.cs b/Emby.Dlna/Profiles/MediaMonkeyProfile.cs
index 53cae4e2f..10218fa56 100644
--- a/Emby.Dlna/Profiles/MediaMonkeyProfile.cs
+++ b/Emby.Dlna/Profiles/MediaMonkeyProfile.cs
@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using MediaBrowser.Model.Dlna;
namespace Emby.Dlna.Profiles
diff --git a/Emby.Dlna/Profiles/PanasonicVieraProfile.cs b/Emby.Dlna/Profiles/PanasonicVieraProfile.cs
index 5f31ec484..945ec4518 100644
--- a/Emby.Dlna/Profiles/PanasonicVieraProfile.cs
+++ b/Emby.Dlna/Profiles/PanasonicVieraProfile.cs
@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using MediaBrowser.Model.Dlna;
namespace Emby.Dlna.Profiles
diff --git a/Emby.Dlna/Profiles/PopcornHourProfile.cs b/Emby.Dlna/Profiles/PopcornHourProfile.cs
index aefe8c44f..3765d01dc 100644
--- a/Emby.Dlna/Profiles/PopcornHourProfile.cs
+++ b/Emby.Dlna/Profiles/PopcornHourProfile.cs
@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using MediaBrowser.Model.Dlna;
namespace Emby.Dlna.Profiles
diff --git a/Emby.Dlna/Profiles/SamsungSmartTvProfile.cs b/Emby.Dlna/Profiles/SamsungSmartTvProfile.cs
index 51a1c8173..61c5f4dce 100644
--- a/Emby.Dlna/Profiles/SamsungSmartTvProfile.cs
+++ b/Emby.Dlna/Profiles/SamsungSmartTvProfile.cs
@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using MediaBrowser.Model.Dlna;
namespace Emby.Dlna.Profiles
diff --git a/Emby.Dlna/Profiles/SharpSmartTvProfile.cs b/Emby.Dlna/Profiles/SharpSmartTvProfile.cs
index f840cfb34..8967dc16a 100644
--- a/Emby.Dlna/Profiles/SharpSmartTvProfile.cs
+++ b/Emby.Dlna/Profiles/SharpSmartTvProfile.cs
@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using MediaBrowser.Model.Dlna;
namespace Emby.Dlna.Profiles
diff --git a/Emby.Dlna/Profiles/SonyBlurayPlayer2013.cs b/Emby.Dlna/Profiles/SonyBlurayPlayer2013.cs
index 2af1d3b50..308d74aa8 100644
--- a/Emby.Dlna/Profiles/SonyBlurayPlayer2013.cs
+++ b/Emby.Dlna/Profiles/SonyBlurayPlayer2013.cs
@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using MediaBrowser.Model.Dlna;
namespace Emby.Dlna.Profiles
diff --git a/Emby.Dlna/Profiles/SonyBlurayPlayer2014.cs b/Emby.Dlna/Profiles/SonyBlurayPlayer2014.cs
index 3de0b5192..496c24316 100644
--- a/Emby.Dlna/Profiles/SonyBlurayPlayer2014.cs
+++ b/Emby.Dlna/Profiles/SonyBlurayPlayer2014.cs
@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using MediaBrowser.Model.Dlna;
namespace Emby.Dlna.Profiles
diff --git a/Emby.Dlna/Profiles/SonyBlurayPlayer2015.cs b/Emby.Dlna/Profiles/SonyBlurayPlayer2015.cs
index 889484bea..987a9af4b 100644
--- a/Emby.Dlna/Profiles/SonyBlurayPlayer2015.cs
+++ b/Emby.Dlna/Profiles/SonyBlurayPlayer2015.cs
@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using MediaBrowser.Model.Dlna;
namespace Emby.Dlna.Profiles
diff --git a/Emby.Dlna/Profiles/SonyBlurayPlayer2016.cs b/Emby.Dlna/Profiles/SonyBlurayPlayer2016.cs
index acb90bd01..560193ded 100644
--- a/Emby.Dlna/Profiles/SonyBlurayPlayer2016.cs
+++ b/Emby.Dlna/Profiles/SonyBlurayPlayer2016.cs
@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using MediaBrowser.Model.Dlna;
namespace Emby.Dlna.Profiles
diff --git a/Emby.Dlna/Profiles/SonyBlurayPlayerProfile.cs b/Emby.Dlna/Profiles/SonyBlurayPlayerProfile.cs
index e1808b205..c983d98ba 100644
--- a/Emby.Dlna/Profiles/SonyBlurayPlayerProfile.cs
+++ b/Emby.Dlna/Profiles/SonyBlurayPlayerProfile.cs
@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using MediaBrowser.Model.Dlna;
namespace Emby.Dlna.Profiles
diff --git a/Emby.Dlna/Profiles/SonyBravia2010Profile.cs b/Emby.Dlna/Profiles/SonyBravia2010Profile.cs
index f8e8faa76..186c89473 100644
--- a/Emby.Dlna/Profiles/SonyBravia2010Profile.cs
+++ b/Emby.Dlna/Profiles/SonyBravia2010Profile.cs
@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using MediaBrowser.Model.Dlna;
namespace Emby.Dlna.Profiles
diff --git a/Emby.Dlna/Profiles/SonyBravia2011Profile.cs b/Emby.Dlna/Profiles/SonyBravia2011Profile.cs
index 111f36e9b..a29d143f6 100644
--- a/Emby.Dlna/Profiles/SonyBravia2011Profile.cs
+++ b/Emby.Dlna/Profiles/SonyBravia2011Profile.cs
@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using MediaBrowser.Model.Dlna;
namespace Emby.Dlna.Profiles
diff --git a/Emby.Dlna/Profiles/SonyBravia2012Profile.cs b/Emby.Dlna/Profiles/SonyBravia2012Profile.cs
index d5efe4270..9bcdd21b8 100644
--- a/Emby.Dlna/Profiles/SonyBravia2012Profile.cs
+++ b/Emby.Dlna/Profiles/SonyBravia2012Profile.cs
@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using MediaBrowser.Model.Dlna;
namespace Emby.Dlna.Profiles
diff --git a/Emby.Dlna/Profiles/SonyBravia2013Profile.cs b/Emby.Dlna/Profiles/SonyBravia2013Profile.cs
index 3b0228694..900e4ff06 100644
--- a/Emby.Dlna/Profiles/SonyBravia2013Profile.cs
+++ b/Emby.Dlna/Profiles/SonyBravia2013Profile.cs
@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using MediaBrowser.Model.Dlna;
namespace Emby.Dlna.Profiles
diff --git a/Emby.Dlna/Profiles/SonyBravia2014Profile.cs b/Emby.Dlna/Profiles/SonyBravia2014Profile.cs
index e860eae34..963e7993e 100644
--- a/Emby.Dlna/Profiles/SonyBravia2014Profile.cs
+++ b/Emby.Dlna/Profiles/SonyBravia2014Profile.cs
@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using MediaBrowser.Model.Dlna;
namespace Emby.Dlna.Profiles
diff --git a/Emby.Dlna/Profiles/SonyPs3Profile.cs b/Emby.Dlna/Profiles/SonyPs3Profile.cs
index 88d064695..31a764d8d 100644
--- a/Emby.Dlna/Profiles/SonyPs3Profile.cs
+++ b/Emby.Dlna/Profiles/SonyPs3Profile.cs
@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using MediaBrowser.Model.Dlna;
namespace Emby.Dlna.Profiles
diff --git a/Emby.Dlna/Profiles/SonyPs4Profile.cs b/Emby.Dlna/Profiles/SonyPs4Profile.cs
index 499cf8803..9376a564b 100644
--- a/Emby.Dlna/Profiles/SonyPs4Profile.cs
+++ b/Emby.Dlna/Profiles/SonyPs4Profile.cs
@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using MediaBrowser.Model.Dlna;
namespace Emby.Dlna.Profiles
diff --git a/Emby.Dlna/Profiles/WdtvLiveProfile.cs b/Emby.Dlna/Profiles/WdtvLiveProfile.cs
index bf7b1ab47..8e056792a 100644
--- a/Emby.Dlna/Profiles/WdtvLiveProfile.cs
+++ b/Emby.Dlna/Profiles/WdtvLiveProfile.cs
@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using MediaBrowser.Model.Dlna;
namespace Emby.Dlna.Profiles
diff --git a/Emby.Dlna/Profiles/XboxOneProfile.cs b/Emby.Dlna/Profiles/XboxOneProfile.cs
index 710b891e3..364c43354 100644
--- a/Emby.Dlna/Profiles/XboxOneProfile.cs
+++ b/Emby.Dlna/Profiles/XboxOneProfile.cs
@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using MediaBrowser.Model.Dlna;
namespace Emby.Dlna.Profiles
diff --git a/Emby.Dlna/Server/DescriptionXmlBuilder.cs b/Emby.Dlna/Server/DescriptionXmlBuilder.cs
index 1b53e9242..a72c62b12 100644
--- a/Emby.Dlna/Server/DescriptionXmlBuilder.cs
+++ b/Emby.Dlna/Server/DescriptionXmlBuilder.cs
@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using System;
using System.Collections.Generic;
using System.Globalization;
diff --git a/Emby.Dlna/Service/BaseControlHandler.cs b/Emby.Dlna/Service/BaseControlHandler.cs
index a8da7aecd..4704ecbe6 100644
--- a/Emby.Dlna/Service/BaseControlHandler.cs
+++ b/Emby.Dlna/Service/BaseControlHandler.cs
@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using System;
using System.Collections.Generic;
using System.IO;
@@ -65,8 +68,6 @@ namespace Emby.Dlna.Service
Logger.LogDebug("Received control request {0}", requestInfo.LocalName);
- var result = GetResult(requestInfo.LocalName, requestInfo.Headers);
-
var settings = new XmlWriterSettings
{
Encoding = Encoding.UTF8,
@@ -84,12 +85,9 @@ namespace Emby.Dlna.Service
writer.WriteStartElement("SOAP-ENV", "Body", NS_SOAPENV);
writer.WriteStartElement("u", requestInfo.LocalName + "Response", requestInfo.NamespaceURI);
- foreach (var i in result)
- {
- writer.WriteStartElement(i.Key);
- writer.WriteString(i.Value);
- writer.WriteFullEndElement();
- }
+
+ WriteResult(requestInfo.LocalName, requestInfo.Headers, writer);
+
writer.WriteFullEndElement();
writer.WriteFullEndElement();
@@ -97,7 +95,7 @@ namespace Emby.Dlna.Service
writer.WriteEndDocument();
}
- var xml = builder.ToString().Replace("xmlns:m=", "xmlns:u=");
+ var xml = builder.ToString().Replace("xmlns:m=", "xmlns:u=", StringComparison.Ordinal);
var controlResponse = new ControlResponse
{
@@ -218,7 +216,7 @@ namespace Emby.Dlna.Service
public Dictionary<string, string> Headers { get; } = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
}
- protected abstract IEnumerable<KeyValuePair<string, string>> GetResult(string methodName, IDictionary<string, string> methodParams);
+ protected abstract void WriteResult(string methodName, IDictionary<string, string> methodParams, XmlWriter xmlWriter);
private void LogRequest(ControlRequest request)
{
diff --git a/Emby.Dlna/Service/BaseService.cs b/Emby.Dlna/Service/BaseService.cs
index 5359e94c4..d7e5c541d 100644
--- a/Emby.Dlna/Service/BaseService.cs
+++ b/Emby.Dlna/Service/BaseService.cs
@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using Emby.Dlna.Eventing;
using MediaBrowser.Common.Net;
using Microsoft.Extensions.Logging;
diff --git a/Emby.Dlna/Service/ControlErrorHandler.cs b/Emby.Dlna/Service/ControlErrorHandler.cs
index bbf975f38..a2f5057fb 100644
--- a/Emby.Dlna/Service/ControlErrorHandler.cs
+++ b/Emby.Dlna/Service/ControlErrorHandler.cs
@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using System;
using System.IO;
using System.Text;
diff --git a/Emby.Dlna/Service/ServiceXmlBuilder.cs b/Emby.Dlna/Service/ServiceXmlBuilder.cs
index bd1f0bf05..0787b8df9 100644
--- a/Emby.Dlna/Service/ServiceXmlBuilder.cs
+++ b/Emby.Dlna/Service/ServiceXmlBuilder.cs
@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using System.Collections.Generic;
using System.Text;
using Emby.Dlna.Common;
diff --git a/Emby.Dlna/Ssdp/DeviceDiscovery.cs b/Emby.Dlna/Ssdp/DeviceDiscovery.cs
index c5f3593da..c5e57d0ff 100644
--- a/Emby.Dlna/Ssdp/DeviceDiscovery.cs
+++ b/Emby.Dlna/Ssdp/DeviceDiscovery.cs
@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using System;
using System.Collections.Generic;
using System.Linq;
@@ -9,16 +12,16 @@ using Rssdp.Infrastructure;
namespace Emby.Dlna.Ssdp
{
- public class DeviceDiscovery : IDeviceDiscovery
+ public sealed class DeviceDiscovery : IDeviceDiscovery, IDisposable
{
- private bool _disposed;
+ private readonly object _syncLock = new object();
private readonly IServerConfigurationManager _config;
- private event EventHandler<GenericEventArgs<UpnpDeviceInfo>> DeviceDiscoveredInternal;
-
private int _listenerCount;
- private object _syncLock = new object();
+ private bool _disposed;
+
+ private event EventHandler<GenericEventArgs<UpnpDeviceInfo>> DeviceDiscoveredInternal;
/// <inheritdoc />
public event EventHandler<GenericEventArgs<UpnpDeviceInfo>> DeviceDiscovered
@@ -33,6 +36,7 @@ namespace Emby.Dlna.Ssdp
StartInternal();
}
+
remove
{
lock (_syncLock)
@@ -130,6 +134,7 @@ namespace Emby.Dlna.Ssdp
DeviceLeft?.Invoke(this, args);
}
+ /// <inheritdoc />
public void Dispose()
{
if (!_disposed)
diff --git a/Emby.Dlna/Ssdp/Extensions.cs b/Emby.Dlna/Ssdp/Extensions.cs
index c680c123e..836d4abfd 100644
--- a/Emby.Dlna/Ssdp/Extensions.cs
+++ b/Emby.Dlna/Ssdp/Extensions.cs
@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using System.Xml.Linq;
namespace Emby.Dlna.Ssdp
diff --git a/Emby.Drawing/Emby.Drawing.csproj b/Emby.Drawing/Emby.Drawing.csproj
index 85cecdc44..b7090b262 100644
--- a/Emby.Drawing/Emby.Drawing.csproj
+++ b/Emby.Drawing/Emby.Drawing.csproj
@@ -17,4 +17,16 @@
<Compile Include="..\SharedVersion.cs" />
</ItemGroup>
+ <!-- Code analysers-->
+ <ItemGroup Condition=" '$(Configuration)' == 'Debug' ">
+ <PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.9.8" PrivateAssets="All" />
+ <PackageReference Include="SerilogAnalyzer" Version="0.15.0" PrivateAssets="All" />
+ <PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="All" />
+ <PackageReference Include="SmartAnalyzers.MultithreadingAnalyzer" Version="1.1.31" PrivateAssets="All" />
+ </ItemGroup>
+
+ <PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
+ <CodeAnalysisRuleSet>../jellyfin.ruleset</CodeAnalysisRuleSet>
+ </PropertyGroup>
+
</Project>
diff --git a/Emby.Drawing/ImageProcessor.cs b/Emby.Drawing/ImageProcessor.cs
index 4e0f9493a..eca4b56eb 100644
--- a/Emby.Drawing/ImageProcessor.cs
+++ b/Emby.Drawing/ImageProcessor.cs
@@ -3,7 +3,6 @@ using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
-using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Controller;
@@ -11,7 +10,6 @@ using MediaBrowser.Controller.Drawing;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.MediaEncoding;
-using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Drawing;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.IO;
@@ -23,7 +21,7 @@ namespace Emby.Drawing
/// <summary>
/// Class ImageProcessor.
/// </summary>
- public class ImageProcessor : IImageProcessor, IDisposable
+ public sealed class ImageProcessor : IImageProcessor, IDisposable
{
// Increment this when there's a change requiring caches to be invalidated
private const string Version = "3";
@@ -31,28 +29,24 @@ namespace Emby.Drawing
private static readonly HashSet<string> _transparentImageTypes
= new HashSet<string>(StringComparer.OrdinalIgnoreCase) { ".png", ".webp", ".gif" };
- /// <summary>
- /// The _logger
- /// </summary>
private readonly ILogger _logger;
private readonly IFileSystem _fileSystem;
private readonly IServerApplicationPaths _appPaths;
- private IImageEncoder _imageEncoder;
+ private readonly IImageEncoder _imageEncoder;
private readonly Func<ILibraryManager> _libraryManager;
private readonly Func<IMediaEncoder> _mediaEncoder;
- private readonly Dictionary<string, LockInfo> _locks = new Dictionary<string, LockInfo>();
private bool _disposed = false;
/// <summary>
- ///
+ /// Initializes a new instance of the <see cref="ImageProcessor"/> class.
/// </summary>
- /// <param name="logger"></param>
- /// <param name="appPaths"></param>
- /// <param name="fileSystem"></param>
- /// <param name="imageEncoder"></param>
- /// <param name="libraryManager"></param>
- /// <param name="mediaEncoder"></param>
+ /// <param name="logger">The logger.</param>
+ /// <param name="appPaths">The server application paths.</param>
+ /// <param name="fileSystem">The filesystem.</param>
+ /// <param name="imageEncoder">The image encoder.</param>
+ /// <param name="libraryManager">The library manager.</param>
+ /// <param name="mediaEncoder">The media encoder.</param>
public ImageProcessor(
ILogger<ImageProcessor> logger,
IServerApplicationPaths appPaths,
@@ -67,16 +61,10 @@ namespace Emby.Drawing
_libraryManager = libraryManager;
_mediaEncoder = mediaEncoder;
_appPaths = appPaths;
-
- ImageEnhancers = Array.Empty<IImageEnhancer>();
-
- ImageHelper.ImageProcessor = this;
}
private string ResizedImageCachePath => Path.Combine(_appPaths.ImageCachePath, "resized-images");
- private string EnhancedImageCachePath => Path.Combine(_appPaths.ImageCachePath, "enhanced-images");
-
/// <inheritdoc />
public IReadOnlyCollection<string> SupportedInputFormats =>
new HashSet<string>(StringComparer.OrdinalIgnoreCase)
@@ -89,9 +77,7 @@ namespace Emby.Drawing
"aiff",
"cr2",
"crw",
-
- // Remove until supported
- //"nef",
+ "nef",
"orf",
"pef",
"arw",
@@ -111,19 +97,9 @@ namespace Emby.Drawing
};
/// <inheritdoc />
- public IReadOnlyCollection<IImageEnhancer> ImageEnhancers { get; set; }
-
- /// <inheritdoc />
public bool SupportsImageCollageCreation => _imageEncoder.SupportsImageCollageCreation;
/// <inheritdoc />
- public IImageEncoder ImageEncoder
- {
- get => _imageEncoder;
- set => _imageEncoder = value ?? throw new ArgumentNullException(nameof(value));
- }
-
- /// <inheritdoc />
public async Task ProcessImage(ImageProcessingOptions options, Stream toStream)
{
var file = await ProcessImage(options).ConfigureAwait(false);
@@ -150,6 +126,8 @@ namespace Emby.Drawing
throw new ArgumentNullException(nameof(options));
}
+ var libraryManager = _libraryManager();
+
ItemImageInfo originalImage = options.Image;
BaseItem item = options.Item;
@@ -157,9 +135,10 @@ namespace Emby.Drawing
{
if (item == null)
{
- item = _libraryManager().GetItemById(options.ItemId);
+ item = libraryManager.GetItemById(options.ItemId);
}
- originalImage = await _libraryManager().ConvertImageToLocal(item, originalImage, options.ImageIndex).ConfigureAwait(false);
+
+ originalImage = await libraryManager.ConvertImageToLocal(item, originalImage, options.ImageIndex).ConfigureAwait(false);
}
string originalImagePath = originalImage.Path;
@@ -186,27 +165,6 @@ namespace Emby.Drawing
dateModified = supportedImageInfo.dateModified;
bool requiresTransparency = _transparentImageTypes.Contains(Path.GetExtension(originalImagePath));
- if (options.Enhancers.Count > 0)
- {
- if (item == null)
- {
- item = _libraryManager().GetItemById(options.ItemId);
- }
-
- var tuple = await GetEnhancedImage(new ItemImageInfo
- {
- DateModified = dateModified,
- Type = originalImage.Type,
- Path = originalImagePath
- }, requiresTransparency, item, options.ImageIndex, options.Enhancers, CancellationToken.None).ConfigureAwait(false);
-
- originalImagePath = tuple.path;
- dateModified = tuple.dateModified;
- requiresTransparency = tuple.transparent;
- // TODO: Get this info
- originalImageSize = null;
- }
-
bool autoOrient = false;
ImageOrientation? orientation = null;
if (item is Photo photo)
@@ -239,12 +197,6 @@ namespace Emby.Drawing
ImageFormat outputFormat = GetOutputFormat(options.SupportedOutputFormats, requiresTransparency);
string cacheFilePath = GetCacheFilePath(originalImagePath, newSize, quality, dateModified, outputFormat, options.AddPlayedIndicator, options.PercentPlayed, options.UnplayedCount, options.Blur, options.BackgroundColor, options.ForegroundLayer);
- CheckDisposed();
-
- LockInfo lockInfo = GetLock(cacheFilePath);
-
- await lockInfo.Lock.WaitAsync().ConfigureAwait(false);
-
try
{
if (!File.Exists(cacheFilePath))
@@ -270,10 +222,6 @@ namespace Emby.Drawing
_logger.LogError(ex, "Error encoding image");
return (originalImagePath, MimeTypes.GetMimeType(originalImagePath), dateModified);
}
- finally
- {
- ReleaseLock(cacheFilePath, lockInfo);
- }
}
private ImageFormat GetOutputFormat(IReadOnlyCollection<ImageFormat> clientSupportedFormats, bool requiresTransparency)
@@ -305,20 +253,18 @@ namespace Emby.Drawing
}
private string GetMimeType(ImageFormat format, string path)
- {
- switch(format)
- {
- case ImageFormat.Bmp: return MimeTypes.GetMimeType("i.bmp");
- case ImageFormat.Gif: return MimeTypes.GetMimeType("i.gif");
- case ImageFormat.Jpg: return MimeTypes.GetMimeType("i.jpg");
- case ImageFormat.Png: return MimeTypes.GetMimeType("i.png");
- case ImageFormat.Webp: return MimeTypes.GetMimeType("i.webp");
- default: return MimeTypes.GetMimeType(path);
- }
- }
+ => format switch
+ {
+ ImageFormat.Bmp => MimeTypes.GetMimeType("i.bmp"),
+ ImageFormat.Gif => MimeTypes.GetMimeType("i.gif"),
+ ImageFormat.Jpg => MimeTypes.GetMimeType("i.jpg"),
+ ImageFormat.Png => MimeTypes.GetMimeType("i.png"),
+ ImageFormat.Webp => MimeTypes.GetMimeType("i.webp"),
+ _ => MimeTypes.GetMimeType(path)
+ };
/// <summary>
- /// Gets the cache file path based on a set of parameters
+ /// Gets the cache file path based on a set of parameters.
/// </summary>
private string GetCacheFilePath(string originalPath, ImageDimensions outputSize, int quality, DateTime dateModified, ImageFormat format, bool addPlayedIndicator, double percentPlayed, int? unwatchedCount, int? blur, string backgroundColor, string foregroundLayer)
{
@@ -400,11 +346,7 @@ namespace Emby.Drawing
/// <inheritdoc />
public string GetImageCacheTag(BaseItem item, ItemImageInfo image)
- {
- var supportedEnhancers = GetSupportedEnhancers(item, image.Type).ToArray();
-
- return GetImageCacheTag(item, image, supportedEnhancers);
- }
+ => (item.Path + image.DateModified.Ticks).GetMD5().ToString("N", CultureInfo.InvariantCulture);
/// <inheritdoc />
public string GetImageCacheTag(BaseItem item, ChapterInfo chapter)
@@ -424,26 +366,6 @@ namespace Emby.Drawing
}
}
- /// <inheritdoc />
- public string GetImageCacheTag(BaseItem item, ItemImageInfo image, IReadOnlyCollection<IImageEnhancer> imageEnhancers)
- {
- string originalImagePath = image.Path;
- DateTime dateModified = image.DateModified;
- ImageType imageType = image.Type;
-
- // Optimization
- if (imageEnhancers.Count == 0)
- {
- return (originalImagePath + dateModified.Ticks).GetMD5().ToString("N", CultureInfo.InvariantCulture);
- }
-
- // Cache name is created with supported enhancers combined with the last config change so we pick up new config changes
- var cacheKeys = imageEnhancers.Select(i => i.GetConfigurationCacheKey(item, imageType)).ToList();
- cacheKeys.Add(originalImagePath + dateModified.Ticks);
-
- return string.Join("|", cacheKeys).GetMD5().ToString("N", CultureInfo.InvariantCulture);
- }
-
private async Task<(string path, DateTime dateModified)> GetSupportedImage(string originalImagePath, DateTime dateModified)
{
var inputFormat = Path.GetExtension(originalImagePath)
@@ -487,154 +409,6 @@ namespace Emby.Drawing
return (originalImagePath, dateModified);
}
- /// <inheritdoc />
- public async Task<string> GetEnhancedImage(BaseItem item, ImageType imageType, int imageIndex)
- {
- var enhancers = GetSupportedEnhancers(item, imageType).ToArray();
-
- ItemImageInfo imageInfo = item.GetImageInfo(imageType, imageIndex);
-
- bool inputImageSupportsTransparency = SupportsTransparency(imageInfo.Path);
-
- var result = await GetEnhancedImage(imageInfo, inputImageSupportsTransparency, item, imageIndex, enhancers, CancellationToken.None);
-
- return result.path;
- }
-
- private async Task<(string path, DateTime dateModified, bool transparent)> GetEnhancedImage(
- ItemImageInfo image,
- bool inputImageSupportsTransparency,
- BaseItem item,
- int imageIndex,
- IReadOnlyCollection<IImageEnhancer> enhancers,
- CancellationToken cancellationToken)
- {
- var originalImagePath = image.Path;
- var dateModified = image.DateModified;
- var imageType = image.Type;
-
- try
- {
- var cacheGuid = GetImageCacheTag(item, image, enhancers);
-
- // Enhance if we have enhancers
- var enhancedImageInfo = await GetEnhancedImageInternal(originalImagePath, item, imageType, imageIndex, enhancers, cacheGuid, cancellationToken).ConfigureAwait(false);
-
- string enhancedImagePath = enhancedImageInfo.path;
-
- // If the path changed update dateModified
- if (!string.Equals(enhancedImagePath, originalImagePath, StringComparison.OrdinalIgnoreCase))
- {
- var treatmentRequiresTransparency = enhancedImageInfo.transparent;
-
- return (enhancedImagePath, _fileSystem.GetLastWriteTimeUtc(enhancedImagePath), treatmentRequiresTransparency);
- }
- }
- catch (Exception ex)
- {
- _logger.LogError(ex, "Error enhancing image");
- }
-
- return (originalImagePath, dateModified, inputImageSupportsTransparency);
- }
-
- /// <summary>
- /// Gets the enhanced image internal.
- /// </summary>
- /// <param name="originalImagePath">The original image path.</param>
- /// <param name="item">The item.</param>
- /// <param name="imageType">Type of the image.</param>
- /// <param name="imageIndex">Index of the image.</param>
- /// <param name="supportedEnhancers">The supported enhancers.</param>
- /// <param name="cacheGuid">The cache unique identifier.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task&lt;System.String&gt;.</returns>
- /// <exception cref="ArgumentNullException">
- /// originalImagePath
- /// or
- /// item
- /// </exception>
- private async Task<(string path, bool transparent)> GetEnhancedImageInternal(
- string originalImagePath,
- BaseItem item,
- ImageType imageType,
- int imageIndex,
- IReadOnlyCollection<IImageEnhancer> supportedEnhancers,
- string cacheGuid,
- CancellationToken cancellationToken = default)
- {
- if (string.IsNullOrEmpty(originalImagePath))
- {
- throw new ArgumentNullException(nameof(originalImagePath));
- }
-
- if (item == null)
- {
- throw new ArgumentNullException(nameof(item));
- }
-
- var treatmentRequiresTransparency = false;
- foreach (var enhancer in supportedEnhancers)
- {
- if (!treatmentRequiresTransparency)
- {
- treatmentRequiresTransparency = enhancer.GetEnhancedImageInfo(item, originalImagePath, imageType, imageIndex).RequiresTransparency;
- }
- }
-
- // All enhanced images are saved as png to allow transparency
- string cacheExtension = _imageEncoder.SupportedOutputFormats.Contains(ImageFormat.Webp) ?
- ".webp" :
- (treatmentRequiresTransparency ? ".png" : ".jpg");
-
- string enhancedImagePath = GetCachePath(EnhancedImageCachePath, cacheGuid + cacheExtension);
-
- LockInfo lockInfo = GetLock(enhancedImagePath);
-
- await lockInfo.Lock.WaitAsync(cancellationToken).ConfigureAwait(false);
-
- try
- {
- // Check again in case of contention
- if (File.Exists(enhancedImagePath))
- {
- return (enhancedImagePath, treatmentRequiresTransparency);
- }
-
- Directory.CreateDirectory(Path.GetDirectoryName(enhancedImagePath));
-
- await ExecuteImageEnhancers(supportedEnhancers, originalImagePath, enhancedImagePath, item, imageType, imageIndex).ConfigureAwait(false);
-
- return (enhancedImagePath, treatmentRequiresTransparency);
- }
- finally
- {
- ReleaseLock(enhancedImagePath, lockInfo);
- }
- }
-
- /// <summary>
- /// Executes the image enhancers.
- /// </summary>
- /// <param name="imageEnhancers">The image enhancers.</param>
- /// <param name="inputPath">The input path.</param>
- /// <param name="outputPath">The output path.</param>
- /// <param name="item">The item.</param>
- /// <param name="imageType">Type of the image.</param>
- /// <param name="imageIndex">Index of the image.</param>
- /// <returns>Task{EnhancedImage}.</returns>
- private static async Task ExecuteImageEnhancers(IEnumerable<IImageEnhancer> imageEnhancers, string inputPath, string outputPath, BaseItem item, ImageType imageType, int imageIndex)
- {
- // Run the enhancers sequentially in order of priority
- foreach (var enhancer in imageEnhancers)
- {
- await enhancer.EnhanceImageAsync(item, inputPath, outputPath, imageType, imageIndex).ConfigureAwait(false);
-
- // Feed the output into the next enhancer as input
- inputPath = outputPath;
- }
- }
-
/// <summary>
/// Gets the cache path.
/// </summary>
@@ -647,7 +421,7 @@ namespace Emby.Drawing
/// or
/// uniqueName
/// or
- /// fileExtension
+ /// fileExtension.
/// </exception>
public string GetCachePath(string path, string uniqueName, string fileExtension)
{
@@ -680,7 +454,7 @@ namespace Emby.Drawing
/// <exception cref="ArgumentNullException">
/// path
/// or
- /// filename
+ /// filename.
/// </exception>
public string GetCachePath(string path, string filename)
{
@@ -688,6 +462,7 @@ namespace Emby.Drawing
{
throw new ArgumentNullException(nameof(path));
}
+
if (string.IsNullOrEmpty(filename))
{
throw new ArgumentNullException(nameof(filename));
@@ -709,74 +484,19 @@ namespace Emby.Drawing
}
/// <inheritdoc />
- public IEnumerable<IImageEnhancer> GetSupportedEnhancers(BaseItem item, ImageType imageType)
- {
- foreach (var i in ImageEnhancers)
- {
- if (i.Supports(item, imageType))
- {
- yield return i;
- }
- }
- }
-
-
- private class LockInfo
- {
- public SemaphoreSlim Lock = new SemaphoreSlim(1, 1);
- public int Count = 1;
- }
-
- private LockInfo GetLock(string key)
- {
- lock (_locks)
- {
- if (_locks.TryGetValue(key, out LockInfo info))
- {
- info.Count++;
- }
- else
- {
- info = new LockInfo();
- _locks[key] = info;
- }
- return info;
- }
- }
-
- private void ReleaseLock(string key, LockInfo info)
+ public void Dispose()
{
- info.Lock.Release();
-
- lock (_locks)
+ if (_disposed)
{
- info.Count--;
- if (info.Count <= 0)
- {
- _locks.Remove(key);
- info.Lock.Dispose();
- }
+ return;
}
- }
-
- /// <inheritdoc />
- public void Dispose()
- {
- _disposed = true;
- var disposable = _imageEncoder as IDisposable;
- if (disposable != null)
+ if (_imageEncoder is IDisposable disposable)
{
disposable.Dispose();
}
- }
- private void CheckDisposed()
- {
- if (_disposed)
- {
- throw new ObjectDisposedException(GetType().Name);
- }
+ _disposed = true;
}
}
}
diff --git a/Emby.Naming/Audio/AudioFileParser.cs b/Emby.Naming/Audio/AudioFileParser.cs
index 9f21e93dc..748622102 100644
--- a/Emby.Naming/Audio/AudioFileParser.cs
+++ b/Emby.Naming/Audio/AudioFileParser.cs
@@ -8,19 +8,12 @@ using Emby.Naming.Common;
namespace Emby.Naming.Audio
{
- public class AudioFileParser
+ public static class AudioFileParser
{
- private readonly NamingOptions _options;
-
- public AudioFileParser(NamingOptions options)
- {
- _options = options;
- }
-
- public bool IsAudioFile(string path)
+ public static bool IsAudioFile(string path, NamingOptions options)
{
var extension = Path.GetExtension(path) ?? string.Empty;
- return _options.AudioFileExtensions.Contains(extension, StringComparer.OrdinalIgnoreCase);
+ return options.AudioFileExtensions.Contains(extension, StringComparer.OrdinalIgnoreCase);
}
}
}
diff --git a/Emby.Naming/Common/NamingOptions.cs b/Emby.Naming/Common/NamingOptions.cs
index 1554e61d8..b4f22ed69 100644
--- a/Emby.Naming/Common/NamingOptions.cs
+++ b/Emby.Naming/Common/NamingOptions.cs
@@ -277,7 +277,7 @@ namespace Emby.Naming.Common
// This isn't a Kodi naming rule, but the expression below causes false positives,
// so we make sure this one gets tested first.
// "Foo Bar 889"
- new EpisodeExpression(@".*[\\\/](?![Ee]pisode)(?<seriesname>[\w\s]+?)\s(?<epnumber>\d{1,3})(-(?<endingepnumber>\d{2,3}))*[^\\\/]*$")
+ new EpisodeExpression(@".*[\\\/](?![Ee]pisode)(?<seriesname>[\w\s]+?)\s(?<epnumber>\d{1,3})(-(?<endingepnumber>\d{2,3}))*[^\\\/x]*$")
{
IsNamed = true
},
diff --git a/Emby.Naming/TV/SeasonPathParser.cs b/Emby.Naming/TV/SeasonPathParser.cs
index 7715a16a4..79fdae573 100644
--- a/Emby.Naming/TV/SeasonPathParser.cs
+++ b/Emby.Naming/TV/SeasonPathParser.cs
@@ -4,7 +4,6 @@
using System;
using System.Globalization;
using System.IO;
-using System.Linq;
namespace Emby.Naming.TV
{
@@ -29,14 +28,14 @@ namespace Emby.Naming.TV
{
var result = new SeasonPathParserResult();
- var seasonNumberInfo = GetSeasonNumberFromPath(path, supportSpecialAliases, supportNumericSeasonFolders);
+ var (seasonNumber, isSeasonFolder) = GetSeasonNumberFromPath(path, supportSpecialAliases, supportNumericSeasonFolders);
- result.SeasonNumber = seasonNumberInfo.seasonNumber;
+ result.SeasonNumber = seasonNumber;
if (result.SeasonNumber.HasValue)
{
result.Success = true;
- result.IsSeasonFolder = seasonNumberInfo.isSeasonFolder;
+ result.IsSeasonFolder = isSeasonFolder;
}
return result;
@@ -90,12 +89,10 @@ namespace Emby.Naming.TV
// Look for one of the season folder names
foreach (var name in _seasonFolderNames)
{
- var index = filename.IndexOf(name, StringComparison.OrdinalIgnoreCase);
-
- if (index != -1)
+ if (filename.Contains(name, StringComparison.OrdinalIgnoreCase))
{
var result = GetSeasonNumberFromPathSubstring(filename.Replace(name, " ", StringComparison.OrdinalIgnoreCase));
- if (result.Item1.HasValue)
+ if (result.seasonNumber.HasValue)
{
return result;
}
@@ -105,25 +102,32 @@ namespace Emby.Naming.TV
}
var parts = filename.Split(new[] { '.', '_', ' ', '-' }, StringSplitOptions.RemoveEmptyEntries);
- var resultNumber = parts.Select(GetSeasonNumberFromPart).FirstOrDefault(i => i.HasValue);
- return (resultNumber, true);
+ for (int i = 0; i < parts.Length; i++)
+ {
+ if (TryGetSeasonNumberFromPart(parts[i], out int seasonNumber))
+ {
+ return (seasonNumber, true);
+ }
+ }
+
+ return (null, true);
}
- private static int? GetSeasonNumberFromPart(string part)
+ private static bool TryGetSeasonNumberFromPart(ReadOnlySpan<char> part, out int seasonNumber)
{
+ seasonNumber = 0;
if (part.Length < 2 || !part.StartsWith("s", StringComparison.OrdinalIgnoreCase))
{
- return null;
+ return false;
}
- part = part.Substring(1);
-
- if (int.TryParse(part, NumberStyles.Integer, CultureInfo.InvariantCulture, out var value))
+ if (int.TryParse(part.Slice(1), NumberStyles.Integer, CultureInfo.InvariantCulture, out var value))
{
- return value;
+ seasonNumber = value;
+ return true;
}
- return null;
+ return false;
}
/// <summary>
@@ -131,7 +135,7 @@ namespace Emby.Naming.TV
/// </summary>
/// <param name="path">The path.</param>
/// <returns>System.Nullable{System.Int32}.</returns>
- private static (int? seasonNumber, bool isSeasonFolder) GetSeasonNumberFromPathSubstring(string path)
+ private static (int? seasonNumber, bool isSeasonFolder) GetSeasonNumberFromPathSubstring(ReadOnlySpan<char> path)
{
var numericStart = -1;
var length = 0;
@@ -142,7 +146,7 @@ namespace Emby.Naming.TV
// Find out where the numbers start, and then keep going until they end
for (var i = 0; i < path.Length; i++)
{
- if (char.IsNumber(path, i))
+ if (char.IsNumber(path[i]))
{
if (!hasOpenParenth)
{
@@ -177,7 +181,7 @@ namespace Emby.Naming.TV
return (null, isSeasonFolder);
}
- return (int.Parse(path.Substring(numericStart, length), CultureInfo.InvariantCulture), isSeasonFolder);
+ return (int.Parse(path.Slice(numericStart, length), provider: CultureInfo.InvariantCulture), isSeasonFolder);
}
}
}
diff --git a/Emby.Naming/Video/ExtraResolver.cs b/Emby.Naming/Video/ExtraResolver.cs
index ea9a6d6c2..3e5d473ec 100644
--- a/Emby.Naming/Video/ExtraResolver.cs
+++ b/Emby.Naming/Video/ExtraResolver.cs
@@ -32,7 +32,7 @@ namespace Emby.Naming.Video
if (rule.MediaType == MediaType.Audio)
{
- if (!new AudioFileParser(_options).IsAudioFile(path))
+ if (!AudioFileParser.IsAudioFile(path, _options))
{
return result;
}
diff --git a/Emby.Naming/Video/StackResolver.cs b/Emby.Naming/Video/StackResolver.cs
index 8f210fa45..b9afe998b 100644
--- a/Emby.Naming/Video/StackResolver.cs
+++ b/Emby.Naming/Video/StackResolver.cs
@@ -194,7 +194,7 @@ namespace Emby.Naming.Video
}
}
- private string GetRegexInput(FileSystemMetadata file)
+ private static string GetRegexInput(FileSystemMetadata file)
{
// For directories, dummy up an extension otherwise the expressions will fail
var input = !file.IsDirectory
@@ -204,7 +204,7 @@ namespace Emby.Naming.Video
return Path.GetFileName(input);
}
- private Match FindMatch(FileSystemMetadata input, Regex regex, int offset)
+ private static Match FindMatch(FileSystemMetadata input, Regex regex, int offset)
{
var regexInput = GetRegexInput(input);
diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs
index 91e635b46..8ea188724 100644
--- a/Emby.Server.Implementations/ApplicationHost.cs
+++ b/Emby.Server.Implementations/ApplicationHost.cs
@@ -755,7 +755,18 @@ namespace Emby.Server.Implementations
serviceCollection.AddSingleton(UserManager);
- LibraryManager = new LibraryManager(this, LoggerFactory, TaskManager, UserManager, ServerConfigurationManager, UserDataManager, () => LibraryMonitor, FileSystemManager, () => ProviderManager, () => UserViewManager);
+ MediaEncoder = new MediaBrowser.MediaEncoding.Encoder.MediaEncoder(
+ LoggerFactory.CreateLogger<MediaBrowser.MediaEncoding.Encoder.MediaEncoder>(),
+ ServerConfigurationManager,
+ FileSystemManager,
+ ProcessFactory,
+ LocalizationManager,
+ () => SubtitleEncoder,
+ _configuration,
+ StartupOptions.FFmpegPath);
+ serviceCollection.AddSingleton(MediaEncoder);
+
+ LibraryManager = new LibraryManager(this, LoggerFactory, TaskManager, UserManager, ServerConfigurationManager, UserDataManager, () => LibraryMonitor, FileSystemManager, () => ProviderManager, () => UserViewManager, MediaEncoder);
serviceCollection.AddSingleton(LibraryManager);
var musicManager = new MusicManager(LibraryManager);
@@ -808,7 +819,18 @@ namespace Emby.Server.Implementations
ChannelManager = new ChannelManager(UserManager, DtoService, LibraryManager, LoggerFactory, ServerConfigurationManager, FileSystemManager, UserDataManager, JsonSerializer, ProviderManager);
serviceCollection.AddSingleton(ChannelManager);
- SessionManager = new SessionManager(UserDataManager, LoggerFactory, LibraryManager, UserManager, musicManager, DtoService, ImageProcessor, this, AuthenticationRepository, DeviceManager, MediaSourceManager);
+ SessionManager = new SessionManager(
+ LoggerFactory.CreateLogger<SessionManager>(),
+ UserDataManager,
+ LibraryManager,
+ UserManager,
+ musicManager,
+ DtoService,
+ ImageProcessor,
+ this,
+ AuthenticationRepository,
+ DeviceManager,
+ MediaSourceManager);
serviceCollection.AddSingleton(SessionManager);
serviceCollection.AddSingleton<IDlnaManager>(
@@ -836,17 +858,6 @@ namespace Emby.Server.Implementations
ChapterManager = new ChapterManager(LibraryManager, LoggerFactory, ServerConfigurationManager, ItemRepository);
serviceCollection.AddSingleton(ChapterManager);
- MediaEncoder = new MediaBrowser.MediaEncoding.Encoder.MediaEncoder(
- LoggerFactory.CreateLogger<MediaBrowser.MediaEncoding.Encoder.MediaEncoder>(),
- ServerConfigurationManager,
- FileSystemManager,
- ProcessFactory,
- LocalizationManager,
- () => SubtitleEncoder,
- _configuration,
- StartupOptions.FFmpegPath);
- serviceCollection.AddSingleton(MediaEncoder);
-
EncodingManager = new MediaEncoder.EncodingManager(FileSystemManager, LoggerFactory, MediaEncoder, ChapterManager, LibraryManager);
serviceCollection.AddSingleton(EncodingManager);
@@ -1077,8 +1088,6 @@ namespace Emby.Server.Implementations
GetExports<IMetadataSaver>(),
GetExports<IExternalId>());
- ImageProcessor.ImageEnhancers = GetExports<IImageEnhancer>();
-
LiveTvManager.AddParts(GetExports<ILiveTvService>(), GetExports<ITunerHost>(), GetExports<IListingsProvider>());
SubtitleManager.AddParts(GetExports<ISubtitleProvider>());
@@ -1525,7 +1534,7 @@ namespace Emby.Server.Implementations
string baseUrl = ServerConfigurationManager.Configuration.BaseUrl;
if (baseUrl.Length != 0)
{
- url.Append('/').Append(baseUrl);
+ url.Append(baseUrl);
}
return url.ToString();
diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs
index c514846e5..44f38504a 100644
--- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs
+++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs
@@ -3521,20 +3521,6 @@ namespace Emby.Server.Implementations.Data
}
var includeTypes = query.IncludeItemTypes.SelectMany(MapIncludeItemTypes).ToArray();
- if (includeTypes.Length == 1)
- {
- whereClauses.Add("type=@type");
- if (statement != null)
- {
- statement.TryBind("@type", includeTypes[0]);
- }
- }
- else if (includeTypes.Length > 1)
- {
- var inClause = string.Join(",", includeTypes.Select(i => "'" + i + "'"));
- whereClauses.Add($"type in ({inClause})");
- }
-
// Only specify excluded types if no included types are specified
if (includeTypes.Length == 0)
{
@@ -3553,6 +3539,19 @@ namespace Emby.Server.Implementations.Data
whereClauses.Add($"type not in ({inClause})");
}
}
+ else if (includeTypes.Length == 1)
+ {
+ whereClauses.Add("type=@type");
+ if (statement != null)
+ {
+ statement.TryBind("@type", includeTypes[0]);
+ }
+ }
+ else if (includeTypes.Length > 1)
+ {
+ var inClause = string.Join(",", includeTypes.Select(i => "'" + i + "'"));
+ whereClauses.Add($"type in ({inClause})");
+ }
if (query.ChannelIds.Length == 1)
{
@@ -4927,7 +4926,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
// Not crazy about having this all the way down here, but at least it's in one place
readonly Dictionary<string, string[]> _types = GetTypeMapDictionary();
- private IEnumerable<string> MapIncludeItemTypes(string value)
+ private string[] MapIncludeItemTypes(string value)
{
if (_types.TryGetValue(value, out string[] result))
{
@@ -5611,32 +5610,32 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
return counts;
}
- private List<Tuple<int, string>> GetItemValuesToSave(BaseItem item, List<string> inheritedTags)
+ private List<(int, string)> GetItemValuesToSave(BaseItem item, List<string> inheritedTags)
{
- var list = new List<Tuple<int, string>>();
+ var list = new List<(int, string)>();
if (item is IHasArtist hasArtist)
{
- list.AddRange(hasArtist.Artists.Select(i => new Tuple<int, string>(0, i)));
+ list.AddRange(hasArtist.Artists.Select(i => (0, i)));
}
if (item is IHasAlbumArtist hasAlbumArtist)
{
- list.AddRange(hasAlbumArtist.AlbumArtists.Select(i => new Tuple<int, string>(1, i)));
+ list.AddRange(hasAlbumArtist.AlbumArtists.Select(i => (1, i)));
}
- list.AddRange(item.Genres.Select(i => new Tuple<int, string>(2, i)));
- list.AddRange(item.Studios.Select(i => new Tuple<int, string>(3, i)));
- list.AddRange(item.Tags.Select(i => new Tuple<int, string>(4, i)));
+ list.AddRange(item.Genres.Select(i => (2, i)));
+ list.AddRange(item.Studios.Select(i => (3, i)));
+ list.AddRange(item.Tags.Select(i => (4, i)));
// keywords was 5
- list.AddRange(inheritedTags.Select(i => new Tuple<int, string>(6, i)));
+ list.AddRange(inheritedTags.Select(i => (6, i)));
return list;
}
- private void UpdateItemValues(Guid itemId, List<Tuple<int, string>> values, IDatabaseConnection db)
+ private void UpdateItemValues(Guid itemId, List<(int, string)> values, IDatabaseConnection db)
{
if (itemId.Equals(Guid.Empty))
{
@@ -5658,7 +5657,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
InsertItemValues(guidBlob, values, db);
}
- private void InsertItemValues(byte[] idBlob, List<Tuple<int, string>> values, IDatabaseConnection db)
+ private void InsertItemValues(byte[] idBlob, List<(int, string)> values, IDatabaseConnection db)
{
var startIndex = 0;
var limit = 100;
diff --git a/Emby.Server.Implementations/Devices/DeviceManager.cs b/Emby.Server.Implementations/Devices/DeviceManager.cs
index 2bd0b840a..4f8f9f23b 100644
--- a/Emby.Server.Implementations/Devices/DeviceManager.cs
+++ b/Emby.Server.Implementations/Devices/DeviceManager.cs
@@ -142,11 +142,10 @@ namespace Emby.Server.Implementations.Devices
public QueryResult<DeviceInfo> GetDevices(DeviceQuery query)
{
- var sessions = _authRepo.Get(new AuthenticationInfoQuery
+ IEnumerable<AuthenticationInfo> sessions = _authRepo.Get(new AuthenticationInfoQuery
{
//UserId = query.UserId
HasUser = true
-
}).Items;
// TODO: DeviceQuery doesn't seem to be used from client. Not even Swagger.
@@ -154,23 +153,19 @@ namespace Emby.Server.Implementations.Devices
{
var val = query.SupportsSync.Value;
- sessions = sessions.Where(i => GetCapabilities(i.DeviceId).SupportsSync == val).ToArray();
+ sessions = sessions.Where(i => GetCapabilities(i.DeviceId).SupportsSync == val);
}
if (!query.UserId.Equals(Guid.Empty))
{
var user = _userManager.GetUserById(query.UserId);
- sessions = sessions.Where(i => CanAccessDevice(user, i.DeviceId)).ToArray();
+ sessions = sessions.Where(i => CanAccessDevice(user, i.DeviceId));
}
var array = sessions.Select(ToDeviceInfo).ToArray();
- return new QueryResult<DeviceInfo>
- {
- Items = array,
- TotalRecordCount = array.Length
- };
+ return new QueryResult<DeviceInfo>(array);
}
private DeviceInfo ToDeviceInfo(AuthenticationInfo authInfo)
@@ -186,7 +181,7 @@ namespace Emby.Server.Implementations.Devices
LastUserName = authInfo.UserName,
Name = authInfo.DeviceName,
DateLastActivity = authInfo.DateLastActivity,
- IconUrl = caps == null ? null : caps.IconUrl
+ IconUrl = caps?.IconUrl
};
}
diff --git a/Emby.Server.Implementations/Dto/DtoService.cs b/Emby.Server.Implementations/Dto/DtoService.cs
index fcf0360c7..960f3f2d6 100644
--- a/Emby.Server.Implementations/Dto/DtoService.cs
+++ b/Emby.Server.Implementations/Dto/DtoService.cs
@@ -1362,56 +1362,33 @@ namespace Emby.Server.Implementations.Dto
return null;
}
- var supportedEnhancers = _imageProcessor.GetSupportedEnhancers(item, ImageType.Primary).ToArray();
-
ImageDimensions size;
var defaultAspectRatio = item.GetDefaultPrimaryImageAspectRatio();
if (defaultAspectRatio > 0)
{
- if (supportedEnhancers.Length == 0)
- {
- return defaultAspectRatio;
- }
+ return defaultAspectRatio;
+ }
- int dummyWidth = 200;
- int dummyHeight = Convert.ToInt32(dummyWidth / defaultAspectRatio);
- size = new ImageDimensions(dummyWidth, dummyHeight);
+ if (!imageInfo.IsLocalFile)
+ {
+ return null;
}
- else
+
+ try
{
- if (!imageInfo.IsLocalFile)
- {
- return null;
- }
+ size = _imageProcessor.GetImageDimensions(item, imageInfo);
- try
+ if (size.Width <= 0 || size.Height <= 0)
{
- size = _imageProcessor.GetImageDimensions(item, imageInfo);
-
- if (size.Width <= 0 || size.Height <= 0)
- {
- return null;
- }
- }
- catch (Exception ex)
- {
- _logger.LogError(ex, "Failed to determine primary image aspect ratio for {0}", imageInfo.Path);
return null;
}
}
-
- foreach (var enhancer in supportedEnhancers)
+ catch (Exception ex)
{
- try
- {
- size = enhancer.GetEnhancedImageSize(item, ImageType.Primary, 0, size);
- }
- catch (Exception ex)
- {
- _logger.LogError(ex, "Error in image enhancer: {0}", enhancer.GetType().Name);
- }
+ _logger.LogError(ex, "Failed to determine primary image aspect ratio for {0}", imageInfo.Path);
+ return null;
}
var width = size.Width;
diff --git a/Emby.Server.Implementations/EntryPoints/RecordingNotifier.cs b/Emby.Server.Implementations/EntryPoints/RecordingNotifier.cs
index e0aa18e89..9603d7976 100644
--- a/Emby.Server.Implementations/EntryPoints/RecordingNotifier.cs
+++ b/Emby.Server.Implementations/EntryPoints/RecordingNotifier.cs
@@ -13,7 +13,7 @@ using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.EntryPoints
{
- public class RecordingNotifier : IServerEntryPoint
+ public sealed class RecordingNotifier : IServerEntryPoint
{
private readonly ILiveTvManager _liveTvManager;
private readonly ISessionManager _sessionManager;
@@ -28,32 +28,33 @@ namespace Emby.Server.Implementations.EntryPoints
_liveTvManager = liveTvManager;
}
+ /// <inheritdoc />
public Task RunAsync()
{
- _liveTvManager.TimerCancelled += _liveTvManager_TimerCancelled;
- _liveTvManager.SeriesTimerCancelled += _liveTvManager_SeriesTimerCancelled;
- _liveTvManager.TimerCreated += _liveTvManager_TimerCreated;
- _liveTvManager.SeriesTimerCreated += _liveTvManager_SeriesTimerCreated;
+ _liveTvManager.TimerCancelled += OnLiveTvManagerTimerCancelled;
+ _liveTvManager.SeriesTimerCancelled += OnLiveTvManagerSeriesTimerCancelled;
+ _liveTvManager.TimerCreated += OnLiveTvManagerTimerCreated;
+ _liveTvManager.SeriesTimerCreated += OnLiveTvManagerSeriesTimerCreated;
return Task.CompletedTask;
}
- private void _liveTvManager_SeriesTimerCreated(object sender, MediaBrowser.Model.Events.GenericEventArgs<TimerEventInfo> e)
+ private void OnLiveTvManagerSeriesTimerCreated(object sender, MediaBrowser.Model.Events.GenericEventArgs<TimerEventInfo> e)
{
SendMessage("SeriesTimerCreated", e.Argument);
}
- private void _liveTvManager_TimerCreated(object sender, MediaBrowser.Model.Events.GenericEventArgs<TimerEventInfo> e)
+ private void OnLiveTvManagerTimerCreated(object sender, MediaBrowser.Model.Events.GenericEventArgs<TimerEventInfo> e)
{
SendMessage("TimerCreated", e.Argument);
}
- private void _liveTvManager_SeriesTimerCancelled(object sender, MediaBrowser.Model.Events.GenericEventArgs<TimerEventInfo> e)
+ private void OnLiveTvManagerSeriesTimerCancelled(object sender, MediaBrowser.Model.Events.GenericEventArgs<TimerEventInfo> e)
{
SendMessage("SeriesTimerCancelled", e.Argument);
}
- private void _liveTvManager_TimerCancelled(object sender, MediaBrowser.Model.Events.GenericEventArgs<TimerEventInfo> e)
+ private void OnLiveTvManagerTimerCancelled(object sender, MediaBrowser.Model.Events.GenericEventArgs<TimerEventInfo> e)
{
SendMessage("TimerCancelled", e.Argument);
}
@@ -64,11 +65,7 @@ namespace Emby.Server.Implementations.EntryPoints
try
{
- await _sessionManager.SendMessageToUserSessions(users, name, info, CancellationToken.None);
- }
- catch (ObjectDisposedException)
- {
- // TODO Log exception or Investigate and properly fix.
+ await _sessionManager.SendMessageToUserSessions(users, name, info, CancellationToken.None).ConfigureAwait(false);
}
catch (Exception ex)
{
@@ -76,12 +73,13 @@ namespace Emby.Server.Implementations.EntryPoints
}
}
+ /// <inheritdoc />
public void Dispose()
{
- _liveTvManager.TimerCancelled -= _liveTvManager_TimerCancelled;
- _liveTvManager.SeriesTimerCancelled -= _liveTvManager_SeriesTimerCancelled;
- _liveTvManager.TimerCreated -= _liveTvManager_TimerCreated;
- _liveTvManager.SeriesTimerCreated -= _liveTvManager_SeriesTimerCreated;
+ _liveTvManager.TimerCancelled -= OnLiveTvManagerTimerCancelled;
+ _liveTvManager.SeriesTimerCancelled -= OnLiveTvManagerSeriesTimerCancelled;
+ _liveTvManager.TimerCreated -= OnLiveTvManagerTimerCreated;
+ _liveTvManager.SeriesTimerCreated -= OnLiveTvManagerSeriesTimerCreated;
}
}
}
diff --git a/Emby.Server.Implementations/EntryPoints/RefreshUsersMetadata.cs b/Emby.Server.Implementations/EntryPoints/RefreshUsersMetadata.cs
index f00996b5f..54f4b67e6 100644
--- a/Emby.Server.Implementations/EntryPoints/RefreshUsersMetadata.cs
+++ b/Emby.Server.Implementations/EntryPoints/RefreshUsersMetadata.cs
@@ -6,7 +6,6 @@ using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Tasks;
-using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.EntryPoints
{
@@ -15,21 +14,17 @@ namespace Emby.Server.Implementations.EntryPoints
/// </summary>
public class RefreshUsersMetadata : IScheduledTask, IConfigurableScheduledTask
{
- private readonly ILogger _logger;
-
/// <summary>
/// The user manager.
/// </summary>
private readonly IUserManager _userManager;
-
- private IFileSystem _fileSystem;
+ private readonly IFileSystem _fileSystem;
/// <summary>
/// Initializes a new instance of the <see cref="RefreshUsersMetadata" /> class.
/// </summary>
- public RefreshUsersMetadata(ILogger logger, IUserManager userManager, IFileSystem fileSystem)
+ public RefreshUsersMetadata(IUserManager userManager, IFileSystem fileSystem)
{
- _logger = logger;
_userManager = userManager;
_fileSystem = fileSystem;
}
diff --git a/Emby.Server.Implementations/EntryPoints/StartupWizard.cs b/Emby.Server.Implementations/EntryPoints/StartupWizard.cs
index 161788c63..5f2d629fe 100644
--- a/Emby.Server.Implementations/EntryPoints/StartupWizard.cs
+++ b/Emby.Server.Implementations/EntryPoints/StartupWizard.cs
@@ -3,37 +3,28 @@ using Emby.Server.Implementations.Browser;
using MediaBrowser.Controller;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Plugins;
-using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.EntryPoints
{
/// <summary>
/// Class StartupWizard.
/// </summary>
- public class StartupWizard : IServerEntryPoint
+ public sealed class StartupWizard : IServerEntryPoint
{
/// <summary>
/// The app host.
/// </summary>
private readonly IServerApplicationHost _appHost;
-
- /// <summary>
- /// The user manager.
- /// </summary>
- private readonly ILogger _logger;
-
- private IServerConfigurationManager _config;
+ private readonly IServerConfigurationManager _config;
/// <summary>
/// Initializes a new instance of the <see cref="StartupWizard"/> class.
/// </summary>
/// <param name="appHost">The application host.</param>
- /// <param name="logger">The logger.</param>
/// <param name="config">The configuration manager.</param>
- public StartupWizard(IServerApplicationHost appHost, ILogger logger, IServerConfigurationManager config)
+ public StartupWizard(IServerApplicationHost appHost, IServerConfigurationManager config)
{
_appHost = appHost;
- _logger = logger;
_config = config;
}
diff --git a/Emby.Server.Implementations/EntryPoints/UdpServerEntryPoint.cs b/Emby.Server.Implementations/EntryPoints/UdpServerEntryPoint.cs
index 529f83560..50ba0f8fa 100644
--- a/Emby.Server.Implementations/EntryPoints/UdpServerEntryPoint.cs
+++ b/Emby.Server.Implementations/EntryPoints/UdpServerEntryPoint.cs
@@ -3,8 +3,6 @@ using System.Threading.Tasks;
using Emby.Server.Implementations.Udp;
using MediaBrowser.Controller;
using MediaBrowser.Controller.Plugins;
-using MediaBrowser.Model.Net;
-using MediaBrowser.Model.Serialization;
using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.EntryPoints
@@ -23,9 +21,7 @@ namespace Emby.Server.Implementations.EntryPoints
/// The logger.
/// </summary>
private readonly ILogger _logger;
- private readonly ISocketFactory _socketFactory;
private readonly IServerApplicationHost _appHost;
- private readonly IJsonSerializer _json;
/// <summary>
/// The UDP server.
@@ -64,7 +60,7 @@ namespace Emby.Server.Implementations.EntryPoints
_cancellationTokenSource.Cancel();
_udpServer.Dispose();
-
+ _cancellationTokenSource.Dispose();
_cancellationTokenSource = null;
_udpServer = null;
diff --git a/Emby.Server.Implementations/EntryPoints/UserDataChangeNotifier.cs b/Emby.Server.Implementations/EntryPoints/UserDataChangeNotifier.cs
index 3e22080fc..026b5dae9 100644
--- a/Emby.Server.Implementations/EntryPoints/UserDataChangeNotifier.cs
+++ b/Emby.Server.Implementations/EntryPoints/UserDataChangeNotifier.cs
@@ -13,39 +13,38 @@ using MediaBrowser.Controller.Plugins;
using MediaBrowser.Controller.Session;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Session;
-using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.EntryPoints
{
- public class UserDataChangeNotifier : IServerEntryPoint
+ public sealed class UserDataChangeNotifier : IServerEntryPoint
{
+ private const int UpdateDuration = 500;
+
private readonly ISessionManager _sessionManager;
- private readonly ILogger _logger;
private readonly IUserDataManager _userDataManager;
private readonly IUserManager _userManager;
+ private readonly Dictionary<Guid, List<BaseItem>> _changedItems = new Dictionary<Guid, List<BaseItem>>();
+
private readonly object _syncLock = new object();
- private Timer UpdateTimer { get; set; }
- private const int UpdateDuration = 500;
+ private Timer _updateTimer;
- private readonly Dictionary<Guid, List<BaseItem>> _changedItems = new Dictionary<Guid, List<BaseItem>>();
- public UserDataChangeNotifier(IUserDataManager userDataManager, ISessionManager sessionManager, ILogger logger, IUserManager userManager)
+ public UserDataChangeNotifier(IUserDataManager userDataManager, ISessionManager sessionManager, IUserManager userManager)
{
_userDataManager = userDataManager;
_sessionManager = sessionManager;
- _logger = logger;
_userManager = userManager;
}
public Task RunAsync()
{
- _userDataManager.UserDataSaved += _userDataManager_UserDataSaved;
+ _userDataManager.UserDataSaved += OnUserDataManagerUserDataSaved;
return Task.CompletedTask;
}
- void _userDataManager_UserDataSaved(object sender, UserDataSaveEventArgs e)
+ void OnUserDataManagerUserDataSaved(object sender, UserDataSaveEventArgs e)
{
if (e.SaveReason == UserDataSaveReason.PlaybackProgress)
{
@@ -54,14 +53,17 @@ namespace Emby.Server.Implementations.EntryPoints
lock (_syncLock)
{
- if (UpdateTimer == null)
+ if (_updateTimer == null)
{
- UpdateTimer = new Timer(UpdateTimerCallback, null, UpdateDuration,
- Timeout.Infinite);
+ _updateTimer = new Timer(
+ UpdateTimerCallback,
+ null,
+ UpdateDuration,
+ Timeout.Infinite);
}
else
{
- UpdateTimer.Change(UpdateDuration, Timeout.Infinite);
+ _updateTimer.Change(UpdateDuration, Timeout.Infinite);
}
if (!_changedItems.TryGetValue(e.UserId, out List<BaseItem> keys))
@@ -97,10 +99,10 @@ namespace Emby.Server.Implementations.EntryPoints
var task = SendNotifications(changes, CancellationToken.None);
- if (UpdateTimer != null)
+ if (_updateTimer != null)
{
- UpdateTimer.Dispose();
- UpdateTimer = null;
+ _updateTimer.Dispose();
+ _updateTimer = null;
}
}
}
@@ -145,13 +147,13 @@ namespace Emby.Server.Implementations.EntryPoints
public void Dispose()
{
- if (UpdateTimer != null)
+ if (_updateTimer != null)
{
- UpdateTimer.Dispose();
- UpdateTimer = null;
+ _updateTimer.Dispose();
+ _updateTimer = null;
}
- _userDataManager.UserDataSaved -= _userDataManager_UserDataSaved;
+ _userDataManager.UserDataSaved -= OnUserDataManagerUserDataSaved;
}
}
}
diff --git a/Emby.Server.Implementations/HttpClientManager/HttpClientManager.cs b/Emby.Server.Implementations/HttpClientManager/HttpClientManager.cs
index 8a2bc83fb..45fa03cdd 100644
--- a/Emby.Server.Implementations/HttpClientManager/HttpClientManager.cs
+++ b/Emby.Server.Implementations/HttpClientManager/HttpClientManager.cs
@@ -78,7 +78,7 @@ namespace Emby.Server.Implementations.HttpClientManager
if (!string.IsNullOrWhiteSpace(userInfo))
{
_logger.LogWarning("Found userInfo in url: {0} ... url: {1}", userInfo, url);
- url = url.Replace(userInfo + '@', string.Empty);
+ url = url.Replace(userInfo + '@', string.Empty, StringComparison.Ordinal);
}
var request = new HttpRequestMessage(method, url);
diff --git a/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs b/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs
index b0126f7fa..85602a67f 100644
--- a/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs
+++ b/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs
@@ -40,9 +40,9 @@ namespace Emby.Server.Implementations.HttpServer
private readonly Func<Type, Func<string, object>> _funcParseFn;
private readonly string _defaultRedirectPath;
private readonly string _baseUrlPrefix;
- private readonly Dictionary<Type, Type> ServiceOperationsMap = new Dictionary<Type, Type>();
- private IWebSocketListener[] _webSocketListeners = Array.Empty<IWebSocketListener>();
+ private readonly Dictionary<Type, Type> _serviceOperationsMap = new Dictionary<Type, Type>();
private readonly List<IWebSocketConnection> _webSocketConnections = new List<IWebSocketConnection>();
+ private IWebSocketListener[] _webSocketListeners = Array.Empty<IWebSocketListener>();
private bool _disposed = false;
public HttpListenerHost(
@@ -72,6 +72,8 @@ namespace Emby.Server.Implementations.HttpServer
ResponseFilters = Array.Empty<Action<IRequest, HttpResponse, object>>();
}
+ public event EventHandler<GenericEventArgs<IWebSocketConnection>> WebSocketConnected;
+
public Action<IRequest, HttpResponse, object>[] ResponseFilters { get; set; }
public static HttpListenerHost Instance { get; protected set; }
@@ -82,8 +84,6 @@ namespace Emby.Server.Implementations.HttpServer
public ServiceController ServiceController { get; private set; }
- public event EventHandler<GenericEventArgs<IWebSocketConnection>> WebSocketConnected;
-
public object CreateInstance(Type type)
{
return _appHost.CreateInstance(type);
@@ -91,7 +91,7 @@ namespace Emby.Server.Implementations.HttpServer
private static string NormalizeUrlPath(string path)
{
- if (path.StartsWith("/"))
+ if (path.Length > 0 && path[0] == '/')
{
// If the path begins with a leading slash, just return it as-is
return path;
@@ -131,13 +131,13 @@ namespace Emby.Server.Implementations.HttpServer
public Type GetServiceTypeByRequest(Type requestType)
{
- ServiceOperationsMap.TryGetValue(requestType, out var serviceType);
+ _serviceOperationsMap.TryGetValue(requestType, out var serviceType);
return serviceType;
}
public void AddServiceInfo(Type serviceType, Type requestType)
{
- ServiceOperationsMap[requestType] = serviceType;
+ _serviceOperationsMap[requestType] = serviceType;
}
private List<IHasRequestFilter> GetRequestFilterAttributes(Type requestDtoType)
@@ -199,7 +199,7 @@ namespace Emby.Server.Implementations.HttpServer
else
{
var inners = agg.InnerExceptions;
- if (inners != null && inners.Count > 0)
+ if (inners.Count > 0)
{
return GetActualException(inners[0]);
}
@@ -362,7 +362,7 @@ namespace Emby.Server.Implementations.HttpServer
return true;
}
- host = host ?? string.Empty;
+ host ??= string.Empty;
if (_networkManager.IsInPrivateAddressSpace(host))
{
@@ -433,7 +433,7 @@ namespace Emby.Server.Implementations.HttpServer
}
/// <summary>
- /// Overridable method that can be used to implement a custom hnandler
+ /// Overridable method that can be used to implement a custom handler.
/// </summary>
public async Task RequestHandler(IHttpRequest httpReq, string urlString, string host, string localPath, CancellationToken cancellationToken)
{
@@ -492,7 +492,7 @@ namespace Emby.Server.Implementations.HttpServer
|| string.Equals(localPath, _baseUrlPrefix, StringComparison.OrdinalIgnoreCase)
|| string.Equals(localPath, "/", StringComparison.OrdinalIgnoreCase)
|| string.IsNullOrEmpty(localPath)
- || !localPath.StartsWith(_baseUrlPrefix))
+ || !localPath.StartsWith(_baseUrlPrefix, StringComparison.OrdinalIgnoreCase))
{
// Always redirect back to the default path if the base prefix is invalid or missing
_logger.LogDebug("Normalizing a URL at {0}", localPath);
@@ -693,7 +693,10 @@ namespace Emby.Server.Implementations.HttpServer
protected virtual void Dispose(bool disposing)
{
- if (_disposed) return;
+ if (_disposed)
+ {
+ return;
+ }
if (disposing)
{
diff --git a/Emby.Server.Implementations/IO/ExtendedFileSystemInfo.cs b/Emby.Server.Implementations/IO/ExtendedFileSystemInfo.cs
index 5be144452..ec26324c3 100644
--- a/Emby.Server.Implementations/IO/ExtendedFileSystemInfo.cs
+++ b/Emby.Server.Implementations/IO/ExtendedFileSystemInfo.cs
@@ -6,7 +6,9 @@ namespace Emby.Server.Implementations.IO
public class ExtendedFileSystemInfo
{
public bool IsHidden { get; set; }
+
public bool IsReadOnly { get; set; }
+
public bool Exists { get; set; }
}
}
diff --git a/Emby.Server.Implementations/IO/FileRefresher.cs b/Emby.Server.Implementations/IO/FileRefresher.cs
index cf92ddbcd..f37a6af90 100644
--- a/Emby.Server.Implementations/IO/FileRefresher.cs
+++ b/Emby.Server.Implementations/IO/FileRefresher.cs
@@ -15,27 +15,29 @@ namespace Emby.Server.Implementations.IO
{
public class FileRefresher : IDisposable
{
- private ILogger Logger { get; set; }
- private ILibraryManager LibraryManager { get; set; }
- private IServerConfigurationManager ConfigurationManager { get; set; }
+ private readonly ILogger _logger;
+ private readonly ILibraryManager _libraryManager;
+ private readonly IServerConfigurationManager _configurationManager;
+
private readonly List<string> _affectedPaths = new List<string>();
- private Timer _timer;
private readonly object _timerLock = new object();
- public string Path { get; private set; }
-
- public event EventHandler<EventArgs> Completed;
+ private Timer _timer;
public FileRefresher(string path, IServerConfigurationManager configurationManager, ILibraryManager libraryManager, ILogger logger)
{
logger.LogDebug("New file refresher created for {0}", path);
Path = path;
- ConfigurationManager = configurationManager;
- LibraryManager = libraryManager;
- Logger = logger;
+ _configurationManager = configurationManager;
+ _libraryManager = libraryManager;
+ _logger = logger;
AddPath(path);
}
+ public event EventHandler<EventArgs> Completed;
+
+ public string Path { get; private set; }
+
private void AddAffectedPath(string path)
{
if (string.IsNullOrEmpty(path))
@@ -80,11 +82,11 @@ namespace Emby.Server.Implementations.IO
if (_timer == null)
{
- _timer = new Timer(OnTimerCallback, null, TimeSpan.FromSeconds(ConfigurationManager.Configuration.LibraryMonitorDelay), TimeSpan.FromMilliseconds(-1));
+ _timer = new Timer(OnTimerCallback, null, TimeSpan.FromSeconds(_configurationManager.Configuration.LibraryMonitorDelay), TimeSpan.FromMilliseconds(-1));
}
else
{
- _timer.Change(TimeSpan.FromSeconds(ConfigurationManager.Configuration.LibraryMonitorDelay), TimeSpan.FromMilliseconds(-1));
+ _timer.Change(TimeSpan.FromSeconds(_configurationManager.Configuration.LibraryMonitorDelay), TimeSpan.FromMilliseconds(-1));
}
}
}
@@ -93,7 +95,7 @@ namespace Emby.Server.Implementations.IO
{
lock (_timerLock)
{
- Logger.LogDebug("Resetting file refresher from {0} to {1}", Path, path);
+ _logger.LogDebug("Resetting file refresher from {0} to {1}", Path, path);
Path = path;
AddAffectedPath(path);
@@ -116,7 +118,7 @@ namespace Emby.Server.Implementations.IO
paths = _affectedPaths.ToList();
}
- Logger.LogDebug("Timer stopped.");
+ _logger.LogDebug("Timer stopped.");
DisposeTimer();
Completed?.Invoke(this, EventArgs.Empty);
@@ -127,7 +129,7 @@ namespace Emby.Server.Implementations.IO
}
catch (Exception ex)
{
- Logger.LogError(ex, "Error processing directory changes");
+ _logger.LogError(ex, "Error processing directory changes");
}
}
@@ -147,7 +149,7 @@ namespace Emby.Server.Implementations.IO
continue;
}
- Logger.LogInformation("{name} ({path}) will be refreshed.", item.Name, item.Path);
+ _logger.LogInformation("{name} ({path}) will be refreshed.", item.Name, item.Path);
try
{
@@ -158,11 +160,11 @@ namespace Emby.Server.Implementations.IO
// For now swallow and log.
// Research item: If an IOException occurs, the item may be in a disconnected state (media unavailable)
// Should we remove it from it's parent?
- Logger.LogError(ex, "Error refreshing {name}", item.Name);
+ _logger.LogError(ex, "Error refreshing {name}", item.Name);
}
catch (Exception ex)
{
- Logger.LogError(ex, "Error refreshing {name}", item.Name);
+ _logger.LogError(ex, "Error refreshing {name}", item.Name);
}
}
}
@@ -178,7 +180,7 @@ namespace Emby.Server.Implementations.IO
while (item == null && !string.IsNullOrEmpty(path))
{
- item = LibraryManager.FindByPath(path, null);
+ item = _libraryManager.FindByPath(path, null);
path = System.IO.Path.GetDirectoryName(path);
}
diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs
index d983c1dc6..5d16a9050 100644
--- a/Emby.Server.Implementations/Library/LibraryManager.cs
+++ b/Emby.Server.Implementations/Library/LibraryManager.cs
@@ -29,11 +29,13 @@ using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.IO;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.LiveTv;
+using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.Controller.Persistence;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Controller.Resolvers;
using MediaBrowser.Controller.Sorting;
using MediaBrowser.Model.Configuration;
+using MediaBrowser.Model.Dlna;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.IO;
@@ -141,6 +143,7 @@ namespace Emby.Server.Implementations.Library
public bool IsScanRunning { get; private set; }
private IServerApplicationHost _appHost;
+ private readonly IMediaEncoder _mediaEncoder;
/// <summary>
/// The _library items cache
@@ -174,7 +177,8 @@ namespace Emby.Server.Implementations.Library
Func<ILibraryMonitor> libraryMonitorFactory,
IFileSystem fileSystem,
Func<IProviderManager> providerManagerFactory,
- Func<IUserViewManager> userviewManager)
+ Func<IUserViewManager> userviewManager,
+ IMediaEncoder mediaEncoder)
{
_appHost = appHost;
_logger = loggerFactory.CreateLogger(nameof(LibraryManager));
@@ -186,6 +190,7 @@ namespace Emby.Server.Implementations.Library
_fileSystem = fileSystem;
_providerManagerFactory = providerManagerFactory;
_userviewManager = userviewManager;
+ _mediaEncoder = mediaEncoder;
_libraryItemsCache = new ConcurrentDictionary<Guid, BaseItem>();
@@ -1169,7 +1174,6 @@ namespace Emby.Server.Implementations.Library
return _fileSystem.GetDirectoryPaths(ConfigurationManager.ApplicationPaths.DefaultUserViewsPath)
.Select(dir => GetVirtualFolderInfo(dir, topLibraryFolders, refreshQueue))
- .OrderBy(i => i.Name)
.ToList();
}
@@ -1401,25 +1405,32 @@ namespace Emby.Server.Implementations.Library
private void SetTopParentOrAncestorIds(InternalItemsQuery query)
{
- if (query.AncestorIds.Length == 0)
+ var ancestorIds = query.AncestorIds;
+ int len = ancestorIds.Length;
+ if (len == 0)
{
return;
}
- var parents = query.AncestorIds.Select(i => GetItemById(i)).ToList();
-
- if (parents.All(i => i is ICollectionFolder || i is UserView))
+ var parents = new BaseItem[len];
+ for (int i = 0; i < len; i++)
{
- // Optimize by querying against top level views
- query.TopParentIds = parents.SelectMany(i => GetTopParentIdsForQuery(i, query.User)).ToArray();
- query.AncestorIds = Array.Empty<Guid>();
-
- // Prevent searching in all libraries due to empty filter
- if (query.TopParentIds.Length == 0)
+ parents[i] = GetItemById(ancestorIds[i]);
+ if (!(parents[i] is ICollectionFolder || parents[i] is UserView))
{
- query.TopParentIds = new[] { Guid.NewGuid() };
+ return;
}
}
+
+ // Optimize by querying against top level views
+ query.TopParentIds = parents.SelectMany(i => GetTopParentIdsForQuery(i, query.User)).ToArray();
+ query.AncestorIds = Array.Empty<Guid>();
+
+ // Prevent searching in all libraries due to empty filter
+ if (query.TopParentIds.Length == 0)
+ {
+ query.TopParentIds = new[] { Guid.NewGuid() };
+ }
}
public QueryResult<(BaseItem, ItemCounts)> GetAlbumArtists(InternalItemsQuery query)
@@ -1580,7 +1591,7 @@ namespace Emby.Server.Implementations.Library
public async Task<IEnumerable<Video>> GetIntros(BaseItem item, User user)
{
var tasks = IntroProviders
- .OrderBy(i => i.GetType().Name.IndexOf("Default", StringComparison.OrdinalIgnoreCase) == -1 ? 0 : 1)
+ .OrderBy(i => i.GetType().Name.Contains("Default", StringComparison.OrdinalIgnoreCase) ? 1 : 0)
.Take(1)
.Select(i => GetIntros(i, item, user));
@@ -2358,33 +2369,22 @@ namespace Emby.Server.Implementations.Library
new SubtitleResolver(BaseItem.LocalizationManager, _fileSystem).AddExternalSubtitleStreams(streams, videoPath, streams.Count, files);
}
- public bool IsVideoFile(string path, LibraryOptions libraryOptions)
+ /// <inheritdoc />
+ public bool IsVideoFile(string path)
{
var resolver = new VideoResolver(GetNamingOptions());
return resolver.IsVideoFile(path);
}
- public bool IsVideoFile(string path)
- {
- return IsVideoFile(path, new LibraryOptions());
- }
-
- public bool IsAudioFile(string path, LibraryOptions libraryOptions)
- {
- var parser = new AudioFileParser(GetNamingOptions());
- return parser.IsAudioFile(path);
- }
-
+ /// <inheritdoc />
public bool IsAudioFile(string path)
- {
- return IsAudioFile(path, new LibraryOptions());
- }
+ => AudioFileParser.IsAudioFile(path, GetNamingOptions());
+ /// <inheritdoc />
public int? GetSeasonNumberFromPath(string path)
- {
- return SeasonPathParser.Parse(path, true, true).SeasonNumber;
- }
+ => SeasonPathParser.Parse(path, true, true).SeasonNumber;
+ /// <inheritdoc />
public bool FillMissingEpisodeNumbersFromPath(Episode episode, bool forceRefresh)
{
var series = episode.Series;
@@ -2408,6 +2408,38 @@ namespace Emby.Server.Implementations.Library
episodeInfo = new Naming.TV.EpisodeInfo();
}
+ try
+ {
+ var libraryOptions = GetLibraryOptions(episode);
+ if (libraryOptions.EnableEmbeddedEpisodeInfos && string.Equals(episodeInfo.Container, "mp4", StringComparison.OrdinalIgnoreCase))
+ {
+ // Read from metadata
+ var mediaInfo = _mediaEncoder.GetMediaInfo(new MediaInfoRequest
+ {
+ MediaSource = episode.GetMediaSources(false)[0],
+ MediaType = DlnaProfileType.Video
+ }, CancellationToken.None).GetAwaiter().GetResult();
+ if (mediaInfo.ParentIndexNumber > 0)
+ {
+ episodeInfo.SeasonNumber = mediaInfo.ParentIndexNumber;
+ }
+
+ if (mediaInfo.IndexNumber > 0)
+ {
+ episodeInfo.EpisodeNumber = mediaInfo.IndexNumber;
+ }
+
+ if (!string.IsNullOrEmpty(mediaInfo.ShowName))
+ {
+ episodeInfo.SeriesName = mediaInfo.ShowName;
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "Error reading the episode informations with ffprobe. Episode: {EpisodeInfo}", episodeInfo.Path);
+ }
+
var changed = false;
if (episodeInfo.IsByDate)
diff --git a/Emby.Server.Implementations/Library/Resolvers/Audio/AudioResolver.cs b/Emby.Server.Implementations/Library/Resolvers/Audio/AudioResolver.cs
index 7e3b27a12..524fb7c10 100644
--- a/Emby.Server.Implementations/Library/Resolvers/Audio/AudioResolver.cs
+++ b/Emby.Server.Implementations/Library/Resolvers/Audio/AudioResolver.cs
@@ -73,7 +73,6 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio
{
// Return audio if the path is a file and has a matching extension
- var libraryOptions = args.GetLibraryOptions();
var collectionType = args.GetCollectionType();
var isBooksCollectionType = string.Equals(collectionType, CollectionType.Books, StringComparison.OrdinalIgnoreCase);
@@ -92,7 +91,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio
return FindAudio<AudioBook>(args, args.Path, args.Parent, files, args.DirectoryService, collectionType, false);
}
- if (LibraryManager.IsAudioFile(args.Path, libraryOptions))
+ if (LibraryManager.IsAudioFile(args.Path))
{
var extension = Path.GetExtension(args.Path);
@@ -105,7 +104,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio
var isMixedCollectionType = string.IsNullOrEmpty(collectionType);
// For conflicting extensions, give priority to videos
- if (isMixedCollectionType && LibraryManager.IsVideoFile(args.Path, libraryOptions))
+ if (isMixedCollectionType && LibraryManager.IsVideoFile(args.Path))
{
return null;
}
@@ -121,7 +120,6 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio
{
item = new MediaBrowser.Controller.Entities.Audio.Audio();
}
-
else if (isBooksCollectionType)
{
item = new AudioBook();
diff --git a/Emby.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs b/Emby.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs
index 9f858f98d..85b1b6e32 100644
--- a/Emby.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs
+++ b/Emby.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs
@@ -5,7 +5,6 @@ using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Controller.Resolvers;
-using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.IO;
using Microsoft.Extensions.Logging;
@@ -78,9 +77,9 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio
/// <summary>
/// Determine if the supplied file data points to a music album.
/// </summary>
- public bool IsMusicAlbum(string path, IDirectoryService directoryService, LibraryOptions libraryOptions)
+ public bool IsMusicAlbum(string path, IDirectoryService directoryService)
{
- return ContainsMusic(directoryService.GetFileSystemEntries(path), true, directoryService, _logger, _fileSystem, libraryOptions, _libraryManager);
+ return ContainsMusic(directoryService.GetFileSystemEntries(path), true, directoryService, _logger, _fileSystem, _libraryManager);
}
/// <summary>
@@ -94,7 +93,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio
if (args.IsDirectory)
{
// if (args.Parent is MusicArtist) return true; //saves us from testing children twice
- if (ContainsMusic(args.FileSystemChildren, true, args.DirectoryService, _logger, _fileSystem, args.GetLibraryOptions(), _libraryManager))
+ if (ContainsMusic(args.FileSystemChildren, true, args.DirectoryService, _logger, _fileSystem, _libraryManager))
{
return true;
}
@@ -112,7 +111,6 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio
IDirectoryService directoryService,
ILogger logger,
IFileSystem fileSystem,
- LibraryOptions libraryOptions,
ILibraryManager libraryManager)
{
var discSubfolderCount = 0;
@@ -132,7 +130,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio
}
var path = fileSystemInfo.FullName;
- var hasMusic = ContainsMusic(directoryService.GetFileSystemEntries(path), false, directoryService, logger, fileSystem, libraryOptions, libraryManager);
+ var hasMusic = ContainsMusic(directoryService.GetFileSystemEntries(path), false, directoryService, logger, fileSystem, libraryManager);
if (hasMusic)
{
@@ -153,7 +151,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio
{
var fullName = fileSystemInfo.FullName;
- if (libraryManager.IsAudioFile(fullName, libraryOptions))
+ if (libraryManager.IsAudioFile(fullName))
{
return true;
}
diff --git a/Emby.Server.Implementations/Library/Resolvers/Audio/MusicArtistResolver.cs b/Emby.Server.Implementations/Library/Resolvers/Audio/MusicArtistResolver.cs
index ee7e84929..013fdbf13 100644
--- a/Emby.Server.Implementations/Library/Resolvers/Audio/MusicArtistResolver.cs
+++ b/Emby.Server.Implementations/Library/Resolvers/Audio/MusicArtistResolver.cs
@@ -80,14 +80,17 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio
}
// Avoid mis-identifying top folders
- if (args.Parent.IsRoot) return null;
+ if (args.Parent.IsRoot)
+ {
+ return null;
+ }
var directoryService = args.DirectoryService;
var albumResolver = new MusicAlbumResolver(_logger, _fileSystem, _libraryManager);
// If we contain an album assume we are an artist folder
- return args.FileSystemChildren.Where(i => i.IsDirectory).Any(i => albumResolver.IsMusicAlbum(i.FullName, directoryService, args.GetLibraryOptions())) ? new MusicArtist() : null;
+ return args.FileSystemChildren.Where(i => i.IsDirectory).Any(i => albumResolver.IsMusicAlbum(i.FullName, directoryService)) ? new MusicArtist() : null;
}
}
}
diff --git a/Emby.Server.Implementations/Library/Resolvers/BaseVideoResolver.cs b/Emby.Server.Implementations/Library/Resolvers/BaseVideoResolver.cs
index 43302bb3f..848cdb7bd 100644
--- a/Emby.Server.Implementations/Library/Resolvers/BaseVideoResolver.cs
+++ b/Emby.Server.Implementations/Library/Resolvers/BaseVideoResolver.cs
@@ -80,6 +80,7 @@ namespace Emby.Server.Implementations.Library.Resolvers
};
break;
}
+
if (IsBluRayDirectory(child.FullName, filename, args.DirectoryService))
{
videoInfo = parser.ResolveDirectory(args.Path);
@@ -137,7 +138,7 @@ namespace Emby.Server.Implementations.Library.Resolvers
return null;
}
- if (LibraryManager.IsVideoFile(args.Path, args.GetLibraryOptions()) || videoInfo.IsStub)
+ if (LibraryManager.IsVideoFile(args.Path) || videoInfo.IsStub)
{
var path = args.Path;
diff --git a/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs b/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs
index 08db168bc..cb67c8aa7 100644
--- a/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs
+++ b/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs
@@ -436,7 +436,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
if (result.Items.Count == 1)
{
var videoPath = result.Items[0].Path;
- var hasPhotos = photos.Any(i => !PhotoResolver.IsOwnedByResolvedMedia(LibraryManager, libraryOptions, videoPath, i.Name));
+ var hasPhotos = photos.Any(i => !PhotoResolver.IsOwnedByResolvedMedia(LibraryManager, videoPath, i.Name));
if (!hasPhotos)
{
@@ -446,8 +446,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
return movie;
}
}
-
- if (result.Items.Count == 0 && multiDiscFolders.Count > 0)
+ else if (result.Items.Count == 0 && multiDiscFolders.Count > 0)
{
return GetMultiDiscMovie<T>(multiDiscFolders, directoryService);
}
@@ -519,14 +518,15 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
return null;
}
+ int additionalPartsLen = folderPaths.Count - 1;
+ var additionalParts = new string[additionalPartsLen];
+ folderPaths.CopyTo(1, additionalParts, 0, additionalPartsLen);
+
var returnVideo = new T
{
Path = folderPaths[0],
-
- AdditionalParts = folderPaths.Skip(1).ToArray(),
-
+ AdditionalParts = additionalParts,
VideoType = videoTypes[0],
-
Name = result[0].Name
};
diff --git a/Emby.Server.Implementations/Library/Resolvers/PhotoAlbumResolver.cs b/Emby.Server.Implementations/Library/Resolvers/PhotoAlbumResolver.cs
index 4536b0aaa..3ac837057 100644
--- a/Emby.Server.Implementations/Library/Resolvers/PhotoAlbumResolver.cs
+++ b/Emby.Server.Implementations/Library/Resolvers/PhotoAlbumResolver.cs
@@ -63,13 +63,12 @@ namespace Emby.Server.Implementations.Library.Resolvers
{
if (!file.IsDirectory && PhotoResolver.IsImageFile(file.FullName, _imageProcessor))
{
- var libraryOptions = args.GetLibraryOptions();
var filename = file.Name;
var ownedByMedia = false;
foreach (var siblingFile in files)
{
- if (PhotoResolver.IsOwnedByMedia(_libraryManager, libraryOptions, siblingFile.FullName, filename))
+ if (PhotoResolver.IsOwnedByMedia(_libraryManager, siblingFile.FullName, filename))
{
ownedByMedia = true;
break;
diff --git a/Emby.Server.Implementations/Library/Resolvers/PhotoResolver.cs b/Emby.Server.Implementations/Library/Resolvers/PhotoResolver.cs
index e1eb23652..8ad546f8e 100644
--- a/Emby.Server.Implementations/Library/Resolvers/PhotoResolver.cs
+++ b/Emby.Server.Implementations/Library/Resolvers/PhotoResolver.cs
@@ -8,7 +8,6 @@ using System.Linq;
using MediaBrowser.Controller.Drawing;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
-using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Entities;
namespace Emby.Server.Implementations.Library.Resolvers
@@ -57,11 +56,10 @@ namespace Emby.Server.Implementations.Library.Resolvers
// Make sure the image doesn't belong to a video file
var files = args.DirectoryService.GetFiles(Path.GetDirectoryName(args.Path));
- var libraryOptions = args.GetLibraryOptions();
foreach (var file in files)
{
- if (IsOwnedByMedia(_libraryManager, libraryOptions, file.FullName, filename))
+ if (IsOwnedByMedia(_libraryManager, file.FullName, filename))
{
return null;
}
@@ -78,17 +76,17 @@ namespace Emby.Server.Implementations.Library.Resolvers
return null;
}
- internal static bool IsOwnedByMedia(ILibraryManager libraryManager, LibraryOptions libraryOptions, string file, string imageFilename)
+ internal static bool IsOwnedByMedia(ILibraryManager libraryManager, string file, string imageFilename)
{
- if (libraryManager.IsVideoFile(file, libraryOptions))
+ if (libraryManager.IsVideoFile(file))
{
- return IsOwnedByResolvedMedia(libraryManager, libraryOptions, file, imageFilename);
+ return IsOwnedByResolvedMedia(libraryManager, file, imageFilename);
}
return false;
}
- internal static bool IsOwnedByResolvedMedia(ILibraryManager libraryManager, LibraryOptions libraryOptions, string file, string imageFilename)
+ internal static bool IsOwnedByResolvedMedia(ILibraryManager libraryManager, string file, string imageFilename)
=> imageFilename.StartsWith(Path.GetFileNameWithoutExtension(file), StringComparison.OrdinalIgnoreCase);
internal static bool IsImageFile(string path, IImageProcessor imageProcessor)
diff --git a/Emby.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs b/Emby.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs
index 4ee30b475..b547fc8c9 100644
--- a/Emby.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs
+++ b/Emby.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs
@@ -102,7 +102,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV
return null;
}
- if (IsSeriesFolder(args.Path, args.FileSystemChildren, args.DirectoryService, _fileSystem, _logger, _libraryManager, args.GetLibraryOptions(), false))
+ if (IsSeriesFolder(args.Path, args.FileSystemChildren, args.DirectoryService, _fileSystem, _logger, _libraryManager, false))
{
return new Series
{
@@ -123,24 +123,10 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV
IFileSystem fileSystem,
ILogger logger,
ILibraryManager libraryManager,
- LibraryOptions libraryOptions,
bool isTvContentType)
{
foreach (var child in fileSystemChildren)
{
- //if ((attributes & FileAttributes.Hidden) == FileAttributes.Hidden)
- //{
- // //logger.LogDebug("Igoring series file or folder marked hidden: {0}", child.FullName);
- // continue;
- //}
-
- // Can't enforce this because files saved by Bitcasa are always marked System
- //if ((attributes & FileAttributes.System) == FileAttributes.System)
- //{
- // logger.LogDebug("Igoring series subfolder marked system: {0}", child.FullName);
- // continue;
- //}
-
if (child.IsDirectory)
{
if (IsSeasonFolder(child.FullName, isTvContentType, libraryManager))
@@ -152,7 +138,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV
else
{
string fullName = child.FullName;
- if (libraryManager.IsVideoFile(fullName, libraryOptions))
+ if (libraryManager.IsVideoFile(fullName))
{
if (isTvContentType)
{
diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs
index 161cf6051..9c4f5fe3d 100644
--- a/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs
+++ b/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs
@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using System;
using System.IO;
using System.Net.Http;
diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
index 4ac48e537..49d4ddbaf 100644
--- a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
+++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
@@ -30,7 +30,6 @@ using MediaBrowser.Model.Diagnostics;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Events;
-using MediaBrowser.Model.Extensions;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.LiveTv;
using MediaBrowser.Model.MediaInfo;
diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs
index 6e4ac2fec..8590c56df 100644
--- a/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs
+++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs
@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using System;
using System.Collections.Generic;
using System.Globalization;
diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EntryPoint.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EntryPoint.cs
index 9c9ba09f5..a716b6240 100644
--- a/Emby.Server.Implementations/LiveTv/EmbyTV/EntryPoint.cs
+++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EntryPoint.cs
@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using System.Threading.Tasks;
using MediaBrowser.Controller.Plugins;
@@ -5,11 +8,13 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
{
public class EntryPoint : IServerEntryPoint
{
+ /// <inheritdoc />
public Task RunAsync()
{
return EmbyTV.Current.Start();
}
+ /// <inheritdoc />
public void Dispose()
{
}
diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/IRecorder.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/IRecorder.cs
index 6eced3050..d6a1aee38 100644
--- a/Emby.Server.Implementations/LiveTv/EmbyTV/IRecorder.cs
+++ b/Emby.Server.Implementations/LiveTv/EmbyTV/IRecorder.cs
@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using System;
using System.Threading;
using System.Threading.Tasks;
diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs
index 9055a70a6..6d42a58f4 100644
--- a/Emby.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs
+++ b/Emby.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs
@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using System;
using System.Collections.Generic;
using System.IO;
diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/RecordingHelper.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/RecordingHelper.cs
index ded3c7607..4cb9f6fe8 100644
--- a/Emby.Server.Implementations/LiveTv/EmbyTV/RecordingHelper.cs
+++ b/Emby.Server.Implementations/LiveTv/EmbyTV/RecordingHelper.cs
@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using System;
using System.Globalization;
using MediaBrowser.Controller.LiveTv;
@@ -21,7 +24,11 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
if (info.SeasonNumber.HasValue && info.EpisodeNumber.HasValue)
{
- name += string.Format(" S{0}E{1}", info.SeasonNumber.Value.ToString("00", CultureInfo.InvariantCulture), info.EpisodeNumber.Value.ToString("00", CultureInfo.InvariantCulture));
+ name += string.Format(
+ CultureInfo.InvariantCulture,
+ " S{0}E{1}",
+ info.SeasonNumber.Value.ToString("00", CultureInfo.InvariantCulture),
+ info.EpisodeNumber.Value.ToString("00", CultureInfo.InvariantCulture));
addHyphen = false;
}
else if (info.OriginalAirDate.HasValue)
@@ -32,7 +39,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
}
else
{
- name += " " + info.OriginalAirDate.Value.ToLocalTime().ToString("yyyy-MM-dd");
+ name += " " + info.OriginalAirDate.Value.ToLocalTime().ToString("yyyy-MM-dd", CultureInfo.InvariantCulture);
}
}
else
@@ -67,14 +74,15 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
{
date = date.ToLocalTime();
- return string.Format("{0}_{1}_{2}_{3}_{4}_{5}",
+ return string.Format(
+ CultureInfo.InvariantCulture,
+ "{0}_{1}_{2}_{3}_{4}_{5}",
date.Year.ToString("0000", CultureInfo.InvariantCulture),
date.Month.ToString("00", CultureInfo.InvariantCulture),
date.Day.ToString("00", CultureInfo.InvariantCulture),
date.Hour.ToString("00", CultureInfo.InvariantCulture),
date.Minute.ToString("00", CultureInfo.InvariantCulture),
- date.Second.ToString("00", CultureInfo.InvariantCulture)
- );
+ date.Second.ToString("00", CultureInfo.InvariantCulture));
}
}
}
diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/SeriesTimerManager.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/SeriesTimerManager.cs
index 520b44404..9cc53fddc 100644
--- a/Emby.Server.Implementations/LiveTv/EmbyTV/SeriesTimerManager.cs
+++ b/Emby.Server.Implementations/LiveTv/EmbyTV/SeriesTimerManager.cs
@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using System;
using MediaBrowser.Controller.LiveTv;
using MediaBrowser.Model.Serialization;
@@ -12,6 +15,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
{
}
+ /// <inheritdoc />
public override void Add(SeriesTimerInfo item)
{
if (string.IsNullOrEmpty(item.Id))
diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs
index d09b281d4..330e881ef 100644
--- a/Emby.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs
+++ b/Emby.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs
@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using System;
using System.Collections.Concurrent;
using System.Globalization;
diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs
index 1dd794da0..906f42d2e 100644
--- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs
+++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs
@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
diff --git a/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs b/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs
index 1f38de2d8..42daa98f5 100644
--- a/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs
+++ b/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs
@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using System;
using System.Collections.Generic;
using System.Globalization;
@@ -91,12 +94,12 @@ namespace Emby.Server.Implementations.LiveTv.Listings
{
using (var gzStream = new GZipStream(stream, CompressionMode.Decompress))
{
- await gzStream.CopyToAsync(fileStream).ConfigureAwait(false);
+ await gzStream.CopyToAsync(fileStream, cancellationToken).ConfigureAwait(false);
}
}
else
{
- await stream.CopyToAsync(fileStream).ConfigureAwait(false);
+ await stream.CopyToAsync(fileStream, cancellationToken).ConfigureAwait(false);
}
}
diff --git a/Emby.Server.Implementations/LiveTv/LiveTvConfigurationFactory.cs b/Emby.Server.Implementations/LiveTv/LiveTvConfigurationFactory.cs
index f9b274acb..222fed9d9 100644
--- a/Emby.Server.Implementations/LiveTv/LiveTvConfigurationFactory.cs
+++ b/Emby.Server.Implementations/LiveTv/LiveTvConfigurationFactory.cs
@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using System.Collections.Generic;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Model.LiveTv;
diff --git a/Emby.Server.Implementations/LiveTv/LiveTvDtoService.cs b/Emby.Server.Implementations/LiveTv/LiveTvDtoService.cs
index e584664c9..14b627f82 100644
--- a/Emby.Server.Implementations/LiveTv/LiveTvDtoService.cs
+++ b/Emby.Server.Implementations/LiveTv/LiveTvDtoService.cs
@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using System;
using System.Globalization;
using System.Linq;
diff --git a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs
index e3f9df35a..f20f6140e 100644
--- a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs
+++ b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs
@@ -1,5 +1,5 @@
-#pragma warning disable SA1600
#pragma warning disable CS1591
+#pragma warning disable SA1600
using System;
using System.Collections.Generic;
diff --git a/Emby.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs b/Emby.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs
index 52d60c004..33887bbfd 100644
--- a/Emby.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs
+++ b/Emby.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs
@@ -1,52 +1,48 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
-using MediaBrowser.Common.Configuration;
using MediaBrowser.Controller;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.LiveTv;
-using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.MediaInfo;
-using MediaBrowser.Model.Serialization;
using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.LiveTv
{
public class LiveTvMediaSourceProvider : IMediaSourceProvider
{
+ // Do not use a pipe here because Roku http requests to the server will fail, without any explicit error message.
+ private const char StreamIdDelimeter = '_';
+ private const string StreamIdDelimeterString = "_";
+
private readonly ILiveTvManager _liveTvManager;
- private readonly IJsonSerializer _jsonSerializer;
private readonly ILogger _logger;
private readonly IMediaSourceManager _mediaSourceManager;
- private readonly IMediaEncoder _mediaEncoder;
private readonly IServerApplicationHost _appHost;
- private IApplicationPaths _appPaths;
- public LiveTvMediaSourceProvider(ILiveTvManager liveTvManager, IApplicationPaths appPaths, IJsonSerializer jsonSerializer, ILoggerFactory loggerFactory, IMediaSourceManager mediaSourceManager, IMediaEncoder mediaEncoder, IServerApplicationHost appHost)
+ public LiveTvMediaSourceProvider(ILiveTvManager liveTvManager, ILogger<LiveTvMediaSourceProvider> logger, IMediaSourceManager mediaSourceManager, IServerApplicationHost appHost)
{
_liveTvManager = liveTvManager;
- _jsonSerializer = jsonSerializer;
+ _logger = logger;
_mediaSourceManager = mediaSourceManager;
- _mediaEncoder = mediaEncoder;
_appHost = appHost;
- _logger = loggerFactory.CreateLogger(GetType().Name);
- _appPaths = appPaths;
}
public Task<IEnumerable<MediaSourceInfo>> GetMediaSources(BaseItem item, CancellationToken cancellationToken)
{
- var baseItem = (BaseItem)item;
-
- if (baseItem.SourceType == SourceType.LiveTV)
+ if (item.SourceType == SourceType.LiveTV)
{
var activeRecordingInfo = _liveTvManager.GetActiveRecordingInfo(item.Path);
- if (string.IsNullOrEmpty(baseItem.Path) || activeRecordingInfo != null)
+ if (string.IsNullOrEmpty(item.Path) || activeRecordingInfo != null)
{
return GetMediaSourcesInternal(item, activeRecordingInfo, cancellationToken);
}
@@ -55,10 +51,6 @@ namespace Emby.Server.Implementations.LiveTv
return Task.FromResult<IEnumerable<MediaSourceInfo>>(Array.Empty<MediaSourceInfo>());
}
- // Do not use a pipe here because Roku http requests to the server will fail, without any explicit error message.
- private const char StreamIdDelimeter = '_';
- private const string StreamIdDelimeterString = "_";
-
private async Task<IEnumerable<MediaSourceInfo>> GetMediaSourcesInternal(BaseItem item, ActiveRecordingInfo activeRecordingInfo, CancellationToken cancellationToken)
{
IEnumerable<MediaSourceInfo> sources;
@@ -91,7 +83,7 @@ namespace Emby.Server.Implementations.LiveTv
foreach (var source in list)
{
source.Type = MediaSourceType.Default;
- source.BufferMs = source.BufferMs ?? 1500;
+ source.BufferMs ??= 1500;
if (source.RequiresOpening || forceRequireOpening)
{
@@ -100,11 +92,14 @@ namespace Emby.Server.Implementations.LiveTv
if (source.RequiresOpening)
{
- var openKeys = new List<string>();
- openKeys.Add(item.GetType().Name);
- openKeys.Add(item.Id.ToString("N", CultureInfo.InvariantCulture));
- openKeys.Add(source.Id ?? string.Empty);
- source.OpenToken = string.Join(StreamIdDelimeterString, openKeys.ToArray());
+ var openKeys = new List<string>
+ {
+ item.GetType().Name,
+ item.Id.ToString("N", CultureInfo.InvariantCulture),
+ source.Id ?? string.Empty
+ };
+
+ source.OpenToken = string.Join(StreamIdDelimeterString, openKeys);
}
// Dummy this up so that direct play checks can still run
@@ -114,11 +109,12 @@ namespace Emby.Server.Implementations.LiveTv
}
}
- _logger.LogDebug("MediaSources: {0}", _jsonSerializer.SerializeToString(list));
+ _logger.LogDebug("MediaSources: {@MediaSources}", list);
return list;
}
+ /// <inheritdoc />
public async Task<ILiveStream> OpenMediaSource(string openToken, List<ILiveStream> currentLiveStreams, CancellationToken cancellationToken)
{
var keys = openToken.Split(new[] { StreamIdDelimeter }, 3);
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs
index 715f600a1..419ec3635 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs
@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs
index 06f27fa3e..e5cb6c7b9 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs
@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using System;
using System.Collections.Generic;
using System.Globalization;
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunManager.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunManager.cs
index 9702392b2..56864ab11 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunManager.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunManager.cs
@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using System;
using System.Buffers;
using System.Collections.Generic;
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs
index 649becbd3..77669da39 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs
@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using System;
using System.Collections.Generic;
using System.IO;
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs
index 862b9fdfe..5354489f9 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs
@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using System;
using System.Collections.Generic;
using System.Globalization;
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs
index df054f1eb..46c77e7b0 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs
@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using System;
using System.Collections.Generic;
using System.Globalization;
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs
index 51f61bac7..511af150b 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs
@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using System;
using System.Collections.Generic;
using System.Globalization;
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs
index 99244eb62..861518387 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs
@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using System;
using System.Collections.Generic;
using System.IO;
diff --git a/Emby.Server.Implementations/Localization/Core/bn.json b/Emby.Server.Implementations/Localization/Core/bn.json
new file mode 100644
index 000000000..a7219a725
--- /dev/null
+++ b/Emby.Server.Implementations/Localization/Core/bn.json
@@ -0,0 +1,96 @@
+{
+ "DeviceOnlineWithName": "{0}-এর সাথে সংযুক্ত হয়েছে",
+ "DeviceOfflineWithName": "{0}-এর সাথে সংযোগ বিচ্ছিন্ন হয়েছে",
+ "Collections": "সংকলন",
+ "ChapterNameValue": "অধ্যায় {0}",
+ "Channels": "চ্যানেল",
+ "CameraImageUploadedFrom": "একটি নতুন ক্যামেরার চিত্র আপলোড করা হয়েছে {0} থেকে",
+ "Books": "বই",
+ "AuthenticationSucceededWithUserName": "{0} যাচাই সফল",
+ "Artists": "শিল্পী",
+ "Application": "অ্যাপ্লিকেশন",
+ "Albums": "অ্যালবামগুলো",
+ "HeaderFavoriteEpisodes": "প্রিব পর্বগুলো",
+ "HeaderFavoriteArtists": "প্রিয় শিল্পীরা",
+ "HeaderFavoriteAlbums": "প্রিয় এলবামগুলো",
+ "HeaderContinueWatching": "দেখতে থাকুন",
+ "HeaderCameraUploads": "ক্যামেরার আপলোডগুলো",
+ "HeaderAlbumArtists": "এলবামের শিল্পী",
+ "Genres": "ঘরানা",
+ "Folders": "ফোল্ডারগুলো",
+ "Favorites": "ফেভারিটগুলো",
+ "FailedLoginAttemptWithUserName": "{0} থেকে লগিন করতে ব্যর্থ",
+ "AppDeviceValues": "এপ: {0}, ডিভাইস: {0}",
+ "VersionNumber": "সংস্করণ {0}",
+ "ValueSpecialEpisodeName": "বিশেষ - {0}",
+ "ValueHasBeenAddedToLibrary": "আপনার লাইব্রেরিতে {0} যোগ করা হয়েছে",
+ "UserStoppedPlayingItemWithValues": "{2}তে {1} বাজানো শেষ করেছেন {0}",
+ "UserStartedPlayingItemWithValues": "{2}তে {1} বাজাচ্ছেন {0}",
+ "UserPolicyUpdatedWithName": "{0} এর জন্য ব্যবহার নীতি আপডেট করা হয়েছে",
+ "UserPasswordChangedWithName": "ব্যবহারকারী {0} এর পাসওয়ার্ড পরিবর্তিত হয়েছে",
+ "UserOnlineFromDevice": "{0}, {1} থেকে অনলাইন",
+ "UserOfflineFromDevice": "{0} {1} থেকে বিযুক্ত হয়ে গেছে",
+ "UserLockedOutWithName": "ব্যবহারকারী {0} ঢুকতে পারছে না",
+ "UserDownloadingItemWithValues": "{0}, {1} ডাউনলোড করছে",
+ "UserDeletedWithName": "ব্যবহারকারী {0}কে বাদ দেয়া হয়েছে",
+ "UserCreatedWithName": "ব্যবহারকারী {0} সৃষ্টি করা হয়েছে",
+ "User": "ব্যবহারকারী",
+ "TvShows": "টিভি শোগুলো",
+ "System": "সিস্টেম",
+ "Sync": "সিংক",
+ "SubtitlesDownloadedForItem": "{0} এর জন্য সাবটাইটেল ডাউনলোড করা হয়েছে",
+ "SubtitleDownloadFailureFromForItem": "{2} থেকে {1} এর জন্য সাবটাইটেল ডাউনলোড ব্যর্থ",
+ "StartupEmbyServerIsLoading": "জেলিফিন সার্ভার লোড হচ্ছে। দয়া করে একটু পরে আবার চেষ্টা করুন।",
+ "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": "জেলিফিন সার্ভারের একটি নতুন ভার্শন ডাউনলোডের জন্য তৈরী",
+ "NameSeasonUnknown": "সিজন অজানা",
+ "NameSeasonNumber": "সিজন {0}",
+ "NameInstallFailed": "{0} ইন্সটল ব্যর্থ",
+ "MusicVideos": "গানের ভিডিও",
+ "Music": "গান",
+ "Movies": "সিনেমা",
+ "MixedContent": "মিশ্র কন্টেন্ট",
+ "MessageServerConfigurationUpdated": "সার্ভারের কনফিগারেশন হালনাগাদ করা হয়েছে",
+ "HeaderRecordingGroups": "রেকর্ডিং গ্রুপ",
+ "MessageNamedServerConfigurationUpdatedWithValue": "সার্ভারের {0} কনফিগারেসন অংশ আপডেট করা হয়েছে",
+ "MessageApplicationUpdatedTo": "জেলিফিন সার্ভার {0} তে হালনাগাদ করা হয়েছে",
+ "MessageApplicationUpdated": "জেলিফিন সার্ভার হালনাগাদ করা হয়েছে",
+ "Latest": "একদম নতুন",
+ "LabelRunningTimeValue": "চলার সময়: {0}",
+ "LabelIpAddressValue": "আইপি ঠিকানা: {0}",
+ "ItemRemovedWithName": "{0} লাইব্রেরি থেকে বাদ দেয়া হয়েছে",
+ "ItemAddedWithName": "{0} লাইব্রেরিতে যোগ করা হয়েছে",
+ "Inherit": "থেকে পাওয়া",
+ "HomeVideos": "বাসার ভিডিও",
+ "HeaderNextUp": "এরপরে আসছে",
+ "HeaderLiveTV": "লাইভ টিভি",
+ "HeaderFavoriteSongs": "প্রিয় গানগুলো",
+ "HeaderFavoriteShows": "প্রিয় শোগুলো"
+}
diff --git a/Emby.Server.Implementations/Localization/Core/es_DO.json b/Emby.Server.Implementations/Localization/Core/es_DO.json
new file mode 100644
index 000000000..1ac8d3ae4
--- /dev/null
+++ b/Emby.Server.Implementations/Localization/Core/es_DO.json
@@ -0,0 +1,14 @@
+{
+ "Channels": "Canales",
+ "Books": "Libros",
+ "Albums": "Álbumes",
+ "Collections": "Colecciones",
+ "Artists": "Artistas",
+ "DeviceOnlineWithName": "{0} está conectado",
+ "DeviceOfflineWithName": "{0} ha desconectado",
+ "ChapterNameValue": "Capítulo {0}",
+ "CameraImageUploadedFrom": "Se ha subido una nueva imagen de cámara desde {0}",
+ "AuthenticationSucceededWithUserName": "{0} autenticado con éxito",
+ "Application": "Aplicación",
+ "AppDeviceValues": "App: {0}, Dispositivo: {1}"
+}
diff --git a/Emby.Server.Implementations/Localization/Core/fi.json b/Emby.Server.Implementations/Localization/Core/fi.json
index 1bd906b8e..d02f841fd 100644
--- a/Emby.Server.Implementations/Localization/Core/fi.json
+++ b/Emby.Server.Implementations/Localization/Core/fi.json
@@ -1,6 +1,6 @@
{
- "HeaderLiveTV": "Netti-TV",
- "NewVersionIsAvailable": "Uusi versio Jellyfin palvelimesta on ladattavissa",
+ "HeaderLiveTV": "TV-lähetykset",
+ "NewVersionIsAvailable": "Uusi versio Jellyfin palvelimesta on ladattavissa.",
"NameSeasonUnknown": "Tuntematon Kausi",
"NameSeasonNumber": "Kausi {0}",
"NameInstallFailed": "{0} asennus epäonnistui",
@@ -8,28 +8,28 @@
"Music": "Musiikki",
"Movies": "Elokuvat",
"MixedContent": "Sekoitettu sisältö",
- "MessageServerConfigurationUpdated": "Palvelimen konfiguraatio on päivitetty",
- "MessageNamedServerConfigurationUpdatedWithValue": "Palvelimen konfiguraatio-osa {0} on päivitetty",
- "MessageApplicationUpdatedTo": "Jellyfin palvelin on päivitetty {0}",
+ "MessageServerConfigurationUpdated": "Palvelimen asetukset on päivitetty",
+ "MessageNamedServerConfigurationUpdatedWithValue": "Palvelimen asetusryhmä {0} on päivitetty",
+ "MessageApplicationUpdatedTo": "Jellyfin palvelin on päivitetty versioon {0}",
"MessageApplicationUpdated": "Jellyfin palvelin on päivitetty",
"Latest": "Viimeisin",
- "LabelRunningTimeValue": "Kesto: {0}",
+ "LabelRunningTimeValue": "Toiston kesto: {0}",
"LabelIpAddressValue": "IP-osoite: {0}",
"ItemRemovedWithName": "{0} poistettiin kirjastosta",
"ItemAddedWithName": "{0} lisättiin kirjastoon",
"Inherit": "Periä",
"HomeVideos": "Kotivideot",
- "HeaderRecordingGroups": "Äänitysryhmä",
+ "HeaderRecordingGroups": "Äänitysryhmät",
"HeaderNextUp": "Seuraavaksi",
"HeaderFavoriteSongs": "Lempikappaleet",
"HeaderFavoriteShows": "Lempisarjat",
"HeaderFavoriteEpisodes": "Lempijaksot",
- "HeaderCameraUploads": "Kamera lataukset",
+ "HeaderCameraUploads": "Kamerasta lähetetyt",
"HeaderFavoriteArtists": "Lempiartistit",
"HeaderFavoriteAlbums": "Lempialbumit",
- "HeaderContinueWatching": "Jatka Katsomista",
- "HeaderAlbumArtists": "Albumiartistit",
- "Genres": "Lajipiiri",
+ "HeaderContinueWatching": "Jatka katsomista",
+ "HeaderAlbumArtists": "Albumin artistit",
+ "Genres": "Tyylilaji",
"Folders": "Kansiot",
"Favorites": "Suosikit",
"FailedLoginAttemptWithUserName": "Epäonnistunut kirjautumisyritys kohteesta {0}",
@@ -44,5 +44,53 @@
"Artists": "Artistit",
"Application": "Sovellus",
"AppDeviceValues": "Sovellus: {0}, Laite: {1}",
- "Albums": "Albumit"
+ "Albums": "Albumit",
+ "User": "Käyttäjä",
+ "System": "Järjestelmä",
+ "ScheduledTaskFailedWithName": "{0} epäonnistui",
+ "PluginUpdatedWithName": "{0} päivitetty",
+ "PluginInstalledWithName": "{0} asennettu",
+ "Photos": "Kuvat",
+ "ScheduledTaskStartedWithName": "{0} aloitettu",
+ "PluginUninstalledWithName": "{0} poistettu",
+ "Playlists": "Soittolistat",
+ "VersionNumber": "Versio {0}",
+ "ValueSpecialEpisodeName": "Erikois - {0}",
+ "ValueHasBeenAddedToLibrary": "{0} lisättiin mediakirjastoon",
+ "UserStoppedPlayingItemWithValues": "{0} toistaminen valmistui {1} laitteella {2}",
+ "UserStartedPlayingItemWithValues": "{0} toistaa {1} laitteella {2}",
+ "UserPolicyUpdatedWithName": "Käyttöoikeudet päivitetty käyttäjälle {0}",
+ "UserPasswordChangedWithName": "Salasana vaihdettu käyttäjälle {0}",
+ "UserOnlineFromDevice": "{0} on paikalla osoitteesta {1}",
+ "UserOfflineFromDevice": "{0} yhteys katkaistu {1}",
+ "UserLockedOutWithName": "Käyttäjä {0} kirjautui ulos",
+ "UserDownloadingItemWithValues": "{0} latautumassa {1}",
+ "UserDeletedWithName": "Poistettiin käyttäjä {0}",
+ "UserCreatedWithName": "Luotiin käyttäjä {0}",
+ "TvShows": "TV-Ohjelmat",
+ "Sync": "Synkronoi",
+ "SubtitlesDownloadedForItem": "Tekstitys ladattu {0}",
+ "SubtitleDownloadFailureFromForItem": "Tekstityksen lataaminen epäonnistui {0} - {1}",
+ "StartupEmbyServerIsLoading": "Jellyfin palvelin latautuu. Kokeile hetken kuluttua uudelleen.",
+ "Songs": "Kappaleet",
+ "Shows": "Ohjelmat",
+ "ServerNameNeedsToBeRestarted": "{0} vaatii uudelleenkäynnistyksen",
+ "ProviderValue": "Palveluntarjoaja: {0}",
+ "Plugin": "Laajennus",
+ "NotificationOptionVideoPlaybackStopped": "Videon toistaminen pysäytetty",
+ "NotificationOptionVideoPlayback": "Videon toistaminen aloitettu",
+ "NotificationOptionUserLockedOut": "Käyttäjä kirjautui ulos",
+ "NotificationOptionTaskFailed": "Ajastetun tehtävän ongelma",
+ "NotificationOptionServerRestartRequired": "Palvelimen uudelleenkäynnistys vaaditaan",
+ "NotificationOptionPluginUpdateInstalled": "Laajennuksen päivitys asennettu",
+ "NotificationOptionPluginUninstalled": "Laajennus poistettu",
+ "NotificationOptionPluginInstalled": "Laajennus asennettu",
+ "NotificationOptionPluginError": "Ongelma laajennuksessa",
+ "NotificationOptionNewLibraryContent": "Uusi sisältö lisätty",
+ "NotificationOptionInstallationFailed": "Asennusvirhe",
+ "NotificationOptionCameraImageUploaded": "Kameran kuva lisätty",
+ "NotificationOptionAudioPlaybackStopped": "Äänen toistaminen pysäytetty",
+ "NotificationOptionAudioPlayback": "Äänen toistaminen aloitettu",
+ "NotificationOptionApplicationUpdateInstalled": "Ohjelmistopäivitys asennettu",
+ "NotificationOptionApplicationUpdateAvailable": "Ohjelmistopäivitys saatavilla"
}
diff --git a/Emby.Server.Implementations/Localization/Core/hu.json b/Emby.Server.Implementations/Localization/Core/hu.json
index 3a6852321..950be68d0 100644
--- a/Emby.Server.Implementations/Localization/Core/hu.json
+++ b/Emby.Server.Implementations/Localization/Core/hu.json
@@ -1,7 +1,7 @@
{
"Albums": "Albumok",
"AppDeviceValues": "Program: {0}, Eszköz: {1}",
- "Application": "Program",
+ "Application": "Alkalmazás",
"Artists": "Előadók",
"AuthenticationSucceededWithUserName": "{0} sikeresen azonosítva",
"Books": "Könyvek",
@@ -17,7 +17,7 @@
"Genres": "Műfajok",
"HeaderAlbumArtists": "Album előadók",
"HeaderCameraUploads": "Kamera feltöltések",
- "HeaderContinueWatching": "Folyamatban lévő filmek",
+ "HeaderContinueWatching": "Megtekintés folytatása",
"HeaderFavoriteAlbums": "Kedvenc albumok",
"HeaderFavoriteArtists": "Kedvenc előadók",
"HeaderFavoriteEpisodes": "Kedvenc epizódok",
@@ -27,7 +27,7 @@
"HeaderNextUp": "Következik",
"HeaderRecordingGroups": "Felvételi csoportok",
"HomeVideos": "Házi videók",
- "Inherit": "Inherit",
+ "Inherit": "Öröklés",
"ItemAddedWithName": "{0} hozzáadva a könyvtárhoz",
"ItemRemovedWithName": "{0} eltávolítva a könyvtárból",
"LabelIpAddressValue": "IP cím: {0}",
@@ -42,7 +42,7 @@
"Music": "Zene",
"MusicVideos": "Zenei videók",
"NameInstallFailed": "{0} sikertelen telepítés",
- "NameSeasonNumber": "Évad {0}",
+ "NameSeasonNumber": "{0}. évad",
"NameSeasonUnknown": "Ismeretlen évad",
"NewVersionIsAvailable": "Letölthető a Jellyfin Szerver új verziója.",
"NotificationOptionApplicationUpdateAvailable": "Frissítés érhető el az alkalmazáshoz",
diff --git a/Emby.Server.Implementations/Localization/Core/id.json b/Emby.Server.Implementations/Localization/Core/id.json
index 13415eda5..38c6cf54f 100644
--- a/Emby.Server.Implementations/Localization/Core/id.json
+++ b/Emby.Server.Implementations/Localization/Core/id.json
@@ -86,5 +86,10 @@
"FailedLoginAttemptWithUserName": "Percobaan login gagal dari {0}",
"CameraImageUploadedFrom": "Sebuah gambar baru telah diunggah dari {0}",
"DeviceOfflineWithName": "{0} telah terputus",
- "DeviceOnlineWithName": "{0} telah terhubung"
+ "DeviceOnlineWithName": "{0} telah terhubung",
+ "NotificationOptionVideoPlaybackStopped": "Pemutaran video berhenti",
+ "NotificationOptionVideoPlayback": "Pemutaran video dimulai",
+ "NotificationOptionAudioPlaybackStopped": "Pemutaran audio berhenti",
+ "NotificationOptionAudioPlayback": "Pemutaran audio dimulai",
+ "MixedContent": "Konten campur"
}
diff --git a/Emby.Server.Implementations/Localization/Core/is.json b/Emby.Server.Implementations/Localization/Core/is.json
index c3b5211b8..3490a7302 100644
--- a/Emby.Server.Implementations/Localization/Core/is.json
+++ b/Emby.Server.Implementations/Localization/Core/is.json
@@ -3,7 +3,7 @@
"ItemRemovedWithName": "{0} var fjarlægt úr safninu",
"ItemAddedWithName": "{0} var bætt í safnið",
"Inherit": "Erfa",
- "HomeVideos": "Myndbönd að heiman",
+ "HomeVideos": "Heimamyndbönd",
"HeaderRecordingGroups": "Upptökuhópar",
"HeaderNextUp": "Næst á dagskrá",
"HeaderLiveTV": "Sjónvarp í beinni útsendingu",
@@ -36,10 +36,10 @@
"NotificationOptionVideoPlaybackStopped": "Myndbandafspilun stöðvuð",
"NotificationOptionVideoPlayback": "Myndbandafspilun hafin",
"NotificationOptionUserLockedOut": "Notandi læstur úti",
- "NotificationOptionServerRestartRequired": "Endurræsing miðlara nauðsynileg",
+ "NotificationOptionServerRestartRequired": "Endurræsing þjóns er nauðsynileg",
"NotificationOptionPluginUpdateInstalled": "Viðbótar uppfærsla uppsett",
"NotificationOptionPluginUninstalled": "Viðbót fjarlægð",
- "NotificationOptionPluginInstalled": "Viðbót settur upp",
+ "NotificationOptionPluginInstalled": "Viðbót sett upp",
"NotificationOptionPluginError": "Bilun í viðbót",
"NotificationOptionInstallationFailed": "Uppsetning tókst ekki",
"NotificationOptionCameraImageUploaded": "Myndavélarmynd hlaðið upp",
@@ -50,15 +50,15 @@
"NameSeasonUnknown": "Sería óþekkt",
"NameSeasonNumber": "Sería {0}",
"MixedContent": "Blandað efni",
- "MessageServerConfigurationUpdated": "Stillingar miðlarans hefur verið uppfærð",
- "MessageApplicationUpdatedTo": "Jellyfin Server hefur verið uppfærður í {0}",
- "MessageApplicationUpdated": "Jellyfin Server hefur verið uppfærður",
+ "MessageServerConfigurationUpdated": "Stillingar þjóns hafa verið uppfærðar",
+ "MessageApplicationUpdatedTo": "Jellyfin þjónn hefur verið uppfærður í {0}",
+ "MessageApplicationUpdated": "Jellyfin þjónn hefur verið uppfærður",
"Latest": "Nýjasta",
- "LabelRunningTimeValue": "Keyrslutími kerfis: {0}",
+ "LabelRunningTimeValue": "spilunartími: {0}",
"User": "Notandi",
"System": "Kerfi",
"NotificationOptionNewLibraryContent": "Nýju efni bætt við",
- "NewVersionIsAvailable": "Ný útgáfa af Jellyfin Server er fáanleg til niðurhals.",
+ "NewVersionIsAvailable": "Ný útgáfa af Jellyfin þjón er fáanleg til niðurhals.",
"NameInstallFailed": "{0} uppsetning mistókst",
"MusicVideos": "Tónlistarmyndbönd",
"Music": "Tónlist",
@@ -74,5 +74,23 @@
"PluginUpdatedWithName": "{0} var uppfært",
"PluginUninstalledWithName": "{0} var fjarlægt",
"PluginInstalledWithName": "{0} var sett upp",
- "NotificationOptionTaskFailed": "Tímasett verkefni mistókst"
+ "NotificationOptionTaskFailed": "Tímasett verkefni mistókst",
+ "StartupEmbyServerIsLoading": "Jellyfin netþjónnin er að hlaðast. Vinsamlega prufaðu aftur fljótlega.",
+ "VersionNumber": "Útgáfa {0}",
+ "ValueHasBeenAddedToLibrary": "{0} hefur verið bætt við í gagnasafnið þitt",
+ "UserStoppedPlayingItemWithValues": "{0} hefur lokið spilunar af {1} á {2}",
+ "UserStartedPlayingItemWithValues": "{0} er að spila {1} á {2}",
+ "UserPolicyUpdatedWithName": "Notandaregla hefur verið uppfærð fyrir notanda {0}",
+ "UserPasswordChangedWithName": "Lykilorði fyrir notandann {0} hefur verið breytt",
+ "UserOnlineFromDevice": "{0} hefur verið virkur síðan {1}",
+ "UserOfflineFromDevice": "{0} hefur aftengst frá {1}",
+ "UserLockedOutWithName": "Notanda {0} hefur verið hindraður aðgangur",
+ "UserDownloadingItemWithValues": "{0} Hleður niður {1}",
+ "SubtitlesDownloadedForItem": "Skjátextum halað niður fyrir {0}",
+ "SubtitleDownloadFailureFromForItem": "Tókst ekki að hala niður skjátextum frá {0} til {1}",
+ "ProviderValue": "Veitandi: {0}",
+ "MessageNamedServerConfigurationUpdatedWithValue": "Stilling {0} hefur verið uppfærð á netþjón",
+ "ValueSpecialEpisodeName": "Sérstakt - {0}",
+ "Shows": "Þættir",
+ "Playlists": "Spilunarlisti"
}
diff --git a/Emby.Server.Implementations/Localization/Core/nn.json b/Emby.Server.Implementations/Localization/Core/nn.json
new file mode 100644
index 000000000..0967ef424
--- /dev/null
+++ b/Emby.Server.Implementations/Localization/Core/nn.json
@@ -0,0 +1 @@
+{}
diff --git a/Emby.Server.Implementations/Localization/Core/zh-CN.json b/Emby.Server.Implementations/Localization/Core/zh-CN.json
index e0daac8a5..dd6168614 100644
--- a/Emby.Server.Implementations/Localization/Core/zh-CN.json
+++ b/Emby.Server.Implementations/Localization/Core/zh-CN.json
@@ -89,8 +89,8 @@
"UserOnlineFromDevice": "{0} 在线,来自 {1}",
"UserPasswordChangedWithName": "已为用户 {0} 更改密码",
"UserPolicyUpdatedWithName": "用户协议已经被更新为 {0}",
- "UserStartedPlayingItemWithValues": "{0} 已开始播放 {1}",
- "UserStoppedPlayingItemWithValues": "{0} 已停止播放 {1}",
+ "UserStartedPlayingItemWithValues": "{0} 已在 {2} 上开始播放 {1}",
+ "UserStoppedPlayingItemWithValues": "{0} 已在 {2} 上停止播放 {1}",
"ValueHasBeenAddedToLibrary": "{0} 已添加至您的媒体库中",
"ValueSpecialEpisodeName": "特典 - {0}",
"VersionNumber": "版本 {0}"
diff --git a/Emby.Server.Implementations/Localization/Core/zh-HK.json b/Emby.Server.Implementations/Localization/Core/zh-HK.json
index 33fcb2d37..f3d9e5fce 100644
--- a/Emby.Server.Implementations/Localization/Core/zh-HK.json
+++ b/Emby.Server.Implementations/Localization/Core/zh-HK.json
@@ -1,97 +1,97 @@
{
- "Albums": "Albums",
- "AppDeviceValues": "App: {0}, Device: {1}",
- "Application": "Application",
+ "Albums": "專輯",
+ "AppDeviceValues": "軟體: {0}, 設備: {1}",
+ "Application": "應用程式",
"Artists": "藝人",
- "AuthenticationSucceededWithUserName": "{0} successfully authenticated",
- "Books": "Books",
- "CameraImageUploadedFrom": "A new camera image has been uploaded from {0}",
- "Channels": "Channels",
- "ChapterNameValue": "Chapter {0}",
- "Collections": "Collections",
- "DeviceOfflineWithName": "{0} has disconnected",
- "DeviceOnlineWithName": "{0} is connected",
- "FailedLoginAttemptWithUserName": "Failed login attempt from {0}",
- "Favorites": "Favorites",
- "Folders": "Folders",
- "Genres": "Genres",
- "HeaderAlbumArtists": "Album Artists",
- "HeaderCameraUploads": "Camera Uploads",
- "HeaderContinueWatching": "Continue Watching",
- "HeaderFavoriteAlbums": "Favorite Albums",
- "HeaderFavoriteArtists": "Favorite Artists",
- "HeaderFavoriteEpisodes": "Favorite Episodes",
- "HeaderFavoriteShows": "Favorite Shows",
- "HeaderFavoriteSongs": "Favorite Songs",
- "HeaderLiveTV": "Live TV",
- "HeaderNextUp": "Next Up",
- "HeaderRecordingGroups": "Recording Groups",
- "HomeVideos": "Home videos",
- "Inherit": "Inherit",
- "ItemAddedWithName": "{0} was added to the library",
- "ItemRemovedWithName": "{0} was removed from the library",
- "LabelIpAddressValue": "Ip address: {0}",
- "LabelRunningTimeValue": "Running time: {0}",
- "Latest": "Latest",
- "MessageApplicationUpdated": "Jellyfin Server has been updated",
- "MessageApplicationUpdatedTo": "Jellyfin Server has been updated to {0}",
- "MessageNamedServerConfigurationUpdatedWithValue": "Server configuration section {0} has been updated",
- "MessageServerConfigurationUpdated": "Server configuration has been updated",
+ "AuthenticationSucceededWithUserName": "{0} 授權成功",
+ "Books": "圖書",
+ "CameraImageUploadedFrom": "{0} 成功上傳一張新相片",
+ "Channels": "頻道",
+ "ChapterNameValue": "章節 {0}",
+ "Collections": "合輯",
+ "DeviceOfflineWithName": "{0} 已經斷開連結",
+ "DeviceOnlineWithName": "{0} 已經連接",
+ "FailedLoginAttemptWithUserName": "來自 {0} 的失敗登入嘗試",
+ "Favorites": "我的最愛",
+ "Folders": "檔案夾",
+ "Genres": "風格",
+ "HeaderAlbumArtists": "專輯藝術家",
+ "HeaderCameraUploads": "相機上載",
+ "HeaderContinueWatching": "繼續觀看",
+ "HeaderFavoriteAlbums": "最愛專輯",
+ "HeaderFavoriteArtists": "最愛藝術家",
+ "HeaderFavoriteEpisodes": "最愛的劇集",
+ "HeaderFavoriteShows": "最愛的節目",
+ "HeaderFavoriteSongs": "最愛的歌曲",
+ "HeaderLiveTV": "電視直播",
+ "HeaderNextUp": "接下來",
+ "HeaderRecordingGroups": "錄製組",
+ "HomeVideos": "家庭影片",
+ "Inherit": "繼承",
+ "ItemAddedWithName": "{0} 已添加至媒體庫",
+ "ItemRemovedWithName": "{0} 已從媒體庫移除",
+ "LabelIpAddressValue": "IP 地址: {0}",
+ "LabelRunningTimeValue": "運行時間: {0}",
+ "Latest": "最新",
+ "MessageApplicationUpdated": "Jellyfin Server 已更新",
+ "MessageApplicationUpdatedTo": "Jellyfin 伺服器已更新至 {0}",
+ "MessageNamedServerConfigurationUpdatedWithValue": "伺服器設定 {0} 部分已更新",
+ "MessageServerConfigurationUpdated": "伺服器設定已經更新",
"MixedContent": "Mixed content",
- "Movies": "Movies",
- "Music": "Music",
- "MusicVideos": "Music videos",
- "NameInstallFailed": "{0} installation failed",
- "NameSeasonNumber": "Season {0}",
- "NameSeasonUnknown": "Season Unknown",
- "NewVersionIsAvailable": "A new version of Jellyfin Server is available for download.",
- "NotificationOptionApplicationUpdateAvailable": "Application update available",
- "NotificationOptionApplicationUpdateInstalled": "Application update installed",
- "NotificationOptionAudioPlayback": "Audio playback started",
- "NotificationOptionAudioPlaybackStopped": "Audio playback stopped",
- "NotificationOptionCameraImageUploaded": "Camera image uploaded",
- "NotificationOptionInstallationFailed": "Installation failure",
- "NotificationOptionNewLibraryContent": "New content added",
- "NotificationOptionPluginError": "Plugin failure",
- "NotificationOptionPluginInstalled": "Plugin installed",
- "NotificationOptionPluginUninstalled": "Plugin uninstalled",
- "NotificationOptionPluginUpdateInstalled": "Plugin update installed",
- "NotificationOptionServerRestartRequired": "Server restart required",
- "NotificationOptionTaskFailed": "Scheduled task failure",
- "NotificationOptionUserLockedOut": "User locked out",
- "NotificationOptionVideoPlayback": "Video playback started",
- "NotificationOptionVideoPlaybackStopped": "Video playback stopped",
- "Photos": "Photos",
- "Playlists": "Playlists",
+ "Movies": "電影",
+ "Music": "音樂",
+ "MusicVideos": "音樂MV",
+ "NameInstallFailed": "{0} 安裝失敗",
+ "NameSeasonNumber": "第 {0} 季",
+ "NameSeasonUnknown": "未知季數",
+ "NewVersionIsAvailable": "新版本的 Jellyfin 伺服器可供下載。",
+ "NotificationOptionApplicationUpdateAvailable": "有可用的應用程式更新",
+ "NotificationOptionApplicationUpdateInstalled": "應用程式已更新",
+ "NotificationOptionAudioPlayback": "開始播放音頻",
+ "NotificationOptionAudioPlaybackStopped": "已停止播放音頻",
+ "NotificationOptionCameraImageUploaded": "相機相片已上傳",
+ "NotificationOptionInstallationFailed": "安裝失敗",
+ "NotificationOptionNewLibraryContent": "已添加新内容",
+ "NotificationOptionPluginError": "擴充元件錯誤",
+ "NotificationOptionPluginInstalled": "擴充元件已安裝",
+ "NotificationOptionPluginUninstalled": "擴充元件已移除",
+ "NotificationOptionPluginUpdateInstalled": "擴充元件更新已安裝",
+ "NotificationOptionServerRestartRequired": "伺服器需要重啓",
+ "NotificationOptionTaskFailed": "計劃任務失敗",
+ "NotificationOptionUserLockedOut": "用家已鎖定",
+ "NotificationOptionVideoPlayback": "開始播放視頻",
+ "NotificationOptionVideoPlaybackStopped": "已停止播放視頻",
+ "Photos": "相片",
+ "Playlists": "播放清單",
"Plugin": "Plugin",
- "PluginInstalledWithName": "{0} was installed",
- "PluginUninstalledWithName": "{0} was uninstalled",
- "PluginUpdatedWithName": "{0} was updated",
+ "PluginInstalledWithName": "已安裝 {0}",
+ "PluginUninstalledWithName": "已移除 {0}",
+ "PluginUpdatedWithName": "已更新 {0}",
"ProviderValue": "Provider: {0}",
- "ScheduledTaskFailedWithName": "{0} failed",
- "ScheduledTaskStartedWithName": "{0} started",
- "ServerNameNeedsToBeRestarted": "{0} needs to be restarted",
- "Shows": "Shows",
- "Songs": "Songs",
- "StartupEmbyServerIsLoading": "Jellyfin Server is loading. Please try again shortly.",
+ "ScheduledTaskFailedWithName": "{0} 任務失敗",
+ "ScheduledTaskStartedWithName": "{0} 任務開始",
+ "ServerNameNeedsToBeRestarted": "{0} 需要重啓",
+ "Shows": "節目",
+ "Songs": "歌曲",
+ "StartupEmbyServerIsLoading": "Jellyfin 伺服器載入中,請稍後再試。",
"SubtitleDownloadFailureForItem": "Subtitles failed to download for {0}",
- "SubtitleDownloadFailureFromForItem": "Subtitles failed to download from {0} for {1}",
- "SubtitlesDownloadedForItem": "Subtitles downloaded for {0}",
- "Sync": "Sync",
+ "SubtitleDownloadFailureFromForItem": "無法從 {0} 下載 {1} 的字幕",
+ "SubtitlesDownloadedForItem": "已為 {0} 下載了字幕",
+ "Sync": "同步",
"System": "System",
- "TvShows": "TV Shows",
+ "TvShows": "電視節目",
"User": "User",
- "UserCreatedWithName": "User {0} has been created",
- "UserDeletedWithName": "User {0} has been deleted",
- "UserDownloadingItemWithValues": "{0} is downloading {1}",
- "UserLockedOutWithName": "User {0} has been locked out",
- "UserOfflineFromDevice": "{0} has disconnected from {1}",
- "UserOnlineFromDevice": "{0} is online from {1}",
- "UserPasswordChangedWithName": "Password has been changed for user {0}",
- "UserPolicyUpdatedWithName": "User policy has been updated for {0}",
- "UserStartedPlayingItemWithValues": "{0} is playing {1} on {2}",
- "UserStoppedPlayingItemWithValues": "{0} has finished playing {1} on {2}",
- "ValueHasBeenAddedToLibrary": "{0} has been added to your media library",
- "ValueSpecialEpisodeName": "Special - {0}",
+ "UserCreatedWithName": "用家 {0} 已創建",
+ "UserDeletedWithName": "用家 {0} 已移除",
+ "UserDownloadingItemWithValues": "{0} 正在下載 {1}",
+ "UserLockedOutWithName": "用家 {0} 已被鎖定",
+ "UserOfflineFromDevice": "{0} 已從 {1} 斷開",
+ "UserOnlineFromDevice": "{0} 已連綫,來自 {1}",
+ "UserPasswordChangedWithName": "用家 {0} 的密碼已變更",
+ "UserPolicyUpdatedWithName": "用戶協議已被更新為 {0}",
+ "UserStartedPlayingItemWithValues": "{0} 正在 {2} 上播放 {1}",
+ "UserStoppedPlayingItemWithValues": "{0} 已在 {2} 上停止播放 {1}",
+ "ValueHasBeenAddedToLibrary": "{0} 已添加到你的媒體庫",
+ "ValueSpecialEpisodeName": "特典 - {0}",
"VersionNumber": "版本{0}"
}
diff --git a/Emby.Server.Implementations/Localization/Core/zh-TW.json b/Emby.Server.Implementations/Localization/Core/zh-TW.json
index 33bdbfb98..acd211f22 100644
--- a/Emby.Server.Implementations/Localization/Core/zh-TW.json
+++ b/Emby.Server.Implementations/Localization/Core/zh-TW.json
@@ -50,10 +50,10 @@
"NotificationOptionCameraImageUploaded": "相機相片已上傳",
"NotificationOptionInstallationFailed": "安裝失敗",
"NotificationOptionNewLibraryContent": "已新增新內容",
- "NotificationOptionPluginError": "外掛失敗",
- "NotificationOptionPluginInstalled": "外掛已安裝",
- "NotificationOptionPluginUninstalled": "外掛已移除",
- "NotificationOptionPluginUpdateInstalled": "已更新外掛",
+ "NotificationOptionPluginError": "擴充元件錯誤",
+ "NotificationOptionPluginInstalled": "擴充元件已安裝",
+ "NotificationOptionPluginUninstalled": "擴充元件已移除",
+ "NotificationOptionPluginUpdateInstalled": "已更新擴充元件",
"NotificationOptionServerRestartRequired": "伺服器需要重新啟動",
"NotificationOptionTaskFailed": "排程任務失敗",
"NotificationOptionUserLockedOut": "使用者已鎖定",
diff --git a/Emby.Server.Implementations/Session/SessionManager.cs b/Emby.Server.Implementations/Session/SessionManager.cs
index 0bba19f2a..dfcd3843c 100644
--- a/Emby.Server.Implementations/Session/SessionManager.cs
+++ b/Emby.Server.Implementations/Session/SessionManager.cs
@@ -62,36 +62,14 @@ namespace Emby.Server.Implementations.Session
private readonly ConcurrentDictionary<string, SessionInfo> _activeConnections =
new ConcurrentDictionary<string, SessionInfo>(StringComparer.OrdinalIgnoreCase);
- public event EventHandler<GenericEventArgs<AuthenticationRequest>> AuthenticationFailed;
-
- public event EventHandler<GenericEventArgs<AuthenticationResult>> AuthenticationSucceeded;
-
- /// <summary>
- /// Occurs when [playback start].
- /// </summary>
- public event EventHandler<PlaybackProgressEventArgs> PlaybackStart;
-
- /// <summary>
- /// Occurs when [playback progress].
- /// </summary>
- public event EventHandler<PlaybackProgressEventArgs> PlaybackProgress;
-
- /// <summary>
- /// Occurs when [playback stopped].
- /// </summary>
- public event EventHandler<PlaybackStopEventArgs> PlaybackStopped;
-
- public event EventHandler<SessionEventArgs> SessionStarted;
-
- public event EventHandler<SessionEventArgs> CapabilitiesChanged;
-
- public event EventHandler<SessionEventArgs> SessionEnded;
+ private Timer _idleTimer;
- public event EventHandler<SessionEventArgs> SessionActivity;
+ private DtoOptions _itemInfoDtoOptions;
+ private bool _disposed = false;
public SessionManager(
+ ILogger<SessionManager> logger,
IUserDataManager userDataManager,
- ILoggerFactory loggerFactory,
ILibraryManager libraryManager,
IUserManager userManager,
IMusicManager musicManager,
@@ -102,8 +80,8 @@ namespace Emby.Server.Implementations.Session
IDeviceManager deviceManager,
IMediaSourceManager mediaSourceManager)
{
+ _logger = logger;
_userDataManager = userDataManager;
- _logger = loggerFactory.CreateLogger(nameof(SessionManager));
_libraryManager = libraryManager;
_userManager = userManager;
_musicManager = musicManager;
@@ -113,9 +91,49 @@ namespace Emby.Server.Implementations.Session
_authRepo = authRepo;
_deviceManager = deviceManager;
_mediaSourceManager = mediaSourceManager;
+
_deviceManager.DeviceOptionsUpdated += OnDeviceManagerDeviceOptionsUpdated;
}
+ /// <inheritdoc />
+ public event EventHandler<GenericEventArgs<AuthenticationRequest>> AuthenticationFailed;
+
+ /// <inheritdoc />
+ public event EventHandler<GenericEventArgs<AuthenticationResult>> AuthenticationSucceeded;
+
+ /// <summary>
+ /// Occurs when playback has started.
+ /// </summary>
+ public event EventHandler<PlaybackProgressEventArgs> PlaybackStart;
+
+ /// <summary>
+ /// Occurs when playback has progressed.
+ /// </summary>
+ public event EventHandler<PlaybackProgressEventArgs> PlaybackProgress;
+
+ /// <summary>
+ /// Occurs when playback has stopped.
+ /// </summary>
+ public event EventHandler<PlaybackStopEventArgs> PlaybackStopped;
+
+ /// <inheritdoc />
+ public event EventHandler<SessionEventArgs> SessionStarted;
+
+ /// <inheritdoc />
+ public event EventHandler<SessionEventArgs> CapabilitiesChanged;
+
+ /// <inheritdoc />
+ public event EventHandler<SessionEventArgs> SessionEnded;
+
+ /// <inheritdoc />
+ public event EventHandler<SessionEventArgs> SessionActivity;
+
+ /// <summary>
+ /// Gets all connections.
+ /// </summary>
+ /// <value>All connections.</value>
+ public IEnumerable<SessionInfo> Sessions => _activeConnections.Values.OrderByDescending(c => c.LastActivityDate);
+
private void OnDeviceManagerDeviceOptionsUpdated(object sender, GenericEventArgs<Tuple<string, DeviceOptions>> e)
{
foreach (var session in Sessions)
@@ -135,14 +153,17 @@ namespace Emby.Server.Implementations.Session
}
}
- private bool _disposed = false;
-
+ /// <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)
@@ -152,15 +173,17 @@ namespace Emby.Server.Implementations.Session
if (disposing)
{
- // TODO: dispose stuff
+ _idleTimer?.Dispose();
}
+ _idleTimer = null;
+
_deviceManager.DeviceOptionsUpdated -= OnDeviceManagerDeviceOptionsUpdated;
_disposed = true;
}
- public void CheckDisposed()
+ private void CheckDisposed()
{
if (_disposed)
{
@@ -168,12 +191,6 @@ namespace Emby.Server.Implementations.Session
}
}
- /// <summary>
- /// Gets all connections.
- /// </summary>
- /// <value>All connections.</value>
- public IEnumerable<SessionInfo> Sessions => _activeConnections.Values.OrderByDescending(c => c.LastActivityDate);
-
private void OnSessionStarted(SessionInfo info)
{
if (!string.IsNullOrEmpty(info.DeviceId))
@@ -204,13 +221,13 @@ namespace Emby.Server.Implementations.Session
new SessionEventArgs
{
SessionInfo = info
-
},
_logger);
info.Dispose();
}
+ /// <inheritdoc />
public void UpdateDeviceName(string sessionId, string deviceName)
{
var session = GetSession(sessionId);
@@ -230,7 +247,6 @@ namespace Emby.Server.Implementations.Session
/// <param name="remoteEndPoint">The remote end point.</param>
/// <param name="user">The user.</param>
/// <returns>SessionInfo.</returns>
- /// <exception cref="ArgumentNullException">user</exception>
public SessionInfo LogSessionActivity(
string appName,
string appVersion,
@@ -268,14 +284,7 @@ namespace Emby.Server.Implementations.Session
if ((activityDate - userLastActivityDate).TotalSeconds > 60)
{
- try
- {
- _userManager.UpdateUser(user);
- }
- catch (Exception ex)
- {
- _logger.LogError("Error updating user", ex);
- }
+ _userManager.UpdateUser(user);
}
}
@@ -292,18 +301,20 @@ namespace Emby.Server.Implementations.Session
return session;
}
+ /// <inheritdoc />
public void CloseIfNeeded(SessionInfo session)
{
if (!session.SessionControllers.Any(i => i.IsSessionActive))
{
var key = GetSessionKey(session.Client, session.DeviceId);
- _activeConnections.TryRemove(key, out var removed);
+ _activeConnections.TryRemove(key, out _);
OnSessionEnded(session);
}
}
+ /// <inheritdoc />
public void ReportSessionEnded(string sessionId)
{
CheckDisposed();
@@ -313,7 +324,7 @@ namespace Emby.Server.Implementations.Session
{
var key = GetSessionKey(session.Client, session.DeviceId);
- _activeConnections.TryRemove(key, out var removed);
+ _activeConnections.TryRemove(key, out _);
OnSessionEnded(session);
}
@@ -344,7 +355,7 @@ namespace Emby.Server.Implementations.Session
var runtimeTicks = libraryItem.RunTimeTicks;
MediaSourceInfo mediaSource = null;
- if (libraryItem is IHasMediaSources hasMediaSources)
+ if (libraryItem is IHasMediaSources)
{
mediaSource = await GetMediaSource(libraryItem, info.MediaSourceId, info.LiveStreamId).ConfigureAwait(false);
@@ -396,7 +407,6 @@ namespace Emby.Server.Implementations.Session
/// Removes the now playing item id.
/// </summary>
/// <param name="session">The session.</param>
- /// <exception cref="ArgumentNullException">item</exception>
private void RemoveNowPlayingItem(SessionInfo session)
{
session.NowPlayingItem = null;
@@ -409,9 +419,7 @@ namespace Emby.Server.Implementations.Session
}
private static string GetSessionKey(string appName, string deviceId)
- {
- return appName + deviceId;
- }
+ => appName + deviceId;
/// <summary>
/// Gets the connection.
@@ -431,6 +439,7 @@ namespace Emby.Server.Implementations.Session
{
throw new ArgumentNullException(nameof(deviceId));
}
+
var key = GetSessionKey(appName, deviceId);
CheckDisposed();
@@ -503,7 +512,7 @@ namespace Emby.Server.Implementations.Session
{
var users = new List<User>();
- if (!session.UserId.Equals(Guid.Empty))
+ if (session.UserId != Guid.Empty)
{
var user = _userManager.GetUserById(session.UserId);
@@ -522,8 +531,6 @@ namespace Emby.Server.Implementations.Session
return users;
}
- private Timer _idleTimer;
-
private void StartIdleCheckTimer()
{
if (_idleTimer == null)
@@ -599,11 +606,11 @@ namespace Emby.Server.Implementations.Session
}
/// <summary>
- /// Used to report that playback has started for an item
+ /// Used to report that playback has started for an item.
/// </summary>
/// <param name="info">The info.</param>
/// <returns>Task.</returns>
- /// <exception cref="ArgumentNullException">info</exception>
+ /// <exception cref="ArgumentNullException"><c>info</c> is <c>null</c>.</exception>
public async Task OnPlaybackStart(PlaybackStartInfo info)
{
CheckDisposed();
@@ -615,7 +622,7 @@ namespace Emby.Server.Implementations.Session
var session = GetSession(info.SessionId);
- var libraryItem = info.ItemId.Equals(Guid.Empty)
+ var libraryItem = info.ItemId == Guid.Empty
? null
: GetNowPlayingItem(session, info.ItemId);
@@ -653,7 +660,6 @@ namespace Emby.Server.Implementations.Session
ClientName = session.Client,
DeviceId = session.DeviceId,
Session = session
-
},
_logger);
@@ -684,13 +690,14 @@ namespace Emby.Server.Implementations.Session
_userDataManager.SaveUserData(user, item, data, UserDataSaveReason.PlaybackStart, CancellationToken.None);
}
+ /// <inheritdoc />
public Task OnPlaybackProgress(PlaybackProgressInfo info)
{
return OnPlaybackProgress(info, false);
}
/// <summary>
- /// Used to report playback progress for an item
+ /// Used to report playback progress for an item.
/// </summary>
/// <returns>Task.</returns>
public async Task OnPlaybackProgress(PlaybackProgressInfo info, bool isAutomated)
@@ -857,7 +864,7 @@ namespace Emby.Server.Implementations.Session
{
MediaSourceInfo mediaSource = null;
- if (libraryItem is IHasMediaSources hasMediaSources)
+ if (libraryItem is IHasMediaSources)
{
mediaSource = await GetMediaSource(libraryItem, info.MediaSourceId, info.LiveStreamId).ConfigureAwait(false);
}
@@ -966,13 +973,17 @@ namespace Emby.Server.Implementations.Session
/// <param name="sessionId">The session identifier.</param>
/// <param name="throwOnMissing">if set to <c>true</c> [throw on missing].</param>
/// <returns>SessionInfo.</returns>
- /// <exception cref="ResourceNotFoundException">sessionId</exception>
+ /// <exception cref="ResourceNotFoundException">
+ /// No session with an Id equal to <c>sessionId</c> was found
+ /// and <c>throwOnMissing</c> is <c>true</c>.
+ /// </exception>
private SessionInfo GetSession(string sessionId, bool throwOnMissing = true)
{
var session = Sessions.FirstOrDefault(i => string.Equals(i.Id, sessionId, StringComparison.Ordinal));
if (session == null && throwOnMissing)
{
- throw new ResourceNotFoundException(string.Format("Session {0} not found.", sessionId));
+ throw new ResourceNotFoundException(
+ string.Format(CultureInfo.InvariantCulture, "Session {0} not found.", sessionId));
}
return session;
@@ -985,12 +996,14 @@ namespace Emby.Server.Implementations.Session
if (session == null)
{
- throw new ResourceNotFoundException(string.Format("Session {0} not found.", sessionId));
+ throw new ResourceNotFoundException(
+ string.Format(CultureInfo.InvariantCulture, "Session {0} not found.", sessionId));
}
return session;
}
+ /// <inheritdoc />
public Task SendMessageCommand(string controllingSessionId, string sessionId, MessageCommand command, CancellationToken cancellationToken)
{
CheckDisposed();
@@ -1011,6 +1024,7 @@ namespace Emby.Server.Implementations.Session
return SendGeneralCommand(controllingSessionId, sessionId, generalCommand, cancellationToken);
}
+ /// <inheritdoc />
public Task SendGeneralCommand(string controllingSessionId, string sessionId, GeneralCommand command, CancellationToken cancellationToken)
{
CheckDisposed();
@@ -1055,6 +1069,7 @@ namespace Emby.Server.Implementations.Session
return Task.WhenAll(GetTasks());
}
+ /// <inheritdoc />
public async Task SendPlayCommand(string controllingSessionId, string sessionId, PlayRequest command, CancellationToken cancellationToken)
{
CheckDisposed();
@@ -1096,7 +1111,8 @@ namespace Emby.Server.Implementations.Session
{
if (items.Any(i => i.GetPlayAccess(user) != PlayAccess.Full))
{
- throw new ArgumentException(string.Format("{0} is not allowed to play media.", user.Name));
+ throw new ArgumentException(
+ string.Format(CultureInfo.InvariantCulture, "{0} is not allowed to play media.", user.Name));
}
}
@@ -1204,6 +1220,7 @@ namespace Emby.Server.Implementations.Session
return _musicManager.GetInstantMixFromItem(item, user, new DtoOptions(false) { EnableImages = false });
}
+ /// <inheritdoc />
public Task SendBrowseCommand(string controllingSessionId, string sessionId, BrowseRequest command, CancellationToken cancellationToken)
{
var generalCommand = new GeneralCommand
@@ -1220,6 +1237,7 @@ namespace Emby.Server.Implementations.Session
return SendGeneralCommand(controllingSessionId, sessionId, generalCommand, cancellationToken);
}
+ /// <inheritdoc />
public Task SendPlaystateCommand(string controllingSessionId, string sessionId, PlaystateRequest command, CancellationToken cancellationToken)
{
CheckDisposed();
@@ -1303,12 +1321,12 @@ namespace Emby.Server.Implementations.Session
var session = GetSession(sessionId);
- if (session.UserId.Equals(userId))
+ if (session.UserId == userId)
{
throw new ArgumentException("The requested user is already the primary user of the session.");
}
- if (session.AdditionalUsers.All(i => !i.UserId.Equals(userId)))
+ if (session.AdditionalUsers.All(i => i.UserId != userId))
{
var user = _userManager.GetUserById(userId);
@@ -1383,20 +1401,16 @@ namespace Emby.Server.Implementations.Session
user = _userManager.GetUserByName(request.Username);
}
- if (user != null)
+ if (user == null)
{
- // TODO: Move this to userManager?
- if (!string.IsNullOrEmpty(request.DeviceId)
- && !_deviceManager.CanAccessDevice(user, request.DeviceId))
- {
- throw new SecurityException("User is not allowed access from this device.");
- }
+ AuthenticationFailed?.Invoke(this, new GenericEventArgs<AuthenticationRequest>(request));
+ throw new SecurityException("Invalid username or password entered.");
}
- if (user == null)
+ if (!string.IsNullOrEmpty(request.DeviceId)
+ && !_deviceManager.CanAccessDevice(user, request.DeviceId))
{
- AuthenticationFailed?.Invoke(this, new GenericEventArgs<AuthenticationRequest>(request));
- throw new SecurityException("Invalid user or password entered.");
+ throw new SecurityException("User is not allowed access from this device.");
}
if (enforcePassword)
@@ -1434,19 +1448,19 @@ namespace Emby.Server.Implementations.Session
private string GetAuthorizationToken(User user, string deviceId, string app, string appVersion, string deviceName)
{
- var existing = _authRepo.Get(new AuthenticationInfoQuery
- {
- DeviceId = deviceId,
- UserId = user.Id,
- Limit = 1
-
- }).Items.FirstOrDefault();
-
- var allExistingForDevice = _authRepo.Get(new AuthenticationInfoQuery
- {
- DeviceId = deviceId
+ var existing = _authRepo.Get(
+ new AuthenticationInfoQuery
+ {
+ DeviceId = deviceId,
+ UserId = user.Id,
+ Limit = 1
+ }).Items.FirstOrDefault();
- }).Items;
+ var allExistingForDevice = _authRepo.Get(
+ new AuthenticationInfoQuery
+ {
+ DeviceId = deviceId
+ }).Items;
foreach (var auth in allExistingForDevice)
{
@@ -1465,7 +1479,7 @@ namespace Emby.Server.Implementations.Session
if (existing != null)
{
- _logger.LogInformation("Reissuing access token: " + existing.AccessToken);
+ _logger.LogInformation("Reissuing access token: {Token}", existing.AccessToken);
return existing.AccessToken;
}
@@ -1490,6 +1504,7 @@ namespace Emby.Server.Implementations.Session
return newToken.AccessToken;
}
+ /// <inheritdoc />
public void Logout(string accessToken)
{
CheckDisposed();
@@ -1499,19 +1514,20 @@ namespace Emby.Server.Implementations.Session
throw new ArgumentNullException(nameof(accessToken));
}
- var existing = _authRepo.Get(new AuthenticationInfoQuery
- {
- Limit = 1,
- AccessToken = accessToken
-
- }).Items.FirstOrDefault();
+ var existing = _authRepo.Get(
+ new AuthenticationInfoQuery
+ {
+ Limit = 1,
+ AccessToken = accessToken
+ }).Items;
- if (existing != null)
+ if (existing.Count > 0)
{
- Logout(existing);
+ Logout(existing[0]);
}
}
+ /// <inheritdoc />
public void Logout(AuthenticationInfo existing)
{
CheckDisposed();
@@ -1537,6 +1553,7 @@ namespace Emby.Server.Implementations.Session
}
}
+ /// <inheritdoc />
public void RevokeUserTokens(Guid userId, string currentAccessToken)
{
CheckDisposed();
@@ -1555,6 +1572,7 @@ namespace Emby.Server.Implementations.Session
}
}
+ /// <inheritdoc />
public void RevokeToken(string token)
{
Logout(token);
@@ -1611,8 +1629,6 @@ namespace Emby.Server.Implementations.Session
_deviceManager.SaveCapabilities(deviceId, capabilities);
}
- private DtoOptions _itemInfoDtoOptions;
-
/// <summary>
/// Converts a BaseItem to a BaseItemInfo.
/// </summary>
@@ -1689,6 +1705,7 @@ namespace Emby.Server.Implementations.Session
}
}
+ /// <inheritdoc />
public void ReportNowViewingItem(string sessionId, string itemId)
{
if (string.IsNullOrEmpty(itemId))
@@ -1696,23 +1713,26 @@ namespace Emby.Server.Implementations.Session
throw new ArgumentNullException(nameof(itemId));
}
- //var item = _libraryManager.GetItemById(new Guid(itemId));
+ var item = _libraryManager.GetItemById(new Guid(itemId));
- //var info = GetItemInfo(item, null, null);
+ var info = GetItemInfo(item, null);
- //ReportNowViewingItem(sessionId, info);
+ ReportNowViewingItem(sessionId, info);
}
+ /// <inheritdoc />
public void ReportNowViewingItem(string sessionId, BaseItemDto item)
{
- //var session = GetSession(sessionId);
+ var session = GetSession(sessionId);
- //session.NowViewingItem = item;
+ session.NowViewingItem = item;
}
+ /// <inheritdoc />
public void ReportTranscodingInfo(string deviceId, TranscodingInfo info)
{
- var session = Sessions.FirstOrDefault(i => string.Equals(i.DeviceId, deviceId));
+ var session = Sessions.FirstOrDefault(i =>
+ string.Equals(i.DeviceId, deviceId, StringComparison.OrdinalIgnoreCase));
if (session != null)
{
@@ -1720,17 +1740,21 @@ namespace Emby.Server.Implementations.Session
}
}
+ /// <inheritdoc />
public void ClearTranscodingInfo(string deviceId)
{
ReportTranscodingInfo(deviceId, null);
}
+ /// <inheritdoc />
public SessionInfo GetSession(string deviceId, string client, string version)
{
- return Sessions.FirstOrDefault(i => string.Equals(i.DeviceId, deviceId) &&
- string.Equals(i.Client, client));
+ return Sessions.FirstOrDefault(i =>
+ string.Equals(i.DeviceId, deviceId, StringComparison.OrdinalIgnoreCase)
+ && string.Equals(i.Client, client, StringComparison.OrdinalIgnoreCase));
}
+ /// <inheritdoc />
public SessionInfo GetSessionByAuthenticationToken(AuthenticationInfo info, string deviceId, string remoteEndpoint, string appVersion)
{
if (info == null)
@@ -1763,23 +1787,24 @@ namespace Emby.Server.Implementations.Session
return LogSessionActivity(appName, appVersion, deviceId, deviceName, remoteEndpoint, user);
}
+ /// <inheritdoc />
public SessionInfo GetSessionByAuthenticationToken(string token, string deviceId, string remoteEndpoint)
{
- var result = _authRepo.Get(new AuthenticationInfoQuery
+ var items = _authRepo.Get(new AuthenticationInfoQuery
{
- AccessToken = token
- });
-
- var info = result.Items.FirstOrDefault();
+ AccessToken = token,
+ Limit = 1
+ }).Items;
- if (info == null)
+ if (items.Count == 0)
{
return null;
}
- return GetSessionByAuthenticationToken(info, deviceId, remoteEndpoint, null);
+ return GetSessionByAuthenticationToken(items[0], deviceId, remoteEndpoint, null);
}
+ /// <inheritdoc />
public Task SendMessageToAdminSessions<T>(string name, T data, CancellationToken cancellationToken)
{
CheckDisposed();
@@ -1789,6 +1814,7 @@ namespace Emby.Server.Implementations.Session
return SendMessageToUserSessions(adminUserIds, name, data, cancellationToken);
}
+ /// <inheritdoc />
public Task SendMessageToUserSessions<T>(List<Guid> userIds, string name, Func<T> dataFn, CancellationToken cancellationToken)
{
CheckDisposed();
@@ -1800,11 +1826,10 @@ namespace Emby.Server.Implementations.Session
return Task.CompletedTask;
}
- var data = dataFn();
-
- return SendMessageToSessions(sessions, name, data, cancellationToken);
+ return SendMessageToSessions(sessions, name, dataFn(), cancellationToken);
}
+ /// <inheritdoc />
public Task SendMessageToUserSessions<T>(List<Guid> userIds, string name, T data, CancellationToken cancellationToken)
{
CheckDisposed();
@@ -1813,6 +1838,7 @@ namespace Emby.Server.Implementations.Session
return SendMessageToSessions(sessions, name, data, cancellationToken);
}
+ /// <inheritdoc />
public Task SendMessageToUserDeviceSessions<T>(string deviceId, string name, T data, CancellationToken cancellationToken)
{
CheckDisposed();
@@ -1821,22 +1847,5 @@ namespace Emby.Server.Implementations.Session
return SendMessageToSessions(sessions, name, data, cancellationToken);
}
-
- public Task SendMessageToUserDeviceAndAdminSessions<T>(string deviceId, string name, T data, CancellationToken cancellationToken)
- {
- CheckDisposed();
-
- var sessions = Sessions
- .Where(i => string.Equals(i.DeviceId, deviceId, StringComparison.OrdinalIgnoreCase) || IsAdminSession(i));
-
- return SendMessageToSessions(sessions, name, data, cancellationToken);
- }
-
- private bool IsAdminSession(SessionInfo s)
- {
- var user = _userManager.GetUserById(s.UserId);
-
- return user != null && user.Policy.IsAdministrator;
- }
}
}
diff --git a/Jellyfin.Drawing.Skia/SkiaEncoder.cs b/Jellyfin.Drawing.Skia/SkiaEncoder.cs
index b080b3e6a..2ea690650 100644
--- a/Jellyfin.Drawing.Skia/SkiaEncoder.cs
+++ b/Jellyfin.Drawing.Skia/SkiaEncoder.cs
@@ -6,7 +6,6 @@ using MediaBrowser.Common.Configuration;
using MediaBrowser.Controller.Drawing;
using MediaBrowser.Controller.Extensions;
using MediaBrowser.Model.Drawing;
-using MediaBrowser.Model.Globalization;
using Microsoft.Extensions.Logging;
using SkiaSharp;
using static Jellyfin.Drawing.Skia.SkiaHelper;
@@ -18,27 +17,23 @@ namespace Jellyfin.Drawing.Skia
/// </summary>
public class SkiaEncoder : IImageEncoder
{
- private readonly ILogger _logger;
- private readonly IApplicationPaths _appPaths;
- private readonly ILocalizationManager _localizationManager;
-
private static readonly HashSet<string> _transparentImageTypes
= new HashSet<string>(StringComparer.OrdinalIgnoreCase) { ".png", ".gif", ".webp" };
+ private readonly ILogger _logger;
+ private readonly IApplicationPaths _appPaths;
+
/// <summary>
/// Initializes a new instance of the <see cref="SkiaEncoder"/> class.
/// </summary>
/// <param name="logger">The application logger.</param>
/// <param name="appPaths">The application paths.</param>
- /// <param name="localizationManager">The application localization manager.</param>
public SkiaEncoder(
ILogger<SkiaEncoder> logger,
- IApplicationPaths appPaths,
- ILocalizationManager localizationManager)
+ IApplicationPaths appPaths)
{
_logger = logger;
_appPaths = appPaths;
- _localizationManager = localizationManager;
}
/// <inheritdoc/>
@@ -235,9 +230,12 @@ namespace Jellyfin.Drawing.Skia
private bool RequiresSpecialCharacterHack(string path)
{
- if (_localizationManager.HasUnicodeCategory(path, UnicodeCategory.OtherLetter))
+ for (int i = 0; i < path.Length; i++)
{
- return true;
+ if (char.GetUnicodeCategory(path[i]) == UnicodeCategory.OtherLetter)
+ {
+ return true;
+ }
}
if (HasDiacritics(path))
diff --git a/Jellyfin.Server/Program.cs b/Jellyfin.Server/Program.cs
index 1b4280d82..1dd598236 100644
--- a/Jellyfin.Server/Program.cs
+++ b/Jellyfin.Server/Program.cs
@@ -168,7 +168,7 @@ namespace Jellyfin.Server
_loggerFactory,
options,
new ManagedFileSystem(_loggerFactory.CreateLogger<ManagedFileSystem>(), appPaths),
- new NullImageEncoder(),
+ GetImageEncoder(appPaths),
new NetworkManager(_loggerFactory.CreateLogger<NetworkManager>()),
appConfig);
try
@@ -192,8 +192,6 @@ namespace Jellyfin.Server
throw;
}
- appHost.ImageProcessor.ImageEncoder = GetImageEncoder(appPaths, appHost.LocalizationManager);
-
await appHost.RunStartupTasksAsync().ConfigureAwait(false);
stopWatch.Stop();
@@ -491,9 +489,7 @@ namespace Jellyfin.Server
}
}
- private static IImageEncoder GetImageEncoder(
- IApplicationPaths appPaths,
- ILocalizationManager localizationManager)
+ private static IImageEncoder GetImageEncoder(IApplicationPaths appPaths)
{
try
{
@@ -502,8 +498,7 @@ namespace Jellyfin.Server
return new SkiaEncoder(
_loggerFactory.CreateLogger<SkiaEncoder>(),
- appPaths,
- localizationManager);
+ appPaths);
}
catch (Exception ex)
{
diff --git a/MediaBrowser.Api/Images/ImageService.cs b/MediaBrowser.Api/Images/ImageService.cs
index c55618aa1..af455987b 100644
--- a/MediaBrowser.Api/Images/ImageService.cs
+++ b/MediaBrowser.Api/Images/ImageService.cs
@@ -24,7 +24,7 @@ using Microsoft.Net.Http.Headers;
namespace MediaBrowser.Api.Images
{
/// <summary>
- /// Class GetItemImage
+ /// Class GetItemImage.
/// </summary>
[Route("/Items/{Id}/Images", "GET", Summary = "Gets information about an item's images")]
[Authenticated]
@@ -558,21 +558,6 @@ namespace MediaBrowser.Api.Images
throw new ResourceNotFoundException(string.Format("{0} does not have an image of type {1}", displayText, request.Type));
}
- IImageEnhancer[] supportedImageEnhancers;
- if (_imageProcessor.ImageEnhancers.Count > 0)
- {
- if (item == null)
- {
- item = _libraryManager.GetItemById(itemId);
- }
-
- supportedImageEnhancers = request.EnableImageEnhancers ? _imageProcessor.GetSupportedEnhancers(item, request.Type).ToArray() : Array.Empty<IImageEnhancer>();
- }
- else
- {
- supportedImageEnhancers = Array.Empty<IImageEnhancer>();
- }
-
bool cropwhitespace;
if (request.CropWhitespace.HasValue)
{
@@ -598,25 +583,25 @@ namespace MediaBrowser.Api.Images
{"realTimeInfo.dlna.org", "DLNA.ORG_TLAG=*"}
};
- return GetImageResult(item,
+ return GetImageResult(
+ item,
itemId,
request,
imageInfo,
cropwhitespace,
outputFormats,
- supportedImageEnhancers,
cacheDuration,
responseHeaders,
isHeadRequest);
}
- private async Task<object> GetImageResult(BaseItem item,
+ private async Task<object> GetImageResult(
+ BaseItem item,
Guid itemId,
ImageRequest request,
ItemImageInfo image,
bool cropwhitespace,
IReadOnlyCollection<ImageFormat> supportedFormats,
- IReadOnlyCollection<IImageEnhancer> enhancers,
TimeSpan? cacheDuration,
IDictionary<string, string> headers,
bool isHeadRequest)
@@ -624,7 +609,6 @@ namespace MediaBrowser.Api.Images
var options = new ImageProcessingOptions
{
CropWhiteSpace = cropwhitespace,
- Enhancers = enhancers,
Height = request.Height,
ImageIndex = request.Index ?? 0,
Image = image,
diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs
index ab74bab1c..5029ce0bb 100644
--- a/MediaBrowser.Api/Playback/BaseStreamingService.cs
+++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs
@@ -250,11 +250,11 @@ namespace MediaBrowser.Api.Playback
{
if (string.Equals(state.OutputAudioCodec, "copy", StringComparison.OrdinalIgnoreCase))
{
- logFilePrefix = "ffmpeg-directstream";
+ logFilePrefix = "ffmpeg-remux";
}
else
{
- logFilePrefix = "ffmpeg-remux";
+ logFilePrefix = "ffmpeg-directstream";
}
}
@@ -327,15 +327,19 @@ namespace MediaBrowser.Api.Playback
private bool EnableThrottling(StreamState state)
{
+ var encodingOptions = ServerConfigurationManager.GetEncodingOptions();
+
+ // enable throttling when NOT using hardware acceleration
+ if (encodingOptions.HardwareAccelerationType == string.Empty)
+ {
+ return state.InputProtocol == MediaProtocol.File &&
+ state.RunTimeTicks.HasValue &&
+ state.RunTimeTicks.Value >= TimeSpan.FromMinutes(5).Ticks &&
+ state.IsInputVideo &&
+ state.VideoType == VideoType.VideoFile &&
+ !string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase);
+ }
return false;
- //// do not use throttling with hardware encoders
- //return state.InputProtocol == MediaProtocol.File &&
- // state.RunTimeTicks.HasValue &&
- // state.RunTimeTicks.Value >= TimeSpan.FromMinutes(5).Ticks &&
- // state.IsInputVideo &&
- // state.VideoType == VideoType.VideoFile &&
- // !string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase) &&
- // string.Equals(GetVideoEncoder(state), "libx264", StringComparison.OrdinalIgnoreCase);
}
/// <summary>
diff --git a/MediaBrowser.Api/Sessions/ApiKeyService.cs b/MediaBrowser.Api/Sessions/ApiKeyService.cs
new file mode 100644
index 000000000..5102ce0a7
--- /dev/null
+++ b/MediaBrowser.Api/Sessions/ApiKeyService.cs
@@ -0,0 +1,85 @@
+using System;
+using System.Globalization;
+using MediaBrowser.Controller;
+using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Controller.Net;
+using MediaBrowser.Controller.Security;
+using MediaBrowser.Controller.Session;
+using MediaBrowser.Model.Services;
+using Microsoft.Extensions.Logging;
+
+namespace MediaBrowser.Api.Sessions
+{
+ [Route("/Auth/Keys", "GET")]
+ [Authenticated(Roles = "Admin")]
+ public class GetKeys
+ {
+ }
+
+ [Route("/Auth/Keys/{Key}", "DELETE")]
+ [Authenticated(Roles = "Admin")]
+ public class RevokeKey
+ {
+ [ApiMember(Name = "Key", Description = "Authentication key", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "DELETE")]
+ public string Key { get; set; }
+ }
+
+ [Route("/Auth/Keys", "POST")]
+ [Authenticated(Roles = "Admin")]
+ public class CreateKey
+ {
+ [ApiMember(Name = "App", Description = "Name of the app using the authentication key", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "POST")]
+ public string App { get; set; }
+ }
+
+ public class ApiKeyService : BaseApiService
+ {
+ private readonly ISessionManager _sessionManager;
+
+ private readonly IAuthenticationRepository _authRepo;
+
+ private readonly IServerApplicationHost _appHost;
+
+ public ApiKeyService(
+ ILogger<ApiKeyService> logger,
+ IServerConfigurationManager serverConfigurationManager,
+ IHttpResultFactory httpResultFactory,
+ ISessionManager sessionManager,
+ IServerApplicationHost appHost,
+ IAuthenticationRepository authRepo)
+ : base(logger, serverConfigurationManager, httpResultFactory)
+ {
+ _sessionManager = sessionManager;
+ _authRepo = authRepo;
+ _appHost = appHost;
+ }
+
+ public void Delete(RevokeKey request)
+ {
+ _sessionManager.RevokeToken(request.Key);
+ }
+
+ public void Post(CreateKey request)
+ {
+ _authRepo.Create(new AuthenticationInfo
+ {
+ AppName = request.App,
+ AccessToken = Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture),
+ DateCreated = DateTime.UtcNow,
+ DeviceId = _appHost.SystemId,
+ DeviceName = _appHost.FriendlyName,
+ AppVersion = _appHost.ApplicationVersionString
+ });
+ }
+
+ public object Get(GetKeys request)
+ {
+ var result = _authRepo.Get(new AuthenticationInfoQuery
+ {
+ HasUser = false
+ });
+
+ return result;
+ }
+ }
+}
diff --git a/MediaBrowser.Api/Session/SessionInfoWebSocketListener.cs b/MediaBrowser.Api/Sessions/SessionInfoWebSocketListener.cs
index f1a6622fb..051d09850 100644
--- a/MediaBrowser.Api/Session/SessionInfoWebSocketListener.cs
+++ b/MediaBrowser.Api/Sessions/SessionInfoWebSocketListener.cs
@@ -5,7 +5,7 @@ using MediaBrowser.Controller.Net;
using MediaBrowser.Controller.Session;
using Microsoft.Extensions.Logging;
-namespace MediaBrowser.Api.Session
+namespace MediaBrowser.Api.Sessions
{
/// <summary>
/// Class SessionInfoWebSocketListener
diff --git a/MediaBrowser.Api/Session/SessionsService.cs b/MediaBrowser.Api/Sessions/SessionService.cs
index 9aa7b2c88..020bb5042 100644
--- a/MediaBrowser.Api/Session/SessionsService.cs
+++ b/MediaBrowser.Api/Sessions/SessionService.cs
@@ -1,21 +1,18 @@
using System;
-using System.Globalization;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
-using MediaBrowser.Controller;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Devices;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Net;
-using MediaBrowser.Controller.Security;
using MediaBrowser.Controller.Session;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Services;
using MediaBrowser.Model.Session;
using Microsoft.Extensions.Logging;
-namespace MediaBrowser.Api.Session
+namespace MediaBrowser.Api.Sessions
{
/// <summary>
/// Class GetSessions.
@@ -24,10 +21,10 @@ namespace MediaBrowser.Api.Session
[Authenticated]
public class GetSessions : IReturn<SessionInfo[]>
{
- [ApiMember(Name = "ControllableByUserId", Description = "Optional. Filter by sessions that a given user is allowed to remote control.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
+ [ApiMember(Name = "ControllableByUserId", Description = "Filter by sessions that a given user is allowed to remote control.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
public Guid ControllableByUserId { get; set; }
- [ApiMember(Name = "DeviceId", Description = "Optional. Filter by device id.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
+ [ApiMember(Name = "DeviceId", Description = "Filter by device Id.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
public string DeviceId { get; set; }
public int? ActiveWithinSeconds { get; set; }
@@ -182,7 +179,7 @@ namespace MediaBrowser.Api.Session
[ApiMember(Name = "Id", Description = "Session Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
public string Id { get; set; }
- [ApiMember(Name = "UserId", Description = "UserId Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
+ [ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
public string UserId { get; set; }
}
@@ -230,15 +227,20 @@ namespace MediaBrowser.Api.Session
public string Id { get; set; }
}
- [Route("/Sessions/Logout", "POST", Summary = "Reports that a session has ended")]
+ [Route("/Sessions/Viewing", "POST", Summary = "Reports that a session is viewing an item")]
[Authenticated]
- public class ReportSessionEnded : IReturnVoid
+ public class ReportViewing : IReturnVoid
{
+ [ApiMember(Name = "SessionId", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")]
+ public string SessionId { get; set; }
+
+ [ApiMember(Name = "ItemId", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "POST")]
+ public string ItemId { get; set; }
}
- [Route("/Auth/Keys", "GET")]
- [Authenticated(Roles = "Admin")]
- public class GetApiKeys
+ [Route("/Sessions/Logout", "POST", Summary = "Reports that a session has ended")]
+ [Authenticated]
+ public class ReportSessionEnded : IReturnVoid
{
}
@@ -254,48 +256,28 @@ namespace MediaBrowser.Api.Session
{
}
- [Route("/Auth/Keys/{Key}", "DELETE")]
- [Authenticated(Roles = "Admin")]
- public class RevokeKey
- {
- [ApiMember(Name = "Key", Description = "Auth Key", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "DELETE")]
- public string Key { get; set; }
- }
-
- [Route("/Auth/Keys", "POST")]
- [Authenticated(Roles = "Admin")]
- public class CreateKey
- {
- [ApiMember(Name = "App", Description = "App", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "POST")]
- public string App { get; set; }
- }
-
/// <summary>
/// Class SessionsService.
/// </summary>
- public class SessionsService : BaseApiService
+ public class SessionService : BaseApiService
{
/// <summary>
- /// The _session manager.
+ /// The session manager.
/// </summary>
private readonly ISessionManager _sessionManager;
private readonly IUserManager _userManager;
private readonly IAuthorizationContext _authContext;
- private readonly IAuthenticationRepository _authRepo;
private readonly IDeviceManager _deviceManager;
private readonly ISessionContext _sessionContext;
- private readonly IServerApplicationHost _appHost;
- public SessionsService(
- ILogger<SessionsService> logger,
+ public SessionService(
+ ILogger<SessionService> logger,
IServerConfigurationManager serverConfigurationManager,
IHttpResultFactory httpResultFactory,
ISessionManager sessionManager,
- IServerApplicationHost appHost,
IUserManager userManager,
IAuthorizationContext authContext,
- IAuthenticationRepository authRepo,
IDeviceManager deviceManager,
ISessionContext sessionContext)
: base(logger, serverConfigurationManager, httpResultFactory)
@@ -303,10 +285,8 @@ namespace MediaBrowser.Api.Session
_sessionManager = sessionManager;
_userManager = userManager;
_authContext = authContext;
- _authRepo = authRepo;
_deviceManager = deviceManager;
_sessionContext = sessionContext;
- _appHost = appHost;
}
public object Get(GetAuthProviders request)
@@ -319,25 +299,6 @@ namespace MediaBrowser.Api.Session
return _userManager.GetPasswordResetProviders();
}
- public void Delete(RevokeKey request)
- {
- _sessionManager.RevokeToken(request.Key);
-
- }
-
- public void Post(CreateKey request)
- {
- _authRepo.Create(new AuthenticationInfo
- {
- AppName = request.App,
- AccessToken = Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture),
- DateCreated = DateTime.UtcNow,
- DeviceId = _appHost.SystemId,
- DeviceName = _appHost.FriendlyName,
- AppVersion = _appHost.ApplicationVersionString
- });
- }
-
public void Post(ReportSessionEnded request)
{
var auth = _authContext.GetAuthorizationInfo(Request);
@@ -345,16 +306,6 @@ namespace MediaBrowser.Api.Session
_sessionManager.Logout(auth.Token);
}
- public object Get(GetApiKeys request)
- {
- var result = _authRepo.Get(new AuthenticationInfoQuery
- {
- HasUser = false
- });
-
- return result;
- }
-
/// <summary>
/// Gets the specified request.
/// </summary>
@@ -438,14 +389,12 @@ namespace MediaBrowser.Api.Session
public Task Post(SendSystemCommand request)
{
var name = request.Command;
-
if (Enum.TryParse(name, true, out GeneralCommandType commandType))
{
name = commandType.ToString();
}
var currentSession = GetSession(_sessionContext);
-
var command = new GeneralCommand
{
Name = name,
@@ -518,16 +467,13 @@ namespace MediaBrowser.Api.Session
{
request.Id = GetSession(_sessionContext).Id;
}
+
_sessionManager.ReportCapabilities(request.Id, new ClientCapabilities
{
PlayableMediaTypes = SplitValue(request.PlayableMediaTypes, ','),
-
SupportedCommands = SplitValue(request.SupportedCommands, ','),
-
SupportsMediaControl = request.SupportsMediaControl,
-
SupportsSync = request.SupportsSync,
-
SupportsPersistentIdentifier = request.SupportsPersistentIdentifier
});
}
@@ -538,7 +484,15 @@ namespace MediaBrowser.Api.Session
{
request.Id = GetSession(_sessionContext).Id;
}
+
_sessionManager.ReportCapabilities(request.Id, request);
}
+
+ public void Post(ReportViewing request)
+ {
+ request.SessionId = GetSession(_sessionContext).Id;
+
+ _sessionManager.ReportNowViewingItem(request.SessionId, request.ItemId);
+ }
}
}
diff --git a/MediaBrowser.Api/UserLibrary/PlaystateService.cs b/MediaBrowser.Api/UserLibrary/PlaystateService.cs
index 9d1cf5d9e..d0faca163 100644
--- a/MediaBrowser.Api/UserLibrary/PlaystateService.cs
+++ b/MediaBrowser.Api/UserLibrary/PlaystateService.cs
@@ -103,10 +103,6 @@ namespace MediaBrowser.Api.UserLibrary
[ApiMember(Name = "MediaSourceId", Description = "The id of the MediaSource", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "POST")]
public string MediaSourceId { get; set; }
- /// <summary>
- /// Gets or sets a value indicating whether this <see cref="UpdateUserItemRating" /> is likes.
- /// </summary>
- /// <value><c>true</c> if likes; otherwise, <c>false</c>.</value>
[ApiMember(Name = "CanSeek", Description = "Indicates if the client can seek", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "POST")]
public bool CanSeek { get; set; }
diff --git a/MediaBrowser.Api/UserService.cs b/MediaBrowser.Api/UserService.cs
index ac140150b..401514349 100644
--- a/MediaBrowser.Api/UserService.cs
+++ b/MediaBrowser.Api/UserService.cs
@@ -240,7 +240,7 @@ namespace MediaBrowser.Api
public class UserService : BaseApiService
{
/// <summary>
- /// The _user manager
+ /// The user manager.
/// </summary>
private readonly IUserManager _userManager;
private readonly ISessionManager _sessionMananger;
diff --git a/MediaBrowser.Common/Configuration/IConfigurationFactory.cs b/MediaBrowser.Common/Configuration/IConfigurationFactory.cs
index 9b4ed772d..07ca2b58b 100644
--- a/MediaBrowser.Common/Configuration/IConfigurationFactory.cs
+++ b/MediaBrowser.Common/Configuration/IConfigurationFactory.cs
@@ -1,25 +1,47 @@
-#pragma warning disable CS1591
-#pragma warning disable SA1600
-
using System;
using System.Collections.Generic;
namespace MediaBrowser.Common.Configuration
{
+ /// <summary>
+ /// Provides an interface to retrieve a configuration store. Classes with this interface are scanned for at
+ /// application start to dynamically register configuration for various modules/plugins.
+ /// </summary>
public interface IConfigurationFactory
{
+ /// <summary>
+ /// Get the configuration store for this module.
+ /// </summary>
+ /// <returns>The configuration store.</returns>
IEnumerable<ConfigurationStore> GetConfigurations();
}
+ /// <summary>
+ /// Describes a single entry in the application configuration.
+ /// </summary>
public class ConfigurationStore
{
+ /// <summary>
+ /// Gets or sets the unique identifier for the configuration.
+ /// </summary>
public string Key { get; set; }
+ /// <summary>
+ /// Gets or sets the type used to store the data for this configuration entry.
+ /// </summary>
public Type ConfigurationType { get; set; }
}
+ /// <summary>
+ /// A configuration store that can be validated.
+ /// </summary>
public interface IValidatingConfiguration
{
+ /// <summary>
+ /// Validation method to be invoked before saving the configuration.
+ /// </summary>
+ /// <param name="oldConfig">The old configuration.</param>
+ /// <param name="newConfig">The new configuration.</param>
void Validate(object oldConfig, object newConfig);
}
}
diff --git a/MediaBrowser.Controller/Drawing/IImageProcessor.cs b/MediaBrowser.Controller/Drawing/IImageProcessor.cs
index a58a11bd1..79399807f 100644
--- a/MediaBrowser.Controller/Drawing/IImageProcessor.cs
+++ b/MediaBrowser.Controller/Drawing/IImageProcessor.cs
@@ -3,7 +3,6 @@ using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Drawing;
using MediaBrowser.Model.Entities;
@@ -21,19 +20,11 @@ namespace MediaBrowser.Controller.Drawing
IReadOnlyCollection<string> SupportedInputFormats { get; }
/// <summary>
- /// Gets the image enhancers.
- /// </summary>
- /// <value>The image enhancers.</value>
- IReadOnlyCollection<IImageEnhancer> ImageEnhancers { get; set; }
-
- /// <summary>
/// Gets a value indicating whether [supports image collage creation].
/// </summary>
/// <value><c>true</c> if [supports image collage creation]; otherwise, <c>false</c>.</value>
bool SupportsImageCollageCreation { get; }
- IImageEncoder ImageEncoder { get; set; }
-
/// <summary>
/// Gets the dimensions of the image.
/// </summary>
@@ -59,14 +50,6 @@ namespace MediaBrowser.Controller.Drawing
ImageDimensions GetImageDimensions(BaseItem item, ItemImageInfo info, bool updateItem);
/// <summary>
- /// Gets the supported enhancers.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="imageType">Type of the image.</param>
- /// <returns>IEnumerable{IImageEnhancer}.</returns>
- IEnumerable<IImageEnhancer> GetSupportedEnhancers(BaseItem item, ImageType imageType);
-
- /// <summary>
/// Gets the image cache tag.
/// </summary>
/// <param name="item">The item.</param>
@@ -76,15 +59,6 @@ namespace MediaBrowser.Controller.Drawing
string GetImageCacheTag(BaseItem item, ChapterInfo info);
/// <summary>
- /// Gets the image cache tag.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="image">The image.</param>
- /// <param name="imageEnhancers">The image enhancers.</param>
- /// <returns>Guid.</returns>
- string GetImageCacheTag(BaseItem item, ItemImageInfo image, IReadOnlyCollection<IImageEnhancer> imageEnhancers);
-
- /// <summary>
/// Processes the image.
/// </summary>
/// <param name="options">The options.</param>
@@ -100,15 +74,6 @@ namespace MediaBrowser.Controller.Drawing
Task<(string path, string mimeType, DateTime dateModified)> ProcessImage(ImageProcessingOptions options);
/// <summary>
- /// Gets the enhanced image.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="imageType">Type of the image.</param>
- /// <param name="imageIndex">Index of the image.</param>
- /// <returns>Task{System.String}.</returns>
- Task<string> GetEnhancedImage(BaseItem item, ImageType imageType, int imageIndex);
-
- /// <summary>
/// Gets the supported image output formats.
/// </summary>
/// <returns><see cref="IReadOnlyCollection{ImageOutput}" />.</returns>
diff --git a/MediaBrowser.Controller/Drawing/ImageHelper.cs b/MediaBrowser.Controller/Drawing/ImageHelper.cs
index 432cf8042..d5a5f547e 100644
--- a/MediaBrowser.Controller/Drawing/ImageHelper.cs
+++ b/MediaBrowser.Controller/Drawing/ImageHelper.cs
@@ -19,8 +19,6 @@ namespace MediaBrowser.Controller.Drawing
return GetSizeEstimate(options);
}
- public static IImageProcessor ImageProcessor { get; set; }
-
private static ImageDimensions GetSizeEstimate(ImageProcessingOptions options)
{
if (options.Width.HasValue && options.Height.HasValue)
diff --git a/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs b/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs
index 29addf6e6..870e0278e 100644
--- a/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs
+++ b/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs
@@ -3,7 +3,6 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Drawing;
namespace MediaBrowser.Controller.Drawing
@@ -34,8 +33,6 @@ namespace MediaBrowser.Controller.Drawing
public int Quality { get; set; }
- public IReadOnlyCollection<IImageEnhancer> Enhancers { get; set; }
-
public IReadOnlyCollection<ImageFormat> SupportedOutputFormats { get; set; }
public bool AddPlayedIndicator { get; set; }
diff --git a/MediaBrowser.Controller/Entities/Photo.cs b/MediaBrowser.Controller/Entities/Photo.cs
index 86d62add9..5ebc9f16a 100644
--- a/MediaBrowser.Controller/Entities/Photo.cs
+++ b/MediaBrowser.Controller/Entities/Photo.cs
@@ -41,10 +41,10 @@ namespace MediaBrowser.Controller.Entities
public override double GetDefaultPrimaryImageAspectRatio()
{
// REVIEW: @bond
- if (Width.HasValue && Height.HasValue)
+ if (Width != 0 && Height != 0)
{
- double width = Width.Value;
- double height = Height.Value;
+ double width = Width;
+ double height = Height;
if (Orientation.HasValue)
{
@@ -67,8 +67,6 @@ namespace MediaBrowser.Controller.Entities
return base.GetDefaultPrimaryImageAspectRatio();
}
- public new int? Width { get; set; }
- public new int? Height { get; set; }
public string CameraMake { get; set; }
public string CameraModel { get; set; }
public string Software { get; set; }
diff --git a/MediaBrowser.Controller/Library/ILibraryManager.cs b/MediaBrowser.Controller/Library/ILibraryManager.cs
index 511356aa4..2e1c97f67 100644
--- a/MediaBrowser.Controller/Library/ILibraryManager.cs
+++ b/MediaBrowser.Controller/Library/ILibraryManager.cs
@@ -157,7 +157,8 @@ namespace MediaBrowser.Controller.Library
/// <param name="introProviders">The intro providers.</param>
/// <param name="itemComparers">The item comparers.</param>
/// <param name="postscanTasks">The postscan tasks.</param>
- void AddParts(IEnumerable<IResolverIgnoreRule> rules,
+ void AddParts(
+ IEnumerable<IResolverIgnoreRule> rules,
IEnumerable<IItemResolver> resolvers,
IEnumerable<IIntroProvider> introProviders,
IEnumerable<IBaseItemComparer> itemComparers,
@@ -349,9 +350,6 @@ namespace MediaBrowser.Controller.Library
/// <returns><c>true</c> if [is audio file] [the specified path]; otherwise, <c>false</c>.</returns>
bool IsAudioFile(string path);
- bool IsAudioFile(string path, LibraryOptions libraryOptions);
- bool IsVideoFile(string path, LibraryOptions libraryOptions);
-
/// <summary>
/// Gets the season number from path.
/// </summary>
diff --git a/MediaBrowser.Controller/Library/IMediaSourceProvider.cs b/MediaBrowser.Controller/Library/IMediaSourceProvider.cs
index 9e74879fc..ec7798551 100644
--- a/MediaBrowser.Controller/Library/IMediaSourceProvider.cs
+++ b/MediaBrowser.Controller/Library/IMediaSourceProvider.cs
@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs b/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs
index 35f188bb7..38ef33caf 100644
--- a/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs
+++ b/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs
@@ -316,11 +316,7 @@ namespace MediaBrowser.Controller.MediaEncoding
{
if (VideoStream != null && VideoStream.Width.HasValue && VideoStream.Height.HasValue)
{
- var size = new ImageDimensions
- {
- Width = VideoStream.Width.Value,
- Height = VideoStream.Height.Value
- };
+ var size = new ImageDimensions(VideoStream.Width.Value, VideoStream.Height.Value);
var newSize = DrawingUtils.Resize(size,
BaseRequest.Width ?? 0,
@@ -346,11 +342,7 @@ namespace MediaBrowser.Controller.MediaEncoding
{
if (VideoStream != null && VideoStream.Width.HasValue && VideoStream.Height.HasValue)
{
- var size = new ImageDimensions
- {
- Width = VideoStream.Width.Value,
- Height = VideoStream.Height.Value
- };
+ var size = new ImageDimensions(VideoStream.Width.Value, VideoStream.Height.Value);
var newSize = DrawingUtils.Resize(size,
BaseRequest.Width ?? 0,
diff --git a/MediaBrowser.Controller/Net/IAuthService.cs b/MediaBrowser.Controller/Net/IAuthService.cs
index 4c9120e0c..9132404a0 100644
--- a/MediaBrowser.Controller/Net/IAuthService.cs
+++ b/MediaBrowser.Controller/Net/IAuthService.cs
@@ -1,3 +1,5 @@
+#nullable enable
+
using MediaBrowser.Controller.Entities;
using MediaBrowser.Model.Services;
using Microsoft.AspNetCore.Http;
@@ -7,6 +9,6 @@ namespace MediaBrowser.Controller.Net
public interface IAuthService
{
void Authenticate(IRequest request, IAuthenticationAttributes authAttribtues);
- User Authenticate(HttpRequest request, IAuthenticationAttributes authAttribtues);
+ User? Authenticate(HttpRequest request, IAuthenticationAttributes authAttribtues);
}
}
diff --git a/MediaBrowser.Controller/Plugins/IServerEntryPoint.cs b/MediaBrowser.Controller/Plugins/IServerEntryPoint.cs
index e57929989..1e8654c4d 100644
--- a/MediaBrowser.Controller/Plugins/IServerEntryPoint.cs
+++ b/MediaBrowser.Controller/Plugins/IServerEntryPoint.cs
@@ -4,16 +4,22 @@ using System.Threading.Tasks;
namespace MediaBrowser.Controller.Plugins
{
/// <summary>
- /// Interface IServerEntryPoint
+ /// Represents an entry point for a module in the application. This interface is scanned for automatically and
+ /// provides a hook to initialize the module at application start.
+ /// The entry point can additionally be flagged as a pre-startup task by implementing the
+ /// <see cref="IRunBeforeStartup"/> interface.
/// </summary>
public interface IServerEntryPoint : IDisposable
{
/// <summary>
- /// Runs this instance.
+ /// Run the initialization for this module. This method is invoked at application start.
/// </summary>
Task RunAsync();
}
+ /// <summary>
+ /// Indicates that a <see cref="IServerEntryPoint"/> should be invoked as a pre-startup task.
+ /// </summary>
public interface IRunBeforeStartup
{
diff --git a/MediaBrowser.Controller/Providers/IImageEnhancer.cs b/MediaBrowser.Controller/Providers/IImageEnhancer.cs
deleted file mode 100644
index c27c00ca2..000000000
--- a/MediaBrowser.Controller/Providers/IImageEnhancer.cs
+++ /dev/null
@@ -1,61 +0,0 @@
-using System.Threading.Tasks;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Model.Drawing;
-using MediaBrowser.Model.Entities;
-
-namespace MediaBrowser.Controller.Providers
-{
- public interface IImageEnhancer
- {
- /// <summary>
- /// Return true only if the given image for the given item will be enhanced by this enhancer.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="imageType">Type of the image.</param>
- /// <returns><c>true</c> if this enhancer will enhance the supplied image for the supplied item, <c>false</c> otherwise</returns>
- bool Supports(BaseItem item, ImageType imageType);
-
- /// <summary>
- /// Gets the priority or order in which this enhancer should be run.
- /// </summary>
- /// <value>The priority.</value>
- MetadataProviderPriority Priority { get; }
-
- /// <summary>
- /// Return a key incorporating all configuration information related to this item
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="imageType">Type of the image.</param>
- /// <returns>Cache key relating to the current state of this item and configuration</returns>
- string GetConfigurationCacheKey(BaseItem item, ImageType imageType);
-
- /// <summary>
- /// Gets the size of the enhanced image.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="imageType">Type of the image.</param>
- /// <param name="imageIndex">Index of the image.</param>
- /// <param name="originalImageSize">Size of the original image.</param>
- /// <returns>ImageSize.</returns>
- ImageDimensions GetEnhancedImageSize(BaseItem item, ImageType imageType, int imageIndex, ImageDimensions originalImageSize);
-
- EnhancedImageInfo GetEnhancedImageInfo(BaseItem item, string inputFile, ImageType imageType, int imageIndex);
-
- /// <summary>
- /// Enhances the image async.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="inputFile">The input file.</param>
- /// <param name="outputFile">The output file.</param>
- /// <param name="imageType">Type of the image.</param>
- /// <param name="imageIndex">Index of the image.</param>
- /// <returns>Task{Image}.</returns>
- /// <exception cref="System.ArgumentNullException"></exception>
- Task EnhanceImageAsync(BaseItem item, string inputFile, string outputFile, ImageType imageType, int imageIndex);
- }
-
- public class EnhancedImageInfo
- {
- public bool RequiresTransparency { get; set; }
- }
-}
diff --git a/MediaBrowser.Controller/Session/SessionInfo.cs b/MediaBrowser.Controller/Session/SessionInfo.cs
index 6e8385cf8..f1f10a3a3 100644
--- a/MediaBrowser.Controller/Session/SessionInfo.cs
+++ b/MediaBrowser.Controller/Session/SessionInfo.cs
@@ -107,6 +107,8 @@ namespace MediaBrowser.Controller.Session
public BaseItem FullNowPlayingItem { get; set; }
+ public BaseItemDto NowViewingItem { get; set; }
+
/// <summary>
/// Gets or sets the device id.
/// </summary>
@@ -239,11 +241,6 @@ namespace MediaBrowser.Controller.Session
SessionControllers = controllers.ToArray();
}
- public bool ContainsUser(string userId)
- {
- return ContainsUser(new Guid(userId));
- }
-
public bool ContainsUser(Guid userId)
{
if (UserId.Equals(userId))
diff --git a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs
index bd89c6cae..f8047af42 100644
--- a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs
+++ b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs
@@ -112,6 +112,9 @@ namespace MediaBrowser.MediaEncoding.Probing
info.Name = title;
}
+ info.IndexNumber = FFProbeHelpers.GetDictionaryNumericValue(tags, "episode_sort");
+ info.ParentIndexNumber = FFProbeHelpers.GetDictionaryNumericValue(tags, "season_number");
+ info.ShowName = FFProbeHelpers.GetDictionaryValue(tags, "show_name");
info.ProductionYear = FFProbeHelpers.GetDictionaryNumericValue(tags, "date");
// Several different forms of retaildate
diff --git a/MediaBrowser.Model/Configuration/LibraryOptions.cs b/MediaBrowser.Model/Configuration/LibraryOptions.cs
index 3c99f9bb5..9d5d2b869 100644
--- a/MediaBrowser.Model/Configuration/LibraryOptions.cs
+++ b/MediaBrowser.Model/Configuration/LibraryOptions.cs
@@ -21,6 +21,7 @@ namespace MediaBrowser.Model.Configuration
public bool ImportMissingEpisodes { get; set; }
public bool EnableAutomaticSeriesGrouping { get; set; }
public bool EnableEmbeddedTitles { get; set; }
+ public bool EnableEmbeddedEpisodeInfos { get; set; }
public int AutomaticRefreshIntervalDays { get; set; }
diff --git a/MediaBrowser.Model/Configuration/ServerConfiguration.cs b/MediaBrowser.Model/Configuration/ServerConfiguration.cs
index f42aa2b44..5280d455c 100644
--- a/MediaBrowser.Model/Configuration/ServerConfiguration.cs
+++ b/MediaBrowser.Model/Configuration/ServerConfiguration.cs
@@ -165,6 +165,7 @@ namespace MediaBrowser.Model.Configuration
public bool SkipDeserializationForBasicTypes { get; set; }
public string ServerName { get; set; }
+
public string BaseUrl
{
get => _baseUrl;
diff --git a/MediaBrowser.Model/Drawing/ImageDimensions.cs b/MediaBrowser.Model/Drawing/ImageDimensions.cs
index b546dbb25..160be11f0 100644
--- a/MediaBrowser.Model/Drawing/ImageDimensions.cs
+++ b/MediaBrowser.Model/Drawing/ImageDimensions.cs
@@ -1,39 +1,46 @@
#pragma warning disable CS1591
#pragma warning disable SA1600
+using System.Globalization;
+
namespace MediaBrowser.Model.Drawing
{
/// <summary>
/// Struct ImageDimensions.
/// </summary>
- public struct ImageDimensions
+ public readonly struct ImageDimensions
{
+ public ImageDimensions(int width, int height)
+ {
+ Width = width;
+ Height = height;
+ }
+
/// <summary>
- /// Gets or sets the height.
+ /// Gets the height.
/// </summary>
/// <value>The height.</value>
- public int Height { get; set; }
+ public int Height { get; }
/// <summary>
- /// Gets or sets the width.
+ /// Gets the width.
/// </summary>
/// <value>The width.</value>
- public int Width { get; set; }
+ public int Width { get; }
public bool Equals(ImageDimensions size)
{
return Width.Equals(size.Width) && Height.Equals(size.Height);
}
+ /// <inheritdoc />
public override string ToString()
{
- return string.Format("{0}-{1}", Width, Height);
- }
-
- public ImageDimensions(int width, int height)
- {
- Width = width;
- Height = height;
+ return string.Format(
+ CultureInfo.InvariantCulture,
+ "{0}-{1}",
+ Width,
+ Height);
}
}
}
diff --git a/MediaBrowser.Model/MediaInfo/MediaInfo.cs b/MediaBrowser.Model/MediaInfo/MediaInfo.cs
index 6ad766d39..237a2b36c 100644
--- a/MediaBrowser.Model/MediaInfo/MediaInfo.cs
+++ b/MediaBrowser.Model/MediaInfo/MediaInfo.cs
@@ -36,6 +36,7 @@ namespace MediaBrowser.Model.MediaInfo
/// <value>The studios.</value>
public string[] Studios { get; set; }
public string[] Genres { get; set; }
+ public string ShowName { get; set; }
public int? IndexNumber { get; set; }
public int? ParentIndexNumber { get; set; }
public int? ProductionYear { get; set; }
diff --git a/MediaBrowser.Model/Querying/QueryResult.cs b/MediaBrowser.Model/Querying/QueryResult.cs
index ad89ae38d..5d4d6226b 100644
--- a/MediaBrowser.Model/Querying/QueryResult.cs
+++ b/MediaBrowser.Model/Querying/QueryResult.cs
@@ -30,5 +30,11 @@ namespace MediaBrowser.Model.Querying
{
Items = Array.Empty<T>();
}
+
+ public QueryResult(IReadOnlyList<T> items)
+ {
+ Items = items;
+ TotalRecordCount = items.Count;
+ }
}
}
diff --git a/MediaBrowser.Model/Services/ApiMemberAttribute.cs b/MediaBrowser.Model/Services/ApiMemberAttribute.cs
index 7267fce24..8e50836f4 100644
--- a/MediaBrowser.Model/Services/ApiMemberAttribute.cs
+++ b/MediaBrowser.Model/Services/ApiMemberAttribute.cs
@@ -1,10 +1,10 @@
-#pragma warning disable CS1591
-#pragma warning disable SA1600
-
using System;
namespace MediaBrowser.Model.Services
{
+ /// <summary>
+ /// Identifies a single API endpoint.
+ /// </summary>
[AttributeUsage(AttributeTargets.Property, AllowMultiple = true, Inherited = true)]
public class ApiMemberAttribute : Attribute
{
diff --git a/deployment/fedora-package-x64/Dockerfile b/deployment/fedora-package-x64/Dockerfile
index f5c3ab7a6..05a4ef21f 100644
--- a/deployment/fedora-package-x64/Dockerfile
+++ b/deployment/fedora-package-x64/Dockerfile
@@ -12,11 +12,11 @@ ENV ARTIFACT_DIR=/dist
RUN dnf update -y
# Install build dependencies
-RUN dnf install -y @buildsys-build rpmdevtools dnf-plugins-core libcurl-devel fontconfig-devel freetype-devel openssl-devel glibc-devel libicu-devel nodejs-yarn
+RUN dnf install -y @buildsys-build rpmdevtools git dnf-plugins-core libcurl-devel fontconfig-devel freetype-devel openssl-devel glibc-devel libicu-devel nodejs-yarn
# Install DotNET SDK
-RUN dnf copr enable -y @dotnet-sig/dotnet \
- && rpmdev-setuptree \
+RUN rpm --import https://packages.microsoft.com/keys/microsoft.asc \
+ && curl -o /etc/yum.repos.d/microsoft-prod.repo https://packages.microsoft.com/config/fedora/$(rpm -E %fedora)/prod.repo \
&& dnf install -y dotnet-sdk-${SDK_VERSION} dotnet-runtime-${SDK_VERSION}
# Create symlinks and directories
diff --git a/tests/Jellyfin.Api.Tests/Auth/CustomAuthenticationHandlerTests.cs b/tests/Jellyfin.Api.Tests/Auth/CustomAuthenticationHandlerTests.cs
index a2f5c2501..3b3d03c8b 100644
--- a/tests/Jellyfin.Api.Tests/Auth/CustomAuthenticationHandlerTests.cs
+++ b/tests/Jellyfin.Api.Tests/Auth/CustomAuthenticationHandlerTests.cs
@@ -83,7 +83,7 @@ namespace Jellyfin.Api.Tests.Auth
a => a.Authenticate(
It.IsAny<HttpRequest>(),
It.IsAny<AuthenticatedAttribute>()))
- .Returns((User)null);
+ .Returns((User?)null);
var authenticateResult = await _sut.AuthenticateAsync();
diff --git a/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj b/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj
index 0e8ef135e..1d7e4f7af 100644
--- a/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj
+++ b/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj
@@ -3,6 +3,8 @@
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<IsPackable>false</IsPackable>
+ <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
+ <Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
diff --git a/tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj b/tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj
index da5e6576d..86bb11bd4 100644
--- a/tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj
+++ b/tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj
@@ -3,6 +3,8 @@
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<IsPackable>false</IsPackable>
+ <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
+ <Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
diff --git a/tests/Jellyfin.MediaEncoding.Tests/EncoderValidatorTests.cs b/tests/Jellyfin.MediaEncoding.Tests/EncoderValidatorTests.cs
index a7848316e..e0f1f236c 100644
--- a/tests/Jellyfin.MediaEncoding.Tests/EncoderValidatorTests.cs
+++ b/tests/Jellyfin.MediaEncoding.Tests/EncoderValidatorTests.cs
@@ -9,15 +9,15 @@ namespace Jellyfin.MediaEncoding.Tests
{
public class EncoderValidatorTests
{
- private class GetFFmpegVersionTestData : IEnumerable<object[]>
+ private class GetFFmpegVersionTestData : IEnumerable<object?[]>
{
- public IEnumerator<object[]> GetEnumerator()
+ public IEnumerator<object?[]> GetEnumerator()
{
- yield return new object[] { EncoderValidatorTestsData.FFmpegV421Output, new Version(4, 2, 1) };
- yield return new object[] { EncoderValidatorTestsData.FFmpegV42Output, new Version(4, 2) };
- yield return new object[] { EncoderValidatorTestsData.FFmpegV414Output, new Version(4, 1, 4) };
- yield return new object[] { EncoderValidatorTestsData.FFmpegV404Output, new Version(4, 0, 4) };
- yield return new object[] { EncoderValidatorTestsData.FFmpegGitUnknownOutput, null };
+ yield return new object?[] { EncoderValidatorTestsData.FFmpegV421Output, new Version(4, 2, 1) };
+ yield return new object?[] { EncoderValidatorTestsData.FFmpegV42Output, new Version(4, 2) };
+ yield return new object?[] { EncoderValidatorTestsData.FFmpegV414Output, new Version(4, 1, 4) };
+ yield return new object?[] { EncoderValidatorTestsData.FFmpegV404Output, new Version(4, 0, 4) };
+ yield return new object?[] { EncoderValidatorTestsData.FFmpegGitUnknownOutput, null };
}
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
@@ -25,7 +25,7 @@ namespace Jellyfin.MediaEncoding.Tests
[Theory]
[ClassData(typeof(GetFFmpegVersionTestData))]
- public void GetFFmpegVersionTest(string versionOutput, Version version)
+ public void GetFFmpegVersionTest(string versionOutput, Version? version)
{
Assert.Equal(version, EncoderValidator.GetFFmpegVersion(versionOutput));
}
diff --git a/tests/Jellyfin.MediaEncoding.Tests/Jellyfin.MediaEncoding.Tests.csproj b/tests/Jellyfin.MediaEncoding.Tests/Jellyfin.MediaEncoding.Tests.csproj
index c01edd9fe..b5e4a1287 100644
--- a/tests/Jellyfin.MediaEncoding.Tests/Jellyfin.MediaEncoding.Tests.csproj
+++ b/tests/Jellyfin.MediaEncoding.Tests/Jellyfin.MediaEncoding.Tests.csproj
@@ -3,6 +3,8 @@
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<IsPackable>false</IsPackable>
+ <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
+ <Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
diff --git a/tests/Jellyfin.Naming.Tests/Jellyfin.Naming.Tests.csproj b/tests/Jellyfin.Naming.Tests/Jellyfin.Naming.Tests.csproj
index f246d459b..9602d9e58 100644
--- a/tests/Jellyfin.Naming.Tests/Jellyfin.Naming.Tests.csproj
+++ b/tests/Jellyfin.Naming.Tests/Jellyfin.Naming.Tests.csproj
@@ -3,6 +3,7 @@
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<IsPackable>false</IsPackable>
+ <Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
diff --git a/tests/Jellyfin.Naming.Tests/TV/EpisodeNumberTests.cs b/tests/Jellyfin.Naming.Tests/TV/EpisodeNumberTests.cs
index 93c59c9ca..5017fce4d 100644
--- a/tests/Jellyfin.Naming.Tests/TV/EpisodeNumberTests.cs
+++ b/tests/Jellyfin.Naming.Tests/TV/EpisodeNumberTests.cs
@@ -6,6 +6,21 @@ namespace Jellyfin.Naming.Tests.TV
{
public class EpisodeNumberTests
{
+ private readonly NamingOptions _namingOptions = new NamingOptions();
+
+ [Theory]
+ [InlineData("Watchmen (2019)/Watchmen 1x03 [WEBDL-720p][EAC3 5.1][h264][-TBS] - She Was Killed by Space Junk.mkv", 3)]
+ [InlineData("The Daily Show/The Daily Show 25x22 - [WEBDL-720p][AAC 2.0][x264] Noah Baumbach-TBS.mkv", 22)]
+ [InlineData("Castle Rock 2x01 Que el rio siga su curso [WEB-DL HULU 1080p h264 Dual DD5.1 Subs].mkv", 1)]
+ [InlineData("After Life 1x06 Episodio 6 [WEB-DL NF 1080p h264 Dual DD 5.1 Sub].mkv", 6)]
+ public void GetEpisodeNumberFromFileTest(string path, int? expected)
+ {
+ var result = new EpisodePathParser(_namingOptions)
+ .Parse(path, false);
+
+ Assert.Equal(expected, result.EpisodeNumber);
+ }
+
[Fact]
public void TestEpisodeNumber1()
{
@@ -382,9 +397,7 @@ namespace Jellyfin.Naming.Tests.TV
private int? GetEpisodeNumberFromFile(string path)
{
- var options = new NamingOptions();
-
- var result = new EpisodePathParser(options)
+ var result = new EpisodePathParser(_namingOptions)
.Parse(path, false);
return result.EpisodeNumber;
diff --git a/tests/Jellyfin.Naming.Tests/TV/SeasonNumberTests.cs b/tests/Jellyfin.Naming.Tests/TV/SeasonNumberTests.cs
index ba3c5ecac..1df28c974 100644
--- a/tests/Jellyfin.Naming.Tests/TV/SeasonNumberTests.cs
+++ b/tests/Jellyfin.Naming.Tests/TV/SeasonNumberTests.cs
@@ -6,11 +6,21 @@ namespace Jellyfin.Naming.Tests.TV
{
public class SeasonNumberTests
{
- private int? GetSeasonNumberFromEpisodeFile(string path)
+ private readonly NamingOptions _namingOptions = new NamingOptions();
+
+ [Theory]
+ [InlineData("The Daily Show/The Daily Show 25x22 - [WEBDL-720p][AAC 2.0][x264] Noah Baumbach-TBS.mkv", 25)]
+ public void GetSeasonNumberFromEpisodeFileTest(string path, int? expected)
{
- var options = new NamingOptions();
+ var result = new EpisodeResolver(_namingOptions)
+ .Resolve(path, false);
- var result = new EpisodeResolver(options)
+ Assert.Equal(expected, result.SeasonNumber);
+ }
+
+ private int? GetSeasonNumberFromEpisodeFile(string path)
+ {
+ var result = new EpisodeResolver(_namingOptions)
.Resolve(path, false);
return result.SeasonNumber;
diff --git a/tests/Jellyfin.Server.Implementations.Tests/Jellyfin.Server.Implementations.Tests.csproj b/tests/Jellyfin.Server.Implementations.Tests/Jellyfin.Server.Implementations.Tests.csproj
index c554bc937..29733a1c4 100644
--- a/tests/Jellyfin.Server.Implementations.Tests/Jellyfin.Server.Implementations.Tests.csproj
+++ b/tests/Jellyfin.Server.Implementations.Tests/Jellyfin.Server.Implementations.Tests.csproj
@@ -3,6 +3,8 @@
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<IsPackable>false</IsPackable>
+ <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
+ <Nullable>enable</Nullable>
<RootNamespace>Jellyfin.Server.Implementations.Tests</RootNamespace>
</PropertyGroup>