| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585 | 
							- using System;
 
- using System.Collections.Generic;
 
- using System.IO;
 
- using System.Linq;
 
- using System.Text;
 
- using System.Text.RegularExpressions;
 
- using Emby.Dlna.Profiles;
 
- using Emby.Dlna.Server;
 
- using MediaBrowser.Common.Configuration;
 
- using MediaBrowser.Common.Extensions;
 
- using MediaBrowser.Controller;
 
- using MediaBrowser.Controller.Dlna;
 
- using MediaBrowser.Controller.Drawing;
 
- using MediaBrowser.Model.Dlna;
 
- using MediaBrowser.Model.Drawing;
 
- using MediaBrowser.Model.IO;
 
- using MediaBrowser.Model.Reflection;
 
- using MediaBrowser.Model.Serialization;
 
- using Microsoft.Extensions.Logging;
 
- namespace Emby.Dlna
 
- {
 
-     public class DlnaManager : IDlnaManager
 
-     {
 
-         private readonly IApplicationPaths _appPaths;
 
-         private readonly IXmlSerializer _xmlSerializer;
 
-         private readonly IFileSystem _fileSystem;
 
-         private readonly ILogger _logger;
 
-         private readonly IJsonSerializer _jsonSerializer;
 
-         private readonly IServerApplicationHost _appHost;
 
-         private readonly IAssemblyInfo _assemblyInfo;
 
-         private readonly Dictionary<string, Tuple<InternalProfileInfo, DeviceProfile>> _profiles = new Dictionary<string, Tuple<InternalProfileInfo, DeviceProfile>>(StringComparer.Ordinal);
 
-         public DlnaManager(
 
-             IXmlSerializer xmlSerializer,
 
-             IFileSystem fileSystem,
 
-             IApplicationPaths appPaths,
 
-             ILoggerFactory loggerFactory,
 
-             IJsonSerializer jsonSerializer, IServerApplicationHost appHost, IAssemblyInfo assemblyInfo)
 
-         {
 
-             _xmlSerializer = xmlSerializer;
 
-             _fileSystem = fileSystem;
 
-             _appPaths = appPaths;
 
-             _logger = loggerFactory.CreateLogger("Dlna");
 
-             _jsonSerializer = jsonSerializer;
 
-             _appHost = appHost;
 
-             _assemblyInfo = assemblyInfo;
 
-         }
 
-         public void InitProfiles()
 
-         {
 
-             try
 
-             {
 
-                 ExtractSystemProfiles();
 
-                 LoadProfiles();
 
-             }
 
-             catch (Exception ex)
 
-             {
 
-                 _logger.LogError(ex, "Error extracting DLNA profiles.");
 
-             }
 
-         }
 
-         private void LoadProfiles()
 
-         {
 
-             var list = GetProfiles(UserProfilesPath, DeviceProfileType.User)
 
-                 .OrderBy(i => i.Name)
 
-                 .ToList();
 
-             list.AddRange(GetProfiles(SystemProfilesPath, DeviceProfileType.System)
 
-                 .OrderBy(i => i.Name));
 
-         }
 
-         public IEnumerable<DeviceProfile> GetProfiles()
 
-         {
 
-             lock (_profiles)
 
-             {
 
-                 var list = _profiles.Values.ToList();
 
-                 return list
 
-                     .OrderBy(i => i.Item1.Info.Type == DeviceProfileType.User ? 0 : 1)
 
-                     .ThenBy(i => i.Item1.Info.Name)
 
-                     .Select(i => i.Item2)
 
-                     .ToList();
 
-             }
 
-         }
 
-         public DeviceProfile GetDefaultProfile()
 
-         {
 
-             return new DefaultProfile();
 
-         }
 
-         public DeviceProfile GetProfile(DeviceIdentification deviceInfo)
 
-         {
 
-             if (deviceInfo == null)
 
-             {
 
-                 throw new ArgumentNullException(nameof(deviceInfo));
 
-             }
 
-             var profile = GetProfiles()
 
-                 .FirstOrDefault(i => i.Identification != null && IsMatch(deviceInfo, i.Identification));
 
-             if (profile != null)
 
-             {
 
-                 _logger.LogDebug("Found matching device profile: {0}", profile.Name);
 
-             }
 
-             else
 
-             {
 
-                 LogUnmatchedProfile(deviceInfo);
 
-             }
 
-             return profile;
 
-         }
 
-         private void LogUnmatchedProfile(DeviceIdentification profile)
 
-         {
 
-             var builder = new StringBuilder();
 
-             builder.AppendLine("No matching device profile found. The default will need to be used.");
 
-             builder.AppendLine(string.Format("DeviceDescription:{0}", profile.DeviceDescription ?? string.Empty));
 
-             builder.AppendLine(string.Format("FriendlyName:{0}", profile.FriendlyName ?? string.Empty));
 
-             builder.AppendLine(string.Format("Manufacturer:{0}", profile.Manufacturer ?? string.Empty));
 
-             builder.AppendLine(string.Format("ManufacturerUrl:{0}", profile.ManufacturerUrl ?? string.Empty));
 
-             builder.AppendLine(string.Format("ModelDescription:{0}", profile.ModelDescription ?? string.Empty));
 
-             builder.AppendLine(string.Format("ModelName:{0}", profile.ModelName ?? string.Empty));
 
-             builder.AppendLine(string.Format("ModelNumber:{0}", profile.ModelNumber ?? string.Empty));
 
-             builder.AppendLine(string.Format("ModelUrl:{0}", profile.ModelUrl ?? string.Empty));
 
-             builder.AppendLine(string.Format("SerialNumber:{0}", profile.SerialNumber ?? string.Empty));
 
-             _logger.LogInformation(builder.ToString());
 
-         }
 
-         private bool IsMatch(DeviceIdentification deviceInfo, DeviceIdentification profileInfo)
 
-         {
 
-             if (!string.IsNullOrEmpty(profileInfo.DeviceDescription))
 
-             {
 
-                 if (deviceInfo.DeviceDescription == null || !IsRegexMatch(deviceInfo.DeviceDescription, profileInfo.DeviceDescription))
 
-                     return false;
 
-             }
 
-             if (!string.IsNullOrEmpty(profileInfo.FriendlyName))
 
-             {
 
-                 if (deviceInfo.FriendlyName == null || !IsRegexMatch(deviceInfo.FriendlyName, profileInfo.FriendlyName))
 
-                     return false;
 
-             }
 
-             if (!string.IsNullOrEmpty(profileInfo.Manufacturer))
 
-             {
 
-                 if (deviceInfo.Manufacturer == null || !IsRegexMatch(deviceInfo.Manufacturer, profileInfo.Manufacturer))
 
-                     return false;
 
-             }
 
-             if (!string.IsNullOrEmpty(profileInfo.ManufacturerUrl))
 
-             {
 
-                 if (deviceInfo.ManufacturerUrl == null || !IsRegexMatch(deviceInfo.ManufacturerUrl, profileInfo.ManufacturerUrl))
 
-                     return false;
 
-             }
 
-             if (!string.IsNullOrEmpty(profileInfo.ModelDescription))
 
-             {
 
-                 if (deviceInfo.ModelDescription == null || !IsRegexMatch(deviceInfo.ModelDescription, profileInfo.ModelDescription))
 
-                     return false;
 
-             }
 
-             if (!string.IsNullOrEmpty(profileInfo.ModelName))
 
-             {
 
-                 if (deviceInfo.ModelName == null || !IsRegexMatch(deviceInfo.ModelName, profileInfo.ModelName))
 
-                     return false;
 
-             }
 
-             if (!string.IsNullOrEmpty(profileInfo.ModelNumber))
 
-             {
 
-                 if (deviceInfo.ModelNumber == null || !IsRegexMatch(deviceInfo.ModelNumber, profileInfo.ModelNumber))
 
-                     return false;
 
-             }
 
-             if (!string.IsNullOrEmpty(profileInfo.ModelUrl))
 
-             {
 
-                 if (deviceInfo.ModelUrl == null || !IsRegexMatch(deviceInfo.ModelUrl, profileInfo.ModelUrl))
 
-                     return false;
 
-             }
 
-             if (!string.IsNullOrEmpty(profileInfo.SerialNumber))
 
-             {
 
-                 if (deviceInfo.SerialNumber == null || !IsRegexMatch(deviceInfo.SerialNumber, profileInfo.SerialNumber))
 
-                     return false;
 
-             }
 
-             return true;
 
-         }
 
-         private bool IsRegexMatch(string input, string pattern)
 
-         {
 
-             try
 
-             {
 
-                 return Regex.IsMatch(input, pattern);
 
-             }
 
-             catch (ArgumentException ex)
 
-             {
 
-                 _logger.LogError(ex, "Error evaluating regex pattern {Pattern}", pattern);
 
-                 return false;
 
-             }
 
-         }
 
-         public DeviceProfile GetProfile(IDictionary<string, string> headers)
 
-         {
 
-             if (headers == null)
 
-             {
 
-                 throw new ArgumentNullException(nameof(headers));
 
-             }
 
-             // Convert to case insensitive
 
-             headers = new Dictionary<string, string>(headers, StringComparer.OrdinalIgnoreCase);
 
-             var profile = GetProfiles().FirstOrDefault(i => i.Identification != null && IsMatch(headers, i.Identification));
 
-             if (profile != null)
 
-             {
 
-                 _logger.LogDebug("Found matching device profile: {0}", profile.Name);
 
-             }
 
-             else
 
-             {
 
-                 var headerString = string.Join(", ", headers.Select(i => string.Format("{0}={1}", i.Key, i.Value)).ToArray());
 
-                 _logger.LogDebug("No matching device profile found. {0}", headerString);
 
-             }
 
-             return profile;
 
-         }
 
-         private bool IsMatch(IDictionary<string, string> headers, DeviceIdentification profileInfo)
 
-         {
 
-             return profileInfo.Headers.Any(i => IsMatch(headers, i));
 
-         }
 
-         private bool IsMatch(IDictionary<string, string> headers, HttpHeaderInfo header)
 
-         {
 
-             // Handle invalid user setup
 
-             if (string.IsNullOrEmpty(header.Name))
 
-             {
 
-                 return false;
 
-             }
 
-             if (headers.TryGetValue(header.Name, out string value))
 
-             {
 
-                 switch (header.Match)
 
-                 {
 
-                     case HeaderMatchType.Equals:
 
-                         return string.Equals(value, header.Value, StringComparison.OrdinalIgnoreCase);
 
-                     case HeaderMatchType.Substring:
 
-                         var isMatch = value.IndexOf(header.Value, StringComparison.OrdinalIgnoreCase) != -1;
 
-                         //_logger.LogDebug("IsMatch-Substring value: {0} testValue: {1} isMatch: {2}", value, header.Value, isMatch);
 
-                         return isMatch;
 
-                     case HeaderMatchType.Regex:
 
-                         return Regex.IsMatch(value, header.Value, RegexOptions.IgnoreCase);
 
-                     default:
 
-                         throw new ArgumentException("Unrecognized HeaderMatchType");
 
-                 }
 
-             }
 
-             return false;
 
-         }
 
-         private string UserProfilesPath => Path.Combine(_appPaths.ConfigurationDirectoryPath, "dlna", "user");
 
-         private string SystemProfilesPath => Path.Combine(_appPaths.ConfigurationDirectoryPath, "dlna", "system");
 
-         private IEnumerable<DeviceProfile> GetProfiles(string path, DeviceProfileType type)
 
-         {
 
-             try
 
-             {
 
-                 var xmlFies = _fileSystem.GetFilePaths(path)
 
-                     .Where(i => string.Equals(Path.GetExtension(i), ".xml", StringComparison.OrdinalIgnoreCase))
 
-                     .ToList();
 
-                 return xmlFies
 
-                     .Select(i => ParseProfileFile(i, type))
 
-                     .Where(i => i != null)
 
-                     .ToList();
 
-             }
 
-             catch (IOException)
 
-             {
 
-                 return new List<DeviceProfile>();
 
-             }
 
-         }
 
-         private DeviceProfile ParseProfileFile(string path, DeviceProfileType type)
 
-         {
 
-             lock (_profiles)
 
-             {
 
-                 if (_profiles.TryGetValue(path, out Tuple<InternalProfileInfo, DeviceProfile> profileTuple))
 
-                 {
 
-                     return profileTuple.Item2;
 
-                 }
 
-                 try
 
-                 {
 
-                     DeviceProfile profile;
 
-                     var tempProfile = (DeviceProfile)_xmlSerializer.DeserializeFromFile(typeof(DeviceProfile), path);
 
-                     profile = ReserializeProfile(tempProfile);
 
-                     profile.Id = path.ToLower().GetMD5().ToString("N");
 
-                     _profiles[path] = new Tuple<InternalProfileInfo, DeviceProfile>(GetInternalProfileInfo(_fileSystem.GetFileInfo(path), type), profile);
 
-                     return profile;
 
-                 }
 
-                 catch (Exception ex)
 
-                 {
 
-                     _logger.LogError(ex, "Error parsing profile file: {Path}", path);
 
-                     return null;
 
-                 }
 
-             }
 
-         }
 
-         public DeviceProfile GetProfile(string id)
 
-         {
 
-             if (string.IsNullOrEmpty(id))
 
-             {
 
-                 throw new ArgumentNullException(nameof(id));
 
-             }
 
-             var info = GetProfileInfosInternal().First(i => string.Equals(i.Info.Id, id, StringComparison.OrdinalIgnoreCase));
 
-             return ParseProfileFile(info.Path, info.Info.Type);
 
-         }
 
-         private IEnumerable<InternalProfileInfo> GetProfileInfosInternal()
 
-         {
 
-             lock (_profiles)
 
-             {
 
-                 var list = _profiles.Values.ToList();
 
-                 return list
 
-                     .Select(i => i.Item1)
 
-                     .OrderBy(i => i.Info.Type == DeviceProfileType.User ? 0 : 1)
 
-                     .ThenBy(i => i.Info.Name);
 
-             }
 
-         }
 
-         public IEnumerable<DeviceProfileInfo> GetProfileInfos()
 
-         {
 
-             return GetProfileInfosInternal().Select(i => i.Info);
 
-         }
 
-         private InternalProfileInfo GetInternalProfileInfo(FileSystemMetadata file, DeviceProfileType type)
 
-         {
 
-             return new InternalProfileInfo
 
-             {
 
-                 Path = file.FullName,
 
-                 Info = new DeviceProfileInfo
 
-                 {
 
-                     Id = file.FullName.ToLower().GetMD5().ToString("N"),
 
-                     Name = _fileSystem.GetFileNameWithoutExtension(file),
 
-                     Type = type
 
-                 }
 
-             };
 
-         }
 
-         private void ExtractSystemProfiles()
 
-         {
 
-             var namespaceName = GetType().Namespace + ".Profiles.Xml.";
 
-             var systemProfilesPath = SystemProfilesPath;
 
-             foreach (var name in _assemblyInfo.GetManifestResourceNames(GetType())
 
-                 .Where(i => i.StartsWith(namespaceName))
 
-                 .ToList())
 
-             {
 
-                 var filename = Path.GetFileName(name).Substring(namespaceName.Length);
 
-                 var path = Path.Combine(systemProfilesPath, filename);
 
-                 using (var stream = _assemblyInfo.GetManifestResourceStream(GetType(), name))
 
-                 {
 
-                     var fileInfo = _fileSystem.GetFileInfo(path);
 
-                     if (!fileInfo.Exists || fileInfo.Length != stream.Length)
 
-                     {
 
-                         _fileSystem.CreateDirectory(systemProfilesPath);
 
-                         using (var fileStream = _fileSystem.GetFileStream(path, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read))
 
-                         {
 
-                             stream.CopyTo(fileStream);
 
-                         }
 
-                     }
 
-                 }
 
-             }
 
-             // Not necessary, but just to make it easy to find
 
-             _fileSystem.CreateDirectory(UserProfilesPath);
 
-         }
 
-         public void DeleteProfile(string id)
 
-         {
 
-             var info = GetProfileInfosInternal().First(i => string.Equals(id, i.Info.Id, StringComparison.OrdinalIgnoreCase));
 
-             if (info.Info.Type == DeviceProfileType.System)
 
-             {
 
-                 throw new ArgumentException("System profiles cannot be deleted.");
 
-             }
 
-             _fileSystem.DeleteFile(info.Path);
 
-             lock (_profiles)
 
-             {
 
-                 _profiles.Remove(info.Path);
 
-             }
 
-         }
 
-         public void CreateProfile(DeviceProfile profile)
 
-         {
 
-             profile = ReserializeProfile(profile);
 
-             if (string.IsNullOrEmpty(profile.Name))
 
-             {
 
-                 throw new ArgumentException("Profile is missing Name");
 
-             }
 
-             var newFilename = _fileSystem.GetValidFilename(profile.Name) + ".xml";
 
-             var path = Path.Combine(UserProfilesPath, newFilename);
 
-             SaveProfile(profile, path, DeviceProfileType.User);
 
-         }
 
-         public void UpdateProfile(DeviceProfile profile)
 
-         {
 
-             profile = ReserializeProfile(profile);
 
-             if (string.IsNullOrEmpty(profile.Id))
 
-             {
 
-                 throw new ArgumentException("Profile is missing Id");
 
-             }
 
-             if (string.IsNullOrEmpty(profile.Name))
 
-             {
 
-                 throw new ArgumentException("Profile is missing Name");
 
-             }
 
-             var current = GetProfileInfosInternal().First(i => string.Equals(i.Info.Id, profile.Id, StringComparison.OrdinalIgnoreCase));
 
-             var newFilename = _fileSystem.GetValidFilename(profile.Name) + ".xml";
 
-             var path = Path.Combine(UserProfilesPath, newFilename);
 
-             if (!string.Equals(path, current.Path, StringComparison.Ordinal) &&
 
-                 current.Info.Type != DeviceProfileType.System)
 
-             {
 
-                 _fileSystem.DeleteFile(current.Path);
 
-             }
 
-             SaveProfile(profile, path, DeviceProfileType.User);
 
-         }
 
-         private void SaveProfile(DeviceProfile profile, string path, DeviceProfileType type)
 
-         {
 
-             lock (_profiles)
 
-             {
 
-                 _profiles[path] = new Tuple<InternalProfileInfo, DeviceProfile>(GetInternalProfileInfo(_fileSystem.GetFileInfo(path), type), profile);
 
-             }
 
-             SerializeToXml(profile, path);
 
-         }
 
-         internal void SerializeToXml(DeviceProfile profile, string path)
 
-         {
 
-             _xmlSerializer.SerializeToFile(profile, path);
 
-         }
 
-         /// <summary>
 
-         /// Recreates the object using serialization, to ensure it's not a subclass.
 
-         /// If it's a subclass it may not serlialize properly to xml (different root element tag name)
 
-         /// </summary>
 
-         /// <param name="profile"></param>
 
-         /// <returns></returns>
 
-         private DeviceProfile ReserializeProfile(DeviceProfile profile)
 
-         {
 
-             if (profile.GetType() == typeof(DeviceProfile))
 
-             {
 
-                 return profile;
 
-             }
 
-             var json = _jsonSerializer.SerializeToString(profile);
 
-             return _jsonSerializer.DeserializeFromString<DeviceProfile>(json);
 
-         }
 
-         class InternalProfileInfo
 
-         {
 
-             internal DeviceProfileInfo Info { get; set; }
 
-             internal string Path { get; set; }
 
-         }
 
-         public string GetServerDescriptionXml(IDictionary<string, string> headers, string serverUuId, string serverAddress)
 
-         {
 
-             var profile = GetProfile(headers) ??
 
-                           GetDefaultProfile();
 
-             var serverId = _appHost.SystemId;
 
-             return new DescriptionXmlBuilder(profile, serverUuId, serverAddress, _appHost.FriendlyName, serverId).GetXml();
 
-         }
 
-         public ImageStream GetIcon(string filename)
 
-         {
 
-             var format = filename.EndsWith(".png", StringComparison.OrdinalIgnoreCase)
 
-                 ? ImageFormat.Png
 
-                 : ImageFormat.Jpg;
 
-             var resource = GetType().Namespace + ".Images." + filename.ToLower();
 
-             return new ImageStream
 
-             {
 
-                 Format = format,
 
-                 Stream = _assemblyInfo.GetManifestResourceStream(GetType(), resource)
 
-             };
 
-         }
 
-     }
 
-     /*
 
-     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()
 
-         {
 
-         }
 
-     }*/
 
- }
 
 
  |