aboutsummaryrefslogtreecommitdiff
path: root/MediaBrowser.Dlna/DlnaManager.cs
diff options
context:
space:
mode:
Diffstat (limited to 'MediaBrowser.Dlna/DlnaManager.cs')
-rw-r--r--MediaBrowser.Dlna/DlnaManager.cs290
1 files changed, 279 insertions, 11 deletions
diff --git a/MediaBrowser.Dlna/DlnaManager.cs b/MediaBrowser.Dlna/DlnaManager.cs
index c6da865cd7..ec9ecb9ef2 100644
--- a/MediaBrowser.Dlna/DlnaManager.cs
+++ b/MediaBrowser.Dlna/DlnaManager.cs
@@ -1,9 +1,14 @@
using MediaBrowser.Common.Configuration;
+using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.IO;
using MediaBrowser.Controller.Dlna;
using MediaBrowser.Dlna.Profiles;
+using MediaBrowser.Model.Dlna;
+using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Serialization;
+using System;
using System.Collections.Generic;
+using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
@@ -11,22 +16,37 @@ namespace MediaBrowser.Dlna
{
public class DlnaManager : IDlnaManager
{
- private IApplicationPaths _appPaths;
+ private readonly IApplicationPaths _appPaths;
private readonly IXmlSerializer _xmlSerializer;
private readonly IFileSystem _fileSystem;
- private readonly IJsonSerializer _jsonSerializer;
+ private readonly ILogger _logger;
- public DlnaManager(IXmlSerializer xmlSerializer, IFileSystem fileSystem, IJsonSerializer jsonSerializer)
+ public DlnaManager(IXmlSerializer xmlSerializer, IFileSystem fileSystem, IApplicationPaths appPaths, ILogger logger)
{
_xmlSerializer = xmlSerializer;
_fileSystem = fileSystem;
- _jsonSerializer = jsonSerializer;
+ _appPaths = appPaths;
+ _logger = logger;
- GetProfiles();
+ //DumpProfiles();
}
public IEnumerable<DeviceProfile> GetProfiles()
{
+ ExtractProfilesIfNeeded();
+
+ var list = GetProfiles(UserProfilesPath, DeviceProfileType.User)
+ .OrderBy(i => i.Name)
+ .ToList();
+
+ list.AddRange(GetProfiles(SystemProfilesPath, DeviceProfileType.System)
+ .OrderBy(i => i.Name));
+
+ return list;
+ }
+
+ private void DumpProfiles()
+ {
var list = new List<DeviceProfile>
{
new SamsungSmartTvProfile(),
@@ -43,27 +63,72 @@ namespace MediaBrowser.Dlna
new WdtvLiveProfile(),
new DenonAvrProfile(),
new LinksysDMA2100Profile(),
- new LgTvProfile()
+ new LgTvProfile(),
+ new Foobar2000Profile(),
+ new DefaultProfile()
};
foreach (var item in list)
{
- //_xmlSerializer.SerializeToFile(item, "d:\\" + _fileSystem.GetValidFilename(item.Name) + ".xml");
- //_jsonSerializer.SerializeToFile(item, "d:\\" + _fileSystem.GetValidFilename(item.Name) + ".json");
+ var path = Path.Combine(_appPaths.ProgramDataPath, _fileSystem.GetValidFilename(item.Name) + ".xml");
+
+ _xmlSerializer.SerializeToFile(item, path);
}
+ }
- return list;
+ private bool _extracted;
+ private readonly object _syncLock = new object();
+ private void ExtractProfilesIfNeeded()
+ {
+ if (!_extracted)
+ {
+ lock (_syncLock)
+ {
+ if (!_extracted)
+ {
+ try
+ {
+ ExtractSystemProfiles();
+ }
+ catch (Exception ex)
+ {
+ _logger.ErrorException("Error extracting DLNA profiles.", ex);
+ }
+
+ _extracted = true;
+ }
+
+ }
+ }
}
public DeviceProfile GetDefaultProfile()
{
+ ExtractProfilesIfNeeded();
+
return new DefaultProfile();
}
public DeviceProfile GetProfile(DeviceIdentification deviceInfo)
{
- return GetProfiles().FirstOrDefault(i => IsMatch(deviceInfo, i.Identification)) ??
- GetDefaultProfile();
+ if (deviceInfo == null)
+ {
+ throw new ArgumentNullException("deviceInfo");
+ }
+
+ var profile = GetProfiles()
+ .FirstOrDefault(i => i.Identification != null && IsMatch(deviceInfo, i.Identification));
+
+ if (profile != null)
+ {
+ _logger.Debug("Found matching device profile: {0}", profile.Name);
+ }
+ else
+ {
+ _logger.Debug("No matching device profile found. The default will need to be used.");
+ }
+
+ return profile;
}
private bool IsMatch(DeviceIdentification deviceInfo, DeviceIdentification profileInfo)
@@ -124,5 +189,208 @@ namespace MediaBrowser.Dlna
return true;
}
+
+ public DeviceProfile GetProfile(IDictionary<string, string> headers)
+ {
+ if (headers == null)
+ {
+ throw new ArgumentNullException("headers");
+ }
+
+ return GetProfiles().FirstOrDefault(i => i.Identification != null && IsMatch(headers, i.Identification));
+ }
+
+ 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)
+ {
+ string value;
+
+ if (headers.TryGetValue(header.Name, out value))
+ {
+ switch (header.Match)
+ {
+ case HeaderMatchType.Equals:
+ return string.Equals(value, header.Value, StringComparison.OrdinalIgnoreCase);
+ case HeaderMatchType.Substring:
+ return value.IndexOf(header.Value, StringComparison.OrdinalIgnoreCase) != -1;
+ case HeaderMatchType.Regex:
+ return Regex.IsMatch(value, header.Value, RegexOptions.IgnoreCase);
+ default:
+ throw new ArgumentException("Unrecognized HeaderMatchType");
+ }
+ }
+
+ return false;
+ }
+
+ private string UserProfilesPath
+ {
+ get
+ {
+ return Path.Combine(_appPaths.ConfigurationDirectoryPath, "dlna", "user");
+ }
+ }
+
+ private string SystemProfilesPath
+ {
+ get
+ {
+ return Path.Combine(_appPaths.ConfigurationDirectoryPath, "dlna", "system");
+ }
+ }
+
+ private IEnumerable<DeviceProfile> GetProfiles(string path, DeviceProfileType type)
+ {
+ try
+ {
+ return new DirectoryInfo(path)
+ .EnumerateFiles("*", SearchOption.TopDirectoryOnly)
+ .Where(i => string.Equals(i.Extension, ".xml", StringComparison.OrdinalIgnoreCase))
+ .Select(i => ParseProfileXmlFile(i.FullName, type))
+ .Where(i => i != null)
+ .ToList();
+ }
+ catch (DirectoryNotFoundException)
+ {
+ return new List<DeviceProfile>();
+ }
+ }
+
+ private DeviceProfile ParseProfileXmlFile(string path, DeviceProfileType type)
+ {
+ try
+ {
+ var profile = (DeviceProfile)_xmlSerializer.DeserializeFromFile(typeof(DeviceProfile), path);
+
+ profile.Id = path.ToLower().GetMD5().ToString("N");
+ profile.ProfileType = type;
+
+ return profile;
+ }
+ catch (Exception ex)
+ {
+ _logger.ErrorException("Error parsing profile xml: {0}", ex, path);
+
+ return null;
+ }
+ }
+
+ public DeviceProfile GetProfile(string id)
+ {
+ if (string.IsNullOrWhiteSpace(id))
+ {
+ throw new ArgumentNullException("id");
+ }
+
+ var info = GetProfileInfosInternal().First(i => string.Equals(i.Info.Id, id));
+
+ return ParseProfileXmlFile(info.Path, info.Info.Type);
+ }
+
+ private IEnumerable<InternalProfileInfo> GetProfileInfosInternal()
+ {
+ ExtractProfilesIfNeeded();
+
+ return GetProfileInfos(UserProfilesPath, DeviceProfileType.User)
+ .Concat(GetProfileInfos(SystemProfilesPath, DeviceProfileType.System))
+ .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 IEnumerable<InternalProfileInfo> GetProfileInfos(string path, DeviceProfileType type)
+ {
+ try
+ {
+ return new DirectoryInfo(path)
+ .EnumerateFiles("*", SearchOption.TopDirectoryOnly)
+ .Where(i => string.Equals(i.Extension, ".xml", StringComparison.OrdinalIgnoreCase))
+ .Select(i => new InternalProfileInfo
+ {
+ Path = i.FullName,
+
+ Info = new DeviceProfileInfo
+ {
+ Id = i.FullName.ToLower().GetMD5().ToString("N"),
+ Name = Path.GetFileNameWithoutExtension(i.FullName),
+ Type = type
+ }
+ })
+ .ToList();
+ }
+ catch (DirectoryNotFoundException)
+ {
+ return new List<InternalProfileInfo>();
+ }
+ }
+
+ private void ExtractSystemProfiles()
+ {
+ var assembly = GetType().Assembly;
+ var namespaceName = GetType().Namespace + ".Profiles.Xml.";
+
+ var systemProfilesPath = SystemProfilesPath;
+
+ foreach (var name in assembly.GetManifestResourceNames()
+ .Where(i => i.StartsWith(namespaceName))
+ .ToList())
+ {
+ var filename = Path.GetFileName(name).Substring(namespaceName.Length);
+
+ var path = Path.Combine(systemProfilesPath, filename);
+
+ using (var stream = assembly.GetManifestResourceStream(name))
+ {
+ var fileInfo = new FileInfo(path);
+
+ if (!fileInfo.Exists || fileInfo.Length != stream.Length)
+ {
+ Directory.CreateDirectory(systemProfilesPath);
+
+ using (var fileStream = _fileSystem.GetFileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read))
+ {
+ stream.CopyTo(fileStream);
+ }
+ }
+ }
+ }
+
+ // Not necessary, but just to make it easy to find
+ Directory.CreateDirectory(UserProfilesPath);
+ }
+
+ public void DeleteProfile(string id)
+ {
+ var info = GetProfileInfosInternal().First(i => string.Equals(id, i.Info.Id));
+
+ if (info.Info.Type == DeviceProfileType.System)
+ {
+ throw new ArgumentException("System profiles cannot be deleted.");
+ }
+
+ File.Delete(info.Path);
+ }
+
+ public void CreateProfile(DeviceProfile profile)
+ {
+ }
+
+ public void UpdateProfile(DeviceProfile profile)
+ {
+ }
+
+ class InternalProfileInfo
+ {
+ internal DeviceProfileInfo Info { get; set; }
+ internal string Path { get; set; }
+ }
}
} \ No newline at end of file