aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Emby.Common.Implementations/BaseApplicationHost.cs902
-rw-r--r--Emby.Common.Implementations/Emby.Common.Implementations.csproj453
-rw-r--r--Emby.Common.Implementations/Logging/NLogger.cs224
-rw-r--r--Emby.Common.Implementations/Logging/NlogManager.cs544
-rw-r--r--Emby.Common.Implementations/Net/NetAcceptSocket.cs154
-rw-r--r--Emby.Common.Implementations/Properties/AssemblyInfo.cs34
-rw-r--r--Emby.Common.Implementations/packages.config7
-rw-r--r--Emby.Dlna/ContentDirectory/ContentDirectory.cs29
-rw-r--r--Emby.Dlna/ContentDirectory/ControlHandler.cs498
-rw-r--r--Emby.Dlna/Didl/DidlBuilder.cs58
-rw-r--r--Emby.Dlna/Didl/Filter.cs7
-rw-r--r--Emby.Dlna/Didl/StringWriterWithEncoding.cs1
-rw-r--r--Emby.Dlna/DlnaManager.cs12
-rw-r--r--Emby.Dlna/Main/DlnaEntryPoint.cs3
-rw-r--r--Emby.Dlna/MediaReceiverRegistrar/MediaReceiverRegistrar.cs7
-rw-r--r--Emby.Dlna/PlayTo/Device.cs46
-rw-r--r--Emby.Dlna/PlayTo/PlayToController.cs16
-rw-r--r--Emby.Dlna/PlayTo/PlayToManager.cs3
-rw-r--r--Emby.Dlna/Profiles/DefaultProfile.cs3
-rw-r--r--Emby.Dlna/Profiles/PanasonicVieraProfile.cs270
-rw-r--r--Emby.Dlna/Server/DescriptionXmlBuilder.cs2
-rw-r--r--Emby.Dlna/Service/BaseControlHandler.cs28
-rw-r--r--Emby.Dlna/Ssdp/Extensions.cs9
-rw-r--r--Emby.Drawing.ImageMagick/Emby.Drawing.ImageMagick.csproj9
-rw-r--r--Emby.Drawing.ImageMagick/ImageHelpers.cs6
-rw-r--r--Emby.Drawing.ImageMagick/ImageMagickEncoder.cs13
-rw-r--r--Emby.Drawing.ImageMagick/StripCollageBuilder.cs12
-rw-r--r--Emby.Drawing.ImageMagick/packages.config2
-rw-r--r--Emby.Drawing.Skia/Emby.Drawing.Skia.csproj2
-rw-r--r--Emby.Drawing.Skia/SkiaEncoder.cs244
-rw-r--r--Emby.Drawing.Skia/packages.config2
-rw-r--r--Emby.Drawing/Emby.Drawing.csproj5
-rw-r--r--Emby.Drawing/ImageProcessor.cs144
-rw-r--r--Emby.Drawing/NullImageEncoder.cs4
-rw-r--r--Emby.Photos/PhotoProvider.cs2
-rw-r--r--Emby.Server.Core/Emby.Server.Core.csproj176
-rw-r--r--Emby.Server.Core/IO/MemoryStreamProvider.cs56
-rw-r--r--Emby.Server.Core/Properties/AssemblyInfo.cs34
-rw-r--r--Emby.Server.Core/app.config11
-rw-r--r--Emby.Server.Core/packages.config6
-rw-r--r--Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs16
-rw-r--r--Emby.Server.Implementations/Activity/ActivityManager.cs6
-rw-r--r--Emby.Server.Implementations/Activity/ActivityRepository.cs16
-rw-r--r--Emby.Server.Implementations/AppBase/BaseApplicationPaths.cs9
-rw-r--r--Emby.Server.Implementations/ApplicationHost.cs (renamed from Emby.Server.Core/ApplicationHost.cs)1125
-rw-r--r--Emby.Server.Implementations/Archiving/ZipClient.cs (renamed from Emby.Common.Implementations/Archiving/ZipClient.cs)3
-rw-r--r--Emby.Server.Implementations/Channels/ChannelImageProvider.cs8
-rw-r--r--Emby.Server.Implementations/Channels/ChannelManager.cs68
-rw-r--r--Emby.Server.Implementations/Collections/CollectionImageProvider.cs6
-rw-r--r--Emby.Server.Implementations/Collections/CollectionManager.cs44
-rw-r--r--Emby.Server.Implementations/Configuration/ServerConfigurationManager.cs5
-rw-r--r--Emby.Server.Implementations/Cryptography/ASN1.cs (renamed from Emby.Server.Core/Cryptography/ASN1.cs)0
-rw-r--r--Emby.Server.Implementations/Cryptography/ASN1Convert.cs (renamed from Emby.Server.Core/Cryptography/ASN1Convert.cs)0
-rw-r--r--Emby.Server.Implementations/Cryptography/BitConverterLE.cs (renamed from Emby.Server.Core/Cryptography/BitConverterLE.cs)0
-rw-r--r--Emby.Server.Implementations/Cryptography/CertificateGenerator.cs (renamed from Emby.Server.Core/Cryptography/CertificateGenerator.cs)42
-rw-r--r--Emby.Server.Implementations/Cryptography/CryptoConvert.cs (renamed from Emby.Server.Core/Cryptography/CryptoConvert.cs)0
-rw-r--r--Emby.Server.Implementations/Cryptography/CryptographyProvider.cs (renamed from Emby.Common.Implementations/Cryptography/CryptographyProvider.cs)2
-rw-r--r--Emby.Server.Implementations/Cryptography/PKCS1.cs (renamed from Emby.Server.Core/Cryptography/PKCS1.cs)0
-rw-r--r--Emby.Server.Implementations/Cryptography/PKCS12.cs (renamed from Emby.Server.Core/Cryptography/PKCS12.cs)0
-rw-r--r--Emby.Server.Implementations/Cryptography/PKCS7.cs (renamed from Emby.Server.Core/Cryptography/PKCS7.cs)0
-rw-r--r--Emby.Server.Implementations/Cryptography/PKCS8.cs (renamed from Emby.Server.Core/Cryptography/PKCS8.cs)0
-rw-r--r--Emby.Server.Implementations/Cryptography/PfxGenerator.cs (renamed from Emby.Server.Core/Cryptography/PfxGenerator.cs)0
-rw-r--r--Emby.Server.Implementations/Cryptography/X501Name.cs (renamed from Emby.Server.Core/Cryptography/X501Name.cs)0
-rw-r--r--Emby.Server.Implementations/Cryptography/X509Builder.cs (renamed from Emby.Server.Core/Cryptography/X509Builder.cs)0
-rw-r--r--Emby.Server.Implementations/Cryptography/X509Certificate.cs (renamed from Emby.Server.Core/Cryptography/X509Certificate.cs)0
-rw-r--r--Emby.Server.Implementations/Cryptography/X509CertificateBuilder.cs (renamed from Emby.Server.Core/Cryptography/X509CertificateBuilder.cs)0
-rw-r--r--Emby.Server.Implementations/Cryptography/X509CertificateCollection.cs (renamed from Emby.Server.Core/Cryptography/X509CertificateCollection.cs)0
-rw-r--r--Emby.Server.Implementations/Cryptography/X509Extension.cs (renamed from Emby.Server.Core/Cryptography/X509Extension.cs)0
-rw-r--r--Emby.Server.Implementations/Cryptography/X509Extensions.cs (renamed from Emby.Server.Core/Cryptography/X509Extensions.cs)0
-rw-r--r--Emby.Server.Implementations/Cryptography/X520Attributes.cs (renamed from Emby.Server.Core/Cryptography/X520Attributes.cs)0
-rw-r--r--Emby.Server.Implementations/Data/BaseSqliteRepository.cs27
-rw-r--r--Emby.Server.Implementations/Data/CleanDatabaseScheduledTask.cs47
-rw-r--r--Emby.Server.Implementations/Data/ManagedConnection.cs1
-rw-r--r--Emby.Server.Implementations/Data/SqliteDisplayPreferencesRepository.cs9
-rw-r--r--Emby.Server.Implementations/Data/SqliteItemRepository.cs462
-rw-r--r--Emby.Server.Implementations/Data/SqliteUserDataRepository.cs15
-rw-r--r--Emby.Server.Implementations/Data/SqliteUserRepository.cs5
-rw-r--r--Emby.Server.Implementations/Devices/CameraUploadsDynamicFolder.cs1
-rw-r--r--Emby.Server.Implementations/Devices/CameraUploadsFolder.cs (renamed from MediaBrowser.Server.Implementations/Devices/CameraUploadsFolder.cs)10
-rw-r--r--Emby.Server.Implementations/Devices/DeviceId.cs (renamed from Emby.Common.Implementations/Devices/DeviceId.cs)2
-rw-r--r--Emby.Server.Implementations/Devices/DeviceRepository.cs6
-rw-r--r--Emby.Server.Implementations/Diagnostics/CommonProcess.cs (renamed from Emby.Common.Implementations/Diagnostics/CommonProcess.cs)5
-rw-r--r--Emby.Server.Implementations/Diagnostics/ProcessFactory.cs (renamed from Emby.Common.Implementations/Diagnostics/ProcessFactory.cs)2
-rw-r--r--Emby.Server.Implementations/Dto/DtoService.cs211
-rw-r--r--Emby.Server.Implementations/Emby.Server.Implementations.csproj458
-rw-r--r--Emby.Server.Implementations/EntryPoints/AutomaticRestartEntryPoint.cs1
-rw-r--r--Emby.Server.Implementations/EntryPoints/ExternalPortForwarding.cs (renamed from Emby.Server.Core/EntryPoints/ExternalPortForwarding.cs)8
-rw-r--r--Emby.Server.Implementations/EntryPoints/KeepServerAwake.cs1
-rw-r--r--Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs11
-rw-r--r--Emby.Server.Implementations/EntryPoints/LoadRegistrations.cs1
-rw-r--r--Emby.Server.Implementations/EntryPoints/RecordingNotifier.cs1
-rw-r--r--Emby.Server.Implementations/EntryPoints/RefreshUsersMetadata.cs4
-rw-r--r--Emby.Server.Implementations/EntryPoints/ServerEventNotifier.cs1
-rw-r--r--Emby.Server.Implementations/EntryPoints/StartupWizard.cs4
-rw-r--r--Emby.Server.Implementations/EntryPoints/SystemEvents.cs1
-rw-r--r--Emby.Server.Implementations/EntryPoints/UdpServerEntryPoint.cs1
-rw-r--r--Emby.Server.Implementations/EntryPoints/UsageEntryPoint.cs4
-rw-r--r--Emby.Server.Implementations/EntryPoints/UserDataChangeNotifier.cs3
-rw-r--r--Emby.Server.Implementations/EnvironmentInfo/EnvironmentInfo.cs (renamed from Emby.Common.Implementations/EnvironmentInfo/EnvironmentInfo.cs)26
-rw-r--r--Emby.Server.Implementations/HttpClientManager/HttpClientInfo.cs (renamed from Emby.Common.Implementations/HttpClientManager/HttpClientInfo.cs)2
-rw-r--r--Emby.Server.Implementations/HttpClientManager/HttpClientManager.cs (renamed from Emby.Common.Implementations/HttpClientManager/HttpClientManager.cs)52
-rw-r--r--Emby.Server.Implementations/HttpServer/FileWriter.cs3
-rw-r--r--Emby.Server.Implementations/HttpServer/HttpListenerHost.cs155
-rw-r--r--Emby.Server.Implementations/HttpServer/HttpResultFactory.cs268
-rw-r--r--Emby.Server.Implementations/HttpServer/IHttpListener.cs4
-rw-r--r--Emby.Server.Implementations/HttpServer/LoggerUtils.cs19
-rw-r--r--Emby.Server.Implementations/HttpServer/Security/AuthService.cs36
-rw-r--r--Emby.Server.Implementations/HttpServer/Security/AuthorizationContext.cs15
-rw-r--r--Emby.Server.Implementations/HttpServer/Security/SessionContext.cs12
-rw-r--r--Emby.Server.Implementations/HttpServer/SocketSharp/HttpUtility.cs3
-rw-r--r--Emby.Server.Implementations/HttpServer/SocketSharp/SharpWebSocket.cs1
-rw-r--r--Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpListener.cs27
-rw-r--r--Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpRequest.cs40
-rw-r--r--Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpResponse.cs1
-rw-r--r--Emby.Server.Implementations/HttpServerFactory.cs (renamed from Emby.Server.Core/HttpServerFactory.cs)42
-rw-r--r--Emby.Server.Implementations/IO/FileRefresher.cs99
-rw-r--r--Emby.Server.Implementations/IO/IsoManager.cs (renamed from Emby.Common.Implementations/IO/IsoManager.cs)3
-rw-r--r--Emby.Server.Implementations/IO/LibraryMonitor.cs (renamed from Emby.Server.Core/IO/LibraryMonitor.cs)12
-rw-r--r--Emby.Server.Implementations/IO/ManagedFileSystem.cs (renamed from Emby.Common.Implementations/IO/ManagedFileSystem.cs)2
-rw-r--r--Emby.Server.Implementations/IO/MemoryStreamProvider.cs29
-rw-r--r--Emby.Server.Implementations/IO/ProgressStream.cs (renamed from Emby.Common.Implementations/IO/ProgressStream.cs)2
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Config.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Config.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Dcerpc/DcerpcBind.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Dcerpc/DcerpcBind.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Dcerpc/DcerpcBinding.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Dcerpc/DcerpcBinding.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Dcerpc/DcerpcConstants.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Dcerpc/DcerpcConstants.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Dcerpc/DcerpcError.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Dcerpc/DcerpcError.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Dcerpc/DcerpcException.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Dcerpc/DcerpcException.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Dcerpc/DcerpcHandle.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Dcerpc/DcerpcHandle.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Dcerpc/DcerpcMessage.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Dcerpc/DcerpcMessage.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Dcerpc/DcerpcPipeHandle.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Dcerpc/DcerpcPipeHandle.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Dcerpc/DcerpcSecurityProvider.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Dcerpc/DcerpcSecurityProvider.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Dcerpc/Msrpc/LsaPolicyHandle.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Dcerpc/Msrpc/LsaPolicyHandle.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Dcerpc/Msrpc/LsarSidArrayX.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Dcerpc/Msrpc/LsarSidArrayX.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Dcerpc/Msrpc/Lsarpc.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Dcerpc/Msrpc/Lsarpc.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Dcerpc/Msrpc/MsrpcDfsRootEnum.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Dcerpc/Msrpc/MsrpcDfsRootEnum.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Dcerpc/Msrpc/MsrpcEnumerateAliasesInDomain.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Dcerpc/Msrpc/MsrpcEnumerateAliasesInDomain.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Dcerpc/Msrpc/MsrpcGetMembersInAlias.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Dcerpc/Msrpc/MsrpcGetMembersInAlias.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Dcerpc/Msrpc/MsrpcLookupSids.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Dcerpc/Msrpc/MsrpcLookupSids.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Dcerpc/Msrpc/MsrpcLsarOpenPolicy2.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Dcerpc/Msrpc/MsrpcLsarOpenPolicy2.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Dcerpc/Msrpc/MsrpcQueryInformationPolicy.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Dcerpc/Msrpc/MsrpcQueryInformationPolicy.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Dcerpc/Msrpc/MsrpcSamrConnect2.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Dcerpc/Msrpc/MsrpcSamrConnect2.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Dcerpc/Msrpc/MsrpcSamrConnect4.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Dcerpc/Msrpc/MsrpcSamrConnect4.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Dcerpc/Msrpc/MsrpcSamrOpenAlias.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Dcerpc/Msrpc/MsrpcSamrOpenAlias.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Dcerpc/Msrpc/MsrpcSamrOpenDomain.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Dcerpc/Msrpc/MsrpcSamrOpenDomain.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Dcerpc/Msrpc/MsrpcShareEnum.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Dcerpc/Msrpc/MsrpcShareEnum.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Dcerpc/Msrpc/MsrpcShareGetInfo.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Dcerpc/Msrpc/MsrpcShareGetInfo.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Dcerpc/Msrpc/Netdfs.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Dcerpc/Msrpc/Netdfs.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Dcerpc/Msrpc/Samr.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Dcerpc/Msrpc/Samr.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Dcerpc/Msrpc/SamrAliasHandle.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Dcerpc/Msrpc/SamrAliasHandle.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Dcerpc/Msrpc/SamrDomainHandle.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Dcerpc/Msrpc/SamrDomainHandle.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Dcerpc/Msrpc/SamrPolicyHandle.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Dcerpc/Msrpc/SamrPolicyHandle.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Dcerpc/Msrpc/Srvsvc.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Dcerpc/Msrpc/Srvsvc.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Dcerpc/Ndr/NdrBuffer.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Dcerpc/Ndr/NdrBuffer.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Dcerpc/Ndr/NdrException.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Dcerpc/Ndr/NdrException.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Dcerpc/Ndr/NdrHyper.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Dcerpc/Ndr/NdrHyper.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Dcerpc/Ndr/NdrLong.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Dcerpc/Ndr/NdrLong.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Dcerpc/Ndr/NdrObject.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Dcerpc/Ndr/NdrObject.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Dcerpc/Ndr/NdrShort.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Dcerpc/Ndr/NdrShort.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Dcerpc/Ndr/NdrSmall.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Dcerpc/Ndr/NdrSmall.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Dcerpc/Rpc.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Dcerpc/Rpc.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Dcerpc/UUID.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Dcerpc/UUID.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Dcerpc/UnicodeString.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Dcerpc/UnicodeString.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Netbios/Lmhosts.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Netbios/Lmhosts.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Netbios/Name.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Netbios/Name.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Netbios/NameQueryRequest.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Netbios/NameQueryRequest.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Netbios/NameQueryResponse.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Netbios/NameQueryResponse.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Netbios/NameServiceClient.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Netbios/NameServiceClient.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Netbios/NameServicePacket.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Netbios/NameServicePacket.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Netbios/NbtAddress.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Netbios/NbtAddress.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Netbios/NbtException.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Netbios/NbtException.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Netbios/NodeStatusRequest.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Netbios/NodeStatusRequest.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Netbios/NodeStatusResponse.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Netbios/NodeStatusResponse.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Netbios/SessionRequestPacket.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Netbios/SessionRequestPacket.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Netbios/SessionRetargetResponsePacket.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Netbios/SessionRetargetResponsePacket.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Netbios/SessionServicePacket.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Netbios/SessionServicePacket.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Ntlmssp/NtlmFlags.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Ntlmssp/NtlmFlags.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Ntlmssp/NtlmMessage.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Ntlmssp/NtlmMessage.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Ntlmssp/Type1Message.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Ntlmssp/Type1Message.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Ntlmssp/Type2Message.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Ntlmssp/Type2Message.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Ntlmssp/Type3Message.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Ntlmssp/Type3Message.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Smb/ACE.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Smb/ACE.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Smb/AllocInfo.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Smb/AllocInfo.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Smb/AndXServerMessageBlock.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Smb/AndXServerMessageBlock.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Smb/BufferCache.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Smb/BufferCache.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Smb/Dfs.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Smb/Dfs.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Smb/DfsReferral.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Smb/DfsReferral.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Smb/DosError.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Smb/DosError.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Smb/DosFileFilter.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Smb/DosFileFilter.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Smb/FileEntry.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Smb/FileEntry.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Smb/IInfo.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Smb/IInfo.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Smb/NetServerEnum2.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Smb/NetServerEnum2.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Smb/NetServerEnum2Response.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Smb/NetServerEnum2Response.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Smb/NetShareEnum.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Smb/NetShareEnum.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Smb/NetShareEnumResponse.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Smb/NetShareEnumResponse.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Smb/NtStatus.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Smb/NtStatus.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Smb/NtTransQuerySecurityDesc.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Smb/NtTransQuerySecurityDesc.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Smb/NtTransQuerySecurityDescResponse.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Smb/NtTransQuerySecurityDescResponse.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Smb/NtlmAuthenticator.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Smb/NtlmAuthenticator.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Smb/NtlmChallenge.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Smb/NtlmChallenge.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Smb/NtlmContext.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Smb/NtlmContext.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Smb/NtlmPasswordAuthentication.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Smb/NtlmPasswordAuthentication.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Smb/Principal.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Smb/Principal.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Smb/SID.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Smb/SID.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Smb/SecurityDescriptor.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Smb/SecurityDescriptor.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Smb/ServerMessageBlock.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Smb/ServerMessageBlock.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Smb/SigningDigest.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Smb/SigningDigest.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Smb/SmbAuthException.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Smb/SmbAuthException.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Smb/SmbComBlankResponse.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Smb/SmbComBlankResponse.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Smb/SmbComClose.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Smb/SmbComClose.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Smb/SmbComCreateDirectory.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Smb/SmbComCreateDirectory.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Smb/SmbComDelete.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Smb/SmbComDelete.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Smb/SmbComDeleteDirectory.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Smb/SmbComDeleteDirectory.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Smb/SmbComFindClose2.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Smb/SmbComFindClose2.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Smb/SmbComLogoffAndX.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Smb/SmbComLogoffAndX.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Smb/SmbComNTCreateAndX.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Smb/SmbComNTCreateAndX.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Smb/SmbComNTCreateAndXResponse.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Smb/SmbComNTCreateAndXResponse.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Smb/SmbComNegotiate.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Smb/SmbComNegotiate.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Smb/SmbComNegotiateResponse.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Smb/SmbComNegotiateResponse.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Smb/SmbComNtTransaction.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Smb/SmbComNtTransaction.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Smb/SmbComNtTransactionResponse.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Smb/SmbComNtTransactionResponse.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Smb/SmbComOpenAndX.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Smb/SmbComOpenAndX.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Smb/SmbComOpenAndXResponse.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Smb/SmbComOpenAndXResponse.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Smb/SmbComQueryInformation.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Smb/SmbComQueryInformation.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Smb/SmbComQueryInformationResponse.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Smb/SmbComQueryInformationResponse.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Smb/SmbComReadAndX.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Smb/SmbComReadAndX.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Smb/SmbComReadAndXResponse.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Smb/SmbComReadAndXResponse.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Smb/SmbComRename.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Smb/SmbComRename.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Smb/SmbComSessionSetupAndX.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Smb/SmbComSessionSetupAndX.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Smb/SmbComSessionSetupAndXResponse.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Smb/SmbComSessionSetupAndXResponse.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Smb/SmbComTransaction.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Smb/SmbComTransaction.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Smb/SmbComTransactionResponse.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Smb/SmbComTransactionResponse.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Smb/SmbComTreeConnectAndX.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Smb/SmbComTreeConnectAndX.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Smb/SmbComTreeConnectAndXResponse.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Smb/SmbComTreeConnectAndXResponse.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Smb/SmbComTreeDisconnect.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Smb/SmbComTreeDisconnect.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Smb/SmbComWrite.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Smb/SmbComWrite.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Smb/SmbComWriteAndX.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Smb/SmbComWriteAndX.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Smb/SmbComWriteAndXResponse.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Smb/SmbComWriteAndXResponse.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Smb/SmbComWriteResponse.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Smb/SmbComWriteResponse.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Smb/SmbConstants.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Smb/SmbConstants.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Smb/SmbException.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Smb/SmbException.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Smb/SmbFile.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Smb/SmbFile.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Smb/SmbFileExtensions.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Smb/SmbFileExtensions.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Smb/SmbFileFilter.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Smb/SmbFileFilter.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Smb/SmbFileInputStream.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Smb/SmbFileInputStream.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Smb/SmbFileOutputStream.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Smb/SmbFileOutputStream.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Smb/SmbFilenameFilter.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Smb/SmbFilenameFilter.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Smb/SmbNamedPipe.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Smb/SmbNamedPipe.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Smb/SmbRandomAccessFile.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Smb/SmbRandomAccessFile.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Smb/SmbSession.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Smb/SmbSession.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Smb/SmbShareInfo.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Smb/SmbShareInfo.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Smb/SmbTransport.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Smb/SmbTransport.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Smb/SmbTree.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Smb/SmbTree.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Smb/Trans2FindFirst2.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Smb/Trans2FindFirst2.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Smb/Trans2FindFirst2Response.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Smb/Trans2FindFirst2Response.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Smb/Trans2FindNext2.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Smb/Trans2FindNext2.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Smb/Trans2GetDfsReferral.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Smb/Trans2GetDfsReferral.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Smb/Trans2GetDfsReferralResponse.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Smb/Trans2GetDfsReferralResponse.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Smb/Trans2QueryFSInformation.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Smb/Trans2QueryFSInformation.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Smb/Trans2QueryFSInformationResponse.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Smb/Trans2QueryFSInformationResponse.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Smb/Trans2QueryPathInformation.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Smb/Trans2QueryPathInformation.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Smb/Trans2QueryPathInformationResponse.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Smb/Trans2QueryPathInformationResponse.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Smb/Trans2SetFileInformation.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Smb/Trans2SetFileInformation.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Smb/Trans2SetFileInformationResponse.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Smb/Trans2SetFileInformationResponse.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Smb/TransCallNamedPipe.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Smb/TransCallNamedPipe.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Smb/TransCallNamedPipeResponse.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Smb/TransCallNamedPipeResponse.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Smb/TransPeekNamedPipe.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Smb/TransPeekNamedPipe.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Smb/TransPeekNamedPipeResponse.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Smb/TransPeekNamedPipeResponse.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Smb/TransTransactNamedPipe.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Smb/TransTransactNamedPipe.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Smb/TransTransactNamedPipeResponse.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Smb/TransTransactNamedPipeResponse.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Smb/TransWaitNamedPipe.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Smb/TransWaitNamedPipe.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Smb/TransWaitNamedPipeResponse.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Smb/TransWaitNamedPipeResponse.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Smb/TransactNamedPipeInputStream.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Smb/TransactNamedPipeInputStream.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Smb/TransactNamedPipeOutputStream.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Smb/TransactNamedPipeOutputStream.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Smb/WinError.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Smb/WinError.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/UniAddress.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/UniAddress.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Util/Base64.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Util/Base64.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Util/DES.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Util/DES.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Util/Encdec.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Util/Encdec.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Util/HMACT64.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Util/HMACT64.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Util/Hexdump.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Util/Hexdump.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Util/LogStream.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Util/LogStream.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Util/MD4.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Util/MD4.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Util/RC4.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Util/RC4.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/AbstractMap.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/AbstractMap.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/Arrays.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/Arrays.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/BufferedReader.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/BufferedReader.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/BufferedWriter.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/BufferedWriter.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/CharBuffer.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/CharBuffer.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/CharSequence.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/CharSequence.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/Collections.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/Collections.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/ConcurrentHashMap.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/ConcurrentHashMap.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/DateFormat.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/DateFormat.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/EnumeratorWrapper.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/EnumeratorWrapper.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/Exceptions.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/Exceptions.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/Extensions.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/Extensions.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/FileInputStream.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/FileInputStream.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/FileOutputStream.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/FileOutputStream.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/FilePath.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/FilePath.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/FileReader.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/FileReader.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/FileWriter.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/FileWriter.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/FilterInputStream.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/FilterInputStream.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/FilterOutputStream.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/FilterOutputStream.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/Hashtable.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/Hashtable.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/HttpURLConnection.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/HttpURLConnection.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/ICallable.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/ICallable.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/IConcurrentMap.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/IConcurrentMap.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/IExecutor.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/IExecutor.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/IFilenameFilter.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/IFilenameFilter.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/IFuture.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/IFuture.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/IPrivilegedAction.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/IPrivilegedAction.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/IRunnable.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/IRunnable.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/InputStream.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/InputStream.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/InputStreamReader.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/InputStreamReader.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/Iterator.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/Iterator.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/LinkageError.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/LinkageError.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/MD5.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/MD5.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/MD5Managed.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/MD5Managed.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/Matcher.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/Matcher.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/MessageDigest.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/MessageDigest.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/NetworkStream.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/NetworkStream.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/ObjectInputStream.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/ObjectInputStream.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/ObjectOutputStream.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/ObjectOutputStream.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/OutputStream.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/OutputStream.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/OutputStreamWriter.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/OutputStreamWriter.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/PipedInputStream.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/PipedInputStream.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/PipedOutputStream.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/PipedOutputStream.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/PrintWriter.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/PrintWriter.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/Properties.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/Properties.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/RandomAccessFile.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/RandomAccessFile.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/ReentrantLock.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/ReentrantLock.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/Reference.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/Reference.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/Runtime.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/Runtime.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/SimpleDateFormat.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/SimpleDateFormat.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/SocketEx.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/SocketEx.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/StringTokenizer.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/StringTokenizer.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/SynchronizedList.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/SynchronizedList.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/Thread.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/Thread.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/ThreadFactory.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/ThreadFactory.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/ThreadPoolExecutor.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/ThreadPoolExecutor.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/WrappedSystemStream.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/WrappedSystemStream.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Util/Transport/Request.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Util/Transport/Request.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Util/Transport/Response.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Util/Transport/Response.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Util/Transport/Transport.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Util/Transport/Transport.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Util/Transport/TransportException.cs (renamed from Emby.Common.Implementations/IO/SharpCifs/Util/Transport/TransportException.cs)0
-rw-r--r--Emby.Server.Implementations/IO/SharpCifsFileSystem.cs (renamed from Emby.Common.Implementations/IO/SharpCifsFileSystem.cs)7
-rw-r--r--Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs38
-rw-r--r--Emby.Server.Implementations/Library/LibraryManager.cs139
-rw-r--r--Emby.Server.Implementations/Library/LocalTrailerPostScanTask.cs7
-rw-r--r--Emby.Server.Implementations/Library/MediaSourceManager.cs16
-rw-r--r--Emby.Server.Implementations/Library/MusicManager.cs25
-rw-r--r--Emby.Server.Implementations/Library/Resolvers/BaseVideoResolver.cs12
-rw-r--r--Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs20
-rw-r--r--Emby.Server.Implementations/Library/Resolvers/PhotoResolver.cs2
-rw-r--r--Emby.Server.Implementations/Library/Resolvers/SpecialFolderResolver.cs2
-rw-r--r--Emby.Server.Implementations/Library/Resolvers/TV/EpisodeResolver.cs9
-rw-r--r--Emby.Server.Implementations/Library/Resolvers/TV/SeasonResolver.cs17
-rw-r--r--Emby.Server.Implementations/Library/Resolvers/VideoResolver.cs12
-rw-r--r--Emby.Server.Implementations/Library/SearchEngine.cs10
-rw-r--r--Emby.Server.Implementations/Library/UserDataManager.cs14
-rw-r--r--Emby.Server.Implementations/Library/UserManager.cs76
-rw-r--r--Emby.Server.Implementations/Library/UserViewManager.cs66
-rw-r--r--Emby.Server.Implementations/Library/Validators/PeopleValidator.cs17
-rw-r--r--Emby.Server.Implementations/LiveTv/ChannelImageProvider.cs6
-rw-r--r--Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs174
-rw-r--r--Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs9
-rw-r--r--Emby.Server.Implementations/LiveTv/EmbyTV/EntryPoint.cs4
-rw-r--r--Emby.Server.Implementations/LiveTv/EmbyTV/RecordingHelper.cs4
-rw-r--r--Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs31
-rw-r--r--Emby.Server.Implementations/LiveTv/LiveTvDtoService.cs59
-rw-r--r--Emby.Server.Implementations/LiveTv/LiveTvManager.cs316
-rw-r--r--Emby.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs28
-rw-r--r--Emby.Server.Implementations/LiveTv/RecordingImageProvider.cs6
-rw-r--r--Emby.Server.Implementations/LiveTv/RefreshChannelsScheduledTask.cs2
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs7
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunManager.cs1
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs148
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs32
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/MulticastStream.cs50
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/QueueStream.cs82
-rw-r--r--Emby.Server.Implementations/Localization/Core/core.json179
-rw-r--r--Emby.Server.Implementations/Localization/Core/en-US.json16
-rw-r--r--Emby.Server.Implementations/Localization/LocalizationManager.cs20
-rw-r--r--Emby.Server.Implementations/Localization/Ratings/es.txt1
-rw-r--r--Emby.Server.Implementations/Localization/Ratings/ro.txt1
-rw-r--r--Emby.Server.Implementations/Localization/Ratings/us.txt1
-rw-r--r--Emby.Server.Implementations/Localization/TextLocalizer.cs (renamed from Emby.Server.Core/Localization/TextLocalizer.cs)3
-rw-r--r--Emby.Server.Implementations/Logging/ConsoleLogger.cs (renamed from Emby.Server.Core/Logging/ConsoleLogger.cs)5
-rw-r--r--Emby.Server.Implementations/Logging/SimpleLogManager.cs301
-rw-r--r--Emby.Server.Implementations/MediaEncoder/EncodingManager.cs36
-rw-r--r--Emby.Server.Implementations/Net/DisposableManagedObjectBase.cs (renamed from Emby.Common.Implementations/Net/DisposableManagedObjectBase.cs)5
-rw-r--r--Emby.Server.Implementations/Net/NetAcceptSocket.cs98
-rw-r--r--Emby.Server.Implementations/Net/SocketFactory.cs (renamed from Emby.Common.Implementations/Net/SocketFactory.cs)30
-rw-r--r--Emby.Server.Implementations/Net/UdpSocket.cs (renamed from Emby.Common.Implementations/Net/UdpSocket.cs)7
-rw-r--r--Emby.Server.Implementations/Networking/NetworkManager.cs (renamed from Emby.Common.Implementations/Networking/NetworkManager.cs)12
-rw-r--r--Emby.Server.Implementations/News/NewsEntryPoint.cs1
-rw-r--r--Emby.Server.Implementations/Notifications/CoreNotificationTypes.cs32
-rw-r--r--Emby.Server.Implementations/Notifications/NotificationManager.cs2
-rw-r--r--Emby.Server.Implementations/Notifications/Notifications.cs5
-rw-r--r--Emby.Server.Implementations/Notifications/SqliteNotificationsRepository.cs13
-rw-r--r--Emby.Server.Implementations/Notifications/WebSocketNotifier.cs7
-rw-r--r--Emby.Server.Implementations/Photos/PhotoAlbumImageProvider.cs6
-rw-r--r--Emby.Server.Implementations/Playlists/ManualPlaylistsFolder.cs (renamed from MediaBrowser.Server.Implementations/Playlists/ManualPlaylistsFolder.cs)6
-rw-r--r--Emby.Server.Implementations/Playlists/PlaylistImageProvider.cs24
-rw-r--r--Emby.Server.Implementations/Playlists/PlaylistManager.cs27
-rw-r--r--Emby.Server.Implementations/Playlists/PlaylistsDynamicFolder.cs1
-rw-r--r--Emby.Server.Implementations/Reflection/AssemblyInfo.cs (renamed from Emby.Common.Implementations/Reflection/AssemblyInfo.cs)4
-rw-r--r--Emby.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs14
-rw-r--r--Emby.Server.Implementations/ScheduledTasks/DailyTrigger.cs (renamed from Emby.Common.Implementations/ScheduledTasks/DailyTrigger.cs)2
-rw-r--r--Emby.Server.Implementations/ScheduledTasks/IntervalTrigger.cs (renamed from Emby.Common.Implementations/ScheduledTasks/IntervalTrigger.cs)2
-rw-r--r--Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs (renamed from Emby.Common.Implementations/ScheduledTasks/ScheduledTaskWorker.cs)8
-rw-r--r--Emby.Server.Implementations/ScheduledTasks/StartupTrigger.cs (renamed from Emby.Common.Implementations/ScheduledTasks/StartupTrigger.cs)2
-rw-r--r--Emby.Server.Implementations/ScheduledTasks/SystemEventTrigger.cs (renamed from Emby.Common.Implementations/ScheduledTasks/SystemEventTrigger.cs)2
-rw-r--r--Emby.Server.Implementations/ScheduledTasks/TaskManager.cs (renamed from Emby.Common.Implementations/ScheduledTasks/TaskManager.cs)16
-rw-r--r--Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs (renamed from Emby.Common.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs)2
-rw-r--r--Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteLogFileTask.cs (renamed from Emby.Common.Implementations/ScheduledTasks/Tasks/DeleteLogFileTask.cs)2
-rw-r--r--Emby.Server.Implementations/ScheduledTasks/Tasks/ReloadLoggerFileTask.cs (renamed from Emby.Common.Implementations/ScheduledTasks/Tasks/ReloadLoggerFileTask.cs)2
-rw-r--r--Emby.Server.Implementations/ScheduledTasks/WeeklyTrigger.cs (renamed from Emby.Common.Implementations/ScheduledTasks/WeeklyTrigger.cs)2
-rw-r--r--Emby.Server.Implementations/Security/AuthenticationRepository.cs16
-rw-r--r--Emby.Server.Implementations/Serialization/JsonSerializer.cs (renamed from Emby.Common.Implementations/Serialization/JsonSerializer.cs)0
-rw-r--r--Emby.Server.Implementations/Serialization/XmlSerializer.cs (renamed from Emby.Common.Implementations/Serialization/XmlSerializer.cs)7
-rw-r--r--Emby.Server.Implementations/ServerApplicationPaths.cs4
-rw-r--r--Emby.Server.Implementations/ServerManager/ServerManager.cs4
-rw-r--r--Emby.Server.Implementations/ServerManager/WebSocketConnection.cs2
-rw-r--r--Emby.Server.Implementations/Services/HttpResult.cs9
-rw-r--r--Emby.Server.Implementations/Services/ResponseHelper.cs31
-rw-r--r--Emby.Server.Implementations/Services/ServiceController.cs57
-rw-r--r--Emby.Server.Implementations/Services/ServiceExec.cs36
-rw-r--r--Emby.Server.Implementations/Services/ServiceHandler.cs60
-rw-r--r--Emby.Server.Implementations/Services/ServiceMethod.cs7
-rw-r--r--Emby.Server.Implementations/Services/ServicePath.cs133
-rw-r--r--Emby.Server.Implementations/Services/StringMapTypeDeserializer.cs10
-rw-r--r--Emby.Server.Implementations/Session/HttpSessionController.cs6
-rw-r--r--Emby.Server.Implementations/Session/SessionManager.cs134
-rw-r--r--Emby.Server.Implementations/Session/SessionWebSocketListener.cs1
-rw-r--r--Emby.Server.Implementations/Session/WebSocketController.cs1
-rw-r--r--Emby.Server.Implementations/Social/SharingManager.cs8
-rw-r--r--Emby.Server.Implementations/Social/SharingRepository.cs9
-rw-r--r--Emby.Server.Implementations/Sorting/AirTimeComparer.cs71
-rw-r--r--Emby.Server.Implementations/Sorting/ArtistComparer.cs2
-rw-r--r--Emby.Server.Implementations/SystemEvents.cs (renamed from Emby.Server.Core/SystemEvents.cs)2
-rw-r--r--Emby.Server.Implementations/TV/SeriesPostScanTask.cs1
-rw-r--r--Emby.Server.Implementations/TV/TVSeriesManager.cs65
-rw-r--r--Emby.Server.Implementations/TextEncoding/NLangDetect/Detector.cs (renamed from Emby.Common.Implementations/TextEncoding/NLangDetect/Detector.cs)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/NLangDetect/DetectorFactory.cs (renamed from Emby.Common.Implementations/TextEncoding/NLangDetect/DetectorFactory.cs)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/NLangDetect/ErrorCode.cs (renamed from Emby.Common.Implementations/TextEncoding/NLangDetect/ErrorCode.cs)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/NLangDetect/Extensions/CharExtensions.cs (renamed from Emby.Common.Implementations/TextEncoding/NLangDetect/Extensions/CharExtensions.cs)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/NLangDetect/Extensions/RandomExtensions.cs (renamed from Emby.Common.Implementations/TextEncoding/NLangDetect/Extensions/RandomExtensions.cs)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/NLangDetect/Extensions/StringExtensions.cs (renamed from Emby.Common.Implementations/TextEncoding/NLangDetect/Extensions/StringExtensions.cs)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/NLangDetect/Extensions/UnicodeBlock.cs (renamed from Emby.Common.Implementations/TextEncoding/NLangDetect/Extensions/UnicodeBlock.cs)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/NLangDetect/GenProfile.cs (renamed from Emby.Common.Implementations/TextEncoding/NLangDetect/GenProfile.cs)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/NLangDetect/InternalException.cs (renamed from Emby.Common.Implementations/TextEncoding/NLangDetect/InternalException.cs)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/NLangDetect/Language.cs (renamed from Emby.Common.Implementations/TextEncoding/NLangDetect/Language.cs)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/NLangDetect/LanguageDetector.cs (renamed from Emby.Common.Implementations/TextEncoding/NLangDetect/LanguageDetector.cs)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/NLangDetect/NLangDetectException.cs (renamed from Emby.Common.Implementations/TextEncoding/NLangDetect/NLangDetectException.cs)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/NLangDetect/ProbVector.cs (renamed from Emby.Common.Implementations/TextEncoding/NLangDetect/ProbVector.cs)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/afr (renamed from Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/afr)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/ara (renamed from Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/ara)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/ben (renamed from Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/ben)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/bul (renamed from Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/bul)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/ces (renamed from Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/ces)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/dan (renamed from Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/dan)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/deu (renamed from Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/deu)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/ell (renamed from Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/ell)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/eng (renamed from Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/eng)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/est (renamed from Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/est)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/fas (renamed from Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/fas)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/fin (renamed from Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/fin)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/fra (renamed from Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/fra)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/guj (renamed from Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/guj)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/heb (renamed from Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/heb)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/hin (renamed from Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/hin)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/hrv (renamed from Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/hrv)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/hun (renamed from Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/hun)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/ind (renamed from Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/ind)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/ita (renamed from Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/ita)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/jpn (renamed from Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/jpn)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/kan (renamed from Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/kan)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/kor (renamed from Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/kor)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/lav (renamed from Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/lav)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/lit (renamed from Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/lit)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/mal (renamed from Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/mal)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/mar (renamed from Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/mar)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/mkd (renamed from Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/mkd)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/nep (renamed from Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/nep)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/nld (renamed from Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/nld)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/nor (renamed from Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/nor)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/pan (renamed from Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/pan)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/pol (renamed from Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/pol)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/por (renamed from Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/por)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/ron (renamed from Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/ron)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/rus (renamed from Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/rus)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/slk (renamed from Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/slk)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/slv (renamed from Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/slv)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/som (renamed from Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/som)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/spa (renamed from Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/spa)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/sqi (renamed from Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/sqi)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/swa (renamed from Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/swa)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/swe (renamed from Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/swe)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/tam (renamed from Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/tam)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/tel (renamed from Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/tel)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/tgl (renamed from Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/tgl)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/tha (renamed from Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/tha)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/tur (renamed from Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/tur)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/ukr (renamed from Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/ukr)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/urd (renamed from Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/urd)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/vie (renamed from Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/vie)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/zh-cn (renamed from Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/zh-cn)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/zh-tw (renamed from Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/zh-tw)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/NLangDetect/Utils/LangProfile.cs (renamed from Emby.Common.Implementations/TextEncoding/NLangDetect/Utils/LangProfile.cs)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/NLangDetect/Utils/Messages.cs (renamed from Emby.Common.Implementations/TextEncoding/NLangDetect/Utils/Messages.cs)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/NLangDetect/Utils/NGram.cs (renamed from Emby.Common.Implementations/TextEncoding/NLangDetect/Utils/NGram.cs)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/NLangDetect/Utils/TagExtractor.cs (renamed from Emby.Common.Implementations/TextEncoding/NLangDetect/Utils/TagExtractor.cs)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/NLangDetect/Utils/messages.properties (renamed from Emby.Common.Implementations/TextEncoding/NLangDetect/Utils/messages.properties)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/TextEncoding.cs (renamed from Emby.Common.Implementations/TextEncoding/TextEncoding.cs)73
-rw-r--r--Emby.Server.Implementations/TextEncoding/TextEncodingDetect.cs (renamed from Emby.Common.Implementations/TextEncoding/TextEncodingDetect.cs)7
-rw-r--r--Emby.Server.Implementations/TextEncoding/UniversalDetector/CharsetDetector.cs (renamed from Emby.Common.Implementations/TextEncoding/UniversalDetector/CharsetDetector.cs)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/UniversalDetector/Core/Big5Prober.cs (renamed from Emby.Common.Implementations/TextEncoding/UniversalDetector/Core/Big5Prober.cs)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/UniversalDetector/Core/BitPackage.cs (renamed from Emby.Common.Implementations/TextEncoding/UniversalDetector/Core/BitPackage.cs)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/UniversalDetector/Core/CharDistributionAnalyser.cs (renamed from Emby.Common.Implementations/TextEncoding/UniversalDetector/Core/CharDistributionAnalyser.cs)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/UniversalDetector/Core/CharsetProber.cs (renamed from Emby.Common.Implementations/TextEncoding/UniversalDetector/Core/CharsetProber.cs)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/UniversalDetector/Core/Charsets.cs (renamed from Emby.Common.Implementations/TextEncoding/UniversalDetector/Core/Charsets.cs)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/UniversalDetector/Core/CodingStateMachine.cs (renamed from Emby.Common.Implementations/TextEncoding/UniversalDetector/Core/CodingStateMachine.cs)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/UniversalDetector/Core/EUCJPProber.cs (renamed from Emby.Common.Implementations/TextEncoding/UniversalDetector/Core/EUCJPProber.cs)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/UniversalDetector/Core/EUCKRProber.cs (renamed from Emby.Common.Implementations/TextEncoding/UniversalDetector/Core/EUCKRProber.cs)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/UniversalDetector/Core/EUCTWProber.cs (renamed from Emby.Common.Implementations/TextEncoding/UniversalDetector/Core/EUCTWProber.cs)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/UniversalDetector/Core/EscCharsetProber.cs (renamed from Emby.Common.Implementations/TextEncoding/UniversalDetector/Core/EscCharsetProber.cs)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/UniversalDetector/Core/EscSM.cs (renamed from Emby.Common.Implementations/TextEncoding/UniversalDetector/Core/EscSM.cs)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/UniversalDetector/Core/GB18030Prober.cs (renamed from Emby.Common.Implementations/TextEncoding/UniversalDetector/Core/GB18030Prober.cs)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/UniversalDetector/Core/HebrewProber.cs (renamed from Emby.Common.Implementations/TextEncoding/UniversalDetector/Core/HebrewProber.cs)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/UniversalDetector/Core/JapaneseContextAnalyser.cs (renamed from Emby.Common.Implementations/TextEncoding/UniversalDetector/Core/JapaneseContextAnalyser.cs)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/UniversalDetector/Core/LangBulgarianModel.cs (renamed from Emby.Common.Implementations/TextEncoding/UniversalDetector/Core/LangBulgarianModel.cs)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/UniversalDetector/Core/LangCyrillicModel.cs (renamed from Emby.Common.Implementations/TextEncoding/UniversalDetector/Core/LangCyrillicModel.cs)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/UniversalDetector/Core/LangGreekModel.cs (renamed from Emby.Common.Implementations/TextEncoding/UniversalDetector/Core/LangGreekModel.cs)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/UniversalDetector/Core/LangHebrewModel.cs (renamed from Emby.Common.Implementations/TextEncoding/UniversalDetector/Core/LangHebrewModel.cs)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/UniversalDetector/Core/LangHungarianModel.cs (renamed from Emby.Common.Implementations/TextEncoding/UniversalDetector/Core/LangHungarianModel.cs)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/UniversalDetector/Core/LangThaiModel.cs (renamed from Emby.Common.Implementations/TextEncoding/UniversalDetector/Core/LangThaiModel.cs)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/UniversalDetector/Core/Latin1Prober.cs (renamed from Emby.Common.Implementations/TextEncoding/UniversalDetector/Core/Latin1Prober.cs)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/UniversalDetector/Core/MBCSGroupProber.cs (renamed from Emby.Common.Implementations/TextEncoding/UniversalDetector/Core/MBCSGroupProber.cs)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/UniversalDetector/Core/MBCSSM.cs (renamed from Emby.Common.Implementations/TextEncoding/UniversalDetector/Core/MBCSSM.cs)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/UniversalDetector/Core/SBCSGroupProber.cs (renamed from Emby.Common.Implementations/TextEncoding/UniversalDetector/Core/SBCSGroupProber.cs)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/UniversalDetector/Core/SBCharsetProber.cs (renamed from Emby.Common.Implementations/TextEncoding/UniversalDetector/Core/SBCharsetProber.cs)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/UniversalDetector/Core/SJISProber.cs (renamed from Emby.Common.Implementations/TextEncoding/UniversalDetector/Core/SJISProber.cs)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/UniversalDetector/Core/SMModel.cs (renamed from Emby.Common.Implementations/TextEncoding/UniversalDetector/Core/SMModel.cs)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/UniversalDetector/Core/SequenceModel.cs (renamed from Emby.Common.Implementations/TextEncoding/UniversalDetector/Core/SequenceModel.cs)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/UniversalDetector/Core/UTF8Prober.cs (renamed from Emby.Common.Implementations/TextEncoding/UniversalDetector/Core/UTF8Prober.cs)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/UniversalDetector/Core/UniversalDetector.cs (renamed from Emby.Common.Implementations/TextEncoding/UniversalDetector/Core/UniversalDetector.cs)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/UniversalDetector/DetectionConfidence.cs (renamed from Emby.Common.Implementations/TextEncoding/UniversalDetector/DetectionConfidence.cs)0
-rw-r--r--Emby.Server.Implementations/TextEncoding/UniversalDetector/ICharsetDetector.cs (renamed from Emby.Common.Implementations/TextEncoding/UniversalDetector/ICharsetDetector.cs)0
-rw-r--r--Emby.Server.Implementations/Threading/CommonTimer.cs (renamed from Emby.Common.Implementations/Threading/CommonTimer.cs)6
-rw-r--r--Emby.Server.Implementations/Threading/TimerFactory.cs (renamed from Emby.Common.Implementations/Threading/TimerFactory.cs)5
-rw-r--r--Emby.Server.Implementations/Updates/InstallationManager.cs131
-rw-r--r--Emby.Server.Implementations/UserViews/CollectionFolderImageProvider.cs26
-rw-r--r--Emby.Server.Implementations/UserViews/DynamicImageProvider.cs24
-rw-r--r--Emby.Server.Implementations/Xml/XmlReaderSettingsFactory.cs (renamed from Emby.Common.Implementations/Xml/XmlReaderSettingsFactory.cs)2
-rw-r--r--Emby.Server.Implementations/packages.config9
-rw-r--r--MediaBrowser.Api/ApiEntryPoint.cs752
-rw-r--r--MediaBrowser.Api/BaseApiService.cs24
-rw-r--r--MediaBrowser.Api/BasePeriodicWebSocketListener.cs1
-rw-r--r--MediaBrowser.Api/ChannelService.cs23
-rw-r--r--MediaBrowser.Api/ConfigurationService.cs5
-rw-r--r--MediaBrowser.Api/Devices/DeviceService.cs3
-rw-r--r--MediaBrowser.Api/DisplayPreferencesService.cs4
-rw-r--r--MediaBrowser.Api/Dlna/DlnaServerService.cs37
-rw-r--r--MediaBrowser.Api/Dlna/DlnaService.cs9
-rw-r--r--MediaBrowser.Api/EnvironmentService.cs11
-rw-r--r--MediaBrowser.Api/FilterService.cs6
-rw-r--r--MediaBrowser.Api/GamesService.cs73
-rw-r--r--MediaBrowser.Api/IHasItemFields.cs4
-rw-r--r--MediaBrowser.Api/Images/ImageService.cs42
-rw-r--r--MediaBrowser.Api/Images/RemoteImageService.cs10
-rw-r--r--MediaBrowser.Api/ItemUpdateService.cs38
-rw-r--r--MediaBrowser.Api/Library/LibraryService.cs47
-rw-r--r--MediaBrowser.Api/LiveTv/LiveTvService.cs42
-rw-r--r--MediaBrowser.Api/LiveTv/ProgressiveFileCopier.cs (renamed from MediaBrowser.Api/Playback/Progressive/ProgressiveStreamWriter.cs)107
-rw-r--r--MediaBrowser.Api/LocalizationService.cs17
-rw-r--r--MediaBrowser.Api/MediaBrowser.Api.csproj19
-rw-r--r--MediaBrowser.Api/Movies/CollectionService.cs9
-rw-r--r--MediaBrowser.Api/Movies/MoviesService.cs58
-rw-r--r--MediaBrowser.Api/Movies/TrailersService.cs3
-rw-r--r--MediaBrowser.Api/Music/AlbumsService.cs17
-rw-r--r--MediaBrowser.Api/Music/InstantMixService.cs33
-rw-r--r--MediaBrowser.Api/NotificationsService.cs2
-rw-r--r--MediaBrowser.Api/PackageReviewService.cs162
-rw-r--r--MediaBrowser.Api/PackageService.cs27
-rw-r--r--MediaBrowser.Api/Playback/BaseStreamingService.cs1024
-rw-r--r--MediaBrowser.Api/Playback/Hls/BaseHlsService.cs331
-rw-r--r--MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs970
-rw-r--r--MediaBrowser.Api/Playback/Hls/HlsSegmentService.cs163
-rw-r--r--MediaBrowser.Api/Playback/Hls/VideoHlsService.cs137
-rw-r--r--MediaBrowser.Api/Playback/MediaInfoService.cs591
-rw-r--r--MediaBrowser.Api/Playback/Progressive/AudioService.cs67
-rw-r--r--MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs429
-rw-r--r--MediaBrowser.Api/Playback/Progressive/VideoService.cs100
-rw-r--r--MediaBrowser.Api/Playback/StaticRemoteStreamWriter.cs47
-rw-r--r--MediaBrowser.Api/Playback/StreamRequest.cs63
-rw-r--r--MediaBrowser.Api/Playback/StreamState.cs259
-rw-r--r--MediaBrowser.Api/Playback/TranscodingThrottler.cs176
-rw-r--r--MediaBrowser.Api/Playback/UniversalAudioService.cs339
-rw-r--r--MediaBrowser.Api/PlaylistService.cs14
-rw-r--r--MediaBrowser.Api/PluginService.cs11
-rw-r--r--MediaBrowser.Api/Reports/Data/ReportBuilder.cs8
-rw-r--r--MediaBrowser.Api/Reports/ReportsService.cs10
-rw-r--r--MediaBrowser.Api/ScheduledTasks/ScheduledTaskService.cs4
-rw-r--r--MediaBrowser.Api/SearchService.cs15
-rw-r--r--MediaBrowser.Api/Session/SessionsService.cs17
-rw-r--r--MediaBrowser.Api/SimilarItemsHelper.cs15
-rw-r--r--MediaBrowser.Api/Social/SharingService.cs5
-rw-r--r--MediaBrowser.Api/StartupWizardService.cs3
-rw-r--r--MediaBrowser.Api/Subtitles/SubtitleService.cs6
-rw-r--r--MediaBrowser.Api/SuggestionsService.cs14
-rw-r--r--MediaBrowser.Api/System/SystemService.cs22
-rw-r--r--MediaBrowser.Api/TestService.cs77
-rw-r--r--MediaBrowser.Api/TvShowsService.cs105
-rw-r--r--MediaBrowser.Api/UserLibrary/ArtistsService.cs2
-rw-r--r--MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs33
-rw-r--r--MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs53
-rw-r--r--MediaBrowser.Api/UserLibrary/GameGenresService.cs2
-rw-r--r--MediaBrowser.Api/UserLibrary/GenresService.cs2
-rw-r--r--MediaBrowser.Api/UserLibrary/ItemsService.cs43
-rw-r--r--MediaBrowser.Api/UserLibrary/MusicGenresService.cs2
-rw-r--r--MediaBrowser.Api/UserLibrary/PersonsService.cs12
-rw-r--r--MediaBrowser.Api/UserLibrary/PlaystateService.cs451
-rw-r--r--MediaBrowser.Api/UserLibrary/StudiosService.cs6
-rw-r--r--MediaBrowser.Api/UserLibrary/UserLibraryService.cs57
-rw-r--r--MediaBrowser.Api/UserLibrary/UserViewsService.cs21
-rw-r--r--MediaBrowser.Api/UserLibrary/YearsService.cs6
-rw-r--r--MediaBrowser.Api/UserService.cs63
-rw-r--r--MediaBrowser.Api/VideosService.cs13
-rw-r--r--MediaBrowser.Common/Net/HttpResponseInfo.cs1
-rw-r--r--MediaBrowser.Common/Net/IHttpClient.cs2
-rw-r--r--MediaBrowser.Common/Plugins/BasePlugin.cs11
-rw-r--r--MediaBrowser.Common/Progress/ActionableProgress.cs1
-rw-r--r--MediaBrowser.Common/Updates/IInstallationManager.cs4
-rw-r--r--MediaBrowser.Controller/Channels/Channel.cs3
-rw-r--r--MediaBrowser.Controller/Channels/IChannelManager.cs2
-rw-r--r--MediaBrowser.Controller/Channels/InternalChannelFeatures.cs9
-rw-r--r--MediaBrowser.Controller/Chapters/IChapterManager.cs10
-rw-r--r--MediaBrowser.Controller/Collections/CollectionCreationOptions.cs8
-rw-r--r--MediaBrowser.Controller/Collections/ICollectionManager.cs5
-rw-r--r--MediaBrowser.Controller/Collections/ManualCollectionsFolder.cs1
-rw-r--r--MediaBrowser.Controller/Drawing/IImageEncoder.cs2
-rw-r--r--MediaBrowser.Controller/Drawing/IImageProcessor.cs10
-rw-r--r--MediaBrowser.Controller/Drawing/ImageHelper.cs2
-rw-r--r--MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs2
-rw-r--r--MediaBrowser.Controller/Drawing/ImageProcessorExtensions.cs4
-rw-r--r--MediaBrowser.Controller/Drawing/ImageStream.cs1
-rw-r--r--MediaBrowser.Controller/Dto/DtoOptions.cs24
-rw-r--r--MediaBrowser.Controller/Dto/IDtoService.cs16
-rw-r--r--MediaBrowser.Controller/Entities/AggregateFolder.cs51
-rw-r--r--MediaBrowser.Controller/Entities/Audio/Audio.cs50
-rw-r--r--MediaBrowser.Controller/Entities/Audio/IHasAlbumArtist.cs18
-rw-r--r--MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs66
-rw-r--r--MediaBrowser.Controller/Entities/Audio/MusicArtist.cs22
-rw-r--r--MediaBrowser.Controller/Entities/Audio/MusicGenre.cs1
-rw-r--r--MediaBrowser.Controller/Entities/BaseItem.cs256
-rw-r--r--MediaBrowser.Controller/Entities/Book.cs2
-rw-r--r--MediaBrowser.Controller/Entities/CollectionFolder.cs45
-rw-r--r--MediaBrowser.Controller/Entities/Extensions.cs23
-rw-r--r--MediaBrowser.Controller/Entities/Folder.cs129
-rw-r--r--MediaBrowser.Controller/Entities/Game.cs30
-rw-r--r--MediaBrowser.Controller/Entities/GameGenre.cs1
-rw-r--r--MediaBrowser.Controller/Entities/Genre.cs1
-rw-r--r--MediaBrowser.Controller/Entities/ICollectionFolder.cs2
-rw-r--r--MediaBrowser.Controller/Entities/IHasId.cs9
-rw-r--r--MediaBrowser.Controller/Entities/IHasImages.cs264
-rw-r--r--MediaBrowser.Controller/Entities/IHasMediaSources.cs6
-rw-r--r--MediaBrowser.Controller/Entities/IHasMetadata.cs257
-rw-r--r--MediaBrowser.Controller/Entities/IHasSpecialFeatures.cs3
-rw-r--r--MediaBrowser.Controller/Entities/IHasTrailers.cs6
-rw-r--r--MediaBrowser.Controller/Entities/IHasUserData.cs9
-rw-r--r--MediaBrowser.Controller/Entities/InternalItemsQuery.cs13
-rw-r--r--MediaBrowser.Controller/Entities/InternalPeopleQuery.cs4
-rw-r--r--MediaBrowser.Controller/Entities/Movies/BoxSet.cs74
-rw-r--r--MediaBrowser.Controller/Entities/Movies/Movie.cs33
-rw-r--r--MediaBrowser.Controller/Entities/MusicVideo.cs18
-rw-r--r--MediaBrowser.Controller/Entities/PeopleHelper.cs10
-rw-r--r--MediaBrowser.Controller/Entities/Person.cs1
-rw-r--r--MediaBrowser.Controller/Entities/Photo.cs12
-rw-r--r--MediaBrowser.Controller/Entities/Studio.cs1
-rw-r--r--MediaBrowser.Controller/Entities/TV/Episode.cs21
-rw-r--r--MediaBrowser.Controller/Entities/TV/Season.cs12
-rw-r--r--MediaBrowser.Controller/Entities/TV/Series.cs154
-rw-r--r--MediaBrowser.Controller/Entities/TagExtensions.cs18
-rw-r--r--MediaBrowser.Controller/Entities/Trailer.cs4
-rw-r--r--MediaBrowser.Controller/Entities/User.cs34
-rw-r--r--MediaBrowser.Controller/Entities/UserRootFolder.cs4
-rw-r--r--MediaBrowser.Controller/Entities/UserView.cs14
-rw-r--r--MediaBrowser.Controller/Entities/UserViewBuilder.cs59
-rw-r--r--MediaBrowser.Controller/Entities/Video.cs169
-rw-r--r--MediaBrowser.Controller/Entities/Year.cs1
-rw-r--r--MediaBrowser.Controller/IO/FileData.cs32
-rw-r--r--MediaBrowser.Controller/Library/ILibraryManager.cs36
-rw-r--r--MediaBrowser.Controller/Library/IMediaSourceManager.cs8
-rw-r--r--MediaBrowser.Controller/Library/IMusicManager.cs10
-rw-r--r--MediaBrowser.Controller/Library/IUserDataManager.cs9
-rw-r--r--MediaBrowser.Controller/Library/IUserManager.cs16
-rw-r--r--MediaBrowser.Controller/Library/IUserViewManager.cs2
-rw-r--r--MediaBrowser.Controller/Library/ItemResolveArgs.cs43
-rw-r--r--MediaBrowser.Controller/Library/NameExtensions.cs44
-rw-r--r--MediaBrowser.Controller/Library/TVUtils.cs8
-rw-r--r--MediaBrowser.Controller/LiveTv/ChannelInfo.cs2
-rw-r--r--MediaBrowser.Controller/LiveTv/ILiveTvManager.cs16
-rw-r--r--MediaBrowser.Controller/LiveTv/ILiveTvRecording.cs15
-rw-r--r--MediaBrowser.Controller/LiveTv/LiveTvAudioRecording.cs5
-rw-r--r--MediaBrowser.Controller/LiveTv/LiveTvChannel.cs7
-rw-r--r--MediaBrowser.Controller/LiveTv/LiveTvProgram.cs22
-rw-r--r--MediaBrowser.Controller/LiveTv/LiveTvVideoRecording.cs14
-rw-r--r--MediaBrowser.Controller/LiveTv/TimerInfo.cs3
-rw-r--r--MediaBrowser.Controller/MediaBrowser.Controller.csproj7
-rw-r--r--MediaBrowser.Controller/MediaEncoding/ChapterImageRefreshOptions.cs17
-rw-r--r--MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs169
-rw-r--r--MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs15
-rw-r--r--MediaBrowser.Controller/MediaEncoding/IEncodingManager.cs10
-rw-r--r--MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs28
-rw-r--r--MediaBrowser.Controller/MediaEncoding/JobLogger.cs149
-rw-r--r--MediaBrowser.Controller/MediaEncoding/MediaEncoderHelpers.cs21
-rw-r--r--MediaBrowser.Controller/MediaEncoding/MediaInfoRequest.cs4
-rw-r--r--MediaBrowser.Controller/Net/AuthenticatedAttribute.cs16
-rw-r--r--MediaBrowser.Controller/Net/IAuthService.cs6
-rw-r--r--MediaBrowser.Controller/Net/IAuthorizationContext.cs5
-rw-r--r--MediaBrowser.Controller/Net/IHttpServer.cs4
-rw-r--r--MediaBrowser.Controller/Net/IServerManager.cs2
-rw-r--r--MediaBrowser.Controller/Net/IServiceRequest.cs14
-rw-r--r--MediaBrowser.Controller/Net/ISessionContext.cs5
-rw-r--r--MediaBrowser.Controller/Net/LoggedAttribute.cs4
-rw-r--r--MediaBrowser.Controller/Net/ServiceRequest.cs42
-rw-r--r--MediaBrowser.Controller/Notifications/INotificationManager.cs2
-rw-r--r--MediaBrowser.Controller/Persistence/IDisplayPreferencesRepository.cs7
-rw-r--r--MediaBrowser.Controller/Persistence/IItemRepository.cs34
-rw-r--r--MediaBrowser.Controller/Persistence/IUserDataRepository.cs7
-rw-r--r--MediaBrowser.Controller/Persistence/IUserRepository.cs5
-rw-r--r--MediaBrowser.Controller/Playlists/Playlist.cs21
-rw-r--r--MediaBrowser.Controller/Providers/AlbumInfo.cs4
-rw-r--r--MediaBrowser.Controller/Providers/DirectoryService.cs71
-rw-r--r--MediaBrowser.Controller/Providers/EpisodeInfo.cs1
-rw-r--r--MediaBrowser.Controller/Providers/IDirectoryService.cs10
-rw-r--r--MediaBrowser.Controller/Providers/IDynamicImageProvider.cs4
-rw-r--r--MediaBrowser.Controller/Providers/IImageEnhancer.cs8
-rw-r--r--MediaBrowser.Controller/Providers/IImageProvider.cs2
-rw-r--r--MediaBrowser.Controller/Providers/ILocalImageFileProvider.cs2
-rw-r--r--MediaBrowser.Controller/Providers/IProviderManager.cs14
-rw-r--r--MediaBrowser.Controller/Providers/IRemoteImageProvider.cs4
-rw-r--r--MediaBrowser.Controller/Providers/ItemInfo.cs2
-rw-r--r--MediaBrowser.Controller/Providers/ItemLookupInfo.cs2
-rw-r--r--MediaBrowser.Controller/Providers/MetadataResult.cs11
-rw-r--r--MediaBrowser.Controller/Providers/SongInfo.cs9
-rw-r--r--MediaBrowser.Controller/Security/IAuthenticationRepository.cs5
-rw-r--r--MediaBrowser.Controller/Session/ISessionManager.cs6
-rw-r--r--MediaBrowser.Controller/Session/SessionInfo.cs28
-rw-r--r--MediaBrowser.Controller/Subtitles/ISubtitleManager.cs6
-rw-r--r--MediaBrowser.Controller/Sync/ISyncManager.cs33
-rw-r--r--MediaBrowser.Controller/Sync/ISyncProvider.cs4
-rw-r--r--MediaBrowser.Controller/Sync/ISyncRepository.cs80
-rw-r--r--MediaBrowser.LocalMetadata/Images/CollectionFolderImageProvider.cs4
-rw-r--r--MediaBrowser.LocalMetadata/Images/EpisodeLocalImageProvider.cs75
-rw-r--r--MediaBrowser.LocalMetadata/Images/ImagesByNameImageProvider.cs58
-rw-r--r--MediaBrowser.LocalMetadata/Images/InternalMetadataFolderImageProvider.cs4
-rw-r--r--MediaBrowser.LocalMetadata/Images/LocalImageProvider.cs114
-rw-r--r--MediaBrowser.LocalMetadata/MediaBrowser.LocalMetadata.csproj1
-rw-r--r--MediaBrowser.LocalMetadata/Parsers/BaseItemXmlParser.cs34
-rw-r--r--MediaBrowser.LocalMetadata/Parsers/BoxSetXmlParser.cs3
-rw-r--r--MediaBrowser.LocalMetadata/Parsers/PlaylistXmlParser.cs3
-rw-r--r--MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs18
-rw-r--r--MediaBrowser.LocalMetadata/Savers/GameXmlSaver.cs2
-rw-r--r--MediaBrowser.MediaEncoding/BdInfo/BdInfoExaminer.cs201
-rw-r--r--MediaBrowser.MediaEncoding/Configuration/EncodingConfigurationFactory.cs58
-rw-r--r--MediaBrowser.MediaEncoding/Encoder/AudioEncoder.cs62
-rw-r--r--MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs375
-rw-r--r--MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs219
-rw-r--r--MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs197
-rw-r--r--MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs305
-rw-r--r--MediaBrowser.MediaEncoding/Encoder/EncodingUtils.cs70
-rw-r--r--MediaBrowser.MediaEncoding/Encoder/FontConfigLoader.cs182
-rw-r--r--MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs1089
-rw-r--r--MediaBrowser.MediaEncoding/Encoder/VideoEncoder.cs66
-rw-r--r--MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj100
-rw-r--r--MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.nuget.targets6
-rw-r--r--MediaBrowser.MediaEncoding/Probing/FFProbeHelpers.cs117
-rw-r--r--MediaBrowser.MediaEncoding/Probing/InternalMediaInfoResult.cs341
-rw-r--r--MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs1372
-rw-r--r--MediaBrowser.MediaEncoding/Properties/AssemblyInfo.cs33
-rw-r--r--MediaBrowser.MediaEncoding/Subtitles/AssParser.cs120
-rw-r--r--MediaBrowser.MediaEncoding/Subtitles/ConfigurationExtension.cs29
-rw-r--r--MediaBrowser.MediaEncoding/Subtitles/ISubtitleParser.cs17
-rw-r--r--MediaBrowser.MediaEncoding/Subtitles/ISubtitleWriter.cs20
-rw-r--r--MediaBrowser.MediaEncoding/Subtitles/JsonWriter.cs28
-rw-r--r--MediaBrowser.MediaEncoding/Subtitles/OpenSubtitleDownloader.cs349
-rw-r--r--MediaBrowser.MediaEncoding/Subtitles/ParserValues.cs7
-rw-r--r--MediaBrowser.MediaEncoding/Subtitles/SrtParser.cs90
-rw-r--r--MediaBrowser.MediaEncoding/Subtitles/SrtWriter.cs39
-rw-r--r--MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs394
-rw-r--r--MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs738
-rw-r--r--MediaBrowser.MediaEncoding/Subtitles/TtmlWriter.cs60
-rw-r--r--MediaBrowser.MediaEncoding/Subtitles/VttWriter.cs44
-rw-r--r--MediaBrowser.MediaEncoding/packages.config3
-rw-r--r--MediaBrowser.Model/Activity/IActivityManager.cs3
-rw-r--r--MediaBrowser.Model/Activity/IActivityRepository.cs3
-rw-r--r--MediaBrowser.Model/ApiClient/ApiClientExtensions.cs48
-rw-r--r--MediaBrowser.Model/ApiClient/ApiHelpers.cs22
-rw-r--r--MediaBrowser.Model/ApiClient/ConnectionMode.cs9
-rw-r--r--MediaBrowser.Model/ApiClient/ConnectionOptions.cs29
-rw-r--r--MediaBrowser.Model/ApiClient/ConnectionResult.cs21
-rw-r--r--MediaBrowser.Model/ApiClient/ConnectionState.cs13
-rw-r--r--MediaBrowser.Model/ApiClient/IApiClient.cs1427
-rw-r--r--MediaBrowser.Model/ApiClient/IClientWebSocket.cs54
-rw-r--r--MediaBrowser.Model/ApiClient/IConnectionManager.cs192
-rw-r--r--MediaBrowser.Model/ApiClient/IDevice.cs44
-rw-r--r--MediaBrowser.Model/ApiClient/IServerEvents.cs152
-rw-r--r--MediaBrowser.Model/ApiClient/NetworkStatus.cs30
-rw-r--r--MediaBrowser.Model/ApiClient/RemoteLogoutReason.cs9
-rw-r--r--MediaBrowser.Model/ApiClient/ServerCredentials.cs131
-rw-r--r--MediaBrowser.Model/ApiClient/ServerInfo.cs127
-rw-r--r--MediaBrowser.Model/ApiClient/ServerUserInfo.cs9
-rw-r--r--MediaBrowser.Model/Channels/AllChannelMediaQuery.cs4
-rw-r--r--MediaBrowser.Model/Channels/ChannelFeatures.cs12
-rw-r--r--MediaBrowser.Model/Channels/ChannelItemQuery.cs9
-rw-r--r--MediaBrowser.Model/Configuration/EncodingOptions.cs7
-rw-r--r--MediaBrowser.Model/Configuration/MetadataOptions.cs3
-rw-r--r--MediaBrowser.Model/Configuration/MetadataPluginSummary.cs8
-rw-r--r--MediaBrowser.Model/Configuration/ServerConfiguration.cs9
-rw-r--r--MediaBrowser.Model/Configuration/UserConfiguration.cs1
-rw-r--r--MediaBrowser.Model/Devices/ContentUploadHistory.cs4
-rw-r--r--MediaBrowser.Model/Dlna/AudioOptions.cs2
-rw-r--r--MediaBrowser.Model/Dlna/CodecProfile.cs29
-rw-r--r--MediaBrowser.Model/Dlna/ConditionProcessor.cs1
-rw-r--r--MediaBrowser.Model/Dlna/ContainerProfile.cs49
-rw-r--r--MediaBrowser.Model/Dlna/DeviceProfile.cs56
-rw-r--r--MediaBrowser.Model/Dlna/DirectPlayProfile.cs39
-rw-r--r--MediaBrowser.Model/Dlna/ITranscoderSupport.cs5
-rw-r--r--MediaBrowser.Model/Dlna/MediaFormatProfileResolver.cs60
-rw-r--r--MediaBrowser.Model/Dlna/ResolutionNormalizer.cs10
-rw-r--r--MediaBrowser.Model/Dlna/ResponseProfile.cs27
-rw-r--r--MediaBrowser.Model/Dlna/StreamBuilder.cs164
-rw-r--r--MediaBrowser.Model/Dlna/StreamInfo.cs32
-rw-r--r--MediaBrowser.Model/Dlna/StreamInfoSorter.cs4
-rw-r--r--MediaBrowser.Model/Dlna/SubtitleProfile.cs13
-rw-r--r--MediaBrowser.Model/Dlna/TranscodingProfile.cs9
-rw-r--r--MediaBrowser.Model/Dto/BaseItemDto.cs112
-rw-r--r--MediaBrowser.Model/Dto/GameSystemSummary.cs4
-rw-r--r--MediaBrowser.Model/Dto/ItemLayout.cs72
-rw-r--r--MediaBrowser.Model/Dto/MediaSourceInfo.cs26
-rw-r--r--MediaBrowser.Model/Dto/MetadataEditorInfo.cs20
-rw-r--r--MediaBrowser.Model/Dto/StudioDto.cs29
-rw-r--r--MediaBrowser.Model/Entities/LibraryUpdateInfo.cs23
-rw-r--r--MediaBrowser.Model/Entities/MediaStream.cs4
-rw-r--r--MediaBrowser.Model/Entities/VideoType.cs6
-rw-r--r--MediaBrowser.Model/Entities/VirtualFolderInfo.cs4
-rw-r--r--MediaBrowser.Model/Extensions/LinqExtensions.cs13
-rw-r--r--MediaBrowser.Model/Extensions/ListHelper.cs18
-rw-r--r--MediaBrowser.Model/Globalization/ILocalizationManager.cs8
-rw-r--r--MediaBrowser.Model/Health/IHealthMonitor.cs12
-rw-r--r--MediaBrowser.Model/LiveTv/BaseTimerInfoDto.cs2
-rw-r--r--MediaBrowser.Model/LiveTv/ChannelInfoDto.cs4
-rw-r--r--MediaBrowser.Model/LiveTv/LiveTvInfo.cs8
-rw-r--r--MediaBrowser.Model/LiveTv/LiveTvOptions.cs13
-rw-r--r--MediaBrowser.Model/LiveTv/LiveTvServiceInfo.cs4
-rw-r--r--MediaBrowser.Model/LiveTv/LiveTvTunerInfoDto.cs4
-rw-r--r--MediaBrowser.Model/LiveTv/ProgramQuery.cs14
-rw-r--r--MediaBrowser.Model/LiveTv/SeriesTimerInfoDto.cs14
-rw-r--r--MediaBrowser.Model/Logging/ILogManager.cs6
-rw-r--r--MediaBrowser.Model/MediaBrowser.Model.csproj22
-rw-r--r--MediaBrowser.Model/MediaInfo/BlurayDiscInfo.cs6
-rw-r--r--MediaBrowser.Model/MediaInfo/MediaInfo.cs26
-rw-r--r--MediaBrowser.Model/MediaInfo/PlaybackInfoResponse.cs4
-rw-r--r--MediaBrowser.Model/MediaInfo/SubtitleTrackInfo.cs4
-rw-r--r--MediaBrowser.Model/Net/HttpResponse.cs1
-rw-r--r--MediaBrowser.Model/Net/IAcceptSocket.cs3
-rw-r--r--MediaBrowser.Model/Net/ISocket.cs1
-rw-r--r--MediaBrowser.Model/Net/MimeTypes.cs20
-rw-r--r--MediaBrowser.Model/Notifications/NotificationTypeInfo.cs4
-rw-r--r--MediaBrowser.Model/Playlists/PlaylistCreationRequest.cs4
-rw-r--r--MediaBrowser.Model/Providers/ImageProviderInfo.cs4
-rw-r--r--MediaBrowser.Model/Providers/RemoteImageResult.cs4
-rw-r--r--MediaBrowser.Model/Querying/ItemFields.cs13
-rw-r--r--MediaBrowser.Model/Querying/ItemQuery.cs332
-rw-r--r--MediaBrowser.Model/Querying/ItemsResult.cs11
-rw-r--r--MediaBrowser.Model/Querying/QueryResult.cs3
-rw-r--r--MediaBrowser.Model/Querying/SeasonQuery.cs22
-rw-r--r--MediaBrowser.Model/Querying/ThemeMediaResult.cs5
-rw-r--r--MediaBrowser.Model/Search/SearchHint.cs6
-rw-r--r--MediaBrowser.Model/Services/IHttpRequest.cs1
-rw-r--r--MediaBrowser.Model/Services/IHttpResponse.cs1
-rw-r--r--MediaBrowser.Model/Services/IHttpResult.cs1
-rw-r--r--MediaBrowser.Model/Services/IRequest.cs5
-rw-r--r--MediaBrowser.Model/Services/QueryParamCollection.cs70
-rw-r--r--MediaBrowser.Model/Session/ClientCapabilities.cs12
-rw-r--r--MediaBrowser.Model/Session/PlaybackProgressInfo.cs2
-rw-r--r--MediaBrowser.Model/Session/SessionInfoDto.cs12
-rw-r--r--MediaBrowser.Model/Session/TranscodingInfo.cs4
-rw-r--r--MediaBrowser.Model/Session/UserDataChangeInfo.cs2
-rw-r--r--MediaBrowser.Model/Social/ISharingManager.cs2
-rw-r--r--MediaBrowser.Model/Social/ISharingRepository.cs11
-rw-r--r--MediaBrowser.Model/Sync/CompleteSyncJobInfo.cs4
-rw-r--r--MediaBrowser.Model/Sync/LocalItem.cs8
-rw-r--r--MediaBrowser.Model/Sync/SyncDataRequest.cs11
-rw-r--r--MediaBrowser.Model/Sync/SyncDataResponse.cs9
-rw-r--r--MediaBrowser.Model/Sync/SyncDialogOptions.cs16
-rw-r--r--MediaBrowser.Model/Sync/SyncJob.cs7
-rw-r--r--MediaBrowser.Model/Sync/SyncJobCreationResult.cs4
-rw-r--r--MediaBrowser.Model/Sync/SyncJobItem.cs9
-rw-r--r--MediaBrowser.Model/Sync/SyncJobItemStatus.cs4
-rw-r--r--MediaBrowser.Model/Sync/SyncJobRequest.cs4
-rw-r--r--MediaBrowser.Model/Sync/SyncJobStatus.cs3
-rw-r--r--MediaBrowser.Model/Sync/SyncedItem.cs4
-rw-r--r--MediaBrowser.Model/System/SystemInfo.cs12
-rw-r--r--MediaBrowser.Model/Tasks/ScheduledTaskHelpers.cs12
-rw-r--r--MediaBrowser.Model/Tasks/TaskInfo.cs4
-rw-r--r--MediaBrowser.Model/Text/ITextEncoding.cs4
-rw-r--r--MediaBrowser.Model/Updates/PackageInfo.cs4
-rw-r--r--MediaBrowser.Model/Updates/PackageVersionInfo.cs2
-rw-r--r--MediaBrowser.Model/Users/UserPolicy.cs2
-rw-r--r--MediaBrowser.Providers/Books/AudioBookMetadataService.cs6
-rw-r--r--MediaBrowser.Providers/Books/AudioPodcastMetadataService.cs6
-rw-r--r--MediaBrowser.Providers/Books/BookMetadataService.cs2
-rw-r--r--MediaBrowser.Providers/BoxSets/BoxSetMetadataService.cs13
-rw-r--r--MediaBrowser.Providers/BoxSets/MovieDbBoxSetImageProvider.cs12
-rw-r--r--MediaBrowser.Providers/Channels/ChannelMetadataService.cs2
-rw-r--r--MediaBrowser.Providers/Chapters/ChapterManager.cs7
-rw-r--r--MediaBrowser.Providers/Folders/CollectionFolderMetadataService.cs4
-rw-r--r--MediaBrowser.Providers/Folders/FolderMetadataService.cs2
-rw-r--r--MediaBrowser.Providers/Folders/UserViewMetadataService.cs2
-rw-r--r--MediaBrowser.Providers/GameGenres/GameGenreMetadataService.cs2
-rw-r--r--MediaBrowser.Providers/Games/GameMetadataService.cs2
-rw-r--r--MediaBrowser.Providers/Games/GameSystemMetadataService.cs2
-rw-r--r--MediaBrowser.Providers/Genres/GenreMetadataService.cs2
-rw-r--r--MediaBrowser.Providers/ImagesByName/ImageUtils.cs2
-rw-r--r--MediaBrowser.Providers/LiveTv/AudioRecordingService.cs2
-rw-r--r--MediaBrowser.Providers/LiveTv/ChannelMetadataService.cs2
-rw-r--r--MediaBrowser.Providers/LiveTv/ProgramMetadataService.cs2
-rw-r--r--MediaBrowser.Providers/LiveTv/VideoRecordingService.cs2
-rw-r--r--MediaBrowser.Providers/Manager/GenericPriorityQueue.cs1
-rw-r--r--MediaBrowser.Providers/Manager/GenericPriorityQueueNode.cs1
-rw-r--r--MediaBrowser.Providers/Manager/IFixedSizePriorityQueue.cs1
-rw-r--r--MediaBrowser.Providers/Manager/IPriorityQueue.cs1
-rw-r--r--MediaBrowser.Providers/Manager/ImageSaver.cs29
-rw-r--r--MediaBrowser.Providers/Manager/ItemImageProvider.cs38
-rw-r--r--MediaBrowser.Providers/Manager/MetadataService.cs26
-rw-r--r--MediaBrowser.Providers/Manager/ProviderManager.cs48
-rw-r--r--MediaBrowser.Providers/Manager/ProviderUtils.cs34
-rw-r--r--MediaBrowser.Providers/Manager/SimplePriorityQueue.cs1
-rw-r--r--MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs13
-rw-r--r--MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs26
-rw-r--r--MediaBrowser.Providers/MediaInfo/FFProbeProvider.cs5
-rw-r--r--MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs197
-rw-r--r--MediaBrowser.Providers/MediaInfo/SubtitleDownloader.cs5
-rw-r--r--MediaBrowser.Providers/MediaInfo/SubtitleResolver.cs2
-rw-r--r--MediaBrowser.Providers/MediaInfo/SubtitleScheduledTask.cs3
-rw-r--r--MediaBrowser.Providers/MediaInfo/VideoImageProvider.cs146
-rw-r--r--MediaBrowser.Providers/Movies/FanartMovieImageProvider.cs6
-rw-r--r--MediaBrowser.Providers/Movies/GenericMovieDbInfo.cs11
-rw-r--r--MediaBrowser.Providers/Movies/MovieDbImageProvider.cs12
-rw-r--r--MediaBrowser.Providers/Movies/MovieDbProvider.cs18
-rw-r--r--MediaBrowser.Providers/Movies/MovieMetadataService.cs4
-rw-r--r--MediaBrowser.Providers/Music/AlbumImageFromSongProvider.cs6
-rw-r--r--MediaBrowser.Providers/Music/AlbumMetadataService.cs14
-rw-r--r--MediaBrowser.Providers/Music/ArtistMetadataService.cs6
-rw-r--r--MediaBrowser.Providers/Music/AudioDbAlbumImageProvider.cs6
-rw-r--r--MediaBrowser.Providers/Music/AudioDbAlbumProvider.cs2
-rw-r--r--MediaBrowser.Providers/Music/AudioDbArtistImageProvider.cs6
-rw-r--r--MediaBrowser.Providers/Music/AudioMetadataService.cs7
-rw-r--r--MediaBrowser.Providers/Music/FanArtAlbumProvider.cs6
-rw-r--r--MediaBrowser.Providers/Music/FanArtArtistProvider.cs6
-rw-r--r--MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs2
-rw-r--r--MediaBrowser.Providers/Music/MusicBrainzArtistProvider.cs6
-rw-r--r--MediaBrowser.Providers/Music/MusicVideoMetadataService.cs7
-rw-r--r--MediaBrowser.Providers/MusicGenres/MusicGenreMetadataService.cs2
-rw-r--r--MediaBrowser.Providers/Omdb/OmdbImageProvider.cs6
-rw-r--r--MediaBrowser.Providers/Omdb/OmdbProvider.cs2
-rw-r--r--MediaBrowser.Providers/People/MovieDbPersonImageProvider.cs9
-rw-r--r--MediaBrowser.Providers/People/MovieDbPersonProvider.cs2
-rw-r--r--MediaBrowser.Providers/People/PersonMetadataService.cs2
-rw-r--r--MediaBrowser.Providers/People/TvdbPersonImageProvider.cs6
-rw-r--r--MediaBrowser.Providers/Photos/PhotoAlbumMetadataService.cs2
-rw-r--r--MediaBrowser.Providers/Photos/PhotoMetadataService.cs2
-rw-r--r--MediaBrowser.Providers/Playlists/PlaylistMetadataService.cs9
-rw-r--r--MediaBrowser.Providers/Studios/StudioMetadataService.cs2
-rw-r--r--MediaBrowser.Providers/Studios/StudiosImageProvider.cs10
-rw-r--r--MediaBrowser.Providers/Subtitles/SubtitleManager.cs39
-rw-r--r--MediaBrowser.Providers/TV/DummySeasonProvider.cs6
-rw-r--r--MediaBrowser.Providers/TV/EpisodeMetadataService.cs2
-rw-r--r--MediaBrowser.Providers/TV/FanArt/FanArtSeasonProvider.cs6
-rw-r--r--MediaBrowser.Providers/TV/FanArt/FanartSeriesProvider.cs6
-rw-r--r--MediaBrowser.Providers/TV/MissingEpisodeProvider.cs17
-rw-r--r--MediaBrowser.Providers/TV/Omdb/OmdbEpisodeProvider.cs2
-rw-r--r--MediaBrowser.Providers/TV/SeasonMetadataService.cs10
-rw-r--r--MediaBrowser.Providers/TV/SeriesMetadataService.cs4
-rw-r--r--MediaBrowser.Providers/TV/TheMovieDb/MovieDbEpisodeImageProvider.cs9
-rw-r--r--MediaBrowser.Providers/TV/TheMovieDb/MovieDbEpisodeProvider.cs4
-rw-r--r--MediaBrowser.Providers/TV/TheMovieDb/MovieDbSeriesImageProvider.cs12
-rw-r--r--MediaBrowser.Providers/TV/TheMovieDb/MovieDbSeriesProvider.cs5
-rw-r--r--MediaBrowser.Providers/TV/TheTVDB/TvdbEpisodeImageProvider.cs6
-rw-r--r--MediaBrowser.Providers/TV/TheTVDB/TvdbPrescanTask.cs7
-rw-r--r--MediaBrowser.Providers/TV/TheTVDB/TvdbSeasonImageProvider.cs9
-rw-r--r--MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesImageProvider.cs9
-rw-r--r--MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesProvider.cs49
-rw-r--r--MediaBrowser.Providers/TV/TvExternalIds.cs23
-rw-r--r--MediaBrowser.Providers/Users/UserMetadataService.cs2
-rw-r--r--MediaBrowser.Providers/Videos/VideoMetadataService.cs2
-rw-r--r--MediaBrowser.Providers/Years/YearMetadataService.cs2
-rw-r--r--MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj69
-rw-r--r--MediaBrowser.Server.Implementations/Properties/AssemblyInfo.cs30
-rw-r--r--MediaBrowser.Server.Implementations/app.config11
-rw-r--r--MediaBrowser.Server.Mac.sln136
-rw-r--r--MediaBrowser.Server.Mac/Emby.Server.Mac.csproj166
-rw-r--r--MediaBrowser.Server.Mac/MacAppHost.cs4
-rw-r--r--MediaBrowser.Server.Mac/Main.cs59
-rw-r--r--MediaBrowser.Server.Mac/Native/MonoFileSystem.cs2
-rw-r--r--MediaBrowser.Server.Mono/ApplicationPathHelper.cs (renamed from Emby.Server.Core/ApplicationPathHelper.cs)2
-rw-r--r--MediaBrowser.Server.Mono/MediaBrowser.Server.Mono.csproj30
-rw-r--r--MediaBrowser.Server.Mono/MonoAppHost.cs6
-rw-r--r--MediaBrowser.Server.Mono/Native/MonoFileSystem.cs2
-rw-r--r--MediaBrowser.Server.Mono/Program.cs117
-rw-r--r--MediaBrowser.Server.Mono/packages.config7
-rw-r--r--MediaBrowser.ServerApplication/ApplicationPathHelper.cs51
-rw-r--r--MediaBrowser.ServerApplication/ImageEncoderHelper.cs1
-rw-r--r--MediaBrowser.ServerApplication/MainStartup.cs176
-rw-r--r--MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj48
-rw-r--r--MediaBrowser.ServerApplication/Native/LnkShortcutHandler.cs (renamed from Emby.Common.Implementations/IO/LnkShortcutHandler.cs)3
-rw-r--r--MediaBrowser.ServerApplication/Native/LoopUtil.cs1
-rw-r--r--MediaBrowser.ServerApplication/Networking/NetworkManager.cs2
-rw-r--r--MediaBrowser.ServerApplication/WindowsAppHost.cs7
-rw-r--r--MediaBrowser.ServerApplication/packages.config7
-rw-r--r--MediaBrowser.ServerApplication/x64/libSkiaSharp.dll.REMOVED.git-id1
-rw-r--r--MediaBrowser.Tests/M3uParserTest.cs2
-rw-r--r--MediaBrowser.Tests/MediaBrowser.Tests.csproj37
-rw-r--r--MediaBrowser.Tests/MediaEncoding/Subtitles/AssParserTests.cs7
-rw-r--r--MediaBrowser.Tests/MediaEncoding/Subtitles/SrtParserTests.cs8
-rw-r--r--MediaBrowser.Tests/MediaEncoding/Subtitles/VttWriterTest.cs4
-rw-r--r--MediaBrowser.WebDashboard/Api/PackageCreator.cs5
-rw-r--r--MediaBrowser.XbmcMetadata/EntryPoint.cs4
-rw-r--r--MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs36
-rw-r--r--MediaBrowser.XbmcMetadata/Parsers/MovieNfoParser.cs16
-rw-r--r--MediaBrowser.XbmcMetadata/Parsers/SeriesNfoParser.cs22
-rw-r--r--MediaBrowser.XbmcMetadata/Savers/AlbumNfoSaver.cs5
-rw-r--r--MediaBrowser.XbmcMetadata/Savers/ArtistNfoSaver.cs7
-rw-r--r--MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs26
-rw-r--r--MediaBrowser.XbmcMetadata/Savers/MovieNfoSaver.cs6
-rw-r--r--MediaBrowser.XbmcMetadata/Savers/SeriesNfoSaver.cs18
-rw-r--r--MediaBrowser.sln157
-rw-r--r--Mono.Nat/NatUtility.cs7
-rw-r--r--Mono.Nat/Pmp/PmpNatDevice.cs3
-rw-r--r--Mono.Nat/Pmp/Searchers/PmpSearcher.cs1
-rw-r--r--Mono.Nat/Upnp/Upnp.cs1
-rw-r--r--Nuget/MediaBrowser.Common.Internal.nuspec24
-rw-r--r--Nuget/MediaBrowser.Common.nuspec2
-rw-r--r--Nuget/MediaBrowser.Server.Core.nuspec4
-rw-r--r--RSSDP/CustomHttpHeaders.cs1
-rw-r--r--RSSDP/DeviceAvailableEventArgs.cs1
-rw-r--r--RSSDP/DeviceEventArgs.cs1
-rw-r--r--RSSDP/DeviceUnavailableEventArgs.cs1
-rw-r--r--RSSDP/DiscoveredSsdpDevice.cs1
-rw-r--r--RSSDP/DisposableManagedObjectBase.cs1
-rw-r--r--RSSDP/IUPnPDeviceValidator.cs4
-rw-r--r--RSSDP/RequestReceivedEventArgs.cs1
-rw-r--r--RSSDP/ResponseReceivedEventArgs.cs1
-rw-r--r--RSSDP/SsdpCommunicationsServer.cs2
-rw-r--r--RSSDP/SsdpConstants.cs1
-rw-r--r--RSSDP/SsdpDevice.cs7
-rw-r--r--RSSDP/SsdpDeviceExtensions.cs1
-rw-r--r--RSSDP/SsdpDeviceIcon.cs1
-rw-r--r--RSSDP/SsdpDeviceLocator.cs1
-rw-r--r--RSSDP/SsdpDeviceLocatorBase.cs37
-rw-r--r--RSSDP/SsdpDeviceProperties.cs1
-rw-r--r--RSSDP/SsdpDeviceProperty.cs1
-rw-r--r--RSSDP/SsdpDevicePublisher.cs1
-rw-r--r--RSSDP/SsdpEmbeddedDevice.cs1
-rw-r--r--RSSDP/SsdpRootDevice.cs1
-rw-r--r--RSSDP/UPnP10DeviceValidator.cs10
-rw-r--r--SharedVersion.cs2
-rw-r--r--SocketHttpListener/Net/BoundaryType.cs1
-rw-r--r--SocketHttpListener/Net/CookieHelper.cs1
-rw-r--r--SocketHttpListener/Net/EndPointListener.cs67
-rw-r--r--SocketHttpListener/Net/EndPointManager.cs25
-rw-r--r--SocketHttpListener/Net/EntitySendFormat.cs1
-rw-r--r--SocketHttpListener/Net/HttpConnection.cs38
-rw-r--r--SocketHttpListener/Net/HttpListener.cs20
-rw-r--r--SocketHttpListener/Net/HttpListenerRequest.cs19
-rw-r--r--SocketHttpListener/Net/HttpListenerResponse.Managed.cs1
-rw-r--r--SocketHttpListener/Net/HttpListenerResponse.cs1
-rw-r--r--SocketHttpListener/Net/HttpRequestStream.Managed.cs1
-rw-r--r--SocketHttpListener/Net/HttpRequestStream.cs1
-rw-r--r--SocketHttpListener/Net/HttpResponseStream.Managed.cs22
-rw-r--r--SocketHttpListener/Net/HttpResponseStream.cs1
-rw-r--r--SocketHttpListener/Net/HttpStatusDescription.cs1
-rw-r--r--SocketHttpListener/Net/ListenerPrefix.cs4
-rw-r--r--SocketHttpListener/Net/SocketAcceptor.cs (renamed from Emby.Common.Implementations/Net/SocketAcceptor.cs)11
-rw-r--r--SocketHttpListener/Net/UriScheme.cs1
-rw-r--r--SocketHttpListener/Net/WebHeaderCollection.cs13
-rw-r--r--SocketHttpListener/Net/WebHeaderEncoding.cs1
-rw-r--r--SocketHttpListener/Net/WebSockets/HttpListenerWebSocketContext.cs4
-rw-r--r--SocketHttpListener/Net/WebSockets/WebSocketContext.cs4
-rw-r--r--SocketHttpListener/Primitives/ICertificate.cs12
-rw-r--r--SocketHttpListener/Primitives/IStreamFactory.cs18
-rw-r--r--SocketHttpListener/Primitives/ITextEncoding.cs1
-rw-r--r--SocketHttpListener/SocketHttpListener.csproj4
-rw-r--r--SocketHttpListener/SocketStream.cs86
-rw-r--r--SocketHttpListener/WebSocket.cs1
1097 files changed, 8651 insertions, 26714 deletions
diff --git a/Emby.Common.Implementations/BaseApplicationHost.cs b/Emby.Common.Implementations/BaseApplicationHost.cs
deleted file mode 100644
index e7710162c..000000000
--- a/Emby.Common.Implementations/BaseApplicationHost.cs
+++ /dev/null
@@ -1,902 +0,0 @@
-using MediaBrowser.Common.Configuration;
-using MediaBrowser.Common.Events;
-using Emby.Common.Implementations.Devices;
-using Emby.Common.Implementations.IO;
-using Emby.Common.Implementations.ScheduledTasks;
-using Emby.Common.Implementations.Serialization;
-using MediaBrowser.Common.Net;
-using MediaBrowser.Common.Plugins;
-using MediaBrowser.Common.Progress;
-using MediaBrowser.Common.Security;
-using MediaBrowser.Common.Updates;
-using MediaBrowser.Model.Events;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Model.Logging;
-using MediaBrowser.Model.Serialization;
-using MediaBrowser.Model.Updates;
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Net;
-using System.Reflection;
-using System.Runtime.InteropServices;
-using System.Text;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Common.Extensions;
-using Emby.Common.Implementations.Cryptography;
-using Emby.Common.Implementations.Diagnostics;
-using Emby.Common.Implementations.Net;
-using Emby.Common.Implementations.EnvironmentInfo;
-using Emby.Common.Implementations.Threading;
-using MediaBrowser.Common;
-using MediaBrowser.Model.Cryptography;
-using MediaBrowser.Model.Diagnostics;
-using MediaBrowser.Model.Net;
-using MediaBrowser.Model.System;
-using MediaBrowser.Model.Tasks;
-using MediaBrowser.Model.Threading;
-
-namespace Emby.Common.Implementations
-{
- /// <summary>
- /// Class BaseApplicationHost
- /// </summary>
- /// <typeparam name="TApplicationPathsType">The type of the T application paths type.</typeparam>
- public abstract class BaseApplicationHost<TApplicationPathsType> : IApplicationHost
- where TApplicationPathsType : class, IApplicationPaths
- {
- /// <summary>
- /// Occurs when [has pending restart changed].
- /// </summary>
- public event EventHandler HasPendingRestartChanged;
-
- /// <summary>
- /// Occurs when [application updated].
- /// </summary>
- public event EventHandler<GenericEventArgs<PackageVersionInfo>> ApplicationUpdated;
-
- /// <summary>
- /// Gets or sets a value indicating whether this instance has changes that require the entire application to restart.
- /// </summary>
- /// <value><c>true</c> if this instance has pending application restart; otherwise, <c>false</c>.</value>
- public bool HasPendingRestart { get; private set; }
-
- /// <summary>
- /// Gets or sets the logger.
- /// </summary>
- /// <value>The logger.</value>
- protected ILogger Logger { get; private set; }
-
- /// <summary>
- /// Gets or sets the plugins.
- /// </summary>
- /// <value>The plugins.</value>
- public IPlugin[] Plugins { get; protected set; }
-
- /// <summary>
- /// Gets or sets the log manager.
- /// </summary>
- /// <value>The log manager.</value>
- public ILogManager LogManager { get; protected set; }
-
- /// <summary>
- /// Gets the application paths.
- /// </summary>
- /// <value>The application paths.</value>
- protected TApplicationPathsType ApplicationPaths { get; private set; }
-
- /// <summary>
- /// The json serializer
- /// </summary>
- public IJsonSerializer JsonSerializer { get; private set; }
-
- /// <summary>
- /// The _XML serializer
- /// </summary>
- protected readonly IXmlSerializer XmlSerializer;
-
- /// <summary>
- /// Gets assemblies that failed to load
- /// </summary>
- /// <value>The failed assemblies.</value>
- public List<string> FailedAssemblies { get; protected set; }
-
- /// <summary>
- /// Gets all concrete types.
- /// </summary>
- /// <value>All concrete types.</value>
- public Type[] AllConcreteTypes { get; protected set; }
-
- /// <summary>
- /// The disposable parts
- /// </summary>
- protected readonly List<IDisposable> DisposableParts = new List<IDisposable>();
-
- /// <summary>
- /// Gets a value indicating whether this instance is first run.
- /// </summary>
- /// <value><c>true</c> if this instance is first run; otherwise, <c>false</c>.</value>
- public bool IsFirstRun { get; private set; }
-
- /// <summary>
- /// Gets the kernel.
- /// </summary>
- /// <value>The kernel.</value>
- protected ITaskManager TaskManager { get; private set; }
- /// <summary>
- /// Gets the HTTP client.
- /// </summary>
- /// <value>The HTTP client.</value>
- public IHttpClient HttpClient { get; private set; }
- /// <summary>
- /// Gets the network manager.
- /// </summary>
- /// <value>The network manager.</value>
- protected INetworkManager NetworkManager { get; private set; }
-
- /// <summary>
- /// Gets the configuration manager.
- /// </summary>
- /// <value>The configuration manager.</value>
- protected IConfigurationManager ConfigurationManager { get; private set; }
-
- public IFileSystem FileSystemManager { get; private set; }
-
- protected IIsoManager IsoManager { get; private set; }
-
- protected IProcessFactory ProcessFactory { get; private set; }
- protected ITimerFactory TimerFactory { get; private set; }
- protected ISocketFactory SocketFactory { get; private set; }
-
- /// <summary>
- /// Gets the name.
- /// </summary>
- /// <value>The name.</value>
- public abstract string Name { get; }
-
- protected ICryptoProvider CryptographyProvider = new CryptographyProvider();
-
- protected IEnvironmentInfo EnvironmentInfo { get; private set; }
-
- private DeviceId _deviceId;
- public string SystemId
- {
- get
- {
- if (_deviceId == null)
- {
- _deviceId = new DeviceId(ApplicationPaths, LogManager.GetLogger("SystemId"), FileSystemManager);
- }
-
- return _deviceId.Value;
- }
- }
-
- public PackageVersionClass SystemUpdateLevel
- {
- get
- {
-
-#if BETA
- return PackageVersionClass.Beta;
-#endif
- return PackageVersionClass.Release;
- }
- }
-
- public virtual string OperatingSystemDisplayName
- {
- get { return EnvironmentInfo.OperatingSystemName; }
- }
-
- /// <summary>
- /// The container
- /// </summary>
- protected readonly SimpleInjector.Container Container = new SimpleInjector.Container();
-
- protected ISystemEvents SystemEvents { get; private set; }
- protected IMemoryStreamFactory MemoryStreamFactory { get; private set; }
-
- /// <summary>
- /// Initializes a new instance of the <see cref="BaseApplicationHost{TApplicationPathsType}"/> class.
- /// </summary>
- protected BaseApplicationHost(TApplicationPathsType applicationPaths,
- ILogManager logManager,
- IFileSystem fileSystem,
- IEnvironmentInfo environmentInfo,
- ISystemEvents systemEvents,
- IMemoryStreamFactory memoryStreamFactory,
- INetworkManager networkManager)
- {
- NetworkManager = networkManager;
- EnvironmentInfo = environmentInfo;
- SystemEvents = systemEvents;
- MemoryStreamFactory = memoryStreamFactory;
-
- // hack alert, until common can target .net core
- BaseExtensions.CryptographyProvider = CryptographyProvider;
-
- XmlSerializer = new MyXmlSerializer(fileSystem, logManager.GetLogger("XmlSerializer"));
- FailedAssemblies = new List<string>();
-
- ApplicationPaths = applicationPaths;
- LogManager = logManager;
- FileSystemManager = fileSystem;
-
- ConfigurationManager = GetConfigurationManager();
-
- // Initialize this early in case the -v command line option is used
- Logger = LogManager.GetLogger("App");
- }
-
- /// <summary>
- /// Inits this instance.
- /// </summary>
- /// <returns>Task.</returns>
- public virtual async Task Init(IProgress<double> progress)
- {
- progress.Report(1);
-
- JsonSerializer = CreateJsonSerializer();
-
- OnLoggerLoaded(true);
- LogManager.LoggerLoaded += (s, e) => OnLoggerLoaded(false);
-
- IsFirstRun = !ConfigurationManager.CommonConfiguration.IsStartupWizardCompleted;
- progress.Report(2);
-
- LogManager.LogSeverity = ConfigurationManager.CommonConfiguration.EnableDebugLevelLogging
- ? LogSeverity.Debug
- : LogSeverity.Info;
-
- progress.Report(3);
-
- DiscoverTypes();
- progress.Report(14);
-
- SetHttpLimit();
- progress.Report(15);
-
- var innerProgress = new ActionableProgress<double>();
- innerProgress.RegisterAction(p => progress.Report(.8 * p + 15));
-
- await RegisterResources(innerProgress).ConfigureAwait(false);
-
- FindParts();
- progress.Report(95);
-
- await InstallIsoMounters(CancellationToken.None).ConfigureAwait(false);
-
- progress.Report(100);
- }
-
- protected virtual void OnLoggerLoaded(bool isFirstLoad)
- {
- Logger.Info("Application version: {0}", ApplicationVersion);
-
- if (!isFirstLoad)
- {
- LogEnvironmentInfo(Logger, ApplicationPaths, false);
- }
-
- // Put the app config in the log for troubleshooting purposes
- Logger.LogMultiline("Application configuration:", LogSeverity.Info, new StringBuilder(JsonSerializer.SerializeToString(ConfigurationManager.CommonConfiguration)));
-
- if (Plugins != null)
- {
- var pluginBuilder = new StringBuilder();
-
- foreach (var plugin in Plugins)
- {
- pluginBuilder.AppendLine(string.Format("{0} {1}", plugin.Name, plugin.Version));
- }
-
- Logger.LogMultiline("Plugins:", LogSeverity.Info, pluginBuilder);
- }
- }
-
- public static void LogEnvironmentInfo(ILogger logger, IApplicationPaths appPaths, bool isStartup)
- {
- logger.LogMultiline("Emby", LogSeverity.Info, GetBaseExceptionMessage(appPaths));
- }
-
- protected static StringBuilder GetBaseExceptionMessage(IApplicationPaths appPaths)
- {
- var builder = new StringBuilder();
-
- builder.AppendLine(string.Format("Command line: {0}", string.Join(" ", Environment.GetCommandLineArgs())));
-
- builder.AppendLine(string.Format("Operating system: {0}", Environment.OSVersion));
- builder.AppendLine(string.Format("64-Bit OS: {0}", Environment.Is64BitOperatingSystem));
- builder.AppendLine(string.Format("64-Bit Process: {0}", Environment.Is64BitProcess));
-
- Type type = Type.GetType("Mono.Runtime");
- if (type != null)
- {
- MethodInfo displayName = type.GetMethod("GetDisplayName", BindingFlags.NonPublic | BindingFlags.Static);
- if (displayName != null)
- {
- builder.AppendLine("Mono: " + displayName.Invoke(null, null));
- }
- }
-
- builder.AppendLine(string.Format("Processor count: {0}", Environment.ProcessorCount));
- builder.AppendLine(string.Format("Program data path: {0}", appPaths.ProgramDataPath));
- builder.AppendLine(string.Format("Application directory: {0}", appPaths.ProgramSystemPath));
-
- return builder;
- }
-
- protected abstract IJsonSerializer CreateJsonSerializer();
-
- private void SetHttpLimit()
- {
- try
- {
- // Increase the max http request limit
- ServicePointManager.DefaultConnectionLimit = Math.Max(96, ServicePointManager.DefaultConnectionLimit);
- }
- catch (Exception ex)
- {
- Logger.ErrorException("Error setting http limit", ex);
- }
- }
-
- /// <summary>
- /// Installs the iso mounters.
- /// </summary>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- private async Task InstallIsoMounters(CancellationToken cancellationToken)
- {
- var list = new List<IIsoMounter>();
-
- foreach (var isoMounter in GetExports<IIsoMounter>())
- {
- try
- {
- if (isoMounter.RequiresInstallation && !isoMounter.IsInstalled)
- {
- Logger.Info("Installing {0}", isoMounter.Name);
-
- await isoMounter.Install(cancellationToken).ConfigureAwait(false);
- }
-
- list.Add(isoMounter);
- }
- catch (Exception ex)
- {
- Logger.ErrorException("{0} failed to load.", ex, isoMounter.Name);
- }
- }
-
- IsoManager.AddParts(list);
- }
-
- /// <summary>
- /// Runs the startup tasks.
- /// </summary>
- /// <returns>Task.</returns>
- public virtual Task RunStartupTasks()
- {
- Resolve<ITaskManager>().AddTasks(GetExports<IScheduledTask>(false));
-
- ConfigureAutorun();
-
- ConfigurationManager.ConfigurationUpdated += OnConfigurationUpdated;
-
- return Task.FromResult(true);
- }
-
- /// <summary>
- /// Configures the autorun.
- /// </summary>
- private void ConfigureAutorun()
- {
- try
- {
- ConfigureAutoRunAtStartup(ConfigurationManager.CommonConfiguration.RunAtStartup);
- }
- catch (Exception ex)
- {
- Logger.ErrorException("Error configuring autorun", ex);
- }
- }
-
- /// <summary>
- /// Gets the composable part assemblies.
- /// </summary>
- /// <returns>IEnumerable{Assembly}.</returns>
- protected abstract IEnumerable<Assembly> GetComposablePartAssemblies();
-
- /// <summary>
- /// Gets the configuration manager.
- /// </summary>
- /// <returns>IConfigurationManager.</returns>
- protected abstract IConfigurationManager GetConfigurationManager();
-
- /// <summary>
- /// Finds the parts.
- /// </summary>
- protected virtual void FindParts()
- {
- ConfigurationManager.AddParts(GetExports<IConfigurationFactory>());
- Plugins = GetExports<IPlugin>().Select(LoadPlugin).Where(i => i != null).ToArray();
- }
-
- private IPlugin LoadPlugin(IPlugin plugin)
- {
- try
- {
- var assemblyPlugin = plugin as IPluginAssembly;
-
- if (assemblyPlugin != null)
- {
- var assembly = plugin.GetType().Assembly;
- var assemblyName = assembly.GetName();
-
- var attribute = (GuidAttribute)assembly.GetCustomAttributes(typeof(GuidAttribute), true)[0];
- var assemblyId = new Guid(attribute.Value);
-
- var assemblyFileName = assemblyName.Name + ".dll";
- var assemblyFilePath = Path.Combine(ApplicationPaths.PluginsPath, assemblyFileName);
-
- assemblyPlugin.SetAttributes(assemblyFilePath, assemblyFileName, assemblyName.Version, assemblyId);
- }
-
- var isFirstRun = !File.Exists(plugin.ConfigurationFilePath);
- plugin.SetStartupInfo(isFirstRun, File.GetLastWriteTimeUtc, s => Directory.CreateDirectory(s));
- }
- catch (Exception ex)
- {
- Logger.ErrorException("Error loading plugin {0}", ex, plugin.GetType().FullName);
- return null;
- }
-
- return plugin;
- }
-
- /// <summary>
- /// Discovers the types.
- /// </summary>
- protected void DiscoverTypes()
- {
- FailedAssemblies.Clear();
-
- var assemblies = GetComposablePartAssemblies().ToList();
-
- foreach (var assembly in assemblies)
- {
- Logger.Info("Loading {0}", assembly.FullName);
- }
-
- AllConcreteTypes = assemblies
- .SelectMany(GetTypes)
- .Where(t => t.IsClass && !t.IsAbstract && !t.IsInterface && !t.IsGenericType)
- .ToArray();
- }
-
- /// <summary>
- /// Registers resources that classes will depend on
- /// </summary>
- /// <returns>Task.</returns>
- protected virtual Task RegisterResources(IProgress<double> progress)
- {
- RegisterSingleInstance(ConfigurationManager);
- RegisterSingleInstance<IApplicationHost>(this);
-
- RegisterSingleInstance<IApplicationPaths>(ApplicationPaths);
-
- TaskManager = new TaskManager(ApplicationPaths, JsonSerializer, LogManager.GetLogger("TaskManager"), FileSystemManager, SystemEvents);
-
- RegisterSingleInstance(JsonSerializer);
- RegisterSingleInstance(XmlSerializer);
- RegisterSingleInstance(MemoryStreamFactory);
- RegisterSingleInstance(SystemEvents);
-
- RegisterSingleInstance(LogManager);
- RegisterSingleInstance(Logger);
-
- RegisterSingleInstance(TaskManager);
- RegisterSingleInstance(EnvironmentInfo);
-
- RegisterSingleInstance(FileSystemManager);
-
- HttpClient = new HttpClientManager.HttpClientManager(ApplicationPaths, LogManager.GetLogger("HttpClient"), FileSystemManager, MemoryStreamFactory, GetDefaultUserAgent);
- RegisterSingleInstance(HttpClient);
-
- RegisterSingleInstance(NetworkManager);
-
- IsoManager = new IsoManager();
- RegisterSingleInstance(IsoManager);
-
- ProcessFactory = new ProcessFactory();
- RegisterSingleInstance(ProcessFactory);
-
- TimerFactory = new TimerFactory();
- RegisterSingleInstance(TimerFactory);
-
- SocketFactory = new SocketFactory(LogManager.GetLogger("SocketFactory"));
- RegisterSingleInstance(SocketFactory);
-
- RegisterSingleInstance(CryptographyProvider);
-
- return Task.FromResult(true);
- }
-
- private string GetDefaultUserAgent()
- {
- var name = FormatAttribute(Name);
-
- return name + "/" + ApplicationVersion.ToString();
- }
-
- private string FormatAttribute(string str)
- {
- var arr = str.ToCharArray();
-
- arr = Array.FindAll<char>(arr, (c => (char.IsLetterOrDigit(c)
- || char.IsWhiteSpace(c))));
-
- var result = new string(arr);
-
- if (string.IsNullOrWhiteSpace(result))
- {
- result = "Emby";
- }
-
- return result;
- }
-
- /// <summary>
- /// Gets a list of types within an assembly
- /// This will handle situations that would normally throw an exception - such as a type within the assembly that depends on some other non-existant reference
- /// </summary>
- /// <param name="assembly">The assembly.</param>
- /// <returns>IEnumerable{Type}.</returns>
- /// <exception cref="System.ArgumentNullException">assembly</exception>
- protected List<Type> GetTypes(Assembly assembly)
- {
- if (assembly == null)
- {
- return new List<Type>();
- }
-
- try
- {
- // This null checking really shouldn't be needed but adding it due to some
- // unhandled exceptions in mono 5.0 that are a little hard to hunt down
- var types = assembly.GetTypes() ?? new Type[] { };
- return types.Where(t => t != null).ToList();
- }
- catch (ReflectionTypeLoadException ex)
- {
- if (ex.LoaderExceptions != null)
- {
- foreach (var loaderException in ex.LoaderExceptions)
- {
- if (loaderException != null)
- {
- Logger.Error("LoaderException: " + loaderException.Message);
- }
- }
- }
-
- // If it fails we can still get a list of the Types it was able to resolve
- var types = ex.Types ?? new Type[] { };
- return types.Where(t => t != null).ToList();
- }
- catch (Exception ex)
- {
- Logger.ErrorException("Error loading types from assembly", ex);
-
- return new List<Type>();
- }
- }
-
- /// <summary>
- /// Creates an instance of type and resolves all constructor dependancies
- /// </summary>
- /// <param name="type">The type.</param>
- /// <returns>System.Object.</returns>
- public object CreateInstance(Type type)
- {
- try
- {
- return Container.GetInstance(type);
- }
- catch (Exception ex)
- {
- Logger.ErrorException("Error creating {0}", ex, type.FullName);
-
- throw;
- }
- }
-
- /// <summary>
- /// Creates the instance safe.
- /// </summary>
- /// <param name="type">The type.</param>
- /// <returns>System.Object.</returns>
- protected object CreateInstanceSafe(Type type)
- {
- try
- {
- return Container.GetInstance(type);
- }
- catch (Exception ex)
- {
- Logger.ErrorException("Error creating {0}", ex, type.FullName);
- // Don't blow up in release mode
- return null;
- }
- }
-
- /// <summary>
- /// Registers the specified obj.
- /// </summary>
- /// <typeparam name="T"></typeparam>
- /// <param name="obj">The obj.</param>
- /// <param name="manageLifetime">if set to <c>true</c> [manage lifetime].</param>
- protected void RegisterSingleInstance<T>(T obj, bool manageLifetime = true)
- where T : class
- {
- Container.RegisterSingleton(obj);
-
- if (manageLifetime)
- {
- var disposable = obj as IDisposable;
-
- if (disposable != null)
- {
- DisposableParts.Add(disposable);
- }
- }
- }
-
- /// <summary>
- /// Registers the single instance.
- /// </summary>
- /// <typeparam name="T"></typeparam>
- /// <param name="func">The func.</param>
- protected void RegisterSingleInstance<T>(Func<T> func)
- where T : class
- {
- Container.RegisterSingleton(func);
- }
-
- /// <summary>
- /// Resolves this instance.
- /// </summary>
- /// <typeparam name="T"></typeparam>
- /// <returns>``0.</returns>
- public T Resolve<T>()
- {
- return (T)Container.GetRegistration(typeof(T), true).GetInstance();
- }
-
- /// <summary>
- /// Resolves this instance.
- /// </summary>
- /// <typeparam name="T"></typeparam>
- /// <returns>``0.</returns>
- public T TryResolve<T>()
- {
- var result = Container.GetRegistration(typeof(T), false);
-
- if (result == null)
- {
- return default(T);
- }
- return (T)result.GetInstance();
- }
-
- /// <summary>
- /// Loads the assembly.
- /// </summary>
- /// <param name="file">The file.</param>
- /// <returns>Assembly.</returns>
- protected Assembly LoadAssembly(string file)
- {
- try
- {
- return Assembly.Load(File.ReadAllBytes(file));
- }
- catch (Exception ex)
- {
- FailedAssemblies.Add(file);
- Logger.ErrorException("Error loading assembly {0}", ex, file);
- return null;
- }
- }
-
- /// <summary>
- /// Gets the export types.
- /// </summary>
- /// <typeparam name="T"></typeparam>
- /// <returns>IEnumerable{Type}.</returns>
- public IEnumerable<Type> GetExportTypes<T>()
- {
- var currentType = typeof(T);
-
- return AllConcreteTypes.Where(currentType.IsAssignableFrom);
- }
-
- /// <summary>
- /// Gets the exports.
- /// </summary>
- /// <typeparam name="T"></typeparam>
- /// <param name="manageLiftime">if set to <c>true</c> [manage liftime].</param>
- /// <returns>IEnumerable{``0}.</returns>
- public IEnumerable<T> GetExports<T>(bool manageLiftime = true)
- {
- var parts = GetExportTypes<T>()
- .Select(CreateInstanceSafe)
- .Where(i => i != null)
- .Cast<T>()
- .ToList();
-
- if (manageLiftime)
- {
- lock (DisposableParts)
- {
- DisposableParts.AddRange(parts.OfType<IDisposable>());
- }
- }
-
- return parts;
- }
-
- /// <summary>
- /// Gets the application version.
- /// </summary>
- /// <value>The application version.</value>
- public abstract Version ApplicationVersion { get; }
-
- /// <summary>
- /// Handles the ConfigurationUpdated event of the ConfigurationManager control.
- /// </summary>
- /// <param name="sender">The source of the event.</param>
- /// <param name="e">The <see cref="EventArgs" /> instance containing the event data.</param>
- /// <exception cref="System.NotImplementedException"></exception>
- protected virtual void OnConfigurationUpdated(object sender, EventArgs e)
- {
- ConfigureAutorun();
- }
-
- protected abstract void ConfigureAutoRunAtStartup(bool autorun);
-
- /// <summary>
- /// Removes the plugin.
- /// </summary>
- /// <param name="plugin">The plugin.</param>
- public void RemovePlugin(IPlugin plugin)
- {
- var list = Plugins.ToList();
- list.Remove(plugin);
- Plugins = list.ToArray();
- }
-
- /// <summary>
- /// Gets a value indicating whether this instance can self restart.
- /// </summary>
- /// <value><c>true</c> if this instance can self restart; otherwise, <c>false</c>.</value>
- public abstract bool CanSelfRestart { get; }
-
- /// <summary>
- /// Notifies that the kernel that a change has been made that requires a restart
- /// </summary>
- public void NotifyPendingRestart()
- {
- Logger.Info("App needs to be restarted.");
-
- var changed = !HasPendingRestart;
-
- HasPendingRestart = true;
-
- if (changed)
- {
- EventHelper.QueueEventIfNotNull(HasPendingRestartChanged, this, EventArgs.Empty, Logger);
- }
- }
-
- /// <summary>
- /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
- /// </summary>
- public void Dispose()
- {
- Dispose(true);
- }
-
- /// <summary>
- /// Releases unmanaged and - optionally - managed resources.
- /// </summary>
- /// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
- protected virtual void Dispose(bool dispose)
- {
- if (dispose)
- {
- var type = GetType();
-
- Logger.Info("Disposing " + type.Name);
-
- var parts = DisposableParts.Distinct().Where(i => i.GetType() != type).ToList();
- DisposableParts.Clear();
-
- foreach (var part in parts)
- {
- Logger.Info("Disposing " + part.GetType().Name);
-
- try
- {
- part.Dispose();
- }
- catch (Exception ex)
- {
- Logger.ErrorException("Error disposing {0}", ex, part.GetType().Name);
- }
- }
- }
- }
-
- /// <summary>
- /// Restarts this instance.
- /// </summary>
- public abstract Task Restart();
-
- /// <summary>
- /// Gets or sets a value indicating whether this instance can self update.
- /// </summary>
- /// <value><c>true</c> if this instance can self update; otherwise, <c>false</c>.</value>
- public virtual bool CanSelfUpdate
- {
- get
- {
- return false;
- }
- }
-
- /// <summary>
- /// Checks for update.
- /// </summary>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <param name="progress">The progress.</param>
- /// <returns>Task{CheckForUpdateResult}.</returns>
- public abstract Task<CheckForUpdateResult> CheckForApplicationUpdate(CancellationToken cancellationToken,
- IProgress<double> progress);
-
- /// <summary>
- /// Updates the application.
- /// </summary>
- /// <param name="package">The package that contains the update</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <param name="progress">The progress.</param>
- /// <returns>Task.</returns>
- public abstract Task UpdateApplication(PackageVersionInfo package, CancellationToken cancellationToken,
- IProgress<double> progress);
-
- /// <summary>
- /// Shuts down.
- /// </summary>
- public abstract Task Shutdown();
-
- /// <summary>
- /// Called when [application updated].
- /// </summary>
- /// <param name="package">The package.</param>
- protected void OnApplicationUpdated(PackageVersionInfo package)
- {
- Logger.Info("Application has been updated to version {0}", package.versionStr);
-
- EventHelper.FireEventIfNotNull(ApplicationUpdated, this, new GenericEventArgs<PackageVersionInfo>
- {
- Argument = package
-
- }, Logger);
-
- NotifyPendingRestart();
- }
- }
-}
diff --git a/Emby.Common.Implementations/Emby.Common.Implementations.csproj b/Emby.Common.Implementations/Emby.Common.Implementations.csproj
deleted file mode 100644
index 00c90d16e..000000000
--- a/Emby.Common.Implementations/Emby.Common.Implementations.csproj
+++ /dev/null
@@ -1,453 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
- <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
- <PropertyGroup>
- <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
- <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
- <ProjectGuid>{1E37A338-9F57-4B70-BD6D-BB9C591E319B}</ProjectGuid>
- <OutputType>Library</OutputType>
- <AppDesignerFolder>Properties</AppDesignerFolder>
- <RootNamespace>Emby.Common.Implementations</RootNamespace>
- <AssemblyName>Emby.Common.Implementations</AssemblyName>
- <TargetFrameworkVersion>v4.6</TargetFrameworkVersion>
- <FileAlignment>512</FileAlignment>
- <TargetFrameworkProfile />
- </PropertyGroup>
- <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
- <DebugSymbols>true</DebugSymbols>
- <DebugType>full</DebugType>
- <Optimize>false</Optimize>
- <OutputPath>bin\Debug\</OutputPath>
- <DefineConstants>DEBUG;TRACE</DefineConstants>
- <ErrorReport>prompt</ErrorReport>
- <WarningLevel>4</WarningLevel>
- </PropertyGroup>
- <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
- <DebugType>pdbonly</DebugType>
- <Optimize>true</Optimize>
- <OutputPath>bin\Release\</OutputPath>
- <DefineConstants>TRACE</DefineConstants>
- <ErrorReport>prompt</ErrorReport>
- <WarningLevel>4</WarningLevel>
- </PropertyGroup>
- <ItemGroup>
- <Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
- <HintPath>..\packages\NLog.4.4.11\lib\net45\NLog.dll</HintPath>
- <Private>True</Private>
- </Reference>
- <Reference Include="ServiceStack.Text, Version=4.5.8.0, Culture=neutral, processorArchitecture=MSIL">
- <HintPath>..\packages\ServiceStack.Text.4.5.8\lib\net45\ServiceStack.Text.dll</HintPath>
- <Private>True</Private>
- </Reference>
- <Reference Include="SharpCompress, Version=0.14.0.0, Culture=neutral, processorArchitecture=MSIL">
- <HintPath>..\packages\SharpCompress.0.14.0\lib\net45\SharpCompress.dll</HintPath>
- <Private>True</Private>
- </Reference>
- <Reference Include="SimpleInjector, Version=4.0.8.0, Culture=neutral, PublicKeyToken=984cb50dea722e99, processorArchitecture=MSIL">
- <HintPath>..\packages\SimpleInjector.4.0.8\lib\net45\SimpleInjector.dll</HintPath>
- </Reference>
- <Reference Include="System" />
- <Reference Include="System.Core" />
- <Reference Include="System.Xml.Linq" />
- <Reference Include="System.Data.DataSetExtensions" />
- <Reference Include="Microsoft.CSharp" />
- <Reference Include="System.Data" />
- <Reference Include="System.Net.Http" />
- <Reference Include="System.Xml" />
- </ItemGroup>
- <ItemGroup>
- <Compile Include="..\SharedVersion.cs">
- <Link>Properties\SharedVersion.cs</Link>
- </Compile>
- <Compile Include="Archiving\ZipClient.cs" />
- <Compile Include="BaseApplicationHost.cs" />
- <Compile Include="Cryptography\CryptographyProvider.cs" />
- <Compile Include="Devices\DeviceId.cs" />
- <Compile Include="Diagnostics\CommonProcess.cs" />
- <Compile Include="Diagnostics\ProcessFactory.cs" />
- <Compile Include="EnvironmentInfo\EnvironmentInfo.cs" />
- <Compile Include="HttpClientManager\HttpClientInfo.cs" />
- <Compile Include="HttpClientManager\HttpClientManager.cs" />
- <Compile Include="IO\IsoManager.cs" />
- <Compile Include="IO\LnkShortcutHandler.cs" />
- <Compile Include="IO\ManagedFileSystem.cs" />
- <Compile Include="IO\ProgressStream.cs" />
- <Compile Include="IO\SharpCifsFileSystem.cs" />
- <Compile Include="IO\SharpCifs\Config.cs" />
- <Compile Include="IO\SharpCifs\Dcerpc\DcerpcBind.cs" />
- <Compile Include="IO\SharpCifs\Dcerpc\DcerpcBinding.cs" />
- <Compile Include="IO\SharpCifs\Dcerpc\DcerpcConstants.cs" />
- <Compile Include="IO\SharpCifs\Dcerpc\DcerpcError.cs" />
- <Compile Include="IO\SharpCifs\Dcerpc\DcerpcException.cs" />
- <Compile Include="IO\SharpCifs\Dcerpc\DcerpcHandle.cs" />
- <Compile Include="IO\SharpCifs\Dcerpc\DcerpcMessage.cs" />
- <Compile Include="IO\SharpCifs\Dcerpc\DcerpcPipeHandle.cs" />
- <Compile Include="IO\SharpCifs\Dcerpc\DcerpcSecurityProvider.cs" />
- <Compile Include="IO\SharpCifs\Dcerpc\Msrpc\LsaPolicyHandle.cs" />
- <Compile Include="IO\SharpCifs\Dcerpc\Msrpc\Lsarpc.cs" />
- <Compile Include="IO\SharpCifs\Dcerpc\Msrpc\LsarSidArrayX.cs" />
- <Compile Include="IO\SharpCifs\Dcerpc\Msrpc\MsrpcDfsRootEnum.cs" />
- <Compile Include="IO\SharpCifs\Dcerpc\Msrpc\MsrpcEnumerateAliasesInDomain.cs" />
- <Compile Include="IO\SharpCifs\Dcerpc\Msrpc\MsrpcGetMembersInAlias.cs" />
- <Compile Include="IO\SharpCifs\Dcerpc\Msrpc\MsrpcLookupSids.cs" />
- <Compile Include="IO\SharpCifs\Dcerpc\Msrpc\MsrpcLsarOpenPolicy2.cs" />
- <Compile Include="IO\SharpCifs\Dcerpc\Msrpc\MsrpcQueryInformationPolicy.cs" />
- <Compile Include="IO\SharpCifs\Dcerpc\Msrpc\MsrpcSamrConnect2.cs" />
- <Compile Include="IO\SharpCifs\Dcerpc\Msrpc\MsrpcSamrConnect4.cs" />
- <Compile Include="IO\SharpCifs\Dcerpc\Msrpc\MsrpcSamrOpenAlias.cs" />
- <Compile Include="IO\SharpCifs\Dcerpc\Msrpc\MsrpcSamrOpenDomain.cs" />
- <Compile Include="IO\SharpCifs\Dcerpc\Msrpc\MsrpcShareEnum.cs" />
- <Compile Include="IO\SharpCifs\Dcerpc\Msrpc\MsrpcShareGetInfo.cs" />
- <Compile Include="IO\SharpCifs\Dcerpc\Msrpc\Netdfs.cs" />
- <Compile Include="IO\SharpCifs\Dcerpc\Msrpc\Samr.cs" />
- <Compile Include="IO\SharpCifs\Dcerpc\Msrpc\SamrAliasHandle.cs" />
- <Compile Include="IO\SharpCifs\Dcerpc\Msrpc\SamrDomainHandle.cs" />
- <Compile Include="IO\SharpCifs\Dcerpc\Msrpc\SamrPolicyHandle.cs" />
- <Compile Include="IO\SharpCifs\Dcerpc\Msrpc\Srvsvc.cs" />
- <Compile Include="IO\SharpCifs\Dcerpc\Ndr\NdrBuffer.cs" />
- <Compile Include="IO\SharpCifs\Dcerpc\Ndr\NdrException.cs" />
- <Compile Include="IO\SharpCifs\Dcerpc\Ndr\NdrHyper.cs" />
- <Compile Include="IO\SharpCifs\Dcerpc\Ndr\NdrLong.cs" />
- <Compile Include="IO\SharpCifs\Dcerpc\Ndr\NdrObject.cs" />
- <Compile Include="IO\SharpCifs\Dcerpc\Ndr\NdrShort.cs" />
- <Compile Include="IO\SharpCifs\Dcerpc\Ndr\NdrSmall.cs" />
- <Compile Include="IO\SharpCifs\Dcerpc\Rpc.cs" />
- <Compile Include="IO\SharpCifs\Dcerpc\UnicodeString.cs" />
- <Compile Include="IO\SharpCifs\Dcerpc\UUID.cs" />
- <Compile Include="IO\SharpCifs\Netbios\Lmhosts.cs" />
- <Compile Include="IO\SharpCifs\Netbios\Name.cs" />
- <Compile Include="IO\SharpCifs\Netbios\NameQueryRequest.cs" />
- <Compile Include="IO\SharpCifs\Netbios\NameQueryResponse.cs" />
- <Compile Include="IO\SharpCifs\Netbios\NameServiceClient.cs" />
- <Compile Include="IO\SharpCifs\Netbios\NameServicePacket.cs" />
- <Compile Include="IO\SharpCifs\Netbios\NbtAddress.cs" />
- <Compile Include="IO\SharpCifs\Netbios\NbtException.cs" />
- <Compile Include="IO\SharpCifs\Netbios\NodeStatusRequest.cs" />
- <Compile Include="IO\SharpCifs\Netbios\NodeStatusResponse.cs" />
- <Compile Include="IO\SharpCifs\Netbios\SessionRequestPacket.cs" />
- <Compile Include="IO\SharpCifs\Netbios\SessionRetargetResponsePacket.cs" />
- <Compile Include="IO\SharpCifs\Netbios\SessionServicePacket.cs" />
- <Compile Include="IO\SharpCifs\Ntlmssp\NtlmFlags.cs" />
- <Compile Include="IO\SharpCifs\Ntlmssp\NtlmMessage.cs" />
- <Compile Include="IO\SharpCifs\Ntlmssp\Type1Message.cs" />
- <Compile Include="IO\SharpCifs\Ntlmssp\Type2Message.cs" />
- <Compile Include="IO\SharpCifs\Ntlmssp\Type3Message.cs" />
- <Compile Include="IO\SharpCifs\Smb\ACE.cs" />
- <Compile Include="IO\SharpCifs\Smb\AllocInfo.cs" />
- <Compile Include="IO\SharpCifs\Smb\AndXServerMessageBlock.cs" />
- <Compile Include="IO\SharpCifs\Smb\BufferCache.cs" />
- <Compile Include="IO\SharpCifs\Smb\Dfs.cs" />
- <Compile Include="IO\SharpCifs\Smb\DfsReferral.cs" />
- <Compile Include="IO\SharpCifs\Smb\DosError.cs" />
- <Compile Include="IO\SharpCifs\Smb\DosFileFilter.cs" />
- <Compile Include="IO\SharpCifs\Smb\FileEntry.cs" />
- <Compile Include="IO\SharpCifs\Smb\IInfo.cs" />
- <Compile Include="IO\SharpCifs\Smb\NetServerEnum2.cs" />
- <Compile Include="IO\SharpCifs\Smb\NetServerEnum2Response.cs" />
- <Compile Include="IO\SharpCifs\Smb\NetShareEnum.cs" />
- <Compile Include="IO\SharpCifs\Smb\NetShareEnumResponse.cs" />
- <Compile Include="IO\SharpCifs\Smb\NtlmAuthenticator.cs" />
- <Compile Include="IO\SharpCifs\Smb\NtlmChallenge.cs" />
- <Compile Include="IO\SharpCifs\Smb\NtlmContext.cs" />
- <Compile Include="IO\SharpCifs\Smb\NtlmPasswordAuthentication.cs" />
- <Compile Include="IO\SharpCifs\Smb\NtStatus.cs" />
- <Compile Include="IO\SharpCifs\Smb\NtTransQuerySecurityDesc.cs" />
- <Compile Include="IO\SharpCifs\Smb\NtTransQuerySecurityDescResponse.cs" />
- <Compile Include="IO\SharpCifs\Smb\Principal.cs" />
- <Compile Include="IO\SharpCifs\Smb\SecurityDescriptor.cs" />
- <Compile Include="IO\SharpCifs\Smb\ServerMessageBlock.cs" />
- <Compile Include="IO\SharpCifs\Smb\SID.cs" />
- <Compile Include="IO\SharpCifs\Smb\SigningDigest.cs" />
- <Compile Include="IO\SharpCifs\Smb\SmbAuthException.cs" />
- <Compile Include="IO\SharpCifs\Smb\SmbComBlankResponse.cs" />
- <Compile Include="IO\SharpCifs\Smb\SmbComClose.cs" />
- <Compile Include="IO\SharpCifs\Smb\SmbComCreateDirectory.cs" />
- <Compile Include="IO\SharpCifs\Smb\SmbComDelete.cs" />
- <Compile Include="IO\SharpCifs\Smb\SmbComDeleteDirectory.cs" />
- <Compile Include="IO\SharpCifs\Smb\SmbComFindClose2.cs" />
- <Compile Include="IO\SharpCifs\Smb\SmbComLogoffAndX.cs" />
- <Compile Include="IO\SharpCifs\Smb\SmbComNegotiate.cs" />
- <Compile Include="IO\SharpCifs\Smb\SmbComNegotiateResponse.cs" />
- <Compile Include="IO\SharpCifs\Smb\SmbComNTCreateAndX.cs" />
- <Compile Include="IO\SharpCifs\Smb\SmbComNTCreateAndXResponse.cs" />
- <Compile Include="IO\SharpCifs\Smb\SmbComNtTransaction.cs" />
- <Compile Include="IO\SharpCifs\Smb\SmbComNtTransactionResponse.cs" />
- <Compile Include="IO\SharpCifs\Smb\SmbComOpenAndX.cs" />
- <Compile Include="IO\SharpCifs\Smb\SmbComOpenAndXResponse.cs" />
- <Compile Include="IO\SharpCifs\Smb\SmbComQueryInformation.cs" />
- <Compile Include="IO\SharpCifs\Smb\SmbComQueryInformationResponse.cs" />
- <Compile Include="IO\SharpCifs\Smb\SmbComReadAndX.cs" />
- <Compile Include="IO\SharpCifs\Smb\SmbComReadAndXResponse.cs" />
- <Compile Include="IO\SharpCifs\Smb\SmbComRename.cs" />
- <Compile Include="IO\SharpCifs\Smb\SmbComSessionSetupAndX.cs" />
- <Compile Include="IO\SharpCifs\Smb\SmbComSessionSetupAndXResponse.cs" />
- <Compile Include="IO\SharpCifs\Smb\SmbComTransaction.cs" />
- <Compile Include="IO\SharpCifs\Smb\SmbComTransactionResponse.cs" />
- <Compile Include="IO\SharpCifs\Smb\SmbComTreeConnectAndX.cs" />
- <Compile Include="IO\SharpCifs\Smb\SmbComTreeConnectAndXResponse.cs" />
- <Compile Include="IO\SharpCifs\Smb\SmbComTreeDisconnect.cs" />
- <Compile Include="IO\SharpCifs\Smb\SmbComWrite.cs" />
- <Compile Include="IO\SharpCifs\Smb\SmbComWriteAndX.cs" />
- <Compile Include="IO\SharpCifs\Smb\SmbComWriteAndXResponse.cs" />
- <Compile Include="IO\SharpCifs\Smb\SmbComWriteResponse.cs" />
- <Compile Include="IO\SharpCifs\Smb\SmbConstants.cs" />
- <Compile Include="IO\SharpCifs\Smb\SmbException.cs" />
- <Compile Include="IO\SharpCifs\Smb\SmbFile.cs" />
- <Compile Include="IO\SharpCifs\Smb\SmbFileExtensions.cs" />
- <Compile Include="IO\SharpCifs\Smb\SmbFileFilter.cs" />
- <Compile Include="IO\SharpCifs\Smb\SmbFileInputStream.cs" />
- <Compile Include="IO\SharpCifs\Smb\SmbFilenameFilter.cs" />
- <Compile Include="IO\SharpCifs\Smb\SmbFileOutputStream.cs" />
- <Compile Include="IO\SharpCifs\Smb\SmbNamedPipe.cs" />
- <Compile Include="IO\SharpCifs\Smb\SmbRandomAccessFile.cs" />
- <Compile Include="IO\SharpCifs\Smb\SmbSession.cs" />
- <Compile Include="IO\SharpCifs\Smb\SmbShareInfo.cs" />
- <Compile Include="IO\SharpCifs\Smb\SmbTransport.cs" />
- <Compile Include="IO\SharpCifs\Smb\SmbTree.cs" />
- <Compile Include="IO\SharpCifs\Smb\Trans2FindFirst2.cs" />
- <Compile Include="IO\SharpCifs\Smb\Trans2FindFirst2Response.cs" />
- <Compile Include="IO\SharpCifs\Smb\Trans2FindNext2.cs" />
- <Compile Include="IO\SharpCifs\Smb\Trans2GetDfsReferral.cs" />
- <Compile Include="IO\SharpCifs\Smb\Trans2GetDfsReferralResponse.cs" />
- <Compile Include="IO\SharpCifs\Smb\Trans2QueryFSInformation.cs" />
- <Compile Include="IO\SharpCifs\Smb\Trans2QueryFSInformationResponse.cs" />
- <Compile Include="IO\SharpCifs\Smb\Trans2QueryPathInformation.cs" />
- <Compile Include="IO\SharpCifs\Smb\Trans2QueryPathInformationResponse.cs" />
- <Compile Include="IO\SharpCifs\Smb\Trans2SetFileInformation.cs" />
- <Compile Include="IO\SharpCifs\Smb\Trans2SetFileInformationResponse.cs" />
- <Compile Include="IO\SharpCifs\Smb\TransactNamedPipeInputStream.cs" />
- <Compile Include="IO\SharpCifs\Smb\TransactNamedPipeOutputStream.cs" />
- <Compile Include="IO\SharpCifs\Smb\TransCallNamedPipe.cs" />
- <Compile Include="IO\SharpCifs\Smb\TransCallNamedPipeResponse.cs" />
- <Compile Include="IO\SharpCifs\Smb\TransPeekNamedPipe.cs" />
- <Compile Include="IO\SharpCifs\Smb\TransPeekNamedPipeResponse.cs" />
- <Compile Include="IO\SharpCifs\Smb\TransTransactNamedPipe.cs" />
- <Compile Include="IO\SharpCifs\Smb\TransTransactNamedPipeResponse.cs" />
- <Compile Include="IO\SharpCifs\Smb\TransWaitNamedPipe.cs" />
- <Compile Include="IO\SharpCifs\Smb\TransWaitNamedPipeResponse.cs" />
- <Compile Include="IO\SharpCifs\Smb\WinError.cs" />
- <Compile Include="IO\SharpCifs\UniAddress.cs" />
- <Compile Include="IO\SharpCifs\Util\Base64.cs" />
- <Compile Include="IO\SharpCifs\Util\DES.cs" />
- <Compile Include="IO\SharpCifs\Util\Encdec.cs" />
- <Compile Include="IO\SharpCifs\Util\Hexdump.cs" />
- <Compile Include="IO\SharpCifs\Util\HMACT64.cs" />
- <Compile Include="IO\SharpCifs\Util\LogStream.cs" />
- <Compile Include="IO\SharpCifs\Util\MD4.cs" />
- <Compile Include="IO\SharpCifs\Util\RC4.cs" />
- <Compile Include="IO\SharpCifs\Util\Sharpen\AbstractMap.cs" />
- <Compile Include="IO\SharpCifs\Util\Sharpen\Arrays.cs" />
- <Compile Include="IO\SharpCifs\Util\Sharpen\BufferedReader.cs" />
- <Compile Include="IO\SharpCifs\Util\Sharpen\BufferedWriter.cs" />
- <Compile Include="IO\SharpCifs\Util\Sharpen\CharBuffer.cs" />
- <Compile Include="IO\SharpCifs\Util\Sharpen\CharSequence.cs" />
- <Compile Include="IO\SharpCifs\Util\Sharpen\Collections.cs" />
- <Compile Include="IO\SharpCifs\Util\Sharpen\ConcurrentHashMap.cs" />
- <Compile Include="IO\SharpCifs\Util\Sharpen\DateFormat.cs" />
- <Compile Include="IO\SharpCifs\Util\Sharpen\EnumeratorWrapper.cs" />
- <Compile Include="IO\SharpCifs\Util\Sharpen\Exceptions.cs" />
- <Compile Include="IO\SharpCifs\Util\Sharpen\Extensions.cs" />
- <Compile Include="IO\SharpCifs\Util\Sharpen\FileInputStream.cs" />
- <Compile Include="IO\SharpCifs\Util\Sharpen\FileOutputStream.cs" />
- <Compile Include="IO\SharpCifs\Util\Sharpen\FilePath.cs" />
- <Compile Include="IO\SharpCifs\Util\Sharpen\FileReader.cs" />
- <Compile Include="IO\SharpCifs\Util\Sharpen\FileWriter.cs" />
- <Compile Include="IO\SharpCifs\Util\Sharpen\FilterInputStream.cs" />
- <Compile Include="IO\SharpCifs\Util\Sharpen\FilterOutputStream.cs" />
- <Compile Include="IO\SharpCifs\Util\Sharpen\Hashtable.cs" />
- <Compile Include="IO\SharpCifs\Util\Sharpen\HttpURLConnection.cs" />
- <Compile Include="IO\SharpCifs\Util\Sharpen\ICallable.cs" />
- <Compile Include="IO\SharpCifs\Util\Sharpen\IConcurrentMap.cs" />
- <Compile Include="IO\SharpCifs\Util\Sharpen\IExecutor.cs" />
- <Compile Include="IO\SharpCifs\Util\Sharpen\IFilenameFilter.cs" />
- <Compile Include="IO\SharpCifs\Util\Sharpen\IFuture.cs" />
- <Compile Include="IO\SharpCifs\Util\Sharpen\InputStream.cs" />
- <Compile Include="IO\SharpCifs\Util\Sharpen\InputStreamReader.cs" />
- <Compile Include="IO\SharpCifs\Util\Sharpen\IPrivilegedAction.cs" />
- <Compile Include="IO\SharpCifs\Util\Sharpen\IRunnable.cs" />
- <Compile Include="IO\SharpCifs\Util\Sharpen\Iterator.cs" />
- <Compile Include="IO\SharpCifs\Util\Sharpen\LinkageError.cs" />
- <Compile Include="IO\SharpCifs\Util\Sharpen\Matcher.cs" />
- <Compile Include="IO\SharpCifs\Util\Sharpen\MD5.cs" />
- <Compile Include="IO\SharpCifs\Util\Sharpen\MD5Managed.cs" />
- <Compile Include="IO\SharpCifs\Util\Sharpen\MessageDigest.cs" />
- <Compile Include="IO\SharpCifs\Util\Sharpen\NetworkStream.cs" />
- <Compile Include="IO\SharpCifs\Util\Sharpen\ObjectInputStream.cs" />
- <Compile Include="IO\SharpCifs\Util\Sharpen\ObjectOutputStream.cs" />
- <Compile Include="IO\SharpCifs\Util\Sharpen\OutputStream.cs" />
- <Compile Include="IO\SharpCifs\Util\Sharpen\OutputStreamWriter.cs" />
- <Compile Include="IO\SharpCifs\Util\Sharpen\PipedInputStream.cs" />
- <Compile Include="IO\SharpCifs\Util\Sharpen\PipedOutputStream.cs" />
- <Compile Include="IO\SharpCifs\Util\Sharpen\PrintWriter.cs" />
- <Compile Include="IO\SharpCifs\Util\Sharpen\Properties.cs" />
- <Compile Include="IO\SharpCifs\Util\Sharpen\RandomAccessFile.cs" />
- <Compile Include="IO\SharpCifs\Util\Sharpen\ReentrantLock.cs" />
- <Compile Include="IO\SharpCifs\Util\Sharpen\Reference.cs" />
- <Compile Include="IO\SharpCifs\Util\Sharpen\Runtime.cs" />
- <Compile Include="IO\SharpCifs\Util\Sharpen\SimpleDateFormat.cs" />
- <Compile Include="IO\SharpCifs\Util\Sharpen\SocketEx.cs" />
- <Compile Include="IO\SharpCifs\Util\Sharpen\StringTokenizer.cs" />
- <Compile Include="IO\SharpCifs\Util\Sharpen\SynchronizedList.cs" />
- <Compile Include="IO\SharpCifs\Util\Sharpen\Thread.cs" />
- <Compile Include="IO\SharpCifs\Util\Sharpen\ThreadFactory.cs" />
- <Compile Include="IO\SharpCifs\Util\Sharpen\ThreadPoolExecutor.cs" />
- <Compile Include="IO\SharpCifs\Util\Sharpen\WrappedSystemStream.cs" />
- <Compile Include="IO\SharpCifs\Util\Transport\Request.cs" />
- <Compile Include="IO\SharpCifs\Util\Transport\Response.cs" />
- <Compile Include="IO\SharpCifs\Util\Transport\Transport.cs" />
- <Compile Include="IO\SharpCifs\Util\Transport\TransportException.cs" />
- <Compile Include="Logging\NLogger.cs" />
- <Compile Include="Logging\NlogManager.cs" />
- <Compile Include="Networking\NetworkManager.cs" />
- <Compile Include="Net\DisposableManagedObjectBase.cs" />
- <Compile Include="Net\NetAcceptSocket.cs" />
- <Compile Include="Net\SocketAcceptor.cs" />
- <Compile Include="Net\SocketFactory.cs" />
- <Compile Include="Net\UdpSocket.cs" />
- <Compile Include="Properties\AssemblyInfo.cs" />
- <Compile Include="Reflection\AssemblyInfo.cs" />
- <Compile Include="ScheduledTasks\DailyTrigger.cs" />
- <Compile Include="ScheduledTasks\IntervalTrigger.cs" />
- <Compile Include="ScheduledTasks\ScheduledTaskWorker.cs" />
- <Compile Include="ScheduledTasks\StartupTrigger.cs" />
- <Compile Include="ScheduledTasks\SystemEventTrigger.cs" />
- <Compile Include="ScheduledTasks\TaskManager.cs" />
- <Compile Include="ScheduledTasks\Tasks\DeleteCacheFileTask.cs" />
- <Compile Include="ScheduledTasks\Tasks\DeleteLogFileTask.cs" />
- <Compile Include="ScheduledTasks\Tasks\ReloadLoggerFileTask.cs" />
- <Compile Include="ScheduledTasks\WeeklyTrigger.cs" />
- <Compile Include="Serialization\JsonSerializer.cs" />
- <Compile Include="Serialization\XmlSerializer.cs" />
- <Compile Include="TextEncoding\NLangDetect\Detector.cs" />
- <Compile Include="TextEncoding\NLangDetect\DetectorFactory.cs" />
- <Compile Include="TextEncoding\NLangDetect\ErrorCode.cs" />
- <Compile Include="TextEncoding\NLangDetect\Extensions\CharExtensions.cs" />
- <Compile Include="TextEncoding\NLangDetect\Extensions\RandomExtensions.cs" />
- <Compile Include="TextEncoding\NLangDetect\Extensions\StringExtensions.cs" />
- <Compile Include="TextEncoding\NLangDetect\Extensions\UnicodeBlock.cs" />
- <Compile Include="TextEncoding\NLangDetect\GenProfile.cs" />
- <Compile Include="TextEncoding\NLangDetect\InternalException.cs" />
- <Compile Include="TextEncoding\NLangDetect\Language.cs" />
- <Compile Include="TextEncoding\NLangDetect\LanguageDetector.cs" />
- <Compile Include="TextEncoding\NLangDetect\NLangDetectException.cs" />
- <Compile Include="TextEncoding\NLangDetect\ProbVector.cs" />
- <Compile Include="TextEncoding\NLangDetect\Utils\LangProfile.cs" />
- <Compile Include="TextEncoding\NLangDetect\Utils\Messages.cs" />
- <Compile Include="TextEncoding\NLangDetect\Utils\NGram.cs" />
- <Compile Include="TextEncoding\NLangDetect\Utils\TagExtractor.cs" />
- <Compile Include="TextEncoding\TextEncoding.cs" />
- <Compile Include="TextEncoding\TextEncodingDetect.cs" />
- <Compile Include="TextEncoding\UniversalDetector\CharsetDetector.cs" />
- <Compile Include="TextEncoding\UniversalDetector\Core\Big5Prober.cs" />
- <Compile Include="TextEncoding\UniversalDetector\Core\BitPackage.cs" />
- <Compile Include="TextEncoding\UniversalDetector\Core\CharDistributionAnalyser.cs" />
- <Compile Include="TextEncoding\UniversalDetector\Core\CharsetProber.cs" />
- <Compile Include="TextEncoding\UniversalDetector\Core\Charsets.cs" />
- <Compile Include="TextEncoding\UniversalDetector\Core\CodingStateMachine.cs" />
- <Compile Include="TextEncoding\UniversalDetector\Core\EscCharsetProber.cs" />
- <Compile Include="TextEncoding\UniversalDetector\Core\EscSM.cs" />
- <Compile Include="TextEncoding\UniversalDetector\Core\EUCJPProber.cs" />
- <Compile Include="TextEncoding\UniversalDetector\Core\EUCKRProber.cs" />
- <Compile Include="TextEncoding\UniversalDetector\Core\EUCTWProber.cs" />
- <Compile Include="TextEncoding\UniversalDetector\Core\GB18030Prober.cs" />
- <Compile Include="TextEncoding\UniversalDetector\Core\HebrewProber.cs" />
- <Compile Include="TextEncoding\UniversalDetector\Core\JapaneseContextAnalyser.cs" />
- <Compile Include="TextEncoding\UniversalDetector\Core\LangBulgarianModel.cs" />
- <Compile Include="TextEncoding\UniversalDetector\Core\LangCyrillicModel.cs" />
- <Compile Include="TextEncoding\UniversalDetector\Core\LangGreekModel.cs" />
- <Compile Include="TextEncoding\UniversalDetector\Core\LangHebrewModel.cs" />
- <Compile Include="TextEncoding\UniversalDetector\Core\LangHungarianModel.cs" />
- <Compile Include="TextEncoding\UniversalDetector\Core\LangThaiModel.cs" />
- <Compile Include="TextEncoding\UniversalDetector\Core\Latin1Prober.cs" />
- <Compile Include="TextEncoding\UniversalDetector\Core\MBCSGroupProber.cs" />
- <Compile Include="TextEncoding\UniversalDetector\Core\MBCSSM.cs" />
- <Compile Include="TextEncoding\UniversalDetector\Core\SBCharsetProber.cs" />
- <Compile Include="TextEncoding\UniversalDetector\Core\SBCSGroupProber.cs" />
- <Compile Include="TextEncoding\UniversalDetector\Core\SequenceModel.cs" />
- <Compile Include="TextEncoding\UniversalDetector\Core\SJISProber.cs" />
- <Compile Include="TextEncoding\UniversalDetector\Core\SMModel.cs" />
- <Compile Include="TextEncoding\UniversalDetector\Core\UniversalDetector.cs" />
- <Compile Include="TextEncoding\UniversalDetector\Core\UTF8Prober.cs" />
- <Compile Include="TextEncoding\UniversalDetector\DetectionConfidence.cs" />
- <Compile Include="TextEncoding\UniversalDetector\ICharsetDetector.cs" />
- <Compile Include="Threading\CommonTimer.cs" />
- <Compile Include="Threading\TimerFactory.cs" />
- <Compile Include="Xml\XmlReaderSettingsFactory.cs" />
- </ItemGroup>
- <ItemGroup>
- <ProjectReference Include="..\MediaBrowser.Common\MediaBrowser.Common.csproj">
- <Project>{9142eefa-7570-41e1-bfcc-468bb571af2f}</Project>
- <Name>MediaBrowser.Common</Name>
- </ProjectReference>
- <ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj">
- <Project>{7eeeb4bb-f3e8-48fc-b4c5-70f0fff8329b}</Project>
- <Name>MediaBrowser.Model</Name>
- </ProjectReference>
- </ItemGroup>
- <ItemGroup>
- <None Include="packages.config" />
- <None Include="TextEncoding\NLangDetect\Profiles\afr" />
- <None Include="TextEncoding\NLangDetect\Profiles\ara" />
- <None Include="TextEncoding\NLangDetect\Profiles\bul" />
- <None Include="TextEncoding\NLangDetect\Profiles\ben" />
- <None Include="TextEncoding\NLangDetect\Profiles\ces" />
- <None Include="TextEncoding\NLangDetect\Profiles\dan" />
- <None Include="TextEncoding\NLangDetect\Profiles\deu" />
- <None Include="TextEncoding\NLangDetect\Profiles\ell" />
- <None Include="TextEncoding\NLangDetect\Profiles\eng" />
- <None Include="TextEncoding\NLangDetect\Profiles\spa" />
- <None Include="TextEncoding\NLangDetect\Profiles\est" />
- <None Include="TextEncoding\NLangDetect\Profiles\fas" />
- <None Include="TextEncoding\NLangDetect\Profiles\fin" />
- <None Include="TextEncoding\NLangDetect\Profiles\fra" />
- <None Include="TextEncoding\NLangDetect\Profiles\guj" />
- <None Include="TextEncoding\NLangDetect\Profiles\heb" />
- <None Include="TextEncoding\NLangDetect\Profiles\hin" />
- <None Include="TextEncoding\NLangDetect\Profiles\hrv" />
- <None Include="TextEncoding\NLangDetect\Profiles\hun" />
- <None Include="TextEncoding\NLangDetect\Profiles\ind" />
- <None Include="TextEncoding\NLangDetect\Profiles\ita" />
- <None Include="TextEncoding\NLangDetect\Profiles\jpn" />
- <None Include="TextEncoding\NLangDetect\Profiles\kan" />
- <None Include="TextEncoding\NLangDetect\Profiles\kor" />
- <None Include="TextEncoding\NLangDetect\Profiles\lit" />
- <None Include="TextEncoding\NLangDetect\Profiles\lav" />
- <None Include="TextEncoding\NLangDetect\Profiles\mkd" />
- <None Include="TextEncoding\NLangDetect\Profiles\mal" />
- <None Include="TextEncoding\NLangDetect\Profiles\mar" />
- <None Include="TextEncoding\NLangDetect\Profiles\nep" />
- <None Include="TextEncoding\NLangDetect\Profiles\nld" />
- <None Include="TextEncoding\NLangDetect\Profiles\nor" />
- <None Include="TextEncoding\NLangDetect\Profiles\pan" />
- <None Include="TextEncoding\NLangDetect\Profiles\pol" />
- <None Include="TextEncoding\NLangDetect\Profiles\por" />
- <None Include="TextEncoding\NLangDetect\Profiles\ron" />
- <None Include="TextEncoding\NLangDetect\Profiles\rus" />
- <None Include="TextEncoding\NLangDetect\Profiles\slk" />
- <None Include="TextEncoding\NLangDetect\Profiles\slv" />
- <None Include="TextEncoding\NLangDetect\Profiles\som" />
- <None Include="TextEncoding\NLangDetect\Profiles\sqi" />
- <None Include="TextEncoding\NLangDetect\Profiles\swe" />
- <None Include="TextEncoding\NLangDetect\Profiles\swa" />
- <None Include="TextEncoding\NLangDetect\Profiles\tam" />
- <None Include="TextEncoding\NLangDetect\Profiles\tel" />
- <None Include="TextEncoding\NLangDetect\Profiles\tha" />
- <None Include="TextEncoding\NLangDetect\Profiles\tgl" />
- <None Include="TextEncoding\NLangDetect\Profiles\tur" />
- <None Include="TextEncoding\NLangDetect\Profiles\ukr" />
- <None Include="TextEncoding\NLangDetect\Profiles\urd" />
- <None Include="TextEncoding\NLangDetect\Profiles\vie" />
- <EmbeddedResource Include="TextEncoding\NLangDetect\Profiles\zh-cn" />
- <EmbeddedResource Include="TextEncoding\NLangDetect\Profiles\zh-tw" />
- <EmbeddedResource Include="TextEncoding\NLangDetect\Utils\messages.properties" />
- </ItemGroup>
- <ItemGroup />
- <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
- <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
- Other similar extension points exist, see Microsoft.Common.targets.
- <Target Name="BeforeBuild">
- </Target>
- <Target Name="AfterBuild">
- </Target>
- -->
-</Project> \ No newline at end of file
diff --git a/Emby.Common.Implementations/Logging/NLogger.cs b/Emby.Common.Implementations/Logging/NLogger.cs
deleted file mode 100644
index 8abd3d0d9..000000000
--- a/Emby.Common.Implementations/Logging/NLogger.cs
+++ /dev/null
@@ -1,224 +0,0 @@
-using MediaBrowser.Model.Logging;
-using System;
-using System.Text;
-
-namespace Emby.Common.Implementations.Logging
-{
- /// <summary>
- /// Class NLogger
- /// </summary>
- public class NLogger : ILogger
- {
- /// <summary>
- /// The _logger
- /// </summary>
- private readonly NLog.Logger _logger;
-
- private readonly ILogManager _logManager;
-
- /// <summary>
- /// The _lock object
- /// </summary>
- private static readonly object LockObject = new object();
-
- /// <summary>
- /// Initializes a new instance of the <see cref="NLogger" /> class.
- /// </summary>
- /// <param name="name">The name.</param>
- /// <param name="logManager">The log manager.</param>
- public NLogger(string name, ILogManager logManager)
- {
- _logManager = logManager;
- lock (LockObject)
- {
- _logger = NLog.LogManager.GetLogger(name);
- }
- }
-
- /// <summary>
- /// Infoes the specified message.
- /// </summary>
- /// <param name="message">The message.</param>
- /// <param name="paramList">The param list.</param>
- public void Info(string message, params object[] paramList)
- {
- _logger.Info(message, paramList);
- }
-
- /// <summary>
- /// Errors the specified message.
- /// </summary>
- /// <param name="message">The message.</param>
- /// <param name="paramList">The param list.</param>
- public void Error(string message, params object[] paramList)
- {
- _logger.Error(message, paramList);
- }
-
- /// <summary>
- /// Warns the specified message.
- /// </summary>
- /// <param name="message">The message.</param>
- /// <param name="paramList">The param list.</param>
- public void Warn(string message, params object[] paramList)
- {
- _logger.Warn(message, paramList);
- }
-
- /// <summary>
- /// Debugs the specified message.
- /// </summary>
- /// <param name="message">The message.</param>
- /// <param name="paramList">The param list.</param>
- public void Debug(string message, params object[] paramList)
- {
- if (_logManager.LogSeverity == LogSeverity.Info)
- {
- return;
- }
-
- _logger.Debug(message, paramList);
- }
-
- /// <summary>
- /// Logs the exception.
- /// </summary>
- /// <param name="message">The message.</param>
- /// <param name="exception">The exception.</param>
- /// <param name="paramList">The param list.</param>
- /// <exception cref="System.NotImplementedException"></exception>
- public void ErrorException(string message, Exception exception, params object[] paramList)
- {
- LogException(LogSeverity.Error, message, exception, paramList);
- }
-
- /// <summary>
- /// Logs the exception.
- /// </summary>
- /// <param name="level">The level.</param>
- /// <param name="message">The message.</param>
- /// <param name="exception">The exception.</param>
- /// <param name="paramList">The param list.</param>
- private void LogException(LogSeverity level, string message, Exception exception, params object[] paramList)
- {
- message = FormatMessage(message, paramList).Replace(Environment.NewLine, ". ");
-
- var messageText = LogHelper.GetLogMessage(exception);
-
- var prefix = _logManager.ExceptionMessagePrefix;
-
- if (!string.IsNullOrWhiteSpace(prefix))
- {
- messageText.Insert(0, prefix);
- }
-
- LogMultiline(message, level, messageText);
- }
-
- /// <summary>
- /// Formats the message.
- /// </summary>
- /// <param name="message">The message.</param>
- /// <param name="paramList">The param list.</param>
- /// <returns>System.String.</returns>
- private static string FormatMessage(string message, params object[] paramList)
- {
- if (paramList != null)
- {
- for (var i = 0; i < paramList.Length; i++)
- {
- var obj = paramList[i];
-
- message = message.Replace("{" + i + "}", (obj == null ? "null" : obj.ToString()));
- }
- }
-
- return message;
- }
-
- /// <summary>
- /// Logs the multiline.
- /// </summary>
- /// <param name="message">The message.</param>
- /// <param name="severity">The severity.</param>
- /// <param name="additionalContent">Content of the additional.</param>
- public void LogMultiline(string message, LogSeverity severity, StringBuilder additionalContent)
- {
- if (severity == LogSeverity.Debug && _logManager.LogSeverity == LogSeverity.Info)
- {
- return;
- }
-
- additionalContent.Insert(0, message + Environment.NewLine);
-
- const char tabChar = '\t';
-
- var text = additionalContent.ToString()
- .Replace(Environment.NewLine, Environment.NewLine + tabChar)
- .TrimEnd(tabChar);
-
- if (text.EndsWith(Environment.NewLine))
- {
- text = text.Substring(0, text.LastIndexOf(Environment.NewLine, StringComparison.OrdinalIgnoreCase));
- }
-
- _logger.Log(GetLogLevel(severity), text);
- }
-
- /// <summary>
- /// Gets the log level.
- /// </summary>
- /// <param name="severity">The severity.</param>
- /// <returns>NLog.LogLevel.</returns>
- private NLog.LogLevel GetLogLevel(LogSeverity severity)
- {
- switch (severity)
- {
- case LogSeverity.Debug:
- return NLog.LogLevel.Debug;
- case LogSeverity.Error:
- return NLog.LogLevel.Error;
- case LogSeverity.Warn:
- return NLog.LogLevel.Warn;
- case LogSeverity.Fatal:
- return NLog.LogLevel.Fatal;
- case LogSeverity.Info:
- return NLog.LogLevel.Info;
- default:
- throw new ArgumentException("Unknown LogSeverity: " + severity.ToString());
- }
- }
-
- /// <summary>
- /// Logs the specified severity.
- /// </summary>
- /// <param name="severity">The severity.</param>
- /// <param name="message">The message.</param>
- /// <param name="paramList">The param list.</param>
- public void Log(LogSeverity severity, string message, params object[] paramList)
- {
- _logger.Log(GetLogLevel(severity), message, paramList);
- }
-
- /// <summary>
- /// Fatals the specified message.
- /// </summary>
- /// <param name="message">The message.</param>
- /// <param name="paramList">The param list.</param>
- public void Fatal(string message, params object[] paramList)
- {
- _logger.Fatal(message, paramList);
- }
-
- /// <summary>
- /// Fatals the exception.
- /// </summary>
- /// <param name="message">The message.</param>
- /// <param name="exception">The exception.</param>
- /// <param name="paramList">The param list.</param>
- public void FatalException(string message, Exception exception, params object[] paramList)
- {
- LogException(LogSeverity.Fatal, message, exception, paramList);
- }
- }
-}
diff --git a/Emby.Common.Implementations/Logging/NlogManager.cs b/Emby.Common.Implementations/Logging/NlogManager.cs
deleted file mode 100644
index f7b723e8b..000000000
--- a/Emby.Common.Implementations/Logging/NlogManager.cs
+++ /dev/null
@@ -1,544 +0,0 @@
-using System;
-using System.IO;
-using System.Linq;
-using System.Xml;
-using NLog;
-using NLog.Config;
-using NLog.Filters;
-using NLog.Targets;
-using NLog.Targets.Wrappers;
-using MediaBrowser.Model.Logging;
-
-namespace Emby.Common.Implementations.Logging
-{
- /// <summary>
- /// Class NlogManager
- /// </summary>
- public class NlogManager : ILogManager
- {
- #region Private Fields
-
- private LogSeverity _severity = LogSeverity.Debug;
-
- /// <summary>
- /// Gets or sets the log directory.
- /// </summary>
- /// <value>The log directory.</value>
- private readonly string LogDirectory;
-
- /// <summary>
- /// Gets or sets the log file prefix.
- /// </summary>
- /// <value>The log file prefix.</value>
- private readonly string LogFilePrefix;
-
- #endregion
-
- #region Event Declarations
-
- /// <summary>
- /// Occurs when [logger loaded].
- /// </summary>
- public event EventHandler LoggerLoaded;
-
- #endregion
-
- #region Public Properties
-
- /// <summary>
- /// Gets the log file path.
- /// </summary>
- /// <value>The log file path.</value>
- public string LogFilePath { get; private set; }
-
- /// <summary>
- /// Gets or sets the exception message prefix.
- /// </summary>
- /// <value>The exception message prefix.</value>
- public string ExceptionMessagePrefix { get; set; }
-
- public string NLogConfigurationFilePath { get; set; }
-
- public LogSeverity LogSeverity
- {
-
- get
- {
- return _severity;
- }
-
- set
- {
- DebugFileWriter(
- LogDirectory, String.Format(
- "SET LogSeverity, _severity = [{0}], value = [{1}]",
- _severity.ToString(),
- value.ToString()
- ));
-
- var changed = _severity != value;
-
- _severity = value;
-
- if (changed)
- {
- UpdateLogLevel(value);
- }
-
- }
- }
-
- #endregion
-
- #region Constructor(s)
-
- /// <summary>
- /// Initializes a new instance of the <see cref="NlogManager" /> class.
- /// </summary>
- /// <param name="logDirectory">The log directory.</param>
- /// <param name="logFileNamePrefix">The log file name prefix.</param>
- public NlogManager(string logDirectory, string logFileNamePrefix)
- {
- DebugFileWriter(
- logDirectory, String.Format(
- "NlogManager constructor called, logDirectory is [{0}], logFileNamePrefix is [{1}], _severity is [{2}].",
- logDirectory,
- logFileNamePrefix,
- _severity.ToString()
- ));
-
- LogDirectory = logDirectory;
- LogFilePrefix = logFileNamePrefix;
-
- LogManager.Configuration = new LoggingConfiguration();
- }
-
- /// <summary>
- /// Initializes a new instance of the <see cref="NlogManager" /> class.
- /// </summary>
- /// <param name="logDirectory">The log directory.</param>
- /// <param name="logFileNamePrefix">The log file name prefix.</param>
- public NlogManager(string logDirectory, string logFileNamePrefix, LogSeverity initialSeverity) : this(logDirectory, logFileNamePrefix)
- {
- _severity = initialSeverity;
-
- DebugFileWriter(
- logDirectory, String.Format(
- "NlogManager constructor called, logDirectory is [{0}], logFileNamePrefix is [{1}], _severity is [{2}].",
- logDirectory,
- logFileNamePrefix,
- _severity.ToString()
- ));
- }
-
- #endregion
-
- #region Private Methods
-
- /// <summary>
- /// Adds the file target.
- /// </summary>
- /// <param name="path">The path.</param>
- /// <param name="level">The level.</param>
- private void AddFileTarget(string path, LogSeverity level)
- {
-
- DebugFileWriter(
- LogDirectory, String.Format(
- "AddFileTarget called, path = [{0}], level = [{1}].",
- path,
- level.ToString()
- ));
-
- RemoveTarget("ApplicationLogFileWrapper");
-
- var wrapper = new AsyncTargetWrapper();
- wrapper.Name = "ApplicationLogFileWrapper";
-
- var logFile = new FileTarget
- {
- FileName = path,
- Layout = "${longdate} ${level} ${logger}: ${message}"
- };
-
- logFile.Name = "ApplicationLogFile";
-
- wrapper.WrappedTarget = logFile;
-
- AddLogTarget(wrapper, level);
-
- }
-
- /// <summary>
- /// Gets the log level.
- /// </summary>
- /// <param name="severity">The severity.</param>
- /// <returns>LogLevel.</returns>
- /// <exception cref="System.ArgumentException">Unrecognized LogSeverity</exception>
- private LogLevel GetLogLevel(LogSeverity severity)
- {
- switch (severity)
- {
- case LogSeverity.Debug:
- return LogLevel.Debug;
- case LogSeverity.Error:
- return LogLevel.Error;
- case LogSeverity.Fatal:
- return LogLevel.Fatal;
- case LogSeverity.Info:
- return LogLevel.Info;
- case LogSeverity.Warn:
- return LogLevel.Warn;
- default:
- throw new ArgumentException("Unrecognized LogSeverity");
- }
- }
-
- private void UpdateLogLevel(LogSeverity newLevel)
- {
- DebugFileWriter(
- LogDirectory, String.Format(
- "UpdateLogLevel called, newLevel = [{0}].",
- newLevel.ToString()
- ));
-
- var level = GetLogLevel(newLevel);
-
- var rules = LogManager.Configuration.LoggingRules;
-
- foreach (var rule in rules)
- {
- if (!rule.IsLoggingEnabledForLevel(level))
- {
- rule.EnableLoggingForLevel(level);
- }
- foreach (var lev in rule.Levels.ToArray())
- {
- if (lev < level)
- {
- rule.DisableLoggingForLevel(lev);
- }
- }
- }
- }
-
- private void AddCustomFilters(string defaultLoggerNamePattern, LoggingRule defaultRule)
- {
- DebugFileWriter(
- LogDirectory, String.Format(
- "AddCustomFilters called, defaultLoggerNamePattern = [{0}], defaultRule.LoggerNamePattern = [{1}].",
- defaultLoggerNamePattern,
- defaultRule.LoggerNamePattern
- ));
-
- try
- {
- var customConfig = new NLog.Config.XmlLoggingConfiguration(NLogConfigurationFilePath);
-
- DebugFileWriter(
- LogDirectory, String.Format(
- "Custom Configuration Loaded, Rule Count = [{0}].",
- customConfig.LoggingRules.Count.ToString()
- ));
-
- foreach (var customRule in customConfig.LoggingRules)
- {
-
- DebugFileWriter(
- LogDirectory, String.Format(
- "Read Custom Rule, LoggerNamePattern = [{0}], Targets = [{1}].",
- customRule.LoggerNamePattern,
- string.Join(",", customRule.Targets.Select(x => x.Name).ToList())
- ));
-
- if (customRule.LoggerNamePattern.Equals(defaultLoggerNamePattern))
- {
-
- if (customRule.Targets.Any((arg) => arg.Name.Equals(defaultRule.Targets.First().Name)))
- {
-
- DebugFileWriter(
- LogDirectory, String.Format(
- "Custom rule filters can be applied to this target, Filter Count = [{0}].",
- customRule.Filters.Count.ToString()
- ));
-
- foreach (ConditionBasedFilter customFilter in customRule.Filters)
- {
-
- DebugFileWriter(
- LogDirectory, String.Format(
- "Read Custom Filter, Filter = [{0}], Action = [{1}], Type = [{2}].",
- customFilter.Condition.ToString(),
- customFilter.Action.ToString(),
- customFilter.GetType().ToString()
- ));
-
- defaultRule.Filters.Add(customFilter);
-
- }
- }
- else
- {
-
- DebugFileWriter(
- LogDirectory, String.Format(
- "Ignoring custom rule as [Target] does not match."
- ));
-
- }
-
- }
- else
- {
-
- DebugFileWriter(
- LogDirectory, String.Format(
- "Ignoring custom rule as [LoggerNamePattern] does not match."
- ));
-
- }
- }
- }
- catch (Exception ex)
- {
- // Intentionally do nothing, prevent issues affecting normal execution.
- DebugFileWriter(
- LogDirectory, String.Format(
- "Exception in AddCustomFilters, ex.Message = [{0}].",
- ex.Message
- )
- );
-
- }
- }
-
- #endregion
-
- #region Public Methods
-
- /// <summary>
- /// Gets the logger.
- /// </summary>
- /// <param name="name">The name.</param>
- /// <returns>ILogger.</returns>
- public MediaBrowser.Model.Logging.ILogger GetLogger(string name)
- {
-
- DebugFileWriter(
- LogDirectory, String.Format(
- "GetLogger called, name = [{0}].",
- name
- ));
-
- return new NLogger(name, this);
-
- }
-
- /// <summary>
- /// Adds the log target.
- /// </summary>
- /// <param name="target">The target.</param>
- /// <param name="level">The level.</param>
- public void AddLogTarget(Target target, LogSeverity level)
- {
-
- DebugFileWriter(
- LogDirectory, String.Format(
- "AddLogTarget called, target.Name = [{0}], level = [{1}].",
- target.Name,
- level.ToString()
- ));
-
- string loggerNamePattern = "*";
- var config = LogManager.Configuration;
- var rule = new LoggingRule(loggerNamePattern, GetLogLevel(level), target);
-
- config.AddTarget(target.Name, target);
-
- AddCustomFilters(loggerNamePattern, rule);
-
- config.LoggingRules.Add(rule);
-
- LogManager.Configuration = config;
-
- }
-
- /// <summary>
- /// Removes the target.
- /// </summary>
- /// <param name="name">The name.</param>
- public void RemoveTarget(string name)
- {
-
- DebugFileWriter(
- LogDirectory, String.Format(
- "RemoveTarget called, name = [{0}].",
- name
- ));
-
- var config = LogManager.Configuration;
-
- var target = config.FindTargetByName(name);
-
- if (target != null)
- {
- foreach (var rule in config.LoggingRules.ToList())
- {
- var contains = rule.Targets.Contains(target);
-
- rule.Targets.Remove(target);
-
- if (contains)
- {
- config.LoggingRules.Remove(rule);
- }
- }
-
- config.RemoveTarget(name);
- LogManager.Configuration = config;
- }
- }
-
- public void AddConsoleOutput()
- {
-
- DebugFileWriter(
- LogDirectory, String.Format(
- "AddConsoleOutput called."
- ));
-
- RemoveTarget("ConsoleTargetWrapper");
-
- var wrapper = new AsyncTargetWrapper();
- wrapper.Name = "ConsoleTargetWrapper";
-
- var target = new ConsoleTarget()
- {
- Layout = "${level}, ${logger}, ${message}",
- Error = false
- };
-
- target.Name = "ConsoleTarget";
-
- wrapper.WrappedTarget = target;
-
- AddLogTarget(wrapper, LogSeverity);
-
- }
-
- public void RemoveConsoleOutput()
- {
-
- DebugFileWriter(
- LogDirectory, String.Format(
- "RemoveConsoleOutput called."
- ));
-
- RemoveTarget("ConsoleTargetWrapper");
-
- }
-
- /// <summary>
- /// Reloads the logger, maintaining the current log level.
- /// </summary>
- public void ReloadLogger()
- {
- ReloadLogger(LogSeverity);
- }
-
- /// <summary>
- /// Reloads the logger, using the specified logging level.
- /// </summary>
- /// <param name="level">The level.</param>
- public void ReloadLogger(LogSeverity level)
- {
-
- DebugFileWriter(
- LogDirectory, String.Format(
- "ReloadLogger called, level = [{0}], LogFilePath (existing) = [{1}].",
- level.ToString(),
- LogFilePath
- ));
-
- LogFilePath = Path.Combine(LogDirectory, LogFilePrefix + "-" + decimal.Floor(DateTime.Now.Ticks / 10000000) + ".txt");
-
- Directory.CreateDirectory(Path.GetDirectoryName(LogFilePath));
-
- AddFileTarget(LogFilePath, level);
-
- LogSeverity = level;
-
- if (LoggerLoaded != null)
- {
- try
- {
-
- DebugFileWriter(
- LogDirectory, String.Format(
- "ReloadLogger called, raised event LoggerLoaded."
- ));
-
- LoggerLoaded(this, EventArgs.Empty);
-
- }
- catch (Exception ex)
- {
- GetLogger("Logger").ErrorException("Error in LoggerLoaded event", ex);
- }
- }
- }
-
- /// <summary>
- /// Flushes this instance.
- /// </summary>
- public void Flush()
- {
-
- DebugFileWriter(
- LogDirectory, String.Format(
- "Flush called."
- ));
-
- LogManager.Flush();
-
- }
-
- #endregion
-
- #region Conditional Debug Methods
-
- /// <summary>
- /// DEBUG: Standalone method to write out debug to assist with logger development/troubleshooting.
- /// <list type="bullet">
- /// <item><description>The output file will be written to the server's log directory.</description></item>
- /// <item><description>Calls to the method are safe and will never throw any exceptions.</description></item>
- /// <item><description>Method calls will be omitted unless the library is compiled with DEBUG defined.</description></item>
- /// </list>
- /// </summary>
- private static void DebugFileWriter(string logDirectory, string message)
- {
-#if DEBUG
- try
- {
-
- System.IO.File.AppendAllText(
- Path.Combine(logDirectory, "NlogManager.txt"),
- String.Format(
- "{0} : {1}{2}",
- System.DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ss.fffZ"),
- message,
- System.Environment.NewLine
- )
- );
-
- }
- catch (Exception ex)
- {
- // Intentionally do nothing, prevent issues affecting normal execution.
- }
-#endif
- }
- #endregion
- }
-} \ No newline at end of file
diff --git a/Emby.Common.Implementations/Net/NetAcceptSocket.cs b/Emby.Common.Implementations/Net/NetAcceptSocket.cs
deleted file mode 100644
index 5e831ac7a..000000000
--- a/Emby.Common.Implementations/Net/NetAcceptSocket.cs
+++ /dev/null
@@ -1,154 +0,0 @@
-using System;
-using System.Net;
-using System.Net.Sockets;
-using System.Threading;
-using System.Threading.Tasks;
-using Emby.Common.Implementations.Networking;
-using MediaBrowser.Model.Net;
-using MediaBrowser.Model.Logging;
-
-namespace Emby.Common.Implementations.Net
-{
- public class NetAcceptSocket : IAcceptSocket
- {
- public Socket Socket { get; private set; }
- private readonly ILogger _logger;
-
- public bool DualMode { get; private set; }
-
- public NetAcceptSocket(Socket socket, ILogger logger, bool isDualMode)
- {
- if (socket == null)
- {
- throw new ArgumentNullException("socket");
- }
- if (logger == null)
- {
- throw new ArgumentNullException("logger");
- }
-
- Socket = socket;
- _logger = logger;
- DualMode = isDualMode;
- }
-
- public IpEndPointInfo LocalEndPoint
- {
- get
- {
- return NetworkManager.ToIpEndPointInfo((IPEndPoint)Socket.LocalEndPoint);
- }
- }
-
- public IpEndPointInfo RemoteEndPoint
- {
- get
- {
- return NetworkManager.ToIpEndPointInfo((IPEndPoint)Socket.RemoteEndPoint);
- }
- }
-
- public void Connect(IpEndPointInfo endPoint)
- {
- var nativeEndpoint = NetworkManager.ToIPEndPoint(endPoint);
-
- Socket.Connect(nativeEndpoint);
- }
-
- public void Close()
- {
-#if NET46
- Socket.Close();
-#else
- Socket.Dispose();
-#endif
- }
-
- public void Shutdown(bool both)
- {
- if (both)
- {
- Socket.Shutdown(SocketShutdown.Both);
- }
- else
- {
- // Change interface if ever needed
- throw new NotImplementedException();
- }
- }
-
- public void Listen(int backlog)
- {
- Socket.Listen(backlog);
- }
-
- public void Bind(IpEndPointInfo endpoint)
- {
- var nativeEndpoint = NetworkManager.ToIPEndPoint(endpoint);
-
- Socket.Bind(nativeEndpoint);
- }
-
- private SocketAcceptor _acceptor;
- public void StartAccept(Action<IAcceptSocket> onAccept, Func<bool> isClosed)
- {
- _acceptor = new SocketAcceptor(_logger, Socket, onAccept, isClosed, DualMode);
-
- _acceptor.StartAccept();
- }
-
- public Task SendFile(string path, byte[] preBuffer, byte[] postBuffer, CancellationToken cancellationToken)
- {
- var options = TransmitFileOptions.UseDefaultWorkerThread;
-
- var completionSource = new TaskCompletionSource<bool>();
-
- var result = Socket.BeginSendFile(path, preBuffer, postBuffer, options, new AsyncCallback(FileSendCallback), new Tuple<Socket, string, TaskCompletionSource<bool>>(Socket, path, completionSource));
-
- return completionSource.Task;
- }
-
- public IAsyncResult BeginSendFile(string path, byte[] preBuffer, byte[] postBuffer, AsyncCallback callback, object state)
- {
- var options = TransmitFileOptions.UseDefaultWorkerThread;
-
- return Socket.BeginSendFile(path, preBuffer, postBuffer, options, new AsyncCallback(FileSendCallback), state);
- }
-
- public void EndSendFile(IAsyncResult result)
- {
- Socket.EndSendFile(result);
- }
-
- private void FileSendCallback(IAsyncResult ar)
- {
- // Retrieve the socket from the state object.
- Tuple<Socket, string, TaskCompletionSource<bool>> data = (Tuple<Socket, string, TaskCompletionSource<bool>>)ar.AsyncState;
-
- var client = data.Item1;
- var path = data.Item2;
- var taskCompletion = data.Item3;
-
- // Complete sending the data to the remote device.
- try
- {
- client.EndSendFile(ar);
- taskCompletion.TrySetResult(true);
- }
- catch (SocketException ex)
- {
- _logger.Info("Socket.SendFile failed for {0}. error code {1}", path, ex.SocketErrorCode);
- taskCompletion.TrySetException(ex);
- }
- catch (Exception ex)
- {
- taskCompletion.TrySetException(ex);
- }
- }
-
- public void Dispose()
- {
- Socket.Dispose();
- }
- }
-}
diff --git a/Emby.Common.Implementations/Properties/AssemblyInfo.cs b/Emby.Common.Implementations/Properties/AssemblyInfo.cs
deleted file mode 100644
index 787f18997..000000000
--- a/Emby.Common.Implementations/Properties/AssemblyInfo.cs
+++ /dev/null
@@ -1,34 +0,0 @@
-using System.Reflection;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-
-// General Information about an assembly is controlled through the following
-// set of attributes. Change these attribute values to modify the information
-// associated with an assembly.
-[assembly: AssemblyTitle("Emby.Common.Implementations")]
-[assembly: AssemblyDescription("")]
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("")]
-[assembly: AssemblyProduct("Emby.Common.Implementations")]
-[assembly: AssemblyCopyright("Copyright © 2017")]
-[assembly: AssemblyTrademark("")]
-[assembly: AssemblyCulture("")]
-
-// Setting ComVisible to false makes the types in this assembly not visible
-// to COM components. If you need to access a type in this assembly from
-// COM, set the ComVisible attribute to true on that type.
-[assembly: ComVisible(false)]
-
-// The following GUID is for the ID of the typelib if this project is exposed to COM
-[assembly: Guid("1e37a338-9f57-4b70-bd6d-bb9c591e319b")]
-
-// Version information for an assembly consists of the following four values:
-//
-// Major Version
-// Minor Version
-// Build Number
-// Revision
-//
-// You can specify all the values or you can default the Build and Revision Numbers
-// by using the '*' as shown below:
-// [assembly: AssemblyVersion("1.0.*")] \ No newline at end of file
diff --git a/Emby.Common.Implementations/packages.config b/Emby.Common.Implementations/packages.config
deleted file mode 100644
index a255465cc..000000000
--- a/Emby.Common.Implementations/packages.config
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<packages>
- <package id="NLog" version="4.4.11" targetFramework="net46" />
- <package id="ServiceStack.Text" version="4.5.8" targetFramework="net462" />
- <package id="SharpCompress" version="0.14.0" targetFramework="net462" />
- <package id="SimpleInjector" version="4.0.8" targetFramework="net46" />
-</packages> \ No newline at end of file
diff --git a/Emby.Dlna/ContentDirectory/ContentDirectory.cs b/Emby.Dlna/ContentDirectory/ContentDirectory.cs
index 4a36a16eb..fbd709010 100644
--- a/Emby.Dlna/ContentDirectory/ContentDirectory.cs
+++ b/Emby.Dlna/ContentDirectory/ContentDirectory.cs
@@ -10,14 +10,14 @@ using MediaBrowser.Model.Dlna;
using MediaBrowser.Model.Logging;
using System;
using System.Collections.Generic;
-using System.Linq;
using MediaBrowser.Controller.MediaEncoding;
+using MediaBrowser.Controller.TV;
using MediaBrowser.Model.Globalization;
using MediaBrowser.Model.Xml;
namespace Emby.Dlna.ContentDirectory
{
- public class ContentDirectory : BaseService, IContentDirectory, IDisposable
+ public class ContentDirectory : BaseService, IContentDirectory
{
private readonly ILibraryManager _libraryManager;
private readonly IImageProcessor _imageProcessor;
@@ -31,6 +31,7 @@ namespace Emby.Dlna.ContentDirectory
private readonly IUserViewManager _userViewManager;
private readonly Func<IMediaEncoder> _mediaEncoder;
protected readonly IXmlReaderSettingsFactory XmlReaderSettingsFactory;
+ private readonly ITVSeriesManager _tvSeriesManager;
public ContentDirectory(IDlnaManager dlna,
IUserDataManager userDataManager,
@@ -39,7 +40,7 @@ namespace Emby.Dlna.ContentDirectory
IServerConfigurationManager config,
IUserManager userManager,
ILogger logger,
- IHttpClient httpClient, ILocalizationManager localization, IChannelManager channelManager, IMediaSourceManager mediaSourceManager, IUserViewManager userViewManager, Func<IMediaEncoder> mediaEncoder, IXmlReaderSettingsFactory xmlReaderSettingsFactory)
+ IHttpClient httpClient, ILocalizationManager localization, IChannelManager channelManager, IMediaSourceManager mediaSourceManager, IUserViewManager userViewManager, Func<IMediaEncoder> mediaEncoder, IXmlReaderSettingsFactory xmlReaderSettingsFactory, ITVSeriesManager tvSeriesManager)
: base(logger, httpClient)
{
_dlna = dlna;
@@ -54,6 +55,7 @@ namespace Emby.Dlna.ContentDirectory
_userViewManager = userViewManager;
_mediaEncoder = mediaEncoder;
XmlReaderSettingsFactory = xmlReaderSettingsFactory;
+ _tvSeriesManager = tvSeriesManager;
}
private int SystemUpdateId
@@ -97,7 +99,8 @@ namespace Emby.Dlna.ContentDirectory
_mediaSourceManager,
_userViewManager,
_mediaEncoder(),
- XmlReaderSettingsFactory)
+ XmlReaderSettingsFactory,
+ _tvSeriesManager)
.ProcessControlRequest(request);
}
@@ -125,14 +128,20 @@ namespace Emby.Dlna.ContentDirectory
}
}
- // No configuration so it's going to be pretty arbitrary
- return _userManager.Users.FirstOrDefault(i => i.Policy.IsAdministrator) ??
- _userManager.Users.First();
- }
+ foreach (var user in _userManager.Users)
+ {
+ if (user.Policy.IsAdministrator)
+ {
+ return user;
+ }
+ }
- public void Dispose()
- {
+ foreach (var user in _userManager.Users)
+ {
+ return user;
+ }
+ return null;
}
}
}
diff --git a/Emby.Dlna/ContentDirectory/ControlHandler.cs b/Emby.Dlna/ContentDirectory/ControlHandler.cs
index 9345a1df7..47d199e6e 100644
--- a/Emby.Dlna/ContentDirectory/ControlHandler.cs
+++ b/Emby.Dlna/ContentDirectory/ControlHandler.cs
@@ -27,8 +27,10 @@ using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.Controller.Playlists;
+using MediaBrowser.Controller.TV;
using MediaBrowser.Model.Globalization;
using MediaBrowser.Model.Xml;
+using MediaBrowser.Model.Extensions;
namespace Emby.Dlna.ContentDirectory
{
@@ -40,6 +42,7 @@ namespace Emby.Dlna.ContentDirectory
private readonly IServerConfigurationManager _config;
private readonly User _user;
private readonly IUserViewManager _userViewManager;
+ private readonly ITVSeriesManager _tvSeriesManager;
private const string NS_DC = "http://purl.org/dc/elements/1.1/";
private const string NS_DIDL = "urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/";
@@ -53,7 +56,7 @@ namespace Emby.Dlna.ContentDirectory
private readonly DeviceProfile _profile;
- public ControlHandler(ILogger logger, ILibraryManager libraryManager, DeviceProfile profile, string serverAddress, string accessToken, IImageProcessor imageProcessor, IUserDataManager userDataManager, User user, int systemUpdateId, IServerConfigurationManager config, ILocalizationManager localization, IChannelManager channelManager, IMediaSourceManager mediaSourceManager, IUserViewManager userViewManager, IMediaEncoder mediaEncoder, IXmlReaderSettingsFactory xmlReaderSettingsFactory)
+ public ControlHandler(ILogger logger, ILibraryManager libraryManager, DeviceProfile profile, string serverAddress, string accessToken, IImageProcessor imageProcessor, IUserDataManager userDataManager, User user, int systemUpdateId, IServerConfigurationManager config, ILocalizationManager localization, IChannelManager channelManager, IMediaSourceManager mediaSourceManager, IUserViewManager userViewManager, IMediaEncoder mediaEncoder, IXmlReaderSettingsFactory xmlReaderSettingsFactory, ITVSeriesManager tvSeriesManager)
: base(config, logger, xmlReaderSettingsFactory)
{
_libraryManager = libraryManager;
@@ -62,6 +65,7 @@ namespace Emby.Dlna.ContentDirectory
_systemUpdateId = systemUpdateId;
_channelManager = channelManager;
_userViewManager = userViewManager;
+ _tvSeriesManager = tvSeriesManager;
_profile = profile;
_config = config;
@@ -454,14 +458,13 @@ namespace Emby.Dlna.ContentDirectory
{
Limit = limit,
StartIndex = startIndex,
- SortBy = sortOrders.ToArray(),
- SortOrder = sort.SortOrder,
+ OrderBy = sortOrders.Select(i => new Tuple<string, SortOrder>(i, sort.SortOrder)).ToArray(),
User = user,
Recursive = true,
IsMissing = false,
ExcludeItemTypes = new[] { typeof(Game).Name, typeof(Book).Name },
IsFolder = isFolder,
- MediaTypes = mediaTypes.ToArray(),
+ MediaTypes = mediaTypes.ToArray(mediaTypes.Count),
DtoOptions = GetDtoOptions()
});
}
@@ -483,31 +486,27 @@ namespace Emby.Dlna.ContentDirectory
return GetMusicArtistItems(item, null, user, sort, startIndex, limit);
}
+ if (item is Genre)
+ {
+ return GetGenreItems(item, null, user, sort, startIndex, limit);
+ }
+
var collectionFolder = item as ICollectionFolder;
if (collectionFolder != null && string.Equals(CollectionType.Music, collectionFolder.CollectionType, StringComparison.OrdinalIgnoreCase))
{
return GetMusicFolders(item, user, stubType, sort, startIndex, limit);
}
+ if (collectionFolder != null && string.Equals(CollectionType.Movies, collectionFolder.CollectionType, StringComparison.OrdinalIgnoreCase))
+ {
+ return GetMovieFolders(item, user, stubType, sort, startIndex, limit);
+ }
+ if (collectionFolder != null && string.Equals(CollectionType.TvShows, collectionFolder.CollectionType, StringComparison.OrdinalIgnoreCase))
+ {
+ return GetTvFolders(item, user, stubType, sort, startIndex, limit);
+ }
if (stubType.HasValue)
{
- if (stubType.Value == StubType.People)
- {
- var items = _libraryManager.GetPeopleItems(new InternalPeopleQuery
- {
- ItemId = item.Id
-
- }).ToArray();
-
- var result = new QueryResult<ServerItem>
- {
- Items = items.Select(i => new ServerItem(i)).ToArray(),
- TotalRecordCount = items.Length
- };
-
- return ApplyPaging(result, startIndex, limit);
- }
-
var person = item as Person;
if (person != null)
{
@@ -524,8 +523,8 @@ namespace Emby.Dlna.ContentDirectory
Limit = limit,
StartIndex = startIndex,
User = user,
- IsMissing = false,
- PresetViews = new[] { CollectionType.Movies, CollectionType.TvShows },
+ IsVirtualItem = false,
+ PresetViews = new string[] { },
ExcludeItemTypes = new[] { typeof(Game).Name, typeof(Book).Name },
IsPlaceHolder = false,
DtoOptions = GetDtoOptions()
@@ -651,11 +650,236 @@ namespace Emby.Dlna.ContentDirectory
return new QueryResult<ServerItem>
{
- Items = list.ToArray(),
+ Items = list.ToArray(list.Count),
TotalRecordCount = list.Count
};
}
+ private QueryResult<ServerItem> GetMovieFolders(BaseItem item, User user, StubType? stubType, SortCriteria sort, int? startIndex, int? limit)
+ {
+ var query = new InternalItemsQuery(user)
+ {
+ StartIndex = startIndex,
+ Limit = limit
+ };
+ SetSorting(query, sort, false);
+
+ if (stubType.HasValue && stubType.Value == StubType.ContinueWatching)
+ {
+ return GetMovieContinueWatching(item, user, query);
+ }
+
+ if (stubType.HasValue && stubType.Value == StubType.Latest)
+ {
+ return GetMovieLatest(item, user, query);
+ }
+
+ if (stubType.HasValue && stubType.Value == StubType.Movies)
+ {
+ return GetMovieMovies(item, user, query);
+ }
+
+ if (stubType.HasValue && stubType.Value == StubType.Collections)
+ {
+ return GetMovieCollections(item, user, query);
+ }
+
+ if (stubType.HasValue && stubType.Value == StubType.Favorites)
+ {
+ return GetMovieFavorites(item, user, query);
+ }
+
+ if (stubType.HasValue && stubType.Value == StubType.Genres)
+ {
+ return GetGenres(item, user, query);
+ }
+
+ var list = new List<ServerItem>();
+
+ list.Add(new ServerItem(item)
+ {
+ StubType = StubType.ContinueWatching
+ });
+
+ list.Add(new ServerItem(item)
+ {
+ StubType = StubType.Latest
+ });
+
+ list.Add(new ServerItem(item)
+ {
+ StubType = StubType.Movies
+ });
+
+ list.Add(new ServerItem(item)
+ {
+ StubType = StubType.Collections
+ });
+
+ list.Add(new ServerItem(item)
+ {
+ StubType = StubType.Favorites
+ });
+
+ list.Add(new ServerItem(item)
+ {
+ StubType = StubType.Genres
+ });
+
+ return new QueryResult<ServerItem>
+ {
+ Items = list.ToArray(list.Count),
+ TotalRecordCount = list.Count
+ };
+ }
+
+ private QueryResult<ServerItem> GetTvFolders(BaseItem item, User user, StubType? stubType, SortCriteria sort, int? startIndex, int? limit)
+ {
+ var query = new InternalItemsQuery(user)
+ {
+ StartIndex = startIndex,
+ Limit = limit
+ };
+ SetSorting(query, sort, false);
+
+ if (stubType.HasValue && stubType.Value == StubType.ContinueWatching)
+ {
+ return GetMovieContinueWatching(item, user, query);
+ }
+
+ if (stubType.HasValue && stubType.Value == StubType.NextUp)
+ {
+ return GetNextUp(item, user, query);
+ }
+
+ if (stubType.HasValue && stubType.Value == StubType.Latest)
+ {
+ return GetTvLatest(item, user, query);
+ }
+
+ if (stubType.HasValue && stubType.Value == StubType.Series)
+ {
+ return GetSeries(item, user, query);
+ }
+
+ if (stubType.HasValue && stubType.Value == StubType.FavoriteSeries)
+ {
+ return GetFavoriteSeries(item, user, query);
+ }
+
+ if (stubType.HasValue && stubType.Value == StubType.FavoriteEpisodes)
+ {
+ return GetFavoriteEpisodes(item, user, query);
+ }
+
+ if (stubType.HasValue && stubType.Value == StubType.Genres)
+ {
+ return GetGenres(item, user, query);
+ }
+
+ var list = new List<ServerItem>();
+
+ list.Add(new ServerItem(item)
+ {
+ StubType = StubType.ContinueWatching
+ });
+
+ list.Add(new ServerItem(item)
+ {
+ StubType = StubType.NextUp
+ });
+
+ list.Add(new ServerItem(item)
+ {
+ StubType = StubType.Latest
+ });
+
+ list.Add(new ServerItem(item)
+ {
+ StubType = StubType.Series
+ });
+
+ list.Add(new ServerItem(item)
+ {
+ StubType = StubType.FavoriteSeries
+ });
+
+ list.Add(new ServerItem(item)
+ {
+ StubType = StubType.FavoriteEpisodes
+ });
+
+ list.Add(new ServerItem(item)
+ {
+ StubType = StubType.Genres
+ });
+
+ return new QueryResult<ServerItem>
+ {
+ Items = list.ToArray(list.Count),
+ TotalRecordCount = list.Count
+ };
+ }
+
+ private QueryResult<ServerItem> GetMovieContinueWatching(BaseItem parent, User user, InternalItemsQuery query)
+ {
+ query.Recursive = true;
+ query.Parent = parent;
+ query.SetUser(user);
+
+ query.OrderBy = new Tuple<string, SortOrder>[]
+ {
+ new Tuple<string, SortOrder> (ItemSortBy.DatePlayed, SortOrder.Descending),
+ new Tuple<string, SortOrder> (ItemSortBy.SortName, SortOrder.Ascending)
+ };
+
+ query.IsResumable = true;
+ query.Limit = 10;
+
+ var result = _libraryManager.GetItemsResult(query);
+
+ return ToResult(result);
+ }
+
+ private QueryResult<ServerItem> GetSeries(BaseItem parent, User user, InternalItemsQuery query)
+ {
+ query.Recursive = true;
+ query.Parent = parent;
+ query.SetUser(user);
+
+ query.IncludeItemTypes = new[] { typeof(Series).Name };
+
+ var result = _libraryManager.GetItemsResult(query);
+
+ return ToResult(result);
+ }
+
+ private QueryResult<ServerItem> GetMovieMovies(BaseItem parent, User user, InternalItemsQuery query)
+ {
+ query.Recursive = true;
+ query.Parent = parent;
+ query.SetUser(user);
+
+ query.IncludeItemTypes = new[] { typeof(Movie).Name };
+
+ var result = _libraryManager.GetItemsResult(query);
+
+ return ToResult(result);
+ }
+
+ private QueryResult<ServerItem> GetMovieCollections(BaseItem parent, User user, InternalItemsQuery query)
+ {
+ query.Recursive = true;
+ //query.Parent = parent;
+ query.SetUser(user);
+
+ query.IncludeItemTypes = new[] { typeof(BoxSet).Name };
+
+ var result = _libraryManager.GetItemsResult(query);
+
+ return ToResult(result);
+ }
+
private QueryResult<ServerItem> GetMusicAlbums(BaseItem parent, User user, InternalItemsQuery query)
{
query.Recursive = true;
@@ -695,6 +919,45 @@ namespace Emby.Dlna.ContentDirectory
return ToResult(result);
}
+ private QueryResult<ServerItem> GetFavoriteSeries(BaseItem parent, User user, InternalItemsQuery query)
+ {
+ query.Recursive = true;
+ query.Parent = parent;
+ query.SetUser(user);
+ query.IsFavorite = true;
+ query.IncludeItemTypes = new[] { typeof(Series).Name };
+
+ var result = _libraryManager.GetItemsResult(query);
+
+ return ToResult(result);
+ }
+
+ private QueryResult<ServerItem> GetFavoriteEpisodes(BaseItem parent, User user, InternalItemsQuery query)
+ {
+ query.Recursive = true;
+ query.Parent = parent;
+ query.SetUser(user);
+ query.IsFavorite = true;
+ query.IncludeItemTypes = new[] { typeof(Episode).Name };
+
+ var result = _libraryManager.GetItemsResult(query);
+
+ return ToResult(result);
+ }
+
+ private QueryResult<ServerItem> GetMovieFavorites(BaseItem parent, User user, InternalItemsQuery query)
+ {
+ query.Recursive = true;
+ query.Parent = parent;
+ query.SetUser(user);
+ query.IsFavorite = true;
+ query.IncludeItemTypes = new[] { typeof(Movie).Name };
+
+ var result = _libraryManager.GetItemsResult(query);
+
+ return ToResult(result);
+ }
+
private QueryResult<ServerItem> GetFavoriteAlbums(BaseItem parent, User user, InternalItemsQuery query)
{
query.Recursive = true;
@@ -708,6 +971,24 @@ namespace Emby.Dlna.ContentDirectory
return ToResult(result);
}
+ private QueryResult<ServerItem> GetGenres(BaseItem parent, User user, InternalItemsQuery query)
+ {
+ var genresResult = _libraryManager.GetGenres(new InternalItemsQuery(user)
+ {
+ AncestorIds = new[] { parent.Id.ToString("N") },
+ StartIndex = query.StartIndex,
+ Limit = query.Limit
+ });
+
+ var result = new QueryResult<BaseItem>
+ {
+ TotalRecordCount = genresResult.TotalRecordCount,
+ Items = genresResult.Items.Select(i => i.Item1).ToArray(genresResult.Items.Length)
+ };
+
+ return ToResult(result);
+ }
+
private QueryResult<ServerItem> GetMusicGenres(BaseItem parent, User user, InternalItemsQuery query)
{
var genresResult = _libraryManager.GetMusicGenres(new InternalItemsQuery(user)
@@ -720,7 +1001,7 @@ namespace Emby.Dlna.ContentDirectory
var result = new QueryResult<BaseItem>
{
TotalRecordCount = genresResult.TotalRecordCount,
- Items = genresResult.Items.Select(i => i.Item1).ToArray()
+ Items = genresResult.Items.Select(i => i.Item1).ToArray(genresResult.Items.Length)
};
return ToResult(result);
@@ -738,7 +1019,7 @@ namespace Emby.Dlna.ContentDirectory
var result = new QueryResult<BaseItem>
{
TotalRecordCount = artists.TotalRecordCount,
- Items = artists.Items.Select(i => i.Item1).ToArray()
+ Items = artists.Items.Select(i => i.Item1).ToArray(artists.Items.Length)
};
return ToResult(result);
@@ -756,7 +1037,7 @@ namespace Emby.Dlna.ContentDirectory
var result = new QueryResult<BaseItem>
{
TotalRecordCount = artists.TotalRecordCount,
- Items = artists.Items.Select(i => i.Item1).ToArray()
+ Items = artists.Items.Select(i => i.Item1).ToArray(artists.Items.Length)
};
return ToResult(result);
@@ -775,7 +1056,7 @@ namespace Emby.Dlna.ContentDirectory
var result = new QueryResult<BaseItem>
{
TotalRecordCount = artists.TotalRecordCount,
- Items = artists.Items.Select(i => i.Item1).ToArray()
+ Items = artists.Items.Select(i => i.Item1).ToArray(artists.Items.Length)
};
return ToResult(result);
@@ -795,7 +1076,7 @@ namespace Emby.Dlna.ContentDirectory
private QueryResult<ServerItem> GetMusicLatest(BaseItem parent, User user, InternalItemsQuery query)
{
- query.SortBy = new string[] { };
+ query.OrderBy = new Tuple<string, SortOrder>[] { };
var items = _userViewManager.GetLatestItems(new LatestItemsQuery
{
@@ -810,6 +1091,55 @@ namespace Emby.Dlna.ContentDirectory
return ToResult(items);
}
+ private QueryResult<ServerItem> GetNextUp(BaseItem parent, User user, InternalItemsQuery query)
+ {
+ query.OrderBy = new Tuple<string, SortOrder>[] { };
+
+ var result = _tvSeriesManager.GetNextUp(new NextUpQuery
+ {
+ Limit = query.Limit,
+ StartIndex = query.StartIndex,
+ UserId = query.User.Id.ToString("N")
+
+ }, new List<Folder> { (Folder)parent }, query.DtoOptions);
+
+ return ToResult(result);
+ }
+
+ private QueryResult<ServerItem> GetTvLatest(BaseItem parent, User user, InternalItemsQuery query)
+ {
+ query.OrderBy = new Tuple<string, SortOrder>[] { };
+
+ var items = _userViewManager.GetLatestItems(new LatestItemsQuery
+ {
+ UserId = user.Id.ToString("N"),
+ Limit = 50,
+ IncludeItemTypes = new[] { typeof(Episode).Name },
+ ParentId = parent == null ? null : parent.Id.ToString("N"),
+ GroupItems = false
+
+ }, query.DtoOptions).Select(i => i.Item1 ?? i.Item2.FirstOrDefault()).Where(i => i != null).ToList();
+
+ return ToResult(items);
+ }
+
+ private QueryResult<ServerItem> GetMovieLatest(BaseItem parent, User user, InternalItemsQuery query)
+ {
+ query.OrderBy = new Tuple<string, SortOrder>[] { };
+
+ var items = _userViewManager.GetLatestItems(new LatestItemsQuery
+ {
+ UserId = user.Id.ToString("N"),
+ Limit = 50,
+ IncludeItemTypes = new[] { typeof(Movie).Name },
+ ParentId = parent == null ? null : parent.Id.ToString("N"),
+ GroupItems = true
+
+ }, query.DtoOptions).Select(i => i.Item1 ?? i.Item2.FirstOrDefault()).Where(i => i != null).ToList();
+
+ return ToResult(items);
+ }
+
private QueryResult<ServerItem> GetMusicArtistItems(BaseItem item, Guid? parentId, User user, SortCriteria sort, int? startIndex, int? limit)
{
var query = new InternalItemsQuery(user)
@@ -830,6 +1160,26 @@ namespace Emby.Dlna.ContentDirectory
return ToResult(result);
}
+ private QueryResult<ServerItem> GetGenreItems(BaseItem item, Guid? parentId, User user, SortCriteria sort, int? startIndex, int? limit)
+ {
+ var query = new InternalItemsQuery(user)
+ {
+ Recursive = true,
+ ParentId = parentId,
+ GenreIds = new[] { item.Id.ToString("N") },
+ IncludeItemTypes = new[] { typeof(Movie).Name, typeof(Series).Name },
+ Limit = limit,
+ StartIndex = startIndex,
+ DtoOptions = GetDtoOptions()
+ };
+
+ SetSorting(query, sort, false);
+
+ var result = _libraryManager.GetItemsResult(query);
+
+ return ToResult(result);
+ }
+
private QueryResult<ServerItem> GetMusicGenreItems(BaseItem item, Guid? parentId, User user, SortCriteria sort, int? startIndex, int? limit)
{
var query = new InternalItemsQuery(user)
@@ -854,7 +1204,7 @@ namespace Emby.Dlna.ContentDirectory
{
var serverItems = result
.Select(i => new ServerItem(i))
- .ToArray();
+ .ToArray(result.Count);
return new QueryResult<ServerItem>
{
@@ -868,7 +1218,7 @@ namespace Emby.Dlna.ContentDirectory
var serverItems = result
.Items
.Select(i => new ServerItem(i))
- .ToArray();
+ .ToArray(result.Items.Length);
return new QueryResult<ServerItem>
{
@@ -885,8 +1235,7 @@ namespace Emby.Dlna.ContentDirectory
sortOrders.Add(ItemSortBy.SortName);
}
- query.SortBy = sortOrders.ToArray();
- query.SortOrder = sort.SortOrder;
+ query.OrderBy = sortOrders.Select(i => new Tuple<string, SortOrder>(i, sort.SortOrder)).ToArray();
}
private QueryResult<ServerItem> GetItemsFromPerson(Person person, User user, int? startIndex, int? limit)
@@ -895,14 +1244,13 @@ namespace Emby.Dlna.ContentDirectory
{
PersonIds = new[] { person.Id.ToString("N") },
IncludeItemTypes = new[] { typeof(Movie).Name, typeof(Series).Name, typeof(Trailer).Name },
- SortBy = new[] { ItemSortBy.SortName },
+ OrderBy = new[] { ItemSortBy.SortName }.Select(i => new Tuple<string, SortOrder>(i, SortOrder.Ascending)).ToArray(),
Limit = limit,
StartIndex = startIndex,
DtoOptions = GetDtoOptions()
});
- var serverItems = itemsResult.Items.Select(i => new ServerItem(i))
- .ToArray();
+ var serverItems = itemsResult.Items.Select(i => new ServerItem(i)).ToArray(itemsResult.Items.Length);
return new QueryResult<ServerItem>
{
@@ -942,65 +1290,16 @@ namespace Emby.Dlna.ContentDirectory
id = parts[23];
}
- if (id.StartsWith("folder_", StringComparison.OrdinalIgnoreCase))
- {
- stubType = StubType.Folder;
- id = id.Split(new[] { '_' }, 2)[1];
- }
- else if (id.StartsWith("people_", StringComparison.OrdinalIgnoreCase))
- {
- stubType = StubType.People;
- id = id.Split(new[] { '_' }, 2)[1];
- }
- else if (id.StartsWith("latest_", StringComparison.OrdinalIgnoreCase))
- {
- stubType = StubType.Latest;
- id = id.Split(new[] { '_' }, 2)[1];
- }
- else if (id.StartsWith("playlists_", StringComparison.OrdinalIgnoreCase))
- {
- stubType = StubType.Playlists;
- id = id.Split(new[] { '_' }, 2)[1];
- }
- else if (id.StartsWith("Albums_", StringComparison.OrdinalIgnoreCase))
- {
- stubType = StubType.Albums;
- id = id.Split(new[] { '_' }, 2)[1];
- }
- else if (id.StartsWith("AlbumArtists_", StringComparison.OrdinalIgnoreCase))
- {
- stubType = StubType.AlbumArtists;
- id = id.Split(new[] { '_' }, 2)[1];
- }
- else if (id.StartsWith("Artists_", StringComparison.OrdinalIgnoreCase))
- {
- stubType = StubType.Artists;
- id = id.Split(new[] { '_' }, 2)[1];
- }
- else if (id.StartsWith("Genres_", StringComparison.OrdinalIgnoreCase))
- {
- stubType = StubType.Genres;
- id = id.Split(new[] { '_' }, 2)[1];
- }
- else if (id.StartsWith("Songs_", StringComparison.OrdinalIgnoreCase))
- {
- stubType = StubType.Songs;
- id = id.Split(new[] { '_' }, 2)[1];
- }
- else if (id.StartsWith("FavoriteAlbums_", StringComparison.OrdinalIgnoreCase))
- {
- stubType = StubType.FavoriteAlbums;
- id = id.Split(new[] { '_' }, 2)[1];
- }
- else if (id.StartsWith("FavoriteArtists_", StringComparison.OrdinalIgnoreCase))
+ var enumNames = Enum.GetNames(typeof(StubType));
+ foreach (var name in enumNames)
{
- stubType = StubType.FavoriteArtists;
- id = id.Split(new[] { '_' }, 2)[1];
- }
- else if (id.StartsWith("FavoriteSongs_", StringComparison.OrdinalIgnoreCase))
- {
- stubType = StubType.FavoriteSongs;
- id = id.Split(new[] { '_' }, 2)[1];
+ if (id.StartsWith(name + "_", StringComparison.OrdinalIgnoreCase))
+ {
+ stubType = (StubType)Enum.Parse(typeof(StubType), name, true);
+ id = id.Split(new[] { '_' }, 2)[1];
+
+ break;
+ }
}
if (Guid.TryParse(id, out itemId))
@@ -1038,7 +1337,6 @@ namespace Emby.Dlna.ContentDirectory
public enum StubType
{
Folder = 0,
- People = 1,
Latest = 2,
Playlists = 3,
Albums = 4,
@@ -1048,6 +1346,14 @@ namespace Emby.Dlna.ContentDirectory
Genres = 8,
FavoriteSongs = 9,
FavoriteArtists = 10,
- FavoriteAlbums = 11
+ FavoriteAlbums = 11,
+ ContinueWatching = 12,
+ Movies = 13,
+ Collections = 14,
+ Favorites = 15,
+ NextUp = 16,
+ Series = 17,
+ FavoriteSeries = 18,
+ FavoriteEpisodes = 19
}
}
diff --git a/Emby.Dlna/Didl/DidlBuilder.cs b/Emby.Dlna/Didl/DidlBuilder.cs
index d2a160cf7..844a6a5ce 100644
--- a/Emby.Dlna/Didl/DidlBuilder.cs
+++ b/Emby.Dlna/Didl/DidlBuilder.cs
@@ -193,12 +193,12 @@ namespace Emby.Dlna.Didl
{
if (streamInfo == null)
{
- var sources = _mediaSourceManager.GetStaticMediaSources(video, true, _user).ToList();
+ var sources = _mediaSourceManager.GetStaticMediaSources(video, true, _user);
streamInfo = new StreamBuilder(_mediaEncoder, GetStreamBuilderLogger(options)).BuildVideoItem(new VideoOptions
{
ItemId = GetClientId(video),
- MediaSources = sources,
+ MediaSources = sources.ToArray(sources.Count),
Profile = _profile,
DeviceId = deviceId,
MaxBitrate = _profile.MaxStreamingBitrate
@@ -236,7 +236,7 @@ namespace Emby.Dlna.Didl
AddVideoResource(writer, video, deviceId, filter, contentFeature, streamInfo);
}
- var subtitleProfiles = streamInfo.GetSubtitleProfiles(false, _serverAddress, _accessToken)
+ var subtitleProfiles = streamInfo.GetSubtitleProfiles(_mediaEncoder, false, _serverAddress, _accessToken)
.Where(subtitle => subtitle.DeliveryMethod == SubtitleDeliveryMethod.External)
.ToList();
@@ -391,14 +391,6 @@ namespace Emby.Dlna.Didl
private string GetDisplayName(BaseItem item, StubType? itemStubType, BaseItem context)
{
- if (itemStubType.HasValue && itemStubType.Value == StubType.People)
- {
- if (item is Video)
- {
- return _localization.GetLocalizedString("HeaderCastCrew");
- }
- return _localization.GetLocalizedString("HeaderPeople");
- }
if (itemStubType.HasValue && itemStubType.Value == StubType.Latest)
{
return _localization.GetLocalizedString("ViewTypeMusicLatest");
@@ -439,6 +431,38 @@ namespace Emby.Dlna.Didl
{
return _localization.GetLocalizedString("ViewTypeMusicFavoriteSongs");
}
+ if (itemStubType.HasValue && itemStubType.Value == StubType.ContinueWatching)
+ {
+ return _localization.GetLocalizedString("ViewTypeMovieResume");
+ }
+ if (itemStubType.HasValue && itemStubType.Value == StubType.Movies)
+ {
+ return _localization.GetLocalizedString("ViewTypeMovieMovies");
+ }
+ if (itemStubType.HasValue && itemStubType.Value == StubType.Collections)
+ {
+ return _localization.GetLocalizedString("ViewTypeMovieCollections");
+ }
+ if (itemStubType.HasValue && itemStubType.Value == StubType.Favorites)
+ {
+ return _localization.GetLocalizedString("ViewTypeMovieFavorites");
+ }
+ if (itemStubType.HasValue && itemStubType.Value == StubType.NextUp)
+ {
+ return _localization.GetLocalizedString("ViewTypeTvNextUp");
+ }
+ if (itemStubType.HasValue && itemStubType.Value == StubType.FavoriteSeries)
+ {
+ return _localization.GetLocalizedString("ViewTypeTvFavoriteSeries");
+ }
+ if (itemStubType.HasValue && itemStubType.Value == StubType.FavoriteEpisodes)
+ {
+ return _localization.GetLocalizedString("ViewTypeTvFavoriteEpisodes");
+ }
+ if (itemStubType.HasValue && itemStubType.Value == StubType.Series)
+ {
+ return _localization.GetLocalizedString("ViewTypeTvShowSeries");
+ }
var episode = item as Episode;
var season = context as Season;
@@ -476,12 +500,12 @@ namespace Emby.Dlna.Didl
if (streamInfo == null)
{
- var sources = _mediaSourceManager.GetStaticMediaSources(audio, true, _user).ToList();
+ var sources = _mediaSourceManager.GetStaticMediaSources(audio, true, _user);
streamInfo = new StreamBuilder(_mediaEncoder, GetStreamBuilderLogger(options)).BuildAudioItem(new AudioOptions
{
ItemId = GetClientId(audio),
- MediaSources = sources,
+ MediaSources = sources.ToArray(sources.Count),
Profile = _profile,
DeviceId = deviceId
});
@@ -629,7 +653,7 @@ namespace Emby.Dlna.Didl
return;
}
- XmlAttribute secAttribute = null;
+ MediaBrowser.Model.Dlna.XmlAttribute secAttribute = null;
foreach (var attribute in _profile.XmlRootAttributes)
{
if (string.Equals(attribute.Name, "xmlns:sec", StringComparison.OrdinalIgnoreCase))
@@ -929,12 +953,6 @@ namespace Emby.Dlna.Didl
private void AddCover(BaseItem item, BaseItem context, StubType? stubType, XmlWriter writer)
{
- if (stubType.HasValue && stubType.Value == StubType.People)
- {
- AddEmbeddedImageAsCover("people", writer);
- return;
- }
-
ImageDownloadInfo imageInfo = null;
if (context is UserView)
diff --git a/Emby.Dlna/Didl/Filter.cs b/Emby.Dlna/Didl/Filter.cs
index 5e9aeb530..2c9a1ea18 100644
--- a/Emby.Dlna/Didl/Filter.cs
+++ b/Emby.Dlna/Didl/Filter.cs
@@ -1,13 +1,12 @@
using MediaBrowser.Model.Extensions;
using System;
using System.Collections.Generic;
-using System.Linq;
namespace Emby.Dlna.Didl
{
public class Filter
{
- private readonly List<string> _fields;
+ private readonly string[] _fields;
private readonly bool _all;
public Filter()
@@ -20,9 +19,7 @@ namespace Emby.Dlna.Didl
{
_all = StringHelper.EqualsIgnoreCase(filter, "*");
- var list = (filter ?? string.Empty).Split(new[] {','}, StringSplitOptions.RemoveEmptyEntries).ToList();
-
- _fields = list;
+ _fields = (filter ?? string.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
}
public bool Contains(string field)
diff --git a/Emby.Dlna/Didl/StringWriterWithEncoding.cs b/Emby.Dlna/Didl/StringWriterWithEncoding.cs
index 052d6610b..b5c565801 100644
--- a/Emby.Dlna/Didl/StringWriterWithEncoding.cs
+++ b/Emby.Dlna/Didl/StringWriterWithEncoding.cs
@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.IO;
-using System.Linq;
using System.Text;
using System.Threading.Tasks;
diff --git a/Emby.Dlna/DlnaManager.cs b/Emby.Dlna/DlnaManager.cs
index 82975ce22..bdc523c8b 100644
--- a/Emby.Dlna/DlnaManager.cs
+++ b/Emby.Dlna/DlnaManager.cs
@@ -18,6 +18,7 @@ using System.Text;
using System.Text.RegularExpressions;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Reflection;
+using MediaBrowser.Model.Extensions;
namespace Emby.Dlna
{
@@ -106,7 +107,6 @@ namespace Emby.Dlna
}
else
{
- _logger.Debug("No matching device profile found. The default will need to be used.");
LogUnmatchedProfile(deviceInfo);
}
@@ -220,12 +220,8 @@ namespace Emby.Dlna
}
else
{
- var msg = new StringBuilder();
- foreach (var header in headers)
- {
- msg.AppendLine(header.Key + ": " + header.Value);
- }
- _logger.LogMultiline("No matching device profile found. The default will need to be used.", LogSeverity.Info, msg);
+ var headerString = string.Join(", ", headers.Select(i => string.Format("{0}={1}", i.Key, i.Value)).ToArray(headers.Count));
+ _logger.Debug("No matching device profile found. {0}", headerString);
}
return profile;
@@ -320,7 +316,6 @@ namespace Emby.Dlna
profile = ReserializeProfile(tempProfile);
profile.Id = path.ToLower().GetMD5().ToString("N");
- profile.ProfileType = type;
_profiles[path] = new Tuple<InternalProfileInfo, DeviceProfile>(GetInternalProfileInfo(_fileSystem.GetFileInfo(path), type), profile);
@@ -601,6 +596,7 @@ namespace Emby.Dlna
public void Dispose()
{
+ GC.SuppressFinalize(this);
}
}
} \ No newline at end of file
diff --git a/Emby.Dlna/Main/DlnaEntryPoint.cs b/Emby.Dlna/Main/DlnaEntryPoint.cs
index 16108522c..3dd36a27b 100644
--- a/Emby.Dlna/Main/DlnaEntryPoint.cs
+++ b/Emby.Dlna/Main/DlnaEntryPoint.cs
@@ -158,7 +158,7 @@ namespace Emby.Dlna.Main
{
if (_communicationsServer == null)
{
- var enableMultiSocketBinding = _environmentInfo.OperatingSystem == OperatingSystem.Windows;
+ var enableMultiSocketBinding = _environmentInfo.OperatingSystem == MediaBrowser.Model.System.OperatingSystem.Windows;
_communicationsServer = new SsdpCommunicationsServer(_socketFactory, _networkManager, _logger, enableMultiSocketBinding)
{
@@ -394,6 +394,7 @@ namespace Emby.Dlna.Main
_communicationsServer.Dispose();
_communicationsServer = null;
}
+ GC.SuppressFinalize(this);
}
public void DisposeDlnaServer()
diff --git a/Emby.Dlna/MediaReceiverRegistrar/MediaReceiverRegistrar.cs b/Emby.Dlna/MediaReceiverRegistrar/MediaReceiverRegistrar.cs
index 365354efd..4ed74a684 100644
--- a/Emby.Dlna/MediaReceiverRegistrar/MediaReceiverRegistrar.cs
+++ b/Emby.Dlna/MediaReceiverRegistrar/MediaReceiverRegistrar.cs
@@ -9,7 +9,7 @@ using MediaBrowser.Model.Xml;
namespace Emby.Dlna.MediaReceiverRegistrar
{
- public class MediaReceiverRegistrar : BaseService, IMediaReceiverRegistrar, IDisposable
+ public class MediaReceiverRegistrar : BaseService, IMediaReceiverRegistrar
{
private readonly IServerConfigurationManager _config;
protected readonly IXmlReaderSettingsFactory XmlReaderSettingsFactory;
@@ -33,10 +33,5 @@ namespace Emby.Dlna.MediaReceiverRegistrar
Logger, XmlReaderSettingsFactory)
.ProcessControlRequest(request);
}
-
- public void Dispose()
- {
-
- }
}
}
diff --git a/Emby.Dlna/PlayTo/Device.cs b/Emby.Dlna/PlayTo/Device.cs
index e22298010..5a63be304 100644
--- a/Emby.Dlna/PlayTo/Device.cs
+++ b/Emby.Dlna/PlayTo/Device.cs
@@ -15,6 +15,7 @@ using System.Threading.Tasks;
using System.Xml.Linq;
using Emby.Dlna.Server;
using MediaBrowser.Model.Threading;
+using MediaBrowser.Model.Extensions;
namespace Emby.Dlna.PlayTo
{
@@ -112,7 +113,7 @@ namespace Emby.Dlna.PlayTo
private int GetInactiveTimerIntervalMs()
{
- return 30000;
+ return Timeout.Infinite;
}
public void Start()
@@ -160,18 +161,15 @@ namespace Emby.Dlna.PlayTo
if (_disposed)
return;
- if (!_timerActive)
+ lock (_timerLock)
{
- lock (_timerLock)
+ if (!_timerActive)
{
- if (!_timerActive)
- {
- _logger.Debug("RestartTimer");
- _timer.Change(10, GetPlaybackTimerIntervalMs());
- }
-
- _timerActive = true;
+ _logger.Debug("RestartTimer");
+ _timer.Change(10, GetPlaybackTimerIntervalMs());
}
+
+ _timerActive = true;
}
}
@@ -183,23 +181,20 @@ namespace Emby.Dlna.PlayTo
if (_disposed)
return;
- if (_timerActive)
+ lock (_timerLock)
{
- lock (_timerLock)
+ if (_timerActive)
{
- if (_timerActive)
- {
- _logger.Debug("RestartTimerInactive");
- var interval = GetInactiveTimerIntervalMs();
+ _logger.Debug("RestartTimerInactive");
+ var interval = GetInactiveTimerIntervalMs();
- if (_timer != null)
- {
- _timer.Change(interval, interval);
- }
+ if (_timer != null)
+ {
+ _timer.Change(interval, interval);
}
-
- _timerActive = false;
}
+
+ _timerActive = false;
}
}
@@ -492,6 +487,10 @@ namespace Emby.Dlna.PlayTo
RestartTimer();
}
}
+ else
+ {
+ RestartTimerInactive();
+ }
}
catch (HttpException ex)
{
@@ -890,7 +889,7 @@ namespace Emby.Dlna.PlayTo
if (room != null && !string.IsNullOrWhiteSpace(room.Value))
friendlyNames.Add(room.Value);
- deviceProperties.Name = string.Join(" ", friendlyNames.ToArray());
+ deviceProperties.Name = string.Join(" ", friendlyNames.ToArray(friendlyNames.Count));
var model = document.Descendants(uPnpNamespaces.ud.GetName("modelName")).FirstOrDefault();
if (model != null)
@@ -1106,6 +1105,7 @@ namespace Emby.Dlna.PlayTo
_disposed = true;
DisposeTimer();
+ GC.SuppressFinalize(this);
}
}
diff --git a/Emby.Dlna/PlayTo/PlayToController.cs b/Emby.Dlna/PlayTo/PlayToController.cs
index 15d73e824..e8d7c9127 100644
--- a/Emby.Dlna/PlayTo/PlayToController.cs
+++ b/Emby.Dlna/PlayTo/PlayToController.cs
@@ -13,13 +13,13 @@ using MediaBrowser.Model.System;
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.MediaEncoding;
using MediaBrowser.Model.Events;
using MediaBrowser.Model.Globalization;
+using MediaBrowser.Model.Extensions;
namespace Emby.Dlna.PlayTo
{
@@ -48,7 +48,7 @@ namespace Emby.Dlna.PlayTo
{
get
{
- var lastDateKnownActivity = new[] { _creationTime, _device.DateLastActivity }.Max();
+ var lastDateKnownActivity = _creationTime > _device.DateLastActivity ? _creationTime : _device.DateLastActivity;
if (DateTime.UtcNow >= lastDateKnownActivity.AddSeconds(120))
{
@@ -386,6 +386,9 @@ namespace Emby.Dlna.PlayTo
case PlaystateCommand.Unpause:
return _device.SetPlay();
+ case PlaystateCommand.PlayPause:
+ return _device.IsPaused ? _device.SetPlay() : _device.SetPause();
+
case PlaystateCommand.Seek:
{
return Seek(command.SeekPositionTicks ?? 0);
@@ -503,7 +506,7 @@ namespace Emby.Dlna.PlayTo
var hasMediaSources = item as IHasMediaSources;
var mediaSources = hasMediaSources != null
- ? (_mediaSourceManager.GetStaticMediaSources(hasMediaSources, true, user)).ToList()
+ ? (_mediaSourceManager.GetStaticMediaSources(hasMediaSources, true, user))
: new List<MediaSourceInfo>();
var playlistItem = GetPlaylistItem(item, mediaSources, profile, _session.DeviceId, mediaSourceId, audioStreamIndex, subtitleStreamIndex);
@@ -564,7 +567,7 @@ namespace Emby.Dlna.PlayTo
streamInfo.TargetVideoCodecTag,
streamInfo.IsTargetAVC);
- return list.FirstOrDefault();
+ return list.Count == 0 ? null : list[0];
}
return null;
@@ -589,7 +592,7 @@ namespace Emby.Dlna.PlayTo
StreamInfo = new StreamBuilder(_mediaEncoder, GetStreamBuilderLogger()).BuildVideoItem(new VideoOptions
{
ItemId = item.Id.ToString("N"),
- MediaSources = mediaSources,
+ MediaSources = mediaSources.ToArray(mediaSources.Count),
Profile = profile,
DeviceId = deviceId,
MaxBitrate = profile.MaxStreamingBitrate,
@@ -609,7 +612,7 @@ namespace Emby.Dlna.PlayTo
StreamInfo = new StreamBuilder(_mediaEncoder, GetStreamBuilderLogger()).BuildAudioItem(new AudioOptions
{
ItemId = item.Id.ToString("N"),
- MediaSources = mediaSources,
+ MediaSources = mediaSources.ToArray(mediaSources.Count),
Profile = profile,
DeviceId = deviceId,
MaxBitrate = profile.MaxStreamingBitrate,
@@ -682,6 +685,7 @@ namespace Emby.Dlna.PlayTo
_device.OnDeviceUnavailable = null;
_device.Dispose();
+ GC.SuppressFinalize(this);
}
}
diff --git a/Emby.Dlna/PlayTo/PlayToManager.cs b/Emby.Dlna/PlayTo/PlayToManager.cs
index 32f542e73..6f2f5f24b 100644
--- a/Emby.Dlna/PlayTo/PlayToManager.cs
+++ b/Emby.Dlna/PlayTo/PlayToManager.cs
@@ -182,7 +182,7 @@ namespace Emby.Dlna.PlayTo
{
PlayableMediaTypes = profile.GetSupportedMediaTypes(),
- SupportedCommands = new List<string>
+ SupportedCommands = new string[]
{
GeneralCommandType.VolumeDown.ToString(),
GeneralCommandType.VolumeUp.ToString(),
@@ -225,6 +225,7 @@ namespace Emby.Dlna.PlayTo
{
_disposed = true;
_deviceDiscovery.DeviceDiscovered -= _deviceDiscovery_DeviceDiscovered;
+ GC.SuppressFinalize(this);
}
}
}
diff --git a/Emby.Dlna/Profiles/DefaultProfile.cs b/Emby.Dlna/Profiles/DefaultProfile.cs
index 06ce93640..46639ee42 100644
--- a/Emby.Dlna/Profiles/DefaultProfile.cs
+++ b/Emby.Dlna/Profiles/DefaultProfile.cs
@@ -1,6 +1,7 @@
using MediaBrowser.Model.Dlna;
using System.Linq;
using System.Xml.Serialization;
+using MediaBrowser.Model.Extensions;
namespace Emby.Dlna.Profiles
{
@@ -172,7 +173,7 @@ namespace Emby.Dlna.Profiles
Value = value
});
- XmlRootAttributes = list.ToArray();
+ XmlRootAttributes = list.ToArray(list.Count);
}
}
}
diff --git a/Emby.Dlna/Profiles/PanasonicVieraProfile.cs b/Emby.Dlna/Profiles/PanasonicVieraProfile.cs
index 63c7e3a8e..eb9cf9528 100644
--- a/Emby.Dlna/Profiles/PanasonicVieraProfile.cs
+++ b/Emby.Dlna/Profiles/PanasonicVieraProfile.cs
@@ -16,14 +16,14 @@ namespace Emby.Dlna.Profiles
Manufacturer = "Panasonic",
Headers = new[]
- {
- new HttpHeaderInfo
- {
- Name = "User-Agent",
- Value = "Panasonic MIL DLNA",
- Match = HeaderMatchType.Substring
- }
- }
+ {
+ new HttpHeaderInfo
+ {
+ Name = "User-Agent",
+ Value = "Panasonic MIL DLNA",
+ Match = HeaderMatchType.Substring
+ }
+ }
};
AddXmlRootAttribute("xmlns:pv", "http://www.pv.com/pvns/");
@@ -31,105 +31,105 @@ namespace Emby.Dlna.Profiles
TimelineOffsetSeconds = 10;
TranscodingProfiles = new[]
- {
- new TranscodingProfile
- {
- Container = "mp3",
- AudioCodec = "mp3",
- Type = DlnaProfileType.Audio
- },
- new TranscodingProfile
- {
- Container = "ts",
- AudioCodec = "ac3",
- VideoCodec = "h264",
- Type = DlnaProfileType.Video
- },
- new TranscodingProfile
- {
- Container = "jpeg",
- Type = DlnaProfileType.Photo
- }
- };
+ {
+ new TranscodingProfile
+ {
+ Container = "mp3",
+ AudioCodec = "mp3",
+ Type = DlnaProfileType.Audio
+ },
+ new TranscodingProfile
+ {
+ Container = "ts",
+ AudioCodec = "ac3",
+ VideoCodec = "h264",
+ Type = DlnaProfileType.Video
+ },
+ new TranscodingProfile
+ {
+ Container = "jpeg",
+ Type = DlnaProfileType.Photo
+ }
+ };
DirectPlayProfiles = new[]
- {
- new DirectPlayProfile
- {
- Container = "mpeg,mpg",
- VideoCodec = "mpeg2video,mpeg4",
- AudioCodec = "ac3,mp3,pcm_dvd",
- Type = DlnaProfileType.Video
- },
-
- new DirectPlayProfile
- {
- Container = "mkv",
- VideoCodec = "h264,mpeg2video",
- AudioCodec = "aac,ac3,dca,mp3,mp2,pcm,dts",
- Type = DlnaProfileType.Video
- },
-
- new DirectPlayProfile
- {
- Container = "ts",
- VideoCodec = "h264,mpeg2video",
- AudioCodec = "aac,mp3,mp2",
- Type = DlnaProfileType.Video
- },
-
- new DirectPlayProfile
- {
- Container = "mp4,m4v",
- VideoCodec = "h264",
- AudioCodec = "aac,ac3,mp3,pcm",
- Type = DlnaProfileType.Video
- },
-
- new DirectPlayProfile
- {
- Container = "mov",
- VideoCodec = "h264",
- AudioCodec = "aac,pcm",
- Type = DlnaProfileType.Video
- },
-
- new DirectPlayProfile
- {
- Container = "avi",
- VideoCodec = "mpeg4",
- AudioCodec = "pcm",
- Type = DlnaProfileType.Video
- },
-
- new DirectPlayProfile
- {
- Container = "flv",
- VideoCodec = "h264",
- AudioCodec = "aac",
- Type = DlnaProfileType.Video
- },
-
- new DirectPlayProfile
- {
- Container = "mp3",
- AudioCodec = "mp3",
- Type = DlnaProfileType.Audio
- },
-
- new DirectPlayProfile
- {
- Container = "mp4",
- AudioCodec = "aac",
- Type = DlnaProfileType.Audio
- },
-
- new DirectPlayProfile
- {
- Container = "jpeg",
- Type = DlnaProfileType.Photo
- }
- };
+ {
+ new DirectPlayProfile
+ {
+ Container = "mpeg,mpg",
+ VideoCodec = "mpeg2video,mpeg4",
+ AudioCodec = "ac3,mp3,pcm_dvd",
+ Type = DlnaProfileType.Video
+ },
+
+ new DirectPlayProfile
+ {
+ Container = "mkv",
+ VideoCodec = "h264,mpeg2video",
+ AudioCodec = "aac,ac3,dca,mp3,mp2,pcm,dts",
+ Type = DlnaProfileType.Video
+ },
+
+ new DirectPlayProfile
+ {
+ Container = "ts",
+ VideoCodec = "h264,mpeg2video",
+ AudioCodec = "aac,mp3,mp2",
+ Type = DlnaProfileType.Video
+ },
+
+ new DirectPlayProfile
+ {
+ Container = "mp4,m4v",
+ VideoCodec = "h264",
+ AudioCodec = "aac,ac3,mp3,pcm",
+ Type = DlnaProfileType.Video
+ },
+
+ new DirectPlayProfile
+ {
+ Container = "mov",
+ VideoCodec = "h264",
+ AudioCodec = "aac,pcm",
+ Type = DlnaProfileType.Video
+ },
+
+ new DirectPlayProfile
+ {
+ Container = "avi",
+ VideoCodec = "mpeg4",
+ AudioCodec = "pcm",
+ Type = DlnaProfileType.Video
+ },
+
+ new DirectPlayProfile
+ {
+ Container = "flv",
+ VideoCodec = "h264",
+ AudioCodec = "aac",
+ Type = DlnaProfileType.Video
+ },
+
+ new DirectPlayProfile
+ {
+ Container = "mp3",
+ AudioCodec = "mp3",
+ Type = DlnaProfileType.Audio
+ },
+
+ new DirectPlayProfile
+ {
+ Container = "mp4",
+ AudioCodec = "aac",
+ Type = DlnaProfileType.Audio
+ },
+
+ new DirectPlayProfile
+ {
+ Container = "jpeg",
+ Type = DlnaProfileType.Photo
+ }
+ };
ContainerProfiles = new[]
{
@@ -156,35 +156,35 @@ namespace Emby.Dlna.Profiles
};
CodecProfiles = new[]
- {
- new CodecProfile
- {
- Type = CodecType.Video,
-
- Conditions = new[]
- {
- new ProfileCondition
- {
- Condition = ProfileConditionType.LessThanEqual,
- Property = ProfileConditionValue.Width,
- Value = "1920"
- },
- new ProfileCondition
- {
- Condition = ProfileConditionType.LessThanEqual,
- Property = ProfileConditionValue.Height,
- Value = "1080"
- },
- new ProfileCondition
- {
- Condition = ProfileConditionType.LessThanEqual,
- Property = ProfileConditionValue.VideoBitDepth,
- Value = "8",
- IsRequired = false
- }
- }
- }
- };
+ {
+ new CodecProfile
+ {
+ Type = CodecType.Video,
+
+ Conditions = new[]
+ {
+ new ProfileCondition
+ {
+ Condition = ProfileConditionType.LessThanEqual,
+ Property = ProfileConditionValue.Width,
+ Value = "1920"
+ },
+ new ProfileCondition
+ {
+ Condition = ProfileConditionType.LessThanEqual,
+ Property = ProfileConditionValue.Height,
+ Value = "1080"
+ },
+ new ProfileCondition
+ {
+ Condition = ProfileConditionType.LessThanEqual,
+ Property = ProfileConditionValue.VideoBitDepth,
+ Value = "8",
+ IsRequired = false
+ }
+ }
+ }
+ };
SubtitleProfiles = new[]
{
@@ -218,4 +218,4 @@ namespace Emby.Dlna.Profiles
};
}
}
-}
+} \ No newline at end of file
diff --git a/Emby.Dlna/Server/DescriptionXmlBuilder.cs b/Emby.Dlna/Server/DescriptionXmlBuilder.cs
index 2a4a5792f..bba4adc5f 100644
--- a/Emby.Dlna/Server/DescriptionXmlBuilder.cs
+++ b/Emby.Dlna/Server/DescriptionXmlBuilder.cs
@@ -226,7 +226,7 @@ namespace Emby.Dlna.Server
}
}
- var characters = characterList.ToArray();
+ var characters = characterList.ToArray(characterList.Count);
var serverName = new string(characters);
diff --git a/Emby.Dlna/Service/BaseControlHandler.cs b/Emby.Dlna/Service/BaseControlHandler.cs
index 3092589c1..7cd10bd01 100644
--- a/Emby.Dlna/Service/BaseControlHandler.cs
+++ b/Emby.Dlna/Service/BaseControlHandler.cs
@@ -11,6 +11,7 @@ using System.Xml;
using Emby.Dlna.Didl;
using MediaBrowser.Controller.Extensions;
using MediaBrowser.Model.Xml;
+using MediaBrowser.Model.Extensions;
namespace Emby.Dlna.Service
{
@@ -235,26 +236,29 @@ namespace Emby.Dlna.Service
private void LogRequest(ControlRequest request)
{
- var builder = new StringBuilder();
+ if (!Config.GetDlnaConfiguration().EnableDebugLog)
+ {
+ return;
+ }
- var headers = string.Join(", ", request.Headers.Select(i => string.Format("{0}={1}", i.Key, i.Value)).ToArray());
- builder.AppendFormat("Headers: {0}", headers);
- builder.AppendLine();
- //builder.Append(request.InputXml);
+ var originalHeaders = request.Headers;
+ var headers = string.Join(", ", originalHeaders.Select(i => string.Format("{0}={1}", i.Key, i.Value)).ToArray(originalHeaders.Count));
- Logger.LogMultiline("Control request", LogSeverity.Debug, builder);
+ Logger.Debug("Control request. Headers: {0}", headers);
}
private void LogResponse(ControlResponse response)
{
- var builder = new StringBuilder();
+ if (!Config.GetDlnaConfiguration().EnableDebugLog)
+ {
+ return;
+ }
- var headers = string.Join(", ", response.Headers.Select(i => string.Format("{0}={1}", i.Key, i.Value)).ToArray());
- builder.AppendFormat("Headers: {0}", headers);
- builder.AppendLine();
- builder.Append(response.Xml);
+ var originalHeaders = response.Headers;
+ var headers = string.Join(", ", originalHeaders.Select(i => string.Format("{0}={1}", i.Key, i.Value)).ToArray(originalHeaders.Count));
+ //builder.Append(response.Xml);
- Logger.LogMultiline("Control response", LogSeverity.Debug, builder);
+ Logger.Debug("Control response. Headers: {0}", headers);
}
}
}
diff --git a/Emby.Dlna/Ssdp/Extensions.cs b/Emby.Dlna/Ssdp/Extensions.cs
index 611bf7e02..41a361515 100644
--- a/Emby.Dlna/Ssdp/Extensions.cs
+++ b/Emby.Dlna/Ssdp/Extensions.cs
@@ -1,5 +1,4 @@
using System;
-using System.Linq;
using System.Net;
using System.Threading.Tasks;
using System.Xml.Linq;
@@ -24,10 +23,12 @@ namespace Emby.Dlna.Ssdp
public static string GetDescendantValue(this XElement container, XName name)
{
- var node = container.Descendants(name)
- .FirstOrDefault();
+ foreach (var node in container.Descendants(name))
+ {
+ return node.Value;
+ }
- return node == null ? null : node.Value;
+ return null;
}
}
}
diff --git a/Emby.Drawing.ImageMagick/Emby.Drawing.ImageMagick.csproj b/Emby.Drawing.ImageMagick/Emby.Drawing.ImageMagick.csproj
index 98e99c92b..c4cef629a 100644
--- a/Emby.Drawing.ImageMagick/Emby.Drawing.ImageMagick.csproj
+++ b/Emby.Drawing.ImageMagick/Emby.Drawing.ImageMagick.csproj
@@ -31,8 +31,7 @@
</PropertyGroup>
<ItemGroup>
<Reference Include="ImageMagickSharp, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
- <HintPath>..\packages\ImageMagickSharp.1.0.0.18\lib\net45\ImageMagickSharp.dll</HintPath>
- <Private>True</Private>
+ <HintPath>..\packages\ImageMagickSharp.1.0.0.19\lib\net45\ImageMagickSharp.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
@@ -56,9 +55,6 @@
<EmbeddedResource Include="fonts\robotoregular.ttf" />
</ItemGroup>
<ItemGroup>
- <None Include="packages.config" />
- </ItemGroup>
- <ItemGroup>
<ProjectReference Include="..\MediaBrowser.Common\MediaBrowser.Common.csproj">
<Project>{9142eefa-7570-41e1-bfcc-468bb571af2f}</Project>
<Name>MediaBrowser.Common</Name>
@@ -72,6 +68,9 @@
<Name>MediaBrowser.Model</Name>
</ProjectReference>
</ItemGroup>
+ <ItemGroup>
+ <None Include="packages.config" />
+ </ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
diff --git a/Emby.Drawing.ImageMagick/ImageHelpers.cs b/Emby.Drawing.ImageMagick/ImageHelpers.cs
index c623c21aa..866693399 100644
--- a/Emby.Drawing.ImageMagick/ImageHelpers.cs
+++ b/Emby.Drawing.ImageMagick/ImageHelpers.cs
@@ -6,13 +6,13 @@ namespace Emby.Drawing.ImageMagick
{
internal static class ImageHelpers
{
- internal static List<string> ProjectPaths(List<string> paths, int count)
+ internal static List<string> ProjectPaths(string[] paths, int count)
{
if (count <= 0)
{
throw new ArgumentOutOfRangeException("count");
}
- if (paths.Count == 0)
+ if (paths.Length == 0)
{
throw new ArgumentOutOfRangeException("paths");
}
@@ -24,7 +24,7 @@ namespace Emby.Drawing.ImageMagick
return list.Take(count).ToList();
}
- private static void AddToList(List<string> list, List<string> paths, int count)
+ private static void AddToList(List<string> list, string[] paths, int count)
{
while (list.Count < count)
{
diff --git a/Emby.Drawing.ImageMagick/ImageMagickEncoder.cs b/Emby.Drawing.ImageMagick/ImageMagickEncoder.cs
index ea8687de0..2c40bf570 100644
--- a/Emby.Drawing.ImageMagick/ImageMagickEncoder.cs
+++ b/Emby.Drawing.ImageMagick/ImageMagickEncoder.cs
@@ -7,13 +7,12 @@ using MediaBrowser.Model.Drawing;
using MediaBrowser.Model.Logging;
using System;
using System.IO;
-using System.Linq;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.System;
namespace Emby.Drawing.ImageMagick
{
- public class ImageMagickEncoder : IImageEncoder
+ public class ImageMagickEncoder : IImageEncoder, IDisposable
{
private readonly ILogger _logger;
private readonly IApplicationPaths _appPaths;
@@ -39,7 +38,8 @@ namespace Emby.Drawing.ImageMagick
// Some common file name extensions for RAW picture files include: .cr2, .crw, .dng, .nef, .orf, .rw2, .pef, .arw, .sr2, .srf, and .tif.
return new[]
{
- "tiff",
+ "tiff",
+ "tif",
"jpeg",
"jpg",
"png",
@@ -306,15 +306,15 @@ namespace Emby.Drawing.ImageMagick
if (ratio >= 1.4)
{
- new StripCollageBuilder(_appPaths, _fileSystem).BuildThumbCollage(options.InputPaths.ToList(), options.OutputPath, options.Width, options.Height);
+ new StripCollageBuilder(_appPaths, _fileSystem).BuildThumbCollage(options.InputPaths, options.OutputPath, options.Width, options.Height);
}
else if (ratio >= .9)
{
- new StripCollageBuilder(_appPaths, _fileSystem).BuildSquareCollage(options.InputPaths.ToList(), options.OutputPath, options.Width, options.Height);
+ new StripCollageBuilder(_appPaths, _fileSystem).BuildSquareCollage(options.InputPaths, options.OutputPath, options.Width, options.Height);
}
else
{
- new StripCollageBuilder(_appPaths, _fileSystem).BuildPosterCollage(options.InputPaths.ToList(), options.OutputPath, options.Width, options.Height);
+ new StripCollageBuilder(_appPaths, _fileSystem).BuildPosterCollage(options.InputPaths, options.OutputPath, options.Width, options.Height);
}
}
@@ -328,6 +328,7 @@ namespace Emby.Drawing.ImageMagick
{
_disposed = true;
Wand.CloseEnvironment();
+ GC.SuppressFinalize(this);
}
private void CheckDisposed()
diff --git a/Emby.Drawing.ImageMagick/StripCollageBuilder.cs b/Emby.Drawing.ImageMagick/StripCollageBuilder.cs
index 63cf8fe5f..26c6c868d 100644
--- a/Emby.Drawing.ImageMagick/StripCollageBuilder.cs
+++ b/Emby.Drawing.ImageMagick/StripCollageBuilder.cs
@@ -19,7 +19,7 @@ namespace Emby.Drawing.ImageMagick
_fileSystem = fileSystem;
}
- public void BuildPosterCollage(List<string> paths, string outputPath, int width, int height)
+ public void BuildPosterCollage(string[] paths, string outputPath, int width, int height)
{
using (var wand = BuildPosterCollageWand(paths, width, height))
{
@@ -27,7 +27,7 @@ namespace Emby.Drawing.ImageMagick
}
}
- public void BuildSquareCollage(List<string> paths, string outputPath, int width, int height)
+ public void BuildSquareCollage(string[] paths, string outputPath, int width, int height)
{
using (var wand = BuildSquareCollageWand(paths, width, height))
{
@@ -35,7 +35,7 @@ namespace Emby.Drawing.ImageMagick
}
}
- public void BuildThumbCollage(List<string> paths, string outputPath, int width, int height)
+ public void BuildThumbCollage(string[] paths, string outputPath, int width, int height)
{
using (var wand = BuildThumbCollageWand(paths, width, height))
{
@@ -43,7 +43,7 @@ namespace Emby.Drawing.ImageMagick
}
}
- private MagickWand BuildPosterCollageWand(List<string> paths, int width, int height)
+ private MagickWand BuildPosterCollageWand(string[] paths, int width, int height)
{
var inputPaths = ImageHelpers.ProjectPaths(paths, 3);
using (var wandImages = new MagickWand(inputPaths.ToArray()))
@@ -108,7 +108,7 @@ namespace Emby.Drawing.ImageMagick
}
}
- private MagickWand BuildThumbCollageWand(List<string> paths, int width, int height)
+ private MagickWand BuildThumbCollageWand(string[] paths, int width, int height)
{
var inputPaths = ImageHelpers.ProjectPaths(paths, 4);
using (var wandImages = new MagickWand(inputPaths.ToArray()))
@@ -173,7 +173,7 @@ namespace Emby.Drawing.ImageMagick
}
}
- private MagickWand BuildSquareCollageWand(List<string> paths, int width, int height)
+ private MagickWand BuildSquareCollageWand(string[] paths, int width, int height)
{
var inputPaths = ImageHelpers.ProjectPaths(paths, 4);
var outputWand = new MagickWand(width, height, new PixelWand("none", 1));
diff --git a/Emby.Drawing.ImageMagick/packages.config b/Emby.Drawing.ImageMagick/packages.config
index 619310d28..aaf7ab7ba 100644
--- a/Emby.Drawing.ImageMagick/packages.config
+++ b/Emby.Drawing.ImageMagick/packages.config
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
- <package id="ImageMagickSharp" version="1.0.0.18" targetFramework="net452" />
+ <package id="ImageMagickSharp" version="1.0.0.19" targetFramework="net452" />
</packages> \ No newline at end of file
diff --git a/Emby.Drawing.Skia/Emby.Drawing.Skia.csproj b/Emby.Drawing.Skia/Emby.Drawing.Skia.csproj
index a4ab19f83..f2b32d52c 100644
--- a/Emby.Drawing.Skia/Emby.Drawing.Skia.csproj
+++ b/Emby.Drawing.Skia/Emby.Drawing.Skia.csproj
@@ -64,7 +64,7 @@
</ItemGroup>
<ItemGroup>
<Reference Include="SkiaSharp, Version=1.58.0.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756, processorArchitecture=MSIL">
- <HintPath>..\packages\SkiaSharp.1.58.0\lib\portable-net45+win8+wpa81+wp8\SkiaSharp.dll</HintPath>
+ <HintPath>..\packages\SkiaSharp.1.58.1\lib\portable-net45+win8+wpa81+wp8\SkiaSharp.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
diff --git a/Emby.Drawing.Skia/SkiaEncoder.cs b/Emby.Drawing.Skia/SkiaEncoder.cs
index 071c40c29..0eaa96609 100644
--- a/Emby.Drawing.Skia/SkiaEncoder.cs
+++ b/Emby.Drawing.Skia/SkiaEncoder.cs
@@ -74,8 +74,9 @@ namespace Emby.Drawing.Skia
return typeof(SKBitmap).GetTypeInfo().Assembly.GetName().Version.ToString();
}
- private static bool IsWhiteSpace(SKColor color)
+ private static bool IsTransparent(SKColor color)
{
+
return (color.Red == 255 && color.Green == 255 && color.Blue == 255) || color.Alpha == 0;
}
@@ -96,11 +97,11 @@ namespace Emby.Drawing.Skia
}
}
- private static bool IsAllWhiteRow(SKBitmap bmp, int row)
+ private static bool IsTransparentRow(SKBitmap bmp, int row)
{
for (var i = 0; i < bmp.Width; ++i)
{
- if (!IsWhiteSpace(bmp.GetPixel(i, row)))
+ if (!IsTransparent(bmp.GetPixel(i, row)))
{
return false;
}
@@ -108,11 +109,11 @@ namespace Emby.Drawing.Skia
return true;
}
- private static bool IsAllWhiteColumn(SKBitmap bmp, int col)
+ private static bool IsTransparentColumn(SKBitmap bmp, int col)
{
for (var i = 0; i < bmp.Height; ++i)
{
- if (!IsWhiteSpace(bmp.GetPixel(col, i)))
+ if (!IsTransparent(bmp.GetPixel(col, i)))
{
return false;
}
@@ -125,7 +126,7 @@ namespace Emby.Drawing.Skia
var topmost = 0;
for (int row = 0; row < bitmap.Height; ++row)
{
- if (IsAllWhiteRow(bitmap, row))
+ if (IsTransparentRow(bitmap, row))
topmost = row + 1;
else break;
}
@@ -133,7 +134,7 @@ namespace Emby.Drawing.Skia
int bottommost = bitmap.Height;
for (int row = bitmap.Height - 1; row >= 0; --row)
{
- if (IsAllWhiteRow(bitmap, row))
+ if (IsTransparentRow(bitmap, row))
bottommost = row;
else break;
}
@@ -141,7 +142,7 @@ namespace Emby.Drawing.Skia
int leftmost = 0, rightmost = bitmap.Width;
for (int col = 0; col < bitmap.Width; ++col)
{
- if (IsAllWhiteColumn(bitmap, col))
+ if (IsTransparentColumn(bitmap, col))
leftmost = col + 1;
else
break;
@@ -149,7 +150,7 @@ namespace Emby.Drawing.Skia
for (int col = bitmap.Width - 1; col >= 0; --col)
{
- if (IsAllWhiteColumn(bitmap, col))
+ if (IsTransparentColumn(bitmap, col))
rightmost = col;
else
break;
@@ -192,16 +193,31 @@ namespace Emby.Drawing.Skia
{
using (var stream = new SKFileStream(path))
{
- var codec = SKCodec.Create(stream);
+ using (var codec = SKCodec.Create(stream))
+ {
+ if (codec == null)
+ {
+ origin = SKCodecOrigin.TopLeft;
+ return null;
+ }
- // create the bitmap
- var bitmap = new SKBitmap(codec.Info.Width, codec.Info.Height, !requiresTransparencyHack);
- // decode
- codec.GetPixels(bitmap.Info, bitmap.GetPixels());
+ // create the bitmap
+ var bitmap = new SKBitmap(codec.Info.Width, codec.Info.Height, !requiresTransparencyHack);
- origin = codec.Origin;
+ if (bitmap != null)
+ {
+ // decode
+ codec.GetPixels(bitmap.Info, bitmap.GetPixels());
- return bitmap;
+ origin = codec.Origin;
+ }
+ else
+ {
+ origin = SKCodecOrigin.TopLeft;
+ }
+
+ return bitmap;
+ }
}
}
@@ -238,7 +254,7 @@ namespace Emby.Drawing.Skia
return Decode(path, forceAnalyzeBitmap, out origin);
}
- private SKBitmap GetBitmap(string path, bool cropWhitespace, bool autoOrient, ImageOrientation? orientation)
+ private SKBitmap GetBitmap(string path, bool cropWhitespace, bool autoOrient)
{
SKCodecOrigin origin;
@@ -246,11 +262,14 @@ namespace Emby.Drawing.Skia
{
var bitmap = GetBitmap(path, cropWhitespace, true, out origin);
- if (origin != SKCodecOrigin.TopLeft)
+ if (bitmap != null)
{
- using (bitmap)
+ if (origin != SKCodecOrigin.TopLeft)
{
- return RotateAndFlip(bitmap, origin);
+ using (bitmap)
+ {
+ return OrientImage(bitmap, origin);
+ }
}
}
@@ -260,82 +279,153 @@ namespace Emby.Drawing.Skia
return GetBitmap(path, cropWhitespace, false, out origin);
}
- private SKBitmap RotateAndFlip(SKBitmap original, SKCodecOrigin origin)
+ private SKBitmap OrientImage(SKBitmap bitmap, SKCodecOrigin origin)
{
- // these are the origins that represent a 90 degree turn in some fashion
- var differentOrientations = new SKCodecOrigin[]
+ //var transformations = {
+ // 2: { rotate: 0, flip: true},
+ // 3: { rotate: 180, flip: false},
+ // 4: { rotate: 180, flip: true},
+ // 5: { rotate: 90, flip: true},
+ // 6: { rotate: 90, flip: false},
+ // 7: { rotate: 270, flip: true},
+ // 8: { rotate: 270, flip: false},
+ //}
+
+ switch (origin)
{
- SKCodecOrigin.LeftBottom,
- SKCodecOrigin.LeftTop,
- SKCodecOrigin.RightBottom,
- SKCodecOrigin.RightTop
- };
- // check if we need to turn the image
- bool isDifferentOrientation = differentOrientations.Any(o => o == origin);
+ case SKCodecOrigin.TopRight:
+ {
+ var rotated = new SKBitmap(bitmap.Width, bitmap.Height);
+ using (var surface = new SKCanvas(rotated))
+ {
+ surface.Translate(rotated.Width, 0);
+ surface.Scale(-1, 1);
+ surface.DrawBitmap(bitmap, 0, 0);
+ }
+
+ return rotated;
+ }
- // define new width/height
- var width = isDifferentOrientation ? original.Height : original.Width;
- var height = isDifferentOrientation ? original.Width : original.Height;
+ case SKCodecOrigin.BottomRight:
+ {
+ var rotated = new SKBitmap(bitmap.Width, bitmap.Height);
+ using (var surface = new SKCanvas(rotated))
+ {
+ float px = bitmap.Width;
+ px /= 2;
- var bitmap = new SKBitmap(width, height, true);
+ float py = bitmap.Height;
+ py /= 2;
- // todo: the stuff in this switch statement should be rewritten to use pointers
- switch (origin)
- {
- case SKCodecOrigin.LeftBottom:
+ surface.RotateDegrees(180, px, py);
+ surface.DrawBitmap(bitmap, 0, 0);
+ }
- for (var x = 0; x < original.Width; x++)
- for (var y = 0; y < original.Height; y++)
- bitmap.SetPixel(y, original.Width - 1 - x, original.GetPixel(x, y));
- break;
+ return rotated;
+ }
- case SKCodecOrigin.RightTop:
+ case SKCodecOrigin.BottomLeft:
+ {
+ var rotated = new SKBitmap(bitmap.Width, bitmap.Height);
+ using (var surface = new SKCanvas(rotated))
+ {
+ float px = bitmap.Width;
+ px /= 2;
- for (var x = 0; x < original.Width; x++)
- for (var y = 0; y < original.Height; y++)
- bitmap.SetPixel(original.Height - 1 - y, x, original.GetPixel(x, y));
- break;
+ float py = bitmap.Height;
+ py /= 2;
- case SKCodecOrigin.RightBottom:
+ surface.Translate(rotated.Width, 0);
+ surface.Scale(-1, 1);
- for (var x = 0; x < original.Width; x++)
- for (var y = 0; y < original.Height; y++)
- bitmap.SetPixel(original.Height - 1 - y, original.Width - 1 - x, original.GetPixel(x, y));
+ surface.RotateDegrees(180, px, py);
+ surface.DrawBitmap(bitmap, 0, 0);
+ }
- break;
+ return rotated;
+ }
case SKCodecOrigin.LeftTop:
+ {
+ // TODO: Remove dual canvases, had trouble with flipping
+ using (var rotated = new SKBitmap(bitmap.Height, bitmap.Width))
+ {
+ using (var surface = new SKCanvas(rotated))
+ {
+ surface.Translate(rotated.Width, 0);
- for (var x = 0; x < original.Width; x++)
- for (var y = 0; y < original.Height; y++)
- bitmap.SetPixel(y, x, original.GetPixel(x, y));
- break;
+ surface.RotateDegrees(90);
- case SKCodecOrigin.BottomLeft:
+ surface.DrawBitmap(bitmap, 0, 0);
- for (var x = 0; x < original.Width; x++)
- for (var y = 0; y < original.Height; y++)
- bitmap.SetPixel(x, original.Height - 1 - y, original.GetPixel(x, y));
- break;
+ }
- case SKCodecOrigin.BottomRight:
+ var flippedBitmap = new SKBitmap(rotated.Width, rotated.Height);
+ using (var flippedCanvas = new SKCanvas(flippedBitmap))
+ {
+ flippedCanvas.Translate(flippedBitmap.Width, 0);
+ flippedCanvas.Scale(-1, 1);
+ flippedCanvas.DrawBitmap(rotated, 0, 0);
+ }
- for (var x = 0; x < original.Width; x++)
- for (var y = 0; y < original.Height; y++)
- bitmap.SetPixel(original.Width - 1 - x, original.Height - 1 - y, original.GetPixel(x, y));
- break;
+ return flippedBitmap;
+ }
+ }
- case SKCodecOrigin.TopRight:
+ case SKCodecOrigin.RightTop:
+ {
+ var rotated = new SKBitmap(bitmap.Height, bitmap.Width);
+ using (var surface = new SKCanvas(rotated))
+ {
+ surface.Translate(rotated.Width, 0);
+ surface.RotateDegrees(90);
+ surface.DrawBitmap(bitmap, 0, 0);
+ }
- for (var x = 0; x < original.Width; x++)
- for (var y = 0; y < original.Height; y++)
- bitmap.SetPixel(original.Width - 1 - x, y, original.GetPixel(x, y));
- break;
+ return rotated;
+ }
- }
+ case SKCodecOrigin.RightBottom:
+ {
+ // TODO: Remove dual canvases, had trouble with flipping
+ using (var rotated = new SKBitmap(bitmap.Height, bitmap.Width))
+ {
+ using (var surface = new SKCanvas(rotated))
+ {
+ surface.Translate(0, rotated.Height);
+ surface.RotateDegrees(270);
+ surface.DrawBitmap(bitmap, 0, 0);
+ }
+
+ var flippedBitmap = new SKBitmap(rotated.Width, rotated.Height);
+ using (var flippedCanvas = new SKCanvas(flippedBitmap))
+ {
+ flippedCanvas.Translate(flippedBitmap.Width, 0);
+ flippedCanvas.Scale(-1, 1);
+ flippedCanvas.DrawBitmap(rotated, 0, 0);
+ }
- return bitmap;
+ return flippedBitmap;
+ }
+ }
+
+ case SKCodecOrigin.LeftBottom:
+ {
+ var rotated = new SKBitmap(bitmap.Height, bitmap.Width);
+ using (var surface = new SKCanvas(rotated))
+ {
+ surface.Translate(0, rotated.Height);
+ surface.RotateDegrees(270);
+ surface.DrawBitmap(bitmap, 0, 0);
+ }
+
+ return rotated;
+ }
+
+ default:
+ return bitmap;
+ }
}
public string EncodeImage(string inputPath, DateTime dateModified, string outputPath, bool autoOrient, ImageOrientation? orientation, int quality, ImageProcessingOptions options, ImageFormat selectedOutputFormat)
@@ -356,11 +446,11 @@ namespace Emby.Drawing.Skia
var blur = options.Blur ?? 0;
var hasIndicator = options.AddPlayedIndicator || options.UnplayedCount.HasValue || !options.PercentPlayed.Equals(0);
- using (var bitmap = GetBitmap(inputPath, options.CropWhiteSpace, autoOrient, orientation))
+ using (var bitmap = GetBitmap(inputPath, options.CropWhiteSpace, autoOrient))
{
if (bitmap == null)
{
- throw new Exception(string.Format("Skia unable to read image {0}", inputPath));
+ throw new ArgumentOutOfRangeException(string.Format("Skia unable to read image {0}", inputPath));
}
//_logger.Info("Color type {0}", bitmap.Info.ColorType);
@@ -504,10 +594,6 @@ namespace Emby.Drawing.Skia
get { return "Skia"; }
}
- public void Dispose()
- {
- }
-
public bool SupportsImageCollageCreation
{
get { return true; }
diff --git a/Emby.Drawing.Skia/packages.config b/Emby.Drawing.Skia/packages.config
index 9d21b2864..2b9b0aee4 100644
--- a/Emby.Drawing.Skia/packages.config
+++ b/Emby.Drawing.Skia/packages.config
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
- <package id="SkiaSharp" version="1.58.0" targetFramework="portable45-net45+win8" />
+ <package id="SkiaSharp" version="1.58.1" targetFramework="portable45-net45+win8" />
</packages> \ No newline at end of file
diff --git a/Emby.Drawing/Emby.Drawing.csproj b/Emby.Drawing/Emby.Drawing.csproj
index 90418f631..c5dd671a8 100644
--- a/Emby.Drawing/Emby.Drawing.csproj
+++ b/Emby.Drawing/Emby.Drawing.csproj
@@ -33,11 +33,6 @@
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
- <Reference Include="TagLib.Portable">
- <HintPath>..\ThirdParty\taglib\TagLib.Portable.dll</HintPath>
- </Reference>
- </ItemGroup>
- <ItemGroup>
<Compile Include="..\SharedVersion.cs">
<Link>Properties\SharedVersion.cs</Link>
</Compile>
diff --git a/Emby.Drawing/ImageProcessor.cs b/Emby.Drawing/ImageProcessor.cs
index 88ead3a5f..1d3f4a8e3 100644
--- a/Emby.Drawing/ImageProcessor.cs
+++ b/Emby.Drawing/ImageProcessor.cs
@@ -17,12 +17,11 @@ using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Model.IO;
using Emby.Drawing.Common;
-
-using MediaBrowser.Controller.IO;
using MediaBrowser.Controller.Library;
+using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.Model.Net;
using MediaBrowser.Model.Threading;
-using TagLib;
+using MediaBrowser.Model.Extensions;
namespace Emby.Drawing
{
@@ -46,7 +45,7 @@ namespace Emby.Drawing
/// Image processors are specialized metadata providers that run after the normal ones
/// </summary>
/// <value>The image enhancers.</value>
- public IEnumerable<IImageEnhancer> ImageEnhancers { get; private set; }
+ public IImageEnhancer[] ImageEnhancers { get; private set; }
/// <summary>
/// The _logger
@@ -58,22 +57,24 @@ namespace Emby.Drawing
private readonly IServerApplicationPaths _appPaths;
private IImageEncoder _imageEncoder;
private readonly Func<ILibraryManager> _libraryManager;
+ private readonly Func<IMediaEncoder> _mediaEncoder;
public ImageProcessor(ILogger logger,
IServerApplicationPaths appPaths,
IFileSystem fileSystem,
IJsonSerializer jsonSerializer,
IImageEncoder imageEncoder,
- Func<ILibraryManager> libraryManager, ITimerFactory timerFactory)
+ Func<ILibraryManager> libraryManager, ITimerFactory timerFactory, Func<IMediaEncoder> mediaEncoder)
{
_logger = logger;
_fileSystem = fileSystem;
_jsonSerializer = jsonSerializer;
_imageEncoder = imageEncoder;
_libraryManager = libraryManager;
+ _mediaEncoder = mediaEncoder;
_appPaths = appPaths;
- ImageEnhancers = new List<IImageEnhancer>();
+ ImageEnhancers = new IImageEnhancer[] { };
_saveImageSizeTimer = timerFactory.Create(SaveImageSizeCallback, null, Timeout.Infinite, Timeout.Infinite);
ImageHelper.ImageProcessor = this;
@@ -122,7 +123,37 @@ namespace Emby.Drawing
{
get
{
- return _imageEncoder.SupportedInputFormats;
+ return new string[]
+ {
+ "tiff",
+ "tif",
+ "jpeg",
+ "jpg",
+ "png",
+ "aiff",
+ "cr2",
+ "crw",
+ "dng",
+
+ // Remove until supported
+ //"nef",
+ "orf",
+ "pef",
+ "arw",
+ "webp",
+ "gif",
+ "bmp",
+ "erf",
+ "raf",
+ "rw2",
+ "nrw",
+ "dng",
+ "ico",
+ "astc",
+ "ktx",
+ "pkm",
+ "wbmp"
+ };
}
}
@@ -186,7 +217,7 @@ namespace Emby.Drawing
}
var originalImage = options.Image;
- IHasImages item = options.Item;
+ IHasMetadata item = options.Item;
if (!originalImage.IsLocalFile)
{
@@ -205,6 +236,10 @@ namespace Emby.Drawing
return new Tuple<string, string, DateTime>(originalImagePath, MimeTypes.GetMimeType(originalImagePath), dateModified);
}
+ var supportedImageInfo = await GetSupportedImage(originalImagePath, dateModified).ConfigureAwait(false);
+ originalImagePath = supportedImageInfo.Item1;
+ dateModified = supportedImageInfo.Item2;
+
if (options.Enhancers.Count > 0)
{
if (item == null)
@@ -262,11 +297,6 @@ namespace Emby.Drawing
var tmpPath = Path.ChangeExtension(Path.Combine(_appPaths.TempDirectory, Guid.NewGuid().ToString("N")), Path.GetExtension(cacheFilePath));
_fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(tmpPath));
- if (item == null && string.Equals(options.ItemType, typeof(Photo).Name, StringComparison.OrdinalIgnoreCase))
- {
- item = _libraryManager().GetItemById(options.ItemId);
- }
-
if (options.CropWhiteSpace && !SupportsTransparency(originalImagePath))
{
options.CropWhiteSpace = false;
@@ -287,6 +317,15 @@ namespace Emby.Drawing
return new Tuple<string, string, DateTime>(cacheFilePath, GetMimeType(outputFormat, cacheFilePath), _fileSystem.GetLastWriteTimeUtc(cacheFilePath));
}
+ catch (ArgumentOutOfRangeException ex)
+ {
+ // Decoder failed to decode it
+#if DEBUG
+ _logger.ErrorException("Error encoding image", ex);
+#endif
+ // Just spit out the original file if all the options are default
+ return new Tuple<string, string, DateTime>(originalImagePath, MimeTypes.GetMimeType(originalImagePath), dateModified);
+ }
catch (Exception ex)
{
// If it fails for whatever reason, return the original image
@@ -606,7 +645,7 @@ namespace Emby.Drawing
/// <param name="image">The image.</param>
/// <returns>Guid.</returns>
/// <exception cref="System.ArgumentNullException">item</exception>
- public string GetImageCacheTag(IHasImages item, ItemImageInfo image)
+ public string GetImageCacheTag(IHasMetadata item, ItemImageInfo image)
{
if (item == null)
{
@@ -620,7 +659,7 @@ namespace Emby.Drawing
var supportedEnhancers = GetSupportedEnhancers(item, image.Type);
- return GetImageCacheTag(item, image, supportedEnhancers.ToList());
+ return GetImageCacheTag(item, image, supportedEnhancers);
}
/// <summary>
@@ -631,7 +670,7 @@ namespace Emby.Drawing
/// <param name="imageEnhancers">The image enhancers.</param>
/// <returns>Guid.</returns>
/// <exception cref="System.ArgumentNullException">item</exception>
- public string GetImageCacheTag(IHasImages item, ItemImageInfo image, List<IImageEnhancer> imageEnhancers)
+ public string GetImageCacheTag(IHasMetadata item, ItemImageInfo image, List<IImageEnhancer> imageEnhancers)
{
if (item == null)
{
@@ -662,7 +701,43 @@ namespace Emby.Drawing
var cacheKeys = imageEnhancers.Select(i => i.GetConfigurationCacheKey(item, imageType)).ToList();
cacheKeys.Add(originalImagePath + dateModified.Ticks);
- return string.Join("|", cacheKeys.ToArray()).GetMD5().ToString("N");
+ return string.Join("|", cacheKeys.ToArray(cacheKeys.Count)).GetMD5().ToString("N");
+ }
+
+ private async Task<Tuple<string, DateTime>> GetSupportedImage(string originalImagePath, DateTime dateModified)
+ {
+ var inputFormat = (Path.GetExtension(originalImagePath) ?? string.Empty)
+ .TrimStart('.')
+ .Replace("jpeg", "jpg", StringComparison.OrdinalIgnoreCase);
+
+ if (!_imageEncoder.SupportedInputFormats.Contains(inputFormat, StringComparer.OrdinalIgnoreCase))
+ {
+ try
+ {
+ var filename = (originalImagePath + dateModified.Ticks.ToString(UsCulture)).GetMD5().ToString("N");
+
+ var outputPath = Path.Combine(_appPaths.ImageCachePath, "converted-images", filename + ".webp");
+
+ var file = _fileSystem.GetFileInfo(outputPath);
+ if (!file.Exists)
+ {
+ await _mediaEncoder().ConvertImage(originalImagePath, outputPath).ConfigureAwait(false);
+ dateModified = _fileSystem.GetLastWriteTimeUtc(outputPath);
+ }
+ else
+ {
+ dateModified = file.LastWriteTimeUtc;
+ }
+
+ originalImagePath = outputPath;
+ }
+ catch (Exception ex)
+ {
+ _logger.ErrorException("Image conversion failed for {0}", ex, originalImagePath);
+ }
+ }
+
+ return new Tuple<string, DateTime>(originalImagePath, dateModified);
}
/// <summary>
@@ -672,9 +747,9 @@ namespace Emby.Drawing
/// <param name="imageType">Type of the image.</param>
/// <param name="imageIndex">Index of the image.</param>
/// <returns>Task{System.String}.</returns>
- public async Task<string> GetEnhancedImage(IHasImages item, ImageType imageType, int imageIndex)
+ public async Task<string> GetEnhancedImage(IHasMetadata item, ImageType imageType, int imageIndex)
{
- var enhancers = GetSupportedEnhancers(item, imageType).ToList();
+ var enhancers = GetSupportedEnhancers(item, imageType);
var imageInfo = item.GetImageInfo(imageType, imageIndex);
@@ -684,7 +759,7 @@ namespace Emby.Drawing
}
private async Task<Tuple<string, DateTime>> GetEnhancedImage(ItemImageInfo image,
- IHasImages item,
+ IHasMetadata item,
int imageIndex,
List<IImageEnhancer> enhancers)
{
@@ -729,7 +804,7 @@ namespace Emby.Drawing
/// item
/// </exception>
private async Task<string> GetEnhancedImageInternal(string originalImagePath,
- IHasImages item,
+ IHasMetadata item,
ImageType imageType,
int imageIndex,
IEnumerable<IImageEnhancer> supportedEnhancers,
@@ -783,7 +858,7 @@ namespace Emby.Drawing
/// <param name="imageType">Type of the image.</param>
/// <param name="imageIndex">Index of the image.</param>
/// <returns>Task{EnhancedImage}.</returns>
- private async Task ExecuteImageEnhancers(IEnumerable<IImageEnhancer> imageEnhancers, string inputPath, string outputPath, IHasImages item, ImageType imageType, int imageIndex)
+ private async Task ExecuteImageEnhancers(IEnumerable<IImageEnhancer> imageEnhancers, string inputPath, string outputPath, IHasMetadata item, ImageType imageType, int imageIndex)
{
// Run the enhancers sequentially in order of priority
foreach (var enhancer in imageEnhancers)
@@ -868,29 +943,40 @@ namespace Emby.Drawing
_logger.Info("Completed creation of image collage and saved to {0}", options.OutputPath);
}
- public IEnumerable<IImageEnhancer> GetSupportedEnhancers(IHasImages item, ImageType imageType)
+ public List<IImageEnhancer> GetSupportedEnhancers(IHasMetadata item, ImageType imageType)
{
- return ImageEnhancers.Where(i =>
+ var list = new List<IImageEnhancer>();
+
+ foreach (var i in ImageEnhancers)
{
try
{
- return i.Supports(item, imageType);
+ if (i.Supports(item, imageType))
+ {
+ list.Add(i);
+ }
}
catch (Exception ex)
{
_logger.ErrorException("Error in image enhancer: {0}", ex, i.GetType().Name);
-
- return false;
}
- });
+ }
+ return list;
}
private bool _disposed;
public void Dispose()
{
_disposed = true;
- _imageEncoder.Dispose();
+
+ var disposable = _imageEncoder as IDisposable;
+ if (disposable != null)
+ {
+ disposable.Dispose();
+ }
+
_saveImageSizeTimer.Dispose();
+ GC.SuppressFinalize(this);
}
private void CheckDisposed()
diff --git a/Emby.Drawing/NullImageEncoder.cs b/Emby.Drawing/NullImageEncoder.cs
index f04e8aaf1..95ea42ecf 100644
--- a/Emby.Drawing/NullImageEncoder.cs
+++ b/Emby.Drawing/NullImageEncoder.cs
@@ -61,9 +61,5 @@ namespace Emby.Drawing
{
throw new NotImplementedException();
}
-
- public void Dispose()
- {
- }
}
}
diff --git a/Emby.Photos/PhotoProvider.cs b/Emby.Photos/PhotoProvider.cs
index 57047cf81..c3c30ab6d 100644
--- a/Emby.Photos/PhotoProvider.cs
+++ b/Emby.Photos/PhotoProvider.cs
@@ -111,7 +111,7 @@ namespace Emby.Photos
}
item.Genres = image.ImageTag.Genres.ToList();
- item.Tags = image.ImageTag.Keywords.ToList();
+ item.Tags = image.ImageTag.Keywords;
item.Software = image.ImageTag.Software;
if (image.ImageTag.Orientation == TagLib.Image.ImageOrientation.None)
diff --git a/Emby.Server.Core/Emby.Server.Core.csproj b/Emby.Server.Core/Emby.Server.Core.csproj
deleted file mode 100644
index 063ef6eb9..000000000
--- a/Emby.Server.Core/Emby.Server.Core.csproj
+++ /dev/null
@@ -1,176 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
- <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
- <PropertyGroup>
- <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
- <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
- <ProjectGuid>{776B9F0C-5195-45E3-9A36-1CC1F0D8E0B0}</ProjectGuid>
- <OutputType>Library</OutputType>
- <AppDesignerFolder>Properties</AppDesignerFolder>
- <RootNamespace>Emby.Server.Core</RootNamespace>
- <AssemblyName>Emby.Server.Core</AssemblyName>
- <TargetFrameworkVersion>v4.6</TargetFrameworkVersion>
- <FileAlignment>512</FileAlignment>
- <TargetFrameworkProfile />
- </PropertyGroup>
- <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
- <DebugSymbols>true</DebugSymbols>
- <DebugType>full</DebugType>
- <Optimize>false</Optimize>
- <OutputPath>bin\Debug\</OutputPath>
- <DefineConstants>DEBUG;TRACE</DefineConstants>
- <ErrorReport>prompt</ErrorReport>
- <WarningLevel>4</WarningLevel>
- <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
- </PropertyGroup>
- <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
- <DebugType>pdbonly</DebugType>
- <Optimize>true</Optimize>
- <OutputPath>bin\Release\</OutputPath>
- <DefineConstants>TRACE</DefineConstants>
- <ErrorReport>prompt</ErrorReport>
- <WarningLevel>4</WarningLevel>
- <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
- </PropertyGroup>
- <ItemGroup>
- <Reference Include="Microsoft.IO.RecyclableMemoryStream, Version=1.2.2.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
- <HintPath>..\packages\Microsoft.IO.RecyclableMemoryStream.1.2.2\lib\net45\Microsoft.IO.RecyclableMemoryStream.dll</HintPath>
- <Private>True</Private>
- </Reference>
- <Reference Include="ServiceStack.Text, Version=4.5.8.0, Culture=neutral, processorArchitecture=MSIL">
- <HintPath>..\packages\ServiceStack.Text.4.5.8\lib\net45\ServiceStack.Text.dll</HintPath>
- <Private>True</Private>
- </Reference>
- <Reference Include="SimpleInjector, Version=4.0.8.0, Culture=neutral, PublicKeyToken=984cb50dea722e99, processorArchitecture=MSIL">
- <HintPath>..\packages\SimpleInjector.4.0.8\lib\net45\SimpleInjector.dll</HintPath>
- </Reference>
- <Reference Include="System" />
- <Reference Include="System.Configuration" />
- <Reference Include="System.Core" />
- <Reference Include="System.Xml.Linq" />
- <Reference Include="System.Data.DataSetExtensions" />
- <Reference Include="Microsoft.CSharp" />
- <Reference Include="System.Data" />
- <Reference Include="System.Net.Http" />
- <Reference Include="System.Xml" />
- </ItemGroup>
- <ItemGroup>
- <Compile Include="..\SharedVersion.cs">
- <Link>Properties\SharedVersion.cs</Link>
- </Compile>
- <Compile Include="ApplicationHost.cs" />
- <Compile Include="ApplicationPathHelper.cs" />
- <Compile Include="Cryptography\ASN1.cs" />
- <Compile Include="Cryptography\ASN1Convert.cs" />
- <Compile Include="Cryptography\BitConverterLE.cs" />
- <Compile Include="Cryptography\CertificateGenerator.cs" />
- <Compile Include="Cryptography\CryptoConvert.cs" />
- <Compile Include="Cryptography\PfxGenerator.cs" />
- <Compile Include="Cryptography\PKCS1.cs" />
- <Compile Include="Cryptography\PKCS12.cs" />
- <Compile Include="Cryptography\PKCS7.cs" />
- <Compile Include="Cryptography\PKCS8.cs" />
- <Compile Include="Cryptography\X501Name.cs" />
- <Compile Include="Cryptography\X509Builder.cs" />
- <Compile Include="Cryptography\X509Certificate.cs" />
- <Compile Include="Cryptography\X509CertificateBuilder.cs" />
- <Compile Include="Cryptography\X509CertificateCollection.cs" />
- <Compile Include="Cryptography\X509Extension.cs" />
- <Compile Include="Cryptography\X509Extensions.cs" />
- <Compile Include="Cryptography\X520Attributes.cs" />
- <Compile Include="EntryPoints\ExternalPortForwarding.cs" />
- <Compile Include="HttpServerFactory.cs" />
- <Compile Include="IO\LibraryMonitor.cs" />
- <Compile Include="IO\MemoryStreamProvider.cs" />
- <Compile Include="Localization\TextLocalizer.cs" />
- <Compile Include="Logging\ConsoleLogger.cs" />
- <Compile Include="Properties\AssemblyInfo.cs" />
- <Compile Include="SystemEvents.cs" />
- </ItemGroup>
- <ItemGroup>
- <ProjectReference Include="..\Emby.Common.Implementations\Emby.Common.Implementations.csproj">
- <Project>{1e37a338-9f57-4b70-bd6d-bb9c591e319b}</Project>
- <Name>Emby.Common.Implementations</Name>
- </ProjectReference>
- <ProjectReference Include="..\Emby.Dlna\Emby.Dlna.csproj">
- <Project>{805844ab-e92f-45e6-9d99-4f6d48d129a5}</Project>
- <Name>Emby.Dlna</Name>
- </ProjectReference>
- <ProjectReference Include="..\Emby.Drawing\Emby.Drawing.csproj">
- <Project>{08fff49b-f175-4807-a2b5-73b0ebd9f716}</Project>
- <Name>Emby.Drawing</Name>
- </ProjectReference>
- <ProjectReference Include="..\Emby.Photos\Emby.Photos.csproj">
- <Project>{89ab4548-770d-41fd-a891-8daff44f452c}</Project>
- <Name>Emby.Photos</Name>
- </ProjectReference>
- <ProjectReference Include="..\Emby.Server.Implementations\Emby.Server.Implementations.csproj">
- <Project>{e383961b-9356-4d5d-8233-9a1079d03055}</Project>
- <Name>Emby.Server.Implementations</Name>
- </ProjectReference>
- <ProjectReference Include="..\MediaBrowser.Api\MediaBrowser.Api.csproj">
- <Project>{4fd51ac5-2c16-4308-a993-c3a84f3b4582}</Project>
- <Name>MediaBrowser.Api</Name>
- </ProjectReference>
- <ProjectReference Include="..\MediaBrowser.Common\MediaBrowser.Common.csproj">
- <Project>{9142eefa-7570-41e1-bfcc-468bb571af2f}</Project>
- <Name>MediaBrowser.Common</Name>
- </ProjectReference>
- <ProjectReference Include="..\MediaBrowser.Controller\MediaBrowser.Controller.csproj">
- <Project>{17e1f4e6-8abd-4fe5-9ecf-43d4b6087ba2}</Project>
- <Name>MediaBrowser.Controller</Name>
- </ProjectReference>
- <ProjectReference Include="..\MediaBrowser.LocalMetadata\MediaBrowser.LocalMetadata.csproj">
- <Project>{7ef9f3e0-697d-42f3-a08f-19deb5f84392}</Project>
- <Name>MediaBrowser.LocalMetadata</Name>
- </ProjectReference>
- <ProjectReference Include="..\MediaBrowser.MediaEncoding\MediaBrowser.MediaEncoding.csproj">
- <Project>{0bd82fa6-eb8a-4452-8af5-74f9c3849451}</Project>
- <Name>MediaBrowser.MediaEncoding</Name>
- </ProjectReference>
- <ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj">
- <Project>{7eeeb4bb-f3e8-48fc-b4c5-70f0fff8329b}</Project>
- <Name>MediaBrowser.Model</Name>
- </ProjectReference>
- <ProjectReference Include="..\MediaBrowser.Providers\MediaBrowser.Providers.csproj">
- <Project>{442b5058-dcaf-4263-bb6a-f21e31120a1b}</Project>
- <Name>MediaBrowser.Providers</Name>
- </ProjectReference>
- <ProjectReference Include="..\MediaBrowser.Server.Implementations\MediaBrowser.Server.Implementations.csproj">
- <Project>{2e781478-814d-4a48-9d80-bff206441a65}</Project>
- <Name>MediaBrowser.Server.Implementations</Name>
- </ProjectReference>
- <ProjectReference Include="..\MediaBrowser.WebDashboard\MediaBrowser.WebDashboard.csproj">
- <Project>{5624b7b5-b5a7-41d8-9f10-cc5611109619}</Project>
- <Name>MediaBrowser.WebDashboard</Name>
- </ProjectReference>
- <ProjectReference Include="..\MediaBrowser.XbmcMetadata\MediaBrowser.XbmcMetadata.csproj">
- <Project>{23499896-b135-4527-8574-c26e926ea99e}</Project>
- <Name>MediaBrowser.XbmcMetadata</Name>
- </ProjectReference>
- <ProjectReference Include="..\Mono.Nat\Mono.Nat.csproj">
- <Project>{cb7f2326-6497-4a3d-ba03-48513b17a7be}</Project>
- <Name>Mono.Nat</Name>
- </ProjectReference>
- <ProjectReference Include="..\OpenSubtitlesHandler\OpenSubtitlesHandler.csproj">
- <Project>{4a4402d4-e910-443b-b8fc-2c18286a2ca0}</Project>
- <Name>OpenSubtitlesHandler</Name>
- </ProjectReference>
- <ProjectReference Include="..\SocketHttpListener\SocketHttpListener.csproj">
- <Project>{1d74413b-e7cf-455b-b021-f52bdf881542}</Project>
- <Name>SocketHttpListener</Name>
- </ProjectReference>
- </ItemGroup>
- <ItemGroup>
- <None Include="app.config" />
- <None Include="packages.config" />
- </ItemGroup>
- <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
- <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
- Other similar extension points exist, see Microsoft.Common.targets.
- <Target Name="BeforeBuild">
- </Target>
- <Target Name="AfterBuild">
- </Target>
- -->
-</Project> \ No newline at end of file
diff --git a/Emby.Server.Core/IO/MemoryStreamProvider.cs b/Emby.Server.Core/IO/MemoryStreamProvider.cs
deleted file mode 100644
index f6dd1ecbc..000000000
--- a/Emby.Server.Core/IO/MemoryStreamProvider.cs
+++ /dev/null
@@ -1,56 +0,0 @@
-using System.IO;
-using MediaBrowser.Model.IO;
-using Microsoft.IO;
-
-namespace Emby.Server.Core.IO
-{
- public class RecyclableMemoryStreamProvider : IMemoryStreamFactory
- {
- readonly RecyclableMemoryStreamManager _manager = new RecyclableMemoryStreamManager();
-
- public MemoryStream CreateNew()
- {
- return _manager.GetStream();
- }
-
- public MemoryStream CreateNew(int capacity)
- {
- return _manager.GetStream("RecyclableMemoryStream", capacity);
- }
-
- public MemoryStream CreateNew(byte[] buffer)
- {
- return _manager.GetStream("RecyclableMemoryStream", buffer, 0, buffer.Length);
- }
-
- public bool TryGetBuffer(MemoryStream stream, out byte[] buffer)
- {
- buffer = stream.GetBuffer();
- return true;
- }
- }
-
- public class MemoryStreamProvider : IMemoryStreamFactory
- {
- public MemoryStream CreateNew()
- {
- return new MemoryStream();
- }
-
- public MemoryStream CreateNew(int capacity)
- {
- return new MemoryStream(capacity);
- }
-
- public MemoryStream CreateNew(byte[] buffer)
- {
- return new MemoryStream(buffer);
- }
-
- public bool TryGetBuffer(MemoryStream stream, out byte[] buffer)
- {
- buffer = stream.GetBuffer();
- return true;
- }
- }
-}
diff --git a/Emby.Server.Core/Properties/AssemblyInfo.cs b/Emby.Server.Core/Properties/AssemblyInfo.cs
deleted file mode 100644
index ead042981..000000000
--- a/Emby.Server.Core/Properties/AssemblyInfo.cs
+++ /dev/null
@@ -1,34 +0,0 @@
-using System.Reflection;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-
-// General Information about an assembly is controlled through the following
-// set of attributes. Change these attribute values to modify the information
-// associated with an assembly.
-[assembly: AssemblyTitle("Emby.Server.Core")]
-[assembly: AssemblyDescription("")]
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("")]
-[assembly: AssemblyProduct("Emby.Server.Core")]
-[assembly: AssemblyCopyright("Copyright © 2017")]
-[assembly: AssemblyTrademark("")]
-[assembly: AssemblyCulture("")]
-
-// Setting ComVisible to false makes the types in this assembly not visible
-// to COM components. If you need to access a type in this assembly from
-// COM, set the ComVisible attribute to true on that type.
-[assembly: ComVisible(false)]
-
-// The following GUID is for the ID of the typelib if this project is exposed to COM
-[assembly: Guid("776b9f0c-5195-45e3-9a36-1cc1f0d8e0b0")]
-
-// Version information for an assembly consists of the following four values:
-//
-// Major Version
-// Minor Version
-// Build Number
-// Revision
-//
-// You can specify all the values or you can default the Build and Revision Numbers
-// by using the '*' as shown below:
-// [assembly: AssemblyVersion("1.0.*")] \ No newline at end of file
diff --git a/Emby.Server.Core/app.config b/Emby.Server.Core/app.config
deleted file mode 100644
index 57ff62392..000000000
--- a/Emby.Server.Core/app.config
+++ /dev/null
@@ -1,11 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<configuration>
- <runtime>
- <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
- <dependentAssembly>
- <assemblyIdentity name="SimpleInjector" publicKeyToken="984cb50dea722e99" culture="neutral"/>
- <bindingRedirect oldVersion="0.0.0.0-4.0.7.0" newVersion="4.0.7.0"/>
- </dependentAssembly>
- </assemblyBinding>
- </runtime>
-<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6"/></startup></configuration>
diff --git a/Emby.Server.Core/packages.config b/Emby.Server.Core/packages.config
deleted file mode 100644
index 6311b55eb..000000000
--- a/Emby.Server.Core/packages.config
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<packages>
- <package id="Microsoft.IO.RecyclableMemoryStream" version="1.2.2" targetFramework="net462" />
- <package id="ServiceStack.Text" version="4.5.8" targetFramework="net462" />
- <package id="SimpleInjector" version="4.0.8" targetFramework="net46" />
-</packages> \ No newline at end of file
diff --git a/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs b/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs
index 567f139fd..4e448ac64 100644
--- a/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs
+++ b/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs
@@ -18,6 +18,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using MediaBrowser.Model.Globalization;
+using MediaBrowser.Model.Extensions;
namespace Emby.Server.Implementations.Activity
{
@@ -127,7 +128,7 @@ namespace Emby.Server.Implementations.Activity
{
// Don't report theme song or local trailer playback
return;
- }
+ }
if (e.Users.Count == 0)
{
@@ -159,8 +160,8 @@ namespace Emby.Server.Implementations.Activity
{
// Don't report theme song or local trailer playback
return;
- }
-
+ }
+
if (e.Users.Count == 0)
{
return;
@@ -415,7 +416,7 @@ namespace Emby.Server.Implementations.Activity
{
return;
}
-
+
var time = result.EndTimeUtc - result.StartTimeUtc;
var runningTime = string.Format(_localization.GetLocalizedString("LabelRunningTimeValue"), ToUserFriendlyString(time));
@@ -436,18 +437,18 @@ namespace Emby.Server.Implementations.Activity
{
Name = string.Format(_localization.GetLocalizedString("ScheduledTaskFailedWithName"), task.Name),
Type = "ScheduledTaskFailed",
- Overview = string.Join(Environment.NewLine, vals.ToArray()),
+ Overview = string.Join(Environment.NewLine, vals.ToArray(vals.Count)),
ShortOverview = runningTime,
Severity = LogSeverity.Error
});
}
}
- private async void CreateLogEntry(ActivityLogEntry entry)
+ private void CreateLogEntry(ActivityLogEntry entry)
{
try
{
- await _activityManager.Create(entry).ConfigureAwait(false);
+ _activityManager.Create(entry);
}
catch
{
@@ -490,6 +491,7 @@ namespace Emby.Server.Implementations.Activity
//_logManager.LoggerLoaded -= _logManager_LoggerLoaded;
_appHost.ApplicationUpdated -= _appHost_ApplicationUpdated;
+ GC.SuppressFinalize(this);
}
/// <summary>
diff --git a/Emby.Server.Implementations/Activity/ActivityManager.cs b/Emby.Server.Implementations/Activity/ActivityManager.cs
index b6095f082..9a3f1ae47 100644
--- a/Emby.Server.Implementations/Activity/ActivityManager.cs
+++ b/Emby.Server.Implementations/Activity/ActivityManager.cs
@@ -13,7 +13,7 @@ namespace Emby.Server.Implementations.Activity
public class ActivityManager : IActivityManager
{
public event EventHandler<GenericEventArgs<ActivityLogEntry>> EntryCreated;
-
+
private readonly IActivityRepository _repo;
private readonly ILogger _logger;
private readonly IUserManager _userManager;
@@ -25,12 +25,12 @@ namespace Emby.Server.Implementations.Activity
_userManager = userManager;
}
- public async Task Create(ActivityLogEntry entry)
+ public void Create(ActivityLogEntry entry)
{
entry.Id = Guid.NewGuid().ToString("N");
entry.Date = DateTime.UtcNow;
- await _repo.Create(entry).ConfigureAwait(false);
+ _repo.Create(entry);
EventHelper.FireEventIfNotNull(EntryCreated, this, new GenericEventArgs<ActivityLogEntry>(entry), _logger);
}
diff --git a/Emby.Server.Implementations/Activity/ActivityRepository.cs b/Emby.Server.Implementations/Activity/ActivityRepository.cs
index e9b6f7a40..3dcc50ba3 100644
--- a/Emby.Server.Implementations/Activity/ActivityRepository.cs
+++ b/Emby.Server.Implementations/Activity/ActivityRepository.cs
@@ -3,13 +3,13 @@ using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
-using System.Threading.Tasks;
using Emby.Server.Implementations.Data;
using MediaBrowser.Controller;
using MediaBrowser.Model.Activity;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Querying;
using SQLitePCL.pretty;
+using MediaBrowser.Model.Extensions;
namespace Emby.Server.Implementations.Activity
{
@@ -40,12 +40,12 @@ namespace Emby.Server.Implementations.Activity
private const string BaseActivitySelectText = "select Id, Name, Overview, ShortOverview, Type, ItemId, UserId, DateCreated, LogSeverity from ActivityLogEntries";
- public Task Create(ActivityLogEntry entry)
+ public void Create(ActivityLogEntry entry)
{
- return Update(entry);
+ Update(entry);
}
- public async Task Update(ActivityLogEntry entry)
+ public void Update(ActivityLogEntry entry)
{
if (entry == null)
{
@@ -94,13 +94,13 @@ namespace Emby.Server.Implementations.Activity
var whereTextWithoutPaging = whereClauses.Count == 0 ?
string.Empty :
- " where " + string.Join(" AND ", whereClauses.ToArray());
+ " where " + string.Join(" AND ", whereClauses.ToArray(whereClauses.Count));
if (startIndex.HasValue && startIndex.Value > 0)
{
var pagingWhereText = whereClauses.Count == 0 ?
string.Empty :
- " where " + string.Join(" AND ", whereClauses.ToArray());
+ " where " + string.Join(" AND ", whereClauses.ToArray(whereClauses.Count));
whereClauses.Add(string.Format("Id NOT IN (SELECT Id FROM ActivityLogEntries {0} ORDER BY DateCreated DESC LIMIT {1})",
pagingWhereText,
@@ -109,7 +109,7 @@ namespace Emby.Server.Implementations.Activity
var whereText = whereClauses.Count == 0 ?
string.Empty :
- " where " + string.Join(" AND ", whereClauses.ToArray());
+ " where " + string.Join(" AND ", whereClauses.ToArray(whereClauses.Count));
commandText += whereText;
@@ -154,7 +154,7 @@ namespace Emby.Server.Implementations.Activity
result.TotalRecordCount = statement.ExecuteQuery().SelectScalarInt().First();
}
- result.Items = list.ToArray();
+ result.Items = list.ToArray(list.Count);
return result;
}, ReadTransactionMode);
diff --git a/Emby.Server.Implementations/AppBase/BaseApplicationPaths.cs b/Emby.Server.Implementations/AppBase/BaseApplicationPaths.cs
index 54d1d5302..1e63aa1a6 100644
--- a/Emby.Server.Implementations/AppBase/BaseApplicationPaths.cs
+++ b/Emby.Server.Implementations/AppBase/BaseApplicationPaths.cs
@@ -13,15 +13,12 @@ namespace Emby.Server.Implementations.AppBase
/// <summary>
/// Initializes a new instance of the <see cref="BaseApplicationPaths"/> class.
/// </summary>
- protected BaseApplicationPaths(string programDataPath, string appFolderPath, Action<string> createDirectoryFn)
+ protected BaseApplicationPaths(string programDataPath, string appFolderPath)
{
ProgramDataPath = programDataPath;
ProgramSystemPath = appFolderPath;
- CreateDirectoryFn = createDirectoryFn;
}
- protected Action<string> CreateDirectoryFn;
-
public string ProgramDataPath { get; private set; }
/// <summary>
@@ -45,7 +42,7 @@ namespace Emby.Server.Implementations.AppBase
{
_dataDirectory = Path.Combine(ProgramDataPath, "data");
- CreateDirectoryFn(_dataDirectory);
+ Directory.CreateDirectory(_dataDirectory);
}
return _dataDirectory;
@@ -152,7 +149,7 @@ namespace Emby.Server.Implementations.AppBase
{
_cachePath = Path.Combine(ProgramDataPath, "cache");
- CreateDirectoryFn(_cachePath);
+ Directory.CreateDirectory(_cachePath);
}
return _cachePath;
diff --git a/Emby.Server.Core/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs
index 67c936437..b3268b156 100644
--- a/Emby.Server.Core/ApplicationHost.cs
+++ b/Emby.Server.Implementations/ApplicationHost.cs
@@ -1,11 +1,46 @@
-using MediaBrowser.Api;
+using Emby.Common.Implementations;
+using Emby.Common.Implementations.Serialization;
+using Emby.Dlna;
+using Emby.Dlna.ConnectionManager;
+using Emby.Dlna.ContentDirectory;
+using Emby.Dlna.Main;
+using Emby.Dlna.MediaReceiverRegistrar;
+using Emby.Dlna.Ssdp;
+using Emby.Drawing;
+using Emby.Photos;
+using Emby.Server.Implementations.Activity;
+using Emby.Server.Implementations.Channels;
+using Emby.Server.Implementations.Collections;
+using Emby.Server.Implementations.Configuration;
+using Emby.Server.Implementations.Data;
+using Emby.Server.Implementations.Devices;
+using Emby.Server.Implementations.Dto;
+using Emby.Server.Implementations.FFMpeg;
+using Emby.Server.Implementations.HttpServer;
+using Emby.Server.Implementations.HttpServer.Security;
+using Emby.Server.Implementations.IO;
+using Emby.Server.Implementations.Library;
+using Emby.Server.Implementations.LiveTv;
+using Emby.Server.Implementations.Localization;
+using Emby.Server.Implementations.MediaEncoder;
+using Emby.Server.Implementations.Migrations;
+using Emby.Server.Implementations.Notifications;
+using Emby.Server.Implementations.Playlists;
+using Emby.Server.Implementations.Security;
+using Emby.Server.Implementations.Session;
+using Emby.Server.Implementations.Social;
+using Emby.Server.Implementations.TV;
+using Emby.Server.Implementations.Updates;
+using MediaBrowser.Api;
using MediaBrowser.Common;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Events;
using MediaBrowser.Common.Extensions;
-using Emby.Common.Implementations.ScheduledTasks;
using MediaBrowser.Common.Net;
+using MediaBrowser.Common.Plugins;
using MediaBrowser.Common.Progress;
+using MediaBrowser.Common.Security;
+using MediaBrowser.Common.Updates;
using MediaBrowser.Controller;
using MediaBrowser.Controller.Channels;
using MediaBrowser.Controller.Chapters;
@@ -17,6 +52,9 @@ using MediaBrowser.Controller.Dlna;
using MediaBrowser.Controller.Drawing;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Entities.Audio;
+using MediaBrowser.Controller.Entities.Movies;
+using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.LiveTv;
using MediaBrowser.Controller.MediaEncoding;
@@ -34,18 +72,32 @@ using MediaBrowser.Controller.Subtitles;
using MediaBrowser.Controller.Sync;
using MediaBrowser.Controller.TV;
using MediaBrowser.LocalMetadata.Savers;
-using MediaBrowser.MediaEncoding.BdInfo;
-using MediaBrowser.MediaEncoding.Encoder;
-using MediaBrowser.MediaEncoding.Subtitles;
+using MediaBrowser.Model.Activity;
+using MediaBrowser.Model.Configuration;
+using MediaBrowser.Model.Diagnostics;
+using MediaBrowser.Model.Dlna;
+using MediaBrowser.Model.Globalization;
+using MediaBrowser.Model.IO;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.MediaInfo;
+using MediaBrowser.Model.Net;
+using MediaBrowser.Model.News;
+using MediaBrowser.Model.Reflection;
+using MediaBrowser.Model.Serialization;
+using MediaBrowser.Model.Services;
+using MediaBrowser.Model.Social;
using MediaBrowser.Model.System;
+using MediaBrowser.Model.Text;
using MediaBrowser.Model.Updates;
+using MediaBrowser.Model.Xml;
using MediaBrowser.Providers.Chapters;
using MediaBrowser.Providers.Manager;
using MediaBrowser.Providers.Subtitles;
using MediaBrowser.WebDashboard.Api;
using MediaBrowser.XbmcMetadata.Providers;
+using OpenSubtitlesHandler;
+using ServiceStack;
+using SocketHttpListener.Primitives;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
@@ -53,90 +105,157 @@ using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
-using System.Net.Sockets;
using System.Reflection;
+using System.Runtime.InteropServices;
using System.Security.Cryptography.X509Certificates;
+using System.Text;
using System.Threading;
using System.Threading.Tasks;
-using Emby.Common.Implementations;
-using Emby.Common.Implementations.Archiving;
-using Emby.Common.Implementations.IO;
-using Emby.Common.Implementations.Reflection;
-using Emby.Common.Implementations.Serialization;
-using Emby.Common.Implementations.TextEncoding;
-using Emby.Common.Implementations.Xml;
-using Emby.Photos;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Api.Playback;
-using MediaBrowser.Common.Plugins;
-using MediaBrowser.Common.Security;
-using MediaBrowser.Common.Updates;
-using MediaBrowser.Controller.Entities.Audio;
-using MediaBrowser.Controller.Entities.Movies;
-using MediaBrowser.Controller.Entities.TV;
-using Emby.Dlna;
-using Emby.Dlna.ConnectionManager;
-using Emby.Dlna.ContentDirectory;
-using Emby.Dlna.Main;
-using Emby.Dlna.MediaReceiverRegistrar;
-using Emby.Dlna.Ssdp;
-using Emby.Server.Core;
-using Emby.Server.Implementations.Activity;
-using Emby.Server.Implementations.Devices;
-using Emby.Server.Implementations.FFMpeg;
-using Emby.Server.Core.IO;
-using Emby.Server.Core.Localization;
-using Emby.Server.Implementations.Migrations;
-using Emby.Server.Implementations.Security;
-using Emby.Server.Implementations.Social;
-using Emby.Server.Implementations.Channels;
-using Emby.Server.Implementations.Collections;
-using Emby.Server.Implementations.Dto;
-using Emby.Server.Implementations.IO;
-using Emby.Server.Implementations.HttpServer;
-using Emby.Server.Implementations.HttpServer.Security;
-using Emby.Server.Implementations.Library;
-using Emby.Server.Implementations.LiveTv;
-using Emby.Server.Implementations.Localization;
-using Emby.Server.Implementations.MediaEncoder;
-using Emby.Server.Implementations.Notifications;
-using Emby.Server.Implementations.Data;
-using Emby.Server.Implementations.Playlists;
-using Emby.Server.Implementations;
-using Emby.Server.Implementations.ServerManager;
-using Emby.Server.Implementations.Session;
-using Emby.Server.Implementations.TV;
-using Emby.Server.Implementations.Updates;
-using MediaBrowser.Model.Activity;
-using MediaBrowser.Model.Configuration;
-using MediaBrowser.Model.Dlna;
-using MediaBrowser.Model.Globalization;
-using MediaBrowser.Model.Net;
-using MediaBrowser.Model.News;
-using MediaBrowser.Model.Reflection;
-using MediaBrowser.Model.Serialization;
-using MediaBrowser.Model.Services;
-using MediaBrowser.Model.Social;
-using MediaBrowser.Model.Text;
-using MediaBrowser.Model.Xml;
-using OpenSubtitlesHandler;
-using ServiceStack;
-using SocketHttpListener.Primitives;
+using Emby.Server.Core.Cryptography;
+using Emby.Server.Implementations.Archiving;
+using Emby.Server.Implementations.Cryptography;
+using Emby.Server.Implementations.Diagnostics;
+using Emby.Server.Implementations.Net;
+using Emby.Server.Implementations.Reflection;
+using Emby.Server.Implementations.ScheduledTasks;
+using Emby.Server.Implementations.Serialization;
+using Emby.Server.Implementations.Threading;
+using Emby.Server.Implementations.Xml;
+using Emby.Server.MediaEncoding.Subtitles;
+using MediaBrowser.MediaEncoding.BdInfo;
+using MediaBrowser.Model.Cryptography;
+using MediaBrowser.Model.Events;
+using MediaBrowser.Model.Tasks;
+using MediaBrowser.Model.Threading;
using StringExtensions = MediaBrowser.Controller.Extensions.StringExtensions;
-using Emby.Drawing;
-using Emby.Server.Implementations.Migrations;
-using MediaBrowser.Model.Diagnostics;
-using Emby.Common.Implementations.Diagnostics;
-using Emby.Server.Implementations.Configuration;
+using X509Certificate = System.Security.Cryptography.X509Certificates.X509Certificate;
-namespace Emby.Server.Core
+namespace Emby.Server.Implementations
{
/// <summary>
/// Class CompositionRoot
/// </summary>
- public abstract class ApplicationHost : BaseApplicationHost<ServerApplicationPaths>, IServerApplicationHost, IDependencyContainer
+ public abstract class ApplicationHost : IServerApplicationHost, IDependencyContainer
{
/// <summary>
+ /// Gets a value indicating whether this instance can self restart.
+ /// </summary>
+ /// <value><c>true</c> if this instance can self restart; otherwise, <c>false</c>.</value>
+ public abstract bool CanSelfRestart { get; }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether this instance can self update.
+ /// </summary>
+ /// <value><c>true</c> if this instance can self update; otherwise, <c>false</c>.</value>
+ public virtual bool CanSelfUpdate
+ {
+ get
+ {
+ return false;
+ }
+ }
+
+ /// <summary>
+ /// Occurs when [has pending restart changed].
+ /// </summary>
+ public event EventHandler HasPendingRestartChanged;
+
+ /// <summary>
+ /// Occurs when [application updated].
+ /// </summary>
+ public event EventHandler<GenericEventArgs<PackageVersionInfo>> ApplicationUpdated;
+
+ /// <summary>
+ /// Gets or sets a value indicating whether this instance has changes that require the entire application to restart.
+ /// </summary>
+ /// <value><c>true</c> if this instance has pending application restart; otherwise, <c>false</c>.</value>
+ public bool HasPendingRestart { get; private set; }
+
+ /// <summary>
+ /// Gets or sets the logger.
+ /// </summary>
+ /// <value>The logger.</value>
+ protected ILogger Logger { get; set; }
+
+ /// <summary>
+ /// Gets or sets the plugins.
+ /// </summary>
+ /// <value>The plugins.</value>
+ public IPlugin[] Plugins { get; protected set; }
+
+ /// <summary>
+ /// Gets or sets the log manager.
+ /// </summary>
+ /// <value>The log manager.</value>
+ public ILogManager LogManager { get; protected set; }
+
+ /// <summary>
+ /// Gets the application paths.
+ /// </summary>
+ /// <value>The application paths.</value>
+ protected ServerApplicationPaths ApplicationPaths { get; set; }
+
+ /// <summary>
+ /// Gets assemblies that failed to load
+ /// </summary>
+ /// <value>The failed assemblies.</value>
+ public List<string> FailedAssemblies { get; protected set; }
+
+ /// <summary>
+ /// Gets all concrete types.
+ /// </summary>
+ /// <value>All concrete types.</value>
+ public Type[] AllConcreteTypes { get; protected set; }
+
+ /// <summary>
+ /// The disposable parts
+ /// </summary>
+ protected readonly List<IDisposable> DisposableParts = new List<IDisposable>();
+
+ /// <summary>
+ /// Gets a value indicating whether this instance is first run.
+ /// </summary>
+ /// <value><c>true</c> if this instance is first run; otherwise, <c>false</c>.</value>
+ public bool IsFirstRun { get; private set; }
+
+ /// <summary>
+ /// Gets the configuration manager.
+ /// </summary>
+ /// <value>The configuration manager.</value>
+ protected IConfigurationManager ConfigurationManager { get; set; }
+
+ public IFileSystem FileSystemManager { get; set; }
+
+ protected IEnvironmentInfo EnvironmentInfo { get; set; }
+
+ private IBlurayExaminer BlurayExaminer { get; set; }
+
+ public PackageVersionClass SystemUpdateLevel
+ {
+ get
+ {
+
+#if BETA
+ return PackageVersionClass.Beta;
+#endif
+ return PackageVersionClass.Release;
+ }
+ }
+
+ public virtual string OperatingSystemDisplayName
+ {
+ get { return EnvironmentInfo.OperatingSystemName; }
+ }
+
+ /// <summary>
+ /// The container
+ /// </summary>
+ protected readonly SimpleInjector.Container Container = new SimpleInjector.Container();
+
+ protected ISystemEvents SystemEvents { get; set; }
+ protected IMemoryStreamFactory MemoryStreamFactory { get; set; }
+
+ /// <summary>
/// Gets the server configuration manager.
/// </summary>
/// <value>The server configuration manager.</value>
@@ -149,7 +268,7 @@ namespace Emby.Server.Core
/// Gets the configuration manager.
/// </summary>
/// <returns>IConfigurationManager.</returns>
- protected override IConfigurationManager GetConfigurationManager()
+ protected IConfigurationManager GetConfigurationManager()
{
return new ServerConfigurationManager(ApplicationPaths, LogManager, XmlSerializer, FileSystemManager);
}
@@ -223,7 +342,6 @@ namespace Emby.Server.Core
internal IUserViewManager UserViewManager { get; set; }
private IAuthenticationRepository AuthenticationRepository { get; set; }
- private ISyncRepository SyncRepository { get; set; }
private ITVSeriesManager TVSeriesManager { get; set; }
private ICollectionManager CollectionManager { get; set; }
private IMediaSourceManager MediaSourceManager { get; set; }
@@ -254,8 +372,17 @@ namespace Emby.Server.Core
internal IPowerManagement PowerManagement { get; private set; }
internal IImageEncoder ImageEncoder { get; private set; }
- private readonly Action<string, string, string> _certificateGenerator;
- private readonly Func<string> _defaultUserNameFactory;
+ protected IProcessFactory ProcessFactory { get; private set; }
+ protected ITimerFactory TimerFactory { get; private set; }
+ protected ICryptoProvider CryptographyProvider = new CryptographyProvider();
+ protected readonly IXmlSerializer XmlSerializer;
+
+ protected ISocketFactory SocketFactory { get; private set; }
+ protected ITaskManager TaskManager { get; private set; }
+ public IHttpClient HttpClient { get; private set; }
+ protected INetworkManager NetworkManager { get; set; }
+ public IJsonSerializer JsonSerializer { get; private set; }
+ protected IIsoManager IsoManager { get; private set; }
/// <summary>
/// Initializes a new instance of the <see cref="ApplicationHost" /> class.
@@ -269,33 +396,37 @@ namespace Emby.Server.Core
IEnvironmentInfo environmentInfo,
IImageEncoder imageEncoder,
ISystemEvents systemEvents,
- IMemoryStreamFactory memoryStreamFactory,
- INetworkManager networkManager,
- Action<string, string, string> certificateGenerator,
- Func<string> defaultUsernameFactory)
- : base(applicationPaths,
- logManager,
- fileSystem,
- environmentInfo,
- systemEvents,
- memoryStreamFactory,
- networkManager)
+ INetworkManager networkManager)
{
+ // hack alert, until common can target .net core
+ BaseExtensions.CryptographyProvider = CryptographyProvider;
+
+ XmlSerializer = new MyXmlSerializer(fileSystem, logManager.GetLogger("XmlSerializer"));
+
+ NetworkManager = networkManager;
+ EnvironmentInfo = environmentInfo;
+ SystemEvents = systemEvents;
+ MemoryStreamFactory = new MemoryStreamProvider();
+
+ FailedAssemblies = new List<string>();
+
+ ApplicationPaths = applicationPaths;
+ LogManager = logManager;
+ FileSystemManager = fileSystem;
+
+ ConfigurationManager = GetConfigurationManager();
+
+ // Initialize this early in case the -v command line option is used
+ Logger = LogManager.GetLogger("App");
+
StartupOptions = options;
- _certificateGenerator = certificateGenerator;
_releaseAssetFilename = releaseAssetFilename;
- _defaultUserNameFactory = defaultUsernameFactory;
PowerManagement = powerManagement;
ImageEncoder = imageEncoder;
SetBaseExceptionMessage();
- if (environmentInfo.OperatingSystem == MediaBrowser.Model.System.OperatingSystem.Windows)
- {
- fileSystem.AddShortcutHandler(new LnkShortcutHandler());
- }
-
fileSystem.AddShortcutHandler(new MbLinkShortcutHandler(fileSystem));
}
@@ -304,7 +435,7 @@ namespace Emby.Server.Core
/// Gets the current application version
/// </summary>
/// <value>The application version.</value>
- public override Version ApplicationVersion
+ public Version ApplicationVersion
{
get
{
@@ -320,11 +451,25 @@ namespace Emby.Server.Core
}
}
+ private DeviceId _deviceId;
+ public string SystemId
+ {
+ get
+ {
+ if (_deviceId == null)
+ {
+ _deviceId = new DeviceId(ApplicationPaths, LogManager.GetLogger("SystemId"), FileSystemManager);
+ }
+
+ return _deviceId.Value;
+ }
+ }
+
/// <summary>
/// Gets the name.
/// </summary>
/// <value>The name.</value>
- public override string Name
+ public string Name
{
get
{
@@ -353,17 +498,163 @@ namespace Emby.Server.Core
}
}
+ /// <summary>
+ /// Creates an instance of type and resolves all constructor dependancies
+ /// </summary>
+ /// <param name="type">The type.</param>
+ /// <returns>System.Object.</returns>
+ public object CreateInstance(Type type)
+ {
+ try
+ {
+ return Container.GetInstance(type);
+ }
+ catch (Exception ex)
+ {
+ Logger.ErrorException("Error creating {0}", ex, type.FullName);
+
+ throw;
+ }
+ }
+
+ /// <summary>
+ /// Creates the instance safe.
+ /// </summary>
+ /// <param name="type">The type.</param>
+ /// <returns>System.Object.</returns>
+ protected object CreateInstanceSafe(Type type)
+ {
+ try
+ {
+ return Container.GetInstance(type);
+ }
+ catch (Exception ex)
+ {
+ Logger.ErrorException("Error creating {0}", ex, type.FullName);
+ // Don't blow up in release mode
+ return null;
+ }
+ }
+
+ /// <summary>
+ /// Registers the specified obj.
+ /// </summary>
+ /// <typeparam name="T"></typeparam>
+ /// <param name="obj">The obj.</param>
+ /// <param name="manageLifetime">if set to <c>true</c> [manage lifetime].</param>
+ protected void RegisterSingleInstance<T>(T obj, bool manageLifetime = true)
+ where T : class
+ {
+ Container.RegisterSingleton(obj);
+
+ if (manageLifetime)
+ {
+ var disposable = obj as IDisposable;
+
+ if (disposable != null)
+ {
+ DisposableParts.Add(disposable);
+ }
+ }
+ }
+
+ /// <summary>
+ /// Registers the single instance.
+ /// </summary>
+ /// <typeparam name="T"></typeparam>
+ /// <param name="func">The func.</param>
+ protected void RegisterSingleInstance<T>(Func<T> func)
+ where T : class
+ {
+ Container.RegisterSingleton(func);
+ }
+
+ /// <summary>
+ /// Resolves this instance.
+ /// </summary>
+ /// <typeparam name="T"></typeparam>
+ /// <returns>``0.</returns>
+ public T Resolve<T>()
+ {
+ return (T)Container.GetRegistration(typeof(T), true).GetInstance();
+ }
+
+ /// <summary>
+ /// Resolves this instance.
+ /// </summary>
+ /// <typeparam name="T"></typeparam>
+ /// <returns>``0.</returns>
+ public T TryResolve<T>()
+ {
+ var result = Container.GetRegistration(typeof(T), false);
+
+ if (result == null)
+ {
+ return default(T);
+ }
+ return (T)result.GetInstance();
+ }
+
+ /// <summary>
+ /// Loads the assembly.
+ /// </summary>
+ /// <param name="file">The file.</param>
+ /// <returns>Assembly.</returns>
+ protected Assembly LoadAssembly(string file)
+ {
+ try
+ {
+ return Assembly.Load(File.ReadAllBytes(file));
+ }
+ catch (Exception ex)
+ {
+ FailedAssemblies.Add(file);
+ Logger.ErrorException("Error loading assembly {0}", ex, file);
+ return null;
+ }
+ }
+
+ /// <summary>
+ /// Gets the export types.
+ /// </summary>
+ /// <typeparam name="T"></typeparam>
+ /// <returns>IEnumerable{Type}.</returns>
+ public IEnumerable<Type> GetExportTypes<T>()
+ {
+ var currentType = typeof(T);
+
+ return AllConcreteTypes.Where(currentType.IsAssignableFrom);
+ }
+
+ /// <summary>
+ /// Gets the exports.
+ /// </summary>
+ /// <typeparam name="T"></typeparam>
+ /// <param name="manageLiftime">if set to <c>true</c> [manage liftime].</param>
+ /// <returns>IEnumerable{``0}.</returns>
+ public IEnumerable<T> GetExports<T>(bool manageLiftime = true)
+ {
+ var parts = GetExportTypes<T>()
+ .Select(CreateInstanceSafe)
+ .Where(i => i != null)
+ .Cast<T>()
+ .ToList();
+
+ if (manageLiftime)
+ {
+ lock (DisposableParts)
+ {
+ DisposableParts.AddRange(parts.OfType<IDisposable>());
+ }
+ }
+
+ return parts;
+ }
+
private void SetBaseExceptionMessage()
{
var builder = GetBaseExceptionMessage(ApplicationPaths);
- // Skip if plugins haven't been loaded yet
- //if (Plugins != null)
- //{
- // var pluginString = string.Join("|", Plugins.Select(i => i.Name + "-" + i.Version.ToString()).ToArray());
- // builder.Insert(0, string.Format("Plugins: {0}{1}", pluginString, Environment.NewLine));
- //}
-
builder.Insert(0, string.Format("Version: {0}{1}", ApplicationVersion, Environment.NewLine));
builder.Insert(0, "*** Error Report ***" + Environment.NewLine);
@@ -373,11 +664,13 @@ namespace Emby.Server.Core
/// <summary>
/// Runs the startup tasks.
/// </summary>
- public override async Task RunStartupTasks()
+ public async Task RunStartupTasks()
{
- await PerformPreInitMigrations().ConfigureAwait(false);
+ Resolve<ITaskManager>().AddTasks(GetExports<IScheduledTask>(false));
+
+ ConfigureAutorun();
- await base.RunStartupTasks().ConfigureAwait(false);
+ ConfigurationManager.ConfigurationUpdated += OnConfigurationUpdated;
await MediaEncoder.Init().ConfigureAwait(false);
@@ -394,7 +687,6 @@ namespace Emby.Server.Core
Logger.Info("Core startup complete");
HttpServer.GlobalResponse = null;
- PerformPostInitMigrations();
Logger.Info("Post-init migrations complete");
foreach (var entryPoint in GetExports<IServerEntryPoint>().ToList())
@@ -410,14 +702,29 @@ namespace Emby.Server.Core
{
Logger.ErrorException("Error in {0}", ex, name);
}
- Logger.Info("Entry point completed: {0}. Duration: {1} seconds", name, (DateTime.UtcNow - now).TotalSeconds.ToString(CultureInfo.InvariantCulture));
+ Logger.Info("Entry point completed: {0}. Duration: {1} seconds", name, (DateTime.UtcNow - now).TotalSeconds.ToString(CultureInfo.InvariantCulture), "ImageInfos");
}
Logger.Info("All entry points have started");
LogManager.RemoveConsoleOutput();
}
- protected override IJsonSerializer CreateJsonSerializer()
+ /// <summary>
+ /// Configures the autorun.
+ /// </summary>
+ private void ConfigureAutorun()
+ {
+ try
+ {
+ ConfigureAutoRunAtStartup(ConfigurationManager.CommonConfiguration.RunAtStartup);
+ }
+ catch (Exception ex)
+ {
+ Logger.ErrorException("Error configuring autorun", ex);
+ }
+ }
+
+ private IJsonSerializer CreateJsonSerializer()
{
try
{
@@ -429,48 +736,10 @@ namespace Emby.Server.Core
// Failing under mono
}
- var result = new JsonSerializer(FileSystemManager, LogManager.GetLogger("JsonSerializer"));
-
- ServiceStack.Text.JsConfig<LiveTvProgram>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "ExtraType" };
- ServiceStack.Text.JsConfig<LiveTvChannel>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "ExtraType" };
- ServiceStack.Text.JsConfig<LiveTvVideoRecording>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "ExtraType" };
- ServiceStack.Text.JsConfig<LiveTvAudioRecording>.ExcludePropertyNames = new[] { "Artists", "AlbumArtists", "ChannelMediaSources", "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "ExtraType" };
- ServiceStack.Text.JsConfig<Series>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "ExtraType" };
- ServiceStack.Text.JsConfig<Audio>.ExcludePropertyNames = new[] { "Artists", "AlbumArtists", "ChannelMediaSources", "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "ExtraType" };
- ServiceStack.Text.JsConfig<MusicAlbum>.ExcludePropertyNames = new[] { "Artists", "AlbumArtists", "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "ExtraType" };
- ServiceStack.Text.JsConfig<MusicArtist>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "ExtraType" };
- ServiceStack.Text.JsConfig<MusicGenre>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "ExtraType" };
- ServiceStack.Text.JsConfig<MusicVideo>.ExcludePropertyNames = new[] { "Artists", "AlbumArtists", "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "ExtraType" };
- ServiceStack.Text.JsConfig<Movie>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "ExtraType" };
- ServiceStack.Text.JsConfig<Playlist>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "ExtraType" };
- ServiceStack.Text.JsConfig<AudioPodcast>.ExcludePropertyNames = new[] { "Artists", "AlbumArtists", "ChannelMediaSources", "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "ExtraType" };
- ServiceStack.Text.JsConfig<AudioBook>.ExcludePropertyNames = new[] { "Artists", "AlbumArtists", "ChannelMediaSources", "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "ExtraType" };
- ServiceStack.Text.JsConfig<Trailer>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "ExtraType" };
- ServiceStack.Text.JsConfig<BoxSet>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "ExtraType" };
- ServiceStack.Text.JsConfig<Episode>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "ExtraType" };
- ServiceStack.Text.JsConfig<Season>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "ExtraType" };
- ServiceStack.Text.JsConfig<Book>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "ExtraType" };
- ServiceStack.Text.JsConfig<CollectionFolder>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "ExtraType" };
- ServiceStack.Text.JsConfig<Folder>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "ExtraType" };
- ServiceStack.Text.JsConfig<Game>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "ExtraType" };
- ServiceStack.Text.JsConfig<GameGenre>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "ExtraType" };
- ServiceStack.Text.JsConfig<GameSystem>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "ExtraType" };
- ServiceStack.Text.JsConfig<Genre>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "ExtraType" };
- ServiceStack.Text.JsConfig<Person>.ExcludePropertyNames = new[] { "PlaceOfBirth", "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "ExtraType" };
- ServiceStack.Text.JsConfig<Photo>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "ExtraType" };
- ServiceStack.Text.JsConfig<PhotoAlbum>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "ExtraType" };
- ServiceStack.Text.JsConfig<Studio>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "ExtraType" };
- ServiceStack.Text.JsConfig<UserRootFolder>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "ExtraType" };
- ServiceStack.Text.JsConfig<UserView>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "ExtraType" };
- ServiceStack.Text.JsConfig<Video>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "ExtraType" };
- ServiceStack.Text.JsConfig<Year>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "ExtraType" };
- ServiceStack.Text.JsConfig<Channel>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "ExtraType" };
- ServiceStack.Text.JsConfig<AggregateFolder>.ExcludePropertyNames = new[] { "ProviderIds", "ImageInfos", "ProductionLocations", "ThemeSongIds", "ThemeVideoIds", "TotalBitrate", "Taglines", "ExtraType" };
-
- return result;
+ return new JsonSerializer(FileSystemManager, LogManager.GetLogger("JsonSerializer"));
}
- public override Task Init(IProgress<double> progress)
+ public async Task Init(IProgress<double> progress)
{
HttpPort = ServerConfigurationManager.Configuration.HttpServerPortNumber;
HttpsPort = ServerConfigurationManager.Configuration.HttpsPortNumber;
@@ -482,44 +751,63 @@ namespace Emby.Server.Core
HttpsPort = ServerConfiguration.DefaultHttpsPort;
}
- return base.Init(progress);
+ progress.Report(1);
+
+ JsonSerializer = CreateJsonSerializer();
+
+ OnLoggerLoaded(true);
+ LogManager.LoggerLoaded += (s, e) => OnLoggerLoaded(false);
+
+ IsFirstRun = !ConfigurationManager.CommonConfiguration.IsStartupWizardCompleted;
+ progress.Report(2);
+
+ LogManager.LogSeverity = ConfigurationManager.CommonConfiguration.EnableDebugLevelLogging
+ ? LogSeverity.Debug
+ : LogSeverity.Info;
+
+ progress.Report(3);
+
+ DiscoverTypes();
+ progress.Report(14);
+
+ SetHttpLimit();
+ progress.Report(15);
+
+ var innerProgress = new ActionableProgress<double>();
+ innerProgress.RegisterAction(p => progress.Report(.8 * p + 15));
+
+ await RegisterResources(innerProgress).ConfigureAwait(false);
+
+ FindParts();
+ progress.Report(95);
+
+ await InstallIsoMounters(CancellationToken.None).ConfigureAwait(false);
+
+ progress.Report(100);
}
- private async Task PerformPreInitMigrations()
+ protected virtual void OnLoggerLoaded(bool isFirstLoad)
{
- var migrations = new List<IVersionMigration>
- {
- };
+ Logger.Info("Application version: {0}", ApplicationVersion);
- foreach (var task in migrations)
+ if (!isFirstLoad)
{
- try
- {
- await task.Run().ConfigureAwait(false);
- }
- catch (Exception ex)
- {
- Logger.ErrorException("Error running migration", ex);
- }
+ LogEnvironmentInfo(Logger, ApplicationPaths, false);
}
- }
- private void PerformPostInitMigrations()
- {
- var migrations = new List<IVersionMigration>
- {
- };
+ // Put the app config in the log for troubleshooting purposes
+ Logger.LogMultiline("Application configuration:", LogSeverity.Info, new StringBuilder(JsonSerializer.SerializeToString(ConfigurationManager.CommonConfiguration)));
- foreach (var task in migrations)
+ if (Plugins != null)
{
- try
- {
- task.Run();
- }
- catch (Exception ex)
+ var pluginBuilder = new StringBuilder();
+
+ foreach (var plugin in Plugins)
{
- Logger.ErrorException("Error running migration", ex);
+ pluginBuilder.AppendLine(string.Format("{0} {1}", plugin.Name, plugin.Version));
}
+
+ Logger.LogMultiline("Plugins:", LogSeverity.Info, pluginBuilder);
}
}
@@ -529,16 +817,54 @@ namespace Emby.Server.Core
/// <summary>
/// Registers resources that classes will depend on
/// </summary>
- protected override async Task RegisterResources(IProgress<double> progress)
+ protected async Task RegisterResources(IProgress<double> progress)
{
- await base.RegisterResources(progress).ConfigureAwait(false);
+ RegisterSingleInstance(ConfigurationManager);
+ RegisterSingleInstance<IApplicationHost>(this);
+
+ RegisterSingleInstance<IApplicationPaths>(ApplicationPaths);
+
+ RegisterSingleInstance(JsonSerializer);
+ RegisterSingleInstance(MemoryStreamFactory);
+ RegisterSingleInstance(SystemEvents);
+
+ RegisterSingleInstance(LogManager, false);
+ RegisterSingleInstance(Logger);
+
+ RegisterSingleInstance(EnvironmentInfo);
+
+ RegisterSingleInstance(FileSystemManager);
+
+ HttpClient = new HttpClientManager.HttpClientManager(ApplicationPaths, LogManager.GetLogger("HttpClient"), FileSystemManager, MemoryStreamFactory, GetDefaultUserAgent);
+ RegisterSingleInstance(HttpClient);
+
+ RegisterSingleInstance(NetworkManager);
+
+ IsoManager = new IsoManager();
+ RegisterSingleInstance(IsoManager);
+
+ TaskManager = new TaskManager(ApplicationPaths, JsonSerializer, LogManager.GetLogger("TaskManager"), FileSystemManager, SystemEvents);
+ RegisterSingleInstance(TaskManager);
+
+ RegisterSingleInstance(XmlSerializer);
+
+ ProcessFactory = new ProcessFactory();
+ RegisterSingleInstance(ProcessFactory);
+
+ TimerFactory = new TimerFactory();
+ RegisterSingleInstance(TimerFactory);
+
+ RegisterSingleInstance(CryptographyProvider);
+
+ SocketFactory = new SocketFactory(LogManager.GetLogger("SocketFactory"));
+ RegisterSingleInstance(SocketFactory);
RegisterSingleInstance(PowerManagement);
SecurityManager = new PluginSecurityManager(this, HttpClient, JsonSerializer, ApplicationPaths, LogManager, FileSystemManager, CryptographyProvider);
RegisterSingleInstance(SecurityManager);
- InstallationManager = new InstallationManager(LogManager.GetLogger("InstallationManager"), this, ApplicationPaths, HttpClient, JsonSerializer, SecurityManager, ConfigurationManager, FileSystemManager, CryptographyProvider);
+ InstallationManager = new InstallationManager(LogManager.GetLogger("InstallationManager"), this, ApplicationPaths, HttpClient, JsonSerializer, SecurityManager, ConfigurationManager, FileSystemManager, CryptographyProvider, PackageRuntime);
RegisterSingleInstance(InstallationManager);
ZipClient = new ZipClient(FileSystemManager);
@@ -558,10 +884,11 @@ namespace Emby.Server.Core
StringExtensions.LocalizationManager = LocalizationManager;
RegisterSingleInstance(LocalizationManager);
- ITextEncoding textEncoding = new TextEncoding(FileSystemManager, LogManager.GetLogger("TextEncoding"), JsonSerializer);
+ ITextEncoding textEncoding = new TextEncoding.TextEncoding(FileSystemManager, LogManager.GetLogger("TextEncoding"), JsonSerializer);
RegisterSingleInstance(textEncoding);
Utilities.EncodingHelper = textEncoding;
- RegisterSingleInstance<IBlurayExaminer>(() => new BdInfoExaminer(FileSystemManager, textEncoding));
+ BlurayExaminer = new BdInfoExaminer(FileSystemManager, textEncoding);
+ RegisterSingleInstance(BlurayExaminer);
RegisterSingleInstance<IXmlReaderSettingsFactory>(new XmlReaderSettingsFactory());
@@ -583,7 +910,7 @@ namespace Emby.Server.Core
AuthenticationRepository = GetAuthenticationRepository();
RegisterSingleInstance(AuthenticationRepository);
- UserManager = new UserManager(LogManager.GetLogger("UserManager"), ServerConfigurationManager, UserRepository, XmlSerializer, NetworkManager, () => ImageProcessor, () => DtoService, () => ConnectManager, this, JsonSerializer, FileSystemManager, CryptographyProvider, _defaultUserNameFactory());
+ UserManager = new UserManager(LogManager.GetLogger("UserManager"), ServerConfigurationManager, UserRepository, XmlSerializer, NetworkManager, () => ImageProcessor, () => DtoService, () => ConnectManager, this, JsonSerializer, FileSystemManager, CryptographyProvider);
RegisterSingleInstance(UserManager);
LibraryManager = new LibraryManager(Logger, TaskManager, UserManager, ServerConfigurationManager, UserDataManager, () => LibraryMonitor, FileSystemManager, () => ProviderManager, () => UserViewManager);
@@ -608,7 +935,7 @@ namespace Emby.Server.Core
RegisterSingleInstance(HttpServer, false);
progress.Report(10);
- ServerManager = new ServerManager(this, JsonSerializer, LogManager.GetLogger("ServerManager"), ServerConfigurationManager, MemoryStreamFactory, textEncoding);
+ ServerManager = new ServerManager.ServerManager(this, JsonSerializer, LogManager.GetLogger("ServerManager"), ServerConfigurationManager, MemoryStreamFactory, textEncoding);
RegisterSingleInstance(ServerManager);
var innerProgress = new ActionableProgress<double>();
@@ -667,7 +994,7 @@ namespace Emby.Server.Core
UserViewManager = new UserViewManager(LibraryManager, LocalizationManager, UserManager, ChannelManager, LiveTvManager, ServerConfigurationManager);
RegisterSingleInstance(UserViewManager);
- var contentDirectory = new ContentDirectory(dlnaManager, UserDataManager, ImageProcessor, LibraryManager, ServerConfigurationManager, UserManager, LogManager.GetLogger("UpnpContentDirectory"), HttpClient, LocalizationManager, ChannelManager, MediaSourceManager, UserViewManager, () => MediaEncoder, new XmlReaderSettingsFactory());
+ var contentDirectory = new ContentDirectory(dlnaManager, UserDataManager, ImageProcessor, LibraryManager, ServerConfigurationManager, UserManager, LogManager.GetLogger("UpnpContentDirectory"), HttpClient, LocalizationManager, ChannelManager, MediaSourceManager, UserViewManager, () => MediaEncoder, new XmlReaderSettingsFactory(), TVSeriesManager);
RegisterSingleInstance<IContentDirectory>(contentDirectory);
var mediaRegistrar = new MediaReceiverRegistrar(LogManager.GetLogger("MediaReceiverRegistrar"), HttpClient, ServerConfigurationManager, new XmlReaderSettingsFactory());
@@ -722,7 +1049,116 @@ namespace Emby.Server.Core
SetStaticProperties();
- await ((UserManager)UserManager).Initialize().ConfigureAwait(false);
+ ((UserManager)UserManager).Initialize();
+ }
+
+ protected virtual string PackageRuntime
+ {
+ get
+ {
+ return "netframework";
+ }
+ }
+
+ public static void LogEnvironmentInfo(ILogger logger, IApplicationPaths appPaths, bool isStartup)
+ {
+ logger.LogMultiline("Emby", LogSeverity.Info, GetBaseExceptionMessage(appPaths));
+ }
+
+ protected static StringBuilder GetBaseExceptionMessage(IApplicationPaths appPaths)
+ {
+ var builder = new StringBuilder();
+
+ builder.AppendLine(string.Format("Command line: {0}", string.Join(" ", Environment.GetCommandLineArgs())));
+
+ builder.AppendLine(string.Format("Operating system: {0}", Environment.OSVersion));
+ builder.AppendLine(string.Format("64-Bit OS: {0}", Environment.Is64BitOperatingSystem));
+ builder.AppendLine(string.Format("64-Bit Process: {0}", Environment.Is64BitProcess));
+ builder.AppendLine(string.Format("User Interactive: {0}", Environment.UserInteractive));
+
+ Type type = Type.GetType("Mono.Runtime");
+ if (type != null)
+ {
+ MethodInfo displayName = type.GetMethod("GetDisplayName", BindingFlags.NonPublic | BindingFlags.Static);
+ if (displayName != null)
+ {
+ builder.AppendLine("Mono: " + displayName.Invoke(null, null));
+ }
+ }
+
+ builder.AppendLine(string.Format("Processor count: {0}", Environment.ProcessorCount));
+ builder.AppendLine(string.Format("Program data path: {0}", appPaths.ProgramDataPath));
+ builder.AppendLine(string.Format("Application directory: {0}", appPaths.ProgramSystemPath));
+
+ return builder;
+ }
+
+ private void SetHttpLimit()
+ {
+ try
+ {
+ // Increase the max http request limit
+ ServicePointManager.DefaultConnectionLimit = Math.Max(96, ServicePointManager.DefaultConnectionLimit);
+ }
+ catch (Exception ex)
+ {
+ Logger.ErrorException("Error setting http limit", ex);
+ }
+ }
+
+ /// <summary>
+ /// Installs the iso mounters.
+ /// </summary>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>Task.</returns>
+ private async Task InstallIsoMounters(CancellationToken cancellationToken)
+ {
+ var list = new List<IIsoMounter>();
+
+ foreach (var isoMounter in GetExports<IIsoMounter>())
+ {
+ try
+ {
+ if (isoMounter.RequiresInstallation && !isoMounter.IsInstalled)
+ {
+ Logger.Info("Installing {0}", isoMounter.Name);
+
+ await isoMounter.Install(cancellationToken).ConfigureAwait(false);
+ }
+
+ list.Add(isoMounter);
+ }
+ catch (Exception ex)
+ {
+ Logger.ErrorException("{0} failed to load.", ex, isoMounter.Name);
+ }
+ }
+
+ IsoManager.AddParts(list);
+ }
+
+ private string GetDefaultUserAgent()
+ {
+ var name = FormatAttribute(Name);
+
+ return name + "/" + ApplicationVersion;
+ }
+
+ private string FormatAttribute(string str)
+ {
+ var arr = str.ToCharArray();
+
+ arr = Array.FindAll<char>(arr, (c => (char.IsLetterOrDigit(c)
+ || char.IsWhiteSpace(c))));
+
+ var result = new string(arr);
+
+ if (string.IsNullOrWhiteSpace(result))
+ {
+ result = "Emby";
+ }
+
+ return result;
}
protected virtual bool SupportsDualModeSockets
@@ -733,7 +1169,7 @@ namespace Emby.Server.Core
}
}
- private ICertificate GetCertificate(CertificateInfo info)
+ private X509Certificate GetCertificate(CertificateInfo info)
{
var certificateLocation = info == null ? null : info.Path;
@@ -760,7 +1196,7 @@ namespace Emby.Server.Core
return null;
}
- return new Certificate(localCert);
+ return localCert;
}
catch (Exception ex)
{
@@ -771,7 +1207,7 @@ namespace Emby.Server.Core
private IImageProcessor GetImageProcessor()
{
- return new ImageProcessor(LogManager.GetLogger("ImageProcessor"), ServerConfigurationManager.ApplicationPaths, FileSystemManager, JsonSerializer, ImageEncoder, () => LibraryManager, TimerFactory);
+ return new ImageProcessor(LogManager.GetLogger("ImageProcessor"), ServerConfigurationManager.ApplicationPaths, FileSystemManager, JsonSerializer, ImageEncoder, () => LibraryManager, TimerFactory, () => MediaEncoder);
}
protected virtual FFMpegInstallInfo GetFfmpegInstallInfo()
@@ -820,10 +1256,10 @@ namespace Emby.Server.Core
{
switch (EnvironmentInfo.SystemArchitecture)
{
- case Architecture.X64:
+ case MediaBrowser.Model.System.Architecture.X64:
return new[]
{
- "https://embydata.com/downloads/ffmpeg/osx/ffmpeg-x64-20170308.7z"
+ "https://embydata.com/downloads/ffmpeg/osx/ffmpeg-x64-20170308.7z"
};
}
@@ -834,15 +1270,15 @@ namespace Emby.Server.Core
{
switch (EnvironmentInfo.SystemArchitecture)
{
- case Architecture.X64:
+ case MediaBrowser.Model.System.Architecture.X64:
return new[]
{
- "https://embydata.com/downloads/ffmpeg/windows/ffmpeg-20170308-win64.7z"
+ "https://embydata.com/downloads/ffmpeg/windows/ffmpeg-20170308-win64.7z"
};
- case Architecture.X86:
+ case MediaBrowser.Model.System.Architecture.X86:
return new[]
{
- "https://embydata.com/downloads/ffmpeg/windows/ffmpeg-20170308-win32.7z"
+ "https://embydata.com/downloads/ffmpeg/windows/ffmpeg-20170308-win32.7z"
};
}
@@ -853,15 +1289,15 @@ namespace Emby.Server.Core
{
switch (EnvironmentInfo.SystemArchitecture)
{
- case Architecture.X64:
+ case MediaBrowser.Model.System.Architecture.X64:
return new[]
{
- "https://embydata.com/downloads/ffmpeg/linux/ffmpeg-git-20170301-64bit-static.7z"
+ "https://embydata.com/downloads/ffmpeg/linux/ffmpeg-git-20170301-64bit-static.7z"
};
- case Architecture.X86:
+ case MediaBrowser.Model.System.Architecture.X86:
return new[]
{
- "https://embydata.com/downloads/ffmpeg/linux/ffmpeg-git-20170301-32bit-static.7z"
+ "https://embydata.com/downloads/ffmpeg/linux/ffmpeg-git-20170301-32bit-static.7z"
};
}
@@ -884,7 +1320,7 @@ namespace Emby.Server.Core
probePath = info.ProbePath;
var hasExternalEncoder = string.Equals(info.Version, "external", StringComparison.OrdinalIgnoreCase);
- var mediaEncoder = new MediaEncoder(LogManager.GetLogger("MediaEncoder"),
+ var mediaEncoder = new MediaEncoding.Encoder.MediaEncoder(LogManager.GetLogger("MediaEncoder"),
JsonSerializer,
encoderPath,
probePath,
@@ -904,7 +1340,8 @@ namespace Emby.Server.Core
ProcessFactory,
(Environment.ProcessorCount > 2 ? 14000 : 40000),
EnvironmentInfo.OperatingSystem == MediaBrowser.Model.System.OperatingSystem.Windows,
- EnvironmentInfo);
+ EnvironmentInfo,
+ BlurayExaminer);
MediaEncoder = mediaEncoder;
RegisterSingleInstance(MediaEncoder);
@@ -980,8 +1417,6 @@ namespace Emby.Server.Core
BaseItem.CollectionManager = CollectionManager;
BaseItem.MediaSourceManager = MediaSourceManager;
CollectionFolder.XmlSerializer = XmlSerializer;
- BaseStreamingService.AppHost = this;
- BaseStreamingService.HttpClient = HttpClient;
Utilities.CryptographyProvider = CryptographyProvider;
AuthenticatedAttribute.AuthService = AuthService;
}
@@ -989,7 +1424,7 @@ namespace Emby.Server.Core
/// <summary>
/// Finds the parts.
/// </summary>
- protected override void FindParts()
+ protected void FindParts()
{
if (!ServerConfigurationManager.Configuration.IsPortAuthorized)
{
@@ -1000,7 +1435,8 @@ namespace Emby.Server.Core
RegisterModules();
- base.FindParts();
+ ConfigurationManager.AddParts(GetExports<IConfigurationFactory>());
+ Plugins = GetExports<IPlugin>().Select(LoadPlugin).Where(i => i != null).ToArray();
HttpServer.Init(GetExports<IService>(false));
@@ -1009,17 +1445,17 @@ namespace Emby.Server.Core
StartServer();
LibraryManager.AddParts(GetExports<IResolverIgnoreRule>(),
- GetExports<IVirtualFolderCreator>(),
- GetExports<IItemResolver>(),
- GetExports<IIntroProvider>(),
- GetExports<IBaseItemComparer>(),
- GetExports<ILibraryPostScanTask>());
+ GetExports<IVirtualFolderCreator>(),
+ GetExports<IItemResolver>(),
+ GetExports<IIntroProvider>(),
+ GetExports<IBaseItemComparer>(),
+ GetExports<ILibraryPostScanTask>());
ProviderManager.AddParts(GetExports<IImageProvider>(),
- GetExports<IMetadataService>(),
- GetExports<IMetadataProvider>(),
- GetExports<IMetadataSaver>(),
- GetExports<IExternalId>());
+ GetExports<IMetadataService>(),
+ GetExports<IMetadataProvider>(),
+ GetExports<IMetadataSaver>(),
+ GetExports<IExternalId>());
ImageProcessor.AddParts(GetExports<IImageEnhancer>());
@@ -1037,8 +1473,119 @@ namespace Emby.Server.Core
SyncManager.AddParts(GetExports<ISyncProvider>());
}
+ private IPlugin LoadPlugin(IPlugin plugin)
+ {
+ try
+ {
+ var assemblyPlugin = plugin as IPluginAssembly;
+
+ if (assemblyPlugin != null)
+ {
+ var assembly = plugin.GetType().Assembly;
+ var assemblyName = assembly.GetName();
+
+ var assemblyFileName = assemblyName.Name + ".dll";
+ var assemblyFilePath = Path.Combine(ApplicationPaths.PluginsPath, assemblyFileName);
+
+ assemblyPlugin.SetAttributes(assemblyFilePath, assemblyFileName, assemblyName.Version);
+
+ try
+ {
+ var idAttributes = assembly.GetCustomAttributes(typeof(GuidAttribute), true);
+ if (idAttributes.Length > 0)
+ {
+ var attribute = (GuidAttribute)idAttributes[0];
+ var assemblyId = new Guid(attribute.Value);
+
+ assemblyPlugin.SetId(assemblyId);
+ }
+ }
+ catch (Exception ex)
+ {
+ Logger.ErrorException("Error getting plugin Id from {0}.", ex, plugin.GetType().FullName);
+ }
+ }
+
+ var isFirstRun = !File.Exists(plugin.ConfigurationFilePath);
+ plugin.SetStartupInfo(isFirstRun, File.GetLastWriteTimeUtc, s => Directory.CreateDirectory(s));
+ }
+ catch (Exception ex)
+ {
+ Logger.ErrorException("Error loading plugin {0}", ex, plugin.GetType().FullName);
+ return null;
+ }
+
+ return plugin;
+ }
+
+ /// <summary>
+ /// Discovers the types.
+ /// </summary>
+ protected void DiscoverTypes()
+ {
+ FailedAssemblies.Clear();
+
+ var assemblies = GetComposablePartAssemblies().ToList();
+
+ foreach (var assembly in assemblies)
+ {
+ Logger.Info("Loading {0}", assembly.FullName);
+ }
+
+ AllConcreteTypes = assemblies
+ .SelectMany(GetTypes)
+ .Where(t => t.IsClass && !t.IsAbstract && !t.IsInterface && !t.IsGenericType)
+ .ToArray();
+ }
+
+ /// <summary>
+ /// Gets a list of types within an assembly
+ /// This will handle situations that would normally throw an exception - such as a type within the assembly that depends on some other non-existant reference
+ /// </summary>
+ /// <param name="assembly">The assembly.</param>
+ /// <returns>IEnumerable{Type}.</returns>
+ /// <exception cref="System.ArgumentNullException">assembly</exception>
+ protected List<Type> GetTypes(Assembly assembly)
+ {
+ if (assembly == null)
+ {
+ return new List<Type>();
+ }
+
+ try
+ {
+ // This null checking really shouldn't be needed but adding it due to some
+ // unhandled exceptions in mono 5.0 that are a little hard to hunt down
+ var types = assembly.GetTypes() ?? new Type[] { };
+ return types.Where(t => t != null).ToList();
+ }
+ catch (ReflectionTypeLoadException ex)
+ {
+ if (ex.LoaderExceptions != null)
+ {
+ foreach (var loaderException in ex.LoaderExceptions)
+ {
+ if (loaderException != null)
+ {
+ Logger.Error("LoaderException: " + loaderException.Message);
+ }
+ }
+ }
+
+ // If it fails we can still get a list of the Types it was able to resolve
+ var types = ex.Types ?? new Type[] { };
+ return types.Where(t => t != null).ToList();
+ }
+ catch (Exception ex)
+ {
+ Logger.ErrorException("Error loading types from assembly", ex);
+
+ return new List<Type>();
+ }
+ }
+
private CertificateInfo CertificateInfo { get; set; }
- private ICertificate Certificate { get; set; }
+ private X509Certificate Certificate { get; set; }
private IEnumerable<string> GetUrlPrefixes()
{
@@ -1069,7 +1616,7 @@ namespace Emby.Server.Core
{
try
{
- ServerManager.Start(GetUrlPrefixes());
+ ServerManager.Start(GetUrlPrefixes().ToArray());
return;
}
catch (Exception ex)
@@ -1086,7 +1633,7 @@ namespace Emby.Server.Core
try
{
- ServerManager.Start(GetUrlPrefixes());
+ ServerManager.Start(GetUrlPrefixes().ToArray());
}
catch (Exception ex)
{
@@ -1121,7 +1668,7 @@ namespace Emby.Server.Core
try
{
- _certificateGenerator(certPath, certHost, password);
+ CertificateGenerator.CreateSelfSignCertificatePfx(certPath, certHost, password, Logger);
}
catch (Exception ex)
{
@@ -1143,9 +1690,9 @@ namespace Emby.Server.Core
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
- protected override void OnConfigurationUpdated(object sender, EventArgs e)
+ protected void OnConfigurationUpdated(object sender, EventArgs e)
{
- base.OnConfigurationUpdated(sender, e);
+ ConfigureAutorun();
var requiresRestart = false;
@@ -1189,9 +1736,26 @@ namespace Emby.Server.Core
}
/// <summary>
+ /// Notifies that the kernel that a change has been made that requires a restart
+ /// </summary>
+ public void NotifyPendingRestart()
+ {
+ Logger.Info("App needs to be restarted.");
+
+ var changed = !HasPendingRestart;
+
+ HasPendingRestart = true;
+
+ if (changed)
+ {
+ EventHelper.QueueEventIfNotNull(HasPendingRestartChanged, this, EventArgs.Empty, Logger);
+ }
+ }
+
+ /// <summary>
/// Restarts this instance.
/// </summary>
- public override async Task Restart()
+ public async Task Restart()
{
if (!CanSelfRestart)
{
@@ -1218,7 +1782,7 @@ namespace Emby.Server.Core
/// Gets the composable part assemblies.
/// </summary>
/// <returns>IEnumerable{Assembly}.</returns>
- protected override IEnumerable<Assembly> GetComposablePartAssemblies()
+ protected IEnumerable<Assembly> GetComposablePartAssemblies()
{
var list = GetPluginAssemblies()
.ToList();
@@ -1247,14 +1811,11 @@ namespace Emby.Server.Core
// Include composable parts in the Photos assembly
list.Add(GetAssembly(typeof(PhotoProvider)));
- // Common implementations
- list.Add(GetAssembly(typeof(TaskManager)));
-
// Emby.Server implementations
list.Add(GetAssembly(typeof(InstallationManager)));
// MediaEncoding
- list.Add(GetAssembly(typeof(MediaEncoder)));
+ list.Add(GetAssembly(typeof(MediaEncoding.Encoder.MediaEncoder)));
// Dlna
list.Add(GetAssembly(typeof(DlnaEntryPoint)));
@@ -1267,10 +1828,7 @@ namespace Emby.Server.Core
list.AddRange(GetAssembliesWithPartsInternal());
- // Include composable parts in the running assembly
- list.Add(GetAssembly(typeof(ApplicationHost)));
-
- return list;
+ return list.ToList();
}
protected abstract List<Assembly> GetAssembliesWithPartsInternal();
@@ -1322,9 +1880,9 @@ namespace Emby.Server.Core
HasPendingRestart = HasPendingRestart,
Version = ApplicationVersion.ToString(),
WebSocketPortNumber = HttpPort,
- FailedPluginAssemblies = FailedAssemblies.ToList(),
- InProgressInstallations = InstallationManager.CurrentInstallations.Select(i => i.Item1).ToList(),
- CompletedInstallations = InstallationManager.CompletedInstallations.ToList(),
+ FailedPluginAssemblies = FailedAssemblies.ToArray(),
+ InProgressInstallations = InstallationManager.CurrentInstallations.Select(i => i.Item1).ToArray(),
+ CompletedInstallations = InstallationManager.CompletedInstallations.ToArray(),
Id = SystemId,
ProgramDataPath = ApplicationPaths.ProgramDataPath,
LogPath = ApplicationPaths.LogDirectoryPath,
@@ -1545,7 +2103,7 @@ namespace Emby.Server.Core
/// <summary>
/// Shuts down.
/// </summary>
- public override async Task Shutdown()
+ public async Task Shutdown()
{
try
{
@@ -1607,27 +2165,34 @@ namespace Emby.Server.Core
}
/// <summary>
+ /// Removes the plugin.
+ /// </summary>
+ /// <param name="plugin">The plugin.</param>
+ public void RemovePlugin(IPlugin plugin)
+ {
+ var list = Plugins.ToList();
+ list.Remove(plugin);
+ Plugins = list.ToArray();
+ }
+
+ /// <summary>
/// Checks for update.
/// </summary>
/// <param name="cancellationToken">The cancellation token.</param>
/// <param name="progress">The progress.</param>
/// <returns>Task{CheckForUpdateResult}.</returns>
- public override async Task<CheckForUpdateResult> CheckForApplicationUpdate(CancellationToken cancellationToken, IProgress<double> progress)
+ public async Task<CheckForUpdateResult> CheckForApplicationUpdate(CancellationToken cancellationToken, IProgress<double> progress)
{
- var cacheLength = TimeSpan.FromHours(3);
+ var cacheLength = TimeSpan.FromHours(1);
var updateLevel = SystemUpdateLevel;
- if (updateLevel == PackageVersionClass.Beta)
- {
- cacheLength = TimeSpan.FromHours(1);
- }
- else if (updateLevel == PackageVersionClass.Dev)
+ if (updateLevel != PackageVersionClass.Release)
{
cacheLength = TimeSpan.FromMinutes(5);
}
var result = await new GithubUpdater(HttpClient, JsonSerializer).CheckForUpdateResult("MediaBrowser", "Emby", ApplicationVersion, updateLevel, _releaseAssetFilename,
- "MBServer", "Mbserver.zip", cacheLength, cancellationToken).ConfigureAwait(false);
+ "MBServer", "Mbserver.zip", cacheLength, cancellationToken).ConfigureAwait(false);
HasUpdateAvailable = result.IsUpdateAvailable;
@@ -1640,7 +2205,7 @@ namespace Emby.Server.Core
/// <param name="package">The package that contains the update</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <param name="progress">The progress.</param>
- public override async Task UpdateApplication(PackageVersionInfo package, CancellationToken cancellationToken, IProgress<double> progress)
+ public async Task UpdateApplication(PackageVersionInfo package, CancellationToken cancellationToken, IProgress<double> progress)
{
await InstallationManager.InstallPackage(package, false, progress, cancellationToken).ConfigureAwait(false);
@@ -1653,7 +2218,7 @@ namespace Emby.Server.Core
/// Configures the automatic run at startup.
/// </summary>
/// <param name="autorun">if set to <c>true</c> [autorun].</param>
- protected override void ConfigureAutoRunAtStartup(bool autorun)
+ protected void ConfigureAutoRunAtStartup(bool autorun)
{
if (SupportsAutoRunAtStartup)
{
@@ -1748,6 +2313,70 @@ namespace Emby.Server.Core
}
}
+ /// <summary>
+ /// Called when [application updated].
+ /// </summary>
+ /// <param name="package">The package.</param>
+ protected void OnApplicationUpdated(PackageVersionInfo package)
+ {
+ Logger.Info("Application has been updated to version {0}", package.versionStr);
+
+ EventHelper.FireEventIfNotNull(ApplicationUpdated, this, new GenericEventArgs<PackageVersionInfo>
+ {
+ Argument = package
+
+ }, Logger);
+
+ NotifyPendingRestart();
+ }
+
+ private bool _disposed;
+ /// <summary>
+ /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
+ /// </summary>
+ public void Dispose()
+ {
+ if (!_disposed)
+ {
+ _disposed = true;
+
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+ }
+
+ /// <summary>
+ /// Releases unmanaged and - optionally - managed resources.
+ /// </summary>
+ /// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
+ protected virtual void Dispose(bool dispose)
+ {
+ if (dispose)
+ {
+ var type = GetType();
+
+ LogManager.AddConsoleOutput();
+ Logger.Info("Disposing " + type.Name);
+
+ var parts = DisposableParts.Distinct().Where(i => i.GetType() != type).ToList();
+ DisposableParts.Clear();
+
+ foreach (var part in parts)
+ {
+ Logger.Info("Disposing " + part.GetType().Name);
+
+ try
+ {
+ part.Dispose();
+ }
+ catch (Exception ex)
+ {
+ Logger.ErrorException("Error disposing {0}", ex, part.GetType().Name);
+ }
+ }
+ }
+ }
+
void IDependencyContainer.RegisterSingleInstance<T>(T obj, bool manageLifetime)
{
RegisterSingleInstance(obj, manageLifetime);
diff --git a/Emby.Common.Implementations/Archiving/ZipClient.cs b/Emby.Server.Implementations/Archiving/ZipClient.cs
index 791c6678c..3218d56c6 100644
--- a/Emby.Common.Implementations/Archiving/ZipClient.cs
+++ b/Emby.Server.Implementations/Archiving/ZipClient.cs
@@ -3,11 +3,10 @@ using MediaBrowser.Model.IO;
using SharpCompress.Archives.Rar;
using SharpCompress.Archives.SevenZip;
using SharpCompress.Archives.Tar;
-using SharpCompress.Common;
using SharpCompress.Readers;
using SharpCompress.Readers.Zip;
-namespace Emby.Common.Implementations.Archiving
+namespace Emby.Server.Implementations.Archiving
{
/// <summary>
/// Class DotNetZipClient
diff --git a/Emby.Server.Implementations/Channels/ChannelImageProvider.cs b/Emby.Server.Implementations/Channels/ChannelImageProvider.cs
index f892b1e62..0c363c585 100644
--- a/Emby.Server.Implementations/Channels/ChannelImageProvider.cs
+++ b/Emby.Server.Implementations/Channels/ChannelImageProvider.cs
@@ -18,12 +18,12 @@ namespace Emby.Server.Implementations.Channels
_channelManager = channelManager;
}
- public IEnumerable<ImageType> GetSupportedImages(IHasImages item)
+ public IEnumerable<ImageType> GetSupportedImages(IHasMetadata item)
{
return GetChannel(item).GetSupportedChannelImages();
}
- public Task<DynamicImageResponse> GetImage(IHasImages item, ImageType type, CancellationToken cancellationToken)
+ public Task<DynamicImageResponse> GetImage(IHasMetadata item, ImageType type, CancellationToken cancellationToken)
{
var channel = GetChannel(item);
@@ -35,12 +35,12 @@ namespace Emby.Server.Implementations.Channels
get { return "Channel Image Provider"; }
}
- public bool Supports(IHasImages item)
+ public bool Supports(IHasMetadata item)
{
return item is Channel;
}
- private IChannel GetChannel(IHasImages item)
+ private IChannel GetChannel(IHasMetadata item)
{
var channel = (Channel)item;
diff --git a/Emby.Server.Implementations/Channels/ChannelManager.cs b/Emby.Server.Implementations/Channels/ChannelManager.cs
index 2adf6a37c..2f726f8ab 100644
--- a/Emby.Server.Implementations/Channels/ChannelManager.cs
+++ b/Emby.Server.Implementations/Channels/ChannelManager.cs
@@ -159,7 +159,7 @@ namespace Emby.Server.Implementations.Channels
all = all.Take(query.Limit.Value).ToList();
}
- var returnItems = all.ToArray();
+ var returnItems = all.ToArray(all.Count);
var result = new QueryResult<Channel>
{
@@ -182,8 +182,7 @@ namespace Emby.Server.Implementations.Channels
{
};
- var returnItems = (await _dtoService.GetBaseItemDtos(internalResult.Items, dtoOptions, user).ConfigureAwait(false))
- .ToArray();
+ var returnItems = _dtoService.GetBaseItemDtos(internalResult.Items, dtoOptions, user);
var result = new QueryResult<BaseItemDto>
{
@@ -429,7 +428,7 @@ namespace Emby.Server.Implementations.Channels
if (isNew)
{
- await _libraryManager.CreateItem(item, cancellationToken).ConfigureAwait(false);
+ _libraryManager.CreateItem(item, cancellationToken);
}
else if (forceUpdate)
{
@@ -462,14 +461,14 @@ namespace Emby.Server.Implementations.Channels
return _libraryManager.GetItemById(id) as Channel;
}
- public IEnumerable<ChannelFeatures> GetAllChannelFeatures()
+ public ChannelFeatures[] GetAllChannelFeatures()
{
return _libraryManager.GetItemIds(new InternalItemsQuery
{
IncludeItemTypes = new[] { typeof(Channel).Name },
- SortBy = new[] { ItemSortBy.SortName }
+ OrderBy = new Tuple<string, SortOrder>[] { new Tuple<string, SortOrder>(ItemSortBy.SortName, SortOrder.Ascending) }
- }).Select(i => GetChannelFeatures(i.ToString("N")));
+ }).Select(i => GetChannelFeatures(i.ToString("N"))).ToArray();
}
public ChannelFeatures GetChannelFeatures(string id)
@@ -509,10 +508,10 @@ namespace Emby.Server.Implementations.Channels
{
CanFilter = !features.MaxPageSize.HasValue,
CanSearch = provider is ISearchableChannel,
- ContentTypes = features.ContentTypes,
- DefaultSortFields = features.DefaultSortFields,
+ ContentTypes = features.ContentTypes.ToArray(),
+ DefaultSortFields = features.DefaultSortFields.ToArray(),
MaxPageSize = features.MaxPageSize,
- MediaTypes = features.MediaTypes,
+ MediaTypes = features.MediaTypes.ToArray(),
SupportsSortOrderToggle = features.SupportsSortOrderToggle,
SupportsLatestMedia = supportsLatest,
Name = channel.Name,
@@ -564,11 +563,10 @@ namespace Emby.Server.Implementations.Channels
var dtoOptions = new DtoOptions()
{
- Fields = query.Fields.ToList()
+ Fields = query.Fields
};
- var returnItems = (await _dtoService.GetBaseItemDtos(items, dtoOptions, user).ConfigureAwait(false))
- .ToArray();
+ var returnItems = _dtoService.GetBaseItemDtos(items, dtoOptions, user);
var result = new QueryResult<BaseItemDto>
{
@@ -676,12 +674,10 @@ namespace Emby.Server.Implementations.Channels
internalItems = internalItems.Take(query.Limit.Value).ToArray();
}
- var returnItemArray = internalItems.ToArray();
-
return new QueryResult<BaseItem>
{
TotalRecordCount = totalCount,
- Items = returnItemArray
+ Items = internalItems
};
}
@@ -813,12 +809,10 @@ namespace Emby.Server.Implementations.Channels
var internalItems = await Task.WhenAll(itemTasks).ConfigureAwait(false);
- var returnItemArray = internalItems.ToArray();
-
return new QueryResult<BaseItem>
{
TotalRecordCount = totalCount,
- Items = returnItemArray
+ Items = internalItems
};
}
@@ -834,11 +828,10 @@ namespace Emby.Server.Implementations.Channels
var dtoOptions = new DtoOptions()
{
- Fields = query.Fields.ToList()
+ Fields = query.Fields
};
- var returnItems = (await _dtoService.GetBaseItemDtos(internalResult.Items, dtoOptions, user).ConfigureAwait(false))
- .ToArray();
+ var returnItems = _dtoService.GetBaseItemDtos(internalResult.Items, dtoOptions, user);
var result = new QueryResult<BaseItemDto>
{
@@ -939,14 +932,15 @@ namespace Emby.Server.Implementations.Channels
ChannelItemSortField? sortField = null;
ChannelItemSortField parsedField;
- if (query.SortBy.Length == 1 &&
- Enum.TryParse(query.SortBy[0], true, out parsedField))
+ var sortDescending = false;
+
+ if (query.OrderBy.Length == 1 &&
+ Enum.TryParse(query.OrderBy[0].Item1, true, out parsedField))
{
sortField = parsedField;
+ sortDescending = query.OrderBy[0].Item2 == SortOrder.Descending;
}
- var sortDescending = query.SortOrder.HasValue && query.SortOrder.Value == SortOrder.Descending;
-
var itemsResult = await GetChannelItems(channelProvider,
user,
query.FolderId,
@@ -986,11 +980,10 @@ namespace Emby.Server.Implementations.Channels
var dtoOptions = new DtoOptions()
{
- Fields = query.Fields.ToList()
+ Fields = query.Fields
};
- var returnItems = (await _dtoService.GetBaseItemDtos(internalResult.Items, dtoOptions, user).ConfigureAwait(false))
- .ToArray();
+ var returnItems = _dtoService.GetBaseItemDtos(internalResult.Items, dtoOptions, user);
var result = new QueryResult<BaseItemDto>
{
@@ -1174,7 +1167,7 @@ namespace Emby.Server.Implementations.Channels
{
items = ApplyFilters(items, query.Filters, user);
- items = _libraryManager.Sort(items, user, query.SortBy, query.SortOrder ?? SortOrder.Ascending);
+ items = _libraryManager.Sort(items, user, query.OrderBy);
var all = items.ToList();
var totalCount = totalCountFromProvider ?? all.Count;
@@ -1191,7 +1184,7 @@ namespace Emby.Server.Implementations.Channels
}
}
- var returnItemArray = all.ToArray();
+ var returnItemArray = all.ToArray(all.Count);
RefreshIfNeeded(returnItemArray);
return new QueryResult<BaseItem>
@@ -1309,7 +1302,7 @@ namespace Emby.Server.Implementations.Channels
{
item.Name = info.Name;
item.Genres = info.Genres;
- item.Studios = info.Studios;
+ item.Studios = info.Studios.ToArray(info.Studios.Count);
item.CommunityRating = info.CommunityRating;
item.Overview = info.Overview;
item.IndexNumber = info.IndexNumber;
@@ -1319,7 +1312,7 @@ namespace Emby.Server.Implementations.Channels
item.ProviderIds = info.ProviderIds;
item.OfficialRating = info.OfficialRating;
item.DateCreated = info.DateCreated ?? DateTime.UtcNow;
- item.Tags = info.Tags;
+ item.Tags = info.Tags.ToArray(info.Tags.Count);
item.HomePageUrl = info.HomePageUrl;
}
else if (info.Type == ChannelItemType.Folder && info.FolderType == ChannelFolderType.Container)
@@ -1335,13 +1328,13 @@ namespace Emby.Server.Implementations.Channels
var hasArtists = item as IHasArtist;
if (hasArtists != null)
{
- hasArtists.Artists = info.Artists;
+ hasArtists.Artists = info.Artists.ToArray();
}
var hasAlbumArtists = item as IHasAlbumArtist;
if (hasAlbumArtists != null)
{
- hasAlbumArtists.AlbumArtists = info.AlbumArtists;
+ hasAlbumArtists.AlbumArtists = info.AlbumArtists.ToArray(info.AlbumArtists.Count);
}
var trailer = item as Trailer;
@@ -1393,11 +1386,11 @@ namespace Emby.Server.Implementations.Channels
if (isNew)
{
- await _libraryManager.CreateItem(item, cancellationToken).ConfigureAwait(false);
+ _libraryManager.CreateItem(item, cancellationToken);
if (info.People != null && info.People.Count > 0)
{
- await _libraryManager.UpdatePeople(item, info.People ?? new List<PersonInfo>()).ConfigureAwait(false);
+ _libraryManager.UpdatePeople(item, info.People ?? new List<PersonInfo>());
}
}
else if (forceUpdate)
@@ -1631,6 +1624,7 @@ namespace Emby.Server.Implementations.Channels
public void Dispose()
{
+ GC.SuppressFinalize(this);
}
}
} \ No newline at end of file
diff --git a/Emby.Server.Implementations/Collections/CollectionImageProvider.cs b/Emby.Server.Implementations/Collections/CollectionImageProvider.cs
index 463d276e5..c7378956d 100644
--- a/Emby.Server.Implementations/Collections/CollectionImageProvider.cs
+++ b/Emby.Server.Implementations/Collections/CollectionImageProvider.cs
@@ -21,7 +21,7 @@ namespace Emby.Server.Implementations.Collections
{
}
- protected override bool Supports(IHasImages item)
+ protected override bool Supports(IHasMetadata item)
{
// Right now this is the only way to prevent this image from getting created ahead of internet image providers
if (!item.IsLocked)
@@ -32,7 +32,7 @@ namespace Emby.Server.Implementations.Collections
return base.Supports(item);
}
- protected override List<BaseItem> GetItemsWithImages(IHasImages item)
+ protected override List<BaseItem> GetItemsWithImages(IHasMetadata item)
{
var playlist = (BoxSet)item;
@@ -76,7 +76,7 @@ namespace Emby.Server.Implementations.Collections
return GetFinalItems(items, 2);
}
- protected override string CreateImage(IHasImages item, List<BaseItem> itemsWithImages, string outputPathWithoutExtension, ImageType imageType, int imageIndex)
+ protected override string CreateImage(IHasMetadata item, List<BaseItem> itemsWithImages, string outputPathWithoutExtension, ImageType imageType, int imageIndex)
{
return CreateSingleImage(itemsWithImages, outputPathWithoutExtension, ImageType.Primary);
}
diff --git a/Emby.Server.Implementations/Collections/CollectionManager.cs b/Emby.Server.Implementations/Collections/CollectionManager.cs
index 4e5d344a3..2e884e729 100644
--- a/Emby.Server.Implementations/Collections/CollectionManager.cs
+++ b/Emby.Server.Implementations/Collections/CollectionManager.cs
@@ -12,6 +12,7 @@ using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Model.IO;
+using MediaBrowser.Model.Extensions;
namespace Emby.Server.Implementations.Collections
{
@@ -83,15 +84,15 @@ namespace Emby.Server.Implementations.Collections
ProviderIds = options.ProviderIds,
Shares = options.UserIds.Select(i => new Share
{
- UserId = i.ToString("N"),
+ UserId = i,
CanEdit = true
}).ToList()
};
- await parentFolder.AddChild(collection, CancellationToken.None).ConfigureAwait(false);
+ parentFolder.AddChild(collection, CancellationToken.None);
- if (options.ItemIdList.Count > 0)
+ if (options.ItemIdList.Length > 0)
{
await AddToCollection(collection.Id, options.ItemIdList, false, new MetadataRefreshOptions(_fileSystem)
{
@@ -148,12 +149,17 @@ namespace Emby.Server.Implementations.Collections
return GetCollectionsFolder(string.Empty);
}
- public Task AddToCollection(Guid collectionId, IEnumerable<Guid> ids)
+ public Task AddToCollection(Guid collectionId, IEnumerable<string> ids)
{
return AddToCollection(collectionId, ids, true, new MetadataRefreshOptions(_fileSystem));
}
- private async Task AddToCollection(Guid collectionId, IEnumerable<Guid> ids, bool fireEvent, MetadataRefreshOptions refreshOptions)
+ public Task AddToCollection(Guid collectionId, IEnumerable<Guid> ids)
+ {
+ return AddToCollection(collectionId, ids.Select(i => i.ToString("N")), true, new MetadataRefreshOptions(_fileSystem));
+ }
+
+ private async Task AddToCollection(Guid collectionId, IEnumerable<string> ids, bool fireEvent, MetadataRefreshOptions refreshOptions)
{
var collection = _libraryManager.GetItemById(collectionId) as BoxSet;
@@ -164,11 +170,12 @@ namespace Emby.Server.Implementations.Collections
var list = new List<LinkedChild>();
var itemList = new List<BaseItem>();
- var currentLinkedChildren = collection.GetLinkedChildren().ToList();
+ var currentLinkedChildrenIds = collection.GetLinkedChildren().Select(i => i.Id).ToList();
- foreach (var itemId in ids)
+ foreach (var id in ids)
{
- var item = _libraryManager.GetItemById(itemId);
+ var guidId = new Guid(id);
+ var item = _libraryManager.GetItemById(guidId);
if (string.IsNullOrWhiteSpace(item.Path))
{
@@ -182,7 +189,7 @@ namespace Emby.Server.Implementations.Collections
itemList.Add(item);
- if (currentLinkedChildren.All(i => i.Id != itemId))
+ if (!currentLinkedChildrenIds.Contains(guidId))
{
list.Add(LinkedChild.Create(item));
}
@@ -190,7 +197,9 @@ namespace Emby.Server.Implementations.Collections
if (list.Count > 0)
{
- collection.LinkedChildren.AddRange(list);
+ var newList = collection.LinkedChildren.ToList();
+ newList.AddRange(list);
+ collection.LinkedChildren = newList.ToArray(newList.Count);
collection.UpdateRatingToContent();
@@ -210,6 +219,11 @@ namespace Emby.Server.Implementations.Collections
}
}
+ public Task RemoveFromCollection(Guid collectionId, IEnumerable<string> itemIds)
+ {
+ return RemoveFromCollection(collectionId, itemIds.Select(i => new Guid(i)));
+ }
+
public async Task RemoveFromCollection(Guid collectionId, IEnumerable<Guid> itemIds)
{
var collection = _libraryManager.GetItemById(collectionId) as BoxSet;
@@ -222,11 +236,11 @@ namespace Emby.Server.Implementations.Collections
var list = new List<LinkedChild>();
var itemList = new List<BaseItem>();
- foreach (var itemId in itemIds)
+ foreach (var guidId in itemIds)
{
- var childItem = _libraryManager.GetItemById(itemId);
+ var childItem = _libraryManager.GetItemById(guidId);
- var child = collection.LinkedChildren.FirstOrDefault(i => (i.ItemId.HasValue && i.ItemId.Value == itemId) || (childItem != null && string.Equals(childItem.Path, i.Path, StringComparison.OrdinalIgnoreCase)));
+ var child = collection.LinkedChildren.FirstOrDefault(i => (i.ItemId.HasValue && i.ItemId.Value == guidId) || (childItem != null && string.Equals(childItem.Path, i.Path, StringComparison.OrdinalIgnoreCase)));
if (child == null)
{
@@ -241,9 +255,9 @@ namespace Emby.Server.Implementations.Collections
}
}
- foreach (var child in list)
+ if (list.Count > 0)
{
- collection.LinkedChildren.Remove(child);
+ collection.LinkedChildren = collection.LinkedChildren.Except(list).ToArray();
}
collection.UpdateRatingToContent();
diff --git a/Emby.Server.Implementations/Configuration/ServerConfigurationManager.cs b/Emby.Server.Implementations/Configuration/ServerConfigurationManager.cs
index 2241e9377..4d9bf0624 100644
--- a/Emby.Server.Implementations/Configuration/ServerConfigurationManager.cs
+++ b/Emby.Server.Implementations/Configuration/ServerConfigurationManager.cs
@@ -16,6 +16,7 @@ using MediaBrowser.Model.Events;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Serialization;
+using MediaBrowser.Model.Extensions;
namespace Emby.Server.Implementations.Configuration
{
@@ -216,7 +217,7 @@ namespace Emby.Server.Implementations.Configuration
list.Add(service);
- options.DisabledMetadataSavers = list.ToArray();
+ options.DisabledMetadataSavers = list.ToArray(list.Count);
}
}
@@ -236,7 +237,7 @@ namespace Emby.Server.Implementations.Configuration
list.Add(options);
- config.MetadataOptions = list.ToArray();
+ config.MetadataOptions = list.ToArray(list.Count);
}
return options;
diff --git a/Emby.Server.Core/Cryptography/ASN1.cs b/Emby.Server.Implementations/Cryptography/ASN1.cs
index f5c826436..f5c826436 100644
--- a/Emby.Server.Core/Cryptography/ASN1.cs
+++ b/Emby.Server.Implementations/Cryptography/ASN1.cs
diff --git a/Emby.Server.Core/Cryptography/ASN1Convert.cs b/Emby.Server.Implementations/Cryptography/ASN1Convert.cs
index 851d36dc7..851d36dc7 100644
--- a/Emby.Server.Core/Cryptography/ASN1Convert.cs
+++ b/Emby.Server.Implementations/Cryptography/ASN1Convert.cs
diff --git a/Emby.Server.Core/Cryptography/BitConverterLE.cs b/Emby.Server.Implementations/Cryptography/BitConverterLE.cs
index 34e6bf6dc..34e6bf6dc 100644
--- a/Emby.Server.Core/Cryptography/BitConverterLE.cs
+++ b/Emby.Server.Implementations/Cryptography/BitConverterLE.cs
diff --git a/Emby.Server.Core/Cryptography/CertificateGenerator.cs b/Emby.Server.Implementations/Cryptography/CertificateGenerator.cs
index 2600d7470..b4c84a600 100644
--- a/Emby.Server.Core/Cryptography/CertificateGenerator.cs
+++ b/Emby.Server.Implementations/Cryptography/CertificateGenerator.cs
@@ -2,6 +2,7 @@
using System;
using System.Collections;
using System.Security.Cryptography;
+using System.Xml;
namespace Emby.Server.Core.Cryptography
{
@@ -27,7 +28,11 @@ namespace Emby.Server.Core.Cryptography
DateTime notAfter = DateTime.Now.AddYears(10);
RSA issuerKey = RSA.Create();
+#if NET46
issuerKey.FromXmlString(MonoTestRootAgency);
+#else
+ RSACryptoServiceProviderExtensions.FromXmlString(issuerKey, MonoTestRootAgency);
+#endif
RSA subjectKey = RSA.Create();
// serial number MUST be positive
@@ -44,7 +49,7 @@ namespace Emby.Server.Core.Cryptography
cb.NotAfter = notAfter;
cb.SubjectName = subject;
cb.SubjectPublicKey = subjectKey;
-
+
// signature
cb.Hash = "SHA256";
byte[] rawcert = cb.Sign(issuerKey);
@@ -66,4 +71,39 @@ namespace Emby.Server.Core.Cryptography
p12.SaveToFile(fileName);
}
}
+
+ public static class RSACryptoServiceProviderExtensions
+ {
+ public static void FromXmlString(RSA rsa, string xmlString)
+ {
+ RSAParameters parameters = new RSAParameters();
+
+ XmlDocument xmlDoc = new XmlDocument();
+ xmlDoc.LoadXml(xmlString);
+
+ if (xmlDoc.DocumentElement.Name.Equals("RSAKeyValue"))
+ {
+ foreach (XmlNode node in xmlDoc.DocumentElement.ChildNodes)
+ {
+ switch (node.Name)
+ {
+ case "Modulus": parameters.Modulus = Convert.FromBase64String(node.InnerText); break;
+ case "Exponent": parameters.Exponent = Convert.FromBase64String(node.InnerText); break;
+ case "P": parameters.P = Convert.FromBase64String(node.InnerText); break;
+ case "Q": parameters.Q = Convert.FromBase64String(node.InnerText); break;
+ case "DP": parameters.DP = Convert.FromBase64String(node.InnerText); break;
+ case "DQ": parameters.DQ = Convert.FromBase64String(node.InnerText); break;
+ case "InverseQ": parameters.InverseQ = Convert.FromBase64String(node.InnerText); break;
+ case "D": parameters.D = Convert.FromBase64String(node.InnerText); break;
+ }
+ }
+ }
+ else
+ {
+ throw new Exception("Invalid XML RSA key.");
+ }
+
+ rsa.ImportParameters(parameters);
+ }
+ }
}
diff --git a/Emby.Server.Core/Cryptography/CryptoConvert.cs b/Emby.Server.Implementations/Cryptography/CryptoConvert.cs
index 70a91bfff..70a91bfff 100644
--- a/Emby.Server.Core/Cryptography/CryptoConvert.cs
+++ b/Emby.Server.Implementations/Cryptography/CryptoConvert.cs
diff --git a/Emby.Common.Implementations/Cryptography/CryptographyProvider.cs b/Emby.Server.Implementations/Cryptography/CryptographyProvider.cs
index 01a31bcc0..6402da0c9 100644
--- a/Emby.Common.Implementations/Cryptography/CryptographyProvider.cs
+++ b/Emby.Server.Implementations/Cryptography/CryptographyProvider.cs
@@ -4,7 +4,7 @@ using System.Security.Cryptography;
using System.Text;
using MediaBrowser.Model.Cryptography;
-namespace Emby.Common.Implementations.Cryptography
+namespace Emby.Server.Implementations.Cryptography
{
public class CryptographyProvider : ICryptoProvider
{
diff --git a/Emby.Server.Core/Cryptography/PKCS1.cs b/Emby.Server.Implementations/Cryptography/PKCS1.cs
index 24c0708c5..24c0708c5 100644
--- a/Emby.Server.Core/Cryptography/PKCS1.cs
+++ b/Emby.Server.Implementations/Cryptography/PKCS1.cs
diff --git a/Emby.Server.Core/Cryptography/PKCS12.cs b/Emby.Server.Implementations/Cryptography/PKCS12.cs
index 50f3776d9..50f3776d9 100644
--- a/Emby.Server.Core/Cryptography/PKCS12.cs
+++ b/Emby.Server.Implementations/Cryptography/PKCS12.cs
diff --git a/Emby.Server.Core/Cryptography/PKCS7.cs b/Emby.Server.Implementations/Cryptography/PKCS7.cs
index 475854500..475854500 100644
--- a/Emby.Server.Core/Cryptography/PKCS7.cs
+++ b/Emby.Server.Implementations/Cryptography/PKCS7.cs
diff --git a/Emby.Server.Core/Cryptography/PKCS8.cs b/Emby.Server.Implementations/Cryptography/PKCS8.cs
index 7e9a27298..7e9a27298 100644
--- a/Emby.Server.Core/Cryptography/PKCS8.cs
+++ b/Emby.Server.Implementations/Cryptography/PKCS8.cs
diff --git a/Emby.Server.Core/Cryptography/PfxGenerator.cs b/Emby.Server.Implementations/Cryptography/PfxGenerator.cs
index 2d1dd649e..2d1dd649e 100644
--- a/Emby.Server.Core/Cryptography/PfxGenerator.cs
+++ b/Emby.Server.Implementations/Cryptography/PfxGenerator.cs
diff --git a/Emby.Server.Core/Cryptography/X501Name.cs b/Emby.Server.Implementations/Cryptography/X501Name.cs
index 3318f95e2..3318f95e2 100644
--- a/Emby.Server.Core/Cryptography/X501Name.cs
+++ b/Emby.Server.Implementations/Cryptography/X501Name.cs
diff --git a/Emby.Server.Core/Cryptography/X509Builder.cs b/Emby.Server.Implementations/Cryptography/X509Builder.cs
index a2e292350..a2e292350 100644
--- a/Emby.Server.Core/Cryptography/X509Builder.cs
+++ b/Emby.Server.Implementations/Cryptography/X509Builder.cs
diff --git a/Emby.Server.Core/Cryptography/X509Certificate.cs b/Emby.Server.Implementations/Cryptography/X509Certificate.cs
index 3de58cfee..3de58cfee 100644
--- a/Emby.Server.Core/Cryptography/X509Certificate.cs
+++ b/Emby.Server.Implementations/Cryptography/X509Certificate.cs
diff --git a/Emby.Server.Core/Cryptography/X509CertificateBuilder.cs b/Emby.Server.Implementations/Cryptography/X509CertificateBuilder.cs
index cecff6578..cecff6578 100644
--- a/Emby.Server.Core/Cryptography/X509CertificateBuilder.cs
+++ b/Emby.Server.Implementations/Cryptography/X509CertificateBuilder.cs
diff --git a/Emby.Server.Core/Cryptography/X509CertificateCollection.cs b/Emby.Server.Implementations/Cryptography/X509CertificateCollection.cs
index a129bfc1a..a129bfc1a 100644
--- a/Emby.Server.Core/Cryptography/X509CertificateCollection.cs
+++ b/Emby.Server.Implementations/Cryptography/X509CertificateCollection.cs
diff --git a/Emby.Server.Core/Cryptography/X509Extension.cs b/Emby.Server.Implementations/Cryptography/X509Extension.cs
index 36b17deba..36b17deba 100644
--- a/Emby.Server.Core/Cryptography/X509Extension.cs
+++ b/Emby.Server.Implementations/Cryptography/X509Extension.cs
diff --git a/Emby.Server.Core/Cryptography/X509Extensions.cs b/Emby.Server.Implementations/Cryptography/X509Extensions.cs
index 018a04d79..018a04d79 100644
--- a/Emby.Server.Core/Cryptography/X509Extensions.cs
+++ b/Emby.Server.Implementations/Cryptography/X509Extensions.cs
diff --git a/Emby.Server.Core/Cryptography/X520Attributes.cs b/Emby.Server.Implementations/Cryptography/X520Attributes.cs
index da7fd2b82..da7fd2b82 100644
--- a/Emby.Server.Core/Cryptography/X520Attributes.cs
+++ b/Emby.Server.Implementations/Cryptography/X520Attributes.cs
diff --git a/Emby.Server.Implementations/Data/BaseSqliteRepository.cs b/Emby.Server.Implementations/Data/BaseSqliteRepository.cs
index 462ff3e47..a34c90cb4 100644
--- a/Emby.Server.Implementations/Data/BaseSqliteRepository.cs
+++ b/Emby.Server.Implementations/Data/BaseSqliteRepository.cs
@@ -131,25 +131,11 @@ namespace Emby.Server.Implementations.Data
{
queries.Add("PRAGMA temp_store = memory");
}
-
- ////foreach (var query in queries)
- ////{
- //// db.Execute(query);
- ////}
-
- //Logger.Info("synchronous: " + db.Query("PRAGMA synchronous").SelectScalarString().First());
- //Logger.Info("temp_store: " + db.Query("PRAGMA temp_store").SelectScalarString().First());
-
- /*if (!string.Equals(_defaultWal, "wal", StringComparison.OrdinalIgnoreCase))
+ else
{
- queries.Add("PRAGMA journal_mode=WAL");
-
- using (WriteLock.Write())
- {
- db.ExecuteAll(string.Join(";", queries.ToArray()));
- }
+ queries.Add("PRAGMA temp_store = file");
}
- else*/
+
foreach (var query in queries)
{
db.Execute(query);
@@ -208,6 +194,13 @@ namespace Emby.Server.Implementations.Data
"pragma temp_store = memory"
});
}
+ else
+ {
+ queries.AddRange(new List<string>
+ {
+ "pragma temp_store = file"
+ });
+ }
db.ExecuteAll(string.Join(";", queries.ToArray()));
Logger.Info("PRAGMA synchronous=" + db.Query("PRAGMA synchronous").SelectScalarString().First());
diff --git a/Emby.Server.Implementations/Data/CleanDatabaseScheduledTask.cs b/Emby.Server.Implementations/Data/CleanDatabaseScheduledTask.cs
index f43e45441..37ba2eb5f 100644
--- a/Emby.Server.Implementations/Data/CleanDatabaseScheduledTask.cs
+++ b/Emby.Server.Implementations/Data/CleanDatabaseScheduledTask.cs
@@ -11,9 +11,6 @@ using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Model.IO;
-using MediaBrowser.Controller.Channels;
-using MediaBrowser.Controller.Entities.Audio;
-using MediaBrowser.Model.Tasks;
namespace Emby.Server.Implementations.Data
{
@@ -34,31 +31,9 @@ namespace Emby.Server.Implementations.Data
_appPaths = appPaths;
}
- public string Name
+ public Task Run(IProgress<double> progress, CancellationToken cancellationToken)
{
- get { return "Clean Database"; }
- }
-
- public string Description
- {
- get { return "Deletes obsolete content from the database."; }
- }
-
- public string Category
- {
- get { return "Library"; }
- }
-
- public async Task Run(IProgress<double> progress, CancellationToken cancellationToken)
- {
- // Ensure these objects are lazy loaded.
- // Without this there is a deadlock that will need to be investigated
- var rootChildren = _libraryManager.RootFolder.Children.ToList();
- rootChildren = _libraryManager.GetUserRootFolder().Children.ToList();
-
- await CleanDeadItems(cancellationToken, progress).ConfigureAwait(false);
-
- //await _itemRepo.UpdateInheritedValues(cancellationToken).ConfigureAwait(false);
+ return CleanDeadItems(cancellationToken, progress);
}
private async Task CleanDeadItems(CancellationToken cancellationToken, IProgress<double> progress)
@@ -98,23 +73,5 @@ namespace Emby.Server.Implementations.Data
progress.Report(100);
}
-
- /// <summary>
- /// Creates the triggers that define when the task will run
- /// </summary>
- /// <returns>IEnumerable{BaseTaskTrigger}.</returns>
- public IEnumerable<TaskTriggerInfo> GetDefaultTriggers()
- {
- return new[] {
-
- // Every so often
- new TaskTriggerInfo { Type = TaskTriggerInfo.TriggerInterval, IntervalTicks = TimeSpan.FromHours(24).Ticks}
- };
- }
-
- public string Key
- {
- get { return "CleanDatabase"; }
- }
}
} \ No newline at end of file
diff --git a/Emby.Server.Implementations/Data/ManagedConnection.cs b/Emby.Server.Implementations/Data/ManagedConnection.cs
index 91a2dfdf6..5d0fc8ebc 100644
--- a/Emby.Server.Implementations/Data/ManagedConnection.cs
+++ b/Emby.Server.Implementations/Data/ManagedConnection.cs
@@ -77,6 +77,7 @@ namespace Emby.Server.Implementations.Data
{
Close();
}
+ GC.SuppressFinalize(this);
}
}
}
diff --git a/Emby.Server.Implementations/Data/SqliteDisplayPreferencesRepository.cs b/Emby.Server.Implementations/Data/SqliteDisplayPreferencesRepository.cs
index 4118bd1b2..89664d158 100644
--- a/Emby.Server.Implementations/Data/SqliteDisplayPreferencesRepository.cs
+++ b/Emby.Server.Implementations/Data/SqliteDisplayPreferencesRepository.cs
@@ -2,7 +2,6 @@
using System.Collections.Generic;
using System.IO;
using System.Threading;
-using System.Threading.Tasks;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Controller.Persistence;
@@ -75,7 +74,7 @@ namespace Emby.Server.Implementations.Data
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
/// <exception cref="System.ArgumentNullException">item</exception>
- public async Task SaveDisplayPreferences(DisplayPreferences displayPreferences, Guid userId, string client, CancellationToken cancellationToken)
+ public void SaveDisplayPreferences(DisplayPreferences displayPreferences, Guid userId, string client, CancellationToken cancellationToken)
{
if (displayPreferences == null)
{
@@ -123,7 +122,7 @@ namespace Emby.Server.Implementations.Data
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
/// <exception cref="System.ArgumentNullException">item</exception>
- public async Task SaveAllDisplayPreferences(IEnumerable<DisplayPreferences> displayPreferences, Guid userId, CancellationToken cancellationToken)
+ public void SaveAllDisplayPreferences(IEnumerable<DisplayPreferences> displayPreferences, Guid userId, CancellationToken cancellationToken)
{
if (displayPreferences == null)
{
@@ -226,9 +225,9 @@ namespace Emby.Server.Implementations.Data
}
}
- public Task SaveDisplayPreferences(DisplayPreferences displayPreferences, string userId, string client, CancellationToken cancellationToken)
+ public void SaveDisplayPreferences(DisplayPreferences displayPreferences, string userId, string client, CancellationToken cancellationToken)
{
- return SaveDisplayPreferences(displayPreferences, new Guid(userId), client, cancellationToken);
+ SaveDisplayPreferences(displayPreferences, new Guid(userId), client, cancellationToken);
}
public DisplayPreferences GetDisplayPreferences(string displayPreferencesId, string userId, string client)
diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs
index 528acd069..165d17a57 100644
--- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs
+++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs
@@ -7,6 +7,8 @@ using System.Runtime.Serialization;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
+using Emby.Server.Implementations.Devices;
+using Emby.Server.Implementations.Playlists;
using MediaBrowser.Controller.Channels;
using MediaBrowser.Controller.Collections;
using MediaBrowser.Controller.Configuration;
@@ -25,12 +27,11 @@ using MediaBrowser.Model.LiveTv;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Querying;
using MediaBrowser.Model.Serialization;
-using MediaBrowser.Server.Implementations.Devices;
-using MediaBrowser.Server.Implementations.Playlists;
using MediaBrowser.Model.Reflection;
using SQLitePCL.pretty;
using MediaBrowser.Model.System;
using MediaBrowser.Model.Threading;
+using MediaBrowser.Model.Extensions;
namespace Emby.Server.Implementations.Data
{
@@ -131,8 +132,7 @@ namespace Emby.Server.Implementations.Data
/// <summary>
/// Opens the connection to the database
/// </summary>
- /// <returns>Task.</returns>
- public async Task Initialize(SqliteUserDataRepository userDataRepo)
+ public void Initialize(SqliteUserDataRepository userDataRepo)
{
using (var connection = CreateConnection())
{
@@ -148,7 +148,7 @@ namespace Emby.Server.Implementations.Data
"create table if not exists AncestorIds (ItemId GUID, AncestorId GUID, AncestorIdText TEXT, PRIMARY KEY (ItemId, AncestorId))",
"create index if not exists idx_AncestorIds1 on AncestorIds(AncestorId)",
- "create index if not exists idx_AncestorIds2 on AncestorIds(AncestorIdText)",
+ "create index if not exists idx_AncestorIds5 on AncestorIds(AncestorIdText,ItemId)",
"create table if not exists ItemValues (ItemId GUID, Type INT, Value TEXT, CleanValue TEXT)",
@@ -190,7 +190,6 @@ namespace Emby.Server.Implementations.Data
AddColumn(db, "TypedBaseItems", "IsLocked", "BIT", existingColumnNames);
AddColumn(db, "TypedBaseItems", "Name", "Text", existingColumnNames);
AddColumn(db, "TypedBaseItems", "OfficialRating", "Text", existingColumnNames);
-
AddColumn(db, "TypedBaseItems", "MediaType", "Text", existingColumnNames);
AddColumn(db, "TypedBaseItems", "Overview", "Text", existingColumnNames);
AddColumn(db, "TypedBaseItems", "ParentIndexNumber", "INT", existingColumnNames);
@@ -200,28 +199,21 @@ namespace Emby.Server.Implementations.Data
AddColumn(db, "TypedBaseItems", "Genres", "Text", existingColumnNames);
AddColumn(db, "TypedBaseItems", "SortName", "Text", existingColumnNames);
AddColumn(db, "TypedBaseItems", "ForcedSortName", "Text", existingColumnNames);
-
AddColumn(db, "TypedBaseItems", "RunTimeTicks", "BIGINT", existingColumnNames);
-
AddColumn(db, "TypedBaseItems", "HomePageUrl", "Text", existingColumnNames);
- AddColumn(db, "TypedBaseItems", "DisplayMediaType", "Text", existingColumnNames);
AddColumn(db, "TypedBaseItems", "DateCreated", "DATETIME", existingColumnNames);
AddColumn(db, "TypedBaseItems", "DateModified", "DATETIME", existingColumnNames);
-
AddColumn(db, "TypedBaseItems", "IsSeries", "BIT", existingColumnNames);
AddColumn(db, "TypedBaseItems", "IsLive", "BIT", existingColumnNames);
AddColumn(db, "TypedBaseItems", "IsNews", "BIT", existingColumnNames);
AddColumn(db, "TypedBaseItems", "IsPremiere", "BIT", existingColumnNames);
-
AddColumn(db, "TypedBaseItems", "EpisodeTitle", "Text", existingColumnNames);
AddColumn(db, "TypedBaseItems", "IsRepeat", "BIT", existingColumnNames);
-
AddColumn(db, "TypedBaseItems", "PreferredMetadataLanguage", "Text", existingColumnNames);
AddColumn(db, "TypedBaseItems", "PreferredMetadataCountryCode", "Text", existingColumnNames);
AddColumn(db, "TypedBaseItems", "IsHD", "BIT", existingColumnNames);
AddColumn(db, "TypedBaseItems", "ExternalEtag", "Text", existingColumnNames);
AddColumn(db, "TypedBaseItems", "DateLastRefreshed", "DATETIME", existingColumnNames);
-
AddColumn(db, "TypedBaseItems", "DateLastSaved", "DATETIME", existingColumnNames);
AddColumn(db, "TypedBaseItems", "IsInMixedFolder", "BIT", existingColumnNames);
AddColumn(db, "TypedBaseItems", "LockedFields", "Text", existingColumnNames);
@@ -235,7 +227,6 @@ namespace Emby.Server.Implementations.Data
AddColumn(db, "TypedBaseItems", "TopParentId", "Text", existingColumnNames);
AddColumn(db, "TypedBaseItems", "TrailerTypes", "Text", existingColumnNames);
AddColumn(db, "TypedBaseItems", "CriticRating", "Float", existingColumnNames);
- AddColumn(db, "TypedBaseItems", "InheritedTags", "Text", existingColumnNames);
AddColumn(db, "TypedBaseItems", "CleanName", "Text", existingColumnNames);
AddColumn(db, "TypedBaseItems", "PresentationUniqueKey", "Text", existingColumnNames);
AddColumn(db, "TypedBaseItems", "OriginalTitle", "Text", existingColumnNames);
@@ -314,6 +305,9 @@ namespace Emby.Server.Implementations.Data
"drop index if exists idx_TypeSeriesPresentationUniqueKey",
"drop index if exists idx_SeriesPresentationUniqueKey",
"drop index if exists idx_TypeSeriesPresentationUniqueKey2",
+ "drop index if exists idx_AncestorIds3",
+ "drop index if exists idx_AncestorIds4",
+ "drop index if exists idx_AncestorIds2",
"create index if not exists idx_PathTypedBaseItems on TypedBaseItems(Path)",
"create index if not exists idx_ParentIdTypedBaseItems on TypedBaseItems(ParentId)",
@@ -352,7 +346,10 @@ namespace Emby.Server.Implementations.Data
// items by name
"create index if not exists idx_ItemValues6 on ItemValues(ItemId,Type,CleanValue)",
- "create index if not exists idx_ItemValues7 on ItemValues(Type,CleanValue,ItemId)"
+ "create index if not exists idx_ItemValues7 on ItemValues(Type,CleanValue,ItemId)",
+
+ // Used to update inherited tags
+ "create index if not exists idx_ItemValues8 on ItemValues(Type, ItemId, Value)",
};
connection.RunQueries(postQueries);
@@ -421,7 +418,6 @@ namespace Emby.Server.Implementations.Data
"ProductionYear",
"OfficialRating",
"HomePageUrl",
- "DisplayMediaType",
"ForcedSortName",
"RunTimeTicks",
"DateCreated",
@@ -449,7 +445,6 @@ namespace Emby.Server.Implementations.Data
"SeriesId",
"PresentationUniqueKey",
"InheritedParentalRatingValue",
- "InheritedTags",
"ExternalSeriesId",
"Tagline",
"ProviderIds",
@@ -539,7 +534,6 @@ namespace Emby.Server.Implementations.Data
"ForcedSortName",
"RunTimeTicks",
"HomePageUrl",
- "DisplayMediaType",
"DateCreated",
"DateModified",
"PreferredMetadataLanguage",
@@ -559,7 +553,6 @@ namespace Emby.Server.Implementations.Data
"TopParentId",
"TrailerTypes",
"CriticRating",
- "InheritedTags",
"CleanName",
"PresentationUniqueKey",
"OriginalTitle",
@@ -606,16 +599,15 @@ namespace Emby.Server.Implementations.Data
/// </summary>
/// <param name="item">The item.</param>
/// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
/// <exception cref="System.ArgumentNullException">item</exception>
- public Task SaveItem(BaseItem item, CancellationToken cancellationToken)
+ public void SaveItem(BaseItem item, CancellationToken cancellationToken)
{
if (item == null)
{
throw new ArgumentNullException("item");
}
- return SaveItems(new List<BaseItem> { item }, cancellationToken);
+ SaveItems(new List<BaseItem> { item }, cancellationToken);
}
/// <summary>
@@ -623,13 +615,12 @@ namespace Emby.Server.Implementations.Data
/// </summary>
/// <param name="items">The items.</param>
/// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
/// <exception cref="System.ArgumentNullException">
/// items
/// or
/// cancellationToken
/// </exception>
- public async Task SaveItems(List<BaseItem> items, CancellationToken cancellationToken)
+ public void SaveItems(List<BaseItem> items, CancellationToken cancellationToken)
{
if (items == null)
{
@@ -640,7 +631,7 @@ namespace Emby.Server.Implementations.Data
CheckDisposed();
- var tuples = new List<Tuple<BaseItem, List<Guid>, BaseItem, string>>();
+ var tuples = new List<Tuple<BaseItem, List<Guid>, BaseItem, string, List<string>>>();
foreach (var item in items)
{
var ancestorIds = item.SupportsAncestors ?
@@ -650,8 +641,9 @@ namespace Emby.Server.Implementations.Data
var topParent = item.GetTopParent();
var userdataKey = item.GetUserDataKeys().FirstOrDefault();
+ var inheritedTags = item.GetInheritedTags();
- tuples.Add(new Tuple<BaseItem, List<Guid>, BaseItem, string>(item, ancestorIds, topParent, userdataKey));
+ tuples.Add(new Tuple<BaseItem, List<Guid>, BaseItem, string, List<string>>(item, ancestorIds, topParent, userdataKey, inheritedTags));
}
using (WriteLock.Write())
@@ -661,12 +653,13 @@ namespace Emby.Server.Implementations.Data
connection.RunInTransaction(db =>
{
SaveItemsInTranscation(db, tuples);
+
}, TransactionMode);
}
}
}
- private void SaveItemsInTranscation(IDatabaseConnection db, List<Tuple<BaseItem, List<Guid>, BaseItem, string>> tuples)
+ private void SaveItemsInTranscation(IDatabaseConnection db, List<Tuple<BaseItem, List<Guid>, BaseItem, string, List<string>>> tuples)
{
var requiresReset = false;
@@ -697,12 +690,14 @@ namespace Emby.Server.Implementations.Data
SaveItem(item, topParent, userDataKey, saveItemStatement);
//Logger.Debug(_saveItemCommand.CommandText);
+ var inheritedTags = tuple.Item5;
+
if (item.SupportsAncestors)
{
UpdateAncestors(item.Id, tuple.Item2, db, deleteAncestorsStatement, updateAncestorsStatement);
}
- UpdateItemValues(item.Id, GetItemValuesToSave(item), db);
+ UpdateItemValues(item.Id, GetItemValuesToSave(item, inheritedTags), db);
requiresReset = true;
}
@@ -813,7 +808,6 @@ namespace Emby.Server.Implementations.Data
saveItemStatement.TryBind("@RunTimeTicks", item.RunTimeTicks);
saveItemStatement.TryBind("@HomePageUrl", item.HomePageUrl);
- saveItemStatement.TryBind("@DisplayMediaType", item.DisplayMediaType);
saveItemStatement.TryBind("@DateCreated", item.DateCreated);
saveItemStatement.TryBind("@DateModified", item.DateModified);
@@ -842,7 +836,7 @@ namespace Emby.Server.Implementations.Data
saveItemStatement.TryBind("@IsInMixedFolder", item.IsInMixedFolder);
- if (item.LockedFields.Count > 0)
+ if (item.LockedFields.Length > 0)
{
saveItemStatement.TryBind("@LockedFields", string.Join("|", item.LockedFields.Select(i => i.ToString()).ToArray()));
}
@@ -851,7 +845,7 @@ namespace Emby.Server.Implementations.Data
saveItemStatement.TryBindNull("@LockedFields");
}
- if (item.Studios.Count > 0)
+ if (item.Studios.Length > 0)
{
saveItemStatement.TryBind("@Studios", string.Join("|", item.Studios.ToArray()));
}
@@ -871,9 +865,9 @@ namespace Emby.Server.Implementations.Data
saveItemStatement.TryBind("@ExternalServiceId", item.ServiceName);
- if (item.Tags.Count > 0)
+ if (item.Tags.Length > 0)
{
- saveItemStatement.TryBind("@Tags", string.Join("|", item.Tags.ToArray()));
+ saveItemStatement.TryBind("@Tags", string.Join("|", item.Tags));
}
else
{
@@ -907,16 +901,6 @@ namespace Emby.Server.Implementations.Data
saveItemStatement.TryBind("@CriticRating", item.CriticRating);
- var inheritedTags = item.InheritedTags;
- if (inheritedTags.Count > 0)
- {
- saveItemStatement.TryBind("@InheritedTags", string.Join("|", inheritedTags.ToArray()));
- }
- else
- {
- saveItemStatement.TryBindNull("@InheritedTags");
- }
-
if (string.IsNullOrWhiteSpace(item.Name))
{
saveItemStatement.TryBindNull("@CleanName");
@@ -1000,16 +984,16 @@ namespace Emby.Server.Implementations.Data
saveItemStatement.TryBind("@ProviderIds", SerializeProviderIds(item));
saveItemStatement.TryBind("@Images", SerializeImages(item));
- if (item.ProductionLocations.Count > 0)
+ if (item.ProductionLocations.Length > 0)
{
- saveItemStatement.TryBind("@ProductionLocations", string.Join("|", item.ProductionLocations.ToArray()));
+ saveItemStatement.TryBind("@ProductionLocations", string.Join("|", item.ProductionLocations));
}
else
{
saveItemStatement.TryBindNull("@ProductionLocations");
}
- if (item.ThemeSongIds.Count > 0)
+ if (item.ThemeSongIds.Length > 0)
{
saveItemStatement.TryBind("@ThemeSongIds", string.Join("|", item.ThemeSongIds.ToArray()));
}
@@ -1018,7 +1002,7 @@ namespace Emby.Server.Implementations.Data
saveItemStatement.TryBindNull("@ThemeSongIds");
}
- if (item.ThemeVideoIds.Count > 0)
+ if (item.ThemeVideoIds.Length > 0)
{
saveItemStatement.TryBind("@ThemeVideoIds", string.Join("|", item.ThemeVideoIds.ToArray()));
}
@@ -1041,9 +1025,9 @@ namespace Emby.Server.Implementations.Data
var hasArtists = item as IHasArtist;
if (hasArtists != null)
{
- if (hasArtists.Artists.Count > 0)
+ if (hasArtists.Artists.Length > 0)
{
- artists = string.Join("|", hasArtists.Artists.ToArray());
+ artists = string.Join("|", hasArtists.Artists);
}
}
saveItemStatement.TryBind("@Artists", artists);
@@ -1052,9 +1036,9 @@ namespace Emby.Server.Implementations.Data
var hasAlbumArtists = item as IHasAlbumArtist;
if (hasAlbumArtists != null)
{
- if (hasAlbumArtists.AlbumArtists.Count > 0)
+ if (hasAlbumArtists.AlbumArtists.Length > 0)
{
- albumArtists = string.Join("|", hasAlbumArtists.AlbumArtists.ToArray());
+ albumArtists = string.Join("|", hasAlbumArtists.AlbumArtists);
}
}
saveItemStatement.TryBind("@AlbumArtists", albumArtists);
@@ -1105,9 +1089,9 @@ namespace Emby.Server.Implementations.Data
private string SerializeImages(BaseItem item)
{
- var images = item.ImageInfos.ToList();
+ var images = item.ImageInfos;
- if (images.Count == 0)
+ if (images.Length == 0)
{
return null;
}
@@ -1124,22 +1108,24 @@ namespace Emby.Server.Implementations.Data
return;
}
- if (item.ImageInfos.Count > 0)
+ if (item.ImageInfos.Length > 0)
{
return;
}
var parts = value.Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
-
+ var list = new List<ItemImageInfo>();
foreach (var part in parts)
{
var image = ItemImageInfoFromValueString(part);
if (image != null)
{
- item.ImageInfos.Add(image);
+ list.Add(image);
}
}
+
+ item.ImageInfos = list.ToArray(list.Count);
}
public string ToValueString(ItemImageInfo image)
@@ -1228,14 +1214,15 @@ namespace Emby.Server.Implementations.Data
{
return false;
}
- if (type == typeof(Season))
- {
- return false;
- }
- if (type == typeof(MusicArtist))
- {
- return false;
- }
+ }
+
+ if (type == typeof(Season))
+ {
+ return false;
+ }
+ if (type == typeof(MusicArtist))
+ {
+ return false;
}
if (type == typeof(Person))
@@ -1306,16 +1293,13 @@ namespace Emby.Server.Implementations.Data
return false;
}
- if (_config.Configuration.SkipDeserializationForAudio)
+ if (type == typeof(Audio))
{
- if (type == typeof(Audio))
- {
- return false;
- }
- if (type == typeof(MusicAlbum))
- {
- return false;
- }
+ return false;
+ }
+ if (type == typeof(MusicAlbum))
+ {
+ return false;
}
return true;
@@ -1586,15 +1570,6 @@ namespace Emby.Server.Implementations.Data
index++;
}
- if (HasField(query, ItemFields.DisplayMediaType))
- {
- if (!reader.IsDBNull(index))
- {
- item.DisplayMediaType = reader.GetString(index);
- }
- index++;
- }
-
if (HasField(query, ItemFields.SortName))
{
if (!reader.IsDBNull(index))
@@ -1690,7 +1665,7 @@ namespace Emby.Server.Implementations.Data
return parsedValue;
}
return (MetadataFields?)null;
- }).Where(i => i.HasValue).Select(i => i.Value).ToList();
+ }).Where(i => i.HasValue).Select(i => i.Value).ToArray();
}
index++;
}
@@ -1699,7 +1674,7 @@ namespace Emby.Server.Implementations.Data
{
if (!reader.IsDBNull(index))
{
- item.Studios = reader.GetString(index).Split('|').Where(i => !string.IsNullOrWhiteSpace(i)).ToList();
+ item.Studios = reader.GetString(index).Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
}
index++;
}
@@ -1708,7 +1683,7 @@ namespace Emby.Server.Implementations.Data
{
if (!reader.IsDBNull(index))
{
- item.Tags = reader.GetString(index).Split('|').Where(i => !string.IsNullOrWhiteSpace(i)).ToList();
+ item.Tags = reader.GetString(index).Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
}
index++;
}
@@ -1849,15 +1824,6 @@ namespace Emby.Server.Implementations.Data
index++;
}
- if (HasField(query, ItemFields.Tags))
- {
- if (!reader.IsDBNull(index))
- {
- item.InheritedTags = reader.GetString(index).Split('|').Where(i => !string.IsNullOrWhiteSpace(i)).ToList();
- }
- index++;
- }
-
if (HasField(query, ItemFields.ExternalSeriesId))
{
if (!reader.IsDBNull(index))
@@ -1895,7 +1861,7 @@ namespace Emby.Server.Implementations.Data
{
if (!reader.IsDBNull(index))
{
- item.ProductionLocations = reader.GetString(index).Split('|').Where(i => !string.IsNullOrWhiteSpace(i)).ToList();
+ item.ProductionLocations = reader.GetString(index).Split('|').Where(i => !string.IsNullOrWhiteSpace(i)).ToArray();
}
index++;
}
@@ -1904,7 +1870,7 @@ namespace Emby.Server.Implementations.Data
{
if (!reader.IsDBNull(index))
{
- item.ThemeSongIds = reader.GetString(index).Split('|').Where(i => !string.IsNullOrWhiteSpace(i)).Select(i => new Guid(i)).ToList();
+ item.ThemeSongIds = SplitToGuids(reader.GetString(index));
}
index++;
}
@@ -1913,7 +1879,7 @@ namespace Emby.Server.Implementations.Data
{
if (!reader.IsDBNull(index))
{
- item.ThemeVideoIds = reader.GetString(index).Split('|').Where(i => !string.IsNullOrWhiteSpace(i)).Select(i => new Guid(i)).ToList();
+ item.ThemeVideoIds = SplitToGuids(reader.GetString(index));
}
index++;
}
@@ -1939,14 +1905,14 @@ namespace Emby.Server.Implementations.Data
var hasArtists = item as IHasArtist;
if (hasArtists != null && !reader.IsDBNull(index))
{
- hasArtists.Artists = reader.GetString(index).Split('|').Where(i => !string.IsNullOrWhiteSpace(i)).ToList();
+ hasArtists.Artists = reader.GetString(index).Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
}
index++;
var hasAlbumArtists = item as IHasAlbumArtist;
if (hasAlbumArtists != null && !reader.IsDBNull(index))
{
- hasAlbumArtists.AlbumArtists = reader.GetString(index).Split('|').Where(i => !string.IsNullOrWhiteSpace(i)).ToList();
+ hasAlbumArtists.AlbumArtists = reader.GetString(index).Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
}
index++;
}
@@ -1972,45 +1938,36 @@ namespace Emby.Server.Implementations.Data
return item;
}
+ private Guid[] SplitToGuids(string value)
+ {
+ var ids = value.Split('|');
+
+ var result = new Guid[ids.Length];
+
+ for (var i = 0; i < result.Length; i++)
+ {
+ result[i] = new Guid(ids[i]);
+ }
+
+ return result;
+ }
+
/// <summary>
/// Gets the critic reviews.
/// </summary>
/// <param name="itemId">The item id.</param>
- /// <returns>Task{IEnumerable{ItemReview}}.</returns>
- public IEnumerable<ItemReview> GetCriticReviews(Guid itemId)
+ public List<ItemReview> GetCriticReviews(Guid itemId)
{
- try
- {
- var path = Path.Combine(_criticReviewsPath, itemId + ".json");
-
- return _jsonSerializer.DeserializeFromFile<List<ItemReview>>(path);
- }
- catch (FileNotFoundException)
- {
- return new List<ItemReview>();
- }
- catch (IOException)
- {
- return new List<ItemReview>();
- }
+ return new List<ItemReview>();
}
- private readonly Task _cachedTask = Task.FromResult(true);
/// <summary>
/// Saves the critic reviews.
/// </summary>
/// <param name="itemId">The item id.</param>
/// <param name="criticReviews">The critic reviews.</param>
- /// <returns>Task.</returns>
- public Task SaveCriticReviews(Guid itemId, IEnumerable<ItemReview> criticReviews)
+ public void SaveCriticReviews(Guid itemId, IEnumerable<ItemReview> criticReviews)
{
- _fileSystem.CreateDirectory(_criticReviewsPath);
-
- var path = Path.Combine(_criticReviewsPath, itemId + ".json");
-
- _jsonSerializer.SerializeToFile(criticReviews.ToList(), path);
-
- return _cachedTask;
}
/// <summary>
@@ -2019,7 +1976,7 @@ namespace Emby.Server.Implementations.Data
/// <param name="id">The id.</param>
/// <returns>IEnumerable{ChapterInfo}.</returns>
/// <exception cref="System.ArgumentNullException">id</exception>
- public IEnumerable<ChapterInfo> GetChapters(Guid id)
+ public List<ChapterInfo> GetChapters(Guid id)
{
CheckDisposed();
if (id == Guid.Empty)
@@ -2115,18 +2072,7 @@ namespace Emby.Server.Implementations.Data
/// <summary>
/// Saves the chapters.
/// </summary>
- /// <param name="id">The id.</param>
- /// <param name="chapters">The chapters.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- /// <exception cref="System.ArgumentNullException">
- /// id
- /// or
- /// chapters
- /// or
- /// cancellationToken
- /// </exception>
- public async Task SaveChapters(Guid id, List<ChapterInfo> chapters, CancellationToken cancellationToken)
+ public void SaveChapters(Guid id, List<ChapterInfo> chapters)
{
CheckDisposed();
@@ -2140,8 +2086,6 @@ namespace Emby.Server.Implementations.Data
throw new ArgumentNullException("chapters");
}
- cancellationToken.ThrowIfCancellationRequested();
-
var index = 0;
using (WriteLock.Write())
@@ -2191,8 +2135,7 @@ namespace Emby.Server.Implementations.Data
//return true;
}
- var sortingFields = query.SortBy.ToList();
- sortingFields.AddRange(query.OrderBy.Select(i => i.Item1));
+ var sortingFields = query.OrderBy.Select(i => i.Item1).ToList();
if (sortingFields.Contains(ItemSortBy.IsFavoriteOrLiked, StringComparer.OrdinalIgnoreCase))
{
@@ -2247,7 +2190,7 @@ namespace Emby.Server.Implementations.Data
return false;
}
- private List<ItemFields> allFields = Enum.GetNames(typeof(ItemFields))
+ private readonly List<ItemFields> allFields = Enum.GetNames(typeof(ItemFields))
.Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true))
.ToList();
@@ -2271,7 +2214,7 @@ namespace Emby.Server.Implementations.Data
}
if (field == ItemFields.Tags)
{
- return new[] { "Tags", "InheritedTags" };
+ return new[] { "Tags" };
}
return new[] { field.ToString() };
@@ -2284,7 +2227,6 @@ namespace Emby.Server.Implementations.Data
switch (name)
{
case ItemFields.HomePageUrl:
- case ItemFields.DisplayMediaType:
case ItemFields.CustomRating:
case ItemFields.ProductionLocations:
case ItemFields.Settings:
@@ -2589,11 +2531,11 @@ namespace Emby.Server.Implementations.Data
}
}
- query.ExcludeItemIds = excludeIds.ToArray();
+ query.ExcludeItemIds = excludeIds.ToArray(excludeIds.Count);
query.ExcludeProviderIds = item.ProviderIds;
}
- return list.ToArray();
+ return list.ToArray(list.Count);
}
private void BindSimilarParams(InternalItemsQuery query, IStatement statement)
@@ -2629,9 +2571,14 @@ namespace Emby.Server.Implementations.Data
groups.Add("PresentationUniqueKey");
}
+ if (query.GroupBySeriesPresentationUniqueKey)
+ {
+ groups.Add("SeriesPresentationUniqueKey");
+ }
+
if (groups.Count > 0)
{
- return " Group by " + string.Join(",", groups.ToArray());
+ return " Group by " + string.Join(",", groups.ToArray(groups.Count));
}
return string.Empty;
@@ -2668,7 +2615,7 @@ namespace Emby.Server.Implementations.Data
var whereText = whereClauses.Count == 0 ?
string.Empty :
- " where " + string.Join(" AND ", whereClauses.ToArray());
+ " where " + string.Join(" AND ", whereClauses.ToArray(whereClauses.Count));
commandText += whereText;
@@ -2725,7 +2672,7 @@ namespace Emby.Server.Implementations.Data
var whereText = whereClauses.Count == 0 ?
string.Empty :
- " where " + string.Join(" AND ", whereClauses.ToArray());
+ " where " + string.Join(" AND ", whereClauses.ToArray(whereClauses.Count));
commandText += whereText;
@@ -2845,7 +2792,7 @@ namespace Emby.Server.Implementations.Data
var slowThreshold = 1000;
#if DEBUG
- slowThreshold = 2;
+ slowThreshold = 10;
#endif
if (elapsed >= slowThreshold)
@@ -2878,7 +2825,7 @@ namespace Emby.Server.Implementations.Data
var returnList = GetItemList(query);
return new QueryResult<BaseItem>
{
- Items = returnList.ToArray(),
+ Items = returnList.ToArray(returnList.Count),
TotalRecordCount = returnList.Count
};
}
@@ -2901,7 +2848,7 @@ namespace Emby.Server.Implementations.Data
var whereText = whereClauses.Count == 0 ?
string.Empty :
- " where " + string.Join(" AND ", whereClauses.ToArray());
+ " where " + string.Join(" AND ", whereClauses.ToArray(whereClauses.Count));
var whereTextWithoutPaging = whereText;
@@ -2941,6 +2888,10 @@ namespace Emby.Server.Implementations.Data
{
commandText += " select count (distinct PresentationUniqueKey)" + GetFromText();
}
+ else if (query.GroupBySeriesPresentationUniqueKey)
+ {
+ commandText += " select count (distinct SeriesPresentationUniqueKey)" + GetFromText();
+ }
else
{
commandText += " select count (guid)" + GetFromText();
@@ -2958,8 +2909,7 @@ namespace Emby.Server.Implementations.Data
return connection.RunInTransaction(db =>
{
var result = new QueryResult<BaseItem>();
- var statements = PrepareAllSafe(db, statementTexts)
- .ToList();
+ var statements = PrepareAllSafe(db, statementTexts);
if (!isReturningZeroItems)
{
@@ -3013,7 +2963,7 @@ namespace Emby.Server.Implementations.Data
LogQueryTime("GetItems", commandText, now);
- result.Items = list.ToArray();
+ result.Items = list.ToArray(list.Count);
return result;
}, ReadTransactionMode);
@@ -3024,16 +2974,7 @@ namespace Emby.Server.Implementations.Data
private string GetOrderByText(InternalItemsQuery query)
{
var orderBy = query.OrderBy.ToList();
- var enableOrderInversion = true;
-
- if (orderBy.Count == 0)
- {
- orderBy.AddRange(query.SortBy.Select(i => new Tuple<string, SortOrder>(i, query.SortOrder)));
- }
- else
- {
- enableOrderInversion = false;
- }
+ var enableOrderInversion = false;
if (query.SimilarTo != null)
{
@@ -3042,12 +2983,10 @@ namespace Emby.Server.Implementations.Data
orderBy.Add(new Tuple<string, SortOrder>(ItemSortBy.Random, SortOrder.Ascending));
orderBy.Add(new Tuple<string, SortOrder>("SimilarityScore", SortOrder.Descending));
//orderBy.Add(new Tuple<string, SortOrder>(ItemSortBy.Random, SortOrder.Ascending));
- query.SortOrder = SortOrder.Descending;
- enableOrderInversion = false;
}
}
- query.OrderBy = orderBy;
+ query.OrderBy = orderBy.ToArray();
if (orderBy.Count == 0)
{
@@ -3086,6 +3025,11 @@ namespace Emby.Server.Implementations.Data
}
if (string.Equals(name, ItemSortBy.DatePlayed, StringComparison.OrdinalIgnoreCase))
{
+ if (query.GroupBySeriesPresentationUniqueKey)
+ {
+ return new Tuple<string, bool>("MAX(LastPlayedDate)", false);
+ }
+
return new Tuple<string, bool>("LastPlayedDate", false);
}
if (string.Equals(name, ItemSortBy.PlayCount, StringComparison.OrdinalIgnoreCase))
@@ -3160,7 +3104,7 @@ namespace Emby.Server.Implementations.Data
var whereText = whereClauses.Count == 0 ?
string.Empty :
- " where " + string.Join(" AND ", whereClauses.ToArray());
+ " where " + string.Join(" AND ", whereClauses.ToArray(whereClauses.Count));
commandText += whereText;
@@ -3231,7 +3175,7 @@ namespace Emby.Server.Implementations.Data
var whereText = whereClauses.Count == 0 ?
string.Empty :
- " where " + string.Join(" AND ", whereClauses.ToArray());
+ " where " + string.Join(" AND ", whereClauses.ToArray(whereClauses.Count));
commandText += whereText;
@@ -3304,7 +3248,7 @@ namespace Emby.Server.Implementations.Data
var returnList = GetItemIdsList(query);
return new QueryResult<Guid>
{
- Items = returnList.ToArray(),
+ Items = returnList.ToArray(returnList.Count),
TotalRecordCount = returnList.Count
};
}
@@ -3319,7 +3263,7 @@ namespace Emby.Server.Implementations.Data
var whereText = whereClauses.Count == 0 ?
string.Empty :
- " where " + string.Join(" AND ", whereClauses.ToArray());
+ " where " + string.Join(" AND ", whereClauses.ToArray(whereClauses.Count));
var whereTextWithoutPaging = whereText;
@@ -3360,6 +3304,10 @@ namespace Emby.Server.Implementations.Data
{
commandText += " select count (distinct PresentationUniqueKey)" + GetFromText();
}
+ else if (query.GroupBySeriesPresentationUniqueKey)
+ {
+ commandText += " select count (distinct SeriesPresentationUniqueKey)" + GetFromText();
+ }
else
{
commandText += " select count (guid)" + GetFromText();
@@ -3378,8 +3326,7 @@ namespace Emby.Server.Implementations.Data
{
var result = new QueryResult<Guid>();
- var statements = PrepareAllSafe(db, statementTexts)
- .ToList();
+ var statements = PrepareAllSafe(db, statementTexts);
if (!isReturningZeroItems)
{
@@ -3422,7 +3369,7 @@ namespace Emby.Server.Implementations.Data
LogQueryTime("GetItemIds", commandText, now);
- result.Items = list.ToArray();
+ result.Items = list.ToArray(list.Count);
return result;
}, ReadTransactionMode);
@@ -3627,7 +3574,7 @@ namespace Emby.Server.Implementations.Data
}
if (programAttribtues.Count > 0)
{
- whereClauses.Add("(" + string.Join(" OR ", programAttribtues.ToArray()) + ")");
+ whereClauses.Add("(" + string.Join(" OR ", programAttribtues.ToArray(programAttribtues.Count)) + ")");
}
}
@@ -4296,12 +4243,13 @@ namespace Emby.Server.Implementations.Data
whereClauses.Add("ProductionYear in (" + val + ")");
}
- if (query.IsVirtualItem.HasValue)
+ var isVirtualItem = query.IsVirtualItem ?? query.IsMissing;
+ if (isVirtualItem.HasValue)
{
whereClauses.Add("IsVirtualItem=@IsVirtualItem");
if (statement != null)
{
- statement.TryBind("@IsVirtualItem", query.IsVirtualItem.Value);
+ statement.TryBind("@IsVirtualItem", isVirtualItem.Value);
}
}
if (query.IsSpecialSeason.HasValue)
@@ -4326,28 +4274,6 @@ namespace Emby.Server.Implementations.Data
whereClauses.Add("PremiereDate < DATETIME('now')");
}
}
- if (query.IsMissing.HasValue)
- {
- if (query.IsMissing.Value)
- {
- whereClauses.Add("(IsVirtualItem=1 AND PremiereDate < DATETIME('now'))");
- }
- else
- {
- whereClauses.Add("(IsVirtualItem=0 OR PremiereDate >= DATETIME('now'))");
- }
- }
- if (query.IsVirtualUnaired.HasValue)
- {
- if (query.IsVirtualUnaired.Value)
- {
- whereClauses.Add("(IsVirtualItem=1 AND PremiereDate >= DATETIME('now'))");
- }
- else
- {
- whereClauses.Add("(IsVirtualItem=0 OR PremiereDate < DATETIME('now'))");
- }
- }
var queryMediaTypes = query.MediaTypes.Where(IsValidMediaType).ToArray();
if (queryMediaTypes.Length == 1)
{
@@ -4563,26 +4489,12 @@ namespace Emby.Server.Implementations.Data
whereClauses.Add(string.Format("(InheritedParentalRatingValue > 0 or UnratedType not in ({0}))", inClause));
}
- var excludeTagIndex = 0;
- foreach (var excludeTag in query.ExcludeTags)
+ if (query.ExcludeInheritedTags.Length > 0)
{
- whereClauses.Add("(Tags is null OR Tags not like @excludeTag" + excludeTagIndex + ")");
- if (statement != null)
- {
- statement.TryBind("@excludeTag" + excludeTagIndex, "%" + excludeTag + "%");
- }
- excludeTagIndex++;
- }
+ var tagValues = query.ExcludeInheritedTags.Select(i => "'" + GetCleanValue(i) + "'").ToArray();
+ var tagValuesList = string.Join(",", tagValues);
- excludeTagIndex = 0;
- foreach (var excludeTag in query.ExcludeInheritedTags)
- {
- whereClauses.Add("(InheritedTags is null OR InheritedTags not like @excludeInheritedTag" + excludeTagIndex + ")");
- if (statement != null)
- {
- statement.TryBind("@excludeInheritedTag" + excludeTagIndex, "%" + excludeTag + "%");
- }
- excludeTagIndex++;
+ whereClauses.Add("((select CleanValue from itemvalues where ItemId=Guid and Type=6 and cleanvalue in (" + tagValuesList + ")) is null)");
}
return whereClauses;
@@ -4647,6 +4559,11 @@ namespace Emby.Server.Implementations.Data
return false;
}
+ if (query.GroupBySeriesPresentationUniqueKey)
+ {
+ return false;
+ }
+
if (!string.IsNullOrWhiteSpace(query.PresentationUniqueKey))
{
return false;
@@ -4718,48 +4635,72 @@ namespace Emby.Server.Implementations.Data
typeof(AggregateFolder)
};
- public async Task UpdateInheritedValues(CancellationToken cancellationToken)
+ public void UpdateInheritedValues(CancellationToken cancellationToken)
{
- await UpdateInheritedTags(cancellationToken).ConfigureAwait(false);
+ UpdateInheritedTags(cancellationToken);
}
- private async Task UpdateInheritedTags(CancellationToken cancellationToken)
+ private void UpdateInheritedTags(CancellationToken cancellationToken)
{
- var newValues = new List<Tuple<Guid, string>>();
+ var newValues = new List<Tuple<Guid, string[]>>();
- var commandText = "select Guid,InheritedTags,(select group_concat(Tags, '|') from TypedBaseItems where (guid=outer.guid) OR (guid in (Select AncestorId from AncestorIds where ItemId=Outer.guid))) as NewInheritedTags from typedbaseitems as Outer where NewInheritedTags <> InheritedTags";
+ var commandText = @"select guid,
+(select group_concat(Value, '|') from ItemValues where (ItemValues.ItemId = Outer.Guid OR ItemValues.ItemId in ((Select AncestorId from AncestorIds where AncestorIds.ItemId=Outer.guid))) and ItemValues.Type = 4) NewInheritedTags,
+(select group_concat(Value, '|') from ItemValues where ItemValues.ItemId = Outer.Guid and ItemValues.Type = 6) CurrentInheritedTags
+from typedbaseitems as Outer
+where (NewInheritedTags <> CurrentInheritedTags or (NewInheritedTags is null) <> (CurrentInheritedTags is null))
+limit 100";
using (WriteLock.Write())
{
using (var connection = CreateConnection())
{
- foreach (var row in connection.Query(commandText))
+ connection.RunInTransaction(db =>
{
- var id = row.GetGuid(0);
- string value = row.IsDBNull(2) ? null : row.GetString(2);
+ foreach (var row in connection.Query(commandText))
+ {
+ var id = row.GetGuid(0);
+ string value = row.IsDBNull(1) ? null : row.GetString(1);
- newValues.Add(new Tuple<Guid, string>(id, value));
- }
+ var valuesArray = string.IsNullOrWhiteSpace(value) ? new string[] { } : value.Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
- Logger.Debug("UpdateInheritedTags - {0} rows", newValues.Count);
- if (newValues.Count == 0)
- {
- return;
- }
+ newValues.Add(new Tuple<Guid, string[]>(id, valuesArray));
+ }
- // write lock here
- using (var statement = PrepareStatement(connection, "Update TypedBaseItems set InheritedTags=@InheritedTags where Guid=@Guid"))
- {
- foreach (var item in newValues)
+ Logger.Debug("UpdateInheritedTags - {0} rows", newValues.Count);
+ if (newValues.Count == 0)
{
- var paramList = new List<object>();
+ return;
+ }
- paramList.Add(item.Item1);
- paramList.Add(item.Item2);
+ using (var insertStatement = PrepareStatement(connection, "insert into ItemValues (ItemId, Type, Value, CleanValue) values (@ItemId, 6, @Value, @CleanValue)"))
+ {
+ using (var deleteStatement = PrepareStatement(connection, "delete from ItemValues where ItemId=@ItemId and Type=6"))
+ {
+ foreach (var item in newValues)
+ {
+ var guidBlob = item.Item1.ToGuidBlob();
- statement.Execute(paramList.ToArray());
+ deleteStatement.Reset();
+ deleteStatement.TryBind("@ItemId", guidBlob);
+ deleteStatement.MoveNext();
+
+ foreach (var itemValue in item.Item2)
+ {
+ insertStatement.Reset();
+
+ insertStatement.TryBind("@ItemId", guidBlob);
+ insertStatement.TryBind("@Value", itemValue);
+
+ insertStatement.TryBind("@CleanValue", GetCleanValue(itemValue));
+
+ insertStatement.MoveNext();
+ }
+ }
+ }
}
- }
+
+ }, TransactionMode);
}
}
}
@@ -4794,7 +4735,7 @@ namespace Emby.Server.Implementations.Data
return new[] { value }.Where(IsValidType);
}
- public async Task DeleteItem(Guid id, CancellationToken cancellationToken)
+ public void DeleteItem(Guid id, CancellationToken cancellationToken)
{
if (id == Guid.Empty)
{
@@ -5161,9 +5102,9 @@ namespace Emby.Server.Implementations.Data
var itemCountColumns = new List<Tuple<string, string>>();
- var typesToCount = query.IncludeItemTypes.ToList();
+ var typesToCount = query.IncludeItemTypes;
- if (typesToCount.Count > 0)
+ if (typesToCount.Length > 0)
{
var itemCountColumnQuery = "select group_concat(type, '|')" + GetFromText("B");
@@ -5223,7 +5164,7 @@ namespace Emby.Server.Implementations.Data
var whereText = " where Type=@SelectType";
- if (typesToCount.Count == 0)
+ if (typesToCount.Length == 0)
{
whereText += " And CleanName In (Select CleanValue from ItemValues where " + typeClause + " AND ItemId in (select guid from TypedBaseItems" + innerWhereText + "))";
}
@@ -5301,8 +5242,7 @@ namespace Emby.Server.Implementations.Data
var list = new List<Tuple<BaseItem, ItemCounts>>();
var result = new QueryResult<Tuple<BaseItem, ItemCounts>>();
- var statements = PrepareAllSafe(db, statementTexts)
- .ToList();
+ var statements = PrepareAllSafe(db, statementTexts);
if (!isReturningZeroItems)
{
@@ -5377,7 +5317,7 @@ namespace Emby.Server.Implementations.Data
{
result.TotalRecordCount = list.Count;
}
- result.Items = list.ToArray();
+ result.Items = list.ToArray(list.Count);
return result;
@@ -5386,11 +5326,11 @@ namespace Emby.Server.Implementations.Data
}
}
- private ItemCounts GetItemCounts(IReadOnlyList<IResultSetValue> reader, int countStartColumn, List<string> typesToCount)
+ private ItemCounts GetItemCounts(IReadOnlyList<IResultSetValue> reader, int countStartColumn, string[] typesToCount)
{
var counts = new ItemCounts();
- if (typesToCount.Count == 0)
+ if (typesToCount.Length == 0)
{
return counts;
}
@@ -5448,7 +5388,7 @@ namespace Emby.Server.Implementations.Data
return counts;
}
- private List<Tuple<int, string>> GetItemValuesToSave(BaseItem item)
+ private List<Tuple<int, string>> GetItemValuesToSave(BaseItem item, List<string> inheritedTags)
{
var list = new List<Tuple<int, string>>();
@@ -5468,6 +5408,10 @@ namespace Emby.Server.Implementations.Data
list.AddRange(item.Studios.Select(i => new Tuple<int, string>(3, i)));
list.AddRange(item.Tags.Select(i => new Tuple<int, string>(4, i)));
+ // keywords was 5
+
+ list.AddRange(inheritedTags.Select(i => new Tuple<int, string>(6, i)));
+
return list;
}
@@ -5485,8 +5429,10 @@ namespace Emby.Server.Implementations.Data
CheckDisposed();
+ var guidBlob = itemId.ToGuidBlob();
+
// First delete
- db.Execute("delete from ItemValues where ItemId=@Id", itemId.ToGuidBlob());
+ db.Execute("delete from ItemValues where ItemId=@Id", guidBlob);
using (var statement = PrepareStatement(db, "insert into ItemValues (ItemId, Type, Value, CleanValue) values (@ItemId, @Type, @Value, @CleanValue)"))
{
@@ -5502,7 +5448,7 @@ namespace Emby.Server.Implementations.Data
statement.Reset();
- statement.TryBind("@ItemId", itemId.ToGuidBlob());
+ statement.TryBind("@ItemId", guidBlob);
statement.TryBind("@Type", pair.Item1);
statement.TryBind("@Value", itemValue);
@@ -5520,7 +5466,7 @@ namespace Emby.Server.Implementations.Data
}
}
- public async Task UpdatePeople(Guid itemId, List<PersonInfo> people)
+ public void UpdatePeople(Guid itemId, List<PersonInfo> people)
{
if (itemId == Guid.Empty)
{
@@ -5594,7 +5540,7 @@ namespace Emby.Server.Implementations.Data
return item;
}
- public IEnumerable<MediaStream> GetMediaStreams(MediaStreamQuery query)
+ public List<MediaStream> GetMediaStreams(MediaStreamQuery query)
{
CheckDisposed();
@@ -5650,7 +5596,7 @@ namespace Emby.Server.Implementations.Data
}
}
- public async Task SaveMediaStreams(Guid id, List<MediaStream> streams, CancellationToken cancellationToken)
+ public void SaveMediaStreams(Guid id, List<MediaStream> streams, CancellationToken cancellationToken)
{
CheckDisposed();
diff --git a/Emby.Server.Implementations/Data/SqliteUserDataRepository.cs b/Emby.Server.Implementations/Data/SqliteUserDataRepository.cs
index bf6388f5d..ef1d7ba44 100644
--- a/Emby.Server.Implementations/Data/SqliteUserDataRepository.cs
+++ b/Emby.Server.Implementations/Data/SqliteUserDataRepository.cs
@@ -3,7 +3,6 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
-using System.Threading.Tasks;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Persistence;
@@ -153,7 +152,7 @@ namespace Emby.Server.Implementations.Data
/// userId
/// or
/// userDataId</exception>
- public Task SaveUserData(Guid userId, string key, UserItemData userData, CancellationToken cancellationToken)
+ public void SaveUserData(Guid userId, string key, UserItemData userData, CancellationToken cancellationToken)
{
if (userData == null)
{
@@ -168,10 +167,10 @@ namespace Emby.Server.Implementations.Data
throw new ArgumentNullException("key");
}
- return PersistUserData(userId, key, userData, cancellationToken);
+ PersistUserData(userId, key, userData, cancellationToken);
}
- public Task SaveAllUserData(Guid userId, IEnumerable<UserItemData> userData, CancellationToken cancellationToken)
+ public void SaveAllUserData(Guid userId, UserItemData[] userData, CancellationToken cancellationToken)
{
if (userData == null)
{
@@ -182,7 +181,7 @@ namespace Emby.Server.Implementations.Data
throw new ArgumentNullException("userId");
}
- return PersistAllUserData(userId, userData.ToList(), cancellationToken);
+ PersistAllUserData(userId, userData, cancellationToken);
}
/// <summary>
@@ -193,7 +192,7 @@ namespace Emby.Server.Implementations.Data
/// <param name="userData">The user data.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
- public async Task PersistUserData(Guid userId, string key, UserItemData userData, CancellationToken cancellationToken)
+ public void PersistUserData(Guid userId, string key, UserItemData userData, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
@@ -264,7 +263,7 @@ namespace Emby.Server.Implementations.Data
/// <summary>
/// Persist all user data for the specified user
/// </summary>
- private async Task PersistAllUserData(Guid userId, List<UserItemData> userDataList, CancellationToken cancellationToken)
+ private void PersistAllUserData(Guid userId, UserItemData[] userDataList, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
@@ -349,7 +348,7 @@ namespace Emby.Server.Implementations.Data
/// </summary>
/// <param name="userId"></param>
/// <returns></returns>
- public IEnumerable<UserItemData> GetAllUserData(Guid userId)
+ public List<UserItemData> GetAllUserData(Guid userId)
{
if (userId == Guid.Empty)
{
diff --git a/Emby.Server.Implementations/Data/SqliteUserRepository.cs b/Emby.Server.Implementations/Data/SqliteUserRepository.cs
index 29959bcab..b65996e40 100644
--- a/Emby.Server.Implementations/Data/SqliteUserRepository.cs
+++ b/Emby.Server.Implementations/Data/SqliteUserRepository.cs
@@ -2,7 +2,6 @@
using System.Collections.Generic;
using System.IO;
using System.Threading;
-using System.Threading.Tasks;
using MediaBrowser.Controller;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Persistence;
@@ -72,7 +71,7 @@ namespace Emby.Server.Implementations.Data
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
/// <exception cref="System.ArgumentNullException">user</exception>
- public async Task SaveUser(User user, CancellationToken cancellationToken)
+ public void SaveUser(User user, CancellationToken cancellationToken)
{
if (user == null)
{
@@ -139,7 +138,7 @@ namespace Emby.Server.Implementations.Data
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
/// <exception cref="System.ArgumentNullException">user</exception>
- public async Task DeleteUser(User user, CancellationToken cancellationToken)
+ public void DeleteUser(User user, CancellationToken cancellationToken)
{
if (user == null)
{
diff --git a/Emby.Server.Implementations/Devices/CameraUploadsDynamicFolder.cs b/Emby.Server.Implementations/Devices/CameraUploadsDynamicFolder.cs
index 52979f085..bb9ef157c 100644
--- a/Emby.Server.Implementations/Devices/CameraUploadsDynamicFolder.cs
+++ b/Emby.Server.Implementations/Devices/CameraUploadsDynamicFolder.cs
@@ -10,7 +10,6 @@ using MediaBrowser.Controller.IO;
using MediaBrowser.Model.IO;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Serialization;
-using MediaBrowser.Server.Implementations.Devices;
namespace Emby.Server.Implementations.Devices
{
diff --git a/MediaBrowser.Server.Implementations/Devices/CameraUploadsFolder.cs b/Emby.Server.Implementations/Devices/CameraUploadsFolder.cs
index ae700e250..55063872c 100644
--- a/MediaBrowser.Server.Implementations/Devices/CameraUploadsFolder.cs
+++ b/Emby.Server.Implementations/Devices/CameraUploadsFolder.cs
@@ -1,14 +1,12 @@
-using MediaBrowser.Common.Configuration;
-using MediaBrowser.Controller.Entities;
-using System;
-using System.IO;
+using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Serialization;
-namespace MediaBrowser.Server.Implementations.Devices
+namespace Emby.Server.Implementations.Devices
{
public class CameraUploadsFolder : BasePluginFolder, ISupportsUserSpecificView
{
@@ -30,7 +28,7 @@ namespace MediaBrowser.Server.Implementations.Devices
[IgnoreDataMember]
public override string CollectionType
{
- get { return Model.Entities.CollectionType.Photos; }
+ get { return MediaBrowser.Model.Entities.CollectionType.Photos; }
}
[IgnoreDataMember]
diff --git a/Emby.Common.Implementations/Devices/DeviceId.cs b/Emby.Server.Implementations/Devices/DeviceId.cs
index 1de76456c..5e0323ddb 100644
--- a/Emby.Common.Implementations/Devices/DeviceId.cs
+++ b/Emby.Server.Implementations/Devices/DeviceId.cs
@@ -5,7 +5,7 @@ using MediaBrowser.Common.Configuration;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Logging;
-namespace Emby.Common.Implementations.Devices
+namespace Emby.Server.Implementations.Devices
{
public class DeviceId
{
diff --git a/Emby.Server.Implementations/Devices/DeviceRepository.cs b/Emby.Server.Implementations/Devices/DeviceRepository.cs
index de0dfda2e..b286a3bb0 100644
--- a/Emby.Server.Implementations/Devices/DeviceRepository.cs
+++ b/Emby.Server.Implementations/Devices/DeviceRepository.cs
@@ -11,6 +11,7 @@ using MediaBrowser.Model.IO;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Serialization;
using MediaBrowser.Model.Session;
+using MediaBrowser.Model.Extensions;
namespace Emby.Server.Implementations.Devices
{
@@ -199,7 +200,10 @@ namespace Emby.Server.Implementations.Devices
}
history.DeviceId = deviceId;
- history.FilesUploaded.Add(file);
+
+ var list = history.FilesUploaded.ToList();
+ list.Add(file);
+ history.FilesUploaded = list.ToArray(list.Count);
_json.SerializeToFile(history, path);
}
diff --git a/Emby.Common.Implementations/Diagnostics/CommonProcess.cs b/Emby.Server.Implementations/Diagnostics/CommonProcess.cs
index afd30bc47..a0a5f32ef 100644
--- a/Emby.Common.Implementations/Diagnostics/CommonProcess.cs
+++ b/Emby.Server.Implementations/Diagnostics/CommonProcess.cs
@@ -1,12 +1,10 @@
using System;
-using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
-using System.Linq;
using System.Threading.Tasks;
using MediaBrowser.Model.Diagnostics;
-namespace Emby.Common.Implementations.Diagnostics
+namespace Emby.Server.Implementations.Diagnostics
{
public class CommonProcess : IProcess
{
@@ -106,6 +104,7 @@ namespace Emby.Common.Implementations.Diagnostics
public void Dispose()
{
_process.Dispose();
+ GC.SuppressFinalize(this);
}
}
}
diff --git a/Emby.Common.Implementations/Diagnostics/ProcessFactory.cs b/Emby.Server.Implementations/Diagnostics/ProcessFactory.cs
index 292da023c..a2c511cb9 100644
--- a/Emby.Common.Implementations/Diagnostics/ProcessFactory.cs
+++ b/Emby.Server.Implementations/Diagnostics/ProcessFactory.cs
@@ -1,6 +1,6 @@
using MediaBrowser.Model.Diagnostics;
-namespace Emby.Common.Implementations.Diagnostics
+namespace Emby.Server.Implementations.Diagnostics
{
public class ProcessFactory : IProcessFactory
{
diff --git a/Emby.Server.Implementations/Dto/DtoService.cs b/Emby.Server.Implementations/Dto/DtoService.cs
index a57ee0b9b..a0bbd171f 100644
--- a/Emby.Server.Implementations/Dto/DtoService.cs
+++ b/Emby.Server.Implementations/Dto/DtoService.cs
@@ -77,7 +77,7 @@ namespace Emby.Server.Implementations.Dto
/// <param name="owner">The owner.</param>
/// <returns>Task{DtoBaseItem}.</returns>
/// <exception cref="System.ArgumentNullException">item</exception>
- public BaseItemDto GetBaseItemDto(BaseItem item, List<ItemFields> fields, User user = null, BaseItem owner = null)
+ public BaseItemDto GetBaseItemDto(BaseItem item, ItemFields[] fields, User user = null, BaseItem owner = null)
{
var options = new DtoOptions
{
@@ -87,7 +87,17 @@ namespace Emby.Server.Implementations.Dto
return GetBaseItemDto(item, options, user, owner);
}
- public async Task<List<BaseItemDto>> GetBaseItemDtos(IEnumerable<BaseItem> items, DtoOptions options, User user = null, BaseItem owner = null)
+ public BaseItemDto[] GetBaseItemDtos(List<BaseItem> items, DtoOptions options, User user = null, BaseItem owner = null)
+ {
+ return GetBaseItemDtos(items, items.Count, options, user, owner);
+ }
+
+ public BaseItemDto[] GetBaseItemDtos(BaseItem[] items, DtoOptions options, User user = null, BaseItem owner = null)
+ {
+ return GetBaseItemDtos(items, items.Length, options, user, owner);
+ }
+
+ public BaseItemDto[] GetBaseItemDtos(IEnumerable<BaseItem> items, int itemCount, DtoOptions options, User user = null, BaseItem owner = null)
{
if (items == null)
{
@@ -101,17 +111,14 @@ namespace Emby.Server.Implementations.Dto
var syncDictionary = GetSyncedItemProgress(options);
- var list = new List<BaseItemDto>();
+ var returnItems = new BaseItemDto[itemCount];
var programTuples = new List<Tuple<BaseItem, BaseItemDto>>();
var channelTuples = new List<Tuple<BaseItemDto, LiveTvChannel>>();
- var refreshQueue = options.Fields.Contains(ItemFields.RefreshState)
- ? _providerManager.GetRefreshQueue()
- : null;
-
+ var index = 0;
foreach (var item in items)
{
- var dto = GetBaseItemDtoInternal(item, options, refreshQueue, user, owner);
+ var dto = GetBaseItemDtoInternal(item, options, user, owner);
var tvChannel = item as LiveTvChannel;
if (tvChannel != null)
@@ -144,37 +151,34 @@ namespace Emby.Server.Implementations.Dto
FillSyncInfo(dto, item, options, user, syncDictionary);
- list.Add(dto);
+ returnItems[index] = dto;
+ index++;
}
if (programTuples.Count > 0)
{
- await _livetvManager().AddInfoToProgramDto(programTuples, options.Fields, user).ConfigureAwait(false);
+ var task = _livetvManager().AddInfoToProgramDto(programTuples, options.Fields, user);
+ Task.WaitAll(task);
}
if (channelTuples.Count > 0)
{
- await _livetvManager().AddChannelInfo(channelTuples, options, user).ConfigureAwait(false);
+ _livetvManager().AddChannelInfo(channelTuples, options, user);
}
- return list;
+ return returnItems;
}
public BaseItemDto GetBaseItemDto(BaseItem item, DtoOptions options, User user = null, BaseItem owner = null)
{
var syncDictionary = GetSyncedItemProgress(options);
- var refreshQueue = options.Fields.Contains(ItemFields.RefreshState)
- ? _providerManager.GetRefreshQueue()
- : null;
-
- var dto = GetBaseItemDtoInternal(item, options, refreshQueue, user, owner);
+ var dto = GetBaseItemDtoInternal(item, options, user, owner);
var tvChannel = item as LiveTvChannel;
if (tvChannel != null)
{
var list = new List<Tuple<BaseItemDto, LiveTvChannel>> { new Tuple<BaseItemDto, LiveTvChannel>(dto, tvChannel) };
- var task = _livetvManager().AddChannelInfo(list, options, user);
- Task.WaitAll(task);
+ _livetvManager().AddChannelInfo(list, options, user);
}
else if (item is LiveTvProgram)
{
@@ -300,7 +304,7 @@ namespace Emby.Server.Implementations.Dto
}
}
- private BaseItemDto GetBaseItemDtoInternal(BaseItem item, DtoOptions options, Dictionary<Guid, Guid> currentRefreshQueue, User user = null, BaseItem owner = null)
+ private BaseItemDto GetBaseItemDtoInternal(BaseItem item, DtoOptions options, User user = null, BaseItem owner = null)
{
var fields = options.Fields;
@@ -359,12 +363,14 @@ namespace Emby.Server.Implementations.Dto
{
if (user == null)
{
- dto.MediaSources = _mediaSourceManager().GetStaticMediaSources(hasMediaSources, true).ToList();
+ dto.MediaSources = _mediaSourceManager().GetStaticMediaSources(hasMediaSources, true);
}
else
{
- dto.MediaSources = _mediaSourceManager().GetStaticMediaSources(hasMediaSources, true, user).ToList();
+ dto.MediaSources = _mediaSourceManager().GetStaticMediaSources(hasMediaSources, true, user);
}
+
+ NormalizeMediaSourceContainers(dto);
}
}
@@ -400,25 +406,74 @@ namespace Emby.Server.Implementations.Dto
dto.Etag = item.GetEtag(user);
}
- if (currentRefreshQueue != null)
+ var liveTvManager = _livetvManager();
+ if (item is ILiveTvRecording)
{
- //dto.RefreshState = item.GetRefreshState(currentRefreshQueue);
+ liveTvManager.AddInfoToRecordingDto(item, dto, user);
}
-
- if (item is ILiveTvRecording)
+ else
{
- _livetvManager().AddInfoToRecordingDto(item, dto, user);
+ var activeRecording = liveTvManager.GetActiveRecordingInfo(item.Path);
+ if (activeRecording != null)
+ {
+ dto.Type = "Recording";
+ dto.CanDownload = false;
+ dto.RunTimeTicks = null;
+
+ if (!string.IsNullOrWhiteSpace(dto.SeriesName))
+ {
+ dto.EpisodeTitle = dto.Name;
+ dto.Name = dto.SeriesName;
+ }
+ liveTvManager.AddInfoToRecordingDto(item, dto, activeRecording, user);
+ }
}
return dto;
}
+ private void NormalizeMediaSourceContainers(BaseItemDto dto)
+ {
+ foreach (var mediaSource in dto.MediaSources)
+ {
+ var container = mediaSource.Container;
+ if (string.IsNullOrWhiteSpace(container))
+ {
+ continue;
+ }
+ var containers = container.Split(new[] { ',' });
+ if (containers.Length < 2)
+ {
+ continue;
+ }
+
+ var path = mediaSource.Path;
+ string fileExtensionContainer = null;
+
+ if (!string.IsNullOrWhiteSpace(path))
+ {
+ path = Path.GetExtension(path);
+ if (!string.IsNullOrWhiteSpace(path))
+ {
+ path = Path.GetExtension(path);
+ if (!string.IsNullOrWhiteSpace(path))
+ {
+ path = path.TrimStart('.');
+ }
+ if (!string.IsNullOrWhiteSpace(path) && containers.Contains(path, StringComparer.OrdinalIgnoreCase))
+ {
+ fileExtensionContainer = path;
+ }
+ }
+ }
+
+ mediaSource.Container = fileExtensionContainer ?? containers[0];
+ }
+ }
+
public BaseItemDto GetItemByNameDto(BaseItem item, DtoOptions options, List<BaseItem> taggedItems, Dictionary<string, SyncedItemProgress> syncProgress, User user = null)
{
- var refreshQueue = options.Fields.Contains(ItemFields.RefreshState)
- ? _providerManager.GetRefreshQueue()
- : null;
- var dto = GetBaseItemDtoInternal(item, options, refreshQueue, user);
+ var dto = GetBaseItemDtoInternal(item, options, user);
if (taggedItems != null && options.Fields.Contains(ItemFields.ItemCounts))
{
@@ -517,7 +572,7 @@ namespace Emby.Server.Implementations.Dto
}
}
- if (!(item is LiveTvProgram) || fields.Contains(ItemFields.PlayAccess))
+ if (/*!(item is LiveTvProgram) ||*/ fields.Contains(ItemFields.PlayAccess))
{
dto.PlayAccess = item.GetPlayAccess(user);
}
@@ -639,7 +694,6 @@ namespace Emby.Server.Implementations.Dto
private void SetGameProperties(BaseItemDto dto, Game item)
{
- dto.Players = item.PlayersSupported;
dto.GameSystem = item.GameSystem;
dto.MultiPartGameFiles = item.MultiPartGameFiles;
}
@@ -649,12 +703,12 @@ namespace Emby.Server.Implementations.Dto
dto.GameSystem = item.GameSystemName;
}
- private List<string> GetImageTags(BaseItem item, List<ItemImageInfo> images)
+ private string[] GetImageTags(BaseItem item, List<ItemImageInfo> images)
{
return images
.Select(p => GetImageCacheTag(item, p))
.Where(i => i != null)
- .ToList();
+ .ToArray();
}
private string GetImageCacheTag(BaseItem item, ImageType type)
@@ -766,7 +820,7 @@ namespace Emby.Server.Implementations.Dto
}
}
- dto.People = list.ToArray();
+ dto.People = list.ToArray(list.Count);
}
/// <summary>
@@ -864,11 +918,6 @@ namespace Emby.Server.Implementations.Dto
dto.DateCreated = item.DateCreated;
}
- if (fields.Contains(ItemFields.DisplayMediaType))
- {
- dto.DisplayMediaType = item.DisplayMediaType;
- }
-
if (fields.Contains(ItemFields.Settings))
{
dto.LockedFields = item.LockedFields;
@@ -998,7 +1047,7 @@ namespace Emby.Server.Implementations.Dto
{
dto.RemoteTrailers = hasTrailers != null ?
hasTrailers.RemoteTrailers :
- new List<MediaUrl>();
+ new MediaUrl[] { };
}
dto.Name = item.Name;
@@ -1054,12 +1103,12 @@ namespace Emby.Server.Implementations.Dto
{
if (!string.IsNullOrWhiteSpace(item.Tagline))
{
- dto.Taglines = new List<string> { item.Tagline };
+ dto.Taglines = new string[] { item.Tagline };
}
if (dto.Taglines == null)
{
- dto.Taglines = new List<string>();
+ dto.Taglines = new string[] { };
}
}
@@ -1125,8 +1174,7 @@ namespace Emby.Server.Implementations.Dto
// Include artists that are not in the database yet, e.g., just added via metadata editor
//var foundArtists = artistItems.Items.Select(i => i.Item1.Name).ToList();
- dto.ArtistItems = new List<NameIdPair>();
- dto.ArtistItems.AddRange(hasArtist.Artists
+ dto.ArtistItems = hasArtist.Artists
//.Except(foundArtists, new DistinctNameComparer())
.Select(i =>
{
@@ -1151,7 +1199,7 @@ namespace Emby.Server.Implementations.Dto
return null;
- }).Where(i => i != null));
+ }).Where(i => i != null).ToArray();
}
var hasAlbumArtist = item as IHasAlbumArtist;
@@ -1177,8 +1225,7 @@ namespace Emby.Server.Implementations.Dto
// })
// .ToList();
- dto.AlbumArtists = new List<NameIdPair>();
- dto.AlbumArtists.AddRange(hasAlbumArtist.AlbumArtists
+ dto.AlbumArtists = hasAlbumArtist.AlbumArtists
//.Except(foundArtists, new DistinctNameComparer())
.Select(i =>
{
@@ -1203,7 +1250,7 @@ namespace Emby.Server.Implementations.Dto
return null;
- }).Where(i => i != null));
+ }).Where(i => i != null).ToArray();
}
// Add video info
@@ -1219,9 +1266,9 @@ namespace Emby.Server.Implementations.Dto
dto.HasSubtitles = video.HasSubtitles;
}
- if (video.AdditionalParts.Count != 0)
+ if (video.AdditionalParts.Length != 0)
{
- dto.PartCount = video.AdditionalParts.Count + 1;
+ dto.PartCount = video.AdditionalParts.Length + 1;
}
if (fields.Contains(ItemFields.MediaSourceCount))
@@ -1251,17 +1298,17 @@ namespace Emby.Server.Implementations.Dto
if (iHasMediaSources != null)
{
- List<MediaStream> mediaStreams;
+ MediaStream[] mediaStreams;
if (dto.MediaSources != null && dto.MediaSources.Count > 0)
{
mediaStreams = dto.MediaSources.Where(i => new Guid(i.Id) == item.Id)
.SelectMany(i => i.MediaStreams)
- .ToList();
+ .ToArray();
}
else
{
- mediaStreams = _mediaSourceManager().GetStaticMediaSources(iHasMediaSources, true).First().MediaStreams;
+ mediaStreams = _mediaSourceManager().GetStaticMediaSources(iHasMediaSources, true).First().MediaStreams.ToArray();
}
dto.MediaStreams = mediaStreams;
@@ -1271,7 +1318,7 @@ namespace Emby.Server.Implementations.Dto
var hasSpecialFeatures = item as IHasSpecialFeatures;
if (hasSpecialFeatures != null)
{
- var specialFeatureCount = hasSpecialFeatures.SpecialFeatureIds.Count;
+ var specialFeatureCount = hasSpecialFeatures.SpecialFeatureIds.Length;
if (specialFeatureCount > 0)
{
@@ -1316,15 +1363,6 @@ namespace Emby.Server.Implementations.Dto
Series episodeSeries = null;
- if (fields.Contains(ItemFields.SeriesGenres))
- {
- episodeSeries = episodeSeries ?? episode.Series;
- if (episodeSeries != null)
- {
- dto.SeriesGenres = episodeSeries.Genres.ToList();
- }
- }
-
//if (fields.Contains(ItemFields.SeriesPrimaryImage))
{
episodeSeries = episodeSeries ?? episode.Series;
@@ -1340,27 +1378,6 @@ namespace Emby.Server.Implementations.Dto
if (episodeSeries != null)
{
dto.SeriesStudio = episodeSeries.Studios.FirstOrDefault();
- if (!string.IsNullOrWhiteSpace(dto.SeriesStudio))
- {
- try
- {
- var studio = _libraryManager.GetStudio(dto.SeriesStudio);
-
- if (studio != null)
- {
- dto.SeriesStudioInfo = new StudioDto
- {
- Name = dto.SeriesStudio,
- Id = studio.Id.ToString("N"),
- PrimaryImageTag = GetImageCacheTag(studio, ImageType.Primary)
- };
- }
- }
- catch (Exception ex)
- {
-
- }
- }
}
}
}
@@ -1435,9 +1452,9 @@ namespace Emby.Server.Implementations.Dto
if (fields.Contains(ItemFields.ProductionLocations))
{
- if (item.ProductionLocations.Count > 0 || item is Movie)
+ if (item.ProductionLocations.Length > 0 || item is Movie)
{
- dto.ProductionLocations = item.ProductionLocations.ToArray();
+ dto.ProductionLocations = item.ProductionLocations;
}
}
@@ -1504,7 +1521,9 @@ namespace Emby.Server.Implementations.Dto
BaseItem parent = null;
var isFirst = true;
- while (((!dto.HasLogo && logoLimit > 0) || (!dto.HasArtImage && artLimit > 0) || (!dto.HasThumb && thumbLimit > 0) || parent is Series) &&
+ var imageTags = dto.ImageTags;
+
+ while (((!(imageTags != null && imageTags.ContainsKey(ImageType.Logo)) && logoLimit > 0) || (!(imageTags != null && imageTags.ContainsKey(ImageType.Art)) && artLimit > 0) || (!(imageTags != null && imageTags.ContainsKey(ImageType.Thumb)) && thumbLimit > 0) || parent is Series) &&
(parent = parent ?? (isFirst ? GetImageDisplayParent(item, item) ?? owner : parent)) != null)
{
if (parent == null)
@@ -1514,7 +1533,7 @@ namespace Emby.Server.Implementations.Dto
var allImages = parent.ImageInfos;
- if (logoLimit > 0 && !dto.HasLogo && dto.ParentLogoItemId == null)
+ if (logoLimit > 0 && !(imageTags != null && imageTags.ContainsKey(ImageType.Logo)) && dto.ParentLogoItemId == null)
{
var image = allImages.FirstOrDefault(i => i.Type == ImageType.Logo);
@@ -1524,7 +1543,7 @@ namespace Emby.Server.Implementations.Dto
dto.ParentLogoImageTag = GetImageCacheTag(parent, image);
}
}
- if (artLimit > 0 && !dto.HasArtImage && dto.ParentArtItemId == null)
+ if (artLimit > 0 && !(imageTags != null && imageTags.ContainsKey(ImageType.Art)) && dto.ParentArtItemId == null)
{
var image = allImages.FirstOrDefault(i => i.Type == ImageType.Art);
@@ -1534,7 +1553,7 @@ namespace Emby.Server.Implementations.Dto
dto.ParentArtImageTag = GetImageCacheTag(parent, image);
}
}
- if (thumbLimit > 0 && !dto.HasThumb && (dto.ParentThumbItemId == null || parent is Series) && !(parent is ICollectionFolder) && !(parent is UserView))
+ if (thumbLimit > 0 && !(imageTags != null && imageTags.ContainsKey(ImageType.Thumb)) && (dto.ParentThumbItemId == null || parent is Series) && !(parent is ICollectionFolder) && !(parent is UserView))
{
var image = allImages.FirstOrDefault(i => i.Type == ImageType.Thumb);
@@ -1544,7 +1563,7 @@ namespace Emby.Server.Implementations.Dto
dto.ParentThumbImageTag = GetImageCacheTag(parent, image);
}
}
- if (backdropLimit > 0 && !dto.HasBackdrop)
+ if (backdropLimit > 0 && !((dto.BackdropImageTags != null && dto.BackdropImageTags.Length > 0) || (dto.ParentBackdropImageTags != null && dto.ParentBackdropImageTags.Length > 0)))
{
var images = allImages.Where(i => i.Type == ImageType.Backdrop).Take(backdropLimit).ToList();
@@ -1586,12 +1605,12 @@ namespace Emby.Server.Implementations.Dto
/// <param name="dto">The dto.</param>
/// <param name="item">The item.</param>
/// <returns>Task.</returns>
- public void AttachPrimaryImageAspectRatio(IItemDto dto, IHasImages item)
+ public void AttachPrimaryImageAspectRatio(IItemDto dto, IHasMetadata item)
{
dto.PrimaryImageAspectRatio = GetPrimaryImageAspectRatio(item);
}
- public double? GetPrimaryImageAspectRatio(IHasImages item)
+ public double? GetPrimaryImageAspectRatio(IHasMetadata item)
{
var imageInfo = item.GetImageInfo(ImageType.Primary, 0);
@@ -1600,7 +1619,7 @@ namespace Emby.Server.Implementations.Dto
return null;
}
- var supportedEnhancers = _imageProcessor.GetSupportedEnhancers(item, ImageType.Primary).ToList();
+ var supportedEnhancers = _imageProcessor.GetSupportedEnhancers(item, ImageType.Primary);
ImageSize size;
diff --git a/Emby.Server.Implementations/Emby.Server.Implementations.csproj b/Emby.Server.Implementations/Emby.Server.Implementations.csproj
index 3d6e02816..75a9d8588 100644
--- a/Emby.Server.Implementations/Emby.Server.Implementations.csproj
+++ b/Emby.Server.Implementations/Emby.Server.Implementations.csproj
@@ -21,6 +21,7 @@
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
+ <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
@@ -29,6 +30,7 @@
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
+ <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<Compile Include="..\SharedVersion.cs">
@@ -40,6 +42,8 @@
<Compile Include="AppBase\BaseApplicationPaths.cs" />
<Compile Include="AppBase\BaseConfigurationManager.cs" />
<Compile Include="AppBase\ConfigurationHelper.cs" />
+ <Compile Include="ApplicationHost.cs" />
+ <Compile Include="Archiving\ZipClient.cs" />
<Compile Include="Branding\BrandingConfigurationFactory.cs" />
<Compile Include="Browser\BrowserLauncher.cs" />
<Compile Include="Channels\ChannelConfigurations.cs" />
@@ -52,6 +56,25 @@
<Compile Include="Collections\CollectionManager.cs" />
<Compile Include="Collections\CollectionsDynamicFolder.cs" />
<Compile Include="Configuration\ServerConfigurationManager.cs" />
+ <Compile Include="Cryptography\ASN1.cs" />
+ <Compile Include="Cryptography\ASN1Convert.cs" />
+ <Compile Include="Cryptography\BitConverterLE.cs" />
+ <Compile Include="Cryptography\CertificateGenerator.cs" />
+ <Compile Include="Cryptography\CryptoConvert.cs" />
+ <Compile Include="Cryptography\CryptographyProvider.cs" />
+ <Compile Include="Cryptography\PfxGenerator.cs" />
+ <Compile Include="Cryptography\PKCS1.cs" />
+ <Compile Include="Cryptography\PKCS12.cs" />
+ <Compile Include="Cryptography\PKCS7.cs" />
+ <Compile Include="Cryptography\PKCS8.cs" />
+ <Compile Include="Cryptography\X501Name.cs" />
+ <Compile Include="Cryptography\X509Builder.cs" />
+ <Compile Include="Cryptography\X509Certificate.cs" />
+ <Compile Include="Cryptography\X509CertificateBuilder.cs" />
+ <Compile Include="Cryptography\X509CertificateCollection.cs" />
+ <Compile Include="Cryptography\X509Extension.cs" />
+ <Compile Include="Cryptography\X509Extensions.cs" />
+ <Compile Include="Cryptography\X520Attributes.cs" />
<Compile Include="Data\ManagedConnection.cs" />
<Compile Include="Data\SqliteDisplayPreferencesRepository.cs" />
<Compile Include="Data\SqliteItemRepository.cs" />
@@ -59,10 +82,15 @@
<Compile Include="Data\SqliteUserRepository.cs" />
<Compile Include="Data\TypeMapper.cs" />
<Compile Include="Devices\CameraUploadsDynamicFolder.cs" />
+ <Compile Include="Devices\CameraUploadsFolder.cs" />
+ <Compile Include="Devices\DeviceId.cs" />
<Compile Include="Devices\DeviceManager.cs" />
<Compile Include="Devices\DeviceRepository.cs" />
+ <Compile Include="Diagnostics\CommonProcess.cs" />
+ <Compile Include="Diagnostics\ProcessFactory.cs" />
<Compile Include="Dto\DtoService.cs" />
<Compile Include="EntryPoints\AutomaticRestartEntryPoint.cs" />
+ <Compile Include="EntryPoints\ExternalPortForwarding.cs" />
<Compile Include="EntryPoints\KeepServerAwake.cs" />
<Compile Include="EntryPoints\LibraryChangedNotifier.cs" />
<Compile Include="EntryPoints\LoadRegistrations.cs" />
@@ -75,9 +103,13 @@
<Compile Include="EntryPoints\UsageEntryPoint.cs" />
<Compile Include="EntryPoints\UsageReporter.cs" />
<Compile Include="EntryPoints\UserDataChangeNotifier.cs" />
+ <Compile Include="EnvironmentInfo\EnvironmentInfo.cs" />
<Compile Include="FFMpeg\FFMpegInfo.cs" />
<Compile Include="FFMpeg\FFMpegInstallInfo.cs" />
<Compile Include="FFMpeg\FFMpegLoader.cs" />
+ <Compile Include="HttpClientManager\HttpClientInfo.cs" />
+ <Compile Include="HttpClientManager\HttpClientManager.cs" />
+ <Compile Include="HttpServerFactory.cs" />
<Compile Include="HttpServer\FileWriter.cs" />
<Compile Include="HttpServer\HttpListenerHost.cs" />
<Compile Include="HttpServer\HttpResultFactory.cs" />
@@ -99,7 +131,236 @@
<Compile Include="Images\BaseDynamicImageProvider.cs" />
<Compile Include="IO\AsyncStreamCopier.cs" />
<Compile Include="IO\FileRefresher.cs" />
+ <Compile Include="IO\IsoManager.cs" />
+ <Compile Include="IO\LibraryMonitor.cs" />
+ <Compile Include="IO\ManagedFileSystem.cs" />
<Compile Include="IO\MbLinkShortcutHandler.cs" />
+ <Compile Include="IO\MemoryStreamProvider.cs" />
+ <Compile Include="IO\ProgressStream.cs" />
+ <Compile Include="IO\SharpCifsFileSystem.cs" />
+ <Compile Include="IO\SharpCifs\Config.cs" />
+ <Compile Include="IO\SharpCifs\Dcerpc\DcerpcBind.cs" />
+ <Compile Include="IO\SharpCifs\Dcerpc\DcerpcBinding.cs" />
+ <Compile Include="IO\SharpCifs\Dcerpc\DcerpcConstants.cs" />
+ <Compile Include="IO\SharpCifs\Dcerpc\DcerpcError.cs" />
+ <Compile Include="IO\SharpCifs\Dcerpc\DcerpcException.cs" />
+ <Compile Include="IO\SharpCifs\Dcerpc\DcerpcHandle.cs" />
+ <Compile Include="IO\SharpCifs\Dcerpc\DcerpcMessage.cs" />
+ <Compile Include="IO\SharpCifs\Dcerpc\DcerpcPipeHandle.cs" />
+ <Compile Include="IO\SharpCifs\Dcerpc\DcerpcSecurityProvider.cs" />
+ <Compile Include="IO\SharpCifs\Dcerpc\Msrpc\LsaPolicyHandle.cs" />
+ <Compile Include="IO\SharpCifs\Dcerpc\Msrpc\Lsarpc.cs" />
+ <Compile Include="IO\SharpCifs\Dcerpc\Msrpc\LsarSidArrayX.cs" />
+ <Compile Include="IO\SharpCifs\Dcerpc\Msrpc\MsrpcDfsRootEnum.cs" />
+ <Compile Include="IO\SharpCifs\Dcerpc\Msrpc\MsrpcEnumerateAliasesInDomain.cs" />
+ <Compile Include="IO\SharpCifs\Dcerpc\Msrpc\MsrpcGetMembersInAlias.cs" />
+ <Compile Include="IO\SharpCifs\Dcerpc\Msrpc\MsrpcLookupSids.cs" />
+ <Compile Include="IO\SharpCifs\Dcerpc\Msrpc\MsrpcLsarOpenPolicy2.cs" />
+ <Compile Include="IO\SharpCifs\Dcerpc\Msrpc\MsrpcQueryInformationPolicy.cs" />
+ <Compile Include="IO\SharpCifs\Dcerpc\Msrpc\MsrpcSamrConnect2.cs" />
+ <Compile Include="IO\SharpCifs\Dcerpc\Msrpc\MsrpcSamrConnect4.cs" />
+ <Compile Include="IO\SharpCifs\Dcerpc\Msrpc\MsrpcSamrOpenAlias.cs" />
+ <Compile Include="IO\SharpCifs\Dcerpc\Msrpc\MsrpcSamrOpenDomain.cs" />
+ <Compile Include="IO\SharpCifs\Dcerpc\Msrpc\MsrpcShareEnum.cs" />
+ <Compile Include="IO\SharpCifs\Dcerpc\Msrpc\MsrpcShareGetInfo.cs" />
+ <Compile Include="IO\SharpCifs\Dcerpc\Msrpc\Netdfs.cs" />
+ <Compile Include="IO\SharpCifs\Dcerpc\Msrpc\Samr.cs" />
+ <Compile Include="IO\SharpCifs\Dcerpc\Msrpc\SamrAliasHandle.cs" />
+ <Compile Include="IO\SharpCifs\Dcerpc\Msrpc\SamrDomainHandle.cs" />
+ <Compile Include="IO\SharpCifs\Dcerpc\Msrpc\SamrPolicyHandle.cs" />
+ <Compile Include="IO\SharpCifs\Dcerpc\Msrpc\Srvsvc.cs" />
+ <Compile Include="IO\SharpCifs\Dcerpc\Ndr\NdrBuffer.cs" />
+ <Compile Include="IO\SharpCifs\Dcerpc\Ndr\NdrException.cs" />
+ <Compile Include="IO\SharpCifs\Dcerpc\Ndr\NdrHyper.cs" />
+ <Compile Include="IO\SharpCifs\Dcerpc\Ndr\NdrLong.cs" />
+ <Compile Include="IO\SharpCifs\Dcerpc\Ndr\NdrObject.cs" />
+ <Compile Include="IO\SharpCifs\Dcerpc\Ndr\NdrShort.cs" />
+ <Compile Include="IO\SharpCifs\Dcerpc\Ndr\NdrSmall.cs" />
+ <Compile Include="IO\SharpCifs\Dcerpc\Rpc.cs" />
+ <Compile Include="IO\SharpCifs\Dcerpc\UnicodeString.cs" />
+ <Compile Include="IO\SharpCifs\Dcerpc\UUID.cs" />
+ <Compile Include="IO\SharpCifs\Netbios\Lmhosts.cs" />
+ <Compile Include="IO\SharpCifs\Netbios\Name.cs" />
+ <Compile Include="IO\SharpCifs\Netbios\NameQueryRequest.cs" />
+ <Compile Include="IO\SharpCifs\Netbios\NameQueryResponse.cs" />
+ <Compile Include="IO\SharpCifs\Netbios\NameServiceClient.cs" />
+ <Compile Include="IO\SharpCifs\Netbios\NameServicePacket.cs" />
+ <Compile Include="IO\SharpCifs\Netbios\NbtAddress.cs" />
+ <Compile Include="IO\SharpCifs\Netbios\NbtException.cs" />
+ <Compile Include="IO\SharpCifs\Netbios\NodeStatusRequest.cs" />
+ <Compile Include="IO\SharpCifs\Netbios\NodeStatusResponse.cs" />
+ <Compile Include="IO\SharpCifs\Netbios\SessionRequestPacket.cs" />
+ <Compile Include="IO\SharpCifs\Netbios\SessionRetargetResponsePacket.cs" />
+ <Compile Include="IO\SharpCifs\Netbios\SessionServicePacket.cs" />
+ <Compile Include="IO\SharpCifs\Ntlmssp\NtlmFlags.cs" />
+ <Compile Include="IO\SharpCifs\Ntlmssp\NtlmMessage.cs" />
+ <Compile Include="IO\SharpCifs\Ntlmssp\Type1Message.cs" />
+ <Compile Include="IO\SharpCifs\Ntlmssp\Type2Message.cs" />
+ <Compile Include="IO\SharpCifs\Ntlmssp\Type3Message.cs" />
+ <Compile Include="IO\SharpCifs\Smb\ACE.cs" />
+ <Compile Include="IO\SharpCifs\Smb\AllocInfo.cs" />
+ <Compile Include="IO\SharpCifs\Smb\AndXServerMessageBlock.cs" />
+ <Compile Include="IO\SharpCifs\Smb\BufferCache.cs" />
+ <Compile Include="IO\SharpCifs\Smb\Dfs.cs" />
+ <Compile Include="IO\SharpCifs\Smb\DfsReferral.cs" />
+ <Compile Include="IO\SharpCifs\Smb\DosError.cs" />
+ <Compile Include="IO\SharpCifs\Smb\DosFileFilter.cs" />
+ <Compile Include="IO\SharpCifs\Smb\FileEntry.cs" />
+ <Compile Include="IO\SharpCifs\Smb\IInfo.cs" />
+ <Compile Include="IO\SharpCifs\Smb\NetServerEnum2.cs" />
+ <Compile Include="IO\SharpCifs\Smb\NetServerEnum2Response.cs" />
+ <Compile Include="IO\SharpCifs\Smb\NetShareEnum.cs" />
+ <Compile Include="IO\SharpCifs\Smb\NetShareEnumResponse.cs" />
+ <Compile Include="IO\SharpCifs\Smb\NtlmAuthenticator.cs" />
+ <Compile Include="IO\SharpCifs\Smb\NtlmChallenge.cs" />
+ <Compile Include="IO\SharpCifs\Smb\NtlmContext.cs" />
+ <Compile Include="IO\SharpCifs\Smb\NtlmPasswordAuthentication.cs" />
+ <Compile Include="IO\SharpCifs\Smb\NtStatus.cs" />
+ <Compile Include="IO\SharpCifs\Smb\NtTransQuerySecurityDesc.cs" />
+ <Compile Include="IO\SharpCifs\Smb\NtTransQuerySecurityDescResponse.cs" />
+ <Compile Include="IO\SharpCifs\Smb\Principal.cs" />
+ <Compile Include="IO\SharpCifs\Smb\SecurityDescriptor.cs" />
+ <Compile Include="IO\SharpCifs\Smb\ServerMessageBlock.cs" />
+ <Compile Include="IO\SharpCifs\Smb\SID.cs" />
+ <Compile Include="IO\SharpCifs\Smb\SigningDigest.cs" />
+ <Compile Include="IO\SharpCifs\Smb\SmbAuthException.cs" />
+ <Compile Include="IO\SharpCifs\Smb\SmbComBlankResponse.cs" />
+ <Compile Include="IO\SharpCifs\Smb\SmbComClose.cs" />
+ <Compile Include="IO\SharpCifs\Smb\SmbComCreateDirectory.cs" />
+ <Compile Include="IO\SharpCifs\Smb\SmbComDelete.cs" />
+ <Compile Include="IO\SharpCifs\Smb\SmbComDeleteDirectory.cs" />
+ <Compile Include="IO\SharpCifs\Smb\SmbComFindClose2.cs" />
+ <Compile Include="IO\SharpCifs\Smb\SmbComLogoffAndX.cs" />
+ <Compile Include="IO\SharpCifs\Smb\SmbComNegotiate.cs" />
+ <Compile Include="IO\SharpCifs\Smb\SmbComNegotiateResponse.cs" />
+ <Compile Include="IO\SharpCifs\Smb\SmbComNTCreateAndX.cs" />
+ <Compile Include="IO\SharpCifs\Smb\SmbComNTCreateAndXResponse.cs" />
+ <Compile Include="IO\SharpCifs\Smb\SmbComNtTransaction.cs" />
+ <Compile Include="IO\SharpCifs\Smb\SmbComNtTransactionResponse.cs" />
+ <Compile Include="IO\SharpCifs\Smb\SmbComOpenAndX.cs" />
+ <Compile Include="IO\SharpCifs\Smb\SmbComOpenAndXResponse.cs" />
+ <Compile Include="IO\SharpCifs\Smb\SmbComQueryInformation.cs" />
+ <Compile Include="IO\SharpCifs\Smb\SmbComQueryInformationResponse.cs" />
+ <Compile Include="IO\SharpCifs\Smb\SmbComReadAndX.cs" />
+ <Compile Include="IO\SharpCifs\Smb\SmbComReadAndXResponse.cs" />
+ <Compile Include="IO\SharpCifs\Smb\SmbComRename.cs" />
+ <Compile Include="IO\SharpCifs\Smb\SmbComSessionSetupAndX.cs" />
+ <Compile Include="IO\SharpCifs\Smb\SmbComSessionSetupAndXResponse.cs" />
+ <Compile Include="IO\SharpCifs\Smb\SmbComTransaction.cs" />
+ <Compile Include="IO\SharpCifs\Smb\SmbComTransactionResponse.cs" />
+ <Compile Include="IO\SharpCifs\Smb\SmbComTreeConnectAndX.cs" />
+ <Compile Include="IO\SharpCifs\Smb\SmbComTreeConnectAndXResponse.cs" />
+ <Compile Include="IO\SharpCifs\Smb\SmbComTreeDisconnect.cs" />
+ <Compile Include="IO\SharpCifs\Smb\SmbComWrite.cs" />
+ <Compile Include="IO\SharpCifs\Smb\SmbComWriteAndX.cs" />
+ <Compile Include="IO\SharpCifs\Smb\SmbComWriteAndXResponse.cs" />
+ <Compile Include="IO\SharpCifs\Smb\SmbComWriteResponse.cs" />
+ <Compile Include="IO\SharpCifs\Smb\SmbConstants.cs" />
+ <Compile Include="IO\SharpCifs\Smb\SmbException.cs" />
+ <Compile Include="IO\SharpCifs\Smb\SmbFile.cs" />
+ <Compile Include="IO\SharpCifs\Smb\SmbFileExtensions.cs" />
+ <Compile Include="IO\SharpCifs\Smb\SmbFileFilter.cs" />
+ <Compile Include="IO\SharpCifs\Smb\SmbFileInputStream.cs" />
+ <Compile Include="IO\SharpCifs\Smb\SmbFilenameFilter.cs" />
+ <Compile Include="IO\SharpCifs\Smb\SmbFileOutputStream.cs" />
+ <Compile Include="IO\SharpCifs\Smb\SmbNamedPipe.cs" />
+ <Compile Include="IO\SharpCifs\Smb\SmbRandomAccessFile.cs" />
+ <Compile Include="IO\SharpCifs\Smb\SmbSession.cs" />
+ <Compile Include="IO\SharpCifs\Smb\SmbShareInfo.cs" />
+ <Compile Include="IO\SharpCifs\Smb\SmbTransport.cs" />
+ <Compile Include="IO\SharpCifs\Smb\SmbTree.cs" />
+ <Compile Include="IO\SharpCifs\Smb\Trans2FindFirst2.cs" />
+ <Compile Include="IO\SharpCifs\Smb\Trans2FindFirst2Response.cs" />
+ <Compile Include="IO\SharpCifs\Smb\Trans2FindNext2.cs" />
+ <Compile Include="IO\SharpCifs\Smb\Trans2GetDfsReferral.cs" />
+ <Compile Include="IO\SharpCifs\Smb\Trans2GetDfsReferralResponse.cs" />
+ <Compile Include="IO\SharpCifs\Smb\Trans2QueryFSInformation.cs" />
+ <Compile Include="IO\SharpCifs\Smb\Trans2QueryFSInformationResponse.cs" />
+ <Compile Include="IO\SharpCifs\Smb\Trans2QueryPathInformation.cs" />
+ <Compile Include="IO\SharpCifs\Smb\Trans2QueryPathInformationResponse.cs" />
+ <Compile Include="IO\SharpCifs\Smb\Trans2SetFileInformation.cs" />
+ <Compile Include="IO\SharpCifs\Smb\Trans2SetFileInformationResponse.cs" />
+ <Compile Include="IO\SharpCifs\Smb\TransactNamedPipeInputStream.cs" />
+ <Compile Include="IO\SharpCifs\Smb\TransactNamedPipeOutputStream.cs" />
+ <Compile Include="IO\SharpCifs\Smb\TransCallNamedPipe.cs" />
+ <Compile Include="IO\SharpCifs\Smb\TransCallNamedPipeResponse.cs" />
+ <Compile Include="IO\SharpCifs\Smb\TransPeekNamedPipe.cs" />
+ <Compile Include="IO\SharpCifs\Smb\TransPeekNamedPipeResponse.cs" />
+ <Compile Include="IO\SharpCifs\Smb\TransTransactNamedPipe.cs" />
+ <Compile Include="IO\SharpCifs\Smb\TransTransactNamedPipeResponse.cs" />
+ <Compile Include="IO\SharpCifs\Smb\TransWaitNamedPipe.cs" />
+ <Compile Include="IO\SharpCifs\Smb\TransWaitNamedPipeResponse.cs" />
+ <Compile Include="IO\SharpCifs\Smb\WinError.cs" />
+ <Compile Include="IO\SharpCifs\UniAddress.cs" />
+ <Compile Include="IO\SharpCifs\Util\Base64.cs" />
+ <Compile Include="IO\SharpCifs\Util\DES.cs" />
+ <Compile Include="IO\SharpCifs\Util\Encdec.cs" />
+ <Compile Include="IO\SharpCifs\Util\Hexdump.cs" />
+ <Compile Include="IO\SharpCifs\Util\HMACT64.cs" />
+ <Compile Include="IO\SharpCifs\Util\LogStream.cs" />
+ <Compile Include="IO\SharpCifs\Util\MD4.cs" />
+ <Compile Include="IO\SharpCifs\Util\RC4.cs" />
+ <Compile Include="IO\SharpCifs\Util\Sharpen\AbstractMap.cs" />
+ <Compile Include="IO\SharpCifs\Util\Sharpen\Arrays.cs" />
+ <Compile Include="IO\SharpCifs\Util\Sharpen\BufferedReader.cs" />
+ <Compile Include="IO\SharpCifs\Util\Sharpen\BufferedWriter.cs" />
+ <Compile Include="IO\SharpCifs\Util\Sharpen\CharBuffer.cs" />
+ <Compile Include="IO\SharpCifs\Util\Sharpen\CharSequence.cs" />
+ <Compile Include="IO\SharpCifs\Util\Sharpen\Collections.cs" />
+ <Compile Include="IO\SharpCifs\Util\Sharpen\ConcurrentHashMap.cs" />
+ <Compile Include="IO\SharpCifs\Util\Sharpen\DateFormat.cs" />
+ <Compile Include="IO\SharpCifs\Util\Sharpen\EnumeratorWrapper.cs" />
+ <Compile Include="IO\SharpCifs\Util\Sharpen\Exceptions.cs" />
+ <Compile Include="IO\SharpCifs\Util\Sharpen\Extensions.cs" />
+ <Compile Include="IO\SharpCifs\Util\Sharpen\FileInputStream.cs" />
+ <Compile Include="IO\SharpCifs\Util\Sharpen\FileOutputStream.cs" />
+ <Compile Include="IO\SharpCifs\Util\Sharpen\FilePath.cs" />
+ <Compile Include="IO\SharpCifs\Util\Sharpen\FileReader.cs" />
+ <Compile Include="IO\SharpCifs\Util\Sharpen\FileWriter.cs" />
+ <Compile Include="IO\SharpCifs\Util\Sharpen\FilterInputStream.cs" />
+ <Compile Include="IO\SharpCifs\Util\Sharpen\FilterOutputStream.cs" />
+ <Compile Include="IO\SharpCifs\Util\Sharpen\Hashtable.cs" />
+ <Compile Include="IO\SharpCifs\Util\Sharpen\HttpURLConnection.cs" />
+ <Compile Include="IO\SharpCifs\Util\Sharpen\ICallable.cs" />
+ <Compile Include="IO\SharpCifs\Util\Sharpen\IConcurrentMap.cs" />
+ <Compile Include="IO\SharpCifs\Util\Sharpen\IExecutor.cs" />
+ <Compile Include="IO\SharpCifs\Util\Sharpen\IFilenameFilter.cs" />
+ <Compile Include="IO\SharpCifs\Util\Sharpen\IFuture.cs" />
+ <Compile Include="IO\SharpCifs\Util\Sharpen\InputStream.cs" />
+ <Compile Include="IO\SharpCifs\Util\Sharpen\InputStreamReader.cs" />
+ <Compile Include="IO\SharpCifs\Util\Sharpen\IPrivilegedAction.cs" />
+ <Compile Include="IO\SharpCifs\Util\Sharpen\IRunnable.cs" />
+ <Compile Include="IO\SharpCifs\Util\Sharpen\Iterator.cs" />
+ <Compile Include="IO\SharpCifs\Util\Sharpen\LinkageError.cs" />
+ <Compile Include="IO\SharpCifs\Util\Sharpen\Matcher.cs" />
+ <Compile Include="IO\SharpCifs\Util\Sharpen\MD5.cs" />
+ <Compile Include="IO\SharpCifs\Util\Sharpen\MD5Managed.cs" />
+ <Compile Include="IO\SharpCifs\Util\Sharpen\MessageDigest.cs" />
+ <Compile Include="IO\SharpCifs\Util\Sharpen\NetworkStream.cs" />
+ <Compile Include="IO\SharpCifs\Util\Sharpen\ObjectInputStream.cs" />
+ <Compile Include="IO\SharpCifs\Util\Sharpen\ObjectOutputStream.cs" />
+ <Compile Include="IO\SharpCifs\Util\Sharpen\OutputStream.cs" />
+ <Compile Include="IO\SharpCifs\Util\Sharpen\OutputStreamWriter.cs" />
+ <Compile Include="IO\SharpCifs\Util\Sharpen\PipedInputStream.cs" />
+ <Compile Include="IO\SharpCifs\Util\Sharpen\PipedOutputStream.cs" />
+ <Compile Include="IO\SharpCifs\Util\Sharpen\PrintWriter.cs" />
+ <Compile Include="IO\SharpCifs\Util\Sharpen\Properties.cs" />
+ <Compile Include="IO\SharpCifs\Util\Sharpen\RandomAccessFile.cs" />
+ <Compile Include="IO\SharpCifs\Util\Sharpen\ReentrantLock.cs" />
+ <Compile Include="IO\SharpCifs\Util\Sharpen\Reference.cs" />
+ <Compile Include="IO\SharpCifs\Util\Sharpen\Runtime.cs" />
+ <Compile Include="IO\SharpCifs\Util\Sharpen\SimpleDateFormat.cs" />
+ <Compile Include="IO\SharpCifs\Util\Sharpen\SocketEx.cs" />
+ <Compile Include="IO\SharpCifs\Util\Sharpen\StringTokenizer.cs" />
+ <Compile Include="IO\SharpCifs\Util\Sharpen\SynchronizedList.cs" />
+ <Compile Include="IO\SharpCifs\Util\Sharpen\Thread.cs" />
+ <Compile Include="IO\SharpCifs\Util\Sharpen\ThreadFactory.cs" />
+ <Compile Include="IO\SharpCifs\Util\Sharpen\ThreadPoolExecutor.cs" />
+ <Compile Include="IO\SharpCifs\Util\Sharpen\WrappedSystemStream.cs" />
+ <Compile Include="IO\SharpCifs\Util\Transport\Request.cs" />
+ <Compile Include="IO\SharpCifs\Util\Transport\Response.cs" />
+ <Compile Include="IO\SharpCifs\Util\Transport\Transport.cs" />
+ <Compile Include="IO\SharpCifs\Util\Transport\TransportException.cs" />
<Compile Include="IO\ThrottledStream.cs" />
<Compile Include="Library\CoreResolutionIgnoreRule.cs" />
<Compile Include="Library\LibraryManager.cs" />
@@ -170,9 +431,17 @@
<Compile Include="LiveTv\TunerHosts\MulticastStream.cs" />
<Compile Include="LiveTv\TunerHosts\QueueStream.cs" />
<Compile Include="Localization\LocalizationManager.cs" />
+ <Compile Include="Localization\TextLocalizer.cs" />
+ <Compile Include="Logging\ConsoleLogger.cs" />
+ <Compile Include="Logging\SimpleLogManager.cs" />
<Compile Include="Logging\UnhandledExceptionWriter.cs" />
<Compile Include="MediaEncoder\EncodingManager.cs" />
<Compile Include="Migrations\IVersionMigration.cs" />
+ <Compile Include="Networking\NetworkManager.cs" />
+ <Compile Include="Net\DisposableManagedObjectBase.cs" />
+ <Compile Include="Net\NetAcceptSocket.cs" />
+ <Compile Include="Net\SocketFactory.cs" />
+ <Compile Include="Net\UdpSocket.cs" />
<Compile Include="News\NewsEntryPoint.cs" />
<Compile Include="News\NewsService.cs" />
<Compile Include="Notifications\CoreNotificationTypes.cs" />
@@ -187,20 +456,34 @@
<Compile Include="Data\CleanDatabaseScheduledTask.cs" />
<Compile Include="Data\SqliteExtensions.cs" />
<Compile Include="Photos\PhotoAlbumImageProvider.cs" />
+ <Compile Include="Playlists\ManualPlaylistsFolder.cs" />
<Compile Include="Playlists\PlaylistImageProvider.cs" />
<Compile Include="Playlists\PlaylistManager.cs" />
<Compile Include="Playlists\PlaylistsDynamicFolder.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
+ <Compile Include="Reflection\AssemblyInfo.cs" />
<Compile Include="ScheduledTasks\ChapterImagesTask.cs" />
+ <Compile Include="ScheduledTasks\DailyTrigger.cs" />
+ <Compile Include="ScheduledTasks\IntervalTrigger.cs" />
<Compile Include="ScheduledTasks\PeopleValidationTask.cs" />
<Compile Include="ScheduledTasks\PluginUpdateTask.cs" />
<Compile Include="ScheduledTasks\RefreshMediaLibraryTask.cs" />
+ <Compile Include="ScheduledTasks\ScheduledTaskWorker.cs" />
+ <Compile Include="ScheduledTasks\StartupTrigger.cs" />
+ <Compile Include="ScheduledTasks\SystemEventTrigger.cs" />
<Compile Include="ScheduledTasks\SystemUpdateTask.cs" />
+ <Compile Include="ScheduledTasks\TaskManager.cs" />
+ <Compile Include="ScheduledTasks\Tasks\DeleteCacheFileTask.cs" />
+ <Compile Include="ScheduledTasks\Tasks\DeleteLogFileTask.cs" />
+ <Compile Include="ScheduledTasks\Tasks\ReloadLoggerFileTask.cs" />
+ <Compile Include="ScheduledTasks\WeeklyTrigger.cs" />
<Compile Include="Security\AuthenticationRepository.cs" />
<Compile Include="Security\EncryptionManager.cs" />
<Compile Include="Security\MBLicenseFile.cs" />
<Compile Include="Security\PluginSecurityManager.cs" />
<Compile Include="Security\RegRecord.cs" />
+ <Compile Include="Serialization\JsonSerializer.cs" />
+ <Compile Include="Serialization\XmlSerializer.cs" />
<Compile Include="ServerApplicationPaths.cs" />
<Compile Include="ServerManager\ServerManager.cs" />
<Compile Include="ServerManager\WebSocketConnection.cs" />
@@ -221,7 +504,6 @@
<Compile Include="Social\SharingManager.cs" />
<Compile Include="Social\SharingRepository.cs" />
<Compile Include="Sorting\AiredEpisodeOrderComparer.cs" />
- <Compile Include="Sorting\AirTimeComparer.cs" />
<Compile Include="Sorting\AlbumArtistComparer.cs" />
<Compile Include="Sorting\AlbumComparer.cs" />
<Compile Include="Sorting\AlphanumComparator.cs" />
@@ -249,17 +531,89 @@
<Compile Include="Sorting\StartDateComparer.cs" />
<Compile Include="Sorting\StudioComparer.cs" />
<Compile Include="StartupOptions.cs" />
+ <Compile Include="SystemEvents.cs" />
+ <Compile Include="TextEncoding\NLangDetect\Detector.cs" />
+ <Compile Include="TextEncoding\NLangDetect\DetectorFactory.cs" />
+ <Compile Include="TextEncoding\NLangDetect\ErrorCode.cs" />
+ <Compile Include="TextEncoding\NLangDetect\Extensions\CharExtensions.cs" />
+ <Compile Include="TextEncoding\NLangDetect\Extensions\RandomExtensions.cs" />
+ <Compile Include="TextEncoding\NLangDetect\Extensions\StringExtensions.cs" />
+ <Compile Include="TextEncoding\NLangDetect\Extensions\UnicodeBlock.cs" />
+ <Compile Include="TextEncoding\NLangDetect\GenProfile.cs" />
+ <Compile Include="TextEncoding\NLangDetect\InternalException.cs" />
+ <Compile Include="TextEncoding\NLangDetect\Language.cs" />
+ <Compile Include="TextEncoding\NLangDetect\LanguageDetector.cs" />
+ <Compile Include="TextEncoding\NLangDetect\NLangDetectException.cs" />
+ <Compile Include="TextEncoding\NLangDetect\ProbVector.cs" />
+ <Compile Include="TextEncoding\NLangDetect\Utils\LangProfile.cs" />
+ <Compile Include="TextEncoding\NLangDetect\Utils\Messages.cs" />
+ <Compile Include="TextEncoding\NLangDetect\Utils\NGram.cs" />
+ <Compile Include="TextEncoding\NLangDetect\Utils\TagExtractor.cs" />
+ <Compile Include="TextEncoding\TextEncoding.cs" />
+ <Compile Include="TextEncoding\TextEncodingDetect.cs" />
+ <Compile Include="TextEncoding\UniversalDetector\CharsetDetector.cs" />
+ <Compile Include="TextEncoding\UniversalDetector\Core\Big5Prober.cs" />
+ <Compile Include="TextEncoding\UniversalDetector\Core\BitPackage.cs" />
+ <Compile Include="TextEncoding\UniversalDetector\Core\CharDistributionAnalyser.cs" />
+ <Compile Include="TextEncoding\UniversalDetector\Core\CharsetProber.cs" />
+ <Compile Include="TextEncoding\UniversalDetector\Core\Charsets.cs" />
+ <Compile Include="TextEncoding\UniversalDetector\Core\CodingStateMachine.cs" />
+ <Compile Include="TextEncoding\UniversalDetector\Core\EscCharsetProber.cs" />
+ <Compile Include="TextEncoding\UniversalDetector\Core\EscSM.cs" />
+ <Compile Include="TextEncoding\UniversalDetector\Core\EUCJPProber.cs" />
+ <Compile Include="TextEncoding\UniversalDetector\Core\EUCKRProber.cs" />
+ <Compile Include="TextEncoding\UniversalDetector\Core\EUCTWProber.cs" />
+ <Compile Include="TextEncoding\UniversalDetector\Core\GB18030Prober.cs" />
+ <Compile Include="TextEncoding\UniversalDetector\Core\HebrewProber.cs" />
+ <Compile Include="TextEncoding\UniversalDetector\Core\JapaneseContextAnalyser.cs" />
+ <Compile Include="TextEncoding\UniversalDetector\Core\LangBulgarianModel.cs" />
+ <Compile Include="TextEncoding\UniversalDetector\Core\LangCyrillicModel.cs" />
+ <Compile Include="TextEncoding\UniversalDetector\Core\LangGreekModel.cs" />
+ <Compile Include="TextEncoding\UniversalDetector\Core\LangHebrewModel.cs" />
+ <Compile Include="TextEncoding\UniversalDetector\Core\LangHungarianModel.cs" />
+ <Compile Include="TextEncoding\UniversalDetector\Core\LangThaiModel.cs" />
+ <Compile Include="TextEncoding\UniversalDetector\Core\Latin1Prober.cs" />
+ <Compile Include="TextEncoding\UniversalDetector\Core\MBCSGroupProber.cs" />
+ <Compile Include="TextEncoding\UniversalDetector\Core\MBCSSM.cs" />
+ <Compile Include="TextEncoding\UniversalDetector\Core\SBCharsetProber.cs" />
+ <Compile Include="TextEncoding\UniversalDetector\Core\SBCSGroupProber.cs" />
+ <Compile Include="TextEncoding\UniversalDetector\Core\SequenceModel.cs" />
+ <Compile Include="TextEncoding\UniversalDetector\Core\SJISProber.cs" />
+ <Compile Include="TextEncoding\UniversalDetector\Core\SMModel.cs" />
+ <Compile Include="TextEncoding\UniversalDetector\Core\UniversalDetector.cs" />
+ <Compile Include="TextEncoding\UniversalDetector\Core\UTF8Prober.cs" />
+ <Compile Include="TextEncoding\UniversalDetector\DetectionConfidence.cs" />
+ <Compile Include="TextEncoding\UniversalDetector\ICharsetDetector.cs" />
+ <Compile Include="Threading\CommonTimer.cs" />
+ <Compile Include="Threading\TimerFactory.cs" />
<Compile Include="TV\SeriesPostScanTask.cs" />
<Compile Include="TV\TVSeriesManager.cs" />
<Compile Include="Udp\UdpServer.cs" />
<Compile Include="Updates\InstallationManager.cs" />
<Compile Include="UserViews\CollectionFolderImageProvider.cs" />
<Compile Include="UserViews\DynamicImageProvider.cs" />
+ <Compile Include="Xml\XmlReaderSettingsFactory.cs" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Localization\iso6392.txt" />
</ItemGroup>
<ItemGroup>
+ <ProjectReference Include="..\Emby.Dlna\Emby.Dlna.csproj">
+ <Project>{805844ab-e92f-45e6-9d99-4f6d48d129a5}</Project>
+ <Name>Emby.Dlna</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\Emby.Drawing\Emby.Drawing.csproj">
+ <Project>{08fff49b-f175-4807-a2b5-73b0ebd9f716}</Project>
+ <Name>Emby.Drawing</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\Emby.Photos\Emby.Photos.csproj">
+ <Project>{89ab4548-770d-41fd-a891-8daff44f452c}</Project>
+ <Name>Emby.Photos</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\MediaBrowser.Api\MediaBrowser.Api.csproj">
+ <Project>{4fd51ac5-2c16-4308-a993-c3a84f3b4582}</Project>
+ <Name>MediaBrowser.Api</Name>
+ </ProjectReference>
<ProjectReference Include="..\MediaBrowser.Common\MediaBrowser.Common.csproj">
<Project>{9142eefa-7570-41e1-bfcc-468bb571af2f}</Project>
<Name>MediaBrowser.Common</Name>
@@ -268,6 +622,10 @@
<Project>{17e1f4e6-8abd-4fe5-9ecf-43d4b6087ba2}</Project>
<Name>MediaBrowser.Controller</Name>
</ProjectReference>
+ <ProjectReference Include="..\MediaBrowser.LocalMetadata\MediaBrowser.LocalMetadata.csproj">
+ <Project>{7ef9f3e0-697d-42f3-a08f-19deb5f84392}</Project>
+ <Name>MediaBrowser.LocalMetadata</Name>
+ </ProjectReference>
<ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj">
<Project>{7eeeb4bb-f3e8-48fc-b4c5-70f0fff8329b}</Project>
<Name>MediaBrowser.Model</Name>
@@ -276,22 +634,46 @@
<Project>{442b5058-dcaf-4263-bb6a-f21e31120a1b}</Project>
<Name>MediaBrowser.Providers</Name>
</ProjectReference>
- <ProjectReference Include="..\MediaBrowser.Server.Implementations\MediaBrowser.Server.Implementations.csproj">
- <Project>{2e781478-814d-4a48-9d80-bff206441a65}</Project>
- <Name>MediaBrowser.Server.Implementations</Name>
+ <ProjectReference Include="..\MediaBrowser.WebDashboard\MediaBrowser.WebDashboard.csproj">
+ <Project>{5624b7b5-b5a7-41d8-9f10-cc5611109619}</Project>
+ <Name>MediaBrowser.WebDashboard</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\MediaBrowser.XbmcMetadata\MediaBrowser.XbmcMetadata.csproj">
+ <Project>{23499896-b135-4527-8574-c26e926ea99e}</Project>
+ <Name>MediaBrowser.XbmcMetadata</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\Mono.Nat\Mono.Nat.csproj">
+ <Project>{cb7f2326-6497-4a3d-ba03-48513b17a7be}</Project>
+ <Name>Mono.Nat</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\OpenSubtitlesHandler\OpenSubtitlesHandler.csproj">
+ <Project>{4a4402d4-e910-443b-b8fc-2c18286a2ca0}</Project>
+ <Name>OpenSubtitlesHandler</Name>
</ProjectReference>
<ProjectReference Include="..\SocketHttpListener\SocketHttpListener.csproj">
<Project>{1d74413b-e7cf-455b-b021-f52bdf881542}</Project>
<Name>SocketHttpListener</Name>
</ProjectReference>
+ <Reference Include="Emby.Server.MediaEncoding">
+ <HintPath>..\ThirdParty\emby\Emby.Server.MediaEncoding.dll</HintPath>
+ </Reference>
<Reference Include="Emby.XmlTv, Version=1.0.6387.29335, Culture=neutral, processorArchitecture=MSIL">
- <HintPath>..\packages\Emby.XmlTv.1.0.9\lib\portable-net45+win8\Emby.XmlTv.dll</HintPath>
+ <HintPath>..\packages\Emby.XmlTv.1.0.10\lib\portable-net45+netstandard2.0+win8\Emby.XmlTv.dll</HintPath>
+ </Reference>
+ <Reference Include="MediaBrowser.Naming, Version=1.0.6447.2217, Culture=neutral, processorArchitecture=MSIL">
+ <HintPath>..\packages\MediaBrowser.Naming.1.0.7\lib\portable-net45+netstandard2.0+win8\MediaBrowser.Naming.dll</HintPath>
<Private>True</Private>
</Reference>
- <Reference Include="MediaBrowser.Naming, Version=1.0.6279.25941, Culture=neutral, processorArchitecture=MSIL">
- <HintPath>..\packages\MediaBrowser.Naming.1.0.5\lib\portable-net45+win8\MediaBrowser.Naming.dll</HintPath>
+ <Reference Include="ServiceStack.Text, Version=4.5.8.0, Culture=neutral, processorArchitecture=MSIL">
+ <HintPath>..\packages\ServiceStack.Text.4.5.8\lib\net45\ServiceStack.Text.dll</HintPath>
<Private>True</Private>
</Reference>
+ <Reference Include="SharpCompress, Version=0.14.0.0, Culture=neutral, processorArchitecture=MSIL">
+ <HintPath>..\packages\SharpCompress.0.14.0\lib\net45\SharpCompress.dll</HintPath>
+ </Reference>
+ <Reference Include="SimpleInjector, Version=4.0.8.0, Culture=neutral, PublicKeyToken=984cb50dea722e99, processorArchitecture=MSIL">
+ <HintPath>..\packages\SimpleInjector.4.0.8\lib\net45\SimpleInjector.dll</HintPath>
+ </Reference>
<Reference Include="SQLitePCL.pretty, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\SQLitePCL.pretty.1.1.0\lib\portable-net45+netcore45+wpa81+wp8\SQLitePCL.pretty.dll</HintPath>
<Private>True</Private>
@@ -299,10 +681,10 @@
</ItemGroup>
<ItemGroup>
<Reference Include="SQLitePCLRaw.core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1488e028ca7ab535, processorArchitecture=MSIL">
- <HintPath>..\packages\SQLitePCLRaw.core.1.1.7\lib\net45\SQLitePCLRaw.core.dll</HintPath>
- <Private>True</Private>
+ <HintPath>..\packages\SQLitePCLRaw.core.1.1.8\lib\net45\SQLitePCLRaw.core.dll</HintPath>
</Reference>
<Reference Include="System" />
+ <Reference Include="System.Configuration" />
<Reference Include="System.Core" />
<Reference Include="System.Runtime.Serialization" />
<Reference Include="System.Xml.Linq" />
@@ -316,7 +698,6 @@
<EmbeddedResource Include="Localization\Core\ar.json" />
<EmbeddedResource Include="Localization\Core\bg-BG.json" />
<EmbeddedResource Include="Localization\Core\ca.json" />
- <EmbeddedResource Include="Localization\Core\core.json" />
<EmbeddedResource Include="Localization\Core\cs.json" />
<EmbeddedResource Include="Localization\Core\da.json" />
<EmbeddedResource Include="Localization\Core\de.json" />
@@ -355,6 +736,60 @@
<EmbeddedResource Include="Localization\Core\zh-TW.json" />
<EmbeddedResource Include="Localization\countries.json" />
<None Include="packages.config" />
+ <None Include="TextEncoding\NLangDetect\Profiles\afr" />
+ <None Include="TextEncoding\NLangDetect\Profiles\ara" />
+ <None Include="TextEncoding\NLangDetect\Profiles\ben" />
+ <None Include="TextEncoding\NLangDetect\Profiles\bul" />
+ <None Include="TextEncoding\NLangDetect\Profiles\ces" />
+ <None Include="TextEncoding\NLangDetect\Profiles\dan" />
+ <None Include="TextEncoding\NLangDetect\Profiles\deu" />
+ <None Include="TextEncoding\NLangDetect\Profiles\ell" />
+ <None Include="TextEncoding\NLangDetect\Profiles\eng" />
+ <None Include="TextEncoding\NLangDetect\Profiles\est" />
+ <None Include="TextEncoding\NLangDetect\Profiles\fas" />
+ <None Include="TextEncoding\NLangDetect\Profiles\fin" />
+ <None Include="TextEncoding\NLangDetect\Profiles\fra" />
+ <None Include="TextEncoding\NLangDetect\Profiles\guj" />
+ <None Include="TextEncoding\NLangDetect\Profiles\heb" />
+ <None Include="TextEncoding\NLangDetect\Profiles\hin" />
+ <None Include="TextEncoding\NLangDetect\Profiles\hrv" />
+ <None Include="TextEncoding\NLangDetect\Profiles\hun" />
+ <None Include="TextEncoding\NLangDetect\Profiles\ind" />
+ <None Include="TextEncoding\NLangDetect\Profiles\ita" />
+ <None Include="TextEncoding\NLangDetect\Profiles\jpn" />
+ <None Include="TextEncoding\NLangDetect\Profiles\kan" />
+ <None Include="TextEncoding\NLangDetect\Profiles\kor" />
+ <None Include="TextEncoding\NLangDetect\Profiles\lav" />
+ <None Include="TextEncoding\NLangDetect\Profiles\lit" />
+ <None Include="TextEncoding\NLangDetect\Profiles\mal" />
+ <None Include="TextEncoding\NLangDetect\Profiles\mar" />
+ <None Include="TextEncoding\NLangDetect\Profiles\mkd" />
+ <None Include="TextEncoding\NLangDetect\Profiles\nep" />
+ <None Include="TextEncoding\NLangDetect\Profiles\nld" />
+ <None Include="TextEncoding\NLangDetect\Profiles\nor" />
+ <None Include="TextEncoding\NLangDetect\Profiles\pan" />
+ <None Include="TextEncoding\NLangDetect\Profiles\pol" />
+ <None Include="TextEncoding\NLangDetect\Profiles\por" />
+ <None Include="TextEncoding\NLangDetect\Profiles\ron" />
+ <None Include="TextEncoding\NLangDetect\Profiles\rus" />
+ <None Include="TextEncoding\NLangDetect\Profiles\slk" />
+ <None Include="TextEncoding\NLangDetect\Profiles\slv" />
+ <None Include="TextEncoding\NLangDetect\Profiles\som" />
+ <None Include="TextEncoding\NLangDetect\Profiles\spa" />
+ <None Include="TextEncoding\NLangDetect\Profiles\sqi" />
+ <None Include="TextEncoding\NLangDetect\Profiles\swa" />
+ <None Include="TextEncoding\NLangDetect\Profiles\swe" />
+ <None Include="TextEncoding\NLangDetect\Profiles\tam" />
+ <None Include="TextEncoding\NLangDetect\Profiles\tel" />
+ <None Include="TextEncoding\NLangDetect\Profiles\tgl" />
+ <None Include="TextEncoding\NLangDetect\Profiles\tha" />
+ <None Include="TextEncoding\NLangDetect\Profiles\tur" />
+ <None Include="TextEncoding\NLangDetect\Profiles\ukr" />
+ <None Include="TextEncoding\NLangDetect\Profiles\urd" />
+ <None Include="TextEncoding\NLangDetect\Profiles\vie" />
+ <EmbeddedResource Include="TextEncoding\NLangDetect\Profiles\zh-cn" />
+ <EmbeddedResource Include="TextEncoding\NLangDetect\Profiles\zh-tw" />
+ <EmbeddedResource Include="TextEncoding\NLangDetect\Utils\messages.properties" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Localization\Ratings\au.txt" />
@@ -413,6 +848,9 @@
<ItemGroup>
<EmbeddedResource Include="Localization\Ratings\es.txt" />
</ItemGroup>
+ <ItemGroup>
+ <EmbeddedResource Include="Localization\Ratings\ro.txt" />
+ </ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
diff --git a/Emby.Server.Implementations/EntryPoints/AutomaticRestartEntryPoint.cs b/Emby.Server.Implementations/EntryPoints/AutomaticRestartEntryPoint.cs
index 561f5ee12..c2cee00c8 100644
--- a/Emby.Server.Implementations/EntryPoints/AutomaticRestartEntryPoint.cs
+++ b/Emby.Server.Implementations/EntryPoints/AutomaticRestartEntryPoint.cs
@@ -112,6 +112,7 @@ namespace Emby.Server.Implementations.EntryPoints
_appHost.HasPendingRestartChanged -= _appHost_HasPendingRestartChanged;
DisposeTimer();
+ GC.SuppressFinalize(this);
}
private void DisposeTimer()
diff --git a/Emby.Server.Core/EntryPoints/ExternalPortForwarding.cs b/Emby.Server.Implementations/EntryPoints/ExternalPortForwarding.cs
index 2c7e6a487..9b434d606 100644
--- a/Emby.Server.Core/EntryPoints/ExternalPortForwarding.cs
+++ b/Emby.Server.Implementations/EntryPoints/ExternalPortForwarding.cs
@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Globalization;
using System.Net;
+using System.Threading.Tasks;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller;
using MediaBrowser.Controller.Configuration;
@@ -11,9 +12,9 @@ using MediaBrowser.Model.Events;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Threading;
using Mono.Nat;
-using System.Threading.Tasks;
+using MediaBrowser.Model.Extensions;
-namespace Emby.Server.Core.EntryPoints
+namespace Emby.Server.Implementations.EntryPoints
{
public class ExternalPortForwarding : IServerEntryPoint
{
@@ -50,7 +51,7 @@ namespace Emby.Server.Core.EntryPoints
values.Add(config.EnableHttps.ToString());
values.Add(_appHost.EnableHttps.ToString());
- return string.Join("|", values.ToArray());
+ return string.Join("|", values.ToArray(values.Count));
}
void _config_ConfigurationUpdated(object sender, EventArgs e)
@@ -293,6 +294,7 @@ namespace Emby.Server.Core.EntryPoints
{
_disposed = true;
DisposeNat();
+ GC.SuppressFinalize(this);
}
private void DisposeNat()
diff --git a/Emby.Server.Implementations/EntryPoints/KeepServerAwake.cs b/Emby.Server.Implementations/EntryPoints/KeepServerAwake.cs
index 8ae85e390..221580681 100644
--- a/Emby.Server.Implementations/EntryPoints/KeepServerAwake.cs
+++ b/Emby.Server.Implementations/EntryPoints/KeepServerAwake.cs
@@ -60,6 +60,7 @@ namespace Emby.Server.Implementations.EntryPoints
_timer.Dispose();
_timer = null;
}
+ GC.SuppressFinalize(this);
}
}
}
diff --git a/Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs b/Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs
index 69a205dda..796d8cf48 100644
--- a/Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs
+++ b/Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs
@@ -367,15 +367,15 @@ namespace Emby.Server.Implementations.EntryPoints
return new LibraryUpdateInfo
{
- ItemsAdded = itemsAdded.SelectMany(i => TranslatePhysicalItemToUserLibrary(i, user)).Select(i => i.Id.ToString("N")).Distinct().ToList(),
+ ItemsAdded = itemsAdded.SelectMany(i => TranslatePhysicalItemToUserLibrary(i, user)).Select(i => i.Id.ToString("N")).Distinct().ToArray(),
- ItemsUpdated = itemsUpdated.SelectMany(i => TranslatePhysicalItemToUserLibrary(i, user)).Select(i => i.Id.ToString("N")).Distinct().ToList(),
+ ItemsUpdated = itemsUpdated.SelectMany(i => TranslatePhysicalItemToUserLibrary(i, user)).Select(i => i.Id.ToString("N")).Distinct().ToArray(),
- ItemsRemoved = itemsRemoved.SelectMany(i => TranslatePhysicalItemToUserLibrary(i, user, true)).Select(i => i.Id.ToString("N")).Distinct().ToList(),
+ ItemsRemoved = itemsRemoved.SelectMany(i => TranslatePhysicalItemToUserLibrary(i, user, true)).Select(i => i.Id.ToString("N")).Distinct().ToArray(),
- FoldersAddedTo = foldersAddedTo.SelectMany(i => TranslatePhysicalItemToUserLibrary(i, user)).Select(i => i.Id.ToString("N")).Distinct().ToList(),
+ FoldersAddedTo = foldersAddedTo.SelectMany(i => TranslatePhysicalItemToUserLibrary(i, user)).Select(i => i.Id.ToString("N")).Distinct().ToArray(),
- FoldersRemovedFrom = foldersRemovedFrom.SelectMany(i => TranslatePhysicalItemToUserLibrary(i, user)).Select(i => i.Id.ToString("N")).Distinct().ToList()
+ FoldersRemovedFrom = foldersRemovedFrom.SelectMany(i => TranslatePhysicalItemToUserLibrary(i, user)).Select(i => i.Id.ToString("N")).Distinct().ToArray()
};
}
@@ -426,6 +426,7 @@ namespace Emby.Server.Implementations.EntryPoints
public void Dispose()
{
Dispose(true);
+ GC.SuppressFinalize(this);
}
/// <summary>
diff --git a/Emby.Server.Implementations/EntryPoints/LoadRegistrations.cs b/Emby.Server.Implementations/EntryPoints/LoadRegistrations.cs
index 0203b5192..21e075cf5 100644
--- a/Emby.Server.Implementations/EntryPoints/LoadRegistrations.cs
+++ b/Emby.Server.Implementations/EntryPoints/LoadRegistrations.cs
@@ -68,6 +68,7 @@ namespace Emby.Server.Implementations.EntryPoints
_timer.Dispose();
_timer = null;
}
+ GC.SuppressFinalize(this);
}
}
}
diff --git a/Emby.Server.Implementations/EntryPoints/RecordingNotifier.cs b/Emby.Server.Implementations/EntryPoints/RecordingNotifier.cs
index b674fc39b..f73b40b46 100644
--- a/Emby.Server.Implementations/EntryPoints/RecordingNotifier.cs
+++ b/Emby.Server.Implementations/EntryPoints/RecordingNotifier.cs
@@ -72,6 +72,7 @@ namespace Emby.Server.Implementations.EntryPoints
_liveTvManager.SeriesTimerCancelled -= _liveTvManager_SeriesTimerCancelled;
_liveTvManager.TimerCreated -= _liveTvManager_TimerCreated;
_liveTvManager.SeriesTimerCreated -= _liveTvManager_SeriesTimerCreated;
+ GC.SuppressFinalize(this);
}
}
}
diff --git a/Emby.Server.Implementations/EntryPoints/RefreshUsersMetadata.cs b/Emby.Server.Implementations/EntryPoints/RefreshUsersMetadata.cs
index 77de849a1..13e14be36 100644
--- a/Emby.Server.Implementations/EntryPoints/RefreshUsersMetadata.cs
+++ b/Emby.Server.Implementations/EntryPoints/RefreshUsersMetadata.cs
@@ -1,4 +1,5 @@
-using MediaBrowser.Controller.Library;
+using System;
+using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Plugins;
using System.Threading;
@@ -36,6 +37,7 @@ namespace Emby.Server.Implementations.EntryPoints
/// </summary>
public void Dispose()
{
+ GC.SuppressFinalize(this);
}
}
}
diff --git a/Emby.Server.Implementations/EntryPoints/ServerEventNotifier.cs b/Emby.Server.Implementations/EntryPoints/ServerEventNotifier.cs
index 4d640bc95..514321e20 100644
--- a/Emby.Server.Implementations/EntryPoints/ServerEventNotifier.cs
+++ b/Emby.Server.Implementations/EntryPoints/ServerEventNotifier.cs
@@ -174,6 +174,7 @@ namespace Emby.Server.Implementations.EntryPoints
public void Dispose()
{
Dispose(true);
+ GC.SuppressFinalize(this);
}
/// <summary>
diff --git a/Emby.Server.Implementations/EntryPoints/StartupWizard.cs b/Emby.Server.Implementations/EntryPoints/StartupWizard.cs
index 424153f22..614c04fd2 100644
--- a/Emby.Server.Implementations/EntryPoints/StartupWizard.cs
+++ b/Emby.Server.Implementations/EntryPoints/StartupWizard.cs
@@ -1,4 +1,5 @@
-using Emby.Server.Implementations.Browser;
+using System;
+using Emby.Server.Implementations.Browser;
using MediaBrowser.Controller;
using MediaBrowser.Controller.Plugins;
using MediaBrowser.Model.Logging;
@@ -54,6 +55,7 @@ namespace Emby.Server.Implementations.EntryPoints
/// </summary>
public void Dispose()
{
+ GC.SuppressFinalize(this);
}
}
} \ No newline at end of file
diff --git a/Emby.Server.Implementations/EntryPoints/SystemEvents.cs b/Emby.Server.Implementations/EntryPoints/SystemEvents.cs
index 4ab6d32f3..aa63dae27 100644
--- a/Emby.Server.Implementations/EntryPoints/SystemEvents.cs
+++ b/Emby.Server.Implementations/EntryPoints/SystemEvents.cs
@@ -43,6 +43,7 @@ namespace Emby.Server.Implementations.EntryPoints
public void Dispose()
{
_systemEvents.SystemShutdown -= _systemEvents_SystemShutdown;
+ GC.SuppressFinalize(this);
}
}
}
diff --git a/Emby.Server.Implementations/EntryPoints/UdpServerEntryPoint.cs b/Emby.Server.Implementations/EntryPoints/UdpServerEntryPoint.cs
index df5a7c985..d04df0d2b 100644
--- a/Emby.Server.Implementations/EntryPoints/UdpServerEntryPoint.cs
+++ b/Emby.Server.Implementations/EntryPoints/UdpServerEntryPoint.cs
@@ -65,6 +65,7 @@ namespace Emby.Server.Implementations.EntryPoints
public void Dispose()
{
Dispose(true);
+ GC.SuppressFinalize(this);
}
/// <summary>
diff --git a/Emby.Server.Implementations/EntryPoints/UsageEntryPoint.cs b/Emby.Server.Implementations/EntryPoints/UsageEntryPoint.cs
index 9fbe06673..fb9402986 100644
--- a/Emby.Server.Implementations/EntryPoints/UsageEntryPoint.cs
+++ b/Emby.Server.Implementations/EntryPoints/UsageEntryPoint.cs
@@ -12,6 +12,7 @@ using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Controller;
using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Model.Extensions;
namespace Emby.Server.Implementations.EntryPoints
{
@@ -58,7 +59,7 @@ namespace Emby.Server.Implementations.EntryPoints
session.ApplicationVersion
};
- var key = string.Join("_", keys.ToArray()).GetMD5();
+ var key = string.Join("_", keys.ToArray(keys.Count)).GetMD5();
_apps.GetOrAdd(key, guid => GetNewClientInfo(session));
}
@@ -129,6 +130,7 @@ namespace Emby.Server.Implementations.EntryPoints
public void Dispose()
{
_sessionManager.SessionStarted -= _sessionManager_SessionStarted;
+ GC.SuppressFinalize(this);
}
}
}
diff --git a/Emby.Server.Implementations/EntryPoints/UserDataChangeNotifier.cs b/Emby.Server.Implementations/EntryPoints/UserDataChangeNotifier.cs
index 71e31d4d4..4a7182a43 100644
--- a/Emby.Server.Implementations/EntryPoints/UserDataChangeNotifier.cs
+++ b/Emby.Server.Implementations/EntryPoints/UserDataChangeNotifier.cs
@@ -126,7 +126,7 @@ namespace Emby.Server.Implementations.EntryPoints
dto.ItemId = i.Id.ToString("N");
return dto;
})
- .ToList();
+ .ToArray();
var info = new UserDataChangeInfo
{
@@ -160,6 +160,7 @@ namespace Emby.Server.Implementations.EntryPoints
}
_userDataManager.UserDataSaved -= _userDataManager_UserDataSaved;
+ GC.SuppressFinalize(this);
}
}
}
diff --git a/Emby.Common.Implementations/EnvironmentInfo/EnvironmentInfo.cs b/Emby.Server.Implementations/EnvironmentInfo/EnvironmentInfo.cs
index 89aa787b5..f86279f37 100644
--- a/Emby.Common.Implementations/EnvironmentInfo/EnvironmentInfo.cs
+++ b/Emby.Server.Implementations/EnvironmentInfo/EnvironmentInfo.cs
@@ -1,25 +1,21 @@
using System;
-using System.Collections.Generic;
using System.IO;
-using System.Linq;
-using System.Runtime.InteropServices;
-using System.Threading.Tasks;
using MediaBrowser.Model.System;
-namespace Emby.Common.Implementations.EnvironmentInfo
+namespace Emby.Server.Implementations.EnvironmentInfo
{
public class EnvironmentInfo : IEnvironmentInfo
{
- public Architecture? CustomArchitecture { get; set; }
- public MediaBrowser.Model.System.OperatingSystem? CustomOperatingSystem { get; set; }
+ private Architecture? _customArchitecture;
+ private MediaBrowser.Model.System.OperatingSystem? _customOperatingSystem;
public virtual MediaBrowser.Model.System.OperatingSystem OperatingSystem
{
get
{
- if (CustomOperatingSystem.HasValue)
+ if (_customOperatingSystem.HasValue)
{
- return CustomOperatingSystem.Value;
+ return _customOperatingSystem.Value;
}
switch (Environment.OSVersion.Platform)
@@ -34,6 +30,10 @@ namespace Emby.Common.Implementations.EnvironmentInfo
return MediaBrowser.Model.System.OperatingSystem.Windows;
}
+ set
+ {
+ _customOperatingSystem = value;
+ }
}
public string OperatingSystemName
@@ -64,13 +64,17 @@ namespace Emby.Common.Implementations.EnvironmentInfo
{
get
{
- if (CustomArchitecture.HasValue)
+ if (_customArchitecture.HasValue)
{
- return CustomArchitecture.Value;
+ return _customArchitecture.Value;
}
return Environment.Is64BitOperatingSystem ? MediaBrowser.Model.System.Architecture.X64 : MediaBrowser.Model.System.Architecture.X86;
}
+ set
+ {
+ _customArchitecture = value;
+ }
}
public string GetEnvironmentVariable(string name)
diff --git a/Emby.Common.Implementations/HttpClientManager/HttpClientInfo.cs b/Emby.Server.Implementations/HttpClientManager/HttpClientInfo.cs
index ca481b33e..6d17bf94d 100644
--- a/Emby.Common.Implementations/HttpClientManager/HttpClientInfo.cs
+++ b/Emby.Server.Implementations/HttpClientManager/HttpClientInfo.cs
@@ -1,6 +1,6 @@
using System;
-namespace Emby.Common.Implementations.HttpClientManager
+namespace Emby.Server.Implementations.HttpClientManager
{
/// <summary>
/// Class HttpClientInfo
diff --git a/Emby.Common.Implementations/HttpClientManager/HttpClientManager.cs b/Emby.Server.Implementations/HttpClientManager/HttpClientManager.cs
index 700d04c4d..fe545ecff 100644
--- a/Emby.Common.Implementations/HttpClientManager/HttpClientManager.cs
+++ b/Emby.Server.Implementations/HttpClientManager/HttpClientManager.cs
@@ -1,26 +1,23 @@
-using System.Net.Sockets;
-using MediaBrowser.Common.Configuration;
-using MediaBrowser.Common.Extensions;
-using MediaBrowser.Common.Net;
-using MediaBrowser.Model.Logging;
-using MediaBrowser.Model.Net;
-using System;
+using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
-using System.Collections.Specialized;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
+using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
-using Emby.Common.Implementations.HttpClientManager;
-using Emby.Common.Implementations.IO;
+using Emby.Server.Implementations.IO;
+using MediaBrowser.Common.Configuration;
+using MediaBrowser.Common.Extensions;
+using MediaBrowser.Common.Net;
using MediaBrowser.Model.IO;
-using MediaBrowser.Common;
+using MediaBrowser.Model.Logging;
+using MediaBrowser.Model.Net;
-namespace Emby.Common.Implementations.HttpClientManager
+namespace Emby.Server.Implementations.HttpClientManager
{
/// <summary>
/// Class HttpClientManager
@@ -69,8 +66,10 @@ namespace Emby.Common.Implementations.HttpClientManager
// http://stackoverflow.com/questions/566437/http-post-returns-the-error-417-expectation-failed-c
ServicePointManager.Expect100Continue = false;
- // Trakt requests sometimes fail without this
+#if NET46
+// Trakt requests sometimes fail without this
ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls;
+#endif
}
/// <summary>
@@ -431,7 +430,7 @@ namespace Emby.Common.Implementations.HttpClientManager
try
{
var bytes = options.RequestContentBytes ??
- Encoding.UTF8.GetBytes(options.RequestContent ?? string.Empty);
+ Encoding.UTF8.GetBytes(options.RequestContent ?? string.Empty);
httpWebRequest.ContentType = options.RequestContentType ?? "application/x-www-form-urlencoded";
@@ -730,7 +729,7 @@ namespace Emby.Common.Implementations.HttpClientManager
}
var webException = ex as WebException
- ?? ex.InnerException as WebException;
+ ?? ex.InnerException as WebException;
if (webException != null)
{
@@ -765,7 +764,7 @@ namespace Emby.Common.Implementations.HttpClientManager
}
var operationCanceledException = ex as OperationCanceledException
- ?? ex.InnerException as OperationCanceledException;
+ ?? ex.InnerException as OperationCanceledException;
if (operationCanceledException != null)
{
@@ -824,27 +823,6 @@ namespace Emby.Common.Implementations.HttpClientManager
}
/// <summary>
- /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
- /// </summary>
- public void Dispose()
- {
- Dispose(true);
- GC.SuppressFinalize(this);
- }
-
- /// <summary>
- /// Releases unmanaged and - optionally - managed resources.
- /// </summary>
- /// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
- protected virtual void Dispose(bool dispose)
- {
- if (dispose)
- {
- _httpClients.Clear();
- }
- }
-
- /// <summary>
/// Throws the cancellation exception.
/// </summary>
/// <param name="options">The options.</param>
diff --git a/Emby.Server.Implementations/HttpServer/FileWriter.cs b/Emby.Server.Implementations/HttpServer/FileWriter.cs
index 8cb7b5dbf..aa679e1b9 100644
--- a/Emby.Server.Implementations/HttpServer/FileWriter.cs
+++ b/Emby.Server.Implementations/HttpServer/FileWriter.cs
@@ -160,6 +160,9 @@ namespace Emby.Server.Implementations.HttpServer
if (string.IsNullOrWhiteSpace(RangeHeader) || (RangeStart <= 0 && RangeEnd >= TotalContentLength - 1))
{
Logger.Info("Transmit file {0}", Path);
+
+ //var count = FileShare == FileShareMode.ReadWrite ? TotalContentLength : 0;
+
await response.TransmitFile(Path, 0, 0, FileShare, cancellationToken).ConfigureAwait(false);
return;
}
diff --git a/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs b/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs
index 05f78eba9..86df798d0 100644
--- a/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs
+++ b/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs
@@ -7,10 +7,10 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
+using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
-using Emby.Server.Implementations.HttpServer;
using Emby.Server.Implementations.HttpServer.SocketSharp;
using Emby.Server.Implementations.Services;
using MediaBrowser.Common.Net;
@@ -24,8 +24,6 @@ using MediaBrowser.Model.Serialization;
using MediaBrowser.Model.Services;
using MediaBrowser.Model.System;
using MediaBrowser.Model.Text;
-using SocketHttpListener.Net;
-using SocketHttpListener.Primitives;
namespace Emby.Server.Implementations.HttpServer
{
@@ -34,7 +32,7 @@ namespace Emby.Server.Implementations.HttpServer
private string DefaultRedirectPath { get; set; }
private readonly ILogger _logger;
- public IEnumerable<string> UrlPrefixes { get; private set; }
+ public string[] UrlPrefixes { get; private set; }
private readonly List<IService> _restServices = new List<IService>();
@@ -56,14 +54,13 @@ namespace Emby.Server.Implementations.HttpServer
private readonly IFileSystem _fileSystem;
private readonly IJsonSerializer _jsonSerializer;
private readonly IXmlSerializer _xmlSerializer;
- private readonly ICertificate _certificate;
+ private readonly X509Certificate _certificate;
private readonly IEnvironmentInfo _environment;
- private readonly IStreamFactory _streamFactory;
private readonly Func<Type, Func<string, object>> _funcParseFn;
private readonly bool _enableDualModeSockets;
- public List<Action<IRequest, IResponse, object>> RequestFilters { get; set; }
- public List<Action<IRequest, IResponse, object>> ResponseFilters { get; set; }
+ public Action<IRequest, IResponse, object>[] RequestFilters { get; set; }
+ public Action<IRequest, IResponse, object>[] ResponseFilters { get; set; }
private readonly Dictionary<Type, Type> ServiceOperationsMap = new Dictionary<Type, Type>();
public static HttpListenerHost Instance { get; protected set; }
@@ -72,7 +69,7 @@ namespace Emby.Server.Implementations.HttpServer
ILogger logger,
IServerConfigurationManager config,
string serviceName,
- string defaultRedirectPath, INetworkManager networkManager, IMemoryStreamFactory memoryStreamProvider, ITextEncoding textEncoding, ISocketFactory socketFactory, ICryptoProvider cryptoProvider, IJsonSerializer jsonSerializer, IXmlSerializer xmlSerializer, IEnvironmentInfo environment, ICertificate certificate, IStreamFactory streamFactory, Func<Type, Func<string, object>> funcParseFn, bool enableDualModeSockets, IFileSystem fileSystem)
+ string defaultRedirectPath, INetworkManager networkManager, IMemoryStreamFactory memoryStreamProvider, ITextEncoding textEncoding, ISocketFactory socketFactory, ICryptoProvider cryptoProvider, IJsonSerializer jsonSerializer, IXmlSerializer xmlSerializer, IEnvironmentInfo environment, X509Certificate certificate, Func<Type, Func<string, object>> funcParseFn, bool enableDualModeSockets, IFileSystem fileSystem)
{
Instance = this;
@@ -87,7 +84,6 @@ namespace Emby.Server.Implementations.HttpServer
_xmlSerializer = xmlSerializer;
_environment = environment;
_certificate = certificate;
- _streamFactory = streamFactory;
_funcParseFn = funcParseFn;
_enableDualModeSockets = enableDualModeSockets;
_fileSystem = fileSystem;
@@ -95,8 +91,8 @@ namespace Emby.Server.Implementations.HttpServer
_logger = logger;
- RequestFilters = new List<Action<IRequest, IResponse, object>>();
- ResponseFilters = new List<Action<IRequest, IResponse, object>>();
+ RequestFilters = new Action<IRequest, IResponse, object>[] { };
+ ResponseFilters = new Action<IRequest, IResponse, object>[] { };
}
public string GlobalResponse { get; set; }
@@ -125,13 +121,6 @@ namespace Emby.Server.Implementations.HttpServer
return _appHost.CreateInstance(type);
}
- private ServiceController CreateServiceController()
- {
- var types = _restServices.Select(r => r.GetType()).ToArray();
-
- return new ServiceController(() => types);
- }
-
/// <summary>
/// Applies the request filters. Returns whether or not the request has been handled
/// and no more processing should be done.
@@ -142,7 +131,9 @@ namespace Emby.Server.Implementations.HttpServer
//Exec all RequestFilter attributes with Priority < 0
var attributes = GetRequestFilterAttributes(requestDto.GetType());
var i = 0;
- for (; i < attributes.Length && attributes[i].Priority < 0; i++)
+ var count = attributes.Count;
+
+ for (; i < count && attributes[i].Priority < 0; i++)
{
var attribute = attributes[i];
attribute.RequestFilter(req, res, requestDto);
@@ -155,7 +146,7 @@ namespace Emby.Server.Implementations.HttpServer
}
//Exec remaining RequestFilter attributes with Priority >= 0
- for (; i < attributes.Length && attributes[i].Priority >= 0; i++)
+ for (; i < count && attributes[i].Priority >= 0; i++)
{
var attribute = attributes[i];
attribute.RequestFilter(req, res, requestDto);
@@ -169,12 +160,12 @@ namespace Emby.Server.Implementations.HttpServer
return serviceType;
}
- public void AddServiceInfo(Type serviceType, Type requestType, Type responseType)
+ public void AddServiceInfo(Type serviceType, Type requestType)
{
ServiceOperationsMap[requestType] = serviceType;
}
- private IHasRequestFilter[] GetRequestFilterAttributes(Type requestDtoType)
+ private List<IHasRequestFilter> GetRequestFilterAttributes(Type requestDtoType)
{
var attributes = requestDtoType.GetTypeInfo().GetCustomAttributes(true).OfType<IHasRequestFilter>().ToList();
@@ -186,40 +177,13 @@ namespace Emby.Server.Implementations.HttpServer
attributes.Sort((x, y) => x.Priority - y.Priority);
- return attributes.ToArray();
- }
-
- /// <summary>
- /// Starts the Web Service
- /// </summary>
- private void StartListener()
- {
- WebSocketSharpRequest.HandlerFactoryPath = GetHandlerPathIfAny(UrlPrefixes.First());
-
- _listener = GetListener();
-
- _listener.WebSocketConnected = OnWebSocketConnected;
- _listener.WebSocketConnecting = OnWebSocketConnecting;
- _listener.ErrorHandler = ErrorHandler;
- _listener.RequestHandler = RequestHandler;
-
- _listener.Start(UrlPrefixes);
- }
-
- public static string GetHandlerPathIfAny(string listenerUrl)
- {
- if (listenerUrl == null) return null;
- var pos = listenerUrl.IndexOf("://", StringComparison.OrdinalIgnoreCase);
- if (pos == -1) return null;
- var startHostUrl = listenerUrl.Substring(pos + "://".Length);
- var endPos = startHostUrl.IndexOf('/');
- if (endPos == -1) return null;
- var endHostUrl = startHostUrl.Substring(endPos + 1);
- return string.IsNullOrEmpty(endHostUrl) ? null : endHostUrl.TrimEnd('/');
+ return attributes;
}
private IHttpListener GetListener()
{
+ //return new KestrelHost.KestrelListener(_logger, _environment, _fileSystem);
+
return new WebSocketSharpListener(_logger,
_certificate,
_memoryStreamProvider,
@@ -227,22 +191,11 @@ namespace Emby.Server.Implementations.HttpServer
_networkManager,
_socketFactory,
_cryptoProvider,
- _streamFactory,
_enableDualModeSockets,
- GetRequest,
_fileSystem,
_environment);
}
- private IHttpRequest GetRequest(HttpListenerContext httpContext)
- {
- var operationName = httpContext.Request.GetOperationName();
-
- var req = new WebSocketSharpRequest(httpContext, operationName, _logger, _memoryStreamProvider);
-
- return req;
- }
-
private void OnWebSocketConnecting(WebSocketConnectingEventArgs args)
{
if (_disposed)
@@ -355,7 +308,8 @@ namespace Emby.Server.Implementations.HttpServer
if (_listener != null)
{
_logger.Info("Stopping HttpListener...");
- _listener.Stop();
+ var task = _listener.Stop();
+ Task.WaitAll(task);
_logger.Info("HttpListener stopped");
}
}
@@ -441,7 +395,7 @@ namespace Emby.Server.Implementations.HttpServer
return address.Trim('/');
}
- private bool ValidateHost(Uri url)
+ private bool ValidateHost(string host)
{
var hosts = _config
.Configuration
@@ -454,7 +408,7 @@ namespace Emby.Server.Implementations.HttpServer
return true;
}
- var host = url.Host ?? string.Empty;
+ host = host ?? string.Empty;
_logger.Debug("Validating host {0}", host);
@@ -472,7 +426,7 @@ namespace Emby.Server.Implementations.HttpServer
/// <summary>
/// Overridable method that can be used to implement a custom hnandler
/// </summary>
- protected async Task RequestHandler(IHttpRequest httpReq, Uri url, CancellationToken cancellationToken)
+ protected async Task RequestHandler(IHttpRequest httpReq, string urlString, string host, string localPath, CancellationToken cancellationToken)
{
var date = DateTime.Now;
var httpRes = httpReq.Response;
@@ -491,7 +445,7 @@ namespace Emby.Server.Implementations.HttpServer
return;
}
- if (!ValidateHost(url))
+ if (!ValidateHost(host))
{
httpRes.StatusCode = 400;
httpRes.ContentType = "text/plain";
@@ -511,9 +465,7 @@ namespace Emby.Server.Implementations.HttpServer
}
var operationName = httpReq.OperationName;
- var localPath = url.LocalPath;
- var urlString = url.OriginalString;
enableLog = EnableLogging(urlString, localPath);
urlToLog = urlString;
logHeaders = enableLog && urlToLog.IndexOf("/videos/", StringComparison.OrdinalIgnoreCase) != -1;
@@ -697,19 +649,26 @@ namespace Emby.Server.Implementations.HttpServer
{
_restServices.AddRange(services);
- ServiceController = CreateServiceController();
+ ServiceController = new ServiceController();
_logger.Info("Calling ServiceStack AppHost.Init");
- ServiceController.Init(this);
+ var types = _restServices.Select(r => r.GetType()).ToArray();
+
+ ServiceController.Init(this, types);
- var requestFilters = _appHost.GetExports<IRequestFilter>().ToList();
- foreach (var filter in requestFilters)
+ var list = new List<Action<IRequest, IResponse, object>>();
+ foreach (var filter in _appHost.GetExports<IRequestFilter>())
{
- RequestFilters.Add(filter.Filter);
+ list.Add(filter.Filter);
}
- ResponseFilters.Add(new ResponseFilter(_logger).FilterResponse);
+ RequestFilters = list.ToArray();
+
+ ResponseFilters = new Action<IRequest, IResponse, object>[]
+ {
+ new ResponseFilter(_logger).FilterResponse
+ };
}
public RouteAttribute[] GetRouteAttributes(Type requestType)
@@ -726,22 +685,22 @@ namespace Emby.Server.Implementations.HttpServer
Summary = route.Summary
});
- routes.Add(new RouteAttribute(NormalizeRoutePath(route.Path), route.Verbs)
+ routes.Add(new RouteAttribute(NormalizeMediaBrowserRoutePath(route.Path), route.Verbs)
{
Notes = route.Notes,
Priority = route.Priority,
Summary = route.Summary
});
- routes.Add(new RouteAttribute(DoubleNormalizeEmbyRoutePath(route.Path), route.Verbs)
- {
- Notes = route.Notes,
- Priority = route.Priority,
- Summary = route.Summary
- });
+ //routes.Add(new RouteAttribute(DoubleNormalizeEmbyRoutePath(route.Path), route.Verbs)
+ //{
+ // Notes = route.Notes,
+ // Priority = route.Priority,
+ // Summary = route.Summary
+ //});
}
- return routes.ToArray();
+ return routes.ToArray(routes.Count);
}
public Func<string, object> GetParseFn(Type propertyType)
@@ -779,24 +738,24 @@ namespace Emby.Server.Implementations.HttpServer
return "emby/" + path;
}
- private string DoubleNormalizeEmbyRoutePath(string path)
+ private string NormalizeMediaBrowserRoutePath(string path)
{
if (path.StartsWith("/", StringComparison.OrdinalIgnoreCase))
{
- return "/emby/emby" + path;
+ return "/mediabrowser" + path;
}
- return "emby/emby/" + path;
+ return "mediabrowser/" + path;
}
- private string NormalizeRoutePath(string path)
+ private string DoubleNormalizeEmbyRoutePath(string path)
{
if (path.StartsWith("/", StringComparison.OrdinalIgnoreCase))
{
- return "/mediabrowser" + path;
+ return "/emby/emby" + path;
}
- return "mediabrowser/" + path;
+ return "emby/emby/" + path;
}
private bool _disposed;
@@ -824,10 +783,18 @@ namespace Emby.Server.Implementations.HttpServer
GC.SuppressFinalize(this);
}
- public void StartServer(IEnumerable<string> urlPrefixes)
+ public void StartServer(string[] urlPrefixes)
{
- UrlPrefixes = urlPrefixes.ToList();
- StartListener();
+ UrlPrefixes = urlPrefixes;
+
+ _listener = GetListener();
+
+ _listener.WebSocketConnected = OnWebSocketConnected;
+ _listener.WebSocketConnecting = OnWebSocketConnecting;
+ _listener.ErrorHandler = ErrorHandler;
+ _listener.RequestHandler = RequestHandler;
+
+ _listener.Start(UrlPrefixes);
}
}
} \ No newline at end of file
diff --git a/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs b/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs
index 396bd8e88..f5a1fe246 100644
--- a/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs
+++ b/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs
@@ -6,19 +6,16 @@ using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
-using System.IO.Compression;
using System.Net;
using System.Runtime.Serialization;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
-using Emby.Server.Implementations.HttpServer;
using Emby.Server.Implementations.Services;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Services;
using IRequest = MediaBrowser.Model.Services.IRequest;
using MimeTypes = MediaBrowser.Model.Net.MimeTypes;
-using StreamWriter = Emby.Server.Implementations.HttpServer.StreamWriter;
namespace Emby.Server.Implementations.HttpServer
{
@@ -193,50 +190,37 @@ namespace Emby.Server.Implementations.HttpServer
/// <returns></returns>
public object ToOptimizedResult<T>(IRequest request, T dto)
{
- var compressionType = GetCompressionType(request);
- if (compressionType == null)
- {
- var contentType = request.ResponseContentType;
+ var contentType = request.ResponseContentType;
- switch (GetRealContentType(contentType))
- {
- case "application/xml":
- case "text/xml":
- case "text/xml; charset=utf-8": //"text/xml; charset=utf-8" also matches xml
- return SerializeToXmlString(dto);
-
- case "application/json":
- case "text/json":
- return _jsonSerializer.SerializeToString(dto);
- }
- }
-
- // Do not use the memoryStreamFactory here, they don't place nice with compression
- using (var ms = new MemoryStream())
+ switch (GetRealContentType(contentType))
{
- var contentType = request.ResponseContentType;
- var writerFn = RequestHelper.GetResponseWriter(HttpListenerHost.Instance, contentType);
+ case "application/xml":
+ case "text/xml":
+ case "text/xml; charset=utf-8": //"text/xml; charset=utf-8" also matches xml
+ return SerializeToXmlString(dto);
- writerFn(dto, ms);
+ case "application/json":
+ case "text/json":
+ return _jsonSerializer.SerializeToString(dto);
+ default:
+ {
+ var ms = new MemoryStream();
+ var writerFn = RequestHelper.GetResponseWriter(HttpListenerHost.Instance, contentType);
- ms.Position = 0;
+ writerFn(dto, ms);
+
+ ms.Position = 0;
- var responseHeaders = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
+ if (string.Equals(request.Verb, "head", StringComparison.OrdinalIgnoreCase))
+ {
+ return GetHttpResult(new byte[] { }, contentType, true);
+ }
- return GetCompressedResult(ms, compressionType, responseHeaders, false, request.ResponseContentType).Result;
+ return GetHttpResult(ms, contentType, true);
+ }
}
}
- private static Stream GetCompressionStream(Stream outputStream, string compressionType)
- {
- if (compressionType == "deflate")
- return new DeflateStream(outputStream, CompressionMode.Compress, true);
- if (compressionType == "gzip")
- return new GZipStream(outputStream, CompressionMode.Compress, true);
-
- throw new NotSupportedException(compressionType);
- }
-
public static string GetRealContentType(string contentType)
{
return contentType == null
@@ -440,11 +424,14 @@ namespace Emby.Server.Implementations.HttpServer
options.ResponseHeaders = options.ResponseHeaders ?? new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
- // Quotes are valid in linux. They'll possibly cause issues here
- var filename = (Path.GetFileName(path) ?? string.Empty).Replace("\"", string.Empty);
- if (!string.IsNullOrWhiteSpace(filename))
+ if (!options.ResponseHeaders.ContainsKey("Content-Disposition"))
{
- options.ResponseHeaders["Content-Disposition"] = "inline; filename=\"" + filename + "\"";
+ // Quotes are valid in linux. They'll possibly cause issues here
+ var filename = (Path.GetFileName(path) ?? string.Empty).Replace("\"", string.Empty);
+ if (!string.IsNullOrWhiteSpace(filename))
+ {
+ options.ResponseHeaders["Content-Disposition"] = "inline; filename=\"" + filename + "\"";
+ }
}
return GetStaticResult(requestContext, options);
@@ -503,190 +490,67 @@ namespace Emby.Server.Implementations.HttpServer
return result;
}
- var compress = ShouldCompressResponse(requestContext, contentType);
- var hasHeaders = await GetStaticResult(requestContext, options, compress).ConfigureAwait(false);
- AddResponseHeaders(hasHeaders, options.ResponseHeaders);
-
- return hasHeaders;
- }
-
- /// <summary>
- /// Shoulds the compress response.
- /// </summary>
- /// <param name="requestContext">The request context.</param>
- /// <param name="contentType">Type of the content.</param>
- /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
- private bool ShouldCompressResponse(IRequest requestContext, string contentType)
- {
- // It will take some work to support compression with byte range requests
- if (!string.IsNullOrWhiteSpace(requestContext.Headers.Get("Range")))
- {
- return false;
- }
-
- // Don't compress media
- if (contentType.StartsWith("audio/", StringComparison.OrdinalIgnoreCase) || contentType.StartsWith("video/", StringComparison.OrdinalIgnoreCase))
- {
- return false;
- }
-
- // Don't compress images
- if (contentType.StartsWith("image/", StringComparison.OrdinalIgnoreCase))
- {
- return false;
- }
-
- if (contentType.StartsWith("font/", StringComparison.OrdinalIgnoreCase))
- {
- return false;
- }
- if (contentType.StartsWith("application/", StringComparison.OrdinalIgnoreCase))
- {
- if (string.Equals(contentType, "application/x-javascript", StringComparison.OrdinalIgnoreCase))
- {
- return true;
- }
- if (string.Equals(contentType, "application/xml", StringComparison.OrdinalIgnoreCase))
- {
- return true;
- }
- return false;
- }
-
- return true;
- }
-
- /// <summary>
- /// The us culture
- /// </summary>
- private static readonly CultureInfo UsCulture = new CultureInfo("en-US");
-
- private async Task<IHasHeaders> GetStaticResult(IRequest requestContext, StaticResultOptions options, bool compress)
- {
var isHeadRequest = options.IsHeadRequest;
var factoryFn = options.ContentFactory;
- var contentType = options.ContentType;
var responseHeaders = options.ResponseHeaders;
- var requestedCompressionType = GetCompressionType(requestContext);
-
- if (!compress || string.IsNullOrEmpty(requestedCompressionType))
- {
- var rangeHeader = requestContext.Headers.Get("Range");
-
- if (!isHeadRequest && !string.IsNullOrWhiteSpace(options.Path))
- {
- return new FileWriter(options.Path, contentType, rangeHeader, _logger, _fileSystem)
- {
- OnComplete = options.OnComplete,
- OnError = options.OnError,
- FileShare = options.FileShare
- };
- }
+ //var requestedCompressionType = GetCompressionType(requestContext);
- if (!string.IsNullOrWhiteSpace(rangeHeader))
- {
- var stream = await factoryFn().ConfigureAwait(false);
+ var rangeHeader = requestContext.Headers.Get("Range");
- return new RangeRequestWriter(rangeHeader, stream, contentType, isHeadRequest, _logger)
- {
- OnComplete = options.OnComplete
- };
- }
- else
+ if (!isHeadRequest && !string.IsNullOrWhiteSpace(options.Path))
+ {
+ var hasHeaders = new FileWriter(options.Path, contentType, rangeHeader, _logger, _fileSystem)
{
- var stream = await factoryFn().ConfigureAwait(false);
-
- responseHeaders["Content-Length"] = stream.Length.ToString(UsCulture);
-
- if (isHeadRequest)
- {
- stream.Dispose();
-
- return GetHttpResult(new byte[] { }, contentType, true);
- }
+ OnComplete = options.OnComplete,
+ OnError = options.OnError,
+ FileShare = options.FileShare
+ };
- return new StreamWriter(stream, contentType, _logger)
- {
- OnComplete = options.OnComplete,
- OnError = options.OnError
- };
- }
+ AddResponseHeaders(hasHeaders, options.ResponseHeaders);
+ return hasHeaders;
}
- using (var stream = await factoryFn().ConfigureAwait(false))
+ if (!string.IsNullOrWhiteSpace(rangeHeader))
{
- return await GetCompressedResult(stream, requestedCompressionType, responseHeaders, isHeadRequest, contentType).ConfigureAwait(false);
- }
- }
+ var stream = await factoryFn().ConfigureAwait(false);
- private async Task<IHasHeaders> GetCompressedResult(Stream stream,
- string requestedCompressionType,
- IDictionary<string, string> responseHeaders,
- bool isHeadRequest,
- string contentType)
- {
- using (var reader = new MemoryStream())
- {
- await stream.CopyToAsync(reader).ConfigureAwait(false);
-
- reader.Position = 0;
- var content = reader.ToArray();
-
- if (content.Length >= 1024)
+ var hasHeaders = new RangeRequestWriter(rangeHeader, stream, contentType, isHeadRequest, _logger)
{
- content = Compress(content, requestedCompressionType);
- responseHeaders["Content-Encoding"] = requestedCompressionType;
- }
+ OnComplete = options.OnComplete
+ };
- responseHeaders["Vary"] = "Accept-Encoding";
- responseHeaders["Content-Length"] = content.Length.ToString(UsCulture);
+ AddResponseHeaders(hasHeaders, options.ResponseHeaders);
+ return hasHeaders;
+ }
+ else
+ {
+ var stream = await factoryFn().ConfigureAwait(false);
+
+ responseHeaders["Content-Length"] = stream.Length.ToString(UsCulture);
if (isHeadRequest)
{
+ stream.Dispose();
+
return GetHttpResult(new byte[] { }, contentType, true);
}
- return GetHttpResult(content, contentType, true, responseHeaders);
- }
- }
-
- private byte[] Compress(byte[] bytes, string compressionType)
- {
- if (compressionType == "deflate")
- return Deflate(bytes);
-
- if (compressionType == "gzip")
- return GZip(bytes);
-
- throw new NotSupportedException(compressionType);
- }
-
- private byte[] Deflate(byte[] bytes)
- {
- // In .NET FX incompat-ville, you can't access compressed bytes without closing DeflateStream
- // Which means we must use MemoryStream since you have to use ToArray() on a closed Stream
- using (var ms = new MemoryStream())
- using (var zipStream = new DeflateStream(ms, CompressionMode.Compress))
- {
- zipStream.Write(bytes, 0, bytes.Length);
- zipStream.Dispose();
+ var hasHeaders = new StreamWriter(stream, contentType, _logger)
+ {
+ OnComplete = options.OnComplete,
+ OnError = options.OnError
+ };
- return ms.ToArray();
+ AddResponseHeaders(hasHeaders, options.ResponseHeaders);
+ return hasHeaders;
}
}
- private byte[] GZip(byte[] buffer)
- {
- using (var ms = new MemoryStream())
- using (var zipStream = new GZipStream(ms, CompressionMode.Compress))
- {
- zipStream.Write(buffer, 0, buffer.Length);
- zipStream.Dispose();
-
- return ms.ToArray();
- }
- }
+ /// <summary>
+ /// The us culture
+ /// </summary>
+ private static readonly CultureInfo UsCulture = new CultureInfo("en-US");
/// <summary>
/// Adds the caching responseHeaders.
diff --git a/Emby.Server.Implementations/HttpServer/IHttpListener.cs b/Emby.Server.Implementations/HttpServer/IHttpListener.cs
index 82175dbed..9feb2311d 100644
--- a/Emby.Server.Implementations/HttpServer/IHttpListener.cs
+++ b/Emby.Server.Implementations/HttpServer/IHttpListener.cs
@@ -19,7 +19,7 @@ namespace Emby.Server.Implementations.HttpServer
/// Gets or sets the request handler.
/// </summary>
/// <value>The request handler.</value>
- Func<IHttpRequest, Uri, CancellationToken, Task> RequestHandler { get; set; }
+ Func<IHttpRequest, string, string, string, CancellationToken, Task> RequestHandler { get; set; }
/// <summary>
/// Gets or sets the web socket handler.
@@ -42,6 +42,6 @@ namespace Emby.Server.Implementations.HttpServer
/// <summary>
/// Stops this instance.
/// </summary>
- void Stop();
+ Task Stop();
}
}
diff --git a/Emby.Server.Implementations/HttpServer/LoggerUtils.cs b/Emby.Server.Implementations/HttpServer/LoggerUtils.cs
index f0e75eea4..46bb4c7f9 100644
--- a/Emby.Server.Implementations/HttpServer/LoggerUtils.cs
+++ b/Emby.Server.Implementations/HttpServer/LoggerUtils.cs
@@ -1,7 +1,6 @@
using MediaBrowser.Model.Logging;
using System;
using System.Globalization;
-using System.Linq;
using MediaBrowser.Model.Services;
using SocketHttpListener.Net;
@@ -29,7 +28,20 @@ namespace Emby.Server.Implementations.HttpServer
}
else
{
- var headerText = string.Join(", ", headers.Select(i => i.Name + "=" + i.Value).ToArray());
+ var headerText = string.Empty;
+ var index = 0;
+
+ foreach (var i in headers)
+ {
+ if (index > 0)
+ {
+ headerText += ", ";
+ }
+
+ headerText += i.Name + "=" + i.Value;
+
+ index++;
+ }
logger.Info("HTTP {0} {1}. {2}", method, url, headerText);
}
@@ -48,7 +60,8 @@ namespace Emby.Server.Implementations.HttpServer
var durationMs = duration.TotalMilliseconds;
var logSuffix = durationMs >= 1000 && durationMs < 60000 ? "ms (slow)" : "ms";
- var headerText = headers == null ? string.Empty : "Headers: " + string.Join(", ", headers.Where(i => i.Name.IndexOf("Access-", StringComparison.OrdinalIgnoreCase) == -1).Select(i => i.Name + "=" + i.Value).ToArray());
+ //var headerText = headers == null ? string.Empty : "Headers: " + string.Join(", ", headers.Where(i => i.Name.IndexOf("Access-", StringComparison.OrdinalIgnoreCase) == -1).Select(i => i.Name + "=" + i.Value).ToArray());
+ var headerText = string.Empty;
logger.Info("HTTP Response {0} to {1}. Time: {2}{3}. {4} {5}", statusCode, endPoint, Convert.ToInt32(durationMs).ToString(CultureInfo.InvariantCulture), logSuffix, url, headerText);
}
}
diff --git a/Emby.Server.Implementations/HttpServer/Security/AuthService.cs b/Emby.Server.Implementations/HttpServer/Security/AuthService.cs
index 4d00c9b19..fadab4482 100644
--- a/Emby.Server.Implementations/HttpServer/Security/AuthService.cs
+++ b/Emby.Server.Implementations/HttpServer/Security/AuthService.cs
@@ -7,8 +7,8 @@ using MediaBrowser.Controller.Net;
using MediaBrowser.Controller.Security;
using MediaBrowser.Controller.Session;
using System;
-using System.Collections.Generic;
using System.Linq;
+using MediaBrowser.Model.Services;
namespace Emby.Server.Implementations.HttpServer.Security
{
@@ -38,19 +38,19 @@ namespace Emby.Server.Implementations.HttpServer.Security
/// </summary>
public string HtmlRedirect { get; set; }
- public void Authenticate(IServiceRequest request,
+ public void Authenticate(IRequest request,
IAuthenticationAttributes authAttribtues)
{
ValidateUser(request, authAttribtues);
}
- private void ValidateUser(IServiceRequest request,
+ private void ValidateUser(IRequest request,
IAuthenticationAttributes authAttribtues)
{
// This code is executed before the service
var auth = AuthorizationContext.GetAuthorizationInfo(request);
- if (!IsExemptFromAuthenticationToken(auth, authAttribtues))
+ if (!IsExemptFromAuthenticationToken(auth, authAttribtues, request))
{
var valid = IsValidConnectKey(auth.Token);
@@ -76,9 +76,9 @@ namespace Emby.Server.Implementations.HttpServer.Security
var info = GetTokenInfo(request);
- if (!IsExemptFromRoles(auth, authAttribtues, info))
+ if (!IsExemptFromRoles(auth, authAttribtues, request, info))
{
- var roles = authAttribtues.GetRoles().ToList();
+ var roles = authAttribtues.GetRoles();
ValidateRoles(roles, user);
}
@@ -96,7 +96,7 @@ namespace Emby.Server.Implementations.HttpServer.Security
}
}
- private void ValidateUserAccess(User user, IServiceRequest request,
+ private void ValidateUserAccess(User user, IRequest request,
IAuthenticationAttributes authAttribtues,
AuthorizationInfo auth)
{
@@ -112,7 +112,7 @@ namespace Emby.Server.Implementations.HttpServer.Security
!authAttribtues.EscapeParentalControl &&
!user.IsParentalScheduleAllowed())
{
- request.AddResponseHeader("X-Application-Error-Code", "ParentalControl");
+ request.Response.AddHeader("X-Application-Error-Code", "ParentalControl");
throw new SecurityException("This user account is not allowed access at this time.")
{
@@ -132,23 +132,33 @@ namespace Emby.Server.Implementations.HttpServer.Security
}
}
- private bool IsExemptFromAuthenticationToken(AuthorizationInfo auth, IAuthenticationAttributes authAttribtues)
+ private bool IsExemptFromAuthenticationToken(AuthorizationInfo auth, IAuthenticationAttributes authAttribtues, IRequest request)
{
if (!_config.Configuration.IsStartupWizardCompleted && authAttribtues.AllowBeforeStartupWizard)
{
return true;
}
+ if (authAttribtues.AllowLocal && request.IsLocal)
+ {
+ return true;
+ }
+
return false;
}
- private bool IsExemptFromRoles(AuthorizationInfo auth, IAuthenticationAttributes authAttribtues, AuthenticationInfo tokenInfo)
+ private bool IsExemptFromRoles(AuthorizationInfo auth, IAuthenticationAttributes authAttribtues, IRequest request, AuthenticationInfo tokenInfo)
{
if (!_config.Configuration.IsStartupWizardCompleted && authAttribtues.AllowBeforeStartupWizard)
{
return true;
}
+ if (authAttribtues.AllowLocal && request.IsLocal)
+ {
+ return true;
+ }
+
if (string.IsNullOrWhiteSpace(auth.Token))
{
return true;
@@ -162,7 +172,7 @@ namespace Emby.Server.Implementations.HttpServer.Security
return false;
}
- private void ValidateRoles(List<string> roles, User user)
+ private void ValidateRoles(string[] roles, User user)
{
if (roles.Contains("admin", StringComparer.OrdinalIgnoreCase))
{
@@ -196,7 +206,7 @@ namespace Emby.Server.Implementations.HttpServer.Security
}
}
- private AuthenticationInfo GetTokenInfo(IServiceRequest request)
+ private AuthenticationInfo GetTokenInfo(IRequest request)
{
object info;
request.Items.TryGetValue("OriginalAuthenticationInfo", out info);
@@ -213,7 +223,7 @@ namespace Emby.Server.Implementations.HttpServer.Security
return ConnectManager.IsAuthorizationTokenValid(token);
}
- private void ValidateSecurityToken(IServiceRequest request, string token)
+ private void ValidateSecurityToken(IRequest request, string token)
{
if (string.IsNullOrWhiteSpace(token))
{
diff --git a/Emby.Server.Implementations/HttpServer/Security/AuthorizationContext.cs b/Emby.Server.Implementations/HttpServer/Security/AuthorizationContext.cs
index ede85fb67..c9d5ed007 100644
--- a/Emby.Server.Implementations/HttpServer/Security/AuthorizationContext.cs
+++ b/Emby.Server.Implementations/HttpServer/Security/AuthorizationContext.cs
@@ -3,8 +3,8 @@ using MediaBrowser.Controller.Net;
using MediaBrowser.Controller.Security;
using System;
using System.Collections.Generic;
-using System.Linq;
using MediaBrowser.Model.Services;
+using System.Linq;
namespace Emby.Server.Implementations.HttpServer.Security
{
@@ -21,11 +21,10 @@ namespace Emby.Server.Implementations.HttpServer.Security
public AuthorizationInfo GetAuthorizationInfo(object requestContext)
{
- var req = new ServiceRequest((IRequest)requestContext);
- return GetAuthorizationInfo(req);
+ return GetAuthorizationInfo((IRequest)requestContext);
}
- public AuthorizationInfo GetAuthorizationInfo(IServiceRequest requestContext)
+ public AuthorizationInfo GetAuthorizationInfo(IRequest requestContext)
{
object cached;
if (requestContext.Items.TryGetValue("AuthorizationInfo", out cached))
@@ -41,7 +40,7 @@ namespace Emby.Server.Implementations.HttpServer.Security
/// </summary>
/// <param name="httpReq">The HTTP req.</param>
/// <returns>Dictionary{System.StringSystem.String}.</returns>
- private AuthorizationInfo GetAuthorization(IServiceRequest httpReq)
+ private AuthorizationInfo GetAuthorization(IRequest httpReq)
{
var auth = GetAuthorizationDictionary(httpReq);
@@ -90,7 +89,7 @@ namespace Emby.Server.Implementations.HttpServer.Security
AccessToken = token
});
- var tokenInfo = result.Items.FirstOrDefault();
+ var tokenInfo = result.Items.Length > 0 ? result.Items[0] : null;
if (tokenInfo != null)
{
@@ -135,7 +134,7 @@ namespace Emby.Server.Implementations.HttpServer.Security
/// </summary>
/// <param name="httpReq">The HTTP req.</param>
/// <returns>Dictionary{System.StringSystem.String}.</returns>
- private Dictionary<string, string> GetAuthorizationDictionary(IServiceRequest httpReq)
+ private Dictionary<string, string> GetAuthorizationDictionary(IRequest httpReq)
{
var auth = httpReq.Headers["X-Emby-Authorization"];
@@ -161,7 +160,7 @@ namespace Emby.Server.Implementations.HttpServer.Security
// There should be at least to parts
if (parts.Length != 2) return null;
- var acceptedNames = new[] { "MediaBrowser", "Emby"};
+ var acceptedNames = new[] { "MediaBrowser", "Emby" };
// It has to be a digest request
if (!acceptedNames.Contains(parts[0] ?? string.Empty, StringComparer.OrdinalIgnoreCase))
diff --git a/Emby.Server.Implementations/HttpServer/Security/SessionContext.cs b/Emby.Server.Implementations/HttpServer/Security/SessionContext.cs
index 33dd4e2d7..dd5d64bf6 100644
--- a/Emby.Server.Implementations/HttpServer/Security/SessionContext.cs
+++ b/Emby.Server.Implementations/HttpServer/Security/SessionContext.cs
@@ -21,7 +21,7 @@ namespace Emby.Server.Implementations.HttpServer.Security
_sessionManager = sessionManager;
}
- public Task<SessionInfo> GetSession(IServiceRequest requestContext)
+ public Task<SessionInfo> GetSession(IRequest requestContext)
{
var authorization = _authContext.GetAuthorizationInfo(requestContext);
@@ -38,7 +38,7 @@ namespace Emby.Server.Implementations.HttpServer.Security
return _sessionManager.LogSessionActivity(authorization.Client, authorization.Version, authorization.DeviceId, authorization.Device, requestContext.RemoteIp, user);
}
- private AuthenticationInfo GetTokenInfo(IServiceRequest request)
+ private AuthenticationInfo GetTokenInfo(IRequest request)
{
object info;
request.Items.TryGetValue("OriginalAuthenticationInfo", out info);
@@ -47,11 +47,10 @@ namespace Emby.Server.Implementations.HttpServer.Security
public Task<SessionInfo> GetSession(object requestContext)
{
- var req = new ServiceRequest((IRequest)requestContext);
- return GetSession(req);
+ return GetSession((IRequest)requestContext);
}
- public async Task<User> GetUser(IServiceRequest requestContext)
+ public async Task<User> GetUser(IRequest requestContext)
{
var session = await GetSession(requestContext).ConfigureAwait(false);
@@ -60,8 +59,7 @@ namespace Emby.Server.Implementations.HttpServer.Security
public Task<User> GetUser(object requestContext)
{
- var req = new ServiceRequest((IRequest)requestContext);
- return GetUser(req);
+ return GetUser((IRequest)requestContext);
}
}
}
diff --git a/Emby.Server.Implementations/HttpServer/SocketSharp/HttpUtility.cs b/Emby.Server.Implementations/HttpServer/SocketSharp/HttpUtility.cs
index 4fbe0ed94..4e8dd7362 100644
--- a/Emby.Server.Implementations/HttpServer/SocketSharp/HttpUtility.cs
+++ b/Emby.Server.Implementations/HttpServer/SocketSharp/HttpUtility.cs
@@ -3,6 +3,7 @@ using System.Collections;
using System.Collections.Generic;
using System.Text;
using MediaBrowser.Model.Services;
+using MediaBrowser.Model.Extensions;
namespace Emby.Server.Implementations.HttpServer.SocketSharp
{
@@ -585,7 +586,7 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp
WriteCharBytes(bytes, ch, e);
}
- byte[] buf = bytes.ToArray();
+ byte[] buf = bytes.ToArray(bytes.Count);
bytes = null;
return e.GetString(buf, 0, buf.Length);
diff --git a/Emby.Server.Implementations/HttpServer/SocketSharp/SharpWebSocket.cs b/Emby.Server.Implementations/HttpServer/SocketSharp/SharpWebSocket.cs
index 9823a2ff5..cc7a4557e 100644
--- a/Emby.Server.Implementations/HttpServer/SocketSharp/SharpWebSocket.cs
+++ b/Emby.Server.Implementations/HttpServer/SocketSharp/SharpWebSocket.cs
@@ -123,6 +123,7 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp
public void Dispose()
{
Dispose(true);
+ GC.SuppressFinalize(this);
}
/// <summary>
diff --git a/Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpListener.cs b/Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpListener.cs
index e648838b2..10aaa4032 100644
--- a/Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpListener.cs
+++ b/Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpListener.cs
@@ -4,6 +4,7 @@ using SocketHttpListener.Net;
using System;
using System.Collections.Generic;
using System.Linq;
+using System.Security.Cryptography.X509Certificates;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Common.Net;
@@ -22,22 +23,20 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp
private HttpListener _listener;
private readonly ILogger _logger;
- private readonly ICertificate _certificate;
+ private readonly X509Certificate _certificate;
private readonly IMemoryStreamFactory _memoryStreamProvider;
private readonly ITextEncoding _textEncoding;
private readonly INetworkManager _networkManager;
private readonly ISocketFactory _socketFactory;
private readonly ICryptoProvider _cryptoProvider;
- private readonly IStreamFactory _streamFactory;
private readonly IFileSystem _fileSystem;
- private readonly Func<HttpListenerContext, IHttpRequest> _httpRequestFactory;
private readonly bool _enableDualMode;
private readonly IEnvironmentInfo _environment;
private CancellationTokenSource _disposeCancellationTokenSource = new CancellationTokenSource();
private CancellationToken _disposeCancellationToken;
- public WebSocketSharpListener(ILogger logger, ICertificate certificate, IMemoryStreamFactory memoryStreamProvider, ITextEncoding textEncoding, INetworkManager networkManager, ISocketFactory socketFactory, ICryptoProvider cryptoProvider, IStreamFactory streamFactory, bool enableDualMode, Func<HttpListenerContext, IHttpRequest> httpRequestFactory, IFileSystem fileSystem, IEnvironmentInfo environment)
+ public WebSocketSharpListener(ILogger logger, X509Certificate certificate, IMemoryStreamFactory memoryStreamProvider, ITextEncoding textEncoding, INetworkManager networkManager, ISocketFactory socketFactory, ICryptoProvider cryptoProvider, bool enableDualMode, IFileSystem fileSystem, IEnvironmentInfo environment)
{
_logger = logger;
_certificate = certificate;
@@ -46,9 +45,7 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp
_networkManager = networkManager;
_socketFactory = socketFactory;
_cryptoProvider = cryptoProvider;
- _streamFactory = streamFactory;
_enableDualMode = enableDualMode;
- _httpRequestFactory = httpRequestFactory;
_fileSystem = fileSystem;
_environment = environment;
@@ -56,7 +53,7 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp
}
public Action<Exception, IRequest, bool> ErrorHandler { get; set; }
- public Func<IHttpRequest, Uri, CancellationToken, Task> RequestHandler { get; set; }
+ public Func<IHttpRequest, string, string, string, CancellationToken, Task> RequestHandler { get; set; }
public Action<WebSocketConnectingEventArgs> WebSocketConnecting { get; set; }
@@ -65,7 +62,7 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp
public void Start(IEnumerable<string> urlPrefixes)
{
if (_listener == null)
- _listener = new HttpListener(_logger, _cryptoProvider, _streamFactory, _socketFactory, _networkManager, _textEncoding, _memoryStreamProvider, _fileSystem, _environment);
+ _listener = new HttpListener(_logger, _cryptoProvider, _socketFactory, _networkManager, _textEncoding, _memoryStreamProvider, _fileSystem, _environment);
_listener.EnableDualMode = _enableDualMode;
@@ -117,7 +114,9 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp
return Task.FromResult(true);
}
- return RequestHandler(httpReq, request.Url, cancellationToken);
+ var uri = request.Url;
+
+ return RequestHandler(httpReq, uri.OriginalString, uri.Host, uri.LocalPath, cancellationToken);
}
private void ProcessWebSocketRequest(HttpListenerContext ctx)
@@ -173,10 +172,14 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp
private IHttpRequest GetRequest(HttpListenerContext httpContext)
{
- return _httpRequestFactory(httpContext);
+ var operationName = httpContext.Request.GetOperationName();
+
+ var req = new WebSocketSharpRequest(httpContext, operationName, _logger, _memoryStreamProvider);
+
+ return req;
}
- public void Stop()
+ public Task Stop()
{
_disposeCancellationTokenSource.Cancel();
@@ -189,6 +192,8 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp
_listener.Close();
}
+
+ return Task.FromResult(true);
}
public void Dispose()
diff --git a/Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpRequest.cs b/Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpRequest.cs
index 2dfe6a9e3..522377f0c 100644
--- a/Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpRequest.cs
+++ b/Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpRequest.cs
@@ -27,6 +27,20 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp
_memoryStreamProvider = memoryStreamProvider;
this.request = httpContext.Request;
this.response = new WebSocketSharpResponse(logger, httpContext.Response, this);
+
+ //HandlerFactoryPath = GetHandlerPathIfAny(UrlPrefixes[0]);
+ }
+
+ private static string GetHandlerPathIfAny(string listenerUrl)
+ {
+ if (listenerUrl == null) return null;
+ var pos = listenerUrl.IndexOf("://", StringComparison.OrdinalIgnoreCase);
+ if (pos == -1) return null;
+ var startHostUrl = listenerUrl.Substring(pos + "://".Length);
+ var endPos = startHostUrl.IndexOf('/');
+ if (endPos == -1) return null;
+ var endHostUrl = startHostUrl.Substring(endPos + 1);
+ return string.IsNullOrEmpty(endHostUrl) ? null : endHostUrl.TrimEnd('/');
}
public HttpListenerRequest HttpRequest
@@ -108,7 +122,7 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp
return remoteIp ??
(remoteIp = (CheckBadChars(XForwardedFor)) ??
(NormalizeIp(CheckBadChars(XRealIp)) ??
- (request.RemoteEndPoint != null ? NormalizeIp(request.RemoteEndPoint.IpAddress.ToString()) : null)));
+ (request.RemoteEndPoint != null ? NormalizeIp(request.RemoteEndPoint.Address.ToString()) : null)));
}
}
@@ -232,13 +246,12 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp
set
{
this.responseContentType = value;
- HasExplicitResponseContentType = true;
}
}
public const string FormUrlEncoded = "application/x-www-form-urlencoded";
public const string MultiPartFormData = "multipart/form-data";
- private static string GetResponseContentType(IRequest httpReq)
+ public static string GetResponseContentType(IRequest httpReq)
{
var specifiedContentType = GetQueryStringContentType(httpReq);
if (!string.IsNullOrEmpty(specifiedContentType)) return specifiedContentType;
@@ -346,8 +359,6 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp
: strVal.Substring(0, pos);
}
- public bool HasExplicitResponseContentType { get; private set; }
-
public static string HandlerFactoryPath;
private string pathInfo;
@@ -490,13 +501,6 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp
get { return HttpMethod; }
}
- public string Param(string name)
- {
- return Headers[name]
- ?? QueryString[name]
- ?? FormData[name];
- }
-
public string ContentType
{
get { return request.ContentType; }
@@ -584,18 +588,6 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp
return stream;
}
- public static string GetHandlerPathIfAny(string listenerUrl)
- {
- if (listenerUrl == null) return null;
- var pos = listenerUrl.IndexOf("://", StringComparison.OrdinalIgnoreCase);
- if (pos == -1) return null;
- var startHostUrl = listenerUrl.Substring(pos + "://".Length);
- var endPos = startHostUrl.IndexOf('/');
- if (endPos == -1) return null;
- var endHostUrl = startHostUrl.Substring(endPos + 1);
- return String.IsNullOrEmpty(endHostUrl) ? null : endHostUrl.TrimEnd('/');
- }
-
public static string NormalizePathInfo(string pathInfo, string handlerPath)
{
if (handlerPath != null && pathInfo.TrimStart('/').StartsWith(
diff --git a/Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpResponse.cs b/Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpResponse.cs
index d6762d94b..5b51c0cf1 100644
--- a/Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpResponse.cs
+++ b/Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpResponse.cs
@@ -29,7 +29,6 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp
}
public IRequest Request { get; private set; }
- public bool UseBufferedStream { get; set; }
public Dictionary<string, object> Items { get; private set; }
public object OriginalResponse
{
diff --git a/Emby.Server.Core/HttpServerFactory.cs b/Emby.Server.Implementations/HttpServerFactory.cs
index e16cbea0e..717c50e7b 100644
--- a/Emby.Server.Core/HttpServerFactory.cs
+++ b/Emby.Server.Implementations/HttpServerFactory.cs
@@ -1,12 +1,10 @@
using System;
using System.IO;
using System.Net.Security;
-using System.Net.Sockets;
using System.Security.Cryptography.X509Certificates;
-using System.Threading;
using System.Threading.Tasks;
-using Emby.Common.Implementations.Net;
using Emby.Server.Implementations.HttpServer;
+using Emby.Server.Implementations.Net;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller;
using MediaBrowser.Controller.Configuration;
@@ -21,7 +19,7 @@ using MediaBrowser.Model.Text;
using ServiceStack.Text.Jsv;
using SocketHttpListener.Primitives;
-namespace Emby.Server.Core
+namespace Emby.Server.Implementations
{
/// <summary>
/// Class ServerFactory
@@ -45,7 +43,7 @@ namespace Emby.Server.Core
IJsonSerializer json,
IXmlSerializer xml,
IEnvironmentInfo environment,
- ICertificate certificate,
+ X509Certificate certificate,
IFileSystem fileSystem,
bool enableDualModeSockets)
{
@@ -65,7 +63,6 @@ namespace Emby.Server.Core
xml,
environment,
certificate,
- new StreamFactory(),
GetParseFn,
enableDualModeSockets,
fileSystem);
@@ -76,37 +73,4 @@ namespace Emby.Server.Core
return s => JsvReader.GetParseFn(propertyType)(s);
}
}
-
- public class StreamFactory : IStreamFactory
- {
- public Stream CreateNetworkStream(IAcceptSocket acceptSocket, bool ownsSocket)
- {
- var netSocket = (NetAcceptSocket)acceptSocket;
-
- return new SocketStream(netSocket.Socket, ownsSocket);
- }
-
- public Task AuthenticateSslStreamAsServer(Stream stream, ICertificate certificate)
- {
- var sslStream = (SslStream)stream;
- var cert = (Certificate)certificate;
-
- return sslStream.AuthenticateAsServerAsync(cert.X509Certificate);
- }
-
- public Stream CreateSslStream(Stream innerStream, bool leaveInnerStreamOpen)
- {
- return new SslStream(innerStream, leaveInnerStreamOpen);
- }
- }
-
- public class Certificate : ICertificate
- {
- public Certificate(X509Certificate x509Certificate)
- {
- X509Certificate = x509Certificate;
- }
-
- public X509Certificate X509Certificate { get; private set; }
- }
}
diff --git a/Emby.Server.Implementations/IO/FileRefresher.cs b/Emby.Server.Implementations/IO/FileRefresher.cs
index d4914e734..20de8a518 100644
--- a/Emby.Server.Implementations/IO/FileRefresher.cs
+++ b/Emby.Server.Implementations/IO/FileRefresher.cs
@@ -121,7 +121,7 @@ namespace Emby.Server.Implementations.IO
RestartTimer();
}
- private async void OnTimerCallback(object state)
+ private void OnTimerCallback(object state)
{
List<string> paths;
@@ -130,14 +130,6 @@ namespace Emby.Server.Implementations.IO
paths = _affectedPaths.ToList();
}
- // Extend the timer as long as any of the paths are still being written to.
- if (paths.Any(IsFileLocked))
- {
- Logger.Info("Timer extended.");
- RestartTimer();
- return;
- }
-
Logger.Debug("Timer stopped.");
DisposeTimer();
@@ -145,7 +137,7 @@ namespace Emby.Server.Implementations.IO
try
{
- await ProcessPathChanges(paths.ToList()).ConfigureAwait(false);
+ ProcessPathChanges(paths.ToList());
}
catch (Exception ex)
{
@@ -153,7 +145,7 @@ namespace Emby.Server.Implementations.IO
}
}
- private async Task ProcessPathChanges(List<string> paths)
+ private void ProcessPathChanges(List<string> paths)
{
var itemsToRefresh = paths
.Distinct(StringComparer.OrdinalIgnoreCase)
@@ -229,90 +221,6 @@ namespace Emby.Server.Implementations.IO
return item;
}
- private bool IsFileLocked(string path)
- {
- if (_environmentInfo.OperatingSystem != MediaBrowser.Model.System.OperatingSystem.Windows)
- {
- // Causing lockups on linux
- return false;
- }
-
- // Only try to open video files
- if (!_libraryManager.IsVideoFile(path))
- {
- return false;
- }
-
- try
- {
- var data = _fileSystem.GetFileSystemInfo(path);
-
- if (!data.Exists
- || data.IsDirectory
-
- // Opening a writable stream will fail with readonly files
- || data.IsReadOnly)
- {
- return false;
- }
- }
- catch (IOException)
- {
- return false;
- }
- catch (Exception ex)
- {
- Logger.ErrorException("Error getting file system info for: {0}", ex, path);
- return false;
- }
-
- // In order to determine if the file is being written to, we have to request write access
- // But if the server only has readonly access, this is going to cause this entire algorithm to fail
- // So we'll take a best guess about our access level
- //var requestedFileAccess = ConfigurationManager.Configuration.SaveLocalMeta
- // ? FileAccessMode.ReadWrite
- // : FileAccessMode.Read;
-
- var requestedFileAccess = FileAccessMode.Read;
- try
- {
- using (_fileSystem.GetFileStream(path, FileOpenMode.Open, requestedFileAccess, FileShareMode.ReadWrite))
- {
- //file is not locked
- return false;
- }
- }
- catch (DirectoryNotFoundException)
- {
- // File may have been deleted
- return false;
- }
- catch (FileNotFoundException)
- {
- // File may have been deleted
- return false;
- }
- catch (UnauthorizedAccessException)
- {
- Logger.Debug("No write permission for: {0}.", path);
- return false;
- }
- catch (IOException)
- {
- //the file is unavailable because it is:
- //still being written to
- //or being processed by another thread
- //or does not exist (has already been processed)
- Logger.Debug("{0} is locked.", path);
- return true;
- }
- catch (Exception ex)
- {
- Logger.ErrorException("Error determining if file is locked: {0}", ex, path);
- return false;
- }
- }
-
private void DisposeTimer()
{
lock (_timerLock)
@@ -330,6 +238,7 @@ namespace Emby.Server.Implementations.IO
{
_disposed = true;
DisposeTimer();
+ GC.SuppressFinalize(this);
}
}
}
diff --git a/Emby.Common.Implementations/IO/IsoManager.cs b/Emby.Server.Implementations/IO/IsoManager.cs
index 14614acaf..dc0b9e122 100644
--- a/Emby.Common.Implementations/IO/IsoManager.cs
+++ b/Emby.Server.Implementations/IO/IsoManager.cs
@@ -5,7 +5,7 @@ using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Model.IO;
-namespace Emby.Common.Implementations.IO
+namespace Emby.Server.Implementations.IO
{
/// <summary>
/// Class IsoManager
@@ -70,6 +70,7 @@ namespace Emby.Common.Implementations.IO
{
mounter.Dispose();
}
+ GC.SuppressFinalize(this);
}
}
}
diff --git a/Emby.Server.Core/IO/LibraryMonitor.cs b/Emby.Server.Implementations/IO/LibraryMonitor.cs
index ebc5e5e55..56b10a7e6 100644
--- a/Emby.Server.Core/IO/LibraryMonitor.cs
+++ b/Emby.Server.Implementations/IO/LibraryMonitor.cs
@@ -13,9 +13,8 @@ using MediaBrowser.Model.Logging;
using MediaBrowser.Model.System;
using MediaBrowser.Model.Tasks;
using MediaBrowser.Model.Threading;
-using Emby.Server.Implementations.IO;
-namespace Emby.Server.Core.IO
+namespace Emby.Server.Implementations.IO
{
public class LibraryMonitor : ILibraryMonitor
{
@@ -36,7 +35,7 @@ namespace Emby.Server.Core.IO
/// <summary>
/// Any file name ending in any of these will be ignored by the watchers
/// </summary>
- private readonly IReadOnlyList<string> _alwaysIgnoreFiles = new List<string>
+ private readonly string[] _alwaysIgnoreFiles = new string[]
{
"small.jpg",
"albumart.jpg",
@@ -46,7 +45,7 @@ namespace Emby.Server.Core.IO
"TempSBE"
};
- private readonly IReadOnlyList<string> _alwaysIgnoreSubstrings = new List<string>
+ private readonly string[] _alwaysIgnoreSubstrings = new string[]
{
// Synology
"eaDir",
@@ -55,7 +54,7 @@ namespace Emby.Server.Core.IO
".actors"
};
- private readonly IReadOnlyList<string> _alwaysIgnoreExtensions = new List<string>
+ private readonly string[] _alwaysIgnoreExtensions = new string[]
{
// thumbs.db
".db",
@@ -86,6 +85,8 @@ namespace Emby.Server.Core.IO
public bool IsPathLocked(string path)
{
+ // This method is not used by the core but it used by auto-organize
+
var lockedPaths = _tempIgnoredPaths.Keys.ToList();
return lockedPaths.Any(i => _fileSystem.AreEqual(i, path) || _fileSystem.ContainsSubPath(i, path));
}
@@ -648,6 +649,7 @@ namespace Emby.Server.Core.IO
public void Dispose()
{
+ GC.SuppressFinalize(this);
}
}
}
diff --git a/Emby.Common.Implementations/IO/ManagedFileSystem.cs b/Emby.Server.Implementations/IO/ManagedFileSystem.cs
index 7d14e521f..0d85a977c 100644
--- a/Emby.Common.Implementations/IO/ManagedFileSystem.cs
+++ b/Emby.Server.Implementations/IO/ManagedFileSystem.cs
@@ -7,7 +7,7 @@ using MediaBrowser.Model.IO;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.System;
-namespace Emby.Common.Implementations.IO
+namespace Emby.Server.Implementations.IO
{
/// <summary>
/// Class ManagedFileSystem
diff --git a/Emby.Server.Implementations/IO/MemoryStreamProvider.cs b/Emby.Server.Implementations/IO/MemoryStreamProvider.cs
new file mode 100644
index 000000000..e9ecb7e44
--- /dev/null
+++ b/Emby.Server.Implementations/IO/MemoryStreamProvider.cs
@@ -0,0 +1,29 @@
+using System.IO;
+using MediaBrowser.Model.IO;
+
+namespace Emby.Server.Implementations.IO
+{
+ public class MemoryStreamProvider : IMemoryStreamFactory
+ {
+ public MemoryStream CreateNew()
+ {
+ return new MemoryStream();
+ }
+
+ public MemoryStream CreateNew(int capacity)
+ {
+ return new MemoryStream(capacity);
+ }
+
+ public MemoryStream CreateNew(byte[] buffer)
+ {
+ return new MemoryStream(buffer);
+ }
+
+ public bool TryGetBuffer(MemoryStream stream, out byte[] buffer)
+ {
+ buffer = stream.GetBuffer();
+ return true;
+ }
+ }
+}
diff --git a/Emby.Common.Implementations/IO/ProgressStream.cs b/Emby.Server.Implementations/IO/ProgressStream.cs
index fb8cf86df..be1ff72f8 100644
--- a/Emby.Common.Implementations/IO/ProgressStream.cs
+++ b/Emby.Server.Implementations/IO/ProgressStream.cs
@@ -1,7 +1,7 @@
using System;
using System.IO;
-namespace Emby.Common.Implementations.IO
+namespace Emby.Server.Implementations.IO
{
/// <summary>
/// Measures progress when reading from a stream or writing to one
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Config.cs b/Emby.Server.Implementations/IO/SharpCifs/Config.cs
index 3fd0e5bd6..3fd0e5bd6 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Config.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Config.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Dcerpc/DcerpcBind.cs b/Emby.Server.Implementations/IO/SharpCifs/Dcerpc/DcerpcBind.cs
index 1d8d13c08..1d8d13c08 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Dcerpc/DcerpcBind.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Dcerpc/DcerpcBind.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Dcerpc/DcerpcBinding.cs b/Emby.Server.Implementations/IO/SharpCifs/Dcerpc/DcerpcBinding.cs
index 234150664..234150664 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Dcerpc/DcerpcBinding.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Dcerpc/DcerpcBinding.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Dcerpc/DcerpcConstants.cs b/Emby.Server.Implementations/IO/SharpCifs/Dcerpc/DcerpcConstants.cs
index 5b69c5c2e..5b69c5c2e 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Dcerpc/DcerpcConstants.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Dcerpc/DcerpcConstants.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Dcerpc/DcerpcError.cs b/Emby.Server.Implementations/IO/SharpCifs/Dcerpc/DcerpcError.cs
index 55c061065..55c061065 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Dcerpc/DcerpcError.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Dcerpc/DcerpcError.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Dcerpc/DcerpcException.cs b/Emby.Server.Implementations/IO/SharpCifs/Dcerpc/DcerpcException.cs
index 13c4f0d0c..13c4f0d0c 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Dcerpc/DcerpcException.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Dcerpc/DcerpcException.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Dcerpc/DcerpcHandle.cs b/Emby.Server.Implementations/IO/SharpCifs/Dcerpc/DcerpcHandle.cs
index 786b0ac12..786b0ac12 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Dcerpc/DcerpcHandle.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Dcerpc/DcerpcHandle.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Dcerpc/DcerpcMessage.cs b/Emby.Server.Implementations/IO/SharpCifs/Dcerpc/DcerpcMessage.cs
index 543dd72dd..543dd72dd 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Dcerpc/DcerpcMessage.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Dcerpc/DcerpcMessage.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Dcerpc/DcerpcPipeHandle.cs b/Emby.Server.Implementations/IO/SharpCifs/Dcerpc/DcerpcPipeHandle.cs
index 0399578cd..0399578cd 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Dcerpc/DcerpcPipeHandle.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Dcerpc/DcerpcPipeHandle.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Dcerpc/DcerpcSecurityProvider.cs b/Emby.Server.Implementations/IO/SharpCifs/Dcerpc/DcerpcSecurityProvider.cs
index cc46902f1..cc46902f1 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Dcerpc/DcerpcSecurityProvider.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Dcerpc/DcerpcSecurityProvider.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Dcerpc/Msrpc/LsaPolicyHandle.cs b/Emby.Server.Implementations/IO/SharpCifs/Dcerpc/Msrpc/LsaPolicyHandle.cs
index 03964fcc7..03964fcc7 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Dcerpc/Msrpc/LsaPolicyHandle.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Dcerpc/Msrpc/LsaPolicyHandle.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Dcerpc/Msrpc/LsarSidArrayX.cs b/Emby.Server.Implementations/IO/SharpCifs/Dcerpc/Msrpc/LsarSidArrayX.cs
index ef09bb16e..ef09bb16e 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Dcerpc/Msrpc/LsarSidArrayX.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Dcerpc/Msrpc/LsarSidArrayX.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Dcerpc/Msrpc/Lsarpc.cs b/Emby.Server.Implementations/IO/SharpCifs/Dcerpc/Msrpc/Lsarpc.cs
index 1ae85c473..1ae85c473 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Dcerpc/Msrpc/Lsarpc.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Dcerpc/Msrpc/Lsarpc.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Dcerpc/Msrpc/MsrpcDfsRootEnum.cs b/Emby.Server.Implementations/IO/SharpCifs/Dcerpc/Msrpc/MsrpcDfsRootEnum.cs
index 6a9d4302a..6a9d4302a 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Dcerpc/Msrpc/MsrpcDfsRootEnum.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Dcerpc/Msrpc/MsrpcDfsRootEnum.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Dcerpc/Msrpc/MsrpcEnumerateAliasesInDomain.cs b/Emby.Server.Implementations/IO/SharpCifs/Dcerpc/Msrpc/MsrpcEnumerateAliasesInDomain.cs
index d9c0afb34..d9c0afb34 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Dcerpc/Msrpc/MsrpcEnumerateAliasesInDomain.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Dcerpc/Msrpc/MsrpcEnumerateAliasesInDomain.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Dcerpc/Msrpc/MsrpcGetMembersInAlias.cs b/Emby.Server.Implementations/IO/SharpCifs/Dcerpc/Msrpc/MsrpcGetMembersInAlias.cs
index 77b2ee375..77b2ee375 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Dcerpc/Msrpc/MsrpcGetMembersInAlias.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Dcerpc/Msrpc/MsrpcGetMembersInAlias.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Dcerpc/Msrpc/MsrpcLookupSids.cs b/Emby.Server.Implementations/IO/SharpCifs/Dcerpc/Msrpc/MsrpcLookupSids.cs
index 0aaf31026..0aaf31026 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Dcerpc/Msrpc/MsrpcLookupSids.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Dcerpc/Msrpc/MsrpcLookupSids.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Dcerpc/Msrpc/MsrpcLsarOpenPolicy2.cs b/Emby.Server.Implementations/IO/SharpCifs/Dcerpc/Msrpc/MsrpcLsarOpenPolicy2.cs
index 9d2c2a0f4..9d2c2a0f4 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Dcerpc/Msrpc/MsrpcLsarOpenPolicy2.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Dcerpc/Msrpc/MsrpcLsarOpenPolicy2.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Dcerpc/Msrpc/MsrpcQueryInformationPolicy.cs b/Emby.Server.Implementations/IO/SharpCifs/Dcerpc/Msrpc/MsrpcQueryInformationPolicy.cs
index 820d81ab2..820d81ab2 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Dcerpc/Msrpc/MsrpcQueryInformationPolicy.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Dcerpc/Msrpc/MsrpcQueryInformationPolicy.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Dcerpc/Msrpc/MsrpcSamrConnect2.cs b/Emby.Server.Implementations/IO/SharpCifs/Dcerpc/Msrpc/MsrpcSamrConnect2.cs
index 80c45257c..80c45257c 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Dcerpc/Msrpc/MsrpcSamrConnect2.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Dcerpc/Msrpc/MsrpcSamrConnect2.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Dcerpc/Msrpc/MsrpcSamrConnect4.cs b/Emby.Server.Implementations/IO/SharpCifs/Dcerpc/Msrpc/MsrpcSamrConnect4.cs
index 0f2603e9c..0f2603e9c 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Dcerpc/Msrpc/MsrpcSamrConnect4.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Dcerpc/Msrpc/MsrpcSamrConnect4.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Dcerpc/Msrpc/MsrpcSamrOpenAlias.cs b/Emby.Server.Implementations/IO/SharpCifs/Dcerpc/Msrpc/MsrpcSamrOpenAlias.cs
index e0b9b68d3..e0b9b68d3 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Dcerpc/Msrpc/MsrpcSamrOpenAlias.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Dcerpc/Msrpc/MsrpcSamrOpenAlias.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Dcerpc/Msrpc/MsrpcSamrOpenDomain.cs b/Emby.Server.Implementations/IO/SharpCifs/Dcerpc/Msrpc/MsrpcSamrOpenDomain.cs
index 2ac6bceed..2ac6bceed 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Dcerpc/Msrpc/MsrpcSamrOpenDomain.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Dcerpc/Msrpc/MsrpcSamrOpenDomain.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Dcerpc/Msrpc/MsrpcShareEnum.cs b/Emby.Server.Implementations/IO/SharpCifs/Dcerpc/Msrpc/MsrpcShareEnum.cs
index 7c7b64abf..7c7b64abf 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Dcerpc/Msrpc/MsrpcShareEnum.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Dcerpc/Msrpc/MsrpcShareEnum.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Dcerpc/Msrpc/MsrpcShareGetInfo.cs b/Emby.Server.Implementations/IO/SharpCifs/Dcerpc/Msrpc/MsrpcShareGetInfo.cs
index 802ed61a3..802ed61a3 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Dcerpc/Msrpc/MsrpcShareGetInfo.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Dcerpc/Msrpc/MsrpcShareGetInfo.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Dcerpc/Msrpc/Netdfs.cs b/Emby.Server.Implementations/IO/SharpCifs/Dcerpc/Msrpc/Netdfs.cs
index a338b2885..a338b2885 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Dcerpc/Msrpc/Netdfs.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Dcerpc/Msrpc/Netdfs.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Dcerpc/Msrpc/Samr.cs b/Emby.Server.Implementations/IO/SharpCifs/Dcerpc/Msrpc/Samr.cs
index bdc71695e..bdc71695e 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Dcerpc/Msrpc/Samr.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Dcerpc/Msrpc/Samr.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Dcerpc/Msrpc/SamrAliasHandle.cs b/Emby.Server.Implementations/IO/SharpCifs/Dcerpc/Msrpc/SamrAliasHandle.cs
index d4ebdacc4..d4ebdacc4 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Dcerpc/Msrpc/SamrAliasHandle.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Dcerpc/Msrpc/SamrAliasHandle.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Dcerpc/Msrpc/SamrDomainHandle.cs b/Emby.Server.Implementations/IO/SharpCifs/Dcerpc/Msrpc/SamrDomainHandle.cs
index d44c79886..d44c79886 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Dcerpc/Msrpc/SamrDomainHandle.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Dcerpc/Msrpc/SamrDomainHandle.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Dcerpc/Msrpc/SamrPolicyHandle.cs b/Emby.Server.Implementations/IO/SharpCifs/Dcerpc/Msrpc/SamrPolicyHandle.cs
index 0cd3f9369..0cd3f9369 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Dcerpc/Msrpc/SamrPolicyHandle.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Dcerpc/Msrpc/SamrPolicyHandle.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Dcerpc/Msrpc/Srvsvc.cs b/Emby.Server.Implementations/IO/SharpCifs/Dcerpc/Msrpc/Srvsvc.cs
index f33f48327..f33f48327 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Dcerpc/Msrpc/Srvsvc.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Dcerpc/Msrpc/Srvsvc.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Dcerpc/Ndr/NdrBuffer.cs b/Emby.Server.Implementations/IO/SharpCifs/Dcerpc/Ndr/NdrBuffer.cs
index 0a47de799..0a47de799 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Dcerpc/Ndr/NdrBuffer.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Dcerpc/Ndr/NdrBuffer.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Dcerpc/Ndr/NdrException.cs b/Emby.Server.Implementations/IO/SharpCifs/Dcerpc/Ndr/NdrException.cs
index 7757735f8..7757735f8 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Dcerpc/Ndr/NdrException.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Dcerpc/Ndr/NdrException.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Dcerpc/Ndr/NdrHyper.cs b/Emby.Server.Implementations/IO/SharpCifs/Dcerpc/Ndr/NdrHyper.cs
index 9e2932337..9e2932337 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Dcerpc/Ndr/NdrHyper.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Dcerpc/Ndr/NdrHyper.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Dcerpc/Ndr/NdrLong.cs b/Emby.Server.Implementations/IO/SharpCifs/Dcerpc/Ndr/NdrLong.cs
index 74d90465e..74d90465e 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Dcerpc/Ndr/NdrLong.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Dcerpc/Ndr/NdrLong.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Dcerpc/Ndr/NdrObject.cs b/Emby.Server.Implementations/IO/SharpCifs/Dcerpc/Ndr/NdrObject.cs
index 8951fa202..8951fa202 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Dcerpc/Ndr/NdrObject.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Dcerpc/Ndr/NdrObject.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Dcerpc/Ndr/NdrShort.cs b/Emby.Server.Implementations/IO/SharpCifs/Dcerpc/Ndr/NdrShort.cs
index e2ea8c65b..e2ea8c65b 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Dcerpc/Ndr/NdrShort.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Dcerpc/Ndr/NdrShort.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Dcerpc/Ndr/NdrSmall.cs b/Emby.Server.Implementations/IO/SharpCifs/Dcerpc/Ndr/NdrSmall.cs
index 8309dea66..8309dea66 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Dcerpc/Ndr/NdrSmall.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Dcerpc/Ndr/NdrSmall.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Dcerpc/Rpc.cs b/Emby.Server.Implementations/IO/SharpCifs/Dcerpc/Rpc.cs
index aa33d3522..aa33d3522 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Dcerpc/Rpc.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Dcerpc/Rpc.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Dcerpc/UUID.cs b/Emby.Server.Implementations/IO/SharpCifs/Dcerpc/UUID.cs
index bef4be214..bef4be214 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Dcerpc/UUID.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Dcerpc/UUID.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Dcerpc/UnicodeString.cs b/Emby.Server.Implementations/IO/SharpCifs/Dcerpc/UnicodeString.cs
index b0c36898c..b0c36898c 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Dcerpc/UnicodeString.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Dcerpc/UnicodeString.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Netbios/Lmhosts.cs b/Emby.Server.Implementations/IO/SharpCifs/Netbios/Lmhosts.cs
index c94d0a260..c94d0a260 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Netbios/Lmhosts.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Netbios/Lmhosts.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Netbios/Name.cs b/Emby.Server.Implementations/IO/SharpCifs/Netbios/Name.cs
index 6c37d57a4..6c37d57a4 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Netbios/Name.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Netbios/Name.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Netbios/NameQueryRequest.cs b/Emby.Server.Implementations/IO/SharpCifs/Netbios/NameQueryRequest.cs
index 646e65bf8..646e65bf8 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Netbios/NameQueryRequest.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Netbios/NameQueryRequest.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Netbios/NameQueryResponse.cs b/Emby.Server.Implementations/IO/SharpCifs/Netbios/NameQueryResponse.cs
index c7fac8e93..c7fac8e93 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Netbios/NameQueryResponse.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Netbios/NameQueryResponse.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Netbios/NameServiceClient.cs b/Emby.Server.Implementations/IO/SharpCifs/Netbios/NameServiceClient.cs
index 01700e64a..01700e64a 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Netbios/NameServiceClient.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Netbios/NameServiceClient.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Netbios/NameServicePacket.cs b/Emby.Server.Implementations/IO/SharpCifs/Netbios/NameServicePacket.cs
index 28e98406e..28e98406e 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Netbios/NameServicePacket.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Netbios/NameServicePacket.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Netbios/NbtAddress.cs b/Emby.Server.Implementations/IO/SharpCifs/Netbios/NbtAddress.cs
index c64d385f1..c64d385f1 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Netbios/NbtAddress.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Netbios/NbtAddress.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Netbios/NbtException.cs b/Emby.Server.Implementations/IO/SharpCifs/Netbios/NbtException.cs
index e785c9943..e785c9943 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Netbios/NbtException.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Netbios/NbtException.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Netbios/NodeStatusRequest.cs b/Emby.Server.Implementations/IO/SharpCifs/Netbios/NodeStatusRequest.cs
index 66d3bb3e5..66d3bb3e5 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Netbios/NodeStatusRequest.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Netbios/NodeStatusRequest.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Netbios/NodeStatusResponse.cs b/Emby.Server.Implementations/IO/SharpCifs/Netbios/NodeStatusResponse.cs
index aa3214419..aa3214419 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Netbios/NodeStatusResponse.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Netbios/NodeStatusResponse.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Netbios/SessionRequestPacket.cs b/Emby.Server.Implementations/IO/SharpCifs/Netbios/SessionRequestPacket.cs
index a5243f7aa..a5243f7aa 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Netbios/SessionRequestPacket.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Netbios/SessionRequestPacket.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Netbios/SessionRetargetResponsePacket.cs b/Emby.Server.Implementations/IO/SharpCifs/Netbios/SessionRetargetResponsePacket.cs
index c901c6e26..c901c6e26 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Netbios/SessionRetargetResponsePacket.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Netbios/SessionRetargetResponsePacket.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Netbios/SessionServicePacket.cs b/Emby.Server.Implementations/IO/SharpCifs/Netbios/SessionServicePacket.cs
index c8d194222..c8d194222 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Netbios/SessionServicePacket.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Netbios/SessionServicePacket.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Ntlmssp/NtlmFlags.cs b/Emby.Server.Implementations/IO/SharpCifs/Ntlmssp/NtlmFlags.cs
index 116f71b75..116f71b75 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Ntlmssp/NtlmFlags.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Ntlmssp/NtlmFlags.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Ntlmssp/NtlmMessage.cs b/Emby.Server.Implementations/IO/SharpCifs/Ntlmssp/NtlmMessage.cs
index 02827d2d0..02827d2d0 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Ntlmssp/NtlmMessage.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Ntlmssp/NtlmMessage.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Ntlmssp/Type1Message.cs b/Emby.Server.Implementations/IO/SharpCifs/Ntlmssp/Type1Message.cs
index afcf5ec7e..afcf5ec7e 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Ntlmssp/Type1Message.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Ntlmssp/Type1Message.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Ntlmssp/Type2Message.cs b/Emby.Server.Implementations/IO/SharpCifs/Ntlmssp/Type2Message.cs
index 104e5b0fd..104e5b0fd 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Ntlmssp/Type2Message.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Ntlmssp/Type2Message.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Ntlmssp/Type3Message.cs b/Emby.Server.Implementations/IO/SharpCifs/Ntlmssp/Type3Message.cs
index 9a2a37f3c..9a2a37f3c 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Ntlmssp/Type3Message.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Ntlmssp/Type3Message.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Smb/ACE.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/ACE.cs
index 73b742cfb..73b742cfb 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Smb/ACE.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/ACE.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Smb/AllocInfo.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/AllocInfo.cs
index 6ebe88293..6ebe88293 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Smb/AllocInfo.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/AllocInfo.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Smb/AndXServerMessageBlock.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/AndXServerMessageBlock.cs
index e78bff9d0..e78bff9d0 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Smb/AndXServerMessageBlock.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/AndXServerMessageBlock.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Smb/BufferCache.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/BufferCache.cs
index b36816e26..b36816e26 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Smb/BufferCache.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/BufferCache.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Smb/Dfs.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/Dfs.cs
index 2f62e5b8d..2f62e5b8d 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Smb/Dfs.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/Dfs.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Smb/DfsReferral.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/DfsReferral.cs
index 3b6091f73..3b6091f73 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Smb/DfsReferral.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/DfsReferral.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Smb/DosError.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/DosError.cs
index d89e5bafa..d89e5bafa 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Smb/DosError.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/DosError.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Smb/DosFileFilter.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/DosFileFilter.cs
index bbf7882c8..bbf7882c8 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Smb/DosFileFilter.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/DosFileFilter.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Smb/FileEntry.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/FileEntry.cs
index bbf3e7cc4..bbf3e7cc4 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Smb/FileEntry.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/FileEntry.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Smb/IInfo.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/IInfo.cs
index b0e40c5cd..b0e40c5cd 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Smb/IInfo.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/IInfo.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Smb/NetServerEnum2.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/NetServerEnum2.cs
index b4a02d8c3..b4a02d8c3 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Smb/NetServerEnum2.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/NetServerEnum2.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Smb/NetServerEnum2Response.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/NetServerEnum2Response.cs
index 9a0e5e3d5..9a0e5e3d5 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Smb/NetServerEnum2Response.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/NetServerEnum2Response.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Smb/NetShareEnum.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/NetShareEnum.cs
index 1b0c6f931..1b0c6f931 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Smb/NetShareEnum.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/NetShareEnum.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Smb/NetShareEnumResponse.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/NetShareEnumResponse.cs
index 408f8e4d1..408f8e4d1 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Smb/NetShareEnumResponse.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/NetShareEnumResponse.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Smb/NtStatus.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/NtStatus.cs
index 511e7ae84..511e7ae84 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Smb/NtStatus.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/NtStatus.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Smb/NtTransQuerySecurityDesc.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/NtTransQuerySecurityDesc.cs
index 6a83543b1..6a83543b1 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Smb/NtTransQuerySecurityDesc.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/NtTransQuerySecurityDesc.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Smb/NtTransQuerySecurityDescResponse.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/NtTransQuerySecurityDescResponse.cs
index 9365d5154..9365d5154 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Smb/NtTransQuerySecurityDescResponse.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/NtTransQuerySecurityDescResponse.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Smb/NtlmAuthenticator.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/NtlmAuthenticator.cs
index 853364f8e..853364f8e 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Smb/NtlmAuthenticator.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/NtlmAuthenticator.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Smb/NtlmChallenge.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/NtlmChallenge.cs
index 745b1f663..745b1f663 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Smb/NtlmChallenge.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/NtlmChallenge.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Smb/NtlmContext.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/NtlmContext.cs
index 44266f974..44266f974 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Smb/NtlmContext.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/NtlmContext.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Smb/NtlmPasswordAuthentication.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/NtlmPasswordAuthentication.cs
index ec3899fe9..ec3899fe9 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Smb/NtlmPasswordAuthentication.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/NtlmPasswordAuthentication.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Smb/Principal.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/Principal.cs
index 14a5479e3..14a5479e3 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Smb/Principal.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/Principal.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Smb/SID.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/SID.cs
index a6ad59fb1..a6ad59fb1 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Smb/SID.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/SID.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Smb/SecurityDescriptor.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/SecurityDescriptor.cs
index 8a424a019..8a424a019 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Smb/SecurityDescriptor.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/SecurityDescriptor.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Smb/ServerMessageBlock.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/ServerMessageBlock.cs
index cb38c89fa..cb38c89fa 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Smb/ServerMessageBlock.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/ServerMessageBlock.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Smb/SigningDigest.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/SigningDigest.cs
index 9f57e887b..9f57e887b 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Smb/SigningDigest.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/SigningDigest.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Smb/SmbAuthException.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbAuthException.cs
index defaea71b..defaea71b 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Smb/SmbAuthException.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbAuthException.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Smb/SmbComBlankResponse.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbComBlankResponse.cs
index 2295de5b9..2295de5b9 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Smb/SmbComBlankResponse.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbComBlankResponse.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Smb/SmbComClose.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbComClose.cs
index 4a160f518..4a160f518 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Smb/SmbComClose.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbComClose.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Smb/SmbComCreateDirectory.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbComCreateDirectory.cs
index 7549db01a..7549db01a 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Smb/SmbComCreateDirectory.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbComCreateDirectory.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Smb/SmbComDelete.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbComDelete.cs
index d055d2446..d055d2446 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Smb/SmbComDelete.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbComDelete.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Smb/SmbComDeleteDirectory.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbComDeleteDirectory.cs
index 240139a17..240139a17 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Smb/SmbComDeleteDirectory.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbComDeleteDirectory.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Smb/SmbComFindClose2.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbComFindClose2.cs
index 9b7c0c765..9b7c0c765 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Smb/SmbComFindClose2.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbComFindClose2.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Smb/SmbComLogoffAndX.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbComLogoffAndX.cs
index 8f88ccd57..8f88ccd57 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Smb/SmbComLogoffAndX.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbComLogoffAndX.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Smb/SmbComNTCreateAndX.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbComNTCreateAndX.cs
index 26b5ba63a..26b5ba63a 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Smb/SmbComNTCreateAndX.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbComNTCreateAndX.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Smb/SmbComNTCreateAndXResponse.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbComNTCreateAndXResponse.cs
index 4a007bdc5..4a007bdc5 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Smb/SmbComNTCreateAndXResponse.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbComNTCreateAndXResponse.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Smb/SmbComNegotiate.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbComNegotiate.cs
index 499bffbd9..499bffbd9 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Smb/SmbComNegotiate.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbComNegotiate.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Smb/SmbComNegotiateResponse.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbComNegotiateResponse.cs
index c4cd1c129..c4cd1c129 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Smb/SmbComNegotiateResponse.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbComNegotiateResponse.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Smb/SmbComNtTransaction.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbComNtTransaction.cs
index b5d2cf947..b5d2cf947 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Smb/SmbComNtTransaction.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbComNtTransaction.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Smb/SmbComNtTransactionResponse.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbComNtTransactionResponse.cs
index 88d73528a..88d73528a 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Smb/SmbComNtTransactionResponse.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbComNtTransactionResponse.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Smb/SmbComOpenAndX.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbComOpenAndX.cs
index de11e2a6a..de11e2a6a 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Smb/SmbComOpenAndX.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbComOpenAndX.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Smb/SmbComOpenAndXResponse.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbComOpenAndXResponse.cs
index 9c49d19a8..9c49d19a8 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Smb/SmbComOpenAndXResponse.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbComOpenAndXResponse.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Smb/SmbComQueryInformation.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbComQueryInformation.cs
index a528dbb11..a528dbb11 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Smb/SmbComQueryInformation.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbComQueryInformation.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Smb/SmbComQueryInformationResponse.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbComQueryInformationResponse.cs
index 040f081f0..040f081f0 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Smb/SmbComQueryInformationResponse.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbComQueryInformationResponse.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Smb/SmbComReadAndX.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbComReadAndX.cs
index e75179700..e75179700 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Smb/SmbComReadAndX.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbComReadAndX.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Smb/SmbComReadAndXResponse.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbComReadAndXResponse.cs
index 4d857aa2c..4d857aa2c 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Smb/SmbComReadAndXResponse.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbComReadAndXResponse.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Smb/SmbComRename.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbComRename.cs
index 0ac57dd3e..0ac57dd3e 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Smb/SmbComRename.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbComRename.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Smb/SmbComSessionSetupAndX.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbComSessionSetupAndX.cs
index a1642391c..a1642391c 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Smb/SmbComSessionSetupAndX.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbComSessionSetupAndX.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Smb/SmbComSessionSetupAndXResponse.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbComSessionSetupAndXResponse.cs
index a3b80a669..a3b80a669 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Smb/SmbComSessionSetupAndXResponse.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbComSessionSetupAndXResponse.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Smb/SmbComTransaction.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbComTransaction.cs
index b3aeaaf7d..b3aeaaf7d 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Smb/SmbComTransaction.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbComTransaction.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Smb/SmbComTransactionResponse.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbComTransactionResponse.cs
index 35f87594d..35f87594d 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Smb/SmbComTransactionResponse.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbComTransactionResponse.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Smb/SmbComTreeConnectAndX.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbComTreeConnectAndX.cs
index 67ad04f5f..67ad04f5f 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Smb/SmbComTreeConnectAndX.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbComTreeConnectAndX.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Smb/SmbComTreeConnectAndXResponse.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbComTreeConnectAndXResponse.cs
index add660b26..add660b26 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Smb/SmbComTreeConnectAndXResponse.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbComTreeConnectAndXResponse.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Smb/SmbComTreeDisconnect.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbComTreeDisconnect.cs
index d9eb5b2eb..d9eb5b2eb 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Smb/SmbComTreeDisconnect.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbComTreeDisconnect.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Smb/SmbComWrite.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbComWrite.cs
index 418a69d1d..418a69d1d 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Smb/SmbComWrite.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbComWrite.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Smb/SmbComWriteAndX.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbComWriteAndX.cs
index b182fd7ff..b182fd7ff 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Smb/SmbComWriteAndX.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbComWriteAndX.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Smb/SmbComWriteAndXResponse.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbComWriteAndXResponse.cs
index c6749b6cb..c6749b6cb 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Smb/SmbComWriteAndXResponse.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbComWriteAndXResponse.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Smb/SmbComWriteResponse.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbComWriteResponse.cs
index 785d406c1..785d406c1 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Smb/SmbComWriteResponse.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbComWriteResponse.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Smb/SmbConstants.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbConstants.cs
index 0793c7541..0793c7541 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Smb/SmbConstants.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbConstants.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Smb/SmbException.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbException.cs
index ea8a0b846..ea8a0b846 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Smb/SmbException.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbException.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Smb/SmbFile.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbFile.cs
index 151ec35c4..151ec35c4 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Smb/SmbFile.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbFile.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Smb/SmbFileExtensions.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbFileExtensions.cs
index 2ebcfa20f..2ebcfa20f 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Smb/SmbFileExtensions.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbFileExtensions.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Smb/SmbFileFilter.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbFileFilter.cs
index 196bfc1b6..196bfc1b6 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Smb/SmbFileFilter.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbFileFilter.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Smb/SmbFileInputStream.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbFileInputStream.cs
index a9a0ea112..a9a0ea112 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Smb/SmbFileInputStream.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbFileInputStream.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Smb/SmbFileOutputStream.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbFileOutputStream.cs
index 58c704dd7..58c704dd7 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Smb/SmbFileOutputStream.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbFileOutputStream.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Smb/SmbFilenameFilter.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbFilenameFilter.cs
index b66dc133a..b66dc133a 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Smb/SmbFilenameFilter.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbFilenameFilter.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Smb/SmbNamedPipe.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbNamedPipe.cs
index f09e16cca..f09e16cca 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Smb/SmbNamedPipe.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbNamedPipe.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Smb/SmbRandomAccessFile.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbRandomAccessFile.cs
index 445a0656c..445a0656c 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Smb/SmbRandomAccessFile.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbRandomAccessFile.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Smb/SmbSession.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbSession.cs
index 6dc5087d0..6dc5087d0 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Smb/SmbSession.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbSession.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Smb/SmbShareInfo.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbShareInfo.cs
index 811c76794..811c76794 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Smb/SmbShareInfo.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbShareInfo.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Smb/SmbTransport.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbTransport.cs
index 800d6d9bc..800d6d9bc 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Smb/SmbTransport.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbTransport.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Smb/SmbTree.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbTree.cs
index 8dc068c4c..8dc068c4c 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Smb/SmbTree.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbTree.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Smb/Trans2FindFirst2.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/Trans2FindFirst2.cs
index 2ef874882..2ef874882 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Smb/Trans2FindFirst2.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/Trans2FindFirst2.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Smb/Trans2FindFirst2Response.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/Trans2FindFirst2Response.cs
index 71f780ff3..71f780ff3 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Smb/Trans2FindFirst2Response.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/Trans2FindFirst2Response.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Smb/Trans2FindNext2.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/Trans2FindNext2.cs
index cb860f799..cb860f799 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Smb/Trans2FindNext2.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/Trans2FindNext2.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Smb/Trans2GetDfsReferral.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/Trans2GetDfsReferral.cs
index c83de7973..c83de7973 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Smb/Trans2GetDfsReferral.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/Trans2GetDfsReferral.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Smb/Trans2GetDfsReferralResponse.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/Trans2GetDfsReferralResponse.cs
index 5fa4a795d..5fa4a795d 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Smb/Trans2GetDfsReferralResponse.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/Trans2GetDfsReferralResponse.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Smb/Trans2QueryFSInformation.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/Trans2QueryFSInformation.cs
index 27b350e53..27b350e53 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Smb/Trans2QueryFSInformation.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/Trans2QueryFSInformation.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Smb/Trans2QueryFSInformationResponse.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/Trans2QueryFSInformationResponse.cs
index 2253e7b6f..2253e7b6f 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Smb/Trans2QueryFSInformationResponse.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/Trans2QueryFSInformationResponse.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Smb/Trans2QueryPathInformation.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/Trans2QueryPathInformation.cs
index b3db64790..b3db64790 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Smb/Trans2QueryPathInformation.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/Trans2QueryPathInformation.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Smb/Trans2QueryPathInformationResponse.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/Trans2QueryPathInformationResponse.cs
index 50650df62..50650df62 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Smb/Trans2QueryPathInformationResponse.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/Trans2QueryPathInformationResponse.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Smb/Trans2SetFileInformation.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/Trans2SetFileInformation.cs
index 289cab866..289cab866 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Smb/Trans2SetFileInformation.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/Trans2SetFileInformation.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Smb/Trans2SetFileInformationResponse.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/Trans2SetFileInformationResponse.cs
index b21f356b4..b21f356b4 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Smb/Trans2SetFileInformationResponse.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/Trans2SetFileInformationResponse.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Smb/TransCallNamedPipe.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/TransCallNamedPipe.cs
index 404af0aaa..404af0aaa 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Smb/TransCallNamedPipe.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/TransCallNamedPipe.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Smb/TransCallNamedPipeResponse.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/TransCallNamedPipeResponse.cs
index b86cc7fdb..b86cc7fdb 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Smb/TransCallNamedPipeResponse.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/TransCallNamedPipeResponse.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Smb/TransPeekNamedPipe.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/TransPeekNamedPipe.cs
index 9b80bbe1e..9b80bbe1e 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Smb/TransPeekNamedPipe.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/TransPeekNamedPipe.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Smb/TransPeekNamedPipeResponse.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/TransPeekNamedPipeResponse.cs
index 6bcf2d07e..6bcf2d07e 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Smb/TransPeekNamedPipeResponse.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/TransPeekNamedPipeResponse.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Smb/TransTransactNamedPipe.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/TransTransactNamedPipe.cs
index 1b6ec9cca..1b6ec9cca 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Smb/TransTransactNamedPipe.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/TransTransactNamedPipe.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Smb/TransTransactNamedPipeResponse.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/TransTransactNamedPipeResponse.cs
index b8d14781c..b8d14781c 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Smb/TransTransactNamedPipeResponse.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/TransTransactNamedPipeResponse.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Smb/TransWaitNamedPipe.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/TransWaitNamedPipe.cs
index a184665aa..a184665aa 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Smb/TransWaitNamedPipe.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/TransWaitNamedPipe.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Smb/TransWaitNamedPipeResponse.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/TransWaitNamedPipeResponse.cs
index a62a82ec7..a62a82ec7 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Smb/TransWaitNamedPipeResponse.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/TransWaitNamedPipeResponse.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Smb/TransactNamedPipeInputStream.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/TransactNamedPipeInputStream.cs
index 46d418582..46d418582 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Smb/TransactNamedPipeInputStream.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/TransactNamedPipeInputStream.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Smb/TransactNamedPipeOutputStream.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/TransactNamedPipeOutputStream.cs
index d3e8d3e1a..d3e8d3e1a 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Smb/TransactNamedPipeOutputStream.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/TransactNamedPipeOutputStream.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Smb/WinError.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/WinError.cs
index daecc5407..daecc5407 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Smb/WinError.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/WinError.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/UniAddress.cs b/Emby.Server.Implementations/IO/SharpCifs/UniAddress.cs
index 816fbe781..816fbe781 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/UniAddress.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/UniAddress.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Util/Base64.cs b/Emby.Server.Implementations/IO/SharpCifs/Util/Base64.cs
index 4770f1354..4770f1354 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Util/Base64.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Util/Base64.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Util/DES.cs b/Emby.Server.Implementations/IO/SharpCifs/Util/DES.cs
index c23b14cf8..c23b14cf8 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Util/DES.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Util/DES.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Util/Encdec.cs b/Emby.Server.Implementations/IO/SharpCifs/Util/Encdec.cs
index 7e4d57705..7e4d57705 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Util/Encdec.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Util/Encdec.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Util/HMACT64.cs b/Emby.Server.Implementations/IO/SharpCifs/Util/HMACT64.cs
index 9ab31d61b..9ab31d61b 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Util/HMACT64.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Util/HMACT64.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Util/Hexdump.cs b/Emby.Server.Implementations/IO/SharpCifs/Util/Hexdump.cs
index 7e53f76e3..7e53f76e3 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Util/Hexdump.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Util/Hexdump.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Util/LogStream.cs b/Emby.Server.Implementations/IO/SharpCifs/Util/LogStream.cs
index 9dd130b50..9dd130b50 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Util/LogStream.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Util/LogStream.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Util/MD4.cs b/Emby.Server.Implementations/IO/SharpCifs/Util/MD4.cs
index 99eb6ade6..99eb6ade6 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Util/MD4.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Util/MD4.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Util/RC4.cs b/Emby.Server.Implementations/IO/SharpCifs/Util/RC4.cs
index b17e076e7..b17e076e7 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Util/RC4.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Util/RC4.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/AbstractMap.cs b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/AbstractMap.cs
index 2868a840a..2868a840a 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/AbstractMap.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/AbstractMap.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/Arrays.cs b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/Arrays.cs
index b3a0a85fa..b3a0a85fa 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/Arrays.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/Arrays.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/BufferedReader.cs b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/BufferedReader.cs
index b3824b0d2..b3824b0d2 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/BufferedReader.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/BufferedReader.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/BufferedWriter.cs b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/BufferedWriter.cs
index 64a45915a..64a45915a 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/BufferedWriter.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/BufferedWriter.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/CharBuffer.cs b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/CharBuffer.cs
index 76ca2dc95..76ca2dc95 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/CharBuffer.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/CharBuffer.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/CharSequence.cs b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/CharSequence.cs
index fa2acf7bd..fa2acf7bd 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/CharSequence.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/CharSequence.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/Collections.cs b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/Collections.cs
index 4432e62fb..4432e62fb 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/Collections.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/Collections.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/ConcurrentHashMap.cs b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/ConcurrentHashMap.cs
index 7f464ad36..7f464ad36 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/ConcurrentHashMap.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/ConcurrentHashMap.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/DateFormat.cs b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/DateFormat.cs
index 9a3b7ec4a..9a3b7ec4a 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/DateFormat.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/DateFormat.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/EnumeratorWrapper.cs b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/EnumeratorWrapper.cs
index f8efdde2a..f8efdde2a 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/EnumeratorWrapper.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/EnumeratorWrapper.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/Exceptions.cs b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/Exceptions.cs
index ec88b2849..ec88b2849 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/Exceptions.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/Exceptions.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/Extensions.cs b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/Extensions.cs
index 1716adef7..1716adef7 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/Extensions.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/Extensions.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/FileInputStream.cs b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/FileInputStream.cs
index 25c5e06e0..25c5e06e0 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/FileInputStream.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/FileInputStream.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/FileOutputStream.cs b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/FileOutputStream.cs
index bf8029488..bf8029488 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/FileOutputStream.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/FileOutputStream.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/FilePath.cs b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/FilePath.cs
index 1b2f5eddc..1b2f5eddc 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/FilePath.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/FilePath.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/FileReader.cs b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/FileReader.cs
index 7a0c1f90e..7a0c1f90e 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/FileReader.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/FileReader.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/FileWriter.cs b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/FileWriter.cs
index 0675c238b..0675c238b 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/FileWriter.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/FileWriter.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/FilterInputStream.cs b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/FilterInputStream.cs
index dfc0ba264..dfc0ba264 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/FilterInputStream.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/FilterInputStream.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/FilterOutputStream.cs b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/FilterOutputStream.cs
index 4863105ed..4863105ed 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/FilterOutputStream.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/FilterOutputStream.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/Hashtable.cs b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/Hashtable.cs
index c2c53485d..c2c53485d 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/Hashtable.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/Hashtable.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/HttpURLConnection.cs b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/HttpURLConnection.cs
index ace314eee..ace314eee 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/HttpURLConnection.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/HttpURLConnection.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/ICallable.cs b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/ICallable.cs
index d847cb497..d847cb497 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/ICallable.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/ICallable.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/IConcurrentMap.cs b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/IConcurrentMap.cs
index dead24244..dead24244 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/IConcurrentMap.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/IConcurrentMap.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/IExecutor.cs b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/IExecutor.cs
index 5f76c2ed5..5f76c2ed5 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/IExecutor.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/IExecutor.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/IFilenameFilter.cs b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/IFilenameFilter.cs
index fe2eb6a3d..fe2eb6a3d 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/IFilenameFilter.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/IFilenameFilter.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/IFuture.cs b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/IFuture.cs
index 5215e4502..5215e4502 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/IFuture.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/IFuture.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/IPrivilegedAction.cs b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/IPrivilegedAction.cs
index 4a5e92f9b..4a5e92f9b 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/IPrivilegedAction.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/IPrivilegedAction.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/IRunnable.cs b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/IRunnable.cs
index 7f6ae5533..7f6ae5533 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/IRunnable.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/IRunnable.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/InputStream.cs b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/InputStream.cs
index 2f3f070b5..2f3f070b5 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/InputStream.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/InputStream.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/InputStreamReader.cs b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/InputStreamReader.cs
index f9f1983b8..f9f1983b8 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/InputStreamReader.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/InputStreamReader.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/Iterator.cs b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/Iterator.cs
index 634c7b404..634c7b404 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/Iterator.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/Iterator.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/LinkageError.cs b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/LinkageError.cs
index 9f4970bdd..9f4970bdd 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/LinkageError.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/LinkageError.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/MD5.cs b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/MD5.cs
index 50f3fa43b..50f3fa43b 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/MD5.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/MD5.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/MD5Managed.cs b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/MD5Managed.cs
index e74a05abf..e74a05abf 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/MD5Managed.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/MD5Managed.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/Matcher.cs b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/Matcher.cs
index d0bd79aa2..d0bd79aa2 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/Matcher.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/Matcher.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/MessageDigest.cs b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/MessageDigest.cs
index 5562f9d36..5562f9d36 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/MessageDigest.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/MessageDigest.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/NetworkStream.cs b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/NetworkStream.cs
index 05599cea3..05599cea3 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/NetworkStream.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/NetworkStream.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/ObjectInputStream.cs b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/ObjectInputStream.cs
index dc3d6ccc3..dc3d6ccc3 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/ObjectInputStream.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/ObjectInputStream.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/ObjectOutputStream.cs b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/ObjectOutputStream.cs
index 97f3a2cfd..97f3a2cfd 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/ObjectOutputStream.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/ObjectOutputStream.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/OutputStream.cs b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/OutputStream.cs
index 0e6189f0c..0e6189f0c 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/OutputStream.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/OutputStream.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/OutputStreamWriter.cs b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/OutputStreamWriter.cs
index 6313b7c79..6313b7c79 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/OutputStreamWriter.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/OutputStreamWriter.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/PipedInputStream.cs b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/PipedInputStream.cs
index d5004c988..d5004c988 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/PipedInputStream.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/PipedInputStream.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/PipedOutputStream.cs b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/PipedOutputStream.cs
index 4c46f1ec0..4c46f1ec0 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/PipedOutputStream.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/PipedOutputStream.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/PrintWriter.cs b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/PrintWriter.cs
index c366aa665..c366aa665 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/PrintWriter.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/PrintWriter.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/Properties.cs b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/Properties.cs
index 3d886ea87..3d886ea87 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/Properties.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/Properties.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/RandomAccessFile.cs b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/RandomAccessFile.cs
index bf3596212..bf3596212 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/RandomAccessFile.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/RandomAccessFile.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/ReentrantLock.cs b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/ReentrantLock.cs
index aa34db9d0..aa34db9d0 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/ReentrantLock.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/ReentrantLock.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/Reference.cs b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/Reference.cs
index c7fbe9a48..c7fbe9a48 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/Reference.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/Reference.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/Runtime.cs b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/Runtime.cs
index 74ff16b1b..74ff16b1b 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/Runtime.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/Runtime.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/SimpleDateFormat.cs b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/SimpleDateFormat.cs
index 35334b4f2..35334b4f2 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/SimpleDateFormat.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/SimpleDateFormat.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/SocketEx.cs b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/SocketEx.cs
index 4d0651949..4d0651949 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/SocketEx.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/SocketEx.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/StringTokenizer.cs b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/StringTokenizer.cs
index 74c14cff6..74c14cff6 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/StringTokenizer.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/StringTokenizer.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/SynchronizedList.cs b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/SynchronizedList.cs
index c105a8bab..c105a8bab 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/SynchronizedList.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/SynchronizedList.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/Thread.cs b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/Thread.cs
index 59f3df469..59f3df469 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/Thread.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/Thread.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/ThreadFactory.cs b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/ThreadFactory.cs
index 7276c06a2..7276c06a2 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/ThreadFactory.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/ThreadFactory.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/ThreadPoolExecutor.cs b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/ThreadPoolExecutor.cs
index ef19b8bff..ef19b8bff 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/ThreadPoolExecutor.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/ThreadPoolExecutor.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/WrappedSystemStream.cs b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/WrappedSystemStream.cs
index ef2993fa6..ef2993fa6 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Util/Sharpen/WrappedSystemStream.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/WrappedSystemStream.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Util/Transport/Request.cs b/Emby.Server.Implementations/IO/SharpCifs/Util/Transport/Request.cs
index 6e0c3fc7b..6e0c3fc7b 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Util/Transport/Request.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Util/Transport/Request.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Util/Transport/Response.cs b/Emby.Server.Implementations/IO/SharpCifs/Util/Transport/Response.cs
index 702fea918..702fea918 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Util/Transport/Response.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Util/Transport/Response.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Util/Transport/Transport.cs b/Emby.Server.Implementations/IO/SharpCifs/Util/Transport/Transport.cs
index b02936ca6..b02936ca6 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Util/Transport/Transport.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Util/Transport/Transport.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Util/Transport/TransportException.cs b/Emby.Server.Implementations/IO/SharpCifs/Util/Transport/TransportException.cs
index bd0455197..bd0455197 100644
--- a/Emby.Common.Implementations/IO/SharpCifs/Util/Transport/TransportException.cs
+++ b/Emby.Server.Implementations/IO/SharpCifs/Util/Transport/TransportException.cs
diff --git a/Emby.Common.Implementations/IO/SharpCifsFileSystem.cs b/Emby.Server.Implementations/IO/SharpCifsFileSystem.cs
index 64cac7623..1d21796b1 100644
--- a/Emby.Common.Implementations/IO/SharpCifsFileSystem.cs
+++ b/Emby.Server.Implementations/IO/SharpCifsFileSystem.cs
@@ -3,13 +3,10 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
-using System.Threading.Tasks;
-using SharpCifs.Smb;
using MediaBrowser.Model.IO;
-using MediaBrowser.Model.Logging;
-using MediaBrowser.Model.System;
+using SharpCifs.Smb;
-namespace Emby.Common.Implementations.IO
+namespace Emby.Server.Implementations.IO
{
public class SharpCifsFileSystem
{
diff --git a/Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs b/Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs
index b8ce23a42..3f9ea79c6 100644
--- a/Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs
+++ b/Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs
@@ -37,12 +37,12 @@ namespace Emby.Server.Implementations.Images
ImageProcessor = imageProcessor;
}
- protected virtual bool Supports(IHasImages item)
+ protected virtual bool Supports(IHasMetadata item)
{
return true;
}
- public virtual IEnumerable<ImageType> GetSupportedImages(IHasImages item)
+ public virtual IEnumerable<ImageType> GetSupportedImages(IHasMetadata item)
{
return new List<ImageType>
{
@@ -51,7 +51,7 @@ namespace Emby.Server.Implementations.Images
};
}
- private IEnumerable<ImageType> GetEnabledImages(IHasImages item)
+ private IEnumerable<ImageType> GetEnabledImages(IHasMetadata item)
{
//var options = ProviderManager.GetMetadataOptions(item);
@@ -84,7 +84,7 @@ namespace Emby.Server.Implementations.Images
return updateType;
}
- protected async Task<ItemUpdateType> FetchAsync(IHasImages item, ImageType imageType, MetadataRefreshOptions options, CancellationToken cancellationToken)
+ protected async Task<ItemUpdateType> FetchAsync(IHasMetadata item, ImageType imageType, MetadataRefreshOptions options, CancellationToken cancellationToken)
{
var image = item.GetImageInfo(imageType, 0);
@@ -106,7 +106,7 @@ namespace Emby.Server.Implementations.Images
return await FetchToFileInternal(item, items, imageType, cancellationToken).ConfigureAwait(false);
}
- protected async Task<ItemUpdateType> FetchToFileInternal(IHasImages item,
+ protected async Task<ItemUpdateType> FetchToFileInternal(IHasMetadata item,
List<BaseItem> itemsWithImages,
ImageType imageType,
CancellationToken cancellationToken)
@@ -132,14 +132,14 @@ namespace Emby.Server.Implementations.Images
return ItemUpdateType.ImageUpdate;
}
- protected abstract List<BaseItem> GetItemsWithImages(IHasImages item);
+ protected abstract List<BaseItem> GetItemsWithImages(IHasMetadata item);
- protected string CreateThumbCollage(IHasImages primaryItem, List<BaseItem> items, string outputPath)
+ protected string CreateThumbCollage(IHasMetadata primaryItem, List<BaseItem> items, string outputPath)
{
return CreateCollage(primaryItem, items, outputPath, 640, 360);
}
- protected virtual IEnumerable<string> GetStripCollageImagePaths(IHasImages primaryItem, IEnumerable<BaseItem> items)
+ protected virtual IEnumerable<string> GetStripCollageImagePaths(IHasMetadata primaryItem, IEnumerable<BaseItem> items)
{
return items
.Select(i =>
@@ -161,22 +161,22 @@ namespace Emby.Server.Implementations.Images
.Where(i => !string.IsNullOrWhiteSpace(i));
}
- protected string CreatePosterCollage(IHasImages primaryItem, List<BaseItem> items, string outputPath)
+ protected string CreatePosterCollage(IHasMetadata primaryItem, List<BaseItem> items, string outputPath)
{
return CreateCollage(primaryItem, items, outputPath, 400, 600);
}
- protected string CreateSquareCollage(IHasImages primaryItem, List<BaseItem> items, string outputPath)
+ protected string CreateSquareCollage(IHasMetadata primaryItem, List<BaseItem> items, string outputPath)
{
return CreateCollage(primaryItem, items, outputPath, 600, 600);
}
- protected string CreateThumbCollage(IHasImages primaryItem, List<BaseItem> items, string outputPath, int width, int height)
+ protected string CreateThumbCollage(IHasMetadata primaryItem, List<BaseItem> items, string outputPath, int width, int height)
{
return CreateCollage(primaryItem, items, outputPath, width, height);
}
- private string CreateCollage(IHasImages primaryItem, List<BaseItem> items, string outputPath, int width, int height)
+ private string CreateCollage(IHasMetadata primaryItem, List<BaseItem> items, string outputPath, int width, int height)
{
FileSystem.CreateDirectory(FileSystem.GetDirectoryName(outputPath));
@@ -207,7 +207,7 @@ namespace Emby.Server.Implementations.Images
get { return "Dynamic Image Provider"; }
}
- protected virtual string CreateImage(IHasImages item,
+ protected virtual string CreateImage(IHasMetadata item,
List<BaseItem> itemsWithImages,
string outputPathWithoutExtension,
ImageType imageType,
@@ -267,7 +267,7 @@ namespace Emby.Server.Implementations.Images
return false;
}
- protected bool HasChanged(IHasImages item, ImageType type)
+ protected bool HasChanged(IHasMetadata item, ImageType type)
{
var image = item.GetImageInfo(type, 0);
@@ -293,20 +293,16 @@ namespace Emby.Server.Implementations.Images
return true;
}
- protected List<BaseItem> GetFinalItems(List<BaseItem> items)
+ protected List<BaseItem> GetFinalItems(IEnumerable<BaseItem> items)
{
return GetFinalItems(items, 4);
}
- protected virtual List<BaseItem> GetFinalItems(List<BaseItem> items, int limit)
+ protected virtual List<BaseItem> GetFinalItems(IEnumerable<BaseItem> items, int limit)
{
- // Rotate the images once every x days
- var random = DateTime.Now.DayOfYear % MaxImageAgeDays;
-
return items
- .OrderBy(i => (random + string.Empty + items.IndexOf(i)).GetMD5())
+ .OrderBy(i => Guid.NewGuid())
.Take(limit)
- .OrderBy(i => i.Name)
.ToList();
}
diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs
index 4846a5768..8c5ecf782 100644
--- a/Emby.Server.Implementations/Library/LibraryManager.cs
+++ b/Emby.Server.Implementations/Library/LibraryManager.cs
@@ -136,14 +136,6 @@ namespace Emby.Server.Implementations.Library
/// <value>The configuration manager.</value>
private IServerConfigurationManager ConfigurationManager { get; set; }
- /// <summary>
- /// A collection of items that may be referenced from multiple physical places in the library
- /// (typically, multiple user roots). We store them here and be sure they all reference a
- /// single instance.
- /// </summary>
- /// <value>The by reference items.</value>
- private ConcurrentDictionary<Guid, BaseItem> ByReferenceItems { get; set; }
-
private readonly Func<ILibraryMonitor> _libraryMonitorFactory;
private readonly Func<IProviderManager> _providerManagerFactory;
private readonly Func<IUserViewManager> _userviewManager;
@@ -186,7 +178,6 @@ namespace Emby.Server.Implementations.Library
_fileSystem = fileSystem;
_providerManagerFactory = providerManagerFactory;
_userviewManager = userviewManager;
- ByReferenceItems = new ConcurrentDictionary<Guid, BaseItem>();
_libraryItemsCache = new ConcurrentDictionary<Guid, BaseItem>();
ConfigurationManager.ConfigurationUpdated += ConfigurationUpdated;
@@ -362,7 +353,7 @@ namespace Emby.Server.Implementations.Library
}
else
{
- if (item is Photo)
+ if (!(item is Video))
{
return;
}
@@ -470,10 +461,10 @@ namespace Emby.Server.Implementations.Library
parent.RemoveChild(item);
}
- await ItemRepository.DeleteItem(item.Id, CancellationToken.None).ConfigureAwait(false);
+ ItemRepository.DeleteItem(item.Id, CancellationToken.None);
foreach (var child in children)
{
- await ItemRepository.DeleteItem(child.Id, CancellationToken.None).ConfigureAwait(false);
+ ItemRepository.DeleteItem(child.Id, CancellationToken.None);
}
BaseItem removed;
@@ -560,22 +551,6 @@ namespace Emby.Server.Implementations.Library
return key.GetMD5();
}
- /// <summary>
- /// Ensure supplied item has only one instance throughout
- /// </summary>
- /// <param name="item">The item.</param>
- /// <returns>The proper instance to the item</returns>
- public BaseItem GetOrAddByReferenceItem(BaseItem item)
- {
- // Add this item to our list if not there already
- if (!ByReferenceItems.TryAdd(item.Id, item))
- {
- // Already there - return the existing reference
- item = ByReferenceItems[item.Id];
- }
- return item;
- }
-
public BaseItem ResolvePath(FileSystemMetadata fileInfo,
Folder parent = null)
{
@@ -624,18 +599,16 @@ namespace Emby.Server.Implementations.Library
// When resolving the root, we need it's grandchildren (children of user views)
var flattenFolderDepth = isPhysicalRoot ? 2 : 0;
- var fileSystemDictionary = FileData.GetFilteredFileSystemEntries(directoryService, args.Path, _fileSystem, _logger, args, flattenFolderDepth: flattenFolderDepth, resolveShortcuts: isPhysicalRoot || args.IsVf);
+ var files = FileData.GetFilteredFileSystemEntries(directoryService, args.Path, _fileSystem, _logger, args, flattenFolderDepth: flattenFolderDepth, resolveShortcuts: isPhysicalRoot || args.IsVf);
// Need to remove subpaths that may have been resolved from shortcuts
// Example: if \\server\movies exists, then strip out \\server\movies\action
if (isPhysicalRoot)
{
- var paths = NormalizeRootPathList(fileSystemDictionary.Values);
-
- fileSystemDictionary = paths.ToDictionary(i => i.FullName);
+ files = NormalizeRootPathList(files).ToArray();
}
- args.FileSystemDictionary = fileSystemDictionary;
+ args.FileSystemChildren = files;
}
// Check to see if we should resolve based on our contents
@@ -681,7 +654,7 @@ namespace Emby.Server.Implementations.Library
return false;
}
- public IEnumerable<FileSystemMetadata> NormalizeRootPathList(IEnumerable<FileSystemMetadata> paths)
+ public List<FileSystemMetadata> NormalizeRootPathList(IEnumerable<FileSystemMetadata> paths)
{
var originalList = paths.ToList();
@@ -873,8 +846,7 @@ namespace Emby.Server.Implementations.Library
{
Path = path,
IsFolder = isFolder,
- SortBy = new[] { ItemSortBy.DateCreated },
- SortOrder = SortOrder.Descending,
+ OrderBy = new[] { ItemSortBy.DateCreated }.Select(i => new Tuple<string, SortOrder>(i, SortOrder.Descending)).ToArray(),
Limit = 1,
DtoOptions = new DtoOptions(true)
};
@@ -1024,8 +996,7 @@ namespace Emby.Server.Implementations.Library
Path = path
};
- var task = CreateItem(item, CancellationToken.None);
- Task.WaitAll(task);
+ CreateItem(item, CancellationToken.None);
}
return item;
@@ -1197,6 +1168,8 @@ namespace Emby.Server.Implementations.Library
progress.Report(percent * 100);
}
+ ItemRepository.UpdateInheritedValues(cancellationToken);
+
progress.Report(100);
}
@@ -1231,7 +1204,7 @@ namespace Emby.Server.Implementations.Library
.Where(i => string.Equals(ShortcutFileExtension, Path.GetExtension(i), StringComparison.OrdinalIgnoreCase))
.Select(_fileSystem.ResolveShortcut)
.OrderBy(i => i)
- .ToList(),
+ .ToArray(),
CollectionType = GetCollectionType(dir)
};
@@ -1298,7 +1271,7 @@ namespace Emby.Server.Implementations.Library
return item;
}
- public IEnumerable<BaseItem> GetItemList(InternalItemsQuery query, bool allowExternalContent)
+ public List<BaseItem> GetItemList(InternalItemsQuery query, bool allowExternalContent)
{
if (query.Recursive && query.ParentId.HasValue)
{
@@ -1317,7 +1290,7 @@ namespace Emby.Server.Implementations.Library
return ItemRepository.GetItemList(query);
}
- public IEnumerable<BaseItem> GetItemList(InternalItemsQuery query)
+ public List<BaseItem> GetItemList(InternalItemsQuery query)
{
return GetItemList(query, true);
}
@@ -1341,7 +1314,7 @@ namespace Emby.Server.Implementations.Library
return ItemRepository.GetCount(query);
}
- public IEnumerable<BaseItem> GetItemList(InternalItemsQuery query, List<BaseItem> parents)
+ public List<BaseItem> GetItemList(InternalItemsQuery query, List<BaseItem> parents)
{
SetTopParentIdsOrAncestors(query, parents);
@@ -1515,9 +1488,11 @@ namespace Emby.Server.Implementations.Library
return ItemRepository.GetItems(query);
}
+ var list = ItemRepository.GetItemList(query);
+
return new QueryResult<BaseItem>
{
- Items = ItemRepository.GetItemList(query).ToArray()
+ Items = list.ToArray(list.Count)
};
}
@@ -1575,7 +1550,7 @@ namespace Emby.Server.Implementations.Library
IncludeHidden = true,
IncludeExternalContent = allowExternalContent
- }, CancellationToken.None).Result.ToList();
+ }, CancellationToken.None).Result;
query.TopParentIds = userViews.SelectMany(i => GetTopParentIdsForQuery(i, user)).Select(i => i.ToString("N")).ToArray();
}
@@ -1801,6 +1776,37 @@ namespace Emby.Server.Implementations.Library
return orderedItems ?? items;
}
+ public IEnumerable<BaseItem> Sort(IEnumerable<BaseItem> items, User user, IEnumerable<Tuple<string, SortOrder>> orderByList)
+ {
+ var isFirst = true;
+
+ IOrderedEnumerable<BaseItem> orderedItems = null;
+
+ foreach (var orderBy in orderByList)
+ {
+ var comparer = GetComparer(orderBy.Item1, user);
+ if (comparer == null)
+ {
+ continue;
+ }
+
+ var sortOrder = orderBy.Item2;
+
+ if (isFirst)
+ {
+ orderedItems = sortOrder == SortOrder.Descending ? items.OrderByDescending(i => i, comparer) : items.OrderBy(i => i, comparer);
+ }
+ else
+ {
+ orderedItems = sortOrder == SortOrder.Descending ? orderedItems.ThenByDescending(i => i, comparer) : orderedItems.ThenBy(i => i, comparer);
+ }
+
+ isFirst = false;
+ }
+
+ return orderedItems ?? items;
+ }
+
/// <summary>
/// Gets the comparer.
/// </summary>
@@ -1835,9 +1841,9 @@ namespace Emby.Server.Implementations.Library
/// <param name="item">The item.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
- public Task CreateItem(BaseItem item, CancellationToken cancellationToken)
+ public void CreateItem(BaseItem item, CancellationToken cancellationToken)
{
- return CreateItems(new[] { item }, cancellationToken);
+ CreateItems(new[] { item }, cancellationToken);
}
/// <summary>
@@ -1846,11 +1852,11 @@ namespace Emby.Server.Implementations.Library
/// <param name="items">The items.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
- public async Task CreateItems(IEnumerable<BaseItem> items, CancellationToken cancellationToken)
+ public void CreateItems(IEnumerable<BaseItem> items, CancellationToken cancellationToken)
{
var list = items.ToList();
- await ItemRepository.SaveItems(list, cancellationToken).ConfigureAwait(false);
+ ItemRepository.SaveItems(list, cancellationToken);
foreach (var item in list)
{
@@ -1893,7 +1899,7 @@ namespace Emby.Server.Implementations.Library
var logName = item.LocationType == LocationType.Remote ? item.Name ?? item.Path : item.Path ?? item.Name;
_logger.Debug("Saving {0} to database.", logName);
- await ItemRepository.SaveItem(item, cancellationToken).ConfigureAwait(false);
+ ItemRepository.SaveItem(item, cancellationToken);
RegisterItem(item);
@@ -2090,7 +2096,7 @@ namespace Emby.Server.Implementations.Library
private readonly TimeSpan _viewRefreshInterval = TimeSpan.FromHours(24);
//private readonly TimeSpan _viewRefreshInterval = TimeSpan.FromMinutes(1);
- public Task<UserView> GetNamedView(User user,
+ public UserView GetNamedView(User user,
string name,
string viewType,
string sortName,
@@ -2128,7 +2134,7 @@ namespace Emby.Server.Implementations.Library
ForcedSortName = sortName
};
- await CreateItem(item, cancellationToken).ConfigureAwait(false);
+ CreateItem(item, cancellationToken);
refresh = true;
}
@@ -2159,7 +2165,7 @@ namespace Emby.Server.Implementations.Library
return item;
}
- public async Task<UserView> GetNamedView(User user,
+ public UserView GetNamedView(User user,
string name,
string parentId,
string viewType,
@@ -2196,7 +2202,7 @@ namespace Emby.Server.Implementations.Library
item.DisplayParentId = new Guid(parentId);
}
- await CreateItem(item, cancellationToken).ConfigureAwait(false);
+ CreateItem(item, cancellationToken);
isNew = true;
}
@@ -2222,7 +2228,7 @@ namespace Emby.Server.Implementations.Library
return item;
}
- public async Task<UserView> GetShadowView(BaseItem parent,
+ public UserView GetShadowView(BaseItem parent,
string viewType,
string sortName,
CancellationToken cancellationToken)
@@ -2261,7 +2267,7 @@ namespace Emby.Server.Implementations.Library
item.DisplayParentId = parentId;
- await CreateItem(item, cancellationToken).ConfigureAwait(false);
+ CreateItem(item, cancellationToken);
isNew = true;
}
@@ -2332,7 +2338,7 @@ namespace Emby.Server.Implementations.Library
item.DisplayParentId = new Guid(parentId);
}
- await CreateItem(item, cancellationToken).ConfigureAwait(false);
+ CreateItem(item, cancellationToken);
isNew = true;
}
@@ -2395,8 +2401,7 @@ namespace Emby.Server.Implementations.Library
var resolver = new EpisodeResolver(GetNamingOptions(),
new NullLogger());
- var isFolder = episode.VideoType == VideoType.BluRay || episode.VideoType == VideoType.Dvd ||
- episode.VideoType == VideoType.HdDvd;
+ var isFolder = episode.VideoType == VideoType.BluRay || episode.VideoType == VideoType.Dvd;
var locationType = episode.LocationType;
@@ -2593,7 +2598,7 @@ namespace Emby.Server.Implementations.Library
{
var namingOptions = GetNamingOptions();
- var files = owner.DetectIsInMixedFolder() ? new List<FileSystemMetadata>() : fileSystemChildren.Where(i => i.IsDirectory)
+ var files = owner.IsInMixedFolder ? new List<FileSystemMetadata>() : fileSystemChildren.Where(i => i.IsDirectory)
.Where(i => string.Equals(i.Name, BaseItem.TrailerFolderName, StringComparison.OrdinalIgnoreCase))
.SelectMany(i => _fileSystem.GetFiles(i.FullName, _videoFileExtensions, false, false))
.ToList();
@@ -2611,7 +2616,7 @@ namespace Emby.Server.Implementations.Library
var resolvers = new IItemResolver[]
{
- new GenericVideoResolver<Trailer>(this)
+ new GenericVideoResolver<Trailer>(this, _fileSystem)
};
return ResolvePaths(files, directoryService, null, new LibraryOptions(), null, resolvers)
@@ -2632,7 +2637,7 @@ namespace Emby.Server.Implementations.Library
return video;
// Sort them so that the list can be easily compared for changes
- }).OrderBy(i => i.Path).ToList();
+ }).OrderBy(i => i.Path);
}
private static readonly string[] ExtrasSubfolderNames = new[] { "extras", "specials", "shorts", "scenes", "featurettes", "behind the scenes", "deleted scenes", "interviews" };
@@ -2674,7 +2679,7 @@ namespace Emby.Server.Implementations.Library
return video;
// Sort them so that the list can be easily compared for changes
- }).OrderBy(i => i.Path).ToList();
+ }).OrderBy(i => i.Path);
}
public string GetPathAfterNetworkSubstitution(string path, BaseItem ownerItem)
@@ -2847,17 +2852,17 @@ namespace Emby.Server.Implementations.Library
return ItemRepository.GetPeopleNames(query);
}
- public Task UpdatePeople(BaseItem item, List<PersonInfo> people)
+ public void UpdatePeople(BaseItem item, List<PersonInfo> people)
{
if (!item.SupportsPeople)
{
- return Task.FromResult(true);
+ return;
}
- return ItemRepository.UpdatePeople(item.Id, people);
+ ItemRepository.UpdatePeople(item.Id, people);
}
- public async Task<ItemImageInfo> ConvertImageToLocal(IHasImages item, ItemImageInfo image, int imageIndex)
+ public async Task<ItemImageInfo> ConvertImageToLocal(IHasMetadata item, ItemImageInfo image, int imageIndex)
{
foreach (var url in image.Path.Split('|'))
{
@@ -3083,7 +3088,7 @@ namespace Emby.Server.Implementations.Library
var topLibraryFolders = GetUserRootFolder().Children.ToList();
var info = GetVirtualFolderInfo(virtualFolderPath, topLibraryFolders, null);
- if (info.Locations.Count > 0 && info.Locations.Count != options.PathInfos.Length)
+ if (info.Locations.Length > 0 && info.Locations.Length != options.PathInfos.Length)
{
var list = options.PathInfos.ToList();
diff --git a/Emby.Server.Implementations/Library/LocalTrailerPostScanTask.cs b/Emby.Server.Implementations/Library/LocalTrailerPostScanTask.cs
index e64980dff..757e67eb4 100644
--- a/Emby.Server.Implementations/Library/LocalTrailerPostScanTask.cs
+++ b/Emby.Server.Implementations/Library/LocalTrailerPostScanTask.cs
@@ -3,6 +3,7 @@ using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Model.Entities;
using System;
+using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
@@ -45,7 +46,7 @@ namespace Emby.Server.Implementations.Library
Recursive = true,
DtoOptions = new DtoOptions(false)
- }).ToArray();
+ });
var numComplete = 0;
@@ -64,7 +65,7 @@ namespace Emby.Server.Implementations.Library
progress.Report(100);
}
- private async Task AssignTrailers(IHasTrailers item, BaseItem[] channelTrailers)
+ private async Task AssignTrailers(IHasTrailers item, IEnumerable<BaseItem> channelTrailers)
{
if (item is Game)
{
@@ -90,7 +91,7 @@ namespace Emby.Server.Implementations.Library
});
var trailerIds = trailers.Select(i => i.Id)
- .ToList();
+ .ToArray();
if (!trailerIds.SequenceEqual(item.RemoteTrailerIds))
{
diff --git a/Emby.Server.Implementations/Library/MediaSourceManager.cs b/Emby.Server.Implementations/Library/MediaSourceManager.cs
index c1360c887..d60a04353 100644
--- a/Emby.Server.Implementations/Library/MediaSourceManager.cs
+++ b/Emby.Server.Implementations/Library/MediaSourceManager.cs
@@ -49,10 +49,9 @@ namespace Emby.Server.Implementations.Library
_providers = providers.ToArray();
}
- public IEnumerable<MediaStream> GetMediaStreams(MediaStreamQuery query)
+ public List<MediaStream> GetMediaStreams(MediaStreamQuery query)
{
- var list = _itemRepo.GetMediaStreams(query)
- .ToList();
+ var list = _itemRepo.GetMediaStreams(query);
foreach (var stream in list)
{
@@ -77,7 +76,7 @@ namespace Emby.Server.Implementations.Library
return false;
}
- public IEnumerable<MediaStream> GetMediaStreams(string mediaSourceId)
+ public List<MediaStream> GetMediaStreams(string mediaSourceId)
{
var list = GetMediaStreams(new MediaStreamQuery
{
@@ -87,7 +86,7 @@ namespace Emby.Server.Implementations.Library
return GetMediaStreamsForItem(list);
}
- public IEnumerable<MediaStream> GetMediaStreams(Guid itemId)
+ public List<MediaStream> GetMediaStreams(Guid itemId)
{
var list = GetMediaStreams(new MediaStreamQuery
{
@@ -97,7 +96,7 @@ namespace Emby.Server.Implementations.Library
return GetMediaStreamsForItem(list);
}
- private IEnumerable<MediaStream> GetMediaStreamsForItem(IEnumerable<MediaStream> streams)
+ private List<MediaStream> GetMediaStreamsForItem(IEnumerable<MediaStream> streams)
{
var list = streams.ToList();
@@ -253,7 +252,7 @@ namespace Emby.Server.Implementations.Library
return sources.FirstOrDefault(i => string.Equals(i.Id, mediaSourceId, StringComparison.OrdinalIgnoreCase));
}
- public IEnumerable<MediaSourceInfo> GetStaticMediaSources(IHasMediaSources item, bool enablePathSubstitution, User user = null)
+ public List<MediaSourceInfo> GetStaticMediaSources(IHasMediaSources item, bool enablePathSubstitution, User user = null)
{
if (item == null)
{
@@ -265,7 +264,7 @@ namespace Emby.Server.Implementations.Library
return item.GetMediaSources(enablePathSubstitution);
}
- var sources = item.GetMediaSources(enablePathSubstitution).ToList();
+ var sources = item.GetMediaSources(enablePathSubstitution);
if (user != null)
{
@@ -525,6 +524,7 @@ namespace Emby.Server.Implementations.Library
public void Dispose()
{
Dispose(true);
+ GC.SuppressFinalize(this);
}
private readonly object _disposeLock = new object();
diff --git a/Emby.Server.Implementations/Library/MusicManager.cs b/Emby.Server.Implementations/Library/MusicManager.cs
index f0d07cc3c..1cbf4235a 100644
--- a/Emby.Server.Implementations/Library/MusicManager.cs
+++ b/Emby.Server.Implementations/Library/MusicManager.cs
@@ -6,6 +6,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using MediaBrowser.Controller.Dto;
+using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Querying;
namespace Emby.Server.Implementations.Library
@@ -19,27 +20,27 @@ namespace Emby.Server.Implementations.Library
_libraryManager = libraryManager;
}
- public IEnumerable<Audio> GetInstantMixFromSong(Audio item, User user, DtoOptions dtoOptions)
+ public List<BaseItem> GetInstantMixFromSong(Audio item, User user, DtoOptions dtoOptions)
{
var list = new List<Audio>
{
item
};
- return list.Concat(GetInstantMixFromGenres(item.Genres, user, dtoOptions));
+ return list.Concat(GetInstantMixFromGenres(item.Genres, user, dtoOptions)).ToList();
}
- public IEnumerable<Audio> GetInstantMixFromArtist(MusicArtist item, User user, DtoOptions dtoOptions)
+ public List<BaseItem> GetInstantMixFromArtist(MusicArtist item, User user, DtoOptions dtoOptions)
{
return GetInstantMixFromGenres(item.Genres, user, dtoOptions);
}
- public IEnumerable<Audio> GetInstantMixFromAlbum(MusicAlbum item, User user, DtoOptions dtoOptions)
+ public List<BaseItem> GetInstantMixFromAlbum(MusicAlbum item, User user, DtoOptions dtoOptions)
{
return GetInstantMixFromGenres(item.Genres, user, dtoOptions);
}
- public IEnumerable<Audio> GetInstantMixFromFolder(Folder item, User user, DtoOptions dtoOptions)
+ public List<BaseItem> GetInstantMixFromFolder(Folder item, User user, DtoOptions dtoOptions)
{
var genres = item
.GetRecursiveChildren(user, new InternalItemsQuery(user)
@@ -55,12 +56,12 @@ namespace Emby.Server.Implementations.Library
return GetInstantMixFromGenres(genres, user, dtoOptions);
}
- public IEnumerable<Audio> GetInstantMixFromPlaylist(Playlist item, User user, DtoOptions dtoOptions)
+ public List<BaseItem> GetInstantMixFromPlaylist(Playlist item, User user, DtoOptions dtoOptions)
{
return GetInstantMixFromGenres(item.Genres, user, dtoOptions);
}
- public IEnumerable<Audio> GetInstantMixFromGenres(IEnumerable<string> genres, User user, DtoOptions dtoOptions)
+ public List<BaseItem> GetInstantMixFromGenres(IEnumerable<string> genres, User user, DtoOptions dtoOptions)
{
var genreIds = genres.DistinctNames().Select(i =>
{
@@ -78,7 +79,7 @@ namespace Emby.Server.Implementations.Library
return GetInstantMixFromGenreIds(genreIds, user, dtoOptions);
}
- public IEnumerable<Audio> GetInstantMixFromGenreIds(IEnumerable<string> genreIds, User user, DtoOptions dtoOptions)
+ public List<BaseItem> GetInstantMixFromGenreIds(IEnumerable<string> genreIds, User user, DtoOptions dtoOptions)
{
return _libraryManager.GetItemList(new InternalItemsQuery(user)
{
@@ -88,14 +89,14 @@ namespace Emby.Server.Implementations.Library
Limit = 200,
- SortBy = new[] { ItemSortBy.Random },
+ OrderBy = new [] { new Tuple<string, SortOrder>(ItemSortBy.Random, SortOrder.Ascending) },
DtoOptions = dtoOptions
- }).Cast<Audio>();
+ });
}
- public IEnumerable<Audio> GetInstantMixFromItem(BaseItem item, User user, DtoOptions dtoOptions)
+ public List<BaseItem> GetInstantMixFromItem(BaseItem item, User user, DtoOptions dtoOptions)
{
var genre = item as MusicGenre;
if (genre != null)
@@ -133,7 +134,7 @@ namespace Emby.Server.Implementations.Library
return GetInstantMixFromFolder(folder, user, dtoOptions);
}
- return new Audio[] { };
+ return new List<BaseItem>();
}
}
}
diff --git a/Emby.Server.Implementations/Library/Resolvers/BaseVideoResolver.cs b/Emby.Server.Implementations/Library/Resolvers/BaseVideoResolver.cs
index 9a5d6b105..fa4f026f4 100644
--- a/Emby.Server.Implementations/Library/Resolvers/BaseVideoResolver.cs
+++ b/Emby.Server.Implementations/Library/Resolvers/BaseVideoResolver.cs
@@ -6,6 +6,7 @@ using System;
using System.IO;
using System.Linq;
using MediaBrowser.Controller.Providers;
+using MediaBrowser.Model.IO;
using MediaBrowser.Model.Logging;
namespace Emby.Server.Implementations.Library.Resolvers
@@ -18,9 +19,11 @@ namespace Emby.Server.Implementations.Library.Resolvers
where T : Video, new()
{
protected readonly ILibraryManager LibraryManager;
+ protected readonly IFileSystem FileSystem;
- protected BaseVideoResolver(ILibraryManager libraryManager)
+ protected BaseVideoResolver(ILibraryManager libraryManager, IFileSystem fileSystem)
{
+ FileSystem = fileSystem;
LibraryManager = libraryManager;
}
@@ -178,11 +181,6 @@ namespace Emby.Server.Implementations.Library.Resolvers
{
video.VideoType = VideoType.Dvd;
}
- else if (string.Equals(videoInfo.StubType, "hddvd", StringComparison.OrdinalIgnoreCase))
- {
- video.VideoType = VideoType.HdDvd;
- video.IsHD = true;
- }
else if (string.Equals(videoInfo.StubType, "bluray", StringComparison.OrdinalIgnoreCase))
{
video.VideoType = VideoType.BluRay;
@@ -276,7 +274,7 @@ namespace Emby.Server.Implementations.Library.Resolvers
return false;
}
- return directoryService.GetFilePaths(fullPath).Any(i => string.Equals(Path.GetExtension(i), ".vob", StringComparison.OrdinalIgnoreCase));
+ return FileSystem.GetFilePaths(fullPath).Any(i => string.Equals(Path.GetExtension(i), ".vob", StringComparison.OrdinalIgnoreCase));
}
/// <summary>
diff --git a/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs b/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs
index 69563e5a0..1e5c0beed 100644
--- a/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs
+++ b/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs
@@ -23,11 +23,6 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
/// </summary>
public class MovieResolver : BaseVideoResolver<Video>, IMultiItemResolver
{
- public MovieResolver(ILibraryManager libraryManager)
- : base(libraryManager)
- {
- }
-
/// <summary>
/// Gets the priority.
/// </summary>
@@ -74,7 +69,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
if (string.Equals(collectionType, CollectionType.MusicVideos, StringComparison.OrdinalIgnoreCase))
{
- return ResolveVideos<MusicVideo>(parent, files, directoryService, false, collectionType);
+ return ResolveVideos<MusicVideo>(parent, files, directoryService, true, collectionType);
}
if (string.Equals(collectionType, CollectionType.HomeVideos, StringComparison.OrdinalIgnoreCase) ||
@@ -164,8 +159,8 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
IsInMixedFolder = isInMixedFolder,
ProductionYear = video.Year,
Name = video.Name,
- AdditionalParts = video.Files.Skip(1).Select(i => i.Path).ToList(),
- LocalAlternateVersions = video.AlternateVersions.Select(i => i.Path).ToList()
+ AdditionalParts = video.Files.Skip(1).Select(i => i.Path).ToArray(),
+ LocalAlternateVersions = video.AlternateVersions.Select(i => i.Path).ToArray()
};
SetVideoType(videoItem, firstVideo);
@@ -452,8 +447,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
var folderPaths = multiDiscFolders.Select(i => i.FullName).Where(i =>
{
- var subFileEntries = directoryService.GetFileSystemEntries(i)
- .ToList();
+ var subFileEntries = directoryService.GetFileSystemEntries(i);
var subfolders = subFileEntries
.Where(e => e.IsDirectory)
@@ -509,7 +503,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
{
Path = folderPaths[0],
- AdditionalParts = folderPaths.Skip(1).ToList(),
+ AdditionalParts = folderPaths.Skip(1).ToArray(),
VideoType = videoTypes[0],
@@ -547,5 +541,9 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
return !validCollectionTypes.Contains(collectionType, StringComparer.OrdinalIgnoreCase);
}
+
+ public MovieResolver(ILibraryManager libraryManager, IFileSystem fileSystem) : base(libraryManager, fileSystem)
+ {
+ }
}
}
diff --git a/Emby.Server.Implementations/Library/Resolvers/PhotoResolver.cs b/Emby.Server.Implementations/Library/Resolvers/PhotoResolver.cs
index 8bbda3b62..04312f277 100644
--- a/Emby.Server.Implementations/Library/Resolvers/PhotoResolver.cs
+++ b/Emby.Server.Implementations/Library/Resolvers/PhotoResolver.cs
@@ -44,7 +44,7 @@ namespace Emby.Server.Implementations.Library.Resolvers
var filename = Path.GetFileNameWithoutExtension(args.Path);
// Make sure the image doesn't belong to a video file
- if (args.DirectoryService.GetFilePaths(_fileSystem.GetDirectoryName(args.Path)).Any(i => IsOwnedByMedia(args.GetLibraryOptions(), i, filename)))
+ if (_fileSystem.GetFilePaths(_fileSystem.GetDirectoryName(args.Path)).Any(i => IsOwnedByMedia(args.GetLibraryOptions(), i, filename)))
{
return null;
}
diff --git a/Emby.Server.Implementations/Library/Resolvers/SpecialFolderResolver.cs b/Emby.Server.Implementations/Library/Resolvers/SpecialFolderResolver.cs
index 6c7c1f052..6a1f8ec6f 100644
--- a/Emby.Server.Implementations/Library/Resolvers/SpecialFolderResolver.cs
+++ b/Emby.Server.Implementations/Library/Resolvers/SpecialFolderResolver.cs
@@ -53,7 +53,7 @@ namespace Emby.Server.Implementations.Library.Resolvers
return new CollectionFolder
{
CollectionType = GetCollectionType(args),
- PhysicalLocationsList = args.PhysicalLocations.ToList()
+ PhysicalLocationsList = args.PhysicalLocations
};
}
}
diff --git a/Emby.Server.Implementations/Library/Resolvers/TV/EpisodeResolver.cs b/Emby.Server.Implementations/Library/Resolvers/TV/EpisodeResolver.cs
index bdab8552a..7d1c4d65a 100644
--- a/Emby.Server.Implementations/Library/Resolvers/TV/EpisodeResolver.cs
+++ b/Emby.Server.Implementations/Library/Resolvers/TV/EpisodeResolver.cs
@@ -3,6 +3,7 @@ using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Library;
using System.Linq;
using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.IO;
namespace Emby.Server.Implementations.Library.Resolvers.TV
{
@@ -11,10 +12,6 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV
/// </summary>
public class EpisodeResolver : BaseVideoResolver<Episode>
{
- public EpisodeResolver(ILibraryManager libraryManager) : base(libraryManager)
- {
- }
-
/// <summary>
/// Resolves the specified args.
/// </summary>
@@ -76,5 +73,9 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV
return null;
}
+
+ public EpisodeResolver(ILibraryManager libraryManager, IFileSystem fileSystem) : base(libraryManager, fileSystem)
+ {
+ }
}
}
diff --git a/Emby.Server.Implementations/Library/Resolvers/TV/SeasonResolver.cs b/Emby.Server.Implementations/Library/Resolvers/TV/SeasonResolver.cs
index 84ceac65e..830bd9d85 100644
--- a/Emby.Server.Implementations/Library/Resolvers/TV/SeasonResolver.cs
+++ b/Emby.Server.Implementations/Library/Resolvers/TV/SeasonResolver.cs
@@ -1,6 +1,8 @@
-using MediaBrowser.Controller.Configuration;
+using System.Globalization;
+using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Library;
+using MediaBrowser.Model.Globalization;
using MediaBrowser.Naming.Common;
using MediaBrowser.Naming.TV;
@@ -17,15 +19,18 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV
private readonly IServerConfigurationManager _config;
private readonly ILibraryManager _libraryManager;
+ private static readonly CultureInfo UsCulture = new CultureInfo("en-US");
+ private readonly ILocalizationManager _localization;
/// <summary>
/// Initializes a new instance of the <see cref="SeasonResolver"/> class.
/// </summary>
/// <param name="config">The config.</param>
- public SeasonResolver(IServerConfigurationManager config, ILibraryManager libraryManager)
+ public SeasonResolver(IServerConfigurationManager config, ILibraryManager libraryManager, ILocalizationManager localization)
{
_config = config;
_libraryManager = libraryManager;
+ _localization = localization;
}
/// <summary>
@@ -47,9 +52,13 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV
SeriesName = series.Name
};
- if (season.IndexNumber.HasValue && season.IndexNumber.Value == 0)
+ if (season.IndexNumber.HasValue)
{
- season.Name = _config.Configuration.SeasonZeroDisplayName;
+ var seasonNumber = season.IndexNumber.Value;
+
+ season.Name = seasonNumber == 0 ?
+ _config.Configuration.SeasonZeroDisplayName :
+ string.Format(_localization.GetLocalizedString("NameSeasonNumber"), seasonNumber.ToString(UsCulture));
}
return season;
diff --git a/Emby.Server.Implementations/Library/Resolvers/VideoResolver.cs b/Emby.Server.Implementations/Library/Resolvers/VideoResolver.cs
index b5e1bf5f7..5c7a528f5 100644
--- a/Emby.Server.Implementations/Library/Resolvers/VideoResolver.cs
+++ b/Emby.Server.Implementations/Library/Resolvers/VideoResolver.cs
@@ -1,6 +1,7 @@
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Resolvers;
+using MediaBrowser.Model.IO;
namespace Emby.Server.Implementations.Library.Resolvers
{
@@ -9,11 +10,6 @@ namespace Emby.Server.Implementations.Library.Resolvers
/// </summary>
public class VideoResolver : BaseVideoResolver<Video>
{
- public VideoResolver(ILibraryManager libraryManager)
- : base(libraryManager)
- {
- }
-
protected override Video Resolve(ItemResolveArgs args)
{
if (args.Parent != null)
@@ -33,12 +29,16 @@ namespace Emby.Server.Implementations.Library.Resolvers
{
get { return ResolverPriority.Last; }
}
+
+ public VideoResolver(ILibraryManager libraryManager, IFileSystem fileSystem) : base(libraryManager, fileSystem)
+ {
+ }
}
public class GenericVideoResolver<T> : BaseVideoResolver<T>
where T : Video, new ()
{
- public GenericVideoResolver(ILibraryManager libraryManager) : base(libraryManager)
+ public GenericVideoResolver(ILibraryManager libraryManager, IFileSystem fileSystem) : base(libraryManager, fileSystem)
{
}
}
diff --git a/Emby.Server.Implementations/Library/SearchEngine.cs b/Emby.Server.Implementations/Library/SearchEngine.cs
index 6f63322c8..b1ed034ca 100644
--- a/Emby.Server.Implementations/Library/SearchEngine.cs
+++ b/Emby.Server.Implementations/Library/SearchEngine.cs
@@ -10,6 +10,8 @@ using System.Linq;
using System.Threading.Tasks;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Extensions;
+using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.Extensions;
namespace Emby.Server.Implementations.Library
{
@@ -163,12 +165,12 @@ namespace Emby.Server.Implementations.Library
var mediaItems = _libraryManager.GetItemList(new InternalItemsQuery(user)
{
NameContains = searchTerm,
- ExcludeItemTypes = excludeItemTypes.ToArray(),
- IncludeItemTypes = includeItemTypes.ToArray(),
+ ExcludeItemTypes = excludeItemTypes.ToArray(excludeItemTypes.Count),
+ IncludeItemTypes = includeItemTypes.ToArray(includeItemTypes.Count),
Limit = query.Limit,
IncludeItemsByName = string.IsNullOrWhiteSpace(query.ParentId),
ParentId = string.IsNullOrWhiteSpace(query.ParentId) ? (Guid?)null : new Guid(query.ParentId),
- SortBy = new[] { ItemSortBy.SortName },
+ OrderBy = new[] { new Tuple<string, SortOrder>(ItemSortBy.SortName, SortOrder.Ascending) },
Recursive = true,
IsKids = query.IsKids,
@@ -180,7 +182,7 @@ namespace Emby.Server.Implementations.Library
DtoOptions = new DtoOptions
{
- Fields = new List<ItemFields>
+ Fields = new ItemFields[]
{
ItemFields.AirTime,
ItemFields.DateCreated,
diff --git a/Emby.Server.Implementations/Library/UserDataManager.cs b/Emby.Server.Implementations/Library/UserDataManager.cs
index e066ab61b..7ef5ca35e 100644
--- a/Emby.Server.Implementations/Library/UserDataManager.cs
+++ b/Emby.Server.Implementations/Library/UserDataManager.cs
@@ -41,7 +41,7 @@ namespace Emby.Server.Implementations.Library
/// <value>The repository.</value>
public IUserDataRepository Repository { get; set; }
- public async Task SaveUserData(Guid userId, IHasUserData item, UserItemData userData, UserDataSaveReason reason, CancellationToken cancellationToken)
+ public void SaveUserData(Guid userId, IHasUserData item, UserItemData userData, UserDataSaveReason reason, CancellationToken cancellationToken)
{
if (userData == null)
{
@@ -62,7 +62,7 @@ namespace Emby.Server.Implementations.Library
foreach (var key in keys)
{
- await Repository.SaveUserData(userId, key, userData, cancellationToken).ConfigureAwait(false);
+ Repository.SaveUserData(userId, key, userData, cancellationToken);
}
var cacheKey = GetCacheKey(userId, item.Id);
@@ -86,7 +86,7 @@ namespace Emby.Server.Implementations.Library
/// <param name="userData"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
- public async Task SaveAllUserData(Guid userId, IEnumerable<UserItemData> userData, CancellationToken cancellationToken)
+ public void SaveAllUserData(Guid userId, UserItemData[] userData, CancellationToken cancellationToken)
{
if (userData == null)
{
@@ -99,7 +99,7 @@ namespace Emby.Server.Implementations.Library
cancellationToken.ThrowIfCancellationRequested();
- await Repository.SaveAllUserData(userId, userData, cancellationToken).ConfigureAwait(false);
+ Repository.SaveAllUserData(userId, userData, cancellationToken);
}
/// <summary>
@@ -107,7 +107,7 @@ namespace Emby.Server.Implementations.Library
/// </summary>
/// <param name="userId"></param>
/// <returns></returns>
- public IEnumerable<UserItemData> GetAllUserData(Guid userId)
+ public List<UserItemData> GetAllUserData(Guid userId)
{
if (userId == Guid.Empty)
{
@@ -187,11 +187,11 @@ namespace Emby.Server.Implementations.Library
var userData = GetUserData(user.Id, item);
var dto = GetUserItemDataDto(userData);
- item.FillUserDataDtoValues(dto, userData, null, user, new List<ItemFields>());
+ item.FillUserDataDtoValues(dto, userData, null, user, new ItemFields[] { });
return dto;
}
- public UserItemDataDto GetUserDataDto(IHasUserData item, BaseItemDto itemDto, User user, List<ItemFields> fields)
+ public UserItemDataDto GetUserDataDto(IHasUserData item, BaseItemDto itemDto, User user, ItemFields[] fields)
{
var userData = GetUserData(user.Id, item);
var dto = GetUserItemDataDto(userData);
diff --git a/Emby.Server.Implementations/Library/UserManager.cs b/Emby.Server.Implementations/Library/UserManager.cs
index 8e8f8c4dc..e5fe2969f 100644
--- a/Emby.Server.Implementations/Library/UserManager.cs
+++ b/Emby.Server.Implementations/Library/UserManager.cs
@@ -71,9 +71,8 @@ namespace Emby.Server.Implementations.Library
private readonly IServerApplicationHost _appHost;
private readonly IFileSystem _fileSystem;
private readonly ICryptoProvider _cryptographyProvider;
- private readonly string _defaultUserName;
- public UserManager(ILogger logger, IServerConfigurationManager configurationManager, IUserRepository userRepository, IXmlSerializer xmlSerializer, INetworkManager networkManager, Func<IImageProcessor> imageProcessorFactory, Func<IDtoService> dtoServiceFactory, Func<IConnectManager> connectFactory, IServerApplicationHost appHost, IJsonSerializer jsonSerializer, IFileSystem fileSystem, ICryptoProvider cryptographyProvider, string defaultUserName)
+ public UserManager(ILogger logger, IServerConfigurationManager configurationManager, IUserRepository userRepository, IXmlSerializer xmlSerializer, INetworkManager networkManager, Func<IImageProcessor> imageProcessorFactory, Func<IDtoService> dtoServiceFactory, Func<IConnectManager> connectFactory, IServerApplicationHost appHost, IJsonSerializer jsonSerializer, IFileSystem fileSystem, ICryptoProvider cryptographyProvider)
{
_logger = logger;
UserRepository = userRepository;
@@ -86,7 +85,6 @@ namespace Emby.Server.Implementations.Library
_jsonSerializer = jsonSerializer;
_fileSystem = fileSystem;
_cryptographyProvider = cryptographyProvider;
- _defaultUserName = defaultUserName;
ConfigurationManager = configurationManager;
Users = new List<User>();
@@ -122,7 +120,7 @@ namespace Emby.Server.Implementations.Library
/// <param name="user">The user.</param>
private void OnUserDeleted(User user)
{
- EventHelper.QueueEventIfNotNull(UserDeleted, this, new GenericEventArgs<User> { Argument = user }, _logger);
+ EventHelper.FireEventIfNotNull(UserDeleted, this, new GenericEventArgs<User> { Argument = user }, _logger);
}
#endregion
@@ -162,9 +160,9 @@ namespace Emby.Server.Implementations.Library
return Users.FirstOrDefault(u => string.Equals(u.Name, name, StringComparison.OrdinalIgnoreCase));
}
- public async Task Initialize()
+ public void Initialize()
{
- Users = await LoadUsers().ConfigureAwait(false);
+ Users = LoadUsers();
var users = Users.ToList();
@@ -176,7 +174,7 @@ namespace Emby.Server.Implementations.Library
if (!user.ConnectLinkType.HasValue || user.ConnectLinkType.Value == UserLinkType.LinkedUser)
{
user.Policy.IsAdministrator = true;
- await UpdateUserPolicy(user, user.Policy, false).ConfigureAwait(false);
+ UpdateUserPolicy(user, user.Policy, false);
}
}
}
@@ -296,12 +294,12 @@ namespace Emby.Server.Implementations.Library
if (success)
{
user.LastActivityDate = user.LastLoginDate = DateTime.UtcNow;
- await UpdateUser(user).ConfigureAwait(false);
- await UpdateInvalidLoginAttemptCount(user, 0).ConfigureAwait(false);
+ UpdateUser(user);
+ UpdateInvalidLoginAttemptCount(user, 0);
}
else
{
- await UpdateInvalidLoginAttemptCount(user, user.Policy.InvalidLoginAttemptCount + 1).ConfigureAwait(false);
+ UpdateInvalidLoginAttemptCount(user, user.Policy.InvalidLoginAttemptCount + 1);
}
_logger.Info("Authentication request for {0} {1}.", user.Name, success ? "has succeeded" : "has been denied");
@@ -309,7 +307,7 @@ namespace Emby.Server.Implementations.Library
return success ? user : null;
}
- private async Task UpdateInvalidLoginAttemptCount(User user, int newValue)
+ private void UpdateInvalidLoginAttemptCount(User user, int newValue)
{
if (user.Policy.InvalidLoginAttemptCount != newValue || newValue > 0)
{
@@ -329,7 +327,7 @@ namespace Emby.Server.Implementations.Library
//fireLockout = true;
}
- await UpdateUserPolicy(user, user.Policy, false).ConfigureAwait(false);
+ UpdateUserPolicy(user, user.Policy, false);
if (fireLockout)
{
@@ -374,27 +372,27 @@ namespace Emby.Server.Implementations.Library
/// Loads the users from the repository
/// </summary>
/// <returns>IEnumerable{User}.</returns>
- private async Task<IEnumerable<User>> LoadUsers()
+ private List<User> LoadUsers()
{
var users = UserRepository.RetrieveAllUsers().ToList();
// There always has to be at least one user.
if (users.Count == 0)
{
- var name = MakeValidUsername(_defaultUserName);
+ var name = MakeValidUsername(Environment.UserName);
var user = InstantiateNewUser(name);
user.DateLastSaved = DateTime.UtcNow;
- await UserRepository.SaveUser(user, CancellationToken.None).ConfigureAwait(false);
+ UserRepository.SaveUser(user, CancellationToken.None);
users.Add(user);
user.Policy.IsAdministrator = true;
user.Policy.EnableContentDeletion = true;
user.Policy.EnableRemoteControlOfOtherUsers = true;
- await UpdateUserPolicy(user, user.Policy, false).ConfigureAwait(false);
+ UpdateUserPolicy(user, user.Policy, false);
}
return users;
@@ -541,7 +539,7 @@ namespace Emby.Server.Implementations.Library
/// <param name="user">The user.</param>
/// <exception cref="System.ArgumentNullException">user</exception>
/// <exception cref="System.ArgumentException"></exception>
- public async Task UpdateUser(User user)
+ public void UpdateUser(User user)
{
if (user == null)
{
@@ -556,7 +554,7 @@ namespace Emby.Server.Implementations.Library
user.DateModified = DateTime.UtcNow;
user.DateLastSaved = DateTime.UtcNow;
- await UserRepository.SaveUser(user, CancellationToken.None).ConfigureAwait(false);
+ UserRepository.SaveUser(user, CancellationToken.None);
OnUserUpdated(user);
}
@@ -601,7 +599,7 @@ namespace Emby.Server.Implementations.Library
user.DateLastSaved = DateTime.UtcNow;
- await UserRepository.SaveUser(user, CancellationToken.None).ConfigureAwait(false);
+ UserRepository.SaveUser(user, CancellationToken.None);
EventHelper.QueueEventIfNotNull(UserCreated, this, new GenericEventArgs<User> { Argument = user }, _logger);
@@ -655,7 +653,7 @@ namespace Emby.Server.Implementations.Library
{
var configPath = GetConfigurationFilePath(user);
- await UserRepository.DeleteUser(user, CancellationToken.None).ConfigureAwait(false);
+ UserRepository.DeleteUser(user, CancellationToken.None);
try
{
@@ -669,7 +667,7 @@ namespace Emby.Server.Implementations.Library
DeleteUserPolicy(user);
// Force this to be lazy loaded again
- Users = await LoadUsers().ConfigureAwait(false);
+ Users = LoadUsers();
OnUserDeleted(user);
}
@@ -683,17 +681,17 @@ namespace Emby.Server.Implementations.Library
/// Resets the password by clearing it.
/// </summary>
/// <returns>Task.</returns>
- public Task ResetPassword(User user)
+ public void ResetPassword(User user)
{
- return ChangePassword(user, GetSha1String(string.Empty));
+ ChangePassword(user, GetSha1String(string.Empty));
}
- public Task ResetEasyPassword(User user)
+ public void ResetEasyPassword(User user)
{
- return ChangeEasyPassword(user, GetSha1String(string.Empty));
+ ChangeEasyPassword(user, GetSha1String(string.Empty));
}
- public async Task ChangePassword(User user, string newPasswordSha1)
+ public void ChangePassword(User user, string newPasswordSha1)
{
if (user == null)
{
@@ -711,12 +709,12 @@ namespace Emby.Server.Implementations.Library
user.Password = newPasswordSha1;
- await UpdateUser(user).ConfigureAwait(false);
+ UpdateUser(user);
EventHelper.FireEventIfNotNull(UserPasswordChanged, this, new GenericEventArgs<User>(user), _logger);
}
- public async Task ChangeEasyPassword(User user, string newPasswordSha1)
+ public void ChangeEasyPassword(User user, string newPasswordSha1)
{
if (user == null)
{
@@ -729,7 +727,7 @@ namespace Emby.Server.Implementations.Library
user.EasyPassword = newPasswordSha1;
- await UpdateUser(user).ConfigureAwait(false);
+ UpdateUser(user);
EventHelper.FireEventIfNotNull(UserPasswordChanged, this, new GenericEventArgs<User>(user), _logger);
}
@@ -844,7 +842,7 @@ namespace Emby.Server.Implementations.Library
};
}
- public async Task<PinRedeemResult> RedeemPasswordResetPin(string pin)
+ public PinRedeemResult RedeemPasswordResetPin(string pin)
{
DeletePinFile();
@@ -865,12 +863,12 @@ namespace Emby.Server.Implementations.Library
foreach (var user in users)
{
- await ResetPassword(user).ConfigureAwait(false);
+ ResetPassword(user);
if (user.Policy.IsDisabled)
{
user.Policy.IsDisabled = false;
- await UpdateUserPolicy(user, user.Policy, true).ConfigureAwait(false);
+ UpdateUserPolicy(user, user.Policy, true);
}
usersReset.Add(user.Name);
}
@@ -947,13 +945,13 @@ namespace Emby.Server.Implementations.Library
}
private readonly object _policySyncLock = new object();
- public Task UpdateUserPolicy(string userId, UserPolicy userPolicy)
+ public void UpdateUserPolicy(string userId, UserPolicy userPolicy)
{
var user = GetUserById(userId);
- return UpdateUserPolicy(user, userPolicy, true);
+ UpdateUserPolicy(user, userPolicy, true);
}
- private async Task UpdateUserPolicy(User user, UserPolicy userPolicy, bool fireEvent)
+ private void UpdateUserPolicy(User user, UserPolicy userPolicy, bool fireEvent)
{
// The xml serializer will output differently if the type is not exact
if (userPolicy.GetType() != typeof(UserPolicy))
@@ -972,7 +970,7 @@ namespace Emby.Server.Implementations.Library
user.Policy = userPolicy;
}
- await UpdateConfiguration(user, user.Configuration, true).ConfigureAwait(false);
+ UpdateConfiguration(user, user.Configuration, true);
}
private void DeleteUserPolicy(User user)
@@ -1034,13 +1032,13 @@ namespace Emby.Server.Implementations.Library
}
private readonly object _configSyncLock = new object();
- public Task UpdateConfiguration(string userId, UserConfiguration config)
+ public void UpdateConfiguration(string userId, UserConfiguration config)
{
var user = GetUserById(userId);
- return UpdateConfiguration(user, config, true);
+ UpdateConfiguration(user, config, true);
}
- private async Task UpdateConfiguration(User user, UserConfiguration config, bool fireEvent)
+ private void UpdateConfiguration(User user, UserConfiguration config, bool fireEvent)
{
var path = GetConfigurationFilePath(user);
diff --git a/Emby.Server.Implementations/Library/UserViewManager.cs b/Emby.Server.Implementations/Library/UserViewManager.cs
index a6ed84f29..8c9377291 100644
--- a/Emby.Server.Implementations/Library/UserViewManager.cs
+++ b/Emby.Server.Implementations/Library/UserViewManager.cs
@@ -15,6 +15,7 @@ using System.Threading.Tasks;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Model.Globalization;
+using MediaBrowser.Model.Extensions;
namespace Emby.Server.Implementations.Library
{
@@ -38,7 +39,7 @@ namespace Emby.Server.Implementations.Library
_config = config;
}
- public async Task<IEnumerable<Folder>> GetUserViews(UserViewQuery query, CancellationToken cancellationToken)
+ public async Task<Folder[]> GetUserViews(UserViewQuery query, CancellationToken cancellationToken)
{
var user = _userManager.GetUserById(query.UserId);
@@ -67,7 +68,7 @@ namespace Emby.Server.Implementations.Library
if (UserView.IsUserSpecific(folder))
{
- list.Add(await _libraryManager.GetNamedView(user, folder.Name, folder.Id.ToString("N"), folderViewType, null, cancellationToken).ConfigureAwait(false));
+ list.Add(_libraryManager.GetNamedView(user, folder.Name, folder.Id.ToString("N"), folderViewType, null, cancellationToken));
continue;
}
@@ -79,7 +80,7 @@ namespace Emby.Server.Implementations.Library
if (query.PresetViews.Contains(folderViewType ?? string.Empty, StringComparer.OrdinalIgnoreCase))
{
- list.Add(await GetUserView(folder, folderViewType, string.Empty, cancellationToken).ConfigureAwait(false));
+ list.Add(GetUserView(folder, folderViewType, string.Empty, cancellationToken));
}
else
{
@@ -94,7 +95,7 @@ namespace Emby.Server.Implementations.Library
if (parents.Count > 0)
{
- list.Add(await GetUserView(parents, viewType, string.Empty, user, query.PresetViews, cancellationToken).ConfigureAwait(false));
+ list.Add(GetUserView(parents, viewType, string.Empty, user, query.PresetViews, cancellationToken));
}
}
@@ -113,7 +114,7 @@ namespace Emby.Server.Implementations.Library
}, cancellationToken).ConfigureAwait(false);
var channels = channelResult.Items;
-
+
if (_config.Configuration.EnableChannelView && channels.Length > 0)
{
list.Add(await _channelManager.GetInternalChannelFolder(cancellationToken).ConfigureAwait(false));
@@ -153,7 +154,8 @@ namespace Emby.Server.Implementations.Library
return index == -1 ? int.MaxValue : index;
})
.ThenBy(sorted.IndexOf)
- .ThenBy(i => i.SortName);
+ .ThenBy(i => i.SortName)
+ .ToArray();
}
public Task<UserView> GetUserSubView(string name, string parentId, string type, string sortName, CancellationToken cancellationToken)
@@ -170,7 +172,7 @@ namespace Emby.Server.Implementations.Library
return GetUserSubView(name, parentId, type, sortName, cancellationToken);
}
- private async Task<Folder> GetUserView(List<ICollectionFolder> parents, string viewType, string sortName, User user, string[] presetViews, CancellationToken cancellationToken)
+ private Folder GetUserView(List<ICollectionFolder> parents, string viewType, string sortName, User user, string[] presetViews, CancellationToken cancellationToken)
{
if (parents.Count == 1 && parents.All(i => string.Equals(i.CollectionType, viewType, StringComparison.OrdinalIgnoreCase)))
{
@@ -179,14 +181,14 @@ namespace Emby.Server.Implementations.Library
return (Folder)parents[0];
}
- return await GetUserView((Folder)parents[0], viewType, string.Empty, cancellationToken).ConfigureAwait(false);
+ return GetUserView((Folder)parents[0], viewType, string.Empty, cancellationToken);
}
var name = _localizationManager.GetLocalizedString("ViewType" + viewType);
- return await _libraryManager.GetNamedView(user, name, viewType, sortName, cancellationToken).ConfigureAwait(false);
+ return _libraryManager.GetNamedView(user, name, viewType, sortName, cancellationToken);
}
- public Task<UserView> GetUserView(Folder parent, string viewType, string sortName, CancellationToken cancellationToken)
+ public UserView GetUserView(Folder parent, string viewType, string sortName, CancellationToken cancellationToken)
{
return _libraryManager.GetShadowView(parent, viewType, sortName, cancellationToken);
}
@@ -231,7 +233,7 @@ namespace Emby.Server.Implementations.Library
return list;
}
- private IEnumerable<BaseItem> GetItemsForLatestItems(User user, LatestItemsQuery request, DtoOptions options)
+ private List<BaseItem> GetItemsForLatestItems(User user, LatestItemsQuery request, DtoOptions options)
{
var parentId = request.ParentId;
@@ -269,7 +271,41 @@ namespace Emby.Server.Implementations.Library
return new List<BaseItem>();
}
- var excludeItemTypes = includeItemTypes.Length == 0 ? new[]
+ var mediaTypes = new List<string>();
+
+ if (includeItemTypes.Length == 0)
+ {
+ foreach (var parent in parents.OfType<ICollectionFolder>())
+ {
+ switch (parent.CollectionType)
+ {
+ case CollectionType.Books:
+ mediaTypes.Add(MediaType.Book);
+ break;
+ case CollectionType.Games:
+ mediaTypes.Add(MediaType.Game);
+ break;
+ case CollectionType.Music:
+ mediaTypes.Add(MediaType.Audio);
+ break;
+ case CollectionType.Photos:
+ mediaTypes.Add(MediaType.Photo);
+ mediaTypes.Add(MediaType.Video);
+ break;
+ case CollectionType.HomeVideos:
+ mediaTypes.Add(MediaType.Photo);
+ mediaTypes.Add(MediaType.Video);
+ break;
+ default:
+ mediaTypes.Add(MediaType.Video);
+ break;
+ }
+ }
+
+ mediaTypes = mediaTypes.Distinct().ToList();
+ }
+
+ var excludeItemTypes = includeItemTypes.Length == 0 && mediaTypes.Count == 0 ? new[]
{
typeof(Person).Name,
typeof(Studio).Name,
@@ -283,14 +319,14 @@ namespace Emby.Server.Implementations.Library
var query = new InternalItemsQuery(user)
{
IncludeItemTypes = includeItemTypes,
- SortOrder = SortOrder.Descending,
- SortBy = new[] { ItemSortBy.DateCreated },
+ OrderBy = new[] { new Tuple<string, SortOrder>(ItemSortBy.DateCreated, SortOrder.Descending) },
IsFolder = includeItemTypes.Length == 0 ? false : (bool?)null,
ExcludeItemTypes = excludeItemTypes,
IsVirtualItem = false,
Limit = limit * 5,
IsPlayed = isPlayed,
- DtoOptions = options
+ DtoOptions = options,
+ MediaTypes = mediaTypes.ToArray(mediaTypes.Count)
};
if (parents.Count == 0)
diff --git a/Emby.Server.Implementations/Library/Validators/PeopleValidator.cs b/Emby.Server.Implementations/Library/Validators/PeopleValidator.cs
index c2eb30ee4..39630cf96 100644
--- a/Emby.Server.Implementations/Library/Validators/PeopleValidator.cs
+++ b/Emby.Server.Implementations/Library/Validators/PeopleValidator.cs
@@ -55,28 +55,21 @@ namespace Emby.Server.Implementations.Library.Validators
/// <returns>Task.</returns>
public async Task ValidatePeople(CancellationToken cancellationToken, IProgress<double> progress)
{
- var people = _libraryManager.GetPeople(new InternalPeopleQuery());
-
- var dict = new Dictionary<string, bool>(StringComparer.OrdinalIgnoreCase);
-
- foreach (var person in people)
- {
- dict[person.Name] = true;
- }
+ var people = _libraryManager.GetPeopleNames(new InternalPeopleQuery());
var numComplete = 0;
- _logger.Debug("Will refresh {0} people", dict.Count);
+ var numPeople = people.Count;
- var numPeople = dict.Count;
+ _logger.Debug("Will refresh {0} people", numPeople);
- foreach (var person in dict)
+ foreach (var person in people)
{
cancellationToken.ThrowIfCancellationRequested();
try
{
- var item = _libraryManager.GetPerson(person.Key);
+ var item = _libraryManager.GetPerson(person);
var options = new MetadataRefreshOptions(_fileSystem)
{
diff --git a/Emby.Server.Implementations/LiveTv/ChannelImageProvider.cs b/Emby.Server.Implementations/LiveTv/ChannelImageProvider.cs
index 95cefd999..0c8049d8b 100644
--- a/Emby.Server.Implementations/LiveTv/ChannelImageProvider.cs
+++ b/Emby.Server.Implementations/LiveTv/ChannelImageProvider.cs
@@ -28,12 +28,12 @@ namespace Emby.Server.Implementations.LiveTv
_appHost = appHost;
}
- public IEnumerable<ImageType> GetSupportedImages(IHasImages item)
+ public IEnumerable<ImageType> GetSupportedImages(IHasMetadata item)
{
return new[] { ImageType.Primary };
}
- public async Task<DynamicImageResponse> GetImage(IHasImages item, ImageType type, CancellationToken cancellationToken)
+ public async Task<DynamicImageResponse> GetImage(IHasMetadata item, ImageType type, CancellationToken cancellationToken)
{
var liveTvItem = (LiveTvChannel)item;
@@ -67,7 +67,7 @@ namespace Emby.Server.Implementations.LiveTv
get { return "Live TV Service Provider"; }
}
- public bool Supports(IHasImages item)
+ public bool Supports(IHasMetadata item)
{
return item is LiveTvChannel;
}
diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
index 9ac599846..92a47bddc 100644
--- a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
+++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
@@ -208,7 +208,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
continue;
}
- if (virtualFolder.Locations.Count == 1)
+ if (virtualFolder.Locations.Length == 1)
{
// remove entire virtual folder
try
@@ -458,7 +458,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
return GetEpgChannelFromTunerChannel(info, tunerChannel, epgChannels);
}
- private string GetMappedChannel(string channelId, List<NameValuePair> mappings)
+ private string GetMappedChannel(string channelId, NameValuePair[] mappings)
{
foreach (NameValuePair mapping in mappings)
{
@@ -472,10 +472,10 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
private ChannelInfo GetEpgChannelFromTunerChannel(ListingsProviderInfo info, ChannelInfo tunerChannel, List<ChannelInfo> epgChannels)
{
- return GetEpgChannelFromTunerChannel(info.ChannelMappings.ToList(), tunerChannel, epgChannels);
+ return GetEpgChannelFromTunerChannel(info.ChannelMappings, tunerChannel, epgChannels);
}
- public ChannelInfo GetEpgChannelFromTunerChannel(List<NameValuePair> mappings, ChannelInfo tunerChannel, List<ChannelInfo> epgChannels)
+ public ChannelInfo GetEpgChannelFromTunerChannel(NameValuePair[] mappings, ChannelInfo tunerChannel, List<ChannelInfo> epgChannels)
{
if (!string.IsNullOrWhiteSpace(tunerChannel.Id))
{
@@ -607,20 +607,22 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
var timer = _timerProvider.GetTimer(timerId);
if (timer != null)
{
+ timer.Status = RecordingStatus.Cancelled;
+
if (string.IsNullOrWhiteSpace(timer.SeriesTimerId) || isSeriesCancelled)
{
_timerProvider.Delete(timer);
}
else
{
- timer.Status = RecordingStatus.Cancelled;
_timerProvider.AddOrUpdate(timer, false);
}
}
ActiveRecordingInfo activeRecordingInfo;
if (_activeRecordings.TryGetValue(timerId, out activeRecordingInfo))
- {
+ {
+ activeRecordingInfo.Timer = timer;
activeRecordingInfo.CancellationTokenSource.Cancel();
}
}
@@ -830,6 +832,9 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
existingTimer.IsKids = updatedTimer.IsKids;
existingTimer.IsNews = updatedTimer.IsNews;
existingTimer.IsMovie = updatedTimer.IsMovie;
+ existingTimer.IsSeries = updatedTimer.IsSeries;
+ existingTimer.IsLive = updatedTimer.IsLive;
+ existingTimer.IsPremiere = updatedTimer.IsPremiere;
existingTimer.IsProgramSeries = updatedTimer.IsProgramSeries;
existingTimer.IsRepeat = updatedTimer.IsRepeat;
existingTimer.IsSports = updatedTimer.IsSports;
@@ -861,7 +866,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
public async Task<IEnumerable<RecordingInfo>> GetRecordingsAsync(CancellationToken cancellationToken)
{
- return _activeRecordings.Values.ToList().Select(GetRecordingInfo).ToList();
+ return new List<RecordingInfo>();
}
public string GetActiveRecordingPath(string id)
@@ -875,49 +880,31 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
return null;
}
- private RecordingInfo GetRecordingInfo(ActiveRecordingInfo info)
- {
- var timer = info.Timer;
- var program = info.Program;
-
- var result = new RecordingInfo
- {
- ChannelId = timer.ChannelId,
- CommunityRating = timer.CommunityRating,
- DateLastUpdated = DateTime.UtcNow,
- EndDate = timer.EndDate,
- EpisodeTitle = timer.EpisodeTitle,
- Genres = timer.Genres,
- Id = "recording" + timer.Id,
- IsKids = timer.IsKids,
- IsMovie = timer.IsMovie,
- IsNews = timer.IsNews,
- IsRepeat = timer.IsRepeat,
- IsSeries = timer.IsProgramSeries,
- IsSports = timer.IsSports,
- Name = timer.Name,
- OfficialRating = timer.OfficialRating,
- OriginalAirDate = timer.OriginalAirDate,
- Overview = timer.Overview,
- ProgramId = timer.ProgramId,
- SeriesTimerId = timer.SeriesTimerId,
- StartDate = timer.StartDate,
- Status = RecordingStatus.InProgress,
- TimerId = timer.Id
- };
+ public IEnumerable<ActiveRecordingInfo> GetAllActiveRecordings()
+ {
+ return _activeRecordings.Values.Where(i => i.Timer.Status == RecordingStatus.InProgress && !i.CancellationTokenSource.IsCancellationRequested);
+ }
- if (program != null)
+ public ActiveRecordingInfo GetActiveRecordingInfo(string path)
+ {
+ if (string.IsNullOrWhiteSpace(path))
{
- result.Audio = program.Audio;
- result.ImagePath = program.ImagePath;
- result.ImageUrl = program.ImageUrl;
- result.IsHD = program.IsHD;
- result.IsLive = program.IsLive;
- result.IsPremiere = program.IsPremiere;
- result.ShowId = program.ShowId;
+ return null;
}
- return result;
+ foreach (var recording in _activeRecordings.Values)
+ {
+ if (string.Equals(recording.Path, path, StringComparison.Ordinal) && !recording.CancellationTokenSource.IsCancellationRequested)
+ {
+ var timer = recording.Timer;
+ if (timer.Status != RecordingStatus.InProgress)
+ {
+ return null;
+ }
+ return recording;
+ }
+ }
+ return null;
}
public Task<IEnumerable<TimerInfo>> GetTimersAsync(CancellationToken cancellationToken)
@@ -1245,6 +1232,33 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
throw new FileNotFoundException();
}
+ public async Task<List<MediaSourceInfo>> GetRecordingStreamMediaSources(ActiveRecordingInfo info, CancellationToken cancellationToken)
+ {
+ var stream = new MediaSourceInfo
+ {
+ Path = _appHost.GetLocalApiUrl("127.0.0.1") + "/LiveTv/LiveRecordings/" + info.Id + "/stream",
+ Id = info.Id,
+ SupportsDirectPlay = false,
+ SupportsDirectStream = true,
+ SupportsTranscoding = true,
+ IsInfiniteStream = true,
+ RequiresOpening = false,
+ RequiresClosing = false,
+ Protocol = MediaBrowser.Model.MediaInfo.MediaProtocol.Http,
+ BufferMs = 0,
+ IgnoreDts = true,
+ IgnoreIndex = true
+ };
+
+ var isAudio = false;
+ await new LiveStreamHelper(_mediaEncoder, _logger).AddMediaInfoWithProbe(stream, isAudio, cancellationToken).ConfigureAwait(false);
+
+ return new List<MediaSourceInfo>
+ {
+ stream
+ };
+ }
+
public async Task CloseLiveStream(string id, CancellationToken cancellationToken)
{
// Ignore the consumer id
@@ -1327,7 +1341,8 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
var activeRecordingInfo = new ActiveRecordingInfo
{
CancellationTokenSource = new CancellationTokenSource(),
- Timer = timer
+ Timer = timer,
+ Id = timer.Id
};
if (_activeRecordings.TryAdd(timer.Id, activeRecordingInfo))
@@ -1493,7 +1508,6 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
recordPath = recorder.GetOutputPath(mediaStreamInfo, recordPath);
recordPath = EnsureFileUnique(recordPath, timer.Id);
- _libraryManager.RegisterIgnoredPath(recordPath);
_libraryMonitor.ReportFileSystemChangeBeginning(recordPath);
_fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(recordPath));
activeRecordingInfo.Path = recordPath;
@@ -1512,6 +1526,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
_timerProvider.AddOrUpdate(timer, false);
SaveRecordingMetadata(timer, recordPath, seriesPath);
+ TriggerRefresh(recordPath);
EnforceKeepUpTo(timer, seriesPath);
};
@@ -1543,7 +1558,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
}
}
- _libraryManager.UnRegisterIgnoredPath(recordPath);
+ TriggerRefresh(recordPath);
_libraryMonitor.ReportFileSystemChangeComplete(recordPath, true);
ActiveRecordingInfo removed;
@@ -1574,6 +1589,44 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
OnRecordingStatusChanged();
}
+ private void TriggerRefresh(string path)
+ {
+ var item = GetAffectedBaseItem(_fileSystem.GetDirectoryName(path));
+
+ if (item != null)
+ {
+ item.ChangedExternally();
+ }
+ }
+
+ private BaseItem GetAffectedBaseItem(string path)
+ {
+ BaseItem item = null;
+
+ while (item == null && !string.IsNullOrEmpty(path))
+ {
+ item = _libraryManager.FindByPath(path, null);
+
+ path = _fileSystem.GetDirectoryName(path);
+ }
+
+ if (item != null)
+ {
+ // If the item has been deleted find the first valid parent that still exists
+ while (!_fileSystem.DirectoryExists(item.Path) && !_fileSystem.FileExists(item.Path))
+ {
+ item = item.GetParent();
+
+ if (item == null)
+ {
+ break;
+ }
+ }
+ }
+
+ return item;
+ }
+
private void OnRecordingStatusChanged()
{
EventHelper.FireEventIfNotNull(RecordingStatusChanged, this, new RecordingStatusChangedEventArgs
@@ -1632,17 +1685,15 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
return;
}
- var episodesToDelete = (librarySeries.GetItems(new InternalItemsQuery
+ var episodesToDelete = (librarySeries.GetItemList(new InternalItemsQuery
{
- SortBy = new[] { ItemSortBy.DateCreated },
- SortOrder = SortOrder.Descending,
+ OrderBy = new[] { new Tuple<string, SortOrder>(ItemSortBy.DateCreated, SortOrder.Descending) },
IsVirtualItem = false,
IsFolder = false,
Recursive = true,
DtoOptions = new DtoOptions(true)
}))
- .Items
.Where(i => i.LocationType == LocationType.FileSystem && _fileSystem.FileExists(i.Path))
.Skip(seriesTimer.KeepUpTo - 1)
.ToList();
@@ -1758,7 +1809,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
{
var config = GetConfiguration();
- var regInfo = await _liveTvManager.GetRegistrationInfo("embytvrecordingconversion").ConfigureAwait(false);
+ var regInfo = await _liveTvManager.GetRegistrationInfo("dvr").ConfigureAwait(false);
if (regInfo.IsValid)
{
@@ -2579,6 +2630,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
{
pair.Value.CancellationTokenSource.Cancel();
}
+ GC.SuppressFinalize(this);
}
public List<VirtualFolderInfo> GetRecordingFolders()
@@ -2592,7 +2644,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
{
list.Add(new VirtualFolderInfo
{
- Locations = new List<string> { defaultFolder },
+ Locations = new string[] { defaultFolder },
Name = defaultName
});
}
@@ -2602,7 +2654,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
{
list.Add(new VirtualFolderInfo
{
- Locations = new List<string> { customPath },
+ Locations = new string[] { customPath },
Name = "Recorded Movies",
CollectionType = CollectionType.Movies
});
@@ -2613,7 +2665,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
{
list.Add(new VirtualFolderInfo
{
- Locations = new List<string> { customPath },
+ Locations = new string[] { customPath },
Name = "Recorded Shows",
CollectionType = CollectionType.TvShows
});
@@ -2622,14 +2674,6 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
return list;
}
- class ActiveRecordingInfo
- {
- public string Path { get; set; }
- public TimerInfo Timer { get; set; }
- public ProgramInfo Program { get; set; }
- public CancellationTokenSource CancellationTokenSource { get; set; }
- }
-
private const int TunerDiscoveryDurationMs = 3000;
public async Task<List<TunerHostInfo>> DiscoverTuners(bool newDevicesOnly, CancellationToken cancellationToken)
diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs
index 6173068cc..48eba4117 100644
--- a/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs
+++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs
@@ -70,7 +70,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
return "ts";
}
- return "mp4";
+ return "mkv";
}
}
@@ -207,9 +207,12 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
inputModifier += " -fflags " + string.Join("", flags.ToArray());
}
- if (!string.IsNullOrWhiteSpace(GetEncodingOptions().HardwareAccelerationType))
+ var videoStream = mediaSource.VideoStream;
+ var videoDecoder = videoStream == null ? null : new EncodingHelper(_mediaEncoder, _fileSystem, null).GetVideoDecoder(VideoType.VideoFile, videoStream, GetEncodingOptions());
+
+ if (!string.IsNullOrWhiteSpace(videoDecoder))
{
- inputModifier += " -hwaccel auto";
+ inputModifier += " " + videoDecoder;
}
if (mediaSource.ReadAtNativeFramerate)
diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EntryPoint.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EntryPoint.cs
index 139cf570e..7c5f630a7 100644
--- a/Emby.Server.Implementations/LiveTv/EmbyTV/EntryPoint.cs
+++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EntryPoint.cs
@@ -1,4 +1,5 @@
-using MediaBrowser.Controller.Plugins;
+using System;
+using MediaBrowser.Controller.Plugins;
namespace Emby.Server.Implementations.LiveTv.EmbyTV
{
@@ -11,6 +12,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
public void Dispose()
{
+ GC.SuppressFinalize(this);
}
}
}
diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/RecordingHelper.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/RecordingHelper.cs
index 94be4a02e..b5de6ef01 100644
--- a/Emby.Server.Implementations/LiveTv/EmbyTV/RecordingHelper.cs
+++ b/Emby.Server.Implementations/LiveTv/EmbyTV/RecordingHelper.cs
@@ -58,6 +58,10 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
timerInfo.OriginalAirDate = programInfo.OriginalAirDate;
timerInfo.IsProgramSeries = programInfo.IsSeries;
+ timerInfo.IsSeries = programInfo.IsSeries;
+ timerInfo.IsLive = programInfo.IsLive;
+ timerInfo.IsPremiere = programInfo.IsPremiere;
+
timerInfo.HomePageUrl = programInfo.HomePageUrl;
timerInfo.CommunityRating = programInfo.CommunityRating;
timerInfo.Overview = programInfo.Overview;
diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs
index e12acf140..b7cfdea1b 100644
--- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs
+++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs
@@ -247,7 +247,10 @@ namespace Emby.Server.Implementations.LiveTv.Listings
ProgramAudio audioType = ProgramAudio.Stereo;
bool repeat = programInfo.@new == null;
- string newID = programInfo.programID + "T" + startAt.Ticks + "C" + channelId;
+
+ var programId = programInfo.programID ?? string.Empty;
+
+ string newID = programId + "T" + startAt.Ticks + "C" + channelId;
if (programInfo.audioProperties != null)
{
@@ -300,7 +303,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
Etag = programInfo.md5
};
- var showId = programInfo.programID ?? string.Empty;
+ var showId = programId;
if (!info.IsSeries)
{
@@ -339,11 +342,11 @@ namespace Emby.Server.Implementations.LiveTv.Listings
if (details.descriptions != null)
{
- if (details.descriptions.description1000 != null)
+ if (details.descriptions.description1000 != null && details.descriptions.description1000.Count > 0)
{
info.Overview = details.descriptions.description1000[0].description;
}
- else if (details.descriptions.description100 != null)
+ else if (details.descriptions.description100 != null && details.descriptions.description100.Count > 0)
{
info.Overview = details.descriptions.description100[0].description;
}
@@ -351,16 +354,24 @@ namespace Emby.Server.Implementations.LiveTv.Listings
if (info.IsSeries)
{
- info.SeriesId = programInfo.programID.Substring(0, 10);
+ info.SeriesId = programId.Substring(0, 10);
if (details.metadata != null)
{
- var gracenote = details.metadata.Find(x => x.Gracenote != null).Gracenote;
- info.SeasonNumber = gracenote.season;
-
- if (gracenote.episode > 0)
+ foreach (var metadataProgram in details.metadata)
{
- info.EpisodeNumber = gracenote.episode;
+ var gracenote = metadataProgram.Gracenote;
+ if (gracenote != null)
+ {
+ info.SeasonNumber = gracenote.season;
+
+ if (gracenote.episode > 0)
+ {
+ info.EpisodeNumber = gracenote.episode;
+ }
+
+ break;
+ }
}
}
}
diff --git a/Emby.Server.Implementations/LiveTv/LiveTvDtoService.cs b/Emby.Server.Implementations/LiveTv/LiveTvDtoService.cs
index 5c5072192..eff2909fd 100644
--- a/Emby.Server.Implementations/LiveTv/LiveTvDtoService.cs
+++ b/Emby.Server.Implementations/LiveTv/LiveTvDtoService.cs
@@ -15,6 +15,8 @@ using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Model.Dto;
+using MediaBrowser.Model.Extensions;
+using MediaBrowser.Model.Querying;
namespace Emby.Server.Implementations.LiveTv
{
@@ -110,7 +112,7 @@ namespace Emby.Server.Implementations.LiveTv
PostPaddingSeconds = info.PostPaddingSeconds,
IsPostPaddingRequired = info.IsPostPaddingRequired,
IsPrePaddingRequired = info.IsPrePaddingRequired,
- Days = info.Days,
+ Days = info.Days.ToArray(),
Priority = info.Priority,
RecordAnyChannel = info.RecordAnyChannel,
RecordAnyTime = info.RecordAnyTime,
@@ -135,7 +137,7 @@ namespace Emby.Server.Implementations.LiveTv
dto.ProgramId = GetInternalProgramId(service.Name, info.ProgramId).ToString("N");
}
- dto.DayPattern = info.Days == null ? null : GetDayPattern(info.Days);
+ dto.DayPattern = info.Days == null ? null : GetDayPattern(info.Days.ToArray(info.Days.Count));
FillImages(dto, info.Name, info.SeriesId);
@@ -150,10 +152,7 @@ namespace Emby.Server.Implementations.LiveTv
Name = seriesName,
Limit = 1,
ImageTypes = new ImageType[] { ImageType.Thumb },
- DtoOptions = new DtoOptions
- {
- Fields = new List<MediaBrowser.Model.Querying.ItemFields>()
- }
+ DtoOptions = new DtoOptions(false)
}).FirstOrDefault();
@@ -176,7 +175,7 @@ namespace Emby.Server.Implementations.LiveTv
{
try
{
- dto.ParentBackdropImageTags = new List<string>
+ dto.ParentBackdropImageTags = new string[]
{
_imageProcessor.GetImageCacheTag(librarySeries, image)
};
@@ -196,10 +195,7 @@ namespace Emby.Server.Implementations.LiveTv
ExternalSeriesId = programSeriesId,
Limit = 1,
ImageTypes = new ImageType[] { ImageType.Primary },
- DtoOptions = new DtoOptions
- {
- Fields = new List<MediaBrowser.Model.Querying.ItemFields>()
- }
+ DtoOptions = new DtoOptions(false)
}).FirstOrDefault();
@@ -218,14 +214,14 @@ namespace Emby.Server.Implementations.LiveTv
}
}
- if (dto.ParentBackdropImageTags == null || dto.ParentBackdropImageTags.Count == 0)
+ if (dto.ParentBackdropImageTags == null || dto.ParentBackdropImageTags.Length == 0)
{
image = program.GetImageInfo(ImageType.Backdrop, 0);
if (image != null)
{
try
{
- dto.ParentBackdropImageTags = new List<string>
+ dto.ParentBackdropImageTags = new string[]
{
_imageProcessor.GetImageCacheTag(program, image)
};
@@ -248,10 +244,7 @@ namespace Emby.Server.Implementations.LiveTv
Name = seriesName,
Limit = 1,
ImageTypes = new ImageType[] { ImageType.Thumb },
- DtoOptions = new DtoOptions
- {
- Fields = new List<MediaBrowser.Model.Querying.ItemFields>()
- }
+ DtoOptions = new DtoOptions(false)
}).FirstOrDefault();
@@ -274,7 +267,7 @@ namespace Emby.Server.Implementations.LiveTv
{
try
{
- dto.ParentBackdropImageTags = new List<string>
+ dto.ParentBackdropImageTags = new string[]
{
_imageProcessor.GetImageCacheTag(librarySeries, image)
};
@@ -294,10 +287,7 @@ namespace Emby.Server.Implementations.LiveTv
Name = seriesName,
Limit = 1,
ImageTypes = new ImageType[] { ImageType.Primary },
- DtoOptions = new DtoOptions
- {
- Fields = new List<MediaBrowser.Model.Querying.ItemFields>()
- }
+ DtoOptions = new DtoOptions(false)
}).FirstOrDefault() ?? _libraryManager.GetItemList(new InternalItemsQuery
{
@@ -305,10 +295,7 @@ namespace Emby.Server.Implementations.LiveTv
ExternalSeriesId = programSeriesId,
Limit = 1,
ImageTypes = new ImageType[] { ImageType.Primary },
- DtoOptions = new DtoOptions
- {
- Fields = new List<MediaBrowser.Model.Querying.ItemFields>()
- }
+ DtoOptions = new DtoOptions(false)
}).FirstOrDefault();
@@ -327,14 +314,14 @@ namespace Emby.Server.Implementations.LiveTv
}
}
- if (dto.ParentBackdropImageTags == null || dto.ParentBackdropImageTags.Count == 0)
+ if (dto.ParentBackdropImageTags == null || dto.ParentBackdropImageTags.Length == 0)
{
image = program.GetImageInfo(ImageType.Backdrop, 0);
if (image != null)
{
try
{
- dto.ParentBackdropImageTags = new List<string>
+ dto.ParentBackdropImageTags = new string[]
{
_imageProcessor.GetImageCacheTag(program, image)
};
@@ -349,24 +336,24 @@ namespace Emby.Server.Implementations.LiveTv
}
}
- public DayPattern? GetDayPattern(List<DayOfWeek> days)
+ public DayPattern? GetDayPattern(DayOfWeek[] days)
{
DayPattern? pattern = null;
- if (days.Count > 0)
+ if (days.Length > 0)
{
- if (days.Count == 7)
+ if (days.Length == 7)
{
pattern = DayPattern.Daily;
}
- else if (days.Count == 2)
+ else if (days.Length == 2)
{
if (days.Contains(DayOfWeek.Saturday) && days.Contains(DayOfWeek.Sunday))
{
pattern = DayPattern.Weekends;
}
}
- else if (days.Count == 5)
+ else if (days.Length == 5)
{
if (days.Contains(DayOfWeek.Monday) && days.Contains(DayOfWeek.Tuesday) && days.Contains(DayOfWeek.Wednesday) && days.Contains(DayOfWeek.Thursday) && days.Contains(DayOfWeek.Friday))
{
@@ -384,7 +371,7 @@ namespace Emby.Server.Implementations.LiveTv
{
Name = info.Name,
Id = info.Id,
- Clients = info.Clients,
+ Clients = info.Clients.ToArray(),
ProgramName = info.ProgramName,
SourceType = info.SourceType,
Status = info.Status,
@@ -406,7 +393,7 @@ namespace Emby.Server.Implementations.LiveTv
return dto;
}
- internal string GetImageTag(IHasImages info)
+ internal string GetImageTag(IHasMetadata info)
{
try
{
@@ -543,7 +530,7 @@ namespace Emby.Server.Implementations.LiveTv
PostPaddingSeconds = dto.PostPaddingSeconds,
IsPostPaddingRequired = dto.IsPostPaddingRequired,
IsPrePaddingRequired = dto.IsPrePaddingRequired,
- Days = dto.Days,
+ Days = dto.Days.ToList(),
Priority = dto.Priority,
RecordAnyChannel = dto.RecordAnyChannel,
RecordAnyTime = dto.RecordAnyTime,
diff --git a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs
index bf11b7d3a..b243c6599 100644
--- a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs
+++ b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs
@@ -60,7 +60,7 @@ namespace Emby.Server.Implementations.LiveTv
private readonly LiveTvDtoService _tvDtoService;
- private readonly List<ILiveTvService> _services = new List<ILiveTvService>();
+ private ILiveTvService[] _services = new ILiveTvService[] { };
private readonly SemaphoreSlim _refreshRecordingsLock = new SemaphoreSlim(1, 1);
@@ -124,7 +124,7 @@ namespace Emby.Server.Implementations.LiveTv
/// <param name="listingProviders">The listing providers.</param>
public void AddParts(IEnumerable<ILiveTvService> services, IEnumerable<ITunerHost> tunerHosts, IEnumerable<IListingsProvider> listingProviders)
{
- _services.AddRange(services);
+ _services = services.ToArray();
_tunerHosts.AddRange(tunerHosts);
_listingProviders.AddRange(listingProviders);
@@ -173,7 +173,7 @@ namespace Emby.Server.Implementations.LiveTv
}
}
- public async Task<QueryResult<LiveTvChannel>> GetInternalChannels(LiveTvChannelQuery query, DtoOptions dtoOptions, CancellationToken cancellationToken)
+ public async Task<QueryResult<BaseItem>> GetInternalChannels(LiveTvChannelQuery query, DtoOptions dtoOptions, CancellationToken cancellationToken)
{
var user = string.IsNullOrEmpty(query.UserId) ? null : _userManager.GetUserById(query.UserId);
@@ -187,7 +187,6 @@ namespace Emby.Server.Implementations.LiveTv
IsSports = query.IsSports,
IsSeries = query.IsSeries,
IncludeItemTypes = new[] { typeof(LiveTvChannel).Name },
- SortOrder = query.SortOrder ?? SortOrder.Ascending,
TopParentIds = new[] { topFolder.Id.ToString("N") },
IsFavorite = query.IsFavorite,
IsLiked = query.IsLiked,
@@ -196,27 +195,23 @@ namespace Emby.Server.Implementations.LiveTv
DtoOptions = dtoOptions
};
- internalQuery.OrderBy.AddRange(query.SortBy.Select(i => new Tuple<string, SortOrder>(i, query.SortOrder ?? SortOrder.Ascending)));
+ var orderBy = internalQuery.OrderBy.ToList();
+
+ orderBy.AddRange(query.SortBy.Select(i => new Tuple<string, SortOrder>(i, query.SortOrder ?? SortOrder.Ascending)));
if (query.EnableFavoriteSorting)
{
- internalQuery.OrderBy.Insert(0, new Tuple<string, SortOrder>(ItemSortBy.IsFavoriteOrLiked, SortOrder.Descending));
+ orderBy.Insert(0, new Tuple<string, SortOrder>(ItemSortBy.IsFavoriteOrLiked, SortOrder.Descending));
}
if (!internalQuery.OrderBy.Any(i => string.Equals(i.Item1, ItemSortBy.SortName, StringComparison.OrdinalIgnoreCase)))
{
- internalQuery.OrderBy.Add(new Tuple<string, SortOrder>(ItemSortBy.SortName, SortOrder.Ascending));
+ orderBy.Add(new Tuple<string, SortOrder>(ItemSortBy.SortName, SortOrder.Ascending));
}
- var channelResult = _libraryManager.GetItemsResult(internalQuery);
-
- var result = new QueryResult<LiveTvChannel>
- {
- Items = channelResult.Items.Cast<LiveTvChannel>().ToArray(),
- TotalRecordCount = channelResult.TotalRecordCount
- };
+ internalQuery.OrderBy = orderBy.ToArray();
- return result;
+ return _libraryManager.GetItemsResult(internalQuery);
}
public LiveTvChannel GetInternalChannel(string id)
@@ -566,7 +561,7 @@ namespace Emby.Server.Implementations.LiveTv
if (isNew)
{
- await _libraryManager.CreateItem(item, cancellationToken).ConfigureAwait(false);
+ _libraryManager.CreateItem(item, cancellationToken);
}
else if (forceUpdate)
{
@@ -883,7 +878,7 @@ namespace Emby.Server.Implementations.LiveTv
if (isNew)
{
- await _libraryManager.CreateItem(item, cancellationToken).ConfigureAwait(false);
+ _libraryManager.CreateItem(item, cancellationToken);
}
else if (dataChanged || info.DateLastUpdated > recording.DateLastSaved || statusChanged)
{
@@ -926,10 +921,10 @@ namespace Emby.Server.Implementations.LiveTv
var topFolder = await GetInternalLiveTvFolder(cancellationToken).ConfigureAwait(false);
- if (query.SortBy.Length == 0)
+ if (query.OrderBy.Length == 0)
{
// Unless something else was specified, order by start date to take advantage of a specialized index
- query.SortBy = new[] { ItemSortBy.StartDate };
+ query.OrderBy = new Tuple<string, SortOrder>[] { new Tuple<string, SortOrder>(ItemSortBy.StartDate, SortOrder.Ascending) };
}
RemoveFields(options);
@@ -950,8 +945,7 @@ namespace Emby.Server.Implementations.LiveTv
Genres = query.Genres,
StartIndex = query.StartIndex,
Limit = query.Limit,
- SortBy = query.SortBy,
- SortOrder = query.SortOrder ?? SortOrder.Ascending,
+ OrderBy = query.OrderBy,
EnableTotalRecordCount = query.EnableTotalRecordCount,
TopParentIds = new[] { topFolder.Id.ToString("N") },
Name = query.Name,
@@ -993,7 +987,7 @@ namespace Emby.Server.Implementations.LiveTv
var queryResult = _libraryManager.QueryItems(internalQuery);
- var returnArray = (await _dtoService.GetBaseItemDtos(queryResult.Items, options, user).ConfigureAwait(false)).ToArray();
+ var returnArray = _dtoService.GetBaseItemDtos(queryResult.Items, options, user);
var result = new QueryResult<BaseItemDto>
{
@@ -1004,7 +998,7 @@ namespace Emby.Server.Implementations.LiveTv
return result;
}
- public async Task<QueryResult<LiveTvProgram>> GetRecommendedProgramsInternal(RecommendedProgramQuery query, DtoOptions options, CancellationToken cancellationToken)
+ public async Task<QueryResult<BaseItem>> GetRecommendedProgramsInternal(RecommendedProgramQuery query, DtoOptions options, CancellationToken cancellationToken)
{
var user = _userManager.GetUserById(query.UserId);
@@ -1020,7 +1014,7 @@ namespace Emby.Server.Implementations.LiveTv
IsSports = query.IsSports,
IsKids = query.IsKids,
EnableTotalRecordCount = query.EnableTotalRecordCount,
- SortBy = new[] { ItemSortBy.StartDate },
+ OrderBy = new[] { new Tuple<string, SortOrder>(ItemSortBy.StartDate, SortOrder.Ascending) },
TopParentIds = new[] { topFolder.Id.ToString("N") },
DtoOptions = options
};
@@ -1042,10 +1036,10 @@ namespace Emby.Server.Implementations.LiveTv
}
}
- var programList = _libraryManager.QueryItems(internalQuery).Items.Cast<LiveTvProgram>().ToList();
- var totalCount = programList.Count;
+ var programList = _libraryManager.QueryItems(internalQuery).Items;
+ var totalCount = programList.Length;
- IOrderedEnumerable<LiveTvProgram> orderedPrograms = programList.OrderBy(i => i.StartDate.Date);
+ IOrderedEnumerable<LiveTvProgram> orderedPrograms = programList.Cast<LiveTvProgram>().OrderBy(i => i.StartDate.Date);
if (query.IsAiring ?? false)
{
@@ -1053,14 +1047,14 @@ namespace Emby.Server.Implementations.LiveTv
.ThenByDescending(i => GetRecommendationScore(i, user.Id, true));
}
- IEnumerable<LiveTvProgram> programs = orderedPrograms;
+ IEnumerable<BaseItem> programs = orderedPrograms;
if (query.Limit.HasValue)
{
programs = programs.Take(query.Limit.Value);
}
- var result = new QueryResult<LiveTvProgram>
+ var result = new QueryResult<BaseItem>
{
Items = programs.ToArray(),
TotalRecordCount = totalCount
@@ -1077,7 +1071,7 @@ namespace Emby.Server.Implementations.LiveTv
var user = _userManager.GetUserById(query.UserId);
- var returnArray = (await _dtoService.GetBaseItemDtos(internalResult.Items, options, user).ConfigureAwait(false)).ToArray();
+ var returnArray = _dtoService.GetBaseItemDtos(internalResult.Items, options, user);
var result = new QueryResult<BaseItemDto>
{
@@ -1227,9 +1221,9 @@ namespace Emby.Server.Implementations.LiveTv
await EmbyTV.EmbyTV.Current.ScanForTunerDeviceChanges(cancellationToken).ConfigureAwait(false);
var numComplete = 0;
- double progressPerService = _services.Count == 0
+ double progressPerService = _services.Length == 0
? 0
- : 1 / _services.Count;
+ : 1 / _services.Length;
var newChannelIdList = new List<Guid>();
var newProgramIdList = new List<Guid>();
@@ -1261,13 +1255,13 @@ namespace Emby.Server.Implementations.LiveTv
numComplete++;
double percent = numComplete;
- percent /= _services.Count;
+ percent /= _services.Length;
progress.Report(100 * percent);
}
- await CleanDatabaseInternal(newChannelIdList, new[] { typeof(LiveTvChannel).Name }, progress, cancellationToken).ConfigureAwait(false);
- await CleanDatabaseInternal(newProgramIdList, new[] { typeof(LiveTvProgram).Name }, progress, cancellationToken).ConfigureAwait(false);
+ await CleanDatabaseInternal(newChannelIdList.ToArray(), new[] { typeof(LiveTvChannel).Name }, progress, cancellationToken).ConfigureAwait(false);
+ await CleanDatabaseInternal(newProgramIdList.ToArray(), new[] { typeof(LiveTvProgram).Name }, progress, cancellationToken).ConfigureAwait(false);
var coreService = _services.OfType<EmbyTV.EmbyTV>().FirstOrDefault();
@@ -1279,8 +1273,11 @@ namespace Emby.Server.Implementations.LiveTv
// Load these now which will prefetch metadata
var dtoOptions = new DtoOptions();
- dtoOptions.Fields.Remove(ItemFields.SyncInfo);
- dtoOptions.Fields.Remove(ItemFields.BasicSyncInfo);
+ var fields = dtoOptions.Fields.ToList();
+ fields.Remove(ItemFields.SyncInfo);
+ fields.Remove(ItemFields.BasicSyncInfo);
+ dtoOptions.Fields = fields.ToArray(fields.Count);
+
await GetRecordings(new RecordingQuery(), dtoOptions, cancellationToken).ConfigureAwait(false);
progress.Report(100);
@@ -1413,7 +1410,7 @@ namespace Emby.Server.Implementations.LiveTv
if (newPrograms.Count > 0)
{
- await _libraryManager.CreateItems(newPrograms, cancellationToken).ConfigureAwait(false);
+ _libraryManager.CreateItems(newPrograms, cancellationToken);
}
// TODO: Do this in bulk
@@ -1450,14 +1447,14 @@ namespace Emby.Server.Implementations.LiveTv
return new Tuple<List<Guid>, List<Guid>>(channels, programs);
}
- private async Task CleanDatabaseInternal(List<Guid> currentIdList, string[] validTypes, IProgress<double> progress, CancellationToken cancellationToken)
+ private async Task CleanDatabaseInternal(Guid[] currentIdList, string[] validTypes, IProgress<double> progress, CancellationToken cancellationToken)
{
var list = _itemRepo.GetItemIdsList(new InternalItemsQuery
{
IncludeItemTypes = validTypes,
DtoOptions = new DtoOptions(false)
- }).ToList();
+ });
var numComplete = 0;
@@ -1547,7 +1544,7 @@ namespace Emby.Server.Implementations.LiveTv
var idList = await Task.WhenAll(recordingTasks).ConfigureAwait(false);
- await CleanDatabaseInternal(idList.ToList(), new[] { typeof(LiveTvVideoRecording).Name, typeof(LiveTvAudioRecording).Name }, new SimpleProgress<double>(), cancellationToken).ConfigureAwait(false);
+ await CleanDatabaseInternal(idList, new[] { typeof(LiveTvVideoRecording).Name, typeof(LiveTvAudioRecording).Name }, new SimpleProgress<double>(), cancellationToken).ConfigureAwait(false);
_lastRecordingRefreshTime = DateTime.UtcNow;
}
@@ -1564,11 +1561,6 @@ namespace Emby.Server.Implementations.LiveTv
return new QueryResult<BaseItem>();
}
- if ((query.IsInProgress ?? false))
- {
- return new QueryResult<BaseItem>();
- }
-
var folderIds = EmbyTV.EmbyTV.Current.GetRecordingFolders()
.SelectMany(i => i.Locations)
.Distinct(StringComparer.OrdinalIgnoreCase)
@@ -1580,13 +1572,10 @@ namespace Emby.Server.Implementations.LiveTv
var excludeItemTypes = new List<string>();
- if (!query.IsInProgress.HasValue)
- {
- folderIds.Add(internalLiveTvFolderId);
+ folderIds.Add(internalLiveTvFolderId);
- excludeItemTypes.Add(typeof(LiveTvChannel).Name);
- excludeItemTypes.Add(typeof(LiveTvProgram).Name);
- }
+ excludeItemTypes.Add(typeof(LiveTvChannel).Name);
+ excludeItemTypes.Add(typeof(LiveTvProgram).Name);
if (folderIds.Count == 0)
{
@@ -1635,26 +1624,38 @@ namespace Emby.Server.Implementations.LiveTv
}
}
+ if ((query.IsInProgress ?? false))
+ {
+ // TODO: filter
+ var allActivePaths = EmbyTV.EmbyTV.Current.GetAllActiveRecordings().Select(i => i.Path).ToArray();
+ var items = allActivePaths.Select(i => _libraryManager.FindByPath(i, false)).Where(i => i != null).ToArray();
+
+ return new QueryResult<BaseItem>
+ {
+ Items = items,
+ TotalRecordCount = items.Length
+ };
+ }
+
return _libraryManager.GetItemsResult(new InternalItemsQuery(user)
{
MediaTypes = new[] { MediaType.Video },
Recursive = true,
- AncestorIds = folderIds.Select(i => i.ToString("N")).ToArray(),
+ AncestorIds = folderIds.Select(i => i.ToString("N")).ToArray(folderIds.Count),
IsFolder = false,
IsVirtualItem = false,
Limit = query.Limit,
StartIndex = query.StartIndex,
- SortBy = new[] { ItemSortBy.DateCreated },
- SortOrder = SortOrder.Descending,
+ OrderBy = new[] { new Tuple<string, SortOrder>(ItemSortBy.DateCreated, SortOrder.Descending) },
EnableTotalRecordCount = query.EnableTotalRecordCount,
- IncludeItemTypes = includeItemTypes.ToArray(),
- ExcludeItemTypes = excludeItemTypes.ToArray(),
- Genres = genres.ToArray(),
+ IncludeItemTypes = includeItemTypes.ToArray(includeItemTypes.Count),
+ ExcludeItemTypes = excludeItemTypes.ToArray(excludeItemTypes.Count),
+ Genres = genres.ToArray(genres.Count),
DtoOptions = dtoOptions
});
}
- public async Task<QueryResult<BaseItemDto>> GetRecordingSeries(RecordingQuery query, DtoOptions options, CancellationToken cancellationToken)
+ public QueryResult<BaseItemDto> GetRecordingSeries(RecordingQuery query, DtoOptions options, CancellationToken cancellationToken)
{
var user = string.IsNullOrEmpty(query.UserId) ? null : _userManager.GetUserById(query.UserId);
if (user != null && !IsLiveTvEnabled(user))
@@ -1662,11 +1663,6 @@ namespace Emby.Server.Implementations.LiveTv
return new QueryResult<BaseItemDto>();
}
- if (_services.Count > 1)
- {
- return new QueryResult<BaseItemDto>();
- }
-
if (user == null || (query.IsInProgress ?? false))
{
return new QueryResult<BaseItemDto>();
@@ -1695,17 +1691,16 @@ namespace Emby.Server.Implementations.LiveTv
var internalResult = _libraryManager.GetItemsResult(new InternalItemsQuery(user)
{
Recursive = true,
- AncestorIds = folders.Select(i => i.Id.ToString("N")).ToArray(),
+ AncestorIds = folders.Select(i => i.Id.ToString("N")).ToArray(folders.Count),
Limit = query.Limit,
- SortBy = new[] { ItemSortBy.DateCreated },
- SortOrder = SortOrder.Descending,
+ OrderBy = new[] { new Tuple<string, SortOrder>(ItemSortBy.DateCreated, SortOrder.Descending) },
EnableTotalRecordCount = query.EnableTotalRecordCount,
- IncludeItemTypes = includeItemTypes.ToArray(),
- ExcludeItemTypes = excludeItemTypes.ToArray(),
+ IncludeItemTypes = includeItemTypes.ToArray(includeItemTypes.Count),
+ ExcludeItemTypes = excludeItemTypes.ToArray(excludeItemTypes.Count),
DtoOptions = options
});
- var returnArray = (await _dtoService.GetBaseItemDtos(internalResult.Items, options, user).ConfigureAwait(false)).ToArray();
+ var returnArray = _dtoService.GetBaseItemDtos(internalResult.Items, options, user);
return new QueryResult<BaseItemDto>
{
@@ -1724,13 +1719,9 @@ namespace Emby.Server.Implementations.LiveTv
var folder = await GetInternalLiveTvFolder(cancellationToken).ConfigureAwait(false);
- if (_services.Count == 1 && (!query.IsInProgress.HasValue || !query.IsInProgress.Value) && (!query.IsLibraryItem.HasValue || query.IsLibraryItem.Value))
+ // TODO: Figure out how to merge emby recordings + service recordings
+ if (_services.Length == 1)
{
- if (!query.IsInProgress.HasValue)
- {
- await RefreshRecordings(folder.Id, cancellationToken).ConfigureAwait(false);
- }
-
return GetEmbyRecordings(query, options, folder.Id, user);
}
@@ -1842,9 +1833,12 @@ namespace Emby.Server.Implementations.LiveTv
};
}
- public async Task AddInfoToProgramDto(List<Tuple<BaseItem, BaseItemDto>> tuples, List<ItemFields> fields, User user = null)
+ public async Task AddInfoToProgramDto(List<Tuple<BaseItem, BaseItemDto>> tuples, ItemFields[] fields, User user = null)
{
var programTuples = new List<Tuple<BaseItemDto, string, string, string>>();
+ var hasChannelImage = fields.Contains(ItemFields.ChannelImage);
+ var hasChannelInfo = fields.Contains(ItemFields.ChannelInfo);
+ var hasServiceName = fields.Contains(ItemFields.ServiceName);
foreach (var tuple in tuples)
{
@@ -1887,7 +1881,7 @@ namespace Emby.Server.Implementations.LiveTv
dto.IsPremiere = program.IsPremiere;
}
- if (fields.Contains(ItemFields.ChannelInfo))
+ if (hasChannelInfo || hasChannelImage)
{
var channel = GetInternalChannel(program.ChannelId);
@@ -1897,7 +1891,7 @@ namespace Emby.Server.Implementations.LiveTv
dto.MediaType = channel.MediaType;
dto.ChannelNumber = channel.Number;
- if (channel.HasImage(ImageType.Primary))
+ if (hasChannelImage && channel.HasImage(ImageType.Primary))
{
dto.ChannelPrimaryImageTag = _tvDtoService.GetImageTag(channel);
}
@@ -1906,7 +1900,7 @@ namespace Emby.Server.Implementations.LiveTv
var serviceName = program.ServiceName;
- if (fields.Contains(ItemFields.ServiceName))
+ if (hasServiceName)
{
dto.ServiceName = serviceName;
}
@@ -1919,6 +1913,11 @@ namespace Emby.Server.Implementations.LiveTv
await AddRecordingInfo(programTuples, CancellationToken.None).ConfigureAwait(false);
}
+ public ActiveRecordingInfo GetActiveRecordingInfo(string path)
+ {
+ return EmbyTV.EmbyTV.Current.GetActiveRecordingInfo(path);
+ }
+
public void AddInfoToRecordingDto(BaseItem item, BaseItemDto dto, User user = null)
{
var recording = (ILiveTvRecording)item;
@@ -1928,11 +1927,11 @@ namespace Emby.Server.Implementations.LiveTv
var info = recording;
- dto.SeriesTimerId = string.IsNullOrEmpty(info.SeriesTimerId)
+ dto.SeriesTimerId = string.IsNullOrEmpty(info.SeriesTimerId) || service == null
? null
: _tvDtoService.GetInternalSeriesTimerId(service.Name, info.SeriesTimerId).ToString("N");
- dto.TimerId = string.IsNullOrEmpty(info.TimerId)
+ dto.TimerId = string.IsNullOrEmpty(info.TimerId) || service == null
? null
: _tvDtoService.GetInternalTimerId(service.Name, info.TimerId).ToString("N");
@@ -1948,27 +1947,72 @@ namespace Emby.Server.Implementations.LiveTv
dto.IsKids = info.IsKids;
dto.IsPremiere = info.IsPremiere;
- dto.CanDelete = user == null
- ? recording.CanDelete()
- : recording.CanDelete(user);
-
- if (dto.MediaSources == null)
+ if (info.Status == RecordingStatus.InProgress && info.EndDate.HasValue)
{
- dto.MediaSources = recording.GetMediaSources(true).ToList();
+ var now = DateTime.UtcNow.Ticks;
+ var start = info.StartDate.Ticks;
+ var end = info.EndDate.Value.Ticks;
+
+ var pct = now - start;
+ pct /= end;
+ pct *= 100;
+ dto.CompletionPercentage = pct;
}
- if (dto.MediaStreams == null)
+ if (channel != null)
{
- dto.MediaStreams = dto.MediaSources.SelectMany(i => i.MediaStreams).ToList();
+ dto.ChannelName = channel.Name;
+
+ if (channel.HasImage(ImageType.Primary))
+ {
+ dto.ChannelPrimaryImageTag = _tvDtoService.GetImageTag(channel);
+ }
}
+ }
- if (info.Status == RecordingStatus.InProgress && info.EndDate.HasValue)
+ public void AddInfoToRecordingDto(BaseItem item, BaseItemDto dto, ActiveRecordingInfo activeRecordingInfo, User user = null)
+ {
+ var service = EmbyTV.EmbyTV.Current;
+
+ var info = activeRecordingInfo.Timer;
+
+ var channel = string.IsNullOrWhiteSpace(info.ChannelId) ? null : GetInternalChannel(_tvDtoService.GetInternalChannelId(service.Name, info.ChannelId));
+
+ dto.SeriesTimerId = string.IsNullOrEmpty(info.SeriesTimerId)
+ ? null
+ : _tvDtoService.GetInternalSeriesTimerId(service.Name, info.SeriesTimerId).ToString("N");
+
+ dto.TimerId = string.IsNullOrEmpty(info.Id)
+ ? null
+ : _tvDtoService.GetInternalTimerId(service.Name, info.Id).ToString("N");
+
+ var startDate = info.StartDate;
+ var endDate = info.EndDate;
+
+ dto.StartDate = startDate;
+ dto.EndDate = endDate;
+ dto.Status = info.Status.ToString();
+ dto.IsRepeat = info.IsRepeat;
+ dto.EpisodeTitle = info.EpisodeTitle;
+ dto.IsMovie = info.IsMovie;
+ dto.IsSeries = info.IsSeries;
+ dto.IsSports = info.IsSports;
+ dto.IsLive = info.IsLive;
+ dto.IsNews = info.IsNews;
+ dto.IsKids = info.IsKids;
+ dto.IsPremiere = info.IsPremiere;
+
+ if (info.Status == RecordingStatus.InProgress)
{
+ startDate = info.StartDate.AddSeconds(0 - info.PrePaddingSeconds);
+ endDate = info.EndDate.AddSeconds(info.PostPaddingSeconds);
+
var now = DateTime.UtcNow.Ticks;
- var start = info.StartDate.Ticks;
- var end = info.EndDate.Value.Ticks;
+ var start = startDate.Ticks;
+ var end = endDate.Ticks;
var pct = now - start;
+
pct /= end;
pct *= 100;
dto.CompletionPercentage = pct;
@@ -1993,7 +2037,7 @@ namespace Emby.Server.Implementations.LiveTv
var internalResult = await GetInternalRecordings(query, options, cancellationToken).ConfigureAwait(false);
- var returnArray = (await _dtoService.GetBaseItemDtos(internalResult.Items, options, user).ConfigureAwait(false)).ToArray();
+ var returnArray = _dtoService.GetBaseItemDtos(internalResult.Items, options, user);
return new QueryResult<BaseItemDto>
{
@@ -2081,7 +2125,7 @@ namespace Emby.Server.Implementations.LiveTv
var returnArray = returnList
.OrderBy(i => i.StartDate)
- .ToArray();
+ .ToArray(returnList.Count);
return new QueryResult<TimerInfoDto>
{
@@ -2096,7 +2140,6 @@ namespace Emby.Server.Implementations.LiveTv
if (service is EmbyTV.EmbyTV)
{
- // We can't trust that we'll be able to direct stream it through emby server, no matter what the provider says
return service.DeleteRecordingAsync(GetItemExternalId(recording), CancellationToken.None);
}
@@ -2154,7 +2197,7 @@ namespace Emby.Server.Implementations.LiveTv
await service.CancelTimerAsync(timer.ExternalId, CancellationToken.None).ConfigureAwait(false);
_lastRecordingRefreshTime = DateTime.MinValue;
- EventHelper.QueueEventIfNotNull(TimerCancelled, this, new GenericEventArgs<TimerEventInfo>
+ EventHelper.FireEventIfNotNull(TimerCancelled, this, new GenericEventArgs<TimerEventInfo>
{
Argument = new TimerEventInfo
{
@@ -2177,7 +2220,7 @@ namespace Emby.Server.Implementations.LiveTv
await service.CancelSeriesTimerAsync(timer.ExternalId, CancellationToken.None).ConfigureAwait(false);
_lastRecordingRefreshTime = DateTime.MinValue;
- EventHelper.QueueEventIfNotNull(SeriesTimerCancelled, this, new GenericEventArgs<TimerEventInfo>
+ EventHelper.FireEventIfNotNull(SeriesTimerCancelled, this, new GenericEventArgs<TimerEventInfo>
{
Argument = new TimerEventInfo
{
@@ -2321,7 +2364,7 @@ namespace Emby.Server.Implementations.LiveTv
};
}
- public async Task AddChannelInfo(List<Tuple<BaseItemDto, LiveTvChannel>> tuples, DtoOptions options, User user)
+ public void AddChannelInfo(List<Tuple<BaseItemDto, LiveTvChannel>> tuples, DtoOptions options, User user)
{
var now = DateTime.UtcNow;
@@ -2334,11 +2377,11 @@ namespace Emby.Server.Implementations.LiveTv
MaxStartDate = now,
MinEndDate = now,
Limit = channelIds.Length,
- SortBy = new[] { "StartDate" },
+ OrderBy = new[] { new Tuple<string, SortOrder>(ItemSortBy.StartDate, SortOrder.Ascending) },
TopParentIds = new[] { GetInternalLiveTvFolder(CancellationToken.None).Result.Id.ToString("N") },
DtoOptions = options
- }).ToList() : new List<BaseItem>();
+ }) : new List<BaseItem>();
RemoveFields(options);
@@ -2346,7 +2389,7 @@ namespace Emby.Server.Implementations.LiveTv
var currentChannelsDict = new Dictionary<string, BaseItemDto>();
var addCurrentProgram = options.AddCurrentProgram;
- var addMediaSources = options.Fields.Contains(ItemFields.MediaSources);
+ var addServiceName = options.Fields.Contains(ItemFields.ServiceName);
foreach (var tuple in tuples)
{
@@ -2356,15 +2399,14 @@ namespace Emby.Server.Implementations.LiveTv
dto.Number = channel.Number;
dto.ChannelNumber = channel.Number;
dto.ChannelType = channel.ChannelType;
- dto.ServiceName = channel.ServiceName;
- currentChannelsDict[dto.Id] = dto;
-
- if (addMediaSources)
+ if (addServiceName)
{
- dto.MediaSources = channel.GetMediaSources(true).ToList();
+ dto.ServiceName = channel.ServiceName;
}
+ currentChannelsDict[dto.Id] = dto;
+
if (addCurrentProgram)
{
var channelIdString = channel.Id.ToString("N");
@@ -2379,7 +2421,7 @@ namespace Emby.Server.Implementations.LiveTv
if (addCurrentProgram)
{
- var currentProgramDtos = await _dtoService.GetBaseItemDtos(currentProgramsList, options, user).ConfigureAwait(false);
+ var currentProgramDtos = _dtoService.GetBaseItemDtos(currentProgramsList, options, user);
foreach (var programDto in currentProgramDtos)
{
@@ -2470,7 +2512,7 @@ namespace Emby.Server.Implementations.LiveTv
var defaults = await GetNewTimerDefaultsInternal(cancellationToken, program).ConfigureAwait(false);
var info = _tvDtoService.GetSeriesTimerInfoDto(defaults.Item1, defaults.Item2, null);
- info.Days = defaults.Item1.Days;
+ info.Days = defaults.Item1.Days.ToArray();
info.DayPattern = _tvDtoService.GetDayPattern(info.Days);
@@ -2516,7 +2558,7 @@ namespace Emby.Server.Implementations.LiveTv
_lastRecordingRefreshTime = DateTime.MinValue;
_logger.Info("New recording scheduled");
- EventHelper.QueueEventIfNotNull(TimerCreated, this, new GenericEventArgs<TimerEventInfo>
+ EventHelper.FireEventIfNotNull(TimerCreated, this, new GenericEventArgs<TimerEventInfo>
{
Argument = new TimerEventInfo
{
@@ -2558,7 +2600,7 @@ namespace Emby.Server.Implementations.LiveTv
_lastRecordingRefreshTime = DateTime.MinValue;
- EventHelper.QueueEventIfNotNull(SeriesTimerCreated, this, new GenericEventArgs<TimerEventInfo>
+ EventHelper.FireEventIfNotNull(SeriesTimerCreated, this, new GenericEventArgs<TimerEventInfo>
{
Argument = new TimerEventInfo
{
@@ -2647,8 +2689,7 @@ namespace Emby.Server.Implementations.LiveTv
var series = recordings
.Where(i => i.IsSeries)
- .ToLookup(i => i.Name, StringComparer.OrdinalIgnoreCase)
- .ToList();
+ .ToLookup(i => i.Name, StringComparer.OrdinalIgnoreCase);
groups.AddRange(series.OrderByString(i => i.Key).Select(i => new BaseItemDto
{
@@ -2697,7 +2738,7 @@ namespace Emby.Server.Implementations.LiveTv
return new QueryResult<BaseItemDto>
{
- Items = groups.ToArray(),
+ Items = groups.ToArray(groups.Count),
TotalRecordCount = groups.Count
};
}
@@ -2738,6 +2779,7 @@ namespace Emby.Server.Implementations.LiveTv
public void Dispose()
{
Dispose(true);
+ GC.SuppressFinalize(this);
}
private bool _isDisposed = false;
@@ -2753,7 +2795,7 @@ namespace Emby.Server.Implementations.LiveTv
}
}
- private async Task<IEnumerable<LiveTvServiceInfo>> GetServiceInfos(CancellationToken cancellationToken)
+ private async Task<LiveTvServiceInfo[]> GetServiceInfos(CancellationToken cancellationToken)
{
var tasks = Services.Select(i => GetServiceInfo(i, cancellationToken));
@@ -2797,7 +2839,7 @@ namespace Emby.Server.Implementations.LiveTv
return dto;
- }).ToList();
+ }).ToArray();
}
catch (Exception ex)
{
@@ -2813,25 +2855,24 @@ namespace Emby.Server.Implementations.LiveTv
public async Task<LiveTvInfo> GetLiveTvInfo(CancellationToken cancellationToken)
{
var services = await GetServiceInfos(CancellationToken.None).ConfigureAwait(false);
- var servicesList = services.ToList();
var info = new LiveTvInfo
{
- Services = servicesList.ToList(),
- IsEnabled = servicesList.Count > 0
+ Services = services,
+ IsEnabled = services.Length > 0
};
info.EnabledUsers = _userManager.Users
.Where(IsLiveTvEnabled)
.Select(i => i.Id.ToString("N"))
- .ToList();
+ .ToArray();
return info;
}
private bool IsLiveTvEnabled(User user)
{
- return user.Policy.EnableLiveTvAccess && (Services.Count > 1 || GetConfiguration().TunerHosts.Count > 0);
+ return user.Policy.EnableLiveTvAccess && (Services.Count > 1 || GetConfiguration().TunerHosts.Length > 0);
}
public IEnumerable<User> GetEnabledUsers()
@@ -2871,10 +2912,13 @@ namespace Emby.Server.Implementations.LiveTv
private void RemoveFields(DtoOptions options)
{
- options.Fields.Remove(ItemFields.CanDelete);
- options.Fields.Remove(ItemFields.CanDownload);
- options.Fields.Remove(ItemFields.DisplayPreferencesId);
- options.Fields.Remove(ItemFields.Etag);
+ var fields = options.Fields.ToList();
+
+ fields.Remove(ItemFields.CanDelete);
+ fields.Remove(ItemFields.CanDownload);
+ fields.Remove(ItemFields.DisplayPreferencesId);
+ fields.Remove(ItemFields.Etag);
+ options.Fields = fields.ToArray(fields.Count);
}
public async Task<Folder> GetInternalLiveTvFolder(CancellationToken cancellationToken)
@@ -2902,12 +2946,14 @@ namespace Emby.Server.Implementations.LiveTv
var config = GetConfiguration();
- var index = config.TunerHosts.FindIndex(i => string.Equals(i.Id, info.Id, StringComparison.OrdinalIgnoreCase));
+ var list = config.TunerHosts.ToList();
+ var index = list.FindIndex(i => string.Equals(i.Id, info.Id, StringComparison.OrdinalIgnoreCase));
if (index == -1 || string.IsNullOrWhiteSpace(info.Id))
{
info.Id = Guid.NewGuid().ToString("N");
- config.TunerHosts.Add(info);
+ list.Add(info);
+ config.TunerHosts = list.ToArray(list.Count);
}
else
{
@@ -2939,12 +2985,14 @@ namespace Emby.Server.Implementations.LiveTv
var config = GetConfiguration();
- var index = config.ListingProviders.FindIndex(i => string.Equals(i.Id, info.Id, StringComparison.OrdinalIgnoreCase));
+ var list = config.ListingProviders.ToList();
+ var index = list.FindIndex(i => string.Equals(i.Id, info.Id, StringComparison.OrdinalIgnoreCase));
if (index == -1 || string.IsNullOrWhiteSpace(info.Id))
{
info.Id = Guid.NewGuid().ToString("N");
- config.ListingProviders.Add(info);
+ list.Add(info);
+ config.ListingProviders = list.ToArray(list.Count);
info.EnableNewProgramIds = true;
}
else
@@ -2963,7 +3011,7 @@ namespace Emby.Server.Implementations.LiveTv
{
var config = GetConfiguration();
- config.ListingProviders = config.ListingProviders.Where(i => !string.Equals(id, i.Id, StringComparison.OrdinalIgnoreCase)).ToList();
+ config.ListingProviders = config.ListingProviders.Where(i => !string.Equals(id, i.Id, StringComparison.OrdinalIgnoreCase)).ToArray();
_config.SaveConfiguration("livetv", config);
_taskManager.CancelIfRunningAndQueue<RefreshChannelsScheduledTask>();
@@ -2984,7 +3032,7 @@ namespace Emby.Server.Implementations.LiveTv
Name = tunerChannelId,
Value = providerChannelId
});
- listingsProviderInfo.ChannelMappings = list.ToArray();
+ listingsProviderInfo.ChannelMappings = list.ToArray(list.Count);
}
_config.SaveConfiguration("livetv", config);
@@ -2995,7 +3043,7 @@ namespace Emby.Server.Implementations.LiveTv
var providerChannels = await GetChannelsFromListingsProviderData(providerId, CancellationToken.None)
.ConfigureAwait(false);
- var mappings = listingsProviderInfo.ChannelMappings.ToList();
+ var mappings = listingsProviderInfo.ChannelMappings;
var tunerChannelMappings =
tunerChannels.Select(i => GetTunerChannelMapping(i, mappings, providerChannels)).ToList();
@@ -3005,7 +3053,7 @@ namespace Emby.Server.Implementations.LiveTv
return tunerChannelMappings.First(i => string.Equals(i.Id, tunerChannelId, StringComparison.OrdinalIgnoreCase));
}
- public TunerChannelMapping GetTunerChannelMapping(ChannelInfo tunerChannel, List<NameValuePair> mappings, List<ChannelInfo> epgChannels)
+ public TunerChannelMapping GetTunerChannelMapping(ChannelInfo tunerChannel, NameValuePair[] mappings, List<ChannelInfo> epgChannels)
{
var result = new TunerChannelMapping
{
@@ -3069,7 +3117,7 @@ namespace Emby.Server.Implementations.LiveTv
if (string.Equals(feature, "dvr-l", StringComparison.OrdinalIgnoreCase))
{
var config = GetConfiguration();
- if (config.TunerHosts.Count > 0 &&
+ if (config.TunerHosts.Length > 0 &&
config.ListingProviders.Count(i => (i.EnableAllTuners || i.EnabledTuners.Length > 0) && string.Equals(i.Type, SchedulesDirect.TypeName, StringComparison.OrdinalIgnoreCase)) > 0)
{
return Task.FromResult(new MBRegistrationRecord
diff --git a/Emby.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs b/Emby.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs
index 919c0f10d..0e52f874d 100644
--- a/Emby.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs
+++ b/Emby.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs
@@ -14,6 +14,7 @@ using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Model.Dlna;
+using MediaBrowser.Model.Extensions;
namespace Emby.Server.Implementations.LiveTv
{
@@ -42,9 +43,11 @@ namespace Emby.Server.Implementations.LiveTv
if (baseItem.SourceType == SourceType.LiveTV)
{
- if (string.IsNullOrWhiteSpace(baseItem.Path))
+ var activeRecordingInfo = _liveTvManager.GetActiveRecordingInfo(item.Path);
+
+ if (string.IsNullOrWhiteSpace(baseItem.Path) || activeRecordingInfo != null)
{
- return GetMediaSourcesInternal(item, cancellationToken);
+ return GetMediaSourcesInternal(item, activeRecordingInfo, cancellationToken);
}
}
@@ -55,7 +58,7 @@ namespace Emby.Server.Implementations.LiveTv
private const char StreamIdDelimeter = '_';
private const string StreamIdDelimeterString = "_";
- private async Task<IEnumerable<MediaSourceInfo>> GetMediaSourcesInternal(IHasMediaSources item, CancellationToken cancellationToken)
+ private async Task<IEnumerable<MediaSourceInfo>> GetMediaSourcesInternal(IHasMediaSources item, ActiveRecordingInfo activeRecordingInfo, CancellationToken cancellationToken)
{
IEnumerable<MediaSourceInfo> sources;
@@ -66,20 +69,27 @@ namespace Emby.Server.Implementations.LiveTv
if (item is ILiveTvRecording)
{
sources = await _liveTvManager.GetRecordingMediaSources(item, cancellationToken)
- .ConfigureAwait(false);
+ .ConfigureAwait(false);
}
else
{
- sources = await _liveTvManager.GetChannelMediaSources(item, cancellationToken)
- .ConfigureAwait(false);
+ if (activeRecordingInfo != null)
+ {
+ sources = await EmbyTV.EmbyTV.Current.GetRecordingStreamMediaSources(activeRecordingInfo, cancellationToken)
+ .ConfigureAwait(false);
+ }
+ else
+ {
+ sources = await _liveTvManager.GetChannelMediaSources(item, cancellationToken)
+ .ConfigureAwait(false);
+ }
}
}
catch (NotImplementedException)
{
var hasMediaSources = (IHasMediaSources)item;
- sources = _mediaSourceManager.GetStaticMediaSources(hasMediaSources, false)
- .ToList();
+ sources = _mediaSourceManager.GetStaticMediaSources(hasMediaSources, false);
forceRequireOpening = true;
}
@@ -103,7 +113,7 @@ namespace Emby.Server.Implementations.LiveTv
openKeys.Add(item.GetType().Name);
openKeys.Add(item.Id.ToString("N"));
openKeys.Add(source.Id ?? string.Empty);
- source.OpenToken = string.Join(StreamIdDelimeterString, openKeys.ToArray());
+ source.OpenToken = string.Join(StreamIdDelimeterString, openKeys.ToArray(openKeys.Count));
}
// Dummy this up so that direct play checks can still run
diff --git a/Emby.Server.Implementations/LiveTv/RecordingImageProvider.cs b/Emby.Server.Implementations/LiveTv/RecordingImageProvider.cs
index 47663bdbc..992badbb5 100644
--- a/Emby.Server.Implementations/LiveTv/RecordingImageProvider.cs
+++ b/Emby.Server.Implementations/LiveTv/RecordingImageProvider.cs
@@ -19,12 +19,12 @@ namespace Emby.Server.Implementations.LiveTv
_liveTvManager = liveTvManager;
}
- public IEnumerable<ImageType> GetSupportedImages(IHasImages item)
+ public IEnumerable<ImageType> GetSupportedImages(IHasMetadata item)
{
return new[] { ImageType.Primary };
}
- public async Task<DynamicImageResponse> GetImage(IHasImages item, ImageType type, CancellationToken cancellationToken)
+ public async Task<DynamicImageResponse> GetImage(IHasMetadata item, ImageType type, CancellationToken cancellationToken)
{
var liveTvItem = (ILiveTvRecording)item;
@@ -58,7 +58,7 @@ namespace Emby.Server.Implementations.LiveTv
get { return "Live TV Service Provider"; }
}
- public bool Supports(IHasImages item)
+ public bool Supports(IHasMetadata item)
{
return item is ILiveTvRecording;
}
diff --git a/Emby.Server.Implementations/LiveTv/RefreshChannelsScheduledTask.cs b/Emby.Server.Implementations/LiveTv/RefreshChannelsScheduledTask.cs
index 5582d8f35..cad28c809 100644
--- a/Emby.Server.Implementations/LiveTv/RefreshChannelsScheduledTask.cs
+++ b/Emby.Server.Implementations/LiveTv/RefreshChannelsScheduledTask.cs
@@ -62,7 +62,7 @@ namespace Emby.Server.Implementations.LiveTv
public bool IsHidden
{
- get { return _liveTvManager.Services.Count == 1 && GetConfiguration().TunerHosts.Count == 0; }
+ get { return _liveTvManager.Services.Count == 1 && GetConfiguration().TunerHosts.Length == 0; }
}
public bool IsEnabled
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs
index b6ba8b45c..f974b5c2c 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs
@@ -68,7 +68,10 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
{
var id = ChannelIdPrefix + i.GuideNumber;
- id += '_' + (i.GuideName ?? string.Empty).GetMD5().ToString("N");
+ if (!info.EnableNewHdhrChannelIds)
+ {
+ id += '_' + (i.GuideName ?? string.Empty).GetMD5().ToString("N");
+ }
return id;
}
@@ -419,7 +422,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
SupportsTranscoding = true,
IsInfiniteStream = true,
IgnoreDts = true,
- //SupportsProbing = false,
+ SupportsProbing = false,
//AnalyzeDurationMs = 2000000
//IgnoreIndex = true,
//ReadAtNativeFramerate = true
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunManager.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunManager.cs
index 41b058baf..c737c4cba 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunManager.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunManager.cs
@@ -99,6 +99,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
var task = StopStreaming();
Task.WaitAll(task);
+ GC.SuppressFinalize(this);
}
public async Task<bool> CheckTunerAvailability(IpAddressInfo remoteIp, int tuner, CancellationToken cancellationToken)
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs
index 113cb33f4..eac845579 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs
@@ -1,5 +1,4 @@
-using MediaBrowser.Common.Configuration;
-using MediaBrowser.Common.Extensions;
+using MediaBrowser.Common.Extensions;
using MediaBrowser.Controller.LiveTv;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
@@ -11,12 +10,10 @@ using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
-
using MediaBrowser.Model.IO;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller;
using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.IO;
using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.Model.Serialization;
using MediaBrowser.Model.System;
@@ -28,12 +25,14 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
private readonly IHttpClient _httpClient;
private readonly IServerApplicationHost _appHost;
private readonly IEnvironmentInfo _environment;
+ private readonly INetworkManager _networkManager;
- public M3UTunerHost(IServerConfigurationManager config, ILogger logger, IJsonSerializer jsonSerializer, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IHttpClient httpClient, IServerApplicationHost appHost, IEnvironmentInfo environment) : base(config, logger, jsonSerializer, mediaEncoder, fileSystem)
+ public M3UTunerHost(IServerConfigurationManager config, ILogger logger, IJsonSerializer jsonSerializer, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IHttpClient httpClient, IServerApplicationHost appHost, IEnvironmentInfo environment, INetworkManager networkManager) : base(config, logger, jsonSerializer, mediaEncoder, fileSystem)
{
_httpClient = httpClient;
_appHost = appHost;
_environment = environment;
+ _networkManager = networkManager;
}
public override string Type
@@ -41,14 +40,21 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
get { return "m3u"; }
}
- public string Name
+ public virtual string Name
{
get { return "M3U Tuner"; }
}
+ private string GetFullChannelIdPrefix(TunerHostInfo info)
+ {
+ return ChannelIdPrefix + info.Url.GetMD5().ToString("N");
+ }
+
protected override async Task<List<ChannelInfo>> GetChannelsInternal(TunerHostInfo info, CancellationToken cancellationToken)
{
- var result = await new M3uParser(Logger, FileSystem, _httpClient, _appHost).Parse(info.Url, ChannelIdPrefix, info.Id, !info.EnableTvgId, cancellationToken).ConfigureAwait(false);
+ var channelIdPrefix = GetFullChannelIdPrefix(info);
+
+ var result = await new M3uParser(Logger, FileSystem, _httpClient, _appHost).Parse(info.Url, channelIdPrefix, info.Id, cancellationToken).ConfigureAwait(false);
return result.Cast<ChannelInfo>().ToList();
}
@@ -87,80 +93,92 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
protected override async Task<List<MediaSourceInfo>> GetChannelStreamMediaSources(TunerHostInfo info, string channelId, CancellationToken cancellationToken)
{
- var urlHash = info.Url.GetMD5().ToString("N");
- var prefix = ChannelIdPrefix + urlHash;
- if (!channelId.StartsWith(prefix, StringComparison.OrdinalIgnoreCase))
+ var channelIdPrefix = GetFullChannelIdPrefix(info);
+
+ if (!channelId.StartsWith(channelIdPrefix, StringComparison.OrdinalIgnoreCase))
{
return null;
}
var channels = await GetChannels(info, true, cancellationToken).ConfigureAwait(false);
- var m3uchannels = channels.Cast<M3UChannel>();
- var channel = m3uchannels.FirstOrDefault(c => string.Equals(c.Id, channelId, StringComparison.OrdinalIgnoreCase));
+ var channel = channels.FirstOrDefault(c => string.Equals(c.Id, channelId, StringComparison.OrdinalIgnoreCase));
if (channel != null)
{
- var path = channel.Path;
- MediaProtocol protocol = MediaProtocol.File;
- if (path.StartsWith("http", StringComparison.OrdinalIgnoreCase))
- {
- protocol = MediaProtocol.Http;
- }
- else if (path.StartsWith("rtmp", StringComparison.OrdinalIgnoreCase))
- {
- protocol = MediaProtocol.Rtmp;
- }
- else if (path.StartsWith("rtsp", StringComparison.OrdinalIgnoreCase))
- {
- protocol = MediaProtocol.Rtsp;
- }
- else if (path.StartsWith("udp", StringComparison.OrdinalIgnoreCase))
- {
- protocol = MediaProtocol.Udp;
- }
- else if (path.StartsWith("rtp", StringComparison.OrdinalIgnoreCase))
- {
- protocol = MediaProtocol.Rtmp;
- }
+ return new List<MediaSourceInfo> { CreateMediaSourceInfo(info, channel) };
+ }
+ return new List<MediaSourceInfo>();
+ }
+
+ protected virtual MediaSourceInfo CreateMediaSourceInfo(TunerHostInfo info, ChannelInfo channel)
+ {
+ var path = channel.Path;
+ MediaProtocol protocol = MediaProtocol.File;
+ if (path.StartsWith("http", StringComparison.OrdinalIgnoreCase))
+ {
+ protocol = MediaProtocol.Http;
+ }
+ else if (path.StartsWith("rtmp", StringComparison.OrdinalIgnoreCase))
+ {
+ protocol = MediaProtocol.Rtmp;
+ }
+ else if (path.StartsWith("rtsp", StringComparison.OrdinalIgnoreCase))
+ {
+ protocol = MediaProtocol.Rtsp;
+ }
+ else if (path.StartsWith("udp", StringComparison.OrdinalIgnoreCase))
+ {
+ protocol = MediaProtocol.Udp;
+ }
+ else if (path.StartsWith("rtp", StringComparison.OrdinalIgnoreCase))
+ {
+ protocol = MediaProtocol.Rtmp;
+ }
- var mediaSource = new MediaSourceInfo
+ Uri uri;
+ var isRemote = true;
+ if (Uri.TryCreate(path, UriKind.Absolute, out uri))
+ {
+ isRemote = !_networkManager.IsInLocalNetwork(uri.Host);
+ }
+
+ var mediaSource = new MediaSourceInfo
+ {
+ Path = path,
+ Protocol = protocol,
+ MediaStreams = new List<MediaStream>
{
- Path = channel.Path,
- Protocol = protocol,
- MediaStreams = new List<MediaStream>
+ new MediaStream
{
- new MediaStream
- {
- Type = MediaStreamType.Video,
- // Set the index to -1 because we don't know the exact index of the video stream within the container
- Index = -1,
- IsInterlaced = true
- },
- new MediaStream
- {
- Type = MediaStreamType.Audio,
- // Set the index to -1 because we don't know the exact index of the audio stream within the container
- Index = -1
-
- }
+ Type = MediaStreamType.Video,
+ // Set the index to -1 because we don't know the exact index of the video stream within the container
+ Index = -1,
+ IsInterlaced = true
},
- RequiresOpening = true,
- RequiresClosing = true,
- RequiresLooping = info.EnableStreamLooping,
+ new MediaStream
+ {
+ Type = MediaStreamType.Audio,
+ // Set the index to -1 because we don't know the exact index of the audio stream within the container
+ Index = -1
- ReadAtNativeFramerate = false,
+ }
+ },
+ RequiresOpening = true,
+ RequiresClosing = true,
+ RequiresLooping = info.EnableStreamLooping,
+ EnableMpDecimate = info.EnableMpDecimate,
- Id = channel.Path.GetMD5().ToString("N"),
- IsInfiniteStream = true,
- IsRemote = true,
+ ReadAtNativeFramerate = false,
- IgnoreDts = true
- };
+ Id = channel.Path.GetMD5().ToString("N"),
+ IsInfiniteStream = true,
+ IsRemote = isRemote,
- mediaSource.InferTotalBitrate();
+ IgnoreDts = true
+ };
- return new List<MediaSourceInfo> { mediaSource };
- }
- return new List<MediaSourceInfo>();
+ mediaSource.InferTotalBitrate();
+
+ return mediaSource;
}
protected override Task<bool> IsAvailableInternal(TunerHostInfo tuner, string channelId, CancellationToken cancellationToken)
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs
index 8d73c7e2b..ca744b615 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs
@@ -32,25 +32,21 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
_appHost = appHost;
}
- public async Task<List<M3UChannel>> Parse(string url, string channelIdPrefix, string tunerHostId, bool enableStreamUrlAsIdentifier, CancellationToken cancellationToken)
+ public async Task<List<ChannelInfo>> Parse(string url, string channelIdPrefix, string tunerHostId, CancellationToken cancellationToken)
{
- var urlHash = url.GetMD5().ToString("N");
-
// Read the file and display it line by line.
using (var reader = new StreamReader(await GetListingsStream(url, cancellationToken).ConfigureAwait(false)))
{
- return GetChannels(reader, urlHash, channelIdPrefix, tunerHostId, enableStreamUrlAsIdentifier);
+ return GetChannels(reader, channelIdPrefix, tunerHostId);
}
}
- public List<M3UChannel> ParseString(string text, string channelIdPrefix, string tunerHostId)
+ public List<ChannelInfo> ParseString(string text, string channelIdPrefix, string tunerHostId)
{
- var urlHash = "text".GetMD5().ToString("N");
-
// Read the file and display it line by line.
using (var reader = new StringReader(text))
{
- return GetChannels(reader, urlHash, channelIdPrefix, tunerHostId, false);
+ return GetChannels(reader, channelIdPrefix, tunerHostId);
}
}
@@ -70,9 +66,9 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
}
const string ExtInfPrefix = "#EXTINF:";
- private List<M3UChannel> GetChannels(TextReader reader, string urlHash, string channelIdPrefix, string tunerHostId, bool enableStreamUrlAsIdentifier)
+ private List<ChannelInfo> GetChannels(TextReader reader, string channelIdPrefix, string tunerHostId)
{
- var channels = new List<M3UChannel>();
+ var channels = new List<ChannelInfo>();
string line;
string extInf = "";
@@ -97,13 +93,13 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
else if (!string.IsNullOrWhiteSpace(extInf) && !line.StartsWith("#", StringComparison.OrdinalIgnoreCase))
{
var channel = GetChannelnfo(extInf, tunerHostId, line);
- if (string.IsNullOrWhiteSpace(channel.Id) || enableStreamUrlAsIdentifier)
+ if (string.IsNullOrWhiteSpace(channel.Id))
{
- channel.Id = channelIdPrefix + urlHash + line.GetMD5().ToString("N");
+ channel.Id = channelIdPrefix + line.GetMD5().ToString("N");
}
else
{
- channel.Id = channelIdPrefix + urlHash + channel.Id.GetMD5().ToString("N");
+ channel.Id = channelIdPrefix + channel.Id.GetMD5().ToString("N");
}
channel.Path = line;
@@ -115,9 +111,9 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
return channels;
}
- private M3UChannel GetChannelnfo(string extInf, string tunerHostId, string mediaUrl)
+ private ChannelInfo GetChannelnfo(string extInf, string tunerHostId, string mediaUrl)
{
- var channel = new M3UChannel();
+ var channel = new ChannelInfo();
channel.TunerHostId = tunerHostId;
extInf = extInf.Trim();
@@ -339,10 +335,4 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
return dict;
}
}
-
-
- public class M3UChannel : ChannelInfo
- {
- public string Path { get; set; }
- }
} \ No newline at end of file
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/MulticastStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/MulticastStream.cs
index cf50e6092..45a0c348e 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/MulticastStream.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/MulticastStream.cs
@@ -24,8 +24,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
public async Task CopyUntilCancelled(Stream source, Action onStarted, CancellationToken cancellationToken)
{
- byte[] buffer = new byte[BufferSize];
-
if (source == null)
{
throw new ArgumentNullException("source");
@@ -35,25 +33,15 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
{
cancellationToken.ThrowIfCancellationRequested();
+ byte[] buffer = new byte[BufferSize];
+
var bytesRead = source.Read(buffer, 0, buffer.Length);
if (bytesRead > 0)
{
- var allStreams = _outputStreams.ToList();
-
- //if (allStreams.Count == 1)
- //{
- // allStreams[0].Value.Write(buffer, 0, bytesRead);
- //}
- //else
+ foreach (var stream in _outputStreams)
{
- byte[] copy = new byte[bytesRead];
- Buffer.BlockCopy(buffer, 0, copy, 0, bytesRead);
-
- foreach (var stream in allStreams)
- {
- stream.Value.Queue(copy, 0, copy.Length);
- }
+ stream.Value.Queue(buffer, 0, bytesRead);
}
if (onStarted != null)
@@ -73,27 +61,21 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
public Task CopyToAsync(Stream stream, CancellationToken cancellationToken)
{
- var result = new QueueStream(stream, _logger)
- {
- OnFinished = OnFinished
- };
-
- _outputStreams.TryAdd(result.Id, result);
+ var queueStream = new QueueStream(stream, _logger);
- result.Start(cancellationToken);
-
- return result.TaskCompletion.Task;
- }
+ _outputStreams.TryAdd(queueStream.Id, queueStream);
- public void RemoveOutputStream(QueueStream stream)
- {
- QueueStream removed;
- _outputStreams.TryRemove(stream.Id, out removed);
- }
+ try
+ {
+ queueStream.Start(cancellationToken);
+ }
+ finally
+ {
+ _outputStreams.TryRemove(queueStream.Id, out queueStream);
+ GC.Collect();
+ }
- private void OnFinished(QueueStream queueStream)
- {
- RemoveOutputStream(queueStream);
+ return Task.FromResult(true);
}
}
}
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/QueueStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/QueueStream.cs
index 61bc390b4..07a4daa87 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/QueueStream.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/QueueStream.cs
@@ -13,10 +13,8 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
public class QueueStream
{
private readonly Stream _outputStream;
- private readonly ConcurrentQueue<Tuple<byte[], int, int>> _queue = new ConcurrentQueue<Tuple<byte[], int, int>>();
- public TaskCompletionSource<bool> TaskCompletion { get; private set; }
+ private readonly BlockingCollection<Tuple<byte[], int, int>> _queue = new BlockingCollection<Tuple<byte[], int, int>>();
- public Action<QueueStream> OnFinished { get; set; }
private readonly ILogger _logger;
public Guid Id = Guid.NewGuid();
@@ -24,94 +22,24 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
{
_outputStream = outputStream;
_logger = logger;
- TaskCompletion = new TaskCompletionSource<bool>();
}
public void Queue(byte[] bytes, int offset, int count)
{
- _queue.Enqueue(new Tuple<byte[], int, int>(bytes, offset, count));
+ _queue.Add(new Tuple<byte[], int, int>(bytes, offset, count));
}
public void Start(CancellationToken cancellationToken)
{
- Task.Run(() => StartInternal(cancellationToken));
- }
-
- private Tuple<byte[], int, int> Dequeue()
- {
- Tuple<byte[], int, int> result;
- if (_queue.TryDequeue(out result))
- {
- return result;
- }
-
- return null;
- }
-
- private void OnClosed()
- {
- GC.Collect();
- if (OnFinished != null)
- {
- OnFinished(this);
- }
- }
-
- public void Write(byte[] bytes, int offset, int count)
- {
- //return _outputStream.WriteAsync(bytes, offset, count, cancellationToken);
-
- try
+ while (true)
{
- _outputStream.Write(bytes, offset, count);
- }
- catch (OperationCanceledException)
- {
- _logger.Debug("QueueStream cancelled");
- TaskCompletion.TrySetCanceled();
- OnClosed();
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error in QueueStream", ex);
- TaskCompletion.TrySetException(ex);
- OnClosed();
- }
- }
-
- private async Task StartInternal(CancellationToken cancellationToken)
- {
- try
- {
- while (true)
+ foreach (var result in _queue.GetConsumingEnumerable())
{
cancellationToken.ThrowIfCancellationRequested();
- var result = Dequeue();
- if (result != null)
- {
- _outputStream.Write(result.Item1, result.Item2, result.Item3);
- }
- else
- {
- await Task.Delay(50, cancellationToken).ConfigureAwait(false);
- }
+ _outputStream.Write(result.Item1, result.Item2, result.Item3);
}
}
- catch (OperationCanceledException)
- {
- _logger.Debug("QueueStream cancelled");
- TaskCompletion.TrySetCanceled();
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error in QueueStream", ex);
- TaskCompletion.TrySetException(ex);
- }
- finally
- {
- OnClosed();
- }
}
}
}
diff --git a/Emby.Server.Implementations/Localization/Core/core.json b/Emby.Server.Implementations/Localization/Core/core.json
deleted file mode 100644
index 976faa8cb..000000000
--- a/Emby.Server.Implementations/Localization/Core/core.json
+++ /dev/null
@@ -1,179 +0,0 @@
-{
- "AppDeviceValues": "App: {0}, Device: {1}",
- "UserDownloadingItemWithValues": "{0} is downloading {1}",
- "FolderTypeMixed": "Mixed content",
- "FolderTypeMovies": "Movies",
- "FolderTypeMusic": "Music",
- "FolderTypeAdultVideos": "Adult videos",
- "FolderTypePhotos": "Photos",
- "FolderTypeMusicVideos": "Music videos",
- "FolderTypeHomeVideos": "Home videos",
- "FolderTypeGames": "Games",
- "FolderTypeBooks": "Books",
- "FolderTypeTvShows": "TV",
- "FolderTypeInherit": "Inherit",
- "HeaderCastCrew": "Cast & Crew",
- "HeaderPeople": "People",
- "ValueSpecialEpisodeName": "Special - {0}",
- "LabelChapterName": "Chapter {0}",
- "NameSeasonNumber": "Season {0}",
- "LabelExit": "Exit",
- "LabelVisitCommunity": "Visit Community",
- "LabelGithub": "Github",
- "LabelApiDocumentation": "Api Documentation",
- "LabelDeveloperResources": "Developer Resources",
- "LabelBrowseLibrary": "Browse Library",
- "LabelConfigureServer": "Configure Emby",
- "LabelRestartServer": "Restart Server",
- "CategorySync": "Sync",
- "CategoryUser": "User",
- "CategorySystem": "System",
- "CategoryApplication": "Application",
- "CategoryPlugin": "Plugin",
- "NotificationOptionPluginError": "Plugin failure",
- "NotificationOptionApplicationUpdateAvailable": "Application update available",
- "NotificationOptionApplicationUpdateInstalled": "Application update installed",
- "NotificationOptionPluginUpdateInstalled": "Plugin update installed",
- "NotificationOptionPluginInstalled": "Plugin installed",
- "NotificationOptionPluginUninstalled": "Plugin uninstalled",
- "NotificationOptionVideoPlayback": "Video playback started",
- "NotificationOptionAudioPlayback": "Audio playback started",
- "NotificationOptionGamePlayback": "Game playback started",
- "NotificationOptionVideoPlaybackStopped": "Video playback stopped",
- "NotificationOptionAudioPlaybackStopped": "Audio playback stopped",
- "NotificationOptionGamePlaybackStopped": "Game playback stopped",
- "NotificationOptionTaskFailed": "Scheduled task failure",
- "NotificationOptionInstallationFailed": "Installation failure",
- "NotificationOptionNewLibraryContent": "New content added",
- "NotificationOptionNewLibraryContentMultiple": "New content added (multiple)",
- "NotificationOptionCameraImageUploaded": "Camera image uploaded",
- "NotificationOptionUserLockedOut": "User locked out",
- "NotificationOptionServerRestartRequired": "Server restart required",
- "ViewTypePlaylists": "Playlists",
- "ViewTypeMovies": "Movies",
- "ViewTypeTvShows": "TV",
- "ViewTypeGames": "Games",
- "ViewTypeMusic": "Music",
- "ViewTypeMusicGenres": "Genres",
- "ViewTypeMusicArtists": "Artists",
- "ViewTypeBoxSets": "Collections",
- "ViewTypeChannels": "Channels",
- "ViewTypeLiveTV": "Live TV",
- "ViewTypeLiveTvNowPlaying": "Now Airing",
- "ViewTypeLatestGames": "Latest Games",
- "ViewTypeRecentlyPlayedGames": "Recently Played",
- "ViewTypeGameFavorites": "Favorites",
- "ViewTypeGameSystems": "Game Systems",
- "ViewTypeGameGenres": "Genres",
- "ViewTypeTvResume": "Resume",
- "ViewTypeTvNextUp": "Next Up",
- "ViewTypeTvLatest": "Latest",
- "ViewTypeTvShowSeries": "Series",
- "ViewTypeTvGenres": "Genres",
- "ViewTypeTvFavoriteSeries": "Favorite Series",
- "ViewTypeTvFavoriteEpisodes": "Favorite Episodes",
- "ViewTypeMovieResume": "Resume",
- "ViewTypeMovieLatest": "Latest",
- "ViewTypeMovieMovies": "Movies",
- "ViewTypeMovieCollections": "Collections",
- "ViewTypeMovieFavorites": "Favorites",
- "ViewTypeMovieGenres": "Genres",
- "ViewTypeMusicLatest": "Latest",
- "ViewTypeMusicPlaylists": "Playlists",
- "ViewTypeMusicAlbums": "Albums",
- "ViewTypeMusicAlbumArtists": "Album Artists",
- "HeaderOtherDisplaySettings": "Display Settings",
- "ViewTypeMusicSongs": "Songs",
- "ViewTypeMusicFavorites": "Favorites",
- "ViewTypeMusicFavoriteAlbums": "Favorite Albums",
- "ViewTypeMusicFavoriteArtists": "Favorite Artists",
- "ViewTypeMusicFavoriteSongs": "Favorite Songs",
- "ViewTypeFolders": "Folders",
- "ViewTypeLiveTvRecordingGroups": "Recordings",
- "ViewTypeLiveTvChannels": "Channels",
- "ScheduledTaskFailedWithName": "{0} failed",
- "LabelRunningTimeValue": "Running time: {0}",
- "ScheduledTaskStartedWithName": "{0} started",
- "VersionNumber": "Version {0}",
- "PluginInstalledWithName": "{0} was installed",
- "PluginUpdatedWithName": "{0} was updated",
- "PluginUninstalledWithName": "{0} was uninstalled",
- "ItemAddedWithName": "{0} was added to the library",
- "ItemRemovedWithName": "{0} was removed from the library",
- "LabelIpAddressValue": "Ip address: {0}",
- "DeviceOnlineWithName": "{0} is connected",
- "UserOnlineFromDevice": "{0} is online from {1}",
- "ProviderValue": "Provider: {0}",
- "SubtitlesDownloadedForItem": "Subtitles downloaded for {0}",
- "UserConfigurationUpdatedWithName": "User configuration has been updated for {0}",
- "UserCreatedWithName": "User {0} has been created",
- "UserPasswordChangedWithName": "Password has been changed for user {0}",
- "UserDeletedWithName": "User {0} has been deleted",
- "MessageServerConfigurationUpdated": "Server configuration has been updated",
- "MessageNamedServerConfigurationUpdatedWithValue": "Server configuration section {0} has been updated",
- "MessageApplicationUpdated": "Emby Server has been updated",
- "FailedLoginAttemptWithUserName": "Failed login attempt from {0}",
- "AuthenticationSucceededWithUserName": "{0} successfully authenticated",
- "DeviceOfflineWithName": "{0} has disconnected",
- "UserLockedOutWithName": "User {0} has been locked out",
- "UserOfflineFromDevice": "{0} has disconnected from {1}",
- "UserStartedPlayingItemWithValues": "{0} has started playing {1}",
- "UserStoppedPlayingItemWithValues": "{0} has stopped playing {1}",
- "SubtitlesDownloadedForItem": "Subtitles downloaded for {0}",
- "SubtitleDownloadFailureForItem": "Subtitles failed to download for {0}",
- "HeaderUnidentified": "Unidentified",
- "HeaderImagePrimary": "Primary",
- "HeaderImageBackdrop": "Backdrop",
- "HeaderImageLogo": "Logo",
- "HeaderUserPrimaryImage": "User Image",
- "HeaderOverview": "Overview",
- "HeaderShortOverview": "Short Overview",
- "HeaderType": "Type",
- "HeaderSeverity": "Severity",
- "HeaderUser": "User",
- "HeaderName": "Name",
- "HeaderDate": "Date",
- "HeaderPremiereDate": "Premiere Date",
- "HeaderDateAdded": "Date Added",
- "HeaderReleaseDate": "Release date",
- "HeaderRuntime": "Runtime",
- "HeaderPlayCount": "Play Count",
- "HeaderSeason": "Season",
- "HeaderSeasonNumber": "Season number",
- "HeaderSeries": "Series:",
- "HeaderNetwork": "Network",
- "HeaderYear": "Year:",
- "HeaderYears": "Years:",
- "HeaderParentalRating": "Parental Rating",
- "HeaderCommunityRating": "Community rating",
- "HeaderTrailers": "Trailers",
- "HeaderSpecials": "Specials",
- "HeaderGameSystems": "Game Systems",
- "HeaderPlayers": "Players:",
- "HeaderAlbumArtists": "Album Artists",
- "HeaderAlbums": "Albums",
- "HeaderDisc": "Disc",
- "HeaderTrack": "Track",
- "HeaderAudio": "Audio",
- "HeaderVideo": "Video",
- "HeaderEmbeddedImage": "Embedded image",
- "HeaderResolution": "Resolution",
- "HeaderSubtitles": "Subtitles",
- "HeaderGenres": "Genres",
- "HeaderCountries": "Countries",
- "HeaderStatus": "Status",
- "HeaderTracks": "Tracks",
- "HeaderMusicArtist": "Music artist",
- "HeaderLocked": "Locked",
- "HeaderStudios": "Studios",
- "HeaderActor": "Actors",
- "HeaderComposer": "Composers",
- "HeaderDirector": "Directors",
- "HeaderGuestStar": "Guest star",
- "HeaderProducer": "Producers",
- "HeaderWriter": "Writers",
- "HeaderParentalRatings": "Parental Ratings",
- "HeaderCommunityRatings": "Community ratings",
- "StartupEmbyServerIsLoading": "Emby Server is loading. Please try again shortly.",
- "DbUpgradeMessage": "Please wait while your Emby Server database is upgraded. {0}% complete."
-}
diff --git a/Emby.Server.Implementations/Localization/Core/en-US.json b/Emby.Server.Implementations/Localization/Core/en-US.json
index bc0dc236d..c7f865233 100644
--- a/Emby.Server.Implementations/Localization/Core/en-US.json
+++ b/Emby.Server.Implementations/Localization/Core/en-US.json
@@ -1,5 +1,4 @@
{
- "DbUpgradeMessage": "Please wait while your Emby Server database is upgraded. {0}% complete.",
"AppDeviceValues": "App: {0}, Device: {1}",
"UserDownloadingItemWithValues": "{0} is downloading {1}",
"FolderTypeMixed": "Mixed content",
@@ -13,15 +12,12 @@
"FolderTypeBooks": "Books",
"FolderTypeTvShows": "TV",
"FolderTypeInherit": "Inherit",
- "HeaderCastCrew": "Cast & Crew",
- "HeaderPeople": "People",
"ValueSpecialEpisodeName": "Special - {0}",
"LabelChapterName": "Chapter {0}",
"NameSeasonUnknown": "Season Unknown",
"NameSeasonNumber": "Season {0}",
"LabelExit": "Exit",
"LabelVisitCommunity": "Visit Community",
- "LabelGithub": "Github",
"LabelApiDocumentation": "Api Documentation",
"LabelDeveloperResources": "Developer Resources",
"LabelBrowseLibrary": "Browse Library",
@@ -69,7 +65,7 @@
"ViewTypeTvResume": "Resume",
"ViewTypeTvNextUp": "Next Up",
"ViewTypeTvLatest": "Latest",
- "ViewTypeTvShowSeries": "Series",
+ "ViewTypeTvShowSeries": "Shows",
"ViewTypeTvGenres": "Genres",
"ViewTypeTvFavoriteSeries": "Favorite Series",
"ViewTypeTvFavoriteEpisodes": "Favorite Episodes",
@@ -164,15 +160,5 @@
"HeaderStatus": "Status",
"HeaderTracks": "Tracks",
"HeaderMusicArtist": "Music artist",
- "HeaderLocked": "Locked",
- "HeaderStudios": "Studios",
- "HeaderActor": "Actors",
- "HeaderComposer": "Composers",
- "HeaderDirector": "Directors",
- "HeaderGuestStar": "Guest star",
- "HeaderProducer": "Producers",
- "HeaderWriter": "Writers",
- "HeaderParentalRatings": "Parental Ratings",
- "HeaderCommunityRatings": "Community ratings",
"StartupEmbyServerIsLoading": "Emby Server is loading. Please try again shortly."
} \ No newline at end of file
diff --git a/Emby.Server.Implementations/Localization/LocalizationManager.cs b/Emby.Server.Implementations/Localization/LocalizationManager.cs
index 64a41acef..278a39cd1 100644
--- a/Emby.Server.Implementations/Localization/LocalizationManager.cs
+++ b/Emby.Server.Implementations/Localization/LocalizationManager.cs
@@ -132,7 +132,7 @@ namespace Emby.Server.Implementations.Localization
/// Gets the cultures.
/// </summary>
/// <returns>IEnumerable{CultureDto}.</returns>
- public IEnumerable<CultureDto> GetCultures()
+ public CultureDto[] GetCultures()
{
var type = GetType();
var path = type.Namespace + ".iso6392.txt";
@@ -169,21 +169,21 @@ namespace Emby.Server.Implementations.Localization
return list.Where(i => !string.IsNullOrWhiteSpace(i.Name) &&
!string.IsNullOrWhiteSpace(i.DisplayName) &&
!string.IsNullOrWhiteSpace(i.ThreeLetterISOLanguageName) &&
- !string.IsNullOrWhiteSpace(i.TwoLetterISOLanguageName));
+ !string.IsNullOrWhiteSpace(i.TwoLetterISOLanguageName)).ToArray();
}
/// <summary>
/// Gets the countries.
/// </summary>
/// <returns>IEnumerable{CountryInfo}.</returns>
- public IEnumerable<CountryInfo> GetCountries()
+ public CountryInfo[] GetCountries()
{
var type = GetType();
var path = type.Namespace + ".countries.json";
using (var stream = _assemblyInfo.GetManifestResourceStream(type, path))
{
- return _jsonSerializer.DeserializeFromStream<List<CountryInfo>>(stream);
+ return _jsonSerializer.DeserializeFromStream<CountryInfo[]>(stream);
}
}
@@ -191,9 +191,9 @@ namespace Emby.Server.Implementations.Localization
/// Gets the parental ratings.
/// </summary>
/// <returns>IEnumerable{ParentalRating}.</returns>
- public IEnumerable<ParentalRating> GetParentalRatings()
+ public ParentalRating[] GetParentalRatings()
{
- return GetParentalRatingsDictionary().Values.ToList();
+ return GetParentalRatingsDictionary().Values.ToArray();
}
/// <summary>
@@ -335,7 +335,7 @@ namespace Emby.Server.Implementations.Localization
const string prefix = "Core";
var key = prefix + culture;
- return _dictionaries.GetOrAdd(key, k => GetDictionary(prefix, culture, "core.json"));
+ return _dictionaries.GetOrAdd(key, k => GetDictionary(prefix, culture, "en-US.json"));
}
private Dictionary<string, string> GetDictionary(string prefix, string culture, string baseFilename)
@@ -382,9 +382,9 @@ namespace Emby.Server.Implementations.Localization
return culture + ".json";
}
- public IEnumerable<LocalizatonOption> GetLocalizationOptions()
+ public LocalizatonOption[] GetLocalizationOptions()
{
- return new List<LocalizatonOption>
+ return new LocalizatonOption[]
{
new LocalizatonOption{ Name="Arabic", Value="ar"},
new LocalizatonOption{ Name="Bulgarian (Bulgaria)", Value="bg-BG"},
@@ -421,7 +421,7 @@ namespace Emby.Server.Implementations.Localization
new LocalizatonOption{ Name="Ukrainian", Value="uk"},
new LocalizatonOption{ Name="Vietnamese", Value="vi"}
- }.OrderBy(i => i.Name);
+ };
}
}
diff --git a/Emby.Server.Implementations/Localization/Ratings/es.txt b/Emby.Server.Implementations/Localization/Ratings/es.txt
index 1ba24fb99..32a1e6438 100644
--- a/Emby.Server.Implementations/Localization/Ratings/es.txt
+++ b/Emby.Server.Implementations/Localization/Ratings/es.txt
@@ -1,4 +1,5 @@
ES-A,1
+ES-APTA,1
ES-7,3
ES-12,6
ES-16,8
diff --git a/Emby.Server.Implementations/Localization/Ratings/ro.txt b/Emby.Server.Implementations/Localization/Ratings/ro.txt
new file mode 100644
index 000000000..3fdaed9cc
--- /dev/null
+++ b/Emby.Server.Implementations/Localization/Ratings/ro.txt
@@ -0,0 +1 @@
+RO-AG,1 \ No newline at end of file
diff --git a/Emby.Server.Implementations/Localization/Ratings/us.txt b/Emby.Server.Implementations/Localization/Ratings/us.txt
index 3f5311e0e..9bd78c72b 100644
--- a/Emby.Server.Implementations/Localization/Ratings/us.txt
+++ b/Emby.Server.Implementations/Localization/Ratings/us.txt
@@ -1,3 +1,4 @@
+APPROVED,1
G,1
E,1
EC,1
diff --git a/Emby.Server.Core/Localization/TextLocalizer.cs b/Emby.Server.Implementations/Localization/TextLocalizer.cs
index 1e8ccbbfa..5188a959e 100644
--- a/Emby.Server.Core/Localization/TextLocalizer.cs
+++ b/Emby.Server.Implementations/Localization/TextLocalizer.cs
@@ -3,9 +3,8 @@ using System.Globalization;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
-using Emby.Server.Implementations.Localization;
-namespace Emby.Server.Core.Localization
+namespace Emby.Server.Implementations.Localization
{
public class TextLocalizer : ITextLocalizer
{
diff --git a/Emby.Server.Core/Logging/ConsoleLogger.cs b/Emby.Server.Implementations/Logging/ConsoleLogger.cs
index 01eca7b7e..51199f08a 100644
--- a/Emby.Server.Core/Logging/ConsoleLogger.cs
+++ b/Emby.Server.Implementations/Logging/ConsoleLogger.cs
@@ -1,10 +1,7 @@
using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading.Tasks;
using MediaBrowser.Model.Logging;
-namespace Emby.Server.Core.Logging
+namespace Emby.Server.Implementations.Logging
{
public class ConsoleLogger : IConsoleLogger
{
diff --git a/Emby.Server.Implementations/Logging/SimpleLogManager.cs b/Emby.Server.Implementations/Logging/SimpleLogManager.cs
new file mode 100644
index 000000000..6129f38c4
--- /dev/null
+++ b/Emby.Server.Implementations/Logging/SimpleLogManager.cs
@@ -0,0 +1,301 @@
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using MediaBrowser.Model.Logging;
+
+namespace Emby.Server.Implementations.Logging
+{
+ public class SimpleLogManager : ILogManager, IDisposable
+ {
+ public LogSeverity LogSeverity { get; set; }
+ public string ExceptionMessagePrefix { get; set; }
+ private FileLogger _fileLogger;
+
+ private readonly string LogDirectory;
+ private readonly string LogFilePrefix;
+ public string DateTimeFormat = "yyyy-MM-dd HH:mm:ss.fff";
+
+ public SimpleLogManager(string logDirectory, string logFileNamePrefix)
+ {
+ LogDirectory = logDirectory;
+ LogFilePrefix = logFileNamePrefix;
+ }
+
+ public ILogger GetLogger(string name)
+ {
+ return new NamedLogger(name, this);
+ }
+
+ public void ReloadLogger(LogSeverity severity)
+ {
+ LogSeverity = severity;
+
+ var logger = _fileLogger;
+ if (logger != null)
+ {
+ logger.Dispose();
+ }
+
+ var path = Path.Combine(LogDirectory, LogFilePrefix + "-" + decimal.Floor(DateTime.Now.Ticks / 10000000) + ".txt");
+
+ _fileLogger = new FileLogger(path);
+
+ if (LoggerLoaded != null)
+ {
+ try
+ {
+
+ LoggerLoaded(this, EventArgs.Empty);
+
+ }
+ catch (Exception ex)
+ {
+ GetLogger("Logger").ErrorException("Error in LoggerLoaded event", ex);
+ }
+ }
+ }
+
+ public event EventHandler LoggerLoaded;
+
+ public void Flush()
+ {
+ var logger = _fileLogger;
+ if (logger != null)
+ {
+ logger.Flush();
+ }
+ }
+
+ private bool _console = true;
+ public void AddConsoleOutput()
+ {
+ _console = true;
+ }
+
+ public void RemoveConsoleOutput()
+ {
+ _console = false;
+ }
+
+ public void Log(string message)
+ {
+ if (_console)
+ {
+ Console.WriteLine(message);
+ }
+
+ var logger = _fileLogger;
+ if (logger != null)
+ {
+ message = DateTime.Now.ToString(DateTimeFormat) + " " + message;
+
+ logger.Log(message);
+ }
+ }
+
+ public void Dispose()
+ {
+ var logger = _fileLogger;
+ if (logger != null)
+ {
+ logger.Dispose();
+ }
+
+ _fileLogger = null;
+ GC.SuppressFinalize(this);
+ }
+ }
+
+ public class FileLogger : IDisposable
+ {
+ private readonly FileStream _fileStream;
+
+ private bool _disposed;
+ private readonly CancellationTokenSource _cancellationTokenSource;
+ private readonly BlockingCollection<string> _queue = new BlockingCollection<string>();
+
+ public FileLogger(string path)
+ {
+ Directory.CreateDirectory(Path.GetDirectoryName(path));
+
+ _fileStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read, 32768);
+ _cancellationTokenSource = new CancellationTokenSource();
+
+ Task.Factory.StartNew(LogInternal, _cancellationTokenSource.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default);
+ }
+
+ private void LogInternal()
+ {
+ while (!_cancellationTokenSource.IsCancellationRequested && !_disposed)
+ {
+ try
+ {
+ foreach (var message in _queue.GetConsumingEnumerable())
+ {
+ var bytes = Encoding.UTF8.GetBytes(message + Environment.NewLine);
+ if (_disposed)
+ {
+ return;
+ }
+
+ _fileStream.Write(bytes, 0, bytes.Length);
+
+ _fileStream.Flush(true);
+ }
+ }
+ catch
+ {
+
+ }
+ }
+ }
+
+ public void Log(string message)
+ {
+ if (_disposed)
+ {
+ return;
+ }
+
+ _queue.Add(message);
+ }
+
+ public void Flush()
+ {
+ if (_disposed)
+ {
+ return;
+ }
+
+ _fileStream.Flush(true);
+ }
+
+ public void Dispose()
+ {
+ _cancellationTokenSource.Cancel();
+
+ Flush();
+
+ _disposed = true;
+ _fileStream.Dispose();
+ GC.SuppressFinalize(this);
+ }
+ }
+
+ public class NamedLogger : ILogger
+ {
+ public string Name { get; private set; }
+ private readonly SimpleLogManager _logManager;
+
+ public NamedLogger(string name, SimpleLogManager logManager)
+ {
+ Name = name;
+ _logManager = logManager;
+ }
+
+ public void Info(string message, params object[] paramList)
+ {
+ Log(LogSeverity.Info, message, paramList);
+ }
+
+ public void Error(string message, params object[] paramList)
+ {
+ Log(LogSeverity.Error, message, paramList);
+ }
+
+ public void Warn(string message, params object[] paramList)
+ {
+ Log(LogSeverity.Warn, message, paramList);
+ }
+
+ public void Debug(string message, params object[] paramList)
+ {
+ if (_logManager.LogSeverity == LogSeverity.Info)
+ {
+ return;
+ }
+ Log(LogSeverity.Debug, message, paramList);
+ }
+
+ public void Fatal(string message, params object[] paramList)
+ {
+ Log(LogSeverity.Fatal, message, paramList);
+ }
+
+ public void FatalException(string message, Exception exception, params object[] paramList)
+ {
+ ErrorException(message, exception, paramList);
+ }
+
+ public void ErrorException(string message, Exception exception, params object[] paramList)
+ {
+ LogException(LogSeverity.Error, message, exception, paramList);
+ }
+
+ private void LogException(LogSeverity level, string message, Exception exception, params object[] paramList)
+ {
+ message = FormatMessage(message, paramList).Replace(Environment.NewLine, ". ");
+
+ var messageText = LogHelper.GetLogMessage(exception);
+
+ var prefix = _logManager.ExceptionMessagePrefix;
+
+ if (!string.IsNullOrWhiteSpace(prefix))
+ {
+ messageText.Insert(0, prefix);
+ }
+
+ LogMultiline(message, level, messageText);
+ }
+
+ private static string FormatMessage(string message, params object[] paramList)
+ {
+ if (paramList != null)
+ {
+ for (var i = 0; i < paramList.Length; i++)
+ {
+ var obj = paramList[i];
+
+ message = message.Replace("{" + i + "}", (obj == null ? "null" : obj.ToString()));
+ }
+ }
+
+ return message;
+ }
+
+ public void LogMultiline(string message, LogSeverity severity, StringBuilder additionalContent)
+ {
+ if (severity == LogSeverity.Debug && _logManager.LogSeverity == LogSeverity.Info)
+ {
+ return;
+ }
+
+ additionalContent.Insert(0, message + Environment.NewLine);
+
+ const char tabChar = '\t';
+
+ var text = additionalContent.ToString()
+ .Replace(Environment.NewLine, Environment.NewLine + tabChar)
+ .TrimEnd(tabChar);
+
+ if (text.EndsWith(Environment.NewLine))
+ {
+ text = text.Substring(0, text.LastIndexOf(Environment.NewLine, StringComparison.OrdinalIgnoreCase));
+ }
+
+ Log(severity, text);
+ }
+
+ public void Log(LogSeverity severity, string message, params object[] paramList)
+ {
+ message = severity + " " + Name + ": " + FormatMessage(message, paramList);
+
+ _logManager.Log(message);
+ }
+ }
+}
diff --git a/Emby.Server.Implementations/MediaEncoder/EncodingManager.cs b/Emby.Server.Implementations/MediaEncoder/EncodingManager.cs
index 1d74e8788..9a9e619a6 100644
--- a/Emby.Server.Implementations/MediaEncoder/EncodingManager.cs
+++ b/Emby.Server.Implementations/MediaEncoder/EncodingManager.cs
@@ -29,9 +29,9 @@ namespace Emby.Server.Implementations.MediaEncoder
private readonly IChapterManager _chapterManager;
private readonly ILibraryManager _libraryManager;
- public EncodingManager(IFileSystem fileSystem,
- ILogger logger,
- IMediaEncoder encoder,
+ public EncodingManager(IFileSystem fileSystem,
+ ILogger logger,
+ IMediaEncoder encoder,
IChapterManager chapterManager, ILibraryManager libraryManager)
{
_fileSystem = fileSystem;
@@ -45,7 +45,7 @@ namespace Emby.Server.Implementations.MediaEncoder
/// Gets the chapter images data path.
/// </summary>
/// <value>The chapter images data path.</value>
- private string GetChapterImagesPath(IHasImages item)
+ private string GetChapterImagesPath(IHasMetadata item)
{
return Path.Combine(item.GetInternalMetadataPath(), "chapters");
}
@@ -75,6 +75,11 @@ namespace Emby.Server.Implementations.MediaEncoder
return false;
}
+ if (!video.IsCompleteMedia)
+ {
+ return false;
+ }
+
// Can't extract images if there are no video streams
return video.DefaultVideoStreamIndex.HasValue;
}
@@ -84,13 +89,8 @@ namespace Emby.Server.Implementations.MediaEncoder
/// </summary>
private static readonly long FirstChapterTicks = TimeSpan.FromSeconds(15).Ticks;
- public async Task<bool> RefreshChapterImages(ChapterImageRefreshOptions options, CancellationToken cancellationToken)
+ public async Task<bool> RefreshChapterImages(Video video, List<ChapterInfo> chapters, bool extractImages, bool saveChapters, CancellationToken cancellationToken)
{
- var extractImages = options.ExtractImages;
- var video = options.Video;
- var chapters = options.Chapters;
- var saveChapters = options.SaveChapters;
-
if (!IsEligibleForChapterImageExtraction(video))
{
extractImages = false;
@@ -117,16 +117,14 @@ namespace Emby.Server.Implementations.MediaEncoder
{
if (extractImages)
{
- if (video.VideoType == VideoType.HdDvd || video.VideoType == VideoType.Iso)
+ if (video.VideoType == VideoType.Iso)
{
continue;
}
+
if (video.VideoType == VideoType.BluRay || video.VideoType == VideoType.Dvd)
{
- if (video.PlayableStreamFileNames.Count != 1)
- {
- continue;
- }
+ continue;
}
try
@@ -136,13 +134,13 @@ namespace Emby.Server.Implementations.MediaEncoder
var protocol = MediaProtocol.File;
- var inputPath = MediaEncoderHelpers.GetInputArgument(_fileSystem, video.Path, protocol, null, video.PlayableStreamFileNames);
+ var inputPath = MediaEncoderHelpers.GetInputArgument(_fileSystem, video.Path, protocol, null, new string[] { });
_fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(path));
var container = video.Container;
- var tempFile = await _encoder.ExtractVideoImage(inputPath, container, protocol, video.Video3DFormat, time, cancellationToken).ConfigureAwait(false);
+ var tempFile = await _encoder.ExtractVideoImage(inputPath, container, protocol, video.GetDefaultVideoStream(), video.Video3DFormat, time, cancellationToken).ConfigureAwait(false);
_fileSystem.CopyFile(tempFile, path, true);
try
@@ -151,7 +149,7 @@ namespace Emby.Server.Implementations.MediaEncoder
}
catch
{
-
+
}
chapter.ImagePath = path;
@@ -181,7 +179,7 @@ namespace Emby.Server.Implementations.MediaEncoder
if (saveChapters && changesMade)
{
- await _chapterManager.SaveChapters(video.Id.ToString(), chapters, cancellationToken).ConfigureAwait(false);
+ _chapterManager.SaveChapters(video.Id.ToString(), chapters);
}
DeleteDeadImages(currentImages, chapters);
diff --git a/Emby.Common.Implementations/Net/DisposableManagedObjectBase.cs b/Emby.Server.Implementations/Net/DisposableManagedObjectBase.cs
index 8476cea32..b18335da7 100644
--- a/Emby.Common.Implementations/Net/DisposableManagedObjectBase.cs
+++ b/Emby.Server.Implementations/Net/DisposableManagedObjectBase.cs
@@ -1,9 +1,6 @@
using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading.Tasks;
-namespace Emby.Common.Implementations.Net
+namespace Emby.Server.Implementations.Net
{
/// <summary>
/// Correclty implements the <see cref="IDisposable"/> interface and pattern for an object containing only managed resources, and adds a few common niceities not on the interface such as an <see cref="IsDisposed"/> property.
diff --git a/Emby.Server.Implementations/Net/NetAcceptSocket.cs b/Emby.Server.Implementations/Net/NetAcceptSocket.cs
new file mode 100644
index 000000000..d80341a07
--- /dev/null
+++ b/Emby.Server.Implementations/Net/NetAcceptSocket.cs
@@ -0,0 +1,98 @@
+using System;
+using System.Net;
+using System.Net.Sockets;
+using System.Threading;
+using System.Threading.Tasks;
+using Emby.Server.Implementations.Networking;
+using MediaBrowser.Model.Logging;
+using MediaBrowser.Model.Net;
+
+namespace Emby.Server.Implementations.Net
+{
+ public class NetAcceptSocket : IAcceptSocket
+ {
+ public Socket Socket { get; private set; }
+ private readonly ILogger _logger;
+
+ public bool DualMode { get; private set; }
+
+ public NetAcceptSocket(Socket socket, ILogger logger, bool isDualMode)
+ {
+ if (socket == null)
+ {
+ throw new ArgumentNullException("socket");
+ }
+ if (logger == null)
+ {
+ throw new ArgumentNullException("logger");
+ }
+
+ Socket = socket;
+ _logger = logger;
+ DualMode = isDualMode;
+ }
+
+ public IpEndPointInfo LocalEndPoint
+ {
+ get
+ {
+ return NetworkManager.ToIpEndPointInfo((IPEndPoint)Socket.LocalEndPoint);
+ }
+ }
+
+ public IpEndPointInfo RemoteEndPoint
+ {
+ get
+ {
+ return NetworkManager.ToIpEndPointInfo((IPEndPoint)Socket.RemoteEndPoint);
+ }
+ }
+
+ public void Connect(IpEndPointInfo endPoint)
+ {
+ var nativeEndpoint = NetworkManager.ToIPEndPoint(endPoint);
+
+ Socket.Connect(nativeEndpoint);
+ }
+
+ public void Close()
+ {
+#if NET46
+ Socket.Close();
+#else
+ Socket.Dispose();
+#endif
+ }
+
+ public void Shutdown(bool both)
+ {
+ if (both)
+ {
+ Socket.Shutdown(SocketShutdown.Both);
+ }
+ else
+ {
+ // Change interface if ever needed
+ throw new NotImplementedException();
+ }
+ }
+
+ public void Listen(int backlog)
+ {
+ Socket.Listen(backlog);
+ }
+
+ public void Bind(IpEndPointInfo endpoint)
+ {
+ var nativeEndpoint = NetworkManager.ToIPEndPoint(endpoint);
+
+ Socket.Bind(nativeEndpoint);
+ }
+
+ public void Dispose()
+ {
+ Socket.Dispose();
+ GC.SuppressFinalize(this);
+ }
+ }
+}
diff --git a/Emby.Common.Implementations/Net/SocketFactory.cs b/Emby.Server.Implementations/Net/SocketFactory.cs
index 0a1232a40..f78fbdfd7 100644
--- a/Emby.Common.Implementations/Net/SocketFactory.cs
+++ b/Emby.Server.Implementations/Net/SocketFactory.cs
@@ -1,15 +1,12 @@
using System;
-using System.Collections.Generic;
using System.IO;
-using System.Linq;
using System.Net;
using System.Net.Sockets;
-using System.Threading.Tasks;
-using Emby.Common.Implementations.Networking;
+using Emby.Server.Implementations.Networking;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Net;
-namespace Emby.Common.Implementations.Net
+namespace Emby.Server.Implementations.Net
{
public class SocketFactory : ISocketFactory
{
@@ -72,8 +69,8 @@ namespace Emby.Common.Implementations.Net
if (remotePort < 0) throw new ArgumentException("remotePort cannot be less than zero.", "remotePort");
var addressFamily = remoteAddress.AddressFamily == IpAddressFamily.InterNetwork
- ? AddressFamily.InterNetwork
- : AddressFamily.InterNetworkV6;
+ ? AddressFamily.InterNetwork
+ : AddressFamily.InterNetworkV6;
var retVal = new Socket(addressFamily, System.Net.Sockets.SocketType.Stream, System.Net.Sockets.ProtocolType.Tcp);
@@ -85,7 +82,7 @@ namespace Emby.Common.Implementations.Net
{
// This is not supported on all operating systems (qnap)
}
-
+
try
{
return new UdpSocket(retVal, new IpEndPointInfo(remoteAddress, remotePort));
@@ -142,11 +139,11 @@ namespace Emby.Common.Implementations.Net
throw;
}
}
-
+
/// <summary>
- /// Creates a new UDP acceptSocket that is a member of the SSDP multicast local admin group and binds it to the specified local port.
- /// </summary>
- /// <returns>An implementation of the <see cref="ISocket"/> interface used by RSSDP components to perform acceptSocket operations.</returns>
+ /// Creates a new UDP acceptSocket that is a member of the SSDP multicast local admin group and binds it to the specified local port.
+ /// </summary>
+ /// <returns>An implementation of the <see cref="ISocket"/> interface used by RSSDP components to perform acceptSocket operations.</returns>
public ISocket CreateSsdpUdpSocket(IpAddressInfo localIpAddress, int localPort)
{
if (localPort < 0) throw new ArgumentException("localPort cannot be less than zero.", "localPort");
@@ -189,7 +186,16 @@ namespace Emby.Common.Implementations.Net
try
{
+ // not supported on all platforms. throws on ubuntu with .net core 2.0
retVal.ExclusiveAddressUse = false;
+ }
+ catch (SocketException)
+ {
+
+ }
+
+ try
+ {
//retVal.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, true);
retVal.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
retVal.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive, multicastTimeToLive);
diff --git a/Emby.Common.Implementations/Net/UdpSocket.cs b/Emby.Server.Implementations/Net/UdpSocket.cs
index 542d16d24..58e4d6f89 100644
--- a/Emby.Common.Implementations/Net/UdpSocket.cs
+++ b/Emby.Server.Implementations/Net/UdpSocket.cs
@@ -1,15 +1,12 @@
using System;
-using System.Collections.Generic;
-using System.Linq;
using System.Net;
using System.Net.Sockets;
-using System.Security;
using System.Threading;
using System.Threading.Tasks;
-using Emby.Common.Implementations.Networking;
+using Emby.Server.Implementations.Networking;
using MediaBrowser.Model.Net;
-namespace Emby.Common.Implementations.Net
+namespace Emby.Server.Implementations.Net
{
// THIS IS A LINKED FILE - SHARED AMONGST MULTIPLE PLATFORMS
// Be careful to check any changes compile and work for all platform projects it is shared in.
diff --git a/Emby.Common.Implementations/Networking/NetworkManager.cs b/Emby.Server.Implementations/Networking/NetworkManager.cs
index 2f218656c..b47c058df 100644
--- a/Emby.Common.Implementations/Networking/NetworkManager.cs
+++ b/Emby.Server.Implementations/Networking/NetworkManager.cs
@@ -1,5 +1,4 @@
-using MediaBrowser.Model.Logging;
-using System;
+using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
@@ -7,12 +6,13 @@ using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Threading.Tasks;
+using MediaBrowser.Common.Net;
using MediaBrowser.Model.Extensions;
-using MediaBrowser.Model.Net;
using MediaBrowser.Model.IO;
-using MediaBrowser.Common.Net;
+using MediaBrowser.Model.Logging;
+using MediaBrowser.Model.Net;
-namespace Emby.Common.Implementations.Networking
+namespace Emby.Server.Implementations.Networking
{
public class NetworkManager : INetworkManager
{
@@ -506,7 +506,7 @@ namespace Emby.Common.Implementations.Networking
public async Task<IpAddressInfo[]> GetHostAddressesAsync(string host)
{
var addresses = await Dns.GetHostAddressesAsync(host).ConfigureAwait(false);
- return addresses.Select(ToIpAddressInfo).ToArray();
+ return addresses.Select(ToIpAddressInfo).ToArray(addresses.Length);
}
/// <summary>
diff --git a/Emby.Server.Implementations/News/NewsEntryPoint.cs b/Emby.Server.Implementations/News/NewsEntryPoint.cs
index 3c9a3bbf1..03c79c2c1 100644
--- a/Emby.Server.Implementations/News/NewsEntryPoint.cs
+++ b/Emby.Server.Implementations/News/NewsEntryPoint.cs
@@ -271,6 +271,7 @@ namespace Emby.Server.Implementations.News
_timer.Dispose();
_timer = null;
}
+ GC.SuppressFinalize(this);
}
}
}
diff --git a/Emby.Server.Implementations/Notifications/CoreNotificationTypes.cs b/Emby.Server.Implementations/Notifications/CoreNotificationTypes.cs
index f9fb98f85..849e02d81 100644
--- a/Emby.Server.Implementations/Notifications/CoreNotificationTypes.cs
+++ b/Emby.Server.Implementations/Notifications/CoreNotificationTypes.cs
@@ -28,21 +28,21 @@ namespace Emby.Server.Implementations.Notifications
Type = NotificationType.ApplicationUpdateInstalled.ToString(),
DefaultDescription = "{ReleaseNotes}",
DefaultTitle = "A new version of Emby Server has been installed.",
- Variables = new List<string>{"Version"}
+ Variables = new string[]{"Version"}
},
new NotificationTypeInfo
{
Type = NotificationType.InstallationFailed.ToString(),
DefaultTitle = "{Name} installation failed.",
- Variables = new List<string>{"Name", "Version"}
+ Variables = new string[]{"Name", "Version"}
},
new NotificationTypeInfo
{
Type = NotificationType.PluginInstalled.ToString(),
DefaultTitle = "{Name} was installed.",
- Variables = new List<string>{"Name", "Version"}
+ Variables = new string[]{"Name", "Version"}
},
new NotificationTypeInfo
@@ -50,14 +50,14 @@ namespace Emby.Server.Implementations.Notifications
Type = NotificationType.PluginError.ToString(),
DefaultTitle = "{Name} has encountered an error.",
DefaultDescription = "{ErrorMessage}",
- Variables = new List<string>{"Name", "ErrorMessage"}
+ Variables = new string[]{"Name", "ErrorMessage"}
},
new NotificationTypeInfo
{
Type = NotificationType.PluginUninstalled.ToString(),
DefaultTitle = "{Name} was uninstalled.",
- Variables = new List<string>{"Name", "Version"}
+ Variables = new string[]{"Name", "Version"}
},
new NotificationTypeInfo
@@ -65,7 +65,7 @@ namespace Emby.Server.Implementations.Notifications
Type = NotificationType.PluginUpdateInstalled.ToString(),
DefaultTitle = "{Name} was updated.",
DefaultDescription = "{ReleaseNotes}",
- Variables = new List<string>{"Name", "ReleaseNotes", "Version"}
+ Variables = new string[]{"Name", "ReleaseNotes", "Version"}
},
new NotificationTypeInfo
@@ -79,70 +79,70 @@ namespace Emby.Server.Implementations.Notifications
Type = NotificationType.TaskFailed.ToString(),
DefaultTitle = "{Name} failed.",
DefaultDescription = "{ErrorMessage}",
- Variables = new List<string>{"Name", "ErrorMessage"}
+ Variables = new string[]{"Name", "ErrorMessage"}
},
new NotificationTypeInfo
{
Type = NotificationType.NewLibraryContent.ToString(),
DefaultTitle = "{Name} has been added to your media library.",
- Variables = new List<string>{"Name"}
+ Variables = new string[]{"Name"}
},
new NotificationTypeInfo
{
Type = NotificationType.AudioPlayback.ToString(),
DefaultTitle = "{UserName} is playing {ItemName} on {DeviceName}.",
- Variables = new List<string>{"UserName", "ItemName", "DeviceName", "AppName"}
+ Variables = new string[]{"UserName", "ItemName", "DeviceName", "AppName"}
},
new NotificationTypeInfo
{
Type = NotificationType.GamePlayback.ToString(),
DefaultTitle = "{UserName} is playing {ItemName} on {DeviceName}.",
- Variables = new List<string>{"UserName", "ItemName", "DeviceName", "AppName"}
+ Variables = new string[]{"UserName", "ItemName", "DeviceName", "AppName"}
},
new NotificationTypeInfo
{
Type = NotificationType.VideoPlayback.ToString(),
DefaultTitle = "{UserName} is playing {ItemName} on {DeviceName}.",
- Variables = new List<string>{"UserName", "ItemName", "DeviceName", "AppName"}
+ Variables = new string[]{"UserName", "ItemName", "DeviceName", "AppName"}
},
new NotificationTypeInfo
{
Type = NotificationType.AudioPlaybackStopped.ToString(),
DefaultTitle = "{UserName} has finished playing {ItemName} on {DeviceName}.",
- Variables = new List<string>{"UserName", "ItemName", "DeviceName", "AppName"}
+ Variables = new string[]{"UserName", "ItemName", "DeviceName", "AppName"}
},
new NotificationTypeInfo
{
Type = NotificationType.GamePlaybackStopped.ToString(),
DefaultTitle = "{UserName} has finished playing {ItemName} on {DeviceName}.",
- Variables = new List<string>{"UserName", "ItemName", "DeviceName", "AppName"}
+ Variables = new string[]{"UserName", "ItemName", "DeviceName", "AppName"}
},
new NotificationTypeInfo
{
Type = NotificationType.VideoPlaybackStopped.ToString(),
DefaultTitle = "{UserName} has finished playing {ItemName} on {DeviceName}.",
- Variables = new List<string>{"UserName", "ItemName", "DeviceName", "AppName"}
+ Variables = new string[]{"UserName", "ItemName", "DeviceName", "AppName"}
},
new NotificationTypeInfo
{
Type = NotificationType.CameraImageUploaded.ToString(),
DefaultTitle = "A new camera image has been uploaded from {DeviceName}.",
- Variables = new List<string>{"DeviceName"}
+ Variables = new string[]{"DeviceName"}
},
new NotificationTypeInfo
{
Type = NotificationType.UserLockedOut.ToString(),
DefaultTitle = "{UserName} has been locked out.",
- Variables = new List<string>{"UserName"}
+ Variables = new string[]{"UserName"}
}
};
diff --git a/Emby.Server.Implementations/Notifications/NotificationManager.cs b/Emby.Server.Implementations/Notifications/NotificationManager.cs
index db7980497..f49d5a1d1 100644
--- a/Emby.Server.Implementations/Notifications/NotificationManager.cs
+++ b/Emby.Server.Implementations/Notifications/NotificationManager.cs
@@ -251,7 +251,7 @@ namespace Emby.Server.Implementations.Notifications
_typeFactories = notificationTypeFactories.ToArray();
}
- public IEnumerable<NotificationTypeInfo> GetNotificationTypes()
+ public List<NotificationTypeInfo> GetNotificationTypes()
{
var list = _typeFactories.Select(i =>
{
diff --git a/Emby.Server.Implementations/Notifications/Notifications.cs b/Emby.Server.Implementations/Notifications/Notifications.cs
index f95b3f701..09c1f07e0 100644
--- a/Emby.Server.Implementations/Notifications/Notifications.cs
+++ b/Emby.Server.Implementations/Notifications/Notifications.cs
@@ -422,7 +422,7 @@ namespace Emby.Server.Implementations.Notifications
{
var artists = hasArtist.AllArtists;
- if (artists.Count > 0)
+ if (artists.Length > 0)
{
name = hasArtist.AllArtists[0] + " - " + name;
}
@@ -440,7 +440,7 @@ namespace Emby.Server.Implementations.Notifications
name = item.SeriesName + " - " + name;
}
- if (item.Artists != null && item.Artists.Count > 0)
+ if (item.Artists != null && item.Artists.Length > 0)
{
name = item.Artists[0] + " - " + name;
}
@@ -551,6 +551,7 @@ namespace Emby.Server.Implementations.Notifications
_deviceManager.CameraImageUploaded -= _deviceManager_CameraImageUploaded;
_userManager.UserLockedOut -= _userManager_UserLockedOut;
+ GC.SuppressFinalize(this);
}
private void DisposeLibraryUpdateTimer()
diff --git a/Emby.Server.Implementations/Notifications/SqliteNotificationsRepository.cs b/Emby.Server.Implementations/Notifications/SqliteNotificationsRepository.cs
index 40752db80..ff152c9e9 100644
--- a/Emby.Server.Implementations/Notifications/SqliteNotificationsRepository.cs
+++ b/Emby.Server.Implementations/Notifications/SqliteNotificationsRepository.cs
@@ -12,6 +12,7 @@ using MediaBrowser.Model.IO;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Notifications;
using SQLitePCL.pretty;
+using MediaBrowser.Model.Extensions;
namespace Emby.Server.Implementations.Notifications
{
@@ -83,13 +84,13 @@ namespace Emby.Server.Implementations.Notifications
clauses.Add("UserId=?");
paramList.Add(query.UserId.ToGuidBlob());
- var whereClause = " where " + string.Join(" And ", clauses.ToArray());
+ var whereClause = " where " + string.Join(" And ", clauses.ToArray(clauses.Count));
using (WriteLock.Read())
{
using (var connection = CreateConnection(true))
{
- result.TotalRecordCount = connection.Query("select count(Id) from Notifications" + whereClause, paramList.ToArray()).SelectScalarInt().First();
+ result.TotalRecordCount = connection.Query("select count(Id) from Notifications" + whereClause, paramList.ToArray(paramList.Count)).SelectScalarInt().First();
var commandText = string.Format("select Id,UserId,Date,Name,Description,Url,Level,IsRead,Category,RelatedId from Notifications{0} order by IsRead asc, Date desc", whereClause);
@@ -110,12 +111,12 @@ namespace Emby.Server.Implementations.Notifications
var resultList = new List<Notification>();
- foreach (var row in connection.Query(commandText, paramList.ToArray()))
+ foreach (var row in connection.Query(commandText, paramList.ToArray(paramList.Count)))
{
resultList.Add(GetNotification(row));
}
- result.Notifications = resultList.ToArray();
+ result.Notifications = resultList.ToArray(resultList.Count);
}
}
@@ -280,7 +281,7 @@ namespace Emby.Server.Implementations.Notifications
public async Task MarkRead(IEnumerable<string> notificationIdList, string userId, bool isRead, CancellationToken cancellationToken)
{
var list = notificationIdList.ToList();
- var idArray = list.Select(i => new Guid(i)).ToArray();
+ var idArray = list.Select(i => new Guid(i)).ToArray(list.Count);
await MarkReadInternal(idArray, userId, isRead, cancellationToken).ConfigureAwait(false);
@@ -290,7 +291,7 @@ namespace Emby.Server.Implementations.Notifications
{
NotificationsMarkedRead(this, new NotificationReadEventArgs
{
- IdList = list.ToArray(),
+ IdList = list.ToArray(list.Count),
IsRead = isRead,
UserId = userId
});
diff --git a/Emby.Server.Implementations/Notifications/WebSocketNotifier.cs b/Emby.Server.Implementations/Notifications/WebSocketNotifier.cs
index 0239ee336..6e57e7f81 100644
--- a/Emby.Server.Implementations/Notifications/WebSocketNotifier.cs
+++ b/Emby.Server.Implementations/Notifications/WebSocketNotifier.cs
@@ -1,7 +1,9 @@
-using MediaBrowser.Controller.Net;
+using System;
+using MediaBrowser.Controller.Net;
using MediaBrowser.Controller.Notifications;
using MediaBrowser.Controller.Plugins;
using System.Linq;
+using MediaBrowser.Model.Extensions;
namespace Emby.Server.Implementations.Notifications
{
@@ -33,7 +35,7 @@ namespace Emby.Server.Implementations.Notifications
list.Add(e.UserId);
list.Add(e.IsRead.ToString().ToLower());
- var msg = string.Join("|", list.ToArray());
+ var msg = string.Join("|", list.ToArray(list.Count));
_serverManager.SendWebSocketMessage("NotificationsMarkedRead", msg);
}
@@ -48,6 +50,7 @@ namespace Emby.Server.Implementations.Notifications
public void Dispose()
{
_notificationsRepo.NotificationAdded -= _notificationsRepo_NotificationAdded;
+ GC.SuppressFinalize(this);
}
}
}
diff --git a/Emby.Server.Implementations/Photos/PhotoAlbumImageProvider.cs b/Emby.Server.Implementations/Photos/PhotoAlbumImageProvider.cs
index 17f9b491d..f7c65f63d 100644
--- a/Emby.Server.Implementations/Photos/PhotoAlbumImageProvider.cs
+++ b/Emby.Server.Implementations/Photos/PhotoAlbumImageProvider.cs
@@ -18,15 +18,15 @@ namespace Emby.Server.Implementations.Photos
{
}
- protected override List<BaseItem> GetItemsWithImages(IHasImages item)
+ protected override List<BaseItem> GetItemsWithImages(IHasMetadata item)
{
var photoAlbum = (PhotoAlbum)item;
- var items = GetFinalItems(photoAlbum.Children.ToList());
+ var items = GetFinalItems(photoAlbum.Children);
return items;
}
- protected override string CreateImage(IHasImages item, List<BaseItem> itemsWithImages, string outputPathWithoutExtension, ImageType imageType, int imageIndex)
+ protected override string CreateImage(IHasMetadata item, List<BaseItem> itemsWithImages, string outputPathWithoutExtension, ImageType imageType, int imageIndex)
{
return CreateSingleImage(itemsWithImages, outputPathWithoutExtension, ImageType.Primary);
}
diff --git a/MediaBrowser.Server.Implementations/Playlists/ManualPlaylistsFolder.cs b/Emby.Server.Implementations/Playlists/ManualPlaylistsFolder.cs
index 236dbde9c..2a178895c 100644
--- a/MediaBrowser.Server.Implementations/Playlists/ManualPlaylistsFolder.cs
+++ b/Emby.Server.Implementations/Playlists/ManualPlaylistsFolder.cs
@@ -1,15 +1,11 @@
using System.Collections.Generic;
-using System.IO;
using System.Linq;
-using System.Threading.Tasks;
-using MediaBrowser.Common.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Playlists;
-using MediaBrowser.Model.IO;
using MediaBrowser.Model.Querying;
using MediaBrowser.Model.Serialization;
-namespace MediaBrowser.Server.Implementations.Playlists
+namespace Emby.Server.Implementations.Playlists
{
public class PlaylistsFolder : BasePluginFolder
{
diff --git a/Emby.Server.Implementations/Playlists/PlaylistImageProvider.cs b/Emby.Server.Implementations/Playlists/PlaylistImageProvider.cs
index 127ce24ae..525df0350 100644
--- a/Emby.Server.Implementations/Playlists/PlaylistImageProvider.cs
+++ b/Emby.Server.Implementations/Playlists/PlaylistImageProvider.cs
@@ -1,4 +1,5 @@
-using MediaBrowser.Common.Configuration;
+using System;
+using MediaBrowser.Common.Configuration;
using MediaBrowser.Controller.Drawing;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
@@ -27,7 +28,7 @@ namespace Emby.Server.Implementations.Playlists
{
}
- protected override List<BaseItem> GetItemsWithImages(IHasImages item)
+ protected override List<BaseItem> GetItemsWithImages(IHasMetadata item)
{
var playlist = (Playlist)item;
@@ -65,8 +66,7 @@ namespace Emby.Server.Implementations.Playlists
return null;
})
.Where(i => i != null)
- .DistinctBy(i => i.Id)
- .ToList();
+ .DistinctBy(i => i.Id);
return GetFinalItems(items);
}
@@ -81,24 +81,24 @@ namespace Emby.Server.Implementations.Playlists
_libraryManager = libraryManager;
}
- protected override List<BaseItem> GetItemsWithImages(IHasImages item)
+ protected override List<BaseItem> GetItemsWithImages(IHasMetadata item)
{
var items = _libraryManager.GetItemList(new InternalItemsQuery
{
Genres = new[] { item.Name },
IncludeItemTypes = new[] { typeof(MusicAlbum).Name, typeof(MusicVideo).Name, typeof(Audio).Name },
- SortBy = new[] { ItemSortBy.Random },
+ OrderBy = new[] { new Tuple<string, SortOrder>(ItemSortBy.Random, SortOrder.Ascending) },
Limit = 4,
Recursive = true,
ImageTypes = new[] { ImageType.Primary },
DtoOptions = new DtoOptions(false)
- }).ToList();
+ });
return GetFinalItems(items);
}
- //protected override Task<string> CreateImage(IHasImages item, List<BaseItem> itemsWithImages, string outputPathWithoutExtension, ImageType imageType, int imageIndex)
+ //protected override Task<string> CreateImage(IHasMetadata item, List<BaseItem> itemsWithImages, string outputPathWithoutExtension, ImageType imageType, int imageIndex)
//{
// return CreateSingleImage(itemsWithImages, outputPathWithoutExtension, ImageType.Primary);
//}
@@ -113,24 +113,24 @@ namespace Emby.Server.Implementations.Playlists
_libraryManager = libraryManager;
}
- protected override List<BaseItem> GetItemsWithImages(IHasImages item)
+ protected override List<BaseItem> GetItemsWithImages(IHasMetadata item)
{
var items = _libraryManager.GetItemList(new InternalItemsQuery
{
Genres = new[] { item.Name },
IncludeItemTypes = new[] { typeof(Series).Name, typeof(Movie).Name },
- SortBy = new[] { ItemSortBy.Random },
+ OrderBy = new[] { new Tuple<string, SortOrder>(ItemSortBy.Random, SortOrder.Ascending) },
Limit = 4,
Recursive = true,
ImageTypes = new[] { ImageType.Primary },
DtoOptions = new DtoOptions(false)
- }).ToList();
+ });
return GetFinalItems(items);
}
- //protected override Task<string> CreateImage(IHasImages item, List<BaseItem> itemsWithImages, string outputPathWithoutExtension, ImageType imageType, int imageIndex)
+ //protected override Task<string> CreateImage(IHasMetadata item, List<BaseItem> itemsWithImages, string outputPathWithoutExtension, ImageType imageType, int imageIndex)
//{
// return CreateSingleImage(itemsWithImages, outputPathWithoutExtension, ImageType.Primary);
//}
diff --git a/Emby.Server.Implementations/Playlists/PlaylistManager.cs b/Emby.Server.Implementations/Playlists/PlaylistManager.cs
index e0e133e38..87832e7dd 100644
--- a/Emby.Server.Implementations/Playlists/PlaylistManager.cs
+++ b/Emby.Server.Implementations/Playlists/PlaylistManager.cs
@@ -12,10 +12,9 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
-
using MediaBrowser.Controller.Dto;
-using MediaBrowser.Controller.IO;
using MediaBrowser.Model.IO;
+using MediaBrowser.Model.Extensions;
namespace Emby.Server.Implementations.Playlists
{
@@ -129,12 +128,12 @@ namespace Emby.Server.Implementations.Playlists
playlist.SetMediaType(options.MediaType);
- await parentFolder.AddChild(playlist, CancellationToken.None).ConfigureAwait(false);
+ parentFolder.AddChild(playlist, CancellationToken.None);
await playlist.RefreshMetadata(new MetadataRefreshOptions(_fileSystem) { ForceSave = true }, CancellationToken.None)
.ConfigureAwait(false);
- if (options.ItemIdList.Count > 0)
+ if (options.ItemIdList.Length > 0)
{
await AddToPlaylistInternal(playlist.Id.ToString("N"), options.ItemIdList, user, new DtoOptions(false)
{
@@ -164,7 +163,7 @@ namespace Emby.Server.Implementations.Playlists
return path;
}
- private IEnumerable<BaseItem> GetPlaylistItems(IEnumerable<string> itemIds, string playlistMediaType, User user, DtoOptions options)
+ private List<BaseItem> GetPlaylistItems(IEnumerable<string> itemIds, string playlistMediaType, User user, DtoOptions options)
{
var items = itemIds.Select(i => _libraryManager.GetItemById(i)).Where(i => i != null);
@@ -206,7 +205,9 @@ namespace Emby.Server.Implementations.Playlists
list.Add(LinkedChild.Create(item));
}
- playlist.LinkedChildren.AddRange(list);
+ var newList = playlist.LinkedChildren.ToList();
+ newList.AddRange(list);
+ playlist.LinkedChildren = newList.ToArray(newList.Count);
await playlist.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false);
@@ -234,7 +235,7 @@ namespace Emby.Server.Implementations.Playlists
playlist.LinkedChildren = children.Except(removals)
.Select(i => i.Item1)
- .ToList();
+ .ToArray();
await playlist.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false);
@@ -265,17 +266,21 @@ namespace Emby.Server.Implementations.Playlists
var item = playlist.LinkedChildren[oldIndex];
- playlist.LinkedChildren.Remove(item);
+ var newList = playlist.LinkedChildren.ToList();
- if (newIndex >= playlist.LinkedChildren.Count)
+ newList.Remove(item);
+
+ if (newIndex >= newList.Count)
{
- playlist.LinkedChildren.Add(item);
+ newList.Add(item);
}
else
{
- playlist.LinkedChildren.Insert(newIndex, item);
+ newList.Insert(newIndex, item);
}
+ playlist.LinkedChildren = newList.ToArray(newList.Count);
+
await playlist.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false);
}
diff --git a/Emby.Server.Implementations/Playlists/PlaylistsDynamicFolder.cs b/Emby.Server.Implementations/Playlists/PlaylistsDynamicFolder.cs
index dacc937e1..2ce835576 100644
--- a/Emby.Server.Implementations/Playlists/PlaylistsDynamicFolder.cs
+++ b/Emby.Server.Implementations/Playlists/PlaylistsDynamicFolder.cs
@@ -2,7 +2,6 @@
using MediaBrowser.Common.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Model.IO;
-using MediaBrowser.Server.Implementations.Playlists;
namespace Emby.Server.Implementations.Playlists
{
diff --git a/Emby.Common.Implementations/Reflection/AssemblyInfo.cs b/Emby.Server.Implementations/Reflection/AssemblyInfo.cs
index 87821bf7a..c3ce97d40 100644
--- a/Emby.Common.Implementations/Reflection/AssemblyInfo.cs
+++ b/Emby.Server.Implementations/Reflection/AssemblyInfo.cs
@@ -1,9 +1,9 @@
using System;
using System.IO;
-using MediaBrowser.Model.Reflection;
using System.Reflection;
+using MediaBrowser.Model.Reflection;
-namespace Emby.Common.Implementations.Reflection
+namespace Emby.Server.Implementations.Reflection
{
public class AssemblyInfo : IAssemblyInfo
{
diff --git a/Emby.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs b/Emby.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs
index 967e7ddd8..ec371c741 100644
--- a/Emby.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs
+++ b/Emby.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs
@@ -15,6 +15,7 @@ using MediaBrowser.Controller.IO;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Tasks;
+using MediaBrowser.Model.Extensions;
namespace Emby.Server.Implementations.ScheduledTasks
{
@@ -123,16 +124,9 @@ namespace Emby.Server.Implementations.ScheduledTasks
try
{
- var chapters = _itemRepo.GetChapters(video.Id).ToList();
+ var chapters = _itemRepo.GetChapters(video.Id);
- var success = await _encodingManager.RefreshChapterImages(new ChapterImageRefreshOptions
- {
- SaveChapters = true,
- ExtractImages = extract,
- Video = video,
- Chapters = chapters
-
- }, CancellationToken.None);
+ var success = await _encodingManager.RefreshChapterImages(video, chapters, extract, true, CancellationToken.None);
if (!success)
{
@@ -142,7 +136,7 @@ namespace Emby.Server.Implementations.ScheduledTasks
_fileSystem.CreateDirectory(parentPath);
- _fileSystem.WriteAllText(failHistoryPath, string.Join("|", previouslyFailedImages.ToArray()));
+ _fileSystem.WriteAllText(failHistoryPath, string.Join("|", previouslyFailedImages.ToArray(previouslyFailedImages.Count)));
}
numComplete++;
diff --git a/Emby.Common.Implementations/ScheduledTasks/DailyTrigger.cs b/Emby.Server.Implementations/ScheduledTasks/DailyTrigger.cs
index 5735f8026..1ba5d4329 100644
--- a/Emby.Common.Implementations/ScheduledTasks/DailyTrigger.cs
+++ b/Emby.Server.Implementations/ScheduledTasks/DailyTrigger.cs
@@ -5,7 +5,7 @@ using MediaBrowser.Model.Events;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Tasks;
-namespace Emby.Common.Implementations.ScheduledTasks
+namespace Emby.Server.Implementations.ScheduledTasks
{
/// <summary>
/// Represents a task trigger that fires everyday
diff --git a/Emby.Common.Implementations/ScheduledTasks/IntervalTrigger.cs b/Emby.Server.Implementations/ScheduledTasks/IntervalTrigger.cs
index 4d2769d8f..d09765e34 100644
--- a/Emby.Common.Implementations/ScheduledTasks/IntervalTrigger.cs
+++ b/Emby.Server.Implementations/ScheduledTasks/IntervalTrigger.cs
@@ -5,7 +5,7 @@ using MediaBrowser.Model.Events;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Tasks;
-namespace Emby.Common.Implementations.ScheduledTasks
+namespace Emby.Server.Implementations.ScheduledTasks
{
/// <summary>
/// Represents a task trigger that runs repeatedly on an interval
diff --git a/Emby.Common.Implementations/ScheduledTasks/ScheduledTaskWorker.cs b/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs
index c373ffddb..d7d048110 100644
--- a/Emby.Common.Implementations/ScheduledTasks/ScheduledTaskWorker.cs
+++ b/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs
@@ -9,13 +9,14 @@ using MediaBrowser.Common.Events;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.Progress;
using MediaBrowser.Model.Events;
+using MediaBrowser.Model.Extensions;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Serialization;
using MediaBrowser.Model.System;
using MediaBrowser.Model.Tasks;
-namespace Emby.Common.Implementations.ScheduledTasks
+namespace Emby.Server.Implementations.ScheduledTasks
{
/// <summary>
/// Class ScheduledTaskWorker
@@ -274,7 +275,8 @@ namespace Emby.Common.Implementations.ScheduledTasks
{
get
{
- return InternalTriggers.Select(i => i.Item1).ToArray();
+ var triggers = InternalTriggers;
+ return triggers.Select(i => i.Item1).ToArray(triggers.Length);
}
set
{
@@ -288,7 +290,7 @@ namespace Emby.Common.Implementations.ScheduledTasks
SaveTriggers(triggerList);
- InternalTriggers = triggerList.Select(i => new Tuple<TaskTriggerInfo, ITaskTrigger>(i, GetTrigger(i))).ToArray();
+ InternalTriggers = triggerList.Select(i => new Tuple<TaskTriggerInfo, ITaskTrigger>(i, GetTrigger(i))).ToArray(triggerList.Length);
}
}
diff --git a/Emby.Common.Implementations/ScheduledTasks/StartupTrigger.cs b/Emby.Server.Implementations/ScheduledTasks/StartupTrigger.cs
index 8aae644bc..d708c905d 100644
--- a/Emby.Common.Implementations/ScheduledTasks/StartupTrigger.cs
+++ b/Emby.Server.Implementations/ScheduledTasks/StartupTrigger.cs
@@ -4,7 +4,7 @@ using MediaBrowser.Model.Events;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Tasks;
-namespace Emby.Common.Implementations.ScheduledTasks
+namespace Emby.Server.Implementations.ScheduledTasks
{
/// <summary>
/// Class StartupTaskTrigger
diff --git a/Emby.Common.Implementations/ScheduledTasks/SystemEventTrigger.cs b/Emby.Server.Implementations/ScheduledTasks/SystemEventTrigger.cs
index a136a975a..976754a40 100644
--- a/Emby.Common.Implementations/ScheduledTasks/SystemEventTrigger.cs
+++ b/Emby.Server.Implementations/ScheduledTasks/SystemEventTrigger.cs
@@ -5,7 +5,7 @@ using MediaBrowser.Model.Logging;
using MediaBrowser.Model.System;
using MediaBrowser.Model.Tasks;
-namespace Emby.Common.Implementations.ScheduledTasks
+namespace Emby.Server.Implementations.ScheduledTasks
{
/// <summary>
/// Class SystemEventTrigger
diff --git a/Emby.Common.Implementations/ScheduledTasks/TaskManager.cs b/Emby.Server.Implementations/ScheduledTasks/TaskManager.cs
index b0153c588..5f9bf3731 100644
--- a/Emby.Common.Implementations/ScheduledTasks/TaskManager.cs
+++ b/Emby.Server.Implementations/ScheduledTasks/TaskManager.cs
@@ -1,18 +1,18 @@
-using MediaBrowser.Common.Configuration;
-using MediaBrowser.Common.Events;
-using MediaBrowser.Model.Events;
-using MediaBrowser.Model.Logging;
-using MediaBrowser.Model.Serialization;
-using MediaBrowser.Model.Tasks;
-using System;
+using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
+using MediaBrowser.Common.Configuration;
+using MediaBrowser.Common.Events;
+using MediaBrowser.Model.Events;
using MediaBrowser.Model.IO;
+using MediaBrowser.Model.Logging;
+using MediaBrowser.Model.Serialization;
using MediaBrowser.Model.System;
+using MediaBrowser.Model.Tasks;
-namespace Emby.Common.Implementations.ScheduledTasks
+namespace Emby.Server.Implementations.ScheduledTasks
{
/// <summary>
/// Class TaskManager
diff --git a/Emby.Common.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs b/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs
index 1cad2e9b8..701358fd4 100644
--- a/Emby.Common.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs
+++ b/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs
@@ -9,7 +9,7 @@ using MediaBrowser.Model.IO;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Tasks;
-namespace Emby.Common.Implementations.ScheduledTasks.Tasks
+namespace Emby.Server.Implementations.ScheduledTasks.Tasks
{
/// <summary>
/// Deletes old cache files
diff --git a/Emby.Common.Implementations/ScheduledTasks/Tasks/DeleteLogFileTask.cs b/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteLogFileTask.cs
index 3f43fa889..f98b09659 100644
--- a/Emby.Common.Implementations/ScheduledTasks/Tasks/DeleteLogFileTask.cs
+++ b/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteLogFileTask.cs
@@ -7,7 +7,7 @@ using MediaBrowser.Common.Configuration;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Tasks;
-namespace Emby.Common.Implementations.ScheduledTasks.Tasks
+namespace Emby.Server.Implementations.ScheduledTasks.Tasks
{
/// <summary>
/// Deletes old log files
diff --git a/Emby.Common.Implementations/ScheduledTasks/Tasks/ReloadLoggerFileTask.cs b/Emby.Server.Implementations/ScheduledTasks/Tasks/ReloadLoggerFileTask.cs
index 80411de05..032fa05a0 100644
--- a/Emby.Common.Implementations/ScheduledTasks/Tasks/ReloadLoggerFileTask.cs
+++ b/Emby.Server.Implementations/ScheduledTasks/Tasks/ReloadLoggerFileTask.cs
@@ -6,7 +6,7 @@ using MediaBrowser.Common.Configuration;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Tasks;
-namespace Emby.Common.Implementations.ScheduledTasks.Tasks
+namespace Emby.Server.Implementations.ScheduledTasks.Tasks
{
/// <summary>
/// Class ReloadLoggerFileTask
diff --git a/Emby.Common.Implementations/ScheduledTasks/WeeklyTrigger.cs b/Emby.Server.Implementations/ScheduledTasks/WeeklyTrigger.cs
index 91540ba16..1a944ebf2 100644
--- a/Emby.Common.Implementations/ScheduledTasks/WeeklyTrigger.cs
+++ b/Emby.Server.Implementations/ScheduledTasks/WeeklyTrigger.cs
@@ -4,7 +4,7 @@ using MediaBrowser.Model.Events;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Tasks;
-namespace Emby.Common.Implementations.ScheduledTasks
+namespace Emby.Server.Implementations.ScheduledTasks
{
/// <summary>
/// Represents a task trigger that fires on a weekly basis
diff --git a/Emby.Server.Implementations/Security/AuthenticationRepository.cs b/Emby.Server.Implementations/Security/AuthenticationRepository.cs
index 9ec0af6bb..f5b847ccf 100644
--- a/Emby.Server.Implementations/Security/AuthenticationRepository.cs
+++ b/Emby.Server.Implementations/Security/AuthenticationRepository.cs
@@ -4,13 +4,13 @@ using System.Globalization;
using System.IO;
using System.Linq;
using System.Threading;
-using System.Threading.Tasks;
using Emby.Server.Implementations.Data;
using MediaBrowser.Controller;
using MediaBrowser.Controller.Security;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Querying;
using SQLitePCL.pretty;
+using MediaBrowser.Model.Extensions;
namespace Emby.Server.Implementations.Security
{
@@ -50,14 +50,14 @@ namespace Emby.Server.Implementations.Security
}
}
- public Task Create(AuthenticationInfo info, CancellationToken cancellationToken)
+ public void Create(AuthenticationInfo info, CancellationToken cancellationToken)
{
info.Id = Guid.NewGuid().ToString("N");
- return Update(info, cancellationToken);
+ Update(info, cancellationToken);
}
- public async Task Update(AuthenticationInfo info, CancellationToken cancellationToken)
+ public void Update(AuthenticationInfo info, CancellationToken cancellationToken)
{
if (info == null)
{
@@ -174,13 +174,13 @@ namespace Emby.Server.Implementations.Security
var whereTextWithoutPaging = whereClauses.Count == 0 ?
string.Empty :
- " where " + string.Join(" AND ", whereClauses.ToArray());
+ " where " + string.Join(" AND ", whereClauses.ToArray(whereClauses.Count));
if (startIndex > 0)
{
var pagingWhereText = whereClauses.Count == 0 ?
string.Empty :
- " where " + string.Join(" AND ", whereClauses.ToArray());
+ " where " + string.Join(" AND ", whereClauses.ToArray(whereClauses.Count));
whereClauses.Add(string.Format("Id NOT IN (SELECT Id FROM AccessTokens {0} ORDER BY DateCreated LIMIT {1})",
pagingWhereText,
@@ -189,7 +189,7 @@ namespace Emby.Server.Implementations.Security
var whereText = whereClauses.Count == 0 ?
string.Empty :
- " where " + string.Join(" AND ", whereClauses.ToArray());
+ " where " + string.Join(" AND ", whereClauses.ToArray(whereClauses.Count));
commandText += whereText;
@@ -236,7 +236,7 @@ namespace Emby.Server.Implementations.Security
}
}
- result.Items = list.ToArray();
+ result.Items = list.ToArray(list.Count);
return result;
}, ReadTransactionMode);
diff --git a/Emby.Common.Implementations/Serialization/JsonSerializer.cs b/Emby.Server.Implementations/Serialization/JsonSerializer.cs
index c9db33689..c9db33689 100644
--- a/Emby.Common.Implementations/Serialization/JsonSerializer.cs
+++ b/Emby.Server.Implementations/Serialization/JsonSerializer.cs
diff --git a/Emby.Common.Implementations/Serialization/XmlSerializer.cs b/Emby.Server.Implementations/Serialization/XmlSerializer.cs
index b5896e6b0..e0603a01f 100644
--- a/Emby.Common.Implementations/Serialization/XmlSerializer.cs
+++ b/Emby.Server.Implementations/Serialization/XmlSerializer.cs
@@ -1,14 +1,13 @@
-using MediaBrowser.Model.Serialization;
-using System;
-using System.Collections.Concurrent;
+using System;
using System.Collections.Generic;
using System.IO;
using System.Xml;
using System.Xml.Serialization;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Logging;
+using MediaBrowser.Model.Serialization;
-namespace Emby.Common.Implementations.Serialization
+namespace Emby.Server.Implementations.Serialization
{
/// <summary>
/// Provides a wrapper around third party xml serialization.
diff --git a/Emby.Server.Implementations/ServerApplicationPaths.cs b/Emby.Server.Implementations/ServerApplicationPaths.cs
index b4b2bb139..675b0d78c 100644
--- a/Emby.Server.Implementations/ServerApplicationPaths.cs
+++ b/Emby.Server.Implementations/ServerApplicationPaths.cs
@@ -13,8 +13,8 @@ namespace Emby.Server.Implementations
/// <summary>
/// Initializes a new instance of the <see cref="BaseApplicationPaths" /> class.
/// </summary>
- public ServerApplicationPaths(string programDataPath, string appFolderPath, string applicationResourcesPath, Action<string> createDirectoryFn)
- : base(programDataPath, appFolderPath, createDirectoryFn)
+ public ServerApplicationPaths(string programDataPath, string appFolderPath, string applicationResourcesPath)
+ : base(programDataPath, appFolderPath)
{
ApplicationResourcesPath = applicationResourcesPath;
}
diff --git a/Emby.Server.Implementations/ServerManager/ServerManager.cs b/Emby.Server.Implementations/ServerManager/ServerManager.cs
index 7cd94c526..b267f928b 100644
--- a/Emby.Server.Implementations/ServerManager/ServerManager.cs
+++ b/Emby.Server.Implementations/ServerManager/ServerManager.cs
@@ -112,7 +112,7 @@ namespace Emby.Server.Implementations.ServerManager
/// <summary>
/// Starts this instance.
/// </summary>
- public void Start(IEnumerable<string> urlPrefixes)
+ public void Start(string[] urlPrefixes)
{
ReloadHttpServer(urlPrefixes);
}
@@ -120,7 +120,7 @@ namespace Emby.Server.Implementations.ServerManager
/// <summary>
/// Restarts the Http Server, or starts it if not currently running
/// </summary>
- private void ReloadHttpServer(IEnumerable<string> urlPrefixes)
+ private void ReloadHttpServer(string[] urlPrefixes)
{
_logger.Info("Loading Http Server");
diff --git a/Emby.Server.Implementations/ServerManager/WebSocketConnection.cs b/Emby.Server.Implementations/ServerManager/WebSocketConnection.cs
index 4d5192fea..076f50d93 100644
--- a/Emby.Server.Implementations/ServerManager/WebSocketConnection.cs
+++ b/Emby.Server.Implementations/ServerManager/WebSocketConnection.cs
@@ -136,7 +136,7 @@ namespace Emby.Server.Implementations.ServerManager
return;
}
- var charset = _textEncoding.GetDetectedEncodingName(bytes, null, false);
+ var charset = _textEncoding.GetDetectedEncodingName(bytes, bytes.Length, null, false);
if (string.Equals(charset, "utf-8", StringComparison.OrdinalIgnoreCase))
{
diff --git a/Emby.Server.Implementations/Services/HttpResult.cs b/Emby.Server.Implementations/Services/HttpResult.cs
index dfad09f7b..91314c15a 100644
--- a/Emby.Server.Implementations/Services/HttpResult.cs
+++ b/Emby.Server.Implementations/Services/HttpResult.cs
@@ -45,10 +45,15 @@ namespace Emby.Server.Implementations.Services
var bytesResponse = this.Response as byte[];
if (bytesResponse != null)
{
+ var contentLength = bytesResponse.Length;
+
if (response != null)
- response.SetContentLength(bytesResponse.Length);
+ response.SetContentLength(contentLength);
- await responseStream.WriteAsync(bytesResponse, 0, bytesResponse.Length).ConfigureAwait(false);
+ if (contentLength > 0)
+ {
+ await responseStream.WriteAsync(bytesResponse, 0, contentLength).ConfigureAwait(false);
+ }
return;
}
diff --git a/Emby.Server.Implementations/Services/ResponseHelper.cs b/Emby.Server.Implementations/Services/ResponseHelper.cs
index 84dc343c3..22e1bc4aa 100644
--- a/Emby.Server.Implementations/Services/ResponseHelper.cs
+++ b/Emby.Server.Implementations/Services/ResponseHelper.cs
@@ -41,11 +41,11 @@ namespace Emby.Server.Implementations.Services
response.StatusCode = httpResult.Status;
response.StatusDescription = httpResult.StatusCode.ToString();
- if (string.IsNullOrEmpty(httpResult.ContentType))
- {
- httpResult.ContentType = defaultContentType;
- }
- response.ContentType = httpResult.ContentType;
+ //if (string.IsNullOrEmpty(httpResult.ContentType))
+ //{
+ // httpResult.ContentType = defaultContentType;
+ //}
+ //response.ContentType = httpResult.ContentType;
if (httpResult.Cookies != null)
{
@@ -124,7 +124,10 @@ namespace Emby.Server.Implementations.Services
response.ContentType = "application/octet-stream";
response.SetContentLength(bytes.Length);
- await response.OutputStream.WriteAsync(bytes, 0, bytes.Length, cancellationToken).ConfigureAwait(false);
+ if (bytes.Length > 0)
+ {
+ await response.OutputStream.WriteAsync(bytes, 0, bytes.Length, cancellationToken).ConfigureAwait(false);
+ }
return;
}
@@ -133,7 +136,10 @@ namespace Emby.Server.Implementations.Services
{
bytes = Encoding.UTF8.GetBytes(responseText);
response.SetContentLength(bytes.Length);
- await response.OutputStream.WriteAsync(bytes, 0, bytes.Length, cancellationToken).ConfigureAwait(false);
+ if (bytes.Length > 0)
+ {
+ await response.OutputStream.WriteAsync(bytes, 0, bytes.Length, cancellationToken).ConfigureAwait(false);
+ }
return;
}
@@ -150,8 +156,15 @@ namespace Emby.Server.Implementations.Services
serializer(result, ms);
ms.Position = 0;
- response.SetContentLength(ms.Length);
- await ms.CopyToAsync(response.OutputStream).ConfigureAwait(false);
+
+ var contentLength = ms.Length;
+
+ response.SetContentLength(contentLength);
+
+ if (contentLength > 0)
+ {
+ await ms.CopyToAsync(response.OutputStream).ConfigureAwait(false);
+ }
}
//serializer(result, outputStream);
diff --git a/Emby.Server.Implementations/Services/ServiceController.cs b/Emby.Server.Implementations/Services/ServiceController.cs
index 1c530144c..4dc14a193 100644
--- a/Emby.Server.Implementations/Services/ServiceController.cs
+++ b/Emby.Server.Implementations/Services/ServiceController.cs
@@ -15,29 +15,20 @@ namespace Emby.Server.Implementations.Services
public class ServiceController
{
public static ServiceController Instance;
- private readonly Func<IEnumerable<Type>> _resolveServicesFn;
- public ServiceController(Func<IEnumerable<Type>> resolveServicesFn)
+ public ServiceController()
{
Instance = this;
- _resolveServicesFn = resolveServicesFn;
}
- public void Init(HttpListenerHost appHost)
+ public void Init(HttpListenerHost appHost, Type[] serviceTypes)
{
- foreach (var serviceType in _resolveServicesFn())
+ foreach (var serviceType in serviceTypes)
{
RegisterService(appHost, serviceType);
}
}
- private Type[] GetGenericArguments(Type type)
- {
- return type.GetTypeInfo().IsGenericTypeDefinition
- ? type.GetTypeInfo().GenericTypeParameters
- : type.GetTypeInfo().GenericTypeArguments;
- }
-
public void RegisterService(HttpListenerHost appHost, Type serviceType)
{
var processedReqs = new HashSet<Type>();
@@ -52,36 +43,17 @@ namespace Emby.Server.Implementations.Services
ServiceExecGeneral.CreateServiceRunnersFor(requestType, actions);
- var returnMarker = GetTypeWithGenericTypeDefinitionOf(requestType, typeof(IReturn<>));
- var responseType = returnMarker != null ?
- GetGenericArguments(returnMarker)[0]
- : mi.ReturnType != typeof(object) && mi.ReturnType != typeof(void) ?
- mi.ReturnType
- : Type.GetType(requestType.FullName + "Response");
+ //var returnMarker = GetTypeWithGenericTypeDefinitionOf(requestType, typeof(IReturn<>));
+ //var responseType = returnMarker != null ?
+ // GetGenericArguments(returnMarker)[0]
+ // : mi.ReturnType != typeof(object) && mi.ReturnType != typeof(void) ?
+ // mi.ReturnType
+ // : Type.GetType(requestType.FullName + "Response");
RegisterRestPaths(appHost, requestType);
- appHost.AddServiceInfo(serviceType, requestType, responseType);
- }
- }
-
- private static Type GetTypeWithGenericTypeDefinitionOf(Type type, Type genericTypeDefinition)
- {
- foreach (var t in type.GetTypeInfo().ImplementedInterfaces)
- {
- if (t.GetTypeInfo().IsGenericType && t.GetGenericTypeDefinition() == genericTypeDefinition)
- {
- return t;
- }
- }
-
- var genericType = FirstGenericType(type);
- if (genericType != null && genericType.GetGenericTypeDefinition() == genericTypeDefinition)
- {
- return genericType;
+ appHost.AddServiceInfo(serviceType, requestType);
}
-
- return null;
}
public static Type FirstGenericType(Type type)
@@ -103,11 +75,7 @@ namespace Emby.Server.Implementations.Services
var attrs = appHost.GetRouteAttributes(requestType);
foreach (RouteAttribute attr in attrs)
{
- var restPath = new RestPath(appHost.CreateInstance, appHost.GetParseFn, requestType, attr.Path, attr.Verbs, attr.Summary, attr.Notes);
-
- if (!restPath.IsValid)
- throw new NotSupportedException(string.Format(
- "RestPath '{0}' on Type '{1}' is not Valid", attr.Path, requestType.GetMethodName()));
+ var restPath = new RestPath(appHost.CreateInstance, appHost.GetParseFn, requestType, attr.Path, attr.Verbs, attr.Summary);
RegisterRestPath(restPath);
}
@@ -120,8 +88,7 @@ namespace Emby.Server.Implementations.Services
if (!restPath.Path.StartsWith("/"))
throw new ArgumentException(string.Format("Route '{0}' on '{1}' must start with a '/'", restPath.Path, restPath.RequestType.GetMethodName()));
if (restPath.Path.IndexOfAny(InvalidRouteChars) != -1)
- throw new ArgumentException(string.Format("Route '{0}' on '{1}' contains invalid chars. " +
- "See https://github.com/ServiceStack/ServiceStack/wiki/Routing for info on valid routes.", restPath.Path, restPath.RequestType.GetMethodName()));
+ throw new ArgumentException(string.Format("Route '{0}' on '{1}' contains invalid chars. ", restPath.Path, restPath.RequestType.GetMethodName()));
List<RestPath> pathsAtFirstMatch;
if (!RestPathMap.TryGetValue(restPath.FirstMatchHashKey, out pathsAtFirstMatch))
diff --git a/Emby.Server.Implementations/Services/ServiceExec.cs b/Emby.Server.Implementations/Services/ServiceExec.cs
index e0b5e69c0..5709d3e0a 100644
--- a/Emby.Server.Implementations/Services/ServiceExec.cs
+++ b/Emby.Server.Implementations/Services/ServiceExec.cs
@@ -5,12 +5,13 @@ using System.Linq.Expressions;
using System.Reflection;
using System.Threading.Tasks;
using MediaBrowser.Model.Services;
+using MediaBrowser.Model.Extensions;
namespace Emby.Server.Implementations.Services
{
public static class ServiceExecExtensions
{
- public static HashSet<string> AllVerbs = new HashSet<string>(new[] {
+ public static string[] AllVerbs = new[] {
"OPTIONS", "GET", "HEAD", "POST", "PUT", "DELETE", "TRACE", "CONNECT", // RFC 2616
"PROPFIND", "PROPPATCH", "MKCOL", "COPY", "MOVE", "LOCK", "UNLOCK", // RFC 2518
"VERSION-CONTROL", "REPORT", "CHECKOUT", "CHECKIN", "UNCHECKOUT",
@@ -21,27 +22,43 @@ namespace Emby.Server.Implementations.Services
"SEARCH", // https://datatracker.ietf.org/doc/draft-reschke-webdav-search/
"BCOPY", "BDELETE", "BMOVE", "BPROPFIND", "BPROPPATCH", "NOTIFY",
"POLL", "SUBSCRIBE", "UNSUBSCRIBE"
- });
+ };
- public static IEnumerable<MethodInfo> GetActions(this Type serviceType)
+ public static HashSet<string> AllVerbsSet = new HashSet<string>(AllVerbs);
+
+ public static List<MethodInfo> GetActions(this Type serviceType)
{
- foreach (var mi in serviceType.GetRuntimeMethods().Where(i => i.IsPublic && !i.IsStatic))
+ var list = new List<MethodInfo>();
+
+ foreach (var mi in serviceType.GetRuntimeMethods())
{
+ if (!mi.IsPublic)
+ {
+ continue;
+ }
+
+ if (mi.IsStatic)
+ {
+ continue;
+ }
+
if (mi.GetParameters().Length != 1)
continue;
var actionName = mi.Name;
- if (!AllVerbs.Contains(actionName, StringComparer.OrdinalIgnoreCase) && !string.Equals(actionName, ServiceMethod.AnyAction, StringComparison.OrdinalIgnoreCase))
+ if (!AllVerbs.Contains(actionName, StringComparer.OrdinalIgnoreCase))
continue;
- yield return mi;
+ list.Add(mi);
}
+
+ return list;
}
}
internal static class ServiceExecGeneral
{
- public static Dictionary<string, ServiceMethod> execMap = new Dictionary<string, ServiceMethod>();
+ private static Dictionary<string, ServiceMethod> execMap = new Dictionary<string, ServiceMethod>();
public static void CreateServiceRunnersFor(Type requestType, List<ServiceMethod> actions)
{
@@ -58,8 +75,7 @@ namespace Emby.Server.Implementations.Services
var actionName = request.Verb ?? "POST";
ServiceMethod actionContext;
- if (ServiceExecGeneral.execMap.TryGetValue(ServiceMethod.Key(serviceType, actionName, requestName), out actionContext)
- || ServiceExecGeneral.execMap.TryGetValue(ServiceMethod.AnyKey(serviceType, requestName), out actionContext))
+ if (ServiceExecGeneral.execMap.TryGetValue(ServiceMethod.Key(serviceType, actionName, requestName), out actionContext))
{
if (actionContext.RequestFilters != null)
{
@@ -123,7 +139,7 @@ namespace Emby.Server.Implementations.Services
}
if (reqFilters.Count > 0)
- actionCtx.RequestFilters = reqFilters.OrderBy(i => i.Priority).ToArray();
+ actionCtx.RequestFilters = reqFilters.OrderBy(i => i.Priority).ToArray(reqFilters.Count);
actions.Add(actionCtx);
}
diff --git a/Emby.Server.Implementations/Services/ServiceHandler.cs b/Emby.Server.Implementations/Services/ServiceHandler.cs
index 526e62d39..d500595ce 100644
--- a/Emby.Server.Implementations/Services/ServiceHandler.cs
+++ b/Emby.Server.Implementations/Services/ServiceHandler.cs
@@ -162,7 +162,11 @@ namespace Emby.Server.Implementations.Services
if (RequireqRequestStream(requestType))
{
// Used by IRequiresRequestStream
- return CreateRequiresRequestStreamRequest(host, httpReq, requestType);
+ var request = ServiceHandler.CreateRequest(httpReq, restPath, GetRequestParams(httpReq), host.CreateInstance(requestType));
+
+ var rawReq = (IRequiresRequestStream)request;
+ rawReq.RequestStream = httpReq.InputStream;
+ return rawReq;
}
var requestParams = GetFlattenedRequestParams(httpReq);
@@ -176,16 +180,6 @@ namespace Emby.Server.Implementations.Services
return requiresRequestStreamTypeInfo.IsAssignableFrom(requestType.GetTypeInfo());
}
- private static IRequiresRequestStream CreateRequiresRequestStreamRequest(HttpListenerHost host, IRequest req, Type requestType)
- {
- var restPath = GetRoute(req);
- var request = ServiceHandler.CreateRequest(req, restPath, GetRequestParams(req), host.CreateInstance(requestType));
-
- var rawReq = (IRequiresRequestStream)request;
- rawReq.RequestStream = req.InputStream;
- return rawReq;
- }
-
public static object CreateRequest(HttpListenerHost host, IRequest httpReq, RestPath restPath, Dictionary<string, string> requestParams)
{
var requestDto = CreateContentTypeRequest(host, httpReq, restPath.RequestType, httpReq.ContentType);
@@ -215,35 +209,39 @@ namespace Emby.Server.Implementations.Services
if (name == null) continue; //thank you ASP.NET
var values = request.QueryString.GetValues(name);
- if (values.Length == 1)
+ if (values.Count == 1)
{
map[name] = values[0];
}
else
{
- for (var i = 0; i < values.Length; i++)
+ for (var i = 0; i < values.Count; i++)
{
map[name + (i == 0 ? "" : "#" + i)] = values[i];
}
}
}
- if ((IsMethod(request.Verb, "POST") || IsMethod(request.Verb, "PUT")) && request.FormData != null)
+ if ((IsMethod(request.Verb, "POST") || IsMethod(request.Verb, "PUT")))
{
- foreach (var name in request.FormData.Keys)
+ var formData = request.FormData;
+ if (formData != null)
{
- if (name == null) continue; //thank you ASP.NET
-
- var values = request.FormData.GetValues(name);
- if (values.Length == 1)
+ foreach (var name in formData.Keys)
{
- map[name] = values[0];
- }
- else
- {
- for (var i = 0; i < values.Length; i++)
+ if (name == null) continue; //thank you ASP.NET
+
+ var values = formData.GetValues(name);
+ if (values.Count == 1)
+ {
+ map[name] = values[0];
+ }
+ else
{
- map[name + (i == 0 ? "" : "#" + i)] = values[i];
+ for (var i = 0; i < values.Count; i++)
+ {
+ map[name + (i == 0 ? "" : "#" + i)] = values[i];
+ }
}
}
}
@@ -270,12 +268,16 @@ namespace Emby.Server.Implementations.Services
map[name] = request.QueryString[name];
}
- if ((IsMethod(request.Verb, "POST") || IsMethod(request.Verb, "PUT")) && request.FormData != null)
+ if ((IsMethod(request.Verb, "POST") || IsMethod(request.Verb, "PUT")))
{
- foreach (var name in request.FormData.Keys)
+ var formData = request.FormData;
+ if (formData != null)
{
- if (name == null) continue; //thank you ASP.NET
- map[name] = request.FormData[name];
+ foreach (var name in formData.Keys)
+ {
+ if (name == null) continue; //thank you ASP.NET
+ map[name] = formData[name];
+ }
}
}
diff --git a/Emby.Server.Implementations/Services/ServiceMethod.cs b/Emby.Server.Implementations/Services/ServiceMethod.cs
index bcbc6fb57..fa2dd43d0 100644
--- a/Emby.Server.Implementations/Services/ServiceMethod.cs
+++ b/Emby.Server.Implementations/Services/ServiceMethod.cs
@@ -4,8 +4,6 @@ namespace Emby.Server.Implementations.Services
{
public class ServiceMethod
{
- public const string AnyAction = "ANY";
-
public string Id { get; set; }
public ActionInvokerFn ServiceAction { get; set; }
@@ -15,10 +13,5 @@ namespace Emby.Server.Implementations.Services
{
return serviceType.FullName + " " + method.ToUpper() + " " + requestDtoName;
}
-
- public static string AnyKey(Type serviceType, string requestDtoName)
- {
- return Key(serviceType, AnyAction, requestDtoName);
- }
}
} \ No newline at end of file
diff --git a/Emby.Server.Implementations/Services/ServicePath.cs b/Emby.Server.Implementations/Services/ServicePath.cs
index 255b20919..df5d71374 100644
--- a/Emby.Server.Implementations/Services/ServicePath.cs
+++ b/Emby.Server.Implementations/Services/ServicePath.cs
@@ -5,6 +5,7 @@ using System.Linq;
using System.Reflection;
using System.Text;
using MediaBrowser.Model.Logging;
+using MediaBrowser.Model.Extensions;
namespace Emby.Server.Implementations.Services
{
@@ -20,8 +21,6 @@ namespace Emby.Server.Implementations.Services
readonly bool[] componentsWithSeparators;
private readonly string restPath;
- private readonly string allowedVerbs;
- private readonly bool allowsAllVerbs;
public bool IsWildCardPath { get; private set; }
private readonly string[] literalsToMatch;
@@ -45,15 +44,7 @@ namespace Emby.Server.Implementations.Services
/// </summary>
public int TotalComponentsCount { get; set; }
- public string[] Verbs
- {
- get
- {
- return allowsAllVerbs
- ? new[] { "ANY" }
- : AllowedVerbs.Split(new[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries);
- }
- }
+ public string[] Verbs { get; private set; }
public Type RequestType { get; private set; }
@@ -61,19 +52,11 @@ namespace Emby.Server.Implementations.Services
public string Summary { get; private set; }
- public string Notes { get; private set; }
-
- public bool AllowsAllVerbs { get { return this.allowsAllVerbs; } }
-
- public string AllowedVerbs { get { return this.allowedVerbs; } }
-
public int Priority { get; set; } //passed back to RouteAttribute
public static string[] GetPathPartsForMatching(string pathInfo)
{
- var parts = pathInfo.ToLower().Split(PathSeperatorChar)
- .Where(x => !String.IsNullOrEmpty(x)).ToArray();
- return parts;
+ return pathInfo.ToLower().Split(new[] { PathSeperatorChar }, StringSplitOptions.RemoveEmptyEntries);
}
public static List<string> GetFirstMatchHashKeys(string[] pathPartsForMatching)
@@ -108,18 +91,13 @@ namespace Emby.Server.Implementations.Services
return list;
}
- public RestPath(Func<Type, object> createInstanceFn, Func<Type, Func<string, object>> getParseFn, Type requestType, string path, string verbs, string summary = null, string notes = null)
+ public RestPath(Func<Type, object> createInstanceFn, Func<Type, Func<string, object>> getParseFn, Type requestType, string path, string verbs, string summary = null)
{
this.RequestType = requestType;
this.Summary = summary;
- this.Notes = notes;
this.restPath = path;
- this.allowsAllVerbs = verbs == null || String.Equals(verbs, WildCard, StringComparison.OrdinalIgnoreCase);
- if (!this.allowsAllVerbs)
- {
- this.allowedVerbs = verbs.ToUpper();
- }
+ this.Verbs = string.IsNullOrWhiteSpace(verbs) ? ServiceExecExtensions.AllVerbs : verbs.ToUpper().Split(new[] { ' ', ',' }, StringSplitOptions.RemoveEmptyEntries);
var componentsList = new List<string>();
@@ -142,17 +120,16 @@ namespace Emby.Server.Implementations.Services
}
}
- var components = componentsList.ToArray();
+ var components = componentsList.ToArray(componentsList.Count);
this.TotalComponentsCount = components.Length;
this.literalsToMatch = new string[this.TotalComponentsCount];
this.variablesNames = new string[this.TotalComponentsCount];
this.isWildcard = new bool[this.TotalComponentsCount];
- this.componentsWithSeparators = hasSeparators.ToArray();
+ this.componentsWithSeparators = hasSeparators.ToArray(hasSeparators.Count);
this.PathComponentsCount = this.componentsWithSeparators.Length;
string firstLiteralMatch = null;
- var sbHashKey = new StringBuilder();
for (var i = 0; i < components.Length; i++)
{
var component = components[i];
@@ -171,7 +148,6 @@ namespace Emby.Server.Implementations.Services
else
{
this.literalsToMatch[i] = component.ToLower();
- sbHashKey.Append(i + PathSeperatorChar.ToString() + this.literalsToMatch);
if (firstLiteralMatch == null)
{
@@ -197,9 +173,6 @@ namespace Emby.Server.Implementations.Services
? this.PathComponentsCount + PathSeperator + firstLiteralMatch
: WildCardChar + PathSeperator + firstLiteralMatch;
- this.IsValid = sbHashKey.Length > 0;
- this.UniqueMatchHashKey = sbHashKey.ToString();
-
this.typeDeserializer = new StringMapTypeDeserializer(createInstanceFn, getParseFn, this.RequestType);
RegisterCaseInsenstivePropertyNameMappings();
}
@@ -219,26 +192,46 @@ namespace Emby.Server.Implementations.Services
};
- private static List<Type> _excludeTypes = new List<Type> { typeof(Stream) };
+ private static Type excludeType = typeof(Stream);
- internal static PropertyInfo[] GetSerializableProperties(Type type)
+ internal static List<PropertyInfo> GetSerializableProperties(Type type)
{
- var properties = GetPublicProperties(type);
- var readableProperties = properties.Where(x => x.GetMethod != null);
+ var list = new List<PropertyInfo>();
+ var props = GetPublicProperties(type);
- // else return those properties that are not decorated with IgnoreDataMember
- return readableProperties
- .Where(prop => prop.GetCustomAttributes(true)
- .All(attr =>
+ foreach (var prop in props)
+ {
+ if (prop.GetMethod == null)
+ {
+ continue;
+ }
+
+ if (excludeType == prop.PropertyType)
+ {
+ continue;
+ }
+
+ var ignored = false;
+ foreach (var attr in prop.GetCustomAttributes(true))
+ {
+ if (IgnoreAttributesNamed.Contains(attr.GetType().Name))
{
- var name = attr.GetType().Name;
- return !IgnoreAttributesNamed.Contains(name);
- }))
- .Where(prop => !_excludeTypes.Contains(prop.PropertyType))
- .ToArray();
+ ignored = true;
+ break;
+ }
+ }
+
+ if (!ignored)
+ {
+ list.Add(prop);
+ }
+ }
+
+ // else return those properties that are not decorated with IgnoreDataMember
+ return list;
}
- private static PropertyInfo[] GetPublicProperties(Type type)
+ private static List<PropertyInfo> GetPublicProperties(Type type)
{
if (type.GetTypeInfo().IsInterface)
{
@@ -268,12 +261,19 @@ namespace Emby.Server.Implementations.Services
propertyInfos.InsertRange(0, newPropertyInfos);
}
- return propertyInfos.ToArray();
+ return propertyInfos;
}
- return GetTypesPublicProperties(type)
- .Where(t => t.GetIndexParameters().Length == 0) // ignore indexed properties
- .ToArray();
+ var list = new List<PropertyInfo>();
+
+ foreach (var t in GetTypesPublicProperties(type))
+ {
+ if (t.GetIndexParameters().Length == 0)
+ {
+ list.Add(t);
+ }
+ }
+ return list;
}
private static PropertyInfo[] GetTypesPublicProperties(Type subType)
@@ -285,19 +285,14 @@ namespace Emby.Server.Implementations.Services
if (mi != null && mi.IsStatic) continue;
pis.Add(pi);
}
- return pis.ToArray();
+ return pis.ToArray(pis.Count);
}
-
- public bool IsValid { get; set; }
-
/// <summary>
/// Provide for quick lookups based on hashes that can be determined from a request url
/// </summary>
public string FirstMatchHashKey { get; private set; }
- public string UniqueMatchHashKey { get; private set; }
-
private readonly StringMapTypeDeserializer typeDeserializer;
private readonly Dictionary<string, string> propertyNamesMap = new Dictionary<string, string>();
@@ -320,8 +315,14 @@ namespace Emby.Server.Implementations.Services
score += Math.Max((10 - VariableArgsCount), 1) * 100;
//Exact verb match is better than ANY
- var exactVerb = String.Equals(httpMethod, AllowedVerbs, StringComparison.OrdinalIgnoreCase);
- score += exactVerb ? 10 : 1;
+ if (Verbs.Length == 1 && string.Equals(httpMethod, Verbs[0], StringComparison.OrdinalIgnoreCase))
+ {
+ score += 10;
+ }
+ else
+ {
+ score += 1;
+ }
return score;
}
@@ -345,7 +346,7 @@ namespace Emby.Server.Implementations.Services
return false;
}
- if (!this.allowsAllVerbs && !StringContains(this.allowedVerbs, httpMethod))
+ if (!Verbs.Contains(httpMethod, StringComparer.OrdinalIgnoreCase))
{
//logger.Info("allowsAllVerbs mismatch for {0} for {1} allowedverbs {2}", httpMethod, string.Join("/", withPathInfoParts), this.allowedVerbs);
return false;
@@ -450,14 +451,13 @@ namespace Emby.Server.Implementations.Services
}
}
- withPathInfoParts = totalComponents.ToArray();
+ withPathInfoParts = totalComponents.ToArray(totalComponents.Count);
return true;
}
public object CreateRequest(string pathInfo, Dictionary<string, string> queryStringAndFormData, object fromInstance)
{
- var requestComponents = pathInfo.Split(PathSeperatorChar)
- .Where(x => !String.IsNullOrEmpty(x)).ToArray();
+ var requestComponents = pathInfo.Split(new[] { PathSeperatorChar }, StringSplitOptions.RemoveEmptyEntries);
ExplodeComponents(ref requestComponents);
@@ -554,10 +554,5 @@ namespace Emby.Server.Implementations.Services
return this.typeDeserializer.PopulateFromMap(fromInstance, requestKeyValuesMap);
}
-
- public override int GetHashCode()
- {
- return UniqueMatchHashKey.GetHashCode();
- }
}
} \ No newline at end of file
diff --git a/Emby.Server.Implementations/Services/StringMapTypeDeserializer.cs b/Emby.Server.Implementations/Services/StringMapTypeDeserializer.cs
index fc1cf4ed9..2233bf918 100644
--- a/Emby.Server.Implementations/Services/StringMapTypeDeserializer.cs
+++ b/Emby.Server.Implementations/Services/StringMapTypeDeserializer.cs
@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
-using System.Linq;
using System.Reflection;
namespace Emby.Server.Implementations.Services
@@ -64,11 +63,16 @@ namespace Emby.Server.Implementations.Services
if (instance == null)
instance = _CreateInstanceFn(type);
- foreach (var pair in keyValuePairs.Where(x => !string.IsNullOrEmpty(x.Value)))
+ foreach (var pair in keyValuePairs)
{
propertyName = pair.Key;
propertyTextValue = pair.Value;
+ if (string.IsNullOrEmpty(propertyTextValue))
+ {
+ continue;
+ }
+
if (!propertySetterMap.TryGetValue(propertyName, out propertySerializerEntry))
{
if (propertyName == "v")
@@ -115,7 +119,7 @@ namespace Emby.Server.Implementations.Services
{
public static Action<object, object> GetSetPropertyMethod(Type type, PropertyInfo propertyInfo)
{
- if (!propertyInfo.CanWrite || propertyInfo.GetIndexParameters().Any()) return null;
+ if (!propertyInfo.CanWrite || propertyInfo.GetIndexParameters().Length > 0) return null;
var setMethodInfo = propertyInfo.SetMethod;
return (instance, value) => setMethodInfo.Invoke(instance, new[] { value });
diff --git a/Emby.Server.Implementations/Session/HttpSessionController.cs b/Emby.Server.Implementations/Session/HttpSessionController.cs
index dbac76bb4..bd53da1bd 100644
--- a/Emby.Server.Implementations/Session/HttpSessionController.cs
+++ b/Emby.Server.Implementations/Session/HttpSessionController.cs
@@ -14,7 +14,7 @@ using System.Threading.Tasks;
namespace Emby.Server.Implementations.Session
{
- public class HttpSessionController : ISessionController, IDisposable
+ public class HttpSessionController : ISessionController
{
private readonly IHttpClient _httpClient;
private readonly IJsonSerializer _json;
@@ -195,9 +195,5 @@ namespace Emby.Server.Implementations.Session
return "?" + args;
}
-
- public void Dispose()
- {
- }
}
}
diff --git a/Emby.Server.Implementations/Session/SessionManager.cs b/Emby.Server.Implementations/Session/SessionManager.cs
index 317f40a37..0692a0ba5 100644
--- a/Emby.Server.Implementations/Session/SessionManager.cs
+++ b/Emby.Server.Implementations/Session/SessionManager.cs
@@ -6,11 +6,8 @@ using MediaBrowser.Controller.Devices;
using MediaBrowser.Controller.Drawing;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.LiveTv;
-using MediaBrowser.Controller.Persistence;
using MediaBrowser.Controller.Security;
using MediaBrowser.Controller.Session;
using MediaBrowser.Model.Devices;
@@ -32,6 +29,7 @@ using System.Threading.Tasks;
using MediaBrowser.Controller.Net;
using MediaBrowser.Model.Querying;
using MediaBrowser.Model.Threading;
+using MediaBrowser.Model.Extensions;
namespace Emby.Server.Implementations.Session
{
@@ -252,7 +250,7 @@ namespace Emby.Server.Implementations.Session
{
try
{
- await _userManager.UpdateUser(user).ConfigureAwait(false);
+ _userManager.UpdateUser(user);
}
catch (Exception ex)
{
@@ -467,7 +465,7 @@ namespace Emby.Server.Implementations.Session
if (!userId.HasValue)
{
- sessionInfo.AdditionalUsers.Clear();
+ sessionInfo.AdditionalUsers = new SessionUserInfo[] { };
}
if (sessionInfo.SessionController == null)
@@ -621,7 +619,7 @@ namespace Emby.Server.Implementations.Session
{
foreach (var user in users)
{
- await OnPlaybackStart(user.Id, libraryItem).ConfigureAwait(false);
+ OnPlaybackStart(user.Id, libraryItem);
}
}
@@ -649,8 +647,7 @@ namespace Emby.Server.Implementations.Session
/// </summary>
/// <param name="userId">The user identifier.</param>
/// <param name="item">The item.</param>
- /// <returns>Task.</returns>
- private async Task OnPlaybackStart(Guid userId, IHasUserData item)
+ private void OnPlaybackStart(Guid userId, IHasUserData item)
{
var data = _userDataManager.GetUserData(userId, item);
@@ -669,7 +666,7 @@ namespace Emby.Server.Implementations.Session
data.Played = false;
}
- await _userDataManager.SaveUserData(userId, item, data, UserDataSaveReason.PlaybackStart, CancellationToken.None).ConfigureAwait(false);
+ _userDataManager.SaveUserData(userId, item, data, UserDataSaveReason.PlaybackStart, CancellationToken.None);
}
public Task OnPlaybackProgress(PlaybackProgressInfo info)
@@ -701,7 +698,7 @@ namespace Emby.Server.Implementations.Session
{
foreach (var user in users)
{
- await OnPlaybackProgress(user, libraryItem, info).ConfigureAwait(false);
+ OnPlaybackProgress(user, libraryItem, info);
}
}
@@ -729,7 +726,7 @@ namespace Emby.Server.Implementations.Session
StartIdleCheckTimer();
}
- private async Task OnPlaybackProgress(User user, BaseItem item, PlaybackProgressInfo info)
+ private void OnPlaybackProgress(User user, BaseItem item, PlaybackProgressInfo info)
{
var data = _userDataManager.GetUserData(user.Id, item);
@@ -741,7 +738,7 @@ namespace Emby.Server.Implementations.Session
UpdatePlaybackSettings(user, info, data);
- await _userDataManager.SaveUserData(user.Id, item, data, UserDataSaveReason.PlaybackProgress, CancellationToken.None).ConfigureAwait(false);
+ _userDataManager.SaveUserData(user.Id, item, data, UserDataSaveReason.PlaybackProgress, CancellationToken.None);
}
}
@@ -841,7 +838,7 @@ namespace Emby.Server.Implementations.Session
{
foreach (var user in users)
{
- playedToCompletion = await OnPlaybackStopped(user.Id, libraryItem, info.PositionTicks, info.Failed).ConfigureAwait(false);
+ playedToCompletion = OnPlaybackStopped(user.Id, libraryItem, info.PositionTicks, info.Failed);
}
}
@@ -874,7 +871,7 @@ namespace Emby.Server.Implementations.Session
await SendPlaybackStoppedNotification(session, CancellationToken.None).ConfigureAwait(false);
}
- private async Task<bool> OnPlaybackStopped(Guid userId, BaseItem item, long? positionTicks, bool playbackFailed)
+ private bool OnPlaybackStopped(Guid userId, BaseItem item, long? positionTicks, bool playbackFailed)
{
bool playedToCompletion = false;
@@ -895,7 +892,7 @@ namespace Emby.Server.Implementations.Session
playedToCompletion = true;
}
- await _userDataManager.SaveUserData(userId, item, data, UserDataSaveReason.PlaybackFinished, CancellationToken.None).ConfigureAwait(false);
+ _userDataManager.SaveUserData(userId, item, data, UserDataSaveReason.PlaybackFinished, CancellationToken.None);
}
return playedToCompletion;
@@ -1000,7 +997,7 @@ namespace Emby.Server.Implementations.Session
command.PlayCommand = PlayCommand.PlayNow;
}
- command.ItemIds = items.Select(i => i.Id.ToString("N")).ToArray();
+ command.ItemIds = items.Select(i => i.Id.ToString("N")).ToArray(items.Count);
if (user != null)
{
@@ -1033,7 +1030,7 @@ namespace Emby.Server.Implementations.Session
if (episodes.Count > 0)
{
- command.ItemIds = episodes.Select(i => i.Id.ToString("N")).ToArray();
+ command.ItemIds = episodes.Select(i => i.Id.ToString("N")).ToArray(episodes.Count);
}
}
}
@@ -1073,7 +1070,7 @@ namespace Emby.Server.Implementations.Session
DtoOptions = new DtoOptions(false)
{
EnableImages = false,
- Fields = new List<ItemFields>
+ Fields = new ItemFields[]
{
ItemFields.SortName
}
@@ -1089,14 +1086,14 @@ namespace Emby.Server.Implementations.Session
{
var folder = (Folder)item;
- var itemsResult = folder.GetItems(new InternalItemsQuery(user)
+ var itemsResult = folder.GetItemList(new InternalItemsQuery(user)
{
Recursive = true,
IsFolder = false,
DtoOptions = new DtoOptions(false)
{
EnableImages = false,
- Fields = new List<ItemFields>
+ Fields = new ItemFields[]
{
ItemFields.SortName
}
@@ -1104,7 +1101,7 @@ namespace Emby.Server.Implementations.Session
});
- return FilterToSingleMediaType(itemsResult.Items)
+ return FilterToSingleMediaType(itemsResult)
.OrderBy(i => i.SortName)
.ToList();
}
@@ -1339,11 +1336,15 @@ namespace Emby.Server.Implementations.Session
{
var user = _userManager.GetUserById(userId);
- session.AdditionalUsers.Add(new SessionUserInfo
+ var list = session.AdditionalUsers.ToList();
+
+ list.Add(new SessionUserInfo
{
UserId = userId,
UserName = user.Name
});
+
+ session.AdditionalUsers = list.ToArray(list.Count);
}
}
@@ -1367,7 +1368,10 @@ namespace Emby.Server.Implementations.Session
if (user != null)
{
- session.AdditionalUsers.Remove(user);
+ var list = session.AdditionalUsers.ToList();
+ list.Remove(user);
+
+ session.AdditionalUsers = list.ToArray(list.Count);
}
}
@@ -1424,7 +1428,7 @@ namespace Emby.Server.Implementations.Session
user = result;
}
- var token = await GetAuthorizationToken(user.Id.ToString("N"), request.DeviceId, request.App, request.AppVersion, request.DeviceName).ConfigureAwait(false);
+ var token = GetAuthorizationToken(user.Id.ToString("N"), request.DeviceId, request.App, request.AppVersion, request.DeviceName);
EventHelper.FireEventIfNotNull(AuthenticationSucceeded, this, new GenericEventArgs<AuthenticationRequest>(request), _logger);
@@ -1446,7 +1450,7 @@ namespace Emby.Server.Implementations.Session
}
- private async Task<string> GetAuthorizationToken(string userId, string deviceId, string app, string appVersion, string deviceName)
+ private string GetAuthorizationToken(string userId, string deviceId, string app, string appVersion, string deviceName)
{
var existing = _authRepo.Get(new AuthenticationInfoQuery
{
@@ -1476,12 +1480,12 @@ namespace Emby.Server.Implementations.Session
};
_logger.Info("Creating new access token for user {0}", userId);
- await _authRepo.Create(newToken, CancellationToken.None).ConfigureAwait(false);
+ _authRepo.Create(newToken, CancellationToken.None);
return newToken.AccessToken;
}
- public async Task Logout(string accessToken)
+ public void Logout(string accessToken)
{
if (string.IsNullOrWhiteSpace(accessToken))
{
@@ -1501,7 +1505,7 @@ namespace Emby.Server.Implementations.Session
{
existing.IsActive = false;
- await _authRepo.Update(existing, CancellationToken.None).ConfigureAwait(false);
+ _authRepo.Update(existing, CancellationToken.None);
var sessions = Sessions
.Where(i => string.Equals(i.DeviceId, existing.DeviceId, StringComparison.OrdinalIgnoreCase))
@@ -1521,7 +1525,7 @@ namespace Emby.Server.Implementations.Session
}
}
- public async Task RevokeUserTokens(string userId, string currentAccessToken)
+ public void RevokeUserTokens(string userId, string currentAccessToken)
{
var existing = _authRepo.Get(new AuthenticationInfoQuery
{
@@ -1533,14 +1537,14 @@ namespace Emby.Server.Implementations.Session
{
if (!string.Equals(currentAccessToken, info.AccessToken, StringComparison.OrdinalIgnoreCase))
{
- await Logout(info.AccessToken).ConfigureAwait(false);
+ Logout(info.AccessToken);
}
}
}
- public Task RevokeToken(string token)
+ public void RevokeToken(string token)
{
- return Logout(token);
+ Logout(token);
}
/// <summary>
@@ -1660,37 +1664,39 @@ namespace Emby.Server.Implementations.Session
AddProgramRecordingInfo = false
};
- dtoOptions.Fields.Remove(ItemFields.BasicSyncInfo);
- dtoOptions.Fields.Remove(ItemFields.SyncInfo);
- dtoOptions.Fields.Remove(ItemFields.CanDelete);
- dtoOptions.Fields.Remove(ItemFields.CanDownload);
- dtoOptions.Fields.Remove(ItemFields.ChildCount);
- dtoOptions.Fields.Remove(ItemFields.CustomRating);
- dtoOptions.Fields.Remove(ItemFields.DateLastMediaAdded);
- dtoOptions.Fields.Remove(ItemFields.DateLastRefreshed);
- dtoOptions.Fields.Remove(ItemFields.DateLastSaved);
- dtoOptions.Fields.Remove(ItemFields.DisplayMediaType);
- dtoOptions.Fields.Remove(ItemFields.DisplayPreferencesId);
- dtoOptions.Fields.Remove(ItemFields.Etag);
- dtoOptions.Fields.Remove(ItemFields.ExternalEtag);
- dtoOptions.Fields.Remove(ItemFields.InheritedParentalRatingValue);
- dtoOptions.Fields.Remove(ItemFields.ItemCounts);
- dtoOptions.Fields.Remove(ItemFields.MediaSourceCount);
- dtoOptions.Fields.Remove(ItemFields.MediaStreams);
- dtoOptions.Fields.Remove(ItemFields.MediaSources);
- dtoOptions.Fields.Remove(ItemFields.People);
- dtoOptions.Fields.Remove(ItemFields.PlayAccess);
- dtoOptions.Fields.Remove(ItemFields.People);
- dtoOptions.Fields.Remove(ItemFields.ProductionLocations);
- dtoOptions.Fields.Remove(ItemFields.RecursiveItemCount);
- dtoOptions.Fields.Remove(ItemFields.RemoteTrailers);
- dtoOptions.Fields.Remove(ItemFields.SeasonUserData);
- dtoOptions.Fields.Remove(ItemFields.SeriesGenres);
- dtoOptions.Fields.Remove(ItemFields.Settings);
- dtoOptions.Fields.Remove(ItemFields.SortName);
- dtoOptions.Fields.Remove(ItemFields.Tags);
- dtoOptions.Fields.Remove(ItemFields.ThemeSongIds);
- dtoOptions.Fields.Remove(ItemFields.ThemeVideoIds);
+ var fields = dtoOptions.Fields.ToList();
+
+ fields.Remove(ItemFields.BasicSyncInfo);
+ fields.Remove(ItemFields.SyncInfo);
+ fields.Remove(ItemFields.CanDelete);
+ fields.Remove(ItemFields.CanDownload);
+ fields.Remove(ItemFields.ChildCount);
+ fields.Remove(ItemFields.CustomRating);
+ fields.Remove(ItemFields.DateLastMediaAdded);
+ fields.Remove(ItemFields.DateLastRefreshed);
+ fields.Remove(ItemFields.DateLastSaved);
+ fields.Remove(ItemFields.DisplayPreferencesId);
+ fields.Remove(ItemFields.Etag);
+ fields.Remove(ItemFields.ExternalEtag);
+ fields.Remove(ItemFields.InheritedParentalRatingValue);
+ fields.Remove(ItemFields.ItemCounts);
+ fields.Remove(ItemFields.MediaSourceCount);
+ fields.Remove(ItemFields.MediaStreams);
+ fields.Remove(ItemFields.MediaSources);
+ fields.Remove(ItemFields.People);
+ fields.Remove(ItemFields.PlayAccess);
+ fields.Remove(ItemFields.People);
+ fields.Remove(ItemFields.ProductionLocations);
+ fields.Remove(ItemFields.RecursiveItemCount);
+ fields.Remove(ItemFields.RemoteTrailers);
+ fields.Remove(ItemFields.SeasonUserData);
+ fields.Remove(ItemFields.Settings);
+ fields.Remove(ItemFields.SortName);
+ fields.Remove(ItemFields.Tags);
+ fields.Remove(ItemFields.ThemeSongIds);
+ fields.Remove(ItemFields.ThemeVideoIds);
+
+ dtoOptions.Fields = fields.ToArray(fields.Count);
_itemInfoDtoOptions = dtoOptions;
}
@@ -1699,7 +1705,7 @@ namespace Emby.Server.Implementations.Session
if (mediaSource != null)
{
- info.MediaStreams = mediaSource.MediaStreams;
+ info.MediaStreams = mediaSource.MediaStreams.ToArray();
}
return info;
diff --git a/Emby.Server.Implementations/Session/SessionWebSocketListener.cs b/Emby.Server.Implementations/Session/SessionWebSocketListener.cs
index 2735bb237..a5af843db 100644
--- a/Emby.Server.Implementations/Session/SessionWebSocketListener.cs
+++ b/Emby.Server.Implementations/Session/SessionWebSocketListener.cs
@@ -102,6 +102,7 @@ namespace Emby.Server.Implementations.Session
public void Dispose()
{
_serverManager.WebSocketConnected -= _serverManager_WebSocketConnected;
+ GC.SuppressFinalize(this);
}
/// <summary>
diff --git a/Emby.Server.Implementations/Session/WebSocketController.cs b/Emby.Server.Implementations/Session/WebSocketController.cs
index f0ff0b5dd..ee9ee8969 100644
--- a/Emby.Server.Implementations/Session/WebSocketController.cs
+++ b/Emby.Server.Implementations/Session/WebSocketController.cs
@@ -283,6 +283,7 @@ namespace Emby.Server.Implementations.Session
{
socket.Closed -= connection_Closed;
}
+ GC.SuppressFinalize(this);
}
}
}
diff --git a/Emby.Server.Implementations/Social/SharingManager.cs b/Emby.Server.Implementations/Social/SharingManager.cs
index 54614c879..57cf93948 100644
--- a/Emby.Server.Implementations/Social/SharingManager.cs
+++ b/Emby.Server.Implementations/Social/SharingManager.cs
@@ -58,8 +58,8 @@ namespace Emby.Server.Implementations.Social
};
AddShareInfo(info, externalUrl);
-
- await _repository.CreateShare(info).ConfigureAwait(false);
+
+ _repository.CreateShare(info);
return info;
}
@@ -92,9 +92,9 @@ namespace Emby.Server.Implementations.Social
}
}
- public Task DeleteShare(string id)
+ public void DeleteShare(string id)
{
- return _repository.DeleteShare(id);
+ _repository.DeleteShare(id);
}
}
}
diff --git a/Emby.Server.Implementations/Social/SharingRepository.cs b/Emby.Server.Implementations/Social/SharingRepository.cs
index 46e9205bb..f306e76c4 100644
--- a/Emby.Server.Implementations/Social/SharingRepository.cs
+++ b/Emby.Server.Implementations/Social/SharingRepository.cs
@@ -1,13 +1,12 @@
using System;
using System.Collections.Generic;
using System.IO;
-using System.Threading;
-using System.Threading.Tasks;
using Emby.Server.Implementations.Data;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Social;
using SQLitePCL.pretty;
+using MediaBrowser.Model.Extensions;
namespace Emby.Server.Implementations.Social
{
@@ -41,7 +40,7 @@ namespace Emby.Server.Implementations.Social
}
}
- public async Task CreateShare(SocialShareInfo info)
+ public void CreateShare(SocialShareInfo info)
{
if (info == null)
{
@@ -86,7 +85,7 @@ namespace Emby.Server.Implementations.Social
var paramList = new List<object>();
paramList.Add(id.ToGuidBlob());
- foreach (var row in connection.Query(commandText, paramList.ToArray()))
+ foreach (var row in connection.Query(commandText, paramList.ToArray(paramList.Count)))
{
return GetSocialShareInfo(row);
}
@@ -108,7 +107,7 @@ namespace Emby.Server.Implementations.Social
return info;
}
- public async Task DeleteShare(string id)
+ public void DeleteShare(string id)
{
}
diff --git a/Emby.Server.Implementations/Sorting/AirTimeComparer.cs b/Emby.Server.Implementations/Sorting/AirTimeComparer.cs
deleted file mode 100644
index bc05e9af3..000000000
--- a/Emby.Server.Implementations/Sorting/AirTimeComparer.cs
+++ /dev/null
@@ -1,71 +0,0 @@
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Entities.TV;
-using MediaBrowser.Controller.Sorting;
-using MediaBrowser.Model.Querying;
-using System;
-
-namespace Emby.Server.Implementations.Sorting
-{
- public class AirTimeComparer : IBaseItemComparer
- {
- /// <summary>
- /// Compares the specified x.
- /// </summary>
- /// <param name="x">The x.</param>
- /// <param name="y">The y.</param>
- /// <returns>System.Int32.</returns>
- public int Compare(BaseItem x, BaseItem y)
- {
- return DateTime.Compare(GetValue(x), GetValue(y));
- }
-
- /// <summary>
- /// Gets the value.
- /// </summary>
- /// <param name="x">The x.</param>
- /// <returns>System.String.</returns>
- private DateTime GetValue(BaseItem x)
- {
- var series = x as Series;
-
- if (series == null)
- {
- var season = x as Season;
-
- if (season != null)
- {
- series = season.Series;
- }
- else
- {
- var episode = x as Episode;
-
- if (episode != null)
- {
- series = episode.Series;
- }
- }
- }
-
- if (series != null)
- {
- DateTime result;
- if (DateTime.TryParse(series.AirTime, out result))
- {
- return result;
- }
- }
-
- return DateTime.MinValue;
- }
-
- /// <summary>
- /// Gets the name.
- /// </summary>
- /// <value>The name.</value>
- public string Name
- {
- get { return ItemSortBy.AirTime; }
- }
- }
-}
diff --git a/Emby.Server.Implementations/Sorting/ArtistComparer.cs b/Emby.Server.Implementations/Sorting/ArtistComparer.cs
index edb195820..616aff673 100644
--- a/Emby.Server.Implementations/Sorting/ArtistComparer.cs
+++ b/Emby.Server.Implementations/Sorting/ArtistComparer.cs
@@ -36,7 +36,7 @@ namespace Emby.Server.Implementations.Sorting
return string.Empty;
}
- return audio.Artists.Count == 0 ? null : audio.Artists[0];
+ return audio.Artists.Length == 0 ? null : audio.Artists[0];
}
/// <summary>
diff --git a/Emby.Server.Core/SystemEvents.cs b/Emby.Server.Implementations/SystemEvents.cs
index 8d5cd4ad8..dfff92f1e 100644
--- a/Emby.Server.Core/SystemEvents.cs
+++ b/Emby.Server.Implementations/SystemEvents.cs
@@ -3,7 +3,7 @@ using MediaBrowser.Common.Events;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.System;
-namespace MediaBrowser.Server.Startup.Common
+namespace Emby.Server.Implementations
{
public class SystemEvents : ISystemEvents
{
diff --git a/Emby.Server.Implementations/TV/SeriesPostScanTask.cs b/Emby.Server.Implementations/TV/SeriesPostScanTask.cs
index 23b6a3cb5..764df8baf 100644
--- a/Emby.Server.Implementations/TV/SeriesPostScanTask.cs
+++ b/Emby.Server.Implementations/TV/SeriesPostScanTask.cs
@@ -217,6 +217,7 @@ namespace Emby.Server.Implementations.TV
public void Dispose()
{
Dispose(true);
+ GC.SuppressFinalize(this);
}
/// <summary>
diff --git a/Emby.Server.Implementations/TV/TVSeriesManager.cs b/Emby.Server.Implementations/TV/TVSeriesManager.cs
index 876c5d58b..0b81f7e93 100644
--- a/Emby.Server.Implementations/TV/TVSeriesManager.cs
+++ b/Emby.Server.Implementations/TV/TVSeriesManager.cs
@@ -42,7 +42,7 @@ namespace Emby.Server.Implementations.TV
int? limit = null;
if (!string.IsNullOrWhiteSpace(request.SeriesId))
{
- var series = _libraryManager.GetItemById(request.SeriesId);
+ var series = _libraryManager.GetItemById(request.SeriesId) as Series;
if (series != null)
{
@@ -51,29 +51,34 @@ namespace Emby.Server.Implementations.TV
}
}
- if (string.IsNullOrWhiteSpace(presentationUniqueKey) && limit.HasValue)
+ if (!string.IsNullOrWhiteSpace(presentationUniqueKey))
+ {
+ return GetResult(GetNextUpEpisodes(request, user, new[] { presentationUniqueKey }, dtoOptions), request);
+ }
+
+ if (limit.HasValue)
{
limit = limit.Value + 10;
}
var items = _libraryManager.GetItemList(new InternalItemsQuery(user)
{
- IncludeItemTypes = new[] { typeof(Series).Name },
- SortBy = new[] { ItemSortBy.SeriesDatePlayed },
- SortOrder = SortOrder.Descending,
- PresentationUniqueKey = presentationUniqueKey,
+ IncludeItemTypes = new[] { typeof(Episode).Name },
+ OrderBy = new[] { new Tuple<string, SortOrder>(ItemSortBy.DatePlayed, SortOrder.Descending) },
+ SeriesPresentationUniqueKey = presentationUniqueKey,
Limit = limit,
ParentId = parentIdGuid,
Recursive = true,
DtoOptions = new MediaBrowser.Controller.Dto.DtoOptions
{
- Fields = new List<ItemFields>
+ Fields = new ItemFields[]
{
- ItemFields.PresentationUniqueKey
+ ItemFields.SeriesPresentationUniqueKey
}
- }
+ },
+ GroupBySeriesPresentationUniqueKey = true
- }).Cast<Series>().Select(GetUniqueSeriesKey);
+ }).Cast<Episode>().Select(GetUniqueSeriesKey);
// Avoid implicitly captured closure
var episodes = GetNextUpEpisodes(request, user, items, dtoOptions);
@@ -94,7 +99,7 @@ namespace Emby.Server.Implementations.TV
int? limit = null;
if (!string.IsNullOrWhiteSpace(request.SeriesId))
{
- var series = _libraryManager.GetItemById(request.SeriesId);
+ var series = _libraryManager.GetItemById(request.SeriesId) as Series;
if (series != null)
{
@@ -103,28 +108,33 @@ namespace Emby.Server.Implementations.TV
}
}
- if (string.IsNullOrWhiteSpace(presentationUniqueKey) && limit.HasValue)
+ if (!string.IsNullOrWhiteSpace(presentationUniqueKey))
+ {
+ return GetResult(GetNextUpEpisodes(request, user, new [] { presentationUniqueKey }, dtoOptions), request);
+ }
+
+ if (limit.HasValue)
{
limit = limit.Value + 10;
}
var items = _libraryManager.GetItemList(new InternalItemsQuery(user)
{
- IncludeItemTypes = new[] { typeof(Series).Name },
- SortBy = new[] { ItemSortBy.SeriesDatePlayed },
- SortOrder = SortOrder.Descending,
- PresentationUniqueKey = presentationUniqueKey,
+ IncludeItemTypes = new[] { typeof(Episode).Name },
+ OrderBy = new[] { new Tuple<string, SortOrder>(ItemSortBy.DatePlayed, SortOrder.Descending) },
+ SeriesPresentationUniqueKey = presentationUniqueKey,
Limit = limit,
DtoOptions = new MediaBrowser.Controller.Dto.DtoOptions
{
- Fields = new List<ItemFields>
+ Fields = new ItemFields[]
{
- ItemFields.PresentationUniqueKey
+ ItemFields.SeriesPresentationUniqueKey
},
EnableImages = false
- }
+ },
+ GroupBySeriesPresentationUniqueKey = true
- }, parentsFolders.Cast<BaseItem>().ToList()).Cast<Series>().Select(GetUniqueSeriesKey);
+ }, parentsFolders.Cast<BaseItem>().ToList()).Cast<Episode>().Select(GetUniqueSeriesKey);
// Avoid implicitly captured closure
var episodes = GetNextUpEpisodes(request, user, items, dtoOptions);
@@ -167,7 +177,12 @@ namespace Emby.Server.Implementations.TV
.Where(i => i != null);
}
- private string GetUniqueSeriesKey(BaseItem series)
+ private string GetUniqueSeriesKey(Episode episode)
+ {
+ return episode.SeriesPresentationUniqueKey;
+ }
+
+ private string GetUniqueSeriesKey(Series series)
{
return series.GetPresentationUniqueKey();
}
@@ -183,14 +198,13 @@ namespace Emby.Server.Implementations.TV
AncestorWithPresentationUniqueKey = null,
SeriesPresentationUniqueKey = seriesKey,
IncludeItemTypes = new[] { typeof(Episode).Name },
- SortBy = new[] { ItemSortBy.SortName },
- SortOrder = SortOrder.Descending,
+ OrderBy = new[] { new Tuple<string, SortOrder>(ItemSortBy.SortName, SortOrder.Descending) },
IsPlayed = true,
Limit = 1,
ParentIndexNumberNotEquals = 0,
DtoOptions = new MediaBrowser.Controller.Dto.DtoOptions
{
- Fields = new List<ItemFields>
+ Fields = new ItemFields[]
{
ItemFields.SortName
},
@@ -206,8 +220,7 @@ namespace Emby.Server.Implementations.TV
AncestorWithPresentationUniqueKey = null,
SeriesPresentationUniqueKey = seriesKey,
IncludeItemTypes = new[] { typeof(Episode).Name },
- SortBy = new[] { ItemSortBy.SortName },
- SortOrder = SortOrder.Ascending,
+ OrderBy = new[] { new Tuple<string, SortOrder>(ItemSortBy.SortName, SortOrder.Ascending) },
Limit = 1,
IsPlayed = false,
IsVirtualItem = false,
diff --git a/Emby.Common.Implementations/TextEncoding/NLangDetect/Detector.cs b/Emby.Server.Implementations/TextEncoding/NLangDetect/Detector.cs
index 507dd5e42..507dd5e42 100644
--- a/Emby.Common.Implementations/TextEncoding/NLangDetect/Detector.cs
+++ b/Emby.Server.Implementations/TextEncoding/NLangDetect/Detector.cs
diff --git a/Emby.Common.Implementations/TextEncoding/NLangDetect/DetectorFactory.cs b/Emby.Server.Implementations/TextEncoding/NLangDetect/DetectorFactory.cs
index 9d75b8356..9d75b8356 100644
--- a/Emby.Common.Implementations/TextEncoding/NLangDetect/DetectorFactory.cs
+++ b/Emby.Server.Implementations/TextEncoding/NLangDetect/DetectorFactory.cs
diff --git a/Emby.Common.Implementations/TextEncoding/NLangDetect/ErrorCode.cs b/Emby.Server.Implementations/TextEncoding/NLangDetect/ErrorCode.cs
index 3ffd3b2d9..3ffd3b2d9 100644
--- a/Emby.Common.Implementations/TextEncoding/NLangDetect/ErrorCode.cs
+++ b/Emby.Server.Implementations/TextEncoding/NLangDetect/ErrorCode.cs
diff --git a/Emby.Common.Implementations/TextEncoding/NLangDetect/Extensions/CharExtensions.cs b/Emby.Server.Implementations/TextEncoding/NLangDetect/Extensions/CharExtensions.cs
index 59076bd66..59076bd66 100644
--- a/Emby.Common.Implementations/TextEncoding/NLangDetect/Extensions/CharExtensions.cs
+++ b/Emby.Server.Implementations/TextEncoding/NLangDetect/Extensions/CharExtensions.cs
diff --git a/Emby.Common.Implementations/TextEncoding/NLangDetect/Extensions/RandomExtensions.cs b/Emby.Server.Implementations/TextEncoding/NLangDetect/Extensions/RandomExtensions.cs
index d55ca80df..d55ca80df 100644
--- a/Emby.Common.Implementations/TextEncoding/NLangDetect/Extensions/RandomExtensions.cs
+++ b/Emby.Server.Implementations/TextEncoding/NLangDetect/Extensions/RandomExtensions.cs
diff --git a/Emby.Common.Implementations/TextEncoding/NLangDetect/Extensions/StringExtensions.cs b/Emby.Server.Implementations/TextEncoding/NLangDetect/Extensions/StringExtensions.cs
index fc6c58a95..fc6c58a95 100644
--- a/Emby.Common.Implementations/TextEncoding/NLangDetect/Extensions/StringExtensions.cs
+++ b/Emby.Server.Implementations/TextEncoding/NLangDetect/Extensions/StringExtensions.cs
diff --git a/Emby.Common.Implementations/TextEncoding/NLangDetect/Extensions/UnicodeBlock.cs b/Emby.Server.Implementations/TextEncoding/NLangDetect/Extensions/UnicodeBlock.cs
index 71b5de75e..71b5de75e 100644
--- a/Emby.Common.Implementations/TextEncoding/NLangDetect/Extensions/UnicodeBlock.cs
+++ b/Emby.Server.Implementations/TextEncoding/NLangDetect/Extensions/UnicodeBlock.cs
diff --git a/Emby.Common.Implementations/TextEncoding/NLangDetect/GenProfile.cs b/Emby.Server.Implementations/TextEncoding/NLangDetect/GenProfile.cs
index 5895f68ae..5895f68ae 100644
--- a/Emby.Common.Implementations/TextEncoding/NLangDetect/GenProfile.cs
+++ b/Emby.Server.Implementations/TextEncoding/NLangDetect/GenProfile.cs
diff --git a/Emby.Common.Implementations/TextEncoding/NLangDetect/InternalException.cs b/Emby.Server.Implementations/TextEncoding/NLangDetect/InternalException.cs
index 32e50a219..32e50a219 100644
--- a/Emby.Common.Implementations/TextEncoding/NLangDetect/InternalException.cs
+++ b/Emby.Server.Implementations/TextEncoding/NLangDetect/InternalException.cs
diff --git a/Emby.Common.Implementations/TextEncoding/NLangDetect/Language.cs b/Emby.Server.Implementations/TextEncoding/NLangDetect/Language.cs
index f4b4b153e..f4b4b153e 100644
--- a/Emby.Common.Implementations/TextEncoding/NLangDetect/Language.cs
+++ b/Emby.Server.Implementations/TextEncoding/NLangDetect/Language.cs
diff --git a/Emby.Common.Implementations/TextEncoding/NLangDetect/LanguageDetector.cs b/Emby.Server.Implementations/TextEncoding/NLangDetect/LanguageDetector.cs
index fc7d420a9..fc7d420a9 100644
--- a/Emby.Common.Implementations/TextEncoding/NLangDetect/LanguageDetector.cs
+++ b/Emby.Server.Implementations/TextEncoding/NLangDetect/LanguageDetector.cs
diff --git a/Emby.Common.Implementations/TextEncoding/NLangDetect/NLangDetectException.cs b/Emby.Server.Implementations/TextEncoding/NLangDetect/NLangDetectException.cs
index e0d066020..e0d066020 100644
--- a/Emby.Common.Implementations/TextEncoding/NLangDetect/NLangDetectException.cs
+++ b/Emby.Server.Implementations/TextEncoding/NLangDetect/NLangDetectException.cs
diff --git a/Emby.Common.Implementations/TextEncoding/NLangDetect/ProbVector.cs b/Emby.Server.Implementations/TextEncoding/NLangDetect/ProbVector.cs
index c5a20dbf0..c5a20dbf0 100644
--- a/Emby.Common.Implementations/TextEncoding/NLangDetect/ProbVector.cs
+++ b/Emby.Server.Implementations/TextEncoding/NLangDetect/ProbVector.cs
diff --git a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/afr b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/afr
index be8b1722a..be8b1722a 100644
--- a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/afr
+++ b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/afr
diff --git a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/ara b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/ara
index a7b40cca0..a7b40cca0 100644
--- a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/ara
+++ b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/ara
diff --git a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/ben b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/ben
index 69083369c..69083369c 100644
--- a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/ben
+++ b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/ben
diff --git a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/bul b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/bul
index 201663afc..201663afc 100644
--- a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/bul
+++ b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/bul
diff --git a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/ces b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/ces
index e46e24f29..e46e24f29 100644
--- a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/ces
+++ b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/ces
diff --git a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/dan b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/dan
index 23e865876..23e865876 100644
--- a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/dan
+++ b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/dan
diff --git a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/deu b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/deu
index 94ebdbbdc..94ebdbbdc 100644
--- a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/deu
+++ b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/deu
diff --git a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/ell b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/ell
index 9ef014bcb..9ef014bcb 100644
--- a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/ell
+++ b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/ell
diff --git a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/eng b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/eng
index 4807e957e..4807e957e 100644
--- a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/eng
+++ b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/eng
diff --git a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/est b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/est
index 2bdb2a607..2bdb2a607 100644
--- a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/est
+++ b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/est
diff --git a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/fas b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/fas
index 87dddc1b1..87dddc1b1 100644
--- a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/fas
+++ b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/fas
diff --git a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/fin b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/fin
index fdb41748e..fdb41748e 100644
--- a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/fin
+++ b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/fin
diff --git a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/fra b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/fra
index 1d6d3baa0..1d6d3baa0 100644
--- a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/fra
+++ b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/fra
diff --git a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/guj b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/guj
index 5ab783f82..5ab783f82 100644
--- a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/guj
+++ b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/guj
diff --git a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/heb b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/heb
index 38a8c9d47..38a8c9d47 100644
--- a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/heb
+++ b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/heb
diff --git a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/hin b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/hin
index 104ed583e..104ed583e 100644
--- a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/hin
+++ b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/hin
diff --git a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/hrv b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/hrv
index 116cfa0d0..116cfa0d0 100644
--- a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/hrv
+++ b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/hrv
diff --git a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/hun b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/hun
index 77ab7c4c8..77ab7c4c8 100644
--- a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/hun
+++ b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/hun
diff --git a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/ind b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/ind
index 578fd6c45..578fd6c45 100644
--- a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/ind
+++ b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/ind
diff --git a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/ita b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/ita
index 4ba4b4009..4ba4b4009 100644
--- a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/ita
+++ b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/ita
diff --git a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/jpn b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/jpn
index 5a76401a1..5a76401a1 100644
--- a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/jpn
+++ b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/jpn
diff --git a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/kan b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/kan
index 7a599ba75..7a599ba75 100644
--- a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/kan
+++ b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/kan
diff --git a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/kor b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/kor
index 1f30ef966..1f30ef966 100644
--- a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/kor
+++ b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/kor
diff --git a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/lav b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/lav
index ce5ff7ed1..ce5ff7ed1 100644
--- a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/lav
+++ b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/lav
diff --git a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/lit b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/lit
index 3f3e0526e..3f3e0526e 100644
--- a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/lit
+++ b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/lit
diff --git a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/mal b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/mal
index 422334423..422334423 100644
--- a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/mal
+++ b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/mal
diff --git a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/mar b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/mar
index 19a194292..19a194292 100644
--- a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/mar
+++ b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/mar
diff --git a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/mkd b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/mkd
index a0c736aa6..a0c736aa6 100644
--- a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/mkd
+++ b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/mkd
diff --git a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/nep b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/nep
index 22477481b..22477481b 100644
--- a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/nep
+++ b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/nep
diff --git a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/nld b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/nld
index c74f0d267..c74f0d267 100644
--- a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/nld
+++ b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/nld
diff --git a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/nor b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/nor
index 7dc51ea94..7dc51ea94 100644
--- a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/nor
+++ b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/nor
diff --git a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/pan b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/pan
index 1140be0bf..1140be0bf 100644
--- a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/pan
+++ b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/pan
diff --git a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/pol b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/pol
index 139647c01..139647c01 100644
--- a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/pol
+++ b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/pol
diff --git a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/por b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/por
index bbdf3ed0e..bbdf3ed0e 100644
--- a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/por
+++ b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/por
diff --git a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/ron b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/ron
index a5c7b8d49..a5c7b8d49 100644
--- a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/ron
+++ b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/ron
diff --git a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/rus b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/rus
index 228e71e1b..228e71e1b 100644
--- a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/rus
+++ b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/rus
diff --git a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/slk b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/slk
index 97f988076..97f988076 100644
--- a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/slk
+++ b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/slk
diff --git a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/slv b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/slv
index cb9617131..cb9617131 100644
--- a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/slv
+++ b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/slv
diff --git a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/som b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/som
index 9d0c19cf6..9d0c19cf6 100644
--- a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/som
+++ b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/som
diff --git a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/spa b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/spa
index cdc195676..cdc195676 100644
--- a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/spa
+++ b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/spa
diff --git a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/sqi b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/sqi
index fe3fc7a2f..fe3fc7a2f 100644
--- a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/sqi
+++ b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/sqi
diff --git a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/swa b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/swa
index e745ecba7..e745ecba7 100644
--- a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/swa
+++ b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/swa
diff --git a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/swe b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/swe
index a648588e8..a648588e8 100644
--- a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/swe
+++ b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/swe
diff --git a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/tam b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/tam
index facb43d2d..facb43d2d 100644
--- a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/tam
+++ b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/tam
diff --git a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/tel b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/tel
index 2a2370453..2a2370453 100644
--- a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/tel
+++ b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/tel
diff --git a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/tgl b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/tgl
index d68c2b3df..d68c2b3df 100644
--- a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/tgl
+++ b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/tgl
diff --git a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/tha b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/tha
index 2852f4340..2852f4340 100644
--- a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/tha
+++ b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/tha
diff --git a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/tur b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/tur
index ed84e9ba3..ed84e9ba3 100644
--- a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/tur
+++ b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/tur
diff --git a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/ukr b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/ukr
index e80f2034b..e80f2034b 100644
--- a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/ukr
+++ b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/ukr
diff --git a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/urd b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/urd
index 0c11cc7f6..0c11cc7f6 100644
--- a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/urd
+++ b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/urd
diff --git a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/vie b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/vie
index 10c3d892e..10c3d892e 100644
--- a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/vie
+++ b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/vie
diff --git a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/zh-cn b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/zh-cn
index 904c61e39..904c61e39 100644
--- a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/zh-cn
+++ b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/zh-cn
diff --git a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/zh-tw b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/zh-tw
index 674b28d12..674b28d12 100644
--- a/Emby.Common.Implementations/TextEncoding/NLangDetect/Profiles/zh-tw
+++ b/Emby.Server.Implementations/TextEncoding/NLangDetect/Profiles/zh-tw
diff --git a/Emby.Common.Implementations/TextEncoding/NLangDetect/Utils/LangProfile.cs b/Emby.Server.Implementations/TextEncoding/NLangDetect/Utils/LangProfile.cs
index 0413edfad..0413edfad 100644
--- a/Emby.Common.Implementations/TextEncoding/NLangDetect/Utils/LangProfile.cs
+++ b/Emby.Server.Implementations/TextEncoding/NLangDetect/Utils/LangProfile.cs
diff --git a/Emby.Common.Implementations/TextEncoding/NLangDetect/Utils/Messages.cs b/Emby.Server.Implementations/TextEncoding/NLangDetect/Utils/Messages.cs
index 1d605cc47..1d605cc47 100644
--- a/Emby.Common.Implementations/TextEncoding/NLangDetect/Utils/Messages.cs
+++ b/Emby.Server.Implementations/TextEncoding/NLangDetect/Utils/Messages.cs
diff --git a/Emby.Common.Implementations/TextEncoding/NLangDetect/Utils/NGram.cs b/Emby.Server.Implementations/TextEncoding/NLangDetect/Utils/NGram.cs
index b1738f7ca..b1738f7ca 100644
--- a/Emby.Common.Implementations/TextEncoding/NLangDetect/Utils/NGram.cs
+++ b/Emby.Server.Implementations/TextEncoding/NLangDetect/Utils/NGram.cs
diff --git a/Emby.Common.Implementations/TextEncoding/NLangDetect/Utils/TagExtractor.cs b/Emby.Server.Implementations/TextEncoding/NLangDetect/Utils/TagExtractor.cs
index 896fd0960..896fd0960 100644
--- a/Emby.Common.Implementations/TextEncoding/NLangDetect/Utils/TagExtractor.cs
+++ b/Emby.Server.Implementations/TextEncoding/NLangDetect/Utils/TagExtractor.cs
diff --git a/Emby.Common.Implementations/TextEncoding/NLangDetect/Utils/messages.properties b/Emby.Server.Implementations/TextEncoding/NLangDetect/Utils/messages.properties
index 7967efff0..7967efff0 100644
--- a/Emby.Common.Implementations/TextEncoding/NLangDetect/Utils/messages.properties
+++ b/Emby.Server.Implementations/TextEncoding/NLangDetect/Utils/messages.properties
diff --git a/Emby.Common.Implementations/TextEncoding/TextEncoding.cs b/Emby.Server.Implementations/TextEncoding/TextEncoding.cs
index 54c47d62c..9eb9be7ea 100644
--- a/Emby.Common.Implementations/TextEncoding/TextEncoding.cs
+++ b/Emby.Server.Implementations/TextEncoding/TextEncoding.cs
@@ -1,17 +1,13 @@
using System;
using System.Text;
using MediaBrowser.Model.IO;
-using MediaBrowser.Model.Text;
-using System.IO;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Model.MediaInfo;
using MediaBrowser.Model.Logging;
-using UniversalDetector;
-using NLangDetect.Core;
using MediaBrowser.Model.Serialization;
+using MediaBrowser.Model.Text;
+using NLangDetect.Core;
+using UniversalDetector;
-namespace Emby.Common.Implementations.TextEncoding
+namespace Emby.Server.Implementations.TextEncoding
{
public class TextEncoding : ITextEncoding
{
@@ -31,18 +27,33 @@ namespace Emby.Common.Implementations.TextEncoding
return Encoding.ASCII;
}
- private Encoding GetInitialEncoding(byte[] buffer)
+ private Encoding GetInitialEncoding(byte[] buffer, int count)
{
- if (buffer[0] == 0xef && buffer[1] == 0xbb && buffer[2] == 0xbf)
- return Encoding.UTF8;
- if (buffer[0] == 0xfe && buffer[1] == 0xff)
- return Encoding.Unicode;
- if (buffer[0] == 0 && buffer[1] == 0 && buffer[2] == 0xfe && buffer[3] == 0xff)
- return Encoding.UTF32;
- if (buffer[0] == 0x2b && buffer[1] == 0x2f && buffer[2] == 0x76)
- return Encoding.UTF7;
+ if (count >= 3)
+ {
+ if (buffer[0] == 0xef && buffer[1] == 0xbb && buffer[2] == 0xbf)
+ return Encoding.UTF8;
+ }
+
+ if (count >= 2)
+ {
+ if (buffer[0] == 0xfe && buffer[1] == 0xff)
+ return Encoding.Unicode;
+ }
+
+ if (count >= 4)
+ {
+ if (buffer[0] == 0 && buffer[1] == 0 && buffer[2] == 0xfe && buffer[3] == 0xff)
+ return Encoding.UTF32;
+ }
- var result = new TextEncodingDetect().DetectEncoding(buffer, buffer.Length);
+ if (count >= 3)
+ {
+ if (buffer[0] == 0x2b && buffer[1] == 0x2f && buffer[2] == 0x76)
+ return Encoding.UTF7;
+ }
+
+ var result = new TextEncodingDetect().DetectEncoding(buffer, count);
switch (result)
{
@@ -68,9 +79,11 @@ namespace Emby.Common.Implementations.TextEncoding
}
private bool _langDetectInitialized;
- public string GetDetectedEncodingName(byte[] bytes, string language, bool enableLanguageDetection)
+ public string GetDetectedEncodingName(byte[] bytes, int count, string language, bool enableLanguageDetection)
{
- var encoding = GetInitialEncoding(bytes);
+ var index = 0;
+
+ var encoding = GetInitialEncoding(bytes, count);
if (encoding != null && encoding.Equals(Encoding.UTF8))
{
@@ -85,7 +98,7 @@ namespace Emby.Common.Implementations.TextEncoding
LanguageDetector.Initialize(_json);
}
- language = DetectLanguage(bytes);
+ language = DetectLanguage(bytes, index, count);
if (!string.IsNullOrWhiteSpace(language))
{
@@ -93,7 +106,7 @@ namespace Emby.Common.Implementations.TextEncoding
}
}
- var charset = DetectCharset(bytes, language);
+ var charset = DetectCharset(bytes, index, count, language);
if (!string.IsNullOrWhiteSpace(charset))
{
@@ -116,11 +129,11 @@ namespace Emby.Common.Implementations.TextEncoding
return null;
}
- private string DetectLanguage(byte[] bytes)
+ private string DetectLanguage(byte[] bytes, int index, int count)
{
try
{
- return LanguageDetector.DetectLanguage(Encoding.UTF8.GetString(bytes));
+ return LanguageDetector.DetectLanguage(Encoding.UTF8.GetString(bytes, index, count));
}
catch (NLangDetectException ex)
{
@@ -128,7 +141,7 @@ namespace Emby.Common.Implementations.TextEncoding
try
{
- return LanguageDetector.DetectLanguage(Encoding.ASCII.GetString(bytes));
+ return LanguageDetector.DetectLanguage(Encoding.ASCII.GetString(bytes, index, count));
}
catch (NLangDetectException ex)
{
@@ -136,7 +149,7 @@ namespace Emby.Common.Implementations.TextEncoding
try
{
- return LanguageDetector.DetectLanguage(Encoding.Unicode.GetString(bytes));
+ return LanguageDetector.DetectLanguage(Encoding.Unicode.GetString(bytes, index, count));
}
catch (NLangDetectException ex)
{
@@ -167,9 +180,9 @@ namespace Emby.Common.Implementations.TextEncoding
}
}
- public Encoding GetDetectedEncoding(byte[] bytes, string language, bool enableLanguageDetection)
+ public Encoding GetDetectedEncoding(byte[] bytes, int size, string language, bool enableLanguageDetection)
{
- var charset = GetDetectedEncodingName(bytes, language, enableLanguageDetection);
+ var charset = GetDetectedEncodingName(bytes, size, language, enableLanguageDetection);
return GetEncodingFromCharset(charset);
}
@@ -229,10 +242,10 @@ namespace Emby.Common.Implementations.TextEncoding
}
}
- private string DetectCharset(byte[] bytes, string language)
+ private string DetectCharset(byte[] bytes, int index, int count, string language)
{
var detector = new CharsetDetector();
- detector.Feed(bytes, 0, bytes.Length);
+ detector.Feed(bytes, index, count);
detector.DataEnd();
var charset = detector.Charset;
diff --git a/Emby.Common.Implementations/TextEncoding/TextEncodingDetect.cs b/Emby.Server.Implementations/TextEncoding/TextEncodingDetect.cs
index 1018dd24c..a0395a21b 100644
--- a/Emby.Common.Implementations/TextEncoding/TextEncodingDetect.cs
+++ b/Emby.Server.Implementations/TextEncoding/TextEncodingDetect.cs
@@ -1,9 +1,4 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading.Tasks;
-
-namespace Emby.Common.Implementations.TextEncoding
+namespace Emby.Server.Implementations.TextEncoding
{
// Copyright 2015-2016 Jonathan Bennett <jon@autoitscript.com>
//
diff --git a/Emby.Common.Implementations/TextEncoding/UniversalDetector/CharsetDetector.cs b/Emby.Server.Implementations/TextEncoding/UniversalDetector/CharsetDetector.cs
index 942fda8d1..942fda8d1 100644
--- a/Emby.Common.Implementations/TextEncoding/UniversalDetector/CharsetDetector.cs
+++ b/Emby.Server.Implementations/TextEncoding/UniversalDetector/CharsetDetector.cs
diff --git a/Emby.Common.Implementations/TextEncoding/UniversalDetector/Core/Big5Prober.cs b/Emby.Server.Implementations/TextEncoding/UniversalDetector/Core/Big5Prober.cs
index 760fca9bd..760fca9bd 100644
--- a/Emby.Common.Implementations/TextEncoding/UniversalDetector/Core/Big5Prober.cs
+++ b/Emby.Server.Implementations/TextEncoding/UniversalDetector/Core/Big5Prober.cs
diff --git a/Emby.Common.Implementations/TextEncoding/UniversalDetector/Core/BitPackage.cs b/Emby.Server.Implementations/TextEncoding/UniversalDetector/Core/BitPackage.cs
index 16483e661..16483e661 100644
--- a/Emby.Common.Implementations/TextEncoding/UniversalDetector/Core/BitPackage.cs
+++ b/Emby.Server.Implementations/TextEncoding/UniversalDetector/Core/BitPackage.cs
diff --git a/Emby.Common.Implementations/TextEncoding/UniversalDetector/Core/CharDistributionAnalyser.cs b/Emby.Server.Implementations/TextEncoding/UniversalDetector/Core/CharDistributionAnalyser.cs
index 8b5bc37d3..8b5bc37d3 100644
--- a/Emby.Common.Implementations/TextEncoding/UniversalDetector/Core/CharDistributionAnalyser.cs
+++ b/Emby.Server.Implementations/TextEncoding/UniversalDetector/Core/CharDistributionAnalyser.cs
diff --git a/Emby.Common.Implementations/TextEncoding/UniversalDetector/Core/CharsetProber.cs b/Emby.Server.Implementations/TextEncoding/UniversalDetector/Core/CharsetProber.cs
index 3369dd430..3369dd430 100644
--- a/Emby.Common.Implementations/TextEncoding/UniversalDetector/Core/CharsetProber.cs
+++ b/Emby.Server.Implementations/TextEncoding/UniversalDetector/Core/CharsetProber.cs
diff --git a/Emby.Common.Implementations/TextEncoding/UniversalDetector/Core/Charsets.cs b/Emby.Server.Implementations/TextEncoding/UniversalDetector/Core/Charsets.cs
index a7c1be92a..a7c1be92a 100644
--- a/Emby.Common.Implementations/TextEncoding/UniversalDetector/Core/Charsets.cs
+++ b/Emby.Server.Implementations/TextEncoding/UniversalDetector/Core/Charsets.cs
diff --git a/Emby.Common.Implementations/TextEncoding/UniversalDetector/Core/CodingStateMachine.cs b/Emby.Server.Implementations/TextEncoding/UniversalDetector/Core/CodingStateMachine.cs
index f837dd966..f837dd966 100644
--- a/Emby.Common.Implementations/TextEncoding/UniversalDetector/Core/CodingStateMachine.cs
+++ b/Emby.Server.Implementations/TextEncoding/UniversalDetector/Core/CodingStateMachine.cs
diff --git a/Emby.Common.Implementations/TextEncoding/UniversalDetector/Core/EUCJPProber.cs b/Emby.Server.Implementations/TextEncoding/UniversalDetector/Core/EUCJPProber.cs
index 050a9d9ce..050a9d9ce 100644
--- a/Emby.Common.Implementations/TextEncoding/UniversalDetector/Core/EUCJPProber.cs
+++ b/Emby.Server.Implementations/TextEncoding/UniversalDetector/Core/EUCJPProber.cs
diff --git a/Emby.Common.Implementations/TextEncoding/UniversalDetector/Core/EUCKRProber.cs b/Emby.Server.Implementations/TextEncoding/UniversalDetector/Core/EUCKRProber.cs
index 67d4b0a72..67d4b0a72 100644
--- a/Emby.Common.Implementations/TextEncoding/UniversalDetector/Core/EUCKRProber.cs
+++ b/Emby.Server.Implementations/TextEncoding/UniversalDetector/Core/EUCKRProber.cs
diff --git a/Emby.Common.Implementations/TextEncoding/UniversalDetector/Core/EUCTWProber.cs b/Emby.Server.Implementations/TextEncoding/UniversalDetector/Core/EUCTWProber.cs
index a4e0b486e..a4e0b486e 100644
--- a/Emby.Common.Implementations/TextEncoding/UniversalDetector/Core/EUCTWProber.cs
+++ b/Emby.Server.Implementations/TextEncoding/UniversalDetector/Core/EUCTWProber.cs
diff --git a/Emby.Common.Implementations/TextEncoding/UniversalDetector/Core/EscCharsetProber.cs b/Emby.Server.Implementations/TextEncoding/UniversalDetector/Core/EscCharsetProber.cs
index e9cefa9bc..e9cefa9bc 100644
--- a/Emby.Common.Implementations/TextEncoding/UniversalDetector/Core/EscCharsetProber.cs
+++ b/Emby.Server.Implementations/TextEncoding/UniversalDetector/Core/EscCharsetProber.cs
diff --git a/Emby.Common.Implementations/TextEncoding/UniversalDetector/Core/EscSM.cs b/Emby.Server.Implementations/TextEncoding/UniversalDetector/Core/EscSM.cs
index 61ac5545f..61ac5545f 100644
--- a/Emby.Common.Implementations/TextEncoding/UniversalDetector/Core/EscSM.cs
+++ b/Emby.Server.Implementations/TextEncoding/UniversalDetector/Core/EscSM.cs
diff --git a/Emby.Common.Implementations/TextEncoding/UniversalDetector/Core/GB18030Prober.cs b/Emby.Server.Implementations/TextEncoding/UniversalDetector/Core/GB18030Prober.cs
index ac237c5cd..ac237c5cd 100644
--- a/Emby.Common.Implementations/TextEncoding/UniversalDetector/Core/GB18030Prober.cs
+++ b/Emby.Server.Implementations/TextEncoding/UniversalDetector/Core/GB18030Prober.cs
diff --git a/Emby.Common.Implementations/TextEncoding/UniversalDetector/Core/HebrewProber.cs b/Emby.Server.Implementations/TextEncoding/UniversalDetector/Core/HebrewProber.cs
index 92974d3a8..92974d3a8 100644
--- a/Emby.Common.Implementations/TextEncoding/UniversalDetector/Core/HebrewProber.cs
+++ b/Emby.Server.Implementations/TextEncoding/UniversalDetector/Core/HebrewProber.cs
diff --git a/Emby.Common.Implementations/TextEncoding/UniversalDetector/Core/JapaneseContextAnalyser.cs b/Emby.Server.Implementations/TextEncoding/UniversalDetector/Core/JapaneseContextAnalyser.cs
index 93b9d7580..93b9d7580 100644
--- a/Emby.Common.Implementations/TextEncoding/UniversalDetector/Core/JapaneseContextAnalyser.cs
+++ b/Emby.Server.Implementations/TextEncoding/UniversalDetector/Core/JapaneseContextAnalyser.cs
diff --git a/Emby.Common.Implementations/TextEncoding/UniversalDetector/Core/LangBulgarianModel.cs b/Emby.Server.Implementations/TextEncoding/UniversalDetector/Core/LangBulgarianModel.cs
index 4b6729ed3..4b6729ed3 100644
--- a/Emby.Common.Implementations/TextEncoding/UniversalDetector/Core/LangBulgarianModel.cs
+++ b/Emby.Server.Implementations/TextEncoding/UniversalDetector/Core/LangBulgarianModel.cs
diff --git a/Emby.Common.Implementations/TextEncoding/UniversalDetector/Core/LangCyrillicModel.cs b/Emby.Server.Implementations/TextEncoding/UniversalDetector/Core/LangCyrillicModel.cs
index 5e55a4839..5e55a4839 100644
--- a/Emby.Common.Implementations/TextEncoding/UniversalDetector/Core/LangCyrillicModel.cs
+++ b/Emby.Server.Implementations/TextEncoding/UniversalDetector/Core/LangCyrillicModel.cs
diff --git a/Emby.Common.Implementations/TextEncoding/UniversalDetector/Core/LangGreekModel.cs b/Emby.Server.Implementations/TextEncoding/UniversalDetector/Core/LangGreekModel.cs
index 563ba52c2..563ba52c2 100644
--- a/Emby.Common.Implementations/TextEncoding/UniversalDetector/Core/LangGreekModel.cs
+++ b/Emby.Server.Implementations/TextEncoding/UniversalDetector/Core/LangGreekModel.cs
diff --git a/Emby.Common.Implementations/TextEncoding/UniversalDetector/Core/LangHebrewModel.cs b/Emby.Server.Implementations/TextEncoding/UniversalDetector/Core/LangHebrewModel.cs
index 030fcc598..030fcc598 100644
--- a/Emby.Common.Implementations/TextEncoding/UniversalDetector/Core/LangHebrewModel.cs
+++ b/Emby.Server.Implementations/TextEncoding/UniversalDetector/Core/LangHebrewModel.cs
diff --git a/Emby.Common.Implementations/TextEncoding/UniversalDetector/Core/LangHungarianModel.cs b/Emby.Server.Implementations/TextEncoding/UniversalDetector/Core/LangHungarianModel.cs
index d7eee2251..d7eee2251 100644
--- a/Emby.Common.Implementations/TextEncoding/UniversalDetector/Core/LangHungarianModel.cs
+++ b/Emby.Server.Implementations/TextEncoding/UniversalDetector/Core/LangHungarianModel.cs
diff --git a/Emby.Common.Implementations/TextEncoding/UniversalDetector/Core/LangThaiModel.cs b/Emby.Server.Implementations/TextEncoding/UniversalDetector/Core/LangThaiModel.cs
index bdda20f14..bdda20f14 100644
--- a/Emby.Common.Implementations/TextEncoding/UniversalDetector/Core/LangThaiModel.cs
+++ b/Emby.Server.Implementations/TextEncoding/UniversalDetector/Core/LangThaiModel.cs
diff --git a/Emby.Common.Implementations/TextEncoding/UniversalDetector/Core/Latin1Prober.cs b/Emby.Server.Implementations/TextEncoding/UniversalDetector/Core/Latin1Prober.cs
index c79a10aa7..c79a10aa7 100644
--- a/Emby.Common.Implementations/TextEncoding/UniversalDetector/Core/Latin1Prober.cs
+++ b/Emby.Server.Implementations/TextEncoding/UniversalDetector/Core/Latin1Prober.cs
diff --git a/Emby.Common.Implementations/TextEncoding/UniversalDetector/Core/MBCSGroupProber.cs b/Emby.Server.Implementations/TextEncoding/UniversalDetector/Core/MBCSGroupProber.cs
index abf49aacd..abf49aacd 100644
--- a/Emby.Common.Implementations/TextEncoding/UniversalDetector/Core/MBCSGroupProber.cs
+++ b/Emby.Server.Implementations/TextEncoding/UniversalDetector/Core/MBCSGroupProber.cs
diff --git a/Emby.Common.Implementations/TextEncoding/UniversalDetector/Core/MBCSSM.cs b/Emby.Server.Implementations/TextEncoding/UniversalDetector/Core/MBCSSM.cs
index 7aa8581bc..7aa8581bc 100644
--- a/Emby.Common.Implementations/TextEncoding/UniversalDetector/Core/MBCSSM.cs
+++ b/Emby.Server.Implementations/TextEncoding/UniversalDetector/Core/MBCSSM.cs
diff --git a/Emby.Common.Implementations/TextEncoding/UniversalDetector/Core/SBCSGroupProber.cs b/Emby.Server.Implementations/TextEncoding/UniversalDetector/Core/SBCSGroupProber.cs
index d8f496474..d8f496474 100644
--- a/Emby.Common.Implementations/TextEncoding/UniversalDetector/Core/SBCSGroupProber.cs
+++ b/Emby.Server.Implementations/TextEncoding/UniversalDetector/Core/SBCSGroupProber.cs
diff --git a/Emby.Common.Implementations/TextEncoding/UniversalDetector/Core/SBCharsetProber.cs b/Emby.Server.Implementations/TextEncoding/UniversalDetector/Core/SBCharsetProber.cs
index 5a3496075..5a3496075 100644
--- a/Emby.Common.Implementations/TextEncoding/UniversalDetector/Core/SBCharsetProber.cs
+++ b/Emby.Server.Implementations/TextEncoding/UniversalDetector/Core/SBCharsetProber.cs
diff --git a/Emby.Common.Implementations/TextEncoding/UniversalDetector/Core/SJISProber.cs b/Emby.Server.Implementations/TextEncoding/UniversalDetector/Core/SJISProber.cs
index 515cd2498..515cd2498 100644
--- a/Emby.Common.Implementations/TextEncoding/UniversalDetector/Core/SJISProber.cs
+++ b/Emby.Server.Implementations/TextEncoding/UniversalDetector/Core/SJISProber.cs
diff --git a/Emby.Common.Implementations/TextEncoding/UniversalDetector/Core/SMModel.cs b/Emby.Server.Implementations/TextEncoding/UniversalDetector/Core/SMModel.cs
index 2321ecad2..2321ecad2 100644
--- a/Emby.Common.Implementations/TextEncoding/UniversalDetector/Core/SMModel.cs
+++ b/Emby.Server.Implementations/TextEncoding/UniversalDetector/Core/SMModel.cs
diff --git a/Emby.Common.Implementations/TextEncoding/UniversalDetector/Core/SequenceModel.cs b/Emby.Server.Implementations/TextEncoding/UniversalDetector/Core/SequenceModel.cs
index 9048796b5..9048796b5 100644
--- a/Emby.Common.Implementations/TextEncoding/UniversalDetector/Core/SequenceModel.cs
+++ b/Emby.Server.Implementations/TextEncoding/UniversalDetector/Core/SequenceModel.cs
diff --git a/Emby.Common.Implementations/TextEncoding/UniversalDetector/Core/UTF8Prober.cs b/Emby.Server.Implementations/TextEncoding/UniversalDetector/Core/UTF8Prober.cs
index 084797c5e..084797c5e 100644
--- a/Emby.Common.Implementations/TextEncoding/UniversalDetector/Core/UTF8Prober.cs
+++ b/Emby.Server.Implementations/TextEncoding/UniversalDetector/Core/UTF8Prober.cs
diff --git a/Emby.Common.Implementations/TextEncoding/UniversalDetector/Core/UniversalDetector.cs b/Emby.Server.Implementations/TextEncoding/UniversalDetector/Core/UniversalDetector.cs
index 0c9a4ee60..0c9a4ee60 100644
--- a/Emby.Common.Implementations/TextEncoding/UniversalDetector/Core/UniversalDetector.cs
+++ b/Emby.Server.Implementations/TextEncoding/UniversalDetector/Core/UniversalDetector.cs
diff --git a/Emby.Common.Implementations/TextEncoding/UniversalDetector/DetectionConfidence.cs b/Emby.Server.Implementations/TextEncoding/UniversalDetector/DetectionConfidence.cs
index 6dfa55f6c..6dfa55f6c 100644
--- a/Emby.Common.Implementations/TextEncoding/UniversalDetector/DetectionConfidence.cs
+++ b/Emby.Server.Implementations/TextEncoding/UniversalDetector/DetectionConfidence.cs
diff --git a/Emby.Common.Implementations/TextEncoding/UniversalDetector/ICharsetDetector.cs b/Emby.Server.Implementations/TextEncoding/UniversalDetector/ICharsetDetector.cs
index c0c35a59e..c0c35a59e 100644
--- a/Emby.Common.Implementations/TextEncoding/UniversalDetector/ICharsetDetector.cs
+++ b/Emby.Server.Implementations/TextEncoding/UniversalDetector/ICharsetDetector.cs
diff --git a/Emby.Common.Implementations/Threading/CommonTimer.cs b/Emby.Server.Implementations/Threading/CommonTimer.cs
index 8895f6798..bb67325d1 100644
--- a/Emby.Common.Implementations/Threading/CommonTimer.cs
+++ b/Emby.Server.Implementations/Threading/CommonTimer.cs
@@ -1,11 +1,8 @@
using System;
-using System.Collections.Generic;
-using System.Linq;
using System.Threading;
-using System.Threading.Tasks;
using MediaBrowser.Model.Threading;
-namespace Emby.Common.Implementations.Threading
+namespace Emby.Server.Implementations.Threading
{
public class CommonTimer : ITimer
{
@@ -34,6 +31,7 @@ namespace Emby.Common.Implementations.Threading
public void Dispose()
{
_timer.Dispose();
+ GC.SuppressFinalize(this);
}
}
}
diff --git a/Emby.Common.Implementations/Threading/TimerFactory.cs b/Emby.Server.Implementations/Threading/TimerFactory.cs
index 028dd0963..4ab6f6fc4 100644
--- a/Emby.Common.Implementations/Threading/TimerFactory.cs
+++ b/Emby.Server.Implementations/Threading/TimerFactory.cs
@@ -1,10 +1,7 @@
using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading.Tasks;
using MediaBrowser.Model.Threading;
-namespace Emby.Common.Implementations.Threading
+namespace Emby.Server.Implementations.Threading
{
public class TimerFactory : ITimerFactory
{
diff --git a/Emby.Server.Implementations/Updates/InstallationManager.cs b/Emby.Server.Implementations/Updates/InstallationManager.cs
index 6e37c1dc1..180463040 100644
--- a/Emby.Server.Implementations/Updates/InstallationManager.cs
+++ b/Emby.Server.Implementations/Updates/InstallationManager.cs
@@ -122,7 +122,10 @@ namespace Emby.Server.Implementations.Updates
private readonly ICryptoProvider _cryptographyProvider;
- public InstallationManager(ILogger logger, IApplicationHost appHost, IApplicationPaths appPaths, IHttpClient httpClient, IJsonSerializer jsonSerializer, ISecurityManager securityManager, IConfigurationManager config, IFileSystem fileSystem, ICryptoProvider cryptographyProvider)
+ // netframework or netcore
+ private readonly string _packageRuntime;
+
+ public InstallationManager(ILogger logger, IApplicationHost appHost, IApplicationPaths appPaths, IHttpClient httpClient, IJsonSerializer jsonSerializer, ISecurityManager securityManager, IConfigurationManager config, IFileSystem fileSystem, ICryptoProvider cryptographyProvider, string packageRuntime)
{
if (logger == null)
{
@@ -140,6 +143,7 @@ namespace Emby.Server.Implementations.Updates
_config = config;
_fileSystem = fileSystem;
_cryptographyProvider = cryptographyProvider;
+ _packageRuntime = packageRuntime;
_logger = logger;
}
@@ -157,7 +161,7 @@ namespace Emby.Server.Implementations.Updates
/// Gets all available packages.
/// </summary>
/// <returns>Task{List{PackageInfo}}.</returns>
- public async Task<IEnumerable<PackageInfo>> GetAvailablePackages(CancellationToken cancellationToken,
+ public async Task<List<PackageInfo>> GetAvailablePackages(CancellationToken cancellationToken,
bool withRegistration = true,
string packageType = null,
Version applicationVersion = null)
@@ -171,11 +175,11 @@ namespace Emby.Server.Implementations.Updates
{ "systemid", _applicationHost.SystemId }
};
- using (var json = await _httpClient.Post("https://www.mb3admin.com/admin/service/package/retrieveall", data, cancellationToken).ConfigureAwait(false))
+ using (var json = await _httpClient.Post("https://www.mb3admin.com/admin/service/package/retrieveall?includeAllRuntimes=true", data, cancellationToken).ConfigureAwait(false))
{
cancellationToken.ThrowIfCancellationRequested();
- var packages = _jsonSerializer.DeserializeFromStream<List<PackageInfo>>(json).ToList();
+ var packages = _jsonSerializer.DeserializeFromStream<PackageInfo[]>(json);
return FilterPackages(packages, packageType, applicationVersion);
}
@@ -184,7 +188,7 @@ namespace Emby.Server.Implementations.Updates
{
var packages = await GetAvailablePackagesWithoutRegistrationInfo(cancellationToken).ConfigureAwait(false);
- return FilterPackages(packages.ToList(), packageType, applicationVersion);
+ return FilterPackages(packages, packageType, applicationVersion);
}
}
@@ -195,21 +199,21 @@ namespace Emby.Server.Implementations.Updates
/// </summary>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task{List{PackageInfo}}.</returns>
- public async Task<IEnumerable<PackageInfo>> GetAvailablePackagesWithoutRegistrationInfo(CancellationToken cancellationToken)
+ public async Task<List<PackageInfo>> GetAvailablePackagesWithoutRegistrationInfo(CancellationToken cancellationToken)
{
_logger.Info("Opening {0}", PackageCachePath);
try
{
using (var stream = _fileSystem.OpenRead(PackageCachePath))
{
- var packages = _jsonSerializer.DeserializeFromStream<List<PackageInfo>>(stream).ToList();
+ var packages = _jsonSerializer.DeserializeFromStream<PackageInfo[]>(stream);
if (DateTime.UtcNow - _lastPackageUpdateTime > GetCacheLength())
{
UpdateCachedPackages(CancellationToken.None, false);
}
- return packages;
+ return FilterPackages(packages);
}
}
catch (Exception)
@@ -221,7 +225,7 @@ namespace Emby.Server.Implementations.Updates
await UpdateCachedPackages(cancellationToken, true).ConfigureAwait(false);
using (var stream = _fileSystem.OpenRead(PackageCachePath))
{
- return _jsonSerializer.DeserializeFromStream<List<PackageInfo>>(stream).ToList();
+ return FilterPackages(_jsonSerializer.DeserializeFromStream<PackageInfo[]>(stream));
}
}
@@ -244,7 +248,7 @@ namespace Emby.Server.Implementations.Updates
var tempFile = await _httpClient.GetTempFile(new HttpRequestOptions
{
- Url = "https://www.mb3admin.com/admin/service/MB3Packages.json",
+ Url = "https://www.mb3admin.com/admin/service/EmbyPackages.json",
CancellationToken = cancellationToken,
Progress = new SimpleProgress<Double>()
@@ -277,57 +281,77 @@ namespace Emby.Server.Implementations.Updates
private TimeSpan GetCacheLength()
{
- switch (GetSystemUpdateLevel())
- {
- case PackageVersionClass.Beta:
- return TimeSpan.FromMinutes(30);
- case PackageVersionClass.Dev:
- return TimeSpan.FromMinutes(3);
- default:
- return TimeSpan.FromHours(24);
- }
+ return TimeSpan.FromMinutes(3);
}
- protected IEnumerable<PackageInfo> FilterPackages(List<PackageInfo> packages)
+ protected List<PackageInfo> FilterPackages(IEnumerable<PackageInfo> packages)
{
+ var list = new List<PackageInfo>();
+
foreach (var package in packages)
{
- package.versions = package.versions.Where(v => !string.IsNullOrWhiteSpace(v.sourceUrl))
- .OrderByDescending(GetPackageVersion).ToList();
+ var versions = new List<PackageVersionInfo>();
+ foreach (var version in package.versions)
+ {
+ if (string.IsNullOrWhiteSpace(version.sourceUrl))
+ {
+ continue;
+ }
+
+ if (string.IsNullOrWhiteSpace(version.runtimes) || version.runtimes.IndexOf(_packageRuntime, StringComparison.OrdinalIgnoreCase) == -1)
+ {
+ continue;
+ }
+
+ versions.Add(version);
+ }
+
+ package.versions = versions
+ .OrderByDescending(GetPackageVersion)
+ .ToArray();
+
+ if (package.versions.Length == 0)
+ {
+ continue;
+ }
+
+ list.Add(package);
}
// Remove packages with no versions
- packages = packages.Where(p => p.versions.Any()).ToList();
-
- return packages;
+ return list;
}
- protected IEnumerable<PackageInfo> FilterPackages(List<PackageInfo> packages, string packageType, Version applicationVersion)
+ protected List<PackageInfo> FilterPackages(IEnumerable<PackageInfo> packages, string packageType, Version applicationVersion)
{
- foreach (var package in packages)
- {
- package.versions = package.versions.Where(v => !string.IsNullOrWhiteSpace(v.sourceUrl))
- .OrderByDescending(GetPackageVersion).ToList();
- }
+ var packagesList = FilterPackages(packages);
- if (!string.IsNullOrWhiteSpace(packageType))
- {
- packages = packages.Where(p => string.Equals(p.type, packageType, StringComparison.OrdinalIgnoreCase)).ToList();
- }
+ var returnList = new List<PackageInfo>();
- // If an app version was supplied, filter the versions for each package to only include supported versions
- if (applicationVersion != null)
+ var filterOnPackageType = !string.IsNullOrWhiteSpace(packageType);
+
+ foreach (var p in packagesList)
{
- foreach (var package in packages)
+ if (filterOnPackageType && !string.Equals(p.type, packageType, StringComparison.OrdinalIgnoreCase))
{
- package.versions = package.versions.Where(v => IsPackageVersionUpToDate(v, applicationVersion)).ToList();
+ continue;
}
- }
- // Remove packages with no versions
- packages = packages.Where(p => p.versions.Any()).ToList();
+ // If an app version was supplied, filter the versions for each package to only include supported versions
+ if (applicationVersion != null)
+ {
+ p.versions = p.versions.Where(v => IsPackageVersionUpToDate(v, applicationVersion)).ToArray();
+ }
- return packages;
+ if (p.versions.Length == 0)
+ {
+ continue;
+ }
+
+ returnList.Add(p);
+ }
+
+ return returnList;
}
/// <summary>
@@ -418,30 +442,24 @@ namespace Emby.Server.Implementations.Updates
/// <returns>Task{IEnumerable{PackageVersionInfo}}.</returns>
public async Task<IEnumerable<PackageVersionInfo>> GetAvailablePluginUpdates(Version applicationVersion, bool withAutoUpdateEnabled, CancellationToken cancellationToken)
{
- var catalog = await GetAvailablePackagesWithoutRegistrationInfo(cancellationToken).ConfigureAwait(false);
-
- var plugins = _applicationHost.Plugins.ToList();
-
- if (withAutoUpdateEnabled)
+ if (!_config.CommonConfiguration.EnableAutoUpdate)
{
- plugins = plugins
- .Where(p => _config.CommonConfiguration.EnableAutoUpdate)
- .ToList();
+ return new PackageVersionInfo[] { };
}
+ var catalog = await GetAvailablePackagesWithoutRegistrationInfo(cancellationToken).ConfigureAwait(false);
+
var systemUpdateLevel = GetSystemUpdateLevel();
// Figure out what needs to be installed
- var packages = plugins.Select(p =>
+ return _applicationHost.Plugins.Select(p =>
{
var latestPluginInfo = GetLatestCompatibleVersion(catalog, p.Name, p.Id.ToString(), applicationVersion, systemUpdateLevel);
return latestPluginInfo != null && GetPackageVersion(latestPluginInfo) > p.Version ? latestPluginInfo : null;
- }).Where(i => i != null).ToList();
-
- return packages
- .Where(p => !string.IsNullOrWhiteSpace(p.sourceUrl) && !CompletedInstallations.Any(i => string.Equals(i.AssemblyGuid, p.guid, StringComparison.OrdinalIgnoreCase)));
+ }).Where(i => i != null)
+ .Where(p => !string.IsNullOrWhiteSpace(p.sourceUrl) && !CompletedInstallations.Any(i => string.Equals(i.AssemblyGuid, p.guid, StringComparison.OrdinalIgnoreCase)));
}
/// <summary>
@@ -704,6 +722,7 @@ namespace Emby.Server.Implementations.Updates
public void Dispose()
{
Dispose(true);
+ GC.SuppressFinalize(this);
}
}
}
diff --git a/Emby.Server.Implementations/UserViews/CollectionFolderImageProvider.cs b/Emby.Server.Implementations/UserViews/CollectionFolderImageProvider.cs
index f54613384..fa1d5b74e 100644
--- a/Emby.Server.Implementations/UserViews/CollectionFolderImageProvider.cs
+++ b/Emby.Server.Implementations/UserViews/CollectionFolderImageProvider.cs
@@ -28,7 +28,7 @@ namespace Emby.Server.Implementations.UserViews
{
}
- public override IEnumerable<ImageType> GetSupportedImages(IHasImages item)
+ public override IEnumerable<ImageType> GetSupportedImages(IHasMetadata item)
{
return new List<ImageType>
{
@@ -36,13 +36,13 @@ namespace Emby.Server.Implementations.UserViews
};
}
- protected override List<BaseItem> GetItemsWithImages(IHasImages item)
+ protected override List<BaseItem> GetItemsWithImages(IHasMetadata item)
{
var view = (CollectionFolder)item;
var recursive = !new[] { CollectionType.Playlists, CollectionType.Channels }.Contains(view.CollectionType ?? string.Empty, StringComparer.OrdinalIgnoreCase);
- var result = view.GetItems(new InternalItemsQuery
+ var result = view.GetItemList(new InternalItemsQuery
{
CollapseBoxSetItems = false,
Recursive = recursive,
@@ -51,7 +51,7 @@ namespace Emby.Server.Implementations.UserViews
});
- var items = result.Items.Select(i =>
+ var items = result.Select(i =>
{
var episode = i as Episode;
if (episode != null)
@@ -91,15 +91,15 @@ namespace Emby.Server.Implementations.UserViews
}).DistinctBy(i => i.Id);
- return GetFinalItems(items.Where(i => i.HasImage(ImageType.Primary) || i.HasImage(ImageType.Thumb)).ToList(), 8);
+ return GetFinalItems(items.Where(i => i.HasImage(ImageType.Primary) || i.HasImage(ImageType.Thumb)), 8);
}
- protected override bool Supports(IHasImages item)
+ protected override bool Supports(IHasMetadata item)
{
return item is CollectionFolder;
}
- protected override string CreateImage(IHasImages item, List<BaseItem> itemsWithImages, string outputPathWithoutExtension, ImageType imageType, int imageIndex)
+ protected override string CreateImage(IHasMetadata item, List<BaseItem> itemsWithImages, string outputPathWithoutExtension, ImageType imageType, int imageIndex)
{
var outputPath = Path.ChangeExtension(outputPathWithoutExtension, ".png");
@@ -126,7 +126,7 @@ namespace Emby.Server.Implementations.UserViews
_libraryManager = libraryManager;
}
- public override IEnumerable<ImageType> GetSupportedImages(IHasImages item)
+ public override IEnumerable<ImageType> GetSupportedImages(IHasMetadata item)
{
return new List<ImageType>
{
@@ -134,7 +134,7 @@ namespace Emby.Server.Implementations.UserViews
};
}
- protected override List<BaseItem> GetItemsWithImages(IHasImages item)
+ protected override List<BaseItem> GetItemsWithImages(IHasMetadata item)
{
var view = (ManualCollectionsFolder)item;
@@ -145,19 +145,19 @@ namespace Emby.Server.Implementations.UserViews
Recursive = recursive,
IncludeItemTypes = new[] { typeof(BoxSet).Name },
Limit = 20,
- SortBy = new[] { ItemSortBy.Random },
+ OrderBy = new [] { new Tuple<string, SortOrder>(ItemSortBy.Random, SortOrder.Ascending) },
DtoOptions = new DtoOptions(false)
});
- return GetFinalItems(items.Where(i => i.HasImage(ImageType.Primary) || i.HasImage(ImageType.Thumb)).ToList(), 8);
+ return GetFinalItems(items.Where(i => i.HasImage(ImageType.Primary) || i.HasImage(ImageType.Thumb)), 8);
}
- protected override bool Supports(IHasImages item)
+ protected override bool Supports(IHasMetadata item)
{
return item is ManualCollectionsFolder;
}
- protected override string CreateImage(IHasImages item, List<BaseItem> itemsWithImages, string outputPathWithoutExtension, ImageType imageType, int imageIndex)
+ protected override string CreateImage(IHasMetadata item, List<BaseItem> itemsWithImages, string outputPathWithoutExtension, ImageType imageType, int imageIndex)
{
var outputPath = Path.ChangeExtension(outputPathWithoutExtension, ".png");
diff --git a/Emby.Server.Implementations/UserViews/DynamicImageProvider.cs b/Emby.Server.Implementations/UserViews/DynamicImageProvider.cs
index cd2c4728f..885dfec58 100644
--- a/Emby.Server.Implementations/UserViews/DynamicImageProvider.cs
+++ b/Emby.Server.Implementations/UserViews/DynamicImageProvider.cs
@@ -31,7 +31,7 @@ namespace Emby.Server.Implementations.UserViews
_libraryManager = libraryManager;
}
- public override IEnumerable<ImageType> GetSupportedImages(IHasImages item)
+ public override IEnumerable<ImageType> GetSupportedImages(IHasMetadata item)
{
var view = (UserView)item;
if (IsUsingCollectionStrip(view))
@@ -48,7 +48,7 @@ namespace Emby.Server.Implementations.UserViews
};
}
- protected override List<BaseItem> GetItemsWithImages(IHasImages item)
+ protected override List<BaseItem> GetItemsWithImages(IHasMetadata item)
{
var view = (UserView)item;
@@ -62,27 +62,27 @@ namespace Emby.Server.Implementations.UserViews
IsMovie = true,
DtoOptions = new DtoOptions(false)
- }).ToList();
+ });
- return GetFinalItems(programs).ToList();
+ return GetFinalItems(programs);
}
if (string.Equals(view.ViewType, SpecialFolder.MovieGenre, StringComparison.OrdinalIgnoreCase) ||
string.Equals(view.ViewType, SpecialFolder.TvGenre, StringComparison.OrdinalIgnoreCase))
{
- var userItemsResult = view.GetItems(new InternalItemsQuery
+ var userItemsResult = view.GetItemList(new InternalItemsQuery
{
CollapseBoxSetItems = false,
DtoOptions = new DtoOptions(false)
});
- return userItemsResult.Items.ToList();
+ return userItemsResult.ToList();
}
var isUsingCollectionStrip = IsUsingCollectionStrip(view);
var recursive = isUsingCollectionStrip && !new[] { CollectionType.Channels, CollectionType.BoxSets, CollectionType.Playlists }.Contains(view.ViewType ?? string.Empty, StringComparer.OrdinalIgnoreCase);
- var result = view.GetItems(new InternalItemsQuery
+ var result = view.GetItemList(new InternalItemsQuery
{
User = view.UserId.HasValue ? _userManager.GetUserById(view.UserId.Value) : null,
CollapseBoxSetItems = false,
@@ -91,7 +91,7 @@ namespace Emby.Server.Implementations.UserViews
DtoOptions = new DtoOptions(false)
});
- var items = result.Items.Select(i =>
+ var items = result.Select(i =>
{
var episode = i as Episode;
if (episode != null)
@@ -133,13 +133,13 @@ namespace Emby.Server.Implementations.UserViews
if (isUsingCollectionStrip)
{
- return GetFinalItems(items.Where(i => i.HasImage(ImageType.Primary) || i.HasImage(ImageType.Thumb)).ToList(), 8);
+ return GetFinalItems(items.Where(i => i.HasImage(ImageType.Primary) || i.HasImage(ImageType.Thumb)), 8);
}
- return GetFinalItems(items.Where(i => i.HasImage(ImageType.Primary)).ToList());
+ return GetFinalItems(items.Where(i => i.HasImage(ImageType.Primary)));
}
- protected override bool Supports(IHasImages item)
+ protected override bool Supports(IHasMetadata item)
{
var view = item as UserView;
if (view != null)
@@ -163,7 +163,7 @@ namespace Emby.Server.Implementations.UserViews
return collectionStripViewTypes.Contains(view.ViewType ?? string.Empty);
}
- protected override string CreateImage(IHasImages item, List<BaseItem> itemsWithImages, string outputPathWithoutExtension, ImageType imageType, int imageIndex)
+ protected override string CreateImage(IHasMetadata item, List<BaseItem> itemsWithImages, string outputPathWithoutExtension, ImageType imageType, int imageIndex)
{
if (itemsWithImages.Count == 0)
{
diff --git a/Emby.Common.Implementations/Xml/XmlReaderSettingsFactory.cs b/Emby.Server.Implementations/Xml/XmlReaderSettingsFactory.cs
index 35c266cdb..0f4e8af3c 100644
--- a/Emby.Common.Implementations/Xml/XmlReaderSettingsFactory.cs
+++ b/Emby.Server.Implementations/Xml/XmlReaderSettingsFactory.cs
@@ -1,7 +1,7 @@
using System.Xml;
using MediaBrowser.Model.Xml;
-namespace Emby.Common.Implementations.Xml
+namespace Emby.Server.Implementations.Xml
{
public class XmlReaderSettingsFactory : IXmlReaderSettingsFactory
{
diff --git a/Emby.Server.Implementations/packages.config b/Emby.Server.Implementations/packages.config
index 03336c936..5b869221a 100644
--- a/Emby.Server.Implementations/packages.config
+++ b/Emby.Server.Implementations/packages.config
@@ -1,7 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
- <package id="Emby.XmlTv" version="1.0.9" targetFramework="net46" />
- <package id="MediaBrowser.Naming" version="1.0.5" targetFramework="portable45-net45+win8" />
+ <package id="Emby.XmlTv" version="1.0.10" targetFramework="net46" />
+ <package id="MediaBrowser.Naming" version="1.0.7" targetFramework="net46" />
+ <package id="ServiceStack.Text" version="4.5.8" targetFramework="net46" />
+ <package id="SharpCompress" version="0.14.0" targetFramework="net46" />
+ <package id="SimpleInjector" version="4.0.8" targetFramework="net46" />
<package id="SQLitePCL.pretty" version="1.1.0" targetFramework="portable45-net45+win8" />
- <package id="SQLitePCLRaw.core" version="1.1.7" targetFramework="net46" />
+ <package id="SQLitePCLRaw.core" version="1.1.8" targetFramework="net46" />
</packages> \ No newline at end of file
diff --git a/MediaBrowser.Api/ApiEntryPoint.cs b/MediaBrowser.Api/ApiEntryPoint.cs
index 34d0bd413..04cef60bf 100644
--- a/MediaBrowser.Api/ApiEntryPoint.cs
+++ b/MediaBrowser.Api/ApiEntryPoint.cs
@@ -1,27 +1,15 @@
-using MediaBrowser.Api.Playback;
-using MediaBrowser.Common.Configuration;
+using System;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Library;
+using MediaBrowser.Controller.Net;
using MediaBrowser.Controller.Plugins;
using MediaBrowser.Controller.Session;
-using MediaBrowser.Model.Configuration;
-using MediaBrowser.Model.Logging;
-using MediaBrowser.Model.Session;
-using System;
-using System.Collections.Concurrent;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.IO;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-
-using MediaBrowser.Controller.MediaEncoding;
-using MediaBrowser.Controller.Net;
using MediaBrowser.Model.Diagnostics;
using MediaBrowser.Model.IO;
-using MediaBrowser.Model.Dto;
+using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Threading;
+using System.Collections.Generic;
+using System.Threading;
namespace MediaBrowser.Api
{
@@ -53,11 +41,6 @@ namespace MediaBrowser.Api
public readonly ITimerFactory TimerFactory;
public readonly IProcessFactory ProcessFactory;
- /// <summary>
- /// The active transcoding jobs
- /// </summary>
- private readonly List<TranscodingJob> _activeTranscodingJobs = new List<TranscodingJob>();
-
private readonly Dictionary<string, SemaphoreSlim> _transcodingLocks =
new Dictionary<string, SemaphoreSlim>();
@@ -81,742 +64,31 @@ namespace MediaBrowser.Api
ResultFactory = resultFactory;
Instance = this;
- _sessionManager.PlaybackProgress += _sessionManager_PlaybackProgress;
- _sessionManager.PlaybackStart += _sessionManager_PlaybackStart;
}
- public SemaphoreSlim GetTranscodingLock(string outputPath)
+ public static string[] Split(string value, char separator, bool removeEmpty)
{
- lock (_transcodingLocks)
+ if (string.IsNullOrWhiteSpace(value))
{
- SemaphoreSlim result;
- if (!_transcodingLocks.TryGetValue(outputPath, out result))
- {
- result = new SemaphoreSlim(1, 1);
- _transcodingLocks[outputPath] = result;
- }
-
- return result;
+ return new string[] { };
}
- }
- private void _sessionManager_PlaybackStart(object sender, PlaybackProgressEventArgs e)
- {
- if (!string.IsNullOrWhiteSpace(e.PlaySessionId))
+ if (removeEmpty)
{
- PingTranscodingJob(e.PlaySessionId, e.IsPaused);
+ return value.Split(new[] { separator }, StringSplitOptions.RemoveEmptyEntries);
}
- }
- void _sessionManager_PlaybackProgress(object sender, PlaybackProgressEventArgs e)
- {
- if (!string.IsNullOrWhiteSpace(e.PlaySessionId))
- {
- PingTranscodingJob(e.PlaySessionId, e.IsPaused);
- }
+ return value.Split(separator);
}
- /// <summary>
- /// Runs this instance.
- /// </summary>
public void Run()
{
- try
- {
- DeleteEncodedMediaCache();
- }
- catch (FileNotFoundException)
- {
- // Don't clutter the log
- }
- catch (IOException)
- {
- // Don't clutter the log
- }
- catch (Exception ex)
- {
- Logger.ErrorException("Error deleting encoded media cache", ex);
- }
- }
-
- public EncodingOptions GetEncodingOptions()
- {
- return _config.GetConfiguration<EncodingOptions>("encoding");
- }
-
- /// <summary>
- /// Deletes the encoded media cache.
- /// </summary>
- private void DeleteEncodedMediaCache()
- {
- var path = _config.ApplicationPaths.TranscodingTempPath;
-
- foreach (var file in _fileSystem.GetFilePaths(path, true)
- .ToList())
- {
- _fileSystem.DeleteFile(file);
- }
+
}
- /// <summary>
- /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
- /// </summary>
public void Dispose()
{
- Dispose(true);
GC.SuppressFinalize(this);
}
-
- /// <summary>
- /// Releases unmanaged and - optionally - managed resources.
- /// </summary>
- /// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
- protected virtual void Dispose(bool dispose)
- {
- var list = _activeTranscodingJobs.ToList();
- var jobCount = list.Count;
-
- Parallel.ForEach(list, j => KillTranscodingJob(j, false, path => true));
-
- // Try to allow for some time to kill the ffmpeg processes and delete the partial stream files
- if (jobCount > 0)
- {
- var task = Task.Delay(1000);
- Task.WaitAll(task);
- }
- }
-
- /// <summary>
- /// Called when [transcode beginning].
- /// </summary>
- /// <param name="path">The path.</param>
- /// <param name="playSessionId">The play session identifier.</param>
- /// <param name="liveStreamId">The live stream identifier.</param>
- /// <param name="transcodingJobId">The transcoding job identifier.</param>
- /// <param name="type">The type.</param>
- /// <param name="process">The process.</param>
- /// <param name="deviceId">The device id.</param>
- /// <param name="state">The state.</param>
- /// <param name="cancellationTokenSource">The cancellation token source.</param>
- /// <returns>TranscodingJob.</returns>
- public TranscodingJob OnTranscodeBeginning(string path,
- string playSessionId,
- string liveStreamId,
- string transcodingJobId,
- TranscodingJobType type,
- IProcess process,
- string deviceId,
- StreamState state,
- CancellationTokenSource cancellationTokenSource)
- {
- lock (_activeTranscodingJobs)
- {
- var job = new TranscodingJob(Logger, TimerFactory)
- {
- Type = type,
- Path = path,
- Process = process,
- ActiveRequestCount = 1,
- DeviceId = deviceId,
- CancellationTokenSource = cancellationTokenSource,
- Id = transcodingJobId,
- PlaySessionId = playSessionId,
- LiveStreamId = liveStreamId,
- MediaSource = state.MediaSource
- };
-
- _activeTranscodingJobs.Add(job);
-
- ReportTranscodingProgress(job, state, null, null, null, null, null);
-
- return job;
- }
- }
-
- public void ReportTranscodingProgress(TranscodingJob job, StreamState state, TimeSpan? transcodingPosition, float? framerate, double? percentComplete, long? bytesTranscoded, int? bitRate)
- {
- var ticks = transcodingPosition.HasValue ? transcodingPosition.Value.Ticks : (long?)null;
-
- if (job != null)
- {
- job.Framerate = framerate;
- job.CompletionPercentage = percentComplete;
- job.TranscodingPositionTicks = ticks;
- job.BytesTranscoded = bytesTranscoded;
- job.BitRate = bitRate;
- }
-
- var deviceId = state.Request.DeviceId;
-
- if (!string.IsNullOrWhiteSpace(deviceId))
- {
- var audioCodec = state.ActualOutputAudioCodec;
- var videoCodec = state.ActualOutputVideoCodec;
-
- _sessionManager.ReportTranscodingInfo(deviceId, new TranscodingInfo
- {
- Bitrate = bitRate ?? state.TotalOutputBitrate,
- AudioCodec = audioCodec,
- VideoCodec = videoCodec,
- Container = state.OutputContainer,
- Framerate = framerate,
- CompletionPercentage = percentComplete,
- Width = state.OutputWidth,
- Height = state.OutputHeight,
- AudioChannels = state.OutputAudioChannels,
- IsAudioDirect = string.Equals(state.OutputAudioCodec, "copy", StringComparison.OrdinalIgnoreCase),
- IsVideoDirect = string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase),
- TranscodeReasons = state.TranscodeReasons
- });
- }
- }
-
- /// <summary>
- /// <summary>
- /// The progressive
- /// </summary>
- /// Called when [transcode failed to start].
- /// </summary>
- /// <param name="path">The path.</param>
- /// <param name="type">The type.</param>
- /// <param name="state">The state.</param>
- public void OnTranscodeFailedToStart(string path, TranscodingJobType type, StreamState state)
- {
- lock (_activeTranscodingJobs)
- {
- var job = _activeTranscodingJobs.FirstOrDefault(j => j.Type == type && string.Equals(j.Path, path, StringComparison.OrdinalIgnoreCase));
-
- if (job != null)
- {
- _activeTranscodingJobs.Remove(job);
- }
- }
-
- lock (_transcodingLocks)
- {
- _transcodingLocks.Remove(path);
- }
-
- if (!string.IsNullOrWhiteSpace(state.Request.DeviceId))
- {
- _sessionManager.ClearTranscodingInfo(state.Request.DeviceId);
- }
- }
-
- /// <summary>
- /// Determines whether [has active transcoding job] [the specified path].
- /// </summary>
- /// <param name="path">The path.</param>
- /// <param name="type">The type.</param>
- /// <returns><c>true</c> if [has active transcoding job] [the specified path]; otherwise, <c>false</c>.</returns>
- public bool HasActiveTranscodingJob(string path, TranscodingJobType type)
- {
- return GetTranscodingJob(path, type) != null;
- }
-
- public TranscodingJob GetTranscodingJob(string path, TranscodingJobType type)
- {
- lock (_activeTranscodingJobs)
- {
- return _activeTranscodingJobs.FirstOrDefault(j => j.Type == type && string.Equals(j.Path, path, StringComparison.OrdinalIgnoreCase));
- }
- }
-
- public TranscodingJob GetTranscodingJob(string playSessionId)
- {
- lock (_activeTranscodingJobs)
- {
- return _activeTranscodingJobs.FirstOrDefault(j => string.Equals(j.PlaySessionId, playSessionId, StringComparison.OrdinalIgnoreCase));
- }
- }
-
- /// <summary>
- /// Called when [transcode begin request].
- /// </summary>
- /// <param name="path">The path.</param>
- /// <param name="type">The type.</param>
- public TranscodingJob OnTranscodeBeginRequest(string path, TranscodingJobType type)
- {
- lock (_activeTranscodingJobs)
- {
- var job = _activeTranscodingJobs.FirstOrDefault(j => j.Type == type && string.Equals(j.Path, path, StringComparison.OrdinalIgnoreCase));
-
- if (job == null)
- {
- return null;
- }
-
- OnTranscodeBeginRequest(job);
-
- return job;
- }
- }
-
- public void OnTranscodeBeginRequest(TranscodingJob job)
- {
- job.ActiveRequestCount++;
-
- if (string.IsNullOrWhiteSpace(job.PlaySessionId) || job.Type == TranscodingJobType.Progressive)
- {
- job.StopKillTimer();
- }
- }
-
- public void OnTranscodeEndRequest(TranscodingJob job)
- {
- job.ActiveRequestCount--;
- //Logger.Debug("OnTranscodeEndRequest job.ActiveRequestCount={0}", job.ActiveRequestCount);
- if (job.ActiveRequestCount <= 0)
- {
- PingTimer(job, false);
- }
- }
- internal void PingTranscodingJob(string playSessionId, bool? isUserPaused)
- {
- if (string.IsNullOrEmpty(playSessionId))
- {
- throw new ArgumentNullException("playSessionId");
- }
-
- //Logger.Debug("PingTranscodingJob PlaySessionId={0} isUsedPaused: {1}", playSessionId, isUserPaused);
-
- List<TranscodingJob> jobs;
-
- lock (_activeTranscodingJobs)
- {
- // This is really only needed for HLS.
- // Progressive streams can stop on their own reliably
- jobs = _activeTranscodingJobs.Where(j => string.Equals(playSessionId, j.PlaySessionId, StringComparison.OrdinalIgnoreCase)).ToList();
- }
-
- foreach (var job in jobs)
- {
- if (isUserPaused.HasValue)
- {
- //Logger.Debug("Setting job.IsUserPaused to {0}. jobId: {1}", isUserPaused, job.Id);
- job.IsUserPaused = isUserPaused.Value;
- }
- PingTimer(job, true);
- }
- }
-
- private void PingTimer(TranscodingJob job, bool isProgressCheckIn)
- {
- if (job.HasExited)
- {
- job.StopKillTimer();
- return;
- }
-
- var timerDuration = 10000;
-
- if (job.Type != TranscodingJobType.Progressive)
- {
- timerDuration = 60000;
- }
-
- job.PingTimeout = timerDuration;
- job.LastPingDate = DateTime.UtcNow;
-
- // Don't start the timer for playback checkins with progressive streaming
- if (job.Type != TranscodingJobType.Progressive || !isProgressCheckIn)
- {
- job.StartKillTimer(OnTranscodeKillTimerStopped);
- }
- else
- {
- job.ChangeKillTimerIfStarted();
- }
- }
-
- /// <summary>
- /// Called when [transcode kill timer stopped].
- /// </summary>
- /// <param name="state">The state.</param>
- private void OnTranscodeKillTimerStopped(object state)
- {
- var job = (TranscodingJob)state;
-
- if (!job.HasExited && job.Type != TranscodingJobType.Progressive)
- {
- var timeSinceLastPing = (DateTime.UtcNow - job.LastPingDate).TotalMilliseconds;
-
- if (timeSinceLastPing < job.PingTimeout)
- {
- job.StartKillTimer(OnTranscodeKillTimerStopped, job.PingTimeout);
- return;
- }
- }
-
- Logger.Info("Transcoding kill timer stopped for JobId {0} PlaySessionId {1}. Killing transcoding", job.Id, job.PlaySessionId);
-
- KillTranscodingJob(job, true, path => true);
- }
-
- /// <summary>
- /// Kills the single transcoding job.
- /// </summary>
- /// <param name="deviceId">The device id.</param>
- /// <param name="playSessionId">The play session identifier.</param>
- /// <param name="deleteFiles">The delete files.</param>
- /// <returns>Task.</returns>
- internal void KillTranscodingJobs(string deviceId, string playSessionId, Func<string, bool> deleteFiles)
- {
- KillTranscodingJobs(j =>
- {
- if (!string.IsNullOrWhiteSpace(playSessionId))
- {
- return string.Equals(playSessionId, j.PlaySessionId, StringComparison.OrdinalIgnoreCase);
- }
-
- return string.Equals(deviceId, j.DeviceId, StringComparison.OrdinalIgnoreCase);
-
- }, deleteFiles);
- }
-
- /// <summary>
- /// Kills the transcoding jobs.
- /// </summary>
- /// <param name="killJob">The kill job.</param>
- /// <param name="deleteFiles">The delete files.</param>
- /// <returns>Task.</returns>
- private void KillTranscodingJobs(Func<TranscodingJob, bool> killJob, Func<string, bool> deleteFiles)
- {
- var jobs = new List<TranscodingJob>();
-
- lock (_activeTranscodingJobs)
- {
- // This is really only needed for HLS.
- // Progressive streams can stop on their own reliably
- jobs.AddRange(_activeTranscodingJobs.Where(killJob));
- }
-
- if (jobs.Count == 0)
- {
- return;
- }
-
- foreach (var job in jobs)
- {
- KillTranscodingJob(job, false, deleteFiles);
- }
- }
-
- /// <summary>
- /// Kills the transcoding job.
- /// </summary>
- /// <param name="job">The job.</param>
- /// <param name="closeLiveStream">if set to <c>true</c> [close live stream].</param>
- /// <param name="delete">The delete.</param>
- private async void KillTranscodingJob(TranscodingJob job, bool closeLiveStream, Func<string, bool> delete)
- {
- job.DisposeKillTimer();
-
- Logger.Debug("KillTranscodingJob - JobId {0} PlaySessionId {1}. Killing transcoding", job.Id, job.PlaySessionId);
-
- lock (_activeTranscodingJobs)
- {
- _activeTranscodingJobs.Remove(job);
-
- if (!job.CancellationTokenSource.IsCancellationRequested)
- {
- job.CancellationTokenSource.Cancel();
- }
- }
-
- lock (_transcodingLocks)
- {
- _transcodingLocks.Remove(job.Path);
- }
-
- lock (job.ProcessLock)
- {
- if (job.TranscodingThrottler != null)
- {
- job.TranscodingThrottler.Stop();
- }
-
- var process = job.Process;
-
- var hasExited = job.HasExited;
-
- if (!hasExited)
- {
- try
- {
- Logger.Info("Stopping ffmpeg process with q command for {0}", job.Path);
-
- //process.Kill();
- process.StandardInput.WriteLine("q");
-
- // Need to wait because killing is asynchronous
- if (!process.WaitForExit(5000))
- {
- Logger.Info("Killing ffmpeg process for {0}", job.Path);
- process.Kill();
- }
- }
- catch (Exception ex)
- {
- Logger.ErrorException("Error killing transcoding job for {0}", ex, job.Path);
- }
- }
- }
-
- if (delete(job.Path))
- {
- DeletePartialStreamFiles(job.Path, job.Type, 0, 1500);
- }
-
- if (closeLiveStream && !string.IsNullOrWhiteSpace(job.LiveStreamId))
- {
- try
- {
- await _mediaSourceManager.CloseLiveStream(job.LiveStreamId).ConfigureAwait(false);
- }
- catch (Exception ex)
- {
- Logger.ErrorException("Error closing live stream for {0}", ex, job.Path);
- }
- }
- }
-
- private async void DeletePartialStreamFiles(string path, TranscodingJobType jobType, int retryCount, int delayMs)
- {
- if (retryCount >= 10)
- {
- return;
- }
-
- Logger.Info("Deleting partial stream file(s) {0}", path);
-
- await Task.Delay(delayMs).ConfigureAwait(false);
-
- try
- {
- if (jobType == TranscodingJobType.Progressive)
- {
- DeleteProgressivePartialStreamFiles(path);
- }
- else
- {
- DeleteHlsPartialStreamFiles(path);
- }
- }
- catch (FileNotFoundException)
- {
-
- }
- catch (IOException)
- {
- //Logger.ErrorException("Error deleting partial stream file(s) {0}", ex, path);
-
- DeletePartialStreamFiles(path, jobType, retryCount + 1, 500);
- }
- catch
- {
- //Logger.ErrorException("Error deleting partial stream file(s) {0}", ex, path);
- }
- }
-
- /// <summary>
- /// Deletes the progressive partial stream files.
- /// </summary>
- /// <param name="outputFilePath">The output file path.</param>
- private void DeleteProgressivePartialStreamFiles(string outputFilePath)
- {
- _fileSystem.DeleteFile(outputFilePath);
- }
-
- /// <summary>
- /// Deletes the HLS partial stream files.
- /// </summary>
- /// <param name="outputFilePath">The output file path.</param>
- private void DeleteHlsPartialStreamFiles(string outputFilePath)
- {
- var directory = _fileSystem.GetDirectoryName(outputFilePath);
- var name = Path.GetFileNameWithoutExtension(outputFilePath);
-
- var filesToDelete = _fileSystem.GetFilePaths(directory)
- .Where(f => f.IndexOf(name, StringComparison.OrdinalIgnoreCase) != -1)
- .ToList();
-
- Exception e = null;
-
- foreach (var file in filesToDelete)
- {
- try
- {
- //Logger.Debug("Deleting HLS file {0}", file);
- _fileSystem.DeleteFile(file);
- }
- catch (FileNotFoundException)
- {
-
- }
- catch (IOException ex)
- {
- e = ex;
- //Logger.ErrorException("Error deleting HLS file {0}", ex, file);
- }
- }
-
- if (e != null)
- {
- throw e;
- }
- }
- }
-
- /// <summary>
- /// Class TranscodingJob
- /// </summary>
- public class TranscodingJob
- {
- /// <summary>
- /// Gets or sets the play session identifier.
- /// </summary>
- /// <value>The play session identifier.</value>
- public string PlaySessionId { get; set; }
- /// <summary>
- /// Gets or sets the live stream identifier.
- /// </summary>
- /// <value>The live stream identifier.</value>
- public string LiveStreamId { get; set; }
-
- public bool IsLiveOutput { get; set; }
-
- /// <summary>
- /// Gets or sets the path.
- /// </summary>
- /// <value>The path.</value>
- public MediaSourceInfo MediaSource { get; set; }
- public string Path { get; set; }
- /// <summary>
- /// Gets or sets the type.
- /// </summary>
- /// <value>The type.</value>
- public TranscodingJobType Type { get; set; }
- /// <summary>
- /// Gets or sets the process.
- /// </summary>
- /// <value>The process.</value>
- public IProcess Process { get; set; }
- public ILogger Logger { get; private set; }
- /// <summary>
- /// Gets or sets the active request count.
- /// </summary>
- /// <value>The active request count.</value>
- public int ActiveRequestCount { get; set; }
- /// <summary>
- /// Gets or sets the kill timer.
- /// </summary>
- /// <value>The kill timer.</value>
- private ITimer KillTimer { get; set; }
-
- private readonly ITimerFactory _timerFactory;
-
- public string DeviceId { get; set; }
-
- public CancellationTokenSource CancellationTokenSource { get; set; }
-
- public object ProcessLock = new object();
-
- public bool HasExited { get; set; }
- public bool IsUserPaused { get; set; }
-
- public string Id { get; set; }
-
- public float? Framerate { get; set; }
- public double? CompletionPercentage { get; set; }
-
- public long? BytesDownloaded { get; set; }
- public long? BytesTranscoded { get; set; }
- public int? BitRate { get; set; }
-
- public long? TranscodingPositionTicks { get; set; }
- public long? DownloadPositionTicks { get; set; }
-
- public TranscodingThrottler TranscodingThrottler { get; set; }
-
- private readonly object _timerLock = new object();
-
- public DateTime LastPingDate { get; set; }
- public int PingTimeout { get; set; }
-
- public TranscodingJob(ILogger logger, ITimerFactory timerFactory)
- {
- Logger = logger;
- _timerFactory = timerFactory;
- }
-
- public void StopKillTimer()
- {
- lock (_timerLock)
- {
- if (KillTimer != null)
- {
- KillTimer.Change(Timeout.Infinite, Timeout.Infinite);
- }
- }
- }
-
- public void DisposeKillTimer()
- {
- lock (_timerLock)
- {
- if (KillTimer != null)
- {
- KillTimer.Dispose();
- KillTimer = null;
- }
- }
- }
-
- public void StartKillTimer(Action<object> callback)
- {
- StartKillTimer(callback, PingTimeout);
- }
-
- public void StartKillTimer(Action<object> callback, int intervalMs)
- {
- if (HasExited)
- {
- return;
- }
-
- lock (_timerLock)
- {
- if (KillTimer == null)
- {
- //Logger.Debug("Starting kill timer at {0}ms. JobId {1} PlaySessionId {2}", intervalMs, Id, PlaySessionId);
- KillTimer = _timerFactory.Create(callback, this, intervalMs, Timeout.Infinite);
- }
- else
- {
- //Logger.Debug("Changing kill timer to {0}ms. JobId {1} PlaySessionId {2}", intervalMs, Id, PlaySessionId);
- KillTimer.Change(intervalMs, Timeout.Infinite);
- }
- }
- }
-
- public void ChangeKillTimerIfStarted()
- {
- if (HasExited)
- {
- return;
- }
-
- lock (_timerLock)
- {
- if (KillTimer != null)
- {
- var intervalMs = PingTimeout;
-
- //Logger.Debug("Changing kill timer to {0}ms. JobId {1} PlaySessionId {2}", intervalMs, Id, PlaySessionId);
- KillTimer.Change(intervalMs, Timeout.Infinite);
- }
- }
- }
}
}
diff --git a/MediaBrowser.Api/BaseApiService.cs b/MediaBrowser.Api/BaseApiService.cs
index d3cc18d4b..1629d49b4 100644
--- a/MediaBrowser.Api/BaseApiService.cs
+++ b/MediaBrowser.Api/BaseApiService.cs
@@ -11,6 +11,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using MediaBrowser.Model.Services;
+using MediaBrowser.Model.Extensions;
namespace MediaBrowser.Api
{
@@ -54,6 +55,17 @@ namespace MediaBrowser.Api
return Request.Headers[name];
}
+ private static readonly string[] EmptyStringArray = new string[] { };
+ public static string[] SplitValue(string value, char delim)
+ {
+ if (string.IsNullOrWhiteSpace(value))
+ {
+ return EmptyStringArray;
+ }
+
+ return value.Split(new[] { delim }, StringSplitOptions.RemoveEmptyEntries);
+ }
+
/// <summary>
/// To the optimized result.
/// </summary>
@@ -128,7 +140,7 @@ namespace MediaBrowser.Api
var hasFields = request as IHasItemFields;
if (hasFields != null)
{
- options.Fields = hasFields.GetItemFields().ToList();
+ options.Fields = hasFields.GetItemFields();
}
var client = authInfo.Client ?? string.Empty;
@@ -137,7 +149,9 @@ namespace MediaBrowser.Api
client.IndexOf("media center", StringComparison.OrdinalIgnoreCase) != -1 ||
client.IndexOf("classic", StringComparison.OrdinalIgnoreCase) != -1)
{
- options.Fields.Add(Model.Querying.ItemFields.RecursiveItemCount);
+ var list = options.Fields.ToList();
+ list.Add(Model.Querying.ItemFields.RecursiveItemCount);
+ options.Fields = list.ToArray(list.Count);
}
if (client.IndexOf("kodi", StringComparison.OrdinalIgnoreCase) != -1 ||
@@ -148,7 +162,9 @@ namespace MediaBrowser.Api
client.IndexOf("samsung", StringComparison.OrdinalIgnoreCase) != -1 ||
client.IndexOf("androidtv", StringComparison.OrdinalIgnoreCase) != -1)
{
- options.Fields.Add(Model.Querying.ItemFields.ChildCount);
+ var list = options.Fields.ToList();
+ list.Add(Model.Querying.ItemFields.ChildCount);
+ options.Fields = list.ToArray(list.Count);
}
var hasDtoOptions = request as IHasDtoOptions;
@@ -167,7 +183,7 @@ namespace MediaBrowser.Api
if (!string.IsNullOrWhiteSpace(hasDtoOptions.EnableImageTypes))
{
- options.ImageTypes = (hasDtoOptions.EnableImageTypes ?? string.Empty).Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).Select(v => (ImageType)Enum.Parse(typeof(ImageType), v, true)).ToList();
+ options.ImageTypes = (hasDtoOptions.EnableImageTypes ?? string.Empty).Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).Select(v => (ImageType)Enum.Parse(typeof(ImageType), v, true)).ToArray();
}
}
diff --git a/MediaBrowser.Api/BasePeriodicWebSocketListener.cs b/MediaBrowser.Api/BasePeriodicWebSocketListener.cs
index 8004d7e9b..c7a9d97ba 100644
--- a/MediaBrowser.Api/BasePeriodicWebSocketListener.cs
+++ b/MediaBrowser.Api/BasePeriodicWebSocketListener.cs
@@ -314,6 +314,7 @@ namespace MediaBrowser.Api
public void Dispose()
{
Dispose(true);
+ GC.SuppressFinalize(this);
}
}
diff --git a/MediaBrowser.Api/ChannelService.cs b/MediaBrowser.Api/ChannelService.cs
index bce1e6682..d64bf7ec7 100644
--- a/MediaBrowser.Api/ChannelService.cs
+++ b/MediaBrowser.Api/ChannelService.cs
@@ -9,6 +9,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using MediaBrowser.Api.UserLibrary;
using MediaBrowser.Model.Services;
namespace MediaBrowser.Api
@@ -55,7 +56,7 @@ namespace MediaBrowser.Api
}
[Route("/Channels/Features", "GET", Summary = "Gets features for a channel")]
- public class GetAllChannelFeatures : IReturn<List<ChannelFeatures>>
+ public class GetAllChannelFeatures : IReturn<ChannelFeatures[]>
{
}
@@ -90,7 +91,7 @@ namespace MediaBrowser.Api
public int? Limit { get; set; }
[ApiMember(Name = "SortOrder", Description = "Sort Order - Ascending,Descending", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
- public SortOrder? SortOrder { get; set; }
+ public string SortOrder { get; set; }
[ApiMember(Name = "Filters", Description = "Optional. Specify additional filters to apply. This allows multiple, comma delimeted. Options: IsFolder, IsNotFolder, IsUnplayed, IsPlayed, IsFavorite, IsResumable, Likes, Dislikes", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
public string Filters { get; set; }
@@ -116,6 +117,15 @@ namespace MediaBrowser.Api
return val.Split(',').Select(v => (ItemFilter)Enum.Parse(typeof(ItemFilter), v, true));
}
+
+ /// <summary>
+ /// Gets the order by.
+ /// </summary>
+ /// <returns>IEnumerable{ItemSortBy}.</returns>
+ public Tuple<string, SortOrder>[] GetOrderBy()
+ {
+ return BaseItemsRequest.GetOrderBy(SortBy, SortOrder);
+ }
}
[Route("/Channels/Items/Latest", "GET", Summary = "Gets channel items")]
@@ -187,7 +197,7 @@ namespace MediaBrowser.Api
public object Get(GetAllChannelFeatures request)
{
- var result = _channelManager.GetAllChannelFeatures().ToList();
+ var result = _channelManager.GetAllChannelFeatures();
return ToOptimizedResult(result);
}
@@ -228,10 +238,9 @@ namespace MediaBrowser.Api
UserId = request.UserId,
ChannelId = request.Id,
FolderId = request.FolderId,
- SortOrder = request.SortOrder,
- SortBy = (request.SortBy ?? string.Empty).Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).ToArray(),
+ OrderBy = request.GetOrderBy(),
Filters = request.GetFilters().ToArray(),
- Fields = request.GetItemFields().ToArray()
+ Fields = request.GetItemFields()
}, CancellationToken.None).ConfigureAwait(false);
@@ -247,7 +256,7 @@ namespace MediaBrowser.Api
ChannelIds = (request.ChannelIds ?? string.Empty).Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).ToArray(),
UserId = request.UserId,
Filters = request.GetFilters().ToArray(),
- Fields = request.GetItemFields().ToList()
+ Fields = request.GetItemFields()
}, CancellationToken.None).ConfigureAwait(false);
diff --git a/MediaBrowser.Api/ConfigurationService.cs b/MediaBrowser.Api/ConfigurationService.cs
index 8d5f46962..643ecd9c8 100644
--- a/MediaBrowser.Api/ConfigurationService.cs
+++ b/MediaBrowser.Api/ConfigurationService.cs
@@ -6,7 +6,6 @@ using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Serialization;
using System.Collections.Generic;
using System.IO;
-using System.Linq;
using System.Threading.Tasks;
using MediaBrowser.Controller.IO;
@@ -62,7 +61,7 @@ namespace MediaBrowser.Api
[Route("/System/Configuration/MetadataPlugins", "GET", Summary = "Gets all available metadata plugins")]
[Authenticated(Roles = "Admin")]
- public class GetMetadataPlugins : IReturn<List<MetadataPluginSummary>>
+ public class GetMetadataPlugins : IReturn<MetadataPluginSummary[]>
{
}
@@ -170,7 +169,7 @@ namespace MediaBrowser.Api
public object Get(GetMetadataPlugins request)
{
- return ToOptimizedSerializedResultUsingCache(_providerManager.GetAllMetadataPlugins().ToList());
+ return ToOptimizedSerializedResultUsingCache(_providerManager.GetAllMetadataPlugins());
}
}
}
diff --git a/MediaBrowser.Api/Devices/DeviceService.cs b/MediaBrowser.Api/Devices/DeviceService.cs
index 544960f5f..012f0ddb2 100644
--- a/MediaBrowser.Api/Devices/DeviceService.cs
+++ b/MediaBrowser.Api/Devices/DeviceService.cs
@@ -1,5 +1,4 @@
using System;
-using System.Linq;
using MediaBrowser.Controller.Devices;
using MediaBrowser.Controller.Net;
using MediaBrowser.Model.Devices;
@@ -143,7 +142,7 @@ namespace MediaBrowser.Api.Devices
}
else
{
- var file = Request.Files.First();
+ var file = Request.Files.Length == 0 ? null : Request.Files[0];
var task = _deviceManager.AcceptCameraUpload(deviceId, file.InputStream, new LocalFileInfo
{
diff --git a/MediaBrowser.Api/DisplayPreferencesService.cs b/MediaBrowser.Api/DisplayPreferencesService.cs
index 5a21fc9f4..4f8cc5255 100644
--- a/MediaBrowser.Api/DisplayPreferencesService.cs
+++ b/MediaBrowser.Api/DisplayPreferencesService.cs
@@ -88,9 +88,7 @@ namespace MediaBrowser.Api
// Serialize to json and then back so that the core doesn't see the request dto type
var displayPreferences = _jsonSerializer.DeserializeFromString<DisplayPreferences>(_jsonSerializer.SerializeToString(request));
- var task = _displayPreferencesManager.SaveDisplayPreferences(displayPreferences, request.UserId, request.Client, CancellationToken.None);
-
- Task.WaitAll(task);
+ _displayPreferencesManager.SaveDisplayPreferences(displayPreferences, request.UserId, request.Client, CancellationToken.None);
}
}
}
diff --git a/MediaBrowser.Api/Dlna/DlnaServerService.cs b/MediaBrowser.Api/Dlna/DlnaServerService.cs
index fc8c0edf6..cbef6e5b3 100644
--- a/MediaBrowser.Api/Dlna/DlnaServerService.cs
+++ b/MediaBrowser.Api/Dlna/DlnaServerService.cs
@@ -3,7 +3,6 @@ using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
-using System.Linq;
using System.Threading.Tasks;
using MediaBrowser.Controller.IO;
@@ -71,24 +70,27 @@ namespace MediaBrowser.Api.Dlna
public Stream RequestStream { get; set; }
}
- [Route("/Dlna/{UuId}/mediareceiverregistrar/events", Summary = "Processes an event subscription request")]
+ [Route("/Dlna/{UuId}/mediareceiverregistrar/events", "SUBSCRIBE", Summary = "Processes an event subscription request")]
+ [Route("/Dlna/{UuId}/mediareceiverregistrar/events", "UNSUBSCRIBE", Summary = "Processes an event subscription request")]
public class ProcessMediaReceiverRegistrarEventRequest
{
- [ApiMember(Name = "UuId", Description = "Server UuId", IsRequired = false, DataType = "string", ParameterType = "path", Verb = "SUBSCRIBE,POST")]
+ [ApiMember(Name = "UuId", Description = "Server UuId", IsRequired = false, DataType = "string", ParameterType = "path", Verb = "SUBSCRIBE,UNSUBSCRIBE")]
public string UuId { get; set; }
}
- [Route("/Dlna/{UuId}/contentdirectory/events", Summary = "Processes an event subscription request")]
+ [Route("/Dlna/{UuId}/contentdirectory/events", "SUBSCRIBE", Summary = "Processes an event subscription request")]
+ [Route("/Dlna/{UuId}/contentdirectory/events", "UNSUBSCRIBE", Summary = "Processes an event subscription request")]
public class ProcessContentDirectoryEventRequest
{
- [ApiMember(Name = "UuId", Description = "Server UuId", IsRequired = false, DataType = "string", ParameterType = "path", Verb = "SUBSCRIBE,POST")]
+ [ApiMember(Name = "UuId", Description = "Server UuId", IsRequired = false, DataType = "string", ParameterType = "path", Verb = "SUBSCRIBE,UNSUBSCRIBE")]
public string UuId { get; set; }
}
- [Route("/Dlna/{UuId}/connectionmanager/events", Summary = "Processes an event subscription request")]
+ [Route("/Dlna/{UuId}/connectionmanager/events", "SUBSCRIBE", Summary = "Processes an event subscription request")]
+ [Route("/Dlna/{UuId}/connectionmanager/events", "UNSUBSCRIBE", Summary = "Processes an event subscription request")]
public class ProcessConnectionManagerEventRequest
{
- [ApiMember(Name = "UuId", Description = "Server UuId", IsRequired = false, DataType = "string", ParameterType = "path", Verb = "SUBSCRIBE,POST")]
+ [ApiMember(Name = "UuId", Description = "Server UuId", IsRequired = false, DataType = "string", ParameterType = "path", Verb = "SUBSCRIBE,UNSUBSCRIBE")]
public string UuId { get; set; }
}
@@ -201,17 +203,32 @@ namespace MediaBrowser.Api.Dlna
}
}
- public object Any(ProcessContentDirectoryEventRequest request)
+ public object Subscribe(ProcessContentDirectoryEventRequest request)
{
return ProcessEventRequest(_contentDirectory);
}
- public object Any(ProcessConnectionManagerEventRequest request)
+ public object Subscribe(ProcessConnectionManagerEventRequest request)
{
return ProcessEventRequest(_connectionManager);
}
- public object Any(ProcessMediaReceiverRegistrarEventRequest request)
+ public object Subscribe(ProcessMediaReceiverRegistrarEventRequest request)
+ {
+ return ProcessEventRequest(_mediaReceiverRegistrar);
+ }
+
+ public object Unsubscribe(ProcessContentDirectoryEventRequest request)
+ {
+ return ProcessEventRequest(_contentDirectory);
+ }
+
+ public object Unsubscribe(ProcessConnectionManagerEventRequest request)
+ {
+ return ProcessEventRequest(_connectionManager);
+ }
+
+ public object Unsubscribe(ProcessMediaReceiverRegistrarEventRequest request)
{
return ProcessEventRequest(_mediaReceiverRegistrar);
}
diff --git a/MediaBrowser.Api/Dlna/DlnaService.cs b/MediaBrowser.Api/Dlna/DlnaService.cs
index ecb54bf5c..4dd71f446 100644
--- a/MediaBrowser.Api/Dlna/DlnaService.cs
+++ b/MediaBrowser.Api/Dlna/DlnaService.cs
@@ -1,14 +1,13 @@
-using MediaBrowser.Controller.Dlna;
+using System.Linq;
+using MediaBrowser.Controller.Dlna;
using MediaBrowser.Controller.Net;
using MediaBrowser.Model.Dlna;
-using System.Collections.Generic;
-using System.Linq;
using MediaBrowser.Model.Services;
namespace MediaBrowser.Api.Dlna
{
[Route("/Dlna/ProfileInfos", "GET", Summary = "Gets a list of profiles")]
- public class GetProfileInfos : IReturn<List<DeviceProfileInfo>>
+ public class GetProfileInfos : IReturn<DeviceProfileInfo[]>
{
}
@@ -53,7 +52,7 @@ namespace MediaBrowser.Api.Dlna
public object Get(GetProfileInfos request)
{
- var result = _dlnaManager.GetProfileInfos().ToList();
+ var result = _dlnaManager.GetProfileInfos().ToArray();
return ToOptimizedResult(result);
}
diff --git a/MediaBrowser.Api/EnvironmentService.cs b/MediaBrowser.Api/EnvironmentService.cs
index 9764a71db..400169ac5 100644
--- a/MediaBrowser.Api/EnvironmentService.cs
+++ b/MediaBrowser.Api/EnvironmentService.cs
@@ -226,7 +226,7 @@ namespace MediaBrowser.Api
return ToOptimizedSerializedResultUsingCache(GetNetworkShares(path).OrderBy(i => i.Path).ToList());
}
- return ToOptimizedSerializedResultUsingCache(GetFileSystemEntries(request).OrderBy(i => i.Path).ToList());
+ return ToOptimizedSerializedResultUsingCache(GetFileSystemEntries(request).ToList());
}
public object Get(GetNetworkShares request)
@@ -271,9 +271,7 @@ namespace MediaBrowser.Api
/// <returns>System.Object.</returns>
public object Get(GetNetworkDevices request)
{
- var result = _networkManager.GetNetworkDevices()
- .OrderBy(i => i.Path)
- .ToList();
+ var result = _networkManager.GetNetworkDevices().ToList();
return ToOptimizedSerializedResultUsingCache(result);
}
@@ -300,8 +298,7 @@ namespace MediaBrowser.Api
/// <returns>IEnumerable{FileSystemEntryInfo}.</returns>
private IEnumerable<FileSystemEntryInfo> GetFileSystemEntries(GetDirectoryContents request)
{
- // using EnumerateFileSystemInfos doesn't handle reparse points (symlinks)
- var entries = _fileSystem.GetFileSystemEntries(request.Path).Where(i =>
+ var entries = _fileSystem.GetFileSystemEntries(request.Path).OrderBy(i => i.FullName).Where(i =>
{
if (!request.IncludeHidden && i.IsHidden)
{
@@ -329,7 +326,7 @@ namespace MediaBrowser.Api
Path = f.FullName,
Type = f.IsDirectory ? FileSystemEntryType.Directory : FileSystemEntryType.File
- }).ToList();
+ });
}
public object Get(GetParentPath request)
diff --git a/MediaBrowser.Api/FilterService.cs b/MediaBrowser.Api/FilterService.cs
index a1f891506..52b274653 100644
--- a/MediaBrowser.Api/FilterService.cs
+++ b/MediaBrowser.Api/FilterService.cs
@@ -61,9 +61,9 @@ namespace MediaBrowser.Api
user == null ? _libraryManager.RootFolder : user.RootFolder :
parentItem;
- var result = ((Folder)item).GetItems(GetItemsQuery(request, user));
+ var result = ((Folder)item).GetItemList(GetItemsQuery(request, user));
- return ToOptimizedResult(GetFilters(result.Items));
+ return ToOptimizedResult(GetFilters(result));
}
private QueryFilters GetFilters(BaseItem[] items)
@@ -108,7 +108,7 @@ namespace MediaBrowser.Api
EnableTotalRecordCount = false,
DtoOptions = new Controller.Dto.DtoOptions
{
- Fields = new List<ItemFields> { ItemFields.Genres, ItemFields.Tags },
+ Fields = new ItemFields[] { ItemFields.Genres, ItemFields.Tags },
EnableImages = false,
EnableUserData = false
}
diff --git a/MediaBrowser.Api/GamesService.cs b/MediaBrowser.Api/GamesService.cs
index 2d161ccfd..6c48b732f 100644
--- a/MediaBrowser.Api/GamesService.cs
+++ b/MediaBrowser.Api/GamesService.cs
@@ -12,6 +12,7 @@ using System.Linq;
using System.Threading.Tasks;
using MediaBrowser.Model.Querying;
using MediaBrowser.Model.Services;
+using MediaBrowser.Model.Extensions;
namespace MediaBrowser.Api
{
@@ -27,21 +28,7 @@ namespace MediaBrowser.Api
/// Class GetGameSystemSummaries
/// </summary>
[Route("/Games/SystemSummaries", "GET", Summary = "Finds games similar to a given game.")]
- public class GetGameSystemSummaries : IReturn<List<GameSystemSummary>>
- {
- /// <summary>
- /// Gets or sets the user id.
- /// </summary>
- /// <value>The user id.</value>
- [ApiMember(Name = "UserId", Description = "Optional. Filter by user id", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
- public string UserId { get; set; }
- }
-
- /// <summary>
- /// Class GetGameSystemSummaries
- /// </summary>
- [Route("/Games/PlayerIndex", "GET", Summary = "Gets an index of players (1-x) and the number of games listed under each")]
- public class GetPlayerIndex : IReturn<List<ItemIndex>>
+ public class GetGameSystemSummaries : IReturn<GameSystemSummary[]>
{
/// <summary>
/// Gets or sets the user id.
@@ -116,47 +103,17 @@ namespace MediaBrowser.Api
EnableImages = false
}
};
- var gameSystems = _libraryManager.GetItemList(query)
- .Cast<GameSystem>()
- .ToList();
- var result = gameSystems
+ var result = _libraryManager.GetItemList(query)
+ .Cast<GameSystem>()
.Select(i => GetSummary(i, user))
- .ToList();
+ .ToArray();
return ToOptimizedSerializedResultUsingCache(result);
}
private static readonly CultureInfo UsCulture = new CultureInfo("en-US");
- public object Get(GetPlayerIndex request)
- {
- var user = request.UserId == null ? null : _userManager.GetUserById(request.UserId);
- var query = new InternalItemsQuery(user)
- {
- IncludeItemTypes = new[] { typeof(Game).Name },
- DtoOptions = new DtoOptions(false)
- {
- EnableImages = false
- }
- };
- var games = _libraryManager.GetItemList(query)
- .Cast<Game>()
- .ToList();
-
- var lookup = games
- .ToLookup(i => i.PlayersSupported ?? -1)
- .OrderBy(i => i.Key)
- .Select(i => new ItemIndex
- {
- ItemCount = i.Count(),
- Name = i.Key == -1 ? string.Empty : i.Key.ToString(UsCulture)
- })
- .ToList();
-
- return ToOptimizedSerializedResultUsingCache(lookup);
- }
-
/// <summary>
/// Gets the summary.
/// </summary>
@@ -171,7 +128,7 @@ namespace MediaBrowser.Api
DisplayName = system.Name
};
- var items = user == null ?
+ var items = user == null ?
system.GetRecursiveChildren(i => i is Game) :
system.GetRecursiveChildren(user, new InternalItemsQuery(user)
{
@@ -182,15 +139,15 @@ namespace MediaBrowser.Api
}
});
- var games = items.Cast<Game>().ToList();
+ var games = items.Cast<Game>().ToArray();
summary.ClientInstalledGameCount = games.Count(i => i.IsPlaceHolder);
- summary.GameCount = games.Count;
+ summary.GameCount = games.Length;
summary.GameFileExtensions = games.Where(i => !i.IsPlaceHolder).Select(i => Path.GetExtension(i.Path))
.Distinct(StringComparer.OrdinalIgnoreCase)
- .ToList();
+ .ToArray();
return summary;
}
@@ -200,14 +157,14 @@ namespace MediaBrowser.Api
/// </summary>
/// <param name="request">The request.</param>
/// <returns>System.Object.</returns>
- public async Task<object> Get(GetSimilarGames request)
+ public object Get(GetSimilarGames request)
{
- var result = await GetSimilarItemsResult(request).ConfigureAwait(false);
+ var result = GetSimilarItemsResult(request);
return ToOptimizedSerializedResultUsingCache(result);
}
- private async Task<QueryResult<BaseItemDto>> GetSimilarItemsResult(BaseGetSimilarItemsFromItem request)
+ private QueryResult<BaseItemDto> GetSimilarItemsResult(BaseGetSimilarItemsFromItem request)
{
var user = !string.IsNullOrWhiteSpace(request.UserId) ? _userManager.GetUserById(request.UserId) : null;
@@ -227,11 +184,13 @@ namespace MediaBrowser.Api
SimilarTo = item,
DtoOptions = dtoOptions
- }).ToList();
+ });
+
+ var returnList = _dtoService.GetBaseItemDtos(itemsResult, dtoOptions, user);
var result = new QueryResult<BaseItemDto>
{
- Items = (await _dtoService.GetBaseItemDtos(itemsResult, dtoOptions, user).ConfigureAwait(false)).ToArray(),
+ Items = returnList,
TotalRecordCount = itemsResult.Count
};
diff --git a/MediaBrowser.Api/IHasItemFields.cs b/MediaBrowser.Api/IHasItemFields.cs
index 36303c889..0b3919985 100644
--- a/MediaBrowser.Api/IHasItemFields.cs
+++ b/MediaBrowser.Api/IHasItemFields.cs
@@ -27,7 +27,7 @@ namespace MediaBrowser.Api
/// </summary>
/// <param name="request">The request.</param>
/// <returns>IEnumerable{ItemFields}.</returns>
- public static IEnumerable<ItemFields> GetItemFields(this IHasItemFields request)
+ public static ItemFields[] GetItemFields(this IHasItemFields request)
{
var val = request.Fields;
@@ -46,7 +46,7 @@ namespace MediaBrowser.Api
}
return null;
- }).Where(i => i.HasValue).Select(i => i.Value);
+ }).Where(i => i.HasValue).Select(i => i.Value).ToArray();
}
}
}
diff --git a/MediaBrowser.Api/Images/ImageService.cs b/MediaBrowser.Api/Images/ImageService.cs
index f6c97e091..69d4a4ab4 100644
--- a/MediaBrowser.Api/Images/ImageService.cs
+++ b/MediaBrowser.Api/Images/ImageService.cs
@@ -279,13 +279,16 @@ namespace MediaBrowser.Api.Images
var itemImages = item.ImageInfos;
- foreach (var image in itemImages.Where(i => !item.AllowsMultipleImages(i.Type)))
+ foreach (var image in itemImages)
{
- var info = GetImageInfo(item, image, null);
-
- if (info != null)
+ if (!item.AllowsMultipleImages(image.Type))
{
- list.Add(info);
+ var info = GetImageInfo(item, image, null);
+
+ if (info != null)
+ {
+ list.Add(info);
+ }
}
}
@@ -312,7 +315,7 @@ namespace MediaBrowser.Api.Images
return list;
}
- private ImageInfo GetImageInfo(IHasImages item, ItemImageInfo info, int? imageIndex)
+ private ImageInfo GetImageInfo(IHasMetadata item, ItemImageInfo info, int? imageIndex)
{
try
{
@@ -507,7 +510,7 @@ namespace MediaBrowser.Api.Images
/// <param name="currentIndex">Index of the current.</param>
/// <param name="newIndex">The new index.</param>
/// <returns>Task.</returns>
- private Task UpdateItemIndex(IHasImages item, ImageType type, int currentIndex, int newIndex)
+ private Task UpdateItemIndex(IHasMetadata item, ImageType type, int currentIndex, int newIndex)
{
return item.SwapImages(type, currentIndex, newIndex);
}
@@ -520,7 +523,7 @@ namespace MediaBrowser.Api.Images
/// <param name="isHeadRequest">if set to <c>true</c> [is head request].</param>
/// <returns>System.Object.</returns>
/// <exception cref="ResourceNotFoundException"></exception>
- public Task<object> GetImage(ImageRequest request, IHasImages item, bool isHeadRequest)
+ public Task<object> GetImage(ImageRequest request, IHasMetadata item, bool isHeadRequest)
{
if (request.PercentPlayed.HasValue)
{
@@ -553,20 +556,7 @@ namespace MediaBrowser.Api.Images
throw new ResourceNotFoundException(string.Format("{0} does not have an image of type {1}", item.Name, request.Type));
}
- var supportedImageEnhancers = request.EnableImageEnhancers ? _imageProcessor.ImageEnhancers.Where(i =>
- {
- try
- {
- return i.Supports(item, request.Type);
- }
- catch (Exception ex)
- {
- Logger.ErrorException("Error in image enhancer: {0}", ex, i.GetType().Name);
-
- return false;
- }
-
- }).ToList() : new List<IImageEnhancer>();
+ var supportedImageEnhancers = request.EnableImageEnhancers ? _imageProcessor.GetSupportedEnhancers(item, request.Type) : new List<IImageEnhancer>();
var cropwhitespace = request.Type == ImageType.Logo ||
request.Type == ImageType.Art
@@ -603,7 +593,7 @@ namespace MediaBrowser.Api.Images
isHeadRequest);
}
- private async Task<object> GetImageResult(IHasImages item,
+ private async Task<object> GetImageResult(IHasMetadata item,
ImageRequest request,
ItemImageInfo image,
bool cropwhitespace,
@@ -649,9 +639,7 @@ namespace MediaBrowser.Api.Images
IsHeadRequest = isHeadRequest,
Path = imageResult.Item1,
- // Sometimes imagemagick keeps a hold on the file briefly even after it's done writing to it.
- // I'd rather do this than add a delay after saving the file
- FileShare = FileShareMode.ReadWrite
+ FileShare = FileShareMode.Read
}).ConfigureAwait(false);
}
@@ -749,7 +737,7 @@ namespace MediaBrowser.Api.Images
/// <param name="request">The request.</param>
/// <param name="item">The item.</param>
/// <returns>System.String.</returns>
- private ItemImageInfo GetImageInfo(ImageRequest request, IHasImages item)
+ private ItemImageInfo GetImageInfo(ImageRequest request, IHasMetadata item)
{
var index = request.Index ?? 0;
diff --git a/MediaBrowser.Api/Images/RemoteImageService.cs b/MediaBrowser.Api/Images/RemoteImageService.cs
index e4f3fd3d7..3512a526b 100644
--- a/MediaBrowser.Api/Images/RemoteImageService.cs
+++ b/MediaBrowser.Api/Images/RemoteImageService.cs
@@ -150,7 +150,7 @@ namespace MediaBrowser.Api.Images
}, CancellationToken.None).ConfigureAwait(false);
- var imagesList = images.ToList();
+ var imagesList = images.ToArray();
var allProviders = _providerManager.GetRemoteImageProviderInfo(item);
@@ -161,22 +161,22 @@ namespace MediaBrowser.Api.Images
var result = new RemoteImageResult
{
- TotalRecordCount = imagesList.Count,
+ TotalRecordCount = imagesList.Length,
Providers = allProviders.Select(i => i.Name)
.Distinct(StringComparer.OrdinalIgnoreCase)
- .ToList()
+ .ToArray()
};
if (request.StartIndex.HasValue)
{
imagesList = imagesList.Skip(request.StartIndex.Value)
- .ToList();
+ .ToArray();
}
if (request.Limit.HasValue)
{
imagesList = imagesList.Take(request.Limit.Value)
- .ToList();
+ .ToArray();
}
result.Images = imagesList;
diff --git a/MediaBrowser.Api/ItemUpdateService.cs b/MediaBrowser.Api/ItemUpdateService.cs
index 5325df325..9e83cf680 100644
--- a/MediaBrowser.Api/ItemUpdateService.cs
+++ b/MediaBrowser.Api/ItemUpdateService.cs
@@ -64,10 +64,10 @@ namespace MediaBrowser.Api
var info = new MetadataEditorInfo
{
- ParentalRatingOptions = _localizationManager.GetParentalRatings().ToList(),
- ExternalIdInfos = _providerManager.GetExternalIdInfos(item).ToList(),
- Countries = _localizationManager.GetCountries().ToList(),
- Cultures = _localizationManager.GetCultures().ToList()
+ ParentalRatingOptions = _localizationManager.GetParentalRatings(),
+ ExternalIdInfos = _providerManager.GetExternalIdInfos(item).ToArray(),
+ Countries = _localizationManager.GetCountries(),
+ Cultures = _localizationManager.GetCultures()
};
if (!item.IsVirtualItem && !(item is ICollectionFolder) && !(item is UserView) && !(item is AggregateFolder) && !(item is LiveTvChannel) && !(item is IItemByName) &&
@@ -78,14 +78,14 @@ namespace MediaBrowser.Api
if (string.IsNullOrWhiteSpace(inheritedContentType) || !string.IsNullOrWhiteSpace(configuredContentType))
{
- info.ContentTypeOptions = GetContentTypeOptions(true);
+ info.ContentTypeOptions = GetContentTypeOptions(true).ToArray();
info.ContentType = configuredContentType;
if (string.IsNullOrWhiteSpace(inheritedContentType) || string.Equals(inheritedContentType, CollectionType.TvShows, StringComparison.OrdinalIgnoreCase))
{
info.ContentTypeOptions = info.ContentTypeOptions
.Where(i => string.IsNullOrWhiteSpace(i.Value) || string.Equals(i.Value, CollectionType.TvShows, StringComparison.OrdinalIgnoreCase))
- .ToList();
+ .ToArray();
}
}
}
@@ -209,7 +209,7 @@ namespace MediaBrowser.Api
// Do this first so that metadata savers can pull the updates from the database.
if (request.People != null)
{
- await _libraryManager.UpdatePeople(item, request.People.Select(x => new PersonInfo { Name = x.Name, Role = x.Role, Type = x.Type }).ToList());
+ _libraryManager.UpdatePeople(item, request.People.Select(x => new PersonInfo { Name = x.Name, Role = x.Role, Type = x.Type }).ToList());
}
UpdateItem(request, item);
@@ -242,7 +242,6 @@ namespace MediaBrowser.Api
item.CriticRating = request.CriticRating;
- item.DisplayMediaType = request.DisplayMediaType;
item.CommunityRating = request.CommunityRating;
item.HomePageUrl = request.HomePageUrl;
item.IndexNumber = request.IndexNumber;
@@ -270,7 +269,7 @@ namespace MediaBrowser.Api
if (request.Studios != null)
{
- item.Studios = request.Studios.Select(x => x.Name).ToList();
+ item.Studios = request.Studios.Select(x => x.Name).ToArray();
}
if (request.DateCreated.HasValue)
@@ -286,7 +285,7 @@ namespace MediaBrowser.Api
if (request.ProductionLocations != null)
{
- item.ProductionLocations = request.ProductionLocations.ToList();
+ item.ProductionLocations = request.ProductionLocations;
}
item.PreferredMetadataCountryCode = request.PreferredMetadataCountryCode;
@@ -333,13 +332,6 @@ namespace MediaBrowser.Api
video.Video3DFormat = request.Video3DFormat;
}
- var game = item as Game;
-
- if (game != null)
- {
- game.PlayersSupported = request.Players;
- }
-
if (request.AlbumArtists != null)
{
var hasAlbumArtists = item as IHasAlbumArtist;
@@ -348,7 +340,7 @@ namespace MediaBrowser.Api
hasAlbumArtists.AlbumArtists = request
.AlbumArtists
.Select(i => i.Name)
- .ToList();
+ .ToArray();
}
}
@@ -360,7 +352,7 @@ namespace MediaBrowser.Api
hasArtists.Artists = request
.ArtistItems
.Select(i => i.Name)
- .ToList();
+ .ToArray();
}
}
@@ -380,8 +372,12 @@ namespace MediaBrowser.Api
if (series != null)
{
series.Status = GetSeriesStatus(request);
- series.AirDays = request.AirDays;
- series.AirTime = request.AirTime;
+
+ if (request.AirDays != null)
+ {
+ series.AirDays = request.AirDays;
+ series.AirTime = request.AirTime;
+ }
}
}
diff --git a/MediaBrowser.Api/Library/LibraryService.cs b/MediaBrowser.Api/Library/LibraryService.cs
index 3bb119cba..6152ea20b 100644
--- a/MediaBrowser.Api/Library/LibraryService.cs
+++ b/MediaBrowser.Api/Library/LibraryService.cs
@@ -29,6 +29,7 @@ using MediaBrowser.Model.Globalization;
using MediaBrowser.Model.Services;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.Progress;
+using MediaBrowser.Model.Extensions;
namespace MediaBrowser.Api.Library
{
@@ -226,7 +227,7 @@ namespace MediaBrowser.Api.Library
[Route("/Library/MediaFolders", "GET", Summary = "Gets all user media folders.")]
[Authenticated]
- public class GetMediaFolders : IReturn<ItemsResult>
+ public class GetMediaFolders : IReturn<QueryResult<BaseItemDto>>
{
[ApiMember(Name = "IsHidden", Description = "Optional. Filter by folders that are marked hidden, or not.", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")]
public bool? IsHidden { get; set; }
@@ -399,7 +400,7 @@ namespace MediaBrowser.Api.Library
});
}
- return new ItemsResult();
+ return new QueryResult<BaseItemDto>();
}
public object Get(GetMediaFolders request)
@@ -415,7 +416,7 @@ namespace MediaBrowser.Api.Library
var dtoOptions = GetDtoOptions(_authContext, request);
- var result = new ItemsResult
+ var result = new QueryResult<BaseItemDto>
{
TotalRecordCount = items.Count,
@@ -460,22 +461,22 @@ namespace MediaBrowser.Api.Library
EnableImages = false
}
- }).ToArray();
+ });
if (!string.IsNullOrWhiteSpace(request.ImdbId))
{
- movies = movies.Where(i => string.Equals(request.ImdbId, i.GetProviderId(MetadataProviders.Imdb), StringComparison.OrdinalIgnoreCase)).ToArray();
+ movies = movies.Where(i => string.Equals(request.ImdbId, i.GetProviderId(MetadataProviders.Imdb), StringComparison.OrdinalIgnoreCase)).ToList();
}
else if (!string.IsNullOrWhiteSpace(request.TmdbId))
{
- movies = movies.Where(i => string.Equals(request.TmdbId, i.GetProviderId(MetadataProviders.Tmdb), StringComparison.OrdinalIgnoreCase)).ToArray();
+ movies = movies.Where(i => string.Equals(request.TmdbId, i.GetProviderId(MetadataProviders.Tmdb), StringComparison.OrdinalIgnoreCase)).ToList();
}
else
{
- movies = new BaseItem[] { };
+ movies = new List<BaseItem>();
}
- if (movies.Length > 0)
+ if (movies.Count > 0)
{
foreach (var item in movies)
{
@@ -517,25 +518,34 @@ namespace MediaBrowser.Api.Library
LogDownload(item, user, auth);
}
+ var path = item.Path;
+
+ // Quotes are valid in linux. They'll possibly cause issues here
+ var filename = (Path.GetFileName(path) ?? string.Empty).Replace("\"", string.Empty);
+ if (!string.IsNullOrWhiteSpace(filename))
+ {
+ headers["Content-Disposition"] = "attachment; filename=\"" + filename + "\"";
+ }
+
return ResultFactory.GetStaticFileResult(Request, new StaticFileResultOptions
{
- Path = item.Path,
+ Path = path,
ResponseHeaders = headers
});
}
- private async void LogDownload(BaseItem item, User user, AuthorizationInfo auth)
+ private void LogDownload(BaseItem item, User user, AuthorizationInfo auth)
{
try
{
- await _activityManager.Create(new ActivityLogEntry
+ _activityManager.Create(new ActivityLogEntry
{
Name = string.Format(_localization.GetLocalizedString("UserDownloadingItemWithValues"), user.Name, item.Name),
Type = "UserDownloadingContent",
ShortOverview = string.Format(_localization.GetLocalizedString("AppDeviceValues"), auth.Client, auth.Device),
UserId = auth.UserId
- }).ConfigureAwait(false);
+ });
}
catch
{
@@ -614,7 +624,7 @@ namespace MediaBrowser.Api.Library
parent = parent.GetParent();
}
- return baseItemDtos.ToList();
+ return baseItemDtos;
}
private BaseItem TranslateParentItem(BaseItem item, User user)
@@ -732,7 +742,8 @@ namespace MediaBrowser.Api.Library
{
DeleteFileLocation = true
});
- }).ToArray();
+
+ }).ToArray(ids.Length);
Task.WaitAll(tasks);
}
@@ -758,7 +769,7 @@ namespace MediaBrowser.Api.Library
{
var reviews = _itemRepo.GetCriticReviews(new Guid(request.Id));
- var reviewsArray = reviews.ToArray();
+ var reviewsArray = reviews.ToArray(reviews.Count);
var result = new QueryResult<ItemReview>
{
@@ -833,7 +844,7 @@ namespace MediaBrowser.Api.Library
throw new ResourceNotFoundException("Item not found.");
}
- while (item.ThemeSongIds.Count == 0 && request.InheritFromParent && item.GetParent() != null)
+ while (item.ThemeSongIds.Length == 0 && request.InheritFromParent && item.GetParent() != null)
{
item = item.GetParent();
}
@@ -882,7 +893,7 @@ namespace MediaBrowser.Api.Library
throw new ResourceNotFoundException("Item not found.");
}
- while (item.ThemeVideoIds.Count == 0 && request.InheritFromParent && item.GetParent() != null)
+ while (item.ThemeVideoIds.Length == 0 && request.InheritFromParent && item.GetParent() != null)
{
item = item.GetParent();
}
@@ -913,7 +924,7 @@ namespace MediaBrowser.Api.Library
: request.IncludeItemTypes.Split(',');
var user = !string.IsNullOrWhiteSpace(request.UserId) ? _userManager.GetUserById(request.UserId) : null;
-
+
var query = new InternalItemsQuery(user)
{
IncludeItemTypes = includeTypes,
diff --git a/MediaBrowser.Api/LiveTv/LiveTvService.cs b/MediaBrowser.Api/LiveTv/LiveTvService.cs
index 837a0f6a6..36bcee913 100644
--- a/MediaBrowser.Api/LiveTv/LiveTvService.cs
+++ b/MediaBrowser.Api/LiveTv/LiveTvService.cs
@@ -15,14 +15,14 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using MediaBrowser.Api.UserLibrary;
using MediaBrowser.Model.IO;
-using MediaBrowser.Api.Playback.Progressive;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities.TV;
-using MediaBrowser.Controller.IO;
using MediaBrowser.Model.Services;
using MediaBrowser.Model.System;
+using MediaBrowser.Model.Extensions;
namespace MediaBrowser.Api.LiveTv
{
@@ -374,7 +374,7 @@ namespace MediaBrowser.Api.LiveTv
public string SortBy { get; set; }
[ApiMember(Name = "SortOrder", Description = "Sort Order - Ascending,Descending", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
- public SortOrder? SortOrder { get; set; }
+ public string SortOrder { get; set; }
[ApiMember(Name = "Genres", Description = "The genres to return guide information for.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET,POST")]
public string Genres { get; set; }
@@ -649,7 +649,7 @@ namespace MediaBrowser.Api.LiveTv
{
public List<TunerChannelMapping> TunerChannels { get; set; }
public List<NameIdPair> ProviderChannels { get; set; }
- public List<NameValuePair> Mappings { get; set; }
+ public NameValuePair[] Mappings { get; set; }
public string ProviderName { get; set; }
}
@@ -734,7 +734,7 @@ namespace MediaBrowser.Api.LiveTv
outputHeaders["Content-Type"] = Model.Net.MimeTypes.GetMimeType(path);
- return new ProgressiveFileCopier(_fileSystem, path, outputHeaders, null, Logger, _environment, CancellationToken.None)
+ return new ProgressiveFileCopier(_fileSystem, path, outputHeaders, Logger, _environment, CancellationToken.None)
{
AllowEndOfFile = false
};
@@ -753,7 +753,7 @@ namespace MediaBrowser.Api.LiveTv
outputHeaders["Content-Type"] = Model.Net.MimeTypes.GetMimeType("file." + request.Container);
- return new ProgressiveFileCopier(directStreamProvider, outputHeaders, null, Logger, _environment, CancellationToken.None)
+ return new ProgressiveFileCopier(directStreamProvider, outputHeaders, Logger, _environment, CancellationToken.None)
{
AllowEndOfFile = false
};
@@ -790,7 +790,7 @@ namespace MediaBrowser.Api.LiveTv
var providerChannels = await _liveTvManager.GetChannelsFromListingsProviderData(request.ProviderId, CancellationToken.None)
.ConfigureAwait(false);
- var mappings = listingsProviderInfo.ChannelMappings.ToList();
+ var mappings = listingsProviderInfo.ChannelMappings;
var result = new ChannelMappingOptions
{
@@ -853,6 +853,8 @@ namespace MediaBrowser.Api.LiveTv
public async Task<object> Post(AddTunerHost request)
{
+ request.EnableNewHdhrChannelIds = true;
+
var result = await _liveTvManager.SaveTunerHost(request).ConfigureAwait(false);
return ToOptimizedResult(result);
}
@@ -861,7 +863,7 @@ namespace MediaBrowser.Api.LiveTv
{
var config = GetConfiguration();
- config.TunerHosts = config.TunerHosts.Where(i => !string.Equals(request.Id, i.Id, StringComparison.OrdinalIgnoreCase)).ToList();
+ config.TunerHosts = config.TunerHosts.Where(i => !string.Equals(request.Id, i.Id, StringComparison.OrdinalIgnoreCase)).ToArray();
_config.SaveConfiguration("livetv", config);
}
@@ -921,7 +923,7 @@ namespace MediaBrowser.Api.LiveTv
options.AddCurrentProgram = request.AddCurrentProgram;
- var returnArray = (await _dtoService.GetBaseItemDtos(channelResult.Items, options, user).ConfigureAwait(false)).ToArray();
+ var returnArray = _dtoService.GetBaseItemDtos(channelResult.Items, options, user);
var result = new QueryResult<BaseItemDto>
{
@@ -934,10 +936,13 @@ namespace MediaBrowser.Api.LiveTv
private void RemoveFields(DtoOptions options)
{
- options.Fields.Remove(ItemFields.CanDelete);
- options.Fields.Remove(ItemFields.CanDownload);
- options.Fields.Remove(ItemFields.DisplayPreferencesId);
- options.Fields.Remove(ItemFields.Etag);
+ var fields = options.Fields.ToList();
+
+ fields.Remove(ItemFields.CanDelete);
+ fields.Remove(ItemFields.CanDownload);
+ fields.Remove(ItemFields.DisplayPreferencesId);
+ fields.Remove(ItemFields.Etag);
+ options.Fields = fields.ToArray(fields.Count);
}
public object Get(GetChannel request)
@@ -962,7 +967,7 @@ namespace MediaBrowser.Api.LiveTv
{
var query = new ProgramQuery
{
- ChannelIds = (request.ChannelIds ?? string.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToArray(),
+ ChannelIds = ApiEntryPoint.Split(request.ChannelIds, ',', true),
UserId = request.UserId,
HasAired = request.HasAired,
EnableTotalRecordCount = request.EnableTotalRecordCount
@@ -990,8 +995,7 @@ namespace MediaBrowser.Api.LiveTv
query.StartIndex = request.StartIndex;
query.Limit = request.Limit;
- query.SortBy = (request.SortBy ?? String.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
- query.SortOrder = request.SortOrder;
+ query.OrderBy = BaseItemsRequest.GetOrderBy(request.SortBy, request.SortOrder);
query.IsNews = request.IsNews;
query.IsMovie = request.IsMovie;
query.IsSeries = request.IsSeries;
@@ -1070,12 +1074,12 @@ namespace MediaBrowser.Api.LiveTv
return ToOptimizedResult(result);
}
- public async Task<object> Get(GetRecordingSeries request)
+ public object Get(GetRecordingSeries request)
{
var options = GetDtoOptions(_authContext, request);
options.DeviceId = _authContext.GetAuthorizationInfo(Request).DeviceId;
- var result = await _liveTvManager.GetRecordingSeries(new RecordingQuery
+ var result = _liveTvManager.GetRecordingSeries(new RecordingQuery
{
ChannelId = request.ChannelId,
UserId = request.UserId,
@@ -1087,7 +1091,7 @@ namespace MediaBrowser.Api.LiveTv
IsInProgress = request.IsInProgress,
EnableTotalRecordCount = request.EnableTotalRecordCount
- }, options, CancellationToken.None).ConfigureAwait(false);
+ }, options, CancellationToken.None);
return ToOptimizedResult(result);
}
diff --git a/MediaBrowser.Api/Playback/Progressive/ProgressiveStreamWriter.cs b/MediaBrowser.Api/LiveTv/ProgressiveFileCopier.cs
index d84d889fa..9ce109fc4 100644
--- a/MediaBrowser.Api/Playback/Progressive/ProgressiveStreamWriter.cs
+++ b/MediaBrowser.Api/LiveTv/ProgressiveFileCopier.cs
@@ -1,23 +1,19 @@
-using MediaBrowser.Model.Logging;
-using System;
+using System;
+using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Controller.Net;
-using System.Collections.Generic;
-
-using MediaBrowser.Controller.IO;
using MediaBrowser.Controller.Library;
+using MediaBrowser.Model.IO;
+using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Services;
using MediaBrowser.Model.System;
-namespace MediaBrowser.Api.Playback.Progressive
+namespace MediaBrowser.Api.LiveTv
{
public class ProgressiveFileCopier : IAsyncStreamWriter, IHasHeaders
{
private readonly IFileSystem _fileSystem;
- private readonly TranscodingJob _job;
private readonly ILogger _logger;
private readonly string _path;
private readonly CancellationToken _cancellationToken;
@@ -32,22 +28,20 @@ namespace MediaBrowser.Api.Playback.Progressive
private readonly IDirectStreamProvider _directStreamProvider;
private readonly IEnvironmentInfo _environment;
- public ProgressiveFileCopier(IFileSystem fileSystem, string path, Dictionary<string, string> outputHeaders, TranscodingJob job, ILogger logger, IEnvironmentInfo environment, CancellationToken cancellationToken)
+ public ProgressiveFileCopier(IFileSystem fileSystem, string path, Dictionary<string, string> outputHeaders, ILogger logger, IEnvironmentInfo environment, CancellationToken cancellationToken)
{
_fileSystem = fileSystem;
_path = path;
_outputHeaders = outputHeaders;
- _job = job;
_logger = logger;
_cancellationToken = cancellationToken;
_environment = environment;
}
- public ProgressiveFileCopier(IDirectStreamProvider directStreamProvider, Dictionary<string, string> outputHeaders, TranscodingJob job, ILogger logger, IEnvironmentInfo environment, CancellationToken cancellationToken)
+ public ProgressiveFileCopier(IDirectStreamProvider directStreamProvider, Dictionary<string, string> outputHeaders, ILogger logger, IEnvironmentInfo environment, CancellationToken cancellationToken)
{
_directStreamProvider = directStreamProvider;
_outputHeaders = outputHeaders;
- _job = job;
_logger = logger;
_cancellationToken = cancellationToken;
_environment = environment;
@@ -77,61 +71,48 @@ namespace MediaBrowser.Api.Playback.Progressive
{
cancellationToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, _cancellationToken).Token;
- try
+ if (_directStreamProvider != null)
{
- if (_directStreamProvider != null)
- {
- await _directStreamProvider.CopyToAsync(outputStream, cancellationToken).ConfigureAwait(false);
- return;
- }
+ await _directStreamProvider.CopyToAsync(outputStream, cancellationToken).ConfigureAwait(false);
+ return;
+ }
- var eofCount = 0;
+ var eofCount = 0;
- // use non-async filestream along with read due to https://github.com/dotnet/corefx/issues/6039
- var allowAsyncFileRead = _environment.OperatingSystem != OperatingSystem.Windows;
+ // use non-async filestream along with read due to https://github.com/dotnet/corefx/issues/6039
+ var allowAsyncFileRead = _environment.OperatingSystem != MediaBrowser.Model.System.OperatingSystem.Windows;
- using (var inputStream = GetInputStream(allowAsyncFileRead))
+ using (var inputStream = GetInputStream(allowAsyncFileRead))
+ {
+ if (StartPosition > 0)
{
- if (StartPosition > 0)
+ inputStream.Position = StartPosition;
+ }
+
+ while (eofCount < 20 || !AllowEndOfFile)
+ {
+ int bytesRead;
+ if (allowAsyncFileRead)
+ {
+ bytesRead = await CopyToInternalAsync(inputStream, outputStream, cancellationToken).ConfigureAwait(false);
+ }
+ else
{
- inputStream.Position = StartPosition;
+ bytesRead = await CopyToInternalAsyncWithSyncRead(inputStream, outputStream, cancellationToken).ConfigureAwait(false);
}
- while (eofCount < 20 || !AllowEndOfFile)
+ //var position = fs.Position;
+ //_logger.Debug("Streamed {0} bytes to position {1} from file {2}", bytesRead, position, path);
+
+ if (bytesRead == 0)
{
- int bytesRead;
- if (allowAsyncFileRead)
- {
- bytesRead = await CopyToInternalAsync(inputStream, outputStream, cancellationToken).ConfigureAwait(false);
- }
- else
- {
- bytesRead = await CopyToInternalAsyncWithSyncRead(inputStream, outputStream, cancellationToken).ConfigureAwait(false);
- }
-
- //var position = fs.Position;
- //_logger.Debug("Streamed {0} bytes to position {1} from file {2}", bytesRead, position, path);
-
- if (bytesRead == 0)
- {
- if (_job == null || _job.HasExited)
- {
- eofCount++;
- }
- await Task.Delay(100, cancellationToken).ConfigureAwait(false);
- }
- else
- {
- eofCount = 0;
- }
+ eofCount++;
+ await Task.Delay(100, cancellationToken).ConfigureAwait(false);
+ }
+ else
+ {
+ eofCount = 0;
}
- }
- }
- finally
- {
- if (_job != null)
- {
- ApiEntryPoint.Instance.OnTranscodeEndRequest(_job);
}
}
}
@@ -152,11 +133,6 @@ namespace MediaBrowser.Api.Playback.Progressive
_bytesWritten += bytesRead;
totalBytesRead += bytesRead;
-
- if (_job != null)
- {
- _job.BytesDownloaded = Math.Max(_job.BytesDownloaded ?? _bytesWritten, _bytesWritten);
- }
}
}
@@ -179,11 +155,6 @@ namespace MediaBrowser.Api.Playback.Progressive
_bytesWritten += bytesRead;
totalBytesRead += bytesRead;
-
- if (_job != null)
- {
- _job.BytesDownloaded = Math.Max(_job.BytesDownloaded ?? _bytesWritten, _bytesWritten);
- }
}
}
diff --git a/MediaBrowser.Api/LocalizationService.cs b/MediaBrowser.Api/LocalizationService.cs
index 90b963149..56d32fc37 100644
--- a/MediaBrowser.Api/LocalizationService.cs
+++ b/MediaBrowser.Api/LocalizationService.cs
@@ -2,7 +2,6 @@
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Globalization;
using System.Collections.Generic;
-using System.Linq;
using MediaBrowser.Model.Services;
namespace MediaBrowser.Api
@@ -11,7 +10,7 @@ namespace MediaBrowser.Api
/// Class GetCultures
/// </summary>
[Route("/Localization/Cultures", "GET", Summary = "Gets known cultures")]
- public class GetCultures : IReturn<List<CultureDto>>
+ public class GetCultures : IReturn<CultureDto[]>
{
}
@@ -19,7 +18,7 @@ namespace MediaBrowser.Api
/// Class GetCountries
/// </summary>
[Route("/Localization/Countries", "GET", Summary = "Gets known countries")]
- public class GetCountries : IReturn<List<CountryInfo>>
+ public class GetCountries : IReturn<CountryInfo[]>
{
}
@@ -27,7 +26,7 @@ namespace MediaBrowser.Api
/// Class ParentalRatings
/// </summary>
[Route("/Localization/ParentalRatings", "GET", Summary = "Gets known parental ratings")]
- public class GetParentalRatings : IReturn<List<ParentalRating>>
+ public class GetParentalRatings : IReturn<ParentalRating[]>
{
}
@@ -35,7 +34,7 @@ namespace MediaBrowser.Api
/// Class ParentalRatings
/// </summary>
[Route("/Localization/Options", "GET", Summary = "Gets localization options")]
- public class GetLocalizationOptions : IReturn<List<LocalizatonOption>>
+ public class GetLocalizationOptions : IReturn<LocalizatonOption[]>
{
}
@@ -66,14 +65,14 @@ namespace MediaBrowser.Api
/// <returns>System.Object.</returns>
public object Get(GetParentalRatings request)
{
- var result = _localization.GetParentalRatings().ToList();
+ var result = _localization.GetParentalRatings();
return ToOptimizedResult(result);
}
public object Get(GetLocalizationOptions request)
{
- var result = _localization.GetLocalizationOptions().ToList();
+ var result = _localization.GetLocalizationOptions();
return ToOptimizedResult(result);
}
@@ -85,7 +84,7 @@ namespace MediaBrowser.Api
/// <returns>System.Object.</returns>
public object Get(GetCountries request)
{
- var result = _localization.GetCountries().ToList();
+ var result = _localization.GetCountries();
return ToOptimizedResult(result);
}
@@ -97,7 +96,7 @@ namespace MediaBrowser.Api
/// <returns>System.Object.</returns>
public object Get(GetCultures request)
{
- var result = _localization.GetCultures().ToList();
+ var result = _localization.GetCultures();
return ToOptimizedResult(result);
}
diff --git a/MediaBrowser.Api/MediaBrowser.Api.csproj b/MediaBrowser.Api/MediaBrowser.Api.csproj
index 88889e5e7..602a697bf 100644
--- a/MediaBrowser.Api/MediaBrowser.Api.csproj
+++ b/MediaBrowser.Api/MediaBrowser.Api.csproj
@@ -48,9 +48,7 @@
<Compile Include="Dlna\DlnaService.cs" />
<Compile Include="FilterService.cs" />
<Compile Include="IHasDtoOptions.cs" />
- <Compile Include="Playback\MediaInfoService.cs" />
- <Compile Include="Playback\TranscodingThrottler.cs" />
- <Compile Include="Playback\UniversalAudioService.cs" />
+ <Compile Include="LiveTv\ProgressiveFileCopier.cs" />
<Compile Include="PlaylistService.cs" />
<Compile Include="Reports\Activities\ReportActivitiesBuilder.cs" />
<Compile Include="Reports\Common\HeaderActivitiesMetadata.cs" />
@@ -99,20 +97,7 @@
<Compile Include="Movies\MoviesService.cs" />
<Compile Include="NewsService.cs" />
<Compile Include="NotificationsService.cs" />
- <Compile Include="PackageReviewService.cs" />
<Compile Include="PackageService.cs" />
- <Compile Include="Playback\Hls\BaseHlsService.cs" />
- <Compile Include="Playback\Hls\DynamicHlsService.cs" />
- <Compile Include="Playback\Hls\HlsSegmentService.cs" />
- <Compile Include="Playback\Hls\VideoHlsService.cs" />
- <Compile Include="Playback\Progressive\AudioService.cs" />
- <Compile Include="Playback\Progressive\BaseProgressiveStreamingService.cs" />
- <Compile Include="Playback\BaseStreamingService.cs" />
- <Compile Include="Playback\Progressive\ProgressiveStreamWriter.cs" />
- <Compile Include="Playback\StaticRemoteStreamWriter.cs" />
- <Compile Include="Playback\StreamRequest.cs" />
- <Compile Include="Playback\StreamState.cs" />
- <Compile Include="Playback\Progressive\VideoService.cs" />
<Compile Include="PluginService.cs" />
<Compile Include="Images\RemoteImageService.cs" />
<Compile Include="ScheduledTasks\ScheduledTaskService.cs" />
@@ -126,7 +111,6 @@
<Compile Include="System\ActivityLogWebSocketListener.cs" />
<Compile Include="System\SystemService.cs" />
<Compile Include="Movies\TrailersService.cs" />
- <Compile Include="TestService.cs" />
<Compile Include="TvShowsService.cs" />
<Compile Include="UserLibrary\ArtistsService.cs" />
<Compile Include="UserLibrary\BaseItemsByNameService.cs" />
@@ -136,7 +120,6 @@
<Compile Include="UserLibrary\ItemsService.cs" />
<Compile Include="UserLibrary\MusicGenresService.cs" />
<Compile Include="UserLibrary\PersonsService.cs" />
- <Compile Include="UserLibrary\PlaystateService.cs" />
<Compile Include="UserLibrary\StudiosService.cs" />
<Compile Include="UserLibrary\UserLibraryService.cs" />
<Compile Include="UserLibrary\UserViewsService.cs" />
diff --git a/MediaBrowser.Api/Movies/CollectionService.cs b/MediaBrowser.Api/Movies/CollectionService.cs
index 917a3bc0b..c63712f4c 100644
--- a/MediaBrowser.Api/Movies/CollectionService.cs
+++ b/MediaBrowser.Api/Movies/CollectionService.cs
@@ -4,7 +4,6 @@ using MediaBrowser.Controller.Net;
using MediaBrowser.Model.Collections;
using System;
using System.Collections.Generic;
-using System.Linq;
using System.Threading.Tasks;
using MediaBrowser.Model.Services;
@@ -71,8 +70,8 @@ namespace MediaBrowser.Api.Movies
IsLocked = request.IsLocked,
Name = request.Name,
ParentId = parentId,
- ItemIdList = (request.Ids ?? string.Empty).Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).Select(i => new Guid(i)).ToList(),
- UserIds = new List<Guid> { new Guid(userId) }
+ ItemIdList = SplitValue(request.Ids, ','),
+ UserIds = new string[] { userId }
}).ConfigureAwait(false);
@@ -88,14 +87,14 @@ namespace MediaBrowser.Api.Movies
public void Post(AddToCollection request)
{
- var task = _collectionManager.AddToCollection(new Guid(request.Id), request.Ids.Split(',').Select(i => new Guid(i)));
+ var task = _collectionManager.AddToCollection(new Guid(request.Id), SplitValue(request.Ids, ','));
Task.WaitAll(task);
}
public void Delete(RemoveFromCollection request)
{
- var task = _collectionManager.RemoveFromCollection(new Guid(request.Id), request.Ids.Split(',').Select(i => new Guid(i)));
+ var task = _collectionManager.RemoveFromCollection(new Guid(request.Id), SplitValue(request.Ids, ','));
Task.WaitAll(task);
}
diff --git a/MediaBrowser.Api/Movies/MoviesService.cs b/MediaBrowser.Api/Movies/MoviesService.cs
index e20fa2cca..254c93b33 100644
--- a/MediaBrowser.Api/Movies/MoviesService.cs
+++ b/MediaBrowser.Api/Movies/MoviesService.cs
@@ -113,16 +113,16 @@ namespace MediaBrowser.Api.Movies
/// </summary>
/// <param name="request">The request.</param>
/// <returns>System.Object.</returns>
- public async Task<object> Get(GetSimilarMovies request)
+ public object Get(GetSimilarMovies request)
{
- var result = await GetSimilarItemsResult(request).ConfigureAwait(false);
+ var result = GetSimilarItemsResult(request);
return ToOptimizedSerializedResultUsingCache(result);
}
- public async Task<object> Get(GetSimilarTrailers request)
+ public object Get(GetSimilarTrailers request)
{
- var result = await GetSimilarItemsResult(request).ConfigureAwait(false);
+ var result = GetSimilarItemsResult(request);
return ToOptimizedSerializedResultUsingCache(result);
}
@@ -138,7 +138,7 @@ namespace MediaBrowser.Api.Movies
return ToOptimizedResult(result);
}
- private async Task<QueryResult<BaseItemDto>> GetSimilarItemsResult(BaseGetSimilarItemsFromItem request)
+ private QueryResult<BaseItemDto> GetSimilarItemsResult(BaseGetSimilarItemsFromItem request)
{
var user = !string.IsNullOrWhiteSpace(request.UserId) ? _userManager.GetUserById(request.UserId) : null;
@@ -158,17 +158,19 @@ namespace MediaBrowser.Api.Movies
var itemsResult = _libraryManager.GetItemList(new InternalItemsQuery(user)
{
Limit = request.Limit,
- IncludeItemTypes = itemTypes.ToArray(),
+ IncludeItemTypes = itemTypes.ToArray(itemTypes.Count),
IsMovie = true,
SimilarTo = item,
EnableGroupByMetadataKey = true,
DtoOptions = dtoOptions
- }).ToList();
+ });
+
+ var returnList = _dtoService.GetBaseItemDtos(itemsResult, dtoOptions, user);
var result = new QueryResult<BaseItemDto>
{
- Items = (await _dtoService.GetBaseItemDtos(itemsResult, dtoOptions, user).ConfigureAwait(false)).ToArray(),
+ Items = returnList,
TotalRecordCount = itemsResult.Count
};
@@ -191,8 +193,7 @@ namespace MediaBrowser.Api.Movies
//typeof(LiveTvProgram).Name
},
// IsMovie = true
- SortBy = new[] { ItemSortBy.DatePlayed, ItemSortBy.Random },
- SortOrder = SortOrder.Descending,
+ OrderBy = new[] { ItemSortBy.DatePlayed, ItemSortBy.Random }.Select(i => new Tuple<string, SortOrder>(i, SortOrder.Descending)).ToArray(),
Limit = 7,
ParentId = parentIdGuid,
Recursive = true,
@@ -200,7 +201,7 @@ namespace MediaBrowser.Api.Movies
DtoOptions = dtoOptions
};
- var recentlyPlayedMovies = _libraryManager.GetItemList(query).ToList();
+ var recentlyPlayedMovies = _libraryManager.GetItemList(query);
var itemTypes = new List<string> { typeof(Movie).Name };
if (_config.Configuration.EnableExternalContentInSuggestions)
@@ -211,19 +212,18 @@ namespace MediaBrowser.Api.Movies
var likedMovies = _libraryManager.GetItemList(new InternalItemsQuery(user)
{
- IncludeItemTypes = itemTypes.ToArray(),
+ IncludeItemTypes = itemTypes.ToArray(itemTypes.Count),
IsMovie = true,
- SortBy = new[] { ItemSortBy.Random },
- SortOrder = SortOrder.Descending,
+ OrderBy = new[] { ItemSortBy.Random }.Select(i => new Tuple<string, SortOrder>(i, SortOrder.Descending)).ToArray(),
Limit = 10,
IsFavoriteOrLiked = true,
- ExcludeItemIds = recentlyPlayedMovies.Select(i => i.Id.ToString("N")).ToArray(),
+ ExcludeItemIds = recentlyPlayedMovies.Select(i => i.Id.ToString("N")).ToArray(recentlyPlayedMovies.Count),
EnableGroupByMetadataKey = true,
ParentId = parentIdGuid,
Recursive = true,
DtoOptions = dtoOptions
- }).ToList();
+ });
var mostRecentMovies = recentlyPlayedMovies.Take(6).ToList();
// Get recently played directors
@@ -300,7 +300,7 @@ namespace MediaBrowser.Api.Movies
// Account for duplicates by imdb id, since the database doesn't support this yet
Limit = itemLimit + 2,
PersonTypes = new[] { PersonType.Director },
- IncludeItemTypes = itemTypes.ToArray(),
+ IncludeItemTypes = itemTypes.ToArray(itemTypes.Count),
IsMovie = true,
EnableGroupByMetadataKey = true,
DtoOptions = dtoOptions
@@ -311,12 +311,14 @@ namespace MediaBrowser.Api.Movies
if (items.Count > 0)
{
+ var returnItems = _dtoService.GetBaseItemDtos(items, dtoOptions, user);
+
yield return new RecommendationDto
{
BaselineItemName = name,
CategoryId = name.GetMD5().ToString("N"),
RecommendationType = type,
- Items = _dtoService.GetBaseItemDtos(items, dtoOptions, user).Result.ToArray()
+ Items = returnItems
};
}
}
@@ -338,7 +340,7 @@ namespace MediaBrowser.Api.Movies
Person = name,
// Account for duplicates by imdb id, since the database doesn't support this yet
Limit = itemLimit + 2,
- IncludeItemTypes = itemTypes.ToArray(),
+ IncludeItemTypes = itemTypes.ToArray(itemTypes.Count),
IsMovie = true,
EnableGroupByMetadataKey = true,
DtoOptions = dtoOptions
@@ -349,12 +351,14 @@ namespace MediaBrowser.Api.Movies
if (items.Count > 0)
{
+ var returnItems = _dtoService.GetBaseItemDtos(items, dtoOptions, user);
+
yield return new RecommendationDto
{
BaselineItemName = name,
CategoryId = name.GetMD5().ToString("N"),
RecommendationType = type,
- Items = _dtoService.GetBaseItemDtos(items, dtoOptions, user).Result.ToArray()
+ Items = returnItems
};
}
}
@@ -374,28 +378,30 @@ namespace MediaBrowser.Api.Movies
var similar = _libraryManager.GetItemList(new InternalItemsQuery(user)
{
Limit = itemLimit,
- IncludeItemTypes = itemTypes.ToArray(),
+ IncludeItemTypes = itemTypes.ToArray(itemTypes.Count),
IsMovie = true,
SimilarTo = item,
EnableGroupByMetadataKey = true,
DtoOptions = dtoOptions
- }).ToList();
+ });
if (similar.Count > 0)
{
+ var returnItems = _dtoService.GetBaseItemDtos(similar, dtoOptions, user);
+
yield return new RecommendationDto
{
BaselineItemName = item.Name,
CategoryId = item.Id.ToString("N"),
RecommendationType = type,
- Items = _dtoService.GetBaseItemDtos(similar, dtoOptions, user).Result.ToArray()
+ Items = returnItems
};
}
}
}
- private IEnumerable<string> GetActors(IEnumerable<BaseItem> items)
+ private IEnumerable<string> GetActors(List<BaseItem> items)
{
var people = _libraryManager.GetPeople(new InternalPeopleQuery
{
@@ -414,11 +420,11 @@ namespace MediaBrowser.Api.Movies
.DistinctNames();
}
- private IEnumerable<string> GetDirectors(IEnumerable<BaseItem> items)
+ private IEnumerable<string> GetDirectors(List<BaseItem> items)
{
var people = _libraryManager.GetPeople(new InternalPeopleQuery
{
- PersonTypes = new List<string>
+ PersonTypes = new string[]
{
PersonType.Director
}
diff --git a/MediaBrowser.Api/Movies/TrailersService.cs b/MediaBrowser.Api/Movies/TrailersService.cs
index eb5365ab8..45b07712f 100644
--- a/MediaBrowser.Api/Movies/TrailersService.cs
+++ b/MediaBrowser.Api/Movies/TrailersService.cs
@@ -4,6 +4,7 @@ using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Net;
using MediaBrowser.Model.Querying;
using MediaBrowser.Controller.Collections;
+using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Globalization;
using MediaBrowser.Model.Serialization;
using MediaBrowser.Model.Services;
@@ -11,7 +12,7 @@ using MediaBrowser.Model.Services;
namespace MediaBrowser.Api.Movies
{
[Route("/Trailers", "GET", Summary = "Finds movies and trailers similar to a given trailer.")]
- public class Getrailers : BaseItemsRequest, IReturn<ItemsResult>
+ public class Getrailers : BaseItemsRequest, IReturn<QueryResult<BaseItemDto>>
{
}
diff --git a/MediaBrowser.Api/Music/AlbumsService.cs b/MediaBrowser.Api/Music/AlbumsService.cs
index bc7ae2be2..d7986fa50 100644
--- a/MediaBrowser.Api/Music/AlbumsService.cs
+++ b/MediaBrowser.Api/Music/AlbumsService.cs
@@ -7,7 +7,6 @@ using MediaBrowser.Controller.Persistence;
using System;
using System.Collections.Generic;
using System.Linq;
-using System.Threading.Tasks;
using MediaBrowser.Model.Services;
namespace MediaBrowser.Api.Music
@@ -52,43 +51,43 @@ namespace MediaBrowser.Api.Music
_authContext = authContext;
}
- public async Task<object> Get(GetSimilarArtists request)
+ public object Get(GetSimilarArtists request)
{
var dtoOptions = GetDtoOptions(_authContext, request);
- var result = await SimilarItemsHelper.GetSimilarItemsResult(dtoOptions, _userManager,
+ var result = SimilarItemsHelper.GetSimilarItemsResult(dtoOptions, _userManager,
_itemRepo,
_libraryManager,
_userDataRepository,
_dtoService,
Logger,
request, new[] { typeof(MusicArtist) },
- SimilarItemsHelper.GetSimiliarityScore).ConfigureAwait(false);
+ SimilarItemsHelper.GetSimiliarityScore);
return ToOptimizedSerializedResultUsingCache(result);
}
-
+
/// <summary>
/// Gets the specified request.
/// </summary>
/// <param name="request">The request.</param>
/// <returns>System.Object.</returns>
- public async Task<object> Get(GetSimilarAlbums request)
+ public object Get(GetSimilarAlbums request)
{
var dtoOptions = GetDtoOptions(_authContext, request);
- var result = await SimilarItemsHelper.GetSimilarItemsResult(dtoOptions, _userManager,
+ var result = SimilarItemsHelper.GetSimilarItemsResult(dtoOptions, _userManager,
_itemRepo,
_libraryManager,
_userDataRepository,
_dtoService,
Logger,
request, new[] { typeof(MusicAlbum) },
- GetAlbumSimilarityScore).ConfigureAwait(false);
+ GetAlbumSimilarityScore);
return ToOptimizedSerializedResultUsingCache(result);
}
-
+
/// <summary>
/// Gets the album similarity score.
/// </summary>
diff --git a/MediaBrowser.Api/Music/InstantMixService.cs b/MediaBrowser.Api/Music/InstantMixService.cs
index 3cb29de07..8a18298f1 100644
--- a/MediaBrowser.Api/Music/InstantMixService.cs
+++ b/MediaBrowser.Api/Music/InstantMixService.cs
@@ -8,7 +8,9 @@ using MediaBrowser.Model.Querying;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
+using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Services;
+using MediaBrowser.Model.Extensions;
namespace MediaBrowser.Api.Music
{
@@ -79,7 +81,7 @@ namespace MediaBrowser.Api.Music
_authContext = authContext;
}
- public Task<object> Get(GetInstantMixFromItem request)
+ public object Get(GetInstantMixFromItem request)
{
var item = _libraryManager.GetItemById(request.Id);
@@ -92,7 +94,7 @@ namespace MediaBrowser.Api.Music
return GetResult(items, user, request, dtoOptions);
}
- public Task<object> Get(GetInstantMixFromArtistId request)
+ public object Get(GetInstantMixFromArtistId request)
{
var item = _libraryManager.GetItemById(request.Id);
@@ -105,7 +107,7 @@ namespace MediaBrowser.Api.Music
return GetResult(items, user, request, dtoOptions);
}
- public Task<object> Get(GetInstantMixFromMusicGenreId request)
+ public object Get(GetInstantMixFromMusicGenreId request)
{
var item = _libraryManager.GetItemById(request.Id);
@@ -118,7 +120,7 @@ namespace MediaBrowser.Api.Music
return GetResult(items, user, request, dtoOptions);
}
- public Task<object> Get(GetInstantMixFromSong request)
+ public object Get(GetInstantMixFromSong request)
{
var item = _libraryManager.GetItemById(request.Id);
@@ -131,7 +133,7 @@ namespace MediaBrowser.Api.Music
return GetResult(items, user, request, dtoOptions);
}
- public Task<object> Get(GetInstantMixFromAlbum request)
+ public object Get(GetInstantMixFromAlbum request)
{
var album = _libraryManager.GetItemById(request.Id);
@@ -144,7 +146,7 @@ namespace MediaBrowser.Api.Music
return GetResult(items, user, request, dtoOptions);
}
- public Task<object> Get(GetInstantMixFromPlaylist request)
+ public object Get(GetInstantMixFromPlaylist request)
{
var playlist = (Playlist)_libraryManager.GetItemById(request.Id);
@@ -157,7 +159,7 @@ namespace MediaBrowser.Api.Music
return GetResult(items, user, request, dtoOptions);
}
- public Task<object> Get(GetInstantMixFromMusicGenre request)
+ public object Get(GetInstantMixFromMusicGenre request)
{
var user = _userManager.GetUserById(request.UserId);
@@ -168,7 +170,7 @@ namespace MediaBrowser.Api.Music
return GetResult(items, user, request, dtoOptions);
}
- public Task<object> Get(GetInstantMixFromArtist request)
+ public object Get(GetInstantMixFromArtist request)
{
var user = _userManager.GetUserById(request.UserId);
var artist = _libraryManager.GetArtist(request.Name, new DtoOptions(false));
@@ -180,16 +182,23 @@ namespace MediaBrowser.Api.Music
return GetResult(items, user, request, dtoOptions);
}
- private async Task<object> GetResult(IEnumerable<Audio> items, User user, BaseGetSimilarItems request, DtoOptions dtoOptions)
+ private object GetResult(List<BaseItem> items, User user, BaseGetSimilarItems request, DtoOptions dtoOptions)
{
- var list = items.ToList();
+ var list = items;
- var result = new ItemsResult
+ var result = new QueryResult<BaseItemDto>
{
TotalRecordCount = list.Count
};
- result.Items = (await _dtoService.GetBaseItemDtos(list.Take(request.Limit ?? list.Count), dtoOptions, user).ConfigureAwait(false)).ToArray();
+ if (request.Limit.HasValue)
+ {
+ list = list.Take(request.Limit.Value).ToList();
+ }
+
+ var returnList = _dtoService.GetBaseItemDtos(list, dtoOptions, user);
+
+ result.Items = returnList;
return ToOptimizedResult(result);
}
diff --git a/MediaBrowser.Api/NotificationsService.cs b/MediaBrowser.Api/NotificationsService.cs
index 58e413cef..4876351fc 100644
--- a/MediaBrowser.Api/NotificationsService.cs
+++ b/MediaBrowser.Api/NotificationsService.cs
@@ -99,7 +99,7 @@ namespace MediaBrowser.Api
public object Get(GetNotificationTypes request)
{
- var result = _notificationManager.GetNotificationTypes().ToList();
+ var result = _notificationManager.GetNotificationTypes();
return ToOptimizedResult(result);
}
diff --git a/MediaBrowser.Api/PackageReviewService.cs b/MediaBrowser.Api/PackageReviewService.cs
deleted file mode 100644
index baf1adc19..000000000
--- a/MediaBrowser.Api/PackageReviewService.cs
+++ /dev/null
@@ -1,162 +0,0 @@
-using MediaBrowser.Common.Net;
-using MediaBrowser.Controller;
-using MediaBrowser.Controller.Net;
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Serialization;
-using System.Collections.Generic;
-using System.Globalization;
-using System.Net;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Model.Services;
-
-namespace MediaBrowser.Api
-{
- /// <summary>
- /// Class InstallPackage
- /// </summary>
- [Route("/Packages/Reviews/{Id}", "POST", Summary = "Creates or updates a package review")]
- public class CreateReviewRequest : IReturnVoid
- {
- /// <summary>
- /// Gets or sets the Id.
- /// </summary>
- /// <value>The Id.</value>
- [ApiMember(Name = "Id", Description = "Package Id", IsRequired = true, DataType = "int", ParameterType = "path", Verb = "POST")]
- public int Id { get; set; }
-
- /// <summary>
- /// Gets or sets the rating.
- /// </summary>
- /// <value>The review.</value>
- [ApiMember(Name = "Rating", Description = "The rating value (1-5)", IsRequired = true, DataType = "int", ParameterType = "query", Verb = "POST")]
- public int Rating { get; set; }
-
- /// <summary>
- /// Gets or sets the recommend value.
- /// </summary>
- /// <value>Whether or not this review recommends this item.</value>
- [ApiMember(Name = "Recommend", Description = "Whether or not this review recommends this item", IsRequired = true, DataType = "bool", ParameterType = "query", Verb = "POST")]
- public bool Recommend { get; set; }
-
- /// <summary>
- /// Gets or sets the title.
- /// </summary>
- /// <value>The title.</value>
- [ApiMember(Name = "Title", Description = "Optional short description of review.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")]
- public string Title { get; set; }
-
- /// <summary>
- /// Gets or sets the full review.
- /// </summary>
- /// <value>The full review.</value>
- [ApiMember(Name = "Review", Description = "Optional full review.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")]
- public string Review { get; set; }
- }
-
- /// <summary>
- /// Class InstallPackage
- /// </summary>
- [Route("/Packages/{Id}/Reviews", "GET", Summary = "Gets reviews for a package")]
- public class ReviewRequest : IReturn<List<PackageReviewInfo>>
- {
- /// <summary>
- /// Gets or sets the Id.
- /// </summary>
- /// <value>The Id.</value>
- [ApiMember(Name = "Id", Description = "Package Id", IsRequired = true, DataType = "int", ParameterType = "path", Verb = "GET")]
- public int Id { get; set; }
-
- /// <summary>
- /// Gets or sets the max rating.
- /// </summary>
- /// <value>The max rating.</value>
- [ApiMember(Name = "MaxRating", Description = "Retrieve only reviews less than or equal to this", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
- public int MaxRating { get; set; }
-
- /// <summary>
- /// Gets or sets the min rating.
- /// </summary>
- /// <value>The max rating.</value>
- [ApiMember(Name = "MinRating", Description = "Retrieve only reviews greator than or equal to this", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
- public int MinRating { get; set; }
-
- /// <summary>
- /// Only retrieve reviews with at least a short review.
- /// </summary>
- /// <value>True if should only get reviews with a title.</value>
- [ApiMember(Name = "ForceTitle", Description = "Whether or not to restrict results to those with a title", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
- public bool ForceTitle { get; set; }
-
- /// <summary>
- /// Gets or sets the limit for the query.
- /// </summary>
- /// <value>The max rating.</value>
- [ApiMember(Name = "Limit", Description = "Limit the result to this many reviews (ordered by latest)", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
- public int Limit { get; set; }
-
- }
-
- [Authenticated]
- public class PackageReviewService : BaseApiService
- {
- private readonly IHttpClient _httpClient;
- private readonly IJsonSerializer _serializer;
- private const string MbAdminUrl = "https://www.mb3admin.com/admin/";
- private readonly IServerApplicationHost _appHost;
-
- public PackageReviewService(IHttpClient httpClient, IJsonSerializer serializer, IServerApplicationHost appHost)
- {
- _httpClient = httpClient;
- _serializer = serializer;
- _appHost = appHost;
- }
-
- public async Task<object> Get(ReviewRequest request)
- {
- var parms = "?id=" + request.Id;
-
- if (request.MaxRating > 0)
- {
- parms += "&max=" + request.MaxRating;
- }
- if (request.MinRating > 0)
- {
- parms += "&min=" + request.MinRating;
- }
- if (request.MinRating > 0)
- {
- parms += "&limit=" + request.Limit;
- }
- if (request.ForceTitle)
- {
- parms += "&title=true";
- }
-
- using (var result = await _httpClient.Get(MbAdminUrl + "/service/packageReview/retrieve" + parms, CancellationToken.None)
- .ConfigureAwait(false))
- {
- var reviews = _serializer.DeserializeFromStream<List<PackageReviewInfo>>(result);
-
- return ToOptimizedResult(reviews);
- }
- }
-
- public void Post(CreateReviewRequest request)
- {
- var reviewText = WebUtility.HtmlEncode(request.Review ?? string.Empty);
- var title = WebUtility.HtmlEncode(request.Title ?? string.Empty);
-
- var review = new Dictionary<string, string>
- { { "id", request.Id.ToString(CultureInfo.InvariantCulture) },
- { "mac", _appHost.SystemId },
- { "rating", request.Rating.ToString(CultureInfo.InvariantCulture) },
- { "recommend", request.Recommend.ToString() },
- { "title", title },
- { "review", reviewText },
- };
-
- Task.WaitAll(_httpClient.Post(MbAdminUrl + "/service/packageReview/update", review, CancellationToken.None));
- }
- }
-}
diff --git a/MediaBrowser.Api/PackageService.cs b/MediaBrowser.Api/PackageService.cs
index 64424795f..79dda8702 100644
--- a/MediaBrowser.Api/PackageService.cs
+++ b/MediaBrowser.Api/PackageService.cs
@@ -40,7 +40,7 @@ namespace MediaBrowser.Api
/// </summary>
[Route("/Packages", "GET", Summary = "Gets available packages")]
[Authenticated]
- public class GetPackages : IReturn<List<PackageInfo>>
+ public class GetPackages : IReturn<PackageInfo[]>
{
/// <summary>
/// Gets or sets the name.
@@ -66,7 +66,7 @@ namespace MediaBrowser.Api
/// </summary>
[Route("/Packages/Updates", "GET", Summary = "Gets available package updates for currently installed packages")]
[Authenticated(Roles = "Admin")]
- public class GetPackageVersionUpdates : IReturn<List<PackageVersionInfo>>
+ public class GetPackageVersionUpdates : IReturn<PackageVersionInfo[]>
{
/// <summary>
/// Gets or sets the name.
@@ -148,24 +148,26 @@ namespace MediaBrowser.Api
/// <returns>System.Object.</returns>
public object Get(GetPackageVersionUpdates request)
{
- var result = new List<PackageVersionInfo>();
+ PackageVersionInfo[] result = null;
if (string.Equals(request.PackageType, "UserInstalled", StringComparison.OrdinalIgnoreCase) || string.Equals(request.PackageType, "All", StringComparison.OrdinalIgnoreCase))
{
- result.AddRange(_installationManager.GetAvailablePluginUpdates(_appHost.ApplicationVersion, false, CancellationToken.None).Result.ToList());
+ result = _installationManager.GetAvailablePluginUpdates(_appHost.ApplicationVersion, false, CancellationToken.None).Result.ToArray();
}
- else if (string.Equals(request.PackageType, "System", StringComparison.OrdinalIgnoreCase) || string.Equals(request.PackageType, "All", StringComparison.OrdinalIgnoreCase))
+ else if (string.Equals(request.PackageType, "System", StringComparison.OrdinalIgnoreCase) ||
+ string.Equals(request.PackageType, "All", StringComparison.OrdinalIgnoreCase))
{
- var updateCheckResult = _appHost.CheckForApplicationUpdate(CancellationToken.None, new SimpleProgress<double>()).Result;
+ var updateCheckResult = _appHost
+ .CheckForApplicationUpdate(CancellationToken.None, new SimpleProgress<double>()).Result;
if (updateCheckResult.IsUpdateAvailable)
{
- result.Add(updateCheckResult.Package);
+ result = new PackageVersionInfo[] {updateCheckResult.Package};
}
}
- return ToOptimizedResult(result);
+ return ToOptimizedResult(result ?? new PackageVersionInfo[] { });
}
/// <summary>
@@ -176,10 +178,9 @@ namespace MediaBrowser.Api
public object Get(GetPackage request)
{
var packages = _installationManager.GetAvailablePackages(CancellationToken.None, applicationVersion: _appHost.ApplicationVersion).Result;
- var list = packages.ToList();
- var result = list.FirstOrDefault(p => string.Equals(p.guid, request.AssemblyGuid ?? "none", StringComparison.OrdinalIgnoreCase))
- ?? list.FirstOrDefault(p => p.name.Equals(request.Name, StringComparison.OrdinalIgnoreCase));
+ var result = packages.FirstOrDefault(p => string.Equals(p.guid, request.AssemblyGuid ?? "none", StringComparison.OrdinalIgnoreCase))
+ ?? packages.FirstOrDefault(p => p.name.Equals(request.Name, StringComparison.OrdinalIgnoreCase));
return ToOptimizedResult(result);
}
@@ -191,7 +192,7 @@ namespace MediaBrowser.Api
/// <returns>System.Object.</returns>
public async Task<object> Get(GetPackages request)
{
- var packages = await _installationManager.GetAvailablePackages(CancellationToken.None, false, request.PackageType, _appHost.ApplicationVersion).ConfigureAwait(false);
+ IEnumerable<PackageInfo> packages = await _installationManager.GetAvailablePackages(CancellationToken.None, false, request.PackageType, _appHost.ApplicationVersion).ConfigureAwait(false);
if (!string.IsNullOrEmpty(request.TargetSystems))
{
@@ -215,7 +216,7 @@ namespace MediaBrowser.Api
packages = packages.Where(p => p.enableInAppStore == request.IsAppStoreEnabled.Value);
}
- return ToOptimizedResult(packages.ToList());
+ return ToOptimizedResult(packages.ToArray());
}
/// <summary>
diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs
deleted file mode 100644
index c300fcce3..000000000
--- a/MediaBrowser.Api/Playback/BaseStreamingService.cs
+++ /dev/null
@@ -1,1024 +0,0 @@
-using MediaBrowser.Common.Extensions;
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Devices;
-using MediaBrowser.Controller.Dlna;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.MediaEncoding;
-using MediaBrowser.Model.Dlna;
-using MediaBrowser.Model.Dto;
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Extensions;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Model.MediaInfo;
-using MediaBrowser.Model.Serialization;
-using System;
-using System.Collections.Generic;
-using System.Globalization;
-using System.IO;
-using System.Linq;
-using System.Text;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Common.Net;
-using MediaBrowser.Controller;
-using MediaBrowser.Controller.Net;
-using MediaBrowser.Model.Configuration;
-using MediaBrowser.Model.Diagnostics;
-
-namespace MediaBrowser.Api.Playback
-{
- /// <summary>
- /// Class BaseStreamingService
- /// </summary>
- public abstract class BaseStreamingService : BaseApiService
- {
- /// <summary>
- /// Gets or sets the application paths.
- /// </summary>
- /// <value>The application paths.</value>
- protected IServerConfigurationManager ServerConfigurationManager { get; private set; }
-
- /// <summary>
- /// Gets or sets the user manager.
- /// </summary>
- /// <value>The user manager.</value>
- protected IUserManager UserManager { get; private set; }
-
- /// <summary>
- /// Gets or sets the library manager.
- /// </summary>
- /// <value>The library manager.</value>
- protected ILibraryManager LibraryManager { get; private set; }
-
- /// <summary>
- /// Gets or sets the iso manager.
- /// </summary>
- /// <value>The iso manager.</value>
- protected IIsoManager IsoManager { get; private set; }
-
- /// <summary>
- /// Gets or sets the media encoder.
- /// </summary>
- /// <value>The media encoder.</value>
- protected IMediaEncoder MediaEncoder { get; private set; }
-
- protected IFileSystem FileSystem { get; private set; }
-
- protected IDlnaManager DlnaManager { get; private set; }
- protected IDeviceManager DeviceManager { get; private set; }
- protected ISubtitleEncoder SubtitleEncoder { get; private set; }
- protected IMediaSourceManager MediaSourceManager { get; private set; }
- protected IZipClient ZipClient { get; private set; }
- protected IJsonSerializer JsonSerializer { get; private set; }
-
- public static IServerApplicationHost AppHost;
- public static IHttpClient HttpClient;
- protected IAuthorizationContext AuthorizationContext { get; private set; }
-
- protected EncodingHelper EncodingHelper { get; set; }
-
- /// <summary>
- /// Initializes a new instance of the <see cref="BaseStreamingService" /> class.
- /// </summary>
- protected BaseStreamingService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IJsonSerializer jsonSerializer, IAuthorizationContext authorizationContext)
- {
- JsonSerializer = jsonSerializer;
- AuthorizationContext = authorizationContext;
- ZipClient = zipClient;
- MediaSourceManager = mediaSourceManager;
- DeviceManager = deviceManager;
- SubtitleEncoder = subtitleEncoder;
- DlnaManager = dlnaManager;
- FileSystem = fileSystem;
- ServerConfigurationManager = serverConfig;
- UserManager = userManager;
- LibraryManager = libraryManager;
- IsoManager = isoManager;
- MediaEncoder = mediaEncoder;
- EncodingHelper = new EncodingHelper(MediaEncoder, serverConfig, FileSystem, SubtitleEncoder);
- }
-
- /// <summary>
- /// Gets the command line arguments.
- /// </summary>
- protected abstract string GetCommandLineArguments(string outputPath, EncodingOptions encodingOptions, StreamState state, bool isEncoding);
-
- /// <summary>
- /// Gets the type of the transcoding job.
- /// </summary>
- /// <value>The type of the transcoding job.</value>
- protected abstract TranscodingJobType TranscodingJobType { get; }
-
- /// <summary>
- /// Gets the output file extension.
- /// </summary>
- /// <param name="state">The state.</param>
- /// <returns>System.String.</returns>
- protected virtual string GetOutputFileExtension(StreamState state)
- {
- return Path.GetExtension(state.RequestedUrl);
- }
-
- /// <summary>
- /// Gets the output file path.
- /// </summary>
- private string GetOutputFilePath(StreamState state, EncodingOptions encodingOptions, string outputFileExtension)
- {
- var folder = ServerConfigurationManager.ApplicationPaths.TranscodingTempPath;
-
- var data = GetCommandLineArguments("dummy\\dummy", encodingOptions, state, false);
-
- data += "-" + (state.Request.DeviceId ?? string.Empty);
- data += "-" + (state.Request.PlaySessionId ?? string.Empty);
-
- var dataHash = data.GetMD5().ToString("N");
-
- if (EnableOutputInSubFolder)
- {
- return Path.Combine(folder, dataHash, dataHash + (outputFileExtension ?? string.Empty).ToLower());
- }
-
- return Path.Combine(folder, dataHash + (outputFileExtension ?? string.Empty).ToLower());
- }
-
- protected virtual bool EnableOutputInSubFolder
- {
- get { return false; }
- }
-
- protected readonly CultureInfo UsCulture = new CultureInfo("en-US");
-
- protected virtual string GetDefaultH264Preset()
- {
- return "superfast";
- }
-
- private async Task AcquireResources(StreamState state, CancellationTokenSource cancellationTokenSource)
- {
- if (state.VideoType == VideoType.Iso && state.IsoType.HasValue && IsoManager.CanMount(state.MediaPath))
- {
- state.IsoMount = await IsoManager.Mount(state.MediaPath, cancellationTokenSource.Token).ConfigureAwait(false);
- }
-
- if (state.MediaSource.RequiresOpening && string.IsNullOrWhiteSpace(state.Request.LiveStreamId))
- {
- var liveStreamResponse = await MediaSourceManager.OpenLiveStream(new LiveStreamRequest
- {
- OpenToken = state.MediaSource.OpenToken
-
- }, cancellationTokenSource.Token).ConfigureAwait(false);
-
- EncodingHelper.AttachMediaSourceInfo(state, liveStreamResponse.MediaSource, state.RequestedUrl);
-
- if (state.VideoRequest != null)
- {
- EncodingHelper.TryStreamCopy(state);
- }
- }
-
- if (state.MediaSource.BufferMs.HasValue)
- {
- await Task.Delay(state.MediaSource.BufferMs.Value, cancellationTokenSource.Token).ConfigureAwait(false);
- }
- }
-
- /// <summary>
- /// Starts the FFMPEG.
- /// </summary>
- /// <param name="state">The state.</param>
- /// <param name="outputPath">The output path.</param>
- /// <param name="cancellationTokenSource">The cancellation token source.</param>
- /// <param name="workingDirectory">The working directory.</param>
- /// <returns>Task.</returns>
- protected async Task<TranscodingJob> StartFfMpeg(StreamState state,
- string outputPath,
- CancellationTokenSource cancellationTokenSource,
- string workingDirectory = null)
- {
- FileSystem.CreateDirectory(FileSystem.GetDirectoryName(outputPath));
-
- await AcquireResources(state, cancellationTokenSource).ConfigureAwait(false);
-
- if (state.VideoRequest != null && !string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase))
- {
- var auth = AuthorizationContext.GetAuthorizationInfo(Request);
- if (!string.IsNullOrWhiteSpace(auth.UserId))
- {
- var user = UserManager.GetUserById(auth.UserId);
- if (!user.Policy.EnableVideoPlaybackTranscoding)
- {
- ApiEntryPoint.Instance.OnTranscodeFailedToStart(outputPath, TranscodingJobType, state);
-
- throw new ArgumentException("User does not have access to video transcoding");
- }
- }
- }
-
- var encodingOptions = ApiEntryPoint.Instance.GetEncodingOptions();
-
- var transcodingId = Guid.NewGuid().ToString("N");
- var commandLineArgs = GetCommandLineArguments(outputPath, encodingOptions, state, true);
-
- var process = ApiEntryPoint.Instance.ProcessFactory.Create(new ProcessOptions
- {
- CreateNoWindow = true,
- UseShellExecute = false,
-
- // Must consume both stdout and stderr or deadlocks may occur
- //RedirectStandardOutput = true,
- RedirectStandardError = true,
- RedirectStandardInput = true,
-
- FileName = MediaEncoder.EncoderPath,
- Arguments = commandLineArgs,
-
- IsHidden = true,
- ErrorDialog = false,
- EnableRaisingEvents = true,
- WorkingDirectory = !string.IsNullOrWhiteSpace(workingDirectory) ? workingDirectory : null
- });
-
- var transcodingJob = ApiEntryPoint.Instance.OnTranscodeBeginning(outputPath,
- state.Request.PlaySessionId,
- state.MediaSource.LiveStreamId,
- transcodingId,
- TranscodingJobType,
- process,
- state.Request.DeviceId,
- state,
- cancellationTokenSource);
-
- var commandLineLogMessage = process.StartInfo.FileName + " " + process.StartInfo.Arguments;
- Logger.Info(commandLineLogMessage);
-
- var logFilePrefix = "ffmpeg-transcode";
- if (state.VideoRequest != null && string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase) && string.Equals(state.OutputAudioCodec, "copy", StringComparison.OrdinalIgnoreCase))
- {
- logFilePrefix = "ffmpeg-directstream";
- }
- else if (state.VideoRequest != null && string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase))
- {
- logFilePrefix = "ffmpeg-remux";
- }
-
- var logFilePath = Path.Combine(ServerConfigurationManager.ApplicationPaths.LogDirectoryPath, logFilePrefix + "-" + Guid.NewGuid() + ".txt");
- FileSystem.CreateDirectory(FileSystem.GetDirectoryName(logFilePath));
-
- // FFMpeg writes debug/error info to stderr. This is useful when debugging so let's put it in the log directory.
- state.LogFileStream = FileSystem.GetFileStream(logFilePath, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read, true);
-
- var commandLineLogMessageBytes = Encoding.UTF8.GetBytes(Request.AbsoluteUri + Environment.NewLine + Environment.NewLine + JsonSerializer.SerializeToString(state.MediaSource) + Environment.NewLine + Environment.NewLine + commandLineLogMessage + Environment.NewLine + Environment.NewLine);
- await state.LogFileStream.WriteAsync(commandLineLogMessageBytes, 0, commandLineLogMessageBytes.Length, cancellationTokenSource.Token).ConfigureAwait(false);
-
- process.Exited += (sender, args) => OnFfMpegProcessExited(process, transcodingJob, state);
-
- try
- {
- process.Start();
- }
- catch (Exception ex)
- {
- Logger.ErrorException("Error starting ffmpeg", ex);
-
- ApiEntryPoint.Instance.OnTranscodeFailedToStart(outputPath, TranscodingJobType, state);
-
- throw;
- }
-
- // MUST read both stdout and stderr asynchronously or a deadlock may occurr
- //process.BeginOutputReadLine();
-
- state.TranscodingJob = transcodingJob;
-
- // Important - don't await the log task or we won't be able to kill ffmpeg when the user stops playback
- new JobLogger(Logger).StartStreamingLog(state, process.StandardError.BaseStream, state.LogFileStream);
-
- // Wait for the file to exist before proceeeding
- while (!FileSystem.FileExists(state.WaitForPath ?? outputPath) && !transcodingJob.HasExited)
- {
- await Task.Delay(100, cancellationTokenSource.Token).ConfigureAwait(false);
- }
-
- if (state.IsInputVideo && transcodingJob.Type == TranscodingJobType.Progressive && !transcodingJob.HasExited)
- {
- await Task.Delay(1000, cancellationTokenSource.Token).ConfigureAwait(false);
-
- if (state.ReadInputAtNativeFramerate && !transcodingJob.HasExited)
- {
- await Task.Delay(1500, cancellationTokenSource.Token).ConfigureAwait(false);
- }
- }
-
- if (!transcodingJob.HasExited)
- {
- StartThrottler(state, transcodingJob);
- }
-
- return transcodingJob;
- }
-
- private void StartThrottler(StreamState state, TranscodingJob transcodingJob)
- {
- if (EnableThrottling(state))
- {
- transcodingJob.TranscodingThrottler = state.TranscodingThrottler = new TranscodingThrottler(transcodingJob, Logger, ServerConfigurationManager, ApiEntryPoint.Instance.TimerFactory, FileSystem);
- state.TranscodingThrottler.Start();
- }
- }
-
- private bool EnableThrottling(StreamState state)
- {
- 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>
- /// Processes the exited.
- /// </summary>
- /// <param name="process">The process.</param>
- /// <param name="job">The job.</param>
- /// <param name="state">The state.</param>
- private void OnFfMpegProcessExited(IProcess process, TranscodingJob job, StreamState state)
- {
- if (job != null)
- {
- job.HasExited = true;
- }
-
- Logger.Debug("Disposing stream resources");
- state.Dispose();
-
- try
- {
- Logger.Info("FFMpeg exited with code {0}", process.ExitCode);
- }
- catch
- {
- Logger.Error("FFMpeg exited with an error.");
- }
-
- // This causes on exited to be called twice:
- //try
- //{
- // // Dispose the process
- // process.Dispose();
- //}
- //catch (Exception ex)
- //{
- // Logger.ErrorException("Error disposing ffmpeg.", ex);
- //}
- }
-
- /// <summary>
- /// Parses the parameters.
- /// </summary>
- /// <param name="request">The request.</param>
- private void ParseParams(StreamRequest request)
- {
- var vals = request.Params.Split(';');
-
- var videoRequest = request as VideoStreamRequest;
-
- for (var i = 0; i < vals.Length; i++)
- {
- var val = vals[i];
-
- if (string.IsNullOrWhiteSpace(val))
- {
- continue;
- }
-
- if (i == 0)
- {
- request.DeviceProfileId = val;
- }
- else if (i == 1)
- {
- request.DeviceId = val;
- }
- else if (i == 2)
- {
- request.MediaSourceId = val;
- }
- else if (i == 3)
- {
- request.Static = string.Equals("true", val, StringComparison.OrdinalIgnoreCase);
- }
- else if (i == 4)
- {
- if (videoRequest != null)
- {
- videoRequest.VideoCodec = val;
- }
- }
- else if (i == 5)
- {
- request.AudioCodec = val;
- }
- else if (i == 6)
- {
- if (videoRequest != null)
- {
- videoRequest.AudioStreamIndex = int.Parse(val, UsCulture);
- }
- }
- else if (i == 7)
- {
- if (videoRequest != null)
- {
- videoRequest.SubtitleStreamIndex = int.Parse(val, UsCulture);
- }
- }
- else if (i == 8)
- {
- if (videoRequest != null)
- {
- videoRequest.VideoBitRate = int.Parse(val, UsCulture);
- }
- }
- else if (i == 9)
- {
- request.AudioBitRate = int.Parse(val, UsCulture);
- }
- else if (i == 10)
- {
- request.MaxAudioChannels = int.Parse(val, UsCulture);
- }
- else if (i == 11)
- {
- if (videoRequest != null)
- {
- videoRequest.MaxFramerate = float.Parse(val, UsCulture);
- }
- }
- else if (i == 12)
- {
- if (videoRequest != null)
- {
- videoRequest.MaxWidth = int.Parse(val, UsCulture);
- }
- }
- else if (i == 13)
- {
- if (videoRequest != null)
- {
- videoRequest.MaxHeight = int.Parse(val, UsCulture);
- }
- }
- else if (i == 14)
- {
- request.StartTimeTicks = long.Parse(val, UsCulture);
- }
- else if (i == 15)
- {
- if (videoRequest != null)
- {
- videoRequest.Level = val;
- }
- }
- else if (i == 16)
- {
- if (videoRequest != null)
- {
- videoRequest.MaxRefFrames = int.Parse(val, UsCulture);
- }
- }
- else if (i == 17)
- {
- if (videoRequest != null)
- {
- videoRequest.MaxVideoBitDepth = int.Parse(val, UsCulture);
- }
- }
- else if (i == 18)
- {
- if (videoRequest != null)
- {
- videoRequest.Profile = val;
- }
- }
- else if (i == 19)
- {
- // cabac no longer used
- }
- else if (i == 20)
- {
- request.PlaySessionId = val;
- }
- else if (i == 21)
- {
- // api_key
- }
- else if (i == 22)
- {
- request.LiveStreamId = val;
- }
- else if (i == 23)
- {
- // Duplicating ItemId because of MediaMonkey
- }
- else if (i == 24)
- {
- if (videoRequest != null)
- {
- videoRequest.CopyTimestamps = string.Equals("true", val, StringComparison.OrdinalIgnoreCase);
- }
- }
- else if (i == 25)
- {
- if (!string.IsNullOrWhiteSpace(val) && videoRequest != null)
- {
- SubtitleDeliveryMethod method;
- if (Enum.TryParse(val, out method))
- {
- videoRequest.SubtitleMethod = method;
- }
- }
- }
- else if (i == 26)
- {
- request.TranscodingMaxAudioChannels = int.Parse(val, UsCulture);
- }
- else if (i == 27)
- {
- if (videoRequest != null)
- {
- videoRequest.EnableSubtitlesInManifest = string.Equals("true", val, StringComparison.OrdinalIgnoreCase);
- }
- }
- else if (i == 28)
- {
- request.Tag = val;
- }
- else if (i == 29)
- {
- if (videoRequest != null)
- {
- videoRequest.RequireAvc = string.Equals("true", val, StringComparison.OrdinalIgnoreCase);
- }
- }
- else if (i == 30)
- {
- request.SubtitleCodec = val;
- }
- else if (i == 31)
- {
- if (videoRequest != null)
- {
- videoRequest.RequireNonAnamorphic = string.Equals("true", val, StringComparison.OrdinalIgnoreCase);
- }
- }
- else if (i == 32)
- {
- if (videoRequest != null)
- {
- videoRequest.DeInterlace = string.Equals("true", val, StringComparison.OrdinalIgnoreCase);
- }
- }
- else if (i == 33)
- {
- request.TranscodeReasons = val;
- }
- }
- }
-
- /// <summary>
- /// Parses the dlna headers.
- /// </summary>
- /// <param name="request">The request.</param>
- private void ParseDlnaHeaders(StreamRequest request)
- {
- if (!request.StartTimeTicks.HasValue)
- {
- var timeSeek = GetHeader("TimeSeekRange.dlna.org");
-
- request.StartTimeTicks = ParseTimeSeekHeader(timeSeek);
- }
- }
-
- /// <summary>
- /// Parses the time seek header.
- /// </summary>
- private long? ParseTimeSeekHeader(string value)
- {
- if (string.IsNullOrWhiteSpace(value))
- {
- return null;
- }
-
- if (value.IndexOf("npt=", StringComparison.OrdinalIgnoreCase) != 0)
- {
- throw new ArgumentException("Invalid timeseek header");
- }
- value = value.Substring(4).Split(new[] { '-' }, 2)[0];
-
- if (value.IndexOf(':') == -1)
- {
- // Parses npt times in the format of '417.33'
- double seconds;
- if (double.TryParse(value, NumberStyles.Any, UsCulture, out seconds))
- {
- return TimeSpan.FromSeconds(seconds).Ticks;
- }
-
- throw new ArgumentException("Invalid timeseek header");
- }
-
- // Parses npt times in the format of '10:19:25.7'
- var tokens = value.Split(new[] { ':' }, 3);
- double secondsSum = 0;
- var timeFactor = 3600;
-
- foreach (var time in tokens)
- {
- double digit;
- if (double.TryParse(time, NumberStyles.Any, UsCulture, out digit))
- {
- secondsSum += digit * timeFactor;
- }
- else
- {
- throw new ArgumentException("Invalid timeseek header");
- }
- timeFactor /= 60;
- }
- return TimeSpan.FromSeconds(secondsSum).Ticks;
- }
-
- /// <summary>
- /// Gets the state.
- /// </summary>
- /// <param name="request">The request.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>StreamState.</returns>
- protected async Task<StreamState> GetState(StreamRequest request, CancellationToken cancellationToken)
- {
- ParseDlnaHeaders(request);
-
- if (!string.IsNullOrWhiteSpace(request.Params))
- {
- ParseParams(request);
- }
-
- var url = Request.PathInfo;
-
- if (string.IsNullOrEmpty(request.AudioCodec))
- {
- request.AudioCodec = EncodingHelper.InferAudioCodec(url);
- }
-
- var enableDlnaHeaders = !string.IsNullOrWhiteSpace(request.Params) /*||
- string.Equals(Request.Headers.Get("GetContentFeatures.DLNA.ORG"), "1", StringComparison.OrdinalIgnoreCase)*/;
-
- var state = new StreamState(MediaSourceManager, Logger, TranscodingJobType)
- {
- Request = request,
- RequestedUrl = url,
- UserAgent = Request.UserAgent,
- EnableDlnaHeaders = enableDlnaHeaders
- };
-
- var auth = AuthorizationContext.GetAuthorizationInfo(Request);
- if (!string.IsNullOrWhiteSpace(auth.UserId))
- {
- state.User = UserManager.GetUserById(auth.UserId);
- }
-
- //if ((Request.UserAgent ?? string.Empty).IndexOf("iphone", StringComparison.OrdinalIgnoreCase) != -1 ||
- // (Request.UserAgent ?? string.Empty).IndexOf("ipad", StringComparison.OrdinalIgnoreCase) != -1 ||
- // (Request.UserAgent ?? string.Empty).IndexOf("ipod", StringComparison.OrdinalIgnoreCase) != -1)
- //{
- // state.SegmentLength = 6;
- //}
-
- if (state.VideoRequest != null)
- {
- if (!string.IsNullOrWhiteSpace(state.VideoRequest.VideoCodec))
- {
- state.SupportedVideoCodecs = state.VideoRequest.VideoCodec.Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).ToList();
- state.VideoRequest.VideoCodec = state.SupportedVideoCodecs.FirstOrDefault();
- }
- }
-
- if (!string.IsNullOrWhiteSpace(request.AudioCodec))
- {
- state.SupportedAudioCodecs = request.AudioCodec.Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).ToList();
- state.Request.AudioCodec = state.SupportedAudioCodecs.FirstOrDefault(i => MediaEncoder.CanEncodeToAudioCodec(i))
- ?? state.SupportedAudioCodecs.FirstOrDefault();
- }
-
- if (!string.IsNullOrWhiteSpace(request.SubtitleCodec))
- {
- state.SupportedSubtitleCodecs = request.SubtitleCodec.Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).ToList();
- state.Request.SubtitleCodec = state.SupportedSubtitleCodecs.FirstOrDefault(i => MediaEncoder.CanEncodeToSubtitleCodec(i))
- ?? state.SupportedSubtitleCodecs.FirstOrDefault();
- }
-
- var item = LibraryManager.GetItemById(request.Id);
-
- state.IsInputVideo = string.Equals(item.MediaType, MediaType.Video, StringComparison.OrdinalIgnoreCase);
-
- //var primaryImage = item.GetImageInfo(ImageType.Primary, 0) ??
- // item.Parents.Select(i => i.GetImageInfo(ImageType.Primary, 0)).FirstOrDefault(i => i != null);
- //if (primaryImage != null)
- //{
- // state.AlbumCoverPath = primaryImage.Path;
- //}
-
- MediaSourceInfo mediaSource = null;
- if (string.IsNullOrWhiteSpace(request.LiveStreamId))
- {
- TranscodingJob currentJob = !string.IsNullOrWhiteSpace(request.PlaySessionId) ?
- ApiEntryPoint.Instance.GetTranscodingJob(request.PlaySessionId)
- : null;
-
- if (currentJob != null)
- {
- mediaSource = currentJob.MediaSource;
- }
-
- if (mediaSource == null)
- {
- var mediaSources = (await MediaSourceManager.GetPlayackMediaSources(request.Id, null, false, new[] { MediaType.Audio, MediaType.Video }, cancellationToken).ConfigureAwait(false)).ToList();
-
- mediaSource = string.IsNullOrEmpty(request.MediaSourceId)
- ? mediaSources.First()
- : mediaSources.FirstOrDefault(i => string.Equals(i.Id, request.MediaSourceId));
-
- if (mediaSource == null && string.Equals(request.Id, request.MediaSourceId, StringComparison.OrdinalIgnoreCase))
- {
- mediaSource = mediaSources.First();
- }
- }
- }
- else
- {
- var liveStreamInfo = await MediaSourceManager.GetLiveStreamWithDirectStreamProvider(request.LiveStreamId, cancellationToken).ConfigureAwait(false);
- mediaSource = liveStreamInfo.Item1;
- state.DirectStreamProvider = liveStreamInfo.Item2;
- }
-
- var videoRequest = request as VideoStreamRequest;
-
- EncodingHelper.AttachMediaSourceInfo(state, mediaSource, url);
-
- var container = Path.GetExtension(state.RequestedUrl);
-
- if (string.IsNullOrEmpty(container))
- {
- container = request.Container;
- }
-
- if (string.IsNullOrEmpty(container))
- {
- container = request.Static ?
- state.InputContainer :
- GetOutputFileExtension(state);
- }
-
- state.OutputContainer = (container ?? string.Empty).TrimStart('.');
-
- state.OutputAudioBitrate = EncodingHelper.GetAudioBitrateParam(state.Request, state.AudioStream);
-
- state.OutputAudioCodec = state.Request.AudioCodec;
-
- state.OutputAudioChannels = EncodingHelper.GetNumAudioChannelsParam(state.Request, state.AudioStream, state.OutputAudioCodec);
-
- if (videoRequest != null)
- {
- state.OutputVideoCodec = state.VideoRequest.VideoCodec;
- state.OutputVideoBitrate = EncodingHelper.GetVideoBitrateParamValue(state.VideoRequest, state.VideoStream, state.OutputVideoCodec);
-
- if (videoRequest != null)
- {
- EncodingHelper.TryStreamCopy(state);
- }
-
- if (state.OutputVideoBitrate.HasValue && !string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase))
- {
- var resolution = ResolutionNormalizer.Normalize(
- state.VideoStream == null ? (int?)null : state.VideoStream.BitRate,
- state.OutputVideoBitrate.Value,
- state.VideoStream == null ? null : state.VideoStream.Codec,
- state.OutputVideoCodec,
- videoRequest.MaxWidth,
- videoRequest.MaxHeight);
-
- videoRequest.MaxWidth = resolution.MaxWidth;
- videoRequest.MaxHeight = resolution.MaxHeight;
- }
-
- ApplyDeviceProfileSettings(state);
- }
- else
- {
- ApplyDeviceProfileSettings(state);
- }
-
- var ext = string.IsNullOrWhiteSpace(state.OutputContainer)
- ? GetOutputFileExtension(state)
- : ("." + state.OutputContainer);
-
- var encodingOptions = ApiEntryPoint.Instance.GetEncodingOptions();
-
- state.OutputFilePath = GetOutputFilePath(state, encodingOptions, ext);
-
- return state;
- }
-
- private void ApplyDeviceProfileSettings(StreamState state)
- {
- var headers = Request.Headers.ToDictionary();
-
- if (!string.IsNullOrWhiteSpace(state.Request.DeviceProfileId))
- {
- state.DeviceProfile = DlnaManager.GetProfile(state.Request.DeviceProfileId);
- }
- else
- {
- if (!string.IsNullOrWhiteSpace(state.Request.DeviceId))
- {
- var caps = DeviceManager.GetCapabilities(state.Request.DeviceId);
-
- if (caps != null)
- {
- state.DeviceProfile = caps.DeviceProfile;
- }
- else
- {
- state.DeviceProfile = DlnaManager.GetProfile(headers);
- }
- }
- }
-
- var profile = state.DeviceProfile;
-
- if (profile == null)
- {
- // Don't use settings from the default profile.
- // Only use a specific profile if it was requested.
- return;
- }
-
- var audioCodec = state.ActualOutputAudioCodec;
- var videoCodec = state.ActualOutputVideoCodec;
-
- var mediaProfile = state.VideoRequest == null ?
- profile.GetAudioMediaProfile(state.OutputContainer, audioCodec, state.OutputAudioChannels, state.OutputAudioBitrate, state.OutputAudioSampleRate, state.OutputAudioBitDepth) :
- profile.GetVideoMediaProfile(state.OutputContainer,
- audioCodec,
- videoCodec,
- state.OutputWidth,
- state.OutputHeight,
- state.TargetVideoBitDepth,
- state.OutputVideoBitrate,
- state.TargetVideoProfile,
- state.TargetVideoLevel,
- state.TargetFramerate,
- state.TargetPacketLength,
- state.TargetTimestamp,
- state.IsTargetAnamorphic,
- state.IsTargetInterlaced,
- state.TargetRefFrames,
- state.TargetVideoStreamCount,
- state.TargetAudioStreamCount,
- state.TargetVideoCodecTag,
- state.IsTargetAVC);
-
- if (mediaProfile != null)
- {
- state.MimeType = mediaProfile.MimeType;
- }
-
- if (!state.Request.Static)
- {
- var transcodingProfile = state.VideoRequest == null ?
- profile.GetAudioTranscodingProfile(state.OutputContainer, audioCodec) :
- profile.GetVideoTranscodingProfile(state.OutputContainer, audioCodec, videoCodec);
-
- if (transcodingProfile != null)
- {
- state.EstimateContentLength = transcodingProfile.EstimateContentLength;
- state.EnableMpegtsM2TsMode = transcodingProfile.EnableMpegtsM2TsMode;
- state.TranscodeSeekInfo = transcodingProfile.TranscodeSeekInfo;
-
- if (state.VideoRequest != null)
- {
- state.VideoRequest.CopyTimestamps = transcodingProfile.CopyTimestamps;
- state.VideoRequest.EnableSubtitlesInManifest = transcodingProfile.EnableSubtitlesInManifest;
- }
- }
- }
- }
-
- /// <summary>
- /// Adds the dlna headers.
- /// </summary>
- /// <param name="state">The state.</param>
- /// <param name="responseHeaders">The response headers.</param>
- /// <param name="isStaticallyStreamed">if set to <c>true</c> [is statically streamed].</param>
- /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
- protected void AddDlnaHeaders(StreamState state, IDictionary<string, string> responseHeaders, bool isStaticallyStreamed)
- {
- if (!state.EnableDlnaHeaders)
- {
- return;
- }
-
- var profile = state.DeviceProfile;
-
- var transferMode = GetHeader("transferMode.dlna.org");
- responseHeaders["transferMode.dlna.org"] = string.IsNullOrEmpty(transferMode) ? "Streaming" : transferMode;
- responseHeaders["realTimeInfo.dlna.org"] = "DLNA.ORG_TLAG=*";
-
- if (string.Equals(GetHeader("getMediaInfo.sec"), "1", StringComparison.OrdinalIgnoreCase))
- {
- if (state.RunTimeTicks.HasValue)
- {
- var ms = TimeSpan.FromTicks(state.RunTimeTicks.Value).TotalMilliseconds;
- responseHeaders["MediaInfo.sec"] = string.Format("SEC_Duration={0};", Convert.ToInt32(ms).ToString(CultureInfo.InvariantCulture));
- }
- }
-
- if (state.RunTimeTicks.HasValue && !isStaticallyStreamed && profile != null)
- {
- AddTimeSeekResponseHeaders(state, responseHeaders);
- }
-
- if (profile == null)
- {
- profile = DlnaManager.GetDefaultProfile();
- }
-
- var audioCodec = state.ActualOutputAudioCodec;
-
- if (state.VideoRequest == null)
- {
- responseHeaders["contentFeatures.dlna.org"] = new ContentFeatureBuilder(profile)
- .BuildAudioHeader(
- state.OutputContainer,
- audioCodec,
- state.OutputAudioBitrate,
- state.OutputAudioSampleRate,
- state.OutputAudioChannels,
- state.OutputAudioBitDepth,
- isStaticallyStreamed,
- state.RunTimeTicks,
- state.TranscodeSeekInfo
- );
- }
- else
- {
- var videoCodec = state.ActualOutputVideoCodec;
-
- responseHeaders["contentFeatures.dlna.org"] = new ContentFeatureBuilder(profile)
- .BuildVideoHeader(
- state.OutputContainer,
- videoCodec,
- audioCodec,
- state.OutputWidth,
- state.OutputHeight,
- state.TargetVideoBitDepth,
- state.OutputVideoBitrate,
- state.TargetTimestamp,
- isStaticallyStreamed,
- state.RunTimeTicks,
- state.TargetVideoProfile,
- state.TargetVideoLevel,
- state.TargetFramerate,
- state.TargetPacketLength,
- state.TranscodeSeekInfo,
- state.IsTargetAnamorphic,
- state.IsTargetInterlaced,
- state.TargetRefFrames,
- state.TargetVideoStreamCount,
- state.TargetAudioStreamCount,
- state.TargetVideoCodecTag,
- state.IsTargetAVC
-
- ).FirstOrDefault() ?? string.Empty;
- }
-
- foreach (var item in responseHeaders)
- {
- Request.Response.AddHeader(item.Key, item.Value);
- }
- }
-
- private void AddTimeSeekResponseHeaders(StreamState state, IDictionary<string, string> responseHeaders)
- {
- var runtimeSeconds = TimeSpan.FromTicks(state.RunTimeTicks.Value).TotalSeconds.ToString(UsCulture);
- var startSeconds = TimeSpan.FromTicks(state.Request.StartTimeTicks ?? 0).TotalSeconds.ToString(UsCulture);
-
- responseHeaders["TimeSeekRange.dlna.org"] = string.Format("npt={0}-{1}/{1}", startSeconds, runtimeSeconds);
- responseHeaders["X-AvailableSeekRange"] = string.Format("1 npt={0}-{1}", startSeconds, runtimeSeconds);
- }
- }
-}
diff --git a/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs b/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs
deleted file mode 100644
index 83157c703..000000000
--- a/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs
+++ /dev/null
@@ -1,331 +0,0 @@
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Devices;
-using MediaBrowser.Controller.Dlna;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.MediaEncoding;
-using MediaBrowser.Model.Extensions;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Model.Net;
-using MediaBrowser.Model.Serialization;
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Text;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Controller.Net;
-using MediaBrowser.Model.Configuration;
-
-namespace MediaBrowser.Api.Playback.Hls
-{
- /// <summary>
- /// Class BaseHlsService
- /// </summary>
- public abstract class BaseHlsService : BaseStreamingService
- {
- /// <summary>
- /// Gets the audio arguments.
- /// </summary>
- protected abstract string GetAudioArguments(StreamState state, EncodingOptions encodingOptions);
-
- /// <summary>
- /// Gets the video arguments.
- /// </summary>
- protected abstract string GetVideoArguments(StreamState state, EncodingOptions encodingOptions);
-
- /// <summary>
- /// Gets the segment file extension.
- /// </summary>
- protected string GetSegmentFileExtension(StreamRequest request)
- {
- var segmentContainer = request.SegmentContainer;
- if (!string.IsNullOrWhiteSpace(segmentContainer))
- {
- return "." + segmentContainer;
- }
-
- return ".ts";
- }
-
- /// <summary>
- /// Gets the type of the transcoding job.
- /// </summary>
- /// <value>The type of the transcoding job.</value>
- protected override TranscodingJobType TranscodingJobType
- {
- get { return TranscodingJobType.Hls; }
- }
-
- /// <summary>
- /// Processes the request.
- /// </summary>
- /// <param name="request">The request.</param>
- /// <param name="isLive">if set to <c>true</c> [is live].</param>
- /// <returns>System.Object.</returns>
- protected async Task<object> ProcessRequest(StreamRequest request, bool isLive)
- {
- return await ProcessRequestAsync(request, isLive).ConfigureAwait(false);
- }
-
- /// <summary>
- /// Processes the request async.
- /// </summary>
- /// <param name="request">The request.</param>
- /// <param name="isLive">if set to <c>true</c> [is live].</param>
- /// <returns>Task{System.Object}.</returns>
- /// <exception cref="ArgumentException">A video bitrate is required
- /// or
- /// An audio bitrate is required</exception>
- private async Task<object> ProcessRequestAsync(StreamRequest request, bool isLive)
- {
- var cancellationTokenSource = new CancellationTokenSource();
-
- var state = await GetState(request, cancellationTokenSource.Token).ConfigureAwait(false);
-
- TranscodingJob job = null;
- var playlist = state.OutputFilePath;
-
- if (!FileSystem.FileExists(playlist))
- {
- var transcodingLock = ApiEntryPoint.Instance.GetTranscodingLock(playlist);
- await transcodingLock.WaitAsync(cancellationTokenSource.Token).ConfigureAwait(false);
- try
- {
- if (!FileSystem.FileExists(playlist))
- {
- // If the playlist doesn't already exist, startup ffmpeg
- try
- {
- job = await StartFfMpeg(state, playlist, cancellationTokenSource).ConfigureAwait(false);
- job.IsLiveOutput = isLive;
- }
- catch
- {
- state.Dispose();
- throw;
- }
-
- var minSegments = state.MinSegments;
- if (minSegments > 0)
- {
- await WaitForMinimumSegmentCount(playlist, minSegments, cancellationTokenSource.Token).ConfigureAwait(false);
- }
- }
- }
- finally
- {
- transcodingLock.Release();
- }
- }
-
- if (isLive)
- {
- job = job ?? ApiEntryPoint.Instance.OnTranscodeBeginRequest(playlist, TranscodingJobType);
-
- if (job != null)
- {
- ApiEntryPoint.Instance.OnTranscodeEndRequest(job);
- }
- return ResultFactory.GetResult(GetLivePlaylistText(playlist, state.SegmentLength), MimeTypes.GetMimeType("playlist.m3u8"), new Dictionary<string, string>());
- }
-
- var audioBitrate = state.OutputAudioBitrate ?? 0;
- var videoBitrate = state.OutputVideoBitrate ?? 0;
-
- var baselineStreamBitrate = 64000;
-
- var playlistText = GetMasterPlaylistFileText(playlist, videoBitrate + audioBitrate, baselineStreamBitrate);
-
- job = job ?? ApiEntryPoint.Instance.OnTranscodeBeginRequest(playlist, TranscodingJobType);
-
- if (job != null)
- {
- ApiEntryPoint.Instance.OnTranscodeEndRequest(job);
- }
-
- return ResultFactory.GetResult(playlistText, MimeTypes.GetMimeType("playlist.m3u8"), new Dictionary<string, string>());
- }
-
- private string GetLivePlaylistText(string path, int segmentLength)
- {
- using (var stream = FileSystem.GetFileStream(path, FileOpenMode.Open, FileAccessMode.Read, FileShareMode.ReadWrite))
- {
- using (var reader = new StreamReader(stream))
- {
- var text = reader.ReadToEnd();
-
- text = text.Replace("#EXTM3U", "#EXTM3U\n#EXT-X-PLAYLIST-TYPE:EVENT");
-
- var newDuration = "#EXT-X-TARGETDURATION:" + segmentLength.ToString(UsCulture);
-
- text = text.Replace("#EXT-X-TARGETDURATION:" + (segmentLength - 1).ToString(UsCulture), newDuration, StringComparison.OrdinalIgnoreCase);
- //text = text.Replace("#EXT-X-TARGETDURATION:" + (segmentLength + 1).ToString(UsCulture), newDuration, StringComparison.OrdinalIgnoreCase);
-
- return text;
- }
- }
- }
-
- private string GetMasterPlaylistFileText(string firstPlaylist, int bitrate, int baselineStreamBitrate)
- {
- var builder = new StringBuilder();
-
- builder.AppendLine("#EXTM3U");
-
- // Pad a little to satisfy the apple hls validator
- var paddedBitrate = Convert.ToInt32(bitrate * 1.15);
-
- // Main stream
- builder.AppendLine("#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=" + paddedBitrate.ToString(UsCulture));
- var playlistUrl = "hls/" + Path.GetFileName(firstPlaylist).Replace(".m3u8", "/stream.m3u8");
- builder.AppendLine(playlistUrl);
-
- return builder.ToString();
- }
-
- protected virtual async Task WaitForMinimumSegmentCount(string playlist, int segmentCount, CancellationToken cancellationToken)
- {
- Logger.Debug("Waiting for {0} segments in {1}", segmentCount, playlist);
-
- while (!cancellationToken.IsCancellationRequested)
- {
- try
- {
- // Need to use FileShareMode.ReadWrite because we're reading the file at the same time it's being written
- using (var fileStream = GetPlaylistFileStream(playlist))
- {
- using (var reader = new StreamReader(fileStream))
- {
- var count = 0;
-
- while (!reader.EndOfStream)
- {
- var line = reader.ReadLine();
-
- if (line.IndexOf("#EXTINF:", StringComparison.OrdinalIgnoreCase) != -1)
- {
- count++;
- if (count >= segmentCount)
- {
- Logger.Debug("Finished waiting for {0} segments in {1}", segmentCount, playlist);
- return;
- }
- }
- }
- await Task.Delay(100, cancellationToken).ConfigureAwait(false);
- }
- }
- }
- catch (IOException)
- {
- // May get an error if the file is locked
- }
-
- await Task.Delay(50, cancellationToken).ConfigureAwait(false);
- }
- }
-
- protected Stream GetPlaylistFileStream(string path)
- {
- var tmpPath = path + ".tmp";
- tmpPath = path;
-
- try
- {
- return FileSystem.GetFileStream(tmpPath, FileOpenMode.Open, FileAccessMode.Read, FileShareMode.ReadWrite, FileOpenOptions.SequentialScan);
- }
- catch (IOException)
- {
- return FileSystem.GetFileStream(path, FileOpenMode.Open, FileAccessMode.Read, FileShareMode.ReadWrite, FileOpenOptions.SequentialScan);
- }
- }
-
- protected override string GetCommandLineArguments(string outputPath, EncodingOptions encodingOptions, StreamState state, bool isEncoding)
- {
- var itsOffsetMs = 0;
-
- var itsOffset = itsOffsetMs == 0 ? string.Empty : string.Format("-itsoffset {0} ", TimeSpan.FromMilliseconds(itsOffsetMs).TotalSeconds.ToString(UsCulture));
-
- var threads = EncodingHelper.GetNumberOfThreads(state, encodingOptions, false);
-
- var inputModifier = EncodingHelper.GetInputModifier(state, encodingOptions);
-
- // If isEncoding is true we're actually starting ffmpeg
- var startNumberParam = isEncoding ? GetStartNumber(state).ToString(UsCulture) : "0";
-
- var baseUrlParam = string.Empty;
-
- if (state.Request is GetLiveHlsStream)
- {
- baseUrlParam = string.Format(" -hls_base_url \"{0}/\"",
- "hls/" + Path.GetFileNameWithoutExtension(outputPath));
- }
-
- var useGenericSegmenter = true;
- if (useGenericSegmenter)
- {
- var outputTsArg = Path.Combine(FileSystem.GetDirectoryName(outputPath), Path.GetFileNameWithoutExtension(outputPath)) + "%d" + GetSegmentFileExtension(state.Request);
-
- var timeDeltaParam = String.Empty;
-
- var segmentFormat = GetSegmentFileExtension(state.Request).TrimStart('.');
- if (string.Equals(segmentFormat, "ts", StringComparison.OrdinalIgnoreCase))
- {
- segmentFormat = "mpegts";
- }
-
- baseUrlParam = string.Format("\"{0}/\"", "hls/" + Path.GetFileNameWithoutExtension(outputPath));
-
- return string.Format("{0} {1} -map_metadata -1 -map_chapters -1 -threads {2} {3} {4} {5} -f segment -max_delay 5000000 -avoid_negative_ts disabled -start_at_zero -segment_time {6} {10} -individual_header_trailer 0 -segment_format {11} -segment_list_entry_prefix {12} -segment_list_type m3u8 -segment_start_number {7} -segment_list \"{8}\" -y \"{9}\"",
- inputModifier,
- EncodingHelper.GetInputArgument(state, encodingOptions),
- threads,
- EncodingHelper.GetMapArgs(state),
- GetVideoArguments(state, encodingOptions),
- GetAudioArguments(state, encodingOptions),
- state.SegmentLength.ToString(UsCulture),
- startNumberParam,
- outputPath,
- outputTsArg,
- timeDeltaParam,
- segmentFormat,
- baseUrlParam
- ).Trim();
- }
-
- // add when stream copying?
- // -avoid_negative_ts make_zero -fflags +genpts
-
- var args = string.Format("{0} {1} {2} -map_metadata -1 -map_chapters -1 -threads {3} {4} {5} -max_delay 5000000 -avoid_negative_ts disabled -start_at_zero {6} -hls_time {7} -individual_header_trailer 0 -start_number {8} -hls_list_size {9}{10} -y \"{11}\"",
- itsOffset,
- inputModifier,
- EncodingHelper.GetInputArgument(state, encodingOptions),
- threads,
- EncodingHelper.GetMapArgs(state),
- GetVideoArguments(state, encodingOptions),
- GetAudioArguments(state, encodingOptions),
- state.SegmentLength.ToString(UsCulture),
- startNumberParam,
- state.HlsListSize.ToString(UsCulture),
- baseUrlParam,
- outputPath
- ).Trim();
-
- return args;
- }
-
- protected override string GetDefaultH264Preset()
- {
- return "veryfast";
- }
-
- protected virtual int GetStartNumber(StreamState state)
- {
- return 0;
- }
-
- public BaseHlsService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IJsonSerializer jsonSerializer, IAuthorizationContext authorizationContext) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient, jsonSerializer, authorizationContext)
- {
- }
- }
-} \ No newline at end of file
diff --git a/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs b/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs
deleted file mode 100644
index 6744fbd92..000000000
--- a/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs
+++ /dev/null
@@ -1,970 +0,0 @@
-using MediaBrowser.Common.Net;
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Devices;
-using MediaBrowser.Controller.Dlna;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.MediaEncoding;
-using MediaBrowser.Controller.Net;
-using MediaBrowser.Model.Dlna;
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Extensions;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Model.Serialization;
-using System;
-using System.Collections.Generic;
-using System.Globalization;
-using System.IO;
-using System.Linq;
-using System.Text;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Model.Configuration;
-using MediaBrowser.Model.Services;
-using MimeTypes = MediaBrowser.Model.Net.MimeTypes;
-
-namespace MediaBrowser.Api.Playback.Hls
-{
- /// <summary>
- /// Options is needed for chromecast. Threw Head in there since it's related
- /// </summary>
- [Route("/Videos/{Id}/master.m3u8", "GET", Summary = "Gets a video stream using HTTP live streaming.")]
- [Route("/Videos/{Id}/master.m3u8", "HEAD", Summary = "Gets a video stream using HTTP live streaming.")]
- public class GetMasterHlsVideoPlaylist : VideoStreamRequest, IMasterHlsRequest
- {
- public bool EnableAdaptiveBitrateStreaming { get; set; }
-
- public GetMasterHlsVideoPlaylist()
- {
- EnableAdaptiveBitrateStreaming = true;
- }
- }
-
- [Route("/Audio/{Id}/master.m3u8", "GET", Summary = "Gets an audio stream using HTTP live streaming.")]
- [Route("/Audio/{Id}/master.m3u8", "HEAD", Summary = "Gets an audio stream using HTTP live streaming.")]
- public class GetMasterHlsAudioPlaylist : StreamRequest, IMasterHlsRequest
- {
- public bool EnableAdaptiveBitrateStreaming { get; set; }
-
- public GetMasterHlsAudioPlaylist()
- {
- EnableAdaptiveBitrateStreaming = true;
- }
- }
-
- public interface IMasterHlsRequest
- {
- bool EnableAdaptiveBitrateStreaming { get; set; }
- }
-
- [Route("/Videos/{Id}/main.m3u8", "GET", Summary = "Gets a video stream using HTTP live streaming.")]
- public class GetVariantHlsVideoPlaylist : VideoStreamRequest
- {
- }
-
- [Route("/Audio/{Id}/main.m3u8", "GET", Summary = "Gets an audio stream using HTTP live streaming.")]
- public class GetVariantHlsAudioPlaylist : StreamRequest
- {
- }
-
- [Route("/Videos/{Id}/hls1/{PlaylistId}/{SegmentId}.{SegmentContainer}", "GET")]
- public class GetHlsVideoSegment : VideoStreamRequest
- {
- public string PlaylistId { get; set; }
-
- /// <summary>
- /// Gets or sets the segment id.
- /// </summary>
- /// <value>The segment id.</value>
- public string SegmentId { get; set; }
- }
-
- [Route("/Audio/{Id}/hls1/{PlaylistId}/{SegmentId}.{SegmentContainer}", "GET")]
- public class GetHlsAudioSegment : StreamRequest
- {
- public string PlaylistId { get; set; }
-
- /// <summary>
- /// Gets or sets the segment id.
- /// </summary>
- /// <value>The segment id.</value>
- public string SegmentId { get; set; }
- }
-
- [Authenticated]
- public class DynamicHlsService : BaseHlsService
- {
-
- public DynamicHlsService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IJsonSerializer jsonSerializer, IAuthorizationContext authorizationContext, INetworkManager networkManager) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient, jsonSerializer, authorizationContext)
- {
- NetworkManager = networkManager;
- }
-
- protected INetworkManager NetworkManager { get; private set; }
-
- public Task<object> Get(GetMasterHlsVideoPlaylist request)
- {
- return GetMasterPlaylistInternal(request, "GET");
- }
-
- public Task<object> Head(GetMasterHlsVideoPlaylist request)
- {
- return GetMasterPlaylistInternal(request, "HEAD");
- }
-
- public Task<object> Get(GetMasterHlsAudioPlaylist request)
- {
- return GetMasterPlaylistInternal(request, "GET");
- }
-
- public Task<object> Head(GetMasterHlsAudioPlaylist request)
- {
- return GetMasterPlaylistInternal(request, "HEAD");
- }
-
- public Task<object> Get(GetVariantHlsVideoPlaylist request)
- {
- return GetVariantPlaylistInternal(request, true, "main");
- }
-
- public Task<object> Get(GetVariantHlsAudioPlaylist request)
- {
- return GetVariantPlaylistInternal(request, false, "main");
- }
-
- public Task<object> Get(GetHlsVideoSegment request)
- {
- return GetDynamicSegment(request, request.SegmentId);
- }
-
- public Task<object> Get(GetHlsAudioSegment request)
- {
- return GetDynamicSegment(request, request.SegmentId);
- }
-
- private async Task<object> GetDynamicSegment(StreamRequest request, string segmentId)
- {
- if ((request.StartTimeTicks ?? 0) > 0)
- {
- throw new ArgumentException("StartTimeTicks is not allowed.");
- }
-
- var cancellationTokenSource = new CancellationTokenSource();
- var cancellationToken = cancellationTokenSource.Token;
-
- var requestedIndex = int.Parse(segmentId, NumberStyles.Integer, UsCulture);
-
- var state = await GetState(request, cancellationToken).ConfigureAwait(false);
-
- var playlistPath = Path.ChangeExtension(state.OutputFilePath, ".m3u8");
-
- var segmentPath = GetSegmentPath(state, playlistPath, requestedIndex);
-
- var segmentExtension = GetSegmentFileExtension(state.Request);
-
- TranscodingJob job = null;
-
- if (FileSystem.FileExists(segmentPath))
- {
- job = ApiEntryPoint.Instance.OnTranscodeBeginRequest(playlistPath, TranscodingJobType);
- return await GetSegmentResult(state, playlistPath, segmentPath, segmentExtension, requestedIndex, job, cancellationToken).ConfigureAwait(false);
- }
-
- var transcodingLock = ApiEntryPoint.Instance.GetTranscodingLock(playlistPath);
- await transcodingLock.WaitAsync(cancellationTokenSource.Token).ConfigureAwait(false);
- var released = false;
- var startTranscoding = false;
-
- try
- {
- if (FileSystem.FileExists(segmentPath))
- {
- job = ApiEntryPoint.Instance.OnTranscodeBeginRequest(playlistPath, TranscodingJobType);
- transcodingLock.Release();
- released = true;
- return await GetSegmentResult(state, playlistPath, segmentPath, segmentExtension, requestedIndex, job, cancellationToken).ConfigureAwait(false);
- }
- else
- {
- var currentTranscodingIndex = GetCurrentTranscodingIndex(playlistPath, segmentExtension);
- var segmentGapRequiringTranscodingChange = 24 / state.SegmentLength;
-
- if (currentTranscodingIndex == null)
- {
- Logger.Debug("Starting transcoding because currentTranscodingIndex=null");
- startTranscoding = true;
- }
- else if (requestedIndex < currentTranscodingIndex.Value)
- {
- Logger.Debug("Starting transcoding because requestedIndex={0} and currentTranscodingIndex={1}", requestedIndex, currentTranscodingIndex);
- startTranscoding = true;
- }
- else if (requestedIndex - currentTranscodingIndex.Value > segmentGapRequiringTranscodingChange)
- {
- Logger.Debug("Starting transcoding because segmentGap is {0} and max allowed gap is {1}. requestedIndex={2}", requestedIndex - currentTranscodingIndex.Value, segmentGapRequiringTranscodingChange, requestedIndex);
- startTranscoding = true;
- }
- if (startTranscoding)
- {
- // If the playlist doesn't already exist, startup ffmpeg
- try
- {
- ApiEntryPoint.Instance.KillTranscodingJobs(request.DeviceId, request.PlaySessionId, p => false);
-
- if (currentTranscodingIndex.HasValue)
- {
- DeleteLastFile(playlistPath, segmentExtension, 0);
- }
-
- request.StartTimeTicks = GetStartPositionTicks(state, requestedIndex);
-
- job = await StartFfMpeg(state, playlistPath, cancellationTokenSource).ConfigureAwait(false);
- }
- catch
- {
- state.Dispose();
- throw;
- }
-
- //await WaitForMinimumSegmentCount(playlistPath, 1, cancellationTokenSource.Token).ConfigureAwait(false);
- }
- else
- {
- job = ApiEntryPoint.Instance.OnTranscodeBeginRequest(playlistPath, TranscodingJobType);
- if (job.TranscodingThrottler != null)
- {
- job.TranscodingThrottler.UnpauseTranscoding();
- }
- }
- }
- }
- finally
- {
- if (!released)
- {
- transcodingLock.Release();
- }
- }
-
- //Logger.Info("waiting for {0}", segmentPath);
- //while (!File.Exists(segmentPath))
- //{
- // await Task.Delay(50, cancellationToken).ConfigureAwait(false);
- //}
-
- Logger.Info("returning {0}", segmentPath);
- job = job ?? ApiEntryPoint.Instance.OnTranscodeBeginRequest(playlistPath, TranscodingJobType);
- return await GetSegmentResult(state, playlistPath, segmentPath, segmentExtension, requestedIndex, job, cancellationToken).ConfigureAwait(false);
- }
-
- private const int BufferSize = 81920;
-
- private long GetStartPositionTicks(StreamState state, int requestedIndex)
- {
- double startSeconds = 0;
- var lengths = GetSegmentLengths(state);
-
- if (requestedIndex >= lengths.Length)
- {
- var msg = string.Format("Invalid segment index requested: {0} - Segment count: {1}", requestedIndex, lengths.Length);
- throw new ArgumentException(msg);
- }
-
- for (var i = 0; i < requestedIndex; i++)
- {
- startSeconds += lengths[i];
- }
-
- var position = TimeSpan.FromSeconds(startSeconds).Ticks;
- return position;
- }
-
- private long GetEndPositionTicks(StreamState state, int requestedIndex)
- {
- double startSeconds = 0;
- var lengths = GetSegmentLengths(state);
-
- if (requestedIndex >= lengths.Length)
- {
- var msg = string.Format("Invalid segment index requested: {0} - Segment count: {1}", requestedIndex, lengths.Length);
- throw new ArgumentException(msg);
- }
-
- for (var i = 0; i <= requestedIndex; i++)
- {
- startSeconds += lengths[i];
- }
-
- var position = TimeSpan.FromSeconds(startSeconds).Ticks;
- return position;
- }
-
- private double[] GetSegmentLengths(StreamState state)
- {
- var result = new List<double>();
-
- var ticks = state.RunTimeTicks ?? 0;
-
- var segmentLengthTicks = TimeSpan.FromSeconds(state.SegmentLength).Ticks;
-
- while (ticks > 0)
- {
- var length = ticks >= segmentLengthTicks ? segmentLengthTicks : ticks;
-
- result.Add(TimeSpan.FromTicks(length).TotalSeconds);
-
- ticks -= length;
- }
-
- return result.ToArray();
- }
-
- public int? GetCurrentTranscodingIndex(string playlist, string segmentExtension)
- {
- var job = ApiEntryPoint.Instance.GetTranscodingJob(playlist, TranscodingJobType);
-
- if (job == null || job.HasExited)
- {
- return null;
- }
-
- var file = GetLastTranscodingFile(playlist, segmentExtension, FileSystem);
-
- if (file == null)
- {
- return null;
- }
-
- var playlistFilename = Path.GetFileNameWithoutExtension(playlist);
-
- var indexString = Path.GetFileNameWithoutExtension(file.Name).Substring(playlistFilename.Length);
-
- return int.Parse(indexString, NumberStyles.Integer, UsCulture);
- }
-
- private void DeleteLastFile(string playlistPath, string segmentExtension, int retryCount)
- {
- var file = GetLastTranscodingFile(playlistPath, segmentExtension, FileSystem);
-
- if (file != null)
- {
- DeleteFile(file.FullName, retryCount);
- }
- }
-
- private void DeleteFile(string path, int retryCount)
- {
- if (retryCount >= 5)
- {
- return;
- }
-
- Logger.Debug("Deleting partial HLS file {0}", path);
-
- try
- {
- FileSystem.DeleteFile(path);
- }
- catch (IOException ex)
- {
- Logger.ErrorException("Error deleting partial stream file(s) {0}", ex, path);
-
- var task = Task.Delay(100);
- Task.WaitAll(task);
- DeleteFile(path, retryCount + 1);
- }
- catch (Exception ex)
- {
- Logger.ErrorException("Error deleting partial stream file(s) {0}", ex, path);
- }
- }
-
- private static FileSystemMetadata GetLastTranscodingFile(string playlist, string segmentExtension, IFileSystem fileSystem)
- {
- var folder = fileSystem.GetDirectoryName(playlist);
-
- var filePrefix = Path.GetFileNameWithoutExtension(playlist) ?? string.Empty;
-
- try
- {
- return fileSystem.GetFiles(folder, new[] { segmentExtension }, true, false)
- .Where(i => Path.GetFileNameWithoutExtension(i.Name).StartsWith(filePrefix, StringComparison.OrdinalIgnoreCase))
- .OrderByDescending(fileSystem.GetLastWriteTimeUtc)
- .FirstOrDefault();
- }
- catch (IOException)
- {
- return null;
- }
- }
-
- protected override int GetStartNumber(StreamState state)
- {
- return GetStartNumber(state.VideoRequest);
- }
-
- private int GetStartNumber(VideoStreamRequest request)
- {
- var segmentId = "0";
-
- var segmentRequest = request as GetHlsVideoSegment;
- if (segmentRequest != null)
- {
- segmentId = segmentRequest.SegmentId;
- }
-
- return int.Parse(segmentId, NumberStyles.Integer, UsCulture);
- }
-
- private string GetSegmentPath(StreamState state, string playlist, int index)
- {
- var folder = FileSystem.GetDirectoryName(playlist);
-
- var filename = Path.GetFileNameWithoutExtension(playlist);
-
- return Path.Combine(folder, filename + index.ToString(UsCulture) + GetSegmentFileExtension(state.Request));
- }
-
- private async Task<object> GetSegmentResult(StreamState state,
- string playlistPath,
- string segmentPath,
- string segmentExtension,
- int segmentIndex,
- TranscodingJob transcodingJob,
- CancellationToken cancellationToken)
- {
- var segmentFileExists = FileSystem.FileExists(segmentPath);
-
- // If all transcoding has completed, just return immediately
- if (transcodingJob != null && transcodingJob.HasExited && segmentFileExists)
- {
- return await GetSegmentResult(state, segmentPath, segmentIndex, transcodingJob).ConfigureAwait(false);
- }
-
- if (segmentFileExists)
- {
- var currentTranscodingIndex = GetCurrentTranscodingIndex(playlistPath, segmentExtension);
-
- // If requested segment is less than transcoding position, we can't transcode backwards, so assume it's ready
- if (segmentIndex < currentTranscodingIndex)
- {
- return await GetSegmentResult(state, segmentPath, segmentIndex, transcodingJob).ConfigureAwait(false);
- }
- }
-
- var segmentFilename = Path.GetFileName(segmentPath);
-
- while (!cancellationToken.IsCancellationRequested)
- {
- try
- {
- var text = FileSystem.ReadAllText(playlistPath, Encoding.UTF8);
-
- // If it appears in the playlist, it's done
- if (text.IndexOf(segmentFilename, StringComparison.OrdinalIgnoreCase) != -1)
- {
- if (!segmentFileExists)
- {
- segmentFileExists = FileSystem.FileExists(segmentPath);
- }
- if (segmentFileExists)
- {
- return await GetSegmentResult(state, segmentPath, segmentIndex, transcodingJob).ConfigureAwait(false);
- }
- //break;
- }
- }
- catch (IOException)
- {
- // May get an error if the file is locked
- }
-
- await Task.Delay(100, cancellationToken).ConfigureAwait(false);
- }
-
- cancellationToken.ThrowIfCancellationRequested();
- return await GetSegmentResult(state, segmentPath, segmentIndex, transcodingJob).ConfigureAwait(false);
- }
-
- private Task<object> GetSegmentResult(StreamState state, string segmentPath, int index, TranscodingJob transcodingJob)
- {
- var segmentEndingPositionTicks = GetEndPositionTicks(state, index);
-
- return ResultFactory.GetStaticFileResult(Request, new StaticFileResultOptions
- {
- Path = segmentPath,
- FileShare = FileShareMode.ReadWrite,
- OnComplete = () =>
- {
- if (transcodingJob != null)
- {
- transcodingJob.DownloadPositionTicks = Math.Max(transcodingJob.DownloadPositionTicks ?? segmentEndingPositionTicks, segmentEndingPositionTicks);
- ApiEntryPoint.Instance.OnTranscodeEndRequest(transcodingJob);
- }
- }
- });
- }
-
- private async Task<object> GetMasterPlaylistInternal(StreamRequest request, string method)
- {
- var state = await GetState(request, CancellationToken.None).ConfigureAwait(false);
-
- if (string.IsNullOrEmpty(request.MediaSourceId))
- {
- throw new ArgumentException("MediaSourceId is required");
- }
-
- var playlistText = string.Empty;
-
- if (string.Equals(method, "GET", StringComparison.OrdinalIgnoreCase))
- {
- var audioBitrate = state.OutputAudioBitrate ?? 0;
- var videoBitrate = state.OutputVideoBitrate ?? 0;
-
- playlistText = GetMasterPlaylistFileText(state, videoBitrate + audioBitrate);
- }
-
- return ResultFactory.GetResult(playlistText, MimeTypes.GetMimeType("playlist.m3u8"), new Dictionary<string, string>());
- }
-
- private string GetMasterPlaylistFileText(StreamState state, int totalBitrate)
- {
- var builder = new StringBuilder();
-
- builder.AppendLine("#EXTM3U");
-
- var isLiveStream = state.IsSegmentedLiveStream;
-
- var queryStringIndex = Request.RawUrl.IndexOf('?');
- var queryString = queryStringIndex == -1 ? string.Empty : Request.RawUrl.Substring(queryStringIndex);
-
- // from universal audio service
- if (queryString.IndexOf("SegmentContainer", StringComparison.OrdinalIgnoreCase) == -1 && !string.IsNullOrWhiteSpace(state.Request.SegmentContainer))
- {
- queryString += "&SegmentContainer=" + state.Request.SegmentContainer;
- }
- // from universal audio service
- if (!string.IsNullOrWhiteSpace(state.Request.TranscodeReasons) && queryString.IndexOf("TranscodeReasons=", StringComparison.OrdinalIgnoreCase) == -1)
- {
- queryString += "&TranscodeReasons=" + state.Request.TranscodeReasons;
- }
-
- // Main stream
- var playlistUrl = isLiveStream ? "live.m3u8" : "main.m3u8";
-
- playlistUrl += queryString;
-
- var request = state.Request;
-
- var subtitleStreams = state.MediaSource
- .MediaStreams
- .Where(i => i.IsTextSubtitleStream)
- .ToList();
-
- var subtitleGroup = subtitleStreams.Count > 0 &&
- request is GetMasterHlsVideoPlaylist &&
- (state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Hls || state.VideoRequest.EnableSubtitlesInManifest) ?
- "subs" :
- null;
-
- // If we're burning in subtitles then don't add additional subs to the manifest
- if (state.SubtitleStream != null && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode)
- {
- subtitleGroup = null;
- }
-
- if (!string.IsNullOrWhiteSpace(subtitleGroup))
- {
- AddSubtitles(state, subtitleStreams, builder);
- }
-
- AppendPlaylist(builder, state, playlistUrl, totalBitrate, subtitleGroup);
-
- if (EnableAdaptiveBitrateStreaming(state, isLiveStream))
- {
- var requestedVideoBitrate = state.VideoRequest == null ? 0 : state.VideoRequest.VideoBitRate ?? 0;
-
- // By default, vary by just 200k
- var variation = GetBitrateVariation(totalBitrate);
-
- var newBitrate = totalBitrate - variation;
- var variantUrl = ReplaceBitrate(playlistUrl, requestedVideoBitrate, requestedVideoBitrate - variation);
- AppendPlaylist(builder, state, variantUrl, newBitrate, subtitleGroup);
-
- variation *= 2;
- newBitrate = totalBitrate - variation;
- variantUrl = ReplaceBitrate(playlistUrl, requestedVideoBitrate, requestedVideoBitrate - variation);
- AppendPlaylist(builder, state, variantUrl, newBitrate, subtitleGroup);
- }
-
- return builder.ToString();
- }
-
- private string ReplaceBitrate(string url, int oldValue, int newValue)
- {
- return url.Replace(
- "videobitrate=" + oldValue.ToString(UsCulture),
- "videobitrate=" + newValue.ToString(UsCulture),
- StringComparison.OrdinalIgnoreCase);
- }
-
- private void AddSubtitles(StreamState state, IEnumerable<MediaStream> subtitles, StringBuilder builder)
- {
- var selectedIndex = state.SubtitleStream == null || state.SubtitleDeliveryMethod != SubtitleDeliveryMethod.Hls ? (int?)null : state.SubtitleStream.Index;
-
- foreach (var stream in subtitles)
- {
- const string format = "#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID=\"subs\",NAME=\"{0}\",DEFAULT={1},FORCED={2},AUTOSELECT=YES,URI=\"{3}\",LANGUAGE=\"{4}\"";
-
- var name = stream.DisplayTitle;
-
- var isDefault = selectedIndex.HasValue && selectedIndex.Value == stream.Index;
- var isForced = stream.IsForced;
-
- var url = string.Format("{0}/Subtitles/{1}/subtitles.m3u8?SegmentLength={2}&api_key={3}",
- state.Request.MediaSourceId,
- stream.Index.ToString(UsCulture),
- 30.ToString(UsCulture),
- AuthorizationContext.GetAuthorizationInfo(Request).Token);
-
- var line = string.Format(format,
- name,
- isDefault ? "YES" : "NO",
- isForced ? "YES" : "NO",
- url,
- stream.Language ?? "Unknown");
-
- builder.AppendLine(line);
- }
- }
-
- private bool EnableAdaptiveBitrateStreaming(StreamState state, bool isLiveStream)
- {
- // Within the local network this will likely do more harm than good.
- if (Request.IsLocal || NetworkManager.IsInLocalNetwork(Request.RemoteIp))
- {
- return false;
- }
-
- var request = state.Request as IMasterHlsRequest;
- if (request != null && !request.EnableAdaptiveBitrateStreaming)
- {
- return false;
- }
-
- if (isLiveStream || string.IsNullOrWhiteSpace(state.MediaPath))
- {
- // Opening live streams is so slow it's not even worth it
- return false;
- }
-
- if (string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase))
- {
- return false;
- }
-
- if (string.Equals(state.OutputAudioCodec, "copy", StringComparison.OrdinalIgnoreCase))
- {
- return false;
- }
-
- if (!state.IsOutputVideo)
- {
- return false;
- }
-
- // Having problems in android
- return false;
- //return state.VideoRequest.VideoBitRate.HasValue;
- }
-
- private void AppendPlaylist(StringBuilder builder, StreamState state, string url, int bitrate, string subtitleGroup)
- {
- var header = "#EXT-X-STREAM-INF:BANDWIDTH=" + bitrate.ToString(UsCulture) + ",AVERAGE-BANDWIDTH=" + bitrate.ToString(UsCulture);
-
- // tvos wants resolution, codecs, framerate
- //if (state.TargetFramerate.HasValue)
- //{
- // header += string.Format(",FRAME-RATE=\"{0}\"", state.TargetFramerate.Value.ToString(CultureInfo.InvariantCulture));
- //}
-
- if (!string.IsNullOrWhiteSpace(subtitleGroup))
- {
- header += string.Format(",SUBTITLES=\"{0}\"", subtitleGroup);
- }
-
- builder.AppendLine(header);
- builder.AppendLine(url);
- }
-
- private int GetBitrateVariation(int bitrate)
- {
- // By default, vary by just 50k
- var variation = 50000;
-
- if (bitrate >= 10000000)
- {
- variation = 2000000;
- }
- else if (bitrate >= 5000000)
- {
- variation = 1500000;
- }
- else if (bitrate >= 3000000)
- {
- variation = 1000000;
- }
- else if (bitrate >= 2000000)
- {
- variation = 500000;
- }
- else if (bitrate >= 1000000)
- {
- variation = 300000;
- }
- else if (bitrate >= 600000)
- {
- variation = 200000;
- }
- else if (bitrate >= 400000)
- {
- variation = 100000;
- }
-
- return variation;
- }
-
- private async Task<object> GetVariantPlaylistInternal(StreamRequest request, bool isOutputVideo, string name)
- {
- var state = await GetState(request, CancellationToken.None).ConfigureAwait(false);
-
- var segmentLengths = GetSegmentLengths(state);
-
- var builder = new StringBuilder();
-
- builder.AppendLine("#EXTM3U");
- builder.AppendLine("#EXT-X-PLAYLIST-TYPE:VOD");
- builder.AppendLine("#EXT-X-VERSION:3");
- builder.AppendLine("#EXT-X-TARGETDURATION:" + Math.Ceiling(segmentLengths.Length > 0 ? segmentLengths.Max() : state.SegmentLength).ToString(UsCulture));
- builder.AppendLine("#EXT-X-MEDIA-SEQUENCE:0");
-
- var queryStringIndex = Request.RawUrl.IndexOf('?');
- var queryString = queryStringIndex == -1 ? string.Empty : Request.RawUrl.Substring(queryStringIndex);
-
- //if ((Request.UserAgent ?? string.Empty).IndexOf("roku", StringComparison.OrdinalIgnoreCase) != -1)
- //{
- // queryString = string.Empty;
- //}
-
- var index = 0;
-
- foreach (var length in segmentLengths)
- {
- builder.AppendLine("#EXTINF:" + length.ToString("0.0000", UsCulture) + ", nodesc");
-
- builder.AppendLine(string.Format("hls1/{0}/{1}{2}{3}",
-
- name,
- index.ToString(UsCulture),
- GetSegmentFileExtension(request),
- queryString));
-
- index++;
- }
-
- builder.AppendLine("#EXT-X-ENDLIST");
-
- var playlistText = builder.ToString();
-
- return ResultFactory.GetResult(playlistText, MimeTypes.GetMimeType("playlist.m3u8"), new Dictionary<string, string>());
- }
-
- protected override string GetAudioArguments(StreamState state, EncodingOptions encodingOptions)
- {
- var audioCodec = EncodingHelper.GetAudioEncoder(state);
-
- if (!state.IsOutputVideo)
- {
- if (string.Equals(audioCodec, "copy", StringComparison.OrdinalIgnoreCase))
- {
- return "-acodec copy";
- }
-
- var audioTranscodeParams = new List<string>();
-
- audioTranscodeParams.Add("-acodec " + audioCodec);
-
- if (state.OutputAudioBitrate.HasValue)
- {
- audioTranscodeParams.Add("-ab " + state.OutputAudioBitrate.Value.ToString(UsCulture));
- }
-
- if (state.OutputAudioChannels.HasValue)
- {
- audioTranscodeParams.Add("-ac " + state.OutputAudioChannels.Value.ToString(UsCulture));
- }
-
- if (state.OutputAudioSampleRate.HasValue)
- {
- audioTranscodeParams.Add("-ar " + state.OutputAudioSampleRate.Value.ToString(UsCulture));
- }
-
- audioTranscodeParams.Add("-vn");
- return string.Join(" ", audioTranscodeParams.ToArray());
- }
-
- if (string.Equals(audioCodec, "copy", StringComparison.OrdinalIgnoreCase))
- {
- var videoCodec = EncodingHelper.GetVideoEncoder(state, encodingOptions);
-
- if (string.Equals(videoCodec, "copy", StringComparison.OrdinalIgnoreCase) && state.EnableBreakOnNonKeyFrames(videoCodec))
- {
- return "-codec:a:0 copy -copypriorss:a:0 0";
- }
-
- return "-codec:a:0 copy";
- }
-
- var args = "-codec:a:0 " + audioCodec;
-
- var channels = state.OutputAudioChannels;
-
- if (channels.HasValue)
- {
- args += " -ac " + channels.Value;
- }
-
- var bitrate = state.OutputAudioBitrate;
-
- if (bitrate.HasValue)
- {
- args += " -ab " + bitrate.Value.ToString(UsCulture);
- }
-
- if (state.OutputAudioSampleRate.HasValue)
- {
- args += " -ar " + state.OutputAudioSampleRate.Value.ToString(UsCulture);
- }
-
- args += " " + EncodingHelper.GetAudioFilterParam(state, encodingOptions, true);
-
- return args;
- }
-
- protected override string GetVideoArguments(StreamState state, EncodingOptions encodingOptions)
- {
- if (!state.IsOutputVideo)
- {
- return string.Empty;
- }
-
- var codec = EncodingHelper.GetVideoEncoder(state, encodingOptions);
-
- var args = "-codec:v:0 " + codec;
-
- if (state.EnableMpegtsM2TsMode)
- {
- args += " -mpegts_m2ts_mode 1";
- }
-
- // See if we can save come cpu cycles by avoiding encoding
- if (string.Equals(codec, "copy", StringComparison.OrdinalIgnoreCase))
- {
- if (state.VideoStream != null && EncodingHelper.IsH264(state.VideoStream) && !string.Equals(state.VideoStream.NalLengthSize, "0", StringComparison.OrdinalIgnoreCase))
- {
- args += " -bsf:v h264_mp4toannexb";
- }
-
- //args += " -flags -global_header";
- }
- else
- {
- var keyFrameArg = string.Format(" -force_key_frames \"expr:gte(t,n_forced*{0})\"",
- state.SegmentLength.ToString(UsCulture));
-
- var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsTextSubtitleStream && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode;
-
- args += " " + EncodingHelper.GetVideoQualityParam(state, codec, encodingOptions, GetDefaultH264Preset()) + keyFrameArg;
-
- //args += " -mixed-refs 0 -refs 3 -x264opts b_pyramid=0:weightb=0:weightp=0";
-
- // Add resolution params, if specified
- if (!hasGraphicalSubs)
- {
- args += EncodingHelper.GetOutputSizeParam(state, codec, true);
- }
-
- // This is for internal graphical subs
- if (hasGraphicalSubs)
- {
- args += EncodingHelper.GetGraphicalSubtitleParam(state, codec);
- }
-
- //args += " -flags -global_header";
- }
-
- if (args.IndexOf("-copyts", StringComparison.OrdinalIgnoreCase) == -1)
- {
- args += " -copyts";
- }
-
- if (!string.IsNullOrEmpty(state.OutputVideoSync))
- {
- args += " -vsync " + state.OutputVideoSync;
- }
-
- args += EncodingHelper.GetOutputFFlags(state);
-
- return args;
- }
-
- protected override string GetCommandLineArguments(string outputPath, EncodingOptions encodingOptions, StreamState state, bool isEncoding)
- {
- var threads = EncodingHelper.GetNumberOfThreads(state, encodingOptions, false);
-
- var inputModifier = EncodingHelper.GetInputModifier(state, encodingOptions);
-
- // If isEncoding is true we're actually starting ffmpeg
- var startNumber = GetStartNumber(state);
- var startNumberParam = isEncoding ? startNumber.ToString(UsCulture) : "0";
-
- var mapArgs = state.IsOutputVideo ? EncodingHelper.GetMapArgs(state) : string.Empty;
-
- var outputTsArg = Path.Combine(FileSystem.GetDirectoryName(outputPath), Path.GetFileNameWithoutExtension(outputPath)) + "%d" + GetSegmentFileExtension(state.Request);
-
- var timeDeltaParam = String.Empty;
-
- if (isEncoding && startNumber > 0)
- {
- var startTime = state.SegmentLength * startNumber;
- timeDeltaParam = string.Format("-segment_time_delta -{0}", startTime);
- }
-
- var segmentFormat = GetSegmentFileExtension(state.Request).TrimStart('.');
- if (string.Equals(segmentFormat, "ts", StringComparison.OrdinalIgnoreCase))
- {
- segmentFormat = "mpegts";
- }
-
- var videoCodec = EncodingHelper.GetVideoEncoder(state, encodingOptions);
- var breakOnNonKeyFrames = state.EnableBreakOnNonKeyFrames(videoCodec);
-
- var breakOnNonKeyFramesArg = breakOnNonKeyFrames ? " -break_non_keyframes 1" : "";
-
- return string.Format("{0} {1} -map_metadata -1 -map_chapters -1 -threads {2} {3} {4} {5} -f segment -max_delay 5000000 -avoid_negative_ts disabled -start_at_zero -segment_time {6} {10} -individual_header_trailer 0{12} -segment_format {11} -segment_list_type m3u8 -segment_start_number {7} -segment_list \"{8}\" -y \"{9}\"",
- inputModifier,
- EncodingHelper.GetInputArgument(state, encodingOptions),
- threads,
- mapArgs,
- GetVideoArguments(state, encodingOptions),
- GetAudioArguments(state, encodingOptions),
- state.SegmentLength.ToString(UsCulture),
- startNumberParam,
- outputPath,
- outputTsArg,
- timeDeltaParam,
- segmentFormat,
- breakOnNonKeyFramesArg
- ).Trim();
- }
- }
-} \ No newline at end of file
diff --git a/MediaBrowser.Api/Playback/Hls/HlsSegmentService.cs b/MediaBrowser.Api/Playback/Hls/HlsSegmentService.cs
deleted file mode 100644
index 52cc02528..000000000
--- a/MediaBrowser.Api/Playback/Hls/HlsSegmentService.cs
+++ /dev/null
@@ -1,163 +0,0 @@
-using MediaBrowser.Controller;
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Net;
-using System;
-using System.IO;
-using System.Linq;
-using System.Threading.Tasks;
-
-using MediaBrowser.Controller.MediaEncoding;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Model.Services;
-
-namespace MediaBrowser.Api.Playback.Hls
-{
- /// <summary>
- /// Class GetHlsAudioSegment
- /// </summary>
- // Can't require authentication just yet due to seeing some requests come from Chrome without full query string
- //[Authenticated]
- [Route("/Audio/{Id}/hls/{SegmentId}/stream.mp3", "GET")]
- [Route("/Audio/{Id}/hls/{SegmentId}/stream.aac", "GET")]
- public class GetHlsAudioSegmentLegacy
- {
- // TODO: Deprecate with new iOS app
-
- /// <summary>
- /// Gets or sets the id.
- /// </summary>
- /// <value>The id.</value>
- public string Id { get; set; }
-
- /// <summary>
- /// Gets or sets the segment id.
- /// </summary>
- /// <value>The segment id.</value>
- public string SegmentId { get; set; }
- }
-
- /// <summary>
- /// Class GetHlsVideoSegment
- /// </summary>
- [Route("/Videos/{Id}/hls/{PlaylistId}/stream.m3u8", "GET")]
- [Authenticated]
- public class GetHlsPlaylistLegacy
- {
- // TODO: Deprecate with new iOS app
-
- /// <summary>
- /// Gets or sets the id.
- /// </summary>
- /// <value>The id.</value>
- public string Id { get; set; }
-
- public string PlaylistId { get; set; }
- }
-
- [Route("/Videos/ActiveEncodings", "DELETE")]
- [Authenticated]
- public class StopEncodingProcess
- {
- [ApiMember(Name = "DeviceId", Description = "The device id of the client requesting. Used to stop encoding processes when needed.", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "DELETE")]
- public string DeviceId { get; set; }
-
- [ApiMember(Name = "PlaySessionId", Description = "The play session id", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "DELETE")]
- public string PlaySessionId { get; set; }
- }
-
- /// <summary>
- /// Class GetHlsVideoSegment
- /// </summary>
- // Can't require authentication just yet due to seeing some requests come from Chrome without full query string
- //[Authenticated]
- [Route("/Videos/{Id}/hls/{PlaylistId}/{SegmentId}.{SegmentContainer}", "GET")]
- public class GetHlsVideoSegmentLegacy : VideoStreamRequest
- {
- public string PlaylistId { get; set; }
-
- /// <summary>
- /// Gets or sets the segment id.
- /// </summary>
- /// <value>The segment id.</value>
- public string SegmentId { get; set; }
- }
-
- public class HlsSegmentService : BaseApiService
- {
- private readonly IServerApplicationPaths _appPaths;
- private readonly IServerConfigurationManager _config;
- private readonly IFileSystem _fileSystem;
-
- public HlsSegmentService(IServerApplicationPaths appPaths, IServerConfigurationManager config, IFileSystem fileSystem)
- {
- _appPaths = appPaths;
- _config = config;
- _fileSystem = fileSystem;
- }
-
- public Task<object> Get(GetHlsPlaylistLegacy request)
- {
- var file = request.PlaylistId + Path.GetExtension(Request.PathInfo);
- file = Path.Combine(_appPaths.TranscodingTempPath, file);
-
- return GetFileResult(file, file);
- }
-
- public void Delete(StopEncodingProcess request)
- {
- ApiEntryPoint.Instance.KillTranscodingJobs(request.DeviceId, request.PlaySessionId, path => true);
- }
-
- /// <summary>
- /// Gets the specified request.
- /// </summary>
- /// <param name="request">The request.</param>
- /// <returns>System.Object.</returns>
- public Task<object> Get(GetHlsVideoSegmentLegacy request)
- {
- var file = request.SegmentId + Path.GetExtension(Request.PathInfo);
-
- var transcodeFolderPath = _config.ApplicationPaths.TranscodingTempPath;
- file = Path.Combine(transcodeFolderPath, file);
-
- var normalizedPlaylistId = request.PlaylistId;
-
- var playlistPath = _fileSystem.GetFilePaths(transcodeFolderPath)
- .FirstOrDefault(i => string.Equals(Path.GetExtension(i), ".m3u8", StringComparison.OrdinalIgnoreCase) && i.IndexOf(normalizedPlaylistId, StringComparison.OrdinalIgnoreCase) != -1);
-
- return GetFileResult(file, playlistPath);
- }
-
- /// <summary>
- /// Gets the specified request.
- /// </summary>
- /// <param name="request">The request.</param>
- /// <returns>System.Object.</returns>
- public Task<object> Get(GetHlsAudioSegmentLegacy request)
- {
- // TODO: Deprecate with new iOS app
- var file = request.SegmentId + Path.GetExtension(Request.PathInfo);
- file = Path.Combine(_appPaths.TranscodingTempPath, file);
-
- return ResultFactory.GetStaticFileResult(Request, file, FileShareMode.ReadWrite);
- }
-
- private Task<object> GetFileResult(string path, string playlistPath)
- {
- var transcodingJob = ApiEntryPoint.Instance.OnTranscodeBeginRequest(playlistPath, TranscodingJobType.Hls);
-
- return ResultFactory.GetStaticFileResult(Request, new StaticFileResultOptions
- {
- Path = path,
- FileShare = FileShareMode.ReadWrite,
- OnComplete = () =>
- {
- if (transcodingJob != null)
- {
- ApiEntryPoint.Instance.OnTranscodeEndRequest(transcodingJob);
- }
- }
- });
- }
- }
-}
diff --git a/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs b/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs
deleted file mode 100644
index 9b3c8a08f..000000000
--- a/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs
+++ /dev/null
@@ -1,137 +0,0 @@
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Devices;
-using MediaBrowser.Controller.Dlna;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.MediaEncoding;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Model.Serialization;
-using System;
-using MediaBrowser.Controller.Net;
-using MediaBrowser.Model.Configuration;
-using MediaBrowser.Model.Dlna;
-using MediaBrowser.Model.Services;
-
-namespace MediaBrowser.Api.Playback.Hls
-{
- [Route("/Videos/{Id}/live.m3u8", "GET")]
- public class GetLiveHlsStream : VideoStreamRequest
- {
- }
-
- /// <summary>
- /// Class VideoHlsService
- /// </summary>
- [Authenticated]
- public class VideoHlsService : BaseHlsService
- {
- public object Get(GetLiveHlsStream request)
- {
- return ProcessRequest(request, true);
- }
-
- /// <summary>
- /// Gets the audio arguments.
- /// </summary>
- protected override string GetAudioArguments(StreamState state, EncodingOptions encodingOptions)
- {
- var codec = EncodingHelper.GetAudioEncoder(state);
-
- if (string.Equals(codec, "copy", StringComparison.OrdinalIgnoreCase))
- {
- return "-codec:a:0 copy";
- }
-
- var args = "-codec:a:0 " + codec;
-
- var channels = state.OutputAudioChannels;
-
- if (channels.HasValue)
- {
- args += " -ac " + channels.Value;
- }
-
- var bitrate = state.OutputAudioBitrate;
-
- if (bitrate.HasValue)
- {
- args += " -ab " + bitrate.Value.ToString(UsCulture);
- }
-
- if (state.OutputAudioSampleRate.HasValue)
- {
- args += " -ar " + state.OutputAudioSampleRate.Value.ToString(UsCulture);
- }
-
- args += " " + EncodingHelper.GetAudioFilterParam(state, encodingOptions, true);
-
- return args;
- }
-
- /// <summary>
- /// Gets the video arguments.
- /// </summary>
- protected override string GetVideoArguments(StreamState state, EncodingOptions encodingOptions)
- {
- if (!state.IsOutputVideo)
- {
- return string.Empty;
- }
-
- var codec = EncodingHelper.GetVideoEncoder(state, encodingOptions);
-
- var args = "-codec:v:0 " + codec;
-
- if (state.EnableMpegtsM2TsMode)
- {
- args += " -mpegts_m2ts_mode 1";
- }
-
- // See if we can save come cpu cycles by avoiding encoding
- if (codec.Equals("copy", StringComparison.OrdinalIgnoreCase))
- {
- // if h264_mp4toannexb is ever added, do not use it for live tv
- if (state.VideoStream != null && EncodingHelper.IsH264(state.VideoStream) &&
- !string.Equals(state.VideoStream.NalLengthSize, "0", StringComparison.OrdinalIgnoreCase))
- {
- args += " -bsf:v h264_mp4toannexb";
- }
- }
- else
- {
- var keyFrameArg = string.Format(" -force_key_frames \"expr:gte(t,n_forced*{0})\"",
- state.SegmentLength.ToString(UsCulture));
-
- var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsTextSubtitleStream && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode;
-
- args += " " + EncodingHelper.GetVideoQualityParam(state, codec, encodingOptions, GetDefaultH264Preset()) + keyFrameArg;
-
- // Add resolution params, if specified
- if (!hasGraphicalSubs)
- {
- args += EncodingHelper.GetOutputSizeParam(state, codec);
- }
-
- // This is for internal graphical subs
- if (hasGraphicalSubs)
- {
- args += EncodingHelper.GetGraphicalSubtitleParam(state, codec);
- }
- }
-
- args += " -flags -global_header";
-
- if (!string.IsNullOrEmpty(state.OutputVideoSync))
- {
- args += " -vsync " + state.OutputVideoSync;
- }
-
- args += EncodingHelper.GetOutputFFlags(state);
-
- return args;
- }
-
- public VideoHlsService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IJsonSerializer jsonSerializer, IAuthorizationContext authorizationContext) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient, jsonSerializer, authorizationContext)
- {
- }
- }
-}
diff --git a/MediaBrowser.Api/Playback/MediaInfoService.cs b/MediaBrowser.Api/Playback/MediaInfoService.cs
deleted file mode 100644
index 536236f5f..000000000
--- a/MediaBrowser.Api/Playback/MediaInfoService.cs
+++ /dev/null
@@ -1,591 +0,0 @@
-using MediaBrowser.Common.Net;
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Devices;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.Net;
-using MediaBrowser.Model.Dlna;
-using MediaBrowser.Model.Dto;
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.MediaInfo;
-using MediaBrowser.Model.Session;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Controller.Entities.Audio;
-using MediaBrowser.Controller.MediaEncoding;
-using MediaBrowser.Model.Serialization;
-using MediaBrowser.Model.Services;
-
-namespace MediaBrowser.Api.Playback
-{
- [Route("/Items/{Id}/PlaybackInfo", "GET", Summary = "Gets live playback media info for an item")]
- public class GetPlaybackInfo : IReturn<PlaybackInfoResponse>
- {
- [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
- public string Id { get; set; }
-
- [ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
- public string UserId { get; set; }
- }
-
- [Route("/Items/{Id}/PlaybackInfo", "POST", Summary = "Gets live playback media info for an item")]
- public class GetPostedPlaybackInfo : PlaybackInfoRequest, IReturn<PlaybackInfoResponse>
- {
- }
-
- [Route("/LiveStreams/Open", "POST", Summary = "Opens a media source")]
- public class OpenMediaSource : LiveStreamRequest, IReturn<LiveStreamResponse>
- {
- }
-
- [Route("/LiveStreams/Close", "POST", Summary = "Closes a media source")]
- public class CloseMediaSource : IReturnVoid
- {
- [ApiMember(Name = "LiveStreamId", Description = "LiveStreamId", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
- public string LiveStreamId { get; set; }
- }
-
- [Route("/Playback/BitrateTest", "GET")]
- public class GetBitrateTestBytes
- {
- [ApiMember(Name = "Size", Description = "Size", IsRequired = true, DataType = "int", ParameterType = "query", Verb = "GET")]
- public long Size { get; set; }
-
- public GetBitrateTestBytes()
- {
- // 100k
- Size = 102400;
- }
- }
-
- [Authenticated]
- public class MediaInfoService : BaseApiService
- {
- private readonly IMediaSourceManager _mediaSourceManager;
- private readonly IDeviceManager _deviceManager;
- private readonly ILibraryManager _libraryManager;
- private readonly IServerConfigurationManager _config;
- private readonly INetworkManager _networkManager;
- private readonly IMediaEncoder _mediaEncoder;
- private readonly IUserManager _userManager;
- private readonly IJsonSerializer _json;
- private readonly IAuthorizationContext _authContext;
-
- public MediaInfoService(IMediaSourceManager mediaSourceManager, IDeviceManager deviceManager, ILibraryManager libraryManager, IServerConfigurationManager config, INetworkManager networkManager, IMediaEncoder mediaEncoder, IUserManager userManager, IJsonSerializer json, IAuthorizationContext authContext)
- {
- _mediaSourceManager = mediaSourceManager;
- _deviceManager = deviceManager;
- _libraryManager = libraryManager;
- _config = config;
- _networkManager = networkManager;
- _mediaEncoder = mediaEncoder;
- _userManager = userManager;
- _json = json;
- _authContext = authContext;
- }
-
- public object Get(GetBitrateTestBytes request)
- {
- var bytes = new byte[request.Size];
-
- for (var i = 0; i < bytes.Length; i++)
- {
- bytes[i] = 0;
- }
-
- return ResultFactory.GetResult(bytes, "application/octet-stream");
- }
-
- public async Task<object> Get(GetPlaybackInfo request)
- {
- var result = await GetPlaybackInfo(request.Id, request.UserId, new[] { MediaType.Audio, MediaType.Video }).ConfigureAwait(false);
- return ToOptimizedResult(result);
- }
-
- public async Task<object> Post(OpenMediaSource request)
- {
- var result = await OpenMediaSource(request).ConfigureAwait(false);
-
- return ToOptimizedResult(result);
- }
-
- private async Task<LiveStreamResponse> OpenMediaSource(OpenMediaSource request)
- {
- var authInfo = _authContext.GetAuthorizationInfo(Request);
-
- var result = await _mediaSourceManager.OpenLiveStream(request, CancellationToken.None).ConfigureAwait(false);
-
- var profile = request.DeviceProfile;
- if (profile == null)
- {
- var caps = _deviceManager.GetCapabilities(authInfo.DeviceId);
- if (caps != null)
- {
- profile = caps.DeviceProfile;
- }
- }
-
- if (profile != null)
- {
- var item = _libraryManager.GetItemById(request.ItemId);
-
- SetDeviceSpecificData(item, result.MediaSource, profile, authInfo, request.MaxStreamingBitrate,
- request.StartTimeTicks ?? 0, result.MediaSource.Id, request.AudioStreamIndex,
- request.SubtitleStreamIndex, request.MaxAudioChannels, request.PlaySessionId, request.UserId, request.EnableDirectPlay, true, request.EnableDirectStream, true, true, true);
- }
- else
- {
- if (!string.IsNullOrWhiteSpace(result.MediaSource.TranscodingUrl))
- {
- result.MediaSource.TranscodingUrl += "&LiveStreamId=" + result.MediaSource.LiveStreamId;
- }
- }
-
- return result;
- }
-
- public void Post(CloseMediaSource request)
- {
- var task = _mediaSourceManager.CloseLiveStream(request.LiveStreamId);
- Task.WaitAll(task);
- }
-
- public async Task<PlaybackInfoResponse> GetPlaybackInfo(GetPostedPlaybackInfo request)
- {
- var authInfo = _authContext.GetAuthorizationInfo(Request);
-
- var profile = request.DeviceProfile;
-
- //Logger.Info("GetPostedPlaybackInfo profile: {0}", _json.SerializeToString(profile));
-
- if (profile == null)
- {
- var caps = _deviceManager.GetCapabilities(authInfo.DeviceId);
- if (caps != null)
- {
- profile = caps.DeviceProfile;
- }
- }
-
- var info = await GetPlaybackInfo(request.Id, request.UserId, new[] { MediaType.Audio, MediaType.Video }, request.MediaSourceId, request.LiveStreamId).ConfigureAwait(false);
-
- if (profile != null)
- {
- var mediaSourceId = request.MediaSourceId;
-
- SetDeviceSpecificData(request.Id, info, profile, authInfo, request.MaxStreamingBitrate ?? profile.MaxStreamingBitrate, request.StartTimeTicks ?? 0, mediaSourceId, request.AudioStreamIndex, request.SubtitleStreamIndex, request.MaxAudioChannels, request.UserId, request.EnableDirectPlay, true, request.EnableDirectStream, request.EnableTranscoding, request.AllowVideoStreamCopy, request.AllowAudioStreamCopy);
- }
-
- if (request.AutoOpenLiveStream)
- {
- var mediaSource = string.IsNullOrWhiteSpace(request.MediaSourceId) ? info.MediaSources.FirstOrDefault() : info.MediaSources.FirstOrDefault(i => string.Equals(i.Id, request.MediaSourceId, StringComparison.Ordinal));
-
- if (mediaSource != null && mediaSource.RequiresOpening && string.IsNullOrWhiteSpace(mediaSource.LiveStreamId))
- {
- var openStreamResult = await OpenMediaSource(new OpenMediaSource
- {
- AudioStreamIndex = request.AudioStreamIndex,
- DeviceProfile = request.DeviceProfile,
- EnableDirectPlay = request.EnableDirectPlay,
- EnableDirectStream = request.EnableDirectStream,
- ItemId = request.Id,
- MaxAudioChannels = request.MaxAudioChannels,
- MaxStreamingBitrate = request.MaxStreamingBitrate,
- PlaySessionId = info.PlaySessionId,
- StartTimeTicks = request.StartTimeTicks,
- SubtitleStreamIndex = request.SubtitleStreamIndex,
- UserId = request.UserId,
- OpenToken = mediaSource.OpenToken,
- EnableMediaProbe = request.EnableMediaProbe
-
- }).ConfigureAwait(false);
-
- info.MediaSources = new List<MediaSourceInfo> { openStreamResult.MediaSource };
- }
- }
-
- return info;
- }
-
- public async Task<object> Post(GetPostedPlaybackInfo request)
- {
- var result = await GetPlaybackInfo(request).ConfigureAwait(false);
-
- return ToOptimizedResult(result);
- }
-
- private T Clone<T>(T obj)
- {
- // Since we're going to be setting properties on MediaSourceInfos that come out of _mediaSourceManager, we should clone it
- // Should we move this directly into MediaSourceManager?
-
- var json = _json.SerializeToString(obj);
- return _json.DeserializeFromString<T>(json);
- }
-
- private async Task<PlaybackInfoResponse> GetPlaybackInfo(string id, string userId, string[] supportedLiveMediaTypes, string mediaSourceId = null, string liveStreamId = null)
- {
- var result = new PlaybackInfoResponse();
-
- if (string.IsNullOrWhiteSpace(liveStreamId))
- {
- IEnumerable<MediaSourceInfo> mediaSources;
- try
- {
- mediaSources = await _mediaSourceManager.GetPlayackMediaSources(id, userId, true, supportedLiveMediaTypes, CancellationToken.None).ConfigureAwait(false);
- }
- catch (PlaybackException ex)
- {
- mediaSources = new List<MediaSourceInfo>();
- result.ErrorCode = ex.ErrorCode;
- }
-
- result.MediaSources = mediaSources.ToList();
-
- if (!string.IsNullOrWhiteSpace(mediaSourceId))
- {
- result.MediaSources = result.MediaSources
- .Where(i => string.Equals(i.Id, mediaSourceId, StringComparison.OrdinalIgnoreCase))
- .ToList();
- }
- }
- else
- {
- var mediaSource = await _mediaSourceManager.GetLiveStream(liveStreamId, CancellationToken.None).ConfigureAwait(false);
-
- result.MediaSources = new List<MediaSourceInfo> { mediaSource };
- }
-
- if (result.MediaSources.Count == 0)
- {
- if (!result.ErrorCode.HasValue)
- {
- result.ErrorCode = PlaybackErrorCode.NoCompatibleStream;
- }
- }
- else
- {
- result.MediaSources = Clone(result.MediaSources);
-
- result.PlaySessionId = Guid.NewGuid().ToString("N");
- }
-
- return result;
- }
-
- private void SetDeviceSpecificData(string itemId,
- PlaybackInfoResponse result,
- DeviceProfile profile,
- AuthorizationInfo auth,
- long? maxBitrate,
- long startTimeTicks,
- string mediaSourceId,
- int? audioStreamIndex,
- int? subtitleStreamIndex,
- int? maxAudioChannels,
- string userId,
- bool enableDirectPlay,
- bool forceDirectPlayRemoteMediaSource,
- bool enableDirectStream,
- bool enableTranscoding,
- bool allowVideoStreamCopy,
- bool allowAudioStreamCopy)
- {
- var item = _libraryManager.GetItemById(itemId);
-
- foreach (var mediaSource in result.MediaSources)
- {
- SetDeviceSpecificData(item, mediaSource, profile, auth, maxBitrate, startTimeTicks, mediaSourceId, audioStreamIndex, subtitleStreamIndex, maxAudioChannels, result.PlaySessionId, userId, enableDirectPlay, forceDirectPlayRemoteMediaSource, enableDirectStream, enableTranscoding, allowVideoStreamCopy, allowAudioStreamCopy);
- }
-
- SortMediaSources(result, maxBitrate);
- }
-
- private void SetDeviceSpecificData(BaseItem item,
- MediaSourceInfo mediaSource,
- DeviceProfile profile,
- AuthorizationInfo auth,
- long? maxBitrate,
- long startTimeTicks,
- string mediaSourceId,
- int? audioStreamIndex,
- int? subtitleStreamIndex,
- int? maxAudioChannels,
- string playSessionId,
- string userId,
- bool enableDirectPlay,
- bool forceDirectPlayRemoteMediaSource,
- bool enableDirectStream,
- bool enableTranscoding,
- bool allowVideoStreamCopy,
- bool allowAudioStreamCopy)
- {
- var streamBuilder = new StreamBuilder(_mediaEncoder, Logger);
-
- var options = new VideoOptions
- {
- MediaSources = new List<MediaSourceInfo> { mediaSource },
- Context = EncodingContext.Streaming,
- DeviceId = auth.DeviceId,
- ItemId = item.Id.ToString("N"),
- Profile = profile,
- MaxAudioChannels = maxAudioChannels
- };
-
- if (string.Equals(mediaSourceId, mediaSource.Id, StringComparison.OrdinalIgnoreCase))
- {
- options.MediaSourceId = mediaSourceId;
- options.AudioStreamIndex = audioStreamIndex;
- options.SubtitleStreamIndex = subtitleStreamIndex;
- }
-
- var user = _userManager.GetUserById(userId);
-
- if (!enableDirectPlay)
- {
- mediaSource.SupportsDirectPlay = false;
- }
- if (!enableDirectStream)
- {
- mediaSource.SupportsDirectStream = false;
- }
- if (!enableTranscoding)
- {
- mediaSource.SupportsTranscoding = false;
- }
-
- if (item is Audio)
- {
- Logger.Info("User policy for {0}. EnableAudioPlaybackTranscoding: {1}", user.Name, user.Policy.EnableAudioPlaybackTranscoding);
- }
- else
- {
- Logger.Info("User policy for {0}. EnablePlaybackRemuxing: {1} EnableVideoPlaybackTranscoding: {2} EnableAudioPlaybackTranscoding: {3}",
- user.Name,
- user.Policy.EnablePlaybackRemuxing,
- user.Policy.EnableVideoPlaybackTranscoding,
- user.Policy.EnableAudioPlaybackTranscoding);
- }
-
- if (mediaSource.SupportsDirectPlay)
- {
- if (mediaSource.IsRemote && forceDirectPlayRemoteMediaSource)
- {
- }
- else
- {
- var supportsDirectStream = mediaSource.SupportsDirectStream;
-
- // Dummy this up to fool StreamBuilder
- mediaSource.SupportsDirectStream = true;
- options.MaxBitrate = maxBitrate;
-
- if (item is Audio)
- {
- if (!user.Policy.EnableAudioPlaybackTranscoding)
- {
- options.ForceDirectPlay = true;
- }
- }
- else if (item is Video)
- {
- if (!user.Policy.EnableAudioPlaybackTranscoding && !user.Policy.EnableVideoPlaybackTranscoding && !user.Policy.EnablePlaybackRemuxing)
- {
- options.ForceDirectPlay = true;
- }
- }
-
- // The MediaSource supports direct stream, now test to see if the client supports it
- var streamInfo = string.Equals(item.MediaType, MediaType.Audio, StringComparison.OrdinalIgnoreCase) ?
- streamBuilder.BuildAudioItem(options) :
- streamBuilder.BuildVideoItem(options);
-
- if (streamInfo == null || !streamInfo.IsDirectStream)
- {
- mediaSource.SupportsDirectPlay = false;
- }
-
- // Set this back to what it was
- mediaSource.SupportsDirectStream = supportsDirectStream;
-
- if (streamInfo != null)
- {
- SetDeviceSpecificSubtitleInfo(streamInfo, mediaSource, auth.Token);
- }
- }
- }
-
- if (mediaSource.SupportsDirectStream)
- {
- options.MaxBitrate = GetMaxBitrate(maxBitrate);
-
- if (item is Audio)
- {
- if (!user.Policy.EnableAudioPlaybackTranscoding)
- {
- options.ForceDirectStream = true;
- }
- }
- else if (item is Video)
- {
- if (!user.Policy.EnableAudioPlaybackTranscoding && !user.Policy.EnableVideoPlaybackTranscoding && !user.Policy.EnablePlaybackRemuxing)
- {
- options.ForceDirectStream = true;
- }
- }
-
- // The MediaSource supports direct stream, now test to see if the client supports it
- var streamInfo = string.Equals(item.MediaType, MediaType.Audio, StringComparison.OrdinalIgnoreCase) ?
- streamBuilder.BuildAudioItem(options) :
- streamBuilder.BuildVideoItem(options);
-
- if (streamInfo == null || !streamInfo.IsDirectStream)
- {
- mediaSource.SupportsDirectStream = false;
- }
-
- if (streamInfo != null)
- {
- SetDeviceSpecificSubtitleInfo(streamInfo, mediaSource, auth.Token);
- }
- }
-
- if (mediaSource.SupportsTranscoding)
- {
- options.MaxBitrate = GetMaxBitrate(maxBitrate);
-
- // The MediaSource supports direct stream, now test to see if the client supports it
- var streamInfo = string.Equals(item.MediaType, MediaType.Audio, StringComparison.OrdinalIgnoreCase) ?
- streamBuilder.BuildAudioItem(options) :
- streamBuilder.BuildVideoItem(options);
-
- if (streamInfo != null)
- {
- streamInfo.PlaySessionId = playSessionId;
-
- if (streamInfo.PlayMethod == PlayMethod.Transcode)
- {
- streamInfo.StartPositionTicks = startTimeTicks;
- mediaSource.TranscodingUrl = streamInfo.ToUrl("-", auth.Token).TrimStart('-');
-
- if (!allowVideoStreamCopy)
- {
- mediaSource.TranscodingUrl += "&allowVideoStreamCopy=false";
- }
- if (!allowAudioStreamCopy)
- {
- mediaSource.TranscodingUrl += "&allowAudioStreamCopy=false";
- }
- mediaSource.TranscodingContainer = streamInfo.Container;
- mediaSource.TranscodingSubProtocol = streamInfo.SubProtocol;
- }
-
- // Do this after the above so that StartPositionTicks is set
- SetDeviceSpecificSubtitleInfo(streamInfo, mediaSource, auth.Token);
- }
- }
- }
-
- private long? GetMaxBitrate(long? clientMaxBitrate)
- {
- var maxBitrate = clientMaxBitrate;
- var remoteClientMaxBitrate = _config.Configuration.RemoteClientBitrateLimit;
-
- if (remoteClientMaxBitrate > 0)
- {
- var isInLocalNetwork = _networkManager.IsInLocalNetwork(Request.RemoteIp);
-
- Logger.Info("RemoteClientBitrateLimit: {0}, RemoteIp: {1}, IsInLocalNetwork: {2}", remoteClientMaxBitrate, Request.RemoteIp, isInLocalNetwork);
- if (!isInLocalNetwork)
- {
- maxBitrate = Math.Min(maxBitrate ?? remoteClientMaxBitrate, remoteClientMaxBitrate);
- }
- }
-
- return maxBitrate;
- }
-
- private void SetDeviceSpecificSubtitleInfo(StreamInfo info, MediaSourceInfo mediaSource, string accessToken)
- {
- var profiles = info.GetSubtitleProfiles(false, "-", accessToken);
- mediaSource.DefaultSubtitleStreamIndex = info.SubtitleStreamIndex;
-
- mediaSource.TranscodeReasons = info.TranscodeReasons;
-
- foreach (var profile in profiles)
- {
- foreach (var stream in mediaSource.MediaStreams)
- {
- if (stream.Type == MediaStreamType.Subtitle && stream.Index == profile.Index)
- {
- stream.DeliveryMethod = profile.DeliveryMethod;
-
- if (profile.DeliveryMethod == SubtitleDeliveryMethod.External)
- {
- stream.DeliveryUrl = profile.Url.TrimStart('-');
- stream.IsExternalUrl = profile.IsExternalUrl;
- }
- }
- }
- }
- }
-
- private void SortMediaSources(PlaybackInfoResponse result, long? maxBitrate)
- {
- var originalList = result.MediaSources.ToList();
-
- result.MediaSources = result.MediaSources.OrderBy(i =>
- {
- // Nothing beats direct playing a file
- if (i.SupportsDirectPlay && i.Protocol == MediaProtocol.File)
- {
- return 0;
- }
-
- return 1;
-
- }).ThenBy(i =>
- {
- // Let's assume direct streaming a file is just as desirable as direct playing a remote url
- if (i.SupportsDirectPlay || i.SupportsDirectStream)
- {
- return 0;
- }
-
- return 1;
-
- }).ThenBy(i =>
- {
- switch (i.Protocol)
- {
- case MediaProtocol.File:
- return 0;
- default:
- return 1;
- }
-
- }).ThenBy(i =>
- {
- if (maxBitrate.HasValue)
- {
- if (i.Bitrate.HasValue)
- {
- if (i.Bitrate.Value <= maxBitrate.Value)
- {
- return 0;
- }
-
- return 2;
- }
- }
-
- return 1;
-
- }).ThenBy(originalList.IndexOf)
- .ToList();
- }
- }
-}
diff --git a/MediaBrowser.Api/Playback/Progressive/AudioService.cs b/MediaBrowser.Api/Playback/Progressive/AudioService.cs
deleted file mode 100644
index 44e096dd7..000000000
--- a/MediaBrowser.Api/Playback/Progressive/AudioService.cs
+++ /dev/null
@@ -1,67 +0,0 @@
-using MediaBrowser.Common.Net;
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Devices;
-using MediaBrowser.Controller.Dlna;
-using MediaBrowser.Controller.Drawing;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.MediaEncoding;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Model.Serialization;
-using System.Collections.Generic;
-using System.Threading.Tasks;
-using MediaBrowser.Controller.Net;
-using MediaBrowser.Model.Configuration;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Model.Services;
-using MediaBrowser.Model.System;
-
-namespace MediaBrowser.Api.Playback.Progressive
-{
- /// <summary>
- /// Class GetAudioStream
- /// </summary>
- [Route("/Audio/{Id}/stream.{Container}", "GET", Summary = "Gets an audio stream")]
- [Route("/Audio/{Id}/stream", "GET", Summary = "Gets an audio stream")]
- [Route("/Audio/{Id}/stream.{Container}", "HEAD", Summary = "Gets an audio stream")]
- [Route("/Audio/{Id}/stream", "HEAD", Summary = "Gets an audio stream")]
- public class GetAudioStream : StreamRequest
- {
- }
-
- /// <summary>
- /// Class AudioService
- /// </summary>
- // TODO: In order to autheneticate this in the future, Dlna playback will require updating
- //[Authenticated]
- public class AudioService : BaseProgressiveStreamingService
- {
- public AudioService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IJsonSerializer jsonSerializer, IAuthorizationContext authorizationContext, IImageProcessor imageProcessor, IEnvironmentInfo environmentInfo) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient, jsonSerializer, authorizationContext, imageProcessor, environmentInfo)
- {
- }
-
- /// <summary>
- /// Gets the specified request.
- /// </summary>
- /// <param name="request">The request.</param>
- /// <returns>System.Object.</returns>
- public Task<object> Get(GetAudioStream request)
- {
- return ProcessRequest(request, false);
- }
-
- /// <summary>
- /// Gets the specified request.
- /// </summary>
- /// <param name="request">The request.</param>
- /// <returns>System.Object.</returns>
- public Task<object> Head(GetAudioStream request)
- {
- return ProcessRequest(request, true);
- }
-
- protected override string GetCommandLineArguments(string outputPath, EncodingOptions encodingOptions, StreamState state, bool isEncoding)
- {
- return EncodingHelper.GetProgressiveAudioFullCommandLine(state, encodingOptions, outputPath);
- }
- }
-}
diff --git a/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs b/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs
deleted file mode 100644
index db5c78a2f..000000000
--- a/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs
+++ /dev/null
@@ -1,429 +0,0 @@
-using MediaBrowser.Common.Net;
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Devices;
-using MediaBrowser.Controller.Dlna;
-using MediaBrowser.Controller.Drawing;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.MediaEncoding;
-using MediaBrowser.Controller.Net;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Model.MediaInfo;
-using MediaBrowser.Model.Serialization;
-using System;
-using System.Collections.Generic;
-using System.Globalization;
-using System.IO;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Model.Services;
-using MediaBrowser.Model.System;
-
-namespace MediaBrowser.Api.Playback.Progressive
-{
- /// <summary>
- /// Class BaseProgressiveStreamingService
- /// </summary>
- public abstract class BaseProgressiveStreamingService : BaseStreamingService
- {
- protected readonly IImageProcessor ImageProcessor;
- protected readonly IEnvironmentInfo EnvironmentInfo;
-
- public BaseProgressiveStreamingService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IJsonSerializer jsonSerializer, IAuthorizationContext authorizationContext, IImageProcessor imageProcessor, IEnvironmentInfo environmentInfo) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient, jsonSerializer, authorizationContext)
- {
- ImageProcessor = imageProcessor;
- EnvironmentInfo = environmentInfo;
- }
-
- /// <summary>
- /// Gets the output file extension.
- /// </summary>
- /// <param name="state">The state.</param>
- /// <returns>System.String.</returns>
- protected override string GetOutputFileExtension(StreamState state)
- {
- var ext = base.GetOutputFileExtension(state);
-
- if (!string.IsNullOrEmpty(ext))
- {
- return ext;
- }
-
- var isVideoRequest = state.VideoRequest != null;
-
- // Try to infer based on the desired video codec
- if (isVideoRequest)
- {
- var videoCodec = state.VideoRequest.VideoCodec;
-
- if (string.Equals(videoCodec, "h264", StringComparison.OrdinalIgnoreCase))
- {
- return ".ts";
- }
- if (string.Equals(videoCodec, "theora", StringComparison.OrdinalIgnoreCase))
- {
- return ".ogv";
- }
- if (string.Equals(videoCodec, "vpx", StringComparison.OrdinalIgnoreCase))
- {
- return ".webm";
- }
- if (string.Equals(videoCodec, "wmv", StringComparison.OrdinalIgnoreCase))
- {
- return ".asf";
- }
- }
-
- // Try to infer based on the desired audio codec
- if (!isVideoRequest)
- {
- var audioCodec = state.Request.AudioCodec;
-
- if (string.Equals("aac", audioCodec, StringComparison.OrdinalIgnoreCase))
- {
- return ".aac";
- }
- if (string.Equals("mp3", audioCodec, StringComparison.OrdinalIgnoreCase))
- {
- return ".mp3";
- }
- if (string.Equals("vorbis", audioCodec, StringComparison.OrdinalIgnoreCase))
- {
- return ".ogg";
- }
- if (string.Equals("wma", audioCodec, StringComparison.OrdinalIgnoreCase))
- {
- return ".wma";
- }
- }
-
- return null;
- }
-
- /// <summary>
- /// Gets the type of the transcoding job.
- /// </summary>
- /// <value>The type of the transcoding job.</value>
- protected override TranscodingJobType TranscodingJobType
- {
- get { return TranscodingJobType.Progressive; }
- }
-
- /// <summary>
- /// Processes the request.
- /// </summary>
- /// <param name="request">The request.</param>
- /// <param name="isHeadRequest">if set to <c>true</c> [is head request].</param>
- /// <returns>Task.</returns>
- protected async Task<object> ProcessRequest(StreamRequest request, bool isHeadRequest)
- {
- var cancellationTokenSource = new CancellationTokenSource();
-
- var state = await GetState(request, cancellationTokenSource.Token).ConfigureAwait(false);
-
- var responseHeaders = new Dictionary<string, string>();
-
- if (request.Static && state.DirectStreamProvider != null)
- {
- AddDlnaHeaders(state, responseHeaders, true);
-
- using (state)
- {
- var outputHeaders = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
-
- // TODO: Don't hardcode this
- outputHeaders["Content-Type"] = MediaBrowser.Model.Net.MimeTypes.GetMimeType("file.ts");
-
- return new ProgressiveFileCopier(state.DirectStreamProvider, outputHeaders, null, Logger, EnvironmentInfo, CancellationToken.None)
- {
- AllowEndOfFile = false
- };
- }
- }
-
- // Static remote stream
- if (request.Static && state.InputProtocol == MediaProtocol.Http)
- {
- AddDlnaHeaders(state, responseHeaders, true);
-
- using (state)
- {
- return await GetStaticRemoteStreamResult(state, responseHeaders, isHeadRequest, cancellationTokenSource).ConfigureAwait(false);
- }
- }
-
- if (request.Static && state.InputProtocol != MediaProtocol.File)
- {
- throw new ArgumentException(string.Format("Input protocol {0} cannot be streamed statically.", state.InputProtocol));
- }
-
- var outputPath = state.OutputFilePath;
- var outputPathExists = FileSystem.FileExists(outputPath);
-
- var transcodingJob = ApiEntryPoint.Instance.GetTranscodingJob(outputPath, TranscodingJobType.Progressive);
- var isTranscodeCached = outputPathExists && transcodingJob != null;
-
- AddDlnaHeaders(state, responseHeaders, request.Static || isTranscodeCached);
-
- // Static stream
- if (request.Static)
- {
- var contentType = state.GetMimeType(state.MediaPath);
-
- using (state)
- {
- if (state.MediaSource.IsInfiniteStream)
- {
- var outputHeaders = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
-
- outputHeaders["Content-Type"] = contentType;
-
- return new ProgressiveFileCopier(FileSystem, state.MediaPath, outputHeaders, null, Logger, EnvironmentInfo, CancellationToken.None)
- {
- AllowEndOfFile = false
- };
- }
-
- TimeSpan? cacheDuration = null;
-
- if (!string.IsNullOrEmpty(request.Tag))
- {
- cacheDuration = TimeSpan.FromDays(365);
- }
-
- return await ResultFactory.GetStaticFileResult(Request, new StaticFileResultOptions
- {
- ResponseHeaders = responseHeaders,
- ContentType = contentType,
- IsHeadRequest = isHeadRequest,
- Path = state.MediaPath,
- CacheDuration = cacheDuration
-
- }).ConfigureAwait(false);
- }
- }
-
- //// Not static but transcode cache file exists
- //if (isTranscodeCached && state.VideoRequest == null)
- //{
- // var contentType = state.GetMimeType(outputPath);
-
- // try
- // {
- // if (transcodingJob != null)
- // {
- // ApiEntryPoint.Instance.OnTranscodeBeginRequest(transcodingJob);
- // }
-
- // return await ResultFactory.GetStaticFileResult(Request, new StaticFileResultOptions
- // {
- // ResponseHeaders = responseHeaders,
- // ContentType = contentType,
- // IsHeadRequest = isHeadRequest,
- // Path = outputPath,
- // FileShare = FileShareMode.ReadWrite,
- // OnComplete = () =>
- // {
- // if (transcodingJob != null)
- // {
- // ApiEntryPoint.Instance.OnTranscodeEndRequest(transcodingJob);
- // }
- // }
-
- // }).ConfigureAwait(false);
- // }
- // finally
- // {
- // state.Dispose();
- // }
- //}
-
- // Need to start ffmpeg
- try
- {
- return await GetStreamResult(state, responseHeaders, isHeadRequest, cancellationTokenSource).ConfigureAwait(false);
- }
- catch
- {
- state.Dispose();
-
- throw;
- }
- }
-
- /// <summary>
- /// Gets the static remote stream result.
- /// </summary>
- /// <param name="state">The state.</param>
- /// <param name="responseHeaders">The response headers.</param>
- /// <param name="isHeadRequest">if set to <c>true</c> [is head request].</param>
- /// <param name="cancellationTokenSource">The cancellation token source.</param>
- /// <returns>Task{System.Object}.</returns>
- private async Task<object> GetStaticRemoteStreamResult(StreamState state, Dictionary<string, string> responseHeaders, bool isHeadRequest, CancellationTokenSource cancellationTokenSource)
- {
- string useragent = null;
- state.RemoteHttpHeaders.TryGetValue("User-Agent", out useragent);
-
- var trySupportSeek = false;
-
- var options = new HttpRequestOptions
- {
- Url = state.MediaPath,
- UserAgent = useragent,
- BufferContent = false,
- CancellationToken = cancellationTokenSource.Token
- };
-
- if (trySupportSeek)
- {
- if (!string.IsNullOrWhiteSpace(Request.QueryString["Range"]))
- {
- options.RequestHeaders["Range"] = Request.QueryString["Range"];
- }
- }
- var response = await HttpClient.GetResponse(options).ConfigureAwait(false);
-
- if (trySupportSeek)
- {
- foreach (var name in new[] { "Content-Range", "Accept-Ranges" })
- {
- var val = response.Headers[name];
- if (!string.IsNullOrWhiteSpace(val))
- {
- responseHeaders[name] = val;
- }
- }
- }
- else
- {
- responseHeaders["Accept-Ranges"] = "none";
- }
-
- // Seeing cases of -1 here
- if (response.ContentLength.HasValue && response.ContentLength.Value >= 0)
- {
- responseHeaders["Content-Length"] = response.ContentLength.Value.ToString(UsCulture);
- }
-
- if (isHeadRequest)
- {
- using (response)
- {
- return ResultFactory.GetResult(new byte[] { }, response.ContentType, responseHeaders);
- }
- }
-
- var result = new StaticRemoteStreamWriter(response);
-
- result.Headers["Content-Type"] = response.ContentType;
-
- // Add the response headers to the result object
- foreach (var header in responseHeaders)
- {
- result.Headers[header.Key] = header.Value;
- }
-
- return result;
- }
-
- /// <summary>
- /// Gets the stream result.
- /// </summary>
- /// <param name="state">The state.</param>
- /// <param name="responseHeaders">The response headers.</param>
- /// <param name="isHeadRequest">if set to <c>true</c> [is head request].</param>
- /// <param name="cancellationTokenSource">The cancellation token source.</param>
- /// <returns>Task{System.Object}.</returns>
- private async Task<object> GetStreamResult(StreamState state, IDictionary<string, string> responseHeaders, bool isHeadRequest, CancellationTokenSource cancellationTokenSource)
- {
- // Use the command line args with a dummy playlist path
- var outputPath = state.OutputFilePath;
-
- responseHeaders["Accept-Ranges"] = "none";
-
- var contentType = state.GetMimeType(outputPath);
-
- // TODO: The isHeadRequest is only here because ServiceStack will add Content-Length=0 to the response
- // What we really want to do is hunt that down and remove that
- var contentLength = state.EstimateContentLength || isHeadRequest ? GetEstimatedContentLength(state) : null;
-
- if (contentLength.HasValue)
- {
- responseHeaders["Content-Length"] = contentLength.Value.ToString(UsCulture);
- }
-
- // Headers only
- if (isHeadRequest)
- {
- var streamResult = ResultFactory.GetResult(new byte[] { }, contentType, responseHeaders);
-
- var hasHeaders = streamResult as IHasHeaders;
- if (hasHeaders != null)
- {
- if (contentLength.HasValue)
- {
- hasHeaders.Headers["Content-Length"] = contentLength.Value.ToString(CultureInfo.InvariantCulture);
- }
- else
- {
- if (hasHeaders.Headers.ContainsKey("Content-Length"))
- {
- hasHeaders.Headers.Remove("Content-Length");
- }
- }
- }
-
- return streamResult;
- }
-
- var transcodingLock = ApiEntryPoint.Instance.GetTranscodingLock(outputPath);
- await transcodingLock.WaitAsync(cancellationTokenSource.Token).ConfigureAwait(false);
- try
- {
- TranscodingJob job;
-
- if (!FileSystem.FileExists(outputPath))
- {
- job = await StartFfMpeg(state, outputPath, cancellationTokenSource).ConfigureAwait(false);
- }
- else
- {
- job = ApiEntryPoint.Instance.OnTranscodeBeginRequest(outputPath, TranscodingJobType.Progressive);
- state.Dispose();
- }
-
- var outputHeaders = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
-
- outputHeaders["Content-Type"] = contentType;
-
- // Add the response headers to the result object
- foreach (var item in responseHeaders)
- {
- outputHeaders[item.Key] = item.Value;
- }
-
- return new ProgressiveFileCopier(FileSystem, outputPath, outputHeaders, job, Logger, EnvironmentInfo, CancellationToken.None);
- }
- finally
- {
- transcodingLock.Release();
- }
- }
-
- /// <summary>
- /// Gets the length of the estimated content.
- /// </summary>
- /// <param name="state">The state.</param>
- /// <returns>System.Nullable{System.Int64}.</returns>
- private long? GetEstimatedContentLength(StreamState state)
- {
- var totalBitrate = state.TotalOutputBitrate ?? 0;
-
- if (totalBitrate > 0 && state.RunTimeTicks.HasValue)
- {
- return Convert.ToInt64(totalBitrate * TimeSpan.FromTicks(state.RunTimeTicks.Value).TotalSeconds / 8);
- }
-
- return null;
- }
- }
-}
diff --git a/MediaBrowser.Api/Playback/Progressive/VideoService.cs b/MediaBrowser.Api/Playback/Progressive/VideoService.cs
deleted file mode 100644
index a41b4cbf5..000000000
--- a/MediaBrowser.Api/Playback/Progressive/VideoService.cs
+++ /dev/null
@@ -1,100 +0,0 @@
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Devices;
-using MediaBrowser.Controller.Dlna;
-using MediaBrowser.Controller.Drawing;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.MediaEncoding;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Model.Serialization;
-using System.Threading.Tasks;
-using MediaBrowser.Controller.Net;
-using MediaBrowser.Model.Configuration;
-using MediaBrowser.Model.Services;
-using MediaBrowser.Model.System;
-
-namespace MediaBrowser.Api.Playback.Progressive
-{
- /// <summary>
- /// Class GetVideoStream
- /// </summary>
- [Route("/Videos/{Id}/stream.mpegts", "GET")]
- [Route("/Videos/{Id}/stream.ts", "GET")]
- [Route("/Videos/{Id}/stream.webm", "GET")]
- [Route("/Videos/{Id}/stream.asf", "GET")]
- [Route("/Videos/{Id}/stream.wmv", "GET")]
- [Route("/Videos/{Id}/stream.ogv", "GET")]
- [Route("/Videos/{Id}/stream.mp4", "GET")]
- [Route("/Videos/{Id}/stream.m4v", "GET")]
- [Route("/Videos/{Id}/stream.mkv", "GET")]
- [Route("/Videos/{Id}/stream.mpeg", "GET")]
- [Route("/Videos/{Id}/stream.mpg", "GET")]
- [Route("/Videos/{Id}/stream.avi", "GET")]
- [Route("/Videos/{Id}/stream.m2ts", "GET")]
- [Route("/Videos/{Id}/stream.3gp", "GET")]
- [Route("/Videos/{Id}/stream.wmv", "GET")]
- [Route("/Videos/{Id}/stream.wtv", "GET")]
- [Route("/Videos/{Id}/stream.mov", "GET")]
- [Route("/Videos/{Id}/stream.iso", "GET")]
- [Route("/Videos/{Id}/stream.flv", "GET")]
- [Route("/Videos/{Id}/stream", "GET")]
- [Route("/Videos/{Id}/stream.ts", "HEAD")]
- [Route("/Videos/{Id}/stream.webm", "HEAD")]
- [Route("/Videos/{Id}/stream.asf", "HEAD")]
- [Route("/Videos/{Id}/stream.wmv", "HEAD")]
- [Route("/Videos/{Id}/stream.ogv", "HEAD")]
- [Route("/Videos/{Id}/stream.mp4", "HEAD")]
- [Route("/Videos/{Id}/stream.m4v", "HEAD")]
- [Route("/Videos/{Id}/stream.mkv", "HEAD")]
- [Route("/Videos/{Id}/stream.mpeg", "HEAD")]
- [Route("/Videos/{Id}/stream.mpg", "HEAD")]
- [Route("/Videos/{Id}/stream.avi", "HEAD")]
- [Route("/Videos/{Id}/stream.3gp", "HEAD")]
- [Route("/Videos/{Id}/stream.wmv", "HEAD")]
- [Route("/Videos/{Id}/stream.wtv", "HEAD")]
- [Route("/Videos/{Id}/stream.m2ts", "HEAD")]
- [Route("/Videos/{Id}/stream.mov", "HEAD")]
- [Route("/Videos/{Id}/stream.iso", "HEAD")]
- [Route("/Videos/{Id}/stream.flv", "HEAD")]
- [Route("/Videos/{Id}/stream", "HEAD")]
- public class GetVideoStream : VideoStreamRequest
- {
-
- }
-
- /// <summary>
- /// Class VideoService
- /// </summary>
- // TODO: In order to autheneticate this in the future, Dlna playback will require updating
- //[Authenticated]
- public class VideoService : BaseProgressiveStreamingService
- {
- public VideoService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IJsonSerializer jsonSerializer, IAuthorizationContext authorizationContext, IImageProcessor imageProcessor, IEnvironmentInfo environmentInfo) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient, jsonSerializer, authorizationContext, imageProcessor, environmentInfo)
- {
- }
-
- /// <summary>
- /// Gets the specified request.
- /// </summary>
- /// <param name="request">The request.</param>
- /// <returns>System.Object.</returns>
- public Task<object> Get(GetVideoStream request)
- {
- return ProcessRequest(request, false);
- }
-
- /// <summary>
- /// Heads the specified request.
- /// </summary>
- /// <param name="request">The request.</param>
- /// <returns>System.Object.</returns>
- public Task<object> Head(GetVideoStream request)
- {
- return ProcessRequest(request, true);
- }
-
- protected override string GetCommandLineArguments(string outputPath, EncodingOptions encodingOptions, StreamState state, bool isEncoding)
- {
- return EncodingHelper.GetProgressiveVideoFullCommandLine(state, encodingOptions, outputPath, GetDefaultH264Preset());
- }
- }
-} \ No newline at end of file
diff --git a/MediaBrowser.Api/Playback/StaticRemoteStreamWriter.cs b/MediaBrowser.Api/Playback/StaticRemoteStreamWriter.cs
deleted file mode 100644
index 6bb3b6b80..000000000
--- a/MediaBrowser.Api/Playback/StaticRemoteStreamWriter.cs
+++ /dev/null
@@ -1,47 +0,0 @@
-using MediaBrowser.Common.Net;
-using System.Collections.Generic;
-using System.IO;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Model.Services;
-
-namespace MediaBrowser.Api.Playback
-{
- /// <summary>
- /// Class StaticRemoteStreamWriter
- /// </summary>
- public class StaticRemoteStreamWriter : IAsyncStreamWriter, IHasHeaders
- {
- /// <summary>
- /// The _input stream
- /// </summary>
- private readonly HttpResponseInfo _response;
-
- /// <summary>
- /// The _options
- /// </summary>
- private readonly IDictionary<string, string> _options = new Dictionary<string, string>();
-
- public StaticRemoteStreamWriter(HttpResponseInfo response)
- {
- _response = response;
- }
-
- /// <summary>
- /// Gets the options.
- /// </summary>
- /// <value>The options.</value>
- public IDictionary<string, string> Headers
- {
- get { return _options; }
- }
-
- public async Task WriteToAsync(Stream responseStream, CancellationToken cancellationToken)
- {
- using (_response)
- {
- await _response.Content.CopyToAsync(responseStream, 81920, cancellationToken).ConfigureAwait(false);
- }
- }
- }
-}
diff --git a/MediaBrowser.Api/Playback/StreamRequest.cs b/MediaBrowser.Api/Playback/StreamRequest.cs
deleted file mode 100644
index 176b68f37..000000000
--- a/MediaBrowser.Api/Playback/StreamRequest.cs
+++ /dev/null
@@ -1,63 +0,0 @@
-using MediaBrowser.Controller.MediaEncoding;
-using MediaBrowser.Model.Dlna;
-using MediaBrowser.Model.Services;
-
-namespace MediaBrowser.Api.Playback
-{
- /// <summary>
- /// Class StreamRequest
- /// </summary>
- public class StreamRequest : BaseEncodingJobOptions
- {
- /// <summary>
- /// Gets or sets the id.
- /// </summary>
- /// <value>The id.</value>
- [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
- public string Id { get; set; }
-
- [ApiMember(Name = "MediaSourceId", Description = "The media version id, if playing an alternate version", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
- public string MediaSourceId { get; set; }
-
- [ApiMember(Name = "DeviceId", Description = "The device id of the client requesting. Used to stop encoding processes when needed.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
- public string DeviceId { get; set; }
-
- [ApiMember(Name = "Container", Description = "Container", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
- public string Container { get; set; }
-
- /// <summary>
- /// Gets or sets the audio codec.
- /// </summary>
- /// <value>The audio codec.</value>
- [ApiMember(Name = "AudioCodec", Description = "Optional. Specify a audio codec to encode to, e.g. mp3. If omitted the server will auto-select using the url's extension. Options: aac, mp3, vorbis, wma.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
- public string AudioCodec { get; set; }
-
- [ApiMember(Name = "DeviceProfileId", Description = "Optional. The dlna device profile id to utilize.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
- public string DeviceProfileId { get; set; }
-
- public string Params { get; set; }
- public string PlaySessionId { get; set; }
- public string Tag { get; set; }
- public string SegmentContainer { get; set; }
-
- public int? SegmentLength { get; set; }
- public int? MinSegments { get; set; }
- }
-
- public class VideoStreamRequest : StreamRequest
- {
- /// <summary>
- /// Gets a value indicating whether this instance has fixed resolution.
- /// </summary>
- /// <value><c>true</c> if this instance has fixed resolution; otherwise, <c>false</c>.</value>
- public bool HasFixedResolution
- {
- get
- {
- return Width.HasValue || Height.HasValue;
- }
- }
-
- public bool EnableSubtitlesInManifest { get; set; }
- }
-}
diff --git a/MediaBrowser.Api/Playback/StreamState.cs b/MediaBrowser.Api/Playback/StreamState.cs
deleted file mode 100644
index eecc12432..000000000
--- a/MediaBrowser.Api/Playback/StreamState.cs
+++ /dev/null
@@ -1,259 +0,0 @@
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Model.Dlna;
-using MediaBrowser.Model.Drawing;
-using MediaBrowser.Model.Dto;
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Model.Logging;
-using MediaBrowser.Model.MediaInfo;
-using MediaBrowser.Model.Net;
-using System;
-using System.Collections.Generic;
-using System.Globalization;
-using System.IO;
-using System.Linq;
-using System.Threading;
-using MediaBrowser.Controller.MediaEncoding;
-
-namespace MediaBrowser.Api.Playback
-{
- public class StreamState : EncodingJobInfo, IDisposable
- {
- private readonly ILogger _logger;
- private readonly IMediaSourceManager _mediaSourceManager;
-
- public string RequestedUrl { get; set; }
-
- public StreamRequest Request
- {
- get { return (StreamRequest)BaseRequest; }
- set
- {
- BaseRequest = value;
-
- IsVideoRequest = VideoRequest != null;
- }
- }
-
- public TranscodingThrottler TranscodingThrottler { get; set; }
-
- public VideoStreamRequest VideoRequest
- {
- get { return Request as VideoStreamRequest; }
- }
-
- /// <summary>
- /// Gets or sets the log file stream.
- /// </summary>
- /// <value>The log file stream.</value>
- public Stream LogFileStream { get; set; }
- public IDirectStreamProvider DirectStreamProvider { get; set; }
-
- public string WaitForPath { get; set; }
-
- public bool IsOutputVideo
- {
- get { return Request is VideoStreamRequest; }
- }
-
- public int SegmentLength
- {
- get
- {
- if (Request.SegmentLength.HasValue)
- {
- return Request.SegmentLength.Value;
- }
-
- if (string.Equals(OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase))
- {
- var userAgent = UserAgent ?? string.Empty;
-
- if (userAgent.IndexOf("AppleTV", StringComparison.OrdinalIgnoreCase) != -1 ||
- userAgent.IndexOf("cfnetwork", StringComparison.OrdinalIgnoreCase) != -1 ||
- userAgent.IndexOf("ipad", StringComparison.OrdinalIgnoreCase) != -1 ||
- userAgent.IndexOf("iphone", StringComparison.OrdinalIgnoreCase) != -1 ||
- userAgent.IndexOf("ipod", StringComparison.OrdinalIgnoreCase) != -1)
- {
- if (IsSegmentedLiveStream)
- {
- return 6;
- }
-
- return 6;
- }
-
- if (IsSegmentedLiveStream)
- {
- return 3;
- }
- return 6;
- }
-
- return 3;
- }
- }
-
- public int MinSegments
- {
- get
- {
- if (Request.MinSegments.HasValue)
- {
- return Request.MinSegments.Value;
- }
-
- return SegmentLength >= 10 ? 2 : 3;
- }
- }
-
- public int HlsListSize
- {
- get
- {
- return 0;
- }
- }
-
- public string UserAgent { get; set; }
-
- public StreamState(IMediaSourceManager mediaSourceManager, ILogger logger, TranscodingJobType transcodingType)
- : base(logger, transcodingType)
- {
- _mediaSourceManager = mediaSourceManager;
- _logger = logger;
- }
-
- public string MimeType { get; set; }
-
- public bool EstimateContentLength { get; set; }
- public TranscodeSeekInfo TranscodeSeekInfo { get; set; }
-
- public long? EncodingDurationTicks { get; set; }
-
- public string GetMimeType(string outputPath)
- {
- if (!string.IsNullOrEmpty(MimeType))
- {
- return MimeType;
- }
-
- return MimeTypes.GetMimeType(outputPath);
- }
-
- public bool EnableDlnaHeaders { get; set; }
-
- public void Dispose()
- {
- DisposeTranscodingThrottler();
- DisposeLiveStream();
- DisposeLogStream();
- DisposeIsoMount();
-
- TranscodingJob = null;
- }
-
- private void DisposeLogStream()
- {
- if (LogFileStream != null)
- {
- try
- {
- LogFileStream.Dispose();
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error disposing log stream", ex);
- }
-
- LogFileStream = null;
- }
- }
-
- private void DisposeTranscodingThrottler()
- {
- if (TranscodingThrottler != null)
- {
- try
- {
- TranscodingThrottler.Dispose();
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error disposing TranscodingThrottler", ex);
- }
-
- TranscodingThrottler = null;
- }
- }
-
- private async void DisposeLiveStream()
- {
- if (MediaSource.RequiresClosing && string.IsNullOrWhiteSpace(Request.LiveStreamId) && !string.IsNullOrWhiteSpace(MediaSource.LiveStreamId))
- {
- try
- {
- await _mediaSourceManager.CloseLiveStream(MediaSource.LiveStreamId).ConfigureAwait(false);
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error closing media source", ex);
- }
- }
- }
-
- public string OutputFilePath { get; set; }
-
- public string ActualOutputVideoCodec
- {
- get
- {
- var codec = OutputVideoCodec;
-
- if (string.Equals(codec, "copy", StringComparison.OrdinalIgnoreCase))
- {
- var stream = VideoStream;
-
- if (stream != null)
- {
- return stream.Codec;
- }
-
- return null;
- }
-
- return codec;
- }
- }
-
- public string ActualOutputAudioCodec
- {
- get
- {
- var codec = OutputAudioCodec;
-
- if (string.Equals(codec, "copy", StringComparison.OrdinalIgnoreCase))
- {
- var stream = AudioStream;
-
- if (stream != null)
- {
- return stream.Codec;
- }
-
- return null;
- }
-
- return codec;
- }
- }
-
- public DeviceProfile DeviceProfile { get; set; }
-
- public TranscodingJob TranscodingJob;
- public override void ReportTranscodingProgress(TimeSpan? transcodingPosition, float? framerate, double? percentComplete, long? bytesTranscoded, int? bitRate)
- {
- ApiEntryPoint.Instance.ReportTranscodingProgress(TranscodingJob, this, transcodingPosition, framerate, percentComplete, bytesTranscoded, bitRate);
- }
- }
-}
diff --git a/MediaBrowser.Api/Playback/TranscodingThrottler.cs b/MediaBrowser.Api/Playback/TranscodingThrottler.cs
deleted file mode 100644
index c42d0c3e4..000000000
--- a/MediaBrowser.Api/Playback/TranscodingThrottler.cs
+++ /dev/null
@@ -1,176 +0,0 @@
-using MediaBrowser.Common.Configuration;
-using MediaBrowser.Model.Configuration;
-using MediaBrowser.Model.Logging;
-using System;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Model.Threading;
-
-namespace MediaBrowser.Api.Playback
-{
- public class TranscodingThrottler : IDisposable
- {
- private readonly TranscodingJob _job;
- private readonly ILogger _logger;
- private ITimer _timer;
- private bool _isPaused;
- private readonly IConfigurationManager _config;
- private readonly ITimerFactory _timerFactory;
- private readonly IFileSystem _fileSystem;
-
- public TranscodingThrottler(TranscodingJob job, ILogger logger, IConfigurationManager config, ITimerFactory timerFactory, IFileSystem fileSystem)
- {
- _job = job;
- _logger = logger;
- _config = config;
- _timerFactory = timerFactory;
- _fileSystem = fileSystem;
- }
-
- private EncodingOptions GetOptions()
- {
- return _config.GetConfiguration<EncodingOptions>("encoding");
- }
-
- public void Start()
- {
- _timer = _timerFactory.Create(TimerCallback, null, 5000, 5000);
- }
-
- private void TimerCallback(object state)
- {
- if (_job.HasExited)
- {
- DisposeTimer();
- return;
- }
-
- var options = GetOptions();
-
- if (options.EnableThrottling && IsThrottleAllowed(_job, options.ThrottleDelaySeconds))
- {
- PauseTranscoding();
- }
- else
- {
- UnpauseTranscoding();
- }
- }
-
- private void PauseTranscoding()
- {
- if (!_isPaused)
- {
- _logger.Debug("Sending pause command to ffmpeg");
-
- try
- {
- _job.Process.StandardInput.Write("c");
- _isPaused = true;
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error pausing transcoding", ex);
- }
- }
- }
-
- public void UnpauseTranscoding()
- {
- if (_isPaused)
- {
- _logger.Debug("Sending unpause command to ffmpeg");
-
- try
- {
- _job.Process.StandardInput.WriteLine();
- _isPaused = false;
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error unpausing transcoding", ex);
- }
- }
- }
-
- private bool IsThrottleAllowed(TranscodingJob job, int thresholdSeconds)
- {
- var bytesDownloaded = job.BytesDownloaded ?? 0;
- var transcodingPositionTicks = job.TranscodingPositionTicks ?? 0;
- var downloadPositionTicks = job.DownloadPositionTicks ?? 0;
-
- var path = job.Path;
- var gapLengthInTicks = TimeSpan.FromSeconds(thresholdSeconds).Ticks;
-
- if (downloadPositionTicks > 0 && transcodingPositionTicks > 0)
- {
- // HLS - time-based consideration
-
- var targetGap = gapLengthInTicks;
- var gap = transcodingPositionTicks - downloadPositionTicks;
-
- if (gap < targetGap)
- {
- //_logger.Debug("Not throttling transcoder gap {0} target gap {1}", gap, targetGap);
- return false;
- }
-
- //_logger.Debug("Throttling transcoder gap {0} target gap {1}", gap, targetGap);
- return true;
- }
-
- if (bytesDownloaded > 0 && transcodingPositionTicks > 0)
- {
- // Progressive Streaming - byte-based consideration
-
- try
- {
- var bytesTranscoded = job.BytesTranscoded ?? _fileSystem.GetFileInfo(path).Length;
-
- // Estimate the bytes the transcoder should be ahead
- double gapFactor = gapLengthInTicks;
- gapFactor /= transcodingPositionTicks;
- var targetGap = bytesTranscoded * gapFactor;
-
- var gap = bytesTranscoded - bytesDownloaded;
-
- if (gap < targetGap)
- {
- //_logger.Debug("Not throttling transcoder gap {0} target gap {1} bytes downloaded {2}", gap, targetGap, bytesDownloaded);
- return false;
- }
-
- //_logger.Debug("Throttling transcoder gap {0} target gap {1} bytes downloaded {2}", gap, targetGap, bytesDownloaded);
- return true;
- }
- catch
- {
- //_logger.Error("Error getting output size");
- return false;
- }
- }
-
- //_logger.Debug("No throttle data for " + path);
- return false;
- }
-
- public void Stop()
- {
- DisposeTimer();
- UnpauseTranscoding();
- }
-
- public void Dispose()
- {
- DisposeTimer();
- }
-
- private void DisposeTimer()
- {
- if (_timer != null)
- {
- _timer.Dispose();
- _timer = null;
- }
- }
- }
-}
diff --git a/MediaBrowser.Api/Playback/UniversalAudioService.cs b/MediaBrowser.Api/Playback/UniversalAudioService.cs
deleted file mode 100644
index 118bf5246..000000000
--- a/MediaBrowser.Api/Playback/UniversalAudioService.cs
+++ /dev/null
@@ -1,339 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Globalization;
-using System.Linq;
-using System.Threading.Tasks;
-using MediaBrowser.Api.Playback.Hls;
-using MediaBrowser.Api.Playback.Progressive;
-using MediaBrowser.Common.Net;
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Devices;
-using MediaBrowser.Controller.Dlna;
-using MediaBrowser.Controller.Drawing;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.MediaEncoding;
-using MediaBrowser.Controller.Net;
-using MediaBrowser.Model.Dlna;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Model.MediaInfo;
-using MediaBrowser.Model.Serialization;
-using MediaBrowser.Model.Services;
-using MediaBrowser.Model.System;
-
-namespace MediaBrowser.Api.Playback
-{
- public class BaseUniversalRequest
- {
- /// <summary>
- /// Gets or sets the id.
- /// </summary>
- /// <value>The id.</value>
- [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
- public string Id { get; set; }
-
- [ApiMember(Name = "MediaSourceId", Description = "The media version id, if playing an alternate version", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
- public string MediaSourceId { get; set; }
-
- [ApiMember(Name = "DeviceId", Description = "The device id of the client requesting. Used to stop encoding processes when needed.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
- public string DeviceId { get; set; }
-
- public string UserId { get; set; }
- public string AudioCodec { get; set; }
- public string Container { get; set; }
-
- public int? MaxAudioChannels { get; set; }
- public int? TranscodingAudioChannels { get; set; }
-
- public long? MaxStreamingBitrate { get; set; }
-
- [ApiMember(Name = "StartTimeTicks", Description = "Optional. Specify a starting offset, in ticks. 1 tick = 10000 ms", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
- public long? StartTimeTicks { get; set; }
-
- public string TranscodingContainer { get; set; }
- public string TranscodingProtocol { get; set; }
- public int? MaxAudioSampleRate { get; set; }
- public int? MaxAudioBitDepth { get; set; }
-
- public bool EnableRedirection { get; set; }
- public bool EnableRemoteMedia { get; set; }
- public bool BreakOnNonKeyFrames { get; set; }
-
- public BaseUniversalRequest()
- {
- EnableRedirection = true;
- }
- }
-
- [Route("/Audio/{Id}/universal.{Container}", "GET", Summary = "Gets an audio stream")]
- [Route("/Audio/{Id}/universal", "GET", Summary = "Gets an audio stream")]
- [Route("/Audio/{Id}/universal.{Container}", "HEAD", Summary = "Gets an audio stream")]
- [Route("/Audio/{Id}/universal", "HEAD", Summary = "Gets an audio stream")]
- public class GetUniversalAudioStream : BaseUniversalRequest
- {
- }
-
- [Authenticated]
- public class UniversalAudioService : BaseApiService
- {
- public UniversalAudioService(IServerConfigurationManager serverConfigurationManager, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, IDeviceManager deviceManager, ISubtitleEncoder subtitleEncoder, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IJsonSerializer jsonSerializer, IAuthorizationContext authorizationContext, IImageProcessor imageProcessor, INetworkManager networkManager, IEnvironmentInfo environmentInfo)
- {
- ServerConfigurationManager = serverConfigurationManager;
- UserManager = userManager;
- LibraryManager = libraryManager;
- IsoManager = isoManager;
- MediaEncoder = mediaEncoder;
- FileSystem = fileSystem;
- DlnaManager = dlnaManager;
- DeviceManager = deviceManager;
- SubtitleEncoder = subtitleEncoder;
- MediaSourceManager = mediaSourceManager;
- ZipClient = zipClient;
- JsonSerializer = jsonSerializer;
- AuthorizationContext = authorizationContext;
- ImageProcessor = imageProcessor;
- NetworkManager = networkManager;
- EnvironmentInfo = environmentInfo;
- }
-
- protected IServerConfigurationManager ServerConfigurationManager { get; private set; }
- protected IUserManager UserManager { get; private set; }
- protected ILibraryManager LibraryManager { get; private set; }
- protected IIsoManager IsoManager { get; private set; }
- protected IMediaEncoder MediaEncoder { get; private set; }
- protected IFileSystem FileSystem { get; private set; }
- protected IDlnaManager DlnaManager { get; private set; }
- protected IDeviceManager DeviceManager { get; private set; }
- protected ISubtitleEncoder SubtitleEncoder { get; private set; }
- protected IMediaSourceManager MediaSourceManager { get; private set; }
- protected IZipClient ZipClient { get; private set; }
- protected IJsonSerializer JsonSerializer { get; private set; }
- protected IAuthorizationContext AuthorizationContext { get; private set; }
- protected IImageProcessor ImageProcessor { get; private set; }
- protected INetworkManager NetworkManager { get; private set; }
- protected IEnvironmentInfo EnvironmentInfo { get; private set; }
-
- public Task<object> Get(GetUniversalAudioStream request)
- {
- return GetUniversalStream(request, false);
- }
-
- public Task<object> Head(GetUniversalAudioStream request)
- {
- return GetUniversalStream(request, true);
- }
-
- private DeviceProfile GetDeviceProfile(GetUniversalAudioStream request)
- {
- var deviceProfile = new DeviceProfile();
-
- var directPlayProfiles = new List<DirectPlayProfile>();
-
- directPlayProfiles.Add(new DirectPlayProfile
- {
- Type = DlnaProfileType.Audio,
- Container = request.Container
- });
-
- deviceProfile.DirectPlayProfiles = directPlayProfiles.ToArray();
-
- deviceProfile.TranscodingProfiles = new[]
- {
- new TranscodingProfile
- {
- Type = DlnaProfileType.Audio,
- Context = EncodingContext.Streaming,
- Container = request.TranscodingContainer,
- AudioCodec = request.AudioCodec,
- Protocol = request.TranscodingProtocol,
- BreakOnNonKeyFrames = request.BreakOnNonKeyFrames,
- MaxAudioChannels = request.TranscodingAudioChannels.HasValue ? request.TranscodingAudioChannels.Value.ToString(CultureInfo.InvariantCulture) : null
- }
- };
-
- var codecProfiles = new List<CodecProfile>();
- var conditions = new List<ProfileCondition>();
-
- if (request.MaxAudioSampleRate.HasValue)
- {
- // codec profile
- conditions.Add(new ProfileCondition
- {
- Condition = ProfileConditionType.LessThanEqual,
- IsRequired = false,
- Property = ProfileConditionValue.AudioSampleRate,
- Value = request.MaxAudioSampleRate.Value.ToString(CultureInfo.InvariantCulture)
- });
- }
-
- if (request.MaxAudioBitDepth.HasValue)
- {
- // codec profile
- conditions.Add(new ProfileCondition
- {
- Condition = ProfileConditionType.LessThanEqual,
- IsRequired = false,
- Property = ProfileConditionValue.AudioBitDepth,
- Value = request.MaxAudioBitDepth.Value.ToString(CultureInfo.InvariantCulture)
- });
- }
-
- if (request.MaxAudioChannels.HasValue)
- {
- // codec profile
- conditions.Add(new ProfileCondition
- {
- Condition = ProfileConditionType.LessThanEqual,
- IsRequired = false,
- Property = ProfileConditionValue.AudioChannels,
- Value = request.MaxAudioChannels.Value.ToString(CultureInfo.InvariantCulture)
- });
- }
-
- if (conditions.Count > 0)
- {
- // codec profile
- codecProfiles.Add(new CodecProfile
- {
- Type = CodecType.Audio,
- Container = request.Container,
- Conditions = conditions.ToArray()
- });
- }
-
- deviceProfile.CodecProfiles = codecProfiles.ToArray();
-
- return deviceProfile;
- }
-
- private async Task<object> GetUniversalStream(GetUniversalAudioStream request, bool isHeadRequest)
- {
- var deviceProfile = GetDeviceProfile(request);
-
- AuthorizationContext.GetAuthorizationInfo(Request).DeviceId = request.DeviceId;
-
- var mediaInfoService = new MediaInfoService(MediaSourceManager, DeviceManager, LibraryManager, ServerConfigurationManager, NetworkManager, MediaEncoder, UserManager, JsonSerializer, AuthorizationContext)
- {
- Request = Request
- };
-
- var playbackInfoResult = await mediaInfoService.GetPlaybackInfo(new GetPostedPlaybackInfo
- {
- Id = request.Id,
- MaxAudioChannels = request.MaxAudioChannels,
- MaxStreamingBitrate = request.MaxStreamingBitrate,
- StartTimeTicks = request.StartTimeTicks,
- UserId = request.UserId,
- DeviceProfile = deviceProfile,
- MediaSourceId = request.MediaSourceId
-
- }).ConfigureAwait(false);
-
- var mediaSource = playbackInfoResult.MediaSources[0];
-
- if (mediaSource.SupportsDirectPlay && mediaSource.Protocol == MediaProtocol.Http)
- {
- if (request.EnableRedirection)
- {
- if (mediaSource.IsRemote && request.EnableRemoteMedia)
- {
- return ResultFactory.GetRedirectResult(mediaSource.Path);
- }
- }
- }
-
- var isStatic = mediaSource.SupportsDirectStream;
-
- if (!isStatic && string.Equals(mediaSource.TranscodingSubProtocol, "hls", StringComparison.OrdinalIgnoreCase))
- {
- var service = new DynamicHlsService(ServerConfigurationManager,
- UserManager,
- LibraryManager,
- IsoManager,
- MediaEncoder,
- FileSystem,
- DlnaManager,
- SubtitleEncoder,
- DeviceManager,
- MediaSourceManager,
- ZipClient,
- JsonSerializer,
- AuthorizationContext,
- NetworkManager)
- {
- Request = Request
- };
-
- var transcodingProfile = deviceProfile.TranscodingProfiles[0];
-
- var newRequest = new GetMasterHlsAudioPlaylist
- {
- AudioBitRate = isStatic ? (int?)null : Convert.ToInt32(Math.Min(request.MaxStreamingBitrate ?? 192000, int.MaxValue)),
- AudioCodec = transcodingProfile.AudioCodec,
- Container = ".m3u8",
- DeviceId = request.DeviceId,
- Id = request.Id,
- MaxAudioChannels = request.MaxAudioChannels,
- MediaSourceId = mediaSource.Id,
- PlaySessionId = playbackInfoResult.PlaySessionId,
- StartTimeTicks = request.StartTimeTicks,
- Static = isStatic,
- SegmentContainer = request.TranscodingContainer,
- AudioSampleRate = request.MaxAudioSampleRate,
- MaxAudioBitDepth = request.MaxAudioBitDepth,
- BreakOnNonKeyFrames = transcodingProfile.BreakOnNonKeyFrames,
- TranscodeReasons = mediaSource.TranscodeReasons == null ? null : string.Join(",", mediaSource.TranscodeReasons.Select(i => i.ToString()).ToArray())
- };
-
- if (isHeadRequest)
- {
- return await service.Head(newRequest).ConfigureAwait(false);
- }
- return await service.Get(newRequest).ConfigureAwait(false);
- }
- else
- {
- var service = new AudioService(ServerConfigurationManager,
- UserManager,
- LibraryManager,
- IsoManager,
- MediaEncoder,
- FileSystem,
- DlnaManager,
- SubtitleEncoder,
- DeviceManager,
- MediaSourceManager,
- ZipClient,
- JsonSerializer,
- AuthorizationContext,
- ImageProcessor,
- EnvironmentInfo)
- {
- Request = Request
- };
-
- var newRequest = new GetAudioStream
- {
- AudioBitRate = isStatic ? (int?)null : Convert.ToInt32(Math.Min(request.MaxStreamingBitrate ?? 192000, int.MaxValue)),
- AudioCodec = request.AudioCodec,
- Container = isStatic ? null : ("." + mediaSource.TranscodingContainer),
- DeviceId = request.DeviceId,
- Id = request.Id,
- MaxAudioChannels = request.MaxAudioChannels,
- MediaSourceId = mediaSource.Id,
- PlaySessionId = playbackInfoResult.PlaySessionId,
- StartTimeTicks = request.StartTimeTicks,
- Static = isStatic,
- AudioSampleRate = request.MaxAudioSampleRate,
- MaxAudioBitDepth = request.MaxAudioBitDepth,
- TranscodeReasons = mediaSource.TranscodeReasons == null ? null : string.Join(",", mediaSource.TranscodeReasons.Select(i => i.ToString()).ToArray())
- };
-
- if (isHeadRequest)
- {
- return await service.Head(newRequest).ConfigureAwait(false);
- }
- return await service.Get(newRequest).ConfigureAwait(false);
- }
- }
- }
-}
diff --git a/MediaBrowser.Api/PlaylistService.cs b/MediaBrowser.Api/PlaylistService.cs
index 9f37bb70a..226678021 100644
--- a/MediaBrowser.Api/PlaylistService.cs
+++ b/MediaBrowser.Api/PlaylistService.cs
@@ -1,13 +1,14 @@
-using MediaBrowser.Controller.Dto;
+using System.Linq;
+using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Net;
using MediaBrowser.Controller.Playlists;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Playlists;
using MediaBrowser.Model.Querying;
-using System.Linq;
using System.Threading.Tasks;
using MediaBrowser.Model.Services;
+using MediaBrowser.Model.Extensions;
namespace MediaBrowser.Api
{
@@ -148,7 +149,7 @@ namespace MediaBrowser.Api
var result = await _playlistManager.CreatePlaylist(new PlaylistCreationRequest
{
Name = request.Name,
- ItemIdList = (request.Ids ?? string.Empty).Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).ToList(),
+ ItemIdList = SplitValue(request.Ids, ','),
UserId = request.UserId,
MediaType = request.MediaType
@@ -171,7 +172,7 @@ namespace MediaBrowser.Api
Task.WaitAll(task);
}
- public async Task<object> Get(GetPlaylistItems request)
+ public object Get(GetPlaylistItems request)
{
var playlist = (Playlist)_libraryManager.GetItemById(request.Id);
var user = !string.IsNullOrWhiteSpace(request.UserId) ? _userManager.GetUserById(request.UserId) : null;
@@ -192,8 +193,7 @@ namespace MediaBrowser.Api
var dtoOptions = GetDtoOptions(_authContext, request);
- var dtos = (await _dtoService.GetBaseItemDtos(items.Select(i => i.Item2), dtoOptions, user).ConfigureAwait(false))
- .ToArray();
+ var dtos = _dtoService.GetBaseItemDtos(items.Select(i => i.Item2).ToList(), dtoOptions, user);
var index = 0;
foreach (var item in dtos)
@@ -202,7 +202,7 @@ namespace MediaBrowser.Api
index++;
}
- var result = new ItemsResult
+ var result = new QueryResult<BaseItemDto>
{
Items = dtos,
TotalRecordCount = count
diff --git a/MediaBrowser.Api/PluginService.cs b/MediaBrowser.Api/PluginService.cs
index eb95224b7..f6efe15e6 100644
--- a/MediaBrowser.Api/PluginService.cs
+++ b/MediaBrowser.Api/PluginService.cs
@@ -23,7 +23,7 @@ namespace MediaBrowser.Api
/// </summary>
[Route("/Plugins", "GET", Summary = "Gets a list of currently installed plugins")]
[Authenticated]
- public class GetPlugins : IReturn<List<PluginInfo>>
+ public class GetPlugins : IReturn<PluginInfo[]>
{
public bool? IsAppStoreEnabled { get; set; }
}
@@ -195,14 +195,13 @@ namespace MediaBrowser.Api
/// <returns>System.Object.</returns>
public async Task<object> Get(GetPlugins request)
{
- var result = _appHost.Plugins.OrderBy(p => p.Name).Select(p => p.GetPluginInfo()).ToList();
+ var result = _appHost.Plugins.OrderBy(p => p.Name).Select(p => p.GetPluginInfo()).ToArray();
var requireAppStoreEnabled = request.IsAppStoreEnabled.HasValue && request.IsAppStoreEnabled.Value;
// Don't fail just on account of image url's
try
{
- var packages = (await _installationManager.GetAvailablePackagesWithoutRegistrationInfo(CancellationToken.None))
- .ToList();
+ var packages = (await _installationManager.GetAvailablePackagesWithoutRegistrationInfo(CancellationToken.None));
foreach (var plugin in result)
{
@@ -223,7 +222,7 @@ namespace MediaBrowser.Api
return pkg != null && pkg.enableInAppStore;
})
- .ToList();
+ .ToArray();
}
}
catch
@@ -232,7 +231,7 @@ namespace MediaBrowser.Api
// Play it safe here
if (requireAppStoreEnabled)
{
- result = new List<PluginInfo>();
+ result = new PluginInfo[] { };
}
}
diff --git a/MediaBrowser.Api/Reports/Data/ReportBuilder.cs b/MediaBrowser.Api/Reports/Data/ReportBuilder.cs
index 9c3dde6a4..6a1502c7e 100644
--- a/MediaBrowser.Api/Reports/Data/ReportBuilder.cs
+++ b/MediaBrowser.Api/Reports/Data/ReportBuilder.cs
@@ -458,7 +458,7 @@ namespace MediaBrowser.Api.Reports
break;
case HeaderMetadata.Network:
- option.Column = (i, r) => this.GetListAsString(i.Studios);
+ option.Column = (i, r) => this.GetListAsString(i.Studios.ToList());
option.ItemID = (i) => this.GetStudioID(i.Studios.FirstOrDefault());
option.Header.ItemViewType = ItemViewType.ItemByNameDetails;
option.Header.SortField = "Studio,SortName";
@@ -513,7 +513,7 @@ namespace MediaBrowser.Api.Reports
internalHeader = HeaderMetadata.AlbumArtist;
break;
case HeaderMetadata.AudioAlbumArtist:
- option.Column = (i, r) => this.GetListAsString(this.GetObject<Audio, List<string>>(i, (x) => x.AlbumArtists));
+ option.Column = (i, r) => this.GetListAsString(this.GetObject<Audio, List<string>>(i, (x) => x.AlbumArtists.ToList()));
option.Header.SortField = "AlbumArtist,Album,SortName";
internalHeader = HeaderMetadata.AlbumArtist;
break;
@@ -533,7 +533,7 @@ namespace MediaBrowser.Api.Reports
break;
case HeaderMetadata.Tracks:
- option.Column = (i, r) => this.GetObject<MusicAlbum, List<Audio>>(i, (x) => x.Tracks.ToList(), new List<Audio>()).Count();
+ option.Column = (i, r) => this.GetObject<MusicAlbum, List<Audio>>(i, (x) => x.Tracks.Cast<Audio>().ToList(), new List<Audio>()).Count();
break;
case HeaderMetadata.Audio:
@@ -613,7 +613,7 @@ namespace MediaBrowser.Api.Reports
HasImageTagsPrimary = item.ImageInfos != null && item.ImageInfos.Count(n => n.Type == ImageType.Primary) > 0,
HasImageTagsBackdrop = item.ImageInfos != null && item.ImageInfos.Count(n => n.Type == ImageType.Backdrop) > 0,
HasImageTagsLogo = item.ImageInfos != null && item.ImageInfos.Count(n => n.Type == ImageType.Logo) > 0,
- HasSpecials = hasSpecialFeatures != null ? hasSpecialFeatures.SpecialFeatureIds.Count > 0 : false,
+ HasSpecials = hasSpecialFeatures != null ? hasSpecialFeatures.SpecialFeatureIds.Length > 0 : false,
HasSubtitles = video != null ? video.HasSubtitles : false,
RowType = ReportHelper.GetRowType(item.GetClientTypeName())
};
diff --git a/MediaBrowser.Api/Reports/ReportsService.cs b/MediaBrowser.Api/Reports/ReportsService.cs
index d4201e73c..a100b91e6 100644
--- a/MediaBrowser.Api/Reports/ReportsService.cs
+++ b/MediaBrowser.Api/Reports/ReportsService.cs
@@ -176,14 +176,12 @@ namespace MediaBrowser.Api.Reports
IncludeItemTypes = request.GetIncludeItemTypes(),
ExcludeItemTypes = request.GetExcludeItemTypes(),
Recursive = request.Recursive,
- SortBy = request.GetOrderBy(),
- SortOrder = request.SortOrder ?? SortOrder.Ascending,
+ OrderBy = request.GetOrderBy(),
IsFavorite = request.IsFavorite,
Limit = request.Limit,
StartIndex = request.StartIndex,
IsMissing = request.IsMissing,
- IsVirtualUnaired = request.IsVirtualUnaired,
IsUnaired = request.IsUnaired,
CollapseBoxSetItems = request.CollapseBoxSetItems,
NameLessThan = request.NameLessThan,
@@ -283,12 +281,6 @@ namespace MediaBrowser.Api.Reports
query.SeriesStatuses = request.SeriesStatus.Split(',').Select(d => (SeriesStatus)Enum.Parse(typeof(SeriesStatus), d, true)).ToArray();
}
- // Filter by Series AirDays
- if (!string.IsNullOrEmpty(request.AirDays))
- {
- query.AirDays = request.AirDays.Split(',').Select(d => (DayOfWeek)Enum.Parse(typeof(DayOfWeek), d, true)).ToArray();
- }
-
// ExcludeLocationTypes
if (!string.IsNullOrEmpty(request.ExcludeLocationTypes))
{
diff --git a/MediaBrowser.Api/ScheduledTasks/ScheduledTaskService.cs b/MediaBrowser.Api/ScheduledTasks/ScheduledTaskService.cs
index e8ad9ea95..abe3e5407 100644
--- a/MediaBrowser.Api/ScheduledTasks/ScheduledTaskService.cs
+++ b/MediaBrowser.Api/ScheduledTasks/ScheduledTaskService.cs
@@ -27,7 +27,7 @@ namespace MediaBrowser.Api.ScheduledTasks
/// Class GetScheduledTasks
/// </summary>
[Route("/ScheduledTasks", "GET", Summary = "Gets scheduled tasks")]
- public class GetScheduledTasks : IReturn<List<TaskInfo>>
+ public class GetScheduledTasks : IReturn<TaskInfo[]>
{
[ApiMember(Name = "IsHidden", Description = "Optional filter tasks that are hidden, or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
public bool? IsHidden { get; set; }
@@ -158,7 +158,7 @@ namespace MediaBrowser.Api.ScheduledTasks
var infos = result
.Select(ScheduledTaskHelpers.GetTaskInfo)
- .ToList();
+ .ToArray();
return ToOptimizedResult(infos);
}
diff --git a/MediaBrowser.Api/SearchService.cs b/MediaBrowser.Api/SearchService.cs
index 80a703313..ad79ea57b 100644
--- a/MediaBrowser.Api/SearchService.cs
+++ b/MediaBrowser.Api/SearchService.cs
@@ -1,4 +1,5 @@
-using MediaBrowser.Controller.Drawing;
+using System.Linq;
+using MediaBrowser.Controller.Drawing;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
@@ -7,7 +8,6 @@ using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Net;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Search;
-using System.Linq;
using System.Threading.Tasks;
using MediaBrowser.Controller.LiveTv;
using MediaBrowser.Model.Services;
@@ -159,9 +159,9 @@ namespace MediaBrowser.Api
IncludeStudios = request.IncludeStudios,
StartIndex = request.StartIndex,
UserId = request.UserId,
- IncludeItemTypes = (request.IncludeItemTypes ?? string.Empty).Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).ToArray(),
- ExcludeItemTypes = (request.ExcludeItemTypes ?? string.Empty).Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).ToArray(),
- MediaTypes = (request.MediaTypes ?? string.Empty).Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).ToArray(),
+ IncludeItemTypes = ApiEntryPoint.Split(request.IncludeItemTypes, ',', true),
+ ExcludeItemTypes = ApiEntryPoint.Split(request.ExcludeItemTypes, ',', true),
+ MediaTypes = ApiEntryPoint.Split(request.MediaTypes, ',', true),
ParentId = request.ParentId,
IsKids = request.IsKids,
@@ -198,7 +198,6 @@ namespace MediaBrowser.Api
Type = item.GetClientTypeName(),
MediaType = item.MediaType,
MatchedTerm = hintInfo.MatchedTerm,
- DisplayMediaType = item.DisplayMediaType,
RunTimeTicks = item.RunTimeTicks,
ProductionYear = item.ProductionYear,
ChannelId = item.ChannelId,
@@ -241,7 +240,7 @@ namespace MediaBrowser.Api
if (album != null)
{
- result.Artists = album.Artists.ToArray();
+ result.Artists = album.Artists;
result.AlbumArtist = album.AlbumArtist;
}
@@ -251,7 +250,7 @@ namespace MediaBrowser.Api
{
result.Album = song.Album;
result.AlbumArtist = song.AlbumArtists.FirstOrDefault();
- result.Artists = song.Artists.ToArray();
+ result.Artists = song.Artists;
}
if (!string.IsNullOrWhiteSpace(item.ChannelId))
diff --git a/MediaBrowser.Api/Session/SessionsService.cs b/MediaBrowser.Api/Session/SessionsService.cs
index 358d09c18..8f54b591e 100644
--- a/MediaBrowser.Api/Session/SessionsService.cs
+++ b/MediaBrowser.Api/Session/SessionsService.cs
@@ -18,7 +18,7 @@ namespace MediaBrowser.Api.Session
/// </summary>
[Route("/Sessions", "GET", Summary = "Gets a list of sessions")]
[Authenticated]
- public class GetSessions : IReturn<List<SessionInfoDto>>
+ public class GetSessions : IReturn<SessionInfoDto[]>
{
[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")]
public string ControllableByUserId { get; set; }
@@ -313,14 +313,13 @@ namespace MediaBrowser.Api.Session
public void Delete(RevokeKey request)
{
- var task = _sessionManager.RevokeToken(request.Key);
+ _sessionManager.RevokeToken(request.Key);
- Task.WaitAll(task);
}
public void Post(CreateKey request)
{
- var task = _authRepo.Create(new AuthenticationInfo
+ _authRepo.Create(new AuthenticationInfo
{
AppName = request.App,
IsActive = true,
@@ -328,8 +327,6 @@ namespace MediaBrowser.Api.Session
DateCreated = DateTime.UtcNow
}, CancellationToken.None);
-
- Task.WaitAll(task);
}
public void Post(ReportSessionEnded request)
@@ -396,7 +393,7 @@ namespace MediaBrowser.Api.Session
});
}
- return ToOptimizedResult(result.Select(_sessionManager.GetSessionInfoDto).ToList());
+ return ToOptimizedResult(result.Select(_sessionManager.GetSessionInfoDto).ToArray());
}
public void Post(SendPlaystateCommand request)
@@ -477,7 +474,7 @@ namespace MediaBrowser.Api.Session
{
var command = new PlayRequest
{
- ItemIds = request.ItemIds.Split(',').ToArray(),
+ ItemIds = request.ItemIds.Split(','),
PlayCommand = request.PlayCommand,
StartPositionTicks = request.StartPositionTicks
@@ -532,9 +529,9 @@ namespace MediaBrowser.Api.Session
}
_sessionManager.ReportCapabilities(request.Id, new ClientCapabilities
{
- PlayableMediaTypes = (request.PlayableMediaTypes ?? string.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList(),
+ PlayableMediaTypes = SplitValue(request.PlayableMediaTypes, ','),
- SupportedCommands = (request.SupportedCommands ?? string.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList(),
+ SupportedCommands = SplitValue(request.SupportedCommands, ','),
SupportsMediaControl = request.SupportsMediaControl,
diff --git a/MediaBrowser.Api/SimilarItemsHelper.cs b/MediaBrowser.Api/SimilarItemsHelper.cs
index 93aad0ef0..0b5eaa476 100644
--- a/MediaBrowser.Api/SimilarItemsHelper.cs
+++ b/MediaBrowser.Api/SimilarItemsHelper.cs
@@ -11,6 +11,7 @@ using System.Linq;
using System.Threading.Tasks;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Services;
+using MediaBrowser.Model.Extensions;
namespace MediaBrowser.Api
{
@@ -29,7 +30,7 @@ namespace MediaBrowser.Api
public string ExcludeArtistIds { get; set; }
}
- public class BaseGetSimilarItems : IReturn<ItemsResult>, IHasDtoOptions
+ public class BaseGetSimilarItems : IReturn<QueryResult<BaseItemDto>>, IHasDtoOptions
{
[ApiMember(Name = "EnableImages", Description = "Optional, include image information in output", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")]
public bool? EnableImages { get; set; }
@@ -70,7 +71,7 @@ namespace MediaBrowser.Api
/// </summary>
public static class SimilarItemsHelper
{
- internal static async Task<QueryResult<BaseItemDto>> GetSimilarItemsResult(DtoOptions dtoOptions, IUserManager userManager, IItemRepository itemRepository, ILibraryManager libraryManager, IUserDataManager userDataRepository, IDtoService dtoService, ILogger logger, BaseGetSimilarItemsFromItem request, Type[] includeTypes, Func<BaseItem, List<PersonInfo>, List<PersonInfo>, BaseItem, int> getSimilarityScore)
+ internal static QueryResult<BaseItemDto> GetSimilarItemsResult(DtoOptions dtoOptions, IUserManager userManager, IItemRepository itemRepository, ILibraryManager libraryManager, IUserDataManager userDataRepository, IDtoService dtoService, ILogger logger, BaseGetSimilarItemsFromItem request, Type[] includeTypes, Func<BaseItem, List<PersonInfo>, List<PersonInfo>, BaseItem, int> getSimilarityScore)
{
var user = !string.IsNullOrWhiteSpace(request.UserId) ? userManager.GetUserById(request.UserId) : null;
@@ -80,7 +81,7 @@ namespace MediaBrowser.Api
var query = new InternalItemsQuery(user)
{
- IncludeItemTypes = includeTypes.Select(i => i.Name).ToArray(),
+ IncludeItemTypes = includeTypes.Select(i => i.Name).ToArray(includeTypes.Length),
Recursive = true,
DtoOptions = dtoOptions
};
@@ -96,18 +97,18 @@ namespace MediaBrowser.Api
var items = GetSimilaritems(item, libraryManager, inputItems, getSimilarityScore)
.ToList();
- IEnumerable<BaseItem> returnItems = items;
+ List<BaseItem> returnItems = items;
if (request.Limit.HasValue)
{
- returnItems = returnItems.Take(request.Limit.Value);
+ returnItems = returnItems.Take(request.Limit.Value).ToList();
}
- var dtos = await dtoService.GetBaseItemDtos(returnItems, dtoOptions, user).ConfigureAwait(false);
+ var dtos = dtoService.GetBaseItemDtos(returnItems, dtoOptions, user);
return new QueryResult<BaseItemDto>
{
- Items = dtos.ToArray(),
+ Items = dtos,
TotalRecordCount = items.Count
};
diff --git a/MediaBrowser.Api/Social/SharingService.cs b/MediaBrowser.Api/Social/SharingService.cs
index 37941bd4a..4f10667b7 100644
--- a/MediaBrowser.Api/Social/SharingService.cs
+++ b/MediaBrowser.Api/Social/SharingService.cs
@@ -121,8 +121,7 @@ namespace MediaBrowser.Api.Social
public void Delete(DeleteShare request)
{
- var task = _sharingManager.DeleteShare(request.Id);
- Task.WaitAll(task);
+ _sharingManager.DeleteShare(request.Id);
}
public async Task<object> Get(GetShareImage request)
@@ -157,7 +156,7 @@ namespace MediaBrowser.Api.Social
}
catch
{
-
+
}
}
diff --git a/MediaBrowser.Api/StartupWizardService.cs b/MediaBrowser.Api/StartupWizardService.cs
index cd56b69bd..7a75aeb4b 100644
--- a/MediaBrowser.Api/StartupWizardService.cs
+++ b/MediaBrowser.Api/StartupWizardService.cs
@@ -95,7 +95,6 @@ namespace MediaBrowser.Api
config.EnableStandaloneMusicKeys = true;
config.EnableCaseSensitiveItemIds = true;
config.SkipDeserializationForBasicTypes = true;
- config.SkipDeserializationForAudio = true;
config.EnableLocalizedGuids = true;
config.EnableSimpleArtistDetection = true;
config.EnableNormalizedItemByNameIds = true;
@@ -126,7 +125,7 @@ namespace MediaBrowser.Api
var user = _userManager.Users.First();
user.Name = request.Name;
- await _userManager.UpdateUser(user).ConfigureAwait(false);
+ _userManager.UpdateUser(user);
var result = new UpdateStartupUserResult();
diff --git a/MediaBrowser.Api/Subtitles/SubtitleService.cs b/MediaBrowser.Api/Subtitles/SubtitleService.cs
index 645aacdec..4d4b4cb27 100644
--- a/MediaBrowser.Api/Subtitles/SubtitleService.cs
+++ b/MediaBrowser.Api/Subtitles/SubtitleService.cs
@@ -14,8 +14,6 @@ using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
-
-using MediaBrowser.Controller.IO;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Services;
using MimeTypes = MediaBrowser.Model.Net.MimeTypes;
@@ -39,7 +37,7 @@ namespace MediaBrowser.Api.Subtitles
[Route("/Items/{Id}/RemoteSearch/Subtitles/{Language}", "GET")]
[Authenticated]
- public class SearchRemoteSubtitles : IReturn<List<RemoteSubtitleInfo>>
+ public class SearchRemoteSubtitles : IReturn<RemoteSubtitleInfo[]>
{
[ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
public string Id { get; set; }
@@ -52,7 +50,7 @@ namespace MediaBrowser.Api.Subtitles
[Route("/Items/{Id}/RemoteSearch/Subtitles/Providers", "GET")]
[Authenticated]
- public class GetSubtitleProviders : IReturn<List<SubtitleProviderInfo>>
+ public class GetSubtitleProviders : IReturn<SubtitleProviderInfo[]>
{
[ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
public string Id { get; set; }
diff --git a/MediaBrowser.Api/SuggestionsService.cs b/MediaBrowser.Api/SuggestionsService.cs
index 99411ffdc..3b918d8a2 100644
--- a/MediaBrowser.Api/SuggestionsService.cs
+++ b/MediaBrowser.Api/SuggestionsService.cs
@@ -8,6 +8,8 @@ using System;
using System.Linq;
using System.Threading.Tasks;
using MediaBrowser.Controller.Library;
+using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.Extensions;
namespace MediaBrowser.Api
{
@@ -47,21 +49,21 @@ namespace MediaBrowser.Api
_libraryManager = libraryManager;
}
- public async Task<object> Get(GetSuggestedItems request)
+ public object Get(GetSuggestedItems request)
{
- var result = await GetResultItems(request).ConfigureAwait(false);
+ var result = GetResultItems(request);
return ToOptimizedResult(result);
}
- private async Task<QueryResult<BaseItemDto>> GetResultItems(GetSuggestedItems request)
+ private QueryResult<BaseItemDto> GetResultItems(GetSuggestedItems request)
{
var user = !string.IsNullOrWhiteSpace(request.UserId) ? _userManager.GetUserById(request.UserId) : null;
var dtoOptions = GetDtoOptions(_authContext, request);
var result = GetItems(request, user, dtoOptions);
- var dtoList = await _dtoService.GetBaseItemDtos(result.Items, dtoOptions, user).ConfigureAwait(false);
+ var dtoList = _dtoService.GetBaseItemDtos(result.Items, dtoOptions, user);
if (dtoList == null)
{
@@ -71,7 +73,7 @@ namespace MediaBrowser.Api
return new QueryResult<BaseItemDto>
{
TotalRecordCount = result.TotalRecordCount,
- Items = dtoList.ToArray()
+ Items = dtoList
};
}
@@ -79,7 +81,7 @@ namespace MediaBrowser.Api
{
return _libraryManager.GetItemsResult(new InternalItemsQuery(user)
{
- SortBy = new string[] { ItemSortBy.Random },
+ OrderBy = new[] { ItemSortBy.Random }.Select(i => new Tuple<string, SortOrder>(i, SortOrder.Descending)).ToArray(),
MediaTypes = request.GetMediaTypes(),
IncludeItemTypes = request.GetIncludeItemTypes(),
IsVirtualItem = false,
diff --git a/MediaBrowser.Api/System/SystemService.cs b/MediaBrowser.Api/System/SystemService.cs
index a9cec0914..37613c1c8 100644
--- a/MediaBrowser.Api/System/SystemService.cs
+++ b/MediaBrowser.Api/System/SystemService.cs
@@ -43,7 +43,7 @@ namespace MediaBrowser.Api.System
/// Class RestartApplication
/// </summary>
[Route("/System/Restart", "POST", Summary = "Restarts the application, if needed")]
- [Authenticated(Roles = "Admin")]
+ [Authenticated(Roles = "Admin", AllowLocal = true)]
public class RestartApplication
{
}
@@ -52,15 +52,14 @@ namespace MediaBrowser.Api.System
/// This is currently not authenticated because the uninstaller needs to be able to shutdown the server.
/// </summary>
[Route("/System/Shutdown", "POST", Summary = "Shuts down the application")]
+ [Authenticated(Roles = "Admin", AllowLocal = true)]
public class ShutdownApplication
{
- // TODO: This is not currently authenticated due to uninstaller
- // Improve later
}
[Route("/System/Logs", "GET", Summary = "Gets a list of available server log files")]
[Authenticated(Roles = "Admin")]
- public class GetServerLogs : IReturn<List<LogFile>>
+ public class GetServerLogs : IReturn<LogFile[]>
{
}
@@ -118,16 +117,15 @@ namespace MediaBrowser.Api.System
public object Get(GetServerLogs request)
{
- List<FileSystemMetadata> files;
+ IEnumerable<FileSystemMetadata> files;
try
{
- files = _fileSystem.GetFiles(_appPaths.LogDirectoryPath, new[] { ".txt" }, true, false)
- .ToList();
+ files = _fileSystem.GetFiles(_appPaths.LogDirectoryPath, new[] { ".txt" }, true, false);
}
catch (IOException)
{
- files = new List<FileSystemMetadata>();
+ files = new FileSystemMetadata[] { };
}
var result = files.Select(i => new LogFile
@@ -140,7 +138,7 @@ namespace MediaBrowser.Api.System
}).OrderByDescending(i => i.DateModified)
.ThenByDescending(i => i.DateCreated)
.ThenBy(i => i.Name)
- .ToList();
+ .ToArray();
return ToOptimizedResult(result);
}
@@ -150,6 +148,12 @@ namespace MediaBrowser.Api.System
var file = _fileSystem.GetFiles(_appPaths.LogDirectoryPath)
.First(i => string.Equals(i.Name, request.Name, StringComparison.OrdinalIgnoreCase));
+ // For older files, assume fully static
+ if (file.LastWriteTimeUtc < DateTime.UtcNow.AddHours(-1))
+ {
+ return ResultFactory.GetStaticFileResult(Request, file.FullName, FileShareMode.Read);
+ }
+
return ResultFactory.GetStaticFileResult(Request, file.FullName, FileShareMode.ReadWrite);
}
diff --git a/MediaBrowser.Api/TestService.cs b/MediaBrowser.Api/TestService.cs
deleted file mode 100644
index 5340b816c..000000000
--- a/MediaBrowser.Api/TestService.cs
+++ /dev/null
@@ -1,77 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using MediaBrowser.Model.Services;
-
-namespace MediaBrowser.Api
-{
- [Route("/Test/String", "GET")]
- public class GetString
- {
- }
-
- [Route("/Test/OptimizedString", "GET")]
- public class GetOptimizedString
- {
- }
-
- [Route("/Test/Bytes", "GET")]
- public class GetBytes
- {
- }
-
- [Route("/Test/OptimizedBytes", "GET")]
- public class GetOptimizedBytes
- {
- }
-
- [Route("/Test/Stream", "GET")]
- public class GetStream
- {
- }
-
- [Route("/Test/OptimizedStream", "GET")]
- public class GetOptimizedStream
- {
- }
-
- [Route("/Test/BytesWithContentType", "GET")]
- public class GetBytesWithContentType
- {
- }
-
- public class TestService : BaseApiService
- {
- public object Get(GetString request)
- {
- return "Welcome to Emby!";
- }
- public object Get(GetOptimizedString request)
- {
- return ToOptimizedResult("Welcome to Emby!");
- }
- public object Get(GetBytes request)
- {
- return Encoding.UTF8.GetBytes("Welcome to Emby!");
- }
- public object Get(GetOptimizedBytes request)
- {
- return ToOptimizedResult(Encoding.UTF8.GetBytes("Welcome to Emby!"));
- }
- public object Get(GetBytesWithContentType request)
- {
- return ApiEntryPoint.Instance.ResultFactory.GetResult(Encoding.UTF8.GetBytes("Welcome to Emby!"), "text/html");
- }
- public object Get(GetStream request)
- {
- return new MemoryStream(Encoding.UTF8.GetBytes("Welcome to Emby!"));
- }
- public object Get(GetOptimizedStream request)
- {
- return ToOptimizedResult(new MemoryStream(Encoding.UTF8.GetBytes("Welcome to Emby!")));
- }
- }
-}
diff --git a/MediaBrowser.Api/TvShowsService.cs b/MediaBrowser.Api/TvShowsService.cs
index 5a6004760..fd81a9a3e 100644
--- a/MediaBrowser.Api/TvShowsService.cs
+++ b/MediaBrowser.Api/TvShowsService.cs
@@ -21,7 +21,7 @@ namespace MediaBrowser.Api
/// Class GetNextUpEpisodes
/// </summary>
[Route("/Shows/NextUp", "GET", Summary = "Gets a list of next up episodes")]
- public class GetNextUpEpisodes : IReturn<ItemsResult>, IHasDtoOptions
+ public class GetNextUpEpisodes : IReturn<QueryResult<BaseItemDto>>, IHasDtoOptions
{
/// <summary>
/// Gets or sets the user id.
@@ -81,7 +81,7 @@ namespace MediaBrowser.Api
}
[Route("/Shows/Upcoming", "GET", Summary = "Gets a list of upcoming episodes")]
- public class GetUpcomingEpisodes : IReturn<ItemsResult>, IHasDtoOptions
+ public class GetUpcomingEpisodes : IReturn<QueryResult<BaseItemDto>>, IHasDtoOptions
{
/// <summary>
/// Gets or sets the user id.
@@ -137,7 +137,7 @@ namespace MediaBrowser.Api
}
[Route("/Shows/{Id}/Episodes", "GET", Summary = "Gets episodes for a tv season")]
- public class GetEpisodes : IReturn<ItemsResult>, IHasItemFields, IHasDtoOptions
+ public class GetEpisodes : IReturn<QueryResult<BaseItemDto>>, IHasItemFields, IHasDtoOptions
{
/// <summary>
/// Gets or sets the user id.
@@ -165,9 +165,6 @@ namespace MediaBrowser.Api
[ApiMember(Name = "IsMissing", Description = "Optional filter by items that are missing episodes or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
public bool? IsMissing { get; set; }
- [ApiMember(Name = "IsVirtualUnaired", Description = "Optional filter by items that are virtual unaired episodes or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
- public bool? IsVirtualUnaired { get; set; }
-
[ApiMember(Name = "AdjacentTo", Description = "Optional. Return items that are siblings of a supplied item.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
public string AdjacentTo { get; set; }
@@ -199,10 +196,16 @@ namespace MediaBrowser.Api
[ApiMember(Name = "EnableUserData", Description = "Optional, include user data", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")]
public bool? EnableUserData { get; set; }
+
+ [ApiMember(Name = "SortBy", Description = "Optional. Specify one or more sort orders, comma delimeted. Options: Album, AlbumArtist, Artist, Budget, CommunityRating, CriticRating, DateCreated, DatePlayed, PlayCount, PremiereDate, ProductionYear, SortName, Random, Revenue, Runtime", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
+ public string SortBy { get; set; }
+
+ [ApiMember(Name = "SortOrder", Description = "Sort Order - Ascending,Descending", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
+ public SortOrder? SortOrder { get; set; }
}
[Route("/Shows/{Id}/Seasons", "GET", Summary = "Gets seasons for a tv series")]
- public class GetSeasons : IReturn<ItemsResult>, IHasItemFields, IHasDtoOptions
+ public class GetSeasons : IReturn<QueryResult<BaseItemDto>>, IHasItemFields, IHasDtoOptions
{
/// <summary>
/// Gets or sets the user id.
@@ -227,9 +230,6 @@ namespace MediaBrowser.Api
[ApiMember(Name = "IsMissing", Description = "Optional filter by items that are missing episodes or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
public bool? IsMissing { get; set; }
- [ApiMember(Name = "IsVirtualUnaired", Description = "Optional filter by items that are virtual unaired episodes or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
- public bool? IsVirtualUnaired { get; set; }
-
[ApiMember(Name = "AdjacentTo", Description = "Optional. Return items that are siblings of a supplied item.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
public string AdjacentTo { get; set; }
@@ -293,14 +293,14 @@ namespace MediaBrowser.Api
/// </summary>
/// <param name="request">The request.</param>
/// <returns>System.Object.</returns>
- public async Task<object> Get(GetSimilarShows request)
+ public object Get(GetSimilarShows request)
{
- var result = await GetSimilarItemsResult(request).ConfigureAwait(false);
+ var result = GetSimilarItemsResult(request);
return ToOptimizedSerializedResultUsingCache(result);
}
- private async Task<QueryResult<BaseItemDto>> GetSimilarItemsResult(BaseGetSimilarItemsFromItem request)
+ private QueryResult<BaseItemDto> GetSimilarItemsResult(BaseGetSimilarItemsFromItem request)
{
var user = !string.IsNullOrWhiteSpace(request.UserId) ? _userManager.GetUserById(request.UserId) : null;
@@ -320,11 +320,13 @@ namespace MediaBrowser.Api
SimilarTo = item,
DtoOptions = dtoOptions
- }).ToList();
+ });
+
+ var returnList = _dtoService.GetBaseItemDtos(itemsResult, dtoOptions, user);
var result = new QueryResult<BaseItemDto>
{
- Items = (await _dtoService.GetBaseItemDtos(itemsResult, dtoOptions, user).ConfigureAwait(false)).ToArray(),
+ Items = returnList,
TotalRecordCount = itemsResult.Count
};
@@ -332,7 +334,7 @@ namespace MediaBrowser.Api
return result;
}
- public async Task<object> Get(GetUpcomingEpisodes request)
+ public object Get(GetUpcomingEpisodes request)
{
var user = _userManager.GetUserById(request.UserId);
@@ -345,8 +347,7 @@ namespace MediaBrowser.Api
var itemsResult = _libraryManager.GetItemList(new InternalItemsQuery(user)
{
IncludeItemTypes = new[] { typeof(Episode).Name },
- SortBy = new[] { "PremiereDate", "AirTime", "SortName" },
- SortOrder = SortOrder.Ascending,
+ OrderBy = new[] { ItemSortBy.PremiereDate, ItemSortBy.SortName }.Select(i => new Tuple<string, SortOrder>(i, SortOrder.Ascending)).ToArray(),
MinPremiereDate = minPremiereDate,
StartIndex = request.StartIndex,
Limit = request.Limit,
@@ -354,11 +355,11 @@ namespace MediaBrowser.Api
Recursive = true,
DtoOptions = options
- }).ToList();
+ });
- var returnItems = (await _dtoService.GetBaseItemDtos(itemsResult, options, user).ConfigureAwait(false)).ToArray();
+ var returnItems = _dtoService.GetBaseItemDtos(itemsResult, options, user);
- var result = new ItemsResult
+ var result = new QueryResult<BaseItemDto>
{
TotalRecordCount = itemsResult.Count,
Items = returnItems
@@ -372,7 +373,7 @@ namespace MediaBrowser.Api
/// </summary>
/// <param name="request">The request.</param>
/// <returns>System.Object.</returns>
- public async Task<object> Get(GetNextUpEpisodes request)
+ public object Get(GetNextUpEpisodes request)
{
var options = GetDtoOptions(_authContext, request);
@@ -388,9 +389,9 @@ namespace MediaBrowser.Api
var user = _userManager.GetUserById(request.UserId);
- var returnItems = (await _dtoService.GetBaseItemDtos(result.Items, options, user).ConfigureAwait(false)).ToArray();
+ var returnItems = _dtoService.GetBaseItemDtos(result.Items, options, user);
- return ToOptimizedSerializedResultUsingCache(new ItemsResult
+ return ToOptimizedSerializedResultUsingCache(new QueryResult<BaseItemDto>
{
TotalRecordCount = result.TotalRecordCount,
Items = returnItems
@@ -421,7 +422,7 @@ namespace MediaBrowser.Api
return items;
}
- public async Task<object> Get(GetSeasons request)
+ public object Get(GetSeasons request)
{
var user = _userManager.GetUserById(request.UserId);
@@ -432,21 +433,19 @@ namespace MediaBrowser.Api
throw new ResourceNotFoundException("Series not found");
}
- var seasons = (series.GetItems(new InternalItemsQuery(user)
+ var seasons = (series.GetItemList(new InternalItemsQuery(user)
{
IsMissing = request.IsMissing,
- IsVirtualUnaired = request.IsVirtualUnaired,
IsSpecialSeason = request.IsSpecialSeason,
AdjacentTo = request.AdjacentTo
- })).Items.OfType<Season>();
+ }));
var dtoOptions = GetDtoOptions(_authContext, request);
- var returnItems = (await _dtoService.GetBaseItemDtos(seasons, dtoOptions, user).ConfigureAwait(false))
- .ToArray();
+ var returnItems = _dtoService.GetBaseItemDtos(seasons, dtoOptions, user);
- return new ItemsResult
+ return new QueryResult<BaseItemDto>
{
TotalRecordCount = returnItems.Length,
Items = returnItems
@@ -463,11 +462,11 @@ namespace MediaBrowser.Api
return null;
}
- public async Task<object> Get(GetEpisodes request)
+ public object Get(GetEpisodes request)
{
var user = _userManager.GetUserById(request.UserId);
- IEnumerable<Episode> episodes;
+ List<BaseItem> episodes;
var dtoOptions = GetDtoOptions(_authContext, request);
@@ -495,11 +494,11 @@ namespace MediaBrowser.Api
if (season == null)
{
- episodes = new List<Episode>();
+ episodes = new List<BaseItem>();
}
else
{
- episodes = season.GetEpisodes(user, dtoOptions);
+ episodes = ((Season)season).GetEpisodes(user, dtoOptions);
}
}
else
@@ -511,46 +510,44 @@ namespace MediaBrowser.Api
throw new ResourceNotFoundException("Series not found");
}
- episodes = series.GetEpisodes(user, dtoOptions);
+ episodes = series.GetEpisodes(user, dtoOptions).ToList();
}
// Filter after the fact in case the ui doesn't want them
if (request.IsMissing.HasValue)
{
var val = request.IsMissing.Value;
- episodes = episodes.Where(i => i.IsMissingEpisode == val);
- }
-
- // Filter after the fact in case the ui doesn't want them
- if (request.IsVirtualUnaired.HasValue)
- {
- var val = request.IsVirtualUnaired.Value;
- episodes = episodes.Where(i => i.IsVirtualUnaired == val);
+ episodes = episodes.Where(i => ((Episode)i).IsMissingEpisode == val).ToList();
}
if (!string.IsNullOrWhiteSpace(request.StartItemId))
{
- episodes = episodes.SkipWhile(i => !string.Equals(i.Id.ToString("N"), request.StartItemId, StringComparison.OrdinalIgnoreCase));
+ episodes = episodes.SkipWhile(i => !string.Equals(i.Id.ToString("N"), request.StartItemId, StringComparison.OrdinalIgnoreCase)).ToList();
}
- IEnumerable<BaseItem> returnItems = episodes;
-
// This must be the last filter
if (!string.IsNullOrEmpty(request.AdjacentTo))
{
- returnItems = UserViewBuilder.FilterForAdjacency(returnItems, request.AdjacentTo);
+ episodes = UserViewBuilder.FilterForAdjacency(episodes, request.AdjacentTo).ToList();
}
- var returnList = returnItems.ToList();
+ if (string.Equals(request.SortBy, ItemSortBy.Random, StringComparison.OrdinalIgnoreCase))
+ {
+ episodes = episodes.OrderBy(i => Guid.NewGuid()).ToList();
+ }
+
+ var returnItems = episodes;
- var pagedItems = ApplyPaging(returnList, request.StartIndex, request.Limit);
+ if (request.StartIndex.HasValue || request.Limit.HasValue)
+ {
+ returnItems = ApplyPaging(episodes, request.StartIndex, request.Limit).ToList();
+ }
- var dtos = (await _dtoService.GetBaseItemDtos(pagedItems, dtoOptions, user).ConfigureAwait(false))
- .ToArray();
+ var dtos = _dtoService.GetBaseItemDtos(returnItems, dtoOptions, user);
- return new ItemsResult
+ return new QueryResult<BaseItemDto>
{
- TotalRecordCount = returnList.Count,
+ TotalRecordCount = episodes.Count,
Items = dtos
};
}
diff --git a/MediaBrowser.Api/UserLibrary/ArtistsService.cs b/MediaBrowser.Api/UserLibrary/ArtistsService.cs
index 7c1519e9f..4018759d9 100644
--- a/MediaBrowser.Api/UserLibrary/ArtistsService.cs
+++ b/MediaBrowser.Api/UserLibrary/ArtistsService.cs
@@ -132,7 +132,7 @@ namespace MediaBrowser.Api.UserLibrary
/// <param name="request">The request.</param>
/// <param name="items">The items.</param>
/// <returns>IEnumerable{Tuple{System.StringFunc{System.Int32}}}.</returns>
- protected override IEnumerable<BaseItem> GetAllItems(GetItemsByName request, IEnumerable<BaseItem> items)
+ protected override IEnumerable<BaseItem> GetAllItems(GetItemsByName request, IList<BaseItem> items)
{
throw new NotImplementedException();
}
diff --git a/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs b/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs
index 24d0a7d52..ed0c4069b 100644
--- a/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs
+++ b/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs
@@ -10,6 +10,7 @@ using System.Linq;
using MediaBrowser.Controller.Net;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Services;
+using MediaBrowser.Model.Extensions;
namespace MediaBrowser.Api.UserLibrary
{
@@ -87,7 +88,7 @@ namespace MediaBrowser.Api.UserLibrary
return null;
}
- protected ItemsResult GetResultSlim(GetItemsByName request)
+ protected QueryResult<BaseItemDto> GetResultSlim(GetItemsByName request)
{
var dtoOptions = GetDtoOptions(AuthorizationContext, request);
@@ -208,9 +209,9 @@ namespace MediaBrowser.Api.UserLibrary
return dto;
});
- return new ItemsResult
+ return new QueryResult<BaseItemDto>
{
- Items = dtos.ToArray(),
+ Items = dtos.ToArray(result.Items.Length),
TotalRecordCount = result.TotalRecordCount
};
}
@@ -239,7 +240,7 @@ namespace MediaBrowser.Api.UserLibrary
/// </summary>
/// <param name="request">The request.</param>
/// <returns>Task{ItemsResult}.</returns>
- protected ItemsResult GetResult(GetItemsByName request)
+ protected QueryResult<BaseItemDto> GetResult(GetItemsByName request)
{
var dtoOptions = GetDtoOptions(AuthorizationContext, request);
@@ -256,7 +257,7 @@ namespace MediaBrowser.Api.UserLibrary
parentItem = string.IsNullOrEmpty(request.ParentId) ? LibraryManager.RootFolder : LibraryManager.GetItemById(request.ParentId);
}
- IEnumerable<BaseItem> items;
+ IList<BaseItem> items;
var excludeItemTypes = request.GetExcludeItemTypes();
var includeItemTypes = request.GetIncludeItemTypes();
@@ -279,32 +280,32 @@ namespace MediaBrowser.Api.UserLibrary
if (!string.IsNullOrWhiteSpace(request.UserId))
{
items = request.Recursive ?
- folder.GetRecursiveChildren(user, query) :
- folder.GetChildren(user, true).Where(filter);
+ folder.GetRecursiveChildren(user, query).ToList() :
+ folder.GetChildren(user, true).Where(filter).ToList();
}
else
{
items = request.Recursive ?
folder.GetRecursiveChildren(filter) :
- folder.Children.Where(filter);
+ folder.Children.Where(filter).ToList();
}
}
else
{
- items = new[] { parentItem }.Where(filter);
+ items = new[] { parentItem }.Where(filter).ToList();
}
var extractedItems = GetAllItems(request, items);
var filteredItems = FilterItems(request, extractedItems, user);
- filteredItems = LibraryManager.Sort(filteredItems, user, request.GetOrderBy(), request.SortOrder ?? SortOrder.Ascending);
+ filteredItems = LibraryManager.Sort(filteredItems, user, request.GetOrderBy());
var ibnItemsArray = filteredItems.ToList();
IEnumerable<BaseItem> ibnItems = ibnItemsArray;
- var result = new ItemsResult
+ var result = new QueryResult<BaseItemDto>
{
TotalRecordCount = ibnItemsArray.Count
};
@@ -356,13 +357,13 @@ namespace MediaBrowser.Api.UserLibrary
items = items.Where(i => string.Compare(request.NameLessThan, i.SortName, StringComparison.CurrentCultureIgnoreCase) == 1);
}
- var imageTypes = request.GetImageTypes().ToList();
- if (imageTypes.Count > 0)
+ var imageTypes = request.GetImageTypes();
+ if (imageTypes.Length > 0)
{
items = items.Where(item => imageTypes.Any(item.HasImage));
}
- var filters = request.GetFilters().ToList();
+ var filters = request.GetFilters();
if (filters.Contains(ItemFilter.Dislikes))
{
@@ -499,13 +500,13 @@ namespace MediaBrowser.Api.UserLibrary
/// <param name="request">The request.</param>
/// <param name="items">The items.</param>
/// <returns>IEnumerable{Task{`0}}.</returns>
- protected abstract IEnumerable<BaseItem> GetAllItems(GetItemsByName request, IEnumerable<BaseItem> items);
+ protected abstract IEnumerable<BaseItem> GetAllItems(GetItemsByName request, IList<BaseItem> items);
}
/// <summary>
/// Class GetItemsByName
/// </summary>
- public class GetItemsByName : BaseItemsRequest, IReturn<ItemsResult>
+ public class GetItemsByName : BaseItemsRequest, IReturn<QueryResult<BaseItemDto>>
{
public GetItemsByName()
{
diff --git a/MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs b/MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs
index 3415d01f1..88d080db5 100644
--- a/MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs
+++ b/MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs
@@ -70,9 +70,6 @@ namespace MediaBrowser.Api.UserLibrary
[ApiMember(Name = "IsUnaired", Description = "Optional filter by items that are unaired episodes or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
public bool? IsUnaired { get; set; }
- [ApiMember(Name = "IsVirtualUnaired", Description = "Optional filter by items that are virtual unaired episodes or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
- public bool? IsVirtualUnaired { get; set; }
-
[ApiMember(Name = "MinCommunityRating", Description = "Optional filter by minimum community rating.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
public double? MinCommunityRating { get; set; }
@@ -139,7 +136,7 @@ namespace MediaBrowser.Api.UserLibrary
/// </summary>
/// <value>The sort order.</value>
[ApiMember(Name = "SortOrder", Description = "Sort Order - Ascending,Descending", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
- public SortOrder? SortOrder { get; set; }
+ public string SortOrder { get; set; }
/// <summary>
/// Specify this to localize the search to a specific item or folder. Omit to use the root.
@@ -300,13 +297,6 @@ namespace MediaBrowser.Api.UserLibrary
public string VideoTypes { get; set; }
/// <summary>
- /// Gets or sets the air days.
- /// </summary>
- /// <value>The air days.</value>
- [ApiMember(Name = "AirDays", Description = "Optional filter by Series Air Days. Allows multiple, comma delimeted.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
- public string AirDays { get; set; }
-
- /// <summary>
/// Gets or sets the user id.
/// </summary>
/// <value>The user id.</value>
@@ -445,7 +435,7 @@ namespace MediaBrowser.Api.UserLibrary
/// Gets the filters.
/// </summary>
/// <returns>IEnumerable{ItemFilter}.</returns>
- public IEnumerable<ItemFilter> GetFilters()
+ public ItemFilter[] GetFilters()
{
var val = Filters;
@@ -454,14 +444,14 @@ namespace MediaBrowser.Api.UserLibrary
return new ItemFilter[] { };
}
- return val.Split(',').Select(v => (ItemFilter)Enum.Parse(typeof(ItemFilter), v, true));
+ return val.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(v => (ItemFilter)Enum.Parse(typeof(ItemFilter), v, true)).ToArray();
}
/// <summary>
/// Gets the image types.
/// </summary>
/// <returns>IEnumerable{ImageType}.</returns>
- public IEnumerable<ImageType> GetImageTypes()
+ public ImageType[] GetImageTypes()
{
var val = ImageTypes;
@@ -470,23 +460,48 @@ namespace MediaBrowser.Api.UserLibrary
return new ImageType[] { };
}
- return val.Split(',').Select(v => (ImageType)Enum.Parse(typeof(ImageType), v, true));
+ return val.Split(',').Select(v => (ImageType)Enum.Parse(typeof(ImageType), v, true)).ToArray();
}
/// <summary>
/// Gets the order by.
/// </summary>
/// <returns>IEnumerable{ItemSortBy}.</returns>
- public string[] GetOrderBy()
+ public Tuple<string, SortOrder>[] GetOrderBy()
{
- var val = SortBy;
+ return GetOrderBy(SortBy, SortOrder);
+ }
+
+ public static Tuple<string, SortOrder>[] GetOrderBy(string sortBy, string requestedSortOrder)
+ {
+ var val = sortBy;
if (string.IsNullOrEmpty(val))
{
- return new string[] { };
+ return new Tuple<string, Model.Entities.SortOrder>[] { };
+ }
+
+ var vals = val.Split(',');
+ if (string.IsNullOrWhiteSpace(requestedSortOrder))
+ {
+ requestedSortOrder = "Ascending";
+ }
+
+ var sortOrders = requestedSortOrder.Split(',');
+
+ var result = new Tuple<string, Model.Entities.SortOrder>[vals.Length];
+
+ for (var i = 0; i < vals.Length; i++)
+ {
+ var sortOrderIndex = sortOrders.Length > i ? i : 0;
+
+ var sortOrderValue = sortOrders.Length > sortOrderIndex ? sortOrders[sortOrderIndex] : null;
+ var sortOrder = string.Equals(sortOrderValue, "Descending", StringComparison.OrdinalIgnoreCase) ? MediaBrowser.Model.Entities.SortOrder.Descending : MediaBrowser.Model.Entities.SortOrder.Ascending;
+
+ result[i] = new Tuple<string, Model.Entities.SortOrder>(vals[i], sortOrder);
}
- return val.Split(',');
+ return result;
}
}
}
diff --git a/MediaBrowser.Api/UserLibrary/GameGenresService.cs b/MediaBrowser.Api/UserLibrary/GameGenresService.cs
index 56730c1b2..0b2ca4daf 100644
--- a/MediaBrowser.Api/UserLibrary/GameGenresService.cs
+++ b/MediaBrowser.Api/UserLibrary/GameGenresService.cs
@@ -93,7 +93,7 @@ namespace MediaBrowser.Api.UserLibrary
/// <param name="request">The request.</param>
/// <param name="items">The items.</param>
/// <returns>IEnumerable{Tuple{System.StringFunc{System.Int32}}}.</returns>
- protected override IEnumerable<BaseItem> GetAllItems(GetItemsByName request, IEnumerable<BaseItem> items)
+ protected override IEnumerable<BaseItem> GetAllItems(GetItemsByName request, IList<BaseItem> items)
{
throw new NotImplementedException();
}
diff --git a/MediaBrowser.Api/UserLibrary/GenresService.cs b/MediaBrowser.Api/UserLibrary/GenresService.cs
index fc387e5e3..d913f52d9 100644
--- a/MediaBrowser.Api/UserLibrary/GenresService.cs
+++ b/MediaBrowser.Api/UserLibrary/GenresService.cs
@@ -115,7 +115,7 @@ namespace MediaBrowser.Api.UserLibrary
/// <param name="request">The request.</param>
/// <param name="items">The items.</param>
/// <returns>IEnumerable{Tuple{System.StringFunc{System.Int32}}}.</returns>
- protected override IEnumerable<BaseItem> GetAllItems(GetItemsByName request, IEnumerable<BaseItem> items)
+ protected override IEnumerable<BaseItem> GetAllItems(GetItemsByName request, IList<BaseItem> items)
{
throw new NotImplementedException();
}
diff --git a/MediaBrowser.Api/UserLibrary/ItemsService.cs b/MediaBrowser.Api/UserLibrary/ItemsService.cs
index 01e1ce769..fb48f65e4 100644
--- a/MediaBrowser.Api/UserLibrary/ItemsService.cs
+++ b/MediaBrowser.Api/UserLibrary/ItemsService.cs
@@ -10,8 +10,10 @@ using System.Globalization;
using System.Linq;
using System.Threading.Tasks;
using MediaBrowser.Controller.Entities.Audio;
+using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Globalization;
using MediaBrowser.Model.Services;
+using MediaBrowser.Model.Extensions;
namespace MediaBrowser.Api.UserLibrary
{
@@ -20,7 +22,7 @@ namespace MediaBrowser.Api.UserLibrary
/// </summary>
[Route("/Items", "GET", Summary = "Gets items based on a query.")]
[Route("/Users/{UserId}/Items", "GET", Summary = "Gets items based on a query.")]
- public class GetItems : BaseItemsRequest, IReturn<ItemsResult>
+ public class GetItems : BaseItemsRequest, IReturn<QueryResult<BaseItemDto>>
{
}
@@ -82,14 +84,14 @@ namespace MediaBrowser.Api.UserLibrary
/// </summary>
/// <param name="request">The request.</param>
/// <returns>System.Object.</returns>
- public async Task<object> Get(GetItems request)
+ public object Get(GetItems request)
{
if (request == null)
{
throw new ArgumentNullException("request");
}
- var result = await GetItems(request).ConfigureAwait(false);
+ var result = GetItems(request);
return ToOptimizedSerializedResultUsingCache(result);
}
@@ -98,8 +100,7 @@ namespace MediaBrowser.Api.UserLibrary
/// Gets the items.
/// </summary>
/// <param name="request">The request.</param>
- /// <returns>Task{ItemsResult}.</returns>
- private async Task<ItemsResult> GetItems(GetItems request)
+ private QueryResult<BaseItemDto> GetItems(GetItems request)
{
var user = !string.IsNullOrWhiteSpace(request.UserId) ? _userManager.GetUserById(request.UserId) : null;
@@ -117,17 +118,17 @@ namespace MediaBrowser.Api.UserLibrary
throw new InvalidOperationException("GetItemsToSerialize result.Items returned null");
}
- var dtoList = await _dtoService.GetBaseItemDtos(result.Items, dtoOptions, user).ConfigureAwait(false);
+ var dtoList = _dtoService.GetBaseItemDtos(result.Items, dtoOptions, user);
if (dtoList == null)
{
throw new InvalidOperationException("GetBaseItemDtos returned null");
}
- return new ItemsResult
+ return new QueryResult<BaseItemDto>
{
TotalRecordCount = result.TotalRecordCount,
- Items = dtoList.ToArray()
+ Items = dtoList
};
}
@@ -179,9 +180,7 @@ namespace MediaBrowser.Api.UserLibrary
return folder.GetItems(GetItemsQuery(request, dtoOptions, user));
}
- IEnumerable<BaseItem> items = folder.GetChildren(user, true);
-
- var itemsArray = items.ToArray();
+ var itemsArray = folder.GetChildren(user, true).ToArray();
return new QueryResult<BaseItem>
{
@@ -199,14 +198,12 @@ namespace MediaBrowser.Api.UserLibrary
IncludeItemTypes = request.GetIncludeItemTypes(),
ExcludeItemTypes = request.GetExcludeItemTypes(),
Recursive = request.Recursive,
- SortBy = request.GetOrderBy(),
- SortOrder = request.SortOrder ?? SortOrder.Ascending,
+ OrderBy = request.GetOrderBy(),
IsFavorite = request.IsFavorite,
Limit = request.Limit,
StartIndex = request.StartIndex,
IsMissing = request.IsMissing,
- IsVirtualUnaired = request.IsVirtualUnaired,
IsUnaired = request.IsUnaired,
CollapseBoxSetItems = request.CollapseBoxSetItems,
NameLessThan = request.NameLessThan,
@@ -238,8 +235,8 @@ namespace MediaBrowser.Api.UserLibrary
PersonIds = request.GetPersonIds(),
PersonTypes = request.GetPersonTypes(),
Years = request.GetYears(),
- ImageTypes = request.GetImageTypes().ToArray(),
- VideoTypes = request.GetVideoTypes().ToArray(),
+ ImageTypes = request.GetImageTypes(),
+ VideoTypes = request.GetVideoTypes(),
AdjacentTo = request.AdjacentTo,
ItemIds = request.GetItemIds(),
MinPlayers = request.MinPlayers,
@@ -319,12 +316,6 @@ namespace MediaBrowser.Api.UserLibrary
query.SeriesStatuses = request.SeriesStatus.Split(',').Select(d => (SeriesStatus)Enum.Parse(typeof(SeriesStatus), d, true)).ToArray();
}
- // Filter by Series AirDays
- if (!string.IsNullOrEmpty(request.AirDays))
- {
- query.AirDays = request.AirDays.Split(',').Select(d => (DayOfWeek)Enum.Parse(typeof(DayOfWeek), d, true)).ToArray();
- }
-
// ExcludeLocationTypes
if (!string.IsNullOrEmpty(request.ExcludeLocationTypes))
{
@@ -338,13 +329,11 @@ namespace MediaBrowser.Api.UserLibrary
if (!string.IsNullOrEmpty(request.LocationTypes))
{
var requestedLocationTypes =
- request.LocationTypes.Split(',')
- .Select(d => (LocationType)Enum.Parse(typeof(LocationType), d, true))
- .ToList();
+ request.LocationTypes.Split(',');
- if (requestedLocationTypes.Count > 0 && requestedLocationTypes.Count < 4)
+ if (requestedLocationTypes.Length > 0 && requestedLocationTypes.Length < 4)
{
- query.IsVirtualItem = requestedLocationTypes.Contains(LocationType.Virtual);
+ query.IsVirtualItem = requestedLocationTypes.Contains(LocationType.Virtual.ToString());
}
}
diff --git a/MediaBrowser.Api/UserLibrary/MusicGenresService.cs b/MediaBrowser.Api/UserLibrary/MusicGenresService.cs
index d1d4aa634..36dc773d4 100644
--- a/MediaBrowser.Api/UserLibrary/MusicGenresService.cs
+++ b/MediaBrowser.Api/UserLibrary/MusicGenresService.cs
@@ -94,7 +94,7 @@ namespace MediaBrowser.Api.UserLibrary
/// <param name="request">The request.</param>
/// <param name="items">The items.</param>
/// <returns>IEnumerable{Tuple{System.StringFunc{System.Int32}}}.</returns>
- protected override IEnumerable<BaseItem> GetAllItems(GetItemsByName request, IEnumerable<BaseItem> items)
+ protected override IEnumerable<BaseItem> GetAllItems(GetItemsByName request, IList<BaseItem> items)
{
throw new NotImplementedException();
}
diff --git a/MediaBrowser.Api/UserLibrary/PersonsService.cs b/MediaBrowser.Api/UserLibrary/PersonsService.cs
index 21f416025..9417447d8 100644
--- a/MediaBrowser.Api/UserLibrary/PersonsService.cs
+++ b/MediaBrowser.Api/UserLibrary/PersonsService.cs
@@ -96,15 +96,13 @@ namespace MediaBrowser.Api.UserLibrary
/// <param name="request">The request.</param>
/// <param name="items">The items.</param>
/// <returns>IEnumerable{Tuple{System.StringFunc{System.Int32}}}.</returns>
- protected override IEnumerable<BaseItem> GetAllItems(GetItemsByName request, IEnumerable<BaseItem> items)
+ protected override IEnumerable<BaseItem> GetAllItems(GetItemsByName request, IList<BaseItem> items)
{
var inputPersonTypes = ((GetPersons)request).PersonTypes;
var personTypes = string.IsNullOrEmpty(inputPersonTypes) ? new string[] { } : inputPersonTypes.Split(',');
- var itemsList = items.ToList();
-
// Either get all people, or all people filtered by a specific person type
- var allPeople = GetAllPeople(itemsList, personTypes);
+ var allPeople = GetAllPeople(items, personTypes);
return allPeople
.Select(i => i.Name)
@@ -132,13 +130,13 @@ namespace MediaBrowser.Api.UserLibrary
/// <param name="itemsList">The items list.</param>
/// <param name="personTypes">The person types.</param>
/// <returns>IEnumerable{PersonInfo}.</returns>
- private IEnumerable<PersonInfo> GetAllPeople(IEnumerable<BaseItem> itemsList, IEnumerable<string> personTypes)
+ private IEnumerable<PersonInfo> GetAllPeople(IList<BaseItem> itemsList, string[] personTypes)
{
- var allIds = itemsList.Select(i => i.Id).ToList();
+ var allIds = itemsList.Select(i => i.Id).ToArray();
var allPeople = LibraryManager.GetPeople(new InternalPeopleQuery
{
- PersonTypes = personTypes.ToList()
+ PersonTypes = personTypes
});
return allPeople.Where(i => allIds.Contains(i.ItemId)).OrderBy(p => p.SortOrder ?? int.MaxValue).ThenBy(p => p.Type);
diff --git a/MediaBrowser.Api/UserLibrary/PlaystateService.cs b/MediaBrowser.Api/UserLibrary/PlaystateService.cs
deleted file mode 100644
index 98b4a5d5d..000000000
--- a/MediaBrowser.Api/UserLibrary/PlaystateService.cs
+++ /dev/null
@@ -1,451 +0,0 @@
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.Net;
-using MediaBrowser.Controller.Session;
-using MediaBrowser.Model.Dto;
-using MediaBrowser.Model.Session;
-using System;
-using System.Globalization;
-using System.Linq;
-using System.Threading.Tasks;
-using MediaBrowser.Model.Services;
-
-namespace MediaBrowser.Api.UserLibrary
-{
- /// <summary>
- /// Class MarkPlayedItem
- /// </summary>
- [Route("/Users/{UserId}/PlayedItems/{Id}", "POST", Summary = "Marks an item as played")]
- public class MarkPlayedItem : IReturn<UserItemDataDto>
- {
- /// <summary>
- /// Gets or sets the user id.
- /// </summary>
- /// <value>The user id.</value>
- [ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
- public string UserId { get; set; }
-
- [ApiMember(Name = "DatePlayed", Description = "The date the item was played (if any). Format = yyyyMMddHHmmss", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")]
- public string DatePlayed { get; set; }
-
- /// <summary>
- /// Gets or sets the id.
- /// </summary>
- /// <value>The id.</value>
- [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
- public string Id { get; set; }
- }
-
- /// <summary>
- /// Class MarkUnplayedItem
- /// </summary>
- [Route("/Users/{UserId}/PlayedItems/{Id}", "DELETE", Summary = "Marks an item as unplayed")]
- public class MarkUnplayedItem : IReturn<UserItemDataDto>
- {
- /// <summary>
- /// Gets or sets the user id.
- /// </summary>
- /// <value>The user id.</value>
- [ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "DELETE")]
- public string UserId { get; set; }
-
- /// <summary>
- /// Gets or sets the id.
- /// </summary>
- /// <value>The id.</value>
- [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "DELETE")]
- public string Id { get; set; }
- }
-
- [Route("/Sessions/Playing", "POST", Summary = "Reports playback has started within a session")]
- public class ReportPlaybackStart : PlaybackStartInfo, IReturnVoid
- {
- }
-
- [Route("/Sessions/Playing/Progress", "POST", Summary = "Reports playback progress within a session")]
- public class ReportPlaybackProgress : PlaybackProgressInfo, IReturnVoid
- {
- }
-
- [Route("/Sessions/Playing/Ping", "POST", Summary = "Pings a playback session")]
- public class PingPlaybackSession : IReturnVoid
- {
- [ApiMember(Name = "PlaySessionId", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")]
- public string PlaySessionId { get; set; }
- }
-
- [Route("/Sessions/Playing/Stopped", "POST", Summary = "Reports playback has stopped within a session")]
- public class ReportPlaybackStopped : PlaybackStopInfo, IReturnVoid
- {
- }
-
- /// <summary>
- /// Class OnPlaybackStart
- /// </summary>
- [Route("/Users/{UserId}/PlayingItems/{Id}", "POST", Summary = "Reports that a user has begun playing an item")]
- public class OnPlaybackStart : IReturnVoid
- {
- /// <summary>
- /// Gets or sets the user id.
- /// </summary>
- /// <value>The user id.</value>
- [ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
- public string UserId { get; set; }
-
- /// <summary>
- /// Gets or sets the id.
- /// </summary>
- /// <value>The id.</value>
- [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
- public string Id { get; set; }
-
- [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; }
-
- [ApiMember(Name = "AudioStreamIndex", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "POST")]
- public int? AudioStreamIndex { get; set; }
-
- [ApiMember(Name = "SubtitleStreamIndex", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "POST")]
- public int? SubtitleStreamIndex { get; set; }
-
- [ApiMember(Name = "PlayMethod", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")]
- public PlayMethod PlayMethod { get; set; }
-
- [ApiMember(Name = "LiveStreamId", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")]
- public string LiveStreamId { get; set; }
-
- [ApiMember(Name = "PlaySessionId", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")]
- public string PlaySessionId { get; set; }
- }
-
- /// <summary>
- /// Class OnPlaybackProgress
- /// </summary>
- [Route("/Users/{UserId}/PlayingItems/{Id}/Progress", "POST", Summary = "Reports a user's playback progress")]
- public class OnPlaybackProgress : IReturnVoid
- {
- /// <summary>
- /// Gets or sets the user id.
- /// </summary>
- /// <value>The user id.</value>
- [ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
- public string UserId { get; set; }
-
- /// <summary>
- /// Gets or sets the id.
- /// </summary>
- /// <value>The id.</value>
- [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
- public string Id { get; set; }
-
- [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 the position ticks.
- /// </summary>
- /// <value>The position ticks.</value>
- [ApiMember(Name = "PositionTicks", Description = "Optional. The current position, in ticks. 1 tick = 10000 ms", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "POST")]
- public long? PositionTicks { get; set; }
-
- [ApiMember(Name = "IsPaused", Description = "Indicates if the player is paused.", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "POST")]
- public bool IsPaused { get; set; }
-
- [ApiMember(Name = "IsMuted", Description = "Indicates if the player is muted.", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "POST")]
- public bool IsMuted { get; set; }
-
- [ApiMember(Name = "AudioStreamIndex", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "POST")]
- public int? AudioStreamIndex { get; set; }
-
- [ApiMember(Name = "SubtitleStreamIndex", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "POST")]
- public int? SubtitleStreamIndex { get; set; }
-
- [ApiMember(Name = "VolumeLevel", Description = "Scale of 0-100", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "POST")]
- public int? VolumeLevel { get; set; }
-
- [ApiMember(Name = "PlayMethod", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")]
- public PlayMethod PlayMethod { get; set; }
-
- [ApiMember(Name = "LiveStreamId", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")]
- public string LiveStreamId { get; set; }
-
- [ApiMember(Name = "PlaySessionId", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")]
- public string PlaySessionId { get; set; }
-
- [ApiMember(Name = "RepeatMode", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")]
- public RepeatMode RepeatMode { get; set; }
- }
-
- /// <summary>
- /// Class OnPlaybackStopped
- /// </summary>
- [Route("/Users/{UserId}/PlayingItems/{Id}", "DELETE", Summary = "Reports that a user has stopped playing an item")]
- public class OnPlaybackStopped : IReturnVoid
- {
- /// <summary>
- /// Gets or sets the user id.
- /// </summary>
- /// <value>The user id.</value>
- [ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "DELETE")]
- public string UserId { get; set; }
-
- /// <summary>
- /// Gets or sets the id.
- /// </summary>
- /// <value>The id.</value>
- [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "DELETE")]
- public string Id { get; set; }
-
- [ApiMember(Name = "MediaSourceId", Description = "The id of the MediaSource", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "DELETE")]
- public string MediaSourceId { get; set; }
-
- [ApiMember(Name = "NextMediaType", Description = "The next media type that will play", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "DELETE")]
- public string NextMediaType { get; set; }
-
- /// <summary>
- /// Gets or sets the position ticks.
- /// </summary>
- /// <value>The position ticks.</value>
- [ApiMember(Name = "PositionTicks", Description = "Optional. The position, in ticks, where playback stopped. 1 tick = 10000 ms", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "DELETE")]
- public long? PositionTicks { get; set; }
-
- [ApiMember(Name = "LiveStreamId", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")]
- public string LiveStreamId { get; set; }
-
- [ApiMember(Name = "PlaySessionId", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")]
- public string PlaySessionId { get; set; }
- }
-
- [Authenticated]
- public class PlaystateService : BaseApiService
- {
- private readonly IUserManager _userManager;
- private readonly IUserDataManager _userDataRepository;
- private readonly ILibraryManager _libraryManager;
- private readonly ISessionManager _sessionManager;
- private readonly ISessionContext _sessionContext;
- private readonly IAuthorizationContext _authContext;
-
- public PlaystateService(IUserManager userManager, IUserDataManager userDataRepository, ILibraryManager libraryManager, ISessionManager sessionManager, ISessionContext sessionContext, IAuthorizationContext authContext)
- {
- _userManager = userManager;
- _userDataRepository = userDataRepository;
- _libraryManager = libraryManager;
- _sessionManager = sessionManager;
- _sessionContext = sessionContext;
- _authContext = authContext;
- }
-
- /// <summary>
- /// Posts the specified request.
- /// </summary>
- /// <param name="request">The request.</param>
- public async Task<object> Post(MarkPlayedItem request)
- {
- var result = await MarkPlayed(request).ConfigureAwait(false);
-
- return ToOptimizedResult(result);
- }
-
- private async Task<UserItemDataDto> MarkPlayed(MarkPlayedItem request)
- {
- var user = _userManager.GetUserById(request.UserId);
-
- DateTime? datePlayed = null;
-
- if (!string.IsNullOrEmpty(request.DatePlayed))
- {
- datePlayed = DateTime.ParseExact(request.DatePlayed, "yyyyMMddHHmmss", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal);
- }
-
- var session = await GetSession(_sessionContext).ConfigureAwait(false);
-
- var dto = await UpdatePlayedStatus(user, request.Id, true, datePlayed).ConfigureAwait(false);
-
- foreach (var additionalUserInfo in session.AdditionalUsers)
- {
- var additionalUser = _userManager.GetUserById(additionalUserInfo.UserId);
-
- await UpdatePlayedStatus(additionalUser, request.Id, true, datePlayed).ConfigureAwait(false);
- }
-
- return dto;
- }
-
- private PlayMethod ValidatePlayMethod(PlayMethod method, string playSessionId)
- {
- if (method == PlayMethod.Transcode)
- {
- var job = string.IsNullOrWhiteSpace(playSessionId) ? null : ApiEntryPoint.Instance.GetTranscodingJob(playSessionId);
- if (job == null)
- {
- return PlayMethod.DirectPlay;
- }
- }
-
- return method;
- }
-
- /// <summary>
- /// Posts the specified request.
- /// </summary>
- /// <param name="request">The request.</param>
- public void Post(OnPlaybackStart request)
- {
- Post(new ReportPlaybackStart
- {
- CanSeek = request.CanSeek,
- ItemId = request.Id,
- MediaSourceId = request.MediaSourceId,
- AudioStreamIndex = request.AudioStreamIndex,
- SubtitleStreamIndex = request.SubtitleStreamIndex,
- PlayMethod = request.PlayMethod,
- PlaySessionId = request.PlaySessionId,
- LiveStreamId = request.LiveStreamId
- });
- }
-
- public void Post(ReportPlaybackStart request)
- {
- request.PlayMethod = ValidatePlayMethod(request.PlayMethod, request.PlaySessionId);
-
- request.SessionId = GetSession(_sessionContext).Result.Id;
-
- var task = _sessionManager.OnPlaybackStart(request);
-
- Task.WaitAll(task);
- }
-
- /// <summary>
- /// Posts the specified request.
- /// </summary>
- /// <param name="request">The request.</param>
- public void Post(OnPlaybackProgress request)
- {
- Post(new ReportPlaybackProgress
- {
- ItemId = request.Id,
- PositionTicks = request.PositionTicks,
- IsMuted = request.IsMuted,
- IsPaused = request.IsPaused,
- MediaSourceId = request.MediaSourceId,
- AudioStreamIndex = request.AudioStreamIndex,
- SubtitleStreamIndex = request.SubtitleStreamIndex,
- VolumeLevel = request.VolumeLevel,
- PlayMethod = request.PlayMethod,
- PlaySessionId = request.PlaySessionId,
- LiveStreamId = request.LiveStreamId,
- RepeatMode = request.RepeatMode
- });
- }
-
- public void Post(ReportPlaybackProgress request)
- {
- request.PlayMethod = ValidatePlayMethod(request.PlayMethod, request.PlaySessionId);
-
- request.SessionId = GetSession(_sessionContext).Result.Id;
-
- var task = _sessionManager.OnPlaybackProgress(request);
-
- Task.WaitAll(task);
- }
-
- public void Post(PingPlaybackSession request)
- {
- ApiEntryPoint.Instance.PingTranscodingJob(request.PlaySessionId, null);
- }
-
- /// <summary>
- /// Posts the specified request.
- /// </summary>
- /// <param name="request">The request.</param>
- public void Delete(OnPlaybackStopped request)
- {
- Post(new ReportPlaybackStopped
- {
- ItemId = request.Id,
- PositionTicks = request.PositionTicks,
- MediaSourceId = request.MediaSourceId,
- PlaySessionId = request.PlaySessionId,
- LiveStreamId = request.LiveStreamId,
- NextMediaType = request.NextMediaType
- });
- }
-
- public void Post(ReportPlaybackStopped request)
- {
- Logger.Debug("ReportPlaybackStopped PlaySessionId: {0}", request.PlaySessionId ?? string.Empty);
-
- if (!string.IsNullOrWhiteSpace(request.PlaySessionId))
- {
- ApiEntryPoint.Instance.KillTranscodingJobs(_authContext.GetAuthorizationInfo(Request).DeviceId, request.PlaySessionId, s => true);
- }
-
- request.SessionId = GetSession(_sessionContext).Result.Id;
-
- var task = _sessionManager.OnPlaybackStopped(request);
-
- Task.WaitAll(task);
- }
-
- /// <summary>
- /// Deletes the specified request.
- /// </summary>
- /// <param name="request">The request.</param>
- public object Delete(MarkUnplayedItem request)
- {
- var task = MarkUnplayed(request);
-
- return ToOptimizedResult(task.Result);
- }
-
- private async Task<UserItemDataDto> MarkUnplayed(MarkUnplayedItem request)
- {
- var user = _userManager.GetUserById(request.UserId);
-
- var session = await GetSession(_sessionContext).ConfigureAwait(false);
-
- var dto = await UpdatePlayedStatus(user, request.Id, false, null).ConfigureAwait(false);
-
- foreach (var additionalUserInfo in session.AdditionalUsers)
- {
- var additionalUser = _userManager.GetUserById(additionalUserInfo.UserId);
-
- await UpdatePlayedStatus(additionalUser, request.Id, false, null).ConfigureAwait(false);
- }
-
- return dto;
- }
-
- /// <summary>
- /// Updates the played status.
- /// </summary>
- /// <param name="user">The user.</param>
- /// <param name="itemId">The item id.</param>
- /// <param name="wasPlayed">if set to <c>true</c> [was played].</param>
- /// <param name="datePlayed">The date played.</param>
- /// <returns>Task.</returns>
- private async Task<UserItemDataDto> UpdatePlayedStatus(User user, string itemId, bool wasPlayed, DateTime? datePlayed)
- {
- var item = _libraryManager.GetItemById(itemId);
-
- if (wasPlayed)
- {
- await item.MarkPlayed(user, datePlayed, true).ConfigureAwait(false);
- }
- else
- {
- await item.MarkUnplayed(user).ConfigureAwait(false);
- }
-
- return _userDataRepository.GetUserDataDto(item, user);
- }
- }
-} \ No newline at end of file
diff --git a/MediaBrowser.Api/UserLibrary/StudiosService.cs b/MediaBrowser.Api/UserLibrary/StudiosService.cs
index 7ac1264e8..f10cccbb1 100644
--- a/MediaBrowser.Api/UserLibrary/StudiosService.cs
+++ b/MediaBrowser.Api/UserLibrary/StudiosService.cs
@@ -103,11 +103,9 @@ namespace MediaBrowser.Api.UserLibrary
/// <param name="request">The request.</param>
/// <param name="items">The items.</param>
/// <returns>IEnumerable{Tuple{System.StringFunc{System.Int32}}}.</returns>
- protected override IEnumerable<BaseItem> GetAllItems(GetItemsByName request, IEnumerable<BaseItem> items)
+ protected override IEnumerable<BaseItem> GetAllItems(GetItemsByName request, IList<BaseItem> items)
{
- var itemsList = items.Where(i => i.Studios != null).ToList();
-
- return itemsList
+ return items
.SelectMany(i => i.Studios)
.DistinctNames()
.Select(name => LibraryManager.GetStudio(name));
diff --git a/MediaBrowser.Api/UserLibrary/UserLibraryService.cs b/MediaBrowser.Api/UserLibrary/UserLibraryService.cs
index 4bb3de882..1bbc740c0 100644
--- a/MediaBrowser.Api/UserLibrary/UserLibraryService.cs
+++ b/MediaBrowser.Api/UserLibrary/UserLibraryService.cs
@@ -12,7 +12,6 @@ using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Controller.Entities.Audio;
-using MediaBrowser.Controller.IO;
using MediaBrowser.Model.IO;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Services;
@@ -58,7 +57,7 @@ namespace MediaBrowser.Api.UserLibrary
/// Class GetIntros
/// </summary>
[Route("/Users/{UserId}/Items/{Id}/Intros", "GET", Summary = "Gets intros to play before the main media item plays")]
- public class GetIntros : IReturn<ItemsResult>
+ public class GetIntros : IReturn<QueryResult<BaseItemDto>>
{
/// <summary>
/// Gets or sets the user id.
@@ -170,7 +169,7 @@ namespace MediaBrowser.Api.UserLibrary
/// Class GetLocalTrailers
/// </summary>
[Route("/Users/{UserId}/Items/{Id}/LocalTrailers", "GET", Summary = "Gets local trailers for an item")]
- public class GetLocalTrailers : IReturn<List<BaseItemDto>>
+ public class GetLocalTrailers : IReturn<BaseItemDto[]>
{
/// <summary>
/// Gets or sets the user id.
@@ -191,7 +190,7 @@ namespace MediaBrowser.Api.UserLibrary
/// Class GetSpecialFeatures
/// </summary>
[Route("/Users/{UserId}/Items/{Id}/SpecialFeatures", "GET", Summary = "Gets special features for an item")]
- public class GetSpecialFeatures : IReturn<List<BaseItemDto>>
+ public class GetSpecialFeatures : IReturn<BaseItemDto[]>
{
/// <summary>
/// Gets or sets the user id.
@@ -209,7 +208,7 @@ namespace MediaBrowser.Api.UserLibrary
}
[Route("/Users/{UserId}/Items/Latest", "GET", Summary = "Gets latest media")]
- public class GetLatestMedia : IReturn<List<BaseItemDto>>, IHasDtoOptions
+ public class GetLatestMedia : IReturn<BaseItemDto[]>, IHasDtoOptions
{
/// <summary>
/// Gets or sets the user id.
@@ -312,7 +311,7 @@ namespace MediaBrowser.Api.UserLibrary
var list = _userViewManager.GetLatestItems(new LatestItemsQuery
{
GroupItems = request.GroupItems,
- IncludeItemTypes = (request.IncludeItemTypes ?? string.Empty).Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).ToArray(),
+ IncludeItemTypes = ApiEntryPoint.Split(request.IncludeItemTypes, ',', true),
IsPlayed = request.IsPlayed,
Limit = request.Limit,
ParentId = request.ParentId,
@@ -337,10 +336,10 @@ namespace MediaBrowser.Api.UserLibrary
return dto;
});
- return ToOptimizedResult(dtos.ToList());
+ return ToOptimizedResult(dtos.ToArray());
}
- private List<BaseItemDto> GetAsync(GetSpecialFeatures request)
+ private BaseItemDto[] GetAsync(GetSpecialFeatures request)
{
var user = _userManager.GetUserById(request.UserId);
@@ -363,7 +362,7 @@ namespace MediaBrowser.Api.UserLibrary
.Where(i => i.ParentIndexNumber.HasValue && i.ParentIndexNumber.Value == 0)
.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, currentUser));
- return dtos.ToList();
+ return dtos.ToArray();
}
var movie = item as IHasSpecialFeatures;
@@ -378,10 +377,10 @@ namespace MediaBrowser.Api.UserLibrary
.OrderBy(i => i.SortName)
.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user, item));
- return dtos.ToList();
+ return dtos.ToArray();
}
- return new List<BaseItemDto>();
+ return new BaseItemDto[] { };
}
/// <summary>
@@ -395,19 +394,24 @@ namespace MediaBrowser.Api.UserLibrary
var item = string.IsNullOrEmpty(request.Id) ? user.RootFolder : _libraryManager.GetItemById(request.Id);
- var trailerIds = new List<Guid>();
+ List<Guid> trailerIds = null;
var hasTrailers = item as IHasTrailers;
if (hasTrailers != null)
{
trailerIds = hasTrailers.GetTrailerIds();
}
+ else
+ {
+ trailerIds = new List<Guid>();
+ }
var dtoOptions = GetDtoOptions(_authContext, request);
var dtos = trailerIds
.Select(_libraryManager.GetItemById)
- .Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user, item));
+ .Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user, item))
+ .ToArray();
return ToOptimizedSerializedResultUsingCache(dtos);
}
@@ -486,10 +490,9 @@ namespace MediaBrowser.Api.UserLibrary
var dtoOptions = GetDtoOptions(_authContext, request);
- var dtos = items.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user))
- .ToArray();
+ var dtos = items.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user)).ToArray();
- var result = new ItemsResult
+ var result = new QueryResult<BaseItemDto>
{
Items = dtos,
TotalRecordCount = dtos.Length
@@ -502,9 +505,9 @@ namespace MediaBrowser.Api.UserLibrary
/// Posts the specified request.
/// </summary>
/// <param name="request">The request.</param>
- public async Task<object> Post(MarkFavoriteItem request)
+ public object Post(MarkFavoriteItem request)
{
- var dto = await MarkFavorite(request.UserId, request.Id, true).ConfigureAwait(false);
+ var dto = MarkFavorite(request.UserId, request.Id, true);
return ToOptimizedResult(dto);
}
@@ -515,7 +518,7 @@ namespace MediaBrowser.Api.UserLibrary
/// <param name="request">The request.</param>
public object Delete(UnmarkFavoriteItem request)
{
- var dto = MarkFavorite(request.UserId, request.Id, false).Result;
+ var dto = MarkFavorite(request.UserId, request.Id, false);
return ToOptimizedResult(dto);
}
@@ -526,8 +529,7 @@ namespace MediaBrowser.Api.UserLibrary
/// <param name="userId">The user id.</param>
/// <param name="itemId">The item id.</param>
/// <param name="isFavorite">if set to <c>true</c> [is favorite].</param>
- /// <returns>Task{UserItemDataDto}.</returns>
- private async Task<UserItemDataDto> MarkFavorite(string userId, string itemId, bool isFavorite)
+ private UserItemDataDto MarkFavorite(string userId, string itemId, bool isFavorite)
{
var user = _userManager.GetUserById(userId);
@@ -539,7 +541,7 @@ namespace MediaBrowser.Api.UserLibrary
// Set favorite status
data.IsFavorite = isFavorite;
- await _userDataRepository.SaveUserData(user.Id, item, data, UserDataSaveReason.UpdateUserRating, CancellationToken.None).ConfigureAwait(false);
+ _userDataRepository.SaveUserData(user.Id, item, data, UserDataSaveReason.UpdateUserRating, CancellationToken.None);
return _userDataRepository.GetUserDataDto(item, user);
}
@@ -550,7 +552,7 @@ namespace MediaBrowser.Api.UserLibrary
/// <param name="request">The request.</param>
public object Delete(DeleteUserItemRating request)
{
- var dto = UpdateUserItemRating(request.UserId, request.Id, null).Result;
+ var dto = UpdateUserItemRating(request.UserId, request.Id, null);
return ToOptimizedResult(dto);
}
@@ -559,9 +561,9 @@ namespace MediaBrowser.Api.UserLibrary
/// Posts the specified request.
/// </summary>
/// <param name="request">The request.</param>
- public async Task<object> Post(UpdateUserItemRating request)
+ public object Post(UpdateUserItemRating request)
{
- var dto = await UpdateUserItemRating(request.UserId, request.Id, request.Likes).ConfigureAwait(false);
+ var dto = UpdateUserItemRating(request.UserId, request.Id, request.Likes);
return ToOptimizedResult(dto);
}
@@ -572,8 +574,7 @@ namespace MediaBrowser.Api.UserLibrary
/// <param name="userId">The user id.</param>
/// <param name="itemId">The item id.</param>
/// <param name="likes">if set to <c>true</c> [likes].</param>
- /// <returns>Task{UserItemDataDto}.</returns>
- private async Task<UserItemDataDto> UpdateUserItemRating(string userId, string itemId, bool? likes)
+ private UserItemDataDto UpdateUserItemRating(string userId, string itemId, bool? likes)
{
var user = _userManager.GetUserById(userId);
@@ -584,7 +585,7 @@ namespace MediaBrowser.Api.UserLibrary
data.Likes = likes;
- await _userDataRepository.SaveUserData(user.Id, item, data, UserDataSaveReason.UpdateUserRating, CancellationToken.None).ConfigureAwait(false);
+ _userDataRepository.SaveUserData(user.Id, item, data, UserDataSaveReason.UpdateUserRating, CancellationToken.None);
return _userDataRepository.GetUserDataDto(item, user);
}
diff --git a/MediaBrowser.Api/UserLibrary/UserViewsService.cs b/MediaBrowser.Api/UserLibrary/UserViewsService.cs
index 3ed5166a4..096157e47 100644
--- a/MediaBrowser.Api/UserLibrary/UserViewsService.cs
+++ b/MediaBrowser.Api/UserLibrary/UserViewsService.cs
@@ -12,6 +12,7 @@ using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Controller.Net;
using MediaBrowser.Model.Services;
+using MediaBrowser.Model.Extensions;
namespace MediaBrowser.Api.UserLibrary
{
@@ -32,7 +33,7 @@ namespace MediaBrowser.Api.UserLibrary
}
[Route("/Users/{UserId}/GroupingOptions", "GET")]
- public class GetGroupingOptions : IReturn<List<SpecialViewOption>>
+ public class GetGroupingOptions : IReturn<SpecialViewOption[]>
{
/// <summary>
/// Gets or sets the user id.
@@ -84,10 +85,13 @@ namespace MediaBrowser.Api.UserLibrary
var folders = await _userViewManager.GetUserViews(query, CancellationToken.None).ConfigureAwait(false);
var dtoOptions = GetDtoOptions(_authContext, request);
- dtoOptions.Fields.Add(ItemFields.PrimaryImageAspectRatio);
- dtoOptions.Fields.Add(ItemFields.DisplayPreferencesId);
- dtoOptions.Fields.Remove(ItemFields.SyncInfo);
- dtoOptions.Fields.Remove(ItemFields.BasicSyncInfo);
+ var fields = dtoOptions.Fields.ToList();
+
+ fields.Add(ItemFields.PrimaryImageAspectRatio);
+ fields.Add(ItemFields.DisplayPreferencesId);
+ fields.Remove(ItemFields.SyncInfo);
+ fields.Remove(ItemFields.BasicSyncInfo);
+ dtoOptions.Fields = fields.ToArray(fields.Count);
var user = _userManager.GetUserById(request.UserId);
@@ -107,13 +111,10 @@ namespace MediaBrowser.Api.UserLibrary
{
var user = _userManager.GetUserById(request.UserId);
- var views = user.RootFolder
+ var list = user.RootFolder
.GetChildren(user, true)
.OfType<Folder>()
.Where(UserView.IsEligibleForGrouping)
- .ToList();
-
- var list = views
.Select(i => new SpecialViewOption
{
Name = i.Name,
@@ -121,7 +122,7 @@ namespace MediaBrowser.Api.UserLibrary
})
.OrderBy(i => i.Name)
- .ToList();
+ .ToArray();
return ToOptimizedResult(list);
}
diff --git a/MediaBrowser.Api/UserLibrary/YearsService.cs b/MediaBrowser.Api/UserLibrary/YearsService.cs
index 1059b72cb..db622a9b3 100644
--- a/MediaBrowser.Api/UserLibrary/YearsService.cs
+++ b/MediaBrowser.Api/UserLibrary/YearsService.cs
@@ -96,11 +96,9 @@ namespace MediaBrowser.Api.UserLibrary
/// <param name="request">The request.</param>
/// <param name="items">The items.</param>
/// <returns>IEnumerable{Tuple{System.StringFunc{System.Int32}}}.</returns>
- protected override IEnumerable<BaseItem> GetAllItems(GetItemsByName request, IEnumerable<BaseItem> items)
+ protected override IEnumerable<BaseItem> GetAllItems(GetItemsByName request, IList<BaseItem> items)
{
- var itemsList = items.Where(i => i.ProductionYear != null).ToList();
-
- return itemsList
+ return items
.Select(i => i.ProductionYear ?? 0)
.Where(i => i > 0)
.Distinct()
diff --git a/MediaBrowser.Api/UserService.cs b/MediaBrowser.Api/UserService.cs
index 49b7f6c15..512356b43 100644
--- a/MediaBrowser.Api/UserService.cs
+++ b/MediaBrowser.Api/UserService.cs
@@ -22,7 +22,7 @@ namespace MediaBrowser.Api
/// </summary>
[Route("/Users", "GET", Summary = "Gets a list of users")]
[Authenticated]
- public class GetUsers : IReturn<List<UserDto>>
+ public class GetUsers : IReturn<UserDto[]>
{
[ApiMember(Name = "IsHidden", Description = "Optional filter by IsHidden=true or false", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
public bool? IsHidden { get; set; }
@@ -35,7 +35,7 @@ namespace MediaBrowser.Api
}
[Route("/Users/Public", "GET", Summary = "Gets a list of publicly visible users for display on a login screen.")]
- public class GetPublicUsers : IReturn<List<UserDto>>
+ public class GetPublicUsers : IReturn<UserDto[]>
{
}
@@ -329,7 +329,7 @@ namespace MediaBrowser.Api
var result = users
.OrderBy(u => u.Name)
.Select(i => _userManager.GetUserDto(i, Request.RemoteIp))
- .ToList();
+ .ToArray();
return ToOptimizedResult(result);
}
@@ -387,7 +387,7 @@ namespace MediaBrowser.Api
throw new ResourceNotFoundException("User not found");
}
- await _sessionMananger.RevokeUserTokens(user.Id.ToString("N"), null).ConfigureAwait(false);
+ _sessionMananger.RevokeUserTokens(user.Id.ToString("N"), null);
await _userManager.DeleteUser(user).ConfigureAwait(false);
}
@@ -455,7 +455,7 @@ namespace MediaBrowser.Api
if (request.ResetPassword)
{
- await _userManager.ResetPassword(user).ConfigureAwait(false);
+ _userManager.ResetPassword(user);
}
else
{
@@ -466,24 +466,18 @@ namespace MediaBrowser.Api
throw new ArgumentException("Invalid user or password entered.");
}
- await _userManager.ChangePassword(user, request.NewPassword).ConfigureAwait(false);
+ _userManager.ChangePassword(user, request.NewPassword);
var currentToken = _authContext.GetAuthorizationInfo(Request).Token;
- await _sessionMananger.RevokeUserTokens(user.Id.ToString("N"), currentToken).ConfigureAwait(false);
+ _sessionMananger.RevokeUserTokens(user.Id.ToString("N"), currentToken);
}
}
public void Post(UpdateUserEasyPassword request)
{
- var task = PostAsync(request);
- Task.WaitAll(task);
- }
-
- public async Task PostAsync(UpdateUserEasyPassword request)
- {
AssertCanUpdateUser(_authContext, _userManager, request.Id, true);
-
+
var user = _userManager.GetUserById(request.Id);
if (user == null)
@@ -493,11 +487,11 @@ namespace MediaBrowser.Api
if (request.ResetPassword)
{
- await _userManager.ResetEasyPassword(user).ConfigureAwait(false);
+ _userManager.ResetEasyPassword(user);
}
else
{
- await _userManager.ChangeEasyPassword(user, request.NewPassword).ConfigureAwait(false);
+ _userManager.ChangeEasyPassword(user, request.NewPassword);
}
}
@@ -507,13 +501,6 @@ namespace MediaBrowser.Api
/// <param name="request">The request.</param>
public void Post(UpdateUser request)
{
- var task = PostAsync(request);
-
- Task.WaitAll(task);
- }
-
- public async Task PostAsync(UpdateUser request)
- {
// We need to parse this manually because we told service stack not to with IRequiresRequestStream
// https://code.google.com/p/servicestack/source/browse/trunk/Common/ServiceStack.Text/ServiceStack.Text/Controller/PathInfo.cs
var id = GetPathValue(1);
@@ -524,13 +511,18 @@ namespace MediaBrowser.Api
var user = _userManager.GetUserById(id);
- var task = string.Equals(user.Name, dtoUser.Name, StringComparison.Ordinal) ?
- _userManager.UpdateUser(user) :
- _userManager.RenameUser(user, dtoUser.Name);
+ if (string.Equals(user.Name, dtoUser.Name, StringComparison.Ordinal))
+ {
+ _userManager.UpdateUser(user);
+ }
+ else
+ {
+ var task = _userManager.RenameUser(user, dtoUser.Name);
- await task.ConfigureAwait(false);
+ Task.WaitAll(task);
+ }
- await _userManager.UpdateConfiguration(dtoUser.Id, dtoUser.Configuration);
+ _userManager.UpdateConfiguration(dtoUser.Id, dtoUser.Configuration);
}
/// <summary>
@@ -570,21 +562,14 @@ namespace MediaBrowser.Api
{
AssertCanUpdateUser(_authContext, _userManager, request.Id, false);
- var task = _userManager.UpdateConfiguration(request.Id, request);
+ _userManager.UpdateConfiguration(request.Id, request);
- Task.WaitAll(task);
}
public void Post(UpdateUserPolicy request)
{
- var task = UpdateUserPolicy(request);
- Task.WaitAll(task);
- }
-
- private async Task UpdateUserPolicy(UpdateUserPolicy request)
- {
var user = _userManager.GetUserById(request.Id);
-
+
// If removing admin access
if (!request.IsAdministrator && user.Policy.IsAdministrator)
{
@@ -609,10 +594,10 @@ namespace MediaBrowser.Api
}
var currentToken = _authContext.GetAuthorizationInfo(Request).Token;
- await _sessionMananger.RevokeUserTokens(user.Id.ToString("N"), currentToken).ConfigureAwait(false);
+ _sessionMananger.RevokeUserTokens(user.Id.ToString("N"), currentToken);
}
- await _userManager.UpdateUserPolicy(request.Id, request).ConfigureAwait(false);
+ _userManager.UpdateUserPolicy(request.Id, request);
}
}
}
diff --git a/MediaBrowser.Api/VideosService.cs b/MediaBrowser.Api/VideosService.cs
index 729b50c1f..3bd0497f7 100644
--- a/MediaBrowser.Api/VideosService.cs
+++ b/MediaBrowser.Api/VideosService.cs
@@ -19,7 +19,7 @@ namespace MediaBrowser.Api
{
[Route("/Videos/{Id}/AdditionalParts", "GET", Summary = "Gets additional parts for a video.")]
[Authenticated]
- public class GetAdditionalParts : IReturn<ItemsResult>
+ public class GetAdditionalParts : IReturn<QueryResult<BaseItemDto>>
{
[ApiMember(Name = "UserId", Description = "Optional. Filter by user id, and attach user data", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
public string UserId { get; set; }
@@ -99,7 +99,7 @@ namespace MediaBrowser.Api
items = new BaseItemDto[] { };
}
- var result = new ItemsResult
+ var result = new QueryResult<BaseItemDto>
{
Items = items,
TotalRecordCount = items.Length
@@ -126,7 +126,7 @@ namespace MediaBrowser.Api
await link.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false);
}
- video.LinkedAlternateVersions.Clear();
+ video.LinkedAlternateVersions = Video.EmptyLinkedChildArray;
await video.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false);
}
@@ -140,7 +140,6 @@ namespace MediaBrowser.Api
public async Task PostAsync(MergeVersions request)
{
var items = request.Ids.Split(',')
- .Select(i => new Guid(i))
.Select(i => _libraryManager.GetItemById(i))
.OfType<Video>()
.ToList();
@@ -185,19 +184,23 @@ namespace MediaBrowser.Api
}).First();
}
+ var list = primaryVersion.LinkedAlternateVersions.ToList();
+
foreach (var item in items.Where(i => i.Id != primaryVersion.Id))
{
item.PrimaryVersionId = primaryVersion.Id.ToString("N");
await item.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false);
- primaryVersion.LinkedAlternateVersions.Add(new LinkedChild
+ list.Add(new LinkedChild
{
Path = item.Path,
ItemId = item.Id
});
}
+ primaryVersion.LinkedAlternateVersions = list.ToArray();
+
await primaryVersion.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false);
}
}
diff --git a/MediaBrowser.Common/Net/HttpResponseInfo.cs b/MediaBrowser.Common/Net/HttpResponseInfo.cs
index ed941a447..0d7fb69cb 100644
--- a/MediaBrowser.Common/Net/HttpResponseInfo.cs
+++ b/MediaBrowser.Common/Net/HttpResponseInfo.cs
@@ -70,6 +70,7 @@ namespace MediaBrowser.Common.Net
{
_disposable.Dispose();
}
+ GC.SuppressFinalize(this);
}
}
}
diff --git a/MediaBrowser.Common/Net/IHttpClient.cs b/MediaBrowser.Common/Net/IHttpClient.cs
index 4eabbc803..15257715f 100644
--- a/MediaBrowser.Common/Net/IHttpClient.cs
+++ b/MediaBrowser.Common/Net/IHttpClient.cs
@@ -9,7 +9,7 @@ namespace MediaBrowser.Common.Net
/// <summary>
/// Interface IHttpClient
/// </summary>
- public interface IHttpClient : IDisposable
+ public interface IHttpClient
{
/// <summary>
/// Gets the response.
diff --git a/MediaBrowser.Common/Plugins/BasePlugin.cs b/MediaBrowser.Common/Plugins/BasePlugin.cs
index 95e076096..73be04ac8 100644
--- a/MediaBrowser.Common/Plugins/BasePlugin.cs
+++ b/MediaBrowser.Common/Plugins/BasePlugin.cs
@@ -55,11 +55,15 @@ namespace MediaBrowser.Common.Plugins
get { return typeof(TConfigurationType); }
}
- public void SetAttributes(string assemblyFilePath, string assemblyFileName, Version assemblyVersion, Guid assemblyId)
+ public void SetAttributes(string assemblyFilePath, string assemblyFileName, Version assemblyVersion)
{
AssemblyFilePath = assemblyFilePath;
AssemblyFileName = assemblyFileName;
Version = assemblyVersion;
+ }
+
+ public void SetId(Guid assemblyId)
+ {
Id = assemblyId;
}
@@ -78,7 +82,7 @@ namespace MediaBrowser.Common.Plugins
/// Gets the unique id.
/// </summary>
/// <value>The unique id.</value>
- public Guid Id { get; private set; }
+ public virtual Guid Id { get; private set; }
/// <summary>
/// Gets the plugin version
@@ -284,6 +288,7 @@ namespace MediaBrowser.Common.Plugins
public interface IPluginAssembly
{
- void SetAttributes(string assemblyFilePath, string assemblyFileName, Version assemblyVersion, Guid assemblyId);
+ void SetAttributes(string assemblyFilePath, string assemblyFileName, Version assemblyVersion);
+ void SetId(Guid assemblyId);
}
}
diff --git a/MediaBrowser.Common/Progress/ActionableProgress.cs b/MediaBrowser.Common/Progress/ActionableProgress.cs
index 503f3f407..5b318c6a7 100644
--- a/MediaBrowser.Common/Progress/ActionableProgress.cs
+++ b/MediaBrowser.Common/Progress/ActionableProgress.cs
@@ -30,6 +30,7 @@ namespace MediaBrowser.Common.Progress
public void Dispose()
{
Dispose(true);
+ GC.SuppressFinalize(this);
}
/// <summary>
diff --git a/MediaBrowser.Common/Updates/IInstallationManager.cs b/MediaBrowser.Common/Updates/IInstallationManager.cs
index 636526567..dab38b27c 100644
--- a/MediaBrowser.Common/Updates/IInstallationManager.cs
+++ b/MediaBrowser.Common/Updates/IInstallationManager.cs
@@ -48,7 +48,7 @@ namespace MediaBrowser.Common.Updates
/// <param name="packageType">Type of the package.</param>
/// <param name="applicationVersion">The application version.</param>
/// <returns>Task{List{PackageInfo}}.</returns>
- Task<IEnumerable<PackageInfo>> GetAvailablePackages(CancellationToken cancellationToken,
+ Task<List<PackageInfo>> GetAvailablePackages(CancellationToken cancellationToken,
bool withRegistration = true,
string packageType = null,
Version applicationVersion = null);
@@ -58,7 +58,7 @@ namespace MediaBrowser.Common.Updates
/// </summary>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task{List{PackageInfo}}.</returns>
- Task<IEnumerable<PackageInfo>> GetAvailablePackagesWithoutRegistrationInfo(CancellationToken cancellationToken);
+ Task<List<PackageInfo>> GetAvailablePackagesWithoutRegistrationInfo(CancellationToken cancellationToken);
/// <summary>
/// Gets the package.
diff --git a/MediaBrowser.Controller/Channels/Channel.cs b/MediaBrowser.Controller/Channels/Channel.cs
index c6e750a0c..54faa1443 100644
--- a/MediaBrowser.Controller/Channels/Channel.cs
+++ b/MediaBrowser.Controller/Channels/Channel.cs
@@ -58,8 +58,7 @@ namespace MediaBrowser.Controller.Channels
Limit = query.Limit,
StartIndex = query.StartIndex,
UserId = query.User.Id.ToString("N"),
- SortBy = query.SortBy,
- SortOrder = query.SortOrder
+ OrderBy = query.OrderBy
}, new SimpleProgress<double>(), CancellationToken.None).Result;
}
diff --git a/MediaBrowser.Controller/Channels/IChannelManager.cs b/MediaBrowser.Controller/Channels/IChannelManager.cs
index 824bdf8ff..46e55a21c 100644
--- a/MediaBrowser.Controller/Channels/IChannelManager.cs
+++ b/MediaBrowser.Controller/Channels/IChannelManager.cs
@@ -30,7 +30,7 @@ namespace MediaBrowser.Controller.Channels
/// Gets all channel features.
/// </summary>
/// <returns>IEnumerable{ChannelFeatures}.</returns>
- IEnumerable<ChannelFeatures> GetAllChannelFeatures();
+ ChannelFeatures[] GetAllChannelFeatures();
/// <summary>
/// Gets the channel.
diff --git a/MediaBrowser.Controller/Channels/InternalChannelFeatures.cs b/MediaBrowser.Controller/Channels/InternalChannelFeatures.cs
index 7d80d7e12..976808aad 100644
--- a/MediaBrowser.Controller/Channels/InternalChannelFeatures.cs
+++ b/MediaBrowser.Controller/Channels/InternalChannelFeatures.cs
@@ -58,13 +58,4 @@ namespace MediaBrowser.Controller.Channels
DefaultSortFields = new List<ChannelItemSortField>();
}
}
-
- public class ChannelDownloadException : Exception
- {
- public ChannelDownloadException(string message)
- : base(message)
- {
-
- }
- }
}
diff --git a/MediaBrowser.Controller/Chapters/IChapterManager.cs b/MediaBrowser.Controller/Chapters/IChapterManager.cs
index 05517ebcd..d1c190ab5 100644
--- a/MediaBrowser.Controller/Chapters/IChapterManager.cs
+++ b/MediaBrowser.Controller/Chapters/IChapterManager.cs
@@ -1,7 +1,5 @@
using System.Collections.Generic;
-using System.Threading;
using System.Threading.Tasks;
-using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Entities;
namespace MediaBrowser.Controller.Chapters
@@ -16,15 +14,11 @@ namespace MediaBrowser.Controller.Chapters
/// </summary>
/// <param name="itemId">The item identifier.</param>
/// <returns>List{ChapterInfo}.</returns>
- IEnumerable<ChapterInfo> GetChapters(string itemId);
+ List<ChapterInfo> GetChapters(string itemId);
/// <summary>
/// Saves the chapters.
/// </summary>
- /// <param name="itemId">The item identifier.</param>
- /// <param name="chapters">The chapters.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- Task SaveChapters(string itemId, List<ChapterInfo> chapters, CancellationToken cancellationToken);
+ void SaveChapters(string itemId, List<ChapterInfo> chapters);
}
}
diff --git a/MediaBrowser.Controller/Collections/CollectionCreationOptions.cs b/MediaBrowser.Controller/Collections/CollectionCreationOptions.cs
index 4a2d39066..7a387e319 100644
--- a/MediaBrowser.Controller/Collections/CollectionCreationOptions.cs
+++ b/MediaBrowser.Controller/Collections/CollectionCreationOptions.cs
@@ -14,14 +14,14 @@ namespace MediaBrowser.Controller.Collections
public Dictionary<string, string> ProviderIds { get; set; }
- public List<Guid> ItemIdList { get; set; }
- public List<Guid> UserIds { get; set; }
+ public string[] ItemIdList { get; set; }
+ public string[] UserIds { get; set; }
public CollectionCreationOptions()
{
ProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
- ItemIdList = new List<Guid>();
- UserIds = new List<Guid>();
+ ItemIdList = new string[] { };
+ UserIds = new string[] { };
}
}
}
diff --git a/MediaBrowser.Controller/Collections/ICollectionManager.cs b/MediaBrowser.Controller/Collections/ICollectionManager.cs
index 89e505579..d89843cc0 100644
--- a/MediaBrowser.Controller/Collections/ICollectionManager.cs
+++ b/MediaBrowser.Controller/Collections/ICollectionManager.cs
@@ -36,7 +36,7 @@ namespace MediaBrowser.Controller.Collections
/// <param name="collectionId">The collection identifier.</param>
/// <param name="itemIds">The item ids.</param>
/// <returns>Task.</returns>
- Task AddToCollection(Guid collectionId, IEnumerable<Guid> itemIds);
+ Task AddToCollection(Guid collectionId, IEnumerable<string> itemIds);
/// <summary>
/// Removes from collection.
@@ -44,6 +44,9 @@ namespace MediaBrowser.Controller.Collections
/// <param name="collectionId">The collection identifier.</param>
/// <param name="itemIds">The item ids.</param>
/// <returns>Task.</returns>
+ Task RemoveFromCollection(Guid collectionId, IEnumerable<string> itemIds);
+
+ Task AddToCollection(Guid collectionId, IEnumerable<Guid> itemIds);
Task RemoveFromCollection(Guid collectionId, IEnumerable<Guid> itemIds);
/// <summary>
diff --git a/MediaBrowser.Controller/Collections/ManualCollectionsFolder.cs b/MediaBrowser.Controller/Collections/ManualCollectionsFolder.cs
index 160a788f1..38d2611f0 100644
--- a/MediaBrowser.Controller/Collections/ManualCollectionsFolder.cs
+++ b/MediaBrowser.Controller/Collections/ManualCollectionsFolder.cs
@@ -8,7 +8,6 @@ namespace MediaBrowser.Controller.Collections
public ManualCollectionsFolder()
{
Name = "Collections";
- DisplayMediaType = "CollectionFolder";
}
public override bool IsHidden
diff --git a/MediaBrowser.Controller/Drawing/IImageEncoder.cs b/MediaBrowser.Controller/Drawing/IImageEncoder.cs
index 131d0bd9e..757448eb2 100644
--- a/MediaBrowser.Controller/Drawing/IImageEncoder.cs
+++ b/MediaBrowser.Controller/Drawing/IImageEncoder.cs
@@ -3,7 +3,7 @@ using MediaBrowser.Model.Drawing;
namespace MediaBrowser.Controller.Drawing
{
- public interface IImageEncoder : IDisposable
+ public interface IImageEncoder
{
/// <summary>
/// Gets the supported input formats.
diff --git a/MediaBrowser.Controller/Drawing/IImageProcessor.cs b/MediaBrowser.Controller/Drawing/IImageProcessor.cs
index 2832462a8..113f823f5 100644
--- a/MediaBrowser.Controller/Drawing/IImageProcessor.cs
+++ b/MediaBrowser.Controller/Drawing/IImageProcessor.cs
@@ -24,7 +24,7 @@ namespace MediaBrowser.Controller.Drawing
/// Gets the image enhancers.
/// </summary>
/// <value>The image enhancers.</value>
- IEnumerable<IImageEnhancer> ImageEnhancers { get; }
+ IImageEnhancer[] ImageEnhancers { get; }
/// <summary>
/// Gets the size of the image.
@@ -54,7 +54,7 @@ namespace MediaBrowser.Controller.Drawing
/// <param name="item">The item.</param>
/// <param name="imageType">Type of the image.</param>
/// <returns>IEnumerable{IImageEnhancer}.</returns>
- IEnumerable<IImageEnhancer> GetSupportedEnhancers(IHasImages item, ImageType imageType);
+ List<IImageEnhancer> GetSupportedEnhancers(IHasMetadata item, ImageType imageType);
/// <summary>
/// Gets the image cache tag.
@@ -62,7 +62,7 @@ namespace MediaBrowser.Controller.Drawing
/// <param name="item">The item.</param>
/// <param name="image">The image.</param>
/// <returns>Guid.</returns>
- string GetImageCacheTag(IHasImages item, ItemImageInfo image);
+ string GetImageCacheTag(IHasMetadata item, ItemImageInfo image);
/// <summary>
/// Gets the image cache tag.
@@ -71,7 +71,7 @@ namespace MediaBrowser.Controller.Drawing
/// <param name="image">The image.</param>
/// <param name="imageEnhancers">The image enhancers.</param>
/// <returns>Guid.</returns>
- string GetImageCacheTag(IHasImages item, ItemImageInfo image, List<IImageEnhancer> imageEnhancers);
+ string GetImageCacheTag(IHasMetadata item, ItemImageInfo image, List<IImageEnhancer> imageEnhancers);
/// <summary>
/// Processes the image.
@@ -95,7 +95,7 @@ namespace MediaBrowser.Controller.Drawing
/// <param name="imageType">Type of the image.</param>
/// <param name="imageIndex">Index of the image.</param>
/// <returns>Task{System.String}.</returns>
- Task<string> GetEnhancedImage(IHasImages item, ImageType imageType, int imageIndex);
+ Task<string> GetEnhancedImage(IHasMetadata item, ImageType imageType, int imageIndex);
/// <summary>
/// Gets the supported image output formats.
diff --git a/MediaBrowser.Controller/Drawing/ImageHelper.cs b/MediaBrowser.Controller/Drawing/ImageHelper.cs
index 54f2ff987..9452446a1 100644
--- a/MediaBrowser.Controller/Drawing/ImageHelper.cs
+++ b/MediaBrowser.Controller/Drawing/ImageHelper.cs
@@ -48,7 +48,7 @@ namespace MediaBrowser.Controller.Drawing
return new ImageSize(widthValue, height);
}
- private static double GetEstimatedAspectRatio(ImageType type, IHasImages item)
+ private static double GetEstimatedAspectRatio(ImageType type, IHasMetadata item)
{
switch (type)
{
diff --git a/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs b/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs
index cfb3a97ee..fac21c744 100644
--- a/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs
+++ b/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs
@@ -12,7 +12,7 @@ namespace MediaBrowser.Controller.Drawing
{
public string ItemId { get; set; }
public string ItemType { get; set; }
- public IHasImages Item { get; set; }
+ public IHasMetadata Item { get; set; }
public ItemImageInfo Image { get; set; }
diff --git a/MediaBrowser.Controller/Drawing/ImageProcessorExtensions.cs b/MediaBrowser.Controller/Drawing/ImageProcessorExtensions.cs
index c5601c49f..5dfa94e1e 100644
--- a/MediaBrowser.Controller/Drawing/ImageProcessorExtensions.cs
+++ b/MediaBrowser.Controller/Drawing/ImageProcessorExtensions.cs
@@ -5,12 +5,12 @@ namespace MediaBrowser.Controller.Drawing
{
public static class ImageProcessorExtensions
{
- public static string GetImageCacheTag(this IImageProcessor processor, IHasImages item, ImageType imageType)
+ public static string GetImageCacheTag(this IImageProcessor processor, IHasMetadata item, ImageType imageType)
{
return processor.GetImageCacheTag(item, imageType, 0);
}
- public static string GetImageCacheTag(this IImageProcessor processor, IHasImages item, ImageType imageType, int imageIndex)
+ public static string GetImageCacheTag(this IImageProcessor processor, IHasMetadata item, ImageType imageType, int imageIndex)
{
var imageInfo = item.GetImageInfo(imageType, imageIndex);
diff --git a/MediaBrowser.Controller/Drawing/ImageStream.cs b/MediaBrowser.Controller/Drawing/ImageStream.cs
index 353abaca3..b5e14eb6c 100644
--- a/MediaBrowser.Controller/Drawing/ImageStream.cs
+++ b/MediaBrowser.Controller/Drawing/ImageStream.cs
@@ -23,6 +23,7 @@ namespace MediaBrowser.Controller.Drawing
{
Stream.Dispose();
}
+ GC.SuppressFinalize(this);
}
}
}
diff --git a/MediaBrowser.Controller/Dto/DtoOptions.cs b/MediaBrowser.Controller/Dto/DtoOptions.cs
index 098ba558f..f05ae4e71 100644
--- a/MediaBrowser.Controller/Dto/DtoOptions.cs
+++ b/MediaBrowser.Controller/Dto/DtoOptions.cs
@@ -14,8 +14,8 @@ namespace MediaBrowser.Controller.Dto
ItemFields.RefreshState
};
- public List<ItemFields> Fields { get; set; }
- public List<ImageType> ImageTypes { get; set; }
+ public ItemFields[] Fields { get; set; }
+ public ImageType[] ImageTypes { get; set; }
public int ImageTypeLimit { get; set; }
public bool EnableImages { get; set; }
public bool AddProgramRecordingInfo { get; set; }
@@ -28,6 +28,15 @@ namespace MediaBrowser.Controller.Dto
{
}
+ private static readonly ImageType[] AllImageTypes = Enum.GetNames(typeof(ImageType))
+ .Select(i => (ImageType)Enum.Parse(typeof(ImageType), i, true))
+ .ToArray();
+
+ private static readonly ItemFields[] AllItemFields = Enum.GetNames(typeof(ItemFields))
+ .Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true))
+ .Except(DefaultExcludedFields)
+ .ToArray();
+
public DtoOptions(bool allFields)
{
ImageTypeLimit = int.MaxValue;
@@ -37,19 +46,14 @@ namespace MediaBrowser.Controller.Dto
if (allFields)
{
- Fields = Enum.GetNames(typeof(ItemFields))
- .Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true))
- .Except(DefaultExcludedFields)
- .ToList();
+ Fields = AllItemFields;
}
else
{
- Fields = new List<ItemFields>();
+ Fields = new ItemFields[] { };
}
- ImageTypes = Enum.GetNames(typeof(ImageType))
- .Select(i => (ImageType)Enum.Parse(typeof(ImageType), i, true))
- .ToList();
+ ImageTypes = AllImageTypes;
}
public int GetImageLimit(ImageType type)
diff --git a/MediaBrowser.Controller/Dto/IDtoService.cs b/MediaBrowser.Controller/Dto/IDtoService.cs
index a6f807ce9..c0217330d 100644
--- a/MediaBrowser.Controller/Dto/IDtoService.cs
+++ b/MediaBrowser.Controller/Dto/IDtoService.cs
@@ -2,7 +2,6 @@
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Querying;
using System.Collections.Generic;
-using System.Threading.Tasks;
using MediaBrowser.Controller.Sync;
namespace MediaBrowser.Controller.Dto
@@ -24,14 +23,14 @@ namespace MediaBrowser.Controller.Dto
/// </summary>
/// <param name="dto">The dto.</param>
/// <param name="item">The item.</param>
- void AttachPrimaryImageAspectRatio(IItemDto dto, IHasImages item);
+ void AttachPrimaryImageAspectRatio(IItemDto dto, IHasMetadata item);
/// <summary>
/// Gets the primary image aspect ratio.
/// </summary>
/// <param name="item">The item.</param>
/// <returns>System.Nullable&lt;System.Double&gt;.</returns>
- double? GetPrimaryImageAspectRatio(IHasImages item);
+ double? GetPrimaryImageAspectRatio(IHasMetadata item);
/// <summary>
/// Gets the base item dto.
@@ -40,8 +39,7 @@ namespace MediaBrowser.Controller.Dto
/// <param name="fields">The fields.</param>
/// <param name="user">The user.</param>
/// <param name="owner">The owner.</param>
- /// <returns>Task{BaseItemDto}.</returns>
- BaseItemDto GetBaseItemDto(BaseItem item, List<ItemFields> fields, User user = null, BaseItem owner = null);
+ BaseItemDto GetBaseItemDto(BaseItem item, ItemFields[] fields, User user = null, BaseItem owner = null);
/// <summary>
/// Gets the base item dto.
@@ -60,10 +58,10 @@ namespace MediaBrowser.Controller.Dto
/// <param name="options">The options.</param>
/// <param name="user">The user.</param>
/// <param name="owner">The owner.</param>
- /// <returns>IEnumerable&lt;BaseItemDto&gt;.</returns>
- Task<List<BaseItemDto>> GetBaseItemDtos(IEnumerable<BaseItem> items, DtoOptions options, User user = null,
- BaseItem owner = null);
-
+ BaseItemDto[] GetBaseItemDtos(BaseItem[] items, DtoOptions options, User user = null, BaseItem owner = null);
+
+ BaseItemDto[] GetBaseItemDtos(List<BaseItem> items, DtoOptions options, User user = null, BaseItem owner = null);
+
/// <summary>
/// Gets the chapter information dto.
/// </summary>
diff --git a/MediaBrowser.Controller/Entities/AggregateFolder.cs b/MediaBrowser.Controller/Entities/AggregateFolder.cs
index e8ebbdb70..2105ef907 100644
--- a/MediaBrowser.Controller/Entities/AggregateFolder.cs
+++ b/MediaBrowser.Controller/Entities/AggregateFolder.cs
@@ -20,19 +20,7 @@ namespace MediaBrowser.Controller.Entities
{
public AggregateFolder()
{
- PhysicalLocationsList = new List<string>();
- }
-
- /// <summary>
- /// We don't support manual shortcuts
- /// </summary>
- [IgnoreDataMember]
- protected override bool SupportsShortcutChildren
- {
- get
- {
- return false;
- }
+ PhysicalLocationsList = EmptyStringArray;
}
[IgnoreDataMember]
@@ -70,7 +58,7 @@ namespace MediaBrowser.Controller.Entities
}
[IgnoreDataMember]
- public override IEnumerable<string> PhysicalLocations
+ public override string[] PhysicalLocations
{
get
{
@@ -78,23 +66,23 @@ namespace MediaBrowser.Controller.Entities
}
}
- public List<string> PhysicalLocationsList { get; set; }
+ public string[] PhysicalLocationsList { get; set; }
- protected override IEnumerable<FileSystemMetadata> GetFileSystemChildren(IDirectoryService directoryService)
+ protected override FileSystemMetadata[] GetFileSystemChildren(IDirectoryService directoryService)
{
return CreateResolveArgs(directoryService, true).FileSystemChildren;
}
- private List<Guid> _childrenIds = null;
+ private Guid[] _childrenIds = null;
private readonly object _childIdsLock = new object();
protected override List<BaseItem> LoadChildren()
{
lock (_childIdsLock)
{
- if (_childrenIds == null || _childrenIds.Count == 0)
+ if (_childrenIds == null || _childrenIds.Length == 0)
{
- var list = base.LoadChildren().ToList();
- _childrenIds = list.Select(i => i.Id).ToList();
+ var list = base.LoadChildren();
+ _childrenIds = list.Select(i => i.Id).ToArray();
return list;
}
@@ -117,9 +105,9 @@ namespace MediaBrowser.Controller.Entities
if (!changed)
{
- var locations = PhysicalLocations.ToList();
+ var locations = PhysicalLocations;
- var newLocations = CreateResolveArgs(new DirectoryService(Logger, FileSystem), false).PhysicalLocations.ToList();
+ var newLocations = CreateResolveArgs(new DirectoryService(Logger, FileSystem), false).PhysicalLocations;
if (!locations.SequenceEqual(newLocations))
{
@@ -160,24 +148,22 @@ namespace MediaBrowser.Controller.Entities
// When resolving the root, we need it's grandchildren (children of user views)
var flattenFolderDepth = isPhysicalRoot ? 2 : 0;
- var fileSystemDictionary = FileData.GetFilteredFileSystemEntries(directoryService, args.Path, FileSystem, Logger, args, flattenFolderDepth: flattenFolderDepth, resolveShortcuts: isPhysicalRoot || args.IsVf);
+ var files = FileData.GetFilteredFileSystemEntries(directoryService, args.Path, FileSystem, Logger, args, flattenFolderDepth: flattenFolderDepth, resolveShortcuts: isPhysicalRoot || args.IsVf);
// Need to remove subpaths that may have been resolved from shortcuts
// Example: if \\server\movies exists, then strip out \\server\movies\action
if (isPhysicalRoot)
{
- var paths = LibraryManager.NormalizeRootPathList(fileSystemDictionary.Values);
-
- fileSystemDictionary = paths.ToDictionary(i => i.FullName);
+ files = LibraryManager.NormalizeRootPathList(files).ToArray();
}
- args.FileSystemDictionary = fileSystemDictionary;
+ args.FileSystemChildren = files;
}
_requiresRefresh = _requiresRefresh || !args.PhysicalLocations.SequenceEqual(PhysicalLocations);
if (setPhysicalLocations)
{
- PhysicalLocationsList = args.PhysicalLocations.ToList();
+ PhysicalLocationsList = args.PhysicalLocations;
}
return args;
@@ -226,7 +212,14 @@ namespace MediaBrowser.Controller.Entities
throw new ArgumentNullException("id");
}
- return _virtualChildren.FirstOrDefault(i => i.Id == id);
+ foreach (var child in _virtualChildren)
+ {
+ if (child.Id == id)
+ {
+ return child;
+ }
+ }
+ return null;
}
}
}
diff --git a/MediaBrowser.Controller/Entities/Audio/Audio.cs b/MediaBrowser.Controller/Entities/Audio/Audio.cs
index 873ac3104..3ebf4da00 100644
--- a/MediaBrowser.Controller/Entities/Audio/Audio.cs
+++ b/MediaBrowser.Controller/Entities/Audio/Audio.cs
@@ -9,6 +9,7 @@ using System.Globalization;
using System.Linq;
using System.Threading;
using MediaBrowser.Common.Extensions;
+using MediaBrowser.Controller.Persistence;
using MediaBrowser.Model.Serialization;
namespace MediaBrowser.Controller.Entities.Audio
@@ -27,9 +28,11 @@ namespace MediaBrowser.Controller.Entities.Audio
/// Gets or sets the artist.
/// </summary>
/// <value>The artist.</value>
- public List<string> Artists { get; set; }
+ [IgnoreDataMember]
+ public string[] Artists { get; set; }
- public List<string> AlbumArtists { get; set; }
+ [IgnoreDataMember]
+ public string[] AlbumArtists { get; set; }
[IgnoreDataMember]
public override bool EnableRefreshOnDateModifiedChange
@@ -39,8 +42,8 @@ namespace MediaBrowser.Controller.Entities.Audio
public Audio()
{
- Artists = new List<string>();
- AlbumArtists = new List<string>();
+ Artists = EmptyStringArray;
+ AlbumArtists = EmptyStringArray;
}
public override double? GetDefaultPrimaryImageAspectRatio()
@@ -95,13 +98,23 @@ namespace MediaBrowser.Controller.Entities.Audio
}
[IgnoreDataMember]
- public List<string> AllArtists
+ public string[] AllArtists
{
get
{
- var list = AlbumArtists.ToList();
+ var list = new string[AlbumArtists.Length + Artists.Length];
- list.AddRange(Artists);
+ var index = 0;
+ foreach (var artist in AlbumArtists)
+ {
+ list[index] = artist;
+ index++;
+ }
+ foreach (var artist in Artists)
+ {
+ list[index] = artist;
+ index++;
+ }
return list;
@@ -157,7 +170,7 @@ namespace MediaBrowser.Controller.Entities.Audio
songKey = Album + "-" + songKey;
}
- var albumArtist = AlbumArtists.FirstOrDefault();
+ var albumArtist = AlbumArtists.Length == 0 ? null : AlbumArtists[0];
if (!string.IsNullOrWhiteSpace(albumArtist))
{
songKey = albumArtist + "-" + songKey;
@@ -193,6 +206,23 @@ namespace MediaBrowser.Controller.Entities.Audio
return base.GetBlockUnratedType();
}
+ public List<MediaStream> GetMediaStreams()
+ {
+ return MediaSourceManager.GetMediaStreams(new MediaStreamQuery
+ {
+ ItemId = Id
+ });
+ }
+
+ public List<MediaStream> GetMediaStreams(MediaStreamType type)
+ {
+ return MediaSourceManager.GetMediaStreams(new MediaStreamQuery
+ {
+ ItemId = Id,
+ Type = type
+ });
+ }
+
public SongInfo GetLookupInfo()
{
var info = GetItemLookupInfo<SongInfo>();
@@ -204,7 +234,7 @@ namespace MediaBrowser.Controller.Entities.Audio
return info;
}
- public virtual IEnumerable<MediaSourceInfo> GetMediaSources(bool enablePathSubstitution)
+ public virtual List<MediaSourceInfo> GetMediaSources(bool enablePathSubstitution)
{
if (SourceType == SourceType.Channel)
{
@@ -248,7 +278,7 @@ namespace MediaBrowser.Controller.Entities.Audio
{
Id = i.Id.ToString("N"),
Protocol = locationType == LocationType.Remote ? MediaProtocol.Http : MediaProtocol.File,
- MediaStreams = MediaSourceManager.GetMediaStreams(i.Id).ToList(),
+ MediaStreams = MediaSourceManager.GetMediaStreams(i.Id),
Name = i.Name,
Path = enablePathSubstituion ? GetMappedPath(i, i.Path, locationType) : i.Path,
RunTimeTicks = i.RunTimeTicks,
diff --git a/MediaBrowser.Controller/Entities/Audio/IHasAlbumArtist.cs b/MediaBrowser.Controller/Entities/Audio/IHasAlbumArtist.cs
index a7c914664..b2dedada4 100644
--- a/MediaBrowser.Controller/Entities/Audio/IHasAlbumArtist.cs
+++ b/MediaBrowser.Controller/Entities/Audio/IHasAlbumArtist.cs
@@ -1,25 +1,15 @@
-using MediaBrowser.Controller.Library;
-using System.Collections.Generic;
-
+
namespace MediaBrowser.Controller.Entities.Audio
{
public interface IHasAlbumArtist
{
- List<string> AlbumArtists { get; set; }
+ string[] AlbumArtists { get; set; }
}
public interface IHasArtist
{
- List<string> AllArtists { get; }
-
- List<string> Artists { get; set; }
- }
+ string[] AllArtists { get; }
- public static class HasArtistExtensions
- {
- public static bool HasAnyArtist(this IHasArtist hasArtist, string artist)
- {
- return NameExtensions.EqualsAny(hasArtist.AllArtists, artist);
- }
+ string[] Artists { get; set; }
}
}
diff --git a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs
index 516ab5053..7af8161ca 100644
--- a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs
+++ b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs
@@ -10,7 +10,6 @@ using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Library;
-using MediaBrowser.Model.Dto;
namespace MediaBrowser.Controller.Entities.Audio
{
@@ -19,13 +18,13 @@ namespace MediaBrowser.Controller.Entities.Audio
/// </summary>
public class MusicAlbum : Folder, IHasAlbumArtist, IHasArtist, IHasMusicGenres, IHasLookupInfo<AlbumInfo>, IMetadataContainer
{
- public List<string> AlbumArtists { get; set; }
- public List<string> Artists { get; set; }
+ public string[] AlbumArtists { get; set; }
+ public string[] Artists { get; set; }
public MusicAlbum()
{
- Artists = new List<string>();
- AlbumArtists = new List<string>();
+ Artists = EmptyStringArray;
+ AlbumArtists = EmptyStringArray;
}
[IgnoreDataMember]
@@ -48,17 +47,22 @@ namespace MediaBrowser.Controller.Entities.Audio
public MusicArtist GetMusicArtist(DtoOptions options)
{
- var artist = GetParents().OfType<MusicArtist>().FirstOrDefault();
-
- if (artist == null)
+ var parents = GetParents();
+ foreach (var parent in parents)
{
- var name = AlbumArtist;
- if (!string.IsNullOrWhiteSpace(name))
+ var artist = parent as MusicArtist;
+ if (artist != null)
{
- artist = LibraryManager.GetArtist(name, options);
+ return artist;
}
}
- return artist;
+
+ var name = AlbumArtist;
+ if (!string.IsNullOrWhiteSpace(name))
+ {
+ return LibraryManager.GetArtist(name, options);
+ }
+ return null;
}
[IgnoreDataMember]
@@ -80,23 +84,32 @@ namespace MediaBrowser.Controller.Entities.Audio
}
[IgnoreDataMember]
- public List<string> AllArtists
+ public string[] AllArtists
{
get
{
- var list = AlbumArtists.ToList();
+ var list = new string[AlbumArtists.Length + Artists.Length];
- list.AddRange(Artists);
+ var index = 0;
+ foreach (var artist in AlbumArtists)
+ {
+ list[index] = artist;
+ index++;
+ }
+ foreach (var artist in Artists)
+ {
+ list[index] = artist;
+ index++;
+ }
return list;
-
}
}
[IgnoreDataMember]
public string AlbumArtist
{
- get { return AlbumArtists.FirstOrDefault(); }
+ get { return AlbumArtists.Length == 0 ? null : AlbumArtists[0]; }
}
[IgnoreDataMember]
@@ -110,11 +123,11 @@ namespace MediaBrowser.Controller.Entities.Audio
/// </summary>
/// <value>The tracks.</value>
[IgnoreDataMember]
- public IEnumerable<Audio> Tracks
+ public IEnumerable<BaseItem> Tracks
{
get
{
- return GetRecursiveChildren(i => i is Audio).Cast<Audio>();
+ return GetRecursiveChildren(i => i is Audio);
}
}
@@ -200,7 +213,7 @@ namespace MediaBrowser.Controller.Entities.Audio
public async Task RefreshAllMetadata(MetadataRefreshOptions refreshOptions, IProgress<double> progress, CancellationToken cancellationToken)
{
- var items = GetRecursiveChildren().ToList();
+ var items = GetRecursiveChildren();
var totalItems = items.Count;
var numComplete = 0;
@@ -239,27 +252,22 @@ namespace MediaBrowser.Controller.Entities.Audio
private async Task RefreshArtists(MetadataRefreshOptions refreshOptions, CancellationToken cancellationToken)
{
- var artists = AllArtists.Select(i =>
+ var all = AllArtists;
+ foreach (var i in all)
{
// This should not be necessary but we're seeing some cases of it
if (string.IsNullOrWhiteSpace(i))
{
- return null;
+ continue;
}
var artist = LibraryManager.GetArtist(i);
if (!artist.IsAccessedByName)
{
- return null;
+ continue;
}
- return artist;
-
- }).Where(i => i != null).ToList();
-
- foreach (var artist in artists)
- {
await artist.RefreshMetadata(refreshOptions, cancellationToken).ConfigureAwait(false);
}
}
diff --git a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs
index 7a37b2e02..19fe68e25 100644
--- a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs
+++ b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs
@@ -212,20 +212,21 @@ namespace MediaBrowser.Controller.Entities.Audio
public async Task RefreshAllMetadata(MetadataRefreshOptions refreshOptions, IProgress<double> progress, CancellationToken cancellationToken)
{
- var items = GetRecursiveChildren().ToList();
+ var items = GetRecursiveChildren();
- var songs = items.OfType<Audio>().ToList();
-
- var others = items.Except(songs).ToList();
-
- var totalItems = songs.Count + others.Count;
+ var totalItems = items.Count;
var numComplete = 0;
var childUpdateType = ItemUpdateType.None;
// Refresh songs
- foreach (var item in songs)
+ foreach (var item in items)
{
+ if (!(item is Audio))
+ {
+ continue;
+ }
+
cancellationToken.ThrowIfCancellationRequested();
var updateType = await item.RefreshMetadata(refreshOptions, cancellationToken).ConfigureAwait(false);
@@ -248,8 +249,13 @@ namespace MediaBrowser.Controller.Entities.Audio
await RefreshMetadata(parentRefreshOptions, cancellationToken).ConfigureAwait(false);
// Refresh all non-songs
- foreach (var item in others)
+ foreach (var item in items)
{
+ if (item is Audio)
+ {
+ continue;
+ }
+
cancellationToken.ThrowIfCancellationRequested();
var updateType = await item.RefreshMetadata(parentRefreshOptions, cancellationToken).ConfigureAwait(false);
diff --git a/MediaBrowser.Controller/Entities/Audio/MusicGenre.cs b/MediaBrowser.Controller/Entities/Audio/MusicGenre.cs
index d4a85b4d0..02e652048 100644
--- a/MediaBrowser.Controller/Entities/Audio/MusicGenre.cs
+++ b/MediaBrowser.Controller/Entities/Audio/MusicGenre.cs
@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
-using System.Linq;
using MediaBrowser.Model.Serialization;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Controller.Extensions;
diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs
index 6f8d62c0c..c41d3e0cd 100644
--- a/MediaBrowser.Controller/Entities/BaseItem.cs
+++ b/MediaBrowser.Controller/Entities/BaseItem.cs
@@ -25,6 +25,7 @@ using System.Threading.Tasks;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Extensions;
using MediaBrowser.Controller.IO;
+using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.Controller.Sorting;
using MediaBrowser.Model.Extensions;
using MediaBrowser.Model.Globalization;
@@ -39,20 +40,26 @@ namespace MediaBrowser.Controller.Entities
/// <summary>
/// Class BaseItem
/// </summary>
- public abstract class BaseItem : IHasProviderIds, IHasImages, IHasUserData, IHasMetadata, IHasLookupInfo<ItemLookupInfo>
+ public abstract class BaseItem : IHasMetadata, IHasLookupInfo<ItemLookupInfo>
{
+ protected static Guid[] EmptyGuidArray = new Guid[] { };
+ protected static MetadataFields[] EmptyMetadataFieldsArray = new MetadataFields[] { };
+ protected static string[] EmptyStringArray = new string[] { };
+ protected static MediaUrl[] EmptyMediaUrlArray = new MediaUrl[] { };
+ protected static ItemImageInfo[] EmptyItemImageInfoArray = new ItemImageInfo[] { };
+ public static readonly LinkedChild[] EmptyLinkedChildArray = new LinkedChild[] { };
+
protected BaseItem()
{
- ThemeSongIds = new List<Guid>();
- ThemeVideoIds = new List<Guid>();
- Tags = new List<string>();
+ ThemeSongIds = EmptyGuidArray;
+ ThemeVideoIds = EmptyGuidArray;
+ Tags = EmptyStringArray;
Genres = new List<string>();
- Studios = new List<string>();
+ Studios = EmptyStringArray;
ProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
- LockedFields = new List<MetadataFields>();
- ImageInfos = new List<ItemImageInfo>();
- InheritedTags = new List<string>();
- ProductionLocations = new List<string>();
+ LockedFields = EmptyMetadataFieldsArray;
+ ImageInfos = EmptyItemImageInfoArray;
+ ProductionLocations = EmptyStringArray;
}
public static readonly char[] SlugReplaceChars = { '?', '/', '&' };
@@ -73,8 +80,10 @@ namespace MediaBrowser.Controller.Entities
public static string ThemeSongFilename = "theme";
public static string ThemeVideosFolderName = "backdrops";
- public List<Guid> ThemeSongIds { get; set; }
- public List<Guid> ThemeVideoIds { get; set; }
+ [IgnoreDataMember]
+ public Guid[] ThemeSongIds { get; set; }
+ [IgnoreDataMember]
+ public Guid[] ThemeVideoIds { get; set; }
[IgnoreDataMember]
public string PreferredMetadataCountryCode { get; set; }
@@ -87,7 +96,8 @@ namespace MediaBrowser.Controller.Entities
[IgnoreDataMember]
public string Tagline { get; set; }
- public List<ItemImageInfo> ImageInfos { get; set; }
+ [IgnoreDataMember]
+ public ItemImageInfo[] ImageInfos { get; set; }
[IgnoreDataMember]
public bool IsVirtualItem { get; set; }
@@ -129,12 +139,6 @@ namespace MediaBrowser.Controller.Entities
public bool IsInMixedFolder { get; set; }
[IgnoreDataMember]
- protected virtual bool SupportsIsInMixedFolderDetection
- {
- get { return false; }
- }
-
- [IgnoreDataMember]
public virtual bool SupportsPlayedStatus
{
get
@@ -152,16 +156,6 @@ namespace MediaBrowser.Controller.Entities
}
}
- public bool DetectIsInMixedFolder()
- {
- if (SupportsIsInMixedFolderDetection)
- {
-
- }
-
- return IsInMixedFolder;
- }
-
[IgnoreDataMember]
public virtual bool SupportsRemoteImageDownloading
{
@@ -193,27 +187,14 @@ namespace MediaBrowser.Controller.Entities
}
[IgnoreDataMember]
- public string SlugName
- {
- get
- {
- var name = Name;
- if (string.IsNullOrWhiteSpace(name))
- {
- return string.Empty;
- }
-
- return SlugReplaceChars.Aggregate(name, (current, c) => current.Replace(c, SlugChar));
- }
- }
-
- [IgnoreDataMember]
public bool IsUnaired
{
get { return PremiereDate.HasValue && PremiereDate.Value.ToLocalTime().Date >= DateTime.Now.Date; }
}
+ [IgnoreDataMember]
public int? TotalBitrate { get; set; }
+ [IgnoreDataMember]
public ExtraType? ExtraType { get; set; }
[IgnoreDataMember]
@@ -541,6 +522,7 @@ namespace MediaBrowser.Controller.Entities
public static ICollectionManager CollectionManager { get; set; }
public static IImageProcessor ImageProcessor { get; set; }
public static IMediaSourceManager MediaSourceManager { get; set; }
+ public static IMediaEncoder MediaEncoder { get; set; }
/// <summary>
/// Returns a <see cref="System.String" /> that represents this instance.
@@ -559,7 +541,7 @@ namespace MediaBrowser.Controller.Entities
/// </summary>
/// <value>The locked fields.</value>
[IgnoreDataMember]
- public List<MetadataFields> LockedFields { get; set; }
+ public MetadataFields[] LockedFields { get; set; }
/// <summary>
/// Gets the type of the media.
@@ -575,7 +557,7 @@ namespace MediaBrowser.Controller.Entities
}
[IgnoreDataMember]
- public virtual IEnumerable<string> PhysicalLocations
+ public virtual string[] PhysicalLocations
{
get
{
@@ -667,27 +649,34 @@ namespace MediaBrowser.Controller.Entities
}
var sortable = Name.Trim().ToLower();
- sortable = ConfigurationManager.Configuration.SortRemoveCharacters.Aggregate(sortable, (current, search) => current.Replace(search.ToLower(), string.Empty));
- sortable = ConfigurationManager.Configuration.SortReplaceCharacters.Aggregate(sortable, (current, search) => current.Replace(search.ToLower(), " "));
+ foreach (var removeChar in ConfigurationManager.Configuration.SortRemoveCharacters)
+ {
+ sortable = sortable.Replace(removeChar, string.Empty);
+ }
+
+ foreach (var replaceChar in ConfigurationManager.Configuration.SortReplaceCharacters)
+ {
+ sortable = sortable.Replace(replaceChar, " ");
+ }
foreach (var search in ConfigurationManager.Configuration.SortRemoveWords)
{
- var searchLower = search.ToLower();
// Remove from beginning if a space follows
- if (sortable.StartsWith(searchLower + " "))
+ if (sortable.StartsWith(search + " "))
{
- sortable = sortable.Remove(0, searchLower.Length + 1);
+ sortable = sortable.Remove(0, search.Length + 1);
}
// Remove from middle if surrounded by spaces
- sortable = sortable.Replace(" " + searchLower + " ", " ");
+ sortable = sortable.Replace(" " + search + " ", " ");
// Remove from end if followed by a space
- if (sortable.EndsWith(" " + searchLower))
+ if (sortable.EndsWith(" " + search))
{
- sortable = sortable.Remove(sortable.Length - (searchLower.Length + 1));
+ sortable = sortable.Remove(sortable.Length - (search.Length + 1));
}
}
+
return ModifySortChunks(sortable);
}
@@ -774,7 +763,15 @@ namespace MediaBrowser.Controller.Entities
public T FindParent<T>()
where T : Folder
{
- return GetParents().OfType<T>().FirstOrDefault();
+ foreach (var parent in GetParents())
+ {
+ var item = parent as T;
+ if (item != null)
+ {
+ return item;
+ }
+ }
+ return null;
}
[IgnoreDataMember]
@@ -819,13 +816,6 @@ namespace MediaBrowser.Controller.Entities
public DateTime? EndDate { get; set; }
/// <summary>
- /// Gets or sets the display type of the media.
- /// </summary>
- /// <value>The display type of the media.</value>
- [IgnoreDataMember]
- public string DisplayMediaType { get; set; }
-
- /// <summary>
/// Gets or sets the official rating.
/// </summary>
/// <value>The official rating.</value>
@@ -835,9 +825,6 @@ namespace MediaBrowser.Controller.Entities
[IgnoreDataMember]
public int InheritedParentalRatingValue { get; set; }
- [IgnoreDataMember]
- public List<string> InheritedTags { get; set; }
-
/// <summary>
/// Gets or sets the critic rating.
/// </summary>
@@ -864,7 +851,7 @@ namespace MediaBrowser.Controller.Entities
/// </summary>
/// <value>The studios.</value>
[IgnoreDataMember]
- public List<string> Studios { get; set; }
+ public string[] Studios { get; set; }
/// <summary>
/// Gets or sets the genres.
@@ -878,9 +865,10 @@ namespace MediaBrowser.Controller.Entities
/// </summary>
/// <value>The tags.</value>
[IgnoreDataMember]
- public List<string> Tags { get; set; }
+ public string[] Tags { get; set; }
- public List<string> ProductionLocations { get; set; }
+ [IgnoreDataMember]
+ public string[] ProductionLocations { get; set; }
/// <summary>
/// Gets or sets the home page URL.
@@ -989,11 +977,11 @@ namespace MediaBrowser.Controller.Entities
/// Loads the theme songs.
/// </summary>
/// <returns>List{Audio.Audio}.</returns>
- private static IEnumerable<Audio.Audio> LoadThemeSongs(List<FileSystemMetadata> fileSystemChildren, IDirectoryService directoryService)
+ private static Audio.Audio[] LoadThemeSongs(List<FileSystemMetadata> fileSystemChildren, IDirectoryService directoryService)
{
var files = fileSystemChildren.Where(i => i.IsDirectory)
.Where(i => string.Equals(i.Name, ThemeSongsFolderName, StringComparison.OrdinalIgnoreCase))
- .SelectMany(i => directoryService.GetFiles(i.FullName))
+ .SelectMany(i => FileSystem.GetFiles(i.FullName))
.ToList();
// Support plex/xbmc convention
@@ -1018,18 +1006,18 @@ namespace MediaBrowser.Controller.Entities
return audio;
// Sort them so that the list can be easily compared for changes
- }).OrderBy(i => i.Path).ToList();
+ }).OrderBy(i => i.Path).ToArray();
}
/// <summary>
/// Loads the video backdrops.
/// </summary>
/// <returns>List{Video}.</returns>
- private static IEnumerable<Video> LoadThemeVideos(IEnumerable<FileSystemMetadata> fileSystemChildren, IDirectoryService directoryService)
+ private static Video[] LoadThemeVideos(IEnumerable<FileSystemMetadata> fileSystemChildren, IDirectoryService directoryService)
{
var files = fileSystemChildren.Where(i => i.IsDirectory)
.Where(i => string.Equals(i.Name, ThemeVideosFolderName, StringComparison.OrdinalIgnoreCase))
- .SelectMany(i => directoryService.GetFiles(i.FullName));
+ .SelectMany(i => FileSystem.GetFiles(i.FullName));
return LibraryManager.ResolvePaths(files, directoryService, null, new LibraryOptions())
.OfType<Video>()
@@ -1048,7 +1036,7 @@ namespace MediaBrowser.Controller.Entities
return item;
// Sort them so that the list can be easily compared for changes
- }).OrderBy(i => i.Path).ToList();
+ }).OrderBy(i => i.Path).ToArray();
}
public Task RefreshMetadata(CancellationToken cancellationToken)
@@ -1156,7 +1144,7 @@ namespace MediaBrowser.Controller.Entities
{
if (SupportsThemeMedia)
{
- if (!DetectIsInMixedFolder())
+ if (!IsInMixedFolder)
{
themeSongsChanged = await RefreshThemeSongs(this, options, fileSystemChildren, cancellationToken).ConfigureAwait(false);
@@ -1174,7 +1162,7 @@ namespace MediaBrowser.Controller.Entities
return themeSongsChanged || themeVideosChanged || localTrailersChanged;
}
- protected virtual IEnumerable<FileSystemMetadata> GetFileSystemChildren(IDirectoryService directoryService)
+ protected virtual FileSystemMetadata[] GetFileSystemChildren(IDirectoryService directoryService)
{
var path = ContainingFolderPath;
@@ -1185,7 +1173,7 @@ namespace MediaBrowser.Controller.Entities
{
var newItems = LibraryManager.FindTrailers(this, fileSystemChildren, options.DirectoryService).ToList();
- var newItemIds = newItems.Select(i => i.Id).ToList();
+ var newItemIds = newItems.Select(i => i.Id).ToArray();
var itemsChanged = !item.LocalTrailerIds.SequenceEqual(newItemIds);
@@ -1200,9 +1188,9 @@ namespace MediaBrowser.Controller.Entities
private async Task<bool> RefreshThemeVideos(BaseItem item, MetadataRefreshOptions options, IEnumerable<FileSystemMetadata> fileSystemChildren, CancellationToken cancellationToken)
{
- var newThemeVideos = LoadThemeVideos(fileSystemChildren, options.DirectoryService).ToList();
+ var newThemeVideos = LoadThemeVideos(fileSystemChildren, options.DirectoryService);
- var newThemeVideoIds = newThemeVideos.Select(i => i.Id).ToList();
+ var newThemeVideoIds = newThemeVideos.Select(i => i.Id).ToArray(newThemeVideos.Length);
var themeVideosChanged = !item.ThemeVideoIds.SequenceEqual(newThemeVideoIds);
@@ -1231,8 +1219,8 @@ namespace MediaBrowser.Controller.Entities
/// </summary>
private async Task<bool> RefreshThemeSongs(BaseItem item, MetadataRefreshOptions options, List<FileSystemMetadata> fileSystemChildren, CancellationToken cancellationToken)
{
- var newThemeSongs = LoadThemeSongs(fileSystemChildren, options.DirectoryService).ToList();
- var newThemeSongIds = newThemeSongs.Select(i => i.Id).ToList();
+ var newThemeSongs = LoadThemeSongs(fileSystemChildren, options.DirectoryService);
+ var newThemeSongIds = newThemeSongs.Select(i => i.Id).ToArray(newThemeSongs.Length);
var themeSongsChanged = !item.ThemeSongIds.SequenceEqual(newThemeSongIds);
@@ -1260,6 +1248,7 @@ namespace MediaBrowser.Controller.Entities
/// Gets or sets the provider ids.
/// </summary>
/// <value>The provider ids.</value>
+ [IgnoreDataMember]
public Dictionary<string, string> ProviderIds { get; set; }
[IgnoreDataMember]
@@ -1311,12 +1300,9 @@ namespace MediaBrowser.Controller.Entities
{
var current = this;
- if (!SupportsIsInMixedFolderDetection)
+ if (current.IsInMixedFolder != newItem.IsInMixedFolder)
{
- if (current.IsInMixedFolder != newItem.IsInMixedFolder)
- {
- return false;
- }
+ return false;
}
return true;
@@ -1737,12 +1723,28 @@ namespace MediaBrowser.Controller.Entities
throw new ArgumentNullException("name");
}
- if (!Studios.Contains(name, StringComparer.OrdinalIgnoreCase))
+ var current = Studios;
+
+ if (!current.Contains(name, StringComparer.OrdinalIgnoreCase))
{
- Studios.Add(name);
+ if (current.Length == 0)
+ {
+ Studios = new[] { name };
+ }
+ else
+ {
+ var list = current.ToArray(current.Length + 1);
+ list[list.Length - 1] = name;
+ Studios = list;
+ }
}
}
+ public void SetStudios(IEnumerable<string> names)
+ {
+ Studios = names.Distinct().ToArray();
+ }
+
/// <summary>
/// Adds a genre to the item
/// </summary>
@@ -1769,7 +1771,7 @@ namespace MediaBrowser.Controller.Entities
/// <param name="resetPosition">if set to <c>true</c> [reset position].</param>
/// <returns>Task.</returns>
/// <exception cref="System.ArgumentNullException"></exception>
- public virtual async Task MarkPlayed(User user,
+ public virtual void MarkPlayed(User user,
DateTime? datePlayed,
bool resetPosition)
{
@@ -1797,7 +1799,7 @@ namespace MediaBrowser.Controller.Entities
data.LastPlayedDate = datePlayed ?? data.LastPlayedDate ?? DateTime.UtcNow;
data.Played = true;
- await UserDataManager.SaveUserData(user.Id, this, data, UserDataSaveReason.TogglePlayed, CancellationToken.None).ConfigureAwait(false);
+ UserDataManager.SaveUserData(user.Id, this, data, UserDataSaveReason.TogglePlayed, CancellationToken.None);
}
/// <summary>
@@ -1806,7 +1808,7 @@ namespace MediaBrowser.Controller.Entities
/// <param name="user">The user.</param>
/// <returns>Task.</returns>
/// <exception cref="System.ArgumentNullException"></exception>
- public virtual async Task MarkUnplayed(User user)
+ public virtual void MarkUnplayed(User user)
{
if (user == null)
{
@@ -1823,7 +1825,7 @@ namespace MediaBrowser.Controller.Entities
data.LastPlayedDate = null;
data.Played = false;
- await UserDataManager.SaveUserData(user.Id, this, data, UserDataSaveReason.TogglePlayed, CancellationToken.None).ConfigureAwait(false);
+ UserDataManager.SaveUserData(user.Id, this, data, UserDataSaveReason.TogglePlayed, CancellationToken.None);
}
/// <summary>
@@ -1862,10 +1864,18 @@ namespace MediaBrowser.Controller.Entities
if (existingImage != null)
{
- ImageInfos.Remove(existingImage);
+ existingImage.Path = image.Path;
+ existingImage.DateModified = image.DateModified;
+ existingImage.IsPlaceholder = image.IsPlaceholder;
}
- ImageInfos.Add(image);
+ else
+ {
+ var currentCount = ImageInfos.Length;
+ var newList = ImageInfos.ToArray(currentCount + 1);
+ newList[currentCount] = image;
+ ImageInfos = newList;
+ }
}
public void SetImagePath(ImageType type, int index, FileSystemMetadata file)
@@ -1879,7 +1889,10 @@ namespace MediaBrowser.Controller.Entities
if (image == null)
{
- ImageInfos.Add(GetImageInfo(file, type));
+ var currentCount = ImageInfos.Length;
+ var newList = ImageInfos.ToArray(currentCount + 1);
+ newList[currentCount] = GetImageInfo(file, type);
+ ImageInfos = newList;
}
else
{
@@ -1920,7 +1933,12 @@ namespace MediaBrowser.Controller.Entities
public void RemoveImage(ItemImageInfo image)
{
- ImageInfos.Remove(image);
+ RemoveImages(new List<ItemImageInfo> { image });
+ }
+
+ public void RemoveImages(List<ItemImageInfo> deletedImages)
+ {
+ ImageInfos = ImageInfos.Except(deletedImages).ToArray();
}
public virtual Task UpdateToRepository(ItemUpdateType updateReason, CancellationToken cancellationToken)
@@ -1937,7 +1955,7 @@ namespace MediaBrowser.Controller.Entities
.Where(i => i.IsLocalFile)
.Select(i => FileSystem.GetDirectoryName(i.Path))
.Distinct(StringComparer.OrdinalIgnoreCase)
- .SelectMany(directoryService.GetFilePaths)
+ .SelectMany(i => FileSystem.GetFilePaths(i))
.ToList();
var deletedImages = ImageInfos
@@ -1946,7 +1964,7 @@ namespace MediaBrowser.Controller.Entities
if (deletedImages.Count > 0)
{
- ImageInfos = ImageInfos.Except(deletedImages).ToList();
+ ImageInfos = ImageInfos.Except(deletedImages).ToArray();
}
return deletedImages.Count > 0;
@@ -2066,10 +2084,25 @@ namespace MediaBrowser.Controller.Entities
.Where(i => i.IsLocalFile && !newImagePaths.Contains(i.Path, StringComparer.OrdinalIgnoreCase) && !FileSystem.FileExists(i.Path))
.ToList();
- ImageInfos = ImageInfos.Except(deleted).ToList();
+ if (deleted.Count > 0)
+ {
+ ImageInfos = ImageInfos.Except(deleted).ToArray();
+ }
}
- ImageInfos.AddRange(newImageList.Select(i => GetImageInfo(i, imageType)));
+ if (newImageList.Count > 0)
+ {
+ var currentCount = ImageInfos.Length;
+ var newList = ImageInfos.ToArray(currentCount + newImageList.Count);
+
+ foreach (var image in newImageList)
+ {
+ newList[currentCount] = GetImageInfo(image, imageType);
+ currentCount++;
+ }
+
+ ImageInfos = newList;
+ }
return newImageList.Count > 0;
}
@@ -2107,10 +2140,10 @@ namespace MediaBrowser.Controller.Entities
}
var filename = System.IO.Path.GetFileNameWithoutExtension(Path);
- var extensions = new[] { ".nfo", ".xml", ".srt" }.ToList();
- extensions.AddRange(SupportedImageExtensionsList);
+ var extensions = new List<string> { ".nfo", ".xml", ".srt" };
+ extensions.AddRange(SupportedImageExtensions);
- return FileSystem.GetFiles(FileSystem.GetDirectoryName(Path), extensions.ToArray(), false, false)
+ return FileSystem.GetFiles(FileSystem.GetDirectoryName(Path), extensions.ToArray(extensions.Count), false, false)
.Where(i => System.IO.Path.GetFileNameWithoutExtension(i.FullName).StartsWith(filename, StringComparison.OrdinalIgnoreCase))
.ToList();
}
@@ -2234,7 +2267,7 @@ namespace MediaBrowser.Controller.Entities
return path;
}
- public virtual void FillUserDataDtoValues(UserItemDataDto dto, UserItemData userData, BaseItemDto itemDto, User user, List<ItemFields> fields)
+ public virtual void FillUserDataDtoValues(UserItemDataDto dto, UserItemData userData, BaseItemDto itemDto, User user, ItemFields[] fields)
{
if (RunTimeTicks.HasValue)
{
@@ -2270,12 +2303,12 @@ namespace MediaBrowser.Controller.Entities
if (!item.Studios.SequenceEqual(ownedItem.Studios, StringComparer.Ordinal))
{
newOptions.ForceSave = true;
- ownedItem.Studios = item.Studios.ToList();
+ ownedItem.Studios = item.Studios;
}
if (!item.ProductionLocations.SequenceEqual(ownedItem.ProductionLocations, StringComparer.Ordinal))
{
newOptions.ForceSave = true;
- ownedItem.ProductionLocations = item.ProductionLocations.ToList();
+ ownedItem.ProductionLocations = item.ProductionLocations;
}
if (item.CommunityRating != ownedItem.CommunityRating)
{
@@ -2334,7 +2367,9 @@ namespace MediaBrowser.Controller.Entities
public string GetEtag(User user)
{
- return string.Join("|", GetEtagValues(user).ToArray()).GetMD5().ToString("N");
+ var list = GetEtagValues(user);
+
+ return string.Join("|", list.ToArray(list.Count)).GetMD5().ToString("N");
}
protected virtual List<string> GetEtagValues(User user)
@@ -2357,7 +2392,14 @@ namespace MediaBrowser.Controller.Entities
return this;
}
- return GetParents().FirstOrDefault(i => i.IsTopParent);
+ foreach (var parent in GetParents())
+ {
+ if (parent.IsTopParent)
+ {
+ return parent;
+ }
+ }
+ return null;
}
[IgnoreDataMember]
diff --git a/MediaBrowser.Controller/Entities/Book.cs b/MediaBrowser.Controller/Entities/Book.cs
index 7cb242589..9b1a52f83 100644
--- a/MediaBrowser.Controller/Entities/Book.cs
+++ b/MediaBrowser.Controller/Entities/Book.cs
@@ -1,7 +1,7 @@
using System;
+using System.Linq;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Configuration;
-using System.Linq;
using MediaBrowser.Model.Serialization;
using MediaBrowser.Model.Entities;
diff --git a/MediaBrowser.Controller/Entities/CollectionFolder.cs b/MediaBrowser.Controller/Entities/CollectionFolder.cs
index d88b7da34..537beb26b 100644
--- a/MediaBrowser.Controller/Entities/CollectionFolder.cs
+++ b/MediaBrowser.Controller/Entities/CollectionFolder.cs
@@ -27,17 +27,8 @@ namespace MediaBrowser.Controller.Entities
public CollectionFolder()
{
- PhysicalLocationsList = new List<string>();
- PhysicalFolderIds = new List<Guid>();
- }
-
- [IgnoreDataMember]
- protected override bool SupportsShortcutChildren
- {
- get
- {
- return true;
- }
+ PhysicalLocationsList = EmptyStringArray;
+ PhysicalFolderIds = EmptyGuidArray;
}
[IgnoreDataMember]
@@ -149,7 +140,7 @@ namespace MediaBrowser.Controller.Entities
}
[IgnoreDataMember]
- public override IEnumerable<string> PhysicalLocations
+ public override string[] PhysicalLocations
{
get
{
@@ -162,10 +153,10 @@ namespace MediaBrowser.Controller.Entities
return true;
}
- public List<string> PhysicalLocationsList { get; set; }
- public List<Guid> PhysicalFolderIds { get; set; }
+ public string[] PhysicalLocationsList { get; set; }
+ public Guid[] PhysicalFolderIds { get; set; }
- protected override IEnumerable<FileSystemMetadata> GetFileSystemChildren(IDirectoryService directoryService)
+ protected override FileSystemMetadata[] GetFileSystemChildren(IDirectoryService directoryService)
{
return CreateResolveArgs(directoryService, true).FileSystemChildren;
}
@@ -177,9 +168,9 @@ namespace MediaBrowser.Controller.Entities
if (!changed)
{
- var locations = PhysicalLocations.ToList();
+ var locations = PhysicalLocations;
- var newLocations = CreateResolveArgs(new DirectoryService(Logger, FileSystem), false).PhysicalLocations.ToList();
+ var newLocations = CreateResolveArgs(new DirectoryService(Logger, FileSystem), false).PhysicalLocations;
if (!locations.SequenceEqual(newLocations))
{
@@ -189,7 +180,7 @@ namespace MediaBrowser.Controller.Entities
if (!changed)
{
- var folderIds = PhysicalFolderIds.ToList();
+ var folderIds = PhysicalFolderIds;
var newFolderIds = GetPhysicalFolders(false).Select(i => i.Id).ToList();
@@ -249,17 +240,17 @@ namespace MediaBrowser.Controller.Entities
var changed = !linkedChildren.SequenceEqual(LinkedChildren, new LinkedChildComparer(FileSystem));
- LinkedChildren = linkedChildren;
+ LinkedChildren = linkedChildren.ToArray(linkedChildren.Count);
- var folderIds = PhysicalFolderIds.ToList();
- var newFolderIds = physicalFolders.Select(i => i.Id).ToList();
+ var folderIds = PhysicalFolderIds;
+ var newFolderIds = physicalFolders.Select(i => i.Id).ToArray();
if (!folderIds.SequenceEqual(newFolderIds))
{
changed = true;
if (setFolders)
{
- PhysicalFolderIds = newFolderIds.ToList();
+ PhysicalFolderIds = newFolderIds;
}
}
@@ -301,24 +292,22 @@ namespace MediaBrowser.Controller.Entities
// When resolving the root, we need it's grandchildren (children of user views)
var flattenFolderDepth = isPhysicalRoot ? 2 : 0;
- var fileSystemDictionary = FileData.GetFilteredFileSystemEntries(directoryService, args.Path, FileSystem, Logger, args, flattenFolderDepth: flattenFolderDepth, resolveShortcuts: isPhysicalRoot || args.IsVf);
+ var files = FileData.GetFilteredFileSystemEntries(directoryService, args.Path, FileSystem, Logger, args, flattenFolderDepth: flattenFolderDepth, resolveShortcuts: isPhysicalRoot || args.IsVf);
// Need to remove subpaths that may have been resolved from shortcuts
// Example: if \\server\movies exists, then strip out \\server\movies\action
if (isPhysicalRoot)
{
- var paths = LibraryManager.NormalizeRootPathList(fileSystemDictionary.Values);
-
- fileSystemDictionary = paths.ToDictionary(i => i.FullName);
+ files = LibraryManager.NormalizeRootPathList(files).ToArray();
}
- args.FileSystemDictionary = fileSystemDictionary;
+ args.FileSystemChildren = files;
}
_requiresRefresh = _requiresRefresh || !args.PhysicalLocations.SequenceEqual(PhysicalLocations);
if (setPhysicalLocations)
{
- PhysicalLocationsList = args.PhysicalLocations.ToList();
+ PhysicalLocationsList = args.PhysicalLocations;
}
return args;
diff --git a/MediaBrowser.Controller/Entities/Extensions.cs b/MediaBrowser.Controller/Entities/Extensions.cs
index 5e792a03a..36855a86c 100644
--- a/MediaBrowser.Controller/Entities/Extensions.cs
+++ b/MediaBrowser.Controller/Entities/Extensions.cs
@@ -1,6 +1,7 @@
using MediaBrowser.Model.Entities;
using System;
using System.Linq;
+using MediaBrowser.Model.Extensions;
namespace MediaBrowser.Controller.Entities
{
@@ -12,11 +13,7 @@ namespace MediaBrowser.Controller.Entities
/// <summary>
/// Adds the trailer URL.
/// </summary>
- /// <param name="item">The item.</param>
- /// <param name="url">The URL.</param>
- /// <param name="isDirectLink">if set to <c>true</c> [is direct link].</param>
- /// <exception cref="System.ArgumentNullException">url</exception>
- public static void AddTrailerUrl(this IHasTrailers item, string url, bool isDirectLink)
+ public static void AddTrailerUrl(this IHasTrailers item, string url)
{
if (string.IsNullOrWhiteSpace(url))
{
@@ -27,10 +24,22 @@ namespace MediaBrowser.Controller.Entities
if (current == null)
{
- item.RemoteTrailers.Add(new MediaUrl
+ var mediaUrl = new MediaUrl
{
Url = url
- });
+ };
+
+ if (item.RemoteTrailers.Length == 0)
+ {
+ item.RemoteTrailers = new[] { mediaUrl };
+ }
+ else
+ {
+ var list = item.RemoteTrailers.ToArray(item.RemoteTrailers.Length + 1);
+ list[list.Length - 1] = mediaUrl;
+
+ item.RemoteTrailers = list;
+ }
}
}
}
diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs
index 5d74cf218..2e741a8c4 100644
--- a/MediaBrowser.Controller/Entities/Folder.cs
+++ b/MediaBrowser.Controller/Entities/Folder.cs
@@ -20,6 +20,7 @@ using MediaBrowser.Controller.IO;
using MediaBrowser.Model.Channels;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Serialization;
+using MediaBrowser.Model.Extensions;
namespace MediaBrowser.Controller.Entities
{
@@ -37,14 +38,14 @@ namespace MediaBrowser.Controller.Entities
/// <value><c>true</c> if this instance is root; otherwise, <c>false</c>.</value>
public bool IsRoot { get; set; }
- public virtual List<LinkedChild> LinkedChildren { get; set; }
+ public LinkedChild[] LinkedChildren { get; set; }
[IgnoreDataMember]
public DateTime? DateLastMediaAdded { get; set; }
public Folder()
{
- LinkedChildren = new List<LinkedChild>();
+ LinkedChildren = EmptyLinkedChildArray;
}
[IgnoreDataMember]
@@ -185,7 +186,7 @@ namespace MediaBrowser.Controller.Entities
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
/// <exception cref="System.InvalidOperationException">Unable to add + item.Name</exception>
- public async Task AddChild(BaseItem item, CancellationToken cancellationToken)
+ public void AddChild(BaseItem item, CancellationToken cancellationToken)
{
item.SetParent(this);
@@ -208,7 +209,7 @@ namespace MediaBrowser.Controller.Entities
item.DateModified = DateTime.UtcNow;
}
- await LibraryManager.CreateItem(item, cancellationToken).ConfigureAwait(false);
+ LibraryManager.CreateItem(item, cancellationToken);
}
/// <summary>
@@ -468,7 +469,7 @@ namespace MediaBrowser.Controller.Entities
}
}
- await LibraryManager.CreateItems(newItems, cancellationToken).ConfigureAwait(false);
+ LibraryManager.CreateItems(newItems, cancellationToken);
}
}
else
@@ -647,15 +648,15 @@ namespace MediaBrowser.Controller.Entities
public static bool IsPathOffline(string path, List<string> allLibraryPaths)
{
- if (FileSystem.FileExists(path))
- {
- return false;
- }
+ //if (FileSystem.FileExists(path))
+ //{
+ // return false;
+ //}
var originalPath = path;
// Depending on whether the path is local or unc, it may return either null or '\' at the top
- while (!string.IsNullOrEmpty(path) && path.Length > 1)
+ while (!string.IsNullOrWhiteSpace(path) && path.Length > 1)
{
if (FileSystem.DirectoryExists(path))
{
@@ -706,11 +707,11 @@ namespace MediaBrowser.Controller.Entities
public virtual int GetChildCount(User user)
{
- if (LinkedChildren.Count > 0)
+ if (LinkedChildren.Length > 0)
{
if (!(this is ICollectionFolder))
{
- return GetChildren(user, true).Count();
+ return GetChildren(user, true).Count;
}
}
@@ -797,10 +798,10 @@ namespace MediaBrowser.Controller.Entities
if (user != null)
{
// needed for boxsets
- itemsList = itemsList.Where(i => i.IsVisibleStandalone(query.User));
+ itemsList = itemsList.Where(i => i.IsVisibleStandalone(query.User)).ToList();
}
- IEnumerable<BaseItem> returnItems;
+ BaseItem[] returnItems;
int totalCount = 0;
if (query.EnableTotalRecordCount)
@@ -811,16 +812,16 @@ namespace MediaBrowser.Controller.Entities
}
else
{
- returnItems = itemsList;
+ returnItems = itemsList.ToArray();
}
if (limit.HasValue)
{
- returnItems = returnItems.Skip(startIndex ?? 0).Take(limit.Value);
+ returnItems = returnItems.Skip(startIndex ?? 0).Take(limit.Value).ToArray();
}
else if (startIndex.HasValue)
{
- returnItems = returnItems.Skip(startIndex.Value);
+ returnItems = returnItems.Skip(startIndex.Value).ToArray();
}
return new QueryResult<BaseItem>
@@ -843,7 +844,7 @@ namespace MediaBrowser.Controller.Entities
private bool RequiresPostFiltering(InternalItemsQuery query)
{
- if (LinkedChildren.Count > 0)
+ if (LinkedChildren.Length > 0)
{
if (!(this is ICollectionFolder))
{
@@ -921,12 +922,6 @@ namespace MediaBrowser.Controller.Entities
return true;
}
- if (query.AirDays.Length > 0)
- {
- Logger.Debug("Query requires post-filtering due to AirDays");
- return true;
- }
-
if (query.SeriesStatuses.Length > 0)
{
Logger.Debug("Query requires post-filtering due to SeriesStatuses");
@@ -957,7 +952,7 @@ namespace MediaBrowser.Controller.Entities
{
var result = LibraryManager.GetItemsResult(query);
- if (query.SortBy.Length == 0)
+ if (query.OrderBy.Length == 0)
{
var ids = query.ItemIds.ToList();
@@ -970,6 +965,27 @@ namespace MediaBrowser.Controller.Entities
return GetItemsInternal(query);
}
+ public BaseItem[] GetItemList(InternalItemsQuery query)
+ {
+ query.EnableTotalRecordCount = false;
+
+ if (query.ItemIds.Length > 0)
+ {
+ var result = LibraryManager.GetItemList(query);
+
+ if (query.OrderBy.Length == 0)
+ {
+ var ids = query.ItemIds.ToList();
+
+ // Try to preserve order
+ return result.OrderBy(i => ids.IndexOf(i.Id.ToString("N"))).ToArray();
+ }
+ return result.ToArray(result.Count);
+ }
+
+ return GetItemsInternal(query).Items;
+ }
+
protected virtual QueryResult<BaseItem> GetItemsInternal(InternalItemsQuery query)
{
if (SourceType == SourceType.Channel)
@@ -984,8 +1000,7 @@ namespace MediaBrowser.Controller.Entities
Limit = query.Limit,
StartIndex = query.StartIndex,
UserId = query.User.Id.ToString("N"),
- SortBy = query.SortBy,
- SortOrder = query.SortOrder
+ OrderBy = query.OrderBy
}, new SimpleProgress<double>(), CancellationToken.None).Result;
}
@@ -1028,7 +1043,7 @@ namespace MediaBrowser.Controller.Entities
return UserViewBuilder.PostFilterAndSort(items, this, null, query, LibraryManager, ConfigurationManager, collapseBoxSetItems, enableSorting);
}
- public virtual IEnumerable<BaseItem> GetChildren(User user, bool includeLinkedChildren)
+ public virtual List<BaseItem> GetChildren(User user, bool includeLinkedChildren)
{
if (user == null)
{
@@ -1042,7 +1057,7 @@ namespace MediaBrowser.Controller.Entities
AddChildren(user, includeLinkedChildren, result, false, null);
- return result.Values;
+ return result.Values.ToList();
}
protected virtual IEnumerable<BaseItem> GetEligibleChildrenForRecursiveChildren(User user)
@@ -1203,7 +1218,7 @@ namespace MediaBrowser.Controller.Entities
return GetLinkedChildren();
}
- if (LinkedChildren.Count == 0)
+ if (LinkedChildren.Length == 0)
{
return new List<BaseItem>();
}
@@ -1292,14 +1307,9 @@ namespace MediaBrowser.Controller.Entities
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
protected virtual bool RefreshLinkedChildren(IEnumerable<FileSystemMetadata> fileSystemChildren)
{
- var currentManualLinks = LinkedChildren.Where(i => i.Type == LinkedChildType.Manual).ToList();
- var currentShortcutLinks = LinkedChildren.Where(i => i.Type == LinkedChildType.Shortcut).ToList();
-
- List<LinkedChild> newShortcutLinks;
-
if (SupportsShortcutChildren)
{
- newShortcutLinks = fileSystemChildren
+ var newShortcutLinks = fileSystemChildren
.Where(i => !i.IsDirectory && FileSystem.IsShortcut(i.FullName))
.Select(i =>
{
@@ -1330,16 +1340,17 @@ namespace MediaBrowser.Controller.Entities
})
.Where(i => i != null)
.ToList();
- }
- else { newShortcutLinks = new List<LinkedChild>(); }
- if (!newShortcutLinks.SequenceEqual(currentShortcutLinks, new LinkedChildComparer(FileSystem)))
- {
- Logger.Info("Shortcut links have changed for {0}", Path);
+ var currentShortcutLinks = LinkedChildren.Where(i => i.Type == LinkedChildType.Shortcut).ToList();
- newShortcutLinks.AddRange(currentManualLinks);
- LinkedChildren = newShortcutLinks;
- return true;
+ if (!newShortcutLinks.SequenceEqual(currentShortcutLinks, new LinkedChildComparer(FileSystem)))
+ {
+ Logger.Info("Shortcut links have changed for {0}", Path);
+
+ newShortcutLinks.AddRange(LinkedChildren.Where(i => i.Type == LinkedChildType.Manual));
+ LinkedChildren = newShortcutLinks.ToArray(newShortcutLinks.Count);
+ return true;
+ }
}
foreach (var child in LinkedChildren)
@@ -1358,7 +1369,7 @@ namespace MediaBrowser.Controller.Entities
/// <param name="datePlayed">The date played.</param>
/// <param name="resetPosition">if set to <c>true</c> [reset position].</param>
/// <returns>Task.</returns>
- public override async Task MarkPlayed(User user,
+ public override void MarkPlayed(User user,
DateTime? datePlayed,
bool resetPosition)
{
@@ -1370,17 +1381,18 @@ namespace MediaBrowser.Controller.Entities
EnableTotalRecordCount = false
};
- if (!user.Configuration.DisplayMissingEpisodes || !user.Configuration.DisplayUnairedEpisodes)
+ if (!user.Configuration.DisplayMissingEpisodes)
{
query.IsVirtualItem = false;
}
- var itemsResult = GetItems(query);
+ var itemsResult = GetItemList(query);
// Sweep through recursively and update status
- var tasks = itemsResult.Items.Select(c => c.MarkPlayed(user, datePlayed, resetPosition));
-
- await Task.WhenAll(tasks).ConfigureAwait(false);
+ foreach (var item in itemsResult)
+ {
+ item.MarkPlayed(user, datePlayed, resetPosition);
+ }
}
/// <summary>
@@ -1388,9 +1400,9 @@ namespace MediaBrowser.Controller.Entities
/// </summary>
/// <param name="user">The user.</param>
/// <returns>Task.</returns>
- public override async Task MarkUnplayed(User user)
+ public override void MarkUnplayed(User user)
{
- var itemsResult = GetItems(new InternalItemsQuery
+ var itemsResult = GetItemList(new InternalItemsQuery
{
User = user,
Recursive = true,
@@ -1400,14 +1412,15 @@ namespace MediaBrowser.Controller.Entities
});
// Sweep through recursively and update status
- var tasks = itemsResult.Items.Select(c => c.MarkUnplayed(user));
-
- await Task.WhenAll(tasks).ConfigureAwait(false);
+ foreach (var item in itemsResult)
+ {
+ item.MarkUnplayed(user);
+ }
}
public override bool IsPlayed(User user)
{
- var itemsResult = GetItems(new InternalItemsQuery(user)
+ var itemsResult = GetItemList(new InternalItemsQuery(user)
{
Recursive = true,
IsFolder = false,
@@ -1416,7 +1429,7 @@ namespace MediaBrowser.Controller.Entities
});
- return itemsResult.Items
+ return itemsResult
.All(i => i.IsPlayed(user));
}
@@ -1465,7 +1478,7 @@ namespace MediaBrowser.Controller.Entities
}
}
- public override void FillUserDataDtoValues(UserItemDataDto dto, UserItemData userData, BaseItemDto itemDto, User user, List<ItemFields> fields)
+ public override void FillUserDataDtoValues(UserItemDataDto dto, UserItemData userData, BaseItemDto itemDto, User user, ItemFields[] fields)
{
if (!SupportsUserDataFromChildren)
{
diff --git a/MediaBrowser.Controller/Entities/Game.cs b/MediaBrowser.Controller/Entities/Game.cs
index baefc9dfa..a99058925 100644
--- a/MediaBrowser.Controller/Entities/Game.cs
+++ b/MediaBrowser.Controller/Entities/Game.cs
@@ -3,7 +3,6 @@ using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Entities;
using System;
using System.Collections.Generic;
-using System.Linq;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Serialization;
@@ -13,14 +12,14 @@ namespace MediaBrowser.Controller.Entities
{
public Game()
{
- MultiPartGameFiles = new List<string>();
- RemoteTrailers = new List<MediaUrl>();
- LocalTrailerIds = new List<Guid>();
- RemoteTrailerIds = new List<Guid>();
+ MultiPartGameFiles = EmptyStringArray;
+ RemoteTrailers = EmptyMediaUrlArray;
+ LocalTrailerIds = EmptyGuidArray;
+ RemoteTrailerIds = EmptyGuidArray;
}
- public List<Guid> LocalTrailerIds { get; set; }
- public List<Guid> RemoteTrailerIds { get; set; }
+ public Guid[] LocalTrailerIds { get; set; }
+ public Guid[] RemoteTrailerIds { get; set; }
public override bool CanDownload()
{
@@ -45,7 +44,7 @@ namespace MediaBrowser.Controller.Entities
/// Gets or sets the remote trailers.
/// </summary>
/// <value>The remote trailers.</value>
- public List<MediaUrl> RemoteTrailers { get; set; }
+ public MediaUrl[] RemoteTrailers { get; set; }
/// <summary>
/// Gets the type of the media.
@@ -84,7 +83,7 @@ namespace MediaBrowser.Controller.Entities
/// <summary>
/// Holds the paths to the game files in the event this is a multipart game
/// </summary>
- public List<string> MultiPartGameFiles { get; set; }
+ public string[] MultiPartGameFiles { get; set; }
public override List<string> GetUserDataKeys()
{
@@ -100,7 +99,7 @@ namespace MediaBrowser.Controller.Entities
public override IEnumerable<FileSystemMetadata> GetDeletePaths()
{
- if (!DetectIsInMixedFolder())
+ if (!IsInMixedFolder)
{
return new[] {
new FileSystemMetadata
@@ -127,16 +126,5 @@ namespace MediaBrowser.Controller.Entities
return id;
}
-
- /// <summary>
- /// Gets the trailer ids.
- /// </summary>
- /// <returns>List&lt;Guid&gt;.</returns>
- public List<Guid> GetTrailerIds()
- {
- var list = LocalTrailerIds.ToList();
- list.AddRange(RemoteTrailerIds);
- return list;
- }
}
}
diff --git a/MediaBrowser.Controller/Entities/GameGenre.cs b/MediaBrowser.Controller/Entities/GameGenre.cs
index 836020d88..4e78a7fa5 100644
--- a/MediaBrowser.Controller/Entities/GameGenre.cs
+++ b/MediaBrowser.Controller/Entities/GameGenre.cs
@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
-using System.Linq;
using MediaBrowser.Model.Serialization;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Controller.Extensions;
diff --git a/MediaBrowser.Controller/Entities/Genre.cs b/MediaBrowser.Controller/Entities/Genre.cs
index 4b70eae58..790f8938e 100644
--- a/MediaBrowser.Controller/Entities/Genre.cs
+++ b/MediaBrowser.Controller/Entities/Genre.cs
@@ -2,7 +2,6 @@
using MediaBrowser.Controller.Entities.Audio;
using System;
using System.Collections.Generic;
-using System.Linq;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Controller.Extensions;
using MediaBrowser.Model.Extensions;
diff --git a/MediaBrowser.Controller/Entities/ICollectionFolder.cs b/MediaBrowser.Controller/Entities/ICollectionFolder.cs
index d8b02034c..b70ad322d 100644
--- a/MediaBrowser.Controller/Entities/ICollectionFolder.cs
+++ b/MediaBrowser.Controller/Entities/ICollectionFolder.cs
@@ -13,7 +13,7 @@ namespace MediaBrowser.Controller.Entities
string Path { get; }
string Name { get; }
Guid Id { get; }
- IEnumerable<string> PhysicalLocations { get; }
+ string[] PhysicalLocations { get; }
}
public interface ISupportsUserSpecificView
diff --git a/MediaBrowser.Controller/Entities/IHasId.cs b/MediaBrowser.Controller/Entities/IHasId.cs
deleted file mode 100644
index 9698adf7a..000000000
--- a/MediaBrowser.Controller/Entities/IHasId.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-using System;
-
-namespace MediaBrowser.Controller.Entities
-{
- public interface IHasId
- {
- Guid Id { get; }
- }
-}
diff --git a/MediaBrowser.Controller/Entities/IHasImages.cs b/MediaBrowser.Controller/Entities/IHasImages.cs
deleted file mode 100644
index e2b3c0777..000000000
--- a/MediaBrowser.Controller/Entities/IHasImages.cs
+++ /dev/null
@@ -1,264 +0,0 @@
-using MediaBrowser.Controller.Providers;
-using MediaBrowser.Model.Entities;
-using System.Collections.Generic;
-using System.Threading;
-using System.Threading.Tasks;
-
-using MediaBrowser.Controller.IO;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Model.IO;
-
-namespace MediaBrowser.Controller.Entities
-{
- public interface IHasImages : IHasProviderIds, IHasId
- {
- /// <summary>
- /// Gets the name.
- /// </summary>
- /// <value>The name.</value>
- string Name { get; set; }
-
- /// <summary>
- /// Gets the path.
- /// </summary>
- /// <value>The path.</value>
- string Path { get; set; }
-
- /// <summary>
- /// Gets the file name without extension.
- /// </summary>
- /// <value>The file name without extension.</value>
- string FileNameWithoutExtension { get; }
-
- /// <summary>
- /// Gets the type of the location.
- /// </summary>
- /// <value>The type of the location.</value>
- LocationType LocationType { get; }
-
- /// <summary>
- /// Gets the locked fields.
- /// </summary>
- /// <value>The locked fields.</value>
- List<MetadataFields> LockedFields { get; }
-
- /// <summary>
- /// Gets the images.
- /// </summary>
- /// <param name="imageType">Type of the image.</param>
- /// <returns>IEnumerable{ItemImageInfo}.</returns>
- IEnumerable<ItemImageInfo> GetImages(ImageType imageType);
-
- /// <summary>
- /// Gets the image path.
- /// </summary>
- /// <param name="imageType">Type of the image.</param>
- /// <param name="imageIndex">Index of the image.</param>
- /// <returns>System.String.</returns>
- string GetImagePath(ImageType imageType, int imageIndex);
-
- /// <summary>
- /// Gets the image information.
- /// </summary>
- /// <param name="imageType">Type of the image.</param>
- /// <param name="imageIndex">Index of the image.</param>
- /// <returns>ItemImageInfo.</returns>
- ItemImageInfo GetImageInfo(ImageType imageType, int imageIndex);
-
- /// <summary>
- /// Sets the image.
- /// </summary>
- /// <param name="type">The type.</param>
- /// <param name="index">The index.</param>
- /// <param name="file">The file.</param>
- void SetImagePath(ImageType type, int index, FileSystemMetadata file);
-
- /// <summary>
- /// Determines whether the specified type has image.
- /// </summary>
- /// <param name="type">The type.</param>
- /// <param name="imageIndex">Index of the image.</param>
- /// <returns><c>true</c> if the specified type has image; otherwise, <c>false</c>.</returns>
- bool HasImage(ImageType type, int imageIndex);
-
- /// <summary>
- /// Allowses the multiple images.
- /// </summary>
- /// <param name="type">The type.</param>
- /// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
- bool AllowsMultipleImages(ImageType type);
-
- /// <summary>
- /// Swaps the images.
- /// </summary>
- /// <param name="type">The type.</param>
- /// <param name="index1">The index1.</param>
- /// <param name="index2">The index2.</param>
- /// <returns>Task.</returns>
- Task SwapImages(ImageType type, int index1, int index2);
-
- /// <summary>
- /// Gets the display type of the media.
- /// </summary>
- /// <value>The display type of the media.</value>
- string DisplayMediaType { get; set; }
-
- /// <summary>
- /// Gets or sets the primary image path.
- /// </summary>
- /// <value>The primary image path.</value>
- string PrimaryImagePath { get; }
-
- /// <summary>
- /// Gets the preferred metadata language.
- /// </summary>
- /// <returns>System.String.</returns>
- string GetPreferredMetadataLanguage();
-
- /// <summary>
- /// Validates the images and returns true or false indicating if any were removed.
- /// </summary>
- bool ValidateImages(IDirectoryService directoryService);
-
- /// <summary>
- /// Gets a value indicating whether this instance is owned item.
- /// </summary>
- /// <value><c>true</c> if this instance is owned item; otherwise, <c>false</c>.</value>
- bool IsOwnedItem { get; }
-
- /// <summary>
- /// Gets the containing folder path.
- /// </summary>
- /// <value>The containing folder path.</value>
- string ContainingFolderPath { get; }
-
- /// <summary>
- /// Adds the images.
- /// </summary>
- /// <param name="imageType">Type of the image.</param>
- /// <param name="images">The images.</param>
- /// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
- bool AddImages(ImageType imageType, List<FileSystemMetadata> images);
-
- /// <summary>
- /// Determines whether [is save local metadata enabled].
- /// </summary>
- /// <returns><c>true</c> if [is save local metadata enabled]; otherwise, <c>false</c>.</returns>
- bool IsSaveLocalMetadataEnabled();
-
- /// <summary>
- /// Gets a value indicating whether [supports local metadata].
- /// </summary>
- /// <value><c>true</c> if [supports local metadata]; otherwise, <c>false</c>.</value>
- bool SupportsLocalMetadata { get; }
-
- bool DetectIsInMixedFolder();
-
- /// <summary>
- /// Gets a value indicating whether this instance is locked.
- /// </summary>
- /// <value><c>true</c> if this instance is locked; otherwise, <c>false</c>.</value>
- bool IsLocked { get; }
-
- /// <summary>
- /// Gets a value indicating whether [supports remote image downloading].
- /// </summary>
- /// <value><c>true</c> if [supports remote image downloading]; otherwise, <c>false</c>.</value>
- bool SupportsRemoteImageDownloading { get; }
-
- /// <summary>
- /// Gets the internal metadata path.
- /// </summary>
- /// <returns>System.String.</returns>
- string GetInternalMetadataPath();
-
- /// <summary>
- /// Gets a value indicating whether [always scan internal metadata path].
- /// </summary>
- /// <value><c>true</c> if [always scan internal metadata path]; otherwise, <c>false</c>.</value>
- bool AlwaysScanInternalMetadataPath { get; }
-
- /// <summary>
- /// Determines whether [is internet metadata enabled].
- /// </summary>
- /// <returns><c>true</c> if [is internet metadata enabled]; otherwise, <c>false</c>.</returns>
- bool IsInternetMetadataEnabled();
-
- /// <summary>
- /// Removes the image.
- /// </summary>
- /// <param name="image">The image.</param>
- void RemoveImage(ItemImageInfo image);
-
- /// <summary>
- /// Updates to repository.
- /// </summary>
- /// <param name="updateReason">The update reason.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- Task UpdateToRepository(ItemUpdateType updateReason, CancellationToken cancellationToken);
-
- /// <summary>
- /// Sets the image.
- /// </summary>
- /// <param name="image">The image.</param>
- /// <param name="index">The index.</param>
- void SetImage(ItemImageInfo image, int index);
-
- double? GetDefaultPrimaryImageAspectRatio();
-
- int? ProductionYear { get; set; }
- }
-
- public static class HasImagesExtensions
- {
- /// <summary>
- /// Gets the image path.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="imageType">Type of the image.</param>
- /// <returns>System.String.</returns>
- public static string GetImagePath(this IHasImages item, ImageType imageType)
- {
- return item.GetImagePath(imageType, 0);
- }
-
- public static bool HasImage(this IHasImages item, ImageType imageType)
- {
- return item.HasImage(imageType, 0);
- }
-
- /// <summary>
- /// Sets the image path.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="imageType">Type of the image.</param>
- /// <param name="file">The file.</param>
- public static void SetImagePath(this IHasImages item, ImageType imageType, FileSystemMetadata file)
- {
- item.SetImagePath(imageType, 0, file);
- }
-
- /// <summary>
- /// Sets the image path.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="imageType">Type of the image.</param>
- /// <param name="file">The file.</param>
- public static void SetImagePath(this IHasImages item, ImageType imageType, string file)
- {
- if (file.StartsWith("http", System.StringComparison.OrdinalIgnoreCase))
- {
- item.SetImage(new ItemImageInfo
- {
- Path = file,
- Type = imageType
- }, 0);
- }
- else
- {
- item.SetImagePath(imageType, BaseItem.FileSystem.GetFileInfo(file));
- }
- }
- }
-}
diff --git a/MediaBrowser.Controller/Entities/IHasMediaSources.cs b/MediaBrowser.Controller/Entities/IHasMediaSources.cs
index 832b9f6c1..54786134f 100644
--- a/MediaBrowser.Controller/Entities/IHasMediaSources.cs
+++ b/MediaBrowser.Controller/Entities/IHasMediaSources.cs
@@ -1,15 +1,17 @@
using MediaBrowser.Model.Dto;
using System.Collections.Generic;
+using MediaBrowser.Model.Entities;
namespace MediaBrowser.Controller.Entities
{
- public interface IHasMediaSources : IHasUserData
+ public interface IHasMediaSources : IHasMetadata
{
/// <summary>
/// Gets the media sources.
/// </summary>
/// <param name="enablePathSubstitution">if set to <c>true</c> [enable path substitution].</param>
/// <returns>Task{IEnumerable{MediaSourceInfo}}.</returns>
- IEnumerable<MediaSourceInfo> GetMediaSources(bool enablePathSubstitution);
+ List<MediaSourceInfo> GetMediaSources(bool enablePathSubstitution);
+ List<MediaStream> GetMediaStreams();
}
}
diff --git a/MediaBrowser.Controller/Entities/IHasMetadata.cs b/MediaBrowser.Controller/Entities/IHasMetadata.cs
index 62c67336c..59d9bd9f9 100644
--- a/MediaBrowser.Controller/Entities/IHasMetadata.cs
+++ b/MediaBrowser.Controller/Entities/IHasMetadata.cs
@@ -1,12 +1,18 @@
using System;
using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
+using MediaBrowser.Controller.Library;
+using MediaBrowser.Controller.Providers;
+using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.IO;
namespace MediaBrowser.Controller.Entities
{
/// <summary>
/// Interface IHasMetadata
/// </summary>
- public interface IHasMetadata : IHasImages
+ public interface IHasMetadata : IHasProviderIds, IHasUserData
{
/// <summary>
/// Gets the preferred metadata country code.
@@ -64,6 +70,253 @@ namespace MediaBrowser.Controller.Entities
int? GetInheritedParentalRatingValue();
int InheritedParentalRatingValue { get; set; }
List<string> GetInheritedTags();
- List<string> InheritedTags { get; set; }
+ long? RunTimeTicks { get; set; }
+
+ /// <summary>
+ /// Gets the name.
+ /// </summary>
+ /// <value>The name.</value>
+ string Name { get; set; }
+
+ /// <summary>
+ /// Gets the path.
+ /// </summary>
+ /// <value>The path.</value>
+ string Path { get; set; }
+
+ /// <summary>
+ /// Gets the file name without extension.
+ /// </summary>
+ /// <value>The file name without extension.</value>
+ string FileNameWithoutExtension { get; }
+
+ /// <summary>
+ /// Gets the type of the location.
+ /// </summary>
+ /// <value>The type of the location.</value>
+ LocationType LocationType { get; }
+
+ /// <summary>
+ /// Gets the locked fields.
+ /// </summary>
+ /// <value>The locked fields.</value>
+ MetadataFields[] LockedFields { get; }
+
+ /// <summary>
+ /// Gets the images.
+ /// </summary>
+ /// <param name="imageType">Type of the image.</param>
+ /// <returns>IEnumerable{ItemImageInfo}.</returns>
+ IEnumerable<ItemImageInfo> GetImages(ImageType imageType);
+
+ /// <summary>
+ /// Gets the image path.
+ /// </summary>
+ /// <param name="imageType">Type of the image.</param>
+ /// <param name="imageIndex">Index of the image.</param>
+ /// <returns>System.String.</returns>
+ string GetImagePath(ImageType imageType, int imageIndex);
+
+ /// <summary>
+ /// Gets the image information.
+ /// </summary>
+ /// <param name="imageType">Type of the image.</param>
+ /// <param name="imageIndex">Index of the image.</param>
+ /// <returns>ItemImageInfo.</returns>
+ ItemImageInfo GetImageInfo(ImageType imageType, int imageIndex);
+
+ /// <summary>
+ /// Sets the image.
+ /// </summary>
+ /// <param name="type">The type.</param>
+ /// <param name="index">The index.</param>
+ /// <param name="file">The file.</param>
+ void SetImagePath(ImageType type, int index, FileSystemMetadata file);
+
+ /// <summary>
+ /// Determines whether the specified type has image.
+ /// </summary>
+ /// <param name="type">The type.</param>
+ /// <param name="imageIndex">Index of the image.</param>
+ /// <returns><c>true</c> if the specified type has image; otherwise, <c>false</c>.</returns>
+ bool HasImage(ImageType type, int imageIndex);
+
+ /// <summary>
+ /// Allowses the multiple images.
+ /// </summary>
+ /// <param name="type">The type.</param>
+ /// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
+ bool AllowsMultipleImages(ImageType type);
+
+ /// <summary>
+ /// Swaps the images.
+ /// </summary>
+ /// <param name="type">The type.</param>
+ /// <param name="index1">The index1.</param>
+ /// <param name="index2">The index2.</param>
+ /// <returns>Task.</returns>
+ Task SwapImages(ImageType type, int index1, int index2);
+
+ /// <summary>
+ /// Gets or sets the primary image path.
+ /// </summary>
+ /// <value>The primary image path.</value>
+ string PrimaryImagePath { get; }
+
+ /// <summary>
+ /// Gets the preferred metadata language.
+ /// </summary>
+ /// <returns>System.String.</returns>
+ string GetPreferredMetadataLanguage();
+
+ /// <summary>
+ /// Validates the images and returns true or false indicating if any were removed.
+ /// </summary>
+ bool ValidateImages(IDirectoryService directoryService);
+
+ /// <summary>
+ /// Gets a value indicating whether this instance is owned item.
+ /// </summary>
+ /// <value><c>true</c> if this instance is owned item; otherwise, <c>false</c>.</value>
+ bool IsOwnedItem { get; }
+
+ /// <summary>
+ /// Gets the containing folder path.
+ /// </summary>
+ /// <value>The containing folder path.</value>
+ string ContainingFolderPath { get; }
+
+ /// <summary>
+ /// Adds the images.
+ /// </summary>
+ /// <param name="imageType">Type of the image.</param>
+ /// <param name="images">The images.</param>
+ /// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
+ bool AddImages(ImageType imageType, List<FileSystemMetadata> images);
+
+ /// <summary>
+ /// Determines whether [is save local metadata enabled].
+ /// </summary>
+ /// <returns><c>true</c> if [is save local metadata enabled]; otherwise, <c>false</c>.</returns>
+ bool IsSaveLocalMetadataEnabled();
+
+ /// <summary>
+ /// Gets a value indicating whether [supports local metadata].
+ /// </summary>
+ /// <value><c>true</c> if [supports local metadata]; otherwise, <c>false</c>.</value>
+ bool SupportsLocalMetadata { get; }
+
+ bool IsInMixedFolder { get; }
+
+ /// <summary>
+ /// Gets a value indicating whether this instance is locked.
+ /// </summary>
+ /// <value><c>true</c> if this instance is locked; otherwise, <c>false</c>.</value>
+ bool IsLocked { get; }
+
+ /// <summary>
+ /// Gets a value indicating whether [supports remote image downloading].
+ /// </summary>
+ /// <value><c>true</c> if [supports remote image downloading]; otherwise, <c>false</c>.</value>
+ bool SupportsRemoteImageDownloading { get; }
+
+ /// <summary>
+ /// Gets the internal metadata path.
+ /// </summary>
+ /// <returns>System.String.</returns>
+ string GetInternalMetadataPath();
+
+ /// <summary>
+ /// Gets a value indicating whether [always scan internal metadata path].
+ /// </summary>
+ /// <value><c>true</c> if [always scan internal metadata path]; otherwise, <c>false</c>.</value>
+ bool AlwaysScanInternalMetadataPath { get; }
+
+ /// <summary>
+ /// Determines whether [is internet metadata enabled].
+ /// </summary>
+ /// <returns><c>true</c> if [is internet metadata enabled]; otherwise, <c>false</c>.</returns>
+ bool IsInternetMetadataEnabled();
+
+ /// <summary>
+ /// Removes the image.
+ /// </summary>
+ /// <param name="image">The image.</param>
+ void RemoveImage(ItemImageInfo image);
+
+ void RemoveImages(List<ItemImageInfo> images);
+
+ /// <summary>
+ /// Updates to repository.
+ /// </summary>
+ /// <param name="updateReason">The update reason.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>Task.</returns>
+ Task UpdateToRepository(ItemUpdateType updateReason, CancellationToken cancellationToken);
+
+ /// <summary>
+ /// Sets the image.
+ /// </summary>
+ /// <param name="image">The image.</param>
+ /// <param name="index">The index.</param>
+ void SetImage(ItemImageInfo image, int index);
+
+ double? GetDefaultPrimaryImageAspectRatio();
+
+ int? ProductionYear { get; set; }
+
+ string[] Tags { get; set; }
+ }
+
+ public static class HasMetadataExtensions
+ {
+ /// <summary>
+ /// Gets the image path.
+ /// </summary>
+ /// <param name="item">The item.</param>
+ /// <param name="imageType">Type of the image.</param>
+ /// <returns>System.String.</returns>
+ public static string GetImagePath(this IHasMetadata item, ImageType imageType)
+ {
+ return item.GetImagePath(imageType, 0);
+ }
+
+ public static bool HasImage(this IHasMetadata item, ImageType imageType)
+ {
+ return item.HasImage(imageType, 0);
+ }
+
+ /// <summary>
+ /// Sets the image path.
+ /// </summary>
+ /// <param name="item">The item.</param>
+ /// <param name="imageType">Type of the image.</param>
+ /// <param name="file">The file.</param>
+ public static void SetImagePath(this IHasMetadata item, ImageType imageType, FileSystemMetadata file)
+ {
+ item.SetImagePath(imageType, 0, file);
+ }
+
+ /// <summary>
+ /// Sets the image path.
+ /// </summary>
+ /// <param name="item">The item.</param>
+ /// <param name="imageType">Type of the image.</param>
+ /// <param name="file">The file.</param>
+ public static void SetImagePath(this IHasMetadata item, ImageType imageType, string file)
+ {
+ if (file.StartsWith("http", System.StringComparison.OrdinalIgnoreCase))
+ {
+ item.SetImage(new ItemImageInfo
+ {
+ Path = file,
+ Type = imageType
+ }, 0);
+ }
+ else
+ {
+ item.SetImagePath(imageType, BaseItem.FileSystem.GetFileInfo(file));
+ }
+ }
}
}
diff --git a/MediaBrowser.Controller/Entities/IHasSpecialFeatures.cs b/MediaBrowser.Controller/Entities/IHasSpecialFeatures.cs
index b3a0dc237..f4905b7dc 100644
--- a/MediaBrowser.Controller/Entities/IHasSpecialFeatures.cs
+++ b/MediaBrowser.Controller/Entities/IHasSpecialFeatures.cs
@@ -1,5 +1,4 @@
using System;
-using System.Collections.Generic;
namespace MediaBrowser.Controller.Entities
{
@@ -9,6 +8,6 @@ namespace MediaBrowser.Controller.Entities
/// Gets or sets the special feature ids.
/// </summary>
/// <value>The special feature ids.</value>
- List<Guid> SpecialFeatureIds { get; set; }
+ Guid[] SpecialFeatureIds { get; set; }
}
}
diff --git a/MediaBrowser.Controller/Entities/IHasTrailers.cs b/MediaBrowser.Controller/Entities/IHasTrailers.cs
index e5cbdff72..8686c802a 100644
--- a/MediaBrowser.Controller/Entities/IHasTrailers.cs
+++ b/MediaBrowser.Controller/Entities/IHasTrailers.cs
@@ -11,14 +11,14 @@ namespace MediaBrowser.Controller.Entities
/// Gets or sets the remote trailers.
/// </summary>
/// <value>The remote trailers.</value>
- List<MediaUrl> RemoteTrailers { get; set; }
+ MediaUrl[] RemoteTrailers { get; set; }
/// <summary>
/// Gets or sets the local trailer ids.
/// </summary>
/// <value>The local trailer ids.</value>
- List<Guid> LocalTrailerIds { get; set; }
- List<Guid> RemoteTrailerIds { get; set; }
+ Guid[] LocalTrailerIds { get; set; }
+ Guid[] RemoteTrailerIds { get; set; }
}
public static class HasTrailerExtensions
diff --git a/MediaBrowser.Controller/Entities/IHasUserData.cs b/MediaBrowser.Controller/Entities/IHasUserData.cs
index 0029947ee..ab4f624e2 100644
--- a/MediaBrowser.Controller/Entities/IHasUserData.cs
+++ b/MediaBrowser.Controller/Entities/IHasUserData.cs
@@ -1,4 +1,5 @@
-using System.Collections.Generic;
+using System;
+using System.Collections.Generic;
using System.Threading.Tasks;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Querying;
@@ -8,17 +9,19 @@ namespace MediaBrowser.Controller.Entities
/// <summary>
/// Interface IHasUserData
/// </summary>
- public interface IHasUserData : IHasId
+ public interface IHasUserData
{
List<string> GetUserDataKeys();
/// <summary>
/// Fills the user data dto values.
/// </summary>
- void FillUserDataDtoValues(UserItemDataDto dto, UserItemData userData, BaseItemDto itemDto, User user, List<ItemFields> fields);
+ void FillUserDataDtoValues(UserItemDataDto dto, UserItemData userData, BaseItemDto itemDto, User user, ItemFields[] fields);
bool EnableRememberingTrackSelections { get; }
bool SupportsPlayedStatus { get; }
+
+ Guid Id { get; }
}
}
diff --git a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs
index 4f21aaa56..03dc18b7a 100644
--- a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs
+++ b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs
@@ -16,10 +16,6 @@ namespace MediaBrowser.Controller.Entities
public int? Limit { get; set; }
- public string[] SortBy { get; set; }
-
- public SortOrder SortOrder { get; set; }
-
public User User { get; set; }
public BaseItem SimilarTo { get; set; }
@@ -42,7 +38,6 @@ namespace MediaBrowser.Controller.Entities
public bool? IsSpecialSeason { get; set; }
public bool? IsMissing { get; set; }
public bool? IsUnaired { get; set; }
- public bool? IsVirtualUnaired { get; set; }
public bool? CollapseBoxSetItems { get; set; }
public string NameStartsWithOrGreater { get; set; }
@@ -149,7 +144,6 @@ namespace MediaBrowser.Controller.Entities
public TrailerType[] TrailerTypes { get; set; }
public SourceType[] SourceTypes { get; set; }
- public DayOfWeek[] AirDays { get; set; }
public SeriesStatus[] SeriesStatuses { get; set; }
public string ExternalSeriesId { get; set; }
public string ExternalId { get; set; }
@@ -161,12 +155,13 @@ namespace MediaBrowser.Controller.Entities
public string SeriesPresentationUniqueKey { get; set; }
public bool GroupByPresentationUniqueKey { get; set; }
+ public bool GroupBySeriesPresentationUniqueKey { get; set; }
public bool EnableTotalRecordCount { get; set; }
public bool ForceDirect { get; set; }
public Dictionary<string, string> ExcludeProviderIds { get; set; }
public bool EnableGroupByMetadataKey { get; set; }
- public List<Tuple<string, SortOrder>> OrderBy { get; set; }
+ public Tuple<string, SortOrder>[] OrderBy { get; set; }
public DateTime? MinDateCreated { get; set; }
public DateTime? MinDateLastSaved { get; set; }
@@ -191,7 +186,6 @@ namespace MediaBrowser.Controller.Entities
BlockUnratedItems = new UnratedItem[] { };
Tags = new string[] { };
OfficialRatings = new string[] { };
- SortBy = new string[] { };
MediaTypes = new string[] { };
IncludeItemTypes = new string[] { };
ExcludeItemTypes = new string[] { };
@@ -213,9 +207,8 @@ namespace MediaBrowser.Controller.Entities
PresetViews = new string[] { };
TrailerTypes = new TrailerType[] { };
SourceTypes = new SourceType[] { };
- AirDays = new DayOfWeek[] { };
SeriesStatuses = new SeriesStatus[] { };
- OrderBy = new List<Tuple<string, SortOrder>>();
+ OrderBy = new Tuple<string, SortOrder>[] { };
}
public InternalItemsQuery(User user)
diff --git a/MediaBrowser.Controller/Entities/InternalPeopleQuery.cs b/MediaBrowser.Controller/Entities/InternalPeopleQuery.cs
index 05d23d986..9e0e9c208 100644
--- a/MediaBrowser.Controller/Entities/InternalPeopleQuery.cs
+++ b/MediaBrowser.Controller/Entities/InternalPeopleQuery.cs
@@ -6,7 +6,7 @@ namespace MediaBrowser.Controller.Entities
public class InternalPeopleQuery
{
public Guid ItemId { get; set; }
- public List<string> PersonTypes { get; set; }
+ public string[] PersonTypes { get; set; }
public List<string> ExcludePersonTypes { get; set; }
public int? MaxListOrder { get; set; }
public Guid AppearsInItemId { get; set; }
@@ -14,7 +14,7 @@ namespace MediaBrowser.Controller.Entities
public InternalPeopleQuery()
{
- PersonTypes = new List<string>();
+ PersonTypes = new string[] {};
ExcludePersonTypes = new List<string>();
}
}
diff --git a/MediaBrowser.Controller/Entities/Movies/BoxSet.cs b/MediaBrowser.Controller/Entities/Movies/BoxSet.cs
index 071ed405f..900e8a664 100644
--- a/MediaBrowser.Controller/Entities/Movies/BoxSet.cs
+++ b/MediaBrowser.Controller/Entities/Movies/BoxSet.cs
@@ -1,5 +1,4 @@
-using MediaBrowser.Controller.Entities.TV;
-using MediaBrowser.Controller.Providers;
+using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Querying;
@@ -8,7 +7,6 @@ using System;
using System.Collections.Generic;
using System.Linq;
using MediaBrowser.Model.Serialization;
-using MediaBrowser.Controller.Entities.Audio;
namespace MediaBrowser.Controller.Entities.Movies
{
@@ -21,9 +19,9 @@ namespace MediaBrowser.Controller.Entities.Movies
public BoxSet()
{
- RemoteTrailers = new List<MediaUrl>();
- LocalTrailerIds = new List<Guid>();
- RemoteTrailerIds = new List<Guid>();
+ RemoteTrailers = EmptyMediaUrlArray;
+ LocalTrailerIds = EmptyGuidArray;
+ RemoteTrailerIds = EmptyGuidArray;
DisplayOrder = ItemSortBy.PremiereDate;
Shares = new List<Share>();
@@ -47,14 +45,14 @@ namespace MediaBrowser.Controller.Entities.Movies
}
}
- public List<Guid> LocalTrailerIds { get; set; }
- public List<Guid> RemoteTrailerIds { get; set; }
+ public Guid[] LocalTrailerIds { get; set; }
+ public Guid[] RemoteTrailerIds { get; set; }
/// <summary>
/// Gets or sets the remote trailers.
/// </summary>
/// <value>The remote trailers.</value>
- public List<MediaUrl> RemoteTrailers { get; set; }
+ public MediaUrl[] RemoteTrailers { get; set; }
/// <summary>
/// Gets or sets the display order.
@@ -82,20 +80,11 @@ namespace MediaBrowser.Controller.Entities.Movies
protected override IEnumerable<BaseItem> GetNonCachedChildren(IDirectoryService directoryService)
{
- if (IsLegacyBoxSet)
- {
- return base.GetNonCachedChildren(directoryService);
- }
return new List<BaseItem>();
}
protected override List<BaseItem> LoadChildren()
{
- if (IsLegacyBoxSet)
- {
- return base.LoadChildren();
- }
-
// Save a trip to the database
return new List<BaseItem>();
}
@@ -109,34 +98,6 @@ namespace MediaBrowser.Controller.Entities.Movies
}
}
- [IgnoreDataMember]
- protected override bool SupportsShortcutChildren
- {
- get
- {
- if (IsLegacyBoxSet)
- {
- return true;
- }
-
- return false;
- }
- }
-
- [IgnoreDataMember]
- private bool IsLegacyBoxSet
- {
- get
- {
- if (string.IsNullOrWhiteSpace(Path))
- {
- return false;
- }
-
- return !FileSystem.ContainsSubPath(ConfigurationManager.ApplicationPaths.DataPath, Path);
- }
- }
-
public override bool IsAuthorizedToDelete(User user)
{
return true;
@@ -148,17 +109,6 @@ namespace MediaBrowser.Controller.Entities.Movies
}
/// <summary>
- /// Gets the trailer ids.
- /// </summary>
- /// <returns>List&lt;Guid&gt;.</returns>
- public List<Guid> GetTrailerIds()
- {
- var list = LocalTrailerIds.ToList();
- list.AddRange(RemoteTrailerIds);
- return list;
- }
-
- /// <summary>
/// Updates the official rating based on content and returns true or false indicating if it changed.
/// </summary>
/// <returns></returns>
@@ -181,24 +131,24 @@ namespace MediaBrowser.Controller.Entities.Movies
StringComparison.OrdinalIgnoreCase);
}
- public override IEnumerable<BaseItem> GetChildren(User user, bool includeLinkedChildren)
+ public override List<BaseItem> GetChildren(User user, bool includeLinkedChildren)
{
var children = base.GetChildren(user, includeLinkedChildren);
if (string.Equals(DisplayOrder, ItemSortBy.SortName, StringComparison.OrdinalIgnoreCase))
{
// Sort by name
- return LibraryManager.Sort(children, user, new[] { ItemSortBy.SortName }, SortOrder.Ascending);
+ return LibraryManager.Sort(children, user, new[] { ItemSortBy.SortName }, SortOrder.Ascending).ToList();
}
if (string.Equals(DisplayOrder, ItemSortBy.PremiereDate, StringComparison.OrdinalIgnoreCase))
{
// Sort by release date
- return LibraryManager.Sort(children, user, new[] { ItemSortBy.ProductionYear, ItemSortBy.PremiereDate, ItemSortBy.SortName }, SortOrder.Ascending);
+ return LibraryManager.Sort(children, user, new[] { ItemSortBy.ProductionYear, ItemSortBy.PremiereDate, ItemSortBy.SortName }, SortOrder.Ascending).ToList();
}
// Default sorting
- return LibraryManager.Sort(children, user, new[] { ItemSortBy.ProductionYear, ItemSortBy.PremiereDate, ItemSortBy.SortName }, SortOrder.Ascending);
+ return LibraryManager.Sort(children, user, new[] { ItemSortBy.ProductionYear, ItemSortBy.PremiereDate, ItemSortBy.SortName }, SortOrder.Ascending).ToList();
}
public BoxSetInfo GetLookupInfo()
@@ -218,7 +168,7 @@ namespace MediaBrowser.Controller.Entities.Movies
if (base.IsVisible(user))
{
- return base.GetChildren(user, true).Any();
+ return base.GetChildren(user, true).Count > 0;
}
return false;
diff --git a/MediaBrowser.Controller/Entities/Movies/Movie.cs b/MediaBrowser.Controller/Entities/Movies/Movie.cs
index 8a5b726e2..3a41709fe 100644
--- a/MediaBrowser.Controller/Entities/Movies/Movie.cs
+++ b/MediaBrowser.Controller/Entities/Movies/Movie.cs
@@ -19,20 +19,20 @@ namespace MediaBrowser.Controller.Entities.Movies
/// </summary>
public class Movie : Video, IHasSpecialFeatures, IHasTrailers, IHasLookupInfo<MovieInfo>, ISupportsBoxSetGrouping
{
- public List<Guid> SpecialFeatureIds { get; set; }
+ public Guid[] SpecialFeatureIds { get; set; }
public Movie()
{
- SpecialFeatureIds = new List<Guid>();
- RemoteTrailers = new List<MediaUrl>();
- LocalTrailerIds = new List<Guid>();
- RemoteTrailerIds = new List<Guid>();
+ SpecialFeatureIds = EmptyGuidArray;
+ RemoteTrailers = EmptyMediaUrlArray;
+ LocalTrailerIds = EmptyGuidArray;
+ RemoteTrailerIds = EmptyGuidArray;
}
- public List<Guid> LocalTrailerIds { get; set; }
- public List<Guid> RemoteTrailerIds { get; set; }
+ public Guid[] LocalTrailerIds { get; set; }
+ public Guid[] RemoteTrailerIds { get; set; }
- public List<MediaUrl> RemoteTrailers { get; set; }
+ public MediaUrl[] RemoteTrailers { get; set; }
/// <summary>
/// Gets or sets the name of the TMDB collection.
@@ -55,22 +55,13 @@ namespace MediaBrowser.Controller.Entities.Movies
return value;
}
- [IgnoreDataMember]
- protected override bool SupportsIsInMixedFolderDetection
- {
- get
- {
- return false;
- }
- }
-
protected override async Task<bool> RefreshedOwnedItems(MetadataRefreshOptions options, List<FileSystemMetadata> fileSystemChildren, CancellationToken cancellationToken)
{
var hasChanges = await base.RefreshedOwnedItems(options, fileSystemChildren, cancellationToken).ConfigureAwait(false);
// Must have a parent to have special features
// In other words, it must be part of the Parent/Child tree
- if (LocationType == LocationType.FileSystem && GetParent() != null && !DetectIsInMixedFolder())
+ if (LocationType == LocationType.FileSystem && GetParent() != null && !IsInMixedFolder)
{
var specialFeaturesChanged = await RefreshSpecialFeatures(options, fileSystemChildren, cancellationToken).ConfigureAwait(false);
@@ -86,7 +77,7 @@ namespace MediaBrowser.Controller.Entities.Movies
private async Task<bool> RefreshSpecialFeatures(MetadataRefreshOptions options, List<FileSystemMetadata> fileSystemChildren, CancellationToken cancellationToken)
{
var newItems = LibraryManager.FindExtras(this, fileSystemChildren, options.DirectoryService).ToList();
- var newItemIds = newItems.Select(i => i.Id).ToList();
+ var newItemIds = newItems.Select(i => i.Id).ToArray();
var itemsChanged = !SpecialFeatureIds.SequenceEqual(newItemIds);
@@ -108,7 +99,7 @@ namespace MediaBrowser.Controller.Entities.Movies
{
var info = GetItemLookupInfo<MovieInfo>();
- if (!DetectIsInMixedFolder())
+ if (!IsInMixedFolder)
{
var name = System.IO.Path.GetFileName(ContainingFolderPath);
@@ -145,7 +136,7 @@ namespace MediaBrowser.Controller.Entities.Movies
else
{
// Try to get the year from the folder name
- if (!DetectIsInMixedFolder())
+ if (!IsInMixedFolder)
{
info = LibraryManager.ParseName(System.IO.Path.GetFileName(ContainingFolderPath));
diff --git a/MediaBrowser.Controller/Entities/MusicVideo.cs b/MediaBrowser.Controller/Entities/MusicVideo.cs
index 7344cb8e4..b7470d679 100644
--- a/MediaBrowser.Controller/Entities/MusicVideo.cs
+++ b/MediaBrowser.Controller/Entities/MusicVideo.cs
@@ -8,15 +8,16 @@ namespace MediaBrowser.Controller.Entities
{
public class MusicVideo : Video, IHasArtist, IHasMusicGenres, IHasLookupInfo<MusicVideoInfo>
{
- public List<string> Artists { get; set; }
+ [IgnoreDataMember]
+ public string[] Artists { get; set; }
public MusicVideo()
{
- Artists = new List<string>();
+ Artists = EmptyStringArray;
}
[IgnoreDataMember]
- public List<string> AllArtists
+ public string[] AllArtists
{
get
{
@@ -24,15 +25,6 @@ namespace MediaBrowser.Controller.Entities
}
}
- [IgnoreDataMember]
- protected override bool SupportsIsInMixedFolderDetection
- {
- get
- {
- return false;
- }
- }
-
public override UnratedItem GetBlockUnratedType()
{
return UnratedItem.Music;
@@ -61,7 +53,7 @@ namespace MediaBrowser.Controller.Entities
else
{
// Try to get the year from the folder name
- if (!DetectIsInMixedFolder())
+ if (!IsInMixedFolder)
{
info = LibraryManager.ParseName(System.IO.Path.GetFileName(ContainingFolderPath));
diff --git a/MediaBrowser.Controller/Entities/PeopleHelper.cs b/MediaBrowser.Controller/Entities/PeopleHelper.cs
index 40a93d9e6..412eb9499 100644
--- a/MediaBrowser.Controller/Entities/PeopleHelper.cs
+++ b/MediaBrowser.Controller/Entities/PeopleHelper.cs
@@ -105,7 +105,15 @@ namespace MediaBrowser.Controller.Entities
{
throw new ArgumentNullException("name");
}
- return people.Any(i => string.Equals(i.Name, name, StringComparison.OrdinalIgnoreCase));
+
+ foreach (var i in people)
+ {
+ if (string.Equals(i.Name, name, StringComparison.OrdinalIgnoreCase))
+ {
+ return true;
+ }
+ }
+ return false;
}
}
}
diff --git a/MediaBrowser.Controller/Entities/Person.cs b/MediaBrowser.Controller/Entities/Person.cs
index 20d9c7999..b3a91f944 100644
--- a/MediaBrowser.Controller/Entities/Person.cs
+++ b/MediaBrowser.Controller/Entities/Person.cs
@@ -1,7 +1,6 @@
using MediaBrowser.Controller.Providers;
using System;
using System.Collections.Generic;
-using System.Linq;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Controller.Extensions;
using MediaBrowser.Model.Entities;
diff --git a/MediaBrowser.Controller/Entities/Photo.cs b/MediaBrowser.Controller/Entities/Photo.cs
index e95ceee52..8e9eac50c 100644
--- a/MediaBrowser.Controller/Entities/Photo.cs
+++ b/MediaBrowser.Controller/Entities/Photo.cs
@@ -1,5 +1,4 @@
using MediaBrowser.Model.Drawing;
-using System.Linq;
using MediaBrowser.Model.Serialization;
namespace MediaBrowser.Controller.Entities
@@ -39,7 +38,16 @@ namespace MediaBrowser.Controller.Entities
{
get
{
- return GetParents().OfType<PhotoAlbum>().FirstOrDefault();
+ var parents = GetParents();
+ foreach (var parent in parents)
+ {
+ var photoAlbum = parent as PhotoAlbum;
+ if (photoAlbum != null)
+ {
+ return photoAlbum;
+ }
+ }
+ return null;
}
}
diff --git a/MediaBrowser.Controller/Entities/Studio.cs b/MediaBrowser.Controller/Entities/Studio.cs
index 8cb65c60a..a6a72d994 100644
--- a/MediaBrowser.Controller/Entities/Studio.cs
+++ b/MediaBrowser.Controller/Entities/Studio.cs
@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
-using System.Linq;
using MediaBrowser.Model.Serialization;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Controller.Extensions;
diff --git a/MediaBrowser.Controller/Entities/TV/Episode.cs b/MediaBrowser.Controller/Entities/TV/Episode.cs
index 45b4de1b3..c30e0ef8e 100644
--- a/MediaBrowser.Controller/Entities/TV/Episode.cs
+++ b/MediaBrowser.Controller/Entities/TV/Episode.cs
@@ -17,14 +17,14 @@ namespace MediaBrowser.Controller.Entities.TV
{
public Episode()
{
- RemoteTrailers = new List<MediaUrl>();
- LocalTrailerIds = new List<Guid>();
- RemoteTrailerIds = new List<Guid>();
+ RemoteTrailers = EmptyMediaUrlArray;
+ LocalTrailerIds = EmptyGuidArray;
+ RemoteTrailerIds = EmptyGuidArray;
}
- public List<Guid> LocalTrailerIds { get; set; }
- public List<Guid> RemoteTrailerIds { get; set; }
- public List<MediaUrl> RemoteTrailers { get; set; }
+ public Guid[] LocalTrailerIds { get; set; }
+ public Guid[] RemoteTrailerIds { get; set; }
+ public MediaUrl[] RemoteTrailers { get; set; }
/// <summary>
/// Gets the season in which it aired.
@@ -282,17 +282,11 @@ namespace MediaBrowser.Controller.Entities.TV
{
get
{
- return LocationType == LocationType.Virtual && !IsUnaired;
+ return LocationType == LocationType.Virtual;
}
}
[IgnoreDataMember]
- public bool IsVirtualUnaired
- {
- get { return LocationType == LocationType.Virtual && IsUnaired; }
- }
-
- [IgnoreDataMember]
public Guid? SeasonId { get; set; }
[IgnoreDataMember]
public Guid? SeriesId { get; set; }
@@ -346,7 +340,6 @@ namespace MediaBrowser.Controller.Entities.TV
id.IsMissingEpisode = IsMissingEpisode;
id.IndexNumberEnd = IndexNumberEnd;
- id.IsVirtualUnaired = IsVirtualUnaired;
return id;
}
diff --git a/MediaBrowser.Controller/Entities/TV/Season.cs b/MediaBrowser.Controller/Entities/TV/Season.cs
index b681fdcb1..bf6dc5678 100644
--- a/MediaBrowser.Controller/Entities/TV/Season.cs
+++ b/MediaBrowser.Controller/Entities/TV/Season.cs
@@ -81,7 +81,7 @@ namespace MediaBrowser.Controller.Entities.TV
public override int GetChildCount(User user)
{
- var result = GetChildren(user, true).Count();
+ var result = GetChildren(user, true).Count;
return result;
}
@@ -160,27 +160,27 @@ namespace MediaBrowser.Controller.Entities.TV
/// <summary>
/// Gets the episodes.
/// </summary>
- public IEnumerable<Episode> GetEpisodes(User user, DtoOptions options)
+ public List<BaseItem> GetEpisodes(User user, DtoOptions options)
{
return GetEpisodes(Series, user, options);
}
- public IEnumerable<Episode> GetEpisodes(Series series, User user, DtoOptions options)
+ public List<BaseItem> GetEpisodes(Series series, User user, DtoOptions options)
{
return GetEpisodes(series, user, null, options);
}
- public IEnumerable<Episode> GetEpisodes(Series series, User user, IEnumerable<Episode> allSeriesEpisodes, DtoOptions options)
+ public List<BaseItem> GetEpisodes(Series series, User user, IEnumerable<Episode> allSeriesEpisodes, DtoOptions options)
{
return series.GetSeasonEpisodes(this, user, allSeriesEpisodes, options);
}
- public IEnumerable<Episode> GetEpisodes()
+ public List<BaseItem> GetEpisodes()
{
return Series.GetSeasonEpisodes(this, null, null, new DtoOptions(true));
}
- public override IEnumerable<BaseItem> GetChildren(User user, bool includeLinkedChildren)
+ public override List<BaseItem> GetChildren(User user, bool includeLinkedChildren)
{
return GetEpisodes(user, new DtoOptions(true));
}
diff --git a/MediaBrowser.Controller/Entities/TV/Series.cs b/MediaBrowser.Controller/Entities/TV/Series.cs
index 8b73b80b0..60d2624fa 100644
--- a/MediaBrowser.Controller/Entities/TV/Series.cs
+++ b/MediaBrowser.Controller/Entities/TV/Series.cs
@@ -22,13 +22,15 @@ namespace MediaBrowser.Controller.Entities.TV
{
public Series()
{
- AirDays = new List<DayOfWeek>();
-
- RemoteTrailers = new List<MediaUrl>();
- LocalTrailerIds = new List<Guid>();
- RemoteTrailerIds = new List<Guid>();
+ RemoteTrailers = EmptyMediaUrlArray;
+ LocalTrailerIds = EmptyGuidArray;
+ RemoteTrailerIds = EmptyGuidArray;
+ AirDays = new DayOfWeek[] { };
}
+ public DayOfWeek[] AirDays { get; set; }
+ public string AirTime { get; set; }
+
[IgnoreDataMember]
public override bool SupportsAddingToPlaylist
{
@@ -62,10 +64,10 @@ namespace MediaBrowser.Controller.Entities.TV
}
}
- public List<Guid> LocalTrailerIds { get; set; }
- public List<Guid> RemoteTrailerIds { get; set; }
+ public Guid[] LocalTrailerIds { get; set; }
+ public Guid[] RemoteTrailerIds { get; set; }
- public List<MediaUrl> RemoteTrailers { get; set; }
+ public MediaUrl[] RemoteTrailers { get; set; }
/// <summary>
/// airdate, dvd or absolute
@@ -77,16 +79,6 @@ namespace MediaBrowser.Controller.Entities.TV
/// </summary>
/// <value>The status.</value>
public SeriesStatus? Status { get; set; }
- /// <summary>
- /// Gets or sets the air days.
- /// </summary>
- /// <value>The air days.</value>
- public List<DayOfWeek> AirDays { get; set; }
- /// <summary>
- /// Gets or sets the air time.
- /// </summary>
- /// <value>The air time.</value>
- public string AirTime { get; set; }
/// <summary>
/// Gets or sets the date last episode added.
@@ -160,12 +152,8 @@ namespace MediaBrowser.Controller.Entities.TV
IncludeItemTypes = new[] { typeof(Season).Name },
IsVirtualItem = false,
Limit = 0,
- DtoOptions = new Dto.DtoOptions
+ DtoOptions = new Dto.DtoOptions(false)
{
- Fields = new List<ItemFields>
- {
-
- },
EnableImages = false
}
});
@@ -181,19 +169,15 @@ namespace MediaBrowser.Controller.Entities.TV
{
AncestorWithPresentationUniqueKey = null,
SeriesPresentationUniqueKey = seriesKey,
- DtoOptions = new Dto.DtoOptions
+ DtoOptions = new Dto.DtoOptions(false)
{
- Fields = new List<ItemFields>
- {
-
- },
EnableImages = false
}
};
if (query.IncludeItemTypes.Length == 0)
{
- query.IncludeItemTypes = new[] { typeof(Episode).Name, typeof(Season).Name };
+ query.IncludeItemTypes = new[] { typeof(Episode).Name };
}
query.IsVirtualItem = false;
query.Limit = 0;
@@ -225,32 +209,29 @@ namespace MediaBrowser.Controller.Entities.TV
return list;
}
- /// <summary>
- /// Gets the trailer ids.
- /// </summary>
- /// <returns>List&lt;Guid&gt;.</returns>
- public List<Guid> GetTrailerIds()
- {
- var list = LocalTrailerIds.ToList();
- list.AddRange(RemoteTrailerIds);
- return list;
- }
-
[IgnoreDataMember]
public bool ContainsEpisodesWithoutSeasonFolders
{
get
{
- return Children.OfType<Video>().Any();
+ var children = Children;
+ foreach (var child in children)
+ {
+ if (child is Video)
+ {
+ return true;
+ }
+ }
+ return false;
}
}
- public override IEnumerable<BaseItem> GetChildren(User user, bool includeLinkedChildren)
+ public override List<BaseItem> GetChildren(User user, bool includeLinkedChildren)
{
return GetSeasons(user, new DtoOptions(true));
}
- public IEnumerable<Season> GetSeasons(User user, DtoOptions options)
+ public List<BaseItem> GetSeasons(User user, DtoOptions options)
{
var query = new InternalItemsQuery(user)
{
@@ -259,7 +240,7 @@ namespace MediaBrowser.Controller.Entities.TV
SetSeasonQueryOptions(query, user);
- return LibraryManager.GetItemList(query).Cast<Season>();
+ return LibraryManager.GetItemList(query);
}
private void SetSeasonQueryOptions(InternalItemsQuery query, User user)
@@ -271,20 +252,12 @@ namespace MediaBrowser.Controller.Entities.TV
query.AncestorWithPresentationUniqueKey = null;
query.SeriesPresentationUniqueKey = seriesKey;
query.IncludeItemTypes = new[] { typeof(Season).Name };
- query.SortBy = new[] {ItemSortBy.SortName};
+ query.OrderBy = new[] { ItemSortBy.SortName }.Select(i => new Tuple<string, SortOrder>(i, SortOrder.Ascending)).ToArray();
- if (!config.DisplayMissingEpisodes && !config.DisplayUnairedEpisodes)
- {
- query.IsVirtualItem = false;
- }
- else if (!config.DisplayMissingEpisodes)
+ if (!config.DisplayMissingEpisodes)
{
query.IsMissing = false;
}
- else if (!config.DisplayUnairedEpisodes)
- {
- query.IsVirtualUnaired = false;
- }
}
protected override QueryResult<BaseItem> GetItemsInternal(InternalItemsQuery query)
@@ -302,9 +275,9 @@ namespace MediaBrowser.Controller.Entities.TV
query.AncestorWithPresentationUniqueKey = null;
query.SeriesPresentationUniqueKey = seriesKey;
- if (query.SortBy.Length == 0)
+ if (query.OrderBy.Length == 0)
{
- query.SortBy = new[] { ItemSortBy.SortName };
+ query.OrderBy = new[] { ItemSortBy.SortName }.Select(i => new Tuple<string, SortOrder>(i, SortOrder.Ascending)).ToArray();
}
if (query.IncludeItemTypes.Length == 0)
{
@@ -319,7 +292,7 @@ namespace MediaBrowser.Controller.Entities.TV
return LibraryManager.GetItemsResult(query);
}
- public IEnumerable<Episode> GetEpisodes(User user, DtoOptions options)
+ public IEnumerable<BaseItem> GetEpisodes(User user, DtoOptions options)
{
var seriesKey = GetUniqueSeriesKey(this);
@@ -328,31 +301,22 @@ namespace MediaBrowser.Controller.Entities.TV
AncestorWithPresentationUniqueKey = null,
SeriesPresentationUniqueKey = seriesKey,
IncludeItemTypes = new[] { typeof(Episode).Name, typeof(Season).Name },
- SortBy = new[] { ItemSortBy.SortName },
+ OrderBy = new[] { ItemSortBy.SortName }.Select(i => new Tuple<string, SortOrder>(i, SortOrder.Ascending)).ToArray(),
DtoOptions = options
};
var config = user.Configuration;
- if (!config.DisplayMissingEpisodes && !config.DisplayUnairedEpisodes)
- {
- query.IsVirtualItem = false;
- }
- else if (!config.DisplayMissingEpisodes)
+ if (!config.DisplayMissingEpisodes)
{
query.IsMissing = false;
}
- else if (!config.DisplayUnairedEpisodes)
- {
- query.IsVirtualUnaired = false;
- }
- var allItems = LibraryManager.GetItemList(query).ToList();
+ var allItems = LibraryManager.GetItemList(query);
var allSeriesEpisodes = allItems.OfType<Episode>().ToList();
var allEpisodes = allItems.OfType<Season>()
.SelectMany(i => i.GetEpisodes(this, user, allSeriesEpisodes, options))
- .Reverse()
- .ToList();
+ .Reverse();
// Specials could appear twice based on above - once in season 0, once in the aired season
// This depends on settings for that series
@@ -365,20 +329,22 @@ namespace MediaBrowser.Controller.Entities.TV
{
// Refresh bottom up, children first, then the boxset
// By then hopefully the movies within will have Tmdb collection values
- var items = GetRecursiveChildren().ToList();
+ var items = GetRecursiveChildren();
- var seasons = items.OfType<Season>().ToList();
- var otherItems = items.Except(seasons).ToList();
-
- var totalItems = seasons.Count + otherItems.Count;
+ var totalItems = items.Count;
var numComplete = 0;
// Refresh current item
await RefreshMetadata(refreshOptions, cancellationToken).ConfigureAwait(false);
// Refresh seasons
- foreach (var item in seasons)
+ foreach (var item in items)
{
+ if (!(item is Season))
+ {
+ continue;
+ }
+
cancellationToken.ThrowIfCancellationRequested();
await item.RefreshMetadata(refreshOptions, cancellationToken).ConfigureAwait(false);
@@ -390,8 +356,13 @@ namespace MediaBrowser.Controller.Entities.TV
}
// Refresh episodes and other children
- foreach (var item in otherItems)
+ foreach (var item in items)
{
+ if ((item is Season))
+ {
+ continue;
+ }
+
cancellationToken.ThrowIfCancellationRequested();
var skipItem = false;
@@ -425,7 +396,7 @@ namespace MediaBrowser.Controller.Entities.TV
await ProviderManager.RefreshSingleItem(this, refreshOptions, cancellationToken).ConfigureAwait(false);
}
- public IEnumerable<Episode> GetSeasonEpisodes(Season parentSeason, User user, DtoOptions options)
+ public List<BaseItem> GetSeasonEpisodes(Season parentSeason, User user, DtoOptions options)
{
var queryFromSeries = ConfigurationManager.Configuration.DisplaySpecialsWithinSeasons;
@@ -439,32 +410,24 @@ namespace MediaBrowser.Controller.Entities.TV
AncestorWithPresentationUniqueKey = queryFromSeries ? null : seriesKey,
SeriesPresentationUniqueKey = queryFromSeries ? seriesKey : null,
IncludeItemTypes = new[] { typeof(Episode).Name },
- SortBy = new[] { ItemSortBy.SortName },
+ OrderBy = new[] { ItemSortBy.SortName }.Select(i => new Tuple<string, SortOrder>(i, SortOrder.Ascending)).ToArray(),
DtoOptions = options
};
if (user != null)
{
var config = user.Configuration;
- if (!config.DisplayMissingEpisodes && !config.DisplayUnairedEpisodes)
- {
- query.IsVirtualItem = false;
- }
- else if (!config.DisplayMissingEpisodes)
+ if (!config.DisplayMissingEpisodes)
{
query.IsMissing = false;
}
- else if (!config.DisplayUnairedEpisodes)
- {
- query.IsVirtualUnaired = false;
- }
}
- var allItems = LibraryManager.GetItemList(query).OfType<Episode>();
+ var allItems = LibraryManager.GetItemList(query);
return GetSeasonEpisodes(parentSeason, user, allItems, options);
}
- public IEnumerable<Episode> GetSeasonEpisodes(Season parentSeason, User user, IEnumerable<Episode> allSeriesEpisodes, DtoOptions options)
+ public List<BaseItem> GetSeasonEpisodes(Season parentSeason, User user, IEnumerable<BaseItem> allSeriesEpisodes, DtoOptions options)
{
if (allSeriesEpisodes == null)
{
@@ -475,14 +438,13 @@ namespace MediaBrowser.Controller.Entities.TV
var sortBy = (parentSeason.IndexNumber ?? -1) == 0 ? ItemSortBy.SortName : ItemSortBy.AiredEpisodeOrder;
- return LibraryManager.Sort(episodes, user, new[] { sortBy }, SortOrder.Ascending)
- .Cast<Episode>();
+ return LibraryManager.Sort(episodes, user, new[] { sortBy }, SortOrder.Ascending).ToList();
}
/// <summary>
/// Filters the episodes by season.
/// </summary>
- public static IEnumerable<Episode> FilterEpisodesBySeason(IEnumerable<Episode> episodes, Season parentSeason, bool includeSpecials)
+ public static IEnumerable<BaseItem> FilterEpisodesBySeason(IEnumerable<BaseItem> episodes, Season parentSeason, bool includeSpecials)
{
var seasonNumber = parentSeason.IndexNumber;
var seasonPresentationKey = GetUniqueSeriesKey(parentSeason);
@@ -491,7 +453,9 @@ namespace MediaBrowser.Controller.Entities.TV
return episodes.Where(episode =>
{
- var currentSeasonNumber = supportSpecialsInSeason ? episode.AiredSeasonNumber : episode.ParentIndexNumber;
+ var episodeItem = (Episode)episode;
+
+ var currentSeasonNumber = supportSpecialsInSeason ? episodeItem.AiredSeasonNumber : episode.ParentIndexNumber;
if (currentSeasonNumber.HasValue && seasonNumber.HasValue && currentSeasonNumber.Value == seasonNumber.Value)
{
return true;
@@ -502,7 +466,7 @@ namespace MediaBrowser.Controller.Entities.TV
return true;
}
- var season = episode.Season;
+ var season = episodeItem.Season;
return season != null && string.Equals(GetUniqueSeriesKey(season), seasonPresentationKey, StringComparison.OrdinalIgnoreCase);
});
}
diff --git a/MediaBrowser.Controller/Entities/TagExtensions.cs b/MediaBrowser.Controller/Entities/TagExtensions.cs
index 0e1df72cd..e5d8f35d9 100644
--- a/MediaBrowser.Controller/Entities/TagExtensions.cs
+++ b/MediaBrowser.Controller/Entities/TagExtensions.cs
@@ -1,5 +1,7 @@
using System;
+using System.Collections.Generic;
using System.Linq;
+using MediaBrowser.Model.Extensions;
namespace MediaBrowser.Controller.Entities
{
@@ -12,9 +14,21 @@ namespace MediaBrowser.Controller.Entities
throw new ArgumentNullException("name");
}
- if (!item.Tags.Contains(name, StringComparer.OrdinalIgnoreCase))
+ var current = item.Tags;
+
+ if (!current.Contains(name, StringComparer.OrdinalIgnoreCase))
{
- item.Tags.Add(name);
+ if (current.Length == 0)
+ {
+ item.Tags = new[] { name };
+ }
+ else
+ {
+ var list = current.ToArray(current.Length + 1);
+ list[list.Length - 1] = name;
+
+ item.Tags = list;
+ }
}
}
}
diff --git a/MediaBrowser.Controller/Entities/Trailer.cs b/MediaBrowser.Controller/Entities/Trailer.cs
index 99acce164..c5144aadf 100644
--- a/MediaBrowser.Controller/Entities/Trailer.cs
+++ b/MediaBrowser.Controller/Entities/Trailer.cs
@@ -47,7 +47,7 @@ namespace MediaBrowser.Controller.Entities
info.IsLocalTrailer = TrailerTypes.Contains(TrailerType.LocalTrailer);
- if (!DetectIsInMixedFolder() && LocationType == LocationType.FileSystem)
+ if (!IsInMixedFolder && LocationType == LocationType.FileSystem)
{
info.Name = System.IO.Path.GetFileName(ContainingFolderPath);
}
@@ -73,7 +73,7 @@ namespace MediaBrowser.Controller.Entities
else
{
// Try to get the year from the folder name
- if (!DetectIsInMixedFolder())
+ if (!IsInMixedFolder)
{
info = LibraryManager.ParseName(System.IO.Path.GetFileName(ContainingFolderPath));
diff --git a/MediaBrowser.Controller/Entities/User.cs b/MediaBrowser.Controller/Entities/User.cs
index d5d229bb3..3c89037cc 100644
--- a/MediaBrowser.Controller/Entities/User.cs
+++ b/MediaBrowser.Controller/Entities/User.cs
@@ -5,7 +5,6 @@ using MediaBrowser.Model.Connect;
using MediaBrowser.Model.Serialization;
using MediaBrowser.Model.Users;
using System;
-using System.Linq;
using System.Threading;
using System.Threading.Tasks;
@@ -166,7 +165,7 @@ namespace MediaBrowser.Controller.Entities
}
}
}
-
+
return _policy;
}
set { _policy = value; }
@@ -195,24 +194,24 @@ namespace MediaBrowser.Controller.Entities
var oldConfigurationDirectory = ConfigurationDirectoryPath;
// Exceptions will be thrown if these paths already exist
- if (FileSystem.DirectoryExists(newConfigDirectory))
+ if (FileSystem.DirectoryExists(newConfigDirectory))
{
FileSystem.DeleteDirectory(newConfigDirectory, true);
}
- if (FileSystem.DirectoryExists(oldConfigurationDirectory))
+ if (FileSystem.DirectoryExists(oldConfigurationDirectory))
{
- FileSystem.MoveDirectory(oldConfigurationDirectory, newConfigDirectory);
+ FileSystem.MoveDirectory(oldConfigurationDirectory, newConfigDirectory);
}
else
{
- FileSystem.CreateDirectory(newConfigDirectory);
+ FileSystem.CreateDirectory(newConfigDirectory);
}
}
Name = newName;
- return RefreshMetadata(new MetadataRefreshOptions(new DirectoryService(Logger, FileSystem))
+ return RefreshMetadata(new MetadataRefreshOptions(new DirectoryService(Logger, FileSystem))
{
ReplaceAllMetadata = true,
ImageRefreshMode = ImageRefreshMode.FullRefresh,
@@ -224,7 +223,8 @@ namespace MediaBrowser.Controller.Entities
public override Task UpdateToRepository(ItemUpdateType updateReason, CancellationToken cancellationToken)
{
- return UserManager.UpdateUser(this);
+ UserManager.UpdateUser(this);
+ return Task.FromResult(true);
}
/// <summary>
@@ -279,7 +279,14 @@ namespace MediaBrowser.Controller.Entities
return true;
}
- return schedules.Any(i => IsParentalScheduleAllowed(i, date));
+ foreach (var i in schedules)
+ {
+ if (IsParentalScheduleAllowed(i, date))
+ {
+ return true;
+ }
+ }
+ return false;
}
private bool IsParentalScheduleAllowed(AccessSchedule schedule, DateTime date)
@@ -304,7 +311,14 @@ namespace MediaBrowser.Controller.Entities
public bool IsFolderGrouped(Guid id)
{
- return Configuration.GroupedFolders.Select(i => new Guid(i)).Contains(id);
+ foreach (var i in Configuration.GroupedFolders)
+ {
+ if (new Guid(i) == id)
+ {
+ return true;
+ }
+ }
+ return false;
}
[IgnoreDataMember]
diff --git a/MediaBrowser.Controller/Entities/UserRootFolder.cs b/MediaBrowser.Controller/Entities/UserRootFolder.cs
index d35156345..2ed3bf20f 100644
--- a/MediaBrowser.Controller/Entities/UserRootFolder.cs
+++ b/MediaBrowser.Controller/Entities/UserRootFolder.cs
@@ -24,7 +24,7 @@ namespace MediaBrowser.Controller.Entities
{
if (_childrenIds == null)
{
- var list = base.LoadChildren().ToList();
+ var list = base.LoadChildren();
_childrenIds = list.Select(i => i.Id).ToList();
return list;
}
@@ -81,7 +81,7 @@ namespace MediaBrowser.Controller.Entities
public override int GetChildCount(User user)
{
- return GetChildren(user, true).Count();
+ return GetChildren(user, true).Count;
}
[IgnoreDataMember]
diff --git a/MediaBrowser.Controller/Entities/UserView.cs b/MediaBrowser.Controller/Entities/UserView.cs
index 0d2d69c94..66174034d 100644
--- a/MediaBrowser.Controller/Entities/UserView.cs
+++ b/MediaBrowser.Controller/Entities/UserView.cs
@@ -4,9 +4,9 @@ using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Querying;
using System;
using System.Collections.Generic;
+using System.Linq;
using MediaBrowser.Model.Serialization;
using System.Threading.Tasks;
-using System.Linq;
using MediaBrowser.Controller.Dto;
namespace MediaBrowser.Controller.Entities
@@ -60,7 +60,7 @@ namespace MediaBrowser.Controller.Entities
public override int GetChildCount(User user)
{
- return GetChildren(user, true).Count();
+ return GetChildren(user, true).Count;
}
protected override QueryResult<BaseItem> GetItemsInternal(InternalItemsQuery query)
@@ -80,9 +80,9 @@ namespace MediaBrowser.Controller.Entities
.GetUserItems(parent, this, ViewType, query).Result;
}
- public override IEnumerable<BaseItem> GetChildren(User user, bool includeLinkedChildren)
+ public override List<BaseItem> GetChildren(User user, bool includeLinkedChildren)
{
- var result = GetItems(new InternalItemsQuery
+ var result = GetItemList(new InternalItemsQuery
{
User = user,
EnableTotalRecordCount = false,
@@ -90,7 +90,7 @@ namespace MediaBrowser.Controller.Entities
});
- return result.Items;
+ return result.ToList();
}
public override bool CanDelete()
@@ -105,7 +105,7 @@ namespace MediaBrowser.Controller.Entities
public override IEnumerable<BaseItem> GetRecursiveChildren(User user, InternalItemsQuery query)
{
- var result = GetItems(new InternalItemsQuery
+ var result = GetItemList(new InternalItemsQuery
{
User = user,
Recursive = true,
@@ -117,7 +117,7 @@ namespace MediaBrowser.Controller.Entities
});
- return result.Items.Where(i => UserViewBuilder.FilterItem(i, query));
+ return result.Where(i => UserViewBuilder.FilterItem(i, query));
}
protected override IEnumerable<BaseItem> GetEligibleChildrenForRecursiveChildren(User user)
diff --git a/MediaBrowser.Controller/Entities/UserViewBuilder.cs b/MediaBrowser.Controller/Entities/UserViewBuilder.cs
index 91e24caeb..3ab82a103 100644
--- a/MediaBrowser.Controller/Entities/UserViewBuilder.cs
+++ b/MediaBrowser.Controller/Entities/UserViewBuilder.cs
@@ -397,7 +397,7 @@ namespace MediaBrowser.Controller.Entities
}, query.DtoOptions).Select(i => i.Item1 ?? i.Item2.FirstOrDefault()).Where(i => i != null);
- query.SortBy = new string[] { };
+ query.OrderBy = new Tuple<string, SortOrder>[] { };
return PostFilterAndSort(items, parent, null, query, false, true);
}
@@ -507,8 +507,7 @@ namespace MediaBrowser.Controller.Entities
private QueryResult<BaseItem> GetMovieLatest(Folder parent, User user, InternalItemsQuery query)
{
- query.SortBy = new[] { ItemSortBy.DateCreated, ItemSortBy.SortName };
- query.SortOrder = SortOrder.Descending;
+ query.OrderBy = new[] { ItemSortBy.DateCreated, ItemSortBy.SortName }.Select(i => new Tuple<string, SortOrder>(i, SortOrder.Descending)).ToArray();
query.Recursive = true;
query.Parent = parent;
@@ -521,8 +520,7 @@ namespace MediaBrowser.Controller.Entities
private QueryResult<BaseItem> GetMovieResume(Folder parent, User user, InternalItemsQuery query)
{
- query.SortBy = new[] { ItemSortBy.DatePlayed, ItemSortBy.SortName };
- query.SortOrder = SortOrder.Descending;
+ query.OrderBy = new[] { ItemSortBy.DatePlayed, ItemSortBy.SortName }.Select(i => new Tuple<string, SortOrder>(i, SortOrder.Descending)).ToArray();
query.IsResumable = true;
query.Recursive = true;
query.Parent = parent;
@@ -533,7 +531,7 @@ namespace MediaBrowser.Controller.Entities
return ConvertToResult(_libraryManager.GetItemList(query));
}
- private QueryResult<BaseItem> ConvertToResult(IEnumerable<BaseItem> items)
+ private QueryResult<BaseItem> ConvertToResult(List<BaseItem> items)
{
var arr = items.ToArray();
return new QueryResult<BaseItem>
@@ -633,8 +631,7 @@ namespace MediaBrowser.Controller.Entities
private QueryResult<BaseItem> GetTvLatest(Folder parent, User user, InternalItemsQuery query)
{
- query.SortBy = new[] { ItemSortBy.DateCreated, ItemSortBy.SortName };
- query.SortOrder = SortOrder.Descending;
+ query.OrderBy = new[] { ItemSortBy.DateCreated, ItemSortBy.SortName }.Select(i => new Tuple<string, SortOrder>(i, SortOrder.Descending)).ToArray();
query.Recursive = true;
query.Parent = parent;
@@ -663,8 +660,7 @@ namespace MediaBrowser.Controller.Entities
private QueryResult<BaseItem> GetTvResume(Folder parent, User user, InternalItemsQuery query)
{
- query.SortBy = new[] { ItemSortBy.DatePlayed, ItemSortBy.SortName };
- query.SortOrder = SortOrder.Descending;
+ query.OrderBy = new[] { ItemSortBy.DatePlayed, ItemSortBy.SortName }.Select(i => new Tuple<string, SortOrder>(i, SortOrder.Descending)).ToArray();
query.IsResumable = true;
query.Recursive = true;
query.Parent = parent;
@@ -779,7 +775,6 @@ namespace MediaBrowser.Controller.Entities
items = FilterVirtualEpisodes(items,
query.IsMissing,
- query.IsVirtualUnaired,
query.IsUnaired);
if (collapseBoxSetItems && user != null)
@@ -790,7 +785,7 @@ namespace MediaBrowser.Controller.Entities
// This must be the last filter
if (!string.IsNullOrEmpty(query.AdjacentTo))
{
- items = FilterForAdjacency(items, query.AdjacentTo);
+ items = FilterForAdjacency(items.ToList(), query.AdjacentTo);
}
return SortAndPage(items, totalRecordLimit, query, libraryManager, enableSorting);
@@ -1065,7 +1060,6 @@ namespace MediaBrowser.Controller.Entities
private static IEnumerable<BaseItem> FilterVirtualEpisodes(
IEnumerable<BaseItem> items,
bool? isMissing,
- bool? isVirtualUnaired,
bool? isUnaired)
{
if (isMissing.HasValue)
@@ -1096,20 +1090,6 @@ namespace MediaBrowser.Controller.Entities
});
}
- if (isVirtualUnaired.HasValue)
- {
- var val = isVirtualUnaired.Value;
- items = items.Where(i =>
- {
- var e = i as Episode;
- if (e != null)
- {
- return e.IsVirtualUnaired == val;
- }
- return true;
- });
- }
-
return items;
}
@@ -1120,9 +1100,9 @@ namespace MediaBrowser.Controller.Entities
{
items = items.DistinctBy(i => i.GetPresentationUniqueKey(), StringComparer.OrdinalIgnoreCase);
- if (query.SortBy.Length > 0)
+ if (query.OrderBy.Length > 0)
{
- items = libraryManager.Sort(items, query.User, query.SortBy, query.SortOrder);
+ items = libraryManager.Sort(items, query.User, query.OrderBy);
}
var itemsArray = totalRecordLimit.HasValue ? items.Take(totalRecordLimit.Value).ToArray() : items.ToArray();
@@ -1387,8 +1367,8 @@ namespace MediaBrowser.Controller.Entities
if (movie != null)
{
var ok = filterValue
- ? movie.SpecialFeatureIds.Count > 0
- : movie.SpecialFeatureIds.Count == 0;
+ ? movie.SpecialFeatureIds.Length > 0
+ : movie.SpecialFeatureIds.Length == 0;
if (!ok)
{
@@ -1463,7 +1443,7 @@ namespace MediaBrowser.Controller.Entities
{
var filterValue = query.HasThemeSong.Value;
- var themeCount = item.ThemeSongIds.Count;
+ var themeCount = item.ThemeSongIds.Length;
var ok = filterValue ? themeCount > 0 : themeCount == 0;
if (!ok)
@@ -1476,7 +1456,7 @@ namespace MediaBrowser.Controller.Entities
{
var filterValue = query.HasThemeVideo.Value;
- var themeCount = item.ThemeVideoIds.Count;
+ var themeCount = item.ThemeVideoIds.Length;
var ok = filterValue ? themeCount > 0 : themeCount == 0;
if (!ok)
@@ -1674,15 +1654,6 @@ namespace MediaBrowser.Controller.Entities
}
}
- if (query.AirDays.Length > 0)
- {
- var ok = new[] { item }.OfType<Series>().Any(p => p.AirDays != null && query.AirDays.Any(d => p.AirDays.Contains(d)));
- if (!ok)
- {
- return false;
- }
- }
-
if (query.SeriesStatuses.Length > 0)
{
var ok = new[] { item }.OfType<Series>().Any(p => p.Status.HasValue && query.SeriesStatuses.Contains(p.Status.Value));
@@ -1788,10 +1759,8 @@ namespace MediaBrowser.Controller.Entities
return _userViewManager.GetUserSubView(parent.Id.ToString("N"), type, sortName, CancellationToken.None);
}
- public static IEnumerable<BaseItem> FilterForAdjacency(IEnumerable<BaseItem> items, string adjacentToId)
+ public static IEnumerable<BaseItem> FilterForAdjacency(List<BaseItem> list, string adjacentToId)
{
- var list = items.ToList();
-
var adjacentToIdGuid = new Guid(adjacentToId);
var adjacentToItem = list.FirstOrDefault(i => i.Id == adjacentToIdGuid);
diff --git a/MediaBrowser.Controller/Entities/Video.cs b/MediaBrowser.Controller/Entities/Video.cs
index c5d9b9203..ffb601dc4 100644
--- a/MediaBrowser.Controller/Entities/Video.cs
+++ b/MediaBrowser.Controller/Entities/Video.cs
@@ -16,6 +16,7 @@ using MediaBrowser.Controller.Channels;
using MediaBrowser.Controller.IO;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Serialization;
+using MediaBrowser.Model.Extensions;
namespace MediaBrowser.Controller.Entities
{
@@ -30,9 +31,9 @@ namespace MediaBrowser.Controller.Entities
[IgnoreDataMember]
public string PrimaryVersionId { get; set; }
- public List<string> AdditionalParts { get; set; }
- public List<string> LocalAlternateVersions { get; set; }
- public List<LinkedChild> LinkedAlternateVersions { get; set; }
+ public string[] AdditionalParts { get; set; }
+ public string[] LocalAlternateVersions { get; set; }
+ public LinkedChild[] LinkedAlternateVersions { get; set; }
[IgnoreDataMember]
public override bool SupportsPlayedStatus
@@ -77,15 +78,6 @@ namespace MediaBrowser.Controller.Entities
}
}
- [IgnoreDataMember]
- protected override bool SupportsIsInMixedFolderDetection
- {
- get
- {
- return true;
- }
- }
-
public override string CreatePresentationUniqueKey()
{
if (!string.IsNullOrWhiteSpace(PrimaryVersionId))
@@ -121,7 +113,7 @@ namespace MediaBrowser.Controller.Entities
/// Gets or sets the subtitle paths.
/// </summary>
/// <value>The subtitle paths.</value>
- public List<string> SubtitleFiles { get; set; }
+ public string[] SubtitleFiles { get; set; }
/// <summary>
/// Gets or sets a value indicating whether this instance has subtitles.
@@ -157,18 +149,23 @@ namespace MediaBrowser.Controller.Entities
/// <value>The video3 D format.</value>
public Video3DFormat? Video3DFormat { get; set; }
- /// <summary>
- /// If the video is a folder-rip, this will hold the file list for the largest playlist
- /// </summary>
- public List<string> PlayableStreamFileNames { get; set; }
-
- /// <summary>
- /// Gets the playable stream files.
- /// </summary>
- /// <returns>List{System.String}.</returns>
- public List<string> GetPlayableStreamFiles()
+ public string[] GetPlayableStreamFileNames()
{
- return GetPlayableStreamFiles(Path);
+ var videoType = VideoType;
+
+ if (videoType == VideoType.Iso && IsoType == Model.Entities.IsoType.BluRay)
+ {
+ videoType = VideoType.BluRay;
+ }
+ else if (videoType == VideoType.Iso && IsoType == Model.Entities.IsoType.Dvd)
+ {
+ videoType = VideoType.Dvd;
+ }
+ else
+ {
+ return new string[] { };
+ }
+ return MediaEncoder.GetPlayableStreamFileNames(Path, videoType);
}
/// <summary>
@@ -179,17 +176,15 @@ namespace MediaBrowser.Controller.Entities
public Video()
{
- PlayableStreamFileNames = new List<string>();
- AdditionalParts = new List<string>();
- LocalAlternateVersions = new List<string>();
- SubtitleFiles = new List<string>();
- LinkedAlternateVersions = new List<LinkedChild>();
+ AdditionalParts = EmptyStringArray;
+ LocalAlternateVersions = EmptyStringArray;
+ SubtitleFiles = EmptyStringArray;
+ LinkedAlternateVersions = EmptyLinkedChildArray;
}
public override bool CanDownload()
{
- if (VideoType == VideoType.HdDvd || VideoType == VideoType.Dvd ||
- VideoType == VideoType.BluRay)
+ if (VideoType == VideoType.Dvd || VideoType == VideoType.BluRay)
{
return false;
}
@@ -218,20 +213,20 @@ namespace MediaBrowser.Controller.Entities
return item.MediaSourceCount;
}
}
- return LinkedAlternateVersions.Count + LocalAlternateVersions.Count + 1;
+ return LinkedAlternateVersions.Length + LocalAlternateVersions.Length + 1;
}
}
[IgnoreDataMember]
public bool IsStacked
{
- get { return AdditionalParts.Count > 0; }
+ get { return AdditionalParts.Length > 0; }
}
[IgnoreDataMember]
public bool HasLocalAlternateVersions
{
- get { return LocalAlternateVersions.Count > 0; }
+ get { return LocalAlternateVersions.Length > 0; }
}
public IEnumerable<Guid> GetAdditionalPartIds()
@@ -245,6 +240,41 @@ namespace MediaBrowser.Controller.Entities
}
[IgnoreDataMember]
+ public override SourceType SourceType
+ {
+ get
+ {
+ if (IsActiveRecording())
+ {
+ return SourceType.LiveTV;
+ }
+
+ return base.SourceType;
+ }
+ }
+
+ protected bool IsActiveRecording()
+ {
+ return LiveTvManager.GetActiveRecordingInfo(Path) != null;
+ }
+
+ public override bool CanDelete()
+ {
+ if (IsActiveRecording())
+ {
+ return false;
+ }
+
+ return base.CanDelete();
+ }
+
+ [IgnoreDataMember]
+ public bool IsCompleteMedia
+ {
+ get { return !IsActiveRecording(); }
+ }
+
+ [IgnoreDataMember]
protected virtual bool EnableDefaultVideoUserDataKeys
{
get
@@ -339,8 +369,7 @@ namespace MediaBrowser.Controller.Entities
if (!IsPlaceHolder)
{
- if (VideoType == VideoType.BluRay || VideoType == VideoType.Dvd ||
- VideoType == VideoType.HdDvd)
+ if (VideoType == VideoType.BluRay || VideoType == VideoType.Dvd)
{
return Path;
}
@@ -357,7 +386,7 @@ namespace MediaBrowser.Controller.Entities
{
if (LocationType == LocationType.FileSystem)
{
- if (VideoType == VideoType.BluRay || VideoType == VideoType.Dvd || VideoType == VideoType.HdDvd)
+ if (VideoType == VideoType.BluRay || VideoType == VideoType.Dvd)
{
return System.IO.Path.GetFileName(Path);
}
@@ -395,18 +424,27 @@ namespace MediaBrowser.Controller.Entities
return base.IsValidFromResolver(newItem);
}
- /// <summary>
- /// Gets the playable stream files.
- /// </summary>
- /// <param name="rootPath">The root path.</param>
- /// <returns>List{System.String}.</returns>
- public List<string> GetPlayableStreamFiles(string rootPath)
+ public static string[] QueryPlayableStreamFiles(string rootPath, VideoType videoType)
{
- var allFiles = FileSystem.GetFilePaths(rootPath, true).ToList();
-
- return PlayableStreamFileNames.Select(name => allFiles.FirstOrDefault(f => string.Equals(System.IO.Path.GetFileName(f), name, StringComparison.OrdinalIgnoreCase)))
- .Where(f => !string.IsNullOrEmpty(f))
- .ToList();
+ if (videoType == VideoType.Dvd)
+ {
+ return FileSystem.GetFiles(rootPath, new[] { ".vob" }, false, true)
+ .OrderByDescending(i => i.Length)
+ .ThenBy(i => i.FullName)
+ .Take(1)
+ .Select(i => i.FullName)
+ .ToArray();
+ }
+ if (videoType == VideoType.BluRay)
+ {
+ return FileSystem.GetFiles(rootPath, new[] { ".m2ts" }, false, true)
+ .OrderByDescending(i => i.Length)
+ .ThenBy(i => i.FullName)
+ .Take(1)
+ .Select(i => i.FullName)
+ .ToArray();
+ }
+ return new string[] { };
}
/// <summary>
@@ -500,7 +538,7 @@ namespace MediaBrowser.Controller.Entities
public override IEnumerable<FileSystemMetadata> GetDeletePaths()
{
- if (!DetectIsInMixedFolder())
+ if (!IsInMixedFolder)
{
return new[] {
new FileSystemMetadata
@@ -514,17 +552,12 @@ namespace MediaBrowser.Controller.Entities
return base.GetDeletePaths();
}
- public IEnumerable<MediaStream> GetMediaStreams()
+ public List<MediaStream> GetMediaStreams()
{
- var mediaSource = GetMediaSources(false)
- .FirstOrDefault();
-
- if (mediaSource == null)
+ return MediaSourceManager.GetMediaStreams(new MediaStreamQuery
{
- return new List<MediaStream>();
- }
-
- return mediaSource.MediaStreams;
+ ItemId = Id
+ });
}
public virtual MediaStream GetDefaultVideoStream()
@@ -572,7 +605,7 @@ namespace MediaBrowser.Controller.Entities
return list;
}
- public virtual IEnumerable<MediaSourceInfo> GetMediaSources(bool enablePathSubstitution)
+ public virtual List<MediaSourceInfo> GetMediaSources(bool enablePathSubstitution)
{
if (SourceType == SourceType.Channel)
{
@@ -593,6 +626,14 @@ namespace MediaBrowser.Controller.Entities
var list = GetAllVideosForMediaSources();
var result = list.Select(i => GetVersionInfo(enablePathSubstitution, i.Item1, i.Item2)).ToList();
+ if (IsActiveRecording())
+ {
+ foreach (var mediaSource in result)
+ {
+ mediaSource.Type = MediaSourceType.Placeholder;
+ }
+ }
+
return result.OrderBy(i =>
{
if (i.VideoType == VideoType.VideoFile)
@@ -619,8 +660,7 @@ namespace MediaBrowser.Controller.Entities
throw new ArgumentNullException("media");
}
- var mediaStreams = MediaSourceManager.GetMediaStreams(media.Id)
- .ToList();
+ var mediaStreams = MediaSourceManager.GetMediaStreams(media.Id);
var locationType = media.LocationType;
@@ -639,7 +679,6 @@ namespace MediaBrowser.Controller.Entities
Size = media.Size,
Timestamp = media.Timestamp,
Type = type,
- PlayableStreamFileNames = media.PlayableStreamFileNames.ToList(),
SupportsDirectStream = media.VideoType == VideoType.VideoFile,
IsRemote = media.IsShortcut
};
@@ -714,10 +753,6 @@ namespace MediaBrowser.Controller.Entities
{
terms.Add("DVD");
}
- else if (video.VideoType == VideoType.HdDvd)
- {
- terms.Add("HD-DVD");
- }
else if (video.VideoType == VideoType.Iso)
{
if (video.IsoType.HasValue)
@@ -781,7 +816,7 @@ namespace MediaBrowser.Controller.Entities
}
}
- return string.Join("/", terms.ToArray());
+ return string.Join("/", terms.ToArray(terms.Count));
}
}
diff --git a/MediaBrowser.Controller/Entities/Year.cs b/MediaBrowser.Controller/Entities/Year.cs
index 61b1a3b1a..7d820b007 100644
--- a/MediaBrowser.Controller/Entities/Year.cs
+++ b/MediaBrowser.Controller/Entities/Year.cs
@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.Globalization;
-using System.Linq;
using MediaBrowser.Model.Serialization;
namespace MediaBrowser.Controller.Entities
diff --git a/MediaBrowser.Controller/IO/FileData.cs b/MediaBrowser.Controller/IO/FileData.cs
index 97b778d0c..880b3a0ce 100644
--- a/MediaBrowser.Controller/IO/FileData.cs
+++ b/MediaBrowser.Controller/IO/FileData.cs
@@ -3,7 +3,6 @@ using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Logging;
using System;
using System.Collections.Generic;
-
using MediaBrowser.Model.IO;
namespace MediaBrowser.Controller.IO
@@ -13,6 +12,17 @@ namespace MediaBrowser.Controller.IO
/// </summary>
public static class FileData
{
+ private static Dictionary<string, FileSystemMetadata> GetFileSystemDictionary(FileSystemMetadata[] list)
+ {
+ var dict = new Dictionary<string, FileSystemMetadata>(StringComparer.OrdinalIgnoreCase);
+
+ foreach (var file in list)
+ {
+ dict[file.FullName] = file;
+ }
+ return dict;
+ }
+
/// <summary>
/// Gets the filtered file system entries.
/// </summary>
@@ -25,7 +35,7 @@ namespace MediaBrowser.Controller.IO
/// <param name="resolveShortcuts">if set to <c>true</c> [resolve shortcuts].</param>
/// <returns>Dictionary{System.StringFileSystemInfo}.</returns>
/// <exception cref="System.ArgumentNullException">path</exception>
- public static Dictionary<string, FileSystemMetadata> GetFilteredFileSystemEntries(IDirectoryService directoryService,
+ public static FileSystemMetadata[] GetFilteredFileSystemEntries(IDirectoryService directoryService,
string path,
IFileSystem fileSystem,
ILogger logger,
@@ -42,13 +52,13 @@ namespace MediaBrowser.Controller.IO
throw new ArgumentNullException("args");
}
+ var entries = directoryService.GetFileSystemEntries(path);
+
if (!resolveShortcuts && flattenFolderDepth == 0)
{
- return directoryService.GetFileSystemDictionary(path);
+ return entries;
}
- var entries = directoryService.GetFileSystemEntries(path);
-
var dict = new Dictionary<string, FileSystemMetadata>(StringComparer.OrdinalIgnoreCase);
foreach (var entry in entries)
@@ -87,7 +97,7 @@ namespace MediaBrowser.Controller.IO
{
foreach (var child in GetFilteredFileSystemEntries(directoryService, fullName, fileSystem, logger, args, flattenFolderDepth: flattenFolderDepth - 1, resolveShortcuts: resolveShortcuts))
{
- dict[child.Key] = child.Value;
+ dict[child.FullName] = child;
}
}
else
@@ -96,7 +106,15 @@ namespace MediaBrowser.Controller.IO
}
}
- return dict;
+ var returnResult = new FileSystemMetadata[dict.Count];
+ var index = 0;
+ var values = dict.Values;
+ foreach (var value in values)
+ {
+ returnResult[index] = value;
+ index++;
+ }
+ return returnResult;
}
}
diff --git a/MediaBrowser.Controller/Library/ILibraryManager.cs b/MediaBrowser.Controller/Library/ILibraryManager.cs
index b726c267c..05845102b 100644
--- a/MediaBrowser.Controller/Library/ILibraryManager.cs
+++ b/MediaBrowser.Controller/Library/ILibraryManager.cs
@@ -181,15 +181,8 @@ namespace MediaBrowser.Controller.Library
/// <param name="sortBy">The sort by.</param>
/// <param name="sortOrder">The sort order.</param>
/// <returns>IEnumerable{BaseItem}.</returns>
- IEnumerable<BaseItem> Sort(IEnumerable<BaseItem> items, User user, IEnumerable<string> sortBy,
- SortOrder sortOrder);
-
- /// <summary>
- /// Ensure supplied item has only one instance throughout
- /// </summary>
- /// <param name="item">The item.</param>
- /// <returns>The proper instance to the item</returns>
- BaseItem GetOrAddByReferenceItem(BaseItem item);
+ IEnumerable<BaseItem> Sort(IEnumerable<BaseItem> items, User user, IEnumerable<string> sortBy, SortOrder sortOrder);
+ IEnumerable<BaseItem> Sort(IEnumerable<BaseItem> items, User user, IEnumerable<Tuple<string, SortOrder>> orderBy);
/// <summary>
/// Gets the user root folder.
@@ -202,16 +195,14 @@ namespace MediaBrowser.Controller.Library
/// </summary>
/// <param name="item">The item.</param>
/// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- Task CreateItem(BaseItem item, CancellationToken cancellationToken);
+ void CreateItem(BaseItem item, CancellationToken cancellationToken);
/// <summary>
/// Creates the items.
/// </summary>
/// <param name="items">The items.</param>
/// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- Task CreateItems(IEnumerable<BaseItem> items, CancellationToken cancellationToken);
+ void CreateItems(IEnumerable<BaseItem> items, CancellationToken cancellationToken);
/// <summary>
/// Updates the item.
@@ -284,7 +275,7 @@ namespace MediaBrowser.Controller.Library
/// </summary>
/// <param name="paths">The paths.</param>
/// <returns>IEnumerable{System.String}.</returns>
- IEnumerable<FileSystemMetadata> NormalizeRootPathList(IEnumerable<FileSystemMetadata> paths);
+ List<FileSystemMetadata> NormalizeRootPathList(IEnumerable<FileSystemMetadata> paths);
/// <summary>
/// Registers the item.
@@ -310,7 +301,7 @@ namespace MediaBrowser.Controller.Library
/// <param name="sortName">Name of the sort.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task&lt;UserView&gt;.</returns>
- Task<UserView> GetNamedView(User user,
+ UserView GetNamedView(User user,
string name,
string parentId,
string viewType,
@@ -326,7 +317,7 @@ namespace MediaBrowser.Controller.Library
/// <param name="sortName">Name of the sort.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task&lt;UserView&gt;.</returns>
- Task<UserView> GetNamedView(User user,
+ UserView GetNamedView(User user,
string name,
string viewType,
string sortName,
@@ -370,7 +361,7 @@ namespace MediaBrowser.Controller.Library
/// <param name="sortName">Name of the sort.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task&lt;UserView&gt;.</returns>
- Task<UserView> GetShadowView(BaseItem parent,
+ UserView GetShadowView(BaseItem parent,
string viewType,
string sortName,
CancellationToken cancellationToken);
@@ -478,8 +469,7 @@ namespace MediaBrowser.Controller.Library
/// </summary>
/// <param name="item">The item.</param>
/// <param name="people">The people.</param>
- /// <returns>Task.</returns>
- Task UpdatePeople(BaseItem item, List<PersonInfo> people);
+ void UpdatePeople(BaseItem item, List<PersonInfo> people);
/// <summary>
/// Gets the item ids.
@@ -520,21 +510,21 @@ namespace MediaBrowser.Controller.Library
/// <param name="image">The image.</param>
/// <param name="imageIndex">Index of the image.</param>
/// <returns>Task.</returns>
- Task<ItemImageInfo> ConvertImageToLocal(IHasImages item, ItemImageInfo image, int imageIndex);
+ Task<ItemImageInfo> ConvertImageToLocal(IHasMetadata item, ItemImageInfo image, int imageIndex);
/// <summary>
/// Gets the items.
/// </summary>
/// <param name="query">The query.</param>
/// <returns>QueryResult&lt;BaseItem&gt;.</returns>
- IEnumerable<BaseItem> GetItemList(InternalItemsQuery query);
+ List<BaseItem> GetItemList(InternalItemsQuery query);
- IEnumerable<BaseItem> GetItemList(InternalItemsQuery query, bool allowExternalContent);
+ List<BaseItem> GetItemList(InternalItemsQuery query, bool allowExternalContent);
/// <summary>
/// Gets the items.
/// </summary>
- IEnumerable<BaseItem> GetItemList(InternalItemsQuery query, List<BaseItem> parents);
+ List<BaseItem> GetItemList(InternalItemsQuery query, List<BaseItem> parents);
/// <summary>
/// Gets the items result.
diff --git a/MediaBrowser.Controller/Library/IMediaSourceManager.cs b/MediaBrowser.Controller/Library/IMediaSourceManager.cs
index 2f8f37789..204033e1d 100644
--- a/MediaBrowser.Controller/Library/IMediaSourceManager.cs
+++ b/MediaBrowser.Controller/Library/IMediaSourceManager.cs
@@ -24,19 +24,19 @@ namespace MediaBrowser.Controller.Library
/// </summary>
/// <param name="itemId">The item identifier.</param>
/// <returns>IEnumerable&lt;MediaStream&gt;.</returns>
- IEnumerable<MediaStream> GetMediaStreams(Guid itemId);
+ List<MediaStream> GetMediaStreams(Guid itemId);
/// <summary>
/// Gets the media streams.
/// </summary>
/// <param name="mediaSourceId">The media source identifier.</param>
/// <returns>IEnumerable&lt;MediaStream&gt;.</returns>
- IEnumerable<MediaStream> GetMediaStreams(string mediaSourceId);
+ List<MediaStream> GetMediaStreams(string mediaSourceId);
/// <summary>
/// Gets the media streams.
/// </summary>
/// <param name="query">The query.</param>
/// <returns>IEnumerable&lt;MediaStream&gt;.</returns>
- IEnumerable<MediaStream> GetMediaStreams(MediaStreamQuery query);
+ List<MediaStream> GetMediaStreams(MediaStreamQuery query);
/// <summary>
/// Gets the playack media sources.
@@ -56,7 +56,7 @@ namespace MediaBrowser.Controller.Library
/// <param name="enablePathSubstitution">if set to <c>true</c> [enable path substitution].</param>
/// <param name="user">The user.</param>
/// <returns>IEnumerable&lt;MediaSourceInfo&gt;.</returns>
- IEnumerable<MediaSourceInfo> GetStaticMediaSources(IHasMediaSources item, bool enablePathSubstitution, User user = null);
+ List<MediaSourceInfo> GetStaticMediaSources(IHasMediaSources item, bool enablePathSubstitution, User user = null);
/// <summary>
/// Gets the static media source.
diff --git a/MediaBrowser.Controller/Library/IMusicManager.cs b/MediaBrowser.Controller/Library/IMusicManager.cs
index 95ba671b4..535e6df7e 100644
--- a/MediaBrowser.Controller/Library/IMusicManager.cs
+++ b/MediaBrowser.Controller/Library/IMusicManager.cs
@@ -10,16 +10,16 @@ namespace MediaBrowser.Controller.Library
/// <summary>
/// Gets the instant mix from song.
/// </summary>
- IEnumerable<Audio> GetInstantMixFromItem(BaseItem item, User user, DtoOptions dtoOptions);
-
+ List<BaseItem> GetInstantMixFromItem(BaseItem item, User user, DtoOptions dtoOptions);
+
/// <summary>
/// Gets the instant mix from artist.
/// </summary>
- IEnumerable<Audio> GetInstantMixFromArtist(MusicArtist artist, User user, DtoOptions dtoOptions);
-
+ List<BaseItem> GetInstantMixFromArtist(MusicArtist artist, User user, DtoOptions dtoOptions);
+
/// <summary>
/// Gets the instant mix from genre.
/// </summary>
- IEnumerable<Audio> GetInstantMixFromGenres(IEnumerable<string> genres, User user, DtoOptions dtoOptions);
+ List<BaseItem> GetInstantMixFromGenres(IEnumerable<string> genres, User user, DtoOptions dtoOptions);
}
}
diff --git a/MediaBrowser.Controller/Library/IUserDataManager.cs b/MediaBrowser.Controller/Library/IUserDataManager.cs
index e9954545e..cd4bd2e34 100644
--- a/MediaBrowser.Controller/Library/IUserDataManager.cs
+++ b/MediaBrowser.Controller/Library/IUserDataManager.cs
@@ -4,7 +4,6 @@ using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
using System;
using System.Threading;
-using System.Threading.Tasks;
using MediaBrowser.Model.Querying;
namespace MediaBrowser.Controller.Library
@@ -28,7 +27,7 @@ namespace MediaBrowser.Controller.Library
/// <param name="reason">The reason.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
- Task SaveUserData(Guid userId, IHasUserData item, UserItemData userData, UserDataSaveReason reason, CancellationToken cancellationToken);
+ void SaveUserData(Guid userId, IHasUserData item, UserItemData userData, UserDataSaveReason reason, CancellationToken cancellationToken);
UserItemData GetUserData(IHasUserData user, IHasUserData item);
@@ -40,14 +39,14 @@ namespace MediaBrowser.Controller.Library
/// </summary>
UserItemDataDto GetUserDataDto(IHasUserData item, User user);
- UserItemDataDto GetUserDataDto(IHasUserData item, BaseItemDto itemDto, User user, List<ItemFields> fields);
+ UserItemDataDto GetUserDataDto(IHasUserData item, BaseItemDto itemDto, User user, ItemFields[] fields);
/// <summary>
/// Get all user data for the given user
/// </summary>
/// <param name="userId"></param>
/// <returns></returns>
- IEnumerable<UserItemData> GetAllUserData(Guid userId);
+ List<UserItemData> GetAllUserData(Guid userId);
/// <summary>
/// Save the all provided user data for the given user
@@ -56,7 +55,7 @@ namespace MediaBrowser.Controller.Library
/// <param name="userData"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
- Task SaveAllUserData(Guid userId, IEnumerable<UserItemData> userData, CancellationToken cancellationToken);
+ void SaveAllUserData(Guid userId, UserItemData[] userData, CancellationToken cancellationToken);
/// <summary>
/// Updates playstate for an item and returns true or false indicating if it was played to completion
diff --git a/MediaBrowser.Controller/Library/IUserManager.cs b/MediaBrowser.Controller/Library/IUserManager.cs
index ef68d2560..6da3e53aa 100644
--- a/MediaBrowser.Controller/Library/IUserManager.cs
+++ b/MediaBrowser.Controller/Library/IUserManager.cs
@@ -91,7 +91,7 @@ namespace MediaBrowser.Controller.Library
/// <param name="user">The user.</param>
/// <exception cref="System.ArgumentNullException">user</exception>
/// <exception cref="System.ArgumentException"></exception>
- Task UpdateUser(User user);
+ void UpdateUser(User user);
/// <summary>
/// Creates the user.
@@ -116,7 +116,7 @@ namespace MediaBrowser.Controller.Library
/// </summary>
/// <param name="user">The user.</param>
/// <returns>Task.</returns>
- Task ResetPassword(User user);
+ void ResetPassword(User user);
/// <summary>
/// Gets the offline user dto.
@@ -130,7 +130,7 @@ namespace MediaBrowser.Controller.Library
/// </summary>
/// <param name="user">The user.</param>
/// <returns>Task.</returns>
- Task ResetEasyPassword(User user);
+ void ResetEasyPassword(User user);
/// <summary>
/// Changes the password.
@@ -138,7 +138,7 @@ namespace MediaBrowser.Controller.Library
/// <param name="user">The user.</param>
/// <param name="newPasswordSha1">The new password sha1.</param>
/// <returns>Task.</returns>
- Task ChangePassword(User user, string newPasswordSha1);
+ void ChangePassword(User user, string newPasswordSha1);
/// <summary>
/// Changes the easy password.
@@ -146,7 +146,7 @@ namespace MediaBrowser.Controller.Library
/// <param name="user">The user.</param>
/// <param name="newPasswordSha1">The new password sha1.</param>
/// <returns>Task.</returns>
- Task ChangeEasyPassword(User user, string newPasswordSha1);
+ void ChangeEasyPassword(User user, string newPasswordSha1);
/// <summary>
/// Gets the user dto.
@@ -179,7 +179,7 @@ namespace MediaBrowser.Controller.Library
/// </summary>
/// <param name="pin">The pin.</param>
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
- Task<PinRedeemResult> RedeemPasswordResetPin(string pin);
+ PinRedeemResult RedeemPasswordResetPin(string pin);
/// <summary>
/// Gets the user policy.
@@ -201,14 +201,14 @@ namespace MediaBrowser.Controller.Library
/// <param name="userId">The user identifier.</param>
/// <param name="newConfiguration">The new configuration.</param>
/// <returns>Task.</returns>
- Task UpdateConfiguration(string userId, UserConfiguration newConfiguration);
+ void UpdateConfiguration(string userId, UserConfiguration newConfiguration);
/// <summary>
/// Updates the user policy.
/// </summary>
/// <param name="userId">The user identifier.</param>
/// <param name="userPolicy">The user policy.</param>
- Task UpdateUserPolicy(string userId, UserPolicy userPolicy);
+ void UpdateUserPolicy(string userId, UserPolicy userPolicy);
/// <summary>
/// Makes the valid username.
diff --git a/MediaBrowser.Controller/Library/IUserViewManager.cs b/MediaBrowser.Controller/Library/IUserViewManager.cs
index b46ece49d..76182c641 100644
--- a/MediaBrowser.Controller/Library/IUserViewManager.cs
+++ b/MediaBrowser.Controller/Library/IUserViewManager.cs
@@ -11,7 +11,7 @@ namespace MediaBrowser.Controller.Library
{
public interface IUserViewManager
{
- Task<IEnumerable<Folder>> GetUserViews(UserViewQuery query, CancellationToken cancellationToken);
+ Task<Folder[]> GetUserViews(UserViewQuery query, CancellationToken cancellationToken);
Task<UserView> GetUserSubView(string name, string parentId, string type, string sortName, CancellationToken cancellationToken);
diff --git a/MediaBrowser.Controller/Library/ItemResolveArgs.cs b/MediaBrowser.Controller/Library/ItemResolveArgs.cs
index 76b6d8768..56392eee7 100644
--- a/MediaBrowser.Controller/Library/ItemResolveArgs.cs
+++ b/MediaBrowser.Controller/Library/ItemResolveArgs.cs
@@ -4,7 +4,6 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
-
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.IO;
using MediaBrowser.Model.Configuration;
@@ -40,20 +39,7 @@ namespace MediaBrowser.Controller.Library
/// Gets the file system children.
/// </summary>
/// <value>The file system children.</value>
- public IEnumerable<FileSystemMetadata> FileSystemChildren
- {
- get
- {
- var dict = FileSystemDictionary;
-
- if (dict == null)
- {
- return new List<FileSystemMetadata>();
- }
-
- return dict.Values;
- }
- }
+ public FileSystemMetadata[] FileSystemChildren { get; set; }
public LibraryOptions LibraryOptions { get; set; }
@@ -63,12 +49,6 @@ namespace MediaBrowser.Controller.Library
}
/// <summary>
- /// Gets or sets the file system dictionary.
- /// </summary>
- /// <value>The file system dictionary.</value>
- public Dictionary<string, FileSystemMetadata> FileSystemDictionary { get; set; }
-
- /// <summary>
/// Gets or sets the parent.
/// </summary>
/// <value>The parent.</value>
@@ -153,7 +133,14 @@ namespace MediaBrowser.Controller.Library
// Not officially supported but in some cases we can handle it.
if (item == null)
{
- item = parent.GetParents().OfType<T>().FirstOrDefault();
+ var parents = parent.GetParents();
+ foreach (var currentParent in parents)
+ {
+ if (currentParent is T)
+ {
+ return true;
+ }
+ }
}
return item != null;
@@ -186,12 +173,12 @@ namespace MediaBrowser.Controller.Library
/// Gets the physical locations.
/// </summary>
/// <value>The physical locations.</value>
- public IEnumerable<string> PhysicalLocations
+ public string[] PhysicalLocations
{
get
{
var paths = string.IsNullOrWhiteSpace(Path) ? new string[] { } : new[] { Path };
- return AdditionalLocations == null ? paths : paths.Concat(AdditionalLocations);
+ return AdditionalLocations == null ? paths : paths.Concat(AdditionalLocations).ToArray();
}
}
@@ -224,13 +211,11 @@ namespace MediaBrowser.Controller.Library
throw new ArgumentNullException();
}
- if (FileSystemDictionary != null)
+ foreach (var file in FileSystemChildren)
{
- FileSystemMetadata entry;
-
- if (FileSystemDictionary.TryGetValue(path, out entry))
+ if (string.Equals(file.FullName, path, StringComparison.Ordinal))
{
- return entry;
+ return file;
}
}
diff --git a/MediaBrowser.Controller/Library/NameExtensions.cs b/MediaBrowser.Controller/Library/NameExtensions.cs
index 693b7b221..bab334a6d 100644
--- a/MediaBrowser.Controller/Library/NameExtensions.cs
+++ b/MediaBrowser.Controller/Library/NameExtensions.cs
@@ -1,7 +1,5 @@
using System;
using System.Collections.Generic;
-using System.Globalization;
-using System.Linq;
using MediaBrowser.Controller.Extensions;
using MediaBrowser.Model.Extensions;
@@ -9,25 +7,6 @@ namespace MediaBrowser.Controller.Library
{
public static class NameExtensions
{
- public static bool EqualsAny(IEnumerable<string> names, string x)
- {
- x = NormalizeForComparison(x);
-
- return names.Any(y => string.Compare(x, y, StringComparison.OrdinalIgnoreCase) == 0);
- //return names.Any(y => string.Compare(x, y, CultureInfo.InvariantCulture, CompareOptions.IgnoreCase | CompareOptions.IgnoreNonSpace) == 0);
- }
-
- private static string NormalizeForComparison(string name)
- {
- if (name == null)
- {
- return string.Empty;
- }
-
- return name;
- //return name.RemoveDiacritics();
- }
-
private static string RemoveDiacritics(string name)
{
if (name == null)
@@ -44,27 +23,4 @@ namespace MediaBrowser.Controller.Library
return names.DistinctBy(RemoveDiacritics, StringComparer.OrdinalIgnoreCase);
}
}
-
- public class DistinctNameComparer : IComparer<string>, IEqualityComparer<string>
- {
- public int Compare(string x, string y)
- {
- if (string.IsNullOrWhiteSpace(x) && string.IsNullOrWhiteSpace(y))
- {
- return 0;
- }
-
- return string.Compare(x.RemoveDiacritics(), y.RemoveDiacritics(), StringComparison.OrdinalIgnoreCase);
- }
-
- public bool Equals(string x, string y)
- {
- return Compare(x, y) == 0;
- }
-
- public int GetHashCode(string obj)
- {
- return (obj ?? string.Empty).GetHashCode();
- }
- }
}
diff --git a/MediaBrowser.Controller/Library/TVUtils.cs b/MediaBrowser.Controller/Library/TVUtils.cs
index 29421ebaf..7c82ec293 100644
--- a/MediaBrowser.Controller/Library/TVUtils.cs
+++ b/MediaBrowser.Controller/Library/TVUtils.cs
@@ -22,13 +22,13 @@ namespace MediaBrowser.Controller.Library
/// </summary>
/// <param name="day">The day.</param>
/// <returns>List{DayOfWeek}.</returns>
- public static List<DayOfWeek> GetAirDays(string day)
+ public static DayOfWeek[] GetAirDays(string day)
{
if (!string.IsNullOrWhiteSpace(day))
{
if (day.Equals("Daily", StringComparison.OrdinalIgnoreCase))
{
- return new List<DayOfWeek>
+ return new DayOfWeek[]
{
DayOfWeek.Sunday,
DayOfWeek.Monday,
@@ -44,13 +44,13 @@ namespace MediaBrowser.Controller.Library
if (Enum.TryParse(day, true, out value))
{
- return new List<DayOfWeek>
+ return new DayOfWeek[]
{
value
};
}
- return new List<DayOfWeek>();
+ return new DayOfWeek[]{};
}
return null;
}
diff --git a/MediaBrowser.Controller/LiveTv/ChannelInfo.cs b/MediaBrowser.Controller/LiveTv/ChannelInfo.cs
index 6682942ad..892a7d5b7 100644
--- a/MediaBrowser.Controller/LiveTv/ChannelInfo.cs
+++ b/MediaBrowser.Controller/LiveTv/ChannelInfo.cs
@@ -25,6 +25,8 @@ namespace MediaBrowser.Controller.LiveTv
/// <value>The id of the channel.</value>
public string Id { get; set; }
+ public string Path { get; set; }
+
public string TunerChannelId { get; set; }
public string CallSign { get; set; }
diff --git a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs
index 288b30278..42c31c629 100644
--- a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs
+++ b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs
@@ -109,7 +109,7 @@ namespace MediaBrowser.Controller.LiveTv
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>QueryResult{RecordingInfoDto}.</returns>
Task<QueryResult<BaseItemDto>> GetRecordings(RecordingQuery query, DtoOptions options, CancellationToken cancellationToken);
- Task<QueryResult<BaseItemDto>> GetRecordingSeries(RecordingQuery query, DtoOptions options, CancellationToken cancellationToken);
+ QueryResult<BaseItemDto> GetRecordingSeries(RecordingQuery query, DtoOptions options, CancellationToken cancellationToken);
/// <summary>
/// Gets the timers.
@@ -243,7 +243,7 @@ namespace MediaBrowser.Controller.LiveTv
/// Gets the recommended programs internal.
/// </summary>
/// <returns>Task&lt;QueryResult&lt;LiveTvProgram&gt;&gt;.</returns>
- Task<QueryResult<LiveTvProgram>> GetRecommendedProgramsInternal(RecommendedProgramQuery query, DtoOptions options, CancellationToken cancellationToken);
+ Task<QueryResult<BaseItem>> GetRecommendedProgramsInternal(RecommendedProgramQuery query, DtoOptions options, CancellationToken cancellationToken);
/// <summary>
/// Gets the live tv information.
@@ -284,7 +284,7 @@ namespace MediaBrowser.Controller.LiveTv
/// <summary>
/// Gets the internal channels.
/// </summary>
- Task<QueryResult<LiveTvChannel>> GetInternalChannels(LiveTvChannelQuery query, DtoOptions dtoOptions, CancellationToken cancellationToken);
+ Task<QueryResult<BaseItem>> GetInternalChannels(LiveTvChannelQuery query, DtoOptions dtoOptions, CancellationToken cancellationToken);
/// <summary>
/// Gets the internal recordings.
@@ -316,7 +316,7 @@ namespace MediaBrowser.Controller.LiveTv
/// <param name="fields">The fields.</param>
/// <param name="user">The user.</param>
/// <returns>Task.</returns>
- Task AddInfoToProgramDto(List<Tuple<BaseItem, BaseItemDto>> programs, List<ItemFields> fields, User user = null);
+ Task AddInfoToProgramDto(List<Tuple<BaseItem, BaseItemDto>> programs, ItemFields[] fields, User user = null);
/// <summary>
/// Saves the tuner host.
@@ -335,7 +335,7 @@ namespace MediaBrowser.Controller.LiveTv
Task<TunerChannelMapping> SetChannelMapping(string providerId, string tunerChannelNumber, string providerChannelNumber);
- TunerChannelMapping GetTunerChannelMapping(ChannelInfo channel, List<NameValuePair> mappings, List<ChannelInfo> providerChannels);
+ TunerChannelMapping GetTunerChannelMapping(ChannelInfo channel, NameValuePair[] mappings, List<ChannelInfo> providerChannels);
/// <summary>
/// Gets the lineups.
@@ -360,7 +360,7 @@ namespace MediaBrowser.Controller.LiveTv
/// <param name="items">The items.</param>
/// <param name="options">The options.</param>
/// <param name="user">The user.</param>
- Task AddChannelInfo(List<Tuple<BaseItemDto, LiveTvChannel>> items, DtoOptions options, User user);
+ void AddChannelInfo(List<Tuple<BaseItemDto, LiveTvChannel>> items, DtoOptions options, User user);
/// <summary>
/// Called when [recording file deleted].
@@ -384,5 +384,9 @@ namespace MediaBrowser.Controller.LiveTv
string GetEmbyTvActiveRecordingPath(string id);
Task<LiveStream> GetEmbyTvLiveStream(string id);
+
+ ActiveRecordingInfo GetActiveRecordingInfo(string path);
+
+ void AddInfoToRecordingDto(BaseItem item, BaseItemDto dto, ActiveRecordingInfo activeRecordingInfo, User user = null);
}
}
diff --git a/MediaBrowser.Controller/LiveTv/ILiveTvRecording.cs b/MediaBrowser.Controller/LiveTv/ILiveTvRecording.cs
index 1bbd1a008..4b757f0b9 100644
--- a/MediaBrowser.Controller/LiveTv/ILiveTvRecording.cs
+++ b/MediaBrowser.Controller/LiveTv/ILiveTvRecording.cs
@@ -9,7 +9,7 @@ using System.Threading.Tasks;
namespace MediaBrowser.Controller.LiveTv
{
- public interface ILiveTvRecording : IHasImages, IHasMediaSources, IHasUserData, IHasStartDate, IHasProgramAttributes
+ public interface ILiveTvRecording : IHasMetadata, IHasMediaSources, IHasUserData, IHasStartDate, IHasProgramAttributes
{
string ServiceName { get; set; }
string ExternalId { get; set; }
@@ -18,8 +18,6 @@ namespace MediaBrowser.Controller.LiveTv
string Container { get; }
- long? RunTimeTicks { get; set; }
-
string GetClientTypeName();
bool IsParentalAllowed(User user);
@@ -36,8 +34,15 @@ namespace MediaBrowser.Controller.LiveTv
string TimerId { get; set; }
RecordingStatus Status { get; set; }
DateTime? EndDate { get; set; }
- DateTime DateLastSaved { get; set; }
DateTime DateCreated { get; set; }
- DateTime DateModified { get; set; }
+ }
+
+ public class ActiveRecordingInfo
+ {
+ public string Id { get; set; }
+ public string Path { get; set; }
+ public TimerInfo Timer { get; set; }
+ public ProgramInfo Program { get; set; }
+ public CancellationTokenSource CancellationTokenSource { get; set; }
}
}
diff --git a/MediaBrowser.Controller/LiveTv/LiveTvAudioRecording.cs b/MediaBrowser.Controller/LiveTv/LiveTvAudioRecording.cs
index 9f8234402..c29d73253 100644
--- a/MediaBrowser.Controller/LiveTv/LiveTvAudioRecording.cs
+++ b/MediaBrowser.Controller/LiveTv/LiveTvAudioRecording.cs
@@ -6,7 +6,6 @@ using MediaBrowser.Model.Entities;
using MediaBrowser.Model.LiveTv;
using System;
using System.Collections.Generic;
-using System.Linq;
using MediaBrowser.Model.Serialization;
using System.Threading.Tasks;
using MediaBrowser.Controller.Library;
@@ -151,9 +150,9 @@ namespace MediaBrowser.Controller.LiveTv
return user.Policy.EnableLiveTvManagement;
}
- public override IEnumerable<MediaSourceInfo> GetMediaSources(bool enablePathSubstitution)
+ public override List<MediaSourceInfo> GetMediaSources(bool enablePathSubstitution)
{
- var list = base.GetMediaSources(enablePathSubstitution).ToList();
+ var list = base.GetMediaSources(enablePathSubstitution);
foreach (var mediaSource in list)
{
diff --git a/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs b/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs
index 898ea9ff4..4a93d0399 100644
--- a/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs
+++ b/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs
@@ -122,7 +122,7 @@ namespace MediaBrowser.Controller.LiveTv
return new List<BaseItem>();
}
- public IEnumerable<MediaSourceInfo> GetMediaSources(bool enablePathSubstitution)
+ public List<MediaSourceInfo> GetMediaSources(bool enablePathSubstitution)
{
var list = new List<MediaSourceInfo>();
@@ -144,6 +144,11 @@ namespace MediaBrowser.Controller.LiveTv
return list;
}
+ public List<MediaStream> GetMediaStreams()
+ {
+ return new List<MediaStream>();
+ }
+
protected override string GetInternalMetadataPath(string basePath)
{
return System.IO.Path.Combine(basePath, "livetv", Id.ToString("N"), "metadata");
diff --git a/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs b/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs
index 9f55a9ff2..1607dbcba 100644
--- a/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs
+++ b/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs
@@ -9,7 +9,6 @@ using MediaBrowser.Common.Configuration;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Providers;
using MediaBrowser.Model.Serialization;
-using MediaBrowser.Model.Extensions;
namespace MediaBrowser.Controller.LiveTv
{
@@ -48,22 +47,19 @@ namespace MediaBrowser.Controller.LiveTv
return list;
}
+ private static string EmbyServiceName = "Emby";
public override double? GetDefaultPrimaryImageAspectRatio()
{
- if (IsMovie)
+ var serviceName = ServiceName;
+ if (!IsMovie && !string.Equals(serviceName, EmbyServiceName, StringComparison.OrdinalIgnoreCase) || !string.IsNullOrWhiteSpace(serviceName))
{
- double value = 2;
- value /= 3;
-
- return value;
+ return null;
}
- else
- {
- double value = 2;
- value /= 3;
- return value;
- }
+ double value = 2;
+ value /= 3;
+
+ return value;
}
[IgnoreDataMember]
@@ -227,7 +223,7 @@ namespace MediaBrowser.Controller.LiveTv
public LiveTvProgramLookupInfo GetLookupInfo()
{
var info = GetItemLookupInfo<LiveTvProgramLookupInfo>();
- info.IsMovie = IsMovie;
+ info.IsMovie = IsMovie;
return info;
}
diff --git a/MediaBrowser.Controller/LiveTv/LiveTvVideoRecording.cs b/MediaBrowser.Controller/LiveTv/LiveTvVideoRecording.cs
index c29d3dc47..950949f37 100644
--- a/MediaBrowser.Controller/LiveTv/LiveTvVideoRecording.cs
+++ b/MediaBrowser.Controller/LiveTv/LiveTvVideoRecording.cs
@@ -5,7 +5,6 @@ using MediaBrowser.Model.Entities;
using MediaBrowser.Model.LiveTv;
using System;
using System.Collections.Generic;
-using System.Linq;
using MediaBrowser.Model.Serialization;
using System.Threading.Tasks;
using MediaBrowser.Controller.Library;
@@ -54,15 +53,6 @@ namespace MediaBrowser.Controller.LiveTv
}
[IgnoreDataMember]
- protected override bool SupportsIsInMixedFolderDetection
- {
- get
- {
- return false;
- }
- }
-
- [IgnoreDataMember]
public override bool SupportsPlayedStatus
{
get
@@ -159,9 +149,9 @@ namespace MediaBrowser.Controller.LiveTv
return user.Policy.EnableLiveTvManagement;
}
- public override IEnumerable<MediaSourceInfo> GetMediaSources(bool enablePathSubstitution)
+ public override List<MediaSourceInfo> GetMediaSources(bool enablePathSubstitution)
{
- var list = base.GetMediaSources(enablePathSubstitution).ToList();
+ var list = base.GetMediaSources(enablePathSubstitution);
foreach (var mediaSource in list)
{
diff --git a/MediaBrowser.Controller/LiveTv/TimerInfo.cs b/MediaBrowser.Controller/LiveTv/TimerInfo.cs
index 0b94c85fa..a0002241d 100644
--- a/MediaBrowser.Controller/LiveTv/TimerInfo.cs
+++ b/MediaBrowser.Controller/LiveTv/TimerInfo.cs
@@ -109,6 +109,9 @@ namespace MediaBrowser.Controller.LiveTv
public bool IsKids { get; set; }
public bool IsSports { get; set; }
public bool IsNews { get; set; }
+ public bool IsSeries { get; set; }
+ public bool IsLive { get; set; }
+ public bool IsPremiere { get; set; }
public int? ProductionYear { get; set; }
public string EpisodeTitle { get; set; }
public DateTime? OriginalAirDate { get; set; }
diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj
index 9cba48b74..5ef763b62 100644
--- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj
+++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj
@@ -99,8 +99,6 @@
<Compile Include="Entities\GameSystem.cs" />
<Compile Include="Entities\IHasAspectRatio.cs" />
<Compile Include="Entities\IHasDisplayOrder.cs" />
- <Compile Include="Entities\IHasId.cs" />
- <Compile Include="Entities\IHasImages.cs" />
<Compile Include="Entities\IHasMediaSources.cs" />
<Compile Include="Entities\IHasProgramAttributes.cs" />
<Compile Include="Entities\IHasScreenshots.cs" />
@@ -168,7 +166,6 @@
<Compile Include="LiveTv\TimerEventInfo.cs" />
<Compile Include="LiveTv\TimerInfo.cs" />
<Compile Include="LiveTv\TunerChannelMapping.cs" />
- <Compile Include="MediaEncoding\ChapterImageRefreshOptions.cs" />
<Compile Include="MediaEncoding\EncodingHelper.cs" />
<Compile Include="MediaEncoding\EncodingJobInfo.cs" />
<Compile Include="MediaEncoding\EncodingJobOptions.cs" />
@@ -176,7 +173,6 @@
<Compile Include="MediaEncoding\ImageEncodingOptions.cs" />
<Compile Include="MediaEncoding\IMediaEncoder.cs" />
<Compile Include="MediaEncoding\ISubtitleEncoder.cs" />
- <Compile Include="MediaEncoding\JobLogger.cs" />
<Compile Include="MediaEncoding\MediaInfoRequest.cs" />
<Compile Include="MediaEncoding\MediaStreamSelector.cs" />
<Compile Include="Net\AuthenticatedAttribute.cs" />
@@ -187,14 +183,12 @@
<Compile Include="Net\IHttpResultFactory.cs" />
<Compile Include="Net\IHttpServer.cs" />
<Compile Include="Net\IServerManager.cs" />
- <Compile Include="Net\IServiceRequest.cs" />
<Compile Include="Net\ISessionContext.cs" />
<Compile Include="Net\IWebSocket.cs" />
<Compile Include="Net\IWebSocketConnection.cs" />
<Compile Include="Net\IWebSocketListener.cs" />
<Compile Include="Net\LoggedAttribute.cs" />
<Compile Include="Net\SecurityException.cs" />
- <Compile Include="Net\ServiceRequest.cs" />
<Compile Include="Net\StaticResultOptions.cs" />
<Compile Include="Net\WebSocketConnectEventArgs.cs" />
<Compile Include="Net\WebSocketMessageInfo.cs" />
@@ -339,7 +333,6 @@
<Compile Include="Sync\ISyncDataProvider.cs" />
<Compile Include="Sync\ISyncManager.cs" />
<Compile Include="Sync\ISyncProvider.cs" />
- <Compile Include="Sync\ISyncRepository.cs" />
<Compile Include="Sync\SyncedFileInfo.cs" />
<Compile Include="Sync\SyncedItemProgress.cs" />
<Compile Include="TV\ITVSeriesManager.cs" />
diff --git a/MediaBrowser.Controller/MediaEncoding/ChapterImageRefreshOptions.cs b/MediaBrowser.Controller/MediaEncoding/ChapterImageRefreshOptions.cs
deleted file mode 100644
index e11bd6cdf..000000000
--- a/MediaBrowser.Controller/MediaEncoding/ChapterImageRefreshOptions.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Model.Entities;
-using System.Collections.Generic;
-
-namespace MediaBrowser.Controller.MediaEncoding
-{
- public class ChapterImageRefreshOptions
- {
- public Video Video { get; set; }
-
- public List<ChapterInfo> Chapters { get; set; }
-
- public bool SaveChapters { get; set; }
-
- public bool ExtractImages { get; set; }
- }
-}
diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs
index bd7bbb6fe..531711b55 100644
--- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs
+++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs
@@ -4,13 +4,14 @@ using System.Globalization;
using System.IO;
using System.Linq;
using System.Threading;
-using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Controller.Entities;
using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Dlna;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.MediaInfo;
+using MediaBrowser.Model.Extensions;
namespace MediaBrowser.Controller.MediaEncoding
{
@@ -19,14 +20,12 @@ namespace MediaBrowser.Controller.MediaEncoding
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
private readonly IMediaEncoder _mediaEncoder;
- private readonly IServerConfigurationManager _config;
private readonly IFileSystem _fileSystem;
private readonly ISubtitleEncoder _subtitleEncoder;
- public EncodingHelper(IMediaEncoder mediaEncoder, IServerConfigurationManager config, IFileSystem fileSystem, ISubtitleEncoder subtitleEncoder)
+ public EncodingHelper(IMediaEncoder mediaEncoder, IFileSystem fileSystem, ISubtitleEncoder subtitleEncoder)
{
_mediaEncoder = mediaEncoder;
- _config = config;
_fileSystem = fileSystem;
_subtitleEncoder = subtitleEncoder;
}
@@ -151,10 +150,13 @@ namespace MediaBrowser.Controller.MediaEncoding
public string GetInputFormat(string container)
{
- if (string.Equals(container, "mkv", StringComparison.OrdinalIgnoreCase))
+ if (string.IsNullOrWhiteSpace(container))
{
- return "matroska";
+ return null;
}
+
+ container = container.Replace("mkv", "matroska", StringComparison.OrdinalIgnoreCase);
+
if (string.Equals(container, "ts", StringComparison.OrdinalIgnoreCase))
{
return "mpegts";
@@ -209,6 +211,10 @@ namespace MediaBrowser.Controller.MediaEncoding
{
return null;
}
+ if (string.Equals(container, "rtp", StringComparison.OrdinalIgnoreCase))
+ {
+ return null;
+ }
// Seeing reported failures here, not sure yet if this is related to specfying input format
if (string.Equals(container, "m4v", StringComparison.OrdinalIgnoreCase))
@@ -772,6 +778,11 @@ namespace MediaBrowser.Controller.MediaEncoding
return false;
}
+ if (state.EnableMpDecimate)
+ {
+ return false;
+ }
+
if (videoStream.IsInterlaced)
{
if (request.DeInterlace)
@@ -923,19 +934,6 @@ namespace MediaBrowser.Controller.MediaEncoding
return false;
}
- // Video bitrate must fall within requested value
- if (request.AudioBitRate.HasValue)
- {
- if (!audioStream.BitRate.HasValue || audioStream.BitRate.Value <= 0)
- {
- return false;
- }
- if (audioStream.BitRate.Value > request.AudioBitRate.Value)
- {
- return false;
- }
- }
-
// Channels must fall within requested value
var channels = request.AudioChannels ?? request.MaxAudioChannels;
if (channels.HasValue)
@@ -963,6 +961,19 @@ namespace MediaBrowser.Controller.MediaEncoding
}
}
+ // Video bitrate must fall within requested value
+ if (request.AudioBitRate.HasValue)
+ {
+ if (!audioStream.BitRate.HasValue || audioStream.BitRate.Value <= 0)
+ {
+ return false;
+ }
+ if (audioStream.BitRate.Value > request.AudioBitRate.Value)
+ {
+ return false;
+ }
+ }
+
return request.EnableAutoStreamCopy;
}
@@ -1443,6 +1454,11 @@ namespace MediaBrowser.Controller.MediaEncoding
}
}
+ if (state.EnableMpDecimate)
+ {
+ filters.Add("mpdecimate,setpts=N/FRAME_RATE/TB");
+ }
+
if (filters.Count > 0)
{
output += string.Format(" -vf \"{0}\"", string.Join(",", filters.ToArray()));
@@ -1515,7 +1531,7 @@ namespace MediaBrowser.Controller.MediaEncoding
{
var inputModifier = string.Empty;
- var numInputFiles = state.PlayableStreamFileNames.Count > 0 ? state.PlayableStreamFileNames.Count : 1;
+ var numInputFiles = state.PlayableStreamFileNames.Length > 0 ? state.PlayableStreamFileNames.Length : 1;
var probeSizeArgument = GetProbeSizeArgument(numInputFiles);
string analyzeDurationArgument;
@@ -1625,26 +1641,6 @@ namespace MediaBrowser.Controller.MediaEncoding
inputModifier += " -f " + inputFormat;
}
}
-
- // Only do this for video files due to sometimes unpredictable codec names coming from BDInfo
- if (state.VideoType == VideoType.VideoFile && state.RunTimeTicks.HasValue && string.IsNullOrWhiteSpace(encodingOptions.HardwareAccelerationType))
- {
- foreach (var stream in state.MediaSource.MediaStreams)
- {
- if (!stream.IsExternal && stream.Type != MediaStreamType.Subtitle)
- {
- if (!string.IsNullOrWhiteSpace(stream.Codec) && stream.Index != -1)
- {
- var decoder = GetDecoderFromCodec(stream.Codec);
-
- if (!string.IsNullOrWhiteSpace(decoder))
- {
- inputModifier += " -codec:" + stream.Index.ToString(_usCulture) + " " + decoder;
- }
- }
- }
- }
- }
}
if (state.MediaSource.RequiresLooping)
@@ -1675,14 +1671,33 @@ namespace MediaBrowser.Controller.MediaEncoding
state.RunTimeTicks = mediaSource.RunTimeTicks;
state.RemoteHttpHeaders = mediaSource.RequiredHttpHeaders;
+ state.IsoType = mediaSource.IsoType;
+
if (mediaSource.VideoType.HasValue)
{
state.VideoType = mediaSource.VideoType.Value;
- }
-
- state.IsoType = mediaSource.IsoType;
- state.PlayableStreamFileNames = mediaSource.PlayableStreamFileNames.ToList();
+ if (mediaSource.VideoType.Value == VideoType.BluRay || mediaSource.VideoType.Value == VideoType.Dvd)
+ {
+ state.PlayableStreamFileNames = Video.QueryPlayableStreamFiles(state.MediaPath, mediaSource.VideoType.Value).Select(Path.GetFileName).ToArray();
+ }
+ else if (mediaSource.VideoType.Value == VideoType.Iso && state.IsoType == IsoType.BluRay)
+ {
+ state.PlayableStreamFileNames = Video.QueryPlayableStreamFiles(state.MediaPath, VideoType.BluRay).Select(Path.GetFileName).ToArray();
+ }
+ else if (mediaSource.VideoType.Value == VideoType.Iso && state.IsoType == IsoType.Dvd)
+ {
+ state.PlayableStreamFileNames = Video.QueryPlayableStreamFiles(state.MediaPath, VideoType.Dvd).Select(Path.GetFileName).ToArray();
+ }
+ else
+ {
+ state.PlayableStreamFileNames = new string[]{};
+ }
+ }
+ else
+ {
+ state.PlayableStreamFileNames = new string[] { };
+ }
if (mediaSource.Timestamp.HasValue)
{
@@ -1702,7 +1717,8 @@ namespace MediaBrowser.Controller.MediaEncoding
state.InputAudioSync = "1";
}
- if (string.Equals(mediaSource.Container, "wma", StringComparison.OrdinalIgnoreCase))
+ if (string.Equals(mediaSource.Container, "wma", StringComparison.OrdinalIgnoreCase) ||
+ string.Equals(mediaSource.Container, "asf", StringComparison.OrdinalIgnoreCase))
{
// Seeing some stuttering when transcoding wma to audio-only HLS
state.InputAudioSync = "1";
@@ -1776,50 +1792,54 @@ namespace MediaBrowser.Controller.MediaEncoding
return null;
}
+ return GetVideoDecoder(state.MediaSource.VideoType ?? VideoType.VideoFile, state.VideoStream, encodingOptions);
+ }
+
+ public string GetVideoDecoder(VideoType videoType, MediaStream videoStream, EncodingOptions encodingOptions)
+ {
// Only use alternative encoders for video files.
// When using concat with folder rips, if the mfx session fails to initialize, ffmpeg will be stuck retrying and will not exit gracefully
// Since transcoding of folder rips is expiremental anyway, it's not worth adding additional variables such as this.
- if (state.VideoType != VideoType.VideoFile)
+ if (videoType != VideoType.VideoFile)
{
return null;
}
- if (state.VideoStream != null &&
- !string.IsNullOrWhiteSpace(state.VideoStream.Codec) &&
- !string.IsNullOrWhiteSpace(encodingOptions.HardwareAccelerationType) &&
- encodingOptions.EnableHardwareDecoding)
+ if (videoStream != null &&
+ !string.IsNullOrWhiteSpace(videoStream.Codec) &&
+ !string.IsNullOrWhiteSpace(encodingOptions.HardwareAccelerationType))
{
if (string.Equals(encodingOptions.HardwareAccelerationType, "qsv", StringComparison.OrdinalIgnoreCase))
{
- switch (state.MediaSource.VideoStream.Codec.ToLower())
+ switch (videoStream.Codec.ToLower())
{
case "avc":
case "h264":
- if (_mediaEncoder.SupportsDecoder("h264_qsv"))
+ if (_mediaEncoder.SupportsDecoder("h264_qsv") && encodingOptions.HardwareDecodingCodecs.Contains("h264", StringComparer.OrdinalIgnoreCase))
{
// qsv decoder does not support 10-bit input
- if ((state.VideoStream.BitDepth ?? 8) > 8)
+ if ((videoStream.BitDepth ?? 8) > 8)
{
return null;
}
return "-c:v h264_qsv ";
}
break;
- //case "hevc":
- //case "h265":
- // if (_mediaEncoder.SupportsDecoder("hevc_qsv"))
- // {
- // return "-c:v hevc_qsv ";
- // }
- // break;
+ case "hevc":
+ case "h265":
+ if (_mediaEncoder.SupportsDecoder("hevc_qsv") && encodingOptions.HardwareDecodingCodecs.Contains("hevc", StringComparer.OrdinalIgnoreCase))
+ {
+ return "-c:v hevc_qsv ";
+ }
+ break;
case "mpeg2video":
- if (_mediaEncoder.SupportsDecoder("mpeg2_qsv"))
+ if (_mediaEncoder.SupportsDecoder("mpeg2_qsv") && encodingOptions.HardwareDecodingCodecs.Contains("mpeg2video", StringComparer.OrdinalIgnoreCase))
{
return "-c:v mpeg2_qsv ";
}
break;
case "vc1":
- if (_mediaEncoder.SupportsDecoder("vc1_qsv"))
+ if (_mediaEncoder.SupportsDecoder("vc1_qsv") && encodingOptions.HardwareDecodingCodecs.Contains("vc1", StringComparer.OrdinalIgnoreCase))
{
return "-c:v vc1_qsv ";
}
@@ -1829,22 +1849,40 @@ namespace MediaBrowser.Controller.MediaEncoding
else if (string.Equals(encodingOptions.HardwareAccelerationType, "nvenc", StringComparison.OrdinalIgnoreCase))
{
- switch (state.MediaSource.VideoStream.Codec.ToLower())
+ switch (videoStream.Codec.ToLower())
{
case "avc":
case "h264":
- if (_mediaEncoder.SupportsDecoder("h264_cuvid"))
+ if (_mediaEncoder.SupportsDecoder("h264_cuvid") && encodingOptions.HardwareDecodingCodecs.Contains("h264", StringComparer.OrdinalIgnoreCase))
{
return "-c:v h264_cuvid ";
}
break;
case "hevc":
case "h265":
- if (_mediaEncoder.SupportsDecoder("hevc_cuvid"))
+ if (_mediaEncoder.SupportsDecoder("hevc_cuvid") && encodingOptions.HardwareDecodingCodecs.Contains("hevc", StringComparer.OrdinalIgnoreCase))
{
return "-c:v hevc_cuvid ";
}
break;
+ case "mpeg2video":
+ if (_mediaEncoder.SupportsDecoder("mpeg2_cuvid") && encodingOptions.HardwareDecodingCodecs.Contains("mpeg2video", StringComparer.OrdinalIgnoreCase))
+ {
+ return "-c:v mpeg2_cuvid ";
+ }
+ break;
+ case "vc1":
+ if (_mediaEncoder.SupportsDecoder("vc1_cuvid") && encodingOptions.HardwareDecodingCodecs.Contains("vc1", StringComparer.OrdinalIgnoreCase))
+ {
+ return "-c:v vc1_cuvid ";
+ }
+ break;
+ case "mpeg4":
+ if (_mediaEncoder.SupportsDecoder("mpeg4_cuvid") && encodingOptions.HardwareDecodingCodecs.Contains("mpeg4", StringComparer.OrdinalIgnoreCase))
+ {
+ return "-c:v mpeg4_cuvid ";
+ }
+ break;
}
}
}
@@ -2109,6 +2147,7 @@ namespace MediaBrowser.Controller.MediaEncoding
var vn = string.Empty;
var hasArt = !string.IsNullOrWhiteSpace(state.AlbumCoverPath);
+ hasArt = false;
if (hasArt)
{
diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs b/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs
index b552579a8..e76217fda 100644
--- a/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs
+++ b/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs
@@ -27,7 +27,7 @@ namespace MediaBrowser.Controller.MediaEncoding
public string MediaPath { get; set; }
public bool IsInputVideo { get; set; }
public IIsoMount IsoMount { get; set; }
- public List<string> PlayableStreamFileNames { get; set; }
+ public string[] PlayableStreamFileNames { get; set; }
public string OutputAudioCodec { get; set; }
public int? OutputVideoBitrate { get; set; }
public MediaStream SubtitleStream { get; set; }
@@ -42,8 +42,8 @@ namespace MediaBrowser.Controller.MediaEncoding
public bool ReadInputAtNativeFramerate { get; set; }
- private List<TranscodeReason> _transcodeReasons = null;
- public List<TranscodeReason> TranscodeReasons
+ private TranscodeReason[] _transcodeReasons = null;
+ public TranscodeReason[] TranscodeReasons
{
get
{
@@ -53,7 +53,7 @@ namespace MediaBrowser.Controller.MediaEncoding
.Split(',')
.Where(i => !string.IsNullOrWhiteSpace(i))
.Select(v => (TranscodeReason)Enum.Parse(typeof(TranscodeReason), v, true))
- .ToList();
+ .ToArray();
}
return _transcodeReasons;
@@ -127,6 +127,11 @@ namespace MediaBrowser.Controller.MediaEncoding
}
}
+ public bool EnableMpDecimate
+ {
+ get { return MediaSource.EnableMpDecimate; }
+ }
+
public string AlbumCoverPath { get; set; }
public string InputAudioSync { get; set; }
@@ -164,7 +169,7 @@ namespace MediaBrowser.Controller.MediaEncoding
_logger = logger;
TranscodingType = jobType;
RemoteHttpHeaders = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
- PlayableStreamFileNames = new List<string>();
+ PlayableStreamFileNames = new string[]{};
SupportedAudioCodecs = new List<string>();
SupportedVideoCodecs = new List<string>();
SupportedSubtitleCodecs = new List<string>();
diff --git a/MediaBrowser.Controller/MediaEncoding/IEncodingManager.cs b/MediaBrowser.Controller/MediaEncoding/IEncodingManager.cs
index 8683a6af4..81269fe3f 100644
--- a/MediaBrowser.Controller/MediaEncoding/IEncodingManager.cs
+++ b/MediaBrowser.Controller/MediaEncoding/IEncodingManager.cs
@@ -1,5 +1,8 @@
-using System.Threading;
+using System.Collections.Generic;
+using System.Threading;
using System.Threading.Tasks;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Model.Entities;
namespace MediaBrowser.Controller.MediaEncoding
{
@@ -8,9 +11,6 @@ namespace MediaBrowser.Controller.MediaEncoding
/// <summary>
/// Refreshes the chapter images.
/// </summary>
- /// <param name="options">The options.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task{System.Boolean}.</returns>
- Task<bool> RefreshChapterImages(ChapterImageRefreshOptions options, CancellationToken cancellationToken);
+ Task<bool> RefreshChapterImages(Video video, List<ChapterInfo> chapters, bool extractImages, bool saveChapters, CancellationToken cancellationToken);
}
}
diff --git a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs
index 10d7b9a7e..31cd96c9a 100644
--- a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs
+++ b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs
@@ -1,9 +1,11 @@
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.MediaInfo;
using System;
+using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Model.Dlna;
+using MediaBrowser.Model.IO;
namespace MediaBrowser.Controller.MediaEncoding
{
@@ -39,29 +41,16 @@ namespace MediaBrowser.Controller.MediaEncoding
/// <summary>
/// Extracts the video image.
/// </summary>
- /// <param name="inputFiles">The input files.</param>
- /// <param name="protocol">The protocol.</param>
- /// <param name="threedFormat">The threed format.</param>
- /// <param name="offset">The offset.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task{Stream}.</returns>
- Task<string> ExtractVideoImage(string[] inputFiles, string container, MediaProtocol protocol, Video3DFormat? threedFormat, TimeSpan? offset, CancellationToken cancellationToken);
+ Task<string> ExtractVideoImage(string[] inputFiles, string container, MediaProtocol protocol, MediaStream videoStream, Video3DFormat? threedFormat, TimeSpan? offset, CancellationToken cancellationToken);
- Task<string> ExtractVideoImage(string[] inputFiles, string container, MediaProtocol protocol, int? imageStreamIndex, CancellationToken cancellationToken);
+ Task<string> ExtractVideoImage(string[] inputFiles, string container, MediaProtocol protocol, MediaStream imageStream, int? imageStreamIndex, CancellationToken cancellationToken);
/// <summary>
/// Extracts the video images on interval.
/// </summary>
- /// <param name="inputFiles">The input files.</param>
- /// <param name="protocol">The protocol.</param>
- /// <param name="threedFormat">The threed format.</param>
- /// <param name="interval">The interval.</param>
- /// <param name="targetDirectory">The target directory.</param>
- /// <param name="filenamePrefix">The filename prefix.</param>
- /// <param name="maxWidth">The maximum width.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
Task ExtractVideoImagesOnInterval(string[] inputFiles,
+ string container,
+ MediaStream videoStream,
MediaProtocol protocol,
Video3DFormat? threedFormat,
TimeSpan interval,
@@ -115,6 +104,8 @@ namespace MediaBrowser.Controller.MediaEncoding
IProgress<double> progress,
CancellationToken cancellationToken);
+ Task ConvertImage(string inputPath, string outputPath);
+
/// <summary>
/// Escapes the subtitle filter path.
/// </summary>
@@ -129,5 +120,8 @@ namespace MediaBrowser.Controller.MediaEncoding
void SetLogFilename(string name);
void ClearLogFilename();
+
+ string[] GetPlayableStreamFileNames(string path, VideoType videoType);
+ IEnumerable<string> GetPrimaryPlaylistVobFiles(string path, IIsoMount isoMount, uint? titleNumber);
}
}
diff --git a/MediaBrowser.Controller/MediaEncoding/JobLogger.cs b/MediaBrowser.Controller/MediaEncoding/JobLogger.cs
deleted file mode 100644
index 03e4f7771..000000000
--- a/MediaBrowser.Controller/MediaEncoding/JobLogger.cs
+++ /dev/null
@@ -1,149 +0,0 @@
-using MediaBrowser.Model.Extensions;
-using MediaBrowser.Model.Logging;
-using System;
-using System.Globalization;
-using System.IO;
-using System.Linq;
-using System.Text;
-
-namespace MediaBrowser.Controller.MediaEncoding
-{
- public class JobLogger
- {
- private readonly CultureInfo _usCulture = new CultureInfo("en-US");
- private readonly ILogger _logger;
-
- public JobLogger(ILogger logger)
- {
- _logger = logger;
- }
-
- public async void StartStreamingLog(EncodingJobInfo state, Stream source, Stream target)
- {
- try
- {
- using (var reader = new StreamReader(source))
- {
- while (!reader.EndOfStream)
- {
- var line = await reader.ReadLineAsync().ConfigureAwait(false);
-
- ParseLogLine(line, state);
-
- var bytes = Encoding.UTF8.GetBytes(Environment.NewLine + line);
-
- await target.WriteAsync(bytes, 0, bytes.Length).ConfigureAwait(false);
- await target.FlushAsync().ConfigureAwait(false);
- }
- }
- }
- catch (ObjectDisposedException)
- {
- // Don't spam the log. This doesn't seem to throw in windows, but sometimes under linux
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error reading ffmpeg log", ex);
- }
- }
-
- private void ParseLogLine(string line, EncodingJobInfo state)
- {
- float? framerate = null;
- double? percent = null;
- TimeSpan? transcodingPosition = null;
- long? bytesTranscoded = null;
- int? bitRate = null;
-
- var parts = line.Split(' ');
-
- var totalMs = state.RunTimeTicks.HasValue
- ? TimeSpan.FromTicks(state.RunTimeTicks.Value).TotalMilliseconds
- : 0;
-
- var startMs = state.BaseRequest.StartTimeTicks.HasValue
- ? TimeSpan.FromTicks(state.BaseRequest.StartTimeTicks.Value).TotalMilliseconds
- : 0;
-
- for (var i = 0; i < parts.Length; i++)
- {
- var part = parts[i];
-
- if (string.Equals(part, "fps=", StringComparison.OrdinalIgnoreCase) &&
- (i + 1 < parts.Length))
- {
- var rate = parts[i + 1];
- float val;
-
- if (float.TryParse(rate, NumberStyles.Any, _usCulture, out val))
- {
- framerate = val;
- }
- }
- else if (state.RunTimeTicks.HasValue &&
- part.StartsWith("time=", StringComparison.OrdinalIgnoreCase))
- {
- var time = part.Split(new[] { '=' }, 2).Last();
- TimeSpan val;
-
- if (TimeSpan.TryParse(time, _usCulture, out val))
- {
- var currentMs = startMs + val.TotalMilliseconds;
-
- var percentVal = currentMs / totalMs;
- percent = 100 * percentVal;
-
- transcodingPosition = val;
- }
- }
- else if (part.StartsWith("size=", StringComparison.OrdinalIgnoreCase))
- {
- var size = part.Split(new[] { '=' }, 2).Last();
-
- int? scale = null;
- if (size.IndexOf("kb", StringComparison.OrdinalIgnoreCase) != -1)
- {
- scale = 1024;
- size = size.Replace("kb", string.Empty, StringComparison.OrdinalIgnoreCase);
- }
-
- if (scale.HasValue)
- {
- long val;
-
- if (long.TryParse(size, NumberStyles.Any, _usCulture, out val))
- {
- bytesTranscoded = val * scale.Value;
- }
- }
- }
- else if (part.StartsWith("bitrate=", StringComparison.OrdinalIgnoreCase))
- {
- var rate = part.Split(new[] { '=' }, 2).Last();
-
- int? scale = null;
- if (rate.IndexOf("kbits/s", StringComparison.OrdinalIgnoreCase) != -1)
- {
- scale = 1024;
- rate = rate.Replace("kbits/s", string.Empty, StringComparison.OrdinalIgnoreCase);
- }
-
- if (scale.HasValue)
- {
- float val;
-
- if (float.TryParse(rate, NumberStyles.Any, _usCulture, out val))
- {
- bitRate = (int)Math.Ceiling(val * scale.Value);
- }
- }
- }
- }
-
- if (framerate.HasValue || percent.HasValue)
- {
- state.ReportTranscodingProgress(transcodingPosition, framerate, percent, bytesTranscoded, bitRate);
- }
- }
- }
-}
diff --git a/MediaBrowser.Controller/MediaEncoding/MediaEncoderHelpers.cs b/MediaBrowser.Controller/MediaEncoding/MediaEncoderHelpers.cs
index d5c85197f..70e4db84f 100644
--- a/MediaBrowser.Controller/MediaEncoding/MediaEncoderHelpers.cs
+++ b/MediaBrowser.Controller/MediaEncoding/MediaEncoderHelpers.cs
@@ -1,12 +1,9 @@
using MediaBrowser.Model.IO;
using MediaBrowser.Model.MediaInfo;
using System;
-using System.Collections.Generic;
using System.IO;
using System.Linq;
-using MediaBrowser.Controller.IO;
-
namespace MediaBrowser.Controller.MediaEncoding
{
/// <summary>
@@ -23,34 +20,34 @@ namespace MediaBrowser.Controller.MediaEncoding
/// <param name="isoMount">The iso mount.</param>
/// <param name="playableStreamFileNames">The playable stream file names.</param>
/// <returns>System.String[][].</returns>
- public static string[] GetInputArgument(IFileSystem fileSystem, string videoPath, MediaProtocol protocol, IIsoMount isoMount, List<string> playableStreamFileNames)
+ public static string[] GetInputArgument(IFileSystem fileSystem, string videoPath, MediaProtocol protocol, IIsoMount isoMount, string[] playableStreamFileNames)
{
- if (playableStreamFileNames.Count > 0)
+ if (playableStreamFileNames.Length > 0)
{
if (isoMount == null)
{
- return GetPlayableStreamFiles(fileSystem, videoPath, playableStreamFileNames).ToArray();
+ return GetPlayableStreamFiles(fileSystem, videoPath, playableStreamFileNames);
}
- return GetPlayableStreamFiles(fileSystem, isoMount.MountedPath, playableStreamFileNames).ToArray();
+ return GetPlayableStreamFiles(fileSystem, isoMount.MountedPath, playableStreamFileNames);
}
return new[] {videoPath};
}
- private static List<string> GetPlayableStreamFiles(IFileSystem fileSystem, string rootPath, List<string> filenames)
+ private static string[] GetPlayableStreamFiles(IFileSystem fileSystem, string rootPath, string[] filenames)
{
- if (filenames.Count == 0)
+ if (filenames.Length == 0)
{
- return new List<string>();
+ return new string[]{};
}
var allFiles = fileSystem
.GetFilePaths(rootPath, true)
- .ToList();
+ .ToArray();
return filenames.Select(name => allFiles.FirstOrDefault(f => string.Equals(Path.GetFileName(f), name, StringComparison.OrdinalIgnoreCase)))
.Where(f => !string.IsNullOrEmpty(f))
- .ToList();
+ .ToArray();
}
}
}
diff --git a/MediaBrowser.Controller/MediaEncoding/MediaInfoRequest.cs b/MediaBrowser.Controller/MediaEncoding/MediaInfoRequest.cs
index 0785ee29f..929f4e649 100644
--- a/MediaBrowser.Controller/MediaEncoding/MediaInfoRequest.cs
+++ b/MediaBrowser.Controller/MediaEncoding/MediaInfoRequest.cs
@@ -14,12 +14,12 @@ namespace MediaBrowser.Controller.MediaEncoding
public DlnaProfileType MediaType { get; set; }
public IIsoMount MountedIso { get; set; }
public VideoType VideoType { get; set; }
- public List<string> PlayableStreamFileNames { get; set; }
+ public string[] PlayableStreamFileNames { get; set; }
public int AnalyzeDurationMs { get; set; }
public MediaInfoRequest()
{
- PlayableStreamFileNames = new List<string>();
+ PlayableStreamFileNames = new string[] { };
}
}
}
diff --git a/MediaBrowser.Controller/Net/AuthenticatedAttribute.cs b/MediaBrowser.Controller/Net/AuthenticatedAttribute.cs
index b025011d7..ecbfaecea 100644
--- a/MediaBrowser.Controller/Net/AuthenticatedAttribute.cs
+++ b/MediaBrowser.Controller/Net/AuthenticatedAttribute.cs
@@ -1,6 +1,4 @@
using System;
-using System.Collections.Generic;
-using System.Linq;
using MediaBrowser.Model.Services;
namespace MediaBrowser.Controller.Net
@@ -27,6 +25,8 @@ namespace MediaBrowser.Controller.Net
/// <value><c>true</c> if [allow before startup wizard]; otherwise, <c>false</c>.</value>
public bool AllowBeforeStartupWizard { get; set; }
+ public bool AllowLocal { get; set; }
+
/// <summary>
/// The request filter is executed before the service.
/// </summary>
@@ -35,9 +35,7 @@ namespace MediaBrowser.Controller.Net
/// <param name="requestDto">The request DTO</param>
public void RequestFilter(IRequest request, IResponse response, object requestDto)
{
- var serviceRequest = new ServiceRequest(request);
-
- AuthService.Authenticate(serviceRequest, this);
+ AuthService.Authenticate(request, this);
}
/// <summary>
@@ -51,10 +49,9 @@ namespace MediaBrowser.Controller.Net
get { return 0; }
}
- public IEnumerable<string> GetRoles()
+ public string[] GetRoles()
{
- return (Roles ?? string.Empty).Split(',')
- .Where(i => !string.IsNullOrWhiteSpace(i));
+ return (Roles ?? string.Empty).Split(new []{ ',' }, StringSplitOptions.RemoveEmptyEntries);
}
}
@@ -62,7 +59,8 @@ namespace MediaBrowser.Controller.Net
{
bool EscapeParentalControl { get; }
bool AllowBeforeStartupWizard { get; }
+ bool AllowLocal { get; }
- IEnumerable<string> GetRoles();
+ string[] GetRoles();
}
}
diff --git a/MediaBrowser.Controller/Net/IAuthService.cs b/MediaBrowser.Controller/Net/IAuthService.cs
index dc298c8d9..361320250 100644
--- a/MediaBrowser.Controller/Net/IAuthService.cs
+++ b/MediaBrowser.Controller/Net/IAuthService.cs
@@ -1,9 +1,9 @@
-
+using MediaBrowser.Model.Services;
+
namespace MediaBrowser.Controller.Net
{
public interface IAuthService
{
- void Authenticate(IServiceRequest request,
- IAuthenticationAttributes authAttribtues);
+ void Authenticate(IRequest request, IAuthenticationAttributes authAttribtues);
}
}
diff --git a/MediaBrowser.Controller/Net/IAuthorizationContext.cs b/MediaBrowser.Controller/Net/IAuthorizationContext.cs
index bdaed6046..5a9d0aa30 100644
--- a/MediaBrowser.Controller/Net/IAuthorizationContext.cs
+++ b/MediaBrowser.Controller/Net/IAuthorizationContext.cs
@@ -1,4 +1,5 @@
-
+using MediaBrowser.Model.Services;
+
namespace MediaBrowser.Controller.Net
{
public interface IAuthorizationContext
@@ -15,6 +16,6 @@ namespace MediaBrowser.Controller.Net
/// </summary>
/// <param name="requestContext">The request context.</param>
/// <returns>AuthorizationInfo.</returns>
- AuthorizationInfo GetAuthorizationInfo(IServiceRequest requestContext);
+ AuthorizationInfo GetAuthorizationInfo(IRequest requestContext);
}
}
diff --git a/MediaBrowser.Controller/Net/IHttpServer.cs b/MediaBrowser.Controller/Net/IHttpServer.cs
index f319244da..f41572b45 100644
--- a/MediaBrowser.Controller/Net/IHttpServer.cs
+++ b/MediaBrowser.Controller/Net/IHttpServer.cs
@@ -13,13 +13,13 @@ namespace MediaBrowser.Controller.Net
/// Gets the URL prefix.
/// </summary>
/// <value>The URL prefix.</value>
- IEnumerable<string> UrlPrefixes { get; }
+ string[] UrlPrefixes { get; }
/// <summary>
/// Starts the specified server name.
/// </summary>
/// <param name="urlPrefixes">The URL prefixes.</param>
- void StartServer(IEnumerable<string> urlPrefixes);
+ void StartServer(string[] urlPrefixes);
/// <summary>
/// Stops this instance.
diff --git a/MediaBrowser.Controller/Net/IServerManager.cs b/MediaBrowser.Controller/Net/IServerManager.cs
index 202df2982..a84c48c5b 100644
--- a/MediaBrowser.Controller/Net/IServerManager.cs
+++ b/MediaBrowser.Controller/Net/IServerManager.cs
@@ -15,7 +15,7 @@ namespace MediaBrowser.Controller.Net
/// Starts this instance.
/// </summary>
/// <param name="urlPrefixes">The URL prefixes.</param>
- void Start(IEnumerable<string> urlPrefixes);
+ void Start(string[] urlPrefixes);
/// <summary>
/// Sends a message to all clients currently connected via a web socket
diff --git a/MediaBrowser.Controller/Net/IServiceRequest.cs b/MediaBrowser.Controller/Net/IServiceRequest.cs
deleted file mode 100644
index ebc7e8d65..000000000
--- a/MediaBrowser.Controller/Net/IServiceRequest.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-using System.Collections.Generic;
-using MediaBrowser.Model.Services;
-
-namespace MediaBrowser.Controller.Net
-{
- public interface IServiceRequest
- {
- string RemoteIp { get; }
- QueryParamCollection Headers { get; }
- QueryParamCollection QueryString { get; }
- IDictionary<string,object> Items { get; }
- void AddResponseHeader(string name, string value);
- }
-}
diff --git a/MediaBrowser.Controller/Net/ISessionContext.cs b/MediaBrowser.Controller/Net/ISessionContext.cs
index 167e17867..213a66dac 100644
--- a/MediaBrowser.Controller/Net/ISessionContext.cs
+++ b/MediaBrowser.Controller/Net/ISessionContext.cs
@@ -1,6 +1,7 @@
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Session;
using System.Threading.Tasks;
+using MediaBrowser.Model.Services;
namespace MediaBrowser.Controller.Net
{
@@ -9,7 +10,7 @@ namespace MediaBrowser.Controller.Net
Task<SessionInfo> GetSession(object requestContext);
Task<User> GetUser(object requestContext);
- Task<SessionInfo> GetSession(IServiceRequest requestContext);
- Task<User> GetUser(IServiceRequest requestContext);
+ Task<SessionInfo> GetSession(IRequest requestContext);
+ Task<User> GetUser(IRequest requestContext);
}
}
diff --git a/MediaBrowser.Controller/Net/LoggedAttribute.cs b/MediaBrowser.Controller/Net/LoggedAttribute.cs
index 6a2a5e2e3..eb57392e2 100644
--- a/MediaBrowser.Controller/Net/LoggedAttribute.cs
+++ b/MediaBrowser.Controller/Net/LoggedAttribute.cs
@@ -30,10 +30,8 @@ namespace MediaBrowser.Controller.Net
/// <param name="requestDto">The request DTO</param>
public void Filter(IRequest request, IResponse response, object requestDto)
{
- var serviceRequest = new ServiceRequest(request);
-
//This code is executed before the service
- var auth = AuthorizationContext.GetAuthorizationInfo(serviceRequest);
+ var auth = AuthorizationContext.GetAuthorizationInfo(request);
if (auth != null)
{
diff --git a/MediaBrowser.Controller/Net/ServiceRequest.cs b/MediaBrowser.Controller/Net/ServiceRequest.cs
deleted file mode 100644
index 1f72d0eb2..000000000
--- a/MediaBrowser.Controller/Net/ServiceRequest.cs
+++ /dev/null
@@ -1,42 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Collections.Specialized;
-using MediaBrowser.Model.Services;
-
-namespace MediaBrowser.Controller.Net
-{
- public class ServiceRequest : IServiceRequest
- {
- private readonly IRequest _request;
-
- public ServiceRequest(IRequest request)
- {
- _request = request;
- }
-
- public string RemoteIp
- {
- get { return _request.RemoteIp; }
- }
-
- public QueryParamCollection Headers
- {
- get { return _request.Headers; }
- }
-
- public QueryParamCollection QueryString
- {
- get { return _request.QueryString; }
- }
-
- public IDictionary<string, object> Items
- {
- get { return _request.Items; }
- }
-
- public void AddResponseHeader(string name, string value)
- {
- _request.Response.AddHeader(name, value);
- }
- }
-}
diff --git a/MediaBrowser.Controller/Notifications/INotificationManager.cs b/MediaBrowser.Controller/Notifications/INotificationManager.cs
index cb1e3da90..f9d264314 100644
--- a/MediaBrowser.Controller/Notifications/INotificationManager.cs
+++ b/MediaBrowser.Controller/Notifications/INotificationManager.cs
@@ -26,7 +26,7 @@ namespace MediaBrowser.Controller.Notifications
/// Gets the notification types.
/// </summary>
/// <returns>IEnumerable{NotificationTypeInfo}.</returns>
- IEnumerable<NotificationTypeInfo> GetNotificationTypes();
+ List<NotificationTypeInfo> GetNotificationTypes();
/// <summary>
/// Gets the notification services.
diff --git a/MediaBrowser.Controller/Persistence/IDisplayPreferencesRepository.cs b/MediaBrowser.Controller/Persistence/IDisplayPreferencesRepository.cs
index abf96994f..25aba6bd9 100644
--- a/MediaBrowser.Controller/Persistence/IDisplayPreferencesRepository.cs
+++ b/MediaBrowser.Controller/Persistence/IDisplayPreferencesRepository.cs
@@ -2,7 +2,6 @@
using MediaBrowser.Model.Entities;
using System;
using System.Threading;
-using System.Threading.Tasks;
namespace MediaBrowser.Controller.Persistence
{
@@ -19,9 +18,9 @@ namespace MediaBrowser.Controller.Persistence
/// <param name="client">The client.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
- Task SaveDisplayPreferences(DisplayPreferences displayPreferences, string userId, string client,
+ void SaveDisplayPreferences(DisplayPreferences displayPreferences, string userId, string client,
CancellationToken cancellationToken);
-
+
/// <summary>
/// Saves all display preferences for a user
/// </summary>
@@ -29,7 +28,7 @@ namespace MediaBrowser.Controller.Persistence
/// <param name="userId">The user id.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
- Task SaveAllDisplayPreferences(IEnumerable<DisplayPreferences> displayPreferences, Guid userId,
+ void SaveAllDisplayPreferences(IEnumerable<DisplayPreferences> displayPreferences, Guid userId,
CancellationToken cancellationToken);
/// <summary>
/// Gets the display preferences.
diff --git a/MediaBrowser.Controller/Persistence/IItemRepository.cs b/MediaBrowser.Controller/Persistence/IItemRepository.cs
index 58ae1f3b0..3d05d2fca 100644
--- a/MediaBrowser.Controller/Persistence/IItemRepository.cs
+++ b/MediaBrowser.Controller/Persistence/IItemRepository.cs
@@ -3,7 +3,6 @@ using MediaBrowser.Model.Entities;
using System;
using System.Collections.Generic;
using System.Threading;
-using System.Threading.Tasks;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Querying;
@@ -19,39 +18,35 @@ namespace MediaBrowser.Controller.Persistence
/// </summary>
/// <param name="item">The item.</param>
/// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- Task SaveItem(BaseItem item, CancellationToken cancellationToken);
+ void SaveItem(BaseItem item, CancellationToken cancellationToken);
/// <summary>
/// Deletes the item.
/// </summary>
/// <param name="id">The identifier.</param>
/// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- Task DeleteItem(Guid id, CancellationToken cancellationToken);
+ void DeleteItem(Guid id, CancellationToken cancellationToken);
/// <summary>
/// Gets the critic reviews.
/// </summary>
/// <param name="itemId">The item id.</param>
/// <returns>Task{IEnumerable{ItemReview}}.</returns>
- IEnumerable<ItemReview> GetCriticReviews(Guid itemId);
+ List<ItemReview> GetCriticReviews(Guid itemId);
/// <summary>
/// Saves the critic reviews.
/// </summary>
/// <param name="itemId">The item id.</param>
/// <param name="criticReviews">The critic reviews.</param>
- /// <returns>Task.</returns>
- Task SaveCriticReviews(Guid itemId, IEnumerable<ItemReview> criticReviews);
+ void SaveCriticReviews(Guid itemId, IEnumerable<ItemReview> criticReviews);
/// <summary>
/// Saves the items.
/// </summary>
/// <param name="items">The items.</param>
/// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- Task SaveItems(List<BaseItem> items, CancellationToken cancellationToken);
+ void SaveItems(List<BaseItem> items, CancellationToken cancellationToken);
/// <summary>
/// Retrieves the item.
@@ -65,7 +60,7 @@ namespace MediaBrowser.Controller.Persistence
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
- IEnumerable<ChapterInfo> GetChapters(Guid id);
+ List<ChapterInfo> GetChapters(Guid id);
/// <summary>
/// Gets a single chapter for an item
@@ -78,18 +73,14 @@ namespace MediaBrowser.Controller.Persistence
/// <summary>
/// Saves the chapters.
/// </summary>
- /// <param name="id">The id.</param>
- /// <param name="chapters">The chapters.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- Task SaveChapters(Guid id, List<ChapterInfo> chapters, CancellationToken cancellationToken);
+ void SaveChapters(Guid id, List<ChapterInfo> chapters);
/// <summary>
/// Gets the media streams.
/// </summary>
/// <param name="query">The query.</param>
/// <returns>IEnumerable{MediaStream}.</returns>
- IEnumerable<MediaStream> GetMediaStreams(MediaStreamQuery query);
+ List<MediaStream> GetMediaStreams(MediaStreamQuery query);
/// <summary>
/// Saves the media streams.
@@ -97,8 +88,7 @@ namespace MediaBrowser.Controller.Persistence
/// <param name="id">The identifier.</param>
/// <param name="streams">The streams.</param>
/// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- Task SaveMediaStreams(Guid id, List<MediaStream> streams, CancellationToken cancellationToken);
+ void SaveMediaStreams(Guid id, List<MediaStream> streams, CancellationToken cancellationToken);
/// <summary>
/// Gets the item ids.
@@ -132,8 +122,7 @@ namespace MediaBrowser.Controller.Persistence
/// </summary>
/// <param name="itemId">The item identifier.</param>
/// <param name="people">The people.</param>
- /// <returns>Task.</returns>
- Task UpdatePeople(Guid itemId, List<PersonInfo> people);
+ void UpdatePeople(Guid itemId, List<PersonInfo> people);
/// <summary>
/// Gets the people names.
@@ -160,8 +149,7 @@ namespace MediaBrowser.Controller.Persistence
/// Updates the inherited values.
/// </summary>
/// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- Task UpdateInheritedValues(CancellationToken cancellationToken);
+ void UpdateInheritedValues(CancellationToken cancellationToken);
int GetCount(InternalItemsQuery query);
diff --git a/MediaBrowser.Controller/Persistence/IUserDataRepository.cs b/MediaBrowser.Controller/Persistence/IUserDataRepository.cs
index ca4dc9751..f79a3a9fc 100644
--- a/MediaBrowser.Controller/Persistence/IUserDataRepository.cs
+++ b/MediaBrowser.Controller/Persistence/IUserDataRepository.cs
@@ -2,7 +2,6 @@
using MediaBrowser.Controller.Entities;
using System;
using System.Threading;
-using System.Threading.Tasks;
namespace MediaBrowser.Controller.Persistence
{
@@ -19,7 +18,7 @@ namespace MediaBrowser.Controller.Persistence
/// <param name="userData">The user data.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
- Task SaveUserData(Guid userId, string key, UserItemData userData, CancellationToken cancellationToken);
+ void SaveUserData(Guid userId, string key, UserItemData userData, CancellationToken cancellationToken);
/// <summary>
/// Gets the user data.
@@ -36,7 +35,7 @@ namespace MediaBrowser.Controller.Persistence
/// </summary>
/// <param name="userId"></param>
/// <returns></returns>
- IEnumerable<UserItemData> GetAllUserData(Guid userId);
+ List<UserItemData> GetAllUserData(Guid userId);
/// <summary>
/// Save all user data associated with the given user
@@ -45,7 +44,7 @@ namespace MediaBrowser.Controller.Persistence
/// <param name="userData"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
- Task SaveAllUserData(Guid userId, IEnumerable<UserItemData> userData, CancellationToken cancellationToken);
+ void SaveAllUserData(Guid userId, UserItemData[] userData, CancellationToken cancellationToken);
}
}
diff --git a/MediaBrowser.Controller/Persistence/IUserRepository.cs b/MediaBrowser.Controller/Persistence/IUserRepository.cs
index 80961a369..721ddb7e3 100644
--- a/MediaBrowser.Controller/Persistence/IUserRepository.cs
+++ b/MediaBrowser.Controller/Persistence/IUserRepository.cs
@@ -1,7 +1,6 @@
using MediaBrowser.Controller.Entities;
using System.Collections.Generic;
using System.Threading;
-using System.Threading.Tasks;
namespace MediaBrowser.Controller.Persistence
{
@@ -16,7 +15,7 @@ namespace MediaBrowser.Controller.Persistence
/// <param name="user">The user.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
- Task DeleteUser(User user, CancellationToken cancellationToken);
+ void DeleteUser(User user, CancellationToken cancellationToken);
/// <summary>
/// Saves the user.
@@ -24,7 +23,7 @@ namespace MediaBrowser.Controller.Persistence
/// <param name="user">The user.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
- Task SaveUser(User user, CancellationToken cancellationToken);
+ void SaveUser(User user, CancellationToken cancellationToken);
/// <summary>
/// Retrieves all users.
diff --git a/MediaBrowser.Controller/Playlists/Playlist.cs b/MediaBrowser.Controller/Playlists/Playlist.cs
index c992ac56a..ee96a8c3b 100644
--- a/MediaBrowser.Controller/Playlists/Playlist.cs
+++ b/MediaBrowser.Controller/Playlists/Playlist.cs
@@ -89,7 +89,7 @@ namespace MediaBrowser.Controller.Playlists
return new List<BaseItem>();
}
- public override IEnumerable<BaseItem> GetChildren(User user, bool includeLinkedChildren)
+ public override List<BaseItem> GetChildren(User user, bool includeLinkedChildren)
{
return GetPlayableItems(user, new DtoOptions(true));
}
@@ -105,7 +105,7 @@ namespace MediaBrowser.Controller.Playlists
if (query != null)
{
- items = items.Where(i => UserViewBuilder.FilterItem(i, query));
+ items = items.Where(i => UserViewBuilder.FilterItem(i, query)).ToList();
}
return items;
@@ -116,12 +116,12 @@ namespace MediaBrowser.Controller.Playlists
return GetLinkedChildrenInfos();
}
- private IEnumerable<BaseItem> GetPlayableItems(User user, DtoOptions options)
+ private List<BaseItem> GetPlayableItems(User user, DtoOptions options)
{
return GetPlaylistItems(MediaType, base.GetChildren(user, true), user, options);
}
- public static IEnumerable<BaseItem> GetPlaylistItems(string playlistMediaType, IEnumerable<BaseItem> inputItems, User user, DtoOptions options)
+ public static List<BaseItem> GetPlaylistItems(string playlistMediaType, IEnumerable<BaseItem> inputItems, User user, DtoOptions options)
{
if (user != null)
{
@@ -149,8 +149,7 @@ namespace MediaBrowser.Controller.Playlists
Recursive = true,
IncludeItemTypes = new[] { typeof(Audio).Name },
GenreIds = new[] { musicGenre.Id.ToString("N") },
- SortBy = new[] { ItemSortBy.AlbumArtist, ItemSortBy.Album, ItemSortBy.SortName },
- SortOrder = SortOrder.Ascending,
+ OrderBy = new[] { ItemSortBy.AlbumArtist, ItemSortBy.Album, ItemSortBy.SortName }.Select(i => new Tuple<string, SortOrder>(i, SortOrder.Ascending)).ToArray(),
DtoOptions = options
});
}
@@ -163,8 +162,7 @@ namespace MediaBrowser.Controller.Playlists
Recursive = true,
IncludeItemTypes = new[] { typeof(Audio).Name },
ArtistIds = new[] { musicArtist.Id.ToString("N") },
- SortBy = new[] { ItemSortBy.AlbumArtist, ItemSortBy.Album, ItemSortBy.SortName },
- SortOrder = SortOrder.Ascending,
+ OrderBy = new[] { ItemSortBy.AlbumArtist, ItemSortBy.Album, ItemSortBy.SortName }.Select(i => new Tuple<string, SortOrder>(i, SortOrder.Ascending)).ToArray(),
DtoOptions = options
});
}
@@ -176,16 +174,13 @@ namespace MediaBrowser.Controller.Playlists
{
Recursive = true,
IsFolder = false,
- SortBy = new[] { ItemSortBy.SortName },
+ OrderBy = new[] { ItemSortBy.SortName }.Select(i => new Tuple<string, SortOrder>(i, SortOrder.Ascending)).ToArray(),
MediaTypes = new[] { mediaType },
EnableTotalRecordCount = false,
DtoOptions = options
};
- var itemsResult = folder.GetItems(query);
- var items = itemsResult.Items;
-
- return items;
+ return folder.GetItemList(query);
}
return new[] { item };
diff --git a/MediaBrowser.Controller/Providers/AlbumInfo.cs b/MediaBrowser.Controller/Providers/AlbumInfo.cs
index b88477409..74feb4ea2 100644
--- a/MediaBrowser.Controller/Providers/AlbumInfo.cs
+++ b/MediaBrowser.Controller/Providers/AlbumInfo.cs
@@ -9,7 +9,7 @@ namespace MediaBrowser.Controller.Providers
/// Gets or sets the album artist.
/// </summary>
/// <value>The album artist.</value>
- public List<string> AlbumArtists { get; set; }
+ public string[] AlbumArtists { get; set; }
/// <summary>
/// Gets or sets the artist provider ids.
@@ -22,7 +22,7 @@ namespace MediaBrowser.Controller.Providers
{
ArtistProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
SongInfos = new List<SongInfo>();
- AlbumArtists = new List<string>();
+ AlbumArtists = EmptyStringArray;
}
}
} \ No newline at end of file
diff --git a/MediaBrowser.Controller/Providers/DirectoryService.cs b/MediaBrowser.Controller/Providers/DirectoryService.cs
index 6d220f3a3..d957470d3 100644
--- a/MediaBrowser.Controller/Providers/DirectoryService.cs
+++ b/MediaBrowser.Controller/Providers/DirectoryService.cs
@@ -4,7 +4,6 @@ using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
-
using MediaBrowser.Controller.IO;
using MediaBrowser.Model.IO;
@@ -13,10 +12,10 @@ namespace MediaBrowser.Controller.Providers
public class DirectoryService : IDirectoryService
{
private readonly ILogger _logger;
- private readonly IFileSystem _fileSystem;
+ private readonly IFileSystem _fileSystem;
- private readonly ConcurrentDictionary<string, Dictionary<string, FileSystemMetadata>> _cache =
- new ConcurrentDictionary<string, Dictionary<string, FileSystemMetadata>>(StringComparer.OrdinalIgnoreCase);
+ private readonly ConcurrentDictionary<string, FileSystemMetadata[]> _cache =
+ new ConcurrentDictionary<string, FileSystemMetadata[]>(StringComparer.OrdinalIgnoreCase);
private readonly ConcurrentDictionary<string, FileSystemMetadata> _fileCache =
new ConcurrentDictionary<string, FileSystemMetadata>(StringComparer.OrdinalIgnoreCase);
@@ -24,7 +23,7 @@ namespace MediaBrowser.Controller.Providers
public DirectoryService(ILogger logger, IFileSystem fileSystem)
{
_logger = logger;
- _fileSystem = fileSystem;
+ _fileSystem = fileSystem;
}
public DirectoryService(IFileSystem fileSystem)
@@ -32,28 +31,23 @@ namespace MediaBrowser.Controller.Providers
{
}
- public IEnumerable<FileSystemMetadata> GetFileSystemEntries(string path)
+ public FileSystemMetadata[] GetFileSystemEntries(string path)
{
return GetFileSystemEntries(path, false);
}
- public Dictionary<string, FileSystemMetadata> GetFileSystemDictionary(string path)
- {
- return GetFileSystemDictionary(path, false);
- }
-
- private Dictionary<string, FileSystemMetadata> GetFileSystemDictionary(string path, bool clearCache)
+ private FileSystemMetadata[] GetFileSystemEntries(string path, bool clearCache)
{
if (string.IsNullOrWhiteSpace(path))
{
throw new ArgumentNullException("path");
}
- Dictionary<string, FileSystemMetadata> entries;
+ FileSystemMetadata[] entries;
if (clearCache)
{
- Dictionary<string, FileSystemMetadata> removed;
+ FileSystemMetadata[] removed;
_cache.TryRemove(path, out removed);
}
@@ -62,55 +56,39 @@ namespace MediaBrowser.Controller.Providers
{
//_logger.Debug("Getting files for " + path);
- entries = new Dictionary<string, FileSystemMetadata>(StringComparer.OrdinalIgnoreCase);
-
try
{
// using EnumerateFileSystemInfos doesn't handle reparse points (symlinks)
- var list = _fileSystem.GetFileSystemEntries(path)
- .ToList();
-
- // Seeing dupes on some users file system for some reason
- foreach (var item in list)
- {
- entries[item.FullName] = item;
- }
+ entries = _fileSystem.GetFileSystemEntries(path).ToArray();
}
catch (IOException)
{
+ entries = new FileSystemMetadata[] { };
}
- //var group = entries.ToLookup(i => _fileSystem.GetDirectoryName(i.FullName)).ToList();
-
_cache.TryAdd(path, entries);
}
return entries;
}
- private IEnumerable<FileSystemMetadata> GetFileSystemEntries(string path, bool clearCache)
- {
- return GetFileSystemDictionary(path, clearCache).Values;
- }
-
- public IEnumerable<FileSystemMetadata> GetFiles(string path)
+ public List<FileSystemMetadata> GetFiles(string path)
{
return GetFiles(path, false);
}
- public IEnumerable<FileSystemMetadata> GetFiles(string path, bool clearCache)
- {
- return GetFileSystemEntries(path, clearCache).Where(i => !i.IsDirectory);
- }
-
- public IEnumerable<string> GetFilePaths(string path)
- {
- return _fileSystem.GetFilePaths(path);
- }
-
- public IEnumerable<string> GetFilePaths(string path, bool clearCache)
+ public List<FileSystemMetadata> GetFiles(string path, bool clearCache)
{
- return _fileSystem.GetFilePaths(path);
+ var list = new List<FileSystemMetadata>();
+ var items = GetFileSystemEntries(path, clearCache);
+ foreach (var item in items)
+ {
+ if (!item.IsDirectory)
+ {
+ list.Add(item);
+ }
+ }
+ return list;
}
public FileSystemMetadata GetFile(string path)
@@ -133,10 +111,5 @@ namespace MediaBrowser.Controller.Providers
return file;
//return _fileSystem.GetFileInfo(path);
}
-
- public IEnumerable<FileSystemMetadata> GetDirectories(string path)
- {
- return GetFileSystemEntries(path, false).Where(i => i.IsDirectory);
- }
}
}
diff --git a/MediaBrowser.Controller/Providers/EpisodeInfo.cs b/MediaBrowser.Controller/Providers/EpisodeInfo.cs
index b8e88ea53..5df999ab0 100644
--- a/MediaBrowser.Controller/Providers/EpisodeInfo.cs
+++ b/MediaBrowser.Controller/Providers/EpisodeInfo.cs
@@ -10,7 +10,6 @@ namespace MediaBrowser.Controller.Providers
public int? IndexNumberEnd { get; set; }
public bool IsMissingEpisode { get; set; }
- public bool IsVirtualUnaired { get; set; }
public EpisodeInfo()
{
diff --git a/MediaBrowser.Controller/Providers/IDirectoryService.cs b/MediaBrowser.Controller/Providers/IDirectoryService.cs
index 1b203f32c..6f864f4be 100644
--- a/MediaBrowser.Controller/Providers/IDirectoryService.cs
+++ b/MediaBrowser.Controller/Providers/IDirectoryService.cs
@@ -1,18 +1,12 @@
using System.Collections.Generic;
-
-using MediaBrowser.Controller.IO;
using MediaBrowser.Model.IO;
namespace MediaBrowser.Controller.Providers
{
public interface IDirectoryService
{
- IEnumerable<FileSystemMetadata> GetFileSystemEntries(string path);
- IEnumerable<FileSystemMetadata> GetDirectories(string path);
- IEnumerable<FileSystemMetadata> GetFiles(string path);
- IEnumerable<string> GetFilePaths(string path);
- IEnumerable<string> GetFilePaths(string path, bool clearCache);
+ FileSystemMetadata[] GetFileSystemEntries(string path);
+ List<FileSystemMetadata> GetFiles(string path);
FileSystemMetadata GetFile(string path);
- Dictionary<string, FileSystemMetadata> GetFileSystemDictionary(string path);
}
} \ No newline at end of file
diff --git a/MediaBrowser.Controller/Providers/IDynamicImageProvider.cs b/MediaBrowser.Controller/Providers/IDynamicImageProvider.cs
index 9c3f94763..e96a2d65e 100644
--- a/MediaBrowser.Controller/Providers/IDynamicImageProvider.cs
+++ b/MediaBrowser.Controller/Providers/IDynamicImageProvider.cs
@@ -13,7 +13,7 @@ namespace MediaBrowser.Controller.Providers
/// </summary>
/// <param name="item">The item.</param>
/// <returns>IEnumerable{ImageType}.</returns>
- IEnumerable<ImageType> GetSupportedImages(IHasImages item);
+ IEnumerable<ImageType> GetSupportedImages(IHasMetadata item);
/// <summary>
/// Gets the image.
@@ -22,6 +22,6 @@ namespace MediaBrowser.Controller.Providers
/// <param name="type">The type.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task{DynamicImageResponse}.</returns>
- Task<DynamicImageResponse> GetImage(IHasImages item, ImageType type, CancellationToken cancellationToken);
+ Task<DynamicImageResponse> GetImage(IHasMetadata item, ImageType type, CancellationToken cancellationToken);
}
} \ No newline at end of file
diff --git a/MediaBrowser.Controller/Providers/IImageEnhancer.cs b/MediaBrowser.Controller/Providers/IImageEnhancer.cs
index a43941607..a993f536d 100644
--- a/MediaBrowser.Controller/Providers/IImageEnhancer.cs
+++ b/MediaBrowser.Controller/Providers/IImageEnhancer.cs
@@ -13,7 +13,7 @@ namespace MediaBrowser.Controller.Providers
/// <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(IHasImages item, ImageType imageType);
+ bool Supports(IHasMetadata item, ImageType imageType);
/// <summary>
/// Gets the priority or order in which this enhancer should be run.
@@ -27,7 +27,7 @@ namespace MediaBrowser.Controller.Providers
/// <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(IHasImages item, ImageType imageType);
+ string GetConfigurationCacheKey(IHasMetadata item, ImageType imageType);
/// <summary>
/// Gets the size of the enhanced image.
@@ -37,7 +37,7 @@ namespace MediaBrowser.Controller.Providers
/// <param name="imageIndex">Index of the image.</param>
/// <param name="originalImageSize">Size of the original image.</param>
/// <returns>ImageSize.</returns>
- ImageSize GetEnhancedImageSize(IHasImages item, ImageType imageType, int imageIndex, ImageSize originalImageSize);
+ ImageSize GetEnhancedImageSize(IHasMetadata item, ImageType imageType, int imageIndex, ImageSize originalImageSize);
/// <summary>
/// Enhances the image async.
@@ -49,6 +49,6 @@ namespace MediaBrowser.Controller.Providers
/// <param name="imageIndex">Index of the image.</param>
/// <returns>Task{Image}.</returns>
/// <exception cref="System.ArgumentNullException"></exception>
- Task EnhanceImageAsync(IHasImages item, string inputFile, string outputFile, ImageType imageType, int imageIndex);
+ Task EnhanceImageAsync(IHasMetadata item, string inputFile, string outputFile, ImageType imageType, int imageIndex);
}
} \ No newline at end of file
diff --git a/MediaBrowser.Controller/Providers/IImageProvider.cs b/MediaBrowser.Controller/Providers/IImageProvider.cs
index 1e5bdfeaf..2b43c9cb8 100644
--- a/MediaBrowser.Controller/Providers/IImageProvider.cs
+++ b/MediaBrowser.Controller/Providers/IImageProvider.cs
@@ -18,6 +18,6 @@ namespace MediaBrowser.Controller.Providers
/// </summary>
/// <param name="item">The item.</param>
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
- bool Supports(IHasImages item);
+ bool Supports(IHasMetadata item);
}
}
diff --git a/MediaBrowser.Controller/Providers/ILocalImageFileProvider.cs b/MediaBrowser.Controller/Providers/ILocalImageFileProvider.cs
index 7e5d82843..e93c73a52 100644
--- a/MediaBrowser.Controller/Providers/ILocalImageFileProvider.cs
+++ b/MediaBrowser.Controller/Providers/ILocalImageFileProvider.cs
@@ -5,6 +5,6 @@ namespace MediaBrowser.Controller.Providers
{
public interface ILocalImageFileProvider : ILocalImageProvider
{
- List<LocalImageInfo> GetImages(IHasImages item, IDirectoryService directoryService);
+ List<LocalImageInfo> GetImages(IHasMetadata item, IDirectoryService directoryService);
}
} \ No newline at end of file
diff --git a/MediaBrowser.Controller/Providers/IProviderManager.cs b/MediaBrowser.Controller/Providers/IProviderManager.cs
index 0ba573da8..77e6a7e40 100644
--- a/MediaBrowser.Controller/Providers/IProviderManager.cs
+++ b/MediaBrowser.Controller/Providers/IProviderManager.cs
@@ -50,7 +50,7 @@ namespace MediaBrowser.Controller.Providers
/// <param name="imageIndex">Index of the image.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
- Task SaveImage(IHasImages item, string url, ImageType type, int? imageIndex, CancellationToken cancellationToken);
+ Task SaveImage(IHasMetadata item, string url, ImageType type, int? imageIndex, CancellationToken cancellationToken);
/// <summary>
/// Saves the image.
@@ -62,13 +62,13 @@ namespace MediaBrowser.Controller.Providers
/// <param name="imageIndex">Index of the image.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
- Task SaveImage(IHasImages item, Stream source, string mimeType, ImageType type, int? imageIndex, CancellationToken cancellationToken);
+ Task SaveImage(IHasMetadata item, Stream source, string mimeType, ImageType type, int? imageIndex, CancellationToken cancellationToken);
/// <summary>
/// Saves the image.
/// </summary>
/// <returns>Task.</returns>
- Task SaveImage(IHasImages item, string source, string mimeType, ImageType type, int? imageIndex, bool? saveLocallyWithMedia, CancellationToken cancellationToken);
+ Task SaveImage(IHasMetadata item, string source, string mimeType, ImageType type, int? imageIndex, bool? saveLocallyWithMedia, CancellationToken cancellationToken);
/// <summary>
/// Adds the metadata providers.
@@ -84,20 +84,20 @@ namespace MediaBrowser.Controller.Providers
/// <param name="query">The query.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task{IEnumerable{RemoteImageInfo}}.</returns>
- Task<IEnumerable<RemoteImageInfo>> GetAvailableRemoteImages(IHasImages item, RemoteImageQuery query, CancellationToken cancellationToken);
+ Task<IEnumerable<RemoteImageInfo>> GetAvailableRemoteImages(IHasMetadata item, RemoteImageQuery query, CancellationToken cancellationToken);
/// <summary>
/// Gets the image providers.
/// </summary>
/// <param name="item">The item.</param>
/// <returns>IEnumerable{ImageProviderInfo}.</returns>
- IEnumerable<ImageProviderInfo> GetRemoteImageProviderInfo(IHasImages item);
+ IEnumerable<ImageProviderInfo> GetRemoteImageProviderInfo(IHasMetadata item);
/// <summary>
/// Gets all metadata plugins.
/// </summary>
/// <returns>IEnumerable{MetadataPlugin}.</returns>
- IEnumerable<MetadataPluginSummary> GetAllMetadataPlugins();
+ MetadataPluginSummary[] GetAllMetadataPlugins();
/// <summary>
/// Gets the external urls.
@@ -135,7 +135,7 @@ namespace MediaBrowser.Controller.Providers
/// </summary>
/// <param name="item">The item.</param>
/// <returns>MetadataOptions.</returns>
- MetadataOptions GetMetadataOptions(IHasImages item);
+ MetadataOptions GetMetadataOptions(IHasMetadata item);
/// <summary>
/// Gets the remote search results.
diff --git a/MediaBrowser.Controller/Providers/IRemoteImageProvider.cs b/MediaBrowser.Controller/Providers/IRemoteImageProvider.cs
index 6b94547bb..86a7939e6 100644
--- a/MediaBrowser.Controller/Providers/IRemoteImageProvider.cs
+++ b/MediaBrowser.Controller/Providers/IRemoteImageProvider.cs
@@ -18,7 +18,7 @@ namespace MediaBrowser.Controller.Providers
/// </summary>
/// <param name="item">The item.</param>
/// <returns>IEnumerable{ImageType}.</returns>
- IEnumerable<ImageType> GetSupportedImages(IHasImages item);
+ IEnumerable<ImageType> GetSupportedImages(IHasMetadata item);
/// <summary>
/// Gets the images.
@@ -26,7 +26,7 @@ namespace MediaBrowser.Controller.Providers
/// <param name="item">The item.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task{IEnumerable{RemoteImageInfo}}.</returns>
- Task<IEnumerable<RemoteImageInfo>> GetImages(IHasImages item, CancellationToken cancellationToken);
+ Task<IEnumerable<RemoteImageInfo>> GetImages(IHasMetadata item, CancellationToken cancellationToken);
/// <summary>
/// Gets the image response.
diff --git a/MediaBrowser.Controller/Providers/ItemInfo.cs b/MediaBrowser.Controller/Providers/ItemInfo.cs
index 8de11b743..63cc48058 100644
--- a/MediaBrowser.Controller/Providers/ItemInfo.cs
+++ b/MediaBrowser.Controller/Providers/ItemInfo.cs
@@ -10,7 +10,7 @@ namespace MediaBrowser.Controller.Providers
{
Path = item.Path;
ContainingFolderPath = item.ContainingFolderPath;
- IsInMixedFolder = item.DetectIsInMixedFolder();
+ IsInMixedFolder = item.IsInMixedFolder;
var video = item as Video;
if (video != null)
diff --git a/MediaBrowser.Controller/Providers/ItemLookupInfo.cs b/MediaBrowser.Controller/Providers/ItemLookupInfo.cs
index dc7a04135..98122e776 100644
--- a/MediaBrowser.Controller/Providers/ItemLookupInfo.cs
+++ b/MediaBrowser.Controller/Providers/ItemLookupInfo.cs
@@ -6,6 +6,8 @@ namespace MediaBrowser.Controller.Providers
{
public class ItemLookupInfo : IHasProviderIds
{
+ protected static string[] EmptyStringArray = new string[] { };
+
/// <summary>
/// Gets or sets the name.
/// </summary>
diff --git a/MediaBrowser.Controller/Providers/MetadataResult.cs b/MediaBrowser.Controller/Providers/MetadataResult.cs
index 99402a969..5ed55ea16 100644
--- a/MediaBrowser.Controller/Providers/MetadataResult.cs
+++ b/MediaBrowser.Controller/Providers/MetadataResult.cs
@@ -1,7 +1,6 @@
using MediaBrowser.Controller.Entities;
using System;
using System.Collections.Generic;
-using System.Linq;
namespace MediaBrowser.Controller.Providers
{
@@ -51,7 +50,15 @@ namespace MediaBrowser.Controller.Providers
UserDataList = new List<UserItemData>();
}
- var userData = UserDataList.FirstOrDefault(i => string.Equals(userId, i.UserId.ToString("N"), StringComparison.OrdinalIgnoreCase));
+ UserItemData userData = null;
+
+ foreach (var i in UserDataList)
+ {
+ if (string.Equals(userId, i.UserId.ToString("N"), StringComparison.OrdinalIgnoreCase))
+ {
+ userData = i;
+ }
+ }
if (userData == null)
{
diff --git a/MediaBrowser.Controller/Providers/SongInfo.cs b/MediaBrowser.Controller/Providers/SongInfo.cs
index b83912a00..e3a6f5d37 100644
--- a/MediaBrowser.Controller/Providers/SongInfo.cs
+++ b/MediaBrowser.Controller/Providers/SongInfo.cs
@@ -1,17 +1,16 @@
-using System.Collections.Generic;
namespace MediaBrowser.Controller.Providers
{
public class SongInfo : ItemLookupInfo
{
- public List<string> AlbumArtists { get; set; }
+ public string[] AlbumArtists { get; set; }
public string Album { get; set; }
- public List<string> Artists { get; set; }
+ public string[] Artists { get; set; }
public SongInfo()
{
- Artists = new List<string>();
- AlbumArtists = new List<string>();
+ Artists = EmptyStringArray;
+ AlbumArtists = EmptyStringArray;
}
}
} \ No newline at end of file
diff --git a/MediaBrowser.Controller/Security/IAuthenticationRepository.cs b/MediaBrowser.Controller/Security/IAuthenticationRepository.cs
index 219b07028..f80ee6e7f 100644
--- a/MediaBrowser.Controller/Security/IAuthenticationRepository.cs
+++ b/MediaBrowser.Controller/Security/IAuthenticationRepository.cs
@@ -1,6 +1,5 @@
using MediaBrowser.Model.Querying;
using System.Threading;
-using System.Threading.Tasks;
namespace MediaBrowser.Controller.Security
{
@@ -12,7 +11,7 @@ namespace MediaBrowser.Controller.Security
/// <param name="info">The information.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
- Task Create(AuthenticationInfo info, CancellationToken cancellationToken);
+ void Create(AuthenticationInfo info, CancellationToken cancellationToken);
/// <summary>
/// Updates the specified information.
@@ -20,7 +19,7 @@ namespace MediaBrowser.Controller.Security
/// <param name="info">The information.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
- Task Update(AuthenticationInfo info, CancellationToken cancellationToken);
+ void Update(AuthenticationInfo info, CancellationToken cancellationToken);
/// <summary>
/// Gets the specified query.
diff --git a/MediaBrowser.Controller/Session/ISessionManager.cs b/MediaBrowser.Controller/Session/ISessionManager.cs
index 8d77e0747..603e5ef76 100644
--- a/MediaBrowser.Controller/Session/ISessionManager.cs
+++ b/MediaBrowser.Controller/Session/ISessionManager.cs
@@ -318,19 +318,19 @@ namespace MediaBrowser.Controller.Session
/// </summary>
/// <param name="accessToken">The access token.</param>
/// <returns>Task.</returns>
- Task Logout(string accessToken);
+ void Logout(string accessToken);
/// <summary>
/// Revokes the user tokens.
/// </summary>
/// <returns>Task.</returns>
- Task RevokeUserTokens(string userId, string currentAccessToken);
+ void RevokeUserTokens(string userId, string currentAccessToken);
/// <summary>
/// Revokes the token.
/// </summary>
/// <param name="id">The identifier.</param>
/// <returns>Task.</returns>
- Task RevokeToken(string id);
+ void RevokeToken(string id);
}
} \ No newline at end of file
diff --git a/MediaBrowser.Controller/Session/SessionInfo.cs b/MediaBrowser.Controller/Session/SessionInfo.cs
index 11a9ceac4..367a7a467 100644
--- a/MediaBrowser.Controller/Session/SessionInfo.cs
+++ b/MediaBrowser.Controller/Session/SessionInfo.cs
@@ -2,7 +2,6 @@
using MediaBrowser.Model.Session;
using System;
using System.Collections.Generic;
-using System.Linq;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Threading;
@@ -22,13 +21,13 @@ namespace MediaBrowser.Controller.Session
_sessionManager = sessionManager;
_logger = logger;
- AdditionalUsers = new List<SessionUserInfo>();
+ AdditionalUsers = new SessionUserInfo[] { };
PlayState = new PlayerStateInfo();
}
public PlayerStateInfo PlayState { get; set; }
- public List<SessionUserInfo> AdditionalUsers { get; set; }
+ public SessionUserInfo[] AdditionalUsers { get; set; }
public ClientCapabilities Capabilities { get; set; }
@@ -42,13 +41,13 @@ namespace MediaBrowser.Controller.Session
/// Gets or sets the playable media types.
/// </summary>
/// <value>The playable media types.</value>
- public List<string> PlayableMediaTypes
+ public string[] PlayableMediaTypes
{
get
{
if (Capabilities == null)
{
- return new List<string>();
+ return new string[] { };
}
return Capabilities.PlayableMediaTypes;
}
@@ -138,13 +137,13 @@ namespace MediaBrowser.Controller.Session
/// Gets or sets the supported commands.
/// </summary>
/// <value>The supported commands.</value>
- public List<string> SupportedCommands
+ public string[] SupportedCommands
{
get
{
if (Capabilities == null)
{
- return new List<string>();
+ return new string[] { };
}
return Capabilities.SupportedCommands;
}
@@ -194,7 +193,19 @@ namespace MediaBrowser.Controller.Session
public bool ContainsUser(Guid userId)
{
- return (UserId ?? Guid.Empty) == userId || AdditionalUsers.Any(i => userId == new Guid(i.UserId));
+ if ((UserId ?? Guid.Empty) == userId)
+ {
+ return true;
+ }
+
+ foreach (var additionalUser in AdditionalUsers)
+ {
+ if (userId == new Guid(additionalUser.UserId))
+ {
+ return true;
+ }
+ }
+ return false;
}
private readonly object _progressLock = new object();
@@ -292,6 +303,7 @@ namespace MediaBrowser.Controller.Session
StopAutomaticProgress();
_sessionManager = null;
+ GC.SuppressFinalize(this);
}
}
}
diff --git a/MediaBrowser.Controller/Subtitles/ISubtitleManager.cs b/MediaBrowser.Controller/Subtitles/ISubtitleManager.cs
index d1d5f27be..2199c21e6 100644
--- a/MediaBrowser.Controller/Subtitles/ISubtitleManager.cs
+++ b/MediaBrowser.Controller/Subtitles/ISubtitleManager.cs
@@ -28,7 +28,7 @@ namespace MediaBrowser.Controller.Subtitles
/// <summary>
/// Searches the subtitles.
/// </summary>
- Task<IEnumerable<RemoteSubtitleInfo>> SearchSubtitles(Video video,
+ Task<RemoteSubtitleInfo[]> SearchSubtitles(Video video,
string language,
bool? isPerfectMatch,
CancellationToken cancellationToken);
@@ -39,7 +39,7 @@ namespace MediaBrowser.Controller.Subtitles
/// <param name="request">The request.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task{IEnumerable{RemoteSubtitleInfo}}.</returns>
- Task<IEnumerable<RemoteSubtitleInfo>> SearchSubtitles(SubtitleSearchRequest request,
+ Task<RemoteSubtitleInfo[]> SearchSubtitles(SubtitleSearchRequest request,
CancellationToken cancellationToken);
/// <summary>
@@ -74,6 +74,6 @@ namespace MediaBrowser.Controller.Subtitles
/// </summary>
/// <param name="itemId">The item identifier.</param>
/// <returns>IEnumerable{SubtitleProviderInfo}.</returns>
- IEnumerable<SubtitleProviderInfo> GetProviders(string itemId);
+ SubtitleProviderInfo[] GetProviders(string itemId);
}
}
diff --git a/MediaBrowser.Controller/Sync/ISyncManager.cs b/MediaBrowser.Controller/Sync/ISyncManager.cs
index 291632ea5..910d697ec 100644
--- a/MediaBrowser.Controller/Sync/ISyncManager.cs
+++ b/MediaBrowser.Controller/Sync/ISyncManager.cs
@@ -16,6 +16,7 @@ namespace MediaBrowser.Controller.Sync
event EventHandler<GenericEventArgs<SyncJob>> SyncJobUpdated;
event EventHandler<GenericEventArgs<SyncJobItem>> SyncJobItemUpdated;
event EventHandler<GenericEventArgs<SyncJobItem>> SyncJobItemCreated;
+ event EventHandler<GenericEventArgs<SyncJobItem>> SyncJobItemCancelled;
/// <summary>
/// Creates the job.
@@ -78,7 +79,7 @@ namespace MediaBrowser.Controller.Sync
/// <param name="targetId">The target identifier.</param>
/// <param name="itemIds">The item ids.</param>
/// <returns>Task.</returns>
- Task CancelItems(string targetId, IEnumerable<string> itemIds);
+ Task CancelItems(string targetId, string[] itemIds);
/// <summary>
/// Adds the parts.
@@ -88,9 +89,9 @@ namespace MediaBrowser.Controller.Sync
/// <summary>
/// Gets the synchronize targets.
/// </summary>
- IEnumerable<SyncTarget> GetSyncTargets(string userId);
+ List<SyncTarget> GetSyncTargets(string userId);
- IEnumerable<SyncTarget> GetSyncTargets(string userId, bool? supportsRemoteSync);
+ List<SyncTarget> GetSyncTargets(string userId, bool? supportsRemoteSync);
/// <summary>
/// Supportses the synchronize.
@@ -135,20 +136,6 @@ namespace MediaBrowser.Controller.Sync
Task<SyncDataResponse> SyncData(SyncDataRequest request);
/// <summary>
- /// Marks the job item for removal.
- /// </summary>
- /// <param name="id">The identifier.</param>
- /// <returns>Task.</returns>
- Task MarkJobItemForRemoval(string id);
-
- /// <summary>
- /// Unmarks the job item for removal.
- /// </summary>
- /// <param name="id">The identifier.</param>
- /// <returns>Task.</returns>
- Task UnmarkJobItemForRemoval(string id);
-
- /// <summary>
/// Gets the library item ids.
/// </summary>
/// <param name="query">The query.</param>
@@ -173,28 +160,24 @@ namespace MediaBrowser.Controller.Sync
/// Gets the quality options.
/// </summary>
/// <param name="targetId">The target identifier.</param>
- /// <returns>IEnumerable&lt;SyncQualityOption&gt;.</returns>
- IEnumerable<SyncQualityOption> GetQualityOptions(string targetId);
+ List<SyncQualityOption> GetQualityOptions(string targetId);
/// <summary>
/// Gets the quality options.
/// </summary>
/// <param name="targetId">The target identifier.</param>
/// <param name="user">The user.</param>
- /// <returns>IEnumerable&lt;SyncQualityOption&gt;.</returns>
- IEnumerable<SyncQualityOption> GetQualityOptions(string targetId, User user);
+ List<SyncQualityOption> GetQualityOptions(string targetId, User user);
/// <summary>
/// Gets the profile options.
/// </summary>
/// <param name="targetId">The target identifier.</param>
- /// <returns>IEnumerable&lt;SyncQualityOption&gt;.</returns>
- IEnumerable<SyncProfileOption> GetProfileOptions(string targetId);
+ List<SyncProfileOption> GetProfileOptions(string targetId);
/// <summary>
/// Gets the profile options.
/// </summary>
/// <param name="targetId">The target identifier.</param>
/// <param name="user">The user.</param>
- /// <returns>IEnumerable&lt;SyncProfileOption&gt;.</returns>
- IEnumerable<SyncProfileOption> GetProfileOptions(string targetId, User user);
+ List<SyncProfileOption> GetProfileOptions(string targetId, User user);
}
}
diff --git a/MediaBrowser.Controller/Sync/ISyncProvider.cs b/MediaBrowser.Controller/Sync/ISyncProvider.cs
index aa4b36427..2f60e124e 100644
--- a/MediaBrowser.Controller/Sync/ISyncProvider.cs
+++ b/MediaBrowser.Controller/Sync/ISyncProvider.cs
@@ -18,13 +18,13 @@ namespace MediaBrowser.Controller.Sync
/// </summary>
/// <param name="userId">The user identifier.</param>
/// <returns>IEnumerable&lt;SyncTarget&gt;.</returns>
- IEnumerable<SyncTarget> GetSyncTargets(string userId);
+ List<SyncTarget> GetSyncTargets(string userId);
/// <summary>
/// Gets all synchronize targets.
/// </summary>
/// <returns>IEnumerable&lt;SyncTarget&gt;.</returns>
- IEnumerable<SyncTarget> GetAllSyncTargets();
+ List<SyncTarget> GetAllSyncTargets();
}
public interface IHasUniqueTargetIds
diff --git a/MediaBrowser.Controller/Sync/ISyncRepository.cs b/MediaBrowser.Controller/Sync/ISyncRepository.cs
deleted file mode 100644
index 8e9b2bf77..000000000
--- a/MediaBrowser.Controller/Sync/ISyncRepository.cs
+++ /dev/null
@@ -1,80 +0,0 @@
-using System.Collections.Generic;
-using MediaBrowser.Model.Querying;
-using MediaBrowser.Model.Sync;
-using System.Threading.Tasks;
-
-namespace MediaBrowser.Controller.Sync
-{
- public interface ISyncRepository
- {
- /// <summary>
- /// Gets the job.
- /// </summary>
- /// <param name="id">The identifier.</param>
- /// <returns>SyncJob.</returns>
- SyncJob GetJob(string id);
-
- /// <summary>
- /// Creates the specified job.
- /// </summary>
- /// <param name="job">The job.</param>
- /// <returns>Task.</returns>
- Task Create(SyncJob job);
-
- /// <summary>
- /// Updates the specified job.
- /// </summary>
- /// <param name="job">The job.</param>
- /// <returns>Task.</returns>
- Task Update(SyncJob job);
-
- /// <summary>
- /// Deletes the job.
- /// </summary>
- /// <param name="id">The identifier.</param>
- /// <returns>Task.</returns>
- Task DeleteJob(string id);
-
- /// <summary>
- /// Gets the jobs.
- /// </summary>
- /// <param name="query">The query.</param>
- /// <returns>QueryResult&lt;SyncJob&gt;.</returns>
- QueryResult<SyncJob> GetJobs(SyncJobQuery query);
-
- /// <summary>
- /// Gets the job item.
- /// </summary>
- /// <param name="id">The identifier.</param>
- /// <returns>SyncJobItem.</returns>
- SyncJobItem GetJobItem(string id);
-
- /// <summary>
- /// Creates the specified job item.
- /// </summary>
- /// <param name="jobItem">The job item.</param>
- /// <returns>Task.</returns>
- Task Create(SyncJobItem jobItem);
-
- /// <summary>
- /// Updates the specified job item.
- /// </summary>
- /// <param name="jobItem">The job item.</param>
- /// <returns>Task.</returns>
- Task Update(SyncJobItem jobItem);
-
- /// <summary>
- /// Gets the job items.
- /// </summary>
- /// <param name="query">The query.</param>
- /// <returns>IEnumerable&lt;SyncJobItem&gt;.</returns>
- QueryResult<SyncJobItem> GetJobItems(SyncJobItemQuery query);
-
- /// <summary>
- /// Gets the library item ids.
- /// </summary>
- /// <param name="query">The query.</param>
- /// <returns>QueryResult&lt;System.String&gt;.</returns>
- Dictionary<string, SyncedItemProgress> GetSyncedItemProgresses(SyncJobItemQuery query);
- }
-}
diff --git a/MediaBrowser.LocalMetadata/Images/CollectionFolderImageProvider.cs b/MediaBrowser.LocalMetadata/Images/CollectionFolderImageProvider.cs
index 954e0c322..4ec2eeeb1 100644
--- a/MediaBrowser.LocalMetadata/Images/CollectionFolderImageProvider.cs
+++ b/MediaBrowser.LocalMetadata/Images/CollectionFolderImageProvider.cs
@@ -21,7 +21,7 @@ namespace MediaBrowser.LocalMetadata.Images
get { return "Collection Folder Images"; }
}
- public bool Supports(IHasImages item)
+ public bool Supports(IHasMetadata item)
{
return item is CollectionFolder && item.SupportsLocalMetadata;
}
@@ -35,7 +35,7 @@ namespace MediaBrowser.LocalMetadata.Images
}
}
- public List<LocalImageInfo> GetImages(IHasImages item, IDirectoryService directoryService)
+ public List<LocalImageInfo> GetImages(IHasMetadata item, IDirectoryService directoryService)
{
var collectionFolder = (CollectionFolder)item;
diff --git a/MediaBrowser.LocalMetadata/Images/EpisodeLocalImageProvider.cs b/MediaBrowser.LocalMetadata/Images/EpisodeLocalImageProvider.cs
index 2b5858aec..9195a9cd4 100644
--- a/MediaBrowser.LocalMetadata/Images/EpisodeLocalImageProvider.cs
+++ b/MediaBrowser.LocalMetadata/Images/EpisodeLocalImageProvider.cs
@@ -4,10 +4,8 @@ using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities;
using System;
using System.Collections.Generic;
-using System.IO;
using System.Linq;
-using MediaBrowser.Controller.IO;
using MediaBrowser.Model.IO;
namespace MediaBrowser.LocalMetadata.Images
@@ -31,58 +29,59 @@ namespace MediaBrowser.LocalMetadata.Images
get { return 0; }
}
- public bool Supports(IHasImages item)
+ public bool Supports(IHasMetadata item)
{
return item is Episode && item.SupportsLocalMetadata;
}
- public List<LocalImageInfo> GetImages(IHasImages item, IDirectoryService directoryService)
+ public List<LocalImageInfo> GetImages(IHasMetadata item, IDirectoryService directoryService)
{
var parentPath = _fileSystem.GetDirectoryName(item.Path);
- var parentPathFiles = directoryService.GetFiles(parentPath)
- .ToList();
+ var parentPathFiles = directoryService.GetFiles(parentPath);
var nameWithoutExtension = _fileSystem.GetFileNameWithoutExtension(item.Path);
return GetFilesFromParentFolder(nameWithoutExtension, parentPathFiles);
}
- private List<LocalImageInfo> GetFilesFromParentFolder(string filenameWithoutExtension, IEnumerable<FileSystemMetadata> parentPathFiles)
+ private List<LocalImageInfo> GetFilesFromParentFolder(string filenameWithoutExtension, List<FileSystemMetadata> parentPathFiles)
{
var thumbName = filenameWithoutExtension + "-thumb";
- return parentPathFiles
- .Where(i =>
- {
- if (i.IsDirectory)
- {
- return false;
- }
-
- if (BaseItem.SupportedImageExtensions.Contains(i.Extension, StringComparer.OrdinalIgnoreCase))
- {
- var currentNameWithoutExtension = _fileSystem.GetFileNameWithoutExtension(i);
-
- if (string.Equals(filenameWithoutExtension, currentNameWithoutExtension, StringComparison.OrdinalIgnoreCase))
- {
- return true;
- }
-
- if (string.Equals(thumbName, currentNameWithoutExtension, StringComparison.OrdinalIgnoreCase))
- {
- return true;
- }
- }
-
- return false;
- })
- .Select(i => new LocalImageInfo
- {
- FileInfo = i,
- Type = ImageType.Primary
- })
- .ToList();
+ var list = new List<LocalImageInfo>(1);
+
+ foreach (var i in parentPathFiles)
+ {
+ if (i.IsDirectory)
+ {
+ continue;
+ }
+
+ if (BaseItem.SupportedImageExtensions.Contains(i.Extension, StringComparer.OrdinalIgnoreCase))
+ {
+ var currentNameWithoutExtension = _fileSystem.GetFileNameWithoutExtension(i);
+
+ if (string.Equals(filenameWithoutExtension, currentNameWithoutExtension, StringComparison.OrdinalIgnoreCase))
+ {
+ list.Add(new LocalImageInfo
+ {
+ FileInfo = i,
+ Type = ImageType.Primary
+ });
+ }
+
+ else if (string.Equals(thumbName, currentNameWithoutExtension, StringComparison.OrdinalIgnoreCase))
+ {
+ list.Add(new LocalImageInfo
+ {
+ FileInfo = i,
+ Type = ImageType.Primary
+ });
+ }
+ }
+ }
+ return list;
}
}
}
diff --git a/MediaBrowser.LocalMetadata/Images/ImagesByNameImageProvider.cs b/MediaBrowser.LocalMetadata/Images/ImagesByNameImageProvider.cs
deleted file mode 100644
index 83554f044..000000000
--- a/MediaBrowser.LocalMetadata/Images/ImagesByNameImageProvider.cs
+++ /dev/null
@@ -1,58 +0,0 @@
-using System.Collections.Generic;
-using System.IO;
-
-using MediaBrowser.Model.IO;
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.IO;
-using MediaBrowser.Controller.Providers;
-
-namespace MediaBrowser.LocalMetadata.Images
-{
- public class ImagesByNameImageProvider : ILocalImageFileProvider, IHasOrder
- {
- private readonly IFileSystem _fileSystem;
- private readonly IServerConfigurationManager _config;
-
- public ImagesByNameImageProvider(IFileSystem fileSystem, IServerConfigurationManager config)
- {
- _fileSystem = fileSystem;
- _config = config;
- }
-
- public string Name
- {
- get { return "Images By Name"; }
- }
-
- public bool Supports(IHasImages item)
- {
- return item is CollectionFolder;
- }
-
- public int Order
- {
- get
- {
- // Run after LocalImageProvider, and after CollectionFolderImageProvider
- return 2;
- }
- }
-
- public List<LocalImageInfo> GetImages(IHasImages item, IDirectoryService directoryService)
- {
- var name = _fileSystem.GetValidFilename(item.Name);
-
- var path = Path.Combine(_config.ApplicationPaths.GeneralPath, name);
-
- try
- {
- return new LocalImageProvider(_fileSystem).GetImages(item, path, false, directoryService);
- }
- catch (IOException)
- {
- return new List<LocalImageInfo>();
- }
- }
- }
-}
diff --git a/MediaBrowser.LocalMetadata/Images/InternalMetadataFolderImageProvider.cs b/MediaBrowser.LocalMetadata/Images/InternalMetadataFolderImageProvider.cs
index 47579f870..469a31442 100644
--- a/MediaBrowser.LocalMetadata/Images/InternalMetadataFolderImageProvider.cs
+++ b/MediaBrowser.LocalMetadata/Images/InternalMetadataFolderImageProvider.cs
@@ -26,7 +26,7 @@ namespace MediaBrowser.LocalMetadata.Images
get { return "Internal Images"; }
}
- public bool Supports(IHasImages item)
+ public bool Supports(IHasMetadata item)
{
if (item is Photo)
{
@@ -61,7 +61,7 @@ namespace MediaBrowser.LocalMetadata.Images
}
}
- public List<LocalImageInfo> GetImages(IHasImages item, IDirectoryService directoryService)
+ public List<LocalImageInfo> GetImages(IHasMetadata item, IDirectoryService directoryService)
{
var path = item.GetInternalMetadataPath();
diff --git a/MediaBrowser.LocalMetadata/Images/LocalImageProvider.cs b/MediaBrowser.LocalMetadata/Images/LocalImageProvider.cs
index b449ad6e0..56a2c271f 100644
--- a/MediaBrowser.LocalMetadata/Images/LocalImageProvider.cs
+++ b/MediaBrowser.LocalMetadata/Images/LocalImageProvider.cs
@@ -7,7 +7,6 @@ using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
-
using MediaBrowser.Controller.IO;
using MediaBrowser.Model.IO;
@@ -32,7 +31,7 @@ namespace MediaBrowser.LocalMetadata.Images
get { return 0; }
}
- public bool Supports(IHasImages item)
+ public bool Supports(IHasMetadata item)
{
if (item.SupportsLocalMetadata)
{
@@ -63,7 +62,7 @@ namespace MediaBrowser.LocalMetadata.Images
return false;
}
- private IEnumerable<FileSystemMetadata> GetFiles(IHasImages item, bool includeDirectories, IDirectoryService directoryService)
+ private IEnumerable<FileSystemMetadata> GetFiles(IHasMetadata item, bool includeDirectories, IDirectoryService directoryService)
{
if (item.LocationType != LocationType.FileSystem)
{
@@ -85,7 +84,7 @@ namespace MediaBrowser.LocalMetadata.Images
.OrderBy(i => BaseItem.SupportedImageExtensionsList.IndexOf(i.Extension ?? string.Empty));
}
- public List<LocalImageInfo> GetImages(IHasImages item, IDirectoryService directoryService)
+ public List<LocalImageInfo> GetImages(IHasMetadata item, IDirectoryService directoryService)
{
var files = GetFiles(item, true, directoryService).ToList();
@@ -96,30 +95,14 @@ namespace MediaBrowser.LocalMetadata.Images
return list;
}
- public List<LocalImageInfo> GetImages(IHasImages item, string path, bool isPathInMediaFolder, IDirectoryService directoryService)
+ public List<LocalImageInfo> GetImages(IHasMetadata item, string path, bool isPathInMediaFolder, IDirectoryService directoryService)
{
return GetImages(item, new[] { path }, isPathInMediaFolder, directoryService);
}
- public List<LocalImageInfo> GetImages(IHasImages item, IEnumerable<string> paths, bool arePathsInMediaFolders, IDirectoryService directoryService)
+ public List<LocalImageInfo> GetImages(IHasMetadata item, IEnumerable<string> paths, bool arePathsInMediaFolders, IDirectoryService directoryService)
{
- IEnumerable<FileSystemMetadata> files;
-
- if (arePathsInMediaFolders)
- {
- files = paths.SelectMany(i => _fileSystem.GetFiles(i, BaseItem.SupportedImageExtensions, true, false));
- }
- else
- {
- files = paths.SelectMany(directoryService.GetFiles)
- .Where(i =>
- {
- var ext = i.Extension;
-
- return !string.IsNullOrEmpty(ext) &&
- BaseItem.SupportedImageExtensions.Contains(ext, StringComparer.OrdinalIgnoreCase);
- });
- }
+ IEnumerable<FileSystemMetadata> files = paths.SelectMany(i => _fileSystem.GetFiles(i, BaseItem.SupportedImageExtensions, true, false));
files = files
.OrderBy(i => BaseItem.SupportedImageExtensionsList.IndexOf(i.Extension ?? string.Empty));
@@ -131,7 +114,7 @@ namespace MediaBrowser.LocalMetadata.Images
return list;
}
- private void PopulateImages(IHasImages item, List<LocalImageInfo> images, List<FileSystemMetadata> files, bool supportParentSeriesFiles, IDirectoryService directoryService)
+ private void PopulateImages(IHasMetadata item, List<LocalImageInfo> images, List<FileSystemMetadata> files, bool supportParentSeriesFiles, IDirectoryService directoryService)
{
if (supportParentSeriesFiles)
{
@@ -144,7 +127,7 @@ namespace MediaBrowser.LocalMetadata.Images
}
var imagePrefix = item.FileNameWithoutExtension + "-";
- var isInMixedFolder = item.DetectIsInMixedFolder();
+ var isInMixedFolder = item.IsInMixedFolder;
PopulatePrimaryImages(item, images, files, imagePrefix, isInMixedFolder);
@@ -179,36 +162,71 @@ namespace MediaBrowser.LocalMetadata.Images
PopulateScreenshots(images, files, imagePrefix, isInMixedFolder);
}
- private void PopulatePrimaryImages(IHasImages item, List<LocalImageInfo> images, List<FileSystemMetadata> files, string imagePrefix, bool isInMixedFolder)
+ private static readonly string[] CommonImageFileNames = new[]
{
- var names = new List<string>
- {
- "cover",
- "default"
- };
+ "poster",
+ "folder",
+ "cover",
+ "default"
+ };
- if (item is MusicAlbum || item is MusicArtist || item is PhotoAlbum || item is Person)
+ private static readonly string[] MusicImageFileNames = new[]
+ {
+ "folder",
+ "poster",
+ "cover",
+ "default"
+ };
+
+ private static readonly string[] PersonImageFileNames = new[]
+ {
+ "folder",
+ "poster"
+ };
+
+ private static readonly string[] SeriesImageFileNames = new[]
+ {
+ "poster",
+ "folder",
+ "cover",
+ "default",
+ "show"
+ };
+
+ private static readonly string[] VideoImageFileNames = new[]
+ {
+ "poster",
+ "folder",
+ "cover",
+ "default",
+ "movie"
+ };
+
+ private void PopulatePrimaryImages(IHasMetadata item, List<LocalImageInfo> images, List<FileSystemMetadata> files, string imagePrefix, bool isInMixedFolder)
+ {
+ string[] imageFileNames;
+
+ if (item is MusicAlbum || item is MusicArtist || item is PhotoAlbum)
{
// these prefer folder
- names.Insert(0, "poster");
- names.Insert(0, "folder");
+ imageFileNames = MusicImageFileNames;
}
- else
+ else if (item is Person)
{
- names.Insert(0, "folder");
- names.Insert(0, "poster");
+ // these prefer folder
+ imageFileNames = PersonImageFileNames;
}
-
- // Support plex/kodi convention
- if (item is Series)
+ else if (item is Series)
{
- names.Add("show");
+ imageFileNames = SeriesImageFileNames;
}
-
- // Support plex/kodi convention
- if (item is Video && !(item is Episode))
+ else if (item is Video && !(item is Episode))
+ {
+ imageFileNames = VideoImageFileNames;
+ }
+ else
{
- names.Add("movie");
+ imageFileNames = CommonImageFileNames;
}
var fileNameWithoutExtension = item.FileNameWithoutExtension;
@@ -217,21 +235,21 @@ namespace MediaBrowser.LocalMetadata.Images
AddImage(files, images, fileNameWithoutExtension, ImageType.Primary);
}
- foreach (var name in names)
+ foreach (var name in imageFileNames)
{
AddImage(files, images, imagePrefix + name, ImageType.Primary);
}
if (!isInMixedFolder)
{
- foreach (var name in names)
+ foreach (var name in imageFileNames)
{
AddImage(files, images, name, ImageType.Primary);
}
}
}
- private void PopulateBackdrops(IHasImages item, List<LocalImageInfo> images, List<FileSystemMetadata> files, string imagePrefix, bool isInMixedFolder, IDirectoryService directoryService)
+ private void PopulateBackdrops(IHasMetadata item, List<LocalImageInfo> images, List<FileSystemMetadata> files, string imagePrefix, bool isInMixedFolder, IDirectoryService directoryService)
{
if (!string.IsNullOrEmpty(item.Path))
{
diff --git a/MediaBrowser.LocalMetadata/MediaBrowser.LocalMetadata.csproj b/MediaBrowser.LocalMetadata/MediaBrowser.LocalMetadata.csproj
index 9a7371a66..0986ffdc2 100644
--- a/MediaBrowser.LocalMetadata/MediaBrowser.LocalMetadata.csproj
+++ b/MediaBrowser.LocalMetadata/MediaBrowser.LocalMetadata.csproj
@@ -39,7 +39,6 @@
<Compile Include="BaseXmlProvider.cs" />
<Compile Include="Images\CollectionFolderImageProvider.cs" />
<Compile Include="Images\EpisodeLocalImageProvider.cs" />
- <Compile Include="Images\ImagesByNameImageProvider.cs" />
<Compile Include="Images\InternalMetadataFolderImageProvider.cs" />
<Compile Include="Images\LocalImageProvider.cs" />
<Compile Include="Parsers\BaseItemXmlParser.cs" />
diff --git a/MediaBrowser.LocalMetadata/Parsers/BaseItemXmlParser.cs b/MediaBrowser.LocalMetadata/Parsers/BaseItemXmlParser.cs
index b92fc2ea8..9a814213b 100644
--- a/MediaBrowser.LocalMetadata/Parsers/BaseItemXmlParser.cs
+++ b/MediaBrowser.LocalMetadata/Parsers/BaseItemXmlParser.cs
@@ -179,18 +179,6 @@ namespace MediaBrowser.LocalMetadata.Parsers
item.Name = reader.ReadElementContentAsString();
break;
- case "Type":
- {
- var type = reader.ReadElementContentAsString();
-
- if (!string.IsNullOrWhiteSpace(type) && !type.Equals("none", StringComparison.OrdinalIgnoreCase))
- {
- item.DisplayMediaType = type;
- }
-
- break;
- }
-
case "CriticRating":
{
var text = reader.ReadElementContentAsString();
@@ -258,7 +246,7 @@ namespace MediaBrowser.LocalMetadata.Parsers
var person = item as Person;
if (person != null)
{
- person.ProductionLocations = new List<string> { val };
+ person.ProductionLocations = new string[] { val };
}
}
@@ -279,13 +267,11 @@ namespace MediaBrowser.LocalMetadata.Parsers
case "LockedFields":
{
- var fields = new List<MetadataFields>();
-
var val = reader.ReadElementContentAsString();
if (!string.IsNullOrWhiteSpace(val))
{
- var list = val.Split('|').Select(i =>
+ item.LockedFields = val.Split('|').Select(i =>
{
MetadataFields field;
@@ -296,13 +282,9 @@ namespace MediaBrowser.LocalMetadata.Parsers
return null;
- }).Where(i => i.HasValue).Select(i => i.Value);
-
- fields.AddRange(list);
+ }).Where(i => i.HasValue).Select(i => i.Value).ToArray();
}
- item.LockedFields = fields;
-
break;
}
@@ -485,7 +467,7 @@ namespace MediaBrowser.LocalMetadata.Parsers
{
if (!string.IsNullOrWhiteSpace(val))
{
- hasTrailers.AddTrailerUrl(val, false);
+ hasTrailers.AddTrailerUrl(val);
}
}
break;
@@ -945,6 +927,8 @@ namespace MediaBrowser.LocalMetadata.Parsers
reader.MoveToContent();
reader.Read();
+ var tags = new List<string>();
+
// Loop through each element
while (!reader.EOF && reader.ReadState == ReadState.Interactive)
{
@@ -958,7 +942,7 @@ namespace MediaBrowser.LocalMetadata.Parsers
if (!string.IsNullOrWhiteSpace(tag))
{
- item.AddTag(tag);
+ tags.Add(tag);
}
break;
}
@@ -973,6 +957,8 @@ namespace MediaBrowser.LocalMetadata.Parsers
reader.Read();
}
}
+
+ item.Tags = tags.Distinct(StringComparer.Ordinal).ToArray();
}
/// <summary>
@@ -1044,7 +1030,7 @@ namespace MediaBrowser.LocalMetadata.Parsers
if (!string.IsNullOrWhiteSpace(val))
{
- item.AddTrailerUrl(val, false);
+ item.AddTrailerUrl(val);
}
break;
}
diff --git a/MediaBrowser.LocalMetadata/Parsers/BoxSetXmlParser.cs b/MediaBrowser.LocalMetadata/Parsers/BoxSetXmlParser.cs
index a0f0e4476..33eb75edb 100644
--- a/MediaBrowser.LocalMetadata/Parsers/BoxSetXmlParser.cs
+++ b/MediaBrowser.LocalMetadata/Parsers/BoxSetXmlParser.cs
@@ -6,6 +6,7 @@ using System.Collections.Generic;
using System.Xml;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Xml;
+using MediaBrowser.Model.Extensions;
namespace MediaBrowser.LocalMetadata.Parsers
{
@@ -84,7 +85,7 @@ namespace MediaBrowser.LocalMetadata.Parsers
}
}
- item.Item.LinkedChildren = list;
+ item.Item.LinkedChildren = list.ToArray(list.Count);
}
public BoxSetXmlParser(ILogger logger, IProviderManager providerManager, IXmlReaderSettingsFactory xmlReaderSettingsFactory, IFileSystem fileSystem) : base(logger, providerManager, xmlReaderSettingsFactory, fileSystem)
diff --git a/MediaBrowser.LocalMetadata/Parsers/PlaylistXmlParser.cs b/MediaBrowser.LocalMetadata/Parsers/PlaylistXmlParser.cs
index 695fe2b12..c6ef85814 100644
--- a/MediaBrowser.LocalMetadata/Parsers/PlaylistXmlParser.cs
+++ b/MediaBrowser.LocalMetadata/Parsers/PlaylistXmlParser.cs
@@ -8,6 +8,7 @@ using System.Linq;
using System.Xml;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Xml;
+using MediaBrowser.Model.Extensions;
namespace MediaBrowser.LocalMetadata.Parsers
{
@@ -124,7 +125,7 @@ namespace MediaBrowser.LocalMetadata.Parsers
}
}
- item.LinkedChildren = list;
+ item.LinkedChildren = list.ToArray(list.Count);
}
private void FetchFromSharesNode(XmlReader reader, Playlist item)
diff --git a/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs b/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs
index f112dfc81..259f42391 100644
--- a/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs
+++ b/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs
@@ -106,7 +106,6 @@ namespace MediaBrowser.LocalMetadata.Savers
"Trailers",
"TVcomId",
"TvDbId",
- "Type",
"TVRageId",
"Website",
"Zap2ItId",
@@ -303,14 +302,9 @@ namespace MediaBrowser.LocalMetadata.Savers
writer.WriteElementString("LockData", item.IsLocked.ToString().ToLower());
- if (item.LockedFields.Count > 0)
+ if (item.LockedFields.Length > 0)
{
- writer.WriteElementString("LockedFields", string.Join("|", item.LockedFields.Select(i => i.ToString()).ToArray()));
- }
-
- if (!string.IsNullOrEmpty(item.DisplayMediaType))
- {
- writer.WriteElementString("Type", item.DisplayMediaType);
+ writer.WriteElementString("LockedFields", string.Join("|", item.LockedFields));
}
if (item.CriticRating.HasValue)
@@ -370,7 +364,7 @@ namespace MediaBrowser.LocalMetadata.Savers
var hasTrailers = item as IHasTrailers;
if (hasTrailers != null)
{
- if (hasTrailers.RemoteTrailers.Count > 0)
+ if (hasTrailers.RemoteTrailers.Length > 0)
{
writer.WriteStartElement("Trailers");
@@ -383,7 +377,7 @@ namespace MediaBrowser.LocalMetadata.Savers
}
}
- if (item.ProductionLocations.Count > 0)
+ if (item.ProductionLocations.Length > 0)
{
writer.WriteStartElement("Countries");
@@ -475,7 +469,7 @@ namespace MediaBrowser.LocalMetadata.Savers
writer.WriteEndElement();
}
- if (item.Studios.Count > 0)
+ if (item.Studios.Length > 0)
{
writer.WriteStartElement("Studios");
@@ -487,7 +481,7 @@ namespace MediaBrowser.LocalMetadata.Savers
writer.WriteEndElement();
}
- if (item.Tags.Count > 0)
+ if (item.Tags.Length > 0)
{
writer.WriteStartElement("Tags");
diff --git a/MediaBrowser.LocalMetadata/Savers/GameXmlSaver.cs b/MediaBrowser.LocalMetadata/Savers/GameXmlSaver.cs
index 26c4b4a93..24c5a4679 100644
--- a/MediaBrowser.LocalMetadata/Savers/GameXmlSaver.cs
+++ b/MediaBrowser.LocalMetadata/Savers/GameXmlSaver.cs
@@ -65,7 +65,7 @@ namespace MediaBrowser.LocalMetadata.Savers
public static string GetGameSavePath(Game item)
{
- if (item.DetectIsInMixedFolder())
+ if (item.IsInMixedFolder)
{
return Path.ChangeExtension(item.Path, ".xml");
}
diff --git a/MediaBrowser.MediaEncoding/BdInfo/BdInfoExaminer.cs b/MediaBrowser.MediaEncoding/BdInfo/BdInfoExaminer.cs
deleted file mode 100644
index 219b1f3c5..000000000
--- a/MediaBrowser.MediaEncoding/BdInfo/BdInfoExaminer.cs
+++ /dev/null
@@ -1,201 +0,0 @@
-using BDInfo;
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.MediaInfo;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Model.Text;
-
-namespace MediaBrowser.MediaEncoding.BdInfo
-{
- /// <summary>
- /// Class BdInfoExaminer
- /// </summary>
- public class BdInfoExaminer : IBlurayExaminer
- {
- private readonly IFileSystem _fileSystem;
- private readonly ITextEncoding _textEncoding;
-
- public BdInfoExaminer(IFileSystem fileSystem, ITextEncoding textEncoding)
- {
- _fileSystem = fileSystem;
- _textEncoding = textEncoding;
- }
-
- /// <summary>
- /// Gets the disc info.
- /// </summary>
- /// <param name="path">The path.</param>
- /// <returns>BlurayDiscInfo.</returns>
- public BlurayDiscInfo GetDiscInfo(string path)
- {
- if (string.IsNullOrWhiteSpace(path))
- {
- throw new ArgumentNullException("path");
- }
-
- var bdrom = new BDROM(path, _fileSystem, _textEncoding);
-
- bdrom.Scan();
-
- // Get the longest playlist
- var playlist = bdrom.PlaylistFiles.Values.OrderByDescending(p => p.TotalLength).FirstOrDefault(p => p.IsValid);
-
- var outputStream = new BlurayDiscInfo
- {
- MediaStreams = new List<MediaStream>()
- };
-
- if (playlist == null)
- {
- return outputStream;
- }
-
- outputStream.Chapters = playlist.Chapters;
-
- outputStream.RunTimeTicks = TimeSpan.FromSeconds(playlist.TotalLength).Ticks;
-
- var mediaStreams = new List<MediaStream>();
-
- foreach (var stream in playlist.SortedStreams)
- {
- var videoStream = stream as TSVideoStream;
-
- if (videoStream != null)
- {
- AddVideoStream(mediaStreams, videoStream);
- continue;
- }
-
- var audioStream = stream as TSAudioStream;
-
- if (audioStream != null)
- {
- AddAudioStream(mediaStreams, audioStream);
- continue;
- }
-
- var textStream = stream as TSTextStream;
-
- if (textStream != null)
- {
- AddSubtitleStream(mediaStreams, textStream);
- continue;
- }
-
- var graphicsStream = stream as TSGraphicsStream;
-
- if (graphicsStream != null)
- {
- AddSubtitleStream(mediaStreams, graphicsStream);
- }
- }
-
- outputStream.MediaStreams = mediaStreams;
-
- outputStream.PlaylistName = playlist.Name;
-
- if (playlist.StreamClips != null && playlist.StreamClips.Any())
- {
- // Get the files in the playlist
- outputStream.Files = playlist.StreamClips.Select(i => i.StreamFile.Name).ToList();
- }
-
- return outputStream;
- }
-
- /// <summary>
- /// Adds the video stream.
- /// </summary>
- /// <param name="streams">The streams.</param>
- /// <param name="videoStream">The video stream.</param>
- private void AddVideoStream(List<MediaStream> streams, TSVideoStream videoStream)
- {
- var mediaStream = new MediaStream
- {
- BitRate = Convert.ToInt32(videoStream.BitRate),
- Width = videoStream.Width,
- Height = videoStream.Height,
- Codec = videoStream.CodecShortName,
- IsInterlaced = videoStream.IsInterlaced,
- Type = MediaStreamType.Video,
- Index = streams.Count
- };
-
- if (videoStream.FrameRateDenominator > 0)
- {
- float frameRateEnumerator = videoStream.FrameRateEnumerator;
- float frameRateDenominator = videoStream.FrameRateDenominator;
-
- mediaStream.AverageFrameRate = mediaStream.RealFrameRate = frameRateEnumerator / frameRateDenominator;
- }
-
- streams.Add(mediaStream);
- }
-
- /// <summary>
- /// Adds the audio stream.
- /// </summary>
- /// <param name="streams">The streams.</param>
- /// <param name="audioStream">The audio stream.</param>
- private void AddAudioStream(List<MediaStream> streams, TSAudioStream audioStream)
- {
- var stream = new MediaStream
- {
- Codec = audioStream.CodecShortName,
- Language = audioStream.LanguageCode,
- Channels = audioStream.ChannelCount,
- SampleRate = audioStream.SampleRate,
- Type = MediaStreamType.Audio,
- Index = streams.Count
- };
-
- var bitrate = Convert.ToInt32(audioStream.BitRate);
-
- if (bitrate > 0)
- {
- stream.BitRate = bitrate;
- }
-
- if (audioStream.LFE > 0)
- {
- stream.Channels = audioStream.ChannelCount + 1;
- }
-
- streams.Add(stream);
- }
-
- /// <summary>
- /// Adds the subtitle stream.
- /// </summary>
- /// <param name="streams">The streams.</param>
- /// <param name="textStream">The text stream.</param>
- private void AddSubtitleStream(List<MediaStream> streams, TSTextStream textStream)
- {
- streams.Add(new MediaStream
- {
- Language = textStream.LanguageCode,
- Codec = textStream.CodecShortName,
- Type = MediaStreamType.Subtitle,
- Index = streams.Count
- });
- }
-
- /// <summary>
- /// Adds the subtitle stream.
- /// </summary>
- /// <param name="streams">The streams.</param>
- /// <param name="textStream">The text stream.</param>
- private void AddSubtitleStream(List<MediaStream> streams, TSGraphicsStream textStream)
- {
- streams.Add(new MediaStream
- {
- Language = textStream.LanguageCode,
- Codec = textStream.CodecShortName,
- Type = MediaStreamType.Subtitle,
- Index = streams.Count
- });
- }
- }
-}
diff --git a/MediaBrowser.MediaEncoding/Configuration/EncodingConfigurationFactory.cs b/MediaBrowser.MediaEncoding/Configuration/EncodingConfigurationFactory.cs
deleted file mode 100644
index 16c67655a..000000000
--- a/MediaBrowser.MediaEncoding/Configuration/EncodingConfigurationFactory.cs
+++ /dev/null
@@ -1,58 +0,0 @@
-using MediaBrowser.Common.Configuration;
-using MediaBrowser.Model.Configuration;
-using System.Collections.Generic;
-using System.IO;
-
-using MediaBrowser.Controller.IO;
-using MediaBrowser.Model.IO;
-
-namespace MediaBrowser.MediaEncoding.Configuration
-{
- public class EncodingConfigurationFactory : IConfigurationFactory
- {
- private readonly IFileSystem _fileSystem;
-
- public EncodingConfigurationFactory(IFileSystem fileSystem)
- {
- _fileSystem = fileSystem;
- }
-
- public IEnumerable<ConfigurationStore> GetConfigurations()
- {
- return new[]
- {
- new EncodingConfigurationStore(_fileSystem)
- };
- }
- }
-
- public class EncodingConfigurationStore : ConfigurationStore, IValidatingConfiguration
- {
- private readonly IFileSystem _fileSystem;
-
- public EncodingConfigurationStore(IFileSystem fileSystem)
- {
- ConfigurationType = typeof(EncodingOptions);
- Key = "encoding";
- _fileSystem = fileSystem;
- }
-
- public void Validate(object oldConfig, object newConfig)
- {
- var oldEncodingConfig = (EncodingOptions)oldConfig;
- var newEncodingConfig = (EncodingOptions)newConfig;
-
- var newPath = newEncodingConfig.TranscodingTempPath;
-
- if (!string.IsNullOrWhiteSpace(newPath)
- && !string.Equals(oldEncodingConfig.TranscodingTempPath ?? string.Empty, newPath))
- {
- // Validate
- if (!_fileSystem.DirectoryExists(newPath))
- {
- throw new FileNotFoundException(string.Format("{0} does not exist.", newPath));
- }
- }
- }
- }
-}
diff --git a/MediaBrowser.MediaEncoding/Encoder/AudioEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/AudioEncoder.cs
deleted file mode 100644
index 566e7946d..000000000
--- a/MediaBrowser.MediaEncoding/Encoder/AudioEncoder.cs
+++ /dev/null
@@ -1,62 +0,0 @@
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.MediaEncoding;
-using MediaBrowser.Controller.Session;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Model.Logging;
-using System;
-using MediaBrowser.Model.Diagnostics;
-
-namespace MediaBrowser.MediaEncoding.Encoder
-{
- public class AudioEncoder : BaseEncoder
- {
- public AudioEncoder(MediaEncoder mediaEncoder, ILogger logger, IServerConfigurationManager configurationManager, IFileSystem fileSystem, IIsoManager isoManager, ILibraryManager libraryManager, ISessionManager sessionManager, ISubtitleEncoder subtitleEncoder, IMediaSourceManager mediaSourceManager, IProcessFactory processFactory) : base(mediaEncoder, logger, configurationManager, fileSystem, isoManager, libraryManager, sessionManager, subtitleEncoder, mediaSourceManager, processFactory)
- {
- }
-
- protected override string GetCommandLineArguments(EncodingJob state)
- {
- var encodingOptions = GetEncodingOptions();
-
- return EncodingHelper.GetProgressiveAudioFullCommandLine(state, encodingOptions, state.OutputFilePath);
- }
-
- protected override string GetOutputFileExtension(EncodingJob state)
- {
- var ext = base.GetOutputFileExtension(state);
-
- if (!string.IsNullOrEmpty(ext))
- {
- return ext;
- }
-
- var audioCodec = state.Options.AudioCodec;
-
- if (string.Equals("aac", audioCodec, StringComparison.OrdinalIgnoreCase))
- {
- return ".aac";
- }
- if (string.Equals("mp3", audioCodec, StringComparison.OrdinalIgnoreCase))
- {
- return ".mp3";
- }
- if (string.Equals("vorbis", audioCodec, StringComparison.OrdinalIgnoreCase))
- {
- return ".ogg";
- }
- if (string.Equals("wma", audioCodec, StringComparison.OrdinalIgnoreCase))
- {
- return ".wma";
- }
-
- return null;
- }
-
- protected override bool IsVideoEncoder
- {
- get { return false; }
- }
-
- }
-}
diff --git a/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs
deleted file mode 100644
index 3672e4e84..000000000
--- a/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs
+++ /dev/null
@@ -1,375 +0,0 @@
-using MediaBrowser.Common.Configuration;
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.MediaEncoding;
-using MediaBrowser.Controller.Session;
-using MediaBrowser.Model.Configuration;
-using MediaBrowser.Model.Dto;
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Model.Logging;
-using MediaBrowser.Model.MediaInfo;
-using System;
-using System.Collections.Generic;
-using System.Globalization;
-using System.IO;
-using System.Text;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Model.Diagnostics;
-using MediaBrowser.Model.Dlna;
-
-namespace MediaBrowser.MediaEncoding.Encoder
-{
- public abstract class BaseEncoder
- {
- protected readonly MediaEncoder MediaEncoder;
- protected readonly ILogger Logger;
- protected readonly IServerConfigurationManager ConfigurationManager;
- protected readonly IFileSystem FileSystem;
- protected readonly IIsoManager IsoManager;
- protected readonly ILibraryManager LibraryManager;
- protected readonly ISessionManager SessionManager;
- protected readonly ISubtitleEncoder SubtitleEncoder;
- protected readonly IMediaSourceManager MediaSourceManager;
- protected IProcessFactory ProcessFactory;
-
- protected readonly CultureInfo UsCulture = new CultureInfo("en-US");
-
- protected EncodingHelper EncodingHelper;
-
- protected BaseEncoder(MediaEncoder mediaEncoder,
- ILogger logger,
- IServerConfigurationManager configurationManager,
- IFileSystem fileSystem,
- IIsoManager isoManager,
- ILibraryManager libraryManager,
- ISessionManager sessionManager,
- ISubtitleEncoder subtitleEncoder,
- IMediaSourceManager mediaSourceManager, IProcessFactory processFactory)
- {
- MediaEncoder = mediaEncoder;
- Logger = logger;
- ConfigurationManager = configurationManager;
- FileSystem = fileSystem;
- IsoManager = isoManager;
- LibraryManager = libraryManager;
- SessionManager = sessionManager;
- SubtitleEncoder = subtitleEncoder;
- MediaSourceManager = mediaSourceManager;
- ProcessFactory = processFactory;
-
- EncodingHelper = new EncodingHelper(MediaEncoder, ConfigurationManager, FileSystem, SubtitleEncoder);
- }
-
- public async Task<EncodingJob> Start(EncodingJobOptions options,
- IProgress<double> progress,
- CancellationToken cancellationToken)
- {
- var encodingJob = await new EncodingJobFactory(Logger, LibraryManager, MediaSourceManager, ConfigurationManager, MediaEncoder)
- .CreateJob(options, EncodingHelper, IsVideoEncoder, progress, cancellationToken).ConfigureAwait(false);
-
- encodingJob.OutputFilePath = GetOutputFilePath(encodingJob);
- FileSystem.CreateDirectory(FileSystem.GetDirectoryName(encodingJob.OutputFilePath));
-
- encodingJob.ReadInputAtNativeFramerate = options.ReadInputAtNativeFramerate;
-
- await AcquireResources(encodingJob, cancellationToken).ConfigureAwait(false);
-
- var commandLineArgs = GetCommandLineArguments(encodingJob);
-
- var process = ProcessFactory.Create(new ProcessOptions
- {
- CreateNoWindow = true,
- UseShellExecute = false,
-
- // Must consume both stdout and stderr or deadlocks may occur
- //RedirectStandardOutput = true,
- RedirectStandardError = true,
- RedirectStandardInput = true,
-
- FileName = MediaEncoder.EncoderPath,
- Arguments = commandLineArgs,
-
- IsHidden = true,
- ErrorDialog = false,
- EnableRaisingEvents = true
- });
-
- var workingDirectory = GetWorkingDirectory(options);
- if (!string.IsNullOrWhiteSpace(workingDirectory))
- {
- process.StartInfo.WorkingDirectory = workingDirectory;
- }
-
- OnTranscodeBeginning(encodingJob);
-
- var commandLineLogMessage = process.StartInfo.FileName + " " + process.StartInfo.Arguments;
- Logger.Info(commandLineLogMessage);
-
- var logFilePath = Path.Combine(ConfigurationManager.CommonApplicationPaths.LogDirectoryPath, "transcode-" + Guid.NewGuid() + ".txt");
- FileSystem.CreateDirectory(FileSystem.GetDirectoryName(logFilePath));
-
- // FFMpeg writes debug/error info to stderr. This is useful when debugging so let's put it in the log directory.
- encodingJob.LogFileStream = FileSystem.GetFileStream(logFilePath, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read, true);
-
- var commandLineLogMessageBytes = Encoding.UTF8.GetBytes(commandLineLogMessage + Environment.NewLine + Environment.NewLine);
- await encodingJob.LogFileStream.WriteAsync(commandLineLogMessageBytes, 0, commandLineLogMessageBytes.Length, cancellationToken).ConfigureAwait(false);
-
- process.Exited += (sender, args) => OnFfMpegProcessExited(process, encodingJob);
-
- try
- {
- process.Start();
- }
- catch (Exception ex)
- {
- Logger.ErrorException("Error starting ffmpeg", ex);
-
- OnTranscodeFailedToStart(encodingJob.OutputFilePath, encodingJob);
-
- throw;
- }
-
- cancellationToken.Register(() => Cancel(process, encodingJob));
-
- // MUST read both stdout and stderr asynchronously or a deadlock may occurr
- //process.BeginOutputReadLine();
-
- // Important - don't await the log task or we won't be able to kill ffmpeg when the user stops playback
- new JobLogger(Logger).StartStreamingLog(encodingJob, process.StandardError.BaseStream, encodingJob.LogFileStream);
-
- // Wait for the file to exist before proceeeding
- while (!FileSystem.FileExists(encodingJob.OutputFilePath) && !encodingJob.HasExited)
- {
- await Task.Delay(100, cancellationToken).ConfigureAwait(false);
- }
-
- return encodingJob;
- }
-
- private void Cancel(IProcess process, EncodingJob job)
- {
- Logger.Info("Killing ffmpeg process for {0}", job.OutputFilePath);
-
- //process.Kill();
- process.StandardInput.WriteLine("q");
-
- job.IsCancelled = true;
- }
-
- /// <summary>
- /// Processes the exited.
- /// </summary>
- /// <param name="process">The process.</param>
- /// <param name="job">The job.</param>
- private void OnFfMpegProcessExited(IProcess process, EncodingJob job)
- {
- job.HasExited = true;
-
- Logger.Debug("Disposing stream resources");
- job.Dispose();
-
- var isSuccesful = false;
-
- try
- {
- var exitCode = process.ExitCode;
- Logger.Info("FFMpeg exited with code {0}", exitCode);
-
- isSuccesful = exitCode == 0;
- }
- catch
- {
- Logger.Error("FFMpeg exited with an error.");
- }
-
- if (isSuccesful && !job.IsCancelled)
- {
- job.TaskCompletionSource.TrySetResult(true);
- }
- else if (job.IsCancelled)
- {
- try
- {
- DeleteFiles(job);
- }
- catch
- {
- }
- try
- {
- job.TaskCompletionSource.TrySetException(new OperationCanceledException());
- }
- catch
- {
- }
- }
- else
- {
- try
- {
- DeleteFiles(job);
- }
- catch
- {
- }
- try
- {
- job.TaskCompletionSource.TrySetException(new Exception("Encoding failed"));
- }
- catch
- {
- }
- }
-
- // This causes on exited to be called twice:
- //try
- //{
- // // Dispose the process
- // process.Dispose();
- //}
- //catch (Exception ex)
- //{
- // Logger.ErrorException("Error disposing ffmpeg.", ex);
- //}
- }
-
- protected virtual void DeleteFiles(EncodingJob job)
- {
- FileSystem.DeleteFile(job.OutputFilePath);
- }
-
- private void OnTranscodeBeginning(EncodingJob job)
- {
- job.ReportTranscodingProgress(null, null, null, null, null);
- }
-
- private void OnTranscodeFailedToStart(string path, EncodingJob job)
- {
- if (!string.IsNullOrWhiteSpace(job.Options.DeviceId))
- {
- SessionManager.ClearTranscodingInfo(job.Options.DeviceId);
- }
- }
-
- protected abstract bool IsVideoEncoder { get; }
-
- protected virtual string GetWorkingDirectory(EncodingJobOptions options)
- {
- return null;
- }
-
- protected EncodingOptions GetEncodingOptions()
- {
- return ConfigurationManager.GetConfiguration<EncodingOptions>("encoding");
- }
-
- protected abstract string GetCommandLineArguments(EncodingJob job);
-
- private string GetOutputFilePath(EncodingJob state)
- {
- var folder = string.IsNullOrWhiteSpace(state.Options.OutputDirectory) ?
- ConfigurationManager.ApplicationPaths.TranscodingTempPath :
- state.Options.OutputDirectory;
-
- var outputFileExtension = GetOutputFileExtension(state);
-
- var filename = state.Id + (outputFileExtension ?? string.Empty).ToLower();
- return Path.Combine(folder, filename);
- }
-
- protected virtual string GetOutputFileExtension(EncodingJob state)
- {
- if (!string.IsNullOrWhiteSpace(state.Options.OutputContainer))
- {
- return "." + state.Options.OutputContainer;
- }
-
- return null;
- }
-
- /// <summary>
- /// Gets the name of the output video codec
- /// </summary>
- /// <param name="state">The state.</param>
- /// <returns>System.String.</returns>
- protected string GetVideoDecoder(EncodingJob state)
- {
- if (string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase))
- {
- return null;
- }
-
- // Only use alternative encoders for video files.
- // When using concat with folder rips, if the mfx session fails to initialize, ffmpeg will be stuck retrying and will not exit gracefully
- // Since transcoding of folder rips is expiremental anyway, it's not worth adding additional variables such as this.
- if (state.VideoType != VideoType.VideoFile)
- {
- return null;
- }
-
- if (state.VideoStream != null && !string.IsNullOrWhiteSpace(state.VideoStream.Codec))
- {
- if (string.Equals(GetEncodingOptions().HardwareAccelerationType, "qsv", StringComparison.OrdinalIgnoreCase))
- {
- switch (state.MediaSource.VideoStream.Codec.ToLower())
- {
- case "avc":
- case "h264":
- if (MediaEncoder.SupportsDecoder("h264_qsv"))
- {
- // Seeing stalls and failures with decoding. Not worth it compared to encoding.
- return "-c:v h264_qsv ";
- }
- break;
- case "mpeg2video":
- if (MediaEncoder.SupportsDecoder("mpeg2_qsv"))
- {
- return "-c:v mpeg2_qsv ";
- }
- break;
- case "vc1":
- if (MediaEncoder.SupportsDecoder("vc1_qsv"))
- {
- return "-c:v vc1_qsv ";
- }
- break;
- }
- }
- }
-
- // leave blank so ffmpeg will decide
- return null;
- }
-
- private async Task AcquireResources(EncodingJob state, CancellationToken cancellationToken)
- {
- if (state.VideoType == VideoType.Iso && state.IsoType.HasValue && IsoManager.CanMount(state.MediaPath))
- {
- state.IsoMount = await IsoManager.Mount(state.MediaPath, cancellationToken).ConfigureAwait(false);
- }
-
- if (state.MediaSource.RequiresOpening && string.IsNullOrWhiteSpace(state.Options.LiveStreamId))
- {
- var liveStreamResponse = await MediaSourceManager.OpenLiveStream(new LiveStreamRequest
- {
- OpenToken = state.MediaSource.OpenToken
-
- }, cancellationToken).ConfigureAwait(false);
-
- EncodingHelper.AttachMediaSourceInfo(state, liveStreamResponse.MediaSource, null);
-
- if (state.IsVideoRequest)
- {
- EncodingHelper.TryStreamCopy(state);
- }
- }
-
- if (state.MediaSource.BufferMs.HasValue)
- {
- await Task.Delay(state.MediaSource.BufferMs.Value, cancellationToken).ConfigureAwait(false);
- }
- }
- }
-}
diff --git a/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs b/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs
deleted file mode 100644
index 59f3576ec..000000000
--- a/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs
+++ /dev/null
@@ -1,219 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.Globalization;
-using MediaBrowser.Model.Diagnostics;
-using MediaBrowser.Model.Logging;
-
-namespace MediaBrowser.MediaEncoding.Encoder
-{
- public class EncoderValidator
- {
- private readonly ILogger _logger;
- private readonly IProcessFactory _processFactory;
-
- public EncoderValidator(ILogger logger, IProcessFactory processFactory)
- {
- _logger = logger;
- _processFactory = processFactory;
- }
-
- public Tuple<List<string>, List<string>> Validate(string encoderPath)
- {
- _logger.Info("Validating media encoder at {0}", encoderPath);
-
- var decoders = GetDecoders(encoderPath);
- var encoders = GetEncoders(encoderPath);
-
- _logger.Info("Encoder validation complete");
-
- return new Tuple<List<string>, List<string>>(decoders, encoders);
- }
-
- public bool ValidateVersion(string encoderAppPath, bool logOutput)
- {
- string output = string.Empty;
- try
- {
- output = GetProcessOutput(encoderAppPath, "-version");
- }
- catch (Exception ex)
- {
- if (logOutput)
- {
- _logger.ErrorException("Error validating encoder", ex);
- }
- }
-
- if (string.IsNullOrWhiteSpace(output))
- {
- return false;
- }
-
- _logger.Info("ffmpeg info: {0}", output);
-
- if (output.IndexOf("Libav developers", StringComparison.OrdinalIgnoreCase) != -1)
- {
- return false;
- }
-
- output = " " + output + " ";
-
- for (var i = 2013; i <= 2015; i++)
- {
- var yearString = i.ToString(CultureInfo.InvariantCulture);
- if (output.IndexOf(" " + yearString + " ", StringComparison.OrdinalIgnoreCase) != -1)
- {
- return false;
- }
- }
-
- return true;
- }
-
- private List<string> GetDecoders(string encoderAppPath)
- {
- string output = string.Empty;
- try
- {
- output = GetProcessOutput(encoderAppPath, "-decoders");
- }
- catch (Exception )
- {
- //_logger.ErrorException("Error detecting available decoders", ex);
- }
-
- var found = new List<string>();
- var required = new[]
- {
- "mpeg2video",
- "h264_qsv",
- "hevc_qsv",
- "mpeg2_qsv",
- "vc1_qsv",
- "h264_cuvid",
- "hevc_cuvid",
- "dts",
- "ac3",
- "aac",
- "mp3",
- "h264",
- "hevc"
- };
-
- foreach (var codec in required)
- {
- var srch = " " + codec + " ";
-
- if (output.IndexOf(srch, StringComparison.OrdinalIgnoreCase) != -1)
- {
- _logger.Info("Decoder available: " + codec);
- found.Add(codec);
- }
- }
-
- return found;
- }
-
- private List<string> GetEncoders(string encoderAppPath)
- {
- string output = null;
- try
- {
- output = GetProcessOutput(encoderAppPath, "-encoders");
- }
- catch
- {
- }
-
- var found = new List<string>();
- var required = new[]
- {
- "libx264",
- "libx265",
- "mpeg4",
- "msmpeg4",
- "libvpx",
- "libvpx-vp9",
- "aac",
- "libmp3lame",
- "libopus",
- "libvorbis",
- "srt",
- "h264_nvenc",
- "hevc_nvenc",
- "h264_qsv",
- "hevc_qsv",
- "h264_omx",
- "hevc_omx",
- "h264_vaapi",
- "hevc_vaapi",
- "ac3"
- };
-
- output = output ?? string.Empty;
-
- var index = 0;
-
- foreach (var codec in required)
- {
- var srch = " " + codec + " ";
-
- if (output.IndexOf(srch, StringComparison.OrdinalIgnoreCase) != -1)
- {
- if (index < required.Length - 1)
- {
- _logger.Info("Encoder available: " + codec);
- }
-
- found.Add(codec);
- }
- index++;
- }
-
- return found;
- }
-
- private string GetProcessOutput(string path, string arguments)
- {
- var process = _processFactory.Create(new ProcessOptions
- {
- CreateNoWindow = true,
- UseShellExecute = false,
- FileName = path,
- Arguments = arguments,
- IsHidden = true,
- ErrorDialog = false,
- RedirectStandardOutput = true
- });
-
- _logger.Info("Running {0} {1}", path, arguments);
-
- using (process)
- {
- process.Start();
-
- try
- {
- return process.StandardOutput.ReadToEnd();
- }
- catch
- {
- _logger.Info("Killing process {0} {1}", path, arguments);
-
- // Hate having to do this
- try
- {
- process.Kill();
- }
- catch (Exception ex1)
- {
- _logger.ErrorException("Error killing process", ex1);
- }
-
- throw;
- }
- }
- }
- }
-}
diff --git a/MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs b/MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs
deleted file mode 100644
index d53701feb..000000000
--- a/MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs
+++ /dev/null
@@ -1,197 +0,0 @@
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.MediaEncoding;
-using MediaBrowser.Model.Dlna;
-using MediaBrowser.Model.Drawing;
-using MediaBrowser.Model.Dto;
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Model.Logging;
-using MediaBrowser.Model.MediaInfo;
-using MediaBrowser.Model.Net;
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace MediaBrowser.MediaEncoding.Encoder
-{
- public class EncodingJob : EncodingJobInfo, IDisposable
- {
- public bool HasExited { get; internal set; }
- public bool IsCancelled { get; internal set; }
-
- public Stream LogFileStream { get; set; }
- public IProgress<double> Progress { get; set; }
- public TaskCompletionSource<bool> TaskCompletionSource;
-
- public EncodingJobOptions Options
- {
- get { return (EncodingJobOptions) BaseRequest; }
- set { BaseRequest = value; }
- }
-
- public string Id { get; set; }
-
- public string MimeType { get; set; }
- public bool EstimateContentLength { get; set; }
- public TranscodeSeekInfo TranscodeSeekInfo { get; set; }
- public long? EncodingDurationTicks { get; set; }
-
- public string ItemType { get; set; }
-
- public string GetMimeType(string outputPath)
- {
- if (!string.IsNullOrEmpty(MimeType))
- {
- return MimeType;
- }
-
- return MimeTypes.GetMimeType(outputPath);
- }
-
- private readonly ILogger _logger;
- private readonly IMediaSourceManager _mediaSourceManager;
-
- public EncodingJob(ILogger logger, IMediaSourceManager mediaSourceManager) :
- base(logger, TranscodingJobType.Progressive)
- {
- _logger = logger;
- _mediaSourceManager = mediaSourceManager;
- Id = Guid.NewGuid().ToString("N");
-
- _logger = logger;
- TaskCompletionSource = new TaskCompletionSource<bool>();
- }
-
- public void Dispose()
- {
- DisposeLiveStream();
- DisposeLogStream();
- DisposeIsoMount();
- }
-
- private void DisposeLogStream()
- {
- if (LogFileStream != null)
- {
- try
- {
- LogFileStream.Dispose();
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error disposing log stream", ex);
- }
-
- LogFileStream = null;
- }
- }
-
- private async void DisposeLiveStream()
- {
- if (MediaSource.RequiresClosing && string.IsNullOrWhiteSpace(Options.LiveStreamId) && !string.IsNullOrWhiteSpace(MediaSource.LiveStreamId))
- {
- try
- {
- await _mediaSourceManager.CloseLiveStream(MediaSource.LiveStreamId).ConfigureAwait(false);
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error closing media source", ex);
- }
- }
- }
-
- public string OutputFilePath { get; set; }
-
- public string ActualOutputVideoCodec
- {
- get
- {
- var codec = OutputVideoCodec;
-
- if (string.Equals(codec, "copy", StringComparison.OrdinalIgnoreCase))
- {
- var stream = VideoStream;
-
- if (stream != null)
- {
- return stream.Codec;
- }
-
- return null;
- }
-
- return codec;
- }
- }
-
- public string ActualOutputAudioCodec
- {
- get
- {
- var codec = OutputAudioCodec;
-
- if (string.Equals(codec, "copy", StringComparison.OrdinalIgnoreCase))
- {
- var stream = AudioStream;
-
- if (stream != null)
- {
- return stream.Codec;
- }
-
- return null;
- }
-
- return codec;
- }
- }
-
- public override void ReportTranscodingProgress(TimeSpan? transcodingPosition, float? framerate, double? percentComplete, long? bytesTranscoded, int? bitRate)
- {
- var ticks = transcodingPosition.HasValue ? transcodingPosition.Value.Ticks : (long?)null;
-
- // job.Framerate = framerate;
-
- if (!percentComplete.HasValue && ticks.HasValue && RunTimeTicks.HasValue)
- {
- var pct = ticks.Value / RunTimeTicks.Value;
- percentComplete = pct * 100;
- }
-
- if (percentComplete.HasValue)
- {
- Progress.Report(percentComplete.Value);
- }
-
- // job.TranscodingPositionTicks = ticks;
- // job.BytesTranscoded = bytesTranscoded;
-
- var deviceId = Options.DeviceId;
-
- if (!string.IsNullOrWhiteSpace(deviceId))
- {
- var audioCodec = ActualOutputVideoCodec;
- var videoCodec = ActualOutputVideoCodec;
-
- // SessionManager.ReportTranscodingInfo(deviceId, new TranscodingInfo
- // {
- // Bitrate = job.TotalOutputBitrate,
- // AudioCodec = audioCodec,
- // VideoCodec = videoCodec,
- // Container = job.Options.OutputContainer,
- // Framerate = framerate,
- // CompletionPercentage = percentComplete,
- // Width = job.OutputWidth,
- // Height = job.OutputHeight,
- // AudioChannels = job.OutputAudioChannels,
- // IsAudioDirect = string.Equals(job.OutputAudioCodec, "copy", StringComparison.OrdinalIgnoreCase),
- // IsVideoDirect = string.Equals(job.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase)
- // });
- }
- }
- }
-}
diff --git a/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs b/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs
deleted file mode 100644
index 50d3d254a..000000000
--- a/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs
+++ /dev/null
@@ -1,305 +0,0 @@
-using MediaBrowser.Common.Configuration;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.MediaEncoding;
-using MediaBrowser.Model.Configuration;
-using MediaBrowser.Model.Dlna;
-using MediaBrowser.Model.Dto;
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Logging;
-using MediaBrowser.Model.MediaInfo;
-using System;
-using System.Collections.Generic;
-using System.Globalization;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace MediaBrowser.MediaEncoding.Encoder
-{
- public class EncodingJobFactory
- {
- private readonly ILogger _logger;
- private readonly ILibraryManager _libraryManager;
- private readonly IMediaSourceManager _mediaSourceManager;
- private readonly IConfigurationManager _config;
- private readonly IMediaEncoder _mediaEncoder;
-
- protected static readonly CultureInfo UsCulture = new CultureInfo("en-US");
-
- public EncodingJobFactory(ILogger logger, ILibraryManager libraryManager, IMediaSourceManager mediaSourceManager, IConfigurationManager config, IMediaEncoder mediaEncoder)
- {
- _logger = logger;
- _libraryManager = libraryManager;
- _mediaSourceManager = mediaSourceManager;
- _config = config;
- _mediaEncoder = mediaEncoder;
- }
-
- public async Task<EncodingJob> CreateJob(EncodingJobOptions options, EncodingHelper encodingHelper, bool isVideoRequest, IProgress<double> progress, CancellationToken cancellationToken)
- {
- var request = options;
-
- if (string.IsNullOrEmpty(request.AudioCodec))
- {
- request.AudioCodec = InferAudioCodec(request.OutputContainer);
- }
-
- var state = new EncodingJob(_logger, _mediaSourceManager)
- {
- Options = options,
- IsVideoRequest = isVideoRequest,
- Progress = progress
- };
-
- if (!string.IsNullOrWhiteSpace(request.VideoCodec))
- {
- state.SupportedVideoCodecs = request.VideoCodec.Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).ToList();
- request.VideoCodec = state.SupportedVideoCodecs.FirstOrDefault();
- }
-
- if (!string.IsNullOrWhiteSpace(request.AudioCodec))
- {
- state.SupportedAudioCodecs = request.AudioCodec.Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).ToList();
- request.AudioCodec = state.SupportedAudioCodecs.FirstOrDefault();
- }
-
- if (!string.IsNullOrWhiteSpace(request.SubtitleCodec))
- {
- state.SupportedSubtitleCodecs = request.SubtitleCodec.Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).ToList();
- request.SubtitleCodec = state.SupportedSubtitleCodecs.FirstOrDefault(i => _mediaEncoder.CanEncodeToSubtitleCodec(i))
- ?? state.SupportedSubtitleCodecs.FirstOrDefault();
- }
-
- var item = _libraryManager.GetItemById(request.ItemId);
- state.ItemType = item.GetType().Name;
-
- state.IsInputVideo = string.Equals(item.MediaType, MediaType.Video, StringComparison.OrdinalIgnoreCase);
-
- var primaryImage = item.GetImageInfo(ImageType.Primary, 0) ??
- item.Parents.Select(i => i.GetImageInfo(ImageType.Primary, 0)).FirstOrDefault(i => i != null);
-
- if (primaryImage != null)
- {
- state.AlbumCoverPath = primaryImage.Path;
- }
-
- var mediaSources = await _mediaSourceManager.GetPlayackMediaSources(request.ItemId, null, false, new[] { MediaType.Audio, MediaType.Video }, cancellationToken).ConfigureAwait(false);
-
- var mediaSource = string.IsNullOrEmpty(request.MediaSourceId)
- ? mediaSources.First()
- : mediaSources.First(i => string.Equals(i.Id, request.MediaSourceId));
-
- var videoRequest = state.Options;
-
- encodingHelper.AttachMediaSourceInfo(state, mediaSource, null);
-
- //var container = Path.GetExtension(state.RequestedUrl);
-
- //if (string.IsNullOrEmpty(container))
- //{
- // container = request.Static ?
- // state.InputContainer :
- // (Path.GetExtension(GetOutputFilePath(state)) ?? string.Empty).TrimStart('.');
- //}
-
- //state.OutputContainer = (container ?? string.Empty).TrimStart('.');
-
- state.OutputAudioBitrate = encodingHelper.GetAudioBitrateParam(state.Options, state.AudioStream);
-
- state.OutputAudioCodec = state.Options.AudioCodec;
-
- state.OutputAudioChannels = encodingHelper.GetNumAudioChannelsParam(state.Options, state.AudioStream, state.OutputAudioCodec);
-
- if (videoRequest != null)
- {
- state.OutputVideoCodec = state.Options.VideoCodec;
- state.OutputVideoBitrate = encodingHelper.GetVideoBitrateParamValue(state.Options, state.VideoStream, state.OutputVideoCodec);
-
- if (state.OutputVideoBitrate.HasValue)
- {
- var resolution = ResolutionNormalizer.Normalize(
- state.VideoStream == null ? (int?)null : state.VideoStream.BitRate,
- state.OutputVideoBitrate.Value,
- state.VideoStream == null ? null : state.VideoStream.Codec,
- state.OutputVideoCodec,
- videoRequest.MaxWidth,
- videoRequest.MaxHeight);
-
- videoRequest.MaxWidth = resolution.MaxWidth;
- videoRequest.MaxHeight = resolution.MaxHeight;
- }
- }
-
- ApplyDeviceProfileSettings(state);
-
- if (videoRequest != null)
- {
- encodingHelper.TryStreamCopy(state);
- }
-
- //state.OutputFilePath = GetOutputFilePath(state);
-
- return state;
- }
-
- protected EncodingOptions GetEncodingOptions()
- {
- return _config.GetConfiguration<EncodingOptions>("encoding");
- }
-
- /// <summary>
- /// Infers the video codec.
- /// </summary>
- /// <param name="container">The container.</param>
- /// <returns>System.Nullable{VideoCodecs}.</returns>
- private static string InferVideoCodec(string container)
- {
- var ext = "." + (container ?? string.Empty);
-
- if (string.Equals(ext, ".asf", StringComparison.OrdinalIgnoreCase))
- {
- return "wmv";
- }
- if (string.Equals(ext, ".webm", StringComparison.OrdinalIgnoreCase))
- {
- return "vpx";
- }
- if (string.Equals(ext, ".ogg", StringComparison.OrdinalIgnoreCase) || string.Equals(ext, ".ogv", StringComparison.OrdinalIgnoreCase))
- {
- return "theora";
- }
- if (string.Equals(ext, ".m3u8", StringComparison.OrdinalIgnoreCase) || string.Equals(ext, ".ts", StringComparison.OrdinalIgnoreCase))
- {
- return "h264";
- }
-
- return "copy";
- }
-
- private string InferAudioCodec(string container)
- {
- var ext = "." + (container ?? string.Empty);
-
- if (string.Equals(ext, ".mp3", StringComparison.OrdinalIgnoreCase))
- {
- return "mp3";
- }
- if (string.Equals(ext, ".aac", StringComparison.OrdinalIgnoreCase))
- {
- return "aac";
- }
- if (string.Equals(ext, ".wma", StringComparison.OrdinalIgnoreCase))
- {
- return "wma";
- }
- if (string.Equals(ext, ".ogg", StringComparison.OrdinalIgnoreCase))
- {
- return "vorbis";
- }
- if (string.Equals(ext, ".oga", StringComparison.OrdinalIgnoreCase))
- {
- return "vorbis";
- }
- if (string.Equals(ext, ".ogv", StringComparison.OrdinalIgnoreCase))
- {
- return "vorbis";
- }
- if (string.Equals(ext, ".webm", StringComparison.OrdinalIgnoreCase))
- {
- return "vorbis";
- }
- if (string.Equals(ext, ".webma", StringComparison.OrdinalIgnoreCase))
- {
- return "vorbis";
- }
-
- return "copy";
- }
-
- /// <summary>
- /// Determines whether the specified stream is H264.
- /// </summary>
- /// <param name="stream">The stream.</param>
- /// <returns><c>true</c> if the specified stream is H264; otherwise, <c>false</c>.</returns>
- protected bool IsH264(MediaStream stream)
- {
- var codec = stream.Codec ?? string.Empty;
-
- return codec.IndexOf("264", StringComparison.OrdinalIgnoreCase) != -1 ||
- codec.IndexOf("avc", StringComparison.OrdinalIgnoreCase) != -1;
- }
-
- private static int GetVideoProfileScore(string profile)
- {
- var list = new List<string>
- {
- "Constrained Baseline",
- "Baseline",
- "Extended",
- "Main",
- "High",
- "Progressive High",
- "Constrained High"
- };
-
- return Array.FindIndex(list.ToArray(), t => string.Equals(t, profile, StringComparison.OrdinalIgnoreCase));
- }
-
- private void ApplyDeviceProfileSettings(EncodingJob state)
- {
- var profile = state.Options.DeviceProfile;
-
- if (profile == null)
- {
- // Don't use settings from the default profile.
- // Only use a specific profile if it was requested.
- return;
- }
-
- var audioCodec = state.ActualOutputAudioCodec;
-
- var videoCodec = state.ActualOutputVideoCodec;
- var outputContainer = state.Options.OutputContainer;
-
- var mediaProfile = state.IsVideoRequest ?
- profile.GetAudioMediaProfile(outputContainer, audioCodec, state.OutputAudioChannels, state.OutputAudioBitrate, state.OutputAudioSampleRate, state.OutputAudioBitDepth) :
- profile.GetVideoMediaProfile(outputContainer,
- audioCodec,
- videoCodec,
- state.OutputWidth,
- state.OutputHeight,
- state.TargetVideoBitDepth,
- state.OutputVideoBitrate,
- state.TargetVideoProfile,
- state.TargetVideoLevel,
- state.TargetFramerate,
- state.TargetPacketLength,
- state.TargetTimestamp,
- state.IsTargetAnamorphic,
- state.IsTargetInterlaced,
- state.TargetRefFrames,
- state.TargetVideoStreamCount,
- state.TargetAudioStreamCount,
- state.TargetVideoCodecTag,
- state.IsTargetAVC);
-
- if (mediaProfile != null)
- {
- state.MimeType = mediaProfile.MimeType;
- }
-
- var transcodingProfile = state.IsVideoRequest ?
- profile.GetAudioTranscodingProfile(outputContainer, audioCodec) :
- profile.GetVideoTranscodingProfile(outputContainer, audioCodec, videoCodec);
-
- if (transcodingProfile != null)
- {
- state.EstimateContentLength = transcodingProfile.EstimateContentLength;
- state.EnableMpegtsM2TsMode = transcodingProfile.EnableMpegtsM2TsMode;
- state.TranscodeSeekInfo = transcodingProfile.TranscodeSeekInfo;
-
- state.Options.CopyTimestamps = transcodingProfile.CopyTimestamps;
- }
- }
- }
-}
diff --git a/MediaBrowser.MediaEncoding/Encoder/EncodingUtils.cs b/MediaBrowser.MediaEncoding/Encoder/EncodingUtils.cs
deleted file mode 100644
index dc3cb5f5e..000000000
--- a/MediaBrowser.MediaEncoding/Encoder/EncodingUtils.cs
+++ /dev/null
@@ -1,70 +0,0 @@
-using MediaBrowser.Model.MediaInfo;
-using System.Collections.Generic;
-using System.Linq;
-
-namespace MediaBrowser.MediaEncoding.Encoder
-{
- public static class EncodingUtils
- {
- public static string GetInputArgument(List<string> inputFiles, MediaProtocol protocol)
- {
- if (protocol != MediaProtocol.File)
- {
- var url = inputFiles.First();
-
- return string.Format("\"{0}\"", url);
- }
-
- return GetConcatInputArgument(inputFiles);
- }
-
- /// <summary>
- /// Gets the concat input argument.
- /// </summary>
- /// <param name="inputFiles">The input files.</param>
- /// <returns>System.String.</returns>
- private static string GetConcatInputArgument(IReadOnlyList<string> inputFiles)
- {
- // Get all streams
- // If there's more than one we'll need to use the concat command
- if (inputFiles.Count > 1)
- {
- var files = string.Join("|", inputFiles.Select(NormalizePath).ToArray());
-
- return string.Format("concat:\"{0}\"", files);
- }
-
- // Determine the input path for video files
- return GetFileInputArgument(inputFiles[0]);
- }
-
- /// <summary>
- /// Gets the file input argument.
- /// </summary>
- /// <param name="path">The path.</param>
- /// <returns>System.String.</returns>
- private static string GetFileInputArgument(string path)
- {
- if (path.IndexOf("://") != -1)
- {
- return string.Format("\"{0}\"", path);
- }
-
- // Quotes are valid path characters in linux and they need to be escaped here with a leading \
- path = NormalizePath(path);
-
- return string.Format("file:\"{0}\"", path);
- }
-
- /// <summary>
- /// Normalizes the path.
- /// </summary>
- /// <param name="path">The path.</param>
- /// <returns>System.String.</returns>
- private static string NormalizePath(string path)
- {
- // Quotes are valid path characters in linux and they need to be escaped here with a leading \
- return path.Replace("\"", "\\\"");
- }
- }
-}
diff --git a/MediaBrowser.MediaEncoding/Encoder/FontConfigLoader.cs b/MediaBrowser.MediaEncoding/Encoder/FontConfigLoader.cs
deleted file mode 100644
index e21292cbd..000000000
--- a/MediaBrowser.MediaEncoding/Encoder/FontConfigLoader.cs
+++ /dev/null
@@ -1,182 +0,0 @@
-using System;
-using System.IO;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Common.Configuration;
-
-using MediaBrowser.Common.Net;
-using MediaBrowser.Common.Progress;
-using MediaBrowser.Controller.IO;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Model.Logging;
-using MediaBrowser.Model.Net;
-
-namespace MediaBrowser.MediaEncoding.Encoder
-{
- public class FontConfigLoader
- {
- private readonly IHttpClient _httpClient;
- private readonly IApplicationPaths _appPaths;
- private readonly ILogger _logger;
- private readonly IZipClient _zipClient;
- private readonly IFileSystem _fileSystem;
-
- private readonly string[] _fontUrls =
- {
- "https://github.com/MediaBrowser/MediaBrowser.Resources/raw/master/ffmpeg/ARIALUNI.7z"
- };
-
- public FontConfigLoader(IHttpClient httpClient, IApplicationPaths appPaths, ILogger logger, IZipClient zipClient, IFileSystem fileSystem)
- {
- _httpClient = httpClient;
- _appPaths = appPaths;
- _logger = logger;
- _zipClient = zipClient;
- _fileSystem = fileSystem;
- }
-
- /// <summary>
- /// Extracts the fonts.
- /// </summary>
- /// <param name="targetPath">The target path.</param>
- /// <returns>Task.</returns>
- public async Task DownloadFonts(string targetPath)
- {
- try
- {
- var fontsDirectory = Path.Combine(targetPath, "fonts");
-
- _fileSystem.CreateDirectory(fontsDirectory);
-
- const string fontFilename = "ARIALUNI.TTF";
-
- var fontFile = Path.Combine(fontsDirectory, fontFilename);
-
- if (_fileSystem.FileExists(fontFile))
- {
- await WriteFontConfigFile(fontsDirectory).ConfigureAwait(false);
- }
- else
- {
- // Kick this off, but no need to wait on it
- var task = Task.Run(async () =>
- {
- await DownloadFontFile(fontsDirectory, fontFilename, new SimpleProgress<double>()).ConfigureAwait(false);
-
- await WriteFontConfigFile(fontsDirectory).ConfigureAwait(false);
- });
- }
- }
- catch (HttpException ex)
- {
- // Don't let the server crash because of this
- _logger.ErrorException("Error downloading ffmpeg font files", ex);
- }
- catch (Exception ex)
- {
- // Don't let the server crash because of this
- _logger.ErrorException("Error writing ffmpeg font files", ex);
- }
- }
-
- /// <summary>
- /// Downloads the font file.
- /// </summary>
- /// <param name="fontsDirectory">The fonts directory.</param>
- /// <param name="fontFilename">The font filename.</param>
- /// <returns>Task.</returns>
- private async Task DownloadFontFile(string fontsDirectory, string fontFilename, IProgress<double> progress)
- {
- var existingFile = _fileSystem
- .GetFilePaths(_appPaths.ProgramDataPath, true)
- .FirstOrDefault(i => string.Equals(fontFilename, Path.GetFileName(i), StringComparison.OrdinalIgnoreCase));
-
- if (existingFile != null)
- {
- try
- {
- _fileSystem.CopyFile(existingFile, Path.Combine(fontsDirectory, fontFilename), true);
- return;
- }
- catch (IOException ex)
- {
- // Log this, but don't let it fail the operation
- _logger.ErrorException("Error copying file", ex);
- }
- }
-
- string tempFile = null;
-
- foreach (var url in _fontUrls)
- {
- progress.Report(0);
-
- try
- {
- tempFile = await _httpClient.GetTempFile(new HttpRequestOptions
- {
- Url = url,
- Progress = progress
-
- }).ConfigureAwait(false);
-
- break;
- }
- catch (Exception ex)
- {
- // The core can function without the font file, so handle this
- _logger.ErrorException("Failed to download ffmpeg font file from {0}", ex, url);
- }
- }
-
- if (string.IsNullOrEmpty(tempFile))
- {
- return;
- }
-
- Extract7zArchive(tempFile, fontsDirectory);
-
- try
- {
- _fileSystem.DeleteFile(tempFile);
- }
- catch (IOException ex)
- {
- // Log this, but don't let it fail the operation
- _logger.ErrorException("Error deleting temp file {0}", ex, tempFile);
- }
- }
- private void Extract7zArchive(string archivePath, string targetPath)
- {
- _logger.Info("Extracting {0} to {1}", archivePath, targetPath);
-
- _zipClient.ExtractAllFrom7z(archivePath, targetPath, true);
- }
-
- /// <summary>
- /// Writes the font config file.
- /// </summary>
- /// <param name="fontsDirectory">The fonts directory.</param>
- /// <returns>Task.</returns>
- private async Task WriteFontConfigFile(string fontsDirectory)
- {
- const string fontConfigFilename = "fonts.conf";
- var fontConfigFile = Path.Combine(fontsDirectory, fontConfigFilename);
-
- if (!_fileSystem.FileExists(fontConfigFile))
- {
- var contents = string.Format("<?xml version=\"1.0\"?><fontconfig><dir>{0}</dir><alias><family>Arial</family><prefer>Arial Unicode MS</prefer></alias></fontconfig>", fontsDirectory);
-
- var bytes = Encoding.UTF8.GetBytes(contents);
-
- using (var fileStream = _fileSystem.GetFileStream(fontConfigFile, FileOpenMode.Create, FileAccessMode.Write,
- FileShareMode.Read, true))
- {
- await fileStream.WriteAsync(bytes, 0, bytes.Length);
- }
- }
- }
- }
-}
diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
deleted file mode 100644
index f416ea417..000000000
--- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
+++ /dev/null
@@ -1,1089 +0,0 @@
-using MediaBrowser.Controller.Channels;
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.LiveTv;
-using MediaBrowser.Controller.MediaEncoding;
-using MediaBrowser.Controller.Session;
-using MediaBrowser.MediaEncoding.Probing;
-using MediaBrowser.Model.Dlna;
-using MediaBrowser.Model.Dto;
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Model.Logging;
-using MediaBrowser.Model.MediaInfo;
-using MediaBrowser.Model.Serialization;
-using System;
-using System.Collections.Generic;
-using System.Globalization;
-using System.IO;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Model.Configuration;
-using MediaBrowser.Common.Configuration;
-using MediaBrowser.Common.Extensions;
-using MediaBrowser.Common.Net;
-using MediaBrowser.Model.Diagnostics;
-using MediaBrowser.Model.System;
-
-namespace MediaBrowser.MediaEncoding.Encoder
-{
- /// <summary>
- /// Class MediaEncoder
- /// </summary>
- public class MediaEncoder : IMediaEncoder, IDisposable
- {
- /// <summary>
- /// The _logger
- /// </summary>
- private readonly ILogger _logger;
-
- /// <summary>
- /// Gets the json serializer.
- /// </summary>
- /// <value>The json serializer.</value>
- private readonly IJsonSerializer _jsonSerializer;
-
- /// <summary>
- /// The _thumbnail resource pool
- /// </summary>
- private readonly SemaphoreSlim _thumbnailResourcePool = new SemaphoreSlim(1, 1);
-
- public string FFMpegPath { get; private set; }
-
- public string FFProbePath { get; private set; }
-
- protected readonly IServerConfigurationManager ConfigurationManager;
- protected readonly IFileSystem FileSystem;
- protected readonly ILiveTvManager LiveTvManager;
- protected readonly IIsoManager IsoManager;
- protected readonly ILibraryManager LibraryManager;
- protected readonly IChannelManager ChannelManager;
- protected readonly ISessionManager SessionManager;
- protected readonly Func<ISubtitleEncoder> SubtitleEncoder;
- protected readonly Func<IMediaSourceManager> MediaSourceManager;
- private readonly IHttpClient _httpClient;
- private readonly IZipClient _zipClient;
- private readonly IProcessFactory _processFactory;
- private readonly IMemoryStreamFactory _memoryStreamProvider;
-
- private readonly List<ProcessWrapper> _runningProcesses = new List<ProcessWrapper>();
- private readonly bool _hasExternalEncoder;
- private readonly string _originalFFMpegPath;
- private readonly string _originalFFProbePath;
- private readonly int DefaultImageExtractionTimeoutMs;
- private readonly bool EnableEncoderFontFile;
-
- private readonly IEnvironmentInfo _environmentInfo;
-
- public MediaEncoder(ILogger logger, IJsonSerializer jsonSerializer, string ffMpegPath, string ffProbePath, bool hasExternalEncoder, IServerConfigurationManager configurationManager, IFileSystem fileSystem, ILiveTvManager liveTvManager, IIsoManager isoManager, ILibraryManager libraryManager, IChannelManager channelManager, ISessionManager sessionManager, Func<ISubtitleEncoder> subtitleEncoder, Func<IMediaSourceManager> mediaSourceManager, IHttpClient httpClient, IZipClient zipClient, IMemoryStreamFactory memoryStreamProvider, IProcessFactory processFactory,
- int defaultImageExtractionTimeoutMs,
- bool enableEncoderFontFile, IEnvironmentInfo environmentInfo)
- {
- _logger = logger;
- _jsonSerializer = jsonSerializer;
- ConfigurationManager = configurationManager;
- FileSystem = fileSystem;
- LiveTvManager = liveTvManager;
- IsoManager = isoManager;
- LibraryManager = libraryManager;
- ChannelManager = channelManager;
- SessionManager = sessionManager;
- SubtitleEncoder = subtitleEncoder;
- MediaSourceManager = mediaSourceManager;
- _httpClient = httpClient;
- _zipClient = zipClient;
- _memoryStreamProvider = memoryStreamProvider;
- _processFactory = processFactory;
- DefaultImageExtractionTimeoutMs = defaultImageExtractionTimeoutMs;
- EnableEncoderFontFile = enableEncoderFontFile;
- _environmentInfo = environmentInfo;
- FFProbePath = ffProbePath;
- FFMpegPath = ffMpegPath;
- _originalFFProbePath = ffProbePath;
- _originalFFMpegPath = ffMpegPath;
-
- _hasExternalEncoder = hasExternalEncoder;
-
- SetEnvironmentVariable();
- }
-
- private readonly object _logLock = new object();
- public void SetLogFilename(string name)
- {
- lock (_logLock)
- {
- try
- {
- _environmentInfo.SetProcessEnvironmentVariable("FFREPORT", "file=" + name + ":level=32");
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error setting FFREPORT environment variable", ex);
- }
- }
- }
-
- public void ClearLogFilename()
- {
- lock (_logLock)
- {
- try
- {
- _environmentInfo.SetProcessEnvironmentVariable("FFREPORT", null);
- }
- catch (Exception ex)
- {
- //_logger.ErrorException("Error setting FFREPORT environment variable", ex);
- }
- }
- }
-
- private void SetEnvironmentVariable()
- {
- try
- {
- //_environmentInfo.SetProcessEnvironmentVariable("FFREPORT", "file=program-YYYYMMDD-HHMMSS.txt:level=32");
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error setting FFREPORT environment variable", ex);
- }
- try
- {
- //_environmentInfo.SetUserEnvironmentVariable("FFREPORT", "file=program-YYYYMMDD-HHMMSS.txt:level=32");
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error setting FFREPORT environment variable", ex);
- }
- }
-
- public string EncoderLocationType
- {
- get
- {
- if (_hasExternalEncoder)
- {
- return "External";
- }
-
- if (string.IsNullOrWhiteSpace(FFMpegPath))
- {
- return null;
- }
-
- if (IsSystemInstalledPath(FFMpegPath))
- {
- return "System";
- }
-
- return "Custom";
- }
- }
-
- private bool IsSystemInstalledPath(string path)
- {
- if (path.IndexOf("/", StringComparison.Ordinal) == -1 && path.IndexOf("\\", StringComparison.Ordinal) == -1)
- {
- return true;
- }
-
- return false;
- }
-
- public async Task Init()
- {
- InitPaths();
-
- if (!string.IsNullOrWhiteSpace(FFMpegPath))
- {
- var result = new EncoderValidator(_logger, _processFactory).Validate(FFMpegPath);
-
- SetAvailableDecoders(result.Item1);
- SetAvailableEncoders(result.Item2);
-
- if (EnableEncoderFontFile)
- {
- var directory = FileSystem.GetDirectoryName(FFMpegPath);
-
- if (!string.IsNullOrWhiteSpace(directory) && FileSystem.ContainsSubPath(ConfigurationManager.ApplicationPaths.ProgramDataPath, directory))
- {
- await new FontConfigLoader(_httpClient, ConfigurationManager.ApplicationPaths, _logger, _zipClient, FileSystem).DownloadFonts(directory).ConfigureAwait(false);
- }
- }
- }
- }
-
- private void InitPaths()
- {
- ConfigureEncoderPaths();
-
- if (_hasExternalEncoder)
- {
- LogPaths();
- return;
- }
-
- // If the path was passed in, save it into config now.
- var encodingOptions = GetEncodingOptions();
- var appPath = encodingOptions.EncoderAppPath;
-
- var valueToSave = FFMpegPath;
-
- if (!string.IsNullOrWhiteSpace(valueToSave))
- {
- // if using system variable, don't save this.
- if (IsSystemInstalledPath(valueToSave) || _hasExternalEncoder)
- {
- valueToSave = null;
- }
- }
-
- if (!string.Equals(valueToSave, appPath, StringComparison.Ordinal))
- {
- encodingOptions.EncoderAppPath = valueToSave;
- ConfigurationManager.SaveConfiguration("encoding", encodingOptions);
- }
- }
-
- public void UpdateEncoderPath(string path, string pathType)
- {
- if (_hasExternalEncoder)
- {
- return;
- }
-
- _logger.Info("Attempting to update encoder path to {0}. pathType: {1}", path ?? string.Empty, pathType ?? string.Empty);
-
- Tuple<string, string> newPaths;
-
- if (string.Equals(pathType, "system", StringComparison.OrdinalIgnoreCase))
- {
- path = "ffmpeg";
-
- newPaths = TestForInstalledVersions();
- }
- else if (string.Equals(pathType, "custom", StringComparison.OrdinalIgnoreCase))
- {
- if (string.IsNullOrWhiteSpace(path))
- {
- throw new ArgumentNullException("path");
- }
-
- if (!FileSystem.FileExists(path) && !FileSystem.DirectoryExists(path))
- {
- throw new ResourceNotFoundException();
- }
- newPaths = GetEncoderPaths(path);
- }
- else
- {
- throw new ArgumentException("Unexpected pathType value");
- }
-
- if (string.IsNullOrWhiteSpace(newPaths.Item1))
- {
- throw new ResourceNotFoundException("ffmpeg not found");
- }
- if (string.IsNullOrWhiteSpace(newPaths.Item2))
- {
- throw new ResourceNotFoundException("ffprobe not found");
- }
-
- path = newPaths.Item1;
-
- if (!ValidateVersion(path, true))
- {
- throw new ResourceNotFoundException("ffmpeg version 3.0 or greater is required.");
- }
-
- var config = GetEncodingOptions();
- config.EncoderAppPath = path;
- ConfigurationManager.SaveConfiguration("encoding", config);
-
- Init();
- }
-
- private bool ValidateVersion(string path, bool logOutput)
- {
- return new EncoderValidator(_logger, _processFactory).ValidateVersion(path, logOutput);
- }
-
- private void ConfigureEncoderPaths()
- {
- if (_hasExternalEncoder)
- {
- return;
- }
-
- var appPath = GetEncodingOptions().EncoderAppPath;
-
- if (string.IsNullOrWhiteSpace(appPath))
- {
- appPath = Path.Combine(ConfigurationManager.ApplicationPaths.ProgramDataPath, "ffmpeg");
- }
-
- var newPaths = GetEncoderPaths(appPath);
- if (string.IsNullOrWhiteSpace(newPaths.Item1) || string.IsNullOrWhiteSpace(newPaths.Item2) || IsSystemInstalledPath(appPath))
- {
- newPaths = TestForInstalledVersions();
- }
-
- if (!string.IsNullOrWhiteSpace(newPaths.Item1) && !string.IsNullOrWhiteSpace(newPaths.Item2))
- {
- FFMpegPath = newPaths.Item1;
- FFProbePath = newPaths.Item2;
- }
-
- LogPaths();
- }
-
- private Tuple<string, string> GetEncoderPaths(string configuredPath)
- {
- var appPath = configuredPath;
-
- if (!string.IsNullOrWhiteSpace(appPath))
- {
- if (FileSystem.DirectoryExists(appPath))
- {
- return GetPathsFromDirectory(appPath);
- }
-
- if (FileSystem.FileExists(appPath))
- {
- return new Tuple<string, string>(appPath, GetProbePathFromEncoderPath(appPath));
- }
- }
-
- return new Tuple<string, string>(null, null);
- }
-
- private Tuple<string, string> TestForInstalledVersions()
- {
- string encoderPath = null;
- string probePath = null;
-
- if (_hasExternalEncoder && ValidateVersion(_originalFFMpegPath, true))
- {
- encoderPath = _originalFFMpegPath;
- probePath = _originalFFProbePath;
- }
-
- if (string.IsNullOrWhiteSpace(encoderPath))
- {
- if (ValidateVersion("ffmpeg", true) && ValidateVersion("ffprobe", false))
- {
- encoderPath = "ffmpeg";
- probePath = "ffprobe";
- }
- }
-
- return new Tuple<string, string>(encoderPath, probePath);
- }
-
- private Tuple<string, string> GetPathsFromDirectory(string path)
- {
- // Since we can't predict the file extension, first try directly within the folder
- // If that doesn't pan out, then do a recursive search
- var files = FileSystem.GetFilePaths(path);
-
- var excludeExtensions = new[] { ".c" };
-
- var ffmpegPath = files.FirstOrDefault(i => string.Equals(Path.GetFileNameWithoutExtension(i), "ffmpeg", StringComparison.OrdinalIgnoreCase) && !excludeExtensions.Contains(Path.GetExtension(i) ?? string.Empty));
- var ffprobePath = files.FirstOrDefault(i => string.Equals(Path.GetFileNameWithoutExtension(i), "ffprobe", StringComparison.OrdinalIgnoreCase) && !excludeExtensions.Contains(Path.GetExtension(i) ?? string.Empty));
-
- if (string.IsNullOrWhiteSpace(ffmpegPath) || !FileSystem.FileExists(ffmpegPath))
- {
- files = FileSystem.GetFilePaths(path, true);
-
- ffmpegPath = files.FirstOrDefault(i => string.Equals(Path.GetFileNameWithoutExtension(i), "ffmpeg", StringComparison.OrdinalIgnoreCase) && !excludeExtensions.Contains(Path.GetExtension(i) ?? string.Empty));
-
- if (!string.IsNullOrWhiteSpace(ffmpegPath))
- {
- ffprobePath = GetProbePathFromEncoderPath(ffmpegPath);
- }
- }
-
- return new Tuple<string, string>(ffmpegPath, ffprobePath);
- }
-
- private string GetProbePathFromEncoderPath(string appPath)
- {
- return FileSystem.GetFilePaths(FileSystem.GetDirectoryName(appPath))
- .FirstOrDefault(i => string.Equals(Path.GetFileNameWithoutExtension(i), "ffprobe", StringComparison.OrdinalIgnoreCase));
- }
-
- private void LogPaths()
- {
- _logger.Info("FFMpeg: {0}", FFMpegPath ?? "not found");
- _logger.Info("FFProbe: {0}", FFProbePath ?? "not found");
- }
-
- private EncodingOptions GetEncodingOptions()
- {
- return ConfigurationManager.GetConfiguration<EncodingOptions>("encoding");
- }
-
- private List<string> _encoders = new List<string>();
- public void SetAvailableEncoders(List<string> list)
- {
- _encoders = list.ToList();
- //_logger.Info("Supported encoders: {0}", string.Join(",", list.ToArray()));
- }
-
- private List<string> _decoders = new List<string>();
- public void SetAvailableDecoders(List<string> list)
- {
- _decoders = list.ToList();
- //_logger.Info("Supported decoders: {0}", string.Join(",", list.ToArray()));
- }
-
- public bool SupportsEncoder(string encoder)
- {
- return _encoders.Contains(encoder, StringComparer.OrdinalIgnoreCase);
- }
-
- public bool SupportsDecoder(string decoder)
- {
- return _decoders.Contains(decoder, StringComparer.OrdinalIgnoreCase);
- }
-
- public bool CanEncodeToAudioCodec(string codec)
- {
- if (string.Equals(codec, "opus", StringComparison.OrdinalIgnoreCase))
- {
- codec = "libopus";
- }
- else if (string.Equals(codec, "mp3", StringComparison.OrdinalIgnoreCase))
- {
- codec = "libmp3lame";
- }
-
- return SupportsEncoder(codec);
- }
-
- public bool CanEncodeToSubtitleCodec(string codec)
- {
- // TODO
- return true;
- }
-
- /// <summary>
- /// Gets the encoder path.
- /// </summary>
- /// <value>The encoder path.</value>
- public string EncoderPath
- {
- get { return FFMpegPath; }
- }
-
- /// <summary>
- /// Gets the media info.
- /// </summary>
- /// <param name="request">The request.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- public Task<MediaInfo> GetMediaInfo(MediaInfoRequest request, CancellationToken cancellationToken)
- {
- var extractChapters = request.MediaType == DlnaProfileType.Video && request.ExtractChapters;
-
- var inputFiles = MediaEncoderHelpers.GetInputArgument(FileSystem, request.InputPath, request.Protocol, request.MountedIso, request.PlayableStreamFileNames);
-
- var probeSize = EncodingHelper.GetProbeSizeArgument(inputFiles.Length);
- string analyzeDuration;
-
- if (request.AnalyzeDurationMs > 0)
- {
- analyzeDuration = "-analyzeduration " +
- (request.AnalyzeDurationMs * 1000).ToString(CultureInfo.InvariantCulture);
- }
- else
- {
- analyzeDuration = EncodingHelper.GetAnalyzeDurationArgument(inputFiles.Length);
- }
-
- probeSize = probeSize + " " + analyzeDuration;
- probeSize = probeSize.Trim();
-
- var forceEnableLogging = request.Protocol != MediaProtocol.File;
-
- return GetMediaInfoInternal(GetInputArgument(inputFiles, request.Protocol), request.InputPath, request.Protocol, extractChapters,
- probeSize, request.MediaType == DlnaProfileType.Audio, request.VideoType, forceEnableLogging, cancellationToken);
- }
-
- /// <summary>
- /// Gets the input argument.
- /// </summary>
- /// <param name="inputFiles">The input files.</param>
- /// <param name="protocol">The protocol.</param>
- /// <returns>System.String.</returns>
- /// <exception cref="System.ArgumentException">Unrecognized InputType</exception>
- public string GetInputArgument(string[] inputFiles, MediaProtocol protocol)
- {
- return EncodingUtils.GetInputArgument(inputFiles.ToList(), protocol);
- }
-
- /// <summary>
- /// Gets the media info internal.
- /// </summary>
- /// <returns>Task{MediaInfoResult}.</returns>
- private async Task<MediaInfo> GetMediaInfoInternal(string inputPath,
- string primaryPath,
- MediaProtocol protocol,
- bool extractChapters,
- string probeSizeArgument,
- bool isAudio,
- VideoType videoType,
- bool forceEnableLogging,
- CancellationToken cancellationToken)
- {
- var args = extractChapters
- ? "{0} -i {1} -threads 0 -v info -print_format json -show_streams -show_chapters -show_format"
- : "{0} -i {1} -threads 0 -v info -print_format json -show_streams -show_format";
-
- var process = _processFactory.Create(new ProcessOptions
- {
- CreateNoWindow = true,
- UseShellExecute = false,
-
- // Must consume both or ffmpeg may hang due to deadlocks. See comments below.
- RedirectStandardOutput = true,
- FileName = FFProbePath,
- Arguments = string.Format(args, probeSizeArgument, inputPath).Trim(),
-
- IsHidden = true,
- ErrorDialog = false,
- EnableRaisingEvents = true
- });
-
- if (forceEnableLogging)
- {
- _logger.Info("{0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments);
- }
- else
- {
- _logger.Debug("{0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments);
- }
-
- using (var processWrapper = new ProcessWrapper(process, this, _logger))
- {
- StartProcess(processWrapper);
-
- try
- {
- //process.BeginErrorReadLine();
-
- var result = _jsonSerializer.DeserializeFromStream<InternalMediaInfoResult>(process.StandardOutput.BaseStream);
-
- if (result == null || (result.streams == null && result.format == null))
- {
- throw new Exception("ffprobe failed - streams and format are both null.");
- }
-
- if (result.streams != null)
- {
- // Normalize aspect ratio if invalid
- foreach (var stream in result.streams)
- {
- if (string.Equals(stream.display_aspect_ratio, "0:1", StringComparison.OrdinalIgnoreCase))
- {
- stream.display_aspect_ratio = string.Empty;
- }
- if (string.Equals(stream.sample_aspect_ratio, "0:1", StringComparison.OrdinalIgnoreCase))
- {
- stream.sample_aspect_ratio = string.Empty;
- }
- }
- }
-
- return new ProbeResultNormalizer(_logger, FileSystem, _memoryStreamProvider).GetMediaInfo(result, videoType, isAudio, primaryPath, protocol);
- }
- catch
- {
- StopProcess(processWrapper, 100);
-
- throw;
- }
- }
- }
-
- /// <summary>
- /// The us culture
- /// </summary>
- protected readonly CultureInfo UsCulture = new CultureInfo("en-US");
-
- public Task<string> ExtractAudioImage(string path, int? imageStreamIndex, CancellationToken cancellationToken)
- {
- return ExtractImage(new[] { path }, null, imageStreamIndex, MediaProtocol.File, true, null, null, cancellationToken);
- }
-
- public Task<string> ExtractVideoImage(string[] inputFiles, string container, MediaProtocol protocol, Video3DFormat? threedFormat, TimeSpan? offset, CancellationToken cancellationToken)
- {
- return ExtractImage(inputFiles, container, null, protocol, false, threedFormat, offset, cancellationToken);
- }
-
- public Task<string> ExtractVideoImage(string[] inputFiles, string container, MediaProtocol protocol, int? imageStreamIndex, CancellationToken cancellationToken)
- {
- return ExtractImage(inputFiles, container, imageStreamIndex, protocol, false, null, null, cancellationToken);
- }
-
- private async Task<string> ExtractImage(string[] inputFiles, string container, int? imageStreamIndex, MediaProtocol protocol, bool isAudio,
- Video3DFormat? threedFormat, TimeSpan? offset, CancellationToken cancellationToken)
- {
- var inputArgument = GetInputArgument(inputFiles, protocol);
-
- if (isAudio)
- {
- if (imageStreamIndex.HasValue && imageStreamIndex.Value > 0)
- {
- // It seems for audio files we need to subtract 1 (for the audio stream??)
- imageStreamIndex = imageStreamIndex.Value - 1;
- }
- }
- else
- {
- try
- {
- return await ExtractImageInternal(inputArgument, container, imageStreamIndex, protocol, threedFormat, offset, true, cancellationToken).ConfigureAwait(false);
- }
- catch (ArgumentException)
- {
- throw;
- }
- catch
- {
- _logger.Error("I-frame image extraction failed, will attempt standard way. Input: {0}", inputArgument);
- }
- }
-
- return await ExtractImageInternal(inputArgument, container, imageStreamIndex, protocol, threedFormat, offset, false, cancellationToken).ConfigureAwait(false);
- }
-
- private async Task<string> ExtractImageInternal(string inputPath, string container, int? imageStreamIndex, MediaProtocol protocol, Video3DFormat? threedFormat, TimeSpan? offset, bool useIFrame, CancellationToken cancellationToken)
- {
- if (string.IsNullOrEmpty(inputPath))
- {
- throw new ArgumentNullException("inputPath");
- }
-
- var tempExtractPath = Path.Combine(ConfigurationManager.ApplicationPaths.TempDirectory, Guid.NewGuid() + ".jpg");
- FileSystem.CreateDirectory(FileSystem.GetDirectoryName(tempExtractPath));
-
- // apply some filters to thumbnail extracted below (below) crop any black lines that we made and get the correct ar then scale to width 600.
- // This filter chain may have adverse effects on recorded tv thumbnails if ar changes during presentation ex. commercials @ diff ar
- var vf = "scale=600:trunc(600/dar/2)*2";
-
- if (threedFormat.HasValue)
- {
- switch (threedFormat.Value)
- {
- case Video3DFormat.HalfSideBySide:
- vf = "crop=iw/2:ih:0:0,scale=(iw*2):ih,setdar=dar=a,crop=min(iw\\,ih*dar):min(ih\\,iw/dar):(iw-min(iw\\,iw*sar))/2:(ih - min (ih\\,ih/sar))/2,setsar=sar=1,scale=600:trunc(600/dar/2)*2";
- // hsbs crop width in half,scale to correct size, set the display aspect,crop out any black bars we may have made the scale width to 600. Work out the correct height based on the display aspect it will maintain the aspect where -1 in this case (3d) may not.
- break;
- case Video3DFormat.FullSideBySide:
- vf = "crop=iw/2:ih:0:0,setdar=dar=a,crop=min(iw\\,ih*dar):min(ih\\,iw/dar):(iw-min(iw\\,iw*sar))/2:(ih - min (ih\\,ih/sar))/2,setsar=sar=1,scale=600:trunc(600/dar/2)*2";
- //fsbs crop width in half,set the display aspect,crop out any black bars we may have made the scale width to 600.
- break;
- case Video3DFormat.HalfTopAndBottom:
- vf = "crop=iw:ih/2:0:0,scale=(iw*2):ih),setdar=dar=a,crop=min(iw\\,ih*dar):min(ih\\,iw/dar):(iw-min(iw\\,iw*sar))/2:(ih - min (ih\\,ih/sar))/2,setsar=sar=1,scale=600:trunc(600/dar/2)*2";
- //htab crop heigh in half,scale to correct size, set the display aspect,crop out any black bars we may have made the scale width to 600
- break;
- case Video3DFormat.FullTopAndBottom:
- vf = "crop=iw:ih/2:0:0,setdar=dar=a,crop=min(iw\\,ih*dar):min(ih\\,iw/dar):(iw-min(iw\\,iw*sar))/2:(ih - min (ih\\,ih/sar))/2,setsar=sar=1,scale=600:trunc(600/dar/2)*2";
- // ftab crop heigt in half, set the display aspect,crop out any black bars we may have made the scale width to 600
- break;
- default:
- break;
- }
- }
-
- var mapArg = imageStreamIndex.HasValue ? (" -map 0:v:" + imageStreamIndex.Value.ToString(CultureInfo.InvariantCulture)) : string.Empty;
-
- var enableThumbnail = !new List<string> { "wtv" }.Contains(container ?? string.Empty, StringComparer.OrdinalIgnoreCase);
- // Use ffmpeg to sample 100 (we can drop this if required using thumbnail=50 for 50 frames) frames and pick the best thumbnail. Have a fall back just in case.
- var thumbnail = enableThumbnail ? ",thumbnail=24" : string.Empty;
-
- var args = useIFrame ? string.Format("-i {0}{3} -threads 0 -v quiet -vframes 1 -vf \"{2}{4}\" -f image2 \"{1}\"", inputPath, tempExtractPath, vf, mapArg, thumbnail) :
- string.Format("-i {0}{3} -threads 0 -v quiet -vframes 1 -vf \"{2}\" -f image2 \"{1}\"", inputPath, tempExtractPath, vf, mapArg);
-
- var probeSizeArgument = EncodingHelper.GetProbeSizeArgument(1);
- var analyzeDurationArgument = EncodingHelper.GetAnalyzeDurationArgument(1);
-
- if (!string.IsNullOrWhiteSpace(probeSizeArgument))
- {
- args = probeSizeArgument + " " + args;
- }
-
- if (!string.IsNullOrWhiteSpace(analyzeDurationArgument))
- {
- args = analyzeDurationArgument + " " + args;
- }
-
- if (offset.HasValue)
- {
- args = string.Format("-ss {0} ", GetTimeParameter(offset.Value)) + args;
- }
-
- var process = _processFactory.Create(new ProcessOptions
- {
- CreateNoWindow = true,
- UseShellExecute = false,
- FileName = FFMpegPath,
- Arguments = args,
- IsHidden = true,
- ErrorDialog = false
- });
-
- _logger.Debug("{0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments);
-
- using (var processWrapper = new ProcessWrapper(process, this, _logger))
- {
- bool ranToCompletion;
-
- StartProcess(processWrapper);
-
- var timeoutMs = ConfigurationManager.Configuration.ImageExtractionTimeoutMs;
- if (timeoutMs <= 0)
- {
- timeoutMs = DefaultImageExtractionTimeoutMs;
- }
-
- ranToCompletion = await process.WaitForExitAsync(timeoutMs).ConfigureAwait(false);
-
- if (!ranToCompletion)
- {
- StopProcess(processWrapper, 1000);
- }
-
- var exitCode = ranToCompletion ? processWrapper.ExitCode ?? 0 : -1;
- var file = FileSystem.GetFileInfo(tempExtractPath);
-
- if (exitCode == -1 || !file.Exists || file.Length == 0)
- {
- var msg = string.Format("ffmpeg image extraction failed for {0}", inputPath);
-
- _logger.Error(msg);
-
- throw new Exception(msg);
- }
-
- return tempExtractPath;
- }
- }
-
- public string GetTimeParameter(long ticks)
- {
- var time = TimeSpan.FromTicks(ticks);
-
- return GetTimeParameter(time);
- }
-
- public string GetTimeParameter(TimeSpan time)
- {
- return time.ToString(@"hh\:mm\:ss\.fff", UsCulture);
- }
-
- public async Task ExtractVideoImagesOnInterval(string[] inputFiles,
- MediaProtocol protocol,
- Video3DFormat? threedFormat,
- TimeSpan interval,
- string targetDirectory,
- string filenamePrefix,
- int? maxWidth,
- CancellationToken cancellationToken)
- {
- var resourcePool = _thumbnailResourcePool;
-
- var inputArgument = GetInputArgument(inputFiles, protocol);
-
- var vf = "fps=fps=1/" + interval.TotalSeconds.ToString(UsCulture);
-
- if (maxWidth.HasValue)
- {
- var maxWidthParam = maxWidth.Value.ToString(UsCulture);
-
- vf += string.Format(",scale=min(iw\\,{0}):trunc(ow/dar/2)*2", maxWidthParam);
- }
-
- FileSystem.CreateDirectory(targetDirectory);
- var outputPath = Path.Combine(targetDirectory, filenamePrefix + "%05d.jpg");
-
- var args = string.Format("-i {0} -threads 0 -v quiet -vf \"{2}\" -f image2 \"{1}\"", inputArgument, outputPath, vf);
-
- var probeSizeArgument = EncodingHelper.GetProbeSizeArgument(1);
- var analyzeDurationArgument = EncodingHelper.GetAnalyzeDurationArgument(1);
-
- if (!string.IsNullOrWhiteSpace(probeSizeArgument))
- {
- args = probeSizeArgument + " " + args;
- }
-
- if (!string.IsNullOrWhiteSpace(analyzeDurationArgument))
- {
- args = analyzeDurationArgument + " " + args;
- }
-
- var process = _processFactory.Create(new ProcessOptions
- {
- CreateNoWindow = true,
- UseShellExecute = false,
- FileName = FFMpegPath,
- Arguments = args,
- IsHidden = true,
- ErrorDialog = false
- });
-
- _logger.Info(process.StartInfo.FileName + " " + process.StartInfo.Arguments);
-
- await resourcePool.WaitAsync(cancellationToken).ConfigureAwait(false);
-
- bool ranToCompletion = false;
-
- using (var processWrapper = new ProcessWrapper(process, this, _logger))
- {
- try
- {
- StartProcess(processWrapper);
-
- // Need to give ffmpeg enough time to make all the thumbnails, which could be a while,
- // but we still need to detect if the process hangs.
- // Making the assumption that as long as new jpegs are showing up, everything is good.
-
- bool isResponsive = true;
- int lastCount = 0;
-
- while (isResponsive)
- {
- if (await process.WaitForExitAsync(30000).ConfigureAwait(false))
- {
- ranToCompletion = true;
- break;
- }
-
- cancellationToken.ThrowIfCancellationRequested();
-
- var jpegCount = FileSystem.GetFilePaths(targetDirectory)
- .Count(i => string.Equals(Path.GetExtension(i), ".jpg", StringComparison.OrdinalIgnoreCase));
-
- isResponsive = (jpegCount > lastCount);
- lastCount = jpegCount;
- }
-
- if (!ranToCompletion)
- {
- StopProcess(processWrapper, 1000);
- }
- }
- finally
- {
- resourcePool.Release();
- }
-
- var exitCode = ranToCompletion ? processWrapper.ExitCode ?? 0 : -1;
-
- if (exitCode == -1)
- {
- var msg = string.Format("ffmpeg image extraction failed for {0}", inputArgument);
-
- _logger.Error(msg);
-
- throw new Exception(msg);
- }
- }
- }
-
- public async Task<string> EncodeAudio(EncodingJobOptions options,
- IProgress<double> progress,
- CancellationToken cancellationToken)
- {
- var job = await new AudioEncoder(this,
- _logger,
- ConfigurationManager,
- FileSystem,
- IsoManager,
- LibraryManager,
- SessionManager,
- SubtitleEncoder(),
- MediaSourceManager(),
- _processFactory)
- .Start(options, progress, cancellationToken).ConfigureAwait(false);
-
- await job.TaskCompletionSource.Task.ConfigureAwait(false);
-
- return job.OutputFilePath;
- }
-
- public async Task<string> EncodeVideo(EncodingJobOptions options,
- IProgress<double> progress,
- CancellationToken cancellationToken)
- {
- var job = await new VideoEncoder(this,
- _logger,
- ConfigurationManager,
- FileSystem,
- IsoManager,
- LibraryManager,
- SessionManager,
- SubtitleEncoder(),
- MediaSourceManager(),
- _processFactory)
- .Start(options, progress, cancellationToken).ConfigureAwait(false);
-
- await job.TaskCompletionSource.Task.ConfigureAwait(false);
-
- return job.OutputFilePath;
- }
-
- private void StartProcess(ProcessWrapper process)
- {
- process.Process.Start();
-
- lock (_runningProcesses)
- {
- _runningProcesses.Add(process);
- }
- }
- private void StopProcess(ProcessWrapper process, int waitTimeMs)
- {
- try
- {
- if (process.Process.WaitForExit(waitTimeMs))
- {
- return;
- }
- }
- catch (Exception ex)
- {
- _logger.Error("Error in WaitForExit", ex);
- }
-
- try
- {
- _logger.Info("Killing ffmpeg process");
-
- process.Process.Kill();
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error killing process", ex);
- }
- }
-
- private void StopProcesses()
- {
- List<ProcessWrapper> proceses;
- lock (_runningProcesses)
- {
- proceses = _runningProcesses.ToList();
- _runningProcesses.Clear();
- }
-
- foreach (var process in proceses)
- {
- if (!process.HasExited)
- {
- StopProcess(process, 500);
- }
- }
- }
-
- public string EscapeSubtitleFilterPath(string path)
- {
- // https://ffmpeg.org/ffmpeg-filters.html#Notes-on-filtergraph-escaping
- // We need to double escape
-
- return path.Replace('\\', '/').Replace(":", "\\:").Replace("'", "'\\\\\\''");
- }
-
- /// <summary>
- /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
- /// </summary>
- public void Dispose()
- {
- Dispose(true);
- }
-
- /// <summary>
- /// Releases unmanaged and - optionally - managed resources.
- /// </summary>
- /// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
- protected virtual void Dispose(bool dispose)
- {
- if (dispose)
- {
- StopProcesses();
- }
- }
-
- private class ProcessWrapper : IDisposable
- {
- public readonly IProcess Process;
- public bool HasExited;
- public int? ExitCode;
- private readonly MediaEncoder _mediaEncoder;
- private readonly ILogger _logger;
-
- public ProcessWrapper(IProcess process, MediaEncoder mediaEncoder, ILogger logger)
- {
- Process = process;
- _mediaEncoder = mediaEncoder;
- _logger = logger;
- Process.Exited += Process_Exited;
- }
-
- void Process_Exited(object sender, EventArgs e)
- {
- var process = (IProcess)sender;
-
- HasExited = true;
-
- try
- {
- ExitCode = process.ExitCode;
- }
- catch
- {
- }
-
- DisposeProcess(process);
- }
-
- private void DisposeProcess(IProcess process)
- {
- lock (_mediaEncoder._runningProcesses)
- {
- _mediaEncoder._runningProcesses.Remove(this);
- }
-
- try
- {
- process.Dispose();
- }
- catch
- {
- }
- }
-
- private bool _disposed;
- private readonly object _syncLock = new object();
- public void Dispose()
- {
- lock (_syncLock)
- {
- if (!_disposed)
- {
- if (Process != null)
- {
- Process.Exited -= Process_Exited;
- DisposeProcess(Process);
- }
- }
-
- _disposed = true;
- }
- }
- }
- }
-} \ No newline at end of file
diff --git a/MediaBrowser.MediaEncoding/Encoder/VideoEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/VideoEncoder.cs
deleted file mode 100644
index 96c126923..000000000
--- a/MediaBrowser.MediaEncoding/Encoder/VideoEncoder.cs
+++ /dev/null
@@ -1,66 +0,0 @@
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.MediaEncoding;
-using MediaBrowser.Controller.Session;
-using MediaBrowser.Model.Dlna;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Model.Logging;
-using System;
-using System.IO;
-using System.Threading.Tasks;
-using MediaBrowser.Model.Diagnostics;
-
-namespace MediaBrowser.MediaEncoding.Encoder
-{
- public class VideoEncoder : BaseEncoder
- {
- public VideoEncoder(MediaEncoder mediaEncoder, ILogger logger, IServerConfigurationManager configurationManager, IFileSystem fileSystem, IIsoManager isoManager, ILibraryManager libraryManager, ISessionManager sessionManager, ISubtitleEncoder subtitleEncoder, IMediaSourceManager mediaSourceManager, IProcessFactory processFactory) : base(mediaEncoder, logger, configurationManager, fileSystem, isoManager, libraryManager, sessionManager, subtitleEncoder, mediaSourceManager, processFactory)
- {
- }
-
- protected override string GetCommandLineArguments(EncodingJob state)
- {
- // Get the output codec name
- var encodingOptions = GetEncodingOptions();
-
- return EncodingHelper.GetProgressiveVideoFullCommandLine(state, encodingOptions, state.OutputFilePath, "superfast");
- }
-
- protected override string GetOutputFileExtension(EncodingJob state)
- {
- var ext = base.GetOutputFileExtension(state);
-
- if (!string.IsNullOrEmpty(ext))
- {
- return ext;
- }
-
- var videoCodec = state.Options.VideoCodec;
-
- if (string.Equals(videoCodec, "h264", StringComparison.OrdinalIgnoreCase))
- {
- return ".ts";
- }
- if (string.Equals(videoCodec, "theora", StringComparison.OrdinalIgnoreCase))
- {
- return ".ogv";
- }
- if (string.Equals(videoCodec, "vpx", StringComparison.OrdinalIgnoreCase))
- {
- return ".webm";
- }
- if (string.Equals(videoCodec, "wmv", StringComparison.OrdinalIgnoreCase))
- {
- return ".asf";
- }
-
- return null;
- }
-
- protected override bool IsVideoEncoder
- {
- get { return true; }
- }
-
- }
-} \ No newline at end of file
diff --git a/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj b/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj
deleted file mode 100644
index 142e1c627..000000000
--- a/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj
+++ /dev/null
@@ -1,100 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
- <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
- <PropertyGroup>
- <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
- <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
- <ProjectGuid>{0BD82FA6-EB8A-4452-8AF5-74F9C3849451}</ProjectGuid>
- <OutputType>Library</OutputType>
- <AppDesignerFolder>Properties</AppDesignerFolder>
- <RootNamespace>MediaBrowser.MediaEncoding</RootNamespace>
- <AssemblyName>MediaBrowser.MediaEncoding</AssemblyName>
- <FileAlignment>512</FileAlignment>
- <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
- <TargetFrameworkProfile>Profile7</TargetFrameworkProfile>
- <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
- </PropertyGroup>
- <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
- <DebugSymbols>true</DebugSymbols>
- <DebugType>full</DebugType>
- <Optimize>false</Optimize>
- <OutputPath>bin\Debug\</OutputPath>
- <DefineConstants>DEBUG;TRACE</DefineConstants>
- <ErrorReport>prompt</ErrorReport>
- <WarningLevel>4</WarningLevel>
- </PropertyGroup>
- <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
- <DebugType>none</DebugType>
- <Optimize>true</Optimize>
- <OutputPath>bin\Release\</OutputPath>
- <DefineConstants>TRACE</DefineConstants>
- <ErrorReport>prompt</ErrorReport>
- <WarningLevel>4</WarningLevel>
- </PropertyGroup>
- <ItemGroup>
- <Compile Include="..\SharedVersion.cs">
- <Link>Properties\SharedVersion.cs</Link>
- </Compile>
- <Compile Include="BdInfo\BdInfoExaminer.cs" />
- <Compile Include="Configuration\EncodingConfigurationFactory.cs" />
- <Compile Include="Encoder\AudioEncoder.cs" />
- <Compile Include="Encoder\BaseEncoder.cs" />
- <Compile Include="Encoder\EncodingJob.cs" />
- <Compile Include="Encoder\EncodingJobFactory.cs" />
- <Compile Include="Encoder\EncodingUtils.cs" />
- <Compile Include="Encoder\EncoderValidator.cs" />
- <Compile Include="Encoder\FontConfigLoader.cs" />
- <Compile Include="Encoder\MediaEncoder.cs" />
- <Compile Include="Encoder\VideoEncoder.cs" />
- <Compile Include="Probing\FFProbeHelpers.cs" />
- <Compile Include="Probing\InternalMediaInfoResult.cs" />
- <Compile Include="Probing\ProbeResultNormalizer.cs" />
- <Compile Include="Properties\AssemblyInfo.cs" />
- <Compile Include="Subtitles\ConfigurationExtension.cs" />
- <Compile Include="Subtitles\ISubtitleParser.cs" />
- <Compile Include="Subtitles\ISubtitleWriter.cs" />
- <Compile Include="Subtitles\JsonWriter.cs" />
- <Compile Include="Subtitles\OpenSubtitleDownloader.cs" />
- <Compile Include="Subtitles\ParserValues.cs" />
- <Compile Include="Subtitles\SrtParser.cs" />
- <Compile Include="Subtitles\SrtWriter.cs" />
- <Compile Include="Subtitles\AssParser.cs" />
- <Compile Include="Subtitles\SsaParser.cs" />
- <Compile Include="Subtitles\SubtitleEncoder.cs" />
- <Compile Include="Subtitles\TtmlWriter.cs" />
- <Compile Include="Subtitles\VttWriter.cs" />
- </ItemGroup>
- <ItemGroup>
- <ProjectReference Include="..\BDInfo\BDInfo.csproj">
- <Project>{88ae38df-19d7-406f-a6a9-09527719a21e}</Project>
- <Name>BDInfo</Name>
- </ProjectReference>
- <ProjectReference Include="..\MediaBrowser.Common\MediaBrowser.Common.csproj">
- <Project>{9142eefa-7570-41e1-bfcc-468bb571af2f}</Project>
- <Name>MediaBrowser.Common</Name>
- </ProjectReference>
- <ProjectReference Include="..\MediaBrowser.Controller\MediaBrowser.Controller.csproj">
- <Project>{17e1f4e6-8abd-4fe5-9ecf-43d4b6087ba2}</Project>
- <Name>MediaBrowser.Controller</Name>
- </ProjectReference>
- <ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj">
- <Project>{7eeeb4bb-f3e8-48fc-b4c5-70f0fff8329b}</Project>
- <Name>MediaBrowser.Model</Name>
- </ProjectReference>
- <ProjectReference Include="..\OpenSubtitlesHandler\OpenSubtitlesHandler.csproj">
- <Project>{4a4402d4-e910-443b-b8fc-2c18286a2ca0}</Project>
- <Name>OpenSubtitlesHandler</Name>
- </ProjectReference>
- </ItemGroup>
- <ItemGroup>
- <None Include="packages.config" />
- </ItemGroup>
- <Import Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets" />
- <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
- Other similar extension points exist, see Microsoft.Common.targets.
- <Target Name="BeforeBuild">
- </Target>
- <Target Name="AfterBuild">
- </Target>
- -->
-</Project> \ No newline at end of file
diff --git a/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.nuget.targets b/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.nuget.targets
deleted file mode 100644
index e69ce0e64..000000000
--- a/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.nuget.targets
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8" standalone="no"?>
-<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
- <Target Name="EmitMSBuildWarning" BeforeTargets="Build">
- <Warning Text="Packages containing MSBuild targets and props files cannot be fully installed in projects targeting multiple frameworks. The MSBuild targets and props files have been ignored." />
- </Target>
-</Project> \ No newline at end of file
diff --git a/MediaBrowser.MediaEncoding/Probing/FFProbeHelpers.cs b/MediaBrowser.MediaEncoding/Probing/FFProbeHelpers.cs
deleted file mode 100644
index 396c85e21..000000000
--- a/MediaBrowser.MediaEncoding/Probing/FFProbeHelpers.cs
+++ /dev/null
@@ -1,117 +0,0 @@
-using System;
-using System.Collections.Generic;
-
-namespace MediaBrowser.MediaEncoding.Probing
-{
- public static class FFProbeHelpers
- {
- /// <summary>
- /// Normalizes the FF probe result.
- /// </summary>
- /// <param name="result">The result.</param>
- public static void NormalizeFFProbeResult(InternalMediaInfoResult result)
- {
- if (result == null)
- {
- throw new ArgumentNullException("result");
- }
-
- if (result.format != null && result.format.tags != null)
- {
- result.format.tags = ConvertDictionaryToCaseInSensitive(result.format.tags);
- }
-
- if (result.streams != null)
- {
- // Convert all dictionaries to case insensitive
- foreach (var stream in result.streams)
- {
- if (stream.tags != null)
- {
- stream.tags = ConvertDictionaryToCaseInSensitive(stream.tags);
- }
-
- if (stream.disposition != null)
- {
- stream.disposition = ConvertDictionaryToCaseInSensitive(stream.disposition);
- }
- }
- }
- }
-
- /// <summary>
- /// Gets a string from an FFProbeResult tags dictionary
- /// </summary>
- /// <param name="tags">The tags.</param>
- /// <param name="key">The key.</param>
- /// <returns>System.String.</returns>
- public static string GetDictionaryValue(Dictionary<string, string> tags, string key)
- {
- if (tags == null)
- {
- return null;
- }
-
- string val;
-
- tags.TryGetValue(key, out val);
- return val;
- }
-
- /// <summary>
- /// Gets an int from an FFProbeResult tags dictionary
- /// </summary>
- /// <param name="tags">The tags.</param>
- /// <param name="key">The key.</param>
- /// <returns>System.Nullable{System.Int32}.</returns>
- public static int? GetDictionaryNumericValue(Dictionary<string, string> tags, string key)
- {
- var val = GetDictionaryValue(tags, key);
-
- if (!string.IsNullOrEmpty(val))
- {
- int i;
-
- if (int.TryParse(val, out i))
- {
- return i;
- }
- }
-
- return null;
- }
-
- /// <summary>
- /// Gets a DateTime from an FFProbeResult tags dictionary
- /// </summary>
- /// <param name="tags">The tags.</param>
- /// <param name="key">The key.</param>
- /// <returns>System.Nullable{DateTime}.</returns>
- public static DateTime? GetDictionaryDateTime(Dictionary<string, string> tags, string key)
- {
- var val = GetDictionaryValue(tags, key);
-
- if (!string.IsNullOrEmpty(val))
- {
- DateTime i;
-
- if (DateTime.TryParse(val, out i))
- {
- return i.ToUniversalTime();
- }
- }
-
- return null;
- }
-
- /// <summary>
- /// Converts a dictionary to case insensitive
- /// </summary>
- /// <param name="dict">The dict.</param>
- /// <returns>Dictionary{System.StringSystem.String}.</returns>
- private static Dictionary<string, string> ConvertDictionaryToCaseInSensitive(Dictionary<string, string> dict)
- {
- return new Dictionary<string, string>(dict, StringComparer.OrdinalIgnoreCase);
- }
- }
-}
diff --git a/MediaBrowser.MediaEncoding/Probing/InternalMediaInfoResult.cs b/MediaBrowser.MediaEncoding/Probing/InternalMediaInfoResult.cs
deleted file mode 100644
index eef273250..000000000
--- a/MediaBrowser.MediaEncoding/Probing/InternalMediaInfoResult.cs
+++ /dev/null
@@ -1,341 +0,0 @@
-using System.Collections.Generic;
-
-namespace MediaBrowser.MediaEncoding.Probing
-{
- /// <summary>
- /// Class MediaInfoResult
- /// </summary>
- public class InternalMediaInfoResult
- {
- /// <summary>
- /// Gets or sets the streams.
- /// </summary>
- /// <value>The streams.</value>
- public MediaStreamInfo[] streams { get; set; }
-
- /// <summary>
- /// Gets or sets the format.
- /// </summary>
- /// <value>The format.</value>
- public MediaFormatInfo format { get; set; }
-
- /// <summary>
- /// Gets or sets the chapters.
- /// </summary>
- /// <value>The chapters.</value>
- public MediaChapter[] Chapters { get; set; }
- }
-
- public class MediaChapter
- {
- public int id { get; set; }
- public string time_base { get; set; }
- public long start { get; set; }
- public string start_time { get; set; }
- public long end { get; set; }
- public string end_time { get; set; }
- public Dictionary<string, string> tags { get; set; }
- }
-
- /// <summary>
- /// Represents a stream within the output
- /// </summary>
- public class MediaStreamInfo
- {
- /// <summary>
- /// Gets or sets the index.
- /// </summary>
- /// <value>The index.</value>
- public int index { get; set; }
-
- /// <summary>
- /// Gets or sets the profile.
- /// </summary>
- /// <value>The profile.</value>
- public string profile { get; set; }
-
- /// <summary>
- /// Gets or sets the codec_name.
- /// </summary>
- /// <value>The codec_name.</value>
- public string codec_name { get; set; }
-
- /// <summary>
- /// Gets or sets the codec_long_name.
- /// </summary>
- /// <value>The codec_long_name.</value>
- public string codec_long_name { get; set; }
-
- /// <summary>
- /// Gets or sets the codec_type.
- /// </summary>
- /// <value>The codec_type.</value>
- public string codec_type { get; set; }
-
- /// <summary>
- /// Gets or sets the sample_rate.
- /// </summary>
- /// <value>The sample_rate.</value>
- public string sample_rate { get; set; }
-
- /// <summary>
- /// Gets or sets the channels.
- /// </summary>
- /// <value>The channels.</value>
- public int channels { get; set; }
-
- /// <summary>
- /// Gets or sets the channel_layout.
- /// </summary>
- /// <value>The channel_layout.</value>
- public string channel_layout { get; set; }
-
- /// <summary>
- /// Gets or sets the avg_frame_rate.
- /// </summary>
- /// <value>The avg_frame_rate.</value>
- public string avg_frame_rate { get; set; }
-
- /// <summary>
- /// Gets or sets the duration.
- /// </summary>
- /// <value>The duration.</value>
- public string duration { get; set; }
-
- /// <summary>
- /// Gets or sets the bit_rate.
- /// </summary>
- /// <value>The bit_rate.</value>
- public string bit_rate { get; set; }
-
- /// <summary>
- /// Gets or sets the width.
- /// </summary>
- /// <value>The width.</value>
- public int width { get; set; }
-
- /// <summary>
- /// Gets or sets the refs.
- /// </summary>
- /// <value>The refs.</value>
- public int refs { get; set; }
-
- /// <summary>
- /// Gets or sets the height.
- /// </summary>
- /// <value>The height.</value>
- public int height { get; set; }
-
- /// <summary>
- /// Gets or sets the display_aspect_ratio.
- /// </summary>
- /// <value>The display_aspect_ratio.</value>
- public string display_aspect_ratio { get; set; }
-
- /// <summary>
- /// Gets or sets the tags.
- /// </summary>
- /// <value>The tags.</value>
- public Dictionary<string, string> tags { get; set; }
-
- /// <summary>
- /// Gets or sets the bits_per_sample.
- /// </summary>
- /// <value>The bits_per_sample.</value>
- public int bits_per_sample { get; set; }
-
- /// <summary>
- /// Gets or sets the bits_per_raw_sample.
- /// </summary>
- /// <value>The bits_per_raw_sample.</value>
- public int bits_per_raw_sample { get; set; }
-
- /// <summary>
- /// Gets or sets the r_frame_rate.
- /// </summary>
- /// <value>The r_frame_rate.</value>
- public string r_frame_rate { get; set; }
-
- /// <summary>
- /// Gets or sets the has_b_frames.
- /// </summary>
- /// <value>The has_b_frames.</value>
- public int has_b_frames { get; set; }
-
- /// <summary>
- /// Gets or sets the sample_aspect_ratio.
- /// </summary>
- /// <value>The sample_aspect_ratio.</value>
- public string sample_aspect_ratio { get; set; }
-
- /// <summary>
- /// Gets or sets the pix_fmt.
- /// </summary>
- /// <value>The pix_fmt.</value>
- public string pix_fmt { get; set; }
-
- /// <summary>
- /// Gets or sets the level.
- /// </summary>
- /// <value>The level.</value>
- public int level { get; set; }
-
- /// <summary>
- /// Gets or sets the time_base.
- /// </summary>
- /// <value>The time_base.</value>
- public string time_base { get; set; }
-
- /// <summary>
- /// Gets or sets the start_time.
- /// </summary>
- /// <value>The start_time.</value>
- public string start_time { get; set; }
-
- /// <summary>
- /// Gets or sets the codec_time_base.
- /// </summary>
- /// <value>The codec_time_base.</value>
- public string codec_time_base { get; set; }
-
- /// <summary>
- /// Gets or sets the codec_tag.
- /// </summary>
- /// <value>The codec_tag.</value>
- public string codec_tag { get; set; }
-
- /// <summary>
- /// Gets or sets the codec_tag_string.
- /// </summary>
- /// <value>The codec_tag_string.</value>
- public string codec_tag_string { get; set; }
-
- /// <summary>
- /// Gets or sets the sample_fmt.
- /// </summary>
- /// <value>The sample_fmt.</value>
- public string sample_fmt { get; set; }
-
- /// <summary>
- /// Gets or sets the dmix_mode.
- /// </summary>
- /// <value>The dmix_mode.</value>
- public string dmix_mode { get; set; }
-
- /// <summary>
- /// Gets or sets the start_pts.
- /// </summary>
- /// <value>The start_pts.</value>
- public string start_pts { get; set; }
-
- /// <summary>
- /// Gets or sets the is_avc.
- /// </summary>
- /// <value>The is_avc.</value>
- public string is_avc { get; set; }
-
- /// <summary>
- /// Gets or sets the nal_length_size.
- /// </summary>
- /// <value>The nal_length_size.</value>
- public string nal_length_size { get; set; }
-
- /// <summary>
- /// Gets or sets the ltrt_cmixlev.
- /// </summary>
- /// <value>The ltrt_cmixlev.</value>
- public string ltrt_cmixlev { get; set; }
-
- /// <summary>
- /// Gets or sets the ltrt_surmixlev.
- /// </summary>
- /// <value>The ltrt_surmixlev.</value>
- public string ltrt_surmixlev { get; set; }
-
- /// <summary>
- /// Gets or sets the loro_cmixlev.
- /// </summary>
- /// <value>The loro_cmixlev.</value>
- public string loro_cmixlev { get; set; }
-
- /// <summary>
- /// Gets or sets the loro_surmixlev.
- /// </summary>
- /// <value>The loro_surmixlev.</value>
- public string loro_surmixlev { get; set; }
-
- public string field_order { get; set; }
-
- /// <summary>
- /// Gets or sets the disposition.
- /// </summary>
- /// <value>The disposition.</value>
- public Dictionary<string, string> disposition { get; set; }
- }
-
- /// <summary>
- /// Class MediaFormat
- /// </summary>
- public class MediaFormatInfo
- {
- /// <summary>
- /// Gets or sets the filename.
- /// </summary>
- /// <value>The filename.</value>
- public string filename { get; set; }
-
- /// <summary>
- /// Gets or sets the nb_streams.
- /// </summary>
- /// <value>The nb_streams.</value>
- public int nb_streams { get; set; }
-
- /// <summary>
- /// Gets or sets the format_name.
- /// </summary>
- /// <value>The format_name.</value>
- public string format_name { get; set; }
-
- /// <summary>
- /// Gets or sets the format_long_name.
- /// </summary>
- /// <value>The format_long_name.</value>
- public string format_long_name { get; set; }
-
- /// <summary>
- /// Gets or sets the start_time.
- /// </summary>
- /// <value>The start_time.</value>
- public string start_time { get; set; }
-
- /// <summary>
- /// Gets or sets the duration.
- /// </summary>
- /// <value>The duration.</value>
- public string duration { get; set; }
-
- /// <summary>
- /// Gets or sets the size.
- /// </summary>
- /// <value>The size.</value>
- public string size { get; set; }
-
- /// <summary>
- /// Gets or sets the bit_rate.
- /// </summary>
- /// <value>The bit_rate.</value>
- public string bit_rate { get; set; }
-
- /// <summary>
- /// Gets or sets the probe_score.
- /// </summary>
- /// <value>The probe_score.</value>
- public int probe_score { get; set; }
-
- /// <summary>
- /// Gets or sets the tags.
- /// </summary>
- /// <value>The tags.</value>
- public Dictionary<string, string> tags { get; set; }
- }
-}
diff --git a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs
deleted file mode 100644
index 1e91a8198..000000000
--- a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs
+++ /dev/null
@@ -1,1372 +0,0 @@
-using MediaBrowser.Model.Dto;
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Extensions;
-using System;
-using System.Collections.Generic;
-using System.Globalization;
-using System.IO;
-using System.Linq;
-using System.Text;
-using System.Xml;
-using MediaBrowser.Model.IO;
-
-using MediaBrowser.Controller.IO;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Model.Logging;
-using MediaBrowser.Model.MediaInfo;
-
-namespace MediaBrowser.MediaEncoding.Probing
-{
- public class ProbeResultNormalizer
- {
- private readonly CultureInfo _usCulture = new CultureInfo("en-US");
- private readonly ILogger _logger;
- private readonly IFileSystem _fileSystem;
- private readonly IMemoryStreamFactory _memoryStreamProvider;
-
- public ProbeResultNormalizer(ILogger logger, IFileSystem fileSystem, IMemoryStreamFactory memoryStreamProvider)
- {
- _logger = logger;
- _fileSystem = fileSystem;
- _memoryStreamProvider = memoryStreamProvider;
- }
-
- public MediaInfo GetMediaInfo(InternalMediaInfoResult data, VideoType videoType, bool isAudio, string path, MediaProtocol protocol)
- {
- var info = new MediaInfo
- {
- Path = path,
- Protocol = protocol
- };
-
- FFProbeHelpers.NormalizeFFProbeResult(data);
- SetSize(data, info);
-
- var internalStreams = data.streams ?? new MediaStreamInfo[] { };
-
- info.MediaStreams = internalStreams.Select(s => GetMediaStream(isAudio, s, data.format))
- .Where(i => i != null)
- // Drop subtitle streams if we don't know the codec because it will just cause failures if we don't know how to handle them
- .Where(i => i.Type != MediaStreamType.Subtitle || !string.IsNullOrWhiteSpace(i.Codec))
- .ToList();
-
- if (data.format != null)
- {
- info.Container = data.format.format_name;
-
- if (!string.IsNullOrEmpty(data.format.bit_rate))
- {
- int value;
- if (int.TryParse(data.format.bit_rate, NumberStyles.Any, _usCulture, out value))
- {
- info.Bitrate = value;
- }
- }
- }
-
- var tags = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
- var tagStreamType = isAudio ? "audio" : "video";
-
- if (data.streams != null)
- {
- var tagStream = data.streams.FirstOrDefault(i => string.Equals(i.codec_type, tagStreamType, StringComparison.OrdinalIgnoreCase));
-
- if (tagStream != null && tagStream.tags != null)
- {
- foreach (var pair in tagStream.tags)
- {
- tags[pair.Key] = pair.Value;
- }
- }
- }
-
- if (data.format != null && data.format.tags != null)
- {
- foreach (var pair in data.format.tags)
- {
- tags[pair.Key] = pair.Value;
- }
- }
-
- FetchGenres(info, tags);
- var overview = FFProbeHelpers.GetDictionaryValue(tags, "synopsis");
-
- if (string.IsNullOrWhiteSpace(overview))
- {
- overview = FFProbeHelpers.GetDictionaryValue(tags, "description");
- }
- if (string.IsNullOrWhiteSpace(overview))
- {
- overview = FFProbeHelpers.GetDictionaryValue(tags, "desc");
- }
-
- if (!string.IsNullOrWhiteSpace(overview))
- {
- info.Overview = overview;
- }
-
- var title = FFProbeHelpers.GetDictionaryValue(tags, "title");
- if (!string.IsNullOrWhiteSpace(title))
- {
- info.Name = title;
- }
-
- info.ProductionYear = FFProbeHelpers.GetDictionaryNumericValue(tags, "date");
-
- // Several different forms of retaildate
- info.PremiereDate = FFProbeHelpers.GetDictionaryDateTime(tags, "retaildate") ??
- FFProbeHelpers.GetDictionaryDateTime(tags, "retail date") ??
- FFProbeHelpers.GetDictionaryDateTime(tags, "retail_date") ??
- FFProbeHelpers.GetDictionaryDateTime(tags, "date");
-
- if (isAudio)
- {
- SetAudioRuntimeTicks(data, info);
-
- // tags are normally located under data.format, but we've seen some cases with ogg where they're part of the info stream
- // so let's create a combined list of both
-
- SetAudioInfoFromTags(info, tags);
- }
- else
- {
- FetchStudios(info, tags, "copyright");
-
- var iTunEXTC = FFProbeHelpers.GetDictionaryValue(tags, "iTunEXTC");
- if (!string.IsNullOrWhiteSpace(iTunEXTC))
- {
- var parts = iTunEXTC.Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
- // Example
- // mpaa|G|100|For crude humor
- if (parts.Length > 1)
- {
- info.OfficialRating = parts[1];
-
- if (parts.Length > 3)
- {
- info.OfficialRatingDescription = parts[3];
- }
- }
- }
-
- var itunesXml = FFProbeHelpers.GetDictionaryValue(tags, "iTunMOVI");
- if (!string.IsNullOrWhiteSpace(itunesXml))
- {
- FetchFromItunesInfo(itunesXml, info);
- }
-
- if (data.format != null && !string.IsNullOrEmpty(data.format.duration))
- {
- info.RunTimeTicks = TimeSpan.FromSeconds(double.Parse(data.format.duration, _usCulture)).Ticks;
- }
-
- FetchWtvInfo(info, data);
-
- if (data.Chapters != null)
- {
- info.Chapters = data.Chapters.Select(GetChapterInfo).ToList();
- }
-
- ExtractTimestamp(info);
-
- var stereoMode = GetDictionaryValue(tags, "stereo_mode");
- if (string.Equals(stereoMode, "left_right", StringComparison.OrdinalIgnoreCase))
- {
- info.Video3DFormat = Video3DFormat.FullSideBySide;
- }
-
- foreach (var mediaStream in info.MediaStreams)
- {
- if (mediaStream.Type == MediaStreamType.Audio && !mediaStream.BitRate.HasValue)
- {
- mediaStream.BitRate = GetEstimatedAudioBitrate(mediaStream.Codec, mediaStream.Channels);
- }
- }
-
- var videoStreamsBitrate = info.MediaStreams.Where(i => i.Type == MediaStreamType.Video).Select(i => i.BitRate ?? 0).Sum();
- // If ffprobe reported the container bitrate as being the same as the video stream bitrate, then it's wrong
- if (videoStreamsBitrate == (info.Bitrate ?? 0))
- {
- info.InferTotalBitrate(true);
- }
- }
-
- return info;
- }
-
- private int? GetEstimatedAudioBitrate(string codec, int? channels)
- {
- if (!channels.HasValue)
- {
- return null;
- }
-
- var channelsValue = channels.Value;
-
- if (string.Equals(codec, "aac", StringComparison.OrdinalIgnoreCase) ||
- string.Equals(codec, "mp3", StringComparison.OrdinalIgnoreCase))
- {
- if (channelsValue <= 2)
- {
- return 192000;
- }
-
- if (channelsValue >= 5)
- {
- return 320000;
- }
- }
-
- return null;
- }
-
- private void FetchFromItunesInfo(string xml, MediaInfo info)
- {
- // Make things simpler and strip out the dtd
- var plistIndex = xml.IndexOf("<plist", StringComparison.OrdinalIgnoreCase);
-
- if (plistIndex != -1)
- {
- xml = xml.Substring(plistIndex);
- }
-
- xml = "<?xml version=\"1.0\"?>" + xml;
-
- // <?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>cast</key>\n\t<array>\n\t\t<dict>\n\t\t\t<key>name</key>\n\t\t\t<string>Blender Foundation</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>name</key>\n\t\t\t<string>Janus Bager Kristensen</string>\n\t\t</dict>\n\t</array>\n\t<key>directors</key>\n\t<array>\n\t\t<dict>\n\t\t\t<key>name</key>\n\t\t\t<string>Sacha Goedegebure</string>\n\t\t</dict>\n\t</array>\n\t<key>studio</key>\n\t<string>Blender Foundation</string>\n</dict>\n</plist>\n
- using (var stream = _memoryStreamProvider.CreateNew(Encoding.UTF8.GetBytes(xml)))
- {
- using (var streamReader = new StreamReader(stream))
- {
- try
- {
- // Use XmlReader for best performance
- using (var reader = XmlReader.Create(streamReader))
- {
- reader.MoveToContent();
- reader.Read();
-
- // Loop through each element
- while (!reader.EOF && reader.ReadState == ReadState.Interactive)
- {
- if (reader.NodeType == XmlNodeType.Element)
- {
- switch (reader.Name)
- {
- case "dict":
- if (reader.IsEmptyElement)
- {
- reader.Read();
- continue;
- }
- using (var subtree = reader.ReadSubtree())
- {
- ReadFromDictNode(subtree, info);
- }
- break;
- default:
- reader.Skip();
- break;
- }
- }
- else
- {
- reader.Read();
- }
- }
- }
- }
- catch (XmlException)
- {
- // I've seen probe examples where the iTunMOVI value is just "<"
- // So we should not allow this to fail the entire probing operation
- }
- }
- }
- }
-
- private void ReadFromDictNode(XmlReader reader, MediaInfo info)
- {
- string currentKey = null;
- List<NameValuePair> pairs = new List<NameValuePair>();
-
- reader.MoveToContent();
- reader.Read();
-
- // Loop through each element
- while (!reader.EOF && reader.ReadState == ReadState.Interactive)
- {
- if (reader.NodeType == XmlNodeType.Element)
- {
- switch (reader.Name)
- {
- case "key":
- if (!string.IsNullOrWhiteSpace(currentKey))
- {
- ProcessPairs(currentKey, pairs, info);
- }
- currentKey = reader.ReadElementContentAsString();
- pairs = new List<NameValuePair>();
- break;
- case "string":
- var value = reader.ReadElementContentAsString();
- if (!string.IsNullOrWhiteSpace(value))
- {
- pairs.Add(new NameValuePair
- {
- Name = value,
- Value = value
- });
- }
- break;
- case "array":
- if (reader.IsEmptyElement)
- {
- reader.Read();
- continue;
- }
- using (var subtree = reader.ReadSubtree())
- {
- if (!string.IsNullOrWhiteSpace(currentKey))
- {
- pairs.AddRange(ReadValueArray(subtree));
- }
- }
- break;
- default:
- reader.Skip();
- break;
- }
- }
- else
- {
- reader.Read();
- }
- }
- }
-
- private List<NameValuePair> ReadValueArray(XmlReader reader)
- {
-
- List<NameValuePair> pairs = new List<NameValuePair>();
-
- reader.MoveToContent();
- reader.Read();
-
- // Loop through each element
- while (!reader.EOF && reader.ReadState == ReadState.Interactive)
- {
- if (reader.NodeType == XmlNodeType.Element)
- {
- switch (reader.Name)
- {
- case "dict":
-
- if (reader.IsEmptyElement)
- {
- reader.Read();
- continue;
- }
- using (var subtree = reader.ReadSubtree())
- {
- var dict = GetNameValuePair(subtree);
- if (dict != null)
- {
- pairs.Add(dict);
- }
- }
- break;
- default:
- reader.Skip();
- break;
- }
- }
- else
- {
- reader.Read();
- }
- }
-
- return pairs;
- }
-
- private void ProcessPairs(string key, List<NameValuePair> pairs, MediaInfo info)
- {
- if (string.Equals(key, "studio", StringComparison.OrdinalIgnoreCase))
- {
- foreach (var pair in pairs)
- {
- info.Studios.Add(pair.Value);
- }
-
- info.Studios = info.Studios
- .Where(i => !string.IsNullOrWhiteSpace(i))
- .Distinct(StringComparer.OrdinalIgnoreCase)
- .ToList();
-
- }
- else if (string.Equals(key, "screenwriters", StringComparison.OrdinalIgnoreCase))
- {
- foreach (var pair in pairs)
- {
- info.People.Add(new BaseItemPerson
- {
- Name = pair.Value,
- Type = PersonType.Writer
- });
- }
- }
- else if (string.Equals(key, "producers", StringComparison.OrdinalIgnoreCase))
- {
- foreach (var pair in pairs)
- {
- info.People.Add(new BaseItemPerson
- {
- Name = pair.Value,
- Type = PersonType.Producer
- });
- }
- }
- else if (string.Equals(key, "directors", StringComparison.OrdinalIgnoreCase))
- {
- foreach (var pair in pairs)
- {
- info.People.Add(new BaseItemPerson
- {
- Name = pair.Value,
- Type = PersonType.Director
- });
- }
- }
- }
-
- private NameValuePair GetNameValuePair(XmlReader reader)
- {
- string name = null;
- string value = null;
-
- reader.MoveToContent();
- reader.Read();
-
- // Loop through each element
- while (!reader.EOF && reader.ReadState == ReadState.Interactive)
- {
- if (reader.NodeType == XmlNodeType.Element)
- {
- switch (reader.Name)
- {
- case "key":
- name = reader.ReadElementContentAsString();
- break;
- case "string":
- value = reader.ReadElementContentAsString();
- break;
- default:
- reader.Skip();
- break;
- }
- }
- else
- {
- reader.Read();
- }
- }
-
- if (string.IsNullOrWhiteSpace(name) ||
- string.IsNullOrWhiteSpace(value))
- {
- return null;
- }
-
- return new NameValuePair
- {
- Name = name,
- Value = value
- };
- }
-
- private string NormalizeSubtitleCodec(string codec)
- {
- if (string.Equals(codec, "dvb_subtitle", StringComparison.OrdinalIgnoreCase))
- {
- codec = "dvbsub";
- }
- else if ((codec ?? string.Empty).IndexOf("PGS", StringComparison.OrdinalIgnoreCase) != -1)
- {
- codec = "PGSSUB";
- }
- else if ((codec ?? string.Empty).IndexOf("DVD", StringComparison.OrdinalIgnoreCase) != -1)
- {
- codec = "DVDSUB";
- }
-
- return codec;
- }
-
- /// <summary>
- /// Converts ffprobe stream info to our MediaStream class
- /// </summary>
- /// <param name="isAudio">if set to <c>true</c> [is info].</param>
- /// <param name="streamInfo">The stream info.</param>
- /// <param name="formatInfo">The format info.</param>
- /// <returns>MediaStream.</returns>
- private MediaStream GetMediaStream(bool isAudio, MediaStreamInfo streamInfo, MediaFormatInfo formatInfo)
- {
- // These are mp4 chapters
- if (string.Equals(streamInfo.codec_name, "mov_text", StringComparison.OrdinalIgnoreCase))
- {
- // Edit: but these are also sometimes subtitles?
- //return null;
- }
-
- var stream = new MediaStream
- {
- Codec = streamInfo.codec_name,
- Profile = streamInfo.profile,
- Level = streamInfo.level,
- Index = streamInfo.index,
- PixelFormat = streamInfo.pix_fmt,
- NalLengthSize = streamInfo.nal_length_size,
- TimeBase = streamInfo.time_base,
- CodecTimeBase = streamInfo.codec_time_base
- };
-
- if (string.Equals(streamInfo.is_avc, "true", StringComparison.OrdinalIgnoreCase) ||
- string.Equals(streamInfo.is_avc, "1", StringComparison.OrdinalIgnoreCase))
- {
- stream.IsAVC = true;
- }
- else if (string.Equals(streamInfo.is_avc, "false", StringComparison.OrdinalIgnoreCase) ||
- string.Equals(streamInfo.is_avc, "0", StringComparison.OrdinalIgnoreCase))
- {
- stream.IsAVC = false;
- }
-
- if (!string.IsNullOrWhiteSpace(streamInfo.field_order) && !string.Equals(streamInfo.field_order, "progressive", StringComparison.OrdinalIgnoreCase))
- {
- stream.IsInterlaced = true;
- }
-
- // Filter out junk
- if (!string.IsNullOrWhiteSpace(streamInfo.codec_tag_string) && streamInfo.codec_tag_string.IndexOf("[0]", StringComparison.OrdinalIgnoreCase) == -1)
- {
- stream.CodecTag = streamInfo.codec_tag_string;
- }
-
- if (streamInfo.tags != null)
- {
- stream.Language = GetDictionaryValue(streamInfo.tags, "language");
- stream.Comment = GetDictionaryValue(streamInfo.tags, "comment");
- stream.Title = GetDictionaryValue(streamInfo.tags, "title");
- }
-
- if (string.Equals(streamInfo.codec_type, "audio", StringComparison.OrdinalIgnoreCase))
- {
- stream.Type = MediaStreamType.Audio;
-
- stream.Channels = streamInfo.channels;
-
- if (!string.IsNullOrEmpty(streamInfo.sample_rate))
- {
- int value;
- if (int.TryParse(streamInfo.sample_rate, NumberStyles.Any, _usCulture, out value))
- {
- stream.SampleRate = value;
- }
- }
-
- stream.ChannelLayout = ParseChannelLayout(streamInfo.channel_layout);
-
- if (streamInfo.bits_per_sample > 0)
- {
- stream.BitDepth = streamInfo.bits_per_sample;
- }
- else if (streamInfo.bits_per_raw_sample > 0)
- {
- stream.BitDepth = streamInfo.bits_per_raw_sample;
- }
- }
- else if (string.Equals(streamInfo.codec_type, "subtitle", StringComparison.OrdinalIgnoreCase))
- {
- stream.Type = MediaStreamType.Subtitle;
- stream.Codec = NormalizeSubtitleCodec(stream.Codec);
- }
- else if (string.Equals(streamInfo.codec_type, "video", StringComparison.OrdinalIgnoreCase))
- {
- stream.Type = isAudio || string.Equals(stream.Codec, "mjpeg", StringComparison.OrdinalIgnoreCase) || string.Equals(stream.Codec, "gif", StringComparison.OrdinalIgnoreCase) || string.Equals(stream.Codec, "png", StringComparison.OrdinalIgnoreCase)
- ? MediaStreamType.EmbeddedImage
- : MediaStreamType.Video;
-
- stream.AverageFrameRate = GetFrameRate(streamInfo.avg_frame_rate);
- stream.RealFrameRate = GetFrameRate(streamInfo.r_frame_rate);
-
- if (isAudio || string.Equals(stream.Codec, "gif", StringComparison.OrdinalIgnoreCase) ||
- string.Equals(stream.Codec, "png", StringComparison.OrdinalIgnoreCase))
- {
- stream.Type = MediaStreamType.EmbeddedImage;
- }
- else if (string.Equals(stream.Codec, "mjpeg", StringComparison.OrdinalIgnoreCase))
- {
- // How to differentiate between video and embedded image?
- // The only difference I've seen thus far is presence of codec tag, also embedded images have high (unusual) framerates
- if (!string.IsNullOrWhiteSpace(stream.CodecTag))
- {
- stream.Type = MediaStreamType.Video;
- }
- else
- {
- stream.Type = MediaStreamType.EmbeddedImage;
- }
- }
- else
- {
- stream.Type = MediaStreamType.Video;
- }
-
- stream.Width = streamInfo.width;
- stream.Height = streamInfo.height;
- stream.AspectRatio = GetAspectRatio(streamInfo);
-
- if (streamInfo.bits_per_sample > 0)
- {
- stream.BitDepth = streamInfo.bits_per_sample;
- }
- else if (streamInfo.bits_per_raw_sample > 0)
- {
- stream.BitDepth = streamInfo.bits_per_raw_sample;
- }
-
- //stream.IsAnamorphic = string.Equals(streamInfo.sample_aspect_ratio, "0:1", StringComparison.OrdinalIgnoreCase) ||
- // string.Equals(stream.AspectRatio, "2.35:1", StringComparison.OrdinalIgnoreCase) ||
- // string.Equals(stream.AspectRatio, "2.40:1", StringComparison.OrdinalIgnoreCase);
-
- // http://stackoverflow.com/questions/17353387/how-to-detect-anamorphic-video-with-ffprobe
- stream.IsAnamorphic = string.Equals(streamInfo.sample_aspect_ratio, "0:1", StringComparison.OrdinalIgnoreCase);
-
- if (streamInfo.refs > 0)
- {
- stream.RefFrames = streamInfo.refs;
- }
- }
- else
- {
- return null;
- }
-
- // Get stream bitrate
- var bitrate = 0;
-
- if (!string.IsNullOrEmpty(streamInfo.bit_rate))
- {
- int value;
- if (int.TryParse(streamInfo.bit_rate, NumberStyles.Any, _usCulture, out value))
- {
- bitrate = value;
- }
- }
-
- if (bitrate == 0 && formatInfo != null && !string.IsNullOrEmpty(formatInfo.bit_rate) && stream.Type == MediaStreamType.Video)
- {
- // If the stream info doesn't have a bitrate get the value from the media format info
- int value;
- if (int.TryParse(formatInfo.bit_rate, NumberStyles.Any, _usCulture, out value))
- {
- bitrate = value;
- }
- }
-
- if (bitrate > 0)
- {
- stream.BitRate = bitrate;
- }
-
- if (streamInfo.disposition != null)
- {
- var isDefault = GetDictionaryValue(streamInfo.disposition, "default");
- var isForced = GetDictionaryValue(streamInfo.disposition, "forced");
-
- stream.IsDefault = string.Equals(isDefault, "1", StringComparison.OrdinalIgnoreCase);
-
- stream.IsForced = string.Equals(isForced, "1", StringComparison.OrdinalIgnoreCase);
- }
-
- NormalizeStreamTitle(stream);
-
- return stream;
- }
-
- private void NormalizeStreamTitle(MediaStream stream)
- {
- if (string.Equals(stream.Title, "cc", StringComparison.OrdinalIgnoreCase))
- {
- stream.Title = null;
- }
-
- if (stream.Type == MediaStreamType.EmbeddedImage)
- {
- stream.Title = null;
- }
- }
-
- /// <summary>
- /// Gets a string from an FFProbeResult tags dictionary
- /// </summary>
- /// <param name="tags">The tags.</param>
- /// <param name="key">The key.</param>
- /// <returns>System.String.</returns>
- private string GetDictionaryValue(Dictionary<string, string> tags, string key)
- {
- if (tags == null)
- {
- return null;
- }
-
- string val;
-
- tags.TryGetValue(key, out val);
- return val;
- }
-
- private string ParseChannelLayout(string input)
- {
- if (string.IsNullOrEmpty(input))
- {
- return input;
- }
-
- return input.Split('(').FirstOrDefault();
- }
-
- private string GetAspectRatio(MediaStreamInfo info)
- {
- var original = info.display_aspect_ratio;
-
- int height;
- int width;
-
- var parts = (original ?? string.Empty).Split(':');
- if (!(parts.Length == 2 &&
- int.TryParse(parts[0], NumberStyles.Any, _usCulture, out width) &&
- int.TryParse(parts[1], NumberStyles.Any, _usCulture, out height) &&
- width > 0 &&
- height > 0))
- {
- width = info.width;
- height = info.height;
- }
-
- if (width > 0 && height > 0)
- {
- double ratio = width;
- ratio /= height;
-
- if (IsClose(ratio, 1.777777778, .03))
- {
- return "16:9";
- }
-
- if (IsClose(ratio, 1.3333333333, .05))
- {
- return "4:3";
- }
-
- if (IsClose(ratio, 1.41))
- {
- return "1.41:1";
- }
-
- if (IsClose(ratio, 1.5))
- {
- return "1.5:1";
- }
-
- if (IsClose(ratio, 1.6))
- {
- return "1.6:1";
- }
-
- if (IsClose(ratio, 1.66666666667))
- {
- return "5:3";
- }
-
- if (IsClose(ratio, 1.85, .02))
- {
- return "1.85:1";
- }
-
- if (IsClose(ratio, 2.35, .025))
- {
- return "2.35:1";
- }
-
- if (IsClose(ratio, 2.4, .025))
- {
- return "2.40:1";
- }
- }
-
- return original;
- }
-
- private bool IsClose(double d1, double d2, double variance = .005)
- {
- return Math.Abs(d1 - d2) <= variance;
- }
-
- /// <summary>
- /// Gets a frame rate from a string value in ffprobe output
- /// This could be a number or in the format of 2997/125.
- /// </summary>
- /// <param name="value">The value.</param>
- /// <returns>System.Nullable{System.Single}.</returns>
- private float? GetFrameRate(string value)
- {
- if (!string.IsNullOrEmpty(value))
- {
- var parts = value.Split('/');
-
- float result;
-
- if (parts.Length == 2)
- {
- result = float.Parse(parts[0], _usCulture) / float.Parse(parts[1], _usCulture);
- }
- else
- {
- result = float.Parse(parts[0], _usCulture);
- }
-
- return float.IsNaN(result) ? (float?)null : result;
- }
-
- return null;
- }
-
- private void SetAudioRuntimeTicks(InternalMediaInfoResult result, MediaInfo data)
- {
- if (result.streams != null)
- {
- // Get the first info stream
- var stream = result.streams.FirstOrDefault(s => string.Equals(s.codec_type, "audio", StringComparison.OrdinalIgnoreCase));
-
- if (stream != null)
- {
- // Get duration from stream properties
- var duration = stream.duration;
-
- // If it's not there go into format properties
- if (string.IsNullOrEmpty(duration))
- {
- duration = result.format.duration;
- }
-
- // If we got something, parse it
- if (!string.IsNullOrEmpty(duration))
- {
- data.RunTimeTicks = TimeSpan.FromSeconds(double.Parse(duration, _usCulture)).Ticks;
- }
- }
- }
- }
-
- private void SetSize(InternalMediaInfoResult data, Model.MediaInfo.MediaInfo info)
- {
- if (data.format != null)
- {
- if (!string.IsNullOrEmpty(data.format.size))
- {
- info.Size = long.Parse(data.format.size, _usCulture);
- }
- else
- {
- info.Size = null;
- }
- }
- }
-
- private void SetAudioInfoFromTags(MediaInfo audio, Dictionary<string, string> tags)
- {
- var composer = FFProbeHelpers.GetDictionaryValue(tags, "composer");
- if (!string.IsNullOrWhiteSpace(composer))
- {
- foreach (var person in Split(composer, false))
- {
- audio.People.Add(new BaseItemPerson { Name = person, Type = PersonType.Composer });
- }
- }
-
- //var conductor = FFProbeHelpers.GetDictionaryValue(tags, "conductor");
- //if (!string.IsNullOrWhiteSpace(conductor))
- //{
- // foreach (var person in Split(conductor, false))
- // {
- // audio.People.Add(new BaseItemPerson { Name = person, Type = PersonType.Conductor });
- // }
- //}
-
- //var lyricist = FFProbeHelpers.GetDictionaryValue(tags, "lyricist");
- //if (!string.IsNullOrWhiteSpace(lyricist))
- //{
- // foreach (var person in Split(lyricist, false))
- // {
- // audio.People.Add(new BaseItemPerson { Name = person, Type = PersonType.Lyricist });
- // }
- //}
-
- // Check for writer some music is tagged that way as alternative to composer/lyricist
- var writer = FFProbeHelpers.GetDictionaryValue(tags, "writer");
-
- if (!string.IsNullOrWhiteSpace(writer))
- {
- foreach (var person in Split(writer, false))
- {
- audio.People.Add(new BaseItemPerson { Name = person, Type = PersonType.Writer });
- }
- }
-
- audio.Album = FFProbeHelpers.GetDictionaryValue(tags, "album");
-
- var artists = FFProbeHelpers.GetDictionaryValue(tags, "artists");
-
- if (!string.IsNullOrWhiteSpace(artists))
- {
- audio.Artists = SplitArtists(artists, new[] { '/', ';' }, false)
- .DistinctNames()
- .ToList();
- }
- else
- {
- var artist = FFProbeHelpers.GetDictionaryValue(tags, "artist");
- if (string.IsNullOrWhiteSpace(artist))
- {
- audio.Artists.Clear();
- }
- else
- {
- audio.Artists = SplitArtists(artist, _nameDelimiters, true)
- .DistinctNames()
- .ToList();
- }
- }
-
- var albumArtist = FFProbeHelpers.GetDictionaryValue(tags, "albumartist");
- if (string.IsNullOrWhiteSpace(albumArtist))
- {
- albumArtist = FFProbeHelpers.GetDictionaryValue(tags, "album artist");
- }
- if (string.IsNullOrWhiteSpace(albumArtist))
- {
- albumArtist = FFProbeHelpers.GetDictionaryValue(tags, "album_artist");
- }
-
- if (string.IsNullOrWhiteSpace(albumArtist))
- {
- audio.AlbumArtists = new List<string>();
- }
- else
- {
- audio.AlbumArtists = SplitArtists(albumArtist, _nameDelimiters, true)
- .DistinctNames()
- .ToList();
-
- }
-
- if (audio.AlbumArtists.Count == 0)
- {
- audio.AlbumArtists = audio.Artists.Take(1).ToList();
- }
-
- // Track number
- audio.IndexNumber = GetDictionaryDiscValue(tags, "track");
-
- // Disc number
- audio.ParentIndexNumber = GetDictionaryDiscValue(tags, "disc");
-
- // If we don't have a ProductionYear try and get it from PremiereDate
- if (audio.PremiereDate.HasValue && !audio.ProductionYear.HasValue)
- {
- audio.ProductionYear = audio.PremiereDate.Value.ToLocalTime().Year;
- }
-
- // There's several values in tags may or may not be present
- FetchStudios(audio, tags, "organization");
- FetchStudios(audio, tags, "ensemble");
- FetchStudios(audio, tags, "publisher");
- FetchStudios(audio, tags, "label");
-
- // These support mulitple values, but for now we only store the first.
- var mb = GetMultipleMusicBrainzId(FFProbeHelpers.GetDictionaryValue(tags, "MusicBrainz Album Artist Id"));
- if (mb == null) mb = GetMultipleMusicBrainzId(FFProbeHelpers.GetDictionaryValue(tags, "MUSICBRAINZ_ALBUMARTISTID"));
- audio.SetProviderId(MetadataProviders.MusicBrainzAlbumArtist, mb);
-
- mb = GetMultipleMusicBrainzId(FFProbeHelpers.GetDictionaryValue(tags, "MusicBrainz Artist Id"));
- if (mb == null) mb = GetMultipleMusicBrainzId(FFProbeHelpers.GetDictionaryValue(tags, "MUSICBRAINZ_ARTISTID"));
- audio.SetProviderId(MetadataProviders.MusicBrainzArtist, mb);
-
- mb = GetMultipleMusicBrainzId(FFProbeHelpers.GetDictionaryValue(tags, "MusicBrainz Album Id"));
- if (mb == null) mb = GetMultipleMusicBrainzId(FFProbeHelpers.GetDictionaryValue(tags, "MUSICBRAINZ_ALBUMID"));
- audio.SetProviderId(MetadataProviders.MusicBrainzAlbum, mb);
-
- mb = GetMultipleMusicBrainzId(FFProbeHelpers.GetDictionaryValue(tags, "MusicBrainz Release Group Id"));
- if (mb == null) mb = GetMultipleMusicBrainzId(FFProbeHelpers.GetDictionaryValue(tags, "MUSICBRAINZ_RELEASEGROUPID"));
- audio.SetProviderId(MetadataProviders.MusicBrainzReleaseGroup, mb);
-
- mb = GetMultipleMusicBrainzId(FFProbeHelpers.GetDictionaryValue(tags, "MusicBrainz Release Track Id"));
- if (mb == null) mb = GetMultipleMusicBrainzId(FFProbeHelpers.GetDictionaryValue(tags, "MUSICBRAINZ_RELEASETRACKID"));
- audio.SetProviderId(MetadataProviders.MusicBrainzTrack, mb);
- }
-
- private string GetMultipleMusicBrainzId(string value)
- {
- if (string.IsNullOrWhiteSpace(value))
- {
- return null;
- }
-
- return value.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries)
- .Select(i => i.Trim())
- .FirstOrDefault(i => !string.IsNullOrWhiteSpace(i));
- }
-
- private readonly char[] _nameDelimiters = { '/', '|', ';', '\\' };
-
- /// <summary>
- /// Splits the specified val.
- /// </summary>
- /// <param name="val">The val.</param>
- /// <param name="allowCommaDelimiter">if set to <c>true</c> [allow comma delimiter].</param>
- /// <returns>System.String[][].</returns>
- private IEnumerable<string> Split(string val, bool allowCommaDelimiter)
- {
- // Only use the comma as a delimeter if there are no slashes or pipes.
- // We want to be careful not to split names that have commas in them
- var delimeter = !allowCommaDelimiter || _nameDelimiters.Any(i => val.IndexOf(i) != -1) ?
- _nameDelimiters :
- new[] { ',' };
-
- return val.Split(delimeter, StringSplitOptions.RemoveEmptyEntries)
- .Where(i => !string.IsNullOrWhiteSpace(i))
- .Select(i => i.Trim());
- }
-
- private const string ArtistReplaceValue = " | ";
-
- private IEnumerable<string> SplitArtists(string val, char[] delimiters, bool splitFeaturing)
- {
- if (splitFeaturing)
- {
- val = val.Replace(" featuring ", ArtistReplaceValue, StringComparison.OrdinalIgnoreCase)
- .Replace(" feat. ", ArtistReplaceValue, StringComparison.OrdinalIgnoreCase);
- }
-
- var artistsFound = new List<string>();
-
- foreach (var whitelistArtist in GetSplitWhitelist())
- {
- var originalVal = val;
- val = val.Replace(whitelistArtist, "|", StringComparison.OrdinalIgnoreCase);
-
- if (!string.Equals(originalVal, val, StringComparison.OrdinalIgnoreCase))
- {
- artistsFound.Add(whitelistArtist);
- }
- }
-
- var artists = val.Split(delimiters, StringSplitOptions.RemoveEmptyEntries)
- .Where(i => !string.IsNullOrWhiteSpace(i))
- .Select(i => i.Trim());
-
- artistsFound.AddRange(artists);
- return artistsFound;
- }
-
-
- private List<string> _splitWhiteList = null;
-
- private IEnumerable<string> GetSplitWhitelist()
- {
- if (_splitWhiteList == null)
- {
- _splitWhiteList = new List<string>
- {
- "AC/DC"
- };
- }
-
- return _splitWhiteList;
- }
-
- /// <summary>
- /// Gets the studios from the tags collection
- /// </summary>
- /// <param name="info">The info.</param>
- /// <param name="tags">The tags.</param>
- /// <param name="tagName">Name of the tag.</param>
- private void FetchStudios(MediaInfo info, Dictionary<string, string> tags, string tagName)
- {
- var val = FFProbeHelpers.GetDictionaryValue(tags, tagName);
-
- if (!string.IsNullOrEmpty(val))
- {
- var studios = Split(val, true);
-
- foreach (var studio in studios)
- {
- // Sometimes the artist name is listed here, account for that
- if (info.Artists.Contains(studio, StringComparer.OrdinalIgnoreCase))
- {
- continue;
- }
- if (info.AlbumArtists.Contains(studio, StringComparer.OrdinalIgnoreCase))
- {
- continue;
- }
-
- info.Studios.Add(studio);
- }
-
- info.Studios = info.Studios
- .Where(i => !string.IsNullOrWhiteSpace(i))
- .Distinct(StringComparer.OrdinalIgnoreCase)
- .ToList();
- }
- }
-
- /// <summary>
- /// Gets the genres from the tags collection
- /// </summary>
- /// <param name="info">The information.</param>
- /// <param name="tags">The tags.</param>
- private void FetchGenres(MediaInfo info, Dictionary<string, string> tags)
- {
- var val = FFProbeHelpers.GetDictionaryValue(tags, "genre");
-
- if (!string.IsNullOrEmpty(val))
- {
- foreach (var genre in Split(val, true))
- {
- info.Genres.Add(genre);
- }
-
- info.Genres = info.Genres
- .Where(i => !string.IsNullOrWhiteSpace(i))
- .Distinct(StringComparer.OrdinalIgnoreCase)
- .ToList();
- }
- }
-
- /// <summary>
- /// Gets the disc number, which is sometimes can be in the form of '1', or '1/3'
- /// </summary>
- /// <param name="tags">The tags.</param>
- /// <param name="tagName">Name of the tag.</param>
- /// <returns>System.Nullable{System.Int32}.</returns>
- private int? GetDictionaryDiscValue(Dictionary<string, string> tags, string tagName)
- {
- var disc = FFProbeHelpers.GetDictionaryValue(tags, tagName);
-
- if (!string.IsNullOrEmpty(disc))
- {
- disc = disc.Split('/')[0];
-
- int num;
-
- if (int.TryParse(disc, out num))
- {
- return num;
- }
- }
-
- return null;
- }
-
- private ChapterInfo GetChapterInfo(MediaChapter chapter)
- {
- var info = new ChapterInfo();
-
- if (chapter.tags != null)
- {
- string name;
- if (chapter.tags.TryGetValue("title", out name))
- {
- info.Name = name;
- }
- }
-
- // Limit accuracy to milliseconds to match xml saving
- var secondsString = chapter.start_time;
- double seconds;
-
- if (double.TryParse(secondsString, NumberStyles.Any, CultureInfo.InvariantCulture, out seconds))
- {
- var ms = Math.Round(TimeSpan.FromSeconds(seconds).TotalMilliseconds);
- info.StartPositionTicks = TimeSpan.FromMilliseconds(ms).Ticks;
- }
-
- return info;
- }
-
- private const int MaxSubtitleDescriptionExtractionLength = 100; // When extracting subtitles, the maximum length to consider (to avoid invalid filenames)
-
- private void FetchWtvInfo(MediaInfo video, InternalMediaInfoResult data)
- {
- if (data.format == null || data.format.tags == null)
- {
- return;
- }
-
- var genres = FFProbeHelpers.GetDictionaryValue(data.format.tags, "WM/Genre");
-
- if (!string.IsNullOrWhiteSpace(genres))
- {
- var genreList = genres.Split(new[] { ';', '/', ',' }, StringSplitOptions.RemoveEmptyEntries)
- .Where(i => !string.IsNullOrWhiteSpace(i))
- .Select(i => i.Trim())
- .ToList();
-
- // If this is empty then don't overwrite genres that might have been fetched earlier
- if (genreList.Count > 0)
- {
- video.Genres = genreList;
- }
- }
-
- var officialRating = FFProbeHelpers.GetDictionaryValue(data.format.tags, "WM/ParentalRating");
-
- if (!string.IsNullOrWhiteSpace(officialRating))
- {
- video.OfficialRating = officialRating;
- }
-
- var people = FFProbeHelpers.GetDictionaryValue(data.format.tags, "WM/MediaCredits");
-
- if (!string.IsNullOrEmpty(people))
- {
- video.People = people.Split(new[] { ';', '/' }, StringSplitOptions.RemoveEmptyEntries)
- .Where(i => !string.IsNullOrWhiteSpace(i))
- .Select(i => new BaseItemPerson { Name = i.Trim(), Type = PersonType.Actor })
- .ToList();
- }
-
- var year = FFProbeHelpers.GetDictionaryValue(data.format.tags, "WM/OriginalReleaseTime");
- if (!string.IsNullOrWhiteSpace(year))
- {
- int val;
-
- if (int.TryParse(year, NumberStyles.Integer, _usCulture, out val))
- {
- video.ProductionYear = val;
- }
- }
-
- var premiereDateString = FFProbeHelpers.GetDictionaryValue(data.format.tags, "WM/MediaOriginalBroadcastDateTime");
- if (!string.IsNullOrWhiteSpace(premiereDateString))
- {
- DateTime val;
-
- // Credit to MCEBuddy: https://mcebuddy2x.codeplex.com/
- // DateTime is reported along with timezone info (typically Z i.e. UTC hence assume None)
- if (DateTime.TryParse(year, null, DateTimeStyles.None, out val))
- {
- video.PremiereDate = val.ToUniversalTime();
- }
- }
-
- var description = FFProbeHelpers.GetDictionaryValue(data.format.tags, "WM/SubTitleDescription");
-
- var subTitle = FFProbeHelpers.GetDictionaryValue(data.format.tags, "WM/SubTitle");
-
- // For below code, credit to MCEBuddy: https://mcebuddy2x.codeplex.com/
-
- // Sometimes for TV Shows the Subtitle field is empty and the subtitle description contains the subtitle, extract if possible. See ticket https://mcebuddy2x.codeplex.com/workitem/1910
- // The format is -> EPISODE/TOTAL_EPISODES_IN_SEASON. SUBTITLE: DESCRIPTION
- // OR -> COMMENT. SUBTITLE: DESCRIPTION
- // e.g. -> 4/13. The Doctor's Wife: Science fiction drama. When he follows a Time Lord distress signal, the Doctor puts Amy, Rory and his beloved TARDIS in grave danger. Also in HD. [AD,S]
- // e.g. -> CBeebies Bedtime Hour. The Mystery: Animated adventures of two friends who live on an island in the middle of the big city. Some of Abney and Teal's favourite objects are missing. [S]
- if (String.IsNullOrWhiteSpace(subTitle) && !String.IsNullOrWhiteSpace(description) && description.Substring(0, Math.Min(description.Length, MaxSubtitleDescriptionExtractionLength)).Contains(":")) // Check within the Subtitle size limit, otherwise from description it can get too long creating an invalid filename
- {
- string[] parts = description.Split(':');
- if (parts.Length > 0)
- {
- string subtitle = parts[0];
- try
- {
- if (subtitle.Contains("/")) // It contains a episode number and season number
- {
- string[] numbers = subtitle.Split(' ');
- video.IndexNumber = int.Parse(numbers[0].Replace(".", "").Split('/')[0]);
- int totalEpisodesInSeason = int.Parse(numbers[0].Replace(".", "").Split('/')[1]);
-
- description = String.Join(" ", numbers, 1, numbers.Length - 1).Trim(); // Skip the first, concatenate the rest, clean up spaces and save it
- }
- else
- throw new Exception(); // Switch to default parsing
- }
- catch // Default parsing
- {
- if (subtitle.Contains(".")) // skip the comment, keep the subtitle
- description = String.Join(".", subtitle.Split('.'), 1, subtitle.Split('.').Length - 1).Trim(); // skip the first
- else
- description = subtitle.Trim(); // Clean up whitespaces and save it
- }
- }
- }
-
- if (!string.IsNullOrWhiteSpace(description))
- {
- video.Overview = description;
- }
- }
-
- private void ExtractTimestamp(MediaInfo video)
- {
- if (video.VideoType == VideoType.VideoFile)
- {
- if (string.Equals(video.Container, "mpeg2ts", StringComparison.OrdinalIgnoreCase) ||
- string.Equals(video.Container, "m2ts", StringComparison.OrdinalIgnoreCase) ||
- string.Equals(video.Container, "ts", StringComparison.OrdinalIgnoreCase))
- {
- try
- {
- video.Timestamp = GetMpegTimestamp(video.Path);
-
- _logger.Debug("Video has {0} timestamp", video.Timestamp);
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error extracting timestamp info from {0}", ex, video.Path);
- video.Timestamp = null;
- }
- }
- }
- }
-
- private TransportStreamTimestamp GetMpegTimestamp(string path)
- {
- var packetBuffer = new byte['Å'];
-
- using (var fs = _fileSystem.GetFileStream(path, FileOpenMode.Open, FileAccessMode.Read, FileShareMode.Read))
- {
- fs.Read(packetBuffer, 0, packetBuffer.Length);
- }
-
- if (packetBuffer[0] == 71)
- {
- return TransportStreamTimestamp.None;
- }
-
- if ((packetBuffer[4] == 71) && (packetBuffer['Ä'] == 71))
- {
- if ((packetBuffer[0] == 0) && (packetBuffer[1] == 0) && (packetBuffer[2] == 0) && (packetBuffer[3] == 0))
- {
- return TransportStreamTimestamp.Zero;
- }
-
- return TransportStreamTimestamp.Valid;
- }
-
- return TransportStreamTimestamp.None;
- }
- }
-}
diff --git a/MediaBrowser.MediaEncoding/Properties/AssemblyInfo.cs b/MediaBrowser.MediaEncoding/Properties/AssemblyInfo.cs
deleted file mode 100644
index 53f4eb403..000000000
--- a/MediaBrowser.MediaEncoding/Properties/AssemblyInfo.cs
+++ /dev/null
@@ -1,33 +0,0 @@
-using System.Reflection;
-using System.Runtime.InteropServices;
-
-// General Information about an assembly is controlled through the following
-// set of attributes. Change these attribute values to modify the information
-// associated with an assembly.
-[assembly: AssemblyTitle("MediaBrowser.MediaEncoding")]
-[assembly: AssemblyDescription("")]
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("")]
-[assembly: AssemblyProduct("MediaBrowser.MediaEncoding")]
-[assembly: AssemblyCopyright("Copyright © 2014")]
-[assembly: AssemblyTrademark("")]
-[assembly: AssemblyCulture("")]
-
-// Setting ComVisible to false makes the types in this assembly not visible
-// to COM components. If you need to access a type in this assembly from
-// COM, set the ComVisible attribute to true on that type.
-[assembly: ComVisible(false)]
-
-// The following GUID is for the ID of the typelib if this project is exposed to COM
-[assembly: Guid("05f49ab9-2a90-4332-9d41-7817a9cccd90")]
-
-// Version information for an assembly consists of the following four values:
-//
-// Major Version
-// Minor Version
-// Build Number
-// Revision
-//
-// You can specify all the values or you can default the Build and Revision Numbers
-// by using the '*' as shown below:
-// [assembly: AssemblyVersion("1.0.*")] \ No newline at end of file
diff --git a/MediaBrowser.MediaEncoding/Subtitles/AssParser.cs b/MediaBrowser.MediaEncoding/Subtitles/AssParser.cs
deleted file mode 100644
index 6d723a087..000000000
--- a/MediaBrowser.MediaEncoding/Subtitles/AssParser.cs
+++ /dev/null
@@ -1,120 +0,0 @@
-using MediaBrowser.Model.Extensions;
-using System;
-using System.Collections.Generic;
-using System.Globalization;
-using System.IO;
-using System.Linq;
-using System.Text.RegularExpressions;
-using System.Threading;
-using MediaBrowser.Model.MediaInfo;
-
-namespace MediaBrowser.MediaEncoding.Subtitles
-{
- public class AssParser : ISubtitleParser
- {
- private readonly CultureInfo _usCulture = new CultureInfo("en-US");
-
- public SubtitleTrackInfo Parse(Stream stream, CancellationToken cancellationToken)
- {
- var trackInfo = new SubtitleTrackInfo();
- var eventIndex = 1;
- using (var reader = new StreamReader(stream))
- {
- string line;
- while (reader.ReadLine() != "[Events]")
- {}
- var headers = ParseFieldHeaders(reader.ReadLine());
-
- while ((line = reader.ReadLine()) != null)
- {
- cancellationToken.ThrowIfCancellationRequested();
-
- if (string.IsNullOrWhiteSpace(line))
- {
- continue;
- }
- if(line.StartsWith("["))
- break;
- if(string.IsNullOrEmpty(line))
- continue;
- var subEvent = new SubtitleTrackEvent { Id = eventIndex.ToString(_usCulture) };
- eventIndex++;
- var sections = line.Substring(10).Split(',');
-
- subEvent.StartPositionTicks = GetTicks(sections[headers["Start"]]);
- subEvent.EndPositionTicks = GetTicks(sections[headers["End"]]);
-
- subEvent.Text = string.Join(",", sections.Skip(headers["Text"]));
- RemoteNativeFormatting(subEvent);
-
- subEvent.Text = subEvent.Text.Replace("\\n", ParserValues.NewLine, StringComparison.OrdinalIgnoreCase);
-
- subEvent.Text = Regex.Replace(subEvent.Text, @"\{(\\[\w]+\(?([\w\d]+,?)+\)?)+\}", string.Empty, RegexOptions.IgnoreCase);
-
- trackInfo.TrackEvents.Add(subEvent);
- }
- }
- return trackInfo;
- }
-
- long GetTicks(string time)
- {
- TimeSpan span;
- return TimeSpan.TryParseExact(time, @"h\:mm\:ss\.ff", _usCulture, out span)
- ? span.Ticks: 0;
- }
-
- private Dictionary<string,int> ParseFieldHeaders(string line) {
- var fields = line.Substring(8).Split(',').Select(x=>x.Trim()).ToList();
-
- var result = new Dictionary<string, int> {
- {"Start", fields.IndexOf("Start")},
- {"End", fields.IndexOf("End")},
- {"Text", fields.IndexOf("Text")}
- };
- return result;
- }
-
- /// <summary>
- /// Credit: https://github.com/SubtitleEdit/subtitleedit/blob/master/src/Logic/SubtitleFormats/AdvancedSubStationAlpha.cs
- /// </summary>
- private void RemoteNativeFormatting(SubtitleTrackEvent p)
- {
- int indexOfBegin = p.Text.IndexOf('{');
- string pre = string.Empty;
- while (indexOfBegin >= 0 && p.Text.IndexOf('}') > indexOfBegin)
- {
- string s = p.Text.Substring(indexOfBegin);
- if (s.StartsWith("{\\an1}", StringComparison.Ordinal) ||
- s.StartsWith("{\\an2}", StringComparison.Ordinal) ||
- s.StartsWith("{\\an3}", StringComparison.Ordinal) ||
- s.StartsWith("{\\an4}", StringComparison.Ordinal) ||
- s.StartsWith("{\\an5}", StringComparison.Ordinal) ||
- s.StartsWith("{\\an6}", StringComparison.Ordinal) ||
- s.StartsWith("{\\an7}", StringComparison.Ordinal) ||
- s.StartsWith("{\\an8}", StringComparison.Ordinal) ||
- s.StartsWith("{\\an9}", StringComparison.Ordinal))
- {
- pre = s.Substring(0, 6);
- }
- else if (s.StartsWith("{\\an1\\", StringComparison.Ordinal) ||
- s.StartsWith("{\\an2\\", StringComparison.Ordinal) ||
- s.StartsWith("{\\an3\\", StringComparison.Ordinal) ||
- s.StartsWith("{\\an4\\", StringComparison.Ordinal) ||
- s.StartsWith("{\\an5\\", StringComparison.Ordinal) ||
- s.StartsWith("{\\an6\\", StringComparison.Ordinal) ||
- s.StartsWith("{\\an7\\", StringComparison.Ordinal) ||
- s.StartsWith("{\\an8\\", StringComparison.Ordinal) ||
- s.StartsWith("{\\an9\\", StringComparison.Ordinal))
- {
- pre = s.Substring(0, 5) + "}";
- }
- int indexOfEnd = p.Text.IndexOf('}');
- p.Text = p.Text.Remove(indexOfBegin, (indexOfEnd - indexOfBegin) + 1);
-
- indexOfBegin = p.Text.IndexOf('{');
- }
- p.Text = pre + p.Text;
- }
- }
-}
diff --git a/MediaBrowser.MediaEncoding/Subtitles/ConfigurationExtension.cs b/MediaBrowser.MediaEncoding/Subtitles/ConfigurationExtension.cs
deleted file mode 100644
index 973c653a4..000000000
--- a/MediaBrowser.MediaEncoding/Subtitles/ConfigurationExtension.cs
+++ /dev/null
@@ -1,29 +0,0 @@
-using System.Collections.Generic;
-using MediaBrowser.Common.Configuration;
-using MediaBrowser.Model.Providers;
-
-namespace MediaBrowser.MediaEncoding.Subtitles
-{
- public static class ConfigurationExtension
- {
- public static SubtitleOptions GetSubtitleConfiguration(this IConfigurationManager manager)
- {
- return manager.GetConfiguration<SubtitleOptions>("subtitles");
- }
- }
-
- public class SubtitleConfigurationFactory : IConfigurationFactory
- {
- public IEnumerable<ConfigurationStore> GetConfigurations()
- {
- return new List<ConfigurationStore>
- {
- new ConfigurationStore
- {
- Key = "subtitles",
- ConfigurationType = typeof (SubtitleOptions)
- }
- };
- }
- }
-}
diff --git a/MediaBrowser.MediaEncoding/Subtitles/ISubtitleParser.cs b/MediaBrowser.MediaEncoding/Subtitles/ISubtitleParser.cs
deleted file mode 100644
index 75de81f46..000000000
--- a/MediaBrowser.MediaEncoding/Subtitles/ISubtitleParser.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-using System.IO;
-using System.Threading;
-using MediaBrowser.Model.MediaInfo;
-
-namespace MediaBrowser.MediaEncoding.Subtitles
-{
- public interface ISubtitleParser
- {
- /// <summary>
- /// Parses the specified stream.
- /// </summary>
- /// <param name="stream">The stream.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>SubtitleTrackInfo.</returns>
- SubtitleTrackInfo Parse(Stream stream, CancellationToken cancellationToken);
- }
-}
diff --git a/MediaBrowser.MediaEncoding/Subtitles/ISubtitleWriter.cs b/MediaBrowser.MediaEncoding/Subtitles/ISubtitleWriter.cs
deleted file mode 100644
index e28da9185..000000000
--- a/MediaBrowser.MediaEncoding/Subtitles/ISubtitleWriter.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-using System.IO;
-using System.Threading;
-using MediaBrowser.Model.MediaInfo;
-
-namespace MediaBrowser.MediaEncoding.Subtitles
-{
- /// <summary>
- /// Interface ISubtitleWriter
- /// </summary>
- public interface ISubtitleWriter
- {
- /// <summary>
- /// Writes the specified information.
- /// </summary>
- /// <param name="info">The information.</param>
- /// <param name="stream">The stream.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- void Write(SubtitleTrackInfo info, Stream stream, CancellationToken cancellationToken);
- }
-}
diff --git a/MediaBrowser.MediaEncoding/Subtitles/JsonWriter.cs b/MediaBrowser.MediaEncoding/Subtitles/JsonWriter.cs
deleted file mode 100644
index 474f712f9..000000000
--- a/MediaBrowser.MediaEncoding/Subtitles/JsonWriter.cs
+++ /dev/null
@@ -1,28 +0,0 @@
-using MediaBrowser.Model.MediaInfo;
-using MediaBrowser.Model.Serialization;
-using System.IO;
-using System.Text;
-using System.Threading;
-
-namespace MediaBrowser.MediaEncoding.Subtitles
-{
- public class JsonWriter : ISubtitleWriter
- {
- private readonly IJsonSerializer _json;
-
- public JsonWriter(IJsonSerializer json)
- {
- _json = json;
- }
-
- public void Write(SubtitleTrackInfo info, Stream stream, CancellationToken cancellationToken)
- {
- using (var writer = new StreamWriter(stream, Encoding.UTF8, 1024, true))
- {
- var json = _json.SerializeToString(info);
-
- writer.Write(json);
- }
- }
- }
-}
diff --git a/MediaBrowser.MediaEncoding/Subtitles/OpenSubtitleDownloader.cs b/MediaBrowser.MediaEncoding/Subtitles/OpenSubtitleDownloader.cs
deleted file mode 100644
index 3954897ca..000000000
--- a/MediaBrowser.MediaEncoding/Subtitles/OpenSubtitleDownloader.cs
+++ /dev/null
@@ -1,349 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Globalization;
-using System.IO;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Common.Configuration;
-using MediaBrowser.Common.Extensions;
-using MediaBrowser.Common.Net;
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Providers;
-using MediaBrowser.Controller.Security;
-using MediaBrowser.Controller.Subtitles;
-using MediaBrowser.Model.Dto;
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Model.Logging;
-using MediaBrowser.Model.Providers;
-using MediaBrowser.Model.Serialization;
-using OpenSubtitlesHandler;
-
-namespace MediaBrowser.MediaEncoding.Subtitles
-{
- public class OpenSubtitleDownloader : ISubtitleProvider, IDisposable
- {
- private readonly ILogger _logger;
- private readonly IHttpClient _httpClient;
- private readonly CultureInfo _usCulture = new CultureInfo("en-US");
-
- private readonly IServerConfigurationManager _config;
- private readonly IEncryptionManager _encryption;
-
- private readonly IJsonSerializer _json;
- private readonly IFileSystem _fileSystem;
-
- public OpenSubtitleDownloader(ILogManager logManager, IHttpClient httpClient, IServerConfigurationManager config, IEncryptionManager encryption, IJsonSerializer json, IFileSystem fileSystem)
- {
- _logger = logManager.GetLogger(GetType().Name);
- _httpClient = httpClient;
- _config = config;
- _encryption = encryption;
- _json = json;
- _fileSystem = fileSystem;
-
- _config.NamedConfigurationUpdating += _config_NamedConfigurationUpdating;
-
- Utilities.HttpClient = httpClient;
- OpenSubtitles.SetUserAgent("mediabrowser.tv");
- }
-
- private const string PasswordHashPrefix = "h:";
- void _config_NamedConfigurationUpdating(object sender, ConfigurationUpdateEventArgs e)
- {
- if (!string.Equals(e.Key, "subtitles", StringComparison.OrdinalIgnoreCase))
- {
- return;
- }
-
- var options = (SubtitleOptions)e.NewConfiguration;
-
- if (options != null &&
- !string.IsNullOrWhiteSpace(options.OpenSubtitlesPasswordHash) &&
- !options.OpenSubtitlesPasswordHash.StartsWith(PasswordHashPrefix, StringComparison.OrdinalIgnoreCase))
- {
- options.OpenSubtitlesPasswordHash = EncryptPassword(options.OpenSubtitlesPasswordHash);
- }
- }
-
- private string EncryptPassword(string password)
- {
- return PasswordHashPrefix + _encryption.EncryptString(password);
- }
-
- private string DecryptPassword(string password)
- {
- if (password == null ||
- !password.StartsWith(PasswordHashPrefix, StringComparison.OrdinalIgnoreCase))
- {
- return string.Empty;
- }
-
- return _encryption.DecryptString(password.Substring(2));
- }
-
- public string Name
- {
- get { return "Open Subtitles"; }
- }
-
- private SubtitleOptions GetOptions()
- {
- return _config.GetSubtitleConfiguration();
- }
-
- public IEnumerable<VideoContentType> SupportedMediaTypes
- {
- get
- {
- var options = GetOptions();
-
- if (string.IsNullOrWhiteSpace(options.OpenSubtitlesUsername) ||
- string.IsNullOrWhiteSpace(options.OpenSubtitlesPasswordHash))
- {
- return new VideoContentType[] { };
- }
-
- return new[] { VideoContentType.Episode, VideoContentType.Movie };
- }
- }
-
- public Task<SubtitleResponse> GetSubtitles(string id, CancellationToken cancellationToken)
- {
- return GetSubtitlesInternal(id, GetOptions(), cancellationToken);
- }
-
- private DateTime _lastRateLimitException;
- private async Task<SubtitleResponse> GetSubtitlesInternal(string id,
- SubtitleOptions options,
- CancellationToken cancellationToken)
- {
- if (string.IsNullOrWhiteSpace(id))
- {
- throw new ArgumentNullException("id");
- }
-
- var idParts = id.Split(new[] { '-' }, 3);
-
- var format = idParts[0];
- var language = idParts[1];
- var ossId = idParts[2];
-
- var downloadsList = new[] { int.Parse(ossId, _usCulture) };
-
- await Login(cancellationToken).ConfigureAwait(false);
-
- if ((DateTime.UtcNow - _lastRateLimitException).TotalHours < 1)
- {
- throw new RateLimitExceededException("OpenSubtitles rate limit reached");
- }
-
- var resultDownLoad = await OpenSubtitles.DownloadSubtitlesAsync(downloadsList, cancellationToken).ConfigureAwait(false);
-
- if ((resultDownLoad.Status ?? string.Empty).IndexOf("407", StringComparison.OrdinalIgnoreCase) != -1)
- {
- _lastRateLimitException = DateTime.UtcNow;
- throw new RateLimitExceededException("OpenSubtitles rate limit reached");
- }
-
- if (!(resultDownLoad is MethodResponseSubtitleDownload))
- {
- throw new Exception("Invalid response type");
- }
-
- var results = ((MethodResponseSubtitleDownload)resultDownLoad).Results;
-
- _lastRateLimitException = DateTime.MinValue;
-
- if (results.Count == 0)
- {
- var msg = string.Format("Subtitle with Id {0} was not found. Name: {1}. Status: {2}. Message: {3}",
- ossId,
- resultDownLoad.Name ?? string.Empty,
- resultDownLoad.Status ?? string.Empty,
- resultDownLoad.Message ?? string.Empty);
-
- throw new ResourceNotFoundException(msg);
- }
-
- var data = Convert.FromBase64String(results.First().Data);
-
- return new SubtitleResponse
- {
- Format = format,
- Language = language,
-
- Stream = new MemoryStream(Utilities.Decompress(new MemoryStream(data)))
- };
- }
-
- private DateTime _lastLogin;
- private async Task Login(CancellationToken cancellationToken)
- {
- if ((DateTime.UtcNow - _lastLogin).TotalSeconds < 60)
- {
- return;
- }
-
- var options = GetOptions();
-
- var user = options.OpenSubtitlesUsername ?? string.Empty;
- var password = DecryptPassword(options.OpenSubtitlesPasswordHash);
-
- var loginResponse = await OpenSubtitles.LogInAsync(user, password, "en", cancellationToken).ConfigureAwait(false);
-
- if (!(loginResponse is MethodResponseLogIn))
- {
- throw new Exception("Authentication to OpenSubtitles failed.");
- }
-
- _lastLogin = DateTime.UtcNow;
- }
-
- public async Task<IEnumerable<NameIdPair>> GetSupportedLanguages(CancellationToken cancellationToken)
- {
- await Login(cancellationToken).ConfigureAwait(false);
-
- var result = OpenSubtitles.GetSubLanguages("en");
- if (!(result is MethodResponseGetSubLanguages))
- {
- _logger.Error("Invalid response type");
- return new List<NameIdPair>();
- }
-
- var results = ((MethodResponseGetSubLanguages)result).Languages;
-
- return results.Select(i => new NameIdPair
- {
- Name = i.LanguageName,
- Id = i.SubLanguageID
- });
- }
-
- private string NormalizeLanguage(string language)
- {
- // Problem with Greek subtitle download #1349
- if (string.Equals(language, "gre", StringComparison.OrdinalIgnoreCase))
- {
-
- return "ell";
- }
-
- return language;
- }
-
- public async Task<IEnumerable<RemoteSubtitleInfo>> Search(SubtitleSearchRequest request, CancellationToken cancellationToken)
- {
- var imdbIdText = request.GetProviderId(MetadataProviders.Imdb);
- long imdbId = 0;
-
- switch (request.ContentType)
- {
- case VideoContentType.Episode:
- if (!request.IndexNumber.HasValue || !request.ParentIndexNumber.HasValue || string.IsNullOrEmpty(request.SeriesName))
- {
- _logger.Debug("Episode information missing");
- return new List<RemoteSubtitleInfo>();
- }
- break;
- case VideoContentType.Movie:
- if (string.IsNullOrEmpty(request.Name))
- {
- _logger.Debug("Movie name missing");
- return new List<RemoteSubtitleInfo>();
- }
- if (string.IsNullOrWhiteSpace(imdbIdText) || !long.TryParse(imdbIdText.TrimStart('t'), NumberStyles.Any, _usCulture, out imdbId))
- {
- _logger.Debug("Imdb id missing");
- return new List<RemoteSubtitleInfo>();
- }
- break;
- }
-
- if (string.IsNullOrEmpty(request.MediaPath))
- {
- _logger.Debug("Path Missing");
- return new List<RemoteSubtitleInfo>();
- }
-
- await Login(cancellationToken).ConfigureAwait(false);
-
- var subLanguageId = NormalizeLanguage(request.Language);
- string hash;
-
- using (var fileStream = _fileSystem.OpenRead(request.MediaPath))
- {
- hash = Utilities.ComputeHash(fileStream);
- }
- var fileInfo = _fileSystem.GetFileInfo(request.MediaPath);
- var movieByteSize = fileInfo.Length;
- var searchImdbId = request.ContentType == VideoContentType.Movie ? imdbId.ToString(_usCulture) : "";
- var subtitleSearchParameters = request.ContentType == VideoContentType.Episode
- ? new List<SubtitleSearchParameters> {
- new SubtitleSearchParameters(subLanguageId,
- query: request.SeriesName,
- season: request.ParentIndexNumber.Value.ToString(_usCulture),
- episode: request.IndexNumber.Value.ToString(_usCulture))
- }
- : new List<SubtitleSearchParameters> {
- new SubtitleSearchParameters(subLanguageId, imdbid: searchImdbId),
- new SubtitleSearchParameters(subLanguageId, query: request.Name, imdbid: searchImdbId)
- };
- var parms = new List<SubtitleSearchParameters> {
- new SubtitleSearchParameters( subLanguageId,
- movieHash: hash,
- movieByteSize: movieByteSize,
- imdbid: searchImdbId ),
- };
- parms.AddRange(subtitleSearchParameters);
- var result = await OpenSubtitles.SearchSubtitlesAsync(parms.ToArray(), cancellationToken).ConfigureAwait(false);
- if (!(result is MethodResponseSubtitleSearch))
- {
- _logger.Error("Invalid response type");
- return new List<RemoteSubtitleInfo>();
- }
-
- Predicate<SubtitleSearchResult> mediaFilter =
- x =>
- request.ContentType == VideoContentType.Episode
- ? !string.IsNullOrEmpty(x.SeriesSeason) && !string.IsNullOrEmpty(x.SeriesEpisode) &&
- int.Parse(x.SeriesSeason, _usCulture) == request.ParentIndexNumber &&
- int.Parse(x.SeriesEpisode, _usCulture) == request.IndexNumber
- : !string.IsNullOrEmpty(x.IDMovieImdb) && long.Parse(x.IDMovieImdb, _usCulture) == imdbId;
-
- var results = ((MethodResponseSubtitleSearch)result).Results;
-
- // Avoid implicitly captured closure
- var hasCopy = hash;
-
- return results.Where(x => x.SubBad == "0" && mediaFilter(x) && (!request.IsPerfectMatch || string.Equals(x.MovieHash, hash, StringComparison.OrdinalIgnoreCase)))
- .OrderBy(x => (string.Equals(x.MovieHash, hash, StringComparison.OrdinalIgnoreCase) ? 0 : 1))
- .ThenBy(x => Math.Abs(long.Parse(x.MovieByteSize, _usCulture) - movieByteSize))
- .ThenByDescending(x => int.Parse(x.SubDownloadsCnt, _usCulture))
- .ThenByDescending(x => double.Parse(x.SubRating, _usCulture))
- .Select(i => new RemoteSubtitleInfo
- {
- Author = i.UserNickName,
- Comment = i.SubAuthorComment,
- CommunityRating = float.Parse(i.SubRating, _usCulture),
- DownloadCount = int.Parse(i.SubDownloadsCnt, _usCulture),
- Format = i.SubFormat,
- ProviderName = Name,
- ThreeLetterISOLanguageName = i.SubLanguageID,
-
- Id = i.SubFormat + "-" + i.SubLanguageID + "-" + i.IDSubtitleFile,
-
- Name = i.SubFileName,
- DateCreated = DateTime.Parse(i.SubAddDate, _usCulture),
- IsHashMatch = i.MovieHash == hasCopy
-
- }).Where(i => !string.Equals(i.Format, "sub", StringComparison.OrdinalIgnoreCase) && !string.Equals(i.Format, "idx", StringComparison.OrdinalIgnoreCase));
- }
-
- public void Dispose()
- {
- _config.NamedConfigurationUpdating -= _config_NamedConfigurationUpdating;
- }
- }
-}
diff --git a/MediaBrowser.MediaEncoding/Subtitles/ParserValues.cs b/MediaBrowser.MediaEncoding/Subtitles/ParserValues.cs
deleted file mode 100644
index b8c2fef1e..000000000
--- a/MediaBrowser.MediaEncoding/Subtitles/ParserValues.cs
+++ /dev/null
@@ -1,7 +0,0 @@
-namespace MediaBrowser.MediaEncoding.Subtitles
-{
- public class ParserValues
- {
- public const string NewLine = "\r\n";
- }
-}
diff --git a/MediaBrowser.MediaEncoding/Subtitles/SrtParser.cs b/MediaBrowser.MediaEncoding/Subtitles/SrtParser.cs
deleted file mode 100644
index 2a6aa993c..000000000
--- a/MediaBrowser.MediaEncoding/Subtitles/SrtParser.cs
+++ /dev/null
@@ -1,90 +0,0 @@
-using MediaBrowser.Model.Extensions;
-using MediaBrowser.Model.Logging;
-using System;
-using System.Collections.Generic;
-using System.Globalization;
-using System.IO;
-using System.Text.RegularExpressions;
-using System.Threading;
-using MediaBrowser.Model.MediaInfo;
-
-namespace MediaBrowser.MediaEncoding.Subtitles
-{
- public class SrtParser : ISubtitleParser
- {
- private readonly ILogger _logger;
-
- private readonly CultureInfo _usCulture = new CultureInfo("en-US");
-
- public SrtParser(ILogger logger)
- {
- _logger = logger;
- }
-
- public SubtitleTrackInfo Parse(Stream stream, CancellationToken cancellationToken)
- {
- var trackInfo = new SubtitleTrackInfo();
- using ( var reader = new StreamReader(stream))
- {
- string line;
- while ((line = reader.ReadLine()) != null)
- {
- cancellationToken.ThrowIfCancellationRequested();
-
- if (string.IsNullOrWhiteSpace(line))
- {
- continue;
- }
- var subEvent = new SubtitleTrackEvent {Id = line};
- line = reader.ReadLine();
-
- if (string.IsNullOrWhiteSpace(line))
- {
- continue;
- }
-
- var time = Regex.Split(line, @"[\t ]*-->[\t ]*");
-
- if (time.Length < 2)
- {
- // This occurs when subtitle text has an empty line as part of the text.
- // Need to adjust the break statement below to resolve this.
- _logger.Warn("Unrecognized line in srt: {0}", line);
- continue;
- }
- subEvent.StartPositionTicks = GetTicks(time[0]);
- var endTime = time[1];
- var idx = endTime.IndexOf(" ", StringComparison.Ordinal);
- if (idx > 0)
- endTime = endTime.Substring(0, idx);
- subEvent.EndPositionTicks = GetTicks(endTime);
- var multiline = new List<string>();
- while ((line = reader.ReadLine()) != null)
- {
- if (string.IsNullOrEmpty(line))
- {
- break;
- }
- multiline.Add(line);
- }
- subEvent.Text = string.Join(ParserValues.NewLine, multiline);
- subEvent.Text = subEvent.Text.Replace(@"\N", ParserValues.NewLine, StringComparison.OrdinalIgnoreCase);
- subEvent.Text = Regex.Replace(subEvent.Text, @"\{(?:\\\d?[\w.-]+(?:\([^\)]*\)|&H?[0-9A-Fa-f]+&|))+\}", string.Empty, RegexOptions.IgnoreCase);
- subEvent.Text = Regex.Replace(subEvent.Text, "<", "&lt;", RegexOptions.IgnoreCase);
- subEvent.Text = Regex.Replace(subEvent.Text, ">", "&gt;", RegexOptions.IgnoreCase);
- subEvent.Text = Regex.Replace(subEvent.Text, "&lt;(\\/?(font|b|u|i|s))((\\s+(\\w|\\w[\\w\\-]*\\w)(\\s*=\\s*(?:\\\".*?\\\"|'.*?'|[^'\\\">\\s]+))?)+\\s*|\\s*)(\\/?)&gt;", "<$1$3$7>", RegexOptions.IgnoreCase);
- trackInfo.TrackEvents.Add(subEvent);
- }
- }
- return trackInfo;
- }
-
- long GetTicks(string time) {
- TimeSpan span;
- return TimeSpan.TryParseExact(time, @"hh\:mm\:ss\.fff", _usCulture, out span)
- ? span.Ticks
- : (TimeSpan.TryParseExact(time, @"hh\:mm\:ss\,fff", _usCulture, out span)
- ? span.Ticks : 0);
- }
- }
-}
diff --git a/MediaBrowser.MediaEncoding/Subtitles/SrtWriter.cs b/MediaBrowser.MediaEncoding/Subtitles/SrtWriter.cs
deleted file mode 100644
index c05929fde..000000000
--- a/MediaBrowser.MediaEncoding/Subtitles/SrtWriter.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-using System;
-using System.Globalization;
-using System.IO;
-using System.Text;
-using System.Text.RegularExpressions;
-using System.Threading;
-using MediaBrowser.Model.MediaInfo;
-
-namespace MediaBrowser.MediaEncoding.Subtitles
-{
- public class SrtWriter : ISubtitleWriter
- {
- public void Write(SubtitleTrackInfo info, Stream stream, CancellationToken cancellationToken)
- {
- using (var writer = new StreamWriter(stream, Encoding.UTF8, 1024, true))
- {
- var index = 1;
-
- foreach (var trackEvent in info.TrackEvents)
- {
- cancellationToken.ThrowIfCancellationRequested();
-
- writer.WriteLine(index.ToString(CultureInfo.InvariantCulture));
- writer.WriteLine(@"{0:hh\:mm\:ss\,fff} --> {1:hh\:mm\:ss\,fff}", TimeSpan.FromTicks(trackEvent.StartPositionTicks), TimeSpan.FromTicks(trackEvent.EndPositionTicks));
-
- var text = trackEvent.Text;
-
- // TODO: Not sure how to handle these
- text = Regex.Replace(text, @"\\n", " ", RegexOptions.IgnoreCase);
-
- writer.WriteLine(text);
- writer.WriteLine(string.Empty);
-
- index++;
- }
- }
- }
- }
-}
diff --git a/MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs b/MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs
deleted file mode 100644
index 6c760658d..000000000
--- a/MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs
+++ /dev/null
@@ -1,394 +0,0 @@
-using MediaBrowser.Model.Extensions;
-using System;
-using System.IO;
-using System.Text;
-using System.Threading;
-using MediaBrowser.Model.MediaInfo;
-
-namespace MediaBrowser.MediaEncoding.Subtitles
-{
- /// <summary>
- /// Credit to https://github.com/SubtitleEdit/subtitleedit/blob/a299dc4407a31796364cc6ad83f0d3786194ba22/src/Logic/SubtitleFormats/SubStationAlpha.cs
- /// </summary>
- public class SsaParser : ISubtitleParser
- {
- public SubtitleTrackInfo Parse(Stream stream, CancellationToken cancellationToken)
- {
- var trackInfo = new SubtitleTrackInfo();
-
- using (var reader = new StreamReader(stream))
- {
- bool eventsStarted = false;
-
- string[] format = "Marked, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text".Split(',');
- int indexLayer = 0;
- int indexStart = 1;
- int indexEnd = 2;
- int indexStyle = 3;
- int indexName = 4;
- int indexEffect = 8;
- int indexText = 9;
- int lineNumber = 0;
-
- var header = new StringBuilder();
-
- string line;
-
- while ((line = reader.ReadLine()) != null)
- {
- cancellationToken.ThrowIfCancellationRequested();
-
- lineNumber++;
- if (!eventsStarted)
- header.AppendLine(line);
-
- if (line.Trim().ToLower() == "[events]")
- {
- eventsStarted = true;
- }
- else if (!string.IsNullOrEmpty(line) && line.Trim().StartsWith(";"))
- {
- // skip comment lines
- }
- else if (eventsStarted && line.Trim().Length > 0)
- {
- string s = line.Trim().ToLower();
- if (s.StartsWith("format:"))
- {
- if (line.Length > 10)
- {
- format = line.ToLower().Substring(8).Split(',');
- for (int i = 0; i < format.Length; i++)
- {
- if (format[i].Trim().ToLower() == "layer")
- indexLayer = i;
- else if (format[i].Trim().ToLower() == "start")
- indexStart = i;
- else if (format[i].Trim().ToLower() == "end")
- indexEnd = i;
- else if (format[i].Trim().ToLower() == "text")
- indexText = i;
- else if (format[i].Trim().ToLower() == "effect")
- indexEffect = i;
- else if (format[i].Trim().ToLower() == "style")
- indexStyle = i;
- }
- }
- }
- else if (!string.IsNullOrEmpty(s))
- {
- string text = string.Empty;
- string start = string.Empty;
- string end = string.Empty;
- string style = string.Empty;
- string layer = string.Empty;
- string effect = string.Empty;
- string name = string.Empty;
-
- string[] splittedLine;
-
- if (s.StartsWith("dialogue:"))
- splittedLine = line.Substring(10).Split(',');
- else
- splittedLine = line.Split(',');
-
- for (int i = 0; i < splittedLine.Length; i++)
- {
- if (i == indexStart)
- start = splittedLine[i].Trim();
- else if (i == indexEnd)
- end = splittedLine[i].Trim();
- else if (i == indexLayer)
- layer = splittedLine[i];
- else if (i == indexEffect)
- effect = splittedLine[i];
- else if (i == indexText)
- text = splittedLine[i];
- else if (i == indexStyle)
- style = splittedLine[i];
- else if (i == indexName)
- name = splittedLine[i];
- else if (i > indexText)
- text += "," + splittedLine[i];
- }
-
- try
- {
- var p = new SubtitleTrackEvent();
-
- p.StartPositionTicks = GetTimeCodeFromString(start);
- p.EndPositionTicks = GetTimeCodeFromString(end);
- p.Text = GetFormattedText(text);
-
- trackInfo.TrackEvents.Add(p);
- }
- catch
- {
- }
- }
- }
- }
-
- //if (header.Length > 0)
- //subtitle.Header = header.ToString();
-
- //subtitle.Renumber(1);
- }
- return trackInfo;
- }
-
- private static long GetTimeCodeFromString(string time)
- {
- // h:mm:ss.cc
- string[] timeCode = time.Split(':', '.');
- return new TimeSpan(0, int.Parse(timeCode[0]),
- int.Parse(timeCode[1]),
- int.Parse(timeCode[2]),
- int.Parse(timeCode[3]) * 10).Ticks;
- }
-
- public static string GetFormattedText(string text)
- {
- text = text.Replace("\\n", ParserValues.NewLine, StringComparison.OrdinalIgnoreCase);
-
- bool italic = false;
-
- for (int i = 0; i < 10; i++) // just look ten times...
- {
- if (text.Contains(@"{\fn"))
- {
- int start = text.IndexOf(@"{\fn");
- int end = text.IndexOf('}', start);
- if (end > 0 && !text.Substring(start).StartsWith("{\\fn}"))
- {
- string fontName = text.Substring(start + 4, end - (start + 4));
- string extraTags = string.Empty;
- CheckAndAddSubTags(ref fontName, ref extraTags, out italic);
- text = text.Remove(start, end - start + 1);
- if (italic)
- text = text.Insert(start, "<font face=\"" + fontName + "\"" + extraTags + "><i>");
- else
- text = text.Insert(start, "<font face=\"" + fontName + "\"" + extraTags + ">");
-
- int indexOfEndTag = text.IndexOf("{\\fn}", start);
- if (indexOfEndTag > 0)
- text = text.Remove(indexOfEndTag, "{\\fn}".Length).Insert(indexOfEndTag, "</font>");
- else
- text += "</font>";
- }
- }
-
- if (text.Contains(@"{\fs"))
- {
- int start = text.IndexOf(@"{\fs");
- int end = text.IndexOf('}', start);
- if (end > 0 && !text.Substring(start).StartsWith("{\\fs}"))
- {
- string fontSize = text.Substring(start + 4, end - (start + 4));
- string extraTags = string.Empty;
- CheckAndAddSubTags(ref fontSize, ref extraTags, out italic);
- if (IsInteger(fontSize))
- {
- text = text.Remove(start, end - start + 1);
- if (italic)
- text = text.Insert(start, "<font size=\"" + fontSize + "\"" + extraTags + "><i>");
- else
- text = text.Insert(start, "<font size=\"" + fontSize + "\"" + extraTags + ">");
-
- int indexOfEndTag = text.IndexOf("{\\fs}", start);
- if (indexOfEndTag > 0)
- text = text.Remove(indexOfEndTag, "{\\fs}".Length).Insert(indexOfEndTag, "</font>");
- else
- text += "</font>";
- }
- }
- }
-
- if (text.Contains(@"{\c"))
- {
- int start = text.IndexOf(@"{\c");
- int end = text.IndexOf('}', start);
- if (end > 0 && !text.Substring(start).StartsWith("{\\c}"))
- {
- string color = text.Substring(start + 4, end - (start + 4));
- string extraTags = string.Empty;
- CheckAndAddSubTags(ref color, ref extraTags, out italic);
-
- color = color.Replace("&", string.Empty).TrimStart('H');
- color = color.PadLeft(6, '0');
-
- // switch to rrggbb from bbggrr
- color = "#" + color.Remove(color.Length - 6) + color.Substring(color.Length - 2, 2) + color.Substring(color.Length - 4, 2) + color.Substring(color.Length - 6, 2);
- color = color.ToLower();
-
- text = text.Remove(start, end - start + 1);
- if (italic)
- text = text.Insert(start, "<font color=\"" + color + "\"" + extraTags + "><i>");
- else
- text = text.Insert(start, "<font color=\"" + color + "\"" + extraTags + ">");
- int indexOfEndTag = text.IndexOf("{\\c}", start);
- if (indexOfEndTag > 0)
- text = text.Remove(indexOfEndTag, "{\\c}".Length).Insert(indexOfEndTag, "</font>");
- else
- text += "</font>";
- }
- }
-
- if (text.Contains(@"{\1c")) // "1" specifices primary color
- {
- int start = text.IndexOf(@"{\1c");
- int end = text.IndexOf('}', start);
- if (end > 0 && !text.Substring(start).StartsWith("{\\1c}"))
- {
- string color = text.Substring(start + 5, end - (start + 5));
- string extraTags = string.Empty;
- CheckAndAddSubTags(ref color, ref extraTags, out italic);
-
- color = color.Replace("&", string.Empty).TrimStart('H');
- color = color.PadLeft(6, '0');
-
- // switch to rrggbb from bbggrr
- color = "#" + color.Remove(color.Length - 6) + color.Substring(color.Length - 2, 2) + color.Substring(color.Length - 4, 2) + color.Substring(color.Length - 6, 2);
- color = color.ToLower();
-
- text = text.Remove(start, end - start + 1);
- if (italic)
- text = text.Insert(start, "<font color=\"" + color + "\"" + extraTags + "><i>");
- else
- text = text.Insert(start, "<font color=\"" + color + "\"" + extraTags + ">");
- text += "</font>";
- }
- }
-
- }
-
- text = text.Replace(@"{\i1}", "<i>");
- text = text.Replace(@"{\i0}", "</i>");
- text = text.Replace(@"{\i}", "</i>");
- if (CountTagInText(text, "<i>") > CountTagInText(text, "</i>"))
- text += "</i>";
-
- text = text.Replace(@"{\u1}", "<u>");
- text = text.Replace(@"{\u0}", "</u>");
- text = text.Replace(@"{\u}", "</u>");
- if (CountTagInText(text, "<u>") > CountTagInText(text, "</u>"))
- text += "</u>";
-
- text = text.Replace(@"{\b1}", "<b>");
- text = text.Replace(@"{\b0}", "</b>");
- text = text.Replace(@"{\b}", "</b>");
- if (CountTagInText(text, "<b>") > CountTagInText(text, "</b>"))
- text += "</b>";
-
- return text;
- }
-
- private static bool IsInteger(string s)
- {
- int i;
- if (int.TryParse(s, out i))
- return true;
- return false;
- }
-
- private static int CountTagInText(string text, string tag)
- {
- int count = 0;
- int index = text.IndexOf(tag);
- while (index >= 0)
- {
- count++;
- if (index == text.Length)
- return count;
- index = text.IndexOf(tag, index + 1);
- }
- return count;
- }
-
- private static void CheckAndAddSubTags(ref string tagName, ref string extraTags, out bool italic)
- {
- italic = false;
- int indexOfSPlit = tagName.IndexOf(@"\");
- if (indexOfSPlit > 0)
- {
- string rest = tagName.Substring(indexOfSPlit).TrimStart('\\');
- tagName = tagName.Remove(indexOfSPlit);
-
- for (int i = 0; i < 10; i++)
- {
- if (rest.StartsWith("fs") && rest.Length > 2)
- {
- indexOfSPlit = rest.IndexOf(@"\");
- string fontSize = rest;
- if (indexOfSPlit > 0)
- {
- fontSize = rest.Substring(0, indexOfSPlit);
- rest = rest.Substring(indexOfSPlit).TrimStart('\\');
- }
- else
- {
- rest = string.Empty;
- }
- extraTags += " size=\"" + fontSize.Substring(2) + "\"";
- }
- else if (rest.StartsWith("fn") && rest.Length > 2)
- {
- indexOfSPlit = rest.IndexOf(@"\");
- string fontName = rest;
- if (indexOfSPlit > 0)
- {
- fontName = rest.Substring(0, indexOfSPlit);
- rest = rest.Substring(indexOfSPlit).TrimStart('\\');
- }
- else
- {
- rest = string.Empty;
- }
- extraTags += " face=\"" + fontName.Substring(2) + "\"";
- }
- else if (rest.StartsWith("c") && rest.Length > 2)
- {
- indexOfSPlit = rest.IndexOf(@"\");
- string fontColor = rest;
- if (indexOfSPlit > 0)
- {
- fontColor = rest.Substring(0, indexOfSPlit);
- rest = rest.Substring(indexOfSPlit).TrimStart('\\');
- }
- else
- {
- rest = string.Empty;
- }
-
- string color = fontColor.Substring(2);
- color = color.Replace("&", string.Empty).TrimStart('H');
- color = color.PadLeft(6, '0');
- // switch to rrggbb from bbggrr
- color = "#" + color.Remove(color.Length - 6) + color.Substring(color.Length - 2, 2) + color.Substring(color.Length - 4, 2) + color.Substring(color.Length - 6, 2);
- color = color.ToLower();
-
- extraTags += " color=\"" + color + "\"";
- }
- else if (rest.StartsWith("i1") && rest.Length > 1)
- {
- indexOfSPlit = rest.IndexOf(@"\");
- italic = true;
- if (indexOfSPlit > 0)
- {
- rest = rest.Substring(indexOfSPlit).TrimStart('\\');
- }
- else
- {
- rest = string.Empty;
- }
- }
- else if (rest.Length > 0 && rest.Contains("\\"))
- {
- indexOfSPlit = rest.IndexOf(@"\");
- rest = rest.Substring(indexOfSPlit).TrimStart('\\');
- }
- }
- }
- }
- }
-}
diff --git a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs
deleted file mode 100644
index 247c5274f..000000000
--- a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs
+++ /dev/null
@@ -1,738 +0,0 @@
-using MediaBrowser.Common.Configuration;
-using MediaBrowser.Common.Extensions;
-using MediaBrowser.Common.Net;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.MediaEncoding;
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Logging;
-using MediaBrowser.Model.MediaInfo;
-using MediaBrowser.Model.Serialization;
-using System;
-using System.Collections.Concurrent;
-using System.Diagnostics;
-using System.Globalization;
-using System.IO;
-using System.Linq;
-using System.Text;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Model.Diagnostics;
-using MediaBrowser.Model.Dto;
-using MediaBrowser.Model.Text;
-
-namespace MediaBrowser.MediaEncoding.Subtitles
-{
- public class SubtitleEncoder : ISubtitleEncoder
- {
- private readonly ILibraryManager _libraryManager;
- private readonly ILogger _logger;
- private readonly IApplicationPaths _appPaths;
- private readonly IFileSystem _fileSystem;
- private readonly IMediaEncoder _mediaEncoder;
- private readonly IJsonSerializer _json;
- private readonly IHttpClient _httpClient;
- private readonly IMediaSourceManager _mediaSourceManager;
- private readonly IMemoryStreamFactory _memoryStreamProvider;
- private readonly IProcessFactory _processFactory;
- private readonly ITextEncoding _textEncoding;
-
- public SubtitleEncoder(ILibraryManager libraryManager, ILogger logger, IApplicationPaths appPaths, IFileSystem fileSystem, IMediaEncoder mediaEncoder, IJsonSerializer json, IHttpClient httpClient, IMediaSourceManager mediaSourceManager, IMemoryStreamFactory memoryStreamProvider, IProcessFactory processFactory, ITextEncoding textEncoding)
- {
- _libraryManager = libraryManager;
- _logger = logger;
- _appPaths = appPaths;
- _fileSystem = fileSystem;
- _mediaEncoder = mediaEncoder;
- _json = json;
- _httpClient = httpClient;
- _mediaSourceManager = mediaSourceManager;
- _memoryStreamProvider = memoryStreamProvider;
- _processFactory = processFactory;
- _textEncoding = textEncoding;
- }
-
- private string SubtitleCachePath
- {
- get
- {
- return Path.Combine(_appPaths.DataPath, "subtitles");
- }
- }
-
- private Stream ConvertSubtitles(Stream stream,
- string inputFormat,
- string outputFormat,
- long startTimeTicks,
- long? endTimeTicks,
- bool preserveOriginalTimestamps,
- CancellationToken cancellationToken)
- {
- var ms = _memoryStreamProvider.CreateNew();
-
- try
- {
- var reader = GetReader(inputFormat, true);
-
- var trackInfo = reader.Parse(stream, cancellationToken);
-
- FilterEvents(trackInfo, startTimeTicks, endTimeTicks, preserveOriginalTimestamps);
-
- var writer = GetWriter(outputFormat);
-
- writer.Write(trackInfo, ms, cancellationToken);
- ms.Position = 0;
- }
- catch
- {
- ms.Dispose();
- throw;
- }
-
- return ms;
- }
-
- private void FilterEvents(SubtitleTrackInfo track, long startPositionTicks, long? endTimeTicks, bool preserveTimestamps)
- {
- // Drop subs that are earlier than what we're looking for
- track.TrackEvents = track.TrackEvents
- .SkipWhile(i => (i.StartPositionTicks - startPositionTicks) < 0 || (i.EndPositionTicks - startPositionTicks) < 0)
- .ToList();
-
- if (endTimeTicks.HasValue)
- {
- var endTime = endTimeTicks.Value;
-
- track.TrackEvents = track.TrackEvents
- .TakeWhile(i => i.StartPositionTicks <= endTime)
- .ToList();
- }
-
- if (!preserveTimestamps)
- {
- foreach (var trackEvent in track.TrackEvents)
- {
- trackEvent.EndPositionTicks -= startPositionTicks;
- trackEvent.StartPositionTicks -= startPositionTicks;
- }
- }
- }
-
- public async Task<Stream> GetSubtitles(string itemId,
- string mediaSourceId,
- int subtitleStreamIndex,
- string outputFormat,
- long startTimeTicks,
- long? endTimeTicks,
- bool preserveOriginalTimestamps,
- CancellationToken cancellationToken)
- {
- if (string.IsNullOrWhiteSpace(itemId))
- {
- throw new ArgumentNullException("itemId");
- }
- if (string.IsNullOrWhiteSpace(mediaSourceId))
- {
- throw new ArgumentNullException("mediaSourceId");
- }
-
- var mediaSources = await _mediaSourceManager.GetPlayackMediaSources(itemId, null, false, new[] { MediaType.Audio, MediaType.Video }, cancellationToken).ConfigureAwait(false);
-
- var mediaSource = mediaSources
- .First(i => string.Equals(i.Id, mediaSourceId, StringComparison.OrdinalIgnoreCase));
-
- var subtitleStream = mediaSource.MediaStreams
- .First(i => i.Type == MediaStreamType.Subtitle && i.Index == subtitleStreamIndex);
-
- var subtitle = await GetSubtitleStream(mediaSource, subtitleStream, cancellationToken)
- .ConfigureAwait(false);
-
- var inputFormat = subtitle.Item2;
- var writer = TryGetWriter(outputFormat);
-
- // Return the original if we don't have any way of converting it
- if (writer == null)
- {
- return subtitle.Item1;
- }
-
- // Return the original if the same format is being requested
- // Character encoding was already handled in GetSubtitleStream
- if (string.Equals(inputFormat, outputFormat, StringComparison.OrdinalIgnoreCase))
- {
- return subtitle.Item1;
- }
-
- using (var stream = subtitle.Item1)
- {
- return ConvertSubtitles(stream, inputFormat, outputFormat, startTimeTicks, endTimeTicks, preserveOriginalTimestamps, cancellationToken);
- }
- }
-
- private async Task<Tuple<Stream, string>> GetSubtitleStream(MediaSourceInfo mediaSource,
- MediaStream subtitleStream,
- CancellationToken cancellationToken)
- {
- var inputFiles = new[] { mediaSource.Path };
-
- if (mediaSource.VideoType.HasValue)
- {
- if (mediaSource.VideoType.Value == VideoType.BluRay || mediaSource.VideoType.Value == VideoType.Dvd)
- {
- var mediaSourceItem = (Video)_libraryManager.GetItemById(new Guid(mediaSource.Id));
- inputFiles = mediaSourceItem.GetPlayableStreamFiles().ToArray();
- }
- }
-
- var fileInfo = await GetReadableFile(mediaSource.Path, inputFiles, mediaSource.Protocol, subtitleStream, cancellationToken).ConfigureAwait(false);
-
- var stream = await GetSubtitleStream(fileInfo.Item1, subtitleStream.Language, fileInfo.Item2, fileInfo.Item4, cancellationToken).ConfigureAwait(false);
-
- return new Tuple<Stream, string>(stream, fileInfo.Item3);
- }
-
- private async Task<Stream> GetSubtitleStream(string path, string language, MediaProtocol protocol, bool requiresCharset, CancellationToken cancellationToken)
- {
- if (requiresCharset)
- {
- var bytes = await GetBytes(path, protocol, cancellationToken).ConfigureAwait(false);
-
- var charset = _textEncoding.GetDetectedEncodingName(bytes, language, true);
- _logger.Debug("charset {0} detected for {1}", charset ?? "null", path);
-
- if (!string.IsNullOrEmpty(charset))
- {
- using (var inputStream = _memoryStreamProvider.CreateNew(bytes))
- {
- using (var reader = new StreamReader(inputStream, _textEncoding.GetEncodingFromCharset(charset)))
- {
- var text = await reader.ReadToEndAsync().ConfigureAwait(false);
-
- bytes = Encoding.UTF8.GetBytes(text);
-
- return _memoryStreamProvider.CreateNew(bytes);
- }
- }
- }
- }
-
- return _fileSystem.OpenRead(path);
- }
-
- private async Task<Tuple<string, MediaProtocol, string, bool>> GetReadableFile(string mediaPath,
- string[] inputFiles,
- MediaProtocol protocol,
- MediaStream subtitleStream,
- CancellationToken cancellationToken)
- {
- if (!subtitleStream.IsExternal)
- {
- string outputFormat;
- string outputCodec;
-
- if (string.Equals(subtitleStream.Codec, "ass", StringComparison.OrdinalIgnoreCase) ||
- string.Equals(subtitleStream.Codec, "ssa", StringComparison.OrdinalIgnoreCase) ||
- string.Equals(subtitleStream.Codec, "srt", StringComparison.OrdinalIgnoreCase))
- {
- // Extract
- outputCodec = "copy";
- outputFormat = subtitleStream.Codec;
- }
- else if (string.Equals(subtitleStream.Codec, "subrip", StringComparison.OrdinalIgnoreCase))
- {
- // Extract
- outputCodec = "copy";
- outputFormat = "srt";
- }
- else
- {
- // Extract
- outputCodec = "srt";
- outputFormat = "srt";
- }
-
- // Extract
- var outputPath = GetSubtitleCachePath(mediaPath, protocol, subtitleStream.Index, "." + outputFormat);
-
- await ExtractTextSubtitle(inputFiles, protocol, subtitleStream.Index, outputCodec, outputPath, cancellationToken)
- .ConfigureAwait(false);
-
- return new Tuple<string, MediaProtocol, string, bool>(outputPath, MediaProtocol.File, outputFormat, false);
- }
-
- var currentFormat = (Path.GetExtension(subtitleStream.Path) ?? subtitleStream.Codec)
- .TrimStart('.');
-
- if (GetReader(currentFormat, false) == null)
- {
- // Convert
- var outputPath = GetSubtitleCachePath(mediaPath, protocol, subtitleStream.Index, ".srt");
-
- await ConvertTextSubtitleToSrt(subtitleStream.Path, subtitleStream.Language, protocol, outputPath, cancellationToken).ConfigureAwait(false);
-
- return new Tuple<string, MediaProtocol, string, bool>(outputPath, MediaProtocol.File, "srt", true);
- }
-
- return new Tuple<string, MediaProtocol, string, bool>(subtitleStream.Path, protocol, currentFormat, true);
- }
-
- private ISubtitleParser GetReader(string format, bool throwIfMissing)
- {
- if (string.IsNullOrEmpty(format))
- {
- throw new ArgumentNullException("format");
- }
-
- if (string.Equals(format, SubtitleFormat.SRT, StringComparison.OrdinalIgnoreCase))
- {
- return new SrtParser(_logger);
- }
- if (string.Equals(format, SubtitleFormat.SSA, StringComparison.OrdinalIgnoreCase))
- {
- return new SsaParser();
- }
- if (string.Equals(format, SubtitleFormat.ASS, StringComparison.OrdinalIgnoreCase))
- {
- return new AssParser();
- }
-
- if (throwIfMissing)
- {
- throw new ArgumentException("Unsupported format: " + format);
- }
-
- return null;
- }
-
- private ISubtitleWriter TryGetWriter(string format)
- {
- if (string.IsNullOrEmpty(format))
- {
- throw new ArgumentNullException("format");
- }
-
- if (string.Equals(format, "json", StringComparison.OrdinalIgnoreCase))
- {
- return new JsonWriter(_json);
- }
- if (string.Equals(format, SubtitleFormat.SRT, StringComparison.OrdinalIgnoreCase))
- {
- return new SrtWriter();
- }
- if (string.Equals(format, SubtitleFormat.VTT, StringComparison.OrdinalIgnoreCase))
- {
- return new VttWriter();
- }
- if (string.Equals(format, SubtitleFormat.TTML, StringComparison.OrdinalIgnoreCase))
- {
- return new TtmlWriter();
- }
-
- return null;
- }
-
- private ISubtitleWriter GetWriter(string format)
- {
- var writer = TryGetWriter(format);
-
- if (writer != null)
- {
- return writer;
- }
-
- throw new ArgumentException("Unsupported format: " + format);
- }
-
- /// <summary>
- /// The _semaphoreLocks
- /// </summary>
- private readonly ConcurrentDictionary<string, SemaphoreSlim> _semaphoreLocks =
- new ConcurrentDictionary<string, SemaphoreSlim>();
-
- /// <summary>
- /// Gets the lock.
- /// </summary>
- /// <param name="filename">The filename.</param>
- /// <returns>System.Object.</returns>
- private SemaphoreSlim GetLock(string filename)
- {
- return _semaphoreLocks.GetOrAdd(filename, key => new SemaphoreSlim(1, 1));
- }
-
- /// <summary>
- /// Converts the text subtitle to SRT.
- /// </summary>
- /// <param name="inputPath">The input path.</param>
- /// <param name="inputProtocol">The input protocol.</param>
- /// <param name="outputPath">The output path.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- private async Task ConvertTextSubtitleToSrt(string inputPath, string language, MediaProtocol inputProtocol, string outputPath, CancellationToken cancellationToken)
- {
- var semaphore = GetLock(outputPath);
-
- await semaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
-
- try
- {
- if (!_fileSystem.FileExists(outputPath))
- {
- await ConvertTextSubtitleToSrtInternal(inputPath, language, inputProtocol, outputPath, cancellationToken).ConfigureAwait(false);
- }
- }
- finally
- {
- semaphore.Release();
- }
- }
-
- /// <summary>
- /// Converts the text subtitle to SRT internal.
- /// </summary>
- /// <param name="inputPath">The input path.</param>
- /// <param name="inputProtocol">The input protocol.</param>
- /// <param name="outputPath">The output path.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- /// <exception cref="System.ArgumentNullException">
- /// inputPath
- /// or
- /// outputPath
- /// </exception>
- private async Task ConvertTextSubtitleToSrtInternal(string inputPath, string language, MediaProtocol inputProtocol, string outputPath, CancellationToken cancellationToken)
- {
- if (string.IsNullOrEmpty(inputPath))
- {
- throw new ArgumentNullException("inputPath");
- }
-
- if (string.IsNullOrEmpty(outputPath))
- {
- throw new ArgumentNullException("outputPath");
- }
-
- _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(outputPath));
-
- var encodingParam = await GetSubtitleFileCharacterSet(inputPath, language, inputProtocol, cancellationToken).ConfigureAwait(false);
-
- if (!string.IsNullOrEmpty(encodingParam))
- {
- encodingParam = " -sub_charenc " + encodingParam;
- }
-
- var process = _processFactory.Create(new ProcessOptions
- {
- CreateNoWindow = true,
- UseShellExecute = false,
- FileName = _mediaEncoder.EncoderPath,
- Arguments = string.Format("{0} -i \"{1}\" -c:s srt \"{2}\"", encodingParam, inputPath, outputPath),
-
- IsHidden = true,
- ErrorDialog = false
- });
-
- _logger.Info("{0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments);
-
- try
- {
- process.Start();
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error starting ffmpeg", ex);
-
- throw;
- }
-
- var ranToCompletion = await process.WaitForExitAsync(300000).ConfigureAwait(false);
-
- if (!ranToCompletion)
- {
- try
- {
- _logger.Info("Killing ffmpeg subtitle conversion process");
-
- process.Kill();
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error killing subtitle conversion process", ex);
- }
- }
-
- var exitCode = ranToCompletion ? process.ExitCode : -1;
-
- process.Dispose();
-
- var failed = false;
-
- if (exitCode == -1)
- {
- failed = true;
-
- if (_fileSystem.FileExists(outputPath))
- {
- try
- {
- _logger.Info("Deleting converted subtitle due to failure: ", outputPath);
- _fileSystem.DeleteFile(outputPath);
- }
- catch (IOException ex)
- {
- _logger.ErrorException("Error deleting converted subtitle {0}", ex, outputPath);
- }
- }
- }
- else if (!_fileSystem.FileExists(outputPath))
- {
- failed = true;
- }
-
- if (failed)
- {
- var msg = string.Format("ffmpeg subtitle conversion failed for {0}", inputPath);
-
- _logger.Error(msg);
-
- throw new Exception(msg);
- }
- await SetAssFont(outputPath).ConfigureAwait(false);
-
- _logger.Info("ffmpeg subtitle conversion succeeded for {0}", inputPath);
- }
-
- /// <summary>
- /// Extracts the text subtitle.
- /// </summary>
- /// <param name="inputFiles">The input files.</param>
- /// <param name="protocol">The protocol.</param>
- /// <param name="subtitleStreamIndex">Index of the subtitle stream.</param>
- /// <param name="outputCodec">The output codec.</param>
- /// <param name="outputPath">The output path.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- /// <exception cref="System.ArgumentException">Must use inputPath list overload</exception>
- private async Task ExtractTextSubtitle(string[] inputFiles, MediaProtocol protocol, int subtitleStreamIndex,
- string outputCodec, string outputPath, CancellationToken cancellationToken)
- {
- var semaphore = GetLock(outputPath);
-
- await semaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
-
- try
- {
- if (!_fileSystem.FileExists(outputPath))
- {
- await ExtractTextSubtitleInternal(_mediaEncoder.GetInputArgument(inputFiles, protocol), subtitleStreamIndex, outputCodec, outputPath, cancellationToken).ConfigureAwait(false);
- }
- }
- finally
- {
- semaphore.Release();
- }
- }
-
- private async Task ExtractTextSubtitleInternal(string inputPath, int subtitleStreamIndex,
- string outputCodec, string outputPath, CancellationToken cancellationToken)
- {
- if (string.IsNullOrEmpty(inputPath))
- {
- throw new ArgumentNullException("inputPath");
- }
-
- if (string.IsNullOrEmpty(outputPath))
- {
- throw new ArgumentNullException("outputPath");
- }
-
- _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(outputPath));
-
- var processArgs = string.Format("-i {0} -map 0:{1} -an -vn -c:s {2} \"{3}\"", inputPath,
- subtitleStreamIndex, outputCodec, outputPath);
-
- var process = _processFactory.Create(new ProcessOptions
- {
- CreateNoWindow = true,
- UseShellExecute = false,
-
- FileName = _mediaEncoder.EncoderPath,
- Arguments = processArgs,
- IsHidden = true,
- ErrorDialog = false
- });
-
- _logger.Info("{0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments);
-
- try
- {
- process.Start();
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error starting ffmpeg", ex);
-
- throw;
- }
-
- var ranToCompletion = await process.WaitForExitAsync(300000).ConfigureAwait(false);
-
- if (!ranToCompletion)
- {
- try
- {
- _logger.Info("Killing ffmpeg subtitle extraction process");
-
- process.Kill();
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error killing subtitle extraction process", ex);
- }
- }
-
- var exitCode = ranToCompletion ? process.ExitCode : -1;
-
- process.Dispose();
-
- var failed = false;
-
- if (exitCode == -1)
- {
- failed = true;
-
- try
- {
- _logger.Info("Deleting extracted subtitle due to failure: {0}", outputPath);
- _fileSystem.DeleteFile(outputPath);
- }
- catch (FileNotFoundException)
- {
-
- }
- catch (IOException ex)
- {
- _logger.ErrorException("Error deleting extracted subtitle {0}", ex, outputPath);
- }
- }
- else if (!_fileSystem.FileExists(outputPath))
- {
- failed = true;
- }
-
- if (failed)
- {
- var msg = string.Format("ffmpeg subtitle extraction failed for {0} to {1}", inputPath, outputPath);
-
- _logger.Error(msg);
-
- throw new Exception(msg);
- }
- else
- {
- var msg = string.Format("ffmpeg subtitle extraction completed for {0} to {1}", inputPath, outputPath);
-
- _logger.Info(msg);
- }
-
- if (string.Equals(outputCodec, "ass", StringComparison.OrdinalIgnoreCase))
- {
- await SetAssFont(outputPath).ConfigureAwait(false);
- }
- }
-
- /// <summary>
- /// Sets the ass font.
- /// </summary>
- /// <param name="file">The file.</param>
- /// <returns>Task.</returns>
- private async Task SetAssFont(string file)
- {
- _logger.Info("Setting ass font within {0}", file);
-
- string text;
- Encoding encoding;
-
- using (var fileStream = _fileSystem.OpenRead(file))
- {
- using (var reader = new StreamReader(fileStream, true))
- {
- encoding = reader.CurrentEncoding;
-
- text = await reader.ReadToEndAsync().ConfigureAwait(false);
- }
- }
-
- var newText = text.Replace(",Arial,", ",Arial Unicode MS,");
-
- if (!string.Equals(text, newText))
- {
- using (var fileStream = _fileSystem.GetFileStream(file, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read))
- {
- using (var writer = new StreamWriter(fileStream, encoding))
- {
- writer.Write(newText);
- }
- }
- }
- }
-
- private string GetSubtitleCachePath(string mediaPath, MediaProtocol protocol, int subtitleStreamIndex, string outputSubtitleExtension)
- {
- if (protocol == MediaProtocol.File)
- {
- var ticksParam = string.Empty;
-
- var date = _fileSystem.GetLastWriteTimeUtc(mediaPath);
-
- var filename = (mediaPath + "_" + subtitleStreamIndex.ToString(CultureInfo.InvariantCulture) + "_" + date.Ticks.ToString(CultureInfo.InvariantCulture) + ticksParam).GetMD5() + outputSubtitleExtension;
-
- var prefix = filename.Substring(0, 1);
-
- return Path.Combine(SubtitleCachePath, prefix, filename);
- }
- else
- {
- var filename = (mediaPath + "_" + subtitleStreamIndex.ToString(CultureInfo.InvariantCulture)).GetMD5() + outputSubtitleExtension;
-
- var prefix = filename.Substring(0, 1);
-
- return Path.Combine(SubtitleCachePath, prefix, filename);
- }
- }
-
- public async Task<string> GetSubtitleFileCharacterSet(string path, string language, MediaProtocol protocol, CancellationToken cancellationToken)
- {
- var bytes = await GetBytes(path, protocol, cancellationToken).ConfigureAwait(false);
-
- var charset = _textEncoding.GetDetectedEncodingName(bytes, language, true);
-
- _logger.Debug("charset {0} detected for {1}", charset ?? "null", path);
-
- return charset;
- }
-
- private async Task<byte[]> GetBytes(string path, MediaProtocol protocol, CancellationToken cancellationToken)
- {
- if (protocol == MediaProtocol.Http)
- {
- using (var file = await _httpClient.Get(path, cancellationToken).ConfigureAwait(false))
- {
- using (var memoryStream = new MemoryStream())
- {
- await file.CopyToAsync(memoryStream).ConfigureAwait(false);
- memoryStream.Position = 0;
-
- return memoryStream.ToArray();
- }
- }
- }
- if (protocol == MediaProtocol.File)
- {
- return _fileSystem.ReadAllBytes(path);
- }
-
- throw new ArgumentOutOfRangeException("protocol");
- }
- }
-} \ No newline at end of file
diff --git a/MediaBrowser.MediaEncoding/Subtitles/TtmlWriter.cs b/MediaBrowser.MediaEncoding/Subtitles/TtmlWriter.cs
deleted file mode 100644
index c32005f89..000000000
--- a/MediaBrowser.MediaEncoding/Subtitles/TtmlWriter.cs
+++ /dev/null
@@ -1,60 +0,0 @@
-using System;
-using System.IO;
-using System.Text;
-using System.Text.RegularExpressions;
-using System.Threading;
-using MediaBrowser.Model.MediaInfo;
-
-namespace MediaBrowser.MediaEncoding.Subtitles
-{
- public class TtmlWriter : ISubtitleWriter
- {
- public void Write(SubtitleTrackInfo info, Stream stream, CancellationToken cancellationToken)
- {
- // Example: https://github.com/zmalltalker/ttml2vtt/blob/master/data/sample.xml
- // Parser example: https://github.com/mozilla/popcorn-js/blob/master/parsers/parserTTML/popcorn.parserTTML.js
-
- using (var writer = new StreamWriter(stream, Encoding.UTF8, 1024, true))
- {
- writer.WriteLine("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
- writer.WriteLine("<tt xmlns=\"http://www.w3.org/ns/ttml\" xmlns:tts=\"http://www.w3.org/2006/04/ttaf1#styling\" lang=\"no\">");
-
- writer.WriteLine("<head>");
- writer.WriteLine("<styling>");
- writer.WriteLine("<style id=\"italic\" tts:fontStyle=\"italic\" />");
- writer.WriteLine("<style id=\"left\" tts:textAlign=\"left\" />");
- writer.WriteLine("<style id=\"center\" tts:textAlign=\"center\" />");
- writer.WriteLine("<style id=\"right\" tts:textAlign=\"right\" />");
- writer.WriteLine("</styling>");
- writer.WriteLine("</head>");
-
- writer.WriteLine("<body>");
- writer.WriteLine("<div>");
-
- foreach (var trackEvent in info.TrackEvents)
- {
- var text = trackEvent.Text;
-
- text = Regex.Replace(text, @"\\n", "<br/>", RegexOptions.IgnoreCase);
-
- writer.WriteLine("<p begin=\"{0}\" dur=\"{1}\">{2}</p>",
- trackEvent.StartPositionTicks,
- (trackEvent.EndPositionTicks - trackEvent.StartPositionTicks),
- text);
- }
-
- writer.WriteLine("</div>");
- writer.WriteLine("</body>");
-
- writer.WriteLine("</tt>");
- }
- }
-
- private string FormatTime(long ticks)
- {
- var time = TimeSpan.FromTicks(ticks);
-
- return string.Format(@"{0:hh\:mm\:ss\,fff}", time);
- }
- }
-}
diff --git a/MediaBrowser.MediaEncoding/Subtitles/VttWriter.cs b/MediaBrowser.MediaEncoding/Subtitles/VttWriter.cs
deleted file mode 100644
index 092add992..000000000
--- a/MediaBrowser.MediaEncoding/Subtitles/VttWriter.cs
+++ /dev/null
@@ -1,44 +0,0 @@
-using System;
-using System.IO;
-using System.Text;
-using System.Text.RegularExpressions;
-using System.Threading;
-using MediaBrowser.Model.MediaInfo;
-
-namespace MediaBrowser.MediaEncoding.Subtitles
-{
- public class VttWriter : ISubtitleWriter
- {
- public void Write(SubtitleTrackInfo info, Stream stream, CancellationToken cancellationToken)
- {
- using (var writer = new StreamWriter(stream, Encoding.UTF8, 1024, true))
- {
- writer.WriteLine("WEBVTT");
- writer.WriteLine(string.Empty);
- foreach (var trackEvent in info.TrackEvents)
- {
- cancellationToken.ThrowIfCancellationRequested();
-
- TimeSpan startTime = TimeSpan.FromTicks(trackEvent.StartPositionTicks);
- TimeSpan endTime = TimeSpan.FromTicks(trackEvent.EndPositionTicks);
-
- // make sure the start and end times are different and seqential
- if (endTime.TotalMilliseconds <= startTime.TotalMilliseconds)
- {
- endTime = startTime.Add(TimeSpan.FromMilliseconds(1));
- }
-
- writer.WriteLine(@"{0:hh\:mm\:ss\.fff} --> {1:hh\:mm\:ss\.fff}", startTime, endTime);
-
- var text = trackEvent.Text;
-
- // TODO: Not sure how to handle these
- text = Regex.Replace(text, @"\\n", " ", RegexOptions.IgnoreCase);
-
- writer.WriteLine(text);
- writer.WriteLine(string.Empty);
- }
- }
- }
- }
-}
diff --git a/MediaBrowser.MediaEncoding/packages.config b/MediaBrowser.MediaEncoding/packages.config
deleted file mode 100644
index 6b8deb9c9..000000000
--- a/MediaBrowser.MediaEncoding/packages.config
+++ /dev/null
@@ -1,3 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<packages>
-</packages> \ No newline at end of file
diff --git a/MediaBrowser.Model/Activity/IActivityManager.cs b/MediaBrowser.Model/Activity/IActivityManager.cs
index 7032dff14..396be9573 100644
--- a/MediaBrowser.Model/Activity/IActivityManager.cs
+++ b/MediaBrowser.Model/Activity/IActivityManager.cs
@@ -1,5 +1,4 @@
using System;
-using System.Threading.Tasks;
using MediaBrowser.Model.Events;
using MediaBrowser.Model.Querying;
@@ -9,7 +8,7 @@ namespace MediaBrowser.Model.Activity
{
event EventHandler<GenericEventArgs<ActivityLogEntry>> EntryCreated;
- Task Create(ActivityLogEntry entry);
+ void Create(ActivityLogEntry entry);
QueryResult<ActivityLogEntry> GetActivityLogEntries(DateTime? minDate, int? startIndex, int? limit);
}
diff --git a/MediaBrowser.Model/Activity/IActivityRepository.cs b/MediaBrowser.Model/Activity/IActivityRepository.cs
index c1952d436..8ee87ee2e 100644
--- a/MediaBrowser.Model/Activity/IActivityRepository.cs
+++ b/MediaBrowser.Model/Activity/IActivityRepository.cs
@@ -1,12 +1,11 @@
using System;
-using System.Threading.Tasks;
using MediaBrowser.Model.Querying;
namespace MediaBrowser.Model.Activity
{
public interface IActivityRepository
{
- Task Create(ActivityLogEntry entry);
+ void Create(ActivityLogEntry entry);
QueryResult<ActivityLogEntry> GetActivityLogEntries(DateTime? minDate, int? startIndex, int? limit);
}
diff --git a/MediaBrowser.Model/ApiClient/ApiClientExtensions.cs b/MediaBrowser.Model/ApiClient/ApiClientExtensions.cs
deleted file mode 100644
index 4ae4fe822..000000000
--- a/MediaBrowser.Model/ApiClient/ApiClientExtensions.cs
+++ /dev/null
@@ -1,48 +0,0 @@
-using MediaBrowser.Model.Dto;
-using MediaBrowser.Model.Querying;
-using MediaBrowser.Model.Sync;
-using System.IO;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace MediaBrowser.Model.ApiClient
-{
- /// <summary>
- /// Class ApiClientExtensions
- /// </summary>
- public static class ApiClientExtensions
- {
- /// <summary>
- /// Gets the image stream async.
- /// </summary>
- /// <param name="apiClient">The API client.</param>
- /// <param name="url">The URL.</param>
- /// <returns>Task{Stream}.</returns>
- public static Task<Stream> GetImageStreamAsync(this IApiClient apiClient, string url)
- {
- return apiClient.GetImageStreamAsync(url, CancellationToken.None);
- }
-
- public static Task<UserDto[]> GetPublicUsersAsync(this IApiClient apiClient)
- {
- return apiClient.GetPublicUsersAsync(CancellationToken.None);
- }
-
- public static Task<ItemsResult> GetItemsAsync(this IApiClient apiClient, ItemQuery query)
- {
- return apiClient.GetItemsAsync(query, CancellationToken.None);
- }
-
- public static Task<SyncDialogOptions> GetSyncOptions(this IApiClient apiClient, SyncJob job)
- {
- return apiClient.GetSyncOptions(new SyncJobRequest
- {
- Category = job.Category,
- ItemIds = job.RequestedItemIds,
- ParentId = job.ParentId,
- TargetId = job.TargetId,
- UserId = job.UserId
- });
- }
- }
-}
diff --git a/MediaBrowser.Model/ApiClient/ApiHelpers.cs b/MediaBrowser.Model/ApiClient/ApiHelpers.cs
deleted file mode 100644
index 65b6495ab..000000000
--- a/MediaBrowser.Model/ApiClient/ApiHelpers.cs
+++ /dev/null
@@ -1,22 +0,0 @@
-using System;
-
-namespace MediaBrowser.Model.ApiClient
-{
- public static class ApiHelpers
- {
- /// <summary>
- /// Gets the name of the slug.
- /// </summary>
- /// <param name="name">The name.</param>
- /// <returns>System.String.</returns>
- public static string GetSlugName(string name)
- {
- if (string.IsNullOrEmpty(name))
- {
- throw new ArgumentNullException("name");
- }
-
- return name.Replace('/', '-').Replace('?', '-').Replace('&', '-');
- }
- }
-}
diff --git a/MediaBrowser.Model/ApiClient/ConnectionMode.cs b/MediaBrowser.Model/ApiClient/ConnectionMode.cs
deleted file mode 100644
index 5dc224d95..000000000
--- a/MediaBrowser.Model/ApiClient/ConnectionMode.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-namespace MediaBrowser.Model.ApiClient
-{
- public enum ConnectionMode
- {
- Local = 1,
- Remote = 2,
- Manual = 3
- }
-} \ No newline at end of file
diff --git a/MediaBrowser.Model/ApiClient/ConnectionOptions.cs b/MediaBrowser.Model/ApiClient/ConnectionOptions.cs
deleted file mode 100644
index e12676311..000000000
--- a/MediaBrowser.Model/ApiClient/ConnectionOptions.cs
+++ /dev/null
@@ -1,29 +0,0 @@
-
-namespace MediaBrowser.Model.ApiClient
-{
- public class ConnectionOptions
- {
- /// <summary>
- /// Gets or sets a value indicating whether [enable web socket].
- /// </summary>
- /// <value><c>true</c> if [enable web socket]; otherwise, <c>false</c>.</value>
- public bool EnableWebSocket { get; set; }
- /// <summary>
- /// Gets or sets a value indicating whether [report capabilities].
- /// </summary>
- /// <value><c>true</c> if [report capabilities]; otherwise, <c>false</c>.</value>
- public bool ReportCapabilities { get; set; }
- /// <summary>
- /// Gets or sets a value indicating whether [update date last accessed].
- /// </summary>
- /// <value><c>true</c> if [update date last accessed]; otherwise, <c>false</c>.</value>
- public bool UpdateDateLastAccessed { get; set; }
-
- public ConnectionOptions()
- {
- EnableWebSocket = true;
- ReportCapabilities = true;
- UpdateDateLastAccessed = true;
- }
- }
-}
diff --git a/MediaBrowser.Model/ApiClient/ConnectionResult.cs b/MediaBrowser.Model/ApiClient/ConnectionResult.cs
deleted file mode 100644
index 32a80d1a3..000000000
--- a/MediaBrowser.Model/ApiClient/ConnectionResult.cs
+++ /dev/null
@@ -1,21 +0,0 @@
-using MediaBrowser.Model.Connect;
-using MediaBrowser.Model.Dto;
-using System.Collections.Generic;
-
-namespace MediaBrowser.Model.ApiClient
-{
- public class ConnectionResult
- {
- public ConnectionState State { get; set; }
- public List<ServerInfo> Servers { get; set; }
- public IApiClient ApiClient { get; set; }
- public ConnectUser ConnectUser { get; set; }
- public UserDto OfflineUser { get; set; }
-
- public ConnectionResult()
- {
- State = ConnectionState.Unavailable;
- Servers = new List<ServerInfo>();
- }
- }
-}
diff --git a/MediaBrowser.Model/ApiClient/ConnectionState.cs b/MediaBrowser.Model/ApiClient/ConnectionState.cs
deleted file mode 100644
index 9b753c7bb..000000000
--- a/MediaBrowser.Model/ApiClient/ConnectionState.cs
+++ /dev/null
@@ -1,13 +0,0 @@
-namespace MediaBrowser.Model.ApiClient
-{
- public enum ConnectionState
- {
- Unavailable = 1,
- ServerSignIn = 2,
- SignedIn = 3,
- ServerSelection = 4,
- ConnectSignIn = 5,
- OfflineSignIn = 6,
- OfflineSignedIn = 7
- }
-} \ No newline at end of file
diff --git a/MediaBrowser.Model/ApiClient/IApiClient.cs b/MediaBrowser.Model/ApiClient/IApiClient.cs
deleted file mode 100644
index 2e9f57087..000000000
--- a/MediaBrowser.Model/ApiClient/IApiClient.cs
+++ /dev/null
@@ -1,1427 +0,0 @@
-using MediaBrowser.Model.Channels;
-using MediaBrowser.Model.Configuration;
-using MediaBrowser.Model.Devices;
-using MediaBrowser.Model.Dto;
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Events;
-using MediaBrowser.Model.Globalization;
-using MediaBrowser.Model.LiveTv;
-using MediaBrowser.Model.MediaInfo;
-using MediaBrowser.Model.Net;
-using MediaBrowser.Model.Notifications;
-using MediaBrowser.Model.Playlists;
-using MediaBrowser.Model.Plugins;
-using MediaBrowser.Model.Querying;
-using MediaBrowser.Model.Search;
-using MediaBrowser.Model.Serialization;
-using MediaBrowser.Model.Session;
-using MediaBrowser.Model.Sync;
-using MediaBrowser.Model.System;
-using MediaBrowser.Model.Tasks;
-using MediaBrowser.Model.Users;
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace MediaBrowser.Model.ApiClient
-{
- /// <summary>
- /// Interface IApiClient
- /// </summary>
- public interface IApiClient : IServerEvents, IDisposable
- {
- /// <summary>
- /// Occurs when [remote logged out].
- /// </summary>
- event EventHandler<GenericEventArgs<RemoteLogoutReason>> RemoteLoggedOut;
-
- /// <summary>
- /// Gets the API URL.
- /// </summary>
- /// <param name="handler">The handler.</param>
- /// <returns>System.String.</returns>
- string GetApiUrl(string handler);
-
- /// <summary>
- /// Gets the game system summaries async.
- /// </summary>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task{List{GameSystemSummary}}.</returns>
- Task<List<GameSystemSummary>> GetGameSystemSummariesAsync(CancellationToken cancellationToken = default(CancellationToken));
-
- /// <summary>
- /// Gets the async.
- /// </summary>
- /// <typeparam name="T"></typeparam>
- /// <param name="url">The URL.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task{``0}.</returns>
- Task<T> GetAsync<T>(string url, CancellationToken cancellationToken = default(CancellationToken))
- where T : class;
-
- /// <summary>
- /// Reports the capabilities.
- /// </summary>
- /// <param name="capabilities">The capabilities.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- Task ReportCapabilities(ClientCapabilities capabilities, CancellationToken cancellationToken = default(CancellationToken));
-
- /// <summary>
- /// Logouts this instance.
- /// </summary>
- /// <returns>Task.</returns>
- Task Logout();
-
- /// <summary>
- /// Gets the index of the game players.
- /// </summary>
- /// <param name="userId">The user id.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task{List{ItemIndex}}.</returns>
- Task<List<ItemIndex>> GetGamePlayerIndex(string userId, CancellationToken cancellationToken = default(CancellationToken));
-
- /// <summary>
- /// Gets the index of the year.
- /// </summary>
- /// <param name="userId">The user id.</param>
- /// <param name="includeItemTypes">The include item types.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task{List{ItemIndex}}.</returns>
- Task<List<ItemIndex>> GetYearIndex(string userId, string[] includeItemTypes, CancellationToken cancellationToken = default(CancellationToken));
-
- /// <summary>
- /// Gets the critic reviews.
- /// </summary>
- /// <param name="itemId">The item id.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <param name="startIndex">The start index.</param>
- /// <param name="limit">The limit.</param>
- /// <returns>Task{ItemReviewsResult}.</returns>
- Task<QueryResult<ItemReview>> GetCriticReviews(string itemId, CancellationToken cancellationToken = default(CancellationToken), int? startIndex = null, int? limit = null);
-
- /// <summary>
- /// Gets the theme songs async.
- /// </summary>
- /// <param name="userId">The user id.</param>
- /// <param name="itemId">The item id.</param>
- /// <param name="inheritFromParents">if set to <c>true</c> [inherit from parents].</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task{ThemeMediaResult}.</returns>
- Task<ThemeMediaResult> GetThemeSongsAsync(string userId, string itemId, bool inheritFromParents, CancellationToken cancellationToken = default(CancellationToken));
-
- /// <summary>
- /// Gets the search hints async.
- /// </summary>
- /// <param name="query">The query.</param>
- /// <returns>Task{SearchHintResult}.</returns>
- Task<SearchHintResult> GetSearchHintsAsync(SearchQuery query);
-
- /// <summary>
- /// Gets the filters.
- /// </summary>
- /// <param name="userId">The user identifier.</param>
- /// <param name="parentId">The parent identifier.</param>
- /// <param name="mediaTypes">The media types.</param>
- /// <param name="itemTypes">The item types.</param>
- /// <returns>Task&lt;QueryFilters&gt;.</returns>
- Task<QueryFilters> GetFilters(string userId, string parentId, string[] mediaTypes, string[] itemTypes);
-
- /// <summary>
- /// Gets the theme videos async.
- /// </summary>
- /// <param name="userId">The user id.</param>
- /// <param name="itemId">The item id.</param>
- /// <param name="inheritFromParents">if set to <c>true</c> [inherit from parents].</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task{ThemeMediaResult}.</returns>
- Task<ThemeMediaResult> GetThemeVideosAsync(string userId, string itemId, bool inheritFromParents, CancellationToken cancellationToken = default(CancellationToken));
-
- /// <summary>
- /// Gets all theme media async.
- /// </summary>
- /// <param name="userId">The user id.</param>
- /// <param name="itemId">The item id.</param>
- /// <param name="inheritFromParents">if set to <c>true</c> [inherit from parents].</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task{AllThemeMediaResult}.</returns>
- Task<AllThemeMediaResult> GetAllThemeMediaAsync(string userId, string itemId, bool inheritFromParents, CancellationToken cancellationToken = default(CancellationToken));
-
- /// <summary>
- /// Marks the notifications read.
- /// </summary>
- /// <param name="userId">The user id.</param>
- /// <param name="notificationIdList">The notification id list.</param>
- /// <param name="isRead">if set to <c>true</c> [is read].</param>
- /// <returns>Task.</returns>
- Task MarkNotificationsRead(string userId, IEnumerable<string> notificationIdList, bool isRead);
-
- /// <summary>
- /// Gets the notifications summary.
- /// </summary>
- /// <param name="userId">The user id.</param>
- /// <returns>Task{NotificationsSummary}.</returns>
- Task<NotificationsSummary> GetNotificationsSummary(string userId);
-
- /// <summary>
- /// Gets the notifications async.
- /// </summary>
- /// <param name="query">The query.</param>
- /// <returns>Task{NotificationResult}.</returns>
- Task<NotificationResult> GetNotificationsAsync(NotificationQuery query);
-
- /// <summary>
- /// Gets an image stream based on a url
- /// </summary>
- /// <param name="url">The URL.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task{Stream}.</returns>
- /// <exception cref="ArgumentNullException">url</exception>
- Task<Stream> GetImageStreamAsync(string url, CancellationToken cancellationToken = default(CancellationToken));
-
- /// <summary>
- /// Gets the stream.
- /// </summary>
- /// <param name="url">The URL.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task&lt;Stream&gt;.</returns>
- Task<Stream> GetStream(string url, CancellationToken cancellationToken = default(CancellationToken));
-
- /// <summary>
- /// Gets the response.
- /// </summary>
- /// <param name="url">The URL.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task&lt;HttpResponse&gt;.</returns>
- Task<HttpResponse> GetResponse(string url, CancellationToken cancellationToken = default(CancellationToken));
-
- /// <summary>
- /// Updates the user configuration.
- /// </summary>
- /// <param name="userId">The user identifier.</param>
- /// <param name="configuration">The configuration.</param>
- /// <returns>Task.</returns>
- Task UpdateUserConfiguration(string userId, UserConfiguration configuration);
-
- /// <summary>
- /// Gets a BaseItem
- /// </summary>
- /// <param name="id">The id.</param>
- /// <param name="userId">The user id.</param>
- /// <returns>Task{BaseItemDto}.</returns>
- /// <exception cref="ArgumentNullException">id</exception>
- Task<BaseItemDto> GetItemAsync(string id, string userId);
-
- /// <summary>
- /// Gets the latest items.
- /// </summary>
- /// <param name="query">The query.</param>
- /// <returns>Task&lt;QueryResult&lt;BaseItemDto&gt;&gt;.</returns>
- Task<BaseItemDto[]> GetLatestItems(LatestItemsQuery query);
-
- /// <summary>
- /// Gets the intros async.
- /// </summary>
- /// <param name="itemId">The item id.</param>
- /// <param name="userId">The user id.</param>
- /// <returns>Task{ItemsResult}.</returns>
- Task<ItemsResult> GetIntrosAsync(string itemId, string userId);
-
- /// <summary>
- /// Gets a BaseItem
- /// </summary>
- /// <param name="userId">The user id.</param>
- /// <returns>Task{BaseItemDto}.</returns>
- /// <exception cref="ArgumentNullException">userId</exception>
- Task<BaseItemDto> GetRootFolderAsync(string userId);
-
- /// <summary>
- /// Gets the additional parts.
- /// </summary>
- /// <param name="itemId">The item identifier.</param>
- /// <param name="userId">The user identifier.</param>
- /// <returns>Task{BaseItemDto[]}.</returns>
- Task<ItemsResult> GetAdditionalParts(string itemId, string userId);
-
- /// <summary>
- /// Gets the playback information.
- /// </summary>
- /// <param name="request">The request.</param>
- /// <returns>Task&lt;LiveMediaInfoResult&gt;.</returns>
- Task<PlaybackInfoResponse> GetPlaybackInfo(PlaybackInfoRequest request);
-
- /// <summary>
- /// Gets the users async.
- /// </summary>
- /// <param name="query">The query.</param>
- /// <returns>Task{UserDto[]}.</returns>
- Task<UserDto[]> GetUsersAsync(UserQuery query);
-
- /// <summary>
- /// Gets the public users async.
- /// </summary>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task{UserDto[]}.</returns>
- Task<UserDto[]> GetPublicUsersAsync(CancellationToken cancellationToken = default(CancellationToken));
-
- /// <summary>
- /// Gets active client sessions.
- /// </summary>
- /// <param name="query">The query.</param>
- /// <returns>Task{SessionInfoDto[]}.</returns>
- Task<SessionInfoDto[]> GetClientSessionsAsync(SessionQuery query);
-
- /// <summary>
- /// Gets the client session asynchronous.
- /// </summary>
- /// <returns>Task{SessionInfoDto}.</returns>
- Task<SessionInfoDto> GetCurrentSessionAsync(CancellationToken cancellationToken = default(CancellationToken));
-
- /// <summary>
- /// Gets the item counts async.
- /// </summary>
- /// <param name="query">The query.</param>
- /// <returns>Task{ItemCounts}.</returns>
- Task<ItemCounts> GetItemCountsAsync(ItemCountsQuery query);
-
- /// <summary>
- /// Gets the episodes asynchronous.
- /// </summary>
- /// <param name="query">The query.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task{ItemsResult}.</returns>
- Task<ItemsResult> GetEpisodesAsync(EpisodeQuery query, CancellationToken cancellationToken = default(CancellationToken));
-
- /// <summary>
- /// Gets the seasons asynchronous.
- /// </summary>
- /// <param name="query">The query.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task{ItemsResult}.</returns>
- Task<ItemsResult> GetSeasonsAsync(SeasonQuery query, CancellationToken cancellationToken = default(CancellationToken));
-
- Task<PluginSecurityInfo> GetRegistrationInfo();
-
- /// <summary>
- /// Queries for items
- /// </summary>
- /// <param name="query">The query.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task{ItemsResult}.</returns>
- /// <exception cref="ArgumentNullException">query</exception>
- Task<ItemsResult> GetItemsAsync(ItemQuery query, CancellationToken cancellationToken = default(CancellationToken));
-
- /// <summary>
- /// Gets the user views.
- /// </summary>
- /// <param name="userId">The user identifier.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task&lt;ItemsResult&gt;.</returns>
- Task<ItemsResult> GetUserViews(string userId, CancellationToken cancellationToken = default(CancellationToken));
-
- /// <summary>
- /// Gets the instant mix from item asynchronous.
- /// </summary>
- /// <param name="query">The query.</param>
- /// <returns>Task&lt;ItemsResult&gt;.</returns>
- Task<ItemsResult> GetInstantMixFromItemAsync(SimilarItemsQuery query);
-
- /// <summary>
- /// Gets the similar movies async.
- /// </summary>
- /// <param name="query">The query.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task{ItemsResult}.</returns>
- Task<ItemsResult> GetSimilarItemsAsync(SimilarItemsQuery query, CancellationToken cancellationToken = default(CancellationToken));
-
- /// <summary>
- /// Gets the people async.
- /// </summary>
- /// <param name="query">The query.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task{ItemsResult}.</returns>
- /// <exception cref="ArgumentNullException">userId</exception>
- Task<ItemsResult> GetPeopleAsync(PersonsQuery query, CancellationToken cancellationToken = default(CancellationToken));
-
- /// <summary>
- /// Gets the artists.
- /// </summary>
- /// <param name="query">The query.</param>
- /// <returns>Task{ItemsResult}.</returns>
- /// <exception cref="ArgumentNullException">userId</exception>
- Task<ItemsResult> GetArtistsAsync(ArtistsQuery query);
-
- /// <summary>
- /// Gets the album artists asynchronous.
- /// </summary>
- /// <param name="query">The query.</param>
- /// <returns>Task{ItemsResult}.</returns>
- Task<ItemsResult> GetAlbumArtistsAsync(ArtistsQuery query);
-
- /// <summary>
- /// Gets the next up async.
- /// </summary>
- /// <param name="query">The query.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task{ItemsResult}.</returns>
- Task<ItemsResult> GetNextUpEpisodesAsync(NextUpQuery query, CancellationToken cancellationToken = default(CancellationToken));
-
- /// <summary>
- /// Gets the upcoming episodes asynchronous.
- /// </summary>
- /// <param name="query">The query.</param>
- /// <returns>Task{ItemsResult}.</returns>
- Task<ItemsResult> GetUpcomingEpisodesAsync(UpcomingEpisodesQuery query);
-
- /// <summary>
- /// Gets a genre
- /// </summary>
- /// <param name="name">The name.</param>
- /// <param name="userId">The user id.</param>
- /// <returns>Task{BaseItemDto}.</returns>
- /// <exception cref="ArgumentNullException">userId</exception>
- Task<BaseItemDto> GetGenreAsync(string name, string userId);
-
- /// <summary>
- /// Gets the genres async.
- /// </summary>
- /// <param name="query">The query.</param>
- /// <returns>Task{ItemsResult}.</returns>
- Task<ItemsResult> GetGenresAsync(ItemsByNameQuery query);
-
- /// <summary>
- /// Gets the studios async.
- /// </summary>
- /// <param name="query">The query.</param>
- /// <returns>Task{ItemsResult}.</returns>
- Task<ItemsResult> GetStudiosAsync(ItemsByNameQuery query);
-
- /// <summary>
- /// Gets the music genre async.
- /// </summary>
- /// <param name="name">The name.</param>
- /// <param name="userId">The user id.</param>
- /// <returns>Task{BaseItemDto}.</returns>
- Task<BaseItemDto> GetMusicGenreAsync(string name, string userId);
-
- /// <summary>
- /// Gets the game genre async.
- /// </summary>
- /// <param name="name">The name.</param>
- /// <param name="userId">The user id.</param>
- /// <returns>Task{BaseItemDto}.</returns>
- Task<BaseItemDto> GetGameGenreAsync(string name, string userId);
-
- /// <summary>
- /// Restarts the server.
- /// </summary>
- /// <returns>Task.</returns>
- Task RestartServerAsync();
-
- /// <summary>
- /// Gets the system status async.
- /// </summary>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task{SystemInfo}.</returns>
- Task<SystemInfo> GetSystemInfoAsync(CancellationToken cancellationToken = default(CancellationToken));
-
- /// <summary>
- /// Gets the public system information asynchronous.
- /// </summary>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task&lt;PublicSystemInfo&gt;.</returns>
- Task<PublicSystemInfo> GetPublicSystemInfoAsync(CancellationToken cancellationToken = default(CancellationToken));
-
- /// <summary>
- /// Gets a list of plugins installed on the server
- /// </summary>
- /// <returns>Task{PluginInfo[]}.</returns>
- Task<PluginInfo[]> GetInstalledPluginsAsync();
-
- /// <summary>
- /// Gets the current server configuration
- /// </summary>
- /// <returns>Task{ServerConfiguration}.</returns>
- Task<ServerConfiguration> GetServerConfigurationAsync();
-
- /// <summary>
- /// Gets the scheduled tasks.
- /// </summary>
- /// <returns>Task{TaskInfo[]}.</returns>
- Task<TaskInfo[]> GetScheduledTasksAsync();
-
- /// <summary>
- /// Gets the scheduled task async.
- /// </summary>
- /// <param name="id">The id.</param>
- /// <returns>Task{TaskInfo}.</returns>
- /// <exception cref="ArgumentNullException">id</exception>
- Task<TaskInfo> GetScheduledTaskAsync(string id);
-
- /// <summary>
- /// Gets a user by id
- /// </summary>
- /// <param name="id">The id.</param>
- /// <returns>Task{UserDto}.</returns>
- /// <exception cref="ArgumentNullException">id</exception>
- Task<UserDto> GetUserAsync(string id);
-
- /// <summary>
- /// Gets the offline user asynchronous.
- /// </summary>
- /// <param name="id">The identifier.</param>
- /// <returns>Task&lt;UserDto&gt;.</returns>
- Task<UserDto> GetOfflineUserAsync(string id);
-
- /// <summary>
- /// Gets the parental ratings async.
- /// </summary>
- /// <returns>Task{List{ParentalRating}}.</returns>
- Task<List<ParentalRating>> GetParentalRatingsAsync();
-
- /// <summary>
- /// Gets local trailers for an item
- /// </summary>
- /// <param name="userId">The user id.</param>
- /// <param name="itemId">The item id.</param>
- /// <returns>Task{ItemsResult}.</returns>
- /// <exception cref="ArgumentNullException">query</exception>
- Task<BaseItemDto[]> GetLocalTrailersAsync(string userId, string itemId);
-
- /// <summary>
- /// Gets special features for an item
- /// </summary>
- /// <param name="userId">The user id.</param>
- /// <param name="itemId">The item id.</param>
- /// <returns>Task{BaseItemDto[]}.</returns>
- /// <exception cref="ArgumentNullException">userId</exception>
- Task<BaseItemDto[]> GetSpecialFeaturesAsync(string userId, string itemId);
-
- /// <summary>
- /// Gets the cultures async.
- /// </summary>
- /// <returns>Task{CultureDto[]}.</returns>
- Task<CultureDto[]> GetCulturesAsync();
-
- /// <summary>
- /// Gets the countries async.
- /// </summary>
- /// <returns>Task{CountryInfo[]}.</returns>
- Task<CountryInfo[]> GetCountriesAsync();
-
- /// <summary>
- /// Marks the played async.
- /// </summary>
- /// <param name="itemId">The item id.</param>
- /// <param name="userId">The user id.</param>
- /// <param name="datePlayed">The date played.</param>
- /// <returns>Task{UserItemDataDto}.</returns>
- Task<UserItemDataDto> MarkPlayedAsync(string itemId, string userId, DateTime? datePlayed);
-
- /// <summary>
- /// Marks the unplayed async.
- /// </summary>
- /// <param name="itemId">The item id.</param>
- /// <param name="userId">The user id.</param>
- /// <returns>Task{UserItemDataDto}.</returns>
- Task<UserItemDataDto> MarkUnplayedAsync(string itemId, string userId);
-
- /// <summary>
- /// Updates the favorite status async.
- /// </summary>
- /// <param name="itemId">The item id.</param>
- /// <param name="userId">The user id.</param>
- /// <param name="isFavorite">if set to <c>true</c> [is favorite].</param>
- /// <returns>Task.</returns>
- /// <exception cref="ArgumentNullException">itemId</exception>
- Task<UserItemDataDto> UpdateFavoriteStatusAsync(string itemId, string userId, bool isFavorite);
-
- /// <summary>
- /// Reports to the server that the user has begun playing an item
- /// </summary>
- /// <param name="info">The information.</param>
- /// <returns>Task{UserItemDataDto}.</returns>
- /// <exception cref="ArgumentNullException">itemId</exception>
- Task ReportPlaybackStartAsync(PlaybackStartInfo info);
-
- /// <summary>
- /// Reports playback progress to the server
- /// </summary>
- /// <param name="info">The information.</param>
- /// <returns>Task{UserItemDataDto}.</returns>
- /// <exception cref="ArgumentNullException">itemId</exception>
- Task ReportPlaybackProgressAsync(PlaybackProgressInfo info);
-
- /// <summary>
- /// Reports to the server that the user has stopped playing an item
- /// </summary>
- /// <param name="info">The information.</param>
- /// <returns>Task{UserItemDataDto}.</returns>
- /// <exception cref="ArgumentNullException">itemId</exception>
- Task ReportPlaybackStoppedAsync(PlaybackStopInfo info);
-
- /// <summary>
- /// Instructs another client to browse to a library item.
- /// </summary>
- /// <param name="sessionId">The session id.</param>
- /// <param name="itemId">The id of the item to browse to.</param>
- /// <param name="itemName">The name of the item to browse to.</param>
- /// <param name="itemType">The type of the item to browse to.</param>
- /// <returns>Task.</returns>
- Task SendBrowseCommandAsync(string sessionId, string itemId, string itemName, string itemType);
-
- /// <summary>
- /// Sends the playstate command async.
- /// </summary>
- /// <param name="sessionId">The session id.</param>
- /// <param name="request">The request.</param>
- /// <returns>Task.</returns>
- Task SendPlaystateCommandAsync(string sessionId, PlaystateRequest request);
-
- /// <summary>
- /// Sends the play command async.
- /// </summary>
- /// <param name="sessionId">The session id.</param>
- /// <param name="request">The request.</param>
- /// <returns>Task.</returns>
- /// <exception cref="ArgumentNullException">sessionId
- /// or
- /// request</exception>
- Task SendPlayCommandAsync(string sessionId, PlayRequest request);
-
- /// <summary>
- /// Sends the command asynchronous.
- /// </summary>
- /// <param name="sessionId">The session identifier.</param>
- /// <param name="command">The command.</param>
- /// <returns>Task.</returns>
- Task SendCommandAsync(string sessionId, GeneralCommand command);
-
- /// <summary>
- /// Sends the string.
- /// </summary>
- /// <param name="sessionId">The session identifier.</param>
- /// <param name="text">The text.</param>
- /// <returns>Task.</returns>
- Task SendString(string sessionId, string text);
-
- /// <summary>
- /// Sets the volume.
- /// </summary>
- /// <param name="sessionId">The session identifier.</param>
- /// <param name="volume">The volume.</param>
- /// <returns>Task.</returns>
- Task SetVolume(string sessionId, int volume);
-
- /// <summary>
- /// Stops the transcoding processes.
- /// </summary>
- /// <param name="deviceId">The device identifier.</param>
- /// <param name="streamId">The stream identifier.</param>
- /// <returns>Task.</returns>
- Task StopTranscodingProcesses(string deviceId, string streamId);
-
- /// <summary>
- /// Sets the index of the audio stream.
- /// </summary>
- /// <param name="sessionId">The session identifier.</param>
- /// <param name="index">The index.</param>
- /// <returns>Task.</returns>
- Task SetAudioStreamIndex(string sessionId, int index);
-
- /// <summary>
- /// Sets the index of the subtitle stream.
- /// </summary>
- /// <param name="sessionId">The session identifier.</param>
- /// <param name="index">The index.</param>
- /// <returns>Task.</returns>
- Task SetSubtitleStreamIndex(string sessionId, int? index);
-
- /// <summary>
- /// Instructs the client to display a message to the user
- /// </summary>
- /// <param name="sessionId">The session id.</param>
- /// <param name="command">The command.</param>
- /// <returns>Task.</returns>
- Task SendMessageCommandAsync(string sessionId, MessageCommand command);
-
- /// <summary>
- /// Clears a user's rating for an item
- /// </summary>
- /// <param name="itemId">The item id.</param>
- /// <param name="userId">The user id.</param>
- /// <returns>Task{UserItemDataDto}.</returns>
- /// <exception cref="ArgumentNullException">itemId</exception>
- Task<UserItemDataDto> ClearUserItemRatingAsync(string itemId, string userId);
-
- /// <summary>
- /// Updates a user's rating for an item, based on likes or dislikes
- /// </summary>
- /// <param name="itemId">The item id.</param>
- /// <param name="userId">The user id.</param>
- /// <param name="likes">if set to <c>true</c> [likes].</param>
- /// <returns>Task.</returns>
- /// <exception cref="ArgumentNullException">itemId</exception>
- Task<UserItemDataDto> UpdateUserItemRatingAsync(string itemId, string userId, bool likes);
-
- /// <summary>
- /// Authenticates a user and returns the result
- /// </summary>
- /// <param name="username">The username.</param>
- /// <param name="password">The password.</param>
- /// <returns>Task.</returns>
- /// <exception cref="ArgumentNullException">userId</exception>
- Task<AuthenticationResult> AuthenticateUserAsync(string username,
- string password);
-
- /// <summary>
- /// Updates the server configuration async.
- /// </summary>
- /// <param name="configuration">The configuration.</param>
- /// <returns>Task.</returns>
- /// <exception cref="ArgumentNullException">configuration</exception>
- Task UpdateServerConfigurationAsync(ServerConfiguration configuration);
-
- /// <summary>
- /// Updates the scheduled task triggers.
- /// </summary>
- /// <param name="id">The id.</param>
- /// <param name="triggers">The triggers.</param>
- /// <returns>Task{RequestResult}.</returns>
- /// <exception cref="ArgumentNullException">id</exception>
- Task UpdateScheduledTaskTriggersAsync(string id, TaskTriggerInfo[] triggers);
-
- /// <summary>
- /// Gets the display preferences.
- /// </summary>
- /// <param name="id">The id.</param>
- /// <param name="userId">The user id.</param>
- /// <param name="client">The client.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task{BaseItemDto}.</returns>
- Task<DisplayPreferences> GetDisplayPreferencesAsync(string id, string userId, string client, CancellationToken cancellationToken = default(CancellationToken));
-
- /// <summary>
- /// Updates display preferences for a user
- /// </summary>
- /// <param name="displayPreferences">The display preferences.</param>
- /// <param name="userId">The user id.</param>
- /// <param name="client">The client.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task{DisplayPreferences}.</returns>
- /// <exception cref="System.ArgumentNullException">userId</exception>
- Task UpdateDisplayPreferencesAsync(DisplayPreferences displayPreferences, string userId, string client, CancellationToken cancellationToken = default(CancellationToken));
-
- /// <summary>
- /// Posts a set of data to a url, and deserializes the return stream into T
- /// </summary>
- /// <typeparam name="T"></typeparam>
- /// <param name="url">The URL.</param>
- /// <param name="args">The args.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task{``0}.</returns>
- Task<T> PostAsync<T>(string url, Dictionary<string, string> args, CancellationToken cancellationToken = default(CancellationToken))
- where T : class;
-
- /// <summary>
- /// This is a helper around getting a stream from the server that contains serialized data
- /// </summary>
- /// <param name="url">The URL.</param>
- /// <returns>Task{Stream}.</returns>
- Task<Stream> GetSerializedStreamAsync(string url);
-
- /// <summary>
- /// Gets the json serializer.
- /// </summary>
- /// <value>The json serializer.</value>
- IJsonSerializer JsonSerializer { get; set; }
-
- /// <summary>
- /// Gets or sets the server address
- /// </summary>
- /// <value>The server address.</value>
- string ServerAddress { get; }
-
- /// <summary>
- /// Gets or sets the type of the client.
- /// </summary>
- /// <value>The type of the client.</value>
- string ClientName { get; set; }
-
- /// <summary>
- /// Gets the device.
- /// </summary>
- /// <value>The device.</value>
- IDevice Device { get; }
-
- /// <summary>
- /// Gets or sets the name of the device.
- /// </summary>
- /// <value>The name of the device.</value>
- string DeviceName { get; }
-
- /// <summary>
- /// Gets or sets the device id.
- /// </summary>
- /// <value>The device id.</value>
- string DeviceId { get; }
-
- /// <summary>
- /// Gets or sets the current user id.
- /// </summary>
- /// <value>The current user id.</value>
- string CurrentUserId { get; }
-
- /// <summary>
- /// Gets the access token.
- /// </summary>
- /// <value>The access token.</value>
- string AccessToken { get; }
-
- /// <summary>
- /// Sets the authentication information.
- /// </summary>
- /// <param name="accessToken">The access token.</param>
- /// <param name="userId">The user identifier.</param>
- void SetAuthenticationInfo(string accessToken, string userId);
-
- /// <summary>
- /// Sets the authentication information.
- /// </summary>
- /// <param name="accessToken">The access token.</param>
- void SetAuthenticationInfo(string accessToken);
-
- /// <summary>
- /// Clears the authentication information.
- /// </summary>
- void ClearAuthenticationInfo();
-
- /// <summary>
- /// Changes the server location.
- /// </summary>
- /// <param name="address">The address.</param>
- /// <param name="keepExistingAuth">if set to <c>true</c> [keep existing authentication].</param>
- void ChangeServerLocation(string address, bool keepExistingAuth = false);
-
- /// <summary>
- /// Starts the receiving synchronize job updates.
- /// </summary>
- /// <param name="intervalMs">The interval ms.</param>
- /// <param name="jobId">The job identifier.</param>
- /// <returns>Task.</returns>
- Task StartReceivingSyncJobUpdates(int intervalMs, string jobId);
-
- /// <summary>
- /// Stops the receiving synchronize job updates.
- /// </summary>
- /// <returns>Task.</returns>
- Task StopReceivingSyncJobUpdates();
-
- /// <summary>
- /// Starts the receiving synchronize jobs updates.
- /// </summary>
- /// <param name="intervalMs">The interval ms.</param>
- /// <param name="userId">The user identifier.</param>
- /// <param name="targetId">The target identifier.</param>
- /// <returns>Task.</returns>
- Task StartReceivingSyncJobsUpdates(int intervalMs, string userId, string targetId);
-
- /// <summary>
- /// Stops the receiving synchronize jobs updates.
- /// </summary>
- /// <returns>Task.</returns>
- Task StopReceivingSyncJobsUpdates();
-
- /// <summary>
- /// Starts the receiving session updates.
- /// </summary>
- /// <param name="intervalMs">The interval ms.</param>
- /// <returns>Task.</returns>
- Task StartReceivingSessionUpdates(int intervalMs);
-
- /// <summary>
- /// Stops the receiving session updates.
- /// </summary>
- /// <returns>Task.</returns>
- Task StopReceivingSessionUpdates();
-
- /// <summary>
- /// Gets the image URL.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="options">The options.</param>
- /// <returns>System.String.</returns>
- /// <exception cref="ArgumentNullException">item</exception>
- string GetImageUrl(BaseItemDto item, ImageOptions options);
-
- /// <summary>
- /// Gets the image URL.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="options">The options.</param>
- /// <returns>System.String.</returns>
- string GetImageUrl(ChannelInfoDto item, ImageOptions options);
-
- /// <summary>
- /// Gets the subtitle URL.
- /// </summary>
- /// <param name="options">The options.</param>
- /// <returns>System.String.</returns>
- string GetSubtitleUrl(SubtitleDownloadOptions options);
-
- /// <summary>
- /// Gets an image url that can be used to download an image from the api
- /// </summary>
- /// <param name="itemId">The Id of the item</param>
- /// <param name="options">The options.</param>
- /// <returns>System.String.</returns>
- /// <exception cref="ArgumentNullException">itemId</exception>
- string GetImageUrl(string itemId, ImageOptions options);
-
- /// <summary>
- /// Gets the user image URL.
- /// </summary>
- /// <param name="user">The user.</param>
- /// <param name="options">The options.</param>
- /// <returns>System.String.</returns>
- /// <exception cref="ArgumentNullException">user</exception>
- string GetUserImageUrl(UserDto user, ImageOptions options);
-
- /// <summary>
- /// Gets an image url that can be used to download an image from the api
- /// </summary>
- /// <param name="userId">The Id of the user</param>
- /// <param name="options">The options.</param>
- /// <returns>System.String.</returns>
- /// <exception cref="ArgumentNullException">userId</exception>
- string GetUserImageUrl(string userId, ImageOptions options);
-
- /// <summary>
- /// Gets the person image URL.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="options">The options.</param>
- /// <returns>System.String.</returns>
- /// <exception cref="ArgumentNullException">item</exception>
- string GetPersonImageUrl(BaseItemPerson item, ImageOptions options);
-
- /// <summary>
- /// Gets an image url that can be used to download an image from the api
- /// </summary>
- /// <param name="name">The name.</param>
- /// <param name="options">The options.</param>
- /// <returns>System.String.</returns>
- /// <exception cref="ArgumentNullException">name</exception>
- string GetGenreImageUrl(string name, ImageOptions options);
-
- /// <summary>
- /// Gets the music genre image URL.
- /// </summary>
- /// <param name="name">The name.</param>
- /// <param name="options">The options.</param>
- /// <returns>System.String.</returns>
- string GetMusicGenreImageUrl(string name, ImageOptions options);
-
- /// <summary>
- /// Gets the game genre image URL.
- /// </summary>
- /// <param name="name">The name.</param>
- /// <param name="options">The options.</param>
- /// <returns>System.String.</returns>
- string GetGameGenreImageUrl(string name, ImageOptions options);
-
- /// <summary>
- /// This is a helper to get a list of backdrop url's from a given ApiBaseItemWrapper. If the actual item does not have any backdrops it will return backdrops from the first parent that does.
- /// </summary>
- /// <param name="item">A given item.</param>
- /// <param name="options">The options.</param>
- /// <returns>System.String[][].</returns>
- /// <exception cref="ArgumentNullException">item</exception>
- string[] GetBackdropImageUrls(BaseItemDto item, ImageOptions options);
-
- /// <summary>
- /// This is a helper to get the logo image url from a given ApiBaseItemWrapper. If the actual item does not have a logo, it will return the logo from the first parent that does, or null.
- /// </summary>
- /// <param name="item">A given item.</param>
- /// <param name="options">The options.</param>
- /// <returns>System.String.</returns>
- /// <exception cref="ArgumentNullException">item</exception>
- string GetLogoImageUrl(BaseItemDto item, ImageOptions options);
-
- /// <summary>
- /// Gets the art image URL.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="options">The options.</param>
- /// <returns>System.String.</returns>
- string GetArtImageUrl(BaseItemDto item, ImageOptions options);
-
- /// <summary>
- /// Gets the thumb image URL.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="options">The options.</param>
- /// <returns>System.String.</returns>
- string GetThumbImageUrl(BaseItemDto item, ImageOptions options);
-
- /// <summary>
- /// Gets the live tv information asynchronous.
- /// </summary>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task{LiveTvInfo}.</returns>
- Task<LiveTvInfo> GetLiveTvInfoAsync(CancellationToken cancellationToken = default(CancellationToken));
-
- /// <summary>
- /// Gets the live tv channels asynchronous.
- /// </summary>
- /// <param name="query">The query.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task{LiveTvInfo}.</returns>
- Task<QueryResult<ChannelInfoDto>> GetLiveTvChannelsAsync(LiveTvChannelQuery query, CancellationToken cancellationToken = default(CancellationToken));
-
- /// <summary>
- /// Gets the live tv channel asynchronous.
- /// </summary>
- /// <param name="id">The identifier.</param>
- /// <param name="userId">The user identifier.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task{ChannelInfoDto}.</returns>
- Task<ChannelInfoDto> GetLiveTvChannelAsync(string id, string userId, CancellationToken cancellationToken = default(CancellationToken));
-
- /// <summary>
- /// Gets the live tv recordings asynchronous.
- /// </summary>
- /// <param name="query">The query.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task{QueryResult{RecordingInfoDto}}.</returns>
- Task<QueryResult<BaseItemDto>> GetLiveTvRecordingsAsync(RecordingQuery query, CancellationToken cancellationToken = default(CancellationToken));
-
- /// <summary>
- /// Gets the live tv recording asynchronous.
- /// </summary>
- /// <param name="id">The identifier.</param>
- /// <param name="userId">The user identifier.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task{RecordingInfoDto}.</returns>
- Task<BaseItemDto> GetLiveTvRecordingAsync(string id, string userId, CancellationToken cancellationToken = default(CancellationToken));
-
- /// <summary>
- /// Gets the live tv recording groups asynchronous.
- /// </summary>
- /// <param name="query">The query.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task{QueryResult{RecordingGroupDto}}.</returns>
- Task<QueryResult<BaseItemDto>> GetLiveTvRecordingGroupsAsync(RecordingGroupQuery query, CancellationToken cancellationToken = default(CancellationToken));
-
- /// <summary>
- /// Gets the live tv recording group asynchronous.
- /// </summary>
- /// <param name="id">The identifier.</param>
- /// <param name="userId">The user identifier.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task{RecordingGroupDto}.</returns>
- Task<BaseItemDto> GetLiveTvRecordingGroupAsync(string id, string userId, CancellationToken cancellationToken = default(CancellationToken));
-
- /// <summary>
- /// Gets the live tv timers asynchronous.
- /// </summary>
- /// <param name="query">The query.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task{QueryResult{TimerInfoDto}}.</returns>
- Task<QueryResult<TimerInfoDto>> GetLiveTvTimersAsync(TimerQuery query, CancellationToken cancellationToken = default(CancellationToken));
-
- /// <summary>
- /// Gets the live tv programs asynchronous.
- /// </summary>
- /// <param name="query">The query.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task{QueryResult{ProgramInfoDto}}.</returns>
- Task<QueryResult<BaseItemDto>> GetLiveTvProgramsAsync(ProgramQuery query, CancellationToken cancellationToken = default(CancellationToken));
-
- /// <summary>
- /// Gets the live tv program asynchronous.
- /// </summary>
- /// <param name="id">The identifier.</param>
- /// <param name="userId">The user identifier.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task{ProgramInfoDto}.</returns>
- Task<BaseItemDto> GetLiveTvProgramAsync(string id, string userId, CancellationToken cancellationToken = default(CancellationToken));
-
- /// <summary>
- /// Gets the recommended live tv programs asynchronous.
- /// </summary>
- /// <param name="query">The query.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task{QueryResult{ProgramInfoDto}}.</returns>
- Task<QueryResult<BaseItemDto>> GetRecommendedLiveTvProgramsAsync(RecommendedProgramQuery query, CancellationToken cancellationToken = default(CancellationToken));
-
- /// <summary>
- /// Creates the live tv timer asynchronous.
- /// </summary>
- /// <param name="timer">The timer.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- Task CreateLiveTvTimerAsync(BaseTimerInfoDto timer, CancellationToken cancellationToken = default(CancellationToken));
-
- /// <summary>
- /// Updates the live tv timer asynchronous.
- /// </summary>
- /// <param name="timer">The timer.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- Task UpdateLiveTvTimerAsync(TimerInfoDto timer, CancellationToken cancellationToken = default(CancellationToken));
-
- /// <summary>
- /// Creates the live tv series timer asynchronous.
- /// </summary>
- /// <param name="timer">The timer.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- Task CreateLiveTvSeriesTimerAsync(SeriesTimerInfoDto timer, CancellationToken cancellationToken = default(CancellationToken));
-
- /// <summary>
- /// Updates the live tv series timer asynchronous.
- /// </summary>
- /// <param name="timer">The timer.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- Task UpdateLiveTvSeriesTimerAsync(SeriesTimerInfoDto timer, CancellationToken cancellationToken = default(CancellationToken));
-
- /// <summary>
- /// Gets the live tv timer asynchronous.
- /// </summary>
- /// <param name="id">The identifier.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task{TimerInfoDto}.</returns>
- Task<TimerInfoDto> GetLiveTvTimerAsync(string id, CancellationToken cancellationToken = default(CancellationToken));
-
- /// <summary>
- /// Gets the live tv series timers asynchronous.
- /// </summary>
- /// <param name="query">The query.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task{QueryResult{SeriesTimerInfoDto}}.</returns>
- Task<QueryResult<SeriesTimerInfoDto>> GetLiveTvSeriesTimersAsync(SeriesTimerQuery query, CancellationToken cancellationToken = default(CancellationToken));
-
- /// <summary>
- /// Gets the live tv series timer asynchronous.
- /// </summary>
- /// <param name="id">The identifier.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task{SeriesTimerInfoDto}.</returns>
- Task<SeriesTimerInfoDto> GetLiveTvSeriesTimerAsync(string id, CancellationToken cancellationToken = default(CancellationToken));
-
- /// <summary>
- /// Cancels the live tv timer asynchronous.
- /// </summary>
- /// <param name="id">The identifier.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- Task CancelLiveTvTimerAsync(string id, CancellationToken cancellationToken = default(CancellationToken));
-
- /// <summary>
- /// Cancels the live tv series timer asynchronous.
- /// </summary>
- /// <param name="id">The identifier.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- Task CancelLiveTvSeriesTimerAsync(string id, CancellationToken cancellationToken = default(CancellationToken));
-
- /// <summary>
- /// Gets the default timer information.
- /// </summary>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task{SeriesTimerInfoDto}.</returns>
- Task<SeriesTimerInfoDto> GetDefaultLiveTvTimerInfo(CancellationToken cancellationToken = default(CancellationToken));
-
- /// <summary>
- /// Gets the live tv guide information.
- /// </summary>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task{GuideInfo}.</returns>
- Task<GuideInfo> GetLiveTvGuideInfo(CancellationToken cancellationToken = default(CancellationToken));
-
- /// <summary>
- /// Gets the default timer information.
- /// </summary>
- /// <param name="programId">The program identifier.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task{SeriesTimerInfoDto}.</returns>
- Task<SeriesTimerInfoDto> GetDefaultLiveTvTimerInfo(string programId, CancellationToken cancellationToken = default(CancellationToken));
-
- /// <summary>
- /// Gets the channel features.
- /// </summary>
- /// <param name="channelId">The channel identifier.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task{ChannelFeatures}.</returns>
- Task<ChannelFeatures> GetChannelFeatures(string channelId, CancellationToken cancellationToken = default(CancellationToken));
-
- /// <summary>
- /// Gets the channel items.
- /// </summary>
- /// <param name="query">The query.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task{QueryResult{BaseItemDto}}.</returns>
- Task<QueryResult<BaseItemDto>> GetChannelItems(ChannelItemQuery query, CancellationToken cancellationToken = default(CancellationToken));
-
- /// <summary>
- /// Gets the channels.
- /// </summary>
- /// <param name="query">The query.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task{QueryResult{BaseItemDto}}.</returns>
- Task<QueryResult<BaseItemDto>> GetChannels(ChannelQuery query, CancellationToken cancellationToken = default(CancellationToken));
-
- /// <summary>
- /// Gets the latest channel items.
- /// </summary>
- /// <param name="query">The query.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task{QueryResult{BaseItemDto}}.</returns>
- Task<QueryResult<BaseItemDto>> GetLatestChannelItems(AllChannelMediaQuery query, CancellationToken cancellationToken = default(CancellationToken));
-
- /// <summary>
- /// Creates the playlist.
- /// </summary>
- /// <param name="request">The request.</param>
- /// <returns>Task&lt;PlaylistCreationResult&gt;.</returns>
- Task<PlaylistCreationResult> CreatePlaylist(PlaylistCreationRequest request);
-
- /// <summary>
- /// Adds to playlist.
- /// </summary>
- /// <param name="playlistId">The playlist identifier.</param>
- /// <param name="itemIds">The item ids.</param>
- /// <param name="userId">The user identifier.</param>
- /// <returns>Task.</returns>
- Task AddToPlaylist(string playlistId, IEnumerable<string> itemIds, string userId);
-
- /// <summary>
- /// Removes from playlist.
- /// </summary>
- /// <param name="playlistId">The playlist identifier.</param>
- /// <param name="entryIds">The entry ids.</param>
- /// <returns>Task.</returns>
- Task RemoveFromPlaylist(string playlistId, IEnumerable<string> entryIds);
-
- /// <summary>
- /// Gets the playlist items.
- /// </summary>
- /// <param name="query">The query.</param>
- /// <returns>Task&lt;QueryResult&lt;BaseItemDto&gt;&gt;.</returns>
- Task<QueryResult<BaseItemDto>> GetPlaylistItems(PlaylistItemQuery query);
-
- /// <summary>
- /// Sends the context message asynchronous.
- /// </summary>
- /// <param name="itemType">Type of the item.</param>
- /// <param name="itemId">The item identifier.</param>
- /// <param name="itemName">Name of the item.</param>
- /// <param name="context">The context.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- Task SendContextMessageAsync(string itemType, string itemId, string itemName, string context,
- CancellationToken cancellationToken = default(CancellationToken));
-
- /// <summary>
- /// Gets the content upload history.
- /// </summary>
- /// <param name="deviceId">The device identifier.</param>
- /// <returns>Task&lt;ContentUploadHistory&gt;.</returns>
- Task<ContentUploadHistory> GetContentUploadHistory(string deviceId);
-
- /// <summary>
- /// Uploads the file.
- /// </summary>
- /// <param name="stream">The stream.</param>
- /// <param name="file">The file.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- Task UploadFile(Stream stream,
- LocalFileInfo file,
- CancellationToken cancellationToken = default(CancellationToken));
-
- /// <summary>
- /// Gets the devices options options.
- /// </summary>
- /// <returns>Task&lt;DevicesOptions&gt;.</returns>
- Task<DevicesOptions> GetDevicesOptions();
-
- /// <summary>
- /// Updates the item.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <returns>Task.</returns>
- Task UpdateItem(BaseItemDto item);
-
- /// <summary>
- /// Creates the synchronize job.
- /// </summary>
- /// <param name="request">The request.</param>
- /// <returns>Task&lt;SyncJob&gt;.</returns>
- Task<SyncJob> CreateSyncJob(SyncJobRequest request);
-
- /// <summary>
- /// Updates the synchronize job.
- /// </summary>
- /// <param name="job">The job.</param>
- /// <returns>Task.</returns>
- Task UpdateSyncJob(SyncJob job);
-
- /// <summary>
- /// Gets the synchronize jobs.
- /// </summary>
- /// <param name="query">The query.</param>
- /// <returns>Task&lt;QueryResult&lt;SyncJob&gt;&gt;.</returns>
- Task<QueryResult<SyncJob>> GetSyncJobs(SyncJobQuery query);
-
- /// <summary>
- /// Gets the synchronize job items.
- /// </summary>
- /// <param name="query">The query.</param>
- /// <returns>Task&lt;QueryResult&lt;SyncJobItem&gt;&gt;.</returns>
- Task<QueryResult<SyncJobItem>> GetSyncJobItems(SyncJobItemQuery query);
-
- /// <summary>
- /// Reports the synchronize job item transferred.
- /// </summary>
- /// <param name="id">The identifier.</param>
- /// <returns>Task.</returns>
- Task ReportSyncJobItemTransferred(string id);
-
- /// <summary>
- /// Gets the synchronize job item file.
- /// </summary>
- /// <param name="id">The identifier.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task&lt;Stream&gt;.</returns>
- Task<Stream> GetSyncJobItemFile(string id, CancellationToken cancellationToken = default(CancellationToken));
-
- /// <summary>
- /// Gets the synchronize job item additional file.
- /// </summary>
- /// <param name="id">The identifier.</param>
- /// <param name="name">The name.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task&lt;Stream&gt;.</returns>
- Task<Stream> GetSyncJobItemAdditionalFile(string id, string name, CancellationToken cancellationToken);
-
- /// <summary>
- /// Opens the web socket.
- /// </summary>
- /// <param name="webSocketFactory">The web socket factory.</param>
- /// <param name="keepAliveTimerMs">The keep alive timer ms.</param>
- void OpenWebSocket(Func<IClientWebSocket> webSocketFactory, int keepAliveTimerMs = 60000);
-
- /// <summary>
- /// Reports the offline actions.
- /// </summary>
- /// <param name="actions">The actions.</param>
- /// <returns>Task.</returns>
- Task ReportOfflineActions(List<UserAction> actions);
-
- /// <summary>
- /// Gets the ready synchronize items.
- /// </summary>
- /// <param name="targetId">The target identifier.</param>
- /// <returns>List&lt;SyncedItem&gt;.</returns>
- Task<List<SyncedItem>> GetReadySyncItems(string targetId);
-
- /// <summary>
- /// Synchronizes the data.
- /// </summary>
- /// <param name="request">The request.</param>
- /// <returns>Task&lt;SyncDataResponse&gt;.</returns>
- Task<SyncDataResponse> SyncData(SyncDataRequest request);
- /// <summary>
- /// Gets the synchronize job item file URL.
- /// </summary>
- /// <param name="id">The identifier.</param>
- /// <returns>System.String.</returns>
- string GetSyncJobItemFileUrl(string id);
- /// <summary>
- /// Marks the synchronize job item for removal.
- /// </summary>
- /// <param name="id">The identifier.</param>
- /// <returns>Task.</returns>
- Task MarkSyncJobItemForRemoval(string id);
- /// <summary>
- /// Unmarks the synchronize job item for removal.
- /// </summary>
- /// <param name="id">The identifier.</param>
- /// <returns>Task.</returns>
- Task UnmarkSyncJobItemForRemoval(string id);
- /// <summary>
- /// Queues the failed synchronize job item for retry.
- /// </summary>
- /// <param name="id">The identifier.</param>
- /// <returns>Task.</returns>
- Task QueueFailedSyncJobItemForRetry(string id);
- /// <summary>
- /// Cancels the synchronize job.
- /// </summary>
- /// <param name="id">The identifier.</param>
- /// <returns>Task.</returns>
- Task CancelSyncJob(string id);
- /// <summary>
- /// Cancels the synchronize job item.
- /// </summary>
- /// <param name="id">The identifier.</param>
- /// <returns>Task.</returns>
- Task CancelSyncJobItem(string id);
- /// <summary>
- /// Enables the cancelled synchronize job item.
- /// </summary>
- /// <param name="id">The identifier.</param>
- /// <returns>Task.</returns>
- Task EnableCancelledSyncJobItem(string id);
- /// <summary>
- /// Gets the synchronize options.
- /// </summary>
- /// <param name="jobInfo">The job information.</param>
- /// <returns>Task&lt;SyncOptions&gt;.</returns>
- Task<SyncDialogOptions> GetSyncOptions(SyncJobRequest jobInfo);
- /// <summary>
- /// Gets the synchronize options.
- /// </summary>
- /// <param name="jobInfo">The job information.</param>
- /// <returns>Task&lt;SyncDialogOptions&gt;.</returns>
- Task<SyncDialogOptions> GetSyncOptions(SyncJob jobInfo);
- /// <summary>
- /// Gets the movie recommendations.
- /// </summary>
- /// <param name="query">The query.</param>
- /// <returns>Task&lt;List&lt;RecommendationDto&gt;&gt;.</returns>
- Task<List<RecommendationDto>> GetMovieRecommendations(MovieRecommendationQuery query);
- /// <summary>
- /// Opens the live stream.
- /// </summary>
- /// <param name="request">The request.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task&lt;LiveStreamResponse&gt;.</returns>
- Task<LiveStreamResponse> OpenLiveStream(LiveStreamRequest request, CancellationToken cancellationToken);
- /// <summary>
- /// Cancels the synchronize library items.
- /// </summary>
- /// <param name="targetId">The target identifier.</param>
- /// <param name="itemIds">The item ids.</param>
- /// <returns>Task.</returns>
- Task CancelSyncLibraryItems(string targetId, IEnumerable<string> itemIds);
- /// <summary>
- /// Gets the supported bitrate.
- /// </summary>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task&lt;System.Int32&gt;.</returns>
- Task<int> DetectMaxBitrate(CancellationToken cancellationToken);
-
- /// <summary>
- /// Gets the end point information.
- /// </summary>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>System.Threading.Tasks.Task&lt;MediaBrowser.Model.Net.EndPointInfo&gt;.</returns>
- Task<EndPointInfo> GetEndPointInfo(CancellationToken cancellationToken);
- }
-} \ No newline at end of file
diff --git a/MediaBrowser.Model/ApiClient/IClientWebSocket.cs b/MediaBrowser.Model/ApiClient/IClientWebSocket.cs
deleted file mode 100644
index ca3a761d4..000000000
--- a/MediaBrowser.Model/ApiClient/IClientWebSocket.cs
+++ /dev/null
@@ -1,54 +0,0 @@
-using MediaBrowser.Model.Net;
-using System;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace MediaBrowser.Model.ApiClient
-{
- /// <summary>
- /// Interface IClientWebSocket
- /// </summary>
- public interface IClientWebSocket : IDisposable
- {
- /// <summary>
- /// Occurs when [closed].
- /// </summary>
- event EventHandler Closed;
-
- /// <summary>
- /// Gets or sets the state.
- /// </summary>
- /// <value>The state.</value>
- WebSocketState State { get; }
-
- /// <summary>
- /// Connects the async.
- /// </summary>
- /// <param name="url">The URL.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- Task ConnectAsync(string url, CancellationToken cancellationToken);
-
- /// <summary>
- /// Gets or sets the receive action.
- /// </summary>
- /// <value>The receive action.</value>
- Action<byte[]> OnReceiveBytes { get; set; }
-
- /// <summary>
- /// Gets or sets the on receive.
- /// </summary>
- /// <value>The on receive.</value>
- Action<string> OnReceive { get; set; }
-
- /// <summary>
- /// Sends the async.
- /// </summary>
- /// <param name="bytes">The bytes.</param>
- /// <param name="type">The type.</param>
- /// <param name="endOfMessage">if set to <c>true</c> [end of message].</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- Task SendAsync(byte[] bytes, WebSocketMessageType type, bool endOfMessage, CancellationToken cancellationToken);
- }
-}
diff --git a/MediaBrowser.Model/ApiClient/IConnectionManager.cs b/MediaBrowser.Model/ApiClient/IConnectionManager.cs
deleted file mode 100644
index 083f230bc..000000000
--- a/MediaBrowser.Model/ApiClient/IConnectionManager.cs
+++ /dev/null
@@ -1,192 +0,0 @@
-using MediaBrowser.Model.Connect;
-using MediaBrowser.Model.Dto;
-using MediaBrowser.Model.Events;
-using MediaBrowser.Model.Session;
-using System;
-using System.Collections.Generic;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace MediaBrowser.Model.ApiClient
-{
- public interface IConnectionManager
- {
- /// <summary>
- /// Occurs when [connected].
- /// </summary>
- event EventHandler<GenericEventArgs<ConnectionResult>> Connected;
- /// <summary>
- /// Occurs when [local user sign in].
- /// </summary>
- event EventHandler<GenericEventArgs<UserDto>> LocalUserSignIn;
- /// <summary>
- /// Occurs when [connect user sign in].
- /// </summary>
- event EventHandler<GenericEventArgs<ConnectUser>> ConnectUserSignIn;
- /// <summary>
- /// Occurs when [local user sign out].
- /// </summary>
- event EventHandler<GenericEventArgs<IApiClient>> LocalUserSignOut;
- /// <summary>
- /// Occurs when [connect user sign out].
- /// </summary>
- event EventHandler<EventArgs> ConnectUserSignOut;
- /// <summary>
- /// Occurs when [remote logged out].
- /// </summary>
- event EventHandler<EventArgs> RemoteLoggedOut;
-
- /// <summary>
- /// Gets the device.
- /// </summary>
- /// <value>The device.</value>
- IDevice Device { get; }
-
- /// <summary>
- /// Gets the connect user.
- /// </summary>
- /// <value>The connect user.</value>
- ConnectUser ConnectUser { get; }
-
- /// <summary>
- /// Gets or sets a value indicating whether [save local credentials].
- /// </summary>
- /// <value><c>true</c> if [save local credentials]; otherwise, <c>false</c>.</value>
- bool SaveLocalCredentials { get; set; }
-
- /// <summary>
- /// Gets the client capabilities.
- /// </summary>
- /// <value>The client capabilities.</value>
- ClientCapabilities ClientCapabilities { get; }
-
- /// <summary>
- /// Gets the API client.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <returns>IApiClient.</returns>
- IApiClient GetApiClient(IHasServerId item);
-
- /// <summary>
- /// Gets the API client.
- /// </summary>
- /// <param name="serverId">The server identifier.</param>
- /// <returns>IApiClient.</returns>
- IApiClient GetApiClient(string serverId);
-
- /// <summary>
- /// Connects the specified cancellation token.
- /// </summary>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task&lt;ConnectionResult&gt;.</returns>
- Task<ConnectionResult> Connect(CancellationToken cancellationToken = default(CancellationToken));
-
- /// <summary>
- /// Connects the specified API client.
- /// </summary>
- /// <param name="apiClient">The API client.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task&lt;ConnectionResult&gt;.</returns>
- Task<ConnectionResult> Connect(IApiClient apiClient, CancellationToken cancellationToken = default(CancellationToken));
-
- /// <summary>
- /// Connects the specified server.
- /// </summary>
- /// <param name="server">The server.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task&lt;ConnectionResult&gt;.</returns>
- Task<ConnectionResult> Connect(ServerInfo server, CancellationToken cancellationToken = default(CancellationToken));
-
- /// <summary>
- /// Connects the specified server.
- /// </summary>
- /// <param name="server">The server.</param>
- /// <param name="options">The options.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task&lt;ConnectionResult&gt;.</returns>
- Task<ConnectionResult> Connect(ServerInfo server, ConnectionOptions options, CancellationToken cancellationToken = default(CancellationToken));
-
- /// <summary>
- /// Connects the specified server.
- /// </summary>
- /// <param name="address">The address.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task&lt;ConnectionResult&gt;.</returns>
- Task<ConnectionResult> Connect(string address, CancellationToken cancellationToken = default(CancellationToken));
-
- /// <summary>
- /// Logouts this instance.
- /// </summary>
- /// <returns>Task&lt;ConnectionResult&gt;.</returns>
- Task Logout();
-
- /// <summary>
- /// Logins to connect.
- /// </summary>
- /// <returns>Task.</returns>
- Task LoginToConnect(string username, string password);
-
- /// <summary>
- /// Gets the active api client instance
- /// </summary>
- IApiClient CurrentApiClient { get; }
-
- /// <summary>
- /// Creates the pin.
- /// </summary>
- /// <returns>Task&lt;PinCreationResult&gt;.</returns>
- Task<PinCreationResult> CreatePin();
-
- /// <summary>
- /// Gets the pin status.
- /// </summary>
- /// <param name="pin">The pin.</param>
- /// <returns>Task&lt;PinStatusResult&gt;.</returns>
- Task<PinStatusResult> GetPinStatus(PinCreationResult pin);
-
- /// <summary>
- /// Exchanges the pin.
- /// </summary>
- /// <param name="pin">The pin.</param>
- /// <returns>Task.</returns>
- Task ExchangePin(PinCreationResult pin);
-
- /// <summary>
- /// Gets the server information.
- /// </summary>
- /// <param name="id">The identifier.</param>
- /// <returns>Task&lt;ServerInfo&gt;.</returns>
- Task<ServerInfo> GetServerInfo(string id);
-
- /// <summary>
- /// Gets the available servers.
- /// </summary>
- /// <param name="cancellationToken">The cancellation token.</param>
- Task<List<ServerInfo>> GetAvailableServers(CancellationToken cancellationToken = default(CancellationToken));
-
- /// <summary>
- /// Authenticates an offline user with their password
- /// </summary>
- /// <param name="user">The user.</param>
- /// <param name="password">The password.</param>
- /// <param name="rememberCredentials">if set to <c>true</c> [remember credentials].</param>
- /// <returns>Task.</returns>
- Task AuthenticateOffline(UserDto user, string password, bool rememberCredentials);
-
- /// <summary>
- /// Gets the offline users.
- /// </summary>
- /// <returns>Task&lt;List&lt;UserDto&gt;&gt;.</returns>
- Task<List<UserDto>> GetOfflineUsers();
-
- /// <summary>
- /// Signups for connect.
- /// </summary>
- /// <param name="email">The email.</param>
- /// <param name="username">The username.</param>
- /// <param name="password">The password.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- Task<ConnectSignupResponse> SignupForConnect(string email, string username, string password, CancellationToken cancellationToken = default(CancellationToken));
- }
-}
diff --git a/MediaBrowser.Model/ApiClient/IDevice.cs b/MediaBrowser.Model/ApiClient/IDevice.cs
deleted file mode 100644
index 7b67122fb..000000000
--- a/MediaBrowser.Model/ApiClient/IDevice.cs
+++ /dev/null
@@ -1,44 +0,0 @@
-using MediaBrowser.Model.Devices;
-using System;
-using System.Collections.Generic;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace MediaBrowser.Model.ApiClient
-{
- public interface IDevice
- {
- /// <summary>
- /// Occurs when [resume from sleep].
- /// </summary>
- event EventHandler<EventArgs> ResumeFromSleep;
- /// <summary>
- /// Gets the name of the device.
- /// </summary>
- /// <value>The name of the device.</value>
- string DeviceName { get; }
- /// <summary>
- /// Gets the device identifier.
- /// </summary>
- /// <value>The device identifier.</value>
- string DeviceId { get; }
- /// <summary>
- /// Gets the local images.
- /// </summary>
- /// <returns>IEnumerable&lt;LocalFileInfo&gt;.</returns>
- Task<IEnumerable<LocalFileInfo>> GetLocalPhotos();
- /// <summary>
- /// Gets the local videos.
- /// </summary>
- /// <returns>IEnumerable&lt;LocalFileInfo&gt;.</returns>
- Task<IEnumerable<LocalFileInfo>> GetLocalVideos();
- /// <summary>
- /// Uploads the file.
- /// </summary>
- /// <param name="file">The file.</param>
- /// <param name="apiClient">The API client.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- Task UploadFile(LocalFileInfo file, IApiClient apiClient, CancellationToken cancellationToken = default(CancellationToken));
- }
-}
diff --git a/MediaBrowser.Model/ApiClient/IServerEvents.cs b/MediaBrowser.Model/ApiClient/IServerEvents.cs
deleted file mode 100644
index ae2d5d323..000000000
--- a/MediaBrowser.Model/ApiClient/IServerEvents.cs
+++ /dev/null
@@ -1,152 +0,0 @@
-using MediaBrowser.Model.Dto;
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Events;
-using MediaBrowser.Model.Plugins;
-using MediaBrowser.Model.Session;
-using MediaBrowser.Model.Sync;
-using MediaBrowser.Model.Tasks;
-using MediaBrowser.Model.Updates;
-using System;
-using System.Collections.Generic;
-
-namespace MediaBrowser.Model.ApiClient
-{
- /// <summary>
- /// Interface IServerEvents
- /// </summary>
- public interface IServerEvents
- {
- /// <summary>
- /// Occurs when [user deleted].
- /// </summary>
- event EventHandler<GenericEventArgs<string>> UserDeleted;
- /// <summary>
- /// Occurs when [scheduled task ended].
- /// </summary>
- event EventHandler<GenericEventArgs<TaskResult>> ScheduledTaskEnded;
- /// <summary>
- /// Occurs when [package installing].
- /// </summary>
- event EventHandler<GenericEventArgs<InstallationInfo>> PackageInstalling;
- /// <summary>
- /// Occurs when [package installation failed].
- /// </summary>
- event EventHandler<GenericEventArgs<InstallationInfo>> PackageInstallationFailed;
- /// <summary>
- /// Occurs when [package installation completed].
- /// </summary>
- event EventHandler<GenericEventArgs<InstallationInfo>> PackageInstallationCompleted;
- /// <summary>
- /// Occurs when [package installation cancelled].
- /// </summary>
- event EventHandler<GenericEventArgs<InstallationInfo>> PackageInstallationCancelled;
- /// <summary>
- /// Occurs when [user updated].
- /// </summary>
- event EventHandler<GenericEventArgs<UserDto>> UserUpdated;
- /// <summary>
- /// Occurs when [plugin uninstalled].
- /// </summary>
- event EventHandler<GenericEventArgs<PluginInfo>> PluginUninstalled;
- /// <summary>
- /// Occurs when [library changed].
- /// </summary>
- event EventHandler<GenericEventArgs<LibraryUpdateInfo>> LibraryChanged;
- /// <summary>
- /// Occurs when [browse command].
- /// </summary>
- event EventHandler<GenericEventArgs<BrowseRequest>> BrowseCommand;
- /// <summary>
- /// Occurs when [play command].
- /// </summary>
- event EventHandler<GenericEventArgs<PlayRequest>> PlayCommand;
- /// <summary>
- /// Occurs when [playstate command].
- /// </summary>
- event EventHandler<GenericEventArgs<PlaystateRequest>> PlaystateCommand;
- /// <summary>
- /// Occurs when [message command].
- /// </summary>
- event EventHandler<GenericEventArgs<MessageCommand>> MessageCommand;
- /// <summary>
- /// Occurs when [system command].
- /// </summary>
- event EventHandler<GenericEventArgs<GeneralCommandEventArgs>> GeneralCommand;
- /// <summary>
- /// Occurs when [notification added].
- /// </summary>
- event EventHandler<EventArgs> NotificationAdded;
- /// <summary>
- /// Occurs when [notification updated].
- /// </summary>
- event EventHandler<EventArgs> NotificationUpdated;
- /// <summary>
- /// Occurs when [notifications marked read].
- /// </summary>
- event EventHandler<EventArgs> NotificationsMarkedRead;
- /// <summary>
- /// Occurs when [server restarting].
- /// </summary>
- event EventHandler<EventArgs> ServerRestarting;
- /// <summary>
- /// Occurs when [server shutting down].
- /// </summary>
- event EventHandler<EventArgs> ServerShuttingDown;
- /// <summary>
- /// Occurs when [send text command].
- /// </summary>
- event EventHandler<GenericEventArgs<string>> SendStringCommand;
- /// <summary>
- /// Occurs when [set volume command].
- /// </summary>
- event EventHandler<GenericEventArgs<int>> SetVolumeCommand;
- /// <summary>
- /// Occurs when [set audio stream index command].
- /// </summary>
- event EventHandler<GenericEventArgs<int>> SetAudioStreamIndexCommand;
- /// <summary>
- /// Occurs when [set video stream index command].
- /// </summary>
- event EventHandler<GenericEventArgs<int>> SetSubtitleStreamIndexCommand;
- /// <summary>
- /// Occurs when [sessions updated].
- /// </summary>
- event EventHandler<GenericEventArgs<SessionUpdatesEventArgs>> SessionsUpdated;
- /// <summary>
- /// Occurs when [restart required].
- /// </summary>
- event EventHandler<EventArgs> RestartRequired;
- /// <summary>
- /// Occurs when [user data changed].
- /// </summary>
- event EventHandler<GenericEventArgs<UserDataChangeInfo>> UserDataChanged;
- /// <summary>
- /// Occurs when [playback start].
- /// </summary>
- event EventHandler<GenericEventArgs<SessionInfoDto>> PlaybackStart;
- /// <summary>
- /// Occurs when [playback stopped].
- /// </summary>
- event EventHandler<GenericEventArgs<SessionInfoDto>> PlaybackStopped;
- /// <summary>
- /// Occurs when [session ended].
- /// </summary>
- event EventHandler<GenericEventArgs<SessionInfoDto>> SessionEnded;
- /// <summary>
- /// Occurs when [synchronize job created].
- /// </summary>
- event EventHandler<GenericEventArgs<SyncJobCreationResult>> SyncJobCreated;
- /// <summary>
- /// Occurs when [synchronize job cancelled].
- /// </summary>
- event EventHandler<GenericEventArgs<SyncJob>> SyncJobCancelled;
- /// <summary>
- /// Occurs when [synchronize jobs updated].
- /// </summary>
- event EventHandler<GenericEventArgs<List<SyncJob>>> SyncJobsUpdated;
- /// <summary>
- /// Occurs when [synchronize job updated].
- /// </summary>
- event EventHandler<GenericEventArgs<CompleteSyncJobInfo>> SyncJobUpdated;
- }
-}
diff --git a/MediaBrowser.Model/ApiClient/NetworkStatus.cs b/MediaBrowser.Model/ApiClient/NetworkStatus.cs
deleted file mode 100644
index 715087607..000000000
--- a/MediaBrowser.Model/ApiClient/NetworkStatus.cs
+++ /dev/null
@@ -1,30 +0,0 @@
-
-namespace MediaBrowser.Model.ApiClient
-{
- public class NetworkStatus
- {
- /// <summary>
- /// Gets or sets a value indicating whether this instance is network available.
- /// </summary>
- /// <value><c>true</c> if this instance is network available; otherwise, <c>false</c>.</value>
- public bool IsNetworkAvailable { get; set; }
- /// <summary>
- /// Gets or sets a value indicating whether this instance is local network available.
- /// </summary>
- /// <value><c>null</c> if [is local network available] contains no value, <c>true</c> if [is local network available]; otherwise, <c>false</c>.</value>
- public bool? IsLocalNetworkAvailable { get; set; }
- /// <summary>
- /// Gets the is any local network available.
- /// </summary>
- /// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
- public bool GetIsAnyLocalNetworkAvailable()
- {
- if (!IsLocalNetworkAvailable.HasValue)
- {
- return IsNetworkAvailable;
- }
-
- return IsLocalNetworkAvailable.Value;
- }
- }
-}
diff --git a/MediaBrowser.Model/ApiClient/RemoteLogoutReason.cs b/MediaBrowser.Model/ApiClient/RemoteLogoutReason.cs
deleted file mode 100644
index 237949c69..000000000
--- a/MediaBrowser.Model/ApiClient/RemoteLogoutReason.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-
-namespace MediaBrowser.Model.ApiClient
-{
- public enum RemoteLogoutReason
- {
- GeneralAccesError = 0,
- ParentalControlRestriction = 1
- }
-}
diff --git a/MediaBrowser.Model/ApiClient/ServerCredentials.cs b/MediaBrowser.Model/ApiClient/ServerCredentials.cs
deleted file mode 100644
index ddeb7e546..000000000
--- a/MediaBrowser.Model/ApiClient/ServerCredentials.cs
+++ /dev/null
@@ -1,131 +0,0 @@
-using MediaBrowser.Model.Extensions;
-using System;
-using System.Collections.Generic;
-
-namespace MediaBrowser.Model.ApiClient
-{
- public class ServerCredentials
- {
- public List<ServerInfo> Servers { get; set; }
-
- public string ConnectUserId { get; set; }
- public string ConnectAccessToken { get; set; }
-
- public ServerCredentials()
- {
- Servers = new List<ServerInfo>();
- }
-
- public void AddOrUpdateServer(ServerInfo server)
- {
- if (server == null)
- {
- throw new ArgumentNullException("server");
- }
-
- // Clone the existing list of servers
- var list = new List<ServerInfo>();
- foreach (ServerInfo serverInfo in Servers)
- {
- list.Add(serverInfo);
- }
-
- var index = FindIndex(list, server.Id);
-
- if (index != -1)
- {
- var existing = list[index];
-
- // Take the most recent DateLastAccessed
- if (server.DateLastAccessed > existing.DateLastAccessed)
- {
- existing.DateLastAccessed = server.DateLastAccessed;
- }
-
- existing.UserLinkType = server.UserLinkType;
-
- if (!string.IsNullOrEmpty(server.AccessToken))
- {
- existing.AccessToken = server.AccessToken;
- existing.UserId = server.UserId;
- }
- if (!string.IsNullOrEmpty(server.ExchangeToken))
- {
- existing.ExchangeToken = server.ExchangeToken;
- }
- if (!string.IsNullOrEmpty(server.RemoteAddress))
- {
- existing.RemoteAddress = server.RemoteAddress;
- }
- if (!string.IsNullOrEmpty(server.ConnectServerId))
- {
- existing.ConnectServerId = server.ConnectServerId;
- }
- if (!string.IsNullOrEmpty(server.LocalAddress))
- {
- existing.LocalAddress = server.LocalAddress;
- }
- if (!string.IsNullOrEmpty(server.ManualAddress))
- {
- existing.ManualAddress = server.ManualAddress;
- }
- if (!string.IsNullOrEmpty(server.Name))
- {
- existing.Name = server.Name;
- }
- if (server.WakeOnLanInfos != null && server.WakeOnLanInfos.Count > 0)
- {
- existing.WakeOnLanInfos = new List<WakeOnLanInfo>();
- foreach (WakeOnLanInfo info in server.WakeOnLanInfos)
- {
- existing.WakeOnLanInfos.Add(info);
- }
- }
- if (server.LastConnectionMode.HasValue)
- {
- existing.LastConnectionMode = server.LastConnectionMode;
- }
- foreach (ServerUserInfo user in server.Users)
- {
- existing.AddOrUpdate(user);
- }
- }
- else
- {
- list.Add(server);
- }
-
- Servers = list;
- }
-
- private int FindIndex(List<ServerInfo> servers, string id)
- {
- var index = 0;
-
- foreach (ServerInfo server in servers)
- {
- if (StringHelper.EqualsIgnoreCase(id, server.Id))
- {
- return index;
- }
-
- index++;
- }
-
- return -1;
- }
-
- public ServerInfo GetServer(string id)
- {
- foreach (ServerInfo server in Servers)
- {
- if (StringHelper.EqualsIgnoreCase(id, server.Id))
- {
- return server;
- }
- }
-
- return null;
- }
- }
-}
diff --git a/MediaBrowser.Model/ApiClient/ServerInfo.cs b/MediaBrowser.Model/ApiClient/ServerInfo.cs
deleted file mode 100644
index 48995e80a..000000000
--- a/MediaBrowser.Model/ApiClient/ServerInfo.cs
+++ /dev/null
@@ -1,127 +0,0 @@
-using MediaBrowser.Model.Connect;
-using MediaBrowser.Model.Extensions;
-using MediaBrowser.Model.System;
-using System;
-using System.Collections.Generic;
-
-namespace MediaBrowser.Model.ApiClient
-{
- public class ServerInfo
- {
- public List<ServerUserInfo> Users { get; set; }
-
- public String Name { get; set; }
- public String Id { get; set; }
- public String ConnectServerId { get; set; }
- public String LocalAddress { get; set; }
- public String RemoteAddress { get; set; }
- public String ManualAddress { get; set; }
- public String UserId { get; set; }
- public String AccessToken { get; set; }
- public List<WakeOnLanInfo> WakeOnLanInfos { get; set; }
- public DateTime DateLastAccessed { get; set; }
- public String ExchangeToken { get; set; }
- public UserLinkType? UserLinkType { get; set; }
- public ConnectionMode? LastConnectionMode { get; set; }
-
- public ServerInfo()
- {
- WakeOnLanInfos = new List<WakeOnLanInfo>();
- Users = new List<ServerUserInfo>();
- }
-
- public void ImportInfo(PublicSystemInfo systemInfo)
- {
- Name = systemInfo.ServerName;
- Id = systemInfo.Id;
-
- if (!string.IsNullOrEmpty(systemInfo.LocalAddress))
- {
- LocalAddress = systemInfo.LocalAddress;
- }
-
- if (!string.IsNullOrEmpty(systemInfo.WanAddress))
- {
- RemoteAddress = systemInfo.WanAddress;
- }
-
- var fullSystemInfo = systemInfo as SystemInfo;
-
- if (fullSystemInfo != null)
- {
- WakeOnLanInfos = new List<WakeOnLanInfo>();
-
- if (!string.IsNullOrEmpty(fullSystemInfo.MacAddress))
- {
- WakeOnLanInfos.Add(new WakeOnLanInfo
- {
- MacAddress = fullSystemInfo.MacAddress
- });
- }
- }
- }
-
- public string GetAddress(ConnectionMode mode)
- {
- switch (mode)
- {
- case ConnectionMode.Local:
- return LocalAddress;
- case ConnectionMode.Manual:
- return ManualAddress;
- case ConnectionMode.Remote:
- return RemoteAddress;
- default:
- throw new ArgumentException("Unexpected ConnectionMode");
- }
- }
-
- public void AddOrUpdate(ServerUserInfo user)
- {
- if (user == null)
- {
- throw new ArgumentNullException("user");
- }
-
- // Clone the existing list of users
- var list = new List<ServerUserInfo>();
- foreach (ServerUserInfo serverUserInfo in Users)
- {
- list.Add(serverUserInfo);
- }
-
- var index = FindIndex(list, user.Id);
-
- if (index != -1)
- {
- var existing = list[index];
-
- // Merge the data
- existing.IsSignedInOffline = user.IsSignedInOffline;
- }
- else
- {
- list.Add(user);
- }
-
- Users = list;
- }
-
- private int FindIndex(List<ServerUserInfo> users, string id)
- {
- var index = 0;
-
- foreach (var user in users)
- {
- if (StringHelper.EqualsIgnoreCase(id, user.Id))
- {
- return index;
- }
-
- index++;
- }
-
- return -1;
- }
- }
-}
diff --git a/MediaBrowser.Model/ApiClient/ServerUserInfo.cs b/MediaBrowser.Model/ApiClient/ServerUserInfo.cs
deleted file mode 100644
index 812da7402..000000000
--- a/MediaBrowser.Model/ApiClient/ServerUserInfo.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-
-namespace MediaBrowser.Model.ApiClient
-{
- public class ServerUserInfo
- {
- public string Id { get; set; }
- public bool IsSignedInOffline { get; set; }
- }
-}
diff --git a/MediaBrowser.Model/Channels/AllChannelMediaQuery.cs b/MediaBrowser.Model/Channels/AllChannelMediaQuery.cs
index c5631899e..920f3e4b2 100644
--- a/MediaBrowser.Model/Channels/AllChannelMediaQuery.cs
+++ b/MediaBrowser.Model/Channels/AllChannelMediaQuery.cs
@@ -52,10 +52,10 @@ namespace MediaBrowser.Model.Channels
TrailerTypes = new TrailerType[] { };
Filters = new ItemFilter[] { };
- Fields = new List<ItemFields>();
+ Fields = new ItemFields[]{};
}
public ItemFilter[] Filters { get; set; }
- public List<ItemFields> Fields { get; set; }
+ public ItemFields[] Fields { get; set; }
}
} \ No newline at end of file
diff --git a/MediaBrowser.Model/Channels/ChannelFeatures.cs b/MediaBrowser.Model/Channels/ChannelFeatures.cs
index 8dfdbcd7a..39b40cabc 100644
--- a/MediaBrowser.Model/Channels/ChannelFeatures.cs
+++ b/MediaBrowser.Model/Channels/ChannelFeatures.cs
@@ -26,13 +26,13 @@ namespace MediaBrowser.Model.Channels
/// Gets or sets the media types.
/// </summary>
/// <value>The media types.</value>
- public List<ChannelMediaType> MediaTypes { get; set; }
+ public ChannelMediaType[] MediaTypes { get; set; }
/// <summary>
/// Gets or sets the content types.
/// </summary>
/// <value>The content types.</value>
- public List<ChannelMediaContentType> ContentTypes { get; set; }
+ public ChannelMediaContentType[] ContentTypes { get; set; }
/// <summary>
/// Represents the maximum number of records the channel allows retrieving at a time
@@ -49,7 +49,7 @@ namespace MediaBrowser.Model.Channels
/// Gets or sets the default sort orders.
/// </summary>
/// <value>The default sort orders.</value>
- public List<ChannelItemSortField> DefaultSortFields { get; set; }
+ public ChannelItemSortField[] DefaultSortFields { get; set; }
/// <summary>
/// Indicates if a sort ascending/descending toggle is supported or not.
@@ -76,10 +76,10 @@ namespace MediaBrowser.Model.Channels
public ChannelFeatures()
{
- MediaTypes = new List<ChannelMediaType>();
- ContentTypes = new List<ChannelMediaContentType>();
+ MediaTypes = new ChannelMediaType[] { };
+ ContentTypes = new ChannelMediaContentType[] { };
- DefaultSortFields = new List<ChannelItemSortField>();
+ DefaultSortFields = new ChannelItemSortField[] { };
}
}
}
diff --git a/MediaBrowser.Model/Channels/ChannelItemQuery.cs b/MediaBrowser.Model/Channels/ChannelItemQuery.cs
index 4aacc1619..909d35b38 100644
--- a/MediaBrowser.Model/Channels/ChannelItemQuery.cs
+++ b/MediaBrowser.Model/Channels/ChannelItemQuery.cs
@@ -1,4 +1,6 @@
-using MediaBrowser.Model.Entities;
+using System;
+using System.Collections.Generic;
+using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Querying;
namespace MediaBrowser.Model.Channels
@@ -35,16 +37,15 @@ namespace MediaBrowser.Model.Channels
/// <value>The limit.</value>
public int? Limit { get; set; }
- public SortOrder? SortOrder { get; set; }
- public string[] SortBy { get; set; }
public ItemFilter[] Filters { get; set; }
public ItemFields[] Fields { get; set; }
+ public Tuple<string, SortOrder>[] OrderBy { get; set; }
public ChannelItemQuery()
{
Filters = new ItemFilter[] { };
- SortBy = new string[] { };
Fields = new ItemFields[] { };
+ OrderBy = new Tuple<string, SortOrder>[] { };
}
}
diff --git a/MediaBrowser.Model/Configuration/EncodingOptions.cs b/MediaBrowser.Model/Configuration/EncodingOptions.cs
index e1b0514e7..b093d82e3 100644
--- a/MediaBrowser.Model/Configuration/EncodingOptions.cs
+++ b/MediaBrowser.Model/Configuration/EncodingOptions.cs
@@ -13,8 +13,10 @@ namespace MediaBrowser.Model.Configuration
public string VaapiDevice { get; set; }
public int H264Crf { get; set; }
public string H264Preset { get; set; }
- public bool EnableHardwareDecoding { get; set; }
public bool EnableHardwareEncoding { get; set; }
+ public bool EnableSubtitleExtraction { get; set; }
+
+ public string[] HardwareDecodingCodecs { get; set; }
public EncodingOptions()
{
@@ -24,8 +26,9 @@ namespace MediaBrowser.Model.Configuration
EncodingThreadCount = -1;
VaapiDevice = "/dev/dri/card0";
H264Crf = 23;
- EnableHardwareDecoding = true;
EnableHardwareEncoding = true;
+ EnableSubtitleExtraction = true;
+ HardwareDecodingCodecs = new string[] { "h264", "vc1" };
}
}
}
diff --git a/MediaBrowser.Model/Configuration/MetadataOptions.cs b/MediaBrowser.Model/Configuration/MetadataOptions.cs
index ddde688b2..8a41decbf 100644
--- a/MediaBrowser.Model/Configuration/MetadataOptions.cs
+++ b/MediaBrowser.Model/Configuration/MetadataOptions.cs
@@ -29,7 +29,7 @@ namespace MediaBrowser.Model.Configuration
public MetadataOptions(int backdropLimit, int minBackdropWidth)
{
- List<ImageOption> imageOptions = new List<ImageOption>
+ ImageOptions = new[]
{
new ImageOption
{
@@ -39,7 +39,6 @@ namespace MediaBrowser.Model.Configuration
}
};
- ImageOptions = imageOptions.ToArray();
DisabledMetadataSavers = new string[] { };
LocalMetadataReaderOrder = new string[] { };
diff --git a/MediaBrowser.Model/Configuration/MetadataPluginSummary.cs b/MediaBrowser.Model/Configuration/MetadataPluginSummary.cs
index 90b3933eb..80142cf43 100644
--- a/MediaBrowser.Model/Configuration/MetadataPluginSummary.cs
+++ b/MediaBrowser.Model/Configuration/MetadataPluginSummary.cs
@@ -15,18 +15,18 @@ namespace MediaBrowser.Model.Configuration
/// Gets or sets the plugins.
/// </summary>
/// <value>The plugins.</value>
- public List<MetadataPlugin> Plugins { get; set; }
+ public MetadataPlugin[] Plugins { get; set; }
/// <summary>
/// Gets or sets the supported image types.
/// </summary>
/// <value>The supported image types.</value>
- public List<ImageType> SupportedImageTypes { get; set; }
+ public ImageType[] SupportedImageTypes { get; set; }
public MetadataPluginSummary()
{
- SupportedImageTypes = new List<ImageType>();
- Plugins = new List<MetadataPlugin>();
+ SupportedImageTypes = new ImageType[] { };
+ Plugins = new MetadataPlugin[] { };
}
}
} \ No newline at end of file
diff --git a/MediaBrowser.Model/Configuration/ServerConfiguration.cs b/MediaBrowser.Model/Configuration/ServerConfiguration.cs
index a570f7b10..5177a757a 100644
--- a/MediaBrowser.Model/Configuration/ServerConfiguration.cs
+++ b/MediaBrowser.Model/Configuration/ServerConfiguration.cs
@@ -162,7 +162,6 @@ namespace MediaBrowser.Model.Configuration
public bool EnableAutomaticRestart { get; set; }
public bool SkipDeserializationForBasicTypes { get; set; }
- public bool SkipDeserializationForAudio { get; set; }
public string ServerName { get; set; }
public string WanDdns { get; set; }
@@ -218,6 +217,7 @@ namespace MediaBrowser.Model.Configuration
EnableHttps = false;
EnableDashboardResponseCaching = true;
EnableAnonymousUsageReporting = true;
+ EnableCaseSensitiveItemIds = true;
EnableAutomaticRestart = true;
@@ -349,7 +349,9 @@ namespace MediaBrowser.Model.Configuration
Limit = 1,
Type = ImageType.Logo
}
- }
+ },
+
+ DisabledImageFetchers = new [] {"FanArt"}
},
new MetadataOptions(1, 1280)
@@ -539,7 +541,8 @@ namespace MediaBrowser.Model.Configuration
Type = ImageType.Thumb
}
},
- DisabledMetadataFetchers = new []{ "TheMovieDb" }
+ DisabledMetadataFetchers = new []{ "TheMovieDb" },
+ DisabledImageFetchers = new [] { "FanArt" }
},
new MetadataOptions(0, 1280)
diff --git a/MediaBrowser.Model/Configuration/UserConfiguration.cs b/MediaBrowser.Model/Configuration/UserConfiguration.cs
index 30b5f384f..15bd003ae 100644
--- a/MediaBrowser.Model/Configuration/UserConfiguration.cs
+++ b/MediaBrowser.Model/Configuration/UserConfiguration.cs
@@ -25,7 +25,6 @@ namespace MediaBrowser.Model.Configuration
public string SubtitleLanguagePreference { get; set; }
public bool DisplayMissingEpisodes { get; set; }
- public bool DisplayUnairedEpisodes { get; set; }
public string[] GroupedFolders { get; set; }
diff --git a/MediaBrowser.Model/Devices/ContentUploadHistory.cs b/MediaBrowser.Model/Devices/ContentUploadHistory.cs
index cd4858d90..2b344df24 100644
--- a/MediaBrowser.Model/Devices/ContentUploadHistory.cs
+++ b/MediaBrowser.Model/Devices/ContentUploadHistory.cs
@@ -5,11 +5,11 @@ namespace MediaBrowser.Model.Devices
public class ContentUploadHistory
{
public string DeviceId { get; set; }
- public List<LocalFileInfo> FilesUploaded { get; set; }
+ public LocalFileInfo[] FilesUploaded { get; set; }
public ContentUploadHistory()
{
- FilesUploaded = new List<LocalFileInfo>();
+ FilesUploaded = new LocalFileInfo[] { };
}
}
}
diff --git a/MediaBrowser.Model/Dlna/AudioOptions.cs b/MediaBrowser.Model/Dlna/AudioOptions.cs
index 24c7aef98..6584bb3cc 100644
--- a/MediaBrowser.Model/Dlna/AudioOptions.cs
+++ b/MediaBrowser.Model/Dlna/AudioOptions.cs
@@ -22,7 +22,7 @@ namespace MediaBrowser.Model.Dlna
public bool ForceDirectStream { get; set; }
public string ItemId { get; set; }
- public List<MediaSourceInfo> MediaSources { get; set; }
+ public MediaSourceInfo[] MediaSources { get; set; }
public DeviceProfile Profile { get; set; }
/// <summary>
diff --git a/MediaBrowser.Model/Dlna/CodecProfile.cs b/MediaBrowser.Model/Dlna/CodecProfile.cs
index e04e04d21..d75547adb 100644
--- a/MediaBrowser.Model/Dlna/CodecProfile.cs
+++ b/MediaBrowser.Model/Dlna/CodecProfile.cs
@@ -2,7 +2,6 @@
using System.Collections.Generic;
using System.Xml.Serialization;
using MediaBrowser.Model.Dlna;
-using System.Linq;
namespace MediaBrowser.Model.Dlna
{
@@ -27,31 +26,14 @@ namespace MediaBrowser.Model.Dlna
ApplyConditions = new ProfileCondition[] { };
}
- private static List<string> SplitValue(string value)
+ public string[] GetCodecs()
{
- List<string> list = new List<string>();
- foreach (string i in (value ?? string.Empty).Split(','))
- {
- if (!string.IsNullOrEmpty(i)) list.Add(i);
- }
- return list;
- }
-
- public List<string> GetCodecs()
- {
- return SplitValue(Codec);
- }
-
- public List<string> GetContainers()
- {
- return SplitValue(Container);
+ return ContainerProfile.SplitValue(Codec);
}
private bool ContainsContainer(string container)
{
- List<string> containers = GetContainers();
-
- return containers.Count == 0 || ListHelper.ContainsIgnoreCase(containers, container ?? string.Empty);
+ return ContainerProfile.ContainsContainer(Container, container);
}
public bool ContainsCodec(string codec, string container)
@@ -61,10 +43,9 @@ namespace MediaBrowser.Model.Dlna
return false;
}
- List<string> codecs = GetCodecs();
+ var codecs = GetCodecs();
- return codecs.Count == 0 || ListHelper.ContainsIgnoreCase(codecs, SplitValue(codec)[0]);
- //return codecs.Count == 0 || SplitValue(codec).Any(i => ListHelper.ContainsIgnoreCase(codecs, i));
+ return codecs.Length == 0 || ListHelper.ContainsIgnoreCase(codecs, ContainerProfile.SplitValue(codec)[0]);
}
}
}
diff --git a/MediaBrowser.Model/Dlna/ConditionProcessor.cs b/MediaBrowser.Model/Dlna/ConditionProcessor.cs
index 291096f75..bd3dc6fd2 100644
--- a/MediaBrowser.Model/Dlna/ConditionProcessor.cs
+++ b/MediaBrowser.Model/Dlna/ConditionProcessor.cs
@@ -3,7 +3,6 @@ using MediaBrowser.Model.MediaInfo;
using System;
using System.Collections.Generic;
using System.Globalization;
-using System.Linq;
namespace MediaBrowser.Model.Dlna
{
diff --git a/MediaBrowser.Model/Dlna/ContainerProfile.cs b/MediaBrowser.Model/Dlna/ContainerProfile.cs
index 35d7ada6b..23bbf0193 100644
--- a/MediaBrowser.Model/Dlna/ContainerProfile.cs
+++ b/MediaBrowser.Model/Dlna/ContainerProfile.cs
@@ -1,4 +1,5 @@
-using System.Collections.Generic;
+using System;
+using System.Collections.Generic;
using System.Xml.Serialization;
using MediaBrowser.Model.Dlna;
using MediaBrowser.Model.Extensions;
@@ -19,21 +20,53 @@ namespace MediaBrowser.Model.Dlna
Conditions = new ProfileCondition[] { };
}
- public List<string> GetContainers()
+ public string[] GetContainers()
{
- List<string> list = new List<string>();
- foreach (string i in (Container ?? string.Empty).Split(','))
+ return SplitValue(Container);
+ }
+
+ private static readonly string[] EmptyStringArray = new string[] { };
+
+ public static string[] SplitValue(string value)
+ {
+ if (string.IsNullOrWhiteSpace(value))
{
- if (!string.IsNullOrEmpty(i)) list.Add(i);
+ return EmptyStringArray;
}
- return list;
+
+ return value.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
}
public bool ContainsContainer(string container)
{
- List<string> containers = GetContainers();
+ var containers = GetContainers();
+
+ return ContainsContainer(containers, container);
+ }
+
+ public static bool ContainsContainer(string profileContainers, string inputContainer)
+ {
+ return ContainsContainer(SplitValue(profileContainers), inputContainer);
+ }
+
+ public static bool ContainsContainer(string[] profileContainers, string inputContainer)
+ {
+ if (profileContainers.Length == 0)
+ {
+ return true;
+ }
+
+ var allInputContainers = SplitValue(inputContainer);
+
+ foreach (var container in allInputContainers)
+ {
+ if (ListHelper.ContainsIgnoreCase(profileContainers, container))
+ {
+ return true;
+ }
+ }
- return containers.Count == 0 || ListHelper.ContainsIgnoreCase(containers, container ?? string.Empty);
+ return false;
}
}
}
diff --git a/MediaBrowser.Model/Dlna/DeviceProfile.cs b/MediaBrowser.Model/Dlna/DeviceProfile.cs
index cd7ff08d6..fc976b605 100644
--- a/MediaBrowser.Model/Dlna/DeviceProfile.cs
+++ b/MediaBrowser.Model/Dlna/DeviceProfile.cs
@@ -17,9 +17,6 @@ namespace MediaBrowser.Model.Dlna
[XmlIgnore]
public string Id { get; set; }
- [XmlIgnore]
- public MediaBrowser.Model.Dlna.DeviceProfileType ProfileType { get; set; }
-
/// <summary>
/// Gets or sets the identification.
/// </summary>
@@ -117,15 +114,9 @@ namespace MediaBrowser.Model.Dlna
MusicStreamingTranscodingBitrate = 128000;
}
- public List<string> GetSupportedMediaTypes()
+ public string[] GetSupportedMediaTypes()
{
- List<string> list = new List<string>();
- foreach (string i in (SupportedMediaTypes ?? string.Empty).Split(','))
- {
- if (!string.IsNullOrEmpty(i))
- list.Add(i);
- }
- return list;
+ return ContainerProfile.SplitValue(SupportedMediaTypes);
}
public TranscodingProfile GetAudioTranscodingProfile(string container, string audioCodec)
@@ -187,28 +178,25 @@ namespace MediaBrowser.Model.Dlna
public ResponseProfile GetAudioMediaProfile(string container, string audioCodec, int? audioChannels, int? audioBitrate, int? audioSampleRate, int? audioBitDepth)
{
- container = StringHelper.TrimStart(container ?? string.Empty, '.');
-
foreach (var i in ResponseProfiles)
{
- if (i.Type != MediaBrowser.Model.Dlna.DlnaProfileType.Audio)
+ if (i.Type != DlnaProfileType.Audio)
{
continue;
}
- List<string> containers = i.GetContainers();
- if (containers.Count > 0 && !ListHelper.ContainsIgnoreCase(containers, container))
+ if (!ContainerProfile.ContainsContainer(i.GetContainers(), container))
{
continue;
}
- List<string> audioCodecs = i.GetAudioCodecs();
- if (audioCodecs.Count > 0 && !ListHelper.ContainsIgnoreCase(audioCodecs, audioCodec ?? string.Empty))
+ var audioCodecs = i.GetAudioCodecs();
+ if (audioCodecs.Length > 0 && !ListHelper.ContainsIgnoreCase(audioCodecs, audioCodec ?? string.Empty))
{
continue;
}
- var conditionProcessor = new MediaBrowser.Model.Dlna.ConditionProcessor();
+ var conditionProcessor = new ConditionProcessor();
var anyOff = false;
foreach (ProfileCondition c in i.Conditions)
@@ -230,9 +218,9 @@ namespace MediaBrowser.Model.Dlna
return null;
}
- private MediaBrowser.Model.Dlna.ProfileCondition GetModelProfileCondition(ProfileCondition c)
+ private ProfileCondition GetModelProfileCondition(ProfileCondition c)
{
- return new MediaBrowser.Model.Dlna.ProfileCondition
+ return new ProfileCondition
{
Condition = c.Condition,
IsRequired = c.IsRequired,
@@ -243,22 +231,19 @@ namespace MediaBrowser.Model.Dlna
public ResponseProfile GetImageMediaProfile(string container, int? width, int? height)
{
- container = StringHelper.TrimStart(container ?? string.Empty, '.');
-
foreach (var i in ResponseProfiles)
{
- if (i.Type != MediaBrowser.Model.Dlna.DlnaProfileType.Photo)
+ if (i.Type != DlnaProfileType.Photo)
{
continue;
}
- List<string> containers = i.GetContainers();
- if (containers.Count > 0 && !ListHelper.ContainsIgnoreCase(containers, container))
+ if (!ContainerProfile.ContainsContainer(i.GetContainers(), container))
{
continue;
}
- var conditionProcessor = new MediaBrowser.Model.Dlna.ConditionProcessor();
+ var conditionProcessor = new ConditionProcessor();
var anyOff = false;
foreach (ProfileCondition c in i.Conditions)
@@ -300,34 +285,31 @@ namespace MediaBrowser.Model.Dlna
string videoCodecTag,
bool? isAvc)
{
- container = StringHelper.TrimStart(container ?? string.Empty, '.');
-
foreach (var i in ResponseProfiles)
{
- if (i.Type != MediaBrowser.Model.Dlna.DlnaProfileType.Video)
+ if (i.Type != DlnaProfileType.Video)
{
continue;
}
- List<string> containers = i.GetContainers();
- if (containers.Count > 0 && !ListHelper.ContainsIgnoreCase(containers, container ?? string.Empty))
+ if (!ContainerProfile.ContainsContainer(i.GetContainers(), container))
{
continue;
}
- List<string> audioCodecs = i.GetAudioCodecs();
- if (audioCodecs.Count > 0 && !ListHelper.ContainsIgnoreCase(audioCodecs, audioCodec ?? string.Empty))
+ var audioCodecs = i.GetAudioCodecs();
+ if (audioCodecs.Length > 0 && !ListHelper.ContainsIgnoreCase(audioCodecs, audioCodec ?? string.Empty))
{
continue;
}
- List<string> videoCodecs = i.GetVideoCodecs();
- if (videoCodecs.Count > 0 && !ListHelper.ContainsIgnoreCase(videoCodecs, videoCodec ?? string.Empty))
+ var videoCodecs = i.GetVideoCodecs();
+ if (videoCodecs.Length > 0 && !ListHelper.ContainsIgnoreCase(videoCodecs, videoCodec ?? string.Empty))
{
continue;
}
- var conditionProcessor = new MediaBrowser.Model.Dlna.ConditionProcessor();
+ var conditionProcessor = new ConditionProcessor();
var anyOff = false;
foreach (ProfileCondition c in i.Conditions)
diff --git a/MediaBrowser.Model/Dlna/DirectPlayProfile.cs b/MediaBrowser.Model/Dlna/DirectPlayProfile.cs
index df511b0da..7430c449f 100644
--- a/MediaBrowser.Model/Dlna/DirectPlayProfile.cs
+++ b/MediaBrowser.Model/Dlna/DirectPlayProfile.cs
@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
-using System.Linq;
using System.Xml.Serialization;
namespace MediaBrowser.Model.Dlna
@@ -19,47 +18,19 @@ namespace MediaBrowser.Model.Dlna
[XmlAttribute("type")]
public DlnaProfileType Type { get; set; }
- public List<string> GetContainers()
- {
- List<string> list = new List<string>();
- foreach (string i in (Container ?? string.Empty).Split(','))
- {
- if (!string.IsNullOrEmpty(i)) list.Add(i);
- }
- return list;
- }
-
public bool SupportsContainer(string container)
{
- var all = GetContainers();
-
- // Only allow unknown container if the profile is all inclusive
- if (string.IsNullOrWhiteSpace(container))
- {
- return all.Count == 0;
- }
-
- return all.Count == 0 || all.Contains(container, StringComparer.OrdinalIgnoreCase);
+ return ContainerProfile.ContainsContainer(Container, container);
}
- public List<string> GetAudioCodecs()
+ public string[] GetAudioCodecs()
{
- List<string> list = new List<string>();
- foreach (string i in (AudioCodec ?? string.Empty).Split(','))
- {
- if (!string.IsNullOrEmpty(i)) list.Add(i);
- }
- return list;
+ return ContainerProfile.SplitValue(AudioCodec);
}
- public List<string> GetVideoCodecs()
+ public string[] GetVideoCodecs()
{
- List<string> list = new List<string>();
- foreach (string i in (VideoCodec ?? string.Empty).Split(','))
- {
- if (!string.IsNullOrEmpty(i)) list.Add(i);
- }
- return list;
+ return ContainerProfile.SplitValue(VideoCodec);
}
}
}
diff --git a/MediaBrowser.Model/Dlna/ITranscoderSupport.cs b/MediaBrowser.Model/Dlna/ITranscoderSupport.cs
index fd615733d..14723bd27 100644
--- a/MediaBrowser.Model/Dlna/ITranscoderSupport.cs
+++ b/MediaBrowser.Model/Dlna/ITranscoderSupport.cs
@@ -4,6 +4,7 @@
{
bool CanEncodeToAudioCodec(string codec);
bool CanEncodeToSubtitleCodec(string codec);
+ bool CanExtractSubtitles(string codec);
}
public class FullTranscoderSupport : ITranscoderSupport
@@ -16,5 +17,9 @@
{
return true;
}
+ public bool CanExtractSubtitles(string codec)
+ {
+ return true;
+ }
}
}
diff --git a/MediaBrowser.Model/Dlna/MediaFormatProfileResolver.cs b/MediaBrowser.Model/Dlna/MediaFormatProfileResolver.cs
index a464b045b..034e0fe6a 100644
--- a/MediaBrowser.Model/Dlna/MediaFormatProfileResolver.cs
+++ b/MediaBrowser.Model/Dlna/MediaFormatProfileResolver.cs
@@ -7,33 +7,33 @@ namespace MediaBrowser.Model.Dlna
{
public class MediaFormatProfileResolver
{
- public List<MediaFormatProfile> ResolveVideoFormat(string container, string videoCodec, string audioCodec, int? width, int? height, TransportStreamTimestamp timestampType)
+ public MediaFormatProfile[] ResolveVideoFormat(string container, string videoCodec, string audioCodec, int? width, int? height, TransportStreamTimestamp timestampType)
{
if (StringHelper.EqualsIgnoreCase(container, "asf"))
{
MediaFormatProfile? val = ResolveVideoASFFormat(videoCodec, audioCodec, width, height);
- return val.HasValue ? new List<MediaFormatProfile> { val.Value } : new List<MediaFormatProfile>();
+ return val.HasValue ? new MediaFormatProfile[] { val.Value } : new MediaFormatProfile[]{};
}
if (StringHelper.EqualsIgnoreCase(container, "mp4"))
{
MediaFormatProfile? val = ResolveVideoMP4Format(videoCodec, audioCodec, width, height);
- return val.HasValue ? new List<MediaFormatProfile> { val.Value } : new List<MediaFormatProfile>();
+ return val.HasValue ? new MediaFormatProfile[] { val.Value } : new MediaFormatProfile[] { };
}
if (StringHelper.EqualsIgnoreCase(container, "avi"))
- return new List<MediaFormatProfile> { MediaFormatProfile.AVI };
+ return new MediaFormatProfile[] { MediaFormatProfile.AVI };
if (StringHelper.EqualsIgnoreCase(container, "mkv"))
- return new List<MediaFormatProfile> { MediaFormatProfile.MATROSKA };
+ return new MediaFormatProfile[] { MediaFormatProfile.MATROSKA };
if (StringHelper.EqualsIgnoreCase(container, "mpeg2ps") ||
StringHelper.EqualsIgnoreCase(container, "ts"))
- return new List<MediaFormatProfile> { MediaFormatProfile.MPEG_PS_NTSC, MediaFormatProfile.MPEG_PS_PAL };
+ return new MediaFormatProfile[] { MediaFormatProfile.MPEG_PS_NTSC, MediaFormatProfile.MPEG_PS_PAL };
if (StringHelper.EqualsIgnoreCase(container, "mpeg1video"))
- return new List<MediaFormatProfile> { MediaFormatProfile.MPEG1 };
+ return new MediaFormatProfile[] { MediaFormatProfile.MPEG1 };
if (StringHelper.EqualsIgnoreCase(container, "mpeg2ts") ||
StringHelper.EqualsIgnoreCase(container, "mpegts") ||
@@ -44,24 +44,24 @@ namespace MediaBrowser.Model.Dlna
}
if (StringHelper.EqualsIgnoreCase(container, "flv"))
- return new List<MediaFormatProfile> { MediaFormatProfile.FLV };
+ return new MediaFormatProfile[] { MediaFormatProfile.FLV };
if (StringHelper.EqualsIgnoreCase(container, "wtv"))
- return new List<MediaFormatProfile> { MediaFormatProfile.WTV };
+ return new MediaFormatProfile[] { MediaFormatProfile.WTV };
if (StringHelper.EqualsIgnoreCase(container, "3gp"))
{
MediaFormatProfile? val = ResolveVideo3GPFormat(videoCodec, audioCodec);
- return val.HasValue ? new List<MediaFormatProfile> { val.Value } : new List<MediaFormatProfile>();
+ return val.HasValue ? new MediaFormatProfile[] { val.Value } : new MediaFormatProfile[] { };
}
if (StringHelper.EqualsIgnoreCase(container, "ogv") || StringHelper.EqualsIgnoreCase(container, "ogg"))
- return new List<MediaFormatProfile> { MediaFormatProfile.OGV };
+ return new MediaFormatProfile[] { MediaFormatProfile.OGV };
- return new List<MediaFormatProfile>();
+ return new MediaFormatProfile[] { };
}
- private List<MediaFormatProfile> ResolveVideoMPEG2TSFormat(string videoCodec, string audioCodec, int? width, int? height, TransportStreamTimestamp timestampType)
+ private MediaFormatProfile[] ResolveVideoMPEG2TSFormat(string videoCodec, string audioCodec, int? width, int? height, TransportStreamTimestamp timestampType)
{
string suffix = "";
@@ -93,41 +93,41 @@ namespace MediaBrowser.Model.Dlna
{
list.Add(MediaFormatProfile.MPEG_TS_JP_T);
}
- return list;
+ return list.ToArray(list.Count);
}
if (StringHelper.EqualsIgnoreCase(videoCodec, "h264"))
{
if (StringHelper.EqualsIgnoreCase(audioCodec, "lpcm"))
- return new List<MediaFormatProfile> { MediaFormatProfile.AVC_TS_HD_50_LPCM_T };
+ return new MediaFormatProfile[] { MediaFormatProfile.AVC_TS_HD_50_LPCM_T };
if (StringHelper.EqualsIgnoreCase(audioCodec, "dts"))
{
if (timestampType == TransportStreamTimestamp.None)
{
- return new List<MediaFormatProfile> { MediaFormatProfile.AVC_TS_HD_DTS_ISO };
+ return new MediaFormatProfile[] { MediaFormatProfile.AVC_TS_HD_DTS_ISO };
}
- return new List<MediaFormatProfile> { MediaFormatProfile.AVC_TS_HD_DTS_T };
+ return new MediaFormatProfile[] { MediaFormatProfile.AVC_TS_HD_DTS_T };
}
if (StringHelper.EqualsIgnoreCase(audioCodec, "mp2"))
{
if (timestampType == TransportStreamTimestamp.None)
{
- return new List<MediaFormatProfile> { ValueOf(string.Format("AVC_TS_HP_{0}D_MPEG1_L2_ISO", resolution)) };
+ return new MediaFormatProfile[] { ValueOf(string.Format("AVC_TS_HP_{0}D_MPEG1_L2_ISO", resolution)) };
}
- return new List<MediaFormatProfile> { ValueOf(string.Format("AVC_TS_HP_{0}D_MPEG1_L2_T", resolution)) };
+ return new MediaFormatProfile[] { ValueOf(string.Format("AVC_TS_HP_{0}D_MPEG1_L2_T", resolution)) };
}
if (StringHelper.EqualsIgnoreCase(audioCodec, "aac"))
- return new List<MediaFormatProfile> { ValueOf(string.Format("AVC_TS_MP_{0}D_AAC_MULT5{1}", resolution, suffix)) };
+ return new MediaFormatProfile[] { ValueOf(string.Format("AVC_TS_MP_{0}D_AAC_MULT5{1}", resolution, suffix)) };
if (StringHelper.EqualsIgnoreCase(audioCodec, "mp3"))
- return new List<MediaFormatProfile> { ValueOf(string.Format("AVC_TS_MP_{0}D_MPEG1_L3{1}", resolution, suffix)) };
+ return new MediaFormatProfile[] { ValueOf(string.Format("AVC_TS_MP_{0}D_MPEG1_L3{1}", resolution, suffix)) };
if (string.IsNullOrEmpty(audioCodec) ||
StringHelper.EqualsIgnoreCase(audioCodec, "ac3"))
- return new List<MediaFormatProfile> { ValueOf(string.Format("AVC_TS_MP_{0}D_AC3{1}", resolution, suffix)) };
+ return new MediaFormatProfile[] { ValueOf(string.Format("AVC_TS_MP_{0}D_AC3{1}", resolution, suffix)) };
}
else if (StringHelper.EqualsIgnoreCase(videoCodec, "vc1"))
{
@@ -135,31 +135,31 @@ namespace MediaBrowser.Model.Dlna
{
if ((width.HasValue && width.Value > 720) || (height.HasValue && height.Value > 576))
{
- return new List<MediaFormatProfile> { MediaFormatProfile.VC1_TS_AP_L2_AC3_ISO };
+ return new MediaFormatProfile[] { MediaFormatProfile.VC1_TS_AP_L2_AC3_ISO };
}
- return new List<MediaFormatProfile> { MediaFormatProfile.VC1_TS_AP_L1_AC3_ISO };
+ return new MediaFormatProfile[] { MediaFormatProfile.VC1_TS_AP_L1_AC3_ISO };
}
if (StringHelper.EqualsIgnoreCase(audioCodec, "dts"))
{
suffix = StringHelper.EqualsIgnoreCase(suffix, "_ISO") ? suffix : "_T";
- return new List<MediaFormatProfile> { ValueOf(string.Format("VC1_TS_HD_DTS{0}", suffix)) };
+ return new MediaFormatProfile[] { ValueOf(string.Format("VC1_TS_HD_DTS{0}", suffix)) };
}
}
else if (StringHelper.EqualsIgnoreCase(videoCodec, "mpeg4") || StringHelper.EqualsIgnoreCase(videoCodec, "msmpeg4"))
{
if (StringHelper.EqualsIgnoreCase(audioCodec, "aac"))
- return new List<MediaFormatProfile> { ValueOf(string.Format("MPEG4_P2_TS_ASP_AAC{0}", suffix)) };
+ return new MediaFormatProfile[] { ValueOf(string.Format("MPEG4_P2_TS_ASP_AAC{0}", suffix)) };
if (StringHelper.EqualsIgnoreCase(audioCodec, "mp3"))
- return new List<MediaFormatProfile> { ValueOf(string.Format("MPEG4_P2_TS_ASP_MPEG1_L3{0}", suffix)) };
+ return new MediaFormatProfile[] { ValueOf(string.Format("MPEG4_P2_TS_ASP_MPEG1_L3{0}", suffix)) };
if (StringHelper.EqualsIgnoreCase(audioCodec, "mp2"))
- return new List<MediaFormatProfile> { ValueOf(string.Format("MPEG4_P2_TS_ASP_MPEG2_L2{0}", suffix)) };
+ return new MediaFormatProfile[] { ValueOf(string.Format("MPEG4_P2_TS_ASP_MPEG2_L2{0}", suffix)) };
if (StringHelper.EqualsIgnoreCase(audioCodec, "ac3"))
- return new List<MediaFormatProfile> { ValueOf(string.Format("MPEG4_P2_TS_ASP_AC3{0}", suffix)) };
+ return new MediaFormatProfile[] { ValueOf(string.Format("MPEG4_P2_TS_ASP_AC3{0}", suffix)) };
}
- return new List<MediaFormatProfile>();
+ return new MediaFormatProfile[]{};
}
private MediaFormatProfile ValueOf(string value)
diff --git a/MediaBrowser.Model/Dlna/ResolutionNormalizer.cs b/MediaBrowser.Model/Dlna/ResolutionNormalizer.cs
index 950d3680d..de832314c 100644
--- a/MediaBrowser.Model/Dlna/ResolutionNormalizer.cs
+++ b/MediaBrowser.Model/Dlna/ResolutionNormalizer.cs
@@ -6,8 +6,8 @@ namespace MediaBrowser.Model.Dlna
{
public class ResolutionNormalizer
{
- private static readonly List<ResolutionConfiguration> Configurations =
- new List<ResolutionConfiguration>
+ private static readonly ResolutionConfiguration[] Configurations =
+ new []
{
new ResolutionConfiguration(426, 320000),
new ResolutionConfiguration(640, 400000),
@@ -58,12 +58,16 @@ namespace MediaBrowser.Model.Dlna
private static ResolutionConfiguration GetResolutionConfiguration(int outputBitrate)
{
+ ResolutionConfiguration previousOption = null;
+
foreach (var config in Configurations)
{
if (outputBitrate <= config.MaxBitrate)
{
- return config;
+ return previousOption ?? config;
}
+
+ previousOption = config;
}
return null;
diff --git a/MediaBrowser.Model/Dlna/ResponseProfile.cs b/MediaBrowser.Model/Dlna/ResponseProfile.cs
index 1d4791b5c..742253fa3 100644
--- a/MediaBrowser.Model/Dlna/ResponseProfile.cs
+++ b/MediaBrowser.Model/Dlna/ResponseProfile.cs
@@ -31,34 +31,19 @@ namespace MediaBrowser.Model.Dlna
Conditions = new ProfileCondition[] {};
}
- public List<string> GetContainers()
+ public string[] GetContainers()
{
- List<string> list = new List<string>();
- foreach (string i in (Container ?? string.Empty).Split(','))
- {
- if (!string.IsNullOrEmpty(i)) list.Add(i);
- }
- return list;
+ return ContainerProfile.SplitValue(Container);
}
- public List<string> GetAudioCodecs()
+ public string[] GetAudioCodecs()
{
- List<string> list = new List<string>();
- foreach (string i in (AudioCodec ?? string.Empty).Split(','))
- {
- if (!string.IsNullOrEmpty(i)) list.Add(i);
- }
- return list;
+ return ContainerProfile.SplitValue(AudioCodec);
}
- public List<string> GetVideoCodecs()
+ public string[] GetVideoCodecs()
{
- List<string> list = new List<string>();
- foreach (string i in (VideoCodec ?? string.Empty).Split(','))
- {
- if (!string.IsNullOrEmpty(i)) list.Add(i);
- }
- return list;
+ return ContainerProfile.SplitValue(VideoCodec);
}
}
}
diff --git a/MediaBrowser.Model/Dlna/StreamBuilder.cs b/MediaBrowser.Model/Dlna/StreamBuilder.cs
index 48f9a4212..10c6a05c0 100644
--- a/MediaBrowser.Model/Dlna/StreamBuilder.cs
+++ b/MediaBrowser.Model/Dlna/StreamBuilder.cs
@@ -31,7 +31,7 @@ namespace MediaBrowser.Model.Dlna
{
ValidateAudioInput(options);
- List<MediaSourceInfo> mediaSources = new List<MediaSourceInfo>();
+ var mediaSources = new List<MediaSourceInfo>();
foreach (MediaSourceInfo i in options.MediaSources)
{
if (string.IsNullOrEmpty(options.MediaSourceId) ||
@@ -41,7 +41,7 @@ namespace MediaBrowser.Model.Dlna
}
}
- List<StreamInfo> streams = new List<StreamInfo>();
+ var streams = new List<StreamInfo>();
foreach (MediaSourceInfo i in mediaSources)
{
StreamInfo streamInfo = BuildAudioItem(i, options);
@@ -64,7 +64,7 @@ namespace MediaBrowser.Model.Dlna
{
ValidateInput(options);
- List<MediaSourceInfo> mediaSources = new List<MediaSourceInfo>();
+ var mediaSources = new List<MediaSourceInfo>();
foreach (MediaSourceInfo i in options.MediaSources)
{
if (string.IsNullOrEmpty(options.MediaSourceId) ||
@@ -74,7 +74,7 @@ namespace MediaBrowser.Model.Dlna
}
}
- List<StreamInfo> streams = new List<StreamInfo>();
+ var streams = new List<StreamInfo>();
foreach (MediaSourceInfo i in mediaSources)
{
StreamInfo streamInfo = BuildVideoItem(i, options);
@@ -95,9 +95,9 @@ namespace MediaBrowser.Model.Dlna
private StreamInfo GetOptimalStream(List<StreamInfo> streams, long? maxBitrate)
{
- streams = StreamInfoSorter.SortMediaSources(streams, maxBitrate);
+ var sorted = StreamInfoSorter.SortMediaSources(streams, maxBitrate);
- foreach (StreamInfo stream in streams)
+ foreach (StreamInfo stream in sorted)
{
return stream;
}
@@ -197,9 +197,43 @@ namespace MediaBrowser.Model.Dlna
}
}
+ public static string NormalizeMediaSourceFormatIntoSingleContainer(string inputContainer, DeviceProfile profile, DlnaProfileType type)
+ {
+ if (string.IsNullOrWhiteSpace(inputContainer))
+ {
+ return null;
+ }
+
+ var formats = ContainerProfile.SplitValue(inputContainer);
+
+ if (formats.Length == 1)
+ {
+ return formats[0];
+ }
+
+ if (profile != null)
+ {
+ foreach (var format in formats)
+ {
+ foreach (var directPlayProfile in profile.DirectPlayProfiles)
+ {
+ if (directPlayProfile.Type == type)
+ {
+ if (directPlayProfile.SupportsContainer(format))
+ {
+ return format;
+ }
+ }
+ }
+ }
+ }
+
+ return formats[0];
+ }
+
private StreamInfo BuildAudioItem(MediaSourceInfo item, AudioOptions options)
{
- List<TranscodeReason> transcodeReasons = new List<TranscodeReason>();
+ var transcodeReasons = new List<TranscodeReason>();
StreamInfo playlistItem = new StreamInfo
{
@@ -214,14 +248,14 @@ namespace MediaBrowser.Model.Dlna
if (options.ForceDirectPlay)
{
playlistItem.PlayMethod = PlayMethod.DirectPlay;
- playlistItem.Container = item.Container;
+ playlistItem.Container = NormalizeMediaSourceFormatIntoSingleContainer(item.Container, options.Profile, DlnaProfileType.Audio);
return playlistItem;
}
if (options.ForceDirectStream)
{
playlistItem.PlayMethod = PlayMethod.DirectStream;
- playlistItem.Container = item.Container;
+ playlistItem.Container = NormalizeMediaSourceFormatIntoSingleContainer(item.Container, options.Profile, DlnaProfileType.Audio);
return playlistItem;
}
@@ -229,7 +263,7 @@ namespace MediaBrowser.Model.Dlna
var directPlayInfo = GetAudioDirectPlayMethods(item, audioStream, options);
- List<PlayMethod> directPlayMethods = directPlayInfo.Item1;
+ var directPlayMethods = directPlayInfo.Item1;
transcodeReasons.AddRange(directPlayInfo.Item2);
ConditionProcessor conditionProcessor = new ConditionProcessor();
@@ -246,7 +280,7 @@ namespace MediaBrowser.Model.Dlna
// Make sure audio codec profiles are satisfied
if (!string.IsNullOrEmpty(audioCodec))
{
- List<ProfileCondition> conditions = new List<ProfileCondition>();
+ var conditions = new List<ProfileCondition>();
foreach (CodecProfile i in options.Profile.CodecProfiles)
{
if (i.Type == CodecType.Audio && i.ContainsCodec(audioCodec, item.Container))
@@ -295,7 +329,7 @@ namespace MediaBrowser.Model.Dlna
playlistItem.PlayMethod = PlayMethod.DirectStream;
}
- playlistItem.Container = item.Container;
+ playlistItem.Container = NormalizeMediaSourceFormatIntoSingleContainer(item.Container, options.Profile, DlnaProfileType.Audio);
return playlistItem;
}
@@ -338,7 +372,7 @@ namespace MediaBrowser.Model.Dlna
playlistItem.SubProtocol = transcodingProfile.Protocol;
- List<CodecProfile> audioCodecProfiles = new List<CodecProfile>();
+ var audioCodecProfiles = new List<CodecProfile>();
foreach (CodecProfile i in options.Profile.CodecProfiles)
{
if (i.Type == CodecType.Audio && i.ContainsCodec(transcodingProfile.AudioCodec, transcodingProfile.Container))
@@ -349,7 +383,7 @@ namespace MediaBrowser.Model.Dlna
if (audioCodecProfiles.Count >= 1) break;
}
- List<ProfileCondition> audioTranscodingConditions = new List<ProfileCondition>();
+ var audioTranscodingConditions = new List<ProfileCondition>();
foreach (CodecProfile i in audioCodecProfiles)
{
bool applyConditions = true;
@@ -413,7 +447,7 @@ namespace MediaBrowser.Model.Dlna
private Tuple<List<PlayMethod>, List<TranscodeReason>> GetAudioDirectPlayMethods(MediaSourceInfo item, MediaStream audioStream, AudioOptions options)
{
- List<TranscodeReason> transcodeReasons = new List<TranscodeReason>();
+ var transcodeReasons = new List<TranscodeReason>();
DirectPlayProfile directPlayProfile = null;
foreach (DirectPlayProfile i in options.Profile.DirectPlayProfiles)
@@ -425,7 +459,7 @@ namespace MediaBrowser.Model.Dlna
}
}
- List<PlayMethod> playMethods = new List<PlayMethod>();
+ var playMethods = new List<PlayMethod>();
if (directPlayProfile != null)
{
@@ -500,8 +534,8 @@ namespace MediaBrowser.Model.Dlna
if (videoStream != null)
{
// Check video codec
- List<string> videoCodecs = profile.GetVideoCodecs();
- if (videoCodecs.Count > 0)
+ var videoCodecs = profile.GetVideoCodecs();
+ if (videoCodecs.Length > 0)
{
string videoCodec = videoStream.Codec;
if (!string.IsNullOrEmpty(videoCodec) && ListHelper.ContainsIgnoreCase(videoCodecs, videoCodec))
@@ -518,8 +552,8 @@ namespace MediaBrowser.Model.Dlna
if (audioStream != null)
{
// Check audio codec
- List<string> audioCodecs = profile.GetAudioCodecs();
- if (audioCodecs.Count > 0)
+ var audioCodecs = profile.GetAudioCodecs();
+ if (audioCodecs.Length > 0)
{
string audioCodec = audioStream.Codec;
if (!string.IsNullOrEmpty(audioCodec) && ListHelper.ContainsIgnoreCase(audioCodecs, audioCodec))
@@ -568,7 +602,7 @@ namespace MediaBrowser.Model.Dlna
}
}
- List<MediaStream> topStreams = new List<MediaStream>();
+ var topStreams = new List<MediaStream>();
foreach (MediaStream stream in item.MediaStreams)
{
if (stream.Type == MediaStreamType.Subtitle && stream.Score.HasValue && stream.Score.Value == highestScore)
@@ -603,7 +637,7 @@ namespace MediaBrowser.Model.Dlna
throw new ArgumentNullException("item");
}
- List<TranscodeReason> transcodeReasons = new List<TranscodeReason>();
+ var transcodeReasons = new List<TranscodeReason>();
StreamInfo playlistItem = new StreamInfo
{
@@ -648,11 +682,11 @@ namespace MediaBrowser.Model.Dlna
if (directPlay != null)
{
playlistItem.PlayMethod = directPlay.Value;
- playlistItem.Container = item.Container;
+ playlistItem.Container = NormalizeMediaSourceFormatIntoSingleContainer(item.Container, options.Profile, DlnaProfileType.Video);
if (subtitleStream != null)
{
- SubtitleProfile subtitleProfile = GetSubtitleProfile(subtitleStream, options.Profile.SubtitleProfiles, directPlay.Value, null, null);
+ SubtitleProfile subtitleProfile = GetSubtitleProfile(subtitleStream, options.Profile.SubtitleProfiles, directPlay.Value, _transcoderSupport, null, null);
playlistItem.SubtitleDeliveryMethod = subtitleProfile.Method;
playlistItem.SubtitleFormat = subtitleProfile.Format;
@@ -694,7 +728,7 @@ namespace MediaBrowser.Model.Dlna
if (subtitleStream != null)
{
- SubtitleProfile subtitleProfile = GetSubtitleProfile(subtitleStream, options.Profile.SubtitleProfiles, PlayMethod.Transcode, transcodingProfile.Protocol, transcodingProfile.Container);
+ SubtitleProfile subtitleProfile = GetSubtitleProfile(subtitleStream, options.Profile.SubtitleProfiles, PlayMethod.Transcode, _transcoderSupport, transcodingProfile.Protocol, transcodingProfile.Container);
playlistItem.SubtitleDeliveryMethod = subtitleProfile.Method;
playlistItem.SubtitleFormat = subtitleProfile.Format;
@@ -735,7 +769,7 @@ namespace MediaBrowser.Model.Dlna
playlistItem.AudioStreamIndex = audioStreamIndex;
ConditionProcessor conditionProcessor = new ConditionProcessor();
- List<ProfileCondition> videoTranscodingConditions = new List<ProfileCondition>();
+ var videoTranscodingConditions = new List<ProfileCondition>();
foreach (CodecProfile i in options.Profile.CodecProfiles)
{
if (i.Type == CodecType.Video && i.ContainsCodec(transcodingProfile.VideoCodec, transcodingProfile.Container))
@@ -770,7 +804,7 @@ namespace MediaBrowser.Model.Dlna
}
ApplyTranscodingConditions(playlistItem, videoTranscodingConditions);
- List<ProfileCondition> audioTranscodingConditions = new List<ProfileCondition>();
+ var audioTranscodingConditions = new List<ProfileCondition>();
foreach (CodecProfile i in options.Profile.CodecProfiles)
{
if (i.Type == CodecType.VideoAudio && i.ContainsCodec(playlistItem.TargetAudioCodec, transcodingProfile.Container))
@@ -956,7 +990,7 @@ namespace MediaBrowser.Model.Dlna
string container = mediaSource.Container;
- List<ProfileCondition> conditions = new List<ProfileCondition>();
+ var conditions = new List<ProfileCondition>();
foreach (ContainerProfile i in profile.ContainerProfiles)
{
if (i.Type == DlnaProfileType.Video &&
@@ -1089,7 +1123,7 @@ namespace MediaBrowser.Model.Dlna
{
if (!conditionProcessor.IsVideoAudioConditionSatisfied(applyCondition, audioChannels, audioBitrate, audioSampleRate, audioBitDepth, audioProfile, isSecondaryAudio))
{
- LogConditionFailure(profile, "VideoAudioCodecProfile", applyCondition, mediaSource);
+ LogConditionFailure(profile, "VideoAudioCodecProfile.ApplyConditions", applyCondition, mediaSource);
applyConditions = false;
break;
}
@@ -1149,7 +1183,7 @@ namespace MediaBrowser.Model.Dlna
{
if (subtitleStream != null)
{
- SubtitleProfile subtitleProfile = GetSubtitleProfile(subtitleStream, options.Profile.SubtitleProfiles, playMethod, null, null);
+ SubtitleProfile subtitleProfile = GetSubtitleProfile(subtitleStream, options.Profile.SubtitleProfiles, playMethod, _transcoderSupport, null, null);
if (subtitleProfile.Method != SubtitleDeliveryMethod.External && subtitleProfile.Method != SubtitleDeliveryMethod.Embed)
{
@@ -1168,7 +1202,7 @@ namespace MediaBrowser.Model.Dlna
return new Tuple<bool, TranscodeReason?>(result, TranscodeReason.ContainerBitrateExceedsLimit);
}
- public static SubtitleProfile GetSubtitleProfile(MediaStream subtitleStream, SubtitleProfile[] subtitleProfiles, PlayMethod playMethod, string transcodingSubProtocol, string transcodingContainer)
+ public static SubtitleProfile GetSubtitleProfile(MediaStream subtitleStream, SubtitleProfile[] subtitleProfiles, PlayMethod playMethod, ITranscoderSupport transcoderSupport, string transcodingSubProtocol, string transcodingContainer)
{
if (!subtitleStream.IsExternal && (playMethod != PlayMethod.Transcode || !string.Equals(transcodingSubProtocol, "hls", StringComparison.OrdinalIgnoreCase)))
{
@@ -1222,7 +1256,9 @@ namespace MediaBrowser.Model.Dlna
}
// Look for an external or hls profile that matches the stream type (text/graphical) and doesn't require conversion
- return GetExternalSubtitleProfile(subtitleStream, subtitleProfiles, playMethod, false) ?? GetExternalSubtitleProfile(subtitleStream, subtitleProfiles, playMethod, true) ?? new SubtitleProfile
+ return GetExternalSubtitleProfile(subtitleStream, subtitleProfiles, playMethod, transcoderSupport, false) ??
+ GetExternalSubtitleProfile(subtitleStream, subtitleProfiles, playMethod, transcoderSupport, true) ??
+ new SubtitleProfile
{
Method = SubtitleDeliveryMethod.Encode,
Format = subtitleStream.Codec
@@ -1231,27 +1267,33 @@ namespace MediaBrowser.Model.Dlna
private static bool IsSubtitleEmbedSupported(MediaStream subtitleStream, SubtitleProfile subtitleProfile, string transcodingSubProtocol, string transcodingContainer)
{
- if (string.Equals(transcodingContainer, "ts", StringComparison.OrdinalIgnoreCase))
- {
- return false;
- }
- if (string.Equals(transcodingContainer, "mpegts", StringComparison.OrdinalIgnoreCase))
- {
- return false;
- }
- if (string.Equals(transcodingContainer, "mp4", StringComparison.OrdinalIgnoreCase))
+ if (!string.IsNullOrWhiteSpace(transcodingContainer))
{
- return false;
- }
- if (string.Equals(transcodingContainer, "mkv", StringComparison.OrdinalIgnoreCase))
- {
- return true;
+ var normalizedContainers = ContainerProfile.SplitValue(transcodingContainer);
+
+ if (ContainerProfile.ContainsContainer(normalizedContainers, "ts"))
+ {
+ return false;
+ }
+ if (ContainerProfile.ContainsContainer(normalizedContainers, "mpegts"))
+ {
+ return false;
+ }
+ if (ContainerProfile.ContainsContainer(normalizedContainers, "mp4"))
+ {
+ return false;
+ }
+ if (ContainerProfile.ContainsContainer(normalizedContainers, "mkv") ||
+ ContainerProfile.ContainsContainer(normalizedContainers, "matroska"))
+ {
+ return true;
+ }
}
return false;
}
- private static SubtitleProfile GetExternalSubtitleProfile(MediaStream subtitleStream, SubtitleProfile[] subtitleProfiles, PlayMethod playMethod, bool allowConversion)
+ private static SubtitleProfile GetExternalSubtitleProfile(MediaStream subtitleStream, SubtitleProfile[] subtitleProfiles, PlayMethod playMethod, ITranscoderSupport transcoderSupport, bool allowConversion)
{
foreach (SubtitleProfile profile in subtitleProfiles)
{
@@ -1270,6 +1312,11 @@ namespace MediaBrowser.Model.Dlna
continue;
}
+ if (!subtitleStream.IsExternal && !transcoderSupport.CanExtractSubtitles(subtitleStream.Codec))
+ {
+ continue;
+ }
+
if ((profile.Method == SubtitleDeliveryMethod.External && subtitleStream.IsTextSubtitleStream == MediaStream.IsTextFormat(profile.Format)) ||
(profile.Method == SubtitleDeliveryMethod.Hls && subtitleStream.IsTextSubtitleStream))
{
@@ -1538,8 +1585,8 @@ namespace MediaBrowser.Model.Dlna
}
// Check audio codec
- List<string> audioCodecs = profile.GetAudioCodecs();
- if (audioCodecs.Count > 0)
+ var audioCodecs = profile.GetAudioCodecs();
+ if (audioCodecs.Length > 0)
{
// Check audio codecs
string audioCodec = audioStream == null ? null : audioStream.Codec;
@@ -1561,8 +1608,8 @@ namespace MediaBrowser.Model.Dlna
}
// Check video codec
- List<string> videoCodecs = profile.GetVideoCodecs();
- if (videoCodecs.Count > 0)
+ var videoCodecs = profile.GetVideoCodecs();
+ if (videoCodecs.Length > 0)
{
string videoCodec = videoStream == null ? null : videoStream.Codec;
if (string.IsNullOrEmpty(videoCodec) || !ListHelper.ContainsIgnoreCase(videoCodecs, videoCodec))
@@ -1572,14 +1619,17 @@ namespace MediaBrowser.Model.Dlna
}
// Check audio codec
- List<string> audioCodecs = profile.GetAudioCodecs();
- if (audioCodecs.Count > 0)
+ if (audioStream != null)
{
- // Check audio codecs
- string audioCodec = audioStream == null ? null : audioStream.Codec;
- if (string.IsNullOrEmpty(audioCodec) || !ListHelper.ContainsIgnoreCase(audioCodecs, audioCodec))
+ var audioCodecs = profile.GetAudioCodecs();
+ if (audioCodecs.Length > 0)
{
- return false;
+ // Check audio codecs
+ string audioCodec = audioStream == null ? null : audioStream.Codec;
+ if (string.IsNullOrEmpty(audioCodec) || !ListHelper.ContainsIgnoreCase(audioCodecs, audioCodec))
+ {
+ return false;
+ }
}
}
diff --git a/MediaBrowser.Model/Dlna/StreamInfo.cs b/MediaBrowser.Model/Dlna/StreamInfo.cs
index 9c8e8b030..c63e74eaf 100644
--- a/MediaBrowser.Model/Dlna/StreamInfo.cs
+++ b/MediaBrowser.Model/Dlna/StreamInfo.cs
@@ -149,7 +149,7 @@ namespace MediaBrowser.Model.Dlna
list.Add(string.Format("{0}={1}", pair.Name, pair.Value));
}
- string queryString = string.Join("&", list.ToArray());
+ string queryString = string.Join("&", list.ToArray(list.Count));
return GetUrl(baseUrl, queryString);
}
@@ -203,7 +203,7 @@ namespace MediaBrowser.Model.Dlna
list.Add(pair.Value);
}
- return string.Format("Params={0}", string.Join(";", list.ToArray()));
+ return string.Format("Params={0}", string.Join(";", list.ToArray(list.Count)));
}
private static List<NameValuePair> BuildParams(StreamInfo item, string accessToken, bool isDlna)
@@ -309,14 +309,14 @@ namespace MediaBrowser.Model.Dlna
return list;
}
- public List<SubtitleStreamInfo> GetExternalSubtitles(bool includeSelectedTrackOnly, string baseUrl, string accessToken)
+ public List<SubtitleStreamInfo> GetExternalSubtitles(ITranscoderSupport transcoderSupport, bool includeSelectedTrackOnly, string baseUrl, string accessToken)
{
- return GetExternalSubtitles(includeSelectedTrackOnly, false, baseUrl, accessToken);
+ return GetExternalSubtitles(transcoderSupport, includeSelectedTrackOnly, false, baseUrl, accessToken);
}
- public List<SubtitleStreamInfo> GetExternalSubtitles(bool includeSelectedTrackOnly, bool enableAllProfiles, string baseUrl, string accessToken)
+ public List<SubtitleStreamInfo> GetExternalSubtitles(ITranscoderSupport transcoderSupport, bool includeSelectedTrackOnly, bool enableAllProfiles, string baseUrl, string accessToken)
{
- List<SubtitleStreamInfo> list = GetSubtitleProfiles(includeSelectedTrackOnly, enableAllProfiles, baseUrl, accessToken);
+ List<SubtitleStreamInfo> list = GetSubtitleProfiles(transcoderSupport, includeSelectedTrackOnly, enableAllProfiles, baseUrl, accessToken);
List<SubtitleStreamInfo> newList = new List<SubtitleStreamInfo>();
// First add the selected track
@@ -331,12 +331,12 @@ namespace MediaBrowser.Model.Dlna
return newList;
}
- public List<SubtitleStreamInfo> GetSubtitleProfiles(bool includeSelectedTrackOnly, string baseUrl, string accessToken)
+ public List<SubtitleStreamInfo> GetSubtitleProfiles(ITranscoderSupport transcoderSupport, bool includeSelectedTrackOnly, string baseUrl, string accessToken)
{
- return GetSubtitleProfiles(includeSelectedTrackOnly, false, baseUrl, accessToken);
+ return GetSubtitleProfiles(transcoderSupport, includeSelectedTrackOnly, false, baseUrl, accessToken);
}
- public List<SubtitleStreamInfo> GetSubtitleProfiles(bool includeSelectedTrackOnly, bool enableAllProfiles, string baseUrl, string accessToken)
+ public List<SubtitleStreamInfo> GetSubtitleProfiles(ITranscoderSupport transcoderSupport, bool includeSelectedTrackOnly, bool enableAllProfiles, string baseUrl, string accessToken)
{
List<SubtitleStreamInfo> list = new List<SubtitleStreamInfo>();
@@ -352,7 +352,7 @@ namespace MediaBrowser.Model.Dlna
{
if (stream.Type == MediaStreamType.Subtitle && stream.Index == SubtitleStreamIndex.Value)
{
- AddSubtitleProfiles(list, stream, enableAllProfiles, baseUrl, accessToken, startPositionTicks);
+ AddSubtitleProfiles(list, stream, transcoderSupport, enableAllProfiles, baseUrl, accessToken, startPositionTicks);
}
}
}
@@ -363,7 +363,7 @@ namespace MediaBrowser.Model.Dlna
{
if (stream.Type == MediaStreamType.Subtitle && (!SubtitleStreamIndex.HasValue || stream.Index != SubtitleStreamIndex.Value))
{
- AddSubtitleProfiles(list, stream, enableAllProfiles, baseUrl, accessToken, startPositionTicks);
+ AddSubtitleProfiles(list, stream, transcoderSupport, enableAllProfiles, baseUrl, accessToken, startPositionTicks);
}
}
}
@@ -371,28 +371,28 @@ namespace MediaBrowser.Model.Dlna
return list;
}
- private void AddSubtitleProfiles(List<SubtitleStreamInfo> list, MediaStream stream, bool enableAllProfiles, string baseUrl, string accessToken, long startPositionTicks)
+ private void AddSubtitleProfiles(List<SubtitleStreamInfo> list, MediaStream stream, ITranscoderSupport transcoderSupport, bool enableAllProfiles, string baseUrl, string accessToken, long startPositionTicks)
{
if (enableAllProfiles)
{
foreach (SubtitleProfile profile in DeviceProfile.SubtitleProfiles)
{
- SubtitleStreamInfo info = GetSubtitleStreamInfo(stream, baseUrl, accessToken, startPositionTicks, new[] { profile });
+ SubtitleStreamInfo info = GetSubtitleStreamInfo(stream, baseUrl, accessToken, startPositionTicks, new[] { profile }, transcoderSupport);
list.Add(info);
}
}
else
{
- SubtitleStreamInfo info = GetSubtitleStreamInfo(stream, baseUrl, accessToken, startPositionTicks, DeviceProfile.SubtitleProfiles);
+ SubtitleStreamInfo info = GetSubtitleStreamInfo(stream, baseUrl, accessToken, startPositionTicks, DeviceProfile.SubtitleProfiles, transcoderSupport);
list.Add(info);
}
}
- private SubtitleStreamInfo GetSubtitleStreamInfo(MediaStream stream, string baseUrl, string accessToken, long startPositionTicks, SubtitleProfile[] subtitleProfiles)
+ private SubtitleStreamInfo GetSubtitleStreamInfo(MediaStream stream, string baseUrl, string accessToken, long startPositionTicks, SubtitleProfile[] subtitleProfiles, ITranscoderSupport transcoderSupport)
{
- SubtitleProfile subtitleProfile = StreamBuilder.GetSubtitleProfile(stream, subtitleProfiles, PlayMethod, SubProtocol, Container);
+ SubtitleProfile subtitleProfile = StreamBuilder.GetSubtitleProfile(stream, subtitleProfiles, PlayMethod, transcoderSupport, SubProtocol, Container);
SubtitleStreamInfo info = new SubtitleStreamInfo
{
IsForced = stream.IsForced,
diff --git a/MediaBrowser.Model/Dlna/StreamInfoSorter.cs b/MediaBrowser.Model/Dlna/StreamInfoSorter.cs
index badd3c5b1..e13b32767 100644
--- a/MediaBrowser.Model/Dlna/StreamInfoSorter.cs
+++ b/MediaBrowser.Model/Dlna/StreamInfoSorter.cs
@@ -8,7 +8,7 @@ namespace MediaBrowser.Model.Dlna
{
public class StreamInfoSorter
{
- public static List<StreamInfo> SortMediaSources(List<StreamInfo> streams, long? maxBitrate)
+ public static StreamInfo[] SortMediaSources(List<StreamInfo> streams, long? maxBitrate)
{
return streams.OrderBy(i =>
{
@@ -54,7 +54,7 @@ namespace MediaBrowser.Model.Dlna
return 0;
- }).ToList();
+ }).ToArray();
}
}
}
diff --git a/MediaBrowser.Model/Dlna/SubtitleProfile.cs b/MediaBrowser.Model/Dlna/SubtitleProfile.cs
index f182541d8..3f639a520 100644
--- a/MediaBrowser.Model/Dlna/SubtitleProfile.cs
+++ b/MediaBrowser.Model/Dlna/SubtitleProfile.cs
@@ -19,14 +19,9 @@ namespace MediaBrowser.Model.Dlna
[XmlAttribute("language")]
public string Language { get; set; }
- public List<string> GetLanguages()
+ public string[] GetLanguages()
{
- List<string> list = new List<string>();
- foreach (string i in (Language ?? string.Empty).Split(','))
- {
- if (!string.IsNullOrEmpty(i)) list.Add(i);
- }
- return list;
+ return ContainerProfile.SplitValue(Language);
}
public bool SupportsLanguage(string subLanguage)
@@ -41,8 +36,8 @@ namespace MediaBrowser.Model.Dlna
subLanguage = "und";
}
- List<string> languages = GetLanguages();
- return languages.Count == 0 || ListHelper.ContainsIgnoreCase(languages, subLanguage);
+ var languages = GetLanguages();
+ return languages.Length == 0 || ListHelper.ContainsIgnoreCase(languages, subLanguage);
}
}
} \ No newline at end of file
diff --git a/MediaBrowser.Model/Dlna/TranscodingProfile.cs b/MediaBrowser.Model/Dlna/TranscodingProfile.cs
index 9623a68b0..8453fdf6d 100644
--- a/MediaBrowser.Model/Dlna/TranscodingProfile.cs
+++ b/MediaBrowser.Model/Dlna/TranscodingProfile.cs
@@ -51,14 +51,9 @@ namespace MediaBrowser.Model.Dlna
[XmlAttribute("breakOnNonKeyFrames")]
public bool BreakOnNonKeyFrames { get; set; }
- public List<string> GetAudioCodecs()
+ public string[] GetAudioCodecs()
{
- List<string> list = new List<string>();
- foreach (string i in (AudioCodec ?? string.Empty).Split(','))
- {
- if (!string.IsNullOrEmpty(i)) list.Add(i);
- }
- return list;
+ return ContainerProfile.SplitValue(AudioCodec);
}
}
}
diff --git a/MediaBrowser.Model/Dto/BaseItemDto.cs b/MediaBrowser.Model/Dto/BaseItemDto.cs
index afd871be0..8bad650b5 100644
--- a/MediaBrowser.Model/Dto/BaseItemDto.cs
+++ b/MediaBrowser.Model/Dto/BaseItemDto.cs
@@ -163,7 +163,7 @@ namespace MediaBrowser.Model.Dto
public string[] ProductionLocations { get; set; }
- public List<string> MultiPartGameFiles { get; set; }
+ public string[] MultiPartGameFiles { get; set; }
/// <summary>
/// Gets or sets the path.
@@ -201,7 +201,7 @@ namespace MediaBrowser.Model.Dto
/// Gets or sets the taglines.
/// </summary>
/// <value>The taglines.</value>
- public List<string> Taglines { get; set; }
+ public string[] Taglines { get; set; }
/// <summary>
/// Gets or sets the genres.
@@ -210,12 +210,6 @@ namespace MediaBrowser.Model.Dto
public List<string> Genres { get; set; }
/// <summary>
- /// Gets or sets the series genres.
- /// </summary>
- /// <value>The series genres.</value>
- public List<string> SeriesGenres { get; set; }
-
- /// <summary>
/// Gets or sets the community rating.
/// </summary>
/// <value>The community rating.</value>
@@ -228,12 +222,6 @@ namespace MediaBrowser.Model.Dto
public long? CumulativeRunTimeTicks { get; set; }
/// <summary>
- /// Gets or sets the original run time ticks.
- /// </summary>
- /// <value>The original run time ticks.</value>
- public long? OriginalRunTimeTicks { get; set; }
-
- /// <summary>
/// Gets or sets the run time ticks.
/// </summary>
/// <value>The run time ticks.</value>
@@ -258,12 +246,6 @@ namespace MediaBrowser.Model.Dto
public int? ProductionYear { get; set; }
/// <summary>
- /// Gets or sets the players supported by a game.
- /// </summary>
- /// <value>The players.</value>
- public int? Players { get; set; }
-
- /// <summary>
/// Gets or sets a value indicating whether this instance is place holder.
/// </summary>
/// <value><c>null</c> if [is place holder] contains no value, <c>true</c> if [is place holder]; otherwise, <c>false</c>.</value>
@@ -298,7 +280,7 @@ namespace MediaBrowser.Model.Dto
/// Gets or sets the trailer urls.
/// </summary>
/// <value>The trailer urls.</value>
- public List<MediaUrl> RemoteTrailers { get; set; }
+ public MediaUrl[] RemoteTrailers { get; set; }
/// <summary>
/// Gets or sets the provider ids.
@@ -360,7 +342,7 @@ namespace MediaBrowser.Model.Dto
/// Gets or sets the parent backdrop image tags.
/// </summary>
/// <value>The parent backdrop image tags.</value>
- public List<string> ParentBackdropImageTags { get; set; }
+ public string[] ParentBackdropImageTags { get; set; }
/// <summary>
/// Gets or sets the local trailer count.
@@ -432,13 +414,13 @@ namespace MediaBrowser.Model.Dto
/// Gets or sets the air days.
/// </summary>
/// <value>The air days.</value>
- public List<DayOfWeek> AirDays { get; set; }
+ public DayOfWeek[] AirDays { get; set; }
/// <summary>
/// Gets or sets the tags.
/// </summary>
/// <value>The tags.</value>
- public List<string> Tags { get; set; }
+ public string[] Tags { get; set; }
/// <summary>
/// Gets or sets the primary image aspect ratio, after image enhancements.
@@ -450,13 +432,13 @@ namespace MediaBrowser.Model.Dto
/// Gets or sets the artists.
/// </summary>
/// <value>The artists.</value>
- public List<string> Artists { get; set; }
+ public string[] Artists { get; set; }
/// <summary>
/// Gets or sets the artist items.
/// </summary>
/// <value>The artist items.</value>
- public List<NameIdPair> ArtistItems { get; set; }
+ public NameIdPair[] ArtistItems { get; set; }
/// <summary>
/// Gets or sets the album.
@@ -503,7 +485,7 @@ namespace MediaBrowser.Model.Dto
/// Gets or sets the album artists.
/// </summary>
/// <value>The album artists.</value>
- public List<NameIdPair> AlbumArtists { get; set; }
+ public NameIdPair[] AlbumArtists { get; set; }
/// <summary>
/// Gets or sets the name of the season.
@@ -515,7 +497,7 @@ namespace MediaBrowser.Model.Dto
/// Gets or sets the media streams.
/// </summary>
/// <value>The media streams.</value>
- public List<MediaStream> MediaStreams { get; set; }
+ public MediaStream[] MediaStreams { get; set; }
/// <summary>
/// Gets or sets the type of the video.
@@ -524,12 +506,6 @@ namespace MediaBrowser.Model.Dto
public VideoType? VideoType { get; set; }
/// <summary>
- /// Gets or sets the display type of the media.
- /// </summary>
- /// <value>The display type of the media.</value>
- public string DisplayMediaType { get; set; }
-
- /// <summary>
/// Gets or sets the part count.
/// </summary>
/// <value>The part count.</value>
@@ -566,13 +542,13 @@ namespace MediaBrowser.Model.Dto
/// Gets or sets the backdrop image tags.
/// </summary>
/// <value>The backdrop image tags.</value>
- public List<string> BackdropImageTags { get; set; }
+ public string[] BackdropImageTags { get; set; }
/// <summary>
/// Gets or sets the screenshot image tags.
/// </summary>
/// <value>The screenshot image tags.</value>
- public List<string> ScreenshotImageTags { get; set; }
+ public string[] ScreenshotImageTags { get; set; }
/// <summary>
/// Gets or sets the parent logo image tag.
@@ -604,8 +580,6 @@ namespace MediaBrowser.Model.Dto
/// <value>The series studio.</value>
public string SeriesStudio { get; set; }
- public StudioDto SeriesStudioInfo { get; set; }
-
/// <summary>
/// Gets or sets the parent thumb item id.
/// </summary>
@@ -670,7 +644,7 @@ namespace MediaBrowser.Model.Dto
/// Gets or sets the locked fields.
/// </summary>
/// <value>The locked fields.</value>
- public List<MetadataFields> LockedFields { get; set; }
+ public MetadataFields[] LockedFields { get; set; }
/// <summary>
/// Gets or sets the trailer count.
@@ -748,66 +722,6 @@ namespace MediaBrowser.Model.Dto
public string SeriesTimerId { get; set; }
/// <summary>
- /// Gets a value indicating whether this instance has art.
- /// </summary>
- /// <value><c>true</c> if this instance has art; otherwise, <c>false</c>.</value>
- [IgnoreDataMember]
- public bool HasArtImage
- {
- get { return ImageTags != null && ImageTags.ContainsKey(ImageType.Art); }
- }
-
- /// <summary>
- /// Gets a value indicating whether this instance has logo.
- /// </summary>
- /// <value><c>true</c> if this instance has logo; otherwise, <c>false</c>.</value>
- [IgnoreDataMember]
- public bool HasLogo
- {
- get { return ImageTags != null && ImageTags.ContainsKey(ImageType.Logo); }
- }
-
- /// <summary>
- /// Gets a value indicating whether this instance has thumb.
- /// </summary>
- /// <value><c>true</c> if this instance has thumb; otherwise, <c>false</c>.</value>
- [IgnoreDataMember]
- public bool HasThumb
- {
- get { return ImageTags != null && ImageTags.ContainsKey(ImageType.Thumb); }
- }
-
- /// <summary>
- /// Gets a value indicating whether this instance has thumb.
- /// </summary>
- /// <value><c>true</c> if this instance has thumb; otherwise, <c>false</c>.</value>
- [IgnoreDataMember]
- public bool HasBackdrop
- {
- get { return (BackdropImageTags != null && BackdropImageTags.Count > 0) || (ParentBackdropImageTags != null && ParentBackdropImageTags.Count > 0); }
- }
-
- /// <summary>
- /// Gets a value indicating whether this instance has primary image.
- /// </summary>
- /// <value><c>true</c> if this instance has primary image; otherwise, <c>false</c>.</value>
- [IgnoreDataMember]
- public bool HasPrimaryImage
- {
- get { return ImageTags != null && ImageTags.ContainsKey(ImageType.Primary); }
- }
-
- /// <summary>
- /// Gets a value indicating whether this instance is video.
- /// </summary>
- /// <value><c>true</c> if this instance is video; otherwise, <c>false</c>.</value>
- [IgnoreDataMember]
- public bool IsVideo
- {
- get { return StringHelper.EqualsIgnoreCase(MediaType, Entities.MediaType.Video); }
- }
-
- /// <summary>
/// Gets or sets the program identifier.
/// </summary>
/// <value>The program identifier.</value>
diff --git a/MediaBrowser.Model/Dto/GameSystemSummary.cs b/MediaBrowser.Model/Dto/GameSystemSummary.cs
index 1da3bb0ac..2cd9d408d 100644
--- a/MediaBrowser.Model/Dto/GameSystemSummary.cs
+++ b/MediaBrowser.Model/Dto/GameSystemSummary.cs
@@ -29,7 +29,7 @@ namespace MediaBrowser.Model.Dto
/// Gets or sets the game extensions.
/// </summary>
/// <value>The game extensions.</value>
- public List<string> GameFileExtensions { get; set; }
+ public string[] GameFileExtensions { get; set; }
/// <summary>
/// Gets or sets the client installed game count.
@@ -42,7 +42,7 @@ namespace MediaBrowser.Model.Dto
/// </summary>
public GameSystemSummary()
{
- GameFileExtensions = new List<string>();
+ GameFileExtensions = new string[] { };
}
}
}
diff --git a/MediaBrowser.Model/Dto/ItemLayout.cs b/MediaBrowser.Model/Dto/ItemLayout.cs
deleted file mode 100644
index c85818390..000000000
--- a/MediaBrowser.Model/Dto/ItemLayout.cs
+++ /dev/null
@@ -1,72 +0,0 @@
-using System;
-using System.Collections.Generic;
-
-namespace MediaBrowser.Model.Dto
-{
- public static class ItemLayout
- {
- public static double? GetDisplayAspectRatio(BaseItemDto item)
- {
- List<BaseItemDto> items = new List<BaseItemDto>();
- items.Add(item);
- return GetDisplayAspectRatio(items);
- }
-
- public static double? GetDisplayAspectRatio(List<BaseItemDto> items)
- {
- List<double> values = new List<double>();
-
- foreach (BaseItemDto item in items)
- {
- if (item.PrimaryImageAspectRatio.HasValue)
- {
- values.Add(item.PrimaryImageAspectRatio.Value);
- }
- }
-
- if (values.Count == 0)
- {
- return null;
- }
-
- values.Sort();
-
- double halfDouble = values.Count;
- halfDouble /= 2;
- int half = Convert.ToInt32(Math.Floor(halfDouble));
-
- double result;
-
- if (values.Count % 2 > 0)
- result = values[half];
- else
- result = (values[half - 1] + values[half]) / 2.0;
-
- // If really close to 2:3 (poster image), just return 2:3
- if (Math.Abs(0.66666666667 - result) <= .15)
- {
- return 0.66666666667;
- }
-
- // If really close to 16:9 (episode image), just return 16:9
- if (Math.Abs(1.777777778 - result) <= .2)
- {
- return 1.777777778;
- }
-
- // If really close to 1 (square image), just return 1
- if (Math.Abs(1 - result) <= .15)
- {
- return 1.0;
- }
-
- // If really close to 4:3 (poster image), just return 2:3
- if (Math.Abs(1.33333333333 - result) <= .15)
- {
- return 1.33333333333;
- }
-
- return result;
- }
- }
-}
diff --git a/MediaBrowser.Model/Dto/MediaSourceInfo.cs b/MediaBrowser.Model/Dto/MediaSourceInfo.cs
index 08824913f..27920bdf3 100644
--- a/MediaBrowser.Model/Dto/MediaSourceInfo.cs
+++ b/MediaBrowser.Model/Dto/MediaSourceInfo.cs
@@ -2,7 +2,6 @@
using MediaBrowser.Model.Extensions;
using MediaBrowser.Model.MediaInfo;
using System.Collections.Generic;
-using System.Linq;
using MediaBrowser.Model.Serialization;
using MediaBrowser.Model.Session;
@@ -41,6 +40,7 @@ namespace MediaBrowser.Model.Dto
public string OpenToken { get; set; }
public bool RequiresClosing { get; set; }
public bool SupportsProbing { get; set; }
+ public bool EnableMpDecimate { get; set; }
public string LiveStreamId { get; set; }
public int? BufferMs { get; set; }
@@ -53,9 +53,8 @@ namespace MediaBrowser.Model.Dto
public Video3DFormat? Video3DFormat { get; set; }
public List<MediaStream> MediaStreams { get; set; }
- public List<string> PlayableStreamFileNames { get; set; }
- public List<string> Formats { get; set; }
+ public string[] Formats { get; set; }
public int? Bitrate { get; set; }
@@ -70,10 +69,9 @@ namespace MediaBrowser.Model.Dto
public MediaSourceInfo()
{
- Formats = new List<string>();
+ Formats = new string[] { };
MediaStreams = new List<MediaStream>();
RequiredHttpHeaders = new Dictionary<string, string>();
- PlayableStreamFileNames = new List<string>();
SupportsTranscoding = true;
SupportsDirectStream = true;
SupportsDirectPlay = true;
@@ -92,19 +90,15 @@ namespace MediaBrowser.Model.Dto
return;
}
- var internalStreams = MediaStreams
- .Where(i => !i.IsExternal)
- .ToList();
-
- if (internalStreams.Count == 0)
+ var bitrate = 0;
+ foreach (var stream in MediaStreams)
{
- return;
+ if (!stream.IsExternal)
+ {
+ bitrate += stream.BitRate ?? 0;
+ }
}
- var bitrate = internalStreams
- .Select(m => m.BitRate ?? 0)
- .Sum();
-
if (bitrate > 0)
{
Bitrate = bitrate;
@@ -164,7 +158,7 @@ namespace MediaBrowser.Model.Dto
{
foreach (MediaStream i in MediaStreams)
{
- if (i.Type == MediaStreamType.Video && StringHelper.IndexOfIgnoreCase(i.Codec ?? string.Empty, "jpeg") == -1)
+ if (i.Type == MediaStreamType.Video)
{
return i;
}
diff --git a/MediaBrowser.Model/Dto/MetadataEditorInfo.cs b/MediaBrowser.Model/Dto/MetadataEditorInfo.cs
index 9bd15fc8f..aa8b33c81 100644
--- a/MediaBrowser.Model/Dto/MetadataEditorInfo.cs
+++ b/MediaBrowser.Model/Dto/MetadataEditorInfo.cs
@@ -7,21 +7,21 @@ namespace MediaBrowser.Model.Dto
{
public class MetadataEditorInfo
{
- public List<ParentalRating> ParentalRatingOptions { get; set; }
- public List<CountryInfo> Countries { get; set; }
- public List<CultureDto> Cultures { get; set; }
- public List<ExternalIdInfo> ExternalIdInfos { get; set; }
+ public ParentalRating[] ParentalRatingOptions { get; set; }
+ public CountryInfo[] Countries { get; set; }
+ public CultureDto[] Cultures { get; set; }
+ public ExternalIdInfo[] ExternalIdInfos { get; set; }
public string ContentType { get; set; }
- public List<NameValuePair> ContentTypeOptions { get; set; }
+ public NameValuePair[] ContentTypeOptions { get; set; }
public MetadataEditorInfo()
{
- ParentalRatingOptions = new List<ParentalRating>();
- Countries = new List<CountryInfo>();
- Cultures = new List<CultureDto>();
- ExternalIdInfos = new List<ExternalIdInfo>();
- ContentTypeOptions = new List<NameValuePair>();
+ ParentalRatingOptions = new ParentalRating[] { };
+ Countries = new CountryInfo[] { };
+ Cultures = new CultureDto[] { };
+ ExternalIdInfos = new ExternalIdInfo[] { };
+ ContentTypeOptions = new NameValuePair[] { };
}
}
}
diff --git a/MediaBrowser.Model/Dto/StudioDto.cs b/MediaBrowser.Model/Dto/StudioDto.cs
deleted file mode 100644
index 10dc60699..000000000
--- a/MediaBrowser.Model/Dto/StudioDto.cs
+++ /dev/null
@@ -1,29 +0,0 @@
-using System.Diagnostics;
-
-namespace MediaBrowser.Model.Dto
-{
- /// <summary>
- /// Class StudioDto
- /// </summary>
- [DebuggerDisplay("Name = {Name}")]
- public class StudioDto
- {
- /// <summary>
- /// Gets or sets the name.
- /// </summary>
- /// <value>The name.</value>
- public string Name { get; set; }
-
- /// <summary>
- /// Gets or sets the identifier.
- /// </summary>
- /// <value>The identifier.</value>
- public string Id { get; set; }
-
- /// <summary>
- /// Gets or sets the primary image tag.
- /// </summary>
- /// <value>The primary image tag.</value>
- public string PrimaryImageTag { get; set; }
- }
-} \ No newline at end of file
diff --git a/MediaBrowser.Model/Entities/LibraryUpdateInfo.cs b/MediaBrowser.Model/Entities/LibraryUpdateInfo.cs
index 07a4b5f60..b3d3be70e 100644
--- a/MediaBrowser.Model/Entities/LibraryUpdateInfo.cs
+++ b/MediaBrowser.Model/Entities/LibraryUpdateInfo.cs
@@ -1,5 +1,4 @@
-using System.Collections.Generic;
-
+
namespace MediaBrowser.Model.Entities
{
/// <summary>
@@ -11,41 +10,41 @@ namespace MediaBrowser.Model.Entities
/// Gets or sets the folders added to.
/// </summary>
/// <value>The folders added to.</value>
- public List<string> FoldersAddedTo { get; set; }
+ public string[] FoldersAddedTo { get; set; }
/// <summary>
/// Gets or sets the folders removed from.
/// </summary>
/// <value>The folders removed from.</value>
- public List<string> FoldersRemovedFrom { get; set; }
+ public string[] FoldersRemovedFrom { get; set; }
/// <summary>
/// Gets or sets the items added.
/// </summary>
/// <value>The items added.</value>
- public List<string> ItemsAdded { get; set; }
+ public string[] ItemsAdded { get; set; }
/// <summary>
/// Gets or sets the items removed.
/// </summary>
/// <value>The items removed.</value>
- public List<string> ItemsRemoved { get; set; }
+ public string[] ItemsRemoved { get; set; }
/// <summary>
/// Gets or sets the items updated.
/// </summary>
/// <value>The items updated.</value>
- public List<string> ItemsUpdated { get; set; }
+ public string[] ItemsUpdated { get; set; }
/// <summary>
/// Initializes a new instance of the <see cref="LibraryUpdateInfo"/> class.
/// </summary>
public LibraryUpdateInfo()
{
- FoldersAddedTo = new List<string>();
- FoldersRemovedFrom = new List<string>();
- ItemsAdded = new List<string>();
- ItemsRemoved = new List<string>();
- ItemsUpdated = new List<string>();
+ FoldersAddedTo = new string[] { };
+ FoldersRemovedFrom = new string[] { };
+ ItemsAdded = new string[] { };
+ ItemsRemoved = new string[] { };
+ ItemsUpdated = new string[] { };
}
}
}
diff --git a/MediaBrowser.Model/Entities/MediaStream.cs b/MediaBrowser.Model/Entities/MediaStream.cs
index 3cd3e7dde..747528cbf 100644
--- a/MediaBrowser.Model/Entities/MediaStream.cs
+++ b/MediaBrowser.Model/Entities/MediaStream.cs
@@ -81,7 +81,7 @@ namespace MediaBrowser.Model.Entities
attributes.Add("Default");
}
- return string.Join(" ", attributes.ToArray());
+ return string.Join(" ", attributes.ToArray(attributes.Count));
}
if (Type == MediaStreamType.Subtitle)
@@ -107,7 +107,7 @@ namespace MediaBrowser.Model.Entities
attributes.Add("Forced");
}
- string name = string.Join(" ", attributes.ToArray());
+ string name = string.Join(" ", attributes.ToArray(attributes.Count));
return name;
}
diff --git a/MediaBrowser.Model/Entities/VideoType.cs b/MediaBrowser.Model/Entities/VideoType.cs
index aa9a3c55f..05c2fa32c 100644
--- a/MediaBrowser.Model/Entities/VideoType.cs
+++ b/MediaBrowser.Model/Entities/VideoType.cs
@@ -21,10 +21,6 @@ namespace MediaBrowser.Model.Entities
/// <summary>
/// The blu ray
/// </summary>
- BluRay,
- /// <summary>
- /// The hd DVD
- /// </summary>
- HdDvd
+ BluRay
}
}
diff --git a/MediaBrowser.Model/Entities/VirtualFolderInfo.cs b/MediaBrowser.Model/Entities/VirtualFolderInfo.cs
index 374d8d028..901090717 100644
--- a/MediaBrowser.Model/Entities/VirtualFolderInfo.cs
+++ b/MediaBrowser.Model/Entities/VirtualFolderInfo.cs
@@ -18,7 +18,7 @@ namespace MediaBrowser.Model.Entities
/// Gets or sets the locations.
/// </summary>
/// <value>The locations.</value>
- public List<string> Locations { get; set; }
+ public string[] Locations { get; set; }
/// <summary>
/// Gets or sets the type of the collection.
@@ -33,7 +33,7 @@ namespace MediaBrowser.Model.Entities
/// </summary>
public VirtualFolderInfo()
{
- Locations = new List<string>();
+ Locations = new string[] { };
}
/// <summary>
diff --git a/MediaBrowser.Model/Extensions/LinqExtensions.cs b/MediaBrowser.Model/Extensions/LinqExtensions.cs
index 6b2bdb4c7..09ace42e8 100644
--- a/MediaBrowser.Model/Extensions/LinqExtensions.cs
+++ b/MediaBrowser.Model/Extensions/LinqExtensions.cs
@@ -42,6 +42,19 @@ namespace MediaBrowser.Model.Extensions
return source.DistinctBy(keySelector, null);
}
+ public static TSource[] ToArray<TSource>(this IEnumerable<TSource> source, int count)
+ {
+ if (source == null) throw new ArgumentNullException("source");
+ if (count < 0) throw new ArgumentOutOfRangeException("count");
+ var array = new TSource[count];
+ int i = 0;
+ foreach (var item in source)
+ {
+ array[i++] = item;
+ }
+ return array;
+ }
+
/// <summary>
/// Returns all distinct elements of the given source, where "distinctness"
/// is determined via a projection and the specified comparer for the projected type.
diff --git a/MediaBrowser.Model/Extensions/ListHelper.cs b/MediaBrowser.Model/Extensions/ListHelper.cs
index 741f07469..6fe1793db 100644
--- a/MediaBrowser.Model/Extensions/ListHelper.cs
+++ b/MediaBrowser.Model/Extensions/ListHelper.cs
@@ -1,28 +1,24 @@
using System;
-using System.Collections.Generic;
-using System.Linq;
namespace MediaBrowser.Model.Extensions
{
public static class ListHelper
{
- public static bool ContainsIgnoreCase(List<string> list, string value)
+ public static bool ContainsIgnoreCase(string[] list, string value)
{
if (value == null)
{
throw new ArgumentNullException("value");
}
- return list.Contains(value, StringComparer.OrdinalIgnoreCase);
- }
- public static bool ContainsIgnoreCase(string[] list, string value)
- {
- if (value == null)
+ foreach (var item in list)
{
- throw new ArgumentNullException("value");
+ if (string.Equals(item, value, StringComparison.OrdinalIgnoreCase))
+ {
+ return true;
+ }
}
-
- return list.Contains(value, StringComparer.OrdinalIgnoreCase);
+ return false;
}
public static bool ContainsAnyIgnoreCase(string[] list, string[] values)
diff --git a/MediaBrowser.Model/Globalization/ILocalizationManager.cs b/MediaBrowser.Model/Globalization/ILocalizationManager.cs
index 4477d8de3..2356a2fa1 100644
--- a/MediaBrowser.Model/Globalization/ILocalizationManager.cs
+++ b/MediaBrowser.Model/Globalization/ILocalizationManager.cs
@@ -12,17 +12,17 @@ namespace MediaBrowser.Model.Globalization
/// Gets the cultures.
/// </summary>
/// <returns>IEnumerable{CultureDto}.</returns>
- IEnumerable<CultureDto> GetCultures();
+ CultureDto[] GetCultures();
/// <summary>
/// Gets the countries.
/// </summary>
/// <returns>IEnumerable{CountryInfo}.</returns>
- IEnumerable<CountryInfo> GetCountries();
+ CountryInfo[] GetCountries();
/// <summary>
/// Gets the parental ratings.
/// </summary>
/// <returns>IEnumerable{ParentalRating}.</returns>
- IEnumerable<ParentalRating> GetParentalRatings();
+ ParentalRating[] GetParentalRatings();
/// <summary>
/// Gets the rating level.
/// </summary>
@@ -49,7 +49,7 @@ namespace MediaBrowser.Model.Globalization
/// Gets the localization options.
/// </summary>
/// <returns>IEnumerable{LocalizatonOption}.</returns>
- IEnumerable<LocalizatonOption> GetLocalizationOptions();
+ LocalizatonOption[] GetLocalizationOptions();
string RemoveDiacritics(string text);
diff --git a/MediaBrowser.Model/Health/IHealthMonitor.cs b/MediaBrowser.Model/Health/IHealthMonitor.cs
deleted file mode 100644
index a4f95c1bc..000000000
--- a/MediaBrowser.Model/Health/IHealthMonitor.cs
+++ /dev/null
@@ -1,12 +0,0 @@
-using System.Collections.Generic;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Model.Notifications;
-
-namespace MediaBrowser.Model.Health
-{
- public interface IHealthMonitor
- {
- Task<List<Notification>> GetNotifications(CancellationToken cancellationToken);
- }
-}
diff --git a/MediaBrowser.Model/LiveTv/BaseTimerInfoDto.cs b/MediaBrowser.Model/LiveTv/BaseTimerInfoDto.cs
index 9d7fdd129..7c9fe0790 100644
--- a/MediaBrowser.Model/LiveTv/BaseTimerInfoDto.cs
+++ b/MediaBrowser.Model/LiveTv/BaseTimerInfoDto.cs
@@ -113,7 +113,7 @@ namespace MediaBrowser.Model.LiveTv
/// Gets or sets the parent backdrop image tags.
/// </summary>
/// <value>The parent backdrop image tags.</value>
- public List<string> ParentBackdropImageTags { get; set; }
+ public string[] ParentBackdropImageTags { get; set; }
/// <summary>
/// Gets or sets a value indicating whether this instance is post padding required.
diff --git a/MediaBrowser.Model/LiveTv/ChannelInfoDto.cs b/MediaBrowser.Model/LiveTv/ChannelInfoDto.cs
index a8ea86494..67e3d44da 100644
--- a/MediaBrowser.Model/LiveTv/ChannelInfoDto.cs
+++ b/MediaBrowser.Model/LiveTv/ChannelInfoDto.cs
@@ -41,7 +41,7 @@ namespace MediaBrowser.Model.LiveTv
/// Gets or sets the media sources.
/// </summary>
/// <value>The media sources.</value>
- public List<MediaSourceInfo> MediaSources { get; set; }
+ public MediaSourceInfo[] MediaSources { get; set; }
/// <summary>
/// Gets or sets the image tags.
@@ -116,7 +116,7 @@ namespace MediaBrowser.Model.LiveTv
public ChannelInfoDto()
{
ImageTags = new Dictionary<ImageType, string>();
- MediaSources = new List<MediaSourceInfo>();
+ MediaSources = new MediaSourceInfo[] { };
}
}
}
diff --git a/MediaBrowser.Model/LiveTv/LiveTvInfo.cs b/MediaBrowser.Model/LiveTv/LiveTvInfo.cs
index f4d3e21d9..4620fbf0c 100644
--- a/MediaBrowser.Model/LiveTv/LiveTvInfo.cs
+++ b/MediaBrowser.Model/LiveTv/LiveTvInfo.cs
@@ -8,7 +8,7 @@ namespace MediaBrowser.Model.LiveTv
/// Gets or sets the services.
/// </summary>
/// <value>The services.</value>
- public List<LiveTvServiceInfo> Services { get; set; }
+ public LiveTvServiceInfo[] Services { get; set; }
/// <summary>
/// Gets or sets a value indicating whether this instance is enabled.
@@ -20,12 +20,12 @@ namespace MediaBrowser.Model.LiveTv
/// Gets or sets the enabled users.
/// </summary>
/// <value>The enabled users.</value>
- public List<string> EnabledUsers { get; set; }
+ public string[] EnabledUsers { get; set; }
public LiveTvInfo()
{
- Services = new List<LiveTvServiceInfo>();
- EnabledUsers = new List<string>();
+ Services = new LiveTvServiceInfo[] { };
+ EnabledUsers = new string[] { };
}
}
} \ No newline at end of file
diff --git a/MediaBrowser.Model/LiveTv/LiveTvOptions.cs b/MediaBrowser.Model/LiveTv/LiveTvOptions.cs
index 8555f9c38..2c2f22e86 100644
--- a/MediaBrowser.Model/LiveTv/LiveTvOptions.cs
+++ b/MediaBrowser.Model/LiveTv/LiveTvOptions.cs
@@ -15,8 +15,8 @@ namespace MediaBrowser.Model.LiveTv
public bool EnableOriginalAudioWithEncodedRecordings { get; set; }
public string RecordedVideoCodec { get; set; }
- public List<TunerHostInfo> TunerHosts { get; set; }
- public List<ListingsProviderInfo> ListingProviders { get; set; }
+ public TunerHostInfo[] TunerHosts { get; set; }
+ public ListingsProviderInfo[] ListingProviders { get; set; }
public int PrePaddingSeconds { get; set; }
public int PostPaddingSeconds { get; set; }
@@ -28,8 +28,8 @@ namespace MediaBrowser.Model.LiveTv
public LiveTvOptions()
{
- TunerHosts = new List<TunerHostInfo>();
- ListingProviders = new List<ListingsProviderInfo>();
+ TunerHosts = new TunerHostInfo[] { };
+ ListingProviders = new ListingsProviderInfo[] { };
MediaLocationsCreated = new string[] { };
RecordingEncodingFormat = "mkv";
RecordingPostProcessorArguments = "\"{path}\"";
@@ -46,13 +46,14 @@ namespace MediaBrowser.Model.LiveTv
public string FriendlyName { get; set; }
public bool ImportFavoritesOnly { get; set; }
public bool AllowHWTranscoding { get; set; }
- public bool EnableTvgId { get; set; }
public bool EnableStreamLooping { get; set; }
+ public bool EnableMpDecimate { get; set; }
+ public bool EnableNewHdhrChannelIds { get; set; }
+ public string Source { get; set; }
public TunerHostInfo()
{
AllowHWTranscoding = true;
- EnableTvgId = true;
}
}
diff --git a/MediaBrowser.Model/LiveTv/LiveTvServiceInfo.cs b/MediaBrowser.Model/LiveTv/LiveTvServiceInfo.cs
index 25d3b289f..09ec4b931 100644
--- a/MediaBrowser.Model/LiveTv/LiveTvServiceInfo.cs
+++ b/MediaBrowser.Model/LiveTv/LiveTvServiceInfo.cs
@@ -48,11 +48,11 @@ namespace MediaBrowser.Model.LiveTv
/// <value><c>true</c> if this instance is visible; otherwise, <c>false</c>.</value>
public bool IsVisible { get; set; }
- public List<LiveTvTunerInfoDto> Tuners { get; set; }
+ public LiveTvTunerInfoDto[] Tuners { get; set; }
public LiveTvServiceInfo()
{
- Tuners = new List<LiveTvTunerInfoDto>();
+ Tuners = new LiveTvTunerInfoDto[] { };
}
}
}
diff --git a/MediaBrowser.Model/LiveTv/LiveTvTunerInfoDto.cs b/MediaBrowser.Model/LiveTv/LiveTvTunerInfoDto.cs
index 9af96df43..937cef057 100644
--- a/MediaBrowser.Model/LiveTv/LiveTvTunerInfoDto.cs
+++ b/MediaBrowser.Model/LiveTv/LiveTvTunerInfoDto.cs
@@ -62,7 +62,7 @@ namespace MediaBrowser.Model.LiveTv
/// Gets or sets the clients.
/// </summary>
/// <value>The clients.</value>
- public List<string> Clients { get; set; }
+ public string[] Clients { get; set; }
/// <summary>
/// Gets or sets a value indicating whether this instance can reset.
@@ -72,7 +72,7 @@ namespace MediaBrowser.Model.LiveTv
public LiveTvTunerInfoDto()
{
- Clients = new List<string>();
+ Clients = new string[] { };
}
}
} \ No newline at end of file
diff --git a/MediaBrowser.Model/LiveTv/ProgramQuery.cs b/MediaBrowser.Model/LiveTv/ProgramQuery.cs
index 1fd995760..c0959635f 100644
--- a/MediaBrowser.Model/LiveTv/ProgramQuery.cs
+++ b/MediaBrowser.Model/LiveTv/ProgramQuery.cs
@@ -12,7 +12,7 @@ namespace MediaBrowser.Model.LiveTv
public ProgramQuery()
{
ChannelIds = new string[] { };
- SortBy = new string[] { };
+ OrderBy = new Tuple<string, SortOrder>[] { };
Genres = new string[] { };
EnableTotalRecordCount = true;
EnableUserData = true;
@@ -104,17 +104,7 @@ namespace MediaBrowser.Model.LiveTv
/// </summary>
public int? Limit { get; set; }
- /// <summary>
- /// What to sort the results by
- /// </summary>
- /// <value>The sort by.</value>
- public string[] SortBy { get; set; }
-
- /// <summary>
- /// The sort order to return results with
- /// </summary>
- /// <value>The sort order.</value>
- public SortOrder? SortOrder { get; set; }
+ public Tuple<string, SortOrder>[] OrderBy { get; set; }
/// <summary>
/// Limit results to items containing specific genres
diff --git a/MediaBrowser.Model/LiveTv/SeriesTimerInfoDto.cs b/MediaBrowser.Model/LiveTv/SeriesTimerInfoDto.cs
index 388001287..743caa97e 100644
--- a/MediaBrowser.Model/LiveTv/SeriesTimerInfoDto.cs
+++ b/MediaBrowser.Model/LiveTv/SeriesTimerInfoDto.cs
@@ -15,7 +15,7 @@ namespace MediaBrowser.Model.LiveTv
public SeriesTimerInfoDto()
{
ImageTags = new Dictionary<ImageType, string>();
- Days = new List<DayOfWeek>();
+ Days = new DayOfWeek[] { };
Type = "SeriesTimer";
}
@@ -45,7 +45,7 @@ namespace MediaBrowser.Model.LiveTv
/// Gets or sets the days.
/// </summary>
/// <value>The days.</value>
- public List<DayOfWeek> Days { get; set; }
+ public DayOfWeek[] Days { get; set; }
/// <summary>
/// Gets or sets the day pattern.
@@ -60,16 +60,6 @@ namespace MediaBrowser.Model.LiveTv
public Dictionary<ImageType, string> ImageTags { get; set; }
/// <summary>
- /// Gets a value indicating whether this instance has primary image.
- /// </summary>
- /// <value><c>true</c> if this instance has primary image; otherwise, <c>false</c>.</value>
- [IgnoreDataMember]
- public bool HasPrimaryImage
- {
- get { return ImageTags != null && ImageTags.ContainsKey(ImageType.Primary); }
- }
-
- /// <summary>
/// Gets or sets the parent thumb item id.
/// </summary>
/// <value>The parent thumb item id.</value>
diff --git a/MediaBrowser.Model/Logging/ILogManager.cs b/MediaBrowser.Model/Logging/ILogManager.cs
index 59bb86756..218f13eb4 100644
--- a/MediaBrowser.Model/Logging/ILogManager.cs
+++ b/MediaBrowser.Model/Logging/ILogManager.cs
@@ -32,12 +32,6 @@ namespace MediaBrowser.Model.Logging
void ReloadLogger(LogSeverity severity);
/// <summary>
- /// Gets the log file path.
- /// </summary>
- /// <value>The log file path.</value>
- string LogFilePath { get; }
-
- /// <summary>
/// Occurs when [logger loaded].
/// </summary>
event EventHandler LoggerLoaded;
diff --git a/MediaBrowser.Model/MediaBrowser.Model.csproj b/MediaBrowser.Model/MediaBrowser.Model.csproj
index 249e970dd..b36a773eb 100644
--- a/MediaBrowser.Model/MediaBrowser.Model.csproj
+++ b/MediaBrowser.Model/MediaBrowser.Model.csproj
@@ -40,25 +40,10 @@
<Compile Include="Activity\ActivityLogEntry.cs" />
<Compile Include="Activity\IActivityManager.cs" />
<Compile Include="Activity\IActivityRepository.cs" />
- <Compile Include="ApiClient\ApiHelpers.cs" />
- <Compile Include="ApiClient\ConnectionMode.cs" />
- <Compile Include="ApiClient\ConnectionResult.cs" />
- <Compile Include="ApiClient\ConnectionState.cs" />
<Compile Include="ApiClient\ConnectSignupResponse.cs" />
<Compile Include="ApiClient\HttpResponseEventArgs.cs" />
- <Compile Include="ApiClient\IApiClient.cs" />
- <Compile Include="ApiClient\ApiClientExtensions.cs" />
- <Compile Include="ApiClient\IClientWebSocket.cs" />
- <Compile Include="ApiClient\IConnectionManager.cs" />
- <Compile Include="ApiClient\IDevice.cs" />
- <Compile Include="ApiClient\IServerEvents.cs" />
<Compile Include="ApiClient\GeneralCommandEventArgs.cs" />
- <Compile Include="ApiClient\NetworkStatus.cs" />
- <Compile Include="ApiClient\RemoteLogoutReason.cs" />
- <Compile Include="ApiClient\ServerCredentials.cs" />
<Compile Include="ApiClient\ServerDiscoveryInfo.cs" />
- <Compile Include="ApiClient\ServerInfo.cs" />
- <Compile Include="ApiClient\ServerUserInfo.cs" />
<Compile Include="ApiClient\SessionUpdatesEventArgs.cs" />
<Compile Include="ApiClient\WakeOnLanInfo.cs" />
<Compile Include="Branding\BrandingOptions.cs" />
@@ -85,7 +70,6 @@
<Compile Include="Connect\ConnectAuthenticationResult.cs" />
<Compile Include="Connect\ConnectAuthorization.cs" />
<Compile Include="Connect\ConnectAuthorizationRequest.cs" />
- <Compile Include="ApiClient\ConnectionOptions.cs" />
<Compile Include="Connect\ConnectPassword.cs" />
<Compile Include="Connect\ConnectUser.cs" />
<Compile Include="Connect\ConnectUserQuery.cs" />
@@ -127,7 +111,6 @@
<Compile Include="Drawing\ImageOrientation.cs" />
<Compile Include="Dto\IHasServerId.cs" />
<Compile Include="Dto\IHasSyncInfo.cs" />
- <Compile Include="Dto\ItemLayout.cs" />
<Compile Include="Dto\MetadataEditorInfo.cs" />
<Compile Include="Dto\NameIdPair.cs" />
<Compile Include="Dto\NameValuePair.cs" />
@@ -143,7 +126,6 @@
<Compile Include="System\IPowerManagement.cs" />
<Compile Include="Text\ITextEncoding.cs" />
<Compile Include="Extensions\LinqExtensions.cs" />
- <Compile Include="Health\IHealthMonitor.cs" />
<Compile Include="IO\FileSystemMetadata.cs" />
<Compile Include="IO\IFileSystem.cs" />
<Compile Include="IO\IMemoryStreamFactory.cs" />
@@ -284,7 +266,6 @@
<Compile Include="Providers\ExternalUrl.cs" />
<Compile Include="Providers\ImageProviderInfo.cs" />
<Compile Include="Providers\RemoteImageInfo.cs" />
- <Compile Include="Dto\StudioDto.cs" />
<Compile Include="Entities\CollectionType.cs" />
<Compile Include="Entities\ItemReview.cs" />
<Compile Include="Entities\MediaUrl.cs" />
@@ -319,7 +300,6 @@
<Compile Include="Querying\NextUpQuery.cs" />
<Compile Include="Querying\QueryFilters.cs" />
<Compile Include="Querying\QueryResult.cs" />
- <Compile Include="Querying\SeasonQuery.cs" />
<Compile Include="Querying\SessionQuery.cs" />
<Compile Include="Querying\SimilarItemsQuery.cs" />
<Compile Include="Querying\UpcomingEpisodesQuery.cs" />
@@ -356,7 +336,6 @@
<Compile Include="IO\FileSystemEntryInfo.cs" />
<Compile Include="Dto\ImageOptions.cs" />
<Compile Include="Querying\ItemFilter.cs" />
- <Compile Include="Querying\ItemQuery.cs" />
<Compile Include="Entities\LibraryUpdateInfo.cs" />
<Compile Include="Entities\ParentalRating.cs" />
<Compile Include="Entities\VirtualFolderInfo.cs" />
@@ -432,7 +411,6 @@
<Compile Include="Querying\ItemSortBy.cs" />
<Compile Include="Dto\BaseItemDto.cs" />
<Compile Include="Dto\UserDto.cs" />
- <Compile Include="Querying\ItemsResult.cs" />
<Compile Include="Entities\DisplayPreferences.cs" />
<Compile Include="Entities\ImageType.cs" />
<Compile Include="Entities\IHasProviderIds.cs" />
diff --git a/MediaBrowser.Model/MediaInfo/BlurayDiscInfo.cs b/MediaBrowser.Model/MediaInfo/BlurayDiscInfo.cs
index 963e8dd95..1b573fba7 100644
--- a/MediaBrowser.Model/MediaInfo/BlurayDiscInfo.cs
+++ b/MediaBrowser.Model/MediaInfo/BlurayDiscInfo.cs
@@ -12,7 +12,7 @@ namespace MediaBrowser.Model.MediaInfo
/// Gets or sets the media streams.
/// </summary>
/// <value>The media streams.</value>
- public List<MediaStream> MediaStreams { get; set; }
+ public MediaStream[] MediaStreams { get; set; }
/// <summary>
/// Gets or sets the run time ticks.
@@ -24,7 +24,7 @@ namespace MediaBrowser.Model.MediaInfo
/// Gets or sets the files.
/// </summary>
/// <value>The files.</value>
- public List<string> Files { get; set; }
+ public string[] Files { get; set; }
public string PlaylistName { get; set; }
@@ -32,6 +32,6 @@ namespace MediaBrowser.Model.MediaInfo
/// Gets or sets the chapters.
/// </summary>
/// <value>The chapters.</value>
- public List<double> Chapters { get; set; }
+ public double[] Chapters { get; set; }
}
}
diff --git a/MediaBrowser.Model/MediaInfo/MediaInfo.cs b/MediaBrowser.Model/MediaInfo/MediaInfo.cs
index 126710197..63b1c9cfd 100644
--- a/MediaBrowser.Model/MediaInfo/MediaInfo.cs
+++ b/MediaBrowser.Model/MediaInfo/MediaInfo.cs
@@ -7,7 +7,9 @@ namespace MediaBrowser.Model.MediaInfo
{
public class MediaInfo : MediaSourceInfo, IHasProviderIds
{
- public List<ChapterInfo> Chapters { get; set; }
+ private static readonly string[] EmptyStringArray = new string[] { };
+
+ public ChapterInfo[] Chapters { get; set; }
/// <summary>
/// Gets or sets the album.
@@ -18,23 +20,23 @@ namespace MediaBrowser.Model.MediaInfo
/// Gets or sets the artists.
/// </summary>
/// <value>The artists.</value>
- public List<string> Artists { get; set; }
+ public string[] Artists { get; set; }
/// <summary>
/// Gets or sets the album artists.
/// </summary>
/// <value>The album artists.</value>
- public List<string> AlbumArtists { get; set; }
+ public string[] AlbumArtists { get; set; }
/// <summary>
/// Gets or sets the studios.
/// </summary>
/// <value>The studios.</value>
- public List<string> Studios { get; set; }
- public List<string> Genres { get; set; }
+ public string[] Studios { get; set; }
+ public string[] Genres { get; set; }
public int? IndexNumber { get; set; }
public int? ParentIndexNumber { get; set; }
public int? ProductionYear { get; set; }
public DateTime? PremiereDate { get; set; }
- public List<BaseItemPerson> People { get; set; }
+ public BaseItemPerson[] People { get; set; }
public Dictionary<string, string> ProviderIds { get; set; }
/// <summary>
/// Gets or sets the official rating.
@@ -54,12 +56,12 @@ namespace MediaBrowser.Model.MediaInfo
public MediaInfo()
{
- Chapters = new List<ChapterInfo>();
- Artists = new List<string>();
- AlbumArtists = new List<string>();
- Studios = new List<string>();
- Genres = new List<string>();
- People = new List<BaseItemPerson>();
+ Chapters = new ChapterInfo[] { };
+ Artists = new string[] { };
+ AlbumArtists = EmptyStringArray;
+ Studios = new string[] { };
+ Genres = new string[] { };
+ People = new BaseItemPerson[] { };
ProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
}
}
diff --git a/MediaBrowser.Model/MediaInfo/PlaybackInfoResponse.cs b/MediaBrowser.Model/MediaInfo/PlaybackInfoResponse.cs
index 1f8936d01..b38fec7d4 100644
--- a/MediaBrowser.Model/MediaInfo/PlaybackInfoResponse.cs
+++ b/MediaBrowser.Model/MediaInfo/PlaybackInfoResponse.cs
@@ -10,7 +10,7 @@ namespace MediaBrowser.Model.MediaInfo
/// Gets or sets the media sources.
/// </summary>
/// <value>The media sources.</value>
- public List<MediaSourceInfo> MediaSources { get; set; }
+ public MediaSourceInfo[] MediaSources { get; set; }
/// <summary>
/// Gets or sets the play session identifier.
@@ -26,7 +26,7 @@ namespace MediaBrowser.Model.MediaInfo
public PlaybackInfoResponse()
{
- MediaSources = new List<MediaSourceInfo>();
+ MediaSources = new MediaSourceInfo[] { };
}
}
}
diff --git a/MediaBrowser.Model/MediaInfo/SubtitleTrackInfo.cs b/MediaBrowser.Model/MediaInfo/SubtitleTrackInfo.cs
index 765cfe32f..d3a3bb1d0 100644
--- a/MediaBrowser.Model/MediaInfo/SubtitleTrackInfo.cs
+++ b/MediaBrowser.Model/MediaInfo/SubtitleTrackInfo.cs
@@ -4,11 +4,11 @@ namespace MediaBrowser.Model.MediaInfo
{
public class SubtitleTrackInfo
{
- public List<SubtitleTrackEvent> TrackEvents { get; set; }
+ public SubtitleTrackEvent[] TrackEvents { get; set; }
public SubtitleTrackInfo()
{
- TrackEvents = new List<SubtitleTrackEvent>();
+ TrackEvents = new SubtitleTrackEvent[] { };
}
}
}
diff --git a/MediaBrowser.Model/Net/HttpResponse.cs b/MediaBrowser.Model/Net/HttpResponse.cs
index f4bd8e681..7c3d1d73d 100644
--- a/MediaBrowser.Model/Net/HttpResponse.cs
+++ b/MediaBrowser.Model/Net/HttpResponse.cs
@@ -59,6 +59,7 @@ namespace MediaBrowser.Model.Net
{
_disposable.Dispose();
}
+ GC.SuppressFinalize(this);
}
}
}
diff --git a/MediaBrowser.Model/Net/IAcceptSocket.cs b/MediaBrowser.Model/Net/IAcceptSocket.cs
index 2b5d33dce..343e12ab6 100644
--- a/MediaBrowser.Model/Net/IAcceptSocket.cs
+++ b/MediaBrowser.Model/Net/IAcceptSocket.cs
@@ -12,9 +12,6 @@ namespace MediaBrowser.Model.Net
void Listen(int backlog);
void Bind(IpEndPointInfo endpoint);
void Connect(IpEndPointInfo endPoint);
- void StartAccept(Action<IAcceptSocket> onAccept, Func<bool> isClosed);
- IAsyncResult BeginSendFile(string path, byte[] preBuffer, byte[] postBuffer, AsyncCallback callback, object state);
- void EndSendFile(IAsyncResult result);
}
public class SocketCreateException : Exception
diff --git a/MediaBrowser.Model/Net/ISocket.cs b/MediaBrowser.Model/Net/ISocket.cs
index 71eb9914b..42550340b 100644
--- a/MediaBrowser.Model/Net/ISocket.cs
+++ b/MediaBrowser.Model/Net/ISocket.cs
@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
-using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
diff --git a/MediaBrowser.Model/Net/MimeTypes.cs b/MediaBrowser.Model/Net/MimeTypes.cs
index 2f132cb37..c4dfd25ca 100644
--- a/MediaBrowser.Model/Net/MimeTypes.cs
+++ b/MediaBrowser.Model/Net/MimeTypes.cs
@@ -14,7 +14,7 @@ namespace MediaBrowser.Model.Net
/// <summary>
/// Any extension in this list is considered a video file - can be added to at runtime for extensibility
/// </summary>
- private static readonly List<string> VideoFileExtensions = new List<string>
+ private static readonly string[] VideoFileExtensions = new string[]
{
".mkv",
".m2t",
@@ -106,14 +106,15 @@ namespace MediaBrowser.Model.Net
return dict;
}
+ public static string GetMimeType(string path)
+ {
+ return GetMimeType(path, true);
+ }
+
/// <summary>
/// Gets the type of the MIME.
/// </summary>
- /// <param name="path">The path.</param>
- /// <returns>System.String.</returns>
- /// <exception cref="ArgumentNullException">path</exception>
- /// <exception cref="InvalidOperationException">Argument not supported: + path</exception>
- public static string GetMimeType(string path)
+ public static string GetMimeType(string path, bool enableStreamDefault)
{
if (string.IsNullOrEmpty(path))
{
@@ -329,7 +330,12 @@ namespace MediaBrowser.Model.Net
return "application/ttml+xml";
}
- return "application/octet-stream";
+ if (enableStreamDefault)
+ {
+ return "application/octet-stream";
+ }
+
+ return null;
}
public static string ToExtension(string mimeType)
diff --git a/MediaBrowser.Model/Notifications/NotificationTypeInfo.cs b/MediaBrowser.Model/Notifications/NotificationTypeInfo.cs
index 59b39fbc7..ee5101011 100644
--- a/MediaBrowser.Model/Notifications/NotificationTypeInfo.cs
+++ b/MediaBrowser.Model/Notifications/NotificationTypeInfo.cs
@@ -18,11 +18,11 @@ namespace MediaBrowser.Model.Notifications
public string DefaultDescription { get; set; }
- public List<string> Variables { get; set; }
+ public string[] Variables { get; set; }
public NotificationTypeInfo()
{
- Variables = new List<string>();
+ Variables = new string[] { };
}
}
} \ No newline at end of file
diff --git a/MediaBrowser.Model/Playlists/PlaylistCreationRequest.cs b/MediaBrowser.Model/Playlists/PlaylistCreationRequest.cs
index 63deb19dc..5314e791a 100644
--- a/MediaBrowser.Model/Playlists/PlaylistCreationRequest.cs
+++ b/MediaBrowser.Model/Playlists/PlaylistCreationRequest.cs
@@ -6,7 +6,7 @@ namespace MediaBrowser.Model.Playlists
{
public string Name { get; set; }
- public List<string> ItemIdList { get; set; }
+ public string[] ItemIdList { get; set; }
public string MediaType { get; set; }
@@ -14,7 +14,7 @@ namespace MediaBrowser.Model.Playlists
public PlaylistCreationRequest()
{
- ItemIdList = new List<string>();
+ ItemIdList = new string[] { };
}
}
}
diff --git a/MediaBrowser.Model/Providers/ImageProviderInfo.cs b/MediaBrowser.Model/Providers/ImageProviderInfo.cs
index c519d66cb..199552640 100644
--- a/MediaBrowser.Model/Providers/ImageProviderInfo.cs
+++ b/MediaBrowser.Model/Providers/ImageProviderInfo.cs
@@ -14,11 +14,11 @@ namespace MediaBrowser.Model.Providers
/// <value>The name.</value>
public string Name { get; set; }
- public List<ImageType> SupportedImages { get; set; }
+ public ImageType[] SupportedImages { get; set; }
public ImageProviderInfo()
{
- SupportedImages = new List<ImageType>();
+ SupportedImages = new ImageType[] { };
}
}
}
diff --git a/MediaBrowser.Model/Providers/RemoteImageResult.cs b/MediaBrowser.Model/Providers/RemoteImageResult.cs
index 1c60db6ae..7e38badfc 100644
--- a/MediaBrowser.Model/Providers/RemoteImageResult.cs
+++ b/MediaBrowser.Model/Providers/RemoteImageResult.cs
@@ -11,7 +11,7 @@ namespace MediaBrowser.Model.Providers
/// Gets or sets the images.
/// </summary>
/// <value>The images.</value>
- public List<RemoteImageInfo> Images { get; set; }
+ public RemoteImageInfo[] Images { get; set; }
/// <summary>
/// Gets or sets the total record count.
@@ -23,6 +23,6 @@ namespace MediaBrowser.Model.Providers
/// Gets or sets the providers.
/// </summary>
/// <value>The providers.</value>
- public List<string> Providers { get; set; }
+ public string[] Providers { get; set; }
}
}
diff --git a/MediaBrowser.Model/Querying/ItemFields.cs b/MediaBrowser.Model/Querying/ItemFields.cs
index e088771b5..f9829c329 100644
--- a/MediaBrowser.Model/Querying/ItemFields.cs
+++ b/MediaBrowser.Model/Querying/ItemFields.cs
@@ -63,11 +63,6 @@
DisplayPreferencesId,
/// <summary>
- /// The display media type
- /// </summary>
- DisplayMediaType,
-
- /// <summary>
/// The etag
/// </summary>
Etag,
@@ -153,11 +148,6 @@
/// </summary>
ScreenshotImageTags,
- /// <summary>
- /// The series genres
- /// </summary>
- SeriesGenres,
-
SeriesPrimaryImage,
/// <summary>
@@ -224,6 +214,7 @@
SeriesPresentationUniqueKey,
DateLastRefreshed,
DateLastSaved,
- RefreshState
+ RefreshState,
+ ChannelImage
}
}
diff --git a/MediaBrowser.Model/Querying/ItemQuery.cs b/MediaBrowser.Model/Querying/ItemQuery.cs
deleted file mode 100644
index 11c046452..000000000
--- a/MediaBrowser.Model/Querying/ItemQuery.cs
+++ /dev/null
@@ -1,332 +0,0 @@
-using MediaBrowser.Model.Entities;
-using System;
-
-namespace MediaBrowser.Model.Querying
-{
- /// <summary>
- /// Contains all the possible parameters that can be used to query for items
- /// </summary>
- public class ItemQuery
- {
- /// <summary>
- /// The user to localize search results for
- /// </summary>
- /// <value>The user id.</value>
- public string UserId { get; set; }
-
- /// <summary>
- /// Specify this to localize the search to a specific item or folder. Omit to use the root.
- /// </summary>
- /// <value>The parent id.</value>
- public string ParentId { get; set; }
-
- /// <summary>
- /// Skips over a given number of items within the results. Use for paging.
- /// </summary>
- /// <value>The start index.</value>
- public int? StartIndex { get; set; }
-
- /// <summary>
- /// The maximum number of items to return
- /// </summary>
- /// <value>The limit.</value>
- public int? Limit { get; set; }
-
- /// <summary>
- /// What to sort the results by
- /// </summary>
- /// <value>The sort by.</value>
- public string[] SortBy { get; set; }
-
- /// <summary>
- /// Gets or sets the artist ids.
- /// </summary>
- /// <value>The artist ids.</value>
- public string[] ArtistIds { get; set; }
-
- /// <summary>
- /// The sort order to return results with
- /// </summary>
- /// <value>The sort order.</value>
- public SortOrder? SortOrder { get; set; }
-
- /// <summary>
- /// Filters to apply to the results
- /// </summary>
- /// <value>The filters.</value>
- public ItemFilter[] Filters { get; set; }
-
- /// <summary>
- /// Fields to return within the items, in addition to basic information
- /// </summary>
- /// <value>The fields.</value>
- public ItemFields[] Fields { get; set; }
-
- /// <summary>
- /// Gets or sets the media types.
- /// </summary>
- /// <value>The media types.</value>
- public string[] MediaTypes { get; set; }
-
- /// <summary>
- /// Gets or sets the video formats.
- /// </summary>
- /// <value>The video formats.</value>
- public bool? Is3D { get; set; }
-
- /// <summary>
- /// Gets or sets the video types.
- /// </summary>
- /// <value>The video types.</value>
- public VideoType[] VideoTypes { get; set; }
-
- /// <summary>
- /// Whether or not to perform the query recursively
- /// </summary>
- /// <value><c>true</c> if recursive; otherwise, <c>false</c>.</value>
- public bool Recursive { get; set; }
-
- /// <summary>
- /// Limit results to items containing specific genres
- /// </summary>
- /// <value>The genres.</value>
- public string[] Genres { get; set; }
-
- /// <summary>
- /// Gets or sets the studio ids.
- /// </summary>
- /// <value>The studio ids.</value>
- public string[] StudioIds { get; set; }
-
- /// <summary>
- /// Gets or sets the exclude item types.
- /// </summary>
- /// <value>The exclude item types.</value>
- public string[] ExcludeItemTypes { get; set; }
-
- /// <summary>
- /// Gets or sets the include item types.
- /// </summary>
- /// <value>The include item types.</value>
- public string[] IncludeItemTypes { get; set; }
-
- /// <summary>
- /// Limit results to items containing specific years
- /// </summary>
- /// <value>The years.</value>
- public int[] Years { get; set; }
-
- /// <summary>
- /// Limit results to items containing a specific person
- /// </summary>
- /// <value>The person.</value>
- public string[] PersonIds { get; set; }
-
- /// <summary>
- /// If the Person filter is used, this can also be used to restrict to a specific person type
- /// </summary>
- /// <value>The type of the person.</value>
- public string[] PersonTypes { get; set; }
-
- /// <summary>
- /// Search characters used to find items
- /// </summary>
- /// <value>The index by.</value>
- public string SearchTerm { get; set; }
-
- /// <summary>
- /// Gets or sets the image types.
- /// </summary>
- /// <value>The image types.</value>
- public ImageType[] ImageTypes { get; set; }
-
- /// <summary>
- /// Gets or sets the air days.
- /// </summary>
- /// <value>The air days.</value>
- public DayOfWeek[] AirDays { get; set; }
-
- /// <summary>
- /// Gets or sets the series status.
- /// </summary>
- /// <value>The series status.</value>
- public SeriesStatus[] SeriesStatuses { get; set; }
-
- /// <summary>
- /// Gets or sets the ids, which are specific items to retrieve
- /// </summary>
- /// <value>The ids.</value>
- public string[] Ids { get; set; }
-
- /// <summary>
- /// Gets or sets the min official rating.
- /// </summary>
- /// <value>The min official rating.</value>
- public string MinOfficialRating { get; set; }
-
- /// <summary>
- /// Gets or sets the max official rating.
- /// </summary>
- /// <value>The max official rating.</value>
- public string MaxOfficialRating { get; set; }
-
- /// <summary>
- /// Gets or sets the min index number.
- /// </summary>
- /// <value>The min index number.</value>
- public int? MinIndexNumber { get; set; }
-
- /// <summary>
- /// Gets or sets a value indicating whether this instance has parental rating.
- /// </summary>
- /// <value><c>null</c> if [has parental rating] contains no value, <c>true</c> if [has parental rating]; otherwise, <c>false</c>.</value>
- public bool? HasParentalRating { get; set; }
-
- /// <summary>
- /// Gets or sets a value indicating whether this instance is HD.
- /// </summary>
- /// <value><c>null</c> if [is HD] contains no value, <c>true</c> if [is HD]; otherwise, <c>false</c>.</value>
- public bool? IsHD { get; set; }
-
- /// <summary>
- /// Gets or sets the parent index number.
- /// </summary>
- /// <value>The parent index number.</value>
- public int? ParentIndexNumber { get; set; }
-
- /// <summary>
- /// Gets or sets the min players.
- /// </summary>
- /// <value>The min players.</value>
- public int? MinPlayers { get; set; }
-
- /// <summary>
- /// Gets or sets the max players.
- /// </summary>
- /// <value>The max players.</value>
- public int? MaxPlayers { get; set; }
-
- /// <summary>
- /// Gets or sets the name starts with or greater.
- /// </summary>
- /// <value>The name starts with or greater.</value>
- public string NameStartsWithOrGreater { get; set; }
-
- /// <summary>
- /// Gets or sets the name starts with.
- /// </summary>
- /// <value>The name starts with or greater.</value>
- public string NameStartsWith { get; set; }
-
- /// <summary>
- /// Gets or sets the name starts with.
- /// </summary>
- /// <value>The name lessthan.</value>
- public string NameLessThan { get; set; }
-
- /// <summary>
- /// Gets or sets the album artist starts with or greater.
- /// </summary>
- /// <value>The album artist starts with or greater.</value>
- public string AlbumArtistStartsWithOrGreater { get; set; }
-
- /// <summary>
- /// Gets or sets a value indicating whether [include index containers].
- /// </summary>
- /// <value><c>true</c> if [include index containers]; otherwise, <c>false</c>.</value>
- public bool IncludeIndexContainers { get; set; }
-
- /// <summary>
- /// Gets or sets the location types.
- /// </summary>
- /// <value>The location types.</value>
- public LocationType[] LocationTypes { get; set; }
-
- /// <summary>
- /// Gets or sets a value indicating whether this instance is missing episode.
- /// </summary>
- /// <value><c>null</c> if [is missing episode] contains no value, <c>true</c> if [is missing episode]; otherwise, <c>false</c>.</value>
- public bool? IsMissing { get; set; }
-
- /// <summary>
- /// Gets or sets a value indicating whether this instance is unaired episode.
- /// </summary>
- /// <value><c>null</c> if [is unaired episode] contains no value, <c>true</c> if [is unaired episode]; otherwise, <c>false</c>.</value>
- public bool? IsUnaired { get; set; }
-
- public bool? IsVirtualUnaired { get; set; }
-
- public bool? IsInBoxSet { get; set; }
-
- public bool? CollapseBoxSetItems { get; set; }
-
- public bool? IsPlayed { get; set; }
-
- /// <summary>
- /// Gets or sets the exclude location types.
- /// </summary>
- /// <value>The exclude location types.</value>
- public LocationType[] ExcludeLocationTypes { get; set; }
-
- public double? MinCommunityRating { get; set; }
- public double? MinCriticRating { get; set; }
-
- public int? AiredDuringSeason { get; set; }
-
- public DateTime? MinPremiereDate { get; set; }
-
- public DateTime? MaxPremiereDate { get; set; }
-
- public bool? EnableImages { get; set; }
- public int? ImageTypeLimit { get; set; }
- public ImageType[] EnableImageTypes { get; set; }
-
- [Obsolete]
- public string[] Artists { get; set; }
- [Obsolete]
- public string[] Studios { get; set; }
- [Obsolete]
- public string Person { get; set; }
-
- public bool EnableTotalRecordCount { get; set; }
-
- /// <summary>
- /// Initializes a new instance of the <see cref="ItemQuery" /> class.
- /// </summary>
- public ItemQuery()
- {
- LocationTypes = new LocationType[] { };
- ExcludeLocationTypes = new LocationType[] { };
-
- SortBy = new string[] { };
-
- Filters = new ItemFilter[] { };
-
- Fields = new ItemFields[] { };
-
- MediaTypes = new string[] { };
-
- VideoTypes = new VideoType[] { };
-
- EnableTotalRecordCount = true;
-
- Artists = new string[] { };
- Studios = new string[] { };
-
- Genres = new string[] { };
- StudioIds = new string[] { };
- IncludeItemTypes = new string[] { };
- ExcludeItemTypes = new string[] { };
- Years = new int[] { };
- PersonTypes = new string[] { };
- Ids = new string[] { };
- ArtistIds = new string[] { };
- PersonIds = new string[] { };
-
- ImageTypes = new ImageType[] { };
- AirDays = new DayOfWeek[] { };
- SeriesStatuses = new SeriesStatus[] { };
- EnableImageTypes = new ImageType[] { };
- }
- }
-}
diff --git a/MediaBrowser.Model/Querying/ItemsResult.cs b/MediaBrowser.Model/Querying/ItemsResult.cs
deleted file mode 100644
index 3b9c59733..000000000
--- a/MediaBrowser.Model/Querying/ItemsResult.cs
+++ /dev/null
@@ -1,11 +0,0 @@
-using MediaBrowser.Model.Dto;
-
-namespace MediaBrowser.Model.Querying
-{
- /// <summary>
- /// Represents the result of a query for items
- /// </summary>
- public class ItemsResult : QueryResult<BaseItemDto>
- {
- }
-}
diff --git a/MediaBrowser.Model/Querying/QueryResult.cs b/MediaBrowser.Model/Querying/QueryResult.cs
index 1ecc1de6c..6f9923d08 100644
--- a/MediaBrowser.Model/Querying/QueryResult.cs
+++ b/MediaBrowser.Model/Querying/QueryResult.cs
@@ -15,9 +15,6 @@ namespace MediaBrowser.Model.Querying
/// <value>The total record count.</value>
public int TotalRecordCount { get; set; }
- /// <summary>
- /// Initializes a new instance of the <see cref="ItemsResult" /> class.
- /// </summary>
public QueryResult()
{
Items = new T[] { };
diff --git a/MediaBrowser.Model/Querying/SeasonQuery.cs b/MediaBrowser.Model/Querying/SeasonQuery.cs
deleted file mode 100644
index b1fe635bb..000000000
--- a/MediaBrowser.Model/Querying/SeasonQuery.cs
+++ /dev/null
@@ -1,22 +0,0 @@
-namespace MediaBrowser.Model.Querying
-{
- public class SeasonQuery
- {
- public string UserId { get; set; }
-
- public string SeriesId { get; set; }
-
- public bool? IsMissing { get; set; }
-
- public bool? IsVirtualUnaired { get; set; }
-
- public ItemFields[] Fields { get; set; }
-
- public bool? IsSpecialSeason { get; set; }
-
- public SeasonQuery()
- {
- Fields = new ItemFields[] { };
- }
- }
-} \ No newline at end of file
diff --git a/MediaBrowser.Model/Querying/ThemeMediaResult.cs b/MediaBrowser.Model/Querying/ThemeMediaResult.cs
index 80478a910..0d7eb502f 100644
--- a/MediaBrowser.Model/Querying/ThemeMediaResult.cs
+++ b/MediaBrowser.Model/Querying/ThemeMediaResult.cs
@@ -1,10 +1,11 @@
-
+using MediaBrowser.Model.Dto;
+
namespace MediaBrowser.Model.Querying
{
/// <summary>
/// Class ThemeMediaResult
/// </summary>
- public class ThemeMediaResult : ItemsResult
+ public class ThemeMediaResult : QueryResult<BaseItemDto>
{
/// <summary>
/// Gets or sets the owner id.
diff --git a/MediaBrowser.Model/Search/SearchHint.cs b/MediaBrowser.Model/Search/SearchHint.cs
index 3ca0eafe6..5c5637481 100644
--- a/MediaBrowser.Model/Search/SearchHint.cs
+++ b/MediaBrowser.Model/Search/SearchHint.cs
@@ -91,12 +91,6 @@ namespace MediaBrowser.Model.Search
/// <value>The type of the media.</value>
public string MediaType { get; set; }
- /// <summary>
- /// Gets or sets the display type of the media.
- /// </summary>
- /// <value>The display type of the media.</value>
- public string DisplayMediaType { get; set; }
-
public DateTime? StartDate { get; set; }
public DateTime? EndDate { get; set; }
diff --git a/MediaBrowser.Model/Services/IHttpRequest.cs b/MediaBrowser.Model/Services/IHttpRequest.cs
index 46c0240cd..e1480f30a 100644
--- a/MediaBrowser.Model/Services/IHttpRequest.cs
+++ b/MediaBrowser.Model/Services/IHttpRequest.cs
@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
-using System.Linq;
using System.Text;
using System.Threading.Tasks;
diff --git a/MediaBrowser.Model/Services/IHttpResponse.cs b/MediaBrowser.Model/Services/IHttpResponse.cs
index 377f303a7..cd9c07d46 100644
--- a/MediaBrowser.Model/Services/IHttpResponse.cs
+++ b/MediaBrowser.Model/Services/IHttpResponse.cs
@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
-using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
diff --git a/MediaBrowser.Model/Services/IHttpResult.cs b/MediaBrowser.Model/Services/IHttpResult.cs
index fcb137c6b..90afb0f27 100644
--- a/MediaBrowser.Model/Services/IHttpResult.cs
+++ b/MediaBrowser.Model/Services/IHttpResult.cs
@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
-using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
diff --git a/MediaBrowser.Model/Services/IRequest.cs b/MediaBrowser.Model/Services/IRequest.cs
index f056c7410..5a895815e 100644
--- a/MediaBrowser.Model/Services/IRequest.cs
+++ b/MediaBrowser.Model/Services/IRequest.cs
@@ -49,11 +49,6 @@ namespace MediaBrowser.Model.Services
string ResponseContentType { get; set; }
/// <summary>
- /// Whether the ResponseContentType has been explicitly overrided or whether it was just the default
- /// </summary>
- bool HasExplicitResponseContentType { get; }
-
- /// <summary>
/// Attach any data to this request that all filters and services can access.
/// </summary>
Dictionary<string, object> Items { get; }
diff --git a/MediaBrowser.Model/Services/QueryParamCollection.cs b/MediaBrowser.Model/Services/QueryParamCollection.cs
index dfea62821..e13e5feca 100644
--- a/MediaBrowser.Model/Services/QueryParamCollection.cs
+++ b/MediaBrowser.Model/Services/QueryParamCollection.cs
@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using MediaBrowser.Model.Dto;
+using MediaBrowser.Model.Extensions;
namespace MediaBrowser.Model.Services
{
@@ -57,9 +58,7 @@ namespace MediaBrowser.Model.Services
{
if (string.IsNullOrWhiteSpace(value))
{
- var stringComparison = GetStringComparison();
-
- var parameters = this.Where(p => string.Equals(key, p.Name, stringComparison)).ToArray();
+ var parameters = GetItems(key);
foreach (var p in parameters)
{
@@ -84,14 +83,6 @@ namespace MediaBrowser.Model.Services
}
/// <summary>
- /// True if the collection contains a query parameter with the given name.
- /// </summary>
- public bool ContainsKey(string name)
- {
- return this.Any(p => p.Name == name);
- }
-
- /// <summary>
/// Removes all parameters of the given name.
/// </summary>
/// <returns>The number of parameters that were removed</returns>
@@ -105,16 +96,49 @@ namespace MediaBrowser.Model.Services
{
var stringComparison = GetStringComparison();
- return this.Where(p => string.Equals(p.Name, name, stringComparison))
- .Select(p => p.Value)
- .FirstOrDefault();
+ foreach (var pair in this)
+ {
+ if (string.Equals(pair.Name, name, stringComparison))
+ {
+ return pair.Value;
+ }
+ }
+
+ return null;
+ }
+
+ public virtual List<NameValuePair> GetItems(string name)
+ {
+ var stringComparison = GetStringComparison();
+
+ var list = new List<NameValuePair>();
+
+ foreach (var pair in this)
+ {
+ if (string.Equals(pair.Name, name, stringComparison))
+ {
+ list.Add(pair);
+ }
+ }
+
+ return list;
}
- public virtual string[] GetValues(string name)
+ public virtual List<string> GetValues(string name)
{
var stringComparison = GetStringComparison();
- return this.Where(p => string.Equals(p.Name, name, stringComparison)).Select(p => p.Value).ToArray();
+ var list = new List<string>();
+
+ foreach (var pair in this)
+ {
+ if (string.Equals(pair.Name, name, stringComparison))
+ {
+ list.Add(pair.Value);
+ }
+ }
+
+ return list;
}
public Dictionary<string, string> ToDictionary()
@@ -133,7 +157,17 @@ namespace MediaBrowser.Model.Services
public IEnumerable<string> Keys
{
- get { return this.Select(i => i.Name); }
+ get
+ {
+ var keys = new string[this.Count];
+
+ for (var i = 0; i < keys.Length; i++)
+ {
+ keys[i] = this[i].Name;
+ }
+
+ return keys;
+ }
}
/// <summary>
@@ -187,7 +221,7 @@ namespace MediaBrowser.Model.Services
public override String ToString()
{
- var vals = this.Select(GetQueryStringValue).ToArray();
+ var vals = this.Select(GetQueryStringValue).ToArray(this.Count);
return string.Join("&", vals);
}
diff --git a/MediaBrowser.Model/Session/ClientCapabilities.cs b/MediaBrowser.Model/Session/ClientCapabilities.cs
index 222c1bd64..9ae1fae9f 100644
--- a/MediaBrowser.Model/Session/ClientCapabilities.cs
+++ b/MediaBrowser.Model/Session/ClientCapabilities.cs
@@ -5,9 +5,9 @@ namespace MediaBrowser.Model.Session
{
public class ClientCapabilities
{
- public List<string> PlayableMediaTypes { get; set; }
+ public string[] PlayableMediaTypes { get; set; }
- public List<string> SupportedCommands { get; set; }
+ public string[] SupportedCommands { get; set; }
public bool SupportsMediaControl { get; set; }
public bool SupportsContentUploading { get; set; }
@@ -17,17 +17,17 @@ namespace MediaBrowser.Model.Session
public bool SupportsSync { get; set; }
public DeviceProfile DeviceProfile { get; set; }
- public List<string> SupportedLiveMediaTypes { get; set; }
+ public string[] SupportedLiveMediaTypes { get; set; }
public string AppStoreUrl { get; set; }
public string IconUrl { get; set; }
public ClientCapabilities()
{
- PlayableMediaTypes = new List<string>();
- SupportedCommands = new List<string>();
+ PlayableMediaTypes = new string[] { };
+ SupportedCommands = new string[] { };
SupportsPersistentIdentifier = true;
- SupportedLiveMediaTypes = new List<string>();
+ SupportedLiveMediaTypes = new string[] { };
}
}
} \ No newline at end of file
diff --git a/MediaBrowser.Model/Session/PlaybackProgressInfo.cs b/MediaBrowser.Model/Session/PlaybackProgressInfo.cs
index 5f81f7269..0319f6711 100644
--- a/MediaBrowser.Model/Session/PlaybackProgressInfo.cs
+++ b/MediaBrowser.Model/Session/PlaybackProgressInfo.cs
@@ -67,7 +67,7 @@ namespace MediaBrowser.Model.Session
/// <value>The position ticks.</value>
public long? PositionTicks { get; set; }
- public long? playbackStartTimeTicks { get; set; }
+ public long? PlaybackStartTimeTicks { get; set; }
/// <summary>
/// Gets or sets the volume level.
diff --git a/MediaBrowser.Model/Session/SessionInfoDto.cs b/MediaBrowser.Model/Session/SessionInfoDto.cs
index 3081d7ee3..78ee72f61 100644
--- a/MediaBrowser.Model/Session/SessionInfoDto.cs
+++ b/MediaBrowser.Model/Session/SessionInfoDto.cs
@@ -12,13 +12,13 @@ namespace MediaBrowser.Model.Session
/// Gets or sets the supported commands.
/// </summary>
/// <value>The supported commands.</value>
- public List<string> SupportedCommands { get; set; }
+ public string[] SupportedCommands { get; set; }
/// <summary>
/// Gets or sets the playable media types.
/// </summary>
/// <value>The playable media types.</value>
- public List<string> PlayableMediaTypes { get; set; }
+ public string[] PlayableMediaTypes { get; set; }
/// <summary>
/// Gets or sets the id.
@@ -50,7 +50,7 @@ namespace MediaBrowser.Model.Session
/// Gets or sets the additional users present.
/// </summary>
/// <value>The additional users present.</value>
- public List<SessionUserInfo> AdditionalUsers { get; set; }
+ public SessionUserInfo[] AdditionalUsers { get; set; }
/// <summary>
/// Gets or sets the application version.
@@ -112,10 +112,10 @@ namespace MediaBrowser.Model.Session
public SessionInfoDto()
{
- AdditionalUsers = new List<SessionUserInfo>();
+ AdditionalUsers = new SessionUserInfo[] { };
- PlayableMediaTypes = new List<string>();
- SupportedCommands = new List<string>();
+ PlayableMediaTypes = new string[] { };
+ SupportedCommands = new string[] { };
}
}
}
diff --git a/MediaBrowser.Model/Session/TranscodingInfo.cs b/MediaBrowser.Model/Session/TranscodingInfo.cs
index f58e605b2..70c299bc2 100644
--- a/MediaBrowser.Model/Session/TranscodingInfo.cs
+++ b/MediaBrowser.Model/Session/TranscodingInfo.cs
@@ -18,11 +18,11 @@ namespace MediaBrowser.Model.Session
public int? Height { get; set; }
public int? AudioChannels { get; set; }
- public List<TranscodeReason> TranscodeReasons { get; set; }
+ public TranscodeReason[] TranscodeReasons { get; set; }
public TranscodingInfo()
{
- TranscodeReasons = new List<TranscodeReason>();
+ TranscodeReasons = new TranscodeReason[] { };
}
}
diff --git a/MediaBrowser.Model/Session/UserDataChangeInfo.cs b/MediaBrowser.Model/Session/UserDataChangeInfo.cs
index f92f44586..c6b03200d 100644
--- a/MediaBrowser.Model/Session/UserDataChangeInfo.cs
+++ b/MediaBrowser.Model/Session/UserDataChangeInfo.cs
@@ -18,6 +18,6 @@ namespace MediaBrowser.Model.Session
/// Gets or sets the user data list.
/// </summary>
/// <value>The user data list.</value>
- public List<UserItemDataDto> UserDataList { get; set; }
+ public UserItemDataDto[] UserDataList { get; set; }
}
}
diff --git a/MediaBrowser.Model/Social/ISharingManager.cs b/MediaBrowser.Model/Social/ISharingManager.cs
index 94c22baba..28c8c7db2 100644
--- a/MediaBrowser.Model/Social/ISharingManager.cs
+++ b/MediaBrowser.Model/Social/ISharingManager.cs
@@ -22,6 +22,6 @@ namespace MediaBrowser.Model.Social
/// </summary>
/// <param name="id">The identifier.</param>
/// <returns>Task.</returns>
- Task DeleteShare(string id);
+ void DeleteShare(string id);
}
}
diff --git a/MediaBrowser.Model/Social/ISharingRepository.cs b/MediaBrowser.Model/Social/ISharingRepository.cs
index 069b6e1fe..dd88ddd04 100644
--- a/MediaBrowser.Model/Social/ISharingRepository.cs
+++ b/MediaBrowser.Model/Social/ISharingRepository.cs
@@ -1,15 +1,10 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
+
namespace MediaBrowser.Model.Social
{
public interface ISharingRepository
{
- Task CreateShare(SocialShareInfo info);
- Task DeleteShare(string id);
+ void CreateShare(SocialShareInfo info);
+ void DeleteShare(string id);
SocialShareInfo GetShareInfo(string id);
}
}
diff --git a/MediaBrowser.Model/Sync/CompleteSyncJobInfo.cs b/MediaBrowser.Model/Sync/CompleteSyncJobInfo.cs
index 52d3fab3c..adfb84b05 100644
--- a/MediaBrowser.Model/Sync/CompleteSyncJobInfo.cs
+++ b/MediaBrowser.Model/Sync/CompleteSyncJobInfo.cs
@@ -5,11 +5,11 @@ namespace MediaBrowser.Model.Sync
public class CompleteSyncJobInfo
{
public SyncJob Job { get; set; }
- public List<SyncJobItem> JobItems { get; set; }
+ public SyncJobItem[] JobItems { get; set; }
public CompleteSyncJobInfo()
{
- JobItems = new List<SyncJobItem>();
+ JobItems = new SyncJobItem[] { };
}
}
}
diff --git a/MediaBrowser.Model/Sync/LocalItem.cs b/MediaBrowser.Model/Sync/LocalItem.cs
index c5728ac97..3d625aa99 100644
--- a/MediaBrowser.Model/Sync/LocalItem.cs
+++ b/MediaBrowser.Model/Sync/LocalItem.cs
@@ -44,17 +44,17 @@ namespace MediaBrowser.Model.Sync
/// Gets or sets the user ids with access.
/// </summary>
/// <value>The user ids with access.</value>
- public List<string> UserIdsWithAccess { get; set; }
+ public string[] UserIdsWithAccess { get; set; }
/// <summary>
/// Gets or sets the additional files.
/// </summary>
/// <value>The additional files.</value>
- public List<string> AdditionalFiles { get; set; }
+ public string[] AdditionalFiles { get; set; }
public LocalItem()
{
- AdditionalFiles = new List<string>();
- UserIdsWithAccess = new List<string>();
+ AdditionalFiles = new string[] { };
+ UserIdsWithAccess = new string[] { };
}
}
}
diff --git a/MediaBrowser.Model/Sync/SyncDataRequest.cs b/MediaBrowser.Model/Sync/SyncDataRequest.cs
index 0df4de86d..79d1842e1 100644
--- a/MediaBrowser.Model/Sync/SyncDataRequest.cs
+++ b/MediaBrowser.Model/Sync/SyncDataRequest.cs
@@ -1,19 +1,16 @@
-using System.Collections.Generic;
-
+
namespace MediaBrowser.Model.Sync
{
public class SyncDataRequest
{
- public List<string> LocalItemIds { get; set; }
- public List<string> OfflineUserIds { get; set; }
- public List<string> SyncJobItemIds { get; set; }
+ public string[] LocalItemIds { get; set; }
+ public string[] SyncJobItemIds { get; set; }
public string TargetId { get; set; }
public SyncDataRequest()
{
- LocalItemIds = new List<string>();
- OfflineUserIds = new List<string>();
+ LocalItemIds = new string[] { };
}
}
}
diff --git a/MediaBrowser.Model/Sync/SyncDataResponse.cs b/MediaBrowser.Model/Sync/SyncDataResponse.cs
index 3799e9455..0b017af6e 100644
--- a/MediaBrowser.Model/Sync/SyncDataResponse.cs
+++ b/MediaBrowser.Model/Sync/SyncDataResponse.cs
@@ -1,16 +1,13 @@
-using System.Collections.Generic;
-
+
namespace MediaBrowser.Model.Sync
{
public class SyncDataResponse
{
- public List<string> ItemIdsToRemove { get; set; }
- public Dictionary<string, List<string>> ItemUserAccess { get; set; }
+ public string[] ItemIdsToRemove { get; set; }
public SyncDataResponse()
{
- ItemIdsToRemove = new List<string>();
- ItemUserAccess = new Dictionary<string, List<string>>();
+ ItemIdsToRemove = new string[] { };
}
}
}
diff --git a/MediaBrowser.Model/Sync/SyncDialogOptions.cs b/MediaBrowser.Model/Sync/SyncDialogOptions.cs
index a987a6cd6..e55ca4f08 100644
--- a/MediaBrowser.Model/Sync/SyncDialogOptions.cs
+++ b/MediaBrowser.Model/Sync/SyncDialogOptions.cs
@@ -8,29 +8,29 @@ namespace MediaBrowser.Model.Sync
/// Gets or sets the targets.
/// </summary>
/// <value>The targets.</value>
- public List<SyncTarget> Targets { get; set; }
+ public SyncTarget[] Targets { get; set; }
/// <summary>
/// Gets or sets the options.
/// </summary>
/// <value>The options.</value>
- public List<SyncJobOption> Options { get; set; }
+ public SyncJobOption[] Options { get; set; }
/// <summary>
/// Gets or sets the quality options.
/// </summary>
/// <value>The quality options.</value>
- public List<SyncQualityOption> QualityOptions { get; set; }
+ public SyncQualityOption[] QualityOptions { get; set; }
/// <summary>
/// Gets or sets the profile options.
/// </summary>
/// <value>The profile options.</value>
- public List<SyncProfileOption> ProfileOptions { get; set; }
+ public SyncProfileOption[] ProfileOptions { get; set; }
public SyncDialogOptions()
{
- Targets = new List<SyncTarget>();
- Options = new List<SyncJobOption>();
- QualityOptions = new List<SyncQualityOption>();
- ProfileOptions = new List<SyncProfileOption>();
+ Targets = new SyncTarget[] { };
+ Options = new SyncJobOption[] { };
+ QualityOptions = new SyncQualityOption[] { };
+ ProfileOptions = new SyncProfileOption[] { };
}
}
}
diff --git a/MediaBrowser.Model/Sync/SyncJob.cs b/MediaBrowser.Model/Sync/SyncJob.cs
index f0e262c50..e8b698f62 100644
--- a/MediaBrowser.Model/Sync/SyncJob.cs
+++ b/MediaBrowser.Model/Sync/SyncJob.cs
@@ -84,7 +84,7 @@ namespace MediaBrowser.Model.Sync
/// Gets or sets the requested item ids.
/// </summary>
/// <value>The requested item ids.</value>
- public List<string> RequestedItemIds { get; set; }
+ public string[] RequestedItemIds { get; set; }
/// <summary>
/// Gets or sets the date created.
/// </summary>
@@ -105,12 +105,9 @@ namespace MediaBrowser.Model.Sync
public string PrimaryImageItemId { get; set; }
public string PrimaryImageTag { get; set; }
- public bool EnableAutomaticResync { get; set; }
-
public SyncJob()
{
- RequestedItemIds = new List<string>();
- EnableAutomaticResync = true;
+ RequestedItemIds = new string[] { };
}
}
}
diff --git a/MediaBrowser.Model/Sync/SyncJobCreationResult.cs b/MediaBrowser.Model/Sync/SyncJobCreationResult.cs
index 6723aa2cf..ee46bc155 100644
--- a/MediaBrowser.Model/Sync/SyncJobCreationResult.cs
+++ b/MediaBrowser.Model/Sync/SyncJobCreationResult.cs
@@ -5,11 +5,11 @@ namespace MediaBrowser.Model.Sync
public class SyncJobCreationResult
{
public SyncJob Job { get; set; }
- public List<SyncJobItem> JobItems { get; set; }
+ public SyncJobItem[] JobItems { get; set; }
public SyncJobCreationResult()
{
- JobItems = new List<SyncJobItem>();
+ JobItems = new SyncJobItem[] { };
}
}
}
diff --git a/MediaBrowser.Model/Sync/SyncJobItem.cs b/MediaBrowser.Model/Sync/SyncJobItem.cs
index 1c72ccd52..5a97bc92e 100644
--- a/MediaBrowser.Model/Sync/SyncJobItem.cs
+++ b/MediaBrowser.Model/Sync/SyncJobItem.cs
@@ -90,12 +90,7 @@ namespace MediaBrowser.Model.Sync
/// Gets or sets the additional files.
/// </summary>
/// <value>The additional files.</value>
- public List<ItemFileInfo> AdditionalFiles { get; set; }
- /// <summary>
- /// Gets or sets a value indicating whether this instance is marked for removal.
- /// </summary>
- /// <value><c>true</c> if this instance is marked for removal; otherwise, <c>false</c>.</value>
- public bool IsMarkedForRemoval { get; set; }
+ public ItemFileInfo[] AdditionalFiles { get; set; }
/// <summary>
/// Gets or sets the index of the job item.
/// </summary>
@@ -106,7 +101,7 @@ namespace MediaBrowser.Model.Sync
public SyncJobItem()
{
- AdditionalFiles = new List<ItemFileInfo>();
+ AdditionalFiles = new ItemFileInfo[] { };
}
}
}
diff --git a/MediaBrowser.Model/Sync/SyncJobItemStatus.cs b/MediaBrowser.Model/Sync/SyncJobItemStatus.cs
index c4e23c63c..2a968869f 100644
--- a/MediaBrowser.Model/Sync/SyncJobItemStatus.cs
+++ b/MediaBrowser.Model/Sync/SyncJobItemStatus.cs
@@ -8,8 +8,6 @@ namespace MediaBrowser.Model.Sync
ReadyToTransfer = 2,
Transferring = 3,
Synced = 4,
- RemovedFromDevice = 5,
- Failed = 6,
- Cancelled = 7
+ Failed = 5
}
}
diff --git a/MediaBrowser.Model/Sync/SyncJobRequest.cs b/MediaBrowser.Model/Sync/SyncJobRequest.cs
index a96c86ed9..3dc863b75 100644
--- a/MediaBrowser.Model/Sync/SyncJobRequest.cs
+++ b/MediaBrowser.Model/Sync/SyncJobRequest.cs
@@ -13,7 +13,7 @@ namespace MediaBrowser.Model.Sync
/// Gets or sets the item ids.
/// </summary>
/// <value>The item ids.</value>
- public List<string> ItemIds { get; set; }
+ public string[] ItemIds { get; set; }
/// <summary>
/// Gets or sets the category.
/// </summary>
@@ -67,7 +67,7 @@ namespace MediaBrowser.Model.Sync
public SyncJobRequest()
{
- ItemIds = new List<string>();
+ ItemIds = new string[] { };
SyncNewContent = true;
}
}
diff --git a/MediaBrowser.Model/Sync/SyncJobStatus.cs b/MediaBrowser.Model/Sync/SyncJobStatus.cs
index ac211a32a..2d1d30802 100644
--- a/MediaBrowser.Model/Sync/SyncJobStatus.cs
+++ b/MediaBrowser.Model/Sync/SyncJobStatus.cs
@@ -9,7 +9,6 @@ namespace MediaBrowser.Model.Sync
Transferring = 3,
Completed = 4,
CompletedWithError = 5,
- Failed = 6,
- Cancelled = 7
+ Failed = 6
}
}
diff --git a/MediaBrowser.Model/Sync/SyncedItem.cs b/MediaBrowser.Model/Sync/SyncedItem.cs
index 4dedcfd2d..68bd8a2eb 100644
--- a/MediaBrowser.Model/Sync/SyncedItem.cs
+++ b/MediaBrowser.Model/Sync/SyncedItem.cs
@@ -50,11 +50,11 @@ namespace MediaBrowser.Model.Sync
/// Gets or sets the additional files.
/// </summary>
/// <value>The additional files.</value>
- public List<ItemFileInfo> AdditionalFiles { get; set; }
+ public ItemFileInfo[] AdditionalFiles { get; set; }
public SyncedItem()
{
- AdditionalFiles = new List<ItemFileInfo>();
+ AdditionalFiles = new ItemFileInfo[] { };
}
}
}
diff --git a/MediaBrowser.Model/System/SystemInfo.cs b/MediaBrowser.Model/System/SystemInfo.cs
index 4154093cb..fce9dea4f 100644
--- a/MediaBrowser.Model/System/SystemInfo.cs
+++ b/MediaBrowser.Model/System/SystemInfo.cs
@@ -46,7 +46,7 @@ namespace MediaBrowser.Model.System
/// Gets or sets the in progress installations.
/// </summary>
/// <value>The in progress installations.</value>
- public List<InstallationInfo> InProgressInstallations { get; set; }
+ public InstallationInfo[] InProgressInstallations { get; set; }
/// <summary>
/// Gets or sets the web socket port number.
@@ -58,7 +58,7 @@ namespace MediaBrowser.Model.System
/// Gets or sets the completed installations.
/// </summary>
/// <value>The completed installations.</value>
- public List<InstallationInfo> CompletedInstallations { get; set; }
+ public InstallationInfo[] CompletedInstallations { get; set; }
/// <summary>
/// Gets or sets a value indicating whether this instance can self restart.
@@ -76,7 +76,7 @@ namespace MediaBrowser.Model.System
/// Gets or sets plugin assemblies that failed to load.
/// </summary>
/// <value>The failed assembly loads.</value>
- public List<string> FailedPluginAssemblies { get; set; }
+ public string[] FailedPluginAssemblies { get; set; }
/// <summary>
/// Gets or sets the program data path.
@@ -153,11 +153,11 @@ namespace MediaBrowser.Model.System
/// </summary>
public SystemInfo()
{
- InProgressInstallations = new List<InstallationInfo>();
+ InProgressInstallations = new InstallationInfo[] { };
- CompletedInstallations = new List<InstallationInfo>();
+ CompletedInstallations = new InstallationInfo[] { };
- FailedPluginAssemblies = new List<string>();
+ FailedPluginAssemblies = new string[] { };
}
}
}
diff --git a/MediaBrowser.Model/Tasks/ScheduledTaskHelpers.cs b/MediaBrowser.Model/Tasks/ScheduledTaskHelpers.cs
index 66f5294e7..2dec79e93 100644
--- a/MediaBrowser.Model/Tasks/ScheduledTaskHelpers.cs
+++ b/MediaBrowser.Model/Tasks/ScheduledTaskHelpers.cs
@@ -1,6 +1,4 @@
-using System;
-using System.Linq;
-
+
namespace MediaBrowser.Model.Tasks
{
/// <summary>
@@ -26,12 +24,6 @@ namespace MediaBrowser.Model.Tasks
string key = task.ScheduledTask.Key;
- var triggers = task.Triggers
- .OrderBy(i => i.Type)
- .ThenBy(i => i.DayOfWeek ?? DayOfWeek.Sunday)
- .ThenBy(i => i.TimeOfDayTicks ?? 0)
- .ToList();
-
return new TaskInfo
{
Name = task.Name,
@@ -40,7 +32,7 @@ namespace MediaBrowser.Model.Tasks
Id = task.Id,
LastExecutionResult = task.LastExecutionResult,
- Triggers = triggers,
+ Triggers = task.Triggers,
Description = task.Description,
Category = task.Category,
diff --git a/MediaBrowser.Model/Tasks/TaskInfo.cs b/MediaBrowser.Model/Tasks/TaskInfo.cs
index 50276f8eb..8792ce952 100644
--- a/MediaBrowser.Model/Tasks/TaskInfo.cs
+++ b/MediaBrowser.Model/Tasks/TaskInfo.cs
@@ -41,7 +41,7 @@ namespace MediaBrowser.Model.Tasks
/// Gets or sets the triggers.
/// </summary>
/// <value>The triggers.</value>
- public List<TaskTriggerInfo> Triggers { get; set; }
+ public TaskTriggerInfo[] Triggers { get; set; }
/// <summary>
/// Gets or sets the description.
@@ -72,7 +72,7 @@ namespace MediaBrowser.Model.Tasks
/// </summary>
public TaskInfo()
{
- Triggers = new List<TaskTriggerInfo>();
+ Triggers = new TaskTriggerInfo[]{};
}
}
}
diff --git a/MediaBrowser.Model/Text/ITextEncoding.cs b/MediaBrowser.Model/Text/ITextEncoding.cs
index 96dca0c04..619d90a2b 100644
--- a/MediaBrowser.Model/Text/ITextEncoding.cs
+++ b/MediaBrowser.Model/Text/ITextEncoding.cs
@@ -7,8 +7,8 @@ namespace MediaBrowser.Model.Text
{
Encoding GetASCIIEncoding();
- string GetDetectedEncodingName(byte[] bytes, string language, bool enableLanguageDetection);
- Encoding GetDetectedEncoding(byte[] bytes, string language, bool enableLanguageDetection);
+ string GetDetectedEncodingName(byte[] bytes, int size, string language, bool enableLanguageDetection);
+ Encoding GetDetectedEncoding(byte[] bytes, int size, string language, bool enableLanguageDetection);
Encoding GetEncodingFromCharset(string charset);
}
}
diff --git a/MediaBrowser.Model/Updates/PackageInfo.cs b/MediaBrowser.Model/Updates/PackageInfo.cs
index 208d5b784..e46d59fc0 100644
--- a/MediaBrowser.Model/Updates/PackageInfo.cs
+++ b/MediaBrowser.Model/Updates/PackageInfo.cs
@@ -151,7 +151,7 @@ namespace MediaBrowser.Model.Updates
/// Gets or sets the versions.
/// </summary>
/// <value>The versions.</value>
- public List<PackageVersionInfo> versions { get; set; }
+ public PackageVersionInfo[] versions { get; set; }
/// <summary>
/// Gets or sets a value indicating whether [enable in application store].
@@ -170,7 +170,7 @@ namespace MediaBrowser.Model.Updates
/// </summary>
public PackageInfo()
{
- versions = new List<PackageVersionInfo>();
+ versions = new PackageVersionInfo[] { };
}
}
}
diff --git a/MediaBrowser.Model/Updates/PackageVersionInfo.cs b/MediaBrowser.Model/Updates/PackageVersionInfo.cs
index 5e0631b3b..3ac518187 100644
--- a/MediaBrowser.Model/Updates/PackageVersionInfo.cs
+++ b/MediaBrowser.Model/Updates/PackageVersionInfo.cs
@@ -89,5 +89,7 @@ namespace MediaBrowser.Model.Updates
public string targetFilename { get; set; }
public string infoUrl { get; set; }
+
+ public string runtimes { get; set; }
}
} \ No newline at end of file
diff --git a/MediaBrowser.Model/Users/UserPolicy.cs b/MediaBrowser.Model/Users/UserPolicy.cs
index e2a75c56b..84ee5d637 100644
--- a/MediaBrowser.Model/Users/UserPolicy.cs
+++ b/MediaBrowser.Model/Users/UserPolicy.cs
@@ -68,6 +68,8 @@ namespace MediaBrowser.Model.Users
public string[] BlockedMediaFolders { get; set; }
public string[] BlockedChannels { get; set; }
+ public int RemoteClientBitrateLimit { get; set; }
+
public UserPolicy()
{
EnableContentDeletion = true;
diff --git a/MediaBrowser.Providers/Books/AudioBookMetadataService.cs b/MediaBrowser.Providers/Books/AudioBookMetadataService.cs
index 7cce85105..834ec6cd3 100644
--- a/MediaBrowser.Providers/Books/AudioBookMetadataService.cs
+++ b/MediaBrowser.Providers/Books/AudioBookMetadataService.cs
@@ -16,16 +16,16 @@ namespace MediaBrowser.Providers.Books
{
public class AudioBookMetadataService : MetadataService<AudioBook, SongInfo>
{
- protected override void MergeData(MetadataResult<AudioBook> source, MetadataResult<AudioBook> target, List<MetadataFields> lockedFields, bool replaceData, bool mergeMetadataSettings)
+ protected override void MergeData(MetadataResult<AudioBook> source, MetadataResult<AudioBook> target, MetadataFields[] lockedFields, bool replaceData, bool mergeMetadataSettings)
{
ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
var sourceItem = source.Item;
var targetItem = target.Item;
- if (replaceData || targetItem.Artists.Count == 0)
+ if (replaceData || targetItem.Artists.Length == 0)
{
- targetItem.Artists = sourceItem.Artists.ToList();
+ targetItem.Artists = sourceItem.Artists;
}
if (replaceData || string.IsNullOrEmpty(targetItem.Album))
diff --git a/MediaBrowser.Providers/Books/AudioPodcastMetadataService.cs b/MediaBrowser.Providers/Books/AudioPodcastMetadataService.cs
index 219f95799..09546e4b6 100644
--- a/MediaBrowser.Providers/Books/AudioPodcastMetadataService.cs
+++ b/MediaBrowser.Providers/Books/AudioPodcastMetadataService.cs
@@ -16,16 +16,16 @@ namespace MediaBrowser.Providers.Books
{
public class AudioPodcastMetadataService : MetadataService<AudioPodcast, SongInfo>
{
- protected override void MergeData(MetadataResult<AudioPodcast> source, MetadataResult<AudioPodcast> target, List<MetadataFields> lockedFields, bool replaceData, bool mergeMetadataSettings)
+ protected override void MergeData(MetadataResult<AudioPodcast> source, MetadataResult<AudioPodcast> target, MetadataFields[] lockedFields, bool replaceData, bool mergeMetadataSettings)
{
ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
var sourceItem = source.Item;
var targetItem = target.Item;
- if (replaceData || targetItem.Artists.Count == 0)
+ if (replaceData || targetItem.Artists.Length == 0)
{
- targetItem.Artists = sourceItem.Artists.ToList();
+ targetItem.Artists = sourceItem.Artists;
}
if (replaceData || string.IsNullOrEmpty(targetItem.Album))
diff --git a/MediaBrowser.Providers/Books/BookMetadataService.cs b/MediaBrowser.Providers/Books/BookMetadataService.cs
index ae7e734cc..68b96486a 100644
--- a/MediaBrowser.Providers/Books/BookMetadataService.cs
+++ b/MediaBrowser.Providers/Books/BookMetadataService.cs
@@ -14,7 +14,7 @@ namespace MediaBrowser.Providers.Books
{
public class BookMetadataService : MetadataService<Book, BookInfo>
{
- protected override void MergeData(MetadataResult<Book> source, MetadataResult<Book> target, List<MetadataFields> lockedFields, bool replaceData, bool mergeMetadataSettings)
+ protected override void MergeData(MetadataResult<Book> source, MetadataResult<Book> target, MetadataFields[] lockedFields, bool replaceData, bool mergeMetadataSettings)
{
ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
diff --git a/MediaBrowser.Providers/BoxSets/BoxSetMetadataService.cs b/MediaBrowser.Providers/BoxSets/BoxSetMetadataService.cs
index b391ce4d3..12748a8a7 100644
--- a/MediaBrowser.Providers/BoxSets/BoxSetMetadataService.cs
+++ b/MediaBrowser.Providers/BoxSets/BoxSetMetadataService.cs
@@ -6,12 +6,9 @@ using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Logging;
using MediaBrowser.Providers.Manager;
-using System.Collections.Generic;
using System.Linq;
-using System.Threading.Tasks;
-
-using MediaBrowser.Controller.IO;
using MediaBrowser.Model.IO;
+using MediaBrowser.Model.Extensions;
namespace MediaBrowser.Providers.BoxSets
{
@@ -35,7 +32,7 @@ namespace MediaBrowser.Providers.BoxSets
return updateType;
}
- protected override void MergeData(MetadataResult<BoxSet> source, MetadataResult<BoxSet> target, List<MetadataFields> lockedFields, bool replaceData, bool mergeMetadataSettings)
+ protected override void MergeData(MetadataResult<BoxSet> source, MetadataResult<BoxSet> target, MetadataFields[] lockedFields, bool replaceData, bool mergeMetadataSettings)
{
ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
@@ -44,11 +41,7 @@ namespace MediaBrowser.Providers.BoxSets
if (mergeMetadataSettings)
{
- // Retain shortcut children
- var linkedChildren = sourceItem.LinkedChildren.ToList();
- linkedChildren.AddRange(sourceItem.LinkedChildren.Where(i => i.Type == LinkedChildType.Shortcut));
-
- targetItem.LinkedChildren = linkedChildren;
+ targetItem.LinkedChildren = sourceItem.LinkedChildren;
targetItem.Shares = sourceItem.Shares;
}
}
diff --git a/MediaBrowser.Providers/BoxSets/MovieDbBoxSetImageProvider.cs b/MediaBrowser.Providers/BoxSets/MovieDbBoxSetImageProvider.cs
index 852feab37..7d1f2779b 100644
--- a/MediaBrowser.Providers/BoxSets/MovieDbBoxSetImageProvider.cs
+++ b/MediaBrowser.Providers/BoxSets/MovieDbBoxSetImageProvider.cs
@@ -33,12 +33,12 @@ namespace MediaBrowser.Providers.BoxSets
get { return "TheMovieDb"; }
}
- public bool Supports(IHasImages item)
+ public bool Supports(IHasMetadata item)
{
return item is BoxSet;
}
- public IEnumerable<ImageType> GetSupportedImages(IHasImages item)
+ public IEnumerable<ImageType> GetSupportedImages(IHasMetadata item)
{
return new List<ImageType>
{
@@ -47,7 +47,7 @@ namespace MediaBrowser.Providers.BoxSets
};
}
- public async Task<IEnumerable<RemoteImageInfo>> GetImages(IHasImages item, CancellationToken cancellationToken)
+ public async Task<IEnumerable<RemoteImageInfo>> GetImages(IHasMetadata item, CancellationToken cancellationToken)
{
var tmdbId = item.GetProviderId(MetadataProviders.Tmdb);
@@ -123,8 +123,7 @@ namespace MediaBrowser.Providers.BoxSets
return 0;
})
.ThenByDescending(i => i.CommunityRating ?? 0)
- .ThenByDescending(i => i.VoteCount ?? 0)
- .ToList();
+ .ThenByDescending(i => i.VoteCount ?? 0);
}
/// <summary>
@@ -145,8 +144,7 @@ namespace MediaBrowser.Providers.BoxSets
private IEnumerable<MovieDbBoxSetProvider.Backdrop> GetBackdrops(MovieDbBoxSetProvider.Images images)
{
var eligibleBackdrops = images.backdrops == null ? new List<MovieDbBoxSetProvider.Backdrop>() :
- images.backdrops
- .ToList();
+ images.backdrops;
return eligibleBackdrops.OrderByDescending(i => i.vote_average)
.ThenByDescending(i => i.vote_count);
diff --git a/MediaBrowser.Providers/Channels/ChannelMetadataService.cs b/MediaBrowser.Providers/Channels/ChannelMetadataService.cs
index 8a3da5bf4..b22db559e 100644
--- a/MediaBrowser.Providers/Channels/ChannelMetadataService.cs
+++ b/MediaBrowser.Providers/Channels/ChannelMetadataService.cs
@@ -14,7 +14,7 @@ namespace MediaBrowser.Providers.Channels
{
public class ChannelMetadataService : MetadataService<Channel, ItemLookupInfo>
{
- protected override void MergeData(MetadataResult<Channel> source, MetadataResult<Channel> target, List<MetadataFields> lockedFields, bool replaceData, bool mergeMetadataSettings)
+ protected override void MergeData(MetadataResult<Channel> source, MetadataResult<Channel> target, MetadataFields[] lockedFields, bool replaceData, bool mergeMetadataSettings)
{
ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
}
diff --git a/MediaBrowser.Providers/Chapters/ChapterManager.cs b/MediaBrowser.Providers/Chapters/ChapterManager.cs
index 5fea2c3cd..1bbc6fa4e 100644
--- a/MediaBrowser.Providers/Chapters/ChapterManager.cs
+++ b/MediaBrowser.Providers/Chapters/ChapterManager.cs
@@ -13,7 +13,6 @@ using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Logging;
using System;
using System.Collections.Generic;
-using System.Linq;
using System.Threading;
using System.Threading.Tasks;
@@ -34,14 +33,14 @@ namespace MediaBrowser.Providers.Chapters
_itemRepo = itemRepo;
}
- public IEnumerable<ChapterInfo> GetChapters(string itemId)
+ public List<ChapterInfo> GetChapters(string itemId)
{
return _itemRepo.GetChapters(new Guid(itemId));
}
- public Task SaveChapters(string itemId, List<ChapterInfo> chapters, CancellationToken cancellationToken)
+ public void SaveChapters(string itemId, List<ChapterInfo> chapters)
{
- return _itemRepo.SaveChapters(new Guid(itemId), chapters, cancellationToken);
+ _itemRepo.SaveChapters(new Guid(itemId), chapters);
}
}
}
diff --git a/MediaBrowser.Providers/Folders/CollectionFolderMetadataService.cs b/MediaBrowser.Providers/Folders/CollectionFolderMetadataService.cs
index dc0fda72e..1dab08671 100644
--- a/MediaBrowser.Providers/Folders/CollectionFolderMetadataService.cs
+++ b/MediaBrowser.Providers/Folders/CollectionFolderMetadataService.cs
@@ -15,7 +15,7 @@ namespace MediaBrowser.Providers.Folders
{
public class CollectionFolderMetadataService : MetadataService<CollectionFolder, ItemLookupInfo>
{
- protected override void MergeData(MetadataResult<CollectionFolder> source, MetadataResult<CollectionFolder> target, List<MetadataFields> lockedFields, bool replaceData, bool mergeMetadataSettings)
+ protected override void MergeData(MetadataResult<CollectionFolder> source, MetadataResult<CollectionFolder> target, MetadataFields[] lockedFields, bool replaceData, bool mergeMetadataSettings)
{
ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
}
@@ -27,7 +27,7 @@ namespace MediaBrowser.Providers.Folders
public class ManualCollectionsFolderMetadataService : MetadataService<ManualCollectionsFolder, ItemLookupInfo>
{
- protected override void MergeData(MetadataResult<ManualCollectionsFolder> source, MetadataResult<ManualCollectionsFolder> target, List<MetadataFields> lockedFields, bool replaceData, bool mergeMetadataSettings)
+ protected override void MergeData(MetadataResult<ManualCollectionsFolder> source, MetadataResult<ManualCollectionsFolder> target, MetadataFields[] lockedFields, bool replaceData, bool mergeMetadataSettings)
{
ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
}
diff --git a/MediaBrowser.Providers/Folders/FolderMetadataService.cs b/MediaBrowser.Providers/Folders/FolderMetadataService.cs
index ff8d87e2b..687dac919 100644
--- a/MediaBrowser.Providers/Folders/FolderMetadataService.cs
+++ b/MediaBrowser.Providers/Folders/FolderMetadataService.cs
@@ -23,7 +23,7 @@ namespace MediaBrowser.Providers.Folders
}
}
- protected override void MergeData(MetadataResult<Folder> source, MetadataResult<Folder> target, List<MetadataFields> lockedFields, bool replaceData, bool mergeMetadataSettings)
+ protected override void MergeData(MetadataResult<Folder> source, MetadataResult<Folder> target, MetadataFields[] lockedFields, bool replaceData, bool mergeMetadataSettings)
{
ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
}
diff --git a/MediaBrowser.Providers/Folders/UserViewMetadataService.cs b/MediaBrowser.Providers/Folders/UserViewMetadataService.cs
index 06b62a98b..951794961 100644
--- a/MediaBrowser.Providers/Folders/UserViewMetadataService.cs
+++ b/MediaBrowser.Providers/Folders/UserViewMetadataService.cs
@@ -14,7 +14,7 @@ namespace MediaBrowser.Providers.Folders
{
public class UserViewMetadataService : MetadataService<UserView, ItemLookupInfo>
{
- protected override void MergeData(MetadataResult<UserView> source, MetadataResult<UserView> target, List<MetadataFields> lockedFields, bool replaceData, bool mergeMetadataSettings)
+ protected override void MergeData(MetadataResult<UserView> source, MetadataResult<UserView> target, MetadataFields[] lockedFields, bool replaceData, bool mergeMetadataSettings)
{
ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
}
diff --git a/MediaBrowser.Providers/GameGenres/GameGenreMetadataService.cs b/MediaBrowser.Providers/GameGenres/GameGenreMetadataService.cs
index 13d40b4d9..edde0f5e3 100644
--- a/MediaBrowser.Providers/GameGenres/GameGenreMetadataService.cs
+++ b/MediaBrowser.Providers/GameGenres/GameGenreMetadataService.cs
@@ -14,7 +14,7 @@ namespace MediaBrowser.Providers.GameGenres
{
public class GameGenreMetadataService : MetadataService<GameGenre, ItemLookupInfo>
{
- protected override void MergeData(MetadataResult<GameGenre> source, MetadataResult<GameGenre> target, List<MetadataFields> lockedFields, bool replaceData, bool mergeMetadataSettings)
+ protected override void MergeData(MetadataResult<GameGenre> source, MetadataResult<GameGenre> target, MetadataFields[] lockedFields, bool replaceData, bool mergeMetadataSettings)
{
ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
}
diff --git a/MediaBrowser.Providers/Games/GameMetadataService.cs b/MediaBrowser.Providers/Games/GameMetadataService.cs
index 10f74629f..67becbf58 100644
--- a/MediaBrowser.Providers/Games/GameMetadataService.cs
+++ b/MediaBrowser.Providers/Games/GameMetadataService.cs
@@ -14,7 +14,7 @@ namespace MediaBrowser.Providers.Games
{
public class GameMetadataService : MetadataService<Game, GameInfo>
{
- protected override void MergeData(MetadataResult<Game> source, MetadataResult<Game> target, List<MetadataFields> lockedFields, bool replaceData, bool mergeMetadataSettings)
+ protected override void MergeData(MetadataResult<Game> source, MetadataResult<Game> target, MetadataFields[] lockedFields, bool replaceData, bool mergeMetadataSettings)
{
ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
diff --git a/MediaBrowser.Providers/Games/GameSystemMetadataService.cs b/MediaBrowser.Providers/Games/GameSystemMetadataService.cs
index ca33563fa..474dd2fcf 100644
--- a/MediaBrowser.Providers/Games/GameSystemMetadataService.cs
+++ b/MediaBrowser.Providers/Games/GameSystemMetadataService.cs
@@ -14,7 +14,7 @@ namespace MediaBrowser.Providers.Games
{
public class GameSystemMetadataService : MetadataService<GameSystem, GameSystemInfo>
{
- protected override void MergeData(MetadataResult<GameSystem> source, MetadataResult<GameSystem> target, List<MetadataFields> lockedFields, bool replaceData, bool mergeMetadataSettings)
+ protected override void MergeData(MetadataResult<GameSystem> source, MetadataResult<GameSystem> target, MetadataFields[] lockedFields, bool replaceData, bool mergeMetadataSettings)
{
ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
diff --git a/MediaBrowser.Providers/Genres/GenreMetadataService.cs b/MediaBrowser.Providers/Genres/GenreMetadataService.cs
index a695fb372..88fba1854 100644
--- a/MediaBrowser.Providers/Genres/GenreMetadataService.cs
+++ b/MediaBrowser.Providers/Genres/GenreMetadataService.cs
@@ -14,7 +14,7 @@ namespace MediaBrowser.Providers.Genres
{
public class GenreMetadataService : MetadataService<Genre, ItemLookupInfo>
{
- protected override void MergeData(MetadataResult<Genre> source, MetadataResult<Genre> target, List<MetadataFields> lockedFields, bool replaceData, bool mergeMetadataSettings)
+ protected override void MergeData(MetadataResult<Genre> source, MetadataResult<Genre> target, MetadataFields[] lockedFields, bool replaceData, bool mergeMetadataSettings)
{
ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
}
diff --git a/MediaBrowser.Providers/ImagesByName/ImageUtils.cs b/MediaBrowser.Providers/ImagesByName/ImageUtils.cs
index 499fd2e0b..74c01fb5c 100644
--- a/MediaBrowser.Providers/ImagesByName/ImageUtils.cs
+++ b/MediaBrowser.Providers/ImagesByName/ImageUtils.cs
@@ -53,7 +53,7 @@ namespace MediaBrowser.Providers.ImagesByName
return file;
}
- public static string FindMatch(IHasImages item, IEnumerable<string> images)
+ public static string FindMatch(IHasMetadata item, IEnumerable<string> images)
{
var name = GetComparableName(item.Name);
diff --git a/MediaBrowser.Providers/LiveTv/AudioRecordingService.cs b/MediaBrowser.Providers/LiveTv/AudioRecordingService.cs
index f4749c37d..509c91188 100644
--- a/MediaBrowser.Providers/LiveTv/AudioRecordingService.cs
+++ b/MediaBrowser.Providers/LiveTv/AudioRecordingService.cs
@@ -14,7 +14,7 @@ namespace MediaBrowser.Providers.LiveTv
{
public class AudioRecordingService : MetadataService<LiveTvAudioRecording, ItemLookupInfo>
{
- protected override void MergeData(MetadataResult<LiveTvAudioRecording> source, MetadataResult<LiveTvAudioRecording> target, List<MetadataFields> lockedFields, bool replaceData, bool mergeMetadataSettings)
+ protected override void MergeData(MetadataResult<LiveTvAudioRecording> source, MetadataResult<LiveTvAudioRecording> target, MetadataFields[] lockedFields, bool replaceData, bool mergeMetadataSettings)
{
ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
}
diff --git a/MediaBrowser.Providers/LiveTv/ChannelMetadataService.cs b/MediaBrowser.Providers/LiveTv/ChannelMetadataService.cs
index 8012021ab..31e3ecaf4 100644
--- a/MediaBrowser.Providers/LiveTv/ChannelMetadataService.cs
+++ b/MediaBrowser.Providers/LiveTv/ChannelMetadataService.cs
@@ -14,7 +14,7 @@ namespace MediaBrowser.Providers.LiveTv
{
public class ChannelMetadataService : MetadataService<LiveTvChannel, ItemLookupInfo>
{
- protected override void MergeData(MetadataResult<LiveTvChannel> source, MetadataResult<LiveTvChannel> target, List<MetadataFields> lockedFields, bool replaceData, bool mergeMetadataSettings)
+ protected override void MergeData(MetadataResult<LiveTvChannel> source, MetadataResult<LiveTvChannel> target, MetadataFields[] lockedFields, bool replaceData, bool mergeMetadataSettings)
{
ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
}
diff --git a/MediaBrowser.Providers/LiveTv/ProgramMetadataService.cs b/MediaBrowser.Providers/LiveTv/ProgramMetadataService.cs
index f203aa8c6..28a12540b 100644
--- a/MediaBrowser.Providers/LiveTv/ProgramMetadataService.cs
+++ b/MediaBrowser.Providers/LiveTv/ProgramMetadataService.cs
@@ -14,7 +14,7 @@ namespace MediaBrowser.Providers.LiveTv
{
public class ProgramMetadataService : MetadataService<LiveTvProgram, LiveTvProgramLookupInfo>
{
- protected override void MergeData(MetadataResult<LiveTvProgram> source, MetadataResult<LiveTvProgram> target, List<MetadataFields> lockedFields, bool replaceData, bool mergeMetadataSettings)
+ protected override void MergeData(MetadataResult<LiveTvProgram> source, MetadataResult<LiveTvProgram> target, MetadataFields[] lockedFields, bool replaceData, bool mergeMetadataSettings)
{
ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
}
diff --git a/MediaBrowser.Providers/LiveTv/VideoRecordingService.cs b/MediaBrowser.Providers/LiveTv/VideoRecordingService.cs
index 528e9a5ec..8bfa91655 100644
--- a/MediaBrowser.Providers/LiveTv/VideoRecordingService.cs
+++ b/MediaBrowser.Providers/LiveTv/VideoRecordingService.cs
@@ -14,7 +14,7 @@ namespace MediaBrowser.Providers.LiveTv
{
public class VideoRecordingService : MetadataService<LiveTvVideoRecording, ItemLookupInfo>
{
- protected override void MergeData(MetadataResult<LiveTvVideoRecording> source, MetadataResult<LiveTvVideoRecording> target, List<MetadataFields> lockedFields, bool replaceData, bool mergeMetadataSettings)
+ protected override void MergeData(MetadataResult<LiveTvVideoRecording> source, MetadataResult<LiveTvVideoRecording> target, MetadataFields[] lockedFields, bool replaceData, bool mergeMetadataSettings)
{
ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
}
diff --git a/MediaBrowser.Providers/Manager/GenericPriorityQueue.cs b/MediaBrowser.Providers/Manager/GenericPriorityQueue.cs
index 03bb0f68c..e24547614 100644
--- a/MediaBrowser.Providers/Manager/GenericPriorityQueue.cs
+++ b/MediaBrowser.Providers/Manager/GenericPriorityQueue.cs
@@ -1,7 +1,6 @@
using System;
using System.Collections;
using System.Collections.Generic;
-using System.Linq;
using System.Text;
using System.Threading.Tasks;
diff --git a/MediaBrowser.Providers/Manager/GenericPriorityQueueNode.cs b/MediaBrowser.Providers/Manager/GenericPriorityQueueNode.cs
index e6e93e443..ec908095f 100644
--- a/MediaBrowser.Providers/Manager/GenericPriorityQueueNode.cs
+++ b/MediaBrowser.Providers/Manager/GenericPriorityQueueNode.cs
@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
-using System.Linq;
using System.Text;
using System.Threading.Tasks;
diff --git a/MediaBrowser.Providers/Manager/IFixedSizePriorityQueue.cs b/MediaBrowser.Providers/Manager/IFixedSizePriorityQueue.cs
index 8da88e1c6..a49d42aca 100644
--- a/MediaBrowser.Providers/Manager/IFixedSizePriorityQueue.cs
+++ b/MediaBrowser.Providers/Manager/IFixedSizePriorityQueue.cs
@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
-using System.Linq;
using System.Text;
using System.Threading.Tasks;
diff --git a/MediaBrowser.Providers/Manager/IPriorityQueue.cs b/MediaBrowser.Providers/Manager/IPriorityQueue.cs
index 425992b18..23f08a13e 100644
--- a/MediaBrowser.Providers/Manager/IPriorityQueue.cs
+++ b/MediaBrowser.Providers/Manager/IPriorityQueue.cs
@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
-using System.Linq;
using System.Text;
using System.Threading.Tasks;
diff --git a/MediaBrowser.Providers/Manager/ImageSaver.cs b/MediaBrowser.Providers/Manager/ImageSaver.cs
index dc6c7e43f..7fdbdbcc7 100644
--- a/MediaBrowser.Providers/Manager/ImageSaver.cs
+++ b/MediaBrowser.Providers/Manager/ImageSaver.cs
@@ -17,6 +17,7 @@ using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Model.IO;
+using MediaBrowser.Model.Extensions;
namespace MediaBrowser.Providers.Manager
{
@@ -67,12 +68,12 @@ namespace MediaBrowser.Providers.Manager
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
/// <exception cref="System.ArgumentNullException">mimeType</exception>
- public Task SaveImage(IHasImages item, Stream source, string mimeType, ImageType type, int? imageIndex, CancellationToken cancellationToken)
+ public Task SaveImage(IHasMetadata item, Stream source, string mimeType, ImageType type, int? imageIndex, CancellationToken cancellationToken)
{
return SaveImage(item, source, mimeType, type, imageIndex, null, cancellationToken);
}
- public async Task SaveImage(IHasImages item, Stream source, string mimeType, ImageType type, int? imageIndex, bool? saveLocallyWithMedia, CancellationToken cancellationToken)
+ public async Task SaveImage(IHasMetadata item, Stream source, string mimeType, ImageType type, int? imageIndex, bool? saveLocallyWithMedia, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(mimeType))
{
@@ -274,7 +275,7 @@ namespace MediaBrowser.Providers.Manager
/// <param name="mimeType">Type of the MIME.</param>
/// <param name="saveLocally">if set to <c>true</c> [save locally].</param>
/// <returns>IEnumerable{System.String}.</returns>
- private string[] GetSavePaths(IHasImages item, ImageType type, int? imageIndex, string mimeType, bool saveLocally)
+ private string[] GetSavePaths(IHasMetadata item, ImageType type, int? imageIndex, string mimeType, bool saveLocally)
{
if (!saveLocally || (_config.Configuration.ImageSavingConvention == ImageSavingConvention.Legacy))
{
@@ -296,7 +297,7 @@ namespace MediaBrowser.Providers.Manager
/// or
/// imageIndex
/// </exception>
- private ItemImageInfo GetCurrentImage(IHasImages item, ImageType type, int imageIndex)
+ private ItemImageInfo GetCurrentImage(IHasMetadata item, ImageType type, int imageIndex)
{
return item.GetImageInfo(type, imageIndex);
}
@@ -311,7 +312,7 @@ namespace MediaBrowser.Providers.Manager
/// <exception cref="System.ArgumentNullException">imageIndex
/// or
/// imageIndex</exception>
- private void SetImagePath(IHasImages item, ImageType type, int? imageIndex, string path)
+ private void SetImagePath(IHasMetadata item, ImageType type, int? imageIndex, string path)
{
item.SetImagePath(type, imageIndex ?? 0, _fileSystem.GetFileInfo(path));
}
@@ -330,7 +331,7 @@ namespace MediaBrowser.Providers.Manager
/// or
/// imageIndex
/// </exception>
- private string GetStandardSavePath(IHasImages item, ImageType type, int? imageIndex, string mimeType, bool saveLocally)
+ private string GetStandardSavePath(IHasMetadata item, ImageType type, int? imageIndex, string mimeType, bool saveLocally)
{
var season = item as Season;
var extension = MimeTypes.ToExtension(mimeType);
@@ -355,7 +356,7 @@ namespace MediaBrowser.Providers.Manager
return Path.Combine(seriesFolder, imageFilename);
}
- if (item.DetectIsInMixedFolder())
+ if (item.IsInMixedFolder)
{
return GetSavePathForItemInMixedFolder(item, type, "landscape", extension);
}
@@ -432,7 +433,7 @@ namespace MediaBrowser.Providers.Manager
path = Path.Combine(_fileSystem.GetDirectoryName(item.Path), "metadata", filename + extension);
}
- else if (item.DetectIsInMixedFolder())
+ else if (item.IsInMixedFolder)
{
path = GetSavePathForItemInMixedFolder(item, type, filename, extension);
}
@@ -483,7 +484,7 @@ namespace MediaBrowser.Providers.Manager
/// <param name="mimeType">Type of the MIME.</param>
/// <returns>IEnumerable{System.String}.</returns>
/// <exception cref="System.ArgumentNullException">imageIndex</exception>
- private string[] GetCompatibleSavePaths(IHasImages item, ImageType type, int? imageIndex, string mimeType)
+ private string[] GetCompatibleSavePaths(IHasMetadata item, ImageType type, int? imageIndex, string mimeType)
{
var season = item as Season;
@@ -499,7 +500,7 @@ namespace MediaBrowser.Providers.Manager
if (imageIndex.Value == 0)
{
- if (item.DetectIsInMixedFolder())
+ if (item.IsInMixedFolder)
{
return new[] { GetSavePathForItemInMixedFolder(item, type, "fanart", extension) };
}
@@ -525,7 +526,7 @@ namespace MediaBrowser.Providers.Manager
var outputIndex = imageIndex.Value;
- if (item.DetectIsInMixedFolder())
+ if (item.IsInMixedFolder)
{
return new[] { GetSavePathForItemInMixedFolder(item, type, "fanart" + outputIndex.ToString(UsCulture), extension) };
}
@@ -541,7 +542,7 @@ namespace MediaBrowser.Providers.Manager
{
list.Add(Path.Combine(item.ContainingFolderPath, "extrathumbs", "thumb" + outputIndex.ToString(UsCulture) + extension));
}
- return list.ToArray();
+ return list.ToArray(list.Count);
}
if (type == ImageType.Primary)
@@ -568,7 +569,7 @@ namespace MediaBrowser.Providers.Manager
return new[] { Path.Combine(seasonFolder, imageFilename) };
}
- if (item.DetectIsInMixedFolder() || item is MusicVideo)
+ if (item.IsInMixedFolder || item is MusicVideo)
{
return new[] { GetSavePathForItemInMixedFolder(item, type, string.Empty, extension) };
}
@@ -603,7 +604,7 @@ namespace MediaBrowser.Providers.Manager
/// <param name="imageFilename">The image filename.</param>
/// <param name="extension">The extension.</param>
/// <returns>System.String.</returns>
- private string GetSavePathForItemInMixedFolder(IHasImages item, ImageType type, string imageFilename, string extension)
+ private string GetSavePathForItemInMixedFolder(IHasMetadata item, ImageType type, string imageFilename, string extension)
{
if (type == ImageType.Primary)
{
diff --git a/MediaBrowser.Providers/Manager/ItemImageProvider.cs b/MediaBrowser.Providers/Manager/ItemImageProvider.cs
index 39715a449..e62ce0225 100644
--- a/MediaBrowser.Providers/Manager/ItemImageProvider.cs
+++ b/MediaBrowser.Providers/Manager/ItemImageProvider.cs
@@ -23,6 +23,7 @@ using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.IO;
using MediaBrowser.Controller.LiveTv;
using MediaBrowser.Model.MediaInfo;
+using MediaBrowser.Model.Extensions;
namespace MediaBrowser.Providers.Manager
{
@@ -41,7 +42,7 @@ namespace MediaBrowser.Providers.Manager
_fileSystem = fileSystem;
}
- public bool ValidateImages(IHasImages item, IEnumerable<IImageProvider> providers, IDirectoryService directoryService)
+ public bool ValidateImages(IHasMetadata item, IEnumerable<IImageProvider> providers, IDirectoryService directoryService)
{
var hasChanges = false;
@@ -60,7 +61,7 @@ namespace MediaBrowser.Providers.Manager
return hasChanges;
}
- public async Task<RefreshResult> RefreshImages(IHasImages item, LibraryOptions libraryOptions, IEnumerable<IImageProvider> imageProviders, ImageRefreshOptions refreshOptions, MetadataOptions savedOptions, CancellationToken cancellationToken)
+ public async Task<RefreshResult> RefreshImages(IHasMetadata item, LibraryOptions libraryOptions, List<IImageProvider> providers, ImageRefreshOptions refreshOptions, MetadataOptions savedOptions, CancellationToken cancellationToken)
{
if (refreshOptions.IsReplacingImage(ImageType.Backdrop))
{
@@ -73,8 +74,6 @@ namespace MediaBrowser.Providers.Manager
var result = new RefreshResult { UpdateType = ItemUpdateType.None };
- var providers = imageProviders.ToList();
-
var providerIds = new List<Guid>();
// In order to avoid duplicates, only download these if there are none already
@@ -118,7 +117,7 @@ namespace MediaBrowser.Providers.Manager
/// <param name="result">The result.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
- private async Task RefreshFromProvider(IHasImages item,
+ private async Task RefreshFromProvider(IHasMetadata item,
IDynamicImageProvider provider,
ImageRefreshOptions refreshOptions,
MetadataOptions savedOptions,
@@ -203,7 +202,7 @@ namespace MediaBrowser.Providers.Manager
ImageType.Thumb
};
- private bool HasImage(IHasImages item, ImageType type)
+ private bool HasImage(IHasMetadata item, ImageType type)
{
var image = item.GetImageInfo(type, 0);
@@ -220,7 +219,7 @@ namespace MediaBrowser.Providers.Manager
/// <param name="backdropLimit">The backdrop limit.</param>
/// <param name="screenshotLimit">The screenshot limit.</param>
/// <returns><c>true</c> if the specified item contains images; otherwise, <c>false</c>.</returns>
- private bool ContainsImages(IHasImages item, List<ImageType> images, MetadataOptions savedOptions, int backdropLimit, int screenshotLimit)
+ private bool ContainsImages(IHasMetadata item, List<ImageType> images, MetadataOptions savedOptions, int backdropLimit, int screenshotLimit)
{
if (_singularImages.Any(i => images.Contains(i) && !HasImage(item, i) && savedOptions.GetLimit(i) > 0))
{
@@ -253,7 +252,7 @@ namespace MediaBrowser.Providers.Manager
/// <param name="result">The result.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
- private async Task RefreshFromProvider(IHasImages item, LibraryOptions libraryOptions,
+ private async Task RefreshFromProvider(IHasMetadata item, LibraryOptions libraryOptions,
IRemoteImageProvider provider,
ImageRefreshOptions refreshOptions,
MetadataOptions savedOptions,
@@ -333,7 +332,7 @@ namespace MediaBrowser.Providers.Manager
}
}
- private bool IsEnabled(MetadataOptions options, ImageType type, IHasImages item)
+ private bool IsEnabled(MetadataOptions options, ImageType type, IHasMetadata item)
{
if (type == ImageType.Backdrop)
{
@@ -360,7 +359,7 @@ namespace MediaBrowser.Providers.Manager
return options.IsEnabled(type);
}
- private void ClearImages(IHasImages item, ImageType type)
+ private void ClearImages(IHasMetadata item, ImageType type)
{
var deleted = false;
var deletedImages = new List<ItemImageInfo>();
@@ -384,10 +383,7 @@ namespace MediaBrowser.Providers.Manager
}
}
- foreach (var image in deletedImages)
- {
- item.RemoveImage(image);
- }
+ item.RemoveImages(deletedImages);
if (deleted)
{
@@ -395,7 +391,7 @@ namespace MediaBrowser.Providers.Manager
}
}
- public bool MergeImages(IHasImages item, List<LocalImageInfo> images)
+ public bool MergeImages(IHasMetadata item, List<LocalImageInfo> images)
{
var changed = false;
@@ -453,7 +449,7 @@ namespace MediaBrowser.Providers.Manager
return changed;
}
- private bool UpdateMultiImages(IHasImages item, List<LocalImageInfo> images, ImageType type)
+ private bool UpdateMultiImages(IHasMetadata item, List<LocalImageInfo> images, ImageType type)
{
var changed = false;
@@ -471,7 +467,7 @@ namespace MediaBrowser.Providers.Manager
return changed;
}
- private async Task<bool> DownloadImage(IHasImages item, LibraryOptions libraryOptions,
+ private async Task<bool> DownloadImage(IHasMetadata item, LibraryOptions libraryOptions,
IRemoteImageProvider provider,
RefreshResult result,
IEnumerable<RemoteImageInfo> images,
@@ -517,7 +513,7 @@ namespace MediaBrowser.Providers.Manager
return false;
}
- private bool EnableImageStub(IHasImages item, ImageType type, LibraryOptions libraryOptions)
+ private bool EnableImageStub(IHasMetadata item, ImageType type, LibraryOptions libraryOptions)
{
if (item is LiveTvProgram)
{
@@ -557,14 +553,14 @@ namespace MediaBrowser.Providers.Manager
}
}
- private void SaveImageStub(IHasImages item, ImageType imageType, IEnumerable<string> urls)
+ private void SaveImageStub(IHasMetadata item, ImageType imageType, IEnumerable<string> urls)
{
var newIndex = item.AllowsMultipleImages(imageType) ? item.GetImages(imageType).Count() : 0;
SaveImageStub(item, imageType, urls, newIndex);
}
- private void SaveImageStub(IHasImages item, ImageType imageType, IEnumerable<string> urls, int newIndex)
+ private void SaveImageStub(IHasMetadata item, ImageType imageType, IEnumerable<string> urls, int newIndex)
{
var path = string.Join("|", urls.Take(1).ToArray());
@@ -576,7 +572,7 @@ namespace MediaBrowser.Providers.Manager
}, newIndex);
}
- private async Task DownloadBackdrops(IHasImages item, LibraryOptions libraryOptions, ImageType imageType, int limit, IRemoteImageProvider provider, RefreshResult result, IEnumerable<RemoteImageInfo> images, int minWidth, CancellationToken cancellationToken)
+ private async Task DownloadBackdrops(IHasMetadata item, LibraryOptions libraryOptions, ImageType imageType, int limit, IRemoteImageProvider provider, RefreshResult result, IEnumerable<RemoteImageInfo> images, int minWidth, CancellationToken cancellationToken)
{
foreach (var image in images.Where(i => i.Type == imageType))
{
diff --git a/MediaBrowser.Providers/Manager/MetadataService.cs b/MediaBrowser.Providers/Manager/MetadataService.cs
index edca5e7d6..9a7ced0a5 100644
--- a/MediaBrowser.Providers/Manager/MetadataService.cs
+++ b/MediaBrowser.Providers/Manager/MetadataService.cs
@@ -201,7 +201,7 @@ namespace MediaBrowser.Providers.Manager
{
var baseItem = result.Item as BaseItem;
- await LibraryManager.UpdatePeople(baseItem, result.People.ToList());
+ LibraryManager.UpdatePeople(baseItem, result.People);
await SavePeopleMetadata(result.People, libraryOptions, cancellationToken).ConfigureAwait(false);
}
await result.Item.UpdateToRepository(reason, cancellationToken).ConfigureAwait(false);
@@ -302,13 +302,6 @@ namespace MediaBrowser.Providers.Manager
updateType |= ItemUpdateType.MetadataImport;
}
- var inheritedTags = item.GetInheritedTags();
- if (!inheritedTags.SequenceEqual(item.InheritedTags, StringComparer.Ordinal))
- {
- item.InheritedTags = inheritedTags;
- updateType |= ItemUpdateType.MetadataImport;
- }
-
return updateType;
}
@@ -321,7 +314,7 @@ namespace MediaBrowser.Providers.Manager
var folder = item as Folder;
if (folder != null && folder.SupportsCumulativeRunTimeTicks)
{
- var items = folder.GetRecursiveChildren(i => !i.IsFolder).ToList();
+ var items = folder.GetRecursiveChildren(i => !i.IsFolder);
var ticks = items.Select(i => i.RunTimeTicks ?? 0).Sum();
if (!folder.RunTimeTicks.HasValue || folder.RunTimeTicks.Value != ticks)
@@ -526,7 +519,7 @@ namespace MediaBrowser.Providers.Manager
userDataList.AddRange(localItem.UserDataList);
}
- MergeData(localItem, temp, new List<MetadataFields>(), !options.ReplaceAllMetadata, true);
+ MergeData(localItem, temp, new MetadataFields[] { }, !options.ReplaceAllMetadata, true);
refreshResult.UpdateType = refreshResult.UpdateType | ItemUpdateType.MetadataImport;
// Only one local provider allowed per item
@@ -574,7 +567,7 @@ namespace MediaBrowser.Providers.Manager
else
{
// TODO: If the new metadata from above has some blank data, this can cause old data to get filled into those empty fields
- MergeData(metadata, temp, new List<MetadataFields>(), false, false);
+ MergeData(metadata, temp, new MetadataFields[] { }, false, false);
MergeData(temp, metadata, item.LockedFields, true, false);
}
}
@@ -587,7 +580,7 @@ namespace MediaBrowser.Providers.Manager
await RunCustomProvider(provider, item, logName, options, refreshResult, cancellationToken).ConfigureAwait(false);
}
- await ImportUserData(item, userDataList, cancellationToken).ConfigureAwait(false);
+ ImportUserData(item, userDataList, cancellationToken);
return refreshResult;
}
@@ -602,7 +595,7 @@ namespace MediaBrowser.Providers.Manager
return true;
}
- private async Task ImportUserData(TItemType item, List<UserItemData> userDataList, CancellationToken cancellationToken)
+ private void ImportUserData(TItemType item, List<UserItemData> userDataList, CancellationToken cancellationToken)
{
var hasUserData = item as IHasUserData;
@@ -610,8 +603,7 @@ namespace MediaBrowser.Providers.Manager
{
foreach (var userData in userDataList)
{
- await UserDataManager.SaveUserData(userData.UserId, hasUserData, userData, UserDataSaveReason.Import, cancellationToken)
- .ConfigureAwait(false);
+ UserDataManager.SaveUserData(userData.UserId, hasUserData, userData, UserDataSaveReason.Import, cancellationToken);
}
}
}
@@ -711,7 +703,7 @@ namespace MediaBrowser.Providers.Manager
foreach (var result in results)
{
- MergeData(result, temp, new List<MetadataFields>(), false, false);
+ MergeData(result, temp, new MetadataFields[] { }, false, false);
}
return refreshResult;
@@ -743,7 +735,7 @@ namespace MediaBrowser.Providers.Manager
protected abstract void MergeData(MetadataResult<TItemType> source,
MetadataResult<TItemType> target,
- List<MetadataFields> lockedFields,
+ MetadataFields[] lockedFields,
bool replaceData,
bool mergeMetadataSettings);
diff --git a/MediaBrowser.Providers/Manager/ProviderManager.cs b/MediaBrowser.Providers/Manager/ProviderManager.cs
index ce995fe64..c36d4cf63 100644
--- a/MediaBrowser.Providers/Manager/ProviderManager.cs
+++ b/MediaBrowser.Providers/Manager/ProviderManager.cs
@@ -24,6 +24,7 @@ using MediaBrowser.Controller.Dto;
using MediaBrowser.Model.Events;
using MediaBrowser.Model.Serialization;
using Priority_Queue;
+using MediaBrowser.Model.Extensions;
namespace MediaBrowser.Providers.Manager
{
@@ -128,7 +129,7 @@ namespace MediaBrowser.Providers.Manager
return Task.FromResult(ItemUpdateType.None);
}
- public async Task SaveImage(IHasImages item, string url, ImageType type, int? imageIndex, CancellationToken cancellationToken)
+ public async Task SaveImage(IHasMetadata item, string url, ImageType type, int? imageIndex, CancellationToken cancellationToken)
{
var response = await _httpClient.GetResponse(new HttpRequestOptions
{
@@ -142,12 +143,12 @@ namespace MediaBrowser.Providers.Manager
.ConfigureAwait(false);
}
- public Task SaveImage(IHasImages item, Stream source, string mimeType, ImageType type, int? imageIndex, CancellationToken cancellationToken)
+ public Task SaveImage(IHasMetadata item, Stream source, string mimeType, ImageType type, int? imageIndex, CancellationToken cancellationToken)
{
return new ImageSaver(ConfigurationManager, _libraryMonitor, _fileSystem, _logger, _memoryStreamProvider).SaveImage(item, source, mimeType, type, imageIndex, cancellationToken);
}
- public Task SaveImage(IHasImages item, string source, string mimeType, ImageType type, int? imageIndex, bool? saveLocallyWithMedia, CancellationToken cancellationToken)
+ public Task SaveImage(IHasMetadata item, string source, string mimeType, ImageType type, int? imageIndex, bool? saveLocallyWithMedia, CancellationToken cancellationToken)
{
if (string.IsNullOrWhiteSpace(source))
{
@@ -159,7 +160,7 @@ namespace MediaBrowser.Providers.Manager
return new ImageSaver(ConfigurationManager, _libraryMonitor, _fileSystem, _logger, _memoryStreamProvider).SaveImage(item, fileStream, mimeType, type, imageIndex, saveLocallyWithMedia, cancellationToken);
}
- public async Task<IEnumerable<RemoteImageInfo>> GetAvailableRemoteImages(IHasImages item, RemoteImageQuery query, CancellationToken cancellationToken)
+ public async Task<IEnumerable<RemoteImageInfo>> GetAvailableRemoteImages(IHasMetadata item, RemoteImageQuery query, CancellationToken cancellationToken)
{
var providers = GetRemoteImageProviders(item, query.IncludeDisabledProviders);
@@ -182,9 +183,7 @@ namespace MediaBrowser.Providers.Manager
var results = await Task.WhenAll(tasks).ConfigureAwait(false);
- var images = results.SelectMany(i => i.ToList());
-
- return images;
+ return results.SelectMany(i => i.ToList());
}
/// <summary>
@@ -196,7 +195,7 @@ namespace MediaBrowser.Providers.Manager
/// <param name="preferredLanguages">The preferred languages.</param>
/// <param name="type">The type.</param>
/// <returns>Task{IEnumerable{RemoteImageInfo}}.</returns>
- private async Task<IEnumerable<RemoteImageInfo>> GetImages(IHasImages item, CancellationToken cancellationToken, IRemoteImageProvider provider, List<string> preferredLanguages, ImageType? type = null)
+ private async Task<IEnumerable<RemoteImageInfo>> GetImages(IHasMetadata item, CancellationToken cancellationToken, IRemoteImageProvider provider, List<string> preferredLanguages, ImageType? type = null)
{
try
{
@@ -232,21 +231,21 @@ namespace MediaBrowser.Providers.Manager
/// </summary>
/// <param name="item">The item.</param>
/// <returns>IEnumerable{IImageProvider}.</returns>
- public IEnumerable<ImageProviderInfo> GetRemoteImageProviderInfo(IHasImages item)
+ public IEnumerable<ImageProviderInfo> GetRemoteImageProviderInfo(IHasMetadata item)
{
return GetRemoteImageProviders(item, true).Select(i => new ImageProviderInfo
{
Name = i.Name,
- SupportedImages = i.GetSupportedImages(item).ToList()
+ SupportedImages = i.GetSupportedImages(item).ToArray()
});
}
- public IEnumerable<IImageProvider> GetImageProviders(IHasImages item, ImageRefreshOptions refreshOptions)
+ public IEnumerable<IImageProvider> GetImageProviders(IHasMetadata item, ImageRefreshOptions refreshOptions)
{
return GetImageProviders(item, GetMetadataOptions(item), refreshOptions, false);
}
- private IEnumerable<IImageProvider> GetImageProviders(IHasImages item, MetadataOptions options, ImageRefreshOptions refreshOptions, bool includeDisabled)
+ private IEnumerable<IImageProvider> GetImageProviders(IHasMetadata item, MetadataOptions options, ImageRefreshOptions refreshOptions, bool includeDisabled)
{
// Avoid implicitly captured closure
var currentOptions = options;
@@ -291,7 +290,7 @@ namespace MediaBrowser.Providers.Manager
.ThenBy(GetDefaultOrder);
}
- private IEnumerable<IRemoteImageProvider> GetRemoteImageProviders(IHasImages item, bool includeDisabled)
+ private IEnumerable<IRemoteImageProvider> GetRemoteImageProviders(IHasMetadata item, bool includeDisabled)
{
var options = GetMetadataOptions(item);
@@ -339,7 +338,7 @@ namespace MediaBrowser.Providers.Manager
return true;
}
- private bool CanRefresh(IImageProvider provider, IHasImages item, MetadataOptions options, ImageRefreshOptions refreshOptions, bool includeDisabled)
+ private bool CanRefresh(IImageProvider provider, IHasMetadata item, MetadataOptions options, ImageRefreshOptions refreshOptions, bool includeDisabled)
{
if (!includeDisabled)
{
@@ -437,9 +436,9 @@ namespace MediaBrowser.Providers.Manager
return 0;
}
- public IEnumerable<MetadataPluginSummary> GetAllMetadataPlugins()
+ public MetadataPluginSummary[] GetAllMetadataPlugins()
{
- var list = new List<MetadataPluginSummary>
+ return new MetadataPluginSummary[]
{
GetPluginSummary<Game>(),
GetPluginSummary<GameSystem>(),
@@ -464,8 +463,6 @@ namespace MediaBrowser.Providers.Manager
GetPluginSummary<LiveTvVideoRecording>(),
GetPluginSummary<LiveTvAudioRecording>()
};
-
- return list;
}
private MetadataPluginSummary GetPluginSummary<T>()
@@ -487,8 +484,12 @@ namespace MediaBrowser.Providers.Manager
var imageProviders = GetImageProviders(dummy, options, new ImageRefreshOptions(new DirectoryService(_logger, _fileSystem)), true).ToList();
- AddMetadataPlugins(summary.Plugins, dummy, options);
- AddImagePlugins(summary.Plugins, dummy, imageProviders);
+ var pluginList = summary.Plugins.ToList();
+
+ AddMetadataPlugins(pluginList, dummy, options);
+ AddImagePlugins(pluginList, dummy, imageProviders);
+
+ summary.Plugins = pluginList.ToArray(pluginList.Count);
var supportedImageTypes = imageProviders.OfType<IRemoteImageProvider>()
.SelectMany(i => i.GetSupportedImages(dummy))
@@ -497,7 +498,7 @@ namespace MediaBrowser.Providers.Manager
supportedImageTypes.AddRange(imageProviders.OfType<IDynamicImageProvider>()
.SelectMany(i => i.GetSupportedImages(dummy)));
- summary.SupportedImageTypes = supportedImageTypes.Distinct().ToList();
+ summary.SupportedImageTypes = supportedImageTypes.Distinct().ToArray();
return summary;
}
@@ -530,7 +531,7 @@ namespace MediaBrowser.Providers.Manager
}
private void AddImagePlugins<T>(List<MetadataPlugin> list, T item, List<IImageProvider> imageProviders)
- where T : IHasImages
+ where T : IHasMetadata
{
// Locals
@@ -550,7 +551,7 @@ namespace MediaBrowser.Providers.Manager
}));
}
- public MetadataOptions GetMetadataOptions(IHasImages item)
+ public MetadataOptions GetMetadataOptions(IHasMetadata item)
{
var type = item.GetType().Name;
@@ -1109,6 +1110,7 @@ namespace MediaBrowser.Providers.Manager
{
_disposeCancellationTokenSource.Cancel();
}
+ GC.SuppressFinalize(this);
}
}
} \ No newline at end of file
diff --git a/MediaBrowser.Providers/Manager/ProviderUtils.cs b/MediaBrowser.Providers/Manager/ProviderUtils.cs
index ff266f4c1..41612321b 100644
--- a/MediaBrowser.Providers/Manager/ProviderUtils.cs
+++ b/MediaBrowser.Providers/Manager/ProviderUtils.cs
@@ -13,7 +13,7 @@ namespace MediaBrowser.Providers.Manager
{
public static void MergeBaseItemData<T>(MetadataResult<T> sourceResult,
MetadataResult<T> targetResult,
- List<MetadataFields> lockedFields,
+ MetadataFields[] lockedFields,
bool replaceData,
bool mergeMetadataSettings)
where T : BaseItem
@@ -150,7 +150,7 @@ namespace MediaBrowser.Providers.Manager
if (!lockedFields.Contains(MetadataFields.Studios))
{
- if (replaceData || target.Studios.Count == 0)
+ if (replaceData || target.Studios.Length == 0)
{
target.Studios = source.Studios;
}
@@ -158,7 +158,7 @@ namespace MediaBrowser.Providers.Manager
if (!lockedFields.Contains(MetadataFields.Tags))
{
- if (replaceData || target.Tags.Count == 0)
+ if (replaceData || target.Tags.Length == 0)
{
target.Tags = source.Tags;
}
@@ -166,7 +166,7 @@ namespace MediaBrowser.Providers.Manager
if (!lockedFields.Contains(MetadataFields.ProductionLocations))
{
- if (replaceData || target.ProductionLocations.Count == 0)
+ if (replaceData || target.ProductionLocations.Length == 0)
{
target.ProductionLocations = source.ProductionLocations;
}
@@ -202,18 +202,6 @@ namespace MediaBrowser.Providers.Manager
}
}
- //if (!lockedFields.Contains(MetadataFields.DisplayMediaType))
- {
- if (replaceData || string.IsNullOrEmpty(target.DisplayMediaType))
- {
- // Safeguard against incoming data having an emtpy name
- if (!string.IsNullOrWhiteSpace(source.DisplayMediaType))
- {
- target.DisplayMediaType = source.DisplayMediaType;
- }
- }
- }
-
if (mergeMetadataSettings)
{
MergeMetadataSettings(source, target);
@@ -261,7 +249,7 @@ namespace MediaBrowser.Providers.Manager
target.PreferredMetadataLanguage = source.PreferredMetadataLanguage;
}
- private static void MergeDisplayOrder(BaseItem source, BaseItem target, List<MetadataFields> lockedFields, bool replaceData)
+ private static void MergeDisplayOrder(BaseItem source, BaseItem target, MetadataFields[] lockedFields, bool replaceData)
{
var sourceHasDisplayOrder = source as IHasDisplayOrder;
var targetHasDisplayOrder = target as IHasDisplayOrder;
@@ -272,21 +260,21 @@ namespace MediaBrowser.Providers.Manager
}
}
- private static void MergeAlbumArtist(BaseItem source, BaseItem target, List<MetadataFields> lockedFields, bool replaceData)
+ private static void MergeAlbumArtist(BaseItem source, BaseItem target, MetadataFields[] lockedFields, bool replaceData)
{
var sourceHasAlbumArtist = source as IHasAlbumArtist;
var targetHasAlbumArtist = target as IHasAlbumArtist;
if (sourceHasAlbumArtist != null && targetHasAlbumArtist != null)
{
- if (replaceData || targetHasAlbumArtist.AlbumArtists.Count == 0)
+ if (replaceData || targetHasAlbumArtist.AlbumArtists.Length == 0)
{
targetHasAlbumArtist.AlbumArtists = sourceHasAlbumArtist.AlbumArtists;
}
}
}
- private static void MergeCriticRating(BaseItem source, BaseItem target, List<MetadataFields> lockedFields, bool replaceData)
+ private static void MergeCriticRating(BaseItem source, BaseItem target, MetadataFields[] lockedFields, bool replaceData)
{
if (replaceData || !target.CriticRating.HasValue)
{
@@ -294,21 +282,21 @@ namespace MediaBrowser.Providers.Manager
}
}
- private static void MergeTrailers(BaseItem source, BaseItem target, List<MetadataFields> lockedFields, bool replaceData)
+ private static void MergeTrailers(BaseItem source, BaseItem target, MetadataFields[] lockedFields, bool replaceData)
{
var sourceCast = source as IHasTrailers;
var targetCast = target as IHasTrailers;
if (sourceCast != null && targetCast != null)
{
- if (replaceData || targetCast.RemoteTrailers.Count == 0)
+ if (replaceData || targetCast.RemoteTrailers.Length == 0)
{
targetCast.RemoteTrailers = sourceCast.RemoteTrailers;
}
}
}
- private static void MergeVideoInfo(BaseItem source, BaseItem target, List<MetadataFields> lockedFields, bool replaceData)
+ private static void MergeVideoInfo(BaseItem source, BaseItem target, MetadataFields[] lockedFields, bool replaceData)
{
var sourceCast = source as Video;
var targetCast = target as Video;
diff --git a/MediaBrowser.Providers/Manager/SimplePriorityQueue.cs b/MediaBrowser.Providers/Manager/SimplePriorityQueue.cs
index f4c261a81..879ae1dca 100644
--- a/MediaBrowser.Providers/Manager/SimplePriorityQueue.cs
+++ b/MediaBrowser.Providers/Manager/SimplePriorityQueue.cs
@@ -1,7 +1,6 @@
using System;
using System.Collections;
using System.Collections.Generic;
-using System.Linq;
using System.Text;
using System.Threading.Tasks;
diff --git a/MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs b/MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs
index cc5e7aef9..a4f2053a9 100644
--- a/MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs
+++ b/MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs
@@ -12,6 +12,7 @@ using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Model.IO;
+using MediaBrowser.Model.Extensions;
namespace MediaBrowser.Providers.MediaInfo
{
@@ -31,19 +32,17 @@ namespace MediaBrowser.Providers.MediaInfo
_fileSystem = fileSystem;
}
- public IEnumerable<ImageType> GetSupportedImages(IHasImages item)
+ public IEnumerable<ImageType> GetSupportedImages(IHasMetadata item)
{
return new List<ImageType> { ImageType.Primary };
}
- public Task<DynamicImageResponse> GetImage(IHasImages item, ImageType type, CancellationToken cancellationToken)
+ public Task<DynamicImageResponse> GetImage(IHasMetadata item, ImageType type, CancellationToken cancellationToken)
{
var audio = (Audio)item;
var imageStreams =
- audio.GetMediaSources(false)
- .Take(1)
- .SelectMany(i => i.MediaStreams)
+ audio.GetMediaStreams(MediaStreamType.EmbeddedImage)
.Where(i => i.Type == MediaStreamType.EmbeddedImage)
.ToList();
@@ -94,7 +93,7 @@ namespace MediaBrowser.Providers.MediaInfo
private string GetAudioImagePath(Audio item)
{
var filename = item.Album ?? string.Empty;
- filename += string.Join(",", item.Artists.ToArray());
+ filename += string.Join(",", item.Artists);
if (!string.IsNullOrWhiteSpace(item.Album))
{
@@ -129,7 +128,7 @@ namespace MediaBrowser.Providers.MediaInfo
get { return "Image Extractor"; }
}
- public bool Supports(IHasImages item)
+ public bool Supports(IHasMetadata item)
{
var audio = item as Audio;
diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs b/MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs
index 04e549526..aa6e5ad31 100644
--- a/MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs
+++ b/MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs
@@ -13,6 +13,7 @@ using System.Globalization;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
+using System.Linq;
namespace MediaBrowser.Providers.MediaInfo
{
@@ -42,7 +43,7 @@ namespace MediaBrowser.Providers.MediaInfo
cancellationToken.ThrowIfCancellationRequested();
- await Fetch(item, cancellationToken, result).ConfigureAwait(false);
+ Fetch(item, cancellationToken, result);
return ItemUpdateType.MetadataImport;
}
@@ -91,22 +92,22 @@ namespace MediaBrowser.Providers.MediaInfo
/// <param name="cancellationToken">The cancellation token.</param>
/// <param name="mediaInfo">The media information.</param>
/// <returns>Task.</returns>
- protected async Task Fetch(Audio audio, CancellationToken cancellationToken, Model.MediaInfo.MediaInfo mediaInfo)
+ protected void Fetch(Audio audio, CancellationToken cancellationToken, Model.MediaInfo.MediaInfo mediaInfo)
{
var mediaStreams = mediaInfo.MediaStreams;
- //audio.FormatName = mediaInfo.Container;
+ audio.Container = mediaInfo.Container;
audio.TotalBitrate = mediaInfo.Bitrate;
audio.RunTimeTicks = mediaInfo.RunTimeTicks;
audio.Size = mediaInfo.Size;
- var extension = (Path.GetExtension(audio.Path) ?? string.Empty).TrimStart('.');
- audio.Container = extension;
+ //var extension = (Path.GetExtension(audio.Path) ?? string.Empty).TrimStart('.');
+ //audio.Container = extension;
- await FetchDataFromTags(audio, mediaInfo).ConfigureAwait(false);
+ FetchDataFromTags(audio, mediaInfo);
- await _itemRepo.SaveMediaStreams(audio.Id, mediaStreams, cancellationToken).ConfigureAwait(false);
+ _itemRepo.SaveMediaStreams(audio.Id, mediaStreams, cancellationToken);
}
/// <summary>
@@ -114,7 +115,7 @@ namespace MediaBrowser.Providers.MediaInfo
/// </summary>
/// <param name="audio">The audio.</param>
/// <param name="data">The data.</param>
- private async Task FetchDataFromTags(Audio audio, Model.MediaInfo.MediaInfo data)
+ private void FetchDataFromTags(Audio audio, Model.MediaInfo.MediaInfo data)
{
// Only set Name if title was found in the dictionary
if (!string.IsNullOrEmpty(data.Name))
@@ -136,7 +137,7 @@ namespace MediaBrowser.Providers.MediaInfo
});
}
- await _libraryManager.UpdatePeople(audio, people).ConfigureAwait(false);
+ _libraryManager.UpdatePeople(audio, people);
}
audio.Album = data.Album;
@@ -165,12 +166,7 @@ namespace MediaBrowser.Providers.MediaInfo
if (!audio.LockedFields.Contains(MetadataFields.Studios))
{
- audio.Studios.Clear();
-
- foreach (var studio in data.Studios)
- {
- audio.AddStudio(studio);
- }
+ audio.SetStudios(data.Studios);
}
audio.SetProviderId(MetadataProviders.MusicBrainzAlbumArtist, data.GetProviderId(MetadataProviders.MusicBrainzAlbumArtist));
diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeProvider.cs b/MediaBrowser.Providers/MediaInfo/FFProbeProvider.cs
index 17e48a835..333f3d593 100644
--- a/MediaBrowser.Providers/MediaInfo/FFProbeProvider.cs
+++ b/MediaBrowser.Providers/MediaInfo/FFProbeProvider.cs
@@ -141,11 +141,6 @@ namespace MediaBrowser.Providers.MediaInfo
return _cachedTask;
}
- if (item.VideoType == VideoType.HdDvd)
- {
- return _cachedTask;
- }
-
if (item.IsPlaceHolder)
{
return _cachedTask;
diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs
index eaf3505d1..64a485bc2 100644
--- a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs
+++ b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs
@@ -25,9 +25,6 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
-
-using MediaBrowser.Controller.IO;
-using MediaBrowser.Model.IO;
using MediaBrowser.Model.Globalization;
namespace MediaBrowser.Providers.MediaInfo
@@ -49,8 +46,6 @@ namespace MediaBrowser.Providers.MediaInfo
private readonly IChapterManager _chapterManager;
private readonly ILibraryManager _libraryManager;
- private readonly CultureInfo _usCulture = new CultureInfo("en-US");
-
public FFProbeVideoInfo(ILogger logger, IIsoManager isoManager, IMediaEncoder mediaEncoder, IItemRepository itemRepo, IBlurayExaminer blurayExaminer, ILocalizationManager localization, IApplicationPaths appPaths, IJsonSerializer json, IEncodingManager encodingManager, IFileSystem fileSystem, IServerConfigurationManager config, ISubtitleManager subtitleManager, IChapterManager chapterManager, ILibraryManager libraryManager)
{
_logger = logger;
@@ -80,35 +75,45 @@ namespace MediaBrowser.Providers.MediaInfo
try
{
- if (item.VideoType == VideoType.BluRay || (item.IsoType.HasValue && item.IsoType == IsoType.BluRay))
- {
- var inputPath = isoMount != null ? isoMount.MountedPath : item.Path;
+ string[] streamFileNames = null;
- blurayDiscInfo = GetBDInfo(inputPath);
+ if (item.VideoType == VideoType.Iso)
+ {
+ item.IsoType = DetermineIsoType(isoMount);
}
- OnPreFetch(item, isoMount, blurayDiscInfo);
-
- // If we didn't find any satisfying the min length, just take them all
if (item.VideoType == VideoType.Dvd || (item.IsoType.HasValue && item.IsoType == IsoType.Dvd))
{
- if (item.PlayableStreamFileNames.Count == 0)
+ streamFileNames = FetchFromDvdLib(item, isoMount);
+
+ if (streamFileNames.Length == 0)
{
_logger.Error("No playable vobs found in dvd structure, skipping ffprobe.");
return ItemUpdateType.MetadataImport;
}
}
- if (item.VideoType == VideoType.BluRay || (item.IsoType.HasValue && item.IsoType == IsoType.BluRay))
+ else if (item.VideoType == VideoType.BluRay || (item.IsoType.HasValue && item.IsoType == IsoType.BluRay))
{
- if (item.PlayableStreamFileNames.Count == 0)
+ var inputPath = isoMount != null ? isoMount.MountedPath : item.Path;
+
+ blurayDiscInfo = GetBDInfo(inputPath);
+
+ streamFileNames = blurayDiscInfo.Files;
+
+ if (streamFileNames.Length == 0)
{
_logger.Error("No playable vobs found in bluray structure, skipping ffprobe.");
return ItemUpdateType.MetadataImport;
}
}
- var result = await GetMediaInfo(item, isoMount, cancellationToken).ConfigureAwait(false);
+ if (streamFileNames == null)
+ {
+ streamFileNames = new string[] { };
+ }
+
+ var result = await GetMediaInfo(item, isoMount, streamFileNames, cancellationToken).ConfigureAwait(false);
cancellationToken.ThrowIfCancellationRequested();
@@ -126,10 +131,9 @@ namespace MediaBrowser.Providers.MediaInfo
return ItemUpdateType.MetadataImport;
}
- private const string SchemaVersion = "6";
-
- private async Task<Model.MediaInfo.MediaInfo> GetMediaInfo(Video item,
+ private Task<Model.MediaInfo.MediaInfo> GetMediaInfo(Video item,
IIsoMount isoMount,
+ string[] streamFileNames,
CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
@@ -138,9 +142,9 @@ namespace MediaBrowser.Providers.MediaInfo
? MediaProtocol.Http
: MediaProtocol.File;
- var result = await _mediaEncoder.GetMediaInfo(new MediaInfoRequest
+ return _mediaEncoder.GetMediaInfo(new MediaInfoRequest
{
- PlayableStreamFileNames = item.PlayableStreamFileNames,
+ PlayableStreamFileNames = streamFileNames,
MountedIso = isoMount,
ExtractChapters = true,
VideoType = item.VideoType,
@@ -148,12 +152,7 @@ namespace MediaBrowser.Providers.MediaInfo
InputPath = item.Path,
Protocol = protocol
- }, cancellationToken).ConfigureAwait(false);
-
- //Directory.CreateDirectory(_fileSystem.GetDirectoryName(cachePath));
- //_json.SerializeToFile(result, cachePath);
-
- return result;
+ }, cancellationToken);
}
protected async Task Fetch(Video video,
@@ -187,8 +186,9 @@ namespace MediaBrowser.Providers.MediaInfo
{
video.Container = null;
}
+ video.Container = mediaInfo.Container;
- var chapters = mediaInfo.Chapters ?? new List<ChapterInfo>();
+ var chapters = mediaInfo.Chapters == null ? new List<ChapterInfo>() : mediaInfo.Chapters.ToList();
if (blurayInfo != null)
{
FetchBdInfo(video, chapters, mediaStreams, blurayInfo);
@@ -198,7 +198,7 @@ namespace MediaBrowser.Providers.MediaInfo
var libraryOptions = _libraryManager.GetLibraryOptions(video);
FetchEmbeddedInfo(video, mediaInfo, options, libraryOptions);
- await FetchPeople(video, mediaInfo, options).ConfigureAwait(false);
+ FetchPeople(video, mediaInfo, options);
video.IsHD = mediaStreams.Any(i => i.Type == MediaStreamType.Video && i.Width.HasValue && i.Width.Value >= 1260);
@@ -211,7 +211,7 @@ namespace MediaBrowser.Providers.MediaInfo
video.Video3DFormat = video.Video3DFormat ?? mediaInfo.Video3DFormat;
- await _itemRepo.SaveMediaStreams(video.Id, mediaStreams, cancellationToken).ConfigureAwait(false);
+ _itemRepo.SaveMediaStreams(video.Id, mediaStreams, cancellationToken);
if (options.MetadataRefreshMode == MetadataRefreshMode.FullRefresh ||
options.MetadataRefreshMode == MetadataRefreshMode.Default)
@@ -229,16 +229,9 @@ namespace MediaBrowser.Providers.MediaInfo
extractDuringScan = libraryOptions.ExtractChapterImagesDuringLibraryScan;
}
- await _encodingManager.RefreshChapterImages(new ChapterImageRefreshOptions
- {
- Chapters = chapters,
- Video = video,
- ExtractImages = extractDuringScan,
- SaveChapters = false
-
- }, cancellationToken).ConfigureAwait(false);
+ await _encodingManager.RefreshChapterImages(video, chapters, extractDuringScan, false, cancellationToken).ConfigureAwait(false);
- await _chapterManager.SaveChapters(video.Id.ToString(), chapters, cancellationToken).ConfigureAwait(false);
+ _chapterManager.SaveChapters(video.Id.ToString(), chapters);
}
}
@@ -265,10 +258,10 @@ namespace MediaBrowser.Providers.MediaInfo
{
var video = (Video)item;
- video.PlayableStreamFileNames = blurayInfo.Files.ToList();
+ //video.PlayableStreamFileNames = blurayInfo.Files.ToList();
// Use BD Info if it has multiple m2ts. Otherwise, treat it like a video file and rely more on ffprobe output
- if (blurayInfo.Files.Count > 1)
+ if (blurayInfo.Files.Length > 1)
{
int? currentHeight = null;
int? currentWidth = null;
@@ -371,14 +364,9 @@ namespace MediaBrowser.Providers.MediaInfo
if (!video.IsLocked && !video.LockedFields.Contains(MetadataFields.Studios))
{
- if (video.Studios.Count == 0 || isFullRefresh)
+ if (video.Studios.Length == 0 || isFullRefresh)
{
- video.Studios.Clear();
-
- foreach (var studio in data.Studios)
- {
- video.AddStudio(studio);
- }
+ video.SetStudios(data.Studios);
}
}
@@ -438,7 +426,7 @@ namespace MediaBrowser.Providers.MediaInfo
}
}
- private async Task FetchPeople(Video video, Model.MediaInfo.MediaInfo data, MetadataRefreshOptions options)
+ private void FetchPeople(Video video, Model.MediaInfo.MediaInfo data, MetadataRefreshOptions options)
{
var isFullRefresh = options.MetadataRefreshMode == MetadataRefreshMode.FullRefresh;
@@ -458,7 +446,7 @@ namespace MediaBrowser.Providers.MediaInfo
});
}
- await _libraryManager.UpdatePeople(video, people);
+ _libraryManager.UpdatePeople(video, people);
}
}
}
@@ -513,7 +501,7 @@ namespace MediaBrowser.Providers.MediaInfo
}
}
- video.SubtitleFiles = externalSubtitleStreams.Select(i => i.Path).OrderBy(i => i).ToList();
+ video.SubtitleFiles = externalSubtitleStreams.Select(i => i.Path).OrderBy(i => i).ToArray();
currentStreams.AddRange(externalSubtitleStreams);
}
@@ -558,31 +546,7 @@ namespace MediaBrowser.Providers.MediaInfo
}
}
- /// <summary>
- /// Called when [pre fetch].
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="mount">The mount.</param>
- /// <param name="blurayDiscInfo">The bluray disc information.</param>
- private void OnPreFetch(Video item, IIsoMount mount, BlurayDiscInfo blurayDiscInfo)
- {
- if (item.VideoType == VideoType.Iso)
- {
- item.IsoType = DetermineIsoType(mount);
- }
-
- if (item.VideoType == VideoType.Dvd || (item.IsoType.HasValue && item.IsoType == IsoType.Dvd))
- {
- FetchFromDvdLib(item, mount);
- }
-
- if (blurayDiscInfo != null)
- {
- item.PlayableStreamFileNames = blurayDiscInfo.Files.ToList();
- }
- }
-
- private void FetchFromDvdLib(Video item, IIsoMount mount)
+ private string[] FetchFromDvdLib(Video item, IIsoMount mount)
{
var path = mount == null ? item.Path : mount.MountedPath;
var dvd = new Dvd(path, _fileSystem);
@@ -597,9 +561,9 @@ namespace MediaBrowser.Providers.MediaInfo
item.RunTimeTicks = GetRuntime(primaryTitle);
}
- item.PlayableStreamFileNames = GetPrimaryPlaylistVobFiles(item, mount, titleNumber)
+ return _mediaEncoder.GetPrimaryPlaylistVobFiles(item.Path, mount, titleNumber)
.Select(Path.GetFileName)
- .ToList();
+ .ToArray();
}
private long GetRuntime(Title title)
@@ -647,82 +611,5 @@ namespace MediaBrowser.Providers.MediaInfo
return null;
}
-
- private IEnumerable<string> GetPrimaryPlaylistVobFiles(Video video, IIsoMount isoMount, uint? titleNumber)
- {
- // min size 300 mb
- const long minPlayableSize = 314572800;
-
- var root = isoMount != null ? isoMount.MountedPath : video.Path;
-
- // Try to eliminate menus and intros by skipping all files at the front of the list that are less than the minimum size
- // Once we reach a file that is at least the minimum, return all subsequent ones
- var allVobs = _fileSystem.GetFiles(root, new[] { ".vob" }, false, true)
- .OrderBy(i => i.FullName)
- .ToList();
-
- // If we didn't find any satisfying the min length, just take them all
- if (allVobs.Count == 0)
- {
- _logger.Error("No vobs found in dvd structure.");
- return new List<string>();
- }
-
- if (titleNumber.HasValue)
- {
- var prefix = string.Format("VTS_0{0}_", titleNumber.Value.ToString(_usCulture));
- var vobs = allVobs.Where(i => i.Name.StartsWith(prefix, StringComparison.OrdinalIgnoreCase)).ToList();
-
- if (vobs.Count > 0)
- {
- var minSizeVobs = vobs
- .SkipWhile(f => f.Length < minPlayableSize)
- .ToList();
-
- return minSizeVobs.Count == 0 ? vobs.Select(i => i.FullName) : minSizeVobs.Select(i => i.FullName);
- }
-
- _logger.Info("Could not determine vob file list for {0} using DvdLib. Will scan using file sizes.", video.Path);
- }
-
- var files = allVobs
- .SkipWhile(f => f.Length < minPlayableSize)
- .ToList();
-
- // If we didn't find any satisfying the min length, just take them all
- if (files.Count == 0)
- {
- _logger.Warn("Vob size filter resulted in zero matches. Taking all vobs.");
- files = allVobs;
- }
-
- // Assuming they're named "vts_05_01", take all files whose second part matches that of the first file
- if (files.Count > 0)
- {
- var parts = _fileSystem.GetFileNameWithoutExtension(files[0]).Split('_');
-
- if (parts.Length == 3)
- {
- var title = parts[1];
-
- files = files.TakeWhile(f =>
- {
- var fileParts = _fileSystem.GetFileNameWithoutExtension(f).Split('_');
-
- return fileParts.Length == 3 && string.Equals(title, fileParts[1], StringComparison.OrdinalIgnoreCase);
-
- }).ToList();
-
- // If this resulted in not getting any vobs, just take them all
- if (files.Count == 0)
- {
- _logger.Warn("Vob filename filter resulted in zero matches. Taking all vobs.");
- files = allVobs;
- }
- }
- }
-
- return files.Select(i => i.FullName);
- }
}
} \ No newline at end of file
diff --git a/MediaBrowser.Providers/MediaInfo/SubtitleDownloader.cs b/MediaBrowser.Providers/MediaInfo/SubtitleDownloader.cs
index 483d8827e..79e89a110 100644
--- a/MediaBrowser.Providers/MediaInfo/SubtitleDownloader.cs
+++ b/MediaBrowser.Providers/MediaInfo/SubtitleDownloader.cs
@@ -39,6 +39,11 @@ namespace MediaBrowser.Providers.MediaInfo
return new List<string>();
}
+ if (!video.IsCompleteMedia)
+ {
+ return new List<string>();
+ }
+
VideoContentType mediaType;
if (video is Episode)
diff --git a/MediaBrowser.Providers/MediaInfo/SubtitleResolver.cs b/MediaBrowser.Providers/MediaInfo/SubtitleResolver.cs
index dfa705126..465c417e7 100644
--- a/MediaBrowser.Providers/MediaInfo/SubtitleResolver.cs
+++ b/MediaBrowser.Providers/MediaInfo/SubtitleResolver.cs
@@ -133,7 +133,7 @@ namespace MediaBrowser.Providers.MediaInfo
throw new ArgumentException(string.Format("Cannot search for items that don't have a path: {0} {1}", video.Name, video.Id));
}
- var files = directoryService.GetFilePaths(containingPath, clearCache);
+ var files = fileSystem.GetFilePaths(containingPath, clearCache);
var videoFileNameWithoutExtension = fileSystem.GetFileNameWithoutExtension(video.Path);
diff --git a/MediaBrowser.Providers/MediaInfo/SubtitleScheduledTask.cs b/MediaBrowser.Providers/MediaInfo/SubtitleScheduledTask.cs
index 200615a5d..61cf1cfc3 100644
--- a/MediaBrowser.Providers/MediaInfo/SubtitleScheduledTask.cs
+++ b/MediaBrowser.Providers/MediaInfo/SubtitleScheduledTask.cs
@@ -17,6 +17,7 @@ using System.IO;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Model.Serialization;
using MediaBrowser.Model.Tasks;
+using MediaBrowser.Model.Extensions;
namespace MediaBrowser.Providers.MediaInfo
{
@@ -83,7 +84,7 @@ namespace MediaBrowser.Providers.MediaInfo
{
MediaTypes = new string[] { MediaType.Video },
IsVirtualItem = false,
- IncludeItemTypes = types.ToArray(),
+ IncludeItemTypes = types.ToArray(types.Count),
DtoOptions = new DtoOptions(true)
}).OfType<Video>()
diff --git a/MediaBrowser.Providers/MediaInfo/VideoImageProvider.cs b/MediaBrowser.Providers/MediaInfo/VideoImageProvider.cs
index ca701b70f..f666d8b7f 100644
--- a/MediaBrowser.Providers/MediaInfo/VideoImageProvider.cs
+++ b/MediaBrowser.Providers/MediaInfo/VideoImageProvider.cs
@@ -18,61 +18,34 @@ namespace MediaBrowser.Providers.MediaInfo
{
public class VideoImageProvider : IDynamicImageProvider, IHasItemChangeMonitor, IHasOrder
{
- private readonly IIsoManager _isoManager;
private readonly IMediaEncoder _mediaEncoder;
- private readonly IServerConfigurationManager _config;
- private readonly ILibraryManager _libraryManager;
private readonly ILogger _logger;
private readonly IFileSystem _fileSystem;
- public VideoImageProvider(IIsoManager isoManager, IMediaEncoder mediaEncoder, IServerConfigurationManager config, ILibraryManager libraryManager, ILogger logger, IFileSystem fileSystem)
+ public VideoImageProvider(IMediaEncoder mediaEncoder, ILogger logger, IFileSystem fileSystem)
{
- _isoManager = isoManager;
_mediaEncoder = mediaEncoder;
- _config = config;
- _libraryManager = libraryManager;
_logger = logger;
_fileSystem = fileSystem;
}
- /// <summary>
- /// The null mount task result
- /// </summary>
- protected readonly Task<IIsoMount> NullMountTaskResult = Task.FromResult<IIsoMount>(null);
-
- /// <summary>
- /// Mounts the iso if needed.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task{IIsoMount}.</returns>
- protected Task<IIsoMount> MountIsoIfNeeded(Video item, CancellationToken cancellationToken)
- {
- if (item.VideoType == VideoType.Iso)
- {
- return _isoManager.Mount(item.Path, cancellationToken);
- }
-
- return NullMountTaskResult;
- }
-
- public IEnumerable<ImageType> GetSupportedImages(IHasImages item)
+ public IEnumerable<ImageType> GetSupportedImages(IHasMetadata item)
{
return new List<ImageType> { ImageType.Primary };
}
- public Task<DynamicImageResponse> GetImage(IHasImages item, ImageType type, CancellationToken cancellationToken)
+ public Task<DynamicImageResponse> GetImage(IHasMetadata item, ImageType type, CancellationToken cancellationToken)
{
var video = (Video)item;
// No support for this
- if (video.VideoType == VideoType.HdDvd || video.IsPlaceHolder)
+ if (video.IsPlaceHolder)
{
return Task.FromResult(new DynamicImageResponse { HasImage = false });
}
- // Can't extract from iso's if we weren't unable to determine iso type
- if (video.VideoType == VideoType.Iso && !video.IsoType.HasValue)
+ // No support for this
+ if (video.VideoType == VideoType.Iso || video.VideoType == VideoType.Dvd || video.VideoType == VideoType.BluRay)
{
return Task.FromResult(new DynamicImageResponse { HasImage = false });
}
@@ -89,79 +62,66 @@ namespace MediaBrowser.Providers.MediaInfo
public async Task<DynamicImageResponse> GetVideoImage(Video item, CancellationToken cancellationToken)
{
- var isoMount = await MountIsoIfNeeded(item, cancellationToken).ConfigureAwait(false);
-
- try
- {
- var protocol = item.LocationType == LocationType.Remote
- ? MediaProtocol.Http
- : MediaProtocol.File;
+ var protocol = item.LocationType == LocationType.Remote
+ ? MediaProtocol.Http
+ : MediaProtocol.File;
- var inputPath = MediaEncoderHelpers.GetInputArgument(_fileSystem, item.Path, protocol, isoMount, item.PlayableStreamFileNames);
+ var inputPath = MediaEncoderHelpers.GetInputArgument(_fileSystem, item.Path, protocol, null, item.GetPlayableStreamFileNames());
- var mediaStreams =
- item.GetMediaSources(false)
- .Take(1)
- .SelectMany(i => i.MediaStreams)
- .ToList();
+ var mediaStreams =
+ item.GetMediaStreams();
- var imageStreams =
- mediaStreams
- .Where(i => i.Type == MediaStreamType.EmbeddedImage)
- .ToList();
+ var imageStreams =
+ mediaStreams
+ .Where(i => i.Type == MediaStreamType.EmbeddedImage)
+ .ToList();
- var imageStream = imageStreams.FirstOrDefault(i => (i.Comment ?? string.Empty).IndexOf("front", StringComparison.OrdinalIgnoreCase) != -1) ??
- imageStreams.FirstOrDefault(i => (i.Comment ?? string.Empty).IndexOf("cover", StringComparison.OrdinalIgnoreCase) != -1) ??
- imageStreams.FirstOrDefault();
+ var imageStream = imageStreams.FirstOrDefault(i => (i.Comment ?? string.Empty).IndexOf("front", StringComparison.OrdinalIgnoreCase) != -1) ??
+ imageStreams.FirstOrDefault(i => (i.Comment ?? string.Empty).IndexOf("cover", StringComparison.OrdinalIgnoreCase) != -1) ??
+ imageStreams.FirstOrDefault();
- string extractedImagePath;
+ string extractedImagePath;
- if (imageStream != null)
+ if (imageStream != null)
+ {
+ // Instead of using the raw stream index, we need to use nth video/embedded image stream
+ var videoIndex = -1;
+ foreach (var mediaStream in mediaStreams)
{
- // Instead of using the raw stream index, we need to use nth video/embedded image stream
- var videoIndex = -1;
- foreach (var mediaStream in mediaStreams)
+ if (mediaStream.Type == MediaStreamType.Video ||
+ mediaStream.Type == MediaStreamType.EmbeddedImage)
{
- if (mediaStream.Type == MediaStreamType.Video ||
- mediaStream.Type == MediaStreamType.EmbeddedImage)
- {
- videoIndex++;
- }
- if (mediaStream == imageStream)
- {
- break;
- }
+ videoIndex++;
+ }
+ if (mediaStream == imageStream)
+ {
+ break;
}
-
- extractedImagePath = await _mediaEncoder.ExtractVideoImage(inputPath, item.Container, protocol, videoIndex, cancellationToken).ConfigureAwait(false);
- }
- else
- {
- // If we know the duration, grab it from 10% into the video. Otherwise just 10 seconds in.
- // Always use 10 seconds for dvd because our duration could be out of whack
- var imageOffset = item.VideoType != VideoType.Dvd && item.RunTimeTicks.HasValue &&
- item.RunTimeTicks.Value > 0
- ? TimeSpan.FromTicks(Convert.ToInt64(item.RunTimeTicks.Value * .1))
- : TimeSpan.FromSeconds(10);
-
- extractedImagePath = await _mediaEncoder.ExtractVideoImage(inputPath, item.Container, protocol, item.Video3DFormat, imageOffset, cancellationToken).ConfigureAwait(false);
}
- return new DynamicImageResponse
- {
- Format = ImageFormat.Jpg,
- HasImage = true,
- Path = extractedImagePath,
- Protocol = MediaProtocol.File
- };
+ extractedImagePath = await _mediaEncoder.ExtractVideoImage(inputPath, item.Container, protocol, imageStream, videoIndex, cancellationToken).ConfigureAwait(false);
}
- finally
+ else
{
- if (isoMount != null)
- {
- isoMount.Dispose();
- }
+ // If we know the duration, grab it from 10% into the video. Otherwise just 10 seconds in.
+ // Always use 10 seconds for dvd because our duration could be out of whack
+ var imageOffset = item.VideoType != VideoType.Dvd && item.RunTimeTicks.HasValue &&
+ item.RunTimeTicks.Value > 0
+ ? TimeSpan.FromTicks(Convert.ToInt64(item.RunTimeTicks.Value * .1))
+ : TimeSpan.FromSeconds(10);
+
+ var videoStream = mediaStreams.FirstOrDefault(i => i.Type == MediaStreamType.Video);
+
+ extractedImagePath = await _mediaEncoder.ExtractVideoImage(inputPath, item.Container, protocol, videoStream, item.Video3DFormat, imageOffset, cancellationToken).ConfigureAwait(false);
}
+
+ return new DynamicImageResponse
+ {
+ Format = ImageFormat.Jpg,
+ HasImage = true,
+ Path = extractedImagePath,
+ Protocol = MediaProtocol.File
+ };
}
public string Name
@@ -169,7 +129,7 @@ namespace MediaBrowser.Providers.MediaInfo
get { return "Screen Grabber"; }
}
- public bool Supports(IHasImages item)
+ public bool Supports(IHasMetadata item)
{
var video = item as Video;
diff --git a/MediaBrowser.Providers/Movies/FanartMovieImageProvider.cs b/MediaBrowser.Providers/Movies/FanartMovieImageProvider.cs
index c3aa87a22..0214788ab 100644
--- a/MediaBrowser.Providers/Movies/FanartMovieImageProvider.cs
+++ b/MediaBrowser.Providers/Movies/FanartMovieImageProvider.cs
@@ -60,12 +60,12 @@ namespace MediaBrowser.Providers.Movies
get { return "FanArt"; }
}
- public bool Supports(IHasImages item)
+ public bool Supports(IHasMetadata item)
{
return item is Movie || item is BoxSet || item is MusicVideo;
}
- public IEnumerable<ImageType> GetSupportedImages(IHasImages item)
+ public IEnumerable<ImageType> GetSupportedImages(IHasMetadata item)
{
return new List<ImageType>
{
@@ -79,7 +79,7 @@ namespace MediaBrowser.Providers.Movies
};
}
- public async Task<IEnumerable<RemoteImageInfo>> GetImages(IHasImages item, CancellationToken cancellationToken)
+ public async Task<IEnumerable<RemoteImageInfo>> GetImages(IHasMetadata item, CancellationToken cancellationToken)
{
var baseItem = (BaseItem)item;
var list = new List<RemoteImageInfo>();
diff --git a/MediaBrowser.Providers/Movies/GenericMovieDbInfo.cs b/MediaBrowser.Providers/Movies/GenericMovieDbInfo.cs
index db621e554..65742f6e6 100644
--- a/MediaBrowser.Providers/Movies/GenericMovieDbInfo.cs
+++ b/MediaBrowser.Providers/Movies/GenericMovieDbInfo.cs
@@ -146,7 +146,7 @@ namespace MediaBrowser.Providers.Movies
movie.ProductionLocations = movieData
.production_countries
.Select(i => i.name)
- .ToList();
+ .ToArray(movieData.production_countries.Count);
}
movie.SetProviderId(MetadataProviders.Tmdb, movieData.id.ToString(_usCulture));
@@ -213,12 +213,7 @@ namespace MediaBrowser.Providers.Movies
//studios
if (movieData.production_companies != null)
{
- movie.Studios.Clear();
-
- foreach (var studio in movieData.production_companies.Select(c => c.name))
- {
- movie.AddStudio(studio);
- }
+ movie.SetStudios(movieData.production_companies.Select(c => c.name));
}
// genres
@@ -323,7 +318,7 @@ namespace MediaBrowser.Providers.Movies
Url = string.Format("https://www.youtube.com/watch?v={0}", i.source),
Name = i.name
- }).ToList();
+ }).ToArray();
}
}
}
diff --git a/MediaBrowser.Providers/Movies/MovieDbImageProvider.cs b/MediaBrowser.Providers/Movies/MovieDbImageProvider.cs
index 215b39181..8dc4bd56a 100644
--- a/MediaBrowser.Providers/Movies/MovieDbImageProvider.cs
+++ b/MediaBrowser.Providers/Movies/MovieDbImageProvider.cs
@@ -41,12 +41,12 @@ namespace MediaBrowser.Providers.Movies
get { return "TheMovieDb"; }
}
- public bool Supports(IHasImages item)
+ public bool Supports(IHasMetadata item)
{
return item is Movie || item is MusicVideo || item is Trailer;
}
- public IEnumerable<ImageType> GetSupportedImages(IHasImages item)
+ public IEnumerable<ImageType> GetSupportedImages(IHasMetadata item)
{
return new List<ImageType>
{
@@ -55,7 +55,7 @@ namespace MediaBrowser.Providers.Movies
};
}
- public async Task<IEnumerable<RemoteImageInfo>> GetImages(IHasImages item, CancellationToken cancellationToken)
+ public async Task<IEnumerable<RemoteImageInfo>> GetImages(IHasMetadata item, CancellationToken cancellationToken)
{
var list = new List<RemoteImageInfo>();
@@ -127,8 +127,7 @@ namespace MediaBrowser.Providers.Movies
return 0;
})
.ThenByDescending(i => i.CommunityRating ?? 0)
- .ThenByDescending(i => i.VoteCount ?? 0)
- .ToList();
+ .ThenByDescending(i => i.VoteCount ?? 0);
}
/// <summary>
@@ -149,8 +148,7 @@ namespace MediaBrowser.Providers.Movies
private IEnumerable<MovieDbProvider.Backdrop> GetBackdrops(MovieDbProvider.Images images)
{
var eligibleBackdrops = images.backdrops == null ? new List<MovieDbProvider.Backdrop>() :
- images.backdrops
- .ToList();
+ images.backdrops;
return eligibleBackdrops.OrderByDescending(i => i.vote_average)
.ThenByDescending(i => i.vote_count);
diff --git a/MediaBrowser.Providers/Movies/MovieDbProvider.cs b/MediaBrowser.Providers/Movies/MovieDbProvider.cs
index fe190afb4..fe798d4f0 100644
--- a/MediaBrowser.Providers/Movies/MovieDbProvider.cs
+++ b/MediaBrowser.Providers/Movies/MovieDbProvider.cs
@@ -22,13 +22,14 @@ using MediaBrowser.Common;
using MediaBrowser.Controller.IO;
using MediaBrowser.Model.Globalization;
using MediaBrowser.Model.Net;
+using MediaBrowser.Model.Extensions;
namespace MediaBrowser.Providers.Movies
{
/// <summary>
/// Class MovieDbProvider
/// </summary>
- public class MovieDbProvider : IRemoteMetadataProvider<Movie, MovieInfo>, IDisposable, IHasOrder
+ public class MovieDbProvider : IRemoteMetadataProvider<Movie, MovieInfo>, IHasOrder
{
internal static MovieDbProvider Current { get; private set; }
@@ -130,14 +131,6 @@ namespace MediaBrowser.Providers.Movies
}
/// <summary>
- /// Releases unmanaged and - optionally - managed resources.
- /// </summary>
- /// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
- protected virtual void Dispose(bool dispose)
- {
- }
-
- /// <summary>
/// The _TMDB settings task
/// </summary>
private TmdbSettingsResult _tmdbSettings;
@@ -282,7 +275,7 @@ namespace MediaBrowser.Providers.Movies
languages.Add("en");
}
- return string.Join(",", languages.ToArray());
+ return string.Join(",", languages.ToArray(languages.Count));
}
public static string NormalizeLanguage(string language)
@@ -433,11 +426,6 @@ namespace MediaBrowser.Providers.Movies
return await _httpClient.Get(options).ConfigureAwait(false);
}
- public void Dispose()
- {
- Dispose(true);
- }
-
/// <summary>
/// Class TmdbTitle
/// </summary>
diff --git a/MediaBrowser.Providers/Movies/MovieMetadataService.cs b/MediaBrowser.Providers/Movies/MovieMetadataService.cs
index 333d289ec..dc3146f2a 100644
--- a/MediaBrowser.Providers/Movies/MovieMetadataService.cs
+++ b/MediaBrowser.Providers/Movies/MovieMetadataService.cs
@@ -28,7 +28,7 @@ namespace MediaBrowser.Providers.Movies
return base.IsFullLocalMetadata(item);
}
- protected override void MergeData(MetadataResult<Movie> source, MetadataResult<Movie> target, List<MetadataFields> lockedFields, bool replaceData, bool mergeMetadataSettings)
+ protected override void MergeData(MetadataResult<Movie> source, MetadataResult<Movie> target, MetadataFields[] lockedFields, bool replaceData, bool mergeMetadataSettings)
{
ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
@@ -61,7 +61,7 @@ namespace MediaBrowser.Providers.Movies
return base.IsFullLocalMetadata(item);
}
- protected override void MergeData(MetadataResult<Trailer> source, MetadataResult<Trailer> target, List<MetadataFields> lockedFields, bool replaceData, bool mergeMetadataSettings)
+ protected override void MergeData(MetadataResult<Trailer> source, MetadataResult<Trailer> target, MetadataFields[] lockedFields, bool replaceData, bool mergeMetadataSettings)
{
ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
diff --git a/MediaBrowser.Providers/Music/AlbumImageFromSongProvider.cs b/MediaBrowser.Providers/Music/AlbumImageFromSongProvider.cs
index 0cb1a7ff1..57e20b852 100644
--- a/MediaBrowser.Providers/Music/AlbumImageFromSongProvider.cs
+++ b/MediaBrowser.Providers/Music/AlbumImageFromSongProvider.cs
@@ -11,12 +11,12 @@ namespace MediaBrowser.Providers.Music
{
public class AlbumImageFromSongProvider : IDynamicImageProvider
{
- public IEnumerable<ImageType> GetSupportedImages(IHasImages item)
+ public IEnumerable<ImageType> GetSupportedImages(IHasMetadata item)
{
return new List<ImageType> { ImageType.Primary };
}
- public Task<DynamicImageResponse> GetImage(IHasImages item, ImageType type, CancellationToken cancellationToken)
+ public Task<DynamicImageResponse> GetImage(IHasMetadata item, ImageType type, CancellationToken cancellationToken)
{
var album = (MusicAlbum)item;
@@ -38,7 +38,7 @@ namespace MediaBrowser.Providers.Music
get { return "Image Extractor"; }
}
- public bool Supports(IHasImages item)
+ public bool Supports(IHasMetadata item)
{
return item is MusicAlbum;
}
diff --git a/MediaBrowser.Providers/Music/AlbumMetadataService.cs b/MediaBrowser.Providers/Music/AlbumMetadataService.cs
index bba40608c..4230c517a 100644
--- a/MediaBrowser.Providers/Music/AlbumMetadataService.cs
+++ b/MediaBrowser.Providers/Music/AlbumMetadataService.cs
@@ -44,13 +44,13 @@ namespace MediaBrowser.Providers.Music
if (!item.LockedFields.Contains(MetadataFields.Studios))
{
- var currentList = item.Studios.ToList();
+ var currentList = item.Studios;
item.Studios = songs.SelectMany(i => i.Studios)
.Distinct(StringComparer.OrdinalIgnoreCase)
- .ToList();
+ .ToArray();
- if (currentList.Count != item.Studios.Count || !currentList.OrderBy(i => i).SequenceEqual(item.Studios.OrderBy(i => i), StringComparer.OrdinalIgnoreCase))
+ if (currentList.Length != item.Studios.Length || !currentList.OrderBy(i => i).SequenceEqual(item.Studios.OrderBy(i => i), StringComparer.OrdinalIgnoreCase))
{
updateType = updateType | ItemUpdateType.MetadataEdit;
}
@@ -87,7 +87,7 @@ namespace MediaBrowser.Providers.Music
.SelectMany(i => i.AlbumArtists)
.Distinct(StringComparer.OrdinalIgnoreCase)
.OrderBy(i => i)
- .ToList();
+ .ToArray();
if (!item.AlbumArtists.SequenceEqual(artists, StringComparer.OrdinalIgnoreCase))
{
@@ -106,7 +106,7 @@ namespace MediaBrowser.Providers.Music
.SelectMany(i => i.Artists)
.Distinct(StringComparer.OrdinalIgnoreCase)
.OrderBy(i => i)
- .ToList();
+ .ToArray();
if (!item.Artists.SequenceEqual(artists, StringComparer.OrdinalIgnoreCase))
{
@@ -151,14 +151,14 @@ namespace MediaBrowser.Providers.Music
return updateType;
}
- protected override void MergeData(MetadataResult<MusicAlbum> source, MetadataResult<MusicAlbum> target, List<MetadataFields> lockedFields, bool replaceData, bool mergeMetadataSettings)
+ protected override void MergeData(MetadataResult<MusicAlbum> source, MetadataResult<MusicAlbum> target, MetadataFields[] lockedFields, bool replaceData, bool mergeMetadataSettings)
{
ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
var sourceItem = source.Item;
var targetItem = target.Item;
- if (replaceData || targetItem.Artists.Count == 0)
+ if (replaceData || targetItem.Artists.Length == 0)
{
targetItem.Artists = sourceItem.Artists;
}
diff --git a/MediaBrowser.Providers/Music/ArtistMetadataService.cs b/MediaBrowser.Providers/Music/ArtistMetadataService.cs
index 98fe766e0..0ff161576 100644
--- a/MediaBrowser.Providers/Music/ArtistMetadataService.cs
+++ b/MediaBrowser.Providers/Music/ArtistMetadataService.cs
@@ -29,9 +29,9 @@ namespace MediaBrowser.Providers.Music
Recursive = true,
IsFolder = false
}) :
- item.GetRecursiveChildren(i => i is IHasArtist && !i.IsFolder).ToList();
+ item.GetRecursiveChildren(i => i is IHasArtist && !i.IsFolder);
- var currentList = item.Genres.ToList();
+ var currentList = item.Genres;
item.Genres = taggedItems.SelectMany(i => i.Genres)
.DistinctNames()
@@ -47,7 +47,7 @@ namespace MediaBrowser.Providers.Music
return updateType;
}
- protected override void MergeData(MetadataResult<MusicArtist> source, MetadataResult<MusicArtist> target, List<MetadataFields> lockedFields, bool replaceData, bool mergeMetadataSettings)
+ protected override void MergeData(MetadataResult<MusicArtist> source, MetadataResult<MusicArtist> target, MetadataFields[] lockedFields, bool replaceData, bool mergeMetadataSettings)
{
ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
}
diff --git a/MediaBrowser.Providers/Music/AudioDbAlbumImageProvider.cs b/MediaBrowser.Providers/Music/AudioDbAlbumImageProvider.cs
index c13d19c43..0ce221b06 100644
--- a/MediaBrowser.Providers/Music/AudioDbAlbumImageProvider.cs
+++ b/MediaBrowser.Providers/Music/AudioDbAlbumImageProvider.cs
@@ -25,7 +25,7 @@ namespace MediaBrowser.Providers.Music
_json = json;
}
- public IEnumerable<ImageType> GetSupportedImages(IHasImages item)
+ public IEnumerable<ImageType> GetSupportedImages(IHasMetadata item)
{
return new List<ImageType>
{
@@ -34,7 +34,7 @@ namespace MediaBrowser.Providers.Music
};
}
- public async Task<IEnumerable<RemoteImageInfo>> GetImages(IHasImages item, CancellationToken cancellationToken)
+ public async Task<IEnumerable<RemoteImageInfo>> GetImages(IHasMetadata item, CancellationToken cancellationToken)
{
var id = item.GetProviderId(MetadataProviders.MusicBrainzReleaseGroup);
@@ -105,7 +105,7 @@ namespace MediaBrowser.Providers.Music
}
}
- public bool Supports(IHasImages item)
+ public bool Supports(IHasMetadata item)
{
return item is MusicAlbum;
}
diff --git a/MediaBrowser.Providers/Music/AudioDbAlbumProvider.cs b/MediaBrowser.Providers/Music/AudioDbAlbumProvider.cs
index cd6b0b827..80f122402 100644
--- a/MediaBrowser.Providers/Music/AudioDbAlbumProvider.cs
+++ b/MediaBrowser.Providers/Music/AudioDbAlbumProvider.cs
@@ -74,7 +74,7 @@ namespace MediaBrowser.Providers.Music
{
if (!string.IsNullOrWhiteSpace(result.strArtist))
{
- item.AlbumArtists = new List<string> { result.strArtist };
+ item.AlbumArtists = new string[] { result.strArtist };
}
if (!string.IsNullOrEmpty(result.intYearReleased))
diff --git a/MediaBrowser.Providers/Music/AudioDbArtistImageProvider.cs b/MediaBrowser.Providers/Music/AudioDbArtistImageProvider.cs
index 6ca1d83d8..dded509e2 100644
--- a/MediaBrowser.Providers/Music/AudioDbArtistImageProvider.cs
+++ b/MediaBrowser.Providers/Music/AudioDbArtistImageProvider.cs
@@ -25,7 +25,7 @@ namespace MediaBrowser.Providers.Music
_httpClient = httpClient;
}
- public IEnumerable<ImageType> GetSupportedImages(IHasImages item)
+ public IEnumerable<ImageType> GetSupportedImages(IHasMetadata item)
{
return new List<ImageType>
{
@@ -36,7 +36,7 @@ namespace MediaBrowser.Providers.Music
};
}
- public async Task<IEnumerable<RemoteImageInfo>> GetImages(IHasImages item, CancellationToken cancellationToken)
+ public async Task<IEnumerable<RemoteImageInfo>> GetImages(IHasMetadata item, CancellationToken cancellationToken)
{
var id = item.GetProviderId(MetadataProviders.MusicBrainzArtist);
@@ -138,7 +138,7 @@ namespace MediaBrowser.Providers.Music
get { return "TheAudioDB"; }
}
- public bool Supports(IHasImages item)
+ public bool Supports(IHasMetadata item)
{
return item is MusicArtist;
}
diff --git a/MediaBrowser.Providers/Music/AudioMetadataService.cs b/MediaBrowser.Providers/Music/AudioMetadataService.cs
index 4d791be01..f02eae19f 100644
--- a/MediaBrowser.Providers/Music/AudioMetadataService.cs
+++ b/MediaBrowser.Providers/Music/AudioMetadataService.cs
@@ -8,21 +8,22 @@ using MediaBrowser.Providers.Manager;
using System.Collections.Generic;
using System.Linq;
using MediaBrowser.Model.IO;
+using MediaBrowser.Model.Extensions;
namespace MediaBrowser.Providers.Music
{
public class AudioMetadataService : MetadataService<Audio, SongInfo>
{
- protected override void MergeData(MetadataResult<Audio> source, MetadataResult<Audio> target, List<MetadataFields> lockedFields, bool replaceData, bool mergeMetadataSettings)
+ protected override void MergeData(MetadataResult<Audio> source, MetadataResult<Audio> target, MetadataFields[] lockedFields, bool replaceData, bool mergeMetadataSettings)
{
ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
var sourceItem = source.Item;
var targetItem = target.Item;
- if (replaceData || targetItem.Artists.Count == 0)
+ if (replaceData || targetItem.Artists.Length == 0)
{
- targetItem.Artists = sourceItem.Artists.ToList();
+ targetItem.Artists = sourceItem.Artists;
}
if (replaceData || string.IsNullOrEmpty(targetItem.Album))
diff --git a/MediaBrowser.Providers/Music/FanArtAlbumProvider.cs b/MediaBrowser.Providers/Music/FanArtAlbumProvider.cs
index 5700b2386..7a6826d31 100644
--- a/MediaBrowser.Providers/Music/FanArtAlbumProvider.cs
+++ b/MediaBrowser.Providers/Music/FanArtAlbumProvider.cs
@@ -47,12 +47,12 @@ namespace MediaBrowser.Providers.Music
get { return "FanArt"; }
}
- public bool Supports(IHasImages item)
+ public bool Supports(IHasMetadata item)
{
return item is MusicAlbum;
}
- public IEnumerable<ImageType> GetSupportedImages(IHasImages item)
+ public IEnumerable<ImageType> GetSupportedImages(IHasMetadata item)
{
return new List<ImageType>
{
@@ -61,7 +61,7 @@ namespace MediaBrowser.Providers.Music
};
}
- public async Task<IEnumerable<RemoteImageInfo>> GetImages(IHasImages item, CancellationToken cancellationToken)
+ public async Task<IEnumerable<RemoteImageInfo>> GetImages(IHasMetadata item, CancellationToken cancellationToken)
{
var album = (MusicAlbum)item;
diff --git a/MediaBrowser.Providers/Music/FanArtArtistProvider.cs b/MediaBrowser.Providers/Music/FanArtArtistProvider.cs
index eefebed29..6094fd26e 100644
--- a/MediaBrowser.Providers/Music/FanArtArtistProvider.cs
+++ b/MediaBrowser.Providers/Music/FanArtArtistProvider.cs
@@ -58,12 +58,12 @@ namespace MediaBrowser.Providers.Music
get { return "FanArt"; }
}
- public bool Supports(IHasImages item)
+ public bool Supports(IHasMetadata item)
{
return item is MusicArtist;
}
- public IEnumerable<ImageType> GetSupportedImages(IHasImages item)
+ public IEnumerable<ImageType> GetSupportedImages(IHasMetadata item)
{
return new List<ImageType>
{
@@ -75,7 +75,7 @@ namespace MediaBrowser.Providers.Music
};
}
- public async Task<IEnumerable<RemoteImageInfo>> GetImages(IHasImages item, CancellationToken cancellationToken)
+ public async Task<IEnumerable<RemoteImageInfo>> GetImages(IHasMetadata item, CancellationToken cancellationToken)
{
var artist = (MusicArtist)item;
diff --git a/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs b/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs
index b77fcf1b2..a35fd696a 100644
--- a/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs
+++ b/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs
@@ -17,6 +17,7 @@ using System.Threading.Tasks;
using System.Xml;
using MediaBrowser.Model.Serialization;
using MediaBrowser.Model.Xml;
+using MediaBrowser.Model.Extensions;
namespace MediaBrowser.Providers.Music
{
@@ -123,6 +124,7 @@ namespace MediaBrowser.Providers.Music
}
return result;
+
}).ToList();
}
}
diff --git a/MediaBrowser.Providers/Music/MusicBrainzArtistProvider.cs b/MediaBrowser.Providers/Music/MusicBrainzArtistProvider.cs
index 1a2b13e94..06f60c8a3 100644
--- a/MediaBrowser.Providers/Music/MusicBrainzArtistProvider.cs
+++ b/MediaBrowser.Providers/Music/MusicBrainzArtistProvider.cs
@@ -50,7 +50,7 @@ namespace MediaBrowser.Providers.Music
using (var stream = await MusicBrainzAlbumProvider.Current.GetMusicBrainzResponse(url, true, cancellationToken).ConfigureAwait(false))
{
- var results = GetResultsFromResponse(stream).ToList();
+ var results = GetResultsFromResponse(stream);
if (results.Count > 0)
{
@@ -73,7 +73,7 @@ namespace MediaBrowser.Providers.Music
return new List<RemoteSearchResult>();
}
- private IEnumerable<RemoteSearchResult> GetResultsFromResponse(Stream stream)
+ private List<RemoteSearchResult> GetResultsFromResponse(Stream stream)
{
using (var oReader = new StreamReader(stream, Encoding.UTF8))
{
@@ -125,7 +125,7 @@ namespace MediaBrowser.Providers.Music
}
}
- private IEnumerable<RemoteSearchResult> ParseArtistList(XmlReader reader)
+ private List<RemoteSearchResult> ParseArtistList(XmlReader reader)
{
var list = new List<RemoteSearchResult>();
diff --git a/MediaBrowser.Providers/Music/MusicVideoMetadataService.cs b/MediaBrowser.Providers/Music/MusicVideoMetadataService.cs
index b8f6e2c63..28504dbd7 100644
--- a/MediaBrowser.Providers/Music/MusicVideoMetadataService.cs
+++ b/MediaBrowser.Providers/Music/MusicVideoMetadataService.cs
@@ -10,12 +10,13 @@ using System.Linq;
using MediaBrowser.Controller.IO;
using MediaBrowser.Model.IO;
+using MediaBrowser.Model.Extensions;
namespace MediaBrowser.Providers.Music
{
class MusicVideoMetadataService : MetadataService<MusicVideo, MusicVideoInfo>
{
- protected override void MergeData(MetadataResult<MusicVideo> source, MetadataResult<MusicVideo> target, List<MetadataFields> lockedFields, bool replaceData, bool mergeMetadataSettings)
+ protected override void MergeData(MetadataResult<MusicVideo> source, MetadataResult<MusicVideo> target, MetadataFields[] lockedFields, bool replaceData, bool mergeMetadataSettings)
{
ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
@@ -27,9 +28,9 @@ namespace MediaBrowser.Providers.Music
targetItem.Album = sourceItem.Album;
}
- if (replaceData || targetItem.Artists.Count == 0)
+ if (replaceData || targetItem.Artists.Length == 0)
{
- targetItem.Artists = sourceItem.Artists.ToList();
+ targetItem.Artists = sourceItem.Artists;
}
}
diff --git a/MediaBrowser.Providers/MusicGenres/MusicGenreMetadataService.cs b/MediaBrowser.Providers/MusicGenres/MusicGenreMetadataService.cs
index ba059bd7b..3828f8d27 100644
--- a/MediaBrowser.Providers/MusicGenres/MusicGenreMetadataService.cs
+++ b/MediaBrowser.Providers/MusicGenres/MusicGenreMetadataService.cs
@@ -14,7 +14,7 @@ namespace MediaBrowser.Providers.MusicGenres
{
public class MusicGenreMetadataService : MetadataService<MusicGenre, ItemLookupInfo>
{
- protected override void MergeData(MetadataResult<MusicGenre> source, MetadataResult<MusicGenre> target, List<MetadataFields> lockedFields, bool replaceData, bool mergeMetadataSettings)
+ protected override void MergeData(MetadataResult<MusicGenre> source, MetadataResult<MusicGenre> target, MetadataFields[] lockedFields, bool replaceData, bool mergeMetadataSettings)
{
ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
}
diff --git a/MediaBrowser.Providers/Omdb/OmdbImageProvider.cs b/MediaBrowser.Providers/Omdb/OmdbImageProvider.cs
index f8b3ba155..74bfa6e03 100644
--- a/MediaBrowser.Providers/Omdb/OmdbImageProvider.cs
+++ b/MediaBrowser.Providers/Omdb/OmdbImageProvider.cs
@@ -32,7 +32,7 @@ namespace MediaBrowser.Providers.Omdb
_configurationManager = configurationManager;
}
- public IEnumerable<ImageType> GetSupportedImages(IHasImages item)
+ public IEnumerable<ImageType> GetSupportedImages(IHasMetadata item)
{
return new List<ImageType>
{
@@ -40,7 +40,7 @@ namespace MediaBrowser.Providers.Omdb
};
}
- public async Task<IEnumerable<RemoteImageInfo>> GetImages(IHasImages item, CancellationToken cancellationToken)
+ public async Task<IEnumerable<RemoteImageInfo>> GetImages(IHasMetadata item, CancellationToken cancellationToken)
{
var imdbId = item.GetProviderId(MetadataProviders.Imdb);
@@ -91,7 +91,7 @@ namespace MediaBrowser.Providers.Omdb
get { return "The Open Movie Database"; }
}
- public bool Supports(IHasImages item)
+ public bool Supports(IHasMetadata item)
{
return item is Movie || item is Trailer || item is Episode;
}
diff --git a/MediaBrowser.Providers/Omdb/OmdbProvider.cs b/MediaBrowser.Providers/Omdb/OmdbProvider.cs
index 0a95b449c..e2043faaf 100644
--- a/MediaBrowser.Providers/Omdb/OmdbProvider.cs
+++ b/MediaBrowser.Providers/Omdb/OmdbProvider.cs
@@ -299,7 +299,7 @@ namespace MediaBrowser.Providers.Omdb
}
}
- var url = GetOmdbUrl(string.Format("i={0}&plot=full&tomatoes=true&r=json", imdbParam), cancellationToken);
+ var url = GetOmdbUrl(string.Format("i={0}&plot=short&tomatoes=true&r=json", imdbParam), cancellationToken);
using (var stream = await GetOmdbResponse(_httpClient, url, cancellationToken).ConfigureAwait(false))
{
diff --git a/MediaBrowser.Providers/People/MovieDbPersonImageProvider.cs b/MediaBrowser.Providers/People/MovieDbPersonImageProvider.cs
index 372813790..4dfcdba09 100644
--- a/MediaBrowser.Providers/People/MovieDbPersonImageProvider.cs
+++ b/MediaBrowser.Providers/People/MovieDbPersonImageProvider.cs
@@ -37,12 +37,12 @@ namespace MediaBrowser.Providers.People
get { return "TheMovieDb"; }
}
- public bool Supports(IHasImages item)
+ public bool Supports(IHasMetadata item)
{
return item is Person;
}
- public IEnumerable<ImageType> GetSupportedImages(IHasImages item)
+ public IEnumerable<ImageType> GetSupportedImages(IHasMetadata item)
{
return new List<ImageType>
{
@@ -50,7 +50,7 @@ namespace MediaBrowser.Providers.People
};
}
- public async Task<IEnumerable<RemoteImageInfo>> GetImages(IHasImages item, CancellationToken cancellationToken)
+ public async Task<IEnumerable<RemoteImageInfo>> GetImages(IHasMetadata item, CancellationToken cancellationToken)
{
var person = (Person)item;
var id = person.GetProviderId(MetadataProviders.Tmdb);
@@ -116,8 +116,7 @@ namespace MediaBrowser.Providers.People
return 0;
})
.ThenByDescending(i => i.CommunityRating ?? 0)
- .ThenByDescending(i => i.VoteCount ?? 0)
- .ToList();
+ .ThenByDescending(i => i.VoteCount ?? 0);
}
private string GetLanguage(MovieDbPersonProvider.Profile profile)
diff --git a/MediaBrowser.Providers/People/MovieDbPersonProvider.cs b/MediaBrowser.Providers/People/MovieDbPersonProvider.cs
index 986c4b4a9..d8c9ce801 100644
--- a/MediaBrowser.Providers/People/MovieDbPersonProvider.cs
+++ b/MediaBrowser.Providers/People/MovieDbPersonProvider.cs
@@ -184,7 +184,7 @@ namespace MediaBrowser.Providers.People
if (!string.IsNullOrWhiteSpace(info.place_of_birth))
{
- item.ProductionLocations = new List<string> { info.place_of_birth };
+ item.ProductionLocations = new string[] { info.place_of_birth };
}
item.Overview = info.biography;
diff --git a/MediaBrowser.Providers/People/PersonMetadataService.cs b/MediaBrowser.Providers/People/PersonMetadataService.cs
index 5d70fc1d6..bbfaa43b4 100644
--- a/MediaBrowser.Providers/People/PersonMetadataService.cs
+++ b/MediaBrowser.Providers/People/PersonMetadataService.cs
@@ -14,7 +14,7 @@ namespace MediaBrowser.Providers.People
{
public class PersonMetadataService : MetadataService<Person, PersonLookupInfo>
{
- protected override void MergeData(MetadataResult<Person> source, MetadataResult<Person> target, List<MetadataFields> lockedFields, bool replaceData, bool mergeMetadataSettings)
+ protected override void MergeData(MetadataResult<Person> source, MetadataResult<Person> target, MetadataFields[] lockedFields, bool replaceData, bool mergeMetadataSettings)
{
ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
}
diff --git a/MediaBrowser.Providers/People/TvdbPersonImageProvider.cs b/MediaBrowser.Providers/People/TvdbPersonImageProvider.cs
index efbf46cd6..2c3ba00c8 100644
--- a/MediaBrowser.Providers/People/TvdbPersonImageProvider.cs
+++ b/MediaBrowser.Providers/People/TvdbPersonImageProvider.cs
@@ -48,12 +48,12 @@ namespace MediaBrowser.Providers.People
get { return "TheTVDB"; }
}
- public bool Supports(IHasImages item)
+ public bool Supports(IHasMetadata item)
{
return item is Person;
}
- public IEnumerable<ImageType> GetSupportedImages(IHasImages item)
+ public IEnumerable<ImageType> GetSupportedImages(IHasMetadata item)
{
return new List<ImageType>
{
@@ -61,7 +61,7 @@ namespace MediaBrowser.Providers.People
};
}
- public Task<IEnumerable<RemoteImageInfo>> GetImages(IHasImages item, CancellationToken cancellationToken)
+ public Task<IEnumerable<RemoteImageInfo>> GetImages(IHasMetadata item, CancellationToken cancellationToken)
{
var seriesWithPerson = _libraryManager.GetItemList(new InternalItemsQuery
{
diff --git a/MediaBrowser.Providers/Photos/PhotoAlbumMetadataService.cs b/MediaBrowser.Providers/Photos/PhotoAlbumMetadataService.cs
index 85b9dafd4..bff933ccf 100644
--- a/MediaBrowser.Providers/Photos/PhotoAlbumMetadataService.cs
+++ b/MediaBrowser.Providers/Photos/PhotoAlbumMetadataService.cs
@@ -14,7 +14,7 @@ namespace MediaBrowser.Providers.Photos
{
class PhotoAlbumMetadataService : MetadataService<PhotoAlbum, ItemLookupInfo>
{
- protected override void MergeData(MetadataResult<PhotoAlbum> source, MetadataResult<PhotoAlbum> target, List<MetadataFields> lockedFields, bool replaceData, bool mergeMetadataSettings)
+ protected override void MergeData(MetadataResult<PhotoAlbum> source, MetadataResult<PhotoAlbum> target, MetadataFields[] lockedFields, bool replaceData, bool mergeMetadataSettings)
{
ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
}
diff --git a/MediaBrowser.Providers/Photos/PhotoMetadataService.cs b/MediaBrowser.Providers/Photos/PhotoMetadataService.cs
index 909d359b9..d7f4982e4 100644
--- a/MediaBrowser.Providers/Photos/PhotoMetadataService.cs
+++ b/MediaBrowser.Providers/Photos/PhotoMetadataService.cs
@@ -12,7 +12,7 @@ namespace MediaBrowser.Providers.Photos
{
class PhotoMetadataService : MetadataService<Photo, ItemLookupInfo>
{
- protected override void MergeData(MetadataResult<Photo> source, MetadataResult<Photo> target, List<MetadataFields> lockedFields, bool replaceData, bool mergeMetadataSettings)
+ protected override void MergeData(MetadataResult<Photo> source, MetadataResult<Photo> target, MetadataFields[] lockedFields, bool replaceData, bool mergeMetadataSettings)
{
ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
}
diff --git a/MediaBrowser.Providers/Playlists/PlaylistMetadataService.cs b/MediaBrowser.Providers/Playlists/PlaylistMetadataService.cs
index c4ea106fb..d39d3baf5 100644
--- a/MediaBrowser.Providers/Playlists/PlaylistMetadataService.cs
+++ b/MediaBrowser.Providers/Playlists/PlaylistMetadataService.cs
@@ -15,7 +15,7 @@ namespace MediaBrowser.Providers.Playlists
{
class PlaylistMetadataService : MetadataService<Playlist, ItemLookupInfo>
{
- protected override void MergeData(MetadataResult<Playlist> source, MetadataResult<Playlist> target, List<MetadataFields> lockedFields, bool replaceData, bool mergeMetadataSettings)
+ protected override void MergeData(MetadataResult<Playlist> source, MetadataResult<Playlist> target, MetadataFields[] lockedFields, bool replaceData, bool mergeMetadataSettings)
{
ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
@@ -42,12 +42,9 @@ namespace MediaBrowser.Providers.Playlists
{
if (!item.IsLocked && !item.LockedFields.Contains(MetadataFields.Genres))
{
- var items = item.GetLinkedChildren()
- .ToList();
-
- var currentList = item.Genres.ToList();
+ var currentList = item.Genres;
- item.Genres = items.SelectMany(i => i.Genres)
+ item.Genres = item.GetLinkedChildren().SelectMany(i => i.Genres)
.Distinct(StringComparer.OrdinalIgnoreCase)
.ToList();
diff --git a/MediaBrowser.Providers/Studios/StudioMetadataService.cs b/MediaBrowser.Providers/Studios/StudioMetadataService.cs
index ef5ced3e2..23953b0d3 100644
--- a/MediaBrowser.Providers/Studios/StudioMetadataService.cs
+++ b/MediaBrowser.Providers/Studios/StudioMetadataService.cs
@@ -12,7 +12,7 @@ namespace MediaBrowser.Providers.Studios
{
public class StudioMetadataService : MetadataService<Studio, ItemLookupInfo>
{
- protected override void MergeData(MetadataResult<Studio> source, MetadataResult<Studio> target, List<MetadataFields> lockedFields, bool replaceData, bool mergeMetadataSettings)
+ protected override void MergeData(MetadataResult<Studio> source, MetadataResult<Studio> target, MetadataFields[] lockedFields, bool replaceData, bool mergeMetadataSettings)
{
ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
}
diff --git a/MediaBrowser.Providers/Studios/StudiosImageProvider.cs b/MediaBrowser.Providers/Studios/StudiosImageProvider.cs
index 8579bd16b..f63615430 100644
--- a/MediaBrowser.Providers/Studios/StudiosImageProvider.cs
+++ b/MediaBrowser.Providers/Studios/StudiosImageProvider.cs
@@ -37,12 +37,12 @@ namespace MediaBrowser.Providers.Studios
get { return "Emby Designs"; }
}
- public bool Supports(IHasImages item)
+ public bool Supports(IHasMetadata item)
{
return item is Studio;
}
- public IEnumerable<ImageType> GetSupportedImages(IHasImages item)
+ public IEnumerable<ImageType> GetSupportedImages(IHasMetadata item)
{
return new List<ImageType>
{
@@ -51,12 +51,12 @@ namespace MediaBrowser.Providers.Studios
};
}
- public Task<IEnumerable<RemoteImageInfo>> GetImages(IHasImages item, CancellationToken cancellationToken)
+ public Task<IEnumerable<RemoteImageInfo>> GetImages(IHasMetadata item, CancellationToken cancellationToken)
{
return GetImages(item, true, true, cancellationToken);
}
- private async Task<IEnumerable<RemoteImageInfo>> GetImages(IHasImages item, bool posters, bool thumbs, CancellationToken cancellationToken)
+ private async Task<IEnumerable<RemoteImageInfo>> GetImages(IHasMetadata item, bool posters, bool thumbs, CancellationToken cancellationToken)
{
var list = new List<RemoteImageInfo>();
@@ -83,7 +83,7 @@ namespace MediaBrowser.Providers.Studios
return list.Where(i => i != null);
}
- private RemoteImageInfo GetImage(IHasImages item, string filename, ImageType type, string remoteFilename)
+ private RemoteImageInfo GetImage(IHasMetadata item, string filename, ImageType type, string remoteFilename)
{
var list = ImageUtils.GetAvailableImages(filename, _fileSystem);
diff --git a/MediaBrowser.Providers/Subtitles/SubtitleManager.cs b/MediaBrowser.Providers/Subtitles/SubtitleManager.cs
index f7071f519..fe655759e 100644
--- a/MediaBrowser.Providers/Subtitles/SubtitleManager.cs
+++ b/MediaBrowser.Providers/Subtitles/SubtitleManager.cs
@@ -48,12 +48,12 @@ namespace MediaBrowser.Providers.Subtitles
_subtitleProviders = subtitleProviders.ToArray();
}
- public async Task<IEnumerable<RemoteSubtitleInfo>> SearchSubtitles(SubtitleSearchRequest request, CancellationToken cancellationToken)
+ public async Task<RemoteSubtitleInfo[]> SearchSubtitles(SubtitleSearchRequest request, CancellationToken cancellationToken)
{
var contentType = request.ContentType;
var providers = _subtitleProviders
.Where(i => i.SupportedMediaTypes.Contains(contentType))
- .ToList();
+ .ToArray();
// If not searching all, search one at a time until something is found
if (!request.SearchAllProviders)
@@ -64,9 +64,9 @@ namespace MediaBrowser.Providers.Subtitles
{
var searchResults = await provider.Search(request, cancellationToken).ConfigureAwait(false);
- var list = searchResults.ToList();
+ var list = searchResults.ToArray();
- if (list.Count > 0)
+ if (list.Length > 0)
{
Normalize(list);
return list;
@@ -77,7 +77,7 @@ namespace MediaBrowser.Providers.Subtitles
_logger.ErrorException("Error downloading subtitles from {0}", ex, provider.Name);
}
}
- return new List<RemoteSubtitleInfo>();
+ return new RemoteSubtitleInfo[] { };
}
var tasks = providers.Select(async i =>
@@ -86,20 +86,20 @@ namespace MediaBrowser.Providers.Subtitles
{
var searchResults = await i.Search(request, cancellationToken).ConfigureAwait(false);
- var list = searchResults.ToList();
+ var list = searchResults.ToArray();
Normalize(list);
return list;
}
catch (Exception ex)
{
_logger.ErrorException("Error downloading subtitles from {0}", ex, i.Name);
- return new List<RemoteSubtitleInfo>();
+ return new RemoteSubtitleInfo[] { };
}
});
var results = await Task.WhenAll(tasks).ConfigureAwait(false);
- return results.SelectMany(i => i);
+ return results.SelectMany(i => i).ToArray();
}
public async Task DownloadSubtitles(Video video,
@@ -173,12 +173,12 @@ namespace MediaBrowser.Providers.Subtitles
}
}
- public Task<IEnumerable<RemoteSubtitleInfo>> SearchSubtitles(Video video, string language, bool? isPerfectMatch, CancellationToken cancellationToken)
+ public Task<RemoteSubtitleInfo[]> SearchSubtitles(Video video, string language, bool? isPerfectMatch, CancellationToken cancellationToken)
{
if (video.LocationType != LocationType.FileSystem ||
video.VideoType != VideoType.VideoFile)
{
- return Task.FromResult<IEnumerable<RemoteSubtitleInfo>>(new List<RemoteSubtitleInfo>());
+ return Task.FromResult<RemoteSubtitleInfo[]>(new RemoteSubtitleInfo[] { });
}
VideoContentType mediaType;
@@ -194,7 +194,7 @@ namespace MediaBrowser.Providers.Subtitles
else
{
// These are the only supported types
- return Task.FromResult<IEnumerable<RemoteSubtitleInfo>>(new List<RemoteSubtitleInfo>());
+ return Task.FromResult<RemoteSubtitleInfo[]>(new RemoteSubtitleInfo[] { });
}
var request = new SubtitleSearchRequest
@@ -275,7 +275,7 @@ namespace MediaBrowser.Providers.Subtitles
return provider.GetSubtitles(id, cancellationToken);
}
- public IEnumerable<SubtitleProviderInfo> GetProviders(string itemId)
+ public SubtitleProviderInfo[] GetProviders(string itemId)
{
var video = _libraryManager.GetItemById(itemId) as Video;
VideoContentType mediaType;
@@ -291,18 +291,17 @@ namespace MediaBrowser.Providers.Subtitles
else
{
// These are the only supported types
- return new List<SubtitleProviderInfo>();
+ return new SubtitleProviderInfo[] { };
}
- var providers = _subtitleProviders
+ return _subtitleProviders
.Where(i => i.SupportedMediaTypes.Contains(mediaType))
- .ToList();
+ .Select(i => new SubtitleProviderInfo
+ {
+ Name = i.Name,
+ Id = GetProviderId(i.Name)
- return providers.Select(i => new SubtitleProviderInfo
- {
- Name = i.Name,
- Id = GetProviderId(i.Name)
- });
+ }).ToArray();
}
}
diff --git a/MediaBrowser.Providers/TV/DummySeasonProvider.cs b/MediaBrowser.Providers/TV/DummySeasonProvider.cs
index aef29abbe..791d14b60 100644
--- a/MediaBrowser.Providers/TV/DummySeasonProvider.cs
+++ b/MediaBrowser.Providers/TV/DummySeasonProvider.cs
@@ -37,7 +37,7 @@ namespace MediaBrowser.Providers.TV
public async Task Run(Series series, CancellationToken cancellationToken)
{
await RemoveObsoleteSeasons(series).ConfigureAwait(false);
-
+
var hasNewSeasons = await AddDummySeasonFolders(series, cancellationToken).ConfigureAwait(false);
if (hasNewSeasons)
@@ -129,8 +129,8 @@ namespace MediaBrowser.Providers.TV
};
season.SetParent(series);
-
- await series.AddChild(season, cancellationToken).ConfigureAwait(false);
+
+ series.AddChild(season, cancellationToken);
await season.RefreshMetadata(new MetadataRefreshOptions(_fileSystem), cancellationToken).ConfigureAwait(false);
diff --git a/MediaBrowser.Providers/TV/EpisodeMetadataService.cs b/MediaBrowser.Providers/TV/EpisodeMetadataService.cs
index 8adb6d4d2..29533a46b 100644
--- a/MediaBrowser.Providers/TV/EpisodeMetadataService.cs
+++ b/MediaBrowser.Providers/TV/EpisodeMetadataService.cs
@@ -58,7 +58,7 @@ namespace MediaBrowser.Providers.TV
return updateType;
}
- protected override void MergeData(MetadataResult<Episode> source, MetadataResult<Episode> target, List<MetadataFields> lockedFields, bool replaceData, bool mergeMetadataSettings)
+ protected override void MergeData(MetadataResult<Episode> source, MetadataResult<Episode> target, MetadataFields[] lockedFields, bool replaceData, bool mergeMetadataSettings)
{
ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
diff --git a/MediaBrowser.Providers/TV/FanArt/FanArtSeasonProvider.cs b/MediaBrowser.Providers/TV/FanArt/FanArtSeasonProvider.cs
index b9f010bb6..002c98e95 100644
--- a/MediaBrowser.Providers/TV/FanArt/FanArtSeasonProvider.cs
+++ b/MediaBrowser.Providers/TV/FanArt/FanArtSeasonProvider.cs
@@ -50,12 +50,12 @@ namespace MediaBrowser.Providers.TV
get { return "FanArt"; }
}
- public bool Supports(IHasImages item)
+ public bool Supports(IHasMetadata item)
{
return item is Season;
}
- public IEnumerable<ImageType> GetSupportedImages(IHasImages item)
+ public IEnumerable<ImageType> GetSupportedImages(IHasMetadata item)
{
return new List<ImageType>
{
@@ -66,7 +66,7 @@ namespace MediaBrowser.Providers.TV
};
}
- public async Task<IEnumerable<RemoteImageInfo>> GetImages(IHasImages item, CancellationToken cancellationToken)
+ public async Task<IEnumerable<RemoteImageInfo>> GetImages(IHasMetadata item, CancellationToken cancellationToken)
{
var list = new List<RemoteImageInfo>();
diff --git a/MediaBrowser.Providers/TV/FanArt/FanartSeriesProvider.cs b/MediaBrowser.Providers/TV/FanArt/FanartSeriesProvider.cs
index 644e9cbb5..583e5900d 100644
--- a/MediaBrowser.Providers/TV/FanArt/FanartSeriesProvider.cs
+++ b/MediaBrowser.Providers/TV/FanArt/FanartSeriesProvider.cs
@@ -59,12 +59,12 @@ namespace MediaBrowser.Providers.TV
get { return "FanArt"; }
}
- public bool Supports(IHasImages item)
+ public bool Supports(IHasMetadata item)
{
return item is Series;
}
- public IEnumerable<ImageType> GetSupportedImages(IHasImages item)
+ public IEnumerable<ImageType> GetSupportedImages(IHasMetadata item)
{
return new List<ImageType>
{
@@ -77,7 +77,7 @@ namespace MediaBrowser.Providers.TV
};
}
- public async Task<IEnumerable<RemoteImageInfo>> GetImages(IHasImages item, CancellationToken cancellationToken)
+ public async Task<IEnumerable<RemoteImageInfo>> GetImages(IHasMetadata item, CancellationToken cancellationToken)
{
var list = new List<RemoteImageInfo>();
diff --git a/MediaBrowser.Providers/TV/MissingEpisodeProvider.cs b/MediaBrowser.Providers/TV/MissingEpisodeProvider.cs
index 51ad12364..44e3cff6a 100644
--- a/MediaBrowser.Providers/TV/MissingEpisodeProvider.cs
+++ b/MediaBrowser.Providers/TV/MissingEpisodeProvider.cs
@@ -191,6 +191,8 @@ namespace MediaBrowser.Providers.TV
});
}
+ private const double UnairedEpisodeThresholdDays = 2;
+
/// <summary>
/// Adds the missing episodes.
/// </summary>
@@ -204,7 +206,7 @@ namespace MediaBrowser.Providers.TV
{
var existingEpisodes = (from s in series
from c in s.GetRecursiveChildren(i => i is Episode).Cast<Episode>()
- select new Tuple<int, Episode>((c.ParentIndexNumber ?? 0) , c))
+ select new Tuple<int, Episode>((c.ParentIndexNumber ?? 0), c))
.ToList();
var lookup = episodeLookup as IList<Tuple<int, int>> ?? episodeLookup.ToList();
@@ -248,8 +250,7 @@ namespace MediaBrowser.Providers.TV
var targetSeries = DetermineAppropriateSeries(series, tuple.Item1);
- var unairedThresholdDays = 2;
- now = now.AddDays(0 - unairedThresholdDays);
+ now = now.AddDays(0 - UnairedEpisodeThresholdDays);
if (airDate.Value < now)
{
@@ -331,7 +332,11 @@ namespace MediaBrowser.Providers.TV
if (!allowMissingEpisodes && i.Episode.IsMissingEpisode)
{
- return true;
+ // If it's missing, but not unaired, remove it
+ if (!i.Episode.PremiereDate.HasValue || i.Episode.PremiereDate.Value.ToLocalTime().Date.AddDays(UnairedEpisodeThresholdDays) < DateTime.Now.Date)
+ {
+ return true;
+ }
}
return false;
@@ -461,7 +466,7 @@ namespace MediaBrowser.Providers.TV
episode.SetParent(season);
- await season.AddChild(episode, cancellationToken).ConfigureAwait(false);
+ season.AddChild(episode, cancellationToken);
await episode.RefreshMetadata(new MetadataRefreshOptions(_fileSystem), cancellationToken).ConfigureAwait(false);
}
@@ -529,7 +534,7 @@ namespace MediaBrowser.Providers.TV
settings.CheckCharacters = false;
settings.IgnoreProcessingInstructions = true;
settings.IgnoreComments = true;
-
+
// Use XmlReader for best performance
using (var reader = XmlReader.Create(streamReader, settings))
{
diff --git a/MediaBrowser.Providers/TV/Omdb/OmdbEpisodeProvider.cs b/MediaBrowser.Providers/TV/Omdb/OmdbEpisodeProvider.cs
index daf493ad9..48af89830 100644
--- a/MediaBrowser.Providers/TV/Omdb/OmdbEpisodeProvider.cs
+++ b/MediaBrowser.Providers/TV/Omdb/OmdbEpisodeProvider.cs
@@ -50,7 +50,7 @@ namespace MediaBrowser.Providers.TV
};
// Allowing this will dramatically increase scan times
- if (info.IsMissingEpisode || info.IsVirtualUnaired)
+ if (info.IsMissingEpisode)
{
return result;
}
diff --git a/MediaBrowser.Providers/TV/SeasonMetadataService.cs b/MediaBrowser.Providers/TV/SeasonMetadataService.cs
index 1b4e3f44f..7cd408791 100644
--- a/MediaBrowser.Providers/TV/SeasonMetadataService.cs
+++ b/MediaBrowser.Providers/TV/SeasonMetadataService.cs
@@ -9,7 +9,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
-
+using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.IO;
using MediaBrowser.Model.IO;
@@ -32,7 +32,7 @@ namespace MediaBrowser.Providers.TV
if (isFullRefresh || currentUpdateType > ItemUpdateType.None)
{
- var episodes = item.GetEpisodes().ToList();
+ var episodes = item.GetEpisodes();
updateType |= SavePremiereDate(item, episodes);
updateType |= SaveIsVirtualItem(item, episodes);
}
@@ -61,12 +61,12 @@ namespace MediaBrowser.Providers.TV
return updateType;
}
- protected override void MergeData(MetadataResult<Season> source, MetadataResult<Season> target, List<MetadataFields> lockedFields, bool replaceData, bool mergeMetadataSettings)
+ protected override void MergeData(MetadataResult<Season> source, MetadataResult<Season> target, MetadataFields[] lockedFields, bool replaceData, bool mergeMetadataSettings)
{
ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
}
- private ItemUpdateType SavePremiereDate(Season item, List<Episode> episodes)
+ private ItemUpdateType SavePremiereDate(Season item, List<BaseItem> episodes)
{
var dates = episodes.Where(i => i.PremiereDate.HasValue).Select(i => i.PremiereDate.Value).ToList();
@@ -86,7 +86,7 @@ namespace MediaBrowser.Providers.TV
return ItemUpdateType.None;
}
- private ItemUpdateType SaveIsVirtualItem(Season item, List<Episode> episodes)
+ private ItemUpdateType SaveIsVirtualItem(Season item, List<BaseItem> episodes)
{
var isVirtualItem = item.LocationType == LocationType.Virtual && (episodes.Count == 0 || episodes.All(i => i.LocationType == LocationType.Virtual));
diff --git a/MediaBrowser.Providers/TV/SeriesMetadataService.cs b/MediaBrowser.Providers/TV/SeriesMetadataService.cs
index 7559a15de..3977ba9d9 100644
--- a/MediaBrowser.Providers/TV/SeriesMetadataService.cs
+++ b/MediaBrowser.Providers/TV/SeriesMetadataService.cs
@@ -57,7 +57,7 @@ namespace MediaBrowser.Providers.TV
return base.IsFullLocalMetadata(item);
}
- protected override void MergeData(MetadataResult<Series> source, MetadataResult<Series> target, List<MetadataFields> lockedFields, bool replaceData, bool mergeMetadataSettings)
+ protected override void MergeData(MetadataResult<Series> source, MetadataResult<Series> target, MetadataFields[] lockedFields, bool replaceData, bool mergeMetadataSettings)
{
ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
@@ -74,7 +74,7 @@ namespace MediaBrowser.Providers.TV
targetItem.Status = sourceItem.Status;
}
- if (replaceData || targetItem.AirDays == null || targetItem.AirDays.Count == 0)
+ if (replaceData || targetItem.AirDays == null || targetItem.AirDays.Length == 0)
{
targetItem.AirDays = sourceItem.AirDays;
}
diff --git a/MediaBrowser.Providers/TV/TheMovieDb/MovieDbEpisodeImageProvider.cs b/MediaBrowser.Providers/TV/TheMovieDb/MovieDbEpisodeImageProvider.cs
index 854f9f06b..728bbc505 100644
--- a/MediaBrowser.Providers/TV/TheMovieDb/MovieDbEpisodeImageProvider.cs
+++ b/MediaBrowser.Providers/TV/TheMovieDb/MovieDbEpisodeImageProvider.cs
@@ -29,7 +29,7 @@ namespace MediaBrowser.Providers.TV
: base(httpClient, configurationManager, jsonSerializer, fileSystem, localization, logManager)
{}
- public IEnumerable<ImageType> GetSupportedImages(IHasImages item)
+ public IEnumerable<ImageType> GetSupportedImages(IHasMetadata item)
{
return new List<ImageType>
{
@@ -37,7 +37,7 @@ namespace MediaBrowser.Providers.TV
};
}
- public async Task<IEnumerable<RemoteImageInfo>> GetImages(IHasImages item, CancellationToken cancellationToken)
+ public async Task<IEnumerable<RemoteImageInfo>> GetImages(IHasMetadata item, CancellationToken cancellationToken)
{
var episode = (Controller.Entities.TV.Episode)item;
var series = episode.Series;
@@ -104,8 +104,7 @@ namespace MediaBrowser.Providers.TV
return 0;
})
.ThenByDescending(i => i.CommunityRating ?? 0)
- .ThenByDescending(i => i.VoteCount ?? 0)
- .ToList();
+ .ThenByDescending(i => i.VoteCount ?? 0);
}
@@ -125,7 +124,7 @@ namespace MediaBrowser.Providers.TV
get { return "TheMovieDb"; }
}
- public bool Supports(IHasImages item)
+ public bool Supports(IHasMetadata item)
{
return item is Controller.Entities.TV.Episode;
}
diff --git a/MediaBrowser.Providers/TV/TheMovieDb/MovieDbEpisodeProvider.cs b/MediaBrowser.Providers/TV/TheMovieDb/MovieDbEpisodeProvider.cs
index 618a4df45..31785ca9c 100644
--- a/MediaBrowser.Providers/TV/TheMovieDb/MovieDbEpisodeProvider.cs
+++ b/MediaBrowser.Providers/TV/TheMovieDb/MovieDbEpisodeProvider.cs
@@ -68,7 +68,7 @@ namespace MediaBrowser.Providers.TV
var result = new MetadataResult<Episode>();
// Allowing this will dramatically increase scan times
- if (info.IsMissingEpisode || info.IsVirtualUnaired)
+ if (info.IsMissingEpisode)
{
return result;
}
@@ -134,7 +134,7 @@ namespace MediaBrowser.Providers.TV
if (video.site.Equals("youtube", System.StringComparison.OrdinalIgnoreCase))
{
var videoUrl = string.Format("http://www.youtube.com/watch?v={0}", video.key);
- item.AddTrailerUrl(videoUrl, true);
+ item.AddTrailerUrl(videoUrl);
}
}
}
diff --git a/MediaBrowser.Providers/TV/TheMovieDb/MovieDbSeriesImageProvider.cs b/MediaBrowser.Providers/TV/TheMovieDb/MovieDbSeriesImageProvider.cs
index c746e0488..f05f7bb30 100644
--- a/MediaBrowser.Providers/TV/TheMovieDb/MovieDbSeriesImageProvider.cs
+++ b/MediaBrowser.Providers/TV/TheMovieDb/MovieDbSeriesImageProvider.cs
@@ -40,12 +40,12 @@ namespace MediaBrowser.Providers.TV
get { return "TheMovieDb"; }
}
- public bool Supports(IHasImages item)
+ public bool Supports(IHasMetadata item)
{
return item is Series;
}
- public IEnumerable<ImageType> GetSupportedImages(IHasImages item)
+ public IEnumerable<ImageType> GetSupportedImages(IHasMetadata item)
{
return new List<ImageType>
{
@@ -54,7 +54,7 @@ namespace MediaBrowser.Providers.TV
};
}
- public async Task<IEnumerable<RemoteImageInfo>> GetImages(IHasImages item, CancellationToken cancellationToken)
+ public async Task<IEnumerable<RemoteImageInfo>> GetImages(IHasMetadata item, CancellationToken cancellationToken)
{
var list = new List<RemoteImageInfo>();
@@ -118,8 +118,7 @@ namespace MediaBrowser.Providers.TV
return 0;
})
.ThenByDescending(i => i.CommunityRating ?? 0)
- .ThenByDescending(i => i.VoteCount ?? 0)
- .ToList();
+ .ThenByDescending(i => i.VoteCount ?? 0);
}
/// <summary>
@@ -138,8 +137,7 @@ namespace MediaBrowser.Providers.TV
private IEnumerable<MovieDbSeriesProvider.Backdrop> GetBackdrops(MovieDbSeriesProvider.Images images)
{
var eligibleBackdrops = images.backdrops == null ? new List<MovieDbSeriesProvider.Backdrop>() :
- images.backdrops
- .ToList();
+ images.backdrops;
return eligibleBackdrops.OrderByDescending(i => i.vote_average)
.ThenByDescending(i => i.vote_count);
diff --git a/MediaBrowser.Providers/TV/TheMovieDb/MovieDbSeriesProvider.cs b/MediaBrowser.Providers/TV/TheMovieDb/MovieDbSeriesProvider.cs
index 0b5708b56..72745a9c3 100644
--- a/MediaBrowser.Providers/TV/TheMovieDb/MovieDbSeriesProvider.cs
+++ b/MediaBrowser.Providers/TV/TheMovieDb/MovieDbSeriesProvider.cs
@@ -21,6 +21,7 @@ using System.Threading.Tasks;
using MediaBrowser.Controller.IO;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Globalization;
+using MediaBrowser.Model.Extensions;
namespace MediaBrowser.Providers.TV
{
@@ -231,7 +232,7 @@ namespace MediaBrowser.Providers.TV
if (seriesInfo.networks != null)
{
- series.Studios = seriesInfo.networks.Select(i => i.name).ToList();
+ series.Studios = seriesInfo.networks.Select(i => i.name).ToArray(seriesInfo.networks.Count);
}
if (seriesInfo.genres != null)
@@ -301,7 +302,7 @@ namespace MediaBrowser.Providers.TV
if (video.site.Equals("youtube", System.StringComparison.OrdinalIgnoreCase))
{
var videoUrl = string.Format("http://www.youtube.com/watch?v={0}", video.key);
- series.AddTrailerUrl(videoUrl, true);
+ series.AddTrailerUrl(videoUrl);
}
}
}
diff --git a/MediaBrowser.Providers/TV/TheTVDB/TvdbEpisodeImageProvider.cs b/MediaBrowser.Providers/TV/TheTVDB/TvdbEpisodeImageProvider.cs
index 48e50c2e1..7b6bcc4c7 100644
--- a/MediaBrowser.Providers/TV/TheTVDB/TvdbEpisodeImageProvider.cs
+++ b/MediaBrowser.Providers/TV/TheTVDB/TvdbEpisodeImageProvider.cs
@@ -35,12 +35,12 @@ namespace MediaBrowser.Providers.TV
get { return "TheTVDB"; }
}
- public bool Supports(IHasImages item)
+ public bool Supports(IHasMetadata item)
{
return item is Episode;
}
- public IEnumerable<ImageType> GetSupportedImages(IHasImages item)
+ public IEnumerable<ImageType> GetSupportedImages(IHasMetadata item)
{
return new List<ImageType>
{
@@ -48,7 +48,7 @@ namespace MediaBrowser.Providers.TV
};
}
- public Task<IEnumerable<RemoteImageInfo>> GetImages(IHasImages item, CancellationToken cancellationToken)
+ public Task<IEnumerable<RemoteImageInfo>> GetImages(IHasMetadata item, CancellationToken cancellationToken)
{
var episode = (Episode)item;
var series = episode.Series;
diff --git a/MediaBrowser.Providers/TV/TheTVDB/TvdbPrescanTask.cs b/MediaBrowser.Providers/TV/TheTVDB/TvdbPrescanTask.cs
index 9a457ba94..30d2691e3 100644
--- a/MediaBrowser.Providers/TV/TheTVDB/TvdbPrescanTask.cs
+++ b/MediaBrowser.Providers/TV/TheTVDB/TvdbPrescanTask.cs
@@ -320,9 +320,8 @@ namespace MediaBrowser.Providers.TV
/// <param name="progress">The progress.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
- private async Task UpdateSeries(IEnumerable<string> seriesIds, string seriesDataPath, long? lastTvDbUpdateTime, IProgress<double> progress, CancellationToken cancellationToken)
+ private async Task UpdateSeries(List<string> seriesIds, string seriesDataPath, long? lastTvDbUpdateTime, IProgress<double> progress, CancellationToken cancellationToken)
{
- var list = seriesIds.ToList();
var numComplete = 0;
var seriesList = _libraryManager.GetItemList(new InternalItemsQuery()
@@ -342,7 +341,7 @@ namespace MediaBrowser.Providers.TV
.Where(i => !string.IsNullOrEmpty(i.GetProviderId(MetadataProviders.Tvdb)))
.ToLookup(i => i.GetProviderId(MetadataProviders.Tvdb));
- foreach (var seriesId in list)
+ foreach (var seriesId in seriesIds)
{
// Find the preferred language(s) for the movie in the library
var languages = allSeries[seriesId]
@@ -371,7 +370,7 @@ namespace MediaBrowser.Providers.TV
numComplete++;
double percent = numComplete;
- percent /= list.Count;
+ percent /= seriesIds.Count;
percent *= 100;
progress.Report(percent);
diff --git a/MediaBrowser.Providers/TV/TheTVDB/TvdbSeasonImageProvider.cs b/MediaBrowser.Providers/TV/TheTVDB/TvdbSeasonImageProvider.cs
index 395d419cf..22dab1cd7 100644
--- a/MediaBrowser.Providers/TV/TheTVDB/TvdbSeasonImageProvider.cs
+++ b/MediaBrowser.Providers/TV/TheTVDB/TvdbSeasonImageProvider.cs
@@ -48,12 +48,12 @@ namespace MediaBrowser.Providers.TV
get { return "TheTVDB"; }
}
- public bool Supports(IHasImages item)
+ public bool Supports(IHasMetadata item)
{
return item is Season;
}
- public IEnumerable<ImageType> GetSupportedImages(IHasImages item)
+ public IEnumerable<ImageType> GetSupportedImages(IHasMetadata item)
{
return new List<ImageType>
{
@@ -63,7 +63,7 @@ namespace MediaBrowser.Providers.TV
};
}
- public async Task<IEnumerable<RemoteImageInfo>> GetImages(IHasImages item, CancellationToken cancellationToken)
+ public async Task<IEnumerable<RemoteImageInfo>> GetImages(IHasMetadata item, CancellationToken cancellationToken)
{
var season = (Season)item;
var series = season.Series;
@@ -175,8 +175,7 @@ namespace MediaBrowser.Providers.TV
return 0;
})
.ThenByDescending(i => i.CommunityRating ?? 0)
- .ThenByDescending(i => i.VoteCount ?? 0)
- .ToList();
+ .ThenByDescending(i => i.VoteCount ?? 0);
}
private static void AddImage(XmlReader reader, List<RemoteImageInfo> images, int seasonNumber)
diff --git a/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesImageProvider.cs b/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesImageProvider.cs
index d7eea4226..6f3d763e2 100644
--- a/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesImageProvider.cs
+++ b/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesImageProvider.cs
@@ -49,12 +49,12 @@ namespace MediaBrowser.Providers.TV
get { return "TheTVDB"; }
}
- public bool Supports(IHasImages item)
+ public bool Supports(IHasMetadata item)
{
return item is Series;
}
- public IEnumerable<ImageType> GetSupportedImages(IHasImages item)
+ public IEnumerable<ImageType> GetSupportedImages(IHasMetadata item)
{
return new List<ImageType>
{
@@ -64,7 +64,7 @@ namespace MediaBrowser.Providers.TV
};
}
- public async Task<IEnumerable<RemoteImageInfo>> GetImages(IHasImages item, CancellationToken cancellationToken)
+ public async Task<IEnumerable<RemoteImageInfo>> GetImages(IHasMetadata item, CancellationToken cancellationToken)
{
if (TvdbSeriesProvider.IsValidSeries(item.ProviderIds))
{
@@ -169,8 +169,7 @@ namespace MediaBrowser.Providers.TV
return 0;
})
.ThenByDescending(i => i.CommunityRating ?? 0)
- .ThenByDescending(i => i.VoteCount ?? 0)
- .ToList();
+ .ThenByDescending(i => i.VoteCount ?? 0);
}
private void AddImage(XmlReader reader, List<RemoteImageInfo> images)
diff --git a/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesProvider.cs b/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesProvider.cs
index 8a10affb9..af18f5f0b 100644
--- a/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesProvider.cs
+++ b/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesProvider.cs
@@ -438,25 +438,25 @@ namespace MediaBrowser.Providers.TV
var seriesXmlFilename = preferredMetadataLanguage + ".xml";
- const int cacheDays = 1;
+ const int cacheHours = 12;
var seriesFile = files.FirstOrDefault(i => string.Equals(seriesXmlFilename, i.Name, StringComparison.OrdinalIgnoreCase));
// No need to check age if automatic updates are enabled
- if (seriesFile == null || !seriesFile.Exists || (DateTime.UtcNow - _fileSystem.GetLastWriteTimeUtc(seriesFile)).TotalDays > cacheDays)
+ if (seriesFile == null || !seriesFile.Exists || (DateTime.UtcNow - _fileSystem.GetLastWriteTimeUtc(seriesFile)).TotalHours > cacheHours)
{
return false;
}
var actorsXml = files.FirstOrDefault(i => string.Equals("actors.xml", i.Name, StringComparison.OrdinalIgnoreCase));
// No need to check age if automatic updates are enabled
- if (actorsXml == null || !actorsXml.Exists || (DateTime.UtcNow - _fileSystem.GetLastWriteTimeUtc(actorsXml)).TotalDays > cacheDays)
+ if (actorsXml == null || !actorsXml.Exists || (DateTime.UtcNow - _fileSystem.GetLastWriteTimeUtc(actorsXml)).TotalHours > cacheHours)
{
return false;
}
var bannersXml = files.FirstOrDefault(i => string.Equals("banners.xml", i.Name, StringComparison.OrdinalIgnoreCase));
// No need to check age if automatic updates are enabled
- if (bannersXml == null || !bannersXml.Exists || (DateTime.UtcNow - _fileSystem.GetLastWriteTimeUtc(bannersXml)).TotalDays > cacheDays)
+ if (bannersXml == null || !bannersXml.Exists || (DateTime.UtcNow - _fileSystem.GetLastWriteTimeUtc(bannersXml)).TotalHours > cacheHours)
{
return false;
}
@@ -482,7 +482,7 @@ namespace MediaBrowser.Providers.TV
/// <returns>Task{System.String}.</returns>
private async Task<IEnumerable<RemoteSearchResult>> FindSeries(string name, int? year, string language, CancellationToken cancellationToken)
{
- var results = (await FindSeriesInternal(name, language, cancellationToken).ConfigureAwait(false)).ToList();
+ var results = (await FindSeriesInternal(name, language, cancellationToken).ConfigureAwait(false));
if (results.Count == 0)
{
@@ -491,7 +491,7 @@ namespace MediaBrowser.Providers.TV
if (!string.IsNullOrWhiteSpace(nameWithoutYear) && !string.Equals(nameWithoutYear, name, StringComparison.OrdinalIgnoreCase))
{
- results = (await FindSeriesInternal(nameWithoutYear, language, cancellationToken).ConfigureAwait(false)).ToList();
+ results = (await FindSeriesInternal(nameWithoutYear, language, cancellationToken).ConfigureAwait(false));
}
}
@@ -507,7 +507,7 @@ namespace MediaBrowser.Providers.TV
});
}
- private async Task<IEnumerable<RemoteSearchResult>> FindSeriesInternal(string name, string language, CancellationToken cancellationToken)
+ private async Task<List<RemoteSearchResult>> FindSeriesInternal(string name, string language, CancellationToken cancellationToken)
{
var url = string.Format(SeriesSearchUrl, WebUtility.UrlEncode(name), NormalizeLanguage(language));
var searchResults = new List<RemoteSearchResult>();
@@ -1091,26 +1091,26 @@ namespace MediaBrowser.Providers.TV
}
case "Airs_DayOfWeek":
- {
- var val = reader.ReadElementContentAsString();
+ {
+ var val = reader.ReadElementContentAsString();
- if (!string.IsNullOrWhiteSpace(val))
- {
- item.AirDays = TVUtils.GetAirDays(val);
- }
- break;
+ if (!string.IsNullOrWhiteSpace(val))
+ {
+ item.AirDays = TVUtils.GetAirDays(val);
}
+ break;
+ }
case "Airs_Time":
- {
- var val = reader.ReadElementContentAsString();
+ {
+ var val = reader.ReadElementContentAsString();
- if (!string.IsNullOrWhiteSpace(val))
- {
- item.AirTime = val;
- }
- break;
+ if (!string.IsNullOrWhiteSpace(val))
+ {
+ item.AirTime = val;
}
+ break;
+ }
case "ContentRating":
{
@@ -1273,12 +1273,7 @@ namespace MediaBrowser.Providers.TV
if (vals.Count > 0)
{
- item.Studios.Clear();
-
- foreach (var genre in vals)
- {
- item.AddStudio(genre);
- }
+ item.SetStudios(vals);
}
}
diff --git a/MediaBrowser.Providers/TV/TvExternalIds.cs b/MediaBrowser.Providers/TV/TvExternalIds.cs
index d2860a622..104bcb5ae 100644
--- a/MediaBrowser.Providers/TV/TvExternalIds.cs
+++ b/MediaBrowser.Providers/TV/TvExternalIds.cs
@@ -96,27 +96,4 @@ namespace MediaBrowser.Providers.TV
return item is Episode;
}
}
-
- public class TvComSeriesExternalId : IExternalId
- {
- public string Name
- {
- get { return "TV.com"; }
- }
-
- public string Key
- {
- get { return MetadataProviders.Tvcom.ToString(); }
- }
-
- public string UrlFormatString
- {
- get { return null; }
- }
-
- public bool Supports(IHasProviderIds item)
- {
- return item is Series;
- }
- }
}
diff --git a/MediaBrowser.Providers/Users/UserMetadataService.cs b/MediaBrowser.Providers/Users/UserMetadataService.cs
index 88df704d6..694315c18 100644
--- a/MediaBrowser.Providers/Users/UserMetadataService.cs
+++ b/MediaBrowser.Providers/Users/UserMetadataService.cs
@@ -14,7 +14,7 @@ namespace MediaBrowser.Providers.Users
{
public class UserMetadataService : MetadataService<User, ItemLookupInfo>
{
- protected override void MergeData(MetadataResult<User> source, MetadataResult<User> target, List<MetadataFields> lockedFields, bool replaceData, bool mergeMetadataSettings)
+ protected override void MergeData(MetadataResult<User> source, MetadataResult<User> target, MetadataFields[] lockedFields, bool replaceData, bool mergeMetadataSettings)
{
ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
}
diff --git a/MediaBrowser.Providers/Videos/VideoMetadataService.cs b/MediaBrowser.Providers/Videos/VideoMetadataService.cs
index a07cc5949..f493eb31f 100644
--- a/MediaBrowser.Providers/Videos/VideoMetadataService.cs
+++ b/MediaBrowser.Providers/Videos/VideoMetadataService.cs
@@ -21,7 +21,7 @@ namespace MediaBrowser.Providers.Videos
}
}
- protected override void MergeData(MetadataResult<Video> source, MetadataResult<Video> target, List<MetadataFields> lockedFields, bool replaceData, bool mergeMetadataSettings)
+ protected override void MergeData(MetadataResult<Video> source, MetadataResult<Video> target, MetadataFields[] lockedFields, bool replaceData, bool mergeMetadataSettings)
{
ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
}
diff --git a/MediaBrowser.Providers/Years/YearMetadataService.cs b/MediaBrowser.Providers/Years/YearMetadataService.cs
index 36c2fd1dd..783833656 100644
--- a/MediaBrowser.Providers/Years/YearMetadataService.cs
+++ b/MediaBrowser.Providers/Years/YearMetadataService.cs
@@ -14,7 +14,7 @@ namespace MediaBrowser.Providers.Years
{
public class YearMetadataService : MetadataService<Year, ItemLookupInfo>
{
- protected override void MergeData(MetadataResult<Year> source, MetadataResult<Year> target, List<MetadataFields> lockedFields, bool replaceData, bool mergeMetadataSettings)
+ protected override void MergeData(MetadataResult<Year> source, MetadataResult<Year> target, MetadataFields[] lockedFields, bool replaceData, bool mergeMetadataSettings)
{
ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
}
diff --git a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
deleted file mode 100644
index 31c400915..000000000
--- a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
+++ /dev/null
@@ -1,69 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
- <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
- <PropertyGroup>
- <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
- <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
- <ProjectGuid>{2E781478-814D-4A48-9D80-BFF206441A65}</ProjectGuid>
- <OutputType>Library</OutputType>
- <AppDesignerFolder>Properties</AppDesignerFolder>
- <RootNamespace>MediaBrowser.Server.Implementations</RootNamespace>
- <AssemblyName>MediaBrowser.Server.Implementations</AssemblyName>
- <FileAlignment>512</FileAlignment>
- <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
- <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
- <TargetFrameworkProfile>Profile7</TargetFrameworkProfile>
- <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
- </PropertyGroup>
- <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
- <DebugSymbols>true</DebugSymbols>
- <DebugType>full</DebugType>
- <Optimize>false</Optimize>
- <OutputPath>bin\Debug\</OutputPath>
- <DefineConstants>DEBUG;TRACE</DefineConstants>
- <ErrorReport>prompt</ErrorReport>
- <WarningLevel>4</WarningLevel>
- </PropertyGroup>
- <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
- <DebugType>none</DebugType>
- <Optimize>true</Optimize>
- <OutputPath>bin\Release\</OutputPath>
- <DefineConstants>TRACE</DefineConstants>
- <ErrorReport>prompt</ErrorReport>
- <WarningLevel>4</WarningLevel>
- </PropertyGroup>
- <ItemGroup>
- <Compile Include="..\SharedVersion.cs">
- <Link>Properties\SharedVersion.cs</Link>
- </Compile>
- <Compile Include="Devices\CameraUploadsFolder.cs" />
- <Compile Include="Playlists\ManualPlaylistsFolder.cs" />
- <Compile Include="Properties\AssemblyInfo.cs" />
- </ItemGroup>
- <ItemGroup>
- <ProjectReference Include="..\MediaBrowser.Common\MediaBrowser.Common.csproj">
- <Project>{9142EEFA-7570-41E1-BFCC-468BB571AF2F}</Project>
- <Name>MediaBrowser.Common</Name>
- </ProjectReference>
- <ProjectReference Include="..\MediaBrowser.Controller\MediaBrowser.Controller.csproj">
- <Project>{17E1F4E6-8ABD-4FE5-9ECF-43D4B6087BA2}</Project>
- <Name>MediaBrowser.Controller</Name>
- </ProjectReference>
- <ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj">
- <Project>{7EEEB4BB-F3E8-48FC-B4C5-70F0FFF8329B}</Project>
- <Name>MediaBrowser.Model</Name>
- </ProjectReference>
- </ItemGroup>
- <ItemGroup>
- <None Include="app.config" />
- </ItemGroup>
- <ItemGroup />
- <Import Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets" />
- <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
- Other similar extension points exist, see Microsoft.Common.targets.
- <Target Name="BeforeBuild">
- </Target>
- <Target Name="AfterBuild">
- </Target>
- -->
-</Project> \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Properties/AssemblyInfo.cs b/MediaBrowser.Server.Implementations/Properties/AssemblyInfo.cs
deleted file mode 100644
index db656b934..000000000
--- a/MediaBrowser.Server.Implementations/Properties/AssemblyInfo.cs
+++ /dev/null
@@ -1,30 +0,0 @@
-using System.Reflection;
-using System.Runtime.InteropServices;
-
-// General Information about an assembly is controlled through the following
-// set of attributes. Change these attribute values to modify the information
-// associated with an assembly.
-[assembly: AssemblyTitle("MediaBrowser.Server.Implementations")]
-[assembly: AssemblyDescription("")]
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("")]
-[assembly: AssemblyProduct("MediaBrowser.Server.Implementations")]
-[assembly: AssemblyCopyright("Copyright © 2013")]
-[assembly: AssemblyTrademark("")]
-[assembly: AssemblyCulture("")]
-
-// Setting ComVisible to false makes the types in this assembly not visible
-// to COM components. If you need to access a type in this assembly from
-// COM, set the ComVisible attribute to true on that type.
-[assembly: ComVisible(false)]
-
-// The following GUID is for the ID of the typelib if this project is exposed to COM
-[assembly: Guid("0537cdd3-a069-4d86-9318-d46d8b119903")]
-
-// Version information for an assembly consists of the following four values:
-//
-// Major Version
-// Minor Version
-// Build Number
-// Revision
-//
diff --git a/MediaBrowser.Server.Implementations/app.config b/MediaBrowser.Server.Implementations/app.config
deleted file mode 100644
index 9d8c1ac93..000000000
--- a/MediaBrowser.Server.Implementations/app.config
+++ /dev/null
@@ -1,11 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<configuration>
- <runtime>
- <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
- <dependentAssembly>
- <assemblyIdentity name="System.Data.SQLite" publicKeyToken="db937bc2d44ff139" culture="neutral"/>
- <bindingRedirect oldVersion="0.0.0.0-1.0.94.0" newVersion="1.0.94.0"/>
- </dependentAssembly>
- </assemblyBinding>
- </runtime>
-<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6"/></startup></configuration>
diff --git a/MediaBrowser.Server.Mac.sln b/MediaBrowser.Server.Mac.sln
index 6fc1dd892..051ea660b 100644
--- a/MediaBrowser.Server.Mac.sln
+++ b/MediaBrowser.Server.Mac.sln
@@ -13,14 +13,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Controller", "
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.LocalMetadata", "MediaBrowser.LocalMetadata\MediaBrowser.LocalMetadata.csproj", "{7EF9F3E0-697D-42F3-A08F-19DEB5F84392}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.MediaEncoding", "MediaBrowser.MediaEncoding\MediaBrowser.MediaEncoding.csproj", "{0BD82FA6-EB8A-4452-8AF5-74F9C3849451}"
-EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Model", "MediaBrowser.Model\MediaBrowser.Model.csproj", "{7EEEB4BB-F3E8-48FC-B4C5-70F0FFF8329B}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Providers", "MediaBrowser.Providers\MediaBrowser.Providers.csproj", "{442B5058-DCAF-4263-BB6A-F21E31120A1B}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Server.Implementations", "MediaBrowser.Server.Implementations\MediaBrowser.Server.Implementations.csproj", "{2E781478-814D-4A48-9D80-BFF206441A65}"
-EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.WebDashboard", "MediaBrowser.WebDashboard\MediaBrowser.WebDashboard.csproj", "{5624B7B5-B5A7-41D8-9F10-CC5611109619}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.XbmcMetadata", "MediaBrowser.XbmcMetadata\MediaBrowser.XbmcMetadata.csproj", "{23499896-B135-4527-8574-C26E926EA99E}"
@@ -43,12 +39,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RSSDP", "RSSDP\RSSDP.csproj
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Emby.Drawing.Skia", "Emby.Drawing.Skia\Emby.Drawing.Skia.csproj", "{2312DA6D-FF86-4597-9777-BCEEC32D96DD}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Emby.Common.Implementations", "Emby.Common.Implementations\Emby.Common.Implementations.csproj", "{1E37A338-9F57-4B70-BD6D-BB9C591E319B}"
-EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SocketHttpListener", "SocketHttpListener\SocketHttpListener.csproj", "{1D74413B-E7CF-455B-B021-F52BDF881542}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Emby.Server.Core", "Emby.Server.Core\Emby.Server.Core.csproj", "{776B9F0C-5195-45E3-9A36-1CC1F0D8E0B0}"
-EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mono.Nat", "Mono.Nat\Mono.Nat.csproj", "{CB7F2326-6497-4A3D-BA03-48513B17A7BE}"
EndProject
Global
@@ -174,26 +166,6 @@ Global
{7EF9F3E0-697D-42F3-A08F-19DEB5F84392}.Signed|Any CPU.Build.0 = Debug|Any CPU
{7EF9F3E0-697D-42F3-A08F-19DEB5F84392}.Signed|x86.ActiveCfg = Debug|Any CPU
{7EF9F3E0-697D-42F3-A08F-19DEB5F84392}.Signed|x86.Build.0 = Debug|Any CPU
- {0BD82FA6-EB8A-4452-8AF5-74F9C3849451}.AppStore|Any CPU.ActiveCfg = Release|Any CPU
- {0BD82FA6-EB8A-4452-8AF5-74F9C3849451}.AppStore|Any CPU.Build.0 = Release|Any CPU
- {0BD82FA6-EB8A-4452-8AF5-74F9C3849451}.AppStore|x86.ActiveCfg = Release Mono|Any CPU
- {0BD82FA6-EB8A-4452-8AF5-74F9C3849451}.AppStore|x86.Build.0 = Release Mono|Any CPU
- {0BD82FA6-EB8A-4452-8AF5-74F9C3849451}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {0BD82FA6-EB8A-4452-8AF5-74F9C3849451}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {0BD82FA6-EB8A-4452-8AF5-74F9C3849451}.Debug|x86.ActiveCfg = Debug|Any CPU
- {0BD82FA6-EB8A-4452-8AF5-74F9C3849451}.Debug|x86.Build.0 = Debug|Any CPU
- {0BD82FA6-EB8A-4452-8AF5-74F9C3849451}.Release Mono|Any CPU.ActiveCfg = Release Mono|Any CPU
- {0BD82FA6-EB8A-4452-8AF5-74F9C3849451}.Release Mono|Any CPU.Build.0 = Release Mono|Any CPU
- {0BD82FA6-EB8A-4452-8AF5-74F9C3849451}.Release Mono|x86.ActiveCfg = Release Mono|Any CPU
- {0BD82FA6-EB8A-4452-8AF5-74F9C3849451}.Release Mono|x86.Build.0 = Release Mono|Any CPU
- {0BD82FA6-EB8A-4452-8AF5-74F9C3849451}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {0BD82FA6-EB8A-4452-8AF5-74F9C3849451}.Release|Any CPU.Build.0 = Release|Any CPU
- {0BD82FA6-EB8A-4452-8AF5-74F9C3849451}.Release|x86.ActiveCfg = Release|Any CPU
- {0BD82FA6-EB8A-4452-8AF5-74F9C3849451}.Release|x86.Build.0 = Release|Any CPU
- {0BD82FA6-EB8A-4452-8AF5-74F9C3849451}.Signed|Any CPU.ActiveCfg = Release Mono|Any CPU
- {0BD82FA6-EB8A-4452-8AF5-74F9C3849451}.Signed|Any CPU.Build.0 = Release Mono|Any CPU
- {0BD82FA6-EB8A-4452-8AF5-74F9C3849451}.Signed|x86.ActiveCfg = Release Mono|Any CPU
- {0BD82FA6-EB8A-4452-8AF5-74F9C3849451}.Signed|x86.Build.0 = Release Mono|Any CPU
{7EEEB4BB-F3E8-48FC-B4C5-70F0FFF8329B}.AppStore|Any CPU.ActiveCfg = Release|Any CPU
{7EEEB4BB-F3E8-48FC-B4C5-70F0FFF8329B}.AppStore|Any CPU.Build.0 = Release|Any CPU
{7EEEB4BB-F3E8-48FC-B4C5-70F0FFF8329B}.AppStore|x86.ActiveCfg = Debug|Any CPU
@@ -234,26 +206,6 @@ Global
{442B5058-DCAF-4263-BB6A-F21E31120A1B}.Signed|Any CPU.Build.0 = Release Mono|Any CPU
{442B5058-DCAF-4263-BB6A-F21E31120A1B}.Signed|x86.ActiveCfg = Release Mono|Any CPU
{442B5058-DCAF-4263-BB6A-F21E31120A1B}.Signed|x86.Build.0 = Release Mono|Any CPU
- {2E781478-814D-4A48-9D80-BFF206441A65}.AppStore|Any CPU.ActiveCfg = Release|Any CPU
- {2E781478-814D-4A48-9D80-BFF206441A65}.AppStore|Any CPU.Build.0 = Release|Any CPU
- {2E781478-814D-4A48-9D80-BFF206441A65}.AppStore|x86.ActiveCfg = Release Mono|Any CPU
- {2E781478-814D-4A48-9D80-BFF206441A65}.AppStore|x86.Build.0 = Release Mono|Any CPU
- {2E781478-814D-4A48-9D80-BFF206441A65}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {2E781478-814D-4A48-9D80-BFF206441A65}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {2E781478-814D-4A48-9D80-BFF206441A65}.Debug|x86.ActiveCfg = Debug|Any CPU
- {2E781478-814D-4A48-9D80-BFF206441A65}.Debug|x86.Build.0 = Debug|Any CPU
- {2E781478-814D-4A48-9D80-BFF206441A65}.Release Mono|Any CPU.ActiveCfg = Release Mono|Any CPU
- {2E781478-814D-4A48-9D80-BFF206441A65}.Release Mono|Any CPU.Build.0 = Release Mono|Any CPU
- {2E781478-814D-4A48-9D80-BFF206441A65}.Release Mono|x86.ActiveCfg = Release Mono|Any CPU
- {2E781478-814D-4A48-9D80-BFF206441A65}.Release Mono|x86.Build.0 = Release Mono|Any CPU
- {2E781478-814D-4A48-9D80-BFF206441A65}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {2E781478-814D-4A48-9D80-BFF206441A65}.Release|Any CPU.Build.0 = Release|Any CPU
- {2E781478-814D-4A48-9D80-BFF206441A65}.Release|x86.ActiveCfg = Release|Any CPU
- {2E781478-814D-4A48-9D80-BFF206441A65}.Release|x86.Build.0 = Release|Any CPU
- {2E781478-814D-4A48-9D80-BFF206441A65}.Signed|Any CPU.ActiveCfg = Release Mono|Any CPU
- {2E781478-814D-4A48-9D80-BFF206441A65}.Signed|Any CPU.Build.0 = Release Mono|Any CPU
- {2E781478-814D-4A48-9D80-BFF206441A65}.Signed|x86.ActiveCfg = Release Mono|Any CPU
- {2E781478-814D-4A48-9D80-BFF206441A65}.Signed|x86.Build.0 = Release Mono|Any CPU
{5624B7B5-B5A7-41D8-9F10-CC5611109619}.AppStore|Any CPU.ActiveCfg = Release|Any CPU
{5624B7B5-B5A7-41D8-9F10-CC5611109619}.AppStore|Any CPU.Build.0 = Release|Any CPU
{5624B7B5-B5A7-41D8-9F10-CC5611109619}.AppStore|x86.ActiveCfg = Release Mono|Any CPU
@@ -494,50 +446,6 @@ Global
{2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Signed|x64.Build.0 = Release|Any CPU
{2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Signed|x86.ActiveCfg = Release|Any CPU
{2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Signed|x86.Build.0 = Release|Any CPU
- {1E37A338-9F57-4B70-BD6D-BB9C591E319B}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
- {1E37A338-9F57-4B70-BD6D-BB9C591E319B}.AppStore|Any CPU.Build.0 = Debug|Any CPU
- {1E37A338-9F57-4B70-BD6D-BB9C591E319B}.AppStore|x86.ActiveCfg = Debug|Any CPU
- {1E37A338-9F57-4B70-BD6D-BB9C591E319B}.AppStore|x86.Build.0 = Debug|Any CPU
- {1E37A338-9F57-4B70-BD6D-BB9C591E319B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {1E37A338-9F57-4B70-BD6D-BB9C591E319B}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {1E37A338-9F57-4B70-BD6D-BB9C591E319B}.Debug|x86.ActiveCfg = Debug|Any CPU
- {1E37A338-9F57-4B70-BD6D-BB9C591E319B}.Debug|x86.Build.0 = Debug|Any CPU
- {1E37A338-9F57-4B70-BD6D-BB9C591E319B}.Release Mono|Any CPU.ActiveCfg = Debug|Any CPU
- {1E37A338-9F57-4B70-BD6D-BB9C591E319B}.Release Mono|Any CPU.Build.0 = Debug|Any CPU
- {1E37A338-9F57-4B70-BD6D-BB9C591E319B}.Release Mono|x86.ActiveCfg = Debug|Any CPU
- {1E37A338-9F57-4B70-BD6D-BB9C591E319B}.Release Mono|x86.Build.0 = Debug|Any CPU
- {1E37A338-9F57-4B70-BD6D-BB9C591E319B}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {1E37A338-9F57-4B70-BD6D-BB9C591E319B}.Release|Any CPU.Build.0 = Release|Any CPU
- {1E37A338-9F57-4B70-BD6D-BB9C591E319B}.Release|x86.ActiveCfg = Release|Any CPU
- {1E37A338-9F57-4B70-BD6D-BB9C591E319B}.Release|x86.Build.0 = Release|Any CPU
- {1E37A338-9F57-4B70-BD6D-BB9C591E319B}.Signed|Any CPU.ActiveCfg = Debug|Any CPU
- {1E37A338-9F57-4B70-BD6D-BB9C591E319B}.Signed|Any CPU.Build.0 = Debug|Any CPU
- {1E37A338-9F57-4B70-BD6D-BB9C591E319B}.Signed|x86.ActiveCfg = Debug|Any CPU
- {1E37A338-9F57-4B70-BD6D-BB9C591E319B}.Signed|x86.Build.0 = Debug|Any CPU
- {1E37A338-9F57-4B70-BD6D-BB9C591E319B}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
- {1E37A338-9F57-4B70-BD6D-BB9C591E319B}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
- {1E37A338-9F57-4B70-BD6D-BB9C591E319B}.Debug|Win32.ActiveCfg = Debug|Any CPU
- {1E37A338-9F57-4B70-BD6D-BB9C591E319B}.Debug|Win32.Build.0 = Debug|Any CPU
- {1E37A338-9F57-4B70-BD6D-BB9C591E319B}.Debug|x64.ActiveCfg = Debug|Any CPU
- {1E37A338-9F57-4B70-BD6D-BB9C591E319B}.Debug|x64.Build.0 = Debug|Any CPU
- {1E37A338-9F57-4B70-BD6D-BB9C591E319B}.Release Mono|Mixed Platforms.ActiveCfg = Debug|Any CPU
- {1E37A338-9F57-4B70-BD6D-BB9C591E319B}.Release Mono|Mixed Platforms.Build.0 = Debug|Any CPU
- {1E37A338-9F57-4B70-BD6D-BB9C591E319B}.Release Mono|Win32.ActiveCfg = Debug|Any CPU
- {1E37A338-9F57-4B70-BD6D-BB9C591E319B}.Release Mono|Win32.Build.0 = Debug|Any CPU
- {1E37A338-9F57-4B70-BD6D-BB9C591E319B}.Release Mono|x64.ActiveCfg = Debug|Any CPU
- {1E37A338-9F57-4B70-BD6D-BB9C591E319B}.Release Mono|x64.Build.0 = Debug|Any CPU
- {1E37A338-9F57-4B70-BD6D-BB9C591E319B}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
- {1E37A338-9F57-4B70-BD6D-BB9C591E319B}.Release|Mixed Platforms.Build.0 = Release|Any CPU
- {1E37A338-9F57-4B70-BD6D-BB9C591E319B}.Release|Win32.ActiveCfg = Release|Any CPU
- {1E37A338-9F57-4B70-BD6D-BB9C591E319B}.Release|Win32.Build.0 = Release|Any CPU
- {1E37A338-9F57-4B70-BD6D-BB9C591E319B}.Release|x64.ActiveCfg = Release|Any CPU
- {1E37A338-9F57-4B70-BD6D-BB9C591E319B}.Release|x64.Build.0 = Release|Any CPU
- {1E37A338-9F57-4B70-BD6D-BB9C591E319B}.Signed|Mixed Platforms.ActiveCfg = Debug|Any CPU
- {1E37A338-9F57-4B70-BD6D-BB9C591E319B}.Signed|Mixed Platforms.Build.0 = Debug|Any CPU
- {1E37A338-9F57-4B70-BD6D-BB9C591E319B}.Signed|Win32.ActiveCfg = Debug|Any CPU
- {1E37A338-9F57-4B70-BD6D-BB9C591E319B}.Signed|Win32.Build.0 = Debug|Any CPU
- {1E37A338-9F57-4B70-BD6D-BB9C591E319B}.Signed|x64.ActiveCfg = Debug|Any CPU
- {1E37A338-9F57-4B70-BD6D-BB9C591E319B}.Signed|x64.Build.0 = Debug|Any CPU
{1D74413B-E7CF-455B-B021-F52BDF881542}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
{1D74413B-E7CF-455B-B021-F52BDF881542}.AppStore|Any CPU.Build.0 = Debug|Any CPU
{1D74413B-E7CF-455B-B021-F52BDF881542}.AppStore|x86.ActiveCfg = Debug|Any CPU
@@ -582,50 +490,6 @@ Global
{1D74413B-E7CF-455B-B021-F52BDF881542}.Signed|Win32.Build.0 = Debug|Any CPU
{1D74413B-E7CF-455B-B021-F52BDF881542}.Signed|x64.ActiveCfg = Debug|Any CPU
{1D74413B-E7CF-455B-B021-F52BDF881542}.Signed|x64.Build.0 = Debug|Any CPU
- {776B9F0C-5195-45E3-9A36-1CC1F0D8E0B0}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
- {776B9F0C-5195-45E3-9A36-1CC1F0D8E0B0}.AppStore|Any CPU.Build.0 = Debug|Any CPU
- {776B9F0C-5195-45E3-9A36-1CC1F0D8E0B0}.AppStore|x86.ActiveCfg = Debug|Any CPU
- {776B9F0C-5195-45E3-9A36-1CC1F0D8E0B0}.AppStore|x86.Build.0 = Debug|Any CPU
- {776B9F0C-5195-45E3-9A36-1CC1F0D8E0B0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {776B9F0C-5195-45E3-9A36-1CC1F0D8E0B0}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {776B9F0C-5195-45E3-9A36-1CC1F0D8E0B0}.Debug|x86.ActiveCfg = Debug|Any CPU
- {776B9F0C-5195-45E3-9A36-1CC1F0D8E0B0}.Debug|x86.Build.0 = Debug|Any CPU
- {776B9F0C-5195-45E3-9A36-1CC1F0D8E0B0}.Release Mono|Any CPU.ActiveCfg = Debug|Any CPU
- {776B9F0C-5195-45E3-9A36-1CC1F0D8E0B0}.Release Mono|Any CPU.Build.0 = Debug|Any CPU
- {776B9F0C-5195-45E3-9A36-1CC1F0D8E0B0}.Release Mono|x86.ActiveCfg = Debug|Any CPU
- {776B9F0C-5195-45E3-9A36-1CC1F0D8E0B0}.Release Mono|x86.Build.0 = Debug|Any CPU
- {776B9F0C-5195-45E3-9A36-1CC1F0D8E0B0}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {776B9F0C-5195-45E3-9A36-1CC1F0D8E0B0}.Release|Any CPU.Build.0 = Release|Any CPU
- {776B9F0C-5195-45E3-9A36-1CC1F0D8E0B0}.Release|x86.ActiveCfg = Release|Any CPU
- {776B9F0C-5195-45E3-9A36-1CC1F0D8E0B0}.Release|x86.Build.0 = Release|Any CPU
- {776B9F0C-5195-45E3-9A36-1CC1F0D8E0B0}.Signed|Any CPU.ActiveCfg = Debug|Any CPU
- {776B9F0C-5195-45E3-9A36-1CC1F0D8E0B0}.Signed|Any CPU.Build.0 = Debug|Any CPU
- {776B9F0C-5195-45E3-9A36-1CC1F0D8E0B0}.Signed|x86.ActiveCfg = Debug|Any CPU
- {776B9F0C-5195-45E3-9A36-1CC1F0D8E0B0}.Signed|x86.Build.0 = Debug|Any CPU
- {776B9F0C-5195-45E3-9A36-1CC1F0D8E0B0}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
- {776B9F0C-5195-45E3-9A36-1CC1F0D8E0B0}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
- {776B9F0C-5195-45E3-9A36-1CC1F0D8E0B0}.Debug|Win32.ActiveCfg = Debug|Any CPU
- {776B9F0C-5195-45E3-9A36-1CC1F0D8E0B0}.Debug|Win32.Build.0 = Debug|Any CPU
- {776B9F0C-5195-45E3-9A36-1CC1F0D8E0B0}.Debug|x64.ActiveCfg = Debug|Any CPU
- {776B9F0C-5195-45E3-9A36-1CC1F0D8E0B0}.Debug|x64.Build.0 = Debug|Any CPU
- {776B9F0C-5195-45E3-9A36-1CC1F0D8E0B0}.Release Mono|Mixed Platforms.ActiveCfg = Debug|Any CPU
- {776B9F0C-5195-45E3-9A36-1CC1F0D8E0B0}.Release Mono|Mixed Platforms.Build.0 = Debug|Any CPU
- {776B9F0C-5195-45E3-9A36-1CC1F0D8E0B0}.Release Mono|Win32.ActiveCfg = Debug|Any CPU
- {776B9F0C-5195-45E3-9A36-1CC1F0D8E0B0}.Release Mono|Win32.Build.0 = Debug|Any CPU
- {776B9F0C-5195-45E3-9A36-1CC1F0D8E0B0}.Release Mono|x64.ActiveCfg = Debug|Any CPU
- {776B9F0C-5195-45E3-9A36-1CC1F0D8E0B0}.Release Mono|x64.Build.0 = Debug|Any CPU
- {776B9F0C-5195-45E3-9A36-1CC1F0D8E0B0}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
- {776B9F0C-5195-45E3-9A36-1CC1F0D8E0B0}.Release|Mixed Platforms.Build.0 = Release|Any CPU
- {776B9F0C-5195-45E3-9A36-1CC1F0D8E0B0}.Release|Win32.ActiveCfg = Release|Any CPU
- {776B9F0C-5195-45E3-9A36-1CC1F0D8E0B0}.Release|Win32.Build.0 = Release|Any CPU
- {776B9F0C-5195-45E3-9A36-1CC1F0D8E0B0}.Release|x64.ActiveCfg = Release|Any CPU
- {776B9F0C-5195-45E3-9A36-1CC1F0D8E0B0}.Release|x64.Build.0 = Release|Any CPU
- {776B9F0C-5195-45E3-9A36-1CC1F0D8E0B0}.Signed|Mixed Platforms.ActiveCfg = Debug|Any CPU
- {776B9F0C-5195-45E3-9A36-1CC1F0D8E0B0}.Signed|Mixed Platforms.Build.0 = Debug|Any CPU
- {776B9F0C-5195-45E3-9A36-1CC1F0D8E0B0}.Signed|Win32.ActiveCfg = Debug|Any CPU
- {776B9F0C-5195-45E3-9A36-1CC1F0D8E0B0}.Signed|Win32.Build.0 = Debug|Any CPU
- {776B9F0C-5195-45E3-9A36-1CC1F0D8E0B0}.Signed|x64.ActiveCfg = Debug|Any CPU
- {776B9F0C-5195-45E3-9A36-1CC1F0D8E0B0}.Signed|x64.Build.0 = Debug|Any CPU
{CB7F2326-6497-4A3D-BA03-48513B17A7BE}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
{CB7F2326-6497-4A3D-BA03-48513B17A7BE}.AppStore|Any CPU.Build.0 = Debug|Any CPU
{CB7F2326-6497-4A3D-BA03-48513B17A7BE}.AppStore|x86.ActiveCfg = Debug|Any CPU
diff --git a/MediaBrowser.Server.Mac/Emby.Server.Mac.csproj b/MediaBrowser.Server.Mac/Emby.Server.Mac.csproj
index 196bdd096..3ec880a77 100644
--- a/MediaBrowser.Server.Mac/Emby.Server.Mac.csproj
+++ b/MediaBrowser.Server.Mac/Emby.Server.Mac.csproj
@@ -92,10 +92,6 @@
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\Mono.Posix.4.0.0.0\lib\net40\Mono.Posix.dll</HintPath>
</Reference>
- <Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
- <HintPath>..\packages\NLog.4.4.11\lib\net45\NLog.dll</HintPath>
- <Private>True</Private>
- </Reference>
<Reference Include="ServiceStack.Text, Version=4.5.8.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\ServiceStack.Text.4.5.8\lib\net45\ServiceStack.Text.dll</HintPath>
<Private>True</Private>
@@ -116,10 +112,10 @@
<HintPath>..\packages\SkiaSharp.1.58.0\lib\net45\SkiaSharp.dll</HintPath>
</Reference>
<Reference Include="SQLitePCLRaw.core">
- <HintPath>..\packages\SQLitePCLRaw.core.1.1.7\lib\net45\SQLitePCLRaw.core.dll</HintPath>
+ <HintPath>..\packages\SQLitePCLRaw.core.1.1.8\lib\net45\SQLitePCLRaw.core.dll</HintPath>
</Reference>
<Reference Include="SQLitePCLRaw.provider.sqlite3">
- <HintPath>..\packages\SQLitePCLRaw.provider.sqlite3.net45.1.1.7\lib\net45\SQLitePCLRaw.provider.sqlite3.dll</HintPath>
+ <HintPath>..\packages\SQLitePCLRaw.provider.sqlite3.net45.1.1.8\lib\net45\SQLitePCLRaw.provider.sqlite3.dll</HintPath>
</Reference>
<Reference Include="Emby.Server.Connect">
<HintPath>..\ThirdParty\emby\Emby.Server.Connect.dll</HintPath>
@@ -130,6 +126,9 @@
<Reference Include="Emby.Server.CinemaMode">
<HintPath>..\ThirdParty\emby\Emby.Server.CinemaMode.dll</HintPath>
</Reference>
+ <Reference Include="Emby.Server.MediaEncoding">
+ <HintPath>..\ThirdParty\emby\Emby.Server.MediaEncoding.dll</HintPath>
+ </Reference>
</ItemGroup>
<ItemGroup>
<Folder Include="Resources\" />
@@ -182,10 +181,6 @@
<Project>{7EF9F3E0-697D-42F3-A08F-19DEB5F84392}</Project>
<Name>MediaBrowser.LocalMetadata</Name>
</ProjectReference>
- <ProjectReference Include="..\MediaBrowser.MediaEncoding\MediaBrowser.MediaEncoding.csproj">
- <Project>{0BD82FA6-EB8A-4452-8AF5-74F9C3849451}</Project>
- <Name>MediaBrowser.MediaEncoding</Name>
- </ProjectReference>
<ProjectReference Include="..\MediaBrowser.Providers\MediaBrowser.Providers.csproj">
<Project>{442B5058-DCAF-4263-BB6A-F21E31120A1B}</Project>
<Name>MediaBrowser.Providers</Name>
@@ -246,10 +241,6 @@
<Project>{1D74413B-E7CF-455B-B021-F52BDF881542}</Project>
<Name>SocketHttpListener</Name>
</ProjectReference>
- <ProjectReference Include="..\Emby.Server.Core\Emby.Server.Core.csproj">
- <Project>{776B9F0C-5195-45E3-9A36-1CC1F0D8E0B0}</Project>
- <Name>Emby.Server.Core</Name>
- </ProjectReference>
<ProjectReference Include="..\Mono.Nat\Mono.Nat.csproj">
<Project>{CB7F2326-6497-4A3D-BA03-48513B17A7BE}</Project>
<Name>Mono.Nat</Name>
@@ -270,12 +261,6 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\autoorganizelog.html">
<Link>Resources\dashboard-ui\autoorganizelog.html</Link>
</BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\autoorganizesmart.html">
- <Link>Resources\dashboard-ui\autoorganizesmart.html</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\autoorganizetv.html">
- <Link>Resources\dashboard-ui\autoorganizetv.html</Link>
- </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\camerauploadsettings.html">
<Link>Resources\dashboard-ui\camerauploadsettings.html</Link>
</BundleResource>
@@ -729,9 +714,6 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\globalize.js">
<Link>Resources\dashboard-ui\bower_components\emby-webcomponents\globalize.js</Link>
</BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\homesections.js">
- <Link>Resources\dashboard-ui\bower_components\emby-webcomponents\homesections.js</Link>
- </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\idb.js">
<Link>Resources\dashboard-ui\bower_components\emby-webcomponents\idb.js</Link>
</BundleResource>
@@ -747,6 +729,9 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\layoutmanager.js">
<Link>Resources\dashboard-ui\bower_components\emby-webcomponents\layoutmanager.js</Link>
</BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\maintabsmanager.js">
+ <Link>Resources\dashboard-ui\bower_components\emby-webcomponents\maintabsmanager.js</Link>
+ </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\multidownload.js">
<Link>Resources\dashboard-ui\bower_components\emby-webcomponents\multidownload.js</Link>
</BundleResource>
@@ -786,6 +771,9 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\shortcuts.js">
<Link>Resources\dashboard-ui\bower_components\emby-webcomponents\shortcuts.js</Link>
</BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\skinmanager.js">
+ <Link>Resources\dashboard-ui\bower_components\emby-webcomponents\skinmanager.js</Link>
+ </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\staticbackdrops.js">
<Link>Resources\dashboard-ui\bower_components\emby-webcomponents\staticbackdrops.js</Link>
</BundleResource>
@@ -852,9 +840,6 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\confirm\nativeconfirm.js">
<Link>Resources\dashboard-ui\bower_components\emby-webcomponents\confirm\nativeconfirm.js</Link>
</BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\dialog\dialog.css">
- <Link>Resources\dashboard-ui\bower_components\emby-webcomponents\dialog\dialog.css</Link>
- </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\dialog\dialog.js">
<Link>Resources\dashboard-ui\bower_components\emby-webcomponents\dialog\dialog.js</Link>
</BundleResource>
@@ -897,9 +882,6 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\emby-input\emby-input.js">
<Link>Resources\dashboard-ui\bower_components\emby-webcomponents\emby-input\emby-input.js</Link>
</BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\emby-itemrefreshindicator\emby-itemrefreshindicator.css">
- <Link>Resources\dashboard-ui\bower_components\emby-webcomponents\emby-itemrefreshindicator\emby-itemrefreshindicator.css</Link>
- </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\emby-itemrefreshindicator\emby-itemrefreshindicator.js">
<Link>Resources\dashboard-ui\bower_components\emby-webcomponents\emby-itemrefreshindicator\emby-itemrefreshindicator.js</Link>
</BundleResource>
@@ -954,6 +936,15 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\emby-textarea\emby-textarea.js">
<Link>Resources\dashboard-ui\bower_components\emby-webcomponents\emby-textarea\emby-textarea.js</Link>
</BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\flvjs\flv.min.js">
+ <Link>Resources\dashboard-ui\bower_components\emby-webcomponents\flvjs\flv.min.js</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\fonts\fonts.css">
+ <Link>Resources\dashboard-ui\bower_components\emby-webcomponents\fonts\fonts.css</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\fonts\fonts.sized.css">
+ <Link>Resources\dashboard-ui\bower_components\emby-webcomponents\fonts\fonts.sized.css</Link>
+ </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\fonts\material-icons\2fcryfnatjcs6g4u3t-y5ewrjpiaoeww8aihgqwrjao.woff">
<Link>Resources\dashboard-ui\bower_components\emby-webcomponents\fonts\material-icons\2fcryfnatjcs6g4u3t-y5ewrjpiaoeww8aihgqwrjao.woff</Link>
</BundleResource>
@@ -1005,6 +996,12 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\homescreensettings\homescreensettingsdialog.template.html">
<Link>Resources\dashboard-ui\bower_components\emby-webcomponents\homescreensettings\homescreensettingsdialog.template.html</Link>
</BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\homesections\homesections.css">
+ <Link>Resources\dashboard-ui\bower_components\emby-webcomponents\homesections\homesections.css</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\homesections\homesections.js">
+ <Link>Resources\dashboard-ui\bower_components\emby-webcomponents\homesections\homesections.js</Link>
+ </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\htmlaudioplayer\blank.mp3">
<Link>Resources\dashboard-ui\bower_components\emby-webcomponents\htmlaudioplayer\blank.mp3</Link>
</BundleResource>
@@ -1164,6 +1161,9 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\playback\brightnessosd.js">
<Link>Resources\dashboard-ui\bower_components\emby-webcomponents\playback\brightnessosd.js</Link>
</BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\playback\experimentalwarnings.js">
+ <Link>Resources\dashboard-ui\bower_components\emby-webcomponents\playback\experimentalwarnings.js</Link>
+ </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\playback\iconosd.css">
<Link>Resources\dashboard-ui\bower_components\emby-webcomponents\playback\iconosd.css</Link>
</BundleResource>
@@ -1275,9 +1275,6 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\registrationservices\registrationservices.js">
<Link>Resources\dashboard-ui\bower_components\emby-webcomponents\registrationservices\registrationservices.js</Link>
</BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\registrationservices\style.css">
- <Link>Resources\dashboard-ui\bower_components\emby-webcomponents\registrationservices\style.css</Link>
- </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\require\requirecss.js">
<Link>Resources\dashboard-ui\bower_components\emby-webcomponents\require\requirecss.js</Link>
</BundleResource>
@@ -1506,6 +1503,72 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\sync\syncjoblist.js">
<Link>Resources\dashboard-ui\bower_components\emby-webcomponents\sync\syncjoblist.js</Link>
</BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\themes\appletv\logo.png">
+ <Link>Resources\dashboard-ui\bower_components\emby-webcomponents\themes\appletv\logo.png</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\themes\appletv\theme.css">
+ <Link>Resources\dashboard-ui\bower_components\emby-webcomponents\themes\appletv\theme.css</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\themes\dark\logo.png">
+ <Link>Resources\dashboard-ui\bower_components\emby-webcomponents\themes\dark\logo.png</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\themes\dark\theme.css">
+ <Link>Resources\dashboard-ui\bower_components\emby-webcomponents\themes\dark\theme.css</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\themes\dark-green\logo.png">
+ <Link>Resources\dashboard-ui\bower_components\emby-webcomponents\themes\dark-green\logo.png</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\themes\dark-green\theme.css">
+ <Link>Resources\dashboard-ui\bower_components\emby-webcomponents\themes\dark-green\theme.css</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\themes\dark-red\logo.png">
+ <Link>Resources\dashboard-ui\bower_components\emby-webcomponents\themes\dark-red\logo.png</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\themes\dark-red\theme.css">
+ <Link>Resources\dashboard-ui\bower_components\emby-webcomponents\themes\dark-red\theme.css</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\themes\light\logo.png">
+ <Link>Resources\dashboard-ui\bower_components\emby-webcomponents\themes\light\logo.png</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\themes\light\theme.css">
+ <Link>Resources\dashboard-ui\bower_components\emby-webcomponents\themes\light\theme.css</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\themes\light-blue\logo.png">
+ <Link>Resources\dashboard-ui\bower_components\emby-webcomponents\themes\light-blue\logo.png</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\themes\light-blue\theme.css">
+ <Link>Resources\dashboard-ui\bower_components\emby-webcomponents\themes\light-blue\theme.css</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\themes\light-green\logo.png">
+ <Link>Resources\dashboard-ui\bower_components\emby-webcomponents\themes\light-green\logo.png</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\themes\light-green\theme.css">
+ <Link>Resources\dashboard-ui\bower_components\emby-webcomponents\themes\light-green\theme.css</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\themes\light-pink\logo.png">
+ <Link>Resources\dashboard-ui\bower_components\emby-webcomponents\themes\light-pink\logo.png</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\themes\light-pink\theme.css">
+ <Link>Resources\dashboard-ui\bower_components\emby-webcomponents\themes\light-pink\theme.css</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\themes\light-purple\logo.png">
+ <Link>Resources\dashboard-ui\bower_components\emby-webcomponents\themes\light-purple\logo.png</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\themes\light-purple\theme.css">
+ <Link>Resources\dashboard-ui\bower_components\emby-webcomponents\themes\light-purple\theme.css</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\themes\light-red\logo.png">
+ <Link>Resources\dashboard-ui\bower_components\emby-webcomponents\themes\light-red\logo.png</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\themes\light-red\theme.css">
+ <Link>Resources\dashboard-ui\bower_components\emby-webcomponents\themes\light-red\theme.css</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\themes\wmc\logo.png">
+ <Link>Resources\dashboard-ui\bower_components\emby-webcomponents\themes\wmc\logo.png</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\themes\wmc\theme.css">
+ <Link>Resources\dashboard-ui\bower_components\emby-webcomponents\themes\wmc\theme.css</Link>
+ </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\toast\toast.css">
<Link>Resources\dashboard-ui\bower_components\emby-webcomponents\toast\toast.css</Link>
</BundleResource>
@@ -1728,12 +1791,6 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\components\dockedtabs\dockedtabs.js">
<Link>Resources\dashboard-ui\components\dockedtabs\dockedtabs.js</Link>
</BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\components\fileorganizer\fileorganizer.js">
- <Link>Resources\dashboard-ui\components\fileorganizer\fileorganizer.js</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\components\fileorganizer\fileorganizer.template.html">
- <Link>Resources\dashboard-ui\components\fileorganizer\fileorganizer.template.html</Link>
- </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\components\filterdialog\filterdialog.js">
<Link>Resources\dashboard-ui\components\filterdialog\filterdialog.js</Link>
</BundleResource>
@@ -1797,9 +1854,6 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\components\tvproviders\xmltv.template.html">
<Link>Resources\dashboard-ui\components\tvproviders\xmltv.template.html</Link>
</BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\css\autoorganizetable.css">
- <Link>Resources\dashboard-ui\css\autoorganizetable.css</Link>
- </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\css\dashboard.css">
<Link>Resources\dashboard-ui\css\dashboard.css</Link>
</BundleResource>
@@ -2058,15 +2112,6 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\dashboard\aboutpage.js">
<Link>Resources\dashboard-ui\dashboard\aboutpage.js</Link>
</BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\dashboard\autoorganizelog.js">
- <Link>Resources\dashboard-ui\dashboard\autoorganizelog.js</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\dashboard\autoorganizesmart.js">
- <Link>Resources\dashboard-ui\dashboard\autoorganizesmart.js</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\dashboard\autoorganizetv.js">
- <Link>Resources\dashboard-ui\dashboard\autoorganizetv.js</Link>
- </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\dashboard\cinemamodeconfiguration.js">
<Link>Resources\dashboard-ui\dashboard\cinemamodeconfiguration.js</Link>
</BundleResource>
@@ -2391,6 +2436,9 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\taskbutton.js">
<Link>Resources\dashboard-ui\scripts\taskbutton.js</Link>
</BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\themeloader.js">
+ <Link>Resources\dashboard-ui\scripts\themeloader.js</Link>
+ </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\tvgenres.js">
<Link>Resources\dashboard-ui\scripts\tvgenres.js</Link>
</BundleResource>
@@ -2502,9 +2550,6 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\strings\fr-ca.json">
<Link>Resources\dashboard-ui\strings\fr-ca.json</Link>
</BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\strings\fr-fr.json">
- <Link>Resources\dashboard-ui\strings\fr-fr.json</Link>
- </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\strings\fr.json">
<Link>Resources\dashboard-ui\strings\fr.json</Link>
</BundleResource>
@@ -2601,9 +2646,6 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\themes\holiday\theme.js">
<Link>Resources\dashboard-ui\themes\holiday\theme.js</Link>
</BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\thirdparty\jquerymobile-1.4.5\jqm.listview.css">
- <Link>Resources\dashboard-ui\thirdparty\jquerymobile-1.4.5\jqm.listview.css</Link>
- </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\thirdparty\jquerymobile-1.4.5\jqm.panel.css">
<Link>Resources\dashboard-ui\thirdparty\jquerymobile-1.4.5\jqm.panel.css</Link>
</BundleResource>
@@ -2616,18 +2658,6 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\thirdparty\jquerymobile-1.4.5\jqm.popup.js">
<Link>Resources\dashboard-ui\thirdparty\jquerymobile-1.4.5\jqm.popup.js</Link>
</BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\thirdparty\jquerymobile-1.4.5\jqm.slider.css">
- <Link>Resources\dashboard-ui\thirdparty\jquerymobile-1.4.5\jqm.slider.css</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\thirdparty\jquerymobile-1.4.5\jqm.slider.js">
- <Link>Resources\dashboard-ui\thirdparty\jquerymobile-1.4.5\jqm.slider.js</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\thirdparty\jquerymobile-1.4.5\jqm.table.css">
- <Link>Resources\dashboard-ui\thirdparty\jquerymobile-1.4.5\jqm.table.css</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\thirdparty\jquerymobile-1.4.5\jqm.table.js">
- <Link>Resources\dashboard-ui\thirdparty\jquerymobile-1.4.5\jqm.table.js</Link>
- </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\thirdparty\jquerymobile-1.4.5\jqm.widget.js">
<Link>Resources\dashboard-ui\thirdparty\jquerymobile-1.4.5\jqm.widget.js</Link>
</BundleResource>
diff --git a/MediaBrowser.Server.Mac/MacAppHost.cs b/MediaBrowser.Server.Mac/MacAppHost.cs
index 2f8ee983c..7ad96d2bf 100644
--- a/MediaBrowser.Server.Mac/MacAppHost.cs
+++ b/MediaBrowser.Server.Mac/MacAppHost.cs
@@ -19,11 +19,11 @@ namespace MediaBrowser.Server.Mac
{
public class MacAppHost : ApplicationHost
{
- public MacAppHost(ServerApplicationPaths applicationPaths, ILogManager logManager, StartupOptions options, IFileSystem fileSystem, IPowerManagement powerManagement, string releaseAssetFilename, IEnvironmentInfo environmentInfo, MediaBrowser.Controller.Drawing.IImageEncoder imageEncoder, ISystemEvents systemEvents, IMemoryStreamFactory memoryStreamFactory, MediaBrowser.Common.Net.INetworkManager networkManager, Action<string, string, string> certificateGenerator, Func<string> defaultUsernameFactory) : base(applicationPaths, logManager, options, fileSystem, powerManagement, releaseAssetFilename, environmentInfo, imageEncoder, systemEvents, memoryStreamFactory, networkManager, certificateGenerator, defaultUsernameFactory)
+ public MacAppHost(ServerApplicationPaths applicationPaths, ILogManager logManager, StartupOptions options, IFileSystem fileSystem, IPowerManagement powerManagement, string releaseAssetFilename, IEnvironmentInfo environmentInfo, MediaBrowser.Controller.Drawing.IImageEncoder imageEncoder, ISystemEvents systemEvents, MediaBrowser.Common.Net.INetworkManager networkManager) : base(applicationPaths, logManager, options, fileSystem, powerManagement, releaseAssetFilename, environmentInfo, imageEncoder, systemEvents, networkManager)
{
}
- public override bool CanSelfRestart
+ public override bool CanSelfRestart
{
get
{
diff --git a/MediaBrowser.Server.Mac/Main.cs b/MediaBrowser.Server.Mac/Main.cs
index d84d696dd..6af58e66c 100644
--- a/MediaBrowser.Server.Mac/Main.cs
+++ b/MediaBrowser.Server.Mac/Main.cs
@@ -1,5 +1,4 @@
using MediaBrowser.Model.Logging;
-using MediaBrowser.Server.Implementations;
using System;
using System.Diagnostics;
using System.Globalization;
@@ -19,23 +18,19 @@ using MonoMac.Foundation;
using MonoMac.ObjCRuntime;
using Emby.Server.Core;
using Emby.Server.Core.Cryptography;
-using Emby.Server.Core.IO;
using Emby.Server.Implementations;
-using Emby.Common.Implementations.Logging;
using Emby.Server.Implementations.Logging;
-using Emby.Common.Implementations.EnvironmentInfo;
using Emby.Server.Mac.Native;
using Emby.Server.Implementations.IO;
-using Emby.Common.Implementations.Networking;
-using Emby.Common.Implementations.Cryptography;
using Mono.Unix.Native;
using MediaBrowser.Model.System;
using MediaBrowser.Model.IO;
-using Emby.Server.Core.Logging;
using Emby.Drawing;
using Emby.Drawing.Skia;
using MediaBrowser.Controller.Drawing;
using MediaBrowser.Model.Drawing;
+using Emby.Server.Implementations.EnvironmentInfo;
+using Emby.Server.Implementations.Networking;
namespace MediaBrowser.Server.Mac
{
@@ -61,20 +56,22 @@ namespace MediaBrowser.Server.Mac
var appPaths = CreateApplicationPaths(appFolderPath, customProgramDataPath);
- var logManager = new NlogManager(appPaths.LogDirectoryPath, "server");
- logManager.ReloadLogger(LogSeverity.Info);
- logManager.AddConsoleOutput();
+ using (var logManager = new SimpleLogManager(appPaths.LogDirectoryPath, "server"))
+ {
+ logManager.ReloadLogger(LogSeverity.Info);
+ logManager.AddConsoleOutput();
- var logger = _logger = logManager.GetLogger("Main");
+ var logger = _logger = logManager.GetLogger("Main");
- ApplicationHost.LogEnvironmentInfo(logger, appPaths, true);
+ ApplicationHost.LogEnvironmentInfo(logger, appPaths, true);
- AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
+ AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
- StartApplication(appPaths, logManager, options);
- NSApplication.Init ();
- NSApplication.Main (args);
- }
+ StartApplication(appPaths, logManager, options);
+ NSApplication.Init();
+ NSApplication.Main(args);
+ }
+ }
private static ServerApplicationPaths CreateApplicationPaths(string appFolderPath, string programDataPath)
{
@@ -91,9 +88,7 @@ namespace MediaBrowser.Server.Mac
// Within the mac bundle, go uo two levels then down into Resources folder
var resourcesPath = Path.Combine(Path.GetDirectoryName(appFolderPath), "Resources");
- Action<string> createDirectoryFn = (string obj) => Directory.CreateDirectory(obj);
-
- return new ServerApplicationPaths(programDataPath, appFolderPath, resourcesPath, createDirectoryFn);
+ return new ServerApplicationPaths(programDataPath, appFolderPath, resourcesPath);
}
/// <summary>
@@ -125,11 +120,8 @@ namespace MediaBrowser.Server.Mac
"Emby.Server.Mac.pkg",
environmentInfo,
imageEncoder,
- new Startup.Common.SystemEvents(logManager.GetLogger("SystemEvents")),
- new MemoryStreamProvider(),
- new NetworkManager(logManager.GetLogger("NetworkManager")),
- GenerateCertificate,
- () => Environment.UserName);
+ new SystemEvents(logManager.GetLogger("SystemEvents")),
+ new NetworkManager(logManager.GetLogger("NetworkManager")));
if (options.ContainsOption("-v")) {
Console.WriteLine (AppHost.ApplicationVersion.ToString());
@@ -153,16 +145,11 @@ namespace MediaBrowser.Server.Mac
}
}
- private static void GenerateCertificate(string certPath, string certHost, string certPassword)
- {
- CertificateGenerator.CreateSelfSignCertificatePfx(certPath, certHost, certPassword, _logger);
- }
-
private static EnvironmentInfo GetEnvironmentInfo()
{
var info = new EnvironmentInfo()
{
- CustomOperatingSystem = MediaBrowser.Model.System.OperatingSystem.OSX
+ OperatingSystem = MediaBrowser.Model.System.OperatingSystem.OSX
};
var uname = GetUnixName();
@@ -187,23 +174,23 @@ namespace MediaBrowser.Server.Mac
if (archX86.IsMatch(uname.machine))
{
- info.CustomArchitecture = Architecture.X86;
+ info.SystemArchitecture = Architecture.X86;
}
else if (string.Equals(uname.machine, "x86_64", StringComparison.OrdinalIgnoreCase))
{
- info.CustomArchitecture = Architecture.X64;
+ info.SystemArchitecture = Architecture.X64;
}
else if (uname.machine.StartsWith("arm", StringComparison.OrdinalIgnoreCase))
{
- info.CustomArchitecture = Architecture.Arm;
+ info.SystemArchitecture = Architecture.Arm;
}
else if (System.Environment.Is64BitOperatingSystem)
{
- info.CustomArchitecture = Architecture.X64;
+ info.SystemArchitecture = Architecture.X64;
}
else
{
- info.CustomArchitecture = Architecture.X86;
+ info.SystemArchitecture = Architecture.X86;
}
return info;
diff --git a/MediaBrowser.Server.Mac/Native/MonoFileSystem.cs b/MediaBrowser.Server.Mac/Native/MonoFileSystem.cs
index 7aeff5ac8..1fd140fb9 100644
--- a/MediaBrowser.Server.Mac/Native/MonoFileSystem.cs
+++ b/MediaBrowser.Server.Mac/Native/MonoFileSystem.cs
@@ -1,4 +1,4 @@
-using Emby.Common.Implementations.IO;
+using Emby.Server.Implementations.IO;
using MediaBrowser.Model.Logging;
using Mono.Unix.Native;
using MediaBrowser.Model.System;
diff --git a/Emby.Server.Core/ApplicationPathHelper.cs b/MediaBrowser.Server.Mono/ApplicationPathHelper.cs
index e83d5444a..c8cca40ff 100644
--- a/Emby.Server.Core/ApplicationPathHelper.cs
+++ b/MediaBrowser.Server.Mono/ApplicationPathHelper.cs
@@ -2,7 +2,7 @@
using System.Configuration;
using System.IO;
-namespace Emby.Server.Core
+namespace MediaBrowser.Server.Mono
{
public static class ApplicationPathHelper
{
diff --git a/MediaBrowser.Server.Mono/MediaBrowser.Server.Mono.csproj b/MediaBrowser.Server.Mono/MediaBrowser.Server.Mono.csproj
index df98c6584..d2ce0b40d 100644
--- a/MediaBrowser.Server.Mono/MediaBrowser.Server.Mono.csproj
+++ b/MediaBrowser.Server.Mono/MediaBrowser.Server.Mono.csproj
@@ -51,10 +51,6 @@
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\Mono.Posix.4.0.0.0\lib\net40\Mono.Posix.dll</HintPath>
</Reference>
- <Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
- <HintPath>..\packages\NLog.4.4.11\lib\net45\NLog.dll</HintPath>
- <Private>True</Private>
- </Reference>
<Reference Include="ServiceStack.Text, Version=4.5.8.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\ServiceStack.Text.4.5.8\lib\net45\ServiceStack.Text.dll</HintPath>
<Private>True</Private>
@@ -67,16 +63,13 @@
<HintPath>..\packages\SimpleInjector.4.0.8\lib\net45\SimpleInjector.dll</HintPath>
</Reference>
<Reference Include="SkiaSharp, Version=1.58.0.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756, processorArchitecture=MSIL">
- <HintPath>..\packages\SkiaSharp.1.58.0\lib\net45\SkiaSharp.dll</HintPath>
- <Private>True</Private>
+ <HintPath>..\packages\SkiaSharp.1.58.1\lib\net45\SkiaSharp.dll</HintPath>
</Reference>
<Reference Include="SQLitePCLRaw.core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1488e028ca7ab535, processorArchitecture=MSIL">
- <HintPath>..\packages\SQLitePCLRaw.core.1.1.7\lib\net45\SQLitePCLRaw.core.dll</HintPath>
- <Private>True</Private>
+ <HintPath>..\packages\SQLitePCLRaw.core.1.1.8\lib\net45\SQLitePCLRaw.core.dll</HintPath>
</Reference>
<Reference Include="SQLitePCLRaw.provider.sqlite3, Version=1.0.0.0, Culture=neutral, PublicKeyToken=62684c7b4f184e3f, processorArchitecture=MSIL">
- <HintPath>..\packages\SQLitePCLRaw.provider.sqlite3.net45.1.1.7\lib\net45\SQLitePCLRaw.provider.sqlite3.dll</HintPath>
- <Private>True</Private>
+ <HintPath>..\packages\SQLitePCLRaw.provider.sqlite3.net45.1.1.8\lib\net45\SQLitePCLRaw.provider.sqlite3.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="MediaBrowser.IsoMounting.Linux">
@@ -92,6 +85,7 @@
<Compile Include="..\SharedVersion.cs">
<Link>Properties\SharedVersion.cs</Link>
</Compile>
+ <Compile Include="ApplicationPathHelper.cs" />
<Compile Include="ImageEncoderHelper.cs" />
<Compile Include="MonoAppHost.cs" />
<Compile Include="Native\MonoFileSystem.cs" />
@@ -109,10 +103,6 @@
<Project>{713f42b5-878e-499d-a878-e4c652b1d5e8}</Project>
<Name>DvdLib</Name>
</ProjectReference>
- <ProjectReference Include="..\Emby.Common.Implementations\Emby.Common.Implementations.csproj">
- <Project>{1e37a338-9f57-4b70-bd6d-bb9c591e319b}</Project>
- <Name>Emby.Common.Implementations</Name>
- </ProjectReference>
<ProjectReference Include="..\Emby.Dlna\Emby.Dlna.csproj">
<Project>{805844ab-e92f-45e6-9d99-4f6d48d129a5}</Project>
<Name>Emby.Dlna</Name>
@@ -133,10 +123,6 @@
<Project>{89ab4548-770d-41fd-a891-8daff44f452c}</Project>
<Name>Emby.Photos</Name>
</ProjectReference>
- <ProjectReference Include="..\Emby.Server.Core\Emby.Server.Core.csproj">
- <Project>{776b9f0c-5195-45e3-9a36-1cc1f0d8e0b0}</Project>
- <Name>Emby.Server.Core</Name>
- </ProjectReference>
<ProjectReference Include="..\Emby.Server.Implementations\Emby.Server.Implementations.csproj">
<Project>{e383961b-9356-4d5d-8233-9a1079d03055}</Project>
<Name>Emby.Server.Implementations</Name>
@@ -145,10 +131,6 @@
<Project>{5624B7B5-B5A7-41D8-9F10-CC5611109619}</Project>
<Name>MediaBrowser.WebDashboard</Name>
</ProjectReference>
- <ProjectReference Include="..\MediaBrowser.Server.Implementations\MediaBrowser.Server.Implementations.csproj">
- <Project>{2E781478-814D-4A48-9D80-BFF206441A65}</Project>
- <Name>MediaBrowser.Server.Implementations</Name>
- </ProjectReference>
<ProjectReference Include="..\MediaBrowser.Providers\MediaBrowser.Providers.csproj">
<Project>{442B5058-DCAF-4263-BB6A-F21E31120A1B}</Project>
<Name>MediaBrowser.Providers</Name>
@@ -169,10 +151,6 @@
<Project>{4FD51AC5-2C16-4308-A993-C3A84F3B4582}</Project>
<Name>MediaBrowser.Api</Name>
</ProjectReference>
- <ProjectReference Include="..\MediaBrowser.MediaEncoding\MediaBrowser.MediaEncoding.csproj">
- <Project>{0BD82FA6-EB8A-4452-8AF5-74F9C3849451}</Project>
- <Name>MediaBrowser.MediaEncoding</Name>
- </ProjectReference>
<ProjectReference Include="..\MediaBrowser.LocalMetadata\MediaBrowser.LocalMetadata.csproj">
<Project>{7EF9F3E0-697D-42F3-A08F-19DEB5F84392}</Project>
<Name>MediaBrowser.LocalMetadata</Name>
diff --git a/MediaBrowser.Server.Mono/MonoAppHost.cs b/MediaBrowser.Server.Mono/MonoAppHost.cs
index 1153d0f7d..ded7bb5f3 100644
--- a/MediaBrowser.Server.Mono/MonoAppHost.cs
+++ b/MediaBrowser.Server.Mono/MonoAppHost.cs
@@ -12,14 +12,12 @@ using MediaBrowser.IsoMounter;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.System;
-using MediaBrowser.Model.Updates;
-using MediaBrowser.Server.Startup.Common;
namespace MediaBrowser.Server.Mono
{
public class MonoAppHost : ApplicationHost
{
- public MonoAppHost(ServerApplicationPaths applicationPaths, ILogManager logManager, StartupOptions options, IFileSystem fileSystem, IPowerManagement powerManagement, string releaseAssetFilename, IEnvironmentInfo environmentInfo, MediaBrowser.Controller.Drawing.IImageEncoder imageEncoder, ISystemEvents systemEvents, IMemoryStreamFactory memoryStreamFactory, MediaBrowser.Common.Net.INetworkManager networkManager, Action<string, string, string> certificateGenerator, Func<string> defaultUsernameFactory) : base(applicationPaths, logManager, options, fileSystem, powerManagement, releaseAssetFilename, environmentInfo, imageEncoder, systemEvents, memoryStreamFactory, networkManager, certificateGenerator, defaultUsernameFactory)
+ public MonoAppHost(ServerApplicationPaths applicationPaths, ILogManager logManager, StartupOptions options, IFileSystem fileSystem, IPowerManagement powerManagement, string releaseAssetFilename, IEnvironmentInfo environmentInfo, MediaBrowser.Controller.Drawing.IImageEncoder imageEncoder, ISystemEvents systemEvents, MediaBrowser.Common.Net.INetworkManager networkManager) : base(applicationPaths, logManager, options, fileSystem, powerManagement, releaseAssetFilename, environmentInfo, imageEncoder, systemEvents, networkManager)
{
}
@@ -44,7 +42,7 @@ namespace MediaBrowser.Server.Mono
protected override void RestartInternal()
{
- MainClass.Restart(StartupOptions);
+ MainClass.Restart();
}
protected override List<Assembly> GetAssembliesWithPartsInternal()
diff --git a/MediaBrowser.Server.Mono/Native/MonoFileSystem.cs b/MediaBrowser.Server.Mono/Native/MonoFileSystem.cs
index 91c064efe..e6b77991c 100644
--- a/MediaBrowser.Server.Mono/Native/MonoFileSystem.cs
+++ b/MediaBrowser.Server.Mono/Native/MonoFileSystem.cs
@@ -1,4 +1,4 @@
-using Emby.Common.Implementations.IO;
+using Emby.Server.Implementations.IO;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.System;
using Mono.Unix.Native;
diff --git a/MediaBrowser.Server.Mono/Program.cs b/MediaBrowser.Server.Mono/Program.cs
index 0a70c446f..98ad8bb02 100644
--- a/MediaBrowser.Server.Mono/Program.cs
+++ b/MediaBrowser.Server.Mono/Program.cs
@@ -11,20 +11,16 @@ using System.Net.Security;
using System.Reflection;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
-using Emby.Common.Implementations.EnvironmentInfo;
-using Emby.Common.Implementations.Logging;
-using Emby.Common.Implementations.Networking;
using Emby.Server.Core.Cryptography;
using Emby.Server.Core;
-using Emby.Server.Core.IO;
-using Emby.Server.Core.Logging;
using Emby.Server.Implementations;
+using Emby.Server.Implementations.EnvironmentInfo;
using Emby.Server.Implementations.IO;
using Emby.Server.Implementations.Logging;
+using Emby.Server.Implementations.Networking;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.System;
using Mono.Unix.Native;
-using NLog;
using ILogger = MediaBrowser.Model.Logging.ILogger;
using X509Certificate = System.Security.Cryptography.X509Certificates.X509Certificate;
@@ -37,6 +33,9 @@ namespace MediaBrowser.Server.Mono
private static ILogger _logger;
private static IFileSystem FileSystem;
+ private static readonly TaskCompletionSource<bool> ApplicationTaskCompletionSource = new TaskCompletionSource<bool>();
+ private static bool _restartOnShutdown;
+
public static void Main(string[] args)
{
var applicationPath = Assembly.GetEntryAssembly().Location;
@@ -51,25 +50,31 @@ namespace MediaBrowser.Server.Mono
var appPaths = CreateApplicationPaths(applicationPath, customProgramDataPath);
- var logManager = new NlogManager(appPaths.LogDirectoryPath, "server");
- logManager.ReloadLogger(LogSeverity.Info);
- logManager.AddConsoleOutput();
+ using (var logManager = new SimpleLogManager(appPaths.LogDirectoryPath, "server"))
+ {
+ logManager.ReloadLogger(LogSeverity.Info);
+ logManager.AddConsoleOutput();
- var logger = _logger = logManager.GetLogger("Main");
+ var logger = _logger = logManager.GetLogger("Main");
- ApplicationHost.LogEnvironmentInfo(logger, appPaths, true);
-
- AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
+ ApplicationHost.LogEnvironmentInfo(logger, appPaths, true);
- try
- {
- RunApplication(appPaths, logManager, options);
- }
- finally
- {
- logger.Info("Shutting down");
+ AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
- _appHost.Dispose();
+ try
+ {
+ RunApplication(appPaths, logManager, options);
+ }
+ finally
+ {
+ _logger.Info("Disposing app host");
+ _appHost.Dispose();
+
+ if (_restartOnShutdown)
+ {
+ StartNewInstance(options);
+ }
+ }
}
}
@@ -87,13 +92,9 @@ namespace MediaBrowser.Server.Mono
var appFolderPath = Path.GetDirectoryName(applicationPath);
- Action<string> createDirectoryFn = s => Directory.CreateDirectory(s);
-
- return new ServerApplicationPaths(programDataPath, appFolderPath, Path.GetDirectoryName(applicationPath), createDirectoryFn);
+ return new ServerApplicationPaths(programDataPath, appFolderPath, Path.GetDirectoryName(applicationPath));
}
- private static readonly TaskCompletionSource<bool> ApplicationTaskCompletionSource = new TaskCompletionSource<bool>();
-
private static void RunApplication(ServerApplicationPaths appPaths, ILogManager logManager, StartupOptions options)
{
// Allow all https requests
@@ -115,11 +116,8 @@ namespace MediaBrowser.Server.Mono
"emby.mono.zip",
environmentInfo,
imageEncoder,
- new Startup.Common.SystemEvents(logManager.GetLogger("SystemEvents")),
- new MemoryStreamProvider(),
- new NetworkManager(logManager.GetLogger("NetworkManager")),
- GenerateCertificate,
- () => Environment.UserName);
+ new SystemEvents(logManager.GetLogger("SystemEvents")),
+ new NetworkManager(logManager.GetLogger("NetworkManager")));
if (options.ContainsOption("-v"))
{
@@ -144,11 +142,6 @@ namespace MediaBrowser.Server.Mono
Task.WaitAll(task);
}
- private static void GenerateCertificate(string certPath, string certHost, string certPassword)
- {
- CertificateGenerator.CreateSelfSignCertificatePfx(certPath, certHost, certPassword, _logger);
- }
-
private static MonoEnvironmentInfo GetEnvironmentInfo()
{
var info = new MonoEnvironmentInfo();
@@ -159,39 +152,38 @@ namespace MediaBrowser.Server.Mono
if (string.Equals(sysName, "Darwin", StringComparison.OrdinalIgnoreCase))
{
- //info.OperatingSystem = Startup.Common.OperatingSystem.Osx;
+ info.OperatingSystem = Model.System.OperatingSystem.OSX;
}
else if (string.Equals(sysName, "Linux", StringComparison.OrdinalIgnoreCase))
{
- //info.OperatingSystem = Startup.Common.OperatingSystem.Linux;
+ info.OperatingSystem = Model.System.OperatingSystem.Linux;
}
else if (string.Equals(sysName, "BSD", StringComparison.OrdinalIgnoreCase))
{
- //info.OperatingSystem = Startup.Common.OperatingSystem.Bsd;
- info.IsBsd = true;
+ info.OperatingSystem = Model.System.OperatingSystem.BSD;
}
var archX86 = new Regex("(i|I)[3-6]86");
if (archX86.IsMatch(uname.machine))
{
- info.CustomArchitecture = Architecture.X86;
+ info.SystemArchitecture = Architecture.X86;
}
else if (string.Equals(uname.machine, "x86_64", StringComparison.OrdinalIgnoreCase))
{
- info.CustomArchitecture = Architecture.X64;
+ info.SystemArchitecture = Architecture.X64;
}
else if (uname.machine.StartsWith("arm", StringComparison.OrdinalIgnoreCase))
{
- info.CustomArchitecture = Architecture.Arm;
+ info.SystemArchitecture = Architecture.Arm;
}
else if (System.Environment.Is64BitOperatingSystem)
{
- info.CustomArchitecture = Architecture.X64;
+ info.SystemArchitecture = Architecture.X64;
}
else
{
- info.CustomArchitecture = Architecture.X86;
+ info.SystemArchitecture = Architecture.X86;
}
return info;
@@ -258,11 +250,15 @@ namespace MediaBrowser.Server.Mono
ApplicationTaskCompletionSource.SetResult(true);
}
- public static void Restart(StartupOptions startupOptions)
+ public static void Restart()
{
- _logger.Info("Disposing app host");
- _appHost.Dispose();
+ _restartOnShutdown = true;
+
+ Shutdown();
+ }
+ private static void StartNewInstance(StartupOptions startupOptions)
+ {
_logger.Info("Starting new instance");
string module = startupOptions.GetOption("-restartpath");
@@ -275,19 +271,17 @@ namespace MediaBrowser.Server.Mono
if (!startupOptions.ContainsOption("-restartargs"))
{
var args = Environment.GetCommandLineArgs()
- .Skip(1)
- .Select(NormalizeCommandLineArgument);
+ .Skip(1)
+ .Select(NormalizeCommandLineArgument)
+ .ToArray();
- commandLineArgsString = string.Join(" ", args.ToArray());
+ commandLineArgsString = string.Join(" ", args);
}
_logger.Info("Executable: {0}", module);
_logger.Info("Arguments: {0}", commandLineArgsString);
Process.Start(module, commandLineArgsString);
-
- _logger.Info("Calling Environment.Exit");
- Environment.Exit(0);
}
private static string NormalizeCommandLineArgument(string arg)
@@ -311,24 +305,9 @@ namespace MediaBrowser.Server.Mono
public class MonoEnvironmentInfo : EnvironmentInfo
{
- public bool IsBsd { get; set; }
-
public override string GetUserId()
{
return Syscall.getuid().ToString(CultureInfo.InvariantCulture);
}
-
- public override Model.System.OperatingSystem OperatingSystem
- {
- get
- {
- if (IsBsd)
- {
- return Model.System.OperatingSystem.BSD;
- }
-
- return base.OperatingSystem;
- }
- }
}
}
diff --git a/MediaBrowser.Server.Mono/packages.config b/MediaBrowser.Server.Mono/packages.config
index dcc477e9a..cff873f1f 100644
--- a/MediaBrowser.Server.Mono/packages.config
+++ b/MediaBrowser.Server.Mono/packages.config
@@ -1,11 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Mono.Posix" version="4.0.0.0" targetFramework="net45" />
- <package id="NLog" version="4.4.11" targetFramework="net46" />
<package id="ServiceStack.Text" version="4.5.8" targetFramework="net46" />
<package id="SharpCompress" version="0.14.0" targetFramework="net46" />
<package id="SimpleInjector" version="4.0.8" targetFramework="net46" />
- <package id="SkiaSharp" version="1.58.0" targetFramework="net46" />
- <package id="SQLitePCLRaw.core" version="1.1.7" targetFramework="net46" />
- <package id="SQLitePCLRaw.provider.sqlite3.net45" version="1.1.7" targetFramework="net46" />
+ <package id="SkiaSharp" version="1.58.1" targetFramework="net46" />
+ <package id="SQLitePCLRaw.core" version="1.1.8" targetFramework="net46" />
+ <package id="SQLitePCLRaw.provider.sqlite3.net45" version="1.1.8" targetFramework="net46" />
</packages> \ No newline at end of file
diff --git a/MediaBrowser.ServerApplication/ApplicationPathHelper.cs b/MediaBrowser.ServerApplication/ApplicationPathHelper.cs
new file mode 100644
index 000000000..e8dad6213
--- /dev/null
+++ b/MediaBrowser.ServerApplication/ApplicationPathHelper.cs
@@ -0,0 +1,51 @@
+using System;
+using System.Configuration;
+using System.IO;
+
+namespace MediaBrowser.ServerApplication
+{
+ public static class ApplicationPathHelper
+ {
+ /// <summary>
+ /// Gets the path to the application's ProgramDataFolder
+ /// </summary>
+ /// <returns>System.String.</returns>
+ public static string GetProgramDataPath(string applicationPath)
+ {
+ var useDebugPath = false;
+
+#if DEBUG
+ useDebugPath = true;
+#endif
+
+ var programDataPath = useDebugPath ?
+ ConfigurationManager.AppSettings["DebugProgramDataPath"] :
+ ConfigurationManager.AppSettings["ReleaseProgramDataPath"];
+
+ programDataPath = programDataPath.Replace("%ApplicationData%", Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData));
+
+ programDataPath = programDataPath
+ .Replace('/', Path.DirectorySeparatorChar)
+ .Replace('\\', Path.DirectorySeparatorChar);
+
+ // If it's a relative path, e.g. "..\"
+ if (!Path.IsPathRooted(programDataPath))
+ {
+ var path = Path.GetDirectoryName(applicationPath);
+
+ if (string.IsNullOrEmpty(path))
+ {
+ throw new ApplicationException("Unable to determine running assembly location");
+ }
+
+ programDataPath = Path.Combine(path, programDataPath);
+
+ programDataPath = Path.GetFullPath(programDataPath);
+ }
+
+ Directory.CreateDirectory(programDataPath);
+
+ return programDataPath;
+ }
+ }
+}
diff --git a/MediaBrowser.ServerApplication/ImageEncoderHelper.cs b/MediaBrowser.ServerApplication/ImageEncoderHelper.cs
index 77e6c65fe..0e99bbbad 100644
--- a/MediaBrowser.ServerApplication/ImageEncoderHelper.cs
+++ b/MediaBrowser.ServerApplication/ImageEncoderHelper.cs
@@ -1,6 +1,5 @@
using System;
using Emby.Drawing;
-using Emby.Drawing.ImageMagick;
using Emby.Drawing.Skia;
using Emby.Server.Core;
using Emby.Server.Implementations;
diff --git a/MediaBrowser.ServerApplication/MainStartup.cs b/MediaBrowser.ServerApplication/MainStartup.cs
index bc38476ca..31acd1820 100644
--- a/MediaBrowser.ServerApplication/MainStartup.cs
+++ b/MediaBrowser.ServerApplication/MainStartup.cs
@@ -1,5 +1,4 @@
using MediaBrowser.Model.Logging;
-using MediaBrowser.Server.Implementations;
using MediaBrowser.Server.Startup.Common;
using MediaBrowser.ServerApplication.Native;
using MediaBrowser.ServerApplication.Splash;
@@ -17,21 +16,17 @@ using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
-using Emby.Common.Implementations.EnvironmentInfo;
-using Emby.Common.Implementations.IO;
-using Emby.Common.Implementations.Logging;
-using Emby.Common.Implementations.Networking;
using Emby.Server.Core.Cryptography;
using Emby.Drawing;
using Emby.Server.Core;
-using Emby.Server.Core.IO;
-using Emby.Server.Core.Logging;
using Emby.Server.Implementations;
using Emby.Server.Implementations.Browser;
+using Emby.Server.Implementations.EnvironmentInfo;
using Emby.Server.Implementations.IO;
using Emby.Server.Implementations.Logging;
using MediaBrowser.Common.Net;
using MediaBrowser.Model.IO;
+using SystemEvents = Emby.Server.Implementations.SystemEvents;
namespace MediaBrowser.ServerApplication
{
@@ -77,69 +72,71 @@ namespace MediaBrowser.ServerApplication
var appPaths = CreateApplicationPaths(ApplicationPath, IsRunningAsService);
- var logManager = new NlogManager(appPaths.LogDirectoryPath, "server");
- logManager.ReloadLogger(LogSeverity.Debug);
- logManager.AddConsoleOutput();
+ using (var logManager = new SimpleLogManager(appPaths.LogDirectoryPath, "server"))
+ {
+ logManager.ReloadLogger(LogSeverity.Debug);
+ logManager.AddConsoleOutput();
- var logger = _logger = logManager.GetLogger("Main");
+ var logger = _logger = logManager.GetLogger("Main");
- ApplicationHost.LogEnvironmentInfo(logger, appPaths, true);
+ ApplicationHost.LogEnvironmentInfo(logger, appPaths, true);
- // Install directly
- if (options.ContainsOption("-installservice"))
- {
- logger.Info("Performing service installation");
- InstallService(ApplicationPath, logger);
- return;
- }
+ // Install directly
+ if (options.ContainsOption("-installservice"))
+ {
+ logger.Info("Performing service installation");
+ InstallService(ApplicationPath, logger);
+ return;
+ }
- // Restart with admin rights, then install
- if (options.ContainsOption("-installserviceasadmin"))
- {
- logger.Info("Performing service installation");
- RunServiceInstallation(ApplicationPath);
- return;
- }
+ // Restart with admin rights, then install
+ if (options.ContainsOption("-installserviceasadmin"))
+ {
+ logger.Info("Performing service installation");
+ RunServiceInstallation(ApplicationPath);
+ return;
+ }
- // Uninstall directly
- if (options.ContainsOption("-uninstallservice"))
- {
- logger.Info("Performing service uninstallation");
- UninstallService(ApplicationPath, logger);
- return;
- }
+ // Uninstall directly
+ if (options.ContainsOption("-uninstallservice"))
+ {
+ logger.Info("Performing service uninstallation");
+ UninstallService(ApplicationPath, logger);
+ return;
+ }
- // Restart with admin rights, then uninstall
- if (options.ContainsOption("-uninstallserviceasadmin"))
- {
- logger.Info("Performing service uninstallation");
- RunServiceUninstallation(ApplicationPath);
- return;
- }
+ // Restart with admin rights, then uninstall
+ if (options.ContainsOption("-uninstallserviceasadmin"))
+ {
+ logger.Info("Performing service uninstallation");
+ RunServiceUninstallation(ApplicationPath);
+ return;
+ }
- AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
+ AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
- RunServiceInstallationIfNeeded(ApplicationPath);
+ RunServiceInstallationIfNeeded(ApplicationPath);
- if (IsAlreadyRunning(ApplicationPath, currentProcess))
- {
- logger.Info("Shutting down because another instance of Emby Server is already running.");
- return;
- }
+ if (IsAlreadyRunning(ApplicationPath, currentProcess))
+ {
+ logger.Info("Shutting down because another instance of Emby Server is already running.");
+ return;
+ }
- if (PerformUpdateIfNeeded(appPaths, logger))
- {
- logger.Info("Exiting to perform application update.");
- return;
- }
+ if (PerformUpdateIfNeeded(appPaths, logger))
+ {
+ logger.Info("Exiting to perform application update.");
+ return;
+ }
- try
- {
- RunApplication(appPaths, logManager, IsRunningAsService, options);
- }
- finally
- {
- OnServiceShutdown();
+ try
+ {
+ RunApplication(appPaths, logManager, IsRunningAsService, options);
+ }
+ finally
+ {
+ OnServiceShutdown();
+ }
}
}
@@ -201,30 +198,37 @@ namespace MediaBrowser.ServerApplication
private static bool IsAlreadyRunningAsService(string applicationPath)
{
- var serviceName = BackgroundService.GetExistingServiceName();
+ try
+ {
+ var serviceName = BackgroundService.GetExistingServiceName();
- WqlObjectQuery wqlObjectQuery = new WqlObjectQuery(string.Format("SELECT * FROM Win32_Service WHERE State = 'Running' AND Name = '{0}'", serviceName));
- ManagementObjectSearcher managementObjectSearcher = new ManagementObjectSearcher(wqlObjectQuery);
- ManagementObjectCollection managementObjectCollection = managementObjectSearcher.Get();
+ WqlObjectQuery wqlObjectQuery = new WqlObjectQuery(string.Format("SELECT * FROM Win32_Service WHERE State = 'Running' AND Name = '{0}'", serviceName));
+ ManagementObjectSearcher managementObjectSearcher = new ManagementObjectSearcher(wqlObjectQuery);
+ ManagementObjectCollection managementObjectCollection = managementObjectSearcher.Get();
- foreach (ManagementObject managementObject in managementObjectCollection)
- {
- var obj = managementObject.GetPropertyValue("PathName");
- if (obj == null)
+ foreach (ManagementObject managementObject in managementObjectCollection)
{
- continue;
- }
- var path = obj.ToString();
+ var obj = managementObject.GetPropertyValue("PathName");
+ if (obj == null)
+ {
+ continue;
+ }
+ var path = obj.ToString();
- _logger.Info("Service path: {0}", path);
- // Need to use indexOf instead of equality because the path will have the full service command line
- if (path.IndexOf(applicationPath, StringComparison.OrdinalIgnoreCase) != -1)
- {
- _logger.Info("The windows service is already running");
- MessageBox.Show("Emby Server is already running as a Windows Service. Only one instance is allowed at a time. To run as a tray icon, shut down the Windows Service.");
- return true;
+ _logger.Info("Service path: {0}", path);
+ // Need to use indexOf instead of equality because the path will have the full service command line
+ if (path.IndexOf(applicationPath, StringComparison.OrdinalIgnoreCase) != -1)
+ {
+ _logger.Info("The windows service is already running");
+ MessageBox.Show("Emby Server is already running as a Windows Service. Only one instance is allowed at a time. To run as a tray icon, shut down the Windows Service.");
+ return true;
+ }
}
}
+ catch (COMException)
+ {
+ // Catch errors thrown due to WMI not being initialized
+ }
return false;
}
@@ -241,18 +245,16 @@ namespace MediaBrowser.ServerApplication
var resourcesPath = Path.GetDirectoryName(applicationPath);
- Action<string> createDirectoryFn = s => Directory.CreateDirectory(s);
-
if (runAsService)
{
var systemPath = Path.GetDirectoryName(applicationPath);
var programDataPath = Path.GetDirectoryName(systemPath);
- return new ServerApplicationPaths(programDataPath, appFolderPath, resourcesPath, createDirectoryFn);
+ return new ServerApplicationPaths(programDataPath, appFolderPath, resourcesPath);
}
- return new ServerApplicationPaths(ApplicationPathHelper.GetProgramDataPath(applicationPath), appFolderPath, resourcesPath, createDirectoryFn);
+ return new ServerApplicationPaths(ApplicationPathHelper.GetProgramDataPath(applicationPath), appFolderPath, resourcesPath);
}
/// <summary>
@@ -320,11 +322,8 @@ namespace MediaBrowser.ServerApplication
"emby.windows.zip",
environmentInfo,
new NullImageEncoder(),
- new Server.Startup.Common.SystemEvents(logManager.GetLogger("SystemEvents")),
- new RecyclableMemoryStreamProvider(),
- new Networking.NetworkManager(logManager.GetLogger("NetworkManager")),
- GenerateCertificate,
- () => Environment.UserDomainName);
+ new SystemEvents(logManager.GetLogger("SystemEvents")),
+ new Networking.NetworkManager(logManager.GetLogger("NetworkManager")));
var initProgress = new Progress<double>();
@@ -371,11 +370,6 @@ namespace MediaBrowser.ServerApplication
}
}
- private static void GenerateCertificate(string certPath, string certHost, string certPassword)
- {
- CertificateGenerator.CreateSelfSignCertificatePfx(certPath, certHost, certPassword, _logger);
- }
-
private static ServerNotifyIcon _serverNotifyIcon;
private static TaskScheduler _mainTaskScheduler;
private static void ShowTrayIcon()
diff --git a/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj b/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj
index 591ac0fba..23db82cf1 100644
--- a/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj
+++ b/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj
@@ -73,10 +73,6 @@
<Reference Include="Emby.Server.Sync">
<HintPath>..\ThirdParty\emby\Emby.Server.Sync.dll</HintPath>
</Reference>
- <Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
- <HintPath>..\packages\NLog.4.4.11\lib\net45\NLog.dll</HintPath>
- <Private>True</Private>
- </Reference>
<Reference Include="ServiceStack.Text, Version=4.5.8.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\ServiceStack.Text.4.5.8\lib\net45\ServiceStack.Text.dll</HintPath>
<Private>True</Private>
@@ -89,15 +85,13 @@
<HintPath>..\packages\SimpleInjector.4.0.8\lib\net45\SimpleInjector.dll</HintPath>
</Reference>
<Reference Include="SkiaSharp, Version=1.58.0.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756, processorArchitecture=MSIL">
- <HintPath>..\packages\SkiaSharp.1.58.0\lib\net45\SkiaSharp.dll</HintPath>
+ <HintPath>..\packages\SkiaSharp.1.58.1\lib\net45\SkiaSharp.dll</HintPath>
</Reference>
<Reference Include="SQLitePCLRaw.core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1488e028ca7ab535, processorArchitecture=MSIL">
- <HintPath>..\packages\SQLitePCLRaw.core.1.1.7\lib\net45\SQLitePCLRaw.core.dll</HintPath>
- <Private>True</Private>
+ <HintPath>..\packages\SQLitePCLRaw.core.1.1.8\lib\net45\SQLitePCLRaw.core.dll</HintPath>
</Reference>
<Reference Include="SQLitePCLRaw.provider.sqlite3, Version=1.0.0.0, Culture=neutral, PublicKeyToken=62684c7b4f184e3f, processorArchitecture=MSIL">
- <HintPath>..\packages\SQLitePCLRaw.provider.sqlite3.net45.1.1.7\lib\net45\SQLitePCLRaw.provider.sqlite3.dll</HintPath>
- <Private>True</Private>
+ <HintPath>..\packages\SQLitePCLRaw.provider.sqlite3.net45.1.1.8\lib\net45\SQLitePCLRaw.provider.sqlite3.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Configuration" />
@@ -119,6 +113,7 @@
<Compile Include="..\SharedVersion.cs">
<Link>Properties\SharedVersion.cs</Link>
</Compile>
+ <Compile Include="ApplicationPathHelper.cs" />
<Compile Include="BackgroundService.cs">
<SubType>Component</SubType>
</Compile>
@@ -127,6 +122,7 @@
</Compile>
<Compile Include="ImageEncoderHelper.cs" />
<Compile Include="MainStartup.cs" />
+ <Compile Include="Native\LnkShortcutHandler.cs" />
<Compile Include="Native\LoopUtil.cs" />
<Compile Include="Native\PowerManagement.cs" />
<Compile Include="Native\Standby.cs" />
@@ -166,6 +162,14 @@
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
+ <Content Include="..\packages\SkiaSharp.1.58.1\runtimes\win7-x64\native\libSkiaSharp.dll">
+ <Link>x64\libSkiaSharp.dll</Link>
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="..\packages\SkiaSharp.1.58.1\runtimes\win7-x86\native\libSkiaSharp.dll">
+ <Link>x86\libSkiaSharp.dll</Link>
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
<Content Include="..\Tools\Installation\MediaBrowser.InstallUtil.dll">
<Link>MediaBrowser.InstallUtil.dll</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
@@ -178,17 +182,11 @@
<Link>MediaBrowser.Updater.exe</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
- <Content Include="x64\libSkiaSharp.dll">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
<Content Include="x64\sqlite3.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<EmbeddedResource Include="Icon.ico" />
<Content Include="Resources\Images\mb3logo800.png" />
- <Content Include="x86\libSkiaSharp.dll">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
<Content Include="x86\sqlite3.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -202,18 +200,10 @@
<Project>{713f42b5-878e-499d-a878-e4c652b1d5e8}</Project>
<Name>DvdLib</Name>
</ProjectReference>
- <ProjectReference Include="..\Emby.Common.Implementations\Emby.Common.Implementations.csproj">
- <Project>{1e37a338-9f57-4b70-bd6d-bb9c591e319b}</Project>
- <Name>Emby.Common.Implementations</Name>
- </ProjectReference>
<ProjectReference Include="..\Emby.Dlna\Emby.Dlna.csproj">
<Project>{805844ab-e92f-45e6-9d99-4f6d48d129a5}</Project>
<Name>Emby.Dlna</Name>
</ProjectReference>
- <ProjectReference Include="..\Emby.Drawing.ImageMagick\Emby.Drawing.ImageMagick.csproj">
- <Project>{6cfee013-6e7c-432b-ac37-cabf0880c69a}</Project>
- <Name>Emby.Drawing.ImageMagick</Name>
- </ProjectReference>
<ProjectReference Include="..\Emby.Drawing.Skia\Emby.Drawing.Skia.csproj">
<Project>{2312da6d-ff86-4597-9777-bceec32d96dd}</Project>
<Name>Emby.Drawing.Skia</Name>
@@ -226,10 +216,6 @@
<Project>{89ab4548-770d-41fd-a891-8daff44f452c}</Project>
<Name>Emby.Photos</Name>
</ProjectReference>
- <ProjectReference Include="..\Emby.Server.Core\Emby.Server.Core.csproj">
- <Project>{776b9f0c-5195-45e3-9a36-1cc1f0d8e0b0}</Project>
- <Name>Emby.Server.Core</Name>
- </ProjectReference>
<ProjectReference Include="..\Emby.Server.Implementations\Emby.Server.Implementations.csproj">
<Project>{e383961b-9356-4d5d-8233-9a1079d03055}</Project>
<Name>Emby.Server.Implementations</Name>
@@ -250,10 +236,6 @@
<Project>{7ef9f3e0-697d-42f3-a08f-19deb5f84392}</Project>
<Name>MediaBrowser.LocalMetadata</Name>
</ProjectReference>
- <ProjectReference Include="..\MediaBrowser.MediaEncoding\MediaBrowser.MediaEncoding.csproj">
- <Project>{0bd82fa6-eb8a-4452-8af5-74f9c3849451}</Project>
- <Name>MediaBrowser.MediaEncoding</Name>
- </ProjectReference>
<ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj">
<Project>{7eeeb4bb-f3e8-48fc-b4c5-70f0fff8329b}</Project>
<Name>MediaBrowser.Model</Name>
@@ -262,10 +244,6 @@
<Project>{442b5058-dcaf-4263-bb6a-f21e31120a1b}</Project>
<Name>MediaBrowser.Providers</Name>
</ProjectReference>
- <ProjectReference Include="..\MediaBrowser.Server.Implementations\MediaBrowser.Server.Implementations.csproj">
- <Project>{2e781478-814d-4a48-9d80-bff206441a65}</Project>
- <Name>MediaBrowser.Server.Implementations</Name>
- </ProjectReference>
<ProjectReference Include="..\MediaBrowser.WebDashboard\MediaBrowser.WebDashboard.csproj">
<Project>{5624b7b5-b5a7-41d8-9f10-cc5611109619}</Project>
<Name>MediaBrowser.WebDashboard</Name>
diff --git a/Emby.Common.Implementations/IO/LnkShortcutHandler.cs b/MediaBrowser.ServerApplication/Native/LnkShortcutHandler.cs
index 5d5f46057..e53a79670 100644
--- a/Emby.Common.Implementations/IO/LnkShortcutHandler.cs
+++ b/MediaBrowser.ServerApplication/Native/LnkShortcutHandler.cs
@@ -2,11 +2,10 @@
using System.IO;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
-using System.Security;
using System.Text;
using MediaBrowser.Model.IO;
-namespace Emby.Common.Implementations.IO
+namespace MediaBrowser.ServerApplication.Native
{
public class LnkShortcutHandler :IShortcutHandler
{
diff --git a/MediaBrowser.ServerApplication/Native/LoopUtil.cs b/MediaBrowser.ServerApplication/Native/LoopUtil.cs
index 7c7471231..0efdba389 100644
--- a/MediaBrowser.ServerApplication/Native/LoopUtil.cs
+++ b/MediaBrowser.ServerApplication/Native/LoopUtil.cs
@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
-using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
diff --git a/MediaBrowser.ServerApplication/Networking/NetworkManager.cs b/MediaBrowser.ServerApplication/Networking/NetworkManager.cs
index 6d3d96e19..8933a5760 100644
--- a/MediaBrowser.ServerApplication/Networking/NetworkManager.cs
+++ b/MediaBrowser.ServerApplication/Networking/NetworkManager.cs
@@ -13,7 +13,7 @@ namespace MediaBrowser.ServerApplication.Networking
/// <summary>
/// Class NetUtils
/// </summary>
- public class NetworkManager : Emby.Common.Implementations.Networking.NetworkManager
+ public class NetworkManager : Emby.Server.Implementations.Networking.NetworkManager
{
public NetworkManager(ILogger logger)
: base(logger)
diff --git a/MediaBrowser.ServerApplication/WindowsAppHost.cs b/MediaBrowser.ServerApplication/WindowsAppHost.cs
index 7a35c5614..a6664c42f 100644
--- a/MediaBrowser.ServerApplication/WindowsAppHost.cs
+++ b/MediaBrowser.ServerApplication/WindowsAppHost.cs
@@ -4,13 +4,13 @@ using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices.ComTypes;
-using Emby.Common.Implementations.IO;
using Emby.Server.CinemaMode;
using Emby.Server.Connect;
using Emby.Server.Core;
using Emby.Server.Implementations;
using Emby.Server.Implementations.EntryPoints;
using Emby.Server.Implementations.FFMpeg;
+using Emby.Server.Implementations.IO;
using Emby.Server.Sync;
using MediaBrowser.Controller.Connect;
using MediaBrowser.Controller.Sync;
@@ -25,9 +25,10 @@ namespace MediaBrowser.ServerApplication
{
public class WindowsAppHost : ApplicationHost
{
- public WindowsAppHost(ServerApplicationPaths applicationPaths, ILogManager logManager, StartupOptions options, IFileSystem fileSystem, IPowerManagement powerManagement, string releaseAssetFilename, IEnvironmentInfo environmentInfo, MediaBrowser.Controller.Drawing.IImageEncoder imageEncoder, ISystemEvents systemEvents, IMemoryStreamFactory memoryStreamFactory, MediaBrowser.Common.Net.INetworkManager networkManager, Action<string, string, string> certificateGenerator, Func<string> defaultUsernameFactory)
- : base(applicationPaths, logManager, options, fileSystem, powerManagement, releaseAssetFilename, environmentInfo, imageEncoder, systemEvents, memoryStreamFactory, networkManager, certificateGenerator, defaultUsernameFactory)
+ public WindowsAppHost(ServerApplicationPaths applicationPaths, ILogManager logManager, StartupOptions options, IFileSystem fileSystem, IPowerManagement powerManagement, string releaseAssetFilename, IEnvironmentInfo environmentInfo, MediaBrowser.Controller.Drawing.IImageEncoder imageEncoder, ISystemEvents systemEvents, MediaBrowser.Common.Net.INetworkManager networkManager)
+ : base(applicationPaths, logManager, options, fileSystem, powerManagement, releaseAssetFilename, environmentInfo, imageEncoder, systemEvents, networkManager)
{
+ fileSystem.AddShortcutHandler(new LnkShortcutHandler());
}
public override bool IsRunningAsService
diff --git a/MediaBrowser.ServerApplication/packages.config b/MediaBrowser.ServerApplication/packages.config
index 0fa93db82..85d2613bb 100644
--- a/MediaBrowser.ServerApplication/packages.config
+++ b/MediaBrowser.ServerApplication/packages.config
@@ -1,10 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
- <package id="NLog" version="4.4.11" targetFramework="net462" />
<package id="ServiceStack.Text" version="4.5.8" targetFramework="net462" />
<package id="SharpCompress" version="0.14.0" targetFramework="net462" />
<package id="SimpleInjector" version="4.0.8" targetFramework="net462" />
- <package id="SkiaSharp" version="1.58.0" targetFramework="net462" />
- <package id="SQLitePCLRaw.core" version="1.1.7" targetFramework="net462" />
- <package id="SQLitePCLRaw.provider.sqlite3.net45" version="1.1.7" targetFramework="net462" />
+ <package id="SkiaSharp" version="1.58.1" targetFramework="net462" />
+ <package id="SQLitePCLRaw.core" version="1.1.8" targetFramework="net462" />
+ <package id="SQLitePCLRaw.provider.sqlite3.net45" version="1.1.8" targetFramework="net462" />
</packages> \ No newline at end of file
diff --git a/MediaBrowser.ServerApplication/x64/libSkiaSharp.dll.REMOVED.git-id b/MediaBrowser.ServerApplication/x64/libSkiaSharp.dll.REMOVED.git-id
deleted file mode 100644
index 4027f61a0..000000000
--- a/MediaBrowser.ServerApplication/x64/libSkiaSharp.dll.REMOVED.git-id
+++ /dev/null
@@ -1 +0,0 @@
-20e469be83c5d41bb44d085c36550780e788a8ef \ No newline at end of file
diff --git a/MediaBrowser.Tests/M3uParserTest.cs b/MediaBrowser.Tests/M3uParserTest.cs
index 3320d8794..1b42a3823 100644
--- a/MediaBrowser.Tests/M3uParserTest.cs
+++ b/MediaBrowser.Tests/M3uParserTest.cs
@@ -3,7 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
-using Emby.Common.Implementations.Cryptography;
+using Emby.Server.Implementations.Cryptography;
using Emby.Server.Implementations.LiveTv.TunerHosts;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Model.Logging;
diff --git a/MediaBrowser.Tests/MediaBrowser.Tests.csproj b/MediaBrowser.Tests/MediaBrowser.Tests.csproj
index a031d47ea..62bcad000 100644
--- a/MediaBrowser.Tests/MediaBrowser.Tests.csproj
+++ b/MediaBrowser.Tests/MediaBrowser.Tests.csproj
@@ -37,6 +37,9 @@
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
+ <Reference Include="Emby.Server.MediaEncoding">
+ <HintPath>..\ThirdParty\emby\Emby.Server.MediaEncoding.dll</HintPath>
+ </Reference>
<Reference Include="System" />
<Reference Include="System.XML" />
</ItemGroup>
@@ -65,14 +68,6 @@
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
- <ProjectReference Include="..\Emby.Common.Implementations\Emby.Common.Implementations.csproj">
- <Project>{1e37a338-9f57-4b70-bd6d-bb9c591e319b}</Project>
- <Name>Emby.Common.Implementations</Name>
- </ProjectReference>
- <ProjectReference Include="..\Emby.Server.Core\Emby.Server.Core.csproj">
- <Project>{776b9f0c-5195-45e3-9a36-1cc1f0d8e0b0}</Project>
- <Name>Emby.Server.Core</Name>
- </ProjectReference>
<ProjectReference Include="..\Emby.Server.Implementations\Emby.Server.Implementations.csproj">
<Project>{e383961b-9356-4d5d-8233-9a1079d03055}</Project>
<Name>Emby.Server.Implementations</Name>
@@ -85,10 +80,6 @@
<Project>{17e1f4e6-8abd-4fe5-9ecf-43d4b6087ba2}</Project>
<Name>MediaBrowser.Controller</Name>
</ProjectReference>
- <ProjectReference Include="..\MediaBrowser.MediaEncoding\MediaBrowser.MediaEncoding.csproj">
- <Project>{0BD82FA6-EB8A-4452-8AF5-74F9C3849451}</Project>
- <Name>MediaBrowser.MediaEncoding</Name>
- </ProjectReference>
<ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj">
<Project>{7eeeb4bb-f3e8-48fc-b4c5-70f0fff8329b}</Project>
<Name>MediaBrowser.Model</Name>
@@ -97,10 +88,6 @@
<Project>{442B5058-DCAF-4263-BB6A-F21E31120A1B}</Project>
<Name>MediaBrowser.Providers</Name>
</ProjectReference>
- <ProjectReference Include="..\MediaBrowser.Server.Implementations\MediaBrowser.Server.Implementations.csproj">
- <Project>{2E781478-814D-4A48-9D80-BFF206441A65}</Project>
- <Name>MediaBrowser.Server.Implementations</Name>
- </ProjectReference>
<ProjectReference Include="..\MediaBrowser.XbmcMetadata\MediaBrowser.XbmcMetadata.csproj">
<Project>{23499896-b135-4527-8574-c26e926ea99e}</Project>
<Name>MediaBrowser.XbmcMetadata</Name>
@@ -108,20 +95,10 @@
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
- </ItemGroup>
- <ItemGroup>
- <None Include="MediaEncoding\Subtitles\TestSubtitles\expected.vtt">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </None>
- <None Include="MediaEncoding\Subtitles\TestSubtitles\data.ass">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </None>
- <None Include="MediaEncoding\Subtitles\TestSubtitles\data2.ass">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </None>
- <None Include="MediaEncoding\Subtitles\TestSubtitles\unit.srt">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </None>
+ <None Include="MediaEncoding\Subtitles\TestSubtitles\data.ass" />
+ <None Include="MediaEncoding\Subtitles\TestSubtitles\data2.ass" />
+ <None Include="MediaEncoding\Subtitles\TestSubtitles\expected.vtt" />
+ <None Include="MediaEncoding\Subtitles\TestSubtitles\unit.srt" />
</ItemGroup>
<ItemGroup>
<ContentWithTargetPath Include="ConsistencyTests\Resources\StringCheck.xslt">
diff --git a/MediaBrowser.Tests/MediaEncoding/Subtitles/AssParserTests.cs b/MediaBrowser.Tests/MediaEncoding/Subtitles/AssParserTests.cs
index d5a62802d..dde9f2fe2 100644
--- a/MediaBrowser.Tests/MediaEncoding/Subtitles/AssParserTests.cs
+++ b/MediaBrowser.Tests/MediaEncoding/Subtitles/AssParserTests.cs
@@ -5,6 +5,7 @@ using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Collections.Generic;
using System.IO;
using System.Threading;
+using Emby.Server.MediaEncoding.Subtitles;
namespace MediaBrowser.Tests.MediaEncoding.Subtitles {
@@ -16,7 +17,7 @@ namespace MediaBrowser.Tests.MediaEncoding.Subtitles {
var expectedSubs =
new SubtitleTrackInfo {
- TrackEvents = new List<SubtitleTrackEvent> {
+ TrackEvents = new SubtitleTrackEvent[] {
new SubtitleTrackEvent {
Id = "1",
StartPositionTicks = 24000000,
@@ -47,8 +48,8 @@ namespace MediaBrowser.Tests.MediaEncoding.Subtitles {
var result = sut.Parse(stream, CancellationToken.None);
Assert.IsNotNull(result);
- Assert.AreEqual(expectedSubs.TrackEvents.Count,result.TrackEvents.Count);
- for (int i = 0; i < expectedSubs.TrackEvents.Count; i++)
+ Assert.AreEqual(expectedSubs.TrackEvents.Length,result.TrackEvents.Length);
+ for (int i = 0; i < expectedSubs.TrackEvents.Length; i++)
{
Assert.AreEqual(expectedSubs.TrackEvents[i].Id, result.TrackEvents[i].Id);
Assert.AreEqual(expectedSubs.TrackEvents[i].StartPositionTicks, result.TrackEvents[i].StartPositionTicks);
diff --git a/MediaBrowser.Tests/MediaEncoding/Subtitles/SrtParserTests.cs b/MediaBrowser.Tests/MediaEncoding/Subtitles/SrtParserTests.cs
index af34e13e7..8acc490e7 100644
--- a/MediaBrowser.Tests/MediaEncoding/Subtitles/SrtParserTests.cs
+++ b/MediaBrowser.Tests/MediaEncoding/Subtitles/SrtParserTests.cs
@@ -1,7 +1,7 @@
using System.Collections.Generic;
using System.IO;
using System.Threading;
-using MediaBrowser.MediaEncoding.Subtitles;
+using Emby.Server.MediaEncoding.Subtitles;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.MediaInfo;
using Microsoft.VisualStudio.TestTools.UnitTesting;
@@ -20,7 +20,7 @@ namespace MediaBrowser.Tests.MediaEncoding.Subtitles
var expectedSubs =
new SubtitleTrackInfo
{
- TrackEvents = new List<SubtitleTrackEvent> {
+ TrackEvents = new SubtitleTrackEvent[] {
new SubtitleTrackEvent {
Id = "1",
StartPositionTicks = 24000000,
@@ -100,8 +100,8 @@ namespace MediaBrowser.Tests.MediaEncoding.Subtitles
var result = sut.Parse(stream, CancellationToken.None);
Assert.IsNotNull(result);
- Assert.AreEqual(expectedSubs.TrackEvents.Count, result.TrackEvents.Count);
- for (int i = 0; i < expectedSubs.TrackEvents.Count; i++)
+ Assert.AreEqual(expectedSubs.TrackEvents.Length, result.TrackEvents.Length);
+ for (int i = 0; i < expectedSubs.TrackEvents.Length; i++)
{
Assert.AreEqual(expectedSubs.TrackEvents[i].Id, result.TrackEvents[i].Id);
Assert.AreEqual(expectedSubs.TrackEvents[i].StartPositionTicks, result.TrackEvents[i].StartPositionTicks);
diff --git a/MediaBrowser.Tests/MediaEncoding/Subtitles/VttWriterTest.cs b/MediaBrowser.Tests/MediaEncoding/Subtitles/VttWriterTest.cs
index 924a1736f..00feb286c 100644
--- a/MediaBrowser.Tests/MediaEncoding/Subtitles/VttWriterTest.cs
+++ b/MediaBrowser.Tests/MediaEncoding/Subtitles/VttWriterTest.cs
@@ -1,7 +1,7 @@
using System.Collections.Generic;
using System.IO;
using System.Threading;
-using MediaBrowser.MediaEncoding.Subtitles;
+using Emby.Server.MediaEncoding.Subtitles;
using MediaBrowser.Model.MediaInfo;
using Microsoft.VisualStudio.TestTools.UnitTesting;
@@ -14,7 +14,7 @@ namespace MediaBrowser.Tests.MediaEncoding.Subtitles {
var infoSubs =
new SubtitleTrackInfo
{
- TrackEvents = new List<SubtitleTrackEvent> {
+ TrackEvents = new SubtitleTrackEvent[] {
new SubtitleTrackEvent {
Id = "1",
StartPositionTicks = 24000000,
diff --git a/MediaBrowser.WebDashboard/Api/PackageCreator.cs b/MediaBrowser.WebDashboard/Api/PackageCreator.cs
index da43dd63a..c855a8d9b 100644
--- a/MediaBrowser.WebDashboard/Api/PackageCreator.cs
+++ b/MediaBrowser.WebDashboard/Api/PackageCreator.cs
@@ -10,6 +10,7 @@ using System.Threading.Tasks;
using MediaBrowser.Controller.Net;
using MediaBrowser.Model.Globalization;
using MediaBrowser.Model.IO;
+using MediaBrowser.Model.Extensions;
namespace MediaBrowser.WebDashboard.Api
{
@@ -39,8 +40,6 @@ namespace MediaBrowser.WebDashboard.Api
if (resourceStream != null)
{
- // Don't apply any caching for html pages
- // jQuery ajax doesn't seem to handle if-modified-since correctly
if (IsFormat(virtualPath, "html"))
{
if (IsCoreHtml(virtualPath))
@@ -284,7 +283,7 @@ namespace MediaBrowser.WebDashboard.Api
files.Insert(0, "cordova.js");
}
- var tags = files.Select(s => string.Format("<script src=\"{0}\" defer></script>", s)).ToArray();
+ var tags = files.Select(s => string.Format("<script src=\"{0}\" defer></script>", s)).ToArray(files.Count);
builder.Append(string.Join(string.Empty, tags));
diff --git a/MediaBrowser.XbmcMetadata/EntryPoint.cs b/MediaBrowser.XbmcMetadata/EntryPoint.cs
index 188fc8504..98460f767 100644
--- a/MediaBrowser.XbmcMetadata/EntryPoint.cs
+++ b/MediaBrowser.XbmcMetadata/EntryPoint.cs
@@ -8,7 +8,6 @@ using MediaBrowser.Model.Logging;
using MediaBrowser.XbmcMetadata.Configuration;
using MediaBrowser.XbmcMetadata.Savers;
using System;
-using System.Linq;
using MediaBrowser.Controller.Dto;
namespace MediaBrowser.XbmcMetadata
@@ -56,7 +55,7 @@ namespace MediaBrowser.XbmcMetadata
PersonIds = new [] { person.Id.ToString("N") },
DtoOptions = new DtoOptions(true)
- }).ToList();
+ });
foreach (var item in items)
{
@@ -82,6 +81,7 @@ namespace MediaBrowser.XbmcMetadata
public void Dispose()
{
_userDataManager.UserDataSaved -= _userDataManager_UserDataSaved;
+ GC.SuppressFinalize(this);
}
private async void SaveMetadataForItem(BaseItem item, ItemUpdateType updateReason)
diff --git a/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs b/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs
index 6857d655f..c1c2e7d9d 100644
--- a/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs
+++ b/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs
@@ -253,7 +253,7 @@ namespace MediaBrowser.XbmcMetadata.Parsers
int value;
if (!string.IsNullOrWhiteSpace(tmdbId) && int.TryParse(tmdbId, NumberStyles.Any, CultureInfo.InvariantCulture, out value))
{
- item.SetProviderId(MetadataProviders.Tmdb, tmdbId);
+ item.SetProviderId(MetadataProviders.Tmdb, value.ToString(_usCulture));
}
}
@@ -269,7 +269,7 @@ namespace MediaBrowser.XbmcMetadata.Parsers
int value;
if (!string.IsNullOrWhiteSpace(tvdbId) && int.TryParse(tvdbId, NumberStyles.Any, CultureInfo.InvariantCulture, out value))
{
- item.SetProviderId(MetadataProviders.Tvdb, tvdbId);
+ item.SetProviderId(MetadataProviders.Tvdb, value.ToString(_usCulture));
}
}
}
@@ -316,10 +316,6 @@ namespace MediaBrowser.XbmcMetadata.Parsers
break;
}
- case "type":
- item.DisplayMediaType = reader.ReadElementContentAsString();
- break;
-
case "title":
case "localtitle":
item.Name = reader.ReadElementContentAsString();
@@ -398,13 +394,11 @@ namespace MediaBrowser.XbmcMetadata.Parsers
case "lockedfields":
{
- var fields = new List<MetadataFields>();
-
var val = reader.ReadElementContentAsString();
if (!string.IsNullOrWhiteSpace(val))
{
- var list = val.Split('|').Select(i =>
+ item.LockedFields = val.Split('|').Select(i =>
{
MetadataFields field;
@@ -415,13 +409,9 @@ namespace MediaBrowser.XbmcMetadata.Parsers
return null;
- }).Where(i => i.HasValue).Select(i => i.Value);
-
- fields.AddRange(list);
+ }).Where(i => i.HasValue).Select(i => i.Value).ToArray();
}
- item.LockedFields = fields;
-
break;
}
@@ -442,9 +432,10 @@ namespace MediaBrowser.XbmcMetadata.Parsers
if (!string.IsNullOrWhiteSpace(val))
{
- item.ProductionLocations.AddRange(val.Split('/')
+ item.ProductionLocations = val.Split('/')
.Select(i => i.Trim())
- .Where(i => !string.IsNullOrWhiteSpace(i)));
+ .Where(i => !string.IsNullOrWhiteSpace(i))
+ .ToArray();
}
break;
}
@@ -608,7 +599,7 @@ namespace MediaBrowser.XbmcMetadata.Parsers
{
val = val.Replace("plugin://plugin.video.youtube/?action=play_video&videoid=", "https://www.youtube.com/watch?v=", StringComparison.OrdinalIgnoreCase);
- hasTrailer.AddTrailerUrl(val, false);
+ hasTrailer.AddTrailerUrl(val);
}
}
break;
@@ -926,17 +917,6 @@ namespace MediaBrowser.XbmcMetadata.Parsers
name = reader.ReadElementContentAsString() ?? string.Empty;
break;
- case "type":
- {
- var val = reader.ReadElementContentAsString();
-
- if (!string.IsNullOrWhiteSpace(val))
- {
- type = val;
- }
- break;
- }
-
case "role":
{
var val = reader.ReadElementContentAsString();
diff --git a/MediaBrowser.XbmcMetadata/Parsers/MovieNfoParser.cs b/MediaBrowser.XbmcMetadata/Parsers/MovieNfoParser.cs
index 035ac15c0..85f9f92ba 100644
--- a/MediaBrowser.XbmcMetadata/Parsers/MovieNfoParser.cs
+++ b/MediaBrowser.XbmcMetadata/Parsers/MovieNfoParser.cs
@@ -1,4 +1,5 @@
-using MediaBrowser.Common.Configuration;
+using System.Linq;
+using MediaBrowser.Common.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Movies;
using MediaBrowser.Controller.Providers;
@@ -60,10 +61,15 @@ namespace MediaBrowser.XbmcMetadata.Parsers
movie.SetProviderId(MetadataProviders.TmdbCollection, tmdbcolid);
}
- var val = reader.ReadElementContentAsString();
+ var val = reader.ReadInnerXml();
+
if (!string.IsNullOrWhiteSpace(val) && movie != null)
{
- movie.CollectionName = val;
+ // TODO Handle this better later
+ if (val.IndexOf('<') == -1)
+ {
+ movie.CollectionName = val;
+ }
}
break;
@@ -76,7 +82,9 @@ namespace MediaBrowser.XbmcMetadata.Parsers
if (!string.IsNullOrWhiteSpace(val) && movie != null)
{
- movie.Artists.Add(val);
+ var list = movie.Artists.ToList();
+ list.Add(val);
+ movie.Artists = list.ToArray();
}
break;
diff --git a/MediaBrowser.XbmcMetadata/Parsers/SeriesNfoParser.cs b/MediaBrowser.XbmcMetadata/Parsers/SeriesNfoParser.cs
index b0db4e6f3..570a7fed8 100644
--- a/MediaBrowser.XbmcMetadata/Parsers/SeriesNfoParser.cs
+++ b/MediaBrowser.XbmcMetadata/Parsers/SeriesNfoParser.cs
@@ -62,21 +62,21 @@ namespace MediaBrowser.XbmcMetadata.Parsers
break;
}
case "airs_dayofweek":
- {
- item.AirDays = TVUtils.GetAirDays(reader.ReadElementContentAsString());
- break;
- }
+ {
+ item.AirDays = TVUtils.GetAirDays(reader.ReadElementContentAsString());
+ break;
+ }
case "airs_time":
- {
- var val = reader.ReadElementContentAsString();
+ {
+ var val = reader.ReadElementContentAsString();
- if (!string.IsNullOrWhiteSpace(val))
- {
- item.AirTime = val;
- }
- break;
+ if (!string.IsNullOrWhiteSpace(val))
+ {
+ item.AirTime = val;
}
+ break;
+ }
case "status":
{
diff --git a/MediaBrowser.XbmcMetadata/Savers/AlbumNfoSaver.cs b/MediaBrowser.XbmcMetadata/Savers/AlbumNfoSaver.cs
index ec53b3bc4..f9f9c9b98 100644
--- a/MediaBrowser.XbmcMetadata/Savers/AlbumNfoSaver.cs
+++ b/MediaBrowser.XbmcMetadata/Savers/AlbumNfoSaver.cs
@@ -57,10 +57,9 @@ namespace MediaBrowser.XbmcMetadata.Savers
private static readonly CultureInfo UsCulture = new CultureInfo("en-US");
- private void AddTracks(IEnumerable<Audio> tracks, XmlWriter writer)
+ private void AddTracks(IEnumerable<BaseItem> tracks, XmlWriter writer)
{
- foreach (var track in tracks.OrderBy(i => i.ParentIndexNumber ?? 0)
- .ThenBy(i => i.IndexNumber ?? 0))
+ foreach (var track in tracks.OrderBy(i => i.ParentIndexNumber ?? 0).ThenBy(i => i.IndexNumber ?? 0))
{
writer.WriteStartElement("track");
diff --git a/MediaBrowser.XbmcMetadata/Savers/ArtistNfoSaver.cs b/MediaBrowser.XbmcMetadata/Savers/ArtistNfoSaver.cs
index 413738ade..a7f4e56a6 100644
--- a/MediaBrowser.XbmcMetadata/Savers/ArtistNfoSaver.cs
+++ b/MediaBrowser.XbmcMetadata/Savers/ArtistNfoSaver.cs
@@ -7,7 +7,6 @@ using MediaBrowser.XbmcMetadata.Configuration;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
-using System.Linq;
using System.Xml;
using MediaBrowser.Controller.IO;
@@ -50,16 +49,14 @@ namespace MediaBrowser.XbmcMetadata.Savers
}
var albums = artist
- .GetRecursiveChildren(i => i is MusicAlbum)
- .Cast<MusicAlbum>()
- .ToList();
+ .GetRecursiveChildren(i => i is MusicAlbum);
AddAlbums(albums, writer);
}
private static readonly CultureInfo UsCulture = new CultureInfo("en-US");
- private void AddAlbums(IEnumerable<MusicAlbum> albums, XmlWriter writer)
+ private void AddAlbums(IList<BaseItem> albums, XmlWriter writer)
{
foreach (var album in albums)
{
diff --git a/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs b/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs
index 510e6e252..41c376ddf 100644
--- a/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs
+++ b/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs
@@ -35,7 +35,6 @@ namespace MediaBrowser.XbmcMetadata.Savers
"plot",
"customrating",
"lockdata",
- "type",
"dateadded",
"title",
"rating",
@@ -300,9 +299,9 @@ namespace MediaBrowser.XbmcMetadata.Savers
writer.WriteStartElement("fileinfo");
writer.WriteStartElement("streamdetails");
- var mediaSource = item.GetMediaSources(false).First();
+ var mediaStreams = item.GetMediaStreams();
- foreach (var stream in mediaSource.MediaStreams)
+ foreach (var stream in mediaStreams)
{
writer.WriteStartElement(stream.Type.ToString().ToLower());
@@ -378,9 +377,10 @@ namespace MediaBrowser.XbmcMetadata.Savers
if (stream.Type == MediaStreamType.Video)
{
- if (mediaSource.RunTimeTicks.HasValue)
+ var runtimeTicks = ((IHasMetadata) item).RunTimeTicks;
+ if (runtimeTicks.HasValue)
{
- var timespan = TimeSpan.FromTicks(mediaSource.RunTimeTicks.Value);
+ var timespan = TimeSpan.FromTicks(runtimeTicks.Value);
writer.WriteElementString("duration", Convert.ToInt32(timespan.TotalMinutes).ToString(UsCulture));
writer.WriteElementString("durationinseconds", Convert.ToInt32(timespan.TotalSeconds).ToString(UsCulture));
@@ -485,14 +485,9 @@ namespace MediaBrowser.XbmcMetadata.Savers
writer.WriteElementString("lockdata", item.IsLocked.ToString().ToLower());
- if (item.LockedFields.Count > 0)
+ if (item.LockedFields.Length > 0)
{
- writer.WriteElementString("lockedfields", string.Join("|", item.LockedFields.Select(i => i.ToString()).ToArray()));
- }
-
- if (!string.IsNullOrEmpty(item.DisplayMediaType))
- {
- writer.WriteElementString("type", item.DisplayMediaType);
+ writer.WriteElementString("lockedfields", string.Join("|", item.LockedFields));
}
writer.WriteElementString("dateadded", item.DateCreated.ToLocalTime().ToString(DateAddedFormat));
@@ -616,13 +611,6 @@ namespace MediaBrowser.XbmcMetadata.Savers
writtenProviderIds.Add(MetadataProviders.Tmdb.ToString());
}
- var tvcom = item.GetProviderId(MetadataProviders.Tvcom);
- if (!string.IsNullOrEmpty(tvcom))
- {
- writer.WriteElementString("tvcomid", tvcom);
- writtenProviderIds.Add(MetadataProviders.Tvcom.ToString());
- }
-
if (!string.IsNullOrEmpty(item.PreferredMetadataLanguage))
{
writer.WriteElementString("language", item.PreferredMetadataLanguage);
diff --git a/MediaBrowser.XbmcMetadata/Savers/MovieNfoSaver.cs b/MediaBrowser.XbmcMetadata/Savers/MovieNfoSaver.cs
index aea3f2c70..1989a2c28 100644
--- a/MediaBrowser.XbmcMetadata/Savers/MovieNfoSaver.cs
+++ b/MediaBrowser.XbmcMetadata/Savers/MovieNfoSaver.cs
@@ -8,7 +8,6 @@ using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Logging;
using System.Collections.Generic;
using System.IO;
-using System.Linq;
using System.Xml;
using MediaBrowser.Controller.IO;
@@ -21,7 +20,8 @@ namespace MediaBrowser.XbmcMetadata.Savers
{
protected override string GetLocalSavePath(IHasMetadata item)
{
- return GetMovieSavePaths(new ItemInfo(item), FileSystem).FirstOrDefault();
+ var paths = GetMovieSavePaths(new ItemInfo(item), FileSystem);
+ return paths.Count == 0 ? null : paths[0];
}
public static List<string> GetMovieSavePaths(ItemInfo item, IFileSystem fileSystem)
@@ -35,7 +35,7 @@ namespace MediaBrowser.XbmcMetadata.Savers
list.Add(Path.Combine(path, "VIDEO_TS", "VIDEO_TS.nfo"));
}
- if (!item.IsPlaceHolder && (item.VideoType == VideoType.Dvd || item.VideoType == VideoType.BluRay || item.VideoType == VideoType.HdDvd))
+ if (!item.IsPlaceHolder && (item.VideoType == VideoType.Dvd || item.VideoType == VideoType.BluRay))
{
var path = item.ContainingFolderPath;
diff --git a/MediaBrowser.XbmcMetadata/Savers/SeriesNfoSaver.cs b/MediaBrowser.XbmcMetadata/Savers/SeriesNfoSaver.cs
index e9b2b786a..a2f07d952 100644
--- a/MediaBrowser.XbmcMetadata/Savers/SeriesNfoSaver.cs
+++ b/MediaBrowser.XbmcMetadata/Savers/SeriesNfoSaver.cs
@@ -69,20 +69,6 @@ namespace MediaBrowser.XbmcMetadata.Savers
{
writer.WriteElementString("status", series.Status.Value.ToString());
}
-
- if (!string.IsNullOrEmpty(series.AirTime))
- {
- writer.WriteElementString("airs_time", series.AirTime);
- }
-
- if (series.AirDays.Count == 7)
- {
- writer.WriteElementString("airs_dayofweek", "Daily");
- }
- else if (series.AirDays.Count > 0)
- {
- writer.WriteElementString("airs_dayofweek", series.AirDays[0].ToString());
- }
}
protected override List<string> GetTagsUsed(IHasMetadata item)
@@ -94,9 +80,7 @@ namespace MediaBrowser.XbmcMetadata.Savers
"episodeguide",
"season",
"episode",
- "status",
- "airs_time",
- "airs_dayofweek"
+ "status"
});
return list;
}
diff --git a/MediaBrowser.sln b/MediaBrowser.sln
index 1a4638265..32485a8c9 100644
--- a/MediaBrowser.sln
+++ b/MediaBrowser.sln
@@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 14
-VisualStudioVersion = 14.0.25420.1
+# Visual Studio 15
+VisualStudioVersion = 15.0.26730.3
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{F0E0E64C-2A6F-4E35-9533-D53AC07C2CD1}"
EndProject
@@ -34,16 +34,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Model", "Media
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.WebDashboard", "MediaBrowser.WebDashboard\MediaBrowser.WebDashboard.csproj", "{5624B7B5-B5A7-41D8-9F10-CC5611109619}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Server.Implementations", "MediaBrowser.Server.Implementations\MediaBrowser.Server.Implementations.csproj", "{2E781478-814D-4A48-9D80-BFF206441A65}"
-EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Tests", "MediaBrowser.Tests\MediaBrowser.Tests.csproj", "{E22BFD35-0FCD-4A85-978A-C22DCD73A081}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Providers", "MediaBrowser.Providers\MediaBrowser.Providers.csproj", "{442B5058-DCAF-4263-BB6A-F21E31120A1B}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.ServerApplication", "MediaBrowser.ServerApplication\MediaBrowser.ServerApplication.csproj", "{94ADE4D3-B7EC-45CD-A200-CC469433072B}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.MediaEncoding", "MediaBrowser.MediaEncoding\MediaBrowser.MediaEncoding.csproj", "{0BD82FA6-EB8A-4452-8AF5-74F9C3849451}"
-EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenSubtitlesHandler", "OpenSubtitlesHandler\OpenSubtitlesHandler.csproj", "{4A4402D4-E910-443B-B8FC-2C18286A2CA0}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.XbmcMetadata", "MediaBrowser.XbmcMetadata\MediaBrowser.XbmcMetadata.csproj", "{23499896-B135-4527-8574-C26E926EA99E}"
@@ -70,12 +66,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Emby.Drawing.ImageMagick",
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Emby.Drawing.Skia", "Emby.Drawing.Skia\Emby.Drawing.Skia.csproj", "{2312DA6D-FF86-4597-9777-BCEEC32D96DD}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Emby.Server.Core", "Emby.Server.Core\Emby.Server.Core.csproj", "{776B9F0C-5195-45E3-9A36-1CC1F0D8E0B0}"
-EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mono.Nat", "Mono.Nat\Mono.Nat.csproj", "{CB7F2326-6497-4A3D-BA03-48513B17A7BE}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Emby.Common.Implementations", "Emby.Common.Implementations\Emby.Common.Implementations.csproj", "{1E37A338-9F57-4B70-BD6D-BB9C591E319B}"
-EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SocketHttpListener", "SocketHttpListener\SocketHttpListener.csproj", "{1D74413B-E7CF-455B-B021-F52BDF881542}"
EndProject
Global
@@ -272,37 +264,6 @@ Global
{5624B7B5-B5A7-41D8-9F10-CC5611109619}.Signed|x64.Build.0 = Release|Any CPU
{5624B7B5-B5A7-41D8-9F10-CC5611109619}.Signed|x86.ActiveCfg = Release|Any CPU
{5624B7B5-B5A7-41D8-9F10-CC5611109619}.Signed|x86.Build.0 = Release|Any CPU
- {2E781478-814D-4A48-9D80-BFF206441A65}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {2E781478-814D-4A48-9D80-BFF206441A65}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {2E781478-814D-4A48-9D80-BFF206441A65}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
- {2E781478-814D-4A48-9D80-BFF206441A65}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
- {2E781478-814D-4A48-9D80-BFF206441A65}.Debug|Win32.ActiveCfg = Debug|Any CPU
- {2E781478-814D-4A48-9D80-BFF206441A65}.Debug|x64.ActiveCfg = Debug|Any CPU
- {2E781478-814D-4A48-9D80-BFF206441A65}.Debug|x86.ActiveCfg = Debug|Any CPU
- {2E781478-814D-4A48-9D80-BFF206441A65}.Release Mono|Any CPU.ActiveCfg = Release|Any CPU
- {2E781478-814D-4A48-9D80-BFF206441A65}.Release Mono|Any CPU.Build.0 = Release|Any CPU
- {2E781478-814D-4A48-9D80-BFF206441A65}.Release Mono|Mixed Platforms.ActiveCfg = Release|Any CPU
- {2E781478-814D-4A48-9D80-BFF206441A65}.Release Mono|Mixed Platforms.Build.0 = Release|Any CPU
- {2E781478-814D-4A48-9D80-BFF206441A65}.Release Mono|Win32.ActiveCfg = Release|Any CPU
- {2E781478-814D-4A48-9D80-BFF206441A65}.Release Mono|x64.ActiveCfg = Release|Any CPU
- {2E781478-814D-4A48-9D80-BFF206441A65}.Release Mono|x86.ActiveCfg = Release|Any CPU
- {2E781478-814D-4A48-9D80-BFF206441A65}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {2E781478-814D-4A48-9D80-BFF206441A65}.Release|Any CPU.Build.0 = Release|Any CPU
- {2E781478-814D-4A48-9D80-BFF206441A65}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
- {2E781478-814D-4A48-9D80-BFF206441A65}.Release|Mixed Platforms.Build.0 = Release|Any CPU
- {2E781478-814D-4A48-9D80-BFF206441A65}.Release|Win32.ActiveCfg = Release|Any CPU
- {2E781478-814D-4A48-9D80-BFF206441A65}.Release|x64.ActiveCfg = Release|Any CPU
- {2E781478-814D-4A48-9D80-BFF206441A65}.Release|x86.ActiveCfg = Release|Any CPU
- {2E781478-814D-4A48-9D80-BFF206441A65}.Signed|Any CPU.ActiveCfg = Release|Any CPU
- {2E781478-814D-4A48-9D80-BFF206441A65}.Signed|Any CPU.Build.0 = Release|Any CPU
- {2E781478-814D-4A48-9D80-BFF206441A65}.Signed|Mixed Platforms.ActiveCfg = Release|Any CPU
- {2E781478-814D-4A48-9D80-BFF206441A65}.Signed|Mixed Platforms.Build.0 = Release|Any CPU
- {2E781478-814D-4A48-9D80-BFF206441A65}.Signed|Win32.ActiveCfg = Release|Any CPU
- {2E781478-814D-4A48-9D80-BFF206441A65}.Signed|Win32.Build.0 = Release|Any CPU
- {2E781478-814D-4A48-9D80-BFF206441A65}.Signed|x64.ActiveCfg = Release|Any CPU
- {2E781478-814D-4A48-9D80-BFF206441A65}.Signed|x64.Build.0 = Release|Any CPU
- {2E781478-814D-4A48-9D80-BFF206441A65}.Signed|x86.ActiveCfg = Release|Any CPU
- {2E781478-814D-4A48-9D80-BFF206441A65}.Signed|x86.Build.0 = Release|Any CPU
{E22BFD35-0FCD-4A85-978A-C22DCD73A081}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E22BFD35-0FCD-4A85-978A-C22DCD73A081}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E22BFD35-0FCD-4A85-978A-C22DCD73A081}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
@@ -394,37 +355,6 @@ Global
{94ADE4D3-B7EC-45CD-A200-CC469433072B}.Signed|x64.Build.0 = Release|Any CPU
{94ADE4D3-B7EC-45CD-A200-CC469433072B}.Signed|x86.ActiveCfg = Debug|x86
{94ADE4D3-B7EC-45CD-A200-CC469433072B}.Signed|x86.Build.0 = Debug|x86
- {0BD82FA6-EB8A-4452-8AF5-74F9C3849451}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {0BD82FA6-EB8A-4452-8AF5-74F9C3849451}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {0BD82FA6-EB8A-4452-8AF5-74F9C3849451}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
- {0BD82FA6-EB8A-4452-8AF5-74F9C3849451}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
- {0BD82FA6-EB8A-4452-8AF5-74F9C3849451}.Debug|Win32.ActiveCfg = Debug|Any CPU
- {0BD82FA6-EB8A-4452-8AF5-74F9C3849451}.Debug|x64.ActiveCfg = Debug|Any CPU
- {0BD82FA6-EB8A-4452-8AF5-74F9C3849451}.Debug|x86.ActiveCfg = Debug|Any CPU
- {0BD82FA6-EB8A-4452-8AF5-74F9C3849451}.Release Mono|Any CPU.ActiveCfg = Release|Any CPU
- {0BD82FA6-EB8A-4452-8AF5-74F9C3849451}.Release Mono|Any CPU.Build.0 = Release|Any CPU
- {0BD82FA6-EB8A-4452-8AF5-74F9C3849451}.Release Mono|Mixed Platforms.ActiveCfg = Release|Any CPU
- {0BD82FA6-EB8A-4452-8AF5-74F9C3849451}.Release Mono|Mixed Platforms.Build.0 = Release|Any CPU
- {0BD82FA6-EB8A-4452-8AF5-74F9C3849451}.Release Mono|Win32.ActiveCfg = Release|Any CPU
- {0BD82FA6-EB8A-4452-8AF5-74F9C3849451}.Release Mono|x64.ActiveCfg = Release|Any CPU
- {0BD82FA6-EB8A-4452-8AF5-74F9C3849451}.Release Mono|x86.ActiveCfg = Release|Any CPU
- {0BD82FA6-EB8A-4452-8AF5-74F9C3849451}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {0BD82FA6-EB8A-4452-8AF5-74F9C3849451}.Release|Any CPU.Build.0 = Release|Any CPU
- {0BD82FA6-EB8A-4452-8AF5-74F9C3849451}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
- {0BD82FA6-EB8A-4452-8AF5-74F9C3849451}.Release|Mixed Platforms.Build.0 = Release|Any CPU
- {0BD82FA6-EB8A-4452-8AF5-74F9C3849451}.Release|Win32.ActiveCfg = Release|Any CPU
- {0BD82FA6-EB8A-4452-8AF5-74F9C3849451}.Release|x64.ActiveCfg = Release|Any CPU
- {0BD82FA6-EB8A-4452-8AF5-74F9C3849451}.Release|x86.ActiveCfg = Release|Any CPU
- {0BD82FA6-EB8A-4452-8AF5-74F9C3849451}.Signed|Any CPU.ActiveCfg = Release|Any CPU
- {0BD82FA6-EB8A-4452-8AF5-74F9C3849451}.Signed|Any CPU.Build.0 = Release|Any CPU
- {0BD82FA6-EB8A-4452-8AF5-74F9C3849451}.Signed|Mixed Platforms.ActiveCfg = Release|Any CPU
- {0BD82FA6-EB8A-4452-8AF5-74F9C3849451}.Signed|Mixed Platforms.Build.0 = Release|Any CPU
- {0BD82FA6-EB8A-4452-8AF5-74F9C3849451}.Signed|Win32.ActiveCfg = Release|Any CPU
- {0BD82FA6-EB8A-4452-8AF5-74F9C3849451}.Signed|Win32.Build.0 = Release|Any CPU
- {0BD82FA6-EB8A-4452-8AF5-74F9C3849451}.Signed|x64.ActiveCfg = Release|Any CPU
- {0BD82FA6-EB8A-4452-8AF5-74F9C3849451}.Signed|x64.Build.0 = Release|Any CPU
- {0BD82FA6-EB8A-4452-8AF5-74F9C3849451}.Signed|x86.ActiveCfg = Release|Any CPU
- {0BD82FA6-EB8A-4452-8AF5-74F9C3849451}.Signed|x86.Build.0 = Release|Any CPU
{4A4402D4-E910-443B-B8FC-2C18286A2CA0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4A4402D4-E910-443B-B8FC-2C18286A2CA0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4A4402D4-E910-443B-B8FC-2C18286A2CA0}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
@@ -905,46 +835,6 @@ Global
{2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Signed|x64.Build.0 = Release|Any CPU
{2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Signed|x86.ActiveCfg = Release|Any CPU
{2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Signed|x86.Build.0 = Release|Any CPU
- {776B9F0C-5195-45E3-9A36-1CC1F0D8E0B0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {776B9F0C-5195-45E3-9A36-1CC1F0D8E0B0}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {776B9F0C-5195-45E3-9A36-1CC1F0D8E0B0}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
- {776B9F0C-5195-45E3-9A36-1CC1F0D8E0B0}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
- {776B9F0C-5195-45E3-9A36-1CC1F0D8E0B0}.Debug|Win32.ActiveCfg = Debug|Any CPU
- {776B9F0C-5195-45E3-9A36-1CC1F0D8E0B0}.Debug|Win32.Build.0 = Debug|Any CPU
- {776B9F0C-5195-45E3-9A36-1CC1F0D8E0B0}.Debug|x64.ActiveCfg = Debug|Any CPU
- {776B9F0C-5195-45E3-9A36-1CC1F0D8E0B0}.Debug|x64.Build.0 = Debug|Any CPU
- {776B9F0C-5195-45E3-9A36-1CC1F0D8E0B0}.Debug|x86.ActiveCfg = Debug|Any CPU
- {776B9F0C-5195-45E3-9A36-1CC1F0D8E0B0}.Debug|x86.Build.0 = Debug|Any CPU
- {776B9F0C-5195-45E3-9A36-1CC1F0D8E0B0}.Release Mono|Any CPU.ActiveCfg = Release|Any CPU
- {776B9F0C-5195-45E3-9A36-1CC1F0D8E0B0}.Release Mono|Any CPU.Build.0 = Release|Any CPU
- {776B9F0C-5195-45E3-9A36-1CC1F0D8E0B0}.Release Mono|Mixed Platforms.ActiveCfg = Release|Any CPU
- {776B9F0C-5195-45E3-9A36-1CC1F0D8E0B0}.Release Mono|Mixed Platforms.Build.0 = Release|Any CPU
- {776B9F0C-5195-45E3-9A36-1CC1F0D8E0B0}.Release Mono|Win32.ActiveCfg = Release|Any CPU
- {776B9F0C-5195-45E3-9A36-1CC1F0D8E0B0}.Release Mono|Win32.Build.0 = Release|Any CPU
- {776B9F0C-5195-45E3-9A36-1CC1F0D8E0B0}.Release Mono|x64.ActiveCfg = Release|Any CPU
- {776B9F0C-5195-45E3-9A36-1CC1F0D8E0B0}.Release Mono|x64.Build.0 = Release|Any CPU
- {776B9F0C-5195-45E3-9A36-1CC1F0D8E0B0}.Release Mono|x86.ActiveCfg = Release|Any CPU
- {776B9F0C-5195-45E3-9A36-1CC1F0D8E0B0}.Release Mono|x86.Build.0 = Release|Any CPU
- {776B9F0C-5195-45E3-9A36-1CC1F0D8E0B0}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {776B9F0C-5195-45E3-9A36-1CC1F0D8E0B0}.Release|Any CPU.Build.0 = Release|Any CPU
- {776B9F0C-5195-45E3-9A36-1CC1F0D8E0B0}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
- {776B9F0C-5195-45E3-9A36-1CC1F0D8E0B0}.Release|Mixed Platforms.Build.0 = Release|Any CPU
- {776B9F0C-5195-45E3-9A36-1CC1F0D8E0B0}.Release|Win32.ActiveCfg = Release|Any CPU
- {776B9F0C-5195-45E3-9A36-1CC1F0D8E0B0}.Release|Win32.Build.0 = Release|Any CPU
- {776B9F0C-5195-45E3-9A36-1CC1F0D8E0B0}.Release|x64.ActiveCfg = Release|Any CPU
- {776B9F0C-5195-45E3-9A36-1CC1F0D8E0B0}.Release|x64.Build.0 = Release|Any CPU
- {776B9F0C-5195-45E3-9A36-1CC1F0D8E0B0}.Release|x86.ActiveCfg = Release|Any CPU
- {776B9F0C-5195-45E3-9A36-1CC1F0D8E0B0}.Release|x86.Build.0 = Release|Any CPU
- {776B9F0C-5195-45E3-9A36-1CC1F0D8E0B0}.Signed|Any CPU.ActiveCfg = Release|Any CPU
- {776B9F0C-5195-45E3-9A36-1CC1F0D8E0B0}.Signed|Any CPU.Build.0 = Release|Any CPU
- {776B9F0C-5195-45E3-9A36-1CC1F0D8E0B0}.Signed|Mixed Platforms.ActiveCfg = Release|Any CPU
- {776B9F0C-5195-45E3-9A36-1CC1F0D8E0B0}.Signed|Mixed Platforms.Build.0 = Release|Any CPU
- {776B9F0C-5195-45E3-9A36-1CC1F0D8E0B0}.Signed|Win32.ActiveCfg = Release|Any CPU
- {776B9F0C-5195-45E3-9A36-1CC1F0D8E0B0}.Signed|Win32.Build.0 = Release|Any CPU
- {776B9F0C-5195-45E3-9A36-1CC1F0D8E0B0}.Signed|x64.ActiveCfg = Release|Any CPU
- {776B9F0C-5195-45E3-9A36-1CC1F0D8E0B0}.Signed|x64.Build.0 = Release|Any CPU
- {776B9F0C-5195-45E3-9A36-1CC1F0D8E0B0}.Signed|x86.ActiveCfg = Release|Any CPU
- {776B9F0C-5195-45E3-9A36-1CC1F0D8E0B0}.Signed|x86.Build.0 = Release|Any CPU
{CB7F2326-6497-4A3D-BA03-48513B17A7BE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CB7F2326-6497-4A3D-BA03-48513B17A7BE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CB7F2326-6497-4A3D-BA03-48513B17A7BE}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
@@ -985,46 +875,6 @@ Global
{CB7F2326-6497-4A3D-BA03-48513B17A7BE}.Signed|x64.Build.0 = Release|Any CPU
{CB7F2326-6497-4A3D-BA03-48513B17A7BE}.Signed|x86.ActiveCfg = Release|Any CPU
{CB7F2326-6497-4A3D-BA03-48513B17A7BE}.Signed|x86.Build.0 = Release|Any CPU
- {1E37A338-9F57-4B70-BD6D-BB9C591E319B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {1E37A338-9F57-4B70-BD6D-BB9C591E319B}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {1E37A338-9F57-4B70-BD6D-BB9C591E319B}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
- {1E37A338-9F57-4B70-BD6D-BB9C591E319B}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
- {1E37A338-9F57-4B70-BD6D-BB9C591E319B}.Debug|Win32.ActiveCfg = Debug|Any CPU
- {1E37A338-9F57-4B70-BD6D-BB9C591E319B}.Debug|Win32.Build.0 = Debug|Any CPU
- {1E37A338-9F57-4B70-BD6D-BB9C591E319B}.Debug|x64.ActiveCfg = Debug|Any CPU
- {1E37A338-9F57-4B70-BD6D-BB9C591E319B}.Debug|x64.Build.0 = Debug|Any CPU
- {1E37A338-9F57-4B70-BD6D-BB9C591E319B}.Debug|x86.ActiveCfg = Debug|Any CPU
- {1E37A338-9F57-4B70-BD6D-BB9C591E319B}.Debug|x86.Build.0 = Debug|Any CPU
- {1E37A338-9F57-4B70-BD6D-BB9C591E319B}.Release Mono|Any CPU.ActiveCfg = Release|Any CPU
- {1E37A338-9F57-4B70-BD6D-BB9C591E319B}.Release Mono|Any CPU.Build.0 = Release|Any CPU
- {1E37A338-9F57-4B70-BD6D-BB9C591E319B}.Release Mono|Mixed Platforms.ActiveCfg = Release|Any CPU
- {1E37A338-9F57-4B70-BD6D-BB9C591E319B}.Release Mono|Mixed Platforms.Build.0 = Release|Any CPU
- {1E37A338-9F57-4B70-BD6D-BB9C591E319B}.Release Mono|Win32.ActiveCfg = Release|Any CPU
- {1E37A338-9F57-4B70-BD6D-BB9C591E319B}.Release Mono|Win32.Build.0 = Release|Any CPU
- {1E37A338-9F57-4B70-BD6D-BB9C591E319B}.Release Mono|x64.ActiveCfg = Release|Any CPU
- {1E37A338-9F57-4B70-BD6D-BB9C591E319B}.Release Mono|x64.Build.0 = Release|Any CPU
- {1E37A338-9F57-4B70-BD6D-BB9C591E319B}.Release Mono|x86.ActiveCfg = Release|Any CPU
- {1E37A338-9F57-4B70-BD6D-BB9C591E319B}.Release Mono|x86.Build.0 = Release|Any CPU
- {1E37A338-9F57-4B70-BD6D-BB9C591E319B}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {1E37A338-9F57-4B70-BD6D-BB9C591E319B}.Release|Any CPU.Build.0 = Release|Any CPU
- {1E37A338-9F57-4B70-BD6D-BB9C591E319B}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
- {1E37A338-9F57-4B70-BD6D-BB9C591E319B}.Release|Mixed Platforms.Build.0 = Release|Any CPU
- {1E37A338-9F57-4B70-BD6D-BB9C591E319B}.Release|Win32.ActiveCfg = Release|Any CPU
- {1E37A338-9F57-4B70-BD6D-BB9C591E319B}.Release|Win32.Build.0 = Release|Any CPU
- {1E37A338-9F57-4B70-BD6D-BB9C591E319B}.Release|x64.ActiveCfg = Release|Any CPU
- {1E37A338-9F57-4B70-BD6D-BB9C591E319B}.Release|x64.Build.0 = Release|Any CPU
- {1E37A338-9F57-4B70-BD6D-BB9C591E319B}.Release|x86.ActiveCfg = Release|Any CPU
- {1E37A338-9F57-4B70-BD6D-BB9C591E319B}.Release|x86.Build.0 = Release|Any CPU
- {1E37A338-9F57-4B70-BD6D-BB9C591E319B}.Signed|Any CPU.ActiveCfg = Release|Any CPU
- {1E37A338-9F57-4B70-BD6D-BB9C591E319B}.Signed|Any CPU.Build.0 = Release|Any CPU
- {1E37A338-9F57-4B70-BD6D-BB9C591E319B}.Signed|Mixed Platforms.ActiveCfg = Release|Any CPU
- {1E37A338-9F57-4B70-BD6D-BB9C591E319B}.Signed|Mixed Platforms.Build.0 = Release|Any CPU
- {1E37A338-9F57-4B70-BD6D-BB9C591E319B}.Signed|Win32.ActiveCfg = Release|Any CPU
- {1E37A338-9F57-4B70-BD6D-BB9C591E319B}.Signed|Win32.Build.0 = Release|Any CPU
- {1E37A338-9F57-4B70-BD6D-BB9C591E319B}.Signed|x64.ActiveCfg = Release|Any CPU
- {1E37A338-9F57-4B70-BD6D-BB9C591E319B}.Signed|x64.Build.0 = Release|Any CPU
- {1E37A338-9F57-4B70-BD6D-BB9C591E319B}.Signed|x86.ActiveCfg = Release|Any CPU
- {1E37A338-9F57-4B70-BD6D-BB9C591E319B}.Signed|x86.Build.0 = Release|Any CPU
{1D74413B-E7CF-455B-B021-F52BDF881542}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1D74413B-E7CF-455B-B021-F52BDF881542}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1D74413B-E7CF-455B-B021-F52BDF881542}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
@@ -1069,4 +919,7 @@ Global
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {3448830C-EBDC-426C-85CD-7BBB9651A7FE}
+ EndGlobalSection
EndGlobal
diff --git a/Mono.Nat/NatUtility.cs b/Mono.Nat/NatUtility.cs
index 983e86833..b9efd9bbd 100644
--- a/Mono.Nat/NatUtility.cs
+++ b/Mono.Nat/NatUtility.cs
@@ -30,7 +30,6 @@ using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;
-using System.Linq;
using System.Collections.Generic;
using System.IO;
using System.Net.NetworkInformation;
@@ -98,16 +97,14 @@ namespace Mono.Nat
{
try
{
- var enabledProtocols = EnabledProtocols.ToList();
-
- if (enabledProtocols.Contains(PmpSearcher.Instance.Protocol))
+ if (EnabledProtocols.Contains(PmpSearcher.Instance.Protocol))
{
await Receive(PmpSearcher.Instance, PmpSearcher.sockets).ConfigureAwait(false);
}
foreach (ISearcher s in controllers)
{
- if (s.NextSearch < DateTime.Now && enabledProtocols.Contains(s.Protocol))
+ if (s.NextSearch < DateTime.Now && EnabledProtocols.Contains(s.Protocol))
{
Log("Searching for: {0}", s.GetType().Name);
s.Search();
diff --git a/Mono.Nat/Pmp/PmpNatDevice.cs b/Mono.Nat/Pmp/PmpNatDevice.cs
index 10ebbdc2c..fb45b365b 100644
--- a/Mono.Nat/Pmp/PmpNatDevice.cs
+++ b/Mono.Nat/Pmp/PmpNatDevice.cs
@@ -31,6 +31,7 @@ using System.Net.Sockets;
using System.Threading;
using System.Collections.Generic;
using System.Threading.Tasks;
+using MediaBrowser.Model.Extensions;
namespace Mono.Nat.Pmp
{
@@ -86,7 +87,7 @@ namespace Mono.Nat.Pmp
try
{
- byte[] buffer = package.ToArray();
+ byte[] buffer = package.ToArray(package.Count);
int attempt = 0;
int delay = PmpConstants.RetryDelay;
diff --git a/Mono.Nat/Pmp/Searchers/PmpSearcher.cs b/Mono.Nat/Pmp/Searchers/PmpSearcher.cs
index 4a8a90412..def50fb72 100644
--- a/Mono.Nat/Pmp/Searchers/PmpSearcher.cs
+++ b/Mono.Nat/Pmp/Searchers/PmpSearcher.cs
@@ -36,7 +36,6 @@ using System.Net;
using Mono.Nat.Pmp;
using System.Net.NetworkInformation;
using System.Net.Sockets;
-using System.Linq;
using System.Threading.Tasks;
namespace Mono.Nat
diff --git a/Mono.Nat/Upnp/Upnp.cs b/Mono.Nat/Upnp/Upnp.cs
index 38d949250..e9321f874 100644
--- a/Mono.Nat/Upnp/Upnp.cs
+++ b/Mono.Nat/Upnp/Upnp.cs
@@ -30,7 +30,6 @@
using System;
using System.Collections.Generic;
-using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
diff --git a/Nuget/MediaBrowser.Common.Internal.nuspec b/Nuget/MediaBrowser.Common.Internal.nuspec
deleted file mode 100644
index fdc2b9f7d..000000000
--- a/Nuget/MediaBrowser.Common.Internal.nuspec
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
- <metadata>
- <id>MediaBrowser.Common.Internal</id>
- <version>3.0.681</version>
- <title>Emby.Common.Internal</title>
- <authors>Luke</authors>
- <owners>ebr,Luke,scottisafool</owners>
- <projectUrl>https://github.com/MediaBrowser/Emby</projectUrl>
- <iconUrl>http://www.mb3admin.com/images/mb3icons1-1.png</iconUrl>
- <requireLicenseAcceptance>false</requireLicenseAcceptance>
- <description>Contains common components shared by Emby Theater and Emby Server. Not intended for plugin developer consumption.</description>
- <copyright>Copyright © Emby 2013</copyright>
- <dependencies>
- <dependency id="MediaBrowser.Common" version="3.0.680" />
- <dependency id="NLog" version="4.3.8" />
- <dependency id="SimpleInjector" version="3.2.2" />
- </dependencies>
- </metadata>
- <files>
- <file src="dlls\MediaBrowser.Common.Implementations.dll" target="lib\net45\MediaBrowser.Common.Implementations.dll" />
- <file src="..\ThirdParty\ServiceStack.Text\ServiceStack.Text.dll" target="lib\net45\ServiceStack.Text.dll" />
- </files>
-</package> \ No newline at end of file
diff --git a/Nuget/MediaBrowser.Common.nuspec b/Nuget/MediaBrowser.Common.nuspec
index ff0973b0f..a3cb05bf7 100644
--- a/Nuget/MediaBrowser.Common.nuspec
+++ b/Nuget/MediaBrowser.Common.nuspec
@@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
<metadata>
<id>MediaBrowser.Common</id>
- <version>3.0.709</version>
+ <version>3.0.748</version>
<title>Emby.Common</title>
<authors>Emby Team</authors>
<owners>ebr,Luke,scottisafool</owners>
diff --git a/Nuget/MediaBrowser.Server.Core.nuspec b/Nuget/MediaBrowser.Server.Core.nuspec
index 31b8ee026..6c2f2d399 100644
--- a/Nuget/MediaBrowser.Server.Core.nuspec
+++ b/Nuget/MediaBrowser.Server.Core.nuspec
@@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata>
<id>MediaBrowser.Server.Core</id>
- <version>3.0.709</version>
+ <version>3.0.748</version>
<title>Emby.Server.Core</title>
<authors>Emby Team</authors>
<owners>ebr,Luke,scottisafool</owners>
@@ -12,7 +12,7 @@
<description>Contains core components required to build plugins for Emby Server.</description>
<copyright>Copyright © Emby 2013</copyright>
<dependencies>
- <dependency id="MediaBrowser.Common" version="3.0.709" />
+ <dependency id="MediaBrowser.Common" version="3.0.748" />
</dependencies>
</metadata>
<files>
diff --git a/RSSDP/CustomHttpHeaders.cs b/RSSDP/CustomHttpHeaders.cs
index 9250d612f..f2412d2e7 100644
--- a/RSSDP/CustomHttpHeaders.cs
+++ b/RSSDP/CustomHttpHeaders.cs
@@ -1,7 +1,6 @@
using System;
using System.Collections;
using System.Collections.Generic;
-using System.Linq;
using System.Text;
namespace Rssdp
diff --git a/RSSDP/DeviceAvailableEventArgs.cs b/RSSDP/DeviceAvailableEventArgs.cs
index 046c10524..d80b4b65b 100644
--- a/RSSDP/DeviceAvailableEventArgs.cs
+++ b/RSSDP/DeviceAvailableEventArgs.cs
@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
-using System.Linq;
using System.Text;
using System.Threading.Tasks;
using MediaBrowser.Model.Net;
diff --git a/RSSDP/DeviceEventArgs.cs b/RSSDP/DeviceEventArgs.cs
index e0c19c4c4..774d812ee 100644
--- a/RSSDP/DeviceEventArgs.cs
+++ b/RSSDP/DeviceEventArgs.cs
@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
-using System.Linq;
using System.Text;
namespace Rssdp
diff --git a/RSSDP/DeviceUnavailableEventArgs.cs b/RSSDP/DeviceUnavailableEventArgs.cs
index 5b7c1437a..171a834a0 100644
--- a/RSSDP/DeviceUnavailableEventArgs.cs
+++ b/RSSDP/DeviceUnavailableEventArgs.cs
@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
-using System.Linq;
using System.Text;
using System.Threading.Tasks;
diff --git a/RSSDP/DiscoveredSsdpDevice.cs b/RSSDP/DiscoveredSsdpDevice.cs
index 58f0acfa5..54701890c 100644
--- a/RSSDP/DiscoveredSsdpDevice.cs
+++ b/RSSDP/DiscoveredSsdpDevice.cs
@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
-using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
diff --git a/RSSDP/DisposableManagedObjectBase.cs b/RSSDP/DisposableManagedObjectBase.cs
index 87f2aa71c..1288ba721 100644
--- a/RSSDP/DisposableManagedObjectBase.cs
+++ b/RSSDP/DisposableManagedObjectBase.cs
@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
-using System.Linq;
using System.Text;
using System.Threading.Tasks;
diff --git a/RSSDP/IUPnPDeviceValidator.cs b/RSSDP/IUPnPDeviceValidator.cs
index 39b80742e..8fa48df7b 100644
--- a/RSSDP/IUPnPDeviceValidator.cs
+++ b/RSSDP/IUPnPDeviceValidator.cs
@@ -11,13 +11,13 @@ namespace Rssdp.Infrastructure
/// Returns an enumerable set of strings, each one being a description of an invalid property on the specified root device.
/// </summary>
/// <param name="device">The <see cref="SsdpRootDevice"/> to validate.</param>
- System.Collections.Generic.IEnumerable<string> GetValidationErrors(SsdpRootDevice device);
+ System.Collections.Generic.List<string> GetValidationErrors(SsdpRootDevice device);
/// <summary>
/// Returns an enumerable set of strings, each one being a description of an invalid property on the specified device.
/// </summary>
/// <param name="device">The <see cref="SsdpDevice"/> to validate.</param>
- System.Collections.Generic.IEnumerable<string> GetValidationErrors(SsdpDevice device);
+ System.Collections.Generic.List<string> GetValidationErrors(SsdpDevice device);
/// <summary>
/// Validates the specified device and throws an <see cref="System.InvalidOperationException"/> if there are any validation errors.
diff --git a/RSSDP/RequestReceivedEventArgs.cs b/RSSDP/RequestReceivedEventArgs.cs
index 03c059634..f4e367760 100644
--- a/RSSDP/RequestReceivedEventArgs.cs
+++ b/RSSDP/RequestReceivedEventArgs.cs
@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
-using System.Linq;
using System.Net;
using System.Net.Http;
using System.Text;
diff --git a/RSSDP/ResponseReceivedEventArgs.cs b/RSSDP/ResponseReceivedEventArgs.cs
index c983fa204..f67d5da90 100644
--- a/RSSDP/ResponseReceivedEventArgs.cs
+++ b/RSSDP/ResponseReceivedEventArgs.cs
@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
-using System.Linq;
using System.Net;
using System.Net.Http;
using System.Text;
diff --git a/RSSDP/SsdpCommunicationsServer.cs b/RSSDP/SsdpCommunicationsServer.cs
index 91004b76f..a4be24ebf 100644
--- a/RSSDP/SsdpCommunicationsServer.cs
+++ b/RSSDP/SsdpCommunicationsServer.cs
@@ -364,7 +364,7 @@ namespace Rssdp.Infrastructure
if (_enableMultiSocketBinding)
{
- foreach (var address in _networkManager.GetLocalIpAddresses().ToList())
+ foreach (var address in _networkManager.GetLocalIpAddresses())
{
try
{
diff --git a/RSSDP/SsdpConstants.cs b/RSSDP/SsdpConstants.cs
index c839d9e0b..87f01f9e0 100644
--- a/RSSDP/SsdpConstants.cs
+++ b/RSSDP/SsdpConstants.cs
@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
-using System.Linq;
using System.Text;
using System.Threading.Tasks;
diff --git a/RSSDP/SsdpDevice.cs b/RSSDP/SsdpDevice.cs
index a595742d0..cda11f0a4 100644
--- a/RSSDP/SsdpDevice.cs
+++ b/RSSDP/SsdpDevice.cs
@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
-using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
@@ -283,7 +282,7 @@ namespace Rssdp
/// </summary>
/// <seealso cref="AddDevice"/>
/// <seealso cref="RemoveDevice"/>
- public IEnumerable<SsdpDevice> Devices
+ public IList<SsdpDevice> Devices
{
get;
private set;
@@ -466,7 +465,7 @@ namespace Rssdp
private static void WriteIcons(XmlWriter writer, SsdpDevice device)
{
- if (device.Icons.Any())
+ if (device.Icons.Count > 0)
{
writer.WriteStartElement("iconList");
@@ -489,7 +488,7 @@ namespace Rssdp
private void WriteChildDevices(XmlWriter writer, SsdpDevice parentDevice)
{
- if (parentDevice.Devices.Any())
+ if (parentDevice.Devices.Count > 0)
{
writer.WriteStartElement("deviceList");
diff --git a/RSSDP/SsdpDeviceExtensions.cs b/RSSDP/SsdpDeviceExtensions.cs
index 0ad710a6b..6e1b45646 100644
--- a/RSSDP/SsdpDeviceExtensions.cs
+++ b/RSSDP/SsdpDeviceExtensions.cs
@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
-using System.Linq;
using System.Text;
namespace Rssdp
diff --git a/RSSDP/SsdpDeviceIcon.cs b/RSSDP/SsdpDeviceIcon.cs
index 4ffda58ff..3ed707c80 100644
--- a/RSSDP/SsdpDeviceIcon.cs
+++ b/RSSDP/SsdpDeviceIcon.cs
@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
-using System.Linq;
using System.Text;
using System.Threading.Tasks;
diff --git a/RSSDP/SsdpDeviceLocator.cs b/RSSDP/SsdpDeviceLocator.cs
index 3ea17237d..8fe4d4a14 100644
--- a/RSSDP/SsdpDeviceLocator.cs
+++ b/RSSDP/SsdpDeviceLocator.cs
@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
-using System.Linq;
using System.Text;
using MediaBrowser.Model.Net;
using MediaBrowser.Model.Threading;
diff --git a/RSSDP/SsdpDeviceLocatorBase.cs b/RSSDP/SsdpDeviceLocatorBase.cs
index 1adb95cdf..d1eaef88a 100644
--- a/RSSDP/SsdpDeviceLocatorBase.cs
+++ b/RSSDP/SsdpDeviceLocatorBase.cs
@@ -127,7 +127,7 @@ namespace Rssdp.Infrastructure
}
catch (Exception ex)
{
-
+
}
}
@@ -543,17 +543,9 @@ namespace Rssdp.Infrastructure
}
}
- private IEnumerable<DiscoveredSsdpDevice> GetUnexpiredDevices()
- {
- lock (_Devices)
- {
- return (from device in _Devices where !device.IsExpired() select device).ToArray();
- }
- }
-
private bool DeviceDied(string deviceUsn, bool expired)
{
- IEnumerable<DiscoveredSsdpDevice> existingDevices = null;
+ List<DiscoveredSsdpDevice> existingDevices = null;
lock (_Devices)
{
existingDevices = FindExistingDeviceNotifications(_Devices, deviceUsn);
@@ -565,7 +557,7 @@ namespace Rssdp.Infrastructure
}
}
- if (existingDevices != null && existingDevices.Any())
+ if (existingDevices != null && existingDevices.Count > 0)
{
foreach (var removedDevice in existingDevices)
{
@@ -591,12 +583,29 @@ namespace Rssdp.Infrastructure
private static DiscoveredSsdpDevice FindExistingDeviceNotification(IEnumerable<DiscoveredSsdpDevice> devices, string notificationType, string usn)
{
- return (from d in devices where d.NotificationType == notificationType && d.Usn == usn select d).FirstOrDefault();
+ foreach (var d in devices)
+ {
+ if (d.NotificationType == notificationType && d.Usn == usn)
+ {
+ return d;
+ }
+ }
+ return null;
}
- private static IEnumerable<DiscoveredSsdpDevice> FindExistingDeviceNotifications(IList<DiscoveredSsdpDevice> devices, string usn)
+ private static List<DiscoveredSsdpDevice> FindExistingDeviceNotifications(IList<DiscoveredSsdpDevice> devices, string usn)
{
- return (from d in devices where d.Usn == usn select d).ToArray();
+ var list = new List<DiscoveredSsdpDevice>();
+
+ foreach (var d in devices)
+ {
+ if (d.Usn == usn)
+ {
+ list.Add(d);
+ }
+ }
+
+ return list;
}
#endregion
diff --git a/RSSDP/SsdpDeviceProperties.cs b/RSSDP/SsdpDeviceProperties.cs
index 850dfb0ba..ae5309da5 100644
--- a/RSSDP/SsdpDeviceProperties.cs
+++ b/RSSDP/SsdpDeviceProperties.cs
@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
-using System.Linq;
using System.Text;
namespace Rssdp
diff --git a/RSSDP/SsdpDeviceProperty.cs b/RSSDP/SsdpDeviceProperty.cs
index 3a8dd2ec7..3abcfb9aa 100644
--- a/RSSDP/SsdpDeviceProperty.cs
+++ b/RSSDP/SsdpDeviceProperty.cs
@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
-using System.Linq;
using System.Text;
using System.Threading.Tasks;
diff --git a/RSSDP/SsdpDevicePublisher.cs b/RSSDP/SsdpDevicePublisher.cs
index 1c17c7837..2aa143775 100644
--- a/RSSDP/SsdpDevicePublisher.cs
+++ b/RSSDP/SsdpDevicePublisher.cs
@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
-using System.Linq;
using System.Text;
using MediaBrowser.Model.Net;
using MediaBrowser.Model.Threading;
diff --git a/RSSDP/SsdpEmbeddedDevice.cs b/RSSDP/SsdpEmbeddedDevice.cs
index c03106b2d..28948f950 100644
--- a/RSSDP/SsdpEmbeddedDevice.cs
+++ b/RSSDP/SsdpEmbeddedDevice.cs
@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
-using System.Linq;
using System.Text;
namespace Rssdp
diff --git a/RSSDP/SsdpRootDevice.cs b/RSSDP/SsdpRootDevice.cs
index faf851bcb..5b7d0f454 100644
--- a/RSSDP/SsdpRootDevice.cs
+++ b/RSSDP/SsdpRootDevice.cs
@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
-using System.Linq;
using System.Text;
using System.Xml;
using Rssdp.Infrastructure;
diff --git a/RSSDP/UPnP10DeviceValidator.cs b/RSSDP/UPnP10DeviceValidator.cs
index f802b7639..2a8a9ccd2 100644
--- a/RSSDP/UPnP10DeviceValidator.cs
+++ b/RSSDP/UPnP10DeviceValidator.cs
@@ -26,11 +26,11 @@ namespace Rssdp.Infrastructure
/// <param name="device">The <see cref="SsdpRootDevice"/> to validate.</param>
/// <exception cref="System.ArgumentNullException">Thrown if the <paramref name="device"/> argument is null.</exception>
/// <returns>A non-null enumerable set of strings, empty if there are no validation errors, otherwise each string represents a discrete problem.</returns>
- public IEnumerable<string> GetValidationErrors(SsdpRootDevice device)
+ public List<string> GetValidationErrors(SsdpRootDevice device)
{
if (device == null) throw new ArgumentNullException("device");
- var retVal = GetValidationErrors((SsdpDevice)device) as IList<string>;
+ var retVal = GetValidationErrors((SsdpDevice)device);
if (device.Location == null)
retVal.Add("Location cannot be null.");
@@ -49,7 +49,7 @@ namespace Rssdp.Infrastructure
/// <param name="device">The <see cref="SsdpDevice"/> to validate.</param>
/// <exception cref="System.ArgumentNullException">Thrown if the <paramref name="device"/> argument is null.</exception>
/// <returns>A non-null enumerable set of strings, empty if there are no validation errors, otherwise each string represents a discrete problem.</returns>
- public IEnumerable<string> GetValidationErrors(SsdpDevice device)
+ public List<string> GetValidationErrors(SsdpDevice device)
{
if (device == null) throw new ArgumentNullException("device");
@@ -110,7 +110,7 @@ namespace Rssdp.Infrastructure
if (String.IsNullOrEmpty(device.ModelName))
retVal.Add("ModelName is required.");
- if (device.Icons.Any())
+ if (device.Icons.Count > 0)
ValidateIcons(device, retVal);
ValidateChildDevices(device, retVal);
@@ -127,7 +127,7 @@ namespace Rssdp.Infrastructure
public void ThrowIfDeviceInvalid(SsdpDevice device)
{
var errors = this.GetValidationErrors(device);
- if (errors != null && errors.Any()) throw new InvalidOperationException("Invalid device settings : " + String.Join(Environment.NewLine, errors));
+ if (errors != null && errors.Count > 0) throw new InvalidOperationException("Invalid device settings : " + String.Join(Environment.NewLine, errors));
}
#endregion
diff --git a/SharedVersion.cs b/SharedVersion.cs
index e799ddfeb..85588a9af 100644
--- a/SharedVersion.cs
+++ b/SharedVersion.cs
@@ -1,3 +1,3 @@
using System.Reflection;
-[assembly: AssemblyVersion("3.2.26.5")]
+[assembly: AssemblyVersion("3.2.30.8")]
diff --git a/SocketHttpListener/Net/BoundaryType.cs b/SocketHttpListener/Net/BoundaryType.cs
index c3ac00c0f..f1e799f63 100644
--- a/SocketHttpListener/Net/BoundaryType.cs
+++ b/SocketHttpListener/Net/BoundaryType.cs
@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
-using System.Linq;
using System.Text;
using System.Threading.Tasks;
diff --git a/SocketHttpListener/Net/CookieHelper.cs b/SocketHttpListener/Net/CookieHelper.cs
index 470507d6b..a32131956 100644
--- a/SocketHttpListener/Net/CookieHelper.cs
+++ b/SocketHttpListener/Net/CookieHelper.cs
@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.Globalization;
-using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
diff --git a/SocketHttpListener/Net/EndPointListener.cs b/SocketHttpListener/Net/EndPointListener.cs
index 2106bbec5..2b1479e42 100644
--- a/SocketHttpListener/Net/EndPointListener.cs
+++ b/SocketHttpListener/Net/EndPointListener.cs
@@ -3,6 +3,8 @@ using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Net;
+using System.Net.Sockets;
+using System.Security.Cryptography.X509Certificates;
using System.Threading;
using MediaBrowser.Model.Cryptography;
using MediaBrowser.Model.IO;
@@ -11,37 +13,37 @@ using MediaBrowser.Model.Net;
using MediaBrowser.Model.System;
using MediaBrowser.Model.Text;
using SocketHttpListener.Primitives;
+using ProtocolType = MediaBrowser.Model.Net.ProtocolType;
+using SocketType = MediaBrowser.Model.Net.SocketType;
namespace SocketHttpListener.Net
{
sealed class EndPointListener
{
HttpListener listener;
- IpEndPointInfo endpoint;
- IAcceptSocket sock;
- Dictionary<ListenerPrefix,HttpListener> prefixes; // Dictionary <ListenerPrefix, HttpListener>
+ IPEndPoint endpoint;
+ Socket sock;
+ Dictionary<ListenerPrefix, HttpListener> prefixes; // Dictionary <ListenerPrefix, HttpListener>
List<ListenerPrefix> unhandled; // List<ListenerPrefix> unhandled; host = '*'
List<ListenerPrefix> all; // List<ListenerPrefix> all; host = '+'
- ICertificate cert;
+ X509Certificate cert;
bool secure;
Dictionary<HttpConnection, HttpConnection> unregistered;
private readonly ILogger _logger;
private bool _closed;
private bool _enableDualMode;
private readonly ICryptoProvider _cryptoProvider;
- private readonly IStreamFactory _streamFactory;
private readonly ISocketFactory _socketFactory;
private readonly ITextEncoding _textEncoding;
private readonly IMemoryStreamFactory _memoryStreamFactory;
private readonly IFileSystem _fileSystem;
private readonly IEnvironmentInfo _environment;
- public EndPointListener(HttpListener listener, IpAddressInfo addr, int port, bool secure, ICertificate cert, ILogger logger, ICryptoProvider cryptoProvider, IStreamFactory streamFactory, ISocketFactory socketFactory, IMemoryStreamFactory memoryStreamFactory, ITextEncoding textEncoding, IFileSystem fileSystem, IEnvironmentInfo environment)
+ public EndPointListener(HttpListener listener, IPAddress addr, int port, bool secure, X509Certificate cert, ILogger logger, ICryptoProvider cryptoProvider, ISocketFactory socketFactory, IMemoryStreamFactory memoryStreamFactory, ITextEncoding textEncoding, IFileSystem fileSystem, IEnvironmentInfo environment)
{
this.listener = listener;
_logger = logger;
_cryptoProvider = cryptoProvider;
- _streamFactory = streamFactory;
_socketFactory = socketFactory;
_memoryStreamFactory = memoryStreamFactory;
_textEncoding = textEncoding;
@@ -51,8 +53,8 @@ namespace SocketHttpListener.Net
this.secure = secure;
this.cert = cert;
- _enableDualMode = addr.Equals(IpAddressInfo.IPv6Any);
- endpoint = new IpEndPointInfo(addr, port);
+ _enableDualMode = addr.Equals(IPAddress.IPv6Any);
+ endpoint = new IPEndPoint(addr, port);
prefixes = new Dictionary<ListenerPrefix, HttpListener>();
unregistered = new Dictionary<HttpConnection, HttpConnection>();
@@ -72,18 +74,18 @@ namespace SocketHttpListener.Net
{
try
{
- sock = _socketFactory.CreateSocket(endpoint.IpAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp, _enableDualMode);
+ sock = CreateSocket(endpoint.Address.AddressFamily, _enableDualMode);
}
catch (SocketCreateException ex)
{
- if (_enableDualMode && endpoint.IpAddress.Equals(IpAddressInfo.IPv6Any) &&
- (string.Equals(ex.ErrorCode, "AddressFamilyNotSupported", StringComparison.OrdinalIgnoreCase) ||
+ if (_enableDualMode && endpoint.Address.Equals(IPAddress.IPv6Any) &&
+ (string.Equals(ex.ErrorCode, "AddressFamilyNotSupported", StringComparison.OrdinalIgnoreCase) ||
// mono on bsd is throwing this
string.Equals(ex.ErrorCode, "ProtocolNotSupported", StringComparison.OrdinalIgnoreCase)))
{
- endpoint = new IpEndPointInfo(IpAddressInfo.Any, endpoint.Port);
+ endpoint = new IPEndPoint(IPAddress.Any, endpoint.Port);
_enableDualMode = false;
- sock = _socketFactory.CreateSocket(endpoint.IpAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp, _enableDualMode);
+ sock = CreateSocket(endpoint.Address.AddressFamily, _enableDualMode);
}
else
{
@@ -96,11 +98,42 @@ namespace SocketHttpListener.Net
// This is the number TcpListener uses.
sock.Listen(2147483647);
- sock.StartAccept(ProcessAccept, () => _closed);
+ new SocketAcceptor(_logger, sock, ProcessAccept, () => _closed).StartAccept();
_closed = false;
}
- private async void ProcessAccept(IAcceptSocket accepted)
+ private Socket CreateSocket(AddressFamily addressFamily, bool dualMode)
+ {
+ try
+ {
+ var socket = new Socket(addressFamily, System.Net.Sockets.SocketType.Stream, System.Net.Sockets.ProtocolType.Tcp);
+
+ if (dualMode)
+ {
+ socket.DualMode = true;
+ }
+
+ return socket;
+ }
+ catch (SocketException ex)
+ {
+ throw new SocketCreateException(ex.SocketErrorCode.ToString(), ex);
+ }
+ catch (ArgumentException ex)
+ {
+ if (dualMode)
+ {
+ // Mono for BSD incorrectly throws ArgumentException instead of SocketException
+ throw new SocketCreateException("AddressFamilyNotSupported", ex);
+ }
+ else
+ {
+ throw;
+ }
+ }
+ }
+
+ private async void ProcessAccept(Socket accepted)
{
try
{
@@ -112,7 +145,7 @@ namespace SocketHttpListener.Net
return;
}
- HttpConnection conn = await HttpConnection.Create(_logger, accepted, listener, listener.secure, listener.cert, _cryptoProvider, _streamFactory, _memoryStreamFactory, _textEncoding, _fileSystem, _environment).ConfigureAwait(false);
+ HttpConnection conn = await HttpConnection.Create(_logger, accepted, listener, listener.secure, listener.cert, _cryptoProvider, _memoryStreamFactory, _textEncoding, _fileSystem, _environment).ConfigureAwait(false);
//_logger.Debug("Adding unregistered connection to {0}. Id: {1}", accepted.RemoteEndPoint, connectionId);
lock (listener.unregistered)
diff --git a/SocketHttpListener/Net/EndPointManager.cs b/SocketHttpListener/Net/EndPointManager.cs
index 6a00ed360..557caa59a 100644
--- a/SocketHttpListener/Net/EndPointManager.cs
+++ b/SocketHttpListener/Net/EndPointManager.cs
@@ -1,7 +1,6 @@
using System;
using System.Collections;
using System.Collections.Generic;
-using System.Linq;
using System.Net;
using System.Reflection;
using System.Threading.Tasks;
@@ -67,23 +66,25 @@ namespace SocketHttpListener.Net
epl.AddPrefix(lp, listener);
}
- private static IpAddressInfo GetIpAnyAddress(HttpListener listener)
+ private static IPAddress GetIpAnyAddress(HttpListener listener)
{
- return listener.EnableDualMode ? IpAddressInfo.IPv6Any : IpAddressInfo.Any;
+ return listener.EnableDualMode ? IPAddress.IPv6Any : IPAddress.Any;
}
static async Task<EndPointListener> GetEPListener(ILogger logger, string host, int port, HttpListener listener, bool secure)
{
var networkManager = listener.NetworkManager;
- IpAddressInfo addr;
+ IPAddress addr;
if (host == "*" || host == "+")
addr = GetIpAnyAddress(listener);
- else if (networkManager.TryParseIpAddress(host, out addr) == false)
+ else if (IPAddress.TryParse(host, out addr) == false)
{
try
{
- addr = (await networkManager.GetHostAddressesAsync(host).ConfigureAwait(false)).FirstOrDefault() ??
+ var all = (await networkManager.GetHostAddressesAsync(host).ConfigureAwait(false));
+
+ addr = (all.Length == 0 ? null : IPAddress.Parse(all[0].Address)) ??
GetIpAnyAddress(listener);
}
catch
@@ -93,10 +94,10 @@ namespace SocketHttpListener.Net
}
Dictionary<int, EndPointListener> p = null; // Dictionary<int, EndPointListener>
- if (!ip_to_endpoints.TryGetValue(addr.Address, out p))
+ if (!ip_to_endpoints.TryGetValue(addr.ToString(), out p))
{
p = new Dictionary<int, EndPointListener>();
- ip_to_endpoints[addr.Address] = p;
+ ip_to_endpoints[addr.ToString()] = p;
}
EndPointListener epl = null;
@@ -106,25 +107,25 @@ namespace SocketHttpListener.Net
}
else
{
- epl = new EndPointListener(listener, addr, port, secure, listener.Certificate, logger, listener.CryptoProvider, listener.StreamFactory, listener.SocketFactory, listener.MemoryStreamFactory, listener.TextEncoding, listener.FileSystem, listener.EnvironmentInfo);
+ epl = new EndPointListener(listener, addr, port, secure, listener.Certificate, logger, listener.CryptoProvider, listener.SocketFactory, listener.MemoryStreamFactory, listener.TextEncoding, listener.FileSystem, listener.EnvironmentInfo);
p[port] = epl;
}
return epl;
}
- public static void RemoveEndPoint(EndPointListener epl, IpEndPointInfo ep)
+ public static void RemoveEndPoint(EndPointListener epl, IPEndPoint ep)
{
lock (ip_to_endpoints)
{
// Dictionary<int, EndPointListener> p
Dictionary<int, EndPointListener> p;
- if (ip_to_endpoints.TryGetValue(ep.IpAddress.Address, out p))
+ if (ip_to_endpoints.TryGetValue(ep.Address.ToString(), out p))
{
p.Remove(ep.Port);
if (p.Count == 0)
{
- ip_to_endpoints.Remove(ep.IpAddress.Address);
+ ip_to_endpoints.Remove(ep.Address.ToString());
}
}
epl.Close();
diff --git a/SocketHttpListener/Net/EntitySendFormat.cs b/SocketHttpListener/Net/EntitySendFormat.cs
index 6e585bdc9..9caee3e11 100644
--- a/SocketHttpListener/Net/EntitySendFormat.cs
+++ b/SocketHttpListener/Net/EntitySendFormat.cs
@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
-using System.Linq;
using System.Text;
using System.Threading.Tasks;
diff --git a/SocketHttpListener/Net/HttpConnection.cs b/SocketHttpListener/Net/HttpConnection.cs
index e66443c59..4e8158964 100644
--- a/SocketHttpListener/Net/HttpConnection.cs
+++ b/SocketHttpListener/Net/HttpConnection.cs
@@ -1,5 +1,9 @@
using System;
using System.IO;
+using System.Net;
+using System.Net.Security;
+using System.Net.Sockets;
+using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading.Tasks;
using MediaBrowser.Model.Cryptography;
@@ -16,7 +20,7 @@ namespace SocketHttpListener.Net
{
private static AsyncCallback s_onreadCallback = new AsyncCallback(OnRead);
const int BufferSize = 8192;
- IAcceptSocket _socket;
+ Socket _socket;
Stream _stream;
EndPointListener _epl;
MemoryStream _memoryStream;
@@ -31,21 +35,20 @@ namespace SocketHttpListener.Net
bool _contextBound;
bool secure;
int _timeout = 300000; // 90k ms for first request, 15k ms from then on
- IpEndPointInfo local_ep;
+ IPEndPoint local_ep;
HttpListener _lastListener;
int[] client_cert_errors;
- ICertificate cert;
- Stream ssl_stream;
+ X509Certificate cert;
+ SslStream ssl_stream;
private readonly ILogger _logger;
private readonly ICryptoProvider _cryptoProvider;
private readonly IMemoryStreamFactory _memoryStreamFactory;
private readonly ITextEncoding _textEncoding;
- private readonly IStreamFactory _streamFactory;
private readonly IFileSystem _fileSystem;
private readonly IEnvironmentInfo _environment;
- private HttpConnection(ILogger logger, IAcceptSocket socket, EndPointListener epl, bool secure, ICertificate cert, ICryptoProvider cryptoProvider, IStreamFactory streamFactory, IMemoryStreamFactory memoryStreamFactory, ITextEncoding textEncoding, IFileSystem fileSystem, IEnvironmentInfo environment)
+ private HttpConnection(ILogger logger, Socket socket, EndPointListener epl, bool secure, X509Certificate cert, ICryptoProvider cryptoProvider, IMemoryStreamFactory memoryStreamFactory, ITextEncoding textEncoding, IFileSystem fileSystem, IEnvironmentInfo environment)
{
_logger = logger;
this._socket = socket;
@@ -57,14 +60,13 @@ namespace SocketHttpListener.Net
_textEncoding = textEncoding;
_fileSystem = fileSystem;
_environment = environment;
- _streamFactory = streamFactory;
}
private async Task InitStream()
{
if (secure == false)
{
- _stream = _streamFactory.CreateNetworkStream(_socket, false);
+ _stream = new SocketStream(_socket, false);
}
else
{
@@ -81,16 +83,16 @@ namespace SocketHttpListener.Net
//});
//_stream = ssl_stream.AuthenticatedStream;
- ssl_stream = _streamFactory.CreateSslStream(_streamFactory.CreateNetworkStream(_socket, false), false);
- await _streamFactory.AuthenticateSslStreamAsServer(ssl_stream, cert).ConfigureAwait(false);
+ ssl_stream = new SslStream(new SocketStream(_socket, false), false);
+ await ssl_stream.AuthenticateAsServerAsync(cert).ConfigureAwait(false);
_stream = ssl_stream;
}
Init();
}
- public static async Task<HttpConnection> Create(ILogger logger, IAcceptSocket sock, EndPointListener epl, bool secure, ICertificate cert, ICryptoProvider cryptoProvider, IStreamFactory streamFactory, IMemoryStreamFactory memoryStreamFactory, ITextEncoding textEncoding, IFileSystem fileSystem, IEnvironmentInfo environment)
+ public static async Task<HttpConnection> Create(ILogger logger, Socket sock, EndPointListener epl, bool secure, X509Certificate cert, ICryptoProvider cryptoProvider, IMemoryStreamFactory memoryStreamFactory, ITextEncoding textEncoding, IFileSystem fileSystem, IEnvironmentInfo environment)
{
- var connection = new HttpConnection(logger, sock, epl, secure, cert, cryptoProvider, streamFactory, memoryStreamFactory, textEncoding, fileSystem, environment);
+ var connection = new HttpConnection(logger, sock, epl, secure, cert, cryptoProvider, memoryStreamFactory, textEncoding, fileSystem, environment);
await connection.InitStream().ConfigureAwait(false);
@@ -134,21 +136,21 @@ namespace SocketHttpListener.Net
get { return _reuses; }
}
- public IpEndPointInfo LocalEndPoint
+ public IPEndPoint LocalEndPoint
{
get
{
if (local_ep != null)
return local_ep;
- local_ep = (IpEndPointInfo)_socket.LocalEndPoint;
+ local_ep = (IPEndPoint)_socket.LocalEndPoint;
return local_ep;
}
}
- public IpEndPointInfo RemoteEndPoint
+ public IPEndPoint RemoteEndPoint
{
- get { return (IpEndPointInfo)_socket.RemoteEndPoint; }
+ get { return _socket.RemoteEndPoint as IPEndPoint; }
}
public bool IsSecure
@@ -513,12 +515,12 @@ namespace SocketHttpListener.Net
return;
}
- IAcceptSocket s = _socket;
+ Socket s = _socket;
_socket = null;
try
{
if (s != null)
- s.Shutdown(true);
+ s.Shutdown(SocketShutdown.Both);
}
catch
{
diff --git a/SocketHttpListener/Net/HttpListener.cs b/SocketHttpListener/Net/HttpListener.cs
index b3e01425c..32c5e90e0 100644
--- a/SocketHttpListener/Net/HttpListener.cs
+++ b/SocketHttpListener/Net/HttpListener.cs
@@ -3,6 +3,7 @@ using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Net;
+using System.Security.Cryptography.X509Certificates;
using MediaBrowser.Common.Net;
using MediaBrowser.Model.Cryptography;
using MediaBrowser.Model.IO;
@@ -17,7 +18,6 @@ namespace SocketHttpListener.Net
public sealed class HttpListener : IDisposable
{
internal ICryptoProvider CryptoProvider { get; private set; }
- internal IStreamFactory StreamFactory { get; private set; }
internal ISocketFactory SocketFactory { get; private set; }
internal IFileSystem FileSystem { get; private set; }
internal ITextEncoding TextEncoding { get; private set; }
@@ -38,15 +38,14 @@ namespace SocketHttpListener.Net
Dictionary<HttpListenerContext, HttpListenerContext> registry; // Dictionary<HttpListenerContext,HttpListenerContext>
Dictionary<HttpConnection, HttpConnection> connections;
private ILogger _logger;
- private ICertificate _certificate;
+ private X509Certificate _certificate;
public Action<HttpListenerContext> OnContext { get; set; }
- public HttpListener(ILogger logger, ICryptoProvider cryptoProvider, IStreamFactory streamFactory, ISocketFactory socketFactory, INetworkManager networkManager, ITextEncoding textEncoding, IMemoryStreamFactory memoryStreamFactory, IFileSystem fileSystem, IEnvironmentInfo environmentInfo)
+ public HttpListener(ILogger logger, ICryptoProvider cryptoProvider, ISocketFactory socketFactory, INetworkManager networkManager, ITextEncoding textEncoding, IMemoryStreamFactory memoryStreamFactory, IFileSystem fileSystem, IEnvironmentInfo environmentInfo)
{
_logger = logger;
CryptoProvider = cryptoProvider;
- StreamFactory = streamFactory;
SocketFactory = socketFactory;
NetworkManager = networkManager;
TextEncoding = textEncoding;
@@ -59,18 +58,18 @@ namespace SocketHttpListener.Net
auth_schemes = AuthenticationSchemes.Anonymous;
}
- public HttpListener(ICertificate certificate, ICryptoProvider cryptoProvider, IStreamFactory streamFactory, ISocketFactory socketFactory, INetworkManager networkManager, ITextEncoding textEncoding, IMemoryStreamFactory memoryStreamFactory, IFileSystem fileSystem, IEnvironmentInfo environmentInfo)
- :this(new NullLogger(), certificate, cryptoProvider, streamFactory, socketFactory, networkManager, textEncoding, memoryStreamFactory, fileSystem, environmentInfo)
+ public HttpListener(X509Certificate certificate, ICryptoProvider cryptoProvider, ISocketFactory socketFactory, INetworkManager networkManager, ITextEncoding textEncoding, IMemoryStreamFactory memoryStreamFactory, IFileSystem fileSystem, IEnvironmentInfo environmentInfo)
+ :this(new NullLogger(), certificate, cryptoProvider, socketFactory, networkManager, textEncoding, memoryStreamFactory, fileSystem, environmentInfo)
{
}
- public HttpListener(ILogger logger, ICertificate certificate, ICryptoProvider cryptoProvider, IStreamFactory streamFactory, ISocketFactory socketFactory, INetworkManager networkManager, ITextEncoding textEncoding, IMemoryStreamFactory memoryStreamFactory, IFileSystem fileSystem, IEnvironmentInfo environmentInfo)
- : this(logger, cryptoProvider, streamFactory, socketFactory, networkManager, textEncoding, memoryStreamFactory, fileSystem, environmentInfo)
+ public HttpListener(ILogger logger, X509Certificate certificate, ICryptoProvider cryptoProvider, ISocketFactory socketFactory, INetworkManager networkManager, ITextEncoding textEncoding, IMemoryStreamFactory memoryStreamFactory, IFileSystem fileSystem, IEnvironmentInfo environmentInfo)
+ : this(logger, cryptoProvider, socketFactory, networkManager, textEncoding, memoryStreamFactory, fileSystem, environmentInfo)
{
_certificate = certificate;
}
- public void LoadCert(ICertificate cert)
+ public void LoadCert(X509Certificate cert)
{
_certificate = cert;
}
@@ -150,7 +149,7 @@ namespace SocketHttpListener.Net
// }
//}
- internal ICertificate Certificate
+ internal X509Certificate Certificate
{
get { return _certificate; }
}
@@ -249,6 +248,7 @@ namespace SocketHttpListener.Net
Close(true); //TODO: Should we force here or not?
disposed = true;
+ GC.SuppressFinalize(this);
}
internal void CheckDisposed()
diff --git a/SocketHttpListener/Net/HttpListenerRequest.cs b/SocketHttpListener/Net/HttpListenerRequest.cs
index f9df52593..5e391424f 100644
--- a/SocketHttpListener/Net/HttpListenerRequest.cs
+++ b/SocketHttpListener/Net/HttpListenerRequest.cs
@@ -3,6 +3,7 @@ using System.Collections.Specialized;
using System.Globalization;
using System.IO;
using System.Net;
+using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading.Tasks;
using MediaBrowser.Model.Net;
@@ -513,7 +514,14 @@ namespace SocketHttpListener.Net
public bool IsLocal
{
- get { return RemoteEndPoint.IpAddress.Equals(IpAddressInfo.Loopback) || RemoteEndPoint.IpAddress.Equals(IpAddressInfo.IPv6Loopback) || LocalEndPoint.IpAddress.Equals(RemoteEndPoint.IpAddress); }
+ get
+ {
+ var remoteEndPoint = RemoteEndPoint;
+
+ return remoteEndPoint.Address.Equals(IPAddress.Loopback) ||
+ remoteEndPoint.Address.Equals(IPAddress.IPv6Loopback) ||
+ LocalEndPoint.Address.Equals(remoteEndPoint.Address);
+ }
}
public bool IsSecureConnection
@@ -557,7 +565,7 @@ namespace SocketHttpListener.Net
}
}
- public IpEndPointInfo LocalEndPoint
+ public IPEndPoint LocalEndPoint
{
get { return context.Connection.LocalEndPoint; }
}
@@ -577,7 +585,7 @@ namespace SocketHttpListener.Net
get { return raw_url; }
}
- public IpEndPointInfo RemoteEndPoint
+ public IPEndPoint RemoteEndPoint
{
get { return context.Connection.RemoteEndPoint; }
}
@@ -651,10 +659,5 @@ namespace SocketHttpListener.Net
return _websocketRequest;
}
}
-
- public Task<ICertificate> GetClientCertificateAsync()
- {
- return Task.FromResult<ICertificate>(null);
- }
}
}
diff --git a/SocketHttpListener/Net/HttpListenerResponse.Managed.cs b/SocketHttpListener/Net/HttpListenerResponse.Managed.cs
index 83fcc09ca..34953b569 100644
--- a/SocketHttpListener/Net/HttpListenerResponse.Managed.cs
+++ b/SocketHttpListener/Net/HttpListenerResponse.Managed.cs
@@ -2,7 +2,6 @@
using System.Collections.Generic;
using System.Globalization;
using System.IO;
-using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
diff --git a/SocketHttpListener/Net/HttpListenerResponse.cs b/SocketHttpListener/Net/HttpListenerResponse.cs
index fc57e8485..1cbd6165e 100644
--- a/SocketHttpListener/Net/HttpListenerResponse.cs
+++ b/SocketHttpListener/Net/HttpListenerResponse.cs
@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.IO;
-using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
diff --git a/SocketHttpListener/Net/HttpRequestStream.Managed.cs b/SocketHttpListener/Net/HttpRequestStream.Managed.cs
index 92f4bbb02..c9c148b15 100644
--- a/SocketHttpListener/Net/HttpRequestStream.Managed.cs
+++ b/SocketHttpListener/Net/HttpRequestStream.Managed.cs
@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.IO;
-using System.Linq;
using System.Runtime.ExceptionServices;
using System.Text;
using System.Threading.Tasks;
diff --git a/SocketHttpListener/Net/HttpRequestStream.cs b/SocketHttpListener/Net/HttpRequestStream.cs
index c54da44a1..f10c04a4f 100644
--- a/SocketHttpListener/Net/HttpRequestStream.cs
+++ b/SocketHttpListener/Net/HttpRequestStream.cs
@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.IO;
-using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
diff --git a/SocketHttpListener/Net/HttpResponseStream.Managed.cs b/SocketHttpListener/Net/HttpResponseStream.Managed.cs
index 116c3280a..7e175f8d6 100644
--- a/SocketHttpListener/Net/HttpResponseStream.Managed.cs
+++ b/SocketHttpListener/Net/HttpResponseStream.Managed.cs
@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.IO;
-using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Runtime.ExceptionServices;
@@ -52,13 +51,13 @@ namespace SocketHttpListener.Net
private bool _trailer_sent;
private Stream _stream;
private readonly IMemoryStreamFactory _memoryStreamFactory;
- private readonly IAcceptSocket _socket;
+ private readonly Socket _socket;
private readonly bool _supportsDirectSocketAccess;
private readonly IEnvironmentInfo _environment;
private readonly IFileSystem _fileSystem;
private readonly ILogger _logger;
- internal HttpResponseStream(Stream stream, HttpListenerResponse response, bool ignore_errors, IMemoryStreamFactory memoryStreamFactory, IAcceptSocket socket, bool supportsDirectSocketAccess, IEnvironmentInfo environment, IFileSystem fileSystem, ILogger logger)
+ internal HttpResponseStream(Stream stream, HttpListenerResponse response, bool ignore_errors, IMemoryStreamFactory memoryStreamFactory, Socket socket, bool supportsDirectSocketAccess, IEnvironmentInfo environment, IFileSystem fileSystem, ILogger logger)
{
_response = response;
_ignore_errors = ignore_errors;
@@ -290,13 +289,14 @@ namespace SocketHttpListener.Net
public Task TransmitFile(string path, long offset, long count, FileShareMode fileShareMode, CancellationToken cancellationToken)
{
- if (_supportsDirectSocketAccess && offset == 0 && count == 0 && !_response.SendChunked && _response.ContentLength64 > 8192)
- {
- if (EnableSendFileWithSocket)
- {
- return TransmitFileOverSocket(path, offset, count, fileShareMode, cancellationToken);
- }
- }
+ //if (_supportsDirectSocketAccess && offset == 0 && count == 0 && !_response.SendChunked && _response.ContentLength64 > 8192)
+ //{
+ // if (EnableSendFileWithSocket)
+ // {
+ // return TransmitFileOverSocket(path, offset, count, fileShareMode, cancellationToken);
+ // }
+ //}
+
return TransmitFileManaged(path, offset, count, fileShareMode, cancellationToken);
}
@@ -336,7 +336,7 @@ namespace SocketHttpListener.Net
}
};
- var result = _socket.BeginSendFile(path, preBuffer, _emptyBuffer, new AsyncCallback(callback), null);
+ var result = _socket.BeginSendFile(path, preBuffer, _emptyBuffer, TransmitFileOptions.UseDefaultWorkerThread, new AsyncCallback(callback), null);
if (result.CompletedSynchronously)
{
diff --git a/SocketHttpListener/Net/HttpResponseStream.cs b/SocketHttpListener/Net/HttpResponseStream.cs
index f7140be66..5b7fa417f 100644
--- a/SocketHttpListener/Net/HttpResponseStream.cs
+++ b/SocketHttpListener/Net/HttpResponseStream.cs
@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.IO;
-using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
diff --git a/SocketHttpListener/Net/HttpStatusDescription.cs b/SocketHttpListener/Net/HttpStatusDescription.cs
index 8d490c511..9cc4a8e8c 100644
--- a/SocketHttpListener/Net/HttpStatusDescription.cs
+++ b/SocketHttpListener/Net/HttpStatusDescription.cs
@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
-using System.Linq;
using System.Text;
using System.Threading.Tasks;
diff --git a/SocketHttpListener/Net/ListenerPrefix.cs b/SocketHttpListener/Net/ListenerPrefix.cs
index 2c314da50..605b7b88c 100644
--- a/SocketHttpListener/Net/ListenerPrefix.cs
+++ b/SocketHttpListener/Net/ListenerPrefix.cs
@@ -11,7 +11,7 @@ namespace SocketHttpListener.Net
ushort port;
string path;
bool secure;
- IpAddressInfo[] addresses;
+ IPAddress[] addresses;
public HttpListener Listener;
public ListenerPrefix(string prefix)
@@ -25,7 +25,7 @@ namespace SocketHttpListener.Net
return original;
}
- public IpAddressInfo[] Addresses
+ public IPAddress[] Addresses
{
get { return addresses; }
set { addresses = value; }
diff --git a/Emby.Common.Implementations/Net/SocketAcceptor.cs b/SocketHttpListener/Net/SocketAcceptor.cs
index 11a8e5381..36332f52b 100644
--- a/Emby.Common.Implementations/Net/SocketAcceptor.cs
+++ b/SocketHttpListener/Net/SocketAcceptor.cs
@@ -1,19 +1,17 @@
using System;
using System.Net.Sockets;
using MediaBrowser.Model.Logging;
-using MediaBrowser.Model.Net;
-namespace Emby.Common.Implementations.Net
+namespace SocketHttpListener.Net
{
public class SocketAcceptor
{
private readonly ILogger _logger;
private readonly Socket _originalSocket;
private readonly Func<bool> _isClosed;
- private readonly Action<IAcceptSocket> _onAccept;
- private readonly bool _isDualMode;
+ private readonly Action<Socket> _onAccept;
- public SocketAcceptor(ILogger logger, Socket originalSocket, Action<IAcceptSocket> onAccept, Func<bool> isClosed, bool isDualMode)
+ public SocketAcceptor(ILogger logger, Socket originalSocket, Action<Socket> onAccept, Func<bool> isClosed)
{
if (logger == null)
{
@@ -35,7 +33,6 @@ namespace Emby.Common.Implementations.Net
_logger = logger;
_originalSocket = originalSocket;
_isClosed = isClosed;
- _isDualMode = isDualMode;
_onAccept = onAccept;
}
@@ -117,7 +114,7 @@ namespace Emby.Common.Implementations.Net
if (acceptSocket != null)
{
//ProcessAccept(acceptSocket);
- _onAccept(new NetAcceptSocket(acceptSocket, _logger, _isDualMode));
+ _onAccept(acceptSocket);
}
// Accept the next connection request
diff --git a/SocketHttpListener/Net/UriScheme.cs b/SocketHttpListener/Net/UriScheme.cs
index eb13619c9..35b01e0e5 100644
--- a/SocketHttpListener/Net/UriScheme.cs
+++ b/SocketHttpListener/Net/UriScheme.cs
@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
-using System.Linq;
using System.Text;
using System.Threading.Tasks;
diff --git a/SocketHttpListener/Net/WebHeaderCollection.cs b/SocketHttpListener/Net/WebHeaderCollection.cs
index d20f99b9b..d82dc6816 100644
--- a/SocketHttpListener/Net/WebHeaderCollection.cs
+++ b/SocketHttpListener/Net/WebHeaderCollection.cs
@@ -7,6 +7,7 @@ using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Text;
using MediaBrowser.Model.Services;
+using MediaBrowser.Model.Extensions;
namespace SocketHttpListener.Net
{
@@ -130,13 +131,13 @@ namespace SocketHttpListener.Net
base.Add(headerName, headerValue);
}
- internal string[] GetValues_internal(string header, bool split)
+ internal List<string> GetValues_internal(string header, bool split)
{
if (header == null)
throw new ArgumentNullException("header");
- string[] values = base.GetValues(header);
- if (values == null || values.Length == 0)
+ var values = base.GetValues(header);
+ if (values == null || values.Count == 0)
return null;
if (split && IsMultiValue(header))
@@ -154,7 +155,7 @@ namespace SocketHttpListener.Net
if (separated == null)
{
- separated = new List<string>(values.Length + 1);
+ separated = new List<string>(values.Count + 1);
foreach (var v in values)
{
if (v == value)
@@ -176,13 +177,13 @@ namespace SocketHttpListener.Net
}
if (separated != null)
- return separated.ToArray();
+ return separated;
}
return values;
}
- public override string[] GetValues(string header)
+ public override List<string> GetValues(string header)
{
return GetValues_internal(header, true);
}
diff --git a/SocketHttpListener/Net/WebHeaderEncoding.cs b/SocketHttpListener/Net/WebHeaderEncoding.cs
index 64330c1b4..4a080179e 100644
--- a/SocketHttpListener/Net/WebHeaderEncoding.cs
+++ b/SocketHttpListener/Net/WebHeaderEncoding.cs
@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
-using System.Linq;
using System.Text;
using System.Threading.Tasks;
diff --git a/SocketHttpListener/Net/WebSockets/HttpListenerWebSocketContext.cs b/SocketHttpListener/Net/WebSockets/HttpListenerWebSocketContext.cs
index 034ac17d2..803c67b83 100644
--- a/SocketHttpListener/Net/WebSockets/HttpListenerWebSocketContext.cs
+++ b/SocketHttpListener/Net/WebSockets/HttpListenerWebSocketContext.cs
@@ -254,7 +254,7 @@ namespace SocketHttpListener.Net.WebSockets
/// </summary>
/// <value>
/// </value>
- public override IpEndPointInfo ServerEndPoint
+ public override IPEndPoint ServerEndPoint
{
get
{
@@ -281,7 +281,7 @@ namespace SocketHttpListener.Net.WebSockets
/// </summary>
/// <value>
/// </value>
- public override IpEndPointInfo UserEndPoint
+ public override IPEndPoint UserEndPoint
{
get
{
diff --git a/SocketHttpListener/Net/WebSockets/WebSocketContext.cs b/SocketHttpListener/Net/WebSockets/WebSocketContext.cs
index 3ffa6e639..9665ab789 100644
--- a/SocketHttpListener/Net/WebSockets/WebSocketContext.cs
+++ b/SocketHttpListener/Net/WebSockets/WebSocketContext.cs
@@ -151,7 +151,7 @@ namespace SocketHttpListener.Net.WebSockets
/// <value>
/// A <see cref="System.Net.IPEndPoint"/> that represents the server endpoint.
/// </value>
- public abstract IpEndPointInfo ServerEndPoint { get; }
+ public abstract IPEndPoint ServerEndPoint { get; }
/// <summary>
/// Gets the client information (identity, authentication, and security roles).
@@ -167,7 +167,7 @@ namespace SocketHttpListener.Net.WebSockets
/// <value>
/// A <see cref="System.Net.IPEndPoint"/> that represents the client endpoint.
/// </value>
- public abstract IpEndPointInfo UserEndPoint { get; }
+ public abstract IPEndPoint UserEndPoint { get; }
/// <summary>
/// Gets the <see cref="SocketHttpListener.WebSocket"/> instance used for two-way communication
diff --git a/SocketHttpListener/Primitives/ICertificate.cs b/SocketHttpListener/Primitives/ICertificate.cs
deleted file mode 100644
index 1289da13d..000000000
--- a/SocketHttpListener/Primitives/ICertificate.cs
+++ /dev/null
@@ -1,12 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace SocketHttpListener.Primitives
-{
- public interface ICertificate
- {
- }
-}
diff --git a/SocketHttpListener/Primitives/IStreamFactory.cs b/SocketHttpListener/Primitives/IStreamFactory.cs
deleted file mode 100644
index 57e21e31b..000000000
--- a/SocketHttpListener/Primitives/IStreamFactory.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using MediaBrowser.Model.Net;
-
-namespace SocketHttpListener.Primitives
-{
- public interface IStreamFactory
- {
- Stream CreateNetworkStream(IAcceptSocket acceptSocket, bool ownsSocket);
- Stream CreateSslStream(Stream innerStream, bool leaveInnerStreamOpen);
-
- Task AuthenticateSslStreamAsServer(Stream stream, ICertificate certificate);
- }
-}
diff --git a/SocketHttpListener/Primitives/ITextEncoding.cs b/SocketHttpListener/Primitives/ITextEncoding.cs
index b10145687..2c25a308c 100644
--- a/SocketHttpListener/Primitives/ITextEncoding.cs
+++ b/SocketHttpListener/Primitives/ITextEncoding.cs
@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
-using System.Linq;
using System.Text;
using System.Threading.Tasks;
using MediaBrowser.Model.Text;
diff --git a/SocketHttpListener/SocketHttpListener.csproj b/SocketHttpListener/SocketHttpListener.csproj
index 1aa788931..6ed42ea88 100644
--- a/SocketHttpListener/SocketHttpListener.csproj
+++ b/SocketHttpListener/SocketHttpListener.csproj
@@ -82,6 +82,7 @@
<Compile Include="Net\HttpStreamAsyncResult.cs" />
<Compile Include="Net\HttpVersion.cs" />
<Compile Include="Net\ListenerPrefix.cs" />
+ <Compile Include="Net\SocketAcceptor.cs" />
<Compile Include="Net\UriScheme.cs" />
<Compile Include="Net\WebHeaderCollection.cs" />
<Compile Include="Net\WebHeaderEncoding.cs" />
@@ -89,11 +90,10 @@
<Compile Include="Net\WebSockets\WebSocketContext.cs" />
<Compile Include="Opcode.cs" />
<Compile Include="PayloadData.cs" />
- <Compile Include="Primitives\ICertificate.cs" />
- <Compile Include="Primitives\IStreamFactory.cs" />
<Compile Include="Primitives\ITextEncoding.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Rsv.cs" />
+ <Compile Include="SocketStream.cs" />
<Compile Include="WebSocket.cs" />
<Compile Include="WebSocketException.cs" />
<Compile Include="WebSocketFrame.cs" />
diff --git a/SocketHttpListener/SocketStream.cs b/SocketHttpListener/SocketStream.cs
new file mode 100644
index 000000000..a4f31eab9
--- /dev/null
+++ b/SocketHttpListener/SocketStream.cs
@@ -0,0 +1,86 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Net.Sockets;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace SocketHttpListener
+{
+ public class SocketStream : Stream
+ {
+ private readonly Socket _socket;
+
+ public SocketStream(Socket socket, bool ownsSocket)
+ {
+ _socket = socket;
+ }
+
+ public override void Flush()
+ {
+ }
+
+ public override bool CanRead
+ {
+ get { return true; }
+ }
+ public override bool CanSeek
+ {
+ get { return false; }
+ }
+ public override bool CanWrite
+ {
+ get { return true; }
+ }
+ public override long Length
+ {
+ get { throw new NotImplementedException(); }
+ }
+ public override long Position
+ {
+ get { throw new NotImplementedException(); }
+ set { throw new NotImplementedException(); }
+ }
+
+ public override void Write(byte[] buffer, int offset, int count)
+ {
+ _socket.Send(buffer, offset, count, SocketFlags.None);
+ }
+
+ public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
+ {
+ return _socket.BeginSend(buffer, offset, count, SocketFlags.None, callback, state);
+ }
+
+ public override void EndWrite(IAsyncResult asyncResult)
+ {
+ _socket.EndSend(asyncResult);
+ }
+
+ public override void SetLength(long value)
+ {
+ throw new NotImplementedException();
+ }
+
+ public override long Seek(long offset, SeekOrigin origin)
+ {
+ throw new NotImplementedException();
+ }
+
+ public override int Read(byte[] buffer, int offset, int count)
+ {
+ return _socket.Receive(buffer, offset, count, SocketFlags.None);
+ }
+
+ public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
+ {
+ return _socket.BeginReceive(buffer, offset, count, SocketFlags.None, callback, state);
+ }
+
+ public override int EndRead(IAsyncResult asyncResult)
+ {
+ return _socket.EndReceive(asyncResult);
+ }
+ }
+}
diff --git a/SocketHttpListener/WebSocket.cs b/SocketHttpListener/WebSocket.cs
index 9966d3fcf..57c075e32 100644
--- a/SocketHttpListener/WebSocket.cs
+++ b/SocketHttpListener/WebSocket.cs
@@ -880,6 +880,7 @@ namespace SocketHttpListener
void IDisposable.Dispose()
{
Close(CloseStatusCode.Away, null);
+ GC.SuppressFinalize(this);
}
#endregion