From 09e897d372e0b8327deb4427b80d92e0de91218a Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Sat, 19 Mar 2022 00:33:32 +0100 Subject: [PATCH 001/245] Clean up DLNA profile code --- Emby.Dlna/DlnaManager.cs | 114 ++--- Emby.Dlna/Profiles/DefaultProfile.cs | 14 - Emby.Dlna/Profiles/DenonAvrProfile.cs | 34 -- Emby.Dlna/Profiles/DirectTvProfile.cs | 129 ------ Emby.Dlna/Profiles/DishHopperJoeyProfile.cs | 228 ---------- Emby.Dlna/Profiles/Foobar2000Profile.cs | 78 ---- Emby.Dlna/Profiles/LgTvProfile.cs | 211 ---------- Emby.Dlna/Profiles/LinksysDMA2100Profile.cs | 55 --- Emby.Dlna/Profiles/MarantzProfile.cs | 43 -- Emby.Dlna/Profiles/MediaMonkeyProfile.cs | 44 -- Emby.Dlna/Profiles/PanasonicVieraProfile.cs | 222 ---------- Emby.Dlna/Profiles/PopcornHourProfile.cs | 225 ---------- Emby.Dlna/Profiles/SamsungSmartTvProfile.cs | 367 ----------------- Emby.Dlna/Profiles/SharpSmartTvProfile.cs | 121 ------ Emby.Dlna/Profiles/SonyBlurayPlayer2013.cs | 230 ----------- Emby.Dlna/Profiles/SonyBlurayPlayer2014.cs | 230 ----------- Emby.Dlna/Profiles/SonyBlurayPlayer2015.cs | 218 ---------- Emby.Dlna/Profiles/SonyBlurayPlayer2016.cs | 218 ---------- Emby.Dlna/Profiles/SonyBlurayPlayerProfile.cs | 284 ------------- Emby.Dlna/Profiles/SonyBravia2010Profile.cs | 366 ---------------- Emby.Dlna/Profiles/SonyBravia2011Profile.cs | 389 ------------------ Emby.Dlna/Profiles/SonyBravia2012Profile.cs | 307 -------------- Emby.Dlna/Profiles/SonyBravia2013Profile.cs | 324 --------------- Emby.Dlna/Profiles/SonyBravia2014Profile.cs | 324 --------------- Emby.Dlna/Profiles/SonyPs3Profile.cs | 269 ------------ Emby.Dlna/Profiles/SonyPs4Profile.cs | 278 ------------- Emby.Dlna/Profiles/WdtvLiveProfile.cs | 266 ------------ Emby.Dlna/Profiles/XboxOneProfile.cs | 372 ----------------- .../Controllers/DlnaControllerTests.cs | 54 ++- 29 files changed, 65 insertions(+), 5949 deletions(-) delete mode 100644 Emby.Dlna/Profiles/DenonAvrProfile.cs delete mode 100644 Emby.Dlna/Profiles/DirectTvProfile.cs delete mode 100644 Emby.Dlna/Profiles/DishHopperJoeyProfile.cs delete mode 100644 Emby.Dlna/Profiles/Foobar2000Profile.cs delete mode 100644 Emby.Dlna/Profiles/LgTvProfile.cs delete mode 100644 Emby.Dlna/Profiles/LinksysDMA2100Profile.cs delete mode 100644 Emby.Dlna/Profiles/MarantzProfile.cs delete mode 100644 Emby.Dlna/Profiles/MediaMonkeyProfile.cs delete mode 100644 Emby.Dlna/Profiles/PanasonicVieraProfile.cs delete mode 100644 Emby.Dlna/Profiles/PopcornHourProfile.cs delete mode 100644 Emby.Dlna/Profiles/SamsungSmartTvProfile.cs delete mode 100644 Emby.Dlna/Profiles/SharpSmartTvProfile.cs delete mode 100644 Emby.Dlna/Profiles/SonyBlurayPlayer2013.cs delete mode 100644 Emby.Dlna/Profiles/SonyBlurayPlayer2014.cs delete mode 100644 Emby.Dlna/Profiles/SonyBlurayPlayer2015.cs delete mode 100644 Emby.Dlna/Profiles/SonyBlurayPlayer2016.cs delete mode 100644 Emby.Dlna/Profiles/SonyBlurayPlayerProfile.cs delete mode 100644 Emby.Dlna/Profiles/SonyBravia2010Profile.cs delete mode 100644 Emby.Dlna/Profiles/SonyBravia2011Profile.cs delete mode 100644 Emby.Dlna/Profiles/SonyBravia2012Profile.cs delete mode 100644 Emby.Dlna/Profiles/SonyBravia2013Profile.cs delete mode 100644 Emby.Dlna/Profiles/SonyBravia2014Profile.cs delete mode 100644 Emby.Dlna/Profiles/SonyPs3Profile.cs delete mode 100644 Emby.Dlna/Profiles/SonyPs4Profile.cs delete mode 100644 Emby.Dlna/Profiles/WdtvLiveProfile.cs delete mode 100644 Emby.Dlna/Profiles/XboxOneProfile.cs diff --git a/Emby.Dlna/DlnaManager.cs b/Emby.Dlna/DlnaManager.cs index 192128c7ec..60374e795d 100644 --- a/Emby.Dlna/DlnaManager.cs +++ b/Emby.Dlna/DlnaManager.cs @@ -1,4 +1,5 @@ #pragma warning disable CS1591 + using System; using System.Collections.Generic; using System.Globalization; @@ -61,6 +62,7 @@ namespace Emby.Dlna try { await ExtractSystemProfilesAsync().ConfigureAwait(false); + Directory.CreateDirectory(UserProfilesPath); LoadProfiles(); } catch (Exception ex) @@ -328,32 +330,28 @@ namespace Emby.Dlna var path = Path.Join( systemProfilesPath, - Path.GetFileName(name.AsSpan()).Slice(namespaceName.Length)); + Path.GetFileName(name.AsSpan())[namespaceName.Length..]); + + if (File.Exists(path)) + { + continue; + } // The stream should exist as we just got its name from GetManifestResourceNames using (var stream = _assembly.GetManifestResourceStream(name)!) { - var length = stream.Length; - var fileInfo = _fileSystem.GetFileInfo(path); + Directory.CreateDirectory(systemProfilesPath); - if (!fileInfo.Exists || fileInfo.Length != length) + var fileOptions = AsyncFile.WriteOptions; + fileOptions.Mode = FileMode.CreateNew; + fileOptions.PreallocationSize = stream.Length; + var fileStream = new FileStream(path, fileOptions); + await using (fileStream.ConfigureAwait(false)) { - Directory.CreateDirectory(systemProfilesPath); - - var fileOptions = AsyncFile.WriteOptions; - fileOptions.Mode = FileMode.Create; - fileOptions.PreallocationSize = length; - var fileStream = new FileStream(path, fileOptions); - await using (fileStream.ConfigureAwait(false)) - { - await stream.CopyToAsync(fileStream).ConfigureAwait(false); - } + await stream.CopyToAsync(fileStream).ConfigureAwait(false); } } } - - // Not necessary, but just to make it easy to find - Directory.CreateDirectory(UserProfilesPath); } /// @@ -406,14 +404,20 @@ namespace Emby.Dlna } var current = GetProfileInfosInternal().First(i => string.Equals(i.Info.Id, profileId, StringComparison.OrdinalIgnoreCase)); + if (current.Info.Type == DeviceProfileType.System) + { + throw new ArgumentException("System profiles can't be edited"); + } var newFilename = _fileSystem.GetValidFilename(profile.Name) + ".xml"; - var path = Path.Combine(UserProfilesPath, newFilename); + var path = Path.Join(UserProfilesPath, newFilename); - if (!string.Equals(path, current.Path, StringComparison.Ordinal) && - current.Info.Type != DeviceProfileType.System) + if (!string.Equals(path, current.Path, StringComparison.Ordinal)) { - _fileSystem.DeleteFile(current.Path); + lock (_profiles) + { + _profiles.Remove(current.Path); + } } SaveProfile(profile, path, DeviceProfileType.User); @@ -496,72 +500,4 @@ namespace Emby.Dlna internal string Path { get; } } } - - /* - class DlnaProfileEntryPoint : IServerEntryPoint - { - private readonly IApplicationPaths _appPaths; - private readonly IFileSystem _fileSystem; - private readonly IXmlSerializer _xmlSerializer; - - public DlnaProfileEntryPoint(IApplicationPaths appPaths, IFileSystem fileSystem, IXmlSerializer xmlSerializer) - { - _appPaths = appPaths; - _fileSystem = fileSystem; - _xmlSerializer = xmlSerializer; - } - - public void Run() - { - DumpProfiles(); - } - - private void DumpProfiles() - { - DeviceProfile[] list = new[] - { - new SamsungSmartTvProfile(), - new XboxOneProfile(), - new SonyPs3Profile(), - new SonyPs4Profile(), - new SonyBravia2010Profile(), - new SonyBravia2011Profile(), - new SonyBravia2012Profile(), - new SonyBravia2013Profile(), - new SonyBravia2014Profile(), - new SonyBlurayPlayer2013(), - new SonyBlurayPlayer2014(), - new SonyBlurayPlayer2015(), - new SonyBlurayPlayer2016(), - new SonyBlurayPlayerProfile(), - new PanasonicVieraProfile(), - new WdtvLiveProfile(), - new DenonAvrProfile(), - new LinksysDMA2100Profile(), - new LgTvProfile(), - new Foobar2000Profile(), - new SharpSmartTvProfile(), - new MediaMonkeyProfile(), - // new Windows81Profile(), - // new WindowsMediaCenterProfile(), - // new WindowsPhoneProfile(), - new DirectTvProfile(), - new DishHopperJoeyProfile(), - new DefaultProfile(), - new PopcornHourProfile(), - new MarantzProfile() - }; - - foreach (var item in list) - { - var path = Path.Combine(_appPaths.ProgramDataPath, _fileSystem.GetValidFilename(item.Name) + ".xml"); - - _xmlSerializer.SerializeToFile(item, path); - } - } - - public void Dispose() - { - } - }*/ } diff --git a/Emby.Dlna/Profiles/DefaultProfile.cs b/Emby.Dlna/Profiles/DefaultProfile.cs index 8f4f2bd384..23437f1bdf 100644 --- a/Emby.Dlna/Profiles/DefaultProfile.cs +++ b/Emby.Dlna/Profiles/DefaultProfile.cs @@ -2,7 +2,6 @@ using System; using System.Globalization; -using System.Linq; using MediaBrowser.Model.Dlna; namespace Emby.Dlna.Profiles @@ -164,18 +163,5 @@ namespace Emby.Dlna.Profiles } }; } - - public void AddXmlRootAttribute(string name, string value) - { - var list = XmlRootAttributes.ToList(); - - list.Add(new XmlAttribute - { - Name = name, - Value = value - }); - - XmlRootAttributes = list.ToArray(); - } } } diff --git a/Emby.Dlna/Profiles/DenonAvrProfile.cs b/Emby.Dlna/Profiles/DenonAvrProfile.cs deleted file mode 100644 index a5ba0f36cc..0000000000 --- a/Emby.Dlna/Profiles/DenonAvrProfile.cs +++ /dev/null @@ -1,34 +0,0 @@ -#pragma warning disable CS1591 - -using MediaBrowser.Model.Dlna; - -namespace Emby.Dlna.Profiles -{ - [System.Xml.Serialization.XmlRoot("Profile")] - public class DenonAvrProfile : DefaultProfile - { - public DenonAvrProfile() - { - Name = "Denon AVR"; - - SupportedMediaTypes = "Audio"; - - Identification = new DeviceIdentification - { - FriendlyName = @"Denon:\[AVR:.*", - Manufacturer = "Denon" - }; - - DirectPlayProfiles = new[] - { - new DirectPlayProfile - { - Container = "mp3,flac,m4a,wma", - Type = DlnaProfileType.Audio - }, - }; - - ResponseProfiles = System.Array.Empty(); - } - } -} diff --git a/Emby.Dlna/Profiles/DirectTvProfile.cs b/Emby.Dlna/Profiles/DirectTvProfile.cs deleted file mode 100644 index f6f98b07d8..0000000000 --- a/Emby.Dlna/Profiles/DirectTvProfile.cs +++ /dev/null @@ -1,129 +0,0 @@ -#pragma warning disable CS1591 - -using MediaBrowser.Model.Dlna; - -namespace Emby.Dlna.Profiles -{ - [System.Xml.Serialization.XmlRoot("Profile")] - public class DirectTvProfile : DefaultProfile - { - public DirectTvProfile() - { - Name = "DirecTV HD-DVR"; - - TimelineOffsetSeconds = 10; - RequiresPlainFolders = true; - RequiresPlainVideoItems = true; - - Identification = new DeviceIdentification - { - Headers = new[] - { - new HttpHeaderInfo - { - Match = HeaderMatchType.Substring, - Name = "User-Agent", - Value = "DIRECTV" - } - }, - - FriendlyName = "^DIRECTV.*$" - }; - - DirectPlayProfiles = new[] - { - new DirectPlayProfile - { - Container = "mpeg", - VideoCodec = "mpeg2video", - AudioCodec = "mp2", - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Container = "jpeg,jpg", - Type = DlnaProfileType.Photo - } - }; - - TranscodingProfiles = new[] - { - new TranscodingProfile - { - Container = "mpeg", - VideoCodec = "mpeg2video", - AudioCodec = "mp2", - Type = DlnaProfileType.Video - }, - new TranscodingProfile - { - Container = "jpeg", - Type = DlnaProfileType.Photo - } - }; - - CodecProfiles = new[] - { - new CodecProfile - { - Codec = "mpeg2video", - Type = CodecType.Video, - - Conditions = new[] - { - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Width, - Value = "1920" - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Height, - Value = "1080" - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.VideoFramerate, - Value = "30" - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.VideoBitrate, - Value = "8192000" - } - } - }, - new CodecProfile - { - Codec = "mp2", - Type = CodecType.Audio, - - Conditions = new[] - { - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.AudioChannels, - Value = "2" - } - } - } - }; - - SubtitleProfiles = new[] - { - new SubtitleProfile - { - Format = "srt", - Method = SubtitleDeliveryMethod.Embed - } - }; - - ResponseProfiles = System.Array.Empty(); - } - } -} diff --git a/Emby.Dlna/Profiles/DishHopperJoeyProfile.cs b/Emby.Dlna/Profiles/DishHopperJoeyProfile.cs deleted file mode 100644 index 2a7524a6a2..0000000000 --- a/Emby.Dlna/Profiles/DishHopperJoeyProfile.cs +++ /dev/null @@ -1,228 +0,0 @@ -#pragma warning disable CS1591 - -using MediaBrowser.Model.Dlna; - -namespace Emby.Dlna.Profiles -{ - [System.Xml.Serialization.XmlRoot("Profile")] - public class DishHopperJoeyProfile : DefaultProfile - { - public DishHopperJoeyProfile() - { - Name = "Dish Hopper-Joey"; - - ProtocolInfo = "http-get:*:video/mp2t:*,http-get:*:video/mpeg:*,http-get:*:video/MP1S:*,http-get:*:video/mpeg2:*,http-get:*:video/mp4:*,http-get:*:video/x-matroska:*,http-get:*:audio/mpeg:*,http-get:*:audio/mpeg3:*,http-get:*:audio/mp3:*,http-get:*:audio/mp4:*,http-get:*:audio/mp4a-latm:*,http-get:*:image/jpeg:*"; - - Identification = new DeviceIdentification - { - Manufacturer = "Echostar Technologies LLC", - ManufacturerUrl = "http://www.echostar.com", - - Headers = new[] - { - new HttpHeaderInfo - { - Match = HeaderMatchType.Substring, - Name = "User-Agent", - Value = "Zip_" - } - } - }; - - TranscodingProfiles = new[] - { - new TranscodingProfile - { - Container = "mp3", - AudioCodec = "mp3", - Type = DlnaProfileType.Audio - }, - new TranscodingProfile - { - Container = "mp4", - Type = DlnaProfileType.Video, - AudioCodec = "aac", - VideoCodec = "h264" - }, - - new TranscodingProfile - { - Container = "jpeg", - Type = DlnaProfileType.Photo - } - }; - - DirectPlayProfiles = new[] - { - new DirectPlayProfile - { - Container = "mp4,mkv,mpeg,ts", - VideoCodec = "h264,mpeg2video", - AudioCodec = "mp3,ac3,aac,he-aac,pcm", - Type = DlnaProfileType.Video - }, - - new DirectPlayProfile - { - Container = "mp3,alac,flac", - Type = DlnaProfileType.Audio - }, - - new DirectPlayProfile - { - Container = "jpeg", - Type = DlnaProfileType.Photo - } - }; - - CodecProfiles = new[] - { - new CodecProfile - { - Type = CodecType.Video, - Codec = "h264", - Conditions = new[] - { - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Width, - Value = "1920", - IsRequired = true - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Height, - Value = "1080", - IsRequired = true - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.VideoFramerate, - Value = "30", - IsRequired = true - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.VideoBitrate, - Value = "20000000", - IsRequired = true - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.VideoLevel, - Value = "41", - IsRequired = true - } - } - }, - - new CodecProfile - { - Type = CodecType.Video, - Conditions = new[] - { - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Width, - Value = "1920", - IsRequired = true - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Height, - Value = "1080", - IsRequired = true - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.VideoFramerate, - Value = "30", - IsRequired = true - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.VideoBitrate, - Value = "20000000", - IsRequired = true - } - } - }, - - new CodecProfile - { - Type = CodecType.VideoAudio, - Codec = "ac3,he-aac", - Conditions = new[] - { - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.AudioChannels, - Value = "6", - IsRequired = true - } - } - }, - - new CodecProfile - { - Type = CodecType.VideoAudio, - Codec = "aac", - Conditions = new[] - { - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.AudioChannels, - Value = "2", - IsRequired = true - } - } - }, - - new CodecProfile - { - Type = CodecType.VideoAudio, - Conditions = new[] - { - // The device does not have any audio switching capabilities - new ProfileCondition - { - Condition = ProfileConditionType.Equals, - Property = ProfileConditionValue.IsSecondaryAudio, - Value = "false" - } - } - } - }; - - ResponseProfiles = new[] - { - new ResponseProfile - { - Container = "mkv,ts,mpegts", - Type = DlnaProfileType.Video, - MimeType = "video/mp4" - } - }; - - SubtitleProfiles = new[] - { - new SubtitleProfile - { - Format = "srt", - Method = SubtitleDeliveryMethod.Embed - } - }; - } - } -} diff --git a/Emby.Dlna/Profiles/Foobar2000Profile.cs b/Emby.Dlna/Profiles/Foobar2000Profile.cs deleted file mode 100644 index 68e959770a..0000000000 --- a/Emby.Dlna/Profiles/Foobar2000Profile.cs +++ /dev/null @@ -1,78 +0,0 @@ -#pragma warning disable CS1591 - -using MediaBrowser.Model.Dlna; - -namespace Emby.Dlna.Profiles -{ - [System.Xml.Serialization.XmlRoot("Profile")] - public class Foobar2000Profile : DefaultProfile - { - public Foobar2000Profile() - { - Name = "foobar2000"; - - SupportedMediaTypes = "Audio"; - - Identification = new DeviceIdentification - { - FriendlyName = @"foobar", - - Headers = new[] - { - new HttpHeaderInfo - { - Name = "User-Agent", - Value = "foobar", - Match = HeaderMatchType.Substring - } - } - }; - - DirectPlayProfiles = new[] - { - new DirectPlayProfile - { - Container = "mp3", - AudioCodec = "mp2,mp3", - Type = DlnaProfileType.Audio - }, - - new DirectPlayProfile - { - Container = "mp4", - AudioCodec = "mp4", - Type = DlnaProfileType.Audio - }, - - new DirectPlayProfile - { - Container = "aac,wav", - Type = DlnaProfileType.Audio - }, - - new DirectPlayProfile - { - Container = "flac", - AudioCodec = "flac", - Type = DlnaProfileType.Audio - }, - - new DirectPlayProfile - { - Container = "asf", - AudioCodec = "wmav2,wmapro,wmavoice", - Type = DlnaProfileType.Audio - }, - - new DirectPlayProfile - { - Container = "ogg", - AudioCodec = "vorbis", - Type = DlnaProfileType.Audio - } - }; - - ResponseProfiles = System.Array.Empty(); - } - } -} diff --git a/Emby.Dlna/Profiles/LgTvProfile.cs b/Emby.Dlna/Profiles/LgTvProfile.cs deleted file mode 100644 index fbb368d3e3..0000000000 --- a/Emby.Dlna/Profiles/LgTvProfile.cs +++ /dev/null @@ -1,211 +0,0 @@ -#pragma warning disable CS1591 - -using MediaBrowser.Model.Dlna; - -namespace Emby.Dlna.Profiles -{ - [System.Xml.Serialization.XmlRoot("Profile")] - public class LgTvProfile : DefaultProfile - { - public LgTvProfile() - { - Name = "LG Smart TV"; - - TimelineOffsetSeconds = 10; - - Identification = new DeviceIdentification - { - FriendlyName = @"LG.*", - - Headers = new[] - { - new HttpHeaderInfo - { - Name = "User-Agent", - Value = "LG", - Match = HeaderMatchType.Substring - } - } - }; - - TranscodingProfiles = new[] - { - new TranscodingProfile - { - Container = "mp3", - AudioCodec = "mp3", - Type = DlnaProfileType.Audio - }, - new TranscodingProfile - { - Container = "ts", - AudioCodec = "ac3,aac,mp3", - VideoCodec = "h264", - Type = DlnaProfileType.Video - }, - new TranscodingProfile - { - Container = "jpeg", - Type = DlnaProfileType.Photo - } - }; - - DirectPlayProfiles = new[] - { - new DirectPlayProfile - { - Container = "ts,mpegts,avi,mkv,m2ts", - VideoCodec = "h264", - AudioCodec = "aac,ac3,eac3,mp3,dca,dts", - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Container = "mp4,m4v", - VideoCodec = "h264,mpeg4", - AudioCodec = "aac,ac3,eac3,mp3,dca,dts", - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Container = "mp3", - Type = DlnaProfileType.Audio - }, - new DirectPlayProfile - { - Container = "jpeg", - Type = DlnaProfileType.Photo - } - }; - - ContainerProfiles = new[] - { - new ContainerProfile - { - Type = DlnaProfileType.Photo, - - Conditions = new[] - { - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Width, - Value = "1920" - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Height, - Value = "1080" - } - } - } - }; - - CodecProfiles = new[] - { - new CodecProfile - { - Type = CodecType.Video, - Codec = "mpeg4", - - Conditions = new[] - { - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Width, - Value = "1920" - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Height, - Value = "1080" - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.VideoFramerate, - Value = "30" - } - } - }, - - new CodecProfile - { - Type = CodecType.Video, - Codec = "h264", - - Conditions = new[] - { - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Width, - Value = "1920" - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Height, - Value = "1080" - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.VideoLevel, - Value = "41" - } - } - }, - - new CodecProfile - { - Type = CodecType.VideoAudio, - Codec = "ac3,eac3,aac,mp3", - - Conditions = new[] - { - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.AudioChannels, - Value = "6" - } - } - } - }; - - SubtitleProfiles = new[] - { - new SubtitleProfile - { - Format = "srt", - Method = SubtitleDeliveryMethod.Embed - }, - new SubtitleProfile - { - Format = "srt", - Method = SubtitleDeliveryMethod.External - } - }; - - ResponseProfiles = new[] - { - new ResponseProfile - { - Container = "m4v", - Type = DlnaProfileType.Video, - MimeType = "video/mp4" - }, - new ResponseProfile - { - Container = "ts,mpegts", - Type = DlnaProfileType.Video, - MimeType = "video/mpeg" - } - }; - } - } -} diff --git a/Emby.Dlna/Profiles/LinksysDMA2100Profile.cs b/Emby.Dlna/Profiles/LinksysDMA2100Profile.cs deleted file mode 100644 index 1a510dfecf..0000000000 --- a/Emby.Dlna/Profiles/LinksysDMA2100Profile.cs +++ /dev/null @@ -1,55 +0,0 @@ -#pragma warning disable CS1591 - -using MediaBrowser.Model.Dlna; - -namespace Emby.Dlna.Profiles -{ - [System.Xml.Serialization.XmlRoot("Profile")] - public class LinksysDMA2100Profile : DefaultProfile - { - public LinksysDMA2100Profile() - { - // Linksys DMA2100us does not need any transcoding of the formats we support statically - Name = "Linksys DMA2100"; - - Identification = new DeviceIdentification - { - ModelName = "DMA2100us" - }; - - DirectPlayProfiles = new[] - { - new DirectPlayProfile - { - Container = "mp3,flac,m4a,wma", - Type = DlnaProfileType.Audio - }, - - new DirectPlayProfile - { - Container = "avi,mp4,mkv,ts,mpegts,m4v", - Type = DlnaProfileType.Video - } - }; - - ResponseProfiles = new[] - { - new ResponseProfile - { - Container = "m4v", - Type = DlnaProfileType.Video, - MimeType = "video/mp4" - } - }; - - SubtitleProfiles = new[] - { - new SubtitleProfile - { - Format = "srt", - Method = SubtitleDeliveryMethod.Embed - } - }; - } - } -} diff --git a/Emby.Dlna/Profiles/MarantzProfile.cs b/Emby.Dlna/Profiles/MarantzProfile.cs deleted file mode 100644 index 24078ab29c..0000000000 --- a/Emby.Dlna/Profiles/MarantzProfile.cs +++ /dev/null @@ -1,43 +0,0 @@ -#pragma warning disable CS1591 - -using MediaBrowser.Model.Dlna; - -namespace Emby.Dlna.Profiles -{ - [System.Xml.Serialization.XmlRoot("Profile")] - public class MarantzProfile : DefaultProfile - { - public MarantzProfile() - { - Name = "Marantz"; - - SupportedMediaTypes = "Audio"; - - Identification = new DeviceIdentification - { - Manufacturer = @"Marantz", - - Headers = new[] - { - new HttpHeaderInfo - { - Name = "User-Agent", - Value = "Marantz", - Match = HeaderMatchType.Substring - } - } - }; - - DirectPlayProfiles = new[] - { - new DirectPlayProfile - { - Container = "aac,mp3,wav,wma,flac", - Type = DlnaProfileType.Audio - }, - }; - - ResponseProfiles = System.Array.Empty(); - } - } -} diff --git a/Emby.Dlna/Profiles/MediaMonkeyProfile.cs b/Emby.Dlna/Profiles/MediaMonkeyProfile.cs deleted file mode 100644 index 28d639b6db..0000000000 --- a/Emby.Dlna/Profiles/MediaMonkeyProfile.cs +++ /dev/null @@ -1,44 +0,0 @@ -#pragma warning disable CS1591 - -using System; -using MediaBrowser.Model.Dlna; - -namespace Emby.Dlna.Profiles -{ - [System.Xml.Serialization.XmlRoot("Profile")] - public class MediaMonkeyProfile : DefaultProfile - { - public MediaMonkeyProfile() - { - Name = "MediaMonkey"; - - SupportedMediaTypes = "Audio"; - - Identification = new DeviceIdentification - { - FriendlyName = @"MediaMonkey", - - Headers = new[] - { - new HttpHeaderInfo - { - Name = "User-Agent", - Value = "MediaMonkey", - Match = HeaderMatchType.Substring - } - } - }; - - DirectPlayProfiles = new[] - { - new DirectPlayProfile - { - Container = "aac,mp3,mpa,wav,wma,mp2,ogg,oga,webma,ape,opus,flac,m4a", - Type = DlnaProfileType.Audio - } - }; - - ResponseProfiles = Array.Empty(); - } - } -} diff --git a/Emby.Dlna/Profiles/PanasonicVieraProfile.cs b/Emby.Dlna/Profiles/PanasonicVieraProfile.cs deleted file mode 100644 index 0d536acf39..0000000000 --- a/Emby.Dlna/Profiles/PanasonicVieraProfile.cs +++ /dev/null @@ -1,222 +0,0 @@ -#pragma warning disable CS1591 - -using MediaBrowser.Model.Dlna; - -namespace Emby.Dlna.Profiles -{ - [System.Xml.Serialization.XmlRoot("Profile")] - public class PanasonicVieraProfile : DefaultProfile - { - public PanasonicVieraProfile() - { - Name = "Panasonic Viera"; - - Identification = new DeviceIdentification - { - FriendlyName = @"VIERA", - Manufacturer = "Panasonic", - - Headers = new[] - { - new HttpHeaderInfo - { - Name = "User-Agent", - Value = "Panasonic MIL DLNA", - Match = HeaderMatchType.Substring - } - } - }; - - AddXmlRootAttribute("xmlns:pv", "http://www.pv.com/pvns/"); - - TimelineOffsetSeconds = 10; - - TranscodingProfiles = new[] - { - new TranscodingProfile - { - Container = "mp3", - AudioCodec = "mp3", - Type = DlnaProfileType.Audio - }, - new TranscodingProfile - { - Container = "ts", - AudioCodec = "ac3", - VideoCodec = "h264", - Type = DlnaProfileType.Video - }, - new TranscodingProfile - { - Container = "jpeg", - Type = DlnaProfileType.Photo - } - }; - - DirectPlayProfiles = new[] - { - new DirectPlayProfile - { - Container = "mpeg,mpg", - VideoCodec = "mpeg2video,mpeg4", - AudioCodec = "ac3,mp3,pcm_dvd", - Type = DlnaProfileType.Video - }, - - new DirectPlayProfile - { - Container = "mkv", - VideoCodec = "h264,mpeg2video", - AudioCodec = "aac,ac3,dca,mp3,mp2,pcm,dts", - Type = DlnaProfileType.Video - }, - - new DirectPlayProfile - { - Container = "ts,mpegts", - VideoCodec = "h264,mpeg2video", - AudioCodec = "aac,mp3,mp2", - Type = DlnaProfileType.Video - }, - - new DirectPlayProfile - { - Container = "mp4,m4v", - VideoCodec = "h264", - AudioCodec = "aac,ac3,mp3,pcm", - Type = DlnaProfileType.Video - }, - - new DirectPlayProfile - { - Container = "mov", - VideoCodec = "h264", - AudioCodec = "aac,pcm", - Type = DlnaProfileType.Video - }, - - new DirectPlayProfile - { - Container = "avi", - VideoCodec = "mpeg4", - AudioCodec = "pcm", - Type = DlnaProfileType.Video - }, - - new DirectPlayProfile - { - Container = "flv", - VideoCodec = "h264", - AudioCodec = "aac", - Type = DlnaProfileType.Video - }, - - new DirectPlayProfile - { - Container = "mp3", - AudioCodec = "mp3", - Type = DlnaProfileType.Audio - }, - - new DirectPlayProfile - { - Container = "mp4", - AudioCodec = "aac", - Type = DlnaProfileType.Audio - }, - - new DirectPlayProfile - { - Container = "jpeg", - Type = DlnaProfileType.Photo - } - }; - - ContainerProfiles = new[] - { - new ContainerProfile - { - Type = DlnaProfileType.Photo, - - Conditions = new[] - { - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Width, - Value = "1920" - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Height, - Value = "1080" - } - } - } - }; - - CodecProfiles = new[] - { - new CodecProfile - { - Type = CodecType.Video, - - Conditions = new[] - { - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Width, - Value = "1920" - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Height, - Value = "1080" - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.VideoBitDepth, - Value = "8", - IsRequired = false - } - } - } - }; - - SubtitleProfiles = new[] - { - new SubtitleProfile - { - Format = "srt", - Method = SubtitleDeliveryMethod.Embed - }, - new SubtitleProfile - { - Format = "srt", - Method = SubtitleDeliveryMethod.External - } - }; - - ResponseProfiles = new[] - { - new ResponseProfile - { - Type = DlnaProfileType.Video, - Container = "ts,mpegts", - OrgPn = "MPEG_TS_SD_EU,MPEG_TS_SD_NA,MPEG_TS_SD_KO", - MimeType = "video/vnd.dlna.mpeg-tts" - }, - new ResponseProfile - { - Container = "m4v", - Type = DlnaProfileType.Video, - MimeType = "video/mp4" - } - }; - } - } -} diff --git a/Emby.Dlna/Profiles/PopcornHourProfile.cs b/Emby.Dlna/Profiles/PopcornHourProfile.cs deleted file mode 100644 index 7fbf8c1649..0000000000 --- a/Emby.Dlna/Profiles/PopcornHourProfile.cs +++ /dev/null @@ -1,225 +0,0 @@ -#pragma warning disable CS1591 - -using MediaBrowser.Model.Dlna; - -namespace Emby.Dlna.Profiles -{ - [System.Xml.Serialization.XmlRoot("Profile")] - public class PopcornHourProfile : DefaultProfile - { - public PopcornHourProfile() - { - Name = "Popcorn Hour"; - - TranscodingProfiles = new[] - { - new TranscodingProfile - { - Container = "mp3", - AudioCodec = "mp3", - Type = DlnaProfileType.Audio - }, - - new TranscodingProfile - { - Container = "mp4", - Type = DlnaProfileType.Video, - AudioCodec = "aac", - VideoCodec = "h264" - }, - - new TranscodingProfile - { - Container = "jpeg", - Type = DlnaProfileType.Photo - } - }; - - DirectPlayProfiles = new[] - { - new DirectPlayProfile - { - Container = "mp4,mov,m4v", - Type = DlnaProfileType.Video, - VideoCodec = "h264,mpeg4", - AudioCodec = "aac" - }, - - new DirectPlayProfile - { - Container = "ts,mpegts", - Type = DlnaProfileType.Video, - VideoCodec = "h264", - AudioCodec = "aac,ac3,eac3,mp3,mp2,pcm" - }, - - new DirectPlayProfile - { - Container = "asf,wmv", - Type = DlnaProfileType.Video, - VideoCodec = "wmv3,vc1", - AudioCodec = "wmav2,wmapro" - }, - - new DirectPlayProfile - { - Container = "avi", - Type = DlnaProfileType.Video, - VideoCodec = "mpeg4,msmpeg4", - AudioCodec = "mp3,ac3,eac3,mp2,pcm" - }, - - new DirectPlayProfile - { - Container = "mkv", - Type = DlnaProfileType.Video, - VideoCodec = "h264", - AudioCodec = "aac,mp3,ac3,eac3,mp2,pcm" - }, - new DirectPlayProfile - { - Container = "aac,mp3,flac,ogg,wma,wav", - Type = DlnaProfileType.Audio - }, - new DirectPlayProfile - { - Container = "jpeg,gif,bmp,png", - Type = DlnaProfileType.Photo - } - }; - - CodecProfiles = new[] - { - new CodecProfile - { - Type = CodecType.Video, - Codec = "h264", - Conditions = new[] - { - new ProfileCondition(ProfileConditionType.EqualsAny, ProfileConditionValue.VideoProfile, "baseline|constrained baseline"), - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Width, - Value = "1920" - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Height, - Value = "1080" - }, - new ProfileCondition - { - Condition = ProfileConditionType.NotEquals, - Property = ProfileConditionValue.IsAnamorphic, - Value = "true", - IsRequired = false - } - } - }, - - new CodecProfile - { - Type = CodecType.Video, - Conditions = new[] - { - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Width, - Value = "1920" - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Height, - Value = "1080" - }, - new ProfileCondition - { - Condition = ProfileConditionType.NotEquals, - Property = ProfileConditionValue.IsAnamorphic, - Value = "true", - IsRequired = false - } - } - }, - - new CodecProfile - { - Type = CodecType.VideoAudio, - Codec = "aac", - Conditions = new[] - { - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.AudioChannels, - Value = "2", - IsRequired = false - } - } - }, - - new CodecProfile - { - Type = CodecType.Audio, - Codec = "aac", - Conditions = new[] - { - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.AudioChannels, - Value = "2", - IsRequired = false - } - } - }, - - new CodecProfile - { - Type = CodecType.Audio, - Codec = "mp3", - Conditions = new[] - { - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.AudioChannels, - Value = "2", - IsRequired = false - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.AudioBitrate, - Value = "320000", - IsRequired = false - } - } - } - }; - - ResponseProfiles = new[] - { - new ResponseProfile - { - Container = "m4v", - Type = DlnaProfileType.Video, - MimeType = "video/mp4" - } - }; - - SubtitleProfiles = new[] - { - new SubtitleProfile - { - Format = "srt", - Method = SubtitleDeliveryMethod.Embed - } - }; - } - } -} diff --git a/Emby.Dlna/Profiles/SamsungSmartTvProfile.cs b/Emby.Dlna/Profiles/SamsungSmartTvProfile.cs deleted file mode 100644 index ddbebba2a4..0000000000 --- a/Emby.Dlna/Profiles/SamsungSmartTvProfile.cs +++ /dev/null @@ -1,367 +0,0 @@ -#pragma warning disable CS1591 - -using MediaBrowser.Model.Dlna; - -namespace Emby.Dlna.Profiles -{ - [System.Xml.Serialization.XmlRoot("Profile")] - public class SamsungSmartTvProfile : DefaultProfile - { - public SamsungSmartTvProfile() - { - Name = "Samsung Smart TV"; - - EnableAlbumArtInDidl = true; - - // Without this, older samsungs fail to browse - EnableSingleAlbumArtLimit = true; - - Identification = new DeviceIdentification - { - ModelUrl = "samsung.com", - - Headers = new[] - { - new HttpHeaderInfo - { - Name = "User-Agent", - Value = @"SEC_", - Match = HeaderMatchType.Substring - } - } - }; - - AddXmlRootAttribute("xmlns:sec", "http://www.sec.co.kr/"); - - TranscodingProfiles = new[] - { - new TranscodingProfile - { - Container = "mp3", - AudioCodec = "mp3", - Type = DlnaProfileType.Audio - }, - new TranscodingProfile - { - Container = "ts", - AudioCodec = "ac3", - VideoCodec = "h264", - Type = DlnaProfileType.Video, - EstimateContentLength = false - }, - new TranscodingProfile - { - Container = "jpeg", - Type = DlnaProfileType.Photo - } - }; - - DirectPlayProfiles = new[] - { - new DirectPlayProfile - { - Container = "asf", - VideoCodec = "h264,mpeg4,mjpeg", - AudioCodec = "mp3,ac3,wmav2,wmapro,wmavoice", - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Container = "avi", - VideoCodec = "h264,mpeg4,mjpeg", - AudioCodec = "mp3,ac3,dca,dts", - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Container = "mkv", - VideoCodec = "h264,mpeg4,mjpeg4", - AudioCodec = "mp3,ac3,dca,aac,dts", - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Container = "mp4,m4v", - VideoCodec = "h264,mpeg4", - AudioCodec = "mp3,aac", - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Container = "3gp", - VideoCodec = "h264,mpeg4", - AudioCodec = "aac,he-aac", - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Container = "mpg,mpeg", - VideoCodec = "mpeg1video,mpeg2video,h264", - AudioCodec = "ac3,mp2,mp3,aac", - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Container = "vro,vob", - VideoCodec = "mpeg1video,mpeg2video", - AudioCodec = "ac3,mp2,mp3", - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Container = "ts", - VideoCodec = "mpeg2video,h264,vc1", - AudioCodec = "ac3,aac,mp3,eac3", - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Container = "asf", - VideoCodec = "wmv2,wmv3", - AudioCodec = "wmav2,wmavoice", - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Container = "mp3,flac", - Type = DlnaProfileType.Audio - }, - new DirectPlayProfile - { - Container = "jpeg", - Type = DlnaProfileType.Photo - } - }; - - ContainerProfiles = new[] - { - new ContainerProfile - { - Type = DlnaProfileType.Photo, - - Conditions = new[] - { - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Width, - Value = "1920" - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Height, - Value = "1080" - } - } - } - }; - - CodecProfiles = new[] - { - new CodecProfile - { - Type = CodecType.Video, - Codec = "mpeg2video", - - Conditions = new[] - { - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Width, - Value = "1920" - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Height, - Value = "1080" - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.VideoFramerate, - Value = "30" - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.VideoBitrate, - Value = "30720000" - } - } - }, - - new CodecProfile - { - Type = CodecType.Video, - Codec = "mpeg4", - - Conditions = new[] - { - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Width, - Value = "1920" - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Height, - Value = "1080" - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.VideoFramerate, - Value = "30" - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.VideoBitrate, - Value = "8192000" - } - } - }, - - new CodecProfile - { - Type = CodecType.Video, - Codec = "h264", - - Conditions = new[] - { - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Width, - Value = "1920" - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Height, - Value = "1080" - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.VideoFramerate, - Value = "30" - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.VideoBitrate, - Value = "37500000" - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.VideoLevel, - Value = "41" - } - } - }, - - new CodecProfile - { - Type = CodecType.Video, - Codec = "wmv2,wmv3,vc1", - - Conditions = new[] - { - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Width, - Value = "1920" - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Height, - Value = "1080" - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.VideoFramerate, - Value = "30" - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.VideoBitrate, - Value = "25600000" - } - } - }, - - new CodecProfile - { - Type = CodecType.VideoAudio, - Codec = "wmav2,dca,aac,mp3,dts", - - Conditions = new[] - { - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.AudioChannels, - Value = "6" - } - } - } - }; - - ResponseProfiles = new[] - { - new ResponseProfile - { - Container = "avi", - MimeType = "video/x-msvideo", - Type = DlnaProfileType.Video - }, - - new ResponseProfile - { - Container = "mkv", - MimeType = "video/x-mkv", - Type = DlnaProfileType.Video - }, - - new ResponseProfile - { - Container = "flac", - MimeType = "audio/x-flac", - Type = DlnaProfileType.Audio - }, - new ResponseProfile - { - Container = "m4v", - Type = DlnaProfileType.Video, - MimeType = "video/mp4" - } - }; - - SubtitleProfiles = new[] - { - new SubtitleProfile - { - Format = "srt", - Method = SubtitleDeliveryMethod.Embed - }, - new SubtitleProfile - { - Format = "srt", - Method = SubtitleDeliveryMethod.External, - DidlMode = "CaptionInfoEx" - } - }; - } - } -} diff --git a/Emby.Dlna/Profiles/SharpSmartTvProfile.cs b/Emby.Dlna/Profiles/SharpSmartTvProfile.cs deleted file mode 100644 index aa8d434e3f..0000000000 --- a/Emby.Dlna/Profiles/SharpSmartTvProfile.cs +++ /dev/null @@ -1,121 +0,0 @@ -#pragma warning disable CS1591 - -using MediaBrowser.Model.Dlna; - -namespace Emby.Dlna.Profiles -{ - [System.Xml.Serialization.XmlRoot("Profile")] - public class SharpSmartTvProfile : DefaultProfile - { - public SharpSmartTvProfile() - { - Name = "Sharp Smart TV"; - - RequiresPlainFolders = true; - RequiresPlainVideoItems = true; - - Identification = new DeviceIdentification - { - Manufacturer = "Sharp", - - Headers = new[] - { - new HttpHeaderInfo - { - Name = "User-Agent", - Value = "Sharp", - Match = HeaderMatchType.Substring - } - } - }; - - TranscodingProfiles = new[] - { - new TranscodingProfile - { - Container = "mp3", - AudioCodec = "mp3", - Type = DlnaProfileType.Audio - }, - - new TranscodingProfile - { - Container = "ts", - Type = DlnaProfileType.Video, - AudioCodec = "ac3,aac,mp3,dts,dca", - VideoCodec = "h264", - EnableMpegtsM2TsMode = true - }, - - new TranscodingProfile - { - Container = "jpeg", - Type = DlnaProfileType.Photo - } - }; - - DirectPlayProfiles = new[] - { - new DirectPlayProfile - { - Container = "m4v,mkv,avi,mov,mp4", - VideoCodec = "h264,mpeg4", - AudioCodec = "aac,mp3,ac3,dts,dca", - Type = DlnaProfileType.Video - }, - - new DirectPlayProfile - { - Container = "asf,wmv", - Type = DlnaProfileType.Video - }, - - new DirectPlayProfile - { - Container = "mpg,mpeg", - VideoCodec = "mpeg2video", - AudioCodec = "mp3,aac", - Type = DlnaProfileType.Video - }, - - new DirectPlayProfile - { - Container = "flv", - VideoCodec = "h264", - AudioCodec = "mp3,aac", - Type = DlnaProfileType.Video - }, - - new DirectPlayProfile - { - Container = "mp3,wav", - Type = DlnaProfileType.Audio - } - }; - - SubtitleProfiles = new[] - { - new SubtitleProfile - { - Format = "srt", - Method = SubtitleDeliveryMethod.Embed - }, - new SubtitleProfile - { - Format = "srt", - Method = SubtitleDeliveryMethod.External - } - }; - - ResponseProfiles = new[] - { - new ResponseProfile - { - Container = "m4v", - Type = DlnaProfileType.Video, - MimeType = "video/mp4" - } - }; - } - } -} diff --git a/Emby.Dlna/Profiles/SonyBlurayPlayer2013.cs b/Emby.Dlna/Profiles/SonyBlurayPlayer2013.cs deleted file mode 100644 index 765c125045..0000000000 --- a/Emby.Dlna/Profiles/SonyBlurayPlayer2013.cs +++ /dev/null @@ -1,230 +0,0 @@ -#pragma warning disable CS1591 - -using System; -using MediaBrowser.Model.Dlna; - -namespace Emby.Dlna.Profiles -{ - [System.Xml.Serialization.XmlRoot("Profile")] - public class SonyBlurayPlayer2013 : DefaultProfile - { - public SonyBlurayPlayer2013() - { - Name = "Sony Blu-ray Player 2013"; - - Identification = new DeviceIdentification - { - ModelNumber = "BDP-2013", - - Headers = new[] - { - new HttpHeaderInfo - { - Name = "X-AV-Physical-Unit-Info", - Value = "BDP-S1100", - Match = HeaderMatchType.Substring - }, - new HttpHeaderInfo - { - Name = "X-AV-Physical-Unit-Info", - Value = "BDP-S3100", - Match = HeaderMatchType.Substring - }, - new HttpHeaderInfo - { - Name = "X-AV-Physical-Unit-Info", - Value = "BDP-S5100", - Match = HeaderMatchType.Substring - }, - new HttpHeaderInfo - { - Name = "X-AV-Physical-Unit-Info", - Value = "BDP-S6100", - Match = HeaderMatchType.Substring - }, - new HttpHeaderInfo - { - Name = "X-AV-Physical-Unit-Info", - Value = "BDP-S7100", - Match = HeaderMatchType.Substring - } - } - }; - - AddXmlRootAttribute("xmlns:av", "urn:schemas-sony-com:av"); - - ModelName = "Windows Media Player Sharing"; - ModelNumber = "3.0"; - Manufacturer = "Microsoft Corporation"; - - ProtocolInfo = "http-get:*:video/divx:DLNA.ORG_PN=MATROSKA;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG_PS_PAL;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG_PS_NTSC;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=MPEG_TS_SD_EU;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=MPEG_TS_SD_NA;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=MPEG_TS_SD_KO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/x-ms-wma:DLNA.ORG_PN=WMABASE;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/x-ms-wma:DLNA.ORG_PN=WMAFULL;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/mp4:DLNA.ORG_PN=AVC_MP4_MP_SD_AAC_MULT5;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/mpeg:DLNA.ORG_PN=MP3;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/L16;rate=44100;channels=1:DLNA.ORG_PN=LPCM;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/L16;rate=44100;channels=2:DLNA.ORG_PN=LPCM;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/L16;rate=48000;channels=1:DLNA.ORG_PN=LPCM;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/L16;rate=48000;channels=2:DLNA.ORG_PN=LPCM;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/mp4:DLNA.ORG_PN=AAC_ISO;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/mp4:DLNA.ORG_PN=AAC_ISO_320;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/vnd.dlna.adts:DLNA.ORG_PN=AAC_ADTS;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/vnd.dlna.adts:DLNA.ORG_PN=AAC_ADTS_320;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/flac:DLNA.ORG_PN=FLAC;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/ogg:DLNA.ORG_PN=OGG;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_SM;DLNA.ORG_OP=00;DLNA.ORG_FLAGS=00D00000000000000000000000000000,http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_MED;DLNA.ORG_OP=00;DLNA.ORG_FLAGS=00D00000000000000000000000000000,http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_LRG;DLNA.ORG_OP=00;DLNA.ORG_FLAGS=00D00000000000000000000000000000,http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_TN;DLNA.ORG_OP=00;DLNA.ORG_FLAGS=00D00000000000000000000000000000,http-get:*:image/png:DLNA.ORG_PN=PNG_LRG;DLNA.ORG_OP=00;DLNA.ORG_FLAGS=00D00000000000000000000000000000,http-get:*:image/png:DLNA.ORG_PN=PNG_TN;DLNA.ORG_OP=00;DLNA.ORG_FLAGS=00D00000000000000000000000000000,http-get:*:image/gif:DLNA.ORG_PN=GIF_LRG;DLNA.ORG_OP=00;DLNA.ORG_FLAGS=00D00000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG1;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=MPEG_TS_SD_EU_T;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG_TS_SD_EU_ISO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=MPEG_TS_SD_NA_T;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG_TS_SD_NA_ISO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=MPEG_TS_SD_KO_T;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG_TS_SD_KO_ISO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=MPEG_TS_JP_T;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-msvideo:DLNA.ORG_PN=AVI;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-flv:DLNA.ORG_PN=FLV;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-ms-dvr:DLNA.ORG_PN=DVR_MS;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/wtv:DLNA.ORG_PN=WTV;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/ogg:DLNA.ORG_PN=OGV;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/vnd.rn-realvideo:DLNA.ORG_PN=REAL_VIDEO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVMED_BASE;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVMED_FULL;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVHIGH_FULL;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVMED_PRO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVHIGH_PRO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-ms-asf:DLNA.ORG_PN=VC1_ASF_AP_L1_WMA;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-ms-asf:DLNA.ORG_PN=VC1_ASF_AP_L2_WMA;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-ms-asf:DLNA.ORG_PN=VC1_ASF_AP_L3_WMA;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/3gpp:DLNA.ORG_PN=MPEG4_P2_3GPP_SP_L0B_AAC;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/3gpp:DLNA.ORG_PN=MPEG4_P2_3GPP_SP_L0B_AMR;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/3gpp:DLNA.ORG_PN=MPEG4_H263_3GPP_P0_L10_AMR;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/3gpp:DLNA.ORG_PN=MPEG4_H263_MP4_P0_L10_AAC;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000"; - - TranscodingProfiles = new[] - { - new TranscodingProfile - { - Container = "mp3", - AudioCodec = "mp3", - Type = DlnaProfileType.Audio - }, - - new TranscodingProfile - { - Container = "mkv", - VideoCodec = "h264", - AudioCodec = "ac3,aac,mp3", - Type = DlnaProfileType.Video - }, - - new TranscodingProfile - { - Container = "jpeg", - Type = DlnaProfileType.Photo - } - }; - - DirectPlayProfiles = new[] - { - new DirectPlayProfile - { - Container = "ts,mpegts", - VideoCodec = "mpeg1video,mpeg2video,h264", - AudioCodec = "ac3,aac,mp3,pcm", - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Container = "mpeg,mpg", - VideoCodec = "mpeg1video,mpeg2video", - AudioCodec = "ac3,mp3,mp2,pcm", - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Container = "mp4,m4v", - VideoCodec = "mpeg4,h264", - AudioCodec = "ac3,aac,pcm,mp3", - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Container = "avi", - VideoCodec = "mpeg4,h264", - AudioCodec = "ac3,aac,mp3,pcm", - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Container = "mkv", - VideoCodec = "mpeg4,h264", - AudioCodec = "ac3,dca,aac,mp3,pcm,dts", - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Container = "m2ts,mts", - VideoCodec = "h264,mpeg4,vc1", - AudioCodec = "aac,mp3,ac3,dca,dts", - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Container = "wmv,asf", - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Container = "mp3,m4a,wma,wav", - Type = DlnaProfileType.Audio - }, - new DirectPlayProfile - { - Container = "jpeg,png,gif", - Type = DlnaProfileType.Photo - } - }; - - CodecProfiles = new[] - { - new CodecProfile - { - Type = CodecType.Video, - Codec = "h264", - Conditions = new[] - { - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Width, - Value = "1920" - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Height, - Value = "1080" - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.VideoFramerate, - Value = "30", - IsRequired = false - } - } - }, - - new CodecProfile - { - Type = CodecType.VideoAudio, - Codec = "ac3", - Conditions = new[] - { - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.AudioChannels, - Value = "6", - IsRequired = false - } - } - } - }; - - ContainerProfiles = new[] - { - new ContainerProfile - { - Type = DlnaProfileType.Photo, - - Conditions = new[] - { - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Width, - Value = "1920" - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Height, - Value = "1080" - } - } - } - }; - - SubtitleProfiles = new[] - { - new SubtitleProfile - { - Format = "srt", - Method = SubtitleDeliveryMethod.Embed - } - }; - - ResponseProfiles = Array.Empty(); - } - } -} diff --git a/Emby.Dlna/Profiles/SonyBlurayPlayer2014.cs b/Emby.Dlna/Profiles/SonyBlurayPlayer2014.cs deleted file mode 100644 index 390c8a3e43..0000000000 --- a/Emby.Dlna/Profiles/SonyBlurayPlayer2014.cs +++ /dev/null @@ -1,230 +0,0 @@ -#pragma warning disable CS1591 - -using System; -using MediaBrowser.Model.Dlna; - -namespace Emby.Dlna.Profiles -{ - [System.Xml.Serialization.XmlRoot("Profile")] - public class SonyBlurayPlayer2014 : DefaultProfile - { - public SonyBlurayPlayer2014() - { - Name = "Sony Blu-ray Player 2014"; - - Identification = new DeviceIdentification - { - ModelNumber = "BDP-2014", - - Headers = new[] - { - new HttpHeaderInfo - { - Name = "X-AV-Physical-Unit-Info", - Value = "BDP-S1200", - Match = HeaderMatchType.Substring - }, - new HttpHeaderInfo - { - Name = "X-AV-Physical-Unit-Info", - Value = "BDP-S3200", - Match = HeaderMatchType.Substring - }, - new HttpHeaderInfo - { - Name = "X-AV-Physical-Unit-Info", - Value = "BDP-S5200", - Match = HeaderMatchType.Substring - }, - new HttpHeaderInfo - { - Name = "X-AV-Physical-Unit-Info", - Value = "BDP-S6200", - Match = HeaderMatchType.Substring - }, - new HttpHeaderInfo - { - Name = "X-AV-Physical-Unit-Info", - Value = "BDP-S7200", - Match = HeaderMatchType.Substring - } - } - }; - - AddXmlRootAttribute("xmlns:av", "urn:schemas-sony-com:av"); - - ModelName = "Windows Media Player Sharing"; - ModelNumber = "3.0"; - Manufacturer = "Microsoft Corporation"; - - ProtocolInfo = "http-get:*:video/divx:DLNA.ORG_PN=MATROSKA;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG_PS_PAL;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG_PS_NTSC;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=MPEG_TS_SD_EU;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=MPEG_TS_SD_NA;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=MPEG_TS_SD_KO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/x-ms-wma:DLNA.ORG_PN=WMABASE;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/x-ms-wma:DLNA.ORG_PN=WMAFULL;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/mp4:DLNA.ORG_PN=AVC_MP4_MP_SD_AAC_MULT5;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/mpeg:DLNA.ORG_PN=MP3;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/L16;rate=44100;channels=1:DLNA.ORG_PN=LPCM;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/L16;rate=44100;channels=2:DLNA.ORG_PN=LPCM;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/L16;rate=48000;channels=1:DLNA.ORG_PN=LPCM;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/L16;rate=48000;channels=2:DLNA.ORG_PN=LPCM;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/mp4:DLNA.ORG_PN=AAC_ISO;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/mp4:DLNA.ORG_PN=AAC_ISO_320;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/vnd.dlna.adts:DLNA.ORG_PN=AAC_ADTS;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/vnd.dlna.adts:DLNA.ORG_PN=AAC_ADTS_320;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/flac:DLNA.ORG_PN=FLAC;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/ogg:DLNA.ORG_PN=OGG;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_SM;DLNA.ORG_OP=00;DLNA.ORG_FLAGS=00D00000000000000000000000000000,http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_MED;DLNA.ORG_OP=00;DLNA.ORG_FLAGS=00D00000000000000000000000000000,http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_LRG;DLNA.ORG_OP=00;DLNA.ORG_FLAGS=00D00000000000000000000000000000,http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_TN;DLNA.ORG_OP=00;DLNA.ORG_FLAGS=00D00000000000000000000000000000,http-get:*:image/png:DLNA.ORG_PN=PNG_LRG;DLNA.ORG_OP=00;DLNA.ORG_FLAGS=00D00000000000000000000000000000,http-get:*:image/png:DLNA.ORG_PN=PNG_TN;DLNA.ORG_OP=00;DLNA.ORG_FLAGS=00D00000000000000000000000000000,http-get:*:image/gif:DLNA.ORG_PN=GIF_LRG;DLNA.ORG_OP=00;DLNA.ORG_FLAGS=00D00000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG1;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=MPEG_TS_SD_EU_T;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG_TS_SD_EU_ISO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=MPEG_TS_SD_NA_T;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG_TS_SD_NA_ISO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=MPEG_TS_SD_KO_T;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG_TS_SD_KO_ISO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=MPEG_TS_JP_T;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-msvideo:DLNA.ORG_PN=AVI;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-flv:DLNA.ORG_PN=FLV;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-ms-dvr:DLNA.ORG_PN=DVR_MS;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/wtv:DLNA.ORG_PN=WTV;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/ogg:DLNA.ORG_PN=OGV;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/vnd.rn-realvideo:DLNA.ORG_PN=REAL_VIDEO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVMED_BASE;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVMED_FULL;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVHIGH_FULL;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVMED_PRO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVHIGH_PRO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-ms-asf:DLNA.ORG_PN=VC1_ASF_AP_L1_WMA;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-ms-asf:DLNA.ORG_PN=VC1_ASF_AP_L2_WMA;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-ms-asf:DLNA.ORG_PN=VC1_ASF_AP_L3_WMA;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/3gpp:DLNA.ORG_PN=MPEG4_P2_3GPP_SP_L0B_AAC;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/3gpp:DLNA.ORG_PN=MPEG4_P2_3GPP_SP_L0B_AMR;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/3gpp:DLNA.ORG_PN=MPEG4_H263_3GPP_P0_L10_AMR;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/3gpp:DLNA.ORG_PN=MPEG4_H263_MP4_P0_L10_AAC;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000"; - - TranscodingProfiles = new[] - { - new TranscodingProfile - { - Container = "mp3", - AudioCodec = "mp3", - Type = DlnaProfileType.Audio - }, - - new TranscodingProfile - { - Container = "mkv", - VideoCodec = "h264", - AudioCodec = "ac3,aac,mp3", - Type = DlnaProfileType.Video - }, - - new TranscodingProfile - { - Container = "jpeg", - Type = DlnaProfileType.Photo - } - }; - - DirectPlayProfiles = new[] - { - new DirectPlayProfile - { - Container = "ts,mpegts", - VideoCodec = "mpeg1video,mpeg2video,h264", - AudioCodec = "ac3,aac,mp3,pcm", - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Container = "mpeg,mpg", - VideoCodec = "mpeg1video,mpeg2video", - AudioCodec = "ac3,mp3,mp2,pcm", - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Container = "mp4,m4v", - VideoCodec = "mpeg4,h264", - AudioCodec = "ac3,aac,pcm,mp3", - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Container = "avi", - VideoCodec = "mpeg4,h264", - AudioCodec = "ac3,aac,mp3,pcm", - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Container = "mkv", - VideoCodec = "mpeg4,h264", - AudioCodec = "ac3,dca,aac,mp3,pcm,dts", - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Container = "m2ts,mts", - VideoCodec = "h264,mpeg4,vc1", - AudioCodec = "aac,mp3,ac3,dca,dts", - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Container = "wmv,asf", - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Container = "mp3,m4a,wma,wav", - Type = DlnaProfileType.Audio - }, - new DirectPlayProfile - { - Container = "jpeg,png,gif", - Type = DlnaProfileType.Photo - } - }; - - CodecProfiles = new[] - { - new CodecProfile - { - Type = CodecType.Video, - Codec = "h264", - Conditions = new[] - { - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Width, - Value = "1920" - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Height, - Value = "1080" - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.VideoFramerate, - Value = "30", - IsRequired = false - } - } - }, - - new CodecProfile - { - Type = CodecType.VideoAudio, - Codec = "ac3", - Conditions = new[] - { - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.AudioChannels, - Value = "6", - IsRequired = false - } - } - } - }; - - ContainerProfiles = new[] - { - new ContainerProfile - { - Type = DlnaProfileType.Photo, - - Conditions = new[] - { - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Width, - Value = "1920" - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Height, - Value = "1080" - } - } - } - }; - - SubtitleProfiles = new[] - { - new SubtitleProfile - { - Format = "srt", - Method = SubtitleDeliveryMethod.Embed - } - }; - - ResponseProfiles = Array.Empty(); - } - } -} diff --git a/Emby.Dlna/Profiles/SonyBlurayPlayer2015.cs b/Emby.Dlna/Profiles/SonyBlurayPlayer2015.cs deleted file mode 100644 index 25adc4d022..0000000000 --- a/Emby.Dlna/Profiles/SonyBlurayPlayer2015.cs +++ /dev/null @@ -1,218 +0,0 @@ -#pragma warning disable CS1591 - -using System; -using MediaBrowser.Model.Dlna; - -namespace Emby.Dlna.Profiles -{ - [System.Xml.Serialization.XmlRoot("Profile")] - public class SonyBlurayPlayer2015 : DefaultProfile - { - public SonyBlurayPlayer2015() - { - Name = "Sony Blu-ray Player 2015"; - - Identification = new DeviceIdentification - { - ModelNumber = "BDP-2015", - - Headers = new[] - { - new HttpHeaderInfo - { - Name = "X-AV-Physical-Unit-Info", - Value = "BDP-S1500", - Match = HeaderMatchType.Substring - }, - new HttpHeaderInfo - { - Name = "X-AV-Physical-Unit-Info", - Value = "BDP-S3500", - Match = HeaderMatchType.Substring - }, - new HttpHeaderInfo - { - Name = "X-AV-Physical-Unit-Info", - Value = "BDP-S6500", - Match = HeaderMatchType.Substring - } - } - }; - - AddXmlRootAttribute("xmlns:av", "urn:schemas-sony-com:av"); - - ModelName = "Windows Media Player Sharing"; - ModelNumber = "3.0"; - Manufacturer = "Microsoft Corporation"; - - ProtocolInfo = "http-get:*:video/divx:DLNA.ORG_PN=MATROSKA;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG_PS_PAL;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG_PS_NTSC;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=MPEG_TS_SD_EU;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=MPEG_TS_SD_NA;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=MPEG_TS_SD_KO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/x-ms-wma:DLNA.ORG_PN=WMABASE;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/x-ms-wma:DLNA.ORG_PN=WMAFULL;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/mp4:DLNA.ORG_PN=AVC_MP4_MP_SD_AAC_MULT5;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/mpeg:DLNA.ORG_PN=MP3;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/L16;rate=44100;channels=1:DLNA.ORG_PN=LPCM;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/L16;rate=44100;channels=2:DLNA.ORG_PN=LPCM;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/L16;rate=48000;channels=1:DLNA.ORG_PN=LPCM;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/L16;rate=48000;channels=2:DLNA.ORG_PN=LPCM;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/mp4:DLNA.ORG_PN=AAC_ISO;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/mp4:DLNA.ORG_PN=AAC_ISO_320;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/vnd.dlna.adts:DLNA.ORG_PN=AAC_ADTS;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/vnd.dlna.adts:DLNA.ORG_PN=AAC_ADTS_320;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/flac:DLNA.ORG_PN=FLAC;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/ogg:DLNA.ORG_PN=OGG;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_SM;DLNA.ORG_OP=00;DLNA.ORG_FLAGS=00D00000000000000000000000000000,http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_MED;DLNA.ORG_OP=00;DLNA.ORG_FLAGS=00D00000000000000000000000000000,http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_LRG;DLNA.ORG_OP=00;DLNA.ORG_FLAGS=00D00000000000000000000000000000,http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_TN;DLNA.ORG_OP=00;DLNA.ORG_FLAGS=00D00000000000000000000000000000,http-get:*:image/png:DLNA.ORG_PN=PNG_LRG;DLNA.ORG_OP=00;DLNA.ORG_FLAGS=00D00000000000000000000000000000,http-get:*:image/png:DLNA.ORG_PN=PNG_TN;DLNA.ORG_OP=00;DLNA.ORG_FLAGS=00D00000000000000000000000000000,http-get:*:image/gif:DLNA.ORG_PN=GIF_LRG;DLNA.ORG_OP=00;DLNA.ORG_FLAGS=00D00000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG1;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=MPEG_TS_SD_EU_T;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG_TS_SD_EU_ISO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=MPEG_TS_SD_NA_T;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG_TS_SD_NA_ISO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=MPEG_TS_SD_KO_T;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG_TS_SD_KO_ISO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=MPEG_TS_JP_T;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-msvideo:DLNA.ORG_PN=AVI;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-flv:DLNA.ORG_PN=FLV;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-ms-dvr:DLNA.ORG_PN=DVR_MS;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/wtv:DLNA.ORG_PN=WTV;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/ogg:DLNA.ORG_PN=OGV;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/vnd.rn-realvideo:DLNA.ORG_PN=REAL_VIDEO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVMED_BASE;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVMED_FULL;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVHIGH_FULL;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVMED_PRO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVHIGH_PRO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-ms-asf:DLNA.ORG_PN=VC1_ASF_AP_L1_WMA;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-ms-asf:DLNA.ORG_PN=VC1_ASF_AP_L2_WMA;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-ms-asf:DLNA.ORG_PN=VC1_ASF_AP_L3_WMA;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/3gpp:DLNA.ORG_PN=MPEG4_P2_3GPP_SP_L0B_AAC;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/3gpp:DLNA.ORG_PN=MPEG4_P2_3GPP_SP_L0B_AMR;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/3gpp:DLNA.ORG_PN=MPEG4_H263_3GPP_P0_L10_AMR;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/3gpp:DLNA.ORG_PN=MPEG4_H263_MP4_P0_L10_AAC;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000"; - - TranscodingProfiles = new[] - { - new TranscodingProfile - { - Container = "mp3", - AudioCodec = "mp3", - Type = DlnaProfileType.Audio - }, - - new TranscodingProfile - { - Container = "mkv", - VideoCodec = "h264", - AudioCodec = "ac3,aac,mp3", - Type = DlnaProfileType.Video - }, - - new TranscodingProfile - { - Container = "jpeg", - Type = DlnaProfileType.Photo - } - }; - - DirectPlayProfiles = new[] - { - new DirectPlayProfile - { - Container = "ts,mpegts", - VideoCodec = "mpeg1video,mpeg2video,h264", - AudioCodec = "ac3,aac,mp3,pcm", - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Container = "mpeg,mpg", - VideoCodec = "mpeg1video,mpeg2video", - AudioCodec = "ac3,mp3,mp2,pcm", - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Container = "mp4,m4v", - VideoCodec = "mpeg4,h264", - AudioCodec = "ac3,aac,pcm,mp3", - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Container = "avi", - VideoCodec = "mpeg4,h264", - AudioCodec = "ac3,aac,mp3,pcm", - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Container = "mkv", - VideoCodec = "mpeg4,h264", - AudioCodec = "ac3,dca,aac,mp3,pcm,dts", - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Container = "m2ts,mts", - VideoCodec = "h264,mpeg4,vc1", - AudioCodec = "aac,mp3,ac3,dca,dts", - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Container = "wmv,asf", - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Container = "mp3,m4a,wma,wav", - Type = DlnaProfileType.Audio - }, - new DirectPlayProfile - { - Container = "jpeg,png,gif", - Type = DlnaProfileType.Photo - } - }; - - CodecProfiles = new[] - { - new CodecProfile - { - Type = CodecType.Video, - Codec = "h264", - Conditions = new[] - { - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Width, - Value = "1920" - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Height, - Value = "1080" - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.VideoFramerate, - Value = "30", - IsRequired = false - } - } - }, - - new CodecProfile - { - Type = CodecType.VideoAudio, - Codec = "ac3", - Conditions = new[] - { - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.AudioChannels, - Value = "6", - IsRequired = false - } - } - } - }; - - ContainerProfiles = new[] - { - new ContainerProfile - { - Type = DlnaProfileType.Photo, - - Conditions = new[] - { - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Width, - Value = "1920" - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Height, - Value = "1080" - } - } - } - }; - - SubtitleProfiles = new[] - { - new SubtitleProfile - { - Format = "srt", - Method = SubtitleDeliveryMethod.Embed - } - }; - - ResponseProfiles = Array.Empty(); - } - } -} diff --git a/Emby.Dlna/Profiles/SonyBlurayPlayer2016.cs b/Emby.Dlna/Profiles/SonyBlurayPlayer2016.cs deleted file mode 100644 index 0a39a5f401..0000000000 --- a/Emby.Dlna/Profiles/SonyBlurayPlayer2016.cs +++ /dev/null @@ -1,218 +0,0 @@ -#pragma warning disable CS1591 - -using System; -using MediaBrowser.Model.Dlna; - -namespace Emby.Dlna.Profiles -{ - [System.Xml.Serialization.XmlRoot("Profile")] - public class SonyBlurayPlayer2016 : DefaultProfile - { - public SonyBlurayPlayer2016() - { - Name = "Sony Blu-ray Player 2016"; - - Identification = new DeviceIdentification - { - ModelNumber = "BDP-2016", - - Headers = new[] - { - new HttpHeaderInfo - { - Name = "X-AV-Physical-Unit-Info", - Value = "BDP-S1700", - Match = HeaderMatchType.Substring - }, - new HttpHeaderInfo - { - Name = "X-AV-Physical-Unit-Info", - Value = "BDP-S3700", - Match = HeaderMatchType.Substring - }, - new HttpHeaderInfo - { - Name = "X-AV-Physical-Unit-Info", - Value = "BDP-S6700", - Match = HeaderMatchType.Substring - } - } - }; - - AddXmlRootAttribute("xmlns:av", "urn:schemas-sony-com:av"); - - ModelName = "Windows Media Player Sharing"; - ModelNumber = "3.0"; - Manufacturer = "Microsoft Corporation"; - - ProtocolInfo = "http-get:*:video/divx:DLNA.ORG_PN=MATROSKA;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG_PS_PAL;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG_PS_NTSC;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=MPEG_TS_SD_EU;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=MPEG_TS_SD_NA;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=MPEG_TS_SD_KO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/x-ms-wma:DLNA.ORG_PN=WMABASE;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/x-ms-wma:DLNA.ORG_PN=WMAFULL;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/mp4:DLNA.ORG_PN=AVC_MP4_MP_SD_AAC_MULT5;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/mpeg:DLNA.ORG_PN=MP3;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/L16;rate=44100;channels=1:DLNA.ORG_PN=LPCM;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/L16;rate=44100;channels=2:DLNA.ORG_PN=LPCM;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/L16;rate=48000;channels=1:DLNA.ORG_PN=LPCM;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/L16;rate=48000;channels=2:DLNA.ORG_PN=LPCM;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/mp4:DLNA.ORG_PN=AAC_ISO;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/mp4:DLNA.ORG_PN=AAC_ISO_320;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/vnd.dlna.adts:DLNA.ORG_PN=AAC_ADTS;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/vnd.dlna.adts:DLNA.ORG_PN=AAC_ADTS_320;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/flac:DLNA.ORG_PN=FLAC;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/ogg:DLNA.ORG_PN=OGG;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_SM;DLNA.ORG_OP=00;DLNA.ORG_FLAGS=00D00000000000000000000000000000,http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_MED;DLNA.ORG_OP=00;DLNA.ORG_FLAGS=00D00000000000000000000000000000,http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_LRG;DLNA.ORG_OP=00;DLNA.ORG_FLAGS=00D00000000000000000000000000000,http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_TN;DLNA.ORG_OP=00;DLNA.ORG_FLAGS=00D00000000000000000000000000000,http-get:*:image/png:DLNA.ORG_PN=PNG_LRG;DLNA.ORG_OP=00;DLNA.ORG_FLAGS=00D00000000000000000000000000000,http-get:*:image/png:DLNA.ORG_PN=PNG_TN;DLNA.ORG_OP=00;DLNA.ORG_FLAGS=00D00000000000000000000000000000,http-get:*:image/gif:DLNA.ORG_PN=GIF_LRG;DLNA.ORG_OP=00;DLNA.ORG_FLAGS=00D00000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG1;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=MPEG_TS_SD_EU_T;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG_TS_SD_EU_ISO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=MPEG_TS_SD_NA_T;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG_TS_SD_NA_ISO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=MPEG_TS_SD_KO_T;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG_TS_SD_KO_ISO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=MPEG_TS_JP_T;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-msvideo:DLNA.ORG_PN=AVI;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-flv:DLNA.ORG_PN=FLV;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-ms-dvr:DLNA.ORG_PN=DVR_MS;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/wtv:DLNA.ORG_PN=WTV;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/ogg:DLNA.ORG_PN=OGV;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/vnd.rn-realvideo:DLNA.ORG_PN=REAL_VIDEO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVMED_BASE;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVMED_FULL;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVHIGH_FULL;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVMED_PRO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVHIGH_PRO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-ms-asf:DLNA.ORG_PN=VC1_ASF_AP_L1_WMA;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-ms-asf:DLNA.ORG_PN=VC1_ASF_AP_L2_WMA;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-ms-asf:DLNA.ORG_PN=VC1_ASF_AP_L3_WMA;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/3gpp:DLNA.ORG_PN=MPEG4_P2_3GPP_SP_L0B_AAC;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/3gpp:DLNA.ORG_PN=MPEG4_P2_3GPP_SP_L0B_AMR;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/3gpp:DLNA.ORG_PN=MPEG4_H263_3GPP_P0_L10_AMR;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/3gpp:DLNA.ORG_PN=MPEG4_H263_MP4_P0_L10_AAC;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000"; - - TranscodingProfiles = new[] - { - new TranscodingProfile - { - Container = "mp3", - AudioCodec = "mp3", - Type = DlnaProfileType.Audio - }, - - new TranscodingProfile - { - Container = "mkv", - VideoCodec = "h264", - AudioCodec = "ac3,aac,mp3", - Type = DlnaProfileType.Video - }, - - new TranscodingProfile - { - Container = "jpeg", - Type = DlnaProfileType.Photo - } - }; - - DirectPlayProfiles = new[] - { - new DirectPlayProfile - { - Container = "ts,mpegts", - VideoCodec = "mpeg1video,mpeg2video,h264", - AudioCodec = "ac3,aac,mp3,pcm", - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Container = "mpeg,mpg", - VideoCodec = "mpeg1video,mpeg2video", - AudioCodec = "ac3,mp3,mp2,pcm", - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Container = "mp4,m4v", - VideoCodec = "mpeg4,h264", - AudioCodec = "ac3,aac,pcm,mp3", - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Container = "avi", - VideoCodec = "mpeg4,h264", - AudioCodec = "ac3,aac,mp3,pcm", - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Container = "mkv", - VideoCodec = "mpeg4,h264", - AudioCodec = "ac3,dca,aac,mp3,pcm,dts", - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Container = "m2ts,mts", - VideoCodec = "h264,mpeg4,vc1", - AudioCodec = "aac,mp3,ac3,dca,dts", - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Container = "wmv,asf", - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Container = "mp3,m4a,wma,wav", - Type = DlnaProfileType.Audio - }, - new DirectPlayProfile - { - Container = "jpeg,png,gif", - Type = DlnaProfileType.Photo - } - }; - - CodecProfiles = new[] - { - new CodecProfile - { - Type = CodecType.Video, - Codec = "h264", - Conditions = new[] - { - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Width, - Value = "1920" - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Height, - Value = "1080" - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.VideoFramerate, - Value = "30", - IsRequired = false - } - } - }, - - new CodecProfile - { - Type = CodecType.VideoAudio, - Codec = "ac3", - Conditions = new[] - { - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.AudioChannels, - Value = "6", - IsRequired = false - } - } - } - }; - - ContainerProfiles = new[] - { - new ContainerProfile - { - Type = DlnaProfileType.Photo, - - Conditions = new[] - { - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Width, - Value = "1920" - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Height, - Value = "1080" - } - } - } - }; - - SubtitleProfiles = new[] - { - new SubtitleProfile - { - Format = "srt", - Method = SubtitleDeliveryMethod.Embed - } - }; - - ResponseProfiles = Array.Empty(); - } - } -} diff --git a/Emby.Dlna/Profiles/SonyBlurayPlayerProfile.cs b/Emby.Dlna/Profiles/SonyBlurayPlayerProfile.cs deleted file mode 100644 index 05c8ab1c14..0000000000 --- a/Emby.Dlna/Profiles/SonyBlurayPlayerProfile.cs +++ /dev/null @@ -1,284 +0,0 @@ -#pragma warning disable CS1591 - -using MediaBrowser.Model.Dlna; - -namespace Emby.Dlna.Profiles -{ - [System.Xml.Serialization.XmlRoot("Profile")] - public class SonyBlurayPlayerProfile : DefaultProfile - { - public SonyBlurayPlayerProfile() - { - Name = "Sony Blu-ray Player"; - - Identification = new DeviceIdentification - { - FriendlyName = @"Blu-ray Disc Player", - Manufacturer = "Sony", - - Headers = new[] - { - new HttpHeaderInfo - { - Name = "X-AV-Client-Info", - Value = @"(Blu-ray Disc Player|Home Theater System|Home Theatre System|Media Player)", - Match = HeaderMatchType.Regex - }, - - new HttpHeaderInfo - { - Name = "X-AV-Physical-Unit-Info", - Value = @"(Blu-ray Disc Player|Home Theater System|Home Theatre System|Media Player)", - Match = HeaderMatchType.Regex - } - } - }; - - AddXmlRootAttribute("xmlns:av", "urn:schemas-sony-com:av"); - - ModelName = "Windows Media Player Sharing"; - ModelNumber = "3.0"; - Manufacturer = "Microsoft Corporation"; - - ProtocolInfo = "http-get:*:video/divx:DLNA.ORG_PN=MATROSKA;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG_PS_PAL;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG_PS_NTSC;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=MPEG_TS_SD_EU;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=MPEG_TS_SD_NA;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=MPEG_TS_SD_KO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/x-ms-wma:DLNA.ORG_PN=WMABASE;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/x-ms-wma:DLNA.ORG_PN=WMAFULL;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/mp4:DLNA.ORG_PN=AVC_MP4_MP_SD_AAC_MULT5;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/mpeg:DLNA.ORG_PN=MP3;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/L16;rate=44100;channels=1:DLNA.ORG_PN=LPCM;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/L16;rate=44100;channels=2:DLNA.ORG_PN=LPCM;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/L16;rate=48000;channels=1:DLNA.ORG_PN=LPCM;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/L16;rate=48000;channels=2:DLNA.ORG_PN=LPCM;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/mp4:DLNA.ORG_PN=AAC_ISO;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/mp4:DLNA.ORG_PN=AAC_ISO_320;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/vnd.dlna.adts:DLNA.ORG_PN=AAC_ADTS;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/vnd.dlna.adts:DLNA.ORG_PN=AAC_ADTS_320;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/flac:DLNA.ORG_PN=FLAC;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/ogg:DLNA.ORG_PN=OGG;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_SM;DLNA.ORG_OP=00;DLNA.ORG_FLAGS=00D00000000000000000000000000000,http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_MED;DLNA.ORG_OP=00;DLNA.ORG_FLAGS=00D00000000000000000000000000000,http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_LRG;DLNA.ORG_OP=00;DLNA.ORG_FLAGS=00D00000000000000000000000000000,http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_TN;DLNA.ORG_OP=00;DLNA.ORG_FLAGS=00D00000000000000000000000000000,http-get:*:image/png:DLNA.ORG_PN=PNG_LRG;DLNA.ORG_OP=00;DLNA.ORG_FLAGS=00D00000000000000000000000000000,http-get:*:image/png:DLNA.ORG_PN=PNG_TN;DLNA.ORG_OP=00;DLNA.ORG_FLAGS=00D00000000000000000000000000000,http-get:*:image/gif:DLNA.ORG_PN=GIF_LRG;DLNA.ORG_OP=00;DLNA.ORG_FLAGS=00D00000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG1;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=MPEG_TS_SD_EU_T;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG_TS_SD_EU_ISO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=MPEG_TS_SD_NA_T;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG_TS_SD_NA_ISO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=MPEG_TS_SD_KO_T;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG_TS_SD_KO_ISO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=MPEG_TS_JP_T;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-msvideo:DLNA.ORG_PN=AVI;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-flv:DLNA.ORG_PN=FLV;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-ms-dvr:DLNA.ORG_PN=DVR_MS;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/wtv:DLNA.ORG_PN=WTV;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/ogg:DLNA.ORG_PN=OGV;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/vnd.rn-realvideo:DLNA.ORG_PN=REAL_VIDEO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVMED_BASE;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVMED_FULL;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVHIGH_FULL;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVMED_PRO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVHIGH_PRO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-ms-asf:DLNA.ORG_PN=VC1_ASF_AP_L1_WMA;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-ms-asf:DLNA.ORG_PN=VC1_ASF_AP_L2_WMA;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-ms-asf:DLNA.ORG_PN=VC1_ASF_AP_L3_WMA;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/3gpp:DLNA.ORG_PN=MPEG4_P2_3GPP_SP_L0B_AAC;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/3gpp:DLNA.ORG_PN=MPEG4_P2_3GPP_SP_L0B_AMR;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/3gpp:DLNA.ORG_PN=MPEG4_H263_3GPP_P0_L10_AMR;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/3gpp:DLNA.ORG_PN=MPEG4_H263_MP4_P0_L10_AAC;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000"; - - TranscodingProfiles = new[] - { - new TranscodingProfile - { - Container = "mp3", - AudioCodec = "mp3", - Type = DlnaProfileType.Audio - }, - - new TranscodingProfile - { - Container = "ts", - VideoCodec = "mpeg2video", - AudioCodec = "ac3", - Type = DlnaProfileType.Video - }, - - new TranscodingProfile - { - Container = "jpeg", - Type = DlnaProfileType.Photo - } - }; - - DirectPlayProfiles = new[] - { - new DirectPlayProfile - { - Container = "ts,mpegts", - VideoCodec = "mpeg1video,mpeg2video,h264", - AudioCodec = "ac3,aac,mp3,pcm", - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Container = "mpeg", - VideoCodec = "mpeg1video,mpeg2video", - AudioCodec = "ac3,mp3,pcm", - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Container = "avi,mp4,m4v", - VideoCodec = "mpeg4,h264", - AudioCodec = "ac3,aac,mp3,pcm", - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Container = "mp3", - AudioCodec = "mp3", - Type = DlnaProfileType.Audio - }, - new DirectPlayProfile - { - Container = "asf", - AudioCodec = "wmav2,wmapro,wmavoice", - Type = DlnaProfileType.Audio - }, - new DirectPlayProfile - { - Container = "jpeg", - Type = DlnaProfileType.Photo - } - }; - - CodecProfiles = new[] - { - new CodecProfile - { - Type = CodecType.Video, - Codec = "h264", - Conditions = new[] - { - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Width, - Value = "1920" - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Height, - Value = "1080" - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.VideoFramerate, - Value = "30", - IsRequired = false - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.VideoLevel, - Value = "41", - IsRequired = false - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.VideoBitrate, - Value = "15360000", - IsRequired = false - } - } - }, - - new CodecProfile - { - Type = CodecType.VideoAudio, - Codec = "ac3", - Conditions = new[] - { - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.AudioChannels, - Value = "6", - IsRequired = false - } - } - }, - - new CodecProfile - { - Type = CodecType.VideoAudio, - Codec = "aac", - Conditions = new[] - { - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.AudioChannels, - Value = "2", - IsRequired = false - } - } - } - }; - - ContainerProfiles = new[] - { - new ContainerProfile - { - Type = DlnaProfileType.Photo, - - Conditions = new[] - { - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Width, - Value = "1920" - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Height, - Value = "1080" - } - } - } - }; - - ResponseProfiles = new[] - { - new ResponseProfile - { - Container = "ts,mpegts", - 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", - Type = DlnaProfileType.Video - }, - - new ResponseProfile - { - Container = "avi", - MimeType = "video/mpeg", - Type = DlnaProfileType.Video - }, - - new ResponseProfile - { - Container = "mkv", - MimeType = "video/vnd.dlna.mpeg-tts", - Type = DlnaProfileType.Video - }, - - new ResponseProfile - { - Container = "ts,mpegts", - MimeType = "video/vnd.dlna.mpeg-tts", - Type = DlnaProfileType.Video - }, - - new ResponseProfile - { - Container = "mp4", - MimeType = "video/mpeg", - Type = DlnaProfileType.Video - }, - - new ResponseProfile - { - Container = "m4v", - MimeType = "video/mpeg", - Type = DlnaProfileType.Video - }, - - new ResponseProfile - { - Container = "mpeg", - MimeType = "video/mpeg", - Type = DlnaProfileType.Video - }, - - new ResponseProfile - { - Container = "mp3", - MimeType = "audio/mpeg", - Type = DlnaProfileType.Audio - } - }; - - SubtitleProfiles = new[] - { - new SubtitleProfile - { - Format = "srt", - Method = SubtitleDeliveryMethod.Embed - } - }; - } - } -} diff --git a/Emby.Dlna/Profiles/SonyBravia2010Profile.cs b/Emby.Dlna/Profiles/SonyBravia2010Profile.cs deleted file mode 100644 index 9f0d82b8f8..0000000000 --- a/Emby.Dlna/Profiles/SonyBravia2010Profile.cs +++ /dev/null @@ -1,366 +0,0 @@ -#pragma warning disable CS1591 - -using MediaBrowser.Model.Dlna; - -namespace Emby.Dlna.Profiles -{ - [System.Xml.Serialization.XmlRoot("Profile")] - public class SonyBravia2010Profile : DefaultProfile - { - public SonyBravia2010Profile() - { - Name = "Sony Bravia (2010)"; - - Identification = new DeviceIdentification - { - FriendlyName = @"KDL-[0-9]{2}[EHLNPB]X[0-9][01][0-9].*", - Manufacturer = "Sony", - - Headers = new[] - { - new HttpHeaderInfo - { - Name = "X-AV-Client-Info", - Value = @".*KDL-[0-9]{2}[EHLNPB]X[0-9][01][0-9].*", - Match = HeaderMatchType.Regex - } - } - }; - - AddXmlRootAttribute("xmlns:av", "urn:schemas-sony-com:av"); - - AlbumArtPn = "JPEG_TN"; - - ModelName = "Windows Media Player Sharing"; - ModelNumber = "3.0"; - ModelUrl = "http://www.microsoft.com/"; - Manufacturer = "Microsoft Corporation"; - ManufacturerUrl = "http://www.microsoft.com/"; - SonyAggregationFlags = "10"; - ProtocolInfo = - "http-get:*:audio/mpeg:DLNA.ORG_PN=MP3;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_SM;DLNA.ORG_OP=00;DLNA.ORG_FLAGS=00D00000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG_PS_PAL;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000"; - - EnableSingleAlbumArtLimit = true; - EnableAlbumArtInDidl = true; - - TranscodingProfiles = new[] - { - new TranscodingProfile - { - Container = "mp3", - AudioCodec = "mp3", - Type = DlnaProfileType.Audio - }, - new TranscodingProfile - { - Container = "ts", - VideoCodec = "h264", - AudioCodec = "ac3", - Type = DlnaProfileType.Video, - EnableMpegtsM2TsMode = true - }, - new TranscodingProfile - { - Container = "jpeg", - Type = DlnaProfileType.Photo - } - }; - - DirectPlayProfiles = new[] - { - new DirectPlayProfile - { - Container = "ts,mpegts", - VideoCodec = "h264", - AudioCodec = "ac3,aac,mp3", - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Container = "ts,mpegts", - VideoCodec = "mpeg1video,mpeg2video", - AudioCodec = "mp3,mp2", - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Container = "mpeg", - VideoCodec = "mpeg2video,mpeg1video", - AudioCodec = "mp3,mp2", - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Container = "mp3", - AudioCodec = "mp3", - Type = DlnaProfileType.Audio - } - }; - - ResponseProfiles = new[] - { - new ResponseProfile - { - Container = "ts,mpegts", - 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", - Type = DlnaProfileType.Video, - - Conditions = new[] - { - new ProfileCondition - { - Condition = ProfileConditionType.Equals, - Property = ProfileConditionValue.PacketLength, - Value = "192" - }, - new ProfileCondition - { - Condition = ProfileConditionType.Equals, - Property = ProfileConditionValue.VideoTimestamp, - Value = "Valid" - } - } - }, - - new ResponseProfile - { - Container = "ts,mpegts", - 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", - Type = DlnaProfileType.Video, - - Conditions = new[] - { - new ProfileCondition - { - Condition = ProfileConditionType.Equals, - Property = ProfileConditionValue.PacketLength, - Value = "188" - } - } - }, - - new ResponseProfile - { - Container = "ts,mpegts", - 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", - Type = DlnaProfileType.Video - }, - - new ResponseProfile - { - Container = "ts,mpegts", - VideoCodec = "mpeg2video", - MimeType = "video/vnd.dlna.mpeg-tts", - OrgPn = "MPEG_TS_SD_EU,MPEG_TS_SD_NA,MPEG_TS_SD_KO", - Type = DlnaProfileType.Video - }, - - new ResponseProfile - { - Container = "mpeg", - VideoCodec = "mpeg1video,mpeg2video", - MimeType = "video/mpeg", - OrgPn = "MPEG_PS_NTSC,MPEG_PS_PAL", - Type = DlnaProfileType.Video - } - }; - - ContainerProfiles = new[] - { - new ContainerProfile - { - Type = DlnaProfileType.Photo, - - Conditions = new[] - { - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Width, - Value = "1920" - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Height, - Value = "1080" - } - } - } - }; - - CodecProfiles = new[] - { - new CodecProfile - { - Type = CodecType.Video, - Codec = "h264", - Conditions = new[] - { - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Width, - Value = "1920" - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Height, - Value = "1080" - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.VideoFramerate, - Value = "30" - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.VideoBitrate, - Value = "20000000" - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.VideoLevel, - Value = "41" - } - } - }, - - new CodecProfile - { - Type = CodecType.Video, - Codec = "mpeg2video", - Conditions = new[] - { - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Width, - Value = "1920" - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Height, - Value = "1080" - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.VideoFramerate, - Value = "30" - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.VideoBitrate, - Value = "20000000" - } - } - }, - - new CodecProfile - { - Type = CodecType.Video, - Conditions = new[] - { - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Width, - Value = "1920" - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Height, - Value = "1080" - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.VideoFramerate, - Value = "30" - } - } - }, - - new CodecProfile - { - Type = CodecType.VideoAudio, - Codec = "ac3", - - Conditions = new[] - { - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.AudioChannels, - Value = "6" - } - } - }, - - new CodecProfile - { - Type = CodecType.VideoAudio, - Codec = "aac", - - Conditions = new[] - { - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.AudioChannels, - Value = "2" - }, - new ProfileCondition - { - Condition = ProfileConditionType.NotEquals, - Property = ProfileConditionValue.AudioProfile, - Value = "he-aac" - } - } - }, - - new CodecProfile - { - Type = CodecType.VideoAudio, - Codec = "mp3,mp2", - - Conditions = new[] - { - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.AudioChannels, - Value = "2" - } - } - } - }; - - SubtitleProfiles = new[] - { - new SubtitleProfile - { - Format = "srt", - Method = SubtitleDeliveryMethod.Embed - } - }; - } - } -} diff --git a/Emby.Dlna/Profiles/SonyBravia2011Profile.cs b/Emby.Dlna/Profiles/SonyBravia2011Profile.cs deleted file mode 100644 index dfb91817ac..0000000000 --- a/Emby.Dlna/Profiles/SonyBravia2011Profile.cs +++ /dev/null @@ -1,389 +0,0 @@ -#pragma warning disable CS1591 - -using MediaBrowser.Model.Dlna; - -namespace Emby.Dlna.Profiles -{ - [System.Xml.Serialization.XmlRoot("Profile")] - public class SonyBravia2011Profile : DefaultProfile - { - public SonyBravia2011Profile() - { - Name = "Sony Bravia (2011)"; - - Identification = new DeviceIdentification - { - FriendlyName = @"KDL-[0-9]{2}([A-Z]X[0-9]2[0-9]|CX400).*", - Manufacturer = "Sony", - - Headers = new[] - { - new HttpHeaderInfo - { - Name = "X-AV-Client-Info", - Value = @".*KDL-[0-9]{2}([A-Z]X[0-9]2[0-9]|CX400).*", - Match = HeaderMatchType.Regex - } - } - }; - - AddXmlRootAttribute("xmlns:av", "urn:schemas-sony-com:av"); - - AlbumArtPn = "JPEG_TN"; - - ModelName = "Windows Media Player Sharing"; - ModelNumber = "3.0"; - ModelUrl = "http://www.microsoft.com/"; - Manufacturer = "Microsoft Corporation"; - ManufacturerUrl = "http://www.microsoft.com/"; - SonyAggregationFlags = "10"; - EnableSingleAlbumArtLimit = true; - EnableAlbumArtInDidl = true; - - TranscodingProfiles = new[] - { - new TranscodingProfile - { - Container = "mp3", - AudioCodec = "mp3", - Type = DlnaProfileType.Audio - }, - new TranscodingProfile - { - Container = "ts", - VideoCodec = "h264", - AudioCodec = "ac3", - Type = DlnaProfileType.Video, - EnableMpegtsM2TsMode = true - }, - new TranscodingProfile - { - Container = "jpeg", - Type = DlnaProfileType.Photo - } - }; - - DirectPlayProfiles = new[] - { - new DirectPlayProfile - { - Container = "ts,mpegts", - VideoCodec = "h264", - AudioCodec = "ac3,aac,mp3", - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Container = "ts,mpegts", - VideoCodec = "mpeg2video", - AudioCodec = "mp3", - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Container = "mp4,m4v", - VideoCodec = "h264,mpeg4", - AudioCodec = "ac3,aac,mp3", - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Container = "mpeg", - VideoCodec = "mpeg2video,mpeg1video", - AudioCodec = "mp3", - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Container = "asf", - VideoCodec = "wmv2,wmv3,vc1", - AudioCodec = "wmav2,wmapro,wmavoice", - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Container = "mp3", - AudioCodec = "mp3", - Type = DlnaProfileType.Audio - }, - new DirectPlayProfile - { - Container = "asf", - AudioCodec = "wmav2,wmapro,wmavoice", - Type = DlnaProfileType.Audio - } - }; - - ContainerProfiles = new[] - { - new ContainerProfile - { - Type = DlnaProfileType.Photo, - - Conditions = new[] - { - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Width, - Value = "1920" - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Height, - Value = "1080" - } - } - } - }; - - ResponseProfiles = new[] - { - new ResponseProfile - { - Container = "ts,mpegts", - 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", - Type = DlnaProfileType.Video, - - Conditions = new[] - { - new ProfileCondition - { - Condition = ProfileConditionType.Equals, - Property = ProfileConditionValue.PacketLength, - Value = "192" - }, - new ProfileCondition - { - Condition = ProfileConditionType.Equals, - Property = ProfileConditionValue.VideoTimestamp, - Value = "Valid" - } - } - }, - - new ResponseProfile - { - Container = "ts,mpegts", - 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", - Type = DlnaProfileType.Video, - - Conditions = new[] - { - new ProfileCondition - { - Condition = ProfileConditionType.Equals, - Property = ProfileConditionValue.PacketLength, - Value = "188" - } - } - }, - - new ResponseProfile - { - Container = "ts,mpegts", - 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", - Type = DlnaProfileType.Video - }, - - new ResponseProfile - { - Container = "ts,mpegts", - VideoCodec = "mpeg2video", - MimeType = "video/vnd.dlna.mpeg-tts", - OrgPn = "MPEG_TS_SD_EU,MPEG_TS_SD_NA,MPEG_TS_SD_KO", - Type = DlnaProfileType.Video - }, - - new ResponseProfile - { - Container = "mpeg", - VideoCodec = "mpeg1video,mpeg2video", - MimeType = "video/mpeg", - OrgPn = "MPEG_PS_NTSC,MPEG_PS_PAL", - Type = DlnaProfileType.Video - }, - new ResponseProfile - { - Container = "m4v", - Type = DlnaProfileType.Video, - MimeType = "video/mp4" - } - }; - - CodecProfiles = new[] - { - new CodecProfile - { - Type = CodecType.Video, - Codec = "h264", - Conditions = new[] - { - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Width, - Value = "1920" - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Height, - Value = "1080" - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.VideoFramerate, - Value = "30" - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.VideoBitrate, - Value = "20000000" - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.VideoLevel, - Value = "41" - } - } - }, - - new CodecProfile - { - Type = CodecType.Video, - Codec = "mpeg2video", - Conditions = new[] - { - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Width, - Value = "1920" - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Height, - Value = "1080" - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.VideoFramerate, - Value = "30" - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.VideoBitrate, - Value = "20000000" - } - } - }, - - new CodecProfile - { - Type = CodecType.Video, - Conditions = new[] - { - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Width, - Value = "1920" - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Height, - Value = "1080" - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.VideoFramerate, - Value = "30" - } - } - }, - - new CodecProfile - { - Type = CodecType.VideoAudio, - Codec = "ac3", - - Conditions = new[] - { - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.AudioChannels, - Value = "6" - } - } - }, - - new CodecProfile - { - Type = CodecType.VideoAudio, - Codec = "aac", - - Conditions = new[] - { - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.AudioChannels, - Value = "2" - }, - new ProfileCondition - { - Condition = ProfileConditionType.NotEquals, - Property = ProfileConditionValue.AudioProfile, - Value = "he-aac" - } - } - }, - - new CodecProfile - { - Type = CodecType.VideoAudio, - Codec = "mp3,mp2", - - Conditions = new[] - { - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.AudioChannels, - Value = "2" - } - } - } - }; - - SubtitleProfiles = new[] - { - new SubtitleProfile - { - Format = "srt", - Method = SubtitleDeliveryMethod.Embed - } - }; - } - } -} diff --git a/Emby.Dlna/Profiles/SonyBravia2012Profile.cs b/Emby.Dlna/Profiles/SonyBravia2012Profile.cs deleted file mode 100644 index d59ee38d74..0000000000 --- a/Emby.Dlna/Profiles/SonyBravia2012Profile.cs +++ /dev/null @@ -1,307 +0,0 @@ -#pragma warning disable CS1591 - -using MediaBrowser.Model.Dlna; - -namespace Emby.Dlna.Profiles -{ - [System.Xml.Serialization.XmlRoot("Profile")] - public class SonyBravia2012Profile : DefaultProfile - { - public SonyBravia2012Profile() - { - Name = "Sony Bravia (2012)"; - - Identification = new DeviceIdentification - { - FriendlyName = @"KDL-[0-9]{2}[A-Z]X[0-9]5([0-9]|G).*", - Manufacturer = "Sony", - - Headers = new[] - { - new HttpHeaderInfo - { - Name = "X-AV-Client-Info", - Value = @".*KDL-[0-9]{2}[A-Z]X[0-9]5([0-9]|G).*", - Match = HeaderMatchType.Regex - } - } - }; - - AddXmlRootAttribute("xmlns:av", "urn:schemas-sony-com:av"); - - AlbumArtPn = "JPEG_TN"; - - ModelName = "Windows Media Player Sharing"; - ModelNumber = "3.0"; - ModelUrl = "http://www.microsoft.com/"; - Manufacturer = "Microsoft Corporation"; - ManufacturerUrl = "http://www.microsoft.com/"; - SonyAggregationFlags = "10"; - EnableSingleAlbumArtLimit = true; - EnableAlbumArtInDidl = true; - - TranscodingProfiles = new[] - { - new TranscodingProfile - { - Container = "mp3", - AudioCodec = "mp3", - Type = DlnaProfileType.Audio - }, - new TranscodingProfile - { - Container = "ts", - VideoCodec = "h264", - AudioCodec = "ac3", - Type = DlnaProfileType.Video, - EnableMpegtsM2TsMode = true - }, - new TranscodingProfile - { - Container = "jpeg", - Type = DlnaProfileType.Photo - } - }; - - DirectPlayProfiles = new[] - { - new DirectPlayProfile - { - Container = "ts,mpegts", - VideoCodec = "h264", - AudioCodec = "ac3,aac,mp3", - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Container = "ts,mpegts", - VideoCodec = "mpeg2video", - AudioCodec = "mp3,mp2", - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Container = "mp4,m4v", - VideoCodec = "h264,mpeg4", - AudioCodec = "ac3,aac,mp3,mp2", - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Container = "avi", - VideoCodec = "mpeg4", - AudioCodec = "ac3,mp3", - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Container = "mpeg", - VideoCodec = "mpeg2video,mpeg1video", - AudioCodec = "mp3,mp2", - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Container = "asf", - VideoCodec = "wmv2,wmv3,vc1", - AudioCodec = "wmav2,wmapro,wmavoice", - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Container = "mp3", - AudioCodec = "mp3", - Type = DlnaProfileType.Audio - }, - new DirectPlayProfile - { - Container = "asf", - AudioCodec = "wmav2,wmapro,wmavoice", - Type = DlnaProfileType.Audio - }, - new DirectPlayProfile - { - Container = "jpeg", - Type = DlnaProfileType.Photo - } - }; - - ResponseProfiles = new[] - { - new ResponseProfile - { - Container = "ts,mpegts", - 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", - Type = DlnaProfileType.Video, - - Conditions = new[] - { - new ProfileCondition - { - Condition = ProfileConditionType.Equals, - Property = ProfileConditionValue.PacketLength, - Value = "192" - }, - new ProfileCondition - { - Condition = ProfileConditionType.Equals, - Property = ProfileConditionValue.VideoTimestamp, - Value = "Valid" - } - } - }, - - new ResponseProfile - { - Container = "ts,mpegts", - 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", - Type = DlnaProfileType.Video, - - Conditions = new[] - { - new ProfileCondition - { - Condition = ProfileConditionType.Equals, - Property = ProfileConditionValue.PacketLength, - Value = "188" - } - } - }, - - new ResponseProfile - { - Container = "ts,mpegts", - 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", - Type = DlnaProfileType.Video - }, - - new ResponseProfile - { - Container = "ts,mpegts", - VideoCodec = "mpeg2video", - MimeType = "video/vnd.dlna.mpeg-tts", - OrgPn = "MPEG_TS_SD_EU,MPEG_TS_SD_NA,MPEG_TS_SD_KO", - Type = DlnaProfileType.Video - }, - - new ResponseProfile - { - Container = "mpeg", - VideoCodec = "mpeg1video,mpeg2video", - MimeType = "video/mpeg", - OrgPn = "MPEG_PS_NTSC,MPEG_PS_PAL", - Type = DlnaProfileType.Video - }, - new ResponseProfile - { - Container = "m4v", - Type = DlnaProfileType.Video, - MimeType = "video/mp4" - } - }; - - ContainerProfiles = new[] - { - new ContainerProfile - { - Type = DlnaProfileType.Photo, - - Conditions = new[] - { - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Width, - Value = "1920" - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Height, - Value = "1080" - } - } - } - }; - - CodecProfiles = new[] - { - new CodecProfile - { - Type = CodecType.Video, - Conditions = new[] - { - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Width, - Value = "1920" - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Height, - Value = "1080" - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.VideoFramerate, - Value = "30" - } - } - }, - - new CodecProfile - { - Type = CodecType.VideoAudio, - Codec = "ac3", - - Conditions = new[] - { - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.AudioChannels, - Value = "6" - } - } - }, - - new CodecProfile - { - Type = CodecType.VideoAudio, - Codec = "mp3,mp2", - - Conditions = new[] - { - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.AudioChannels, - Value = "2" - } - } - } - }; - - SubtitleProfiles = new[] - { - new SubtitleProfile - { - Format = "srt", - Method = SubtitleDeliveryMethod.Embed - } - }; - } - } -} diff --git a/Emby.Dlna/Profiles/SonyBravia2013Profile.cs b/Emby.Dlna/Profiles/SonyBravia2013Profile.cs deleted file mode 100644 index 73b0fd67eb..0000000000 --- a/Emby.Dlna/Profiles/SonyBravia2013Profile.cs +++ /dev/null @@ -1,324 +0,0 @@ -#pragma warning disable CS1591 - -using MediaBrowser.Model.Dlna; - -namespace Emby.Dlna.Profiles -{ - [System.Xml.Serialization.XmlRoot("Profile")] - public class SonyBravia2013Profile : DefaultProfile - { - public SonyBravia2013Profile() - { - Name = "Sony Bravia (2013)"; - - Identification = new DeviceIdentification - { - FriendlyName = @"KDL-[0-9]{2}[WR][5689][0-9]{2}A.*", - Manufacturer = "Sony", - - Headers = new[] - { - new HttpHeaderInfo - { - Name = "X-AV-Client-Info", - Value = @".*KDL-[0-9]{2}[WR][5689][0-9]{2}A.*", - Match = HeaderMatchType.Regex - } - } - }; - - AddXmlRootAttribute("xmlns:av", "urn:schemas-sony-com:av"); - - AlbumArtPn = "JPEG_TN"; - - ModelName = "Windows Media Player Sharing"; - ModelNumber = "3.0"; - ModelUrl = "http://www.microsoft.com/"; - Manufacturer = "Microsoft Corporation"; - ManufacturerUrl = "http://www.microsoft.com/"; - SonyAggregationFlags = "10"; - EnableSingleAlbumArtLimit = true; - EnableAlbumArtInDidl = true; - - TranscodingProfiles = new[] - { - new TranscodingProfile - { - Container = "mp3", - Type = DlnaProfileType.Audio - }, - new TranscodingProfile - { - Container = "ts", - VideoCodec = "h264", - AudioCodec = "ac3", - Type = DlnaProfileType.Video, - EnableMpegtsM2TsMode = true - }, - new TranscodingProfile - { - Container = "jpeg", - Type = DlnaProfileType.Photo - } - }; - - DirectPlayProfiles = new[] - { - new DirectPlayProfile - { - Container = "ts,mpegts", - VideoCodec = "h264", - AudioCodec = "ac3,eac3,aac,mp3", - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Container = "ts,mpegts", - VideoCodec = "mpeg2video", - AudioCodec = "mp3,mp2", - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Container = "mp4,m4v", - VideoCodec = "h264,mpeg4", - AudioCodec = "ac3,eac3,aac,mp3,mp2", - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Container = "mov", - VideoCodec = "h264,mpeg4,mjpeg", - AudioCodec = "ac3,eac3,aac,mp3,mp2", - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Container = "mkv", - VideoCodec = "h264,mpeg4,vp8", - AudioCodec = "ac3,eac3,aac,mp3,mp2,pcm,vorbis", - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Container = "avi", - VideoCodec = "mpeg4", - AudioCodec = "ac3,eac3,mp3", - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Container = "avi", - VideoCodec = "mjpeg", - AudioCodec = "pcm", - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Container = "mpeg", - VideoCodec = "mpeg2video,mpeg1video", - AudioCodec = "mp3,mp2", - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Container = "asf", - VideoCodec = "wmv2,wmv3,vc1", - AudioCodec = "wmav2,wmapro,wmavoice", - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Container = "mp3", - AudioCodec = "mp3", - Type = DlnaProfileType.Audio - }, - new DirectPlayProfile - { - Container = "mp4", - AudioCodec = "aac", - Type = DlnaProfileType.Audio - }, - new DirectPlayProfile - { - Container = "wav", - AudioCodec = "pcm", - Type = DlnaProfileType.Audio - }, - new DirectPlayProfile - { - Container = "asf", - AudioCodec = "wmav2,wmapro,wmavoice", - Type = DlnaProfileType.Audio - }, - new DirectPlayProfile - { - Container = "jpeg", - Type = DlnaProfileType.Photo - } - }; - - ContainerProfiles = new[] - { - new ContainerProfile - { - Type = DlnaProfileType.Photo, - - Conditions = new[] - { - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Width, - Value = "1920" - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Height, - Value = "1080" - } - } - } - }; - - ResponseProfiles = new[] - { - new ResponseProfile - { - Container = "ts,mpegts", - 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", - Type = DlnaProfileType.Video, - - Conditions = new[] - { - new ProfileCondition - { - Condition = ProfileConditionType.Equals, - Property = ProfileConditionValue.PacketLength, - Value = "192" - }, - new ProfileCondition - { - Condition = ProfileConditionType.Equals, - Property = ProfileConditionValue.VideoTimestamp, - Value = "Valid" - } - } - }, - - new ResponseProfile - { - Container = "ts,mpegts", - 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", - Type = DlnaProfileType.Video, - - Conditions = new[] - { - new ProfileCondition - { - Condition = ProfileConditionType.Equals, - Property = ProfileConditionValue.PacketLength, - Value = "188" - } - } - }, - - new ResponseProfile - { - Container = "ts,mpegts", - 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", - Type = DlnaProfileType.Video - }, - - new ResponseProfile - { - Container = "ts,mpegts", - VideoCodec = "mpeg2video", - MimeType = "video/vnd.dlna.mpeg-tts", - OrgPn = "MPEG_TS_SD_EU,MPEG_TS_SD_NA,MPEG_TS_SD_KO", - Type = DlnaProfileType.Video - }, - - new ResponseProfile - { - Container = "mpeg", - VideoCodec = "mpeg1video,mpeg2video", - MimeType = "video/mpeg", - OrgPn = "MPEG_PS_NTSC,MPEG_PS_PAL", - Type = DlnaProfileType.Video - }, - new ResponseProfile - { - Container = "m4v", - Type = DlnaProfileType.Video, - MimeType = "video/mp4" - } - }; - - CodecProfiles = new[] - { - new CodecProfile - { - Type = CodecType.Video, - - Conditions = new[] - { - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Width, - Value = "1920" - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Height, - Value = "1080" - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.VideoFramerate, - Value = "30" - } - } - }, - - new CodecProfile - { - Type = CodecType.VideoAudio, - Codec = "mp3,mp2", - - Conditions = new[] - { - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.AudioChannels, - Value = "2" - } - } - } - }; - - SubtitleProfiles = new[] - { - new SubtitleProfile - { - Format = "srt", - Method = SubtitleDeliveryMethod.Embed - } - }; - } - } -} diff --git a/Emby.Dlna/Profiles/SonyBravia2014Profile.cs b/Emby.Dlna/Profiles/SonyBravia2014Profile.cs deleted file mode 100644 index db8ee5750f..0000000000 --- a/Emby.Dlna/Profiles/SonyBravia2014Profile.cs +++ /dev/null @@ -1,324 +0,0 @@ -#pragma warning disable CS1591 - -using MediaBrowser.Model.Dlna; - -namespace Emby.Dlna.Profiles -{ - [System.Xml.Serialization.XmlRoot("Profile")] - public class SonyBravia2014Profile : DefaultProfile - { - public SonyBravia2014Profile() - { - Name = "Sony Bravia (2014)"; - - Identification = new DeviceIdentification - { - FriendlyName = @"(KDL-[0-9]{2}W[5-9][0-9]{2}B|KDL-[0-9]{2}R480|XBR-[0-9]{2}X[89][0-9]{2}B|KD-[0-9]{2}[SX][89][0-9]{3}B).*", - Manufacturer = "Sony", - - Headers = new[] - { - new HttpHeaderInfo - { - Name = "X-AV-Client-Info", - Value = @".*(KDL-[0-9]{2}W[5-9][0-9]{2}B|KDL-[0-9]{2}R480|XBR-[0-9]{2}X[89][0-9]{2}B|KD-[0-9]{2}[SX][89][0-9]{3}B).*", - Match = HeaderMatchType.Regex - } - } - }; - - AddXmlRootAttribute("xmlns:av", "urn:schemas-sony-com:av"); - - AlbumArtPn = "JPEG_TN"; - - ModelName = "Windows Media Player Sharing"; - ModelNumber = "3.0"; - ModelUrl = "http://www.microsoft.com/"; - Manufacturer = "Microsoft Corporation"; - ManufacturerUrl = "http://www.microsoft.com/"; - SonyAggregationFlags = "10"; - EnableSingleAlbumArtLimit = true; - EnableAlbumArtInDidl = true; - - TranscodingProfiles = new[] - { - new TranscodingProfile - { - Container = "mp3", - Type = DlnaProfileType.Audio - }, - new TranscodingProfile - { - Container = "ts", - VideoCodec = "h264", - AudioCodec = "ac3", - Type = DlnaProfileType.Video, - EnableMpegtsM2TsMode = true - }, - new TranscodingProfile - { - Container = "jpeg", - Type = DlnaProfileType.Photo - } - }; - - DirectPlayProfiles = new[] - { - new DirectPlayProfile - { - Container = "ts,mpegts", - VideoCodec = "h264", - AudioCodec = "ac3,eac3,aac,mp3", - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Container = "ts,mpegts", - VideoCodec = "mpeg2video", - AudioCodec = "mp3,mp2", - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Container = "mp4,m4v", - VideoCodec = "h264,mpeg4", - AudioCodec = "ac3,eac3,aac,mp3,mp2", - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Container = "mov", - VideoCodec = "h264,mpeg4,mjpeg", - AudioCodec = "ac3,eac3,aac,mp3,mp2", - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Container = "mkv", - VideoCodec = "h264,mpeg4,vp8", - AudioCodec = "ac3,eac3,aac,mp3,mp2,pcm,vorbis", - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Container = "avi", - VideoCodec = "mpeg4", - AudioCodec = "ac3,eac3,mp3", - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Container = "avi", - VideoCodec = "mjpeg", - AudioCodec = "pcm", - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Container = "mpeg", - VideoCodec = "mpeg2video,mpeg1video", - AudioCodec = "mp3,mp2", - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Container = "asf", - VideoCodec = "wmv2,wmv3,vc1", - AudioCodec = "wmav2,wmapro,wmavoice", - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Container = "mp3", - AudioCodec = "mp3", - Type = DlnaProfileType.Audio - }, - new DirectPlayProfile - { - Container = "mp4", - AudioCodec = "aac", - Type = DlnaProfileType.Audio - }, - new DirectPlayProfile - { - Container = "wav", - AudioCodec = "pcm", - Type = DlnaProfileType.Audio - }, - new DirectPlayProfile - { - Container = "asf", - AudioCodec = "wmav2,wmapro,wmavoice", - Type = DlnaProfileType.Audio - }, - new DirectPlayProfile - { - Container = "jpeg", - Type = DlnaProfileType.Photo - } - }; - - ContainerProfiles = new[] - { - new ContainerProfile - { - Type = DlnaProfileType.Photo, - - Conditions = new[] - { - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Width, - Value = "1920" - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Height, - Value = "1080" - } - } - } - }; - - ResponseProfiles = new[] - { - new ResponseProfile - { - Container = "ts,mpegts", - 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", - Type = DlnaProfileType.Video, - - Conditions = new[] - { - new ProfileCondition - { - Condition = ProfileConditionType.Equals, - Property = ProfileConditionValue.PacketLength, - Value = "192" - }, - new ProfileCondition - { - Condition = ProfileConditionType.Equals, - Property = ProfileConditionValue.VideoTimestamp, - Value = "Valid" - } - } - }, - - new ResponseProfile - { - Container = "ts,mpegts", - 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", - Type = DlnaProfileType.Video, - - Conditions = new[] - { - new ProfileCondition - { - Condition = ProfileConditionType.Equals, - Property = ProfileConditionValue.PacketLength, - Value = "188" - } - } - }, - - new ResponseProfile - { - Container = "ts,mpegts", - 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", - Type = DlnaProfileType.Video - }, - - new ResponseProfile - { - Container = "ts,mpegts", - VideoCodec = "mpeg2video", - MimeType = "video/vnd.dlna.mpeg-tts", - OrgPn = "MPEG_TS_SD_EU,MPEG_TS_SD_NA,MPEG_TS_SD_KO", - Type = DlnaProfileType.Video - }, - - new ResponseProfile - { - Container = "mpeg", - VideoCodec = "mpeg1video,mpeg2video", - MimeType = "video/mpeg", - OrgPn = "MPEG_PS_NTSC,MPEG_PS_PAL", - Type = DlnaProfileType.Video - }, - new ResponseProfile - { - Container = "m4v", - Type = DlnaProfileType.Video, - MimeType = "video/mp4" - } - }; - - CodecProfiles = new[] - { - new CodecProfile - { - Type = CodecType.Video, - - Conditions = new[] - { - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Width, - Value = "1920" - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Height, - Value = "1080" - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.VideoFramerate, - Value = "30" - } - } - }, - - new CodecProfile - { - Type = CodecType.VideoAudio, - Codec = "mp3,mp2", - - Conditions = new[] - { - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.AudioChannels, - Value = "2" - } - } - } - }; - - SubtitleProfiles = new[] - { - new SubtitleProfile - { - Format = "srt", - Method = SubtitleDeliveryMethod.Embed - } - }; - } - } -} diff --git a/Emby.Dlna/Profiles/SonyPs3Profile.cs b/Emby.Dlna/Profiles/SonyPs3Profile.cs deleted file mode 100644 index e4a7a3a596..0000000000 --- a/Emby.Dlna/Profiles/SonyPs3Profile.cs +++ /dev/null @@ -1,269 +0,0 @@ -#pragma warning disable CS1591 - -using MediaBrowser.Model.Dlna; - -namespace Emby.Dlna.Profiles -{ - [System.Xml.Serialization.XmlRoot("Profile")] - public class SonyPs3Profile : DefaultProfile - { - public SonyPs3Profile() - { - Name = "Sony PlayStation 3"; - - Identification = new DeviceIdentification - { - FriendlyName = "PLAYSTATION 3", - - Headers = new[] - { - new HttpHeaderInfo - { - Name = "User-Agent", - Value = @"PLAYSTATION 3", - Match = HeaderMatchType.Substring - }, - - new HttpHeaderInfo - { - Name = "X-AV-Client-Info", - Value = @"PLAYSTATION 3", - Match = HeaderMatchType.Substring - } - } - }; - - AlbumArtPn = "JPEG_TN"; - - SonyAggregationFlags = "10"; - EnableSingleAlbumArtLimit = true; - - DirectPlayProfiles = new[] - { - new DirectPlayProfile - { - Container = "avi", - Type = DlnaProfileType.Video, - VideoCodec = "mpeg4", - AudioCodec = "mp2,mp3" - }, - new DirectPlayProfile - { - Container = "ts,mpegts", - Type = DlnaProfileType.Video, - VideoCodec = "mpeg1video,mpeg2video,h264", - AudioCodec = "aac,ac3,mp2" - }, - new DirectPlayProfile - { - Container = "mpeg", - Type = DlnaProfileType.Video, - VideoCodec = "mpeg1video,mpeg2video", - AudioCodec = "mp2" - }, - new DirectPlayProfile - { - Container = "mp4", - Type = DlnaProfileType.Video, - VideoCodec = "h264,mpeg4", - AudioCodec = "aac,ac3" - }, - new DirectPlayProfile - { - Container = "aac,mp3,wav", - Type = DlnaProfileType.Audio - }, - new DirectPlayProfile - { - Container = "jpeg,png,gif,bmp,tiff", - Type = DlnaProfileType.Photo - } - }; - - TranscodingProfiles = new[] - { - new TranscodingProfile - { - Container = "mp3", - AudioCodec = "mp3", - Type = DlnaProfileType.Audio - }, - new TranscodingProfile - { - Container = "ts", - VideoCodec = "h264", - AudioCodec = "aac,ac3,mp2", - Type = DlnaProfileType.Video - }, - new TranscodingProfile - { - Container = "jpeg", - Type = DlnaProfileType.Photo - } - }; - - ContainerProfiles = new[] - { - new ContainerProfile - { - Type = DlnaProfileType.Photo, - - Conditions = new[] - { - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Width, - Value = "1920" - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Height, - Value = "1080" - } - } - } - }; - - CodecProfiles = new[] - { - new CodecProfile - { - Type = CodecType.Video, - Codec = "h264", - - Conditions = new[] - { - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Width, - Value = "1920" - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Height, - Value = "1080" - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.VideoFramerate, - Value = "30", - IsRequired = false - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.VideoBitrate, - Value = "15360000", - IsRequired = false - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.VideoLevel, - Value = "41", - IsRequired = false - } - } - }, - - new CodecProfile - { - Type = CodecType.VideoAudio, - Codec = "ac3", - - Conditions = new[] - { - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.AudioChannels, - Value = "6", - IsRequired = false - }, - - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.AudioBitrate, - Value = "640000", - IsRequired = false - } - } - }, - - new CodecProfile - { - Type = CodecType.VideoAudio, - Codec = "wmapro", - - Conditions = new[] - { - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.AudioChannels, - Value = "2" - } - } - }, - - new CodecProfile - { - Type = CodecType.VideoAudio, - Codec = "aac", - - Conditions = new[] - { - new ProfileCondition - { - Condition = ProfileConditionType.NotEquals, - Property = ProfileConditionValue.AudioProfile, - Value = "he-aac", - IsRequired = false - } - } - } - }; - - ResponseProfiles = new[] - { - new ResponseProfile - { - Container = "mp4,mov", - AudioCodec = "aac", - MimeType = "video/mp4", - Type = DlnaProfileType.Video - }, - - new ResponseProfile - { - Container = "avi", - MimeType = "video/divx", - OrgPn = "AVI", - Type = DlnaProfileType.Video - }, - - new ResponseProfile - { - Container = "wav", - MimeType = "audio/wav", - Type = DlnaProfileType.Audio - } - }; - - SubtitleProfiles = new[] - { - new SubtitleProfile - { - Format = "srt", - Method = SubtitleDeliveryMethod.Embed - } - }; - } - } -} diff --git a/Emby.Dlna/Profiles/SonyPs4Profile.cs b/Emby.Dlna/Profiles/SonyPs4Profile.cs deleted file mode 100644 index 985df0c9a5..0000000000 --- a/Emby.Dlna/Profiles/SonyPs4Profile.cs +++ /dev/null @@ -1,278 +0,0 @@ -#pragma warning disable CS1591 - -using MediaBrowser.Model.Dlna; - -namespace Emby.Dlna.Profiles -{ - [System.Xml.Serialization.XmlRoot("Profile")] - public class SonyPs4Profile : DefaultProfile - { - public SonyPs4Profile() - { - Name = "Sony PlayStation 4"; - - Identification = new DeviceIdentification - { - FriendlyName = "PLAYSTATION 4", - - Headers = new[] - { - new HttpHeaderInfo - { - Name = "User-Agent", - Value = @"PLAYSTATION 4", - Match = HeaderMatchType.Substring - }, - - new HttpHeaderInfo - { - Name = "X-AV-Client-Info", - Value = @"PLAYSTATION 4", - Match = HeaderMatchType.Substring - } - } - }; - - AlbumArtPn = "JPEG_TN"; - - SonyAggregationFlags = "10"; - EnableSingleAlbumArtLimit = true; - - DirectPlayProfiles = new[] - { - new DirectPlayProfile - { - Container = "avi", - Type = DlnaProfileType.Video, - VideoCodec = "mpeg4", - AudioCodec = "mp2,mp3" - }, - new DirectPlayProfile - { - Container = "ts,mpegts", - Type = DlnaProfileType.Video, - VideoCodec = "mpeg1video,mpeg2video,h264", - AudioCodec = "aac,ac3,mp2" - }, - new DirectPlayProfile - { - Container = "mpeg", - Type = DlnaProfileType.Video, - VideoCodec = "mpeg1video,mpeg2video", - AudioCodec = "mp2" - }, - new DirectPlayProfile - { - Container = "mp4,mkv,m4v", - Type = DlnaProfileType.Video, - VideoCodec = "h264,mpeg4", - AudioCodec = "aac,ac3" - }, - new DirectPlayProfile - { - Container = "aac,mp3,wav", - Type = DlnaProfileType.Audio - }, - new DirectPlayProfile - { - Container = "jpeg,png,gif,bmp,tiff", - Type = DlnaProfileType.Photo - } - }; - - TranscodingProfiles = new[] - { - new TranscodingProfile - { - Container = "mp3", - AudioCodec = "mp3", - Type = DlnaProfileType.Audio, - // Transcoded audio won't be playable at all without this - TranscodeSeekInfo = TranscodeSeekInfo.Bytes - }, - new TranscodingProfile - { - Container = "ts", - VideoCodec = "h264", - AudioCodec = "aac,ac3,mp2", - Type = DlnaProfileType.Video - }, - new TranscodingProfile - { - Container = "jpeg", - Type = DlnaProfileType.Photo - } - }; - - ContainerProfiles = new[] - { - new ContainerProfile - { - Type = DlnaProfileType.Photo, - - Conditions = new[] - { - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Width, - Value = "1920" - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Height, - Value = "1080" - } - } - } - }; - - CodecProfiles = new[] - { - new CodecProfile - { - Type = CodecType.Video, - Codec = "h264", - - Conditions = new[] - { - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Width, - Value = "1920" - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Height, - Value = "1080" - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.VideoFramerate, - Value = "30", - IsRequired = false - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.VideoBitrate, - Value = "15360000", - IsRequired = false - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.VideoLevel, - Value = "41", - IsRequired = false - } - } - }, - - new CodecProfile - { - Type = CodecType.VideoAudio, - Codec = "ac3", - - Conditions = new[] - { - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.AudioChannels, - Value = "6", - IsRequired = false - }, - - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.AudioBitrate, - Value = "640000", - IsRequired = false - } - } - }, - - new CodecProfile - { - Type = CodecType.VideoAudio, - Codec = "wmapro", - - Conditions = new[] - { - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.AudioChannels, - Value = "2" - } - } - }, - - new CodecProfile - { - Type = CodecType.VideoAudio, - Codec = "aac", - - Conditions = new[] - { - new ProfileCondition - { - Condition = ProfileConditionType.NotEquals, - Property = ProfileConditionValue.AudioProfile, - Value = "he-aac", - IsRequired = false - } - } - } - }; - - ResponseProfiles = new[] - { - new ResponseProfile - { - Container = "mp4,mov", - AudioCodec = "aac", - MimeType = "video/mp4", - Type = DlnaProfileType.Video - }, - - new ResponseProfile - { - Container = "avi", - MimeType = "video/divx", - OrgPn = "AVI", - Type = DlnaProfileType.Video - }, - - new ResponseProfile - { - Container = "wav", - MimeType = "audio/wav", - Type = DlnaProfileType.Audio - }, - - new ResponseProfile - { - Container = "m4v", - Type = DlnaProfileType.Video, - MimeType = "video/mp4" - } - }; - - SubtitleProfiles = new[] - { - new SubtitleProfile - { - Format = "srt", - Method = SubtitleDeliveryMethod.Embed - } - }; - } - } -} diff --git a/Emby.Dlna/Profiles/WdtvLiveProfile.cs b/Emby.Dlna/Profiles/WdtvLiveProfile.cs deleted file mode 100644 index 937ca0f425..0000000000 --- a/Emby.Dlna/Profiles/WdtvLiveProfile.cs +++ /dev/null @@ -1,266 +0,0 @@ -#pragma warning disable CS1591 - -using MediaBrowser.Model.Dlna; - -namespace Emby.Dlna.Profiles -{ - [System.Xml.Serialization.XmlRoot("Profile")] - public class WdtvLiveProfile : DefaultProfile - { - public WdtvLiveProfile() - { - Name = "WDTV Live"; - - TimelineOffsetSeconds = 5; - IgnoreTranscodeByteRangeRequests = true; - - Identification = new DeviceIdentification - { - ModelName = "WD TV", - - Headers = new[] - { - new HttpHeaderInfo { Name = "User-Agent", Value = "alphanetworks", Match = HeaderMatchType.Substring }, - new HttpHeaderInfo - { - Name = "User-Agent", - Value = "ALPHA Networks", - Match = HeaderMatchType.Substring - } - } - }; - - TranscodingProfiles = new[] - { - new TranscodingProfile - { - Container = "mp3", - Type = DlnaProfileType.Audio, - AudioCodec = "mp3" - }, - new TranscodingProfile - { - Container = "ts", - Type = DlnaProfileType.Video, - VideoCodec = "h264", - AudioCodec = "aac" - }, - new TranscodingProfile - { - Container = "jpeg", - Type = DlnaProfileType.Photo - } - }; - - DirectPlayProfiles = new[] - { - new DirectPlayProfile - { - Container = "avi", - Type = DlnaProfileType.Video, - VideoCodec = "mpeg1video,mpeg2video,mpeg4,h264,vc1", - AudioCodec = "ac3,eac3,dca,mp2,mp3,pcm,dts" - }, - - new DirectPlayProfile - { - Container = "mpeg", - Type = DlnaProfileType.Video, - VideoCodec = "mpeg1video,mpeg2video", - AudioCodec = "ac3,eac3,dca,mp2,mp3,pcm,dts" - }, - - new DirectPlayProfile - { - Container = "mkv", - Type = DlnaProfileType.Video, - VideoCodec = "mpeg1video,mpeg2video,mpeg4,h264,vc1", - AudioCodec = "ac3,eac3,dca,aac,mp2,mp3,pcm,dts" - }, - - new DirectPlayProfile - { - Container = "ts,m2ts,mpegts", - Type = DlnaProfileType.Video, - VideoCodec = "mpeg1video,mpeg2video,h264,vc1", - AudioCodec = "ac3,eac3,dca,mp2,mp3,aac,dts" - }, - - new DirectPlayProfile - { - Container = "mp4,mov,m4v", - Type = DlnaProfileType.Video, - VideoCodec = "h264,mpeg4", - AudioCodec = "ac3,eac3,aac,mp2,mp3,dca,dts" - }, - - new DirectPlayProfile - { - Container = "asf", - Type = DlnaProfileType.Video, - VideoCodec = "vc1", - AudioCodec = "wmav2,wmapro" - }, - - new DirectPlayProfile - { - Container = "asf", - Type = DlnaProfileType.Video, - VideoCodec = "mpeg2video", - AudioCodec = "mp2,ac3" - }, - - new DirectPlayProfile - { - Container = "mp3", - AudioCodec = "mp2,mp3", - Type = DlnaProfileType.Audio - }, - - new DirectPlayProfile - { - Container = "mp4", - AudioCodec = "mp4", - Type = DlnaProfileType.Audio - }, - - new DirectPlayProfile - { - Container = "flac", - Type = DlnaProfileType.Audio - }, - - new DirectPlayProfile - { - Container = "asf", - AudioCodec = "wmav2,wmapro,wmavoice", - Type = DlnaProfileType.Audio - }, - - new DirectPlayProfile - { - Container = "ogg", - AudioCodec = "vorbis", - Type = DlnaProfileType.Audio - }, - - new DirectPlayProfile - { - Type = DlnaProfileType.Photo, - - Container = "jpeg,png,gif,bmp,tiff" - } - }; - - ResponseProfiles = new[] - { - new ResponseProfile - { - Container = "ts,mpegts", - OrgPn = "MPEG_TS_SD_NA", - Type = DlnaProfileType.Video - } - }; - - ContainerProfiles = new[] - { - new ContainerProfile - { - Type = DlnaProfileType.Photo, - - Conditions = new[] - { - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Width, - Value = "1920" - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Height, - Value = "1080" - } - } - } - }; - - CodecProfiles = new[] - { - new CodecProfile - { - Type = CodecType.Video, - Codec = "h264", - - Conditions = new[] - { - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Width, - Value = "1920" - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Height, - Value = "1080" - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.VideoLevel, - Value = "41" - } - } - }, - - new CodecProfile - { - Type = CodecType.VideoAudio, - Codec = "aac", - - Conditions = new[] - { - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.AudioChannels, - Value = "2" - } - } - } - }; - - SubtitleProfiles = new[] - { - new SubtitleProfile - { - Format = "srt", - Method = SubtitleDeliveryMethod.External - }, - new SubtitleProfile - { - Format = "srt", - Method = SubtitleDeliveryMethod.Embed - }, - new SubtitleProfile - { - Format = "sub", - Method = SubtitleDeliveryMethod.Embed - }, - new SubtitleProfile - { - Format = "subrip", - Method = SubtitleDeliveryMethod.Embed - }, - new SubtitleProfile - { - Format = "idx", - Method = SubtitleDeliveryMethod.Embed - } - }; - } - } -} diff --git a/Emby.Dlna/Profiles/XboxOneProfile.cs b/Emby.Dlna/Profiles/XboxOneProfile.cs deleted file mode 100644 index 84d8184a22..0000000000 --- a/Emby.Dlna/Profiles/XboxOneProfile.cs +++ /dev/null @@ -1,372 +0,0 @@ -#pragma warning disable CS1591 - -using MediaBrowser.Model.Dlna; - -namespace Emby.Dlna.Profiles -{ - [System.Xml.Serialization.XmlRoot("Profile")] - public class XboxOneProfile : DefaultProfile - { - public XboxOneProfile() - { - Name = "Xbox One"; - - TimelineOffsetSeconds = 40; - - Identification = new DeviceIdentification - { - ModelName = "Xbox One", - - Headers = new[] - { - new HttpHeaderInfo - { - Name = "FriendlyName.DLNA.ORG", Value = "XboxOne", Match = HeaderMatchType.Substring - }, - new HttpHeaderInfo - { - Name = "User-Agent", Value = "NSPlayer/12", Match = HeaderMatchType.Substring - } - } - }; - - var videoProfile = "high|main|baseline|constrained baseline"; - var videoLevel = "41"; - - TranscodingProfiles = new[] - { - new TranscodingProfile - { - Container = "mp3", - AudioCodec = "mp3", - Type = DlnaProfileType.Audio - }, - new TranscodingProfile - { - Container = "jpeg", - VideoCodec = "jpeg", - Type = DlnaProfileType.Photo - }, - new TranscodingProfile - { - Container = "ts", - VideoCodec = "h264", - AudioCodec = "aac", - Type = DlnaProfileType.Video - } - }; - - DirectPlayProfiles = new[] - { - new DirectPlayProfile - { - Container = "ts,mpegts", - VideoCodec = "h264,mpeg2video,hevc", - AudioCodec = "ac3,aac,mp3", - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Container = "avi", - VideoCodec = "mpeg4", - AudioCodec = "ac3,mp3", - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Container = "avi", - VideoCodec = "h264", - AudioCodec = "aac", - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Container = "mp4,mov,mkv,m4v", - VideoCodec = "h264,mpeg4,mpeg2video,hevc", - AudioCodec = "aac,ac3", - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Container = "asf", - VideoCodec = "wmv2,wmv3,vc1", - AudioCodec = "wmav2,wmapro", - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Container = "asf", - AudioCodec = "wmav2,wmapro,wmavoice", - Type = DlnaProfileType.Audio - }, - new DirectPlayProfile - { - Container = "mp3", - AudioCodec = "mp3", - Type = DlnaProfileType.Audio - }, - new DirectPlayProfile - { - Container = "jpeg", - Type = DlnaProfileType.Photo - } - }; - - ContainerProfiles = new[] - { - new ContainerProfile - { - Type = DlnaProfileType.Video, - Container = "mp4,mov", - - Conditions = new[] - { - new ProfileCondition - { - Condition = ProfileConditionType.Equals, - Property = ProfileConditionValue.Has64BitOffsets, - Value = "false", - IsRequired = false - } - } - } - }; - - CodecProfiles = new[] - { - new CodecProfile - { - Type = CodecType.Video, - Codec = "mpeg4", - Conditions = new[] - { - new ProfileCondition - { - Condition = ProfileConditionType.NotEquals, - Property = ProfileConditionValue.IsAnamorphic, - Value = "true", - IsRequired = false - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.VideoBitDepth, - Value = "8", - IsRequired = false - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Width, - Value = "1920" - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Height, - Value = "1080" - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.VideoFramerate, - Value = "30", - IsRequired = false - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.VideoBitrate, - Value = "5120000", - IsRequired = false - } - } - }, - - new CodecProfile - { - Type = CodecType.Video, - Codec = "h264", - Conditions = new[] - { - new ProfileCondition - { - Condition = ProfileConditionType.NotEquals, - Property = ProfileConditionValue.IsAnamorphic, - Value = "true", - IsRequired = false - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.VideoBitDepth, - Value = "8", - IsRequired = false - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Width, - Value = "1920" - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Height, - Value = "1080" - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.VideoLevel, - Value = videoLevel, - IsRequired = false - }, - new ProfileCondition - { - Condition = ProfileConditionType.EqualsAny, - Property = ProfileConditionValue.VideoProfile, - Value = videoProfile, - IsRequired = false - } - } - }, - - new CodecProfile - { - Type = CodecType.Video, - Codec = "wmv2,wmv3,vc1", - Conditions = new[] - { - new ProfileCondition - { - Condition = ProfileConditionType.NotEquals, - Property = ProfileConditionValue.IsAnamorphic, - Value = "true", - IsRequired = false - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.VideoBitDepth, - Value = "8", - IsRequired = false - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Width, - Value = "1920" - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Height, - Value = "1080" - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.VideoFramerate, - Value = "30", - IsRequired = false - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.VideoBitrate, - Value = "15360000", - IsRequired = false - } - } - }, - - new CodecProfile - { - Type = CodecType.Video, - Conditions = new[] - { - new ProfileCondition - { - Condition = ProfileConditionType.NotEquals, - Property = ProfileConditionValue.IsAnamorphic, - Value = "true", - IsRequired = false - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.VideoBitDepth, - Value = "8", - IsRequired = false - } - } - }, - - new CodecProfile - { - Type = CodecType.VideoAudio, - Codec = "ac3,wmav2,wmapro", - Conditions = new[] - { - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.AudioChannels, - Value = "6", - IsRequired = false - } - } - }, - - new CodecProfile - { - Type = CodecType.VideoAudio, - Codec = "aac", - Conditions = new[] - { - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.AudioChannels, - Value = "2", - IsRequired = false - }, - new ProfileCondition - { - Condition = ProfileConditionType.Equals, - Property = ProfileConditionValue.AudioProfile, - Value = "lc", - IsRequired = false - } - } - } - }; - - ResponseProfiles = new[] - { - new ResponseProfile - { - Container = "avi", - MimeType = "video/avi", - Type = DlnaProfileType.Video - }, - new ResponseProfile - { - Container = "m4v", - Type = DlnaProfileType.Video, - MimeType = "video/mp4" - } - }; - - SubtitleProfiles = new[] - { - new SubtitleProfile - { - Format = "srt", - Method = SubtitleDeliveryMethod.Embed - } - }; - } - } -} diff --git a/tests/Jellyfin.Server.Integration.Tests/Controllers/DlnaControllerTests.cs b/tests/Jellyfin.Server.Integration.Tests/Controllers/DlnaControllerTests.cs index 5d7b0e874e..a65f65bb21 100644 --- a/tests/Jellyfin.Server.Integration.Tests/Controllers/DlnaControllerTests.cs +++ b/tests/Jellyfin.Server.Integration.Tests/Controllers/DlnaControllerTests.cs @@ -34,8 +34,8 @@ namespace Jellyfin.Server.Integration.Tests.Controllers var client = _factory.CreateClient(); client.DefaultRequestHeaders.AddAuthHeader(_accessToken ??= await AuthHelper.CompleteStartupAsync(client).ConfigureAwait(false)); - using var getResponse = await client.GetAsync("/Dlna/Profiles/" + NonExistentProfile).ConfigureAwait(false); - Assert.Equal(HttpStatusCode.NotFound, getResponse.StatusCode); + using var response = await client.GetAsync("/Dlna/Profiles/" + NonExistentProfile).ConfigureAwait(false); + Assert.Equal(HttpStatusCode.NotFound, response.StatusCode); } [Fact] @@ -45,8 +45,8 @@ namespace Jellyfin.Server.Integration.Tests.Controllers var client = _factory.CreateClient(); client.DefaultRequestHeaders.AddAuthHeader(_accessToken ??= await AuthHelper.CompleteStartupAsync(client).ConfigureAwait(false)); - using var getResponse = await client.DeleteAsync("/Dlna/Profiles/" + NonExistentProfile).ConfigureAwait(false); - Assert.Equal(HttpStatusCode.NotFound, getResponse.StatusCode); + using var response = await client.DeleteAsync("/Dlna/Profiles/" + NonExistentProfile).ConfigureAwait(false); + Assert.Equal(HttpStatusCode.NotFound, response.StatusCode); } [Fact] @@ -61,8 +61,8 @@ namespace Jellyfin.Server.Integration.Tests.Controllers Name = "ThisProfileDoesNotExist" }; - using var getResponse = await client.PostAsJsonAsync("/Dlna/Profiles/" + NonExistentProfile, deviceProfile, _jsonOptions).ConfigureAwait(false); - Assert.Equal(HttpStatusCode.NotFound, getResponse.StatusCode); + using var response = await client.PostAsJsonAsync("/Dlna/Profiles/" + NonExistentProfile, deviceProfile, _jsonOptions).ConfigureAwait(false); + Assert.Equal(HttpStatusCode.NotFound, response.StatusCode); } [Fact] @@ -77,8 +77,8 @@ namespace Jellyfin.Server.Integration.Tests.Controllers Name = "ThisProfileIsNew" }; - using var getResponse = await client.PostAsJsonAsync("/Dlna/Profiles", deviceProfile, _jsonOptions).ConfigureAwait(false); - Assert.Equal(HttpStatusCode.NoContent, getResponse.StatusCode); + using var response = await client.PostAsJsonAsync("/Dlna/Profiles", deviceProfile, _jsonOptions).ConfigureAwait(false); + Assert.Equal(HttpStatusCode.NoContent, response.StatusCode); } [Fact] @@ -115,20 +115,46 @@ namespace Jellyfin.Server.Integration.Tests.Controllers Id = _newDeviceProfileId }; - using var getResponse = await client.PostAsJsonAsync("/Dlna/Profiles", updatedProfile, _jsonOptions).ConfigureAwait(false); - Assert.Equal(HttpStatusCode.NoContent, getResponse.StatusCode); + using var postResponse = await client.PostAsJsonAsync("/Dlna/Profiles/" + _newDeviceProfileId, updatedProfile, _jsonOptions).ConfigureAwait(false); + Assert.Equal(HttpStatusCode.NoContent, postResponse.StatusCode); + + // Verify that the profile got updated + using var response = await client.GetAsync("/Dlna/ProfileInfos").ConfigureAwait(false); + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.Equal(MediaTypeNames.Application.Json, response.Content.Headers.ContentType?.MediaType); + Assert.Equal(Encoding.UTF8.BodyName, response.Content.Headers.ContentType?.CharSet); + + var profiles = await JsonSerializer.DeserializeAsync( + await response.Content.ReadAsStreamAsync().ConfigureAwait(false), + _jsonOptions).ConfigureAwait(false); + + Assert.Null(profiles?.FirstOrDefault(x => string.Equals(x.Name, "ThisProfileIsNew", StringComparison.Ordinal))); + var newProfile = profiles?.FirstOrDefault(x => string.Equals(x.Name, "ThisProfileIsUpdated", StringComparison.Ordinal)); + Assert.NotNull(newProfile); + _newDeviceProfileId = newProfile!.Id; } [Fact] - [Priority(4)] + [Priority(5)] public async Task DeleteProfile_Valid_NoContent() { var client = _factory.CreateClient(); client.DefaultRequestHeaders.AddAuthHeader(_accessToken ??= await AuthHelper.CompleteStartupAsync(client).ConfigureAwait(false)); - using var getResponse = await client.DeleteAsync("/Dlna/Profiles/" + _newDeviceProfileId).ConfigureAwait(false); - Console.WriteLine(await getResponse.Content.ReadAsStringAsync().ConfigureAwait(false)); - Assert.Equal(HttpStatusCode.NoContent, getResponse.StatusCode); + using var deleteResponse = await client.DeleteAsync("/Dlna/Profiles/" + _newDeviceProfileId).ConfigureAwait(false); + Assert.Equal(HttpStatusCode.NoContent, deleteResponse.StatusCode); + + // Verify that the profile got deleted + using var response = await client.GetAsync("/Dlna/ProfileInfos").ConfigureAwait(false); + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.Equal(MediaTypeNames.Application.Json, response.Content.Headers.ContentType?.MediaType); + Assert.Equal(Encoding.UTF8.BodyName, response.Content.Headers.ContentType?.CharSet); + + var profiles = await JsonSerializer.DeserializeAsync( + await response.Content.ReadAsStreamAsync().ConfigureAwait(false), + _jsonOptions).ConfigureAwait(false); + + Assert.Null(profiles?.FirstOrDefault(x => string.Equals(x.Name, "ThisProfileIsUpdated", StringComparison.Ordinal))); } } } From 2e2a594e19038bc2fcea5fdbeda9d37e8394fff7 Mon Sep 17 00:00:00 2001 From: Joe Rogers <1337joe@gmail.com> Date: Tue, 30 Nov 2021 23:53:34 +0100 Subject: [PATCH 002/245] Move Get*Providers definitions to interface --- .../Providers/IProviderManager.cs | 18 ++++++++++++++++++ .../Manager/MetadataService.cs | 4 ++-- .../Manager/ProviderManager.cs | 15 ++------------- 3 files changed, 22 insertions(+), 15 deletions(-) diff --git a/MediaBrowser.Controller/Providers/IProviderManager.cs b/MediaBrowser.Controller/Providers/IProviderManager.cs index 44bc4a50cb..32a7951f62 100644 --- a/MediaBrowser.Controller/Providers/IProviderManager.cs +++ b/MediaBrowser.Controller/Providers/IProviderManager.cs @@ -131,6 +131,24 @@ namespace MediaBrowser.Controller.Providers /// IEnumerable{ImageProviderInfo}. IEnumerable GetRemoteImageProviderInfo(BaseItem item); + /// + /// Gets the image providers for the provided item. + /// + /// The item. + /// The image refresh options. + /// The image providers for the item. + IEnumerable GetImageProviders(BaseItem item, ImageRefreshOptions refreshOptions); + + /// + /// Gets the metadata providers for the provided item. + /// + /// The item. + /// The library options. + /// The type of metadata provider. + /// The metadata providers. + IEnumerable> GetMetadataProviders(BaseItem item, LibraryOptions libraryOptions) + where T : BaseItem; + /// /// Gets all metadata plugins. /// diff --git a/MediaBrowser.Providers/Manager/MetadataService.cs b/MediaBrowser.Providers/Manager/MetadataService.cs index 0c52d26736..01e2a5db9f 100644 --- a/MediaBrowser.Providers/Manager/MetadataService.cs +++ b/MediaBrowser.Providers/Manager/MetadataService.cs @@ -94,7 +94,7 @@ namespace MediaBrowser.Providers.Manager var localImagesFailed = false; - var allImageProviders = ((ProviderManager)ProviderManager).GetImageProviders(item, refreshOptions).ToList(); + var allImageProviders = ProviderManager.GetImageProviders(item, refreshOptions).ToList(); if (refreshOptions.RemoveOldMetadata && refreshOptions.ReplaceAllImages) { @@ -522,7 +522,7 @@ namespace MediaBrowser.Providers.Manager protected IEnumerable GetProviders(BaseItem item, LibraryOptions libraryOptions, MetadataRefreshOptions options, bool isFirstRefresh, bool requiresRefresh) { // Get providers to refresh - var providers = ((ProviderManager)ProviderManager).GetMetadataProviders(item, libraryOptions).ToList(); + var providers = ProviderManager.GetMetadataProviders(item, libraryOptions).ToList(); var metadataRefreshMode = options.MetadataRefreshMode; diff --git a/MediaBrowser.Providers/Manager/ProviderManager.cs b/MediaBrowser.Providers/Manager/ProviderManager.cs index 0c31d460ff..e644f0e74d 100644 --- a/MediaBrowser.Providers/Manager/ProviderManager.cs +++ b/MediaBrowser.Providers/Manager/ProviderManager.cs @@ -302,12 +302,7 @@ namespace MediaBrowser.Providers.Manager return GetRemoteImageProviders(item, true).Select(i => new ImageProviderInfo(i.Name, i.GetSupportedImages(item).ToArray())); } - /// - /// Gets the image providers for the provided item. - /// - /// The item. - /// The image refresh options. - /// The image providers for the item. + /// public IEnumerable GetImageProviders(BaseItem item, ImageRefreshOptions refreshOptions) { return GetImageProviders(item, _libraryManager.GetLibraryOptions(item), GetMetadataOptions(item), refreshOptions, false); @@ -342,13 +337,7 @@ namespace MediaBrowser.Providers.Manager .ThenBy(GetOrder); } - /// - /// Gets the metadata providers for the provided item. - /// - /// The item. - /// The library options. - /// The type of metadata provider. - /// The metadata providers. + /// public IEnumerable> GetMetadataProviders(BaseItem item, LibraryOptions libraryOptions) where T : BaseItem { From 4ace7f5c532b655449f7121b660a2cb9e66570be Mon Sep 17 00:00:00 2001 From: Joe Rogers <1337joe@gmail.com> Date: Tue, 30 Nov 2021 23:55:53 +0100 Subject: [PATCH 003/245] Fix unused var, log typo --- MediaBrowser.Providers/Manager/ProviderManager.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MediaBrowser.Providers/Manager/ProviderManager.cs b/MediaBrowser.Providers/Manager/ProviderManager.cs index e644f0e74d..1b73574774 100644 --- a/MediaBrowser.Providers/Manager/ProviderManager.cs +++ b/MediaBrowser.Providers/Manager/ProviderManager.cs @@ -354,7 +354,7 @@ namespace MediaBrowser.Providers.Manager return _metadataProviders.OfType>() .Where(i => CanRefresh(i, item, libraryOptions, includeDisabled, forceEnableInternetMetadata)) - .OrderBy(i => GetConfiguredOrder(item, i, libraryOptions, globalMetadataOptions)) + .OrderBy(i => GetConfiguredOrder(item, i, libraryOptions, currentOptions)) .ThenBy(GetDefaultOrder); } @@ -908,7 +908,7 @@ namespace MediaBrowser.Providers.Manager } catch (Exception ex) { - _logger.LogError(ex, "Error in {0}.Suports", i.GetType().Name); + _logger.LogError(ex, "Error in {0}.Supports", i.GetType().Name); return false; } }); From 785cc1bb6ed1cbd3d0c300b9842af6e15167e715 Mon Sep 17 00:00:00 2001 From: Joe Rogers <1337joe@gmail.com> Date: Sun, 5 Dec 2021 17:19:40 +0100 Subject: [PATCH 004/245] Implement sort test for ProviderManager.GetImageProviders --- .../Manager/ProviderManagerTests.cs | 177 ++++++++++++++++++ 1 file changed, 177 insertions(+) create mode 100644 tests/Jellyfin.Providers.Tests/Manager/ProviderManagerTests.cs diff --git a/tests/Jellyfin.Providers.Tests/Manager/ProviderManagerTests.cs b/tests/Jellyfin.Providers.Tests/Manager/ProviderManagerTests.cs new file mode 100644 index 0000000000..31b1913346 --- /dev/null +++ b/tests/Jellyfin.Providers.Tests/Manager/ProviderManagerTests.cs @@ -0,0 +1,177 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using MediaBrowser.Controller.Configuration; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities.Movies; +using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Providers; +using MediaBrowser.Model.Configuration; +using MediaBrowser.Providers.Manager; +using Microsoft.Extensions.Logging.Abstractions; +using Moq; +using Xunit; + +namespace Jellyfin.Providers.Tests.Manager +{ + public class ProviderManagerTests + { + private static TheoryData GetImageProvidersOrderData() + => new () + { + { 3, null, null, null, null, new[] { 0, 1, 2 } }, // no order options set + + // library options ordering + { 3, null, Array.Empty(), null, null, new[] { 0, 1, 2 } }, // no order provided + { 3, null, new[] { 1 }, null, null, new[] { 1, 0, 2 } }, // one item in order + { 3, null, new[] { 2, 1, 0 }, null, null, new[] { 2, 1, 0 } }, // full reverse order + + // server options ordering + { 3, null, null, Array.Empty(), null, new[] { 0, 1, 2 } }, // no order provided + { 3, null, null, new[] { 1 }, null, new[] { 1, 0, 2 } }, // one item in order + { 3, null, null, new[] { 2, 1, 0 }, null, new[] { 2, 1, 0 } }, // full reverse order + + // IHasOrder ordering + // TODO unintuitive - default if not IHasOrder is 0, not max + { 3, null, null, null, new int?[] { null, 0, null }, new[] { 0, 1, 2 } }, // one item with order 0, no change because default order value is 0 + { 3, null, null, null, new int?[] { null, 1, null }, new[] { 0, 2, 1 } }, // one item in order (goes to end, not beginning) + { 3, null, null, null, new int?[] { 2, 1, 0 }, new[] { 2, 1, 0 } }, // full reverse order + + // multiple orders set + // TODO should library fall through to server if both are set on different elements? + { 3, null, new[] { 1 }, new[] { 2, 0, 1 }, null, new[] { 1, 0, 2 } }, // library order first, server order ignored + { 3, null, new[] { 1 }, null, new int?[] { 2, 0, 1 }, new[] { 1, 2, 0 } }, // library order first, then orderby + { 3, null, new[] { 2, 1, 0 }, new[] { 1, 2, 0 }, new int?[] { 2, 0, 1 }, new[] { 2, 1, 0 } }, // library order wins + + // ordering with ILocalImageProvider + // TODO what is the value of testing for ILocalImageProvider on the sort, should this be removed? Behavior is unintuitive + { 3, new[] { false, true, false }, new[] { 1, 0, 2 }, null, null, new[] { 0, 2, 1 } }, // ILocalImageProvider - sorts to end even when set first + { 3, new[] { false, true, false }, new[] { 1 }, null, null, new[] { 0, 1, 2 } }, // ILocalImageProvider - set order ignored when only value set + { 2, new[] { true, true }, new[] { 1, 0 }, null, null, new[] { 0, 1 } }, // ILocalImageProvider - set order ignored + { 2, new[] { true, true }, null, null, new int?[] { 1, 0 }, new[] { 1, 0 } }, // ILocalImageProvider - IHasOrder applies + }; + + [Theory] + [MemberData(nameof(GetImageProvidersOrderData))] + public void GetImageProviders_ProviderOrder_MatchesExpected(int providerCount, bool[]? localImageProvider, int[]? libraryOrder, int[]? serverOrder, int?[]? hasOrderOrder, int[] expectedOrder) + { + var item = new Movie(); + + var nameProvider = new Func(i => "Provider" + i); + + var providerList = new List(); + for (var i = 0; i < providerCount; i++) + { + var order = hasOrderOrder?[i]; + if (localImageProvider != null && localImageProvider[i]) + { + providerList.Add(MockIImageProvider(nameProvider(i), item, order)); + } + else + { + providerList.Add(MockIImageProvider(nameProvider(i), item, order)); + } + } + + var libraryOptions = new LibraryOptions(); + if (libraryOrder != null) + { + libraryOptions.TypeOptions = new[] + { + new TypeOptions + { + Type = item.GetType().Name, + ImageFetcherOrder = libraryOrder.Select(nameProvider).ToArray() + } + }; + } + + var serverConfiguration = new ServerConfiguration(); + if (serverOrder != null) + { + serverConfiguration.MetadataOptions = new[] + { + new MetadataOptions + { + ItemType = item.GetType().Name, + ImageFetcherOrder = serverOrder.Select(nameProvider).ToArray() + } + }; + } + + var providerManager = GetProviderManager(serverConfiguration: serverConfiguration, libraryOptions: libraryOptions); + AddParts(providerManager, imageProviders: providerList); + + var refreshOptions = new ImageRefreshOptions(Mock.Of(MockBehavior.Strict)); + var actualProviders = providerManager.GetImageProviders(item, refreshOptions).ToList(); + + Assert.Equal(providerList.Count, actualProviders.Count); + for (var i = 0; i < providerList.Count; i++) + { + Assert.Equal(i, actualProviders.IndexOf(providerList[expectedOrder[i]])); + } + } + + private static IImageProvider MockIImageProvider(string name, BaseItem supportedType, int? order = null) + where T : class, IImageProvider + { + Mock? hasOrder = null; + if (order != null) + { + hasOrder = new Mock(MockBehavior.Strict); + hasOrder.Setup(i => i.Order) + .Returns((int)order); + } + + var provider = hasOrder == null + ? new Mock(MockBehavior.Strict) + : hasOrder.As(); + provider.Setup(p => p.Name) + .Returns(name); + provider.Setup(p => p.Supports(supportedType)) + .Returns(true); + return provider.Object; + } + + private static ProviderManager GetProviderManager(ServerConfiguration? serverConfiguration = null, LibraryOptions? libraryOptions = null) + { + var serverConfigurationManager = new Mock(MockBehavior.Strict); + serverConfigurationManager.Setup(i => i.Configuration) + .Returns(serverConfiguration ?? new ServerConfiguration()); + + var libraryManager = new Mock(MockBehavior.Strict); + libraryManager.Setup(i => i.GetLibraryOptions(It.IsAny())) + .Returns(libraryOptions ?? new LibraryOptions()); + + var providerManager = new ProviderManager( + null, + null, + serverConfigurationManager.Object, + null, + new NullLogger(), + null, + null, + libraryManager.Object, + null); + + return providerManager; + } + + private static void AddParts( + ProviderManager providerManager, + IEnumerable? imageProviders = null, + IEnumerable? metadataServices = null, + IEnumerable? metadataProviders = null, + IEnumerable? metadataSavers = null, + IEnumerable? externalIds = null) + { + imageProviders ??= Array.Empty(); + metadataServices ??= Array.Empty(); + metadataProviders ??= Array.Empty(); + metadataSavers ??= Array.Empty(); + externalIds ??= Array.Empty(); + + providerManager.AddParts(imageProviders, metadataServices, metadataProviders, metadataSavers, externalIds); + } + } +} From 8515e8fbd111278cad95430e50904d6721be3a63 Mon Sep 17 00:00:00 2001 From: Joe Rogers <1337joe@gmail.com> Date: Sun, 5 Dec 2021 21:33:31 +0100 Subject: [PATCH 005/245] Improve image provider sorting Remove irrelevant check for ILocalImageProvider Providers that are not IHasOrder default to middle, not beginning --- .../Manager/ProviderManager.cs | 60 ++++++++----------- .../Manager/ProviderManagerTests.cs | 47 +++++---------- 2 files changed, 40 insertions(+), 67 deletions(-) diff --git a/MediaBrowser.Providers/Manager/ProviderManager.cs b/MediaBrowser.Providers/Manager/ProviderManager.cs index 1b73574774..855c467208 100644 --- a/MediaBrowser.Providers/Manager/ProviderManager.cs +++ b/MediaBrowser.Providers/Manager/ProviderManager.cs @@ -310,31 +310,25 @@ namespace MediaBrowser.Providers.Manager private IEnumerable GetImageProviders(BaseItem item, LibraryOptions libraryOptions, MetadataOptions options, ImageRefreshOptions refreshOptions, bool includeDisabled) { - // Avoid implicitly captured closure - var currentOptions = options; - var typeOptions = libraryOptions.GetTypeOptions(item.GetType().Name); - var typeFetcherOrder = typeOptions?.ImageFetcherOrder; + var fetcherOrder = typeOptions?.ImageFetcherOrder ?? options.ImageFetcherOrder; return ImageProviders.Where(i => CanRefresh(i, item, libraryOptions, refreshOptions, includeDisabled)) - .OrderBy(i => - { - // See if there's a user-defined order - if (i is not ILocalImageProvider) - { - var fetcherOrder = typeFetcherOrder ?? currentOptions.ImageFetcherOrder; - var index = Array.IndexOf(fetcherOrder, i.Name); + .OrderBy(i => GetConfiguredOrder(fetcherOrder, i.Name)) + .ThenBy(GetOrder); + } - if (index != -1) - { - return index; - } - } + private static int GetConfiguredOrder(string[] order, string providerName) + { + var index = Array.IndexOf(order, providerName); - // Not configured. Just return some high number to put it at the end. - return 100; - }) - .ThenBy(GetOrder); + if (index != -1) + { + return index; + } + + // default to end + return int.MaxValue; } /// @@ -450,21 +444,6 @@ namespace MediaBrowser.Providers.Manager } } - /// - /// Gets the order. - /// - /// The provider. - /// System.Int32. - private int GetOrder(IImageProvider provider) - { - if (provider is not IHasOrder hasOrder) - { - return 0; - } - - return hasOrder.Order; - } - private int GetConfiguredOrder(BaseItem item, IMetadataProvider provider, LibraryOptions libraryOptions, MetadataOptions globalMetadataOptions) { // See if there's a user-defined order @@ -500,6 +479,17 @@ namespace MediaBrowser.Providers.Manager return 100; } + private static int GetOrder(object provider) + { + if (provider is IHasOrder hasOrder) + { + return hasOrder.Order; + } + + // after items that want to be first (~0) but before items that want to be last (~100) + return 50; + } + private int GetDefaultOrder(IMetadataProvider provider) { if (provider is IHasOrder hasOrder) diff --git a/tests/Jellyfin.Providers.Tests/Manager/ProviderManagerTests.cs b/tests/Jellyfin.Providers.Tests/Manager/ProviderManagerTests.cs index 31b1913346..590f50b256 100644 --- a/tests/Jellyfin.Providers.Tests/Manager/ProviderManagerTests.cs +++ b/tests/Jellyfin.Providers.Tests/Manager/ProviderManagerTests.cs @@ -16,44 +16,34 @@ namespace Jellyfin.Providers.Tests.Manager { public class ProviderManagerTests { - private static TheoryData GetImageProvidersOrderData() + private static TheoryData GetImageProvidersOrderData() => new () { - { 3, null, null, null, null, new[] { 0, 1, 2 } }, // no order options set + { 3, null, null, null, new[] { 0, 1, 2 } }, // no order options set // library options ordering - { 3, null, Array.Empty(), null, null, new[] { 0, 1, 2 } }, // no order provided - { 3, null, new[] { 1 }, null, null, new[] { 1, 0, 2 } }, // one item in order - { 3, null, new[] { 2, 1, 0 }, null, null, new[] { 2, 1, 0 } }, // full reverse order + { 3, Array.Empty(), null, null, new[] { 0, 1, 2 } }, // no order provided + { 3, new[] { 1 }, null, null, new[] { 1, 0, 2 } }, // one item in order + { 3, new[] { 2, 1, 0 }, null, null, new[] { 2, 1, 0 } }, // full reverse order // server options ordering - { 3, null, null, Array.Empty(), null, new[] { 0, 1, 2 } }, // no order provided - { 3, null, null, new[] { 1 }, null, new[] { 1, 0, 2 } }, // one item in order - { 3, null, null, new[] { 2, 1, 0 }, null, new[] { 2, 1, 0 } }, // full reverse order + { 3, null, Array.Empty(), null, new[] { 0, 1, 2 } }, // no order provided + { 3, null, new[] { 1 }, null, new[] { 1, 0, 2 } }, // one item in order + { 3, null, new[] { 2, 1, 0 }, null, new[] { 2, 1, 0 } }, // full reverse order // IHasOrder ordering - // TODO unintuitive - default if not IHasOrder is 0, not max - { 3, null, null, null, new int?[] { null, 0, null }, new[] { 0, 1, 2 } }, // one item with order 0, no change because default order value is 0 - { 3, null, null, null, new int?[] { null, 1, null }, new[] { 0, 2, 1 } }, // one item in order (goes to end, not beginning) - { 3, null, null, null, new int?[] { 2, 1, 0 }, new[] { 2, 1, 0 } }, // full reverse order + { 3, null, null, new int?[] { null, 1, null }, new[] { 1, 0, 2 } }, // one item with defined order + { 3, null, null, new int?[] { 2, 1, 0 }, new[] { 2, 1, 0 } }, // full reverse order // multiple orders set - // TODO should library fall through to server if both are set on different elements? - { 3, null, new[] { 1 }, new[] { 2, 0, 1 }, null, new[] { 1, 0, 2 } }, // library order first, server order ignored - { 3, null, new[] { 1 }, null, new int?[] { 2, 0, 1 }, new[] { 1, 2, 0 } }, // library order first, then orderby - { 3, null, new[] { 2, 1, 0 }, new[] { 1, 2, 0 }, new int?[] { 2, 0, 1 }, new[] { 2, 1, 0 } }, // library order wins - - // ordering with ILocalImageProvider - // TODO what is the value of testing for ILocalImageProvider on the sort, should this be removed? Behavior is unintuitive - { 3, new[] { false, true, false }, new[] { 1, 0, 2 }, null, null, new[] { 0, 2, 1 } }, // ILocalImageProvider - sorts to end even when set first - { 3, new[] { false, true, false }, new[] { 1 }, null, null, new[] { 0, 1, 2 } }, // ILocalImageProvider - set order ignored when only value set - { 2, new[] { true, true }, new[] { 1, 0 }, null, null, new[] { 0, 1 } }, // ILocalImageProvider - set order ignored - { 2, new[] { true, true }, null, null, new int?[] { 1, 0 }, new[] { 1, 0 } }, // ILocalImageProvider - IHasOrder applies + { 3, new[] { 1 }, new[] { 2, 0, 1 }, null, new[] { 1, 0, 2 } }, // library order first, server order ignored + { 3, new[] { 1 }, null, new int?[] { 2, 0, 1 }, new[] { 1, 2, 0 } }, // library order first, then orderby + { 3, new[] { 2, 1, 0 }, new[] { 1, 2, 0 }, new int?[] { 2, 0, 1 }, new[] { 2, 1, 0 } }, // library order wins }; [Theory] [MemberData(nameof(GetImageProvidersOrderData))] - public void GetImageProviders_ProviderOrder_MatchesExpected(int providerCount, bool[]? localImageProvider, int[]? libraryOrder, int[]? serverOrder, int?[]? hasOrderOrder, int[] expectedOrder) + public void GetImageProviders_ProviderOrder_MatchesExpected(int providerCount, int[]? libraryOrder, int[]? serverOrder, int?[]? hasOrderOrder, int[] expectedOrder) { var item = new Movie(); @@ -63,14 +53,7 @@ namespace Jellyfin.Providers.Tests.Manager for (var i = 0; i < providerCount; i++) { var order = hasOrderOrder?[i]; - if (localImageProvider != null && localImageProvider[i]) - { - providerList.Add(MockIImageProvider(nameProvider(i), item, order)); - } - else - { - providerList.Add(MockIImageProvider(nameProvider(i), item, order)); - } + providerList.Add(MockIImageProvider(nameProvider(i), item, order)); } var libraryOptions = new LibraryOptions(); From 6221991c630bcbd688316ad35121781c7a52c591 Mon Sep 17 00:00:00 2001 From: Joe Rogers <1337joe@gmail.com> Date: Sun, 5 Dec 2021 21:43:59 +0100 Subject: [PATCH 006/245] Add nullable annotations --- .../Manager/ProviderManager.cs | 32 ++++++++----------- 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/MediaBrowser.Providers/Manager/ProviderManager.cs b/MediaBrowser.Providers/Manager/ProviderManager.cs index 855c467208..9bae738010 100644 --- a/MediaBrowser.Providers/Manager/ProviderManager.cs +++ b/MediaBrowser.Providers/Manager/ProviderManager.cs @@ -1,5 +1,3 @@ -#nullable disable - using System; using System.Collections.Concurrent; using System.Collections.Generic; @@ -47,7 +45,7 @@ namespace MediaBrowser.Providers.Manager /// public class ProviderManager : IProviderManager, IDisposable { - private readonly object _refreshQueueLock = new object(); + private readonly object _refreshQueueLock = new (); private readonly ILogger _logger; private readonly IHttpClientFactory _httpClientFactory; private readonly ILibraryMonitor _libraryMonitor; @@ -57,11 +55,11 @@ namespace MediaBrowser.Providers.Manager private readonly ISubtitleManager _subtitleManager; private readonly IServerConfigurationManager _configurationManager; private readonly IBaseItemManager _baseItemManager; - private readonly ConcurrentDictionary _activeRefreshes = new ConcurrentDictionary(); - private readonly CancellationTokenSource _disposeCancellationTokenSource = new CancellationTokenSource(); - private readonly SimplePriorityQueue> _refreshQueue = - new SimplePriorityQueue>(); + private readonly ConcurrentDictionary _activeRefreshes = new (); + private readonly CancellationTokenSource _disposeCancellationTokenSource = new (); + private readonly SimplePriorityQueue> _refreshQueue = new (); + private IImageProvider[] _imageProviders = Array.Empty(); private IMetadataService[] _metadataServices = Array.Empty(); private IMetadataProvider[] _metadataProviders = Array.Empty(); private IMetadataSaver[] _savers = Array.Empty(); @@ -104,15 +102,13 @@ namespace MediaBrowser.Providers.Manager } /// - public event EventHandler> RefreshStarted; + public event EventHandler>? RefreshStarted; /// - public event EventHandler> RefreshCompleted; + public event EventHandler>? RefreshCompleted; /// - public event EventHandler>> RefreshProgress; - - private IImageProvider[] ImageProviders { get; set; } + public event EventHandler>>? RefreshProgress; /// public void AddParts( @@ -122,8 +118,7 @@ namespace MediaBrowser.Providers.Manager IEnumerable metadataSavers, IEnumerable externalIds) { - ImageProviders = imageProviders.ToArray(); - + _imageProviders = imageProviders.ToArray(); _metadataServices = metadataServices.OrderBy(i => i.Order).ToArray(); _metadataProviders = metadataProviders.ToArray(); _externalIds = externalIds.OrderBy(i => i.ProviderName).ToArray(); @@ -313,7 +308,7 @@ namespace MediaBrowser.Providers.Manager var typeOptions = libraryOptions.GetTypeOptions(item.GetType().Name); var fetcherOrder = typeOptions?.ImageFetcherOrder ?? options.ImageFetcherOrder; - return ImageProviders.Where(i => CanRefresh(i, item, libraryOptions, refreshOptions, includeDisabled)) + return _imageProviders.Where(i => CanRefresh(i, item, libraryOptions, refreshOptions, includeDisabled)) .OrderBy(i => GetConfiguredOrder(fetcherOrder, i.Name)) .ThenBy(GetOrder); } @@ -758,7 +753,7 @@ namespace MediaBrowser.Providers.Manager where TItemType : BaseItem, new() where TLookupType : ItemLookupInfo { - BaseItem referenceItem = null; + BaseItem? referenceItem = null; if (!searchInfo.ItemId.Equals(default)) { @@ -768,7 +763,7 @@ namespace MediaBrowser.Providers.Manager return GetRemoteSearchResults(searchInfo, referenceItem, cancellationToken); } - private async Task> GetRemoteSearchResults(RemoteSearchQuery searchInfo, BaseItem referenceItem, CancellationToken cancellationToken) + private async Task> GetRemoteSearchResults(RemoteSearchQuery searchInfo, BaseItem? referenceItem, CancellationToken cancellationToken) where TItemType : BaseItem, new() where TLookupType : ItemLookupInfo { @@ -930,7 +925,8 @@ namespace MediaBrowser.Providers.Manager i.UrlFormatString, value) }; - }).Where(i => i != null).Concat(item.GetRelatedUrls()); + }).Where(i => i != null) + .Concat(item.GetRelatedUrls())!; // We just filtered out all the nulls } /// From 56900d0fc3bc791fd3c0a92bda22ca2f23f28be1 Mon Sep 17 00:00:00 2001 From: Joe Rogers <1337joe@gmail.com> Date: Mon, 6 Dec 2021 00:09:46 +0100 Subject: [PATCH 007/245] Implement CanRefresh tests for ProviderManager.GetImageProviders --- .../Manager/ProviderManagerTests.cs | 93 +++++++++++++++++-- 1 file changed, 87 insertions(+), 6 deletions(-) diff --git a/tests/Jellyfin.Providers.Tests/Manager/ProviderManagerTests.cs b/tests/Jellyfin.Providers.Tests/Manager/ProviderManagerTests.cs index 590f50b256..4a1b90895f 100644 --- a/tests/Jellyfin.Providers.Tests/Manager/ProviderManagerTests.cs +++ b/tests/Jellyfin.Providers.Tests/Manager/ProviderManagerTests.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using MediaBrowser.Controller.BaseItemManager; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Movies; @@ -53,7 +54,7 @@ namespace Jellyfin.Providers.Tests.Manager for (var i = 0; i < providerCount; i++) { var order = hasOrderOrder?[i]; - providerList.Add(MockIImageProvider(nameProvider(i), item, order)); + providerList.Add(MockIImageProvider(nameProvider(i), item, order: order)); } var libraryOptions = new LibraryOptions(); @@ -95,7 +96,78 @@ namespace Jellyfin.Providers.Tests.Manager } } - private static IImageProvider MockIImageProvider(string name, BaseItem supportedType, int? order = null) + [Theory] + [InlineData(true, false, true)] + [InlineData(false, false, false)] + [InlineData(true, true, false)] + public void GetImageProviders_CanRefreshBasic_WhenSupportsWithoutError(bool supports, bool errorOnSupported, bool expected) + { + GetImageProviders_CanRefresh_Tester(typeof(IImageProvider), supports, expected, errorOnSupported: errorOnSupported); + } + + [Theory] + [InlineData(typeof(ILocalImageProvider), false, true)] + [InlineData(typeof(ILocalImageProvider), true, true)] + [InlineData(typeof(IImageProvider), false, false)] + [InlineData(typeof(IImageProvider), true, true)] + public void GetImageProviders_CanRefreshLocked_WhenLocalOrFullRefresh(Type providerType, bool fullRefresh, bool expected) + { + GetImageProviders_CanRefresh_Tester(providerType, true, expected, itemLocked: true, fullRefresh: fullRefresh); + } + + [Theory] + [InlineData(typeof(ILocalImageProvider), false, true)] + [InlineData(typeof(IRemoteImageProvider), true, true)] + [InlineData(typeof(IDynamicImageProvider), true, true)] + [InlineData(typeof(IRemoteImageProvider), false, false)] + [InlineData(typeof(IDynamicImageProvider), false, false)] + public void GetImageProviders_CanRefreshEnabled_WhenLocalOrEnabled(Type providerType, bool enabled, bool expected) + { + GetImageProviders_CanRefresh_Tester(providerType, true, expected, baseItemEnabled: enabled); + } + + private static void GetImageProviders_CanRefresh_Tester(Type providerType, bool supports, bool expected, bool errorOnSupported = false, bool itemLocked = false, bool fullRefresh = false, bool baseItemEnabled = true) + { + var item = new Movie + { + IsLocked = itemLocked + }; + + var providerName = "provider"; + IImageProvider provider = providerType.Name switch + { + "IImageProvider" => MockIImageProvider(providerName, item, supports: supports, errorOnSupported: errorOnSupported), + "ILocalImageProvider" => MockIImageProvider(providerName, item, supports: supports, errorOnSupported: errorOnSupported), + "IRemoteImageProvider" => MockIImageProvider(providerName, item, supports: supports, errorOnSupported: errorOnSupported), + "IDynamicImageProvider" => MockIImageProvider(providerName, item, supports: supports, errorOnSupported: errorOnSupported), + _ => throw new ArgumentException("Unexpected provider type") + }; + + var refreshOptions = new ImageRefreshOptions(Mock.Of(MockBehavior.Strict)) + { + ImageRefreshMode = fullRefresh ? MetadataRefreshMode.FullRefresh : MetadataRefreshMode.Default + }; + + var baseItemManager = new Mock(MockBehavior.Strict); + baseItemManager.Setup(i => i.IsImageFetcherEnabled(item, It.IsAny(), providerName)) + .Returns(baseItemEnabled); + + var providerManager = GetProviderManager(baseItemManager: baseItemManager.Object); + AddParts(providerManager, imageProviders: new[] { provider }); + + var actualProviders = providerManager.GetImageProviders(item, refreshOptions); + + if (expected) + { + Assert.Single(actualProviders); + } + else + { + Assert.Empty(actualProviders); + } + } + + private static IImageProvider MockIImageProvider(string name, BaseItem expectedType, bool supports = true, int? order = null, bool errorOnSupported = false) where T : class, IImageProvider { Mock? hasOrder = null; @@ -111,12 +183,21 @@ namespace Jellyfin.Providers.Tests.Manager : hasOrder.As(); provider.Setup(p => p.Name) .Returns(name); - provider.Setup(p => p.Supports(supportedType)) - .Returns(true); + if (errorOnSupported) + { + provider.Setup(p => p.Supports(It.IsAny())) + .Throws(new ArgumentException()); + } + else + { + provider.Setup(p => p.Supports(expectedType)) + .Returns(supports); + } + return provider.Object; } - private static ProviderManager GetProviderManager(ServerConfiguration? serverConfiguration = null, LibraryOptions? libraryOptions = null) + private static ProviderManager GetProviderManager(ServerConfiguration? serverConfiguration = null, LibraryOptions? libraryOptions = null, IBaseItemManager? baseItemManager = null) { var serverConfigurationManager = new Mock(MockBehavior.Strict); serverConfigurationManager.Setup(i => i.Configuration) @@ -135,7 +216,7 @@ namespace Jellyfin.Providers.Tests.Manager null, null, libraryManager.Object, - null); + baseItemManager); return providerManager; } From 11c7c24f0ef06e6366c075062928976ae0d30600 Mon Sep 17 00:00:00 2001 From: Joe Rogers <1337joe@gmail.com> Date: Mon, 6 Dec 2021 22:31:16 +0100 Subject: [PATCH 008/245] Clarify naming, minor method ordering improvement --- .../Manager/ProviderManager.cs | 40 +++++++++---------- .../Manager/ProviderManagerTests.cs | 14 +++---- 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/MediaBrowser.Providers/Manager/ProviderManager.cs b/MediaBrowser.Providers/Manager/ProviderManager.cs index 9bae738010..633b3b1db7 100644 --- a/MediaBrowser.Providers/Manager/ProviderManager.cs +++ b/MediaBrowser.Providers/Manager/ProviderManager.cs @@ -297,18 +297,31 @@ namespace MediaBrowser.Providers.Manager return GetRemoteImageProviders(item, true).Select(i => new ImageProviderInfo(i.Name, i.GetSupportedImages(item).ToArray())); } + private IEnumerable GetRemoteImageProviders(BaseItem item, bool includeDisabled) + { + var options = GetMetadataOptions(item); + var libraryOptions = _libraryManager.GetLibraryOptions(item); + + return GetImageProvidersInternal( + item, + libraryOptions, + options, + new ImageRefreshOptions(new DirectoryService(_fileSystem)), + includeDisabled).OfType(); + } + /// public IEnumerable GetImageProviders(BaseItem item, ImageRefreshOptions refreshOptions) { - return GetImageProviders(item, _libraryManager.GetLibraryOptions(item), GetMetadataOptions(item), refreshOptions, false); + return GetImageProvidersInternal(item, _libraryManager.GetLibraryOptions(item), GetMetadataOptions(item), refreshOptions, false); } - private IEnumerable GetImageProviders(BaseItem item, LibraryOptions libraryOptions, MetadataOptions options, ImageRefreshOptions refreshOptions, bool includeDisabled) + private IEnumerable GetImageProvidersInternal(BaseItem item, LibraryOptions libraryOptions, MetadataOptions options, ImageRefreshOptions refreshOptions, bool includeDisabled) { var typeOptions = libraryOptions.GetTypeOptions(item.GetType().Name); var fetcherOrder = typeOptions?.ImageFetcherOrder ?? options.ImageFetcherOrder; - return _imageProviders.Where(i => CanRefresh(i, item, libraryOptions, refreshOptions, includeDisabled)) + return _imageProviders.Where(i => CanRefreshImages(i, item, libraryOptions, refreshOptions, includeDisabled)) .OrderBy(i => GetConfiguredOrder(fetcherOrder, i.Name)) .ThenBy(GetOrder); } @@ -342,25 +355,12 @@ namespace MediaBrowser.Providers.Manager var currentOptions = globalMetadataOptions; return _metadataProviders.OfType>() - .Where(i => CanRefresh(i, item, libraryOptions, includeDisabled, forceEnableInternetMetadata)) + .Where(i => CanRefreshMetadata(i, item, libraryOptions, includeDisabled, forceEnableInternetMetadata)) .OrderBy(i => GetConfiguredOrder(item, i, libraryOptions, currentOptions)) .ThenBy(GetDefaultOrder); } - private IEnumerable GetRemoteImageProviders(BaseItem item, bool includeDisabled) - { - var options = GetMetadataOptions(item); - var libraryOptions = _libraryManager.GetLibraryOptions(item); - - return GetImageProviders( - item, - libraryOptions, - options, - new ImageRefreshOptions(new DirectoryService(_fileSystem)), - includeDisabled).OfType(); - } - - private bool CanRefresh( + private bool CanRefreshMetadata( IMetadataProvider provider, BaseItem item, LibraryOptions libraryOptions, @@ -401,7 +401,7 @@ namespace MediaBrowser.Providers.Manager return true; } - private bool CanRefresh( + private bool CanRefreshImages( IImageProvider provider, BaseItem item, LibraryOptions libraryOptions, @@ -535,7 +535,7 @@ namespace MediaBrowser.Providers.Manager var libraryOptions = new LibraryOptions(); - var imageProviders = GetImageProviders( + var imageProviders = GetImageProvidersInternal( dummy, libraryOptions, options, diff --git a/tests/Jellyfin.Providers.Tests/Manager/ProviderManagerTests.cs b/tests/Jellyfin.Providers.Tests/Manager/ProviderManagerTests.cs index 4a1b90895f..98c1e19b20 100644 --- a/tests/Jellyfin.Providers.Tests/Manager/ProviderManagerTests.cs +++ b/tests/Jellyfin.Providers.Tests/Manager/ProviderManagerTests.cs @@ -100,9 +100,9 @@ namespace Jellyfin.Providers.Tests.Manager [InlineData(true, false, true)] [InlineData(false, false, false)] [InlineData(true, true, false)] - public void GetImageProviders_CanRefreshBasic_WhenSupportsWithoutError(bool supports, bool errorOnSupported, bool expected) + public void GetImageProviders_CanRefreshImagesBasic_WhenSupportsWithoutError(bool supports, bool errorOnSupported, bool expected) { - GetImageProviders_CanRefresh_Tester(typeof(IImageProvider), supports, expected, errorOnSupported: errorOnSupported); + GetImageProviders_CanRefreshImages_Tester(typeof(IImageProvider), supports, expected, errorOnSupported: errorOnSupported); } [Theory] @@ -110,9 +110,9 @@ namespace Jellyfin.Providers.Tests.Manager [InlineData(typeof(ILocalImageProvider), true, true)] [InlineData(typeof(IImageProvider), false, false)] [InlineData(typeof(IImageProvider), true, true)] - public void GetImageProviders_CanRefreshLocked_WhenLocalOrFullRefresh(Type providerType, bool fullRefresh, bool expected) + public void GetImageProviders_CanRefreshImagesLocked_WhenLocalOrFullRefresh(Type providerType, bool fullRefresh, bool expected) { - GetImageProviders_CanRefresh_Tester(providerType, true, expected, itemLocked: true, fullRefresh: fullRefresh); + GetImageProviders_CanRefreshImages_Tester(providerType, true, expected, itemLocked: true, fullRefresh: fullRefresh); } [Theory] @@ -121,12 +121,12 @@ namespace Jellyfin.Providers.Tests.Manager [InlineData(typeof(IDynamicImageProvider), true, true)] [InlineData(typeof(IRemoteImageProvider), false, false)] [InlineData(typeof(IDynamicImageProvider), false, false)] - public void GetImageProviders_CanRefreshEnabled_WhenLocalOrEnabled(Type providerType, bool enabled, bool expected) + public void GetImageProviders_CanRefreshImagesEnabled_WhenLocalOrEnabled(Type providerType, bool enabled, bool expected) { - GetImageProviders_CanRefresh_Tester(providerType, true, expected, baseItemEnabled: enabled); + GetImageProviders_CanRefreshImages_Tester(providerType, true, expected, baseItemEnabled: enabled); } - private static void GetImageProviders_CanRefresh_Tester(Type providerType, bool supports, bool expected, bool errorOnSupported = false, bool itemLocked = false, bool fullRefresh = false, bool baseItemEnabled = true) + private static void GetImageProviders_CanRefreshImages_Tester(Type providerType, bool supports, bool expected, bool errorOnSupported = false, bool itemLocked = false, bool fullRefresh = false, bool baseItemEnabled = true) { var item = new Movie { From 91e706d3873440a28f107da04143a374d4277b9a Mon Sep 17 00:00:00 2001 From: Joe Rogers <1337joe@gmail.com> Date: Wed, 8 Dec 2021 00:52:57 +0100 Subject: [PATCH 009/245] Implement sort test for ProviderManager.GetMetadataProviders --- .../Manager/ProviderManagerTests.cs | 186 +++++++++++++++++- 1 file changed, 177 insertions(+), 9 deletions(-) diff --git a/tests/Jellyfin.Providers.Tests/Manager/ProviderManagerTests.cs b/tests/Jellyfin.Providers.Tests/Manager/ProviderManagerTests.cs index 98c1e19b20..7a542f0eba 100644 --- a/tests/Jellyfin.Providers.Tests/Manager/ProviderManagerTests.cs +++ b/tests/Jellyfin.Providers.Tests/Manager/ProviderManagerTests.cs @@ -37,7 +37,7 @@ namespace Jellyfin.Providers.Tests.Manager { 3, null, null, new int?[] { 2, 1, 0 }, new[] { 2, 1, 0 } }, // full reverse order // multiple orders set - { 3, new[] { 1 }, new[] { 2, 0, 1 }, null, new[] { 1, 0, 2 } }, // library order first, server order ignored + { 3, new[] { 1 }, new[] { 2, 0, 1 }, null, new[] { 1, 0, 2 } }, // partial library order first, server order ignored { 3, new[] { 1 }, null, new int?[] { 2, 0, 1 }, new[] { 1, 2, 0 } }, // library order first, then orderby { 3, new[] { 2, 1, 0 }, new[] { 1, 2, 0 }, new int?[] { 2, 0, 1 }, new[] { 2, 1, 0 } }, // library order wins }; @@ -90,10 +90,8 @@ namespace Jellyfin.Providers.Tests.Manager var actualProviders = providerManager.GetImageProviders(item, refreshOptions).ToList(); Assert.Equal(providerList.Count, actualProviders.Count); - for (var i = 0; i < providerList.Count; i++) - { - Assert.Equal(i, actualProviders.IndexOf(providerList[expectedOrder[i]])); - } + var actualOrder = actualProviders.Select(i => providerList.IndexOf(i)).ToArray(); + Assert.Equal(expectedOrder, actualOrder); } [Theory] @@ -167,8 +165,129 @@ namespace Jellyfin.Providers.Tests.Manager } } - private static IImageProvider MockIImageProvider(string name, BaseItem expectedType, bool supports = true, int? order = null, bool errorOnSupported = false) - where T : class, IImageProvider + private static TheoryData GetMetadataProvidersOrderData() + { + var l = "local"; + var r = "remote"; + return new () + { + { new[] { l, l, r, r }, null, null, null, null, null, new[] { 0, 1, 2, 3 } }, // no order options set + + // library options ordering + { new[] { l, l, r, r }, Array.Empty(), Array.Empty(), null, null, null, new[] { 0, 1, 2, 3 } }, // no order provided + // local only + { new[] { r, l, l, l }, new[] { 2 }, null, null, null, null, new[] { 2, 0, 1, 3 } }, // one item in order + { new[] { r, l, l, l }, new[] { 3, 2, 1 }, null, null, null, null, new[] { 3, 2, 1, 0 } }, // full reverse order + // remote only + { new[] { l, r, r, r }, null, new[] { 2 }, null, null, null, new[] { 2, 0, 1, 3 } }, // one item in order + { new[] { l, r, r, r }, null, new[] { 3, 2, 1 }, null, null, null, new[] { 3, 2, 1, 0 } }, // full reverse order + // local and remote, note that results will be interleaved (odd but expected) + { new[] { l, l, r, r }, new[] { 1 }, new[] { 3 }, null, null, null, new[] { 1, 3, 0, 2 } }, // one item in each order + { new[] { l, l, l, r, r, r }, new[] { 2, 1, 0 }, new[] { 5, 4, 3 }, null, null, null, new[] { 2, 5, 1, 4, 0, 3 } }, // full reverse order + + // // server options ordering + { new[] { l, l, r, r }, null, null, Array.Empty(), Array.Empty(), null, new[] { 0, 1, 2, 3 } }, // no order provided + // local only + { new[] { r, l, l, l }, null, null, new[] { 2 }, null, null, new[] { 2, 0, 1, 3 } }, // one item in order + { new[] { r, l, l, l }, null, null, new[] { 3, 2, 1 }, null, null, new[] { 3, 2, 1, 0 } }, // full reverse order + // remote only + { new[] { l, r, r, r }, null, null, null, new[] { 2 }, null, new[] { 2, 0, 1, 3 } }, // one item in order + { new[] { l, r, r, r }, null, null, null, new[] { 3, 2, 1 }, null, new[] { 3, 2, 1, 0 } }, // full reverse order + // local and remote, note that results will be interleaved (odd but expected) + { new[] { l, l, r, r }, null, null, new[] { 1 }, new[] { 3 }, null, new[] { 1, 3, 0, 2 } }, // one item in each order + { new[] { l, l, l, r, r, r }, null, null, new[] { 2, 1, 0 }, new[] { 5, 4, 3 }, null, new[] { 2, 5, 1, 4, 0, 3 } }, // full reverse order + + // IHasOrder ordering (not interleaved, doesn't care about types) + // TODO unset goes to beginning, not end + { new[] { l, l, r, r }, null, null, null, null, new int?[] { 2, null, 1, null }, new[] { 1, 3, 2, 0 } }, // partially defined + { new[] { l, l, r, r }, null, null, null, null, new int?[] { 3, 2, 1, 0 }, new[] { 3, 2, 1, 0 } }, // full reverse order + // note odd interaction - orderby determines order of slot when local and remote both have a slot 0 + { new[] { l, l, r, r }, new[] { 1 }, new[] { 3 }, null, null, new int?[] { null, 2, null, 1 }, new[] { 3, 1, 0, 2 } }, // sorts interleaved results + + // multiple orders set + { new[] { l, l, l, r, r, r }, new[] { 1 }, new[] { 4 }, new[] { 2, 1, 0 }, new[] { 5, 4, 3 }, null, new[] { 1, 4, 0, 2, 3, 5 } }, // partial library order first, server order ignored + { new[] { l, l, l }, new[] { 1 }, null, null, null, new int?[] { 2, 0, 1 }, new[] { 1, 2, 0 } }, // library order first, then orderby + { new[] { l, l, l, r, r, r }, new[] { 2, 1, 0 }, new[] { 5, 4, 3 }, new[] { 1, 2, 0 }, new[] { 4, 5, 3 }, new int?[] { 5, 4, 1, 6, 3, 2 }, new[] { 2, 5, 4, 1, 0, 3 } }, // library order wins (with orderby between local/remote) + }; + } + + [Theory] + [MemberData(nameof(GetMetadataProvidersOrderData))] + public void GetMetadataProviders_ProviderOrder_MatchesExpected(string[] providers, int[]? libraryLocalOrder, int[]? libraryRemoteOrder, int[]? serverLocalOrder, int[]? serverRemoteOrder, int?[]? hasOrderOrder, int[] expectedOrder) + { + var item = new MetadataTestItem(); + var typeNames = new Dictionary + { + { "remote", nameof(IRemoteMetadataProvider) }, + { "local", nameof(ILocalMetadataProvider) }, + { "custom", nameof(ICustomMetadataProvider) } + }; + + var nameProvider = new Func(i => "Provider" + i); + + var providerList = new List>(); + for (var i = 0; i < providers.Length; i++) + { + var order = hasOrderOrder?[i]; + providerList.Add(MockIMetadataProviderMapper(typeNames[providers[i]], nameProvider(i), order: order)); + } + + var libraryOptions = new LibraryOptions(); + if (libraryLocalOrder != null) + { + libraryOptions.LocalMetadataReaderOrder = libraryLocalOrder.Select(nameProvider).ToArray(); + } + + if (libraryRemoteOrder != null) + { + libraryOptions.TypeOptions = new[] + { + new TypeOptions + { + Type = item.GetType().Name, + MetadataFetcherOrder = libraryRemoteOrder.Select(nameProvider).ToArray() + } + }; + } + + var serverConfiguration = new ServerConfiguration(); + if (serverLocalOrder != null || serverRemoteOrder != null) + { + serverConfiguration.MetadataOptions = new[] + { + new MetadataOptions + { + ItemType = item.GetType().Name + } + }; + if (serverLocalOrder != null) + { + serverConfiguration.MetadataOptions[0].LocalMetadataReaderOrder = serverLocalOrder.Select(nameProvider).ToArray(); + } + + if (serverRemoteOrder != null) + { + serverConfiguration.MetadataOptions[0].MetadataFetcherOrder = serverRemoteOrder.Select(nameProvider).ToArray(); + } + } + + var baseItemManager = new Mock(MockBehavior.Strict); + baseItemManager.Setup(i => i.IsMetadataFetcherEnabled(item, It.IsAny(), It.IsAny())) + .Returns(true); + + var providerManager = GetProviderManager(serverConfiguration: serverConfiguration, baseItemManager: baseItemManager.Object); + AddParts(providerManager, metadataProviders: providerList); + + // TODO why does this take libraryOptions directly while GetImageProviders did not? + var actualProviders = providerManager.GetMetadataProviders(item, libraryOptions).ToList(); + + Assert.Equal(providerList.Count, actualProviders.Count); + var actualOrder = actualProviders.Select(i => providerList.IndexOf(i)).ToArray(); + Assert.Equal(expectedOrder, actualOrder); + } + + private static IImageProvider MockIImageProvider(string name, BaseItem expectedType, bool supports = true, int? order = null, bool errorOnSupported = false) + where TProviderType : class, IImageProvider { Mock? hasOrder = null; if (order != null) @@ -179,8 +298,8 @@ namespace Jellyfin.Providers.Tests.Manager } var provider = hasOrder == null - ? new Mock(MockBehavior.Strict) - : hasOrder.As(); + ? new Mock(MockBehavior.Strict) + : hasOrder.As(); provider.Setup(p => p.Name) .Returns(name); if (errorOnSupported) @@ -197,6 +316,38 @@ namespace Jellyfin.Providers.Tests.Manager return provider.Object; } + private static IMetadataProvider MockIMetadataProviderMapper(string typeName, string providerName, int? order = null) + where TItemType : BaseItem, IHasLookupInfo + where TLookupInfoType : ItemLookupInfo, new() + => typeName switch + { + "ILocalMetadataProvider" => MockIMetadataProvider, TItemType>(providerName, order), + "IRemoteMetadataProvider" => MockIMetadataProvider, TItemType>(providerName, order), + "ICustomMetadataProvider" => MockIMetadataProvider, TItemType>(providerName, order), + _ => MockIMetadataProvider, TItemType>(providerName, order) + }; + + private static IMetadataProvider MockIMetadataProvider(string name, int? order = null) + where TProviderType : class, IMetadataProvider + where TItemType : BaseItem + { + Mock? hasOrder = null; + if (order != null) + { + hasOrder = new Mock(MockBehavior.Strict); + hasOrder.Setup(i => i.Order) + .Returns((int)order); + } + + var provider = hasOrder == null + ? new Mock(MockBehavior.Strict) + : hasOrder.As(); + provider.Setup(p => p.Name) + .Returns(name); + + return provider.Object; + } + private static ProviderManager GetProviderManager(ServerConfiguration? serverConfiguration = null, LibraryOptions? libraryOptions = null, IBaseItemManager? baseItemManager = null) { var serverConfigurationManager = new Mock(MockBehavior.Strict); @@ -237,5 +388,22 @@ namespace Jellyfin.Providers.Tests.Manager providerManager.AddParts(imageProviders, metadataServices, metadataProviders, metadataSavers, externalIds); } + + /// + /// Simple extension to force SupportsLocalMetadata to true. + /// + public class MetadataTestItem : BaseItem, IHasLookupInfo + { + public override bool SupportsLocalMetadata => true; + + public MetadataTestItemInfo GetLookupInfo() + { + return GetItemLookupInfo(); + } + } + + public class MetadataTestItemInfo : ItemLookupInfo + { + } } } From e7df72de497f25deb7f77bf9de39aeaba1159d11 Mon Sep 17 00:00:00 2001 From: Joe Rogers <1337joe@gmail.com> Date: Wed, 8 Dec 2021 16:49:09 +0100 Subject: [PATCH 010/245] Improve metadata provider sorting Extract configured order up front instead of for each provider Non-IHasOrder providers default to middle, not beginning Merge image and metadata sort helper methods --- .../Manager/ProviderManager.cs | 80 ++++++------------- .../Manager/ProviderManagerTests.cs | 16 +--- 2 files changed, 27 insertions(+), 69 deletions(-) diff --git a/MediaBrowser.Providers/Manager/ProviderManager.cs b/MediaBrowser.Providers/Manager/ProviderManager.cs index 633b3b1db7..82d633e234 100644 --- a/MediaBrowser.Providers/Manager/ProviderManager.cs +++ b/MediaBrowser.Providers/Manager/ProviderManager.cs @@ -323,20 +323,7 @@ namespace MediaBrowser.Providers.Manager return _imageProviders.Where(i => CanRefreshImages(i, item, libraryOptions, refreshOptions, includeDisabled)) .OrderBy(i => GetConfiguredOrder(fetcherOrder, i.Name)) - .ThenBy(GetOrder); - } - - private static int GetConfiguredOrder(string[] order, string providerName) - { - var index = Array.IndexOf(order, providerName); - - if (index != -1) - { - return index; - } - - // default to end - return int.MaxValue; + .ThenBy(GetDefaultOrder); } /// @@ -351,12 +338,23 @@ namespace MediaBrowser.Providers.Manager private IEnumerable> GetMetadataProvidersInternal(BaseItem item, LibraryOptions libraryOptions, MetadataOptions globalMetadataOptions, bool includeDisabled, bool forceEnableInternetMetadata) where T : BaseItem { - // Avoid implicitly captured closure - var currentOptions = globalMetadataOptions; + var localMetadataReaderOrder = libraryOptions.LocalMetadataReaderOrder ?? globalMetadataOptions.LocalMetadataReaderOrder; + var typeOptions = libraryOptions.GetTypeOptions(item.GetType().Name); + var metadataFetcherOrder = typeOptions?.MetadataFetcherOrder ?? globalMetadataOptions.MetadataFetcherOrder; return _metadataProviders.OfType>() .Where(i => CanRefreshMetadata(i, item, libraryOptions, includeDisabled, forceEnableInternetMetadata)) - .OrderBy(i => GetConfiguredOrder(item, i, libraryOptions, currentOptions)) + .OrderBy(i => + { + // local and remote providers will be interleaved in the final order + // only relative order within a type matters: consumers of the list filter to one or the other + switch (i) + { + case ILocalMetadataProvider: return GetConfiguredOrder(localMetadataReaderOrder, i.Name); + case IRemoteMetadataProvider: return GetConfiguredOrder(metadataFetcherOrder, i.Name); + default: return int.MaxValue; // default to end + } + }) .ThenBy(GetDefaultOrder); } @@ -439,42 +437,20 @@ namespace MediaBrowser.Providers.Manager } } - private int GetConfiguredOrder(BaseItem item, IMetadataProvider provider, LibraryOptions libraryOptions, MetadataOptions globalMetadataOptions) + private static int GetConfiguredOrder(string[] order, string providerName) { - // See if there's a user-defined order - if (provider is ILocalMetadataProvider) + var index = Array.IndexOf(order, providerName); + + if (index != -1) { - var configuredOrder = libraryOptions.LocalMetadataReaderOrder ?? globalMetadataOptions.LocalMetadataReaderOrder; - - var index = Array.IndexOf(configuredOrder, provider.Name); - - if (index != -1) - { - return index; - } + return index; } - // See if there's a user-defined order - if (provider is IRemoteMetadataProvider) - { - var typeOptions = libraryOptions.GetTypeOptions(item.GetType().Name); - var typeFetcherOrder = typeOptions?.MetadataFetcherOrder; - - var fetcherOrder = typeFetcherOrder ?? globalMetadataOptions.MetadataFetcherOrder; - - var index = Array.IndexOf(fetcherOrder, provider.Name); - - if (index != -1) - { - return index; - } - } - - // Not configured. Just return some high number to put it at the end. - return 100; + // default to end + return int.MaxValue; } - private static int GetOrder(object provider) + private static int GetDefaultOrder(object provider) { if (provider is IHasOrder hasOrder) { @@ -485,16 +461,6 @@ namespace MediaBrowser.Providers.Manager return 50; } - private int GetDefaultOrder(IMetadataProvider provider) - { - if (provider is IHasOrder hasOrder) - { - return hasOrder.Order; - } - - return 0; - } - /// public MetadataPluginSummary[] GetAllMetadataPlugins() { diff --git a/tests/Jellyfin.Providers.Tests/Manager/ProviderManagerTests.cs b/tests/Jellyfin.Providers.Tests/Manager/ProviderManagerTests.cs index 7a542f0eba..d59e4070f9 100644 --- a/tests/Jellyfin.Providers.Tests/Manager/ProviderManagerTests.cs +++ b/tests/Jellyfin.Providers.Tests/Manager/ProviderManagerTests.cs @@ -167,8 +167,8 @@ namespace Jellyfin.Providers.Tests.Manager private static TheoryData GetMetadataProvidersOrderData() { - var l = "local"; - var r = "remote"; + var l = nameof(ILocalMetadataProvider); + var r = nameof(IRemoteMetadataProvider); return new () { { new[] { l, l, r, r }, null, null, null, null, null, new[] { 0, 1, 2, 3 } }, // no order options set @@ -198,8 +198,7 @@ namespace Jellyfin.Providers.Tests.Manager { new[] { l, l, l, r, r, r }, null, null, new[] { 2, 1, 0 }, new[] { 5, 4, 3 }, null, new[] { 2, 5, 1, 4, 0, 3 } }, // full reverse order // IHasOrder ordering (not interleaved, doesn't care about types) - // TODO unset goes to beginning, not end - { new[] { l, l, r, r }, null, null, null, null, new int?[] { 2, null, 1, null }, new[] { 1, 3, 2, 0 } }, // partially defined + { new[] { l, l, r, r }, null, null, null, null, new int?[] { 2, null, 1, null }, new[] { 2, 0, 1, 3 } }, // partially defined { new[] { l, l, r, r }, null, null, null, null, new int?[] { 3, 2, 1, 0 }, new[] { 3, 2, 1, 0 } }, // full reverse order // note odd interaction - orderby determines order of slot when local and remote both have a slot 0 { new[] { l, l, r, r }, new[] { 1 }, new[] { 3 }, null, null, new int?[] { null, 2, null, 1 }, new[] { 3, 1, 0, 2 } }, // sorts interleaved results @@ -216,12 +215,6 @@ namespace Jellyfin.Providers.Tests.Manager public void GetMetadataProviders_ProviderOrder_MatchesExpected(string[] providers, int[]? libraryLocalOrder, int[]? libraryRemoteOrder, int[]? serverLocalOrder, int[]? serverRemoteOrder, int?[]? hasOrderOrder, int[] expectedOrder) { var item = new MetadataTestItem(); - var typeNames = new Dictionary - { - { "remote", nameof(IRemoteMetadataProvider) }, - { "local", nameof(ILocalMetadataProvider) }, - { "custom", nameof(ICustomMetadataProvider) } - }; var nameProvider = new Func(i => "Provider" + i); @@ -229,7 +222,7 @@ namespace Jellyfin.Providers.Tests.Manager for (var i = 0; i < providers.Length; i++) { var order = hasOrderOrder?[i]; - providerList.Add(MockIMetadataProviderMapper(typeNames[providers[i]], nameProvider(i), order: order)); + providerList.Add(MockIMetadataProviderMapper(providers[i], nameProvider(i), order: order)); } var libraryOptions = new LibraryOptions(); @@ -278,7 +271,6 @@ namespace Jellyfin.Providers.Tests.Manager var providerManager = GetProviderManager(serverConfiguration: serverConfiguration, baseItemManager: baseItemManager.Object); AddParts(providerManager, metadataProviders: providerList); - // TODO why does this take libraryOptions directly while GetImageProviders did not? var actualProviders = providerManager.GetMetadataProviders(item, libraryOptions).ToList(); Assert.Equal(providerList.Count, actualProviders.Count); From d5e2c2fb5e8a1328a2e938a7100a1ceb29b28fa7 Mon Sep 17 00:00:00 2001 From: Joe Rogers <1337joe@gmail.com> Date: Fri, 10 Dec 2021 00:38:41 +0100 Subject: [PATCH 011/245] Implement CanRefreshMetadata tests for GetMetadataProviders Cleanup tests, extract common blocks --- .../Manager/ProviderManagerTests.cs | 285 ++++++++++++------ 1 file changed, 196 insertions(+), 89 deletions(-) diff --git a/tests/Jellyfin.Providers.Tests/Manager/ProviderManagerTests.cs b/tests/Jellyfin.Providers.Tests/Manager/ProviderManagerTests.cs index d59e4070f9..ba91f5ed2d 100644 --- a/tests/Jellyfin.Providers.Tests/Manager/ProviderManagerTests.cs +++ b/tests/Jellyfin.Providers.Tests/Manager/ProviderManagerTests.cs @@ -57,33 +57,10 @@ namespace Jellyfin.Providers.Tests.Manager providerList.Add(MockIImageProvider(nameProvider(i), item, order: order)); } - var libraryOptions = new LibraryOptions(); - if (libraryOrder != null) - { - libraryOptions.TypeOptions = new[] - { - new TypeOptions - { - Type = item.GetType().Name, - ImageFetcherOrder = libraryOrder.Select(nameProvider).ToArray() - } - }; - } + var libraryOptions = CreateLibraryOptions(item.GetType().Name, imageFetcherOrder: libraryOrder?.Select(nameProvider).ToArray()); + var serverConfiguration = CreateServerConfiguration(item.GetType().Name, imageFetcherOrder: serverOrder?.Select(nameProvider).ToArray()); - var serverConfiguration = new ServerConfiguration(); - if (serverOrder != null) - { - serverConfiguration.MetadataOptions = new[] - { - new MetadataOptions - { - ItemType = item.GetType().Name, - ImageFetcherOrder = serverOrder.Select(nameProvider).ToArray() - } - }; - } - - var providerManager = GetProviderManager(serverConfiguration: serverConfiguration, libraryOptions: libraryOptions); + using var providerManager = GetProviderManager(serverConfiguration: serverConfiguration, libraryOptions: libraryOptions); AddParts(providerManager, imageProviders: providerList); var refreshOptions = new ImageRefreshOptions(Mock.Of(MockBehavior.Strict)); @@ -119,12 +96,19 @@ namespace Jellyfin.Providers.Tests.Manager [InlineData(typeof(IDynamicImageProvider), true, true)] [InlineData(typeof(IRemoteImageProvider), false, false)] [InlineData(typeof(IDynamicImageProvider), false, false)] - public void GetImageProviders_CanRefreshImagesEnabled_WhenLocalOrEnabled(Type providerType, bool enabled, bool expected) + public void GetImageProviders_CanRefreshImagesBaseItemEnabled_WhenLocalOrEnabled(Type providerType, bool enabled, bool expected) { GetImageProviders_CanRefreshImages_Tester(providerType, true, expected, baseItemEnabled: enabled); } - private static void GetImageProviders_CanRefreshImages_Tester(Type providerType, bool supports, bool expected, bool errorOnSupported = false, bool itemLocked = false, bool fullRefresh = false, bool baseItemEnabled = true) + private static void GetImageProviders_CanRefreshImages_Tester( + Type providerType, + bool supports, + bool expected, + bool errorOnSupported = false, + bool itemLocked = false, + bool fullRefresh = false, + bool baseItemEnabled = true) { var item = new Movie { @@ -150,19 +134,12 @@ namespace Jellyfin.Providers.Tests.Manager baseItemManager.Setup(i => i.IsImageFetcherEnabled(item, It.IsAny(), providerName)) .Returns(baseItemEnabled); - var providerManager = GetProviderManager(baseItemManager: baseItemManager.Object); + using var providerManager = GetProviderManager(baseItemManager: baseItemManager.Object); AddParts(providerManager, imageProviders: new[] { provider }); - var actualProviders = providerManager.GetImageProviders(item, refreshOptions); + var actualProviders = providerManager.GetImageProviders(item, refreshOptions).ToArray(); - if (expected) - { - Assert.Single(actualProviders); - } - else - { - Assert.Empty(actualProviders); - } + Assert.Equal(expected ? 1 : 0, actualProviders.Length); } private static TheoryData GetMetadataProvidersOrderData() @@ -212,7 +189,14 @@ namespace Jellyfin.Providers.Tests.Manager [Theory] [MemberData(nameof(GetMetadataProvidersOrderData))] - public void GetMetadataProviders_ProviderOrder_MatchesExpected(string[] providers, int[]? libraryLocalOrder, int[]? libraryRemoteOrder, int[]? serverLocalOrder, int[]? serverRemoteOrder, int?[]? hasOrderOrder, int[] expectedOrder) + public void GetMetadataProviders_ProviderOrder_MatchesExpected( + string[] providers, + int[]? libraryLocalOrder, + int[]? libraryRemoteOrder, + int[]? serverLocalOrder, + int[]? serverRemoteOrder, + int?[]? hasOrderOrder, + int[] expectedOrder) { var item = new MetadataTestItem(); @@ -225,50 +209,20 @@ namespace Jellyfin.Providers.Tests.Manager providerList.Add(MockIMetadataProviderMapper(providers[i], nameProvider(i), order: order)); } - var libraryOptions = new LibraryOptions(); - if (libraryLocalOrder != null) - { - libraryOptions.LocalMetadataReaderOrder = libraryLocalOrder.Select(nameProvider).ToArray(); - } - - if (libraryRemoteOrder != null) - { - libraryOptions.TypeOptions = new[] - { - new TypeOptions - { - Type = item.GetType().Name, - MetadataFetcherOrder = libraryRemoteOrder.Select(nameProvider).ToArray() - } - }; - } - - var serverConfiguration = new ServerConfiguration(); - if (serverLocalOrder != null || serverRemoteOrder != null) - { - serverConfiguration.MetadataOptions = new[] - { - new MetadataOptions - { - ItemType = item.GetType().Name - } - }; - if (serverLocalOrder != null) - { - serverConfiguration.MetadataOptions[0].LocalMetadataReaderOrder = serverLocalOrder.Select(nameProvider).ToArray(); - } - - if (serverRemoteOrder != null) - { - serverConfiguration.MetadataOptions[0].MetadataFetcherOrder = serverRemoteOrder.Select(nameProvider).ToArray(); - } - } + var libraryOptions = CreateLibraryOptions( + item.GetType().Name, + localMetadataReaderOrder: libraryLocalOrder?.Select(nameProvider).ToArray(), + metadataFetcherOrder: libraryRemoteOrder?.Select(nameProvider).ToArray()); + var serverConfiguration = CreateServerConfiguration( + item.GetType().Name, + localMetadataReaderOrder: serverLocalOrder?.Select(nameProvider).ToArray(), + metadataFetcherOrder: serverRemoteOrder?.Select(nameProvider).ToArray()); var baseItemManager = new Mock(MockBehavior.Strict); baseItemManager.Setup(i => i.IsMetadataFetcherEnabled(item, It.IsAny(), It.IsAny())) .Returns(true); - var providerManager = GetProviderManager(serverConfiguration: serverConfiguration, baseItemManager: baseItemManager.Object); + using var providerManager = GetProviderManager(serverConfiguration: serverConfiguration, baseItemManager: baseItemManager.Object); AddParts(providerManager, metadataProviders: providerList); var actualProviders = providerManager.GetMetadataProviders(item, libraryOptions).ToList(); @@ -278,6 +232,87 @@ namespace Jellyfin.Providers.Tests.Manager Assert.Equal(expectedOrder, actualOrder); } + [Theory] + [InlineData(typeof(IMetadataProvider))] + [InlineData(typeof(ILocalMetadataProvider))] + [InlineData(typeof(IRemoteMetadataProvider))] + [InlineData(typeof(ICustomMetadataProvider))] + public void GetMetadataProviders_CanRefreshMetadataBasic_ReturnsTrue(Type providerType) + { + GetMetadataProviders_CanRefreshMetadata_Tester(providerType, true); + } + + [Theory] + [InlineData(typeof(ILocalMetadataProvider), false, true)] + [InlineData(typeof(IRemoteMetadataProvider), false, false)] + [InlineData(typeof(ICustomMetadataProvider), false, false)] + [InlineData(typeof(ILocalMetadataProvider), true, true)] + [InlineData(typeof(ICustomMetadataProvider), true, false)] + public void GetMetadataProviders_CanRefreshMetadataLocked_WhenLocalOrForced(Type providerType, bool forced, bool expected) + { + GetMetadataProviders_CanRefreshMetadata_Tester(providerType, expected, itemLocked: true, providerForced: forced); + } + + [Theory] + [InlineData(typeof(ILocalMetadataProvider), false, true)] + [InlineData(typeof(ICustomMetadataProvider), false, true)] + [InlineData(typeof(IRemoteMetadataProvider), false, false)] + [InlineData(typeof(IRemoteMetadataProvider), true, true)] + public void GetMetadataProviders_CanRefreshMetadataBaseItemEnabled_WhenEnabledOrNotRemote(Type providerType, bool baseItemEnabled, bool expected) + { + GetMetadataProviders_CanRefreshMetadata_Tester(providerType, expected, baseItemEnabled: baseItemEnabled); + } + + [Theory] + [InlineData(typeof(IRemoteMetadataProvider), false, true)] + [InlineData(typeof(ICustomMetadataProvider), false, true)] + [InlineData(typeof(ILocalMetadataProvider), false, false)] + [InlineData(typeof(ILocalMetadataProvider), true, true)] + public void GetMetadataProviders_CanRefreshMetadataSupportsLocal_WhenSupportsOrNotLocal(Type providerType, bool supportsLocalMetadata, bool expected) + { + GetMetadataProviders_CanRefreshMetadata_Tester(providerType, expected, supportsLocalMetadata: supportsLocalMetadata); + } + + [Theory] + [InlineData(typeof(ICustomMetadataProvider), true)] + [InlineData(typeof(IRemoteMetadataProvider), false)] + [InlineData(typeof(ILocalMetadataProvider), false)] + public void GetMetadataProviders_CanRefreshMetadataOwned_WhenNotLocal(Type providerType, bool expected) + { + GetMetadataProviders_CanRefreshMetadata_Tester(providerType, expected, ownedItem: true); + } + + private static void GetMetadataProviders_CanRefreshMetadata_Tester( + Type providerType, + bool expected, + bool itemLocked = false, + bool baseItemEnabled = true, + bool providerForced = false, + bool supportsLocalMetadata = true, + bool ownedItem = false) + { + var item = new MetadataTestItem + { + IsLocked = itemLocked, + OwnerId = ownedItem ? Guid.NewGuid() : Guid.Empty, + EnableLocalMetadata = supportsLocalMetadata + }; + + var providerName = "provider"; + var provider = MockIMetadataProviderMapper(providerType.Name, providerName, forced: providerForced); + + var baseItemManager = new Mock(MockBehavior.Strict); + baseItemManager.Setup(i => i.IsMetadataFetcherEnabled(item, It.IsAny(), providerName)) + .Returns(baseItemEnabled); + + using var providerManager = GetProviderManager(baseItemManager: baseItemManager.Object); + AddParts(providerManager, metadataProviders: new[] { provider }); + + var actualProviders = providerManager.GetMetadataProviders(item, new LibraryOptions()).ToArray(); + + Assert.Equal(expected ? 1 : 0, actualProviders.Length); + } + private static IImageProvider MockIImageProvider(string name, BaseItem expectedType, bool supports = true, int? order = null, bool errorOnSupported = false) where TProviderType : class, IImageProvider { @@ -297,7 +332,7 @@ namespace Jellyfin.Providers.Tests.Manager if (errorOnSupported) { provider.Setup(p => p.Supports(It.IsAny())) - .Throws(new ArgumentException()); + .Throws(new ArgumentException("Provider threw exception on Supports(item)")); } else { @@ -308,25 +343,31 @@ namespace Jellyfin.Providers.Tests.Manager return provider.Object; } - private static IMetadataProvider MockIMetadataProviderMapper(string typeName, string providerName, int? order = null) + private static IMetadataProvider MockIMetadataProviderMapper(string typeName, string providerName, int? order = null, bool forced = false) where TItemType : BaseItem, IHasLookupInfo where TLookupInfoType : ItemLookupInfo, new() => typeName switch { - "ILocalMetadataProvider" => MockIMetadataProvider, TItemType>(providerName, order), - "IRemoteMetadataProvider" => MockIMetadataProvider, TItemType>(providerName, order), - "ICustomMetadataProvider" => MockIMetadataProvider, TItemType>(providerName, order), - _ => MockIMetadataProvider, TItemType>(providerName, order) + "ILocalMetadataProvider" => MockIMetadataProvider, TItemType>(providerName, order, forced), + "IRemoteMetadataProvider" => MockIMetadataProvider, TItemType>(providerName, order, forced), + "ICustomMetadataProvider" => MockIMetadataProvider, TItemType>(providerName, order, forced), + _ => MockIMetadataProvider, TItemType>(providerName, order, forced) }; - private static IMetadataProvider MockIMetadataProvider(string name, int? order = null) + private static IMetadataProvider MockIMetadataProvider(string name, int? order = null, bool forced = false) where TProviderType : class, IMetadataProvider where TItemType : BaseItem { + Mock? forcedProvider = null; + if (forced) + { + forcedProvider = new Mock(); + } + Mock? hasOrder = null; if (order != null) { - hasOrder = new Mock(MockBehavior.Strict); + hasOrder = forcedProvider == null ? new Mock() : forcedProvider.As(); hasOrder.Setup(i => i.Order) .Returns((int)order); } @@ -340,7 +381,71 @@ namespace Jellyfin.Providers.Tests.Manager return provider.Object; } - private static ProviderManager GetProviderManager(ServerConfiguration? serverConfiguration = null, LibraryOptions? libraryOptions = null, IBaseItemManager? baseItemManager = null) + private static LibraryOptions CreateLibraryOptions( + string typeName, + string[]? imageFetcherOrder = null, + string[]? localMetadataReaderOrder = null, + string[]? metadataFetcherOrder = null) + { + var libraryOptions = new LibraryOptions + { + LocalMetadataReaderOrder = localMetadataReaderOrder + }; + + // only create type options if populating it with something + if (imageFetcherOrder != null || metadataFetcherOrder != null) + { + imageFetcherOrder ??= Array.Empty(); + metadataFetcherOrder ??= Array.Empty(); + + libraryOptions.TypeOptions = new[] + { + new TypeOptions + { + Type = typeName, + ImageFetcherOrder = imageFetcherOrder, + MetadataFetcherOrder = metadataFetcherOrder + } + }; + } + + return libraryOptions; + } + + private static ServerConfiguration CreateServerConfiguration( + string typeName, + string[]? imageFetcherOrder = null, + string[]? localMetadataReaderOrder = null, + string[]? metadataFetcherOrder = null) + { + var serverConfiguration = new ServerConfiguration(); + + // only create type options if populating it with something + if (imageFetcherOrder != null || localMetadataReaderOrder != null || metadataFetcherOrder != null) + { + imageFetcherOrder ??= Array.Empty(); + localMetadataReaderOrder ??= Array.Empty(); + metadataFetcherOrder ??= Array.Empty(); + + serverConfiguration.MetadataOptions = new[] + { + new MetadataOptions + { + ItemType = typeName, + ImageFetcherOrder = imageFetcherOrder, + LocalMetadataReaderOrder = localMetadataReaderOrder, + MetadataFetcherOrder = metadataFetcherOrder + } + }; + } + + return serverConfiguration; + } + + private static ProviderManager GetProviderManager( + ServerConfiguration? serverConfiguration = null, + LibraryOptions? libraryOptions = null, + IBaseItemManager? baseItemManager = null) { var serverConfigurationManager = new Mock(MockBehavior.Strict); serverConfigurationManager.Setup(i => i.Configuration) @@ -382,11 +487,13 @@ namespace Jellyfin.Providers.Tests.Manager } /// - /// Simple extension to force SupportsLocalMetadata to true. + /// Simple extension to make SupportsLocalMetadata directly settable. /// public class MetadataTestItem : BaseItem, IHasLookupInfo { - public override bool SupportsLocalMetadata => true; + public bool EnableLocalMetadata { get; set; } = true; + + public override bool SupportsLocalMetadata => EnableLocalMetadata; public MetadataTestItemInfo GetLookupInfo() { From a7c009e2eb3e21b7b5c07984866419bb8136423f Mon Sep 17 00:00:00 2001 From: Joe Rogers <1337joe@gmail.com> Date: Sat, 18 Dec 2021 21:40:27 +0100 Subject: [PATCH 012/245] Pass TypeOptions instead of full LibraryOptions --- .../BaseItemManager/BaseItemManager.cs | 14 ++++---- .../BaseItemManager/IBaseItemManager.cs | 8 ++--- .../Manager/ProviderManager.cs | 12 +++---- .../BaseItemManagerTests.cs | 32 +++++++------------ .../Manager/ProviderManagerTests.cs | 6 ++-- 5 files changed, 31 insertions(+), 41 deletions(-) diff --git a/MediaBrowser.Controller/BaseItemManager/BaseItemManager.cs b/MediaBrowser.Controller/BaseItemManager/BaseItemManager.cs index d273b54fc6..61539cae56 100644 --- a/MediaBrowser.Controller/BaseItemManager/BaseItemManager.cs +++ b/MediaBrowser.Controller/BaseItemManager/BaseItemManager.cs @@ -35,7 +35,7 @@ namespace MediaBrowser.Controller.BaseItemManager public SemaphoreSlim MetadataRefreshThrottler { get; private set; } /// - public bool IsMetadataFetcherEnabled(BaseItem baseItem, LibraryOptions libraryOptions, string name) + public bool IsMetadataFetcherEnabled(BaseItem baseItem, TypeOptions? libraryTypeOptions, string name) { if (baseItem is Channel) { @@ -49,10 +49,9 @@ namespace MediaBrowser.Controller.BaseItemManager return !baseItem.EnableMediaSourceDisplay; } - var typeOptions = libraryOptions.GetTypeOptions(baseItem.GetType().Name); - if (typeOptions != null) + if (libraryTypeOptions != null) { - return typeOptions.MetadataFetchers.Contains(name.AsSpan(), StringComparison.OrdinalIgnoreCase); + return libraryTypeOptions.MetadataFetchers.Contains(name.AsSpan(), StringComparison.OrdinalIgnoreCase); } var itemConfig = _serverConfigurationManager.Configuration.MetadataOptions.FirstOrDefault(i => string.Equals(i.ItemType, baseItem.GetType().Name, StringComparison.OrdinalIgnoreCase)); @@ -61,7 +60,7 @@ namespace MediaBrowser.Controller.BaseItemManager } /// - public bool IsImageFetcherEnabled(BaseItem baseItem, LibraryOptions libraryOptions, string name) + public bool IsImageFetcherEnabled(BaseItem baseItem, TypeOptions? libraryTypeOptions, string name) { if (baseItem is Channel) { @@ -75,10 +74,9 @@ namespace MediaBrowser.Controller.BaseItemManager return !baseItem.EnableMediaSourceDisplay; } - var typeOptions = libraryOptions.GetTypeOptions(baseItem.GetType().Name); - if (typeOptions != null) + if (libraryTypeOptions != null) { - return typeOptions.ImageFetchers.Contains(name.AsSpan(), StringComparison.OrdinalIgnoreCase); + return libraryTypeOptions.ImageFetchers.Contains(name.AsSpan(), StringComparison.OrdinalIgnoreCase); } var itemConfig = _serverConfigurationManager.Configuration.MetadataOptions.FirstOrDefault(i => string.Equals(i.ItemType, baseItem.GetType().Name, StringComparison.OrdinalIgnoreCase)); diff --git a/MediaBrowser.Controller/BaseItemManager/IBaseItemManager.cs b/MediaBrowser.Controller/BaseItemManager/IBaseItemManager.cs index e18994214e..b07c80879d 100644 --- a/MediaBrowser.Controller/BaseItemManager/IBaseItemManager.cs +++ b/MediaBrowser.Controller/BaseItemManager/IBaseItemManager.cs @@ -18,18 +18,18 @@ namespace MediaBrowser.Controller.BaseItemManager /// Is metadata fetcher enabled. /// /// The base item. - /// The library options. + /// The type options for baseItem from the library (if defined). /// The metadata fetcher name. /// true if metadata fetcher is enabled, else false. - bool IsMetadataFetcherEnabled(BaseItem baseItem, LibraryOptions libraryOptions, string name); + bool IsMetadataFetcherEnabled(BaseItem baseItem, TypeOptions? libraryTypeOptions, string name); /// /// Is image fetcher enabled. /// /// The base item. - /// The library options. + /// The type options for baseItem from the library (if defined). /// The image fetcher name. /// true if image fetcher is enabled, else false. - bool IsImageFetcherEnabled(BaseItem baseItem, LibraryOptions libraryOptions, string name); + bool IsImageFetcherEnabled(BaseItem baseItem, TypeOptions? libraryTypeOptions, string name); } } diff --git a/MediaBrowser.Providers/Manager/ProviderManager.cs b/MediaBrowser.Providers/Manager/ProviderManager.cs index 82d633e234..d1a5831f98 100644 --- a/MediaBrowser.Providers/Manager/ProviderManager.cs +++ b/MediaBrowser.Providers/Manager/ProviderManager.cs @@ -321,7 +321,7 @@ namespace MediaBrowser.Providers.Manager var typeOptions = libraryOptions.GetTypeOptions(item.GetType().Name); var fetcherOrder = typeOptions?.ImageFetcherOrder ?? options.ImageFetcherOrder; - return _imageProviders.Where(i => CanRefreshImages(i, item, libraryOptions, refreshOptions, includeDisabled)) + return _imageProviders.Where(i => CanRefreshImages(i, item, typeOptions, refreshOptions, includeDisabled)) .OrderBy(i => GetConfiguredOrder(fetcherOrder, i.Name)) .ThenBy(GetDefaultOrder); } @@ -343,7 +343,7 @@ namespace MediaBrowser.Providers.Manager var metadataFetcherOrder = typeOptions?.MetadataFetcherOrder ?? globalMetadataOptions.MetadataFetcherOrder; return _metadataProviders.OfType>() - .Where(i => CanRefreshMetadata(i, item, libraryOptions, includeDisabled, forceEnableInternetMetadata)) + .Where(i => CanRefreshMetadata(i, item, typeOptions, includeDisabled, forceEnableInternetMetadata)) .OrderBy(i => { // local and remote providers will be interleaved in the final order @@ -361,7 +361,7 @@ namespace MediaBrowser.Providers.Manager private bool CanRefreshMetadata( IMetadataProvider provider, BaseItem item, - LibraryOptions libraryOptions, + TypeOptions? libraryTypeOptions, bool includeDisabled, bool forceEnableInternetMetadata) { @@ -375,7 +375,7 @@ namespace MediaBrowser.Providers.Manager if (provider is IRemoteMetadataProvider) { - if (!forceEnableInternetMetadata && !_baseItemManager.IsMetadataFetcherEnabled(item, libraryOptions, provider.Name)) + if (!forceEnableInternetMetadata && !_baseItemManager.IsMetadataFetcherEnabled(item, libraryTypeOptions, provider.Name)) { return false; } @@ -402,7 +402,7 @@ namespace MediaBrowser.Providers.Manager private bool CanRefreshImages( IImageProvider provider, BaseItem item, - LibraryOptions libraryOptions, + TypeOptions? libraryTypeOptions, ImageRefreshOptions refreshOptions, bool includeDisabled) { @@ -419,7 +419,7 @@ namespace MediaBrowser.Providers.Manager if (provider is IRemoteImageProvider || provider is IDynamicImageProvider) { - if (!_baseItemManager.IsImageFetcherEnabled(item, libraryOptions, provider.Name)) + if (!_baseItemManager.IsImageFetcherEnabled(item, libraryTypeOptions, provider.Name)) { return false; } diff --git a/tests/Jellyfin.Controller.Tests/BaseItemManagerTests.cs b/tests/Jellyfin.Controller.Tests/BaseItemManagerTests.cs index 463e17ad36..f67e6d1ef0 100644 --- a/tests/Jellyfin.Controller.Tests/BaseItemManagerTests.cs +++ b/tests/Jellyfin.Controller.Tests/BaseItemManagerTests.cs @@ -20,17 +20,13 @@ namespace Jellyfin.Controller.Tests { BaseItem item = (BaseItem)Activator.CreateInstance(itemType)!; - var libraryOptions = new LibraryOptions - { - TypeOptions = new[] + var libraryTypeOptions = itemType == typeof(Book) + ? new TypeOptions { - new TypeOptions - { - Type = "Book", - MetadataFetchers = new[] { "LibraryEnabled" } - } + Type = "Book", + MetadataFetchers = new[] { "LibraryEnabled" } } - }; + : null; var serverConfiguration = new ServerConfiguration(); foreach (var typeConfig in serverConfiguration.MetadataOptions) @@ -43,7 +39,7 @@ namespace Jellyfin.Controller.Tests .Returns(serverConfiguration); var baseItemManager = new BaseItemManager(serverConfigurationManager.Object); - var actual = baseItemManager.IsMetadataFetcherEnabled(item, libraryOptions, fetcherName); + var actual = baseItemManager.IsMetadataFetcherEnabled(item, libraryTypeOptions, fetcherName); Assert.Equal(expected, actual); } @@ -57,17 +53,13 @@ namespace Jellyfin.Controller.Tests { BaseItem item = (BaseItem)Activator.CreateInstance(itemType)!; - var libraryOptions = new LibraryOptions - { - TypeOptions = new[] + var libraryTypeOptions = itemType == typeof(Book) + ? new TypeOptions { - new TypeOptions - { - Type = "Book", - ImageFetchers = new[] { "LibraryEnabled" } - } + Type = "Book", + ImageFetchers = new[] { "LibraryEnabled" } } - }; + : null; var serverConfiguration = new ServerConfiguration(); foreach (var typeConfig in serverConfiguration.MetadataOptions) @@ -80,7 +72,7 @@ namespace Jellyfin.Controller.Tests .Returns(serverConfiguration); var baseItemManager = new BaseItemManager(serverConfigurationManager.Object); - var actual = baseItemManager.IsImageFetcherEnabled(item, libraryOptions, fetcherName); + var actual = baseItemManager.IsImageFetcherEnabled(item, libraryTypeOptions, fetcherName); Assert.Equal(expected, actual); } diff --git a/tests/Jellyfin.Providers.Tests/Manager/ProviderManagerTests.cs b/tests/Jellyfin.Providers.Tests/Manager/ProviderManagerTests.cs index ba91f5ed2d..560b50f091 100644 --- a/tests/Jellyfin.Providers.Tests/Manager/ProviderManagerTests.cs +++ b/tests/Jellyfin.Providers.Tests/Manager/ProviderManagerTests.cs @@ -131,7 +131,7 @@ namespace Jellyfin.Providers.Tests.Manager }; var baseItemManager = new Mock(MockBehavior.Strict); - baseItemManager.Setup(i => i.IsImageFetcherEnabled(item, It.IsAny(), providerName)) + baseItemManager.Setup(i => i.IsImageFetcherEnabled(item, It.IsAny(), providerName)) .Returns(baseItemEnabled); using var providerManager = GetProviderManager(baseItemManager: baseItemManager.Object); @@ -219,7 +219,7 @@ namespace Jellyfin.Providers.Tests.Manager metadataFetcherOrder: serverRemoteOrder?.Select(nameProvider).ToArray()); var baseItemManager = new Mock(MockBehavior.Strict); - baseItemManager.Setup(i => i.IsMetadataFetcherEnabled(item, It.IsAny(), It.IsAny())) + baseItemManager.Setup(i => i.IsMetadataFetcherEnabled(item, It.IsAny(), It.IsAny())) .Returns(true); using var providerManager = GetProviderManager(serverConfiguration: serverConfiguration, baseItemManager: baseItemManager.Object); @@ -302,7 +302,7 @@ namespace Jellyfin.Providers.Tests.Manager var provider = MockIMetadataProviderMapper(providerType.Name, providerName, forced: providerForced); var baseItemManager = new Mock(MockBehavior.Strict); - baseItemManager.Setup(i => i.IsMetadataFetcherEnabled(item, It.IsAny(), providerName)) + baseItemManager.Setup(i => i.IsMetadataFetcherEnabled(item, It.IsAny(), providerName)) .Returns(baseItemEnabled); using var providerManager = GetProviderManager(baseItemManager: baseItemManager.Object); From 6ab64f4930f61f7f0d0968b88da687a95e0035ad Mon Sep 17 00:00:00 2001 From: Joe Rogers <1337joe@gmail.com> Date: Sun, 19 Dec 2021 23:33:27 +0100 Subject: [PATCH 013/245] Switch to nameof to simplify theory signatures --- .../Manager/ProviderManagerTests.cs | 82 +++++++++---------- 1 file changed, 41 insertions(+), 41 deletions(-) diff --git a/tests/Jellyfin.Providers.Tests/Manager/ProviderManagerTests.cs b/tests/Jellyfin.Providers.Tests/Manager/ProviderManagerTests.cs index 560b50f091..d76d411a78 100644 --- a/tests/Jellyfin.Providers.Tests/Manager/ProviderManagerTests.cs +++ b/tests/Jellyfin.Providers.Tests/Manager/ProviderManagerTests.cs @@ -77,32 +77,32 @@ namespace Jellyfin.Providers.Tests.Manager [InlineData(true, true, false)] public void GetImageProviders_CanRefreshImagesBasic_WhenSupportsWithoutError(bool supports, bool errorOnSupported, bool expected) { - GetImageProviders_CanRefreshImages_Tester(typeof(IImageProvider), supports, expected, errorOnSupported: errorOnSupported); + GetImageProviders_CanRefreshImages_Tester(nameof(IImageProvider), supports, expected, errorOnSupported: errorOnSupported); } [Theory] - [InlineData(typeof(ILocalImageProvider), false, true)] - [InlineData(typeof(ILocalImageProvider), true, true)] - [InlineData(typeof(IImageProvider), false, false)] - [InlineData(typeof(IImageProvider), true, true)] - public void GetImageProviders_CanRefreshImagesLocked_WhenLocalOrFullRefresh(Type providerType, bool fullRefresh, bool expected) + [InlineData(nameof(ILocalImageProvider), false, true)] + [InlineData(nameof(ILocalImageProvider), true, true)] + [InlineData(nameof(IImageProvider), false, false)] + [InlineData(nameof(IImageProvider), true, true)] + public void GetImageProviders_CanRefreshImagesLocked_WhenLocalOrFullRefresh(string providerType, bool fullRefresh, bool expected) { GetImageProviders_CanRefreshImages_Tester(providerType, true, expected, itemLocked: true, fullRefresh: fullRefresh); } [Theory] - [InlineData(typeof(ILocalImageProvider), false, true)] - [InlineData(typeof(IRemoteImageProvider), true, true)] - [InlineData(typeof(IDynamicImageProvider), true, true)] - [InlineData(typeof(IRemoteImageProvider), false, false)] - [InlineData(typeof(IDynamicImageProvider), false, false)] - public void GetImageProviders_CanRefreshImagesBaseItemEnabled_WhenLocalOrEnabled(Type providerType, bool enabled, bool expected) + [InlineData(nameof(ILocalImageProvider), false, true)] + [InlineData(nameof(IRemoteImageProvider), true, true)] + [InlineData(nameof(IDynamicImageProvider), true, true)] + [InlineData(nameof(IRemoteImageProvider), false, false)] + [InlineData(nameof(IDynamicImageProvider), false, false)] + public void GetImageProviders_CanRefreshImagesBaseItemEnabled_WhenLocalOrEnabled(string providerType, bool enabled, bool expected) { GetImageProviders_CanRefreshImages_Tester(providerType, true, expected, baseItemEnabled: enabled); } private static void GetImageProviders_CanRefreshImages_Tester( - Type providerType, + string providerType, bool supports, bool expected, bool errorOnSupported = false, @@ -116,7 +116,7 @@ namespace Jellyfin.Providers.Tests.Manager }; var providerName = "provider"; - IImageProvider provider = providerType.Name switch + IImageProvider provider = providerType switch { "IImageProvider" => MockIImageProvider(providerName, item, supports: supports, errorOnSupported: errorOnSupported), "ILocalImageProvider" => MockIImageProvider(providerName, item, supports: supports, errorOnSupported: errorOnSupported), @@ -233,57 +233,57 @@ namespace Jellyfin.Providers.Tests.Manager } [Theory] - [InlineData(typeof(IMetadataProvider))] - [InlineData(typeof(ILocalMetadataProvider))] - [InlineData(typeof(IRemoteMetadataProvider))] - [InlineData(typeof(ICustomMetadataProvider))] - public void GetMetadataProviders_CanRefreshMetadataBasic_ReturnsTrue(Type providerType) + [InlineData(nameof(IMetadataProvider))] + [InlineData(nameof(ILocalMetadataProvider))] + [InlineData(nameof(IRemoteMetadataProvider))] + [InlineData(nameof(ICustomMetadataProvider))] + public void GetMetadataProviders_CanRefreshMetadataBasic_ReturnsTrue(string providerType) { GetMetadataProviders_CanRefreshMetadata_Tester(providerType, true); } [Theory] - [InlineData(typeof(ILocalMetadataProvider), false, true)] - [InlineData(typeof(IRemoteMetadataProvider), false, false)] - [InlineData(typeof(ICustomMetadataProvider), false, false)] - [InlineData(typeof(ILocalMetadataProvider), true, true)] - [InlineData(typeof(ICustomMetadataProvider), true, false)] - public void GetMetadataProviders_CanRefreshMetadataLocked_WhenLocalOrForced(Type providerType, bool forced, bool expected) + [InlineData(nameof(ILocalMetadataProvider), false, true)] + [InlineData(nameof(IRemoteMetadataProvider), false, false)] + [InlineData(nameof(ICustomMetadataProvider), false, false)] + [InlineData(nameof(ILocalMetadataProvider), true, true)] + [InlineData(nameof(ICustomMetadataProvider), true, false)] + public void GetMetadataProviders_CanRefreshMetadataLocked_WhenLocalOrForced(string providerType, bool forced, bool expected) { GetMetadataProviders_CanRefreshMetadata_Tester(providerType, expected, itemLocked: true, providerForced: forced); } [Theory] - [InlineData(typeof(ILocalMetadataProvider), false, true)] - [InlineData(typeof(ICustomMetadataProvider), false, true)] - [InlineData(typeof(IRemoteMetadataProvider), false, false)] - [InlineData(typeof(IRemoteMetadataProvider), true, true)] - public void GetMetadataProviders_CanRefreshMetadataBaseItemEnabled_WhenEnabledOrNotRemote(Type providerType, bool baseItemEnabled, bool expected) + [InlineData(nameof(ILocalMetadataProvider), false, true)] + [InlineData(nameof(ICustomMetadataProvider), false, true)] + [InlineData(nameof(IRemoteMetadataProvider), false, false)] + [InlineData(nameof(IRemoteMetadataProvider), true, true)] + public void GetMetadataProviders_CanRefreshMetadataBaseItemEnabled_WhenEnabledOrNotRemote(string providerType, bool baseItemEnabled, bool expected) { GetMetadataProviders_CanRefreshMetadata_Tester(providerType, expected, baseItemEnabled: baseItemEnabled); } [Theory] - [InlineData(typeof(IRemoteMetadataProvider), false, true)] - [InlineData(typeof(ICustomMetadataProvider), false, true)] - [InlineData(typeof(ILocalMetadataProvider), false, false)] - [InlineData(typeof(ILocalMetadataProvider), true, true)] - public void GetMetadataProviders_CanRefreshMetadataSupportsLocal_WhenSupportsOrNotLocal(Type providerType, bool supportsLocalMetadata, bool expected) + [InlineData(nameof(IRemoteMetadataProvider), false, true)] + [InlineData(nameof(ICustomMetadataProvider), false, true)] + [InlineData(nameof(ILocalMetadataProvider), false, false)] + [InlineData(nameof(ILocalMetadataProvider), true, true)] + public void GetMetadataProviders_CanRefreshMetadataSupportsLocal_WhenSupportsOrNotLocal(string providerType, bool supportsLocalMetadata, bool expected) { GetMetadataProviders_CanRefreshMetadata_Tester(providerType, expected, supportsLocalMetadata: supportsLocalMetadata); } [Theory] - [InlineData(typeof(ICustomMetadataProvider), true)] - [InlineData(typeof(IRemoteMetadataProvider), false)] - [InlineData(typeof(ILocalMetadataProvider), false)] - public void GetMetadataProviders_CanRefreshMetadataOwned_WhenNotLocal(Type providerType, bool expected) + [InlineData(nameof(ICustomMetadataProvider), true)] + [InlineData(nameof(IRemoteMetadataProvider), false)] + [InlineData(nameof(ILocalMetadataProvider), false)] + public void GetMetadataProviders_CanRefreshMetadataOwned_WhenNotLocal(string providerType, bool expected) { GetMetadataProviders_CanRefreshMetadata_Tester(providerType, expected, ownedItem: true); } private static void GetMetadataProviders_CanRefreshMetadata_Tester( - Type providerType, + string providerType, bool expected, bool itemLocked = false, bool baseItemEnabled = true, @@ -299,7 +299,7 @@ namespace Jellyfin.Providers.Tests.Manager }; var providerName = "provider"; - var provider = MockIMetadataProviderMapper(providerType.Name, providerName, forced: providerForced); + var provider = MockIMetadataProviderMapper(providerType, providerName, forced: providerForced); var baseItemManager = new Mock(MockBehavior.Strict); baseItemManager.Setup(i => i.IsMetadataFetcherEnabled(item, It.IsAny(), providerName)) From bdce435b09b88329dd7f23ff5f4e9bb7998763b5 Mon Sep 17 00:00:00 2001 From: Joe Rogers <1337joe@gmail.com> Date: Sat, 18 Dec 2021 22:30:06 +0100 Subject: [PATCH 014/245] Reorder and flatten provider filtering --- .../Manager/ProviderManager.cs | 115 ++++++++---------- .../Manager/ProviderManagerTests.cs | 4 +- 2 files changed, 55 insertions(+), 64 deletions(-) diff --git a/MediaBrowser.Providers/Manager/ProviderManager.cs b/MediaBrowser.Providers/Manager/ProviderManager.cs index d1a5831f98..e2882ee06e 100644 --- a/MediaBrowser.Providers/Manager/ProviderManager.cs +++ b/MediaBrowser.Providers/Manager/ProviderManager.cs @@ -326,6 +326,39 @@ namespace MediaBrowser.Providers.Manager .ThenBy(GetDefaultOrder); } + private bool CanRefreshImages( + IImageProvider provider, + BaseItem item, + TypeOptions? libraryTypeOptions, + ImageRefreshOptions refreshOptions, + bool includeDisabled) + { + try + { + if (!provider.Supports(item)) + { + return false; + } + } + catch (Exception ex) + { + _logger.LogError(ex, "{ProviderName} failed in Supports for type {ItemType} at {ItemPath}", provider.GetType().Name, item.GetType().Name, item.Path); + return false; + } + + if (includeDisabled || provider is ILocalImageProvider) + { + return true; + } + + if (item.IsLocked && refreshOptions.ImageRefreshMode != MetadataRefreshMode.FullRefresh) + { + return false; + } + + return _baseItemManager.IsImageFetcherEnabled(item, libraryTypeOptions, provider.Name); + } + /// public IEnumerable> GetMetadataProviders(BaseItem item, LibraryOptions libraryOptions) where T : BaseItem @@ -365,76 +398,34 @@ namespace MediaBrowser.Providers.Manager bool includeDisabled, bool forceEnableInternetMetadata) { - if (!includeDisabled) - { - // If locked only allow local providers - if (item.IsLocked && provider is not ILocalMetadataProvider && provider is not IForcedProvider) - { - return false; - } - - if (provider is IRemoteMetadataProvider) - { - if (!forceEnableInternetMetadata && !_baseItemManager.IsMetadataFetcherEnabled(item, libraryTypeOptions, provider.Name)) - { - return false; - } - } - } - if (!item.SupportsLocalMetadata && provider is ILocalMetadataProvider) { return false; } - // If this restriction is ever lifted, movie xml providers will have to be updated to prevent owned items like trailers from reading those files - if (!item.OwnerId.Equals(default)) + // Prevent owned items from reading the same local metadata file as their owner + if (!item.OwnerId.Equals(default) && provider is ILocalMetadataProvider) { - if (provider is ILocalMetadataProvider || provider is IRemoteMetadataProvider) - { - return false; - } - } - - return true; - } - - private bool CanRefreshImages( - IImageProvider provider, - BaseItem item, - TypeOptions? libraryTypeOptions, - ImageRefreshOptions refreshOptions, - bool includeDisabled) - { - if (!includeDisabled) - { - // If locked only allow local providers - if (item.IsLocked && provider is not ILocalImageProvider) - { - if (refreshOptions.ImageRefreshMode != MetadataRefreshMode.FullRefresh) - { - return false; - } - } - - if (provider is IRemoteImageProvider || provider is IDynamicImageProvider) - { - if (!_baseItemManager.IsImageFetcherEnabled(item, libraryTypeOptions, provider.Name)) - { - return false; - } - } - } - - try - { - return provider.Supports(item); - } - catch (Exception ex) - { - _logger.LogError(ex, "{ProviderName} failed in Supports for type {ItemType} at {ItemPath}", provider.GetType().Name, item.GetType().Name, item.Path); return false; } + + if (includeDisabled) + { + return true; + } + + // If locked only allow local providers + if (item.IsLocked && provider is not ILocalMetadataProvider && provider is not IForcedProvider) + { + return false; + } + + if (forceEnableInternetMetadata || provider is not IRemoteMetadataProvider) + { + return true; + } + + return _baseItemManager.IsMetadataFetcherEnabled(item, libraryTypeOptions, provider.Name); } private static int GetConfiguredOrder(string[] order, string providerName) diff --git a/tests/Jellyfin.Providers.Tests/Manager/ProviderManagerTests.cs b/tests/Jellyfin.Providers.Tests/Manager/ProviderManagerTests.cs index d76d411a78..8100dcfa6f 100644 --- a/tests/Jellyfin.Providers.Tests/Manager/ProviderManagerTests.cs +++ b/tests/Jellyfin.Providers.Tests/Manager/ProviderManagerTests.cs @@ -54,7 +54,7 @@ namespace Jellyfin.Providers.Tests.Manager for (var i = 0; i < providerCount; i++) { var order = hasOrderOrder?[i]; - providerList.Add(MockIImageProvider(nameProvider(i), item, order: order)); + providerList.Add(MockIImageProvider(nameProvider(i), item, order: order)); } var libraryOptions = CreateLibraryOptions(item.GetType().Name, imageFetcherOrder: libraryOrder?.Select(nameProvider).ToArray()); @@ -275,7 +275,7 @@ namespace Jellyfin.Providers.Tests.Manager [Theory] [InlineData(nameof(ICustomMetadataProvider), true)] - [InlineData(nameof(IRemoteMetadataProvider), false)] + [InlineData(nameof(IRemoteMetadataProvider), true)] [InlineData(nameof(ILocalMetadataProvider), false)] public void GetMetadataProviders_CanRefreshMetadataOwned_WhenNotLocal(string providerType, bool expected) { From ee5bd0daa62e68f4f93e7603017c1f028781e387 Mon Sep 17 00:00:00 2001 From: Joe Rogers <1337joe@gmail.com> Date: Tue, 21 Dec 2021 00:24:07 +0100 Subject: [PATCH 015/245] Implement tests on ProviderManager.RefreshSingleItem --- .../Providers/IMetadataService.cs | 5 + .../Manager/ProviderManagerTests.cs | 110 +++++++++++++++++- 2 files changed, 113 insertions(+), 2 deletions(-) diff --git a/MediaBrowser.Controller/Providers/IMetadataService.cs b/MediaBrowser.Controller/Providers/IMetadataService.cs index 05fbb18ee4..f0f1d18624 100644 --- a/MediaBrowser.Controller/Providers/IMetadataService.cs +++ b/MediaBrowser.Controller/Providers/IMetadataService.cs @@ -23,6 +23,11 @@ namespace MediaBrowser.Controller.Providers /// true if this instance can refresh the specified item. bool CanRefresh(BaseItem item); + /// + /// Determines whether this instance primarily targets the specified type. + /// + /// The type. + /// true if this instance primarily targets the specified type. bool CanRefreshPrimary(Type type); /// diff --git a/tests/Jellyfin.Providers.Tests/Manager/ProviderManagerTests.cs b/tests/Jellyfin.Providers.Tests/Manager/ProviderManagerTests.cs index 8100dcfa6f..5845b31be8 100644 --- a/tests/Jellyfin.Providers.Tests/Manager/ProviderManagerTests.cs +++ b/tests/Jellyfin.Providers.Tests/Manager/ProviderManagerTests.cs @@ -1,6 +1,8 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Threading; +using System.Threading.Tasks; using MediaBrowser.Controller.BaseItemManager; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; @@ -9,6 +11,7 @@ using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Configuration; using MediaBrowser.Providers.Manager; +using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; using Moq; using Xunit; @@ -17,6 +20,95 @@ namespace Jellyfin.Providers.Tests.Manager { public class ProviderManagerTests { + private static readonly ILogger _logger = new NullLogger(); + + private static TheoryData[], int> RefreshSingleItemOrderData() + => new () + { + // no order set, uses provided order + { + new[] + { + MockIMetadataService(true, true), + MockIMetadataService(true, true) + }, + 0 + }, + // sort order sets priority when all match + { + new[] + { + MockIMetadataService(true, true, 1), + MockIMetadataService(true, true, 0), + MockIMetadataService(true, true, 2) + }, + 1 + }, + // CanRefreshPrimary prioritized + { + new[] + { + MockIMetadataService(false, true), + MockIMetadataService(true, true), + }, + 1 + }, + // falls back to CanRefresh + { + new[] + { + MockIMetadataService(false, false), + MockIMetadataService(false, true) + }, + 1 + }, + }; + + [Theory] + [MemberData(nameof(RefreshSingleItemOrderData))] + public void RefreshSingleItem_ServiceOrdering_FollowsPriority(Mock[] servicesList, int expectedIndex) + { + var item = new Movie(); + + using var providerManager = GetProviderManager(); + AddParts(providerManager, metadataServices: servicesList.Select(s => s.Object).ToArray()); + + var refreshOptions = new MetadataRefreshOptions(Mock.Of(MockBehavior.Strict)); + var actual = providerManager.RefreshSingleItem(item, refreshOptions, CancellationToken.None); + + Assert.Equal(ItemUpdateType.MetadataDownload, actual.Result); + for (var i = 0; i < servicesList.Length; i++) + { + if (i == expectedIndex) + { + servicesList[i].Verify(mock => mock.RefreshMetadata(It.IsAny(), It.IsAny(), It.IsAny()), Times.Once()); + } + else + { + servicesList[i].Verify(mock => mock.RefreshMetadata(It.IsAny(), It.IsAny(), It.IsAny()), Times.Never()); + } + } + } + + [Theory] + [InlineData(true)] + [InlineData(false)] + public void RefreshSingleItem_RefreshMetadata_WhenServiceFound(bool serviceFound) + { + var item = new Movie(); + + var servicesList = new[] { MockIMetadataService(false, serviceFound) }; + + using var providerManager = GetProviderManager(); + AddParts(providerManager, metadataServices: servicesList.Select(s => s.Object).ToArray()); + + var refreshOptions = new MetadataRefreshOptions(Mock.Of(MockBehavior.Strict)); + var actual = providerManager.RefreshSingleItem(item, refreshOptions, CancellationToken.None); + + var expectedResult = serviceFound ? ItemUpdateType.MetadataDownload : ItemUpdateType.None; + Assert.Equal(expectedResult, actual.Result); + } + private static TheoryData GetImageProvidersOrderData() => new () { @@ -313,6 +405,20 @@ namespace Jellyfin.Providers.Tests.Manager Assert.Equal(expected ? 1 : 0, actualProviders.Length); } + private static Mock MockIMetadataService(bool refreshPrimary, bool canRefresh, int order = 0) + { + var service = new Mock(MockBehavior.Strict); + service.Setup(s => s.Order) + .Returns(order); + service.Setup(s => s.CanRefreshPrimary(It.IsAny())) + .Returns(refreshPrimary); + service.Setup(s => s.CanRefresh(It.IsAny())) + .Returns(canRefresh); + service.Setup(s => s.RefreshMetadata(It.IsAny(), It.IsAny(), It.IsAny())) + .Returns(Task.FromResult(ItemUpdateType.MetadataDownload)); + return service; + } + private static IImageProvider MockIImageProvider(string name, BaseItem expectedType, bool supports = true, int? order = null, bool errorOnSupported = false) where TProviderType : class, IImageProvider { @@ -460,11 +566,11 @@ namespace Jellyfin.Providers.Tests.Manager null, serverConfigurationManager.Object, null, - new NullLogger(), + _logger, null, null, libraryManager.Object, - baseItemManager); + baseItemManager!); return providerManager; } From ac675318f858e1be6e156e6d9d217cb662ba5c31 Mon Sep 17 00:00:00 2001 From: Joe Rogers <1337joe@gmail.com> Date: Tue, 21 Dec 2021 00:25:35 +0100 Subject: [PATCH 016/245] Simplify RefreshSingleItem --- .../Manager/ProviderManager.cs | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/MediaBrowser.Providers/Manager/ProviderManager.cs b/MediaBrowser.Providers/Manager/ProviderManager.cs index e2882ee06e..135b69a95b 100644 --- a/MediaBrowser.Providers/Manager/ProviderManager.cs +++ b/MediaBrowser.Providers/Manager/ProviderManager.cs @@ -132,26 +132,15 @@ namespace MediaBrowser.Providers.Manager var type = item.GetType(); var service = _metadataServices.FirstOrDefault(current => current.CanRefreshPrimary(type)); + service ??= _metadataServices.FirstOrDefault(current => current.CanRefresh(item)); if (service == null) { - foreach (var current in _metadataServices) - { - if (current.CanRefresh(item)) - { - service = current; - break; - } - } + _logger.LogError("Unable to find a metadata service for item of type {TypeName}", item.GetType().Name); + return Task.FromResult(ItemUpdateType.None); } - if (service != null) - { - return service.RefreshMetadata(item, options, cancellationToken); - } - - _logger.LogError("Unable to find a metadata service for item of type {TypeName}", item.GetType().Name); - return Task.FromResult(ItemUpdateType.None); + return service.RefreshMetadata(item, options, cancellationToken); } /// From 6e4710d048767292ec027a4992ad3448d826e42e Mon Sep 17 00:00:00 2001 From: Joe Rogers <1337joe@users.noreply.github.com> Date: Fri, 24 Dec 2021 09:50:58 +0100 Subject: [PATCH 017/245] Fix review comment Co-authored-by: Cody Robibero --- MediaBrowser.Providers/Manager/ProviderManager.cs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/MediaBrowser.Providers/Manager/ProviderManager.cs b/MediaBrowser.Providers/Manager/ProviderManager.cs index 135b69a95b..9be4bc479b 100644 --- a/MediaBrowser.Providers/Manager/ProviderManager.cs +++ b/MediaBrowser.Providers/Manager/ProviderManager.cs @@ -367,16 +367,15 @@ namespace MediaBrowser.Providers.Manager return _metadataProviders.OfType>() .Where(i => CanRefreshMetadata(i, item, typeOptions, includeDisabled, forceEnableInternetMetadata)) .OrderBy(i => - { // local and remote providers will be interleaved in the final order // only relative order within a type matters: consumers of the list filter to one or the other - switch (i) + i switch { - case ILocalMetadataProvider: return GetConfiguredOrder(localMetadataReaderOrder, i.Name); - case IRemoteMetadataProvider: return GetConfiguredOrder(metadataFetcherOrder, i.Name); - default: return int.MaxValue; // default to end - } - }) + ILocalMetadataProvider => GetConfiguredOrder(localMetadataReaderOrder, i.Name), + IRemoteMetadataProvider => GetConfiguredOrder(metadataFetcherOrder, i.Name), + // Default to end + _ => int.MaxValue + }) .ThenBy(GetDefaultOrder); } From b03f56c3d6e005b615780bcdc676bcd632e80395 Mon Sep 17 00:00:00 2001 From: Joe Rogers <1337joe@gmail.com> Date: Sat, 1 Jan 2022 00:22:46 +0100 Subject: [PATCH 018/245] Remove warnings --- .../Manager/ProviderManager.cs | 26 +++++++++------- .../Manager/ProviderManagerTests.cs | 30 +++++++++++-------- 2 files changed, 33 insertions(+), 23 deletions(-) diff --git a/MediaBrowser.Providers/Manager/ProviderManager.cs b/MediaBrowser.Providers/Manager/ProviderManager.cs index 9be4bc479b..eb4bc3587f 100644 --- a/MediaBrowser.Providers/Manager/ProviderManager.cs +++ b/MediaBrowser.Providers/Manager/ProviderManager.cs @@ -45,7 +45,7 @@ namespace MediaBrowser.Providers.Manager /// public class ProviderManager : IProviderManager, IDisposable { - private readonly object _refreshQueueLock = new (); + private readonly object _refreshQueueLock = new(); private readonly ILogger _logger; private readonly IHttpClientFactory _httpClientFactory; private readonly ILibraryMonitor _libraryMonitor; @@ -55,9 +55,9 @@ namespace MediaBrowser.Providers.Manager private readonly ISubtitleManager _subtitleManager; private readonly IServerConfigurationManager _configurationManager; private readonly IBaseItemManager _baseItemManager; - private readonly ConcurrentDictionary _activeRefreshes = new (); - private readonly CancellationTokenSource _disposeCancellationTokenSource = new (); - private readonly SimplePriorityQueue> _refreshQueue = new (); + private readonly ConcurrentDictionary _activeRefreshes = new(); + private readonly CancellationTokenSource _disposeCancellationTokenSource = new(); + private readonly SimplePriorityQueue> _refreshQueue = new(); private IImageProvider[] _imageProviders = Array.Empty(); private IMetadataService[] _metadataServices = Array.Empty(); @@ -164,6 +164,10 @@ namespace MediaBrowser.Providers.Manager { contentType = "image/png"; } + else + { + throw new HttpRequestException("Invalid image received: contentType not set.", null, response.StatusCode); + } } // thetvdb will sometimes serve a rubbish 404 html page with a 200 OK code, because reasons... @@ -589,7 +593,7 @@ namespace MediaBrowser.Providers.Manager foreach (var saver in savers.Where(i => IsSaverEnabledForItem(i, item, libraryOptions, updateType, false))) { - _logger.LogDebug("Saving {0} to {1}.", item.Path ?? item.Name, saver.Name); + _logger.LogDebug("Saving {Item} to {Saver}", item.Path ?? item.Name, saver.Name); if (saver is IMetadataFileSaver fileSaver) { @@ -601,7 +605,7 @@ namespace MediaBrowser.Providers.Manager } catch (Exception ex) { - _logger.LogError(ex, "Error in {0} GetSavePath", saver.Name); + _logger.LogError(ex, "Error in {Saver} GetSavePath", saver.Name); continue; } @@ -688,7 +692,7 @@ namespace MediaBrowser.Providers.Manager } catch (Exception ex) { - _logger.LogError(ex, "Error in {0}.IsEnabledFor", saver.Name); + _logger.LogError(ex, "Error in {Saver}.IsEnabledFor", saver.Name); return false; } } @@ -838,7 +842,7 @@ namespace MediaBrowser.Providers.Manager } catch (Exception ex) { - _logger.LogError(ex, "Error in {0}.Supports", i.GetType().Name); + _logger.LogError(ex, "Error in {Type}.Supports", i.GetType().Name); return false; } }); @@ -904,7 +908,7 @@ namespace MediaBrowser.Providers.Manager /// public void OnRefreshStart(BaseItem item) { - _logger.LogDebug("OnRefreshStart {0}", item.Id.ToString("N", CultureInfo.InvariantCulture)); + _logger.LogDebug("OnRefreshStart {Item}", item.Id.ToString("N", CultureInfo.InvariantCulture)); _activeRefreshes[item.Id] = 0; RefreshStarted?.Invoke(this, new GenericEventArgs(item)); } @@ -912,7 +916,7 @@ namespace MediaBrowser.Providers.Manager /// public void OnRefreshComplete(BaseItem item) { - _logger.LogDebug("OnRefreshComplete {0}", item.Id.ToString("N", CultureInfo.InvariantCulture)); + _logger.LogDebug("OnRefreshComplete {Item}", item.Id.ToString("N", CultureInfo.InvariantCulture)); _activeRefreshes.Remove(item.Id, out _); @@ -934,7 +938,7 @@ namespace MediaBrowser.Providers.Manager public void OnRefreshProgress(BaseItem item, double progress) { var id = item.Id; - _logger.LogDebug("OnRefreshProgress {0} {1}", id.ToString("N", CultureInfo.InvariantCulture), progress); + _logger.LogDebug("OnRefreshProgress {Id} {Progress}", id.ToString("N", CultureInfo.InvariantCulture), progress); // TODO: Need to hunt down the conditions for this happening _activeRefreshes.AddOrUpdate( diff --git a/tests/Jellyfin.Providers.Tests/Manager/ProviderManagerTests.cs b/tests/Jellyfin.Providers.Tests/Manager/ProviderManagerTests.cs index 5845b31be8..6179e31359 100644 --- a/tests/Jellyfin.Providers.Tests/Manager/ProviderManagerTests.cs +++ b/tests/Jellyfin.Providers.Tests/Manager/ProviderManagerTests.cs @@ -1,21 +1,29 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Net.Http; +using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; +using MediaBrowser.Controller; using MediaBrowser.Controller.BaseItemManager; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Providers; +using MediaBrowser.Controller.Subtitles; using MediaBrowser.Model.Configuration; +using MediaBrowser.Model.IO; using MediaBrowser.Providers.Manager; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; using Moq; using Xunit; +// Allow Moq to see internal class +[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")] + namespace Jellyfin.Providers.Tests.Manager { public class ProviderManagerTests @@ -23,7 +31,7 @@ namespace Jellyfin.Providers.Tests.Manager private static readonly ILogger _logger = new NullLogger(); private static TheoryData[], int> RefreshSingleItemOrderData() - => new () + => new() { // no order set, uses provided order { @@ -110,7 +118,7 @@ namespace Jellyfin.Providers.Tests.Manager } private static TheoryData GetImageProvidersOrderData() - => new () + => new() { { 3, null, null, null, new[] { 0, 1, 2 } }, // no order options set @@ -238,7 +246,7 @@ namespace Jellyfin.Providers.Tests.Manager { var l = nameof(ILocalMetadataProvider); var r = nameof(IRemoteMetadataProvider); - return new () + return new() { { new[] { l, l, r, r }, null, null, null, null, null, new[] { 0, 1, 2, 3 } }, // no order options set @@ -269,8 +277,6 @@ namespace Jellyfin.Providers.Tests.Manager // IHasOrder ordering (not interleaved, doesn't care about types) { new[] { l, l, r, r }, null, null, null, null, new int?[] { 2, null, 1, null }, new[] { 2, 0, 1, 3 } }, // partially defined { new[] { l, l, r, r }, null, null, null, null, new int?[] { 3, 2, 1, 0 }, new[] { 3, 2, 1, 0 } }, // full reverse order - // note odd interaction - orderby determines order of slot when local and remote both have a slot 0 - { new[] { l, l, r, r }, new[] { 1 }, new[] { 3 }, null, null, new int?[] { null, 2, null, 1 }, new[] { 3, 1, 0, 2 } }, // sorts interleaved results // multiple orders set { new[] { l, l, l, r, r, r }, new[] { 1 }, new[] { 4 }, new[] { 2, 1, 0 }, new[] { 5, 4, 3 }, null, new[] { 1, 4, 0, 2, 3, 5 } }, // partial library order first, server order ignored @@ -562,13 +568,13 @@ namespace Jellyfin.Providers.Tests.Manager .Returns(libraryOptions ?? new LibraryOptions()); var providerManager = new ProviderManager( - null, - null, + Mock.Of(), + Mock.Of(), serverConfigurationManager.Object, - null, + Mock.Of(), _logger, - null, - null, + Mock.Of(), + Mock.Of(), libraryManager.Object, baseItemManager!); @@ -595,7 +601,7 @@ namespace Jellyfin.Providers.Tests.Manager /// /// Simple extension to make SupportsLocalMetadata directly settable. /// - public class MetadataTestItem : BaseItem, IHasLookupInfo + internal class MetadataTestItem : BaseItem, IHasLookupInfo { public bool EnableLocalMetadata { get; set; } = true; @@ -607,7 +613,7 @@ namespace Jellyfin.Providers.Tests.Manager } } - public class MetadataTestItemInfo : ItemLookupInfo + internal class MetadataTestItemInfo : ItemLookupInfo { } } From 6bf71c0fd355e9c95a1e142019d9bc5cce34200d Mon Sep 17 00:00:00 2001 From: Joe Rogers <1337joe@users.noreply.github.com> Date: Sun, 16 Jan 2022 14:18:44 +0100 Subject: [PATCH 019/245] Combine verify calls Co-authored-by: Claus Vium --- .../Manager/ProviderManagerTests.cs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/tests/Jellyfin.Providers.Tests/Manager/ProviderManagerTests.cs b/tests/Jellyfin.Providers.Tests/Manager/ProviderManagerTests.cs index 6179e31359..a5673ad838 100644 --- a/tests/Jellyfin.Providers.Tests/Manager/ProviderManagerTests.cs +++ b/tests/Jellyfin.Providers.Tests/Manager/ProviderManagerTests.cs @@ -87,14 +87,8 @@ namespace Jellyfin.Providers.Tests.Manager Assert.Equal(ItemUpdateType.MetadataDownload, actual.Result); for (var i = 0; i < servicesList.Length; i++) { - if (i == expectedIndex) - { - servicesList[i].Verify(mock => mock.RefreshMetadata(It.IsAny(), It.IsAny(), It.IsAny()), Times.Once()); - } - else - { - servicesList[i].Verify(mock => mock.RefreshMetadata(It.IsAny(), It.IsAny(), It.IsAny()), Times.Never()); - } + var times = i == expectedIndex ? Times.Once() : Times.Never(); + servicesList[i].Verify(mock => mock.RefreshMetadata(It.IsAny(), It.IsAny(), It.IsAny()), times); } } From 72893da4d8fe90fd8e5c94a4a337c8d154751f42 Mon Sep 17 00:00:00 2001 From: adrez99 Date: Thu, 2 Jun 2022 22:32:15 +0200 Subject: [PATCH 020/245] Use System.IO.Compression instead of SharpCompress for gzips --- .../ApplicationHost.cs | 3 - .../Archiving/ZipClient.cs | 46 ------- .../Emby.Server.Implementations.csproj | 1 - .../LiveTv/Listings/XmlTvListingsProvider.cs | 113 +++++------------- MediaBrowser.Model/IO/IZipClient.cs | 16 --- 5 files changed, 33 insertions(+), 146 deletions(-) delete mode 100644 Emby.Server.Implementations/Archiving/ZipClient.cs delete mode 100644 MediaBrowser.Model/IO/IZipClient.cs diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index 82294644b8..e05f13d053 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -22,7 +22,6 @@ using Emby.Drawing; using Emby.Naming.Common; using Emby.Notifications; using Emby.Photos; -using Emby.Server.Implementations.Archiving; using Emby.Server.Implementations.Channels; using Emby.Server.Implementations.Collections; using Emby.Server.Implementations.Configuration; @@ -558,8 +557,6 @@ namespace Emby.Server.Implementations serviceCollection.AddSingleton(); - serviceCollection.AddSingleton(); - serviceCollection.AddSingleton(this); serviceCollection.AddSingleton(ApplicationPaths); diff --git a/Emby.Server.Implementations/Archiving/ZipClient.cs b/Emby.Server.Implementations/Archiving/ZipClient.cs deleted file mode 100644 index 6a3b250d25..0000000000 --- a/Emby.Server.Implementations/Archiving/ZipClient.cs +++ /dev/null @@ -1,46 +0,0 @@ -using System.IO; -using MediaBrowser.Model.IO; -using SharpCompress.Common; -using SharpCompress.Readers; -using SharpCompress.Readers.GZip; - -namespace Emby.Server.Implementations.Archiving -{ - /// - /// Class DotNetZipClient. - /// - public class ZipClient : IZipClient - { - /// - public void ExtractAllFromGz(Stream source, string targetPath, bool overwriteExistingFiles) - { - using var reader = GZipReader.Open(source); - var options = new ExtractionOptions - { - ExtractFullPath = true, - Overwrite = overwriteExistingFiles - }; - - Directory.CreateDirectory(targetPath); - reader.WriteAllToDirectory(targetPath, options); - } - - /// - public void ExtractFirstFileFromGz(Stream source, string targetPath, string defaultFileName) - { - using var reader = GZipReader.Open(source); - if (reader.MoveToNextEntry()) - { - var entry = reader.Entry; - - var filename = entry.Key; - if (string.IsNullOrWhiteSpace(filename)) - { - filename = defaultFileName; - } - - reader.WriteEntryToFile(Path.Combine(targetPath, filename)); - } - } - } -} diff --git a/Emby.Server.Implementations/Emby.Server.Implementations.csproj b/Emby.Server.Implementations/Emby.Server.Implementations.csproj index 161c696420..ff037f21bc 100644 --- a/Emby.Server.Implementations/Emby.Server.Implementations.csproj +++ b/Emby.Server.Implementations/Emby.Server.Implementations.csproj @@ -32,7 +32,6 @@ - diff --git a/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs b/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs index bd1cd1e1de..10f7e5cc86 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs @@ -6,9 +6,9 @@ using System; using System.Collections.Generic; using System.Globalization; using System.IO; +using System.IO.Compression; using System.Linq; using System.Net.Http; -using System.Security.Cryptography; using System.Threading; using System.Threading.Tasks; using Jellyfin.Extensions; @@ -33,20 +33,17 @@ namespace Emby.Server.Implementations.LiveTv.Listings private readonly IHttpClientFactory _httpClientFactory; private readonly ILogger _logger; private readonly IFileSystem _fileSystem; - private readonly IZipClient _zipClient; public XmlTvListingsProvider( IServerConfigurationManager config, IHttpClientFactory httpClientFactory, ILogger logger, - IFileSystem fileSystem, - IZipClient zipClient) + IFileSystem fileSystem) { _config = config; _httpClientFactory = httpClientFactory; _logger = logger; _fileSystem = fileSystem; - _zipClient = zipClient; } public string Name => "XmlTV"; @@ -67,16 +64,12 @@ namespace Emby.Server.Implementations.LiveTv.Listings { _logger.LogInformation("xmltv path: {Path}", info.Path); - if (!info.Path.StartsWith("http", StringComparison.OrdinalIgnoreCase)) - { - return UnzipIfNeeded(info.Path, info.Path); - } - string cacheFilename = info.Id + ".xml"; string cacheFile = Path.Combine(_config.ApplicationPaths.CachePath, "xmltv", cacheFilename); + if (File.Exists(cacheFile) && File.GetLastWriteTimeUtc(cacheFile) >= DateTime.UtcNow.Subtract(_maxCacheAge)) { - return UnzipIfNeeded(info.Path, cacheFile); + return cacheFile; } // Must check if file exists as parent directory may not exist. @@ -84,95 +77,55 @@ namespace Emby.Server.Implementations.LiveTv.Listings { File.Delete(cacheFile); } - - _logger.LogInformation("Downloading xmltv listings from {Path}", info.Path); - - Directory.CreateDirectory(Path.GetDirectoryName(cacheFile)); - - using var response = await _httpClientFactory.CreateClient(NamedClient.Default).GetAsync(info.Path, cancellationToken).ConfigureAwait(false); - await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); - await using (var fileStream = new FileStream(cacheFile, FileMode.CreateNew, FileAccess.Write, FileShare.None, IODefaults.CopyToBufferSize, FileOptions.Asynchronous)) + else { - await stream.CopyToAsync(fileStream, cancellationToken).ConfigureAwait(false); + Directory.CreateDirectory(Path.GetDirectoryName(cacheFile)); } - return UnzipIfNeeded(info.Path, cacheFile); + if (info.Path.StartsWith("http", StringComparison.OrdinalIgnoreCase)) + { + _logger.LogInformation("Downloading xmltv listings from {Path}", info.Path); + + using var response = await _httpClientFactory.CreateClient(NamedClient.Default).GetAsync(info.Path, cancellationToken).ConfigureAwait(false); + await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); + + return await UnzipIfNeededAndCopy(info.Path, stream, cacheFile, cancellationToken).ConfigureAwait(false); + } + else + { + await using var stream = new FileStream(info.Path, FileMode.Open, FileAccess.Read, FileShare.Read, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous); + + return await UnzipIfNeededAndCopy(info.Path, stream, cacheFile, cancellationToken).ConfigureAwait(false); + } } - private string UnzipIfNeeded(ReadOnlySpan originalUrl, string file) + private async Task UnzipIfNeededAndCopy(string originalUrl, Stream stream, string file, CancellationToken cancellationToken) { - ReadOnlySpan ext = Path.GetExtension(originalUrl.LeftPart('?')); + int index = originalUrl.IndexOf('?', StringComparison.CurrentCulture); + string ext = Path.GetExtension(index > -1 ? originalUrl.Remove(index) : originalUrl); if (ext.Equals(".gz", StringComparison.OrdinalIgnoreCase)) { try { - string tempFolder = ExtractGz(file); - return FindXmlFile(tempFolder); + using var reader = new GZipStream(stream, CompressionMode.Decompress); + await using var writer = File.Create(file); + await reader.CopyToAsync(writer, cancellationToken).ConfigureAwait(false); } catch (Exception ex) { - _logger.LogError(ex, "Error extracting from gz file {File}", file); - } - - try - { - string tempFolder = ExtractFirstFileFromGz(file); - return FindXmlFile(tempFolder); - } - catch (Exception ex) - { - _logger.LogError(ex, "Error extracting from zip file {File}", file); + _logger.LogError(ex, "Error extracting from gz file {File}", originalUrl); } } + else + { + await using var fileStream = new FileStream(file, FileMode.CreateNew, FileAccess.Write, FileShare.None, IODefaults.CopyToBufferSize, FileOptions.Asynchronous); + await stream.CopyToAsync(fileStream, cancellationToken).ConfigureAwait(false); + } return file; } - private string ExtractFirstFileFromGz(string file) - { - using (var stream = File.OpenRead(file)) - { - string tempFolder = GetTempFolderPath(stream); - Directory.CreateDirectory(tempFolder); - - _zipClient.ExtractFirstFileFromGz(stream, tempFolder, "data.xml"); - - return tempFolder; - } - } - - private string ExtractGz(string file) - { - using (var stream = File.OpenRead(file)) - { - string tempFolder = GetTempFolderPath(stream); - Directory.CreateDirectory(tempFolder); - - _zipClient.ExtractAllFromGz(stream, tempFolder, true); - - return tempFolder; - } - } - - private string GetTempFolderPath(Stream stream) - { -#pragma warning disable CA5351 - using var md5 = MD5.Create(); -#pragma warning restore CA5351 - var checksum = Convert.ToHexString(md5.ComputeHash(stream)); - stream.Position = 0; - return Path.Combine(_config.ApplicationPaths.TempDirectory, checksum); - } - - private string FindXmlFile(string directory) - { - return _fileSystem.GetFiles(directory, true) - .Where(i => string.Equals(i.Extension, ".xml", StringComparison.OrdinalIgnoreCase)) - .Select(i => i.FullName) - .FirstOrDefault(); - } - public async Task> GetProgramsAsync(ListingsProviderInfo info, string channelId, DateTime startDateUtc, DateTime endDateUtc, CancellationToken cancellationToken) { if (string.IsNullOrWhiteSpace(channelId)) diff --git a/MediaBrowser.Model/IO/IZipClient.cs b/MediaBrowser.Model/IO/IZipClient.cs deleted file mode 100644 index 2448575d19..0000000000 --- a/MediaBrowser.Model/IO/IZipClient.cs +++ /dev/null @@ -1,16 +0,0 @@ -#pragma warning disable CS1591 - -using System.IO; - -namespace MediaBrowser.Model.IO -{ - /// - /// Interface IZipClient. - /// - public interface IZipClient - { - void ExtractAllFromGz(Stream source, string targetPath, bool overwriteExistingFiles); - - void ExtractFirstFileFromGz(Stream source, string targetPath, string defaultFileName); - } -} From 12ec0e285ddf8a5360859b5c49bb4b7b916569d2 Mon Sep 17 00:00:00 2001 From: "Negulici-R. Barnabas" Date: Mon, 18 Jul 2022 17:50:52 +0300 Subject: [PATCH 021/245] Chapter Images: - chapter image extraction intervals, limit count and resolutions can be set by the user from the server general settings; --- .../Encoder/MediaEncoder.cs | 30 ++++++++++++- .../Configuration/ServerConfiguration.cs | 18 ++++++++ MediaBrowser.Model/Drawing/ImageResolution.cs | 43 +++++++++++++++++++ .../MediaInfo/FFProbeVideoInfo.cs | 9 ++-- 4 files changed, 93 insertions(+), 7 deletions(-) create mode 100644 MediaBrowser.Model/Drawing/ImageResolution.cs diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index 77b97c9b48..5e2d318290 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -51,6 +51,7 @@ namespace MediaBrowser.MediaEncoding.Encoder private readonly IFileSystem _fileSystem; private readonly ILocalizationManager _localization; private readonly IConfiguration _config; + private readonly IServerConfigurationManager _serverConfig; private readonly string _startupOptionFFmpegPath; private readonly SemaphoreSlim _thumbnailResourcePool = new SemaphoreSlim(2, 2); @@ -81,13 +82,15 @@ namespace MediaBrowser.MediaEncoding.Encoder IServerConfigurationManager configurationManager, IFileSystem fileSystem, ILocalizationManager localization, - IConfiguration config) + IConfiguration config, + IServerConfigurationManager serverConfig) { _logger = logger; _configurationManager = configurationManager; _fileSystem = fileSystem; _localization = localization; _config = config; + _serverConfig = serverConfig; _startupOptionFFmpegPath = config.GetValue(Controller.Extensions.ConfigurationExtensions.FfmpegPathKey) ?? string.Empty; _jsonSerializerOptions = JsonDefaults.Options; } @@ -598,6 +601,29 @@ namespace MediaBrowser.MediaEncoding.Encoder _ => ".jpg" }; + bool enumConversionStatus = Enum.TryParse(_serverConfig.Configuration.ChapterImageResolution, out ImageResolution resolution); + var outputResolution = string.Empty; + + if (enumConversionStatus) + { + outputResolution = resolution switch + { + ImageResolution.P240 => "426x240", + ImageResolution.P360 => "640x360", + ImageResolution.P480 => "854x480", + ImageResolution.P720 => "1280x720", + ImageResolution.P1080 => "1920x1080", + ImageResolution.P1440 => "2560x1440", + ImageResolution.P2160 => "3840x2160", + _ => string.Empty + }; + + if (!string.IsNullOrEmpty(outputResolution)) + { + outputResolution = " -s " + outputResolution; + } + } + var tempExtractPath = Path.Combine(_configurationManager.ApplicationPaths.TempDirectory, Guid.NewGuid() + outputExtension); Directory.CreateDirectory(Path.GetDirectoryName(tempExtractPath)); @@ -651,7 +677,7 @@ namespace MediaBrowser.MediaEncoding.Encoder var vf = string.Join(',', filters); var mapArg = imageStreamIndex.HasValue ? (" -map 0:" + imageStreamIndex.Value.ToString(CultureInfo.InvariantCulture)) : string.Empty; - var args = string.Format(CultureInfo.InvariantCulture, "-i {0}{3} -threads {4} -v quiet -vframes 1 -vf {2} -f image2 \"{1}\"", inputPath, tempExtractPath, vf, mapArg, _threads); + var args = string.Format(CultureInfo.InvariantCulture, "-i {0}{3} -threads {4} -v quiet -vframes 1 -vf {2}{5} -f image2 \"{1}\"", inputPath, tempExtractPath, vf, mapArg, _threads, outputResolution); if (offset.HasValue) { diff --git a/MediaBrowser.Model/Configuration/ServerConfiguration.cs b/MediaBrowser.Model/Configuration/ServerConfiguration.cs index e61b896b9d..c37c167eb6 100644 --- a/MediaBrowser.Model/Configuration/ServerConfiguration.cs +++ b/MediaBrowser.Model/Configuration/ServerConfiguration.cs @@ -240,5 +240,23 @@ namespace MediaBrowser.Model.Configuration /// Gets or sets a value indicating whether clients should be allowed to upload logs. /// public bool AllowClientLogUpload { get; set; } = true; + + /// + /// Gets or sets the dummy chapters duration in seconds. + /// + /// The dummy chapters duration. + public int DummyChapterDuration { get; set; } = 300; + + /// + /// Gets or sets the dummy chapter count. + /// + /// The dummy chapter count. + public int DummyChapterCount { get; set; } = 100; + + /// + /// Gets or sets the chapter image resolution. + /// + /// The chapter image resolution. + public string ChapterImageResolution { get; set; } = "Match Source"; } } diff --git a/MediaBrowser.Model/Drawing/ImageResolution.cs b/MediaBrowser.Model/Drawing/ImageResolution.cs new file mode 100644 index 0000000000..7e1c54f5a3 --- /dev/null +++ b/MediaBrowser.Model/Drawing/ImageResolution.cs @@ -0,0 +1,43 @@ +namespace MediaBrowser.Model.Drawing +{ + /// + /// Enum ImageResolution. + /// + public enum ImageResolution + { + /// + /// 240p. + /// + P240, + + /// + /// 360p. + /// + P360, + + /// + /// 480p. + /// + P480, + + /// + /// 720p. + /// + P720, + + /// + /// 1080p. + /// + P1080, + + /// + /// 1440p. + /// + P1440, + + /// + /// 2160p. + /// + P2160 + } +} diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs index 8c08ab30ef..c8ff5de69a 100644 --- a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs +++ b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs @@ -48,8 +48,6 @@ namespace MediaBrowser.Providers.MediaInfo private readonly SubtitleResolver _subtitleResolver; private readonly IMediaSourceManager _mediaSourceManager; - private readonly long _dummyChapterDuration = TimeSpan.FromMinutes(5).Ticks; - public FFProbeVideoInfo( ILogger logger, IMediaSourceManager mediaSourceManager, @@ -651,6 +649,7 @@ namespace MediaBrowser.Providers.MediaInfo private ChapterInfo[] CreateDummyChapters(Video video) { var runtime = video.RunTimeTicks ?? 0; + long dummyChapterDuration = TimeSpan.FromSeconds(_config.Configuration.DummyChapterDuration).Ticks; if (runtime < 0) { @@ -662,13 +661,13 @@ namespace MediaBrowser.Providers.MediaInfo runtime)); } - if (runtime < _dummyChapterDuration) + if (runtime < dummyChapterDuration) { return Array.Empty(); } // Limit to 100 chapters just in case there's some incorrect metadata here - int chapterCount = (int)Math.Min(runtime / _dummyChapterDuration, 100); + int chapterCount = (int)Math.Min(runtime / dummyChapterDuration, _config.Configuration.DummyChapterCount); var chapters = new ChapterInfo[chapterCount]; long currentChapterTicks = 0; @@ -679,7 +678,7 @@ namespace MediaBrowser.Providers.MediaInfo StartPositionTicks = currentChapterTicks }; - currentChapterTicks += _dummyChapterDuration; + currentChapterTicks += dummyChapterDuration; } return chapters; From 5f5347aee3209383248a6055318ec8883291d406 Mon Sep 17 00:00:00 2001 From: 1hitsong <3330318+1hitsong@users.noreply.github.com> Date: Fri, 9 Sep 2022 20:14:23 -0400 Subject: [PATCH 022/245] Add Lyrics API Endpoint --- .gitignore | 2 + .../Controllers/UserLibraryController.cs | 49 ++++++++++ Jellyfin.Api/Helpers/ItemHelper.cs | 87 ++++++++++++++++++ Jellyfin.Api/Jellyfin.Api.csproj | 12 +++ Jellyfin.Api/Libraries/LrcParser.dll | Bin 0 -> 12288 bytes Jellyfin.Api/Models/UserDtos/Lyrics.cs | 23 +++++ 6 files changed, 173 insertions(+) create mode 100644 Jellyfin.Api/Helpers/ItemHelper.cs create mode 100644 Jellyfin.Api/Libraries/LrcParser.dll create mode 100644 Jellyfin.Api/Models/UserDtos/Lyrics.cs diff --git a/.gitignore b/.gitignore index c2ae76c1e3..3f80ffcf7d 100644 --- a/.gitignore +++ b/.gitignore @@ -281,3 +281,5 @@ apiclient/generated # Omnisharp crash logs mono_crash.*.json + +!LrcParser.dll \ No newline at end of file diff --git a/Jellyfin.Api/Controllers/UserLibraryController.cs b/Jellyfin.Api/Controllers/UserLibraryController.cs index e45f9b58cd..89fb56744c 100644 --- a/Jellyfin.Api/Controllers/UserLibraryController.cs +++ b/Jellyfin.Api/Controllers/UserLibraryController.cs @@ -1,14 +1,18 @@ using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; +using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; using Jellyfin.Api.Constants; using Jellyfin.Api.Extensions; +using Jellyfin.Api.Helpers; using Jellyfin.Api.ModelBinders; +using Jellyfin.Api.Models.UserDtos; using Jellyfin.Data.Enums; using Jellyfin.Extensions; +using Kfstorm.LrcParser; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; @@ -381,5 +385,50 @@ namespace Jellyfin.Api.Controllers return _userDataRepository.GetUserDataDto(item, user); } + + /// + /// Gets an item's lyrics. + /// + /// User id. + /// Item id. + /// Lyrics returned. + /// Something went wrong. No Lyrics will be returned. + /// An containing the intros to play. + [HttpGet("Users/{userId}/Items/{itemId}/Lyrics")] + [ProducesResponseType(StatusCodes.Status200OK)] + public ActionResult> GetLyrics([FromRoute, Required] Guid userId, [FromRoute, Required] Guid itemId) + { + var user = _userManager.GetUserById(userId); + + if (user == null) + { + List lyricsList = new List + { + new Lyrics { Error = "User Not Found" } + }; + return NotFound(new { Results = lyricsList.ToArray() }); + } + + var item = itemId.Equals(default) + ? _libraryManager.GetUserRootFolder() + : _libraryManager.GetItemById(itemId); + + if (item == null) + { + List lyricsList = new List + { + new Lyrics { Error = "Requested Item Not Found" } + }; + return NotFound(new { Results = lyricsList.ToArray() }); + } + + List result = ItemHelper.GetLyricData(item); + if (string.IsNullOrEmpty(result.ElementAt(0).Error)) + { + return Ok(new { Results = result }); + } + + return NotFound(new { Results = result.ToArray() }); + } } } diff --git a/Jellyfin.Api/Helpers/ItemHelper.cs b/Jellyfin.Api/Helpers/ItemHelper.cs new file mode 100644 index 0000000000..43ef7aa093 --- /dev/null +++ b/Jellyfin.Api/Helpers/ItemHelper.cs @@ -0,0 +1,87 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Net.Http; +using System.Threading.Tasks; +using Jellyfin.Api.Models.UserDtos; +using Kfstorm.LrcParser; +using MediaBrowser.Controller.Configuration; +using MediaBrowser.Controller.Devices; +using MediaBrowser.Controller.Dlna; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.MediaEncoding; +using MediaBrowser.Controller.Net; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; + +namespace Jellyfin.Api.Helpers +{ + /// + /// Item helper. + /// + public static class ItemHelper + { + /// + /// Opens lyrics file, converts to a List of Lyrics, and returns it. + /// + /// Requested Item. + /// Collection of Lyrics. + internal static List GetLyricData(BaseItem item) + { + List lyricsList = new List(); + + string lrcFilePath = @Path.ChangeExtension(item.Path, "lrc"); + + // LRC File not found, fallback to TXT file + if (!System.IO.File.Exists(lrcFilePath)) + { + string txtFilePath = @Path.ChangeExtension(item.Path, "txt"); + if (!System.IO.File.Exists(txtFilePath)) + { + lyricsList.Add(new Lyrics { Error = "Lyric File Not Found" }); + return lyricsList; + } + + var lyricTextData = System.IO.File.ReadAllText(txtFilePath); + string[] lyricTextLines = lyricTextData.Split(Environment.NewLine, StringSplitOptions.RemoveEmptyEntries); + + foreach (var lyricLine in lyricTextLines) + { + lyricsList.Add(new Lyrics { Text = lyricLine }); + } + + return lyricsList; + } + + // Process LRC File + ILrcFile lyricData; + string lrcFileContent = System.IO.File.ReadAllText(lrcFilePath); + try + { + lrcFileContent = lrcFileContent.Replace('<', '['); + lrcFileContent = lrcFileContent.Replace('>', ']'); + lyricData = Kfstorm.LrcParser.LrcFile.FromText(lrcFileContent); + } + catch + { + lyricsList.Add(new Lyrics { Error = "No Lyrics Data" }); + return lyricsList; + } + + if (lyricData == null) + { + lyricsList.Add(new Lyrics { Error = "No Lyrics Data" }); + return lyricsList; + } + + foreach (var lyricLine in lyricData.Lyrics) + { + double ticks = lyricLine.Timestamp.TotalSeconds * 10000000; + lyricsList.Add(new Lyrics { Start = Math.Ceiling(ticks), Text = lyricLine.Content }); + } + + return lyricsList; + } + } +} diff --git a/Jellyfin.Api/Jellyfin.Api.csproj b/Jellyfin.Api/Jellyfin.Api.csproj index 894d871383..1b78bb1074 100644 --- a/Jellyfin.Api/Jellyfin.Api.csproj +++ b/Jellyfin.Api/Jellyfin.Api.csproj @@ -46,4 +46,16 @@ + + + Libraries\LrcParser.dll + + + + + + Always + + + diff --git a/Jellyfin.Api/Libraries/LrcParser.dll b/Jellyfin.Api/Libraries/LrcParser.dll new file mode 100644 index 0000000000000000000000000000000000000000..46e4fb703335931a91bdb2bcce2a24c62b6b8dda GIT binary patch literal 12288 zcmeHNe{dXkb${Qz+r87tch=p>k{!#+$v@AMe3ASM*%;gUMNJ?-1~>-*mOzVG{f_q)3q`p_rHM?`*{*RKn2Wb=u>y~BwqYurqQ!=aU) z>3#h~gUUzU_pW`kXoq9izm%U!(-*96YvIEm^6*W9?7!ST!SI3W0Z_~`fp ztjd3tt4A^m$1Cu^myzQ{O`M1uk6EGx;QhRhXyiuOyU_`vV3j-w`i?3(RWQ#KK)0_3 zfK2-8#SKc11fojWj-3G|u^k7(9c{%~b?n4&rED{2L6KvnS)6Pug|q6|Nz_wC3L4re9DdGO_L9>>O5QSQgxmT_6LNko5YVbXJ7AF0zTRpz-MiTM*Tbs3e z(LaCda?N*E5HK(({#J^2_-Gx%fsv@o^VK_TC=cyk9STYC+d@XeZCZV+D>g1!afn-2 zd)k*=8=QdOU}JsMXy~ZeX*_(X)tG?o8+ar!ZG8{+YDy8ki=BP%!Oks4<0047!`by! z0UmM#you;iE9Y&;d$2t>#+#Z#e|1`qiZS~xn^tx(}_WU)htVrFx-~Jc(;WbYPd>jwL@4@X@E+y5x_#N7;SAv0O}Sz+)Rf>Tq06NpAR&2 z-ceFE0vL2@mR!tEZ?jv_my+}$*i)_wH!qn3ei+pb@~t{G?D z5~igcetHvS4Kk`BL7yon$ia*Yg`6h9T4x#Hf`)KIJka$Tmuf(>Fo#0d{0-MsJQxkG z3u)1Sbt_nHsv%y}5D!IbZauQ0GYYryz&!Q#TKg$>B$1U`#%mhmp_+a~f;sQ5fM3S7 z%VdY4bzxY%dqbcx+%@7dqF{tmLBP;8)#h)6=VV z+YpY{y3Ws{l>9~@T6@jd%ma^bLrDxso3*AARlve+C)9Qff$f(x><(I36hjT2+nx8Z z!3B-s=mO6mN`Vb7xMpkgLnP~6WKBd*uS4a33$7mA0w zE?{EB!b#M6C?2^FcSL_Il0=1vEUfUM_`>Ky>oy?m$ANSJv9Y*LTbQ6BYdt`613*c1 zVXg>MFch!5b=!w>(YixPBrFtG8eI|Btnq5A?AWD4Aq*j!D+^ROXvR^%`v_VQ;)_?`YI$Ux^%gR+hNwV|nz3nBsAR zvzO#bNWLGy*#^KRZ?rYqHd=VaRyDCvj30o~*2%Z8U;jZQ7QWViz0Oi=J9w`}{T6OG zA*^qYpslwM=uv+oFKh;HUAnQ(p_r&0;BlNUVG3f?Ajf_7Tij|VEX;DD+k1Q^l53B5 z2yo@@5Cj3Ero<2g4BQ`F4MD)DEinWE1KT85LlA6Q_!icBmwUzSif}+Z2sbF+o<)6f>j=fj@7_bY*>=fC%E4?jX88tK<~6%5%JgQRb}uhg zPEU19=JI;ua^b6I_|6{X?bOf@I<+y?k=oF)p%YVy*YzCW{pj(E`>=n-^)+O0#c;vS z<|iH2cqvZwC~g5O4i3|aMt5Jl;`W0BeUP02{T$1Ba@H6to?jrUq%Hx6}s0 z?G{r*wxc|L2#zq<3AZNMrXqS`TgZuQU0 zns!xRNF68zgMO)P_8atl-}8X`1cn8+3Vc%F>l#b%*VuyYe;D}J42F+s3@y?59Ql+% zPlj%;N7un)YCZa0N7zq*iqa;bFy%qT=zX-Bb{K!FR#T_{ zMb$#z*I!bKI@EW7e@y?L>ZD77R{dw2FGb zzj6-Msv+xgyr3V{IyA0aK3>rO-ssR|=!E)Xy+gx5$nk>y3S=l=mkPIP3lt`yN8K5y zratYjrbhK@>OYP5X_a6!$Mk zKP*$NS`Gcwr4;usMB7>j#~X_KS4;PM6!&idUG*sLUzpmLvnG$jZY@H&6-+%sX9I_{ zD18FkDWZ#uU(k`TKuWiQn_UjPTzgnwRQxL@%513`>q4K2nB+k_k#z^~{E zs|(NUC4eDX3s^^;0=Ee47C0bqzre!+(|`ue04}0)!pREfO*-sfjrCAg3&qyzfe%xS zdMa=j@XrG?@ZRjd09fz8NEhi@|096U2Ogs(>UHA_)FQ1`iiLK8FA7|ua{jlW^Ms)k zYZ~ea+J{PQr*>7RUZmZ61K=;zQnk_Z_!DEDT8W$JUg+#bv@a4{*e2Fi(zE(;)kpP# zi!?~z0DKDfoqJWM`jT;hUZqEjb83rv!2f%yTh+tMT9wltRs(>aQWxnL`X8x5#Q!<9 zO}sBrU&OpvqMi?227DRtB3*}06MWUd%kjVk+ONj3N^PT^fw$p{Gjow@^go52EBaT| zD$LEdR0`wrH(CmF@$Uea(i?y)=x2a!w91#F4YU#P{nQQEOM3u!3x61}m+q#+fFZzs zv6c}|MmQPD(74YO{yE{F_aN(^hxGS-5Agj)yG+aJnC~*3q-TBK7W_v7m16ro#Zn*E zmA8~nu}+KdR|tQF@VkZ6E1X{8q=j=%;CX>h2)r!td4b;+_(RcGSjFB_Edsj*&T8!a zae?G#JRxwWz~cgE1wJnDiomM^Nf&*AvjQI%ctzk=5by)dIg$^pPg@jKqBe-hVQ!E6m!+h6p#sOo9Ujx<%SdSGz zfnEZ<0hOnLy9{tKcA6R`s0Gp%{4~_U3g9d7(`Y5F0=^1AjaJhd;A`;H@S=4s@U{49 z)Q;L!c(2$7JcTRPM8KtVCp}0%rC(vbA68jaQ2tq7$*PY_Sm8?db>=^(wj*aZ^2SAF zuHN~Z@OHo&zq<`08$skGh@Ndmv^JvLOheS~I^VW^%jjt5=Ftw?mdX??d;3_4+@2X7 z?aMmTx%5nLF6}s-TUcqAZB32fJu~ZpyoplhT%}IhQ_SVkV>$D9Ck^!Hi&LguqW0S3 zrfrVTW%gQA(`nnZS$#0;6!@AiY*A5 z+pa7SPOWrN^6Fw<>JAk11$2kJk)s}S!m>f8rwc_~U85%LOWO|IO^uo3Fh2>Jh7>IP4T?iG@9{NJ=#6tU>TlDl~Y9B69qIIu?DTvxZZ9S zycr8Mk~JHUmu~SUOO->TIbO1yQh>QG2>**G4Nd@b-khcJhW8ARbwxt`s*?08GgUd$;sU4pq|Onb*ZjD?+s zO|B3z<1VE#CLWrep3cp9IM-=!(Y8@DqU|lPqF%z0K3;S^Io3bH+!a?8J#@%AW$xk6 zvR-0236!%laxL9UDVrZR&rs>sf*gS=m!M0^t+HnZWzcQg=^1f{J0VYp{(FjPp2mz1 zQi0Mmj+3tx&fyuxrY!cqcwKjT7v4-2DGzx9XOX7yevf6WZGu+-#Woyi zJq39JJBWMn?&d762|5jVfldIc*mX5JJ&m+yom;IJUW(Mh9Ae1e+qX$)(4Hpyah(R0 z0hK^ZdGVfs_tI+N6zt?BGLD88I*219mdBZ{Wj`ndaA~2-=YHkE zBb{Y5d$I2(Lo!GQ@F& zDLi*zO~f`0{TXPN`p6040^$DjqD3CD@K8-iYPo2c$1N)5=RjKxAH$Y>2eju70vF6U zHs)*5OIJR3P)hP7^ipNr9nfD%YIn(IW#G7gy0N+c5aL)zAEBeL&DtgFbBA>eY___# zu=7v7^wqTUfjb}j<%xUlKC${0@+XuE`VypcAoyGc7!h=fu_#tlu_j+Y1sB#SUvOD7 z-gq;wnfxILA_4!hSW|FObVx-9V#(m5*gaaTDLSAhG}W|tah;|uip_o;+KXa`1>S=< zKF!JqiPnNTrC`yO8Lkn8q4^VdQVNn59pE1xu>=c{KN4wbYT6d4Ulcp47DdxqB*IuE zX2S7NgcDmC32HtqwlUVVD4H#)h+=Fi936;6LY1bvw1vMQI_wMT1anOwrR#Adg<>YM z5Ho$X+^vY~uu=Mi&ZxOvstJ`eYLGsb#R=KtsDcUNXyO#A1clym_-ua)kYcl+HGt24 zCgLX*WDt(%grtT!8F(btpzRNUfhIvD1qqHr5PW9G=tra93vKlo%XH1q{RYOvXT%oc zY{z*}Ga`XfYK`asSRFNp%Nr)e&uJlf0WVL4JoGv|sAW3$e=&z1>qj5Ji->P@hXchJ zOSgF3p(!F2Tf88F*A_R#b#Gp07AgZScT5eV% z{v`WOmV770cal@-OHzadVhm~sL!ngoXy$JWBU-};?ez2>D_`DTjhwKp(~g3kCVHC` zEl%y}AL+$&0-i_Oy&dESPHj$gz(AzFygT=vK=)v?PWWhAQ`r{L0!0CAm(4VuDun37 zw<`Q3o4OGA5X9-#<#Mr!+pbl z5Pjth^DiD4IJco?>#En6_xeqn$#eDU^PVg2PVHw;T|LmgS z`L3a(3b61+H_*G(osIyR|NW;5qI~^o5>t< zUW#zOj}*3AIsEwFP&Kq2gpWyS#l4*Noq(#Z*egAllnk{ z;>*qBKG?A2iH4sjDpB67E#6Awt*b(AtJ~a|kxD-J{}DKM-N+YjAEz*ay#3^D^xP~~ Y+Hfv^i;kV{{|xhgd;RYC?aRRb02;KsP5=M^ literal 0 HcmV?d00001 diff --git a/Jellyfin.Api/Models/UserDtos/Lyrics.cs b/Jellyfin.Api/Models/UserDtos/Lyrics.cs new file mode 100644 index 0000000000..df1b5d08a2 --- /dev/null +++ b/Jellyfin.Api/Models/UserDtos/Lyrics.cs @@ -0,0 +1,23 @@ +namespace Jellyfin.Api.Models.UserDtos +{ + /// + /// Lyric dto. + /// + public class Lyrics + { + /// + /// Gets or sets the start. + /// + public double? Start { get; set; } + + /// + /// Gets or sets the test. + /// + public string? Text { get; set; } + + /// + /// Gets or sets the error. + /// + public string? Error { get; set; } + } +} From 8b78802c0b42d9d55f5bd8c3f34a542d78903f75 Mon Sep 17 00:00:00 2001 From: 1hitsong <3330318+1hitsong@users.noreply.github.com> Date: Fri, 9 Sep 2022 21:08:38 -0400 Subject: [PATCH 023/245] Update Jellyfin.Api/Controllers/UserLibraryController.cs Co-authored-by: Cody Robibero --- Jellyfin.Api/Controllers/UserLibraryController.cs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/Jellyfin.Api/Controllers/UserLibraryController.cs b/Jellyfin.Api/Controllers/UserLibraryController.cs index 89fb56744c..42367940d3 100644 --- a/Jellyfin.Api/Controllers/UserLibraryController.cs +++ b/Jellyfin.Api/Controllers/UserLibraryController.cs @@ -402,11 +402,7 @@ namespace Jellyfin.Api.Controllers if (user == null) { - List lyricsList = new List - { - new Lyrics { Error = "User Not Found" } - }; - return NotFound(new { Results = lyricsList.ToArray() }); + return NotFound(); } var item = itemId.Equals(default) From 92715a74262fbf52f7071b45f5b61b7f057bb28e Mon Sep 17 00:00:00 2001 From: 1hitsong <3330318+1hitsong@users.noreply.github.com> Date: Fri, 9 Sep 2022 21:09:39 -0400 Subject: [PATCH 024/245] Update Jellyfin.Api/Controllers/UserLibraryController.cs Co-authored-by: Cody Robibero --- Jellyfin.Api/Controllers/UserLibraryController.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jellyfin.Api/Controllers/UserLibraryController.cs b/Jellyfin.Api/Controllers/UserLibraryController.cs index 42367940d3..a1b911a450 100644 --- a/Jellyfin.Api/Controllers/UserLibraryController.cs +++ b/Jellyfin.Api/Controllers/UserLibraryController.cs @@ -424,7 +424,7 @@ namespace Jellyfin.Api.Controllers return Ok(new { Results = result }); } - return NotFound(new { Results = result.ToArray() }); + return NotFound(); } } } From 0aa2780ea7b23aed31765550f707f7ea9fc0daf1 Mon Sep 17 00:00:00 2001 From: 1hitsong <3330318+1hitsong@users.noreply.github.com> Date: Fri, 9 Sep 2022 21:15:57 -0400 Subject: [PATCH 025/245] Update Jellyfin.Api/Controllers/UserLibraryController.cs Co-authored-by: Cody Robibero --- Jellyfin.Api/Controllers/UserLibraryController.cs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/Jellyfin.Api/Controllers/UserLibraryController.cs b/Jellyfin.Api/Controllers/UserLibraryController.cs index a1b911a450..7830df9bc9 100644 --- a/Jellyfin.Api/Controllers/UserLibraryController.cs +++ b/Jellyfin.Api/Controllers/UserLibraryController.cs @@ -411,11 +411,7 @@ namespace Jellyfin.Api.Controllers if (item == null) { - List lyricsList = new List - { - new Lyrics { Error = "Requested Item Not Found" } - }; - return NotFound(new { Results = lyricsList.ToArray() }); + return NotFound(); } List result = ItemHelper.GetLyricData(item); From d24444b6d3a2e973d50edc2a8a1d01a433db645e Mon Sep 17 00:00:00 2001 From: 1hitsong <3330318+1hitsong@users.noreply.github.com> Date: Sat, 10 Sep 2022 10:51:05 -0400 Subject: [PATCH 026/245] Update Jellyfin.Api/Models/UserDtos/Lyrics.cs Co-authored-by: Neil Burrows --- Jellyfin.Api/Models/UserDtos/Lyrics.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jellyfin.Api/Models/UserDtos/Lyrics.cs b/Jellyfin.Api/Models/UserDtos/Lyrics.cs index df1b5d08a2..cd548eb037 100644 --- a/Jellyfin.Api/Models/UserDtos/Lyrics.cs +++ b/Jellyfin.Api/Models/UserDtos/Lyrics.cs @@ -11,7 +11,7 @@ namespace Jellyfin.Api.Models.UserDtos public double? Start { get; set; } /// - /// Gets or sets the test. + /// Gets or sets the text. /// public string? Text { get; set; } From 2e260e5319b0b58290a1e30a28886c69d5a65325 Mon Sep 17 00:00:00 2001 From: 1hitsong <3330318+1hitsong@users.noreply.github.com> Date: Sat, 10 Sep 2022 14:29:30 -0400 Subject: [PATCH 027/245] Updates based on review --- .../Controllers/UserLibraryController.cs | 9 ++- Jellyfin.Api/Helpers/ItemHelper.cs | 68 +++++++++++------- Jellyfin.Api/Jellyfin.Api.csproj | 13 +--- Jellyfin.Api/Libraries/LrcParser.dll | Bin 12288 -> 0 bytes 4 files changed, 46 insertions(+), 44 deletions(-) delete mode 100644 Jellyfin.Api/Libraries/LrcParser.dll diff --git a/Jellyfin.Api/Controllers/UserLibraryController.cs b/Jellyfin.Api/Controllers/UserLibraryController.cs index 89fb56744c..afd4013ed3 100644 --- a/Jellyfin.Api/Controllers/UserLibraryController.cs +++ b/Jellyfin.Api/Controllers/UserLibraryController.cs @@ -12,7 +12,6 @@ using Jellyfin.Api.ModelBinders; using Jellyfin.Api.Models.UserDtos; using Jellyfin.Data.Enums; using Jellyfin.Extensions; -using Kfstorm.LrcParser; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; @@ -422,13 +421,13 @@ namespace Jellyfin.Api.Controllers return NotFound(new { Results = lyricsList.ToArray() }); } - List result = ItemHelper.GetLyricData(item); - if (string.IsNullOrEmpty(result.ElementAt(0).Error)) + var result = ItemHelper.GetLyricData(item); + if (result is not null) { - return Ok(new { Results = result }); + return Ok(result); } - return NotFound(new { Results = result.ToArray() }); + return NotFound(); } } } diff --git a/Jellyfin.Api/Helpers/ItemHelper.cs b/Jellyfin.Api/Helpers/ItemHelper.cs index 43ef7aa093..c1b5ea6ccc 100644 --- a/Jellyfin.Api/Helpers/ItemHelper.cs +++ b/Jellyfin.Api/Helpers/ItemHelper.cs @@ -1,19 +1,13 @@ using System; using System.Collections.Generic; +using System.Dynamic; +using System.Globalization; using System.IO; -using System.Net.Http; -using System.Threading.Tasks; +using System.Linq; using Jellyfin.Api.Models.UserDtos; -using Kfstorm.LrcParser; -using MediaBrowser.Controller.Configuration; -using MediaBrowser.Controller.Devices; -using MediaBrowser.Controller.Dlna; +using LrcParser.Model; +using LrcParser.Parser; using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Library; -using MediaBrowser.Controller.MediaEncoding; -using MediaBrowser.Controller.Net; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Mvc; namespace Jellyfin.Api.Helpers { @@ -27,7 +21,7 @@ namespace Jellyfin.Api.Helpers /// /// Requested Item. /// Collection of Lyrics. - internal static List GetLyricData(BaseItem item) + internal static object? GetLyricData(BaseItem item) { List lyricsList = new List(); @@ -39,8 +33,7 @@ namespace Jellyfin.Api.Helpers string txtFilePath = @Path.ChangeExtension(item.Path, "txt"); if (!System.IO.File.Exists(txtFilePath)) { - lyricsList.Add(new Lyrics { Error = "Lyric File Not Found" }); - return lyricsList; + return null; } var lyricTextData = System.IO.File.ReadAllText(txtFilePath); @@ -51,37 +44,58 @@ namespace Jellyfin.Api.Helpers lyricsList.Add(new Lyrics { Text = lyricLine }); } - return lyricsList; + return new { lyrics = lyricsList }; } // Process LRC File - ILrcFile lyricData; + Song lyricData; + List sortedLyricData = new List(); + var metaData = new ExpandoObject() as IDictionary; string lrcFileContent = System.IO.File.ReadAllText(lrcFilePath); + try { - lrcFileContent = lrcFileContent.Replace('<', '['); - lrcFileContent = lrcFileContent.Replace('>', ']'); - lyricData = Kfstorm.LrcParser.LrcFile.FromText(lrcFileContent); + LyricParser lrcLyricParser = new LrcParser.Parser.Lrc.LrcParser(); + lyricData = lrcLyricParser.Decode(lrcFileContent); + var _metaData = lyricData.Lyrics + .Where(x => x.TimeTags.Count == 0) + .Where(x => x.Text.StartsWith("[", StringComparison.Ordinal) && x.Text.EndsWith("]", StringComparison.Ordinal)) + .Select(x => x.Text) + .ToList(); + + foreach (string dataRow in _metaData) + { + var data = dataRow.Split(":"); + + string newPropertyName = data[0].Replace("[", string.Empty, StringComparison.Ordinal); + string newPropertyValue = data[1].Replace("]", string.Empty, StringComparison.Ordinal); + + metaData.Add(newPropertyName, newPropertyValue); + } + + sortedLyricData = lyricData.Lyrics.Where(x => x.TimeTags.Count > 0).OrderBy(x => x.TimeTags.ToArray()[0].Value).ToList(); } catch { - lyricsList.Add(new Lyrics { Error = "No Lyrics Data" }); - return lyricsList; + return null; } if (lyricData == null) { - lyricsList.Add(new Lyrics { Error = "No Lyrics Data" }); - return lyricsList; + return null; } - foreach (var lyricLine in lyricData.Lyrics) + for (int i = 0; i < sortedLyricData.Count; i++) { - double ticks = lyricLine.Timestamp.TotalSeconds * 10000000; - lyricsList.Add(new Lyrics { Start = Math.Ceiling(ticks), Text = lyricLine.Content }); + if (sortedLyricData[i].TimeTags.Count > 0) + { + var timeData = sortedLyricData[i].TimeTags.ToArray()[0].Value; + double ticks = Convert.ToDouble(timeData, new NumberFormatInfo()) * 10000; + lyricsList.Add(new Lyrics { Start = Math.Ceiling(ticks), Text = sortedLyricData[i].Text }); + } } - return lyricsList; + return new { MetaData = metaData, lyrics = lyricsList }; } } } diff --git a/Jellyfin.Api/Jellyfin.Api.csproj b/Jellyfin.Api/Jellyfin.Api.csproj index 1b78bb1074..972387e02a 100644 --- a/Jellyfin.Api/Jellyfin.Api.csproj +++ b/Jellyfin.Api/Jellyfin.Api.csproj @@ -17,6 +17,7 @@ + @@ -46,16 +47,4 @@ - - - Libraries\LrcParser.dll - - - - - - Always - - - diff --git a/Jellyfin.Api/Libraries/LrcParser.dll b/Jellyfin.Api/Libraries/LrcParser.dll deleted file mode 100644 index 46e4fb703335931a91bdb2bcce2a24c62b6b8dda..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12288 zcmeHNe{dXkb${Qz+r87tch=p>k{!#+$v@AMe3ASM*%;gUMNJ?-1~>-*mOzVG{f_q)3q`p_rHM?`*{*RKn2Wb=u>y~BwqYurqQ!=aU) z>3#h~gUUzU_pW`kXoq9izm%U!(-*96YvIEm^6*W9?7!ST!SI3W0Z_~`fp ztjd3tt4A^m$1Cu^myzQ{O`M1uk6EGx;QhRhXyiuOyU_`vV3j-w`i?3(RWQ#KK)0_3 zfK2-8#SKc11fojWj-3G|u^k7(9c{%~b?n4&rED{2L6KvnS)6Pug|q6|Nz_wC3L4re9DdGO_L9>>O5QSQgxmT_6LNko5YVbXJ7AF0zTRpz-MiTM*Tbs3e z(LaCda?N*E5HK(({#J^2_-Gx%fsv@o^VK_TC=cyk9STYC+d@XeZCZV+D>g1!afn-2 zd)k*=8=QdOU}JsMXy~ZeX*_(X)tG?o8+ar!ZG8{+YDy8ki=BP%!Oks4<0047!`by! z0UmM#you;iE9Y&;d$2t>#+#Z#e|1`qiZS~xn^tx(}_WU)htVrFx-~Jc(;WbYPd>jwL@4@X@E+y5x_#N7;SAv0O}Sz+)Rf>Tq06NpAR&2 z-ceFE0vL2@mR!tEZ?jv_my+}$*i)_wH!qn3ei+pb@~t{G?D z5~igcetHvS4Kk`BL7yon$ia*Yg`6h9T4x#Hf`)KIJka$Tmuf(>Fo#0d{0-MsJQxkG z3u)1Sbt_nHsv%y}5D!IbZauQ0GYYryz&!Q#TKg$>B$1U`#%mhmp_+a~f;sQ5fM3S7 z%VdY4bzxY%dqbcx+%@7dqF{tmLBP;8)#h)6=VV z+YpY{y3Ws{l>9~@T6@jd%ma^bLrDxso3*AARlve+C)9Qff$f(x><(I36hjT2+nx8Z z!3B-s=mO6mN`Vb7xMpkgLnP~6WKBd*uS4a33$7mA0w zE?{EB!b#M6C?2^FcSL_Il0=1vEUfUM_`>Ky>oy?m$ANSJv9Y*LTbQ6BYdt`613*c1 zVXg>MFch!5b=!w>(YixPBrFtG8eI|Btnq5A?AWD4Aq*j!D+^ROXvR^%`v_VQ;)_?`YI$Ux^%gR+hNwV|nz3nBsAR zvzO#bNWLGy*#^KRZ?rYqHd=VaRyDCvj30o~*2%Z8U;jZQ7QWViz0Oi=J9w`}{T6OG zA*^qYpslwM=uv+oFKh;HUAnQ(p_r&0;BlNUVG3f?Ajf_7Tij|VEX;DD+k1Q^l53B5 z2yo@@5Cj3Ero<2g4BQ`F4MD)DEinWE1KT85LlA6Q_!icBmwUzSif}+Z2sbF+o<)6f>j=fj@7_bY*>=fC%E4?jX88tK<~6%5%JgQRb}uhg zPEU19=JI;ua^b6I_|6{X?bOf@I<+y?k=oF)p%YVy*YzCW{pj(E`>=n-^)+O0#c;vS z<|iH2cqvZwC~g5O4i3|aMt5Jl;`W0BeUP02{T$1Ba@H6to?jrUq%Hx6}s0 z?G{r*wxc|L2#zq<3AZNMrXqS`TgZuQU0 zns!xRNF68zgMO)P_8atl-}8X`1cn8+3Vc%F>l#b%*VuyYe;D}J42F+s3@y?59Ql+% zPlj%;N7un)YCZa0N7zq*iqa;bFy%qT=zX-Bb{K!FR#T_{ zMb$#z*I!bKI@EW7e@y?L>ZD77R{dw2FGb zzj6-Msv+xgyr3V{IyA0aK3>rO-ssR|=!E)Xy+gx5$nk>y3S=l=mkPIP3lt`yN8K5y zratYjrbhK@>OYP5X_a6!$Mk zKP*$NS`Gcwr4;usMB7>j#~X_KS4;PM6!&idUG*sLUzpmLvnG$jZY@H&6-+%sX9I_{ zD18FkDWZ#uU(k`TKuWiQn_UjPTzgnwRQxL@%513`>q4K2nB+k_k#z^~{E zs|(NUC4eDX3s^^;0=Ee47C0bqzre!+(|`ue04}0)!pREfO*-sfjrCAg3&qyzfe%xS zdMa=j@XrG?@ZRjd09fz8NEhi@|096U2Ogs(>UHA_)FQ1`iiLK8FA7|ua{jlW^Ms)k zYZ~ea+J{PQr*>7RUZmZ61K=;zQnk_Z_!DEDT8W$JUg+#bv@a4{*e2Fi(zE(;)kpP# zi!?~z0DKDfoqJWM`jT;hUZqEjb83rv!2f%yTh+tMT9wltRs(>aQWxnL`X8x5#Q!<9 zO}sBrU&OpvqMi?227DRtB3*}06MWUd%kjVk+ONj3N^PT^fw$p{Gjow@^go52EBaT| zD$LEdR0`wrH(CmF@$Uea(i?y)=x2a!w91#F4YU#P{nQQEOM3u!3x61}m+q#+fFZzs zv6c}|MmQPD(74YO{yE{F_aN(^hxGS-5Agj)yG+aJnC~*3q-TBK7W_v7m16ro#Zn*E zmA8~nu}+KdR|tQF@VkZ6E1X{8q=j=%;CX>h2)r!td4b;+_(RcGSjFB_Edsj*&T8!a zae?G#JRxwWz~cgE1wJnDiomM^Nf&*AvjQI%ctzk=5by)dIg$^pPg@jKqBe-hVQ!E6m!+h6p#sOo9Ujx<%SdSGz zfnEZ<0hOnLy9{tKcA6R`s0Gp%{4~_U3g9d7(`Y5F0=^1AjaJhd;A`;H@S=4s@U{49 z)Q;L!c(2$7JcTRPM8KtVCp}0%rC(vbA68jaQ2tq7$*PY_Sm8?db>=^(wj*aZ^2SAF zuHN~Z@OHo&zq<`08$skGh@Ndmv^JvLOheS~I^VW^%jjt5=Ftw?mdX??d;3_4+@2X7 z?aMmTx%5nLF6}s-TUcqAZB32fJu~ZpyoplhT%}IhQ_SVkV>$D9Ck^!Hi&LguqW0S3 zrfrVTW%gQA(`nnZS$#0;6!@AiY*A5 z+pa7SPOWrN^6Fw<>JAk11$2kJk)s}S!m>f8rwc_~U85%LOWO|IO^uo3Fh2>Jh7>IP4T?iG@9{NJ=#6tU>TlDl~Y9B69qIIu?DTvxZZ9S zycr8Mk~JHUmu~SUOO->TIbO1yQh>QG2>**G4Nd@b-khcJhW8ARbwxt`s*?08GgUd$;sU4pq|Onb*ZjD?+s zO|B3z<1VE#CLWrep3cp9IM-=!(Y8@DqU|lPqF%z0K3;S^Io3bH+!a?8J#@%AW$xk6 zvR-0236!%laxL9UDVrZR&rs>sf*gS=m!M0^t+HnZWzcQg=^1f{J0VYp{(FjPp2mz1 zQi0Mmj+3tx&fyuxrY!cqcwKjT7v4-2DGzx9XOX7yevf6WZGu+-#Woyi zJq39JJBWMn?&d762|5jVfldIc*mX5JJ&m+yom;IJUW(Mh9Ae1e+qX$)(4Hpyah(R0 z0hK^ZdGVfs_tI+N6zt?BGLD88I*219mdBZ{Wj`ndaA~2-=YHkE zBb{Y5d$I2(Lo!GQ@F& zDLi*zO~f`0{TXPN`p6040^$DjqD3CD@K8-iYPo2c$1N)5=RjKxAH$Y>2eju70vF6U zHs)*5OIJR3P)hP7^ipNr9nfD%YIn(IW#G7gy0N+c5aL)zAEBeL&DtgFbBA>eY___# zu=7v7^wqTUfjb}j<%xUlKC${0@+XuE`VypcAoyGc7!h=fu_#tlu_j+Y1sB#SUvOD7 z-gq;wnfxILA_4!hSW|FObVx-9V#(m5*gaaTDLSAhG}W|tah;|uip_o;+KXa`1>S=< zKF!JqiPnNTrC`yO8Lkn8q4^VdQVNn59pE1xu>=c{KN4wbYT6d4Ulcp47DdxqB*IuE zX2S7NgcDmC32HtqwlUVVD4H#)h+=Fi936;6LY1bvw1vMQI_wMT1anOwrR#Adg<>YM z5Ho$X+^vY~uu=Mi&ZxOvstJ`eYLGsb#R=KtsDcUNXyO#A1clym_-ua)kYcl+HGt24 zCgLX*WDt(%grtT!8F(btpzRNUfhIvD1qqHr5PW9G=tra93vKlo%XH1q{RYOvXT%oc zY{z*}Ga`XfYK`asSRFNp%Nr)e&uJlf0WVL4JoGv|sAW3$e=&z1>qj5Ji->P@hXchJ zOSgF3p(!F2Tf88F*A_R#b#Gp07AgZScT5eV% z{v`WOmV770cal@-OHzadVhm~sL!ngoXy$JWBU-};?ez2>D_`DTjhwKp(~g3kCVHC` zEl%y}AL+$&0-i_Oy&dESPHj$gz(AzFygT=vK=)v?PWWhAQ`r{L0!0CAm(4VuDun37 zw<`Q3o4OGA5X9-#<#Mr!+pbl z5Pjth^DiD4IJco?>#En6_xeqn$#eDU^PVg2PVHw;T|LmgS z`L3a(3b61+H_*G(osIyR|NW;5qI~^o5>t< zUW#zOj}*3AIsEwFP&Kq2gpWyS#l4*Noq(#Z*egAllnk{ z;>*qBKG?A2iH4sjDpB67E#6Awt*b(AtJ~a|kxD-J{}DKM-N+YjAEz*ay#3^D^xP~~ Y+Hfv^i;kV{{|xhgd;RYC?aRRb02;KsP5=M^ From 9d5cf67dfe2d5871d42a55a5e114c5ead1036ff0 Mon Sep 17 00:00:00 2001 From: 1hitsong <3330318+1hitsong@users.noreply.github.com> Date: Sat, 10 Sep 2022 14:58:03 -0400 Subject: [PATCH 028/245] Create ILyricsProvider --- Emby.Server.Implementations/Dto/DtoService.cs | 5 + Jellyfin.Api/Helpers/ItemHelper.cs | 135 ++++++++++-------- .../Models/UserDtos/ILyricsProvider.cs | 34 +++++ .../Models/UserDtos/LrcLyricsProvider.cs | 117 +++++++++++++++ Jellyfin.Api/Models/UserDtos/Lyric.cs | 18 +++ Jellyfin.Api/Models/UserDtos/Lyrics.cs | 23 --- .../Models/UserDtos/TxtLyricsProvider.cs | 81 +++++++++++ MediaBrowser.Model/Dto/BaseItemDto.cs | 2 + 8 files changed, 334 insertions(+), 81 deletions(-) create mode 100644 Jellyfin.Api/Models/UserDtos/ILyricsProvider.cs create mode 100644 Jellyfin.Api/Models/UserDtos/LrcLyricsProvider.cs create mode 100644 Jellyfin.Api/Models/UserDtos/Lyric.cs delete mode 100644 Jellyfin.Api/Models/UserDtos/Lyrics.cs create mode 100644 Jellyfin.Api/Models/UserDtos/TxtLyricsProvider.cs diff --git a/Emby.Server.Implementations/Dto/DtoService.cs b/Emby.Server.Implementations/Dto/DtoService.cs index 09ba368514..96717cff53 100644 --- a/Emby.Server.Implementations/Dto/DtoService.cs +++ b/Emby.Server.Implementations/Dto/DtoService.cs @@ -7,6 +7,7 @@ using System.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; +using Jellyfin.Api.Helpers; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; using Jellyfin.Extensions; @@ -139,6 +140,10 @@ namespace Emby.Server.Implementations.Dto { LivetvManager.AddInfoToProgramDto(new[] { (item, dto) }, options.Fields, user).GetAwaiter().GetResult(); } + else if (item is Audio) + { + dto.HasLocalLyricsFile = ItemHelper.HasLyricFile(item.Path); + } if (item is IItemByName itemByName && options.ContainsField(ItemFields.ItemCounts)) diff --git a/Jellyfin.Api/Helpers/ItemHelper.cs b/Jellyfin.Api/Helpers/ItemHelper.cs index c1b5ea6ccc..622eb0b9fe 100644 --- a/Jellyfin.Api/Helpers/ItemHelper.cs +++ b/Jellyfin.Api/Helpers/ItemHelper.cs @@ -23,79 +23,98 @@ namespace Jellyfin.Api.Helpers /// Collection of Lyrics. internal static object? GetLyricData(BaseItem item) { - List lyricsList = new List(); + List providerList = new List(); - string lrcFilePath = @Path.ChangeExtension(item.Path, "lrc"); + // Find all classes that implement ILyricsProvider Interface + var foundLyricProviders = System.Reflection.Assembly.GetExecutingAssembly() + .GetTypes() + .Where(type => typeof(ILyricsProvider).IsAssignableFrom(type) && !type.IsInterface); - // LRC File not found, fallback to TXT file - if (!System.IO.File.Exists(lrcFilePath)) - { - string txtFilePath = @Path.ChangeExtension(item.Path, "txt"); - if (!System.IO.File.Exists(txtFilePath)) - { - return null; - } - - var lyricTextData = System.IO.File.ReadAllText(txtFilePath); - string[] lyricTextLines = lyricTextData.Split(Environment.NewLine, StringSplitOptions.RemoveEmptyEntries); - - foreach (var lyricLine in lyricTextLines) - { - lyricsList.Add(new Lyrics { Text = lyricLine }); - } - - return new { lyrics = lyricsList }; - } - - // Process LRC File - Song lyricData; - List sortedLyricData = new List(); - var metaData = new ExpandoObject() as IDictionary; - string lrcFileContent = System.IO.File.ReadAllText(lrcFilePath); - - try - { - LyricParser lrcLyricParser = new LrcParser.Parser.Lrc.LrcParser(); - lyricData = lrcLyricParser.Decode(lrcFileContent); - var _metaData = lyricData.Lyrics - .Where(x => x.TimeTags.Count == 0) - .Where(x => x.Text.StartsWith("[", StringComparison.Ordinal) && x.Text.EndsWith("]", StringComparison.Ordinal)) - .Select(x => x.Text) - .ToList(); - - foreach (string dataRow in _metaData) - { - var data = dataRow.Split(":"); - - string newPropertyName = data[0].Replace("[", string.Empty, StringComparison.Ordinal); - string newPropertyValue = data[1].Replace("]", string.Empty, StringComparison.Ordinal); - - metaData.Add(newPropertyName, newPropertyValue); - } - - sortedLyricData = lyricData.Lyrics.Where(x => x.TimeTags.Count > 0).OrderBy(x => x.TimeTags.ToArray()[0].Value).ToList(); - } - catch + if (!foundLyricProviders.Any()) { return null; } - if (lyricData == null) + foreach (var provider in foundLyricProviders) + { + providerList.Add((ILyricsProvider)Activator.CreateInstance(provider)); + } + + foreach (ILyricsProvider provider in providerList) + { + provider.Process(item); + if (provider.HasData) + { + return provider.Data; + } + } + + return null; + } + + /// + /// Checks if requested item has a matching lyric file. + /// + /// Path of requested item. + /// True if item has a matching lyrics file. + public static string? GetLyricFilePath(string itemPath) + { + List supportedLyricFileExtensions = new List(); + + // Find all classes that implement ILyricsProvider Interface + var foundLyricProviders = System.Reflection.Assembly.GetExecutingAssembly() + .GetTypes() + .Where(type => typeof(ILyricsProvider).IsAssignableFrom(type) && !type.IsInterface); + + if (!foundLyricProviders.Any()) { return null; } - for (int i = 0; i < sortedLyricData.Count; i++) + // Iterate over all found lyric providers + foreach (var provider in foundLyricProviders) { - if (sortedLyricData[i].TimeTags.Count > 0) + var foundProvider = (ILyricsProvider)Activator.CreateInstance(provider); + if (foundProvider?.FileExtensions is null) { - var timeData = sortedLyricData[i].TimeTags.ToArray()[0].Value; - double ticks = Convert.ToDouble(timeData, new NumberFormatInfo()) * 10000; - lyricsList.Add(new Lyrics { Start = Math.Ceiling(ticks), Text = sortedLyricData[i].Text }); + continue; + } + + if (foundProvider.FileExtensions.Any()) + { + // Gather distinct list of handled file extentions + foreach (string lyricFileExtension in foundProvider.FileExtensions) + { + if (!supportedLyricFileExtensions.Contains(lyricFileExtension)) + { + supportedLyricFileExtensions.Add(lyricFileExtension); + } + } } } - return new { MetaData = metaData, lyrics = lyricsList }; + foreach (string lyricFileExtension in supportedLyricFileExtensions) + { + string lyricFilePath = @Path.ChangeExtension(itemPath, lyricFileExtension); + if (System.IO.File.Exists(lyricFilePath)) + { + return lyricFilePath; + } + } + + return null; + } + + + /// + /// Checks if requested item has a matching local lyric file. + /// + /// Path of requested item. + /// True if item has a matching lyrics file; otherwise false. + public static bool HasLyricFile(string itemPath) + { + string? lyricFilePath = GetLyricFilePath(itemPath); + return !string.IsNullOrEmpty(lyricFilePath); } } } diff --git a/Jellyfin.Api/Models/UserDtos/ILyricsProvider.cs b/Jellyfin.Api/Models/UserDtos/ILyricsProvider.cs new file mode 100644 index 0000000000..37f1f5bbe4 --- /dev/null +++ b/Jellyfin.Api/Models/UserDtos/ILyricsProvider.cs @@ -0,0 +1,34 @@ +using System.Collections.ObjectModel; +using MediaBrowser.Controller.Entities; + +namespace Jellyfin.Api.Models.UserDtos +{ + /// + /// Interface ILyricsProvider. + /// + public interface ILyricsProvider + { + /// + /// Gets a value indicating the File Extenstions this provider works with. + /// + public Collection? FileExtensions { get; } + + /// + /// Gets a value indicating whether Process() generated data. + /// + /// true if data generated; otherwise, false. + bool HasData { get; } + + /// + /// Gets Data object generated by Process() method. + /// + /// Object with data if no error occured; otherwise, null. + object? Data { get; } + + /// + /// Opens lyric file for [the specified item], and processes it for API return. + /// + /// The item to to process. + void Process(BaseItem item); + } +} diff --git a/Jellyfin.Api/Models/UserDtos/LrcLyricsProvider.cs b/Jellyfin.Api/Models/UserDtos/LrcLyricsProvider.cs new file mode 100644 index 0000000000..029acd6ca5 --- /dev/null +++ b/Jellyfin.Api/Models/UserDtos/LrcLyricsProvider.cs @@ -0,0 +1,117 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Dynamic; +using System.Globalization; +using System.Linq; +using LrcParser.Model; +using LrcParser.Parser; +using MediaBrowser.Controller.Entities; + +namespace Jellyfin.Api.Models.UserDtos +{ + /// + /// LRC File Lyric Provider. + /// + public class LrcLyricsProvider : ILyricsProvider + { + /// + /// Initializes a new instance of the class. + /// + public LrcLyricsProvider() + { + FileExtensions = new Collection + { + "lrc" + }; + } + + /// + /// Gets a value indicating the File Extenstions this provider works with. + /// + public Collection? FileExtensions { get; } + + /// + /// Gets or Sets a value indicating whether Process() generated data. + /// + /// true if data generated; otherwise, false. + public bool HasData { get; set; } + + /// + /// Gets or Sets Data object generated by Process() method. + /// + /// Object with data if no error occured; otherwise, null. + public object? Data { get; set; } + + /// + /// Opens lyric file for [the specified item], and processes it for API return. + /// + /// The item to to process. + public void Process(BaseItem item) + { + string? lyricFilePath = Helpers.ItemHelper.GetLyricFilePath(item.Path); + + if (string.IsNullOrEmpty(lyricFilePath)) + { + return; + } + + List lyricsList = new List(); + + List sortedLyricData = new List(); + var metaData = new ExpandoObject() as IDictionary; + string lrcFileContent = System.IO.File.ReadAllText(lyricFilePath); + + try + { + // Parse and sort lyric rows + LyricParser lrcLyricParser = new LrcParser.Parser.Lrc.LrcParser(); + Song lyricData = lrcLyricParser.Decode(lrcFileContent); + sortedLyricData = lyricData.Lyrics.Where(x => x.TimeTags.Count > 0).OrderBy(x => x.TimeTags.ToArray()[0].Value).ToList(); + + // Parse metadata rows + var metaDataRows = lyricData.Lyrics + .Where(x => x.TimeTags.Count == 0) + .Where(x => x.Text.StartsWith("[", StringComparison.Ordinal) && x.Text.EndsWith("]", StringComparison.Ordinal)) + .Select(x => x.Text) + .ToList(); + + foreach (string metaDataRow in metaDataRows) + { + var metaDataField = metaDataRow.Split(":"); + + string metaDataFieldName = metaDataField[0].Replace("[", string.Empty, StringComparison.Ordinal); + string metaDataFieldValue = metaDataField[1].Replace("]", string.Empty, StringComparison.Ordinal); + + metaData.Add(metaDataFieldName, metaDataFieldValue); + } + } + catch + { + return; + } + + if (!sortedLyricData.Any()) + { + return; + } + + for (int i = 0; i < sortedLyricData.Count; i++) + { + var timeData = sortedLyricData[i].TimeTags.ToArray()[0].Value; + double ticks = Convert.ToDouble(timeData, new NumberFormatInfo()) * 10000; + lyricsList.Add(new Lyric { Start = Math.Ceiling(ticks), Text = sortedLyricData[i].Text }); + } + + this.HasData = true; + if (metaData.Any()) + { + this.Data = new { MetaData = metaData, lyrics = lyricsList }; + } + else + { + this.Data = new { lyrics = lyricsList }; + } + } + } +} diff --git a/Jellyfin.Api/Models/UserDtos/Lyric.cs b/Jellyfin.Api/Models/UserDtos/Lyric.cs new file mode 100644 index 0000000000..2794cd78a0 --- /dev/null +++ b/Jellyfin.Api/Models/UserDtos/Lyric.cs @@ -0,0 +1,18 @@ +namespace Jellyfin.Api.Models.UserDtos +{ + /// + /// Lyric dto. + /// + public class Lyric + { + /// + /// Gets or sets the start time (ticks). + /// + public double Start { get; set; } + + /// + /// Gets or sets the text. + /// + public string Text { get; set; } = string.Empty; + } +} diff --git a/Jellyfin.Api/Models/UserDtos/Lyrics.cs b/Jellyfin.Api/Models/UserDtos/Lyrics.cs deleted file mode 100644 index cd548eb037..0000000000 --- a/Jellyfin.Api/Models/UserDtos/Lyrics.cs +++ /dev/null @@ -1,23 +0,0 @@ -namespace Jellyfin.Api.Models.UserDtos -{ - /// - /// Lyric dto. - /// - public class Lyrics - { - /// - /// Gets or sets the start. - /// - public double? Start { get; set; } - - /// - /// Gets or sets the text. - /// - public string? Text { get; set; } - - /// - /// Gets or sets the error. - /// - public string? Error { get; set; } - } -} diff --git a/Jellyfin.Api/Models/UserDtos/TxtLyricsProvider.cs b/Jellyfin.Api/Models/UserDtos/TxtLyricsProvider.cs new file mode 100644 index 0000000000..03cce1ffbb --- /dev/null +++ b/Jellyfin.Api/Models/UserDtos/TxtLyricsProvider.cs @@ -0,0 +1,81 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Dynamic; +using System.Globalization; +using System.Linq; +using LrcParser.Model; +using LrcParser.Parser; +using MediaBrowser.Controller.Entities; + +namespace Jellyfin.Api.Models.UserDtos +{ + /// + /// TXT File Lyric Provider. + /// + public class TxtLyricsProvider : ILyricsProvider + { + /// + /// Initializes a new instance of the class. + /// + public TxtLyricsProvider() + { + FileExtensions = new Collection + { + "lrc", "txt" + }; + } + + /// + /// Gets a value indicating the File Extenstions this provider works with. + /// + public Collection? FileExtensions { get; } + + /// + /// Gets or Sets a value indicating whether Process() generated data. + /// + /// true if data generated; otherwise, false. + public bool HasData { get; set; } + + /// + /// Gets or Sets Data object generated by Process() method. + /// + /// Object with data if no error occured; otherwise, null. + public object? Data { get; set; } + + /// + /// Opens lyric file for [the specified item], and processes it for API return. + /// + /// The item to to process. + public void Process(BaseItem item) + { + string? lyricFilePath = Helpers.ItemHelper.GetLyricFilePath(item.Path); + + if (string.IsNullOrEmpty(lyricFilePath)) + { + return; + } + + List lyricsList = new List(); + + string lyricData = System.IO.File.ReadAllText(lyricFilePath); + + // Splitting on Environment.NewLine caused some new lines to be missed in Windows. + char[] newLinedelims = new[] { '\r', '\n' }; + string[] lyricTextLines = lyricData.Split(newLinedelims, StringSplitOptions.RemoveEmptyEntries); + + if (!lyricTextLines.Any()) + { + return; + } + + foreach (string lyricLine in lyricTextLines) + { + lyricsList.Add(new Lyric { Text = lyricLine }); + } + + this.HasData = true; + this.Data = new { lyrics = lyricsList }; + } + } +} diff --git a/MediaBrowser.Model/Dto/BaseItemDto.cs b/MediaBrowser.Model/Dto/BaseItemDto.cs index fdb84fa320..b40a0210ad 100644 --- a/MediaBrowser.Model/Dto/BaseItemDto.cs +++ b/MediaBrowser.Model/Dto/BaseItemDto.cs @@ -76,6 +76,8 @@ namespace MediaBrowser.Model.Dto public bool? CanDownload { get; set; } + public bool? HasLocalLyricsFile { get; set; } + public bool? HasSubtitles { get; set; } public string PreferredMetadataLanguage { get; set; } From 97f8a63b8934ead26cfc7d41550188d86cada93a Mon Sep 17 00:00:00 2001 From: 1hitsong <3330318+1hitsong@users.noreply.github.com> Date: Sun, 11 Sep 2022 15:56:34 -0400 Subject: [PATCH 029/245] Allow LRC start value to be null --- Jellyfin.Api/Models/UserDtos/Lyric.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jellyfin.Api/Models/UserDtos/Lyric.cs b/Jellyfin.Api/Models/UserDtos/Lyric.cs index 2794cd78a0..f83fc9839b 100644 --- a/Jellyfin.Api/Models/UserDtos/Lyric.cs +++ b/Jellyfin.Api/Models/UserDtos/Lyric.cs @@ -8,7 +8,7 @@ namespace Jellyfin.Api.Models.UserDtos /// /// Gets or sets the start time (ticks). /// - public double Start { get; set; } + public double? Start { get; set; } /// /// Gets or sets the text. From 3928d02e175f732d5e13fa0c66dbccb704c4324d Mon Sep 17 00:00:00 2001 From: 1hitsong <3330318+1hitsong@users.noreply.github.com> Date: Sun, 11 Sep 2022 16:13:17 -0400 Subject: [PATCH 030/245] Resolve Possible null reference --- Jellyfin.Api/Helpers/ItemHelper.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Jellyfin.Api/Helpers/ItemHelper.cs b/Jellyfin.Api/Helpers/ItemHelper.cs index 622eb0b9fe..cd29361bd7 100644 --- a/Jellyfin.Api/Helpers/ItemHelper.cs +++ b/Jellyfin.Api/Helpers/ItemHelper.cs @@ -37,7 +37,11 @@ namespace Jellyfin.Api.Helpers foreach (var provider in foundLyricProviders) { - providerList.Add((ILyricsProvider)Activator.CreateInstance(provider)); + ILyricsProvider? newProvider = Activator.CreateInstance(provider) as ILyricsProvider; + if (newProvider is not null) + { + providerList.Add(newProvider); + } } foreach (ILyricsProvider provider in providerList) @@ -74,7 +78,7 @@ namespace Jellyfin.Api.Helpers // Iterate over all found lyric providers foreach (var provider in foundLyricProviders) { - var foundProvider = (ILyricsProvider)Activator.CreateInstance(provider); + ILyricsProvider? foundProvider = Activator.CreateInstance(provider) as ILyricsProvider; if (foundProvider?.FileExtensions is null) { continue; From cecca5f715f70b263f81b5c44dfcee5c38d53bf8 Mon Sep 17 00:00:00 2001 From: 1hitsong <3330318+1hitsong@users.noreply.github.com> Date: Sun, 11 Sep 2022 19:13:02 -0400 Subject: [PATCH 031/245] Remove unneeded 2nd loops --- .gitignore | 2 -- Jellyfin.Api/Helpers/ItemHelper.cs | 30 ++++++++---------------------- 2 files changed, 8 insertions(+), 24 deletions(-) diff --git a/.gitignore b/.gitignore index 3f80ffcf7d..c2ae76c1e3 100644 --- a/.gitignore +++ b/.gitignore @@ -281,5 +281,3 @@ apiclient/generated # Omnisharp crash logs mono_crash.*.json - -!LrcParser.dll \ No newline at end of file diff --git a/Jellyfin.Api/Helpers/ItemHelper.cs b/Jellyfin.Api/Helpers/ItemHelper.cs index cd29361bd7..0afe5a155d 100644 --- a/Jellyfin.Api/Helpers/ItemHelper.cs +++ b/Jellyfin.Api/Helpers/ItemHelper.cs @@ -40,16 +40,11 @@ namespace Jellyfin.Api.Helpers ILyricsProvider? newProvider = Activator.CreateInstance(provider) as ILyricsProvider; if (newProvider is not null) { - providerList.Add(newProvider); - } - } - - foreach (ILyricsProvider provider in providerList) - { - provider.Process(item); - if (provider.HasData) - { - return provider.Data; + newProvider.Process(item); + if (newProvider.HasData) + { + return newProvider.Data; + } } } @@ -86,26 +81,17 @@ namespace Jellyfin.Api.Helpers if (foundProvider.FileExtensions.Any()) { - // Gather distinct list of handled file extentions foreach (string lyricFileExtension in foundProvider.FileExtensions) { - if (!supportedLyricFileExtensions.Contains(lyricFileExtension)) + string lyricFilePath = @Path.ChangeExtension(itemPath, lyricFileExtension); + if (System.IO.File.Exists(lyricFilePath)) { - supportedLyricFileExtensions.Add(lyricFileExtension); + return lyricFilePath; } } } } - foreach (string lyricFileExtension in supportedLyricFileExtensions) - { - string lyricFilePath = @Path.ChangeExtension(itemPath, lyricFileExtension); - if (System.IO.File.Exists(lyricFilePath)) - { - return lyricFilePath; - } - } - return null; } From 31ec521f5ebfdffc1c38b4c67e7632933041a988 Mon Sep 17 00:00:00 2001 From: 1hitsong <3330318+1hitsong@users.noreply.github.com> Date: Sun, 11 Sep 2022 19:15:33 -0400 Subject: [PATCH 032/245] Remove now unused variables --- Jellyfin.Api/Helpers/ItemHelper.cs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Jellyfin.Api/Helpers/ItemHelper.cs b/Jellyfin.Api/Helpers/ItemHelper.cs index 0afe5a155d..49bb8af8e3 100644 --- a/Jellyfin.Api/Helpers/ItemHelper.cs +++ b/Jellyfin.Api/Helpers/ItemHelper.cs @@ -23,8 +23,6 @@ namespace Jellyfin.Api.Helpers /// Collection of Lyrics. internal static object? GetLyricData(BaseItem item) { - List providerList = new List(); - // Find all classes that implement ILyricsProvider Interface var foundLyricProviders = System.Reflection.Assembly.GetExecutingAssembly() .GetTypes() @@ -58,8 +56,6 @@ namespace Jellyfin.Api.Helpers /// True if item has a matching lyrics file. public static string? GetLyricFilePath(string itemPath) { - List supportedLyricFileExtensions = new List(); - // Find all classes that implement ILyricsProvider Interface var foundLyricProviders = System.Reflection.Assembly.GetExecutingAssembly() .GetTypes() From 61fa325ef05daac7c5105623d2de435ec94ef6a7 Mon Sep 17 00:00:00 2001 From: Shadowghost Date: Mon, 28 Mar 2022 23:11:21 +0200 Subject: [PATCH 033/245] Extend music parsing --- Emby.Naming/Common/NamingOptions.cs | 23 +++ .../Resolvers/Audio/MusicAlbumResolver.cs | 11 +- .../Entities/Audio/MusicAlbum.cs | 2 +- .../MediaBrowser.Providers.csproj | 1 + .../MediaInfo/FFProbeAudioInfo.cs | 127 +++++++++------ .../Music/AlbumMetadataService.cs | 152 ++++++++++++++++-- .../Music/AudioMetadataService.cs | 40 +++++ 7 files changed, 291 insertions(+), 65 deletions(-) diff --git a/Emby.Naming/Common/NamingOptions.cs b/Emby.Naming/Common/NamingOptions.cs index e016d7e51f..ddeec679d4 100644 --- a/Emby.Naming/Common/NamingOptions.cs +++ b/Emby.Naming/Common/NamingOptions.cs @@ -181,6 +181,24 @@ namespace Emby.Naming.Common "volume" }; + ArtistSubfolders = new[] + { + "albums", + "broadcasts", + "bootlegs", + "compilations", + "dj-mixes", + "eps", + "live", + "mixtapes", + "others", + "remixes", + "singles", + "soundtracks", + "spokenwords", + "streets" + }; + AudioFileExtensions = new[] { ".669", @@ -732,6 +750,11 @@ namespace Emby.Naming.Common /// public string[] AlbumStackingPrefixes { get; set; } + /// + /// Gets or sets list of artist subfolders. + /// + public string[] ArtistSubfolders { get; set; } + /// /// Gets or sets list of subtitle file extensions. /// diff --git a/Emby.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs b/Emby.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs index da00b9cfa8..5e05ddfb16 100644 --- a/Emby.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs +++ b/Emby.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -98,7 +99,15 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio // Args points to an album if parent is an Artist folder or it directly contains music if (args.IsDirectory) { - // if (args.Parent is MusicArtist) return true; // saves us from testing children twice + foreach (var subfolder in _namingOptions.ArtistSubfolders) + { + if (Path.GetDirectoryName(args.Path.AsSpan()).Equals(subfolder, StringComparison.OrdinalIgnoreCase)) + { + _logger.LogDebug("Found release folder: {Path}", args.Path); + return false; + } + } + if (ContainsMusic(args.FileSystemChildren, true, args.DirectoryService)) { return true; diff --git a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs index bd397bdd13..6555de8554 100644 --- a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs +++ b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs @@ -54,7 +54,7 @@ namespace MediaBrowser.Controller.Entities.Audio public string AlbumArtist => AlbumArtists.FirstOrDefault(); [JsonIgnore] - public override bool SupportsPeople => false; + public override bool SupportsPeople => true; /// /// Gets the tracks. diff --git a/MediaBrowser.Providers/MediaBrowser.Providers.csproj b/MediaBrowser.Providers/MediaBrowser.Providers.csproj index 9864db9ac2..459045dffc 100644 --- a/MediaBrowser.Providers/MediaBrowser.Providers.csproj +++ b/MediaBrowser.Providers/MediaBrowser.Providers.csproj @@ -22,6 +22,7 @@ + diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs b/MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs index f22965436f..e801a20efb 100644 --- a/MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs +++ b/MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -17,6 +18,7 @@ using MediaBrowser.Model.Dlna; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; using MediaBrowser.Model.MediaInfo; +using TagLib; namespace MediaBrowser.Providers.MediaInfo { @@ -93,7 +95,7 @@ namespace MediaBrowser.Providers.MediaInfo // var extension = (Path.GetExtension(audio.Path) ?? string.Empty).TrimStart('.'); // audio.Container = extension; - FetchDataFromTags(audio, mediaInfo); + FetchDataFromTags(audio); _itemRepo.SaveMediaStreams(audio.Id, mediaInfo.MediaStreams, cancellationToken); } @@ -102,71 +104,90 @@ namespace MediaBrowser.Providers.MediaInfo /// Fetches data from the tags dictionary. /// /// The audio. - /// The data. - private void FetchDataFromTags(Audio audio, Model.MediaInfo.MediaInfo data) + private void FetchDataFromTags(Audio audio) { - // Only set Name if title was found in the dictionary - if (!string.IsNullOrEmpty(data.Name)) + var file = TagLib.File.Create(audio.Path); + var tagTypes = file.TagTypesOnDisk; + Tag tags = null; + + if (tagTypes.HasFlag(TagTypes.Id3v2)) { - audio.Name = data.Name; + tags = file.GetTag(TagTypes.Id3v2); + } + else if (tagTypes.HasFlag(TagTypes.Ape)) + { + tags = file.GetTag(TagTypes.Ape); + } + else if (tagTypes.HasFlag(TagTypes.FlacMetadata)) + { + tags = file.GetTag(TagTypes.FlacMetadata); + } + else if (tagTypes.HasFlag(TagTypes.Id3v1)) + { + tags = file.GetTag(TagTypes.Id3v1); } - if (!string.IsNullOrEmpty(data.ForcedSortName)) + if (tags != null) { - audio.ForcedSortName = data.ForcedSortName; - } - - if (audio.SupportsPeople && !audio.LockedFields.Contains(MetadataField.Cast)) - { - var people = new List(); - - foreach (var person in data.People) + if (audio.SupportsPeople && !audio.LockedFields.Contains(MetadataField.Cast)) { - PeopleHelper.AddPerson(people, new PersonInfo + var people = new List(); + var albumArtists = tags.AlbumArtists; + foreach (var albumArtist in albumArtists) { - Name = person.Name, - Type = person.Type, - Role = person.Role - }); + PeopleHelper.AddPerson(people, new PersonInfo + { + Name = albumArtist, + Type = "AlbumArtist" + }); + } + + var performers = tags.Performers; + foreach (var performer in performers) + { + PeopleHelper.AddPerson(people, new PersonInfo + { + Name = performer, + Type = "Artist" + }); + } + + foreach (var composer in tags.Composers) + { + PeopleHelper.AddPerson(people, new PersonInfo + { + Name = composer, + Type = "Composer" + }); + } + + _libraryManager.UpdatePeople(audio, people); + audio.Artists = performers; + audio.AlbumArtists = albumArtists; } - _libraryManager.UpdatePeople(audio, people); - } - - audio.Album = data.Album; - audio.Artists = data.Artists; - audio.AlbumArtists = data.AlbumArtists; - audio.IndexNumber = data.IndexNumber; - audio.ParentIndexNumber = data.ParentIndexNumber; - audio.ProductionYear = data.ProductionYear; - audio.PremiereDate = data.PremiereDate; - - // If we don't have a ProductionYear try and get it from PremiereDate - if (audio.PremiereDate.HasValue && !audio.ProductionYear.HasValue) - { - audio.ProductionYear = audio.PremiereDate.Value.ToLocalTime().Year; - } - - if (!audio.LockedFields.Contains(MetadataField.Genres)) - { - audio.Genres = Array.Empty(); - - foreach (var genre in data.Genres) + audio.Name = tags.Title; + audio.Album = tags.Album; + audio.IndexNumber = Convert.ToInt32(tags.Track); + audio.ParentIndexNumber = Convert.ToInt32(tags.Disc); + if(tags.Year != 0) { - audio.AddGenre(genre); + var year = Convert.ToInt32(tags.Year); + audio.ProductionYear = year; + audio.PremiereDate = new DateTime(year, 01, 01); } - } - if (!audio.LockedFields.Contains(MetadataField.Studios)) - { - audio.SetStudios(data.Studios); - } + if (!audio.LockedFields.Contains(MetadataField.Genres)) + { + audio.Genres = tags.Genres.Distinct(StringComparer.OrdinalIgnoreCase).ToArray(); + } - audio.SetProviderId(MetadataProvider.MusicBrainzAlbumArtist, data.GetProviderId(MetadataProvider.MusicBrainzAlbumArtist)); - audio.SetProviderId(MetadataProvider.MusicBrainzArtist, data.GetProviderId(MetadataProvider.MusicBrainzArtist)); - audio.SetProviderId(MetadataProvider.MusicBrainzAlbum, data.GetProviderId(MetadataProvider.MusicBrainzAlbum)); - audio.SetProviderId(MetadataProvider.MusicBrainzReleaseGroup, data.GetProviderId(MetadataProvider.MusicBrainzReleaseGroup)); - audio.SetProviderId(MetadataProvider.MusicBrainzTrack, data.GetProviderId(MetadataProvider.MusicBrainzTrack)); + audio.SetProviderId(MetadataProvider.MusicBrainzArtist, tags.MusicBrainzArtistId); + audio.SetProviderId(MetadataProvider.MusicBrainzAlbumArtist, tags.MusicBrainzReleaseArtistId); + audio.SetProviderId(MetadataProvider.MusicBrainzAlbum, tags.MusicBrainzReleaseId); + audio.SetProviderId(MetadataProvider.MusicBrainzReleaseGroup, tags.MusicBrainzReleaseGroupId); + audio.SetProviderId(MetadataProvider.MusicBrainzTrack, tags.MusicBrainzTrackId); + } } } } diff --git a/MediaBrowser.Providers/Music/AlbumMetadataService.cs b/MediaBrowser.Providers/Music/AlbumMetadataService.cs index 7743d3b27b..b8426f31c1 100644 --- a/MediaBrowser.Providers/Music/AlbumMetadataService.cs +++ b/MediaBrowser.Providers/Music/AlbumMetadataService.cs @@ -61,40 +61,61 @@ namespace MediaBrowser.Providers.Music var songs = children.Cast