diff options
85 files changed, 1116 insertions, 1020 deletions
diff --git a/Emby.Dlna/Common/ServiceAction.cs b/Emby.Dlna/Common/ServiceAction.cs index db4f27063..d458d7f3f 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 a2c2bf5dd..6daf7ab6b 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 dba901967..fc02e1751 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 e32cc11bf..12338e2b4 100644 --- a/Emby.Dlna/ConnectionManager/ConnectionManager.cs +++ b/Emby.Dlna/ConnectionManager/ConnectionManagerService.cs @@ -9,22 +9,20 @@ 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, + ILogger<ConnectionManagerService> logger, IHttpClient httpClient) : base(logger, httpClient) { _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 b31d437c3..c8db5a367 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 b1ce7e8ec..72732823a 100644 --- a/Emby.Dlna/ContentDirectory/ContentDirectory.cs +++ b/Emby.Dlna/ContentDirectory/ContentDirectoryService.cs @@ -19,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; @@ -33,14 +33,14 @@ namespace Emby.Dlna.ContentDirectory private readonly IMediaEncoder _mediaEncoder; private readonly ITVSeriesManager _tvSeriesManager; - public ContentDirectory( + public ContentDirectoryService( IDlnaManager dlna, IUserDataManager userDataManager, IImageProcessor imageProcessor, ILibraryManager libraryManager, IServerConfigurationManager config, IUserManager userManager, - ILogger<ContentDirectory> logger, + ILogger<ContentDirectoryService> logger, IHttpClient httpClient, ILocalizationManager localization, IMediaSourceManager mediaSourceManager, diff --git a/Emby.Dlna/ContentDirectory/ContentDirectoryXmlBuilder.cs b/Emby.Dlna/ContentDirectory/ContentDirectoryXmlBuilder.cs index 6db4d7cb6..743dcc516 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 00821bf78..be1ed7872 100644 --- a/Emby.Dlna/ContentDirectory/ControlHandler.cs +++ b/Emby.Dlna/ContentDirectory/ControlHandler.cs @@ -40,6 +40,11 @@ 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; @@ -47,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; @@ -181,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); } @@ -253,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; @@ -286,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; @@ -362,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 @@ -397,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); @@ -783,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) @@ -1135,14 +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[] { nameof(Audio) }, - ParentId = parent?.Id ?? Guid.Empty, - 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); } @@ -1151,12 +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); } @@ -1165,14 +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); } @@ -1183,13 +1196,14 @@ namespace Emby.Dlna.ContentDirectory 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(); + { + 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); } @@ -1354,44 +1368,4 @@ namespace Emby.Dlna.ContentDirectory 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 000000000..e40605414 --- /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 000000000..eee405d3e --- /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 a6e03b7e6..4ea4e4e48 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 243b09786..d827eef26 100644 --- a/Emby.Dlna/ControlResponse.cs +++ b/Emby.Dlna/ControlResponse.cs @@ -11,7 +11,7 @@ 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; } diff --git a/Emby.Dlna/Didl/DidlBuilder.cs b/Emby.Dlna/Didl/DidlBuilder.cs index 70e358019..bd09a8051 100644 --- a/Emby.Dlna/Didl/DidlBuilder.cs +++ b/Emby.Dlna/Didl/DidlBuilder.cs @@ -34,12 +34,12 @@ 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; @@ -100,11 +100,11 @@ namespace Emby.Dlna.Didl { // 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); + 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); @@ -147,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); @@ -207,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, @@ -279,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:*"); @@ -288,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}:*", @@ -304,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)); @@ -526,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) { @@ -583,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, @@ -596,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, @@ -627,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"); @@ -714,7 +717,7 @@ namespace Emby.Dlna.Didl // MediaMonkey for example won't display content without a 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); @@ -723,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); } } @@ -731,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)) @@ -748,28 +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 (!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); } } @@ -781,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) { @@ -882,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); } } @@ -896,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) @@ -917,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); } } } @@ -935,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); @@ -971,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) { @@ -1021,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); @@ -1043,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(); } @@ -1139,7 +1143,6 @@ namespace Emby.Dlna.Didl if (width == 0 || height == 0) { - // _imageProcessor.GetImageSize(item, imageInfo); width = null; height = null; } @@ -1149,18 +1152,6 @@ namespace Emby.Dlna.Didl 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); @@ -1177,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); @@ -1218,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, @@ -1256,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 b730d9db2..b58fdff2c 100644 --- a/Emby.Dlna/Didl/Filter.cs +++ b/Emby.Dlna/Didl/Filter.cs @@ -23,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 896fe992b..2b86ea333 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 000000000..4c6ca869a --- /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 ce4be7b51..d5629684c 100644 --- a/Emby.Dlna/DlnaManager.cs +++ b/Emby.Dlna/DlnaManager.cs @@ -495,8 +495,8 @@ namespace Emby.Dlna /// 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). /// </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)) @@ -509,13 +509,6 @@ namespace Emby.Dlna return _jsonSerializer.DeserializeFromString<DeviceProfile>(json); } - private 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) ?? @@ -540,7 +533,15 @@ namespace Emby.Dlna Stream = _assembly.GetManifestResourceStream(resource) }; } + + private class InternalProfileInfo + { + internal DeviceProfileInfo Info { get; set; } + + internal string Path { get; set; } + } } + /* class DlnaProfileEntryPoint : IServerEntryPoint { diff --git a/Emby.Dlna/Emby.Dlna.csproj b/Emby.Dlna/Emby.Dlna.csproj index 42a5f95c1..8538f580c 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--> diff --git a/Emby.Dlna/EventSubscriptionResponse.cs b/Emby.Dlna/EventSubscriptionResponse.cs index fd18343e6..1b1bd426c 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/EventManager.cs index 7d02f5e96..cc8e0ae06 100644 --- a/Emby.Dlna/Eventing/EventManager.cs +++ b/Emby.Dlna/Eventing/EventManager.cs @@ -22,6 +22,8 @@ namespace Emby.Dlna.Eventing private readonly ILogger _logger; private readonly IHttpClient _httpClient; + private readonly CultureInfo _usCulture = new CultureInfo("en-US"); + public EventManager(ILogger logger, IHttpClient httpClient) { _httpClient = httpClient; @@ -58,7 +60,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); @@ -94,7 +97,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 { @@ -103,7 +106,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 diff --git a/Emby.Dlna/IEventManager.cs b/Emby.Dlna/IEventManager.cs index 287203389..de87b0709 100644 --- a/Emby.Dlna/IEventManager.cs +++ b/Emby.Dlna/IEventManager.cs @@ -8,16 +8,26 @@ namespace Emby.Dlna /// 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/Main/DlnaEntryPoint.cs b/Emby.Dlna/Main/DlnaEntryPoint.cs index a21d4cc11..0ad82022d 100644 --- a/Emby.Dlna/Main/DlnaEntryPoint.cs +++ b/Emby.Dlna/Main/DlnaEntryPoint.cs @@ -30,7 +30,7 @@ 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<DlnaEntryPoint> _logger; @@ -54,13 +54,7 @@ namespace Emby.Dlna.Main private SsdpDevicePublisher _publisher; private ISsdpCommunicationsServer _communicationsServer; - public IContentDirectory ContentDirectory { get; private set; } - - public IConnectionManager ConnectionManager { get; private set; } - - public IMediaReceiverRegistrar MediaReceiverRegistrar { get; private set; } - - public static DlnaEntryPoint Current; + private bool _disposed; public DlnaEntryPoint( IServerConfigurationManager config, @@ -99,14 +93,14 @@ namespace Emby.Dlna.Main _networkManager = networkManager; _logger = loggerFactory.CreateLogger<DlnaEntryPoint>(); - ContentDirectory = new ContentDirectory.ContentDirectory( + ContentDirectory = new ContentDirectory.ContentDirectoryService( dlnaManager, userDataManager, imageProcessor, libraryManager, config, userManager, - loggerFactory.CreateLogger<ContentDirectory.ContentDirectory>(), + loggerFactory.CreateLogger<ContentDirectory.ContentDirectoryService>(), httpClient, localizationManager, mediaSourceManager, @@ -114,19 +108,27 @@ namespace Emby.Dlna.Main mediaEncoder, tvSeriesManager); - ConnectionManager = new ConnectionManager.ConnectionManager( + ConnectionManager = new ConnectionManager.ConnectionManagerService( dlnaManager, config, - loggerFactory.CreateLogger<ConnectionManager.ConnectionManager>(), + loggerFactory.CreateLogger<ConnectionManager.ConnectionManagerService>(), httpClient); - MediaReceiverRegistrar = new MediaReceiverRegistrar.MediaReceiverRegistrar( - loggerFactory.CreateLogger<MediaReceiverRegistrar.MediaReceiverRegistrar>(), + MediaReceiverRegistrar = new MediaReceiverRegistrar.MediaReceiverRegistrarService( + loggerFactory.CreateLogger<MediaReceiverRegistrar.MediaReceiverRegistrarService>(), httpClient, 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); @@ -399,8 +401,24 @@ namespace Emby.Dlna.Main } } + public void DisposeDevicePublisher() + { + if (_publisher != null) + { + _logger.LogInformation("Disposing SsdpDevicePublisher"); + _publisher.Dispose(); + _publisher = null; + } + } + + /// <inheritdoc /> public void Dispose() { + if (_disposed) + { + return; + } + DisposeDevicePublisher(); DisposePlayToManager(); DisposeDeviceDiscovery(); @@ -416,16 +434,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/MediaReceiverRegistrar.cs b/Emby.Dlna/MediaReceiverRegistrar/MediaReceiverRegistrarService.cs index 64dfc840a..28de2fef5 100644 --- a/Emby.Dlna/MediaReceiverRegistrar/MediaReceiverRegistrar.cs +++ b/Emby.Dlna/MediaReceiverRegistrar/MediaReceiverRegistrarService.cs @@ -8,12 +8,12 @@ using Microsoft.Extensions.Logging; namespace Emby.Dlna.MediaReceiverRegistrar { - public class MediaReceiverRegistrar : BaseService, IMediaReceiverRegistrar + public class MediaReceiverRegistrarService : BaseService, IMediaReceiverRegistrar { private readonly IServerConfigurationManager _config; - public MediaReceiverRegistrar( - ILogger<MediaReceiverRegistrar> logger, + public MediaReceiverRegistrarService( + ILogger<MediaReceiverRegistrarService> logger, IHttpClient httpClient, IServerConfigurationManager config) : base(logger, httpClient) diff --git a/Emby.Dlna/MediaReceiverRegistrar/MediaReceiverRegistrarXmlBuilder.cs b/Emby.Dlna/MediaReceiverRegistrar/MediaReceiverRegistrarXmlBuilder.cs index 849702546..26994925d 100644 --- a/Emby.Dlna/MediaReceiverRegistrar/MediaReceiverRegistrarXmlBuilder.cs +++ b/Emby.Dlna/MediaReceiverRegistrar/MediaReceiverRegistrarXmlBuilder.cs @@ -10,7 +10,8 @@ namespace Emby.Dlna.MediaReceiverRegistrar { public string GetXml() { - return new ServiceXmlBuilder().GetXml(new ServiceActionListBuilder().GetActions(), + return new ServiceXmlBuilder().GetXml( + new ServiceActionListBuilder().GetActions(), GetStateVariables()); } diff --git a/Emby.Dlna/PlayTo/Device.cs b/Emby.Dlna/PlayTo/Device.cs index 86dd52a1b..5462e7abc 100644 --- a/Emby.Dlna/PlayTo/Device.cs +++ b/Emby.Dlna/PlayTo/Device.cs @@ -21,15 +21,38 @@ namespace Emby.Dlna.PlayTo { private static readonly CultureInfo UsCulture = new CultureInfo("en-US"); + private readonly IHttpClient _httpClient; + + 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, IHttpClient httpClient, ILogger logger) + { + Properties = deviceProperties; + _httpClient = httpClient; + _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 @@ -45,26 +68,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; - private readonly IHttpClient _httpClient; + public Action OnDeviceUnavailable { get; set; } - private readonly ILogger _logger; + private TransportCommands AvCommands { get; set; } - public Action OnDeviceUnavailable { get; set; } + private TransportCommands RendererCommands { get; set; } - public Device(DeviceInfo deviceProperties, IHttpClient httpClient, ILogger logger) - { - Properties = deviceProperties; - _httpClient = httpClient; - _logger = logger; - } + public UBaseObject CurrentMediaInfo { get; private set; } public void Start() { @@ -72,8 +90,6 @@ namespace Emby.Dlna.PlayTo _timer = new Timer(TimerCallback, null, 1000, Timeout.Infinite); } - private DateTime _lastVolumeRefresh; - private bool _volumeRefreshActive; private Task RefreshVolumeIfNeeded() { if (_volumeRefreshActive @@ -104,7 +120,6 @@ namespace Emby.Dlna.PlayTo } } - private readonly object _timerLock = new object(); private void RestartTimer(bool immediate = false) { lock (_timerLock) @@ -232,6 +247,9 @@ namespace Emby.Dlna.PlayTo /// <summary> /// 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); @@ -400,13 +418,11 @@ namespace Emby.Dlna.PlayTo await new SsdpHttpClient(_httpClient).SendCommandAsync(Properties.BaseUrl, service, command.Name, avCommands.BuildPost(command, service.ServiceType, 1)) .ConfigureAwait(false); - TransportState = TRANSPORTSTATE.PAUSED; + TransportState = TransportState.Paused; RestartTimer(true); } - private int _connectFailureCount; - private async void TimerCallback(object sender) { if (_disposed) @@ -435,7 +451,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); } @@ -464,7 +480,7 @@ namespace Emby.Dlna.PlayTo } // 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(); } @@ -538,7 +554,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)) @@ -588,14 +604,14 @@ namespace Emby.Dlna.PlayTo 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) @@ -622,12 +638,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; } @@ -635,7 +651,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) @@ -670,7 +686,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; @@ -686,13 +702,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 }; @@ -701,7 +717,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) @@ -730,10 +746,10 @@ 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 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 durationElem = result.Document.Descendants(UPnpNamespaces.AvTransport + "GetPositionInfoResponse").Select(i => i.Element("TrackDuration")).FirstOrDefault(i => i != null); var duration = durationElem?.Value; if (!string.IsNullOrWhiteSpace(duration) @@ -746,7 +762,7 @@ namespace Emby.Dlna.PlayTo Duration = null; } - var positionElem = result.Document.Descendants(uPnpNamespaces.AvTransport + "GetPositionInfoResponse").Select(i => i.Element("RelTime")).FirstOrDefault(i => i != null); + 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)) @@ -786,7 +802,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); @@ -827,26 +843,26 @@ namespace Emby.Dlna.PlayTo 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), + 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), @@ -861,11 +877,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)) { @@ -953,11 +969,7 @@ 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, IHttpClient httpClient, ILogger logger, CancellationToken cancellationToken) { var ssdpHttpClient = new SsdpHttpClient(httpClient); @@ -965,13 +977,13 @@ namespace Emby.Dlna.PlayTo 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); @@ -983,74 +995,74 @@ namespace Emby.Dlna.PlayTo 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; @@ -1077,11 +1089,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); @@ -1098,11 +1110,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 { @@ -1114,14 +1126,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; @@ -1130,7 +1135,7 @@ namespace Emby.Dlna.PlayTo if (previousMediaInfo == null && mediaInfo != null) { - if (state != TRANSPORTSTATE.STOPPED) + if (state != TransportState.Stopped) { OnPlaybackStart(mediaInfo); } @@ -1149,7 +1154,7 @@ namespace Emby.Dlna.PlayTo } } - private void OnPlaybackStart(uBaseObject mediaInfo) + private void OnPlaybackStart(UBaseObject mediaInfo) { if (string.IsNullOrWhiteSpace(mediaInfo.Url)) { @@ -1162,7 +1167,7 @@ namespace Emby.Dlna.PlayTo }); } - private void OnPlaybackProgress(uBaseObject mediaInfo) + private void OnPlaybackProgress(UBaseObject mediaInfo) { if (string.IsNullOrWhiteSpace(mediaInfo.Url)) { @@ -1175,7 +1180,7 @@ namespace Emby.Dlna.PlayTo }); } - private void OnPlaybackStop(uBaseObject mediaInfo) + private void OnPlaybackStop(UBaseObject mediaInfo) { PlaybackStopped?.Invoke(this, new PlaybackStoppedEventArgs { @@ -1183,7 +1188,7 @@ namespace Emby.Dlna.PlayTo }); } - private void OnMediaChanged(uBaseObject old, uBaseObject newMedia) + private void OnMediaChanged(UBaseObject old, UBaseObject newMedia) { MediaChanged?.Invoke(this, new MediaChangedEventArgs { @@ -1192,14 +1197,17 @@ namespace Emby.Dlna.PlayTo }); } - 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) @@ -1218,6 +1226,7 @@ namespace Emby.Dlna.PlayTo _disposed = true; } + /// <inheritdoc /> public override string ToString() { 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 f3aaaebc4..d3daab9e0 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 000000000..dabd079af --- /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 92a93d434..d9e10f459 100644 --- a/Emby.Dlna/PlayTo/PlayToController.cs +++ b/Emby.Dlna/PlayTo/PlayToController.cs @@ -31,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; @@ -50,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; @@ -372,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); @@ -498,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]; } @@ -633,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) @@ -673,48 +684,41 @@ namespace Emby.Dlna.PlayTo case GeneralCommandType.ToggleMute: return _device.ToggleMute(cancellationToken); case GeneralCommandType.SetAudioStreamIndex: + if (command.Arguments.TryGetValue("Index", out string index)) { - if (command.Arguments.TryGetValue("Index", out string arg)) + if (int.TryParse(index, NumberStyles.Integer, _usCulture, out var val)) { - if (int.TryParse(arg, NumberStyles.Integer, _usCulture, out var val)) - { - return SetAudioStreamIndex(val); - } - - throw new ArgumentException("Unsupported SetAudioStreamIndex value supplied."); + return SetAudioStreamIndex(val); } - throw new ArgumentException("SetAudioStreamIndex argument cannot be null"); + throw new ArgumentException("Unsupported SetAudioStreamIndex value supplied."); } + + throw new ArgumentException("SetAudioStreamIndex argument cannot be null"); case GeneralCommandType.SetSubtitleStreamIndex: + if (command.Arguments.TryGetValue("Index", out index)) { - if (command.Arguments.TryGetValue("Index", out string arg)) + if (int.TryParse(index, NumberStyles.Integer, _usCulture, out var val)) { - if (int.TryParse(arg, NumberStyles.Integer, _usCulture, out var val)) - { - return SetSubtitleStreamIndex(val); - } - - throw new ArgumentException("Unsupported SetSubtitleStreamIndex value supplied."); + return SetSubtitleStreamIndex(val); } - throw new ArgumentException("SetSubtitleStreamIndex argument cannot be null"); + throw new ArgumentException("Unsupported SetSubtitleStreamIndex value supplied."); } + + throw new ArgumentException("SetSubtitleStreamIndex argument cannot be null"); case GeneralCommandType.SetVolume: + if (command.Arguments.TryGetValue("Volume", out string vol)) { - if (command.Arguments.TryGetValue("Volume", out string arg)) + if (int.TryParse(vol, NumberStyles.Integer, _usCulture, out var volume)) { - if (int.TryParse(arg, NumberStyles.Integer, _usCulture, out var volume)) - { - return _device.SetVolume(volume, cancellationToken); - } - - throw new ArgumentException("Unsupported volume value supplied."); + return _device.SetVolume(volume, cancellationToken); } - throw new ArgumentException("Volume argument cannot be null"); + throw new ArgumentException("Unsupported volume value supplied."); } + throw new ArgumentException("Volume argument cannot be null"); default: return Task.CompletedTask; } @@ -778,7 +782,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; @@ -787,8 +791,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>(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; + } + private class StreamParams { + private MediaSourceInfo mediaSource; + private IMediaSourceManager _mediaSourceManager; + public Guid ItemId { get; set; } public bool IsDirectStream { get; set; } @@ -809,15 +872,11 @@ namespace Emby.Dlna.PlayTo 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; @@ -827,9 +886,9 @@ namespace Emby.Dlna.PlayTo return null; } - MediaSource = await _mediaSourceManager.GetMediaSource(Item, MediaSourceId, LiveStreamId, false, cancellationToken).ConfigureAwait(false); + mediaSource = await _mediaSourceManager.GetMediaSource(Item, MediaSourceId, LiveStreamId, false, cancellationToken).ConfigureAwait(false); - return MediaSource; + return mediaSource; } private static Guid GetItemId(string url) @@ -901,61 +960,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 512589e4d..54f4fee05 100644 --- a/Emby.Dlna/PlayTo/PlayToManager.cs +++ b/Emby.Dlna/PlayTo/PlayToManager.cs @@ -92,7 +92,7 @@ namespace Emby.Dlna.PlayTo // 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); return; @@ -174,7 +174,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, _httpClient, _logger, cancellationToken).ConfigureAwait(false); string deviceName = device.Properties.Name; @@ -192,20 +192,20 @@ namespace Emby.Dlna.PlayTo controller = new PlayToController( sessionInfo, - _sessionManager, - _libraryManager, - _logger, - _dlnaManager, - _userManager, - _imageProcessor, - serverAddress, - null, - _deviceDiscovery, - _userDataManager, - _localization, - _mediaSourceManager, - _config, - _mediaEncoder); + _sessionManager, + _libraryManager, + _logger, + _dlnaManager, + _userManager, + _imageProcessor, + serverAddress, + null, + _deviceDiscovery, + _userDataManager, + _localization, + _mediaSourceManager, + _config, + _mediaEncoder); sessionInfo.AddController(controller); @@ -218,17 +218,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.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() }, SupportsMediaControl = true @@ -247,8 +247,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 795618df2..d14617c8a 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 27883ca32..3f8d55263 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 fa42b80e8..deeb47918 100644 --- a/Emby.Dlna/PlayTo/PlaybackStoppedEventArgs.cs +++ b/Emby.Dlna/PlayTo/PlaybackStoppedEventArgs.cs @@ -6,13 +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/TRANSPORTSTATE.cs b/Emby.Dlna/PlayTo/TRANSPORTSTATE.cs deleted file mode 100644 index 7daefeca8..000000000 --- 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 dc797a691..fda17a8b4 100644 --- a/Emby.Dlna/PlayTo/TransportCommands.cs +++ b/Emby.Dlna/PlayTo/TransportCommands.cs @@ -16,34 +16,26 @@ namespace Emby.Dlna.PlayTo private List<StateVariable> _stateVariables = new List<StateVariable>(); private List<ServiceAction> _serviceActions = new List<ServiceAction>(); - public List<StateVariable> StateVariables - { - get => _stateVariables; - set => _stateVariables = value; - } + public List<StateVariable> StateVariables => _stateVariables; - public List<ServiceAction> ServiceActions - { - get => _serviceActions; - set => _serviceActions = value; - } + 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)); } @@ -54,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"), + }; + + var argumentList = serviceAction.ArgumentList; - foreach (var arg in container.Descendants(uPnpNamespaces.svc + "argument")) + 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) @@ -78,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() }; } @@ -183,8 +175,7 @@ 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(CultureInfo.InvariantCulture, "<{0} xmlns:dt=\"urn:schemas-microsoft-com:datatypes\" dt:dt=\"{1}\">{2}</{0}>", argument.Name, state.DataType ?? "string", sendValue); } diff --git a/Emby.Dlna/PlayTo/TransportState.cs b/Emby.Dlna/PlayTo/TransportState.cs new file mode 100644 index 000000000..7068a5d24 --- /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 e2d7a10f0..05f27603f 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 05c19299f..0d9478e42 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 @@ -58,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 dc65cdf43..5042d4493 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 90a23a4a2..d4af72b62 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 } }; diff --git a/Emby.Dlna/Profiles/DishHopperJoeyProfile.cs b/Emby.Dlna/Profiles/DishHopperJoeyProfile.cs index 942e36930..2a7524a6a 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/LgTvProfile.cs b/Emby.Dlna/Profiles/LgTvProfile.cs index 02301764c..fbb368d3e 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 1b1423520..1a510dfec 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/PanasonicVieraProfile.cs b/Emby.Dlna/Profiles/PanasonicVieraProfile.cs index 44c35e142..0d536acf3 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 9e9f6966f..7fbf8c164 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 4ff2ab9be..ddbebba2a 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 238fe9f6b..765c12504 100644 --- a/Emby.Dlna/Profiles/SonyBlurayPlayer2013.cs +++ b/Emby.Dlna/Profiles/SonyBlurayPlayer2013.cs @@ -150,7 +150,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 { @@ -197,7 +197,7 @@ namespace Emby.Dlna.Profiles { Type = DlnaProfileType.Photo, - Conditions = new [] + Conditions = new[] { new ProfileCondition { diff --git a/Emby.Dlna/Profiles/SonyBlurayPlayer2014.cs b/Emby.Dlna/Profiles/SonyBlurayPlayer2014.cs index 812a48151..390c8a3e4 100644 --- a/Emby.Dlna/Profiles/SonyBlurayPlayer2014.cs +++ b/Emby.Dlna/Profiles/SonyBlurayPlayer2014.cs @@ -150,7 +150,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 { @@ -197,7 +197,7 @@ namespace Emby.Dlna.Profiles { Type = DlnaProfileType.Photo, - Conditions = new [] + Conditions = new[] { new ProfileCondition { diff --git a/Emby.Dlna/Profiles/SonyBlurayPlayer2015.cs b/Emby.Dlna/Profiles/SonyBlurayPlayer2015.cs index 6bfff322e..25adc4d02 100644 --- a/Emby.Dlna/Profiles/SonyBlurayPlayer2015.cs +++ b/Emby.Dlna/Profiles/SonyBlurayPlayer2015.cs @@ -138,7 +138,7 @@ namespace Emby.Dlna.Profiles { Type = CodecType.Video, Codec = "h264", - Conditions = new [] + Conditions = new[] { new ProfileCondition { @@ -166,7 +166,7 @@ namespace Emby.Dlna.Profiles { Type = CodecType.VideoAudio, Codec = "ac3", - Conditions = new [] + Conditions = new[] { new ProfileCondition { @@ -185,7 +185,7 @@ namespace Emby.Dlna.Profiles { Type = DlnaProfileType.Photo, - Conditions = new [] + Conditions = new[] { new ProfileCondition { diff --git a/Emby.Dlna/Profiles/SonyBlurayPlayer2016.cs b/Emby.Dlna/Profiles/SonyBlurayPlayer2016.cs index ec2529574..0a39a5f40 100644 --- a/Emby.Dlna/Profiles/SonyBlurayPlayer2016.cs +++ b/Emby.Dlna/Profiles/SonyBlurayPlayer2016.cs @@ -138,7 +138,7 @@ namespace Emby.Dlna.Profiles { Type = CodecType.Video, Codec = "h264", - Conditions = new [] + Conditions = new[] { new ProfileCondition { @@ -166,7 +166,7 @@ namespace Emby.Dlna.Profiles { Type = CodecType.VideoAudio, Codec = "ac3", - Conditions = new [] + Conditions = new[] { new ProfileCondition { @@ -185,7 +185,7 @@ namespace Emby.Dlna.Profiles { Type = DlnaProfileType.Photo, - Conditions = new [] + Conditions = new[] { new ProfileCondition { diff --git a/Emby.Dlna/Profiles/SonyBlurayPlayerProfile.cs b/Emby.Dlna/Profiles/SonyBlurayPlayerProfile.cs index ecdd2e7a4..05c8ab1c1 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 68365ba4a..8ab4acd1b 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 b34af04a5..42d253394 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 0e75d0cb5..0598e8342 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 3300863c9..3d90a1e72 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 4e833441c..9188f73ef 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 7f72356bd..d56b1df50 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 411bfe2b0..db56094e2 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 2de9a8cd9..937ca0f42 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 2cbe4e6ac..84d8184a2 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/Service/BaseControlHandler.cs b/Emby.Dlna/Service/BaseControlHandler.cs index 699d325ea..d160e3339 100644 --- a/Emby.Dlna/Service/BaseControlHandler.cs +++ b/Emby.Dlna/Service/BaseControlHandler.cs @@ -15,11 +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) { @@ -27,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 @@ -80,10 +80,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); @@ -210,15 +210,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) @@ -240,5 +231,14 @@ namespace Emby.Dlna.Service Logger.LogDebug("Control response. Headers: {@Headers}\n{Xml}", response.Headers, response.Xml); } + + 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); + } } } diff --git a/Emby.Dlna/Service/BaseService.cs b/Emby.Dlna/Service/BaseService.cs index 8794ec26a..3ad1ea9e0 100644 --- a/Emby.Dlna/Service/BaseService.cs +++ b/Emby.Dlna/Service/BaseService.cs @@ -8,10 +8,6 @@ namespace Emby.Dlna.Service { public class BaseService : IEventManager { - protected IEventManager EventManager; - protected IHttpClient HttpClient; - protected ILogger Logger; - protected BaseService(ILogger<BaseService> logger, IHttpClient httpClient) { Logger = logger; @@ -20,6 +16,12 @@ namespace Emby.Dlna.Service EventManager = new EventManager(logger, HttpClient); } + protected IEventManager EventManager { get; } + + protected IHttpClient HttpClient { 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 047e9f014..f2b5dd9ca 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 6c7d6f846..1e56d09b2 100644 --- a/Emby.Dlna/Service/ServiceXmlBuilder.cs +++ b/Emby.Dlna/Service/ServiceXmlBuilder.cs @@ -87,7 +87,7 @@ namespace Emby.Dlna.Service .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) diff --git a/Emby.Dlna/Ssdp/DeviceDiscovery.cs b/Emby.Dlna/Ssdp/DeviceDiscovery.cs index 7daac96d1..7c4c0f6d9 100644 --- a/Emby.Dlna/Ssdp/DeviceDiscovery.cs +++ b/Emby.Dlna/Ssdp/DeviceDiscovery.cs @@ -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) { diff --git a/Emby.Dlna/Ssdp/Extensions.cs b/Emby.Dlna/Ssdp/SsdpExtensions.cs index 613d332b2..e7a52f168 100644 --- a/Emby.Dlna/Ssdp/Extensions.cs +++ b/Emby.Dlna/Ssdp/SsdpExtensions.cs @@ -5,7 +5,7 @@ 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) { diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs index 331ffc134..5bf740cfc 100644 --- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs @@ -4308,7 +4308,7 @@ namespace Emby.Server.Implementations.Data whereClauses.Add("ProductionYear=@Years"); if (statement != null) { - statement.TryBind("@Years", query.Years[0].ToString()); + statement.TryBind("@Years", query.Years[0].ToString(CultureInfo.InvariantCulture)); } } else if (query.Years.Length > 1) @@ -5170,7 +5170,10 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type insertText.Append(','); } - insertText.AppendFormat("(@ItemId, @AncestorId{0}, @AncestorIdText{0})", i.ToString(CultureInfo.InvariantCulture)); + insertText.AppendFormat( + CultureInfo.InvariantCulture, + "(@ItemId, @AncestorId{0}, @AncestorIdText{0})", + i.ToString(CultureInfo.InvariantCulture)); } using (var statement = PrepareStatement(db, insertText.ToString())) diff --git a/Emby.Server.Implementations/IO/LibraryMonitor.cs b/Emby.Server.Implementations/IO/LibraryMonitor.cs index a32b03aaa..9290dfcd0 100644 --- a/Emby.Server.Implementations/IO/LibraryMonitor.cs +++ b/Emby.Server.Implementations/IO/LibraryMonitor.cs @@ -6,12 +6,11 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading.Tasks; +using Emby.Server.Implementations.Library; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; -using MediaBrowser.Controller.Plugins; using MediaBrowser.Model.IO; -using Emby.Server.Implementations.Library; using Microsoft.Extensions.Logging; namespace Emby.Server.Implementations.IO @@ -38,6 +37,8 @@ namespace Emby.Server.Implementations.IO /// </summary> private readonly ConcurrentDictionary<string, string> _tempIgnoredPaths = new ConcurrentDictionary<string, string>(StringComparer.OrdinalIgnoreCase); + private bool _disposed = false; + /// <summary> /// Add the path to our temporary ignore list. Use when writing to a path within our listening scope. /// </summary> @@ -492,8 +493,6 @@ namespace Emby.Server.Implementations.IO } } - private bool _disposed = false; - /// <summary> /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. /// </summary> @@ -522,24 +521,4 @@ namespace Emby.Server.Implementations.IO _disposed = true; } } - - public class LibraryMonitorStartup : IServerEntryPoint - { - private readonly ILibraryMonitor _monitor; - - public LibraryMonitorStartup(ILibraryMonitor monitor) - { - _monitor = monitor; - } - - public Task RunAsync() - { - _monitor.Start(); - return Task.CompletedTask; - } - - public void Dispose() - { - } - } } diff --git a/Emby.Server.Implementations/IO/LibraryMonitorStartup.cs b/Emby.Server.Implementations/IO/LibraryMonitorStartup.cs new file mode 100644 index 000000000..c51cf0545 --- /dev/null +++ b/Emby.Server.Implementations/IO/LibraryMonitorStartup.cs @@ -0,0 +1,35 @@ +using System.Threading.Tasks; +using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Plugins; + +namespace Emby.Server.Implementations.IO +{ + /// <summary> + /// <see cref="IServerEntryPoint" /> which is responsible for starting the library monitor. + /// </summary> + public sealed class LibraryMonitorStartup : IServerEntryPoint + { + private readonly ILibraryMonitor _monitor; + + /// <summary> + /// Initializes a new instance of the <see cref="LibraryMonitorStartup"/> class. + /// </summary> + /// <param name="monitor">The library monitor.</param> + public LibraryMonitorStartup(ILibraryMonitor monitor) + { + _monitor = monitor; + } + + /// <inheritdoc /> + public Task RunAsync() + { + _monitor.Start(); + return Task.CompletedTask; + } + + /// <inheritdoc /> + public void Dispose() + { + } + } +} diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index 7b770d940..7ed8f0bbf 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -729,7 +729,7 @@ namespace Emby.Server.Implementations.Library Directory.CreateDirectory(rootFolderPath); var rootFolder = GetItemById(GetNewItemId(rootFolderPath, typeof(AggregateFolder))) as AggregateFolder ?? - ((Folder) ResolvePath(_fileSystem.GetDirectoryInfo(rootFolderPath))) + ((Folder)ResolvePath(_fileSystem.GetDirectoryInfo(rootFolderPath))) .DeepCopy<Folder, AggregateFolder>(); // In case program data folder was moved diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EntryPoint.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EntryPoint.cs index 69a9cb78a..a2ec2df37 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/EntryPoint.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EntryPoint.cs @@ -5,7 +5,7 @@ using MediaBrowser.Controller.Plugins; namespace Emby.Server.Implementations.LiveTv.EmbyTV { - public class EntryPoint : IServerEntryPoint + public sealed class EntryPoint : IServerEntryPoint { /// <inheritdoc /> public Task RunAsync() diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs index 77a7069eb..c4d5cc58a 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs @@ -929,7 +929,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings private static string NormalizeName(string value) { - return value.Replace(" ", string.Empty).Replace("-", string.Empty); + return value.Replace(" ", string.Empty, StringComparison.Ordinal).Replace("-", string.Empty, StringComparison.Ordinal); } public class ScheduleDirect diff --git a/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs b/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs index 8a900f42c..1ef083d04 100644 --- a/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs +++ b/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs @@ -10,7 +10,6 @@ using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Progress; using MediaBrowser.Model.Events; -using MediaBrowser.Model.IO; using MediaBrowser.Model.Serialization; using MediaBrowser.Model.Tasks; using Microsoft.Extensions.Logging; @@ -22,37 +21,53 @@ namespace Emby.Server.Implementations.ScheduledTasks /// </summary> public class ScheduledTaskWorker : IScheduledTaskWorker { - public event EventHandler<GenericEventArgs<double>> TaskProgress; - - /// <summary> - /// Gets the scheduled task. - /// </summary> - /// <value>The scheduled task.</value> - public IScheduledTask ScheduledTask { get; private set; } - /// <summary> /// Gets or sets the json serializer. /// </summary> /// <value>The json serializer.</value> - private IJsonSerializer JsonSerializer { get; set; } + private readonly IJsonSerializer _jsonSerializer; /// <summary> /// Gets or sets the application paths. /// </summary> /// <value>The application paths.</value> - private IApplicationPaths ApplicationPaths { get; set; } + private readonly IApplicationPaths _applicationPaths; /// <summary> - /// Gets the logger. + /// Gets or sets the logger. /// </summary> /// <value>The logger.</value> - private ILogger Logger { get; set; } + private readonly ILogger _logger; /// <summary> - /// Gets the task manager. + /// Gets or sets the task manager. /// </summary> /// <value>The task manager.</value> - private ITaskManager TaskManager { get; set; } + private readonly ITaskManager _taskManager; + + /// <summary> + /// The _last execution result sync lock. + /// </summary> + private readonly object _lastExecutionResultSyncLock = new object(); + + private bool _readFromFile = false; + + /// <summary> + /// The _last execution result. + /// </summary> + private TaskResult _lastExecutionResult; + + private Task _currentTask; + + /// <summary> + /// The _triggers. + /// </summary> + private Tuple<TaskTriggerInfo, ITaskTrigger>[] _triggers; + + /// <summary> + /// The _id. + /// </summary> + private string _id; /// <summary> /// Initializes a new instance of the <see cref="ScheduledTaskWorker" /> class. @@ -71,7 +86,7 @@ namespace Emby.Server.Implementations.ScheduledTasks /// or /// jsonSerializer /// or - /// logger + /// logger. /// </exception> public ScheduledTaskWorker(IScheduledTask scheduledTask, IApplicationPaths applicationPaths, ITaskManager taskManager, IJsonSerializer jsonSerializer, ILogger logger) { @@ -101,23 +116,22 @@ namespace Emby.Server.Implementations.ScheduledTasks } ScheduledTask = scheduledTask; - ApplicationPaths = applicationPaths; - TaskManager = taskManager; - JsonSerializer = jsonSerializer; - Logger = logger; + _applicationPaths = applicationPaths; + _taskManager = taskManager; + _jsonSerializer = jsonSerializer; + _logger = logger; InitTriggerEvents(); } - private bool _readFromFile = false; - /// <summary> - /// The _last execution result. - /// </summary> - private TaskResult _lastExecutionResult; + public event EventHandler<GenericEventArgs<double>> TaskProgress; + /// <summary> - /// The _last execution result sync lock. + /// Gets the scheduled task. /// </summary> - private readonly object _lastExecutionResultSyncLock = new object(); + /// <value>The scheduled task.</value> + public IScheduledTask ScheduledTask { get; private set; } + /// <summary> /// Gets the last execution result. /// </summary> @@ -136,11 +150,11 @@ namespace Emby.Server.Implementations.ScheduledTasks { try { - _lastExecutionResult = JsonSerializer.DeserializeFromFile<TaskResult>(path); + _lastExecutionResult = _jsonSerializer.DeserializeFromFile<TaskResult>(path); } catch (Exception ex) { - Logger.LogError(ex, "Error deserializing {File}", path); + _logger.LogError(ex, "Error deserializing {File}", path); } } @@ -160,7 +174,7 @@ namespace Emby.Server.Implementations.ScheduledTasks lock (_lastExecutionResultSyncLock) { - JsonSerializer.SerializeToFile(value, path); + _jsonSerializer.SerializeToFile(value, path); } } } @@ -184,7 +198,7 @@ namespace Emby.Server.Implementations.ScheduledTasks public string Category => ScheduledTask.Category; /// <summary> - /// Gets the current cancellation token. + /// Gets or sets the current cancellation token. /// </summary> /// <value>The current cancellation token source.</value> private CancellationTokenSource CurrentCancellationTokenSource { get; set; } @@ -221,12 +235,7 @@ namespace Emby.Server.Implementations.ScheduledTasks public double? CurrentProgress { get; private set; } /// <summary> - /// The _triggers. - /// </summary> - private Tuple<TaskTriggerInfo, ITaskTrigger>[] _triggers; - - /// <summary> - /// Gets the triggers that define when the task will run. + /// Gets or sets the triggers that define when the task will run. /// </summary> /// <value>The triggers.</value> private Tuple<TaskTriggerInfo, ITaskTrigger>[] InternalTriggers @@ -255,7 +264,7 @@ namespace Emby.Server.Implementations.ScheduledTasks /// Gets the triggers that define when the task will run. /// </summary> /// <value>The triggers.</value> - /// <exception cref="ArgumentNullException">value</exception> + /// <exception cref="ArgumentNullException"><c>value</c> is <c>null</c>.</exception> public TaskTriggerInfo[] Triggers { get @@ -281,11 +290,6 @@ namespace Emby.Server.Implementations.ScheduledTasks } /// <summary> - /// The _id. - /// </summary> - private string _id; - - /// <summary> /// Gets the unique id. /// </summary> /// <value>The unique id.</value> @@ -325,9 +329,9 @@ namespace Emby.Server.Implementations.ScheduledTasks trigger.Stop(); - trigger.Triggered -= trigger_Triggered; - trigger.Triggered += trigger_Triggered; - trigger.Start(LastExecutionResult, Logger, Name, isApplicationStartup); + trigger.Triggered -= OnTriggerTriggered; + trigger.Triggered += OnTriggerTriggered; + trigger.Start(LastExecutionResult, _logger, Name, isApplicationStartup); } } @@ -336,7 +340,7 @@ namespace Emby.Server.Implementations.ScheduledTasks /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">The <see cref="EventArgs" /> instance containing the event data.</param> - async void trigger_Triggered(object sender, EventArgs e) + private async void OnTriggerTriggered(object sender, EventArgs e) { var trigger = (ITaskTrigger)sender; @@ -347,19 +351,17 @@ namespace Emby.Server.Implementations.ScheduledTasks return; } - Logger.LogInformation("{0} fired for task: {1}", trigger.GetType().Name, Name); + _logger.LogInformation("{0} fired for task: {1}", trigger.GetType().Name, Name); trigger.Stop(); - TaskManager.QueueScheduledTask(ScheduledTask, trigger.TaskOptions); + _taskManager.QueueScheduledTask(ScheduledTask, trigger.TaskOptions); await Task.Delay(1000).ConfigureAwait(false); - trigger.Start(LastExecutionResult, Logger, Name, false); + trigger.Start(LastExecutionResult, _logger, Name, false); } - private Task _currentTask; - /// <summary> /// Executes the task. /// </summary> @@ -395,9 +397,9 @@ namespace Emby.Server.Implementations.ScheduledTasks CurrentCancellationTokenSource = new CancellationTokenSource(); - Logger.LogInformation("Executing {0}", Name); + _logger.LogInformation("Executing {0}", Name); - ((TaskManager)TaskManager).OnTaskExecuting(this); + ((TaskManager)_taskManager).OnTaskExecuting(this); progress.ProgressChanged += OnProgressChanged; @@ -423,7 +425,7 @@ namespace Emby.Server.Implementations.ScheduledTasks } catch (Exception ex) { - Logger.LogError(ex, "Error"); + _logger.LogError(ex, "Error"); failureException = ex; @@ -476,7 +478,7 @@ namespace Emby.Server.Implementations.ScheduledTasks { if (State == TaskState.Running) { - Logger.LogInformation("Attempting to cancel Scheduled Task {0}", Name); + _logger.LogInformation("Attempting to cancel Scheduled Task {0}", Name); CurrentCancellationTokenSource.Cancel(); } } @@ -487,7 +489,7 @@ namespace Emby.Server.Implementations.ScheduledTasks /// <returns>System.String.</returns> private string GetScheduledTasksConfigurationDirectory() { - return Path.Combine(ApplicationPaths.ConfigurationDirectoryPath, "ScheduledTasks"); + return Path.Combine(_applicationPaths.ConfigurationDirectoryPath, "ScheduledTasks"); } /// <summary> @@ -496,7 +498,7 @@ namespace Emby.Server.Implementations.ScheduledTasks /// <returns>System.String.</returns> private string GetScheduledTasksDataDirectory() { - return Path.Combine(ApplicationPaths.DataPath, "ScheduledTasks"); + return Path.Combine(_applicationPaths.DataPath, "ScheduledTasks"); } /// <summary> @@ -535,7 +537,7 @@ namespace Emby.Server.Implementations.ScheduledTasks TaskTriggerInfo[] list = null; if (File.Exists(path)) { - list = JsonSerializer.DeserializeFromFile<TaskTriggerInfo[]>(path); + list = _jsonSerializer.DeserializeFromFile<TaskTriggerInfo[]>(path); } // Return defaults if file doesn't exist. @@ -571,7 +573,7 @@ namespace Emby.Server.Implementations.ScheduledTasks Directory.CreateDirectory(Path.GetDirectoryName(path)); - JsonSerializer.SerializeToFile(triggers, path); + _jsonSerializer.SerializeToFile(triggers, path); } /// <summary> @@ -585,7 +587,7 @@ namespace Emby.Server.Implementations.ScheduledTasks { var elapsedTime = endTime - startTime; - Logger.LogInformation("{0} {1} after {2} minute(s) and {3} seconds", Name, status, Math.Truncate(elapsedTime.TotalMinutes), elapsedTime.Seconds); + _logger.LogInformation("{0} {1} after {2} minute(s) and {3} seconds", Name, status, Math.Truncate(elapsedTime.TotalMinutes), elapsedTime.Seconds); var result = new TaskResult { @@ -606,7 +608,7 @@ namespace Emby.Server.Implementations.ScheduledTasks LastExecutionResult = result; - ((TaskManager)TaskManager).OnTaskCompleted(this, result); + ((TaskManager)_taskManager).OnTaskCompleted(this, result); } /// <summary> @@ -615,6 +617,7 @@ namespace Emby.Server.Implementations.ScheduledTasks public void Dispose() { Dispose(true); + GC.SuppressFinalize(this); } /// <summary> @@ -635,12 +638,12 @@ namespace Emby.Server.Implementations.ScheduledTasks { try { - Logger.LogInformation(Name + ": Cancelling"); + _logger.LogInformation(Name + ": Cancelling"); token.Cancel(); } catch (Exception ex) { - Logger.LogError(ex, "Error calling CancellationToken.Cancel();"); + _logger.LogError(ex, "Error calling CancellationToken.Cancel();"); } } @@ -649,21 +652,21 @@ namespace Emby.Server.Implementations.ScheduledTasks { try { - Logger.LogInformation(Name + ": Waiting on Task"); + _logger.LogInformation(Name + ": Waiting on Task"); var exited = Task.WaitAll(new[] { task }, 2000); if (exited) { - Logger.LogInformation(Name + ": Task exited"); + _logger.LogInformation(Name + ": Task exited"); } else { - Logger.LogInformation(Name + ": Timed out waiting for task to stop"); + _logger.LogInformation(Name + ": Timed out waiting for task to stop"); } } catch (Exception ex) { - Logger.LogError(ex, "Error calling Task.WaitAll();"); + _logger.LogError(ex, "Error calling Task.WaitAll();"); } } @@ -671,12 +674,12 @@ namespace Emby.Server.Implementations.ScheduledTasks { try { - Logger.LogDebug(Name + ": Disposing CancellationToken"); + _logger.LogDebug(Name + ": Disposing CancellationToken"); token.Dispose(); } catch (Exception ex) { - Logger.LogError(ex, "Error calling CancellationToken.Dispose();"); + _logger.LogError(ex, "Error calling CancellationToken.Dispose();"); } } @@ -692,8 +695,7 @@ namespace Emby.Server.Implementations.ScheduledTasks /// </summary> /// <param name="info">The info.</param> /// <returns>BaseTaskTrigger.</returns> - /// <exception cref="ArgumentNullException"></exception> - /// <exception cref="ArgumentException">Invalid trigger type: + info.Type</exception> + /// <exception cref="ArgumentException">Invalid trigger type: + info.Type.</exception> private ITaskTrigger GetTrigger(TaskTriggerInfo info) { var options = new TaskOptions @@ -765,7 +767,7 @@ namespace Emby.Server.Implementations.ScheduledTasks foreach (var triggerInfo in InternalTriggers) { var trigger = triggerInfo.Item2; - trigger.Triggered -= trigger_Triggered; + trigger.Triggered -= OnTriggerTriggered; trigger.Stop(); } } diff --git a/Emby.Server.Implementations/ScheduledTasks/TaskManager.cs b/Emby.Server.Implementations/ScheduledTasks/TaskManager.cs index 81096026b..6d2b4ffc8 100644 --- a/Emby.Server.Implementations/ScheduledTasks/TaskManager.cs +++ b/Emby.Server.Implementations/ScheduledTasks/TaskManager.cs @@ -207,6 +207,7 @@ namespace Emby.Server.Implementations.ScheduledTasks public void Dispose() { Dispose(true); + GC.SuppressFinalize(this); } /// <summary> diff --git a/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteLogFileTask.cs b/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteLogFileTask.cs index 402b39a26..54e18eaea 100644 --- a/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteLogFileTask.cs +++ b/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteLogFileTask.cs @@ -1,12 +1,13 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using System.Threading; using System.Threading.Tasks; using MediaBrowser.Common.Configuration; +using MediaBrowser.Model.Globalization; using MediaBrowser.Model.IO; using MediaBrowser.Model.Tasks; -using MediaBrowser.Model.Globalization; namespace Emby.Server.Implementations.ScheduledTasks.Tasks { @@ -15,12 +16,7 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks /// </summary> public class DeleteLogFileTask : IScheduledTask, IConfigurableScheduledTask { - /// <summary> - /// Gets or sets the configuration manager. - /// </summary> - /// <value>The configuration manager.</value> - private IConfigurationManager ConfigurationManager { get; set; } - + private readonly IConfigurationManager _configurationManager; private readonly IFileSystem _fileSystem; private readonly ILocalizationManager _localization; @@ -32,18 +28,43 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks /// <param name="localization">The localization manager.</param> public DeleteLogFileTask(IConfigurationManager configurationManager, IFileSystem fileSystem, ILocalizationManager localization) { - ConfigurationManager = configurationManager; + _configurationManager = configurationManager; _fileSystem = fileSystem; _localization = localization; } + /// <inheritdoc /> + public string Name => _localization.GetLocalizedString("TaskCleanLogs"); + + /// <inheritdoc /> + public string Description => string.Format( + CultureInfo.InvariantCulture, + _localization.GetLocalizedString("TaskCleanLogsDescription"), + _configurationManager.CommonConfiguration.LogFileRetentionDays); + + /// <inheritdoc /> + public string Category => _localization.GetLocalizedString("TasksMaintenanceCategory"); + + /// <inheritdoc /> + public string Key => "CleanLogFiles"; + + /// <inheritdoc /> + public bool IsHidden => false; + + /// <inheritdoc /> + public bool IsEnabled => true; + + /// <inheritdoc /> + public bool IsLogged => true; + /// <summary> /// Creates the triggers that define when the task will run. /// </summary> /// <returns>IEnumerable{BaseTaskTrigger}.</returns> public IEnumerable<TaskTriggerInfo> GetDefaultTriggers() { - return new[] { + return new[] + { new TaskTriggerInfo { Type = TaskTriggerInfo.TriggerInterval, IntervalTicks = TimeSpan.FromHours(24).Ticks} }; } @@ -57,10 +78,10 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks public Task Execute(CancellationToken cancellationToken, IProgress<double> progress) { // Delete log files more than n days old - var minDateModified = DateTime.UtcNow.AddDays(-ConfigurationManager.CommonConfiguration.LogFileRetentionDays); + var minDateModified = DateTime.UtcNow.AddDays(-_configurationManager.CommonConfiguration.LogFileRetentionDays); // Only delete the .txt log files, the *.log files created by serilog get managed by itself - var filesToDelete = _fileSystem.GetFiles(ConfigurationManager.CommonApplicationPaths.LogDirectoryPath, new[] { ".txt" }, true, true) + var filesToDelete = _fileSystem.GetFiles(_configurationManager.CommonApplicationPaths.LogDirectoryPath, new[] { ".txt" }, true, true) .Where(f => _fileSystem.GetLastWriteTimeUtc(f) < minDateModified) .ToList(); @@ -83,26 +104,5 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks return Task.CompletedTask; } - - /// <inheritdoc /> - public string Name => _localization.GetLocalizedString("TaskCleanLogs"); - - /// <inheritdoc /> - public string Description => string.Format(_localization.GetLocalizedString("TaskCleanLogsDescription"), ConfigurationManager.CommonConfiguration.LogFileRetentionDays); - - /// <inheritdoc /> - public string Category => _localization.GetLocalizedString("TasksMaintenanceCategory"); - - /// <inheritdoc /> - public string Key => "CleanLogFiles"; - - /// <inheritdoc /> - public bool IsHidden => false; - - /// <inheritdoc /> - public bool IsEnabled => true; - - /// <inheritdoc /> - public bool IsLogged => true; } } diff --git a/Emby.Server.Implementations/Services/ServicePath.cs b/Emby.Server.Implementations/Services/ServicePath.cs index 442b2ab1c..0d4728b43 100644 --- a/Emby.Server.Implementations/Services/ServicePath.cs +++ b/Emby.Server.Implementations/Services/ServicePath.cs @@ -80,8 +80,8 @@ namespace Emby.Server.Implementations.Services public static List<string> GetFirstMatchWildCardHashKeys(string[] pathPartsForMatching) { - const string hashPrefix = WildCard + PathSeperator; - return GetPotentialMatchesWithPrefix(hashPrefix, pathPartsForMatching); + const string HashPrefix = WildCard + PathSeperator; + return GetPotentialMatchesWithPrefix(HashPrefix, pathPartsForMatching); } private static List<string> GetPotentialMatchesWithPrefix(string hashPrefix, string[] pathPartsForMatching) @@ -92,7 +92,7 @@ namespace Emby.Server.Implementations.Services { list.Add(hashPrefix + part); - if (part.IndexOf(ComponentSeperator) == -1) + if (part.IndexOf(ComponentSeperator, StringComparison.Ordinal) == -1) { continue; } @@ -130,7 +130,7 @@ namespace Emby.Server.Implementations.Services } if (component.IndexOf(VariablePrefix, StringComparison.OrdinalIgnoreCase) != -1 - && component.IndexOf(ComponentSeperator) != -1) + && component.IndexOf(ComponentSeperator, StringComparison.Ordinal) != -1) { hasSeparators.Add(true); componentsList.AddRange(component.Split(ComponentSeperator)); diff --git a/Jellyfin.Api/Controllers/DlnaServerController.cs b/Jellyfin.Api/Controllers/DlnaServerController.cs index 0100d642b..bbaf39eb1 100644 --- a/Jellyfin.Api/Controllers/DlnaServerController.cs +++ b/Jellyfin.Api/Controllers/DlnaServerController.cs @@ -221,9 +221,8 @@ namespace Jellyfin.Api.Controllers private Task<ControlResponse> ProcessControlRequestInternalAsync(string id, Stream requestStream, IUpnpService service) { - return service.ProcessControlRequestAsync(new ControlRequest + return service.ProcessControlRequestAsync(new ControlRequest(Request.Headers) { - Headers = Request.Headers, InputXml = requestStream, TargetServerUuId = id, RequestedUrl = GetAbsoluteUri() diff --git a/MediaBrowser.Controller/Entities/UserViewBuilder.cs b/MediaBrowser.Controller/Entities/UserViewBuilder.cs index e3f4025bb..b384b27d1 100644 --- a/MediaBrowser.Controller/Entities/UserViewBuilder.cs +++ b/MediaBrowser.Controller/Entities/UserViewBuilder.cs @@ -10,7 +10,6 @@ using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.TV; -using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Querying; using Microsoft.Extensions.Logging; diff --git a/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs b/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs index a8ebe6bc5..21b5d0c5b 100644 --- a/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs +++ b/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs @@ -240,11 +240,11 @@ namespace MediaBrowser.MediaEncoding.Attachments if (protocol == MediaProtocol.File) { var date = _fileSystem.GetLastWriteTimeUtc(mediaPath); - filename = (mediaPath + attachmentStreamIndex.ToString(CultureInfo.InvariantCulture) + "_" + date.Ticks.ToString(CultureInfo.InvariantCulture)).GetMD5().ToString("D"); + filename = (mediaPath + attachmentStreamIndex.ToString(CultureInfo.InvariantCulture) + "_" + date.Ticks.ToString(CultureInfo.InvariantCulture)).GetMD5().ToString("D", CultureInfo.InvariantCulture); } else { - filename = (mediaPath + attachmentStreamIndex.ToString(CultureInfo.InvariantCulture)).GetMD5().ToString("D"); + filename = (mediaPath + attachmentStreamIndex.ToString(CultureInfo.InvariantCulture)).GetMD5().ToString("D", CultureInfo.InvariantCulture); } var prefix = filename.Substring(0, 1); diff --git a/MediaBrowser.MediaEncoding/Encoder/EncodingUtils.cs b/MediaBrowser.MediaEncoding/Encoder/EncodingUtils.cs index 082ae2888..63310fdf6 100644 --- a/MediaBrowser.MediaEncoding/Encoder/EncodingUtils.cs +++ b/MediaBrowser.MediaEncoding/Encoder/EncodingUtils.cs @@ -1,5 +1,6 @@ #pragma warning disable CS1591 +using System; using System.Collections.Generic; using System.Globalization; using System.Linq; @@ -48,7 +49,7 @@ namespace MediaBrowser.MediaEncoding.Encoder /// <returns>System.String.</returns> private static string GetFileInputArgument(string path) { - if (path.IndexOf("://") != -1) + if (path.IndexOf("://", StringComparison.Ordinal) != -1) { return string.Format(CultureInfo.InvariantCulture, "\"{0}\"", path); } @@ -67,7 +68,7 @@ namespace MediaBrowser.MediaEncoding.Encoder private static string NormalizePath(string path) { // Quotes are valid path characters in linux and they need to be escaped here with a leading \ - return path.Replace("\"", "\\\""); + return path.Replace("\"", "\\\"", StringComparison.Ordinal); } } } diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index bdf2babfa..9d01da40f 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -374,7 +374,7 @@ namespace MediaBrowser.MediaEncoding.Encoder var args = extractChapters ? "{0} -i {1} -threads 0 -v warning -print_format json -show_streams -show_chapters -show_format" : "{0} -i {1} -threads 0 -v warning -print_format json -show_streams -show_format"; - args = string.Format(args, probeSizeArgument, inputPath).Trim(); + args = string.Format(CultureInfo.InvariantCulture, args, probeSizeArgument, inputPath).Trim(); var process = new Process { @@ -853,7 +853,7 @@ namespace MediaBrowser.MediaEncoding.Encoder // https://ffmpeg.org/ffmpeg-filters.html#Notes-on-filtergraph-escaping // We need to double escape - return path.Replace('\\', '/').Replace(":", "\\:").Replace("'", "'\\\\\\''"); + return path.Replace('\\', '/').Replace(":", "\\:", StringComparison.Ordinal).Replace("'", "'\\\\\\''", StringComparison.Ordinal); } /// <inheritdoc /> diff --git a/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj b/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj index 017f917e2..814edd732 100644 --- a/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj +++ b/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj @@ -34,7 +34,7 @@ <!-- Code Analyzers--> <ItemGroup Condition=" '$(Configuration)' == 'Debug' "> - <!-- <PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.9.8" PrivateAssets="All" /> --> + <PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.9.8" PrivateAssets="All" /> <PackageReference Include="SerilogAnalyzer" Version="0.15.0" PrivateAssets="All" /> <PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="All" /> <PackageReference Include="SmartAnalyzers.MultithreadingAnalyzer" Version="1.1.31" PrivateAssets="All" /> diff --git a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs index 19e3bd8e6..40a3b43e1 100644 --- a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs +++ b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs @@ -42,7 +42,8 @@ namespace MediaBrowser.MediaEncoding.Probing var info = new MediaInfo { Path = path, - Protocol = protocol + Protocol = protocol, + VideoType = videoType }; FFProbeHelpers.NormalizeFFProbeResult(data); @@ -1133,7 +1134,7 @@ namespace MediaBrowser.MediaEncoding.Probing { // Only use the comma as a delimeter if there are no slashes or pipes. // We want to be careful not to split names that have commas in them - var delimeter = !allowCommaDelimiter || _nameDelimiters.Any(i => val.IndexOf(i) != -1) ? + var delimeter = !allowCommaDelimiter || _nameDelimiters.Any(i => val.IndexOf(i, StringComparison.Ordinal) != -1) ? _nameDelimiters : new[] { ',' }; @@ -1377,8 +1378,8 @@ namespace MediaBrowser.MediaEncoding.Probing if (subtitle.Contains('/', StringComparison.Ordinal)) // It contains a episode number and season number { string[] numbers = subtitle.Split(' '); - video.IndexNumber = int.Parse(numbers[0].Replace(".", string.Empty, StringComparison.Ordinal).Split('/')[0]); - int totalEpisodesInSeason = int.Parse(numbers[0].Replace(".", string.Empty, StringComparison.Ordinal).Split('/')[1]); + video.IndexNumber = int.Parse(numbers[0].Replace(".", string.Empty, StringComparison.Ordinal).Split('/')[0], CultureInfo.InvariantCulture); + int totalEpisodesInSeason = int.Parse(numbers[0].Replace(".", string.Empty, StringComparison.Ordinal).Split('/')[1], CultureInfo.InvariantCulture); description = string.Join(" ", numbers, 1, numbers.Length - 1).Trim(); // Skip the first, concatenate the rest, clean up spaces and save it } diff --git a/MediaBrowser.MediaEncoding/Subtitles/AssParser.cs b/MediaBrowser.MediaEncoding/Subtitles/AssParser.cs index 308b62886..86b87fddd 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/AssParser.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/AssParser.cs @@ -86,9 +86,9 @@ namespace MediaBrowser.MediaEncoding.Subtitles private void RemoteNativeFormatting(SubtitleTrackEvent p) { - int indexOfBegin = p.Text.IndexOf('{'); + int indexOfBegin = p.Text.IndexOf('{', StringComparison.Ordinal); string pre = string.Empty; - while (indexOfBegin >= 0 && p.Text.IndexOf('}') > indexOfBegin) + while (indexOfBegin >= 0 && p.Text.IndexOf('}', StringComparison.Ordinal) > indexOfBegin) { string s = p.Text.Substring(indexOfBegin); if (s.StartsWith("{\\an1}", StringComparison.Ordinal) || @@ -116,10 +116,10 @@ namespace MediaBrowser.MediaEncoding.Subtitles pre = s.Substring(0, 5) + "}"; } - int indexOfEnd = p.Text.IndexOf('}'); + int indexOfEnd = p.Text.IndexOf('}', StringComparison.Ordinal); p.Text = p.Text.Remove(indexOfBegin, (indexOfEnd - indexOfBegin) + 1); - indexOfBegin = p.Text.IndexOf('{'); + indexOfBegin = p.Text.IndexOf('{', StringComparison.Ordinal); } p.Text = pre + p.Text; diff --git a/MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs b/MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs index 6b7a81e6e..a5d641747 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.IO; using System.Text; using System.Threading; @@ -50,14 +51,14 @@ namespace MediaBrowser.MediaEncoding.Subtitles { eventsStarted = true; } - else if (!string.IsNullOrEmpty(line) && line.Trim().StartsWith(";")) + else if (!string.IsNullOrEmpty(line) && line.Trim().StartsWith(";", StringComparison.Ordinal)) { // skip comment lines } else if (eventsStarted && line.Trim().Length > 0) { string s = line.Trim().ToLowerInvariant(); - if (s.StartsWith("format:")) + if (s.StartsWith("format:", StringComparison.Ordinal)) { if (line.Length > 10) { @@ -103,7 +104,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles string[] splittedLine; - if (s.StartsWith("dialogue:")) + if (s.StartsWith("dialogue:", StringComparison.Ordinal)) { splittedLine = line.Substring(10).Split(','); } @@ -181,10 +182,10 @@ namespace MediaBrowser.MediaEncoding.Subtitles string[] timeCode = time.Split(':', '.'); return new TimeSpan( 0, - int.Parse(timeCode[0]), - int.Parse(timeCode[1]), - int.Parse(timeCode[2]), - int.Parse(timeCode[3]) * 10).Ticks; + int.Parse(timeCode[0], CultureInfo.InvariantCulture), + int.Parse(timeCode[1], CultureInfo.InvariantCulture), + int.Parse(timeCode[2], CultureInfo.InvariantCulture), + int.Parse(timeCode[3], CultureInfo.InvariantCulture) * 10).Ticks; } private static string GetFormattedText(string text) @@ -193,11 +194,11 @@ namespace MediaBrowser.MediaEncoding.Subtitles for (int i = 0; i < 10; i++) // just look ten times... { - if (text.Contains(@"{\fn")) + if (text.Contains(@"{\fn", StringComparison.Ordinal)) { - int start = text.IndexOf(@"{\fn"); + int start = text.IndexOf(@"{\fn", StringComparison.Ordinal); int end = text.IndexOf('}', start); - if (end > 0 && !text.Substring(start).StartsWith("{\\fn}")) + if (end > 0 && !text.Substring(start).StartsWith("{\\fn}", StringComparison.Ordinal)) { string fontName = text.Substring(start + 4, end - (start + 4)); string extraTags = string.Empty; @@ -212,7 +213,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles text = text.Insert(start, "<font face=\"" + fontName + "\"" + extraTags + ">"); } - int indexOfEndTag = text.IndexOf("{\\fn}", start); + int indexOfEndTag = text.IndexOf("{\\fn}", start, StringComparison.Ordinal); if (indexOfEndTag > 0) { text = text.Remove(indexOfEndTag, "{\\fn}".Length).Insert(indexOfEndTag, "</font>"); @@ -224,11 +225,11 @@ namespace MediaBrowser.MediaEncoding.Subtitles } } - if (text.Contains(@"{\fs")) + if (text.Contains(@"{\fs", StringComparison.Ordinal)) { - int start = text.IndexOf(@"{\fs"); + int start = text.IndexOf(@"{\fs", StringComparison.Ordinal); int end = text.IndexOf('}', start); - if (end > 0 && !text.Substring(start).StartsWith("{\\fs}")) + if (end > 0 && !text.Substring(start).StartsWith("{\\fs}", StringComparison.Ordinal)) { string fontSize = text.Substring(start + 4, end - (start + 4)); string extraTags = string.Empty; @@ -245,7 +246,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles text = text.Insert(start, "<font size=\"" + fontSize + "\"" + extraTags + ">"); } - int indexOfEndTag = text.IndexOf("{\\fs}", start); + int indexOfEndTag = text.IndexOf("{\\fs}", start, StringComparison.Ordinal); if (indexOfEndTag > 0) { text = text.Remove(indexOfEndTag, "{\\fs}".Length).Insert(indexOfEndTag, "</font>"); @@ -258,17 +259,17 @@ namespace MediaBrowser.MediaEncoding.Subtitles } } - if (text.Contains(@"{\c")) + if (text.Contains(@"{\c", StringComparison.Ordinal)) { - int start = text.IndexOf(@"{\c"); + int start = text.IndexOf(@"{\c", StringComparison.Ordinal); int end = text.IndexOf('}', start); - if (end > 0 && !text.Substring(start).StartsWith("{\\c}")) + if (end > 0 && !text.Substring(start).StartsWith("{\\c}", StringComparison.Ordinal)) { string color = text.Substring(start + 4, end - (start + 4)); string extraTags = string.Empty; CheckAndAddSubTags(ref color, ref extraTags, out bool italic); - color = color.Replace("&", string.Empty).TrimStart('H'); + color = color.Replace("&", string.Empty, StringComparison.Ordinal).TrimStart('H'); color = color.PadLeft(6, '0'); // switch to rrggbb from bbggrr @@ -285,7 +286,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles text = text.Insert(start, "<font color=\"" + color + "\"" + extraTags + ">"); } - int indexOfEndTag = text.IndexOf("{\\c}", start); + int indexOfEndTag = text.IndexOf("{\\c}", start, StringComparison.Ordinal); if (indexOfEndTag > 0) { text = text.Remove(indexOfEndTag, "{\\c}".Length).Insert(indexOfEndTag, "</font>"); @@ -297,17 +298,17 @@ namespace MediaBrowser.MediaEncoding.Subtitles } } - if (text.Contains(@"{\1c")) // "1" specifices primary color + if (text.Contains(@"{\1c", StringComparison.Ordinal)) // "1" specifices primary color { - int start = text.IndexOf(@"{\1c"); + int start = text.IndexOf(@"{\1c", StringComparison.Ordinal); int end = text.IndexOf('}', start); - if (end > 0 && !text.Substring(start).StartsWith("{\\1c}")) + if (end > 0 && !text.Substring(start).StartsWith("{\\1c}", StringComparison.Ordinal)) { string color = text.Substring(start + 5, end - (start + 5)); string extraTags = string.Empty; CheckAndAddSubTags(ref color, ref extraTags, out bool italic); - color = color.Replace("&", string.Empty).TrimStart('H'); + color = color.Replace("&", string.Empty, StringComparison.Ordinal).TrimStart('H'); color = color.PadLeft(6, '0'); // switch to rrggbb from bbggrr @@ -329,25 +330,25 @@ namespace MediaBrowser.MediaEncoding.Subtitles } } - text = text.Replace(@"{\i1}", "<i>"); - text = text.Replace(@"{\i0}", "</i>"); - text = text.Replace(@"{\i}", "</i>"); + text = text.Replace(@"{\i1}", "<i>", StringComparison.Ordinal); + text = text.Replace(@"{\i0}", "</i>", StringComparison.Ordinal); + text = text.Replace(@"{\i}", "</i>", StringComparison.Ordinal); if (CountTagInText(text, "<i>") > CountTagInText(text, "</i>")) { text += "</i>"; } - text = text.Replace(@"{\u1}", "<u>"); - text = text.Replace(@"{\u0}", "</u>"); - text = text.Replace(@"{\u}", "</u>"); + text = text.Replace(@"{\u1}", "<u>", StringComparison.Ordinal); + text = text.Replace(@"{\u0}", "</u>", StringComparison.Ordinal); + text = text.Replace(@"{\u}", "</u>", StringComparison.Ordinal); if (CountTagInText(text, "<u>") > CountTagInText(text, "</u>")) { text += "</u>"; } - text = text.Replace(@"{\b1}", "<b>"); - text = text.Replace(@"{\b0}", "</b>"); - text = text.Replace(@"{\b}", "</b>"); + text = text.Replace(@"{\b1}", "<b>", StringComparison.Ordinal); + text = text.Replace(@"{\b0}", "</b>", StringComparison.Ordinal); + text = text.Replace(@"{\b}", "</b>", StringComparison.Ordinal); if (CountTagInText(text, "<b>") > CountTagInText(text, "</b>")) { text += "</b>"; @@ -362,7 +363,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles private static int CountTagInText(string text, string tag) { int count = 0; - int index = text.IndexOf(tag); + int index = text.IndexOf(tag, StringComparison.Ordinal); while (index >= 0) { count++; @@ -371,7 +372,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles return count; } - index = text.IndexOf(tag, index + 1); + index = text.IndexOf(tag, index + 1, StringComparison.Ordinal); } return count; @@ -380,7 +381,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles private static void CheckAndAddSubTags(ref string tagName, ref string extraTags, out bool italic) { italic = false; - int indexOfSPlit = tagName.IndexOf(@"\"); + int indexOfSPlit = tagName.IndexOf('\\', StringComparison.Ordinal); if (indexOfSPlit > 0) { string rest = tagName.Substring(indexOfSPlit).TrimStart('\\'); @@ -388,9 +389,9 @@ namespace MediaBrowser.MediaEncoding.Subtitles for (int i = 0; i < 10; i++) { - if (rest.StartsWith("fs") && rest.Length > 2) + if (rest.StartsWith("fs", StringComparison.Ordinal) && rest.Length > 2) { - indexOfSPlit = rest.IndexOf(@"\"); + indexOfSPlit = rest.IndexOf('\\', StringComparison.Ordinal); string fontSize = rest; if (indexOfSPlit > 0) { @@ -404,9 +405,9 @@ namespace MediaBrowser.MediaEncoding.Subtitles extraTags += " size=\"" + fontSize.Substring(2) + "\""; } - else if (rest.StartsWith("fn") && rest.Length > 2) + else if (rest.StartsWith("fn", StringComparison.Ordinal) && rest.Length > 2) { - indexOfSPlit = rest.IndexOf(@"\"); + indexOfSPlit = rest.IndexOf('\\', StringComparison.Ordinal); string fontName = rest; if (indexOfSPlit > 0) { @@ -420,9 +421,9 @@ namespace MediaBrowser.MediaEncoding.Subtitles extraTags += " face=\"" + fontName.Substring(2) + "\""; } - else if (rest.StartsWith("c") && rest.Length > 2) + else if (rest.StartsWith("c", StringComparison.Ordinal) && rest.Length > 2) { - indexOfSPlit = rest.IndexOf(@"\"); + indexOfSPlit = rest.IndexOf('\\', StringComparison.Ordinal); string fontColor = rest; if (indexOfSPlit > 0) { @@ -435,7 +436,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles } string color = fontColor.Substring(2); - color = color.Replace("&", string.Empty).TrimStart('H'); + color = color.Replace("&", string.Empty, StringComparison.Ordinal).TrimStart('H'); color = color.PadLeft(6, '0'); // switch to rrggbb from bbggrr color = "#" + color.Remove(color.Length - 6) + color.Substring(color.Length - 2, 2) + color.Substring(color.Length - 4, 2) + color.Substring(color.Length - 6, 2); @@ -443,9 +444,9 @@ namespace MediaBrowser.MediaEncoding.Subtitles extraTags += " color=\"" + color + "\""; } - else if (rest.StartsWith("i1") && rest.Length > 1) + else if (rest.StartsWith("i1", StringComparison.Ordinal) && rest.Length > 1) { - indexOfSPlit = rest.IndexOf(@"\"); + indexOfSPlit = rest.IndexOf('\\', StringComparison.Ordinal); italic = true; if (indexOfSPlit > 0) { @@ -456,9 +457,9 @@ namespace MediaBrowser.MediaEncoding.Subtitles rest = string.Empty; } } - else if (rest.Length > 0 && rest.Contains("\\")) + else if (rest.Length > 0 && rest.Contains('\\', StringComparison.Ordinal)) { - indexOfSPlit = rest.IndexOf(@"\"); + indexOfSPlit = rest.IndexOf('\\', StringComparison.Ordinal); rest = rest.Substring(indexOfSPlit).TrimStart('\\'); } } diff --git a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs index fbe8bd69f..6ac5ac2ff 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs @@ -415,7 +415,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles // FFmpeg automatically convert character encoding when it is UTF-16 // If we specify character encoding, it rejects with "do not specify a character encoding" and "Unable to recode subtitle event" - if ((inputPath.EndsWith(".smi") || inputPath.EndsWith(".sami")) && + if ((inputPath.EndsWith(".smi", StringComparison.Ordinal) || inputPath.EndsWith(".sami", StringComparison.Ordinal)) && (encodingParam.Equals("UTF-16BE", StringComparison.OrdinalIgnoreCase) || encodingParam.Equals("UTF-16LE", StringComparison.OrdinalIgnoreCase))) { @@ -506,7 +506,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles string.Format(CultureInfo.InvariantCulture, "ffmpeg subtitle conversion failed for {0}", inputPath)); } - await SetAssFont(outputPath).ConfigureAwait(false); + await SetAssFont(outputPath, cancellationToken).ConfigureAwait(false); _logger.LogInformation("ffmpeg subtitle conversion succeeded for {Path}", inputPath); } @@ -668,7 +668,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles if (string.Equals(outputCodec, "ass", StringComparison.OrdinalIgnoreCase)) { - await SetAssFont(outputPath).ConfigureAwait(false); + await SetAssFont(outputPath, cancellationToken).ConfigureAwait(false); } } @@ -676,8 +676,9 @@ namespace MediaBrowser.MediaEncoding.Subtitles /// Sets the ass font. /// </summary> /// <param name="file">The file.</param> + /// <param name="cancellationToken">The token to monitor for cancellation requests. The default value is <c>System.Threading.CancellationToken.None</c>.</param> /// <returns>Task.</returns> - private async Task SetAssFont(string file) + private async Task SetAssFont(string file, CancellationToken cancellationToken = default) { _logger.LogInformation("Setting ass font within {File}", file); @@ -692,14 +693,14 @@ namespace MediaBrowser.MediaEncoding.Subtitles text = await reader.ReadToEndAsync().ConfigureAwait(false); } - var newText = text.Replace(",Arial,", ",Arial Unicode MS,"); + var newText = text.Replace(",Arial,", ",Arial Unicode MS,", StringComparison.Ordinal); - if (!string.Equals(text, newText)) + if (!string.Equals(text, newText, StringComparison.Ordinal)) { using (var fileStream = new FileStream(file, FileMode.Create, FileAccess.Write, FileShare.Read)) using (var writer = new StreamWriter(fileStream, encoding)) { - writer.Write(newText); + await writer.WriteAsync(newText.AsMemory(), cancellationToken).ConfigureAwait(false); } } } @@ -736,7 +737,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles var charset = CharsetDetector.DetectFromStream(stream).Detected?.EncodingName; // UTF16 is automatically converted to UTF8 by FFmpeg, do not specify a character encoding - if ((path.EndsWith(".ass") || path.EndsWith(".ssa") || path.EndsWith(".srt")) + if ((path.EndsWith(".ass", StringComparison.Ordinal) || path.EndsWith(".ssa", StringComparison.Ordinal) || path.EndsWith(".srt", StringComparison.Ordinal)) && (string.Equals(charset, "utf-16le", StringComparison.OrdinalIgnoreCase) || string.Equals(charset, "utf-16be", StringComparison.OrdinalIgnoreCase))) { |
