aboutsummaryrefslogtreecommitdiff
path: root/Emby.Dlna
diff options
context:
space:
mode:
authorferferga <ferferga.fer@gmail.com>2020-10-19 17:28:07 +0200
committerferferga <ferferga.fer@gmail.com>2020-10-19 17:28:07 +0200
commit9fd01fade6ac971ba72a2e7dd54e2295f23839bc (patch)
tree20a5ff4a1621e765fc93c0e53b149edb61ff3654 /Emby.Dlna
parentba03ed65fe64b724b3e8b5b94b9cbe1075c61da2 (diff)
parent49ac4c4044b1777dc3a25544aead7b0b15b953e8 (diff)
Remove "download images in advance" option
Diffstat (limited to 'Emby.Dlna')
-rw-r--r--Emby.Dlna/Api/DlnaServerService.cs383
-rw-r--r--Emby.Dlna/Api/DlnaService.cs88
-rw-r--r--Emby.Dlna/Common/ServiceAction.cs2
-rw-r--r--Emby.Dlna/Common/StateVariable.cs3
-rw-r--r--Emby.Dlna/ConfigurationExtension.cs16
-rw-r--r--Emby.Dlna/ConnectionManager/ConnectionManagerService.cs (renamed from Emby.Dlna/ConnectionManager/ConnectionManager.cs)16
-rw-r--r--Emby.Dlna/ConnectionManager/ConnectionManagerXmlBuilder.cs4
-rw-r--r--Emby.Dlna/ContentDirectory/ContentDirectoryService.cs (renamed from Emby.Dlna/ContentDirectory/ContentDirectory.cs)24
-rw-r--r--Emby.Dlna/ContentDirectory/ContentDirectoryXmlBuilder.cs5
-rw-r--r--Emby.Dlna/ContentDirectory/ControlHandler.cs191
-rw-r--r--Emby.Dlna/ContentDirectory/ServerItem.cs23
-rw-r--r--Emby.Dlna/ContentDirectory/StubType.cs28
-rw-r--r--Emby.Dlna/ControlRequest.cs12
-rw-r--r--Emby.Dlna/ControlResponse.cs8
-rw-r--r--Emby.Dlna/Didl/DidlBuilder.cs194
-rw-r--r--Emby.Dlna/Didl/Filter.cs5
-rw-r--r--Emby.Dlna/Didl/StringWriterWithEncoding.cs2
-rw-r--r--Emby.Dlna/DlnaConfigurationFactory.cs24
-rw-r--r--Emby.Dlna/DlnaManager.cs113
-rw-r--r--Emby.Dlna/Emby.Dlna.csproj3
-rw-r--r--Emby.Dlna/EventSubscriptionResponse.cs2
-rw-r--r--Emby.Dlna/Eventing/DlnaEventManager.cs (renamed from Emby.Dlna/Eventing/EventManager.cs)82
-rw-r--r--Emby.Dlna/Eventing/EventSubscription.cs3
-rw-r--r--Emby.Dlna/IConnectionManager.cs2
-rw-r--r--Emby.Dlna/IContentDirectory.cs2
-rw-r--r--Emby.Dlna/IDlnaEventManager.cs (renamed from Emby.Dlna/IEventManager.cs)12
-rw-r--r--Emby.Dlna/IMediaReceiverRegistrar.cs2
-rw-r--r--Emby.Dlna/Images/logo240.jpgbin11520 -> 11483 bytes
-rw-r--r--Emby.Dlna/Images/people48.pngbin286 -> 278 bytes
-rw-r--r--Emby.Dlna/Main/DlnaEntryPoint.cs131
-rw-r--r--Emby.Dlna/MediaReceiverRegistrar/ControlHandler.cs18
-rw-r--r--Emby.Dlna/MediaReceiverRegistrar/MediaReceiverRegistrar.cs39
-rw-r--r--Emby.Dlna/MediaReceiverRegistrar/MediaReceiverRegistrarService.cs46
-rw-r--r--Emby.Dlna/MediaReceiverRegistrar/MediaReceiverRegistrarXmlBuilder.cs121
-rw-r--r--Emby.Dlna/MediaReceiverRegistrar/ServiceActionListBuilder.cs48
-rw-r--r--Emby.Dlna/PlayTo/Device.cs316
-rw-r--r--Emby.Dlna/PlayTo/DeviceInfo.cs5
-rw-r--r--Emby.Dlna/PlayTo/MediaChangedEventArgs.cs13
-rw-r--r--Emby.Dlna/PlayTo/PlayToController.cs337
-rw-r--r--Emby.Dlna/PlayTo/PlayToManager.cs102
-rw-r--r--Emby.Dlna/PlayTo/PlaybackProgressEventArgs.cs2
-rw-r--r--Emby.Dlna/PlayTo/PlaybackStartEventArgs.cs2
-rw-r--r--Emby.Dlna/PlayTo/PlaybackStoppedEventArgs.cs8
-rw-r--r--Emby.Dlna/PlayTo/SsdpHttpClient.cs117
-rw-r--r--Emby.Dlna/PlayTo/TRANSPORTSTATE.cs13
-rw-r--r--Emby.Dlna/PlayTo/TransportCommands.cs70
-rw-r--r--Emby.Dlna/PlayTo/TransportState.cs14
-rw-r--r--Emby.Dlna/PlayTo/UpnpContainer.cs16
-rw-r--r--Emby.Dlna/PlayTo/uBaseObject.cs27
-rw-r--r--Emby.Dlna/PlayTo/uPnpNamespaces.cs90
-rw-r--r--Emby.Dlna/Profiles/DefaultProfile.cs6
-rw-r--r--Emby.Dlna/Profiles/DenonAvrProfile.cs2
-rw-r--r--Emby.Dlna/Profiles/DirectTvProfile.cs2
-rw-r--r--Emby.Dlna/Profiles/DishHopperJoeyProfile.cs12
-rw-r--r--Emby.Dlna/Profiles/Foobar2000Profile.cs2
-rw-r--r--Emby.Dlna/Profiles/LgTvProfile.cs4
-rw-r--r--Emby.Dlna/Profiles/LinksysDMA2100Profile.cs2
-rw-r--r--Emby.Dlna/Profiles/MarantzProfile.cs2
-rw-r--r--Emby.Dlna/Profiles/MediaMonkeyProfile.cs3
-rw-r--r--Emby.Dlna/Profiles/PanasonicVieraProfile.cs2
-rw-r--r--Emby.Dlna/Profiles/PopcornHourProfile.cs14
-rw-r--r--Emby.Dlna/Profiles/SamsungSmartTvProfile.cs2
-rw-r--r--Emby.Dlna/Profiles/SonyBlurayPlayer2013.cs9
-rw-r--r--Emby.Dlna/Profiles/SonyBlurayPlayer2014.cs9
-rw-r--r--Emby.Dlna/Profiles/SonyBlurayPlayer2015.cs9
-rw-r--r--Emby.Dlna/Profiles/SonyBlurayPlayer2016.cs9
-rw-r--r--Emby.Dlna/Profiles/SonyBlurayPlayerProfile.cs10
-rw-r--r--Emby.Dlna/Profiles/SonyBravia2010Profile.cs44
-rw-r--r--Emby.Dlna/Profiles/SonyBravia2011Profile.cs42
-rw-r--r--Emby.Dlna/Profiles/SonyBravia2012Profile.cs34
-rw-r--r--Emby.Dlna/Profiles/SonyBravia2013Profile.cs37
-rw-r--r--Emby.Dlna/Profiles/SonyBravia2014Profile.cs37
-rw-r--r--Emby.Dlna/Profiles/SonyPs3Profile.cs14
-rw-r--r--Emby.Dlna/Profiles/SonyPs4Profile.cs14
-rw-r--r--Emby.Dlna/Profiles/WdtvLiveProfile.cs8
-rw-r--r--Emby.Dlna/Profiles/XboxOneProfile.cs14
-rw-r--r--Emby.Dlna/Server/DescriptionXmlBuilder.cs177
-rw-r--r--Emby.Dlna/Service/BaseControlHandler.cs74
-rw-r--r--Emby.Dlna/Service/BaseService.cs18
-rw-r--r--Emby.Dlna/Service/ControlErrorHandler.cs10
-rw-r--r--Emby.Dlna/Service/ServiceXmlBuilder.cs37
-rw-r--r--Emby.Dlna/Ssdp/DeviceDiscovery.cs37
-rw-r--r--Emby.Dlna/Ssdp/SsdpExtensions.cs (renamed from Emby.Dlna/Ssdp/Extensions.cs)16
83 files changed, 1597 insertions, 1899 deletions
diff --git a/Emby.Dlna/Api/DlnaServerService.cs b/Emby.Dlna/Api/DlnaServerService.cs
deleted file mode 100644
index 7fba2184a7..0000000000
--- a/Emby.Dlna/Api/DlnaServerService.cs
+++ /dev/null
@@ -1,383 +0,0 @@
-#pragma warning disable CS1591
-
-using System;
-using System.Diagnostics.CodeAnalysis;
-using System.IO;
-using System.Text;
-using System.Threading.Tasks;
-using Emby.Dlna.Main;
-using MediaBrowser.Common.Extensions;
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Dlna;
-using MediaBrowser.Controller.Net;
-using MediaBrowser.Model.Services;
-
-namespace Emby.Dlna.Api
-{
- [Route("/Dlna/{UuId}/description.xml", "GET", Summary = "Gets dlna server info")]
- [Route("/Dlna/{UuId}/description", "GET", Summary = "Gets dlna server info")]
- public class GetDescriptionXml
- {
- [ApiMember(Name = "UuId", Description = "Server UuId", IsRequired = false, DataType = "string", ParameterType = "path", Verb = "GET")]
- public string UuId { get; set; }
- }
-
- [Route("/Dlna/{UuId}/contentdirectory/contentdirectory.xml", "GET", Summary = "Gets dlna content directory xml")]
- [Route("/Dlna/{UuId}/contentdirectory/contentdirectory", "GET", Summary = "Gets dlna content directory xml")]
- public class GetContentDirectory
- {
- [ApiMember(Name = "UuId", Description = "Server UuId", IsRequired = false, DataType = "string", ParameterType = "path", Verb = "GET")]
- public string UuId { get; set; }
- }
-
- [Route("/Dlna/{UuId}/connectionmanager/connectionmanager.xml", "GET", Summary = "Gets dlna connection manager xml")]
- [Route("/Dlna/{UuId}/connectionmanager/connectionmanager", "GET", Summary = "Gets dlna connection manager xml")]
- public class GetConnnectionManager
- {
- [ApiMember(Name = "UuId", Description = "Server UuId", IsRequired = false, DataType = "string", ParameterType = "path", Verb = "GET")]
- public string UuId { get; set; }
- }
-
- [Route("/Dlna/{UuId}/mediareceiverregistrar/mediareceiverregistrar.xml", "GET", Summary = "Gets dlna mediareceiverregistrar xml")]
- [Route("/Dlna/{UuId}/mediareceiverregistrar/mediareceiverregistrar", "GET", Summary = "Gets dlna mediareceiverregistrar xml")]
- public class GetMediaReceiverRegistrar
- {
- [ApiMember(Name = "UuId", Description = "Server UuId", IsRequired = false, DataType = "string", ParameterType = "path", Verb = "GET")]
- public string UuId { get; set; }
- }
-
- [Route("/Dlna/{UuId}/contentdirectory/control", "POST", Summary = "Processes a control request")]
- public class ProcessContentDirectoryControlRequest : IRequiresRequestStream
- {
- [ApiMember(Name = "UuId", Description = "Server UuId", IsRequired = false, DataType = "string", ParameterType = "path", Verb = "GET")]
- public string UuId { get; set; }
-
- public Stream RequestStream { get; set; }
- }
-
- [Route("/Dlna/{UuId}/connectionmanager/control", "POST", Summary = "Processes a control request")]
- public class ProcessConnectionManagerControlRequest : IRequiresRequestStream
- {
- [ApiMember(Name = "UuId", Description = "Server UuId", IsRequired = false, DataType = "string", ParameterType = "path", Verb = "GET")]
- public string UuId { get; set; }
-
- public Stream RequestStream { get; set; }
- }
-
- [Route("/Dlna/{UuId}/mediareceiverregistrar/control", "POST", Summary = "Processes a control request")]
- public class ProcessMediaReceiverRegistrarControlRequest : IRequiresRequestStream
- {
- [ApiMember(Name = "UuId", Description = "Server UuId", IsRequired = false, DataType = "string", ParameterType = "path", Verb = "GET")]
- public string UuId { get; set; }
-
- public Stream RequestStream { get; set; }
- }
-
- [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,UNSUBSCRIBE")]
- public string UuId { get; set; }
- }
-
- [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,UNSUBSCRIBE")]
- public string UuId { get; set; }
- }
-
- [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,UNSUBSCRIBE")]
- public string UuId { get; set; }
- }
-
- [Route("/Dlna/{UuId}/icons/{Filename}", "GET", Summary = "Gets a server icon")]
- [Route("/Dlna/icons/{Filename}", "GET", Summary = "Gets a server icon")]
- public class GetIcon
- {
- [ApiMember(Name = "UuId", Description = "Server UuId", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
- public string UuId { get; set; }
-
- [ApiMember(Name = "Filename", Description = "The icon filename", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
- public string Filename { get; set; }
- }
-
- public class DlnaServerService : IService, IRequiresRequest
- {
- private const string XMLContentType = "text/xml; charset=UTF-8";
-
- private readonly IDlnaManager _dlnaManager;
- private readonly IHttpResultFactory _resultFactory;
- private readonly IServerConfigurationManager _configurationManager;
-
- public IRequest Request { get; set; }
-
- private IContentDirectory ContentDirectory => DlnaEntryPoint.Current.ContentDirectory;
-
- private IConnectionManager ConnectionManager => DlnaEntryPoint.Current.ConnectionManager;
-
- private IMediaReceiverRegistrar MediaReceiverRegistrar => DlnaEntryPoint.Current.MediaReceiverRegistrar;
-
- public DlnaServerService(
- IDlnaManager dlnaManager,
- IHttpResultFactory httpResultFactory,
- IServerConfigurationManager configurationManager)
- {
- _dlnaManager = dlnaManager;
- _resultFactory = httpResultFactory;
- _configurationManager = configurationManager;
- }
-
- private string GetHeader(string name)
- {
- return Request.Headers[name];
- }
-
- public object Get(GetDescriptionXml request)
- {
- var url = Request.AbsoluteUri;
- var serverAddress = url.Substring(0, url.IndexOf("/dlna/", StringComparison.OrdinalIgnoreCase));
- var xml = _dlnaManager.GetServerDescriptionXml(Request.Headers, request.UuId, serverAddress);
-
- var cacheLength = TimeSpan.FromDays(1);
- var cacheKey = Request.RawUrl.GetMD5();
- var bytes = Encoding.UTF8.GetBytes(xml);
-
- return _resultFactory.GetStaticResult(Request, cacheKey, null, cacheLength, XMLContentType, () => Task.FromResult<Stream>(new MemoryStream(bytes)));
- }
-
- [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "request", Justification = "Required for ServiceStack")]
- public object Get(GetContentDirectory request)
- {
- var xml = ContentDirectory.GetServiceXml();
-
- return _resultFactory.GetResult(Request, xml, XMLContentType);
- }
-
- [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "request", Justification = "Required for ServiceStack")]
- public object Get(GetMediaReceiverRegistrar request)
- {
- var xml = MediaReceiverRegistrar.GetServiceXml();
-
- return _resultFactory.GetResult(Request, xml, XMLContentType);
- }
-
- [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "request", Justification = "Required for ServiceStack")]
- public object Get(GetConnnectionManager request)
- {
- var xml = ConnectionManager.GetServiceXml();
-
- return _resultFactory.GetResult(Request, xml, XMLContentType);
- }
-
- public async Task<object> Post(ProcessMediaReceiverRegistrarControlRequest request)
- {
- var response = await PostAsync(request.RequestStream, MediaReceiverRegistrar).ConfigureAwait(false);
-
- return _resultFactory.GetResult(Request, response.Xml, XMLContentType);
- }
-
- public async Task<object> Post(ProcessContentDirectoryControlRequest request)
- {
- var response = await PostAsync(request.RequestStream, ContentDirectory).ConfigureAwait(false);
-
- return _resultFactory.GetResult(Request, response.Xml, XMLContentType);
- }
-
- public async Task<object> Post(ProcessConnectionManagerControlRequest request)
- {
- var response = await PostAsync(request.RequestStream, ConnectionManager).ConfigureAwait(false);
-
- return _resultFactory.GetResult(Request, response.Xml, XMLContentType);
- }
-
- private Task<ControlResponse> PostAsync(Stream requestStream, IUpnpService service)
- {
- var id = GetPathValue(2).ToString();
-
- return service.ProcessControlRequestAsync(new ControlRequest
- {
- Headers = Request.Headers,
- InputXml = requestStream,
- TargetServerUuId = id,
- RequestedUrl = Request.AbsoluteUri
- });
- }
-
- // Copied from MediaBrowser.Api/BaseApiService.cs
- // TODO: Remove code duplication
- /// <summary>
- /// Gets the path segment at the specified index.
- /// </summary>
- /// <param name="index">The index of the path segment.</param>
- /// <returns>The path segment at the specified index.</returns>
- /// <exception cref="IndexOutOfRangeException" >Path doesn't contain enough segments.</exception>
- /// <exception cref="InvalidDataException" >Path doesn't start with the base url.</exception>
- protected internal ReadOnlySpan<char> GetPathValue(int index)
- {
- static void ThrowIndexOutOfRangeException()
- => throw new IndexOutOfRangeException("Path doesn't contain enough segments.");
-
- static void ThrowInvalidDataException()
- => throw new InvalidDataException("Path doesn't start with the base url.");
-
- ReadOnlySpan<char> path = Request.PathInfo;
-
- // Remove the protocol part from the url
- int pos = path.LastIndexOf("://");
- if (pos != -1)
- {
- path = path.Slice(pos + 3);
- }
-
- // Remove the query string
- pos = path.LastIndexOf('?');
- if (pos != -1)
- {
- path = path.Slice(0, pos);
- }
-
- // Remove the domain
- pos = path.IndexOf('/');
- if (pos != -1)
- {
- path = path.Slice(pos);
- }
-
- // Remove base url
- string baseUrl = _configurationManager.Configuration.BaseUrl;
- int baseUrlLen = baseUrl.Length;
- if (baseUrlLen != 0)
- {
- if (path.StartsWith(baseUrl, StringComparison.OrdinalIgnoreCase))
- {
- path = path.Slice(baseUrlLen);
- }
- else
- {
- // The path doesn't start with the base url,
- // how did we get here?
- ThrowInvalidDataException();
- }
- }
-
- // Remove leading /
- path = path.Slice(1);
-
- // Backwards compatibility
- const string Emby = "emby/";
- if (path.StartsWith(Emby, StringComparison.OrdinalIgnoreCase))
- {
- path = path.Slice(Emby.Length);
- }
-
- const string MediaBrowser = "mediabrowser/";
- if (path.StartsWith(MediaBrowser, StringComparison.OrdinalIgnoreCase))
- {
- path = path.Slice(MediaBrowser.Length);
- }
-
- // Skip segments until we are at the right index
- for (int i = 0; i < index; i++)
- {
- pos = path.IndexOf('/');
- if (pos == -1)
- {
- ThrowIndexOutOfRangeException();
- }
-
- path = path.Slice(pos + 1);
- }
-
- // Remove the rest
- pos = path.IndexOf('/');
- if (pos != -1)
- {
- path = path.Slice(0, pos);
- }
-
- return path;
- }
-
- public object Get(GetIcon request)
- {
- var contentType = "image/" + Path.GetExtension(request.Filename)
- .TrimStart('.')
- .ToLowerInvariant();
-
- var cacheLength = TimeSpan.FromDays(365);
- var cacheKey = Request.RawUrl.GetMD5();
-
- return _resultFactory.GetStaticResult(Request, cacheKey, null, cacheLength, contentType, () => Task.FromResult(_dlnaManager.GetIcon(request.Filename).Stream));
- }
-
- [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "request", Justification = "Required for ServiceStack")]
- public object Subscribe(ProcessContentDirectoryEventRequest request)
- {
- return ProcessEventRequest(ContentDirectory);
- }
-
- [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "request", Justification = "Required for ServiceStack")]
- public object Subscribe(ProcessConnectionManagerEventRequest request)
- {
- return ProcessEventRequest(ConnectionManager);
- }
-
- [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "request", Justification = "Required for ServiceStack")]
- public object Subscribe(ProcessMediaReceiverRegistrarEventRequest request)
- {
- return ProcessEventRequest(MediaReceiverRegistrar);
- }
-
- [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "request", Justification = "Required for ServiceStack")]
- public object Unsubscribe(ProcessContentDirectoryEventRequest request)
- {
- return ProcessEventRequest(ContentDirectory);
- }
-
- [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "request", Justification = "Required for ServiceStack")]
- public object Unsubscribe(ProcessConnectionManagerEventRequest request)
- {
- return ProcessEventRequest(ConnectionManager);
- }
-
- [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "request", Justification = "Required for ServiceStack")]
- public object Unsubscribe(ProcessMediaReceiverRegistrarEventRequest request)
- {
- return ProcessEventRequest(MediaReceiverRegistrar);
- }
-
- private object ProcessEventRequest(IEventManager eventManager)
- {
- var subscriptionId = GetHeader("SID");
-
- if (string.Equals(Request.Verb, "SUBSCRIBE", StringComparison.OrdinalIgnoreCase))
- {
- var notificationType = GetHeader("NT");
-
- var callback = GetHeader("CALLBACK");
- var timeoutString = GetHeader("TIMEOUT");
-
- if (string.IsNullOrEmpty(notificationType))
- {
- return GetSubscriptionResponse(eventManager.RenewEventSubscription(subscriptionId, notificationType, timeoutString, callback));
- }
-
- return GetSubscriptionResponse(eventManager.CreateEventSubscription(notificationType, timeoutString, callback));
- }
-
- return GetSubscriptionResponse(eventManager.CancelEventSubscription(subscriptionId));
- }
-
- private object GetSubscriptionResponse(EventSubscriptionResponse response)
- {
- return _resultFactory.GetResult(Request, response.Content, response.ContentType, response.Headers);
- }
- }
-}
diff --git a/Emby.Dlna/Api/DlnaService.cs b/Emby.Dlna/Api/DlnaService.cs
deleted file mode 100644
index 5f984bb335..0000000000
--- a/Emby.Dlna/Api/DlnaService.cs
+++ /dev/null
@@ -1,88 +0,0 @@
-#pragma warning disable CS1591
-
-using System.Diagnostics.CodeAnalysis;
-using System.Linq;
-using MediaBrowser.Controller.Dlna;
-using MediaBrowser.Controller.Net;
-using MediaBrowser.Model.Dlna;
-using MediaBrowser.Model.Services;
-
-namespace Emby.Dlna.Api
-{
- [Route("/Dlna/ProfileInfos", "GET", Summary = "Gets a list of profiles")]
- public class GetProfileInfos : IReturn<DeviceProfileInfo[]>
- {
- }
-
- [Route("/Dlna/Profiles/{Id}", "DELETE", Summary = "Deletes a profile")]
- public class DeleteProfile : IReturnVoid
- {
- [ApiMember(Name = "Id", Description = "Profile Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "DELETE")]
- public string Id { get; set; }
- }
-
- [Route("/Dlna/Profiles/Default", "GET", Summary = "Gets the default profile")]
- public class GetDefaultProfile : IReturn<DeviceProfile>
- {
- }
-
- [Route("/Dlna/Profiles/{Id}", "GET", Summary = "Gets a single profile")]
- public class GetProfile : IReturn<DeviceProfile>
- {
- [ApiMember(Name = "Id", Description = "Profile Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
- public string Id { get; set; }
- }
-
- [Route("/Dlna/Profiles/{Id}", "POST", Summary = "Updates a profile")]
- public class UpdateProfile : DeviceProfile, IReturnVoid
- {
- }
-
- [Route("/Dlna/Profiles", "POST", Summary = "Creates a profile")]
- public class CreateProfile : DeviceProfile, IReturnVoid
- {
- }
-
- [Authenticated(Roles = "Admin")]
- public class DlnaService : IService
- {
- private readonly IDlnaManager _dlnaManager;
-
- public DlnaService(IDlnaManager dlnaManager)
- {
- _dlnaManager = dlnaManager;
- }
-
- [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "request", Justification = "Required for ServiceStack")]
- public object Get(GetProfileInfos request)
- {
- return _dlnaManager.GetProfileInfos().ToArray();
- }
-
- public object Get(GetProfile request)
- {
- return _dlnaManager.GetProfile(request.Id);
- }
-
- [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "request", Justification = "Required for ServiceStack")]
- public object Get(GetDefaultProfile request)
- {
- return _dlnaManager.GetDefaultProfile();
- }
-
- public void Delete(DeleteProfile request)
- {
- _dlnaManager.DeleteProfile(request.Id);
- }
-
- public void Post(UpdateProfile request)
- {
- _dlnaManager.UpdateProfile(request);
- }
-
- public void Post(CreateProfile request)
- {
- _dlnaManager.CreateProfile(request);
- }
- }
-}
diff --git a/Emby.Dlna/Common/ServiceAction.cs b/Emby.Dlna/Common/ServiceAction.cs
index db4f270633..d458d7f3f6 100644
--- a/Emby.Dlna/Common/ServiceAction.cs
+++ b/Emby.Dlna/Common/ServiceAction.cs
@@ -13,7 +13,7 @@ namespace Emby.Dlna.Common
public string Name { get; set; }
- public List<Argument> ArgumentList { get; set; }
+ public List<Argument> ArgumentList { get; }
/// <inheritdoc />
public override string ToString()
diff --git a/Emby.Dlna/Common/StateVariable.cs b/Emby.Dlna/Common/StateVariable.cs
index a2c2bf5ddc..6daf7ab6b2 100644
--- a/Emby.Dlna/Common/StateVariable.cs
+++ b/Emby.Dlna/Common/StateVariable.cs
@@ -1,6 +1,7 @@
#pragma warning disable CS1591
using System;
+using System.Collections.Generic;
namespace Emby.Dlna.Common
{
@@ -17,7 +18,7 @@ namespace Emby.Dlna.Common
public bool SendsEvents { get; set; }
- public string[] AllowedValues { get; set; }
+ public IReadOnlyList<string> AllowedValues { get; set; }
/// <inheritdoc />
public override string ToString()
diff --git a/Emby.Dlna/ConfigurationExtension.cs b/Emby.Dlna/ConfigurationExtension.cs
index dba9019677..fc02e17515 100644
--- a/Emby.Dlna/ConfigurationExtension.cs
+++ b/Emby.Dlna/ConfigurationExtension.cs
@@ -1,7 +1,6 @@
#nullable enable
#pragma warning disable CS1591
-using System.Collections.Generic;
using Emby.Dlna.Configuration;
using MediaBrowser.Common.Configuration;
@@ -14,19 +13,4 @@ namespace Emby.Dlna
return manager.GetConfiguration<DlnaOptions>("dlna");
}
}
-
- public class DlnaConfigurationFactory : IConfigurationFactory
- {
- public IEnumerable<ConfigurationStore> GetConfigurations()
- {
- return new ConfigurationStore[]
- {
- new ConfigurationStore
- {
- Key = "dlna",
- ConfigurationType = typeof (DlnaOptions)
- }
- };
- }
- }
}
diff --git a/Emby.Dlna/ConnectionManager/ConnectionManager.cs b/Emby.Dlna/ConnectionManager/ConnectionManagerService.cs
index e32cc11bfa..f5a7eca720 100644
--- a/Emby.Dlna/ConnectionManager/ConnectionManager.cs
+++ b/Emby.Dlna/ConnectionManager/ConnectionManagerService.cs
@@ -1,30 +1,28 @@
#pragma warning disable CS1591
+using System.Net.Http;
using System.Threading.Tasks;
using Emby.Dlna.Service;
-using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Dlna;
using Microsoft.Extensions.Logging;
namespace Emby.Dlna.ConnectionManager
{
- public class ConnectionManager : BaseService, IConnectionManager
+ public class ConnectionManagerService : BaseService, IConnectionManager
{
private readonly IDlnaManager _dlna;
- private readonly ILogger _logger;
private readonly IServerConfigurationManager _config;
- public ConnectionManager(
+ public ConnectionManagerService(
IDlnaManager dlna,
IServerConfigurationManager config,
- ILogger<ConnectionManager> logger,
- IHttpClient httpClient)
- : base(logger, httpClient)
+ ILogger<ConnectionManagerService> logger,
+ IHttpClientFactory httpClientFactory)
+ : base(logger, httpClientFactory)
{
_dlna = dlna;
_config = config;
- _logger = logger;
}
/// <inheritdoc />
@@ -39,7 +37,7 @@ namespace Emby.Dlna.ConnectionManager
var profile = _dlna.GetProfile(request.Headers) ??
_dlna.GetDefaultProfile();
- return new ControlHandler(_config, _logger, profile).ProcessControlRequestAsync(request);
+ return new ControlHandler(_config, Logger, profile).ProcessControlRequestAsync(request);
}
}
}
diff --git a/Emby.Dlna/ConnectionManager/ConnectionManagerXmlBuilder.cs b/Emby.Dlna/ConnectionManager/ConnectionManagerXmlBuilder.cs
index b31d437c3b..c8db5a3674 100644
--- a/Emby.Dlna/ConnectionManager/ConnectionManagerXmlBuilder.cs
+++ b/Emby.Dlna/ConnectionManager/ConnectionManagerXmlBuilder.cs
@@ -44,7 +44,7 @@ namespace Emby.Dlna.ConnectionManager
DataType = "string",
SendsEvents = false,
- AllowedValues = new string[]
+ AllowedValues = new[]
{
"OK",
"ContentFormatMismatch",
@@ -67,7 +67,7 @@ namespace Emby.Dlna.ConnectionManager
DataType = "string",
SendsEvents = false,
- AllowedValues = new string[]
+ AllowedValues = new[]
{
"Output",
"Input"
diff --git a/Emby.Dlna/ContentDirectory/ContentDirectory.cs b/Emby.Dlna/ContentDirectory/ContentDirectoryService.cs
index 64cd308a2a..5760f260cf 100644
--- a/Emby.Dlna/ContentDirectory/ContentDirectory.cs
+++ b/Emby.Dlna/ContentDirectory/ContentDirectoryService.cs
@@ -1,13 +1,15 @@
#pragma warning disable CS1591
using System;
+using System.Linq;
+using System.Net.Http;
using System.Threading.Tasks;
using Emby.Dlna.Service;
-using MediaBrowser.Common.Net;
+using Jellyfin.Data.Entities;
+using Jellyfin.Data.Enums;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Dlna;
using MediaBrowser.Controller.Drawing;
-using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.Controller.TV;
@@ -17,7 +19,7 @@ using Microsoft.Extensions.Logging;
namespace Emby.Dlna.ContentDirectory
{
- public class ContentDirectory : BaseService, IContentDirectory
+ public class ContentDirectoryService : BaseService, IContentDirectory
{
private readonly ILibraryManager _libraryManager;
private readonly IImageProcessor _imageProcessor;
@@ -31,14 +33,15 @@ namespace Emby.Dlna.ContentDirectory
private readonly IMediaEncoder _mediaEncoder;
private readonly ITVSeriesManager _tvSeriesManager;
- public ContentDirectory(IDlnaManager dlna,
+ public ContentDirectoryService(
+ IDlnaManager dlna,
IUserDataManager userDataManager,
IImageProcessor imageProcessor,
ILibraryManager libraryManager,
IServerConfigurationManager config,
IUserManager userManager,
- ILogger<ContentDirectory> logger,
- IHttpClient httpClient,
+ ILogger<ContentDirectoryService> logger,
+ IHttpClientFactory httpClient,
ILocalizationManager localization,
IMediaSourceManager mediaSourceManager,
IUserViewManager userViewManager,
@@ -130,18 +133,13 @@ namespace Emby.Dlna.ContentDirectory
foreach (var user in _userManager.Users)
{
- if (user.Policy.IsAdministrator)
+ if (user.HasPermission(PermissionKind.IsAdministrator))
{
return user;
}
}
- foreach (var user in _userManager.Users)
- {
- return user;
- }
-
- return null;
+ return _userManager.Users.FirstOrDefault();
}
}
}
diff --git a/Emby.Dlna/ContentDirectory/ContentDirectoryXmlBuilder.cs b/Emby.Dlna/ContentDirectory/ContentDirectoryXmlBuilder.cs
index 6db4d7cb66..743dcc5161 100644
--- a/Emby.Dlna/ContentDirectory/ContentDirectoryXmlBuilder.cs
+++ b/Emby.Dlna/ContentDirectory/ContentDirectoryXmlBuilder.cs
@@ -10,7 +10,8 @@ namespace Emby.Dlna.ContentDirectory
{
public string GetXml()
{
- return new ServiceXmlBuilder().GetXml(new ServiceActionListBuilder().GetActions(),
+ return new ServiceXmlBuilder().GetXml(
+ new ServiceActionListBuilder().GetActions(),
GetStateVariables());
}
@@ -101,7 +102,7 @@ namespace Emby.Dlna.ContentDirectory
DataType = "string",
SendsEvents = false,
- AllowedValues = new string[]
+ AllowedValues = new[]
{
"BrowseMetadata",
"BrowseDirectChildren"
diff --git a/Emby.Dlna/ContentDirectory/ControlHandler.cs b/Emby.Dlna/ContentDirectory/ControlHandler.cs
index 28888f031a..4b108b89ea 100644
--- a/Emby.Dlna/ContentDirectory/ControlHandler.cs
+++ b/Emby.Dlna/ContentDirectory/ControlHandler.cs
@@ -10,6 +10,8 @@ using System.Threading;
using System.Xml;
using Emby.Dlna.Didl;
using Emby.Dlna.Service;
+using Jellyfin.Data.Entities;
+using Jellyfin.Data.Enums;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Drawing;
@@ -17,7 +19,6 @@ 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;
@@ -28,11 +29,22 @@ using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Globalization;
using MediaBrowser.Model.Querying;
using Microsoft.Extensions.Logging;
+using Book = MediaBrowser.Controller.Entities.Book;
+using Episode = MediaBrowser.Controller.Entities.TV.Episode;
+using Genre = MediaBrowser.Controller.Entities.Genre;
+using Movie = MediaBrowser.Controller.Entities.Movies.Movie;
+using MusicAlbum = MediaBrowser.Controller.Entities.Audio.MusicAlbum;
+using Series = MediaBrowser.Controller.Entities.TV.Series;
namespace Emby.Dlna.ContentDirectory
{
public class ControlHandler : BaseControlHandler
{
+ private const string NsDc = "http://purl.org/dc/elements/1.1/";
+ private const string NsDidl = "urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/";
+ private const string NsDlna = "urn:schemas-dlna-org:metadata-1-0/";
+ private const string NsUpnp = "urn:schemas-upnp-org:metadata-1-0/upnp/";
+
private readonly ILibraryManager _libraryManager;
private readonly IUserDataManager _userDataManager;
private readonly IServerConfigurationManager _config;
@@ -40,11 +52,6 @@ namespace Emby.Dlna.ContentDirectory
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/";
- private const string NS_DLNA = "urn:schemas-dlna-org:metadata-1-0/";
- private const string NS_UPNP = "urn:schemas-upnp-org:metadata-1-0/upnp/";
-
private readonly int _systemUpdateId;
private readonly DidlBuilder _didlBuilder;
@@ -174,7 +181,11 @@ namespace Emby.Dlna.ContentDirectory
userdata.PlaybackPositionTicks = TimeSpan.FromSeconds(newbookmark).Ticks;
- _userDataManager.SaveUserData(_user, item, userdata, UserDataSaveReason.TogglePlayed,
+ _userDataManager.SaveUserData(
+ _user,
+ item,
+ userdata,
+ UserDataSaveReason.TogglePlayed,
CancellationToken.None);
}
@@ -246,7 +257,7 @@ namespace Emby.Dlna.ContentDirectory
var id = sparams["ObjectID"];
var flag = sparams["BrowseFlag"];
var filter = new Filter(GetValueOrDefault(sparams, "Filter", "*"));
- var sortCriteria = new SortCriteria(GetValueOrDefault(sparams, "SortCriteria", ""));
+ var sortCriteria = new SortCriteria(GetValueOrDefault(sparams, "SortCriteria", string.Empty));
var provided = 0;
@@ -279,18 +290,17 @@ namespace Emby.Dlna.ContentDirectory
using (var writer = XmlWriter.Create(builder, settings))
{
- writer.WriteStartElement(string.Empty, "DIDL-Lite", NS_DIDL);
+ writer.WriteStartElement(string.Empty, "DIDL-Lite", NsDidl);
- writer.WriteAttributeString("xmlns", "dc", null, NS_DC);
- writer.WriteAttributeString("xmlns", "dlna", null, NS_DLNA);
- writer.WriteAttributeString("xmlns", "upnp", null, NS_UPNP);
+ writer.WriteAttributeString("xmlns", "dc", null, NsDc);
+ writer.WriteAttributeString("xmlns", "dlna", null, NsDlna);
+ writer.WriteAttributeString("xmlns", "upnp", null, NsUpnp);
DidlBuilder.WriteXmlRootAttributes(_profile, writer);
var serverItem = GetItemFromObjectId(id);
var item = serverItem.Item;
-
if (string.Equals(flag, "BrowseMetadata", StringComparison.Ordinal))
{
totalCount = 1;
@@ -355,8 +365,8 @@ namespace Emby.Dlna.ContentDirectory
private void HandleSearch(XmlWriter xmlWriter, IDictionary<string, string> sparams, string deviceId)
{
- var searchCriteria = new SearchCriteria(GetValueOrDefault(sparams, "SearchCriteria", ""));
- var sortCriteria = new SortCriteria(GetValueOrDefault(sparams, "SortCriteria", ""));
+ var searchCriteria = new SearchCriteria(GetValueOrDefault(sparams, "SearchCriteria", string.Empty));
+ var sortCriteria = new SortCriteria(GetValueOrDefault(sparams, "SortCriteria", string.Empty));
var filter = new Filter(GetValueOrDefault(sparams, "Filter", "*"));
// sort example: dc:title, dc:date
@@ -390,11 +400,11 @@ namespace Emby.Dlna.ContentDirectory
using (var writer = XmlWriter.Create(builder, settings))
{
- writer.WriteStartElement(string.Empty, "DIDL-Lite", NS_DIDL);
+ writer.WriteStartElement(string.Empty, "DIDL-Lite", NsDidl);
- writer.WriteAttributeString("xmlns", "dc", null, NS_DC);
- writer.WriteAttributeString("xmlns", "dlna", null, NS_DLNA);
- writer.WriteAttributeString("xmlns", "upnp", null, NS_UPNP);
+ writer.WriteAttributeString("xmlns", "dc", null, NsDc);
+ writer.WriteAttributeString("xmlns", "dlna", null, NsDlna);
+ writer.WriteAttributeString("xmlns", "upnp", null, NsUpnp);
DidlBuilder.WriteXmlRootAttributes(_profile, writer);
@@ -460,12 +470,12 @@ namespace Emby.Dlna.ContentDirectory
}
else if (search.SearchType == SearchType.Playlist)
{
- //items = items.OfType<Playlist>();
+ // items = items.OfType<Playlist>();
isFolder = true;
}
else if (search.SearchType == SearchType.MusicAlbum)
{
- //items = items.OfType<MusicAlbum>();
+ // items = items.OfType<MusicAlbum>();
isFolder = true;
}
@@ -731,7 +741,7 @@ namespace Emby.Dlna.ContentDirectory
return GetGenres(item, user, query);
}
- var array = new ServerItem[]
+ var array = new[]
{
new ServerItem(item)
{
@@ -776,11 +786,14 @@ namespace Emby.Dlna.ContentDirectory
})
.ToArray();
- return ApplyPaging(new QueryResult<ServerItem>
- {
- Items = folders,
- TotalRecordCount = folders.Length
- }, startIndex, limit);
+ return ApplyPaging(
+ new QueryResult<ServerItem>
+ {
+ Items = folders,
+ TotalRecordCount = folders.Length
+ },
+ startIndex,
+ limit);
}
private QueryResult<ServerItem> GetTvFolders(BaseItem item, User user, StubType? stubType, SortCriteria sort, int? startIndex, int? limit)
@@ -920,7 +933,7 @@ namespace Emby.Dlna.ContentDirectory
private QueryResult<ServerItem> GetMovieCollections(User user, InternalItemsQuery query)
{
query.Recursive = true;
- //query.Parent = parent;
+ // query.Parent = parent;
query.SetUser(user);
query.IncludeItemTypes = new[] { typeof(BoxSet).Name };
@@ -1115,7 +1128,7 @@ namespace Emby.Dlna.ContentDirectory
private QueryResult<ServerItem> GetMusicPlaylists(User user, InternalItemsQuery query)
{
query.Parent = null;
- query.IncludeItemTypes = new[] { typeof(Playlist).Name };
+ query.IncludeItemTypes = new[] { nameof(Playlist) };
query.SetUser(user);
query.Recursive = true;
@@ -1128,15 +1141,16 @@ namespace Emby.Dlna.ContentDirectory
{
query.OrderBy = Array.Empty<(string, SortOrder)>();
- var items = _userViewManager.GetLatestItems(new LatestItemsQuery
- {
- UserId = user.Id,
- Limit = 50,
- IncludeItemTypes = new[] { typeof(Audio).Name },
- ParentId = parent == null ? Guid.Empty : parent.Id,
- GroupItems = true
-
- }, query.DtoOptions).Select(i => i.Item1 ?? i.Item2.FirstOrDefault()).Where(i => i != null).ToArray();
+ var items = _userViewManager.GetLatestItems(
+ new LatestItemsQuery
+ {
+ UserId = user.Id,
+ Limit = 50,
+ IncludeItemTypes = new[] { nameof(Audio) },
+ ParentId = parent?.Id ?? Guid.Empty,
+ GroupItems = true
+ },
+ query.DtoOptions).Select(i => i.Item1 ?? i.Item2.FirstOrDefault()).Where(i => i != null).ToArray();
return ToResult(items);
}
@@ -1145,13 +1159,15 @@ namespace Emby.Dlna.ContentDirectory
{
query.OrderBy = Array.Empty<(string, SortOrder)>();
- var result = _tvSeriesManager.GetNextUp(new NextUpQuery
- {
- Limit = query.Limit,
- StartIndex = query.StartIndex,
- UserId = query.User.Id
-
- }, new[] { parent }, query.DtoOptions);
+ var result = _tvSeriesManager.GetNextUp(
+ new NextUpQuery
+ {
+ Limit = query.Limit,
+ StartIndex = query.StartIndex,
+ UserId = query.User.Id
+ },
+ new[] { parent },
+ query.DtoOptions);
return ToResult(result);
}
@@ -1160,15 +1176,16 @@ namespace Emby.Dlna.ContentDirectory
{
query.OrderBy = Array.Empty<(string, SortOrder)>();
- var items = _userViewManager.GetLatestItems(new LatestItemsQuery
- {
- UserId = user.Id,
- Limit = 50,
- IncludeItemTypes = new[] { typeof(Episode).Name },
- ParentId = parent == null ? Guid.Empty : parent.Id,
- GroupItems = false
-
- }, query.DtoOptions).Select(i => i.Item1 ?? i.Item2.FirstOrDefault()).Where(i => i != null).ToArray();
+ var items = _userViewManager.GetLatestItems(
+ new LatestItemsQuery
+ {
+ UserId = user.Id,
+ Limit = 50,
+ IncludeItemTypes = new[] { typeof(Episode).Name },
+ ParentId = parent == null ? Guid.Empty : parent.Id,
+ GroupItems = false
+ },
+ query.DtoOptions).Select(i => i.Item1 ?? i.Item2.FirstOrDefault()).Where(i => i != null).ToArray();
return ToResult(items);
}
@@ -1177,15 +1194,16 @@ namespace Emby.Dlna.ContentDirectory
{
query.OrderBy = Array.Empty<(string, SortOrder)>();
- var items = _userViewManager.GetLatestItems(new LatestItemsQuery
- {
- UserId = user.Id,
- Limit = 50,
- IncludeItemTypes = new[] { typeof(Movie).Name },
- ParentId = parent == null ? Guid.Empty : parent.Id,
- GroupItems = true
-
- }, query.DtoOptions).Select(i => i.Item1 ?? i.Item2.FirstOrDefault()).Where(i => i != null).ToArray();
+ var items = _userViewManager.GetLatestItems(
+ new LatestItemsQuery
+ {
+ UserId = user.Id,
+ Limit = 50,
+ IncludeItemTypes = new[] { nameof(Movie) },
+ ParentId = parent?.Id ?? Guid.Empty,
+ GroupItems = true
+ },
+ query.DtoOptions).Select(i => i.Item1 ?? i.Item2.FirstOrDefault()).Where(i => i != null).ToArray();
return ToResult(items);
}
@@ -1217,7 +1235,11 @@ namespace Emby.Dlna.ContentDirectory
Recursive = true,
ParentId = parentId,
GenreIds = new[] { item.Id },
- IncludeItemTypes = new[] { typeof(Movie).Name, typeof(Series).Name },
+ IncludeItemTypes = new[]
+ {
+ nameof(Movie),
+ nameof(Series)
+ },
Limit = limit,
StartIndex = startIndex,
DtoOptions = GetDtoOptions()
@@ -1341,48 +1363,9 @@ namespace Emby.Dlna.ContentDirectory
};
}
- Logger.LogError("Error parsing item Id: {id}. Returning user root folder.", id);
+ Logger.LogError("Error parsing item Id: {Id}. Returning user root folder.", id);
return new ServerItem(_libraryManager.GetUserRootFolder());
}
}
-
- internal class ServerItem
- {
- public BaseItem Item { get; set; }
- public StubType? StubType { get; set; }
-
- public ServerItem(BaseItem item)
- {
- Item = item;
-
- if (item is IItemByName && !(item is Folder))
- {
- StubType = Dlna.ContentDirectory.StubType.Folder;
- }
- }
- }
-
- public enum StubType
- {
- Folder = 0,
- Latest = 2,
- Playlists = 3,
- Albums = 4,
- AlbumArtists = 5,
- Artists = 6,
- Songs = 7,
- Genres = 8,
- FavoriteSongs = 9,
- FavoriteArtists = 10,
- FavoriteAlbums = 11,
- ContinueWatching = 12,
- Movies = 13,
- Collections = 14,
- Favorites = 15,
- NextUp = 16,
- Series = 17,
- FavoriteSeries = 18,
- FavoriteEpisodes = 19
- }
}
diff --git a/Emby.Dlna/ContentDirectory/ServerItem.cs b/Emby.Dlna/ContentDirectory/ServerItem.cs
new file mode 100644
index 0000000000..e406054149
--- /dev/null
+++ b/Emby.Dlna/ContentDirectory/ServerItem.cs
@@ -0,0 +1,23 @@
+#pragma warning disable CS1591
+
+using MediaBrowser.Controller.Entities;
+
+namespace Emby.Dlna.ContentDirectory
+{
+ internal class ServerItem
+ {
+ public ServerItem(BaseItem item)
+ {
+ Item = item;
+
+ if (item is IItemByName && !(item is Folder))
+ {
+ StubType = Dlna.ContentDirectory.StubType.Folder;
+ }
+ }
+
+ public BaseItem Item { get; set; }
+
+ public StubType? StubType { get; set; }
+ }
+}
diff --git a/Emby.Dlna/ContentDirectory/StubType.cs b/Emby.Dlna/ContentDirectory/StubType.cs
new file mode 100644
index 0000000000..eee405d3e7
--- /dev/null
+++ b/Emby.Dlna/ContentDirectory/StubType.cs
@@ -0,0 +1,28 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1602
+
+namespace Emby.Dlna.ContentDirectory
+{
+ public enum StubType
+ {
+ Folder = 0,
+ Latest = 2,
+ Playlists = 3,
+ Albums = 4,
+ AlbumArtists = 5,
+ Artists = 6,
+ Songs = 7,
+ Genres = 8,
+ FavoriteSongs = 9,
+ FavoriteArtists = 10,
+ FavoriteAlbums = 11,
+ ContinueWatching = 12,
+ Movies = 13,
+ Collections = 14,
+ Favorites = 15,
+ NextUp = 16,
+ Series = 17,
+ FavoriteSeries = 18,
+ FavoriteEpisodes = 19
+ }
+}
diff --git a/Emby.Dlna/ControlRequest.cs b/Emby.Dlna/ControlRequest.cs
index a6e03b7e6a..4ea4e4e48c 100644
--- a/Emby.Dlna/ControlRequest.cs
+++ b/Emby.Dlna/ControlRequest.cs
@@ -7,17 +7,17 @@ namespace Emby.Dlna
{
public class ControlRequest
{
- public IHeaderDictionary Headers { get; set; }
+ public ControlRequest(IHeaderDictionary headers)
+ {
+ Headers = headers;
+ }
+
+ public IHeaderDictionary Headers { get; }
public Stream InputXml { get; set; }
public string TargetServerUuId { get; set; }
public string RequestedUrl { get; set; }
-
- public ControlRequest()
- {
- Headers = new HeaderDictionary();
- }
}
}
diff --git a/Emby.Dlna/ControlResponse.cs b/Emby.Dlna/ControlResponse.cs
index 140ef9b463..d827eef26c 100644
--- a/Emby.Dlna/ControlResponse.cs
+++ b/Emby.Dlna/ControlResponse.cs
@@ -11,10 +11,16 @@ namespace Emby.Dlna
Headers = new Dictionary<string, string>();
}
- public IDictionary<string, string> Headers { get; set; }
+ public IDictionary<string, string> Headers { get; }
public string Xml { get; set; }
public bool IsSuccessful { get; set; }
+
+ /// <inheritdoc />
+ public override string ToString()
+ {
+ return Xml;
+ }
}
}
diff --git a/Emby.Dlna/Didl/DidlBuilder.cs b/Emby.Dlna/Didl/DidlBuilder.cs
index f7d840c623..5b8a89d8f3 100644
--- a/Emby.Dlna/Didl/DidlBuilder.cs
+++ b/Emby.Dlna/Didl/DidlBuilder.cs
@@ -6,14 +6,13 @@ using System.IO;
using System.Linq;
using System.Text;
using System.Xml;
-using Emby.Dlna.Configuration;
using Emby.Dlna.ContentDirectory;
+using Jellyfin.Data.Entities;
using MediaBrowser.Controller.Channels;
using MediaBrowser.Controller.Drawing;
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.MediaEncoding;
using MediaBrowser.Controller.Playlists;
@@ -23,17 +22,24 @@ using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Globalization;
using MediaBrowser.Model.Net;
using Microsoft.Extensions.Logging;
+using Episode = MediaBrowser.Controller.Entities.TV.Episode;
+using Genre = MediaBrowser.Controller.Entities.Genre;
+using Movie = MediaBrowser.Controller.Entities.Movies.Movie;
+using MusicAlbum = MediaBrowser.Controller.Entities.Audio.MusicAlbum;
+using Season = MediaBrowser.Controller.Entities.TV.Season;
+using Series = MediaBrowser.Controller.Entities.TV.Series;
+using XmlAttribute = MediaBrowser.Model.Dlna.XmlAttribute;
namespace Emby.Dlna.Didl
{
public class DidlBuilder
{
- private readonly CultureInfo _usCulture = new CultureInfo("en-US");
+ private const string NsDidl = "urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/";
+ private const string NsDc = "http://purl.org/dc/elements/1.1/";
+ private const string NsUpnp = "urn:schemas-upnp-org:metadata-1-0/upnp/";
+ private const string NsDlna = "urn:schemas-dlna-org:metadata-1-0/";
- private const string NS_DIDL = "urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/";
- private const string NS_DC = "http://purl.org/dc/elements/1.1/";
- private const string NS_UPNP = "urn:schemas-upnp-org:metadata-1-0/upnp/";
- private const string NS_DLNA = "urn:schemas-dlna-org:metadata-1-0/";
+ private readonly CultureInfo _usCulture = new CultureInfo("en-US");
private readonly DeviceProfile _profile;
private readonly IImageProcessor _imageProcessor;
@@ -92,21 +98,21 @@ namespace Emby.Dlna.Didl
{
using (var writer = XmlWriter.Create(builder, settings))
{
- //writer.WriteStartDocument();
+ // writer.WriteStartDocument();
- writer.WriteStartElement(string.Empty, "DIDL-Lite", NS_DIDL);
+ writer.WriteStartElement(string.Empty, "DIDL-Lite", NsDidl);
- writer.WriteAttributeString("xmlns", "dc", null, NS_DC);
- writer.WriteAttributeString("xmlns", "dlna", null, NS_DLNA);
- writer.WriteAttributeString("xmlns", "upnp", null, NS_UPNP);
- //didl.SetAttribute("xmlns:sec", NS_SEC);
+ writer.WriteAttributeString("xmlns", "dc", null, NsDc);
+ writer.WriteAttributeString("xmlns", "dlna", null, NsDlna);
+ writer.WriteAttributeString("xmlns", "upnp", null, NsUpnp);
+ // didl.SetAttribute("xmlns:sec", NS_SEC);
WriteXmlRootAttributes(_profile, writer);
WriteItemElement(writer, item, user, context, null, deviceId, filter, streamInfo);
writer.WriteFullEndElement();
- //writer.WriteEndDocument();
+ // writer.WriteEndDocument();
}
return builder.ToString();
@@ -141,7 +147,7 @@ namespace Emby.Dlna.Didl
{
var clientId = GetClientId(item, null);
- writer.WriteStartElement(string.Empty, "item", NS_DIDL);
+ writer.WriteStartElement(string.Empty, "item", NsDidl);
writer.WriteAttributeString("restricted", "1");
writer.WriteAttributeString("id", clientId);
@@ -201,7 +207,8 @@ namespace Emby.Dlna.Didl
var targetWidth = streamInfo.TargetWidth;
var targetHeight = streamInfo.TargetHeight;
- var contentFeatureList = new ContentFeatureBuilder(_profile).BuildVideoHeader(streamInfo.Container,
+ var contentFeatureList = new ContentFeatureBuilder(_profile).BuildVideoHeader(
+ streamInfo.Container,
streamInfo.TargetVideoCodec.FirstOrDefault(),
streamInfo.TargetAudioCodec.FirstOrDefault(),
targetWidth,
@@ -273,7 +280,7 @@ namespace Emby.Dlna.Didl
}
else if (string.Equals(subtitleMode, "smi", StringComparison.OrdinalIgnoreCase))
{
- writer.WriteStartElement(string.Empty, "res", NS_DIDL);
+ writer.WriteStartElement(string.Empty, "res", NsDidl);
writer.WriteAttributeString("protocolInfo", "http-get:*:smi/caption:*");
@@ -282,7 +289,7 @@ namespace Emby.Dlna.Didl
}
else
{
- writer.WriteStartElement(string.Empty, "res", NS_DIDL);
+ writer.WriteStartElement(string.Empty, "res", NsDidl);
var protocolInfo = string.Format(
CultureInfo.InvariantCulture,
"http-get:*:text/{0}:*",
@@ -298,7 +305,7 @@ namespace Emby.Dlna.Didl
private void AddVideoResource(XmlWriter writer, Filter filter, string contentFeatures, StreamInfo streamInfo)
{
- writer.WriteStartElement(string.Empty, "res", NS_DIDL);
+ writer.WriteStartElement(string.Empty, "res", NsDidl);
var url = NormalizeDlnaMediaUrl(streamInfo.ToUrl(_serverAddress, _accessToken));
@@ -358,7 +365,8 @@ namespace Emby.Dlna.Didl
writer.WriteAttributeString("bitrate", totalBitrate.Value.ToString(_usCulture));
}
- var mediaProfile = _profile.GetVideoMediaProfile(streamInfo.Container,
+ var mediaProfile = _profile.GetVideoMediaProfile(
+ streamInfo.Container,
streamInfo.TargetAudioCodec.FirstOrDefault(),
streamInfo.TargetVideoCodec.FirstOrDefault(),
streamInfo.TargetAudioBitrate,
@@ -421,7 +429,6 @@ namespace Emby.Dlna.Didl
case StubType.FavoriteSeries: return _localization.GetLocalizedString("HeaderFavoriteShows");
case StubType.FavoriteEpisodes: return _localization.GetLocalizedString("HeaderFavoriteEpisodes");
case StubType.Series: return _localization.GetLocalizedString("Shows");
- default: break;
}
}
@@ -520,7 +527,7 @@ namespace Emby.Dlna.Didl
private void AddAudioResource(XmlWriter writer, BaseItem audio, string deviceId, Filter filter, StreamInfo streamInfo = null)
{
- writer.WriteStartElement(string.Empty, "res", NS_DIDL);
+ writer.WriteStartElement(string.Empty, "res", NsDidl);
if (streamInfo == null)
{
@@ -577,7 +584,8 @@ namespace Emby.Dlna.Didl
writer.WriteAttributeString("bitrate", targetAudioBitrate.Value.ToString(_usCulture));
}
- var mediaProfile = _profile.GetAudioMediaProfile(streamInfo.Container,
+ var mediaProfile = _profile.GetAudioMediaProfile(
+ streamInfo.Container,
streamInfo.TargetAudioCodec.FirstOrDefault(),
targetChannels,
targetAudioBitrate,
@@ -590,7 +598,8 @@ namespace Emby.Dlna.Didl
? MimeTypes.GetMimeType(filename)
: mediaProfile.MimeType;
- var contentFeatures = new ContentFeatureBuilder(_profile).BuildAudioHeader(streamInfo.Container,
+ var contentFeatures = new ContentFeatureBuilder(_profile).BuildAudioHeader(
+ streamInfo.Container,
streamInfo.TargetAudioCodec.FirstOrDefault(),
targetAudioBitrate,
targetSampleRate,
@@ -621,7 +630,7 @@ namespace Emby.Dlna.Didl
public void WriteFolderElement(XmlWriter writer, BaseItem folder, StubType? stubType, BaseItem context, int childCount, Filter filter, string requestedId = null)
{
- writer.WriteStartElement(string.Empty, "container", NS_DIDL);
+ writer.WriteStartElement(string.Empty, "container", NsDidl);
writer.WriteAttributeString("restricted", "1");
writer.WriteAttributeString("searchable", "1");
@@ -670,7 +679,7 @@ namespace Emby.Dlna.Didl
return;
}
- MediaBrowser.Model.Dlna.XmlAttribute secAttribute = null;
+ XmlAttribute secAttribute = null;
foreach (var attribute in _profile.XmlRootAttributes)
{
if (string.Equals(attribute.Name, "xmlns:sec", StringComparison.OrdinalIgnoreCase))
@@ -700,15 +709,15 @@ namespace Emby.Dlna.Didl
}
/// <summary>
- /// Adds fields used by both items and folders
+ /// Adds fields used by both items and folders.
/// </summary>
private void AddCommonFields(BaseItem item, StubType? itemStubType, BaseItem context, XmlWriter writer, Filter filter)
{
// Don't filter on dc:title because not all devices will include it in the filter
// MediaMonkey for example won't display content without a title
- //if (filter.Contains("dc:title"))
+ // if (filter.Contains("dc:title"))
{
- AddValue(writer, "dc", "title", GetDisplayName(item, itemStubType, context), NS_DC);
+ AddValue(writer, "dc", "title", GetDisplayName(item, itemStubType, context), NsDc);
}
WriteObjectClass(writer, item, itemStubType);
@@ -717,7 +726,7 @@ namespace Emby.Dlna.Didl
{
if (item.PremiereDate.HasValue)
{
- AddValue(writer, "dc", "date", item.PremiereDate.Value.ToString("o", CultureInfo.InvariantCulture), NS_DC);
+ AddValue(writer, "dc", "date", item.PremiereDate.Value.ToString("o", CultureInfo.InvariantCulture), NsDc);
}
}
@@ -725,13 +734,13 @@ namespace Emby.Dlna.Didl
{
foreach (var genre in item.Genres)
{
- AddValue(writer, "upnp", "genre", genre, NS_UPNP);
+ AddValue(writer, "upnp", "genre", genre, NsUpnp);
}
}
foreach (var studio in item.Studios)
{
- AddValue(writer, "upnp", "publisher", studio, NS_UPNP);
+ AddValue(writer, "upnp", "publisher", studio, NsUpnp);
}
if (!(item is Folder))
@@ -742,27 +751,29 @@ namespace Emby.Dlna.Didl
if (!string.IsNullOrWhiteSpace(desc))
{
- AddValue(writer, "dc", "description", desc, NS_DC);
+ AddValue(writer, "dc", "description", desc, NsDc);
}
}
- //if (filter.Contains("upnp:longDescription"))
- //{
+
+ // if (filter.Contains("upnp:longDescription"))
+ // {
// if (!string.IsNullOrWhiteSpace(item.Overview))
// {
- // AddValue(writer, "upnp", "longDescription", item.Overview, NS_UPNP);
+ // AddValue(writer, "upnp", "longDescription", item.Overview, NsUpnp);
// }
- //}
+ // }
}
if (!string.IsNullOrEmpty(item.OfficialRating))
{
if (filter.Contains("dc:rating"))
{
- AddValue(writer, "dc", "rating", item.OfficialRating, NS_DC);
+ AddValue(writer, "dc", "rating", item.OfficialRating, NsDc);
}
+
if (filter.Contains("upnp:rating"))
{
- AddValue(writer, "upnp", "rating", item.OfficialRating, NS_UPNP);
+ AddValue(writer, "upnp", "rating", item.OfficialRating, NsUpnp);
}
}
@@ -774,7 +785,7 @@ namespace Emby.Dlna.Didl
// More types here
// http://oss.linn.co.uk/repos/Public/LibUpnpCil/DidlLite/UpnpAv/Test/TestDidlLite.cs
- writer.WriteStartElement("upnp", "class", NS_UPNP);
+ writer.WriteStartElement("upnp", "class", NsUpnp);
if (item.IsDisplayedAsFolder || stubType.HasValue)
{
@@ -875,7 +886,7 @@ namespace Emby.Dlna.Didl
var type = types.FirstOrDefault(i => string.Equals(i, actor.Type, StringComparison.OrdinalIgnoreCase) || string.Equals(i, actor.Role, StringComparison.OrdinalIgnoreCase))
?? PersonType.Actor;
- AddValue(writer, "upnp", type.ToLowerInvariant(), actor.Name, NS_UPNP);
+ AddValue(writer, "upnp", type.ToLowerInvariant(), actor.Name, NsUpnp);
}
}
@@ -889,8 +900,8 @@ namespace Emby.Dlna.Didl
{
foreach (var artist in hasArtists.Artists)
{
- AddValue(writer, "upnp", "artist", artist, NS_UPNP);
- AddValue(writer, "dc", "creator", artist, NS_DC);
+ AddValue(writer, "upnp", "artist", artist, NsUpnp);
+ AddValue(writer, "dc", "creator", artist, NsDc);
// If it doesn't support album artists (musicvideo), then tag as both
if (hasAlbumArtists == null)
@@ -910,16 +921,16 @@ namespace Emby.Dlna.Didl
if (!string.IsNullOrWhiteSpace(item.Album))
{
- AddValue(writer, "upnp", "album", item.Album, NS_UPNP);
+ AddValue(writer, "upnp", "album", item.Album, NsUpnp);
}
if (item.IndexNumber.HasValue)
{
- AddValue(writer, "upnp", "originalTrackNumber", item.IndexNumber.Value.ToString(_usCulture), NS_UPNP);
+ AddValue(writer, "upnp", "originalTrackNumber", item.IndexNumber.Value.ToString(_usCulture), NsUpnp);
if (item is Episode)
{
- AddValue(writer, "upnp", "episodeNumber", item.IndexNumber.Value.ToString(_usCulture), NS_UPNP);
+ AddValue(writer, "upnp", "episodeNumber", item.IndexNumber.Value.ToString(_usCulture), NsUpnp);
}
}
}
@@ -928,7 +939,7 @@ namespace Emby.Dlna.Didl
{
try
{
- writer.WriteStartElement("upnp", "artist", NS_UPNP);
+ writer.WriteStartElement("upnp", "artist", NsUpnp);
writer.WriteAttributeString("role", "AlbumArtist");
writer.WriteString(name);
@@ -937,7 +948,7 @@ namespace Emby.Dlna.Didl
}
catch (XmlException ex)
{
- _logger.LogError(ex, "Error adding xml value: {value}", name);
+ _logger.LogError(ex, "Error adding xml value: {Value}", name);
}
}
@@ -949,7 +960,7 @@ namespace Emby.Dlna.Didl
}
catch (XmlException ex)
{
- _logger.LogError(ex, "Error adding xml value: {value}", value);
+ _logger.LogError(ex, "Error adding xml value: {Value}", value);
}
}
@@ -964,14 +975,14 @@ namespace Emby.Dlna.Didl
var albumartUrlInfo = GetImageUrl(imageInfo, _profile.MaxAlbumArtWidth, _profile.MaxAlbumArtHeight, "jpg");
- writer.WriteStartElement("upnp", "albumArtURI", NS_UPNP);
- writer.WriteAttributeString("dlna", "profileID", NS_DLNA, _profile.AlbumArtPn);
- writer.WriteString(albumartUrlInfo.Url);
+ writer.WriteStartElement("upnp", "albumArtURI", NsUpnp);
+ writer.WriteAttributeString("dlna", "profileID", NsDlna, _profile.AlbumArtPn);
+ writer.WriteString(albumartUrlInfo.url);
writer.WriteFullEndElement();
// TOOD: Remove these default values
var iconUrlInfo = GetImageUrl(imageInfo, _profile.MaxIconWidth ?? 48, _profile.MaxIconHeight ?? 48, "jpg");
- writer.WriteElementString("upnp", "icon", NS_UPNP, iconUrlInfo.Url);
+ writer.WriteElementString("upnp", "icon", NsUpnp, iconUrlInfo.url);
if (!_profile.EnableAlbumArtInDidl)
{
@@ -995,7 +1006,6 @@ namespace Emby.Dlna.Didl
}
AddImageResElement(item, writer, 160, 160, "jpg", "JPEG_TN");
-
}
private void AddImageResElement(
@@ -1015,12 +1025,12 @@ namespace Emby.Dlna.Didl
var albumartUrlInfo = GetImageUrl(imageInfo, maxWidth, maxHeight, format);
- writer.WriteStartElement(string.Empty, "res", NS_DIDL);
+ writer.WriteStartElement(string.Empty, "res", NsDidl);
// Images must have a reported size or many clients (Bubble upnp), will only use the first thumbnail
// rather than using a larger one when available
- var width = albumartUrlInfo.Width ?? maxWidth;
- var height = albumartUrlInfo.Height ?? maxHeight;
+ var width = albumartUrlInfo.width ?? maxWidth;
+ var height = albumartUrlInfo.height ?? maxHeight;
var contentFeatures = new ContentFeatureBuilder(_profile)
.BuildImageHeader(format, width, height, imageInfo.IsDirectStream, org_Pn);
@@ -1037,7 +1047,7 @@ namespace Emby.Dlna.Didl
"resolution",
string.Format(CultureInfo.InvariantCulture, "{0}x{1}", width, height));
- writer.WriteString(albumartUrlInfo.Url);
+ writer.WriteString(albumartUrlInfo.url);
writer.WriteFullEndElement();
}
@@ -1048,10 +1058,12 @@ namespace Emby.Dlna.Didl
{
return GetImageInfo(item, ImageType.Primary);
}
+
if (item.HasImage(ImageType.Thumb))
{
return GetImageInfo(item, ImageType.Thumb);
}
+
if (item.HasImage(ImageType.Backdrop))
{
if (item is Channel)
@@ -1131,29 +1143,15 @@ namespace Emby.Dlna.Didl
if (width == 0 || height == 0)
{
- //_imageProcessor.GetImageSize(item, imageInfo);
width = null;
height = null;
}
-
else if (width == -1 || height == -1)
{
width = null;
height = null;
}
- //try
- //{
- // var size = _imageProcessor.GetImageSize(imageInfo);
-
- // width = size.Width;
- // height = size.Height;
- //}
- //catch
- //{
-
- //}
-
var inputFormat = (Path.GetExtension(imageInfo.Path) ?? string.Empty)
.TrimStart('.')
.Replace("jpeg", "jpg", StringComparison.OrdinalIgnoreCase);
@@ -1170,30 +1168,6 @@ namespace Emby.Dlna.Didl
};
}
- private class ImageDownloadInfo
- {
- internal Guid ItemId;
- internal string ImageTag;
- internal ImageType Type;
-
- internal int? Width;
- internal int? Height;
-
- internal bool IsDirectStream;
-
- internal string Format;
-
- internal ItemImageInfo ItemImageInfo;
- }
-
- private class ImageUrlInfo
- {
- internal string Url;
-
- internal int? Width;
- internal int? Height;
- }
-
public static string GetClientId(BaseItem item, StubType? stubType)
{
return GetClientId(item.Id, stubType);
@@ -1211,7 +1185,7 @@ namespace Emby.Dlna.Didl
return id;
}
- private ImageUrlInfo GetImageUrl(ImageDownloadInfo info, int maxWidth, int maxHeight, string format)
+ private (string url, int? width, int? height) GetImageUrl(ImageDownloadInfo info, int maxWidth, int maxHeight, string format)
{
var url = string.Format(
CultureInfo.InvariantCulture,
@@ -1249,12 +1223,26 @@ namespace Emby.Dlna.Didl
// just lie
info.IsDirectStream = true;
- return new ImageUrlInfo
- {
- Url = url,
- Width = width,
- Height = height
- };
+ return (url, width, height);
+ }
+
+ private class ImageDownloadInfo
+ {
+ internal Guid ItemId { get; set; }
+
+ internal string ImageTag { get; set; }
+
+ internal ImageType Type { get; set; }
+
+ internal int? Width { get; set; }
+
+ internal int? Height { get; set; }
+
+ internal bool IsDirectStream { get; set; }
+
+ internal string Format { get; set; }
+
+ internal ItemImageInfo ItemImageInfo { get; set; }
}
}
}
diff --git a/Emby.Dlna/Didl/Filter.cs b/Emby.Dlna/Didl/Filter.cs
index 412259e904..b58fdff2c9 100644
--- a/Emby.Dlna/Didl/Filter.cs
+++ b/Emby.Dlna/Didl/Filter.cs
@@ -12,7 +12,6 @@ namespace Emby.Dlna.Didl
public Filter()
: this("*")
{
-
}
public Filter(string filter)
@@ -24,9 +23,7 @@ namespace Emby.Dlna.Didl
public bool Contains(string field)
{
- // Don't bother with this. Some clients (media monkey) use the filter and then don't display very well when very little data comes back.
- return true;
- //return _all || ListHelper.ContainsIgnoreCase(_fields, field);
+ return _all || Array.Exists(_fields, x => x.Equals(field, StringComparison.OrdinalIgnoreCase));
}
}
}
diff --git a/Emby.Dlna/Didl/StringWriterWithEncoding.cs b/Emby.Dlna/Didl/StringWriterWithEncoding.cs
index 896fe992bf..2b86ea333f 100644
--- a/Emby.Dlna/Didl/StringWriterWithEncoding.cs
+++ b/Emby.Dlna/Didl/StringWriterWithEncoding.cs
@@ -1,4 +1,5 @@
#pragma warning disable CS1591
+#pragma warning disable CA1305
using System;
using System.IO;
@@ -29,7 +30,6 @@ namespace Emby.Dlna.Didl
{
}
-
public StringWriterWithEncoding(Encoding encoding)
{
_encoding = encoding;
diff --git a/Emby.Dlna/DlnaConfigurationFactory.cs b/Emby.Dlna/DlnaConfigurationFactory.cs
new file mode 100644
index 0000000000..4c6ca869aa
--- /dev/null
+++ b/Emby.Dlna/DlnaConfigurationFactory.cs
@@ -0,0 +1,24 @@
+#nullable enable
+#pragma warning disable CS1591
+
+using System.Collections.Generic;
+using Emby.Dlna.Configuration;
+using MediaBrowser.Common.Configuration;
+
+namespace Emby.Dlna
+{
+ public class DlnaConfigurationFactory : IConfigurationFactory
+ {
+ public IEnumerable<ConfigurationStore> GetConfigurations()
+ {
+ return new[]
+ {
+ new ConfigurationStore
+ {
+ Key = "dlna",
+ ConfigurationType = typeof(DlnaOptions)
+ }
+ };
+ }
+ }
+}
diff --git a/Emby.Dlna/DlnaManager.cs b/Emby.Dlna/DlnaManager.cs
index 10f881fe76..1807ac6a13 100644
--- a/Emby.Dlna/DlnaManager.cs
+++ b/Emby.Dlna/DlnaManager.cs
@@ -31,7 +31,7 @@ namespace Emby.Dlna
private readonly IApplicationPaths _appPaths;
private readonly IXmlSerializer _xmlSerializer;
private readonly IFileSystem _fileSystem;
- private readonly ILogger _logger;
+ private readonly ILogger<DlnaManager> _logger;
private readonly IJsonSerializer _jsonSerializer;
private readonly IServerApplicationHost _appHost;
private static readonly Assembly _assembly = typeof(DlnaManager).Assembly;
@@ -49,16 +49,20 @@ namespace Emby.Dlna
_xmlSerializer = xmlSerializer;
_fileSystem = fileSystem;
_appPaths = appPaths;
- _logger = loggerFactory.CreateLogger("Dlna");
+ _logger = loggerFactory.CreateLogger<DlnaManager>();
_jsonSerializer = jsonSerializer;
_appHost = appHost;
}
+ private string UserProfilesPath => Path.Combine(_appPaths.ConfigurationDirectoryPath, "dlna", "user");
+
+ private string SystemProfilesPath => Path.Combine(_appPaths.ConfigurationDirectoryPath, "dlna", "system");
+
public async Task InitProfilesAsync()
{
try
{
- await ExtractSystemProfilesAsync();
+ await ExtractSystemProfilesAsync().ConfigureAwait(false);
LoadProfiles();
}
catch (Exception ex)
@@ -88,7 +92,6 @@ namespace Emby.Dlna
.Select(i => i.Item2)
.ToList();
}
-
}
public DeviceProfile GetDefaultProfile()
@@ -123,83 +126,92 @@ namespace Emby.Dlna
var builder = new StringBuilder();
builder.AppendLine("No matching device profile found. The default will need to be used.");
- builder.AppendLine(string.Format("DeviceDescription:{0}", profile.DeviceDescription ?? string.Empty));
- builder.AppendLine(string.Format("FriendlyName:{0}", profile.FriendlyName ?? string.Empty));
- builder.AppendLine(string.Format("Manufacturer:{0}", profile.Manufacturer ?? string.Empty));
- builder.AppendLine(string.Format("ManufacturerUrl:{0}", profile.ManufacturerUrl ?? string.Empty));
- builder.AppendLine(string.Format("ModelDescription:{0}", profile.ModelDescription ?? string.Empty));
- builder.AppendLine(string.Format("ModelName:{0}", profile.ModelName ?? string.Empty));
- builder.AppendLine(string.Format("ModelNumber:{0}", profile.ModelNumber ?? string.Empty));
- builder.AppendLine(string.Format("ModelUrl:{0}", profile.ModelUrl ?? string.Empty));
- builder.AppendLine(string.Format("SerialNumber:{0}", profile.SerialNumber ?? string.Empty));
+ builder.Append("FriendlyName:").AppendLine(profile.FriendlyName);
+ builder.Append("Manufacturer:").AppendLine(profile.Manufacturer);
+ builder.Append("ManufacturerUrl:").AppendLine(profile.ManufacturerUrl);
+ builder.Append("ModelDescription:").AppendLine(profile.ModelDescription);
+ builder.Append("ModelName:").AppendLine(profile.ModelName);
+ builder.Append("ModelNumber:").AppendLine(profile.ModelNumber);
+ builder.Append("ModelUrl:").AppendLine(profile.ModelUrl);
+ builder.Append("SerialNumber:").AppendLine(profile.SerialNumber);
_logger.LogInformation(builder.ToString());
}
private bool IsMatch(DeviceIdentification deviceInfo, DeviceIdentification profileInfo)
{
- if (!string.IsNullOrEmpty(profileInfo.DeviceDescription))
- {
- if (deviceInfo.DeviceDescription == null || !IsRegexMatch(deviceInfo.DeviceDescription, profileInfo.DeviceDescription))
- return false;
- }
-
if (!string.IsNullOrEmpty(profileInfo.FriendlyName))
{
- if (deviceInfo.FriendlyName == null || !IsRegexMatch(deviceInfo.FriendlyName, profileInfo.FriendlyName))
+ if (deviceInfo.FriendlyName == null || !IsRegexOrSubstringMatch(deviceInfo.FriendlyName, profileInfo.FriendlyName))
+ {
return false;
+ }
}
if (!string.IsNullOrEmpty(profileInfo.Manufacturer))
{
- if (deviceInfo.Manufacturer == null || !IsRegexMatch(deviceInfo.Manufacturer, profileInfo.Manufacturer))
+ if (deviceInfo.Manufacturer == null || !IsRegexOrSubstringMatch(deviceInfo.Manufacturer, profileInfo.Manufacturer))
+ {
return false;
+ }
}
if (!string.IsNullOrEmpty(profileInfo.ManufacturerUrl))
{
- if (deviceInfo.ManufacturerUrl == null || !IsRegexMatch(deviceInfo.ManufacturerUrl, profileInfo.ManufacturerUrl))
+ if (deviceInfo.ManufacturerUrl == null || !IsRegexOrSubstringMatch(deviceInfo.ManufacturerUrl, profileInfo.ManufacturerUrl))
+ {
return false;
+ }
}
if (!string.IsNullOrEmpty(profileInfo.ModelDescription))
{
- if (deviceInfo.ModelDescription == null || !IsRegexMatch(deviceInfo.ModelDescription, profileInfo.ModelDescription))
+ if (deviceInfo.ModelDescription == null || !IsRegexOrSubstringMatch(deviceInfo.ModelDescription, profileInfo.ModelDescription))
+ {
return false;
+ }
}
if (!string.IsNullOrEmpty(profileInfo.ModelName))
{
- if (deviceInfo.ModelName == null || !IsRegexMatch(deviceInfo.ModelName, profileInfo.ModelName))
+ if (deviceInfo.ModelName == null || !IsRegexOrSubstringMatch(deviceInfo.ModelName, profileInfo.ModelName))
+ {
return false;
+ }
}
if (!string.IsNullOrEmpty(profileInfo.ModelNumber))
{
- if (deviceInfo.ModelNumber == null || !IsRegexMatch(deviceInfo.ModelNumber, profileInfo.ModelNumber))
+ if (deviceInfo.ModelNumber == null || !IsRegexOrSubstringMatch(deviceInfo.ModelNumber, profileInfo.ModelNumber))
+ {
return false;
+ }
}
if (!string.IsNullOrEmpty(profileInfo.ModelUrl))
{
- if (deviceInfo.ModelUrl == null || !IsRegexMatch(deviceInfo.ModelUrl, profileInfo.ModelUrl))
+ if (deviceInfo.ModelUrl == null || !IsRegexOrSubstringMatch(deviceInfo.ModelUrl, profileInfo.ModelUrl))
+ {
return false;
+ }
}
if (!string.IsNullOrEmpty(profileInfo.SerialNumber))
{
- if (deviceInfo.SerialNumber == null || !IsRegexMatch(deviceInfo.SerialNumber, profileInfo.SerialNumber))
+ if (deviceInfo.SerialNumber == null || !IsRegexOrSubstringMatch(deviceInfo.SerialNumber, profileInfo.SerialNumber))
+ {
return false;
+ }
}
return true;
}
- private bool IsRegexMatch(string input, string pattern)
+ private bool IsRegexOrSubstringMatch(string input, string pattern)
{
try
{
- return Regex.IsMatch(input, pattern);
+ return input.Contains(pattern, StringComparison.OrdinalIgnoreCase) || Regex.IsMatch(input, pattern, RegexOptions.IgnoreCase | RegexOptions.CultureInvariant);
}
catch (ArgumentException ex)
{
@@ -223,7 +235,7 @@ namespace Emby.Dlna
}
else
{
- var headerString = string.Join(", ", headers.Select(i => string.Format("{0}={1}", i.Key, i.Value)).ToArray());
+ var headerString = string.Join(", ", headers.Select(i => string.Format(CultureInfo.InvariantCulture, "{0}={1}", i.Key, i.Value)));
_logger.LogDebug("No matching device profile found. {0}", headerString);
}
@@ -251,7 +263,7 @@ namespace Emby.Dlna
return string.Equals(value, header.Value, StringComparison.OrdinalIgnoreCase);
case HeaderMatchType.Substring:
var isMatch = value.ToString().IndexOf(header.Value, StringComparison.OrdinalIgnoreCase) != -1;
- //_logger.LogDebug("IsMatch-Substring value: {0} testValue: {1} isMatch: {2}", value, header.Value, isMatch);
+ // _logger.LogDebug("IsMatch-Substring value: {0} testValue: {1} isMatch: {2}", value, header.Value, isMatch);
return isMatch;
case HeaderMatchType.Regex:
return Regex.IsMatch(value, header.Value, RegexOptions.IgnoreCase);
@@ -263,10 +275,6 @@ namespace Emby.Dlna
return false;
}
- private string UserProfilesPath => Path.Combine(_appPaths.ConfigurationDirectoryPath, "dlna", "user");
-
- private string SystemProfilesPath => Path.Combine(_appPaths.ConfigurationDirectoryPath, "dlna", "system");
-
private IEnumerable<DeviceProfile> GetProfiles(string path, DeviceProfileType type)
{
try
@@ -370,7 +378,7 @@ namespace Emby.Dlna
foreach (var name in _assembly.GetManifestResourceNames())
{
- if (!name.StartsWith(namespaceName))
+ if (!name.StartsWith(namespaceName, StringComparison.Ordinal))
{
continue;
}
@@ -389,7 +397,7 @@ namespace Emby.Dlna
using (var fileStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read))
{
- await stream.CopyToAsync(fileStream);
+ await stream.CopyToAsync(fileStream).ConfigureAwait(false);
}
}
}
@@ -439,6 +447,7 @@ namespace Emby.Dlna
{
throw new ArgumentException("Profile is missing Id");
}
+
if (string.IsNullOrEmpty(profile.Name))
{
throw new ArgumentException("Profile is missing Name");
@@ -464,6 +473,7 @@ namespace Emby.Dlna
{
_profiles[path] = new Tuple<InternalProfileInfo, DeviceProfile>(GetInternalProfileInfo(_fileSystem.GetFileInfo(path), type), profile);
}
+
SerializeToXml(profile, path);
}
@@ -474,10 +484,10 @@ namespace Emby.Dlna
/// <summary>
/// Recreates the object using serialization, to ensure it's not a subclass.
- /// If it's a subclass it may not serlialize properly to xml (different root element tag name)
+ /// If it's a subclass it may not serlialize properly to xml (different root element tag name).
/// </summary>
- /// <param name="profile"></param>
- /// <returns></returns>
+ /// <param name="profile">The device profile.</param>
+ /// <returns>The reserialized device profile.</returns>
private DeviceProfile ReserializeProfile(DeviceProfile profile)
{
if (profile.GetType() == typeof(DeviceProfile))
@@ -490,16 +500,9 @@ namespace Emby.Dlna
return _jsonSerializer.DeserializeFromString<DeviceProfile>(json);
}
- class InternalProfileInfo
- {
- internal DeviceProfileInfo Info { get; set; }
- internal string Path { get; set; }
- }
-
public string GetServerDescriptionXml(IHeaderDictionary headers, string serverUuId, string serverAddress)
{
- var profile = GetProfile(headers) ??
- GetDefaultProfile();
+ var profile = GetDefaultProfile();
var serverId = _appHost.SystemId;
@@ -520,7 +523,15 @@ namespace Emby.Dlna
Stream = _assembly.GetManifestResourceStream(resource)
};
}
+
+ private class InternalProfileInfo
+ {
+ internal DeviceProfileInfo Info { get; set; }
+
+ internal string Path { get; set; }
+ }
}
+
/*
class DlnaProfileEntryPoint : IServerEntryPoint
{
@@ -566,9 +577,9 @@ namespace Emby.Dlna
new Foobar2000Profile(),
new SharpSmartTvProfile(),
new MediaMonkeyProfile(),
- //new Windows81Profile(),
- //new WindowsMediaCenterProfile(),
- //new WindowsPhoneProfile(),
+ // new Windows81Profile(),
+ // new WindowsMediaCenterProfile(),
+ // new WindowsPhoneProfile(),
new DirectTvProfile(),
new DishHopperJoeyProfile(),
new DefaultProfile(),
diff --git a/Emby.Dlna/Emby.Dlna.csproj b/Emby.Dlna/Emby.Dlna.csproj
index 42a5f95c14..6ed49944c0 100644
--- a/Emby.Dlna/Emby.Dlna.csproj
+++ b/Emby.Dlna/Emby.Dlna.csproj
@@ -20,7 +20,7 @@
<TargetFramework>netstandard2.1</TargetFramework>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
- <TreatWarningsAsErrors Condition=" '$(Configuration)' == 'Release'" >true</TreatWarningsAsErrors>
+ <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>
<!-- Code Analyzers-->
@@ -80,6 +80,7 @@
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Http" Version="2.2.2" />
<PackageReference Include="Microsoft.AspNetCore.WebUtilities" Version="2.2.0" />
+ <PackageReference Include="Microsoft.Extensions.Http" Version="3.1.6" />
</ItemGroup>
</Project>
diff --git a/Emby.Dlna/EventSubscriptionResponse.cs b/Emby.Dlna/EventSubscriptionResponse.cs
index fd18343e62..1b1bd426c5 100644
--- a/Emby.Dlna/EventSubscriptionResponse.cs
+++ b/Emby.Dlna/EventSubscriptionResponse.cs
@@ -15,6 +15,6 @@ namespace Emby.Dlna
public string ContentType { get; set; }
- public Dictionary<string, string> Headers { get; set; }
+ public Dictionary<string, string> Headers { get; }
}
}
diff --git a/Emby.Dlna/Eventing/EventManager.cs b/Emby.Dlna/Eventing/DlnaEventManager.cs
index efbb53b644..7d8da86ef9 100644
--- a/Emby.Dlna/Eventing/EventManager.cs
+++ b/Emby.Dlna/Eventing/DlnaEventManager.cs
@@ -6,6 +6,7 @@ using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Net.Http;
+using System.Net.Mime;
using System.Text;
using System.Threading.Tasks;
using MediaBrowser.Common.Extensions;
@@ -14,35 +15,45 @@ using Microsoft.Extensions.Logging;
namespace Emby.Dlna.Eventing
{
- public class EventManager : IEventManager
+ public class DlnaEventManager : IDlnaEventManager
{
private readonly ConcurrentDictionary<string, EventSubscription> _subscriptions =
new ConcurrentDictionary<string, EventSubscription>(StringComparer.OrdinalIgnoreCase);
private readonly ILogger _logger;
- private readonly IHttpClient _httpClient;
+ private readonly IHttpClientFactory _httpClientFactory;
- public EventManager(ILogger logger, IHttpClient httpClient)
+ private readonly CultureInfo _usCulture = new CultureInfo("en-US");
+
+ public DlnaEventManager(ILogger logger, IHttpClientFactory httpClientFactory)
{
- _httpClient = httpClient;
+ _httpClientFactory = httpClientFactory;
_logger = logger;
}
public EventSubscriptionResponse RenewEventSubscription(string subscriptionId, string notificationType, string requestedTimeoutString, string callbackUrl)
{
var subscription = GetSubscription(subscriptionId, false);
+ if (subscription != null)
+ {
+ subscription.TimeoutSeconds = ParseTimeout(requestedTimeoutString) ?? 300;
+ int timeoutSeconds = subscription.TimeoutSeconds;
+ subscription.SubscriptionTime = DateTime.UtcNow;
- subscription.TimeoutSeconds = ParseTimeout(requestedTimeoutString) ?? 300;
- int timeoutSeconds = subscription.TimeoutSeconds;
- subscription.SubscriptionTime = DateTime.UtcNow;
+ _logger.LogDebug(
+ "Renewing event subscription for {0} with timeout of {1} to {2}",
+ subscription.NotificationType,
+ timeoutSeconds,
+ subscription.CallbackUrl);
- _logger.LogDebug(
- "Renewing event subscription for {0} with timeout of {1} to {2}",
- subscription.NotificationType,
- timeoutSeconds,
- subscription.CallbackUrl);
+ return GetEventSubscriptionResponse(subscriptionId, requestedTimeoutString, timeoutSeconds);
+ }
- return GetEventSubscriptionResponse(subscriptionId, requestedTimeoutString, timeoutSeconds);
+ return new EventSubscriptionResponse
+ {
+ Content = string.Empty,
+ ContentType = "text/plain"
+ };
}
public EventSubscriptionResponse CreateEventSubscription(string notificationType, string requestedTimeoutString, string callbackUrl)
@@ -50,7 +61,8 @@ namespace Emby.Dlna.Eventing
var timeout = ParseTimeout(requestedTimeoutString) ?? 300;
var id = "uuid:" + Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture);
- _logger.LogDebug("Creating event subscription for {0} with timeout of {1} to {2}",
+ _logger.LogDebug(
+ "Creating event subscription for {0} with timeout of {1} to {2}",
notificationType,
timeout,
callbackUrl);
@@ -86,7 +98,7 @@ namespace Emby.Dlna.Eventing
{
_logger.LogDebug("Cancelling event subscription {0}", subscriptionId);
- _subscriptions.TryRemove(subscriptionId, out EventSubscription sub);
+ _subscriptions.TryRemove(subscriptionId, out _);
return new EventSubscriptionResponse
{
@@ -95,7 +107,6 @@ namespace Emby.Dlna.Eventing
};
}
- private readonly CultureInfo _usCulture = new CultureInfo("en-US");
private EventSubscriptionResponse GetEventSubscriptionResponse(string subscriptionId, string requestedTimeoutString, int timeoutSeconds)
{
var response = new EventSubscriptionResponse
@@ -144,33 +155,30 @@ namespace Emby.Dlna.Eventing
builder.Append("<e:propertyset xmlns:e=\"urn:schemas-upnp-org:event-1-0\">");
foreach (var key in stateVariables.Keys)
{
- builder.Append("<e:property>");
- builder.Append("<" + key + ">");
- builder.Append(stateVariables[key]);
- builder.Append("</" + key + ">");
- builder.Append("</e:property>");
+ builder.Append("<e:property>")
+ .Append('<')
+ .Append(key)
+ .Append('>')
+ .Append(stateVariables[key])
+ .Append("</")
+ .Append(key)
+ .Append('>')
+ .Append("</e:property>");
}
- builder.Append("</e:propertyset>");
- var options = new HttpRequestOptions
- {
- RequestContent = builder.ToString(),
- RequestContentType = "text/xml",
- Url = subscription.CallbackUrl,
- BufferContent = false
- };
+ builder.Append("</e:propertyset>");
- options.RequestHeaders.Add("NT", subscription.NotificationType);
- options.RequestHeaders.Add("NTS", "upnp:propchange");
- options.RequestHeaders.Add("SID", subscription.Id);
- options.RequestHeaders.Add("SEQ", subscription.TriggerCount.ToString(_usCulture));
+ using var options = new HttpRequestMessage(new HttpMethod("NOTIFY"), subscription.CallbackUrl);
+ options.Content = new StringContent(builder.ToString(), Encoding.UTF8, MediaTypeNames.Text.Xml);
+ options.Headers.TryAddWithoutValidation("NT", subscription.NotificationType);
+ options.Headers.TryAddWithoutValidation("NTS", "upnp:propchange");
+ options.Headers.TryAddWithoutValidation("SID", subscription.Id);
+ options.Headers.TryAddWithoutValidation("SEQ", subscription.TriggerCount.ToString(_usCulture));
try
{
- using (await _httpClient.SendAsync(options, new HttpMethod("NOTIFY")).ConfigureAwait(false))
- {
-
- }
+ using var response = await _httpClientFactory.CreateClient(NamedClient.Default)
+ .SendAsync(options, HttpCompletionOption.ResponseHeadersRead).ConfigureAwait(false);
}
catch (OperationCanceledException)
{
diff --git a/Emby.Dlna/Eventing/EventSubscription.cs b/Emby.Dlna/Eventing/EventSubscription.cs
index 51eaee9d77..40d73ee0e5 100644
--- a/Emby.Dlna/Eventing/EventSubscription.cs
+++ b/Emby.Dlna/Eventing/EventSubscription.cs
@@ -7,10 +7,13 @@ namespace Emby.Dlna.Eventing
public class EventSubscription
{
public string Id { get; set; }
+
public string CallbackUrl { get; set; }
+
public string NotificationType { get; set; }
public DateTime SubscriptionTime { get; set; }
+
public int TimeoutSeconds { get; set; }
public long TriggerCount { get; set; }
diff --git a/Emby.Dlna/IConnectionManager.cs b/Emby.Dlna/IConnectionManager.cs
index 7b4a33a98c..9f643a9e64 100644
--- a/Emby.Dlna/IConnectionManager.cs
+++ b/Emby.Dlna/IConnectionManager.cs
@@ -2,7 +2,7 @@
namespace Emby.Dlna
{
- public interface IConnectionManager : IEventManager, IUpnpService
+ public interface IConnectionManager : IDlnaEventManager, IUpnpService
{
}
}
diff --git a/Emby.Dlna/IContentDirectory.cs b/Emby.Dlna/IContentDirectory.cs
index 83ef09c665..10f4d63866 100644
--- a/Emby.Dlna/IContentDirectory.cs
+++ b/Emby.Dlna/IContentDirectory.cs
@@ -2,7 +2,7 @@
namespace Emby.Dlna
{
- public interface IContentDirectory : IEventManager, IUpnpService
+ public interface IContentDirectory : IDlnaEventManager, IUpnpService
{
}
}
diff --git a/Emby.Dlna/IEventManager.cs b/Emby.Dlna/IDlnaEventManager.cs
index 2872033892..33cf0896ba 100644
--- a/Emby.Dlna/IEventManager.cs
+++ b/Emby.Dlna/IDlnaEventManager.cs
@@ -2,22 +2,32 @@
namespace Emby.Dlna
{
- public interface IEventManager
+ public interface IDlnaEventManager
{
/// <summary>
/// Cancels the event subscription.
/// </summary>
/// <param name="subscriptionId">The subscription identifier.</param>
+ /// <returns>The response.</returns>
EventSubscriptionResponse CancelEventSubscription(string subscriptionId);
/// <summary>
/// Renews the event subscription.
/// </summary>
+ /// <param name="subscriptionId">The subscription identifier.</param>
+ /// <param name="notificationType">The notification type.</param>
+ /// <param name="requestedTimeoutString">The requested timeout as a sting.</param>
+ /// <param name="callbackUrl">The callback url.</param>
+ /// <returns>The response.</returns>
EventSubscriptionResponse RenewEventSubscription(string subscriptionId, string notificationType, string requestedTimeoutString, string callbackUrl);
/// <summary>
/// Creates the event subscription.
/// </summary>
+ /// <param name="notificationType">The notification type.</param>
+ /// <param name="requestedTimeoutString">The requested timeout as a sting.</param>
+ /// <param name="callbackUrl">The callback url.</param>
+ /// <returns>The response.</returns>
EventSubscriptionResponse CreateEventSubscription(string notificationType, string requestedTimeoutString, string callbackUrl);
}
}
diff --git a/Emby.Dlna/IMediaReceiverRegistrar.cs b/Emby.Dlna/IMediaReceiverRegistrar.cs
index b0376b6a99..43e934b53a 100644
--- a/Emby.Dlna/IMediaReceiverRegistrar.cs
+++ b/Emby.Dlna/IMediaReceiverRegistrar.cs
@@ -2,7 +2,7 @@
namespace Emby.Dlna
{
- public interface IMediaReceiverRegistrar : IEventManager, IUpnpService
+ public interface IMediaReceiverRegistrar : IDlnaEventManager, IUpnpService
{
}
}
diff --git a/Emby.Dlna/Images/logo240.jpg b/Emby.Dlna/Images/logo240.jpg
index da1cb5e071..78a27f1b54 100644
--- a/Emby.Dlna/Images/logo240.jpg
+++ b/Emby.Dlna/Images/logo240.jpg
Binary files differ
diff --git a/Emby.Dlna/Images/people48.png b/Emby.Dlna/Images/people48.png
index 7fb25e6b39..dae5f6057f 100644
--- a/Emby.Dlna/Images/people48.png
+++ b/Emby.Dlna/Images/people48.png
Binary files differ
diff --git a/Emby.Dlna/Main/DlnaEntryPoint.cs b/Emby.Dlna/Main/DlnaEntryPoint.cs
index c5d60b2a05..40c2cc0e0a 100644
--- a/Emby.Dlna/Main/DlnaEntryPoint.cs
+++ b/Emby.Dlna/Main/DlnaEntryPoint.cs
@@ -2,6 +2,7 @@
using System;
using System.Globalization;
+using System.Net.Http;
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;
@@ -30,15 +31,13 @@ using OperatingSystem = MediaBrowser.Common.System.OperatingSystem;
namespace Emby.Dlna.Main
{
- public class DlnaEntryPoint : IServerEntryPoint, IRunBeforeStartup
+ public sealed class DlnaEntryPoint : IServerEntryPoint, IRunBeforeStartup
{
private readonly IServerConfigurationManager _config;
- private readonly ILogger _logger;
+ private readonly ILogger<DlnaEntryPoint> _logger;
private readonly IServerApplicationHost _appHost;
-
- private PlayToManager _manager;
private readonly ISessionManager _sessionManager;
- private readonly IHttpClient _httpClient;
+ private readonly IHttpClientFactory _httpClientFactory;
private readonly ILibraryManager _libraryManager;
private readonly IUserManager _userManager;
private readonly IDlnaManager _dlnaManager;
@@ -47,29 +46,23 @@ namespace Emby.Dlna.Main
private readonly ILocalizationManager _localization;
private readonly IMediaSourceManager _mediaSourceManager;
private readonly IMediaEncoder _mediaEncoder;
-
private readonly IDeviceDiscovery _deviceDiscovery;
-
- private SsdpDevicePublisher _Publisher;
-
private readonly ISocketFactory _socketFactory;
private readonly INetworkManager _networkManager;
+ private readonly object _syncLock = new object();
+ private PlayToManager _manager;
+ private SsdpDevicePublisher _publisher;
private ISsdpCommunicationsServer _communicationsServer;
- internal IContentDirectory ContentDirectory { get; private set; }
-
- internal IConnectionManager ConnectionManager { get; private set; }
-
- internal IMediaReceiverRegistrar MediaReceiverRegistrar { get; private set; }
-
- public static DlnaEntryPoint Current;
+ private bool _disposed;
- public DlnaEntryPoint(IServerConfigurationManager config,
+ public DlnaEntryPoint(
+ IServerConfigurationManager config,
ILoggerFactory loggerFactory,
IServerApplicationHost appHost,
ISessionManager sessionManager,
- IHttpClient httpClient,
+ IHttpClientFactory httpClientFactory,
ILibraryManager libraryManager,
IUserManager userManager,
IDlnaManager dlnaManager,
@@ -87,7 +80,7 @@ namespace Emby.Dlna.Main
_config = config;
_appHost = appHost;
_sessionManager = sessionManager;
- _httpClient = httpClient;
+ _httpClientFactory = httpClientFactory;
_libraryManager = libraryManager;
_userManager = userManager;
_dlnaManager = dlnaManager;
@@ -99,54 +92,62 @@ namespace Emby.Dlna.Main
_mediaEncoder = mediaEncoder;
_socketFactory = socketFactory;
_networkManager = networkManager;
- _logger = loggerFactory.CreateLogger("Dlna");
+ _logger = loggerFactory.CreateLogger<DlnaEntryPoint>();
- ContentDirectory = new ContentDirectory.ContentDirectory(
+ ContentDirectory = new ContentDirectory.ContentDirectoryService(
dlnaManager,
userDataManager,
imageProcessor,
libraryManager,
config,
userManager,
- loggerFactory.CreateLogger<ContentDirectory.ContentDirectory>(),
- httpClient,
+ loggerFactory.CreateLogger<ContentDirectory.ContentDirectoryService>(),
+ httpClientFactory,
localizationManager,
mediaSourceManager,
userViewManager,
mediaEncoder,
tvSeriesManager);
- ConnectionManager = new ConnectionManager.ConnectionManager(
+ ConnectionManager = new ConnectionManager.ConnectionManagerService(
dlnaManager,
config,
- loggerFactory.CreateLogger<ConnectionManager.ConnectionManager>(),
- httpClient);
+ loggerFactory.CreateLogger<ConnectionManager.ConnectionManagerService>(),
+ httpClientFactory);
- MediaReceiverRegistrar = new MediaReceiverRegistrar.MediaReceiverRegistrar(
- loggerFactory.CreateLogger<MediaReceiverRegistrar.MediaReceiverRegistrar>(),
- httpClient,
+ MediaReceiverRegistrar = new MediaReceiverRegistrar.MediaReceiverRegistrarService(
+ loggerFactory.CreateLogger<MediaReceiverRegistrar.MediaReceiverRegistrarService>(),
+ httpClientFactory,
config);
Current = this;
}
+ public static DlnaEntryPoint Current { get; private set; }
+
+ public IContentDirectory ContentDirectory { get; private set; }
+
+ public IConnectionManager ConnectionManager { get; private set; }
+
+ public IMediaReceiverRegistrar MediaReceiverRegistrar { get; private set; }
+
public async Task RunAsync()
{
await ((DlnaManager)_dlnaManager).InitProfilesAsync().ConfigureAwait(false);
- ReloadComponents();
+ await ReloadComponents().ConfigureAwait(false);
- _config.NamedConfigurationUpdated += _config_NamedConfigurationUpdated;
+ _config.NamedConfigurationUpdated += OnNamedConfigurationUpdated;
}
- void _config_NamedConfigurationUpdated(object sender, ConfigurationUpdateEventArgs e)
+ private async void OnNamedConfigurationUpdated(object sender, ConfigurationUpdateEventArgs e)
{
if (string.Equals(e.Key, "dlna", StringComparison.OrdinalIgnoreCase))
{
- ReloadComponents();
+ await ReloadComponents().ConfigureAwait(false);
}
}
- private async void ReloadComponents()
+ private async Task ReloadComponents()
{
var options = _config.GetDlnaConfiguration();
@@ -180,7 +181,7 @@ namespace Emby.Dlna.Main
var enableMultiSocketBinding = OperatingSystem.Id == OperatingSystemId.Windows ||
OperatingSystem.Id == OperatingSystemId.Linux;
- _communicationsServer = new SsdpCommunicationsServer(_config, _socketFactory, _networkManager, _logger, enableMultiSocketBinding)
+ _communicationsServer = new SsdpCommunicationsServer(_socketFactory, _networkManager, _logger, enableMultiSocketBinding)
{
IsShared = true
};
@@ -231,20 +232,22 @@ namespace Emby.Dlna.Main
return;
}
- if (_Publisher != null)
+ if (_publisher != null)
{
return;
}
try
{
- _Publisher = new SsdpDevicePublisher(_communicationsServer, _networkManager, OperatingSystem.Name, Environment.OSVersion.VersionString, _config.GetDlnaConfiguration().SendOnlyMatchedHost);
- _Publisher.LogFunction = LogMessage;
- _Publisher.SupportPnpRootDevice = false;
+ _publisher = new SsdpDevicePublisher(_communicationsServer, _networkManager, OperatingSystem.Name, Environment.OSVersion.VersionString, _config.GetDlnaConfiguration().SendOnlyMatchedHost)
+ {
+ LogFunction = LogMessage,
+ SupportPnpRootDevice = false
+ };
await RegisterServerEndpoints().ConfigureAwait(false);
- _Publisher.StartBroadcastingAliveMessages(TimeSpan.FromSeconds(options.BlastAliveMessageIntervalSeconds));
+ _publisher.StartBroadcastingAliveMessages(TimeSpan.FromSeconds(options.BlastAliveMessageIntervalSeconds));
}
catch (Exception ex)
{
@@ -266,6 +269,12 @@ namespace Emby.Dlna.Main
continue;
}
+ // Limit to LAN addresses only
+ if (!_networkManager.IsAddressInSubnets(address, true, true))
+ {
+ continue;
+ }
+
var fullService = "urn:schemas-upnp-org:device:MediaServer:1";
_logger.LogInformation("Registering publisher for {0} on {1}", fullService, address);
@@ -275,7 +284,7 @@ namespace Emby.Dlna.Main
var device = new SsdpRootDevice
{
- CacheLifetime = TimeSpan.FromSeconds(1800), //How long SSDP clients can cache this info.
+ CacheLifetime = TimeSpan.FromSeconds(1800), // How long SSDP clients can cache this info.
Location = uri, // Must point to the URL that serves your devices UPnP description document.
Address = address,
SubnetMask = _networkManager.GetLocalIpSubnetMask(address),
@@ -287,13 +296,13 @@ namespace Emby.Dlna.Main
};
SetProperies(device, fullService);
- _Publisher.AddDevice(device);
+ _publisher.AddDevice(device);
var embeddedDevices = new[]
{
"urn:schemas-upnp-org:service:ContentDirectory:1",
"urn:schemas-upnp-org:service:ConnectionManager:1",
- //"urn:microsoft.com:service:X_MS_MediaReceiverRegistrar:1"
+ // "urn:microsoft.com:service:X_MS_MediaReceiverRegistrar:1"
};
foreach (var subDevice in embeddedDevices)
@@ -319,12 +328,13 @@ namespace Emby.Dlna.Main
{
guid = text.GetMD5();
}
+
return guid.ToString("N", CultureInfo.InvariantCulture);
}
private void SetProperies(SsdpDevice device, string fullDeviceType)
{
- var service = fullDeviceType.Replace("urn:", string.Empty).Replace(":1", string.Empty);
+ var service = fullDeviceType.Replace("urn:", string.Empty, StringComparison.OrdinalIgnoreCase).Replace(":1", string.Empty, StringComparison.OrdinalIgnoreCase);
var serviceParts = service.Split(':');
@@ -335,7 +345,6 @@ namespace Emby.Dlna.Main
device.DeviceType = serviceParts[2];
}
- private readonly object _syncLock = new object();
private void StartPlayToManager()
{
lock (_syncLock)
@@ -347,7 +356,8 @@ namespace Emby.Dlna.Main
try
{
- _manager = new PlayToManager(_logger,
+ _manager = new PlayToManager(
+ _logger,
_sessionManager,
_libraryManager,
_userManager,
@@ -355,7 +365,7 @@ namespace Emby.Dlna.Main
_appHost,
_imageProcessor,
_deviceDiscovery,
- _httpClient,
+ _httpClientFactory,
_config,
_userDataManager,
_localization,
@@ -386,13 +396,30 @@ namespace Emby.Dlna.Main
{
_logger.LogError(ex, "Error disposing PlayTo manager");
}
+
_manager = null;
}
}
}
+ public void DisposeDevicePublisher()
+ {
+ if (_publisher != null)
+ {
+ _logger.LogInformation("Disposing SsdpDevicePublisher");
+ _publisher.Dispose();
+ _publisher = null;
+ }
+ }
+
+ /// <inheritdoc />
public void Dispose()
{
+ if (_disposed)
+ {
+ return;
+ }
+
DisposeDevicePublisher();
DisposePlayToManager();
DisposeDeviceDiscovery();
@@ -408,16 +435,8 @@ namespace Emby.Dlna.Main
ConnectionManager = null;
MediaReceiverRegistrar = null;
Current = null;
- }
- public void DisposeDevicePublisher()
- {
- if (_Publisher != null)
- {
- _logger.LogInformation("Disposing SsdpDevicePublisher");
- _Publisher.Dispose();
- _Publisher = null;
- }
+ _disposed = true;
}
}
}
diff --git a/Emby.Dlna/MediaReceiverRegistrar/ControlHandler.cs b/Emby.Dlna/MediaReceiverRegistrar/ControlHandler.cs
index 8bf0cd961b..464f71a6f1 100644
--- a/Emby.Dlna/MediaReceiverRegistrar/ControlHandler.cs
+++ b/Emby.Dlna/MediaReceiverRegistrar/ControlHandler.cs
@@ -1,5 +1,3 @@
-#pragma warning disable CS1591
-
using System;
using System.Collections.Generic;
using System.Xml;
@@ -10,8 +8,16 @@ using Microsoft.Extensions.Logging;
namespace Emby.Dlna.MediaReceiverRegistrar
{
+ /// <summary>
+ /// Defines the <see cref="ControlHandler" />.
+ /// </summary>
public class ControlHandler : BaseControlHandler
{
+ /// <summary>
+ /// Initializes a new instance of the <see cref="ControlHandler"/> class.
+ /// </summary>
+ /// <param name="config">The <see cref="IServerConfigurationManager"/> for use with the <see cref="ControlHandler"/> instance.</param>
+ /// <param name="logger">The <see cref="ILogger"/> for use with the <see cref="ControlHandler"/> instance.</param>
public ControlHandler(IServerConfigurationManager config, ILogger logger)
: base(config, logger)
{
@@ -35,9 +41,17 @@ namespace Emby.Dlna.MediaReceiverRegistrar
throw new ResourceNotFoundException("Unexpected control request name: " + methodName);
}
+ /// <summary>
+ /// Records that the handle is authorized in the xml stream.
+ /// </summary>
+ /// <param name="xmlWriter">The <see cref="XmlWriter"/>.</param>
private static void HandleIsAuthorized(XmlWriter xmlWriter)
=> xmlWriter.WriteElementString("Result", "1");
+ /// <summary>
+ /// Records that the handle is validated in the xml stream.
+ /// </summary>
+ /// <param name="xmlWriter">The <see cref="XmlWriter"/>.</param>
private static void HandleIsValidated(XmlWriter xmlWriter)
=> xmlWriter.WriteElementString("Result", "1");
}
diff --git a/Emby.Dlna/MediaReceiverRegistrar/MediaReceiverRegistrar.cs b/Emby.Dlna/MediaReceiverRegistrar/MediaReceiverRegistrar.cs
deleted file mode 100644
index 64dfc840a8..0000000000
--- a/Emby.Dlna/MediaReceiverRegistrar/MediaReceiverRegistrar.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-#pragma warning disable CS1591
-
-using System.Threading.Tasks;
-using Emby.Dlna.Service;
-using MediaBrowser.Common.Net;
-using MediaBrowser.Controller.Configuration;
-using Microsoft.Extensions.Logging;
-
-namespace Emby.Dlna.MediaReceiverRegistrar
-{
- public class MediaReceiverRegistrar : BaseService, IMediaReceiverRegistrar
- {
- private readonly IServerConfigurationManager _config;
-
- public MediaReceiverRegistrar(
- ILogger<MediaReceiverRegistrar> logger,
- IHttpClient httpClient,
- IServerConfigurationManager config)
- : base(logger, httpClient)
- {
- _config = config;
- }
-
- /// <inheritdoc />
- public string GetServiceXml()
- {
- return new MediaReceiverRegistrarXmlBuilder().GetXml();
- }
-
- /// <inheritdoc />
- public Task<ControlResponse> ProcessControlRequestAsync(ControlRequest request)
- {
- return new ControlHandler(
- _config,
- Logger)
- .ProcessControlRequestAsync(request);
- }
- }
-}
diff --git a/Emby.Dlna/MediaReceiverRegistrar/MediaReceiverRegistrarService.cs b/Emby.Dlna/MediaReceiverRegistrar/MediaReceiverRegistrarService.cs
new file mode 100644
index 0000000000..a5aae515c4
--- /dev/null
+++ b/Emby.Dlna/MediaReceiverRegistrar/MediaReceiverRegistrarService.cs
@@ -0,0 +1,46 @@
+using System.Net.Http;
+using System.Threading.Tasks;
+using Emby.Dlna.Service;
+using MediaBrowser.Controller.Configuration;
+using Microsoft.Extensions.Logging;
+
+namespace Emby.Dlna.MediaReceiverRegistrar
+{
+ /// <summary>
+ /// Defines the <see cref="MediaReceiverRegistrarService" />.
+ /// </summary>
+ public class MediaReceiverRegistrarService : BaseService, IMediaReceiverRegistrar
+ {
+ private readonly IServerConfigurationManager _config;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="MediaReceiverRegistrarService"/> class.
+ /// </summary>
+ /// <param name="logger">The <see cref="ILogger{MediaReceiverRegistrarService}"/> for use with the <see cref="MediaReceiverRegistrarService"/> instance.</param>
+ /// <param name="httpClientFactory">The <see cref="IHttpClientFactory"/> for use with the <see cref="MediaReceiverRegistrarService"/> instance.</param>
+ /// <param name="config">The <see cref="IServerConfigurationManager"/> for use with the <see cref="MediaReceiverRegistrarService"/> instance.</param>
+ public MediaReceiverRegistrarService(
+ ILogger<MediaReceiverRegistrarService> logger,
+ IHttpClientFactory httpClientFactory,
+ IServerConfigurationManager config)
+ : base(logger, httpClientFactory)
+ {
+ _config = config;
+ }
+
+ /// <inheritdoc />
+ public string GetServiceXml()
+ {
+ return MediaReceiverRegistrarXmlBuilder.GetXml();
+ }
+
+ /// <inheritdoc />
+ public Task<ControlResponse> ProcessControlRequestAsync(ControlRequest request)
+ {
+ return new ControlHandler(
+ _config,
+ Logger)
+ .ProcessControlRequestAsync(request);
+ }
+ }
+}
diff --git a/Emby.Dlna/MediaReceiverRegistrar/MediaReceiverRegistrarXmlBuilder.cs b/Emby.Dlna/MediaReceiverRegistrar/MediaReceiverRegistrarXmlBuilder.cs
index 8497025461..37840cd096 100644
--- a/Emby.Dlna/MediaReceiverRegistrar/MediaReceiverRegistrarXmlBuilder.cs
+++ b/Emby.Dlna/MediaReceiverRegistrar/MediaReceiverRegistrarXmlBuilder.cs
@@ -1,78 +1,89 @@
-#pragma warning disable CS1591
-
using System.Collections.Generic;
using Emby.Dlna.Common;
using Emby.Dlna.Service;
+using MediaBrowser.Model.Dlna;
namespace Emby.Dlna.MediaReceiverRegistrar
{
- public class MediaReceiverRegistrarXmlBuilder
+ /// <summary>
+ /// Defines the <see cref="MediaReceiverRegistrarXmlBuilder" />.
+ /// See https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-drmnd/5d37515e-7a63-4709-8258-8fd4e0ed4482.
+ /// </summary>
+ public static class MediaReceiverRegistrarXmlBuilder
{
- public string GetXml()
+ /// <summary>
+ /// Retrieves an XML description of the X_MS_MediaReceiverRegistrar.
+ /// </summary>
+ /// <returns>An XML representation of this service.</returns>
+ public static string GetXml()
{
- return new ServiceXmlBuilder().GetXml(new ServiceActionListBuilder().GetActions(),
- GetStateVariables());
+ return new ServiceXmlBuilder().GetXml(ServiceActionListBuilder.GetActions(), GetStateVariables());
}
+ /// <summary>
+ /// The a list of all the state variables for this invocation.
+ /// </summary>
+ /// <returns>The <see cref="IEnumerable{StateVariable}"/>.</returns>
private static IEnumerable<StateVariable> GetStateVariables()
{
- var list = new List<StateVariable>();
-
- list.Add(new StateVariable
+ var list = new List<StateVariable>
{
- Name = "AuthorizationGrantedUpdateID",
- DataType = "ui4",
- SendsEvents = true
- });
+ new StateVariable
+ {
+ Name = "AuthorizationGrantedUpdateID",
+ DataType = "ui4",
+ SendsEvents = true
+ },
- list.Add(new StateVariable
- {
- Name = "A_ARG_TYPE_DeviceID",
- DataType = "string",
- SendsEvents = false
- });
+ new StateVariable
+ {
+ Name = "A_ARG_TYPE_DeviceID",
+ DataType = "string",
+ SendsEvents = false
+ },
- list.Add(new StateVariable
- {
- Name = "AuthorizationDeniedUpdateID",
- DataType = "ui4",
- SendsEvents = true
- });
+ new StateVariable
+ {
+ Name = "AuthorizationDeniedUpdateID",
+ DataType = "ui4",
+ SendsEvents = true
+ },
- list.Add(new StateVariable
- {
- Name = "ValidationSucceededUpdateID",
- DataType = "ui4",
- SendsEvents = true
- });
+ new StateVariable
+ {
+ Name = "ValidationSucceededUpdateID",
+ DataType = "ui4",
+ SendsEvents = true
+ },
- list.Add(new StateVariable
- {
- Name = "A_ARG_TYPE_RegistrationRespMsg",
- DataType = "bin.base64",
- SendsEvents = false
- });
+ new StateVariable
+ {
+ Name = "A_ARG_TYPE_RegistrationRespMsg",
+ DataType = "bin.base64",
+ SendsEvents = false
+ },
- list.Add(new StateVariable
- {
- Name = "A_ARG_TYPE_RegistrationReqMsg",
- DataType = "bin.base64",
- SendsEvents = false
- });
+ new StateVariable
+ {
+ Name = "A_ARG_TYPE_RegistrationReqMsg",
+ DataType = "bin.base64",
+ SendsEvents = false
+ },
- list.Add(new StateVariable
- {
- Name = "ValidationRevokedUpdateID",
- DataType = "ui4",
- SendsEvents = true
- });
+ new StateVariable
+ {
+ Name = "ValidationRevokedUpdateID",
+ DataType = "ui4",
+ SendsEvents = true
+ },
- list.Add(new StateVariable
- {
- Name = "A_ARG_TYPE_Result",
- DataType = "int",
- SendsEvents = false
- });
+ new StateVariable
+ {
+ Name = "A_ARG_TYPE_Result",
+ DataType = "int",
+ SendsEvents = false
+ }
+ };
return list;
}
diff --git a/Emby.Dlna/MediaReceiverRegistrar/ServiceActionListBuilder.cs b/Emby.Dlna/MediaReceiverRegistrar/ServiceActionListBuilder.cs
index 13545c6894..1dc9c79c14 100644
--- a/Emby.Dlna/MediaReceiverRegistrar/ServiceActionListBuilder.cs
+++ b/Emby.Dlna/MediaReceiverRegistrar/ServiceActionListBuilder.cs
@@ -1,13 +1,19 @@
-#pragma warning disable CS1591
-
using System.Collections.Generic;
using Emby.Dlna.Common;
+using MediaBrowser.Model.Dlna;
namespace Emby.Dlna.MediaReceiverRegistrar
{
- public class ServiceActionListBuilder
+ /// <summary>
+ /// Defines the <see cref="ServiceActionListBuilder" />.
+ /// </summary>
+ public static class ServiceActionListBuilder
{
- public IEnumerable<ServiceAction> GetActions()
+ /// <summary>
+ /// Returns a list of services that this instance provides.
+ /// </summary>
+ /// <returns>An <see cref="IEnumerable{ServiceAction}"/>.</returns>
+ public static IEnumerable<ServiceAction> GetActions()
{
return new[]
{
@@ -21,6 +27,10 @@ namespace Emby.Dlna.MediaReceiverRegistrar
};
}
+ /// <summary>
+ /// Returns the action details for "IsValidated".
+ /// </summary>
+ /// <returns>The <see cref="ServiceAction"/>.</returns>
private static ServiceAction GetIsValidated()
{
var action = new ServiceAction
@@ -43,6 +53,10 @@ namespace Emby.Dlna.MediaReceiverRegistrar
return action;
}
+ /// <summary>
+ /// Returns the action details for "IsAuthorized".
+ /// </summary>
+ /// <returns>The <see cref="ServiceAction"/>.</returns>
private static ServiceAction GetIsAuthorized()
{
var action = new ServiceAction
@@ -65,6 +79,10 @@ namespace Emby.Dlna.MediaReceiverRegistrar
return action;
}
+ /// <summary>
+ /// Returns the action details for "RegisterDevice".
+ /// </summary>
+ /// <returns>The <see cref="ServiceAction"/>.</returns>
private static ServiceAction GetRegisterDevice()
{
var action = new ServiceAction
@@ -87,6 +105,10 @@ namespace Emby.Dlna.MediaReceiverRegistrar
return action;
}
+ /// <summary>
+ /// Returns the action details for "GetValidationSucceededUpdateID".
+ /// </summary>
+ /// <returns>The <see cref="ServiceAction"/>.</returns>
private static ServiceAction GetGetValidationSucceededUpdateID()
{
var action = new ServiceAction
@@ -103,7 +125,11 @@ namespace Emby.Dlna.MediaReceiverRegistrar
return action;
}
- private ServiceAction GetGetAuthorizationDeniedUpdateID()
+ /// <summary>
+ /// Returns the action details for "GetGetAuthorizationDeniedUpdateID".
+ /// </summary>
+ /// <returns>The <see cref="ServiceAction"/>.</returns>
+ private static ServiceAction GetGetAuthorizationDeniedUpdateID()
{
var action = new ServiceAction
{
@@ -119,7 +145,11 @@ namespace Emby.Dlna.MediaReceiverRegistrar
return action;
}
- private ServiceAction GetGetValidationRevokedUpdateID()
+ /// <summary>
+ /// Returns the action details for "GetValidationRevokedUpdateID".
+ /// </summary>
+ /// <returns>The <see cref="ServiceAction"/>.</returns>
+ private static ServiceAction GetGetValidationRevokedUpdateID()
{
var action = new ServiceAction
{
@@ -135,7 +165,11 @@ namespace Emby.Dlna.MediaReceiverRegistrar
return action;
}
- private ServiceAction GetGetAuthorizationGrantedUpdateID()
+ /// <summary>
+ /// Returns the action details for "GetAuthorizationGrantedUpdateID".
+ /// </summary>
+ /// <returns>The <see cref="ServiceAction"/>.</returns>
+ private static ServiceAction GetGetAuthorizationGrantedUpdateID()
{
var action = new ServiceAction
{
diff --git a/Emby.Dlna/PlayTo/Device.cs b/Emby.Dlna/PlayTo/Device.cs
index 6abc3a82c3..c97acdb026 100644
--- a/Emby.Dlna/PlayTo/Device.cs
+++ b/Emby.Dlna/PlayTo/Device.cs
@@ -4,12 +4,13 @@ using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
+using System.Net.Http;
+using System.Security;
using System.Threading;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Linq;
using Emby.Dlna.Common;
-using Emby.Dlna.Server;
using Emby.Dlna.Ssdp;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Configuration;
@@ -19,24 +20,48 @@ namespace Emby.Dlna.PlayTo
{
public class Device : IDisposable
{
- #region Fields & Properties
+ private static readonly CultureInfo UsCulture = new CultureInfo("en-US");
+
+ private readonly IHttpClientFactory _httpClientFactory;
+
+ private readonly ILogger _logger;
+ private readonly object _timerLock = new object();
private Timer _timer;
+ private int _muteVol;
+ private int _volume;
+ private DateTime _lastVolumeRefresh;
+ private bool _volumeRefreshActive;
+ private int _connectFailureCount;
+ private bool _disposed;
+
+ public Device(DeviceInfo deviceProperties, IHttpClientFactory httpClientFactory, ILogger logger)
+ {
+ Properties = deviceProperties;
+ _httpClientFactory = httpClientFactory;
+ _logger = logger;
+ }
+
+ public event EventHandler<PlaybackStartEventArgs> PlaybackStart;
+
+ public event EventHandler<PlaybackProgressEventArgs> PlaybackProgress;
+
+ public event EventHandler<PlaybackStoppedEventArgs> PlaybackStopped;
+
+ public event EventHandler<MediaChangedEventArgs> MediaChanged;
public DeviceInfo Properties { get; set; }
- private int _muteVol;
public bool IsMuted { get; set; }
- private int _volume;
-
public int Volume
{
get
{
- RefreshVolumeIfNeeded();
+ RefreshVolumeIfNeeded().GetAwaiter().GetResult();
return _volume;
}
+
set => _volume = value;
}
@@ -44,29 +69,21 @@ namespace Emby.Dlna.PlayTo
public TimeSpan Position { get; set; } = TimeSpan.FromSeconds(0);
- public TRANSPORTSTATE TransportState { get; private set; }
+ public TransportState TransportState { get; private set; }
- public bool IsPlaying => TransportState == TRANSPORTSTATE.PLAYING;
+ public bool IsPlaying => TransportState == TransportState.Playing;
- public bool IsPaused => TransportState == TRANSPORTSTATE.PAUSED || TransportState == TRANSPORTSTATE.PAUSED_PLAYBACK;
+ public bool IsPaused => TransportState == TransportState.Paused || TransportState == TransportState.PausedPlayback;
- public bool IsStopped => TransportState == TRANSPORTSTATE.STOPPED;
+ public bool IsStopped => TransportState == TransportState.Stopped;
- #endregion
+ public Action OnDeviceUnavailable { get; set; }
- private readonly IHttpClient _httpClient;
- private readonly ILogger _logger;
- private readonly IServerConfigurationManager _config;
+ private TransportCommands AvCommands { get; set; }
- public Action OnDeviceUnavailable { get; set; }
+ private TransportCommands RendererCommands { get; set; }
- public Device(DeviceInfo deviceProperties, IHttpClient httpClient, ILogger logger, IServerConfigurationManager config)
- {
- Properties = deviceProperties;
- _httpClient = httpClient;
- _logger = logger;
- _config = config;
- }
+ public UBaseObject CurrentMediaInfo { get; private set; }
public void Start()
{
@@ -74,26 +91,24 @@ namespace Emby.Dlna.PlayTo
_timer = new Timer(TimerCallback, null, 1000, Timeout.Infinite);
}
- private DateTime _lastVolumeRefresh;
- private bool _volumeRefreshActive;
- private void RefreshVolumeIfNeeded()
+ private Task RefreshVolumeIfNeeded()
{
- if (!_volumeRefreshActive)
- {
- return;
- }
-
- if (DateTime.UtcNow >= _lastVolumeRefresh.AddSeconds(5))
+ if (_volumeRefreshActive
+ && DateTime.UtcNow >= _lastVolumeRefresh.AddSeconds(5))
{
_lastVolumeRefresh = DateTime.UtcNow;
- RefreshVolume(CancellationToken.None);
+ return RefreshVolume();
}
+
+ return Task.CompletedTask;
}
- private async void RefreshVolume(CancellationToken cancellationToken)
+ private async Task RefreshVolume(CancellationToken cancellationToken = default)
{
if (_disposed)
+ {
return;
+ }
try
{
@@ -106,7 +121,6 @@ namespace Emby.Dlna.PlayTo
}
}
- private readonly object _timerLock = new object();
private void RestartTimer(bool immediate = false)
{
lock (_timerLock)
@@ -141,8 +155,6 @@ namespace Emby.Dlna.PlayTo
}
}
- #region Commanding
-
public Task VolumeDown(CancellationToken cancellationToken)
{
var sendVolume = Math.Max(Volume - 5, 0);
@@ -211,7 +223,9 @@ namespace Emby.Dlna.PlayTo
var command = rendererCommands.ServiceActions.FirstOrDefault(c => c.Name == "SetMute");
if (command == null)
+ {
return false;
+ }
var service = GetServiceRenderingControl();
@@ -223,7 +237,7 @@ namespace Emby.Dlna.PlayTo
_logger.LogDebug("Setting mute");
var value = mute ? 1 : 0;
- await new SsdpHttpClient(_httpClient).SendCommandAsync(Properties.BaseUrl, service, command.Name, rendererCommands.BuildPost(command, service.ServiceType, value))
+ await new SsdpHttpClient(_httpClientFactory).SendCommandAsync(Properties.BaseUrl, service, command.Name, rendererCommands.BuildPost(command, service.ServiceType, value))
.ConfigureAwait(false);
IsMuted = mute;
@@ -232,15 +246,20 @@ namespace Emby.Dlna.PlayTo
}
/// <summary>
- /// Sets volume on a scale of 0-100
+ /// Sets volume on a scale of 0-100.
/// </summary>
+ /// <param name="value">The volume on a scale of 0-100.</param>
+ /// <param name="cancellationToken">The cancellation token to cancel operation.</param>
+ /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
public async Task SetVolume(int value, CancellationToken cancellationToken)
{
var rendererCommands = await GetRenderingProtocolAsync(cancellationToken).ConfigureAwait(false);
var command = rendererCommands.ServiceActions.FirstOrDefault(c => c.Name == "SetVolume");
if (command == null)
+ {
return;
+ }
var service = GetServiceRenderingControl();
@@ -253,7 +272,7 @@ namespace Emby.Dlna.PlayTo
// Remote control will perform better
Volume = value;
- await new SsdpHttpClient(_httpClient).SendCommandAsync(Properties.BaseUrl, service, command.Name, rendererCommands.BuildPost(command, service.ServiceType, value))
+ await new SsdpHttpClient(_httpClientFactory).SendCommandAsync(Properties.BaseUrl, service, command.Name, rendererCommands.BuildPost(command, service.ServiceType, value))
.ConfigureAwait(false);
}
@@ -263,7 +282,9 @@ namespace Emby.Dlna.PlayTo
var command = avCommands.ServiceActions.FirstOrDefault(c => c.Name == "Seek");
if (command == null)
+ {
return;
+ }
var service = GetAvTransportService();
@@ -272,7 +293,7 @@ namespace Emby.Dlna.PlayTo
throw new InvalidOperationException("Unable to find service");
}
- await new SsdpHttpClient(_httpClient).SendCommandAsync(Properties.BaseUrl, service, command.Name, avCommands.BuildPost(command, service.ServiceType, string.Format("{0:hh}:{0:mm}:{0:ss}", value), "REL_TIME"))
+ await new SsdpHttpClient(_httpClientFactory).SendCommandAsync(Properties.BaseUrl, service, command.Name, avCommands.BuildPost(command, service.ServiceType, string.Format(CultureInfo.InvariantCulture, "{0:hh}:{0:mm}:{0:ss}", value), "REL_TIME"))
.ConfigureAwait(false);
RestartTimer(true);
@@ -282,18 +303,20 @@ namespace Emby.Dlna.PlayTo
{
var avCommands = await GetAVProtocolAsync(cancellationToken).ConfigureAwait(false);
- url = url.Replace("&", "&amp;");
+ url = url.Replace("&", "&amp;", StringComparison.Ordinal);
_logger.LogDebug("{0} - SetAvTransport Uri: {1} DlnaHeaders: {2}", Properties.Name, url, header);
var command = avCommands.ServiceActions.FirstOrDefault(c => c.Name == "SetAVTransportURI");
if (command == null)
+ {
return;
+ }
var dictionary = new Dictionary<string, string>
{
- {"CurrentURI", url},
- {"CurrentURIMetaData", CreateDidlMeta(metaData)}
+ { "CurrentURI", url },
+ { "CurrentURIMetaData", CreateDidlMeta(metaData) }
};
var service = GetAvTransportService();
@@ -304,7 +327,7 @@ namespace Emby.Dlna.PlayTo
}
var post = avCommands.BuildPost(command, service.ServiceType, url, dictionary);
- await new SsdpHttpClient(_httpClient).SendCommandAsync(Properties.BaseUrl, service, command.Name, post, header: header)
+ await new SsdpHttpClient(_httpClientFactory).SendCommandAsync(Properties.BaseUrl, service, command.Name, post, header: header)
.ConfigureAwait(false);
await Task.Delay(50).ConfigureAwait(false);
@@ -329,7 +352,7 @@ namespace Emby.Dlna.PlayTo
return string.Empty;
}
- return DescriptionXmlBuilder.Escape(value);
+ return SecurityElement.Escape(value);
}
private Task SetPlay(TransportCommands avCommands, CancellationToken cancellationToken)
@@ -346,7 +369,7 @@ namespace Emby.Dlna.PlayTo
throw new InvalidOperationException("Unable to find service");
}
- return new SsdpHttpClient(_httpClient).SendCommandAsync(
+ return new SsdpHttpClient(_httpClientFactory).SendCommandAsync(
Properties.BaseUrl,
service,
command.Name,
@@ -375,7 +398,7 @@ namespace Emby.Dlna.PlayTo
var service = GetAvTransportService();
- await new SsdpHttpClient(_httpClient).SendCommandAsync(Properties.BaseUrl, service, command.Name, avCommands.BuildPost(command, service.ServiceType, 1))
+ await new SsdpHttpClient(_httpClientFactory).SendCommandAsync(Properties.BaseUrl, service, command.Name, avCommands.BuildPost(command, service.ServiceType, 1))
.ConfigureAwait(false);
RestartTimer(true);
@@ -393,19 +416,14 @@ namespace Emby.Dlna.PlayTo
var service = GetAvTransportService();
- await new SsdpHttpClient(_httpClient).SendCommandAsync(Properties.BaseUrl, service, command.Name, avCommands.BuildPost(command, service.ServiceType, 1))
+ await new SsdpHttpClient(_httpClientFactory).SendCommandAsync(Properties.BaseUrl, service, command.Name, avCommands.BuildPost(command, service.ServiceType, 1))
.ConfigureAwait(false);
- TransportState = TRANSPORTSTATE.PAUSED;
+ TransportState = TransportState.Paused;
RestartTimer(true);
}
- #endregion
-
- #region Get data
-
- private int _connectFailureCount;
private async void TimerCallback(object sender)
{
if (_disposed)
@@ -434,7 +452,7 @@ namespace Emby.Dlna.PlayTo
if (transportState.HasValue)
{
// If we're not playing anything no need to get additional data
- if (transportState.Value == TRANSPORTSTATE.STOPPED)
+ if (transportState.Value == TransportState.Stopped)
{
UpdateMediaInfo(null, transportState.Value);
}
@@ -458,10 +476,12 @@ namespace Emby.Dlna.PlayTo
_connectFailureCount = 0;
if (_disposed)
+ {
return;
+ }
// If we're not playing anything make sure we don't get data more often than neccessry to keep the Session alive
- if (transportState.Value == TRANSPORTSTATE.STOPPED)
+ if (transportState.Value == TransportState.Stopped)
{
RestartTimerInactive();
}
@@ -478,7 +498,9 @@ namespace Emby.Dlna.PlayTo
catch (Exception ex)
{
if (_disposed)
+ {
return;
+ }
_logger.LogError(ex, "Error updating device info for {DeviceName}", Properties.Name);
@@ -494,6 +516,7 @@ namespace Emby.Dlna.PlayTo
return;
}
}
+
RestartTimerInactive();
}
}
@@ -520,7 +543,7 @@ namespace Emby.Dlna.PlayTo
return;
}
- var result = await new SsdpHttpClient(_httpClient).SendCommandAsync(
+ var result = await new SsdpHttpClient(_httpClientFactory).SendCommandAsync(
Properties.BaseUrl,
service,
command.Name,
@@ -532,7 +555,7 @@ namespace Emby.Dlna.PlayTo
return;
}
- var volume = result.Document.Descendants(uPnpNamespaces.RenderingControl + "GetVolumeResponse").Select(i => i.Element("CurrentVolume")).FirstOrDefault(i => i != null);
+ var volume = result.Document.Descendants(UPnpNamespaces.RenderingControl + "GetVolumeResponse").Select(i => i.Element("CurrentVolume")).FirstOrDefault(i => i != null);
var volumeValue = volume?.Value;
if (string.IsNullOrWhiteSpace(volumeValue))
@@ -570,7 +593,7 @@ namespace Emby.Dlna.PlayTo
return;
}
- var result = await new SsdpHttpClient(_httpClient).SendCommandAsync(
+ var result = await new SsdpHttpClient(_httpClientFactory).SendCommandAsync(
Properties.BaseUrl,
service,
command.Name,
@@ -578,16 +601,18 @@ namespace Emby.Dlna.PlayTo
cancellationToken: cancellationToken).ConfigureAwait(false);
if (result == null || result.Document == null)
+ {
return;
+ }
- var valueNode = result.Document.Descendants(uPnpNamespaces.RenderingControl + "GetMuteResponse")
+ var valueNode = result.Document.Descendants(UPnpNamespaces.RenderingControl + "GetMuteResponse")
.Select(i => i.Element("CurrentMute"))
.FirstOrDefault(i => i != null);
IsMuted = string.Equals(valueNode?.Value, "1", StringComparison.OrdinalIgnoreCase);
}
- private async Task<TRANSPORTSTATE?> GetTransportInfo(TransportCommands avCommands, CancellationToken cancellationToken)
+ private async Task<TransportState?> GetTransportInfo(TransportCommands avCommands, CancellationToken cancellationToken)
{
var command = avCommands.ServiceActions.FirstOrDefault(c => c.Name == "GetTransportInfo");
if (command == null)
@@ -601,7 +626,7 @@ namespace Emby.Dlna.PlayTo
return null;
}
- var result = await new SsdpHttpClient(_httpClient).SendCommandAsync(
+ var result = await new SsdpHttpClient(_httpClientFactory).SendCommandAsync(
Properties.BaseUrl,
service,
command.Name,
@@ -614,12 +639,12 @@ namespace Emby.Dlna.PlayTo
}
var transportState =
- result.Document.Descendants(uPnpNamespaces.AvTransport + "GetTransportInfoResponse").Select(i => i.Element("CurrentTransportState")).FirstOrDefault(i => i != null);
+ result.Document.Descendants(UPnpNamespaces.AvTransport + "GetTransportInfoResponse").Select(i => i.Element("CurrentTransportState")).FirstOrDefault(i => i != null);
var transportStateValue = transportState?.Value;
if (transportStateValue != null
- && Enum.TryParse(transportStateValue, true, out TRANSPORTSTATE state))
+ && Enum.TryParse(transportStateValue, true, out TransportState state))
{
return state;
}
@@ -627,7 +652,7 @@ namespace Emby.Dlna.PlayTo
return null;
}
- private async Task<uBaseObject> GetMediaInfo(TransportCommands avCommands, CancellationToken cancellationToken)
+ private async Task<UBaseObject> GetMediaInfo(TransportCommands avCommands, CancellationToken cancellationToken)
{
var command = avCommands.ServiceActions.FirstOrDefault(c => c.Name == "GetMediaInfo");
if (command == null)
@@ -643,7 +668,7 @@ namespace Emby.Dlna.PlayTo
var rendererCommands = await GetRenderingProtocolAsync(cancellationToken).ConfigureAwait(false);
- var result = await new SsdpHttpClient(_httpClient).SendCommandAsync(
+ var result = await new SsdpHttpClient(_httpClientFactory).SendCommandAsync(
Properties.BaseUrl,
service,
command.Name,
@@ -662,7 +687,7 @@ namespace Emby.Dlna.PlayTo
return null;
}
- var e = track.Element(uPnpNamespaces.items) ?? track;
+ var e = track.Element(UPnpNamespaces.Items) ?? track;
var elementString = (string)e;
@@ -678,13 +703,13 @@ namespace Emby.Dlna.PlayTo
return null;
}
- e = track.Element(uPnpNamespaces.items) ?? track;
+ e = track.Element(UPnpNamespaces.Items) ?? track;
elementString = (string)e;
if (!string.IsNullOrWhiteSpace(elementString))
{
- return new uBaseObject
+ return new UBaseObject
{
Url = elementString
};
@@ -693,7 +718,7 @@ namespace Emby.Dlna.PlayTo
return null;
}
- private async Task<(bool, uBaseObject)> GetPositionInfo(TransportCommands avCommands, CancellationToken cancellationToken)
+ private async Task<(bool, UBaseObject)> GetPositionInfo(TransportCommands avCommands, CancellationToken cancellationToken)
{
var command = avCommands.ServiceActions.FirstOrDefault(c => c.Name == "GetPositionInfo");
if (command == null)
@@ -710,7 +735,7 @@ namespace Emby.Dlna.PlayTo
var rendererCommands = await GetRenderingProtocolAsync(cancellationToken).ConfigureAwait(false);
- var result = await new SsdpHttpClient(_httpClient).SendCommandAsync(
+ var result = await new SsdpHttpClient(_httpClientFactory).SendCommandAsync(
Properties.BaseUrl,
service,
command.Name,
@@ -722,11 +747,11 @@ namespace Emby.Dlna.PlayTo
return (false, null);
}
- var trackUriElem = result.Document.Descendants(uPnpNamespaces.AvTransport + "GetPositionInfoResponse").Select(i => i.Element("TrackURI")).FirstOrDefault(i => i != null);
- var trackUri = trackUriElem == null ? null : trackUriElem.Value;
+ var trackUriElem = result.Document.Descendants(UPnpNamespaces.AvTransport + "GetPositionInfoResponse").Select(i => i.Element("TrackURI")).FirstOrDefault(i => i != null);
+ var trackUri = trackUriElem?.Value;
- var durationElem = result.Document.Descendants(uPnpNamespaces.AvTransport + "GetPositionInfoResponse").Select(i => i.Element("TrackDuration")).FirstOrDefault(i => i != null);
- var duration = durationElem == null ? null : durationElem.Value;
+ var durationElem = result.Document.Descendants(UPnpNamespaces.AvTransport + "GetPositionInfoResponse").Select(i => i.Element("TrackDuration")).FirstOrDefault(i => i != null);
+ var duration = durationElem?.Value;
if (!string.IsNullOrWhiteSpace(duration)
&& !string.Equals(duration, "NOT_IMPLEMENTED", StringComparison.OrdinalIgnoreCase))
@@ -738,8 +763,8 @@ namespace Emby.Dlna.PlayTo
Duration = null;
}
- var positionElem = result.Document.Descendants(uPnpNamespaces.AvTransport + "GetPositionInfoResponse").Select(i => i.Element("RelTime")).FirstOrDefault(i => i != null);
- var position = positionElem == null ? null : positionElem.Value;
+ var positionElem = result.Document.Descendants(UPnpNamespaces.AvTransport + "GetPositionInfoResponse").Select(i => i.Element("RelTime")).FirstOrDefault(i => i != null);
+ var position = positionElem?.Value;
if (!string.IsNullOrWhiteSpace(position) && !string.Equals(position, "NOT_IMPLEMENTED", StringComparison.OrdinalIgnoreCase))
{
@@ -750,7 +775,7 @@ namespace Emby.Dlna.PlayTo
if (track == null)
{
- //If track is null, some vendors do this, use GetMediaInfo instead
+ // If track is null, some vendors do this, use GetMediaInfo instead
return (true, null);
}
@@ -778,7 +803,7 @@ namespace Emby.Dlna.PlayTo
return (true, null);
}
- var e = uPnpResponse.Element(uPnpNamespaces.items);
+ var e = uPnpResponse.Element(UPnpNamespaces.Items);
var uTrack = CreateUBaseObject(e, trackUri);
@@ -794,7 +819,6 @@ namespace Emby.Dlna.PlayTo
}
catch (XmlException)
{
-
}
// first try to add a root node with a dlna namesapce
@@ -806,43 +830,41 @@ namespace Emby.Dlna.PlayTo
}
catch (XmlException)
{
-
}
// some devices send back invalid xml
try
{
- return XElement.Parse(xml.Replace("&", "&amp;"));
+ return XElement.Parse(xml.Replace("&", "&amp;", StringComparison.Ordinal));
}
catch (XmlException)
{
-
}
return null;
}
- private static uBaseObject CreateUBaseObject(XElement container, string trackUri)
+ private static UBaseObject CreateUBaseObject(XElement container, string trackUri)
{
if (container == null)
{
throw new ArgumentNullException(nameof(container));
}
- var url = container.GetValue(uPnpNamespaces.Res);
+ var url = container.GetValue(UPnpNamespaces.Res);
if (string.IsNullOrWhiteSpace(url))
{
url = trackUri;
}
- return new uBaseObject
+ return new UBaseObject
{
- Id = container.GetAttributeValue(uPnpNamespaces.Id),
- ParentId = container.GetAttributeValue(uPnpNamespaces.ParentId),
- Title = container.GetValue(uPnpNamespaces.title),
- IconUrl = container.GetValue(uPnpNamespaces.Artwork),
- SecondText = "",
+ Id = container.GetAttributeValue(UPnpNamespaces.Id),
+ ParentId = container.GetAttributeValue(UPnpNamespaces.ParentId),
+ Title = container.GetValue(UPnpNamespaces.Title),
+ IconUrl = container.GetValue(UPnpNamespaces.Artwork),
+ SecondText = string.Empty,
Url = url,
ProtocolInfo = GetProtocolInfo(container),
MetaData = container.ToString()
@@ -856,11 +878,11 @@ namespace Emby.Dlna.PlayTo
throw new ArgumentNullException(nameof(container));
}
- var resElement = container.Element(uPnpNamespaces.Res);
+ var resElement = container.Element(UPnpNamespaces.Res);
if (resElement != null)
{
- var info = resElement.Attribute(uPnpNamespaces.ProtocolInfo);
+ var info = resElement.Attribute(UPnpNamespaces.ProtocolInfo);
if (info != null && !string.IsNullOrWhiteSpace(info.Value))
{
@@ -871,10 +893,6 @@ namespace Emby.Dlna.PlayTo
return new string[4];
}
- #endregion
-
- #region From XML
-
private async Task<TransportCommands> GetAVProtocolAsync(CancellationToken cancellationToken)
{
if (AvCommands != null)
@@ -895,7 +913,7 @@ namespace Emby.Dlna.PlayTo
string url = NormalizeUrl(Properties.BaseUrl, avService.ScpdUrl);
- var httpClient = new SsdpHttpClient(_httpClient);
+ var httpClient = new SsdpHttpClient(_httpClientFactory);
var document = await httpClient.GetDataAsync(url, cancellationToken).ConfigureAwait(false);
@@ -923,7 +941,7 @@ namespace Emby.Dlna.PlayTo
string url = NormalizeUrl(Properties.BaseUrl, avService.ScpdUrl);
- var httpClient = new SsdpHttpClient(_httpClient);
+ var httpClient = new SsdpHttpClient(_httpClientFactory);
_logger.LogDebug("Dlna Device.GetRenderingProtocolAsync");
var document = await httpClient.GetDataAsync(url, cancellationToken).ConfigureAwait(false);
@@ -939,12 +957,12 @@ namespace Emby.Dlna.PlayTo
return url;
}
- if (!url.Contains("/"))
+ if (!url.Contains('/', StringComparison.Ordinal))
{
url = "/dmr/" + url;
}
- if (!url.StartsWith("/"))
+ if (!url.StartsWith("/", StringComparison.Ordinal))
{
url = "/" + url;
}
@@ -952,25 +970,21 @@ namespace Emby.Dlna.PlayTo
return baseUrl + url;
}
- private TransportCommands AvCommands { get; set; }
-
- private TransportCommands RendererCommands { get; set; }
-
- public static async Task<Device> CreateuPnpDeviceAsync(Uri url, IHttpClient httpClient, IServerConfigurationManager config, ILogger logger, CancellationToken cancellationToken)
+ public static async Task<Device> CreateuPnpDeviceAsync(Uri url, IHttpClientFactory httpClientFactory, ILogger logger, CancellationToken cancellationToken)
{
- var ssdpHttpClient = new SsdpHttpClient(httpClient);
+ var ssdpHttpClient = new SsdpHttpClient(httpClientFactory);
var document = await ssdpHttpClient.GetDataAsync(url.ToString(), cancellationToken).ConfigureAwait(false);
var friendlyNames = new List<string>();
- var name = document.Descendants(uPnpNamespaces.ud.GetName("friendlyName")).FirstOrDefault();
+ var name = document.Descendants(UPnpNamespaces.Ud.GetName("friendlyName")).FirstOrDefault();
if (name != null && !string.IsNullOrWhiteSpace(name.Value))
{
friendlyNames.Add(name.Value);
}
- var room = document.Descendants(uPnpNamespaces.ud.GetName("roomName")).FirstOrDefault();
+ var room = document.Descendants(UPnpNamespaces.Ud.GetName("roomName")).FirstOrDefault();
if (room != null && !string.IsNullOrWhiteSpace(room.Value))
{
friendlyNames.Add(room.Value);
@@ -979,77 +993,77 @@ namespace Emby.Dlna.PlayTo
var deviceProperties = new DeviceInfo()
{
Name = string.Join(" ", friendlyNames),
- BaseUrl = string.Format("http://{0}:{1}", url.Host, url.Port)
+ BaseUrl = string.Format(CultureInfo.InvariantCulture, "http://{0}:{1}", url.Host, url.Port)
};
- var model = document.Descendants(uPnpNamespaces.ud.GetName("modelName")).FirstOrDefault();
+ var model = document.Descendants(UPnpNamespaces.Ud.GetName("modelName")).FirstOrDefault();
if (model != null)
{
deviceProperties.ModelName = model.Value;
}
- var modelNumber = document.Descendants(uPnpNamespaces.ud.GetName("modelNumber")).FirstOrDefault();
+ var modelNumber = document.Descendants(UPnpNamespaces.Ud.GetName("modelNumber")).FirstOrDefault();
if (modelNumber != null)
{
deviceProperties.ModelNumber = modelNumber.Value;
}
- var uuid = document.Descendants(uPnpNamespaces.ud.GetName("UDN")).FirstOrDefault();
+ var uuid = document.Descendants(UPnpNamespaces.Ud.GetName("UDN")).FirstOrDefault();
if (uuid != null)
{
deviceProperties.UUID = uuid.Value;
}
- var manufacturer = document.Descendants(uPnpNamespaces.ud.GetName("manufacturer")).FirstOrDefault();
+ var manufacturer = document.Descendants(UPnpNamespaces.Ud.GetName("manufacturer")).FirstOrDefault();
if (manufacturer != null)
{
deviceProperties.Manufacturer = manufacturer.Value;
}
- var manufacturerUrl = document.Descendants(uPnpNamespaces.ud.GetName("manufacturerURL")).FirstOrDefault();
+ var manufacturerUrl = document.Descendants(UPnpNamespaces.Ud.GetName("manufacturerURL")).FirstOrDefault();
if (manufacturerUrl != null)
{
deviceProperties.ManufacturerUrl = manufacturerUrl.Value;
}
- var presentationUrl = document.Descendants(uPnpNamespaces.ud.GetName("presentationURL")).FirstOrDefault();
+ var presentationUrl = document.Descendants(UPnpNamespaces.Ud.GetName("presentationURL")).FirstOrDefault();
if (presentationUrl != null)
{
deviceProperties.PresentationUrl = presentationUrl.Value;
}
- var modelUrl = document.Descendants(uPnpNamespaces.ud.GetName("modelURL")).FirstOrDefault();
+ var modelUrl = document.Descendants(UPnpNamespaces.Ud.GetName("modelURL")).FirstOrDefault();
if (modelUrl != null)
{
deviceProperties.ModelUrl = modelUrl.Value;
}
- var serialNumber = document.Descendants(uPnpNamespaces.ud.GetName("serialNumber")).FirstOrDefault();
+ var serialNumber = document.Descendants(UPnpNamespaces.Ud.GetName("serialNumber")).FirstOrDefault();
if (serialNumber != null)
{
deviceProperties.SerialNumber = serialNumber.Value;
}
- var modelDescription = document.Descendants(uPnpNamespaces.ud.GetName("modelDescription")).FirstOrDefault();
+ var modelDescription = document.Descendants(UPnpNamespaces.Ud.GetName("modelDescription")).FirstOrDefault();
if (modelDescription != null)
{
deviceProperties.ModelDescription = modelDescription.Value;
}
- var icon = document.Descendants(uPnpNamespaces.ud.GetName("icon")).FirstOrDefault();
+ var icon = document.Descendants(UPnpNamespaces.Ud.GetName("icon")).FirstOrDefault();
if (icon != null)
{
deviceProperties.Icon = CreateIcon(icon);
}
- foreach (var services in document.Descendants(uPnpNamespaces.ud.GetName("serviceList")))
+ foreach (var services in document.Descendants(UPnpNamespaces.Ud.GetName("serviceList")))
{
if (services == null)
{
continue;
}
- var servicesList = services.Descendants(uPnpNamespaces.ud.GetName("service"));
+ var servicesList = services.Descendants(UPnpNamespaces.Ud.GetName("service"));
if (servicesList == null)
{
continue;
@@ -1066,12 +1080,9 @@ namespace Emby.Dlna.PlayTo
}
}
- return new Device(deviceProperties, httpClient, logger, config);
+ return new Device(deviceProperties, httpClientFactory, logger);
}
- #endregion
-
- private static readonly CultureInfo UsCulture = new CultureInfo("en-US");
private static DeviceIcon CreateIcon(XElement element)
{
if (element == null)
@@ -1079,11 +1090,11 @@ namespace Emby.Dlna.PlayTo
throw new ArgumentNullException(nameof(element));
}
- var mimeType = element.GetDescendantValue(uPnpNamespaces.ud.GetName("mimetype"));
- var width = element.GetDescendantValue(uPnpNamespaces.ud.GetName("width"));
- var height = element.GetDescendantValue(uPnpNamespaces.ud.GetName("height"));
- var depth = element.GetDescendantValue(uPnpNamespaces.ud.GetName("depth"));
- var url = element.GetDescendantValue(uPnpNamespaces.ud.GetName("url"));
+ var mimeType = element.GetDescendantValue(UPnpNamespaces.Ud.GetName("mimetype"));
+ var width = element.GetDescendantValue(UPnpNamespaces.Ud.GetName("width"));
+ var height = element.GetDescendantValue(UPnpNamespaces.Ud.GetName("height"));
+ var depth = element.GetDescendantValue(UPnpNamespaces.Ud.GetName("depth"));
+ var url = element.GetDescendantValue(UPnpNamespaces.Ud.GetName("url"));
var widthValue = int.Parse(width, NumberStyles.Integer, UsCulture);
var heightValue = int.Parse(height, NumberStyles.Integer, UsCulture);
@@ -1100,11 +1111,11 @@ namespace Emby.Dlna.PlayTo
private static DeviceService Create(XElement element)
{
- var type = element.GetDescendantValue(uPnpNamespaces.ud.GetName("serviceType"));
- var id = element.GetDescendantValue(uPnpNamespaces.ud.GetName("serviceId"));
- var scpdUrl = element.GetDescendantValue(uPnpNamespaces.ud.GetName("SCPDURL"));
- var controlURL = element.GetDescendantValue(uPnpNamespaces.ud.GetName("controlURL"));
- var eventSubURL = element.GetDescendantValue(uPnpNamespaces.ud.GetName("eventSubURL"));
+ var type = element.GetDescendantValue(UPnpNamespaces.Ud.GetName("serviceType"));
+ var id = element.GetDescendantValue(UPnpNamespaces.Ud.GetName("serviceId"));
+ var scpdUrl = element.GetDescendantValue(UPnpNamespaces.Ud.GetName("SCPDURL"));
+ var controlURL = element.GetDescendantValue(UPnpNamespaces.Ud.GetName("controlURL"));
+ var eventSubURL = element.GetDescendantValue(UPnpNamespaces.Ud.GetName("eventSubURL"));
return new DeviceService
{
@@ -1116,14 +1127,7 @@ namespace Emby.Dlna.PlayTo
};
}
- public event EventHandler<PlaybackStartEventArgs> PlaybackStart;
- public event EventHandler<PlaybackProgressEventArgs> PlaybackProgress;
- public event EventHandler<PlaybackStoppedEventArgs> PlaybackStopped;
- public event EventHandler<MediaChangedEventArgs> MediaChanged;
-
- public uBaseObject CurrentMediaInfo { get; private set; }
-
- private void UpdateMediaInfo(uBaseObject mediaInfo, TRANSPORTSTATE state)
+ private void UpdateMediaInfo(UBaseObject mediaInfo, TransportState state)
{
TransportState = state;
@@ -1132,7 +1136,7 @@ namespace Emby.Dlna.PlayTo
if (previousMediaInfo == null && mediaInfo != null)
{
- if (state != TRANSPORTSTATE.STOPPED)
+ if (state != TransportState.Stopped)
{
OnPlaybackStart(mediaInfo);
}
@@ -1151,7 +1155,7 @@ namespace Emby.Dlna.PlayTo
}
}
- private void OnPlaybackStart(uBaseObject mediaInfo)
+ private void OnPlaybackStart(UBaseObject mediaInfo)
{
if (string.IsNullOrWhiteSpace(mediaInfo.Url))
{
@@ -1164,7 +1168,7 @@ namespace Emby.Dlna.PlayTo
});
}
- private void OnPlaybackProgress(uBaseObject mediaInfo)
+ private void OnPlaybackProgress(UBaseObject mediaInfo)
{
if (string.IsNullOrWhiteSpace(mediaInfo.Url))
{
@@ -1177,7 +1181,7 @@ namespace Emby.Dlna.PlayTo
});
}
- private void OnPlaybackStop(uBaseObject mediaInfo)
+ private void OnPlaybackStop(UBaseObject mediaInfo)
{
PlaybackStopped?.Invoke(this, new PlaybackStoppedEventArgs
{
@@ -1185,7 +1189,7 @@ namespace Emby.Dlna.PlayTo
});
}
- private void OnMediaChanged(uBaseObject old, uBaseObject newMedia)
+ private void OnMediaChanged(UBaseObject old, UBaseObject newMedia)
{
MediaChanged?.Invoke(this, new MediaChangedEventArgs
{
@@ -1194,16 +1198,17 @@ namespace Emby.Dlna.PlayTo
});
}
- #region IDisposable
-
- bool _disposed;
-
+ /// <inheritdoc />
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
+ /// <summary>
+ /// Releases unmanaged and optionally managed resources.
+ /// </summary>
+ /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
protected virtual void Dispose(bool disposing)
{
if (_disposed)
@@ -1222,11 +1227,10 @@ namespace Emby.Dlna.PlayTo
_disposed = true;
}
- #endregion
-
+ /// <inheritdoc />
public override string ToString()
{
- return string.Format("{0} - {1}", Properties.Name, Properties.BaseUrl);
+ return string.Format(CultureInfo.InvariantCulture, "{0} - {1}", Properties.Name, Properties.BaseUrl);
}
}
}
diff --git a/Emby.Dlna/PlayTo/DeviceInfo.cs b/Emby.Dlna/PlayTo/DeviceInfo.cs
index f3aaaebc4a..d3daab9e0a 100644
--- a/Emby.Dlna/PlayTo/DeviceInfo.cs
+++ b/Emby.Dlna/PlayTo/DeviceInfo.cs
@@ -8,6 +8,9 @@ namespace Emby.Dlna.PlayTo
{
public class DeviceInfo
{
+ private readonly List<DeviceService> _services = new List<DeviceService>();
+ private string _baseUrl = string.Empty;
+
public DeviceInfo()
{
Name = "Generic Device";
@@ -33,7 +36,6 @@ namespace Emby.Dlna.PlayTo
public string PresentationUrl { get; set; }
- private string _baseUrl = string.Empty;
public string BaseUrl
{
get => _baseUrl;
@@ -42,7 +44,6 @@ namespace Emby.Dlna.PlayTo
public DeviceIcon Icon { get; set; }
- private readonly List<DeviceService> _services = new List<DeviceService>();
public List<DeviceService> Services => _services;
public DeviceIdentification ToDeviceIdentification()
diff --git a/Emby.Dlna/PlayTo/MediaChangedEventArgs.cs b/Emby.Dlna/PlayTo/MediaChangedEventArgs.cs
new file mode 100644
index 0000000000..dabd079afd
--- /dev/null
+++ b/Emby.Dlna/PlayTo/MediaChangedEventArgs.cs
@@ -0,0 +1,13 @@
+#pragma warning disable CS1591
+
+using System;
+
+namespace Emby.Dlna.PlayTo
+{
+ public class MediaChangedEventArgs : EventArgs
+ {
+ public UBaseObject OldMediaInfo { get; set; }
+
+ public UBaseObject NewMediaInfo { get; set; }
+ }
+}
diff --git a/Emby.Dlna/PlayTo/PlayToController.cs b/Emby.Dlna/PlayTo/PlayToController.cs
index 9d7c0d3659..a5b8e2b3ce 100644
--- a/Emby.Dlna/PlayTo/PlayToController.cs
+++ b/Emby.Dlna/PlayTo/PlayToController.cs
@@ -7,6 +7,8 @@ using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Emby.Dlna.Didl;
+using Jellyfin.Data.Entities;
+using Jellyfin.Data.Events;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Controller.Dlna;
using MediaBrowser.Controller.Drawing;
@@ -17,11 +19,11 @@ using MediaBrowser.Controller.Session;
using MediaBrowser.Model.Dlna;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Events;
using MediaBrowser.Model.Globalization;
using MediaBrowser.Model.Session;
using Microsoft.AspNetCore.WebUtilities;
using Microsoft.Extensions.Logging;
+using Photo = MediaBrowser.Controller.Entities.Photo;
namespace Emby.Dlna.PlayTo
{
@@ -29,7 +31,6 @@ namespace Emby.Dlna.PlayTo
{
private static readonly CultureInfo _usCulture = CultureInfo.ReadOnly(new CultureInfo("en-US"));
- private Device _device;
private readonly SessionInfo _session;
private readonly ISessionManager _sessionManager;
private readonly ILibraryManager _libraryManager;
@@ -48,6 +49,7 @@ namespace Emby.Dlna.PlayTo
private readonly string _accessToken;
private readonly List<PlaylistItem> _playlist = new List<PlaylistItem>();
+ private Device _device;
private int _currentPlaylistIndex;
private bool _disposed;
@@ -146,11 +148,14 @@ namespace Emby.Dlna.PlayTo
{
var positionTicks = GetProgressPositionTicks(streamInfo);
- ReportPlaybackStopped(streamInfo, positionTicks);
+ await ReportPlaybackStopped(streamInfo, positionTicks).ConfigureAwait(false);
}
streamInfo = StreamParams.ParseFromUrl(e.NewMediaInfo.Url, _libraryManager, _mediaSourceManager);
- if (streamInfo.Item == null) return;
+ if (streamInfo.Item == null)
+ {
+ return;
+ }
var newItemProgress = GetProgressInfo(streamInfo);
@@ -173,11 +178,14 @@ namespace Emby.Dlna.PlayTo
{
var streamInfo = StreamParams.ParseFromUrl(e.MediaInfo.Url, _libraryManager, _mediaSourceManager);
- if (streamInfo.Item == null) return;
+ if (streamInfo.Item == null)
+ {
+ return;
+ }
var positionTicks = GetProgressPositionTicks(streamInfo);
- ReportPlaybackStopped(streamInfo, positionTicks);
+ await ReportPlaybackStopped(streamInfo, positionTicks).ConfigureAwait(false);
var mediaSource = await streamInfo.GetMediaSource(CancellationToken.None).ConfigureAwait(false);
@@ -185,7 +193,7 @@ namespace Emby.Dlna.PlayTo
(_device.Duration == null ? (long?)null : _device.Duration.Value.Ticks) :
mediaSource.RunTimeTicks;
- var playedToCompletion = (positionTicks.HasValue && positionTicks.Value == 0);
+ var playedToCompletion = positionTicks.HasValue && positionTicks.Value == 0;
if (!playedToCompletion && duration.HasValue && positionTicks.HasValue)
{
@@ -210,7 +218,7 @@ namespace Emby.Dlna.PlayTo
}
}
- private async void ReportPlaybackStopped(StreamParams streamInfo, long? positionTicks)
+ private async Task ReportPlaybackStopped(StreamParams streamInfo, long? positionTicks)
{
try
{
@@ -220,7 +228,6 @@ namespace Emby.Dlna.PlayTo
SessionId = _session.Id,
PositionTicks = positionTicks,
MediaSourceId = streamInfo.MediaSourceId
-
}).ConfigureAwait(false);
}
catch (Exception ex)
@@ -365,8 +372,13 @@ namespace Emby.Dlna.PlayTo
if (!command.ControllingUserId.Equals(Guid.Empty))
{
- _sessionManager.LogSessionActivity(_session.Client, _session.ApplicationVersion, _session.DeviceId,
- _session.DeviceName, _session.RemoteEndPoint, user);
+ _sessionManager.LogSessionActivity(
+ _session.Client,
+ _session.ApplicationVersion,
+ _session.DeviceId,
+ _session.DeviceName,
+ _session.RemoteEndPoint,
+ user);
}
return PlayItems(playlist, cancellationToken);
@@ -418,6 +430,7 @@ namespace Emby.Dlna.PlayTo
await _device.SetAvTransport(newItem.StreamUrl, GetDlnaHeaders(newItem), newItem.Didl, CancellationToken.None).ConfigureAwait(false);
return;
}
+
await SeekAfterTransportChange(newPosition, CancellationToken.None).ConfigureAwait(false);
}
}
@@ -441,7 +454,13 @@ namespace Emby.Dlna.PlayTo
}
}
- private PlaylistItem CreatePlaylistItem(BaseItem item, User user, long startPostionTicks, string mediaSourceId, int? audioStreamIndex, int? subtitleStreamIndex)
+ private PlaylistItem CreatePlaylistItem(
+ BaseItem item,
+ User user,
+ long startPostionTicks,
+ string mediaSourceId,
+ int? audioStreamIndex,
+ int? subtitleStreamIndex)
{
var deviceInfo = _device.Properties;
@@ -484,42 +503,44 @@ namespace Emby.Dlna.PlayTo
if (streamInfo.MediaType == DlnaProfileType.Audio)
{
return new ContentFeatureBuilder(profile)
- .BuildAudioHeader(streamInfo.Container,
- streamInfo.TargetAudioCodec.FirstOrDefault(),
- streamInfo.TargetAudioBitrate,
- streamInfo.TargetAudioSampleRate,
- streamInfo.TargetAudioChannels,
- streamInfo.TargetAudioBitDepth,
- streamInfo.IsDirectStream,
- streamInfo.RunTimeTicks ?? 0,
- streamInfo.TranscodeSeekInfo);
+ .BuildAudioHeader(
+ streamInfo.Container,
+ streamInfo.TargetAudioCodec.FirstOrDefault(),
+ streamInfo.TargetAudioBitrate,
+ streamInfo.TargetAudioSampleRate,
+ streamInfo.TargetAudioChannels,
+ streamInfo.TargetAudioBitDepth,
+ streamInfo.IsDirectStream,
+ streamInfo.RunTimeTicks ?? 0,
+ streamInfo.TranscodeSeekInfo);
}
if (streamInfo.MediaType == DlnaProfileType.Video)
{
var list = new ContentFeatureBuilder(profile)
- .BuildVideoHeader(streamInfo.Container,
- streamInfo.TargetVideoCodec.FirstOrDefault(),
- streamInfo.TargetAudioCodec.FirstOrDefault(),
- streamInfo.TargetWidth,
- streamInfo.TargetHeight,
- streamInfo.TargetVideoBitDepth,
- streamInfo.TargetVideoBitrate,
- streamInfo.TargetTimestamp,
- streamInfo.IsDirectStream,
- streamInfo.RunTimeTicks ?? 0,
- streamInfo.TargetVideoProfile,
- streamInfo.TargetVideoLevel,
- streamInfo.TargetFramerate ?? 0,
- streamInfo.TargetPacketLength,
- streamInfo.TranscodeSeekInfo,
- streamInfo.IsTargetAnamorphic,
- streamInfo.IsTargetInterlaced,
- streamInfo.TargetRefFrames,
- streamInfo.TargetVideoStreamCount,
- streamInfo.TargetAudioStreamCount,
- streamInfo.TargetVideoCodecTag,
- streamInfo.IsTargetAVC);
+ .BuildVideoHeader(
+ streamInfo.Container,
+ streamInfo.TargetVideoCodec.FirstOrDefault(),
+ streamInfo.TargetAudioCodec.FirstOrDefault(),
+ streamInfo.TargetWidth,
+ streamInfo.TargetHeight,
+ streamInfo.TargetVideoBitDepth,
+ streamInfo.TargetVideoBitrate,
+ streamInfo.TargetTimestamp,
+ streamInfo.IsDirectStream,
+ streamInfo.RunTimeTicks ?? 0,
+ streamInfo.TargetVideoProfile,
+ streamInfo.TargetVideoLevel,
+ streamInfo.TargetFramerate ?? 0,
+ streamInfo.TargetPacketLength,
+ streamInfo.TranscodeSeekInfo,
+ streamInfo.IsTargetAnamorphic,
+ streamInfo.IsTargetInterlaced,
+ streamInfo.TargetRefFrames,
+ streamInfo.TargetVideoStreamCount,
+ streamInfo.TargetAudioStreamCount,
+ streamInfo.TargetVideoCodecTag,
+ streamInfo.IsTargetAVC);
return list.Count == 0 ? null : list[0];
}
@@ -619,6 +640,10 @@ namespace Emby.Dlna.PlayTo
GC.SuppressFinalize(this);
}
+ /// <summary>
+ /// Releases unmanaged and optionally managed resources.
+ /// </summary>
+ /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
protected virtual void Dispose(bool disposing)
{
if (_disposed)
@@ -644,68 +669,57 @@ namespace Emby.Dlna.PlayTo
private Task SendGeneralCommand(GeneralCommand command, CancellationToken cancellationToken)
{
- if (Enum.TryParse(command.Name, true, out GeneralCommandType commandType))
- {
- switch (commandType)
- {
- case GeneralCommandType.VolumeDown:
- return _device.VolumeDown(cancellationToken);
- case GeneralCommandType.VolumeUp:
- return _device.VolumeUp(cancellationToken);
- case GeneralCommandType.Mute:
- return _device.Mute(cancellationToken);
- case GeneralCommandType.Unmute:
- return _device.Unmute(cancellationToken);
- case GeneralCommandType.ToggleMute:
- return _device.ToggleMute(cancellationToken);
- case GeneralCommandType.SetAudioStreamIndex:
+ switch (command.Name)
+ {
+ case GeneralCommandType.VolumeDown:
+ return _device.VolumeDown(cancellationToken);
+ case GeneralCommandType.VolumeUp:
+ return _device.VolumeUp(cancellationToken);
+ case GeneralCommandType.Mute:
+ return _device.Mute(cancellationToken);
+ case GeneralCommandType.Unmute:
+ return _device.Unmute(cancellationToken);
+ case GeneralCommandType.ToggleMute:
+ return _device.ToggleMute(cancellationToken);
+ case GeneralCommandType.SetAudioStreamIndex:
+ if (command.Arguments.TryGetValue("Index", out string index))
+ {
+ if (int.TryParse(index, NumberStyles.Integer, _usCulture, out var val))
{
- if (command.Arguments.TryGetValue("Index", out string arg))
- {
- if (int.TryParse(arg, NumberStyles.Integer, _usCulture, out var val))
- {
- return SetAudioStreamIndex(val);
- }
+ return SetAudioStreamIndex(val);
+ }
- throw new ArgumentException("Unsupported SetAudioStreamIndex value supplied.");
- }
+ throw new ArgumentException("Unsupported SetAudioStreamIndex value supplied.");
+ }
- throw new ArgumentException("SetAudioStreamIndex argument cannot be null");
- }
- case GeneralCommandType.SetSubtitleStreamIndex:
+ throw new ArgumentException("SetAudioStreamIndex argument cannot be null");
+ case GeneralCommandType.SetSubtitleStreamIndex:
+ if (command.Arguments.TryGetValue("Index", out index))
+ {
+ if (int.TryParse(index, NumberStyles.Integer, _usCulture, out var val))
{
- if (command.Arguments.TryGetValue("Index", out string arg))
- {
- if (int.TryParse(arg, NumberStyles.Integer, _usCulture, out var val))
- {
- return SetSubtitleStreamIndex(val);
- }
+ return SetSubtitleStreamIndex(val);
+ }
- throw new ArgumentException("Unsupported SetSubtitleStreamIndex value supplied.");
- }
+ throw new ArgumentException("Unsupported SetSubtitleStreamIndex value supplied.");
+ }
- throw new ArgumentException("SetSubtitleStreamIndex argument cannot be null");
- }
- case GeneralCommandType.SetVolume:
+ throw new ArgumentException("SetSubtitleStreamIndex argument cannot be null");
+ case GeneralCommandType.SetVolume:
+ if (command.Arguments.TryGetValue("Volume", out string vol))
+ {
+ if (int.TryParse(vol, NumberStyles.Integer, _usCulture, out var volume))
{
- if (command.Arguments.TryGetValue("Volume", out string arg))
- {
- if (int.TryParse(arg, NumberStyles.Integer, _usCulture, out var volume))
- {
- return _device.SetVolume(volume, cancellationToken);
- }
+ return _device.SetVolume(volume, cancellationToken);
+ }
- throw new ArgumentException("Unsupported volume value supplied.");
- }
+ throw new ArgumentException("Unsupported volume value supplied.");
+ }
- throw new ArgumentException("Volume argument cannot be null");
- }
- default:
- return Task.CompletedTask;
- }
+ throw new ArgumentException("Volume argument cannot be null");
+ default:
+ return Task.CompletedTask;
}
-
- return Task.CompletedTask;
}
private async Task SetAudioStreamIndex(int? newIndex)
@@ -763,7 +777,7 @@ namespace Emby.Dlna.PlayTo
const int maxWait = 15000000;
const int interval = 500;
var currentWait = 0;
- while (_device.TransportState != TRANSPORTSTATE.PLAYING && currentWait < maxWait)
+ while (_device.TransportState != TransportState.Playing && currentWait < maxWait)
{
await Task.Delay(interval).ConfigureAwait(false);
currentWait += interval;
@@ -772,8 +786,67 @@ namespace Emby.Dlna.PlayTo
await _device.Seek(TimeSpan.FromTicks(positionTicks), cancellationToken).ConfigureAwait(false);
}
+ private static int? GetIntValue(IReadOnlyDictionary<string, string> values, string name)
+ {
+ var value = values.GetValueOrDefault(name);
+
+ if (int.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result))
+ {
+ return result;
+ }
+
+ return null;
+ }
+
+ private static long GetLongValue(IReadOnlyDictionary<string, string> values, string name)
+ {
+ var value = values.GetValueOrDefault(name);
+
+ if (long.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result))
+ {
+ return result;
+ }
+
+ return 0;
+ }
+
+ /// <inheritdoc />
+ public Task SendMessage<T>(SessionMessageType name, Guid messageId, T data, CancellationToken cancellationToken)
+ {
+ if (_disposed)
+ {
+ throw new ObjectDisposedException(GetType().Name);
+ }
+
+ if (_device == null)
+ {
+ return Task.CompletedTask;
+ }
+
+ if (name == SessionMessageType.Play)
+ {
+ return SendPlayCommand(data as PlayRequest, cancellationToken);
+ }
+
+ if (name == SessionMessageType.PlayState)
+ {
+ return SendPlaystateCommand(data as PlaystateRequest, cancellationToken);
+ }
+
+ if (name == SessionMessageType.GeneralCommand)
+ {
+ return SendGeneralCommand(data as GeneralCommand, cancellationToken);
+ }
+
+ // Not supported or needed right now
+ return Task.CompletedTask;
+ }
+
private class StreamParams
{
+ private MediaSourceInfo mediaSource;
+ private IMediaSourceManager _mediaSourceManager;
+
public Guid ItemId { get; set; }
public bool IsDirectStream { get; set; }
@@ -785,21 +858,20 @@ namespace Emby.Dlna.PlayTo
public int? SubtitleStreamIndex { get; set; }
public string DeviceProfileId { get; set; }
+
public string DeviceId { get; set; }
public string MediaSourceId { get; set; }
+
public string LiveStreamId { get; set; }
public BaseItem Item { get; set; }
- private MediaSourceInfo MediaSource;
-
- private IMediaSourceManager _mediaSourceManager;
public async Task<MediaSourceInfo> GetMediaSource(CancellationToken cancellationToken)
{
- if (MediaSource != null)
+ if (mediaSource != null)
{
- return MediaSource;
+ return mediaSource;
}
var hasMediaSources = Item as IHasMediaSources;
@@ -809,9 +881,12 @@ namespace Emby.Dlna.PlayTo
return null;
}
- MediaSource = await _mediaSourceManager.GetMediaSource(Item, MediaSourceId, LiveStreamId, false, cancellationToken).ConfigureAwait(false);
+ if (_mediaSourceManager != null)
+ {
+ mediaSource = await _mediaSourceManager.GetMediaSource(Item, MediaSourceId, LiveStreamId, false, cancellationToken).ConfigureAwait(false);
+ }
- return MediaSource;
+ return mediaSource;
}
private static Guid GetItemId(string url)
@@ -883,61 +958,5 @@ namespace Emby.Dlna.PlayTo
return request;
}
}
-
- private static int? GetIntValue(IReadOnlyDictionary<string, string> values, string name)
- {
- var value = values.GetValueOrDefault(name);
-
- if (int.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result))
- {
- return result;
- }
-
- return null;
- }
-
- private static long GetLongValue(IReadOnlyDictionary<string, string> values, string name)
- {
- var value = values.GetValueOrDefault(name);
-
- if (long.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result))
- {
- return result;
- }
-
- return 0;
- }
-
- /// <inheritdoc />
- public Task SendMessage<T>(string name, Guid messageId, T data, CancellationToken cancellationToken)
- {
- if (_disposed)
- {
- throw new ObjectDisposedException(GetType().Name);
- }
-
- if (_device == null)
- {
- return Task.CompletedTask;
- }
-
- if (string.Equals(name, "Play", StringComparison.OrdinalIgnoreCase))
- {
- return SendPlayCommand(data as PlayRequest, cancellationToken);
- }
-
- if (string.Equals(name, "PlayState", StringComparison.OrdinalIgnoreCase))
- {
- return SendPlaystateCommand(data as PlaystateRequest, cancellationToken);
- }
-
- if (string.Equals(name, "GeneralCommand", StringComparison.OrdinalIgnoreCase))
- {
- return SendGeneralCommand(data as GeneralCommand, cancellationToken);
- }
-
- // Not supported or needed right now
- return Task.CompletedTask;
- }
}
}
diff --git a/Emby.Dlna/PlayTo/PlayToManager.cs b/Emby.Dlna/PlayTo/PlayToManager.cs
index bbedd1485c..e93aef3043 100644
--- a/Emby.Dlna/PlayTo/PlayToManager.cs
+++ b/Emby.Dlna/PlayTo/PlayToManager.cs
@@ -4,8 +4,10 @@ using System;
using System.Globalization;
using System.Linq;
using System.Net;
+using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
+using Jellyfin.Data.Events;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller;
@@ -16,7 +18,6 @@ using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.Controller.Session;
using MediaBrowser.Model.Dlna;
-using MediaBrowser.Model.Events;
using MediaBrowser.Model.Globalization;
using MediaBrowser.Model.Session;
using Microsoft.Extensions.Logging;
@@ -33,7 +34,7 @@ namespace Emby.Dlna.PlayTo
private readonly IDlnaManager _dlnaManager;
private readonly IServerApplicationHost _appHost;
private readonly IImageProcessor _imageProcessor;
- private readonly IHttpClient _httpClient;
+ private readonly IHttpClientFactory _httpClientFactory;
private readonly IServerConfigurationManager _config;
private readonly IUserDataManager _userDataManager;
private readonly ILocalizationManager _localization;
@@ -46,7 +47,7 @@ namespace Emby.Dlna.PlayTo
private SemaphoreSlim _sessionLock = new SemaphoreSlim(1, 1);
private CancellationTokenSource _disposeCancellationTokenSource = new CancellationTokenSource();
- public PlayToManager(ILogger logger, ISessionManager sessionManager, ILibraryManager libraryManager, IUserManager userManager, IDlnaManager dlnaManager, IServerApplicationHost appHost, IImageProcessor imageProcessor, IDeviceDiscovery deviceDiscovery, IHttpClient httpClient, IServerConfigurationManager config, IUserDataManager userDataManager, ILocalizationManager localization, IMediaSourceManager mediaSourceManager, IMediaEncoder mediaEncoder)
+ public PlayToManager(ILogger logger, ISessionManager sessionManager, ILibraryManager libraryManager, IUserManager userManager, IDlnaManager dlnaManager, IServerApplicationHost appHost, IImageProcessor imageProcessor, IDeviceDiscovery deviceDiscovery, IHttpClientFactory httpClientFactory, IServerConfigurationManager config, IUserDataManager userDataManager, ILocalizationManager localization, IMediaSourceManager mediaSourceManager, IMediaEncoder mediaEncoder)
{
_logger = logger;
_sessionManager = sessionManager;
@@ -56,7 +57,7 @@ namespace Emby.Dlna.PlayTo
_appHost = appHost;
_imageProcessor = imageProcessor;
_deviceDiscovery = deviceDiscovery;
- _httpClient = httpClient;
+ _httpClientFactory = httpClientFactory;
_config = config;
_userDataManager = userDataManager;
_localization = localization;
@@ -78,17 +79,23 @@ namespace Emby.Dlna.PlayTo
var info = e.Argument;
- if (!info.Headers.TryGetValue("USN", out string usn)) usn = string.Empty;
+ if (!info.Headers.TryGetValue("USN", out string usn))
+ {
+ usn = string.Empty;
+ }
- if (!info.Headers.TryGetValue("NT", out string nt)) nt = string.Empty;
+ if (!info.Headers.TryGetValue("NT", out string nt))
+ {
+ nt = string.Empty;
+ }
string location = info.Location.ToString();
// It has to report that it's a media renderer
if (usn.IndexOf("MediaRenderer:", StringComparison.OrdinalIgnoreCase) == -1 &&
- nt.IndexOf("MediaRenderer:", StringComparison.OrdinalIgnoreCase) == -1)
+ nt.IndexOf("MediaRenderer:", StringComparison.OrdinalIgnoreCase) == -1)
{
- //_logger.LogDebug("Upnp device {0} does not contain a MediaRenderer device (0).", location);
+ // _logger.LogDebug("Upnp device {0} does not contain a MediaRenderer device (0).", location);
return;
}
@@ -112,7 +119,6 @@ namespace Emby.Dlna.PlayTo
}
catch (OperationCanceledException)
{
-
}
catch (Exception ex)
{
@@ -124,24 +130,21 @@ namespace Emby.Dlna.PlayTo
}
}
- private string GetUuid(string usn)
+ private static string GetUuid(string usn)
{
- var found = false;
- var index = usn.IndexOf("uuid:", StringComparison.OrdinalIgnoreCase);
- if (index != -1)
- {
- usn = usn.Substring(index);
- found = true;
- }
- index = usn.IndexOf("::", StringComparison.OrdinalIgnoreCase);
+ const string UuidStr = "uuid:";
+ const string UuidColonStr = "::";
+
+ var index = usn.IndexOf(UuidStr, StringComparison.OrdinalIgnoreCase);
if (index != -1)
{
- usn = usn.Substring(0, index);
+ return usn.Substring(index + UuidStr.Length);
}
- if (found)
+ index = usn.IndexOf(UuidColonStr, StringComparison.OrdinalIgnoreCase);
+ if (index != -1)
{
- return usn;
+ usn = usn.Substring(0, index + UuidColonStr.Length);
}
return usn.GetMD5().ToString("N", CultureInfo.InvariantCulture);
@@ -168,7 +171,7 @@ namespace Emby.Dlna.PlayTo
if (controller == null)
{
- var device = await Device.CreateuPnpDeviceAsync(uri, _httpClient, _config, _logger, cancellationToken).ConfigureAwait(false);
+ var device = await Device.CreateuPnpDeviceAsync(uri, _httpClientFactory, _logger, cancellationToken).ConfigureAwait(false);
string deviceName = device.Properties.Name;
@@ -184,21 +187,22 @@ namespace Emby.Dlna.PlayTo
serverAddress = _appHost.GetLocalApiUrl(info.LocalIpAddress);
}
- controller = new PlayToController(sessionInfo,
- _sessionManager,
- _libraryManager,
- _logger,
- _dlnaManager,
- _userManager,
- _imageProcessor,
- serverAddress,
- null,
- _deviceDiscovery,
- _userDataManager,
- _localization,
- _mediaSourceManager,
- _config,
- _mediaEncoder);
+ controller = new PlayToController(
+ sessionInfo,
+ _sessionManager,
+ _libraryManager,
+ _logger,
+ _dlnaManager,
+ _userManager,
+ _imageProcessor,
+ serverAddress,
+ null,
+ _deviceDiscovery,
+ _userDataManager,
+ _localization,
+ _mediaSourceManager,
+ _config,
+ _mediaEncoder);
sessionInfo.AddController(controller);
@@ -211,17 +215,17 @@ namespace Emby.Dlna.PlayTo
{
PlayableMediaTypes = profile.GetSupportedMediaTypes(),
- SupportedCommands = new string[]
+ SupportedCommands = new[]
{
- GeneralCommandType.VolumeDown.ToString(),
- GeneralCommandType.VolumeUp.ToString(),
- GeneralCommandType.Mute.ToString(),
- GeneralCommandType.Unmute.ToString(),
- GeneralCommandType.ToggleMute.ToString(),
- GeneralCommandType.SetVolume.ToString(),
- GeneralCommandType.SetAudioStreamIndex.ToString(),
- GeneralCommandType.SetSubtitleStreamIndex.ToString(),
- GeneralCommandType.PlayMediaSource.ToString()
+ GeneralCommandType.VolumeDown,
+ GeneralCommandType.VolumeUp,
+ GeneralCommandType.Mute,
+ GeneralCommandType.Unmute,
+ GeneralCommandType.ToggleMute,
+ GeneralCommandType.SetVolume,
+ GeneralCommandType.SetAudioStreamIndex,
+ GeneralCommandType.SetSubtitleStreamIndex,
+ GeneralCommandType.PlayMediaSource
},
SupportsMediaControl = true
@@ -240,9 +244,9 @@ namespace Emby.Dlna.PlayTo
{
_disposeCancellationTokenSource.Cancel();
}
- catch
+ catch (Exception ex)
{
-
+ _logger.LogDebug(ex, "Error while disposing PlayToManager");
}
_sessionLock.Dispose();
diff --git a/Emby.Dlna/PlayTo/PlaybackProgressEventArgs.cs b/Emby.Dlna/PlayTo/PlaybackProgressEventArgs.cs
index 795618df23..d14617c8a0 100644
--- a/Emby.Dlna/PlayTo/PlaybackProgressEventArgs.cs
+++ b/Emby.Dlna/PlayTo/PlaybackProgressEventArgs.cs
@@ -6,6 +6,6 @@ namespace Emby.Dlna.PlayTo
{
public class PlaybackProgressEventArgs : EventArgs
{
- public uBaseObject MediaInfo { get; set; }
+ public UBaseObject MediaInfo { get; set; }
}
}
diff --git a/Emby.Dlna/PlayTo/PlaybackStartEventArgs.cs b/Emby.Dlna/PlayTo/PlaybackStartEventArgs.cs
index 27883ca32a..3f8d552636 100644
--- a/Emby.Dlna/PlayTo/PlaybackStartEventArgs.cs
+++ b/Emby.Dlna/PlayTo/PlaybackStartEventArgs.cs
@@ -6,6 +6,6 @@ namespace Emby.Dlna.PlayTo
{
public class PlaybackStartEventArgs : EventArgs
{
- public uBaseObject MediaInfo { get; set; }
+ public UBaseObject MediaInfo { get; set; }
}
}
diff --git a/Emby.Dlna/PlayTo/PlaybackStoppedEventArgs.cs b/Emby.Dlna/PlayTo/PlaybackStoppedEventArgs.cs
index 3b169e5993..deeb47918d 100644
--- a/Emby.Dlna/PlayTo/PlaybackStoppedEventArgs.cs
+++ b/Emby.Dlna/PlayTo/PlaybackStoppedEventArgs.cs
@@ -6,12 +6,6 @@ namespace Emby.Dlna.PlayTo
{
public class PlaybackStoppedEventArgs : EventArgs
{
- public uBaseObject MediaInfo { get; set; }
- }
-
- public class MediaChangedEventArgs : EventArgs
- {
- public uBaseObject OldMediaInfo { get; set; }
- public uBaseObject NewMediaInfo { get; set; }
+ public UBaseObject MediaInfo { get; set; }
}
}
diff --git a/Emby.Dlna/PlayTo/SsdpHttpClient.cs b/Emby.Dlna/PlayTo/SsdpHttpClient.cs
index 8c13620075..c8c36fc972 100644
--- a/Emby.Dlna/PlayTo/SsdpHttpClient.cs
+++ b/Emby.Dlna/PlayTo/SsdpHttpClient.cs
@@ -4,6 +4,8 @@ using System;
using System.Globalization;
using System.IO;
using System.Net.Http;
+using System.Net.Http.Headers;
+using System.Net.Mime;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
@@ -20,11 +22,11 @@ namespace Emby.Dlna.PlayTo
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
- private readonly IHttpClient _httpClient;
+ private readonly IHttpClientFactory _httpClientFactory;
- public SsdpHttpClient(IHttpClient httpClient)
+ public SsdpHttpClient(IHttpClientFactory httpClientFactory)
{
- _httpClient = httpClient;
+ _httpClientFactory = httpClientFactory;
}
public async Task<XDocument> SendCommandAsync(
@@ -36,20 +38,18 @@ namespace Emby.Dlna.PlayTo
CancellationToken cancellationToken = default)
{
var url = NormalizeServiceUrl(baseUrl, service.ControlUrl);
- using (var response = await PostSoapDataAsync(
- url,
- $"\"{service.ServiceType}#{command}\"",
- postData,
- header,
- cancellationToken)
- .ConfigureAwait(false))
- using (var stream = response.Content)
- using (var reader = new StreamReader(stream, Encoding.UTF8))
- {
- return XDocument.Parse(
- await reader.ReadToEndAsync().ConfigureAwait(false),
- LoadOptions.PreserveWhitespace);
- }
+ using var response = await PostSoapDataAsync(
+ url,
+ $"\"{service.ServiceType}#{command}\"",
+ postData,
+ header,
+ cancellationToken)
+ .ConfigureAwait(false);
+ await using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false);
+ using var reader = new StreamReader(stream, Encoding.UTF8);
+ return XDocument.Parse(
+ await reader.ReadToEndAsync().ConfigureAwait(false),
+ LoadOptions.PreserveWhitespace);
}
private static string NormalizeServiceUrl(string baseUrl, string serviceUrl)
@@ -76,50 +76,32 @@ namespace Emby.Dlna.PlayTo
int eventport,
int timeOut = 3600)
{
- var options = new HttpRequestOptions
- {
- Url = url,
- UserAgent = USERAGENT,
- LogErrorResponseBody = true,
- BufferContent = false,
- };
-
- options.RequestHeaders["HOST"] = ip + ":" + port.ToString(_usCulture);
- options.RequestHeaders["CALLBACK"] = "<" + localIp + ":" + eventport.ToString(_usCulture) + ">";
- options.RequestHeaders["NT"] = "upnp:event";
- options.RequestHeaders["TIMEOUT"] = "Second-" + timeOut.ToString(_usCulture);
-
- using (await _httpClient.SendAsync(options, new HttpMethod("SUBSCRIBE")).ConfigureAwait(false))
- {
-
- }
+ using var options = new HttpRequestMessage(new HttpMethod("SUBSCRIBE"), url);
+ options.Headers.UserAgent.ParseAdd(USERAGENT);
+ options.Headers.TryAddWithoutValidation("HOST", ip + ":" + port.ToString(_usCulture));
+ options.Headers.TryAddWithoutValidation("CALLBACK", "<" + localIp + ":" + eventport.ToString(_usCulture) + ">");
+ options.Headers.TryAddWithoutValidation("NT", "upnp:event");
+ options.Headers.TryAddWithoutValidation("TIMEOUT", "Second-" + timeOut.ToString(_usCulture));
+
+ using var response = await _httpClientFactory.CreateClient(NamedClient.Default)
+ .SendAsync(options, HttpCompletionOption.ResponseHeadersRead)
+ .ConfigureAwait(false);
}
public async Task<XDocument> GetDataAsync(string url, CancellationToken cancellationToken)
{
- var options = new HttpRequestOptions
- {
- Url = url,
- UserAgent = USERAGENT,
- LogErrorResponseBody = true,
- BufferContent = false,
-
- CancellationToken = cancellationToken
- };
-
- options.RequestHeaders["FriendlyName.DLNA.ORG"] = FriendlyName;
-
- using (var response = await _httpClient.SendAsync(options, HttpMethod.Get).ConfigureAwait(false))
- using (var stream = response.Content)
- using (var reader = new StreamReader(stream, Encoding.UTF8))
- {
- return XDocument.Parse(
- await reader.ReadToEndAsync().ConfigureAwait(false),
- LoadOptions.PreserveWhitespace);
- }
+ using var options = new HttpRequestMessage(HttpMethod.Get, url);
+ options.Headers.UserAgent.ParseAdd(USERAGENT);
+ options.Headers.TryAddWithoutValidation("FriendlyName.DLNA.ORG", FriendlyName);
+ using var response = await _httpClientFactory.CreateClient(NamedClient.Default).SendAsync(options, HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false);
+ await using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false);
+ using var reader = new StreamReader(stream, Encoding.UTF8);
+ return XDocument.Parse(
+ await reader.ReadToEndAsync().ConfigureAwait(false),
+ LoadOptions.PreserveWhitespace);
}
- private Task<HttpResponseInfo> PostSoapDataAsync(
+ private async Task<HttpResponseMessage> PostSoapDataAsync(
string url,
string soapAction,
string postData,
@@ -131,29 +113,20 @@ namespace Emby.Dlna.PlayTo
soapAction = $"\"{soapAction}\"";
}
- var options = new HttpRequestOptions
- {
- Url = url,
- UserAgent = USERAGENT,
- LogErrorResponseBody = true,
- BufferContent = false,
-
- CancellationToken = cancellationToken
- };
-
- options.RequestHeaders["SOAPAction"] = soapAction;
- options.RequestHeaders["Pragma"] = "no-cache";
- options.RequestHeaders["FriendlyName.DLNA.ORG"] = FriendlyName;
+ using var options = new HttpRequestMessage(HttpMethod.Post, url);
+ options.Headers.UserAgent.ParseAdd(USERAGENT);
+ options.Headers.TryAddWithoutValidation("SOAPACTION", soapAction);
+ options.Headers.TryAddWithoutValidation("Pragma", "no-cache");
+ options.Headers.TryAddWithoutValidation("FriendlyName.DLNA.ORG", FriendlyName);
if (!string.IsNullOrEmpty(header))
{
- options.RequestHeaders["contentFeatures.dlna.org"] = header;
+ options.Headers.TryAddWithoutValidation("contentFeatures.dlna.org", header);
}
- options.RequestContentType = "text/xml";
- options.RequestContent = postData;
+ options.Content = new StringContent(postData, Encoding.UTF8, MediaTypeNames.Text.Xml);
- return _httpClient.Post(options);
+ return await _httpClientFactory.CreateClient(NamedClient.Default).SendAsync(options, HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false);
}
}
}
diff --git a/Emby.Dlna/PlayTo/TRANSPORTSTATE.cs b/Emby.Dlna/PlayTo/TRANSPORTSTATE.cs
deleted file mode 100644
index 7daefeca86..0000000000
--- a/Emby.Dlna/PlayTo/TRANSPORTSTATE.cs
+++ /dev/null
@@ -1,13 +0,0 @@
-#pragma warning disable CS1591
-
-namespace Emby.Dlna.PlayTo
-{
- public enum TRANSPORTSTATE
- {
- STOPPED,
- PLAYING,
- TRANSITIONING,
- PAUSED_PLAYBACK,
- PAUSED
- }
-}
diff --git a/Emby.Dlna/PlayTo/TransportCommands.cs b/Emby.Dlna/PlayTo/TransportCommands.cs
index c0ce3ab6e9..fda17a8b41 100644
--- a/Emby.Dlna/PlayTo/TransportCommands.cs
+++ b/Emby.Dlna/PlayTo/TransportCommands.cs
@@ -2,6 +2,7 @@
using System;
using System.Collections.Generic;
+using System.Globalization;
using System.Linq;
using System.Xml.Linq;
using Emby.Dlna.Common;
@@ -11,36 +12,30 @@ namespace Emby.Dlna.PlayTo
{
public class TransportCommands
{
+ private const string CommandBase = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n" + "<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\" SOAP-ENV:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">" + "<SOAP-ENV:Body>" + "<m:{0} xmlns:m=\"{1}\">" + "{2}" + "</m:{0}>" + "</SOAP-ENV:Body></SOAP-ENV:Envelope>";
private List<StateVariable> _stateVariables = new List<StateVariable>();
- public List<StateVariable> StateVariables
- {
- get => _stateVariables;
- set => _stateVariables = value;
- }
-
private List<ServiceAction> _serviceActions = new List<ServiceAction>();
- public List<ServiceAction> ServiceActions
- {
- get => _serviceActions;
- set => _serviceActions = value;
- }
+
+ public List<StateVariable> StateVariables => _stateVariables;
+
+ public List<ServiceAction> ServiceActions => _serviceActions;
public static TransportCommands Create(XDocument document)
{
var command = new TransportCommands();
- var actionList = document.Descendants(uPnpNamespaces.svc + "actionList");
+ var actionList = document.Descendants(UPnpNamespaces.Svc + "actionList");
- foreach (var container in actionList.Descendants(uPnpNamespaces.svc + "action"))
+ foreach (var container in actionList.Descendants(UPnpNamespaces.Svc + "action"))
{
command.ServiceActions.Add(ServiceActionFromXml(container));
}
- var stateValues = document.Descendants(uPnpNamespaces.ServiceStateTable).FirstOrDefault();
+ var stateValues = document.Descendants(UPnpNamespaces.ServiceStateTable).FirstOrDefault();
if (stateValues != null)
{
- foreach (var container in stateValues.Elements(uPnpNamespaces.svc + "stateVariable"))
+ foreach (var container in stateValues.Elements(UPnpNamespaces.Svc + "stateVariable"))
{
command.StateVariables.Add(FromXml(container));
}
@@ -51,19 +46,19 @@ namespace Emby.Dlna.PlayTo
private static ServiceAction ServiceActionFromXml(XElement container)
{
- var argumentList = new List<Argument>();
+ var serviceAction = new ServiceAction
+ {
+ Name = container.GetValue(UPnpNamespaces.Svc + "name"),
+ };
- foreach (var arg in container.Descendants(uPnpNamespaces.svc + "argument"))
+ var argumentList = serviceAction.ArgumentList;
+
+ foreach (var arg in container.Descendants(UPnpNamespaces.Svc + "argument"))
{
argumentList.Add(ArgumentFromXml(arg));
}
- return new ServiceAction
- {
- Name = container.GetValue(uPnpNamespaces.svc + "name"),
-
- ArgumentList = argumentList
- };
+ return serviceAction;
}
private static Argument ArgumentFromXml(XElement container)
@@ -75,29 +70,29 @@ namespace Emby.Dlna.PlayTo
return new Argument
{
- Name = container.GetValue(uPnpNamespaces.svc + "name"),
- Direction = container.GetValue(uPnpNamespaces.svc + "direction"),
- RelatedStateVariable = container.GetValue(uPnpNamespaces.svc + "relatedStateVariable")
+ Name = container.GetValue(UPnpNamespaces.Svc + "name"),
+ Direction = container.GetValue(UPnpNamespaces.Svc + "direction"),
+ RelatedStateVariable = container.GetValue(UPnpNamespaces.Svc + "relatedStateVariable")
};
}
private static StateVariable FromXml(XElement container)
{
var allowedValues = new List<string>();
- var element = container.Descendants(uPnpNamespaces.svc + "allowedValueList")
+ var element = container.Descendants(UPnpNamespaces.Svc + "allowedValueList")
.FirstOrDefault();
if (element != null)
{
- var values = element.Descendants(uPnpNamespaces.svc + "allowedValue");
+ var values = element.Descendants(UPnpNamespaces.Svc + "allowedValue");
allowedValues.AddRange(values.Select(child => child.Value));
}
return new StateVariable
{
- Name = container.GetValue(uPnpNamespaces.svc + "name"),
- DataType = container.GetValue(uPnpNamespaces.svc + "dataType"),
+ Name = container.GetValue(UPnpNamespaces.Svc + "name"),
+ DataType = container.GetValue(UPnpNamespaces.Svc + "dataType"),
AllowedValues = allowedValues.ToArray()
};
}
@@ -123,7 +118,7 @@ namespace Emby.Dlna.PlayTo
}
}
- return string.Format(CommandBase, action.Name, xmlNamespace, stateString);
+ return string.Format(CultureInfo.InvariantCulture, CommandBase, action.Name, xmlNamespace, stateString);
}
public string BuildPost(ServiceAction action, string xmlNamesapce, object value, string commandParameter = "")
@@ -147,7 +142,7 @@ namespace Emby.Dlna.PlayTo
}
}
- return string.Format(CommandBase, action.Name, xmlNamesapce, stateString);
+ return string.Format(CultureInfo.InvariantCulture, CommandBase, action.Name, xmlNamesapce, stateString);
}
public string BuildPost(ServiceAction action, string xmlNamesapce, object value, Dictionary<string, string> dictionary)
@@ -170,7 +165,7 @@ namespace Emby.Dlna.PlayTo
}
}
- return string.Format(CommandBase, action.Name, xmlNamesapce, stateString);
+ return string.Format(CultureInfo.InvariantCulture, CommandBase, action.Name, xmlNamesapce, stateString);
}
private string BuildArgumentXml(Argument argument, string value, string commandParameter = "")
@@ -180,15 +175,12 @@ namespace Emby.Dlna.PlayTo
if (state != null)
{
var sendValue = state.AllowedValues.FirstOrDefault(a => string.Equals(a, commandParameter, StringComparison.OrdinalIgnoreCase)) ??
- state.AllowedValues.FirstOrDefault() ??
- value;
+ (state.AllowedValues.Count > 0 ? state.AllowedValues[0] : value);
- return string.Format("<{0} xmlns:dt=\"urn:schemas-microsoft-com:datatypes\" dt:dt=\"{1}\">{2}</{0}>", argument.Name, state.DataType ?? "string", sendValue);
+ return string.Format(CultureInfo.InvariantCulture, "<{0} xmlns:dt=\"urn:schemas-microsoft-com:datatypes\" dt:dt=\"{1}\">{2}</{0}>", argument.Name, state.DataType ?? "string", sendValue);
}
- return string.Format("<{0}>{1}</{0}>", argument.Name, value);
+ return string.Format(CultureInfo.InvariantCulture, "<{0}>{1}</{0}>", argument.Name, value);
}
-
- private const string CommandBase = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n" + "<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\" SOAP-ENV:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">" + "<SOAP-ENV:Body>" + "<m:{0} xmlns:m=\"{1}\">" + "{2}" + "</m:{0}>" + "</SOAP-ENV:Body></SOAP-ENV:Envelope>";
}
}
diff --git a/Emby.Dlna/PlayTo/TransportState.cs b/Emby.Dlna/PlayTo/TransportState.cs
new file mode 100644
index 0000000000..7068a5d24d
--- /dev/null
+++ b/Emby.Dlna/PlayTo/TransportState.cs
@@ -0,0 +1,14 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1602
+
+namespace Emby.Dlna.PlayTo
+{
+ public enum TransportState
+ {
+ Stopped,
+ Playing,
+ Transitioning,
+ PausedPlayback,
+ Paused
+ }
+}
diff --git a/Emby.Dlna/PlayTo/UpnpContainer.cs b/Emby.Dlna/PlayTo/UpnpContainer.cs
index e2d7a10f02..05f27603fb 100644
--- a/Emby.Dlna/PlayTo/UpnpContainer.cs
+++ b/Emby.Dlna/PlayTo/UpnpContainer.cs
@@ -6,22 +6,22 @@ using Emby.Dlna.Ssdp;
namespace Emby.Dlna.PlayTo
{
- public class UpnpContainer : uBaseObject
+ public class UpnpContainer : UBaseObject
{
- public static uBaseObject Create(XElement container)
+ public static UBaseObject Create(XElement container)
{
if (container == null)
{
throw new ArgumentNullException(nameof(container));
}
- return new uBaseObject
+ return new UBaseObject
{
- Id = container.GetAttributeValue(uPnpNamespaces.Id),
- ParentId = container.GetAttributeValue(uPnpNamespaces.ParentId),
- Title = container.GetValue(uPnpNamespaces.title),
- IconUrl = container.GetValue(uPnpNamespaces.Artwork),
- UpnpClass = container.GetValue(uPnpNamespaces.uClass)
+ Id = container.GetAttributeValue(UPnpNamespaces.Id),
+ ParentId = container.GetAttributeValue(UPnpNamespaces.ParentId),
+ Title = container.GetValue(UPnpNamespaces.Title),
+ IconUrl = container.GetValue(UPnpNamespaces.Artwork),
+ UpnpClass = container.GetValue(UPnpNamespaces.Class)
};
}
}
diff --git a/Emby.Dlna/PlayTo/uBaseObject.cs b/Emby.Dlna/PlayTo/uBaseObject.cs
index a8ed5692c9..0d9478e42e 100644
--- a/Emby.Dlna/PlayTo/uBaseObject.cs
+++ b/Emby.Dlna/PlayTo/uBaseObject.cs
@@ -1,10 +1,11 @@
#pragma warning disable CS1591
using System;
+using System.Collections.Generic;
namespace Emby.Dlna.PlayTo
{
- public class uBaseObject
+ public class UBaseObject
{
public string Id { get; set; }
@@ -20,20 +21,10 @@ namespace Emby.Dlna.PlayTo
public string Url { get; set; }
- public string[] ProtocolInfo { get; set; }
+ public IReadOnlyList<string> ProtocolInfo { get; set; }
public string UpnpClass { get; set; }
- public bool Equals(uBaseObject obj)
- {
- if (obj == null)
- {
- throw new ArgumentNullException(nameof(obj));
- }
-
- return string.Equals(Id, obj.Id);
- }
-
public string MediaType
{
get
@@ -44,10 +35,12 @@ namespace Emby.Dlna.PlayTo
{
return MediaBrowser.Model.Entities.MediaType.Audio;
}
+
if (classType.IndexOf(MediaBrowser.Model.Entities.MediaType.Video, StringComparison.Ordinal) != -1)
{
return MediaBrowser.Model.Entities.MediaType.Video;
}
+
if (classType.IndexOf("image", StringComparison.Ordinal) != -1)
{
return MediaBrowser.Model.Entities.MediaType.Photo;
@@ -56,5 +49,15 @@ namespace Emby.Dlna.PlayTo
return null;
}
}
+
+ public bool Equals(UBaseObject obj)
+ {
+ if (obj == null)
+ {
+ throw new ArgumentNullException(nameof(obj));
+ }
+
+ return string.Equals(Id, obj.Id, StringComparison.Ordinal);
+ }
}
}
diff --git a/Emby.Dlna/PlayTo/uPnpNamespaces.cs b/Emby.Dlna/PlayTo/uPnpNamespaces.cs
index dc65cdf43c..5042d44938 100644
--- a/Emby.Dlna/PlayTo/uPnpNamespaces.cs
+++ b/Emby.Dlna/PlayTo/uPnpNamespaces.cs
@@ -4,38 +4,64 @@ using System.Xml.Linq;
namespace Emby.Dlna.PlayTo
{
- public class uPnpNamespaces
+ public static class UPnpNamespaces
{
- public static XNamespace dc = "http://purl.org/dc/elements/1.1/";
- public static XNamespace ns = "urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/";
- public static XNamespace svc = "urn:schemas-upnp-org:service-1-0";
- public static XNamespace ud = "urn:schemas-upnp-org:device-1-0";
- public static XNamespace upnp = "urn:schemas-upnp-org:metadata-1-0/upnp/";
- public static XNamespace RenderingControl = "urn:schemas-upnp-org:service:RenderingControl:1";
- public static XNamespace AvTransport = "urn:schemas-upnp-org:service:AVTransport:1";
- public static XNamespace ContentDirectory = "urn:schemas-upnp-org:service:ContentDirectory:1";
-
- public static XName containers = ns + "container";
- public static XName items = ns + "item";
- public static XName title = dc + "title";
- public static XName creator = dc + "creator";
- public static XName artist = upnp + "artist";
- public static XName Id = "id";
- public static XName ParentId = "parentID";
- public static XName uClass = upnp + "class";
- public static XName Artwork = upnp + "albumArtURI";
- public static XName Description = dc + "description";
- public static XName LongDescription = upnp + "longDescription";
- public static XName Album = upnp + "album";
- public static XName Author = upnp + "author";
- public static XName Director = upnp + "director";
- public static XName PlayCount = upnp + "playbackCount";
- public static XName Tracknumber = upnp + "originalTrackNumber";
- public static XName Res = ns + "res";
- public static XName Duration = "duration";
- public static XName ProtocolInfo = "protocolInfo";
-
- public static XName ServiceStateTable = svc + "serviceStateTable";
- public static XName StateVariable = svc + "stateVariable";
+ public static XNamespace Dc { get; } = "http://purl.org/dc/elements/1.1/";
+
+ public static XNamespace Ns { get; } = "urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/";
+
+ public static XNamespace Svc { get; } = "urn:schemas-upnp-org:service-1-0";
+
+ public static XNamespace Ud { get; } = "urn:schemas-upnp-org:device-1-0";
+
+ public static XNamespace UPnp { get; } = "urn:schemas-upnp-org:metadata-1-0/upnp/";
+
+ public static XNamespace RenderingControl { get; } = "urn:schemas-upnp-org:service:RenderingControl:1";
+
+ public static XNamespace AvTransport { get; } = "urn:schemas-upnp-org:service:AVTransport:1";
+
+ public static XNamespace ContentDirectory { get; } = "urn:schemas-upnp-org:service:ContentDirectory:1";
+
+ public static XName Containers { get; } = Ns + "container";
+
+ public static XName Items { get; } = Ns + "item";
+
+ public static XName Title { get; } = Dc + "title";
+
+ public static XName Creator { get; } = Dc + "creator";
+
+ public static XName Artist { get; } = UPnp + "artist";
+
+ public static XName Id { get; } = "id";
+
+ public static XName ParentId { get; } = "parentID";
+
+ public static XName Class { get; } = UPnp + "class";
+
+ public static XName Artwork { get; } = UPnp + "albumArtURI";
+
+ public static XName Description { get; } = Dc + "description";
+
+ public static XName LongDescription { get; } = UPnp + "longDescription";
+
+ public static XName Album { get; } = UPnp + "album";
+
+ public static XName Author { get; } = UPnp + "author";
+
+ public static XName Director { get; } = UPnp + "director";
+
+ public static XName PlayCount { get; } = UPnp + "playbackCount";
+
+ public static XName Tracknumber { get; } = UPnp + "originalTrackNumber";
+
+ public static XName Res { get; } = Ns + "res";
+
+ public static XName Duration { get; } = "duration";
+
+ public static XName ProtocolInfo { get; } = "protocolInfo";
+
+ public static XName ServiceStateTable { get; } = Svc + "serviceStateTable";
+
+ public static XName StateVariable { get; } = Svc + "stateVariable";
}
}
diff --git a/Emby.Dlna/Profiles/DefaultProfile.cs b/Emby.Dlna/Profiles/DefaultProfile.cs
index 2347ebd0d3..d4af72b626 100644
--- a/Emby.Dlna/Profiles/DefaultProfile.cs
+++ b/Emby.Dlna/Profiles/DefaultProfile.cs
@@ -64,14 +64,14 @@ namespace Emby.Dlna.Profiles
new DirectPlayProfile
{
// play all
- Container = "",
+ Container = string.Empty,
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
// play all
- Container = "",
+ Container = string.Empty,
Type = DlnaProfileType.Audio
}
};
@@ -164,7 +164,7 @@ namespace Emby.Dlna.Profiles
public void AddXmlRootAttribute(string name, string value)
{
- var atts = XmlRootAttributes ?? new XmlAttribute[] { };
+ var atts = XmlRootAttributes ?? System.Array.Empty<XmlAttribute>();
var list = atts.ToList();
list.Add(new XmlAttribute
diff --git a/Emby.Dlna/Profiles/DenonAvrProfile.cs b/Emby.Dlna/Profiles/DenonAvrProfile.cs
index 73a87c499e..a5ba0f36cc 100644
--- a/Emby.Dlna/Profiles/DenonAvrProfile.cs
+++ b/Emby.Dlna/Profiles/DenonAvrProfile.cs
@@ -28,7 +28,7 @@ namespace Emby.Dlna.Profiles
},
};
- ResponseProfiles = new ResponseProfile[] { };
+ ResponseProfiles = System.Array.Empty<ResponseProfile>();
}
}
}
diff --git a/Emby.Dlna/Profiles/DirectTvProfile.cs b/Emby.Dlna/Profiles/DirectTvProfile.cs
index 5ca388167b..f6f98b07d8 100644
--- a/Emby.Dlna/Profiles/DirectTvProfile.cs
+++ b/Emby.Dlna/Profiles/DirectTvProfile.cs
@@ -123,7 +123,7 @@ namespace Emby.Dlna.Profiles
}
};
- ResponseProfiles = new ResponseProfile[] { };
+ ResponseProfiles = System.Array.Empty<ResponseProfile>();
}
}
}
diff --git a/Emby.Dlna/Profiles/DishHopperJoeyProfile.cs b/Emby.Dlna/Profiles/DishHopperJoeyProfile.cs
index 942e369309..2a7524a6a2 100644
--- a/Emby.Dlna/Profiles/DishHopperJoeyProfile.cs
+++ b/Emby.Dlna/Profiles/DishHopperJoeyProfile.cs
@@ -24,7 +24,7 @@ namespace Emby.Dlna.Profiles
{
Match = HeaderMatchType.Substring,
Name = "User-Agent",
- Value ="Zip_"
+ Value = "Zip_"
}
}
};
@@ -81,7 +81,7 @@ namespace Emby.Dlna.Profiles
{
Type = CodecType.Video,
Codec = "h264",
- Conditions = new []
+ Conditions = new[]
{
new ProfileCondition
{
@@ -124,7 +124,7 @@ namespace Emby.Dlna.Profiles
new CodecProfile
{
Type = CodecType.Video,
- Conditions = new []
+ Conditions = new[]
{
new ProfileCondition
{
@@ -161,7 +161,7 @@ namespace Emby.Dlna.Profiles
{
Type = CodecType.VideoAudio,
Codec = "ac3,he-aac",
- Conditions = new []
+ Conditions = new[]
{
new ProfileCondition
{
@@ -177,7 +177,7 @@ namespace Emby.Dlna.Profiles
{
Type = CodecType.VideoAudio,
Codec = "aac",
- Conditions = new []
+ Conditions = new[]
{
new ProfileCondition
{
@@ -192,7 +192,7 @@ namespace Emby.Dlna.Profiles
new CodecProfile
{
Type = CodecType.VideoAudio,
- Conditions = new []
+ Conditions = new[]
{
// The device does not have any audio switching capabilities
new ProfileCondition
diff --git a/Emby.Dlna/Profiles/Foobar2000Profile.cs b/Emby.Dlna/Profiles/Foobar2000Profile.cs
index ea3de686a6..68e959770a 100644
--- a/Emby.Dlna/Profiles/Foobar2000Profile.cs
+++ b/Emby.Dlna/Profiles/Foobar2000Profile.cs
@@ -72,7 +72,7 @@ namespace Emby.Dlna.Profiles
}
};
- ResponseProfiles = new ResponseProfile[] { };
+ ResponseProfiles = System.Array.Empty<ResponseProfile>();
}
}
}
diff --git a/Emby.Dlna/Profiles/LgTvProfile.cs b/Emby.Dlna/Profiles/LgTvProfile.cs
index 02301764c0..fbb368d3e3 100644
--- a/Emby.Dlna/Profiles/LgTvProfile.cs
+++ b/Emby.Dlna/Profiles/LgTvProfile.cs
@@ -84,7 +84,7 @@ namespace Emby.Dlna.Profiles
{
Type = DlnaProfileType.Photo,
- Conditions = new []
+ Conditions = new[]
{
new ProfileCondition
{
@@ -191,7 +191,7 @@ namespace Emby.Dlna.Profiles
}
};
- ResponseProfiles = new ResponseProfile[]
+ ResponseProfiles = new[]
{
new ResponseProfile
{
diff --git a/Emby.Dlna/Profiles/LinksysDMA2100Profile.cs b/Emby.Dlna/Profiles/LinksysDMA2100Profile.cs
index 1b1423520c..1a510dfecf 100644
--- a/Emby.Dlna/Profiles/LinksysDMA2100Profile.cs
+++ b/Emby.Dlna/Profiles/LinksysDMA2100Profile.cs
@@ -32,7 +32,7 @@ namespace Emby.Dlna.Profiles
}
};
- ResponseProfiles = new ResponseProfile[]
+ ResponseProfiles = new[]
{
new ResponseProfile
{
diff --git a/Emby.Dlna/Profiles/MarantzProfile.cs b/Emby.Dlna/Profiles/MarantzProfile.cs
index 6cfcc3b824..24078ab29c 100644
--- a/Emby.Dlna/Profiles/MarantzProfile.cs
+++ b/Emby.Dlna/Profiles/MarantzProfile.cs
@@ -37,7 +37,7 @@ namespace Emby.Dlna.Profiles
},
};
- ResponseProfiles = new ResponseProfile[] { };
+ ResponseProfiles = System.Array.Empty<ResponseProfile>();
}
}
}
diff --git a/Emby.Dlna/Profiles/MediaMonkeyProfile.cs b/Emby.Dlna/Profiles/MediaMonkeyProfile.cs
index 7161af7386..28d639b6db 100644
--- a/Emby.Dlna/Profiles/MediaMonkeyProfile.cs
+++ b/Emby.Dlna/Profiles/MediaMonkeyProfile.cs
@@ -1,5 +1,6 @@
#pragma warning disable CS1591
+using System;
using MediaBrowser.Model.Dlna;
namespace Emby.Dlna.Profiles
@@ -37,7 +38,7 @@ namespace Emby.Dlna.Profiles
}
};
- ResponseProfiles = new ResponseProfile[] { };
+ ResponseProfiles = Array.Empty<ResponseProfile>();
}
}
}
diff --git a/Emby.Dlna/Profiles/PanasonicVieraProfile.cs b/Emby.Dlna/Profiles/PanasonicVieraProfile.cs
index 44c35e1425..0d536acf39 100644
--- a/Emby.Dlna/Profiles/PanasonicVieraProfile.cs
+++ b/Emby.Dlna/Profiles/PanasonicVieraProfile.cs
@@ -138,7 +138,7 @@ namespace Emby.Dlna.Profiles
{
Type = DlnaProfileType.Photo,
- Conditions = new []
+ Conditions = new[]
{
new ProfileCondition
{
diff --git a/Emby.Dlna/Profiles/PopcornHourProfile.cs b/Emby.Dlna/Profiles/PopcornHourProfile.cs
index 9e9f6966fc..7fbf8c1649 100644
--- a/Emby.Dlna/Profiles/PopcornHourProfile.cs
+++ b/Emby.Dlna/Profiles/PopcornHourProfile.cs
@@ -93,8 +93,8 @@ namespace Emby.Dlna.Profiles
new CodecProfile
{
Type = CodecType.Video,
- Codec="h264",
- Conditions = new []
+ Codec = "h264",
+ Conditions = new[]
{
new ProfileCondition(ProfileConditionType.EqualsAny, ProfileConditionValue.VideoProfile, "baseline|constrained baseline"),
new ProfileCondition
@@ -122,7 +122,7 @@ namespace Emby.Dlna.Profiles
new CodecProfile
{
Type = CodecType.Video,
- Conditions = new []
+ Conditions = new[]
{
new ProfileCondition
{
@@ -150,7 +150,7 @@ namespace Emby.Dlna.Profiles
{
Type = CodecType.VideoAudio,
Codec = "aac",
- Conditions = new []
+ Conditions = new[]
{
new ProfileCondition
{
@@ -166,7 +166,7 @@ namespace Emby.Dlna.Profiles
{
Type = CodecType.Audio,
Codec = "aac",
- Conditions = new []
+ Conditions = new[]
{
new ProfileCondition
{
@@ -182,7 +182,7 @@ namespace Emby.Dlna.Profiles
{
Type = CodecType.Audio,
Codec = "mp3",
- Conditions = new []
+ Conditions = new[]
{
new ProfileCondition
{
@@ -202,7 +202,7 @@ namespace Emby.Dlna.Profiles
}
};
- ResponseProfiles = new ResponseProfile[]
+ ResponseProfiles = new[]
{
new ResponseProfile
{
diff --git a/Emby.Dlna/Profiles/SamsungSmartTvProfile.cs b/Emby.Dlna/Profiles/SamsungSmartTvProfile.cs
index 4ff2ab9be2..ddbebba2a4 100644
--- a/Emby.Dlna/Profiles/SamsungSmartTvProfile.cs
+++ b/Emby.Dlna/Profiles/SamsungSmartTvProfile.cs
@@ -139,7 +139,7 @@ namespace Emby.Dlna.Profiles
{
Type = DlnaProfileType.Photo,
- Conditions = new []
+ Conditions = new[]
{
new ProfileCondition
{
diff --git a/Emby.Dlna/Profiles/SonyBlurayPlayer2013.cs b/Emby.Dlna/Profiles/SonyBlurayPlayer2013.cs
index 42b066d52b..765c125045 100644
--- a/Emby.Dlna/Profiles/SonyBlurayPlayer2013.cs
+++ b/Emby.Dlna/Profiles/SonyBlurayPlayer2013.cs
@@ -1,5 +1,6 @@
#pragma warning disable CS1591
+using System;
using MediaBrowser.Model.Dlna;
namespace Emby.Dlna.Profiles
@@ -149,7 +150,7 @@ namespace Emby.Dlna.Profiles
{
Type = CodecType.Video,
Codec = "h264",
- Conditions = new []
+ Conditions = new[]
{
new ProfileCondition
{
@@ -177,7 +178,7 @@ namespace Emby.Dlna.Profiles
{
Type = CodecType.VideoAudio,
Codec = "ac3",
- Conditions = new []
+ Conditions = new[]
{
new ProfileCondition
{
@@ -196,7 +197,7 @@ namespace Emby.Dlna.Profiles
{
Type = DlnaProfileType.Photo,
- Conditions = new []
+ Conditions = new[]
{
new ProfileCondition
{
@@ -223,7 +224,7 @@ namespace Emby.Dlna.Profiles
}
};
- ResponseProfiles = new ResponseProfile[] { };
+ ResponseProfiles = Array.Empty<ResponseProfile>();
}
}
}
diff --git a/Emby.Dlna/Profiles/SonyBlurayPlayer2014.cs b/Emby.Dlna/Profiles/SonyBlurayPlayer2014.cs
index fbdf2c18e8..390c8a3e43 100644
--- a/Emby.Dlna/Profiles/SonyBlurayPlayer2014.cs
+++ b/Emby.Dlna/Profiles/SonyBlurayPlayer2014.cs
@@ -1,5 +1,6 @@
#pragma warning disable CS1591
+using System;
using MediaBrowser.Model.Dlna;
namespace Emby.Dlna.Profiles
@@ -149,7 +150,7 @@ namespace Emby.Dlna.Profiles
{
Type = CodecType.Video,
Codec = "h264",
- Conditions = new []
+ Conditions = new[]
{
new ProfileCondition
{
@@ -177,7 +178,7 @@ namespace Emby.Dlna.Profiles
{
Type = CodecType.VideoAudio,
Codec = "ac3",
- Conditions = new []
+ Conditions = new[]
{
new ProfileCondition
{
@@ -196,7 +197,7 @@ namespace Emby.Dlna.Profiles
{
Type = DlnaProfileType.Photo,
- Conditions = new []
+ Conditions = new[]
{
new ProfileCondition
{
@@ -223,7 +224,7 @@ namespace Emby.Dlna.Profiles
}
};
- ResponseProfiles = new ResponseProfile[] { };
+ ResponseProfiles = Array.Empty<ResponseProfile>();
}
}
}
diff --git a/Emby.Dlna/Profiles/SonyBlurayPlayer2015.cs b/Emby.Dlna/Profiles/SonyBlurayPlayer2015.cs
index ce32179a1b..25adc4d022 100644
--- a/Emby.Dlna/Profiles/SonyBlurayPlayer2015.cs
+++ b/Emby.Dlna/Profiles/SonyBlurayPlayer2015.cs
@@ -1,5 +1,6 @@
#pragma warning disable CS1591
+using System;
using MediaBrowser.Model.Dlna;
namespace Emby.Dlna.Profiles
@@ -137,7 +138,7 @@ namespace Emby.Dlna.Profiles
{
Type = CodecType.Video,
Codec = "h264",
- Conditions = new []
+ Conditions = new[]
{
new ProfileCondition
{
@@ -165,7 +166,7 @@ namespace Emby.Dlna.Profiles
{
Type = CodecType.VideoAudio,
Codec = "ac3",
- Conditions = new []
+ Conditions = new[]
{
new ProfileCondition
{
@@ -184,7 +185,7 @@ namespace Emby.Dlna.Profiles
{
Type = DlnaProfileType.Photo,
- Conditions = new []
+ Conditions = new[]
{
new ProfileCondition
{
@@ -211,7 +212,7 @@ namespace Emby.Dlna.Profiles
}
};
- ResponseProfiles = new ResponseProfile[] { };
+ ResponseProfiles = Array.Empty<ResponseProfile>();
}
}
}
diff --git a/Emby.Dlna/Profiles/SonyBlurayPlayer2016.cs b/Emby.Dlna/Profiles/SonyBlurayPlayer2016.cs
index aa1721d398..0a39a5f401 100644
--- a/Emby.Dlna/Profiles/SonyBlurayPlayer2016.cs
+++ b/Emby.Dlna/Profiles/SonyBlurayPlayer2016.cs
@@ -1,5 +1,6 @@
#pragma warning disable CS1591
+using System;
using MediaBrowser.Model.Dlna;
namespace Emby.Dlna.Profiles
@@ -137,7 +138,7 @@ namespace Emby.Dlna.Profiles
{
Type = CodecType.Video,
Codec = "h264",
- Conditions = new []
+ Conditions = new[]
{
new ProfileCondition
{
@@ -165,7 +166,7 @@ namespace Emby.Dlna.Profiles
{
Type = CodecType.VideoAudio,
Codec = "ac3",
- Conditions = new []
+ Conditions = new[]
{
new ProfileCondition
{
@@ -184,7 +185,7 @@ namespace Emby.Dlna.Profiles
{
Type = DlnaProfileType.Photo,
- Conditions = new []
+ Conditions = new[]
{
new ProfileCondition
{
@@ -211,7 +212,7 @@ namespace Emby.Dlna.Profiles
}
};
- ResponseProfiles = new ResponseProfile[] { };
+ ResponseProfiles = Array.Empty<ResponseProfile>();
}
}
}
diff --git a/Emby.Dlna/Profiles/SonyBlurayPlayerProfile.cs b/Emby.Dlna/Profiles/SonyBlurayPlayerProfile.cs
index ecdd2e7a4e..05c8ab1c14 100644
--- a/Emby.Dlna/Profiles/SonyBlurayPlayerProfile.cs
+++ b/Emby.Dlna/Profiles/SonyBlurayPlayerProfile.cs
@@ -114,7 +114,7 @@ namespace Emby.Dlna.Profiles
{
Type = CodecType.Video,
Codec = "h264",
- Conditions = new []
+ Conditions = new[]
{
new ProfileCondition
{
@@ -156,7 +156,7 @@ namespace Emby.Dlna.Profiles
{
Type = CodecType.VideoAudio,
Codec = "ac3",
- Conditions = new []
+ Conditions = new[]
{
new ProfileCondition
{
@@ -172,7 +172,7 @@ namespace Emby.Dlna.Profiles
{
Type = CodecType.VideoAudio,
Codec = "aac",
- Conditions = new []
+ Conditions = new[]
{
new ProfileCondition
{
@@ -191,7 +191,7 @@ namespace Emby.Dlna.Profiles
{
Type = DlnaProfileType.Photo,
- Conditions = new []
+ Conditions = new[]
{
new ProfileCondition
{
@@ -217,7 +217,7 @@ namespace Emby.Dlna.Profiles
VideoCodec = "h264,mpeg4,vc1",
AudioCodec = "ac3,aac,mp3",
MimeType = "video/vnd.dlna.mpeg-tts",
- OrgPn="MPEG_TS_SD_EU,MPEG_TS_SD_NA,MPEG_TS_SD_KO",
+ OrgPn = "MPEG_TS_SD_EU,MPEG_TS_SD_NA,MPEG_TS_SD_KO",
Type = DlnaProfileType.Video
},
diff --git a/Emby.Dlna/Profiles/SonyBravia2010Profile.cs b/Emby.Dlna/Profiles/SonyBravia2010Profile.cs
index 68365ba4ae..8ab4acd1be 100644
--- a/Emby.Dlna/Profiles/SonyBravia2010Profile.cs
+++ b/Emby.Dlna/Profiles/SonyBravia2010Profile.cs
@@ -102,13 +102,13 @@ namespace Emby.Dlna.Profiles
new ResponseProfile
{
Container = "ts,mpegts",
- VideoCodec="h264",
- AudioCodec="ac3,aac,mp3",
+ VideoCodec = "h264",
+ AudioCodec = "ac3,aac,mp3",
MimeType = "video/vnd.dlna.mpeg-tts",
- OrgPn="AVC_TS_HD_24_AC3_T,AVC_TS_HD_50_AC3_T,AVC_TS_HD_60_AC3_T,AVC_TS_HD_EU_T",
+ OrgPn = "AVC_TS_HD_24_AC3_T,AVC_TS_HD_50_AC3_T,AVC_TS_HD_60_AC3_T,AVC_TS_HD_EU_T",
Type = DlnaProfileType.Video,
- Conditions = new []
+ Conditions = new[]
{
new ProfileCondition
{
@@ -128,13 +128,13 @@ namespace Emby.Dlna.Profiles
new ResponseProfile
{
Container = "ts,mpegts",
- VideoCodec="h264",
- AudioCodec="ac3,aac,mp3",
+ VideoCodec = "h264",
+ AudioCodec = "ac3,aac,mp3",
MimeType = "video/mpeg",
- OrgPn="AVC_TS_HD_24_AC3_ISO,AVC_TS_HD_50_AC3_ISO,AVC_TS_HD_60_AC3_ISO,AVC_TS_HD_EU_ISO",
+ OrgPn = "AVC_TS_HD_24_AC3_ISO,AVC_TS_HD_50_AC3_ISO,AVC_TS_HD_60_AC3_ISO,AVC_TS_HD_EU_ISO",
Type = DlnaProfileType.Video,
- Conditions = new []
+ Conditions = new[]
{
new ProfileCondition
{
@@ -148,28 +148,28 @@ namespace Emby.Dlna.Profiles
new ResponseProfile
{
Container = "ts,mpegts",
- VideoCodec="h264",
- AudioCodec="ac3,aac,mp3",
+ VideoCodec = "h264",
+ AudioCodec = "ac3,aac,mp3",
MimeType = "video/vnd.dlna.mpeg-tts",
- OrgPn="AVC_TS_HD_24_AC3,AVC_TS_HD_50_AC3,AVC_TS_HD_60_AC3,AVC_TS_HD_EU",
+ OrgPn = "AVC_TS_HD_24_AC3,AVC_TS_HD_50_AC3,AVC_TS_HD_60_AC3,AVC_TS_HD_EU",
Type = DlnaProfileType.Video
},
new ResponseProfile
{
Container = "ts,mpegts",
- VideoCodec="mpeg2video",
+ VideoCodec = "mpeg2video",
MimeType = "video/vnd.dlna.mpeg-tts",
- OrgPn="MPEG_TS_SD_EU,MPEG_TS_SD_NA,MPEG_TS_SD_KO",
+ OrgPn = "MPEG_TS_SD_EU,MPEG_TS_SD_NA,MPEG_TS_SD_KO",
Type = DlnaProfileType.Video
},
new ResponseProfile
{
Container = "mpeg",
- VideoCodec="mpeg1video,mpeg2video",
+ VideoCodec = "mpeg1video,mpeg2video",
MimeType = "video/mpeg",
- OrgPn="MPEG_PS_NTSC,MPEG_PS_PAL",
+ OrgPn = "MPEG_PS_NTSC,MPEG_PS_PAL",
Type = DlnaProfileType.Video
}
};
@@ -180,7 +180,7 @@ namespace Emby.Dlna.Profiles
{
Type = DlnaProfileType.Photo,
- Conditions = new []
+ Conditions = new[]
{
new ProfileCondition
{
@@ -204,7 +204,7 @@ namespace Emby.Dlna.Profiles
{
Type = CodecType.Video,
Codec = "h264",
- Conditions = new []
+ Conditions = new[]
{
new ProfileCondition
{
@@ -243,7 +243,7 @@ namespace Emby.Dlna.Profiles
{
Type = CodecType.Video,
Codec = "mpeg2video",
- Conditions = new []
+ Conditions = new[]
{
new ProfileCondition
{
@@ -275,7 +275,7 @@ namespace Emby.Dlna.Profiles
new CodecProfile
{
Type = CodecType.Video,
- Conditions = new []
+ Conditions = new[]
{
new ProfileCondition
{
@@ -303,7 +303,7 @@ namespace Emby.Dlna.Profiles
Type = CodecType.VideoAudio,
Codec = "ac3",
- Conditions = new []
+ Conditions = new[]
{
new ProfileCondition
{
@@ -319,7 +319,7 @@ namespace Emby.Dlna.Profiles
Type = CodecType.VideoAudio,
Codec = "aac",
- Conditions = new []
+ Conditions = new[]
{
new ProfileCondition
{
@@ -341,7 +341,7 @@ namespace Emby.Dlna.Profiles
Type = CodecType.VideoAudio,
Codec = "mp3,mp2",
- Conditions = new []
+ Conditions = new[]
{
new ProfileCondition
{
diff --git a/Emby.Dlna/Profiles/SonyBravia2011Profile.cs b/Emby.Dlna/Profiles/SonyBravia2011Profile.cs
index b34af04a50..42d253394c 100644
--- a/Emby.Dlna/Profiles/SonyBravia2011Profile.cs
+++ b/Emby.Dlna/Profiles/SonyBravia2011Profile.cs
@@ -120,7 +120,7 @@ namespace Emby.Dlna.Profiles
{
Type = DlnaProfileType.Photo,
- Conditions = new []
+ Conditions = new[]
{
new ProfileCondition
{
@@ -143,13 +143,13 @@ namespace Emby.Dlna.Profiles
new ResponseProfile
{
Container = "ts,mpegts",
- VideoCodec="h264",
- AudioCodec="ac3,aac,mp3",
+ VideoCodec = "h264",
+ AudioCodec = "ac3,aac,mp3",
MimeType = "video/vnd.dlna.mpeg-tts",
- OrgPn="AVC_TS_HD_24_AC3_T,AVC_TS_HD_50_AC3_T,AVC_TS_HD_60_AC3_T,AVC_TS_HD_EU_T",
+ OrgPn = "AVC_TS_HD_24_AC3_T,AVC_TS_HD_50_AC3_T,AVC_TS_HD_60_AC3_T,AVC_TS_HD_EU_T",
Type = DlnaProfileType.Video,
- Conditions = new []
+ Conditions = new[]
{
new ProfileCondition
{
@@ -169,13 +169,13 @@ namespace Emby.Dlna.Profiles
new ResponseProfile
{
Container = "ts,mpegts",
- VideoCodec="h264",
- AudioCodec="ac3,aac,mp3",
+ VideoCodec = "h264",
+ AudioCodec = "ac3,aac,mp3",
MimeType = "video/mpeg",
- OrgPn="AVC_TS_HD_24_AC3_ISO,AVC_TS_HD_50_AC3_ISO,AVC_TS_HD_60_AC3_ISO,AVC_TS_HD_EU_ISO",
+ OrgPn = "AVC_TS_HD_24_AC3_ISO,AVC_TS_HD_50_AC3_ISO,AVC_TS_HD_60_AC3_ISO,AVC_TS_HD_EU_ISO",
Type = DlnaProfileType.Video,
- Conditions = new []
+ Conditions = new[]
{
new ProfileCondition
{
@@ -189,28 +189,28 @@ namespace Emby.Dlna.Profiles
new ResponseProfile
{
Container = "ts,mpegts",
- VideoCodec="h264",
- AudioCodec="ac3,aac,mp3",
+ VideoCodec = "h264",
+ AudioCodec = "ac3,aac,mp3",
MimeType = "video/vnd.dlna.mpeg-tts",
- OrgPn="AVC_TS_HD_24_AC3,AVC_TS_HD_50_AC3,AVC_TS_HD_60_AC3,AVC_TS_HD_EU",
+ OrgPn = "AVC_TS_HD_24_AC3,AVC_TS_HD_50_AC3,AVC_TS_HD_60_AC3,AVC_TS_HD_EU",
Type = DlnaProfileType.Video
},
new ResponseProfile
{
Container = "ts,mpegts",
- VideoCodec="mpeg2video",
+ VideoCodec = "mpeg2video",
MimeType = "video/vnd.dlna.mpeg-tts",
- OrgPn="MPEG_TS_SD_EU,MPEG_TS_SD_NA,MPEG_TS_SD_KO",
+ OrgPn = "MPEG_TS_SD_EU,MPEG_TS_SD_NA,MPEG_TS_SD_KO",
Type = DlnaProfileType.Video
},
new ResponseProfile
{
Container = "mpeg",
- VideoCodec="mpeg1video,mpeg2video",
+ VideoCodec = "mpeg1video,mpeg2video",
MimeType = "video/mpeg",
- OrgPn="MPEG_PS_NTSC,MPEG_PS_PAL",
+ OrgPn = "MPEG_PS_NTSC,MPEG_PS_PAL",
Type = DlnaProfileType.Video
},
new ResponseProfile
@@ -227,7 +227,7 @@ namespace Emby.Dlna.Profiles
{
Type = CodecType.Video,
Codec = "h264",
- Conditions = new []
+ Conditions = new[]
{
new ProfileCondition
{
@@ -266,7 +266,7 @@ namespace Emby.Dlna.Profiles
{
Type = CodecType.Video,
Codec = "mpeg2video",
- Conditions = new []
+ Conditions = new[]
{
new ProfileCondition
{
@@ -298,7 +298,7 @@ namespace Emby.Dlna.Profiles
new CodecProfile
{
Type = CodecType.Video,
- Conditions = new []
+ Conditions = new[]
{
new ProfileCondition
{
@@ -326,7 +326,7 @@ namespace Emby.Dlna.Profiles
Type = CodecType.VideoAudio,
Codec = "ac3",
- Conditions = new []
+ Conditions = new[]
{
new ProfileCondition
{
@@ -364,7 +364,7 @@ namespace Emby.Dlna.Profiles
Type = CodecType.VideoAudio,
Codec = "mp3,mp2",
- Conditions = new []
+ Conditions = new[]
{
new ProfileCondition
{
diff --git a/Emby.Dlna/Profiles/SonyBravia2012Profile.cs b/Emby.Dlna/Profiles/SonyBravia2012Profile.cs
index 0e75d0cb5e..0598e83422 100644
--- a/Emby.Dlna/Profiles/SonyBravia2012Profile.cs
+++ b/Emby.Dlna/Profiles/SonyBravia2012Profile.cs
@@ -131,13 +131,13 @@ namespace Emby.Dlna.Profiles
new ResponseProfile
{
Container = "ts,mpegts",
- VideoCodec="h264",
- AudioCodec="ac3,aac,mp3",
+ VideoCodec = "h264",
+ AudioCodec = "ac3,aac,mp3",
MimeType = "video/vnd.dlna.mpeg-tts",
- OrgPn="AVC_TS_HD_24_AC3_T,AVC_TS_HD_50_AC3_T,AVC_TS_HD_60_AC3_T,AVC_TS_HD_EU_T",
+ OrgPn = "AVC_TS_HD_24_AC3_T,AVC_TS_HD_50_AC3_T,AVC_TS_HD_60_AC3_T,AVC_TS_HD_EU_T",
Type = DlnaProfileType.Video,
- Conditions = new []
+ Conditions = new[]
{
new ProfileCondition
{
@@ -157,13 +157,13 @@ namespace Emby.Dlna.Profiles
new ResponseProfile
{
Container = "ts,mpegts",
- VideoCodec="h264",
- AudioCodec="ac3,aac,mp3",
+ VideoCodec = "h264",
+ AudioCodec = "ac3,aac,mp3",
MimeType = "video/mpeg",
- OrgPn="AVC_TS_HD_24_AC3_ISO,AVC_TS_HD_50_AC3_ISO,AVC_TS_HD_60_AC3_ISO,AVC_TS_HD_EU_ISO",
+ OrgPn = "AVC_TS_HD_24_AC3_ISO,AVC_TS_HD_50_AC3_ISO,AVC_TS_HD_60_AC3_ISO,AVC_TS_HD_EU_ISO",
Type = DlnaProfileType.Video,
- Conditions = new []
+ Conditions = new[]
{
new ProfileCondition
{
@@ -177,28 +177,28 @@ namespace Emby.Dlna.Profiles
new ResponseProfile
{
Container = "ts,mpegts",
- VideoCodec="h264",
- AudioCodec="ac3,aac,mp3",
+ VideoCodec = "h264",
+ AudioCodec = "ac3,aac,mp3",
MimeType = "video/vnd.dlna.mpeg-tts",
- OrgPn="AVC_TS_HD_24_AC3,AVC_TS_HD_50_AC3,AVC_TS_HD_60_AC3,AVC_TS_HD_EU",
+ OrgPn = "AVC_TS_HD_24_AC3,AVC_TS_HD_50_AC3,AVC_TS_HD_60_AC3,AVC_TS_HD_EU",
Type = DlnaProfileType.Video
},
new ResponseProfile
{
Container = "ts,mpegts",
- VideoCodec="mpeg2video",
+ VideoCodec = "mpeg2video",
MimeType = "video/vnd.dlna.mpeg-tts",
- OrgPn="MPEG_TS_SD_EU,MPEG_TS_SD_NA,MPEG_TS_SD_KO",
+ OrgPn = "MPEG_TS_SD_EU,MPEG_TS_SD_NA,MPEG_TS_SD_KO",
Type = DlnaProfileType.Video
},
new ResponseProfile
{
Container = "mpeg",
- VideoCodec="mpeg1video,mpeg2video",
+ VideoCodec = "mpeg1video,mpeg2video",
MimeType = "video/mpeg",
- OrgPn="MPEG_PS_NTSC,MPEG_PS_PAL",
+ OrgPn = "MPEG_PS_NTSC,MPEG_PS_PAL",
Type = DlnaProfileType.Video
},
new ResponseProfile
@@ -215,7 +215,7 @@ namespace Emby.Dlna.Profiles
{
Type = DlnaProfileType.Photo,
- Conditions = new []
+ Conditions = new[]
{
new ProfileCondition
{
@@ -282,7 +282,7 @@ namespace Emby.Dlna.Profiles
Type = CodecType.VideoAudio,
Codec = "mp3,mp2",
- Conditions = new []
+ Conditions = new[]
{
new ProfileCondition
{
diff --git a/Emby.Dlna/Profiles/SonyBravia2013Profile.cs b/Emby.Dlna/Profiles/SonyBravia2013Profile.cs
index 3300863c90..3d90a1e72d 100644
--- a/Emby.Dlna/Profiles/SonyBravia2013Profile.cs
+++ b/Emby.Dlna/Profiles/SonyBravia2013Profile.cs
@@ -164,7 +164,7 @@ namespace Emby.Dlna.Profiles
{
Type = DlnaProfileType.Photo,
- Conditions = new []
+ Conditions = new[]
{
new ProfileCondition
{
@@ -187,13 +187,13 @@ namespace Emby.Dlna.Profiles
new ResponseProfile
{
Container = "ts,mpegts",
- VideoCodec="h264",
- AudioCodec="ac3,aac,mp3",
+ VideoCodec = "h264",
+ AudioCodec = "ac3,aac,mp3",
MimeType = "video/vnd.dlna.mpeg-tts",
- OrgPn="AVC_TS_HD_24_AC3_T,AVC_TS_HD_50_AC3_T,AVC_TS_HD_60_AC3_T,AVC_TS_HD_EU_T",
+ OrgPn = "AVC_TS_HD_24_AC3_T,AVC_TS_HD_50_AC3_T,AVC_TS_HD_60_AC3_T,AVC_TS_HD_EU_T",
Type = DlnaProfileType.Video,
- Conditions = new []
+ Conditions = new[]
{
new ProfileCondition
{
@@ -213,13 +213,13 @@ namespace Emby.Dlna.Profiles
new ResponseProfile
{
Container = "ts,mpegts",
- VideoCodec="h264",
- AudioCodec="ac3,aac,mp3",
+ VideoCodec = "h264",
+ AudioCodec = "ac3,aac,mp3",
MimeType = "video/mpeg",
- OrgPn="AVC_TS_HD_24_AC3_ISO,AVC_TS_HD_50_AC3_ISO,AVC_TS_HD_60_AC3_ISO,AVC_TS_HD_EU_ISO",
+ OrgPn = "AVC_TS_HD_24_AC3_ISO,AVC_TS_HD_50_AC3_ISO,AVC_TS_HD_60_AC3_ISO,AVC_TS_HD_EU_ISO",
Type = DlnaProfileType.Video,
- Conditions = new []
+ Conditions = new[]
{
new ProfileCondition
{
@@ -233,28 +233,28 @@ namespace Emby.Dlna.Profiles
new ResponseProfile
{
Container = "ts,mpegts",
- VideoCodec="h264",
- AudioCodec="ac3,aac,mp3",
+ VideoCodec = "h264",
+ AudioCodec = "ac3,aac,mp3",
MimeType = "video/vnd.dlna.mpeg-tts",
- OrgPn="AVC_TS_HD_24_AC3,AVC_TS_HD_50_AC3,AVC_TS_HD_60_AC3,AVC_TS_HD_EU",
+ OrgPn = "AVC_TS_HD_24_AC3,AVC_TS_HD_50_AC3,AVC_TS_HD_60_AC3,AVC_TS_HD_EU",
Type = DlnaProfileType.Video
},
new ResponseProfile
{
Container = "ts,mpegts",
- VideoCodec="mpeg2video",
+ VideoCodec = "mpeg2video",
MimeType = "video/vnd.dlna.mpeg-tts",
- OrgPn="MPEG_TS_SD_EU,MPEG_TS_SD_NA,MPEG_TS_SD_KO",
+ OrgPn = "MPEG_TS_SD_EU,MPEG_TS_SD_NA,MPEG_TS_SD_KO",
Type = DlnaProfileType.Video
},
new ResponseProfile
{
Container = "mpeg",
- VideoCodec="mpeg1video,mpeg2video",
+ VideoCodec = "mpeg1video,mpeg2video",
MimeType = "video/mpeg",
- OrgPn="MPEG_PS_NTSC,MPEG_PS_PAL",
+ OrgPn = "MPEG_PS_NTSC,MPEG_PS_PAL",
Type = DlnaProfileType.Video
},
new ResponseProfile
@@ -265,14 +265,13 @@ namespace Emby.Dlna.Profiles
}
};
-
CodecProfiles = new[]
{
new CodecProfile
{
Type = CodecType.Video,
- Conditions = new []
+ Conditions = new[]
{
new ProfileCondition
{
@@ -300,7 +299,7 @@ namespace Emby.Dlna.Profiles
Type = CodecType.VideoAudio,
Codec = "mp3,mp2",
- Conditions = new []
+ Conditions = new[]
{
new ProfileCondition
{
diff --git a/Emby.Dlna/Profiles/SonyBravia2014Profile.cs b/Emby.Dlna/Profiles/SonyBravia2014Profile.cs
index 4e833441cc..9188f73ef1 100644
--- a/Emby.Dlna/Profiles/SonyBravia2014Profile.cs
+++ b/Emby.Dlna/Profiles/SonyBravia2014Profile.cs
@@ -164,7 +164,7 @@ namespace Emby.Dlna.Profiles
{
Type = DlnaProfileType.Photo,
- Conditions = new []
+ Conditions = new[]
{
new ProfileCondition
{
@@ -187,13 +187,13 @@ namespace Emby.Dlna.Profiles
new ResponseProfile
{
Container = "ts,mpegts",
- VideoCodec="h264",
- AudioCodec="ac3,aac,mp3",
+ VideoCodec = "h264",
+ AudioCodec = "ac3,aac,mp3",
MimeType = "video/vnd.dlna.mpeg-tts",
- OrgPn="AVC_TS_HD_24_AC3_T,AVC_TS_HD_50_AC3_T,AVC_TS_HD_60_AC3_T,AVC_TS_HD_EU_T",
+ OrgPn = "AVC_TS_HD_24_AC3_T,AVC_TS_HD_50_AC3_T,AVC_TS_HD_60_AC3_T,AVC_TS_HD_EU_T",
Type = DlnaProfileType.Video,
- Conditions = new []
+ Conditions = new[]
{
new ProfileCondition
{
@@ -213,13 +213,13 @@ namespace Emby.Dlna.Profiles
new ResponseProfile
{
Container = "ts,mpegts",
- VideoCodec="h264",
- AudioCodec="ac3,aac,mp3",
+ VideoCodec = "h264",
+ AudioCodec = "ac3,aac,mp3",
MimeType = "video/mpeg",
- OrgPn="AVC_TS_HD_24_AC3_ISO,AVC_TS_HD_50_AC3_ISO,AVC_TS_HD_60_AC3_ISO,AVC_TS_HD_EU_ISO",
+ OrgPn = "AVC_TS_HD_24_AC3_ISO,AVC_TS_HD_50_AC3_ISO,AVC_TS_HD_60_AC3_ISO,AVC_TS_HD_EU_ISO",
Type = DlnaProfileType.Video,
- Conditions = new []
+ Conditions = new[]
{
new ProfileCondition
{
@@ -233,28 +233,28 @@ namespace Emby.Dlna.Profiles
new ResponseProfile
{
Container = "ts,mpegts",
- VideoCodec="h264",
- AudioCodec="ac3,aac,mp3",
+ VideoCodec = "h264",
+ AudioCodec = "ac3,aac,mp3",
MimeType = "video/vnd.dlna.mpeg-tts",
- OrgPn="AVC_TS_HD_24_AC3,AVC_TS_HD_50_AC3,AVC_TS_HD_60_AC3,AVC_TS_HD_EU",
+ OrgPn = "AVC_TS_HD_24_AC3,AVC_TS_HD_50_AC3,AVC_TS_HD_60_AC3,AVC_TS_HD_EU",
Type = DlnaProfileType.Video
},
new ResponseProfile
{
Container = "ts,mpegts",
- VideoCodec="mpeg2video",
+ VideoCodec = "mpeg2video",
MimeType = "video/vnd.dlna.mpeg-tts",
- OrgPn="MPEG_TS_SD_EU,MPEG_TS_SD_NA,MPEG_TS_SD_KO",
+ OrgPn = "MPEG_TS_SD_EU,MPEG_TS_SD_NA,MPEG_TS_SD_KO",
Type = DlnaProfileType.Video
},
new ResponseProfile
{
Container = "mpeg",
- VideoCodec="mpeg1video,mpeg2video",
+ VideoCodec = "mpeg1video,mpeg2video",
MimeType = "video/mpeg",
- OrgPn="MPEG_PS_NTSC,MPEG_PS_PAL",
+ OrgPn = "MPEG_PS_NTSC,MPEG_PS_PAL",
Type = DlnaProfileType.Video
},
new ResponseProfile
@@ -265,14 +265,13 @@ namespace Emby.Dlna.Profiles
}
};
-
CodecProfiles = new[]
{
new CodecProfile
{
Type = CodecType.Video,
- Conditions = new []
+ Conditions = new[]
{
new ProfileCondition
{
@@ -300,7 +299,7 @@ namespace Emby.Dlna.Profiles
Type = CodecType.VideoAudio,
Codec = "mp3,mp2",
- Conditions = new []
+ Conditions = new[]
{
new ProfileCondition
{
diff --git a/Emby.Dlna/Profiles/SonyPs3Profile.cs b/Emby.Dlna/Profiles/SonyPs3Profile.cs
index 7f72356bdc..d56b1df507 100644
--- a/Emby.Dlna/Profiles/SonyPs3Profile.cs
+++ b/Emby.Dlna/Profiles/SonyPs3Profile.cs
@@ -108,7 +108,7 @@ namespace Emby.Dlna.Profiles
{
Type = DlnaProfileType.Photo,
- Conditions = new []
+ Conditions = new[]
{
new ProfileCondition
{
@@ -133,7 +133,7 @@ namespace Emby.Dlna.Profiles
Type = CodecType.Video,
Codec = "h264",
- Conditions = new []
+ Conditions = new[]
{
new ProfileCondition
{
@@ -176,7 +176,7 @@ namespace Emby.Dlna.Profiles
Type = CodecType.VideoAudio,
Codec = "ac3",
- Conditions = new []
+ Conditions = new[]
{
new ProfileCondition
{
@@ -201,7 +201,7 @@ namespace Emby.Dlna.Profiles
Type = CodecType.VideoAudio,
Codec = "wmapro",
- Conditions = new []
+ Conditions = new[]
{
new ProfileCondition
{
@@ -217,7 +217,7 @@ namespace Emby.Dlna.Profiles
Type = CodecType.VideoAudio,
Codec = "aac",
- Conditions = new []
+ Conditions = new[]
{
new ProfileCondition
{
@@ -235,7 +235,7 @@ namespace Emby.Dlna.Profiles
new ResponseProfile
{
Container = "mp4,mov",
- AudioCodec="aac",
+ AudioCodec = "aac",
MimeType = "video/mp4",
Type = DlnaProfileType.Video
},
@@ -244,7 +244,7 @@ namespace Emby.Dlna.Profiles
{
Container = "avi",
MimeType = "video/divx",
- OrgPn="AVI",
+ OrgPn = "AVI",
Type = DlnaProfileType.Video
},
diff --git a/Emby.Dlna/Profiles/SonyPs4Profile.cs b/Emby.Dlna/Profiles/SonyPs4Profile.cs
index 411bfe2b0c..db56094e2b 100644
--- a/Emby.Dlna/Profiles/SonyPs4Profile.cs
+++ b/Emby.Dlna/Profiles/SonyPs4Profile.cs
@@ -110,7 +110,7 @@ namespace Emby.Dlna.Profiles
{
Type = DlnaProfileType.Photo,
- Conditions = new []
+ Conditions = new[]
{
new ProfileCondition
{
@@ -135,7 +135,7 @@ namespace Emby.Dlna.Profiles
Type = CodecType.Video,
Codec = "h264",
- Conditions = new []
+ Conditions = new[]
{
new ProfileCondition
{
@@ -178,7 +178,7 @@ namespace Emby.Dlna.Profiles
Type = CodecType.VideoAudio,
Codec = "ac3",
- Conditions = new []
+ Conditions = new[]
{
new ProfileCondition
{
@@ -203,7 +203,7 @@ namespace Emby.Dlna.Profiles
Type = CodecType.VideoAudio,
Codec = "wmapro",
- Conditions = new []
+ Conditions = new[]
{
new ProfileCondition
{
@@ -219,7 +219,7 @@ namespace Emby.Dlna.Profiles
Type = CodecType.VideoAudio,
Codec = "aac",
- Conditions = new []
+ Conditions = new[]
{
new ProfileCondition
{
@@ -237,7 +237,7 @@ namespace Emby.Dlna.Profiles
new ResponseProfile
{
Container = "mp4,mov",
- AudioCodec="aac",
+ AudioCodec = "aac",
MimeType = "video/mp4",
Type = DlnaProfileType.Video
},
@@ -246,7 +246,7 @@ namespace Emby.Dlna.Profiles
{
Container = "avi",
MimeType = "video/divx",
- OrgPn="AVI",
+ OrgPn = "AVI",
Type = DlnaProfileType.Video
},
diff --git a/Emby.Dlna/Profiles/WdtvLiveProfile.cs b/Emby.Dlna/Profiles/WdtvLiveProfile.cs
index 2de9a8cd9e..937ca0f425 100644
--- a/Emby.Dlna/Profiles/WdtvLiveProfile.cs
+++ b/Emby.Dlna/Profiles/WdtvLiveProfile.cs
@@ -20,7 +20,7 @@ namespace Emby.Dlna.Profiles
Headers = new[]
{
- new HttpHeaderInfo {Name = "User-Agent", Value = "alphanetworks", Match = HeaderMatchType.Substring},
+ new HttpHeaderInfo { Name = "User-Agent", Value = "alphanetworks", Match = HeaderMatchType.Substring },
new HttpHeaderInfo
{
Name = "User-Agent",
@@ -168,7 +168,7 @@ namespace Emby.Dlna.Profiles
{
Type = DlnaProfileType.Photo,
- Conditions = new []
+ Conditions = new[]
{
new ProfileCondition
{
@@ -193,7 +193,7 @@ namespace Emby.Dlna.Profiles
Type = CodecType.Video,
Codec = "h264",
- Conditions = new []
+ Conditions = new[]
{
new ProfileCondition
{
@@ -221,7 +221,7 @@ namespace Emby.Dlna.Profiles
Type = CodecType.VideoAudio,
Codec = "aac",
- Conditions = new []
+ Conditions = new[]
{
new ProfileCondition
{
diff --git a/Emby.Dlna/Profiles/XboxOneProfile.cs b/Emby.Dlna/Profiles/XboxOneProfile.cs
index 2cbe4e6acb..84d8184a22 100644
--- a/Emby.Dlna/Profiles/XboxOneProfile.cs
+++ b/Emby.Dlna/Profiles/XboxOneProfile.cs
@@ -119,7 +119,7 @@ namespace Emby.Dlna.Profiles
Type = DlnaProfileType.Video,
Container = "mp4,mov",
- Conditions = new []
+ Conditions = new[]
{
new ProfileCondition
{
@@ -138,7 +138,7 @@ namespace Emby.Dlna.Profiles
{
Type = CodecType.Video,
Codec = "mpeg4",
- Conditions = new []
+ Conditions = new[]
{
new ProfileCondition
{
@@ -187,7 +187,7 @@ namespace Emby.Dlna.Profiles
{
Type = CodecType.Video,
Codec = "h264",
- Conditions = new []
+ Conditions = new[]
{
new ProfileCondition
{
@@ -236,7 +236,7 @@ namespace Emby.Dlna.Profiles
{
Type = CodecType.Video,
Codec = "wmv2,wmv3,vc1",
- Conditions = new []
+ Conditions = new[]
{
new ProfileCondition
{
@@ -284,7 +284,7 @@ namespace Emby.Dlna.Profiles
new CodecProfile
{
Type = CodecType.Video,
- Conditions = new []
+ Conditions = new[]
{
new ProfileCondition
{
@@ -307,7 +307,7 @@ namespace Emby.Dlna.Profiles
{
Type = CodecType.VideoAudio,
Codec = "ac3,wmav2,wmapro",
- Conditions = new []
+ Conditions = new[]
{
new ProfileCondition
{
@@ -323,7 +323,7 @@ namespace Emby.Dlna.Profiles
{
Type = CodecType.VideoAudio,
Codec = "aac",
- Conditions = new []
+ Conditions = new[]
{
new ProfileCondition
{
diff --git a/Emby.Dlna/Server/DescriptionXmlBuilder.cs b/Emby.Dlna/Server/DescriptionXmlBuilder.cs
index 5ecc81a2f1..bca9e81cd0 100644
--- a/Emby.Dlna/Server/DescriptionXmlBuilder.cs
+++ b/Emby.Dlna/Server/DescriptionXmlBuilder.cs
@@ -4,6 +4,7 @@ using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
+using System.Security;
using System.Text;
using Emby.Dlna.Common;
using MediaBrowser.Model.Dlna;
@@ -64,10 +65,10 @@ namespace Emby.Dlna.Server
foreach (var att in attributes)
{
- builder.AppendFormat(" {0}=\"{1}\"", att.Name, att.Value);
+ builder.AppendFormat(CultureInfo.InvariantCulture, " {0}=\"{1}\"", att.Name, att.Value);
}
- builder.Append(">");
+ builder.Append('>');
builder.Append("<specVersion>");
builder.Append("<major>1</major>");
@@ -76,7 +77,9 @@ namespace Emby.Dlna.Server
if (!EnableAbsoluteUrls)
{
- builder.Append("<URLBase>" + Escape(_serverAddress) + "</URLBase>");
+ builder.Append("<URLBase>")
+ .Append(SecurityElement.Escape(_serverAddress))
+ .Append("</URLBase>");
}
AppendDeviceInfo(builder);
@@ -93,86 +96,14 @@ namespace Emby.Dlna.Server
AppendIconList(builder);
- builder.Append("<presentationURL>" + Escape(_serverAddress) + "/web/index.html</presentationURL>");
+ builder.Append("<presentationURL>")
+ .Append(SecurityElement.Escape(_serverAddress))
+ .Append("/web/index.html</presentationURL>");
AppendServiceList(builder);
builder.Append("</device>");
}
- private static readonly char[] s_escapeChars = new char[]
- {
- '<',
- '>',
- '"',
- '\'',
- '&'
- };
-
- private static readonly string[] s_escapeStringPairs = new[]
- {
- "<",
- "&lt;",
- ">",
- "&gt;",
- "\"",
- "&quot;",
- "'",
- "&apos;",
- "&",
- "&amp;"
- };
-
- private static string GetEscapeSequence(char c)
- {
- int num = s_escapeStringPairs.Length;
- for (int i = 0; i < num; i += 2)
- {
- string text = s_escapeStringPairs[i];
- string result = s_escapeStringPairs[i + 1];
- if (text[0] == c)
- {
- return result;
- }
- }
- return c.ToString(CultureInfo.InvariantCulture);
- }
-
- /// <summary>Replaces invalid XML characters in a string with their valid XML equivalent.</summary>
- /// <returns>The input string with invalid characters replaced.</returns>
- /// <param name="str">The string within which to escape invalid characters. </param>
- public static string Escape(string str)
- {
- if (str == null)
- {
- return null;
- }
-
- StringBuilder stringBuilder = null;
- int length = str.Length;
- int num = 0;
- while (true)
- {
- int num2 = str.IndexOfAny(s_escapeChars, num);
- if (num2 == -1)
- {
- break;
- }
- if (stringBuilder == null)
- {
- stringBuilder = new StringBuilder();
- }
- stringBuilder.Append(str, num, num2 - num);
- stringBuilder.Append(GetEscapeSequence(str[num2]));
- num = num2 + 1;
- }
- if (stringBuilder == null)
- {
- return str;
- }
- stringBuilder.Append(str, num, length - num);
- return stringBuilder.ToString();
- }
-
private void AppendDeviceProperties(StringBuilder builder)
{
builder.Append("<dlna:X_DLNACAP/>");
@@ -182,32 +113,54 @@ namespace Emby.Dlna.Server
builder.Append("<deviceType>urn:schemas-upnp-org:device:MediaServer:1</deviceType>");
- builder.Append("<friendlyName>" + Escape(GetFriendlyName()) + "</friendlyName>");
- builder.Append("<manufacturer>" + Escape(_profile.Manufacturer ?? string.Empty) + "</manufacturer>");
- builder.Append("<manufacturerURL>" + Escape(_profile.ManufacturerUrl ?? string.Empty) + "</manufacturerURL>");
-
- builder.Append("<modelDescription>" + Escape(_profile.ModelDescription ?? string.Empty) + "</modelDescription>");
- builder.Append("<modelName>" + Escape(_profile.ModelName ?? string.Empty) + "</modelName>");
-
- builder.Append("<modelNumber>" + Escape(_profile.ModelNumber ?? string.Empty) + "</modelNumber>");
- builder.Append("<modelURL>" + Escape(_profile.ModelUrl ?? string.Empty) + "</modelURL>");
+ builder.Append("<friendlyName>")
+ .Append(SecurityElement.Escape(GetFriendlyName()))
+ .Append("</friendlyName>");
+ builder.Append("<manufacturer>")
+ .Append(SecurityElement.Escape(_profile.Manufacturer ?? string.Empty))
+ .Append("</manufacturer>");
+ builder.Append("<manufacturerURL>")
+ .Append(SecurityElement.Escape(_profile.ManufacturerUrl ?? string.Empty))
+ .Append("</manufacturerURL>");
+
+ builder.Append("<modelDescription>")
+ .Append(SecurityElement.Escape(_profile.ModelDescription ?? string.Empty))
+ .Append("</modelDescription>");
+ builder.Append("<modelName>")
+ .Append(SecurityElement.Escape(_profile.ModelName ?? string.Empty))
+ .Append("</modelName>");
+
+ builder.Append("<modelNumber>")
+ .Append(SecurityElement.Escape(_profile.ModelNumber ?? string.Empty))
+ .Append("</modelNumber>");
+ builder.Append("<modelURL>")
+ .Append(SecurityElement.Escape(_profile.ModelUrl ?? string.Empty))
+ .Append("</modelURL>");
if (string.IsNullOrEmpty(_profile.SerialNumber))
{
- builder.Append("<serialNumber>" + Escape(_serverId) + "</serialNumber>");
+ builder.Append("<serialNumber>")
+ .Append(SecurityElement.Escape(_serverId))
+ .Append("</serialNumber>");
}
else
{
- builder.Append("<serialNumber>" + Escape(_profile.SerialNumber) + "</serialNumber>");
+ builder.Append("<serialNumber>")
+ .Append(SecurityElement.Escape(_profile.SerialNumber))
+ .Append("</serialNumber>");
}
builder.Append("<UPC/>");
- builder.Append("<UDN>uuid:" + Escape(_serverUdn) + "</UDN>");
+ builder.Append("<UDN>uuid:")
+ .Append(SecurityElement.Escape(_serverUdn))
+ .Append("</UDN>");
if (!string.IsNullOrEmpty(_profile.SonyAggregationFlags))
{
- builder.Append("<av:aggregationFlags xmlns:av=\"urn:schemas-sony-com:av\">" + Escape(_profile.SonyAggregationFlags) + "</av:aggregationFlags>");
+ builder.Append("<av:aggregationFlags xmlns:av=\"urn:schemas-sony-com:av\">")
+ .Append(SecurityElement.Escape(_profile.SonyAggregationFlags))
+ .Append("</av:aggregationFlags>");
}
}
@@ -245,11 +198,21 @@ namespace Emby.Dlna.Server
{
builder.Append("<icon>");
- builder.Append("<mimetype>" + Escape(icon.MimeType ?? string.Empty) + "</mimetype>");
- builder.Append("<width>" + Escape(icon.Width.ToString(_usCulture)) + "</width>");
- builder.Append("<height>" + Escape(icon.Height.ToString(_usCulture)) + "</height>");
- builder.Append("<depth>" + Escape(icon.Depth ?? string.Empty) + "</depth>");
- builder.Append("<url>" + BuildUrl(icon.Url) + "</url>");
+ builder.Append("<mimetype>")
+ .Append(SecurityElement.Escape(icon.MimeType ?? string.Empty))
+ .Append("</mimetype>");
+ builder.Append("<width>")
+ .Append(SecurityElement.Escape(icon.Width.ToString(_usCulture)))
+ .Append("</width>");
+ builder.Append("<height>")
+ .Append(SecurityElement.Escape(icon.Height.ToString(_usCulture)))
+ .Append("</height>");
+ builder.Append("<depth>")
+ .Append(SecurityElement.Escape(icon.Depth ?? string.Empty))
+ .Append("</depth>");
+ builder.Append("<url>")
+ .Append(BuildUrl(icon.Url))
+ .Append("</url>");
builder.Append("</icon>");
}
@@ -265,11 +228,21 @@ namespace Emby.Dlna.Server
{
builder.Append("<service>");
- builder.Append("<serviceType>" + Escape(service.ServiceType ?? string.Empty) + "</serviceType>");
- builder.Append("<serviceId>" + Escape(service.ServiceId ?? string.Empty) + "</serviceId>");
- builder.Append("<SCPDURL>" + BuildUrl(service.ScpdUrl) + "</SCPDURL>");
- builder.Append("<controlURL>" + BuildUrl(service.ControlUrl) + "</controlURL>");
- builder.Append("<eventSubURL>" + BuildUrl(service.EventSubUrl) + "</eventSubURL>");
+ builder.Append("<serviceType>")
+ .Append(SecurityElement.Escape(service.ServiceType ?? string.Empty))
+ .Append("</serviceType>");
+ builder.Append("<serviceId>")
+ .Append(SecurityElement.Escape(service.ServiceId ?? string.Empty))
+ .Append("</serviceId>");
+ builder.Append("<SCPDURL>")
+ .Append(BuildUrl(service.ScpdUrl))
+ .Append("</SCPDURL>");
+ builder.Append("<controlURL>")
+ .Append(BuildUrl(service.ControlUrl))
+ .Append("</controlURL>");
+ builder.Append("<eventSubURL>")
+ .Append(BuildUrl(service.EventSubUrl))
+ .Append("</eventSubURL>");
builder.Append("</service>");
}
@@ -293,7 +266,7 @@ namespace Emby.Dlna.Server
url = _serverAddress.TrimEnd('/') + url;
}
- return Escape(url);
+ return SecurityElement.Escape(url);
}
private IEnumerable<DeviceIcon> GetIcons()
diff --git a/Emby.Dlna/Service/BaseControlHandler.cs b/Emby.Dlna/Service/BaseControlHandler.cs
index 161a3434c5..4b0bbba969 100644
--- a/Emby.Dlna/Service/BaseControlHandler.cs
+++ b/Emby.Dlna/Service/BaseControlHandler.cs
@@ -15,10 +15,7 @@ namespace Emby.Dlna.Service
{
public abstract class BaseControlHandler
{
- private const string NS_SOAPENV = "http://schemas.xmlsoap.org/soap/envelope/";
-
- protected IServerConfigurationManager Config { get; }
- protected ILogger Logger { get; }
+ private const string NsSoapEnv = "http://schemas.xmlsoap.org/soap/envelope/";
protected BaseControlHandler(IServerConfigurationManager config, ILogger logger)
{
@@ -26,6 +23,10 @@ namespace Emby.Dlna.Service
Logger = logger;
}
+ protected IServerConfigurationManager Config { get; }
+
+ protected ILogger Logger { get; }
+
public async Task<ControlResponse> ProcessControlRequestAsync(ControlRequest request)
{
try
@@ -59,10 +60,8 @@ namespace Emby.Dlna.Service
Async = true
};
- using (var reader = XmlReader.Create(streamReader, readerSettings))
- {
- requestInfo = await ParseRequestAsync(reader).ConfigureAwait(false);
- }
+ using var reader = XmlReader.Create(streamReader, readerSettings);
+ requestInfo = await ParseRequestAsync(reader).ConfigureAwait(false);
}
Logger.LogDebug("Received control request {0}", requestInfo.LocalName);
@@ -79,10 +78,10 @@ namespace Emby.Dlna.Service
{
writer.WriteStartDocument(true);
- writer.WriteStartElement("SOAP-ENV", "Envelope", NS_SOAPENV);
- writer.WriteAttributeString(string.Empty, "encodingStyle", NS_SOAPENV, "http://schemas.xmlsoap.org/soap/encoding/");
+ writer.WriteStartElement("SOAP-ENV", "Envelope", NsSoapEnv);
+ writer.WriteAttributeString(string.Empty, "encodingStyle", NsSoapEnv, "http://schemas.xmlsoap.org/soap/encoding/");
- writer.WriteStartElement("SOAP-ENV", "Body", NS_SOAPENV);
+ writer.WriteStartElement("SOAP-ENV", "Body", NsSoapEnv);
writer.WriteStartElement("u", requestInfo.LocalName + "Response", requestInfo.NamespaceURI);
WriteResult(requestInfo.LocalName, requestInfo.Headers, writer);
@@ -123,10 +122,8 @@ namespace Emby.Dlna.Service
{
if (!reader.IsEmptyElement)
{
- using (var subReader = reader.ReadSubtree())
- {
- return await ParseBodyTagAsync(subReader).ConfigureAwait(false);
- }
+ using var subReader = reader.ReadSubtree();
+ return await ParseBodyTagAsync(subReader).ConfigureAwait(false);
}
else
{
@@ -135,6 +132,7 @@ namespace Emby.Dlna.Service
break;
}
+
default:
{
await reader.SkipAsync().ConfigureAwait(false);
@@ -148,12 +146,12 @@ namespace Emby.Dlna.Service
}
}
- return new ControlRequestInfo();
+ throw new EndOfStreamException("Stream ended but no body tag found.");
}
private async Task<ControlRequestInfo> ParseBodyTagAsync(XmlReader reader)
{
- var result = new ControlRequestInfo();
+ string namespaceURI = null, localName = null;
await reader.MoveToContentAsync().ConfigureAwait(false);
await reader.ReadAsync().ConfigureAwait(false);
@@ -163,16 +161,14 @@ namespace Emby.Dlna.Service
{
if (reader.NodeType == XmlNodeType.Element)
{
- result.LocalName = reader.LocalName;
- result.NamespaceURI = reader.NamespaceURI;
+ localName = reader.LocalName;
+ namespaceURI = reader.NamespaceURI;
if (!reader.IsEmptyElement)
{
- using (var subReader = reader.ReadSubtree())
- {
- await ParseFirstBodyChildAsync(subReader, result.Headers).ConfigureAwait(false);
- return result;
- }
+ var result = new ControlRequestInfo(localName, namespaceURI);
+ using var subReader = reader.ReadSubtree();
+ await ParseFirstBodyChildAsync(subReader, result.Headers).ConfigureAwait(false);
}
else
{
@@ -185,7 +181,12 @@ namespace Emby.Dlna.Service
}
}
- return result;
+ if (localName != null && namespaceURI != null)
+ {
+ return new ControlRequestInfo(localName, namespaceURI);
+ }
+
+ throw new EndOfStreamException("Stream ended but no control found.");
}
private async Task ParseFirstBodyChildAsync(XmlReader reader, IDictionary<string, string> headers)
@@ -208,13 +209,6 @@ namespace Emby.Dlna.Service
}
}
- private class ControlRequestInfo
- {
- public string LocalName { get; set; }
- public string NamespaceURI { get; set; }
- public Dictionary<string, string> Headers { get; } = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
- }
-
protected abstract void WriteResult(string methodName, IDictionary<string, string> methodParams, XmlWriter xmlWriter);
private void LogRequest(ControlRequest request)
@@ -236,5 +230,21 @@ namespace Emby.Dlna.Service
Logger.LogDebug("Control response. Headers: {@Headers}\n{Xml}", response.Headers, response.Xml);
}
+
+ private class ControlRequestInfo
+ {
+ public ControlRequestInfo(string localName, string namespaceUri)
+ {
+ LocalName = localName;
+ NamespaceURI = namespaceUri;
+ Headers = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
+ }
+
+ public string LocalName { get; set; }
+
+ public string NamespaceURI { get; set; }
+
+ public Dictionary<string, string> Headers { get; }
+ }
}
}
diff --git a/Emby.Dlna/Service/BaseService.cs b/Emby.Dlna/Service/BaseService.cs
index 3704bedcd5..a97c4d63a6 100644
--- a/Emby.Dlna/Service/BaseService.cs
+++ b/Emby.Dlna/Service/BaseService.cs
@@ -1,25 +1,23 @@
#pragma warning disable CS1591
+using System.Net.Http;
using Emby.Dlna.Eventing;
-using MediaBrowser.Common.Net;
using Microsoft.Extensions.Logging;
namespace Emby.Dlna.Service
{
- public class BaseService : IEventManager
+ public class BaseService : IDlnaEventManager
{
- protected IEventManager EventManager;
- protected IHttpClient HttpClient;
- protected ILogger Logger;
-
- protected BaseService(ILogger<BaseService> logger, IHttpClient httpClient)
+ protected BaseService(ILogger<BaseService> logger, IHttpClientFactory httpClientFactory)
{
Logger = logger;
- HttpClient = httpClient;
-
- EventManager = new EventManager(Logger, HttpClient);
+ EventManager = new DlnaEventManager(logger, httpClientFactory);
}
+ protected IDlnaEventManager EventManager { get; }
+
+ protected ILogger Logger { get; }
+
public EventSubscriptionResponse CancelEventSubscription(string subscriptionId)
{
return EventManager.CancelEventSubscription(subscriptionId);
diff --git a/Emby.Dlna/Service/ControlErrorHandler.cs b/Emby.Dlna/Service/ControlErrorHandler.cs
index 047e9f0142..f2b5dd9ca8 100644
--- a/Emby.Dlna/Service/ControlErrorHandler.cs
+++ b/Emby.Dlna/Service/ControlErrorHandler.cs
@@ -10,7 +10,7 @@ namespace Emby.Dlna.Service
{
public static class ControlErrorHandler
{
- private const string NS_SOAPENV = "http://schemas.xmlsoap.org/soap/envelope/";
+ private const string NsSoapEnv = "http://schemas.xmlsoap.org/soap/envelope/";
public static ControlResponse GetResponse(Exception ex)
{
@@ -26,11 +26,11 @@ namespace Emby.Dlna.Service
{
writer.WriteStartDocument(true);
- writer.WriteStartElement("SOAP-ENV", "Envelope", NS_SOAPENV);
- writer.WriteAttributeString(string.Empty, "encodingStyle", NS_SOAPENV, "http://schemas.xmlsoap.org/soap/encoding/");
+ writer.WriteStartElement("SOAP-ENV", "Envelope", NsSoapEnv);
+ writer.WriteAttributeString(string.Empty, "encodingStyle", NsSoapEnv, "http://schemas.xmlsoap.org/soap/encoding/");
- writer.WriteStartElement("SOAP-ENV", "Body", NS_SOAPENV);
- writer.WriteStartElement("SOAP-ENV", "Fault", NS_SOAPENV);
+ writer.WriteStartElement("SOAP-ENV", "Body", NsSoapEnv);
+ writer.WriteStartElement("SOAP-ENV", "Fault", NsSoapEnv);
writer.WriteElementString("faultcode", "500");
writer.WriteElementString("faultstring", ex.Message);
diff --git a/Emby.Dlna/Service/ServiceXmlBuilder.cs b/Emby.Dlna/Service/ServiceXmlBuilder.cs
index 62ffd9e42a..1e56d09b29 100644
--- a/Emby.Dlna/Service/ServiceXmlBuilder.cs
+++ b/Emby.Dlna/Service/ServiceXmlBuilder.cs
@@ -1,9 +1,9 @@
#pragma warning disable CS1591
using System.Collections.Generic;
+using System.Security;
using System.Text;
using Emby.Dlna.Common;
-using Emby.Dlna.Server;
namespace Emby.Dlna.Service
{
@@ -37,7 +37,9 @@ namespace Emby.Dlna.Service
{
builder.Append("<action>");
- builder.Append("<name>" + DescriptionXmlBuilder.Escape(item.Name ?? string.Empty) + "</name>");
+ builder.Append("<name>")
+ .Append(SecurityElement.Escape(item.Name ?? string.Empty))
+ .Append("</name>");
builder.Append("<argumentList>");
@@ -45,9 +47,15 @@ namespace Emby.Dlna.Service
{
builder.Append("<argument>");
- builder.Append("<name>" + DescriptionXmlBuilder.Escape(argument.Name ?? string.Empty) + "</name>");
- builder.Append("<direction>" + DescriptionXmlBuilder.Escape(argument.Direction ?? string.Empty) + "</direction>");
- builder.Append("<relatedStateVariable>" + DescriptionXmlBuilder.Escape(argument.RelatedStateVariable ?? string.Empty) + "</relatedStateVariable>");
+ builder.Append("<name>")
+ .Append(SecurityElement.Escape(argument.Name ?? string.Empty))
+ .Append("</name>");
+ builder.Append("<direction>")
+ .Append(SecurityElement.Escape(argument.Direction ?? string.Empty))
+ .Append("</direction>");
+ builder.Append("<relatedStateVariable>")
+ .Append(SecurityElement.Escape(argument.RelatedStateVariable ?? string.Empty))
+ .Append("</relatedStateVariable>");
builder.Append("</argument>");
}
@@ -68,18 +76,27 @@ namespace Emby.Dlna.Service
{
var sendEvents = item.SendsEvents ? "yes" : "no";
- builder.Append("<stateVariable sendEvents=\"" + sendEvents + "\">");
+ builder.Append("<stateVariable sendEvents=\"")
+ .Append(sendEvents)
+ .Append("\">");
- builder.Append("<name>" + DescriptionXmlBuilder.Escape(item.Name ?? string.Empty) + "</name>");
- builder.Append("<dataType>" + DescriptionXmlBuilder.Escape(item.DataType ?? string.Empty) + "</dataType>");
+ builder.Append("<name>")
+ .Append(SecurityElement.Escape(item.Name ?? string.Empty))
+ .Append("</name>");
+ builder.Append("<dataType>")
+ .Append(SecurityElement.Escape(item.DataType ?? string.Empty))
+ .Append("</dataType>");
- if (item.AllowedValues.Length > 0)
+ if (item.AllowedValues.Count > 0)
{
builder.Append("<allowedValueList>");
foreach (var allowedValue in item.AllowedValues)
{
- builder.Append("<allowedValue>" + DescriptionXmlBuilder.Escape(allowedValue) + "</allowedValue>");
+ builder.Append("<allowedValue>")
+ .Append(SecurityElement.Escape(allowedValue))
+ .Append("</allowedValue>");
}
+
builder.Append("</allowedValueList>");
}
diff --git a/Emby.Dlna/Ssdp/DeviceDiscovery.cs b/Emby.Dlna/Ssdp/DeviceDiscovery.cs
index f95b8ce7de..8c7d961f3e 100644
--- a/Emby.Dlna/Ssdp/DeviceDiscovery.cs
+++ b/Emby.Dlna/Ssdp/DeviceDiscovery.cs
@@ -3,9 +3,9 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using Jellyfin.Data.Events;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Model.Dlna;
-using MediaBrowser.Model.Events;
using Rssdp;
using Rssdp.Infrastructure;
@@ -17,9 +17,17 @@ namespace Emby.Dlna.Ssdp
private readonly IServerConfigurationManager _config;
+ private SsdpDeviceLocator _deviceLocator;
+ private ISsdpCommunicationsServer _commsServer;
+
private int _listenerCount;
private bool _disposed;
+ public DeviceDiscovery(IServerConfigurationManager config)
+ {
+ _config = config;
+ }
+
private event EventHandler<GenericEventArgs<UpnpDeviceInfo>> DeviceDiscoveredInternal;
/// <inheritdoc />
@@ -49,15 +57,6 @@ namespace Emby.Dlna.Ssdp
/// <inheritdoc />
public event EventHandler<GenericEventArgs<UpnpDeviceInfo>> DeviceLeft;
- private SsdpDeviceLocator _deviceLocator;
-
- private ISsdpCommunicationsServer _commsServer;
-
- public DeviceDiscovery(IServerConfigurationManager config)
- {
- _config = config;
- }
-
// Call this method from somewhere in your code to start the search.
public void Start(ISsdpCommunicationsServer communicationsServer)
{
@@ -77,7 +76,7 @@ namespace Emby.Dlna.Ssdp
// (Optional) Set the filter so we only see notifications for devices we care about
// (can be any search target value i.e device type, uuid value etc - any value that appears in the
// DiscoverdSsdpDevice.NotificationType property or that is used with the searchTarget parameter of the Search method).
- //_DeviceLocator.NotificationFilter = "upnp:rootdevice";
+ // _DeviceLocator.NotificationFilter = "upnp:rootdevice";
// Connect our event handler so we process devices as they are found
_deviceLocator.DeviceAvailable += OnDeviceLocatorDeviceAvailable;
@@ -100,15 +99,13 @@ namespace Emby.Dlna.Ssdp
var headers = headerDict.ToDictionary(i => i.Key, i => i.Value.Value.FirstOrDefault(), StringComparer.OrdinalIgnoreCase);
- var args = new GenericEventArgs<UpnpDeviceInfo>
- {
- Argument = new UpnpDeviceInfo
+ var args = new GenericEventArgs<UpnpDeviceInfo>(
+ new UpnpDeviceInfo
{
Location = e.DiscoveredDevice.DescriptionLocation,
Headers = headers,
LocalIpAddress = e.LocalIpAddress
- }
- };
+ });
DeviceDiscoveredInternal?.Invoke(this, args);
}
@@ -121,14 +118,12 @@ namespace Emby.Dlna.Ssdp
var headers = headerDict.ToDictionary(i => i.Key, i => i.Value.Value.FirstOrDefault(), StringComparer.OrdinalIgnoreCase);
- var args = new GenericEventArgs<UpnpDeviceInfo>
- {
- Argument = new UpnpDeviceInfo
+ var args = new GenericEventArgs<UpnpDeviceInfo>(
+ new UpnpDeviceInfo
{
Location = e.DiscoveredDevice.DescriptionLocation,
Headers = headers
- }
- };
+ });
DeviceLeft?.Invoke(this, args);
}
diff --git a/Emby.Dlna/Ssdp/Extensions.cs b/Emby.Dlna/Ssdp/SsdpExtensions.cs
index 10c1f321be..e7a52f168f 100644
--- a/Emby.Dlna/Ssdp/Extensions.cs
+++ b/Emby.Dlna/Ssdp/SsdpExtensions.cs
@@ -1,33 +1,27 @@
#pragma warning disable CS1591
+using System.Linq;
using System.Xml.Linq;
namespace Emby.Dlna.Ssdp
{
- public static class Extensions
+ public static class SsdpExtensions
{
public static string GetValue(this XElement container, XName name)
{
var node = container.Element(name);
- return node == null ? null : node.Value;
+ return node?.Value;
}
public static string GetAttributeValue(this XElement container, XName name)
{
var node = container.Attribute(name);
- return node == null ? null : node.Value;
+ return node?.Value;
}
public static string GetDescendantValue(this XElement container, XName name)
- {
- foreach (var node in container.Descendants(name))
- {
- return node.Value;
- }
-
- return null;
- }
+ => container.Descendants(name).FirstOrDefault()?.Value;
}
}