From 31e8288393bead548e815a081c34d7e688fa0643 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Tue, 25 Mar 2014 17:13:55 -0400 Subject: make metadata path configurable --- MediaBrowser.ServerApplication/ApplicationHost.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'MediaBrowser.ServerApplication') diff --git a/MediaBrowser.ServerApplication/ApplicationHost.cs b/MediaBrowser.ServerApplication/ApplicationHost.cs index e49244edf0..351cbcfc86 100644 --- a/MediaBrowser.ServerApplication/ApplicationHost.cs +++ b/MediaBrowser.ServerApplication/ApplicationHost.cs @@ -795,7 +795,7 @@ namespace MediaBrowser.ServerApplication list.Add(typeof(ApiEntryPoint).Assembly); // Include composable parts in the Dashboard assembly - list.Add(typeof(DashboardInfo).Assembly); + list.Add(typeof(DashboardService).Assembly); // Include composable parts in the Model assembly list.Add(typeof(SystemInfo).Assembly); -- cgit v1.2.3 From 4e2764e516ba62506aa85765401769d0bc7192aa Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Wed, 26 Mar 2014 11:06:48 -0400 Subject: Create profile xml structure --- MediaBrowser.Api/Playback/BaseStreamingService.cs | 32 ++-- MediaBrowser.Api/Playback/StreamRequest.cs | 3 + MediaBrowser.Controller/Dlna/CodecProfile.cs | 12 ++ MediaBrowser.Controller/Dlna/ContainerProfile.cs | 4 + .../Dlna/DeviceIdentification.cs | 7 + MediaBrowser.Controller/Dlna/DeviceProfile.cs | 40 ++-- MediaBrowser.Controller/Dlna/DirectPlayProfile.cs | 7 + MediaBrowser.Controller/Dlna/IDlnaManager.cs | 22 ++- MediaBrowser.Controller/Dlna/MediaProfile.cs | 11 ++ MediaBrowser.Controller/Dlna/TranscodingProfile.cs | 14 ++ MediaBrowser.Dlna/DlnaManager.cs | 207 ++++++++++++++++++++- MediaBrowser.Dlna/MediaBrowser.Dlna.csproj | 22 ++- MediaBrowser.Dlna/PlayTo/CurrentIdEventArgs.cs | 14 +- MediaBrowser.Dlna/PlayTo/Device.cs | 7 +- MediaBrowser.Dlna/PlayTo/DlnaController.cs | 32 ++-- MediaBrowser.Dlna/PlayTo/PlaylistItem.cs | 2 + MediaBrowser.Dlna/PlayTo/StreamHelper.cs | 1 + MediaBrowser.Dlna/Profiles/DefaultProfile.cs | 2 + MediaBrowser.Dlna/Profiles/DenonAvrProfile.cs | 4 +- MediaBrowser.Dlna/Profiles/Foobar2000Profile.cs | 4 +- MediaBrowser.Dlna/Profiles/LgTvProfile.cs | 4 +- .../Profiles/LinksysDMA2100Profile.cs | 4 +- .../Profiles/PanasonicVieraProfile.cs | 36 ++-- .../Profiles/SamsungSmartTvProfile.cs | 4 +- .../Profiles/SonyBlurayPlayer2013Profile.cs | 4 +- .../Profiles/SonyBlurayPlayerProfile.cs | 4 +- .../Profiles/SonyBravia2010Profile.cs | 4 +- .../Profiles/SonyBravia2011Profile.cs | 4 +- .../Profiles/SonyBravia2012Profile.cs | 4 +- .../Profiles/SonyBravia2013Profile.cs | 4 +- MediaBrowser.Dlna/Profiles/SonyPs3Profile.cs | 4 +- MediaBrowser.Dlna/Profiles/WdtvLiveProfile.cs | 4 +- MediaBrowser.Dlna/Profiles/Xbox360Profile.cs | 4 +- MediaBrowser.Dlna/Profiles/XboxOneProfile.cs | 4 +- MediaBrowser.Dlna/Profiles/Xml/Default.xml | 39 ++++ MediaBrowser.Dlna/Profiles/Xml/Denon AVR.xml | 43 +++++ MediaBrowser.Dlna/Profiles/Xml/LG Smart TV.xml | 71 +++++++ MediaBrowser.Dlna/Profiles/Xml/Linksys DMA2100.xml | 43 +++++ MediaBrowser.Dlna/Profiles/Xml/Panasonic Viera.xml | 64 +++++++ .../Profiles/Xml/Samsung Smart TV.xml | 100 ++++++++++ .../Profiles/Xml/Sony Blu-ray Player 2013.xml | 67 +++++++ .../Profiles/Xml/Sony Blu-ray Player.xml | 95 ++++++++++ .../Profiles/Xml/Sony Bravia (2010).xml | 98 ++++++++++ .../Profiles/Xml/Sony Bravia (2011).xml | 101 ++++++++++ .../Profiles/Xml/Sony Bravia (2012).xml | 84 +++++++++ .../Profiles/Xml/Sony Bravia (2013).xml | 84 +++++++++ .../Profiles/Xml/Sony PlayStation 3.xml | 92 +++++++++ MediaBrowser.Dlna/Profiles/Xml/WDTV Live.xml | 78 ++++++++ MediaBrowser.Dlna/Profiles/Xml/Xbox 360.xml | 103 ++++++++++ MediaBrowser.Dlna/Profiles/Xml/Xbox One.xml | 45 +++++ MediaBrowser.Dlna/Profiles/Xml/foobar2000.xml | 45 +++++ .../MediaBrowser.Model.Portable.csproj | 3 + .../MediaBrowser.Model.net35.csproj | 3 + MediaBrowser.Model/Dlna/DeviceProfileInfo.cs | 30 +++ MediaBrowser.Model/MediaBrowser.Model.csproj | 1 + .../LiveTv/LiveTvManager.cs | 7 +- MediaBrowser.ServerApplication/ApplicationHost.cs | 10 +- .../MediaBrowser.WebDashboard.csproj | 8 +- 58 files changed, 1727 insertions(+), 122 deletions(-) create mode 100644 MediaBrowser.Dlna/Profiles/Xml/Default.xml create mode 100644 MediaBrowser.Dlna/Profiles/Xml/Denon AVR.xml create mode 100644 MediaBrowser.Dlna/Profiles/Xml/LG Smart TV.xml create mode 100644 MediaBrowser.Dlna/Profiles/Xml/Linksys DMA2100.xml create mode 100644 MediaBrowser.Dlna/Profiles/Xml/Panasonic Viera.xml create mode 100644 MediaBrowser.Dlna/Profiles/Xml/Samsung Smart TV.xml create mode 100644 MediaBrowser.Dlna/Profiles/Xml/Sony Blu-ray Player 2013.xml create mode 100644 MediaBrowser.Dlna/Profiles/Xml/Sony Blu-ray Player.xml create mode 100644 MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2010).xml create mode 100644 MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2011).xml create mode 100644 MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2012).xml create mode 100644 MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2013).xml create mode 100644 MediaBrowser.Dlna/Profiles/Xml/Sony PlayStation 3.xml create mode 100644 MediaBrowser.Dlna/Profiles/Xml/WDTV Live.xml create mode 100644 MediaBrowser.Dlna/Profiles/Xml/Xbox 360.xml create mode 100644 MediaBrowser.Dlna/Profiles/Xml/Xbox One.xml create mode 100644 MediaBrowser.Dlna/Profiles/Xml/foobar2000.xml create mode 100644 MediaBrowser.Model/Dlna/DeviceProfileInfo.cs (limited to 'MediaBrowser.ServerApplication') diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs index f65949ac7d..c365fcd829 100644 --- a/MediaBrowser.Api/Playback/BaseStreamingService.cs +++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs @@ -1210,85 +1210,89 @@ namespace MediaBrowser.Api.Playback if (i == 0) { - request.DeviceId = val; + request.DeviceProfileId = val; } else if (i == 1) { - request.MediaSourceId = val; + request.DeviceId = val; } else if (i == 2) { - request.Static = string.Equals("true", val, StringComparison.OrdinalIgnoreCase); + request.MediaSourceId = val; } else if (i == 3) + { + request.Static = string.Equals("true", val, StringComparison.OrdinalIgnoreCase); + } + else if (i == 4) { if (videoRequest != null) { videoRequest.VideoCodec = val; } } - else if (i == 4) + else if (i == 5) { request.AudioCodec = val; } - else if (i == 5) + else if (i == 6) { if (videoRequest != null) { videoRequest.AudioStreamIndex = int.Parse(val, UsCulture); } } - else if (i == 6) + else if (i == 7) { if (videoRequest != null) { videoRequest.SubtitleStreamIndex = int.Parse(val, UsCulture); } } - else if (i == 7) + else if (i == 8) { if (videoRequest != null) { videoRequest.VideoBitRate = int.Parse(val, UsCulture); } } - else if (i == 8) + else if (i == 9) { request.AudioBitRate = int.Parse(val, UsCulture); } - else if (i == 9) + else if (i == 10) { request.MaxAudioChannels = int.Parse(val, UsCulture); } - else if (i == 10) + else if (i == 11) { if (videoRequest != null) { videoRequest.MaxWidth = int.Parse(val, UsCulture); } } - else if (i == 11) + else if (i == 12) { if (videoRequest != null) { videoRequest.MaxHeight = int.Parse(val, UsCulture); } } - else if (i == 12) + else if (i == 13) { if (videoRequest != null) { videoRequest.Framerate = int.Parse(val, UsCulture); } } - else if (i == 13) + else if (i == 14) { if (videoRequest != null) { request.StartTimeTicks = long.Parse(val, UsCulture); } } - else if (i == 14) + else if (i == 15) { if (videoRequest != null) { diff --git a/MediaBrowser.Api/Playback/StreamRequest.cs b/MediaBrowser.Api/Playback/StreamRequest.cs index 8db5920f6b..0eb2984fb5 100644 --- a/MediaBrowser.Api/Playback/StreamRequest.cs +++ b/MediaBrowser.Api/Playback/StreamRequest.cs @@ -65,6 +65,9 @@ namespace MediaBrowser.Api.Playback [ApiMember(Name = "Static", Description = "Optional. If true, the original file will be streamed statically without any encoding. Use either no url extension or the original file extension. true/false", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")] public bool Static { get; set; } + [ApiMember(Name = "DeviceProfileId", Description = "Optional. The dlna device profile id to utilize.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] + public string DeviceProfileId { get; set; } + /// /// For testing purposes /// diff --git a/MediaBrowser.Controller/Dlna/CodecProfile.cs b/MediaBrowser.Controller/Dlna/CodecProfile.cs index 0f61cad98d..75f80ed3b1 100644 --- a/MediaBrowser.Controller/Dlna/CodecProfile.cs +++ b/MediaBrowser.Controller/Dlna/CodecProfile.cs @@ -1,13 +1,18 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Xml.Serialization; namespace MediaBrowser.Controller.Dlna { public class CodecProfile { + [XmlAttribute("type")] public CodecType Type { get; set; } + public ProfileCondition[] Conditions { get; set; } + + [XmlAttribute("codec")] public string Codec { get; set; } public CodecProfile() @@ -37,9 +42,16 @@ namespace MediaBrowser.Controller.Dlna public class ProfileCondition { + [XmlAttribute("condition")] public ProfileConditionType Condition { get; set; } + + [XmlAttribute("property")] public ProfileConditionValue Property { get; set; } + + [XmlAttribute("value")] public string Value { get; set; } + + [XmlAttribute("isRequired")] public bool IsRequired { get; set; } public ProfileCondition() diff --git a/MediaBrowser.Controller/Dlna/ContainerProfile.cs b/MediaBrowser.Controller/Dlna/ContainerProfile.cs index 3bd3c9eaf6..1029ba72cb 100644 --- a/MediaBrowser.Controller/Dlna/ContainerProfile.cs +++ b/MediaBrowser.Controller/Dlna/ContainerProfile.cs @@ -1,12 +1,16 @@ using System.Collections.Generic; using System.Linq; +using System.Xml.Serialization; namespace MediaBrowser.Controller.Dlna { public class ContainerProfile { + [XmlAttribute("type")] public DlnaProfileType Type { get; set; } public ProfileCondition[] Conditions { get; set; } + + [XmlAttribute("container")] public string Container { get; set; } public ContainerProfile() diff --git a/MediaBrowser.Controller/Dlna/DeviceIdentification.cs b/MediaBrowser.Controller/Dlna/DeviceIdentification.cs index 7b8e3a1e72..c9cd4bc703 100644 --- a/MediaBrowser.Controller/Dlna/DeviceIdentification.cs +++ b/MediaBrowser.Controller/Dlna/DeviceIdentification.cs @@ -1,4 +1,6 @@  +using System.Xml.Serialization; + namespace MediaBrowser.Controller.Dlna { public class DeviceIdentification @@ -62,8 +64,13 @@ namespace MediaBrowser.Controller.Dlna public class HttpHeaderInfo { + [XmlAttribute("name")] public string Name { get; set; } + + [XmlAttribute("value")] public string Value { get; set; } + + [XmlAttribute("match")] public HeaderMatchType Match { get; set; } } diff --git a/MediaBrowser.Controller/Dlna/DeviceProfile.cs b/MediaBrowser.Controller/Dlna/DeviceProfile.cs index f34c4bf645..f5aff02629 100644 --- a/MediaBrowser.Controller/Dlna/DeviceProfile.cs +++ b/MediaBrowser.Controller/Dlna/DeviceProfile.cs @@ -1,9 +1,12 @@ using MediaBrowser.Model.Entities; using System; using System.Linq; +using System.Runtime.Serialization; +using System.Xml.Serialization; namespace MediaBrowser.Controller.Dlna { + [XmlRoot("Profile")] public class DeviceProfile { /// @@ -12,19 +15,9 @@ namespace MediaBrowser.Controller.Dlna /// The name. public string Name { get; set; } - /// - /// Gets or sets the transcoding profiles. - /// - /// The transcoding profiles. - public TranscodingProfile[] TranscodingProfiles { get; set; } - - /// - /// Gets or sets the direct play profiles. - /// - /// The direct play profiles. - public DirectPlayProfile[] DirectPlayProfiles { get; set; } - - public ContainerProfile[] ContainerProfiles { get; set; } + [XmlIgnore] + [IgnoreDataMember] + public string Id { get; set; } /// /// Gets or sets the identification. @@ -57,14 +50,27 @@ namespace MediaBrowser.Controller.Dlna public string ProtocolInfo { get; set; } - public MediaProfile[] MediaProfiles { get; set; } - public CodecProfile[] CodecProfiles { get; set; } - public int TimelineOffsetSeconds { get; set; } - public bool RequiresPlainVideoItems { get; set; } public bool RequiresPlainFolders { get; set; } + /// + /// Gets or sets the direct play profiles. + /// + /// The direct play profiles. + public DirectPlayProfile[] DirectPlayProfiles { get; set; } + + /// + /// Gets or sets the transcoding profiles. + /// + /// The transcoding profiles. + public TranscodingProfile[] TranscodingProfiles { get; set; } + + public ContainerProfile[] ContainerProfiles { get; set; } + + public CodecProfile[] CodecProfiles { get; set; } + public MediaProfile[] MediaProfiles { get; set; } + public DeviceProfile() { DirectPlayProfiles = new DirectPlayProfile[] { }; diff --git a/MediaBrowser.Controller/Dlna/DirectPlayProfile.cs b/MediaBrowser.Controller/Dlna/DirectPlayProfile.cs index 686b31287e..ad70640daa 100644 --- a/MediaBrowser.Controller/Dlna/DirectPlayProfile.cs +++ b/MediaBrowser.Controller/Dlna/DirectPlayProfile.cs @@ -1,14 +1,21 @@ using System.Collections.Generic; using System.Linq; +using System.Xml.Serialization; namespace MediaBrowser.Controller.Dlna { public class DirectPlayProfile { + [XmlAttribute("container")] public string Container { get; set; } + + [XmlAttribute("audioCodec")] public string AudioCodec { get; set; } + + [XmlAttribute("videoCodec")] public string VideoCodec { get; set; } + [XmlAttribute("type")] public DlnaProfileType Type { get; set; } public List GetContainers() diff --git a/MediaBrowser.Controller/Dlna/IDlnaManager.cs b/MediaBrowser.Controller/Dlna/IDlnaManager.cs index 22d13fc3ad..dd9b0e8a84 100644 --- a/MediaBrowser.Controller/Dlna/IDlnaManager.cs +++ b/MediaBrowser.Controller/Dlna/IDlnaManager.cs @@ -1,20 +1,15 @@ -using System.Collections.Generic; +using MediaBrowser.Model.Dlna; +using System.Collections.Generic; namespace MediaBrowser.Controller.Dlna { public interface IDlnaManager { /// - /// Gets the dlna profiles. + /// Gets the profile infos. /// - /// IEnumerable{DlnaProfile}. - IEnumerable GetProfiles(); - - /// - /// Gets the default profile. - /// - /// DlnaProfile. - DeviceProfile GetDefaultProfile(); + /// IEnumerable{DeviceProfileInfo}. + IEnumerable GetProfileInfos(); /// /// Gets the profile. @@ -23,6 +18,13 @@ namespace MediaBrowser.Controller.Dlna /// DeviceProfile. DeviceProfile GetProfile(IDictionary headers); + /// + /// Gets the profile. + /// + /// The identifier. + /// DeviceProfile. + DeviceProfile GetProfile(string id); + /// /// Gets the profile. /// diff --git a/MediaBrowser.Controller/Dlna/MediaProfile.cs b/MediaBrowser.Controller/Dlna/MediaProfile.cs index 9a9b56ddd5..bf3057294c 100644 --- a/MediaBrowser.Controller/Dlna/MediaProfile.cs +++ b/MediaBrowser.Controller/Dlna/MediaProfile.cs @@ -1,16 +1,27 @@ using System.Collections.Generic; using System.Linq; +using System.Xml.Serialization; namespace MediaBrowser.Controller.Dlna { public class MediaProfile { + [XmlAttribute("container")] public string Container { get; set; } + + [XmlAttribute("audioCodec")] public string AudioCodec { get; set; } + + [XmlAttribute("videoCodec")] public string VideoCodec { get; set; } + [XmlAttribute("type")] public DlnaProfileType Type { get; set; } + + [XmlAttribute("orgPn")] public string OrgPn { get; set; } + + [XmlAttribute("mimeType")] public string MimeType { get; set; } public ProfileCondition[] Conditions { get; set; } diff --git a/MediaBrowser.Controller/Dlna/TranscodingProfile.cs b/MediaBrowser.Controller/Dlna/TranscodingProfile.cs index d4cfae9893..289333aa77 100644 --- a/MediaBrowser.Controller/Dlna/TranscodingProfile.cs +++ b/MediaBrowser.Controller/Dlna/TranscodingProfile.cs @@ -1,19 +1,30 @@ using System.Collections.Generic; using System.Linq; +using System.Xml.Serialization; namespace MediaBrowser.Controller.Dlna { public class TranscodingProfile { + [XmlAttribute("container")] public string Container { get; set; } + [XmlAttribute("type")] public DlnaProfileType Type { get; set; } + [XmlAttribute("videoCodec")] public string VideoCodec { get; set; } + + [XmlAttribute("audioCodec")] public string AudioCodec { get; set; } + [XmlAttribute("estimateContentLength")] public bool EstimateContentLength { get; set; } + + [XmlAttribute("enableMpegtsM2TsMode")] public bool EnableMpegtsM2TsMode { get; set; } + + [XmlAttribute("transcodeSeekInfo")] public TranscodeSeekInfo TranscodeSeekInfo { get; set; } public TranscodingSetting[] Settings { get; set; } @@ -32,7 +43,10 @@ namespace MediaBrowser.Controller.Dlna public class TranscodingSetting { + [XmlAttribute("name")] public TranscodingSettingType Name { get; set; } + + [XmlAttribute("value")] public string Value { get; set; } } diff --git a/MediaBrowser.Dlna/DlnaManager.cs b/MediaBrowser.Dlna/DlnaManager.cs index 78876d239c..9d9df01e6d 100644 --- a/MediaBrowser.Dlna/DlnaManager.cs +++ b/MediaBrowser.Dlna/DlnaManager.cs @@ -1,10 +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; @@ -12,21 +16,36 @@ 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 GetProfiles() + { + ExtractProfilesIfNeeded(); + + var list = GetProfiles(UserProfilesPath) + .OrderBy(i => i.Name) + .ToList(); + + list.AddRange(GetProfiles(SystemProfilesPath) + .OrderBy(i => i.Name)); + + return list; + } + + private void DumpProfiles() { var list = new List { @@ -45,16 +64,40 @@ namespace MediaBrowser.Dlna new DenonAvrProfile(), new LinksysDMA2100Profile(), new LgTvProfile(), - new Foobar2000Profile() + 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"); + _xmlSerializer.SerializeToFile(item, "d:\\" + _fileSystem.GetValidFilename(item.Name) + ".xml"); } + } - 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() @@ -64,8 +107,12 @@ namespace MediaBrowser.Dlna public DeviceProfile GetProfile(DeviceIdentification deviceInfo) { - return GetProfiles().FirstOrDefault(i => IsMatch(deviceInfo, i.Identification)) ?? + var profile = GetProfiles().FirstOrDefault(i => IsMatch(deviceInfo, i.Identification)) ?? GetDefaultProfile(); + + _logger.Debug("Found matching device profile: {0}", profile.Name); + + return profile; } private bool IsMatch(DeviceIdentification deviceInfo, DeviceIdentification profileInfo) @@ -159,5 +206,145 @@ namespace MediaBrowser.Dlna 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 GetProfiles(string path) + { + try + { + return new DirectoryInfo(path) + .EnumerateFiles("*", SearchOption.TopDirectoryOnly) + .Where(i => string.Equals(i.Extension, ".xml", StringComparison.OrdinalIgnoreCase)) + .Select(i => ParseProfileXmlFile(i.FullName)) + .Where(i => i != null) + .ToList(); + } + catch (DirectoryNotFoundException) + { + return new List(); + } + } + + private DeviceProfile ParseProfileXmlFile(string path) + { + try + { + var profile = (DeviceProfile)_xmlSerializer.DeserializeFromFile(typeof(DeviceProfile), path); + + profile.Id = path.ToLower().GetMD5().ToString("N"); + + return profile; + } + catch (Exception ex) + { + _logger.ErrorException("Error parsing profile xml: {0}", ex, path); + + return null; + } + } + + public DeviceProfile GetProfile(string id) + { + var info = GetProfileInfosInternal().First(i => string.Equals(i.Info.Id, id)); + + return ParseProfileXmlFile(info.Path); + } + + private IEnumerable 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 GetProfileInfos() + { + return GetProfileInfosInternal().Select(i => i.Info); + } + + private IEnumerable 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(); + } + } + + 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); + } + + class InternalProfileInfo + { + internal DeviceProfileInfo Info { get; set; } + internal string Path { get; set; } + } } } \ No newline at end of file diff --git a/MediaBrowser.Dlna/MediaBrowser.Dlna.csproj b/MediaBrowser.Dlna/MediaBrowser.Dlna.csproj index bdfcae39b6..df1fed12f0 100644 --- a/MediaBrowser.Dlna/MediaBrowser.Dlna.csproj +++ b/MediaBrowser.Dlna/MediaBrowser.Dlna.csproj @@ -117,7 +117,27 @@ MediaBrowser.Model - + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/MediaBrowser.MediaEncoding/Properties/AssemblyInfo.cs b/MediaBrowser.MediaEncoding/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..6616e46acc --- /dev/null +++ b/MediaBrowser.MediaEncoding/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("MediaBrowser.MediaEncoding")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("MediaBrowser.MediaEncoding")] +[assembly: AssemblyCopyright("Copyright © 2014")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("05f49ab9-2a90-4332-9d41-7817a9cccd90")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/MediaBrowser.MediaEncoding/packages.config b/MediaBrowser.MediaEncoding/packages.config new file mode 100644 index 0000000000..6e52b72b8f --- /dev/null +++ b/MediaBrowser.MediaEncoding/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs b/MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs index b3c3f278eb..b2ca97f55c 100644 --- a/MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs +++ b/MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs @@ -94,7 +94,7 @@ namespace MediaBrowser.Providers.MediaInfo { Directory.CreateDirectory(Path.GetDirectoryName(path)); - using (var stream = await _mediaEncoder.ExtractImage(new[] { item.Path }, InputType.File, true, null, null, cancellationToken).ConfigureAwait(false)) + using (var stream = await _mediaEncoder.ExtractAudioImage(item.Path, cancellationToken).ConfigureAwait(false)) { using (var fileStream = _fileSystem.GetFileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read, true)) { diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs index 58fe7f66d4..cb326c5ad0 100644 --- a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs +++ b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs @@ -113,8 +113,6 @@ namespace MediaBrowser.Providers.MediaInfo { cancellationToken.ThrowIfCancellationRequested(); - cancellationToken.ThrowIfCancellationRequested(); - var idString = item.Id.ToString("N"); var cachePath = Path.Combine(_appPaths.CachePath, "ffprobe-video", diff --git a/MediaBrowser.Providers/MediaInfo/VideoImageProvider.cs b/MediaBrowser.Providers/MediaInfo/VideoImageProvider.cs index 3547584979..70daa3f519 100644 --- a/MediaBrowser.Providers/MediaInfo/VideoImageProvider.cs +++ b/MediaBrowser.Providers/MediaInfo/VideoImageProvider.cs @@ -93,7 +93,7 @@ namespace MediaBrowser.Providers.MediaInfo var inputPath = MediaEncoderHelpers.GetInputArgument(item.Path, item.LocationType == LocationType.Remote, item.VideoType, item.IsoType, isoMount, item.PlayableStreamFileNames, out type); - var stream = await _mediaEncoder.ExtractImage(inputPath, type, false, item.Video3DFormat, imageOffset, cancellationToken).ConfigureAwait(false); + var stream = await _mediaEncoder.ExtractVideoImage(inputPath, type, item.Video3DFormat, imageOffset, cancellationToken).ConfigureAwait(false); return new DynamicImageResponse { diff --git a/MediaBrowser.Server.Implementations/BdInfo/BdInfoExaminer.cs b/MediaBrowser.Server.Implementations/BdInfo/BdInfoExaminer.cs deleted file mode 100644 index 18f1b92fe7..0000000000 --- a/MediaBrowser.Server.Implementations/BdInfo/BdInfoExaminer.cs +++ /dev/null @@ -1,185 +0,0 @@ -using BDInfo; -using MediaBrowser.Model.Entities; -using MediaBrowser.Model.MediaInfo; -using System; -using System.Collections.Generic; -using System.Linq; - -namespace MediaBrowser.Server.Implementations.BdInfo -{ - /// - /// Class BdInfoExaminer - /// - public class BdInfoExaminer : IBlurayExaminer - { - /// - /// Gets the disc info. - /// - /// The path. - /// BlurayDiscInfo. - public BlurayDiscInfo GetDiscInfo(string path) - { - var bdrom = new BDROM(path); - - bdrom.Scan(); - - // Get the longest playlist - var playlist = bdrom.PlaylistFiles.Values.OrderByDescending(p => p.TotalLength).FirstOrDefault(p => p.IsValid); - - var outputStream = new BlurayDiscInfo - { - MediaStreams = new List() - }; - - if (playlist == null) - { - return outputStream; - } - - outputStream.Chapters = playlist.Chapters; - - outputStream.RunTimeTicks = TimeSpan.FromSeconds(playlist.TotalLength).Ticks; - - var mediaStreams = new List { }; - - foreach (var stream in playlist.SortedStreams) - { - var videoStream = stream as TSVideoStream; - - if (videoStream != null) - { - AddVideoStream(mediaStreams, videoStream); - continue; - } - - var audioStream = stream as TSAudioStream; - - if (audioStream != null) - { - AddAudioStream(mediaStreams, audioStream); - continue; - } - - var textStream = stream as TSTextStream; - - if (textStream != null) - { - AddSubtitleStream(mediaStreams, textStream); - continue; - } - - var graphicsStream = stream as TSGraphicsStream; - - if (graphicsStream != null) - { - AddSubtitleStream(mediaStreams, graphicsStream); - } - } - - outputStream.MediaStreams = mediaStreams; - - outputStream.PlaylistName = playlist.Name; - - if (playlist.StreamClips != null && playlist.StreamClips.Any()) - { - // Get the files in the playlist - outputStream.Files = playlist.StreamClips.Select(i => i.StreamFile.Name).ToList(); - } - - return outputStream; - } - - /// - /// Adds the video stream. - /// - /// The streams. - /// The video stream. - private void AddVideoStream(List streams, TSVideoStream videoStream) - { - var mediaStream = new MediaStream - { - BitRate = Convert.ToInt32(videoStream.BitRate), - Width = videoStream.Width, - Height = videoStream.Height, - Codec = videoStream.CodecShortName, - IsInterlaced = videoStream.IsInterlaced, - Type = MediaStreamType.Video, - Index = streams.Count - }; - - if (videoStream.FrameRateDenominator > 0) - { - float frameRateEnumerator = videoStream.FrameRateEnumerator; - float frameRateDenominator = videoStream.FrameRateDenominator; - - mediaStream.AverageFrameRate = mediaStream.RealFrameRate = frameRateEnumerator / frameRateDenominator; - } - - streams.Add(mediaStream); - } - - /// - /// Adds the audio stream. - /// - /// The streams. - /// The audio stream. - private void AddAudioStream(List streams, TSAudioStream audioStream) - { - var stream = new MediaStream - { - Codec = audioStream.CodecShortName, - Language = audioStream.LanguageCode, - Channels = audioStream.ChannelCount, - SampleRate = audioStream.SampleRate, - Type = MediaStreamType.Audio, - Index = streams.Count - }; - - var bitrate = Convert.ToInt32(audioStream.BitRate); - - if (bitrate > 0) - { - stream.BitRate = bitrate; - } - - if (audioStream.LFE > 0) - { - stream.Channels = audioStream.ChannelCount + 1; - } - - streams.Add(stream); - } - - /// - /// Adds the subtitle stream. - /// - /// The streams. - /// The text stream. - private void AddSubtitleStream(List streams, TSTextStream textStream) - { - streams.Add(new MediaStream - { - Language = textStream.LanguageCode, - Codec = textStream.CodecShortName, - Type = MediaStreamType.Subtitle, - Index = streams.Count - }); - } - - /// - /// Adds the subtitle stream. - /// - /// The streams. - /// The text stream. - private void AddSubtitleStream(List streams, TSGraphicsStream textStream) - { - streams.Add(new MediaStream - { - Language = textStream.LanguageCode, - Codec = textStream.CodecShortName, - Type = MediaStreamType.Subtitle, - Index = streams.Count - }); - } - } -} diff --git a/MediaBrowser.Server.Implementations/IO/LibraryMonitor.cs b/MediaBrowser.Server.Implementations/IO/LibraryMonitor.cs index 0a0b3f4bcd..9279fd8d73 100644 --- a/MediaBrowser.Server.Implementations/IO/LibraryMonitor.cs +++ b/MediaBrowser.Server.Implementations/IO/LibraryMonitor.cs @@ -249,17 +249,24 @@ namespace MediaBrowser.Server.Implementations.IO // Creating a FileSystemWatcher over the LAN can take hundreds of milliseconds, so wrap it in a Task to do them all in parallel Task.Run(() => { - var newWatcher = new FileSystemWatcher(path, "*") { IncludeSubdirectories = true, InternalBufferSize = 32767 }; + try + { + var newWatcher = new FileSystemWatcher(path, "*") + { + IncludeSubdirectories = true, + InternalBufferSize = 32767 + }; - newWatcher.Created += watcher_Changed; - newWatcher.Deleted += watcher_Changed; - newWatcher.Renamed += watcher_Changed; - newWatcher.Changed += watcher_Changed; + newWatcher.NotifyFilter = NotifyFilters.CreationTime | NotifyFilters.DirectoryName | + NotifyFilters.FileName | NotifyFilters.LastWrite | NotifyFilters.Size; - newWatcher.Error += watcher_Error; + newWatcher.Created += watcher_Changed; + newWatcher.Deleted += watcher_Changed; + newWatcher.Renamed += watcher_Changed; + newWatcher.Changed += watcher_Changed; + + newWatcher.Error += watcher_Error; - try - { if (_fileSystemWatchers.TryAdd(path, newWatcher)) { newWatcher.EnableRaisingEvents = true; @@ -272,11 +279,7 @@ namespace MediaBrowser.Server.Implementations.IO } } - catch (IOException ex) - { - Logger.ErrorException("Error watching path: {0}", ex, path); - } - catch (PlatformNotSupportedException ex) + catch (Exception ex) { Logger.ErrorException("Error watching path: {0}", ex, path); } @@ -346,7 +349,9 @@ namespace MediaBrowser.Server.Implementations.IO { try { - OnWatcherChanged(e); + Logger.Debug("Watcher sees change of type " + e.ChangeType + " to " + e.FullPath); + + ReportFileSystemChanged(e.FullPath); } catch (Exception ex) { @@ -354,13 +359,6 @@ namespace MediaBrowser.Server.Implementations.IO } } - private void OnWatcherChanged(FileSystemEventArgs e) - { - Logger.Debug("Watcher sees change of type " + e.ChangeType + " to " + e.FullPath); - - ReportFileSystemChanged(e.FullPath); - } - public void ReportFileSystemChanged(string path) { if (string.IsNullOrEmpty(path)) @@ -370,12 +368,9 @@ namespace MediaBrowser.Server.Implementations.IO var filename = Path.GetFileName(path); - // Ignore certain files - if (!string.IsNullOrEmpty(filename) && _alwaysIgnoreFiles.Contains(filename, StringComparer.OrdinalIgnoreCase)) - { - return; - } + var monitorPath = !(!string.IsNullOrEmpty(filename) && _alwaysIgnoreFiles.Contains(filename, StringComparer.OrdinalIgnoreCase)); + // Ignore certain files var tempIgnorePaths = _tempIgnoredPaths.Keys.ToList(); // If the parent of an ignored path has a change event, ignore that too @@ -416,12 +411,15 @@ namespace MediaBrowser.Server.Implementations.IO })) { - return; + monitorPath = false; } - // Avoid implicitly captured closure - var affectedPath = path; - _affectedPaths.AddOrUpdate(path, path, (key, oldValue) => affectedPath); + if (monitorPath) + { + // Avoid implicitly captured closure + var affectedPath = path; + _affectedPaths.AddOrUpdate(path, path, (key, oldValue) => affectedPath); + } lock (_timerLock) { diff --git a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj index 73a12caf2c..ea7ef2ed65 100644 --- a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj +++ b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj @@ -48,14 +48,6 @@ ..\packages\Alchemy.2.2.1\lib\net40\Alchemy.dll - - False - ..\packages\MediaBrowser.BdInfo.1.0.0.10\lib\net35\BDInfo.dll - - - False - ..\packages\MediaBrowser.BdInfo.1.0.0.10\lib\net35\DvdLib.dll - False ..\packages\Mono.Nat.1.2.3\lib\Net40\Mono.Nat.dll @@ -105,7 +97,6 @@ Properties\SharedVersion.cs - @@ -191,7 +182,6 @@ - diff --git a/MediaBrowser.Server.Implementations/MediaEncoder/EncodingManager.cs b/MediaBrowser.Server.Implementations/MediaEncoder/EncodingManager.cs index f74865d2c7..7237ffee5c 100644 --- a/MediaBrowser.Server.Implementations/MediaEncoder/EncodingManager.cs +++ b/MediaBrowser.Server.Implementations/MediaEncoder/EncodingManager.cs @@ -178,7 +178,7 @@ namespace MediaBrowser.Server.Implementations.MediaEncoder { Directory.CreateDirectory(Path.GetDirectoryName(path)); - using (var stream = await _encoder.ExtractImage(inputPath, type, false, video.Video3DFormat, time, cancellationToken).ConfigureAwait(false)) + using (var stream = await _encoder.ExtractVideoImage(inputPath, type, video.Video3DFormat, time, cancellationToken).ConfigureAwait(false)) { using (var fileStream = _fileSystem.GetFileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read, true)) { diff --git a/MediaBrowser.Server.Implementations/MediaEncoder/MediaEncoder.cs b/MediaBrowser.Server.Implementations/MediaEncoder/MediaEncoder.cs deleted file mode 100644 index c646d80bce..0000000000 --- a/MediaBrowser.Server.Implementations/MediaEncoder/MediaEncoder.cs +++ /dev/null @@ -1,958 +0,0 @@ -using MediaBrowser.Common.Configuration; -using MediaBrowser.Common.IO; -using MediaBrowser.Controller.MediaEncoding; -using MediaBrowser.Model.Entities; -using MediaBrowser.Model.Logging; -using MediaBrowser.Model.Serialization; -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.ComponentModel; -using System.Diagnostics; -using System.Globalization; -using System.IO; -using System.Linq; -using System.Text; -using System.Threading; -using System.Threading.Tasks; - -namespace MediaBrowser.Server.Implementations.MediaEncoder -{ - /// - /// Class MediaEncoder - /// - public class MediaEncoder : IMediaEncoder, IDisposable - { - /// - /// The _logger - /// - private readonly ILogger _logger; - - /// - /// The _app paths - /// - private readonly IApplicationPaths _appPaths; - - /// - /// Gets the json serializer. - /// - /// The json serializer. - private readonly IJsonSerializer _jsonSerializer; - - /// - /// The video image resource pool - /// - private readonly SemaphoreSlim _videoImageResourcePool = new SemaphoreSlim(1, 1); - - /// - /// The audio image resource pool - /// - private readonly SemaphoreSlim _audioImageResourcePool = new SemaphoreSlim(2, 2); - - /// - /// The FF probe resource pool - /// - private readonly SemaphoreSlim _ffProbeResourcePool = new SemaphoreSlim(2, 2); - private readonly IFileSystem _fileSystem; - - public string FFMpegPath { get; private set; } - - public string FFProbePath { get; private set; } - - public string Version { get; private set; } - - public MediaEncoder(ILogger logger, IApplicationPaths appPaths, - IJsonSerializer jsonSerializer, string ffMpegPath, string ffProbePath, string version, IFileSystem fileSystem) - { - _logger = logger; - _appPaths = appPaths; - _jsonSerializer = jsonSerializer; - Version = version; - _fileSystem = fileSystem; - FFProbePath = ffProbePath; - FFMpegPath = ffMpegPath; - } - - /// - /// Gets the encoder path. - /// - /// The encoder path. - public string EncoderPath - { - get { return FFMpegPath; } - } - - /// - /// The _semaphoreLocks - /// - private readonly ConcurrentDictionary _semaphoreLocks = new ConcurrentDictionary(); - - /// - /// Gets the lock. - /// - /// The filename. - /// System.Object. - private SemaphoreSlim GetLock(string filename) - { - return _semaphoreLocks.GetOrAdd(filename, key => new SemaphoreSlim(1, 1)); - } - - /// - /// Gets the media info. - /// - /// The input files. - /// The type. - /// if set to true [is audio]. - /// The cancellation token. - /// Task. - public Task GetMediaInfo(string[] inputFiles, InputType type, bool isAudio, - CancellationToken cancellationToken) - { - return GetMediaInfoInternal(GetInputArgument(inputFiles, type), !isAudio, - GetProbeSizeArgument(type), cancellationToken); - } - - /// - /// Gets the input argument. - /// - /// The input files. - /// The type. - /// System.String. - /// Unrecognized InputType - public string GetInputArgument(string[] inputFiles, InputType type) - { - string inputPath; - - switch (type) - { - case InputType.Bluray: - case InputType.Dvd: - case InputType.File: - inputPath = GetConcatInputArgument(inputFiles); - break; - case InputType.Url: - inputPath = GetHttpInputArgument(inputFiles); - break; - default: - throw new ArgumentException("Unrecognized InputType"); - } - - return inputPath; - } - - /// - /// Gets the HTTP input argument. - /// - /// The input files. - /// System.String. - private string GetHttpInputArgument(string[] inputFiles) - { - var url = inputFiles[0]; - - return string.Format("\"{0}\"", url); - } - - /// - /// Gets the probe size argument. - /// - /// The type. - /// System.String. - public string GetProbeSizeArgument(InputType type) - { - return type == InputType.Dvd ? "-probesize 1G -analyzeduration 200M" : string.Empty; - } - - /// - /// Gets the media info internal. - /// - /// The input path. - /// if set to true [extract chapters]. - /// The probe size argument. - /// The cancellation token. - /// Task{MediaInfoResult}. - /// - private async Task GetMediaInfoInternal(string inputPath, bool extractChapters, - string probeSizeArgument, - CancellationToken cancellationToken) - { - var args = extractChapters - ? "{0} -i {1} -threads 0 -v info -print_format json -show_streams -show_chapters -show_format" - : "{0} -i {1} -threads 0 -v info -print_format json -show_streams -show_format"; - - var process = new Process - { - StartInfo = new ProcessStartInfo - { - CreateNoWindow = true, - UseShellExecute = false, - - // Must consume both or ffmpeg may hang due to deadlocks. See comments below. - RedirectStandardOutput = true, - RedirectStandardError = true, - FileName = FFProbePath, - Arguments = string.Format(args, - probeSizeArgument, inputPath).Trim(), - - WindowStyle = ProcessWindowStyle.Hidden, - ErrorDialog = false - }, - - EnableRaisingEvents = true - }; - - _logger.Debug("{0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments); - - process.Exited += ProcessExited; - - await _ffProbeResourcePool.WaitAsync(cancellationToken).ConfigureAwait(false); - - InternalMediaInfoResult result; - - try - { - process.Start(); - } - catch (Exception ex) - { - _ffProbeResourcePool.Release(); - - _logger.ErrorException("Error starting ffprobe", ex); - - throw; - } - - try - { - process.BeginErrorReadLine(); - - result = _jsonSerializer.DeserializeFromStream(process.StandardOutput.BaseStream); - } - catch - { - // Hate having to do this - try - { - process.Kill(); - } - catch (Exception ex1) - { - _logger.ErrorException("Error killing ffprobe", ex1); - } - - throw; - } - finally - { - _ffProbeResourcePool.Release(); - } - - if (result == null) - { - throw new ApplicationException(string.Format("FFProbe failed for {0}", inputPath)); - } - - cancellationToken.ThrowIfCancellationRequested(); - - if (result.streams != null) - { - // Normalize aspect ratio if invalid - foreach (var stream in result.streams) - { - if (string.Equals(stream.display_aspect_ratio, "0:1", StringComparison.OrdinalIgnoreCase)) - { - stream.display_aspect_ratio = string.Empty; - } - if (string.Equals(stream.sample_aspect_ratio, "0:1", StringComparison.OrdinalIgnoreCase)) - { - stream.sample_aspect_ratio = string.Empty; - } - } - } - - return result; - } - - /// - /// The us culture - /// - protected readonly CultureInfo UsCulture = new CultureInfo("en-US"); - - /// - /// Processes the exited. - /// - /// The sender. - /// The instance containing the event data. - private void ProcessExited(object sender, EventArgs e) - { - ((Process)sender).Dispose(); - } - - /// - /// Converts the text subtitle to ass. - /// - /// The input path. - /// The output path. - /// The language. - /// The cancellation token. - /// Task. - public async Task ConvertTextSubtitleToAss(string inputPath, string outputPath, string language, CancellationToken cancellationToken) - { - var semaphore = GetLock(outputPath); - - await semaphore.WaitAsync(cancellationToken).ConfigureAwait(false); - - try - { - if (!File.Exists(outputPath)) - { - await ConvertTextSubtitleToAssInternal(inputPath, outputPath, language).ConfigureAwait(false); - } - } - finally - { - semaphore.Release(); - } - } - - private const int FastSeekOffsetSeconds = 1; - - /// - /// Converts the text subtitle to ass. - /// - /// The input path. - /// The output path. - /// The language. - /// Task. - /// inputPath - /// or - /// outputPath - /// - private async Task ConvertTextSubtitleToAssInternal(string inputPath, string outputPath, string language) - { - if (string.IsNullOrEmpty(inputPath)) - { - throw new ArgumentNullException("inputPath"); - } - - if (string.IsNullOrEmpty(outputPath)) - { - throw new ArgumentNullException("outputPath"); - } - - - var encodingParam = string.IsNullOrEmpty(language) ? string.Empty : - GetSubtitleLanguageEncodingParam(language) + " "; - - var process = new Process - { - StartInfo = new ProcessStartInfo - { - RedirectStandardOutput = false, - RedirectStandardError = true, - - CreateNoWindow = true, - UseShellExecute = false, - FileName = FFMpegPath, - Arguments = - string.Format("{0} -i \"{1}\" -c:s ass \"{2}\"", encodingParam, inputPath, outputPath), - - WindowStyle = ProcessWindowStyle.Hidden, - ErrorDialog = false - } - }; - - _logger.Debug("{0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments); - - var logFilePath = Path.Combine(_appPaths.LogDirectoryPath, "ffmpeg-sub-convert-" + Guid.NewGuid() + ".txt"); - Directory.CreateDirectory(Path.GetDirectoryName(logFilePath)); - - var logFileStream = _fileSystem.GetFileStream(logFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, true); - - try - { - process.Start(); - } - catch (Exception ex) - { - logFileStream.Dispose(); - - _logger.ErrorException("Error starting ffmpeg", ex); - - throw; - } - - var logTask = process.StandardError.BaseStream.CopyToAsync(logFileStream); - - var ranToCompletion = process.WaitForExit(60000); - - if (!ranToCompletion) - { - try - { - _logger.Info("Killing ffmpeg subtitle conversion process"); - - process.Kill(); - - process.WaitForExit(1000); - - await logTask.ConfigureAwait(false); - } - catch (Exception ex) - { - _logger.ErrorException("Error killing subtitle conversion process", ex); - } - finally - { - logFileStream.Dispose(); - } - } - - var exitCode = ranToCompletion ? process.ExitCode : -1; - - process.Dispose(); - - var failed = false; - - if (exitCode == -1) - { - failed = true; - - if (File.Exists(outputPath)) - { - try - { - _logger.Info("Deleting converted subtitle due to failure: ", outputPath); - File.Delete(outputPath); - } - catch (IOException ex) - { - _logger.ErrorException("Error deleting converted subtitle {0}", ex, outputPath); - } - } - } - else if (!File.Exists(outputPath)) - { - failed = true; - } - - if (failed) - { - var msg = string.Format("ffmpeg subtitle converted failed for {0}", inputPath); - - _logger.Error(msg); - - throw new ApplicationException(msg); - } - await SetAssFont(outputPath).ConfigureAwait(false); - } - - protected string GetFastSeekCommandLineParameter(TimeSpan offset) - { - var seconds = offset.TotalSeconds - FastSeekOffsetSeconds; - - if (seconds > 0) - { - return string.Format("-ss {0} ", seconds.ToString(UsCulture)); - } - - return string.Empty; - } - - protected string GetSlowSeekCommandLineParameter(TimeSpan offset) - { - if (offset.TotalSeconds - FastSeekOffsetSeconds > 0) - { - return string.Format(" -ss {0}", FastSeekOffsetSeconds.ToString(UsCulture)); - } - - return string.Empty; - } - - /// - /// Gets the subtitle language encoding param. - /// - /// The language. - /// System.String. - private string GetSubtitleLanguageEncodingParam(string language) - { - switch (language.ToLower()) - { - case "pol": - case "cze": - case "ces": - case "slo": - case "slk": - case "hun": - case "slv": - case "srp": - case "hrv": - case "rum": - case "ron": - case "rup": - case "alb": - case "sqi": - return "-sub_charenc windows-1250"; - case "ara": - return "-sub_charenc windows-1256"; - case "heb": - return "-sub_charenc windows-1255"; - case "grc": - case "gre": - return "-sub_charenc windows-1253"; - case "crh": - case "ota": - case "tur": - return "-sub_charenc windows-1254"; - case "rus": - return "-sub_charenc windows-1251"; - case "vie": - return "-sub_charenc windows-1258"; - case "kor": - return "-sub_charenc cp949"; - default: - return "-sub_charenc windows-1252"; - } - } - - /// - /// Extracts the text subtitle. - /// - /// The input files. - /// The type. - /// Index of the subtitle stream. - /// if set to true, copy stream instead of converting. - /// The output path. - /// The cancellation token. - /// Task. - /// Must use inputPath list overload - public async Task ExtractTextSubtitle(string[] inputFiles, InputType type, int subtitleStreamIndex, bool copySubtitleStream, string outputPath, CancellationToken cancellationToken) - { - var semaphore = GetLock(outputPath); - - await semaphore.WaitAsync(cancellationToken).ConfigureAwait(false); - - try - { - if (!File.Exists(outputPath)) - { - await ExtractTextSubtitleInternal(GetInputArgument(inputFiles, type), subtitleStreamIndex, copySubtitleStream, outputPath, cancellationToken).ConfigureAwait(false); - } - } - finally - { - semaphore.Release(); - } - } - - /// - /// Extracts the text subtitle. - /// - /// The input path. - /// Index of the subtitle stream. - /// if set to true, copy stream instead of converting. - /// The output path. - /// The cancellation token. - /// Task. - /// inputPath - /// or - /// outputPath - /// or - /// cancellationToken - /// - private async Task ExtractTextSubtitleInternal(string inputPath, int subtitleStreamIndex, bool copySubtitleStream, string outputPath, CancellationToken cancellationToken) - { - if (string.IsNullOrEmpty(inputPath)) - { - throw new ArgumentNullException("inputPath"); - } - - if (string.IsNullOrEmpty(outputPath)) - { - throw new ArgumentNullException("outputPath"); - } - - string processArgs = string.Format("-i {0} -map 0:{1} -an -vn -c:s ass \"{2}\"", inputPath, subtitleStreamIndex, outputPath); - - if (copySubtitleStream) - { - processArgs = string.Format("-i {0} -map 0:{1} -an -vn -c:s copy \"{2}\"", inputPath, subtitleStreamIndex, outputPath); - } - - var process = new Process - { - StartInfo = new ProcessStartInfo - { - CreateNoWindow = true, - UseShellExecute = false, - - RedirectStandardOutput = false, - RedirectStandardError = true, - - FileName = FFMpegPath, - Arguments = processArgs, - WindowStyle = ProcessWindowStyle.Hidden, - ErrorDialog = false - } - }; - - _logger.Debug("{0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments); - - var logFilePath = Path.Combine(_appPaths.LogDirectoryPath, "ffmpeg-sub-extract-" + Guid.NewGuid() + ".txt"); - Directory.CreateDirectory(Path.GetDirectoryName(logFilePath)); - - var logFileStream = _fileSystem.GetFileStream(logFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, true); - - try - { - process.Start(); - } - catch (Exception ex) - { - logFileStream.Dispose(); - - _logger.ErrorException("Error starting ffmpeg", ex); - - throw; - } - - process.StandardError.BaseStream.CopyToAsync(logFileStream); - - var ranToCompletion = process.WaitForExit(60000); - - if (!ranToCompletion) - { - try - { - _logger.Info("Killing ffmpeg subtitle extraction process"); - - process.Kill(); - - process.WaitForExit(1000); - } - catch (Exception ex) - { - _logger.ErrorException("Error killing subtitle extraction process", ex); - } - finally - { - logFileStream.Dispose(); - } - } - - var exitCode = ranToCompletion ? process.ExitCode : -1; - - process.Dispose(); - - var failed = false; - - if (exitCode == -1) - { - failed = true; - - if (File.Exists(outputPath)) - { - try - { - _logger.Info("Deleting extracted subtitle due to failure: ", outputPath); - File.Delete(outputPath); - } - catch (IOException ex) - { - _logger.ErrorException("Error deleting extracted subtitle {0}", ex, outputPath); - } - } - } - else if (!File.Exists(outputPath)) - { - failed = true; - } - - if (failed) - { - var msg = string.Format("ffmpeg subtitle extraction failed for {0} to {1}", inputPath, outputPath); - - _logger.Error(msg); - - throw new ApplicationException(msg); - } - else - { - var msg = string.Format("ffmpeg subtitle extraction completed for {0} to {1}", inputPath, outputPath); - - _logger.Info(msg); - } - - await SetAssFont(outputPath).ConfigureAwait(false); - } - - /// - /// Sets the ass font. - /// - /// The file. - /// Task. - private async Task SetAssFont(string file) - { - _logger.Info("Setting ass font within {0}", file); - - string text; - Encoding encoding; - - using (var reader = new StreamReader(file, detectEncodingFromByteOrderMarks: true)) - { - encoding = reader.CurrentEncoding; - - text = await reader.ReadToEndAsync().ConfigureAwait(false); - } - - var newText = text.Replace(",Arial,", ",Arial Unicode MS,"); - - if (!string.Equals(text, newText)) - { - using (var writer = new StreamWriter(file, false, encoding)) - { - writer.Write(newText); - } - } - } - - public async Task ExtractImage(string[] inputFiles, InputType type, bool isAudio, - Video3DFormat? threedFormat, TimeSpan? offset, CancellationToken cancellationToken) - { - var resourcePool = isAudio ? _audioImageResourcePool : _videoImageResourcePool; - - var inputArgument = GetInputArgument(inputFiles, type); - - if (!isAudio) - { - try - { - return await ExtractImageInternal(inputArgument, type, threedFormat, offset, true, resourcePool, cancellationToken).ConfigureAwait(false); - } - catch - { - _logger.Error("I-frame image extraction failed, will attempt standard way. Input: {0}", inputArgument); - } - } - - return await ExtractImageInternal(inputArgument, type, threedFormat, offset, false, resourcePool, cancellationToken).ConfigureAwait(false); - } - - private async Task ExtractImageInternal(string inputPath, InputType type, Video3DFormat? threedFormat, TimeSpan? offset, bool useIFrame, SemaphoreSlim resourcePool, CancellationToken cancellationToken) - { - if (string.IsNullOrEmpty(inputPath)) - { - throw new ArgumentNullException("inputPath"); - } - - // apply some filters to thumbnail extracted below (below) crop any black lines that we made and get the correct ar then scale to width 600. - // This filter chain may have adverse effects on recorded tv thumbnails if ar changes during presentation ex. commercials @ diff ar - var vf = "scale=600:trunc(600/dar/2)*2"; - //crop=min(iw\,ih*dar):min(ih\,iw/dar):(iw-min(iw\,iw*sar))/2:(ih - min (ih\,ih/sar))/2,scale=600:(600/dar),thumbnail" -f image2 - - if (threedFormat.HasValue) - { - switch (threedFormat.Value) - { - case Video3DFormat.HalfSideBySide: - vf = "crop=iw/2:ih:0:0,scale=(iw*2):ih,setdar=dar=a,crop=min(iw\\,ih*dar):min(ih\\,iw/dar):(iw-min(iw\\,iw*sar))/2:(ih - min (ih\\,ih/sar))/2,setsar=sar=1,scale=600:trunc(600/dar/2)*2"; - // hsbs crop width in half,scale to correct size, set the display aspect,crop out any black bars we may have made the scale width to 600. Work out the correct height based on the display aspect it will maintain the aspect where -1 in this case (3d) may not. - break; - case Video3DFormat.FullSideBySide: - vf = "crop=iw/2:ih:0:0,setdar=dar=a,crop=min(iw\\,ih*dar):min(ih\\,iw/dar):(iw-min(iw\\,iw*sar))/2:(ih - min (ih\\,ih/sar))/2,setsar=sar=1,scale=600:trunc(600/dar/2)*2"; - //fsbs crop width in half,set the display aspect,crop out any black bars we may have made the scale width to 600. - break; - case Video3DFormat.HalfTopAndBottom: - vf = "crop=iw:ih/2:0:0,scale=(iw*2):ih),setdar=dar=a,crop=min(iw\\,ih*dar):min(ih\\,iw/dar):(iw-min(iw\\,iw*sar))/2:(ih - min (ih\\,ih/sar))/2,setsar=sar=1,scale=600:trunc(600/dar/2)*2"; - //htab crop heigh in half,scale to correct size, set the display aspect,crop out any black bars we may have made the scale width to 600 - break; - case Video3DFormat.FullTopAndBottom: - vf = "crop=iw:ih/2:0:0,setdar=dar=a,crop=min(iw\\,ih*dar):min(ih\\,iw/dar):(iw-min(iw\\,iw*sar))/2:(ih - min (ih\\,ih/sar))/2,setsar=sar=1,scale=600:trunc(600/dar/2)*2"; - // ftab crop heigt in half, set the display aspect,crop out any black bars we may have made the scale width to 600 - break; - } - } - - // Use ffmpeg to sample 100 (we can drop this if required using thumbnail=50 for 50 frames) frames and pick the best thumbnail. Have a fall back just in case. - var args = useIFrame ? string.Format("-i {0} -threads 0 -v quiet -vframes 1 -vf \"{2},thumbnail\" -f image2 \"{1}\"", inputPath, "-", vf) : - string.Format("-i {0} -threads 0 -v quiet -vframes 1 -vf \"{2}\" -f image2 \"{1}\"", inputPath, "-", vf); - - var probeSize = GetProbeSizeArgument(type); - - if (!string.IsNullOrEmpty(probeSize)) - { - args = probeSize + " " + args; - } - - if (offset.HasValue) - { - args = string.Format("-ss {0} ", Convert.ToInt32(offset.Value.TotalSeconds)).ToString(UsCulture) + args; - } - - var process = new Process - { - StartInfo = new ProcessStartInfo - { - CreateNoWindow = true, - UseShellExecute = false, - FileName = FFMpegPath, - Arguments = args, - WindowStyle = ProcessWindowStyle.Hidden, - ErrorDialog = false, - RedirectStandardOutput = true, - RedirectStandardError = true - } - }; - - await resourcePool.WaitAsync(cancellationToken).ConfigureAwait(false); - - process.Start(); - - var memoryStream = new MemoryStream(); - -#pragma warning disable 4014 - // Important - don't await the log task or we won't be able to kill ffmpeg when the user stops playback - process.StandardOutput.BaseStream.CopyToAsync(memoryStream); -#pragma warning restore 4014 - - // MUST read both stdout and stderr asynchronously or a deadlock may occurr - process.BeginErrorReadLine(); - - var ranToCompletion = process.WaitForExit(10000); - - if (!ranToCompletion) - { - try - { - _logger.Info("Killing ffmpeg process"); - - process.Kill(); - - process.WaitForExit(1000); - } - catch (Exception ex) - { - _logger.ErrorException("Error killing process", ex); - } - } - - resourcePool.Release(); - - var exitCode = ranToCompletion ? process.ExitCode : -1; - - process.Dispose(); - - if (exitCode == -1 || memoryStream.Length == 0) - { - memoryStream.Dispose(); - - var msg = string.Format("ffmpeg image extraction failed for {0}", inputPath); - - _logger.Error(msg); - - throw new ApplicationException(msg); - } - - memoryStream.Position = 0; - return memoryStream; - } - - /// - /// Starts the and wait for process. - /// - /// The process. - /// The timeout. - /// true if XXXX, false otherwise - private bool StartAndWaitForProcess(Process process, int timeout = 10000) - { - process.Start(); - - var ranToCompletion = process.WaitForExit(timeout); - - if (!ranToCompletion) - { - try - { - _logger.Info("Killing ffmpeg process"); - - process.Kill(); - - process.WaitForExit(1000); - } - catch (Win32Exception ex) - { - _logger.ErrorException("Error killing process", ex); - } - catch (InvalidOperationException ex) - { - _logger.ErrorException("Error killing process", ex); - } - catch (NotSupportedException ex) - { - _logger.ErrorException("Error killing process", ex); - } - } - - return ranToCompletion; - } - - /// - /// Gets the file input argument. - /// - /// The path. - /// System.String. - private string GetFileInputArgument(string path) - { - return string.Format("file:\"{0}\"", path); - } - - /// - /// Gets the concat input argument. - /// - /// The playable stream files. - /// System.String. - private string GetConcatInputArgument(string[] playableStreamFiles) - { - // Get all streams - // If there's more than one we'll need to use the concat command - if (playableStreamFiles.Length > 1) - { - var files = string.Join("|", playableStreamFiles); - - return string.Format("concat:\"{0}\"", files); - } - - // Determine the input path for video files - return GetFileInputArgument(playableStreamFiles[0]); - } - - /// - /// Gets the bluray input argument. - /// - /// The bluray root. - /// System.String. - private string GetBlurayInputArgument(string blurayRoot) - { - return string.Format("bluray:\"{0}\"", blurayRoot); - } - - /// - /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. - /// - public void Dispose() - { - Dispose(true); - } - - /// - /// Releases unmanaged and - optionally - managed resources. - /// - /// true to release both managed and unmanaged resources; false to release only unmanaged resources. - protected virtual void Dispose(bool dispose) - { - if (dispose) - { - _videoImageResourcePool.Dispose(); - } - } - } -} diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteMediaStreamsRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteMediaStreamsRepository.cs index f4e7fd0a6b..fde1e7f216 100644 --- a/MediaBrowser.Server.Implementations/Persistence/SqliteMediaStreamsRepository.cs +++ b/MediaBrowser.Server.Implementations/Persistence/SqliteMediaStreamsRepository.cs @@ -37,6 +37,8 @@ namespace MediaBrowser.Server.Implementations.Persistence var createTableCommand = "create table if not exists mediastreams "; + // Add PixelFormat column + createTableCommand += "(ItemId GUID, StreamIndex INT, StreamType TEXT, Codec TEXT, Language TEXT, ChannelLayout TEXT, Profile TEXT, AspectRatio TEXT, Path TEXT, IsInterlaced BIT, BitRate INT NULL, Channels INT NULL, SampleRate INT NULL, IsDefault BIT, IsForced BIT, IsExternal BIT, Height INT NULL, Width INT NULL, AverageFrameRate FLOAT NULL, RealFrameRate FLOAT NULL, Level FLOAT NULL, PRIMARY KEY (ItemId, StreamIndex))"; string[] queries = { diff --git a/MediaBrowser.Server.Implementations/packages.config b/MediaBrowser.Server.Implementations/packages.config index f04536190b..d82e880c98 100644 --- a/MediaBrowser.Server.Implementations/packages.config +++ b/MediaBrowser.Server.Implementations/packages.config @@ -1,7 +1,6 @@  - diff --git a/MediaBrowser.ServerApplication/ApplicationHost.cs b/MediaBrowser.ServerApplication/ApplicationHost.cs index fe7b17d1dd..dff6242d1a 100644 --- a/MediaBrowser.ServerApplication/ApplicationHost.cs +++ b/MediaBrowser.ServerApplication/ApplicationHost.cs @@ -33,13 +33,14 @@ using MediaBrowser.Controller.Sorting; using MediaBrowser.Controller.Themes; using MediaBrowser.Dlna; using MediaBrowser.Dlna.PlayTo; +using MediaBrowser.MediaEncoding.BdInfo; +using MediaBrowser.MediaEncoding.Encoder; using MediaBrowser.Model.Logging; using MediaBrowser.Model.MediaInfo; using MediaBrowser.Model.System; using MediaBrowser.Model.Updates; using MediaBrowser.Providers.Manager; using MediaBrowser.Server.Implementations; -using MediaBrowser.Server.Implementations.BdInfo; using MediaBrowser.Server.Implementations.Channels; using MediaBrowser.Server.Implementations.Collections; using MediaBrowser.Server.Implementations.Configuration; @@ -815,7 +816,10 @@ namespace MediaBrowser.ServerApplication // Server implementations list.Add(typeof(ServerApplicationPaths).Assembly); - // Dlna implementations + // MediaEncoding + list.Add(typeof(MediaEncoder).Assembly); + + // Dlna list.Add(typeof(PlayToServerEntryPoint).Assembly); list.AddRange(Assemblies.GetAssembliesWithParts()); diff --git a/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj b/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj index 227d0dd1d3..d999841ca7 100644 --- a/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj +++ b/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj @@ -195,6 +195,10 @@ {734098eb-6dc1-4dd0-a1ca-3140dcd2737c} MediaBrowser.Dlna + + {0bd82fa6-eb8a-4452-8af5-74f9c3849451} + MediaBrowser.MediaEncoding + {7eeeb4bb-f3e8-48fc-b4c5-70f0fff8329b} MediaBrowser.Model diff --git a/MediaBrowser.sln b/MediaBrowser.sln index 7ac1580659..7dc06fb0ce 100644 --- a/MediaBrowser.sln +++ b/MediaBrowser.sln @@ -41,6 +41,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.ServerApplicat EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Dlna", "MediaBrowser.Dlna\MediaBrowser.Dlna.csproj", "{734098EB-6DC1-4DD0-A1CA-3140DCD2737C}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.MediaEncoding", "MediaBrowser.MediaEncoding\MediaBrowser.MediaEncoding.csproj", "{0BD82FA6-EB8A-4452-8AF5-74F9C3849451}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -247,6 +249,20 @@ Global {734098EB-6DC1-4DD0-A1CA-3140DCD2737C}.Release|Win32.ActiveCfg = Release|Any CPU {734098EB-6DC1-4DD0-A1CA-3140DCD2737C}.Release|x64.ActiveCfg = Release|Any CPU {734098EB-6DC1-4DD0-A1CA-3140DCD2737C}.Release|x86.ActiveCfg = Release|Any CPU + {0BD82FA6-EB8A-4452-8AF5-74F9C3849451}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0BD82FA6-EB8A-4452-8AF5-74F9C3849451}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0BD82FA6-EB8A-4452-8AF5-74F9C3849451}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {0BD82FA6-EB8A-4452-8AF5-74F9C3849451}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {0BD82FA6-EB8A-4452-8AF5-74F9C3849451}.Debug|Win32.ActiveCfg = Debug|Any CPU + {0BD82FA6-EB8A-4452-8AF5-74F9C3849451}.Debug|x64.ActiveCfg = Debug|Any CPU + {0BD82FA6-EB8A-4452-8AF5-74F9C3849451}.Debug|x86.ActiveCfg = Debug|Any CPU + {0BD82FA6-EB8A-4452-8AF5-74F9C3849451}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0BD82FA6-EB8A-4452-8AF5-74F9C3849451}.Release|Any CPU.Build.0 = Release|Any CPU + {0BD82FA6-EB8A-4452-8AF5-74F9C3849451}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {0BD82FA6-EB8A-4452-8AF5-74F9C3849451}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {0BD82FA6-EB8A-4452-8AF5-74F9C3849451}.Release|Win32.ActiveCfg = Release|Any CPU + {0BD82FA6-EB8A-4452-8AF5-74F9C3849451}.Release|x64.ActiveCfg = Release|Any CPU + {0BD82FA6-EB8A-4452-8AF5-74F9C3849451}.Release|x86.ActiveCfg = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE -- cgit v1.2.3 From 1664de62c0571dc24e495f29e59f92a29a8b9b95 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Thu, 27 Mar 2014 23:32:43 -0400 Subject: added image encoder methods --- .../MediaEncoding/ImageEncodingOptions.cs | 2 + MediaBrowser.MediaEncoding/Encoder/ImageEncoder.cs | 65 +++++++++++----- MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs | 41 +--------- .../Drawing/ImageProcessor.cs | 87 ++++++++++++++-------- MediaBrowser.ServerApplication/ApplicationHost.cs | 14 ++-- MediaBrowser.sln | 3 + 6 files changed, 117 insertions(+), 95 deletions(-) (limited to 'MediaBrowser.ServerApplication') diff --git a/MediaBrowser.Controller/MediaEncoding/ImageEncodingOptions.cs b/MediaBrowser.Controller/MediaEncoding/ImageEncodingOptions.cs index c76977f29b..a8d1e5a0f1 100644 --- a/MediaBrowser.Controller/MediaEncoding/ImageEncodingOptions.cs +++ b/MediaBrowser.Controller/MediaEncoding/ImageEncodingOptions.cs @@ -13,6 +13,8 @@ namespace MediaBrowser.Controller.MediaEncoding public int? MaxHeight { get; set; } + public int? Quality { get; set; } + public string Format { get; set; } } } diff --git a/MediaBrowser.MediaEncoding/Encoder/ImageEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/ImageEncoder.cs index 5e4221b0f5..d259c631d0 100644 --- a/MediaBrowser.MediaEncoding/Encoder/ImageEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/ImageEncoder.cs @@ -1,4 +1,5 @@ -using MediaBrowser.Controller.MediaEncoding; +using MediaBrowser.Common.IO; +using MediaBrowser.Controller.MediaEncoding; using MediaBrowser.Model.Logging; using System; using System.Diagnostics; @@ -13,20 +14,39 @@ namespace MediaBrowser.MediaEncoding.Encoder { private readonly string _ffmpegPath; private readonly ILogger _logger; + private readonly IFileSystem _fileSystem; + private readonly CultureInfo _usCulture = new CultureInfo("en-US"); - private static readonly SemaphoreSlim ResourcePool = new SemaphoreSlim(5, 5); + private static readonly SemaphoreSlim ResourcePool = new SemaphoreSlim(10, 10); - public ImageEncoder(string ffmpegPath, ILogger logger) + public ImageEncoder(string ffmpegPath, ILogger logger, IFileSystem fileSystem) { _ffmpegPath = ffmpegPath; _logger = logger; + _fileSystem = fileSystem; } public async Task EncodeImage(ImageEncodingOptions options, CancellationToken cancellationToken) { ValidateInput(options); + await ResourcePool.WaitAsync(cancellationToken).ConfigureAwait(false); + + try + { + return await EncodeImageInternal(options, cancellationToken).ConfigureAwait(false); + } + finally + { + ResourcePool.Release(); + } + } + + private async Task EncodeImageInternal(ImageEncodingOptions options, CancellationToken cancellationToken) + { + ValidateInput(options); + var process = new Process { StartInfo = new ProcessStartInfo @@ -38,11 +58,12 @@ namespace MediaBrowser.MediaEncoding.Encoder WindowStyle = ProcessWindowStyle.Hidden, ErrorDialog = false, RedirectStandardOutput = true, - RedirectStandardError = true + RedirectStandardError = true, + WorkingDirectory = Path.GetDirectoryName(options.InputPath) } }; - await ResourcePool.WaitAsync(cancellationToken).ConfigureAwait(false); + _logger.Debug("ffmpeg " + process.StartInfo.Arguments); process.Start(); @@ -74,8 +95,6 @@ namespace MediaBrowser.MediaEncoding.Encoder } } - ResourcePool.Release(); - var exitCode = ranToCompletion ? process.ExitCode : -1; process.Dispose(); @@ -94,16 +113,21 @@ namespace MediaBrowser.MediaEncoding.Encoder memoryStream.Position = 0; return memoryStream; } - + private string GetArguments(ImageEncodingOptions options) { var vfScale = GetFilterGraph(options); - var outputFormat = GetOutputFormat(options); + var outputFormat = GetOutputFormat(options.Format); + + var quality = (options.Quality ?? 100) * .3; + quality = 31 - quality; + var qualityValue = Convert.ToInt32(Math.Max(quality, 1)); - return string.Format("-i file:\"{0}\" {1} -f {2}", - options.InputPath, + return string.Format("-f image2 -i file:\"{3}\" -q:v {0} {1} -f image2pipe -vcodec {2} -", + qualityValue.ToString(_usCulture), vfScale, - outputFormat); + outputFormat, + Path.GetFileName(options.InputPath)); } private string GetFilterGraph(ImageEncodingOptions options) @@ -121,7 +145,7 @@ namespace MediaBrowser.MediaEncoding.Encoder if (options.MaxWidth.HasValue) { - widthScale = "min(iw," + options.MaxWidth.Value.ToString(_usCulture) + ")"; + widthScale = "min(iw\\," + options.MaxWidth.Value.ToString(_usCulture) + ")"; } else if (options.Width.HasValue) { @@ -130,7 +154,7 @@ namespace MediaBrowser.MediaEncoding.Encoder if (options.MaxHeight.HasValue) { - heightScale = "min(ih," + options.MaxHeight.Value.ToString(_usCulture) + ")"; + heightScale = "min(ih\\," + options.MaxHeight.Value.ToString(_usCulture) + ")"; } else if (options.Height.HasValue) { @@ -139,15 +163,20 @@ namespace MediaBrowser.MediaEncoding.Encoder var scaleMethod = "lanczos"; - return string.Format("-vf scale=\"{0}:{1}\" -sws_flags {2}", - widthScale, + return string.Format("-vf scale=\"{0}:{1}\" -sws_flags {2}", + widthScale, heightScale, scaleMethod); } - private string GetOutputFormat(ImageEncodingOptions options) + private string GetOutputFormat(string format) { - return options.Format; + if (string.Equals(format, "jpeg", StringComparison.OrdinalIgnoreCase) || + string.Equals(format, "jpg", StringComparison.OrdinalIgnoreCase)) + { + return "mjpeg"; + } + return format; } private void ValidateInput(ImageEncodingOptions options) diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index 55035a4caf..8b41d2105f 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -879,45 +879,6 @@ namespace MediaBrowser.MediaEncoding.Encoder return memoryStream; } - /// - /// Starts the and wait for process. - /// - /// The process. - /// The timeout. - /// true if XXXX, false otherwise - private bool StartAndWaitForProcess(Process process, int timeout = 10000) - { - process.Start(); - - var ranToCompletion = process.WaitForExit(timeout); - - if (!ranToCompletion) - { - try - { - _logger.Info("Killing ffmpeg process"); - - process.Kill(); - - process.WaitForExit(1000); - } - catch (Win32Exception ex) - { - _logger.ErrorException("Error killing process", ex); - } - catch (InvalidOperationException ex) - { - _logger.ErrorException("Error killing process", ex); - } - catch (NotSupportedException ex) - { - _logger.ErrorException("Error killing process", ex); - } - } - - return ranToCompletion; - } - /// /// Gets the file input argument. /// @@ -950,7 +911,7 @@ namespace MediaBrowser.MediaEncoding.Encoder public Task EncodeImage(ImageEncodingOptions options, CancellationToken cancellationToken) { - return new ImageEncoder(FFMpegPath, _logger).EncodeImage(options, cancellationToken); + return new ImageEncoder(FFMpegPath, _logger, _fileSystem).EncodeImage(options, cancellationToken); } /// diff --git a/MediaBrowser.Server.Implementations/Drawing/ImageProcessor.cs b/MediaBrowser.Server.Implementations/Drawing/ImageProcessor.cs index 12d3eadfd3..408d8c9b1f 100644 --- a/MediaBrowser.Server.Implementations/Drawing/ImageProcessor.cs +++ b/MediaBrowser.Server.Implementations/Drawing/ImageProcessor.cs @@ -3,6 +3,7 @@ using MediaBrowser.Common.IO; using MediaBrowser.Controller; using MediaBrowser.Controller.Drawing; using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.MediaEncoding; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Drawing; using MediaBrowser.Model.Entities; @@ -52,12 +53,14 @@ namespace MediaBrowser.Server.Implementations.Drawing private readonly IFileSystem _fileSystem; private readonly IJsonSerializer _jsonSerializer; private readonly IServerApplicationPaths _appPaths; + private readonly IMediaEncoder _mediaEncoder; - public ImageProcessor(ILogger logger, IServerApplicationPaths appPaths, IFileSystem fileSystem, IJsonSerializer jsonSerializer) + public ImageProcessor(ILogger logger, IServerApplicationPaths appPaths, IFileSystem fileSystem, IJsonSerializer jsonSerializer, IMediaEncoder mediaEncoder) { _logger = logger; _fileSystem = fileSystem; _jsonSerializer = jsonSerializer; + _mediaEncoder = mediaEncoder; _appPaths = appPaths; _saveImageSizeTimer = new Timer(SaveImageSizeCallback, null, Timeout.Infinite, Timeout.Infinite); @@ -66,7 +69,7 @@ namespace MediaBrowser.Server.Implementations.Drawing try { - sizeDictionary = jsonSerializer.DeserializeFromFile>(ImageSizeFile) ?? + sizeDictionary = jsonSerializer.DeserializeFromFile>(ImageSizeFile) ?? new Dictionary(); } catch (FileNotFoundException) @@ -213,6 +216,39 @@ namespace MediaBrowser.Server.Implementations.Drawing try { + var hasPostProcessing = !string.IsNullOrEmpty(options.BackgroundColor) || options.UnplayedCount.HasValue || options.AddPlayedIndicator || options.PercentPlayed.HasValue; + + if (!hasPostProcessing) + { + using (var outputStream = await _mediaEncoder.EncodeImage(new ImageEncodingOptions + { + InputPath = originalImagePath, + MaxHeight = options.MaxHeight, + MaxWidth = options.MaxWidth, + Height = options.Height, + Width = options.Width, + Quality = options.Quality, + Format = options.OutputFormat == ImageOutputFormat.Original ? Path.GetExtension(originalImagePath).TrimStart('.') : options.OutputFormat.ToString().ToLower() + + }, CancellationToken.None).ConfigureAwait(false)) + { + using (var outputMemoryStream = new MemoryStream()) + { + // Save to the memory stream + await outputStream.CopyToAsync(outputMemoryStream).ConfigureAwait(false); + + var bytes = outputMemoryStream.ToArray(); + + await toStream.WriteAsync(bytes, 0, bytes.Length).ConfigureAwait(false); + + // kick off a task to cache the result + await CacheResizedImage(cacheFilePath, bytes).ConfigureAwait(false); + } + + return; + } + } + using (var fileStream = _fileSystem.GetFileStream(originalImagePath, FileMode.Open, FileAccess.Read, FileShare.Read, true)) { // Copy to memory stream to avoid Image locking file @@ -241,8 +277,8 @@ namespace MediaBrowser.Server.Implementations.Drawing thumbnailGraph.SmoothingMode = SmoothingMode.HighQuality; thumbnailGraph.InterpolationMode = InterpolationMode.HighQualityBicubic; thumbnailGraph.PixelOffsetMode = PixelOffsetMode.HighQuality; - thumbnailGraph.CompositingMode = string.IsNullOrEmpty(options.BackgroundColor) && !options.UnplayedCount.HasValue && !options.AddPlayedIndicator && !options.PercentPlayed.HasValue ? - CompositingMode.SourceCopy : + thumbnailGraph.CompositingMode = !hasPostProcessing ? + CompositingMode.SourceCopy : CompositingMode.SourceOver; SetBackgroundColor(thumbnailGraph, options); @@ -263,7 +299,7 @@ namespace MediaBrowser.Server.Implementations.Drawing await toStream.WriteAsync(bytes, 0, bytes.Length).ConfigureAwait(false); // kick off a task to cache the result - CacheResizedImage(cacheFilePath, bytes, semaphore); + await CacheResizedImage(cacheFilePath, bytes).ConfigureAwait(false); } } } @@ -272,11 +308,9 @@ namespace MediaBrowser.Server.Implementations.Drawing } } } - catch + finally { semaphore.Release(); - - throw; } } @@ -285,33 +319,26 @@ namespace MediaBrowser.Server.Implementations.Drawing /// /// The cache file path. /// The bytes. - /// The semaphore. - private void CacheResizedImage(string cacheFilePath, byte[] bytes, SemaphoreSlim semaphore) + /// Task. + private async Task CacheResizedImage(string cacheFilePath, byte[] bytes) { - Task.Run(async () => + try { - try - { - var parentPath = Path.GetDirectoryName(cacheFilePath); + var parentPath = Path.GetDirectoryName(cacheFilePath); - Directory.CreateDirectory(parentPath); + Directory.CreateDirectory(parentPath); - // Save to the cache location - using (var cacheFileStream = _fileSystem.GetFileStream(cacheFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, true)) - { - // Save to the filestream - await cacheFileStream.WriteAsync(bytes, 0, bytes.Length).ConfigureAwait(false); - } - } - catch (Exception ex) - { - _logger.ErrorException("Error writing to image cache file {0}", ex, cacheFilePath); - } - finally + // Save to the cache location + using (var cacheFileStream = _fileSystem.GetFileStream(cacheFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, true)) { - semaphore.Release(); + // Save to the filestream + await cacheFileStream.WriteAsync(bytes, 0, bytes.Length).ConfigureAwait(false); } - }); + } + catch (Exception ex) + { + _logger.ErrorException("Error writing to image cache file {0}", ex, cacheFilePath); + } } /// @@ -519,7 +546,7 @@ namespace MediaBrowser.Server.Implementations.Drawing { filename += "iv=" + IndicatorVersion; } - + if (!string.IsNullOrEmpty(backgroundColor)) { filename += "b=" + backgroundColor; diff --git a/MediaBrowser.ServerApplication/ApplicationHost.cs b/MediaBrowser.ServerApplication/ApplicationHost.cs index 6083158bcc..b7e9017d6e 100644 --- a/MediaBrowser.ServerApplication/ApplicationHost.cs +++ b/MediaBrowser.ServerApplication/ApplicationHost.cs @@ -473,7 +473,13 @@ namespace MediaBrowser.ServerApplication LocalizationManager = new LocalizationManager(ServerConfigurationManager, FileSystemManager); RegisterSingleInstance(LocalizationManager); - ImageProcessor = new ImageProcessor(LogManager.GetLogger("ImageProcessor"), ServerConfigurationManager.ApplicationPaths, FileSystemManager, JsonSerializer); + var innerProgress = new ActionableProgress(); + innerProgress.RegisterAction(p => progress.Report((.75 * p) + 15)); + + await RegisterMediaEncoder(innerProgress).ConfigureAwait(false); + progress.Report(90); + + ImageProcessor = new ImageProcessor(LogManager.GetLogger("ImageProcessor"), ServerConfigurationManager.ApplicationPaths, FileSystemManager, JsonSerializer, MediaEncoder); RegisterSingleInstance(ImageProcessor); DtoService = new DtoService(Logger, LibraryManager, UserManager, UserDataManager, ItemRepository, ImageProcessor, ServerConfigurationManager, FileSystemManager, ProviderManager); @@ -487,12 +493,6 @@ namespace MediaBrowser.ServerApplication progress.Report(15); - var innerProgress = new ActionableProgress(); - innerProgress.RegisterAction(p => progress.Report((.75 * p) + 15)); - - await RegisterMediaEncoder(innerProgress).ConfigureAwait(false); - progress.Report(90); - EncodingManager = new EncodingManager(ServerConfigurationManager, FileSystemManager, Logger, ItemRepository, MediaEncoder); RegisterSingleInstance(EncodingManager); diff --git a/MediaBrowser.sln b/MediaBrowser.sln index c2f9dff59c..7dc06fb0ce 100644 --- a/MediaBrowser.sln +++ b/MediaBrowser.sln @@ -267,4 +267,7 @@ Global GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(Performance) = preSolution + HasPerformanceSessions = true + EndGlobalSection EndGlobal -- cgit v1.2.3 From 934b3e668cdad0ad29f7d6a3f613fc4d687c6743 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Fri, 28 Mar 2014 14:17:18 -0400 Subject: add more content to dlna profile editing page --- .../MediaBrowser.Common.Implementations.csproj | 1 - .../Updates/ApplicationUpdater.cs | 55 ---------------------- MediaBrowser.Controller/Dlna/CodecProfile.cs | 6 +-- MediaBrowser.Dlna/PlayTo/PlaylistItemFactory.cs | 12 ++--- MediaBrowser.Dlna/Profiles/LgTvProfile.cs | 6 +-- .../Profiles/PanasonicVieraProfile.cs | 2 +- .../Profiles/SamsungSmartTvProfile.cs | 10 ++-- .../Profiles/SonyBlurayPlayer2013Profile.cs | 4 +- .../Profiles/SonyBlurayPlayerProfile.cs | 6 +-- .../Profiles/SonyBravia2010Profile.cs | 10 ++-- .../Profiles/SonyBravia2011Profile.cs | 10 ++-- .../Profiles/SonyBravia2012Profile.cs | 4 +- .../Profiles/SonyBravia2013Profile.cs | 2 +- MediaBrowser.Dlna/Profiles/SonyPs3Profile.cs | 10 ++-- MediaBrowser.Dlna/Profiles/WdtvLiveProfile.cs | 4 +- MediaBrowser.Dlna/Profiles/Xbox360Profile.cs | 10 ++-- MediaBrowser.Dlna/Profiles/Xml/Default.xml | 1 + MediaBrowser.Dlna/Profiles/Xml/Denon AVR.xml | 1 + MediaBrowser.Dlna/Profiles/Xml/LG Smart TV.xml | 6 +-- MediaBrowser.Dlna/Profiles/Xml/Linksys DMA2100.xml | 1 + MediaBrowser.Dlna/Profiles/Xml/Panasonic Viera.xml | 2 +- .../Profiles/Xml/Samsung Smart TV.xml | 10 ++-- .../Profiles/Xml/Sony Blu-ray Player 2013.xml | 4 +- .../Profiles/Xml/Sony Blu-ray Player.xml | 6 +-- .../Profiles/Xml/Sony Bravia (2010).xml | 10 ++-- .../Profiles/Xml/Sony Bravia (2011).xml | 10 ++-- .../Profiles/Xml/Sony Bravia (2012).xml | 4 +- .../Profiles/Xml/Sony Bravia (2013).xml | 2 +- .../Profiles/Xml/Sony PlayStation 3.xml | 10 ++-- MediaBrowser.Dlna/Profiles/Xml/WDTV Live.xml | 4 +- MediaBrowser.Dlna/Profiles/Xml/Xbox 360.xml | 10 ++-- MediaBrowser.Dlna/Profiles/Xml/Xbox One.xml | 1 + MediaBrowser.Dlna/Profiles/Xml/foobar2000.xml | 1 + MediaBrowser.ServerApplication/MainStartup.cs | 5 +- .../MediaBrowser.ServerApplication.csproj | 1 + .../Updates/ApplicationUpdater.cs | 49 +++++++++++++++++++ 36 files changed, 144 insertions(+), 146 deletions(-) delete mode 100644 MediaBrowser.Common.Implementations/Updates/ApplicationUpdater.cs create mode 100644 MediaBrowser.ServerApplication/Updates/ApplicationUpdater.cs (limited to 'MediaBrowser.ServerApplication') diff --git a/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj b/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj index 04b8865c1d..f6f800f4af 100644 --- a/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj +++ b/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj @@ -102,7 +102,6 @@ - diff --git a/MediaBrowser.Common.Implementations/Updates/ApplicationUpdater.cs b/MediaBrowser.Common.Implementations/Updates/ApplicationUpdater.cs deleted file mode 100644 index e24ff30645..0000000000 --- a/MediaBrowser.Common.Implementations/Updates/ApplicationUpdater.cs +++ /dev/null @@ -1,55 +0,0 @@ -using MediaBrowser.Common.Configuration; -using MediaBrowser.Model.Logging; -using System.Diagnostics; -using System.IO; - -namespace MediaBrowser.Common.Implementations.Updates -{ - public enum MBApplication - { - MBServer, - MBTheater - } - - /// - /// Update the specified application using the specified archive - /// - public class ApplicationUpdater - { - private const string UpdaterExe = "Mediabrowser.Updater.exe"; - private const string UpdaterDll = "Mediabrowser.InstallUtil.dll"; - public void UpdateApplication(MBApplication app, IApplicationPaths appPaths, string archive, ILogger logger, string restartServiceName) - { - // First see if there is a version file and read that in - var version = "Unknown"; - if (File.Exists(archive + ".ver")) - { - version = File.ReadAllText(archive + ".ver"); - } - - // Use our installer passing it the specific archive - // We need to copy to a temp directory and execute it there - var source = Path.Combine(appPaths.ProgramSystemPath, UpdaterExe); - - logger.Info("Copying updater to temporary location"); - var tempUpdater = Path.Combine(Path.GetTempPath(), UpdaterExe); - File.Copy(source, tempUpdater, true); - source = Path.Combine(appPaths.ProgramSystemPath, UpdaterDll); - var tempUpdaterDll = Path.Combine(Path.GetTempPath(), UpdaterDll); - - logger.Info("Copying updater dependencies to temporary location"); - File.Copy(source, tempUpdaterDll, true); - var product = app == MBApplication.MBTheater ? "mbt" : "server"; - // Our updater needs SS and ionic - source = Path.Combine(appPaths.ProgramSystemPath, "ServiceStack.Text.dll"); - File.Copy(source, Path.Combine(Path.GetTempPath(), "ServiceStack.Text.dll"), true); - source = Path.Combine(appPaths.ProgramSystemPath, "SharpCompress.dll"); - File.Copy(source, Path.Combine(Path.GetTempPath(), "SharpCompress.dll"), true); - - logger.Info("Starting updater process."); - Process.Start(tempUpdater, string.Format("product={0} archive=\"{1}\" caller={2} pismo=false version={3} service={4} installpath=\"{5}\"", product, archive, Process.GetCurrentProcess().Id, version, restartServiceName ?? string.Empty, appPaths.ProgramDataPath)); - - // That's it. The installer will do the work once we exit - } - } -} diff --git a/MediaBrowser.Controller/Dlna/CodecProfile.cs b/MediaBrowser.Controller/Dlna/CodecProfile.cs index 75f80ed3b1..e2eb60d9a1 100644 --- a/MediaBrowser.Controller/Dlna/CodecProfile.cs +++ b/MediaBrowser.Controller/Dlna/CodecProfile.cs @@ -35,9 +35,9 @@ namespace MediaBrowser.Controller.Dlna public enum CodecType { - VideoCodec = 0, - VideoAudioCodec = 1, - AudioCodec = 2 + Video = 0, + VideoAudio = 1, + Audio = 2 } public class ProfileCondition diff --git a/MediaBrowser.Dlna/PlayTo/PlaylistItemFactory.cs b/MediaBrowser.Dlna/PlayTo/PlaylistItemFactory.cs index f79dc1e5fc..c14a851cab 100644 --- a/MediaBrowser.Dlna/PlayTo/PlaylistItemFactory.cs +++ b/MediaBrowser.Dlna/PlayTo/PlaylistItemFactory.cs @@ -32,7 +32,7 @@ namespace MediaBrowser.Dlna.PlayTo var audioCodec = audioStream == null ? null : audioStream.Codec; // Make sure audio codec profiles are satisfied - if (!string.IsNullOrEmpty(audioCodec) && profile.CodecProfiles.Where(i => i.Type == CodecType.AudioCodec && i.ContainsCodec(audioCodec)) + if (!string.IsNullOrEmpty(audioCodec) && profile.CodecProfiles.Where(i => i.Type == CodecType.Audio && i.ContainsCodec(audioCodec)) .All(i => AreConditionsSatisfied(i.Conditions, item.Path, null, audioStream))) { playlistItem.Transcode = false; @@ -53,7 +53,7 @@ namespace MediaBrowser.Dlna.PlayTo playlistItem.AudioCodec = transcodingProfile.AudioCodec; var audioTranscodingConditions = profile.CodecProfiles - .Where(i => i.Type == CodecType.AudioCodec && i.ContainsCodec(transcodingProfile.AudioCodec)) + .Where(i => i.Type == CodecType.Audio && i.ContainsCodec(transcodingProfile.AudioCodec)) .Take(1) .SelectMany(i => i.Conditions); @@ -114,13 +114,13 @@ namespace MediaBrowser.Dlna.PlayTo var videoCodec = videoStream == null ? null : videoStream.Codec; // Make sure video codec profiles are satisfied - if (!string.IsNullOrEmpty(videoCodec) && profile.CodecProfiles.Where(i => i.Type == CodecType.VideoCodec && i.ContainsCodec(videoCodec)) + if (!string.IsNullOrEmpty(videoCodec) && profile.CodecProfiles.Where(i => i.Type == CodecType.Video && i.ContainsCodec(videoCodec)) .All(i => AreConditionsSatisfied(i.Conditions, item.Path, videoStream, audioStream))) { var audioCodec = audioStream == null ? null : audioStream.Codec; // Make sure audio codec profiles are satisfied - if (string.IsNullOrEmpty(audioCodec) || profile.CodecProfiles.Where(i => i.Type == CodecType.VideoAudioCodec && i.ContainsCodec(audioCodec)) + if (string.IsNullOrEmpty(audioCodec) || profile.CodecProfiles.Where(i => i.Type == CodecType.VideoAudio && i.ContainsCodec(audioCodec)) .All(i => AreConditionsSatisfied(i.Conditions, item.Path, videoStream, audioStream))) { playlistItem.Transcode = false; @@ -143,14 +143,14 @@ namespace MediaBrowser.Dlna.PlayTo playlistItem.VideoCodec = transcodingProfile.VideoCodec; var videoTranscodingConditions = profile.CodecProfiles - .Where(i => i.Type == CodecType.VideoCodec && i.ContainsCodec(transcodingProfile.VideoCodec)) + .Where(i => i.Type == CodecType.Video && i.ContainsCodec(transcodingProfile.VideoCodec)) .Take(1) .SelectMany(i => i.Conditions); ApplyTranscodingConditions(playlistItem, videoTranscodingConditions); var audioTranscodingConditions = profile.CodecProfiles - .Where(i => i.Type == CodecType.VideoAudioCodec && i.ContainsCodec(transcodingProfile.AudioCodec)) + .Where(i => i.Type == CodecType.VideoAudio && i.ContainsCodec(transcodingProfile.AudioCodec)) .Take(1) .SelectMany(i => i.Conditions); diff --git a/MediaBrowser.Dlna/Profiles/LgTvProfile.cs b/MediaBrowser.Dlna/Profiles/LgTvProfile.cs index 7ca8069dac..ccf36e8447 100644 --- a/MediaBrowser.Dlna/Profiles/LgTvProfile.cs +++ b/MediaBrowser.Dlna/Profiles/LgTvProfile.cs @@ -113,7 +113,7 @@ namespace MediaBrowser.Dlna.Profiles { new CodecProfile { - Type = CodecType.VideoCodec, + Type = CodecType.Video, Codec = "mpeg4", Conditions = new[] @@ -141,7 +141,7 @@ namespace MediaBrowser.Dlna.Profiles new CodecProfile { - Type = CodecType.VideoCodec, + Type = CodecType.Video, Codec = "h264", Conditions = new[] @@ -175,7 +175,7 @@ namespace MediaBrowser.Dlna.Profiles new CodecProfile { - Type = CodecType.VideoAudioCodec, + Type = CodecType.VideoAudio, Codec = "ac3,aac,mp3", Conditions = new[] diff --git a/MediaBrowser.Dlna/Profiles/PanasonicVieraProfile.cs b/MediaBrowser.Dlna/Profiles/PanasonicVieraProfile.cs index 64747776c6..ced9a7c612 100644 --- a/MediaBrowser.Dlna/Profiles/PanasonicVieraProfile.cs +++ b/MediaBrowser.Dlna/Profiles/PanasonicVieraProfile.cs @@ -157,7 +157,7 @@ namespace MediaBrowser.Dlna.Profiles { new CodecProfile { - Type = CodecType.VideoCodec, + Type = CodecType.Video, Conditions = new[] { diff --git a/MediaBrowser.Dlna/Profiles/SamsungSmartTvProfile.cs b/MediaBrowser.Dlna/Profiles/SamsungSmartTvProfile.cs index 259d8e9ffb..122bde875f 100644 --- a/MediaBrowser.Dlna/Profiles/SamsungSmartTvProfile.cs +++ b/MediaBrowser.Dlna/Profiles/SamsungSmartTvProfile.cs @@ -145,7 +145,7 @@ namespace MediaBrowser.Dlna.Profiles { new CodecProfile { - Type = CodecType.VideoCodec, + Type = CodecType.Video, Codec = "mpeg2video", Conditions = new[] @@ -179,7 +179,7 @@ namespace MediaBrowser.Dlna.Profiles new CodecProfile { - Type = CodecType.VideoCodec, + Type = CodecType.Video, Codec = "mpeg4", Conditions = new[] @@ -213,7 +213,7 @@ namespace MediaBrowser.Dlna.Profiles new CodecProfile { - Type = CodecType.VideoCodec, + Type = CodecType.Video, Codec = "h264", Conditions = new[] @@ -253,7 +253,7 @@ namespace MediaBrowser.Dlna.Profiles new CodecProfile { - Type = CodecType.VideoCodec, + Type = CodecType.Video, Codec = "wmv2,wmv3,vc1", Conditions = new[] @@ -287,7 +287,7 @@ namespace MediaBrowser.Dlna.Profiles new CodecProfile { - Type = CodecType.VideoAudioCodec, + Type = CodecType.VideoAudio, Codec = "ac3,wmav2,dca,aac,mp3", Conditions = new[] diff --git a/MediaBrowser.Dlna/Profiles/SonyBlurayPlayer2013Profile.cs b/MediaBrowser.Dlna/Profiles/SonyBlurayPlayer2013Profile.cs index 04309d55f7..b64d4f6caf 100644 --- a/MediaBrowser.Dlna/Profiles/SonyBlurayPlayer2013Profile.cs +++ b/MediaBrowser.Dlna/Profiles/SonyBlurayPlayer2013Profile.cs @@ -113,7 +113,7 @@ namespace MediaBrowser.Dlna.Profiles { new CodecProfile { - Type = CodecType.VideoCodec, + Type = CodecType.Video, Codec = "h264", Conditions = new [] { @@ -141,7 +141,7 @@ namespace MediaBrowser.Dlna.Profiles new CodecProfile { - Type = CodecType.VideoAudioCodec, + Type = CodecType.VideoAudio, Codec = "ac3", Conditions = new [] { diff --git a/MediaBrowser.Dlna/Profiles/SonyBlurayPlayerProfile.cs b/MediaBrowser.Dlna/Profiles/SonyBlurayPlayerProfile.cs index d9dfc1caf8..c5025edbb6 100644 --- a/MediaBrowser.Dlna/Profiles/SonyBlurayPlayerProfile.cs +++ b/MediaBrowser.Dlna/Profiles/SonyBlurayPlayerProfile.cs @@ -109,7 +109,7 @@ namespace MediaBrowser.Dlna.Profiles { new CodecProfile { - Type = CodecType.VideoCodec, + Type = CodecType.Video, Codec = "h264", Conditions = new [] { @@ -151,7 +151,7 @@ namespace MediaBrowser.Dlna.Profiles new CodecProfile { - Type = CodecType.VideoAudioCodec, + Type = CodecType.VideoAudio, Codec = "ac3", Conditions = new [] { @@ -167,7 +167,7 @@ namespace MediaBrowser.Dlna.Profiles new CodecProfile { - Type = CodecType.VideoAudioCodec, + Type = CodecType.VideoAudio, Codec = "aac", Conditions = new [] { diff --git a/MediaBrowser.Dlna/Profiles/SonyBravia2010Profile.cs b/MediaBrowser.Dlna/Profiles/SonyBravia2010Profile.cs index cb91de4a09..8f29ad76e3 100644 --- a/MediaBrowser.Dlna/Profiles/SonyBravia2010Profile.cs +++ b/MediaBrowser.Dlna/Profiles/SonyBravia2010Profile.cs @@ -168,7 +168,7 @@ namespace MediaBrowser.Dlna.Profiles { new CodecProfile { - Type = CodecType.VideoCodec, + Type = CodecType.Video, Conditions = new [] { new ProfileCondition @@ -188,7 +188,7 @@ namespace MediaBrowser.Dlna.Profiles new CodecProfile { - Type = CodecType.VideoCodec, + Type = CodecType.Video, Codec = "h264", Conditions = new [] { @@ -215,7 +215,7 @@ namespace MediaBrowser.Dlna.Profiles new CodecProfile { - Type = CodecType.VideoCodec, + Type = CodecType.Video, Codec = "mpeg2video", Conditions = new [] { @@ -236,7 +236,7 @@ namespace MediaBrowser.Dlna.Profiles new CodecProfile { - Type = CodecType.VideoAudioCodec, + Type = CodecType.VideoAudio, Codec = "ac3", Conditions = new [] @@ -252,7 +252,7 @@ namespace MediaBrowser.Dlna.Profiles new CodecProfile { - Type = CodecType.VideoAudioCodec, + Type = CodecType.VideoAudio, Codec = "aac", Conditions = new [] diff --git a/MediaBrowser.Dlna/Profiles/SonyBravia2011Profile.cs b/MediaBrowser.Dlna/Profiles/SonyBravia2011Profile.cs index 626a91a73c..eaf6979a6b 100644 --- a/MediaBrowser.Dlna/Profiles/SonyBravia2011Profile.cs +++ b/MediaBrowser.Dlna/Profiles/SonyBravia2011Profile.cs @@ -186,7 +186,7 @@ namespace MediaBrowser.Dlna.Profiles { new CodecProfile { - Type = CodecType.VideoCodec, + Type = CodecType.Video, Conditions = new [] { new ProfileCondition @@ -206,7 +206,7 @@ namespace MediaBrowser.Dlna.Profiles new CodecProfile { - Type = CodecType.VideoCodec, + Type = CodecType.Video, Codec = "h264", Conditions = new [] { @@ -233,7 +233,7 @@ namespace MediaBrowser.Dlna.Profiles new CodecProfile { - Type = CodecType.VideoCodec, + Type = CodecType.Video, Codec = "mpeg2video", Conditions = new [] { @@ -254,7 +254,7 @@ namespace MediaBrowser.Dlna.Profiles new CodecProfile { - Type = CodecType.VideoAudioCodec, + Type = CodecType.VideoAudio, Codec = "ac3", Conditions = new [] @@ -270,7 +270,7 @@ namespace MediaBrowser.Dlna.Profiles new CodecProfile { - Type = CodecType.VideoAudioCodec, + Type = CodecType.VideoAudio, Codec = "aac", Conditions = new[] diff --git a/MediaBrowser.Dlna/Profiles/SonyBravia2012Profile.cs b/MediaBrowser.Dlna/Profiles/SonyBravia2012Profile.cs index 82b6b6d5f9..41d057ef8a 100644 --- a/MediaBrowser.Dlna/Profiles/SonyBravia2012Profile.cs +++ b/MediaBrowser.Dlna/Profiles/SonyBravia2012Profile.cs @@ -198,7 +198,7 @@ namespace MediaBrowser.Dlna.Profiles { new CodecProfile { - Type = CodecType.VideoCodec, + Type = CodecType.Video, Conditions = new[] { new ProfileCondition @@ -218,7 +218,7 @@ namespace MediaBrowser.Dlna.Profiles new CodecProfile { - Type = CodecType.VideoAudioCodec, + Type = CodecType.VideoAudio, Codec = "ac3", Conditions = new[] diff --git a/MediaBrowser.Dlna/Profiles/SonyBravia2013Profile.cs b/MediaBrowser.Dlna/Profiles/SonyBravia2013Profile.cs index aec65e98ec..386a36ae0c 100644 --- a/MediaBrowser.Dlna/Profiles/SonyBravia2013Profile.cs +++ b/MediaBrowser.Dlna/Profiles/SonyBravia2013Profile.cs @@ -231,7 +231,7 @@ namespace MediaBrowser.Dlna.Profiles { new CodecProfile { - Type = CodecType.VideoCodec, + Type = CodecType.Video, Conditions = new [] { diff --git a/MediaBrowser.Dlna/Profiles/SonyPs3Profile.cs b/MediaBrowser.Dlna/Profiles/SonyPs3Profile.cs index 7502201eac..351a13f001 100644 --- a/MediaBrowser.Dlna/Profiles/SonyPs3Profile.cs +++ b/MediaBrowser.Dlna/Profiles/SonyPs3Profile.cs @@ -85,7 +85,7 @@ namespace MediaBrowser.Dlna.Profiles { new CodecProfile { - Type = CodecType.VideoCodec, + Type = CodecType.Video, Codec = "h264", Conditions = new [] @@ -128,7 +128,7 @@ namespace MediaBrowser.Dlna.Profiles new CodecProfile { - Type = CodecType.VideoAudioCodec, + Type = CodecType.VideoAudio, Codec = "ac3", Conditions = new [] @@ -153,7 +153,7 @@ namespace MediaBrowser.Dlna.Profiles new CodecProfile { - Type = CodecType.VideoAudioCodec, + Type = CodecType.VideoAudio, Codec = "wmapro", Conditions = new [] @@ -169,7 +169,7 @@ namespace MediaBrowser.Dlna.Profiles new CodecProfile { - Type = CodecType.VideoAudioCodec, + Type = CodecType.VideoAudio, Codec = "aac", Conditions = new [] @@ -186,7 +186,7 @@ namespace MediaBrowser.Dlna.Profiles new CodecProfile { - Type = CodecType.VideoAudioCodec, + Type = CodecType.VideoAudio, Codec = "aac", Conditions = new [] diff --git a/MediaBrowser.Dlna/Profiles/WdtvLiveProfile.cs b/MediaBrowser.Dlna/Profiles/WdtvLiveProfile.cs index af5d9b2956..f0b95d4e88 100644 --- a/MediaBrowser.Dlna/Profiles/WdtvLiveProfile.cs +++ b/MediaBrowser.Dlna/Profiles/WdtvLiveProfile.cs @@ -195,7 +195,7 @@ namespace MediaBrowser.Dlna.Profiles { new CodecProfile { - Type = CodecType.VideoCodec, + Type = CodecType.Video, Codec = "h264", Conditions = new [] @@ -223,7 +223,7 @@ namespace MediaBrowser.Dlna.Profiles new CodecProfile { - Type = CodecType.VideoAudioCodec, + Type = CodecType.VideoAudio, Codec = "aac", Conditions = new [] diff --git a/MediaBrowser.Dlna/Profiles/Xbox360Profile.cs b/MediaBrowser.Dlna/Profiles/Xbox360Profile.cs index ed9edeb27a..38d08adef7 100644 --- a/MediaBrowser.Dlna/Profiles/Xbox360Profile.cs +++ b/MediaBrowser.Dlna/Profiles/Xbox360Profile.cs @@ -165,7 +165,7 @@ namespace MediaBrowser.Dlna.Profiles { new CodecProfile { - Type = CodecType.VideoCodec, + Type = CodecType.Video, Codec = "mpeg4", Conditions = new [] { @@ -200,7 +200,7 @@ namespace MediaBrowser.Dlna.Profiles new CodecProfile { - Type = CodecType.VideoCodec, + Type = CodecType.Video, Codec = "h264", Conditions = new [] { @@ -235,7 +235,7 @@ namespace MediaBrowser.Dlna.Profiles new CodecProfile { - Type = CodecType.VideoCodec, + Type = CodecType.Video, Codec = "wmv2,wmv3,vc1", Conditions = new [] { @@ -270,7 +270,7 @@ namespace MediaBrowser.Dlna.Profiles new CodecProfile { - Type = CodecType.VideoAudioCodec, + Type = CodecType.VideoAudio, Codec = "ac3,wmav2,wmapro", Conditions = new [] { @@ -286,7 +286,7 @@ namespace MediaBrowser.Dlna.Profiles new CodecProfile { - Type = CodecType.VideoAudioCodec, + Type = CodecType.VideoAudio, Codec = "aac", Conditions = new [] { diff --git a/MediaBrowser.Dlna/Profiles/Xml/Default.xml b/MediaBrowser.Dlna/Profiles/Xml/Default.xml index 60f22a64a9..895cb99d32 100644 --- a/MediaBrowser.Dlna/Profiles/Xml/Default.xml +++ b/MediaBrowser.Dlna/Profiles/Xml/Default.xml @@ -30,5 +30,6 @@ + \ No newline at end of file diff --git a/MediaBrowser.Dlna/Profiles/Xml/Denon AVR.xml b/MediaBrowser.Dlna/Profiles/Xml/Denon AVR.xml index 28bb3289e2..58c5cefbc5 100644 --- a/MediaBrowser.Dlna/Profiles/Xml/Denon AVR.xml +++ b/MediaBrowser.Dlna/Profiles/Xml/Denon AVR.xml @@ -34,5 +34,6 @@ + \ No newline at end of file diff --git a/MediaBrowser.Dlna/Profiles/Xml/LG Smart TV.xml b/MediaBrowser.Dlna/Profiles/Xml/LG Smart TV.xml index cc8b40430d..53781ad324 100644 --- a/MediaBrowser.Dlna/Profiles/Xml/LG Smart TV.xml +++ b/MediaBrowser.Dlna/Profiles/Xml/LG Smart TV.xml @@ -48,14 +48,14 @@ - + - + @@ -63,7 +63,7 @@ - + diff --git a/MediaBrowser.Dlna/Profiles/Xml/Linksys DMA2100.xml b/MediaBrowser.Dlna/Profiles/Xml/Linksys DMA2100.xml index 477fee2dde..fc833b9186 100644 --- a/MediaBrowser.Dlna/Profiles/Xml/Linksys DMA2100.xml +++ b/MediaBrowser.Dlna/Profiles/Xml/Linksys DMA2100.xml @@ -34,5 +34,6 @@ + \ No newline at end of file diff --git a/MediaBrowser.Dlna/Profiles/Xml/Panasonic Viera.xml b/MediaBrowser.Dlna/Profiles/Xml/Panasonic Viera.xml index 71e240313b..49fd05b1e0 100644 --- a/MediaBrowser.Dlna/Profiles/Xml/Panasonic Viera.xml +++ b/MediaBrowser.Dlna/Profiles/Xml/Panasonic Viera.xml @@ -54,7 +54,7 @@ - + diff --git a/MediaBrowser.Dlna/Profiles/Xml/Samsung Smart TV.xml b/MediaBrowser.Dlna/Profiles/Xml/Samsung Smart TV.xml index 77648147f5..75c50aae36 100644 --- a/MediaBrowser.Dlna/Profiles/Xml/Samsung Smart TV.xml +++ b/MediaBrowser.Dlna/Profiles/Xml/Samsung Smart TV.xml @@ -52,7 +52,7 @@ - + @@ -60,7 +60,7 @@ - + @@ -68,7 +68,7 @@ - + @@ -77,7 +77,7 @@ - + @@ -85,7 +85,7 @@ - + diff --git a/MediaBrowser.Dlna/Profiles/Xml/Sony Blu-ray Player 2013.xml b/MediaBrowser.Dlna/Profiles/Xml/Sony Blu-ray Player 2013.xml index 9428122954..5bd27c7716 100644 --- a/MediaBrowser.Dlna/Profiles/Xml/Sony Blu-ray Player 2013.xml +++ b/MediaBrowser.Dlna/Profiles/Xml/Sony Blu-ray Player 2013.xml @@ -52,14 +52,14 @@ - + - + diff --git a/MediaBrowser.Dlna/Profiles/Xml/Sony Blu-ray Player.xml b/MediaBrowser.Dlna/Profiles/Xml/Sony Blu-ray Player.xml index 5193045768..f5502ca14a 100644 --- a/MediaBrowser.Dlna/Profiles/Xml/Sony Blu-ray Player.xml +++ b/MediaBrowser.Dlna/Profiles/Xml/Sony Blu-ray Player.xml @@ -51,7 +51,7 @@ - + @@ -60,12 +60,12 @@ - + - + diff --git a/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2010).xml b/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2010).xml index d240e1d348..1337b59361 100644 --- a/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2010).xml +++ b/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2010).xml @@ -49,31 +49,31 @@ - + - + - + - + - + diff --git a/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2011).xml b/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2011).xml index 2372aa5ad9..b022c10a51 100644 --- a/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2011).xml +++ b/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2011).xml @@ -52,31 +52,31 @@ - + - + - + - + - + diff --git a/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2012).xml b/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2012).xml index 7edf09134c..cbef70b378 100644 --- a/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2012).xml +++ b/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2012).xml @@ -54,13 +54,13 @@ - + - + diff --git a/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2013).xml b/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2013).xml index ec624cd8ec..47db46ce11 100644 --- a/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2013).xml +++ b/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2013).xml @@ -59,7 +59,7 @@ - + diff --git a/MediaBrowser.Dlna/Profiles/Xml/Sony PlayStation 3.xml b/MediaBrowser.Dlna/Profiles/Xml/Sony PlayStation 3.xml index eeaf2d8193..d9aa441bb4 100644 --- a/MediaBrowser.Dlna/Profiles/Xml/Sony PlayStation 3.xml +++ b/MediaBrowser.Dlna/Profiles/Xml/Sony PlayStation 3.xml @@ -48,7 +48,7 @@ - + @@ -57,23 +57,23 @@ - + - + - + - + diff --git a/MediaBrowser.Dlna/Profiles/Xml/WDTV Live.xml b/MediaBrowser.Dlna/Profiles/Xml/WDTV Live.xml index ffa39c26d1..0f4ad54a77 100644 --- a/MediaBrowser.Dlna/Profiles/Xml/WDTV Live.xml +++ b/MediaBrowser.Dlna/Profiles/Xml/WDTV Live.xml @@ -59,14 +59,14 @@ - + - + diff --git a/MediaBrowser.Dlna/Profiles/Xml/Xbox 360.xml b/MediaBrowser.Dlna/Profiles/Xml/Xbox 360.xml index ea25391976..1e8d8164c3 100644 --- a/MediaBrowser.Dlna/Profiles/Xml/Xbox 360.xml +++ b/MediaBrowser.Dlna/Profiles/Xml/Xbox 360.xml @@ -59,7 +59,7 @@ - + @@ -67,7 +67,7 @@ - + @@ -75,7 +75,7 @@ - + @@ -83,12 +83,12 @@ - + - + diff --git a/MediaBrowser.Dlna/Profiles/Xml/Xbox One.xml b/MediaBrowser.Dlna/Profiles/Xml/Xbox One.xml index ef4fec99ac..f6c338b2f5 100644 --- a/MediaBrowser.Dlna/Profiles/Xml/Xbox One.xml +++ b/MediaBrowser.Dlna/Profiles/Xml/Xbox One.xml @@ -32,6 +32,7 @@ + diff --git a/MediaBrowser.Dlna/Profiles/Xml/foobar2000.xml b/MediaBrowser.Dlna/Profiles/Xml/foobar2000.xml index 3e6623ac48..f682e4c421 100644 --- a/MediaBrowser.Dlna/Profiles/Xml/foobar2000.xml +++ b/MediaBrowser.Dlna/Profiles/Xml/foobar2000.xml @@ -36,5 +36,6 @@ + \ No newline at end of file diff --git a/MediaBrowser.ServerApplication/MainStartup.cs b/MediaBrowser.ServerApplication/MainStartup.cs index 6afe9367e5..3d490a1f8c 100644 --- a/MediaBrowser.ServerApplication/MainStartup.cs +++ b/MediaBrowser.ServerApplication/MainStartup.cs @@ -1,12 +1,11 @@ using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Constants; using MediaBrowser.Common.Implementations.Logging; -using MediaBrowser.Common.Implementations.Updates; -using MediaBrowser.Controller; using MediaBrowser.Model.Logging; using MediaBrowser.Server.Implementations; using MediaBrowser.ServerApplication.Native; using MediaBrowser.ServerApplication.Splash; +using MediaBrowser.ServerApplication.Updates; using Microsoft.Win32; using System; using System.Configuration.Install; @@ -490,7 +489,7 @@ namespace MediaBrowser.ServerApplication try { var serviceName = _isRunningAsService ? BackgroundService.Name : string.Empty; - new ApplicationUpdater().UpdateApplication(MBApplication.MBServer, appPaths, updateArchive, logger, serviceName); + new ApplicationUpdater().UpdateApplication(appPaths, updateArchive, logger, serviceName); // And just let the app exit so it can update return true; diff --git a/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj b/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj index d999841ca7..b49e100ab2 100644 --- a/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj +++ b/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj @@ -145,6 +145,7 @@ SplashForm.cs + diff --git a/MediaBrowser.ServerApplication/Updates/ApplicationUpdater.cs b/MediaBrowser.ServerApplication/Updates/ApplicationUpdater.cs new file mode 100644 index 0000000000..9f3e44cb0f --- /dev/null +++ b/MediaBrowser.ServerApplication/Updates/ApplicationUpdater.cs @@ -0,0 +1,49 @@ +using MediaBrowser.Common.Configuration; +using MediaBrowser.Model.Logging; +using System.Diagnostics; +using System.IO; + +namespace MediaBrowser.ServerApplication.Updates +{ + /// + /// Update the specified application using the specified archive + /// + public class ApplicationUpdater + { + private const string UpdaterExe = "Mediabrowser.Updater.exe"; + private const string UpdaterDll = "Mediabrowser.InstallUtil.dll"; + public void UpdateApplication(IApplicationPaths appPaths, string archive, ILogger logger, string restartServiceName) + { + // First see if there is a version file and read that in + var version = "Unknown"; + if (File.Exists(archive + ".ver")) + { + version = File.ReadAllText(archive + ".ver"); + } + + // Use our installer passing it the specific archive + // We need to copy to a temp directory and execute it there + var source = Path.Combine(appPaths.ProgramSystemPath, UpdaterExe); + + logger.Info("Copying updater to temporary location"); + var tempUpdater = Path.Combine(Path.GetTempPath(), UpdaterExe); + File.Copy(source, tempUpdater, true); + source = Path.Combine(appPaths.ProgramSystemPath, UpdaterDll); + var tempUpdaterDll = Path.Combine(Path.GetTempPath(), UpdaterDll); + + logger.Info("Copying updater dependencies to temporary location"); + File.Copy(source, tempUpdaterDll, true); + const string product = "server"; + // Our updater needs SS and ionic + source = Path.Combine(appPaths.ProgramSystemPath, "ServiceStack.Text.dll"); + File.Copy(source, Path.Combine(Path.GetTempPath(), "ServiceStack.Text.dll"), true); + source = Path.Combine(appPaths.ProgramSystemPath, "SharpCompress.dll"); + File.Copy(source, Path.Combine(Path.GetTempPath(), "SharpCompress.dll"), true); + + logger.Info("Starting updater process."); + Process.Start(tempUpdater, string.Format("product={0} archive=\"{1}\" caller={2} pismo=false version={3} service={4} installpath=\"{5}\"", product, archive, Process.GetCurrentProcess().Id, version, restartServiceName ?? string.Empty, appPaths.ProgramDataPath)); + + // That's it. The installer will do the work once we exit + } + } +} -- cgit v1.2.3